diff --git a/src/language/PEGGrammar.hpp b/src/language/PEGGrammar.hpp index 61ba912a567c4a6d868d22cc7915e7557f484518..fb3b1d74abf6ba0d33113ec95996c6a270edb77d 100644 --- a/src/language/PEGGrammar.hpp +++ b/src/language/PEGGrammar.hpp @@ -229,7 +229,10 @@ struct expression : logical_or {}; struct tuple_expression : seq< open_parent, expression, plus< if_must< COMMA, expression > >, close_parent >{}; -struct expression_list : seq< open_parent, sor< tuple_expression, expression >, plus< if_must< COMMA, sor< tuple_expression, expression > > >, close_parent >{}; +struct expression_list : seq< open_parent, sor< seq< tuple_expression, + star< if_must< COMMA, sor< tuple_expression, expression > > > >, + seq< expression, + plus< if_must< COMMA, sor< tuple_expression, expression > > > > >, close_parent >{}; struct affect_op : sor< eq_op, multiplyeq_op, divideeq_op, pluseq_op, minuseq_op > {}; diff --git a/src/language/ast/ASTBuilder.cpp b/src/language/ast/ASTBuilder.cpp index cef779ffce63b9c2ad808ca94b993e7eff59d4ff..35d787354c37e5b1dbc3f176548fb4725d924cbb 100644 --- a/src/language/ast/ASTBuilder.cpp +++ b/src/language/ast/ASTBuilder.cpp @@ -138,7 +138,7 @@ struct ASTBuilder::simplify_node_list : parse_tree::apply<ASTBuilder::simplify_n transform(std::unique_ptr<ASTNode>& n, States&&... st) { if (n->is_type<language::name_list>() or n->is_type<language::lvalue_list>() or - n->is_type<language::function_argument_list>() or n->is_type<language::expression_list>()) { + n->is_type<language::function_argument_list>()) { if (n->children.size() == 1) { n = std::move(n->children.back()); transform(n, st...); @@ -255,6 +255,7 @@ using selector = parse_tree::selector< language::fct_declaration, language::type_mapping, language::function_definition, + language::expression_list, language::if_statement, language::do_while_statement, language::while_statement, @@ -303,8 +304,7 @@ using selector = parse_tree::selector< language::post_plusplus>, ASTBuilder::simplify_for_statement_block::on<language::for_statement_block>, parse_tree::discard_empty::on<language::ignored, language::semicol, language::block>, - ASTBuilder::simplify_node_list:: - on<language::name_list, language::lvalue_list, language::function_argument_list, language::expression_list>, + ASTBuilder::simplify_node_list::on<language::name_list, language::lvalue_list, language::function_argument_list>, ASTBuilder::simplify_statement_block::on<language::statement_block>, ASTBuilder::simplify_for_init::on<language::for_init>, ASTBuilder::simplify_for_test::on<language::for_test>, diff --git a/src/language/node_processor/AffectationProcessor.hpp b/src/language/node_processor/AffectationProcessor.hpp index e15d4aa692e9ddbc54ac086317b9ce8289c28b4c..f3f8af44f38477007a0f85b2a3ee00738a5b82c9 100644 --- a/src/language/node_processor/AffectationProcessor.hpp +++ b/src/language/node_processor/AffectationProcessor.hpp @@ -133,7 +133,9 @@ class AffectationExecutor final : public IAffectationExecutor if constexpr (std::is_convertible_v<Vi_T, double>) { m_lhs[i] = vi; } else { + // LCOV_EXCL_START throw UnexpectedError("unexpected rhs type in affectation"); + // LCOV_EXCL_STOP } }, v[i]); @@ -145,7 +147,9 @@ class AffectationExecutor final : public IAffectationExecutor if constexpr (std::is_convertible_v<Vi_T, double>) { m_lhs = v; } else { + // LCOV_EXCL_START throw UnexpectedError("unexpected rhs type in affectation"); + // LCOV_EXCL_STOP } }, rhs); @@ -415,10 +419,16 @@ class AffectationToTupleProcessor final : public INodeProcessor } else { std::ostringstream os; os << v << std::ends; - *m_lhs = std::vector{os.str()}; + *m_lhs = std::vector<std::string>{os.str()}; } } else if constexpr (std::is_same_v<ValueT, TinyVector<1>> and std::is_arithmetic_v<T>) { - *m_lhs = std::vector{TinyVector<1>{static_cast<double>(v)}}; + *m_lhs = std::vector<TinyVector<1>>{TinyVector<1>{static_cast<double>(v)}}; + } else if constexpr (std::is_same_v<ValueT, TinyVector<2>> and std::is_same_v<T, int64_t>) { + Assert(v == 0); + *m_lhs = std::vector<TinyVector<2>>{TinyVector<2>{zero}}; + } else if constexpr (std::is_same_v<ValueT, TinyVector<3>> and std::is_same_v<T, int64_t>) { + Assert(v == 0); + *m_lhs = std::vector<TinyVector<3>>{TinyVector<3>{zero}}; } else { // LCOV_EXCL_START throw ParseError("unexpected error: unexpected right hand side type in affectation", m_node.begin()); diff --git a/src/language/node_processor/BuiltinFunctionProcessor.hpp b/src/language/node_processor/BuiltinFunctionProcessor.hpp index 302cbaf2d2ce3570678fb62a57d4e463e47a2432..4e5583adb2d269e7552ff3cccf7dfcbe811b0791 100644 --- a/src/language/node_processor/BuiltinFunctionProcessor.hpp +++ b/src/language/node_processor/BuiltinFunctionProcessor.hpp @@ -64,7 +64,9 @@ class BuiltinFunctionProcessor : public INodeProcessor } if (SignalManager::pauseOnError()) { + // LCOV_EXCL_START return m_function_expression_processor->execute(context_exec_policy); + // LCOV_EXCL_STOP } else { try { return m_function_expression_processor->execute(context_exec_policy); diff --git a/src/language/node_processor/DoWhileProcessor.hpp b/src/language/node_processor/DoWhileProcessor.hpp index 5b03b769ffe3e376c5e8bddafa91db5d01e2f59f..6f3c14b7f8706c6d5480f792e449c1f110b74498 100644 --- a/src/language/node_processor/DoWhileProcessor.hpp +++ b/src/language/node_processor/DoWhileProcessor.hpp @@ -3,6 +3,7 @@ #include <language/ast/ASTNode.hpp> #include <language/node_processor/INodeProcessor.hpp> +#include <language/utils/SymbolTable.hpp> class DoWhileProcessor final : public INodeProcessor { diff --git a/src/language/node_processor/ForProcessor.hpp b/src/language/node_processor/ForProcessor.hpp index 8680aaf7ded0f7fabbc345682a9a32c772a44f08..4199e0c42867398167c2f1fa5927d87e7f4fddc6 100644 --- a/src/language/node_processor/ForProcessor.hpp +++ b/src/language/node_processor/ForProcessor.hpp @@ -3,6 +3,7 @@ #include <language/ast/ASTNode.hpp> #include <language/node_processor/INodeProcessor.hpp> +#include <language/utils/SymbolTable.hpp> class ForProcessor final : public INodeProcessor { diff --git a/src/language/node_processor/FunctionArgumentConverter.hpp b/src/language/node_processor/FunctionArgumentConverter.hpp index 4bf7e56eebfd93b244d13a774e2e69aac2834794..9e7eec757fb2c396125d6d299f5a7529ca420009 100644 --- a/src/language/node_processor/FunctionArgumentConverter.hpp +++ b/src/language/node_processor/FunctionArgumentConverter.hpp @@ -31,9 +31,20 @@ class FunctionArgumentToStringConverter final : public IFunctionArgumentConverte DataVariant convert(ExecutionPolicy& exec_policy, DataVariant&& value) { - std::ostringstream sout; - sout << value; - exec_policy.currentContext()[m_argument_id] = sout.str(); + std::visit( + [&](auto&& v) { + using T = std::decay_t<decltype(v)>; + if constexpr (std::is_arithmetic_v<T>) { + exec_policy.currentContext()[m_argument_id] = std::to_string(v); + } else if constexpr (std::is_same_v<T, std::string>) { + exec_policy.currentContext()[m_argument_id] = v; + } else { + std::ostringstream sout; + sout << value << std::ends; + exec_policy.currentContext()[m_argument_id] = sout.str(); + } + }, + value); return {}; } @@ -100,6 +111,7 @@ class FunctionTinyVectorArgumentConverter final : public IFunctionArgumentConver } else if constexpr (std::is_same_v<ProvidedValueType, ZeroType>) { exec_policy.currentContext()[m_argument_id] = ExpectedValueType{ZeroType::zero}; } else { + static_assert(std::is_same_v<ExpectedValueType, TinyVector<1>>); exec_policy.currentContext()[m_argument_id] = std::move(static_cast<ExpectedValueType>(std::get<ProvidedValueType>(value))); } @@ -132,19 +144,36 @@ class FunctionTupleArgumentConverter final : public IFunctionArgumentConverter TupleType list_value; list_value.reserve(v.size()); for (size_t i = 0; i < v.size(); ++i) { - list_value.emplace_back(v[i]); + list_value.emplace_back(std::move(v[i])); } exec_policy.currentContext()[m_argument_id] = std::move(list_value); + } else if constexpr ((std::is_convertible_v<ContentT, ContentType>)and not is_tiny_vector_v<ContentType>) { + TupleType list_value; + list_value.reserve(v.size()); + for (size_t i = 0; i < v.size(); ++i) { + list_value.push_back(static_cast<ContentType>(v[i])); + } + exec_policy.currentContext()[m_argument_id] = std::move(list_value); + } else { + // LCOV_EXCL_START + throw UnexpectedError(std::string{"cannot convert '"} + demangle<ValueT>() + "' to '" + + demangle<ContentType>() + "'"); + // LCOV_EXCL_STOP } } else if constexpr (std::is_convertible_v<ValueT, ContentType> and not is_tiny_vector_v<ContentType>) { exec_policy.currentContext()[m_argument_id] = std::move(TupleType{static_cast<ContentType>(v)}); } else { - throw UnexpectedError(demangle<ValueT>() + " unexpected value type"); + throw UnexpectedError(std::string{"cannot convert '"} + demangle<ValueT>() + "' to '" + + demangle<ContentType>() + "'"); } }, value); + } else { - throw UnexpectedError(demangle<std::decay_t<decltype(*this)>>() + ": did nothing!"); + // LCOV_EXCL_START + throw UnexpectedError(std::string{"cannot convert '"} + demangle<ProvidedValueType>() + "' to '" + + demangle<ContentType>() + "'"); + // LCOV_EXCL_STOP } return {}; } @@ -174,31 +203,43 @@ class FunctionListArgumentConverter final : public IFunctionArgumentConverter std::visit( [&](auto&& vi) { using Vi_T = std::decay_t<decltype(vi)>; - if constexpr (is_tiny_vector_v<ContentType>) { - throw NotImplementedError("TinyVector case"); + if constexpr (std::is_same_v<Vi_T, ContentType>) { + list_value.emplace_back(vi); + } else if constexpr (is_tiny_vector_v<ContentType>) { + // LCOV_EXCL_START + throw UnexpectedError(std::string{"invalid conversion of '"} + demangle<Vi_T>() + "' to '" + + demangle<ContentType>() + "'"); + // LCOV_EXCL_STOP } else if constexpr (std::is_convertible_v<Vi_T, ContentType>) { list_value.emplace_back(vi); } else { + // LCOV_EXCL_START throw UnexpectedError("unexpected types"); + // LCOV_EXCL_STOP } }, (v[i])); } exec_policy.currentContext()[m_argument_id] = std::move(list_value); - } else if constexpr (std::is_same_v<ValueT, ContentType>) { - exec_policy.currentContext()[m_argument_id] = std::move(v); } else if constexpr (is_std_vector_v<ValueT>) { using ContentT = typename ValueT::value_type; if constexpr (std::is_same_v<ContentT, ContentType>) { - TupleType list_value; - list_value.reserve(v.size()); - for (size_t i = 0; i < v.size(); ++i) { - list_value.emplace_back(v[i]); - } - exec_policy.currentContext()[m_argument_id] = std::move(list_value); + exec_policy.currentContext()[m_argument_id] = v; + } else { + // LCOV_EXCL_START + throw UnexpectedError(std::string{"invalid conversion of '"} + demangle<ContentT>() + "' to '" + + demangle<ContentType>() + "'"); + // LCOV_EXCL_STOP } + } else if constexpr (std::is_same_v<ValueT, ContentType>) { + exec_policy.currentContext()[m_argument_id] = std::move(TupleType{v}); + } else if constexpr (std::is_convertible_v<ValueT, ContentType> and not is_tiny_vector_v<ValueT> and + not is_tiny_vector_v<ContentType>) { + exec_policy.currentContext()[m_argument_id] = std::move(TupleType{static_cast<ContentType>(v)}); } else { + // LCOV_EXCL_START throw UnexpectedError(demangle<ValueT>() + " unexpected value type"); + // LCOV_EXCL_STOP } }, value); diff --git a/src/language/node_processor/IfProcessor.hpp b/src/language/node_processor/IfProcessor.hpp index 1a76e3068dcb6bd29f4e4e250dc3d6cc1f9f6d41..18d87bb89f11ee0f335fe0637f4569dc5b3cab15 100644 --- a/src/language/node_processor/IfProcessor.hpp +++ b/src/language/node_processor/IfProcessor.hpp @@ -3,6 +3,7 @@ #include <language/ast/ASTNode.hpp> #include <language/node_processor/INodeProcessor.hpp> +#include <language/utils/SymbolTable.hpp> class IfProcessor final : public INodeProcessor { @@ -39,8 +40,7 @@ class IfProcessor final : public INodeProcessor } } - if (m_node.children[0]->m_symbol_table != m_node.m_symbol_table) - m_node.children[0]->m_symbol_table->clearValues(); + Assert(m_node.children[0]->m_symbol_table == m_node.m_symbol_table); return {}; } diff --git a/src/language/node_processor/WhileProcessor.hpp b/src/language/node_processor/WhileProcessor.hpp index 20b0ac985ae43bfaf3f9b165f9a346aa82a9f3cb..af7cc604bb6c2d5f74cb894a1f05ba20acfb35f6 100644 --- a/src/language/node_processor/WhileProcessor.hpp +++ b/src/language/node_processor/WhileProcessor.hpp @@ -3,6 +3,7 @@ #include <language/ast/ASTNode.hpp> #include <language/node_processor/INodeProcessor.hpp> +#include <language/utils/SymbolTable.hpp> class WhileProcessor final : public INodeProcessor { diff --git a/src/language/utils/DataVariant.hpp b/src/language/utils/DataVariant.hpp index 13744172a73c2e3c54d97412cd654ae7211ad42c..55e537f0922a53020797b360d4c235f358bcbc8c 100644 --- a/src/language/utils/DataVariant.hpp +++ b/src/language/utils/DataVariant.hpp @@ -71,14 +71,16 @@ class AggregateDataVariant // LCOV_EXCL_LINE } PUGS_INLINE - DataVariant& operator[](size_t i) + DataVariant& + operator[](size_t i) { Assert(i < m_data_vector.size()); return m_data_vector[i]; } PUGS_INLINE - const DataVariant& operator[](size_t i) const + const DataVariant& + operator[](size_t i) const { Assert(i < m_data_vector.size()); return m_data_vector[i]; diff --git a/src/language/utils/SymbolTable.hpp b/src/language/utils/SymbolTable.hpp index 6bcf267780884d1d8a1492b664ff492026ddd869..39d414b1e120255e9d51c17266512458fcc5f1b8 100644 --- a/src/language/utils/SymbolTable.hpp +++ b/src/language/utils/SymbolTable.hpp @@ -267,7 +267,12 @@ class SymbolTable clearValues() { for (auto& symbol : m_symbol_list) { - symbol.attributes().value() = DataVariant{}; + std::visit( + [](auto&& value) { + using T = std::decay_t<decltype(value)>; + value = T{}; + }, + symbol.attributes().value()); } } diff --git a/src/utils/Types.hpp b/src/utils/Types.hpp index 482190cb6f4c34c614a1237c4c025bbb37812e20..2d53c59f17d00fbd44d92ebc5db06e529a5d47db 100644 --- a/src/utils/Types.hpp +++ b/src/utils/Types.hpp @@ -5,12 +5,12 @@ enum class ZeroType { zero }; -constexpr ZeroType zero = ZeroType::zero; +constexpr inline ZeroType zero = ZeroType::zero; enum class IdentityType { identity }; -constexpr IdentityType identity = IdentityType::identity; +constexpr inline IdentityType identity = IdentityType::identity; #endif // TYPES_HPP diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8d0344a03785fc30e30a20b71b498d7cd2b28d4a..dbaf666c108fe6d96830c53bdb7c87aa50a912c2 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -8,6 +8,7 @@ add_executable (unit_tests test_main.cpp test_AffectationProcessor.cpp test_AffectationToStringProcessor.cpp + test_AffectationToTupleProcessor.cpp test_Array.cpp test_ArraySubscriptProcessor.cpp test_ArrayUtils.cpp @@ -57,6 +58,7 @@ add_executable (unit_tests test_ExecutionPolicy.cpp test_FakeProcessor.cpp test_ForProcessor.cpp + test_FunctionArgumentConverter.cpp test_FunctionProcessor.cpp test_FunctionSymbolId.cpp test_FunctionTable.cpp @@ -68,6 +70,7 @@ add_executable (unit_tests test_MathModule.cpp test_NameProcessor.cpp test_OStreamProcessor.cpp + test_ParseError.cpp test_PugsFunctionAdapter.cpp test_PugsAssert.cpp test_RevisionInfo.cpp diff --git a/tests/test_ASTBuilder.cpp b/tests/test_ASTBuilder.cpp index 2399a78617d6a6f30774fbc70be735d5850967d3..7353fa9a46d6d08542c62d4bee89299c930fc5a1 100644 --- a/tests/test_ASTBuilder.cpp +++ b/tests/test_ASTBuilder.cpp @@ -620,6 +620,41 @@ clog << "log " << l << "\n"; +-(language::literal:"log ") +-(language::name:l) `-(language::literal:"\n") +)"; + CHECK_AST(data, result); + } + + SECTION("tuple list simplification") + { + std::string_view data = R"( +let x:(R^2), x=((0,0),(2,3)); +let y:(R^2), y=((0)); +)"; + + std::string_view result = R"( +(root) + +-(language::var_declaration) + | +-(language::name:x) + | +-(language::tuple_type_specifier) + | | `-(language::vector_type) + | | +-(language::R_set) + | | `-(language::integer:2) + | +-(language::name:x) + | `-(language::expression_list) + | +-(language::tuple_expression) + | | +-(language::integer:0) + | | `-(language::integer:0) + | `-(language::tuple_expression) + | +-(language::integer:2) + | `-(language::integer:3) + `-(language::var_declaration) + +-(language::name:y) + +-(language::tuple_type_specifier) + | `-(language::vector_type) + | +-(language::R_set) + | `-(language::integer:2) + +-(language::name:y) + `-(language::integer:0) )"; CHECK_AST(data, result); } diff --git a/tests/test_ASTSymbolInitializationChecker.cpp b/tests/test_ASTSymbolInitializationChecker.cpp index fe59815acf5c65c642a81155fa30abf422a5b471..fb0c8598beb79861f6cbbb66ebe37461c66b61e5 100644 --- a/tests/test_ASTSymbolInitializationChecker.cpp +++ b/tests/test_ASTSymbolInitializationChecker.cpp @@ -301,5 +301,18 @@ let f : R->R, x->x+y; ASTSymbolTableBuilder{*ast}; REQUIRE_THROWS_WITH(ASTSymbolInitializationChecker{*ast}, std::string{"uninitialized symbol 'y'"}); } + + SECTION("expecting a list of identifiers") + { + std::string_view data = R"( +let (x,y,z):R*R*R, x = 3; +)"; + + string_input input{data, "test.pgs"}; + auto ast = ASTBuilder::build(input); + + ASTSymbolTableBuilder{*ast}; + REQUIRE_THROWS_WITH(ASTSymbolInitializationChecker{*ast}, std::string{"expecting a list of identifiers"}); + } } } diff --git a/tests/test_AffectationToTupleProcessor.cpp b/tests/test_AffectationToTupleProcessor.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3720bc856b30fa39468e90a7a56cc0ce2d01058d --- /dev/null +++ b/tests/test_AffectationToTupleProcessor.cpp @@ -0,0 +1,175 @@ +#include <catch2/catch.hpp> + +#include <language/ast/ASTBuilder.hpp> +#include <language/ast/ASTNodeAffectationExpressionBuilder.hpp> +#include <language/ast/ASTNodeDataTypeBuilder.hpp> +#include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> +#include <language/ast/ASTNodeExpressionBuilder.hpp> +#include <language/ast/ASTNodeTypeCleaner.hpp> +#include <language/ast/ASTSymbolTableBuilder.hpp> +#include <language/utils/ASTPrinter.hpp> +#include <utils/Demangle.hpp> + +#include <pegtl/string_input.hpp> + +#include <sstream> + +#define CHECK_AFFECTATION_RESULT(data, variable_name, expected_value) \ + { \ + string_input input{data, "test.pgs"}; \ + auto ast = ASTBuilder::build(input); \ + \ + ASTSymbolTableBuilder{*ast}; \ + ASTNodeDataTypeBuilder{*ast}; \ + \ + ASTNodeDeclarationToAffectationConverter{*ast}; \ + ASTNodeTypeCleaner<language::var_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); \ + } + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ASTAffectationToTupleProcessor", "[language]") +{ + SECTION("Affectations from value") + { + CHECK_AFFECTATION_RESULT(R"( +let s :(R); s = 2.; +)", + "s", (std::vector<double>{2.})); + + CHECK_AFFECTATION_RESULT(R"( +let s :(R); s = 2; +)", + "s", (std::vector<double>{2})); + + CHECK_AFFECTATION_RESULT(R"( +let s :(string); s = 2.; +)", + "s", (std::vector<std::string>{std::to_string(2.)})); + + const std::string x_string = []() -> std::string { + std::ostringstream os; + os << TinyVector<3, double>{1, 2, 3} << std::ends; + return os.str(); + }(); + + CHECK_AFFECTATION_RESULT(R"( +let x :R^3, x = (1,2,3); +let s :(string); s = x; +)", + "s", (std::vector<std::string>{x_string})); + + CHECK_AFFECTATION_RESULT(R"( +let s :(R^1); s = 1.3; +)", + "s", (std::vector<TinyVector<1>>{TinyVector<1>{1.3}})); + } + + SECTION("Affectations from list") + { + CHECK_AFFECTATION_RESULT(R"( +let t :(R); t = (2.,3); +)", + "t", (std::vector<double>{2., 3})); + + CHECK_AFFECTATION_RESULT(R"( +let s :(string); s = (2.,3); +)", + "s", (std::vector<std::string>{std::to_string(2.), std::to_string(3)})); + + CHECK_AFFECTATION_RESULT(R"( +let s :(string); s = (2.,3,"foo"); +)", + "s", + (std::vector<std::string>{std::to_string(2.), std::to_string(3), std::string{"foo"}})); + + const std::string x_string = []() -> std::string { + std::ostringstream os; + os << TinyVector<2, double>{1, 2} << std::ends; + return os.str(); + }(); + + CHECK_AFFECTATION_RESULT(R"( +let x : R^2, x = (1,2); +let s : (string); s = (2.,3, x); +)", + "s", (std::vector<std::string>{std::to_string(2.), std::to_string(3), x_string})); + + CHECK_AFFECTATION_RESULT(R"( +let x : R^2, x = (1,2); +let t :(R^2); t = (x,0); +)", + "t", (std::vector<TinyVector<2>>{TinyVector<2>{1, 2}, TinyVector<2>{0, 0}})); + + CHECK_AFFECTATION_RESULT(R"( +let t :(R^2); t = ((1,2),0); +)", + "t", (std::vector<TinyVector<2>>{TinyVector<2>{1, 2}, TinyVector<2>{0, 0}})); + + CHECK_AFFECTATION_RESULT(R"( +let t :(R^2); t = (0); +)", + "t", (std::vector<TinyVector<2>>{TinyVector<2>{0, 0}})); + + CHECK_AFFECTATION_RESULT(R"( +let t :(R^3); t = (0); +)", + "t", (std::vector<TinyVector<3>>{TinyVector<3>{0, 0, 0}})); + + CHECK_AFFECTATION_RESULT(R"( +let x : R^1, x = 1; +let t :(R^1); t = (x,2); +)", + "t", (std::vector<TinyVector<1>>{TinyVector<1>{1}, TinyVector<1>{2}})); + } + + SECTION("Affectations from tuple") + { + const std::string x_string = []() -> std::string { + std::ostringstream os; + os << TinyVector<3, double>{1, 2, 3} << std::ends; + return os.str(); + }(); + + CHECK_AFFECTATION_RESULT(R"( +let x :(R^3), x = ((1,2,3)); +let s :(string); s = x; +)", + "s", (std::vector<std::string>{x_string})); + + CHECK_AFFECTATION_RESULT(R"( +let x :(R), x = (1,2,3); +let s :(string); s = x; +)", + "s", + (std::vector<std::string>{std::to_string(1.), std::to_string(2.), std::to_string(3.)})); + + CHECK_AFFECTATION_RESULT(R"( +let n :(N), n = (1,2,3); +let t :(R); t = n; +)", + "t", (std::vector<double>{1, 2, 3})); + + CHECK_AFFECTATION_RESULT(R"( +let s :(N), s = (1,2,3); +let t :(N); t = s; +)", + "t", (std::vector<uint64_t>{1, 2, 3})); + } +} diff --git a/tests/test_DataVariant.cpp b/tests/test_DataVariant.cpp index 1fa8cf72be599782c25fd88f22613e465df818e8..92ca82b9aeb7ee68c9698f973ce48d457fd27696 100644 --- a/tests/test_DataVariant.cpp +++ b/tests/test_DataVariant.cpp @@ -34,7 +34,7 @@ TEST_CASE("DataVariant", "[language]") REQUIRE(std::get<std::vector<double>>(aggregate[2]) == std::vector<double>{1, 2.7}); } - SECTION("Copy") + SECTION("copy") { AggregateDataVariant aggregate_copy{aggregate}; @@ -48,5 +48,40 @@ TEST_CASE("DataVariant", "[language]") REQUIRE(std::get<int64_t>(aggregate[1]) == std::get<int64_t>(aggregate_copy[1])); REQUIRE(std::get<std::vector<double>>(aggregate[2]) == std::get<std::vector<double>>(aggregate_copy[2])); } + + SECTION("affectation") + { + AggregateDataVariant aggregate_copy; + aggregate_copy = aggregate; + + REQUIRE(aggregate.size() == aggregate_copy.size()); + + for (size_t i = 0; i < aggregate.size(); ++i) { + REQUIRE(aggregate[i].index() == aggregate_copy[i].index()); + } + + REQUIRE(std::get<double>(aggregate[0]) == std::get<double>(aggregate_copy[0])); + REQUIRE(std::get<int64_t>(aggregate[1]) == std::get<int64_t>(aggregate_copy[1])); + REQUIRE(std::get<std::vector<double>>(aggregate[2]) == std::get<std::vector<double>>(aggregate_copy[2])); + } + + SECTION("move affectation") + { + AggregateDataVariant aggregate_move_copy; + { + AggregateDataVariant aggregate_copy{aggregate}; + aggregate_move_copy = std::move(aggregate_copy); + } + + REQUIRE(aggregate.size() == aggregate_move_copy.size()); + + for (size_t i = 0; i < aggregate.size(); ++i) { + REQUIRE(aggregate[i].index() == aggregate_move_copy[i].index()); + } + + REQUIRE(std::get<double>(aggregate[0]) == std::get<double>(aggregate_move_copy[0])); + REQUIRE(std::get<int64_t>(aggregate[1]) == std::get<int64_t>(aggregate_move_copy[1])); + REQUIRE(std::get<std::vector<double>>(aggregate[2]) == std::get<std::vector<double>>(aggregate_move_copy[2])); + } } } diff --git a/tests/test_FunctionArgumentConverter.cpp b/tests/test_FunctionArgumentConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e3d2ee0939c306fb971274c782268b161125bee6 --- /dev/null +++ b/tests/test_FunctionArgumentConverter.cpp @@ -0,0 +1,160 @@ +#include <catch2/catch.hpp> + +#include <language/node_processor/FunctionArgumentConverter.hpp> +#include <language/utils/SymbolTable.hpp> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("FunctionArgumentConverter", "[language]") +{ + ExecutionPolicy::Context context(0, std::make_shared<ExecutionPolicy::Context::Values>(3)); + ExecutionPolicy execution_policy(ExecutionPolicy{}, context); + + SECTION("FunctionArgumentToStringConverter") + { + const std::string s{"foo"}; + FunctionArgumentToStringConverter converter0{0}; + converter0.convert(execution_policy, s); + + const TinyVector<3> X{1, 3.2, 4}; + FunctionArgumentToStringConverter converter1{1}; + converter1.convert(execution_policy, X); + std::ostringstream os_X; + os_X << X << std::ends; + + const double x = 3.2; + FunctionArgumentToStringConverter converter2{2}; + converter2.convert(execution_policy, x); + + REQUIRE(std::get<std::string>(execution_policy.currentContext()[0]) == s); + REQUIRE(std::get<std::string>(execution_policy.currentContext()[1]) == os_X.str()); + REQUIRE(std::get<std::string>(execution_policy.currentContext()[2]) == std::to_string(x)); + } + + SECTION("FunctionArgumentConverter") + { + const double double_value = 1.7; + FunctionArgumentConverter<double, double> converter0{0}; + converter0.convert(execution_policy, double{double_value}); + + const uint64_t uint64_value = 3; + FunctionArgumentConverter<double, uint64_t> converter1{1}; + converter1.convert(execution_policy, uint64_value); + + const bool bool_value = false; + FunctionArgumentConverter<uint64_t, bool> converter2{2}; + converter2.convert(execution_policy, bool_value); + + REQUIRE(std::get<double>(execution_policy.currentContext()[0]) == double_value); + REQUIRE(std::get<double>(execution_policy.currentContext()[1]) == static_cast<double>(uint64_value)); + REQUIRE(std::get<uint64_t>(execution_policy.currentContext()[2]) == static_cast<uint64_t>(bool_value)); + } + + SECTION("FunctionTinyVectorArgumentConverter") + { + const TinyVector<3> x3{1.7, 2.9, -3}; + FunctionTinyVectorArgumentConverter<TinyVector<3>, TinyVector<3>> converter0{0}; + converter0.convert(execution_policy, TinyVector{x3}); + + const double x1 = 6.3; + FunctionTinyVectorArgumentConverter<TinyVector<1>, double> converter1{1}; + converter1.convert(execution_policy, double{x1}); + + AggregateDataVariant values{std::vector<DataVariant>{6.3, 3.2, 4ul}}; + FunctionTinyVectorArgumentConverter<TinyVector<3>, TinyVector<3>> converter2{2}; + converter2.convert(execution_policy, values); + + REQUIRE(std::get<TinyVector<3>>(execution_policy.currentContext()[0]) == x3); + REQUIRE(std::get<TinyVector<1>>(execution_policy.currentContext()[1]) == TinyVector<1>{x1}); + REQUIRE(std::get<TinyVector<3>>(execution_policy.currentContext()[2]) == TinyVector<3>{6.3, 3.2, 4ul}); + + AggregateDataVariant bad_values{std::vector<DataVariant>{6.3, 3.2, std::string{"bar"}}}; + + REQUIRE_THROWS_WITH(converter2.convert(execution_policy, bad_values), std::string{"unexpected error: "} + + demangle<std::string>() + + " unexpected aggregate value type"); + } + + SECTION("FunctionTupleArgumentConverter") + { + const TinyVector<3> x3{1.7, 2.9, -3}; + FunctionTupleArgumentConverter<TinyVector<3>, TinyVector<3>> converter0{0}; + converter0.convert(execution_policy, TinyVector{x3}); + + const double a = 1.2; + const double b = -3.5; + const double c = 2.6; + FunctionTupleArgumentConverter<double, double> converter1{1}; + converter1.convert(execution_policy, std::vector{a, b, c}); + + const uint64_t i = 1; + const uint64_t j = 3; + const uint64_t k = 6; + FunctionTupleArgumentConverter<double, uint64_t> converter2{2}; + converter2.convert(execution_policy, std::vector<uint64_t>{i, j, k}); + + REQUIRE(std::get<std::vector<TinyVector<3>>>(execution_policy.currentContext()[0]) == + std::vector<TinyVector<3>>{x3}); + REQUIRE(std::get<std::vector<double>>(execution_policy.currentContext()[1]) == std::vector<double>{a, b, c}); + REQUIRE(std::get<std::vector<double>>(execution_policy.currentContext()[2]) == std::vector<double>{i, j, k}); + + converter1.convert(execution_policy, a); + REQUIRE(std::get<std::vector<double>>(execution_policy.currentContext()[1]) == std::vector<double>{a}); + + converter1.convert(execution_policy, j); + REQUIRE(std::get<std::vector<double>>(execution_policy.currentContext()[1]) == std::vector<double>{j}); + + // Errors + REQUIRE_THROWS_WITH(converter0.convert(execution_policy, j), + "unexpected error: cannot convert 'unsigned long' to 'TinyVector<3ul, double>'"); + } + + SECTION("FunctionListArgumentConverter") + { + const uint64_t i = 3; + FunctionListArgumentConverter<double, double> converter0{0}; + converter0.convert(execution_policy, i); + + const double a = 6.3; + const double b = -1.3; + const double c = 3.6; + FunctionListArgumentConverter<double, double> converter1{1}; + converter1.convert(execution_policy, std::vector<double>{a, b, c}); + + AggregateDataVariant v{std::vector<DataVariant>{1ul, 2.3, -3l}}; + FunctionListArgumentConverter<double, double> converter2{2}; + converter2.convert(execution_policy, v); + + REQUIRE(std::get<std::vector<double>>(execution_policy.currentContext()[0]) == std::vector<double>{i}); + REQUIRE(std::get<std::vector<double>>(execution_policy.currentContext()[1]) == std::vector<double>{a, b, c}); + REQUIRE(std::get<std::vector<double>>(execution_policy.currentContext()[2]) == std::vector<double>{1ul, 2.3, -3l}); + + FunctionListArgumentConverter<TinyVector<2>, TinyVector<2>> converterR2_0{0}; + converterR2_0.convert(execution_policy, TinyVector<2>{1, 3.2}); + + FunctionListArgumentConverter<TinyVector<2>, TinyVector<2>> converterR2_1{1}; + converterR2_1.convert(execution_policy, std::vector{TinyVector<2>{1, 3.2}, TinyVector<2>{-1, 0.2}}); + + AggregateDataVariant v_R2{std::vector<DataVariant>{TinyVector<2>{-3, 12.2}, TinyVector<2>{2, 1.2}}}; + FunctionListArgumentConverter<TinyVector<2>, TinyVector<2>> converterR2_2{2}; + converterR2_2.convert(execution_policy, v_R2); + + REQUIRE(std::get<std::vector<TinyVector<2>>>(execution_policy.currentContext()[0]) == + std::vector<TinyVector<2>>{TinyVector<2>{1, 3.2}}); + REQUIRE(std::get<std::vector<TinyVector<2>>>(execution_policy.currentContext()[1]) == + std::vector<TinyVector<2>>{TinyVector<2>{1, 3.2}, TinyVector<2>{-1, 0.2}}); + REQUIRE(std::get<std::vector<TinyVector<2>>>(execution_policy.currentContext()[2]) == + std::vector<TinyVector<2>>{TinyVector<2>{-3, 12.2}, TinyVector<2>{2, 1.2}}); + } + + SECTION("FunctionArgumentToFunctionSymbolIdConverter") + { + std::shared_ptr symbol_table = std::make_shared<SymbolTable>(); + + const uint64_t f_id = 3; + FunctionArgumentToFunctionSymbolIdConverter converter0{0, symbol_table}; + converter0.convert(execution_policy, f_id); + + REQUIRE(std::get<FunctionSymbolId>(execution_policy.currentContext()[0]).id() == f_id); + } +} diff --git a/tests/test_IfProcessor.cpp b/tests/test_IfProcessor.cpp index ccade16253ae5b1024a97cc5ba038ec222bf5156..71fc766845d22090e319ea02f071e8707d72eed5 100644 --- a/tests/test_IfProcessor.cpp +++ b/tests/test_IfProcessor.cpp @@ -102,6 +102,30 @@ if(false) { CHECK_IF_PROCESSOR_RESULT(data, "i", 2ul); } + SECTION("simple if(true) with local variable") + { + std::string_view data = R"( +let i:N, i = 0; +if(true) { + let j:N, j = 1; + i = j; +} +)"; + CHECK_IF_PROCESSOR_RESULT(data, "i", 1ul); + } + + SECTION("simple if(false) with else local variable") + { + std::string_view data = R"( +let i:N, i = 0; +if(false) {} else { + let j:N, j = 1; + i = j; +} +)"; + CHECK_IF_PROCESSOR_RESULT(data, "i", 1ul); + } + SECTION("errors") { SECTION("bad test type") diff --git a/tests/test_ParseError.cpp b/tests/test_ParseError.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0fb8eb5dca61f1098592eafd1d84d51f2e953bc0 --- /dev/null +++ b/tests/test_ParseError.cpp @@ -0,0 +1,39 @@ +#include <catch2/catch.hpp> + +#include <language/utils/ParseError.hpp> + +#include <string> + +// clazy:excludeall=non-pod-global-static + +TEST_CASE("ParseError", "[language]") +{ + SECTION("single position") + { + const std::string source = R"( +a first line +a second line +)"; + TAO_PEGTL_NAMESPACE::internal::iterator i(&source[0], 3, 1, 2); + TAO_PEGTL_NAMESPACE::position p{i, source}; + ParseError parse_error("error message", p); + REQUIRE(parse_error.positions() == std::vector{p}); + REQUIRE(parse_error.what() == std::string{"error message"}); + } + + SECTION("position list") + { + const std::string source = R"( +a first line +a second line +)"; + TAO_PEGTL_NAMESPACE::internal::iterator i0(&source[0], 3, 1, 2); + TAO_PEGTL_NAMESPACE::position p0{i0, source}; + TAO_PEGTL_NAMESPACE::internal::iterator i1(&source[0], 4, 1, 3); + TAO_PEGTL_NAMESPACE::position p1{i1, source}; + + ParseError parse_error("error message", std::vector{p0, p1}); + REQUIRE(parse_error.positions() == std::vector{p0, p1}); + REQUIRE(parse_error.what() == std::string{"error message"}); + } +} diff --git a/tests/test_SparseMatrixDescriptor.cpp b/tests/test_SparseMatrixDescriptor.cpp index f90cc83b3778e39a3319824f53a34e2041dadcf7..8616a41da0ff8a60857ef314c74e04becf6c651f 100644 --- a/tests/test_SparseMatrixDescriptor.cpp +++ b/tests/test_SparseMatrixDescriptor.cpp @@ -132,7 +132,8 @@ TEST_CASE("SparseMatrixDescriptor", "[algebra]") REQUIRE(graph[3].size() == 2); REQUIRE(graph[4].size() == 2); - REQUIRE(graph[0][0] == 2); + REQUIRE(graph[0][0] == 0); + REQUIRE(graph[0][1] == 2); REQUIRE(graph[1][0] == 1); REQUIRE(graph[1][1] == 2); REQUIRE(graph[2][0] == 2); @@ -159,14 +160,15 @@ TEST_CASE("SparseMatrixDescriptor", "[algebra]") REQUIRE(value_array.size() == 9); - REQUIRE(value_array[0] == 5); - REQUIRE(value_array[1] == 1); - REQUIRE(value_array[2] == 11); - REQUIRE(value_array[3] == 4); - REQUIRE(value_array[4] == -3); - REQUIRE(value_array[5] == 5); - REQUIRE(value_array[6] == 1); - REQUIRE(value_array[7] == -2); + REQUIRE(value_array[0] == 0); + REQUIRE(value_array[1] == 5); + REQUIRE(value_array[2] == 1); + REQUIRE(value_array[3] == 11); + REQUIRE(value_array[4] == 4); + REQUIRE(value_array[5] == -3); + REQUIRE(value_array[6] == 5); + REQUIRE(value_array[7] == 1); + REQUIRE(value_array[8] == -2); } SECTION("output")