def build_func_arg(block, ast_node): # argument: (test (comp_for)? | test '=' test | '**' test | '*' test); childs = ast_node.children if len(childs) == 3: # test = test left = build_test_stmt(childs[0]) right = build_test_stmt(childs[2]) return KeyWordArg(block, childs[0], left_instr=left, right_instr=right) if isinstance(childs[0], DP.TestContext): test_node, *childs = childs test_instr = build_test_stmt(block, test_node) if len(childs) == 0: return test_instr assert len(childs) == 1 and isinstance(childs[0], DP.Comp_forContext) generator_node = childs[0] return build_generator_expr(block, test_instr, generator_node) else: # either *args or **kwargs style var text = ast_node_text(childs[0]) child_instr = build_test_stmt(block, childs[1]) if text == "**": return KeyWordArgVar(block=block, ast_node=childs[1], child_instr=child_instr) else: return ArgListVar(block=block, ast_node=childs[1], child_instr=child_instr)
def build_aug_assign_stmt(block, ast_node): # augassign_stmt: testlist_star_expr augassign (yield_expr | testlist); # augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//='); left_instr = build_test_star_stmt(block, ast_node.children[0]) aug_node = ast_node.children[1] if isinstance(ast_node.children[-1], DP.TestlistContext): right_instr = build_test_list(block, ast_node.children[-1]) else: right_instr = build_yield_expr(block, ast_node.children[-1]) # get the operator without the "=" at the end op_text = ast_node_text(aug_node)[:-1] op_cls = math_operator_classes[op_text] op_instr = op_cls(block=block, ast_node=aug_node, left_instr=left_instr, right_instr=right_instr) block.add_instr(op_instr) assign = Assign(block=block, ast_node=aug_node, left_instr=left_instr, right_instr=op_instr) block.add_instr(assign) return assign
def build_if_statement(block, ast_node): # if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ('else' ':' suite)?; childs = ast_node.children cond = build_test_stmt(block, childs[1]) if_block = IfCondition(cond=cond, parent=block, ast_node=ast_node) build_suite(if_block, childs[3]) childs = childs[4:] while childs: if ast_node_text(childs[0]) == 'else': else_block = ElseBlock(parent=block, ast_node=childs[0]) if_block.else_block = else_block build_suite(else_block, childs[2]) break else: cond = build_test_stmt(block, childs[1]) elif_block = ElifCondition(parent=block, ast_node=childs[0], cond=cond) build_suite(elif_block, childs[3]) childs = childs[4:] if_block.add_elif(elif_block) block.add_instr(if_block) return if_block
def build_kw_args(block, ast_node): # named_kw_args: type_qual? '**' NAME ; type_qual = None if len(ast_node.children) > 2: type_qual = build_type_qual(block, ast_node.children[0]) name = ast_node_text(ast_node.children[-1]) return StarKwFuncArg(block, ast_node, name, type_qual)
def build_type_qual(block, ast_node): # type_qual: NAME (template_def)? ; type_name = ast_node_text(ast_node.children[0]) template_def = None if len(ast_node.children) > 1: template_def = build_template_def(block, ast_node.children[1]) return TypeQualifier(block, ast_node, type_name, template_def)
def build_atom(block, ast_node): child = ast_node.children[0] if isinstance(child, DP.LiteralContext): return build_literal(block, child) elif isinstance(child, DP.Bare_nameContext): return BareName(block, child, ast_node_text(child)) elif isinstance(child, DP.Atom_list_exprContext): return build_atom_list_expr(block, child) elif isinstance(child, DP.Atom_dict_exprContext): return build_atom_dict_expr(block, child) else: raise_unknown_ast_node(block, child)
def build_factor_expr(block, ast_node): if len(ast_node.children) == 1: return build_power_expr(block, ast_node.children[0]) # factor: ('+' | '-' | '~') factor | power; op_node, right_node = ast_node.children right_expr = build_factor_expr(block, right_node) op_text = ast_node_text(op_node) instr_class = factor_operator_classes[op_text] instr = instr_class(block=block, ast_node=op_node, child_instr=right_expr) block.add_instr(instr) return instr
def build_atom_trailer(block, atom, ast_node): # trailer: '('(arglist)? ')' | '[' subscriptlist ']' | '.' NAME; # Array / Dict subscript notation first_char = ast_node_text(ast_node.children[0]) if first_char == '[': return build_subscript_list(block, atom, ast_node.children[1]) elif first_char == '.': bare_name = BareName(block=block, ast_node=ast_node.children[1], text=ast_node_text(ast_node.children[1])) dot_op = DotOperator(block=block, ast_node=ast_node, left_instr=atom, right_instr=bare_name) return dot_op elif first_char == '(': # function call args = [] if len(ast_node.children) == 3: args = build_func_arg_list(block, ast_node.children[1]) return FuncCall(block=block, ast_node=ast_node.children[0], func_ptr_instr=atom, args=args)
def build_template_def(block, ast_node): # template_def: '<' (template_args)? '>' ; # template_args: NAME (',' NAME)* ','?; if len(ast_node.children) == 2: return TemplateDef(block, ast_node, []) args = ast_node.children[1].children arg_names = [] while args: first_arg, *args = args arg_names.append(ast_node_text(first_arg)) if args: comma_, *args = args return TemplateDef(block, ast_node, arg_names)
def build_classdef(block, ast_node): # 'class' NAME ('(' (arglist)? ')')? ':' suite; class_name = ast_node_text(ast_node.children[1]) supers = [] for child in ast_node.children: if isinstance(child, DP.ArglistContext): supers = build_func_arg_list(block, child) break class_instr = ClassDef(parent=block, ast_node=ast_node, class_name=class_name, supers=supers) class_instr.body = build_suite(class_instr, ast_node.children[-1]) block.add_instr(class_instr)
def build_term_expr(block, ast_node): # term: factor(('*' | '@' | '/' | '%' | '//') factor) *; left_expr = build_factor_expr(block, ast_node.children[0]) if len(ast_node.children) == 1: return left_expr childs = ast_node.children[1:] while len(childs) > 0: op_node, right_node, *childs = childs right_expr = build_factor_expr(block, right_node) op_text = ast_node_text(op_node) instr_class = term_operator_classes[op_text] instr = instr_class(block=block, ast_node=op_node, left_instr=left_expr, right_instr=right_expr) block.add_instr(instr) left_expr = instr return left_expr
def build_arith_expr(block, ast_node): # arith_expr: term(('+' | '-') term) *; left_expr = build_term_expr(block, ast_node.children[0]) if len(ast_node.children) == 1: return left_expr childs = ast_node.children[1:] while len(childs) > 0: op_node, right_node, *childs = childs right_expr = build_term_expr(block, right_node) op_text = ast_node_text(op_node) instr_class = arith_operator_classes[op_text] instr = instr_class(block=block, ast_node=op_node, left_instr=left_expr, right_instr=right_expr) block.add_instr(instr) left_expr = instr return left_expr
def build_named_arg(block, ast_node): # namedarg: type_qual? NAME ('=' test) ? ; childs = ast_node.children type_qual, default_value = None, None if isinstance(childs[0], DP.Type_qualContext): type_qual, *childs = childs type_qual = build_type_qual(block, type_qual) name, childs = ast_node_text(childs[0]), childs[1:] if childs: # has a test statement default_value = build_test_stmt(block, childs[1]) return NamedFuncArg(block=block, ast_node=ast_node, name=name, type_qual=type_qual, default_value=default_value)
def build_comparison(block, ast_node): # comparison: expr (comp_op expr) *; child_instrs = [] left_expr = build_expression(block, ast_node.children[0]) operator_cls = None if len(ast_node.children) == 1: return left_expr # Will be multi-comparison, only chainable comparisons valid if len(ast_node.children) > 3: operator_lookup = multi_comparison_operator_classes # <left> <comp> <right>, all binary comparisons valid else: operator_lookup = binary_comparison_operator_classes for child in ast_node.children[1:]: if isinstance(child, DP.Comp_opsContext): op = ast_node_text(child) try: operator_cls = operator_lookup[op] except KeyError: raise ParseException( f"Unrecognized comparison operator {op} at {ast_location_str(child)}" ) else: right_expr = build_expression(block, child) operator_instr = operator_cls(block=block, ast_node=child, left_instr=left_expr, right_instr=right_expr) child_instrs.append(operator_instr) left_expr = right_expr if len(child_instrs) == 1: block.add_instr(child_instrs[0]) return child_instrs[0] else: multi_comp = MultiComparison(block, ast_node, child_instrs) block.add_instr(multi_comp) return multi_comp
def build_func_def(block, ast_node): # funcdef: 'def' NAME parameters ('->' test)? ':' suite; def_, func_name, params, *childs = ast_node.children *childs, colon_, suite = childs returns = None if childs: # have unparsed tokens, is "-> <return>" arrow_, ret_type = childs returns = build_test_stmt(block, ret_type) name_instr = ast_node_text(func_name) params_instr = build_parameters(block, params) func = FuncDef(ast_node=ast_node, parent=block, name=name_instr, params=params_instr, returns=returns) func.body = build_suite(func, ast_node.children[-1]) block.add_instr(func) return func