diff --git a/src/language/ASTBuilder.cpp b/src/language/ASTBuilder.cpp index 1a52ced9dd48d8781eb5c7360f1511c09bf92737..ab30b2aaa2ae3b271d60b29035ea94428989eac0 100644 --- a/src/language/ASTBuilder.cpp +++ b/src/language/ASTBuilder.cpp @@ -260,8 +260,12 @@ using selector = parse_tree::selector<Rule, } // namespace language +template <typename InputT> std::unique_ptr<language::Node> -buildAST(read_input<>& input) +buildAST(InputT& input) { return parse_tree::parse<language::grammar, language::Node, language::selector, nothing, language::errors>(input); } + +template std::unique_ptr<language::Node> buildAST(read_input<>& input); +template std::unique_ptr<language::Node> buildAST(istream_input<>& input); diff --git a/src/language/ASTBuilder.hpp b/src/language/ASTBuilder.hpp index d6ccc2c8b3c974159143bddc84b5349af469eb3d..19adacf161b2a330fb89d4145a82816fec698630 100644 --- a/src/language/ASTBuilder.hpp +++ b/src/language/ASTBuilder.hpp @@ -5,6 +5,10 @@ #include <ASTNode.hpp> -std::unique_ptr<language::Node> buildAST(read_input<>& input); +template <typename InputT> +std::unique_ptr<language::Node> buildAST(InputT& input); + +template <typename InputT> +std::unique_ptr<language::Node> buildAST(InputT& input); #endif // AST_BUILDER_HPP diff --git a/src/language/ASTPrinter.cpp b/src/language/ASTPrinter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..572a97a11a9e48c59599599db941cf43748f72bd --- /dev/null +++ b/src/language/ASTPrinter.cpp @@ -0,0 +1,89 @@ +#include <ASTPrinter.hpp> +#include <EscapedString.hpp> + +namespace language +{ +void +ASTPrinter::_print(std::ostream& os, const Node& node) const +{ + os << '(' << rang::fgB::yellow; + if (node.is_root()) { + os << "root"; + } else { + os << node.name(); + } + os << rang::fg::reset << ':'; + os << dataTypeName(node.m_data_type) << ':'; + + os << rang::fgB::cyan; + std::visit( + [&](const auto& value) { + using T = std::decay_t<decltype(value)>; + if constexpr (std::is_same_v<T, std::monostate>) { + os << "--"; + } else if constexpr (std::is_same_v<T, std::string>) { + os << '\"' << escapeString(value) << '\"'; + } else { + os << value; + } + }, + node.m_value); + os << rang::fg::reset << ")\n"; + + if (not node.children.empty()) { + _print(os, node.children); + } +} + +template <typename NodeVector> +void +ASTPrinter::_print(std::ostream& os, const NodeVector& node_list) const +{ + for (size_t i_child = 0; i_child < node_list.size(); ++i_child) { + if (i_child != node_list.size() - 1) { + os << rang::fgB::green << prefix << T_junction << rang::fg::reset; + } else { + os << rang::fgB::green << prefix << L_junction << rang::fg::reset; + } + auto& child = *(node_list[i_child]); + if (not child.children.empty()) { + last_prefix_size.push_back(prefix.size()); + if (i_child != node_list.size() - 1) { + prefix += pipe_space; + } else { + prefix += space_space; + } + + _print(os, *(node_list[i_child])); + + prefix.resize(last_prefix_size[last_prefix_size.size() - 1]); + last_prefix_size.pop_back(); + } else { + _print(os, *(node_list[i_child])); + } + } +} + +std::ostream& +operator<<(std::ostream& os, const ASTPrinter& ast_printer) +{ + ast_printer._print(os, ast_printer.m_node); + return os; +} + +ASTPrinter::ASTPrinter(const language::Node& node, Format format) : m_node{node} +{ + if (format == Format::pretty) { + T_junction = " \u251c\u2500\u2500"; + L_junction = " \u2514\u2500\u2500"; + pipe_space = " \u2502 "; + space_space = " "; + } else { + Assert(format == Format::raw); + T_junction = " +-"; + L_junction = " `-"; + pipe_space = " | "; + space_space = " "; + } +} +} // namespace language diff --git a/src/language/ASTPrinter.hpp b/src/language/ASTPrinter.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a4715fba240bcb2e0ee7f8da6a7272cfacf10788 --- /dev/null +++ b/src/language/ASTPrinter.hpp @@ -0,0 +1,46 @@ +#ifndef AST_PRINTER_HPP +#define AST_PRINTER_HPP + +#include <ASTNode.hpp> + +namespace language +{ +class ASTPrinter +{ + public: + enum class Format + { + raw, + pretty + }; + + private: + const Node& m_node; + + mutable std::string prefix; + mutable std::vector<int> last_prefix_size; + + std::string T_junction; + std::string L_junction; + + std::string pipe_space; + std::string space_space; + + void _print(std::ostream& os, const Node& node) const; + + template <typename NodeVector> + void _print(std::ostream& os, const NodeVector& node_list) const; + + public: + friend std::ostream& operator<<(std::ostream& os, const ASTPrinter& ast_printer); + + ASTPrinter(const Node& node, Format format = Format::pretty); + + ASTPrinter(const ASTPrinter&) = delete; + + ASTPrinter(ASTPrinter&&) = delete; + + ~ASTPrinter() = default; +}; +} // namespace language +#endif // AST_PRINTER_HPP diff --git a/src/language/CMakeLists.txt b/src/language/CMakeLists.txt index c84943ca41a9ccc1757e92ad3f7e0ff1e28e5903..8cf155b464da49f94cfc7e32cb9a2cdb0168a3b6 100644 --- a/src/language/CMakeLists.txt +++ b/src/language/CMakeLists.txt @@ -12,6 +12,7 @@ add_library( ASTNodeExpressionBuilder.cpp ASTNodeIncDecExpressionBuilder.cpp ASTNodeUnaryOperatorExpressionBuilder.cpp + ASTPrinter.cpp PugsParser.cpp) #include_directories(${PUGS_SOURCE_DIR}/utils) diff --git a/src/language/PugsParser.cpp b/src/language/PugsParser.cpp index 08f9c48613731f25795401c85dcca2a942eb89d5..2edd84b3b6b2f9497a5a4e15c0509c5995c225fa 100644 --- a/src/language/PugsParser.cpp +++ b/src/language/PugsParser.cpp @@ -23,6 +23,8 @@ #include <ASTNodeExpressionBuilder.hpp> +#include <ASTPrinter.hpp> + namespace language { namespace internal @@ -443,77 +445,6 @@ simplify_declarations(Node& n) internal::simplify_declarations(n); } -void print(const Node& n); - -std::string prefix; -std::vector<int> last_prefix_size; -const std::string T_junction(" \u251c\u2500\u2500"); -const std::string L_junction(" \u2514\u2500\u2500"); - -const std::string pipe_space(" \u2502 "); -const std::string space_space(" "); - -template <typename NodeVector> -void -print(const NodeVector& node_list) -{ - for (size_t i_child = 0; i_child < node_list.size(); ++i_child) { - if (i_child != node_list.size() - 1) { - std::cout << rang::fgB::green << prefix << T_junction << rang::fg::reset; - } else { - std::cout << rang::fgB::green << prefix << L_junction << rang::fg::reset; - } - auto& child = *(node_list[i_child]); - if (not child.children.empty()) { - last_prefix_size.push_back(prefix.size()); - if (i_child != node_list.size() - 1) { - prefix += pipe_space; - } else { - prefix += space_space; - } - - print(*(node_list[i_child])); - - prefix.resize(last_prefix_size[last_prefix_size.size() - 1]); - last_prefix_size.pop_back(); - } else { - print(*(node_list[i_child])); - } - } -} - -void -print(const Node& n) -{ - std::cout << '(' << rang::fgB::yellow; - if (n.is_root()) { - std::cout << "root"; - } else { - std::cout << n.name(); - } - std::cout << rang::fg::reset << ':'; - std::cout << dataTypeName(n.m_data_type) << ':'; - - std::cout << rang::fgB::cyan; - std::visit( - [](const auto& value) { - using T = std::decay_t<decltype(value)>; - if constexpr (std::is_same_v<T, std::monostate>) { - std::cout << "--"; - } else if constexpr (std::is_same_v<T, std::string>) { - std::cout << '\"' << escapeString(value) << '\"'; - } else { - std::cout << value; - } - }, - n.m_value); - std::cout << rang::fg::reset << ")\n"; - - if (not n.children.empty()) { - print(n.children); - } -} - } // namespace language void @@ -553,7 +484,7 @@ parser(const std::string& filename) language::build_node_type(*root_node); - language::print(*root_node); + std::cout << language::ASTPrinter{*root_node, language::ASTPrinter::Format::raw} << '\n'; language::ExecUntilBreakOrContinue exec_all; root_node->execute(exec_all); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4eef6c18771aa6768877e9b24a3afe8e91296911..0272ba4f1a526b003eb96fc1bd94463001f5f8b5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -4,6 +4,7 @@ set(EXECUTABLE_OUTPUT_PATH ${PUGS_BINARY_DIR}) add_executable (unit_tests test_main.cpp + test_ASTBuilder.cpp test_Array.cpp test_ArrayUtils.cpp test_ItemType.cpp @@ -22,6 +23,7 @@ target_include_directories(Catch2 INTERFACE ${CATCH_INCLUDE_DIR}) target_link_libraries (unit_tests PugsUtils + PugsLanguage kokkos Catch2 ) diff --git a/tests/test_ASTBuilder.cpp b/tests/test_ASTBuilder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..11c2afc9497c2362437c28c9f9fbb9fb4e3616e5 --- /dev/null +++ b/tests/test_ASTBuilder.cpp @@ -0,0 +1,49 @@ +#include <catch.hpp> + +#include <ASTBuilder.hpp> +#include <ASTPrinter.hpp> +#include <sstream> + +TEST_CASE("ASTBuilder", "[language]") +{ + using namespace language; + + SECTION("checking AST simplifications"){} + { + std::stringstream ss{R"( +Z a = -3; +Z b = - - + - 2; +Z d; +{ + Z c=3; + d = (0 - -c)/3; +} +Z e = 0 + +3; +Z f = 0 + -3; + +B g = not not true; +R h = 0; +R i = h++; +i--; +)"}; + + istream_input input{ss, ss.str().size(), "test.pgs"}; + auto ast = buildAST(input); + std::stringstream ast_output; + ast_output << ASTPrinter{*ast, ASTPrinter::Format::raw}; + REQUIRE(true); + } + + REQUIRE(true); + + SECTION("checking for copies") {} + + SECTION("checking for fill") {} + + SECTION("checking for affectations (shallow copy)") {} + + SECTION("checking for bounds violation") + { + // REQUIRE_THROWS_AS(a[10], AssertError); + } +}