Select Git revision
test_ASTNodeDataTypeBuilder.cpp
test_ASTBuilder.cpp 16.36 KiB
#include <catch2/catch.hpp>
#include <language/ast/ASTBuilder.hpp>
#include <language/utils/ASTPrinter.hpp>
#include <pegtl/string_input.hpp>
#include <sstream>
#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>); \
\
string_input input{data, "test.pgs"}; \
auto ast = ASTBuilder::build(input); \
\
std::stringstream ast_output; \
ast_output << '\n' << ASTPrinter{*ast, ASTPrinter::Format::raw, {ASTPrinter::Info::none}}; \
\
REQUIRE(ast_output.str() == expected_output); \
}
// clazy:excludeall=non-pod-global-static
TEST_CASE("ASTBuilder", "[language]")
{
rang::setControlMode(rang::control::Off);
SECTION("AST parsing")
{
SECTION("declarations with init")
{
std::string_view data = R"(
let n:N, n = 2;
let z:Z, z = 3;
let r :R,r= 2.3e-5;
let b: B ,b = false;
let s : string, s = "foo";
)";
std::string_view result = R"(
(root)
+-(language::var_declaration)
| +-(language::name:n)
| +-(language::N_set)
| +-(language::name:n)
| `-(language::integer:2)
+-(language::var_declaration)
| +-(language::name:z)
| +-(language::Z_set)
| +-(language::name:z)
| `-(language::integer:3)
+-(language::var_declaration)
| +-(language::name:r)
| +-(language::R_set)
| +-(language::name:r)
| `-(language::real:2.3e-5)
+-(language::var_declaration)
| +-(language::name:b)
| +-(language::B_set)
| +-(language::name:b)
| `-(language::false_kw)
`-(language::var_declaration)
+-(language::name:s)
+-(language::string_type)
+-(language::name:s)
`-(language::literal:"foo")
)";
CHECK_AST(data, result);
}
SECTION("affectations")
{
std::string_view data = R"(
let n:N; n = 2;
let z:Z; z = 3;
let r:R; r = 2.3e-5;
let b:B; b = false;
let s:string; s = "foo";
)";
std::string_view result = R"(
(root)
+-(language::var_declaration)
| +-(language::name:n)
| `-(language::N_set)
+-(language::eq_op)
| +-(language::name:n)
| `-(language::integer:2)
+-(language::var_declaration)
| +-(language::name:z)
| `-(language::Z_set)
+-(language::eq_op)
| +-(language::name:z)
| `-(language::integer:3)
+-(language::var_declaration)
| +-(language::name:r)
| `-(language::R_set)
+-(language::eq_op)
| +-(language::name:r)
| `-(language::real:2.3e-5)
+-(language::var_declaration)
| +-(language::name:b)
| `-(language::B_set)
+-(language::eq_op)
| +-(language::name:b)
| `-(language::false_kw)
+-(language::var_declaration)
| +-(language::name:s)
| `-(language::string_type)
`-(language::eq_op)
+-(language::name:s)
`-(language::literal:"foo")
)";
CHECK_AST(data, result);
}
SECTION("empty blocks simplification")
{
std::string_view data = R"(
{
/* nothing but a block */
{
; // nothing
}
}
)";
std::string_view result = R"(
(root)
)";
CHECK_AST(data, result);
}
SECTION("operators precedence")
{
SECTION("basic operations")
{
std::string_view data = R"(
2+3.2*6 - 3.2/4;
)";
std::string_view result = R"(
(root)
`-(language::minus_op)
+-(language::plus_op)
| +-(language::integer:2)
| `-(language::multiply_op)
| +-(language::real:3.2)
| `-(language::integer:6)
`-(language::divide_op)
+-(language::real:3.2)
`-(language::integer:4)
)";
CHECK_AST(data, result);
}
SECTION("parented expression")
{
std::string_view data = R"(
(2+3)*6;
)";
std::string_view result = R"(
(root)
`-(language::multiply_op)
+-(language::plus_op)
| +-(language::integer:2)
| `-(language::integer:3)
`-(language::integer:6)
)";
CHECK_AST(data, result);
}
SECTION("all operators mix")
{
std::string_view data = R"(
1+2 and 3<= 2 * 4 - 1 == 2 or 2>=1 / 5 xor 7 and 2 or 2 <3 >7 xor -2 + true - not false;
)";
std::string_view result = R"(
(root)
`-(language::or_op)
+-(language::or_op)
| +-(language::and_op)
| | +-(language::plus_op)
| | | +-(language::integer:1)
| | | `-(language::integer:2)
| | `-(language::eqeq_op)
| | +-(language::lesser_or_eq_op)
| | | +-(language::integer:3)
| | | `-(language::minus_op)
| | | +-(language::multiply_op)
| | | | +-(language::integer:2)
| | | | `-(language::integer:4)
| | | `-(language::integer:1)
| | `-(language::integer:2)
| `-(language::and_op)
| +-(language::xor_op)
| | +-(language::greater_or_eq_op)
| | | +-(language::integer:2)
| | | `-(language::divide_op)
| | | +-(language::integer:1)
| | | `-(language::integer:5)
| | `-(language::integer:7)
| `-(language::integer:2)
`-(language::xor_op)
+-(language::greater_op)
| +-(language::lesser_op)
| | +-(language::integer:2)
| | `-(language::integer:3)
| `-(language::integer:7)
`-(language::minus_op)
+-(language::plus_op)
| +-(language::unary_minus)
| | `-(language::integer:2)
| `-(language::true_kw)
`-(language::unary_not)
`-(language::false_kw)
)";
CHECK_AST(data, result);
}
}
SECTION("unary operator simplification")
{
SECTION("multiple not")
{
std::string_view data = R"(
not not not not true;
not not not false;
)";
std::string_view result = R"(
(root)
+-(language::true_kw)
`-(language::unary_not)
`-(language::false_kw)
)";
CHECK_AST(data, result);
}
SECTION("multiple unary plus")
{
std::string_view data = R"(
+ + + 3;
)";
std::string_view result = R"(
(root)
`-(language::integer:3)
)";
CHECK_AST(data, result);
}
SECTION("multiple unary minus")
{
std::string_view data = R"(
- - + - - 3;
- + - - 2;
)";
std::string_view result = R"(
(root)
+-(language::integer:3)
`-(language::unary_minus)
`-(language::integer:2)
)";
CHECK_AST(data, result);
}
SECTION("sums and unary plus/minus")
{
std::string_view data = R"(
1 - - 3;
1 + - 2;
4 - + 3;
)";
std::string_view result = R"(
(root)
+-(language::plus_op)
| +-(language::integer:1)
| `-(language::integer:3)
+-(language::minus_op)
| +-(language::integer:1)
| `-(language::integer:2)
`-(language::minus_op)
+-(language::integer:4)
`-(language::integer:3)
)";
CHECK_AST(data, result);
}
}
SECTION("subscript handling")
{
std::string_view data = R"(
u[a];
u[f(c)];
u[u[b]];
)";
std::string_view result = R"(
(root)
+-(language::subscript_expression)
| +-(language::name:u)
| `-(language::name:a)
+-(language::subscript_expression)
| +-(language::name:u)
| `-(language::function_evaluation)
| +-(language::name:f)
| `-(language::name:c)
`-(language::subscript_expression)
+-(language::name:u)
`-(language::subscript_expression)
+-(language::name:u)
`-(language::name:b)
)";
CHECK_AST(data, result);
}
SECTION("post incr/decr rearrangements")
{
std::string_view data = R"(
1++;
2--;
)";
std::string_view result = R"(
(root)
+-(language::post_plusplus)
| `-(language::integer:1)
`-(language::post_minusminus)
`-(language::integer:2)
)";
CHECK_AST(data, result);
}
SECTION("statement block simplification (one instruction per block)")
{
std::string_view data = R"(
if (a > 0) {
a = 0;
} else {
a =-1;
}
)";
std::string_view result = R"(
(root)
`-(language::if_statement)
+-(language::greater_op)
| +-(language::name:a)
| `-(language::integer:0)
+-(language::eq_op)
| +-(language::name:a)
| `-(language::integer:0)
`-(language::eq_op)
+-(language::name:a)
`-(language::unary_minus)
`-(language::integer:1)
)";
CHECK_AST(data, result);
}
SECTION("statement block simplification (one instruction in first block)")
{
std::string_view data = R"(
if (a > 0) {
a = 0;
} else {
a = 3;
a = a++;
}
)";
std::string_view result = R"(
(root)
`-(language::if_statement)
+-(language::greater_op)
| +-(language::name:a)
| `-(language::integer:0)
+-(language::eq_op)
| +-(language::name:a)
| `-(language::integer:0)
`-(language::block)
+-(language::eq_op)
| +-(language::name:a)
| `-(language::integer:3)
`-(language::eq_op)
+-(language::name:a)
`-(language::post_plusplus)
`-(language::name:a)
)";
CHECK_AST(data, result);
}
SECTION("statement block simplification (one instruction in second block)")
{
std::string_view data = R"(
if (a > 0) {
a = 0;
a++;
} else {
a = 3;
}
)";
std::string_view result = R"(
(root)
`-(language::if_statement)
+-(language::greater_op)
| +-(language::name:a)
| `-(language::integer:0)
+-(language::block)
| +-(language::eq_op)
| | +-(language::name:a)
| | `-(language::integer:0)
| `-(language::post_plusplus)
| `-(language::name:a)
`-(language::eq_op)
+-(language::name:a)
`-(language::integer:3)
)";
CHECK_AST(data, result);
}
SECTION("statement block non-simplification (one declaration in each block)")
{
std::string_view data = R"(
if (a > 0) {
let b:R, b = a;
} else {
let c:R, c = 2*a;
}
)";
std::string_view result = R"(
(root)
`-(language::if_statement)
+-(language::greater_op)
| +-(language::name:a)
| `-(language::integer:0)
+-(language::block)
| `-(language::var_declaration)
| +-(language::name:b)
| +-(language::R_set)
| +-(language::name:b)
| `-(language::name:a)
`-(language::block)
`-(language::var_declaration)
+-(language::name:c)
+-(language::R_set)
+-(language::name:c)
`-(language::multiply_op)
+-(language::integer:2)
`-(language::name:a)
)";
CHECK_AST(data, result);
}
SECTION("statement block simplification (one declaration in first block)")
{
std::string_view data = R"(
if (a > 0) {
let b:R, b = a;
} else {
let c:R, c = 2*a;
++a;
}
)";
std::string_view result = R"(
(root)
`-(language::if_statement)
+-(language::greater_op)
| +-(language::name:a)
| `-(language::integer:0)
+-(language::block)
| `-(language::var_declaration)
| +-(language::name:b)
| +-(language::R_set)
| +-(language::name:b)
| `-(language::name:a)
`-(language::block)
+-(language::var_declaration)
| +-(language::name:c)
| +-(language::R_set)
| +-(language::name:c)
| `-(language::multiply_op)
| +-(language::integer:2)
| `-(language::name:a)
`-(language::unary_plusplus)
`-(language::name:a)
)";
CHECK_AST(data, result);
}
SECTION("statement block simplification (one declaration in second block)")
{
std::string_view data = R"(
if (a > 0) {
let b:R, b = a;
++b;
} else {
let c:R, c = 2*a;
}
)";
std::string_view result = R"(
(root)
`-(language::if_statement)
+-(language::greater_op)
| +-(language::name:a)
| `-(language::integer:0)
+-(language::block)
| +-(language::var_declaration)
| | +-(language::name:b)
| | +-(language::R_set)
| | +-(language::name:b)
| | `-(language::name:a)
| `-(language::unary_plusplus)
| `-(language::name:b)
`-(language::block)
`-(language::var_declaration)
+-(language::name:c)
+-(language::R_set)
+-(language::name:c)
`-(language::multiply_op)
+-(language::integer:2)
`-(language::name:a)
)";
CHECK_AST(data, result);
}
SECTION("for-statements simplification")
{
std::string_view data = R"(
for(let i:N, i=0; i<10; ++i) {
i += 3;
}
)";
std::string_view result = R"(
(root)
`-(language::for_statement)
+-(language::var_declaration)
| +-(language::name:i)
| +-(language::N_set)
| +-(language::name:i)
| `-(language::integer:0)
+-(language::lesser_op)
| +-(language::name:i)
| `-(language::integer:10)
+-(language::unary_plusplus)
| `-(language::name:i)
`-(language::pluseq_op)
+-(language::name:i)
`-(language::integer:3)
)";
CHECK_AST(data, result);
}
SECTION("for-statements simplification (complex block)")
{
std::string_view data = R"(
for(let i:N, i=0; i<10; ++i) {
i += 3;
let j:R, j=i/5.;
}
)";
std::string_view result = R"(
(root)
`-(language::for_statement)
+-(language::var_declaration)
| +-(language::name:i)
| +-(language::N_set)
| +-(language::name:i)
| `-(language::integer:0)
+-(language::lesser_op)
| +-(language::name:i)
| `-(language::integer:10)
+-(language::unary_plusplus)
| `-(language::name:i)
`-(language::for_statement_block)
+-(language::pluseq_op)
| +-(language::name:i)
| `-(language::integer:3)
`-(language::var_declaration)
+-(language::name:j)
+-(language::R_set)
+-(language::name:j)
`-(language::divide_op)
+-(language::name:i)
`-(language::real:5.)
)";
CHECK_AST(data, result);
}
SECTION("ostream simplifications")
{
std::string_view data = R"(
cout << 1+2 << "\n";
cerr << "error?\n";
clog << "log " << l << "\n";
)";
std::string_view result = R"(
(root)
+-(language::cout_kw)
| +-(language::plus_op)
| | +-(language::integer:1)
| | `-(language::integer:2)
| `-(language::literal:"\n")
+-(language::cerr_kw)
| `-(language::literal:"error?\n")
`-(language::clog_kw)
+-(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);
}
}
SECTION("errors")
{
SECTION("syntax error")
{
std::string_view data = R"(
1+; // syntax error
)";
string_input input{data, "test.pgs"};
REQUIRE_THROWS_WITH(ASTBuilder::build(input), "parse error, missing expression");
}
}
}