2023-08-30 18:06:26 +00:00
|
|
|
#include <catch2/catch.hpp>
|
|
|
|
#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", "");
|
2023-08-30 22:31:19 +00:00
|
|
|
test_node("PROG(INT[27])", " 27 ");
|
|
|
|
test_node("PROG(INT[27])", " 27 ");
|
2023-08-30 18:06:26 +00:00
|
|
|
|
2023-08-30 22:31:19 +00:00
|
|
|
test_node("PROG(INT[27],"
|
|
|
|
"INT[9],"
|
|
|
|
"USUB(INT[99]))", "27 \n 9 \n -99");
|
2023-08-30 18:06:26 +00:00
|
|
|
|
|
|
|
test_node_err("32 14 -12");
|
|
|
|
}
|
2023-08-30 22:31:19 +00:00
|
|
|
|
|
|
|
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 ");
|
|
|
|
}
|
2023-08-31 09:07:03 +00:00
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
2023-08-31 09:37:13 +00:00
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
2023-08-31 12:41:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
2023-08-31 19:25:00 +00:00
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
2023-08-31 23:22:51 +00:00
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
2023-09-01 20:38:12 +00:00
|
|
|
|
|
|
|
TEST_CASE_METHOD(ParserTest, "Parser_fun")
|
|
|
|
{
|
|
|
|
test_node("PROG(FUN(PARAMS,RET,BODY))",
|
|
|
|
"fun () end");
|
|
|
|
|
|
|
|
test_node("PROG(FUN(PARAMS("
|
|
|
|
"PARAM(IDENT[x],TYPE[int]),"
|
|
|
|
"PARAM(IDENT[y],TYPE[bool])"
|
|
|
|
"),RET,BODY))",
|
|
|
|
"fun (x as int, y as bool) end");
|
|
|
|
|
|
|
|
test_node("PROG(FUN(PARAMS,RET,BODY(INT[0],INT[1],INT[2])))",
|
|
|
|
"fun () 0; 1; 2; end");
|
|
|
|
|
|
|
|
test_node("PROG(FUN(PARAMS,RET(TYPE[int]),BODY(INT[0],INT[1],INT[2])))",
|
|
|
|
"fun () -> int 0; 1; 2; end");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE_METHOD(ParserTest, "Parser_type")
|
|
|
|
{
|
|
|
|
test_node("PROG(FUN(PARAMS,RET(TYPE[int]),BODY))",
|
|
|
|
"fun () -> int end");
|
|
|
|
|
|
|
|
test_node("PROG(FUN(PARAMS,RET(TYPE[nil]),BODY))",
|
|
|
|
"fun () -> nil end");
|
|
|
|
|
|
|
|
test_node("PROG(FUN(PARAMS,RET(TYPE[fun](TYPE[int],TYPE[bool])),BODY))",
|
|
|
|
"fun () -> fun<int -> bool> end");
|
|
|
|
|
|
|
|
test_node("PROG(FUN(PARAMS,RET(TYPE[fun](TYPE[int],TYPE[fun]("
|
|
|
|
"TYPE[bool],TYPE[bool]"
|
|
|
|
"))),BODY))",
|
|
|
|
"fun () -> fun< int -> fun<bool -> bool> > end");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE_METHOD(ParserTest, "Parser_call")
|
|
|
|
{
|
|
|
|
test_node("PROG(CALL(IDENT[f],ARGS(IDENT[a],IDENT[b],IDENT[c])))",
|
|
|
|
"{f a b c}");
|
|
|
|
}
|