aboutsummaryrefslogtreecommitdiffstats
path: root/src/compiler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler.c')
-rw-r--r--src/compiler.c1440
1 files changed, 1320 insertions, 120 deletions
diff --git a/src/compiler.c b/src/compiler.c
index 04afd5d..c2b48b3 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -10,6 +10,7 @@ typedef struct Variable {
10 Str type; 10 Str type;
11 sz size; 11 sz size;
12 sz offset; 12 sz offset;
13 sz idx;
13} Variable; 14} Variable;
14 15
15MAPDEF(StrVarMap, varmap, Str, Variable, str_hash, str_eq) 16MAPDEF(StrVarMap, varmap, Str, Variable, str_hash, str_eq)
@@ -24,13 +25,32 @@ typedef struct Instruction {
24typedef union Constant { 25typedef union Constant {
25 s64 i; 26 s64 i;
26 u64 u; 27 u64 u;
27 double f; 28 f64 f;
28 ptrsize ptr; 29 ptrsize ptr;
29} Constant; 30} Constant;
30 31
32typedef struct LineCol {
33 sz line;
34 sz col;
35} LineCol;
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
31typedef struct Chunk { 46typedef struct Chunk {
32 sz id; 47 sz id;
48 Str name;
49 struct Chunk *parent;
50
33 Instruction *code; 51 Instruction *code;
52 IntIntMap *labels; // label -> chunk_index
53 sz labels_idx;
34 54
35 // Constant values that fit in 64 bits. 55 // Constant values that fit in 64 bits.
36 Constant *constants; 56 Constant *constants;
@@ -46,44 +66,91 @@ typedef struct Chunk {
46 Variable *vars; 66 Variable *vars;
47 StrVarMap *varmap; 67 StrVarMap *varmap;
48 sz var_off; 68 sz var_off;
69 sz param_off;
49 70
50 // Number of registers currently used in this chunk. 71 // Number of registers currently used in this chunk.
51 sz reg_idx; 72 sz reg_idx;
52 73
74 // Number of functions currently used in this chunk.
75 struct Chunk **functions;
76 FunctionMap *funmap;
77 sz fun_idx;
78
53 // Debugging. 79 // Debugging.
54 Str file_name; 80 Str file_name;
55 Arena *storage; 81 Arena *storage;
56 // TODO: line/col info for debugging. 82 LineCol *linecol;
57} Chunk; 83} Chunk;
58 84
85typedef struct Compiler {
86 Chunk main_chunk;
87 Str file_name;
88 Arena *storage;
89
90 // Tables.
91 StrSet *integer_types;
92 StrSet *numeric_types;
93
94 // Destinations.
95 sz lab_pre;
96 sz lab_post;
97} Compiler;
98
59typedef enum OpCode { 99typedef enum OpCode {
60 // OP DST A B 100 // OP DST A B
61 // --------------------------------------------------------------- 101 // ---------------------------------------------------------------
62 // VM/high level instructions. 102 // VM/high level instructions.
63 OP_HALT, // halt 103 OP_HALT, // halt
64 OP_STVARI, // stvari vx, ca 104 // NOTE: LDGVAR/STGVAR* could be obtained in terms of LDGADDR.
65 OP_STVAR, // stvar vx, ra 105 OP_STGVARI, // stgvari vx, ca
106 OP_STGVAR, // stgvar vx, ra
107 OP_LDGVAR, // ldgvar rx, va
108 OP_LDGADDR, // ldgaddr rx, va
109 OP_STLVARI, // stlvari vx, ca
110 OP_STLVAR, // stlvar vx, ra
111 OP_LDLVAR, // ldlvar rx, va
112 OP_LDLADDR, // ldladdr rx, va
113 OP_LDSTR, // ldstr rx, sa ; Stores the address of the string sa into rx
114 // Functions.
115 OP_CALL, // call fx ; Call the function fx
116 OP_RECUR, // recur ; Jump to the beginning of the function.
117 OP_RET, // ret ; Returns from current function
118 OP_RESERVE, // reserve cx ; Increments the stack pointer by cx bytes
119 OP_POP, // pop rx ; Pops the last value of the stack into rx.
120 OP_PUSH, // push rx ; Push the rx value to the stack.
121 OP_PUSHI, // pushi cx ; Push the cx value to the stack.
122 OP_PUTRET, // putret rx ; Put rx into the return value memory.
123 OP_PUTRETI, // putreti cx ; Put cx into the return value memory.
124 // Printing values with builtin print/println functions.
125 OP_PRINTSTR, // p rx
126 OP_PRINTSTRI, // p cx
127 OP_PRINTS64, // p rx
128 OP_PRINTS64I, // p cx
129 OP_PRINTF64, // p rx
130 OP_PRINTF64I, // p cx
131 OP_PRINTBOOL, // p rx
132 OP_PRINTBOOLI, // p cx
66 // Load/Store instructions. 133 // Load/Store instructions.
67 OP_LD8K, // ld8k rx, ca -> u8 rx = ca 134 OP_LD8K, // ld8k rx, ca -> u8 rx = ca
68 OP_LD16K, // ld16k rx, ca -> u16 rx = ca 135 OP_LD16K, // ld16k rx, ca -> u16 rx = ca
69 OP_LD32K, // ld32k rx, ca -> u32 rx = ca 136 OP_LD32K, // ld32k rx, ca -> u32 rx = ca
70 OP_LD64K, // ld64k rx, ca -> u64 rx = ca 137 OP_LD64K, // ld64k rx, ca -> u64 rx = ca
71 OP_LD8I, // ld8i rx, ra, cb -> u8 *p; rx = p[ra + cb] 138 OP_LD8I, // ld8i rx, ra, cb -> u8 *p = ra; rx = p[cb]
72 OP_LD16I, // ld16i rx, ra, cb -> u16 *p; rx = p[ra + cb] 139 OP_LD16I, // ld16i rx, ra, cb -> u16 *p = ra; rx = p[cb]
73 OP_LD32I, // ld32i rx, ra, cb -> u32 *p; rx = p[ra + cb] 140 OP_LD32I, // ld32i rx, ra, cb -> u32 *p = ra; rx = p[cb]
74 OP_LD64I, // ld64i rx, ra, cb -> u64 *p; rx = p[ra + cb] 141 OP_LD64I, // ld64i rx, ra, cb -> u64 *p = ra; rx = p[cb]
75 OP_LD8, // ld8 rx, ra, rb -> u8 *p; rx = p[ra + rb] 142 OP_LD8, // ld8 rx, ra, rb -> u8 *p = ra; rx = p[rb]
76 OP_LD16, // ld16 rx, ra, rb -> u16 *p; rx = p[ra + rb] 143 OP_LD16, // ld16 rx, ra, rb -> u16 *p = ra; rx = p[rb]
77 OP_LD32, // ld32 rx, ra, rb -> u32 *p; rx = p[ra + rb] 144 OP_LD32, // ld32 rx, ra, rb -> u32 *p = ra; rx = p[rb]
78 OP_LD64, // ld64 rx, ra, rb -> u64 *p; rx = p[ra + rb] 145 OP_LD64, // ld64 rx, ra, rb -> u64 *p = ra; rx = p[rb]
79 OP_ST8I, // st8i rx, ra, cb -> u8 *p; p[ra + cb] = rx 146 OP_ST8I, // st8i rx, ra, cb -> u8 *p = ra; p[cb] = rx
80 OP_ST16I, // st16i rx, ra, cb -> u16 *p; p[ra + cb] = rx 147 OP_ST16I, // st16i rx, ra, cb -> u16 *p = ra; p[cb] = rx
81 OP_ST32I, // st32i rx, ra, cb -> u32 *p; p[ra + cb] = rx 148 OP_ST32I, // st32i rx, ra, cb -> u32 *p = ra; p[cb] = rx
82 OP_ST64I, // st64i rx, ra, cb -> u64 *p; p[ra + cb] = rx 149 OP_ST64I, // st64i rx, ra, cb -> u64 *p = ra; p[cb] = rx
83 OP_ST8, // st8 rx, ra, rb -> u8 *p; p[ra + rb] = rx 150 OP_ST8, // st8 rx, ra, rb -> u8 *p = ra; p[rb] = rx
84 OP_ST16, // st16 rx, ra, rb -> u16 *p; p[ra + rb] = rx 151 OP_ST16, // st16 rx, ra, rb -> u16 *p = ra; p[rb] = rx
85 OP_ST32, // st32 rx, ra, rb -> u32 *p; p[ra + rb] = rx 152 OP_ST32, // st32 rx, ra, rb -> u32 *p = ra; p[rb] = rx
86 OP_ST64, // st64 rx, ra, rb -> u64 *p; p[ra + rb] = rx 153 OP_ST64, // st64 rx, ra, rb -> u64 *p = ra; p[rb] = rx
87 // Integer arithmetic (only int/s64 for now). 154 // Integer arithmetic (only int/s64 for now).
88 OP_ADDI, // addk rx, ra, cb 155 OP_ADDI, // addk rx, ra, cb
89 OP_SUBI, // subk rx, ra, cb 156 OP_SUBI, // subk rx, ra, cb
@@ -135,18 +202,52 @@ typedef enum OpCode {
135 OP_BITRSHIFTI, // shri rx, ra, cb 202 OP_BITRSHIFTI, // shri rx, ra, cb
136 OP_BITANDI, // bandi rx, ra, cb 203 OP_BITANDI, // bandi rx, ra, cb
137 OP_BITORI, // bori rx, ra, cb 204 OP_BITORI, // bori rx, ra, cb
205 OP_BITXORI, // bxor rx, ra, cb
138 OP_BITNOTI, // bnoti rx, ca 206 OP_BITNOTI, // bnoti rx, ca
139 OP_BITLSHIFT, // shl rx, ra, rb 207 OP_BITLSHIFT, // shl rx, ra, rb
140 OP_BITRSHIFT, // shr rx, ra, rb 208 OP_BITRSHIFT, // shr rx, ra, rb
141 OP_BITAND, // band rx, ra, rb 209 OP_BITAND, // band rx, ra, rb
142 OP_BITOR, // bor rx, ra, rb 210 OP_BITOR, // bor rx, ra, rb
211 OP_BITXOR, // bxor rx, ra, rb
143 OP_BITNOT, // bnot rx, ra 212 OP_BITNOT, // bnot rx, ra
213 // Jump instructions.
214 OP_JMP, // jmp lx ; jmp to label lx
215 OP_JMPF, // jmpf lx, rx ; jmp to label lx if rx is false
216 OP_JMPT, // jmpt lx, rx ; jmp to label lx if rx is true
217 OP_JMPFI, // jmpf lx, cx ; jmp to label lx if rx is false
218 OP_JMPTI, // jmpt lx, cx ; jmp to label lx if rx is true
144} OpCode; 219} OpCode;
145 220
146Str op_str[] = { 221Str op_str[] = {
222 // High level ops.
147 [OP_HALT] = cstr("HALT "), 223 [OP_HALT] = cstr("HALT "),
148 [OP_STVAR] = cstr("STVAR "), 224 [OP_STGVAR] = cstr("STGVAR "),
149 [OP_STVARI] = cstr("STVARI "), 225 [OP_STGVARI] = cstr("STGVARI "),
226 [OP_LDGVAR] = cstr("LDGVAR "),
227 [OP_LDGADDR] = cstr("LDGADDR "),
228 [OP_STLVAR] = cstr("STLVAR "),
229 [OP_STLVARI] = cstr("STLVARI "),
230 [OP_LDLVAR] = cstr("LDLVAR "),
231 [OP_LDLADDR] = cstr("LDLADDR "),
232 [OP_LDSTR] = cstr("LDSTR "),
233 [OP_PRINTSTR] = cstr("PRNSTR "),
234 [OP_PRINTSTRI] = cstr("PRNSTRI "),
235 [OP_PRINTS64] = cstr("PRNS64 "),
236 [OP_PRINTS64I] = cstr("PRNS64I "),
237 [OP_PRINTF64] = cstr("PRNF64 "),
238 [OP_PRINTF64I] = cstr("PRNF64I "),
239 [OP_PRINTBOOL] = cstr("PRNBOOL "),
240 [OP_PRINTBOOLI] = cstr("PRNBOOLI"),
241 [OP_PUTRET] = cstr("PUTRET "),
242 [OP_PUTRETI] = cstr("PUTRETI "),
243 // Functions.
244 [OP_CALL] = cstr("CALL "),
245 [OP_RECUR] = cstr("RECUR "),
246 [OP_RET] = cstr("RET "),
247 [OP_RESERVE] = cstr("RESERVE "),
248 [OP_POP] = cstr("POP "),
249 [OP_PUSH] = cstr("PUSH "),
250 [OP_PUSHI] = cstr("PUSHI "),
150 // Load ops. 251 // Load ops.
151 [OP_LD8K] = cstr("LD8K "), 252 [OP_LD8K] = cstr("LD8K "),
152 [OP_LD16K] = cstr("LD16K "), 253 [OP_LD16K] = cstr("LD16K "),
@@ -219,12 +320,20 @@ Str op_str[] = {
219 [OP_BITRSHIFTI] = cstr("RSHI "), 320 [OP_BITRSHIFTI] = cstr("RSHI "),
220 [OP_BITANDI] = cstr("BANDI "), 321 [OP_BITANDI] = cstr("BANDI "),
221 [OP_BITORI] = cstr("BORI "), 322 [OP_BITORI] = cstr("BORI "),
323 [OP_BITXORI] = cstr("BXORI "),
222 [OP_BITNOTI] = cstr("BNOTI "), 324 [OP_BITNOTI] = cstr("BNOTI "),
223 [OP_BITLSHIFT] = cstr("LSH "), 325 [OP_BITLSHIFT] = cstr("LSH "),
224 [OP_BITRSHIFT] = cstr("RSH "), 326 [OP_BITRSHIFT] = cstr("RSH "),
225 [OP_BITAND] = cstr("BAND "), 327 [OP_BITAND] = cstr("BAND "),
226 [OP_BITOR] = cstr("BOR "), 328 [OP_BITOR] = cstr("BOR "),
329 [OP_BITXOR] = cstr("XBOR "),
227 [OP_BITNOT] = cstr("BNOT "), 330 [OP_BITNOT] = cstr("BNOT "),
331 // Jump instructions.
332 [OP_JMP] = cstr("JMP "),
333 [OP_JMPF] = cstr("JMPF "),
334 [OP_JMPT] = cstr("JMPT "),
335 [OP_JMPFI] = cstr("JMPFI "),
336 [OP_JMPTI] = cstr("JMPTI "),
228}; 337};
229 338
230typedef enum { 339typedef enum {
@@ -232,6 +341,7 @@ typedef enum {
232 COMP_CONST, 341 COMP_CONST,
233 COMP_STRING, 342 COMP_STRING,
234 COMP_REG, 343 COMP_REG,
344 COMP_RET,
235 COMP_ERR, 345 COMP_ERR,
236} CompResultType; 346} CompResultType;
237 347
@@ -240,21 +350,108 @@ typedef struct CompResult {
240 CompResultType type; 350 CompResultType type;
241} CompResult; 351} CompResult;
242 352
243CompResult compile_expr(Chunk *chunk, Node *node); 353CompResult compile_expr(Compiler *compiler, Chunk *chunk, Node *node);
354
355sz
356add_constant(Chunk *chunk, sz value) {
357 IntIntMap *map = intintmap_lookup(&chunk->intmap, value);
358 // Make sure we don't have duplicated constants.
359 if (!map) {
360 map = intintmap_insert(&chunk->intmap, value, chunk->const_idx++,
361 chunk->storage);
362 Constant c = (Constant){.i = value};
363 array_push(chunk->constants, c, chunk->storage);
364 }
365 return map->val;
366}
244 367
245#define EMIT_OP(OP, DST, A, B, NODE, CHUNK) \ 368sz
246 do { \ 369add_string(Chunk *chunk, Str string) {
247 Instruction inst = (Instruction){ \ 370 // Make sure we don't have duplicated string.
248 .op = (OP), \ 371 StrIntMap *map = strintmap_lookup(&chunk->strmap, string);
249 .dst = (DST), \ 372 if (!map) {
250 .a = (A), \ 373 map = strintmap_insert(&chunk->strmap, string, chunk->str_idx++,
251 .b = (B), \ 374 chunk->storage);
252 }; \ 375 array_push(chunk->strings, string, chunk->storage);
253 array_push((CHUNK)->code, inst, (CHUNK)->storage); \ 376 }
254 } while (0) 377 return map->val;
378}
379
380sz
381add_variable(Chunk *chunk, Str name, Str type, sz arr_size) {
382 sz idx = array_size(chunk->vars);
383 sz size = 8;
384 // TODO: get type storage from a table to consider all the basic
385 // types as well as user defined ones.
386 if (str_eq(type, cstr("str"))) {
387 size = 16;
388 }
389 if (arr_size) {
390 // TODO: get the proper storage size for the multiplication.
391 size *= arr_size;
392 // FIXME: this should be done on the static analysis, plus,
393 // we shouldn't be checking all these types by hand, but
394 // using the symbol tables.
395 type = str_remove_prefix(type, cstr("@"));
396 type = str_concat(cstr("[]"), type, chunk->storage);
397 }
398 Variable var = (Variable){
399 .name = name,
400 .type = type,
401 .size = size,
402 .offset = chunk->var_off,
403 .idx = idx,
404 };
405 varmap_insert(&chunk->varmap, name, var, chunk->storage);
406 array_push(chunk->vars, var, chunk->storage);
407 chunk->var_off += size;
408 return idx;
409}
410
411void
412emit_op(OpCode op, sz dst, sz a, sz b, Node *node, Chunk *chunk) {
413 Instruction inst = (Instruction){
414 .op = op,
415 .dst = dst,
416 .a = a,
417 .b = b,
418 };
419 array_push(chunk->code, inst, chunk->storage);
420 LineCol linecol = (LineCol){0};
421 if (node) {
422 linecol = (LineCol){.line = node->line, .col = node->col};
423 }
424 array_push(chunk->linecol, linecol, chunk->storage);
425}
426
427void
428emit_fat_copy(Chunk *chunk, Node *node, sz dst_addr, sz src_addr) {
429 sz reg_dst = chunk->reg_idx++;
430
431 // Store the fat string pointer into the variable.
432 sz zero = add_constant(chunk, 0);
433 sz one = add_constant(chunk, 1);
434
435 // Get the value for the first word of the string
436 // pointer.
437 emit_op(OP_LD64I, reg_dst, src_addr, zero, node, chunk);
438 emit_op(OP_ST64I, reg_dst, dst_addr, zero, node, chunk);
439 emit_op(OP_LD64I, reg_dst, src_addr, one, node, chunk);
440 emit_op(OP_ST64I, reg_dst, dst_addr, one, node, chunk);
441}
442
443void disassemble_chunk(Chunk chunk);
444
445void
446emit_compile_err(Compiler *compiler, Chunk *chunk, Node *node) {
447 disassemble_chunk(*chunk);
448 eprintln("%s:%d:%d: error: compilation error on: %s", compiler->file_name,
449 node->line, node->col, node_str[node->kind]);
450 exit(EXIT_FAILURE);
451}
255 452
256CompResult 453CompResult
257compile_binary(Chunk *chunk, Node *node) { 454compile_binary(Compiler *compiler, Chunk *chunk, Node *node) {
258 OpCode op = OP_HALT; 455 OpCode op = OP_HALT;
259 OpCode opi = OP_HALT; 456 OpCode opi = OP_HALT;
260 OpCode ldop = OP_LD64K; 457 OpCode ldop = OP_LD64K;
@@ -343,6 +540,10 @@ compile_binary(Chunk *chunk, Node *node) {
343 op = OP_BITOR; 540 op = OP_BITOR;
344 opi = OP_BITORI; 541 opi = OP_BITORI;
345 } break; 542 } break;
543 case NODE_BITXOR: {
544 op = OP_BITXOR;
545 opi = OP_BITXORI;
546 } break;
346 case NODE_BITAND: { 547 case NODE_BITAND: {
347 op = OP_BITAND; 548 op = OP_BITAND;
348 opi = OP_BITANDI; 549 opi = OP_BITANDI;
@@ -357,19 +558,20 @@ compile_binary(Chunk *chunk, Node *node) {
357 } break; 558 } break;
358 default: break; 559 default: break;
359 } 560 }
360 CompResult comp_a = compile_expr(chunk, node->left); 561 CompResult comp_a = compile_expr(compiler, chunk, node->binary.left);
361 CompResult comp_b = compile_expr(chunk, node->right); 562 CompResult comp_b = compile_expr(compiler, chunk, node->binary.right);
362 sz reg_a; 563 sz reg_a;
363 sz reg_b; 564 sz reg_b;
364 switch (comp_a.type) { 565 switch (comp_a.type) {
365 case COMP_CONST: { 566 case COMP_CONST: {
366 reg_a = chunk->reg_idx++; 567 reg_a = chunk->reg_idx++;
367 EMIT_OP(ldop, reg_a, comp_a.idx, 0, node, chunk); 568 emit_op(ldop, reg_a, comp_a.idx, 0, node, chunk);
368 } break; 569 } break;
369 case COMP_REG: { 570 case COMP_REG: {
370 reg_a = comp_a.idx; 571 reg_a = comp_a.idx;
371 } break; 572 } break;
372 default: { 573 default: {
574 emit_compile_err(compiler, chunk, node);
373 return (CompResult){.type = COMP_ERR}; 575 return (CompResult){.type = COMP_ERR};
374 } break; 576 } break;
375 } 577 }
@@ -382,16 +584,17 @@ compile_binary(Chunk *chunk, Node *node) {
382 reg_b = comp_b.idx; 584 reg_b = comp_b.idx;
383 } break; 585 } break;
384 default: { 586 default: {
587 emit_compile_err(compiler, chunk, node);
385 return (CompResult){.type = COMP_ERR}; 588 return (CompResult){.type = COMP_ERR};
386 } break; 589 } break;
387 } 590 }
388 sz reg_dst = chunk->reg_idx++; // Better for optimization 591 sz reg_dst = chunk->reg_idx++; // Better for optimization
389 EMIT_OP(op, reg_dst, reg_a, reg_b, node, chunk); 592 emit_op(op, reg_dst, reg_a, reg_b, node, chunk);
390 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 593 return (CompResult){.type = COMP_REG, .idx = reg_dst};
391} 594}
392 595
393CompResult 596CompResult
394compile_unary(Chunk *chunk, Node *node) { 597compile_unary(Compiler *compiler, Chunk *chunk, Node *node) {
395 OpCode op = OP_HALT; 598 OpCode op = OP_HALT;
396 OpCode opi = OP_HALT; 599 OpCode opi = OP_HALT;
397 switch (node->kind) { 600 switch (node->kind) {
@@ -405,7 +608,7 @@ compile_unary(Chunk *chunk, Node *node) {
405 } break; 608 } break;
406 default: break; 609 default: break;
407 } 610 }
408 CompResult comp_a = compile_expr(chunk, node->left); 611 CompResult comp_a = compile_expr(compiler, chunk, node->binary.left);
409 sz reg_a; 612 sz reg_a;
410 switch (comp_a.type) { 613 switch (comp_a.type) {
411 case COMP_CONST: { 614 case COMP_CONST: {
@@ -416,21 +619,925 @@ compile_unary(Chunk *chunk, Node *node) {
416 reg_a = comp_a.idx; 619 reg_a = comp_a.idx;
417 } break; 620 } break;
418 default: { 621 default: {
622 emit_compile_err(compiler, chunk, node);
623 return (CompResult){.type = COMP_ERR};
624 } break;
625 }
626 sz reg_dst = chunk->reg_idx++;
627 emit_op(op, reg_dst, reg_a, 0, node, chunk);
628 return (CompResult){.type = COMP_REG, .idx = reg_dst};
629}
630
631CompResult
632compile_if(Compiler *compiler, Chunk *chunk, Node *node) {
633 CompResult cond = compile_expr(compiler, chunk, node->ifelse.cond);
634 OpCode jmpop;
635 switch (cond.type) {
636 case COMP_CONST: {
637 jmpop = OP_JMPFI;
638 } break;
639 case COMP_REG: {
640 jmpop = OP_JMPF;
641 } break;
642 default: {
643 emit_compile_err(compiler, chunk, node);
419 return (CompResult){.type = COMP_ERR}; 644 return (CompResult){.type = COMP_ERR};
420 } break; 645 } break;
421 } 646 }
647
648 if (!str_eq(node->type, cstr("nil")) &&
649 !str_has_prefix(node->type, cstr("ret:")) &&
650 !str_has_prefix(node->type, cstr("flow:"))) {
651 sz reg_dst = chunk->reg_idx++;
652
653 // Jump to the `false` branch.
654 sz lab0 = chunk->labels_idx++;
655 emit_op(jmpop, lab0, cond.idx, 0, node->ifelse.cond, chunk);
656
657 // Condition is true.
658 CompResult then_expr =
659 compile_expr(compiler, chunk, node->ifelse.expr_true);
660 switch (then_expr.type) {
661 case COMP_CONST: {
662 emit_op(OP_LD64K, reg_dst, then_expr.idx, 0, node->ifelse.cond,
663 chunk);
664 } break;
665 case COMP_REG: {
666 emit_op(OP_MOV64, reg_dst, then_expr.idx, 0, node->ifelse.cond,
667 chunk);
668 } break;
669 case COMP_RET: break;
670 default: {
671 emit_compile_err(compiler, chunk, node);
672 return (CompResult){.type = COMP_ERR};
673 } break;
674 }
675
676 // Jump to the end of the expression.
677 sz pos0 = array_size(chunk->code);
678 sz lab1 = chunk->labels_idx++;
679 emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk);
680
681 // Else expression.
682 CompResult else_expr =
683 compile_expr(compiler, chunk, node->ifelse.expr_else);
684 switch (else_expr.type) {
685 case COMP_CONST: {
686 emit_op(OP_LD64K, reg_dst, else_expr.idx, 0,
687 node->ifelse.expr_else, chunk);
688 } break;
689 case COMP_REG: {
690 emit_op(OP_MOV64, reg_dst, else_expr.idx, 0,
691 node->ifelse.expr_else, chunk);
692 } break;
693 case COMP_RET: break;
694 default: {
695 emit_compile_err(compiler, chunk, node);
696 return (CompResult){.type = COMP_ERR};
697 } break;
698 }
699 sz pos1 = array_size(chunk->code);
700
701 // Update labels.
702 intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage);
703 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
704 return (CompResult){.type = COMP_REG, .idx = reg_dst};
705 }
706
707 // Jump to the `false` branch.
708 sz lab0 = chunk->labels_idx++;
709 emit_op(jmpop, lab0, cond.idx, 0, node->ifelse.cond, chunk);
710
711 // Condition is true.
712 compile_expr(compiler, chunk, node->ifelse.expr_true);
713
714 // Jump to the end of the expression.
715 sz pos0 = array_size(chunk->code);
716 sz lab1 = chunk->labels_idx++;
717 emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk);
718
719 // Else expression.
720 if (node->ifelse.expr_else) {
721 compile_expr(compiler, chunk, node->ifelse.expr_else);
722 }
723 sz pos1 = array_size(chunk->code);
724
725 // Update labels.
726 intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage);
727 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
728
729 return (CompResult){.type = COMP_NIL};
730}
731
732CompResult
733compile_cond(Compiler *compiler, Chunk *chunk, Node *node) {
734 if (str_eq(node->type, cstr("nil"))) {
735 sz lab1 = chunk->labels_idx++;
736 for (sz i = 0; i < array_size(node->match.cases); i++) {
737 // condition = expression
738 Node *expr = node->match.cases[i];
739 if (expr->case_entry.cond) {
740 CompResult cond =
741 compile_expr(compiler, chunk, expr->case_entry.cond);
742 OpCode jmpop;
743 switch (cond.type) {
744 case COMP_CONST: {
745 jmpop = OP_JMPFI;
746 } break;
747 case COMP_REG: {
748 jmpop = OP_JMPF;
749 } break;
750 default: {
751 emit_compile_err(compiler, chunk, node);
752 return (CompResult){.type = COMP_ERR};
753 } break;
754 }
755 // Jump to the `next` branch.
756 sz lab0 = chunk->labels_idx++;
757 emit_op(jmpop, lab0, cond.idx, 0, expr->case_entry.expr, chunk);
758
759 // Condition is true.
760 compile_expr(compiler, chunk, expr->case_entry.expr);
761 if (i != array_size(node->match.cases) - 1) {
762 // Jump to the end of the expression.
763 sz pos0 = array_size(chunk->code);
764 emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk);
765 intintmap_insert(&chunk->labels, lab0, pos0 + 1,
766 chunk->storage);
767 }
768 } else {
769 compile_expr(compiler, chunk, expr->case_entry.expr);
770 break;
771 }
772 }
773 sz pos1 = array_size(chunk->code);
774 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
775 return (CompResult){.type = COMP_NIL};
776 }
777
422 sz reg_dst = chunk->reg_idx++; 778 sz reg_dst = chunk->reg_idx++;
423 EMIT_OP(op, reg_dst, reg_a, 0, node, chunk); 779 sz lab1 = chunk->labels_idx++;
780 for (sz i = 0; i < array_size(node->match.cases); i++) {
781 // condition = expression
782 Node *expr = node->match.cases[i];
783 if (expr->case_entry.cond) {
784 CompResult cond =
785 compile_expr(compiler, chunk, expr->case_entry.cond);
786 OpCode jmpop;
787 switch (cond.type) {
788 case COMP_CONST: {
789 jmpop = OP_JMPFI;
790 } break;
791 case COMP_REG: {
792 jmpop = OP_JMPF;
793 } break;
794 default: {
795 emit_compile_err(compiler, chunk, node);
796 return (CompResult){.type = COMP_ERR};
797 } break;
798 }
799 // Jump to the `next` branch.
800 sz lab0 = chunk->labels_idx++;
801 emit_op(jmpop, lab0, cond.idx, 0, expr->case_entry.expr, chunk);
802
803 // Condition is true.
804 CompResult then_expr =
805 compile_expr(compiler, chunk, expr->case_entry.expr);
806 switch (then_expr.type) {
807 case COMP_CONST: {
808 emit_op(OP_LD64K, reg_dst, then_expr.idx, 0,
809 expr->case_entry.expr, chunk);
810 } break;
811 case COMP_REG: {
812 emit_op(OP_MOV64, reg_dst, then_expr.idx, 0,
813 expr->case_entry.expr, chunk);
814 } break;
815 case COMP_RET: break;
816 default: {
817 emit_compile_err(compiler, chunk, node);
818 return (CompResult){.type = COMP_ERR};
819 } break;
820 }
821 if (i != array_size(node->match.cases) - 1) {
822 // Jump to the end of the expression.
823 sz pos0 = array_size(chunk->code);
824 emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk);
825 intintmap_insert(&chunk->labels, lab0, pos0 + 1,
826 chunk->storage);
827 }
828 } else {
829 CompResult then_expr =
830 compile_expr(compiler, chunk, expr->case_entry.expr);
831 switch (then_expr.type) {
832 case COMP_CONST: {
833 emit_op(OP_LD64K, reg_dst, then_expr.idx, 0,
834 expr->case_entry.expr, chunk);
835 } break;
836 case COMP_REG: {
837 emit_op(OP_MOV64, reg_dst, then_expr.idx, 0,
838 expr->case_entry.expr, chunk);
839 } break;
840 case COMP_RET: break;
841 default: {
842 emit_compile_err(compiler, chunk, node);
843 return (CompResult){.type = COMP_ERR};
844 } break;
845 }
846 break;
847 }
848 }
849 sz pos1 = array_size(chunk->code);
850 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
851 return (CompResult){.type = COMP_REG, .idx = reg_dst};
852}
853
854CompResult
855compile_break(Compiler *compiler, Chunk *chunk, Node *node) {
856 emit_op(OP_JMP, compiler->lab_post, 0, 0, node, chunk);
857 return (CompResult){.type = COMP_NIL};
858}
859
860CompResult
861compile_continue(Compiler *compiler, Chunk *chunk, Node *node) {
862 emit_op(OP_JMP, compiler->lab_pre, 0, 0, node, chunk);
863 return (CompResult){.type = COMP_NIL};
864}
865
866CompResult
867compile_while(Compiler *compiler, Chunk *chunk, Node *node) {
868 sz lab0 = chunk->labels_idx++;
869 sz lab1 = chunk->labels_idx++;
870 sz pos1 = array_size(chunk->code);
871 CompResult cond = compile_expr(compiler, chunk, node->loop.cond);
872 OpCode jmpop;
873 switch (cond.type) {
874 case COMP_CONST: {
875 jmpop = OP_JMPFI;
876 } break;
877 case COMP_REG: {
878 jmpop = OP_JMPF;
879 } break;
880 default: {
881 emit_compile_err(compiler, chunk, node);
882 return (CompResult){.type = COMP_ERR};
883 } break;
884 }
885
886 // Jump to the `end of the loop` branch.
887 emit_op(jmpop, lab0, cond.idx, 0, node->loop.cond, chunk);
888
889 // Condition is true.
890 compiler->lab_pre = lab1;
891 compiler->lab_post = lab0;
892 compile_expr(compiler, chunk, node->loop.expr);
893 sz pos0 = array_size(chunk->code);
894 emit_op(OP_JMP, lab1, 0, 0, node, chunk);
895
896 // Update labels.
897 intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage);
898 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
899
900 // Return.
901 return (CompResult){.type = COMP_NIL};
902}
903
904CompResult
905compile_tail_call(Compiler *compiler, Chunk *chunk, Node *node) {
906 // Update the local parameters.
907 for (sz i = 0; i < array_size(node->elements); i++) {
908 Node *expr = node->elements[i];
909 CompResult result = compile_expr(compiler, chunk, expr);
910 switch (result.type) {
911 case COMP_CONST: {
912 emit_op(OP_STLVARI, i, result.idx, 0, node, chunk);
913 } break;
914 case COMP_REG: {
915 if (str_eq(expr->type, cstr("str"))) {
916 sz var_addr = chunk->reg_idx++;
917 sz str_addr = result.idx;
918 emit_op(OP_LDLADDR, var_addr, i, 0, node, chunk);
919 emit_fat_copy(chunk, node, var_addr, str_addr);
920 } else {
921 emit_op(OP_STLVAR, i, result.idx, 0, node, chunk);
922 }
923 } break;
924 case COMP_STRING: {
925 sz var_addr = chunk->reg_idx++;
926 sz str_addr = chunk->reg_idx++;
927 emit_op(OP_LDLADDR, var_addr, i, 0, node, chunk);
928 emit_op(OP_LDSTR, str_addr, result.idx, 0, node, chunk);
929 emit_fat_copy(chunk, node, var_addr, str_addr);
930 } break;
931 default: {
932 emit_compile_err(compiler, chunk, node);
933 return (CompResult){.type = COMP_ERR};
934 } break;
935 }
936 }
937
938 emit_op(OP_RECUR, 0, 0, 0, node, chunk);
939 return (CompResult){.type = COMP_NIL};
940}
941
942CompResult
943compile_funcall(Compiler *compiler, Chunk *chunk, Node *node) {
944 Str name = node->value.str;
945
946 // Builtins.
947 if (str_eq(name, cstr("print")) || str_eq(name, cstr("println"))) {
948 for (sz i = 0; i < array_size(node->elements); i++) {
949 Node *expr = node->elements[i];
950 CompResult result = compile_expr(compiler, chunk, expr);
951 if (str_eq(expr->type, cstr("int"))) {
952 switch (result.type) {
953 case COMP_CONST: {
954 emit_op(OP_PRINTS64I, result.idx, 0, 0, expr, chunk);
955 } break;
956 case COMP_REG: {
957 emit_op(OP_PRINTS64, result.idx, 0, 0, expr, chunk);
958 } break;
959 default: {
960 emit_compile_err(compiler, chunk, node);
961 return (CompResult){.type = COMP_ERR};
962 } break;
963 }
964 } else if (str_eq(expr->type, cstr("f64"))) {
965 switch (result.type) {
966 case COMP_CONST: {
967 emit_op(OP_PRINTF64I, result.idx, 0, 0, expr, chunk);
968 } break;
969 case COMP_REG: {
970 emit_op(OP_PRINTF64, result.idx, 0, 0, expr, chunk);
971 } break;
972 default: {
973 emit_compile_err(compiler, chunk, node);
974 return (CompResult){.type = COMP_ERR};
975 } break;
976 }
977 } else if (str_eq(expr->type, cstr("str"))) {
978 switch (result.type) {
979 case COMP_STRING: {
980 emit_op(OP_PRINTSTRI, result.idx, 0, 0, expr, chunk);
981 } break;
982 case COMP_REG: {
983 emit_op(OP_PRINTSTR, result.idx, 0, 0, expr, chunk);
984 } break;
985 default: {
986 emit_compile_err(compiler, chunk, node);
987 return (CompResult){.type = COMP_ERR};
988 } break;
989 }
990 } else if (str_eq(expr->type, cstr("bool"))) {
991 switch (result.type) {
992 case COMP_CONST: {
993 emit_op(OP_PRINTBOOLI, result.idx, 0, 0, expr, chunk);
994 } break;
995 case COMP_REG: {
996 emit_op(OP_PRINTBOOL, result.idx, 0, 0, expr, chunk);
997 } break;
998 default: {
999 emit_compile_err(compiler, chunk, node);
1000 return (CompResult){.type = COMP_ERR};
1001 } break;
1002 }
1003 }
1004 }
1005 if (str_eq(name, cstr("println"))) {
1006 sz idx = add_string(chunk, cstr("\n"));
1007 emit_op(OP_PRINTSTRI, idx, 0, 0, node, chunk);
1008 }
1009 return (CompResult){.type = COMP_NIL};
1010 }
1011
1012 FunctionMap *map =
1013 funcmap_lookup(&compiler->main_chunk.funmap, node->unique_name);
1014 if (!map) {
1015 emit_compile_err(compiler, chunk, node);
1016 return (CompResult){.type = COMP_ERR};
1017 }
1018 Function fun = map->val;
1019
1020 // Check for tail recursive opportunities.
1021 if (str_eq(fun.name, node->unique_name) &&
1022 str_eq(chunk->name, node->unique_name)) {
1023 Node *parent = node->parent;
1024 Node *current = node;
1025 bool tail_recursive = true;
1026 while (parent != NULL) {
1027 switch (parent->kind) {
1028 case NODE_BLOCK: {
1029 sz idx = array_size(parent->statements) - 1;
1030 if (parent->statements[idx] != node) {
1031 tail_recursive = false;
1032 break;
1033 }
1034 } break;
1035 case NODE_WHILE: {
1036 if (current == parent->loop.cond) {
1037 tail_recursive = false;
1038 break;
1039 }
1040 } break;
1041 case NODE_IF: {
1042 if (current == parent->ifelse.cond) {
1043 tail_recursive = false;
1044 break;
1045 }
1046 } break;
1047 case NODE_FUN: {
1048 sz idx = array_size(parent->func.body->statements) - 1;
1049 if (parent->func.body->statements[idx] != current) {
1050 tail_recursive = false;
1051 break;
1052 }
1053 break;
1054 } break;
1055 case NODE_MATCH: {
1056 if (current == parent->match.expr) {
1057 tail_recursive = false;
1058 break;
1059 }
1060 } break;
1061 case NODE_COND: break;
1062 case NODE_CASE_COND: {
1063 if (current == parent->case_entry.cond) {
1064 tail_recursive = false;
1065 break;
1066 }
1067 } break;
1068 default: {
1069 tail_recursive = false;
1070 break;
1071 } break;
1072 }
1073 parent = parent->parent;
1074 current = current->parent;
1075 }
1076 if (tail_recursive) {
1077 return compile_tail_call(compiler, chunk, node);
1078 }
1079 }
1080
1081 // Reserve space for the return value if needed.
1082 if (fun.return_arity > 0) {
1083 // Put the return data into a register
1084 sz ret_size = add_constant(chunk, 8);
1085 emit_op(OP_RESERVE, ret_size, 0, 0, node, chunk);
1086 }
1087
1088 // Send parameters to the stack.
1089 for (sz i = 0; i < array_size(node->elements); i++) {
1090 Node *expr = node->elements[i];
1091 CompResult result = compile_expr(compiler, chunk, expr);
1092 switch (result.type) {
1093 case COMP_CONST: {
1094 emit_op(OP_PUSHI, result.idx, 0, 0, expr, chunk);
1095 } break;
1096 case COMP_REG: {
1097 if (str_eq(expr->type, cstr("str"))) {
1098 sz str_addr = result.idx;
1099 // Store the fat string pointer into the stack.
1100 sz reg_dst = chunk->reg_idx++;
1101 sz zero = add_constant(chunk, 0);
1102 sz one = add_constant(chunk, 1);
1103 emit_op(OP_LD64I, reg_dst, str_addr, zero, node, chunk);
1104 emit_op(OP_PUSH, reg_dst, 0, 0, expr, chunk);
1105 emit_op(OP_LD64I, reg_dst, str_addr, one, node, chunk);
1106 emit_op(OP_PUSH, reg_dst, 0, 0, expr, chunk);
1107 } else {
1108 emit_op(OP_PUSH, result.idx, 0, 0, expr, chunk);
1109 }
1110 } break;
1111 case COMP_STRING: {
1112 // Get the address for the string value variable.
1113 sz str_addr = chunk->reg_idx++;
1114 emit_op(OP_LDSTR, str_addr, result.idx, 0, node->var.val,
1115 chunk);
1116
1117 // Store the fat string pointer into the stack.
1118 sz reg_dst = chunk->reg_idx++;
1119 sz zero = add_constant(chunk, 0);
1120 sz one = add_constant(chunk, 1);
1121 emit_op(OP_LD64I, reg_dst, str_addr, zero, node, chunk);
1122 emit_op(OP_PUSH, reg_dst, 0, 0, expr, chunk);
1123 emit_op(OP_LD64I, reg_dst, str_addr, one, node, chunk);
1124 emit_op(OP_PUSH, reg_dst, 0, 0, expr, chunk);
1125 } break;
1126 default: {
1127 emit_compile_err(compiler, chunk, node);
1128 return (CompResult){.type = COMP_ERR};
1129 } break;
1130 }
1131 }
1132
1133 emit_op(OP_CALL, fun.index, 0, 0, node, chunk);
1134
1135 // Only one return parameter for now.
1136 if (fun.return_arity > 0) {
1137 // Put the return data into a register
1138 sz reg_dst = chunk->reg_idx++;
1139 emit_op(OP_POP, reg_dst, 0, 0, node, chunk);
1140 return (CompResult){.type = COMP_REG, .idx = reg_dst};
1141 }
1142
1143 return (CompResult){.type = COMP_NIL};
1144}
1145
1146CompResult
1147compile_return(Compiler *compiler, Chunk *chunk, Node *node) {
1148 for (sz i = 0; i < array_size(node->elements); i++) {
1149 Node *expr = node->elements[i];
1150 CompResult res = compile_expr(compiler, chunk, expr);
1151
1152 // TODO: Only one return field for now, but this is the idea.
1153 // Put return values into memory.
1154 switch (res.type) {
1155 case COMP_CONST: {
1156 emit_op(OP_PUTRETI, res.idx, 0, 0, node, chunk);
1157 } break;
1158 case COMP_REG: {
1159 emit_op(OP_PUTRET, res.idx, 0, 0, node, chunk);
1160 } break;
1161 case COMP_NIL: break;
1162 default: {
1163 emit_compile_err(compiler, chunk, node);
1164 return (CompResult){.type = COMP_ERR};
1165 } break;
1166 }
1167 break;
1168 }
1169
1170 emit_op(OP_RET, 0, 0, 0, node, chunk);
1171 return (CompResult){.type = COMP_RET};
1172}
1173
1174Chunk *
1175chunk_alloc(Chunk *parent) {
1176 static sz chunk_idx = 1;
1177 Chunk *chunk = arena_calloc((sz)sizeof(Chunk), parent->storage);
1178 chunk->parent = parent;
1179 chunk->id = chunk_idx++;
1180 chunk->storage = parent->storage;
1181 chunk->file_name = parent->file_name;
1182 return chunk;
1183}
1184
1185void
1186verify_chunk(Chunk *chunk) {
1187 if (chunk->const_idx >= 256) {
1188 eprintln("too many constants on chunk %s", chunk->id);
1189 exit(EXIT_FAILURE);
1190 }
1191 if (chunk->str_idx >= 256) {
1192 eprintln("too many strings on chunk %s", chunk->id);
1193 exit(EXIT_FAILURE);
1194 }
1195 if (chunk->reg_idx >= 256) {
1196 eprintln("too many registers used on chunk %s", chunk->id);
1197 exit(EXIT_FAILURE);
1198 }
1199 if (chunk->labels_idx >= 256) {
1200 eprintln("too many labels used on chunk %s", chunk->id);
1201 exit(EXIT_FAILURE);
1202 }
1203 if (chunk->fun_idx >= 256) {
1204 eprintln("too many functions on chunk %s", chunk->id);
1205 exit(EXIT_FAILURE);
1206 }
1207}
1208
1209void
1210declare_function(Chunk *chunk, Node *node) {
1211 Str name = node->unique_name;
1212 FunctionMap *map = funcmap_lookup(&chunk->funmap, node->unique_name);
1213 if (map) {
1214 return;
1215 }
1216 Function fun = (Function){
1217 .name = name,
1218 .index = chunk->fun_idx++,
1219 .param_arity = array_size(node->func.params),
1220 .return_arity = array_size(node->func.ret),
1221 };
1222 funcmap_insert(&chunk->funmap, node->unique_name, fun, chunk->storage);
1223}
1224
1225CompResult
1226compile_function(Compiler *compiler, Chunk *chunk, Node *node) {
1227 // The current activation record procedure for the VM is as follows:
1228 //
1229 // [caller][callee ]
1230 // [ .... ][ RET VAL ][ PARAMS ][ LOCALS ][ REGISTERS ][ RET META ]
1231 // ^
1232 // frame pointer
1233 //
1234 // The caller is responsible for allocating the return memory and the
1235 // parameter memory and filling the param data before OP_CALL.
1236 //
1237 chunk = &compiler->main_chunk;
1238 Chunk *func = chunk_alloc(chunk);
1239 func->name = node->unique_name;
1240 declare_function(chunk, node);
1241 array_push(chunk->functions, func, chunk->storage);
1242
1243 // Push arguments as locals.
1244 for (sz i = 0; i < array_size(node->func.params); i++) {
1245 Node *param = node->func.params[i];
1246 Str name = param->unique_name;
1247 Str type = param->type;
1248 sz arr_size = 0;
1249 if (str_has_prefix(type, cstr("@"))) {
1250 if (param->var.type && param->var.type->kind == NODE_ARR_TYPE &&
1251 param->var.type->sym.arr_size->value.i > 0) {
1252 arr_size = param->var.type->sym.arr_size->value.i;
1253 }
1254 }
1255 add_variable(func, name, type, arr_size);
1256 }
1257 func->param_off = func->var_off;
1258
1259 // Compiling the body.
1260 CompResult res = compile_expr(compiler, func, node->func.body);
1261
1262 // Put return values into memory.
1263 switch (res.type) {
1264 case COMP_CONST: {
1265 emit_op(OP_PUTRETI, res.idx, 0, 0, node, func);
1266 } break;
1267 case COMP_REG: {
1268 emit_op(OP_PUTRET, res.idx, 0, 0, node, func);
1269 } break;
1270 default: break;
1271 }
1272
1273 emit_op(OP_RET, 0, 0, 0, node, func);
1274 verify_chunk(func);
1275 return (CompResult){.type = COMP_NIL};
1276}
1277
1278CompResult
1279compile_let(Compiler *compiler, Chunk *chunk, Node *node) {
1280 sz op_ldaddr = OP_LDLADDR;
1281 sz op_stvari = OP_STLVARI;
1282 sz op_stvar = OP_STLVAR;
1283 if (chunk == &compiler->main_chunk) {
1284 op_ldaddr = OP_LDGADDR;
1285 op_stvari = OP_STGVARI;
1286 op_stvar = OP_STGVAR;
1287 }
1288 Str name = node->unique_name;
1289 Str type = node->var.name->type;
1290 sz arr_size = 0;
1291 if (str_has_prefix(type, cstr("@"))) {
1292 if (node->var.type && node->var.type->kind == NODE_ARR_TYPE &&
1293 node->var.type->sym.arr_size->value.i > 0) {
1294 arr_size = node->var.type->sym.arr_size->value.i;
1295 }
1296 }
1297
1298 sz idx = add_variable(chunk, name, type, arr_size);
1299
1300 // Value.
1301 if (node->var.val) {
1302 CompResult res = compile_expr(compiler, chunk, node->var.val);
1303 switch (res.type) {
1304 case COMP_CONST: {
1305 emit_op(op_stvari, idx, res.idx, 0, node->var.val, chunk);
1306 } break;
1307 case COMP_REG: {
1308 if (str_eq(node->var.val->type, cstr("str"))) {
1309 // Get the address for the local/global storage
1310 // variable.
1311 sz var_addr = chunk->reg_idx++;
1312 emit_op(op_ldaddr, var_addr, idx, 0, node, chunk);
1313
1314 // Copy the fat pointer.
1315 emit_fat_copy(chunk, node, var_addr, res.idx);
1316 } else {
1317 emit_op(op_stvar, idx, res.idx, 0, node->var.val, chunk);
1318 }
1319 } break;
1320 case COMP_STRING: {
1321 // Get the address for the string value variable.
1322 sz str_addr = chunk->reg_idx++;
1323 emit_op(OP_LDSTR, str_addr, res.idx, 0, node->var.val, chunk);
1324
1325 // Get the address for the local/global storage
1326 // variable.
1327 sz var_addr = chunk->reg_idx++;
1328 emit_op(op_ldaddr, var_addr, idx, 0, node, chunk);
1329
1330 // Copy the fat pointer.
1331 emit_fat_copy(chunk, node, var_addr, str_addr);
1332 } break;
1333 default: {
1334 emit_compile_err(compiler, chunk, node);
1335 return (CompResult){.type = COMP_ERR};
1336 } break;
1337 }
1338 }
1339
1340 return (CompResult){.type = COMP_NIL};
1341}
1342
1343CompResult
1344compile_set(Compiler *compiler, Chunk *chunk, Node *node) {
1345 Str name = node->unique_name;
1346 StrVarMap *map = NULL;
1347 Chunk *next = chunk;
1348 while (next) {
1349 map = varmap_lookup(&next->varmap, name);
1350 if (map) {
1351 break;
1352 }
1353 next = chunk->parent;
1354 }
1355 if (!map) {
1356 emit_compile_err(compiler, chunk, node);
1357 return (CompResult){.type = COMP_ERR};
1358 }
1359 sz op_ldaddr = OP_LDLADDR;
1360 sz op_ldvar = OP_LDLVAR;
1361 sz op_stvari = OP_STLVARI;
1362 sz op_stvar = OP_STLVAR;
1363 if (next == &compiler->main_chunk) {
1364 op_ldaddr = OP_LDGADDR;
1365 op_ldvar = OP_LDGVAR;
1366 op_stvari = OP_STGVARI;
1367 op_stvar = OP_STGVAR;
1368 }
1369 CompResult res = compile_expr(compiler, chunk, node->var.val);
1370 if (node->var.name->kind == NODE_SYMBOL_IDX) {
1371 // Value.
1372 sz reg_val;
1373 switch (res.type) {
1374 case COMP_CONST: {
1375 reg_val = chunk->reg_idx++;
1376 emit_op(OP_LD64K, reg_val, res.idx, 0, node, chunk);
1377 } break;
1378 case COMP_REG: {
1379 reg_val = res.idx;
1380 } break;
1381 default: {
1382 emit_compile_err(compiler, chunk, node);
1383 return (CompResult){.type = COMP_ERR};
1384 } break;
1385 }
1386
1387 // Address.
1388 sz reg_addr = chunk->reg_idx++;
1389 // Is this a pointer access or an array access?
1390 if (str_has_prefix(map->val.type, cstr("[]"))) {
1391 emit_op(op_ldaddr, reg_addr, map->val.idx, 0, node->var.val, chunk);
1392 } else {
1393 emit_op(op_ldvar, reg_addr, map->val.idx, 0, node->var.val, chunk);
1394 }
1395
1396 // Index.
1397 CompResult idx =
1398 compile_expr(compiler, chunk, node->var.name->sym.arr_size);
1399 switch (idx.type) {
1400 case COMP_CONST: {
1401 emit_op(OP_ST64I, reg_val, reg_addr, idx.idx, node, chunk);
1402 } break;
1403 case COMP_REG: {
1404 emit_op(OP_ST64, reg_val, reg_addr, idx.idx, node, chunk);
1405 } break;
1406 default: {
1407 emit_compile_err(compiler, chunk, node);
1408 return (CompResult){.type = COMP_ERR};
1409 } break;
1410 }
1411 // TODO: offset should be in bytes, in this case we are assuming
1412 // 64bit types, hence ST64
1413 return (CompResult){.type = COMP_NIL};
1414 }
1415 switch (res.type) {
1416 case COMP_CONST: {
1417 emit_op(op_stvari, map->val.idx, res.idx, 0, node->var.val, chunk);
1418 } break;
1419 case COMP_REG: {
1420 if (str_eq(node->var.val->type, cstr("str"))) {
1421 // Get the address for the local/global storage
1422 // variable.
1423 sz var_addr = chunk->reg_idx++;
1424 emit_op(op_ldaddr, var_addr, map->val.idx, 0, node, chunk);
1425
1426 // Copy the fat pointer.
1427 emit_fat_copy(chunk, node, var_addr, res.idx);
1428 } else {
1429 emit_op(op_stvar, map->val.idx, res.idx, 0, node->var.val,
1430 chunk);
1431 }
1432 } break;
1433 default: {
1434 emit_compile_err(compiler, chunk, node);
1435 return (CompResult){.type = COMP_ERR};
1436 } break;
1437 }
1438 return (CompResult){.type = COMP_NIL};
1439}
1440
1441CompResult
1442compile_symbol(Compiler *compiler, Chunk *chunk, Node *node) {
1443 Str name = node->unique_name;
1444 StrVarMap *map = NULL;
1445 Chunk *next = chunk;
1446 while (next) {
1447 map = varmap_lookup(&next->varmap, name);
1448 if (map) {
1449 break;
1450 }
1451 next = next->parent;
1452 }
1453 if (!map) {
1454 emit_compile_err(compiler, chunk, node);
1455 return (CompResult){.type = COMP_ERR};
1456 }
1457 sz op_ldaddr = OP_LDLADDR;
1458 sz op_ldvar = OP_LDLVAR;
1459 if (next == &compiler->main_chunk) {
1460 op_ldaddr = OP_LDGADDR;
1461 op_ldvar = OP_LDGVAR;
1462 }
1463 Variable var = map->val;
1464 u8 reg_dst = chunk->reg_idx++;
1465 if (node->is_ptr || str_has_prefix(var.type, cstr("[]")) ||
1466 str_eq(var.type, cstr("str"))) {
1467 emit_op(op_ldaddr, reg_dst, var.idx, 0, node, chunk);
1468 } else {
1469 emit_op(op_ldvar, reg_dst, var.idx, 0, node, chunk);
1470 }
424 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 1471 return (CompResult){.type = COMP_REG, .idx = reg_dst};
425} 1472}
426 1473
427CompResult 1474CompResult
428compile_expr(Chunk *chunk, Node *node) { 1475compile_symbol_idx(Compiler *compiler, Chunk *chunk, Node *node) {
1476 Str name = node->unique_name;
1477 StrVarMap *map = NULL;
1478 Chunk *next = chunk;
1479 while (next) {
1480 map = varmap_lookup(&next->varmap, name);
1481 if (map) {
1482 break;
1483 }
1484 next = next->parent;
1485 }
1486 if (!map) {
1487 eprintln("couldn't resolve symbol name: %s", name);
1488 emit_compile_err(compiler, chunk, node);
1489 return (CompResult){.type = COMP_ERR};
1490 }
1491 sz op_ldaddr = OP_LDLADDR;
1492 sz op_ldvar = OP_LDLVAR;
1493 if (next == &compiler->main_chunk) {
1494 op_ldaddr = OP_LDGADDR;
1495 op_ldvar = OP_LDGVAR;
1496 }
1497
1498 // Destination.
1499 u8 reg_dst = chunk->reg_idx++;
1500
1501 // Address.
1502 sz reg_addr = chunk->reg_idx++;
1503 if (str_has_prefix(map->val.type, cstr("[]"))) {
1504 emit_op(op_ldaddr, reg_addr, map->val.idx, 0, node->var.val, chunk);
1505 } else {
1506 emit_op(op_ldvar, reg_addr, map->val.idx, 0, node->var.val, chunk);
1507 }
1508
1509 // Index.
1510 CompResult idx = compile_expr(compiler, chunk, node->sym.arr_size);
1511 switch (idx.type) {
1512 case COMP_CONST: {
1513 emit_op(OP_LD64I, reg_dst, reg_addr, idx.idx, node, chunk);
1514 } break;
1515 case COMP_REG: {
1516 emit_op(OP_LD64, reg_dst, reg_addr, idx.idx, node, chunk);
1517 } break;
1518 default: {
1519 emit_compile_err(compiler, chunk, node);
1520 return (CompResult){.type = COMP_ERR};
1521 } break;
1522 }
1523 // TODO: hardcoding the type size for now (LD64/LD64I).
1524 return (CompResult){.type = COMP_REG, .idx = reg_dst};
1525}
1526
1527CompResult
1528compile_expr(Compiler *compiler, Chunk *chunk, Node *node) {
429 switch (node->kind) { 1529 switch (node->kind) {
1530 case NODE_BREAK: return compile_break(compiler, chunk, node);
1531 case NODE_CONTINUE: return compile_continue(compiler, chunk, node);
1532 case NODE_RETURN: return compile_return(compiler, chunk, node);
1533 case NODE_FUN: return compile_function(compiler, chunk, node);
1534 case NODE_FUNCALL: return compile_funcall(compiler, chunk, node);
1535 case NODE_WHILE: return compile_while(compiler, chunk, node);
1536 case NODE_IF: return compile_if(compiler, chunk, node);
1537 case NODE_COND: return compile_cond(compiler, chunk, node);
430 // Logic. 1538 // Logic.
431 // case NODE_XOR:
432 case NODE_BITNOT: 1539 case NODE_BITNOT:
433 case NODE_NOT: return compile_unary(chunk, node); break; 1540 case NODE_NOT: return compile_unary(compiler, chunk, node); break;
434 case NODE_AND: 1541 case NODE_AND:
435 case NODE_OR: 1542 case NODE_OR:
436 case NODE_EQ: 1543 case NODE_EQ:
@@ -441,6 +1548,7 @@ compile_expr(Chunk *chunk, Node *node) {
441 // Bitwise ops. 1548 // Bitwise ops.
442 case NODE_BITAND: 1549 case NODE_BITAND:
443 case NODE_BITOR: 1550 case NODE_BITOR:
1551 case NODE_BITXOR:
444 case NODE_BITLSHIFT: 1552 case NODE_BITLSHIFT:
445 case NODE_BITRSHIFT: 1553 case NODE_BITRSHIFT:
446 // Arithmetic. 1554 // Arithmetic.
@@ -449,92 +1557,45 @@ compile_expr(Chunk *chunk, Node *node) {
449 case NODE_SUB: 1557 case NODE_SUB:
450 case NODE_MUL: 1558 case NODE_MUL:
451 case NODE_DIV: 1559 case NODE_DIV:
452 case NODE_MOD: return compile_binary(chunk, node); break; 1560 case NODE_MOD: return compile_binary(compiler, chunk, node); break;
453 case NODE_TRUE: 1561 case NODE_TRUE:
454 case NODE_FALSE: 1562 case NODE_FALSE:
455 case NODE_NUM_FLOAT: 1563 case NODE_NUM_FLOAT:
456 case NODE_NUM_UINT: 1564 case NODE_NUM_UINT:
457 case NODE_NUM_INT: { 1565 case NODE_NUM_INT: {
458 sz value = node->value.i; 1566 sz value = node->value.i;
459 // Make sure we don't have duplicated constants. 1567 sz const_idx = add_constant(chunk, value);
460 IntIntMap *map = intintmap_lookup(&chunk->intmap, value);
461 if (!map) {
462 map = intintmap_insert(&chunk->intmap, value,
463 chunk->const_idx++, chunk->storage);
464 Constant c = (Constant){.i = node->value.i};
465 array_push(chunk->constants, c, chunk->storage);
466 }
467 return (CompResult){ 1568 return (CompResult){
468 .type = COMP_CONST, 1569 .type = COMP_CONST,
469 .idx = map->val, 1570 .idx = const_idx,
470 }; 1571 };
471 } break; 1572 } break;
472 case NODE_STRING: { 1573 case NODE_STRING: {
473 Str string = node->value.str; 1574 Str string = node->value.str;
474 // Make sure we don't have duplicated strings. 1575 sz str_idx = add_string(chunk, string);
475 StrIntMap *map = strintmap_lookup(&chunk->strmap, string);
476 if (!map) {
477 map = strintmap_insert(&chunk->strmap, string, chunk->str_idx++,
478 chunk->storage);
479 array_push(chunk->strings, string, chunk->storage);
480 }
481 return (CompResult){ 1576 return (CompResult){
482 .type = COMP_STRING, 1577 .type = COMP_STRING,
483 .idx = map->val, 1578 .idx = str_idx,
484 }; 1579 };
485 } break; 1580 } break;
486 case NODE_LET: { 1581 case NODE_LET: return compile_let(compiler, chunk, node);
487 sz idx = array_size(chunk->vars); 1582 case NODE_SET: return compile_set(compiler, chunk, node);
488 Str name = node->unique_name; 1583 case NODE_SYMBOL: return compile_symbol(compiler, chunk, node);
489 Str type = node->var_name->type; 1584 case NODE_SYMBOL_IDX: return compile_symbol_idx(compiler, chunk, node);
490 sz size = 8;
491 // TODO: get type storage from a table to consider all the basic
492 // types as well as user defined ones.
493 if (str_eq(type, cstr("str"))) {
494 size = 16;
495 }
496 Variable var = (Variable){
497 .name = name,
498 .type = type,
499 .size = size,
500 .offset = chunk->var_off,
501 };
502 varmap_insert(&chunk->varmap, name, var, chunk->storage);
503 array_push(chunk->vars, var, chunk->storage);
504 chunk->var_off += size;
505
506 // Value.
507 if (node->var_val) {
508 CompResult res = compile_expr(chunk, node->var_val);
509 switch (res.type) {
510 case COMP_CONST: {
511 EMIT_OP(OP_STVARI, idx, res.idx, 0, node->var_val,
512 chunk);
513 } break;
514 case COMP_REG: {
515 EMIT_OP(OP_STVAR, idx, res.idx, 0, node->var_val,
516 chunk);
517 } break;
518 default: {
519 return (CompResult){.type = COMP_ERR};
520 } break;
521 }
522 }
523
524 return (CompResult){.type = COMP_NIL};
525 } break;
526 case NODE_BLOCK: { 1585 case NODE_BLOCK: {
527 CompResult res; 1586 CompResult res;
528 for (sz i = 0; i < array_size(node->elements); i++) { 1587 for (sz i = 0; i < array_size(node->elements); i++) {
529 Node *root = node->elements[i]; 1588 Node *root = node->elements[i];
530 res = compile_expr(chunk, root); 1589 res = compile_expr(compiler, chunk, root);
531 } 1590 }
532 return res; 1591 return res;
533 } break; 1592 } break;
1593 case NODE_NIL: return (CompResult){.type = COMP_NIL};
534 default: { 1594 default: {
535 eprintln("error: compilation not implemented for node %s", 1595 eprintln("error: compilation not implemented for node %s",
536 node_str[node->kind]); 1596 node_str[node->kind]);
537 exit(EXIT_FAILURE); 1597 emit_compile_err(compiler, chunk, node);
1598 return (CompResult){.type = COMP_ERR};
538 } break; 1599 } break;
539 } 1600 }
540 return (CompResult){.type = COMP_ERR}; 1601 return (CompResult){.type = COMP_ERR};
@@ -543,6 +1604,10 @@ compile_expr(Chunk *chunk, Node *node) {
543void 1604void
544disassemble_instruction(Instruction instruction) { 1605disassemble_instruction(Instruction instruction) {
545 switch (instruction.op) { 1606 switch (instruction.op) {
1607 case OP_CALL:
1608 println("%s f%d", op_str[instruction.op], instruction.dst,
1609 instruction.a, instruction.b);
1610 break;
546 case OP_MOV8: 1611 case OP_MOV8:
547 case OP_MOV16: 1612 case OP_MOV16:
548 case OP_MOV32: 1613 case OP_MOV32:
@@ -550,6 +1615,11 @@ disassemble_instruction(Instruction instruction) {
550 println("%s r%d, r%d", op_str[instruction.op], instruction.dst, 1615 println("%s r%d, r%d", op_str[instruction.op], instruction.dst,
551 instruction.a, instruction.b); 1616 instruction.a, instruction.b);
552 break; 1617 break;
1618 case OP_JMPF:
1619 case OP_JMPT:
1620 println("%s l%d, r%d", op_str[instruction.op], instruction.dst,
1621 instruction.a, instruction.b);
1622 break;
553 case OP_LD8K: 1623 case OP_LD8K:
554 case OP_LD16K: 1624 case OP_LD16K:
555 case OP_LD32K: 1625 case OP_LD32K:
@@ -587,6 +1657,7 @@ disassemble_instruction(Instruction instruction) {
587 case OP_BITRSHIFTI: 1657 case OP_BITRSHIFTI:
588 case OP_BITANDI: 1658 case OP_BITANDI:
589 case OP_BITORI: 1659 case OP_BITORI:
1660 case OP_BITXORI:
590 println("%s r%d, r%d, c%d", op_str[instruction.op], instruction.dst, 1661 println("%s r%d, r%d, c%d", op_str[instruction.op], instruction.dst,
591 instruction.a, instruction.b); 1662 instruction.a, instruction.b);
592 break; 1663 break;
@@ -620,14 +1691,28 @@ disassemble_instruction(Instruction instruction) {
620 case OP_BITRSHIFT: 1691 case OP_BITRSHIFT:
621 case OP_BITAND: 1692 case OP_BITAND:
622 case OP_BITOR: 1693 case OP_BITOR:
1694 case OP_BITXOR:
623 println("%s r%d, r%d, r%d", op_str[instruction.op], instruction.dst, 1695 println("%s r%d, r%d, r%d", op_str[instruction.op], instruction.dst,
624 instruction.a, instruction.b); 1696 instruction.a, instruction.b);
625 break; 1697 break;
626 case OP_STVAR: 1698 case OP_LDGVAR:
1699 case OP_LDGADDR:
1700 case OP_LDLVAR:
1701 case OP_LDLADDR:
1702 println("%s r%d, v%d", op_str[instruction.op], instruction.dst,
1703 instruction.a, instruction.b);
1704 break;
1705 case OP_LDSTR:
1706 println("%s r%d, s%d", op_str[instruction.op], instruction.dst,
1707 instruction.a, instruction.b);
1708 break;
1709 case OP_STGVAR:
1710 case OP_STLVAR:
627 println("%s v%d, r%d", op_str[instruction.op], instruction.dst, 1711 println("%s v%d, r%d", op_str[instruction.op], instruction.dst,
628 instruction.a, instruction.b); 1712 instruction.a, instruction.b);
629 break; 1713 break;
630 case OP_STVARI: 1714 case OP_STGVARI:
1715 case OP_STLVARI:
631 println("%s v%d, c%d", op_str[instruction.op], instruction.dst, 1716 println("%s v%d, c%d", op_str[instruction.op], instruction.dst,
632 instruction.a, instruction.b); 1717 instruction.a, instruction.b);
633 break; 1718 break;
@@ -641,6 +1726,37 @@ disassemble_instruction(Instruction instruction) {
641 println("%s r%d, r%d", op_str[instruction.op], instruction.dst, 1726 println("%s r%d, r%d", op_str[instruction.op], instruction.dst,
642 instruction.a, instruction.b); 1727 instruction.a, instruction.b);
643 break; 1728 break;
1729 case OP_JMP:
1730 println("%s l%d", op_str[instruction.op], instruction.dst,
1731 instruction.a, instruction.b);
1732 break;
1733 case OP_JMPFI:
1734 case OP_JMPTI:
1735 println("%s l%d, c%d", op_str[instruction.op], instruction.dst,
1736 instruction.a, instruction.b);
1737 break;
1738 case OP_PRINTS64:
1739 case OP_PRINTF64:
1740 case OP_PRINTSTR:
1741 case OP_PRINTBOOL:
1742 case OP_PUSH:
1743 case OP_POP:
1744 case OP_PUTRET:
1745 println("%s r%d", op_str[instruction.op], instruction.dst,
1746 instruction.a, instruction.b);
1747 break;
1748 case OP_PRINTSTRI:
1749 case OP_PRINTS64I:
1750 case OP_PRINTF64I:
1751 case OP_PRINTBOOLI:
1752 case OP_RESERVE:
1753 case OP_PUSHI:
1754 case OP_PUTRETI:
1755 println("%s c%d", op_str[instruction.op], instruction.dst,
1756 instruction.a, instruction.b);
1757 break;
1758 case OP_RET:
1759 case OP_RECUR:
644 case OP_HALT: println("%s", op_str[instruction.op]); break; 1760 case OP_HALT: println("%s", op_str[instruction.op]); break;
645 default: println("Unknown opcode %d", instruction.op); break; 1761 default: println("Unknown opcode %d", instruction.op); break;
646 } 1762 }
@@ -648,36 +1764,120 @@ disassemble_instruction(Instruction instruction) {
648 1764
649void 1765void
650disassemble_chunk(Chunk chunk) { 1766disassemble_chunk(Chunk chunk) {
651 println("%s: =========== code ===========", chunk.file_name); 1767 println("CHUNK %d: %s%s", chunk.id, chunk.file_name, chunk.name);
1768 println("n_regs: %d, n_vars: %d, n_strings: %d, n_consts: %d",
1769 chunk.reg_idx, array_size(chunk.vars), chunk.str_idx,
1770 chunk.const_idx);
1771 println("================== code ==================");
1772 println(" LINE:COL INUM LABELS OP OPERANDS ");
1773 println("------------------------------------------");
652 for (sz i = 0; i < array_size(chunk.code); i++) { 1774 for (sz i = 0; i < array_size(chunk.code); i++) {
653 print("%s: %x{4}: ", chunk.file_name, i); 1775 printf(" %.4ld:%.4ld %.4lx ", chunk.linecol[i].line,
1776 chunk.linecol[i].col, i);
1777 IntIntMapIter lab_it = intintmap_iterator(chunk.labels, chunk.storage);
1778 IntIntMap *m = intintmap_next(&lab_it, chunk.storage);
1779 Str labs = cstr("");
1780 while (m) {
1781 if (m->val == i) {
1782 labs = str_concat(labs, cstr(".L"), chunk.storage);
1783 labs = str_concat(labs, str_from_int(m->key, chunk.storage),
1784 chunk.storage);
1785 break;
1786 }
1787 m = intintmap_next(&lab_it, chunk.storage);
1788 }
1789 if (labs.size) {
1790 print("%s", labs);
1791 for (sz i = 0; i < 7 - labs.size; i++) {
1792 print(" ");
1793 }
1794 } else {
1795 printf(" ");
1796 }
654 disassemble_instruction(chunk.code[i]); 1797 disassemble_instruction(chunk.code[i]);
655 } 1798 }
656 if (array_size(chunk.constants) > 0) { 1799 if (array_size(chunk.constants) > 0) {
657 println("%s: ========= constants ========", chunk.file_name); 1800 println("================ constants ===============", chunk.file_name);
658 for (sz i = 0; i < array_size(chunk.constants); i++) { 1801 for (sz i = 0; i < array_size(chunk.constants); i++) {
659 println("%s: %x{2}: %x{8}", chunk.file_name, i, 1802 println(" %x{2}: %x{8}", i, chunk.constants[i]);
660 chunk.constants[i]);
661 } 1803 }
662 } 1804 }
663 if (array_size(chunk.strings) > 0) { 1805 if (array_size(chunk.strings) > 0) {
664 println("%s: ========== strings =========", chunk.file_name); 1806 println("================= strings ================", chunk.file_name);
665 for (sz i = 0; i < array_size(chunk.strings); i++) { 1807 for (sz i = 0; i < array_size(chunk.strings); i++) {
666 println("%s: %x{2}: %s", chunk.file_name, i, chunk.strings[i]); 1808 println(" %x{2}: %s", i, chunk.strings[i]);
667 } 1809 }
668 } 1810 }
669 if (array_size(chunk.vars) > 0) { 1811 if (array_size(chunk.vars) > 0) {
670 println("%s: ========= variables ========", chunk.file_name); 1812 println("================ variables ===============", chunk.file_name);
671 for (sz i = 0; i < array_size(chunk.vars); i++) { 1813 for (sz i = 0; i < array_size(chunk.vars); i++) {
672 println("%s: %x{2}: [%x{4}:%x{4}] %s: %s", chunk.file_name, i, 1814 println(" %x{2}: [%x{4}:%x{4}] %s: %s", i, chunk.vars[i].offset,
673 chunk.vars[i].offset,
674 chunk.vars[i].offset + chunk.vars[i].size, 1815 chunk.vars[i].offset + chunk.vars[i].size,
675 chunk.vars[i].name, chunk.vars[i].type); 1816 chunk.vars[i].name, chunk.vars[i].type);
676 } 1817 }
677 } 1818 }
678 println("n_regs: %d, n_vars: %d, n_strings: %d, n_consts: %d", 1819 if (array_size(chunk.functions) > 0) {
679 chunk.reg_idx, array_size(chunk.vars), chunk.str_idx, 1820 println("================ functions ===============", chunk.file_name);
680 chunk.const_idx); 1821 for (sz i = 0; i < array_size(chunk.functions); i++) {
1822 Chunk *func = chunk.functions[i];
1823 println(" %x{2}: func%d: %s", i, func->id, func->name);
1824 }
1825 }
1826 println("==========================================");
1827 for (sz i = 0; i < array_size(chunk.functions); i++) {
1828 Chunk *func = chunk.functions[i];
1829 disassemble_chunk(*func);
1830 }
1831}
1832
1833void
1834bytecode_compiler(Compiler *compiler, Parser parser) {
1835 compiler->main_chunk = (Chunk){
1836 .file_name = compiler->file_name,
1837 .storage = compiler->storage,
1838 .name = cstr(".main"),
1839 };
1840 // TODO: Fill up builtin types and tables.
1841 array_zero(compiler->main_chunk.constants, 256, compiler->storage);
1842 array_zero(compiler->main_chunk.code, 0xffff, compiler->storage);
1843 sz n_roots = array_size(parser.nodes);
1844 CompResult res = {0};
1845
1846 // Do a first pass to setup the function declarations on the main scope.
1847 Chunk *chunk = &compiler->main_chunk;
1848 for (sz i = 0; i < n_roots; i++) {
1849 Node *root = parser.nodes[i];
1850 if (root->kind == NODE_FUN) {
1851 declare_function(chunk, root);
1852 }
1853 }
1854
1855 // Compile all root expressions.
1856 for (sz i = 0; i < n_roots; i++) {
1857 Node *root = parser.nodes[i];
1858 res = compile_expr(compiler, chunk, root);
1859 }
1860
1861 // Make sure the last result is on r0.
1862 sz res_reg = 0;
1863 bool is_nil = false;
1864 switch (res.type) {
1865 case COMP_CONST: {
1866 res_reg = chunk->reg_idx++;
1867 Instruction inst =
1868 (Instruction){.op = OP_LD64K, .dst = res_reg, .a = res.idx};
1869 array_push(chunk->code, inst, chunk->storage);
1870 } break;
1871 case COMP_REG: {
1872 res_reg = res.idx;
1873 } break;
1874 case COMP_NIL: {
1875 is_nil = true;
1876 } break;
1877 default: break;
1878 }
1879 emit_op(OP_HALT, res_reg, !is_nil, 0, NULL, chunk);
1880 verify_chunk(chunk);
681} 1881}
682 1882
683#endif // COMPILER_C 1883#endif // COMPILER_C