#include #include "../lib/Lexer.hpp" #include "../lib/Parser.hpp" #include "lib/SrcLoc.hpp" #include "lib/StatusLog.hpp" class ParserTest { public: explicit ParserTest() {} virtual ~ParserTest() {} void test_node(std::string const& oracle, std::string const& source) { roza::SrcLoc loc {"parser_tests"}; roza::StatusLog log; roza::Lexer lexer {log, loc}; roza::Parser parser {lexer, log}; lexer.scan(source); auto node = parser.parse(); REQUIRE(oracle == node->string()); } void test_node_err(std::string const& oracle) { roza::SrcLoc loc {"parser_tests"}; roza::StatusLog log; roza::Lexer lexer {log, loc}; roza::Parser parser {lexer, log}; lexer.scan(oracle); REQUIRE_THROWS(parser.parse()); } protected: }; TEST_CASE_METHOD(ParserTest, "Parser_integers") { test_node("PROG", ""); test_node("PROG(INT[27])", " 27 "); test_node("PROG(INT[27])", " 27 "); test_node("PROG(INT[27]," "INT[9]," "USUB(INT[99]))", "27 \n 9 \n -99"); test_node_err("32 14 -12"); } TEST_CASE_METHOD(ParserTest, "Parser_int_arith") { test_node("PROG(ADD(ADD(INT[1],INT[2]),INT[3]))", "1 + 2 + 3"); test_node("PROG(SUB(SUB(INT[1],INT[2]),INT[3]))", "1 - 2 - 3"); test_node("PROG(ADD(INT[1],MUL(INT[2],INT[3])))", "1 + 2 * 3"); test_node("PROG(MUL(ADD(INT[1],INT[2]),INT[3]))", "(1 + 2) * 3"); test_node("PROG(SUB(INT[1],DIV(INT[2],INT[3])))", "1 - 2 / 3"); test_node("PROG(DIV(SUB(INT[1],INT[2]),INT[3]))", "(1 - 2) / 3"); test_node("PROG(ADD(INT[1],MOD(INT[2],INT[3])))", "1 + 2 % 3"); test_node("PROG(ADD(USUB(INT[2]),INT[3]))", "-2 + 3"); test_node("PROG(ADD(UADD(INT[2]),INT[3]))", "+ 2 + 3"); test_node("PROG(USUB(ADD(INT[2],INT[3])))", " -(2 + 3)"); test_node("PROG(USUB(POW(INT[2],INT[7])))", " -2^7 "); } TEST_CASE_METHOD(ParserTest, "Parser_bool") { test_node("PROG(BOOL[true])", "true"); test_node("PROG(AND(BOOL[true],BOOL[false]))", "true and false"); test_node("PROG(OR(BOOL[true],BOOL[false]))", "true or false"); test_node("PROG(NOT(BOOL[false]))", "not false"); test_node("PROG(NOT(OR(BOOL[false],BOOL[true])))", "not (false or true)"); test_node("PROG(IMP(BOOL[true],BOOL[false]))", "true => false"); } TEST_CASE_METHOD(ParserTest, "Parser_comparisons") { test_node("PROG(LT(INT[5],INT[3]))", "5 < 3"); test_node("PROG(EQ(LE(INT[5],INT[3]),BOOL[false]))", "5 <= 3 == false"); } TEST_CASE_METHOD(ParserTest, "Parser_assertions") { test_node("PROG(ASSERT(EQ(ADD(INT[1],INT[1]),INT[2])))", "assert 1 + 1 == 2"); test_node("PROG(ASSERT_STATIC_FAIL(EQ(ADD(INT[1],INT[1]),INT[2])))", "assert_static_fail 1 + 1 == 2"); } TEST_CASE_METHOD(ParserTest, "Parser_vardecl") { test_node("PROG(VARDECL(IDENT[x],INT[34]))", "let! x = 34"); test_node("PROG(CONSTDECL(IDENT[x],INT[34]))", "let x = 34"); test_node("PROG(CONSTDECL(IDENT[_coucou],MUL(INT[6],INT[7])))", "let _coucou = 6 * 7"); } TEST_CASE_METHOD(ParserTest, "Parser_if") { test_node("PROG(IF(BOOL[true],THEN(ASSIGN(IDENT[x],INT[4]))))", "if true x = 4; end"); test_node("PROG(IF(BOOL[true],THEN(INT[1]),ELSE(INT[4])))", "if true 1; else 4; end"); test_node("PROG(IF(BOOL[true],THEN(INT[0])," "IF(BOOL[false],THEN(INT[1])," "IF(BOOL[true],THEN(INT[2])," "ELSE(INT[3])))))", "if true 0; else if false 1; else if true 2; else 3; end"); }