#include <catch2/catch.hpp> #include <language/ast/ASTBuilder.hpp> #include <language/ast/ASTSymbolInitializationChecker.hpp> #include <language/ast/ASTSymbolTableBuilder.hpp> #include <pegtl/string_input.hpp> // clazy:excludeall=non-pod-global-static TEST_CASE("ASTSymbolInitializationChecker", "[language]") { SECTION("Declarative initialization") { std::string_view data = R"( let m:N, m = 2; let n:N, n = m ; let p:N; )"; string_input input{data, "test.pgs"}; auto ast = ASTBuilder::build(input); ASTSymbolTableBuilder{*ast}; ASTSymbolInitializationChecker{*ast}; position position{internal::iterator{"fixture"}, "fixture"}; position.byte = data.size(); // ensure that variables are declared at this point auto [symbol_m, found_m] = ast->m_symbol_table->find("m", position); REQUIRE(found_m); REQUIRE(symbol_m->attributes().isInitialized()); auto [symbol_n, found_n] = ast->m_symbol_table->find("n", position); REQUIRE(found_n); REQUIRE(symbol_n->attributes().isInitialized()); auto [symbol_p, found_p] = ast->m_symbol_table->find("p", position); REQUIRE(found_p); REQUIRE(not symbol_p->attributes().isInitialized()); } SECTION("Array subscript initialization") { std::string_view data = R"( let x:R^3; x[0] = 1; )"; string_input input{data, "test.pgs"}; auto ast = ASTBuilder::build(input); ASTSymbolTableBuilder{*ast}; ASTSymbolInitializationChecker{*ast}; position position{internal::iterator{"fixture"}, "fixture"}; position.byte = data.size(); // ensure that variables are declared at this point auto [symbol_m, found_m] = ast->m_symbol_table->find("x", position); REQUIRE(found_m); REQUIRE(symbol_m->attributes().isInitialized()); } SECTION("Declaration plus affectation") { std::string_view data = R"( let z:Z; let m:N; let n:N; n = 2; m = n; )"; string_input input{data, "test.pgs"}; auto ast = ASTBuilder::build(input); ASTSymbolTableBuilder{*ast}; ASTSymbolInitializationChecker{*ast}; position position{internal::iterator{"fixture"}, "fixture"}; position.byte = data.size(); // ensure that variables are declared at this point auto [symbol_m, found_m] = ast->m_symbol_table->find("m", position); REQUIRE(found_m); REQUIRE(symbol_m->attributes().isInitialized()); auto [symbol_n, found_n] = ast->m_symbol_table->find("n", position); REQUIRE(found_n); REQUIRE(symbol_n->attributes().isInitialized()); auto [symbol_z, found_z] = ast->m_symbol_table->find("z", position); REQUIRE(found_z); REQUIRE(not symbol_z->attributes().isInitialized()); } SECTION("Declarative function initialization") { std::string_view data = R"( let f: R->R, x->x+1; )"; string_input input{data, "test.pgs"}; auto ast = ASTBuilder::build(input); ASTSymbolTableBuilder{*ast}; ASTSymbolInitializationChecker{*ast}; position position{internal::iterator{"fixture"}, "fixture"}; position.byte = data.size(); // ensure that variables are declared at this point auto [symbol_m, found_m] = ast->m_symbol_table->find("f", position); REQUIRE(found_m); REQUIRE(symbol_m->attributes().isInitialized()); } SECTION("Lists") { SECTION("Declarative initialization") { std::string_view data = R"( let (x,y):R*R, (x,y) = (2.3, 4.1); )"; string_input input{data, "test.pgs"}; auto ast = ASTBuilder::build(input); ASTSymbolTableBuilder{*ast}; ASTSymbolInitializationChecker{*ast}; position position{internal::iterator{"fixture"}, "fixture"}; position.byte = data.size(); // ensure that variables are declared at this point auto [symbol_x, found_x] = ast->m_symbol_table->find("x", position); REQUIRE(found_x); REQUIRE(symbol_x->attributes().isInitialized()); auto [symbol_y, found_y] = ast->m_symbol_table->find("y", position); REQUIRE(found_y); REQUIRE(symbol_y->attributes().isInitialized()); } SECTION("Declarative initialization") { std::string_view data = R"( let x:R^2, x = (2.3, 4.1); )"; string_input input{data, "test.pgs"}; auto ast = ASTBuilder::build(input); ASTSymbolTableBuilder{*ast}; ASTSymbolInitializationChecker{*ast}; position position{internal::iterator{"fixture"}, "fixture"}; position.byte = data.size(); // ensure that variables are declared at this point auto [symbol_x, found_x] = ast->m_symbol_table->find("x", position); REQUIRE(found_x); REQUIRE(symbol_x->attributes().isInitialized()); } SECTION("Not initialized") { std::string_view data = R"( let(x,y):R*R; y = 3; )"; string_input input{data, "test.pgs"}; auto ast = ASTBuilder::build(input); ASTSymbolTableBuilder{*ast}; ASTSymbolInitializationChecker{*ast}; position position{internal::iterator{"fixture"}, "fixture"}; position.byte = data.size(); // ensure that variables are declared at this point auto [symbol_x, found_x] = ast->m_symbol_table->find("x", position); REQUIRE(found_x); REQUIRE(not symbol_x->attributes().isInitialized()); auto [symbol_y, found_y] = ast->m_symbol_table->find("y", position); REQUIRE(found_y); REQUIRE(symbol_y->attributes().isInitialized()); } SECTION("Affectation") { std::string_view data = R"( let (x,y):R*R; (x,y) = (2.3, 4.1); )"; string_input input{data, "test.pgs"}; auto ast = ASTBuilder::build(input); ASTSymbolTableBuilder{*ast}; ASTSymbolInitializationChecker{*ast}; position position{internal::iterator{"fixture"}, "fixture"}; position.byte = data.size(); // ensure that variables are declared at this point auto [symbol_x, found_x] = ast->m_symbol_table->find("x", position); REQUIRE(found_x); REQUIRE(symbol_x->attributes().isInitialized()); auto [symbol_y, found_y] = ast->m_symbol_table->find("y", position); REQUIRE(found_y); REQUIRE(symbol_y->attributes().isInitialized()); } SECTION("Affectation") { std::string_view data = R"( let (x,y):R^3*R; (x,y) = ((2.3, 2, 5), 4.1); )"; string_input input{data, "test.pgs"}; auto ast = ASTBuilder::build(input); ASTSymbolTableBuilder{*ast}; ASTSymbolInitializationChecker{*ast}; position position{internal::iterator{"fixture"}, "fixture"}; position.byte = data.size(); // ensure that variables are declared at this point auto [symbol_x, found_x] = ast->m_symbol_table->find("x", position); REQUIRE(found_x); REQUIRE(symbol_x->attributes().isInitialized()); auto [symbol_y, found_y] = ast->m_symbol_table->find("y", position); REQUIRE(found_y); REQUIRE(symbol_y->attributes().isInitialized()); } } SECTION("Affectation") { std::string_view data = R"( let x:R^3; (x[2], x[1], x[0]) = (1, 2, 3); )"; string_input input{data, "test.pgs"}; auto ast = ASTBuilder::build(input); ASTSymbolTableBuilder{*ast}; ASTSymbolInitializationChecker{*ast}; position position{internal::iterator{"fixture"}, "fixture"}; position.byte = data.size(); // ensure that variables are declared at this point auto [symbol_x, found_x] = ast->m_symbol_table->find("x", position); REQUIRE(found_x); REQUIRE(symbol_x->attributes().isInitialized()); } SECTION("errors") { SECTION("used uninitialized") { std::string_view data = R"( let n:N; let m:N, m = n; )"; string_input input{data, "test.pgs"}; auto ast = ASTBuilder::build(input); ASTSymbolTableBuilder{*ast}; REQUIRE_THROWS_WITH(ASTSymbolInitializationChecker{*ast}, std::string{"uninitialized symbol 'n'"}); } SECTION("used uninitialized in list affectation") { std::string_view data = R"( let k:N; let (l, x) : N*R; (k, x) = (l, 3.2); )"; string_input input{data, "test.pgs"}; auto ast = ASTBuilder::build(input); ASTSymbolTableBuilder{*ast}; REQUIRE_THROWS_WITH(ASTSymbolInitializationChecker{*ast}, std::string{"uninitialized symbol 'l'"}); } SECTION("used uninitialized in function") { std::string_view data = R"( let y:R; let f : R->R, x->x+y; )"; string_input input{data, "test.pgs"}; auto ast = ASTBuilder::build(input); 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"}); } } }