#include <catch2/catch_test_macros.hpp> #include <catch2/matchers/catch_matchers_all.hpp> #include <language/ast/ASTBuilder.hpp> #include <language/ast/ASTModulesImporter.hpp> #include <language/ast/ASTNodeDataTypeBuilder.hpp> #include <language/ast/ASTNodeDeclarationToAffectationConverter.hpp> #include <language/ast/ASTNodeExpressionBuilder.hpp> #include <language/ast/ASTNodeListAffectationExpressionBuilder.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> #define CHECK_AST(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> or \ std::is_same_v<std::decay_t<decltype(expected_output)>, std::string>); \ \ TAO_PEGTL_NAMESPACE::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::var_declaration>{*ast}; \ ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ \ ASTNodeExpressionBuilder{*ast}; \ \ std::stringstream ast_output; \ ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::exec_type}}; \ \ REQUIRE(ast_output.str() == expected_output); \ } #define CHECK_AST_THROWS_WITH(data, error) \ { \ static_assert(std::is_same_v<std::decay_t<decltype(data)>, std::string_view>); \ static_assert(std::is_same_v<std::decay_t<decltype(error)>, std::string>); \ \ TAO_PEGTL_NAMESPACE::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::var_declaration>{*ast}; \ ASTNodeTypeCleaner<language::fct_declaration>{*ast}; \ \ REQUIRE_THROWS_WITH(ASTNodeExpressionBuilder{*ast}, error); \ } // clazy:excludeall=non-pod-global-static TEST_CASE("ASTNodeListAffectationExpressionBuilder", "[language]") { const std::string demangled_stdstring = demangle(typeid(std::string{}).name()); SECTION("Declaration") { SECTION("without conversion R*R") { std::string_view data = R"( let (x, y) : R*R, (x,y) = (2.3, 6.2); )"; std::string_view result = R"( (root:ASTNodeListProcessor) `-(language::eq_op:ListAffectationProcessor<language::eq_op>) +-(language::name_list:FakeProcessor) | +-(language::name:x:NameProcessor) | `-(language::name:y:NameProcessor) `-(language::expression_list:ASTNodeExpressionListProcessor) +-(language::real:2.3:ValueProcessor) `-(language::real:6.2:ValueProcessor) )"; CHECK_AST(data, result); } SECTION("without conversion B*Z*N") { std::string_view data = R"( let n:N, n = 2; let ( b, z , m ): B*Z*N, (b,z,m) = (false, -2, n); )"; std::string_view result = R"( (root:ASTNodeListProcessor) +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) | +-(language::name:n:NameProcessor) | `-(language::integer:2:ValueProcessor) `-(language::eq_op:ListAffectationProcessor<language::eq_op>) +-(language::name_list:FakeProcessor) | +-(language::name:b:NameProcessor) | +-(language::name:z:NameProcessor) | `-(language::name:m:NameProcessor) `-(language::expression_list:ASTNodeExpressionListProcessor) +-(language::false_kw:ValueProcessor) +-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, long>) | `-(language::integer:2:ValueProcessor) `-(language::name:n:NameProcessor) )"; CHECK_AST(data, result); } SECTION("with conversion R*B*Z*N") { std::string_view data = R"( let (r,b,z,m) : R*B*Z*N, (r,b,z,m) = (3.2, true, 6, 2); )"; std::string_view result = R"( (root:ASTNodeListProcessor) `-(language::eq_op:ListAffectationProcessor<language::eq_op>) +-(language::name_list:FakeProcessor) | +-(language::name:r:NameProcessor) | +-(language::name:b:NameProcessor) | +-(language::name:z:NameProcessor) | `-(language::name:m:NameProcessor) `-(language::expression_list:ASTNodeExpressionListProcessor) +-(language::real:3.2:ValueProcessor) +-(language::true_kw:ValueProcessor) +-(language::integer:6:ValueProcessor) `-(language::integer:2:ValueProcessor) )"; CHECK_AST(data, result); } SECTION("with conversion R*R*R*R") { std::string_view data = R"( let (r,b,z,m): R*R*R*R , (r,b,z,m) = (3.2, 1, 6, 2); )"; std::string_view result = R"( (root:ASTNodeListProcessor) `-(language::eq_op:ListAffectationProcessor<language::eq_op>) +-(language::name_list:FakeProcessor) | +-(language::name:r:NameProcessor) | +-(language::name:b:NameProcessor) | +-(language::name:z:NameProcessor) | `-(language::name:m:NameProcessor) `-(language::expression_list:ASTNodeExpressionListProcessor) +-(language::real:3.2:ValueProcessor) +-(language::integer:1:ValueProcessor) +-(language::integer:6:ValueProcessor) `-(language::integer:2:ValueProcessor) )"; CHECK_AST(data, result); } SECTION("without conversion R^1*R^2*R^3*R") { std::string_view data = R"( let a:R^1, a = 0; let b:R^2, b = (1,2); let c:R^3, c = (1,2,3); let (x1,x2,x3,x) : R^1*R^2*R^3*R, (x1,x2,x3,x) = (a, b, c, 2); )"; std::string_view result = R"( (root:ASTNodeListProcessor) +-(language::eq_op:AffectationFromZeroProcessor<TinyVector<1ul, double> >) | +-(language::name:a:NameProcessor) | `-(language::integer:0:ValueProcessor) +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<2ul, double> >) | +-(language::name:b:NameProcessor) | `-(language::expression_list:ASTNodeExpressionListProcessor) | +-(language::integer:1:ValueProcessor) | `-(language::integer:2:ValueProcessor) +-(language::eq_op:AffectationToTinyVectorFromListProcessor<language::eq_op, TinyVector<3ul, double> >) | +-(language::name:c:NameProcessor) | `-(language::expression_list:ASTNodeExpressionListProcessor) | +-(language::integer:1:ValueProcessor) | +-(language::integer:2:ValueProcessor) | `-(language::integer:3:ValueProcessor) `-(language::eq_op:ListAffectationProcessor<language::eq_op>) +-(language::name_list:FakeProcessor) | +-(language::name:x1:NameProcessor) | +-(language::name:x2:NameProcessor) | +-(language::name:x3:NameProcessor) | `-(language::name:x:NameProcessor) `-(language::expression_list:ASTNodeExpressionListProcessor) +-(language::name:a:NameProcessor) +-(language::name:b:NameProcessor) +-(language::name:c:NameProcessor) `-(language::integer:2:ValueProcessor) )"; CHECK_AST(data, result); } SECTION("without conversion R^1x1*R^2x2*R^3x3*R") { std::string_view data = R"( let a:R^1x1, a = 0; let b:R^2x2, b = (1, 2, 3, 4); let c:R^3x3, c = (9, 8, 7, 6, 5, 4, 3, 2, 1); let (x1,x2,x3,x) : R^1x1*R^2x2*R^3x3*R, (x1,x2,x3,x) = (a, b, c, 2); )"; std::string_view result = R"( (root:ASTNodeListProcessor) +-(language::eq_op:AffectationProcessor<language::eq_op, TinyMatrix<1ul, double>, long>) | +-(language::name:a:NameProcessor) | `-(language::integer:0:ValueProcessor) +-(language::eq_op:AffectationToTinyMatrixFromListProcessor<language::eq_op, TinyMatrix<2ul, double> >) | +-(language::name:b:NameProcessor) | `-(language::expression_list:ASTNodeExpressionListProcessor) | +-(language::integer:1:ValueProcessor) | +-(language::integer:2:ValueProcessor) | +-(language::integer:3:ValueProcessor) | `-(language::integer:4:ValueProcessor) +-(language::eq_op:AffectationToTinyMatrixFromListProcessor<language::eq_op, TinyMatrix<3ul, double> >) | +-(language::name:c:NameProcessor) | `-(language::expression_list:ASTNodeExpressionListProcessor) | +-(language::integer:9:ValueProcessor) | +-(language::integer:8:ValueProcessor) | +-(language::integer:7:ValueProcessor) | +-(language::integer:6:ValueProcessor) | +-(language::integer:5:ValueProcessor) | +-(language::integer:4:ValueProcessor) | +-(language::integer:3:ValueProcessor) | +-(language::integer:2:ValueProcessor) | `-(language::integer:1:ValueProcessor) `-(language::eq_op:ListAffectationProcessor<language::eq_op>) +-(language::name_list:FakeProcessor) | +-(language::name:x1:NameProcessor) | +-(language::name:x2:NameProcessor) | +-(language::name:x3:NameProcessor) | `-(language::name:x:NameProcessor) `-(language::expression_list:ASTNodeExpressionListProcessor) +-(language::name:a:NameProcessor) +-(language::name:b:NameProcessor) +-(language::name:c:NameProcessor) `-(language::integer:2:ValueProcessor) )"; CHECK_AST(data, result); } SECTION("Zero initialization") { std::string_view data = R"( let (x1,x2,x3,x) : R^1*R^2*R^3*R, (x1,x2,x3,x) = (0, 0, 0, 0); )"; std::string_view result = R"( (root:ASTNodeListProcessor) `-(language::eq_op:ListAffectationProcessor<language::eq_op>) +-(language::name_list:FakeProcessor) | +-(language::name:x1:NameProcessor) | +-(language::name:x2:NameProcessor) | +-(language::name:x3:NameProcessor) | `-(language::name:x:NameProcessor) `-(language::expression_list:ASTNodeExpressionListProcessor) +-(language::integer:0:ValueProcessor) +-(language::integer:0:ValueProcessor) +-(language::integer:0:ValueProcessor) `-(language::integer:0:ValueProcessor) )"; CHECK_AST(data, result); } SECTION("Zero initialization") { std::string_view data = R"( let (x1,x2,x3,x) : R^1x1*R^2x2*R^3x3*R, (x1,x2,x3,x) = (0, 0, 0, 0); )"; std::string_view result = R"( (root:ASTNodeListProcessor) `-(language::eq_op:ListAffectationProcessor<language::eq_op>) +-(language::name_list:FakeProcessor) | +-(language::name:x1:NameProcessor) | +-(language::name:x2:NameProcessor) | +-(language::name:x3:NameProcessor) | `-(language::name:x:NameProcessor) `-(language::expression_list:ASTNodeExpressionListProcessor) +-(language::integer:0:ValueProcessor) +-(language::integer:0:ValueProcessor) +-(language::integer:0:ValueProcessor) `-(language::integer:0:ValueProcessor) )"; CHECK_AST(data, result); } SECTION("from function") { std::string_view data = R"( let f: R -> R*R, x -> (x*x, x+1); let (x,y): R*R, (x,y) = f(2); )"; std::string_view result = R"( (root:ASTNodeListProcessor) `-(language::eq_op:ListAffectationProcessor<language::eq_op>) +-(language::name_list:FakeProcessor) | +-(language::name:x:NameProcessor) | `-(language::name:y:NameProcessor) `-(language::function_evaluation:FunctionProcessor) +-(language::name:f:NameProcessor) `-(language::integer:2:ValueProcessor) )"; CHECK_AST(data, result); } SECTION("string without conversion") { std::string_view data = R"( let (s,r): string*string, (s,r) = ("foo","bar"); )"; std::string_view result = R"( (root:ASTNodeListProcessor) `-(language::eq_op:ListAffectationProcessor<language::eq_op>) +-(language::name_list:FakeProcessor) | +-(language::name:s:NameProcessor) | `-(language::name:r:NameProcessor) `-(language::expression_list:ASTNodeExpressionListProcessor) +-(language::literal:"foo":ValueProcessor) `-(language::literal:"bar":ValueProcessor) )"; CHECK_AST(data, result); } SECTION("string with conversion") { std::string_view data = R"( let n:N, n =2; let (r,s,t,u) : string*string*string*string, (r,s,t,u) = (3.2, -2, true, n); )"; std::string_view result = R"( (root:ASTNodeListProcessor) +-(language::eq_op:AffectationProcessor<language::eq_op, unsigned long, long>) | +-(language::name:n:NameProcessor) | `-(language::integer:2:ValueProcessor) `-(language::eq_op:ListAffectationProcessor<language::eq_op>) +-(language::name_list:FakeProcessor) | +-(language::name:r:NameProcessor) | +-(language::name:s:NameProcessor) | +-(language::name:t:NameProcessor) | `-(language::name:u:NameProcessor) `-(language::expression_list:ASTNodeExpressionListProcessor) +-(language::real:3.2:ValueProcessor) +-(language::unary_minus:UnaryExpressionProcessor<language::unary_minus, long, long>) | `-(language::integer:2:ValueProcessor) +-(language::true_kw:ValueProcessor) `-(language::name:n:NameProcessor) )"; CHECK_AST(data, result); } } SECTION("Errors") { SECTION("invalid affectation rhs") { std::string_view data = R"( let x:R; let i:R; (x,i) = 3; )"; CHECK_AST_THROWS_WITH(data, std::string{"invalid right hand side in tuple affectation"}); } SECTION("incompatible list sizes") { std::string_view data = R"( let (x,y) : R*R, (x,y) = (3, 3, 2); )"; CHECK_AST_THROWS_WITH(data, std::string{"incompatible list sizes in affectation"}); } SECTION("incompatible list sizes 2") { std::string_view data = R"( let (x,y,z):R*R*R, (x,y,z) = (1, 2); )"; CHECK_AST_THROWS_WITH(data, std::string{"incompatible list sizes in affectation"}); } SECTION("incompatible list sizes from function evaluation") { std::string_view data = R"( let f: R -> R, x -> x*x; let(x,y) : R*R, (x,y) = f(3); )"; CHECK_AST_THROWS_WITH(data, std::string{"incompatible list sizes in affectation"}); } SECTION("incompatible list sizes from function evaluation") { std::string_view data = R"( let(x,y):R*R,(x,y)=(2,3); (x,y) += (1,4); )"; CHECK_AST_THROWS_WITH(data, std::string{"undefined affectation operator for tuples"}); } SECTION("invalid operand type for affectation") { std::string_view data = R"( let f: R -> R, x -> x+1; let (x,y) : R*R, (x,y) = (f,2); )"; CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: function -> R"}); } SECTION("invalid operand type for string affectation") { std::string_view data = R"( let f: R -> R, x -> x+1; let (s,n):string*N, (s,n) = (f,2); )"; CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: function -> string"}); } SECTION("invalid value type for affectation") { std::string_view data = R"( let f: R -> R, x -> x+1; let x:R; (f,x) = (3,2); )"; CHECK_AST_THROWS_WITH(data, std::string{"invalid implicit conversion: Z -> function"}); } SECTION("invalid R^n -> R^m conversion") { std::string_view data = R"( let x:R^2, x = (1,2); let y:R^3, y = x; )"; CHECK_AST_THROWS_WITH(data, std::string{"undefined affectation type: R^3 = R^2"}); } SECTION("invalid Z -> R^d conversion (non-zero)") { std::string_view data = R"( let x:R^2, x = 1; )"; CHECK_AST_THROWS_WITH(data, std::string{"invalid integral value (0 is the solely valid value)"}); } } }