/* This file is part of TON Blockchain Library. TON Blockchain Library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. TON Blockchain Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with TON Blockchain Library. If not, see . */ #pragma once #include "ast.h" #include "platform-utils.h" /* * A module implementing base functionality of read-only traversing a vertex tree. * Since a vertex in general doesn't store a vector of children, iterating is possible only for concrete node_type. * E.g., for ast_if_statement, visit nodes cond, if-body and else-body. For ast_string_const, nothing. And so on. * Visitors below are helpers to inherit from and handle specific vertex types. * * Note, that absence of "children" in ASTNodeBase is not a drawback. Instead, it encourages you to think * about types and match the type system. * * The visitor is read-only, it does not modify visited nodes (except if you purposely call mutating methods). * For example, if you want to replace "beginCell()" call with "begin_cell", a visitor isn't enough for you. * To replace vertices, consider another API: ast-replacer.h. */ namespace tolk { class ASTVisitor { protected: GNU_ATTRIBUTE_ALWAYS_INLINE static void visit_children(const ASTExprLeaf* v) { static_cast(v); } GNU_ATTRIBUTE_ALWAYS_INLINE void visit_children(const ASTExprUnary* v) { visit(v->child); } GNU_ATTRIBUTE_ALWAYS_INLINE void visit_children(const ASTExprBinary* v) { visit(v->lhs); visit(v->rhs); } GNU_ATTRIBUTE_ALWAYS_INLINE void visit_children(const ASTExprVararg* v) { for (AnyExprV child : v->children) { visit(child); } } GNU_ATTRIBUTE_ALWAYS_INLINE void visit_children(const ASTStatementUnary* v) { visit(v->child); } GNU_ATTRIBUTE_ALWAYS_INLINE void visit_children(const ASTStatementVararg* v) { for (AnyV child : v->children) { visit(child); } } GNU_ATTRIBUTE_ALWAYS_INLINE static void visit_children(const ASTOtherLeaf* v) { static_cast(v); } GNU_ATTRIBUTE_ALWAYS_INLINE void visit_children(const ASTOtherVararg* v) { for (AnyV child : v->children) { visit(child); } } virtual void visit(AnyV v) = 0; public: virtual ~ASTVisitor() = default; }; class ASTVisitorFunctionBody : public ASTVisitor { protected: using parent = ASTVisitorFunctionBody; // expressions virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } // statements virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } virtual void visit(V v) { return visit_children(v); } void visit(AnyV v) final { switch (v->type) { // expressions case ast_empty_expression: return visit(v->as()); case ast_parenthesized_expression: return visit(v->as()); case ast_tensor: return visit(v->as()); case ast_typed_tuple: return visit(v->as()); case ast_reference: return visit(v->as()); case ast_local_var_lhs: return visit(v->as()); case ast_local_vars_declaration: return visit(v->as()); case ast_int_const: return visit(v->as()); case ast_string_const: return visit(v->as()); case ast_bool_const: return visit(v->as()); case ast_null_keyword: return visit(v->as()); case ast_argument: return visit(v->as()); case ast_argument_list: return visit(v->as()); case ast_dot_access: return visit(v->as()); case ast_function_call: return visit(v->as()); case ast_underscore: return visit(v->as()); case ast_assign: return visit(v->as()); case ast_set_assign: return visit(v->as()); case ast_unary_operator: return visit(v->as()); case ast_binary_operator: return visit(v->as()); case ast_ternary_operator: return visit(v->as()); case ast_cast_as_operator: return visit(v->as()); // statements case ast_empty_statement: return visit(v->as()); case ast_sequence: return visit(v->as()); case ast_return_statement: return visit(v->as()); case ast_if_statement: return visit(v->as()); case ast_repeat_statement: return visit(v->as()); case ast_while_statement: return visit(v->as()); case ast_do_while_statement: return visit(v->as()); case ast_throw_statement: return visit(v->as()); case ast_assert_statement: return visit(v->as()); case ast_try_catch_statement: return visit(v->as()); #ifdef TOLK_DEBUG case ast_asm_body: throw UnexpectedASTNodeType(v, "ASTVisitor; forgot to filter out asm functions in should_visit_function()?"); #endif default: throw UnexpectedASTNodeType(v, "ASTVisitorFunctionBody::visit"); } } public: virtual bool should_visit_function(const FunctionData* fun_ref) = 0; virtual void start_visiting_function(const FunctionData* fun_ref, V v_function) { visit(v_function->get_body()); } }; const std::vector& get_all_not_builtin_functions(); template void visit_ast_of_all_functions() { BodyVisitorT visitor; for (const FunctionData* fun_ref : get_all_not_builtin_functions()) { if (visitor.should_visit_function(fun_ref)) { visitor.start_visiting_function(fun_ref, fun_ref->ast_root->as()); } } } } // namespace tolk