def process_ast(ast, parents=True, link_identifiers=True, check_return=True, alias_analysis=True, type_check=True): with print_step("Preprocessing AST"): if parents: set_parents(ast) if link_identifiers: try: link(ast) except UnknownIdentifierException as e: raise PreprocessAstException(f'\n\nSYMBOL ERROR: {e}') try: if check_return: r(ast) if alias_analysis: a(ast) call_graph_analysis(ast) compute_modified_sets(ast) check_for_undefined_behavior_due_to_eval_order(ast) except AstException as e: raise AnalysisException(f'\n\nANALYSIS ERROR: {e}') if type_check: with print_step("Zkay type checking"): try: t(ast) check_circuit_compliance(ast) detect_hybrid_functions(ast) check_loops(ast) except (TypeMismatchException, TypeException, RequireException, ReclassifyException) as e: raise TypeCheckException(f'\n\nCOMPILER ERROR: {e}')
def test_symbol_table(self): ast = build_ast(self.example.code()) set_parents(ast) fill_symbol_table(ast) link_identifiers(ast) contract = ast.contracts[0] self.assertEqual(contract.idf.name, self.name)
def test_all_nodes_have_parent(self): ast = build_ast(self.example.code()) set_parents(ast) # test v = ParentChecker() v.visit(ast)
def test_root_children_have_parent(self): ast = build_ast(self.example.code()) set_parents(ast) # test for c in ast.children(): self.assertEqual(c.parent, ast)
def test_contract_identifier(self): ast = build_ast(self.example.code()) set_parents(ast) # test contract = ast.contracts[0] idf = contract.idf self.assertEqual(idf.parent, contract)
def test_link_identifiers(self): ast = build_ast(simple.code()) set_parents(ast) link_identifiers(ast) self.get_ast_elements(ast) self.assertEqual(self.identifier_expr.target, self.decl) self.assertEqual(self.identifier_expr.get_annotated_type(), self.decl.annotated_type)
def test_link_identifiers(self): ast = build_ast(simple_storage.code()) set_parents(ast) link_identifiers(ast) assignment = ast['SimpleStorage']['set'].body[0] self.assertIsInstance(assignment, AssignmentStatement) stored_data = assignment.lhs.target self.assertEqual(stored_data, ast['SimpleStorage']['storedData']) x = assignment.rhs.target self.assertEqual(x.idf.name, 'x')
def transform_ast(ast: SourceUnit) -> Tuple[SourceUnit, Dict[ConstructorOrFunctionDefinition, CircuitHelper]]: """ Convert zkay to solidity AST + proof circuits :param ast: zkay AST :return: solidity AST and dictionary which maps all function definitions which require verification to the corresponding circuit helper instance. """ zt = ZkayTransformer() new_ast = zt.visit(ast) # restore all parent pointers and identifier targets set_parents(new_ast) link_identifiers(new_ast) return new_ast, zt.circuits
def deep_copy(ast: T, with_types=False, with_analysis=False) -> T: """ :param ast: :param with_types: (optional) :return: a deep copy of `ast` Only parents and identifiers are updated in the returned ast (e.g., inferred types are not preserved) """ assert isinstance(ast, AST) v = DeepCopyVisitor(with_types, with_analysis) ast_copy = v.visit(ast) ast_copy.parent = ast.parent set_parents(ast_copy) link_identifiers(ast_copy) return ast_copy
def test_alias_analysis(self): # perform analysis ast = build_ast(analysis.code()) set_parents(ast) link_identifiers(ast) alias_analysis(ast) # generate string, including analysis results v = AnalysisCodeVisitor() s = v.visit(ast) # next statement can be enabled to determine the computed output # print(s) # check output self.maxDiff = None self.assertMultiLineEqual(analysis.code(), re.sub(" +\n", "\n", s.code()))
def _replace_ast(old_ast: AST, new_ast: AST): new_ast.parent = old_ast.parent DeepCopyVisitor.copy_ast_fields(old_ast, new_ast) if old_ast.parent is not None: set_parents(new_ast) link_identifiers(new_ast)
class GlobalDefs: # gasleft: FunctionDefinition = FunctionDefinition( # idf=Identifier('gasleft'), # parameters=[], # modifiers=[], # return_parameters=[Parameter([], annotated_type=AnnotatedTypeName.uint_all(), idf=Identifier(''))], # body=Block([]) # ) # gasleft.idf.parent = gasleft address_struct: StructDefinition = StructDefinition( Identifier('<address>'), [ VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('balance')) ]) set_parents(address_struct) address_payable_struct: StructDefinition = StructDefinition( Identifier('<address_payable>'), [ VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('balance')), ConstructorOrFunctionDefinition( Identifier('send'), [Parameter([], AnnotatedTypeName.uint_all(), Identifier(''))], ['public'], [Parameter([], AnnotatedTypeName.bool_all(), Identifier(''))], Block([])), ConstructorOrFunctionDefinition( Identifier('transfer'), [Parameter([], AnnotatedTypeName.uint_all(), Identifier(''))], ['public'], [], Block([])), ]) address_payable_struct.members[1].can_be_private = False address_payable_struct.members[2].can_be_private = False set_parents(address_payable_struct) msg_struct: StructDefinition = StructDefinition(Identifier('<msg>'), [ VariableDeclaration([], AnnotatedTypeName(TypeName.address_payable_type()), Identifier('sender')), VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('value')), ]) set_parents(msg_struct) block_struct: StructDefinition = StructDefinition(Identifier('<block>'), [ VariableDeclaration([], AnnotatedTypeName(TypeName.address_payable_type()), Identifier('coinbase')), VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('difficulty')), VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('gaslimit')), VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('number')), VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('timestamp')), ]) set_parents(block_struct) tx_struct: StructDefinition = StructDefinition(Identifier('<tx>'), [ VariableDeclaration([], AnnotatedTypeName.uint_all(), Identifier('gasprice')), VariableDeclaration([], AnnotatedTypeName(TypeName.address_payable_type()), Identifier('origin')), ]) set_parents(tx_struct)
def test_alias_analysis(self): # perform analysis ast = build_ast(self.example.code()) set_parents(ast) link_identifiers(ast) alias_analysis(ast)