diff --git a/src/language/node_processor/ArraySubscriptProcessor.hpp b/src/language/node_processor/ArraySubscriptProcessor.hpp index 7bd2f6099366cbb255c95aff97e675428f1942d5..84fe29fd5a313d63a623855049f2a8dc32e8edb8 100644 --- a/src/language/node_processor/ArraySubscriptProcessor.hpp +++ b/src/language/node_processor/ArraySubscriptProcessor.hpp @@ -23,7 +23,9 @@ class ArraySubscriptProcessor : public INodeProcessor if constexpr (std::is_integral_v<ValueT>) { index_value = value; } else { + // LCOV_EXCL_START throw parse_error("unexpected error: invalid index type", std::vector{index_expression.begin()}); + // LCOV_EXCL_STOP } }, value_variant); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e973c87166171d1cabb6b45ebb30b2324ac4787f..2a251118e50a04705c50672d2a3e6392d905a133 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -6,6 +6,7 @@ add_executable (unit_tests test_AffectationProcessor.cpp test_AffectationToStringProcessor.cpp test_Array.cpp + test_ArraySubscriptProcessor.cpp test_ArrayUtils.cpp test_ASTBuilder.cpp test_ASTDotPrinter.cpp diff --git a/tests/test_ArraySubscriptProcessor.cpp b/tests/test_ArraySubscriptProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d5c6dbfe5112f97c2798c8829f95a10076dcccd4 --- /dev/null +++ b/tests/test_ArraySubscriptProcessor.cpp @@ -0,0 +1,165 @@ +#include <catch2/catch.hpp> + +#include <ASTBuilder.hpp> +#include <ASTNodeDataTypeBuilder.hpp> + +#include <ASTModulesImporter.hpp> + +#include <ASTNodeDeclarationToAffectationConverter.hpp> +#include <ASTNodeTypeCleaner.hpp> + +#include <ASTNodeExpressionBuilder.hpp> + +#include <ASTNodeAffectationExpressionBuilder.hpp> + +#include <ASTSymbolTableBuilder.hpp> + +#include <ASTPrinter.hpp> + +#include <Demangle.hpp> + +#include <PEGGrammar.hpp> + +#include <sstream> + +#define CHECK_EVALUATION_RESULT(data, variable_name, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTModulesImporter{*ast}; \ + ASTNodeTypeCleaner<language::import_instruction>{*ast}; \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::declaration>{*ast}; \ + ASTNodeTypeCleaner<language::let_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + \ + auto symbol_table = ast->m_symbol_table; \ + \ + using namespace TAO_PEGTL_NAMESPACE; \ + position use_position{internal::iterator{"fixture"}, "fixture"}; \ + use_position.byte = 10000; \ + auto [symbol, found] = symbol_table->find(variable_name, use_position); \ + \ + auto attributes = symbol->attributes(); \ + auto value = std::get<decltype(expected_value)>(attributes.value()); \ + \ + REQUIRE(value == expected_value); \ + } + +#define CHECK_EVALUATION_THROWS_WITH(data, error_message) \ + { \ + auto eval = [&] { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTModulesImporter{*ast}; \ + ASTNodeTypeCleaner<language::import_instruction>{*ast}; \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::declaration>{*ast}; \ + ASTNodeTypeCleaner<language::let_declaration>{*ast}; \ + \ + ASTNodeExpressionBuilder{*ast}; \ + ExecutionPolicy exec_policy; \ + ast->execute(exec_policy); \ + }; \ + \ + REQUIRE_THROWS_WITH(eval(), error_message); \ + } + +TEST_CASE("ArraySubscriptProcessor", "[language]") +{ + SECTION("R^1 component access") + { + std::string_view data = R"( +R^1 x = 1; +R x0 = x[0]; +)"; + CHECK_EVALUATION_RESULT(data, "x0", double{1}); + } + + SECTION("R^2 component access") + { + std::string_view data = R"( +R^2 x = (1,2); +R x0 = x[0]; +R x1 = x[1]; +)"; + CHECK_EVALUATION_RESULT(data, "x0", double{1}); + CHECK_EVALUATION_RESULT(data, "x1", double{2}); + } + + SECTION("R^3 component access") + { + std::string_view data = R"( +R^3 x = (1,2,3); +R x0 = x[0]; +R x1 = x[1]; +R x2 = x[2]; +)"; + CHECK_EVALUATION_RESULT(data, "x0", double{1}); + CHECK_EVALUATION_RESULT(data, "x1", double{2}); + CHECK_EVALUATION_RESULT(data, "x2", double{3}); + } + + SECTION("R^d component access from integer expression") + { + std::string_view data = R"( +R^3 x = (1,2,3); +R x0 = x[3-2-1]; + +R^2 y = (2,7); +R y1 = y[2/2]; + +R^1 z = 8; +R z0 = z[(2-2)*1]; +)"; + CHECK_EVALUATION_RESULT(data, "x0", double{1}); + CHECK_EVALUATION_RESULT(data, "y1", double{7}); + CHECK_EVALUATION_RESULT(data, "z0", double{8}); + } + + SECTION("error invalid index type") + { + SECTION("R index type") + { + std::string_view data = R"( +R^3 x = (1,2,3); +R x0 = x[2.3]; +)"; + + CHECK_EVALUATION_THROWS_WITH(data, std::string{"invalid implicit conversion: R -> Z"}); + } + + SECTION("string index type") + { + std::string_view data = R"( +R^3 x = (1,2,3); +R x0 = x["foo"]; +)"; + + CHECK_EVALUATION_THROWS_WITH(data, std::string{"invalid implicit conversion: string -> Z"}); + } + + SECTION("R^d index type") + { + std::string_view data = R"( +R^3 x = (1,2,3); +R x0 = x[x]; +)"; + + CHECK_EVALUATION_THROWS_WITH(data, std::string{"invalid implicit conversion: R^3 -> Z"}); + } + } +}