#include <language/PugsParser.hpp> #include <language/PEGGrammar.hpp> #include <language/ast/ASTBacktrace.hpp> #include <language/ast/ASTBuilder.hpp> #include <language/ast/ASTModulesImporter.hpp> #include <language/ast/ASTNode.hpp> #include <language/ast/ASTNodeDataTypeBuilder.hpp> #include <language/ast/ASTNodeDataTypeChecker.hpp> #include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> #include <language/ast/ASTNodeEmptyBlockCleaner.hpp> #include <language/ast/ASTNodeExpressionBuilder.hpp> #include <language/ast/ASTNodeJumpPlacementChecker.hpp> #include <language/ast/ASTNodeTypeCleaner.hpp> #include <language/ast/ASTSymbolInitializationChecker.hpp> #include <language/ast/ASTSymbolTableBuilder.hpp> #include <language/utils/ASTDotPrinter.hpp> #include <language/utils/ASTExecutionInfo.hpp> #include <language/utils/ASTPrinter.hpp> #include <language/utils/Exit.hpp> #include <language/utils/OperatorRepository.hpp> #include <language/utils/SymbolTable.hpp> #include <utils/ConsoleManager.hpp> #include <utils/ExecutionStatManager.hpp> #include <utils/PugsAssert.hpp> #include <utils/PugsUtils.hpp> #include <utils/SignalManager.hpp> #include <pegtl/contrib/analyze.hpp> #include <pegtl/contrib/parse_tree.hpp> #include <pegtl/contrib/parse_tree_to_dot.hpp> #include <rang.hpp> #include <fstream> #include <iostream> #include <memory> #include <sstream> #include <unordered_map> #include <variant> void parser(const std::string& filename) { const size_t grammar_issues = TAO_PEGTL_NAMESPACE::analyze<language::grammar>(); if (grammar_issues != 0) { std::ostringstream os; os << "invalid grammar: " << rang::fgB::yellow << grammar_issues << rang::fg::reset << " were detected!"; throw UnexpectedError(os.str()); } if (ConsoleManager::showPreamble()) { std::cout << rang::style::bold << "Parsing file " << rang::style::reset << rang::style::underline << filename << rang::style::reset << " ...\n"; } auto parse_and_execute = [](auto& input) { OperatorRepository::create(); ASTBacktrace::create(input); std::unique_ptr<ASTNode> root_node = ASTBuilder::build(*input); ASTModulesImporter module_importer{*root_node}; ASTNodeTypeCleaner<language::import_instruction>{*root_node}; ASTSymbolTableBuilder{*root_node}; ASTSymbolInitializationChecker{*root_node}; ASTNodeDataTypeBuilder{*root_node}; ASTNodeDataTypeChecker{*root_node}; ASTNodeJumpPlacementChecker{*root_node}; // optimizations ASTNodeDeclarationToAffectationConverter{*root_node}; ASTNodeTypeCleaner<language::var_declaration>{*root_node}; ASTNodeTypeCleaner<language::fct_declaration>{*root_node}; ASTNodeEmptyBlockCleaner{*root_node}; ASTNodeExpressionBuilder{*root_node}; if (ConsoleManager::showPreamble()) { std::cout << "-------------------------------------------------------\n"; std::cout << rang::style::bold << "Executing AST..." << rang::style::reset << '\n'; } ASTExecutionInfo execution_info{*root_node, module_importer.moduleRepository()}; ExecutionPolicy exec_all; try { root_node->execute(exec_all); } catch (language::Exit& e) { ExecutionStatManager::getInstance().setExitCode(e.code()); } root_node->m_symbol_table->clearValues(); OperatorRepository::destroy(); }; auto input = std::make_shared<TAO_PEGTL_NAMESPACE::file_input<>>(filename); if (not SignalManager::pauseOnError()) { try { parse_and_execute(input); } catch (const ParseError& e) { const auto p = e.positions().front(); std::string error_specifier = [] { std::ostringstream os; os << rang::style::bold << "error:" << rang::style::reset << ' '; return os.str(); }(); std::string message = e.what(); // This is a cosmetic hack to avoid repetition of "error: " in // output if (message.substr(0, error_specifier.size()) == error_specifier) { message = message.substr(error_specifier.size()); } std::cerr << rang::style::bold << p.source << ':' << p.line << ':' << p.column << ": " << rang::style::reset << rang::fgB::red << "error: " << rang::fg::reset << rang::style::bold << message << rang::style::reset << '\n' << input->line_at(p) << '\n' << std::string(p.column - 1, ' ') << rang::fgB::yellow << '^' << rang::fg::reset << '\n'; finalize(); std::exit(1); } catch (const IExitError& e) { // Each failing process must write std::cerr.clear(); std::cerr << ASTBacktrace::getInstance().errorMessageAt(e.what()) << '\n'; std::exit(1); } } else { parse_and_execute(input); } }