/* 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 #ifdef TOLK_DEBUG #include "ast.h" #include "ast-visitor.h" #include /* * ASTStringifier is used to print out the whole vertex tree in a human-readable format. * To stringify any vertex, call v->debug_print(), which uses this class. */ namespace tolk { class ASTStringifier final : public ASTVisitor { constexpr static std::pair name_pairs[] = { {ast_empty, "ast_empty"}, {ast_identifier, "ast_identifier"}, {ast_int_const, "ast_int_const"}, {ast_string_const, "ast_string_const"}, {ast_bool_const, "ast_bool_const"}, {ast_nil_tuple, "ast_nil_tuple"}, {ast_function_call, "ast_function_call"}, {ast_parenthesized_expr, "ast_parenthesized_expr"}, {ast_global_var_declaration, "ast_global_var_declaration"}, {ast_global_var_declaration_list, "ast_global_var_declaration_list"}, {ast_constant_declaration, "ast_constant_declaration"}, {ast_constant_declaration_list, "ast_constant_declaration_list"}, {ast_underscore, "ast_underscore"}, {ast_type_expression, "ast_type_expression"}, {ast_variable_declaration, "ast_variable_declaration"}, {ast_tensor, "ast_tensor"}, {ast_tensor_square, "ast_tensor_square"}, {ast_dot_tilde_call, "ast_dot_tilde_call"}, {ast_unary_operator, "ast_unary_operator"}, {ast_binary_operator, "ast_binary_operator"}, {ast_ternary_operator, "ast_ternary_operator"}, {ast_return_statement, "ast_return_statement"}, {ast_sequence, "ast_sequence"}, {ast_repeat_statement, "ast_repeat_statement"}, {ast_while_statement, "ast_while_statement"}, {ast_do_until_statement, "ast_do_until_statement"}, {ast_try_catch_statement, "ast_try_catch_statement"}, {ast_if_statement, "ast_if_statement"}, {ast_forall_item, "ast_forall_item"}, {ast_forall_list, "ast_forall_list"}, {ast_argument, "ast_argument"}, {ast_argument_list, "ast_argument_list"}, {ast_asm_body, "ast_asm_body"}, {ast_function_declaration, "ast_function_declaration"}, {ast_pragma_no_arg, "ast_pragma_no_arg"}, {ast_pragma_version, "ast_pragma_version"}, {ast_include_statement, "ast_include_statement"}, {ast_tolk_file, "ast_tolk_file"}, }; template constexpr static const char* ast_node_type_to_string() { static_assert(std::size(name_pairs) == ast_tolk_file + 1, "name_pairs needs to be updated"); return name_pairs[node_type].second; } int depth = 0; std::string out; bool colored = false; template void handle_vertex(V v) { out += std::string(depth * 2, ' '); out += ast_node_type_to_string(); if (std::string postfix = specific_str(v); !postfix.empty()) { out += colored ? " \x1b[34m" : " // "; out += postfix; out += colored ? "\x1b[0m" : ""; } out += '\n'; depth++; visit_children(v); depth--; } static std::string specific_str(AnyV v) { switch (v->type) { case ast_identifier: return static_cast(v->as()->name); case ast_int_const: return static_cast(v->as()->int_val); case ast_string_const: if (char modifier = v->as()->modifier) { return "\"" + static_cast(v->as()->str_val) + "\"" + std::string(1, modifier); } else { return "\"" + static_cast(v->as()->str_val) + "\""; } case ast_function_call: { if (auto v_lhs = v->as()->get_called_f()->try_as()) { return static_cast(v_lhs->name) + "()"; } return {}; } case ast_global_var_declaration: return static_cast(v->as()->get_identifier()->name); case ast_constant_declaration: return static_cast(v->as()->get_identifier()->name); case ast_type_expression: { std::ostringstream os; os << v->as()->declared_type; return os.str(); } case ast_variable_declaration: { std::ostringstream os; os << v->as()->declared_type; return os.str(); } case ast_dot_tilde_call: return static_cast(v->as()->method_name); case ast_unary_operator: return static_cast(v->as()->operator_name); case ast_binary_operator: return static_cast(v->as()->operator_name); case ast_sequence: return "↓" + std::to_string(v->as()->get_items().size()); case ast_if_statement: return v->as()->is_ifnot ? "ifnot" : ""; case ast_argument: { std::ostringstream os; os << v->as()->arg_type; return static_cast(v->as()->get_identifier()->name) + ": " + os.str(); } case ast_function_declaration: { std::string arg_names; for (int i = 0; i < v->as()->get_num_args(); i++) { if (!arg_names.empty()) arg_names += ","; arg_names += v->as()->get_arg(i)->get_identifier()->name; } return "fun " + static_cast(v->as()->get_identifier()->name) + "(" + arg_names + ")"; } case ast_pragma_no_arg: return static_cast(v->as()->pragma_name); case ast_pragma_version: return static_cast(v->as()->semver); case ast_include_statement: return static_cast(v->as()->get_file_leaf()->str_val); case ast_tolk_file: return v->as()->file->rel_filename; default: return {}; } } public: explicit ASTStringifier(bool colored) : colored(colored) { } std::string to_string_with_children(AnyV v) { out.clear(); visit(v); return std::move(out); } static std::string to_string_without_children(AnyV v) { std::string result = ast_node_type_to_string(v->type); if (std::string postfix = specific_str(v); !postfix.empty()) { result += ' '; result += specific_str(v); } return result; } static const char* ast_node_type_to_string(ASTNodeType node_type) { return name_pairs[node_type].second; } void visit(AnyV v) override { switch (v->type) { case ast_empty: return handle_vertex(v->as()); case ast_identifier: return handle_vertex(v->as()); case ast_int_const: return handle_vertex(v->as()); case ast_string_const: return handle_vertex(v->as()); case ast_bool_const: return handle_vertex(v->as()); case ast_nil_tuple: return handle_vertex(v->as()); case ast_function_call: return handle_vertex(v->as()); case ast_parenthesized_expr: return handle_vertex(v->as()); case ast_global_var_declaration: return handle_vertex(v->as()); case ast_global_var_declaration_list: return handle_vertex(v->as()); case ast_constant_declaration: return handle_vertex(v->as()); case ast_constant_declaration_list: return handle_vertex(v->as()); case ast_underscore: return handle_vertex(v->as()); case ast_type_expression: return handle_vertex(v->as()); case ast_variable_declaration: return handle_vertex(v->as()); case ast_tensor: return handle_vertex(v->as()); case ast_tensor_square: return handle_vertex(v->as()); case ast_dot_tilde_call: return handle_vertex(v->as()); case ast_unary_operator: return handle_vertex(v->as()); case ast_binary_operator: return handle_vertex(v->as()); case ast_ternary_operator: return handle_vertex(v->as()); case ast_return_statement: return handle_vertex(v->as()); case ast_sequence: return handle_vertex(v->as()); case ast_repeat_statement: return handle_vertex(v->as()); case ast_while_statement: return handle_vertex(v->as()); case ast_do_until_statement: return handle_vertex(v->as()); case ast_try_catch_statement: return handle_vertex(v->as()); case ast_if_statement: return handle_vertex(v->as()); case ast_forall_item: return handle_vertex(v->as()); case ast_forall_list: return handle_vertex(v->as()); case ast_argument: return handle_vertex(v->as()); case ast_argument_list: return handle_vertex(v->as()); case ast_asm_body: return handle_vertex(v->as()); case ast_function_declaration: return handle_vertex(v->as()); case ast_pragma_no_arg: return handle_vertex(v->as()); case ast_pragma_version: return handle_vertex(v->as()); case ast_include_statement: return handle_vertex(v->as()); case ast_tolk_file: return handle_vertex(v->as()); default: throw UnexpectedASTNodeType(v, "ASTStringifier::visit"); } } }; } // namespace tolk #endif // TOLK_DEBUG