def generate_inline_function(code, variables, variables_2, memory_allocator): ast_code = parse_to_ast(code) # Annotate the AST with a temporary old (i.e. typecheck) namespace namespace = Namespace() namespace.update(variables_2) with override_global_namespace(namespace): # Initialise a placeholder `FunctionDef` AST node and corresponding # `ContractFunction` type to rely on the annotation visitors in semantics # module. fn_node = vy_ast.FunctionDef() fn_node.body = [] fn_node.args = vy_ast.arguments(defaults=[]) fn_node._metadata["type"] = ContractFunction( "sqrt_builtin", {}, 0, 0, None, FunctionVisibility.INTERNAL, StateMutability.NONPAYABLE) sv = FunctionNodeVisitor(ast_code, fn_node, namespace) for n in ast_code.body: sv.visit(n) new_context = Context(vars_=variables, global_ctx=GlobalContext(), memory_allocator=memory_allocator) generated_ir = parse_body(ast_code.body, new_context) # strip source position info from the generated_ir since # it doesn't make any sense (e.g. the line numbers will start from 0 # instead of where we are in the code) # NOTE if we ever use this for inlining user-code, it would make # sense to fix the offsets of the source positions in the generated # code instead of stripping them. _strip_source_pos(generated_ir) return new_context, generated_ir
def mk_full_signature_from_json(abi): funcs = [func for func in abi if func["type"] == "function"] sigs = [] for func in funcs: args = [] returns = None for a in func["inputs"]: arg = vy_ast.arg( arg=a["name"], annotation=abi_type_to_ast(a["type"], 1048576), lineno=0, col_offset=0, ) args.append(arg) if len(func["outputs"]) == 1: returns = abi_type_to_ast(func["outputs"][0]["type"], 1) elif len(func["outputs"]) > 1: returns = vy_ast.Tuple(elements=[ abi_type_to_ast(a["type"], 1) for a in func["outputs"] ]) decorator_list = [vy_ast.Name(id="external")] # Handle either constant/payable or stateMutability field if ("constant" in func and func["constant"]) or ("stateMutability" in func and func["stateMutability"] == "view"): decorator_list.append(vy_ast.Name(id="view")) if ("payable" in func and func["payable"]) or ("stateMutability" in func and func["stateMutability"] == "payable"): decorator_list.append(vy_ast.Name(id="payable")) sig = FunctionSignature.from_definition( code=vy_ast.FunctionDef( name=func["name"], args=vy_ast.arguments(args=args), decorator_list=decorator_list, returns=returns, ), custom_structs=dict(), constants=Constants(), is_from_json=True, ) sigs.append(sig) return sigs
def mk_full_signature_from_json(abi): funcs = [func for func in abi if func['type'] == 'function'] sigs = [] for func in funcs: args = [] returns = None for a in func['inputs']: arg = ast.arg( arg=a['name'], annotation=abi_type_to_ast(a['type']), lineno=0, col_offset=0 ) args.append(arg) if len(func['outputs']) == 1: returns = abi_type_to_ast(func['outputs'][0]['type']) elif len(func['outputs']) > 1: returns = ast.Tuple( elts=[ abi_type_to_ast(a['type']) for a in func['outputs'] ] ) decorator_list = [ast.Name(id='public')] if func['constant']: decorator_list.append(ast.Name(id='constant')) if func['payable']: decorator_list.append(ast.Name(id='payable')) sig = FunctionSignature.from_definition( code=ast.FunctionDef( name=func['name'], args=ast.arguments(args=args), decorator_list=decorator_list, returns=returns, ), custom_units=set(), custom_structs=dict(), constants=Constants() ) sigs.append(sig) return sigs
def generate_public_variable_getters(vyper_module: vy_ast.Module) -> None: """ Create getter functions for public variables. Arguments --------- vyper_module : Module Top-level Vyper AST node. """ for node in vyper_module.get_children(vy_ast.AnnAssign, {"annotation.func.id": "public"}): func_type = node._metadata["type"] input_types, return_type = func_type.get_signature() input_nodes = [] # use the annotation node as a base to build the input args and return type # starting with `args[0]` to remove the surrounding `public()` call` annotation = copy.deepcopy(node.annotation.args[0]) # the base return statement is an `Attribute` node, e.g. `self.<var_name>` # for each input type we wrap it in a `Subscript` to access a specific member return_stmt: vy_ast.VyperNode = vy_ast.Attribute( value=vy_ast.Name(id="self"), attr=func_type.name ) for i, type_ in enumerate(input_types): if not isinstance(annotation, vy_ast.Subscript): # if we get here something has failed in type checking raise CompilerPanic("Mismatch between node and input type while building getter") if annotation.value.get("id") == "HashMap": # type: ignore # for a HashMap, split the key/value types and use the key type as the next arg arg, annotation = annotation.slice.value.elements # type: ignore else: # for other types, build an input arg node from the expected type # and remove the outer `Subscript` from the annotation arg = vy_ast.Name(id=type_._id) annotation = annotation.value input_nodes.append(vy_ast.arg(arg=f"arg{i}", annotation=arg)) # wrap the return statement in a `Subscript` return_stmt = vy_ast.Subscript( value=return_stmt, slice=vy_ast.Index(value=vy_ast.Name(id=f"arg{i}")) ) # after iterating the input types, the remaining annotation node is our return type return_node = annotation if isinstance(return_node, vy_ast.Name) and return_node.id != return_type._id: # special case when the return type is an interface # TODO allow interfaces as return types and remove this return_node.id = return_type._id # join everything together as a new `FunctionDef` node, annotate it # with the type, and append it to the existing `Module` node expanded = vy_ast.FunctionDef.from_node( node.annotation, name=func_type.name, args=vy_ast.arguments(args=input_nodes, defaults=[],), body=[vy_ast.Return(value=return_stmt)], decorator_list=[vy_ast.Name(id="external"), vy_ast.Name(id="view")], returns=return_node, ) expanded._metadata["type"] = func_type vyper_module.add_to_body(expanded)