From b797c9f28ba96a50f8ac49517587fa54cc1b595e Mon Sep 17 00:00:00 2001 From: Stephane Del Pino <stephane.delpino44@gmail.com> Date: Fri, 26 Jul 2019 12:04:47 +0200 Subject: [PATCH] Continue clean-up. Add ASTNodeValueBuilder and its tests. --- src/language/ASTNodeValueBuilder.cpp | 55 +++++++++++ src/language/ASTNodeValueBuilder.hpp | 15 +++ src/language/CMakeLists.txt | 5 +- src/language/PugsParser.cpp | 61 +----------- tests/CMakeLists.txt | 3 +- tests/test_ASTNodeValueBuilder.cpp | 138 +++++++++++++++++++++++++++ 6 files changed, 216 insertions(+), 61 deletions(-) create mode 100644 src/language/ASTNodeValueBuilder.cpp create mode 100644 src/language/ASTNodeValueBuilder.hpp create mode 100644 tests/test_ASTNodeValueBuilder.cpp diff --git a/src/language/ASTNodeValueBuilder.cpp b/src/language/ASTNodeValueBuilder.cpp new file mode 100644 index 000000000..19886da79 --- /dev/null +++ b/src/language/ASTNodeValueBuilder.cpp @@ -0,0 +1,55 @@ +#include <ASTNodeValueBuilder.hpp> + +#include <PEGGrammar.hpp> +#include <PugsAssert.hpp> + +#include <EscapedString.hpp> + +void +ASTNodeValueBuilder::_buildNodeValue(ASTNode& n) +{ + if (n.is<language::bloc>()) { + if (!n.children.empty()) { + for (auto& child : n.children) { + this->_buildNodeValue(*child); + } + } + n.m_data_type = ASTNodeDataType::void_t; + } else { + for (auto& child : n.children) { + this->_buildNodeValue(*child); + } + + if (n.has_content()) { + if (n.is<language::real>()) { + std::stringstream ss(n.string()); + double v; + ss >> v; + n.m_value = v; + } else if (n.is<language::integer>()) { + std::stringstream ss(n.string()); + int64_t v; + ss >> v; + n.m_value = v; + } else if (n.is<language::literal>()) { + n.m_value = unescapeString(n.string()); + } else if (n.is<language::for_test>()) { + // if AST contains a for_test statement, it means that no test were + // given to the for-loop, so its value is always true + n.m_value = true; + } else if (n.is<language::true_kw>()) { + n.m_value = true; + } else if (n.is<language::false_kw>()) { + n.m_value = false; + } + } + } +} + +ASTNodeValueBuilder::ASTNodeValueBuilder(ASTNode& n) +{ + Assert(n.is_root()); + n.m_data_type = ASTNodeDataType::void_t; + this->_buildNodeValue(n); + std::cout << " - build node data types\n"; +} diff --git a/src/language/ASTNodeValueBuilder.hpp b/src/language/ASTNodeValueBuilder.hpp new file mode 100644 index 000000000..0e60ccc71 --- /dev/null +++ b/src/language/ASTNodeValueBuilder.hpp @@ -0,0 +1,15 @@ +#ifndef AST_NODE_VALUE_BUILDER_HPP +#define AST_NODE_VALUE_BUILDER_HPP + +#include <ASTNode.hpp> + +class ASTNodeValueBuilder +{ + private: + void _buildNodeValue(ASTNode& node); + + public: + ASTNodeValueBuilder(ASTNode& root_node); +}; + +#endif // AST_NODE_VALUE_BUILDER_HPP diff --git a/src/language/CMakeLists.txt b/src/language/CMakeLists.txt index 5b14863b4..b6a386df0 100644 --- a/src/language/CMakeLists.txt +++ b/src/language/CMakeLists.txt @@ -7,14 +7,15 @@ add_library( PugsLanguage ASTBuilder.cpp ASTDotPrinter.cpp + ASTNodeAffectationExpressionBuilder.cpp + ASTNodeBinaryOperatorExpressionBuilder.cpp ASTNodeDataType.cpp ASTNodeDataTypeBuilder.cpp ASTNodeDataTypeChecker.cpp - ASTNodeAffectationExpressionBuilder.cpp - ASTNodeBinaryOperatorExpressionBuilder.cpp ASTNodeExpressionBuilder.cpp ASTNodeIncDecExpressionBuilder.cpp ASTNodeUnaryOperatorExpressionBuilder.cpp + ASTNodeValueBuilder.cpp ASTPrinter.cpp ASTSymbolTableBuilder.cpp ASTSymbolInitializationChecker.cpp diff --git a/src/language/PugsParser.cpp b/src/language/PugsParser.cpp index f0a3ebb05..b9b0a4677 100644 --- a/src/language/PugsParser.cpp +++ b/src/language/PugsParser.cpp @@ -22,8 +22,6 @@ #include <ASTNodeDataTypeBuilder.hpp> #include <ASTNodeDataTypeChecker.hpp> -#include <EscapedString.hpp> - #include <ASTNodeExpressionBuilder.hpp> #include <ASTSymbolInitializationChecker.hpp> @@ -32,63 +30,10 @@ #include <ASTDotPrinter.hpp> #include <ASTPrinter.hpp> -namespace language -{ -namespace internal -{ -void -build_node_values(ASTNode& n, std::shared_ptr<SymbolTable>& symbol_table) -{ - if (n.is<language::bloc>()) { - if (!n.children.empty()) { - std::shared_ptr bloc_symbol_table = std::make_shared<SymbolTable>(symbol_table); - for (auto& child : n.children) { - build_node_values(*child, bloc_symbol_table); - } - } - n.m_data_type = ASTNodeDataType::void_t; - } else { - for (auto& child : n.children) { - build_node_values(*child, symbol_table); - } +#include <ASTNodeValueBuilder.hpp> - if (n.has_content()) { - if (n.is<language::real>()) { - std::stringstream ss(n.string()); - double v; - ss >> v; - n.m_value = v; - } else if (n.is<language::integer>()) { - std::stringstream ss(n.string()); - int64_t v; - ss >> v; - n.m_value = v; - } else if (n.is<language::literal>()) { - n.m_value = unescapeString(n.string()); - } else if (n.is<language::for_test>()) { - // if AST contains a for_test statement, it means that no test were - // given to the for-loop, so its value is always true - n.m_value = true; - } else if (n.is<language::true_kw>()) { - n.m_value = true; - } else if (n.is<language::false_kw>()) { - n.m_value = false; - } - } - } -} -} // namespace internal - -void -build_node_values(ASTNode& n) +namespace language { - Assert(n.is_root()); - n.m_data_type = ASTNodeDataType::void_t; - std::shared_ptr symbol_table = std::make_shared<SymbolTable>(); - internal::build_node_values(n, symbol_table); - std::cout << " - build node data types\n"; -} - namespace internal { void @@ -179,7 +124,7 @@ parser(const std::string& filename) ASTNodeDataTypeBuilder{*root_node}; ASTNodeDataTypeChecker{*root_node}; - language::build_node_values(*root_node); + ASTNodeValueBuilder{*root_node}; language::check_break_or_continue_placement(*root_node); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 21c8a1b23..c3c89e619 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,11 +5,12 @@ add_executable (unit_tests test_main.cpp test_Array.cpp test_ArrayUtils.cpp - test_ASTDotPrinter.cpp test_ASTBuilder.cpp + test_ASTDotPrinter.cpp test_ASTNodeDataType.cpp test_ASTNodeDataTypeBuilder.cpp test_ASTNodeDataTypeChecker.cpp + test_ASTNodeValueBuilder.cpp test_ASTPrinter.cpp test_ASTSymbolTableBuilder.cpp test_ASTSymbolInitializationChecker.cpp diff --git a/tests/test_ASTNodeValueBuilder.cpp b/tests/test_ASTNodeValueBuilder.cpp new file mode 100644 index 000000000..70364828f --- /dev/null +++ b/tests/test_ASTNodeValueBuilder.cpp @@ -0,0 +1,138 @@ +#include <catch2/catch.hpp> + +#include <ASTNodeValueBuilder.hpp> + +#include <ASTBuilder.hpp> +#include <ASTNodeDataTypeBuilder.hpp> + +#include <ASTSymbolTableBuilder.hpp> + +#include <ASTPrinter.hpp> + +#define CHECK_AST_VALUES(data, expected_output) \ + { \ + static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ + static_assert(std::is_same_v<std::decay_t<decltype(expected_output)>, std::string_view>); \ + \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + ASTNodeValueBuilder{*ast}; \ + \ + std::stringstream ast_output; \ + ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::data_value}}; \ + \ + REQUIRE(ast_output.str() == expected_output); \ + } + +TEST_CASE("ASTNodeValuebuilder", "[language]") +{ + SECTION("integer") + { + std::string_view data = R"( +01; +)"; + + std::string_view result = R"( +(root:--) + `-(language::integer:01:1) +)"; + + CHECK_AST_VALUES(data, result); + } + + SECTION("real") + { + std::string_view data = R"( +1.300; +)"; + + std::string_view result = R"( +(root:--) + `-(language::real:1.300:1.3) +)"; + + CHECK_AST_VALUES(data, result); + } + + SECTION("true") + { + std::string_view data = R"( +true; +)"; + + std::string_view result = R"( +(root:--) + `-(language::true_kw:1) +)"; + + CHECK_AST_VALUES(data, result); + } + + SECTION("false") + { + std::string_view data = R"( +false; +)"; + + std::string_view result = R"( +(root:--) + `-(language::false_kw:0) +)"; + + CHECK_AST_VALUES(data, result); + } + + SECTION("string") + { + std::string_view data = R"( +"\"foo\" or \"bar\""; +)"; + + std::string_view result = R"( +(root:--) + `-(language::literal:"\"foo\" or \"bar\"":"\"foo\" or \"bar\"") +)"; + + CHECK_AST_VALUES(data, result); + } + + SECTION("for empty test") + { + std::string_view data = R"( +for(;;); +)"; + + std::string_view result = R"( +(root:--) + `-(language::for_statement:--) + +-(language::for_init:--) + +-(language::for_test:1) + +-(language::for_post:--) + `-(language::for_statement_bloc:--) +)"; + + CHECK_AST_VALUES(data, result); + } + + SECTION("bloc values") + { + std::string_view data = R"( +{ + 1; + 2.3; +} +)"; + + std::string_view result = R"( +(root:--) + `-(language::bloc:--) + +-(language::integer:1:1) + `-(language::real:2.3:2.3) +)"; + + CHECK_AST_VALUES(data, result); + } +} -- GitLab