aboutsummaryrefslogtreecommitdiffstats
path: root/src/compiler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler.c')
-rw-r--r--src/compiler.c1427
1 files changed, 1241 insertions, 186 deletions
diff --git a/src/compiler.c b/src/compiler.c
index 5bddcb6..c2b48b3 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -25,7 +25,7 @@ typedef struct Instruction {
25typedef union Constant { 25typedef union Constant {
26 s64 i; 26 s64 i;
27 u64 u; 27 u64 u;
28 double f; 28 f64 f;
29 ptrsize ptr; 29 ptrsize ptr;
30} Constant; 30} Constant;
31 31
@@ -34,9 +34,23 @@ typedef struct LineCol {
34 sz col; 34 sz col;
35} LineCol; 35} LineCol;
36 36
37typedef struct Function {
38 Str name;
39 sz param_arity;
40 sz return_arity;
41 sz index;
42} Function;
43
44MAPDEF(FunctionMap, funcmap, Str, Function, str_hash, str_eq)
45
37typedef struct Chunk { 46typedef struct Chunk {
38 sz id; 47 sz id;
48 Str name;
49 struct Chunk *parent;
50
39 Instruction *code; 51 Instruction *code;
52 IntIntMap *labels; // label -> chunk_index
53 sz labels_idx;
40 54
41 // Constant values that fit in 64 bits. 55 // Constant values that fit in 64 bits.
42 Constant *constants; 56 Constant *constants;
@@ -52,45 +66,91 @@ typedef struct Chunk {
52 Variable *vars; 66 Variable *vars;
53 StrVarMap *varmap; 67 StrVarMap *varmap;
54 sz var_off; 68 sz var_off;
69 sz param_off;
55 70
56 // Number of registers currently used in this chunk. 71 // Number of registers currently used in this chunk.
57 sz reg_idx; 72 sz reg_idx;
58 73
74 // Number of functions currently used in this chunk.
75 struct Chunk **functions;
76 FunctionMap *funmap;
77 sz fun_idx;
78
59 // Debugging. 79 // Debugging.
60 Str file_name; 80 Str file_name;
61 Arena *storage; 81 Arena *storage;
62 LineCol *linecol; 82 LineCol *linecol;
63} Chunk; 83} Chunk;
64 84
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
65typedef enum OpCode { 99typedef enum OpCode {
66 // OP DST A B 100 // OP DST A B
67 // --------------------------------------------------------------- 101 // ---------------------------------------------------------------
68 // VM/high level instructions. 102 // VM/high level instructions.
69 OP_HALT, // halt 103 OP_HALT, // halt
104 // NOTE: LDGVAR/STGVAR* could be obtained in terms of LDGADDR.
70 OP_STGVARI, // stgvari vx, ca 105 OP_STGVARI, // stgvari vx, ca
71 OP_STGVAR, // stgvar vx, ra 106 OP_STGVAR, // stgvar vx, ra
72 OP_LDGVAR, // ldgvar rx, vx 107 OP_LDGVAR, // ldgvar rx, va
108 OP_LDGADDR, // ldgaddr rx, va
109 OP_STLVARI, // stlvari vx, ca
110 OP_STLVAR, // stlvar vx, ra
111 OP_LDLVAR, // ldlvar rx, va
112 OP_LDLADDR, // ldladdr rx, va
113 OP_LDSTR, // ldstr rx, sa ; Stores the address of the string sa into rx
114 // Functions.
115 OP_CALL, // call fx ; Call the function fx
116 OP_RECUR, // recur ; Jump to the beginning of the function.
117 OP_RET, // ret ; Returns from current function
118 OP_RESERVE, // reserve cx ; Increments the stack pointer by cx bytes
119 OP_POP, // pop rx ; Pops the last value of the stack into rx.
120 OP_PUSH, // push rx ; Push the rx value to the stack.
121 OP_PUSHI, // pushi cx ; Push the cx value to the stack.
122 OP_PUTRET, // putret rx ; Put rx into the return value memory.
123 OP_PUTRETI, // putreti cx ; Put cx into the return value memory.
124 // Printing values with builtin print/println functions.
125 OP_PRINTSTR, // p rx
126 OP_PRINTSTRI, // p cx
127 OP_PRINTS64, // p rx
128 OP_PRINTS64I, // p cx
129 OP_PRINTF64, // p rx
130 OP_PRINTF64I, // p cx
131 OP_PRINTBOOL, // p rx
132 OP_PRINTBOOLI, // p cx
73 // Load/Store instructions. 133 // Load/Store instructions.
74 OP_LD8K, // ld8k rx, ca -> u8 rx = ca 134 OP_LD8K, // ld8k rx, ca -> u8 rx = ca
75 OP_LD16K, // ld16k rx, ca -> u16 rx = ca 135 OP_LD16K, // ld16k rx, ca -> u16 rx = ca
76 OP_LD32K, // ld32k rx, ca -> u32 rx = ca 136 OP_LD32K, // ld32k rx, ca -> u32 rx = ca
77 OP_LD64K, // ld64k rx, ca -> u64 rx = ca 137 OP_LD64K, // ld64k rx, ca -> u64 rx = ca
78 OP_LD8I, // ld8i rx, ra, cb -> u8 *p; rx = p[ra + cb] 138 OP_LD8I, // ld8i rx, ra, cb -> u8 *p = ra; rx = p[cb]
79 OP_LD16I, // ld16i rx, ra, cb -> u16 *p; rx = p[ra + cb] 139 OP_LD16I, // ld16i rx, ra, cb -> u16 *p = ra; rx = p[cb]
80 OP_LD32I, // ld32i rx, ra, cb -> u32 *p; rx = p[ra + cb] 140 OP_LD32I, // ld32i rx, ra, cb -> u32 *p = ra; rx = p[cb]
81 OP_LD64I, // ld64i rx, ra, cb -> u64 *p; rx = p[ra + cb] 141 OP_LD64I, // ld64i rx, ra, cb -> u64 *p = ra; rx = p[cb]
82 OP_LD8, // ld8 rx, ra, rb -> u8 *p; rx = p[ra + rb] 142 OP_LD8, // ld8 rx, ra, rb -> u8 *p = ra; rx = p[rb]
83 OP_LD16, // ld16 rx, ra, rb -> u16 *p; rx = p[ra + rb] 143 OP_LD16, // ld16 rx, ra, rb -> u16 *p = ra; rx = p[rb]
84 OP_LD32, // ld32 rx, ra, rb -> u32 *p; rx = p[ra + rb] 144 OP_LD32, // ld32 rx, ra, rb -> u32 *p = ra; rx = p[rb]
85 OP_LD64, // ld64 rx, ra, rb -> u64 *p; rx = p[ra + rb] 145 OP_LD64, // ld64 rx, ra, rb -> u64 *p = ra; rx = p[rb]
86 OP_ST8I, // st8i rx, ra, cb -> u8 *p; p[ra + cb] = rx 146 OP_ST8I, // st8i rx, ra, cb -> u8 *p = ra; p[cb] = rx
87 OP_ST16I, // st16i rx, ra, cb -> u16 *p; p[ra + cb] = rx 147 OP_ST16I, // st16i rx, ra, cb -> u16 *p = ra; p[cb] = rx
88 OP_ST32I, // st32i rx, ra, cb -> u32 *p; p[ra + cb] = rx 148 OP_ST32I, // st32i rx, ra, cb -> u32 *p = ra; p[cb] = rx
89 OP_ST64I, // st64i rx, ra, cb -> u64 *p; p[ra + cb] = rx 149 OP_ST64I, // st64i rx, ra, cb -> u64 *p = ra; p[cb] = rx
90 OP_ST8, // st8 rx, ra, rb -> u8 *p; p[ra + rb] = rx 150 OP_ST8, // st8 rx, ra, rb -> u8 *p = ra; p[rb] = rx
91 OP_ST16, // st16 rx, ra, rb -> u16 *p; p[ra + rb] = rx 151 OP_ST16, // st16 rx, ra, rb -> u16 *p = ra; p[rb] = rx
92 OP_ST32, // st32 rx, ra, rb -> u32 *p; p[ra + rb] = rx 152 OP_ST32, // st32 rx, ra, rb -> u32 *p = ra; p[rb] = rx
93 OP_ST64, // st64 rx, ra, rb -> u64 *p; p[ra + rb] = rx 153 OP_ST64, // st64 rx, ra, rb -> u64 *p = ra; p[rb] = rx
94 // Integer arithmetic (only int/s64 for now). 154 // Integer arithmetic (only int/s64 for now).
95 OP_ADDI, // addk rx, ra, cb 155 OP_ADDI, // addk rx, ra, cb
96 OP_SUBI, // subk rx, ra, cb 156 OP_SUBI, // subk rx, ra, cb
@@ -142,26 +202,52 @@ typedef enum OpCode {
142 OP_BITRSHIFTI, // shri rx, ra, cb 202 OP_BITRSHIFTI, // shri rx, ra, cb
143 OP_BITANDI, // bandi rx, ra, cb 203 OP_BITANDI, // bandi rx, ra, cb
144 OP_BITORI, // bori rx, ra, cb 204 OP_BITORI, // bori rx, ra, cb
205 OP_BITXORI, // bxor rx, ra, cb
145 OP_BITNOTI, // bnoti rx, ca 206 OP_BITNOTI, // bnoti rx, ca
146 OP_BITLSHIFT, // shl rx, ra, rb 207 OP_BITLSHIFT, // shl rx, ra, rb
147 OP_BITRSHIFT, // shr rx, ra, rb 208 OP_BITRSHIFT, // shr rx, ra, rb
148 OP_BITAND, // band rx, ra, rb 209 OP_BITAND, // band rx, ra, rb
149 OP_BITOR, // bor rx, ra, rb 210 OP_BITOR, // bor rx, ra, rb
211 OP_BITXOR, // bxor rx, ra, rb
150 OP_BITNOT, // bnot rx, ra 212 OP_BITNOT, // bnot rx, ra
151 // Jump instructions. 213 // Jump instructions.
152 OP_JMPI, // jmp cx ; cx := signed offset 214 OP_JMP, // jmp lx ; jmp to label lx
153 OP_JMPFI, // jmpf cx, ca ; rx := condition, ca := offset 215 OP_JMPF, // jmpf lx, rx ; jmp to label lx if rx is false
154 OP_JMPTI, // jmpt cx, ca ; rx := condition, ca := offset 216 OP_JMPT, // jmpt lx, rx ; jmp to label lx if rx is true
155 OP_JMP, // jmp rx ; rx := signed offset 217 OP_JMPFI, // jmpf lx, cx ; jmp to label lx if rx is false
156 OP_JMPF, // jmpf rx, ca ; rx := condition, ca := offset 218 OP_JMPTI, // jmpt lx, cx ; jmp to label lx if rx is true
157 OP_JMPT, // jmpt rx, ca ; rx := condition, ca := offset
158} OpCode; 219} OpCode;
159 220
160Str op_str[] = { 221Str op_str[] = {
222 // High level ops.
161 [OP_HALT] = cstr("HALT "), 223 [OP_HALT] = cstr("HALT "),
162 [OP_STGVAR] = cstr("STGVAR "), 224 [OP_STGVAR] = cstr("STGVAR "),
163 [OP_STGVARI] = cstr("STGVARI "), 225 [OP_STGVARI] = cstr("STGVARI "),
164 [OP_LDGVAR] = cstr("LDGVAR "), 226 [OP_LDGVAR] = cstr("LDGVAR "),
227 [OP_LDGADDR] = cstr("LDGADDR "),
228 [OP_STLVAR] = cstr("STLVAR "),
229 [OP_STLVARI] = cstr("STLVARI "),
230 [OP_LDLVAR] = cstr("LDLVAR "),
231 [OP_LDLADDR] = cstr("LDLADDR "),
232 [OP_LDSTR] = cstr("LDSTR "),
233 [OP_PRINTSTR] = cstr("PRNSTR "),
234 [OP_PRINTSTRI] = cstr("PRNSTRI "),
235 [OP_PRINTS64] = cstr("PRNS64 "),
236 [OP_PRINTS64I] = cstr("PRNS64I "),
237 [OP_PRINTF64] = cstr("PRNF64 "),
238 [OP_PRINTF64I] = cstr("PRNF64I "),
239 [OP_PRINTBOOL] = cstr("PRNBOOL "),
240 [OP_PRINTBOOLI] = cstr("PRNBOOLI"),
241 [OP_PUTRET] = cstr("PUTRET "),
242 [OP_PUTRETI] = cstr("PUTRETI "),
243 // Functions.
244 [OP_CALL] = cstr("CALL "),
245 [OP_RECUR] = cstr("RECUR "),
246 [OP_RET] = cstr("RET "),
247 [OP_RESERVE] = cstr("RESERVE "),
248 [OP_POP] = cstr("POP "),
249 [OP_PUSH] = cstr("PUSH "),
250 [OP_PUSHI] = cstr("PUSHI "),
165 // Load ops. 251 // Load ops.
166 [OP_LD8K] = cstr("LD8K "), 252 [OP_LD8K] = cstr("LD8K "),
167 [OP_LD16K] = cstr("LD16K "), 253 [OP_LD16K] = cstr("LD16K "),
@@ -234,19 +320,20 @@ Str op_str[] = {
234 [OP_BITRSHIFTI] = cstr("RSHI "), 320 [OP_BITRSHIFTI] = cstr("RSHI "),
235 [OP_BITANDI] = cstr("BANDI "), 321 [OP_BITANDI] = cstr("BANDI "),
236 [OP_BITORI] = cstr("BORI "), 322 [OP_BITORI] = cstr("BORI "),
323 [OP_BITXORI] = cstr("BXORI "),
237 [OP_BITNOTI] = cstr("BNOTI "), 324 [OP_BITNOTI] = cstr("BNOTI "),
238 [OP_BITLSHIFT] = cstr("LSH "), 325 [OP_BITLSHIFT] = cstr("LSH "),
239 [OP_BITRSHIFT] = cstr("RSH "), 326 [OP_BITRSHIFT] = cstr("RSH "),
240 [OP_BITAND] = cstr("BAND "), 327 [OP_BITAND] = cstr("BAND "),
241 [OP_BITOR] = cstr("BOR "), 328 [OP_BITOR] = cstr("BOR "),
329 [OP_BITXOR] = cstr("XBOR "),
242 [OP_BITNOT] = cstr("BNOT "), 330 [OP_BITNOT] = cstr("BNOT "),
243 // Jump instructions. 331 // Jump instructions.
244 [OP_JMPI] = cstr("JMPI "),
245 [OP_JMPFI] = cstr("JMPFI "),
246 [OP_JMPTI] = cstr("JMPTI "),
247 [OP_JMP] = cstr("JMP "), 332 [OP_JMP] = cstr("JMP "),
248 [OP_JMPF] = cstr("JMPF "), 333 [OP_JMPF] = cstr("JMPF "),
249 [OP_JMPT] = cstr("JMPT "), 334 [OP_JMPT] = cstr("JMPT "),
335 [OP_JMPFI] = cstr("JMPFI "),
336 [OP_JMPTI] = cstr("JMPTI "),
250}; 337};
251 338
252typedef enum { 339typedef enum {
@@ -254,6 +341,7 @@ typedef enum {
254 COMP_CONST, 341 COMP_CONST,
255 COMP_STRING, 342 COMP_STRING,
256 COMP_REG, 343 COMP_REG,
344 COMP_RET,
257 COMP_ERR, 345 COMP_ERR,
258} CompResultType; 346} CompResultType;
259 347
@@ -262,23 +350,108 @@ typedef struct CompResult {
262 CompResultType type; 350 CompResultType type;
263} CompResult; 351} CompResult;
264 352
265CompResult compile_expr(Chunk *chunk, Node *node); 353CompResult compile_expr(Compiler *compiler, Chunk *chunk, Node *node);
266 354
267#define EMIT_OP(OP, DST, A, B, NODE, CHUNK) \ 355sz
268 do { \ 356add_constant(Chunk *chunk, sz value) {
269 Instruction inst = (Instruction){ \ 357 IntIntMap *map = intintmap_lookup(&chunk->intmap, value);
270 .op = (OP), \ 358 // Make sure we don't have duplicated constants.
271 .dst = (DST), \ 359 if (!map) {
272 .a = (A), \ 360 map = intintmap_insert(&chunk->intmap, value, chunk->const_idx++,
273 .b = (B), \ 361 chunk->storage);
274 }; \ 362 Constant c = (Constant){.i = value};
275 array_push((CHUNK)->code, inst, (CHUNK)->storage); \ 363 array_push(chunk->constants, c, chunk->storage);
276 LineCol linecol = (LineCol){.line = (NODE)->line, .col = (NODE)->col}; \ 364 }
277 array_push((CHUNK)->linecol, linecol, (CHUNK)->storage); \ 365 return map->val;
278 } while (0) 366}
367
368sz
369add_string(Chunk *chunk, Str string) {
370 // Make sure we don't have duplicated string.
371 StrIntMap *map = strintmap_lookup(&chunk->strmap, string);
372 if (!map) {
373 map = strintmap_insert(&chunk->strmap, string, chunk->str_idx++,
374 chunk->storage);
375 array_push(chunk->strings, string, chunk->storage);
376 }
377 return map->val;
378}
379
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}
279 452
280CompResult 453CompResult
281compile_binary(Chunk *chunk, Node *node) { 454compile_binary(Compiler *compiler, Chunk *chunk, Node *node) {
282 OpCode op = OP_HALT; 455 OpCode op = OP_HALT;
283 OpCode opi = OP_HALT; 456 OpCode opi = OP_HALT;
284 OpCode ldop = OP_LD64K; 457 OpCode ldop = OP_LD64K;
@@ -367,6 +540,10 @@ compile_binary(Chunk *chunk, Node *node) {
367 op = OP_BITOR; 540 op = OP_BITOR;
368 opi = OP_BITORI; 541 opi = OP_BITORI;
369 } break; 542 } break;
543 case NODE_BITXOR: {
544 op = OP_BITXOR;
545 opi = OP_BITXORI;
546 } break;
370 case NODE_BITAND: { 547 case NODE_BITAND: {
371 op = OP_BITAND; 548 op = OP_BITAND;
372 opi = OP_BITANDI; 549 opi = OP_BITANDI;
@@ -381,19 +558,20 @@ compile_binary(Chunk *chunk, Node *node) {
381 } break; 558 } break;
382 default: break; 559 default: break;
383 } 560 }
384 CompResult comp_a = compile_expr(chunk, node->left); 561 CompResult comp_a = compile_expr(compiler, chunk, node->binary.left);
385 CompResult comp_b = compile_expr(chunk, node->right); 562 CompResult comp_b = compile_expr(compiler, chunk, node->binary.right);
386 sz reg_a; 563 sz reg_a;
387 sz reg_b; 564 sz reg_b;
388 switch (comp_a.type) { 565 switch (comp_a.type) {
389 case COMP_CONST: { 566 case COMP_CONST: {
390 reg_a = chunk->reg_idx++; 567 reg_a = chunk->reg_idx++;
391 EMIT_OP(ldop, reg_a, comp_a.idx, 0, node, chunk); 568 emit_op(ldop, reg_a, comp_a.idx, 0, node, chunk);
392 } break; 569 } break;
393 case COMP_REG: { 570 case COMP_REG: {
394 reg_a = comp_a.idx; 571 reg_a = comp_a.idx;
395 } break; 572 } break;
396 default: { 573 default: {
574 emit_compile_err(compiler, chunk, node);
397 return (CompResult){.type = COMP_ERR}; 575 return (CompResult){.type = COMP_ERR};
398 } break; 576 } break;
399 } 577 }
@@ -406,16 +584,17 @@ compile_binary(Chunk *chunk, Node *node) {
406 reg_b = comp_b.idx; 584 reg_b = comp_b.idx;
407 } break; 585 } break;
408 default: { 586 default: {
587 emit_compile_err(compiler, chunk, node);
409 return (CompResult){.type = COMP_ERR}; 588 return (CompResult){.type = COMP_ERR};
410 } break; 589 } break;
411 } 590 }
412 sz reg_dst = chunk->reg_idx++; // Better for optimization 591 sz reg_dst = chunk->reg_idx++; // Better for optimization
413 EMIT_OP(op, reg_dst, reg_a, reg_b, node, chunk); 592 emit_op(op, reg_dst, reg_a, reg_b, node, chunk);
414 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 593 return (CompResult){.type = COMP_REG, .idx = reg_dst};
415} 594}
416 595
417CompResult 596CompResult
418compile_unary(Chunk *chunk, Node *node) { 597compile_unary(Compiler *compiler, Chunk *chunk, Node *node) {
419 OpCode op = OP_HALT; 598 OpCode op = OP_HALT;
420 OpCode opi = OP_HALT; 599 OpCode opi = OP_HALT;
421 switch (node->kind) { 600 switch (node->kind) {
@@ -429,7 +608,7 @@ compile_unary(Chunk *chunk, Node *node) {
429 } break; 608 } break;
430 default: break; 609 default: break;
431 } 610 }
432 CompResult comp_a = compile_expr(chunk, node->left); 611 CompResult comp_a = compile_expr(compiler, chunk, node->binary.left);
433 sz reg_a; 612 sz reg_a;
434 switch (comp_a.type) { 613 switch (comp_a.type) {
435 case COMP_CONST: { 614 case COMP_CONST: {
@@ -440,30 +619,18 @@ compile_unary(Chunk *chunk, Node *node) {
440 reg_a = comp_a.idx; 619 reg_a = comp_a.idx;
441 } break; 620 } break;
442 default: { 621 default: {
622 emit_compile_err(compiler, chunk, node);
443 return (CompResult){.type = COMP_ERR}; 623 return (CompResult){.type = COMP_ERR};
444 } break; 624 } break;
445 } 625 }
446 sz reg_dst = chunk->reg_idx++; 626 sz reg_dst = chunk->reg_idx++;
447 EMIT_OP(op, reg_dst, reg_a, 0, node, chunk); 627 emit_op(op, reg_dst, reg_a, 0, node, chunk);
448 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 628 return (CompResult){.type = COMP_REG, .idx = reg_dst};
449} 629}
450 630
451sz
452add_constant(Chunk *chunk, sz value) {
453 IntIntMap *map = intintmap_lookup(&chunk->intmap, value);
454 // Make sure we don't have duplicated constants.
455 if (!map) {
456 map = intintmap_insert(&chunk->intmap, value, chunk->const_idx++,
457 chunk->storage);
458 Constant c = (Constant){.i = value};
459 array_push(chunk->constants, c, chunk->storage);
460 }
461 return map->val;
462}
463
464CompResult 631CompResult
465compile_if(Chunk *chunk, Node *node) { 632compile_if(Compiler *compiler, Chunk *chunk, Node *node) {
466 CompResult cond = compile_expr(chunk, node->cond_if); 633 CompResult cond = compile_expr(compiler, chunk, node->ifelse.cond);
467 OpCode jmpop; 634 OpCode jmpop;
468 switch (cond.type) { 635 switch (cond.type) {
469 case COMP_CONST: { 636 case COMP_CONST: {
@@ -473,84 +640,904 @@ compile_if(Chunk *chunk, Node *node) {
473 jmpop = OP_JMPF; 640 jmpop = OP_JMPF;
474 } break; 641 } break;
475 default: { 642 default: {
643 emit_compile_err(compiler, chunk, node);
476 return (CompResult){.type = COMP_ERR}; 644 return (CompResult){.type = COMP_ERR};
477 } break; 645 } break;
478 } 646 }
479 sz jump_a = array_size(chunk->code);
480 sz reg_dst = 255;
481 bool has_value = !str_eq(node->type, cstr("nil"));
482 if (has_value) {
483 reg_dst = chunk->reg_idx++;
484 }
485 647
486 // Jump to the `false` branch. 648 if (!str_eq(node->type, cstr("nil")) &&
487 EMIT_OP(jmpop, cond.idx, 0xff, 0, node->cond_if, chunk); 649 !str_has_prefix(node->type, cstr("ret:")) &&
650 !str_has_prefix(node->type, cstr("flow:"))) {
651 sz reg_dst = chunk->reg_idx++;
488 652
489 // Condition is true. 653 // Jump to the `false` branch.
490 CompResult then_expr = compile_expr(chunk, node->cond_expr); 654 sz lab0 = chunk->labels_idx++;
491 if (has_value) { 655 emit_op(jmpop, lab0, cond.idx, 0, node->ifelse.cond, chunk);
656
657 // Condition is true.
658 CompResult then_expr =
659 compile_expr(compiler, chunk, node->ifelse.expr_true);
492 switch (then_expr.type) { 660 switch (then_expr.type) {
493 case COMP_CONST: { 661 case COMP_CONST: {
494 EMIT_OP(OP_LD64K, reg_dst, then_expr.idx, 0, node->cond_if, 662 emit_op(OP_LD64K, reg_dst, then_expr.idx, 0, node->ifelse.cond,
495 chunk); 663 chunk);
496 } break; 664 } break;
497 case COMP_REG: { 665 case COMP_REG: {
498 EMIT_OP(OP_MOV64, reg_dst, then_expr.idx, 0, node->cond_if, 666 emit_op(OP_MOV64, reg_dst, then_expr.idx, 0, node->ifelse.cond,
499 chunk); 667 chunk);
500 } break; 668 } break;
669 case COMP_RET: break;
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;
501 default: { 694 default: {
695 emit_compile_err(compiler, chunk, node);
502 return (CompResult){.type = COMP_ERR}; 696 return (CompResult){.type = COMP_ERR};
503 } break; 697 } break;
504 } 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};
505 } 705 }
506 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
507 // Jump to the end of the expression. 714 // Jump to the end of the expression.
508 sz jump_b = array_size(chunk->code); 715 sz pos0 = array_size(chunk->code);
509 EMIT_OP(OP_JMPI, 0xff, 0, 0, node->cond_if, chunk); 716 sz lab1 = chunk->labels_idx++;
717 emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk);
510 718
511 // Else expression. 719 // Else expression.
512 CompResult else_expr = compile_expr(chunk, node->cond_else); 720 if (node->ifelse.expr_else) {
513 if (has_value) { 721 compile_expr(compiler, chunk, node->ifelse.expr_else);
514 switch (else_expr.type) { 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
778 sz reg_dst = chunk->reg_idx++;
779 sz lab1 = chunk->labels_idx++;
780 for (sz i = 0; i < array_size(node->match.cases); i++) {
781 // condition = expression
782 Node *expr = node->match.cases[i];
783 if (expr->case_entry.cond) {
784 CompResult cond =
785 compile_expr(compiler, chunk, expr->case_entry.cond);
786 OpCode jmpop;
787 switch (cond.type) {
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) {
515 case COMP_CONST: { 911 case COMP_CONST: {
516 EMIT_OP(OP_LD64K, reg_dst, else_expr.idx, 0, node->cond_if, 912 emit_op(OP_STLVARI, i, result.idx, 0, node, chunk);
517 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);
518 } break; 1095 } break;
519 case COMP_REG: { 1096 case COMP_REG: {
520 EMIT_OP(OP_MOV64, reg_dst, else_expr.idx, 0, node->cond_if, 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,
521 chunk); 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);
522 } break; 1125 } break;
523 default: { 1126 default: {
1127 emit_compile_err(compiler, chunk, node);
524 return (CompResult){.type = COMP_ERR}; 1128 return (CompResult){.type = COMP_ERR};
525 } break; 1129 } break;
526 } 1130 }
527 } 1131 }
528 sz end_expr = array_size(chunk->code);
529 1132
530 // Backpatch jumps. 1133 emit_op(OP_CALL, fun.index, 0, 0, node, chunk);
531 sz const_a = add_constant(chunk, jump_b + 1 - jump_a);
532 sz const_b = add_constant(chunk, end_expr - jump_b);
533 chunk->code[jump_a].a = const_a;
534 chunk->code[jump_b].dst = const_b;
535 // TODO: does it has an else or not? Moreover, should we enforce on the
536 // semantic level that if the `if` expression returns a value we must add an
537 // else?
538 1134
539 // Return. 1135 // Only one return parameter for now.
540 if (has_value) { 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);
541 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 1140 return (CompResult){.type = COMP_REG, .idx = reg_dst};
542 } 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 }
543 return (CompResult){.type = COMP_NIL}; 1438 return (CompResult){.type = COMP_NIL};
544} 1439}
545 1440
546CompResult 1441CompResult
547compile_expr(Chunk *chunk, Node *node) { 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) {
548 switch (node->kind) { 1529 switch (node->kind) {
549 case NODE_IF: return compile_if(chunk, node); 1530 case NODE_BREAK: return compile_break(compiler, chunk, node);
1531 case NODE_CONTINUE: return compile_continue(compiler, chunk, node);
1532 case NODE_RETURN: return compile_return(compiler, chunk, node);
1533 case NODE_FUN: return compile_function(compiler, chunk, node);
1534 case NODE_FUNCALL: return compile_funcall(compiler, chunk, node);
1535 case NODE_WHILE: return compile_while(compiler, chunk, node);
1536 case NODE_IF: return compile_if(compiler, chunk, node);
1537 case NODE_COND: return compile_cond(compiler, chunk, node);
550 // Logic. 1538 // Logic.
551 // case NODE_XOR:
552 case NODE_BITNOT: 1539 case NODE_BITNOT:
553 case NODE_NOT: return compile_unary(chunk, node); break; 1540 case NODE_NOT: return compile_unary(compiler, chunk, node); break;
554 case NODE_AND: 1541 case NODE_AND:
555 case NODE_OR: 1542 case NODE_OR:
556 case NODE_EQ: 1543 case NODE_EQ:
@@ -561,6 +1548,7 @@ compile_expr(Chunk *chunk, Node *node) {
561 // Bitwise ops. 1548 // Bitwise ops.
562 case NODE_BITAND: 1549 case NODE_BITAND:
563 case NODE_BITOR: 1550 case NODE_BITOR:
1551 case NODE_BITXOR:
564 case NODE_BITLSHIFT: 1552 case NODE_BITLSHIFT:
565 case NODE_BITRSHIFT: 1553 case NODE_BITRSHIFT:
566 // Arithmetic. 1554 // Arithmetic.
@@ -569,7 +1557,7 @@ compile_expr(Chunk *chunk, Node *node) {
569 case NODE_SUB: 1557 case NODE_SUB:
570 case NODE_MUL: 1558 case NODE_MUL:
571 case NODE_DIV: 1559 case NODE_DIV:
572 case NODE_MOD: return compile_binary(chunk, node); break; 1560 case NODE_MOD: return compile_binary(compiler, chunk, node); break;
573 case NODE_TRUE: 1561 case NODE_TRUE:
574 case NODE_FALSE: 1562 case NODE_FALSE:
575 case NODE_NUM_FLOAT: 1563 case NODE_NUM_FLOAT:
@@ -584,83 +1572,30 @@ compile_expr(Chunk *chunk, Node *node) {
584 } break; 1572 } break;
585 case NODE_STRING: { 1573 case NODE_STRING: {
586 Str string = node->value.str; 1574 Str string = node->value.str;
587 // Make sure we don't have duplicated strings. 1575 sz str_idx = add_string(chunk, string);
588 StrIntMap *map = strintmap_lookup(&chunk->strmap, string);
589 if (!map) {
590 map = strintmap_insert(&chunk->strmap, string, chunk->str_idx++,
591 chunk->storage);
592 array_push(chunk->strings, string, chunk->storage);
593 }
594 return (CompResult){ 1576 return (CompResult){
595 .type = COMP_STRING, 1577 .type = COMP_STRING,
596 .idx = map->val, 1578 .idx = str_idx,
597 }; 1579 };
598 } break; 1580 } break;
599 case NODE_LET: { 1581 case NODE_LET: return compile_let(compiler, chunk, node);
600 sz idx = array_size(chunk->vars); 1582 case NODE_SET: return compile_set(compiler, chunk, node);
601 Str name = node->unique_name; 1583 case NODE_SYMBOL: return compile_symbol(compiler, chunk, node);
602 Str type = node->var_name->type; 1584 case NODE_SYMBOL_IDX: return compile_symbol_idx(compiler, chunk, node);
603 sz size = 8;
604 // TODO: get type storage from a table to consider all the basic
605 // types as well as user defined ones.
606 if (str_eq(type, cstr("str"))) {
607 size = 16;
608 }
609 Variable var = (Variable){
610 .name = name,
611 .type = type,
612 .size = size,
613 .offset = chunk->var_off,
614 .idx = idx,
615 };
616 varmap_insert(&chunk->varmap, name, var, chunk->storage);
617 array_push(chunk->vars, var, chunk->storage);
618 chunk->var_off += size;
619
620 // Value.
621 if (node->var_val) {
622 CompResult res = compile_expr(chunk, node->var_val);
623 switch (res.type) {
624 case COMP_CONST: {
625 EMIT_OP(OP_STGVARI, idx, res.idx, 0, node->var_val,
626 chunk);
627 } break;
628 case COMP_REG: {
629 EMIT_OP(OP_STGVAR, idx, res.idx, 0, node->var_val,
630 chunk);
631 } break;
632 default: {
633 return (CompResult){.type = COMP_ERR};
634 } break;
635 }
636 }
637
638 return (CompResult){.type = COMP_NIL};
639 } break;
640 case NODE_SYMBOL: {
641 Str name = node->unique_name;
642 StrVarMap *map = varmap_lookup(&chunk->varmap, name);
643 if (!map) {
644 println("error: unreachable... name: %s", name);
645 exit(EXIT_FAILURE);
646 }
647 Variable var = map->val;
648 u8 reg_dst = chunk->reg_idx++;
649 EMIT_OP(OP_LDGVAR, reg_dst, var.idx, 0, node, chunk);
650 return (CompResult){.type = COMP_REG, .idx = reg_dst};
651 } break;
652 case NODE_BLOCK: { 1585 case NODE_BLOCK: {
653 CompResult res; 1586 CompResult res;
654 for (sz i = 0; i < array_size(node->elements); i++) { 1587 for (sz i = 0; i < array_size(node->elements); i++) {
655 Node *root = node->elements[i]; 1588 Node *root = node->elements[i];
656 res = compile_expr(chunk, root); 1589 res = compile_expr(compiler, chunk, root);
657 } 1590 }
658 return res; 1591 return res;
659 } break; 1592 } break;
1593 case NODE_NIL: return (CompResult){.type = COMP_NIL};
660 default: { 1594 default: {
661 eprintln("error: compilation not implemented for node %s", 1595 eprintln("error: compilation not implemented for node %s",
662 node_str[node->kind]); 1596 node_str[node->kind]);
663 exit(EXIT_FAILURE); 1597 emit_compile_err(compiler, chunk, node);
1598 return (CompResult){.type = COMP_ERR};
664 } break; 1599 } break;
665 } 1600 }
666 return (CompResult){.type = COMP_ERR}; 1601 return (CompResult){.type = COMP_ERR};
@@ -669,6 +1604,10 @@ compile_expr(Chunk *chunk, Node *node) {
669void 1604void
670disassemble_instruction(Instruction instruction) { 1605disassemble_instruction(Instruction instruction) {
671 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;
672 case OP_MOV8: 1611 case OP_MOV8:
673 case OP_MOV16: 1612 case OP_MOV16:
674 case OP_MOV32: 1613 case OP_MOV32:
@@ -676,12 +1615,15 @@ disassemble_instruction(Instruction instruction) {
676 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,
677 instruction.a, instruction.b); 1616 instruction.a, instruction.b);
678 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;
679 case OP_LD8K: 1623 case OP_LD8K:
680 case OP_LD16K: 1624 case OP_LD16K:
681 case OP_LD32K: 1625 case OP_LD32K:
682 case OP_LD64K: 1626 case OP_LD64K:
683 case OP_JMPF:
684 case OP_JMPT:
685 println("%s r%d, c%d", op_str[instruction.op], instruction.dst, 1627 println("%s r%d, c%d", op_str[instruction.op], instruction.dst,
686 instruction.a, instruction.b); 1628 instruction.a, instruction.b);
687 break; 1629 break;
@@ -715,6 +1657,7 @@ disassemble_instruction(Instruction instruction) {
715 case OP_BITRSHIFTI: 1657 case OP_BITRSHIFTI:
716 case OP_BITANDI: 1658 case OP_BITANDI:
717 case OP_BITORI: 1659 case OP_BITORI:
1660 case OP_BITXORI:
718 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,
719 instruction.a, instruction.b); 1662 instruction.a, instruction.b);
720 break; 1663 break;
@@ -748,18 +1691,28 @@ disassemble_instruction(Instruction instruction) {
748 case OP_BITRSHIFT: 1691 case OP_BITRSHIFT:
749 case OP_BITAND: 1692 case OP_BITAND:
750 case OP_BITOR: 1693 case OP_BITOR:
1694 case OP_BITXOR:
751 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,
752 instruction.a, instruction.b); 1696 instruction.a, instruction.b);
753 break; 1697 break;
754 case OP_LDGVAR: 1698 case OP_LDGVAR:
1699 case OP_LDGADDR:
1700 case OP_LDLVAR:
1701 case OP_LDLADDR:
755 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,
756 instruction.a, instruction.b); 1703 instruction.a, instruction.b);
757 break; 1704 break;
1705 case OP_LDSTR:
1706 println("%s r%d, s%d", op_str[instruction.op], instruction.dst,
1707 instruction.a, instruction.b);
1708 break;
758 case OP_STGVAR: 1709 case OP_STGVAR:
1710 case OP_STLVAR:
759 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,
760 instruction.a, instruction.b); 1712 instruction.a, instruction.b);
761 break; 1713 break;
762 case OP_STGVARI: 1714 case OP_STGVARI:
1715 case OP_STLVARI:
763 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,
764 instruction.a, instruction.b); 1717 instruction.a, instruction.b);
765 break; 1718 break;
@@ -773,19 +1726,37 @@ disassemble_instruction(Instruction instruction) {
773 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,
774 instruction.a, instruction.b); 1727 instruction.a, instruction.b);
775 break; 1728 break;
776 case OP_JMPI:
777 println("%s c%d", op_str[instruction.op], instruction.dst,
778 instruction.a, instruction.b);
779 break;
780 case OP_JMP: 1729 case OP_JMP:
781 println("%s r%d", op_str[instruction.op], instruction.dst, 1730 println("%s l%d", op_str[instruction.op], instruction.dst,
782 instruction.a, instruction.b); 1731 instruction.a, instruction.b);
783 break; 1732 break;
784 case OP_JMPFI: 1733 case OP_JMPFI:
785 case OP_JMPTI: 1734 case OP_JMPTI:
786 println("%s c%d, c%d", op_str[instruction.op], instruction.dst, 1735 println("%s l%d, c%d", op_str[instruction.op], instruction.dst,
787 instruction.a, instruction.b); 1736 instruction.a, instruction.b);
788 break; 1737 break;
1738 case OP_PRINTS64:
1739 case OP_PRINTF64:
1740 case OP_PRINTSTR:
1741 case OP_PRINTBOOL:
1742 case OP_PUSH:
1743 case OP_POP:
1744 case OP_PUTRET:
1745 println("%s r%d", op_str[instruction.op], instruction.dst,
1746 instruction.a, instruction.b);
1747 break;
1748 case OP_PRINTSTRI:
1749 case OP_PRINTS64I:
1750 case OP_PRINTF64I:
1751 case OP_PRINTBOOLI:
1752 case OP_RESERVE:
1753 case OP_PUSHI:
1754 case OP_PUTRETI:
1755 println("%s c%d", op_str[instruction.op], instruction.dst,
1756 instruction.a, instruction.b);
1757 break;
1758 case OP_RET:
1759 case OP_RECUR:
789 case OP_HALT: println("%s", op_str[instruction.op]); break; 1760 case OP_HALT: println("%s", op_str[instruction.op]); break;
790 default: println("Unknown opcode %d", instruction.op); break; 1761 default: println("Unknown opcode %d", instruction.op); break;
791 } 1762 }
@@ -793,36 +1764,120 @@ disassemble_instruction(Instruction instruction) {
793 1764
794void 1765void
795disassemble_chunk(Chunk chunk) { 1766disassemble_chunk(Chunk chunk) {
796 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("------------------------------------------");
797 for (sz i = 0; i < array_size(chunk.code); i++) { 1774 for (sz i = 0; i < array_size(chunk.code); i++) {
798 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 }
799 disassemble_instruction(chunk.code[i]); 1797 disassemble_instruction(chunk.code[i]);
800 } 1798 }
801 if (array_size(chunk.constants) > 0) { 1799 if (array_size(chunk.constants) > 0) {
802 println("%s: ============ constants ===========", chunk.file_name); 1800 println("================ constants ===============", chunk.file_name);
803 for (sz i = 0; i < array_size(chunk.constants); i++) { 1801 for (sz i = 0; i < array_size(chunk.constants); i++) {
804 println("%s: %x{2}: %x{8}", chunk.file_name, i, 1802 println(" %x{2}: %x{8}", i, chunk.constants[i]);
805 chunk.constants[i]);
806 } 1803 }
807 } 1804 }
808 if (array_size(chunk.strings) > 0) { 1805 if (array_size(chunk.strings) > 0) {
809 println("%s: ============= strings ============", chunk.file_name); 1806 println("================= strings ================", chunk.file_name);
810 for (sz i = 0; i < array_size(chunk.strings); i++) { 1807 for (sz i = 0; i < array_size(chunk.strings); i++) {
811 println("%s: %x{2}: %s", chunk.file_name, i, chunk.strings[i]); 1808 println(" %x{2}: %s", i, chunk.strings[i]);
812 } 1809 }
813 } 1810 }
814 if (array_size(chunk.vars) > 0) { 1811 if (array_size(chunk.vars) > 0) {
815 println("%s: ============ variables ===========", chunk.file_name); 1812 println("================ variables ===============", chunk.file_name);
816 for (sz i = 0; i < array_size(chunk.vars); i++) { 1813 for (sz i = 0; i < array_size(chunk.vars); i++) {
817 println("%s: %x{2}: [%x{4}:%x{4}] %s: %s", chunk.file_name, i, 1814 println(" %x{2}: [%x{4}:%x{4}] %s: %s", i, chunk.vars[i].offset,
818 chunk.vars[i].offset,
819 chunk.vars[i].offset + chunk.vars[i].size, 1815 chunk.vars[i].offset + chunk.vars[i].size,
820 chunk.vars[i].name, chunk.vars[i].type); 1816 chunk.vars[i].name, chunk.vars[i].type);
821 } 1817 }
822 } 1818 }
823 println("n_regs: %d, n_vars: %d, n_strings: %d, n_consts: %d", 1819 if (array_size(chunk.functions) > 0) {
824 chunk.reg_idx, array_size(chunk.vars), chunk.str_idx, 1820 println("================ functions ===============", chunk.file_name);
825 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);
826} 1881}
827 1882
828#endif // COMPILER_C 1883#endif // COMPILER_C