diff options
-rw-r--r-- | bench/fib.bad | 12 | ||||
-rw-r--r-- | bench/fib.py | 5 | ||||
-rw-r--r-- | bench/life.bad | 71 | ||||
-rw-r--r-- | bench/rule110.bad | 39 | ||||
-rw-r--r-- | bench/rule110.py | 29 | ||||
-rw-r--r-- | src/badlib.h | 6 | ||||
-rw-r--r-- | src/compiler.c | 1462 | ||||
-rw-r--r-- | src/lexer.c | 148 | ||||
-rw-r--r-- | src/main.c | 98 | ||||
-rw-r--r-- | src/parser.c | 395 | ||||
-rw-r--r-- | src/semantic.c | 509 | ||||
-rw-r--r-- | src/vm.c | 262 | ||||
-rw-r--r-- | tests/compilation.bad | 57 | ||||
-rw-r--r-- | tests/conditionals.bad | 4 | ||||
-rw-r--r-- | tests/semantics.bad | 7 |
15 files changed, 2434 insertions, 670 deletions
diff --git a/bench/fib.bad b/bench/fib.bad new file mode 100644 index 0000000..ae7c729 --- /dev/null +++ b/bench/fib.bad | |||
@@ -0,0 +1,12 @@ | |||
1 | let n = 1000 | ||
2 | let a = 0.0 | ||
3 | let b = 1.0 | ||
4 | let i = 0 | ||
5 | while i < n { | ||
6 | let tmp = a + b | ||
7 | set a = b | ||
8 | set b = tmp | ||
9 | set i = i + 1 | ||
10 | } | ||
11 | |||
12 | a | ||
diff --git a/bench/fib.py b/bench/fib.py new file mode 100644 index 0000000..ceb7406 --- /dev/null +++ b/bench/fib.py | |||
@@ -0,0 +1,5 @@ | |||
1 | n = 1000 | ||
2 | a, b = 0.0, 1.0 | ||
3 | for i in range(0, n): | ||
4 | a, b = b, a + b | ||
5 | print(a) | ||
diff --git a/bench/life.bad b/bench/life.bad new file mode 100644 index 0000000..4dcabff --- /dev/null +++ b/bench/life.bad | |||
@@ -0,0 +1,71 @@ | |||
1 | ; This board is 8 * 8 = 64 cells. | ||
2 | ; let n_cells = 64 | ||
3 | ; let board_a: int[64] | ||
4 | ; let board_b: int[64] | ||
5 | ; let stride = 8 | ||
6 | |||
7 | ; This board is 32 * 32 = 1024 cells. | ||
8 | let n_cells = 1024 | ||
9 | let board_a: int[1024] | ||
10 | let board_b: int[1024] | ||
11 | let stride = 32 | ||
12 | |||
13 | ; Storing pointers to the front/backbuffer to avoid copying the board over. | ||
14 | let front = board_a | ||
15 | let back = board_b | ||
16 | |||
17 | ; Initialize glider | ||
18 | set front[stride * 2 + 5] = 1 | ||
19 | set front[stride * 3 + 6] = 1 | ||
20 | set front[stride * 4 + 4] = 1 | ||
21 | set front[stride * 4 + 5] = 1 | ||
22 | set front[stride * 4 + 6] = 1 | ||
23 | |||
24 | fun print_board(board: @int): nil { | ||
25 | for let i = 0 , i < n_cells , set i += 1 { | ||
26 | if i % stride == 0 { | ||
27 | println("") | ||
28 | } | ||
29 | if board[i] == 1 print("■ ") | ||
30 | else print("· ") | ||
31 | } | ||
32 | println("") | ||
33 | } | ||
34 | |||
35 | fun update_board(): nil { | ||
36 | for let i = 0 , i < n_cells , set i += 1 { | ||
37 | let left = if i > 0 front[i - 1] else 0 | ||
38 | let right = if i < n_cells - 1 front[i + 1] else 0 | ||
39 | let top = if i >= stride front[i - stride] else 0 | ||
40 | let topleft = if i >= stride front[i - stride - 1] else 0 | ||
41 | let topright = if i >= stride front[i - stride + 1] else 0 | ||
42 | let bot = if i <= n_cells - stride front[i + stride] else 0 | ||
43 | let botleft = if i <= n_cells - stride front[i + stride - 1] else 0 | ||
44 | let botright = if i <= n_cells - stride front[i + stride + 1] else 0 | ||
45 | |||
46 | let neig = left | ||
47 | + right | ||
48 | + top | ||
49 | + bot | ||
50 | + topleft | ||
51 | + topright | ||
52 | + botleft | ||
53 | + botright | ||
54 | |||
55 | cond { | ||
56 | front[i] == 0 && neig == 3 = set back[i] = 1 | ||
57 | front[i] == 1 && (neig == 2 || neig == 3) = set back[i] = 1 | ||
58 | else = set back[i] = 0 | ||
59 | } | ||
60 | } | ||
61 | |||
62 | ; Swap boards. | ||
63 | let tmp = front | ||
64 | set front = back | ||
65 | set back = tmp | ||
66 | } | ||
67 | |||
68 | for let n_iter = 100 , n_iter > 0 , set n_iter -= 1 { | ||
69 | print_board(front) | ||
70 | update_board() | ||
71 | } | ||
diff --git a/bench/rule110.bad b/bench/rule110.bad new file mode 100644 index 0000000..b4a2a71 --- /dev/null +++ b/bench/rule110.bad | |||
@@ -0,0 +1,39 @@ | |||
1 | ; Parameters. | ||
2 | let line = 0b00000000000000000000000000000001 | ||
3 | let max_iter = 30 | ||
4 | |||
5 | ; Print current line. | ||
6 | fun print_line(line: int): nil { | ||
7 | for let i = 0 , i < 64 , set i += 1 { | ||
8 | let val = line >> 63 - i & 0b1 | ||
9 | if val == 0b1 { | ||
10 | print("■ ") | ||
11 | } else { | ||
12 | print("· ") | ||
13 | } | ||
14 | } | ||
15 | println("") | ||
16 | } | ||
17 | |||
18 | ; Get the next line. | ||
19 | fun next_line(line: int): int { | ||
20 | let next = 0 | ||
21 | for let j = 0 , j < 61 , set j += 1 { | ||
22 | let val = line >> 60 - j & 0b111 | ||
23 | set val = cond { | ||
24 | val == 1 = 1 | ||
25 | val == 2 = 1 | ||
26 | val == 3 = 1 | ||
27 | val == 5 = 1 | ||
28 | val == 6 = 1 | ||
29 | else = 0 | ||
30 | } | ||
31 | set next |= val << 61 - j | ||
32 | } | ||
33 | next | 1 | ||
34 | } | ||
35 | |||
36 | for let iter = 0 , iter < max_iter , set iter += 1 { | ||
37 | print_line(line) | ||
38 | set line = next_line(line) | ||
39 | } | ||
diff --git a/bench/rule110.py b/bench/rule110.py new file mode 100644 index 0000000..eddcdbe --- /dev/null +++ b/bench/rule110.py | |||
@@ -0,0 +1,29 @@ | |||
1 | line = 0b00000000000000000000000000000001 | ||
2 | max_iter = 30 | ||
3 | |||
4 | for iter in range(0, max_iter): | ||
5 | for i in range(0, 64): | ||
6 | val = line >> 63 - i & 0b1 | ||
7 | if val == 0b1: | ||
8 | print("■", end=" ") | ||
9 | else: | ||
10 | print("·", end=" ") | ||
11 | print("") | ||
12 | |||
13 | next = 0 | ||
14 | for j in range(0, 61): | ||
15 | val = line >> 60 - j & 0b111 | ||
16 | if val == 1: | ||
17 | val = 1 | ||
18 | elif val == 2: | ||
19 | val = 1 | ||
20 | elif val == 3: | ||
21 | val = 1 | ||
22 | elif val == 5: | ||
23 | val = 1 | ||
24 | elif val == 6: | ||
25 | val = 1 | ||
26 | else: | ||
27 | val = 0 | ||
28 | next = next | val << 61 - j | ||
29 | line = next | 1 | ||
diff --git a/src/badlib.h b/src/badlib.h index 73e03db..c73b57f 100644 --- a/src/badlib.h +++ b/src/badlib.h | |||
@@ -347,7 +347,9 @@ str_split_fn(Str *a, StrSplitFn split_fn) { | |||
347 | void | 347 | void |
348 | str_replace(Str *a, Str from, Str to) { | 348 | str_replace(Str *a, Str from, Str to) { |
349 | assert(a != NULL); | 349 | assert(a != NULL); |
350 | assert(from.size == to.size); | 350 | if (from.size != to.size) { |
351 | return; | ||
352 | } | ||
351 | SearchResult res = array_find_next(*a, from); | 353 | SearchResult res = array_find_next(*a, from); |
352 | if (res.found) { | 354 | if (res.found) { |
353 | memcpy(a->mem + res.pos, to.mem, res.matched); | 355 | memcpy(a->mem + res.pos, to.mem, res.matched); |
@@ -1498,7 +1500,7 @@ void | |||
1498 | log_func_memory(Logger *l, void *in) { | 1500 | log_func_memory(Logger *l, void *in) { |
1499 | assert(l); | 1501 | assert(l); |
1500 | Array *val = in; | 1502 | Array *val = in; |
1501 | for (sz i = 0; i < MIN(64, val->size); i++) { | 1503 | for (sz i = 0; i < MIN(256, val->size); i++) { |
1502 | Arena scratch = l->storage; | 1504 | Arena scratch = l->storage; |
1503 | log_str(l, str_from_hex(val->mem[i], 2, &scratch)); | 1505 | log_str(l, str_from_hex(val->mem[i], 2, &scratch)); |
1504 | if ((i + 1) % 16 == 0) { | 1506 | if ((i + 1) % 16 == 0) { |
diff --git a/src/compiler.c b/src/compiler.c index 0f9607e..c2b48b3 100644 --- a/src/compiler.c +++ b/src/compiler.c | |||
@@ -25,7 +25,7 @@ typedef struct Instruction { | |||
25 | typedef union Constant { | 25 | typedef union Constant { |
26 | s64 i; | 26 | s64 i; |
27 | u64 u; | 27 | u64 u; |
28 | double f; | 28 | f64 f; |
29 | ptrsize ptr; | 29 | ptrsize ptr; |
30 | } Constant; | 30 | } Constant; |
31 | 31 | ||
@@ -34,9 +34,23 @@ typedef struct LineCol { | |||
34 | sz col; | 34 | sz col; |
35 | } LineCol; | 35 | } LineCol; |
36 | 36 | ||
37 | typedef struct Function { | ||
38 | Str name; | ||
39 | sz param_arity; | ||
40 | sz return_arity; | ||
41 | sz index; | ||
42 | } Function; | ||
43 | |||
44 | MAPDEF(FunctionMap, funcmap, Str, Function, str_hash, str_eq) | ||
45 | |||
37 | typedef struct Chunk { | 46 | typedef struct Chunk { |
38 | sz id; | 47 | sz id; |
48 | Str name; | ||
49 | struct Chunk *parent; | ||
50 | |||
39 | Instruction *code; | 51 | Instruction *code; |
52 | IntIntMap *labels; // label -> chunk_index | ||
53 | sz labels_idx; | ||
40 | 54 | ||
41 | // Constant values that fit in 64 bits. | 55 | // Constant values that fit in 64 bits. |
42 | Constant *constants; | 56 | Constant *constants; |
@@ -52,45 +66,91 @@ typedef struct Chunk { | |||
52 | Variable *vars; | 66 | Variable *vars; |
53 | StrVarMap *varmap; | 67 | StrVarMap *varmap; |
54 | sz var_off; | 68 | sz var_off; |
69 | sz param_off; | ||
55 | 70 | ||
56 | // Number of registers currently used in this chunk. | 71 | // Number of registers currently used in this chunk. |
57 | sz reg_idx; | 72 | sz reg_idx; |
58 | 73 | ||
74 | // Number of functions currently used in this chunk. | ||
75 | struct Chunk **functions; | ||
76 | FunctionMap *funmap; | ||
77 | sz fun_idx; | ||
78 | |||
59 | // Debugging. | 79 | // Debugging. |
60 | Str file_name; | 80 | Str file_name; |
61 | Arena *storage; | 81 | Arena *storage; |
62 | LineCol *linecol; | 82 | LineCol *linecol; |
63 | } Chunk; | 83 | } Chunk; |
64 | 84 | ||
85 | typedef struct Compiler { | ||
86 | Chunk main_chunk; | ||
87 | Str file_name; | ||
88 | Arena *storage; | ||
89 | |||
90 | // Tables. | ||
91 | StrSet *integer_types; | ||
92 | StrSet *numeric_types; | ||
93 | |||
94 | // Destinations. | ||
95 | sz lab_pre; | ||
96 | sz lab_post; | ||
97 | } Compiler; | ||
98 | |||
65 | typedef enum OpCode { | 99 | typedef enum OpCode { |
66 | // OP DST A B | 100 | // OP DST A B |
67 | // --------------------------------------------------------------- | 101 | // --------------------------------------------------------------- |
68 | // VM/high level instructions. | 102 | // VM/high level instructions. |
69 | OP_HALT, // halt | 103 | OP_HALT, // halt |
104 | // NOTE: LDGVAR/STGVAR* could be obtained in terms of LDGADDR. | ||
70 | OP_STGVARI, // stgvari vx, ca | 105 | OP_STGVARI, // stgvari vx, ca |
71 | OP_STGVAR, // stgvar vx, ra | 106 | OP_STGVAR, // stgvar vx, ra |
72 | OP_LDGVAR, // ldgvar rx, vx | 107 | OP_LDGVAR, // ldgvar rx, va |
108 | OP_LDGADDR, // ldgaddr rx, va | ||
109 | OP_STLVARI, // stlvari vx, ca | ||
110 | OP_STLVAR, // stlvar vx, ra | ||
111 | OP_LDLVAR, // ldlvar rx, va | ||
112 | OP_LDLADDR, // ldladdr rx, va | ||
113 | OP_LDSTR, // ldstr rx, sa ; Stores the address of the string sa into rx | ||
114 | // Functions. | ||
115 | OP_CALL, // call fx ; Call the function fx | ||
116 | OP_RECUR, // recur ; Jump to the beginning of the function. | ||
117 | OP_RET, // ret ; Returns from current function | ||
118 | OP_RESERVE, // reserve cx ; Increments the stack pointer by cx bytes | ||
119 | OP_POP, // pop rx ; Pops the last value of the stack into rx. | ||
120 | OP_PUSH, // push rx ; Push the rx value to the stack. | ||
121 | OP_PUSHI, // pushi cx ; Push the cx value to the stack. | ||
122 | OP_PUTRET, // putret rx ; Put rx into the return value memory. | ||
123 | OP_PUTRETI, // putreti cx ; Put cx into the return value memory. | ||
124 | // Printing values with builtin print/println functions. | ||
125 | OP_PRINTSTR, // p rx | ||
126 | OP_PRINTSTRI, // p cx | ||
127 | OP_PRINTS64, // p rx | ||
128 | OP_PRINTS64I, // p cx | ||
129 | OP_PRINTF64, // p rx | ||
130 | OP_PRINTF64I, // p cx | ||
131 | OP_PRINTBOOL, // p rx | ||
132 | OP_PRINTBOOLI, // p cx | ||
73 | // Load/Store instructions. | 133 | // Load/Store instructions. |
74 | OP_LD8K, // ld8k rx, ca -> u8 rx = ca | 134 | OP_LD8K, // ld8k rx, ca -> u8 rx = ca |
75 | OP_LD16K, // ld16k rx, ca -> u16 rx = ca | 135 | OP_LD16K, // ld16k rx, ca -> u16 rx = ca |
76 | OP_LD32K, // ld32k rx, ca -> u32 rx = ca | 136 | OP_LD32K, // ld32k rx, ca -> u32 rx = ca |
77 | OP_LD64K, // ld64k rx, ca -> u64 rx = ca | 137 | OP_LD64K, // ld64k rx, ca -> u64 rx = ca |
78 | OP_LD8I, // ld8i rx, ra, cb -> u8 *p; rx = p[ra + cb] | 138 | OP_LD8I, // ld8i rx, ra, cb -> u8 *p = ra; rx = p[cb] |
79 | OP_LD16I, // ld16i rx, ra, cb -> u16 *p; rx = p[ra + cb] | 139 | OP_LD16I, // ld16i rx, ra, cb -> u16 *p = ra; rx = p[cb] |
80 | OP_LD32I, // ld32i rx, ra, cb -> u32 *p; rx = p[ra + cb] | 140 | OP_LD32I, // ld32i rx, ra, cb -> u32 *p = ra; rx = p[cb] |
81 | OP_LD64I, // ld64i rx, ra, cb -> u64 *p; rx = p[ra + cb] | 141 | OP_LD64I, // ld64i rx, ra, cb -> u64 *p = ra; rx = p[cb] |
82 | OP_LD8, // ld8 rx, ra, rb -> u8 *p; rx = p[ra + rb] | 142 | OP_LD8, // ld8 rx, ra, rb -> u8 *p = ra; rx = p[rb] |
83 | OP_LD16, // ld16 rx, ra, rb -> u16 *p; rx = p[ra + rb] | 143 | OP_LD16, // ld16 rx, ra, rb -> u16 *p = ra; rx = p[rb] |
84 | OP_LD32, // ld32 rx, ra, rb -> u32 *p; rx = p[ra + rb] | 144 | OP_LD32, // ld32 rx, ra, rb -> u32 *p = ra; rx = p[rb] |
85 | OP_LD64, // ld64 rx, ra, rb -> u64 *p; rx = p[ra + rb] | 145 | OP_LD64, // ld64 rx, ra, rb -> u64 *p = ra; rx = p[rb] |
86 | OP_ST8I, // st8i rx, ra, cb -> u8 *p; p[ra + cb] = rx | 146 | OP_ST8I, // st8i rx, ra, cb -> u8 *p = ra; p[cb] = rx |
87 | OP_ST16I, // st16i rx, ra, cb -> u16 *p; p[ra + cb] = rx | 147 | OP_ST16I, // st16i rx, ra, cb -> u16 *p = ra; p[cb] = rx |
88 | OP_ST32I, // st32i rx, ra, cb -> u32 *p; p[ra + cb] = rx | 148 | OP_ST32I, // st32i rx, ra, cb -> u32 *p = ra; p[cb] = rx |
89 | OP_ST64I, // st64i rx, ra, cb -> u64 *p; p[ra + cb] = rx | 149 | OP_ST64I, // st64i rx, ra, cb -> u64 *p = ra; p[cb] = rx |
90 | OP_ST8, // st8 rx, ra, rb -> u8 *p; p[ra + rb] = rx | 150 | OP_ST8, // st8 rx, ra, rb -> u8 *p = ra; p[rb] = rx |
91 | OP_ST16, // st16 rx, ra, rb -> u16 *p; p[ra + rb] = rx | 151 | OP_ST16, // st16 rx, ra, rb -> u16 *p = ra; p[rb] = rx |
92 | OP_ST32, // st32 rx, ra, rb -> u32 *p; p[ra + rb] = rx | 152 | OP_ST32, // st32 rx, ra, rb -> u32 *p = ra; p[rb] = rx |
93 | OP_ST64, // st64 rx, ra, rb -> u64 *p; p[ra + rb] = rx | 153 | OP_ST64, // st64 rx, ra, rb -> u64 *p = ra; p[rb] = rx |
94 | // Integer arithmetic (only int/s64 for now). | 154 | // Integer arithmetic (only int/s64 for now). |
95 | OP_ADDI, // addk rx, ra, cb | 155 | OP_ADDI, // addk rx, ra, cb |
96 | OP_SUBI, // subk rx, ra, cb | 156 | OP_SUBI, // subk rx, ra, cb |
@@ -142,26 +202,52 @@ typedef enum OpCode { | |||
142 | OP_BITRSHIFTI, // shri rx, ra, cb | 202 | OP_BITRSHIFTI, // shri rx, ra, cb |
143 | OP_BITANDI, // bandi rx, ra, cb | 203 | OP_BITANDI, // bandi rx, ra, cb |
144 | OP_BITORI, // bori rx, ra, cb | 204 | OP_BITORI, // bori rx, ra, cb |
205 | OP_BITXORI, // bxor rx, ra, cb | ||
145 | OP_BITNOTI, // bnoti rx, ca | 206 | OP_BITNOTI, // bnoti rx, ca |
146 | OP_BITLSHIFT, // shl rx, ra, rb | 207 | OP_BITLSHIFT, // shl rx, ra, rb |
147 | OP_BITRSHIFT, // shr rx, ra, rb | 208 | OP_BITRSHIFT, // shr rx, ra, rb |
148 | OP_BITAND, // band rx, ra, rb | 209 | OP_BITAND, // band rx, ra, rb |
149 | OP_BITOR, // bor rx, ra, rb | 210 | OP_BITOR, // bor rx, ra, rb |
211 | OP_BITXOR, // bxor rx, ra, rb | ||
150 | OP_BITNOT, // bnot rx, ra | 212 | OP_BITNOT, // bnot rx, ra |
151 | // Jump instructions. | 213 | // Jump instructions. |
152 | OP_JMPI, // jmp cx ; cx := signed offset | 214 | OP_JMP, // jmp lx ; jmp to label lx |
153 | OP_JMPFI, // jmpf cx, ca ; rx := condition, ca := offset | 215 | OP_JMPF, // jmpf lx, rx ; jmp to label lx if rx is false |
154 | OP_JMPTI, // jmpt cx, ca ; rx := condition, ca := offset | 216 | OP_JMPT, // jmpt lx, rx ; jmp to label lx if rx is true |
155 | OP_JMP, // jmp rx ; rx := signed offset | 217 | OP_JMPFI, // jmpf lx, cx ; jmp to label lx if rx is false |
156 | OP_JMPF, // jmpf rx, ca ; rx := condition, ca := offset | 218 | OP_JMPTI, // jmpt lx, cx ; jmp to label lx if rx is true |
157 | OP_JMPT, // jmpt rx, ca ; rx := condition, ca := offset | ||
158 | } OpCode; | 219 | } OpCode; |
159 | 220 | ||
160 | Str op_str[] = { | 221 | Str op_str[] = { |
222 | // High level ops. | ||
161 | [OP_HALT] = cstr("HALT "), | 223 | [OP_HALT] = cstr("HALT "), |
162 | [OP_STGVAR] = cstr("STGVAR "), | 224 | [OP_STGVAR] = cstr("STGVAR "), |
163 | [OP_STGVARI] = cstr("STGVARI "), | 225 | [OP_STGVARI] = cstr("STGVARI "), |
164 | [OP_LDGVAR] = cstr("LDGVAR "), | 226 | [OP_LDGVAR] = cstr("LDGVAR "), |
227 | [OP_LDGADDR] = cstr("LDGADDR "), | ||
228 | [OP_STLVAR] = cstr("STLVAR "), | ||
229 | [OP_STLVARI] = cstr("STLVARI "), | ||
230 | [OP_LDLVAR] = cstr("LDLVAR "), | ||
231 | [OP_LDLADDR] = cstr("LDLADDR "), | ||
232 | [OP_LDSTR] = cstr("LDSTR "), | ||
233 | [OP_PRINTSTR] = cstr("PRNSTR "), | ||
234 | [OP_PRINTSTRI] = cstr("PRNSTRI "), | ||
235 | [OP_PRINTS64] = cstr("PRNS64 "), | ||
236 | [OP_PRINTS64I] = cstr("PRNS64I "), | ||
237 | [OP_PRINTF64] = cstr("PRNF64 "), | ||
238 | [OP_PRINTF64I] = cstr("PRNF64I "), | ||
239 | [OP_PRINTBOOL] = cstr("PRNBOOL "), | ||
240 | [OP_PRINTBOOLI] = cstr("PRNBOOLI"), | ||
241 | [OP_PUTRET] = cstr("PUTRET "), | ||
242 | [OP_PUTRETI] = cstr("PUTRETI "), | ||
243 | // Functions. | ||
244 | [OP_CALL] = cstr("CALL "), | ||
245 | [OP_RECUR] = cstr("RECUR "), | ||
246 | [OP_RET] = cstr("RET "), | ||
247 | [OP_RESERVE] = cstr("RESERVE "), | ||
248 | [OP_POP] = cstr("POP "), | ||
249 | [OP_PUSH] = cstr("PUSH "), | ||
250 | [OP_PUSHI] = cstr("PUSHI "), | ||
165 | // Load ops. | 251 | // Load ops. |
166 | [OP_LD8K] = cstr("LD8K "), | 252 | [OP_LD8K] = cstr("LD8K "), |
167 | [OP_LD16K] = cstr("LD16K "), | 253 | [OP_LD16K] = cstr("LD16K "), |
@@ -234,19 +320,20 @@ Str op_str[] = { | |||
234 | [OP_BITRSHIFTI] = cstr("RSHI "), | 320 | [OP_BITRSHIFTI] = cstr("RSHI "), |
235 | [OP_BITANDI] = cstr("BANDI "), | 321 | [OP_BITANDI] = cstr("BANDI "), |
236 | [OP_BITORI] = cstr("BORI "), | 322 | [OP_BITORI] = cstr("BORI "), |
323 | [OP_BITXORI] = cstr("BXORI "), | ||
237 | [OP_BITNOTI] = cstr("BNOTI "), | 324 | [OP_BITNOTI] = cstr("BNOTI "), |
238 | [OP_BITLSHIFT] = cstr("LSH "), | 325 | [OP_BITLSHIFT] = cstr("LSH "), |
239 | [OP_BITRSHIFT] = cstr("RSH "), | 326 | [OP_BITRSHIFT] = cstr("RSH "), |
240 | [OP_BITAND] = cstr("BAND "), | 327 | [OP_BITAND] = cstr("BAND "), |
241 | [OP_BITOR] = cstr("BOR "), | 328 | [OP_BITOR] = cstr("BOR "), |
329 | [OP_BITXOR] = cstr("XBOR "), | ||
242 | [OP_BITNOT] = cstr("BNOT "), | 330 | [OP_BITNOT] = cstr("BNOT "), |
243 | // Jump instructions. | 331 | // Jump instructions. |
244 | [OP_JMPI] = cstr("JMPI "), | ||
245 | [OP_JMPFI] = cstr("JMPFI "), | ||
246 | [OP_JMPTI] = cstr("JMPTI "), | ||
247 | [OP_JMP] = cstr("JMP "), | 332 | [OP_JMP] = cstr("JMP "), |
248 | [OP_JMPF] = cstr("JMPF "), | 333 | [OP_JMPF] = cstr("JMPF "), |
249 | [OP_JMPT] = cstr("JMPT "), | 334 | [OP_JMPT] = cstr("JMPT "), |
335 | [OP_JMPFI] = cstr("JMPFI "), | ||
336 | [OP_JMPTI] = cstr("JMPTI "), | ||
250 | }; | 337 | }; |
251 | 338 | ||
252 | typedef enum { | 339 | typedef enum { |
@@ -254,6 +341,7 @@ typedef enum { | |||
254 | COMP_CONST, | 341 | COMP_CONST, |
255 | COMP_STRING, | 342 | COMP_STRING, |
256 | COMP_REG, | 343 | COMP_REG, |
344 | COMP_RET, | ||
257 | COMP_ERR, | 345 | COMP_ERR, |
258 | } CompResultType; | 346 | } CompResultType; |
259 | 347 | ||
@@ -262,23 +350,108 @@ typedef struct CompResult { | |||
262 | CompResultType type; | 350 | CompResultType type; |
263 | } CompResult; | 351 | } CompResult; |
264 | 352 | ||
265 | CompResult compile_expr(Chunk *chunk, Node *node); | 353 | CompResult compile_expr(Compiler *compiler, Chunk *chunk, Node *node); |
266 | 354 | ||
267 | #define EMIT_OP(OP, DST, A, B, NODE, CHUNK) \ | 355 | sz |
268 | do { \ | 356 | add_constant(Chunk *chunk, sz value) { |
269 | Instruction inst = (Instruction){ \ | 357 | IntIntMap *map = intintmap_lookup(&chunk->intmap, value); |
270 | .op = (OP), \ | 358 | // Make sure we don't have duplicated constants. |
271 | .dst = (DST), \ | 359 | if (!map) { |
272 | .a = (A), \ | 360 | map = intintmap_insert(&chunk->intmap, value, chunk->const_idx++, |
273 | .b = (B), \ | 361 | chunk->storage); |
274 | }; \ | 362 | Constant c = (Constant){.i = value}; |
275 | array_push((CHUNK)->code, inst, (CHUNK)->storage); \ | 363 | array_push(chunk->constants, c, chunk->storage); |
276 | LineCol linecol = (LineCol){.line = (NODE)->line, .col = (NODE)->col}; \ | 364 | } |
277 | array_push((CHUNK)->linecol, linecol, (CHUNK)->storage); \ | 365 | return map->val; |
278 | } while (0) | 366 | } |
367 | |||
368 | sz | ||
369 | add_string(Chunk *chunk, Str string) { | ||
370 | // Make sure we don't have duplicated string. | ||
371 | StrIntMap *map = strintmap_lookup(&chunk->strmap, string); | ||
372 | if (!map) { | ||
373 | map = strintmap_insert(&chunk->strmap, string, chunk->str_idx++, | ||
374 | chunk->storage); | ||
375 | array_push(chunk->strings, string, chunk->storage); | ||
376 | } | ||
377 | return map->val; | ||
378 | } | ||
379 | |||
380 | sz | ||
381 | add_variable(Chunk *chunk, Str name, Str type, sz arr_size) { | ||
382 | sz idx = array_size(chunk->vars); | ||
383 | sz size = 8; | ||
384 | // TODO: get type storage from a table to consider all the basic | ||
385 | // types as well as user defined ones. | ||
386 | if (str_eq(type, cstr("str"))) { | ||
387 | size = 16; | ||
388 | } | ||
389 | if (arr_size) { | ||
390 | // TODO: get the proper storage size for the multiplication. | ||
391 | size *= arr_size; | ||
392 | // FIXME: this should be done on the static analysis, plus, | ||
393 | // we shouldn't be checking all these types by hand, but | ||
394 | // using the symbol tables. | ||
395 | type = str_remove_prefix(type, cstr("@")); | ||
396 | type = str_concat(cstr("[]"), type, chunk->storage); | ||
397 | } | ||
398 | Variable var = (Variable){ | ||
399 | .name = name, | ||
400 | .type = type, | ||
401 | .size = size, | ||
402 | .offset = chunk->var_off, | ||
403 | .idx = idx, | ||
404 | }; | ||
405 | varmap_insert(&chunk->varmap, name, var, chunk->storage); | ||
406 | array_push(chunk->vars, var, chunk->storage); | ||
407 | chunk->var_off += size; | ||
408 | return idx; | ||
409 | } | ||
410 | |||
411 | void | ||
412 | emit_op(OpCode op, sz dst, sz a, sz b, Node *node, Chunk *chunk) { | ||
413 | Instruction inst = (Instruction){ | ||
414 | .op = op, | ||
415 | .dst = dst, | ||
416 | .a = a, | ||
417 | .b = b, | ||
418 | }; | ||
419 | array_push(chunk->code, inst, chunk->storage); | ||
420 | LineCol linecol = (LineCol){0}; | ||
421 | if (node) { | ||
422 | linecol = (LineCol){.line = node->line, .col = node->col}; | ||
423 | } | ||
424 | array_push(chunk->linecol, linecol, chunk->storage); | ||
425 | } | ||
426 | |||
427 | void | ||
428 | emit_fat_copy(Chunk *chunk, Node *node, sz dst_addr, sz src_addr) { | ||
429 | sz reg_dst = chunk->reg_idx++; | ||
430 | |||
431 | // Store the fat string pointer into the variable. | ||
432 | sz zero = add_constant(chunk, 0); | ||
433 | sz one = add_constant(chunk, 1); | ||
434 | |||
435 | // Get the value for the first word of the string | ||
436 | // pointer. | ||
437 | emit_op(OP_LD64I, reg_dst, src_addr, zero, node, chunk); | ||
438 | emit_op(OP_ST64I, reg_dst, dst_addr, zero, node, chunk); | ||
439 | emit_op(OP_LD64I, reg_dst, src_addr, one, node, chunk); | ||
440 | emit_op(OP_ST64I, reg_dst, dst_addr, one, node, chunk); | ||
441 | } | ||
442 | |||
443 | void disassemble_chunk(Chunk chunk); | ||
444 | |||
445 | void | ||
446 | emit_compile_err(Compiler *compiler, Chunk *chunk, Node *node) { | ||
447 | disassemble_chunk(*chunk); | ||
448 | eprintln("%s:%d:%d: error: compilation error on: %s", compiler->file_name, | ||
449 | node->line, node->col, node_str[node->kind]); | ||
450 | exit(EXIT_FAILURE); | ||
451 | } | ||
279 | 452 | ||
280 | CompResult | 453 | CompResult |
281 | compile_binary(Chunk *chunk, Node *node) { | 454 | compile_binary(Compiler *compiler, Chunk *chunk, Node *node) { |
282 | OpCode op = OP_HALT; | 455 | OpCode op = OP_HALT; |
283 | OpCode opi = OP_HALT; | 456 | OpCode opi = OP_HALT; |
284 | OpCode ldop = OP_LD64K; | 457 | OpCode ldop = OP_LD64K; |
@@ -367,6 +540,10 @@ compile_binary(Chunk *chunk, Node *node) { | |||
367 | op = OP_BITOR; | 540 | op = OP_BITOR; |
368 | opi = OP_BITORI; | 541 | opi = OP_BITORI; |
369 | } break; | 542 | } break; |
543 | case NODE_BITXOR: { | ||
544 | op = OP_BITXOR; | ||
545 | opi = OP_BITXORI; | ||
546 | } break; | ||
370 | case NODE_BITAND: { | 547 | case NODE_BITAND: { |
371 | op = OP_BITAND; | 548 | op = OP_BITAND; |
372 | opi = OP_BITANDI; | 549 | opi = OP_BITANDI; |
@@ -381,19 +558,20 @@ compile_binary(Chunk *chunk, Node *node) { | |||
381 | } break; | 558 | } break; |
382 | default: break; | 559 | default: break; |
383 | } | 560 | } |
384 | CompResult comp_a = compile_expr(chunk, node->left); | 561 | CompResult comp_a = compile_expr(compiler, chunk, node->binary.left); |
385 | CompResult comp_b = compile_expr(chunk, node->right); | 562 | CompResult comp_b = compile_expr(compiler, chunk, node->binary.right); |
386 | sz reg_a; | 563 | sz reg_a; |
387 | sz reg_b; | 564 | sz reg_b; |
388 | switch (comp_a.type) { | 565 | switch (comp_a.type) { |
389 | case COMP_CONST: { | 566 | case COMP_CONST: { |
390 | reg_a = chunk->reg_idx++; | 567 | reg_a = chunk->reg_idx++; |
391 | EMIT_OP(ldop, reg_a, comp_a.idx, 0, node, chunk); | 568 | emit_op(ldop, reg_a, comp_a.idx, 0, node, chunk); |
392 | } break; | 569 | } break; |
393 | case COMP_REG: { | 570 | case COMP_REG: { |
394 | reg_a = comp_a.idx; | 571 | reg_a = comp_a.idx; |
395 | } break; | 572 | } break; |
396 | default: { | 573 | default: { |
574 | emit_compile_err(compiler, chunk, node); | ||
397 | return (CompResult){.type = COMP_ERR}; | 575 | return (CompResult){.type = COMP_ERR}; |
398 | } break; | 576 | } break; |
399 | } | 577 | } |
@@ -406,16 +584,17 @@ compile_binary(Chunk *chunk, Node *node) { | |||
406 | reg_b = comp_b.idx; | 584 | reg_b = comp_b.idx; |
407 | } break; | 585 | } break; |
408 | default: { | 586 | default: { |
587 | emit_compile_err(compiler, chunk, node); | ||
409 | return (CompResult){.type = COMP_ERR}; | 588 | return (CompResult){.type = COMP_ERR}; |
410 | } break; | 589 | } break; |
411 | } | 590 | } |
412 | sz reg_dst = chunk->reg_idx++; // Better for optimization | 591 | sz reg_dst = chunk->reg_idx++; // Better for optimization |
413 | EMIT_OP(op, reg_dst, reg_a, reg_b, node, chunk); | 592 | emit_op(op, reg_dst, reg_a, reg_b, node, chunk); |
414 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | 593 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; |
415 | } | 594 | } |
416 | 595 | ||
417 | CompResult | 596 | CompResult |
418 | compile_unary(Chunk *chunk, Node *node) { | 597 | compile_unary(Compiler *compiler, Chunk *chunk, Node *node) { |
419 | OpCode op = OP_HALT; | 598 | OpCode op = OP_HALT; |
420 | OpCode opi = OP_HALT; | 599 | OpCode opi = OP_HALT; |
421 | switch (node->kind) { | 600 | switch (node->kind) { |
@@ -429,7 +608,7 @@ compile_unary(Chunk *chunk, Node *node) { | |||
429 | } break; | 608 | } break; |
430 | default: break; | 609 | default: break; |
431 | } | 610 | } |
432 | CompResult comp_a = compile_expr(chunk, node->left); | 611 | CompResult comp_a = compile_expr(compiler, chunk, node->binary.left); |
433 | sz reg_a; | 612 | sz reg_a; |
434 | switch (comp_a.type) { | 613 | switch (comp_a.type) { |
435 | case COMP_CONST: { | 614 | case COMP_CONST: { |
@@ -440,30 +619,18 @@ compile_unary(Chunk *chunk, Node *node) { | |||
440 | reg_a = comp_a.idx; | 619 | reg_a = comp_a.idx; |
441 | } break; | 620 | } break; |
442 | default: { | 621 | default: { |
622 | emit_compile_err(compiler, chunk, node); | ||
443 | return (CompResult){.type = COMP_ERR}; | 623 | return (CompResult){.type = COMP_ERR}; |
444 | } break; | 624 | } break; |
445 | } | 625 | } |
446 | sz reg_dst = chunk->reg_idx++; | 626 | sz reg_dst = chunk->reg_idx++; |
447 | EMIT_OP(op, reg_dst, reg_a, 0, node, chunk); | 627 | emit_op(op, reg_dst, reg_a, 0, node, chunk); |
448 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | 628 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; |
449 | } | 629 | } |
450 | 630 | ||
451 | sz | ||
452 | add_constant(Chunk *chunk, sz value) { | ||
453 | IntIntMap *map = intintmap_lookup(&chunk->intmap, value); | ||
454 | // Make sure we don't have duplicated constants. | ||
455 | if (!map) { | ||
456 | map = intintmap_insert(&chunk->intmap, value, chunk->const_idx++, | ||
457 | chunk->storage); | ||
458 | Constant c = (Constant){.i = value}; | ||
459 | array_push(chunk->constants, c, chunk->storage); | ||
460 | } | ||
461 | return map->val; | ||
462 | } | ||
463 | |||
464 | CompResult | 631 | CompResult |
465 | compile_if(Chunk *chunk, Node *node) { | 632 | compile_if(Compiler *compiler, Chunk *chunk, Node *node) { |
466 | CompResult cond = compile_expr(chunk, node->cond_if); | 633 | CompResult cond = compile_expr(compiler, chunk, node->ifelse.cond); |
467 | OpCode jmpop; | 634 | OpCode jmpop; |
468 | switch (cond.type) { | 635 | switch (cond.type) { |
469 | case COMP_CONST: { | 636 | case COMP_CONST: { |
@@ -473,99 +640,904 @@ compile_if(Chunk *chunk, Node *node) { | |||
473 | jmpop = OP_JMPF; | 640 | jmpop = OP_JMPF; |
474 | } break; | 641 | } break; |
475 | default: { | 642 | default: { |
643 | emit_compile_err(compiler, chunk, node); | ||
476 | return (CompResult){.type = COMP_ERR}; | 644 | return (CompResult){.type = COMP_ERR}; |
477 | } break; | 645 | } break; |
478 | } | 646 | } |
479 | sz jump_a = array_size(chunk->code); | ||
480 | sz reg_dst = 255; | ||
481 | bool has_value = !str_eq(node->type, cstr("nil")); | ||
482 | if (has_value) { | ||
483 | reg_dst = chunk->reg_idx++; | ||
484 | } | ||
485 | 647 | ||
486 | // Jump to the `false` branch. | 648 | if (!str_eq(node->type, cstr("nil")) && |
487 | EMIT_OP(jmpop, cond.idx, 0xff, 0, node->cond_if, chunk); | 649 | !str_has_prefix(node->type, cstr("ret:")) && |
650 | !str_has_prefix(node->type, cstr("flow:"))) { | ||
651 | sz reg_dst = chunk->reg_idx++; | ||
488 | 652 | ||
489 | // Condition is true. | 653 | // Jump to the `false` branch. |
490 | CompResult then_expr = compile_expr(chunk, node->cond_expr); | 654 | sz lab0 = chunk->labels_idx++; |
491 | if (has_value) { | 655 | emit_op(jmpop, lab0, cond.idx, 0, node->ifelse.cond, chunk); |
656 | |||
657 | // Condition is true. | ||
658 | CompResult then_expr = | ||
659 | compile_expr(compiler, chunk, node->ifelse.expr_true); | ||
492 | switch (then_expr.type) { | 660 | switch (then_expr.type) { |
493 | case COMP_CONST: { | 661 | case COMP_CONST: { |
494 | EMIT_OP(OP_LD64K, reg_dst, then_expr.idx, 0, node->cond_if, | 662 | emit_op(OP_LD64K, reg_dst, then_expr.idx, 0, node->ifelse.cond, |
495 | chunk); | 663 | chunk); |
496 | } break; | 664 | } break; |
497 | case COMP_REG: { | 665 | case COMP_REG: { |
498 | EMIT_OP(OP_MOV64, reg_dst, then_expr.idx, 0, node->cond_if, | 666 | emit_op(OP_MOV64, reg_dst, then_expr.idx, 0, node->ifelse.cond, |
499 | chunk); | 667 | chunk); |
500 | } break; | 668 | } break; |
669 | case COMP_RET: break; | ||
501 | default: { | 670 | default: { |
671 | emit_compile_err(compiler, chunk, node); | ||
502 | return (CompResult){.type = COMP_ERR}; | 672 | return (CompResult){.type = COMP_ERR}; |
503 | } break; | 673 | } break; |
504 | } | 674 | } |
505 | } | ||
506 | 675 | ||
507 | if (node->cond_else) { | ||
508 | // Jump to the end of the expression. | 676 | // Jump to the end of the expression. |
509 | sz jump_b = array_size(chunk->code); | 677 | sz pos0 = array_size(chunk->code); |
510 | EMIT_OP(OP_JMPI, 0xff, 0, 0, node->cond_else, chunk); | 678 | sz lab1 = chunk->labels_idx++; |
679 | emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk); | ||
511 | 680 | ||
512 | // Else expression. | 681 | // Else expression. |
513 | CompResult else_expr = compile_expr(chunk, node->cond_else); | 682 | CompResult else_expr = |
514 | if (has_value) { | 683 | compile_expr(compiler, chunk, node->ifelse.expr_else); |
515 | switch (else_expr.type) { | 684 | switch (else_expr.type) { |
685 | case COMP_CONST: { | ||
686 | emit_op(OP_LD64K, reg_dst, else_expr.idx, 0, | ||
687 | node->ifelse.expr_else, chunk); | ||
688 | } break; | ||
689 | case COMP_REG: { | ||
690 | emit_op(OP_MOV64, reg_dst, else_expr.idx, 0, | ||
691 | node->ifelse.expr_else, chunk); | ||
692 | } break; | ||
693 | case COMP_RET: break; | ||
694 | default: { | ||
695 | emit_compile_err(compiler, chunk, node); | ||
696 | return (CompResult){.type = COMP_ERR}; | ||
697 | } break; | ||
698 | } | ||
699 | sz pos1 = array_size(chunk->code); | ||
700 | |||
701 | // Update labels. | ||
702 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage); | ||
703 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); | ||
704 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | ||
705 | } | ||
706 | |||
707 | // Jump to the `false` branch. | ||
708 | sz lab0 = chunk->labels_idx++; | ||
709 | emit_op(jmpop, lab0, cond.idx, 0, node->ifelse.cond, chunk); | ||
710 | |||
711 | // Condition is true. | ||
712 | compile_expr(compiler, chunk, node->ifelse.expr_true); | ||
713 | |||
714 | // Jump to the end of the expression. | ||
715 | sz pos0 = array_size(chunk->code); | ||
716 | sz lab1 = chunk->labels_idx++; | ||
717 | emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk); | ||
718 | |||
719 | // Else expression. | ||
720 | if (node->ifelse.expr_else) { | ||
721 | compile_expr(compiler, chunk, node->ifelse.expr_else); | ||
722 | } | ||
723 | sz pos1 = array_size(chunk->code); | ||
724 | |||
725 | // Update labels. | ||
726 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage); | ||
727 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); | ||
728 | |||
729 | return (CompResult){.type = COMP_NIL}; | ||
730 | } | ||
731 | |||
732 | CompResult | ||
733 | compile_cond(Compiler *compiler, Chunk *chunk, Node *node) { | ||
734 | if (str_eq(node->type, cstr("nil"))) { | ||
735 | sz lab1 = chunk->labels_idx++; | ||
736 | for (sz i = 0; i < array_size(node->match.cases); i++) { | ||
737 | // condition = expression | ||
738 | Node *expr = node->match.cases[i]; | ||
739 | if (expr->case_entry.cond) { | ||
740 | CompResult cond = | ||
741 | compile_expr(compiler, chunk, expr->case_entry.cond); | ||
742 | OpCode jmpop; | ||
743 | switch (cond.type) { | ||
744 | case COMP_CONST: { | ||
745 | jmpop = OP_JMPFI; | ||
746 | } break; | ||
747 | case COMP_REG: { | ||
748 | jmpop = OP_JMPF; | ||
749 | } break; | ||
750 | default: { | ||
751 | emit_compile_err(compiler, chunk, node); | ||
752 | return (CompResult){.type = COMP_ERR}; | ||
753 | } break; | ||
754 | } | ||
755 | // Jump to the `next` branch. | ||
756 | sz lab0 = chunk->labels_idx++; | ||
757 | emit_op(jmpop, lab0, cond.idx, 0, expr->case_entry.expr, chunk); | ||
758 | |||
759 | // Condition is true. | ||
760 | compile_expr(compiler, chunk, expr->case_entry.expr); | ||
761 | if (i != array_size(node->match.cases) - 1) { | ||
762 | // Jump to the end of the expression. | ||
763 | sz pos0 = array_size(chunk->code); | ||
764 | emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk); | ||
765 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, | ||
766 | chunk->storage); | ||
767 | } | ||
768 | } else { | ||
769 | compile_expr(compiler, chunk, expr->case_entry.expr); | ||
770 | break; | ||
771 | } | ||
772 | } | ||
773 | sz pos1 = array_size(chunk->code); | ||
774 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); | ||
775 | return (CompResult){.type = COMP_NIL}; | ||
776 | } | ||
777 | |||
778 | sz reg_dst = chunk->reg_idx++; | ||
779 | sz lab1 = chunk->labels_idx++; | ||
780 | for (sz i = 0; i < array_size(node->match.cases); i++) { | ||
781 | // condition = expression | ||
782 | Node *expr = node->match.cases[i]; | ||
783 | if (expr->case_entry.cond) { | ||
784 | CompResult cond = | ||
785 | compile_expr(compiler, chunk, expr->case_entry.cond); | ||
786 | OpCode jmpop; | ||
787 | switch (cond.type) { | ||
516 | case COMP_CONST: { | 788 | case COMP_CONST: { |
517 | EMIT_OP(OP_LD64K, reg_dst, else_expr.idx, 0, | 789 | jmpop = OP_JMPFI; |
518 | node->cond_else, chunk); | ||
519 | } break; | 790 | } break; |
520 | case COMP_REG: { | 791 | case COMP_REG: { |
521 | EMIT_OP(OP_MOV64, reg_dst, else_expr.idx, 0, | 792 | jmpop = OP_JMPF; |
522 | node->cond_else, chunk); | ||
523 | } break; | 793 | } break; |
524 | default: { | 794 | default: { |
795 | emit_compile_err(compiler, chunk, node); | ||
525 | return (CompResult){.type = COMP_ERR}; | 796 | return (CompResult){.type = COMP_ERR}; |
526 | } break; | 797 | } break; |
527 | } | 798 | } |
528 | } | 799 | // Jump to the `next` branch. |
529 | sz end_expr = array_size(chunk->code); | 800 | sz lab0 = chunk->labels_idx++; |
801 | emit_op(jmpop, lab0, cond.idx, 0, expr->case_entry.expr, chunk); | ||
530 | 802 | ||
531 | // Backpatch jumps. | 803 | // Condition is true. |
532 | sz const_a = add_constant(chunk, jump_b + 1 - jump_a); | 804 | CompResult then_expr = |
533 | sz const_b = add_constant(chunk, end_expr - jump_b); | 805 | compile_expr(compiler, chunk, expr->case_entry.expr); |
534 | chunk->code[jump_a].a = const_a; | 806 | switch (then_expr.type) { |
535 | chunk->code[jump_b].dst = const_b; | 807 | case COMP_CONST: { |
536 | } else { | 808 | emit_op(OP_LD64K, reg_dst, then_expr.idx, 0, |
537 | sz end_expr = array_size(chunk->code); | 809 | expr->case_entry.expr, chunk); |
538 | if (has_value) { | 810 | } break; |
539 | sz const_a = add_constant(chunk, end_expr + 1 - jump_a); | 811 | case COMP_REG: { |
540 | chunk->code[jump_a].a = const_a; | 812 | emit_op(OP_MOV64, reg_dst, then_expr.idx, 0, |
541 | sz zero = add_constant(chunk, 0); | 813 | expr->case_entry.expr, chunk); |
542 | sz end = add_constant(chunk, 2); | 814 | } break; |
543 | EMIT_OP(OP_JMPI, end, 0, 0, node, chunk); | 815 | case COMP_RET: break; |
544 | EMIT_OP(OP_LD64K, reg_dst, zero, 0, node, chunk); | 816 | default: { |
817 | emit_compile_err(compiler, chunk, node); | ||
818 | return (CompResult){.type = COMP_ERR}; | ||
819 | } break; | ||
820 | } | ||
821 | if (i != array_size(node->match.cases) - 1) { | ||
822 | // Jump to the end of the expression. | ||
823 | sz pos0 = array_size(chunk->code); | ||
824 | emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk); | ||
825 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, | ||
826 | chunk->storage); | ||
827 | } | ||
545 | } else { | 828 | } else { |
546 | sz const_a = add_constant(chunk, end_expr - jump_a); | 829 | CompResult then_expr = |
547 | chunk->code[jump_a].a = const_a; | 830 | compile_expr(compiler, chunk, expr->case_entry.expr); |
831 | switch (then_expr.type) { | ||
832 | case COMP_CONST: { | ||
833 | emit_op(OP_LD64K, reg_dst, then_expr.idx, 0, | ||
834 | expr->case_entry.expr, chunk); | ||
835 | } break; | ||
836 | case COMP_REG: { | ||
837 | emit_op(OP_MOV64, reg_dst, then_expr.idx, 0, | ||
838 | expr->case_entry.expr, chunk); | ||
839 | } break; | ||
840 | case COMP_RET: break; | ||
841 | default: { | ||
842 | emit_compile_err(compiler, chunk, node); | ||
843 | return (CompResult){.type = COMP_ERR}; | ||
844 | } break; | ||
845 | } | ||
846 | break; | ||
548 | } | 847 | } |
549 | } | 848 | } |
550 | // TODO: does it has an else or not? Moreover, should we enforce on the | 849 | sz pos1 = array_size(chunk->code); |
551 | // semantic level that if the `if` expression returns a value we must add an | 850 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); |
552 | // else? | 851 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; |
852 | } | ||
853 | |||
854 | CompResult | ||
855 | compile_break(Compiler *compiler, Chunk *chunk, Node *node) { | ||
856 | emit_op(OP_JMP, compiler->lab_post, 0, 0, node, chunk); | ||
857 | return (CompResult){.type = COMP_NIL}; | ||
858 | } | ||
859 | |||
860 | CompResult | ||
861 | compile_continue(Compiler *compiler, Chunk *chunk, Node *node) { | ||
862 | emit_op(OP_JMP, compiler->lab_pre, 0, 0, node, chunk); | ||
863 | return (CompResult){.type = COMP_NIL}; | ||
864 | } | ||
865 | |||
866 | CompResult | ||
867 | compile_while(Compiler *compiler, Chunk *chunk, Node *node) { | ||
868 | sz lab0 = chunk->labels_idx++; | ||
869 | sz lab1 = chunk->labels_idx++; | ||
870 | sz pos1 = array_size(chunk->code); | ||
871 | CompResult cond = compile_expr(compiler, chunk, node->loop.cond); | ||
872 | OpCode jmpop; | ||
873 | switch (cond.type) { | ||
874 | case COMP_CONST: { | ||
875 | jmpop = OP_JMPFI; | ||
876 | } break; | ||
877 | case COMP_REG: { | ||
878 | jmpop = OP_JMPF; | ||
879 | } break; | ||
880 | default: { | ||
881 | emit_compile_err(compiler, chunk, node); | ||
882 | return (CompResult){.type = COMP_ERR}; | ||
883 | } break; | ||
884 | } | ||
885 | |||
886 | // Jump to the `end of the loop` branch. | ||
887 | emit_op(jmpop, lab0, cond.idx, 0, node->loop.cond, chunk); | ||
888 | |||
889 | // Condition is true. | ||
890 | compiler->lab_pre = lab1; | ||
891 | compiler->lab_post = lab0; | ||
892 | compile_expr(compiler, chunk, node->loop.expr); | ||
893 | sz pos0 = array_size(chunk->code); | ||
894 | emit_op(OP_JMP, lab1, 0, 0, node, chunk); | ||
895 | |||
896 | // Update labels. | ||
897 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage); | ||
898 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); | ||
553 | 899 | ||
554 | // Return. | 900 | // Return. |
555 | if (has_value) { | 901 | return (CompResult){.type = COMP_NIL}; |
902 | } | ||
903 | |||
904 | CompResult | ||
905 | compile_tail_call(Compiler *compiler, Chunk *chunk, Node *node) { | ||
906 | // Update the local parameters. | ||
907 | for (sz i = 0; i < array_size(node->elements); i++) { | ||
908 | Node *expr = node->elements[i]; | ||
909 | CompResult result = compile_expr(compiler, chunk, expr); | ||
910 | switch (result.type) { | ||
911 | case COMP_CONST: { | ||
912 | emit_op(OP_STLVARI, i, result.idx, 0, node, chunk); | ||
913 | } break; | ||
914 | case COMP_REG: { | ||
915 | if (str_eq(expr->type, cstr("str"))) { | ||
916 | sz var_addr = chunk->reg_idx++; | ||
917 | sz str_addr = result.idx; | ||
918 | emit_op(OP_LDLADDR, var_addr, i, 0, node, chunk); | ||
919 | emit_fat_copy(chunk, node, var_addr, str_addr); | ||
920 | } else { | ||
921 | emit_op(OP_STLVAR, i, result.idx, 0, node, chunk); | ||
922 | } | ||
923 | } break; | ||
924 | case COMP_STRING: { | ||
925 | sz var_addr = chunk->reg_idx++; | ||
926 | sz str_addr = chunk->reg_idx++; | ||
927 | emit_op(OP_LDLADDR, var_addr, i, 0, node, chunk); | ||
928 | emit_op(OP_LDSTR, str_addr, result.idx, 0, node, chunk); | ||
929 | emit_fat_copy(chunk, node, var_addr, str_addr); | ||
930 | } break; | ||
931 | default: { | ||
932 | emit_compile_err(compiler, chunk, node); | ||
933 | return (CompResult){.type = COMP_ERR}; | ||
934 | } break; | ||
935 | } | ||
936 | } | ||
937 | |||
938 | emit_op(OP_RECUR, 0, 0, 0, node, chunk); | ||
939 | return (CompResult){.type = COMP_NIL}; | ||
940 | } | ||
941 | |||
942 | CompResult | ||
943 | compile_funcall(Compiler *compiler, Chunk *chunk, Node *node) { | ||
944 | Str name = node->value.str; | ||
945 | |||
946 | // Builtins. | ||
947 | if (str_eq(name, cstr("print")) || str_eq(name, cstr("println"))) { | ||
948 | for (sz i = 0; i < array_size(node->elements); i++) { | ||
949 | Node *expr = node->elements[i]; | ||
950 | CompResult result = compile_expr(compiler, chunk, expr); | ||
951 | if (str_eq(expr->type, cstr("int"))) { | ||
952 | switch (result.type) { | ||
953 | case COMP_CONST: { | ||
954 | emit_op(OP_PRINTS64I, result.idx, 0, 0, expr, chunk); | ||
955 | } break; | ||
956 | case COMP_REG: { | ||
957 | emit_op(OP_PRINTS64, result.idx, 0, 0, expr, chunk); | ||
958 | } break; | ||
959 | default: { | ||
960 | emit_compile_err(compiler, chunk, node); | ||
961 | return (CompResult){.type = COMP_ERR}; | ||
962 | } break; | ||
963 | } | ||
964 | } else if (str_eq(expr->type, cstr("f64"))) { | ||
965 | switch (result.type) { | ||
966 | case COMP_CONST: { | ||
967 | emit_op(OP_PRINTF64I, result.idx, 0, 0, expr, chunk); | ||
968 | } break; | ||
969 | case COMP_REG: { | ||
970 | emit_op(OP_PRINTF64, result.idx, 0, 0, expr, chunk); | ||
971 | } break; | ||
972 | default: { | ||
973 | emit_compile_err(compiler, chunk, node); | ||
974 | return (CompResult){.type = COMP_ERR}; | ||
975 | } break; | ||
976 | } | ||
977 | } else if (str_eq(expr->type, cstr("str"))) { | ||
978 | switch (result.type) { | ||
979 | case COMP_STRING: { | ||
980 | emit_op(OP_PRINTSTRI, result.idx, 0, 0, expr, chunk); | ||
981 | } break; | ||
982 | case COMP_REG: { | ||
983 | emit_op(OP_PRINTSTR, result.idx, 0, 0, expr, chunk); | ||
984 | } break; | ||
985 | default: { | ||
986 | emit_compile_err(compiler, chunk, node); | ||
987 | return (CompResult){.type = COMP_ERR}; | ||
988 | } break; | ||
989 | } | ||
990 | } else if (str_eq(expr->type, cstr("bool"))) { | ||
991 | switch (result.type) { | ||
992 | case COMP_CONST: { | ||
993 | emit_op(OP_PRINTBOOLI, result.idx, 0, 0, expr, chunk); | ||
994 | } break; | ||
995 | case COMP_REG: { | ||
996 | emit_op(OP_PRINTBOOL, result.idx, 0, 0, expr, chunk); | ||
997 | } break; | ||
998 | default: { | ||
999 | emit_compile_err(compiler, chunk, node); | ||
1000 | return (CompResult){.type = COMP_ERR}; | ||
1001 | } break; | ||
1002 | } | ||
1003 | } | ||
1004 | } | ||
1005 | if (str_eq(name, cstr("println"))) { | ||
1006 | sz idx = add_string(chunk, cstr("\n")); | ||
1007 | emit_op(OP_PRINTSTRI, idx, 0, 0, node, chunk); | ||
1008 | } | ||
1009 | return (CompResult){.type = COMP_NIL}; | ||
1010 | } | ||
1011 | |||
1012 | FunctionMap *map = | ||
1013 | funcmap_lookup(&compiler->main_chunk.funmap, node->unique_name); | ||
1014 | if (!map) { | ||
1015 | emit_compile_err(compiler, chunk, node); | ||
1016 | return (CompResult){.type = COMP_ERR}; | ||
1017 | } | ||
1018 | Function fun = map->val; | ||
1019 | |||
1020 | // Check for tail recursive opportunities. | ||
1021 | if (str_eq(fun.name, node->unique_name) && | ||
1022 | str_eq(chunk->name, node->unique_name)) { | ||
1023 | Node *parent = node->parent; | ||
1024 | Node *current = node; | ||
1025 | bool tail_recursive = true; | ||
1026 | while (parent != NULL) { | ||
1027 | switch (parent->kind) { | ||
1028 | case NODE_BLOCK: { | ||
1029 | sz idx = array_size(parent->statements) - 1; | ||
1030 | if (parent->statements[idx] != node) { | ||
1031 | tail_recursive = false; | ||
1032 | break; | ||
1033 | } | ||
1034 | } break; | ||
1035 | case NODE_WHILE: { | ||
1036 | if (current == parent->loop.cond) { | ||
1037 | tail_recursive = false; | ||
1038 | break; | ||
1039 | } | ||
1040 | } break; | ||
1041 | case NODE_IF: { | ||
1042 | if (current == parent->ifelse.cond) { | ||
1043 | tail_recursive = false; | ||
1044 | break; | ||
1045 | } | ||
1046 | } break; | ||
1047 | case NODE_FUN: { | ||
1048 | sz idx = array_size(parent->func.body->statements) - 1; | ||
1049 | if (parent->func.body->statements[idx] != current) { | ||
1050 | tail_recursive = false; | ||
1051 | break; | ||
1052 | } | ||
1053 | break; | ||
1054 | } break; | ||
1055 | case NODE_MATCH: { | ||
1056 | if (current == parent->match.expr) { | ||
1057 | tail_recursive = false; | ||
1058 | break; | ||
1059 | } | ||
1060 | } break; | ||
1061 | case NODE_COND: break; | ||
1062 | case NODE_CASE_COND: { | ||
1063 | if (current == parent->case_entry.cond) { | ||
1064 | tail_recursive = false; | ||
1065 | break; | ||
1066 | } | ||
1067 | } break; | ||
1068 | default: { | ||
1069 | tail_recursive = false; | ||
1070 | break; | ||
1071 | } break; | ||
1072 | } | ||
1073 | parent = parent->parent; | ||
1074 | current = current->parent; | ||
1075 | } | ||
1076 | if (tail_recursive) { | ||
1077 | return compile_tail_call(compiler, chunk, node); | ||
1078 | } | ||
1079 | } | ||
1080 | |||
1081 | // Reserve space for the return value if needed. | ||
1082 | if (fun.return_arity > 0) { | ||
1083 | // Put the return data into a register | ||
1084 | sz ret_size = add_constant(chunk, 8); | ||
1085 | emit_op(OP_RESERVE, ret_size, 0, 0, node, chunk); | ||
1086 | } | ||
1087 | |||
1088 | // Send parameters to the stack. | ||
1089 | for (sz i = 0; i < array_size(node->elements); i++) { | ||
1090 | Node *expr = node->elements[i]; | ||
1091 | CompResult result = compile_expr(compiler, chunk, expr); | ||
1092 | switch (result.type) { | ||
1093 | case COMP_CONST: { | ||
1094 | emit_op(OP_PUSHI, result.idx, 0, 0, expr, chunk); | ||
1095 | } break; | ||
1096 | case COMP_REG: { | ||
1097 | if (str_eq(expr->type, cstr("str"))) { | ||
1098 | sz str_addr = result.idx; | ||
1099 | // Store the fat string pointer into the stack. | ||
1100 | sz reg_dst = chunk->reg_idx++; | ||
1101 | sz zero = add_constant(chunk, 0); | ||
1102 | sz one = add_constant(chunk, 1); | ||
1103 | emit_op(OP_LD64I, reg_dst, str_addr, zero, node, chunk); | ||
1104 | emit_op(OP_PUSH, reg_dst, 0, 0, expr, chunk); | ||
1105 | emit_op(OP_LD64I, reg_dst, str_addr, one, node, chunk); | ||
1106 | emit_op(OP_PUSH, reg_dst, 0, 0, expr, chunk); | ||
1107 | } else { | ||
1108 | emit_op(OP_PUSH, result.idx, 0, 0, expr, chunk); | ||
1109 | } | ||
1110 | } break; | ||
1111 | case COMP_STRING: { | ||
1112 | // Get the address for the string value variable. | ||
1113 | sz str_addr = chunk->reg_idx++; | ||
1114 | emit_op(OP_LDSTR, str_addr, result.idx, 0, node->var.val, | ||
1115 | chunk); | ||
1116 | |||
1117 | // Store the fat string pointer into the stack. | ||
1118 | sz reg_dst = chunk->reg_idx++; | ||
1119 | sz zero = add_constant(chunk, 0); | ||
1120 | sz one = add_constant(chunk, 1); | ||
1121 | emit_op(OP_LD64I, reg_dst, str_addr, zero, node, chunk); | ||
1122 | emit_op(OP_PUSH, reg_dst, 0, 0, expr, chunk); | ||
1123 | emit_op(OP_LD64I, reg_dst, str_addr, one, node, chunk); | ||
1124 | emit_op(OP_PUSH, reg_dst, 0, 0, expr, chunk); | ||
1125 | } break; | ||
1126 | default: { | ||
1127 | emit_compile_err(compiler, chunk, node); | ||
1128 | return (CompResult){.type = COMP_ERR}; | ||
1129 | } break; | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | emit_op(OP_CALL, fun.index, 0, 0, node, chunk); | ||
1134 | |||
1135 | // Only one return parameter for now. | ||
1136 | if (fun.return_arity > 0) { | ||
1137 | // Put the return data into a register | ||
1138 | sz reg_dst = chunk->reg_idx++; | ||
1139 | emit_op(OP_POP, reg_dst, 0, 0, node, chunk); | ||
556 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | 1140 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; |
557 | } | 1141 | } |
1142 | |||
1143 | return (CompResult){.type = COMP_NIL}; | ||
1144 | } | ||
1145 | |||
1146 | CompResult | ||
1147 | compile_return(Compiler *compiler, Chunk *chunk, Node *node) { | ||
1148 | for (sz i = 0; i < array_size(node->elements); i++) { | ||
1149 | Node *expr = node->elements[i]; | ||
1150 | CompResult res = compile_expr(compiler, chunk, expr); | ||
1151 | |||
1152 | // TODO: Only one return field for now, but this is the idea. | ||
1153 | // Put return values into memory. | ||
1154 | switch (res.type) { | ||
1155 | case COMP_CONST: { | ||
1156 | emit_op(OP_PUTRETI, res.idx, 0, 0, node, chunk); | ||
1157 | } break; | ||
1158 | case COMP_REG: { | ||
1159 | emit_op(OP_PUTRET, res.idx, 0, 0, node, chunk); | ||
1160 | } break; | ||
1161 | case COMP_NIL: break; | ||
1162 | default: { | ||
1163 | emit_compile_err(compiler, chunk, node); | ||
1164 | return (CompResult){.type = COMP_ERR}; | ||
1165 | } break; | ||
1166 | } | ||
1167 | break; | ||
1168 | } | ||
1169 | |||
1170 | emit_op(OP_RET, 0, 0, 0, node, chunk); | ||
1171 | return (CompResult){.type = COMP_RET}; | ||
1172 | } | ||
1173 | |||
1174 | Chunk * | ||
1175 | chunk_alloc(Chunk *parent) { | ||
1176 | static sz chunk_idx = 1; | ||
1177 | Chunk *chunk = arena_calloc((sz)sizeof(Chunk), parent->storage); | ||
1178 | chunk->parent = parent; | ||
1179 | chunk->id = chunk_idx++; | ||
1180 | chunk->storage = parent->storage; | ||
1181 | chunk->file_name = parent->file_name; | ||
1182 | return chunk; | ||
1183 | } | ||
1184 | |||
1185 | void | ||
1186 | verify_chunk(Chunk *chunk) { | ||
1187 | if (chunk->const_idx >= 256) { | ||
1188 | eprintln("too many constants on chunk %s", chunk->id); | ||
1189 | exit(EXIT_FAILURE); | ||
1190 | } | ||
1191 | if (chunk->str_idx >= 256) { | ||
1192 | eprintln("too many strings on chunk %s", chunk->id); | ||
1193 | exit(EXIT_FAILURE); | ||
1194 | } | ||
1195 | if (chunk->reg_idx >= 256) { | ||
1196 | eprintln("too many registers used on chunk %s", chunk->id); | ||
1197 | exit(EXIT_FAILURE); | ||
1198 | } | ||
1199 | if (chunk->labels_idx >= 256) { | ||
1200 | eprintln("too many labels used on chunk %s", chunk->id); | ||
1201 | exit(EXIT_FAILURE); | ||
1202 | } | ||
1203 | if (chunk->fun_idx >= 256) { | ||
1204 | eprintln("too many functions on chunk %s", chunk->id); | ||
1205 | exit(EXIT_FAILURE); | ||
1206 | } | ||
1207 | } | ||
1208 | |||
1209 | void | ||
1210 | declare_function(Chunk *chunk, Node *node) { | ||
1211 | Str name = node->unique_name; | ||
1212 | FunctionMap *map = funcmap_lookup(&chunk->funmap, node->unique_name); | ||
1213 | if (map) { | ||
1214 | return; | ||
1215 | } | ||
1216 | Function fun = (Function){ | ||
1217 | .name = name, | ||
1218 | .index = chunk->fun_idx++, | ||
1219 | .param_arity = array_size(node->func.params), | ||
1220 | .return_arity = array_size(node->func.ret), | ||
1221 | }; | ||
1222 | funcmap_insert(&chunk->funmap, node->unique_name, fun, chunk->storage); | ||
1223 | } | ||
1224 | |||
1225 | CompResult | ||
1226 | compile_function(Compiler *compiler, Chunk *chunk, Node *node) { | ||
1227 | // The current activation record procedure for the VM is as follows: | ||
1228 | // | ||
1229 | // [caller][callee ] | ||
1230 | // [ .... ][ RET VAL ][ PARAMS ][ LOCALS ][ REGISTERS ][ RET META ] | ||
1231 | // ^ | ||
1232 | // frame pointer | ||
1233 | // | ||
1234 | // The caller is responsible for allocating the return memory and the | ||
1235 | // parameter memory and filling the param data before OP_CALL. | ||
1236 | // | ||
1237 | chunk = &compiler->main_chunk; | ||
1238 | Chunk *func = chunk_alloc(chunk); | ||
1239 | func->name = node->unique_name; | ||
1240 | declare_function(chunk, node); | ||
1241 | array_push(chunk->functions, func, chunk->storage); | ||
1242 | |||
1243 | // Push arguments as locals. | ||
1244 | for (sz i = 0; i < array_size(node->func.params); i++) { | ||
1245 | Node *param = node->func.params[i]; | ||
1246 | Str name = param->unique_name; | ||
1247 | Str type = param->type; | ||
1248 | sz arr_size = 0; | ||
1249 | if (str_has_prefix(type, cstr("@"))) { | ||
1250 | if (param->var.type && param->var.type->kind == NODE_ARR_TYPE && | ||
1251 | param->var.type->sym.arr_size->value.i > 0) { | ||
1252 | arr_size = param->var.type->sym.arr_size->value.i; | ||
1253 | } | ||
1254 | } | ||
1255 | add_variable(func, name, type, arr_size); | ||
1256 | } | ||
1257 | func->param_off = func->var_off; | ||
1258 | |||
1259 | // Compiling the body. | ||
1260 | CompResult res = compile_expr(compiler, func, node->func.body); | ||
1261 | |||
1262 | // Put return values into memory. | ||
1263 | switch (res.type) { | ||
1264 | case COMP_CONST: { | ||
1265 | emit_op(OP_PUTRETI, res.idx, 0, 0, node, func); | ||
1266 | } break; | ||
1267 | case COMP_REG: { | ||
1268 | emit_op(OP_PUTRET, res.idx, 0, 0, node, func); | ||
1269 | } break; | ||
1270 | default: break; | ||
1271 | } | ||
1272 | |||
1273 | emit_op(OP_RET, 0, 0, 0, node, func); | ||
1274 | verify_chunk(func); | ||
1275 | return (CompResult){.type = COMP_NIL}; | ||
1276 | } | ||
1277 | |||
1278 | CompResult | ||
1279 | compile_let(Compiler *compiler, Chunk *chunk, Node *node) { | ||
1280 | sz op_ldaddr = OP_LDLADDR; | ||
1281 | sz op_stvari = OP_STLVARI; | ||
1282 | sz op_stvar = OP_STLVAR; | ||
1283 | if (chunk == &compiler->main_chunk) { | ||
1284 | op_ldaddr = OP_LDGADDR; | ||
1285 | op_stvari = OP_STGVARI; | ||
1286 | op_stvar = OP_STGVAR; | ||
1287 | } | ||
1288 | Str name = node->unique_name; | ||
1289 | Str type = node->var.name->type; | ||
1290 | sz arr_size = 0; | ||
1291 | if (str_has_prefix(type, cstr("@"))) { | ||
1292 | if (node->var.type && node->var.type->kind == NODE_ARR_TYPE && | ||
1293 | node->var.type->sym.arr_size->value.i > 0) { | ||
1294 | arr_size = node->var.type->sym.arr_size->value.i; | ||
1295 | } | ||
1296 | } | ||
1297 | |||
1298 | sz idx = add_variable(chunk, name, type, arr_size); | ||
1299 | |||
1300 | // Value. | ||
1301 | if (node->var.val) { | ||
1302 | CompResult res = compile_expr(compiler, chunk, node->var.val); | ||
1303 | switch (res.type) { | ||
1304 | case COMP_CONST: { | ||
1305 | emit_op(op_stvari, idx, res.idx, 0, node->var.val, chunk); | ||
1306 | } break; | ||
1307 | case COMP_REG: { | ||
1308 | if (str_eq(node->var.val->type, cstr("str"))) { | ||
1309 | // Get the address for the local/global storage | ||
1310 | // variable. | ||
1311 | sz var_addr = chunk->reg_idx++; | ||
1312 | emit_op(op_ldaddr, var_addr, idx, 0, node, chunk); | ||
1313 | |||
1314 | // Copy the fat pointer. | ||
1315 | emit_fat_copy(chunk, node, var_addr, res.idx); | ||
1316 | } else { | ||
1317 | emit_op(op_stvar, idx, res.idx, 0, node->var.val, chunk); | ||
1318 | } | ||
1319 | } break; | ||
1320 | case COMP_STRING: { | ||
1321 | // Get the address for the string value variable. | ||
1322 | sz str_addr = chunk->reg_idx++; | ||
1323 | emit_op(OP_LDSTR, str_addr, res.idx, 0, node->var.val, chunk); | ||
1324 | |||
1325 | // Get the address for the local/global storage | ||
1326 | // variable. | ||
1327 | sz var_addr = chunk->reg_idx++; | ||
1328 | emit_op(op_ldaddr, var_addr, idx, 0, node, chunk); | ||
1329 | |||
1330 | // Copy the fat pointer. | ||
1331 | emit_fat_copy(chunk, node, var_addr, str_addr); | ||
1332 | } break; | ||
1333 | default: { | ||
1334 | emit_compile_err(compiler, chunk, node); | ||
1335 | return (CompResult){.type = COMP_ERR}; | ||
1336 | } break; | ||
1337 | } | ||
1338 | } | ||
1339 | |||
1340 | return (CompResult){.type = COMP_NIL}; | ||
1341 | } | ||
1342 | |||
1343 | CompResult | ||
1344 | compile_set(Compiler *compiler, Chunk *chunk, Node *node) { | ||
1345 | Str name = node->unique_name; | ||
1346 | StrVarMap *map = NULL; | ||
1347 | Chunk *next = chunk; | ||
1348 | while (next) { | ||
1349 | map = varmap_lookup(&next->varmap, name); | ||
1350 | if (map) { | ||
1351 | break; | ||
1352 | } | ||
1353 | next = chunk->parent; | ||
1354 | } | ||
1355 | if (!map) { | ||
1356 | emit_compile_err(compiler, chunk, node); | ||
1357 | return (CompResult){.type = COMP_ERR}; | ||
1358 | } | ||
1359 | sz op_ldaddr = OP_LDLADDR; | ||
1360 | sz op_ldvar = OP_LDLVAR; | ||
1361 | sz op_stvari = OP_STLVARI; | ||
1362 | sz op_stvar = OP_STLVAR; | ||
1363 | if (next == &compiler->main_chunk) { | ||
1364 | op_ldaddr = OP_LDGADDR; | ||
1365 | op_ldvar = OP_LDGVAR; | ||
1366 | op_stvari = OP_STGVARI; | ||
1367 | op_stvar = OP_STGVAR; | ||
1368 | } | ||
1369 | CompResult res = compile_expr(compiler, chunk, node->var.val); | ||
1370 | if (node->var.name->kind == NODE_SYMBOL_IDX) { | ||
1371 | // Value. | ||
1372 | sz reg_val; | ||
1373 | switch (res.type) { | ||
1374 | case COMP_CONST: { | ||
1375 | reg_val = chunk->reg_idx++; | ||
1376 | emit_op(OP_LD64K, reg_val, res.idx, 0, node, chunk); | ||
1377 | } break; | ||
1378 | case COMP_REG: { | ||
1379 | reg_val = res.idx; | ||
1380 | } break; | ||
1381 | default: { | ||
1382 | emit_compile_err(compiler, chunk, node); | ||
1383 | return (CompResult){.type = COMP_ERR}; | ||
1384 | } break; | ||
1385 | } | ||
1386 | |||
1387 | // Address. | ||
1388 | sz reg_addr = chunk->reg_idx++; | ||
1389 | // Is this a pointer access or an array access? | ||
1390 | if (str_has_prefix(map->val.type, cstr("[]"))) { | ||
1391 | emit_op(op_ldaddr, reg_addr, map->val.idx, 0, node->var.val, chunk); | ||
1392 | } else { | ||
1393 | emit_op(op_ldvar, reg_addr, map->val.idx, 0, node->var.val, chunk); | ||
1394 | } | ||
1395 | |||
1396 | // Index. | ||
1397 | CompResult idx = | ||
1398 | compile_expr(compiler, chunk, node->var.name->sym.arr_size); | ||
1399 | switch (idx.type) { | ||
1400 | case COMP_CONST: { | ||
1401 | emit_op(OP_ST64I, reg_val, reg_addr, idx.idx, node, chunk); | ||
1402 | } break; | ||
1403 | case COMP_REG: { | ||
1404 | emit_op(OP_ST64, reg_val, reg_addr, idx.idx, node, chunk); | ||
1405 | } break; | ||
1406 | default: { | ||
1407 | emit_compile_err(compiler, chunk, node); | ||
1408 | return (CompResult){.type = COMP_ERR}; | ||
1409 | } break; | ||
1410 | } | ||
1411 | // TODO: offset should be in bytes, in this case we are assuming | ||
1412 | // 64bit types, hence ST64 | ||
1413 | return (CompResult){.type = COMP_NIL}; | ||
1414 | } | ||
1415 | switch (res.type) { | ||
1416 | case COMP_CONST: { | ||
1417 | emit_op(op_stvari, map->val.idx, res.idx, 0, node->var.val, chunk); | ||
1418 | } break; | ||
1419 | case COMP_REG: { | ||
1420 | if (str_eq(node->var.val->type, cstr("str"))) { | ||
1421 | // Get the address for the local/global storage | ||
1422 | // variable. | ||
1423 | sz var_addr = chunk->reg_idx++; | ||
1424 | emit_op(op_ldaddr, var_addr, map->val.idx, 0, node, chunk); | ||
1425 | |||
1426 | // Copy the fat pointer. | ||
1427 | emit_fat_copy(chunk, node, var_addr, res.idx); | ||
1428 | } else { | ||
1429 | emit_op(op_stvar, map->val.idx, res.idx, 0, node->var.val, | ||
1430 | chunk); | ||
1431 | } | ||
1432 | } break; | ||
1433 | default: { | ||
1434 | emit_compile_err(compiler, chunk, node); | ||
1435 | return (CompResult){.type = COMP_ERR}; | ||
1436 | } break; | ||
1437 | } | ||
558 | return (CompResult){.type = COMP_NIL}; | 1438 | return (CompResult){.type = COMP_NIL}; |
559 | } | 1439 | } |
560 | 1440 | ||
561 | CompResult | 1441 | CompResult |
562 | compile_expr(Chunk *chunk, Node *node) { | 1442 | compile_symbol(Compiler *compiler, Chunk *chunk, Node *node) { |
1443 | Str name = node->unique_name; | ||
1444 | StrVarMap *map = NULL; | ||
1445 | Chunk *next = chunk; | ||
1446 | while (next) { | ||
1447 | map = varmap_lookup(&next->varmap, name); | ||
1448 | if (map) { | ||
1449 | break; | ||
1450 | } | ||
1451 | next = next->parent; | ||
1452 | } | ||
1453 | if (!map) { | ||
1454 | emit_compile_err(compiler, chunk, node); | ||
1455 | return (CompResult){.type = COMP_ERR}; | ||
1456 | } | ||
1457 | sz op_ldaddr = OP_LDLADDR; | ||
1458 | sz op_ldvar = OP_LDLVAR; | ||
1459 | if (next == &compiler->main_chunk) { | ||
1460 | op_ldaddr = OP_LDGADDR; | ||
1461 | op_ldvar = OP_LDGVAR; | ||
1462 | } | ||
1463 | Variable var = map->val; | ||
1464 | u8 reg_dst = chunk->reg_idx++; | ||
1465 | if (node->is_ptr || str_has_prefix(var.type, cstr("[]")) || | ||
1466 | str_eq(var.type, cstr("str"))) { | ||
1467 | emit_op(op_ldaddr, reg_dst, var.idx, 0, node, chunk); | ||
1468 | } else { | ||
1469 | emit_op(op_ldvar, reg_dst, var.idx, 0, node, chunk); | ||
1470 | } | ||
1471 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | ||
1472 | } | ||
1473 | |||
1474 | CompResult | ||
1475 | compile_symbol_idx(Compiler *compiler, Chunk *chunk, Node *node) { | ||
1476 | Str name = node->unique_name; | ||
1477 | StrVarMap *map = NULL; | ||
1478 | Chunk *next = chunk; | ||
1479 | while (next) { | ||
1480 | map = varmap_lookup(&next->varmap, name); | ||
1481 | if (map) { | ||
1482 | break; | ||
1483 | } | ||
1484 | next = next->parent; | ||
1485 | } | ||
1486 | if (!map) { | ||
1487 | eprintln("couldn't resolve symbol name: %s", name); | ||
1488 | emit_compile_err(compiler, chunk, node); | ||
1489 | return (CompResult){.type = COMP_ERR}; | ||
1490 | } | ||
1491 | sz op_ldaddr = OP_LDLADDR; | ||
1492 | sz op_ldvar = OP_LDLVAR; | ||
1493 | if (next == &compiler->main_chunk) { | ||
1494 | op_ldaddr = OP_LDGADDR; | ||
1495 | op_ldvar = OP_LDGVAR; | ||
1496 | } | ||
1497 | |||
1498 | // Destination. | ||
1499 | u8 reg_dst = chunk->reg_idx++; | ||
1500 | |||
1501 | // Address. | ||
1502 | sz reg_addr = chunk->reg_idx++; | ||
1503 | if (str_has_prefix(map->val.type, cstr("[]"))) { | ||
1504 | emit_op(op_ldaddr, reg_addr, map->val.idx, 0, node->var.val, chunk); | ||
1505 | } else { | ||
1506 | emit_op(op_ldvar, reg_addr, map->val.idx, 0, node->var.val, chunk); | ||
1507 | } | ||
1508 | |||
1509 | // Index. | ||
1510 | CompResult idx = compile_expr(compiler, chunk, node->sym.arr_size); | ||
1511 | switch (idx.type) { | ||
1512 | case COMP_CONST: { | ||
1513 | emit_op(OP_LD64I, reg_dst, reg_addr, idx.idx, node, chunk); | ||
1514 | } break; | ||
1515 | case COMP_REG: { | ||
1516 | emit_op(OP_LD64, reg_dst, reg_addr, idx.idx, node, chunk); | ||
1517 | } break; | ||
1518 | default: { | ||
1519 | emit_compile_err(compiler, chunk, node); | ||
1520 | return (CompResult){.type = COMP_ERR}; | ||
1521 | } break; | ||
1522 | } | ||
1523 | // TODO: hardcoding the type size for now (LD64/LD64I). | ||
1524 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | ||
1525 | } | ||
1526 | |||
1527 | CompResult | ||
1528 | compile_expr(Compiler *compiler, Chunk *chunk, Node *node) { | ||
563 | switch (node->kind) { | 1529 | switch (node->kind) { |
564 | case NODE_IF: return compile_if(chunk, node); | 1530 | case NODE_BREAK: return compile_break(compiler, chunk, node); |
1531 | case NODE_CONTINUE: return compile_continue(compiler, chunk, node); | ||
1532 | case NODE_RETURN: return compile_return(compiler, chunk, node); | ||
1533 | case NODE_FUN: return compile_function(compiler, chunk, node); | ||
1534 | case NODE_FUNCALL: return compile_funcall(compiler, chunk, node); | ||
1535 | case NODE_WHILE: return compile_while(compiler, chunk, node); | ||
1536 | case NODE_IF: return compile_if(compiler, chunk, node); | ||
1537 | case NODE_COND: return compile_cond(compiler, chunk, node); | ||
565 | // Logic. | 1538 | // Logic. |
566 | // case NODE_XOR: | ||
567 | case NODE_BITNOT: | 1539 | case NODE_BITNOT: |
568 | case NODE_NOT: return compile_unary(chunk, node); break; | 1540 | case NODE_NOT: return compile_unary(compiler, chunk, node); break; |
569 | case NODE_AND: | 1541 | case NODE_AND: |
570 | case NODE_OR: | 1542 | case NODE_OR: |
571 | case NODE_EQ: | 1543 | case NODE_EQ: |
@@ -576,6 +1548,7 @@ compile_expr(Chunk *chunk, Node *node) { | |||
576 | // Bitwise ops. | 1548 | // Bitwise ops. |
577 | case NODE_BITAND: | 1549 | case NODE_BITAND: |
578 | case NODE_BITOR: | 1550 | case NODE_BITOR: |
1551 | case NODE_BITXOR: | ||
579 | case NODE_BITLSHIFT: | 1552 | case NODE_BITLSHIFT: |
580 | case NODE_BITRSHIFT: | 1553 | case NODE_BITRSHIFT: |
581 | // Arithmetic. | 1554 | // Arithmetic. |
@@ -584,7 +1557,7 @@ compile_expr(Chunk *chunk, Node *node) { | |||
584 | case NODE_SUB: | 1557 | case NODE_SUB: |
585 | case NODE_MUL: | 1558 | case NODE_MUL: |
586 | case NODE_DIV: | 1559 | case NODE_DIV: |
587 | case NODE_MOD: return compile_binary(chunk, node); break; | 1560 | case NODE_MOD: return compile_binary(compiler, chunk, node); break; |
588 | case NODE_TRUE: | 1561 | case NODE_TRUE: |
589 | case NODE_FALSE: | 1562 | case NODE_FALSE: |
590 | case NODE_NUM_FLOAT: | 1563 | case NODE_NUM_FLOAT: |
@@ -599,105 +1572,30 @@ compile_expr(Chunk *chunk, Node *node) { | |||
599 | } break; | 1572 | } break; |
600 | case NODE_STRING: { | 1573 | case NODE_STRING: { |
601 | Str string = node->value.str; | 1574 | Str string = node->value.str; |
602 | // Make sure we don't have duplicated strings. | 1575 | sz str_idx = add_string(chunk, string); |
603 | StrIntMap *map = strintmap_lookup(&chunk->strmap, string); | ||
604 | if (!map) { | ||
605 | map = strintmap_insert(&chunk->strmap, string, chunk->str_idx++, | ||
606 | chunk->storage); | ||
607 | array_push(chunk->strings, string, chunk->storage); | ||
608 | } | ||
609 | return (CompResult){ | 1576 | return (CompResult){ |
610 | .type = COMP_STRING, | 1577 | .type = COMP_STRING, |
611 | .idx = map->val, | 1578 | .idx = str_idx, |
612 | }; | 1579 | }; |
613 | } break; | 1580 | } break; |
614 | case NODE_LET: { | 1581 | case NODE_LET: return compile_let(compiler, chunk, node); |
615 | sz idx = array_size(chunk->vars); | 1582 | case NODE_SET: return compile_set(compiler, chunk, node); |
616 | Str name = node->unique_name; | 1583 | case NODE_SYMBOL: return compile_symbol(compiler, chunk, node); |
617 | Str type = node->var_name->type; | 1584 | case NODE_SYMBOL_IDX: return compile_symbol_idx(compiler, chunk, node); |
618 | sz size = 8; | ||
619 | // TODO: get type storage from a table to consider all the basic | ||
620 | // types as well as user defined ones. | ||
621 | if (str_eq(type, cstr("str"))) { | ||
622 | size = 16; | ||
623 | } | ||
624 | Variable var = (Variable){ | ||
625 | .name = name, | ||
626 | .type = type, | ||
627 | .size = size, | ||
628 | .offset = chunk->var_off, | ||
629 | .idx = idx, | ||
630 | }; | ||
631 | varmap_insert(&chunk->varmap, name, var, chunk->storage); | ||
632 | array_push(chunk->vars, var, chunk->storage); | ||
633 | chunk->var_off += size; | ||
634 | |||
635 | // Value. | ||
636 | if (node->var_val) { | ||
637 | CompResult res = compile_expr(chunk, node->var_val); | ||
638 | switch (res.type) { | ||
639 | case COMP_CONST: { | ||
640 | EMIT_OP(OP_STGVARI, idx, res.idx, 0, node->var_val, | ||
641 | chunk); | ||
642 | } break; | ||
643 | case COMP_REG: { | ||
644 | EMIT_OP(OP_STGVAR, idx, res.idx, 0, node->var_val, | ||
645 | chunk); | ||
646 | } break; | ||
647 | default: { | ||
648 | return (CompResult){.type = COMP_ERR}; | ||
649 | } break; | ||
650 | } | ||
651 | } | ||
652 | |||
653 | return (CompResult){.type = COMP_NIL}; | ||
654 | } break; | ||
655 | case NODE_SET: { | ||
656 | Str name = node->unique_name; | ||
657 | StrVarMap *map = varmap_lookup(&chunk->varmap, name); | ||
658 | if (!map) { | ||
659 | println("you wot mate?: %s", name); | ||
660 | } | ||
661 | CompResult res = compile_expr(chunk, node->var_val); | ||
662 | switch (res.type) { | ||
663 | case COMP_CONST: { | ||
664 | EMIT_OP(OP_STGVARI, map->val.idx, res.idx, 0, node->var_val, | ||
665 | chunk); | ||
666 | } break; | ||
667 | case COMP_REG: { | ||
668 | EMIT_OP(OP_STGVAR, map->val.idx, res.idx, 0, node->var_val, | ||
669 | chunk); | ||
670 | } break; | ||
671 | default: { | ||
672 | return (CompResult){.type = COMP_ERR}; | ||
673 | } break; | ||
674 | } | ||
675 | return (CompResult){.type = COMP_NIL}; | ||
676 | } break; | ||
677 | case NODE_SYMBOL: { | ||
678 | Str name = node->unique_name; | ||
679 | StrVarMap *map = varmap_lookup(&chunk->varmap, name); | ||
680 | if (!map) { | ||
681 | println("error: unreachable... name: %s", name); | ||
682 | exit(EXIT_FAILURE); | ||
683 | } | ||
684 | Variable var = map->val; | ||
685 | u8 reg_dst = chunk->reg_idx++; | ||
686 | EMIT_OP(OP_LDGVAR, reg_dst, var.idx, 0, node, chunk); | ||
687 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | ||
688 | } break; | ||
689 | case NODE_BLOCK: { | 1585 | case NODE_BLOCK: { |
690 | CompResult res; | 1586 | CompResult res; |
691 | for (sz i = 0; i < array_size(node->elements); i++) { | 1587 | for (sz i = 0; i < array_size(node->elements); i++) { |
692 | Node *root = node->elements[i]; | 1588 | Node *root = node->elements[i]; |
693 | res = compile_expr(chunk, root); | 1589 | res = compile_expr(compiler, chunk, root); |
694 | } | 1590 | } |
695 | return res; | 1591 | return res; |
696 | } break; | 1592 | } break; |
1593 | case NODE_NIL: return (CompResult){.type = COMP_NIL}; | ||
697 | default: { | 1594 | default: { |
698 | eprintln("error: compilation not implemented for node %s", | 1595 | eprintln("error: compilation not implemented for node %s", |
699 | node_str[node->kind]); | 1596 | node_str[node->kind]); |
700 | exit(EXIT_FAILURE); | 1597 | emit_compile_err(compiler, chunk, node); |
1598 | return (CompResult){.type = COMP_ERR}; | ||
701 | } break; | 1599 | } break; |
702 | } | 1600 | } |
703 | return (CompResult){.type = COMP_ERR}; | 1601 | return (CompResult){.type = COMP_ERR}; |
@@ -706,6 +1604,10 @@ compile_expr(Chunk *chunk, Node *node) { | |||
706 | void | 1604 | void |
707 | disassemble_instruction(Instruction instruction) { | 1605 | disassemble_instruction(Instruction instruction) { |
708 | switch (instruction.op) { | 1606 | switch (instruction.op) { |
1607 | case OP_CALL: | ||
1608 | println("%s f%d", op_str[instruction.op], instruction.dst, | ||
1609 | instruction.a, instruction.b); | ||
1610 | break; | ||
709 | case OP_MOV8: | 1611 | case OP_MOV8: |
710 | case OP_MOV16: | 1612 | case OP_MOV16: |
711 | case OP_MOV32: | 1613 | case OP_MOV32: |
@@ -713,12 +1615,15 @@ disassemble_instruction(Instruction instruction) { | |||
713 | println("%s r%d, r%d", op_str[instruction.op], instruction.dst, | 1615 | println("%s r%d, r%d", op_str[instruction.op], instruction.dst, |
714 | instruction.a, instruction.b); | 1616 | instruction.a, instruction.b); |
715 | break; | 1617 | break; |
1618 | case OP_JMPF: | ||
1619 | case OP_JMPT: | ||
1620 | println("%s l%d, r%d", op_str[instruction.op], instruction.dst, | ||
1621 | instruction.a, instruction.b); | ||
1622 | break; | ||
716 | case OP_LD8K: | 1623 | case OP_LD8K: |
717 | case OP_LD16K: | 1624 | case OP_LD16K: |
718 | case OP_LD32K: | 1625 | case OP_LD32K: |
719 | case OP_LD64K: | 1626 | case OP_LD64K: |
720 | case OP_JMPF: | ||
721 | case OP_JMPT: | ||
722 | println("%s r%d, c%d", op_str[instruction.op], instruction.dst, | 1627 | println("%s r%d, c%d", op_str[instruction.op], instruction.dst, |
723 | instruction.a, instruction.b); | 1628 | instruction.a, instruction.b); |
724 | break; | 1629 | break; |
@@ -752,6 +1657,7 @@ disassemble_instruction(Instruction instruction) { | |||
752 | case OP_BITRSHIFTI: | 1657 | case OP_BITRSHIFTI: |
753 | case OP_BITANDI: | 1658 | case OP_BITANDI: |
754 | case OP_BITORI: | 1659 | case OP_BITORI: |
1660 | case OP_BITXORI: | ||
755 | println("%s r%d, r%d, c%d", op_str[instruction.op], instruction.dst, | 1661 | println("%s r%d, r%d, c%d", op_str[instruction.op], instruction.dst, |
756 | instruction.a, instruction.b); | 1662 | instruction.a, instruction.b); |
757 | break; | 1663 | break; |
@@ -785,18 +1691,28 @@ disassemble_instruction(Instruction instruction) { | |||
785 | case OP_BITRSHIFT: | 1691 | case OP_BITRSHIFT: |
786 | case OP_BITAND: | 1692 | case OP_BITAND: |
787 | case OP_BITOR: | 1693 | case OP_BITOR: |
1694 | case OP_BITXOR: | ||
788 | println("%s r%d, r%d, r%d", op_str[instruction.op], instruction.dst, | 1695 | println("%s r%d, r%d, r%d", op_str[instruction.op], instruction.dst, |
789 | instruction.a, instruction.b); | 1696 | instruction.a, instruction.b); |
790 | break; | 1697 | break; |
791 | case OP_LDGVAR: | 1698 | case OP_LDGVAR: |
1699 | case OP_LDGADDR: | ||
1700 | case OP_LDLVAR: | ||
1701 | case OP_LDLADDR: | ||
792 | println("%s r%d, v%d", op_str[instruction.op], instruction.dst, | 1702 | println("%s r%d, v%d", op_str[instruction.op], instruction.dst, |
793 | instruction.a, instruction.b); | 1703 | instruction.a, instruction.b); |
794 | break; | 1704 | break; |
1705 | case OP_LDSTR: | ||
1706 | println("%s r%d, s%d", op_str[instruction.op], instruction.dst, | ||
1707 | instruction.a, instruction.b); | ||
1708 | break; | ||
795 | case OP_STGVAR: | 1709 | case OP_STGVAR: |
1710 | case OP_STLVAR: | ||
796 | println("%s v%d, r%d", op_str[instruction.op], instruction.dst, | 1711 | println("%s v%d, r%d", op_str[instruction.op], instruction.dst, |
797 | instruction.a, instruction.b); | 1712 | instruction.a, instruction.b); |
798 | break; | 1713 | break; |
799 | case OP_STGVARI: | 1714 | case OP_STGVARI: |
1715 | case OP_STLVARI: | ||
800 | println("%s v%d, c%d", op_str[instruction.op], instruction.dst, | 1716 | println("%s v%d, c%d", op_str[instruction.op], instruction.dst, |
801 | instruction.a, instruction.b); | 1717 | instruction.a, instruction.b); |
802 | break; | 1718 | break; |
@@ -810,19 +1726,37 @@ disassemble_instruction(Instruction instruction) { | |||
810 | println("%s r%d, r%d", op_str[instruction.op], instruction.dst, | 1726 | println("%s r%d, r%d", op_str[instruction.op], instruction.dst, |
811 | instruction.a, instruction.b); | 1727 | instruction.a, instruction.b); |
812 | break; | 1728 | break; |
813 | case OP_JMPI: | ||
814 | println("%s c%d", op_str[instruction.op], instruction.dst, | ||
815 | instruction.a, instruction.b); | ||
816 | break; | ||
817 | case OP_JMP: | 1729 | case OP_JMP: |
818 | println("%s r%d", op_str[instruction.op], instruction.dst, | 1730 | println("%s l%d", op_str[instruction.op], instruction.dst, |
819 | instruction.a, instruction.b); | 1731 | instruction.a, instruction.b); |
820 | break; | 1732 | break; |
821 | case OP_JMPFI: | 1733 | case OP_JMPFI: |
822 | case OP_JMPTI: | 1734 | case OP_JMPTI: |
823 | println("%s c%d, c%d", op_str[instruction.op], instruction.dst, | 1735 | println("%s l%d, c%d", op_str[instruction.op], instruction.dst, |
824 | instruction.a, instruction.b); | 1736 | instruction.a, instruction.b); |
825 | break; | 1737 | break; |
1738 | case OP_PRINTS64: | ||
1739 | case OP_PRINTF64: | ||
1740 | case OP_PRINTSTR: | ||
1741 | case OP_PRINTBOOL: | ||
1742 | case OP_PUSH: | ||
1743 | case OP_POP: | ||
1744 | case OP_PUTRET: | ||
1745 | println("%s r%d", op_str[instruction.op], instruction.dst, | ||
1746 | instruction.a, instruction.b); | ||
1747 | break; | ||
1748 | case OP_PRINTSTRI: | ||
1749 | case OP_PRINTS64I: | ||
1750 | case OP_PRINTF64I: | ||
1751 | case OP_PRINTBOOLI: | ||
1752 | case OP_RESERVE: | ||
1753 | case OP_PUSHI: | ||
1754 | case OP_PUTRETI: | ||
1755 | println("%s c%d", op_str[instruction.op], instruction.dst, | ||
1756 | instruction.a, instruction.b); | ||
1757 | break; | ||
1758 | case OP_RET: | ||
1759 | case OP_RECUR: | ||
826 | case OP_HALT: println("%s", op_str[instruction.op]); break; | 1760 | case OP_HALT: println("%s", op_str[instruction.op]); break; |
827 | default: println("Unknown opcode %d", instruction.op); break; | 1761 | default: println("Unknown opcode %d", instruction.op); break; |
828 | } | 1762 | } |
@@ -830,36 +1764,120 @@ disassemble_instruction(Instruction instruction) { | |||
830 | 1764 | ||
831 | void | 1765 | void |
832 | disassemble_chunk(Chunk chunk) { | 1766 | disassemble_chunk(Chunk chunk) { |
833 | println("%s: ============== code ==============", chunk.file_name); | 1767 | println("CHUNK %d: %s%s", chunk.id, chunk.file_name, chunk.name); |
1768 | println("n_regs: %d, n_vars: %d, n_strings: %d, n_consts: %d", | ||
1769 | chunk.reg_idx, array_size(chunk.vars), chunk.str_idx, | ||
1770 | chunk.const_idx); | ||
1771 | println("================== code =================="); | ||
1772 | println(" LINE:COL INUM LABELS OP OPERANDS "); | ||
1773 | println("------------------------------------------"); | ||
834 | for (sz i = 0; i < array_size(chunk.code); i++) { | 1774 | for (sz i = 0; i < array_size(chunk.code); i++) { |
835 | print("%s: %x{4}: ", chunk.file_name, i); | 1775 | printf(" %.4ld:%.4ld %.4lx ", chunk.linecol[i].line, |
1776 | chunk.linecol[i].col, i); | ||
1777 | IntIntMapIter lab_it = intintmap_iterator(chunk.labels, chunk.storage); | ||
1778 | IntIntMap *m = intintmap_next(&lab_it, chunk.storage); | ||
1779 | Str labs = cstr(""); | ||
1780 | while (m) { | ||
1781 | if (m->val == i) { | ||
1782 | labs = str_concat(labs, cstr(".L"), chunk.storage); | ||
1783 | labs = str_concat(labs, str_from_int(m->key, chunk.storage), | ||
1784 | chunk.storage); | ||
1785 | break; | ||
1786 | } | ||
1787 | m = intintmap_next(&lab_it, chunk.storage); | ||
1788 | } | ||
1789 | if (labs.size) { | ||
1790 | print("%s", labs); | ||
1791 | for (sz i = 0; i < 7 - labs.size; i++) { | ||
1792 | print(" "); | ||
1793 | } | ||
1794 | } else { | ||
1795 | printf(" "); | ||
1796 | } | ||
836 | disassemble_instruction(chunk.code[i]); | 1797 | disassemble_instruction(chunk.code[i]); |
837 | } | 1798 | } |
838 | if (array_size(chunk.constants) > 0) { | 1799 | if (array_size(chunk.constants) > 0) { |
839 | println("%s: ============ constants ===========", chunk.file_name); | 1800 | println("================ constants ===============", chunk.file_name); |
840 | for (sz i = 0; i < array_size(chunk.constants); i++) { | 1801 | for (sz i = 0; i < array_size(chunk.constants); i++) { |
841 | println("%s: %x{2}: %x{8}", chunk.file_name, i, | 1802 | println(" %x{2}: %x{8}", i, chunk.constants[i]); |
842 | chunk.constants[i]); | ||
843 | } | 1803 | } |
844 | } | 1804 | } |
845 | if (array_size(chunk.strings) > 0) { | 1805 | if (array_size(chunk.strings) > 0) { |
846 | println("%s: ============= strings ============", chunk.file_name); | 1806 | println("================= strings ================", chunk.file_name); |
847 | for (sz i = 0; i < array_size(chunk.strings); i++) { | 1807 | for (sz i = 0; i < array_size(chunk.strings); i++) { |
848 | println("%s: %x{2}: %s", chunk.file_name, i, chunk.strings[i]); | 1808 | println(" %x{2}: %s", i, chunk.strings[i]); |
849 | } | 1809 | } |
850 | } | 1810 | } |
851 | if (array_size(chunk.vars) > 0) { | 1811 | if (array_size(chunk.vars) > 0) { |
852 | println("%s: ============ variables ===========", chunk.file_name); | 1812 | println("================ variables ===============", chunk.file_name); |
853 | for (sz i = 0; i < array_size(chunk.vars); i++) { | 1813 | for (sz i = 0; i < array_size(chunk.vars); i++) { |
854 | println("%s: %x{2}: [%x{4}:%x{4}] %s: %s", chunk.file_name, i, | 1814 | println(" %x{2}: [%x{4}:%x{4}] %s: %s", i, chunk.vars[i].offset, |
855 | chunk.vars[i].offset, | ||
856 | chunk.vars[i].offset + chunk.vars[i].size, | 1815 | chunk.vars[i].offset + chunk.vars[i].size, |
857 | chunk.vars[i].name, chunk.vars[i].type); | 1816 | chunk.vars[i].name, chunk.vars[i].type); |
858 | } | 1817 | } |
859 | } | 1818 | } |
860 | println("n_regs: %d, n_vars: %d, n_strings: %d, n_consts: %d", | 1819 | if (array_size(chunk.functions) > 0) { |
861 | chunk.reg_idx, array_size(chunk.vars), chunk.str_idx, | 1820 | println("================ functions ===============", chunk.file_name); |
862 | chunk.const_idx); | 1821 | for (sz i = 0; i < array_size(chunk.functions); i++) { |
1822 | Chunk *func = chunk.functions[i]; | ||
1823 | println(" %x{2}: func%d: %s", i, func->id, func->name); | ||
1824 | } | ||
1825 | } | ||
1826 | println("=========================================="); | ||
1827 | for (sz i = 0; i < array_size(chunk.functions); i++) { | ||
1828 | Chunk *func = chunk.functions[i]; | ||
1829 | disassemble_chunk(*func); | ||
1830 | } | ||
1831 | } | ||
1832 | |||
1833 | void | ||
1834 | bytecode_compiler(Compiler *compiler, Parser parser) { | ||
1835 | compiler->main_chunk = (Chunk){ | ||
1836 | .file_name = compiler->file_name, | ||
1837 | .storage = compiler->storage, | ||
1838 | .name = cstr(".main"), | ||
1839 | }; | ||
1840 | // TODO: Fill up builtin types and tables. | ||
1841 | array_zero(compiler->main_chunk.constants, 256, compiler->storage); | ||
1842 | array_zero(compiler->main_chunk.code, 0xffff, compiler->storage); | ||
1843 | sz n_roots = array_size(parser.nodes); | ||
1844 | CompResult res = {0}; | ||
1845 | |||
1846 | // Do a first pass to setup the function declarations on the main scope. | ||
1847 | Chunk *chunk = &compiler->main_chunk; | ||
1848 | for (sz i = 0; i < n_roots; i++) { | ||
1849 | Node *root = parser.nodes[i]; | ||
1850 | if (root->kind == NODE_FUN) { | ||
1851 | declare_function(chunk, root); | ||
1852 | } | ||
1853 | } | ||
1854 | |||
1855 | // Compile all root expressions. | ||
1856 | for (sz i = 0; i < n_roots; i++) { | ||
1857 | Node *root = parser.nodes[i]; | ||
1858 | res = compile_expr(compiler, chunk, root); | ||
1859 | } | ||
1860 | |||
1861 | // Make sure the last result is on r0. | ||
1862 | sz res_reg = 0; | ||
1863 | bool is_nil = false; | ||
1864 | switch (res.type) { | ||
1865 | case COMP_CONST: { | ||
1866 | res_reg = chunk->reg_idx++; | ||
1867 | Instruction inst = | ||
1868 | (Instruction){.op = OP_LD64K, .dst = res_reg, .a = res.idx}; | ||
1869 | array_push(chunk->code, inst, chunk->storage); | ||
1870 | } break; | ||
1871 | case COMP_REG: { | ||
1872 | res_reg = res.idx; | ||
1873 | } break; | ||
1874 | case COMP_NIL: { | ||
1875 | is_nil = true; | ||
1876 | } break; | ||
1877 | default: break; | ||
1878 | } | ||
1879 | emit_op(OP_HALT, res_reg, !is_nil, 0, NULL, chunk); | ||
1880 | verify_chunk(chunk); | ||
863 | } | 1881 | } |
864 | 1882 | ||
865 | #endif // COMPILER_C | 1883 | #endif // COMPILER_C |
diff --git a/src/lexer.c b/src/lexer.c index 2feba2a..22d7edc 100644 --- a/src/lexer.c +++ b/src/lexer.c | |||
@@ -41,13 +41,19 @@ typedef enum TokenKind { | |||
41 | TOK_STRUCT, // struct | 41 | TOK_STRUCT, // struct |
42 | TOK_TRUE, // true | 42 | TOK_TRUE, // true |
43 | TOK_WHILE, // while | 43 | TOK_WHILE, // while |
44 | TOK_FOR, // for | ||
44 | 45 | ||
45 | // Arithmetic ops. | 46 | // Arithmetic ops. |
46 | TOK_ADD, // + | 47 | TOK_ADD, // + |
47 | TOK_SUB, // - | 48 | TOK_SUB, // - |
48 | TOK_MUL, // * | 49 | TOK_MUL, // * |
49 | TOK_DIV, // / | 50 | TOK_DIV, // / |
50 | TOK_MOD, // % | 51 | TOK_MOD, // % |
52 | TOK_ADD_ASSIGN, // += | ||
53 | TOK_SUB_ASSIGN, // -= | ||
54 | TOK_MUL_ASSIGN, // *= | ||
55 | TOK_DIV_ASSIGN, // /= | ||
56 | TOK_MOD_ASSIGN, // %= | ||
51 | 57 | ||
52 | // Logical ops. | 58 | // Logical ops. |
53 | TOK_NOT, // ! | 59 | TOK_NOT, // ! |
@@ -61,11 +67,17 @@ typedef enum TokenKind { | |||
61 | TOK_GE, // >= | 67 | TOK_GE, // >= |
62 | 68 | ||
63 | // Bitwise ops. | 69 | // Bitwise ops. |
64 | TOK_BITNOT, // ~ | 70 | TOK_BITNOT, // ~ |
65 | TOK_BITAND, // & | 71 | TOK_BITAND, // & |
66 | TOK_BITOR, // | | 72 | TOK_BITOR, // | |
67 | TOK_BITLSHIFT, // << | 73 | TOK_BITXOR, // ^ |
68 | TOK_BITRSHIFT, // >> | 74 | TOK_BITLSHIFT, // << |
75 | TOK_BITRSHIFT, // >> | ||
76 | TOK_BITAND_ASSIGN, // &= | ||
77 | TOK_BITOR_ASSIGN, // |= | ||
78 | TOK_BITXOR_ASSIGN, // ^= | ||
79 | TOK_BITLSHIFT_ASSIGN, // <<= | ||
80 | TOK_BITRSHIFT_ASSIGN, // >>= | ||
69 | 81 | ||
70 | // Special ops. | 82 | // Special ops. |
71 | TOK_COLON, // : | 83 | TOK_COLON, // : |
@@ -113,6 +125,7 @@ Str token_str[] = { | |||
113 | [TOK_STRUCT] = cstr("STRUCT"), | 125 | [TOK_STRUCT] = cstr("STRUCT"), |
114 | [TOK_TRUE] = cstr("TRUE"), | 126 | [TOK_TRUE] = cstr("TRUE"), |
115 | [TOK_WHILE] = cstr("WHILE"), | 127 | [TOK_WHILE] = cstr("WHILE"), |
128 | [TOK_FOR] = cstr("FOR"), | ||
116 | 129 | ||
117 | // Arithmetic ops. | 130 | // Arithmetic ops. |
118 | [TOK_ADD] = cstr("ADD"), | 131 | [TOK_ADD] = cstr("ADD"), |
@@ -120,6 +133,11 @@ Str token_str[] = { | |||
120 | [TOK_MUL] = cstr("MUL"), | 133 | [TOK_MUL] = cstr("MUL"), |
121 | [TOK_DIV] = cstr("DIV"), | 134 | [TOK_DIV] = cstr("DIV"), |
122 | [TOK_MOD] = cstr("MOD"), | 135 | [TOK_MOD] = cstr("MOD"), |
136 | [TOK_ADD_ASSIGN] = cstr("ADD_ASSIGN"), | ||
137 | [TOK_SUB_ASSIGN] = cstr("SUB_ASSIGN"), | ||
138 | [TOK_MUL_ASSIGN] = cstr("MUL_ASSIGN"), | ||
139 | [TOK_DIV_ASSIGN] = cstr("DIV_ASSIGN"), | ||
140 | [TOK_MOD_ASSIGN] = cstr("MOD_ASSIGN"), | ||
123 | 141 | ||
124 | // Logical ops. | 142 | // Logical ops. |
125 | [TOK_NOT] = cstr("NOT"), | 143 | [TOK_NOT] = cstr("NOT"), |
@@ -136,8 +154,14 @@ Str token_str[] = { | |||
136 | [TOK_BITNOT] = cstr("BITNOT"), | 154 | [TOK_BITNOT] = cstr("BITNOT"), |
137 | [TOK_BITAND] = cstr("BITAND"), | 155 | [TOK_BITAND] = cstr("BITAND"), |
138 | [TOK_BITOR] = cstr("BITOR"), | 156 | [TOK_BITOR] = cstr("BITOR"), |
157 | [TOK_BITXOR] = cstr("BITXOR"), | ||
139 | [TOK_BITLSHIFT] = cstr("BITLSHIFT"), | 158 | [TOK_BITLSHIFT] = cstr("BITLSHIFT"), |
140 | [TOK_BITRSHIFT] = cstr("BITRSHIFT"), | 159 | [TOK_BITRSHIFT] = cstr("BITRSHIFT"), |
160 | [TOK_BITAND_ASSIGN] = cstr("BITAND_ASSIGN"), | ||
161 | [TOK_BITOR_ASSIGN] = cstr("BITOR_ASSIGN"), | ||
162 | [TOK_BITXOR_ASSIGN] = cstr("BITXOR_ASSIGN"), | ||
163 | [TOK_BITLSHIFT_ASSIGN] = cstr("BITLSHIFT_ASSIGN"), | ||
164 | [TOK_BITRSHIFT_ASSIGN] = cstr("BITRSHIFT_ASSIGN"), | ||
141 | 165 | ||
142 | // Special ops. | 166 | // Special ops. |
143 | [TOK_COLON] = cstr("COLON"), | 167 | [TOK_COLON] = cstr("COLON"), |
@@ -429,22 +453,48 @@ scan_token(Scanner *scanner) { | |||
429 | case '+': { | 453 | case '+': { |
430 | char p = scan_peek(scanner); | 454 | char p = scan_peek(scanner); |
431 | if (p >= '0' && p <= '9') { | 455 | if (p >= '0' && p <= '9') { |
432 | *scanner = current; | 456 | scan_next(scanner); |
433 | return emit_token_number(scanner); | 457 | return emit_token_number(scanner); |
434 | } | 458 | } |
459 | if (p == '=') { | ||
460 | scan_next(scanner); | ||
461 | return emit_token(current, scanner, TOK_ADD_ASSIGN); | ||
462 | } | ||
435 | return emit_token(current, scanner, TOK_ADD); | 463 | return emit_token(current, scanner, TOK_ADD); |
436 | }; | 464 | }; |
437 | case '-': { | 465 | case '-': { |
438 | char p = scan_peek(scanner); | 466 | char p = scan_peek(scanner); |
439 | if (p >= '0' && p <= '9') { | 467 | if (p >= '0' && p <= '9') { |
440 | *scanner = current; | 468 | scan_next(scanner); |
441 | return emit_token_number(scanner); | 469 | return emit_token_number(scanner); |
442 | } | 470 | } |
471 | if (p == '=') { | ||
472 | scan_next(scanner); | ||
473 | return emit_token(current, scanner, TOK_SUB_ASSIGN); | ||
474 | } | ||
443 | return emit_token(current, scanner, TOK_SUB); | 475 | return emit_token(current, scanner, TOK_SUB); |
444 | }; | 476 | }; |
445 | case '*': return emit_token(current, scanner, TOK_MUL); | 477 | case '*': { |
446 | case '/': return emit_token(current, scanner, TOK_DIV); | 478 | if (scan_peek(scanner) == '=') { |
447 | case '%': return emit_token(current, scanner, TOK_MOD); | 479 | scan_next(scanner); |
480 | return emit_token(current, scanner, TOK_MUL_ASSIGN); | ||
481 | } | ||
482 | return emit_token(current, scanner, TOK_MUL); | ||
483 | } | ||
484 | case '/': { | ||
485 | if (scan_peek(scanner) == '=') { | ||
486 | scan_next(scanner); | ||
487 | return emit_token(current, scanner, TOK_DIV_ASSIGN); | ||
488 | } | ||
489 | return emit_token(current, scanner, TOK_DIV); | ||
490 | } | ||
491 | case '%': { | ||
492 | if (scan_peek(scanner) == '=') { | ||
493 | scan_next(scanner); | ||
494 | return emit_token(current, scanner, TOK_MOD_ASSIGN); | ||
495 | } | ||
496 | return emit_token(current, scanner, TOK_MOD); | ||
497 | } | ||
448 | case '!': { | 498 | case '!': { |
449 | if (scan_peek(scanner) == '=') { | 499 | if (scan_peek(scanner) == '=') { |
450 | scan_next(scanner); | 500 | scan_next(scanner); |
@@ -467,6 +517,10 @@ scan_token(Scanner *scanner) { | |||
467 | } | 517 | } |
468 | if (p == '<') { | 518 | if (p == '<') { |
469 | scan_next(scanner); | 519 | scan_next(scanner); |
520 | if (scan_peek(scanner) == '=') { | ||
521 | scan_next(scanner); | ||
522 | return emit_token(current, scanner, TOK_BITLSHIFT_ASSIGN); | ||
523 | } | ||
470 | return emit_token(current, scanner, TOK_BITLSHIFT); | 524 | return emit_token(current, scanner, TOK_BITLSHIFT); |
471 | } | 525 | } |
472 | return emit_token(current, scanner, TOK_LT); | 526 | return emit_token(current, scanner, TOK_LT); |
@@ -479,23 +533,44 @@ scan_token(Scanner *scanner) { | |||
479 | } | 533 | } |
480 | if (p == '>') { | 534 | if (p == '>') { |
481 | scan_next(scanner); | 535 | scan_next(scanner); |
536 | if (scan_peek(scanner) == '=') { | ||
537 | scan_next(scanner); | ||
538 | return emit_token(current, scanner, TOK_BITRSHIFT_ASSIGN); | ||
539 | } | ||
482 | return emit_token(current, scanner, TOK_BITRSHIFT); | 540 | return emit_token(current, scanner, TOK_BITRSHIFT); |
483 | } | 541 | } |
484 | return emit_token(current, scanner, TOK_GT); | 542 | return emit_token(current, scanner, TOK_GT); |
485 | }; | 543 | }; |
486 | case '~': return emit_token(current, scanner, TOK_BITNOT); | 544 | case '~': return emit_token(current, scanner, TOK_BITNOT); |
545 | case '^': { | ||
546 | if (scan_peek(scanner) == '=') { | ||
547 | scan_next(scanner); | ||
548 | return emit_token(current, scanner, TOK_BITXOR_ASSIGN); | ||
549 | } | ||
550 | return emit_token(current, scanner, TOK_BITXOR); | ||
551 | }; | ||
487 | case '&': { | 552 | case '&': { |
488 | if (scan_peek(scanner) == '&') { | 553 | char p = scan_peek(scanner); |
554 | if (p == '&') { | ||
489 | scan_next(scanner); | 555 | scan_next(scanner); |
490 | return emit_token(current, scanner, TOK_AND); | 556 | return emit_token(current, scanner, TOK_AND); |
491 | } | 557 | } |
558 | if (p == '=') { | ||
559 | scan_next(scanner); | ||
560 | return emit_token(current, scanner, TOK_BITOR_ASSIGN); | ||
561 | } | ||
492 | return emit_token(current, scanner, TOK_BITAND); | 562 | return emit_token(current, scanner, TOK_BITAND); |
493 | }; | 563 | }; |
494 | case '|': { | 564 | case '|': { |
495 | if (scan_peek(scanner) == '|') { | 565 | char p = scan_peek(scanner); |
566 | if (p == '|') { | ||
496 | scan_next(scanner); | 567 | scan_next(scanner); |
497 | return emit_token(current, scanner, TOK_OR); | 568 | return emit_token(current, scanner, TOK_OR); |
498 | } | 569 | } |
570 | if (p == '=') { | ||
571 | scan_next(scanner); | ||
572 | return emit_token(current, scanner, TOK_BITOR_ASSIGN); | ||
573 | } | ||
499 | return emit_token(current, scanner, TOK_BITOR); | 574 | return emit_token(current, scanner, TOK_BITOR); |
500 | }; | 575 | }; |
501 | case ':': return emit_token(current, scanner, TOK_COLON); | 576 | case ':': return emit_token(current, scanner, TOK_COLON); |
@@ -536,77 +611,80 @@ scan_token(Scanner *scanner) { | |||
536 | } | 611 | } |
537 | switch (val.mem[0]) { | 612 | switch (val.mem[0]) { |
538 | case 'b': { | 613 | case 'b': { |
539 | if (str_has_prefix(val, cstr("break"))) { | 614 | if (str_eq(val, cstr("break"))) { |
540 | return emit_token(current, scanner, TOK_BREAK); | 615 | return emit_token(current, scanner, TOK_BREAK); |
541 | } | 616 | } |
542 | } break; | 617 | } break; |
543 | case 'c': { | 618 | case 'c': { |
544 | if (str_has_prefix(val, cstr("case"))) { | 619 | if (str_eq(val, cstr("case"))) { |
545 | return emit_token(current, scanner, TOK_CASE); | 620 | return emit_token(current, scanner, TOK_CASE); |
546 | } | 621 | } |
547 | if (str_has_prefix(val, cstr("continue"))) { | 622 | if (str_eq(val, cstr("continue"))) { |
548 | return emit_token(current, scanner, TOK_CONTINUE); | 623 | return emit_token(current, scanner, TOK_CONTINUE); |
549 | } | 624 | } |
550 | if (str_has_prefix(val, cstr("cond"))) { | 625 | if (str_eq(val, cstr("cond"))) { |
551 | return emit_token(current, scanner, TOK_COND); | 626 | return emit_token(current, scanner, TOK_COND); |
552 | } | 627 | } |
553 | } break; | 628 | } break; |
554 | case 'e': { | 629 | case 'e': { |
555 | if (str_has_prefix(val, cstr("else"))) { | 630 | if (str_eq(val, cstr("else"))) { |
556 | return emit_token(current, scanner, TOK_ELSE); | 631 | return emit_token(current, scanner, TOK_ELSE); |
557 | } | 632 | } |
558 | if (str_has_prefix(val, cstr("enum"))) { | 633 | if (str_eq(val, cstr("enum"))) { |
559 | return emit_token(current, scanner, TOK_ENUM); | 634 | return emit_token(current, scanner, TOK_ENUM); |
560 | } | 635 | } |
561 | } break; | 636 | } break; |
562 | case 'f': { | 637 | case 'f': { |
563 | if (str_has_prefix(val, cstr("false"))) { | 638 | if (str_eq(val, cstr("false"))) { |
564 | return emit_token(current, scanner, TOK_FALSE); | 639 | return emit_token(current, scanner, TOK_FALSE); |
565 | } | 640 | } |
566 | if (str_has_prefix(val, cstr("fun"))) { | 641 | if (str_eq(val, cstr("fun"))) { |
567 | return emit_token(current, scanner, TOK_FUN); | 642 | return emit_token(current, scanner, TOK_FUN); |
568 | } | 643 | } |
644 | if (str_eq(val, cstr("for"))) { | ||
645 | return emit_token(current, scanner, TOK_FOR); | ||
646 | } | ||
569 | } break; | 647 | } break; |
570 | case 'i': { | 648 | case 'i': { |
571 | if (str_has_prefix(val, cstr("if"))) { | 649 | if (str_eq(val, cstr("if"))) { |
572 | return emit_token(current, scanner, TOK_IF); | 650 | return emit_token(current, scanner, TOK_IF); |
573 | } | 651 | } |
574 | } break; | 652 | } break; |
575 | case 'l': { | 653 | case 'l': { |
576 | if (str_has_prefix(val, cstr("let"))) { | 654 | if (str_eq(val, cstr("let"))) { |
577 | return emit_token(current, scanner, TOK_LET); | 655 | return emit_token(current, scanner, TOK_LET); |
578 | } | 656 | } |
579 | } break; | 657 | } break; |
580 | case 'm': { | 658 | case 'm': { |
581 | if (str_has_prefix(val, cstr("match"))) { | 659 | if (str_eq(val, cstr("match"))) { |
582 | return emit_token(current, scanner, TOK_MATCH); | 660 | return emit_token(current, scanner, TOK_MATCH); |
583 | } | 661 | } |
584 | } break; | 662 | } break; |
585 | case 'n': { | 663 | case 'n': { |
586 | if (str_has_prefix(val, cstr("nil"))) { | 664 | if (str_eq(val, cstr("nil"))) { |
587 | return emit_token(current, scanner, TOK_NIL); | 665 | return emit_token(current, scanner, TOK_NIL); |
588 | } | 666 | } |
589 | } break; | 667 | } break; |
590 | case 'r': { | 668 | case 'r': { |
591 | if (str_has_prefix(val, cstr("return"))) { | 669 | if (str_eq(val, cstr("return"))) { |
592 | return emit_token(current, scanner, TOK_RETURN); | 670 | return emit_token(current, scanner, TOK_RETURN); |
593 | } | 671 | } |
594 | } break; | 672 | } break; |
595 | case 's': { | 673 | case 's': { |
596 | if (str_has_prefix(val, cstr("set"))) { | 674 | if (str_eq(val, cstr("set"))) { |
597 | return emit_token(current, scanner, TOK_SET); | 675 | return emit_token(current, scanner, TOK_SET); |
598 | } | 676 | } |
599 | if (str_has_prefix(val, cstr("struct"))) { | 677 | if (str_eq(val, cstr("struct"))) { |
600 | return emit_token(current, scanner, TOK_STRUCT); | 678 | return emit_token(current, scanner, TOK_STRUCT); |
601 | } | 679 | } |
602 | } break; | 680 | } break; |
603 | case 't': { | 681 | case 't': { |
604 | if (str_has_prefix(val, cstr("true"))) { | 682 | if (str_eq(val, cstr("true"))) { |
605 | return emit_token(current, scanner, TOK_TRUE); | 683 | return emit_token(current, scanner, TOK_TRUE); |
606 | } | 684 | } |
607 | } break; | 685 | } break; |
608 | case 'w': { | 686 | case 'w': { |
609 | if (str_has_prefix(val, cstr("while"))) { | 687 | if (str_eq(val, cstr("while"))) { |
610 | return emit_token(current, scanner, TOK_WHILE); | 688 | return emit_token(current, scanner, TOK_WHILE); |
611 | } | 689 | } |
612 | } break; | 690 | } break; |
@@ -628,4 +706,4 @@ print_tokens(Str path, Token *tokens) { | |||
628 | } | 706 | } |
629 | } | 707 | } |
630 | 708 | ||
631 | #endif // LEXER_C | 709 | #endif // LEXER_C |
@@ -12,7 +12,26 @@ | |||
12 | // TODO: unions | 12 | // TODO: unions |
13 | // TODO: embed (binary file) and include (source file) | 13 | // TODO: embed (binary file) and include (source file) |
14 | // TODO: revisit ast parsing for pointers and arrays (I think I'm missing corner | 14 | // TODO: revisit ast parsing for pointers and arrays (I think I'm missing corner |
15 | // cases). | 15 | // cases). |
16 | // TODO: fix semantics for the following expression: | ||
17 | // let b = int | ||
18 | // a type shouldn't be a valid symbol name | ||
19 | // TODO: consider making all tye types PascalCase: Int F64 Str... | ||
20 | // TODO: add a `const` keyword that can only take literals or constexpr values. | ||
21 | // TODO: "first class functions" via function pointers | ||
22 | // TODO: convenient function calls per data type instead of methods: | ||
23 | // fun add(a: int, b: int): int a + b | ||
24 | // add(12, 34) == 12.add(34) | ||
25 | // concat(str, str): str | ||
26 | // "hello ".concat("world") ; "hello world" | ||
27 | // TODO: more numeric types | ||
28 | // TODO: structs and user defined types | ||
29 | // TODO: tail-call optimization. | ||
30 | // TODO: constant folding | ||
31 | // TODO: constexpr evaluation | ||
32 | // TODO: shortcircuit evaluation for && and || operators. | ||
33 | // TODO: casting on demand (1:u16, 0x123:ptr, "hi":int ??? how to deal with | ||
34 | // unsafe casts?) | ||
16 | 35 | ||
17 | typedef enum ExecMode { | 36 | typedef enum ExecMode { |
18 | RUN_NORMAL, | 37 | RUN_NORMAL, |
@@ -44,6 +63,9 @@ process_file(Str path) { | |||
44 | sz errors = 0; | 63 | sz errors = 0; |
45 | 64 | ||
46 | // Lexer. | 65 | // Lexer. |
66 | #if DEBUG == 1 | ||
67 | println("lexing..."); | ||
68 | #endif | ||
47 | Scanner scanner = {.str = file.data}; | 69 | Scanner scanner = {.str = file.data}; |
48 | Token *tokens = NULL; | 70 | Token *tokens = NULL; |
49 | Token tok = {0}; | 71 | Token tok = {0}; |
@@ -67,6 +89,9 @@ process_file(Str path) { | |||
67 | } | 89 | } |
68 | 90 | ||
69 | // Parser. | 91 | // Parser. |
92 | #if DEBUG == 1 | ||
93 | println("parsing..."); | ||
94 | #endif | ||
70 | Parser parser = { | 95 | Parser parser = { |
71 | .tokens = tokens, | 96 | .tokens = tokens, |
72 | .storage = &lexer_arena, | 97 | .storage = &lexer_arena, |
@@ -94,6 +119,9 @@ process_file(Str path) { | |||
94 | } | 119 | } |
95 | 120 | ||
96 | // Semantic analysis. | 121 | // Semantic analysis. |
122 | #if DEBUG == 1 | ||
123 | println("semantic analysis..."); | ||
124 | #endif | ||
97 | Analyzer analyzer = (Analyzer){ | 125 | Analyzer analyzer = (Analyzer){ |
98 | .storage = &lexer_arena, | 126 | .storage = &lexer_arena, |
99 | .file_name = path, | 127 | .file_name = path, |
@@ -166,63 +194,27 @@ process_file(Str path) { | |||
166 | // TODO: Type checking. | 194 | // TODO: Type checking. |
167 | 195 | ||
168 | // Compile roots. | 196 | // Compile roots. |
197 | #if DEBUG == 1 | ||
198 | println("compilation..."); | ||
199 | #endif | ||
169 | Arena bytecode_arena = arena_create(LEXER_MEM, os_allocator); | 200 | Arena bytecode_arena = arena_create(LEXER_MEM, os_allocator); |
170 | Chunk chunk = {.file_name = path, .storage = &bytecode_arena}; | 201 | Compiler compiler = { |
171 | array_zero(chunk.constants, 256, &bytecode_arena); | 202 | .file_name = path, |
172 | array_zero(chunk.code, 0xffff, &bytecode_arena); | 203 | .storage = &bytecode_arena, |
173 | sz n_roots = array_size(parser.nodes); | 204 | .integer_types = analyzer.integer_types, |
174 | CompResult res = {0}; | 205 | .numeric_types = analyzer.numeric_types, |
175 | for (sz i = 0; i < n_roots; i++) { | 206 | }; |
176 | // The parser stores the root nodes as a stack. | 207 | bytecode_compiler(&compiler, parser); |
177 | Node *root = parser.nodes[i]; | 208 | disassemble_chunk(compiler.main_chunk); |
178 | res = compile_expr(&chunk, root); | ||
179 | if (res.type == COMP_ERR) { | ||
180 | eprintln("compilation error..."); | ||
181 | exit(EXIT_FAILURE); | ||
182 | } | ||
183 | } | ||
184 | sz res_reg = 0; | ||
185 | switch (res.type) { | ||
186 | case COMP_CONST: { | ||
187 | res_reg = chunk.reg_idx++; | ||
188 | Instruction inst = | ||
189 | (Instruction){.op = OP_LD64K, .dst = res_reg, .a = res.idx}; | ||
190 | array_push(chunk.code, inst, chunk.storage); | ||
191 | } break; | ||
192 | case COMP_REG: { | ||
193 | res_reg = res.idx; | ||
194 | } break; | ||
195 | default: break; | ||
196 | } | ||
197 | // After we are done move the last result to r0 for printing. | ||
198 | Instruction halt = (Instruction){.op = OP_HALT, .dst = res_reg}; | ||
199 | array_push(chunk.code, halt, &bytecode_arena); | ||
200 | |||
201 | if (chunk.const_idx >= 256) { | ||
202 | eprintln("too many constants on chunk %s", chunk.id); | ||
203 | exit(EXIT_FAILURE); | ||
204 | } | ||
205 | if (chunk.str_idx >= 256) { | ||
206 | eprintln("too many strings on chunk %s", chunk.id); | ||
207 | exit(EXIT_FAILURE); | ||
208 | } | ||
209 | if (chunk.reg_idx >= 256) { | ||
210 | eprintln("too many registers used on chunk %s", chunk.id); | ||
211 | exit(EXIT_FAILURE); | ||
212 | } | ||
213 | |||
214 | disassemble_chunk(chunk); | ||
215 | 209 | ||
216 | // Run bytecode on VM. | 210 | // Run bytecode on VM. |
217 | VM vm = {0}; | 211 | VM vm = {0}; |
218 | vm_init(&vm, &chunk); | 212 | vm_init(&vm, &compiler.main_chunk); |
219 | // println("VM REGISTERS BEFORE:\n%{Mem}", | ||
220 | // &(Array){.mem = (u8 *)&vm.regs, sizeof(vm.regs)}); | ||
221 | vm_run(&vm); | 213 | vm_run(&vm); |
222 | // println("VM REGISTERS AFTER:\n%{Mem}", | 214 | #if DEBUG == 1 |
223 | // &(Array){.mem = (u8 *)&vm.regs, sizeof(vm.regs)}); | 215 | println("MEMORY:\n%{Mem}", |
224 | // println("VM MEMORY AFTER:\n%{Mem}", | 216 | &(Array){.mem = (u8 *)&vm.stack, sizeof(vm.stack)}); |
225 | // &(Array){.mem = (u8 *)&vm.stack, sizeof(vm.stack)}); | 217 | #endif |
226 | 218 | ||
227 | #if DEBUG == 1 | 219 | #if DEBUG == 1 |
228 | println("Space used: %{Arena}", &lexer_arena); | 220 | println("Space used: %{Arena}", &lexer_arena); |
diff --git a/src/parser.c b/src/parser.c index 90adaf3..5253841 100644 --- a/src/parser.c +++ b/src/parser.c | |||
@@ -9,6 +9,7 @@ | |||
9 | // | 9 | // |
10 | 10 | ||
11 | typedef enum NodeKind { | 11 | typedef enum NodeKind { |
12 | NODE_ERR, | ||
12 | // Arithmetic. | 13 | // Arithmetic. |
13 | NODE_ADD, | 14 | NODE_ADD, |
14 | NODE_SUB, | 15 | NODE_SUB, |
@@ -29,6 +30,7 @@ typedef enum NodeKind { | |||
29 | NODE_BITNOT, | 30 | NODE_BITNOT, |
30 | NODE_BITAND, | 31 | NODE_BITAND, |
31 | NODE_BITOR, | 32 | NODE_BITOR, |
33 | NODE_BITXOR, | ||
32 | NODE_BITLSHIFT, | 34 | NODE_BITLSHIFT, |
33 | NODE_BITRSHIFT, | 35 | NODE_BITRSHIFT, |
34 | // Literals. | 36 | // Literals. |
@@ -69,6 +71,7 @@ typedef enum NodeKind { | |||
69 | } NodeKind; | 71 | } NodeKind; |
70 | 72 | ||
71 | Str node_str[] = { | 73 | Str node_str[] = { |
74 | [NODE_ERR] = cstr("ERR"), | ||
72 | // Arithmetic. | 75 | // Arithmetic. |
73 | [NODE_ADD] = cstr("ADD"), | 76 | [NODE_ADD] = cstr("ADD"), |
74 | [NODE_SUB] = cstr("SUB"), | 77 | [NODE_SUB] = cstr("SUB"), |
@@ -89,6 +92,7 @@ Str node_str[] = { | |||
89 | [NODE_BITNOT] = cstr("BITNOT"), | 92 | [NODE_BITNOT] = cstr("BITNOT"), |
90 | [NODE_BITAND] = cstr("BITAND"), | 93 | [NODE_BITAND] = cstr("BITAND"), |
91 | [NODE_BITOR] = cstr("BITOR"), | 94 | [NODE_BITOR] = cstr("BITOR"), |
95 | [NODE_BITXOR] = cstr("BITXOR"), | ||
92 | [NODE_BITLSHIFT] = cstr("BITLSHIFT"), | 96 | [NODE_BITLSHIFT] = cstr("BITLSHIFT"), |
93 | [NODE_BITRSHIFT] = cstr("BITRSHIFT"), | 97 | [NODE_BITRSHIFT] = cstr("BITRSHIFT"), |
94 | // Literals. | 98 | // Literals. |
@@ -128,75 +132,102 @@ Str node_str[] = { | |||
128 | [NODE_BLOCK] = cstr("BLOCK"), | 132 | [NODE_BLOCK] = cstr("BLOCK"), |
129 | }; | 133 | }; |
130 | 134 | ||
135 | typedef union NodeLit { | ||
136 | f64 d; | ||
137 | sz i; | ||
138 | u64 u; | ||
139 | Str str; | ||
140 | Str sym; | ||
141 | } NodeLit; | ||
142 | |||
143 | typedef struct NodeBinary { | ||
144 | struct Node *left; | ||
145 | struct Node *right; | ||
146 | } NodeBinary; | ||
147 | |||
148 | typedef struct NodeUnary { | ||
149 | struct Node *left; | ||
150 | } NodeUnary; | ||
151 | |||
152 | typedef struct NodeVariable { | ||
153 | struct Node *name; | ||
154 | struct Node *type; | ||
155 | struct Node *val; | ||
156 | } NodeVariable; | ||
157 | |||
158 | typedef struct NodeLoop { | ||
159 | struct Node *cond; | ||
160 | struct Node *expr; | ||
161 | } NodeLoop; | ||
162 | |||
163 | typedef struct NodeIf { | ||
164 | struct Node *cond; | ||
165 | struct Node *expr_true; | ||
166 | struct Node *expr_else; | ||
167 | } NodeIf; | ||
168 | |||
169 | typedef struct NodeField { | ||
170 | struct Node *type; | ||
171 | struct Node *val; | ||
172 | } NodeField; | ||
173 | |||
174 | typedef struct NodeParam { | ||
175 | struct Node *name; | ||
176 | struct Node *type; | ||
177 | } NodeParam; | ||
178 | |||
179 | typedef struct NodeMatch { | ||
180 | struct Node *expr; | ||
181 | struct Node **cases; | ||
182 | } NodeMatch; | ||
183 | |||
184 | typedef struct NodeCase { | ||
185 | struct Node *cond; | ||
186 | struct Node *expr; | ||
187 | } NodeCase; | ||
188 | |||
189 | typedef struct NodeFunction { | ||
190 | struct Node *name; | ||
191 | struct Node **params; | ||
192 | struct Node **ret; | ||
193 | struct Node *body; | ||
194 | } NodeFunction; | ||
195 | |||
196 | typedef struct NodeSymbol { | ||
197 | struct Node *next; | ||
198 | struct Node *arr_size; | ||
199 | } NodeSymbol; | ||
200 | |||
131 | typedef struct Node { | 201 | typedef struct Node { |
132 | sz id; | 202 | sz id; |
133 | sz line; | 203 | sz line; |
134 | sz col; | 204 | sz col; |
205 | struct Node *parent; | ||
135 | 206 | ||
136 | NodeKind kind; | 207 | NodeKind kind; |
208 | NodeLit value; | ||
137 | union { | 209 | union { |
138 | f64 d; | 210 | NodeBinary binary; |
139 | sz i; | 211 | NodeUnary unary; |
140 | u64 u; | 212 | NodeVariable var; |
141 | Str str; | 213 | NodeSymbol sym; |
142 | Str sym; | 214 | NodeLoop loop; |
143 | } value; | 215 | NodeIf ifelse; |
144 | union { | 216 | NodeField field; |
145 | struct { | 217 | NodeParam param; |
146 | struct Node *left; | 218 | NodeMatch match; |
147 | struct Node *right; | 219 | NodeCase case_entry; |
148 | }; | 220 | NodeFunction func; |
149 | struct { | ||
150 | struct Node *next; | ||
151 | struct Node *arr_size; | ||
152 | }; | ||
153 | struct { | ||
154 | struct Node *var_name; | ||
155 | struct Node *var_type; | ||
156 | struct Node *var_val; | ||
157 | }; | ||
158 | struct { | ||
159 | struct Node *while_cond; | ||
160 | struct Node *while_expr; | ||
161 | }; | ||
162 | struct { | ||
163 | struct Node *cond_if; | ||
164 | struct Node *cond_expr; | ||
165 | struct Node *cond_else; | ||
166 | }; | ||
167 | struct { | ||
168 | struct Node *field_type; | ||
169 | struct Node *field_val; | ||
170 | }; | ||
171 | struct { | ||
172 | struct Node *param_name; | ||
173 | struct Node *param_type; | ||
174 | }; | ||
175 | struct { | ||
176 | struct Node *match_expr; | ||
177 | struct Node **match_cases; | ||
178 | }; | ||
179 | struct { | ||
180 | struct Node *case_value; | ||
181 | struct Node *case_expr; | ||
182 | }; | ||
183 | struct Node **struct_field; | 221 | struct Node **struct_field; |
184 | struct Node **elements; | 222 | struct Node **elements; |
185 | struct Node **statements; | 223 | struct Node **statements; |
186 | struct Node **expressions; | 224 | struct Node **expressions; |
187 | struct Node **arguments; | 225 | struct Node **arguments; |
188 | struct { | ||
189 | struct Node *func_name; | ||
190 | struct Node **func_params; | ||
191 | struct Node **func_ret; | ||
192 | struct Node *func_body; | ||
193 | }; | ||
194 | }; | 226 | }; |
195 | bool is_ptr; | 227 | bool is_ptr; |
196 | struct Scope *scope; | ||
197 | Str type; | 228 | Str type; |
198 | Str fun_params; | 229 | Str type_params; |
199 | Str fun_return; | 230 | Str type_returns; |
200 | Str unique_name; | 231 | Str unique_name; |
201 | } Node; | 232 | } Node; |
202 | 233 | ||
@@ -286,6 +317,7 @@ ParseRule parse_rules[] = { | |||
286 | [TOK_BITNOT] = {parse_unary, NULL, PREC_NONE}, | 317 | [TOK_BITNOT] = {parse_unary, NULL, PREC_NONE}, |
287 | [TOK_BITAND] = {NULL, parse_binary, PREC_BITLOGIC}, | 318 | [TOK_BITAND] = {NULL, parse_binary, PREC_BITLOGIC}, |
288 | [TOK_BITOR] = {NULL, parse_binary, PREC_BITLOGIC}, | 319 | [TOK_BITOR] = {NULL, parse_binary, PREC_BITLOGIC}, |
320 | [TOK_BITXOR] = {NULL, parse_binary, PREC_BITLOGIC}, | ||
289 | [TOK_BITLSHIFT] = {NULL, parse_binary, PREC_BITSHIFT}, | 321 | [TOK_BITLSHIFT] = {NULL, parse_binary, PREC_BITSHIFT}, |
290 | [TOK_BITRSHIFT] = {NULL, parse_binary, PREC_BITSHIFT}, | 322 | [TOK_BITRSHIFT] = {NULL, parse_binary, PREC_BITSHIFT}, |
291 | 323 | ||
@@ -308,6 +340,7 @@ ParseRule parse_rules[] = { | |||
308 | [TOK_MATCH] = {parse_keyword, NULL, PREC_NONE}, | 340 | [TOK_MATCH] = {parse_keyword, NULL, PREC_NONE}, |
309 | [TOK_COND] = {parse_keyword, NULL, PREC_NONE}, | 341 | [TOK_COND] = {parse_keyword, NULL, PREC_NONE}, |
310 | [TOK_WHILE] = {parse_keyword, NULL, PREC_NONE}, | 342 | [TOK_WHILE] = {parse_keyword, NULL, PREC_NONE}, |
343 | [TOK_FOR] = {parse_keyword, NULL, PREC_NONE}, | ||
311 | [TOK_CONTINUE] = {parse_keyword, NULL, PREC_NONE}, | 344 | [TOK_CONTINUE] = {parse_keyword, NULL, PREC_NONE}, |
312 | [TOK_BREAK] = {parse_keyword, NULL, PREC_NONE}, | 345 | [TOK_BREAK] = {parse_keyword, NULL, PREC_NONE}, |
313 | [TOK_FUN] = {parse_keyword, NULL, PREC_NONE}, | 346 | [TOK_FUN] = {parse_keyword, NULL, PREC_NONE}, |
@@ -437,7 +470,7 @@ parse_unary(Parser *parser) { | |||
437 | default: break; // Unreachable. | 470 | default: break; // Unreachable. |
438 | } | 471 | } |
439 | if (!node) return; | 472 | if (!node) return; |
440 | node->left = array_pop(parser->nodes); | 473 | node->unary.left = array_pop(parser->nodes); |
441 | array_push(parser->nodes, node, parser->storage); | 474 | array_push(parser->nodes, node, parser->storage); |
442 | } | 475 | } |
443 | 476 | ||
@@ -482,7 +515,7 @@ parse_type(Parser *parser) { | |||
482 | node->kind = NODE_ARR_TYPE, | 515 | node->kind = NODE_ARR_TYPE, |
483 | parse_consume(parser, TOK_NUM_INT, cstr("no array size given")); | 516 | parse_consume(parser, TOK_NUM_INT, cstr("no array size given")); |
484 | parse_number(parser); | 517 | parse_number(parser); |
485 | node->arr_size = array_pop(parser->nodes); | 518 | node->sym.arr_size = array_pop(parser->nodes); |
486 | parse_consume(parser, TOK_RSQUARE, | 519 | parse_consume(parser, TOK_RSQUARE, |
487 | cstr("unmatched brackets ']' in array type")); | 520 | cstr("unmatched brackets ']' in array type")); |
488 | } | 521 | } |
@@ -510,16 +543,16 @@ parse_struct_field(Parser *parser) { | |||
510 | Node *subfield = array_pop(parser->nodes); | 543 | Node *subfield = array_pop(parser->nodes); |
511 | array_push(type->elements, subfield, parser->storage); | 544 | array_push(type->elements, subfield, parser->storage); |
512 | } | 545 | } |
513 | field->field_type = type; | 546 | field->field.type = type; |
514 | } else { | 547 | } else { |
515 | parse_type(parser); | 548 | parse_type(parser); |
516 | field->field_type = array_pop(parser->nodes); | 549 | field->field.type = array_pop(parser->nodes); |
517 | } | 550 | } |
518 | 551 | ||
519 | // Optional assignment. | 552 | // Optional assignment. |
520 | if (parse_match(parser, TOK_ASSIGN)) { | 553 | if (parse_match(parser, TOK_ASSIGN)) { |
521 | parse_expr(parser, PREC_LOW); | 554 | parse_expr(parser, PREC_LOW); |
522 | field->field_val = array_pop(parser->nodes); | 555 | field->field.val = array_pop(parser->nodes); |
523 | } | 556 | } |
524 | array_push(parser->nodes, field, parser->storage); | 557 | array_push(parser->nodes, field, parser->storage); |
525 | } | 558 | } |
@@ -546,10 +579,10 @@ parse_struct_lit_field(Parser *parser) { | |||
546 | Node *subfield = array_pop(parser->nodes); | 579 | Node *subfield = array_pop(parser->nodes); |
547 | array_push(type->elements, subfield, parser->storage); | 580 | array_push(type->elements, subfield, parser->storage); |
548 | } | 581 | } |
549 | field->field_val = type; | 582 | field->field.val = type; |
550 | } else { | 583 | } else { |
551 | parse_expr(parser, PREC_LOW); | 584 | parse_expr(parser, PREC_LOW); |
552 | field->field_val = array_pop(parser->nodes); | 585 | field->field.val = array_pop(parser->nodes); |
553 | } | 586 | } |
554 | array_push(parser->nodes, field, parser->storage); | 587 | array_push(parser->nodes, field, parser->storage); |
555 | } | 588 | } |
@@ -570,8 +603,8 @@ parse_keyword(Parser *parser) { | |||
570 | parse_consume(parser, TOK_SYMBOL, | 603 | parse_consume(parser, TOK_SYMBOL, |
571 | cstr("expected symbol name on let expression")); | 604 | cstr("expected symbol name on let expression")); |
572 | parse_symbol(parser); | 605 | parse_symbol(parser); |
573 | node->var_name = array_pop(parser->nodes); | 606 | node->var.name = array_pop(parser->nodes); |
574 | if (node->var_name->next) { | 607 | if (node->var.name->sym.next) { |
575 | parse_emit_err(parser, prev, | 608 | parse_emit_err(parser, prev, |
576 | cstr("invalid symbol name in let expression")); | 609 | cstr("invalid symbol name in let expression")); |
577 | return; | 610 | return; |
@@ -580,16 +613,16 @@ parse_keyword(Parser *parser) { | |||
580 | // Optional type declaration. | 613 | // Optional type declaration. |
581 | if (parse_match(parser, TOK_COLON)) { | 614 | if (parse_match(parser, TOK_COLON)) { |
582 | parse_type(parser); | 615 | parse_type(parser); |
583 | node->var_type = array_pop(parser->nodes); | 616 | node->var.type = array_pop(parser->nodes); |
584 | } | 617 | } |
585 | 618 | ||
586 | // Optional assignment. | 619 | // Optional assignment. |
587 | if (parse_match(parser, TOK_ASSIGN)) { | 620 | if (parse_match(parser, TOK_ASSIGN)) { |
588 | parse_expr(parser, PREC_LOW); | 621 | parse_expr(parser, PREC_LOW); |
589 | node->var_val = array_pop(parser->nodes); | 622 | node->var.val = array_pop(parser->nodes); |
590 | } | 623 | } |
591 | 624 | ||
592 | if (node->var_type == NULL && node->var_val == NULL) { | 625 | if (node->var.type == NULL && node->var.val == NULL) { |
593 | parse_emit_err(parser, prev, | 626 | parse_emit_err(parser, prev, |
594 | cstr("variable declaration must include type or " | 627 | cstr("variable declaration must include type or " |
595 | "value information")); | 628 | "value information")); |
@@ -599,13 +632,50 @@ parse_keyword(Parser *parser) { | |||
599 | node = node_alloc(parser, NODE_SET, prev); | 632 | node = node_alloc(parser, NODE_SET, prev); |
600 | if (!node) return; | 633 | if (!node) return; |
601 | parse_consume(parser, TOK_SYMBOL, | 634 | parse_consume(parser, TOK_SYMBOL, |
602 | cstr("expected symbol name on let expression")); | 635 | cstr("expected symbol name on set expression")); |
603 | parse_symbol(parser); | 636 | parse_symbol(parser); |
604 | node->var_name = array_pop(parser->nodes); | 637 | node->var.name = array_pop(parser->nodes); |
605 | parse_consume(parser, TOK_ASSIGN, | 638 | |
606 | cstr("expected assignment on set expression")); | 639 | if (parse_match(parser, TOK_ADD_ASSIGN) || |
607 | parse_expr(parser, PREC_LOW); | 640 | parse_match(parser, TOK_ADD_ASSIGN) || |
608 | node->var_val = array_pop(parser->nodes); | 641 | parse_match(parser, TOK_SUB_ASSIGN) || |
642 | parse_match(parser, TOK_MUL_ASSIGN) || | ||
643 | parse_match(parser, TOK_DIV_ASSIGN) || | ||
644 | parse_match(parser, TOK_MOD_ASSIGN) || | ||
645 | parse_match(parser, TOK_BITAND_ASSIGN) || | ||
646 | parse_match(parser, TOK_BITOR_ASSIGN) || | ||
647 | parse_match(parser, TOK_BITXOR_ASSIGN) || | ||
648 | parse_match(parser, TOK_BITLSHIFT_ASSIGN) || | ||
649 | parse_match(parser, TOK_BITRSHIFT_ASSIGN)) { | ||
650 | NodeKind kind = NODE_ERR; | ||
651 | switch (parser->previous.kind) { | ||
652 | case TOK_ADD_ASSIGN: kind = NODE_ADD; break; | ||
653 | case TOK_SUB_ASSIGN: kind = NODE_SUB; break; | ||
654 | case TOK_MUL_ASSIGN: kind = NODE_MUL; break; | ||
655 | case TOK_DIV_ASSIGN: kind = NODE_DIV; break; | ||
656 | case TOK_MOD_ASSIGN: kind = NODE_MOD; break; | ||
657 | case TOK_BITAND_ASSIGN: kind = NODE_BITAND; break; | ||
658 | case TOK_BITOR_ASSIGN: kind = NODE_BITOR; break; | ||
659 | case TOK_BITXOR_ASSIGN: kind = NODE_BITXOR; break; | ||
660 | case TOK_BITLSHIFT_ASSIGN: kind = NODE_BITLSHIFT; break; | ||
661 | case TOK_BITRSHIFT_ASSIGN: kind = NODE_BITRSHIFT; break; | ||
662 | default: break; | ||
663 | } | ||
664 | parse_expr(parser, PREC_LOW); | ||
665 | Node *value = array_pop(parser->nodes); | ||
666 | Node *sym = node_alloc(parser, NODE_SYMBOL, prev); | ||
667 | Node *op = node_alloc(parser, kind, prev); | ||
668 | op->binary.left = sym; | ||
669 | op->binary.right = value; | ||
670 | node->var.val = op; | ||
671 | sym->value = node->var.name->value; | ||
672 | sym->kind = node->var.name->kind; | ||
673 | } else { | ||
674 | parse_consume(parser, TOK_ASSIGN, | ||
675 | cstr("expected assignment on set expression")); | ||
676 | parse_expr(parser, PREC_LOW); | ||
677 | node->var.val = array_pop(parser->nodes); | ||
678 | } | ||
609 | } break; | 679 | } break; |
610 | case TOK_STRUCT: { | 680 | case TOK_STRUCT: { |
611 | node = node_alloc(parser, NODE_STRUCT, prev); | 681 | node = node_alloc(parser, NODE_STRUCT, prev); |
@@ -629,19 +699,19 @@ parse_keyword(Parser *parser) { | |||
629 | node = node_alloc(parser, NODE_IF, prev); | 699 | node = node_alloc(parser, NODE_IF, prev); |
630 | if (!node) return; | 700 | if (!node) return; |
631 | parse_expr(parser, PREC_LOW); | 701 | parse_expr(parser, PREC_LOW); |
632 | node->cond_if = array_pop(parser->nodes); | 702 | node->ifelse.cond = array_pop(parser->nodes); |
633 | parse_expr(parser, PREC_LOW); | 703 | parse_expr(parser, PREC_LOW); |
634 | node->cond_expr = array_pop(parser->nodes); | 704 | node->ifelse.expr_true = array_pop(parser->nodes); |
635 | if (parse_match(parser, TOK_ELSE)) { | 705 | if (parse_match(parser, TOK_ELSE)) { |
636 | parse_expr(parser, PREC_LOW); | 706 | parse_expr(parser, PREC_LOW); |
637 | node->cond_else = array_pop(parser->nodes); | 707 | node->ifelse.expr_else = array_pop(parser->nodes); |
638 | } | 708 | } |
639 | } break; | 709 | } break; |
640 | case TOK_MATCH: { | 710 | case TOK_MATCH: { |
641 | node = node_alloc(parser, NODE_MATCH, prev); | 711 | node = node_alloc(parser, NODE_MATCH, prev); |
642 | if (!node) return; | 712 | if (!node) return; |
643 | parse_expr(parser, PREC_LOW); | 713 | parse_expr(parser, PREC_LOW); |
644 | node->match_expr = array_pop(parser->nodes); | 714 | node->match.expr = array_pop(parser->nodes); |
645 | parse_consume(parser, TOK_LCURLY, | 715 | parse_consume(parser, TOK_LCURLY, |
646 | cstr("expected block of match cases")); | 716 | cstr("expected block of match cases")); |
647 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { | 717 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { |
@@ -653,13 +723,13 @@ parse_keyword(Parser *parser) { | |||
653 | parse_consume(parser, TOK_CASE, | 723 | parse_consume(parser, TOK_CASE, |
654 | cstr("expected case statement")); | 724 | cstr("expected case statement")); |
655 | parse_expr(parser, PREC_LOW); | 725 | parse_expr(parser, PREC_LOW); |
656 | tmp->case_value = array_pop(parser->nodes); | 726 | tmp->case_entry.cond = array_pop(parser->nodes); |
657 | } | 727 | } |
658 | parse_consume(parser, TOK_ASSIGN, | 728 | parse_consume(parser, TOK_ASSIGN, |
659 | cstr("malformed case statement")); | 729 | cstr("malformed case statement")); |
660 | parse_expr(parser, PREC_LOW); | 730 | parse_expr(parser, PREC_LOW); |
661 | tmp->case_expr = array_pop(parser->nodes); | 731 | tmp->case_entry.expr = array_pop(parser->nodes); |
662 | array_push(node->match_cases, tmp, parser->storage); | 732 | array_push(node->match.cases, tmp, parser->storage); |
663 | } | 733 | } |
664 | // TODO: Check that we only have literals on the match case, | 734 | // TODO: Check that we only have literals on the match case, |
665 | // this could be done on the analysis step, but also here... | 735 | // this could be done on the analysis step, but also here... |
@@ -683,7 +753,7 @@ parse_keyword(Parser *parser) { | |||
683 | field->value.sym = parser->previous.val; | 753 | field->value.sym = parser->previous.val; |
684 | if (parse_match(parser, TOK_ASSIGN)) { | 754 | if (parse_match(parser, TOK_ASSIGN)) { |
685 | parse_expr(parser, PREC_LOW); | 755 | parse_expr(parser, PREC_LOW); |
686 | field->field_val = array_pop(parser->nodes); | 756 | field->field.val = array_pop(parser->nodes); |
687 | } | 757 | } |
688 | array_push(node->struct_field, field, parser->storage); | 758 | array_push(node->struct_field, field, parser->storage); |
689 | } | 759 | } |
@@ -703,13 +773,13 @@ parse_keyword(Parser *parser) { | |||
703 | // Are we on the default case. | 773 | // Are we on the default case. |
704 | if (!parse_match(parser, TOK_ELSE)) { | 774 | if (!parse_match(parser, TOK_ELSE)) { |
705 | parse_expr(parser, PREC_LOW); | 775 | parse_expr(parser, PREC_LOW); |
706 | tmp->case_value = array_pop(parser->nodes); | 776 | tmp->case_entry.cond = array_pop(parser->nodes); |
707 | } | 777 | } |
708 | parse_consume(parser, TOK_ASSIGN, | 778 | parse_consume(parser, TOK_ASSIGN, |
709 | cstr("malformed case statement")); | 779 | cstr("malformed case statement")); |
710 | parse_expr(parser, PREC_LOW); | 780 | parse_expr(parser, PREC_LOW); |
711 | tmp->case_expr = array_pop(parser->nodes); | 781 | tmp->case_entry.expr = array_pop(parser->nodes); |
712 | array_push(node->match_cases, tmp, parser->storage); | 782 | array_push(node->match.cases, tmp, parser->storage); |
713 | } | 783 | } |
714 | } break; | 784 | } break; |
715 | case TOK_BREAK: { | 785 | case TOK_BREAK: { |
@@ -720,13 +790,47 @@ parse_keyword(Parser *parser) { | |||
720 | node = node_alloc(parser, NODE_CONTINUE, prev); | 790 | node = node_alloc(parser, NODE_CONTINUE, prev); |
721 | if (!node) return; | 791 | if (!node) return; |
722 | } break; | 792 | } break; |
793 | case TOK_FOR: { | ||
794 | node = node_alloc(parser, NODE_BLOCK, prev); | ||
795 | if (!node) return; | ||
796 | |||
797 | Node *node_while = node_alloc(parser, NODE_WHILE, prev); | ||
798 | if (!node_while) return; | ||
799 | Node *block = node_alloc(parser, NODE_BLOCK, prev); | ||
800 | if (!block) return; | ||
801 | |||
802 | parse_expr(parser, PREC_LOW); | ||
803 | Node *pre = array_pop(parser->nodes); | ||
804 | |||
805 | parse_expr(parser, PREC_LOW); | ||
806 | Node *cond = array_pop(parser->nodes); | ||
807 | |||
808 | parse_expr(parser, PREC_LOW); | ||
809 | Node *post = array_pop(parser->nodes); | ||
810 | |||
811 | // Body. | ||
812 | parse_consume(parser, TOK_LCURLY, | ||
813 | cstr("expected '{' on for loop statement")); | ||
814 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { | ||
815 | parse_expr(parser, PREC_LOW); | ||
816 | Node *next = array_pop(parser->nodes); | ||
817 | array_push(block->statements, next, parser->storage); | ||
818 | } | ||
819 | array_push(block->statements, post, parser->storage); | ||
820 | |||
821 | // Put everything together | ||
822 | node_while->loop.cond = cond; | ||
823 | node_while->loop.expr = block; | ||
824 | array_push(node->statements, pre, parser->storage); | ||
825 | array_push(node->statements, node_while, parser->storage); | ||
826 | } break; | ||
723 | case TOK_WHILE: { | 827 | case TOK_WHILE: { |
724 | node = node_alloc(parser, NODE_WHILE, prev); | 828 | node = node_alloc(parser, NODE_WHILE, prev); |
725 | if (!node) return; | 829 | if (!node) return; |
726 | parse_expr(parser, PREC_LOW); | 830 | parse_expr(parser, PREC_LOW); |
727 | node->while_cond = array_pop(parser->nodes); | 831 | node->loop.cond = array_pop(parser->nodes); |
728 | parse_expr(parser, PREC_LOW); | 832 | parse_expr(parser, PREC_LOW); |
729 | node->while_expr = array_pop(parser->nodes); | 833 | node->loop.expr = array_pop(parser->nodes); |
730 | } break; | 834 | } break; |
731 | case TOK_FUN: { | 835 | case TOK_FUN: { |
732 | node = node_alloc(parser, NODE_FUN, prev); | 836 | node = node_alloc(parser, NODE_FUN, prev); |
@@ -735,7 +839,7 @@ parse_keyword(Parser *parser) { | |||
735 | Node *name = node_alloc(parser, NODE_SYMBOL, prev); | 839 | Node *name = node_alloc(parser, NODE_SYMBOL, prev); |
736 | if (!name) return; | 840 | if (!name) return; |
737 | name->value.sym = parser->previous.val; | 841 | name->value.sym = parser->previous.val; |
738 | node->func_name = name; | 842 | node->func.name = name; |
739 | parse_consume(parser, TOK_LPAREN, | 843 | parse_consume(parser, TOK_LPAREN, |
740 | cstr("expected '(' on function definition")); | 844 | cstr("expected '(' on function definition")); |
741 | // Parameters. | 845 | // Parameters. |
@@ -747,7 +851,7 @@ parse_keyword(Parser *parser) { | |||
747 | if (!name) return; | 851 | if (!name) return; |
748 | parse_consume(parser, TOK_SYMBOL, cstr("expected symbol name")); | 852 | parse_consume(parser, TOK_SYMBOL, cstr("expected symbol name")); |
749 | name->value.sym = parser->previous.val; | 853 | name->value.sym = parser->previous.val; |
750 | param->param_name = name; | 854 | param->param.name = name; |
751 | 855 | ||
752 | Node *type = node_alloc(parser, NODE_TYPE, prev); | 856 | Node *type = node_alloc(parser, NODE_TYPE, prev); |
753 | if (!type) return; | 857 | if (!type) return; |
@@ -757,17 +861,17 @@ parse_keyword(Parser *parser) { | |||
757 | } | 861 | } |
758 | parse_consume(parser, TOK_SYMBOL, cstr("expected param type")); | 862 | parse_consume(parser, TOK_SYMBOL, cstr("expected param type")); |
759 | type->value.sym = parser->previous.val; | 863 | type->value.sym = parser->previous.val; |
760 | param->param_type = type; | 864 | param->param.type = type; |
761 | if (parse_match(parser, TOK_LSQUARE)) { | 865 | if (parse_match(parser, TOK_LSQUARE)) { |
762 | type->kind = NODE_ARR_TYPE, | 866 | type->kind = NODE_ARR_TYPE, |
763 | parse_consume(parser, TOK_NUM_INT, | 867 | parse_consume(parser, TOK_NUM_INT, |
764 | cstr("no array size given")); | 868 | cstr("no array size given")); |
765 | parse_number(parser); | 869 | parse_number(parser); |
766 | type->arr_size = array_pop(parser->nodes); | 870 | type->sym.arr_size = array_pop(parser->nodes); |
767 | parse_consume(parser, TOK_RSQUARE, | 871 | parse_consume(parser, TOK_RSQUARE, |
768 | cstr("unmatched brackets ']' in array type")); | 872 | cstr("unmatched brackets ']' in array type")); |
769 | } | 873 | } |
770 | array_push(node->func_params, param, parser->storage); | 874 | array_push(node->func.params, param, parser->storage); |
771 | } | 875 | } |
772 | parse_consume(parser, TOK_COLON, cstr("expected param type")); | 876 | parse_consume(parser, TOK_COLON, cstr("expected param type")); |
773 | 877 | ||
@@ -788,12 +892,12 @@ parse_keyword(Parser *parser) { | |||
788 | parse_consume(parser, TOK_NUM_INT, | 892 | parse_consume(parser, TOK_NUM_INT, |
789 | cstr("no array size given")); | 893 | cstr("no array size given")); |
790 | parse_number(parser); | 894 | parse_number(parser); |
791 | ret->arr_size = array_pop(parser->nodes); | 895 | ret->sym.arr_size = array_pop(parser->nodes); |
792 | parse_consume(parser, TOK_RSQUARE, | 896 | parse_consume(parser, TOK_RSQUARE, |
793 | cstr("unmatched brackets ']' in " | 897 | cstr("unmatched brackets ']' in " |
794 | "array type")); | 898 | "array type")); |
795 | } | 899 | } |
796 | array_push(node->func_ret, ret, parser->storage); | 900 | array_push(node->func.ret, ret, parser->storage); |
797 | } | 901 | } |
798 | } else { | 902 | } else { |
799 | Node *ret = node_alloc(parser, NODE_TYPE, prev); | 903 | Node *ret = node_alloc(parser, NODE_TYPE, prev); |
@@ -809,18 +913,18 @@ parse_keyword(Parser *parser) { | |||
809 | parse_consume(parser, TOK_NUM_INT, | 913 | parse_consume(parser, TOK_NUM_INT, |
810 | cstr("no array size given")); | 914 | cstr("no array size given")); |
811 | parse_number(parser); | 915 | parse_number(parser); |
812 | ret->arr_size = array_pop(parser->nodes); | 916 | ret->sym.arr_size = array_pop(parser->nodes); |
813 | parse_consume( | 917 | parse_consume( |
814 | parser, TOK_RSQUARE, | 918 | parser, TOK_RSQUARE, |
815 | cstr("unmatched brackets ']' in array type")); | 919 | cstr("unmatched brackets ']' in array type")); |
816 | } | 920 | } |
817 | array_push(node->func_ret, ret, parser->storage); | 921 | array_push(node->func.ret, ret, parser->storage); |
818 | } | 922 | } |
819 | } | 923 | } |
820 | 924 | ||
821 | // Body. | 925 | // Body. |
822 | parse_expr(parser, PREC_LOW); | 926 | parse_expr(parser, PREC_LOW); |
823 | node->func_body = array_pop(parser->nodes); | 927 | node->func.body = array_pop(parser->nodes); |
824 | } break; | 928 | } break; |
825 | case TOK_RETURN: { | 929 | case TOK_RETURN: { |
826 | node = node_alloc(parser, NODE_RETURN, prev); | 930 | node = node_alloc(parser, NODE_RETURN, prev); |
@@ -870,6 +974,9 @@ parse_binary(Parser *parser) { | |||
870 | case TOK_BITOR: { | 974 | case TOK_BITOR: { |
871 | node = node_alloc(parser, NODE_BITOR, prev); | 975 | node = node_alloc(parser, NODE_BITOR, prev); |
872 | } break; | 976 | } break; |
977 | case TOK_BITXOR: { | ||
978 | node = node_alloc(parser, NODE_BITXOR, prev); | ||
979 | } break; | ||
873 | case TOK_BITLSHIFT: { | 980 | case TOK_BITLSHIFT: { |
874 | node = node_alloc(parser, NODE_BITLSHIFT, prev); | 981 | node = node_alloc(parser, NODE_BITLSHIFT, prev); |
875 | } break; | 982 | } break; |
@@ -882,8 +989,8 @@ parse_binary(Parser *parser) { | |||
882 | } | 989 | } |
883 | } | 990 | } |
884 | if (!node) return; | 991 | if (!node) return; |
885 | node->right = array_pop(parser->nodes); | 992 | node->binary.right = array_pop(parser->nodes); |
886 | node->left = array_pop(parser->nodes); | 993 | node->binary.left = array_pop(parser->nodes); |
887 | array_push(parser->nodes, node, parser->storage); | 994 | array_push(parser->nodes, node, parser->storage); |
888 | } | 995 | } |
889 | 996 | ||
@@ -965,7 +1072,7 @@ parse_symbol(Parser *parser) { | |||
965 | parse_consume(parser, TOK_SYMBOL, | 1072 | parse_consume(parser, TOK_SYMBOL, |
966 | cstr("expected symbol after '.' operator")); | 1073 | cstr("expected symbol after '.' operator")); |
967 | parse_symbol(parser); | 1074 | parse_symbol(parser); |
968 | node->next = array_pop(parser->nodes); | 1075 | node->sym.next = array_pop(parser->nodes); |
969 | } else if (parser->current.kind == TOK_COLON && | 1076 | } else if (parser->current.kind == TOK_COLON && |
970 | parse_peek(parser) == TOK_LCURLY) { | 1077 | parse_peek(parser) == TOK_LCURLY) { |
971 | parse_advance(parser); | 1078 | parse_advance(parser); |
@@ -981,7 +1088,7 @@ parse_symbol(Parser *parser) { | |||
981 | } else if (parse_match(parser, TOK_LSQUARE)) { | 1088 | } else if (parse_match(parser, TOK_LSQUARE)) { |
982 | node->kind = NODE_SYMBOL_IDX; | 1089 | node->kind = NODE_SYMBOL_IDX; |
983 | parse_expr(parser, PREC_LOW); | 1090 | parse_expr(parser, PREC_LOW); |
984 | node->arr_size = array_pop(parser->nodes); | 1091 | node->sym.arr_size = array_pop(parser->nodes); |
985 | parse_consume(parser, TOK_RSQUARE, | 1092 | parse_consume(parser, TOK_RSQUARE, |
986 | cstr("unmatched brackets ']' in array type")); | 1093 | cstr("unmatched brackets ']' in array type")); |
987 | if (parse_match(parser, TOK_DOT)) { | 1094 | if (parse_match(parser, TOK_DOT)) { |
@@ -989,7 +1096,7 @@ parse_symbol(Parser *parser) { | |||
989 | parse_consume(parser, TOK_SYMBOL, | 1096 | parse_consume(parser, TOK_SYMBOL, |
990 | cstr("expected symbol after '.' operator")); | 1097 | cstr("expected symbol after '.' operator")); |
991 | parse_symbol(parser); | 1098 | parse_symbol(parser); |
992 | node->next = array_pop(parser->nodes); | 1099 | node->sym.next = array_pop(parser->nodes); |
993 | } | 1100 | } |
994 | } else if (parse_match(parser, TOK_LPAREN)) { | 1101 | } else if (parse_match(parser, TOK_LPAREN)) { |
995 | node->kind = NODE_FUNCALL; | 1102 | node->kind = NODE_FUNCALL; |
@@ -1003,7 +1110,7 @@ parse_symbol(Parser *parser) { | |||
1003 | parse_consume(parser, TOK_SYMBOL, | 1110 | parse_consume(parser, TOK_SYMBOL, |
1004 | cstr("expected symbol after '.' operator")); | 1111 | cstr("expected symbol after '.' operator")); |
1005 | parse_symbol(parser); | 1112 | parse_symbol(parser); |
1006 | node->next = array_pop(parser->nodes); | 1113 | node->sym.next = array_pop(parser->nodes); |
1007 | } | 1114 | } |
1008 | } | 1115 | } |
1009 | node->value.sym = prev.val; | 1116 | node->value.sym = prev.val; |
@@ -1051,43 +1158,43 @@ graph_node(Node *node) { | |||
1051 | if (node->type.size > 0) { | 1158 | if (node->type.size > 0) { |
1052 | print("| Type: %s", node->type); | 1159 | print("| Type: %s", node->type); |
1053 | } | 1160 | } |
1054 | if (node->fun_params.size > 0) { | 1161 | if (node->type_params.size > 0) { |
1055 | print("| Params: %s", node->fun_params); | 1162 | print("| Params: %s", node->type_params); |
1056 | } | 1163 | } |
1057 | if (node->fun_return.size > 0) { | 1164 | if (node->type_returns.size > 0) { |
1058 | print("| Return: %s", node->fun_return); | 1165 | print("| Return: %s", node->type_returns); |
1059 | } | 1166 | } |
1060 | println("\"];"); | 1167 | println("\"];"); |
1061 | 1168 | ||
1062 | switch (node->kind) { | 1169 | switch (node->kind) { |
1063 | case NODE_FUN: { | 1170 | case NODE_FUN: { |
1064 | for (sz i = 0; i < array_size(node->func_params); i++) { | 1171 | for (sz i = 0; i < array_size(node->func.params); i++) { |
1065 | Node *next = node->func_params[i]; | 1172 | Node *next = node->func.params[i]; |
1066 | println("%d:e->%d:w;", node->id, next->id); | 1173 | println("%d:e->%d:w;", node->id, next->id); |
1067 | graph_node(next); | 1174 | graph_node(next); |
1068 | } | 1175 | } |
1069 | for (sz i = 0; i < array_size(node->func_ret); i++) { | 1176 | for (sz i = 0; i < array_size(node->func.ret); i++) { |
1070 | Node *next = node->func_ret[i]; | 1177 | Node *next = node->func.ret[i]; |
1071 | println("%d:e->%d:w;", node->id, next->id); | 1178 | println("%d:e->%d:w;", node->id, next->id); |
1072 | graph_node(next); | 1179 | graph_node(next); |
1073 | } | 1180 | } |
1074 | if (node->func_name) { | 1181 | if (node->func.name) { |
1075 | println("%d:e->%d:w;", node->id, node->func_name->id); | 1182 | println("%d:e->%d:w;", node->id, node->func.name->id); |
1076 | graph_node(node->func_name); | 1183 | graph_node(node->func.name); |
1077 | } | 1184 | } |
1078 | if (node->func_body) { | 1185 | if (node->func.body) { |
1079 | println("%d:e->%d:w;", node->id, node->func_body->id); | 1186 | println("%d:e->%d:w;", node->id, node->func.body->id); |
1080 | graph_node(node->func_body); | 1187 | graph_node(node->func.body); |
1081 | } | 1188 | } |
1082 | } break; | 1189 | } break; |
1083 | case NODE_COND: | 1190 | case NODE_COND: |
1084 | case NODE_MATCH: { | 1191 | case NODE_MATCH: { |
1085 | if (node->match_expr) { | 1192 | if (node->match.expr) { |
1086 | println("%d:e->%d:w;", node->id, node->match_expr->id); | 1193 | println("%d:e->%d:w;", node->id, node->match.expr->id); |
1087 | graph_node(node->match_expr); | 1194 | graph_node(node->match.expr); |
1088 | } | 1195 | } |
1089 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 1196 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
1090 | Node *next = node->match_cases[i]; | 1197 | Node *next = node->match.cases[i]; |
1091 | println("%d:e->%d:w;", node->id, next->id); | 1198 | println("%d:e->%d:w;", node->id, next->id); |
1092 | graph_node(next); | 1199 | graph_node(next); |
1093 | } | 1200 | } |
@@ -1112,43 +1219,43 @@ graph_node(Node *node) { | |||
1112 | } | 1219 | } |
1113 | } break; | 1220 | } break; |
1114 | case NODE_IF: { | 1221 | case NODE_IF: { |
1115 | if (node->cond_if) { | 1222 | if (node->ifelse.cond) { |
1116 | println("%d:e->%d:w;", node->id, node->cond_if->id); | 1223 | println("%d:e->%d:w;", node->id, node->ifelse.cond->id); |
1117 | graph_node(node->cond_if); | 1224 | graph_node(node->ifelse.cond); |
1118 | } | 1225 | } |
1119 | if (node->cond_expr) { | 1226 | if (node->ifelse.expr_true) { |
1120 | println("%d:e->%d:w;", node->id, node->cond_expr->id); | 1227 | println("%d:e->%d:w;", node->id, node->ifelse.expr_true->id); |
1121 | graph_node(node->cond_expr); | 1228 | graph_node(node->ifelse.expr_true); |
1122 | } | 1229 | } |
1123 | if (node->cond_else) { | 1230 | if (node->ifelse.expr_else) { |
1124 | println("%d:e->%d:w;", node->id, node->cond_else->id); | 1231 | println("%d:e->%d:w;", node->id, node->ifelse.expr_else->id); |
1125 | graph_node(node->cond_else); | 1232 | graph_node(node->ifelse.expr_else); |
1126 | } | 1233 | } |
1127 | } break; | 1234 | } break; |
1128 | case NODE_FIELD: | 1235 | case NODE_FIELD: |
1129 | case NODE_SET: | 1236 | case NODE_SET: |
1130 | case NODE_LET: { | 1237 | case NODE_LET: { |
1131 | if (node->var_name) { | 1238 | if (node->var.name) { |
1132 | println("%d:e->%d:w;", node->id, node->var_name->id); | 1239 | println("%d:e->%d:w;", node->id, node->var.name->id); |
1133 | graph_node(node->var_name); | 1240 | graph_node(node->var.name); |
1134 | } | 1241 | } |
1135 | if (node->var_type) { | 1242 | if (node->var.type) { |
1136 | println("%d:e->%d:w;", node->id, node->var_type->id); | 1243 | println("%d:e->%d:w;", node->id, node->var.type->id); |
1137 | graph_node(node->var_type); | 1244 | graph_node(node->var.type); |
1138 | } | 1245 | } |
1139 | if (node->var_val) { | 1246 | if (node->var.val) { |
1140 | println("%d:e->%d:w;", node->id, node->var_val->id); | 1247 | println("%d:e->%d:w;", node->id, node->var.val->id); |
1141 | graph_node(node->var_val); | 1248 | graph_node(node->var.val); |
1142 | } | 1249 | } |
1143 | } break; | 1250 | } break; |
1144 | default: { | 1251 | default: { |
1145 | if (node->left) { | 1252 | if (node->binary.left) { |
1146 | println("%d:e->%d:w;", node->id, node->left->id); | 1253 | println("%d:e->%d:w;", node->id, node->binary.left->id); |
1147 | graph_node(node->left); | 1254 | graph_node(node->binary.left); |
1148 | } | 1255 | } |
1149 | if (node->right) { | 1256 | if (node->binary.right) { |
1150 | println("%d:e->%d:w;", node->id, node->right->id); | 1257 | println("%d:e->%d:w;", node->id, node->binary.right->id); |
1151 | graph_node(node->right); | 1258 | graph_node(node->binary.right); |
1152 | } | 1259 | } |
1153 | } break; | 1260 | } break; |
1154 | } | 1261 | } |
diff --git a/src/semantic.c b/src/semantic.c index 9b119df..7c44671 100644 --- a/src/semantic.c +++ b/src/semantic.c | |||
@@ -82,6 +82,9 @@ Scope * | |||
82 | typescope_alloc(Analyzer *a, Scope *parent) { | 82 | typescope_alloc(Analyzer *a, Scope *parent) { |
83 | Scope *scope = arena_calloc(sizeof(Scope), a->storage); | 83 | Scope *scope = arena_calloc(sizeof(Scope), a->storage); |
84 | scope->parent = parent; | 84 | scope->parent = parent; |
85 | if (parent != NULL) { | ||
86 | scope->name = parent->name; | ||
87 | } | ||
85 | scope->id = a->typescope_gen++; | 88 | scope->id = a->typescope_gen++; |
86 | scope->depth = parent == NULL ? 0 : parent->depth + 1; | 89 | scope->depth = parent == NULL ? 0 : parent->depth + 1; |
87 | array_push(a->scopes, scope, a->storage); | 90 | array_push(a->scopes, scope, a->storage); |
@@ -276,7 +279,7 @@ Str type_inference(Analyzer *a, Node *node, Scope *scope); | |||
276 | 279 | ||
277 | void | 280 | void |
278 | typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | 281 | typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { |
279 | if (node->field_type->kind == NODE_COMPOUND_TYPE) { | 282 | if (node->field.type->kind == NODE_COMPOUND_TYPE) { |
280 | Str field_name = str_concat(symbol, cstr("."), a->storage); | 283 | Str field_name = str_concat(symbol, cstr("."), a->storage); |
281 | field_name = str_concat(field_name, node->value.str, a->storage); | 284 | field_name = str_concat(field_name, node->value.str, a->storage); |
282 | if (structmap_lookup(&scope->structs, field_name)) { | 285 | if (structmap_lookup(&scope->structs, field_name)) { |
@@ -285,8 +288,8 @@ typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | |||
285 | a->err = true; | 288 | a->err = true; |
286 | } | 289 | } |
287 | Str type = cstr("\\{ "); | 290 | Str type = cstr("\\{ "); |
288 | for (sz i = 0; i < array_size(node->field_type->elements); i++) { | 291 | for (sz i = 0; i < array_size(node->field.type->elements); i++) { |
289 | Node *field = node->field_type->elements[i]; | 292 | Node *field = node->field.type->elements[i]; |
290 | typecheck_field(a, field, scope, field_name); | 293 | typecheck_field(a, field, scope, field_name); |
291 | type = str_concat(type, field->type, a->storage); | 294 | type = str_concat(type, field->type, a->storage); |
292 | type = str_concat(type, cstr(" "), a->storage); | 295 | type = str_concat(type, cstr(" "), a->storage); |
@@ -296,16 +299,16 @@ typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | |||
296 | } else { | 299 | } else { |
297 | Str field_name = str_concat(symbol, cstr("."), a->storage); | 300 | Str field_name = str_concat(symbol, cstr("."), a->storage); |
298 | field_name = str_concat(field_name, node->value.str, a->storage); | 301 | field_name = str_concat(field_name, node->value.str, a->storage); |
299 | Str field_type = node->field_type->value.str; | 302 | Str field_type = node->field.type->value.str; |
300 | if (!find_type(scope, field_type)) { | 303 | if (!find_type(scope, field_type)) { |
301 | eprintln("%s:%d:%d: error: unknown type '%s'", a->file_name, | 304 | eprintln("%s:%d:%d: error: unknown type '%s'", a->file_name, |
302 | node->field_type->line, node->field_type->col, field_type); | 305 | node->field.type->line, node->field.type->col, field_type); |
303 | a->err = true; | 306 | a->err = true; |
304 | } | 307 | } |
305 | if (node->field_type->is_ptr) { | 308 | if (node->field.type->is_ptr) { |
306 | field_type = str_concat(cstr("@"), field_type, a->storage); | 309 | field_type = str_concat(cstr("@"), field_type, a->storage); |
307 | } | 310 | } |
308 | if (node->field_type->kind == NODE_ARR_TYPE) { | 311 | if (node->field.type->kind == NODE_ARR_TYPE) { |
309 | field_type = str_concat(cstr("@"), field_type, a->storage); | 312 | field_type = str_concat(cstr("@"), field_type, a->storage); |
310 | } | 313 | } |
311 | if (structmap_lookup(&scope->structs, field_name)) { | 314 | if (structmap_lookup(&scope->structs, field_name)) { |
@@ -313,8 +316,8 @@ typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | |||
313 | a->file_name, node->line, node->col, field_name); | 316 | a->file_name, node->line, node->col, field_name); |
314 | a->err = true; | 317 | a->err = true; |
315 | } | 318 | } |
316 | if (node->field_val) { | 319 | if (node->field.val) { |
317 | Str type = type_inference(a, node->field_val, scope); | 320 | Str type = type_inference(a, node->field.val, scope); |
318 | if (!str_eq(type, field_type)) { | 321 | if (!str_eq(type, field_type)) { |
319 | eprintln( | 322 | eprintln( |
320 | "%s:%d:%d: error: mismatched types in struct " | 323 | "%s:%d:%d: error: mismatched types in struct " |
@@ -329,7 +332,7 @@ typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | |||
329 | (Struct){ | 332 | (Struct){ |
330 | .name = field_name, | 333 | .name = field_name, |
331 | .type = field_type, | 334 | .type = field_type, |
332 | .val = node->field_val, | 335 | .val = node->field.val, |
333 | }, | 336 | }, |
334 | a->storage); | 337 | a->storage); |
335 | symmap_insert(&scope->symbols, field_name, | 338 | symmap_insert(&scope->symbols, field_name, |
@@ -341,10 +344,10 @@ typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | |||
341 | 344 | ||
342 | void | 345 | void |
343 | typecheck_lit_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | 346 | typecheck_lit_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { |
344 | if (node->field_val->kind == NODE_COMPOUND_TYPE) { | 347 | if (node->field.val->kind == NODE_COMPOUND_TYPE) { |
345 | Str type = cstr("\\{ "); | 348 | Str type = cstr("\\{ "); |
346 | for (sz i = 0; i < array_size(node->field_val->elements); i++) { | 349 | for (sz i = 0; i < array_size(node->field.val->elements); i++) { |
347 | Node *field = node->field_val->elements[i]; | 350 | Node *field = node->field.val->elements[i]; |
348 | Str field_name = str_concat(symbol, cstr("."), a->storage); | 351 | Str field_name = str_concat(symbol, cstr("."), a->storage); |
349 | field_name = str_concat(field_name, field->value.str, a->storage); | 352 | field_name = str_concat(field_name, field->value.str, a->storage); |
350 | typecheck_lit_field(a, field, scope, field_name); | 353 | typecheck_lit_field(a, field, scope, field_name); |
@@ -362,7 +365,7 @@ typecheck_lit_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | |||
362 | return; | 365 | return; |
363 | } | 366 | } |
364 | Str field_type = s->val.type; | 367 | Str field_type = s->val.type; |
365 | Str type = type_inference(a, node->field_val, scope); | 368 | Str type = type_inference(a, node->field.val, scope); |
366 | if (!str_eq(type, field_type)) { | 369 | if (!str_eq(type, field_type)) { |
367 | eprintln( | 370 | eprintln( |
368 | "%s:%d:%d: error: mismatched types in struct " | 371 | "%s:%d:%d: error: mismatched types in struct " |
@@ -384,17 +387,18 @@ typecheck_returns(Analyzer *a, Node *node, Str expected) { | |||
384 | switch (node->kind) { | 387 | switch (node->kind) { |
385 | case NODE_COND: | 388 | case NODE_COND: |
386 | case NODE_MATCH: { | 389 | case NODE_MATCH: { |
387 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 390 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
388 | Node *next = node->match_cases[i]; | 391 | Node *next = node->match.cases[i]; |
389 | typecheck_returns(a, next, expected); | 392 | typecheck_returns(a, next, expected); |
390 | } | 393 | } |
391 | } break; | 394 | } break; |
392 | case NODE_RETURN: { | 395 | case NODE_RETURN: { |
393 | bool err = !str_eq(node->type, expected); | 396 | Str type = str_remove_prefix(node->type, cstr("ret:")); |
397 | bool err = !str_eq(type, expected); | ||
394 | if (err) { | 398 | if (err) { |
395 | eprintln( | 399 | eprintln( |
396 | "%s:%d:%d: error: mismatched return type %s, expected %s", | 400 | "%s:%d:%d: error: mismatched return type %s, expected %s", |
397 | a->file_name, node->line, node->col, node->type, expected); | 401 | a->file_name, node->line, node->col, type, expected); |
398 | a->err = true; | 402 | a->err = true; |
399 | } | 403 | } |
400 | } break; | 404 | } break; |
@@ -405,17 +409,17 @@ typecheck_returns(Analyzer *a, Node *node, Str expected) { | |||
405 | } | 409 | } |
406 | } break; | 410 | } break; |
407 | case NODE_IF: { | 411 | case NODE_IF: { |
408 | if (node->cond_expr) { | 412 | if (node->ifelse.expr_true) { |
409 | typecheck_returns(a, node->cond_expr, expected); | 413 | typecheck_returns(a, node->ifelse.expr_true, expected); |
410 | } | 414 | } |
411 | if (node->cond_else) { | 415 | if (node->ifelse.expr_else) { |
412 | typecheck_returns(a, node->cond_else, expected); | 416 | typecheck_returns(a, node->ifelse.expr_else, expected); |
413 | } | 417 | } |
414 | } break; | 418 | } break; |
415 | case NODE_SET: | 419 | case NODE_SET: |
416 | case NODE_LET: { | 420 | case NODE_LET: { |
417 | if (node->var_val) { | 421 | if (node->var.val) { |
418 | typecheck_returns(a, node->var_val, expected); | 422 | typecheck_returns(a, node->var.val, expected); |
419 | } | 423 | } |
420 | } break; | 424 | } break; |
421 | case NODE_ADD: | 425 | case NODE_ADD: |
@@ -435,13 +439,14 @@ typecheck_returns(Analyzer *a, Node *node, Str expected) { | |||
435 | case NODE_BITNOT: | 439 | case NODE_BITNOT: |
436 | case NODE_BITAND: | 440 | case NODE_BITAND: |
437 | case NODE_BITOR: | 441 | case NODE_BITOR: |
442 | case NODE_BITXOR: | ||
438 | case NODE_BITLSHIFT: | 443 | case NODE_BITLSHIFT: |
439 | case NODE_BITRSHIFT: { | 444 | case NODE_BITRSHIFT: { |
440 | if (node->left) { | 445 | if (node->binary.left) { |
441 | typecheck_returns(a, node->left, expected); | 446 | typecheck_returns(a, node->binary.left, expected); |
442 | } | 447 | } |
443 | if (node->right) { | 448 | if (node->binary.right) { |
444 | typecheck_returns(a, node->right, expected); | 449 | typecheck_returns(a, node->binary.right, expected); |
445 | } | 450 | } |
446 | } break; | 451 | } break; |
447 | default: break; | 452 | default: break; |
@@ -452,66 +457,79 @@ Str | |||
452 | type_inference(Analyzer *a, Node *node, Scope *scope) { | 457 | type_inference(Analyzer *a, Node *node, Scope *scope) { |
453 | assert(a); | 458 | assert(a); |
454 | assert(scope); | 459 | assert(scope); |
455 | if (!node) { | 460 | if (!node || a->err) { |
456 | return cstr(""); | 461 | return cstr(""); |
457 | } | 462 | } |
458 | // NOTE: For now we are not going to do implicit numeric conversions. | 463 | // NOTE: For now we are not going to do implicit numeric conversions. |
459 | switch (node->kind) { | 464 | switch (node->kind) { |
460 | case NODE_LET: { | 465 | case NODE_LET: { |
461 | node->type = cstr("nil"); | 466 | node->type = cstr("nil"); |
462 | Str symbol = node->var_name->value.str; | 467 | node->var.name->parent = node; |
468 | Str symbol = node->var.name->value.str; | ||
463 | if (symmap_lookup(&scope->symbols, symbol)) { | 469 | if (symmap_lookup(&scope->symbols, symbol)) { |
464 | eprintln( | 470 | eprintln( |
465 | "%s:%d:%d: error: symbol '%s' already exists in current " | 471 | "%s:%d:%d: error: symbol '%s' already exists in current " |
466 | "scope ", | 472 | "scope ", |
467 | a->file_name, node->var_name->line, node->var_name->col, | 473 | a->file_name, node->var.name->line, node->var.name->col, |
468 | symbol); | 474 | symbol); |
469 | a->err = true; | 475 | a->err = true; |
470 | return cstr(""); | 476 | return cstr(""); |
471 | } | 477 | } |
472 | if (node->var_type) { | 478 | if (node->var.type) { |
473 | Str type_name = node->var_type->value.str; | 479 | node->var.type->parent = node; |
480 | Str type_name = node->var.type->value.str; | ||
474 | SymbolMap *type = find_type(scope, type_name); | 481 | SymbolMap *type = find_type(scope, type_name); |
475 | if (type == NULL) { | 482 | if (type == NULL) { |
476 | eprintln("%s:%d:%d: error: unknown type '%s'", a->file_name, | 483 | eprintln("%s:%d:%d: error: unknown type '%s'", a->file_name, |
477 | node->var_type->line, node->var_type->col, | 484 | node->var.type->line, node->var.type->col, |
478 | type_name); | 485 | type_name); |
479 | a->err = true; | 486 | a->err = true; |
480 | return cstr(""); | 487 | return cstr(""); |
481 | } | 488 | } |
482 | if (node->var_type->is_ptr) { | 489 | if (node->var.type->is_ptr) { |
483 | type_name = str_concat(cstr("@"), type_name, a->storage); | 490 | type_name = str_concat(cstr("@"), type_name, a->storage); |
484 | } | 491 | } |
485 | if (node->var_type->kind == NODE_ARR_TYPE) { | 492 | if (node->var.type->kind == NODE_ARR_TYPE) { |
486 | type_name = str_concat(cstr("@"), type_name, a->storage); | 493 | type_name = str_concat(cstr("@"), type_name, a->storage); |
487 | // TODO: typecheck size | 494 | if (node->var.type->sym.arr_size->value.i == 0) { |
495 | eprintln("%s:%d:%d: error: zero sized array '%s'", | ||
496 | a->file_name, node->var.type->line, | ||
497 | node->var.type->col, symbol); | ||
498 | a->err = true; | ||
499 | return cstr(""); | ||
500 | } | ||
488 | // TODO: register array in scope | 501 | // TODO: register array in scope |
489 | } | 502 | } |
490 | if (node->var_val) { | 503 | if (node->var.val) { |
491 | Str type = type_inference(a, node->var_val, scope); | 504 | node->var.val->parent = node; |
505 | Str type = type_inference(a, node->var.val, scope); | ||
492 | if (!type.size) { | 506 | if (!type.size) { |
493 | eprintln( | 507 | eprintln( |
494 | "%s:%d:%d: error: can't bind `nil` to variable " | 508 | "%s:%d:%d: error: can't bind `nil` to variable " |
495 | "'%s'", | 509 | "'%s'", |
496 | a->file_name, node->var_type->line, | 510 | a->file_name, node->var.type->line, |
497 | node->var_type->col, symbol); | 511 | node->var.type->col, symbol); |
498 | a->err = true; | 512 | a->err = true; |
499 | return cstr(""); | 513 | return cstr(""); |
500 | } | 514 | } |
501 | // TODO: Consider compatible types. | ||
502 | if (!str_eq(type, type_name)) { | 515 | if (!str_eq(type, type_name)) { |
503 | // Special case, enums can be treated as ints. | 516 | if (!(strset_lookup(&a->integer_types, type) && |
504 | FindEnumResult res = find_enum(scope, type_name); | 517 | strset_lookup(&a->integer_types, type_name)) && |
505 | if (!(res.map && str_eq(type, cstr("int")))) { | 518 | !(strset_lookup(&a->numeric_types, type) && |
506 | eprintln( | 519 | strset_lookup(&a->numeric_types, type_name))) { |
507 | "%s:%d:%d: error: type mismatch, trying to " | 520 | // Special case, enums can be treated as ints. |
508 | "assing " | 521 | FindEnumResult res = find_enum(scope, type_name); |
509 | "%s" | 522 | if (!(res.map && str_eq(type, cstr("int")))) { |
510 | " to a variable of type %s", | 523 | eprintln( |
511 | a->file_name, node->var_type->line, | 524 | "%s:%d:%d: error: type mismatch, trying to " |
512 | node->var_type->col, type, type_name); | 525 | "assing " |
513 | a->err = true; | 526 | "%s" |
514 | return cstr(""); | 527 | " to a variable of type %s", |
528 | a->file_name, node->var.type->line, | ||
529 | node->var.type->col, type, type_name); | ||
530 | a->err = true; | ||
531 | return cstr(""); | ||
532 | } | ||
515 | } | 533 | } |
516 | } | 534 | } |
517 | } | 535 | } |
@@ -521,17 +539,29 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
521 | .kind = SYM_VAR, | 539 | .kind = SYM_VAR, |
522 | }, | 540 | }, |
523 | a->storage); | 541 | a->storage); |
542 | node->var.name->type = type_name; | ||
543 | symbol = str_concat(cstr("."), symbol, a->storage); | ||
544 | symbol = str_concat(symbol, str_from_int(scope->id, a->storage), | ||
545 | a->storage); | ||
546 | node->unique_name = symbol; | ||
524 | return node->type; | 547 | return node->type; |
525 | } | 548 | } |
526 | 549 | ||
527 | // We don't know the type for this symbol, perform inference. | 550 | // We don't know the type for this symbol, perform inference. |
528 | Str type = type_inference(a, node->var_val, scope); | 551 | node->var.val->parent = node; |
529 | if (type.size) { | 552 | Str type = type_inference(a, node->var.val, scope); |
530 | symmap_insert(&scope->symbols, symbol, | 553 | if (!type.size || str_eq(type, cstr("nil")) || |
531 | (Symbol){.name = type, .kind = SYM_VAR}, | 554 | str_has_prefix(type, cstr("ret:"))) { |
532 | a->storage); | 555 | eprintln( |
533 | node->var_name->type = type; | 556 | "%s:%d:%d: error: can't bind `nil` to variable " |
557 | "'%s'", | ||
558 | a->file_name, node->line, node->col, symbol); | ||
559 | a->err = true; | ||
560 | return cstr(""); | ||
534 | } | 561 | } |
562 | symmap_insert(&scope->symbols, symbol, | ||
563 | (Symbol){.name = type, .kind = SYM_VAR}, a->storage); | ||
564 | node->var.name->type = type; | ||
535 | symbol = str_concat(cstr("."), symbol, a->storage); | 565 | symbol = str_concat(cstr("."), symbol, a->storage); |
536 | symbol = str_concat(symbol, str_from_int(scope->id, a->storage), | 566 | symbol = str_concat(symbol, str_from_int(scope->id, a->storage), |
537 | a->storage); | 567 | a->storage); |
@@ -539,8 +569,10 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
539 | return node->type; | 569 | return node->type; |
540 | } break; | 570 | } break; |
541 | case NODE_SET: { | 571 | case NODE_SET: { |
542 | Str name = type_inference(a, node->var_name, scope); | 572 | node->var.name->parent = node; |
543 | Str val = type_inference(a, node->var_val, scope); | 573 | node->var.val->parent = node; |
574 | Str name = type_inference(a, node->var.name, scope); | ||
575 | Str val = type_inference(a, node->var.val, scope); | ||
544 | if (!str_eq(name, val)) { | 576 | if (!str_eq(name, val)) { |
545 | eprintln( | 577 | eprintln( |
546 | "%s:%d:%d: error: type mismatch, trying to assing " | 578 | "%s:%d:%d: error: type mismatch, trying to assing " |
@@ -550,7 +582,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
550 | a->err = true; | 582 | a->err = true; |
551 | return cstr(""); | 583 | return cstr(""); |
552 | } | 584 | } |
553 | Str symbol = node->var_name->value.str; | 585 | Str symbol = node->var.name->value.str; |
554 | FindSymbolResult sym = find_symbol(scope, symbol); | 586 | FindSymbolResult sym = find_symbol(scope, symbol); |
555 | node->unique_name = str_concat(cstr("."), symbol, a->storage); | 587 | node->unique_name = str_concat(cstr("."), symbol, a->storage); |
556 | node->unique_name = | 588 | node->unique_name = |
@@ -574,6 +606,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
574 | a->storage); | 606 | a->storage); |
575 | for (sz i = 0; i < array_size(node->struct_field); i++) { | 607 | for (sz i = 0; i < array_size(node->struct_field); i++) { |
576 | Node *field = node->struct_field[i]; | 608 | Node *field = node->struct_field[i]; |
609 | field->parent = node; | ||
577 | typecheck_field(a, field, scope, symbol); | 610 | typecheck_field(a, field, scope, symbol); |
578 | } | 611 | } |
579 | symmap_insert(&scope->symbols, symbol, | 612 | symmap_insert(&scope->symbols, symbol, |
@@ -595,11 +628,12 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
595 | enummap_insert(&scope->enums, symbol, | 628 | enummap_insert(&scope->enums, symbol, |
596 | (Enum){ | 629 | (Enum){ |
597 | .name = symbol, | 630 | .name = symbol, |
598 | .val = node->field_val, | 631 | .val = node->field.val, |
599 | }, | 632 | }, |
600 | a->storage); | 633 | a->storage); |
601 | for (sz i = 0; i < array_size(node->struct_field); i++) { | 634 | for (sz i = 0; i < array_size(node->struct_field); i++) { |
602 | Node *field = node->struct_field[i]; | 635 | Node *field = node->struct_field[i]; |
636 | field->parent = node; | ||
603 | Str field_name = str_concat(symbol, cstr("."), a->storage); | 637 | Str field_name = str_concat(symbol, cstr("."), a->storage); |
604 | field_name = | 638 | field_name = |
605 | str_concat(field_name, field->value.str, a->storage); | 639 | str_concat(field_name, field->value.str, a->storage); |
@@ -608,8 +642,8 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
608 | a->file_name, field->line, field->col, field_name); | 642 | a->file_name, field->line, field->col, field_name); |
609 | a->err = true; | 643 | a->err = true; |
610 | } | 644 | } |
611 | if (field->field_val) { | 645 | if (field->field.val) { |
612 | Str type = type_inference(a, field->field_val, scope); | 646 | Str type = type_inference(a, field->field.val, scope); |
613 | if (!str_eq(type, cstr("int"))) { | 647 | if (!str_eq(type, cstr("int"))) { |
614 | eprintln( | 648 | eprintln( |
615 | "%s:%d:%d: error: non int enum value for '%s.%s'", | 649 | "%s:%d:%d: error: non int enum value for '%s.%s'", |
@@ -632,26 +666,34 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
632 | return node->type; | 666 | return node->type; |
633 | } break; | 667 | } break; |
634 | case NODE_IF: { | 668 | case NODE_IF: { |
635 | Str cond_type = type_inference(a, node->cond_if, scope); | 669 | node->ifelse.cond->parent = node; |
670 | node->ifelse.expr_true->parent = node; | ||
671 | Str cond_type = type_inference(a, node->ifelse.cond, scope); | ||
636 | if (!str_eq(cond_type, cstr("bool"))) { | 672 | if (!str_eq(cond_type, cstr("bool"))) { |
637 | emit_semantic_error( | 673 | emit_semantic_error( |
638 | a, node->cond_if, | 674 | a, node->ifelse.cond, |
639 | cstr("non boolean expression on if condition")); | 675 | cstr("non boolean expression on if condition")); |
640 | return cstr(""); | 676 | return cstr(""); |
641 | } | 677 | } |
642 | if (node->cond_expr->kind == NODE_BLOCK) { | 678 | if (node->ifelse.expr_true->kind == NODE_BLOCK) { |
643 | node->type = type_inference(a, node->cond_expr, scope); | 679 | node->type = type_inference(a, node->ifelse.expr_true, scope); |
644 | } else { | 680 | } else { |
645 | Scope *next = typescope_alloc(a, scope); | 681 | Scope *next = typescope_alloc(a, scope); |
646 | node->type = type_inference(a, node->cond_expr, next); | 682 | node->type = type_inference(a, node->ifelse.expr_true, next); |
683 | } | ||
684 | if (str_has_prefix(node->type, cstr("ret:")) || | ||
685 | str_has_prefix(node->type, cstr("flow:"))) { | ||
686 | node->type = cstr("nil"); | ||
647 | } | 687 | } |
648 | if (node->cond_else) { | 688 | if (node->ifelse.expr_else) { |
689 | node->ifelse.expr_else->parent = node; | ||
649 | Str else_type; | 690 | Str else_type; |
650 | if (node->cond_else->kind == NODE_BLOCK) { | 691 | if (node->ifelse.expr_else->kind == NODE_BLOCK) { |
651 | else_type = type_inference(a, node->cond_else, scope); | 692 | else_type = |
693 | type_inference(a, node->ifelse.expr_else, scope); | ||
652 | } else { | 694 | } else { |
653 | Scope *next = typescope_alloc(a, scope); | 695 | Scope *next = typescope_alloc(a, scope); |
654 | else_type = type_inference(a, node->cond_else, next); | 696 | else_type = type_inference(a, node->ifelse.expr_else, next); |
655 | } | 697 | } |
656 | if (!str_eq(node->type, else_type)) { | 698 | if (!str_eq(node->type, else_type)) { |
657 | emit_semantic_error( | 699 | emit_semantic_error( |
@@ -659,27 +701,41 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
659 | return cstr(""); | 701 | return cstr(""); |
660 | } | 702 | } |
661 | } | 703 | } |
704 | |||
705 | // If it returns a value, verify it contains an `else` statement. | ||
706 | if (!str_eq(node->type, cstr("nil"))) { | ||
707 | if (!node->ifelse.expr_else) { | ||
708 | emit_semantic_error( | ||
709 | a, node, | ||
710 | cstr("missing else statement in if expression")); | ||
711 | return cstr(""); | ||
712 | } | ||
713 | } | ||
662 | return node->type; | 714 | return node->type; |
663 | } break; | 715 | } break; |
664 | case NODE_WHILE: { | 716 | case NODE_WHILE: { |
665 | Str cond_type = type_inference(a, node->while_cond, scope); | 717 | node->loop.cond->parent = node; |
718 | node->loop.expr->parent = node; | ||
719 | Str cond_type = type_inference(a, node->loop.cond, scope); | ||
666 | if (!str_eq(cond_type, cstr("bool"))) { | 720 | if (!str_eq(cond_type, cstr("bool"))) { |
667 | emit_semantic_error( | 721 | emit_semantic_error( |
668 | a, node->cond_if, | 722 | a, node->loop.cond, |
669 | cstr("non boolean expression on while condition")); | 723 | cstr("non boolean expression on while condition")); |
670 | return cstr(""); | 724 | return cstr(""); |
671 | } | 725 | } |
672 | if (node->while_expr->kind != NODE_BLOCK) { | 726 | if (node->loop.expr->kind != NODE_BLOCK) { |
673 | scope = typescope_alloc(a, scope); | 727 | scope = typescope_alloc(a, scope); |
674 | } | 728 | } |
675 | type_inference(a, node->while_expr, scope); | 729 | type_inference(a, node->loop.expr, scope); |
676 | node->type = cstr("nil"); | 730 | node->type = cstr("nil"); |
677 | return node->type; | 731 | return node->type; |
678 | } break; | 732 | } break; |
679 | case NODE_COND: { | 733 | case NODE_COND: { |
680 | Str previous = cstr(""); | 734 | Str previous = cstr(""); |
681 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 735 | bool has_else = false; |
682 | Node *expr = node->match_cases[i]; | 736 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
737 | Node *expr = node->match.cases[i]; | ||
738 | expr->parent = node; | ||
683 | Str next = type_inference(a, expr, scope); | 739 | Str next = type_inference(a, expr, scope); |
684 | if (i != 0 && !str_eq(next, previous)) { | 740 | if (i != 0 && !str_eq(next, previous)) { |
685 | emit_semantic_error( | 741 | emit_semantic_error( |
@@ -687,22 +743,38 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
687 | cstr("non-matching types for cond expressions")); | 743 | cstr("non-matching types for cond expressions")); |
688 | return cstr(""); | 744 | return cstr(""); |
689 | } | 745 | } |
746 | if (!expr->case_entry.cond) { | ||
747 | has_else = true; | ||
748 | } | ||
690 | previous = next; | 749 | previous = next; |
691 | } | 750 | } |
751 | // If it returns a value, verify it contains an `else` statement. | ||
752 | if (!str_eq(node->type, cstr("nil")) && | ||
753 | !str_has_prefix(node->type, cstr("ret:")) && | ||
754 | !str_has_prefix(node->type, cstr("flow:"))) { | ||
755 | if (!has_else) { | ||
756 | emit_semantic_error( | ||
757 | a, node, | ||
758 | cstr("missing else statement in cond expression")); | ||
759 | return cstr(""); | ||
760 | } | ||
761 | } | ||
692 | node->type = previous; | 762 | node->type = previous; |
693 | return node->type; | 763 | return node->type; |
694 | } break; | 764 | } break; |
695 | case NODE_MATCH: { | 765 | case NODE_MATCH: { |
696 | Str e = type_inference(a, node->match_expr, scope); | 766 | node->match.expr->parent = node; |
767 | Str e = type_inference(a, node->match.expr, scope); | ||
697 | if (str_eq(e, cstr("int"))) { | 768 | if (str_eq(e, cstr("int"))) { |
698 | // Integer matching. | 769 | // Integer matching. |
699 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 770 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
700 | Node *field = node->match_cases[i]; | 771 | Node *field = node->match.cases[i]; |
701 | if (field->case_value) { | 772 | field->parent = node; |
702 | if (field->case_value->kind != NODE_NUM_INT && | 773 | if (field->case_entry.cond) { |
703 | field->case_value->kind != NODE_NUM_UINT) { | 774 | if (field->case_entry.cond->kind != NODE_NUM_INT && |
775 | field->case_entry.cond->kind != NODE_NUM_UINT) { | ||
704 | emit_semantic_error( | 776 | emit_semantic_error( |
705 | a, field->case_value, | 777 | a, field->case_entry.cond, |
706 | cstr( | 778 | cstr( |
707 | "non-integer or enum types on match case")); | 779 | "non-integer or enum types on match case")); |
708 | } | 780 | } |
@@ -713,24 +785,26 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
713 | FindEnumResult res = find_enum(scope, e); | 785 | FindEnumResult res = find_enum(scope, e); |
714 | Str enum_prefix = | 786 | Str enum_prefix = |
715 | str_concat(res.map->val.name, cstr("."), a->storage); | 787 | str_concat(res.map->val.name, cstr("."), a->storage); |
716 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 788 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
717 | Node *field = node->match_cases[i]; | 789 | Node *field = node->match.cases[i]; |
718 | if (field->case_value) { | 790 | field->parent = node; |
791 | if (field->case_entry.cond) { | ||
719 | Str field_name = str_concat( | 792 | Str field_name = str_concat( |
720 | enum_prefix, field->case_value->value.str, | 793 | enum_prefix, field->case_entry.cond->value.str, |
721 | a->storage); | 794 | a->storage); |
722 | if (!enummap_lookup(&res.scope->enums, field_name)) { | 795 | if (!enummap_lookup(&res.scope->enums, field_name)) { |
723 | eprintln("%s:%d:%d: error: unknown enum field '%s'", | 796 | eprintln("%s:%d:%d: error: unknown enum field '%s'", |
724 | a->file_name, field->case_value->line, | 797 | a->file_name, field->case_entry.cond->line, |
725 | field->case_value->col, field_name); | 798 | field->case_entry.cond->col, field_name); |
726 | a->err = true; | 799 | a->err = true; |
727 | } | 800 | } |
728 | } | 801 | } |
729 | } | 802 | } |
730 | } | 803 | } |
731 | Str previous = cstr(""); | 804 | Str previous = cstr(""); |
732 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 805 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
733 | Node *expr = node->match_cases[i]; | 806 | Node *expr = node->match.cases[i]; |
807 | expr->parent = node; | ||
734 | Str next = type_inference(a, expr, scope); | 808 | Str next = type_inference(a, expr, scope); |
735 | if (i != 0 && !str_eq(next, previous)) { | 809 | if (i != 0 && !str_eq(next, previous)) { |
736 | emit_semantic_error( | 810 | emit_semantic_error( |
@@ -744,24 +818,27 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
744 | return node->type; | 818 | return node->type; |
745 | } break; | 819 | } break; |
746 | case NODE_CASE_MATCH: { | 820 | case NODE_CASE_MATCH: { |
747 | if (node->case_expr->kind != NODE_BLOCK) { | 821 | if (node->case_entry.expr->kind != NODE_BLOCK) { |
748 | scope = typescope_alloc(a, scope); | 822 | scope = typescope_alloc(a, scope); |
749 | } | 823 | } |
750 | node->type = type_inference(a, node->case_expr, scope); | 824 | node->case_entry.expr->parent = node; |
825 | node->type = type_inference(a, node->case_entry.expr, scope); | ||
751 | return node->type; | 826 | return node->type; |
752 | } break; | 827 | } break; |
753 | case NODE_CASE_COND: { | 828 | case NODE_CASE_COND: { |
754 | if (node->case_value) { | 829 | node->case_entry.expr->parent = node; |
755 | Str cond = type_inference(a, node->case_value, scope); | 830 | if (node->case_entry.cond) { |
831 | node->case_entry.cond->parent = node; | ||
832 | Str cond = type_inference(a, node->case_entry.cond, scope); | ||
756 | if (!str_eq(cond, cstr("bool"))) { | 833 | if (!str_eq(cond, cstr("bool"))) { |
757 | emit_semantic_error(a, node, | 834 | emit_semantic_error(a, node, |
758 | cstr("non-boolean case condition")); | 835 | cstr("non-boolean case condition")); |
759 | } | 836 | } |
760 | } | 837 | } |
761 | if (node->case_expr->kind != NODE_BLOCK) { | 838 | if (node->case_entry.expr->kind != NODE_BLOCK) { |
762 | scope = typescope_alloc(a, scope); | 839 | scope = typescope_alloc(a, scope); |
763 | } | 840 | } |
764 | node->type = type_inference(a, node->case_expr, scope); | 841 | node->type = type_inference(a, node->case_entry.expr, scope); |
765 | return node->type; | 842 | return node->type; |
766 | } break; | 843 | } break; |
767 | case NODE_TRUE: | 844 | case NODE_TRUE: |
@@ -776,14 +853,16 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
776 | case NODE_NOT: | 853 | case NODE_NOT: |
777 | case NODE_AND: | 854 | case NODE_AND: |
778 | case NODE_OR: { | 855 | case NODE_OR: { |
779 | Str left = type_inference(a, node->left, scope); | 856 | node->binary.left->parent = node; |
857 | Str left = type_inference(a, node->binary.left, scope); | ||
780 | if (!str_eq(left, cstr("bool"))) { | 858 | if (!str_eq(left, cstr("bool"))) { |
781 | emit_semantic_error(a, node, | 859 | emit_semantic_error(a, node, |
782 | cstr("expected bool on logic expression")); | 860 | cstr("expected bool on logic expression")); |
783 | return cstr(""); | 861 | return cstr(""); |
784 | } | 862 | } |
785 | if (node->right) { | 863 | if (node->binary.right) { |
786 | Str right = type_inference(a, node->right, scope); | 864 | node->binary.right->parent = node; |
865 | Str right = type_inference(a, node->binary.right, scope); | ||
787 | if (!str_eq(right, cstr("bool"))) { | 866 | if (!str_eq(right, cstr("bool"))) { |
788 | emit_semantic_error( | 867 | emit_semantic_error( |
789 | a, node, cstr("expected bool on logic expression")); | 868 | a, node, cstr("expected bool on logic expression")); |
@@ -799,8 +878,10 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
799 | case NODE_GT: | 878 | case NODE_GT: |
800 | case NODE_LE: | 879 | case NODE_LE: |
801 | case NODE_GE: { | 880 | case NODE_GE: { |
802 | Str left = type_inference(a, node->left, scope); | 881 | node->binary.left->parent = node; |
803 | Str right = type_inference(a, node->right, scope); | 882 | node->binary.right->parent = node; |
883 | Str left = type_inference(a, node->binary.left, scope); | ||
884 | Str right = type_inference(a, node->binary.right, scope); | ||
804 | if (!str_eq(left, right)) { | 885 | if (!str_eq(left, right)) { |
805 | emit_semantic_error( | 886 | emit_semantic_error( |
806 | a, node, cstr("mismatched types on binary expression")); | 887 | a, node, cstr("mismatched types on binary expression")); |
@@ -810,7 +891,8 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
810 | return node->type; | 891 | return node->type; |
811 | } break; | 892 | } break; |
812 | case NODE_BITNOT: { | 893 | case NODE_BITNOT: { |
813 | Str left = type_inference(a, node->left, scope); | 894 | node->binary.left->parent = node; |
895 | Str left = type_inference(a, node->binary.left, scope); | ||
814 | if (!strset_lookup(&a->integer_types, left)) { | 896 | if (!strset_lookup(&a->integer_types, left)) { |
815 | emit_semantic_error( | 897 | emit_semantic_error( |
816 | a, node, cstr("non integer type on bit twiddling expr")); | 898 | a, node, cstr("non integer type on bit twiddling expr")); |
@@ -821,10 +903,13 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
821 | } break; | 903 | } break; |
822 | case NODE_BITAND: | 904 | case NODE_BITAND: |
823 | case NODE_BITOR: | 905 | case NODE_BITOR: |
906 | case NODE_BITXOR: | ||
824 | case NODE_BITLSHIFT: | 907 | case NODE_BITLSHIFT: |
825 | case NODE_BITRSHIFT: { | 908 | case NODE_BITRSHIFT: { |
826 | Str left = type_inference(a, node->left, scope); | 909 | node->binary.left->parent = node; |
827 | Str right = type_inference(a, node->right, scope); | 910 | node->binary.right->parent = node; |
911 | Str left = type_inference(a, node->binary.left, scope); | ||
912 | Str right = type_inference(a, node->binary.right, scope); | ||
828 | if (!strset_lookup(&a->integer_types, left) || | 913 | if (!strset_lookup(&a->integer_types, left) || |
829 | !strset_lookup(&a->integer_types, right)) { | 914 | !strset_lookup(&a->integer_types, right)) { |
830 | emit_semantic_error( | 915 | emit_semantic_error( |
@@ -839,8 +924,10 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
839 | case NODE_DIV: | 924 | case NODE_DIV: |
840 | case NODE_MUL: | 925 | case NODE_MUL: |
841 | case NODE_MOD: { | 926 | case NODE_MOD: { |
842 | Str left = type_inference(a, node->left, scope); | 927 | node->binary.left->parent = node; |
843 | Str right = type_inference(a, node->right, scope); | 928 | node->binary.right->parent = node; |
929 | Str left = type_inference(a, node->binary.left, scope); | ||
930 | Str right = type_inference(a, node->binary.right, scope); | ||
844 | if (!strset_lookup(&a->numeric_types, left) || | 931 | if (!strset_lookup(&a->numeric_types, left) || |
845 | !strset_lookup(&a->numeric_types, right)) { | 932 | !strset_lookup(&a->numeric_types, right)) { |
846 | emit_semantic_error( | 933 | emit_semantic_error( |
@@ -856,7 +943,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
856 | return node->type; | 943 | return node->type; |
857 | } break; | 944 | } break; |
858 | case NODE_NUM_UINT: { | 945 | case NODE_NUM_UINT: { |
859 | node->type = cstr("uint"); | 946 | node->type = cstr("int"); |
860 | return node->type; | 947 | return node->type; |
861 | } break; | 948 | } break; |
862 | case NODE_NUM_INT: { | 949 | case NODE_NUM_INT: { |
@@ -893,6 +980,13 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
893 | } | 980 | } |
894 | 981 | ||
895 | FindSymbolResult sym = find_symbol(scope, symbol); | 982 | FindSymbolResult sym = find_symbol(scope, symbol); |
983 | if (!str_eq(sym.scope->name, scope->name) && sym.scope->name.size) { | ||
984 | eprintln( | ||
985 | "%s:%d:%d: error: can't capture external local symbol '%s'", | ||
986 | a->file_name, node->line, node->col, symbol); | ||
987 | a->err = true; | ||
988 | return cstr(""); | ||
989 | } | ||
896 | node->unique_name = str_concat(cstr("."), symbol, a->storage); | 990 | node->unique_name = str_concat(cstr("."), symbol, a->storage); |
897 | node->unique_name = | 991 | node->unique_name = |
898 | str_concat(node->unique_name, | 992 | str_concat(node->unique_name, |
@@ -900,7 +994,8 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
900 | 994 | ||
901 | Str type_name = type->val.name; | 995 | Str type_name = type->val.name; |
902 | if (node->kind == NODE_SYMBOL_IDX) { | 996 | if (node->kind == NODE_SYMBOL_IDX) { |
903 | Str idx_type = type_inference(a, node->arr_size, scope); | 997 | node->sym.arr_size->parent = node; |
998 | Str idx_type = type_inference(a, node->sym.arr_size, scope); | ||
904 | if (!strset_lookup(&a->integer_types, idx_type)) { | 999 | if (!strset_lookup(&a->integer_types, idx_type)) { |
905 | emit_semantic_error( | 1000 | emit_semantic_error( |
906 | a, node, cstr("can't resolve non integer index")); | 1001 | a, node, cstr("can't resolve non integer index")); |
@@ -914,7 +1009,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
914 | 1009 | ||
915 | FindEnumResult e = find_enum(scope, type_name); | 1010 | FindEnumResult e = find_enum(scope, type_name); |
916 | if (e.map && str_eq(symbol, type_name)) { | 1011 | if (e.map && str_eq(symbol, type_name)) { |
917 | if (!node->next) { | 1012 | if (!node->sym.next) { |
918 | eprintln( | 1013 | eprintln( |
919 | "%s:%d:%d: error: unspecified enum field for symbol " | 1014 | "%s:%d:%d: error: unspecified enum field for symbol " |
920 | "'%s'", | 1015 | "'%s'", |
@@ -924,20 +1019,21 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
924 | } | 1019 | } |
925 | // Check if there is a next and it matches the enum field. | 1020 | // Check if there is a next and it matches the enum field. |
926 | Str field = str_concat(type_name, cstr("."), a->storage); | 1021 | Str field = str_concat(type_name, cstr("."), a->storage); |
927 | field = str_concat(field, node->next->value.str, a->storage); | 1022 | field = |
1023 | str_concat(field, node->sym.next->value.str, a->storage); | ||
928 | if (!enummap_lookup(&e.scope->enums, field)) { | 1024 | if (!enummap_lookup(&e.scope->enums, field)) { |
929 | eprintln( | 1025 | eprintln( |
930 | "%s:%d:%d: error: unknown enum field for " | 1026 | "%s:%d:%d: error: unknown enum field for " |
931 | "'%s': %s", | 1027 | "'%s': %s", |
932 | a->file_name, node->line, node->col, symbol, | 1028 | a->file_name, node->line, node->col, symbol, |
933 | node->next->value.str); | 1029 | node->sym.next->value.str); |
934 | a->err = true; | 1030 | a->err = true; |
935 | return cstr(""); | 1031 | return cstr(""); |
936 | } | 1032 | } |
937 | 1033 | ||
938 | node->next->type = type_name; | 1034 | node->sym.next->type = type_name; |
939 | node->type = type_name; | 1035 | node->type = type_name; |
940 | return node->next->type; | 1036 | return node->sym.next->type; |
941 | } | 1037 | } |
942 | 1038 | ||
943 | FindStructResult s = find_struct(scope, type_name); | 1039 | FindStructResult s = find_struct(scope, type_name); |
@@ -950,11 +1046,11 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
950 | a->err = true; | 1046 | a->err = true; |
951 | return cstr(""); | 1047 | return cstr(""); |
952 | } else { | 1048 | } else { |
953 | if (node->next) { | 1049 | if (node->sym.next) { |
954 | Str chain = type_name; | 1050 | Str chain = type_name; |
955 | Node *next = node; | 1051 | Node *next = node; |
956 | while (next->next) { | 1052 | while (next->sym.next) { |
957 | next = next->next; | 1053 | next = next->sym.next; |
958 | chain = str_concat(chain, cstr("."), a->storage); | 1054 | chain = str_concat(chain, cstr("."), a->storage); |
959 | chain = | 1055 | chain = |
960 | str_concat(chain, next->value.str, a->storage); | 1056 | str_concat(chain, next->value.str, a->storage); |
@@ -970,8 +1066,9 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
970 | } | 1066 | } |
971 | Str field_type = field->val.type; | 1067 | Str field_type = field->val.type; |
972 | if (next->kind == NODE_SYMBOL_IDX) { | 1068 | if (next->kind == NODE_SYMBOL_IDX) { |
1069 | node->sym.arr_size->parent = node; | ||
973 | Str idx_type = | 1070 | Str idx_type = |
974 | type_inference(a, next->arr_size, scope); | 1071 | type_inference(a, next->sym.arr_size, scope); |
975 | if (!strset_lookup(&a->integer_types, idx_type)) { | 1072 | if (!strset_lookup(&a->integer_types, idx_type)) { |
976 | emit_semantic_error( | 1073 | emit_semantic_error( |
977 | a, next, | 1074 | a, next, |
@@ -1002,6 +1099,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
1002 | StrSet *set = NULL; | 1099 | StrSet *set = NULL; |
1003 | for (sz i = 0; i < array_size(node->elements); i++) { | 1100 | for (sz i = 0; i < array_size(node->elements); i++) { |
1004 | Node *next = node->elements[i]; | 1101 | Node *next = node->elements[i]; |
1102 | next->parent = node; | ||
1005 | Str field_name = str_concat(name, cstr("."), a->storage); | 1103 | Str field_name = str_concat(name, cstr("."), a->storage); |
1006 | field_name = | 1104 | field_name = |
1007 | str_concat(field_name, next->value.str, a->storage); | 1105 | str_concat(field_name, next->value.str, a->storage); |
@@ -1031,10 +1129,17 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
1031 | a->err = true; | 1129 | a->err = true; |
1032 | return cstr(""); | 1130 | return cstr(""); |
1033 | } | 1131 | } |
1132 | FindSymbolResult sym = find_symbol(scope, symbol); | ||
1133 | node->unique_name = str_concat(cstr("."), symbol, a->storage); | ||
1134 | node->unique_name = | ||
1135 | str_concat(node->unique_name, | ||
1136 | str_from_int(sym.scope->id, a->storage), a->storage); | ||
1137 | |||
1034 | // Check that actual parameters typecheck | 1138 | // Check that actual parameters typecheck |
1035 | Str args = cstr(""); | 1139 | Str args = cstr(""); |
1036 | for (sz i = 0; i < array_size(node->elements); i++) { | 1140 | for (sz i = 0; i < array_size(node->elements); i++) { |
1037 | Node *expr = node->elements[i]; | 1141 | Node *expr = node->elements[i]; |
1142 | expr->parent = node; | ||
1038 | Str type = type_inference(a, expr, scope); | 1143 | Str type = type_inference(a, expr, scope); |
1039 | args = str_concat(args, type, a->storage); | 1144 | args = str_concat(args, type, a->storage); |
1040 | if (i != array_size(node->elements) - 1) { | 1145 | if (i != array_size(node->elements) - 1) { |
@@ -1060,15 +1165,27 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
1060 | Str type; | 1165 | Str type; |
1061 | for (sz i = 0; i < array_size(node->elements); i++) { | 1166 | for (sz i = 0; i < array_size(node->elements); i++) { |
1062 | Node *expr = node->elements[i]; | 1167 | Node *expr = node->elements[i]; |
1168 | expr->parent = node; | ||
1063 | type = type_inference(a, expr, scope); | 1169 | type = type_inference(a, expr, scope); |
1170 | if (str_has_prefix(type, cstr("ret:")) || | ||
1171 | str_has_prefix(type, cstr("flow:"))) { | ||
1172 | break; | ||
1173 | } | ||
1064 | } | 1174 | } |
1065 | node->type = type; | 1175 | node->type = type; |
1066 | return node->type; | 1176 | return node->type; |
1067 | } break; | 1177 | } break; |
1068 | case NODE_RETURN: { | 1178 | case NODE_RETURN: { |
1069 | Str ret_type = cstr(""); | 1179 | if (!scope->name.size) { |
1180 | emit_semantic_error( | ||
1181 | a, node, cstr("return statement outside a function")); | ||
1182 | a->err = true; | ||
1183 | return cstr(""); | ||
1184 | } | ||
1185 | Str ret_type = cstr("ret:"); | ||
1070 | for (sz i = 0; i < array_size(node->elements); i++) { | 1186 | for (sz i = 0; i < array_size(node->elements); i++) { |
1071 | Node *expr = node->elements[i]; | 1187 | Node *expr = node->elements[i]; |
1188 | expr->parent = node; | ||
1072 | Str type = type_inference(a, expr, scope); | 1189 | Str type = type_inference(a, expr, scope); |
1073 | ret_type = str_concat(ret_type, type, a->storage); | 1190 | ret_type = str_concat(ret_type, type, a->storage); |
1074 | if (i != array_size(node->elements) - 1) { | 1191 | if (i != array_size(node->elements) - 1) { |
@@ -1081,40 +1198,68 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
1081 | node->type = ret_type; | 1198 | node->type = ret_type; |
1082 | return node->type; | 1199 | return node->type; |
1083 | } break; | 1200 | } break; |
1201 | case NODE_CONTINUE: | ||
1202 | case NODE_BREAK: { | ||
1203 | // Check if we are inside a loop. | ||
1204 | Node *parent = node->parent; | ||
1205 | bool inside_loop = false; | ||
1206 | while (parent != NULL) { | ||
1207 | if (parent->kind == NODE_WHILE) { | ||
1208 | inside_loop = true; | ||
1209 | break; | ||
1210 | } | ||
1211 | parent = parent->parent; | ||
1212 | } | ||
1213 | if (!inside_loop) { | ||
1214 | eprintln( | ||
1215 | "%s:%d:%d: error: control flow statement outside a loop", | ||
1216 | a->file_name, node->line, node->col); | ||
1217 | a->err = true; | ||
1218 | return cstr(""); | ||
1219 | } | ||
1220 | node->type = cstr("flow:"); | ||
1221 | return node->type; | ||
1222 | } break; | ||
1084 | case NODE_FUN: { | 1223 | case NODE_FUN: { |
1085 | node->type = cstr("nil"); | 1224 | node->type = cstr("nil"); |
1086 | Scope *prev_scope = scope; | 1225 | Scope *prev_scope = scope; |
1087 | scope = typescope_alloc(a, scope); | 1226 | scope = typescope_alloc(a, scope); |
1088 | Str param_type = cstr(""); | 1227 | Str param_type = cstr(""); |
1089 | for (sz i = 0; i < array_size(node->func_params); i++) { | 1228 | for (sz i = 0; i < array_size(node->func.params); i++) { |
1090 | Node *param = node->func_params[i]; | 1229 | Node *param = node->func.params[i]; |
1091 | Str symbol = param->param_name->value.str; | 1230 | param->parent = node; |
1092 | Str type = param->param_type->value.str; | 1231 | Str symbol = param->param.name->value.str; |
1093 | if (param->param_type->is_ptr) { | 1232 | Str type = param->param.type->value.str; |
1233 | if (param->param.type->is_ptr) { | ||
1094 | type = str_concat(cstr("@"), type, a->storage); | 1234 | type = str_concat(cstr("@"), type, a->storage); |
1095 | } | 1235 | } |
1096 | if (param->param_type->kind == NODE_ARR_TYPE) { | 1236 | if (param->param.type->kind == NODE_ARR_TYPE) { |
1097 | type = str_concat(cstr("@"), type, a->storage); | 1237 | type = str_concat(cstr("@"), type, a->storage); |
1098 | } | 1238 | } |
1099 | param->param_name->type = | 1239 | param->param.name->type = |
1100 | type_inference(a, param->param_type, scope); | 1240 | type_inference(a, param->param.type, scope); |
1101 | param->type = type; | 1241 | param->type = type; |
1102 | symmap_insert(&scope->symbols, symbol, | 1242 | symmap_insert(&scope->symbols, symbol, |
1103 | (Symbol){.name = type, .kind = SYM_PARAM}, | 1243 | (Symbol){.name = type, .kind = SYM_PARAM}, |
1104 | a->storage); | 1244 | a->storage); |
1105 | param_type = str_concat(param_type, type, a->storage); | 1245 | param_type = str_concat(param_type, type, a->storage); |
1106 | if (i != array_size(node->func_params) - 1) { | 1246 | if (i != array_size(node->func.params) - 1) { |
1107 | param_type = str_concat(param_type, cstr(","), a->storage); | 1247 | param_type = str_concat(param_type, cstr(","), a->storage); |
1108 | } | 1248 | } |
1249 | symbol = str_concat(cstr("."), symbol, a->storage); | ||
1250 | symbol = str_concat(symbol, str_from_int(scope->id, a->storage), | ||
1251 | a->storage); | ||
1252 | param->unique_name = symbol; | ||
1109 | } | 1253 | } |
1110 | if (!param_type.size) { | 1254 | if (!param_type.size) { |
1111 | param_type = cstr("nil"); | 1255 | param_type = cstr("nil"); |
1112 | } | 1256 | } |
1113 | node->fun_params = param_type; | 1257 | node->type_params = param_type; |
1114 | 1258 | ||
1115 | Str ret_type = cstr(""); | 1259 | Str ret_type = cstr(""); |
1116 | for (sz i = 0; i < array_size(node->func_ret); i++) { | 1260 | for (sz i = 0; i < array_size(node->func.ret); i++) { |
1117 | Node *expr = node->func_ret[i]; | 1261 | Node *expr = node->func.ret[i]; |
1262 | expr->parent = node; | ||
1118 | Str type = type_inference(a, expr, scope); | 1263 | Str type = type_inference(a, expr, scope); |
1119 | if (expr->is_ptr) { | 1264 | if (expr->is_ptr) { |
1120 | type = str_concat(cstr("@"), type, a->storage); | 1265 | type = str_concat(cstr("@"), type, a->storage); |
@@ -1123,28 +1268,28 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
1123 | type = str_concat(cstr("@"), type, a->storage); | 1268 | type = str_concat(cstr("@"), type, a->storage); |
1124 | } | 1269 | } |
1125 | ret_type = str_concat(ret_type, type, a->storage); | 1270 | ret_type = str_concat(ret_type, type, a->storage); |
1126 | if (i != array_size(node->func_ret) - 1) { | 1271 | if (i != array_size(node->func.ret) - 1) { |
1127 | ret_type = str_concat(ret_type, cstr(","), a->storage); | 1272 | ret_type = str_concat(ret_type, cstr(","), a->storage); |
1128 | } | 1273 | } |
1129 | } | 1274 | } |
1130 | if (!ret_type.size) { | 1275 | if (!ret_type.size) { |
1131 | ret_type = cstr("nil"); | 1276 | ret_type = cstr("nil"); |
1132 | } | 1277 | } |
1133 | node->fun_return = ret_type; | 1278 | node->type_returns = ret_type; |
1134 | 1279 | ||
1135 | Str symbol = node->func_name->value.str; | 1280 | Str symbol = node->func.name->value.str; |
1136 | if (prev_scope->parent != NULL) { | 1281 | if (prev_scope->parent != NULL) { |
1137 | if (symmap_lookup(&prev_scope->symbols, symbol)) { | 1282 | if (symmap_lookup(&prev_scope->symbols, symbol)) { |
1138 | eprintln( | 1283 | eprintln( |
1139 | "%s:%d:%d: error: function '%s' already defined in " | 1284 | "%s:%d:%d: error: function '%s' already defined in " |
1140 | "current " | 1285 | "current " |
1141 | "scope ", | 1286 | "scope ", |
1142 | a->file_name, node->var_name->line, node->var_name->col, | 1287 | a->file_name, node->var.name->line, node->var.name->col, |
1143 | symbol); | 1288 | symbol); |
1144 | a->err = true; | 1289 | a->err = true; |
1145 | return cstr(""); | 1290 | return cstr(""); |
1146 | } | 1291 | } |
1147 | symmap_insert(&scope->symbols, symbol, | 1292 | symmap_insert(&prev_scope->symbols, symbol, |
1148 | (Symbol){.name = symbol, .kind = SYM_FUN}, | 1293 | (Symbol){.name = symbol, .kind = SYM_FUN}, |
1149 | a->storage); | 1294 | a->storage); |
1150 | } | 1295 | } |
@@ -1154,41 +1299,50 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
1154 | .param_type = param_type, | 1299 | .param_type = param_type, |
1155 | .return_type = ret_type}, | 1300 | .return_type = ret_type}, |
1156 | a->storage); | 1301 | a->storage); |
1302 | symbol = str_concat(cstr("."), symbol, a->storage); | ||
1303 | symbol = str_concat( | ||
1304 | symbol, str_from_int(prev_scope->id, a->storage), a->storage); | ||
1305 | node->unique_name = symbol; | ||
1157 | 1306 | ||
1158 | if (node->func_body->kind == NODE_BLOCK) { | 1307 | if (node->func.body->kind == NODE_BLOCK) { |
1159 | Str type; | 1308 | Str type; |
1160 | for (sz i = 0; i < array_size(node->func_body->elements); i++) { | 1309 | for (sz i = 0; i < array_size(node->func.body->elements); i++) { |
1161 | Node *expr = node->func_body->elements[i]; | 1310 | Node *expr = node->func.body->elements[i]; |
1311 | expr->parent = node; | ||
1312 | // TODO: block early return. | ||
1162 | type = type_inference(a, expr, scope); | 1313 | type = type_inference(a, expr, scope); |
1163 | } | 1314 | } |
1164 | if (!type.size) { | 1315 | if (!type.size) { |
1165 | type = cstr("nil"); | 1316 | type = cstr("nil"); |
1166 | } | 1317 | } |
1167 | node->func_body->type = type; | 1318 | node->func.body->type = type; |
1168 | } else { | 1319 | } else { |
1169 | type_inference(a, node->func_body, scope); | 1320 | node->func.body->parent = node; |
1321 | type_inference(a, node->func.body, scope); | ||
1170 | } | 1322 | } |
1171 | 1323 | ||
1172 | // Ensure main body return matches the prototype. | 1324 | // Ensure main body return matches the prototype. |
1173 | if (!str_eq(node->func_body->type, ret_type)) { | 1325 | Str type = str_remove_prefix(node->func.body->type, cstr("ret:")); |
1326 | node->func.body->type = type; | ||
1327 | if (!str_eq(type, ret_type)) { | ||
1174 | eprintln( | 1328 | eprintln( |
1175 | "%s:%d:%d: error: mismatched return type %s, expected %s", | 1329 | "%s:%d:%d: error: mismatched return type %s, expected %s", |
1176 | a->file_name, node->line, node->col, node->func_body->type, | 1330 | a->file_name, node->line, node->col, type, ret_type); |
1177 | ret_type); | ||
1178 | a->err = true; | 1331 | a->err = true; |
1179 | } | 1332 | } |
1180 | 1333 | ||
1181 | // Ensure ALL return statements match the function prototype. | 1334 | // Ensure ALL return statements match the function prototype. |
1182 | typecheck_returns(a, node->func_body, ret_type); | 1335 | typecheck_returns(a, node->func.body, ret_type); |
1183 | 1336 | ||
1184 | // TODO: should return statements be allowed on let blocks? | 1337 | // TODO: should return statements be allowed on let blocks? |
1185 | return node->type; | 1338 | return node->type; |
1186 | } break; | 1339 | } break; |
1187 | default: { | 1340 | default: { |
1188 | emit_semantic_error(a, node, | 1341 | eprintln( |
1189 | cstr("type inference not implemented for this " | 1342 | "%s:%d:%d: error: type inference not implemented for node " |
1190 | "kind of expression")); | 1343 | "type: %s", |
1191 | println("KIND: %s", node_str[node->kind]); | 1344 | a->file_name, node->line, node->col, node_str[node->kind]); |
1345 | a->err = true; | ||
1192 | } break; | 1346 | } break; |
1193 | } | 1347 | } |
1194 | return cstr(""); | 1348 | return cstr(""); |
@@ -1249,16 +1403,59 @@ symbolic_analysis(Analyzer *a, Parser *parser) { | |||
1249 | for (sz i = 0; i < array_size(parser->nodes); i++) { | 1403 | for (sz i = 0; i < array_size(parser->nodes); i++) { |
1250 | Node *root = parser->nodes[i]; | 1404 | Node *root = parser->nodes[i]; |
1251 | if (root->kind == NODE_FUN) { | 1405 | if (root->kind == NODE_FUN) { |
1252 | Str symbol = root->func_name->value.str; | 1406 | Str symbol = root->func.name->value.str; |
1253 | if (symmap_lookup(&scope->symbols, symbol)) { | 1407 | if (symmap_lookup(&scope->symbols, symbol)) { |
1254 | eprintln( | 1408 | eprintln( |
1255 | "%s:%d:%d: error: function '%s' already defined in " | 1409 | "%s:%d:%d: error: function '%s' already defined in " |
1256 | "current " | 1410 | "current " |
1257 | "scope ", | 1411 | "scope ", |
1258 | a->file_name, root->var_name->line, root->var_name->col, | 1412 | a->file_name, root->var.name->line, root->var.name->col, |
1259 | symbol); | 1413 | symbol); |
1260 | a->err = true; | 1414 | a->err = true; |
1261 | } | 1415 | } |
1416 | Str param_type = cstr(""); | ||
1417 | for (sz i = 0; i < array_size(root->func.params); i++) { | ||
1418 | Node *param = root->func.params[i]; | ||
1419 | Str type = param->param.type->value.str; | ||
1420 | if (param->param.type->is_ptr) { | ||
1421 | type = str_concat(cstr("@"), type, a->storage); | ||
1422 | } | ||
1423 | if (param->param.type->kind == NODE_ARR_TYPE) { | ||
1424 | type = str_concat(cstr("@"), type, a->storage); | ||
1425 | } | ||
1426 | param_type = str_concat(param_type, type, a->storage); | ||
1427 | if (i != array_size(root->func.params) - 1) { | ||
1428 | param_type = str_concat(param_type, cstr(","), a->storage); | ||
1429 | } | ||
1430 | } | ||
1431 | if (!param_type.size) { | ||
1432 | param_type = cstr("nil"); | ||
1433 | } | ||
1434 | root->type_params = param_type; | ||
1435 | |||
1436 | Str ret_type = cstr(""); | ||
1437 | for (sz i = 0; i < array_size(root->func.ret); i++) { | ||
1438 | Node *expr = root->func.ret[i]; | ||
1439 | Str type = expr->value.str; | ||
1440 | if (expr->is_ptr) { | ||
1441 | type = str_concat(cstr("@"), type, a->storage); | ||
1442 | } | ||
1443 | if (expr->kind == NODE_ARR_TYPE) { | ||
1444 | type = str_concat(cstr("@"), type, a->storage); | ||
1445 | } | ||
1446 | ret_type = str_concat(ret_type, type, a->storage); | ||
1447 | if (i != array_size(root->func.ret) - 1) { | ||
1448 | ret_type = str_concat(ret_type, cstr(","), a->storage); | ||
1449 | } | ||
1450 | } | ||
1451 | if (!ret_type.size) { | ||
1452 | ret_type = cstr("nil"); | ||
1453 | } | ||
1454 | funmap_insert(&scope->funcs, symbol, | ||
1455 | (Fun){.name = symbol, | ||
1456 | .param_type = param_type, | ||
1457 | .return_type = ret_type}, | ||
1458 | a->storage); | ||
1262 | symmap_insert(&scope->symbols, symbol, | 1459 | symmap_insert(&scope->symbols, symbol, |
1263 | (Symbol){.name = symbol, .kind = SYM_FUN}, | 1460 | (Symbol){.name = symbol, .kind = SYM_FUN}, |
1264 | a->storage); | 1461 | a->storage); |
@@ -5,12 +5,15 @@ | |||
5 | #include "compiler.c" | 5 | #include "compiler.c" |
6 | 6 | ||
7 | #define N_CONST 256 | 7 | #define N_CONST 256 |
8 | #define STACK_SIZE KB(64) | 8 | #define STACK_SIZE MB(4) |
9 | typedef struct VM { | 9 | typedef struct VM { |
10 | Chunk *main; | ||
10 | Chunk *chunk; | 11 | Chunk *chunk; |
11 | Constant regs[N_CONST]; | ||
12 | u8 stack[STACK_SIZE]; | 12 | u8 stack[STACK_SIZE]; |
13 | Instruction *ip; | 13 | Instruction *ip; |
14 | u8 *sp; | ||
15 | u64 *fp; | ||
16 | Constant *regs; | ||
14 | } VM; | 17 | } VM; |
15 | 18 | ||
16 | void | 19 | void |
@@ -18,8 +21,13 @@ vm_init(VM *vm, Chunk *chunk) { | |||
18 | assert(vm); | 21 | assert(vm); |
19 | assert(chunk); | 22 | assert(chunk); |
20 | assert(chunk->code); | 23 | assert(chunk->code); |
24 | vm->main = chunk; | ||
21 | vm->chunk = chunk; | 25 | vm->chunk = chunk; |
22 | vm->ip = vm->chunk->code; | 26 | vm->ip = vm->chunk->code; |
27 | vm->fp = (u64 *)vm->stack; | ||
28 | vm->sp = vm->stack + chunk->var_off; | ||
29 | vm->regs = (Constant *)vm->sp; | ||
30 | vm->sp += sizeof(Constant) * chunk->reg_idx; | ||
23 | } | 31 | } |
24 | 32 | ||
25 | #define OP_UNARY(OP, TYPE) \ | 33 | #define OP_UNARY(OP, TYPE) \ |
@@ -77,6 +85,7 @@ vm_run(VM *vm) { | |||
77 | case OP_NOT: OP_UNARY(!, i) break; | 85 | case OP_NOT: OP_UNARY(!, i) break; |
78 | case OP_BITNOT: OP_UNARY(~, i) break; | 86 | case OP_BITNOT: OP_UNARY(~, i) break; |
79 | case OP_BITOR: OP_BINARY(|, i) break; | 87 | case OP_BITOR: OP_BINARY(|, i) break; |
88 | case OP_BITXOR: OP_BINARY(^, i) break; | ||
80 | case OP_BITAND: OP_BINARY(&, i) break; | 89 | case OP_BITAND: OP_BINARY(&, i) break; |
81 | case OP_BITLSHIFT: OP_BINARY(<<, i) break; | 90 | case OP_BITLSHIFT: OP_BINARY(<<, i) break; |
82 | case OP_BITRSHIFT: OP_BINARY(>>, i) break; | 91 | case OP_BITRSHIFT: OP_BINARY(>>, i) break; |
@@ -107,6 +116,7 @@ vm_run(VM *vm) { | |||
107 | case OP_NOTI: OP_UNARY_CONST(!, i) break; | 116 | case OP_NOTI: OP_UNARY_CONST(!, i) break; |
108 | case OP_BITNOTI: OP_UNARY_CONST(~, i) break; | 117 | case OP_BITNOTI: OP_UNARY_CONST(~, i) break; |
109 | case OP_BITORI: OP_BINARY_CONST(|, i) break; | 118 | case OP_BITORI: OP_BINARY_CONST(|, i) break; |
119 | case OP_BITXORI: OP_BINARY_CONST(^, i) break; | ||
110 | case OP_BITANDI: OP_BINARY_CONST(&, i) break; | 120 | case OP_BITANDI: OP_BINARY_CONST(&, i) break; |
111 | case OP_BITLSHIFTI: OP_BINARY_CONST(<<, i) break; | 121 | case OP_BITLSHIFTI: OP_BINARY_CONST(<<, i) break; |
112 | case OP_BITRSHIFTI: OP_BINARY_CONST(>>, i) break; | 122 | case OP_BITRSHIFTI: OP_BINARY_CONST(>>, i) break; |
@@ -134,61 +144,121 @@ vm_run(VM *vm) { | |||
134 | vm->regs[dst].f = | 144 | vm->regs[dst].f = |
135 | fmod(vm->regs[src_a].f, vm->chunk->constants[src_b].f); | 145 | fmod(vm->regs[src_a].f, vm->chunk->constants[src_b].f); |
136 | } break; | 146 | } break; |
147 | case OP_STGVAR: { | ||
148 | u8 dst = instruction.dst; | ||
149 | u8 src = instruction.a; | ||
150 | Variable var = vm->main->vars[dst]; | ||
151 | s64 *stack = (s64 *)&vm->stack[var.offset]; | ||
152 | *stack = vm->regs[src].i; | ||
153 | } break; | ||
154 | case OP_STGVARI: { | ||
155 | u8 dst = instruction.dst; | ||
156 | u8 src = instruction.a; | ||
157 | Variable var = vm->main->vars[dst]; | ||
158 | s64 *stack = (s64 *)&vm->stack[var.offset]; | ||
159 | *stack = vm->chunk->constants[src].i; | ||
160 | } break; | ||
137 | case OP_LDGVAR: { | 161 | case OP_LDGVAR: { |
138 | u8 dst = instruction.dst; | 162 | u8 dst = instruction.dst; |
139 | u8 src = instruction.a; | 163 | u8 src = instruction.a; |
140 | Variable var = vm->chunk->vars[src]; | 164 | Variable var = vm->main->vars[src]; |
141 | s64 *stack = (s64 *)&vm->stack[var.offset]; | 165 | s64 *stack = (s64 *)&vm->stack[var.offset]; |
142 | vm->regs[dst].i = *stack; | 166 | vm->regs[dst].i = *stack; |
143 | } break; | 167 | } break; |
144 | case OP_STGVAR: { | 168 | case OP_LDGADDR: { |
145 | u8 dst = instruction.dst; | 169 | u8 dst = instruction.dst; |
146 | u8 src = instruction.a; | 170 | u8 src = instruction.a; |
147 | Variable var = vm->chunk->vars[dst]; | 171 | Variable var = vm->main->vars[src]; |
148 | s64 *stack = (s64 *)&vm->stack[var.offset]; | 172 | s64 *stack = (s64 *)&vm->stack[var.offset]; |
149 | *stack = vm->regs[src].i; | 173 | vm->regs[dst].ptr = (ptrsize)stack; |
150 | } break; | 174 | } break; |
151 | case OP_STGVARI: { | 175 | case OP_STLVAR: { |
152 | u8 dst = instruction.dst; | 176 | u8 dst = instruction.dst; |
153 | u8 src = instruction.a; | 177 | u8 src = instruction.a; |
154 | Variable var = vm->chunk->vars[dst]; | 178 | Variable var = vm->chunk->vars[dst]; |
155 | s64 *stack = (s64 *)&vm->stack[var.offset]; | 179 | vm->fp[var.offset / 8] = vm->regs[src].i; |
156 | *stack = vm->chunk->constants[src].i; | ||
157 | } break; | 180 | } break; |
158 | case OP_JMPI: { | 181 | case OP_STLVARI: { |
159 | sz offset = vm->chunk->constants[instruction.dst].i; | 182 | u8 dst = instruction.dst; |
160 | vm->ip += offset - 1; | 183 | u8 src = instruction.a; |
184 | Variable var = vm->chunk->vars[dst]; | ||
185 | vm->fp[var.offset / 8] = vm->chunk->constants[src].i; | ||
186 | } break; | ||
187 | case OP_LDLVAR: { | ||
188 | u8 dst = instruction.dst; | ||
189 | u8 src = instruction.a; | ||
190 | Variable var = vm->chunk->vars[src]; | ||
191 | vm->regs[dst].i = vm->fp[var.offset / 8]; | ||
192 | } break; | ||
193 | case OP_LDLADDR: { | ||
194 | u8 dst = instruction.dst; | ||
195 | u8 src = instruction.a; | ||
196 | Variable var = vm->chunk->vars[src]; | ||
197 | vm->regs[dst].i = (ptrsize)&vm->fp[var.offset / 8]; | ||
198 | } break; | ||
199 | case OP_LDSTR: { | ||
200 | u8 dst = instruction.dst; | ||
201 | u8 src = instruction.a; | ||
202 | Str *str = &vm->chunk->strings[src]; | ||
203 | vm->regs[dst].ptr = (ptrsize)str; | ||
204 | } break; | ||
205 | case OP_ST64I: { | ||
206 | sz value = vm->regs[instruction.dst].ptr; | ||
207 | s64 *addr = (s64 *)vm->regs[instruction.a].ptr; | ||
208 | sz offset = vm->chunk->constants[instruction.b].i; | ||
209 | addr[offset] = value; | ||
210 | } break; | ||
211 | case OP_ST64: { | ||
212 | sz value = vm->regs[instruction.dst].i; | ||
213 | s64 *addr = (s64 *)vm->regs[instruction.a].ptr; | ||
214 | sz offset = vm->regs[instruction.b].i; | ||
215 | addr[offset] = value; | ||
216 | } break; | ||
217 | case OP_LD64I: { | ||
218 | s64 *addr = (s64 *)vm->regs[instruction.a].ptr; | ||
219 | sz offset = vm->chunk->constants[instruction.b].i; | ||
220 | vm->regs[instruction.dst].i = addr[offset]; | ||
221 | } break; | ||
222 | case OP_LD64: { | ||
223 | s64 *addr = (s64 *)vm->regs[instruction.a].ptr; | ||
224 | sz offset = vm->regs[instruction.b].i; | ||
225 | vm->regs[instruction.dst].i = addr[offset]; | ||
226 | } break; | ||
227 | case OP_JMP: { | ||
228 | u8 dst = instruction.dst; | ||
229 | sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val; | ||
230 | vm->ip = vm->chunk->code + pos; | ||
161 | } break; | 231 | } break; |
162 | case OP_JMPFI: { | 232 | case OP_JMPFI: { |
163 | bool cond = vm->chunk->constants[instruction.dst].i; | 233 | u8 dst = instruction.dst; |
164 | sz offset = vm->chunk->constants[instruction.a].i; | 234 | sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val; |
235 | bool cond = vm->chunk->constants[instruction.a].i; | ||
165 | if (!cond) { | 236 | if (!cond) { |
166 | vm->ip += offset - 1; | 237 | vm->ip = vm->chunk->code + pos; |
167 | } | 238 | } |
168 | } break; | 239 | } break; |
169 | case OP_JMPTI: { | 240 | case OP_JMPTI: { |
170 | bool cond = vm->chunk->constants[instruction.dst].i; | 241 | u8 dst = instruction.dst; |
171 | sz offset = vm->chunk->constants[instruction.a].i; | 242 | sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val; |
243 | bool cond = vm->chunk->constants[instruction.a].i; | ||
172 | if (cond) { | 244 | if (cond) { |
173 | vm->ip += offset - 1; | 245 | vm->ip = vm->chunk->code + pos; |
174 | } | 246 | } |
175 | } break; | 247 | } break; |
176 | case OP_JMP: { | ||
177 | sz offset = vm->chunk->constants[instruction.dst].i; | ||
178 | vm->ip += offset - 1; | ||
179 | } break; | ||
180 | case OP_JMPF: { | 248 | case OP_JMPF: { |
181 | bool cond = vm->regs[instruction.dst].i; | 249 | u8 dst = instruction.dst; |
182 | sz offset = vm->chunk->constants[instruction.a].i; | 250 | sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val; |
251 | bool cond = vm->regs[instruction.a].i; | ||
183 | if (!cond) { | 252 | if (!cond) { |
184 | vm->ip += offset - 1; | 253 | vm->ip = vm->chunk->code + pos; |
185 | } | 254 | } |
186 | } break; | 255 | } break; |
187 | case OP_JMPT: { | 256 | case OP_JMPT: { |
188 | bool cond = vm->regs[instruction.dst].i; | 257 | u8 dst = instruction.dst; |
189 | sz offset = vm->chunk->constants[instruction.a].i; | 258 | sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val; |
259 | bool cond = vm->regs[instruction.a].i; | ||
190 | if (cond) { | 260 | if (cond) { |
191 | vm->ip += offset - 1; | 261 | vm->ip = vm->chunk->code + pos; |
192 | } | 262 | } |
193 | } break; | 263 | } break; |
194 | case OP_MOV64: { | 264 | case OP_MOV64: { |
@@ -211,10 +281,140 @@ vm_run(VM *vm) { | |||
211 | u8 src = instruction.a; | 281 | u8 src = instruction.a; |
212 | vm->regs[dst].i = vm->regs[src].i & 0xFF; | 282 | vm->regs[dst].i = vm->regs[src].i & 0xFF; |
213 | } break; | 283 | } break; |
284 | case OP_PRINTS64: { | ||
285 | u8 idx = instruction.dst; | ||
286 | print("%d", vm->regs[idx].i); | ||
287 | } break; | ||
288 | case OP_PRINTS64I: { | ||
289 | u8 idx = instruction.dst; | ||
290 | print("%d", vm->chunk->constants[idx].i); | ||
291 | } break; | ||
292 | case OP_PRINTBOOL: { | ||
293 | u8 idx = instruction.dst; | ||
294 | bool val = vm->regs[idx].i; | ||
295 | if (val) { | ||
296 | print("true"); | ||
297 | } else { | ||
298 | print("false"); | ||
299 | } | ||
300 | } break; | ||
301 | case OP_PRINTBOOLI: { | ||
302 | u8 idx = instruction.dst; | ||
303 | bool val = vm->chunk->constants[idx].i; | ||
304 | if (val) { | ||
305 | print("true"); | ||
306 | } else { | ||
307 | print("false"); | ||
308 | } | ||
309 | } break; | ||
310 | case OP_PRINTF64: { | ||
311 | u8 idx = instruction.dst; | ||
312 | printf("%f", vm->regs[idx].f); | ||
313 | } break; | ||
314 | case OP_PRINTF64I: { | ||
315 | u8 idx = instruction.dst; | ||
316 | printf("%f", vm->chunk->constants[idx].f); | ||
317 | } break; | ||
318 | case OP_PRINTSTR: { | ||
319 | u8 idx = instruction.dst; | ||
320 | Str *string = (Str *)vm->regs[idx].ptr; | ||
321 | print("%s", *string); | ||
322 | } break; | ||
323 | case OP_PRINTSTRI: { | ||
324 | u8 idx = instruction.dst; | ||
325 | Str string = vm->chunk->strings[idx]; | ||
326 | print("%s", string); | ||
327 | } break; | ||
328 | case OP_RESERVE: { | ||
329 | sz offset = vm->chunk->constants[instruction.dst].i; | ||
330 | vm->sp += offset; | ||
331 | } break; | ||
332 | case OP_PUSH: { | ||
333 | sz val = vm->regs[instruction.dst].i; | ||
334 | u64 *p = (u64 *)vm->sp; | ||
335 | *p = val; | ||
336 | vm->sp += sizeof(ptrsize); | ||
337 | } break; | ||
338 | case OP_PUSHI: { | ||
339 | sz val = vm->chunk->constants[instruction.dst].i; | ||
340 | u64 *p = (u64 *)vm->sp; | ||
341 | *p = val; | ||
342 | vm->sp += sizeof(ptrsize); | ||
343 | } break; | ||
344 | case OP_POP: { | ||
345 | vm->sp -= sizeof(ptrsize); | ||
346 | u64 *p = (u64 *)vm->sp; | ||
347 | vm->regs[instruction.dst].i = *p; | ||
348 | } break; | ||
349 | case OP_PUTRET: { | ||
350 | sz val = vm->regs[instruction.dst].i; | ||
351 | vm->fp[-1] = val; | ||
352 | } break; | ||
353 | case OP_PUTRETI: { | ||
354 | sz val = vm->chunk->constants[instruction.dst].i; | ||
355 | vm->fp[-1] = val; | ||
356 | } break; | ||
357 | case OP_CALL: { | ||
358 | u8 dst = instruction.dst; | ||
359 | Chunk *func = vm->main->functions[dst]; | ||
360 | |||
361 | ptrsize chunk_addr = (ptrsize)vm->chunk; | ||
362 | ptrsize ip_addr = (ptrsize)vm->ip; | ||
363 | ptrsize reg_addr = (ptrsize)vm->regs; | ||
364 | ptrsize old_fp = (ptrsize)vm->fp; | ||
365 | |||
366 | // Allocate space for the locals. | ||
367 | memset(vm->sp, 0, func->var_off - func->param_off); | ||
368 | vm->fp = (u64 *)(vm->sp - func->param_off); | ||
369 | vm->sp += func->var_off - func->param_off; | ||
370 | vm->chunk = func; | ||
371 | vm->ip = func->code; | ||
372 | vm->regs = (Constant *)vm->sp; | ||
373 | |||
374 | // Allocate registers. | ||
375 | vm->sp += sizeof(Constant) * func->reg_idx; | ||
376 | |||
377 | // Store memory addresses we need to return to this function. | ||
378 | u64 *p = (u64 *)vm->sp; | ||
379 | p[0] = chunk_addr; | ||
380 | p[1] = ip_addr; | ||
381 | p[2] = reg_addr; | ||
382 | p[3] = old_fp; | ||
383 | vm->sp += sizeof(ptrsize) * 4; | ||
384 | } break; | ||
385 | case OP_RECUR: { | ||
386 | vm->ip = vm->chunk->code; | ||
387 | } break; | ||
388 | case OP_RET: { | ||
389 | u64 *p = (u64 *)vm->sp; | ||
390 | ptrsize chunk_addr = p[-4]; | ||
391 | ptrsize ip_addr = p[-3]; | ||
392 | ptrsize reg_addr = p[-2]; | ||
393 | ptrsize old_fp = p[-1]; | ||
394 | vm->sp -= sizeof(ptrsize) * 4; | ||
395 | |||
396 | // Deallocate registers. | ||
397 | vm->sp -= sizeof(Constant) * vm->chunk->reg_idx; | ||
398 | |||
399 | // Deallocate locals. | ||
400 | vm->sp -= vm->chunk->var_off; | ||
401 | |||
402 | // Restore previous activation record. | ||
403 | vm->regs = (Constant *)reg_addr; | ||
404 | vm->ip = (Instruction *)ip_addr; | ||
405 | vm->chunk = (Chunk *)chunk_addr; | ||
406 | vm->fp = (u64 *)old_fp; | ||
407 | } break; | ||
214 | case OP_HALT: { | 408 | case OP_HALT: { |
215 | println("VM HALT (int) -> %d", vm->regs[instruction.dst]); | 409 | println("VM halt..."); |
216 | println("VM HALT (float) -> %f", vm->regs[instruction.dst]); | 410 | if (instruction.a != 0) { |
217 | println("VM HALT (hex) -> %x", vm->regs[instruction.dst]); | 411 | println("Result:"); |
412 | Constant result = vm->regs[instruction.dst]; | ||
413 | printf("\tint -> %lld\n", result.i); | ||
414 | printf("\tfloat -> %.10e\n", result.f); | ||
415 | printf("\thex -> %llx\n", (u64)result.i); | ||
416 | println("\tbinary -> %b", result.i); | ||
417 | } | ||
218 | return; | 418 | return; |
219 | } | 419 | } |
220 | default: { | 420 | default: { |
diff --git a/tests/compilation.bad b/tests/compilation.bad index afb2be0..5c3b7b6 100644 --- a/tests/compilation.bad +++ b/tests/compilation.bad | |||
@@ -1,27 +1,42 @@ | |||
1 | ; let a = 8 | 1 | fun recur(num: int): nil { |
2 | ; let b = 16 | 2 | println("NUM: " num) |
3 | ; let c = { | 3 | if num == 0 return(nil) |
4 | ; let a = 32 | 4 | recur2(num - 1) |
5 | ; a + 8 | 5 | } |
6 | ; } | ||
7 | 6 | ||
8 | ; a + b + c | 7 | fun recur2(num: int): nil { |
8 | println("NUM: " num) | ||
9 | if num == 0 return(nil) | ||
10 | recur(num - 1) | ||
11 | } | ||
9 | 12 | ||
10 | ; if true { | 13 | recur(5) |
11 | ; 2 | ||
12 | ; } | ||
13 | 14 | ||
14 | ; if true { | 15 | fun infrecur(msg: str num: int): nil { |
15 | ; 1 + 2 | 16 | println("NUM: " msg " " num) |
16 | ; } else { | 17 | infrecur(msg num + 1) |
17 | ; 3 + 4 | 18 | } |
19 | infrecur(" -> " 8) | ||
20 | |||
21 | |||
22 | ; let varint: u16 = 0x0102030405060708 | ||
23 | ; let varfloat: f32 = 1.0 | ||
24 | |||
25 | ; fun printer(): nil println("wowo!") | ||
26 | ; let y = 4 | ||
27 | ; fun nested(): nil { | ||
28 | ; fun adder(a: int b: int): int { | ||
29 | ; fun printer(): nil println("ho!") | ||
30 | ; printer() | ||
31 | ; printer() | ||
32 | ; printer() | ||
33 | ; y + a + b | ||
34 | ; } | ||
35 | ; for let i = 0, i < 2, set i += 1 { | ||
36 | ; println("i: " i " " adder(i, 2)) | ||
37 | ; } | ||
18 | ; } | 38 | ; } |
19 | 39 | ||
20 | let a = 0 | 40 | ; nested() |
21 | if 1 != 1 { | 41 | ; printer() |
22 | set a = 1 | ||
23 | } else { | ||
24 | set a = 2 | ||
25 | } | ||
26 | 42 | ||
27 | a | ||
diff --git a/tests/conditionals.bad b/tests/conditionals.bad index aca5c36..85de62a 100644 --- a/tests/conditionals.bad +++ b/tests/conditionals.bad | |||
@@ -1,8 +1,8 @@ | |||
1 | ; Basic if expressions. | 1 | ; Basic if expressions. |
2 | if true "hello" | 2 | if true "hello" else "world" |
3 | 3 | ||
4 | ; These can produce values and the result bound to a name. | 4 | ; These can produce values and the result bound to a name. |
5 | let a = if (2 + 2 >= 4) 42 | 5 | let a = if (2 + 2 >= 4) 42 else 0 |
6 | 6 | ||
7 | ; We support a single if expression. | 7 | ; We support a single if expression. |
8 | let b = if (0xff == 0x32) "hello" else "world" | 8 | let b = if (0xff == 0x32) "hello" else "world" |
diff --git a/tests/semantics.bad b/tests/semantics.bad index acf4316..befbfab 100644 --- a/tests/semantics.bad +++ b/tests/semantics.bad | |||
@@ -42,6 +42,7 @@ match a { | |||
42 | cond { | 42 | cond { |
43 | 1 == 1 = "ha" | 43 | 1 == 1 = "ha" |
44 | 2 != 2 = "ho" | 44 | 2 != 2 = "ho" |
45 | else = "let's go" | ||
45 | } | 46 | } |
46 | 47 | ||
47 | struct vec { | 48 | struct vec { |
@@ -160,9 +161,7 @@ let maybe = if (1 == 2) { | |||
160 | 44 | 161 | 44 |
161 | } | 162 | } |
162 | 163 | ||
163 | let single = if (true) { | 164 | let single = if (true) 123 else 0 |
164 | 123 | ||
165 | } | ||
166 | 165 | ||
167 | while (!true) { | 166 | while (!true) { |
168 | println("asjdflasdjf") | 167 | println("asjdflasdjf") |
@@ -185,5 +184,5 @@ fun nested(): int { | |||
185 | let c = 32 | 184 | let c = 32 |
186 | 5 + c | 185 | 5 + c |
187 | } | 186 | } |
188 | } | 187 | } else 0 |
189 | } | 188 | } |