aboutsummaryrefslogtreecommitdiff
path: root/tests/parser_test.c
blob: 85626a0509c73b1ea397db0239752d0f1c1ec30e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <string.h>
#include <stdbool.h>

#include "parser/parser.h"
#include "tests.h"

static bool text_is(struct Token token, const char* text)
{
	size_t length = strlen(text);
	return token.length == length && memcmp(token.start, text, length) == 0;
}

static void test_parse_consts(struct TestContext* context)
{
	struct Lexer lexer = create_lexer("const A = 1\nconst B = 60\n");
	struct Program program;

	check(context, parse_program(&lexer, &program));
	check(context, program.const_count == 2);
	check(context, text_is(program.consts[0].name, "A"));
	check(context, text_is(program.consts[0].value, "1"));
	check(context, text_is(program.consts[1].name, "B"));
	check(context, text_is(program.consts[1].value, "60"));

	free_program(&program);
}

static void test_parse_data(struct TestContext* context)
{
	struct Lexer lexer = create_lexer("data msg = \"hi\"\n");
	struct Program program;

	check(context, parse_program(&lexer, &program));
	check(context, program.data_count == 1);
	check(context, text_is(program.data_decls[0].name, "msg"));
	check(context, text_is(program.data_decls[0].value, "\"hi\""));

	free_program(&program);
}

static void test_parse_proc_params(struct TestContext* context)
{
	struct Lexer lexer = create_lexer("proc f(a: rdi, b: rsi)\n{\n}\n");
	struct Program program;

	check(context, parse_program(&lexer, &program));
	check(context, program.proc_count == 1);
	check(context, text_is(program.procs[0].name, "f"));
	check(context, program.procs[0].param_count == 2);
	check(context, text_is(program.procs[0].params[0].name, "a"));
	check(context, text_is(program.procs[0].params[0].reg, "rdi"));
	check(context, text_is(program.procs[0].params[1].name, "b"));
	check(context, text_is(program.procs[0].params[1].reg, "rsi"));

	free_program(&program);
}

static void test_parse_proc_body(struct TestContext* context)
{
	struct Lexer lexer = create_lexer("proc main\n{\nrax = 1\nrcx -= 1\n^rsi = rdx\n}\n");
	struct Program program;

	check(context, parse_program(&lexer, &program));
	check(context, program.proc_count == 1);
	check(context, program.procs[0].body_count == 3);

	struct Statement first = program.procs[0].body[0];
	check(context, first.kind == STATEMENT_ASSIGN);
	check(context, !first.assign.target_deref);
	check(context, text_is(first.assign.target, "rax"));
	check(context, text_is(first.assign.op, "="));
	check(context, text_is(first.assign.value, "1"));

	struct Statement second = program.procs[0].body[1];
	check(context, text_is(second.assign.target, "rcx"));
	check(context, text_is(second.assign.op, "-="));

	struct Statement third = program.procs[0].body[2];
	check(context, third.assign.target_deref);
	check(context, text_is(third.assign.target, "rsi"));
	check(context, text_is(third.assign.value, "rdx"));

	free_program(&program);
}

static void test_parse_errors(struct TestContext* context)
{
	struct Program program;

	struct Lexer missing_name = create_lexer("const = 1\n");
	check(context, !parse_program(&missing_name, &program));
	free_program(&program);

	struct Lexer wrong_value = create_lexer("data x = 5\n");
	check(context, !parse_program(&wrong_value, &program));
	free_program(&program);

	struct Lexer unterminated = create_lexer("proc main\n{\nrax = 1\n");
	check(context, !parse_program(&unterminated, &program));
	free_program(&program);
}

void run_parser_tests(struct TestContext* context)
{
	test_parse_consts(context);
	test_parse_data(context);
	test_parse_proc_params(context);
	test_parse_proc_body(context);
	test_parse_errors(context);
}