def copy_assignee(n, ctx): if isinstance(n, ast.Name): ret = ast.Name(id=n.id, ctx=ctx) elif isinstance(n, ast.Attribute): ret = ast.Attribute(value=n.value, attr=n.attr, ctx=ctx) elif isinstance(n, ast.Subscript): ret = ast.Subscript(value=n.value, slice=n.slice, ctx=ctx) elif isinstance(n, ast.List): elts = [copy_assignee(e, ctx) for e in n.elts] ret = ast.List(elts=elts, ctx=ctx) elif isinstance(n, ast.Tuple): elts = [copy_assignee(e, ctx) for e in n.elts] ret = ast.Tuple(elts=elts, ctx=ctx) elif isinstance(n, ast.Starred): ret = ast.Starred(value=copy_assignee(n.value, ctx), ctx=ctx) elif isinstance(n, ast.Call): args = [copy_assignee(e, ctx) for e in n.args] ret = ast.Call(func=n.func, args=args, keywords=n.keywords, starargs=n.starargs, kwargs=n.kwargs) else: return n ast.copy_location(ret, n) return ret
def _to_custom_constructor_body( signature_data: SignatureData, class_parameter_name: str = CLASS_PARAMETER_NAME, positional_kinds: Sequence[inspect._ParameterKind] = ( inspect._POSITIONAL_ONLY, inspect._POSITIONAL_OR_KEYWORD) ) -> List[ast.stmt]: positionals_names = chain.from_iterable( signature_data.get(kind, []) for kind in positional_kinds) keywords_names = signature_data.get(inspect._KEYWORD_ONLY, []) positional_arguments = [ ast.Name(parameter_name, ast.Load()) for parameter_name in positionals_names ] if inspect._VAR_POSITIONAL in signature_data: variadic_positional_name, = signature_data[inspect._VAR_POSITIONAL] variadic_positional_node = ast.Starred( ast.Name(variadic_positional_name, ast.Load()), ast.Load()) positional_arguments.append(variadic_positional_node) keyword_arguments = [ ast.keyword(parameter_name, ast.Name(parameter_name, ast.Load())) for parameter_name in keywords_names ] if inspect._VAR_KEYWORD in signature_data: variadic_keyword_name, = signature_data[inspect._VAR_KEYWORD] variadic_keyword_node = ast.keyword( None, ast.Name(variadic_keyword_name, ast.Load())) keyword_arguments.append(variadic_keyword_node) return [ ast.Return( ast.Call(ast.Name(class_parameter_name, ast.Load()), positional_arguments, keyword_arguments)) ]
def _create_args(self, stmt: param_stmt.ParametrizedStatement) -> List[ast.expr]: """Creates the positional arguments, i.e., POSITIONAL_ONLY, POSITIONAL_OR_KEYWORD and VAR_POSITIONAL. Args: stmt: The parameterised statement Returns: A list of AST statements """ args: List[ast.expr] = [] gen_callable: GenericCallableAccessibleObject = cast( GenericCallableAccessibleObject, stmt.accessible_object()) for param_name in gen_callable.inferred_signature.parameters: if param_name in stmt.args: param_kind = gen_callable.inferred_signature.signature.parameters[ param_name].kind if param_kind in ( Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD, ): args.append( au.create_var_name(self._variable_names, stmt.args[param_name], True)) elif param_kind == Parameter.VAR_POSITIONAL: # Append *args, if necessary. args.append( ast.Starred( value=au.create_var_name(self._variable_names, stmt.args[param_name], True), ctx=ast.Load(), )) return args
def _storeize(self, expr, name, func=None): """Return a new `name` object with an ast.Store() context""" if not func: func = ast.Store if isinstance(name, Result): if not name.is_expr(): raise self._syntax_error( expr, "Can't assign or delete a non-expression") name = name.expr if isinstance(name, (ast.Tuple, ast.List)): typ = type(name) new_elts = [] for x in name.elts: new_elts.append(self._storeize(expr, x, func)) new_name = typ(elts=new_elts) elif isinstance(name, ast.Name): new_name = ast.Name(id=name.id) elif isinstance(name, ast.Subscript): new_name = ast.Subscript(value=name.value, slice=name.slice) elif isinstance(name, ast.Attribute): new_name = ast.Attribute(value=name.value, attr=name.attr) elif isinstance(name, ast.Starred): new_name = ast.Starred( value=self._storeize(expr, name.value, func)) else: raise self._syntax_error( expr, "Can't assign or delete a " + ("constant" if isinstance( name, ast.Constant) else type(expr).__name__)) new_name.ctx = func() ast.copy_location(new_name, name) return new_name
def add_before_call_used_args_capturing_call(call_code, node, all_source_code): """ When a method is called, capture the arguments of the method before executing it """ old_args_nodes_ast = ast.List(node.args, ctx=ast.Load()) old_args_code = ast.List([ ast.Constant(n=ast.get_source_segment(all_source_code, arg), kind=None) for arg in node.args ], ctx=ast.Load()) new_args_node = ast.Starred(value=ast.Call( func=ast.Name(id='before_call_used_args', ctx=ast.Load()), args=[ ast.Constant(n=False, kind=None), ast.Constant(n=call_code, kind=None), old_args_code, ast.Constant(n=node.lineno, kind=None), ast.Constant(n=node.col_offset, kind=None), ast.Constant(n=node.end_lineno, kind=None), ast.Constant(n=node.end_col_offset, kind=None), ast.Constant(n=False, kind=None), old_args_nodes_ast ], keywords=[]), ctx=ast.Load()) node.args = [new_args_node]
def _to_custom_constructor_body( signature_data: SignatureData, class_parameter_name: str = CLASS_PARAMETER_NAME, positional_kinds: Sequence[inspect._ParameterKind] = ( inspect._POSITIONAL_ONLY, inspect._POSITIONAL_OR_KEYWORD) ) -> List[ast.stmt]: positionals = flatten( signature_data.get(kind, []) for kind in positional_kinds) keywords = signature_data.get(inspect._KEYWORD_ONLY, []) positional_arguments = [ _to_loaded_name(parameter_name) for parameter_name, *_ in positionals ] if inspect._VAR_POSITIONAL in signature_data: (variadic_positional_name, *_), = (signature_data[inspect._VAR_POSITIONAL]) variadic_positional_node = ast.Starred( _to_loaded_name(variadic_positional_name), ast.Load()) positional_arguments.append(variadic_positional_node) keyword_arguments = [ ast.keyword(name, _to_loaded_name(name)) for name, _, is_callable in keywords ] if inspect._VAR_KEYWORD in signature_data: (variadic_keyword_name, *_), = signature_data[inspect._VAR_KEYWORD] variadic_keyword_node = ast.keyword( None, _to_loaded_name(variadic_keyword_name)) keyword_arguments.append(variadic_keyword_node) return [ ast.Return( ast.Call(_to_loaded_name(class_parameter_name), positional_arguments, keyword_arguments)) ]
def Call(*, func, args, keywords, starargs, kwargs, lineno=None, col_offset=None): if flags.PY3_VERSION >= 5: if starargs is not None: args += [ast.Starred(starargs, ast.Load())] if kwargs is not None: keywords += [ast.keyword(arg=None, value=kwargs)] if lineno is not None and col_offset is not None: return ast.Call(func=func, args=args, keywords=keywords, lineno=lineno, col_offset=col_offset) else: return ast.Call(func=func, args=args, keywords=keywords) else: return ast.Call(func=func, args=args, keywords=keywords, starargs=starargs, kwargs=kwargs, lineno=lineno, col_offset=col_offset)
def run(self, interpreter: Interpreter): args = interpreter.stack.pop() class_type = interpreter.stack.pop() if isinstance(args, ast.Tuple): interpreter.stack.append(ast.Call(class_type, list(args.elts), [])) else: interpreter.stack.append( ast.Call(class_type, [ast.Starred(args)], []))
def visit_Call(self, node): """ """ # f(x, y, z) --> (lambda info, call: call)( # wrapper # (lambda: info)(), # banner # (lambda: f)()( # function # (lambda: x)(), # arg # (lambda: y)(), # arg # (lambda: z)(), # arg # ), # ) if self.is_exempt(node): self.generic_visit(node) return node banner_call = self.insert_eager_call( node.lineno, constants.INNER_CALL_LINENO, banner.FunctionCallBanner(self.preprocessor.code, node).summary, ) self.generic_visit(node) function_call = ast.Call( func=self.insert_eager_call( node.func.lineno, constants.FN_WRAPPER_LINENO, node.func, ), args=[(ast.Starred( value=self.insert_lazy_call( arg.value.lineno, constants.RG_WRAPPER_LINENO, ('arg', arg.value), ), ctx=ast.Load(), ) if isinstance(arg, ast.Starred) else self.insert_lazy_call( arg.lineno, constants.RG_WRAPPER_LINENO, ('arg', arg), )) for arg in node.args], keywords=[ ast.keyword(arg=keyword.arg, value=self.insert_lazy_call( keyword.value.lineno, constants.RG_WRAPPER_LINENO, ('arg', keyword.value), )) for keyword in node.keywords ], lineno=node.lineno, ) wrapper_call = self.insert_lazy_call( node.lineno, constants.PG_WRAPPER_LINENO, ('info', banner_call), ('call', function_call), ) return wrapper_call
def ClassDef(*, name, bases, keywords, starargs, kwargs, body, decorator_list, lineno=None, col_offset=None): if flags.PY_VERSION == 2: # Ignore keywords and starargs, they shouldnt be there in the first place if Py2 return ast.ClassDef(name=name, bases=bases, body=body, decorator_list=decorator_list, lineno=lineno, col_offset=col_offset) elif flags.PY_VERSION == 3: if flags.PY3_VERSION >= 5: if starargs is not None: bases += [ast.Starred(starargs, ast.Load())] if kwargs is not None: keywords += [ast.keyword(arg=None, value=kwargs)] if lineno is not None and col_offset is not None: return ast.ClassDef(name=name, bases=bases, keywords=keywords, body=body, decorator_list=decorator_list, lineno=lineno, col_offset=col_offset) else: return ast.ClassDef(name=name, bases=bases, keywords=keywords, body=body, decorator_list=decorator_list) else: if lineno is not None and col_offset is not None: return ast.ClassDef(name=name, bases=bases, keywords=keywords, starargs=starargs, kwargs=kwargs, body=body, decorator_list=decorator_list, lineno=lineno, col_offset=col_offset) else: return ast.ClassDef(name=name, bases=bases, keywords=keywords, starargs=starargs, kwargs=kwargs, body=body, decorator_list=decorator_list)
def visit_Assign(self, node): rhs_visitor = RHSVisitor() rhs_visitor.visit(node.value) if isinstance(node.targets[0], (ast.Tuple, ast.List)): # x,y = [1,2] if isinstance(node.value, (ast.Tuple, ast.List)): return self.assign_tuple_target( node.targets[0].elts, node.value.elts, rhs_visitor.result ) elif isinstance(node.value, ast.Call): call = None for element in node.targets[0].elts: label = LabelVisitor() label.visit(element) call = self.assignment_call_node(label.result, node) return call elif isinstance( node.value, ast.Name ): # Treat `x, y = z` like `x, y = (*z,)` value_node = ast.Starred(node.value, ast.Load()) ast.copy_location(value_node, node) return self.assign_tuple_target( node.targets[0].elts, [value_node], rhs_visitor.result ) else: label = LabelVisitor() label.visit(node) return self.append_node( AssignmentNode( label.result, label.result, node, rhs_visitor.result, path=self.filenames[-1], ) ) elif len(node.targets) > 1: # x = y = 3 return self.assign_multi_target(node, rhs_visitor.result) else: if isinstance(node.value, ast.Call): # x = call() label = LabelVisitor() label.visit(node.targets[0]) return self.assignment_call_node(label.result, node) else: # x = 4 label = LabelVisitor() label.visit(node) return self.append_node( AssignmentNode( label.result, extract_left_hand_side(node.targets[0]), node, rhs_visitor.result, path=self.filenames[-1], ) )
def __build__init(self): super_func_call = ast.Call(func=ast.Name(id='super', ctx=ast.Load()), args=[], keywords=[]) if (sys.version_info[0], sys.version_info[1]) == (3, 5) or \ (sys.version_info[0], sys.version_info[1]) == (3, 6) or \ (sys.version_info[0], sys.version_info[1]) == (3, 7) or \ (sys.version_info[0], sys.version_info[1]) == (3, 8): super_func = ast.Call( func=ast.Attribute(value=super_func_call, attr='__init__', ctx=ast.Load()), args=[ast.Starred(value=ast.Name(id='args', ctx=ast.Load()), ctx=ast.Load())], keywords=[ast.keyword(arg=None, value=ast.Name(id='kwargs', ctx=ast.Load()), ctx=ast.Load())], ) elif (sys.version_info[0], sys.version_info[1]) == (3,4): super_func = ast.Call( func=ast.Attribute(value=super_func_call, attr='__init__', ctx=ast.Load()), args=[], keywords=[], starargs=ast.Name(id='args', ctx=ast.Load()), kwargs=ast.Name(id='kwargs', ctx=ast.Load()), ) else: print("Version:", sys.version_info) raise RuntimeError("This script only functions on python 3.4, 3.5, 3.6, or 3.7. Active python version {}.{}".format(*sys.version_info)) super_init = ast.Expr( value=super_func, lineno = self.__get_line(), col_offset = 0, ) body = [super_init] sig = ast.arguments( args=[ast.arg('self', None)], vararg=ast.arg(arg='args', annotation=None), kwarg=ast.arg(arg='kwargs', annotation=None), varargannotation=None, posonlyargs=[], kwonlyargs=[], kwargannotation=None, defaults=[], kw_defaults=[]) func = ast.FunctionDef( name = "__init__", args = sig, body = body, decorator_list = [], lineno = self.__get_line(), col_offset = 0, ) return func
def visit_Assign(self, node): rhs_visitor = RHSVisitor() rhs_visitor.visit(node.value) if isinstance(node.targets[0], (ast.Tuple, ast.List)): # x,y = [1,2] if isinstance(node.value, (ast.Tuple, ast.List)): return self.assign_tuple_target(node.targets[0].elts, node.value.elts, rhs_visitor.result) elif isinstance(node.value, ast.Call): call = None for element in node.targets[0].elts: label = LabelVisitor() label.visit(element) call = self.assignment_call_node(label.result, node) return call elif isinstance(node.value, ast.Name): # Treat `x, y = z` like `x, y = (*z,)` value_node = ast.Starred(node.value, ast.Load()) ast.copy_location(value_node, node) return self.assign_tuple_target(node.targets[0].elts, [value_node], rhs_visitor.result) else: label = LabelVisitor() label.visit(node) log.warn( 'Assignment not properly handled in %s. Could result in not finding a vulnerability.' 'Assignment: %s', getattr(self, 'filenames', ['?'])[0], self.label.result, ) return self.append_node( AssignmentNode(label.result, label.result, node, rhs_visitor.result, path=self.filenames[-1])) elif len(node.targets) > 1: # x = y = 3 return self.assign_multi_target(node, rhs_visitor.result) else: if isinstance(node.value, ast.Call): # x = call() label = LabelVisitor() label.visit(node.targets[0]) return self.assignment_call_node(label.result, node) else: # x = 4 label = LabelVisitor() label.visit(node) return self.append_node( AssignmentNode(label.result, extract_left_hand_side(node.targets[0]), node, rhs_visitor.result, path=self.filenames[-1]))
def run(self, interpreter: Interpreter): args = interpreter.stack.pop() func = interpreter.stack.pop() if isinstance(args, ast.Tuple): call = ast.Call(func, list(args.elts), []) else: call = ast.Call(func, [ast.Starred(args)], []) # Any call to reduce can have global side effects, since it runs arbitrary Python code. # However, if we just save it to the stack, then it might not make it to the final AST unless the stack # value is actually used. So save the result to a temp variable, and then put that on the stack: var_name = interpreter.new_variable(call) interpreter.stack.append(ast.Name(var_name, ast.Load()))
def _node_with_binop(node: ast.AST, binop: ast.BinOp) -> ast.expr: if isinstance(node, ast.Call): node.args = [ast.Starred(value=binop, ctx=ast.Load())] return node elif isinstance(node, ast.List): # NOTE (mb 2018-06-29): Operands of the binop are always lists return binop elif isinstance(node, ast.Set): return ast.Call(func=ast.Name(id="set", ctx=ast.Load()), args=[binop], keywords=[]) elif isinstance(node, ast.Tuple): return ast.Call(func=ast.Name(id="tuple", ctx=ast.Load()), args=[binop], keywords=[]) else: raise TypeError(f"Unexpected node type {type(node)}")
def function_body_to_z3(self, func): argpairs = [(a.value.arg, True) if type(a) == ast.Starred else (a.arg, False) for a in func.args.args] argnames = [a.arg for a in func.args.args] argvars = [z3.Const(name, Unk) for name in argnames] arg_name_to_var = dict(zip(argnames, argvars)) arg_name_to_def = {name: ast.arg(arg=name) for name in argnames} self.scopes.append(arg_name_to_def) for name, definition in arg_name_to_def.items(): self.env.refs[definition] = arg_name_to_var[name] z3body = self.visit(func.body) self.scopes.pop() z3vars = [ ast.Starred( value=arg_name_to_var[n]) if is_starred else arg_name_to_var[n] for n, is_starred in argpairs ] return z3body, z3vars
def visit_argument(self, arg_value, arg_name=None, nstars=0): """ Rewrite AST node appearing as function argument. """ # Unpack starred expression in Python 3.5+. starred = ast_has_starred and isinstance(arg_value, ast.Starred) if starred: arg_value = arg_value.value nstars = 1 # Create new call. args = [self.visit_with_state(arg_value, boxed=True)] if arg_name: args += [ast.Str(arg_name)] keywords = [] if nstars: keywords += [ast.keyword('nstars', ast.Num(nstars))] call = to_call(self.tracer_method('trace_argument'), args, keywords) # Repack starred expression in Python 3.5+. if starred: call = ast.Starred(call, ast.Load()) return call
def subv(xbody, iotype, name): xast = ast.parse(xbody, f'{iotype}:{name}.body', 'single').body[0] if isinstance(xast, ast.Assign): if isinstance(xast.value, ast.Compare) and len( xast.value.ops) == 1 and isinstance(xast.value.ops[0], ast.In): # x = y in z -> (lambda x: z)(y) rast: ast.Call = ast.parse('x(y)', f'{iotype}:{name}.replacement_body', 'eval').body # call(...) targets = xast.targets[0] if isinstance(targets, ast.Tuple): targets = targets.elts else: targets = [targets] rast.func = ast.Lambda( ast.arguments([ast.arg(x, None) for x in targets], None, None, None, None, []), (lambda x: x if len(targets) == 1 else ast.Starred(x))( xast.value.comparators[0])) rast.args = [xast.value.left] xast = rast return xast
def set_call_arguments(self, node, args): """Set the arguments for an ast.Call node. On Python 3.5+, the starargs and kwargs attributes does not exists anymore. Parameters ---------- node : ast.Call Node was arguments should be set. args : Arguments Arguments for the function call. """ pos_args = args.args if args.starargs: pos_args += [ast.Starred(value=args.starargs, ctx=Load)] key_args = args.keywords if args.kwargs: key_args += [ast.keyword(arg=None, value=args.kwargs)] node.args = pos_args node.keywords = key_args
def generate_function_call(max_depth=None): args_len = random.randrange(MAX_ARGS_LENGTH) kwargs_len = random.randrange(MAX_ARGS_LENGTH) starred_args = random.choice([False, True]) starred_kwargs = random.choice([False, True]) args = [ generate_expression(max_depth=max_depth - 1) for _ in range(args_len) ] if starred_args: starred = ast.Starred(generate_expression(max_depth=max_depth - 1), ast.Load) args.append(starred) kwargs = [ _generate_keyword(max_depth=max_depth) for _ in range(kwargs_len) ] if starred_kwargs: kwargs.append(_generate_keyword(max_depth=max_depth, starred=True)) name = generate_variable() return ast.Call(func=name, args=args, keywords=kwargs)
def decorator(wrapped): if sys.hexversion < 0x03000000: spec = inspect.getargspec(wrapped) assert spec.varargs is not None varargs = spec.varargs keywords = spec.keywords else: spec = inspect.getfullargspec(wrapped) assert spec.varargs is not None assert spec.kwonlyargs == [] assert spec.kwonlydefaults is None assert spec.annotations == {} varargs = spec.varargs keywords = spec.varkw name = wrapped.__name__ # Example was generated with print ast.dump(ast.parse("def f(a, b, *args, **kwds): # return call_wrapped((a, b), *args, **kwds)"), include_attributes=True) # http://code.activestate.com/recipes/578353-code-to-source-and-back/ helped a lot # http://stackoverflow.com/questions/10303248#29927459 if sys.hexversion < 0x03000000: wrapper_ast_args = ast.arguments(args=[ ast.Name(id=a, ctx=ast.Param(), lineno=1, col_offset=0) for a in spec.args ], vararg=varargs, kwarg=keywords, defaults=[]) else: wrapper_ast_args = ast.arguments( args=[ ast.arg(arg=a, annotation=None, lineno=1, col_offset=0) for a in spec.args ], vararg=(None if varargs is None else ast.arg( arg=varargs, annotation=None, lineno=1, col_offset=0)), kwonlyargs=[], kw_defaults=[], kwarg=(None if keywords is None else ast.arg( arg=keywords, annotation=None, lineno=1, col_offset=0)), defaults=[]) wrapped_func = ast.Name(id="wrapped", ctx=ast.Load(), lineno=1, col_offset=0) wrapped_args = [ ast.Name(id=a, ctx=ast.Load(), lineno=1, col_offset=0) for a in spec.args ] flatten_func = ast.Name(id="flatten", ctx=ast.Load(), lineno=1, col_offset=0) flatten_args = [ ast.Name(id=spec.varargs, ctx=ast.Load(), lineno=1, col_offset=0) ] if sys.hexversion < 0x03050000: return_value = ast.Call( func=wrapped_func, args=wrapped_args, keywords=[], starargs=ast.Call(func=flatten_func, args=flatten_args, keywords=[], starargs=None, kwargs=None, lineno=1, col_offset=0), kwargs=(None if keywords is None else ast.Name( id=keywords, ctx=ast.Load(), lineno=1, col_offset=0)), lineno=1, col_offset=0) else: return_value = ast.Call( func=wrapped_func, args=wrapped_args + [ ast.Starred(value=ast.Call(func=flatten_func, args=flatten_args, keywords=[], lineno=1, col_offset=0), ctx=ast.Load(), lineno=1, col_offset=0), ], keywords=([] if keywords is None else [ ast.keyword(arg=None, value=ast.Name(id=keywords, ctx=ast.Load(), lineno=1, col_offset=0)) ]), lineno=1, col_offset=0) wrapper_ast = ast.Module(body=[ ast.FunctionDef( name=name, args=wrapper_ast_args, body=[ast.Return(value=return_value, lineno=1, col_offset=0)], decorator_list=[], lineno=1, col_offset=0) ]) wrapper_code = [ c for c in compile(wrapper_ast, "<ast_in_variadic_py>", "exec").co_consts if isinstance(c, types.CodeType) ][0] wrapper = types.FunctionType(wrapper_code, { "wrapped": wrapped, "flatten": flatten }, argdefs=spec.defaults) functools.update_wrapper(wrapper, wrapped) return wrapper
def visit_Starred(self, node): result = self.visit(node.value) return ast.Starred(result, node.ctx)
def test_Starred(self): self.verify(ast.Starred(ast.Name('X', ast.Store()), ast.Store()), '*X')
def test_starred(self): left = ast.List([ast.Starred(ast.Name("x", ast.Load()), ast.Store())], ast.Store()) assign = ast.Assign([left], ast.Num(4)) self.stmt(assign, "must have Store context")
ast.ExceptHandler(type=None), ast.ExceptHandler(type=1), ]), "must be placed last", ), ( ast.Module([1, 2, ast.ImportFrom("__future__")]), "must occur at the top", ), ( ast.Module( [ast.ImportFrom("__future__", names=[ast.alias(name="lol")])]), "'lol' is not defined", ), ( ast.Assign(targets=[ast.Starred(), ast.Starred()]), "More then one starred expression", ), ( ast.Assign(targets=([ast.Name("i")] * 500 + [ast.Starred()])), "Too many expressions", ), ( ast.Assign(targets=([ast.Name("i")] * 500 + [ast.Starred()])), "Too many expressions", ), (ast.comprehension(is_async=1), "inside of a coroutine"), (ast.Yield(), "inside of a function"), ( ast.AsyncFunctionDef(body=[ast.YieldFrom()]), "can't be used in a coroutine",
def p_star_expr(self, p): ''' star_expr : STAR expr ''' # We can assume Load as we will explicitely set Store p[0] = ast.Starred(value=p[2], ctx=Load)
def visit_Starred(self, starred: ast.Starred) -> Tuple[ast.Starred, str]: # A Starred node can appear in a function call. res, expl = self.visit(starred.value) new_starred = ast.Starred(res, starred.ctx) return new_starred, "*" + expl
def variadic_value(self, value): return value[0], ast.Starred(value[1], ast.Load())
def visit_Starred(self, starred): # From Python 3.5, a Starred node can appear in a function call res, expl = self.visit(starred.value) new_starred = ast.Starred(res, starred.ctx) return new_starred, "*" + expl
def generate(self, element, GC: GenerationContext): from anoky.generation.util import expr_wrap acode = element.code if isinstance(acode, Form): head = acode.first headcode = head.code if isinstance( headcode, Identifier) and headcode.full_name in GC.special_forms: head.color = colors.SPECIAL_FORM hcname = headcode.full_name special_form = GC.special_forms[hcname] generated_code = special_form.generate(element, GC) return generated_code else: # function call # #(func arg1 arg2 arg3 ...) func_element = head #func_element_code = headcode with GC.let(domain=ExDom): func_code = GC.generate(func_element) arg_elements = acode[1:] args = [] keywords = [] for arg_element in arg_elements: arg_element_code = arg_element.code if isinstance(arg_element_code, Form): if is_form(arg_element_code, '='): # keyword argument kw_name = arg_element_code[1].code.full_name with GC.let(domain=ExDom): value_code = GC.generate(arg_element_code[2]) keywords.append(ast.keyword(kw_name, value_code)) elif is_form(arg_element_code, '*') and len(arg_element_code) == 2: # stared argument - expand as list with GC.let(domain=ExDom): arg_code = GC.generate(arg_element_code[1]) args.append(ast.Starred(arg_code, ast.Load())) elif is_form(arg_element_code, '**') and len(arg_element_code) == 2: # double starred argument - expand as kwlist assert len(arg_element_code) == 2 # verify no other dblstars already? with GC.let(domain=ExDom): arg_code = GC.generate(arg_element_code[1]) keywords.append(ast.keyword(None, arg_code)) else: # positional argument with GC.let(domain=ExDom): arg_code = GC.generate(arg_element) args.append(arg_code) else: # arg_element_code not a Form # then generate as expression with GC.let(domain=ExDom): arg_code = GC.generate(arg_element) args.append(arg_code) return expr_wrap(ast.Call(func_code, args, keywords), GC) if isinstance(acode, Seq): seq_codes = [] with GC.let(domain=ExDom): for e in acode: seq_codes.append(GC.generate(e)) if GC.domain == LVDom: return ast.Tuple(seq_codes, ast.Store()) elif GC.domain in [ExDom, SDom]: return expr_wrap(ast.Tuple(seq_codes, ast.Load()), GC) else: raise CodeGenerationError( acode.range, "Unexpected seq in domain `%s`." % str(GC.domain)) if isinstance(acode, Literal): element.color = colors.LITERAL if acode.type is str: return expr_wrap(ast.Str(acode.value), GC) elif acode.type in [int, float]: return expr_wrap(ast.Num(acode.value), GC) else: assert False if isinstance(acode, Identifier): if acode.full_name == "True": return expr_wrap(ast.NameConstant(True), GC) elif acode.full_name == "False": return expr_wrap(ast.NameConstant(False), GC) elif acode.full_name == "None": return expr_wrap(ast.NameConstant(None), GC) elif acode.full_name in GC.special_forms: element.color = colors.SPECIAL_FORM raise CodeGenerationError( acode.range, "Refering to special form `%s` by name requires the use of `the`." % acode.full_name) # elif acode.full_name in GC.macros: # raise CodeGenerationError(acode.range, # "Refering to macro `%s` by name requires the use of `the`." % acode.full_name) # elif acode.full_name in GC.id_macros: # raise CodeGenerationError(acode.range, # "Refering to identifier macro `%s` by name requires the use of `the`." % acode.full_name) elif GC.domain == LVDom: return ast.Name(acode.full_name, ast.Store()) elif GC.domain == DelDom: return ast.Name(acode.full_name, ast.Del()) else: return expr_wrap(ast.Name(acode.full_name, ast.Load()), GC)