aboutsummaryrefslogtreecommitdiffstats
path: root/src/compiler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler.c')
-rw-r--r--src/compiler.c1452
1 files changed, 1316 insertions, 136 deletions
diff --git a/src/compiler.c b/src/compiler.c
index bd50955..c2b48b3 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -25,13 +25,32 @@ 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
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
32typedef struct Chunk { 46typedef struct Chunk {
33 sz id; 47 sz id;
48 Str name;
49 struct Chunk *parent;
50
34 Instruction *code; 51 Instruction *code;
52 IntIntMap *labels; // label -> chunk_index
53 sz labels_idx;
35 54
36 // Constant values that fit in 64 bits. 55 // Constant values that fit in 64 bits.
37 Constant *constants; 56 Constant *constants;
@@ -47,45 +66,91 @@ typedef struct Chunk {
47 Variable *vars; 66 Variable *vars;
48 StrVarMap *varmap; 67 StrVarMap *varmap;
49 sz var_off; 68 sz var_off;
69 sz param_off;
50 70
51 // Number of registers currently used in this chunk. 71 // Number of registers currently used in this chunk.
52 sz reg_idx; 72 sz reg_idx;
53 73
74 // Number of functions currently used in this chunk.
75 struct Chunk **functions;
76 FunctionMap *funmap;
77 sz fun_idx;
78
54 // Debugging. 79 // Debugging.
55 Str file_name; 80 Str file_name;
56 Arena *storage; 81 Arena *storage;
57 // TODO: line/col info for debugging. 82 LineCol *linecol;
58} Chunk; 83} Chunk;
59 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
60typedef enum OpCode { 99typedef enum OpCode {
61 // OP DST A B 100 // OP DST A B
62 // --------------------------------------------------------------- 101 // ---------------------------------------------------------------
63 // VM/high level instructions. 102 // VM/high level instructions.
64 OP_HALT, // halt 103 OP_HALT, // halt
65 OP_STVARI, // stvari vx, ca 104 // NOTE: LDGVAR/STGVAR* could be obtained in terms of LDGADDR.
66 OP_STVAR, // stvar vx, ra 105 OP_STGVARI, // stgvari vx, ca
67 OP_LDVAR, // ldvar rx, vx 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
68 // Load/Store instructions. 133 // Load/Store instructions.
69 OP_LD8K, // ld8k rx, ca -> u8 rx = ca 134 OP_LD8K, // ld8k rx, ca -> u8 rx = ca
70 OP_LD16K, // ld16k rx, ca -> u16 rx = ca 135 OP_LD16K, // ld16k rx, ca -> u16 rx = ca
71 OP_LD32K, // ld32k rx, ca -> u32 rx = ca 136 OP_LD32K, // ld32k rx, ca -> u32 rx = ca
72 OP_LD64K, // ld64k rx, ca -> u64 rx = ca 137 OP_LD64K, // ld64k rx, ca -> u64 rx = ca
73 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]
74 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]
75 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]
76 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]
77 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]
78 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]
79 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]
80 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]
81 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
82 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
83 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
84 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
85 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
86 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
87 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
88 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
89 // Integer arithmetic (only int/s64 for now). 154 // Integer arithmetic (only int/s64 for now).
90 OP_ADDI, // addk rx, ra, cb 155 OP_ADDI, // addk rx, ra, cb
91 OP_SUBI, // subk rx, ra, cb 156 OP_SUBI, // subk rx, ra, cb
@@ -137,19 +202,52 @@ typedef enum OpCode {
137 OP_BITRSHIFTI, // shri rx, ra, cb 202 OP_BITRSHIFTI, // shri rx, ra, cb
138 OP_BITANDI, // bandi rx, ra, cb 203 OP_BITANDI, // bandi rx, ra, cb
139 OP_BITORI, // bori rx, ra, cb 204 OP_BITORI, // bori rx, ra, cb
205 OP_BITXORI, // bxor rx, ra, cb
140 OP_BITNOTI, // bnoti rx, ca 206 OP_BITNOTI, // bnoti rx, ca
141 OP_BITLSHIFT, // shl rx, ra, rb 207 OP_BITLSHIFT, // shl rx, ra, rb
142 OP_BITRSHIFT, // shr rx, ra, rb 208 OP_BITRSHIFT, // shr rx, ra, rb
143 OP_BITAND, // band rx, ra, rb 209 OP_BITAND, // band rx, ra, rb
144 OP_BITOR, // bor rx, ra, rb 210 OP_BITOR, // bor rx, ra, rb
211 OP_BITXOR, // bxor rx, ra, rb
145 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
146} OpCode; 219} OpCode;
147 220
148Str op_str[] = { 221Str op_str[] = {
222 // High level ops.
149 [OP_HALT] = cstr("HALT "), 223 [OP_HALT] = cstr("HALT "),
150 [OP_STVAR] = cstr("STVAR "), 224 [OP_STGVAR] = cstr("STGVAR "),
151 [OP_STVARI] = cstr("STVARI "), 225 [OP_STGVARI] = cstr("STGVARI "),
152 [OP_LDVAR] = cstr("LDVAR "), 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 "),
153 // Load ops. 251 // Load ops.
154 [OP_LD8K] = cstr("LD8K "), 252 [OP_LD8K] = cstr("LD8K "),
155 [OP_LD16K] = cstr("LD16K "), 253 [OP_LD16K] = cstr("LD16K "),
@@ -222,12 +320,20 @@ Str op_str[] = {
222 [OP_BITRSHIFTI] = cstr("RSHI "), 320 [OP_BITRSHIFTI] = cstr("RSHI "),
223 [OP_BITANDI] = cstr("BANDI "), 321 [OP_BITANDI] = cstr("BANDI "),
224 [OP_BITORI] = cstr("BORI "), 322 [OP_BITORI] = cstr("BORI "),
323 [OP_BITXORI] = cstr("BXORI "),
225 [OP_BITNOTI] = cstr("BNOTI "), 324 [OP_BITNOTI] = cstr("BNOTI "),
226 [OP_BITLSHIFT] = cstr("LSH "), 325 [OP_BITLSHIFT] = cstr("LSH "),
227 [OP_BITRSHIFT] = cstr("RSH "), 326 [OP_BITRSHIFT] = cstr("RSH "),
228 [OP_BITAND] = cstr("BAND "), 327 [OP_BITAND] = cstr("BAND "),
229 [OP_BITOR] = cstr("BOR "), 328 [OP_BITOR] = cstr("BOR "),
329 [OP_BITXOR] = cstr("XBOR "),
230 [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 "),
231}; 337};
232 338
233typedef enum { 339typedef enum {
@@ -235,6 +341,7 @@ typedef enum {
235 COMP_CONST, 341 COMP_CONST,
236 COMP_STRING, 342 COMP_STRING,
237 COMP_REG, 343 COMP_REG,
344 COMP_RET,
238 COMP_ERR, 345 COMP_ERR,
239} CompResultType; 346} CompResultType;
240 347
@@ -243,21 +350,108 @@ typedef struct CompResult {
243 CompResultType type; 350 CompResultType type;
244} CompResult; 351} CompResult;
245 352
246CompResult 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}
247 367
248#define EMIT_OP(OP, DST, A, B, NODE, CHUNK) \ 368sz
249 do { \ 369add_string(Chunk *chunk, Str string) {
250 Instruction inst = (Instruction){ \ 370 // Make sure we don't have duplicated string.
251 .op = (OP), \ 371 StrIntMap *map = strintmap_lookup(&chunk->strmap, string);
252 .dst = (DST), \ 372 if (!map) {
253 .a = (A), \ 373 map = strintmap_insert(&chunk->strmap, string, chunk->str_idx++,
254 .b = (B), \ 374 chunk->storage);
255 }; \ 375 array_push(chunk->strings, string, chunk->storage);
256 array_push((CHUNK)->code, inst, (CHUNK)->storage); \ 376 }
257 } 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}
258 452
259CompResult 453CompResult
260compile_binary(Chunk *chunk, Node *node) { 454compile_binary(Compiler *compiler, Chunk *chunk, Node *node) {
261 OpCode op = OP_HALT; 455 OpCode op = OP_HALT;
262 OpCode opi = OP_HALT; 456 OpCode opi = OP_HALT;
263 OpCode ldop = OP_LD64K; 457 OpCode ldop = OP_LD64K;
@@ -346,6 +540,10 @@ compile_binary(Chunk *chunk, Node *node) {
346 op = OP_BITOR; 540 op = OP_BITOR;
347 opi = OP_BITORI; 541 opi = OP_BITORI;
348 } break; 542 } break;
543 case NODE_BITXOR: {
544 op = OP_BITXOR;
545 opi = OP_BITXORI;
546 } break;
349 case NODE_BITAND: { 547 case NODE_BITAND: {
350 op = OP_BITAND; 548 op = OP_BITAND;
351 opi = OP_BITANDI; 549 opi = OP_BITANDI;
@@ -360,19 +558,20 @@ compile_binary(Chunk *chunk, Node *node) {
360 } break; 558 } break;
361 default: break; 559 default: break;
362 } 560 }
363 CompResult comp_a = compile_expr(chunk, node->left); 561 CompResult comp_a = compile_expr(compiler, chunk, node->binary.left);
364 CompResult comp_b = compile_expr(chunk, node->right); 562 CompResult comp_b = compile_expr(compiler, chunk, node->binary.right);
365 sz reg_a; 563 sz reg_a;
366 sz reg_b; 564 sz reg_b;
367 switch (comp_a.type) { 565 switch (comp_a.type) {
368 case COMP_CONST: { 566 case COMP_CONST: {
369 reg_a = chunk->reg_idx++; 567 reg_a = chunk->reg_idx++;
370 EMIT_OP(ldop, reg_a, comp_a.idx, 0, node, chunk); 568 emit_op(ldop, reg_a, comp_a.idx, 0, node, chunk);
371 } break; 569 } break;
372 case COMP_REG: { 570 case COMP_REG: {
373 reg_a = comp_a.idx; 571 reg_a = comp_a.idx;
374 } break; 572 } break;
375 default: { 573 default: {
574 emit_compile_err(compiler, chunk, node);
376 return (CompResult){.type = COMP_ERR}; 575 return (CompResult){.type = COMP_ERR};
377 } break; 576 } break;
378 } 577 }
@@ -385,16 +584,17 @@ compile_binary(Chunk *chunk, Node *node) {
385 reg_b = comp_b.idx; 584 reg_b = comp_b.idx;
386 } break; 585 } break;
387 default: { 586 default: {
587 emit_compile_err(compiler, chunk, node);
388 return (CompResult){.type = COMP_ERR}; 588 return (CompResult){.type = COMP_ERR};
389 } break; 589 } break;
390 } 590 }
391 sz reg_dst = chunk->reg_idx++; // Better for optimization 591 sz reg_dst = chunk->reg_idx++; // Better for optimization
392 EMIT_OP(op, reg_dst, reg_a, reg_b, node, chunk); 592 emit_op(op, reg_dst, reg_a, reg_b, node, chunk);
393 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 593 return (CompResult){.type = COMP_REG, .idx = reg_dst};
394} 594}
395 595
396CompResult 596CompResult
397compile_unary(Chunk *chunk, Node *node) { 597compile_unary(Compiler *compiler, Chunk *chunk, Node *node) {
398 OpCode op = OP_HALT; 598 OpCode op = OP_HALT;
399 OpCode opi = OP_HALT; 599 OpCode opi = OP_HALT;
400 switch (node->kind) { 600 switch (node->kind) {
@@ -408,7 +608,7 @@ compile_unary(Chunk *chunk, Node *node) {
408 } break; 608 } break;
409 default: break; 609 default: break;
410 } 610 }
411 CompResult comp_a = compile_expr(chunk, node->left); 611 CompResult comp_a = compile_expr(compiler, chunk, node->binary.left);
412 sz reg_a; 612 sz reg_a;
413 switch (comp_a.type) { 613 switch (comp_a.type) {
414 case COMP_CONST: { 614 case COMP_CONST: {
@@ -419,21 +619,925 @@ compile_unary(Chunk *chunk, Node *node) {
419 reg_a = comp_a.idx; 619 reg_a = comp_a.idx;
420 } break; 620 } break;
421 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);
422 return (CompResult){.type = COMP_ERR}; 644 return (CompResult){.type = COMP_ERR};
423 } break; 645 } break;
424 } 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
425 sz reg_dst = chunk->reg_idx++; 778 sz reg_dst = chunk->reg_idx++;
426 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);
427 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 851 return (CompResult){.type = COMP_REG, .idx = reg_dst};
428} 852}
429 853
430CompResult 854CompResult
431compile_expr(Chunk *chunk, Node *node) { 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 }
1471 return (CompResult){.type = COMP_REG, .idx = reg_dst};
1472}
1473
1474CompResult
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) {
432 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);
433 // Logic. 1538 // Logic.
434 // case NODE_XOR:
435 case NODE_BITNOT: 1539 case NODE_BITNOT:
436 case NODE_NOT: return compile_unary(chunk, node); break; 1540 case NODE_NOT: return compile_unary(compiler, chunk, node); break;
437 case NODE_AND: 1541 case NODE_AND:
438 case NODE_OR: 1542 case NODE_OR:
439 case NODE_EQ: 1543 case NODE_EQ:
@@ -444,6 +1548,7 @@ compile_expr(Chunk *chunk, Node *node) {
444 // Bitwise ops. 1548 // Bitwise ops.
445 case NODE_BITAND: 1549 case NODE_BITAND:
446 case NODE_BITOR: 1550 case NODE_BITOR:
1551 case NODE_BITXOR:
447 case NODE_BITLSHIFT: 1552 case NODE_BITLSHIFT:
448 case NODE_BITRSHIFT: 1553 case NODE_BITRSHIFT:
449 // Arithmetic. 1554 // Arithmetic.
@@ -452,105 +1557,45 @@ compile_expr(Chunk *chunk, Node *node) {
452 case NODE_SUB: 1557 case NODE_SUB:
453 case NODE_MUL: 1558 case NODE_MUL:
454 case NODE_DIV: 1559 case NODE_DIV:
455 case NODE_MOD: return compile_binary(chunk, node); break; 1560 case NODE_MOD: return compile_binary(compiler, chunk, node); break;
456 case NODE_TRUE: 1561 case NODE_TRUE:
457 case NODE_FALSE: 1562 case NODE_FALSE:
458 case NODE_NUM_FLOAT: 1563 case NODE_NUM_FLOAT:
459 case NODE_NUM_UINT: 1564 case NODE_NUM_UINT:
460 case NODE_NUM_INT: { 1565 case NODE_NUM_INT: {
461 sz value = node->value.i; 1566 sz value = node->value.i;
462 // Make sure we don't have duplicated constants. 1567 sz const_idx = add_constant(chunk, value);
463 IntIntMap *map = intintmap_lookup(&chunk->intmap, value);
464 if (!map) {
465 map = intintmap_insert(&chunk->intmap, value,
466 chunk->const_idx++, chunk->storage);
467 Constant c = (Constant){.i = node->value.i};
468 array_push(chunk->constants, c, chunk->storage);
469 }
470 return (CompResult){ 1568 return (CompResult){
471 .type = COMP_CONST, 1569 .type = COMP_CONST,
472 .idx = map->val, 1570 .idx = const_idx,
473 }; 1571 };
474 } break; 1572 } break;
475 case NODE_STRING: { 1573 case NODE_STRING: {
476 Str string = node->value.str; 1574 Str string = node->value.str;
477 // Make sure we don't have duplicated strings. 1575 sz str_idx = add_string(chunk, string);
478 StrIntMap *map = strintmap_lookup(&chunk->strmap, string);
479 if (!map) {
480 map = strintmap_insert(&chunk->strmap, string, chunk->str_idx++,
481 chunk->storage);
482 array_push(chunk->strings, string, chunk->storage);
483 }
484 return (CompResult){ 1576 return (CompResult){
485 .type = COMP_STRING, 1577 .type = COMP_STRING,
486 .idx = map->val, 1578 .idx = str_idx,
487 }; 1579 };
488 } break; 1580 } break;
489 case NODE_LET: { 1581 case NODE_LET: return compile_let(compiler, chunk, node);
490 sz idx = array_size(chunk->vars); 1582 case NODE_SET: return compile_set(compiler, chunk, node);
491 Str name = node->unique_name; 1583 case NODE_SYMBOL: return compile_symbol(compiler, chunk, node);
492 Str type = node->var_name->type; 1584 case NODE_SYMBOL_IDX: return compile_symbol_idx(compiler, chunk, node);
493 sz size = 8;
494 // TODO: get type storage from a table to consider all the basic
495 // types as well as user defined ones.
496 if (str_eq(type, cstr("str"))) {
497 size = 16;
498 }
499 Variable var = (Variable){
500 .name = name,
501 .type = type,
502 .size = size,
503 .offset = chunk->var_off,
504 .idx = idx,
505 };
506 varmap_insert(&chunk->varmap, name, var, chunk->storage);
507 array_push(chunk->vars, var, chunk->storage);
508 chunk->var_off += size;
509
510 // Value.
511 if (node->var_val) {
512 CompResult res = compile_expr(chunk, node->var_val);
513 switch (res.type) {
514 case COMP_CONST: {
515 EMIT_OP(OP_STVARI, idx, res.idx, 0, node->var_val,
516 chunk);
517 } break;
518 case COMP_REG: {
519 EMIT_OP(OP_STVAR, idx, res.idx, 0, node->var_val,
520 chunk);
521 } break;
522 default: {
523 return (CompResult){.type = COMP_ERR};
524 } break;
525 }
526 }
527
528 return (CompResult){.type = COMP_NIL};
529 } break;
530 case NODE_SYMBOL: {
531 Str name = node->unique_name;
532 StrVarMap *map = varmap_lookup(&chunk->varmap, name);
533 if (!map) {
534 println("error: unreachable... name: %s", name);
535 exit(EXIT_FAILURE);
536 }
537 Variable var = map->val;
538 u8 reg_dst = chunk->reg_idx++;
539 EMIT_OP(OP_LDVAR, reg_dst, var.idx, 0, node->var_val, chunk);
540 return (CompResult){.type = COMP_REG, .idx = reg_dst};
541 } break;
542 case NODE_BLOCK: { 1585 case NODE_BLOCK: {
543 CompResult res; 1586 CompResult res;
544 for (sz i = 0; i < array_size(node->elements); i++) { 1587 for (sz i = 0; i < array_size(node->elements); i++) {
545 Node *root = node->elements[i]; 1588 Node *root = node->elements[i];
546 res = compile_expr(chunk, root); 1589 res = compile_expr(compiler, chunk, root);
547 } 1590 }
548 return res; 1591 return res;
549 } break; 1592 } break;
1593 case NODE_NIL: return (CompResult){.type = COMP_NIL};
550 default: { 1594 default: {
551 eprintln("error: compilation not implemented for node %s", 1595 eprintln("error: compilation not implemented for node %s",
552 node_str[node->kind]); 1596 node_str[node->kind]);
553 exit(EXIT_FAILURE); 1597 emit_compile_err(compiler, chunk, node);
1598 return (CompResult){.type = COMP_ERR};
554 } break; 1599 } break;
555 } 1600 }
556 return (CompResult){.type = COMP_ERR}; 1601 return (CompResult){.type = COMP_ERR};
@@ -559,6 +1604,10 @@ compile_expr(Chunk *chunk, Node *node) {
559void 1604void
560disassemble_instruction(Instruction instruction) { 1605disassemble_instruction(Instruction instruction) {
561 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;
562 case OP_MOV8: 1611 case OP_MOV8:
563 case OP_MOV16: 1612 case OP_MOV16:
564 case OP_MOV32: 1613 case OP_MOV32:
@@ -566,6 +1615,11 @@ disassemble_instruction(Instruction instruction) {
566 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,
567 instruction.a, instruction.b); 1616 instruction.a, instruction.b);
568 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;
569 case OP_LD8K: 1623 case OP_LD8K:
570 case OP_LD16K: 1624 case OP_LD16K:
571 case OP_LD32K: 1625 case OP_LD32K:
@@ -603,6 +1657,7 @@ disassemble_instruction(Instruction instruction) {
603 case OP_BITRSHIFTI: 1657 case OP_BITRSHIFTI:
604 case OP_BITANDI: 1658 case OP_BITANDI:
605 case OP_BITORI: 1659 case OP_BITORI:
1660 case OP_BITXORI:
606 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,
607 instruction.a, instruction.b); 1662 instruction.a, instruction.b);
608 break; 1663 break;
@@ -636,18 +1691,28 @@ disassemble_instruction(Instruction instruction) {
636 case OP_BITRSHIFT: 1691 case OP_BITRSHIFT:
637 case OP_BITAND: 1692 case OP_BITAND:
638 case OP_BITOR: 1693 case OP_BITOR:
1694 case OP_BITXOR:
639 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,
640 instruction.a, instruction.b); 1696 instruction.a, instruction.b);
641 break; 1697 break;
642 case OP_LDVAR: 1698 case OP_LDGVAR:
1699 case OP_LDGADDR:
1700 case OP_LDLVAR:
1701 case OP_LDLADDR:
643 println("%s r%d, v%d", op_str[instruction.op], instruction.dst, 1702 println("%s r%d, v%d", op_str[instruction.op], instruction.dst,
644 instruction.a, instruction.b); 1703 instruction.a, instruction.b);
645 break; 1704 break;
646 case OP_STVAR: 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:
647 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,
648 instruction.a, instruction.b); 1712 instruction.a, instruction.b);
649 break; 1713 break;
650 case OP_STVARI: 1714 case OP_STGVARI:
1715 case OP_STLVARI:
651 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,
652 instruction.a, instruction.b); 1717 instruction.a, instruction.b);
653 break; 1718 break;
@@ -661,6 +1726,37 @@ disassemble_instruction(Instruction instruction) {
661 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,
662 instruction.a, instruction.b); 1727 instruction.a, instruction.b);
663 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:
664 case OP_HALT: println("%s", op_str[instruction.op]); break; 1760 case OP_HALT: println("%s", op_str[instruction.op]); break;
665 default: println("Unknown opcode %d", instruction.op); break; 1761 default: println("Unknown opcode %d", instruction.op); break;
666 } 1762 }
@@ -668,36 +1764,120 @@ disassemble_instruction(Instruction instruction) {
668 1764
669void 1765void
670disassemble_chunk(Chunk chunk) { 1766disassemble_chunk(Chunk chunk) {
671 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("------------------------------------------");
672 for (sz i = 0; i < array_size(chunk.code); i++) { 1774 for (sz i = 0; i < array_size(chunk.code); i++) {
673 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 }
674 disassemble_instruction(chunk.code[i]); 1797 disassemble_instruction(chunk.code[i]);
675 } 1798 }
676 if (array_size(chunk.constants) > 0) { 1799 if (array_size(chunk.constants) > 0) {
677 println("%s: ========= constants ========", chunk.file_name); 1800 println("================ constants ===============", chunk.file_name);
678 for (sz i = 0; i < array_size(chunk.constants); i++) { 1801 for (sz i = 0; i < array_size(chunk.constants); i++) {
679 println("%s: %x{2}: %x{8}", chunk.file_name, i, 1802 println(" %x{2}: %x{8}", i, chunk.constants[i]);
680 chunk.constants[i]);
681 } 1803 }
682 } 1804 }
683 if (array_size(chunk.strings) > 0) { 1805 if (array_size(chunk.strings) > 0) {
684 println("%s: ========== strings =========", chunk.file_name); 1806 println("================= strings ================", chunk.file_name);
685 for (sz i = 0; i < array_size(chunk.strings); i++) { 1807 for (sz i = 0; i < array_size(chunk.strings); i++) {
686 println("%s: %x{2}: %s", chunk.file_name, i, chunk.strings[i]); 1808 println(" %x{2}: %s", i, chunk.strings[i]);
687 } 1809 }
688 } 1810 }
689 if (array_size(chunk.vars) > 0) { 1811 if (array_size(chunk.vars) > 0) {
690 println("%s: ========= variables ========", chunk.file_name); 1812 println("================ variables ===============", chunk.file_name);
691 for (sz i = 0; i < array_size(chunk.vars); i++) { 1813 for (sz i = 0; i < array_size(chunk.vars); i++) {
692 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,
693 chunk.vars[i].offset,
694 chunk.vars[i].offset + chunk.vars[i].size, 1815 chunk.vars[i].offset + chunk.vars[i].size,
695 chunk.vars[i].name, chunk.vars[i].type); 1816 chunk.vars[i].name, chunk.vars[i].type);
696 } 1817 }
697 } 1818 }
698 println("n_regs: %d, n_vars: %d, n_strings: %d, n_consts: %d", 1819 if (array_size(chunk.functions) > 0) {
699 chunk.reg_idx, array_size(chunk.vars), chunk.str_idx, 1820 println("================ functions ===============", chunk.file_name);
700 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);
701} 1881}
702 1882
703#endif // COMPILER_C 1883#endif // COMPILER_C