def produce_source_map(code, interface_codes=None): global_ctx = GlobalContext.get_global_context( parser.parse_to_ast(code), interface_codes=interface_codes) asm_list = compile_lll.compile_to_assembly( optimizer.optimize( parse_to_lll(code, runtime_only=True, interface_codes=interface_codes))) c, line_number_map = compile_lll.assembly_to_evm(asm_list) source_map = { "globals": {}, "locals": {}, "line_number_map": line_number_map } source_map["globals"] = { name: serialise_var_rec(var_record) for name, var_record in global_ctx._globals.items() } # Fetch context for each function. lll = parser.parse_tree_to_lll( parser.parse_to_ast(code), code, interface_codes=interface_codes, runtime_only=True, ) contexts = { f.func_name: f.context for f in lll.args[1:] if hasattr(f, "context") } prev_func_name = None for _def in global_ctx._defs: if _def.name != "__init__": func_info = {"from_lineno": _def.lineno, "variables": {}} # set local variables for specific function. context = contexts[_def.name] func_info["variables"] = { var_name: serialise_var_rec(var_rec) for var_name, var_rec in context.vars.items() } source_map["locals"][_def.name] = func_info # set to_lineno if prev_func_name: source_map["locals"][prev_func_name]["to_lineno"] = _def.lineno prev_func_name = _def.name source_map["locals"][_def.name]["to_lineno"] = len(code.splitlines()) return source_map
def __compile(code, interface_codes=None, *args, **kwargs): ast = parser.parse_to_ast(code) lll = parser.parse_tree_to_lll(ast, code, interface_codes=interface_codes, runtime_only=kwargs.get( 'bytecode_runtime', False)) opt_lll = optimizer.optimize(lll) asm = compile_lll.compile_to_assembly(opt_lll) def find_nested_opcode(asm_list, key): if key in asm_list: return True else: sublists = [sub for sub in asm_list if isinstance(sub, list)] return any(find_nested_opcode(x, key) for x in sublists) if find_nested_opcode(asm, 'DEBUG'): print('Please note this code contains DEBUG opcode.') print( 'This will only work in a support EVM. This FAIL on any other nodes.' ) c, line_number_map = compile_lll.assembly_to_evm(asm) return c
def test_basic_grammar(lark_grammar): code = """ a: uint256 b: uint128 """ code_func = """ @public def one_two_three() -> uint256: return 123123123 """ assert lark_grammar.parse(textwrap.dedent(code) + "\n") assert parser.parse_to_ast(textwrap.dedent(code)) assert lark_grammar.parse(textwrap.dedent(code_func) + "\n") assert parser.parse_to_ast(textwrap.dedent(code_func))
def extract_interface_str(code, contract_name, interface_codes=None): sigs = sig_utils.mk_full_signature( parser.parse_to_ast(code), sig_formatter=lambda x, y: (x, y), interface_codes=interface_codes, ) events = [sig for sig, _ in sigs if isinstance(sig, EventSignature)] functions = [sig for sig, _ in sigs if isinstance(sig, FunctionSignature)] out = "" # Print events. for idx, event in enumerate(events): if idx == 0: out += "# Events\n\n" event_args_str = ', '.join([arg.name + ': ' + str(arg.typ) for arg in event.args]) out += f"{event.name}: event({{{event_args_str}}})\n" # Print functions. def render_decorator(sig): o = "\n" if sig.const: o += "@constant\n" if not sig.private: o += "@public\n" return o for idx, func in enumerate(functions): if idx == 0: out += "\n# Functions\n" if not func.private and func.name != '__init__': args = ", ".join([arg.name + ": " + str(arg.typ) for arg in func.args]) out += f"{render_decorator(func)}def {func.name}({args}){render_return(func)}:\n pass\n" # noqa: E501 out += "\n" return out
def generate_inline_function(code, variables, memory_allocator): ast_code = parse_to_ast(code) new_context = Context(vars=variables, global_ctx=GlobalContext(), memory_allocator=memory_allocator, origcode=code) generated_lll = parse_body(ast_code, new_context) return new_context, generated_lll
def mk_full_signature(code, *args, **kwargs): abi = parser.mk_full_signature(parser.parse_to_ast(code), *args, **kwargs) # Add gas estimates for each function to ABI gas_estimates = gas_estimate(code, *args, **kwargs) for idx, func in enumerate(abi): func_name = func.get('name', '').split('(')[0] # Skip __init__, has no estimate if func_name in gas_estimates: abi[idx]['gas'] = gas_estimates[func_name] return abi
def extract_sigs(sig_code): if sig_code['type'] == 'vyper': return parser.mk_full_signature(parser.parse_to_ast(sig_code['code']), sig_formatter=lambda x, y: x) elif sig_code['type'] == 'json': return mk_full_signature_from_json(sig_code['code']) else: raise Exception( ("Unknown interface signature type '{}' supplied. " "'vyper' & 'json' are supported").format(sig_code['type']))
def produce_source_map(code): global_ctx = GlobalContext.get_global_context(parser.parse_to_ast(code)) asm_list = compile_lll.compile_to_assembly( optimizer.optimize(parse_to_lll(code, runtime_only=True))) c, line_number_map = compile_lll.assembly_to_evm(asm_list) source_map = { 'globals': {}, 'locals': {}, 'line_number_map': line_number_map } source_map['globals'] = { name: serialise_var_rec(var_record) for name, var_record in global_ctx._globals.items() } # Fetch context for each function. lll = parser.parse_tree_to_lll(parser.parse_to_ast(code), code, runtime_only=True) contexts = { f.func_name: f.context for f in lll.args[1:] if hasattr(f, 'context') } prev_func_name = None for _def in global_ctx._defs: if _def.name != '__init__': func_info = {'from_lineno': _def.lineno, 'variables': {}} # set local variables for specific function. context = contexts[_def.name] func_info['variables'] = { var_name: serialise_var_rec(var_rec) for var_name, var_rec in context.vars.items() } source_map['locals'][_def.name] = func_info # set to_lineno if prev_func_name: source_map['locals'][prev_func_name]['to_lineno'] = _def.lineno prev_func_name = _def.name source_map['locals'][_def.name]['to_lineno'] = len(code.splitlines()) return source_map
def extract_file_interface_imports(code): ast_tree = parser.parse_to_ast(code) imports_dict = {} for item in ast_tree: if isinstance(item, ast.Import): for a_name in item.names: if not a_name.asname: raise StructureException('Interface statement requires an accompanying `as` statement.', item) if a_name.asname in imports_dict: raise StructureException('Interface with Alias {} already exists'.format(a_name.asname), item) imports_dict[a_name.asname] = a_name.name return imports_dict
def extract_sigs(sig_code): if sig_code['type'] == 'vyper': interface_ast = parser.parse_to_ast(sig_code['code']) return sig_utils.mk_full_signature( [i for i in interface_ast if not isinstance(i, (ast.Import, ast.ImportFrom))], sig_formatter=lambda x, y: x ) elif sig_code['type'] == 'json': return mk_full_signature_from_json(sig_code['code']) else: raise Exception( (f"Unknown interface signature type '{sig_code['type']}' supplied. " "'vyper' & 'json' are supported") )
def extract_sigs(sig_code): if sig_code['type'] == 'vyper': interface_ast = [ i for i in parser.parse_to_ast(sig_code['code']) if isinstance(i, ast.FunctionDef) or ( isinstance(i, ast.AnnAssign) and i.target.id != "implements") ] return sig_utils.mk_full_signature(interface_ast, sig_formatter=lambda x, y: x) elif sig_code['type'] == 'json': return mk_full_signature_from_json(sig_code['code']) else: raise Exception(( f"Unknown interface signature type '{sig_code['type']}' supplied. " "'vyper' & 'json' are supported"))
def mk_full_signature(code, *args, **kwargs): abi = parser.mk_full_signature(parser.parse_to_ast(code), *args, **kwargs) # Add gas estimates for each function to ABI gas_estimates = gas_estimate(code, *args, **kwargs) for func in abi: try: func_signature = func['name'] except KeyError: # constructor and fallback functions don't have a name continue func_name, _, _ = func_signature.partition('(') # This check ensures we skip __init__ since it has no estimate if func_name in gas_estimates: # TODO: mutation func['gas'] = gas_estimates[func_name] return abi
def extract_file_interface_imports(code: SourceCode) -> InterfaceImports: ast_tree = parser.parse_to_ast(code) imports_dict: InterfaceImports = {} for item in ast_tree: if isinstance(item, ast.Import): for a_name in item.names: # type: ignore if not a_name.asname: raise StructureException( 'Interface statement requires an accompanying `as` statement.', item, ) if a_name.asname in imports_dict: raise StructureException( f'Interface with alias {a_name.asname} already exists', item, ) imports_dict[a_name.asname] = a_name.name.replace('.', '/') elif isinstance(item, ast.ImportFrom): for a_name in item.names: # type: ignore if a_name.asname: raise StructureException("From imports cannot use aliases", item) level = item.level # type: ignore module = item.module or "" # type: ignore if not level and module == 'vyper.interfaces': continue base_path = "" if level > 1: base_path = "../" * (level - 1) elif level == 1: base_path = "./" base_path = f"{base_path}{module.replace('.','/')}/" for a_name in item.names: # type: ignore if a_name.name in imports_dict: raise StructureException( f'Interface with name {a_name.name} already exists', item, ) imports_dict[a_name.name] = f"{base_path}{a_name.name}" return imports_dict
def extract_external_interface(code, contract_name): sigs = parser.mk_full_signature(parser.parse_to_ast(code), sig_formatter=lambda x, y: (x, y)) functions = [sig for sig, _ in sigs if isinstance(sig, FunctionSignature)] cname = os.path.basename(contract_name).split('.')[0].capitalize() out = "" offset = 4 * " " for idx, func in enumerate(functions): if idx == 0: out += "\n# External Contracts\ncontract %s:\n" % cname if not func.private and func.name != '__init__': out += offset + "def {name}({args}){ret}: {func_type}\n".format( name=func.name, args=", ".join([arg.name + ": " + str(arg.typ) for arg in func.args]), ret=render_return(func), func_type="constant" if func.const else "modifying", ) out += "\n" return out
def extract_external_interface(code, contract_name, interface_codes=None): sigs = sig_utils.mk_full_signature( parser.parse_to_ast(code), sig_formatter=lambda x, y: (x, y), interface_codes=interface_codes, ) functions = [sig for sig, _ in sigs if isinstance(sig, FunctionSignature)] cname = Path(contract_name).stem.capitalize() out = "" offset = 4 * " " for idx, func in enumerate(functions): if idx == 0: out += f"\n# External Contracts\ncontract {cname}:\n" if not func.private and func.name != '__init__': args = ", ".join([arg.name + ": " + str(arg.typ) for arg in func.args]) func_type = "constant" if func.const else "modifying" out += offset + f"def {func.name}({args}){render_return(func)}: {func_type}\n" out += "\n" return out
def mk_method_identifiers(code, interface_codes=None): from vyper.parser.parser import parse_to_ast o = {} global_ctx = GlobalContext.get_global_context( parse_to_ast(code), interface_codes=interface_codes, ) for code in global_ctx._defs: sig = FunctionSignature.from_definition( code, sigs=global_ctx._contracts, custom_units=global_ctx._custom_units, constants=global_ctx._constants, ) if not sig.private: default_sigs = generate_default_arg_sigs(code, global_ctx._contracts, global_ctx) for s in default_sigs: o[s.sig] = hex(s.method_id) return o
def extract_interface_str(code, contract_name): sigs = parser.mk_full_signature(parser.parse_to_ast(code), sig_formatter=lambda x, y: (x, y)) events = [sig for sig, _ in sigs if isinstance(sig, EventSignature)] functions = [sig for sig, _ in sigs if isinstance(sig, FunctionSignature)] out = "" # Print events. for idx, event in enumerate(events): if idx == 0: out += "# Events\n\n" out += "{event_name}: event({{{args}}})\n".format( event_name=event.name, args=", ".join([arg.name + ": " + str(arg.typ) for arg in event.args]) ) # Print functions. def render_decorator(sig): o = "\n" if sig.const: o += "@constant\n" if not sig.private: o += "@public\n" return o for idx, func in enumerate(functions): if idx == 0: out += "\n# Functions\n" if not func.private and func.name != '__init__': out += "{decorator}def {name}({args}){ret}:\n pass\n".format( decorator=render_decorator(func), name=func.name, args=", ".join([arg.name + ": " + str(arg.typ) for arg in func.args]), ret=render_return(func) ) out += "\n" return out
def test_grammar_bruteforce(code): if utf8_encodable(code): tree = parser.parse_to_ast(code + "\n") assert isinstance(tree, list)
def _mk_ast_dict(code, contract_name, interface_codes): o = { 'contract_name': contract_name, 'ast': ast_to_dict(parser.parse_to_ast(code)) } return o
def extract_sigs(code): sigs = parser.mk_full_signature(parser.parse_to_ast(code), sig_formatter=lambda x, y: x) return sigs