aboutsummaryrefslogtreecommitdiffstats
path: root/src/compiler.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler.c')
-rw-r--r--src/compiler.c1969
1 files changed, 1724 insertions, 245 deletions
diff --git a/src/compiler.c b/src/compiler.c
index 0f9607e..65429b0 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -5,27 +5,64 @@
5 5
6#include "parser.c" 6#include "parser.c"
7 7
8typedef struct Type {
9 Str name;
10 Str unique_name;
11 // Size of the type in bytes or 0 if it's target dependant.
12 sz size;
13} Type;
14
8typedef struct Variable { 15typedef struct Variable {
9 Str name; 16 Str name;
10 Str type; 17 Str type_name;
11 sz size; 18 sz size;
12 sz offset; 19 sz offset;
13 sz idx; 20 sz idx;
21 Type type;
14} Variable; 22} Variable;
15 23
24#define WORD_SIZE 8
25
26Type builtin_types[] = {
27 // Nil.
28 {cstr("nil"), cstr("nil"), 0},
29
30 // Architecture dependant.
31 {cstr("Int"), cstr("Int"), 8},
32 {cstr("UInt"), cstr("UInt"), 8},
33 {cstr("Ptr"), cstr("Ptr"), 8},
34 {cstr("Str"), cstr("Str"), 16},
35
36 // Fixed integer types.
37 {cstr("Bool"), cstr("Bool"), 1},
38 {cstr("U8"), cstr("U8"), 1},
39 {cstr("S8"), cstr("S8"), 1},
40 {cstr("U16"), cstr("U16"), 2},
41 {cstr("S16"), cstr("S16"), 2},
42 {cstr("U32"), cstr("U32"), 4},
43 {cstr("S32"), cstr("S32"), 4},
44 {cstr("U64"), cstr("U64"), 8},
45 {cstr("S64"), cstr("S64"), 8},
46
47 // Fixed float types.
48 {cstr("F32"), cstr("F32"), 4},
49 {cstr("F64"), cstr("F64"), 8},
50};
51
16MAPDEF(StrVarMap, varmap, Str, Variable, str_hash, str_eq) 52MAPDEF(StrVarMap, varmap, Str, Variable, str_hash, str_eq)
53MAPDEF(StrTypeMap, strtype, Str, Type, str_hash, str_eq)
17 54
18typedef struct Instruction { 55typedef struct Instruction {
19 u8 dst; 56 u16 dst;
20 u8 a; 57 u16 a;
21 u8 b; 58 u16 b;
22 u8 op; 59 u16 op;
23} Instruction; 60} Instruction;
24 61
25typedef union Constant { 62typedef union Constant {
26 s64 i; 63 s64 i;
27 u64 u; 64 u64 u;
28 double f; 65 f64 f;
29 ptrsize ptr; 66 ptrsize ptr;
30} Constant; 67} Constant;
31 68
@@ -34,9 +71,23 @@ typedef struct LineCol {
34 sz col; 71 sz col;
35} LineCol; 72} LineCol;
36 73
74typedef struct Function {
75 Str name;
76 sz param_arity;
77 sz return_arity;
78 sz index;
79} Function;
80
81MAPDEF(FunctionMap, funcmap, Str, Function, str_hash, str_eq)
82
37typedef struct Chunk { 83typedef struct Chunk {
38 sz id; 84 sz id;
85 Str name;
86 struct Chunk *parent;
87
39 Instruction *code; 88 Instruction *code;
89 IntIntMap *labels; // label -> chunk_index
90 sz labels_idx;
40 91
41 // Constant values that fit in 64 bits. 92 // Constant values that fit in 64 bits.
42 Constant *constants; 93 Constant *constants;
@@ -52,45 +103,116 @@ typedef struct Chunk {
52 Variable *vars; 103 Variable *vars;
53 StrVarMap *varmap; 104 StrVarMap *varmap;
54 sz var_off; 105 sz var_off;
106 sz param_off;
55 107
56 // Number of registers currently used in this chunk. 108 // Number of registers currently used in this chunk.
57 sz reg_idx; 109 sz reg_idx;
58 110
111 // Number of functions currently used in this chunk.
112 struct Chunk **functions;
113 FunctionMap *funmap;
114 sz fun_idx;
115
59 // Debugging. 116 // Debugging.
60 Str file_name; 117 Str file_name;
61 Arena *storage; 118 Arena *storage;
62 LineCol *linecol; 119 LineCol *linecol;
63} Chunk; 120} Chunk;
64 121
122typedef struct Compiler {
123 Chunk main_chunk;
124 Str file_name;
125 Arena *storage;
126
127 // Tables.
128 StrSet *integer_types;
129 StrSet *signed_ints;
130 StrSet *unsigned_ints;
131 StrSet *float_types;
132 StrSet *numeric_types;
133 StrTypeMap *type_map;
134
135 // Destinations.
136 sz lab_pre;
137 sz lab_post;
138} Compiler;
139
65typedef enum OpCode { 140typedef enum OpCode {
66 // OP DST A B 141 // OP DST A B
67 // --------------------------------------------------------------- 142 // ---------------------------------------------------------------
68 // VM/high level instructions. 143 // VM/high level instructions.
69 OP_HALT, // halt 144 OP_HALT, // halt
145 // NOTE: LDGVAR/STGVAR* could be obtained in terms of LDGADDR.
70 OP_STGVARI, // stgvari vx, ca 146 OP_STGVARI, // stgvari vx, ca
71 OP_STGVAR, // stgvar vx, ra 147 OP_STGVAR, // stgvar vx, ra
72 OP_LDGVAR, // ldgvar rx, vx 148 OP_LDGVAR, // ldgvar rx, va
149 OP_LDGADDR, // ldgaddr rx, va
150 OP_STLVARI, // stlvari vx, ca
151 OP_STLVAR, // stlvar vx, ra
152 OP_LDLVAR, // ldlvar rx, va
153 OP_LDLADDR, // ldladdr rx, va
154 OP_LDSTR, // ldstr rx, sa ; Stores the address of the string sa into rx
155 // Functions.
156 OP_CALL, // call fx ; Call the function fx
157 OP_RECUR, // recur ; Jump to the beginning of the function.
158 OP_RET, // ret ; Returns from current function
159 OP_RESERVE, // reserve cx ; Increments the stack pointer by cx bytes
160 OP_POP, // pop rx ; Pops the last value of the stack into rx.
161 OP_PUSH, // push rx ; Push the rx value to the stack.
162 OP_PUSHI, // pushi cx ; Push the cx value to the stack.
163 OP_PUTRET, // putret rx ; Put rx into the return value memory.
164 OP_PUTRETI, // putreti cx ; Put cx into the return value memory.
165 // Printing values with builtin print/println functions.
166 OP_PRINTSTR, // p rx
167 OP_PRINTSTRI, // p cx
168 OP_PRINTS8, // p rx
169 OP_PRINTS8I, // p cx
170 OP_PRINTS16, // p rx
171 OP_PRINTS16I, // p cx
172 OP_PRINTS32, // p rx
173 OP_PRINTS32I, // p cx
174 OP_PRINTS64, // p rx
175 OP_PRINTS64I, // p cx
176 OP_PRINTU8, // p rx
177 OP_PRINTU8I, // p cx
178 OP_PRINTU16, // p rx
179 OP_PRINTU16I, // p cx
180 OP_PRINTU32, // p rx
181 OP_PRINTU32I, // p cx
182 OP_PRINTU64, // p rx
183 OP_PRINTU64I, // p cx
184 OP_PRINTF64, // p rx
185 OP_PRINTF64I, // p cx
186 OP_PRINTF32, // p cx
187 OP_PRINTF32I, // p cx
188 OP_PRINTBOOL, // p rx
189 OP_PRINTBOOLI, // p cx
73 // Load/Store instructions. 190 // Load/Store instructions.
74 OP_LD8K, // ld8k rx, ca -> u8 rx = ca 191 OP_LDCONST, // ldconst rx, ca -> u64 rx = ca
75 OP_LD16K, // ld16k rx, ca -> u16 rx = ca 192 OP_LD8K, // ld8k rx, ra -> u8 *p = ra; rx = *p
76 OP_LD32K, // ld32k rx, ca -> u32 rx = ca 193 OP_LD16K, // ld16k rx, ra -> u16 *p = ra; rx = *p
77 OP_LD64K, // ld64k rx, ca -> u64 rx = ca 194 OP_LD32K, // ld32k rx, ra -> u32 *p = ra; rx = *p
78 OP_LD8I, // ld8i rx, ra, cb -> u8 *p; rx = p[ra + cb] 195 OP_LD64K, // ld64k rx, ra -> u64 *p = ra; rx = *p
79 OP_LD16I, // ld16i rx, ra, cb -> u16 *p; rx = p[ra + cb] 196 OP_ST8K, // ld8k rx, ra -> u8 *p = ra; *p = rx
80 OP_LD32I, // ld32i rx, ra, cb -> u32 *p; rx = p[ra + cb] 197 OP_ST16K, // ld16k rx, ra -> u16 *p = ra; *p = rx
81 OP_LD64I, // ld64i rx, ra, cb -> u64 *p; rx = p[ra + cb] 198 OP_ST32K, // ld32k rx, ra -> u32 *p = ra; *p = rx
82 OP_LD8, // ld8 rx, ra, rb -> u8 *p; rx = p[ra + rb] 199 OP_ST64K, // ld64k rx, ra -> u64 *p = ra; *p = rx
83 OP_LD16, // ld16 rx, ra, rb -> u16 *p; rx = p[ra + rb] 200 OP_LD8I, // ld8i rx, ra, cb -> u8 *p = ra; rx = p[cb]
84 OP_LD32, // ld32 rx, ra, rb -> u32 *p; rx = p[ra + rb] 201 OP_LD16I, // ld16i rx, ra, cb -> u16 *p = ra; rx = p[cb]
85 OP_LD64, // ld64 rx, ra, rb -> u64 *p; rx = p[ra + rb] 202 OP_LD32I, // ld32i rx, ra, cb -> u32 *p = ra; rx = p[cb]
86 OP_ST8I, // st8i rx, ra, cb -> u8 *p; p[ra + cb] = rx 203 OP_LD64I, // ld64i rx, ra, cb -> u64 *p = ra; rx = p[cb]
87 OP_ST16I, // st16i rx, ra, cb -> u16 *p; p[ra + cb] = rx 204 OP_LD8, // ld8 rx, ra, rb -> u8 *p = ra; rx = p[rb]
88 OP_ST32I, // st32i rx, ra, cb -> u32 *p; p[ra + cb] = rx 205 OP_LD16, // ld16 rx, ra, rb -> u16 *p = ra; rx = p[rb]
89 OP_ST64I, // st64i rx, ra, cb -> u64 *p; p[ra + cb] = rx 206 OP_LD32, // ld32 rx, ra, rb -> u32 *p = ra; rx = p[rb]
90 OP_ST8, // st8 rx, ra, rb -> u8 *p; p[ra + rb] = rx 207 OP_LD64, // ld64 rx, ra, rb -> u64 *p = ra; rx = p[rb]
91 OP_ST16, // st16 rx, ra, rb -> u16 *p; p[ra + rb] = rx 208 OP_ST8I, // st8i rx, ra, cb -> u8 *p = ra; p[cb] = rx
92 OP_ST32, // st32 rx, ra, rb -> u32 *p; p[ra + rb] = rx 209 OP_ST16I, // st16i rx, ra, cb -> u16 *p = ra; p[cb] = rx
93 OP_ST64, // st64 rx, ra, rb -> u64 *p; p[ra + rb] = rx 210 OP_ST32I, // st32i rx, ra, cb -> u32 *p = ra; p[cb] = rx
211 OP_ST64I, // st64i rx, ra, cb -> u64 *p = ra; p[cb] = rx
212 OP_ST8, // st8 rx, ra, rb -> u8 *p = ra; p[rb] = rx
213 OP_ST16, // st16 rx, ra, rb -> u16 *p = ra; p[rb] = rx
214 OP_ST32, // st32 rx, ra, rb -> u32 *p = ra; p[rb] = rx
215 OP_ST64, // st64 rx, ra, rb -> u64 *p = ra; p[rb] = rx
94 // Integer arithmetic (only int/s64 for now). 216 // Integer arithmetic (only int/s64 for now).
95 OP_ADDI, // addk rx, ra, cb 217 OP_ADDI, // addk rx, ra, cb
96 OP_SUBI, // subk rx, ra, cb 218 OP_SUBI, // subk rx, ra, cb
@@ -142,31 +264,79 @@ typedef enum OpCode {
142 OP_BITRSHIFTI, // shri rx, ra, cb 264 OP_BITRSHIFTI, // shri rx, ra, cb
143 OP_BITANDI, // bandi rx, ra, cb 265 OP_BITANDI, // bandi rx, ra, cb
144 OP_BITORI, // bori rx, ra, cb 266 OP_BITORI, // bori rx, ra, cb
267 OP_BITXORI, // bxor rx, ra, cb
145 OP_BITNOTI, // bnoti rx, ca 268 OP_BITNOTI, // bnoti rx, ca
146 OP_BITLSHIFT, // shl rx, ra, rb 269 OP_BITLSHIFT, // shl rx, ra, rb
147 OP_BITRSHIFT, // shr rx, ra, rb 270 OP_BITRSHIFT, // shr rx, ra, rb
148 OP_BITAND, // band rx, ra, rb 271 OP_BITAND, // band rx, ra, rb
149 OP_BITOR, // bor rx, ra, rb 272 OP_BITOR, // bor rx, ra, rb
273 OP_BITXOR, // bxor rx, ra, rb
150 OP_BITNOT, // bnot rx, ra 274 OP_BITNOT, // bnot rx, ra
151 // Jump instructions. 275 // Jump instructions.
152 OP_JMPI, // jmp cx ; cx := signed offset 276 OP_JMP, // jmp lx ; jmp to label lx
153 OP_JMPFI, // jmpf cx, ca ; rx := condition, ca := offset 277 OP_JMPF, // jmpf lx, rx ; jmp to label lx if rx is false
154 OP_JMPTI, // jmpt cx, ca ; rx := condition, ca := offset 278 OP_JMPT, // jmpt lx, rx ; jmp to label lx if rx is true
155 OP_JMP, // jmp rx ; rx := signed offset 279 OP_JMPFI, // jmpf lx, cx ; jmp to label lx if rx is false
156 OP_JMPF, // jmpf rx, ca ; rx := condition, ca := offset 280 OP_JMPTI, // jmpt lx, cx ; jmp to label lx if rx is true
157 OP_JMPT, // jmpt rx, ca ; rx := condition, ca := offset 281 _OP_NUM,
158} OpCode; 282} OpCode;
159 283
160Str op_str[] = { 284Str op_str[] = {
285 // High level ops.
161 [OP_HALT] = cstr("HALT "), 286 [OP_HALT] = cstr("HALT "),
162 [OP_STGVAR] = cstr("STGVAR "), 287 [OP_STGVAR] = cstr("STGVAR "),
163 [OP_STGVARI] = cstr("STGVARI "), 288 [OP_STGVARI] = cstr("STGVARI "),
164 [OP_LDGVAR] = cstr("LDGVAR "), 289 [OP_LDGVAR] = cstr("LDGVAR "),
290 [OP_LDGADDR] = cstr("LDGADDR "),
291 [OP_STLVAR] = cstr("STLVAR "),
292 [OP_STLVARI] = cstr("STLVARI "),
293 [OP_LDLVAR] = cstr("LDLVAR "),
294 [OP_LDLADDR] = cstr("LDLADDR "),
295 [OP_LDSTR] = cstr("LDSTR "),
296 [OP_PRINTSTR] = cstr("PRNSTR "),
297 [OP_PRINTSTRI] = cstr("PRNSTRI "),
298 [OP_PRINTS8] = cstr("PRNS8 "),
299 [OP_PRINTS8I] = cstr("PRNS8I "),
300 [OP_PRINTS16] = cstr("PRNS16 "),
301 [OP_PRINTS16I] = cstr("PRNS16I "),
302 [OP_PRINTS32] = cstr("PRNS32 "),
303 [OP_PRINTS32I] = cstr("PRNS32I "),
304 [OP_PRINTS64] = cstr("PRNS64 "),
305 [OP_PRINTS64I] = cstr("PRNS64I "),
306 [OP_PRINTU8] = cstr("PRNU8 "),
307 [OP_PRINTU8I] = cstr("PRNU8I "),
308 [OP_PRINTU16] = cstr("PRNU16 "),
309 [OP_PRINTU16I] = cstr("PRNU16I "),
310 [OP_PRINTU32] = cstr("PRNU32 "),
311 [OP_PRINTU32I] = cstr("PRNU32I "),
312 [OP_PRINTU64] = cstr("PRNU64 "),
313 [OP_PRINTU64I] = cstr("PRNU64I "),
314 [OP_PRINTF32] = cstr("PRNF32 "),
315 [OP_PRINTF32I] = cstr("PRNF32I "),
316 [OP_PRINTF64] = cstr("PRNF64 "),
317 [OP_PRINTF64I] = cstr("PRNF64I "),
318 [OP_PRINTBOOL] = cstr("PRNBOOL "),
319 [OP_PRINTBOOLI] = cstr("PRNBOOLI"),
320 [OP_PUTRET] = cstr("PUTRET "),
321 [OP_PUTRETI] = cstr("PUTRETI "),
322 // Functions.
323 [OP_CALL] = cstr("CALL "),
324 [OP_RECUR] = cstr("RECUR "),
325 [OP_RET] = cstr("RET "),
326 [OP_RESERVE] = cstr("RESERVE "),
327 [OP_POP] = cstr("POP "),
328 [OP_PUSH] = cstr("PUSH "),
329 [OP_PUSHI] = cstr("PUSHI "),
165 // Load ops. 330 // Load ops.
331 [OP_LDCONST] = cstr("LDCONST "),
166 [OP_LD8K] = cstr("LD8K "), 332 [OP_LD8K] = cstr("LD8K "),
167 [OP_LD16K] = cstr("LD16K "), 333 [OP_LD16K] = cstr("LD16K "),
168 [OP_LD32K] = cstr("LD32K "), 334 [OP_LD32K] = cstr("LD32K "),
169 [OP_LD64K] = cstr("LD64K "), 335 [OP_LD64K] = cstr("LD64K "),
336 [OP_ST8K] = cstr("ST8K "),
337 [OP_ST16K] = cstr("ST6K "),
338 [OP_ST32K] = cstr("ST32K "),
339 [OP_ST64K] = cstr("ST64K "),
170 [OP_LD8I] = cstr("LD8I "), 340 [OP_LD8I] = cstr("LD8I "),
171 [OP_LD16I] = cstr("LD16I "), 341 [OP_LD16I] = cstr("LD16I "),
172 [OP_LD32I] = cstr("LD32I "), 342 [OP_LD32I] = cstr("LD32I "),
@@ -234,19 +404,20 @@ Str op_str[] = {
234 [OP_BITRSHIFTI] = cstr("RSHI "), 404 [OP_BITRSHIFTI] = cstr("RSHI "),
235 [OP_BITANDI] = cstr("BANDI "), 405 [OP_BITANDI] = cstr("BANDI "),
236 [OP_BITORI] = cstr("BORI "), 406 [OP_BITORI] = cstr("BORI "),
407 [OP_BITXORI] = cstr("BXORI "),
237 [OP_BITNOTI] = cstr("BNOTI "), 408 [OP_BITNOTI] = cstr("BNOTI "),
238 [OP_BITLSHIFT] = cstr("LSH "), 409 [OP_BITLSHIFT] = cstr("LSH "),
239 [OP_BITRSHIFT] = cstr("RSH "), 410 [OP_BITRSHIFT] = cstr("RSH "),
240 [OP_BITAND] = cstr("BAND "), 411 [OP_BITAND] = cstr("BAND "),
241 [OP_BITOR] = cstr("BOR "), 412 [OP_BITOR] = cstr("BOR "),
413 [OP_BITXOR] = cstr("XBOR "),
242 [OP_BITNOT] = cstr("BNOT "), 414 [OP_BITNOT] = cstr("BNOT "),
243 // Jump instructions. 415 // Jump instructions.
244 [OP_JMPI] = cstr("JMPI "),
245 [OP_JMPFI] = cstr("JMPFI "),
246 [OP_JMPTI] = cstr("JMPTI "),
247 [OP_JMP] = cstr("JMP "), 416 [OP_JMP] = cstr("JMP "),
248 [OP_JMPF] = cstr("JMPF "), 417 [OP_JMPF] = cstr("JMPF "),
249 [OP_JMPT] = cstr("JMPT "), 418 [OP_JMPT] = cstr("JMPT "),
419 [OP_JMPFI] = cstr("JMPFI "),
420 [OP_JMPTI] = cstr("JMPTI "),
250}; 421};
251 422
252typedef enum { 423typedef enum {
@@ -254,6 +425,7 @@ typedef enum {
254 COMP_CONST, 425 COMP_CONST,
255 COMP_STRING, 426 COMP_STRING,
256 COMP_REG, 427 COMP_REG,
428 COMP_RET,
257 COMP_ERR, 429 COMP_ERR,
258} CompResultType; 430} CompResultType;
259 431
@@ -262,69 +434,195 @@ typedef struct CompResult {
262 CompResultType type; 434 CompResultType type;
263} CompResult; 435} CompResult;
264 436
265CompResult compile_expr(Chunk *chunk, Node *node); 437CompResult compile_expr(Compiler *compiler, Chunk *chunk, Node *node);
266 438
267#define EMIT_OP(OP, DST, A, B, NODE, CHUNK) \ 439sz
268 do { \ 440add_constant(Chunk *chunk, sz value) {
269 Instruction inst = (Instruction){ \ 441 IntIntMap *map = intintmap_lookup(&chunk->intmap, value);
270 .op = (OP), \ 442 // Make sure we don't have duplicated constants.
271 .dst = (DST), \ 443 if (!map) {
272 .a = (A), \ 444 map = intintmap_insert(&chunk->intmap, value, chunk->const_idx++,
273 .b = (B), \ 445 chunk->storage);
274 }; \ 446 Constant c = (Constant){.i = value};
275 array_push((CHUNK)->code, inst, (CHUNK)->storage); \ 447 array_push(chunk->constants, c, chunk->storage);
276 LineCol linecol = (LineCol){.line = (NODE)->line, .col = (NODE)->col}; \ 448 }
277 array_push((CHUNK)->linecol, linecol, (CHUNK)->storage); \ 449 return map->val;
278 } while (0) 450}
451
452sz
453add_string(Chunk *chunk, Str string) {
454 // Make sure we don't have duplicated string.
455 StrIntMap *map = strintmap_lookup(&chunk->strmap, string);
456 if (!map) {
457 map = strintmap_insert(&chunk->strmap, string, chunk->str_idx++,
458 chunk->storage);
459 array_push(chunk->strings, string, chunk->storage);
460 }
461 return map->val;
462}
463
464sz
465add_variable(Compiler *compiler,
466 Chunk *chunk,
467 Str name,
468 Str type_name,
469 sz arr_size) {
470 sz idx = array_size(chunk->vars);
471 Str base_type = type_name;
472 if (str_has_prefix(base_type, cstr("@"))) {
473 base_type = str_remove_prefix(base_type, cstr("@"));
474 if (str_has_prefix(base_type, cstr("@"))) {
475 base_type = cstr("Ptr");
476 } else if (str_has_prefix(base_type, cstr("["))) {
477 base_type = cstr("Ptr");
478 }
479 } else if (str_has_prefix(base_type, cstr("["))) {
480 str_split(&base_type, cstr("]"));
481 if (str_has_prefix(base_type, cstr("@"))) {
482 base_type = cstr("Ptr");
483 } else if (str_has_prefix(base_type, cstr("["))) {
484 base_type = cstr("Ptr");
485 }
486 }
487 StrTypeMap *t = strtype_lookup(&compiler->type_map, base_type);
488 sz size = t->val.size;
489
490 // An array.
491 if (arr_size) {
492 size *= arr_size;
493 } else if (str_has_prefix(type_name, cstr("@"))) {
494 StrTypeMap *tp = strtype_lookup(&compiler->type_map, cstr("Ptr"));
495 size = tp->val.size;
496 }
497
498 sz padding = -size & (WORD_SIZE - 1);
499 size += padding;
500 Variable var = (Variable){
501 .name = name,
502 .type = t->val,
503 .type_name = type_name,
504 .size = size,
505 .offset = chunk->var_off,
506 .idx = idx,
507 };
508 varmap_insert(&chunk->varmap, name, var, chunk->storage);
509 array_push(chunk->vars, var, chunk->storage);
510 chunk->var_off += size;
511 return idx;
512}
513
514void
515emit_op(OpCode op, sz dst, sz a, sz b, Node *node, Chunk *chunk) {
516 Instruction inst = (Instruction){
517 .op = op,
518 .dst = dst,
519 .a = a,
520 .b = b,
521 };
522 array_push(chunk->code, inst, chunk->storage);
523 LineCol linecol = (LineCol){0};
524 if (node) {
525 linecol = (LineCol){.line = node->line, .col = node->col};
526 }
527 array_push(chunk->linecol, linecol, chunk->storage);
528}
529
530void
531emit_sized_op(sz size,
532 OpCode op64,
533 OpCode op32,
534 OpCode op16,
535 OpCode op8,
536 sz dst,
537 sz a,
538 sz b,
539 Node *node,
540 Chunk *chunk) {
541 if (size == 8) {
542 emit_op(op64, dst, a, b, node, chunk);
543 } else if (size == 4) {
544 emit_op(op32, dst, a, b, node, chunk);
545 } else if (size == 2) {
546 emit_op(op16, dst, a, b, node, chunk);
547 } else if (size == 1) {
548 emit_op(op8, dst, a, b, node, chunk);
549 }
550}
551
552void
553emit_fat_copy(Chunk *chunk, Node *node, sz dst_addr, sz src_addr) {
554 sz reg_dst = chunk->reg_idx++;
555
556 // Store the fat string pointer into the variable.
557 sz zero = add_constant(chunk, 0);
558 sz one = add_constant(chunk, 1);
559
560 // Get the value for the first word of the string
561 // pointer.
562 emit_op(OP_LD64I, reg_dst, src_addr, zero, node, chunk);
563 emit_op(OP_ST64I, reg_dst, dst_addr, zero, node, chunk);
564 emit_op(OP_LD64I, reg_dst, src_addr, one, node, chunk);
565 emit_op(OP_ST64I, reg_dst, dst_addr, one, node, chunk);
566}
567
568void disassemble_chunk(Chunk chunk);
569
570void
571emit_compile_err(Compiler *compiler, Chunk *chunk, Node *node) {
572 disassemble_chunk(*chunk);
573 eprintln("%s:%d:%d: error: compilation error on: %s", compiler->file_name,
574 node->line, node->col, node_str[node->kind]);
575 exit(EXIT_FAILURE);
576}
279 577
280CompResult 578CompResult
281compile_binary(Chunk *chunk, Node *node) { 579compile_binary(Compiler *compiler, Chunk *chunk, Node *node) {
282 OpCode op = OP_HALT; 580 OpCode op = OP_HALT;
283 OpCode opi = OP_HALT; 581 OpCode opi = OP_HALT;
284 OpCode ldop = OP_LD64K; 582 OpCode ldop = OP_LDCONST;
285 switch (node->kind) { 583 switch (node->kind) {
286 // Arithmetic. 584 // Arithmetic.
287 case NODE_ADD: { 585 case NODE_ADD: {
288 if (str_eq(node->type, cstr("int"))) { 586 if (strset_lookup(&compiler->integer_types, node->type)) {
289 op = OP_ADD; 587 op = OP_ADD;
290 opi = OP_ADDI; 588 opi = OP_ADDI;
291 } else if (str_eq(node->type, cstr("f64"))) { 589 } else if (strset_lookup(&compiler->float_types, node->type)) {
292 op = OP_ADDF; 590 op = OP_ADDF;
293 opi = OP_ADDFI; 591 opi = OP_ADDFI;
294 } 592 }
295 } break; 593 } break;
296 case NODE_SUB: { 594 case NODE_SUB: {
297 if (str_eq(node->type, cstr("int"))) { 595 if (strset_lookup(&compiler->integer_types, node->type)) {
298 op = OP_SUB; 596 op = OP_SUB;
299 opi = OP_SUBI; 597 opi = OP_SUBI;
300 } else if (str_eq(node->type, cstr("f64"))) { 598 } else if (strset_lookup(&compiler->float_types, node->type)) {
301 op = OP_SUBF; 599 op = OP_SUBF;
302 opi = OP_SUBFI; 600 opi = OP_SUBFI;
303 } 601 }
304 } break; 602 } break;
305 case NODE_MUL: { 603 case NODE_MUL: {
306 if (str_eq(node->type, cstr("int"))) { 604 if (strset_lookup(&compiler->integer_types, node->type)) {
307 op = OP_MUL; 605 op = OP_MUL;
308 opi = OP_MULI; 606 opi = OP_MULI;
309 } else if (str_eq(node->type, cstr("f64"))) { 607 } else if (strset_lookup(&compiler->float_types, node->type)) {
310 op = OP_MULF; 608 op = OP_MULF;
311 opi = OP_MULFI; 609 opi = OP_MULFI;
312 } 610 }
313 } break; 611 } break;
314 case NODE_DIV: { 612 case NODE_DIV: {
315 if (str_eq(node->type, cstr("int"))) { 613 if (strset_lookup(&compiler->integer_types, node->type)) {
316 op = OP_DIV; 614 op = OP_DIV;
317 opi = OP_DIVI; 615 opi = OP_DIVI;
318 } else if (str_eq(node->type, cstr("f64"))) { 616 } else if (strset_lookup(&compiler->float_types, node->type)) {
319 op = OP_DIVF; 617 op = OP_DIVF;
320 opi = OP_DIVFI; 618 opi = OP_DIVFI;
321 } 619 }
322 } break; 620 } break;
323 case NODE_MOD: { 621 case NODE_MOD: {
324 if (str_eq(node->type, cstr("int"))) { 622 if (strset_lookup(&compiler->integer_types, node->type)) {
325 op = OP_MOD; 623 op = OP_MOD;
326 opi = OP_MODI; 624 opi = OP_MODI;
327 } else if (str_eq(node->type, cstr("f64"))) { 625 } else if (strset_lookup(&compiler->float_types, node->type)) {
328 op = OP_MODF; 626 op = OP_MODF;
329 opi = OP_MODFI; 627 opi = OP_MODFI;
330 } 628 }
@@ -354,19 +652,15 @@ compile_binary(Chunk *chunk, Node *node) {
354 op = OP_GE; 652 op = OP_GE;
355 opi = OP_GEI; 653 opi = OP_GEI;
356 } break; 654 } break;
357 case NODE_AND: {
358 op = OP_AND;
359 opi = OP_ANDI;
360 } break;
361 case NODE_OR: {
362 op = OP_OR;
363 opi = OP_ORI;
364 } break;
365 // Bitwise. 655 // Bitwise.
366 case NODE_BITOR: { 656 case NODE_BITOR: {
367 op = OP_BITOR; 657 op = OP_BITOR;
368 opi = OP_BITORI; 658 opi = OP_BITORI;
369 } break; 659 } break;
660 case NODE_BITXOR: {
661 op = OP_BITXOR;
662 opi = OP_BITXORI;
663 } break;
370 case NODE_BITAND: { 664 case NODE_BITAND: {
371 op = OP_BITAND; 665 op = OP_BITAND;
372 opi = OP_BITANDI; 666 opi = OP_BITANDI;
@@ -381,19 +675,20 @@ compile_binary(Chunk *chunk, Node *node) {
381 } break; 675 } break;
382 default: break; 676 default: break;
383 } 677 }
384 CompResult comp_a = compile_expr(chunk, node->left); 678 CompResult comp_a = compile_expr(compiler, chunk, node->binary.left);
385 CompResult comp_b = compile_expr(chunk, node->right); 679 CompResult comp_b = compile_expr(compiler, chunk, node->binary.right);
386 sz reg_a; 680 sz reg_a;
387 sz reg_b; 681 sz reg_b;
388 switch (comp_a.type) { 682 switch (comp_a.type) {
389 case COMP_CONST: { 683 case COMP_CONST: {
390 reg_a = chunk->reg_idx++; 684 reg_a = chunk->reg_idx++;
391 EMIT_OP(ldop, reg_a, comp_a.idx, 0, node, chunk); 685 emit_op(ldop, reg_a, comp_a.idx, 0, node, chunk);
392 } break; 686 } break;
393 case COMP_REG: { 687 case COMP_REG: {
394 reg_a = comp_a.idx; 688 reg_a = comp_a.idx;
395 } break; 689 } break;
396 default: { 690 default: {
691 emit_compile_err(compiler, chunk, node);
397 return (CompResult){.type = COMP_ERR}; 692 return (CompResult){.type = COMP_ERR};
398 } break; 693 } break;
399 } 694 }
@@ -406,16 +701,99 @@ compile_binary(Chunk *chunk, Node *node) {
406 reg_b = comp_b.idx; 701 reg_b = comp_b.idx;
407 } break; 702 } break;
408 default: { 703 default: {
704 emit_compile_err(compiler, chunk, node);
409 return (CompResult){.type = COMP_ERR}; 705 return (CompResult){.type = COMP_ERR};
410 } break; 706 } break;
411 } 707 }
412 sz reg_dst = chunk->reg_idx++; // Better for optimization 708 sz reg_dst = chunk->reg_idx++; // Better for optimization
413 EMIT_OP(op, reg_dst, reg_a, reg_b, node, chunk); 709 emit_op(op, reg_dst, reg_a, reg_b, node, chunk);
414 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 710 return (CompResult){.type = COMP_REG, .idx = reg_dst};
415} 711}
416 712
417CompResult 713CompResult
418compile_unary(Chunk *chunk, Node *node) { 714compile_binary_logic(Compiler *compiler, Chunk *chunk, Node *node) {
715 // Logical functions have to shortcircuit once the answer is known.
716 OpCode op = OP_HALT;
717 OpCode opi = OP_HALT;
718 OpCode ldop = OP_LDCONST;
719 OpCode jmpop = OP_HALT;
720 OpCode jmpopi = OP_HALT;
721 bool default_value = false;
722 switch (node->kind) {
723 case NODE_AND: {
724 op = OP_AND;
725 opi = OP_ANDI;
726 jmpop = OP_JMPF;
727 jmpopi = OP_JMPFI;
728 default_value = false;
729 } break;
730 case NODE_OR: {
731 op = OP_OR;
732 opi = OP_ORI;
733 jmpop = OP_JMPT;
734 jmpopi = OP_JMPTI;
735 default_value = true;
736 } break;
737 default: break;
738 }
739
740 sz lab0 = chunk->labels_idx++;
741 sz lab1 = chunk->labels_idx++;
742
743 CompResult comp_a = compile_expr(compiler, chunk, node->binary.left);
744 sz reg_a;
745 switch (comp_a.type) {
746 case COMP_CONST: {
747 emit_op(jmpopi, lab0, comp_a.idx, 0, node->binary.left, chunk);
748 reg_a = chunk->reg_idx++;
749 emit_op(ldop, reg_a, comp_a.idx, 0, node, chunk);
750 } break;
751 case COMP_REG: {
752 emit_op(jmpop, lab0, comp_a.idx, 0, node->binary.left, chunk);
753 reg_a = comp_a.idx;
754 } break;
755 default: {
756 emit_compile_err(compiler, chunk, node);
757 return (CompResult){.type = COMP_ERR};
758 } break;
759 }
760
761 CompResult comp_b = compile_expr(compiler, chunk, node->binary.right);
762 sz reg_b;
763 switch (comp_b.type) {
764 case COMP_CONST: {
765 reg_b = comp_b.idx;
766 op = opi;
767 } break;
768 case COMP_REG: {
769 reg_b = comp_b.idx;
770 } break;
771 default: {
772 emit_compile_err(compiler, chunk, node);
773 return (CompResult){.type = COMP_ERR};
774 } break;
775 }
776 sz reg_dst = chunk->reg_idx++;
777 emit_op(op, reg_dst, reg_a, reg_b, node, chunk);
778
779 // Jump to the end of this comparison.
780 emit_op(OP_JMP, lab1, 0, 0, node, chunk);
781 sz pos0 = array_size(chunk->code);
782
783 // Load default value.
784 sz defaul_const = add_constant(chunk, default_value);
785 emit_op(ldop, reg_dst, defaul_const, 0, node, chunk);
786 sz pos1 = array_size(chunk->code);
787
788 // Register labels.
789 intintmap_insert(&chunk->labels, lab0, pos0, chunk->storage);
790 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
791
792 return (CompResult){.type = COMP_REG, .idx = reg_dst};
793}
794
795CompResult
796compile_unary(Compiler *compiler, Chunk *chunk, Node *node) {
419 OpCode op = OP_HALT; 797 OpCode op = OP_HALT;
420 OpCode opi = OP_HALT; 798 OpCode opi = OP_HALT;
421 switch (node->kind) { 799 switch (node->kind) {
@@ -429,7 +807,7 @@ compile_unary(Chunk *chunk, Node *node) {
429 } break; 807 } break;
430 default: break; 808 default: break;
431 } 809 }
432 CompResult comp_a = compile_expr(chunk, node->left); 810 CompResult comp_a = compile_expr(compiler, chunk, node->binary.left);
433 sz reg_a; 811 sz reg_a;
434 switch (comp_a.type) { 812 switch (comp_a.type) {
435 case COMP_CONST: { 813 case COMP_CONST: {
@@ -440,30 +818,18 @@ compile_unary(Chunk *chunk, Node *node) {
440 reg_a = comp_a.idx; 818 reg_a = comp_a.idx;
441 } break; 819 } break;
442 default: { 820 default: {
821 emit_compile_err(compiler, chunk, node);
443 return (CompResult){.type = COMP_ERR}; 822 return (CompResult){.type = COMP_ERR};
444 } break; 823 } break;
445 } 824 }
446 sz reg_dst = chunk->reg_idx++; 825 sz reg_dst = chunk->reg_idx++;
447 EMIT_OP(op, reg_dst, reg_a, 0, node, chunk); 826 emit_op(op, reg_dst, reg_a, 0, node, chunk);
448 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 827 return (CompResult){.type = COMP_REG, .idx = reg_dst};
449} 828}
450 829
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 830CompResult
465compile_if(Chunk *chunk, Node *node) { 831compile_if(Compiler *compiler, Chunk *chunk, Node *node) {
466 CompResult cond = compile_expr(chunk, node->cond_if); 832 CompResult cond = compile_expr(compiler, chunk, node->ifelse.cond);
467 OpCode jmpop; 833 OpCode jmpop;
468 switch (cond.type) { 834 switch (cond.type) {
469 case COMP_CONST: { 835 case COMP_CONST: {
@@ -473,101 +839,1076 @@ compile_if(Chunk *chunk, Node *node) {
473 jmpop = OP_JMPF; 839 jmpop = OP_JMPF;
474 } break; 840 } break;
475 default: { 841 default: {
842 emit_compile_err(compiler, chunk, node);
476 return (CompResult){.type = COMP_ERR}; 843 return (CompResult){.type = COMP_ERR};
477 } break; 844 } break;
478 } 845 }
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 846
486 // Jump to the `false` branch. 847 if (!str_eq(node->type, cstr("nil")) &&
487 EMIT_OP(jmpop, cond.idx, 0xff, 0, node->cond_if, chunk); 848 !str_has_prefix(node->type, cstr("ret:")) &&
849 !str_has_prefix(node->type, cstr("flow:"))) {
850 sz reg_dst = chunk->reg_idx++;
488 851
489 // Condition is true. 852 // Jump to the `false` branch.
490 CompResult then_expr = compile_expr(chunk, node->cond_expr); 853 sz lab0 = chunk->labels_idx++;
491 if (has_value) { 854 emit_op(jmpop, lab0, cond.idx, 0, node->ifelse.cond, chunk);
855
856 // Condition is true.
857 CompResult then_expr =
858 compile_expr(compiler, chunk, node->ifelse.expr_true);
492 switch (then_expr.type) { 859 switch (then_expr.type) {
493 case COMP_CONST: { 860 case COMP_CONST: {
494 EMIT_OP(OP_LD64K, reg_dst, then_expr.idx, 0, node->cond_if, 861 emit_op(OP_LDCONST, reg_dst, then_expr.idx, 0,
495 chunk); 862 node->ifelse.cond, chunk);
496 } break; 863 } break;
497 case COMP_REG: { 864 case COMP_REG: {
498 EMIT_OP(OP_MOV64, reg_dst, then_expr.idx, 0, node->cond_if, 865 emit_op(OP_MOV64, reg_dst, then_expr.idx, 0, node->ifelse.cond,
499 chunk); 866 chunk);
500 } break; 867 } break;
868 case COMP_RET: break;
501 default: { 869 default: {
870 emit_compile_err(compiler, chunk, node);
502 return (CompResult){.type = COMP_ERR}; 871 return (CompResult){.type = COMP_ERR};
503 } break; 872 } break;
504 } 873 }
505 }
506 874
507 if (node->cond_else) {
508 // Jump to the end of the expression. 875 // Jump to the end of the expression.
509 sz jump_b = array_size(chunk->code); 876 sz pos0 = array_size(chunk->code);
510 EMIT_OP(OP_JMPI, 0xff, 0, 0, node->cond_else, chunk); 877 sz lab1 = chunk->labels_idx++;
878 emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk);
511 879
512 // Else expression. 880 // Else expression.
513 CompResult else_expr = compile_expr(chunk, node->cond_else); 881 CompResult else_expr =
514 if (has_value) { 882 compile_expr(compiler, chunk, node->ifelse.expr_else);
515 switch (else_expr.type) { 883 switch (else_expr.type) {
884 case COMP_CONST: {
885 emit_op(OP_LDCONST, reg_dst, else_expr.idx, 0,
886 node->ifelse.expr_else, chunk);
887 } break;
888 case COMP_REG: {
889 emit_op(OP_MOV64, reg_dst, else_expr.idx, 0,
890 node->ifelse.expr_else, chunk);
891 } break;
892 case COMP_RET: break;
893 default: {
894 emit_compile_err(compiler, chunk, node);
895 return (CompResult){.type = COMP_ERR};
896 } break;
897 }
898 sz pos1 = array_size(chunk->code);
899
900 // Update labels.
901 intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage);
902 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
903 return (CompResult){.type = COMP_REG, .idx = reg_dst};
904 }
905
906 // Jump to the `false` branch.
907 sz lab0 = chunk->labels_idx++;
908 emit_op(jmpop, lab0, cond.idx, 0, node->ifelse.cond, chunk);
909
910 // Condition is true.
911 compile_expr(compiler, chunk, node->ifelse.expr_true);
912
913 // Jump to the end of the expression.
914 sz pos0 = array_size(chunk->code);
915 sz lab1 = chunk->labels_idx++;
916 emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk);
917
918 // Else expression.
919 if (node->ifelse.expr_else) {
920 compile_expr(compiler, chunk, node->ifelse.expr_else);
921 }
922 sz pos1 = array_size(chunk->code);
923
924 // Update labels.
925 intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage);
926 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
927
928 return (CompResult){.type = COMP_NIL};
929}
930
931CompResult
932compile_cond(Compiler *compiler, Chunk *chunk, Node *node) {
933 if (str_eq(node->type, cstr("nil"))) {
934 sz lab1 = chunk->labels_idx++;
935 for (sz i = 0; i < array_size(node->match.cases); i++) {
936 // condition = expression
937 Node *expr = node->match.cases[i];
938 if (expr->case_entry.cond) {
939 CompResult cond =
940 compile_expr(compiler, chunk, expr->case_entry.cond);
941 OpCode jmpop;
942 switch (cond.type) {
943 case COMP_CONST: {
944 jmpop = OP_JMPFI;
945 } break;
946 case COMP_REG: {
947 jmpop = OP_JMPF;
948 } break;
949 default: {
950 emit_compile_err(compiler, chunk, node);
951 return (CompResult){.type = COMP_ERR};
952 } break;
953 }
954 // Jump to the `next` branch.
955 sz lab0 = chunk->labels_idx++;
956 emit_op(jmpop, lab0, cond.idx, 0, expr->case_entry.expr, chunk);
957
958 // Condition is true.
959 compile_expr(compiler, chunk, expr->case_entry.expr);
960 if (i != array_size(node->match.cases) - 1) {
961 // Jump to the end of the expression.
962 sz pos0 = array_size(chunk->code);
963 emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk);
964 intintmap_insert(&chunk->labels, lab0, pos0 + 1,
965 chunk->storage);
966 }
967 } else {
968 compile_expr(compiler, chunk, expr->case_entry.expr);
969 break;
970 }
971 }
972 sz pos1 = array_size(chunk->code);
973 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
974 return (CompResult){.type = COMP_NIL};
975 }
976
977 sz reg_dst = chunk->reg_idx++;
978 sz lab1 = chunk->labels_idx++;
979 for (sz i = 0; i < array_size(node->match.cases); i++) {
980 // condition = expression
981 Node *expr = node->match.cases[i];
982 if (expr->case_entry.cond) {
983 CompResult cond =
984 compile_expr(compiler, chunk, expr->case_entry.cond);
985 OpCode jmpop;
986 switch (cond.type) {
516 case COMP_CONST: { 987 case COMP_CONST: {
517 EMIT_OP(OP_LD64K, reg_dst, else_expr.idx, 0, 988 jmpop = OP_JMPFI;
518 node->cond_else, chunk);
519 } break; 989 } break;
520 case COMP_REG: { 990 case COMP_REG: {
521 EMIT_OP(OP_MOV64, reg_dst, else_expr.idx, 0, 991 jmpop = OP_JMPF;
522 node->cond_else, chunk);
523 } break; 992 } break;
524 default: { 993 default: {
994 emit_compile_err(compiler, chunk, node);
525 return (CompResult){.type = COMP_ERR}; 995 return (CompResult){.type = COMP_ERR};
526 } break; 996 } break;
527 } 997 }
528 } 998 // Jump to the `next` branch.
529 sz end_expr = array_size(chunk->code); 999 sz lab0 = chunk->labels_idx++;
1000 emit_op(jmpop, lab0, cond.idx, 0, expr->case_entry.expr, chunk);
530 1001
531 // Backpatch jumps. 1002 // Condition is true.
532 sz const_a = add_constant(chunk, jump_b + 1 - jump_a); 1003 CompResult then_expr =
533 sz const_b = add_constant(chunk, end_expr - jump_b); 1004 compile_expr(compiler, chunk, expr->case_entry.expr);
534 chunk->code[jump_a].a = const_a; 1005 switch (then_expr.type) {
535 chunk->code[jump_b].dst = const_b; 1006 case COMP_CONST: {
536 } else { 1007 emit_op(OP_LDCONST, reg_dst, then_expr.idx, 0,
537 sz end_expr = array_size(chunk->code); 1008 expr->case_entry.expr, chunk);
538 if (has_value) { 1009 } break;
539 sz const_a = add_constant(chunk, end_expr + 1 - jump_a); 1010 case COMP_REG: {
540 chunk->code[jump_a].a = const_a; 1011 emit_op(OP_MOV64, reg_dst, then_expr.idx, 0,
541 sz zero = add_constant(chunk, 0); 1012 expr->case_entry.expr, chunk);
542 sz end = add_constant(chunk, 2); 1013 } break;
543 EMIT_OP(OP_JMPI, end, 0, 0, node, chunk); 1014 case COMP_RET: break;
544 EMIT_OP(OP_LD64K, reg_dst, zero, 0, node, chunk); 1015 default: {
1016 emit_compile_err(compiler, chunk, node);
1017 return (CompResult){.type = COMP_ERR};
1018 } break;
1019 }
1020 if (i != array_size(node->match.cases) - 1) {
1021 // Jump to the end of the expression.
1022 sz pos0 = array_size(chunk->code);
1023 emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk);
1024 intintmap_insert(&chunk->labels, lab0, pos0 + 1,
1025 chunk->storage);
1026 }
545 } else { 1027 } else {
546 sz const_a = add_constant(chunk, end_expr - jump_a); 1028 CompResult then_expr =
547 chunk->code[jump_a].a = const_a; 1029 compile_expr(compiler, chunk, expr->case_entry.expr);
1030 switch (then_expr.type) {
1031 case COMP_CONST: {
1032 emit_op(OP_LDCONST, reg_dst, then_expr.idx, 0,
1033 expr->case_entry.expr, chunk);
1034 } break;
1035 case COMP_REG: {
1036 emit_op(OP_MOV64, reg_dst, then_expr.idx, 0,
1037 expr->case_entry.expr, chunk);
1038 } break;
1039 case COMP_RET: break;
1040 default: {
1041 emit_compile_err(compiler, chunk, node);
1042 return (CompResult){.type = COMP_ERR};
1043 } break;
1044 }
1045 break;
548 } 1046 }
549 } 1047 }
550 // TODO: does it has an else or not? Moreover, should we enforce on the 1048 sz pos1 = array_size(chunk->code);
551 // semantic level that if the `if` expression returns a value we must add an 1049 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
552 // else? 1050 return (CompResult){.type = COMP_REG, .idx = reg_dst};
1051}
1052
1053CompResult
1054compile_break(Compiler *compiler, Chunk *chunk, Node *node) {
1055 emit_op(OP_JMP, compiler->lab_post, 0, 0, node, chunk);
1056 return (CompResult){.type = COMP_NIL};
1057}
1058
1059CompResult
1060compile_continue(Compiler *compiler, Chunk *chunk, Node *node) {
1061 emit_op(OP_JMP, compiler->lab_pre, 0, 0, node, chunk);
1062 return (CompResult){.type = COMP_NIL};
1063}
1064
1065CompResult
1066compile_while(Compiler *compiler, Chunk *chunk, Node *node) {
1067 sz lab0 = chunk->labels_idx++;
1068 sz lab1 = chunk->labels_idx++;
1069 sz pos1 = array_size(chunk->code);
1070 CompResult cond = compile_expr(compiler, chunk, node->loop.cond);
1071 OpCode jmpop;
1072 switch (cond.type) {
1073 case COMP_CONST: {
1074 jmpop = OP_JMPFI;
1075 } break;
1076 case COMP_REG: {
1077 jmpop = OP_JMPF;
1078 } break;
1079 default: {
1080 emit_compile_err(compiler, chunk, node);
1081 return (CompResult){.type = COMP_ERR};
1082 } break;
1083 }
1084
1085 // Jump to the `end of the loop` branch.
1086 emit_op(jmpop, lab0, cond.idx, 0, node->loop.cond, chunk);
1087
1088 // Condition is true.
1089 compiler->lab_pre = lab1;
1090 compiler->lab_post = lab0;
1091 compile_expr(compiler, chunk, node->loop.expr);
1092 sz pos0 = array_size(chunk->code);
1093 emit_op(OP_JMP, lab1, 0, 0, node, chunk);
1094
1095 // Update labels.
1096 intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage);
1097 intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage);
553 1098
554 // Return. 1099 // Return.
555 if (has_value) { 1100 return (CompResult){.type = COMP_NIL};
1101}
1102
1103CompResult
1104compile_tail_call(Compiler *compiler, Chunk *chunk, Node *node) {
1105 // Update the local parameters.
1106 for (sz i = 0; i < array_size(node->elements); i++) {
1107 Node *expr = node->elements[i];
1108 CompResult result = compile_expr(compiler, chunk, expr);
1109 switch (result.type) {
1110 case COMP_CONST: {
1111 emit_op(OP_STLVARI, i, result.idx, 0, node, chunk);
1112 } break;
1113 case COMP_REG: {
1114 if (str_eq(expr->type, cstr("Str"))) {
1115 sz var_addr = chunk->reg_idx++;
1116 sz str_addr = result.idx;
1117 emit_op(OP_LDLADDR, var_addr, i, 0, node, chunk);
1118 emit_fat_copy(chunk, node, var_addr, str_addr);
1119 } else {
1120 emit_op(OP_STLVAR, i, result.idx, 0, node, chunk);
1121 }
1122 } break;
1123 case COMP_STRING: {
1124 sz var_addr = chunk->reg_idx++;
1125 sz str_addr = chunk->reg_idx++;
1126 emit_op(OP_LDLADDR, var_addr, i, 0, node, chunk);
1127 emit_op(OP_LDSTR, str_addr, result.idx, 0, node, chunk);
1128 emit_fat_copy(chunk, node, var_addr, str_addr);
1129 } break;
1130 default: {
1131 emit_compile_err(compiler, chunk, node);
1132 return (CompResult){.type = COMP_ERR};
1133 } break;
1134 }
1135 }
1136
1137 emit_op(OP_RECUR, 0, 0, 0, node, chunk);
1138 return (CompResult){.type = COMP_NIL};
1139}
1140
1141CompResult
1142compile_funcall(Compiler *compiler, Chunk *chunk, Node *node) {
1143 Str name = node->value.str;
1144
1145 // Builtins.
1146 if (str_eq(name, cstr("print")) || str_eq(name, cstr("println"))) {
1147 for (sz i = 0; i < array_size(node->elements); i++) {
1148 Node *expr = node->elements[i];
1149 Str type_name = expr->type;
1150 if (str_has_prefix(type_name, cstr("@")) ||
1151 str_has_prefix(type_name, cstr("["))) {
1152 type_name = cstr("Ptr");
1153 }
1154 StrTypeMap *t = strtype_lookup(&compiler->type_map, type_name);
1155 Str type = t->val.unique_name;
1156 sz size = t->val.size;
1157 CompResult result = compile_expr(compiler, chunk, expr);
1158 if (strset_lookup(&compiler->signed_ints, type)) {
1159 switch (result.type) {
1160 case COMP_CONST: {
1161 emit_sized_op(size, OP_PRINTS64I, OP_PRINTS32I,
1162 OP_PRINTS16I, OP_PRINTS8I, result.idx, 0,
1163 0, expr, chunk);
1164 } break;
1165 case COMP_REG: {
1166 emit_sized_op(size, OP_PRINTS64, OP_PRINTS32,
1167 OP_PRINTS16, OP_PRINTS8, result.idx, 0, 0,
1168 expr, chunk);
1169 } break;
1170 default: {
1171 emit_compile_err(compiler, chunk, node);
1172 return (CompResult){.type = COMP_ERR};
1173 } break;
1174 }
1175 } else if (strset_lookup(&compiler->unsigned_ints, type)) {
1176 switch (result.type) {
1177 case COMP_CONST: {
1178 emit_sized_op(size, OP_PRINTU64I, OP_PRINTU32I,
1179 OP_PRINTU16I, OP_PRINTU8I, result.idx, 0,
1180 0, expr, chunk);
1181 } break;
1182 case COMP_REG: {
1183 emit_sized_op(size, OP_PRINTU64, OP_PRINTU32,
1184 OP_PRINTU16, OP_PRINTU8, result.idx, 0, 0,
1185 expr, chunk);
1186 } break;
1187 default: {
1188 emit_compile_err(compiler, chunk, node);
1189 return (CompResult){.type = COMP_ERR};
1190 } break;
1191 }
1192 } else if (strset_lookup(&compiler->float_types, type)) {
1193 switch (result.type) {
1194 case COMP_CONST: {
1195 if (size == 8) {
1196 emit_op(OP_PRINTF64I, result.idx, 0, 0, expr,
1197 chunk);
1198 } else {
1199 emit_op(OP_PRINTF32I, result.idx, 0, 0, expr,
1200 chunk);
1201 }
1202 } break;
1203 case COMP_REG: {
1204 if (size == 8) {
1205 emit_op(OP_PRINTF64, result.idx, 0, 0, expr, chunk);
1206 } else {
1207 emit_op(OP_PRINTF32, result.idx, 0, 0, expr, chunk);
1208 }
1209 } break;
1210 default: {
1211 emit_compile_err(compiler, chunk, node);
1212 return (CompResult){.type = COMP_ERR};
1213 } break;
1214 }
1215 } else if (str_eq(type, cstr("Str"))) {
1216 switch (result.type) {
1217 case COMP_STRING: {
1218 emit_op(OP_PRINTSTRI, result.idx, 0, 0, expr, chunk);
1219 } break;
1220 case COMP_REG: {
1221 emit_op(OP_PRINTSTR, result.idx, 0, 0, expr, chunk);
1222 } break;
1223 default: {
1224 emit_compile_err(compiler, chunk, node);
1225 return (CompResult){.type = COMP_ERR};
1226 } break;
1227 }
1228 } else if (str_eq(type, cstr("Bool"))) {
1229 switch (result.type) {
1230 case COMP_CONST: {
1231 emit_op(OP_PRINTBOOLI, result.idx, 0, 0, expr, chunk);
1232 } break;
1233 case COMP_REG: {
1234 emit_op(OP_PRINTBOOL, result.idx, 0, 0, expr, chunk);
1235 } break;
1236 default: {
1237 emit_compile_err(compiler, chunk, node);
1238 return (CompResult){.type = COMP_ERR};
1239 } break;
1240 }
1241 }
1242 }
1243 if (str_eq(name, cstr("println"))) {
1244 sz idx = add_string(chunk, cstr("\n"));
1245 emit_op(OP_PRINTSTRI, idx, 0, 0, node, chunk);
1246 }
1247 return (CompResult){.type = COMP_NIL};
1248 } else if (str_eq(name, cstr("sizeof"))) {
1249 // Find size of the given type.
1250 Node *expr = node->elements[0];
1251 Str type_name = expr->value.str;
1252 // Try to find the type on the table.
1253 StrTypeMap *t = strtype_lookup(&compiler->type_map, type_name);
1254 sz size = 0;
1255 if (t) {
1256 size = t->val.size;
1257 } else {
1258 // If that's not possible, try resolving the symbol.
1259 Str name = expr->unique_name;
1260 StrVarMap *map = NULL;
1261 Chunk *next = chunk;
1262 while (next) {
1263 map = varmap_lookup(&next->varmap, name);
1264 if (map) {
1265 break;
1266 }
1267 next = next->parent;
1268 }
1269 if (!map) {
1270 emit_compile_err(compiler, chunk, expr);
1271 return (CompResult){.type = COMP_ERR};
1272 }
1273 Variable var = map->val;
1274 size = var.size;
1275 }
1276
1277 // FIXME: type size and tables is better done on semantic analyzer,
1278 // enough bloat here already.
1279 sz reg_dst = chunk->reg_idx++;
1280 sz const_idx = add_constant(chunk, size);
1281 emit_op(OP_LDCONST, reg_dst, const_idx, 0, node, chunk);
556 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 1282 return (CompResult){.type = COMP_REG, .idx = reg_dst};
557 } 1283 }
1284
1285 FunctionMap *map =
1286 funcmap_lookup(&compiler->main_chunk.funmap, node->unique_name);
1287 if (!map) {
1288 emit_compile_err(compiler, chunk, node);
1289 return (CompResult){.type = COMP_ERR};
1290 }
1291 Function fun = map->val;
1292
1293 // Check for tail recursive opportunities.
1294 if (str_eq(fun.name, node->unique_name) &&
1295 str_eq(chunk->name, node->unique_name)) {
1296 Node *parent = node->parent;
1297 Node *current = node;
1298 bool tail_recursive = true;
1299 while (parent != NULL) {
1300 switch (parent->kind) {
1301 case NODE_BLOCK: {
1302 sz idx = array_size(parent->statements) - 1;
1303 if (parent->statements[idx] != node) {
1304 tail_recursive = false;
1305 break;
1306 }
1307 } break;
1308 case NODE_WHILE: {
1309 if (current == parent->loop.cond) {
1310 tail_recursive = false;
1311 break;
1312 }
1313 } break;
1314 case NODE_IF: {
1315 if (current == parent->ifelse.cond) {
1316 tail_recursive = false;
1317 break;
1318 }
1319 } break;
1320 case NODE_FUN: {
1321 sz idx = array_size(parent->func.body->statements) - 1;
1322 if (parent->func.body->statements[idx] != current) {
1323 tail_recursive = false;
1324 break;
1325 }
1326 break;
1327 } break;
1328 case NODE_MATCH: {
1329 if (current == parent->match.expr) {
1330 tail_recursive = false;
1331 break;
1332 }
1333 } break;
1334 case NODE_COND: break;
1335 case NODE_CASE_COND: {
1336 if (current == parent->case_entry.cond) {
1337 tail_recursive = false;
1338 break;
1339 }
1340 } break;
1341 default: {
1342 tail_recursive = false;
1343 break;
1344 } break;
1345 }
1346 parent = parent->parent;
1347 current = current->parent;
1348 }
1349 if (tail_recursive) {
1350 return compile_tail_call(compiler, chunk, node);
1351 }
1352 }
1353
1354 // Reserve space for the return value if needed.
1355 if (fun.return_arity > 0) {
1356 // Put the return data into a register
1357 sz ret_size = add_constant(chunk, 8);
1358 emit_op(OP_RESERVE, ret_size, 0, 0, node, chunk);
1359 }
1360
1361 // Send parameters to the stack.
1362 for (sz i = 0; i < array_size(node->elements); i++) {
1363 Node *expr = node->elements[i];
1364 CompResult result = compile_expr(compiler, chunk, expr);
1365 Str type_name = expr->type;
1366 if (str_has_prefix(type_name, cstr("@")) ||
1367 str_has_prefix(type_name, cstr("["))) {
1368 type_name = cstr("Ptr");
1369 }
1370 StrTypeMap *t = strtype_lookup(&compiler->type_map, type_name);
1371 sz size = t->val.size;
1372 switch (result.type) {
1373 case COMP_CONST: {
1374 emit_op(OP_PUSHI, result.idx, 0, 0, expr, chunk);
1375 } break;
1376 case COMP_REG: {
1377 if (str_eq(expr->type, cstr("Str"))) {
1378 sz str_addr = result.idx;
1379 // Store the fat string pointer into the stack.
1380 sz reg_dst = chunk->reg_idx++;
1381 sz zero = add_constant(chunk, 0);
1382 sz one = add_constant(chunk, 1);
1383 emit_sized_op(size, OP_LD64I, OP_LD32I, OP_LD16I, OP_LD8I,
1384 reg_dst, str_addr, zero, node, chunk);
1385 emit_op(OP_PUSH, reg_dst, 0, 0, expr, chunk);
1386 emit_sized_op(size, OP_LD64I, OP_LD32I, OP_LD16I, OP_LD8I,
1387 reg_dst, str_addr, one, node, chunk);
1388 emit_op(OP_PUSH, reg_dst, 0, 0, expr, chunk);
1389 } else {
1390 emit_op(OP_PUSH, result.idx, 0, 0, expr, chunk);
1391 }
1392 } break;
1393 case COMP_STRING: {
1394 // Get the address for the string value variable.
1395 sz str_addr = chunk->reg_idx++;
1396 emit_op(OP_LDSTR, str_addr, result.idx, 0, node->var.val,
1397 chunk);
1398
1399 // Store the fat string pointer into the stack.
1400 sz reg_dst = chunk->reg_idx++;
1401 sz zero = add_constant(chunk, 0);
1402 sz one = add_constant(chunk, 1);
1403 emit_op(OP_LD64I, reg_dst, str_addr, zero, node, chunk);
1404 emit_op(OP_PUSH, reg_dst, 0, 0, expr, chunk);
1405 emit_op(OP_LD64I, reg_dst, str_addr, one, node, chunk);
1406 emit_op(OP_PUSH, reg_dst, 0, 0, expr, chunk);
1407 } break;
1408 default: {
1409 emit_compile_err(compiler, chunk, node);
1410 return (CompResult){.type = COMP_ERR};
1411 } break;
1412 }
1413 }
1414
1415 emit_op(OP_CALL, fun.index, 0, 0, node, chunk);
1416
1417 // Only one return parameter for now.
1418 if (fun.return_arity > 0) {
1419 // Put the return data into a register
1420 sz reg_dst = chunk->reg_idx++;
1421 emit_op(OP_POP, reg_dst, 0, 0, node, chunk);
1422 return (CompResult){.type = COMP_REG, .idx = reg_dst};
1423 }
1424
1425 return (CompResult){.type = COMP_NIL};
1426}
1427
1428CompResult
1429compile_return(Compiler *compiler, Chunk *chunk, Node *node) {
1430 for (sz i = 0; i < array_size(node->elements); i++) {
1431 Node *expr = node->elements[i];
1432 CompResult res = compile_expr(compiler, chunk, expr);
1433
1434 // TODO: Only one return field for now, but this is the idea.
1435 // Put return values into memory.
1436 switch (res.type) {
1437 case COMP_CONST: {
1438 emit_op(OP_PUTRETI, res.idx, 0, 0, node, chunk);
1439 } break;
1440 case COMP_REG: {
1441 emit_op(OP_PUTRET, res.idx, 0, 0, node, chunk);
1442 } break;
1443 case COMP_NIL: break;
1444 default: {
1445 emit_compile_err(compiler, chunk, node);
1446 return (CompResult){.type = COMP_ERR};
1447 } break;
1448 }
1449 break;
1450 }
1451
1452 emit_op(OP_RET, 0, 0, 0, node, chunk);
1453 return (CompResult){.type = COMP_RET};
1454}
1455
1456Chunk *
1457chunk_alloc(Chunk *parent) {
1458 static sz chunk_idx = 1;
1459 Chunk *chunk = arena_calloc((sz)sizeof(Chunk), parent->storage);
1460 chunk->parent = parent;
1461 chunk->id = chunk_idx++;
1462 chunk->storage = parent->storage;
1463 chunk->file_name = parent->file_name;
1464 return chunk;
1465}
1466
1467void
1468verify_chunk(Chunk *chunk) {
1469 if (chunk->const_idx >= 256) {
1470 eprintln("too many constants on chunk %s", chunk->id);
1471 exit(EXIT_FAILURE);
1472 }
1473 if (chunk->str_idx >= 256) {
1474 eprintln("too many strings on chunk %s", chunk->id);
1475 exit(EXIT_FAILURE);
1476 }
1477 if (chunk->reg_idx >= 256) {
1478 eprintln("too many registers used on chunk %s", chunk->id);
1479 exit(EXIT_FAILURE);
1480 }
1481 if (chunk->labels_idx >= 256) {
1482 eprintln("too many labels used on chunk %s", chunk->id);
1483 exit(EXIT_FAILURE);
1484 }
1485 if (chunk->fun_idx >= 256) {
1486 eprintln("too many functions on chunk %s", chunk->id);
1487 exit(EXIT_FAILURE);
1488 }
1489}
1490
1491void
1492declare_function(Chunk *chunk, Node *node) {
1493 Str name = node->unique_name;
1494 FunctionMap *map = funcmap_lookup(&chunk->funmap, node->unique_name);
1495 if (map) {
1496 return;
1497 }
1498 Function fun = (Function){
1499 .name = name,
1500 .index = chunk->fun_idx++,
1501 .param_arity = array_size(node->func.params),
1502 .return_arity = array_size(node->func.ret),
1503 };
1504 funcmap_insert(&chunk->funmap, node->unique_name, fun, chunk->storage);
1505}
1506
1507CompResult
1508compile_function(Compiler *compiler, Chunk *chunk, Node *node) {
1509 // The current activation record procedure for the VM is as follows:
1510 //
1511 // [caller][callee ]
1512 // [ .... ][ RET VAL ][ PARAMS ][ LOCALS ][ REGISTERS ][ RET META ]
1513 // ^
1514 // frame pointer
1515 //
1516 // The caller is responsible for allocating the return memory and the
1517 // parameter memory and filling the param data before OP_CALL.
1518 //
1519 chunk = &compiler->main_chunk;
1520 Chunk *func = chunk_alloc(chunk);
1521 func->name = node->unique_name;
1522 declare_function(chunk, node);
1523 array_push(chunk->functions, func, chunk->storage);
1524
1525 // Push arguments as locals.
1526 for (sz i = 0; i < array_size(node->func.params); i++) {
1527 Node *param = node->func.params[i];
1528 Str name = param->unique_name;
1529 Str type = param->type;
1530 sz arr_size = 0;
1531 if (str_has_prefix(type, cstr("@"))) {
1532 // if (param->var.type->sym.arr_size->value.i > 0) {
1533 // arr_size = param->var.type->sym.arr_size->value.i;
1534 // }
1535 }
1536 add_variable(compiler, func, name, type, arr_size);
1537 }
1538 func->param_off = func->var_off;
1539
1540 // Compiling the body.
1541 CompResult res = compile_expr(compiler, func, node->func.body);
1542
1543 // Put return values into memory.
1544 switch (res.type) {
1545 case COMP_CONST: {
1546 emit_op(OP_PUTRETI, res.idx, 0, 0, node, func);
1547 } break;
1548 case COMP_REG: {
1549 emit_op(OP_PUTRET, res.idx, 0, 0, node, func);
1550 } break;
1551 default: break;
1552 }
1553
1554 emit_op(OP_RET, 0, 0, 0, node, func);
1555 verify_chunk(func);
1556 return (CompResult){.type = COMP_NIL};
1557}
1558
1559CompResult
1560compile_let(Compiler *compiler, Chunk *chunk, Node *node) {
1561 sz op_ldaddr = OP_LDLADDR;
1562 if (chunk == &compiler->main_chunk) {
1563 op_ldaddr = OP_LDGADDR;
1564 }
1565 Str name = node->unique_name;
1566 Str type_name = node->var.name->type;
1567 sz arr_size = 0;
1568 if (node->var.type) {
1569 Node *next = node->var.type->t.next;
1570 if (next && next->kind == NODE_ARR) {
1571 // TODO: handle dynamic arrays and slices
1572 arr_size = next->array.size->value.i;
1573 }
1574 }
1575
1576 sz idx = add_variable(compiler, chunk, name, type_name, arr_size);
1577 StrVarMap *map = varmap_lookup(&chunk->varmap, name);
1578 Variable var = map->val;
1579 Type type = map->val.type;
1580
1581 // Value.
1582 if (node->var.val) {
1583 CompResult res = compile_expr(compiler, chunk, node->var.val);
1584 switch (res.type) {
1585 case COMP_CONST: {
1586 sz reg_addr = chunk->reg_idx++;
1587 sz reg_dst = chunk->reg_idx++;
1588 emit_op(op_ldaddr, reg_addr, idx, 0, node, chunk);
1589 emit_op(OP_LDCONST, reg_dst, res.idx, 0, node, chunk);
1590 emit_sized_op(type.size, OP_ST64K, OP_ST32K, OP_ST16K, OP_ST8K,
1591 reg_dst, reg_addr, 0, node, chunk);
1592 } break;
1593 case COMP_REG: {
1594 sz reg_addr = chunk->reg_idx++;
1595 sz reg_val = res.idx;
1596 emit_op(op_ldaddr, reg_addr, idx, 0, node, chunk);
1597 if (var.size > 8 || str_has_prefix(var.type_name, cstr("["))) {
1598 sz reg_dst = chunk->reg_idx++;
1599 for (sz i = 0; i < var.size / 8; i++) {
1600 sz offset = add_constant(chunk, i);
1601 emit_op(OP_LD64I, reg_dst, reg_val, offset, node,
1602 chunk);
1603 emit_op(OP_ST64I, reg_dst, reg_addr, offset, node,
1604 chunk);
1605 }
1606 } else {
1607 emit_sized_op(var.size, OP_ST64K, OP_ST32K, OP_ST16K,
1608 OP_ST8K, reg_val, reg_addr, 0, node, chunk);
1609 }
1610 } break;
1611 case COMP_STRING: {
1612 // Get the address for the string value variable.
1613 sz str_addr = chunk->reg_idx++;
1614 emit_op(OP_LDSTR, str_addr, res.idx, 0, node->var.val, chunk);
1615
1616 // Get the address for the local/global storage
1617 // variable.
1618 sz var_addr = chunk->reg_idx++;
1619 emit_op(op_ldaddr, var_addr, idx, 0, node, chunk);
1620
1621 // Copy the fat pointer.
1622 emit_fat_copy(chunk, node, var_addr, str_addr);
1623 } break;
1624 default: {
1625 emit_compile_err(compiler, chunk, node);
1626 return (CompResult){.type = COMP_ERR};
1627 } break;
1628 }
1629 }
1630
1631 return (CompResult){.type = COMP_NIL};
1632}
1633
1634CompResult
1635compile_set(Compiler *compiler, Chunk *chunk, Node *node) {
1636 Str name = node->unique_name;
1637 StrVarMap *map = NULL;
1638 Chunk *next = chunk;
1639 while (next) {
1640 map = varmap_lookup(&next->varmap, name);
1641 if (map) {
1642 break;
1643 }
1644 next = chunk->parent;
1645 }
1646 if (!map) {
1647 emit_compile_err(compiler, chunk, node);
1648 return (CompResult){.type = COMP_ERR};
1649 }
1650 sz op_ldaddr = OP_LDLADDR;
1651 if (next == &compiler->main_chunk) {
1652 op_ldaddr = OP_LDGADDR;
1653 }
1654 Variable var = map->val;
1655 Type type = map->val.type;
1656 sz idx = map->val.idx;
1657
1658 CompResult res = compile_expr(compiler, chunk, node->var.val);
1659 if (false) {
1660 // // Value.
1661 // sz reg_val;
1662 // switch (res.type) {
1663 // case COMP_CONST: {
1664 // reg_val = chunk->reg_idx++;
1665 // emit_op(OP_LDCONST, reg_val, res.idx, 0, node, chunk);
1666 // } break;
1667 // case COMP_REG: {
1668 // reg_val = res.idx;
1669 // } break;
1670 // default: {
1671 // emit_compile_err(compiler, chunk, node);
1672 // return (CompResult){.type = COMP_ERR};
1673 // } break;
1674 // }
1675
1676 // // Address.
1677 // sz reg_addr = chunk->reg_idx++;
1678 // // Is this a pointer access or an array access?
1679 // if (str_has_prefix(map->val.type_name, cstr("[]"))) {
1680 // emit_op(op_ldaddr, reg_addr, map->val.idx, 0, node->var.val,
1681 // chunk);
1682 // } else {
1683 // emit_op(op_ldvar, reg_addr, map->val.idx, 0, node->var.val,
1684 // chunk);
1685 // }
1686
1687 // // Index.
1688 // CompResult res_idx =
1689 // compile_expr(compiler, chunk, node->var.name->sym.arr_size);
1690 // switch (res_idx.type) {
1691 // case COMP_CONST: {
1692 // emit_sized_op(type.size, OP_ST64I, OP_ST32I, OP_ST16I,
1693 // OP_ST8I,
1694 // reg_val, reg_addr, res_idx.idx, node, chunk);
1695 // } break;
1696 // case COMP_REG: {
1697 // emit_sized_op(type.size, OP_ST64, OP_ST32, OP_ST16, OP_ST8,
1698 // reg_val, reg_addr, res_idx.idx, node, chunk);
1699 // } break;
1700 // case COMP_STRING: {
1701 // // Get the address for the string value variable.
1702 // sz str_addr = chunk->reg_idx++;
1703 // emit_op(OP_LDSTR, str_addr, res.idx, 0, node->var.val,
1704 // chunk);
1705
1706 // // Get the address for the local/global storage
1707 // // variable.
1708 // sz var_addr = chunk->reg_idx++;
1709 // emit_op(op_ldaddr, var_addr, idx, 0, node, chunk);
1710
1711 // // Copy the fat pointer.
1712 // emit_fat_copy(chunk, node, var_addr, str_addr);
1713 // } break;
1714 // default: {
1715 // emit_compile_err(compiler, chunk, node);
1716 // return (CompResult){.type = COMP_ERR};
1717 // } break;
1718 // }
1719 // return (CompResult){.type = COMP_NIL};
1720 } else if (node->var.name->kind == NODE_DEREF) {
1721 // Value.
1722 sz reg_val;
1723 switch (res.type) {
1724 case COMP_CONST: {
1725 reg_val = chunk->reg_idx++;
1726 emit_op(OP_LDCONST, reg_val, res.idx, 0, node, chunk);
1727 } break;
1728 case COMP_REG: {
1729 reg_val = res.idx;
1730 } break;
1731 default: {
1732 emit_compile_err(compiler, chunk, node);
1733 return (CompResult){.type = COMP_ERR};
1734 } break;
1735 }
1736
1737 Node *next = node->var.name->deref.next;
1738 sz n_deref = 0;
1739 while (next) {
1740 n_deref++;
1741 if (next->kind == NODE_SYMBOL) {
1742 break;
1743 }
1744 next = next->deref.next;
1745 }
1746 CompResult res = compile_expr(compiler, chunk, next);
1747 sz reg_src = res.idx;
1748 sz reg_dst = reg_src;
1749 for (sz i = 0; i < n_deref - 1; i++) {
1750 reg_dst = chunk->reg_idx++;
1751 emit_op(OP_LD64K, reg_dst, reg_src, 0, node, chunk);
1752 reg_src = reg_dst;
1753 }
1754 emit_sized_op(type.size, OP_ST64K, OP_ST32K, OP_ST16K, OP_ST8K, reg_val,
1755 reg_dst, 0, node, chunk);
1756
1757 return (CompResult){.type = COMP_NIL};
1758 }
1759
1760 switch (res.type) {
1761 case COMP_CONST: {
1762 sz reg_addr = chunk->reg_idx++;
1763 sz reg_dst = chunk->reg_idx++;
1764 emit_op(op_ldaddr, reg_addr, idx, 0, node, chunk);
1765 emit_op(OP_LDCONST, reg_dst, res.idx, 0, node, chunk);
1766 emit_sized_op(type.size, OP_ST64K, OP_ST32K, OP_ST16K, OP_ST8K,
1767 reg_dst, reg_addr, 0, node, chunk);
1768 } break;
1769 case COMP_REG: {
1770 sz reg_addr = chunk->reg_idx++;
1771 sz reg_val = res.idx;
1772 emit_op(op_ldaddr, reg_addr, idx, 0, node, chunk);
1773 if (var.size > 8 || str_has_prefix(var.type_name, cstr("["))) {
1774 sz reg_dst = chunk->reg_idx++;
1775 for (sz i = 0; i < var.size / 8; i++) {
1776 sz offset = add_constant(chunk, i);
1777 emit_op(OP_LD64I, reg_dst, reg_val, offset, node, chunk);
1778 emit_op(OP_ST64I, reg_dst, reg_addr, offset, node, chunk);
1779 }
1780 } else {
1781 emit_sized_op(var.size, OP_ST64K, OP_ST32K, OP_ST16K, OP_ST8K,
1782 reg_val, reg_addr, 0, node, chunk);
1783 }
1784 } break;
1785 case COMP_STRING: {
1786 // Get the address for the string value variable.
1787 sz str_addr = chunk->reg_idx++;
1788 emit_op(OP_LDSTR, str_addr, res.idx, 0, node->var.val, chunk);
1789
1790 // Get the address for the local/global storage
1791 // variable.
1792 sz var_addr = chunk->reg_idx++;
1793 emit_op(op_ldaddr, var_addr, idx, 0, node, chunk);
1794
1795 // Copy the fat pointer.
1796 emit_fat_copy(chunk, node, var_addr, str_addr);
1797 } break;
1798 default: {
1799 emit_compile_err(compiler, chunk, node);
1800 return (CompResult){.type = COMP_ERR};
1801 } break;
1802 }
558 return (CompResult){.type = COMP_NIL}; 1803 return (CompResult){.type = COMP_NIL};
559} 1804}
560 1805
561CompResult 1806CompResult
562compile_expr(Chunk *chunk, Node *node) { 1807compile_symbol(Compiler *compiler, Chunk *chunk, Node *node) {
1808 Str name = node->unique_name;
1809 StrVarMap *map = NULL;
1810 Chunk *next = chunk;
1811 while (next) {
1812 map = varmap_lookup(&next->varmap, name);
1813 if (map) {
1814 break;
1815 }
1816 next = next->parent;
1817 }
1818 if (!map) {
1819 emit_compile_err(compiler, chunk, node);
1820 return (CompResult){.type = COMP_ERR};
1821 }
1822 sz op_ldaddr = OP_LDLADDR;
1823 if (next == &compiler->main_chunk) {
1824 op_ldaddr = OP_LDGADDR;
1825 }
1826 Variable var = map->val;
1827 sz reg_dst = chunk->reg_idx++;
1828 if (str_has_prefix(var.type_name, cstr("[")) ||
1829 str_eq(var.type_name, cstr("Str"))) {
1830 emit_op(op_ldaddr, reg_dst, var.idx, 0, node, chunk);
1831 } else {
1832 sz reg_addr = chunk->reg_idx++;
1833 emit_op(op_ldaddr, reg_addr, var.idx, 0, node, chunk);
1834 emit_sized_op(var.size, OP_LD64K, OP_LD32K, OP_LD16K, OP_LD8K, reg_dst,
1835 reg_addr, 0, node, chunk);
1836 }
1837 return (CompResult){.type = COMP_REG, .idx = reg_dst};
1838}
1839
1840// CompResult
1841// compile_symbol_idx(Compiler *compiler, Chunk *chunk, Node *node) {
1842// Str name = node->unique_name;
1843// StrVarMap *map = NULL;
1844// Chunk *next = chunk;
1845// while (next) {
1846// map = varmap_lookup(&next->varmap, name);
1847// if (map) {
1848// break;
1849// }
1850// next = next->parent;
1851// }
1852// if (!map) {
1853// eprintln("couldn't resolve symbol name: %s", name);
1854// emit_compile_err(compiler, chunk, node);
1855// return (CompResult){.type = COMP_ERR};
1856// }
1857// sz op_ldaddr = OP_LDLADDR;
1858// sz op_ldvar = OP_LDLVAR;
1859// if (next == &compiler->main_chunk) {
1860// op_ldaddr = OP_LDGADDR;
1861// op_ldvar = OP_LDGVAR;
1862// }
1863
1864// // Destination.
1865// sz reg_dst = chunk->reg_idx++;
1866
1867// // Address.
1868// sz reg_addr = chunk->reg_idx++;
1869// if (str_has_prefix(map->val.type_name, cstr("[]"))) {
1870// emit_op(op_ldaddr, reg_addr, map->val.idx, 0, node->var.val, chunk);
1871// } else {
1872// emit_op(op_ldvar, reg_addr, map->val.idx, 0, node->var.val, chunk);
1873// }
1874
1875// Type type = map->val.type;
1876
1877// // Index.
1878// CompResult idx = compile_expr(compiler, chunk, node->sym.arr_size);
1879// switch (idx.type) {
1880// case COMP_CONST: {
1881// emit_sized_op(type.size, OP_LD64I, OP_LD32I, OP_LD16I, OP_LD8I,
1882// reg_dst, reg_addr, idx.idx, node, chunk);
1883// } break;
1884// case COMP_REG: {
1885// emit_sized_op(type.size, OP_LD64, OP_LD32, OP_LD16, OP_LD8, reg_dst,
1886// reg_addr, idx.idx, node, chunk);
1887// } break;
1888// default: {
1889// emit_compile_err(compiler, chunk, node);
1890// return (CompResult){.type = COMP_ERR};
1891// } break;
1892// }
1893// return (CompResult){.type = COMP_REG, .idx = reg_dst};
1894// }
1895
1896CompResult
1897compile_expr(Compiler *compiler, Chunk *chunk, Node *node) {
563 switch (node->kind) { 1898 switch (node->kind) {
564 case NODE_IF: return compile_if(chunk, node); 1899 case NODE_BREAK: return compile_break(compiler, chunk, node);
1900 case NODE_CONTINUE: return compile_continue(compiler, chunk, node);
1901 case NODE_RETURN: return compile_return(compiler, chunk, node);
1902 case NODE_FUN: return compile_function(compiler, chunk, node);
1903 case NODE_FUNCALL: return compile_funcall(compiler, chunk, node);
1904 case NODE_WHILE: return compile_while(compiler, chunk, node);
1905 case NODE_IF: return compile_if(compiler, chunk, node);
1906 case NODE_COND: return compile_cond(compiler, chunk, node);
565 // Logic. 1907 // Logic.
566 // case NODE_XOR:
567 case NODE_BITNOT: 1908 case NODE_BITNOT:
568 case NODE_NOT: return compile_unary(chunk, node); break; 1909 case NODE_NOT: return compile_unary(compiler, chunk, node); break;
569 case NODE_AND: 1910 case NODE_AND:
570 case NODE_OR: 1911 case NODE_OR: return compile_binary_logic(compiler, chunk, node); break;
571 case NODE_EQ: 1912 case NODE_EQ:
572 case NODE_NEQ: 1913 case NODE_NEQ:
573 case NODE_LT: 1914 case NODE_LT:
@@ -576,6 +1917,7 @@ compile_expr(Chunk *chunk, Node *node) {
576 // Bitwise ops. 1917 // Bitwise ops.
577 case NODE_BITAND: 1918 case NODE_BITAND:
578 case NODE_BITOR: 1919 case NODE_BITOR:
1920 case NODE_BITXOR:
579 case NODE_BITLSHIFT: 1921 case NODE_BITLSHIFT:
580 case NODE_BITRSHIFT: 1922 case NODE_BITRSHIFT:
581 // Arithmetic. 1923 // Arithmetic.
@@ -584,7 +1926,7 @@ compile_expr(Chunk *chunk, Node *node) {
584 case NODE_SUB: 1926 case NODE_SUB:
585 case NODE_MUL: 1927 case NODE_MUL:
586 case NODE_DIV: 1928 case NODE_DIV:
587 case NODE_MOD: return compile_binary(chunk, node); break; 1929 case NODE_MOD: return compile_binary(compiler, chunk, node); break;
588 case NODE_TRUE: 1930 case NODE_TRUE:
589 case NODE_FALSE: 1931 case NODE_FALSE:
590 case NODE_NUM_FLOAT: 1932 case NODE_NUM_FLOAT:
@@ -599,105 +1941,80 @@ compile_expr(Chunk *chunk, Node *node) {
599 } break; 1941 } break;
600 case NODE_STRING: { 1942 case NODE_STRING: {
601 Str string = node->value.str; 1943 Str string = node->value.str;
602 // Make sure we don't have duplicated strings. 1944 sz str_idx = add_string(chunk, string);
603 StrIntMap *map = strintmap_lookup(&chunk->strmap, string);
604 if (!map) {
605 map = strintmap_insert(&chunk->strmap, string, chunk->str_idx++,
606 chunk->storage);
607 array_push(chunk->strings, string, chunk->storage);
608 }
609 return (CompResult){ 1945 return (CompResult){
610 .type = COMP_STRING, 1946 .type = COMP_STRING,
611 .idx = map->val, 1947 .idx = str_idx,
612 }; 1948 };
613 } break; 1949 } break;
614 case NODE_LET: { 1950 case NODE_LET: return compile_let(compiler, chunk, node);
615 sz idx = array_size(chunk->vars); 1951 case NODE_SET: return compile_set(compiler, chunk, node);
616 Str name = node->unique_name; 1952 case NODE_SYMBOL: return compile_symbol(compiler, chunk, node);
617 Str type = node->var_name->type; 1953 case NODE_PTR: {
618 sz size = 8; 1954 // Load and return address of associated symbol.
619 // TODO: get type storage from a table to consider all the basic 1955 Str name = node->t.next->unique_name;
620 // types as well as user defined ones. 1956 sz op_ldaddr = OP_LDLADDR;
621 if (str_eq(type, cstr("str"))) { 1957 if (chunk == &compiler->main_chunk) {
622 size = 16; 1958 op_ldaddr = OP_LDGADDR;
623 }
624 Variable var = (Variable){
625 .name = name,
626 .type = type,
627 .size = size,
628 .offset = chunk->var_off,
629 .idx = idx,
630 };
631 varmap_insert(&chunk->varmap, name, var, chunk->storage);
632 array_push(chunk->vars, var, chunk->storage);
633 chunk->var_off += size;
634
635 // Value.
636 if (node->var_val) {
637 CompResult res = compile_expr(chunk, node->var_val);
638 switch (res.type) {
639 case COMP_CONST: {
640 EMIT_OP(OP_STGVARI, idx, res.idx, 0, node->var_val,
641 chunk);
642 } break;
643 case COMP_REG: {
644 EMIT_OP(OP_STGVAR, idx, res.idx, 0, node->var_val,
645 chunk);
646 } break;
647 default: {
648 return (CompResult){.type = COMP_ERR};
649 } break;
650 }
651 } 1959 }
652 1960
653 return (CompResult){.type = COMP_NIL};
654 } break;
655 case NODE_SET: {
656 Str name = node->unique_name;
657 StrVarMap *map = varmap_lookup(&chunk->varmap, name); 1961 StrVarMap *map = varmap_lookup(&chunk->varmap, name);
658 if (!map) { 1962 if (!map) {
659 println("you wot mate?: %s", name); 1963 emit_compile_err(compiler, chunk, node);
660 }
661 CompResult res = compile_expr(chunk, node->var_val);
662 switch (res.type) {
663 case COMP_CONST: {
664 EMIT_OP(OP_STGVARI, map->val.idx, res.idx, 0, node->var_val,
665 chunk);
666 } break;
667 case COMP_REG: {
668 EMIT_OP(OP_STGVAR, map->val.idx, res.idx, 0, node->var_val,
669 chunk);
670 } break;
671 default: {
672 return (CompResult){.type = COMP_ERR};
673 } break;
674 } 1964 }
675 return (CompResult){.type = COMP_NIL}; 1965 Variable var = map->val;
1966
1967 sz reg_addr = chunk->reg_idx++;
1968 emit_op(op_ldaddr, reg_addr, var.idx, 0, node, chunk);
1969 return (CompResult){.type = COMP_REG, .idx = reg_addr};
676 } break; 1970 } break;
677 case NODE_SYMBOL: { 1971 case NODE_DEREF: {
678 Str name = node->unique_name; 1972 Str type_name = node->type;
679 StrVarMap *map = varmap_lookup(&chunk->varmap, name); 1973 if (str_has_prefix(type_name, cstr("@")) ||
680 if (!map) { 1974 str_has_prefix(type_name, cstr("["))) {
681 println("error: unreachable... name: %s", name); 1975 type_name = cstr("Ptr");
682 exit(EXIT_FAILURE); 1976 }
1977 StrTypeMap *t = strtype_lookup(&compiler->type_map, type_name);
1978 sz size = t->val.size;
1979
1980 Node *next = node->deref.next;
1981 sz n_deref = 0;
1982 while (next) {
1983 n_deref++;
1984 if (next->kind == NODE_SYMBOL) {
1985 break;
1986 }
1987 next = next->deref.next;
1988 }
1989 CompResult res = compile_symbol(compiler, chunk, next);
1990 sz reg_dst = res.idx;
1991 sz reg_src = res.idx;
1992 for (sz i = 0; i < n_deref; i++) {
1993 reg_dst = chunk->reg_idx++;
1994 if (i == n_deref - 1) {
1995 emit_sized_op(size, OP_LD64K, OP_LD32K, OP_LD16K, OP_LD8K,
1996 reg_dst, reg_src, 0, node, chunk);
1997 } else {
1998 emit_op(OP_LD64K, reg_dst, reg_src, 0, node, chunk);
1999 }
2000 reg_src = reg_dst;
683 } 2001 }
684 Variable var = map->val;
685 u8 reg_dst = chunk->reg_idx++;
686 EMIT_OP(OP_LDGVAR, reg_dst, var.idx, 0, node, chunk);
687 return (CompResult){.type = COMP_REG, .idx = reg_dst}; 2002 return (CompResult){.type = COMP_REG, .idx = reg_dst};
688 } break; 2003 } break;
689 case NODE_BLOCK: { 2004 case NODE_BLOCK: {
690 CompResult res; 2005 CompResult res;
691 for (sz i = 0; i < array_size(node->elements); i++) { 2006 for (sz i = 0; i < array_size(node->elements); i++) {
692 Node *root = node->elements[i]; 2007 Node *root = node->elements[i];
693 res = compile_expr(chunk, root); 2008 res = compile_expr(compiler, chunk, root);
694 } 2009 }
695 return res; 2010 return res;
696 } break; 2011 } break;
2012 case NODE_NIL: return (CompResult){.type = COMP_NIL};
697 default: { 2013 default: {
698 eprintln("error: compilation not implemented for node %s", 2014 eprintln("error: compilation not implemented for node %s",
699 node_str[node->kind]); 2015 node_str[node->kind]);
700 exit(EXIT_FAILURE); 2016 emit_compile_err(compiler, chunk, node);
2017 return (CompResult){.type = COMP_ERR};
701 } break; 2018 } break;
702 } 2019 }
703 return (CompResult){.type = COMP_ERR}; 2020 return (CompResult){.type = COMP_ERR};
@@ -706,19 +2023,31 @@ compile_expr(Chunk *chunk, Node *node) {
706void 2023void
707disassemble_instruction(Instruction instruction) { 2024disassemble_instruction(Instruction instruction) {
708 switch (instruction.op) { 2025 switch (instruction.op) {
2026 case OP_CALL:
2027 println("%s f%d", op_str[instruction.op], instruction.dst,
2028 instruction.a, instruction.b);
2029 break;
709 case OP_MOV8: 2030 case OP_MOV8:
710 case OP_MOV16: 2031 case OP_MOV16:
711 case OP_MOV32: 2032 case OP_MOV32:
712 case OP_MOV64: 2033 case OP_MOV64:
713 println("%s r%d, r%d", op_str[instruction.op], instruction.dst,
714 instruction.a, instruction.b);
715 break;
716 case OP_LD8K: 2034 case OP_LD8K:
717 case OP_LD16K: 2035 case OP_LD16K:
718 case OP_LD32K: 2036 case OP_LD32K:
719 case OP_LD64K: 2037 case OP_LD64K:
2038 case OP_ST8K:
2039 case OP_ST16K:
2040 case OP_ST32K:
2041 case OP_ST64K:
2042 println("%s r%d, r%d", op_str[instruction.op], instruction.dst,
2043 instruction.a, instruction.b);
2044 break;
720 case OP_JMPF: 2045 case OP_JMPF:
721 case OP_JMPT: 2046 case OP_JMPT:
2047 println("%s l%d, r%d", op_str[instruction.op], instruction.dst,
2048 instruction.a, instruction.b);
2049 break;
2050 case OP_LDCONST:
722 println("%s r%d, c%d", op_str[instruction.op], instruction.dst, 2051 println("%s r%d, c%d", op_str[instruction.op], instruction.dst,
723 instruction.a, instruction.b); 2052 instruction.a, instruction.b);
724 break; 2053 break;
@@ -752,6 +2081,7 @@ disassemble_instruction(Instruction instruction) {
752 case OP_BITRSHIFTI: 2081 case OP_BITRSHIFTI:
753 case OP_BITANDI: 2082 case OP_BITANDI:
754 case OP_BITORI: 2083 case OP_BITORI:
2084 case OP_BITXORI:
755 println("%s r%d, r%d, c%d", op_str[instruction.op], instruction.dst, 2085 println("%s r%d, r%d, c%d", op_str[instruction.op], instruction.dst,
756 instruction.a, instruction.b); 2086 instruction.a, instruction.b);
757 break; 2087 break;
@@ -785,18 +2115,28 @@ disassemble_instruction(Instruction instruction) {
785 case OP_BITRSHIFT: 2115 case OP_BITRSHIFT:
786 case OP_BITAND: 2116 case OP_BITAND:
787 case OP_BITOR: 2117 case OP_BITOR:
2118 case OP_BITXOR:
788 println("%s r%d, r%d, r%d", op_str[instruction.op], instruction.dst, 2119 println("%s r%d, r%d, r%d", op_str[instruction.op], instruction.dst,
789 instruction.a, instruction.b); 2120 instruction.a, instruction.b);
790 break; 2121 break;
791 case OP_LDGVAR: 2122 case OP_LDGVAR:
2123 case OP_LDGADDR:
2124 case OP_LDLVAR:
2125 case OP_LDLADDR:
792 println("%s r%d, v%d", op_str[instruction.op], instruction.dst, 2126 println("%s r%d, v%d", op_str[instruction.op], instruction.dst,
793 instruction.a, instruction.b); 2127 instruction.a, instruction.b);
794 break; 2128 break;
2129 case OP_LDSTR:
2130 println("%s r%d, s%d", op_str[instruction.op], instruction.dst,
2131 instruction.a, instruction.b);
2132 break;
795 case OP_STGVAR: 2133 case OP_STGVAR:
2134 case OP_STLVAR:
796 println("%s v%d, r%d", op_str[instruction.op], instruction.dst, 2135 println("%s v%d, r%d", op_str[instruction.op], instruction.dst,
797 instruction.a, instruction.b); 2136 instruction.a, instruction.b);
798 break; 2137 break;
799 case OP_STGVARI: 2138 case OP_STGVARI:
2139 case OP_STLVARI:
800 println("%s v%d, c%d", op_str[instruction.op], instruction.dst, 2140 println("%s v%d, c%d", op_str[instruction.op], instruction.dst,
801 instruction.a, instruction.b); 2141 instruction.a, instruction.b);
802 break; 2142 break;
@@ -810,19 +2150,53 @@ disassemble_instruction(Instruction instruction) {
810 println("%s r%d, r%d", op_str[instruction.op], instruction.dst, 2150 println("%s r%d, r%d", op_str[instruction.op], instruction.dst,
811 instruction.a, instruction.b); 2151 instruction.a, instruction.b);
812 break; 2152 break;
813 case OP_JMPI:
814 println("%s c%d", op_str[instruction.op], instruction.dst,
815 instruction.a, instruction.b);
816 break;
817 case OP_JMP: 2153 case OP_JMP:
818 println("%s r%d", op_str[instruction.op], instruction.dst, 2154 println("%s l%d", op_str[instruction.op], instruction.dst,
819 instruction.a, instruction.b); 2155 instruction.a, instruction.b);
820 break; 2156 break;
821 case OP_JMPFI: 2157 case OP_JMPFI:
822 case OP_JMPTI: 2158 case OP_JMPTI:
823 println("%s c%d, c%d", op_str[instruction.op], instruction.dst, 2159 println("%s l%d, c%d", op_str[instruction.op], instruction.dst,
824 instruction.a, instruction.b); 2160 instruction.a, instruction.b);
825 break; 2161 break;
2162 case OP_PRINTS8:
2163 case OP_PRINTS16:
2164 case OP_PRINTS32:
2165 case OP_PRINTS64:
2166 case OP_PRINTU8:
2167 case OP_PRINTU16:
2168 case OP_PRINTU32:
2169 case OP_PRINTU64:
2170 case OP_PRINTF32:
2171 case OP_PRINTF64:
2172 case OP_PRINTSTR:
2173 case OP_PRINTBOOL:
2174 case OP_PUSH:
2175 case OP_POP:
2176 case OP_PUTRET:
2177 println("%s r%d", op_str[instruction.op], instruction.dst,
2178 instruction.a, instruction.b);
2179 break;
2180 case OP_PRINTSTRI:
2181 case OP_PRINTS8I:
2182 case OP_PRINTS16I:
2183 case OP_PRINTS32I:
2184 case OP_PRINTS64I:
2185 case OP_PRINTU8I:
2186 case OP_PRINTU16I:
2187 case OP_PRINTU32I:
2188 case OP_PRINTU64I:
2189 case OP_PRINTF32I:
2190 case OP_PRINTF64I:
2191 case OP_PRINTBOOLI:
2192 case OP_RESERVE:
2193 case OP_PUSHI:
2194 case OP_PUTRETI:
2195 println("%s c%d", op_str[instruction.op], instruction.dst,
2196 instruction.a, instruction.b);
2197 break;
2198 case OP_RET:
2199 case OP_RECUR:
826 case OP_HALT: println("%s", op_str[instruction.op]); break; 2200 case OP_HALT: println("%s", op_str[instruction.op]); break;
827 default: println("Unknown opcode %d", instruction.op); break; 2201 default: println("Unknown opcode %d", instruction.op); break;
828 } 2202 }
@@ -830,36 +2204,141 @@ disassemble_instruction(Instruction instruction) {
830 2204
831void 2205void
832disassemble_chunk(Chunk chunk) { 2206disassemble_chunk(Chunk chunk) {
833 println("%s: ============== code ==============", chunk.file_name); 2207 println("CHUNK %d: %s%s", chunk.id, chunk.file_name, chunk.name);
2208 println("n_regs: %d, n_vars: %d, n_strings: %d, n_consts: %d",
2209 chunk.reg_idx, array_size(chunk.vars), chunk.str_idx,
2210 chunk.const_idx);
2211 println("================== code ==================");
2212 println(" LINE:COL INUM LABELS OP OPERANDS ");
2213 println("------------------------------------------");
834 for (sz i = 0; i < array_size(chunk.code); i++) { 2214 for (sz i = 0; i < array_size(chunk.code); i++) {
835 print("%s: %x{4}: ", chunk.file_name, i); 2215 printf(" %.4ld:%.4ld %.4lx ", chunk.linecol[i].line,
2216 chunk.linecol[i].col, i);
2217 IntIntMapIter lab_it = intintmap_iterator(chunk.labels, chunk.storage);
2218 IntIntMap *m = intintmap_next(&lab_it, chunk.storage);
2219 Str labs = cstr("");
2220 while (m) {
2221 if (m->val == i) {
2222 labs = str_concat(labs, cstr(".L"), chunk.storage);
2223 labs = str_concat(labs, str_from_int(m->key, chunk.storage),
2224 chunk.storage);
2225 break;
2226 }
2227 m = intintmap_next(&lab_it, chunk.storage);
2228 }
2229 if (labs.size) {
2230 print("%s", labs);
2231 for (sz i = 0; i < 7 - labs.size; i++) {
2232 print(" ");
2233 }
2234 } else {
2235 printf(" ");
2236 }
836 disassemble_instruction(chunk.code[i]); 2237 disassemble_instruction(chunk.code[i]);
837 } 2238 }
838 if (array_size(chunk.constants) > 0) { 2239 if (array_size(chunk.constants) > 0) {
839 println("%s: ============ constants ===========", chunk.file_name); 2240 println("================ constants ===============", chunk.file_name);
840 for (sz i = 0; i < array_size(chunk.constants); i++) { 2241 for (sz i = 0; i < array_size(chunk.constants); i++) {
841 println("%s: %x{2}: %x{8}", chunk.file_name, i, 2242 println(" %x{2}: %x{8}", i, chunk.constants[i]);
842 chunk.constants[i]);
843 } 2243 }
844 } 2244 }
845 if (array_size(chunk.strings) > 0) { 2245 if (array_size(chunk.strings) > 0) {
846 println("%s: ============= strings ============", chunk.file_name); 2246 println("================= strings ================", chunk.file_name);
847 for (sz i = 0; i < array_size(chunk.strings); i++) { 2247 for (sz i = 0; i < array_size(chunk.strings); i++) {
848 println("%s: %x{2}: %s", chunk.file_name, i, chunk.strings[i]); 2248 println(" %x{2}: %s", i, chunk.strings[i]);
849 } 2249 }
850 } 2250 }
851 if (array_size(chunk.vars) > 0) { 2251 if (array_size(chunk.vars) > 0) {
852 println("%s: ============ variables ===========", chunk.file_name); 2252 println("================ variables ===============", chunk.file_name);
853 for (sz i = 0; i < array_size(chunk.vars); i++) { 2253 for (sz i = 0; i < array_size(chunk.vars); i++) {
854 println("%s: %x{2}: [%x{4}:%x{4}] %s: %s", chunk.file_name, i, 2254 println(" %x{2}: [%x{4}:%x{4}] %s: %s", i, chunk.vars[i].offset,
855 chunk.vars[i].offset,
856 chunk.vars[i].offset + chunk.vars[i].size, 2255 chunk.vars[i].offset + chunk.vars[i].size,
857 chunk.vars[i].name, chunk.vars[i].type); 2256 chunk.vars[i].name, chunk.vars[i].type_name);
858 } 2257 }
859 } 2258 }
860 println("n_regs: %d, n_vars: %d, n_strings: %d, n_consts: %d", 2259 if (array_size(chunk.functions) > 0) {
861 chunk.reg_idx, array_size(chunk.vars), chunk.str_idx, 2260 println("================ functions ===============", chunk.file_name);
862 chunk.const_idx); 2261 for (sz i = 0; i < array_size(chunk.functions); i++) {
2262 Chunk *func = chunk.functions[i];
2263 println(" %x{2}: func%d: %s", i, func->id, func->name);
2264 }
2265 }
2266 println("==========================================");
2267 for (sz i = 0; i < array_size(chunk.functions); i++) {
2268 Chunk *func = chunk.functions[i];
2269 disassemble_chunk(*func);
2270 }
2271}
2272
2273void
2274bytecode_compiler(Compiler *compiler, Parser parser) {
2275 compiler->main_chunk = (Chunk){
2276 .file_name = compiler->file_name,
2277 .storage = compiler->storage,
2278 .name = cstr(".main"),
2279 };
2280 array_zero(compiler->main_chunk.constants, 256, compiler->storage);
2281 array_zero(compiler->main_chunk.code, 0xffff, compiler->storage);
2282 sz n_roots = array_size(parser.nodes);
2283
2284 // Fill up builtin types and tables.
2285 for (sz i = 0; i < LEN(builtin_types); i++) {
2286 Type type = builtin_types[i];
2287 strtype_insert(&compiler->type_map, type.unique_name, type,
2288 compiler->storage);
2289 }
2290 Str unsigned_ints[] = {
2291 cstr("U8"), cstr("U16"), cstr("U32"),
2292 cstr("U64"), cstr("Ptr"), cstr("UInt"),
2293 };
2294 for (sz i = 0; i < LEN(unsigned_ints); i++) {
2295 Str type = unsigned_ints[i];
2296 strset_insert(&compiler->unsigned_ints, type, compiler->storage);
2297 }
2298 Str signed_ints[] = {
2299 cstr("S8"), cstr("S16"), cstr("S32"), cstr("S64"), cstr("Int"),
2300 };
2301 for (sz i = 0; i < LEN(signed_ints); i++) {
2302 Str type = signed_ints[i];
2303 strset_insert(&compiler->signed_ints, type, compiler->storage);
2304 }
2305
2306 // Do a first pass to setup the function declarations on the main scope.
2307 Chunk *chunk = &compiler->main_chunk;
2308 for (sz i = 0; i < n_roots; i++) {
2309 Node *root = parser.nodes[i];
2310 if (root->kind == NODE_FUN) {
2311 declare_function(chunk, root);
2312 }
2313 }
2314
2315 // Compile all root expressions.
2316 CompResult res = {0};
2317 for (sz i = 0; i < n_roots; i++) {
2318 Node *root = parser.nodes[i];
2319 res = compile_expr(compiler, chunk, root);
2320 }
2321
2322 // Make sure the last result is on r0.
2323 sz res_reg = 0;
2324 bool is_nil = false;
2325 switch (res.type) {
2326 case COMP_CONST: {
2327 res_reg = chunk->reg_idx++;
2328 Instruction inst =
2329 (Instruction){.op = OP_LDCONST, .dst = res_reg, .a = res.idx};
2330 array_push(chunk->code, inst, chunk->storage);
2331 } break;
2332 case COMP_REG: {
2333 res_reg = res.idx;
2334 } break;
2335 case COMP_NIL: {
2336 is_nil = true;
2337 } break;
2338 default: break;
2339 }
2340 emit_op(OP_HALT, res_reg, !is_nil, 0, NULL, chunk);
2341 verify_chunk(chunk);
863} 2342}
864 2343
865#endif // COMPILER_C 2344#endif // COMPILER_C