Skip to content
Snippets Groups Projects
Commit 79d08cd5 authored by Stéphane Del Pino's avatar Stéphane Del Pino
Browse files

Continue clean-up. Add ASTNodeJumpPlacementChecker and its tests.

parent dff663a6
No related branches found
No related tags found
1 merge request!37Feature/language
#include <ASTNodeJumpPlacementChecker.hpp>
#include <PEGGrammar.hpp>
#include <vector>
void
ASTNodeJumpPlacementChecker::_checkJumpPlacement(ASTNode& n, bool is_inside_loop)
{
if (n.is<language::for_statement>() or n.is<language::do_while_statement>() or n.is<language::while_statement>()) {
for (auto& child : n.children) {
this->_checkJumpPlacement(*child, true);
}
} else if (n.is<language::break_kw>() or n.is<language::continue_kw>()) {
if (not is_inside_loop) {
std::ostringstream error_message;
error_message << "unexpected '" << rang::fgB::red << n.string() << rang::fg::reset
<< "' outside of loop or switch statement";
throw parse_error(error_message.str(), std::vector{n.begin()});
}
} else {
for (auto& child : n.children) {
this->_checkJumpPlacement(*child, is_inside_loop);
}
}
}
ASTNodeJumpPlacementChecker::ASTNodeJumpPlacementChecker(ASTNode& n)
{
Assert(n.is_root());
this->_checkJumpPlacement(n, false);
}
#ifndef AST_NODE_JUMP_PLACEMENT_CHECKER_HPP
#define AST_NODE_JUMP_PLACEMENT_CHECKER_HPP
#include <ASTNode.hpp>
class ASTNodeJumpPlacementChecker
{
private:
void _checkJumpPlacement(ASTNode& node, bool is_inside_loop);
public:
ASTNodeJumpPlacementChecker(ASTNode& root_node);
};
#endif // AST_NODE_JUMP_PLACEMENT_CHECKER_HPP
......@@ -14,6 +14,7 @@ add_library(
ASTNodeDataTypeChecker.cpp
ASTNodeExpressionBuilder.cpp
ASTNodeIncDecExpressionBuilder.cpp
ASTNodeJumpPlacementChecker.cpp
ASTNodeUnaryOperatorExpressionBuilder.cpp
ASTNodeValueBuilder.cpp
ASTPrinter.cpp
......
......@@ -22,6 +22,8 @@
#include <ASTNodeDataTypeBuilder.hpp>
#include <ASTNodeDataTypeChecker.hpp>
#include <ASTNodeJumpPlacementChecker.hpp>
#include <ASTNodeExpressionBuilder.hpp>
#include <ASTSymbolInitializationChecker.hpp>
......@@ -34,37 +36,6 @@
namespace language
{
namespace internal
{
void
check_break_or_continue_placement(const ASTNode& n, bool is_inside_loop)
{
if (n.is<language::for_statement>() or n.is<language::do_while_statement>() or n.is<language::while_statement>()) {
for (auto& child : n.children) {
check_break_or_continue_placement(*child, true);
}
} else if (n.is<language::break_kw>() or n.is<language::continue_kw>()) {
if (not is_inside_loop) {
std::ostringstream error_message;
error_message << "unexpected '" << rang::fgB::red << n.string() << rang::fg::reset
<< "' outside of loop or switch statement";
throw parse_error(error_message.str(), std::vector{n.begin()});
}
} else {
for (auto& child : n.children) {
check_break_or_continue_placement(*child, is_inside_loop);
}
}
}
} // namespace internal
void
check_break_or_continue_placement(const ASTNode& n)
{
Assert(n.is_root());
internal::check_break_or_continue_placement(n, false);
}
namespace internal
{
void
......@@ -126,7 +97,7 @@ parser(const std::string& filename)
ASTNodeValueBuilder{*root_node};
language::check_break_or_continue_placement(*root_node);
ASTNodeJumpPlacementChecker{*root_node};
// optimizations
language::simplify_declarations(*root_node);
......
......@@ -10,6 +10,7 @@ add_executable (unit_tests
test_ASTNodeDataType.cpp
test_ASTNodeDataTypeBuilder.cpp
test_ASTNodeDataTypeChecker.cpp
test_ASTNodeJumpPlacementChecker.cpp
test_ASTNodeValueBuilder.cpp
test_ASTPrinter.cpp
test_ASTSymbolTableBuilder.cpp
......
#include <catch2/catch.hpp>
#include <ASTBuilder.hpp>
#include <ASTNodeDataTypeBuilder.hpp>
#include <ASTNodeJumpPlacementChecker.hpp>
TEST_CASE("ASTNodeJumpPlacementChecker", "[language]")
{
SECTION("break")
{
SECTION("in for loop")
{
std::string_view data = R"(
for(;;) {
break;
}
)";
string_input input{data, "test.pgs"};
auto ast = ASTBuilder::build(input);
ASTNodeDataTypeBuilder{*ast};
REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast});
}
SECTION("in while loop")
{
std::string_view data = R"(
while(true) {
break;
}
)";
string_input input{data, "test.pgs"};
auto ast = ASTBuilder::build(input);
ASTNodeDataTypeBuilder{*ast};
REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast});
}
SECTION("in do while loop")
{
std::string_view data = R"(
do {
break;
} while(true);
)";
string_input input{data, "test.pgs"};
auto ast = ASTBuilder::build(input);
ASTNodeDataTypeBuilder{*ast};
REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast});
}
SECTION("misplaced")
{
std::string_view data = R"(
{
break;
}
)";
string_input input{data, "test.pgs"};
auto ast = ASTBuilder::build(input);
ASTNodeDataTypeBuilder{*ast};
ast->children[0]->m_data_type = ASTNodeDataType::undefined_t;
REQUIRE_THROWS_AS(ASTNodeJumpPlacementChecker{*ast}, parse_error);
}
}
SECTION("continue")
{
SECTION("in for loop")
{
std::string_view data = R"(
for(;;) {
continue;
}
)";
string_input input{data, "test.pgs"};
auto ast = ASTBuilder::build(input);
ASTNodeDataTypeBuilder{*ast};
REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast});
}
SECTION("in while loop")
{
std::string_view data = R"(
while(true) {
continue;
}
)";
string_input input{data, "test.pgs"};
auto ast = ASTBuilder::build(input);
ASTNodeDataTypeBuilder{*ast};
REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast});
}
SECTION("in do while loop")
{
std::string_view data = R"(
do {
continue;
} while(true);
)";
string_input input{data, "test.pgs"};
auto ast = ASTBuilder::build(input);
ASTNodeDataTypeBuilder{*ast};
REQUIRE_NOTHROW(ASTNodeJumpPlacementChecker{*ast});
}
SECTION("misplaced")
{
std::string_view data = R"(
{
continue;
}
)";
string_input input{data, "test.pgs"};
auto ast = ASTBuilder::build(input);
ASTNodeDataTypeBuilder{*ast};
ast->children[0]->m_data_type = ASTNodeDataType::undefined_t;
REQUIRE_THROWS_AS(ASTNodeJumpPlacementChecker{*ast}, parse_error);
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment