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);
}
|