gux/lang/tests/parser.c

225 lines
6.0 KiB
C

#include "commons.h"
#include <criterion/criterion.h>
#include <parser.h>
#include <node.h>
static void test_parser(char const* oracle, char const* source)
{
struct parser parser;
parser_init(&parser);
struct node* ast = parser_try_new_root(&parser, source);
cr_assert_neq(NULL, ast, "%s", parser.error_msg);
{
char buf[GUX_STR_SIZE];
node_str(ast, buf, GUX_STR_SIZE);
cr_assert_str_eq(oracle, buf);
}
parser_free(&parser);
}
static void test_parser_fail(char const* source)
{
struct parser parser;
parser_init(&parser);
struct node* ast = parser_try_new_root(&parser, source);
if (ast)
{
char msg[GUX_STR_SIZE];
node_str(ast, msg, GUX_STR_SIZE);
cr_assert_eq(NULL, ast, "ast = %s", msg);
}
cr_assert_eq(NULL, ast);
}
Test(parser, boolean) {
test_parser_fail("true");
test_parser_fail(";");
test_parser("ROOT(BOOL[true])", "true;");
}
Test(parser, assert) {
test_parser("ROOT(ASSERT(BOOL[false]))",
"assert false;");
test_parser_fail("assert;");
}
Test(parser, bool_arith) {
test_parser("ROOT(NOT(NOT(BOOL[true])))",
"!!true;");
test_parser("ROOT(OR(OR(BOOL[true],BOOL[false]),BOOL[false]))",
"true || false || false;");
test_parser("ROOT(OR(AND(BOOL[true],BOOL[false]),BOOL[true]))",
"true && false || true;");
test_parser("ROOT(AND(BOOL[true],OR(BOOL[false],BOOL[true])))",
"true && (false || true);");
test_parser("ROOT(OR(AND(BOOL[true],NOT(BOOL[false])),BOOL[true]))",
"true && !false || true;");
}
Test(parser, eqne) {
test_parser("ROOT(EQ(BOOL[true],BOOL[false]))",
"true == false;");
test_parser("ROOT(NE(BOOL[true],BOOL[false]))",
"true != false;");
}
Test(parser, num) {
test_parser("ROOT(EQ(INT[3],INT[-7]))",
"3 == -7;");
test_parser("ROOT(NE(FLOAT[2.9],FLOAT[-3.]))",
"2.9 != -3.;");
test_parser("ROOT(NE(STRING[bim],STRING[bam]))",
"'bim' != 'bam';");
}
Test(parser, arithmetic) {
test_parser("ROOT(ADD(INT[1],MUL(INT[2],INT[3])))",
"1 + 2 * 3;");
test_parser("ROOT(MUL(ADD(INT[1],INT[2]),INT[3]))",
"(1 + 2) * 3;");
test_parser("ROOT(SUB(INT[1],DIV(INT[2],INT[3])))",
"1 - 2 / 3;");
test_parser("ROOT(DIV(SUB(INT[1],INT[2]),INT[3]))",
"(1 - 2) / 3;");
}
Test(parser, cmp) {
test_parser("ROOT(LT(ADD(INT[1],INT[1]),INT[3]))",
"1 + 1 < 3;");
test_parser("ROOT(AND(LE(INT[0],INT[2]),GE(FLOAT[5.0],FLOAT[1.0])))",
"0 <= 2 && 5.0 >= 1.0;");
}
Test(parser, vardecl) {
test_parser("ROOT(CONSTDECL[x](INT[3]))",
"x := 3;");
test_parser("ROOT(CONSTDECL[x](TYPE[string],STRING[bim]))",
"x : string = 'bim';");
test_parser("ROOT(VARDECL[x](INT[3]))",
"var x := 3;");
test_parser("ROOT(VARDECL[x](TYPE[string],STRING[bim]))",
"var x : string = 'bim';");
}
Test(parser, assign) {
test_parser("ROOT(ASSIGN(IDENT[x],INT[45]))",
"x = 45;");
}
Test(parser, block) {
test_parser("ROOT(BLOCK(ASSIGN(IDENT[x],INT[2]),ADD(INT[1],INT[1])))",
"{ x = 2; 1 + 1;}");
}
Test(parser, if_block) {
test_parser("ROOT(IF(IDENT[a],BLOCK(INT[0])))",
"if a { 0; }");
test_parser("ROOT(IF(IDENT[a],BLOCK(INT[0]),BLOCK(INT[1])))",
"if a { 0; } else { 1; }");
test_parser("ROOT(IF(IDENT[a],BLOCK("
"INT[0]"
"),IF(IDENT[b],BLOCK("
"INT[1]"
"),BLOCK("
"INT[2]"
"))))",
"if a { 0; } else if b { 1; } else { 2; }");
}
Test(parser, while_block) {
test_parser("ROOT(WHILE(BOOL[true],BLOCK(INT[0])))",
"while true { 0; }");
}
Test(parser, while_break_continue) {
test_parser("ROOT(WHILE(BOOL[true],BLOCK(BREAK,CONTINUE)))",
"while true { break; continue; }");
}
Test(parser, fun) {
test_parser("ROOT(FUN(PARAMS(IDENT[x],TYPE[int],IDENT[y],TYPE[float]),"
"TYPE[int],BLOCK(RETURN(IDENT[x]))))",
"fun (x: int, y: float) -> int { return x; };");
test_parser("ROOT(FUN(PARAMS(IDENT[x],TYPE[int],IDENT[y],TYPE[float]),"
"TYPE[void],BLOCK(RETURN(INT[8]))))",
"fun (x: int, y: float) { return 8; };");
}
Test(parser, types) {
test_parser("ROOT(CONSTDECL[x]("
"TYPE[fun](TYPE[int],TYPE[int],RARROW,TYPE[float]),INT[0]))",
"x : (int int -> float) = 0;");
test_parser("ROOT(CONSTDECL[x](TYPE[rawptr](TYPE[float]),INT[0]))",
"x : ^float = 0;");
}
Test(parser, fun_call) {
test_parser("ROOT(CALL(IDENT[k],ARGS))",
"k();");
test_parser("ROOT(CALL(IDENT[f],ARGS(IDENT[x],IDENT[y])))",
"f(x, y);");
test_parser("ROOT(CALL(IDENT[f],ARGS(IDENT[x],IDENT[y]),ARGS(IDENT[z])))",
"f(x, y)(z);");
test_parser("ROOT(CALL(INT[72],ARGS(IDENT[a])))",
"72(a);");
}
Test(parser, fun_decl) {
test_parser("ROOT(CONSTDECL[hello](FUN(PARAMS(IDENT[n],TYPE[int]),"
"TYPE[int],BLOCK(RETURN(IDENT[n])))))",
"fun hello (n: int) -> int { return n; }");
test_parser("ROOT(CONSTDECL[hello](FUN(PARAMS(VAR,IDENT[n],TYPE[int]),"
"TYPE[int],BLOCK(RETURN(IDENT[n])))))",
"fun hello (var n: int) -> int { return n; }");
test_parser("ROOT(CONSTDECL[hello](FUN(PARAMS(IDENT[m],TYPE[float],"
"VAR,IDENT[n],TYPE[int]),"
"TYPE[int],BLOCK(RETURN(IDENT[n])))))",
"fun hello (m: float, var n: int) -> int { return n; }");
}
Test(parser, param_sugar) {
test_parser("ROOT(CONSTDECL[hello](FUN(PARAMS(IDENT[n],TYPE[int],"
"IDENT[m],TYPE[int],IDENT[k],TYPE[int]),"
"TYPE[int],BLOCK(RETURN(IDENT[n])))))",
"fun hello (n, m, k: int) -> int { return n; }");
}
Test(parser, mem) {
test_parser("ROOT(CONSTDECL[x](NEW(INT[32])))",
"x := new 32;");
test_parser("ROOT(FREE(IDENT[hello]))",
"free hello;");
}