aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bench/fib.bad12
-rw-r--r--bench/fib.py5
-rw-r--r--bench/life.bad77
-rw-r--r--bench/rule110.bad45
-rw-r--r--bench/rule110.py29
-rw-r--r--src/badlib.h6
-rw-r--r--src/compiler.c974
-rw-r--r--src/main.c49
-rw-r--r--src/parser.c2
-rw-r--r--src/semantic.c181
-rw-r--r--src/vm.c225
-rw-r--r--tests/compilation.bad38
-rw-r--r--tests/conditionals.bad4
-rw-r--r--tests/semantics.bad7
14 files changed, 1431 insertions, 223 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 @@
1let n = 1000
2let a = 0.0
3let b = 1.0
4let i = 0
5while i < n {
6 let tmp = a + b
7 set a = b
8 set b = tmp
9 set i = i + 1
10}
11
12a
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 @@
1n = 1000
2a, b = 0.0, 1.0
3for i in range(0, n):
4 a, b = b, a + b
5print(a)
diff --git a/bench/life.bad b/bench/life.bad
new file mode 100644
index 0000000..d05038f
--- /dev/null
+++ b/bench/life.bad
@@ -0,0 +1,77 @@
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.
8let n_cells = 1024
9let board_a: int[1024]
10let board_b: int[1024]
11let stride = 32
12
13; Storing pointers to the front/backbuffer to avoid copying the board over.
14let front = board_a
15let back = board_b
16
17; Initialize glider
18set front[stride * 2 + 5] = 1
19set front[stride * 3 + 6] = 1
20set front[stride * 4 + 4] = 1
21set front[stride * 4 + 5] = 1
22set front[stride * 4 + 6] = 1
23
24fun print_board(board: @int): nil {
25 let i = 0
26 while i < n_cells {
27 if i % stride == 0 {
28 println("")
29 }
30 if board[i] == 1 print("■ ")
31 else print("· ")
32 set i = i + 1
33 }
34 println("")
35}
36
37fun update_board(): nil {
38 let i = 0
39 while i < n_cells {
40 let left = if i > 0 front[i - 1] else 0
41 let right = if i < n_cells - 1 front[i + 1] else 0
42 let top = if i >= stride front[i - stride] else 0
43 let topleft = if i >= stride front[i - stride - 1] else 0
44 let topright = if i >= stride front[i - stride + 1] else 0
45 let bot = if i <= n_cells - stride front[i + stride] else 0
46 let botleft = if i <= n_cells - stride front[i + stride - 1] else 0
47 let botright = if i <= n_cells - stride front[i + stride + 1] else 0
48
49 let neig = left
50 + right
51 + top
52 + bot
53 + topleft
54 + topright
55 + botleft
56 + botright
57
58 cond {
59 front[i] == 0 && neig == 3 = set back[i] = 1
60 front[i] == 1 && (neig == 2 || neig == 3) = set back[i] = 1
61 else = set back[i] = 0
62 }
63
64 set i = i + 1
65 }
66
67 let tmp = front
68 set front = back
69 set back = tmp
70}
71
72let n_iter = 1000
73while n_iter > 0 {
74 set n_iter = n_iter - 1
75 print_board(front)
76 update_board()
77}
diff --git a/bench/rule110.bad b/bench/rule110.bad
new file mode 100644
index 0000000..d925e18
--- /dev/null
+++ b/bench/rule110.bad
@@ -0,0 +1,45 @@
1; Parameters.
2let line = 0b00000000000000000000000000000001
3let max_iter = 30000
4
5; Print current line.
6fun print_line(line: int): nil {
7 let i = 0
8 while i < 64 {
9 let val = line >> 63 - i & 0b1
10 if val == 0b1 {
11 print("▀ ")
12 } else {
13 print(" ")
14 }
15 set i = i + 1
16 }
17 println("")
18}
19
20; Get the next line.
21fun next_line(line: int): int {
22 let next = 0
23 let j = 0
24 while j < 61 {
25 let val = line >> 60 - j & 0b111
26 set val = cond {
27 val == 1 = 1
28 val == 2 = 1
29 val == 3 = 1
30 val == 5 = 1
31 val == 6 = 1
32 else = 0
33 }
34 set next = next | val << 61 - j
35 set j = j + 1
36 }
37 next | 1
38}
39
40let iter = 0
41while iter < max_iter {
42 print_line(line)
43 set line = next_line(line)
44 set iter = iter + 1
45}
diff --git a/bench/rule110.py b/bench/rule110.py
new file mode 100644
index 0000000..a4fed06
--- /dev/null
+++ b/bench/rule110.py
@@ -0,0 +1,29 @@
1line = 0b00000000000000000000000000000001
2max_iter = 30000
3
4for 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 >> (61 - j - 1)) & 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) {
347void 347void
348str_replace(Str *a, Str from, Str to) { 348str_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
1498log_func_memory(Logger *l, void *in) { 1500log_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 5bddcb6..ee2c06b 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -25,7 +25,7 @@ typedef struct Instruction {
25typedef union Constant { 25typedef 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,24 @@ typedef struct LineCol {
34 sz col; 34 sz col;
35} LineCol; 35} LineCol;
36 36
37typedef struct Function {
38 Str name;
39 sz param_arity;
40 sz return_arity;
41 sz index;
42} Function;
43
44MAPDEF(FunctionMap, funcmap, Str, Function, str_hash, str_eq)
45
37typedef struct Chunk { 46typedef 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 IntIntMap *labels_rev; // chunk_index -> label
54 sz labels_idx;
40 55
41 // Constant values that fit in 64 bits. 56 // Constant values that fit in 64 bits.
42 Constant *constants; 57 Constant *constants;
@@ -52,10 +67,16 @@ typedef struct Chunk {
52 Variable *vars; 67 Variable *vars;
53 StrVarMap *varmap; 68 StrVarMap *varmap;
54 sz var_off; 69 sz var_off;
70 sz param_off;
55 71
56 // Number of registers currently used in this chunk. 72 // Number of registers currently used in this chunk.
57 sz reg_idx; 73 sz reg_idx;
58 74
75 // Number of functions currently used in this chunk.
76 struct Chunk **functions;
77 FunctionMap *funmap;
78 sz fun_idx;
79
59 // Debugging. 80 // Debugging.
60 Str file_name; 81 Str file_name;
61 Arena *storage; 82 Arena *storage;
@@ -66,31 +87,52 @@ typedef enum OpCode {
66 // OP DST A B 87 // OP DST A B
67 // --------------------------------------------------------------- 88 // ---------------------------------------------------------------
68 // VM/high level instructions. 89 // VM/high level instructions.
69 OP_HALT, // halt 90 OP_HALT, // halt
91 // NOTE: LDGVAR/STGVAR* could be obtained in terms of LDGADDR.
70 OP_STGVARI, // stgvari vx, ca 92 OP_STGVARI, // stgvari vx, ca
71 OP_STGVAR, // stgvar vx, ra 93 OP_STGVAR, // stgvar vx, ra
72 OP_LDGVAR, // ldgvar rx, vx 94 OP_LDGVAR, // ldgvar rx, va
95 OP_LDGADDR, // ldgaddr rx, va
96 OP_STLVARI, // stlvari vx, ca
97 OP_STLVAR, // stlvar vx, ra
98 OP_LDLVAR, // ldlvar rx, va
99 OP_LDLADDR, // ldladdr rx, va
100 // Functions.
101 OP_CALL, // call fx ; Bumps the stack pointer by cx
102 OP_RET, // ret ; Returns from current function
103 OP_RESERVE, // reserve cx ; Increments the stack pointer by cx bytes
104 OP_POP, // pop rx ; Pops the last value of the stack into rx.
105 OP_PUSH, // push rx ; Push the rx value to the stack.
106 OP_PUSHI, // pushi cx ; Push the cx value to the stack.
107 OP_PUTRET, // putret rx ; Put rx into the return value memory.
108 OP_PUTRETI, // putreti cx ; Put cx into the return value memory.
109 // Printing values with builtin print/println functions.
110 OP_PRINTSTR, // p rx
111 OP_PRINTS64, // p rx
112 OP_PRINTF64, // p rx
113 OP_PRINTS64I, // p cx
114 OP_PRINTF64I, // p cx
73 // Load/Store instructions. 115 // Load/Store instructions.
74 OP_LD8K, // ld8k rx, ca -> u8 rx = ca 116 OP_LD8K, // ld8k rx, ca -> u8 rx = ca
75 OP_LD16K, // ld16k rx, ca -> u16 rx = ca 117 OP_LD16K, // ld16k rx, ca -> u16 rx = ca
76 OP_LD32K, // ld32k rx, ca -> u32 rx = ca 118 OP_LD32K, // ld32k rx, ca -> u32 rx = ca
77 OP_LD64K, // ld64k rx, ca -> u64 rx = ca 119 OP_LD64K, // ld64k rx, ca -> u64 rx = ca
78 OP_LD8I, // ld8i rx, ra, cb -> u8 *p; rx = p[ra + cb] 120 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] 121 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] 122 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] 123 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] 124 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] 125 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] 126 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] 127 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 128 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 129 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 130 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 131 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 132 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 133 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 134 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 135 OP_ST64, // st64 rx, ra, rb -> u64 *p = ra; p[rb] = rx
94 // Integer arithmetic (only int/s64 for now). 136 // Integer arithmetic (only int/s64 for now).
95 OP_ADDI, // addk rx, ra, cb 137 OP_ADDI, // addk rx, ra, cb
96 OP_SUBI, // subk rx, ra, cb 138 OP_SUBI, // subk rx, ra, cb
@@ -149,19 +191,38 @@ typedef enum OpCode {
149 OP_BITOR, // bor rx, ra, rb 191 OP_BITOR, // bor rx, ra, rb
150 OP_BITNOT, // bnot rx, ra 192 OP_BITNOT, // bnot rx, ra
151 // Jump instructions. 193 // Jump instructions.
152 OP_JMPI, // jmp cx ; cx := signed offset 194 OP_JMP, // jmp lx ; jmp to label lx
153 OP_JMPFI, // jmpf cx, ca ; rx := condition, ca := offset 195 OP_JMPF, // jmpf lx, rx ; jmp to label lx if rx is false
154 OP_JMPTI, // jmpt cx, ca ; rx := condition, ca := offset 196 OP_JMPT, // jmpt lx, rx ; jmp to label lx if rx is true
155 OP_JMP, // jmp rx ; rx := signed offset 197 OP_JMPFI, // jmpf lx, cx ; jmp to label lx if rx is false
156 OP_JMPF, // jmpf rx, ca ; rx := condition, ca := offset 198 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; 199} OpCode;
159 200
160Str op_str[] = { 201Str op_str[] = {
202 // High level ops.
161 [OP_HALT] = cstr("HALT "), 203 [OP_HALT] = cstr("HALT "),
162 [OP_STGVAR] = cstr("STGVAR "), 204 [OP_STGVAR] = cstr("STGVAR "),
163 [OP_STGVARI] = cstr("STGVARI "), 205 [OP_STGVARI] = cstr("STGVARI "),
164 [OP_LDGVAR] = cstr("LDGVAR "), 206 [OP_LDGVAR] = cstr("LDGVAR "),
207 [OP_LDGADDR] = cstr("LDGADDR "),
208 [OP_STLVAR] = cstr("STLVAR "),
209 [OP_STLVARI] = cstr("STLVARI "),
210 [OP_LDLVAR] = cstr("LDLVAR "),
211 [OP_LDLADDR] = cstr("LDLADDR "),
212 [OP_PRINTSTR] = cstr("PRNTSTR "),
213 [OP_PRINTS64] = cstr("PRNTS64 "),
214 [OP_PRINTF64] = cstr("PRNTF64 "),
215 [OP_PRINTS64I] = cstr("PRNTS64I"),
216 [OP_PRINTF64I] = cstr("PRNTF64I"),
217 [OP_PUTRET] = cstr("PUTRET "),
218 [OP_PUTRETI] = cstr("PUTRETI "),
219 // Functions.
220 [OP_CALL] = cstr("CALL "),
221 [OP_RET] = cstr("RET "),
222 [OP_RESERVE] = cstr("RESERVE "),
223 [OP_POP] = cstr("POP "),
224 [OP_PUSH] = cstr("PUSH "),
225 [OP_PUSHI] = cstr("PUSHI "),
165 // Load ops. 226 // Load ops.
166 [OP_LD8K] = cstr("LD8K "), 227 [OP_LD8K] = cstr("LD8K "),
167 [OP_LD16K] = cstr("LD16K "), 228 [OP_LD16K] = cstr("LD16K "),
@@ -241,12 +302,11 @@ Str op_str[] = {
241 [OP_BITOR] = cstr("BOR "), 302 [OP_BITOR] = cstr("BOR "),
242 [OP_BITNOT] = cstr("BNOT "), 303 [OP_BITNOT] = cstr("BNOT "),
243 // Jump instructions. 304 // Jump instructions.
244 [OP_JMPI] = cstr("JMPI "),
245 [OP_JMPFI] = cstr("JMPFI "),
246 [OP_JMPTI] = cstr("JMPTI "),
247 [OP_JMP] = cstr("JMP "), 305 [OP_JMP] = cstr("JMP "),
248 [OP_JMPF] = cstr("JMPF "), 306 [OP_JMPF] = cstr("JMPF "),
249 [OP_JMPT] = cstr("JMPT "), 307 [OP_JMPT] = cstr("JMPT "),
308 [OP_JMPFI] = cstr("JMPFI "),
309 [OP_JMPTI] = cstr("JMPTI "),
250}; 310};
251 311
252typedef enum { 312typedef enum {
@@ -254,6 +314,7 @@ typedef enum {
254 COMP_CONST, 314 COMP_CONST,
255 COMP_STRING, 315 COMP_STRING,
256 COMP_REG, 316 COMP_REG,
317 COMP_RET,
257 COMP_ERR, 318 COMP_ERR,
258} CompResultType; 319} CompResultType;
259 320
@@ -262,23 +323,27 @@ typedef struct CompResult {
262 CompResultType type; 323 CompResultType type;
263} CompResult; 324} CompResult;
264 325
265CompResult compile_expr(Chunk *chunk, Node *node); 326CompResult compile_expr(Chunk *chunk, Node *node, sz lab_pre, sz lab_post);
266 327
267#define EMIT_OP(OP, DST, A, B, NODE, CHUNK) \ 328#define EMIT_OP(OP, DST, A, B, NODE, CHUNK) \
268 do { \ 329 do { \
269 Instruction inst = (Instruction){ \ 330 Instruction inst = (Instruction){ \
270 .op = (OP), \ 331 .op = (OP), \
271 .dst = (DST), \ 332 .dst = (DST), \
272 .a = (A), \ 333 .a = (A), \
273 .b = (B), \ 334 .b = (B), \
274 }; \ 335 }; \
275 array_push((CHUNK)->code, inst, (CHUNK)->storage); \ 336 array_push((CHUNK)->code, inst, (CHUNK)->storage); \
276 LineCol linecol = (LineCol){.line = (NODE)->line, .col = (NODE)->col}; \ 337 LineCol linecol = (LineCol){0}; \
277 array_push((CHUNK)->linecol, linecol, (CHUNK)->storage); \ 338 if (NODE) { \
339 Node *_node = (NODE); \
340 linecol = (LineCol){.line = _node->line, .col = _node->col}; \
341 } \
342 array_push((CHUNK)->linecol, linecol, (CHUNK)->storage); \
278 } while (0) 343 } while (0)
279 344
280CompResult 345CompResult
281compile_binary(Chunk *chunk, Node *node) { 346compile_binary(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
282 OpCode op = OP_HALT; 347 OpCode op = OP_HALT;
283 OpCode opi = OP_HALT; 348 OpCode opi = OP_HALT;
284 OpCode ldop = OP_LD64K; 349 OpCode ldop = OP_LD64K;
@@ -381,8 +446,8 @@ compile_binary(Chunk *chunk, Node *node) {
381 } break; 446 } break;
382 default: break; 447 default: break;
383 } 448 }
384 CompResult comp_a = compile_expr(chunk, node->left); 449 CompResult comp_a = compile_expr(chunk, node->left, lab_pre, lab_post);
385 CompResult comp_b = compile_expr(chunk, node->right); 450 CompResult comp_b = compile_expr(chunk, node->right, lab_pre, lab_post);
386 sz reg_a; 451 sz reg_a;
387 sz reg_b; 452 sz reg_b;
388 switch (comp_a.type) { 453 switch (comp_a.type) {
@@ -415,7 +480,7 @@ compile_binary(Chunk *chunk, Node *node) {
415} 480}
416 481
417CompResult 482CompResult
418compile_unary(Chunk *chunk, Node *node) { 483compile_unary(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
419 OpCode op = OP_HALT; 484 OpCode op = OP_HALT;
420 OpCode opi = OP_HALT; 485 OpCode opi = OP_HALT;
421 switch (node->kind) { 486 switch (node->kind) {
@@ -429,7 +494,7 @@ compile_unary(Chunk *chunk, Node *node) {
429 } break; 494 } break;
430 default: break; 495 default: break;
431 } 496 }
432 CompResult comp_a = compile_expr(chunk, node->left); 497 CompResult comp_a = compile_expr(chunk, node->left, lab_pre, lab_post);
433 sz reg_a; 498 sz reg_a;
434 switch (comp_a.type) { 499 switch (comp_a.type) {
435 case COMP_CONST: { 500 case COMP_CONST: {
@@ -461,9 +526,52 @@ add_constant(Chunk *chunk, sz value) {
461 return map->val; 526 return map->val;
462} 527}
463 528
529sz
530add_string(Chunk *chunk, Str string) {
531 // Make sure we don't have duplicated string.
532 StrIntMap *map = strintmap_lookup(&chunk->strmap, string);
533 if (!map) {
534 map = strintmap_insert(&chunk->strmap, string, chunk->str_idx++,
535 chunk->storage);
536 array_push(chunk->strings, string, chunk->storage);
537 }
538 return map->val;
539}
540
541sz
542add_variable(Chunk *chunk, Str name, Str type, sz arr_size) {
543 sz idx = array_size(chunk->vars);
544 sz size = 8;
545 // TODO: get type storage from a table to consider all the basic
546 // types as well as user defined ones.
547 if (str_eq(type, cstr("str"))) {
548 size = 16;
549 }
550 if (arr_size) {
551 // TODO: get the proper storage size for the multiplication.
552 size *= arr_size;
553 // FIXME: this should be done on the static analysis, plus,
554 // we shouldn't be checking all these types by hand, but
555 // using the symbol tables.
556 type = str_remove_prefix(type, cstr("@"));
557 type = str_concat(cstr("[]"), type, chunk->storage);
558 }
559 Variable var = (Variable){
560 .name = name,
561 .type = type,
562 .size = size,
563 .offset = chunk->var_off,
564 .idx = idx,
565 };
566 varmap_insert(&chunk->varmap, name, var, chunk->storage);
567 array_push(chunk->vars, var, chunk->storage);
568 chunk->var_off += size;
569 return idx;
570}
571
464CompResult 572CompResult
465compile_if(Chunk *chunk, Node *node) { 573compile_if(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
466 CompResult cond = compile_expr(chunk, node->cond_if); 574 CompResult cond = compile_expr(chunk, node->cond_if, lab_pre, lab_post);
467 OpCode jmpop; 575 OpCode jmpop;
468 switch (cond.type) { 576 switch (cond.type) {
469 case COMP_CONST: { 577 case COMP_CONST: {
@@ -476,19 +584,19 @@ compile_if(Chunk *chunk, Node *node) {
476 return (CompResult){.type = COMP_ERR}; 584 return (CompResult){.type = COMP_ERR};
477 } break; 585 } break;
478 } 586 }
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 587
486 // Jump to the `false` branch. 588 if (!str_eq(node->type, cstr("nil")) &&
487 EMIT_OP(jmpop, cond.idx, 0xff, 0, node->cond_if, chunk); 589 !str_has_prefix(node->type, cstr("ret:")) &&
590 !str_has_prefix(node->type, cstr("flow:"))) {
591 sz reg_dst = chunk->reg_idx++;
488 592
489 // Condition is true. 593 // Jump to the `false` branch.
490 CompResult then_expr = compile_expr(chunk, node->cond_expr); 594 sz lab0 = chunk->labels_idx++;
491 if (has_value) { 595 EMIT_OP(jmpop, lab0, cond.idx, 0, node->cond_if, chunk);
596
597 // Condition is true.
598 CompResult then_expr =
599 compile_expr(chunk, node->cond_expr, lab_pre, lab_post);
492 switch (then_expr.type) { 600 switch (then_expr.type) {
493 case COMP_CONST: { 601 case COMP_CONST: {
494 EMIT_OP(OP_LD64K, reg_dst, then_expr.idx, 0, node->cond_if, 602 EMIT_OP(OP_LD64K, reg_dst, then_expr.idx, 0, node->cond_if,
@@ -498,59 +606,457 @@ compile_if(Chunk *chunk, Node *node) {
498 EMIT_OP(OP_MOV64, reg_dst, then_expr.idx, 0, node->cond_if, 606 EMIT_OP(OP_MOV64, reg_dst, then_expr.idx, 0, node->cond_if,
499 chunk); 607 chunk);
500 } break; 608 } break;
609 case COMP_RET: break;
501 default: { 610 default: {
502 return (CompResult){.type = COMP_ERR}; 611 return (CompResult){.type = COMP_ERR};
503 } break; 612 } break;
504 } 613 }
505 }
506 614
507 // Jump to the end of the expression. 615 // Jump to the end of the expression.
508 sz jump_b = array_size(chunk->code); 616 sz pos0 = array_size(chunk->code);
509 EMIT_OP(OP_JMPI, 0xff, 0, 0, node->cond_if, chunk); 617 sz lab1 = chunk->labels_idx++;
618 EMIT_OP(OP_JMP, lab1, 0, 0, node->cond_else, chunk);
510 619
511 // Else expression. 620 // Else expression.
512 CompResult else_expr = compile_expr(chunk, node->cond_else); 621 CompResult else_expr =
513 if (has_value) { 622 compile_expr(chunk, node->cond_else, lab_pre, lab_post);
514 switch (else_expr.type) { 623 switch (else_expr.type) {
515 case COMP_CONST: { 624 case COMP_CONST: {
516 EMIT_OP(OP_LD64K, reg_dst, else_expr.idx, 0, node->cond_if, 625 EMIT_OP(OP_LD64K, reg_dst, else_expr.idx, 0, node->cond_else,
517 chunk); 626 chunk);
518 } break; 627 } break;
519 case COMP_REG: { 628 case COMP_REG: {
520 EMIT_OP(OP_MOV64, reg_dst, else_expr.idx, 0, node->cond_if, 629 EMIT_OP(OP_MOV64, reg_dst, else_expr.idx, 0, node->cond_else,
521 chunk); 630 chunk);
522 } break; 631 } break;
632 case COMP_RET: break;
523 default: { 633 default: {
524 return (CompResult){.type = COMP_ERR}; 634 return (CompResult){.type = COMP_ERR};
525 } break; 635 } break;
526 } 636 }
637 sz pos1 = array_size(chunk->code);
638
639 // Update labels.
640 intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage);
641 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
642 intintmap_insert(&chunk->labels_rev, pos0 + 1, lab0, chunk->storage);
643 intintmap_insert(&chunk->labels_rev, pos1, lab1, chunk->storage);
644 return (CompResult){.type = COMP_REG, .idx = reg_dst};
645 }
646
647 // Jump to the `false` branch.
648 sz lab0 = chunk->labels_idx++;
649 EMIT_OP(jmpop, lab0, cond.idx, 0, node->cond_if, chunk);
650
651 // Condition is true.
652 compile_expr(chunk, node->cond_expr, lab_pre, lab_post);
653
654 // Jump to the end of the expression.
655 sz pos0 = array_size(chunk->code);
656 sz lab1 = chunk->labels_idx++;
657 EMIT_OP(OP_JMP, lab1, 0, 0, node->cond_else, chunk);
658
659 // Else expression.
660 if (node->cond_else) {
661 compile_expr(chunk, node->cond_else, lab_pre, lab_post);
662 }
663 sz pos1 = array_size(chunk->code);
664
665 // Update labels.
666 intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage);
667 intintmap_insert(&chunk->labels_rev, pos0 + 1, lab0, chunk->storage);
668 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
669 intintmap_insert(&chunk->labels_rev, pos1, lab1, chunk->storage);
670
671 return (CompResult){.type = COMP_NIL};
672}
673
674CompResult
675compile_cond(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
676 if (str_eq(node->type, cstr("nil"))) {
677 sz lab1 = chunk->labels_idx++;
678 for (sz i = 0; i < array_size(node->match_cases); i++) {
679 // condition = expression
680 Node *expr = node->match_cases[i];
681 if (expr->case_value) {
682 CompResult cond =
683 compile_expr(chunk, expr->case_value, lab_pre, lab_post);
684 OpCode jmpop;
685 switch (cond.type) {
686 case COMP_CONST: {
687 jmpop = OP_JMPFI;
688 } break;
689 case COMP_REG: {
690 jmpop = OP_JMPF;
691 } break;
692 default: {
693 return (CompResult){.type = COMP_ERR};
694 } break;
695 }
696 // Jump to the `next` branch.
697 sz lab0 = chunk->labels_idx++;
698 EMIT_OP(jmpop, lab0, cond.idx, 0, expr->case_expr, chunk);
699
700 // Condition is true.
701 compile_expr(chunk, expr->case_expr, lab_pre, lab_post);
702 if (i != array_size(node->match_cases) - 1) {
703 // Jump to the end of the expression.
704 sz pos0 = array_size(chunk->code);
705 EMIT_OP(OP_JMP, lab1, 0, 0, node->cond_else, chunk);
706 intintmap_insert(&chunk->labels, lab0, pos0 + 1,
707 chunk->storage);
708 intintmap_insert(&chunk->labels_rev, pos0 + 1, lab0,
709 chunk->storage);
710 }
711 } else {
712 compile_expr(chunk, expr->case_expr, lab_pre, lab_post);
713 break;
714 }
715 }
716 sz pos1 = array_size(chunk->code);
717 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
718 intintmap_insert(&chunk->labels_rev, pos1, lab1, chunk->storage);
719 return (CompResult){.type = COMP_NIL};
720 }
721
722 sz reg_dst = chunk->reg_idx++;
723 sz lab1 = chunk->labels_idx++;
724 for (sz i = 0; i < array_size(node->match_cases); i++) {
725 // condition = expression
726 Node *expr = node->match_cases[i];
727 if (expr->case_value) {
728 CompResult cond =
729 compile_expr(chunk, expr->case_value, lab_pre, lab_post);
730 OpCode jmpop;
731 switch (cond.type) {
732 case COMP_CONST: {
733 jmpop = OP_JMPFI;
734 } break;
735 case COMP_REG: {
736 jmpop = OP_JMPF;
737 } break;
738 default: {
739 return (CompResult){.type = COMP_ERR};
740 } break;
741 }
742 // Jump to the `next` branch.
743 sz lab0 = chunk->labels_idx++;
744 EMIT_OP(jmpop, lab0, cond.idx, 0, expr->case_expr, chunk);
745
746 // Condition is true.
747 CompResult then_expr =
748 compile_expr(chunk, expr->case_expr, lab_pre, lab_post);
749 switch (then_expr.type) {
750 case COMP_CONST: {
751 EMIT_OP(OP_LD64K, reg_dst, then_expr.idx, 0,
752 expr->case_expr, chunk);
753 } break;
754 case COMP_REG: {
755 EMIT_OP(OP_MOV64, reg_dst, then_expr.idx, 0,
756 expr->case_expr, chunk);
757 } break;
758 case COMP_RET: break;
759 default: {
760 return (CompResult){.type = COMP_ERR};
761 } break;
762 }
763 if (i != array_size(node->match_cases) - 1) {
764 // Jump to the end of the expression.
765 sz pos0 = array_size(chunk->code);
766 EMIT_OP(OP_JMP, lab1, 0, 0, node->cond_else, chunk);
767 intintmap_insert(&chunk->labels, lab0, pos0 + 1,
768 chunk->storage);
769 intintmap_insert(&chunk->labels_rev, pos0 + 1, lab0,
770 chunk->storage);
771 }
772 } else {
773 CompResult then_expr =
774 compile_expr(chunk, expr->case_expr, lab_pre, lab_post);
775 switch (then_expr.type) {
776 case COMP_CONST: {
777 EMIT_OP(OP_LD64K, reg_dst, then_expr.idx, 0,
778 expr->case_expr, chunk);
779 } break;
780 case COMP_REG: {
781 EMIT_OP(OP_MOV64, reg_dst, then_expr.idx, 0,
782 expr->case_expr, chunk);
783 } break;
784 case COMP_RET: break;
785 default: {
786 return (CompResult){.type = COMP_ERR};
787 } break;
788 }
789 break;
790 }
791 }
792 sz pos1 = array_size(chunk->code);
793 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
794 intintmap_insert(&chunk->labels_rev, pos1, lab1, chunk->storage);
795 return (CompResult){.type = COMP_REG, .idx = reg_dst};
796}
797
798CompResult
799compile_break(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
800 (void)lab_pre;
801 EMIT_OP(OP_JMP, lab_post, 0, 0, node, chunk);
802 return (CompResult){.type = COMP_NIL};
803}
804
805CompResult
806compile_continue(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
807 (void)lab_post;
808 EMIT_OP(OP_JMP, lab_pre, 0, 0, node, chunk);
809 return (CompResult){.type = COMP_NIL};
810}
811
812CompResult
813compile_while(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
814 sz lab0 = chunk->labels_idx++;
815 sz lab1 = chunk->labels_idx++;
816 sz pos1 = array_size(chunk->code);
817 CompResult cond = compile_expr(chunk, node->while_cond, lab_pre, lab_post);
818 OpCode jmpop;
819 switch (cond.type) {
820 case COMP_CONST: {
821 jmpop = OP_JMPFI;
822 } break;
823 case COMP_REG: {
824 jmpop = OP_JMPF;
825 } break;
826 default: {
827 return (CompResult){.type = COMP_ERR};
828 } break;
527 } 829 }
528 sz end_expr = array_size(chunk->code);
529 830
530 // Backpatch jumps. 831 // Jump to the `end of the loop` branch.
531 sz const_a = add_constant(chunk, jump_b + 1 - jump_a); 832 EMIT_OP(jmpop, lab0, cond.idx, 0, node->while_cond, chunk);
532 sz const_b = add_constant(chunk, end_expr - jump_b); 833
533 chunk->code[jump_a].a = const_a; 834 // Condition is true.
534 chunk->code[jump_b].dst = const_b; 835 compile_expr(chunk, node->while_expr, lab1, lab0);
535 // TODO: does it has an else or not? Moreover, should we enforce on the 836 sz pos0 = array_size(chunk->code);
536 // semantic level that if the `if` expression returns a value we must add an 837 EMIT_OP(OP_JMP, lab1, 0, 0, node, chunk);
537 // else? 838
839 // Update labels.
840 intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage);
841 intintmap_insert(&chunk->labels_rev, pos0 + 1, lab0, chunk->storage);
842 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
843 intintmap_insert(&chunk->labels_rev, pos1, lab1, chunk->storage);
538 844
539 // Return. 845 // Return.
540 if (has_value) { 846 return (CompResult){.type = COMP_NIL};
847}
848
849CompResult
850compile_funcall(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
851 Str name = node->value.str;
852
853 // Builtins.
854 if (str_eq(name, cstr("print")) || str_eq(name, cstr("println"))) {
855 for (sz i = 0; i < array_size(node->elements); i++) {
856 Node *expr = node->elements[i];
857 CompResult result = compile_expr(chunk, expr, lab_pre, lab_post);
858 if (str_eq(expr->type, cstr("int"))) {
859 switch (result.type) {
860 case COMP_CONST: {
861 EMIT_OP(OP_PRINTS64I, result.idx, 0, 0, expr, chunk);
862 } break;
863 case COMP_REG: {
864 EMIT_OP(OP_PRINTS64, result.idx, 0, 0, expr, chunk);
865 } break;
866 default: {
867 return (CompResult){.type = COMP_ERR};
868 } break;
869 }
870 } else if (str_eq(expr->type, cstr("f64"))) {
871 switch (result.type) {
872 case COMP_CONST: {
873 EMIT_OP(OP_PRINTF64I, result.idx, 0, 0, expr, chunk);
874 } break;
875 case COMP_REG: {
876 EMIT_OP(OP_PRINTF64, result.idx, 0, 0, expr, chunk);
877 } break;
878 default: {
879 return (CompResult){.type = COMP_ERR};
880 } break;
881 }
882 } else if (str_eq(expr->type, cstr("str"))) {
883 switch (result.type) {
884 case COMP_STRING: {
885 EMIT_OP(OP_PRINTSTR, result.idx, 0, 0, expr, chunk);
886 } break;
887 default: {
888 return (CompResult){.type = COMP_ERR};
889 } break;
890 }
891 }
892 }
893 if (str_eq(name, cstr("println"))) {
894 sz idx = add_string(chunk, cstr("\n"));
895 EMIT_OP(OP_PRINTSTR, idx, 0, 0, node, chunk);
896 }
897 return (CompResult){.type = COMP_NIL};
898 }
899
900 // TODO: need to find this on the parents, not just in the current chunk.
901 FunctionMap *map = funcmap_lookup(&chunk->funmap, node->unique_name);
902 if (!map) {
903 println("how come?");
904 exit(EXIT_FAILURE);
905 }
906 Function fun = map->val;
907
908 // Reserve space for the return value if needed.
909 if (fun.return_arity > 0) {
910 // Put the return data into a register
911 sz ret_size = add_constant(chunk, 8);
912 EMIT_OP(OP_RESERVE, ret_size, 0, 0, node, chunk);
913 }
914
915 // Send parameters to the stack.
916 for (sz i = 0; i < array_size(node->elements); i++) {
917 Node *expr = node->elements[i];
918 CompResult result = compile_expr(chunk, expr, lab_pre, lab_post);
919 // TODO: Assuming all values are 8 bytes... again.
920 switch (result.type) {
921 case COMP_CONST: {
922 EMIT_OP(OP_PUSHI, result.idx, 0, 0, expr, chunk);
923 } break;
924 case COMP_REG: {
925 EMIT_OP(OP_PUSH, result.idx, 0, 0, expr, chunk);
926 } break;
927 default: {
928 return (CompResult){.type = COMP_ERR};
929 } break;
930 }
931 }
932
933 EMIT_OP(OP_CALL, fun.index, 0, 0, node, chunk);
934
935 // Only one return parameter for now.
936 if (fun.return_arity > 0) {
937 // Put the return data into a register
938 sz reg_dst = chunk->reg_idx++;
939 EMIT_OP(OP_POP, reg_dst, 0, 0, node, chunk);
541 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 940 return (CompResult){.type = COMP_REG, .idx = reg_dst};
542 } 941 }
942
543 return (CompResult){.type = COMP_NIL}; 943 return (CompResult){.type = COMP_NIL};
544} 944}
545 945
546CompResult 946CompResult
547compile_expr(Chunk *chunk, Node *node) { 947compile_return(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
948 for (sz i = 0; i < array_size(node->elements); i++) {
949 Node *expr = node->elements[i];
950 CompResult res = compile_expr(chunk, expr, lab_pre, lab_post);
951
952 // TODO: Only one return field for now, but this is the idea.
953 // Put return values into memory.
954 switch (res.type) {
955 case COMP_CONST: {
956 EMIT_OP(OP_PUTRETI, res.idx, 0, 0, node, chunk);
957 } break;
958 case COMP_REG: {
959 EMIT_OP(OP_PUTRET, res.idx, 0, 0, node, chunk);
960 } break;
961 default: {
962 return (CompResult){.type = COMP_ERR};
963 } break;
964 }
965 break;
966 }
967
968 EMIT_OP(OP_RET, 0, 0, 0, node, chunk);
969 return (CompResult){.type = COMP_RET};
970}
971
972Chunk *
973chunk_alloc(Chunk *parent) {
974 static sz chunk_idx = 1;
975 Chunk *chunk = arena_calloc((sz)sizeof(Chunk), parent->storage);
976 chunk->parent = parent;
977 chunk->id = chunk_idx++;
978 chunk->storage = parent->storage;
979 chunk->file_name = parent->file_name;
980 return chunk;
981}
982
983CompResult
984compile_function(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
985 // The current activation record procedure for the VM is as follows:
986 //
987 // [caller][callee ]
988 // [ .... ][ RET VAL ][ PARAMS ][ LOCALS ][ REGISTERS ][ RET META ]
989 // ^
990 // frame pointer
991 //
992 // The caller is responsible for allocating the return memory and the
993 // parameter memory and filling the param data before OP_CALL.
994 //
995 Chunk *func = chunk_alloc(chunk);
996 func->name = node->unique_name;
997 Function fun = (Function){
998 .name = func->name,
999 .index = chunk->fun_idx++,
1000 .param_arity = array_size(node->func_params),
1001 .return_arity = array_size(node->func_ret),
1002 };
1003 funcmap_insert(&chunk->funmap, func->name, fun, chunk->storage);
1004 array_push(chunk->functions, func, chunk->storage);
1005
1006 // Push arguments as locals.
1007 for (sz i = 0; i < array_size(node->func_params); i++) {
1008 Node *param = node->func_params[i];
1009 Str name = param->unique_name;
1010 Str type = param->type;
1011 sz arr_size = 0;
1012 if (str_has_prefix(type, cstr("@"))) {
1013 if (param->var_type && param->var_type->kind == NODE_ARR_TYPE &&
1014 param->var_type->arr_size->value.i > 0) {
1015 arr_size = param->var_type->arr_size->value.i;
1016 }
1017 }
1018 add_variable(func, name, type, arr_size);
1019 }
1020 func->param_off = func->var_off;
1021
1022 // Compiling the body.
1023 CompResult res = compile_expr(func, node->func_body, lab_pre, lab_post);
1024
1025 // Put return values into memory.
1026 switch (res.type) {
1027 case COMP_CONST: {
1028 EMIT_OP(OP_PUTRETI, res.idx, 0, 0, node, func);
1029 } break;
1030 case COMP_REG: {
1031 EMIT_OP(OP_PUTRET, res.idx, 0, 0, node, func);
1032 } break;
1033 default: break;
1034 }
1035
1036 // TODO: handle captured locals/globals?
1037 EMIT_OP(OP_RET, 0, 0, 0, node, func);
1038 return (CompResult){.type = COMP_NIL};
1039}
1040
1041CompResult
1042compile_expr(Chunk *chunk, Node *node, sz lab_pre, sz lab_post) {
548 switch (node->kind) { 1043 switch (node->kind) {
549 case NODE_IF: return compile_if(chunk, node); 1044 case NODE_BREAK: return compile_break(chunk, node, lab_pre, lab_post);
1045 case NODE_CONTINUE:
1046 return compile_continue(chunk, node, lab_pre, lab_post);
1047 case NODE_RETURN: return compile_return(chunk, node, lab_pre, lab_post);
1048 case NODE_FUN: return compile_function(chunk, node, lab_pre, lab_post);
1049 case NODE_FUNCALL:
1050 return compile_funcall(chunk, node, lab_pre, lab_post);
1051 case NODE_WHILE: return compile_while(chunk, node, lab_pre, lab_post);
1052 case NODE_IF: return compile_if(chunk, node, lab_pre, lab_post);
1053 case NODE_COND: return compile_cond(chunk, node, lab_pre, lab_post);
550 // Logic. 1054 // Logic.
551 // case NODE_XOR: 1055 // case NODE_XOR:
552 case NODE_BITNOT: 1056 case NODE_BITNOT:
553 case NODE_NOT: return compile_unary(chunk, node); break; 1057 case NODE_NOT:
1058 return compile_unary(chunk, node, lab_pre, lab_post);
1059 break;
554 case NODE_AND: 1060 case NODE_AND:
555 case NODE_OR: 1061 case NODE_OR:
556 case NODE_EQ: 1062 case NODE_EQ:
@@ -569,7 +1075,9 @@ compile_expr(Chunk *chunk, Node *node) {
569 case NODE_SUB: 1075 case NODE_SUB:
570 case NODE_MUL: 1076 case NODE_MUL:
571 case NODE_DIV: 1077 case NODE_DIV:
572 case NODE_MOD: return compile_binary(chunk, node); break; 1078 case NODE_MOD:
1079 return compile_binary(chunk, node, lab_pre, lab_post);
1080 break;
573 case NODE_TRUE: 1081 case NODE_TRUE:
574 case NODE_FALSE: 1082 case NODE_FALSE:
575 case NODE_NUM_FLOAT: 1083 case NODE_NUM_FLOAT:
@@ -584,49 +1092,42 @@ compile_expr(Chunk *chunk, Node *node) {
584 } break; 1092 } break;
585 case NODE_STRING: { 1093 case NODE_STRING: {
586 Str string = node->value.str; 1094 Str string = node->value.str;
587 // Make sure we don't have duplicated strings. 1095 sz str_idx = add_string(chunk, string);
588 StrIntMap *map = strintmap_lookup(&chunk->strmap, string);
589 if (!map) {
590 map = strintmap_insert(&chunk->strmap, string, chunk->str_idx++,
591 chunk->storage);
592 array_push(chunk->strings, string, chunk->storage);
593 }
594 return (CompResult){ 1096 return (CompResult){
595 .type = COMP_STRING, 1097 .type = COMP_STRING,
596 .idx = map->val, 1098 .idx = str_idx,
597 }; 1099 };
598 } break; 1100 } break;
599 case NODE_LET: { 1101 case NODE_LET: {
600 sz idx = array_size(chunk->vars); 1102 u8 op_stvari = OP_STGVARI;
1103 u8 op_stvar = OP_STGVAR;
1104 if (!str_eq(chunk->name, cstr(".main"))) {
1105 op_stvari = OP_STLVARI;
1106 op_stvar = OP_STLVAR;
1107 }
601 Str name = node->unique_name; 1108 Str name = node->unique_name;
602 Str type = node->var_name->type; 1109 Str type = node->var_name->type;
603 sz size = 8; 1110 sz arr_size = 0;
604 // TODO: get type storage from a table to consider all the basic 1111 if (str_has_prefix(type, cstr("@"))) {
605 // types as well as user defined ones. 1112 if (node->var_type && node->var_type->kind == NODE_ARR_TYPE &&
606 if (str_eq(type, cstr("str"))) { 1113 node->var_type->arr_size->value.i > 0) {
607 size = 16; 1114 arr_size = node->var_type->arr_size->value.i;
1115 }
608 } 1116 }
609 Variable var = (Variable){ 1117
610 .name = name, 1118 sz idx = add_variable(chunk, name, type, arr_size);
611 .type = type,
612 .size = size,
613 .offset = chunk->var_off,
614 .idx = idx,
615 };
616 varmap_insert(&chunk->varmap, name, var, chunk->storage);
617 array_push(chunk->vars, var, chunk->storage);
618 chunk->var_off += size;
619 1119
620 // Value. 1120 // Value.
621 if (node->var_val) { 1121 if (node->var_val) {
622 CompResult res = compile_expr(chunk, node->var_val); 1122 CompResult res =
1123 compile_expr(chunk, node->var_val, lab_pre, lab_post);
623 switch (res.type) { 1124 switch (res.type) {
624 case COMP_CONST: { 1125 case COMP_CONST: {
625 EMIT_OP(OP_STGVARI, idx, res.idx, 0, node->var_val, 1126 EMIT_OP(op_stvari, idx, res.idx, 0, node->var_val,
626 chunk); 1127 chunk);
627 } break; 1128 } break;
628 case COMP_REG: { 1129 case COMP_REG: {
629 EMIT_OP(OP_STGVAR, idx, res.idx, 0, node->var_val, 1130 EMIT_OP(op_stvar, idx, res.idx, 0, node->var_val,
630 chunk); 1131 chunk);
631 } break; 1132 } break;
632 default: { 1133 default: {
@@ -637,23 +1138,182 @@ compile_expr(Chunk *chunk, Node *node) {
637 1138
638 return (CompResult){.type = COMP_NIL}; 1139 return (CompResult){.type = COMP_NIL};
639 } break; 1140 } break;
1141 case NODE_SET: {
1142 Str name = node->unique_name;
1143 StrVarMap *map = NULL;
1144 Chunk *next = chunk;
1145 while (next) {
1146 map = varmap_lookup(&next->varmap, name);
1147 if (map) {
1148 break;
1149 }
1150 next = chunk->parent;
1151 }
1152 if (!map) {
1153 println("error: unreachable symbol name: %s", name);
1154 exit(EXIT_FAILURE);
1155 }
1156 u8 op_ldaddr = OP_LDGADDR;
1157 u8 op_ldvar = OP_LDGVAR;
1158 u8 op_stvari = OP_STGVARI;
1159 u8 op_stvar = OP_STGVAR;
1160 if (!str_eq(next->name, cstr(".main"))) {
1161 op_ldaddr = OP_LDLADDR;
1162 op_ldvar = OP_LDLVAR;
1163 op_stvari = OP_STLVARI;
1164 op_stvar = OP_STLVAR;
1165 }
1166 CompResult res =
1167 compile_expr(chunk, node->var_val, lab_pre, lab_post);
1168 if (node->var_name->kind == NODE_SYMBOL_IDX) {
1169 // Value.
1170 sz reg_val;
1171 switch (res.type) {
1172 case COMP_CONST: {
1173 reg_val = chunk->reg_idx++;
1174 EMIT_OP(OP_LD64K, reg_val, res.idx, 0, node, chunk);
1175 } break;
1176 case COMP_REG: {
1177 reg_val = res.idx;
1178 } break;
1179 default: {
1180 return (CompResult){.type = COMP_ERR};
1181 } break;
1182 }
1183
1184 // Address.
1185 sz reg_addr = chunk->reg_idx++;
1186 // Is this a pointer access or an array access?
1187 if (str_has_prefix(map->val.type, cstr("[]"))) {
1188 EMIT_OP(op_ldaddr, reg_addr, map->val.idx, 0, node->var_val,
1189 chunk);
1190 } else {
1191 EMIT_OP(op_ldvar, reg_addr, map->val.idx, 0, node->var_val,
1192 chunk);
1193 }
1194
1195 // Index.
1196 CompResult idx = compile_expr(chunk, node->var_name->arr_size,
1197 lab_pre, lab_post);
1198 switch (idx.type) {
1199 case COMP_CONST: {
1200 EMIT_OP(OP_ST64I, reg_val, reg_addr, idx.idx, node,
1201 chunk);
1202 } break;
1203 case COMP_REG: {
1204 EMIT_OP(OP_ST64, reg_val, reg_addr, idx.idx, node,
1205 chunk);
1206 } break;
1207 default: {
1208 return (CompResult){.type = COMP_ERR};
1209 } break;
1210 }
1211 // TODO: offset should be in bytes, in this case we are assuming
1212 // 64bit types, hence ST64
1213 return (CompResult){.type = COMP_NIL};
1214 }
1215 switch (res.type) {
1216 case COMP_CONST: {
1217 EMIT_OP(op_stvari, map->val.idx, res.idx, 0, node->var_val,
1218 chunk);
1219 } break;
1220 case COMP_REG: {
1221 EMIT_OP(op_stvar, map->val.idx, res.idx, 0, node->var_val,
1222 chunk);
1223 } break;
1224 default: {
1225 return (CompResult){.type = COMP_ERR};
1226 } break;
1227 }
1228 return (CompResult){.type = COMP_NIL};
1229 } break;
640 case NODE_SYMBOL: { 1230 case NODE_SYMBOL: {
641 Str name = node->unique_name; 1231 Str name = node->unique_name;
642 StrVarMap *map = varmap_lookup(&chunk->varmap, name); 1232 StrVarMap *map = NULL;
1233 Chunk *next = chunk;
1234 while (next) {
1235 map = varmap_lookup(&next->varmap, name);
1236 if (map) {
1237 break;
1238 }
1239 next = chunk->parent;
1240 }
643 if (!map) { 1241 if (!map) {
644 println("error: unreachable... name: %s", name); 1242 println("error: unreachable symbol name: %s", name);
645 exit(EXIT_FAILURE); 1243 exit(EXIT_FAILURE);
646 } 1244 }
1245 u8 op_ldaddr = OP_LDGADDR;
1246 u8 op_ldvar = OP_LDGVAR;
1247 if (!str_eq(next->name, cstr(".main"))) {
1248 op_ldaddr = OP_LDLADDR;
1249 op_ldvar = OP_LDLVAR;
1250 }
647 Variable var = map->val; 1251 Variable var = map->val;
648 u8 reg_dst = chunk->reg_idx++; 1252 u8 reg_dst = chunk->reg_idx++;
649 EMIT_OP(OP_LDGVAR, reg_dst, var.idx, 0, node, chunk); 1253 if (node->is_ptr || str_has_prefix(var.type, cstr("[]"))) {
1254 EMIT_OP(op_ldaddr, reg_dst, var.idx, 0, node, chunk);
1255 } else {
1256 EMIT_OP(op_ldvar, reg_dst, var.idx, 0, node, chunk);
1257 }
1258 return (CompResult){.type = COMP_REG, .idx = reg_dst};
1259 } break;
1260 case NODE_SYMBOL_IDX: {
1261 Str name = node->unique_name;
1262 StrVarMap *map = NULL;
1263 Chunk *next = chunk;
1264 while (next) {
1265 map = varmap_lookup(&next->varmap, name);
1266 if (map) {
1267 break;
1268 }
1269 next = chunk->parent;
1270 }
1271 if (!map) {
1272 println("error: unreachable symbol name: %s", name);
1273 exit(EXIT_FAILURE);
1274 }
1275 u8 op_ldaddr = OP_LDGADDR;
1276 u8 op_ldvar = OP_LDGVAR;
1277 if (!str_eq(next->name, cstr(".main"))) {
1278 op_ldaddr = OP_LDLADDR;
1279 op_ldvar = OP_LDLVAR;
1280 }
1281
1282 // Destination.
1283 u8 reg_dst = chunk->reg_idx++;
1284
1285 // Address.
1286 sz reg_addr = chunk->reg_idx++;
1287 if (str_has_prefix(map->val.type, cstr("[]"))) {
1288 EMIT_OP(op_ldaddr, reg_addr, map->val.idx, 0, node->var_val,
1289 chunk);
1290 } else {
1291 EMIT_OP(op_ldvar, reg_addr, map->val.idx, 0, node->var_val,
1292 chunk);
1293 }
1294
1295 // Index.
1296 CompResult idx =
1297 compile_expr(chunk, node->arr_size, lab_pre, lab_post);
1298 switch (idx.type) {
1299 case COMP_CONST: {
1300 EMIT_OP(OP_LD64I, reg_dst, reg_addr, idx.idx, node, chunk);
1301 } break;
1302 case COMP_REG: {
1303 EMIT_OP(OP_LD64, reg_dst, reg_addr, idx.idx, node, chunk);
1304 } break;
1305 default: {
1306 return (CompResult){.type = COMP_ERR};
1307 } break;
1308 }
1309 // TODO: hardcoding the type size for now (LD64/LD64I).
650 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 1310 return (CompResult){.type = COMP_REG, .idx = reg_dst};
651 } break; 1311 } break;
652 case NODE_BLOCK: { 1312 case NODE_BLOCK: {
653 CompResult res; 1313 CompResult res;
654 for (sz i = 0; i < array_size(node->elements); i++) { 1314 for (sz i = 0; i < array_size(node->elements); i++) {
655 Node *root = node->elements[i]; 1315 Node *root = node->elements[i];
656 res = compile_expr(chunk, root); 1316 res = compile_expr(chunk, root, lab_pre, lab_post);
657 } 1317 }
658 return res; 1318 return res;
659 } break; 1319 } break;
@@ -669,6 +1329,10 @@ compile_expr(Chunk *chunk, Node *node) {
669void 1329void
670disassemble_instruction(Instruction instruction) { 1330disassemble_instruction(Instruction instruction) {
671 switch (instruction.op) { 1331 switch (instruction.op) {
1332 case OP_CALL:
1333 println("%s f%d", op_str[instruction.op], instruction.dst,
1334 instruction.a, instruction.b);
1335 break;
672 case OP_MOV8: 1336 case OP_MOV8:
673 case OP_MOV16: 1337 case OP_MOV16:
674 case OP_MOV32: 1338 case OP_MOV32:
@@ -676,12 +1340,15 @@ disassemble_instruction(Instruction instruction) {
676 println("%s r%d, r%d", op_str[instruction.op], instruction.dst, 1340 println("%s r%d, r%d", op_str[instruction.op], instruction.dst,
677 instruction.a, instruction.b); 1341 instruction.a, instruction.b);
678 break; 1342 break;
1343 case OP_JMPF:
1344 case OP_JMPT:
1345 println("%s l%d, r%d", op_str[instruction.op], instruction.dst,
1346 instruction.a, instruction.b);
1347 break;
679 case OP_LD8K: 1348 case OP_LD8K:
680 case OP_LD16K: 1349 case OP_LD16K:
681 case OP_LD32K: 1350 case OP_LD32K:
682 case OP_LD64K: 1351 case OP_LD64K:
683 case OP_JMPF:
684 case OP_JMPT:
685 println("%s r%d, c%d", op_str[instruction.op], instruction.dst, 1352 println("%s r%d, c%d", op_str[instruction.op], instruction.dst,
686 instruction.a, instruction.b); 1353 instruction.a, instruction.b);
687 break; 1354 break;
@@ -752,14 +1419,19 @@ disassemble_instruction(Instruction instruction) {
752 instruction.a, instruction.b); 1419 instruction.a, instruction.b);
753 break; 1420 break;
754 case OP_LDGVAR: 1421 case OP_LDGVAR:
1422 case OP_LDGADDR:
1423 case OP_LDLVAR:
1424 case OP_LDLADDR:
755 println("%s r%d, v%d", op_str[instruction.op], instruction.dst, 1425 println("%s r%d, v%d", op_str[instruction.op], instruction.dst,
756 instruction.a, instruction.b); 1426 instruction.a, instruction.b);
757 break; 1427 break;
758 case OP_STGVAR: 1428 case OP_STGVAR:
1429 case OP_STLVAR:
759 println("%s v%d, r%d", op_str[instruction.op], instruction.dst, 1430 println("%s v%d, r%d", op_str[instruction.op], instruction.dst,
760 instruction.a, instruction.b); 1431 instruction.a, instruction.b);
761 break; 1432 break;
762 case OP_STGVARI: 1433 case OP_STGVARI:
1434 case OP_STLVARI:
763 println("%s v%d, c%d", op_str[instruction.op], instruction.dst, 1435 println("%s v%d, c%d", op_str[instruction.op], instruction.dst,
764 instruction.a, instruction.b); 1436 instruction.a, instruction.b);
765 break; 1437 break;
@@ -773,19 +1445,33 @@ disassemble_instruction(Instruction instruction) {
773 println("%s r%d, r%d", op_str[instruction.op], instruction.dst, 1445 println("%s r%d, r%d", op_str[instruction.op], instruction.dst,
774 instruction.a, instruction.b); 1446 instruction.a, instruction.b);
775 break; 1447 break;
776 case OP_JMPI:
777 println("%s c%d", op_str[instruction.op], instruction.dst,
778 instruction.a, instruction.b);
779 break;
780 case OP_JMP: 1448 case OP_JMP:
781 println("%s r%d", op_str[instruction.op], instruction.dst, 1449 println("%s l%d", op_str[instruction.op], instruction.dst,
782 instruction.a, instruction.b); 1450 instruction.a, instruction.b);
783 break; 1451 break;
784 case OP_JMPFI: 1452 case OP_JMPFI:
785 case OP_JMPTI: 1453 case OP_JMPTI:
786 println("%s c%d, c%d", op_str[instruction.op], instruction.dst, 1454 println("%s l%d, c%d", op_str[instruction.op], instruction.dst,
787 instruction.a, instruction.b); 1455 instruction.a, instruction.b);
788 break; 1456 break;
1457 case OP_PRINTS64:
1458 case OP_PRINTF64:
1459 case OP_PRINTSTR:
1460 case OP_PUSH:
1461 case OP_POP:
1462 case OP_PUTRET:
1463 println("%s r%d", op_str[instruction.op], instruction.dst,
1464 instruction.a, instruction.b);
1465 break;
1466 case OP_PRINTS64I:
1467 case OP_PRINTF64I:
1468 case OP_RESERVE:
1469 case OP_PUSHI:
1470 case OP_PUTRETI:
1471 println("%s c%d", op_str[instruction.op], instruction.dst,
1472 instruction.a, instruction.b);
1473 break;
1474 case OP_RET:
789 case OP_HALT: println("%s", op_str[instruction.op]); break; 1475 case OP_HALT: println("%s", op_str[instruction.op]); break;
790 default: println("Unknown opcode %d", instruction.op); break; 1476 default: println("Unknown opcode %d", instruction.op); break;
791 } 1477 }
@@ -793,36 +1479,56 @@ disassemble_instruction(Instruction instruction) {
793 1479
794void 1480void
795disassemble_chunk(Chunk chunk) { 1481disassemble_chunk(Chunk chunk) {
796 println("%s: ============== code ==============", chunk.file_name); 1482 println("CHUNK %d: %s%s", chunk.id, chunk.file_name, chunk.name);
1483 println("n_regs: %d, n_vars: %d, n_strings: %d, n_consts: %d",
1484 chunk.reg_idx, array_size(chunk.vars), chunk.str_idx,
1485 chunk.const_idx);
1486 println("================== code ==================");
1487 println(" LINE:COL INUM LABELS OP OPERANDS ");
1488 println("------------------------------------------");
797 for (sz i = 0; i < array_size(chunk.code); i++) { 1489 for (sz i = 0; i < array_size(chunk.code); i++) {
798 print("%s: %x{4}: ", chunk.file_name, i); 1490 printf(" %.4ld:%.4ld %.4lx ", chunk.linecol[i].line,
1491 chunk.linecol[i].col, i);
1492 IntIntMap *label = intintmap_lookup(&chunk.labels_rev, i);
1493 if (label) {
1494 printf(".L%.2ld ", label->val);
1495 } else {
1496 printf(" %2s ", "");
1497 }
799 disassemble_instruction(chunk.code[i]); 1498 disassemble_instruction(chunk.code[i]);
800 } 1499 }
801 if (array_size(chunk.constants) > 0) { 1500 if (array_size(chunk.constants) > 0) {
802 println("%s: ============ constants ===========", chunk.file_name); 1501 println("================ constants ===============", chunk.file_name);
803 for (sz i = 0; i < array_size(chunk.constants); i++) { 1502 for (sz i = 0; i < array_size(chunk.constants); i++) {
804 println("%s: %x{2}: %x{8}", chunk.file_name, i, 1503 println(" %x{2}: %x{8}", i, chunk.constants[i]);
805 chunk.constants[i]);
806 } 1504 }
807 } 1505 }
808 if (array_size(chunk.strings) > 0) { 1506 if (array_size(chunk.strings) > 0) {
809 println("%s: ============= strings ============", chunk.file_name); 1507 println("================= strings ================", chunk.file_name);
810 for (sz i = 0; i < array_size(chunk.strings); i++) { 1508 for (sz i = 0; i < array_size(chunk.strings); i++) {
811 println("%s: %x{2}: %s", chunk.file_name, i, chunk.strings[i]); 1509 println(" %x{2}: %s", i, chunk.strings[i]);
812 } 1510 }
813 } 1511 }
814 if (array_size(chunk.vars) > 0) { 1512 if (array_size(chunk.vars) > 0) {
815 println("%s: ============ variables ===========", chunk.file_name); 1513 println("================ variables ===============", chunk.file_name);
816 for (sz i = 0; i < array_size(chunk.vars); i++) { 1514 for (sz i = 0; i < array_size(chunk.vars); i++) {
817 println("%s: %x{2}: [%x{4}:%x{4}] %s: %s", chunk.file_name, i, 1515 println(" %x{2}: [%x{4}:%x{4}] %s: %s", i, chunk.vars[i].offset,
818 chunk.vars[i].offset,
819 chunk.vars[i].offset + chunk.vars[i].size, 1516 chunk.vars[i].offset + chunk.vars[i].size,
820 chunk.vars[i].name, chunk.vars[i].type); 1517 chunk.vars[i].name, chunk.vars[i].type);
821 } 1518 }
822 } 1519 }
823 println("n_regs: %d, n_vars: %d, n_strings: %d, n_consts: %d", 1520 if (array_size(chunk.functions) > 0) {
824 chunk.reg_idx, array_size(chunk.vars), chunk.str_idx, 1521 println("================ functions ===============", chunk.file_name);
825 chunk.const_idx); 1522 for (sz i = 0; i < array_size(chunk.functions); i++) {
1523 Chunk *func = chunk.functions[i];
1524 println(" %x{2}: func%d: %s", i, func->id, func->name);
1525 }
1526 }
1527 println("==========================================");
1528 for (sz i = 0; i < array_size(chunk.functions); i++) {
1529 Chunk *func = chunk.functions[i];
1530 disassemble_chunk(*func);
1531 }
826} 1532}
827 1533
828#endif // COMPILER_C 1534#endif // COMPILER_C
diff --git a/src/main.c b/src/main.c
index 0e453c6..533cadf 100644
--- a/src/main.c
+++ b/src/main.c
@@ -12,7 +12,29 @@
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: for loops?
17// for i = 0 , i < 10 , i++ {
18// ...
19// }
20// TODO: fix semantics for the following expression:
21// let b = int
22// a type shouldn't be a valid symbol name
23// TODO: consider making all tye types PascalCase: Int F64 Str...
24// TODO: add a `const` keyword that can only take literals or constexpr values.
25// TODO: add assignment operators instead of `set` :=, +=, -=
26// TODO: add mifix operators ++ and --
27// TODO: locals should probably be zero-initialized when we are performing
28// a function call to avoid issues.
29// TODO: nested function compilation
30// TODO: "first class functions" via function pointers
31// TODO: convenient function calls per data type instead of methods:
32// fun add(a: int, b: int): int a + b
33// add(12, 34) == 12.add(34)
34// concat(str, str): str
35// "hello ".concat("world") ; "hello world"
36// TODO: refactor the parser to more clearly show the different node type, data
37// fields.
16 38
17typedef enum ExecMode { 39typedef enum ExecMode {
18 RUN_NORMAL, 40 RUN_NORMAL,
@@ -167,7 +189,11 @@ process_file(Str path) {
167 189
168 // Compile roots. 190 // Compile roots.
169 Arena bytecode_arena = arena_create(LEXER_MEM, os_allocator); 191 Arena bytecode_arena = arena_create(LEXER_MEM, os_allocator);
170 Chunk chunk = {.file_name = path, .storage = &bytecode_arena}; 192 Chunk chunk = {
193 .file_name = path,
194 .storage = &bytecode_arena,
195 .name = cstr(".main"),
196 };
171 array_zero(chunk.constants, 256, &bytecode_arena); 197 array_zero(chunk.constants, 256, &bytecode_arena);
172 array_zero(chunk.code, 0xffff, &bytecode_arena); 198 array_zero(chunk.code, 0xffff, &bytecode_arena);
173 sz n_roots = array_size(parser.nodes); 199 sz n_roots = array_size(parser.nodes);
@@ -175,13 +201,15 @@ process_file(Str path) {
175 for (sz i = 0; i < n_roots; i++) { 201 for (sz i = 0; i < n_roots; i++) {
176 // The parser stores the root nodes as a stack. 202 // The parser stores the root nodes as a stack.
177 Node *root = parser.nodes[i]; 203 Node *root = parser.nodes[i];
178 res = compile_expr(&chunk, root); 204 res = compile_expr(&chunk, root, -1, -1);
179 if (res.type == COMP_ERR) { 205 if (res.type == COMP_ERR) {
180 eprintln("compilation error..."); 206 eprintln("compilation error...");
181 exit(EXIT_FAILURE); 207 exit(EXIT_FAILURE);
182 } 208 }
183 } 209 }
210 // Make sure the last result is on r0.
184 sz res_reg = 0; 211 sz res_reg = 0;
212 bool is_nil = false;
185 switch (res.type) { 213 switch (res.type) {
186 case COMP_CONST: { 214 case COMP_CONST: {
187 res_reg = chunk.reg_idx++; 215 res_reg = chunk.reg_idx++;
@@ -192,11 +220,12 @@ process_file(Str path) {
192 case COMP_REG: { 220 case COMP_REG: {
193 res_reg = res.idx; 221 res_reg = res.idx;
194 } break; 222 } break;
223 case COMP_NIL: {
224 is_nil = true;
225 } break;
195 default: break; 226 default: break;
196 } 227 }
197 // After we are done move the last result to r0 for printing. 228 EMIT_OP(OP_HALT, res_reg, !is_nil, 0, NULL, &chunk);
198 Instruction halt = (Instruction){.op = OP_HALT, .dst = res_reg};
199 array_push(chunk.code, halt, &bytecode_arena);
200 229
201 if (chunk.const_idx >= 256) { 230 if (chunk.const_idx >= 256) {
202 eprintln("too many constants on chunk %s", chunk.id); 231 eprintln("too many constants on chunk %s", chunk.id);
@@ -219,10 +248,10 @@ process_file(Str path) {
219 // println("VM REGISTERS BEFORE:\n%{Mem}", 248 // println("VM REGISTERS BEFORE:\n%{Mem}",
220 // &(Array){.mem = (u8 *)&vm.regs, sizeof(vm.regs)}); 249 // &(Array){.mem = (u8 *)&vm.regs, sizeof(vm.regs)});
221 vm_run(&vm); 250 vm_run(&vm);
222 // println("VM REGISTERS AFTER:\n%{Mem}", 251#if DEBUG == 1
223 // &(Array){.mem = (u8 *)&vm.regs, sizeof(vm.regs)}); 252 println("MEMORY:\n%{Mem}",
224 // println("VM MEMORY AFTER:\n%{Mem}", 253 &(Array){.mem = (u8 *)&vm.stack, sizeof(vm.stack)});
225 // &(Array){.mem = (u8 *)&vm.stack, sizeof(vm.stack)}); 254#endif
226 255
227#if DEBUG == 1 256#if DEBUG == 1
228 println("Space used: %{Arena}", &lexer_arena); 257 println("Space used: %{Arena}", &lexer_arena);
diff --git a/src/parser.c b/src/parser.c
index 90adaf3..ace7160 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -132,6 +132,7 @@ typedef struct Node {
132 sz id; 132 sz id;
133 sz line; 133 sz line;
134 sz col; 134 sz col;
135 struct Node *parent;
135 136
136 NodeKind kind; 137 NodeKind kind;
137 union { 138 union {
@@ -193,7 +194,6 @@ typedef struct Node {
193 }; 194 };
194 }; 195 };
195 bool is_ptr; 196 bool is_ptr;
196 struct Scope *scope;
197 Str type; 197 Str type;
198 Str fun_params; 198 Str fun_params;
199 Str fun_return; 199 Str fun_return;
diff --git a/src/semantic.c b/src/semantic.c
index d782cac..386d143 100644
--- a/src/semantic.c
+++ b/src/semantic.c
@@ -390,11 +390,12 @@ typecheck_returns(Analyzer *a, Node *node, Str expected) {
390 } 390 }
391 } break; 391 } break;
392 case NODE_RETURN: { 392 case NODE_RETURN: {
393 bool err = !str_eq(node->type, expected); 393 Str type = str_remove_prefix(node->type, cstr("ret:"));
394 bool err = !str_eq(type, expected);
394 if (err) { 395 if (err) {
395 eprintln( 396 eprintln(
396 "%s:%d:%d: error: mismatched return type %s, expected %s", 397 "%s:%d:%d: error: mismatched return type %s, expected %s",
397 a->file_name, node->line, node->col, node->type, expected); 398 a->file_name, node->line, node->col, type, expected);
398 a->err = true; 399 a->err = true;
399 } 400 }
400 } break; 401 } break;
@@ -452,13 +453,14 @@ Str
452type_inference(Analyzer *a, Node *node, Scope *scope) { 453type_inference(Analyzer *a, Node *node, Scope *scope) {
453 assert(a); 454 assert(a);
454 assert(scope); 455 assert(scope);
455 if (!node) { 456 if (!node || a->err) {
456 return cstr(""); 457 return cstr("");
457 } 458 }
458 // NOTE: For now we are not going to do implicit numeric conversions. 459 // NOTE: For now we are not going to do implicit numeric conversions.
459 switch (node->kind) { 460 switch (node->kind) {
460 case NODE_LET: { 461 case NODE_LET: {
461 node->type = cstr("nil"); 462 node->type = cstr("nil");
463 node->var_name->parent = node;
462 Str symbol = node->var_name->value.str; 464 Str symbol = node->var_name->value.str;
463 if (symmap_lookup(&scope->symbols, symbol)) { 465 if (symmap_lookup(&scope->symbols, symbol)) {
464 eprintln( 466 eprintln(
@@ -470,6 +472,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
470 return cstr(""); 472 return cstr("");
471 } 473 }
472 if (node->var_type) { 474 if (node->var_type) {
475 node->var_type->parent = node;
473 Str type_name = node->var_type->value.str; 476 Str type_name = node->var_type->value.str;
474 SymbolMap *type = find_type(scope, type_name); 477 SymbolMap *type = find_type(scope, type_name);
475 if (type == NULL) { 478 if (type == NULL) {
@@ -484,10 +487,17 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
484 } 487 }
485 if (node->var_type->kind == NODE_ARR_TYPE) { 488 if (node->var_type->kind == NODE_ARR_TYPE) {
486 type_name = str_concat(cstr("@"), type_name, a->storage); 489 type_name = str_concat(cstr("@"), type_name, a->storage);
487 // TODO: typecheck size 490 if (node->var_type->arr_size->value.i == 0) {
491 eprintln("%s:%d:%d: error: zero sized array '%s'",
492 a->file_name, node->var_type->line,
493 node->var_type->col, symbol);
494 a->err = true;
495 return cstr("");
496 }
488 // TODO: register array in scope 497 // TODO: register array in scope
489 } 498 }
490 if (node->var_val) { 499 if (node->var_val) {
500 node->var_val->parent = node;
491 Str type = type_inference(a, node->var_val, scope); 501 Str type = type_inference(a, node->var_val, scope);
492 if (!type.size) { 502 if (!type.size) {
493 eprintln( 503 eprintln(
@@ -521,17 +531,29 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
521 .kind = SYM_VAR, 531 .kind = SYM_VAR,
522 }, 532 },
523 a->storage); 533 a->storage);
534 node->var_name->type = type_name;
535 symbol = str_concat(cstr("."), symbol, a->storage);
536 symbol = str_concat(symbol, str_from_int(scope->id, a->storage),
537 a->storage);
538 node->unique_name = symbol;
524 return node->type; 539 return node->type;
525 } 540 }
526 541
527 // We don't know the type for this symbol, perform inference. 542 // We don't know the type for this symbol, perform inference.
543 node->var_val->parent = node;
528 Str type = type_inference(a, node->var_val, scope); 544 Str type = type_inference(a, node->var_val, scope);
529 if (type.size) { 545 if (!type.size || str_eq(type, cstr("nil")) ||
530 symmap_insert(&scope->symbols, symbol, 546 str_has_prefix(type, cstr("ret:"))) {
531 (Symbol){.name = type, .kind = SYM_VAR}, 547 eprintln(
532 a->storage); 548 "%s:%d:%d: error: can't bind `nil` to variable "
533 node->var_name->type = type; 549 "'%s'",
550 a->file_name, node->line, node->col, symbol);
551 a->err = true;
552 return cstr("");
534 } 553 }
554 symmap_insert(&scope->symbols, symbol,
555 (Symbol){.name = type, .kind = SYM_VAR}, a->storage);
556 node->var_name->type = type;
535 symbol = str_concat(cstr("."), symbol, a->storage); 557 symbol = str_concat(cstr("."), symbol, a->storage);
536 symbol = str_concat(symbol, str_from_int(scope->id, a->storage), 558 symbol = str_concat(symbol, str_from_int(scope->id, a->storage),
537 a->storage); 559 a->storage);
@@ -539,6 +561,8 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
539 return node->type; 561 return node->type;
540 } break; 562 } break;
541 case NODE_SET: { 563 case NODE_SET: {
564 node->var_name->parent = node;
565 node->var_val->parent = node;
542 Str name = type_inference(a, node->var_name, scope); 566 Str name = type_inference(a, node->var_name, scope);
543 Str val = type_inference(a, node->var_val, scope); 567 Str val = type_inference(a, node->var_val, scope);
544 if (!str_eq(name, val)) { 568 if (!str_eq(name, val)) {
@@ -550,6 +574,12 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
550 a->err = true; 574 a->err = true;
551 return cstr(""); 575 return cstr("");
552 } 576 }
577 Str symbol = node->var_name->value.str;
578 FindSymbolResult sym = find_symbol(scope, symbol);
579 node->unique_name = str_concat(cstr("."), symbol, a->storage);
580 node->unique_name =
581 str_concat(node->unique_name,
582 str_from_int(sym.scope->id, a->storage), a->storage);
553 node->type = cstr("nil"); 583 node->type = cstr("nil");
554 return node->type; 584 return node->type;
555 } break; 585 } break;
@@ -568,6 +598,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
568 a->storage); 598 a->storage);
569 for (sz i = 0; i < array_size(node->struct_field); i++) { 599 for (sz i = 0; i < array_size(node->struct_field); i++) {
570 Node *field = node->struct_field[i]; 600 Node *field = node->struct_field[i];
601 field->parent = node;
571 typecheck_field(a, field, scope, symbol); 602 typecheck_field(a, field, scope, symbol);
572 } 603 }
573 symmap_insert(&scope->symbols, symbol, 604 symmap_insert(&scope->symbols, symbol,
@@ -594,6 +625,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
594 a->storage); 625 a->storage);
595 for (sz i = 0; i < array_size(node->struct_field); i++) { 626 for (sz i = 0; i < array_size(node->struct_field); i++) {
596 Node *field = node->struct_field[i]; 627 Node *field = node->struct_field[i];
628 field->parent = node;
597 Str field_name = str_concat(symbol, cstr("."), a->storage); 629 Str field_name = str_concat(symbol, cstr("."), a->storage);
598 field_name = 630 field_name =
599 str_concat(field_name, field->value.str, a->storage); 631 str_concat(field_name, field->value.str, a->storage);
@@ -626,6 +658,8 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
626 return node->type; 658 return node->type;
627 } break; 659 } break;
628 case NODE_IF: { 660 case NODE_IF: {
661 node->cond_if->parent = node;
662 node->cond_expr->parent = node;
629 Str cond_type = type_inference(a, node->cond_if, scope); 663 Str cond_type = type_inference(a, node->cond_if, scope);
630 if (!str_eq(cond_type, cstr("bool"))) { 664 if (!str_eq(cond_type, cstr("bool"))) {
631 emit_semantic_error( 665 emit_semantic_error(
@@ -640,6 +674,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
640 node->type = type_inference(a, node->cond_expr, next); 674 node->type = type_inference(a, node->cond_expr, next);
641 } 675 }
642 if (node->cond_else) { 676 if (node->cond_else) {
677 node->cond_else->parent = node;
643 Str else_type; 678 Str else_type;
644 if (node->cond_else->kind == NODE_BLOCK) { 679 if (node->cond_else->kind == NODE_BLOCK) {
645 else_type = type_inference(a, node->cond_else, scope); 680 else_type = type_inference(a, node->cond_else, scope);
@@ -647,19 +682,34 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
647 Scope *next = typescope_alloc(a, scope); 682 Scope *next = typescope_alloc(a, scope);
648 else_type = type_inference(a, node->cond_else, next); 683 else_type = type_inference(a, node->cond_else, next);
649 } 684 }
650 if (!str_eq(node->type, else_type)) { 685 if (!str_eq(node->type, else_type) &&
686 !str_has_prefix(node->type, cstr("ret:")) &&
687 !str_has_prefix(node->type, cstr("flow:"))) {
651 emit_semantic_error( 688 emit_semantic_error(
652 a, node, cstr("mismatch types for if/else branches")); 689 a, node, cstr("mismatch types for if/else branches"));
653 return cstr(""); 690 return cstr("");
654 } 691 }
655 } 692 }
693 // If it returns a value, verify it contains an `else` statement.
694 if (!str_eq(node->type, cstr("nil")) &&
695 !str_has_prefix(node->type, cstr("ret:")) &&
696 !str_has_prefix(node->type, cstr("flow:"))) {
697 if (!node->cond_else) {
698 emit_semantic_error(
699 a, node,
700 cstr("missing else statement in if expression"));
701 return cstr("");
702 }
703 }
656 return node->type; 704 return node->type;
657 } break; 705 } break;
658 case NODE_WHILE: { 706 case NODE_WHILE: {
707 node->while_cond->parent = node;
708 node->while_expr->parent = node;
659 Str cond_type = type_inference(a, node->while_cond, scope); 709 Str cond_type = type_inference(a, node->while_cond, scope);
660 if (!str_eq(cond_type, cstr("bool"))) { 710 if (!str_eq(cond_type, cstr("bool"))) {
661 emit_semantic_error( 711 emit_semantic_error(
662 a, node->cond_if, 712 a, node->while_cond,
663 cstr("non boolean expression on while condition")); 713 cstr("non boolean expression on while condition"));
664 return cstr(""); 714 return cstr("");
665 } 715 }
@@ -672,8 +722,10 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
672 } break; 722 } break;
673 case NODE_COND: { 723 case NODE_COND: {
674 Str previous = cstr(""); 724 Str previous = cstr("");
725 bool has_else = false;
675 for (sz i = 0; i < array_size(node->match_cases); i++) { 726 for (sz i = 0; i < array_size(node->match_cases); i++) {
676 Node *expr = node->match_cases[i]; 727 Node *expr = node->match_cases[i];
728 expr->parent = node;
677 Str next = type_inference(a, expr, scope); 729 Str next = type_inference(a, expr, scope);
678 if (i != 0 && !str_eq(next, previous)) { 730 if (i != 0 && !str_eq(next, previous)) {
679 emit_semantic_error( 731 emit_semantic_error(
@@ -681,17 +733,33 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
681 cstr("non-matching types for cond expressions")); 733 cstr("non-matching types for cond expressions"));
682 return cstr(""); 734 return cstr("");
683 } 735 }
736 if (!expr->case_value) {
737 has_else = true;
738 }
684 previous = next; 739 previous = next;
685 } 740 }
741 // If it returns a value, verify it contains an `else` statement.
742 if (!str_eq(node->type, cstr("nil")) &&
743 !str_has_prefix(node->type, cstr("ret:")) &&
744 !str_has_prefix(node->type, cstr("flow:"))) {
745 if (!has_else) {
746 emit_semantic_error(
747 a, node,
748 cstr("missing else statement in cond expression"));
749 return cstr("");
750 }
751 }
686 node->type = previous; 752 node->type = previous;
687 return node->type; 753 return node->type;
688 } break; 754 } break;
689 case NODE_MATCH: { 755 case NODE_MATCH: {
756 node->match_expr->parent = node;
690 Str e = type_inference(a, node->match_expr, scope); 757 Str e = type_inference(a, node->match_expr, scope);
691 if (str_eq(e, cstr("int"))) { 758 if (str_eq(e, cstr("int"))) {
692 // Integer matching. 759 // Integer matching.
693 for (sz i = 0; i < array_size(node->match_cases); i++) { 760 for (sz i = 0; i < array_size(node->match_cases); i++) {
694 Node *field = node->match_cases[i]; 761 Node *field = node->match_cases[i];
762 field->parent = node;
695 if (field->case_value) { 763 if (field->case_value) {
696 if (field->case_value->kind != NODE_NUM_INT && 764 if (field->case_value->kind != NODE_NUM_INT &&
697 field->case_value->kind != NODE_NUM_UINT) { 765 field->case_value->kind != NODE_NUM_UINT) {
@@ -709,6 +777,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
709 str_concat(res.map->val.name, cstr("."), a->storage); 777 str_concat(res.map->val.name, cstr("."), a->storage);
710 for (sz i = 0; i < array_size(node->match_cases); i++) { 778 for (sz i = 0; i < array_size(node->match_cases); i++) {
711 Node *field = node->match_cases[i]; 779 Node *field = node->match_cases[i];
780 field->parent = node;
712 if (field->case_value) { 781 if (field->case_value) {
713 Str field_name = str_concat( 782 Str field_name = str_concat(
714 enum_prefix, field->case_value->value.str, 783 enum_prefix, field->case_value->value.str,
@@ -725,6 +794,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
725 Str previous = cstr(""); 794 Str previous = cstr("");
726 for (sz i = 0; i < array_size(node->match_cases); i++) { 795 for (sz i = 0; i < array_size(node->match_cases); i++) {
727 Node *expr = node->match_cases[i]; 796 Node *expr = node->match_cases[i];
797 expr->parent = node;
728 Str next = type_inference(a, expr, scope); 798 Str next = type_inference(a, expr, scope);
729 if (i != 0 && !str_eq(next, previous)) { 799 if (i != 0 && !str_eq(next, previous)) {
730 emit_semantic_error( 800 emit_semantic_error(
@@ -741,11 +811,14 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
741 if (node->case_expr->kind != NODE_BLOCK) { 811 if (node->case_expr->kind != NODE_BLOCK) {
742 scope = typescope_alloc(a, scope); 812 scope = typescope_alloc(a, scope);
743 } 813 }
814 node->case_expr->parent = node;
744 node->type = type_inference(a, node->case_expr, scope); 815 node->type = type_inference(a, node->case_expr, scope);
745 return node->type; 816 return node->type;
746 } break; 817 } break;
747 case NODE_CASE_COND: { 818 case NODE_CASE_COND: {
819 node->case_expr->parent = node;
748 if (node->case_value) { 820 if (node->case_value) {
821 node->case_value->parent = node;
749 Str cond = type_inference(a, node->case_value, scope); 822 Str cond = type_inference(a, node->case_value, scope);
750 if (!str_eq(cond, cstr("bool"))) { 823 if (!str_eq(cond, cstr("bool"))) {
751 emit_semantic_error(a, node, 824 emit_semantic_error(a, node,
@@ -770,6 +843,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
770 case NODE_NOT: 843 case NODE_NOT:
771 case NODE_AND: 844 case NODE_AND:
772 case NODE_OR: { 845 case NODE_OR: {
846 node->left->parent = node;
773 Str left = type_inference(a, node->left, scope); 847 Str left = type_inference(a, node->left, scope);
774 if (!str_eq(left, cstr("bool"))) { 848 if (!str_eq(left, cstr("bool"))) {
775 emit_semantic_error(a, node, 849 emit_semantic_error(a, node,
@@ -777,6 +851,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
777 return cstr(""); 851 return cstr("");
778 } 852 }
779 if (node->right) { 853 if (node->right) {
854 node->right->parent = node;
780 Str right = type_inference(a, node->right, scope); 855 Str right = type_inference(a, node->right, scope);
781 if (!str_eq(right, cstr("bool"))) { 856 if (!str_eq(right, cstr("bool"))) {
782 emit_semantic_error( 857 emit_semantic_error(
@@ -793,6 +868,8 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
793 case NODE_GT: 868 case NODE_GT:
794 case NODE_LE: 869 case NODE_LE:
795 case NODE_GE: { 870 case NODE_GE: {
871 node->left->parent = node;
872 node->right->parent = node;
796 Str left = type_inference(a, node->left, scope); 873 Str left = type_inference(a, node->left, scope);
797 Str right = type_inference(a, node->right, scope); 874 Str right = type_inference(a, node->right, scope);
798 if (!str_eq(left, right)) { 875 if (!str_eq(left, right)) {
@@ -804,6 +881,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
804 return node->type; 881 return node->type;
805 } break; 882 } break;
806 case NODE_BITNOT: { 883 case NODE_BITNOT: {
884 node->left->parent = node;
807 Str left = type_inference(a, node->left, scope); 885 Str left = type_inference(a, node->left, scope);
808 if (!strset_lookup(&a->integer_types, left)) { 886 if (!strset_lookup(&a->integer_types, left)) {
809 emit_semantic_error( 887 emit_semantic_error(
@@ -817,6 +895,8 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
817 case NODE_BITOR: 895 case NODE_BITOR:
818 case NODE_BITLSHIFT: 896 case NODE_BITLSHIFT:
819 case NODE_BITRSHIFT: { 897 case NODE_BITRSHIFT: {
898 node->left->parent = node;
899 node->right->parent = node;
820 Str left = type_inference(a, node->left, scope); 900 Str left = type_inference(a, node->left, scope);
821 Str right = type_inference(a, node->right, scope); 901 Str right = type_inference(a, node->right, scope);
822 if (!strset_lookup(&a->integer_types, left) || 902 if (!strset_lookup(&a->integer_types, left) ||
@@ -833,6 +913,8 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
833 case NODE_DIV: 913 case NODE_DIV:
834 case NODE_MUL: 914 case NODE_MUL:
835 case NODE_MOD: { 915 case NODE_MOD: {
916 node->left->parent = node;
917 node->right->parent = node;
836 Str left = type_inference(a, node->left, scope); 918 Str left = type_inference(a, node->left, scope);
837 Str right = type_inference(a, node->right, scope); 919 Str right = type_inference(a, node->right, scope);
838 if (!strset_lookup(&a->numeric_types, left) || 920 if (!strset_lookup(&a->numeric_types, left) ||
@@ -850,7 +932,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
850 return node->type; 932 return node->type;
851 } break; 933 } break;
852 case NODE_NUM_UINT: { 934 case NODE_NUM_UINT: {
853 node->type = cstr("uint"); 935 node->type = cstr("int");
854 return node->type; 936 return node->type;
855 } break; 937 } break;
856 case NODE_NUM_INT: { 938 case NODE_NUM_INT: {
@@ -894,6 +976,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
894 976
895 Str type_name = type->val.name; 977 Str type_name = type->val.name;
896 if (node->kind == NODE_SYMBOL_IDX) { 978 if (node->kind == NODE_SYMBOL_IDX) {
979 node->arr_size->parent = node;
897 Str idx_type = type_inference(a, node->arr_size, scope); 980 Str idx_type = type_inference(a, node->arr_size, scope);
898 if (!strset_lookup(&a->integer_types, idx_type)) { 981 if (!strset_lookup(&a->integer_types, idx_type)) {
899 emit_semantic_error( 982 emit_semantic_error(
@@ -964,6 +1047,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
964 } 1047 }
965 Str field_type = field->val.type; 1048 Str field_type = field->val.type;
966 if (next->kind == NODE_SYMBOL_IDX) { 1049 if (next->kind == NODE_SYMBOL_IDX) {
1050 node->arr_size->parent = node;
967 Str idx_type = 1051 Str idx_type =
968 type_inference(a, next->arr_size, scope); 1052 type_inference(a, next->arr_size, scope);
969 if (!strset_lookup(&a->integer_types, idx_type)) { 1053 if (!strset_lookup(&a->integer_types, idx_type)) {
@@ -996,6 +1080,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
996 StrSet *set = NULL; 1080 StrSet *set = NULL;
997 for (sz i = 0; i < array_size(node->elements); i++) { 1081 for (sz i = 0; i < array_size(node->elements); i++) {
998 Node *next = node->elements[i]; 1082 Node *next = node->elements[i];
1083 next->parent = node;
999 Str field_name = str_concat(name, cstr("."), a->storage); 1084 Str field_name = str_concat(name, cstr("."), a->storage);
1000 field_name = 1085 field_name =
1001 str_concat(field_name, next->value.str, a->storage); 1086 str_concat(field_name, next->value.str, a->storage);
@@ -1025,10 +1110,17 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
1025 a->err = true; 1110 a->err = true;
1026 return cstr(""); 1111 return cstr("");
1027 } 1112 }
1113 FindSymbolResult sym = find_symbol(scope, symbol);
1114 node->unique_name = str_concat(cstr("."), symbol, a->storage);
1115 node->unique_name =
1116 str_concat(node->unique_name,
1117 str_from_int(sym.scope->id, a->storage), a->storage);
1118
1028 // Check that actual parameters typecheck 1119 // Check that actual parameters typecheck
1029 Str args = cstr(""); 1120 Str args = cstr("");
1030 for (sz i = 0; i < array_size(node->elements); i++) { 1121 for (sz i = 0; i < array_size(node->elements); i++) {
1031 Node *expr = node->elements[i]; 1122 Node *expr = node->elements[i];
1123 expr->parent = node;
1032 Str type = type_inference(a, expr, scope); 1124 Str type = type_inference(a, expr, scope);
1033 args = str_concat(args, type, a->storage); 1125 args = str_concat(args, type, a->storage);
1034 if (i != array_size(node->elements) - 1) { 1126 if (i != array_size(node->elements) - 1) {
@@ -1054,15 +1146,27 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
1054 Str type; 1146 Str type;
1055 for (sz i = 0; i < array_size(node->elements); i++) { 1147 for (sz i = 0; i < array_size(node->elements); i++) {
1056 Node *expr = node->elements[i]; 1148 Node *expr = node->elements[i];
1149 expr->parent = node;
1057 type = type_inference(a, expr, scope); 1150 type = type_inference(a, expr, scope);
1151 if (str_has_prefix(type, cstr("ret:")) ||
1152 str_has_prefix(type, cstr("flow:"))) {
1153 break;
1154 }
1058 } 1155 }
1059 node->type = type; 1156 node->type = type;
1060 return node->type; 1157 return node->type;
1061 } break; 1158 } break;
1062 case NODE_RETURN: { 1159 case NODE_RETURN: {
1063 Str ret_type = cstr(""); 1160 if (!scope->name.size) {
1161 emit_semantic_error(
1162 a, node, cstr("return statement outside a function"));
1163 a->err = true;
1164 return cstr("");
1165 }
1166 Str ret_type = cstr("ret:");
1064 for (sz i = 0; i < array_size(node->elements); i++) { 1167 for (sz i = 0; i < array_size(node->elements); i++) {
1065 Node *expr = node->elements[i]; 1168 Node *expr = node->elements[i];
1169 expr->parent = node;
1066 Str type = type_inference(a, expr, scope); 1170 Str type = type_inference(a, expr, scope);
1067 ret_type = str_concat(ret_type, type, a->storage); 1171 ret_type = str_concat(ret_type, type, a->storage);
1068 if (i != array_size(node->elements) - 1) { 1172 if (i != array_size(node->elements) - 1) {
@@ -1075,6 +1179,28 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
1075 node->type = ret_type; 1179 node->type = ret_type;
1076 return node->type; 1180 return node->type;
1077 } break; 1181 } break;
1182 case NODE_CONTINUE:
1183 case NODE_BREAK: {
1184 // Check if we are inside a loop.
1185 Node *parent = node->parent;
1186 bool inside_loop = false;
1187 while (parent != NULL) {
1188 if (parent->kind == NODE_WHILE) {
1189 inside_loop = true;
1190 break;
1191 }
1192 parent = parent->parent;
1193 }
1194 if (!inside_loop) {
1195 eprintln(
1196 "%s:%d:%d: error: control flow statement outside a loop",
1197 a->file_name, node->line, node->col);
1198 a->err = true;
1199 return cstr("");
1200 }
1201 node->type = cstr("flow:");
1202 return node->type;
1203 } break;
1078 case NODE_FUN: { 1204 case NODE_FUN: {
1079 node->type = cstr("nil"); 1205 node->type = cstr("nil");
1080 Scope *prev_scope = scope; 1206 Scope *prev_scope = scope;
@@ -1082,6 +1208,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
1082 Str param_type = cstr(""); 1208 Str param_type = cstr("");
1083 for (sz i = 0; i < array_size(node->func_params); i++) { 1209 for (sz i = 0; i < array_size(node->func_params); i++) {
1084 Node *param = node->func_params[i]; 1210 Node *param = node->func_params[i];
1211 param->parent = node;
1085 Str symbol = param->param_name->value.str; 1212 Str symbol = param->param_name->value.str;
1086 Str type = param->param_type->value.str; 1213 Str type = param->param_type->value.str;
1087 if (param->param_type->is_ptr) { 1214 if (param->param_type->is_ptr) {
@@ -1100,6 +1227,10 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
1100 if (i != array_size(node->func_params) - 1) { 1227 if (i != array_size(node->func_params) - 1) {
1101 param_type = str_concat(param_type, cstr(","), a->storage); 1228 param_type = str_concat(param_type, cstr(","), a->storage);
1102 } 1229 }
1230 symbol = str_concat(cstr("."), symbol, a->storage);
1231 symbol = str_concat(symbol, str_from_int(scope->id, a->storage),
1232 a->storage);
1233 param->unique_name = symbol;
1103 } 1234 }
1104 if (!param_type.size) { 1235 if (!param_type.size) {
1105 param_type = cstr("nil"); 1236 param_type = cstr("nil");
@@ -1109,6 +1240,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
1109 Str ret_type = cstr(""); 1240 Str ret_type = cstr("");
1110 for (sz i = 0; i < array_size(node->func_ret); i++) { 1241 for (sz i = 0; i < array_size(node->func_ret); i++) {
1111 Node *expr = node->func_ret[i]; 1242 Node *expr = node->func_ret[i];
1243 expr->parent = node;
1112 Str type = type_inference(a, expr, scope); 1244 Str type = type_inference(a, expr, scope);
1113 if (expr->is_ptr) { 1245 if (expr->is_ptr) {
1114 type = str_concat(cstr("@"), type, a->storage); 1246 type = str_concat(cstr("@"), type, a->storage);
@@ -1148,11 +1280,17 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
1148 .param_type = param_type, 1280 .param_type = param_type,
1149 .return_type = ret_type}, 1281 .return_type = ret_type},
1150 a->storage); 1282 a->storage);
1283 symbol = str_concat(cstr("."), symbol, a->storage);
1284 symbol = str_concat(
1285 symbol, str_from_int(prev_scope->id, a->storage), a->storage);
1286 node->unique_name = symbol;
1151 1287
1152 if (node->func_body->kind == NODE_BLOCK) { 1288 if (node->func_body->kind == NODE_BLOCK) {
1153 Str type; 1289 Str type;
1154 for (sz i = 0; i < array_size(node->func_body->elements); i++) { 1290 for (sz i = 0; i < array_size(node->func_body->elements); i++) {
1155 Node *expr = node->func_body->elements[i]; 1291 Node *expr = node->func_body->elements[i];
1292 expr->parent = node;
1293 // TODO: block early return.
1156 type = type_inference(a, expr, scope); 1294 type = type_inference(a, expr, scope);
1157 } 1295 }
1158 if (!type.size) { 1296 if (!type.size) {
@@ -1160,15 +1298,17 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
1160 } 1298 }
1161 node->func_body->type = type; 1299 node->func_body->type = type;
1162 } else { 1300 } else {
1301 node->func_body->parent = node;
1163 type_inference(a, node->func_body, scope); 1302 type_inference(a, node->func_body, scope);
1164 } 1303 }
1165 1304
1166 // Ensure main body return matches the prototype. 1305 // Ensure main body return matches the prototype.
1167 if (!str_eq(node->func_body->type, ret_type)) { 1306 Str type = str_remove_prefix(node->func_body->type, cstr("ret:"));
1307 node->func_body->type = type;
1308 if (!str_eq(type, ret_type)) {
1168 eprintln( 1309 eprintln(
1169 "%s:%d:%d: error: mismatched return type %s, expected %s", 1310 "%s:%d:%d: error: mismatched return type %s, expected %s",
1170 a->file_name, node->line, node->col, node->func_body->type, 1311 a->file_name, node->line, node->col, type, ret_type);
1171 ret_type);
1172 a->err = true; 1312 a->err = true;
1173 } 1313 }
1174 1314
@@ -1179,10 +1319,11 @@ type_inference(Analyzer *a, Node *node, Scope *scope) {
1179 return node->type; 1319 return node->type;
1180 } break; 1320 } break;
1181 default: { 1321 default: {
1182 emit_semantic_error(a, node, 1322 eprintln(
1183 cstr("type inference not implemented for this " 1323 "%s:%d:%d: error: type inference not implemented for node "
1184 "kind of expression")); 1324 "type: %s",
1185 println("KIND: %s", node_str[node->kind]); 1325 a->file_name, node->line, node->col, node_str[node->kind]);
1326 a->err = true;
1186 } break; 1327 } break;
1187 } 1328 }
1188 return cstr(""); 1329 return cstr("");
diff --git a/src/vm.c b/src/vm.c
index 205c15a..392c7e8 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -7,10 +7,13 @@
7#define N_CONST 256 7#define N_CONST 256
8#define STACK_SIZE KB(64) 8#define STACK_SIZE KB(64)
9typedef struct VM { 9typedef 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
16void 19void
@@ -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) \
@@ -134,61 +142,115 @@ vm_run(VM *vm) {
134 vm->regs[dst].f = 142 vm->regs[dst].f =
135 fmod(vm->regs[src_a].f, vm->chunk->constants[src_b].f); 143 fmod(vm->regs[src_a].f, vm->chunk->constants[src_b].f);
136 } break; 144 } break;
145 case OP_STGVAR: {
146 u8 dst = instruction.dst;
147 u8 src = instruction.a;
148 Variable var = vm->chunk->vars[dst];
149 s64 *stack = (s64 *)&vm->stack[var.offset];
150 *stack = vm->regs[src].i;
151 } break;
152 case OP_STGVARI: {
153 u8 dst = instruction.dst;
154 u8 src = instruction.a;
155 Variable var = vm->main->vars[dst];
156 s64 *stack = (s64 *)&vm->stack[var.offset];
157 *stack = vm->chunk->constants[src].i;
158 } break;
137 case OP_LDGVAR: { 159 case OP_LDGVAR: {
138 u8 dst = instruction.dst; 160 u8 dst = instruction.dst;
139 u8 src = instruction.a; 161 u8 src = instruction.a;
140 Variable var = vm->chunk->vars[src]; 162 Variable var = vm->main->vars[src];
141 s64 *stack = (s64 *)&vm->stack[var.offset]; 163 s64 *stack = (s64 *)&vm->stack[var.offset];
142 vm->regs[dst].i = *stack; 164 vm->regs[dst].i = *stack;
143 } break; 165 } break;
144 case OP_STGVAR: { 166 case OP_LDGADDR: {
145 u8 dst = instruction.dst; 167 u8 dst = instruction.dst;
146 u8 src = instruction.a; 168 u8 src = instruction.a;
147 Variable var = vm->chunk->vars[dst]; 169 Variable var = vm->main->vars[src];
148 s64 *stack = (s64 *)&vm->stack[var.offset]; 170 s64 *stack = (s64 *)&vm->stack[var.offset];
149 *stack = vm->regs[src].i; 171 vm->regs[dst].ptr = (ptrsize)stack;
150 } break; 172 } break;
151 case OP_STGVARI: { 173 case OP_STLVAR: {
152 u8 dst = instruction.dst; 174 u8 dst = instruction.dst;
153 u8 src = instruction.a; 175 u8 src = instruction.a;
154 Variable var = vm->chunk->vars[dst]; 176 Variable var = vm->chunk->vars[dst];
155 s64 *stack = (s64 *)&vm->stack[var.offset]; 177 vm->fp[var.offset / 8] = vm->regs[src].i;
156 *stack = vm->chunk->constants[src].i;
157 } break; 178 } break;
158 case OP_JMPI: { 179 case OP_STLVARI: {
159 sz offset = vm->chunk->constants[instruction.dst].i; 180 u8 dst = instruction.dst;
160 vm->ip += offset - 1; 181 u8 src = instruction.a;
182 Variable var = vm->chunk->vars[dst];
183 vm->fp[var.offset / 8] = vm->chunk->constants[src].i;
184 } break;
185 case OP_LDLVAR: {
186 u8 dst = instruction.dst;
187 u8 src = instruction.a;
188 Variable var = vm->chunk->vars[src];
189 vm->regs[dst].i = vm->fp[var.offset / 8];
190 } break;
191 case OP_LDLADDR: {
192 u8 dst = instruction.dst;
193 u8 src = instruction.a;
194 Variable var = vm->chunk->vars[src];
195 vm->regs[dst].i = (ptrsize)&vm->fp[var.offset / 8];
196 } break;
197 case OP_ST64I: {
198 sz value = vm->regs[instruction.dst].i;
199 s64 *addr = (s64 *)vm->regs[instruction.a].ptr;
200 sz offset = vm->chunk->constants[instruction.b].i;
201 addr[offset] = value;
202 } break;
203 case OP_ST64: {
204 sz value = vm->regs[instruction.dst].i;
205 s64 *addr = (s64 *)vm->regs[instruction.a].ptr;
206 sz offset = vm->regs[instruction.b].i;
207 addr[offset] = value;
208 } break;
209 case OP_LD64I: {
210 s64 *addr = (s64 *)vm->regs[instruction.a].ptr;
211 sz offset = vm->chunk->constants[instruction.b].i;
212 vm->regs[instruction.dst].i = addr[offset];
213 } break;
214 case OP_LD64: {
215 s64 *addr = (s64 *)vm->regs[instruction.a].ptr;
216 sz offset = vm->regs[instruction.b].i;
217 vm->regs[instruction.dst].i = addr[offset];
218 } break;
219 case OP_JMP: {
220 u8 dst = instruction.dst;
221 sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val;
222 vm->ip = vm->chunk->code + pos;
161 } break; 223 } break;
162 case OP_JMPFI: { 224 case OP_JMPFI: {
163 bool cond = vm->chunk->constants[instruction.dst].i; 225 u8 dst = instruction.dst;
164 sz offset = vm->chunk->constants[instruction.a].i; 226 sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val;
227 bool cond = vm->chunk->constants[instruction.a].i;
165 if (!cond) { 228 if (!cond) {
166 vm->ip += offset - 1; 229 vm->ip = vm->chunk->code + pos;
167 } 230 }
168 } break; 231 } break;
169 case OP_JMPTI: { 232 case OP_JMPTI: {
170 bool cond = vm->chunk->constants[instruction.dst].i; 233 u8 dst = instruction.dst;
171 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;
172 if (cond) { 236 if (cond) {
173 vm->ip += offset - 1; 237 vm->ip = vm->chunk->code + pos;
174 } 238 }
175 } break; 239 } 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: { 240 case OP_JMPF: {
181 bool cond = vm->regs[instruction.dst].i; 241 u8 dst = instruction.dst;
182 sz offset = vm->chunk->constants[instruction.a].i; 242 sz pos = intintmap_lookup(&vm->chunk->labels, dst)->val;
243 bool cond = vm->regs[instruction.a].i;
183 if (!cond) { 244 if (!cond) {
184 vm->ip += offset - 1; 245 vm->ip = vm->chunk->code + pos;
185 } 246 }
186 } break; 247 } break;
187 case OP_JMPT: { 248 case OP_JMPT: {
188 bool cond = vm->regs[instruction.dst].i; 249 u8 dst = instruction.dst;
189 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;
190 if (cond) { 252 if (cond) {
191 vm->ip += offset - 1; 253 vm->ip = vm->chunk->code + pos;
192 } 254 }
193 } break; 255 } break;
194 case OP_MOV64: { 256 case OP_MOV64: {
@@ -211,10 +273,113 @@ vm_run(VM *vm) {
211 u8 src = instruction.a; 273 u8 src = instruction.a;
212 vm->regs[dst].i = vm->regs[src].i & 0xFF; 274 vm->regs[dst].i = vm->regs[src].i & 0xFF;
213 } break; 275 } break;
276 case OP_PRINTS64: {
277 u8 idx = instruction.dst;
278 print("%d", vm->regs[idx].i);
279 } break;
280 case OP_PRINTS64I: {
281 u8 idx = instruction.dst;
282 print("%d", vm->chunk->constants[idx].i);
283 } break;
284 case OP_PRINTF64: {
285 u8 idx = instruction.dst;
286 printf("%f", vm->regs[idx].f);
287 } break;
288 case OP_PRINTF64I: {
289 u8 idx = instruction.dst;
290 printf("%f", vm->chunk->constants[idx].f);
291 } break;
292 case OP_PRINTSTR: {
293 u8 idx = instruction.dst;
294 Str string = vm->chunk->strings[idx];
295 print("%s", string);
296 } break;
297 case OP_RESERVE: {
298 sz offset = vm->chunk->constants[instruction.dst].i;
299 vm->sp += offset;
300 } break;
301 case OP_PUSH: {
302 sz val = vm->regs[instruction.dst].i;
303 u64 *p = (u64 *)vm->sp;
304 *p = val;
305 vm->sp += sizeof(ptrsize);
306 } break;
307 case OP_PUSHI: {
308 sz val = vm->chunk->constants[instruction.dst].i;
309 u64 *p = (u64 *)vm->sp;
310 *p = val;
311 vm->sp += sizeof(ptrsize);
312 } break;
313 case OP_POP: {
314 vm->sp -= sizeof(ptrsize);
315 u64 *p = (u64 *)vm->sp;
316 vm->regs[instruction.dst].i = *p;
317 } break;
318 case OP_PUTRET: {
319 sz val = vm->regs[instruction.dst].i;
320 vm->fp[-1] = val;
321 } break;
322 case OP_PUTRETI: {
323 sz val = vm->chunk->constants[instruction.dst].i;
324 vm->fp[-1] = val;
325 } break;
326 case OP_CALL: {
327 u8 dst = instruction.dst;
328 Chunk *func = vm->chunk->functions[dst];
329
330 ptrsize chunk_addr = (ptrsize)vm->chunk;
331 ptrsize ip_addr = (ptrsize)vm->ip;
332 ptrsize reg_addr = (ptrsize)vm->regs;
333 ptrsize old_fp = (ptrsize)vm->fp;
334
335 // Allocate space for the locals.
336 vm->fp = (u64 *)(vm->sp - func->param_off);
337 vm->sp += func->var_off - func->param_off;
338 vm->chunk = func;
339 vm->ip = func->code;
340 vm->regs = (Constant *)vm->sp;
341
342 // Allocate registers.
343 vm->sp += sizeof(Constant) * func->reg_idx;
344
345 // Store memory addresses we need to return to this function.
346 u64 *p = (u64 *)vm->sp;
347 p[0] = chunk_addr;
348 p[1] = ip_addr;
349 p[2] = reg_addr;
350 p[3] = old_fp;
351 vm->sp += sizeof(ptrsize) * 4;
352 } break;
353 case OP_RET: {
354 u64 *p = (u64 *)vm->sp;
355 ptrsize chunk_addr = p[-4];
356 ptrsize ip_addr = p[-3];
357 ptrsize reg_addr = p[-2];
358 ptrsize old_fp = p[-1];
359 vm->sp -= sizeof(ptrsize) * 4;
360
361 // Deallocate registers.
362 vm->sp -= sizeof(Constant) * vm->chunk->reg_idx;
363
364 // Deallocate locals.
365 vm->sp -= vm->chunk->var_off;
366
367 // Restore previous activation record.
368 vm->regs = (Constant *)reg_addr;
369 vm->ip = (Instruction *)ip_addr;
370 vm->chunk = (Chunk *)chunk_addr;
371 vm->fp = (u64 *)old_fp;
372 } break;
214 case OP_HALT: { 373 case OP_HALT: {
215 println("VM HALT (int) -> %d", vm->regs[instruction.dst]); 374 println("VM halt...");
216 println("VM HALT (float) -> %f", vm->regs[instruction.dst]); 375 if (instruction.a != 0) {
217 println("VM HALT (hex) -> %x", vm->regs[instruction.dst]); 376 println("Result:");
377 Constant result = vm->regs[instruction.dst];
378 printf("\tint -> %lld\n", result.i);
379 printf("\tfloat -> %.10e\n", result.f);
380 printf("\thex -> %llx\n", (u64)result.i);
381 println("\tbinary -> %b", result.i);
382 }
218 return; 383 return;
219 } 384 }
220 default: { 385 default: {
diff --git a/tests/compilation.bad b/tests/compilation.bad
index e0682a7..334c6ac 100644
--- a/tests/compilation.bad
+++ b/tests/compilation.bad
@@ -1,25 +1,23 @@
1; let a = 8 1; while true {
2; let b = 16 2; if true {
3; let c = { 3; continue
4; let a = 32 4; }
5; a + 8 5; println("ding")
6; break
7; ; if true continue
8; ; break
9; ; println("dong")
10; }
11; println("hello")
12; fun max(a: int b: int): int {
13; if a > b return(a) else return(b)
6; } 14; }
7 15
8; a + b + c 16; println(max(1 2))
17; println(max(4 3))
9 18
10; if true { 19; fun adder(a: int b: int): int a + b
11; 1 + 2
12; }
13 20
14if false { 21; let fpnt = adder
15 1 + 2
16} else {
17 3 + 4
18}
19 22
20; let a = 0 23; println("adder: " adder(1, 2))
21; if 1 != 1 {
22; set a = 1
23; } else {
24; set a = 2
25; }
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.
2if true "hello" 2if 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.
5let a = if (2 + 2 >= 4) 42 5let a = if (2 + 2 >= 4) 42 else 0
6 6
7; We support a single if expression. 7; We support a single if expression.
8let b = if (0xff == 0x32) "hello" else "world" 8let 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 {
42cond { 42cond {
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
47struct vec { 48struct vec {
@@ -160,9 +161,7 @@ let maybe = if (1 == 2) {
160 44 161 44
161} 162}
162 163
163let single = if (true) { 164let single = if (true) 123 else 0
164 123
165}
166 165
167while (!true) { 166while (!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}