aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2024-06-28 14:07:04 +0200
committerBad Diode <bd@badd10de.dev>2024-06-28 14:07:04 +0200
commit821eeb930dc29d4012feb1f65256835430add6e6 (patch)
tree77f3968bacf0131ee8048e7d73629138898f0eb2
parent4ba7a7509d398df55e10274a24985e63e6723ad9 (diff)
downloadbdl-821eeb930dc29d4012feb1f65256835430add6e6.tar.gz
bdl-821eeb930dc29d4012feb1f65256835430add6e6.zip
Split compiler/vm files
-rw-r--r--src/compiler.c261
-rw-r--r--src/main.c4
-rw-r--r--src/semantic.c4
-rw-r--r--src/vm.c253
4 files changed, 273 insertions, 249 deletions
diff --git a/src/compiler.c b/src/compiler.c
new file mode 100644
index 0000000..d1e8a74
--- /dev/null
+++ b/src/compiler.c
@@ -0,0 +1,261 @@
1#ifndef COMPILER_C
2#define COMPILER_C
3
4#include "badlib.h"
5
6#include "parser.c"
7
8typedef struct Instruction {
9 u8 dst;
10 u8 a;
11 u8 b;
12 u8 op;
13} Instruction;
14
15typedef union Constant {
16 s64 i;
17 u64 u;
18 double f;
19 ptrsize ptr;
20} Constant;
21
22typedef struct Chunk {
23 Instruction *code;
24
25 // Constant values that fit in 64 bits.
26 Constant *constants;
27 IntIntMap *intmap;
28 sz const_idx;
29
30 // Constant strings.
31 Str *strings;
32 StrIntMap *strmap;
33 sz str_idx;
34
35 // Number of registers currently used in this chunk.
36 sz reg_idx;
37
38 // Debugging.
39 Str file_name;
40 Arena *storage;
41 // TODO: line/col info for debugging.
42} Chunk;
43
44typedef enum OpCode {
45 // OP DST A B
46 // ---------------------------------------------------------------
47 // VM/high level instructions.
48 OP_HALT, // halt
49 // Load/Store instructions.
50 OP_LD8K, // ld8k rx, ca -> u8 rx = ca
51 OP_LD16K, // ld16k rx, ca -> u16 rx = ca
52 OP_LD32K, // ld32k rx, ca -> u32 rx = ca
53 OP_LD64K, // ld64k rx, ca -> u64 rx = ca
54 OP_LD8I, // ld8i rx, ra, cb -> u8 *p; rx = p[ra + cb]
55 OP_LD16I, // ld16i rx, ra, cb -> u16 *p; rx = p[ra + cb]
56 OP_LD32I, // ld32i rx, ra, cb -> u32 *p; rx = p[ra + cb]
57 OP_LD64I, // ld64i rx, ra, cb -> u64 *p; rx = p[ra + cb]
58 OP_LD8, // ld8 rx, ra, rb -> u8 *p; rx = p[ra + rb]
59 OP_LD16, // ld16 rx, ra, rb -> u16 *p; rx = p[ra + rb]
60 OP_LD32, // ld32 rx, ra, rb -> u32 *p; rx = p[ra + rb]
61 OP_LD64, // ld64 rx, ra, rb -> u64 *p; rx = p[ra + rb]
62 OP_ST8I, // st8i rx, ra, cb -> u8 *p; p[ra + cb] = rx
63 OP_ST16I, // st16i rx, ra, cb -> u16 *p; p[ra + cb] = rx
64 OP_ST32I, // st32i rx, ra, cb -> u32 *p; p[ra + cb] = rx
65 OP_ST64I, // st64i rx, ra, cb -> u64 *p; p[ra + cb] = rx
66 OP_ST8, // st8 rx, ra, rb -> u8 *p; p[ra + rb] = rx
67 OP_ST16, // st16 rx, ra, rb -> u16 *p; p[ra + rb] = rx
68 OP_ST32, // st32 rx, ra, rb -> u32 *p; p[ra + rb] = rx
69 OP_ST64, // st64 rx, ra, rb -> u64 *p; p[ra + rb] = rx
70 // Integer arithmetic (only int/s64 for now).
71 OP_ADDI, // addk rx, ra, cb
72 OP_SUBI, // subk rx, ra, cb
73 OP_MULI, // mulk rx, ra, cb
74 OP_DIVI, // divk rx, ra, cb
75 OP_MODI, // modk rx, ra, cb
76 OP_ADD, // add rx, ra, rb
77 OP_SUB, // sub rx, ra, rb
78 OP_MUL, // mul rx, ra, rb
79 OP_DIV, // div rx, ra, rb
80 OP_MOD, // mod rx, ra, rb
81 // Floating point arithmetic (only f64 for now).
82 OP_ADDFI, // addfk rx, ra, cb
83 OP_SUBFI, // subfk rx, ra, cb
84 OP_MULFI, // mulfk rx, ra, cb
85 OP_DIVFI, // divfk rx, ra, cb
86 OP_MODFI, // modfk rx, ra, cb
87 OP_ADDF, // addf rx, ra, rb
88 OP_SUBF, // subf rx, ra, rb
89 OP_MULF, // mulf rx, ra, rb
90 OP_DIVF, // divf rx, ra, rb
91 OP_MODF, // modf rx, ra, rb
92 // Register-to-register copy.
93 OP_MOV8, // mov8 rx, ra -> rx = ra & 0xFF
94 OP_MOV16, // mov16 rx, ra -> rx = ra & 0xFFFF
95 OP_MOV32, // mov32 rx, ra -> rx = ra & 0xFFFFFFFF
96 OP_MOV64, // mov64 rx, ra -> rx = ra & 0xFFFFFFFFFFFFFFFF
97} OpCode;
98
99Str op_str[] = {
100 [OP_HALT] = cstr("HALT "),
101 // Load ops.
102 [OP_LD8K] = cstr("LD8K "),
103 [OP_LD16K] = cstr("LD16K "),
104 [OP_LD32K] = cstr("LD32K "),
105 [OP_LD64K] = cstr("LD64K "),
106 [OP_LD8I] = cstr("LD8I "),
107 [OP_LD16I] = cstr("LD16I "),
108 [OP_LD32I] = cstr("LD32I "),
109 [OP_LD64I] = cstr("LD64I "),
110 [OP_LD8] = cstr("LD8 "),
111 [OP_LD16] = cstr("LD16 "),
112 [OP_LD32] = cstr("LD32 "),
113 [OP_LD64] = cstr("LD64 "),
114 // Store ops.
115 [OP_ST8I] = cstr("ST8I "),
116 [OP_ST16I] = cstr("ST16I "),
117 [OP_ST32I] = cstr("ST32I "),
118 [OP_ST64I] = cstr("ST64I "),
119 [OP_ST8] = cstr("ST8 "),
120 [OP_ST16] = cstr("ST16 "),
121 [OP_ST32] = cstr("ST32 "),
122 [OP_ST64] = cstr("ST64 "),
123 // Arithmetic.
124 [OP_ADDI] = cstr("ADDI "),
125 [OP_SUBI] = cstr("SUBI "),
126 [OP_MULI] = cstr("MULI "),
127 [OP_DIVI] = cstr("DIVI "),
128 [OP_MODI] = cstr("MODI "),
129 [OP_ADD] = cstr("ADD "),
130 [OP_SUB] = cstr("SUB "),
131 [OP_MUL] = cstr("MUL "),
132 [OP_DIV] = cstr("DIV "),
133 [OP_MOD] = cstr("MOD "),
134 [OP_ADDFI] = cstr("ADDFI "),
135 [OP_SUBFI] = cstr("SUBFI "),
136 [OP_MULFI] = cstr("MULFI "),
137 [OP_DIVFI] = cstr("DIVFI "),
138 [OP_MODFI] = cstr("MODFI "),
139 [OP_ADDF] = cstr("ADDF "),
140 [OP_SUBF] = cstr("SUBF "),
141 [OP_MULF] = cstr("MULF "),
142 [OP_DIVF] = cstr("DIVF "),
143 // Reg copy/move.
144 [OP_MODF] = cstr("MODF "),
145 [OP_MOV8] = cstr("MOV8 "),
146 [OP_MOV16] = cstr("MOV16 "),
147 [OP_MOV32] = cstr("MOV32 "),
148 [OP_MOV64] = cstr("MOV64 "),
149};
150
151typedef enum {
152 COMP_CONST,
153 COMP_STRING,
154 COMP_REG,
155 COMP_ERR,
156} CompResultType;
157
158typedef struct CompResult {
159 sz idx;
160 CompResultType type;
161} CompResult;
162
163CompResult compile_expr(Chunk *chunk, Node *node);
164
165#define EMIT_OP(OP, DST, A, B, NODE, CHUNK) \
166 do { \
167 Instruction inst = (Instruction){ \
168 .op = (OP), \
169 .dst = (DST), \
170 .a = (A), \
171 .b = (B), \
172 }; \
173 array_push((CHUNK)->code, inst, (CHUNK)->storage); \
174 } while (0)
175
176CompResult
177compile_binary(OpCode op, Chunk *chunk, Node *node) {
178 CompResult comp_a = compile_expr(chunk, node->left);
179 CompResult comp_b = compile_expr(chunk, node->right);
180 sz reg_a;
181 sz reg_b;
182 switch (comp_a.type) {
183 case COMP_CONST: {
184 reg_a = chunk->reg_idx++;
185 EMIT_OP(OP_LD64K, reg_a, comp_a.idx, 0, node, chunk);
186 } break;
187 case COMP_REG: {
188 reg_a = comp_a.idx;
189 } break;
190 default: {
191 return (CompResult){.type = COMP_ERR};
192 } break;
193 }
194 switch (comp_b.type) {
195 case COMP_CONST: {
196 reg_b = chunk->reg_idx++;
197 EMIT_OP(OP_LD64K, reg_b, comp_b.idx, 0, node, chunk);
198 } break;
199 case COMP_REG: {
200 reg_b = comp_b.idx;
201 } break;
202 default: {
203 return (CompResult){.type = COMP_ERR};
204 } break;
205 }
206 sz reg_dst = comp_a.idx; // Less registers
207 // sz reg_dst = chunk->reg_idx++; // Better for optimization
208 EMIT_OP(op, reg_dst, reg_a, reg_b, node, chunk);
209 return (CompResult){.type = COMP_REG, .idx = reg_dst};
210}
211
212CompResult
213compile_expr(Chunk *chunk, Node *node) {
214 switch (node->kind) {
215 case NODE_ADD: return compile_binary(OP_ADD, chunk, node); break;
216 case NODE_SUB: return compile_binary(OP_SUB, chunk, node); break;
217 case NODE_MUL: return compile_binary(OP_MUL, chunk, node); break;
218 case NODE_DIV: return compile_binary(OP_DIV, chunk, node); break;
219 case NODE_MOD: return compile_binary(OP_MOD, chunk, node); break;
220 case NODE_TRUE:
221 case NODE_FALSE:
222 case NODE_NUM_FLOAT:
223 case NODE_NUM_INT: {
224 sz value = node->value.i;
225 // Make sure we don't have duplicated constants.
226 IntIntMap *map = intintmap_lookup(&chunk->intmap, value);
227 if (!map) {
228 map = intintmap_insert(&chunk->intmap, value,
229 chunk->const_idx++, chunk->storage);
230 Constant c = (Constant){.i = node->value.i};
231 array_push(chunk->constants, c, chunk->storage);
232 }
233 return (CompResult){
234 .type = COMP_CONST,
235 .idx = map->val,
236 };
237 } break;
238 case NODE_STRING: {
239 Str string = node->value.str;
240 // Make sure we don't have duplicated strings.
241 StrIntMap *map = strintmap_lookup(&chunk->strmap, string);
242 if (!map) {
243 map = strintmap_insert(&chunk->strmap, string, chunk->str_idx++,
244 chunk->storage);
245 array_push(chunk->strings, string, chunk->storage);
246 }
247 return (CompResult){
248 .type = COMP_STRING,
249 .idx = map->val,
250 };
251 } break;
252 default: {
253 eprintln("error: compilation not implemented for node %s",
254 node_str[node->kind]);
255 exit(EXIT_FAILURE);
256 } break;
257 }
258 return (CompResult){.type = COMP_ERR};
259}
260
261#endif // COMPILER_C
diff --git a/src/main.c b/src/main.c
index fdbf4e0..c52ec74 100644
--- a/src/main.c
+++ b/src/main.c
@@ -3,6 +3,7 @@
3#include <stdlib.h> 3#include <stdlib.h>
4 4
5#include "badlib.h" 5#include "badlib.h"
6#include "compiler.c"
6#include "lexer.c" 7#include "lexer.c"
7#include "parser.c" 8#include "parser.c"
8#include "semantic.c" 9#include "semantic.c"
@@ -193,6 +194,8 @@ process_file(Str path) {
193 Instruction halt = (Instruction){.op = OP_HALT, .dst = res_reg}; 194 Instruction halt = (Instruction){.op = OP_HALT, .dst = res_reg};
194 array_push(chunk.code, halt, &bytecode_arena); 195 array_push(chunk.code, halt, &bytecode_arena);
195 196
197 disassemble_chunk(chunk);
198
196 // Run bytecode on VM. 199 // Run bytecode on VM.
197 VM vm = {0}; 200 VM vm = {0};
198 vm_init(&vm, &chunk); 201 vm_init(&vm, &chunk);
@@ -201,7 +204,6 @@ process_file(Str path) {
201 vm_run(&vm); 204 vm_run(&vm);
202 // println("VM REGISTERS AFTER:\n%{Mem}", 205 // println("VM REGISTERS AFTER:\n%{Mem}",
203 // &(Array){.mem = (u8 *)&vm.regs, sizeof(vm.regs)}); 206 // &(Array){.mem = (u8 *)&vm.regs, sizeof(vm.regs)});
204 disassemble_chunk(chunk);
205 207
206#if DEBUG == 1 208#if DEBUG == 1
207 println("Space used: %{Arena}", &lexer_arena); 209 println("Space used: %{Arena}", &lexer_arena);
diff --git a/src/semantic.c b/src/semantic.c
index 428cc53..7158052 100644
--- a/src/semantic.c
+++ b/src/semantic.c
@@ -1,3 +1,6 @@
1#ifndef SEMANTIC_C
2#define SEMANTIC_C
3
1#include "badlib.h" 4#include "badlib.h"
2 5
3typedef enum { 6typedef enum {
@@ -1232,3 +1235,4 @@ symbolic_analysis(Analyzer *a, Parser *parser) {
1232 } 1235 }
1233} 1236}
1234 1237
1238#endif // SEMANTIC_C
diff --git a/src/vm.c b/src/vm.c
index cb1b6cd..8d4e67e 100644
--- a/src/vm.c
+++ b/src/vm.c
@@ -1,143 +1,8 @@
1#include "badlib.h" 1#ifndef VM_C
2#include "parser.c" 2#define VM_C
3
4typedef struct Instruction {
5 u8 dst;
6 u8 a;
7 u8 b;
8 u8 op;
9} Instruction;
10
11typedef union Constant {
12 s64 i;
13 u64 u;
14 double f;
15 ptrsize ptr;
16} Constant;
17
18typedef struct Chunk {
19 Instruction *code;
20
21 // Constant values that fit in 64 bits.
22 Constant *constants;
23 IntIntMap *intmap;
24 sz const_idx;
25
26 // Constant strings.
27 Str *strings;
28 StrIntMap *strmap;
29 sz str_idx;
30 3
31 // Number of registers currently used in this chunk. 4#include "badlib.h"
32 sz reg_idx; 5#include "compiler.c"
33
34 // Debugging.
35 Str file_name;
36 Arena *storage;
37 // TODO: line/col info for debugging.
38} Chunk;
39
40typedef enum OpCode {
41 // OP DST A B
42 // ---------------------------------------------------------------
43 OP_HALT, // halt
44 OP_LD8K, // ld8k rx, ca -> u8 rx = ca
45 OP_LD16K, // ld16k rx, ca -> u16 rx = ca
46 OP_LD32K, // ld32k rx, ca -> u32 rx = ca
47 OP_LD64K, // ld64k rx, ca -> u64 rx = ca
48 OP_LD8I, // ld8i rx, ra, cb -> u8 *p; rx = p[ra + cb]
49 OP_LD16I, // ld16i rx, ra, cb -> u16 *p; rx = p[ra + cb]
50 OP_LD32I, // ld32i rx, ra, cb -> u32 *p; rx = p[ra + cb]
51 OP_LD64I, // ld64i rx, ra, cb -> u64 *p; rx = p[ra + cb]
52 OP_LD8, // ld8 rx, ra, rb -> u8 *p; rx = p[ra + rb]
53 OP_LD16, // ld16 rx, ra, rb -> u16 *p; rx = p[ra + rb]
54 OP_LD32, // ld32 rx, ra, rb -> u32 *p; rx = p[ra + rb]
55 OP_LD64, // ld64 rx, ra, rb -> u64 *p; rx = p[ra + rb]
56 OP_ST8I, // st8i rx, ra, cb -> u8 *p; p[ra + cb] = rx
57 OP_ST16I, // st16i rx, ra, cb -> u16 *p; p[ra + cb] = rx
58 OP_ST32I, // st32i rx, ra, cb -> u32 *p; p[ra + cb] = rx
59 OP_ST64I, // st64i rx, ra, cb -> u64 *p; p[ra + cb] = rx
60 OP_ST8, // st8 rx, ra, rb -> u8 *p; p[ra + rb] = rx
61 OP_ST16, // st16 rx, ra, rb -> u16 *p; p[ra + rb] = rx
62 OP_ST32, // st32 rx, ra, rb -> u32 *p; p[ra + rb] = rx
63 OP_ST64, // st64 rx, ra, rb -> u64 *p; p[ra + rb] = rx
64 OP_ADDI, // addk rx, ra, cb
65 OP_SUBI, // subk rx, ra, cb
66 OP_MULI, // mulk rx, ra, cb
67 OP_DIVI, // divk rx, ra, cb
68 OP_MODI, // modk rx, ra, cb
69 OP_ADD, // add rx, ra, rb
70 OP_SUB, // sub rx, ra, rb
71 OP_MUL, // mul rx, ra, rb
72 OP_DIV, // div rx, ra, rb
73 OP_MOD, // mod rx, ra, rb
74 OP_ADDFI, // addk rx, ra, cb
75 OP_SUBFI, // subk rx, ra, cb
76 OP_MULFI, // mulk rx, ra, cb
77 OP_DIVFI, // divk rx, ra, cb
78 OP_MODFI, // modk rx, ra, cb
79 OP_ADDF, // add rx, ra, rb
80 OP_SUBF, // sub rx, ra, rb
81 OP_MULF, // mul rx, ra, rb
82 OP_DIVF, // div rx, ra, rb
83 OP_MODF, // mod rx, ra, rb
84 OP_MOV8, // mov8 rx, ra -> rx = ra & 0xFF
85 OP_MOV16, // mov16 rx, ra -> rx = ra & 0xFFFF
86 OP_MOV32, // mov32 rx, ra -> rx = ra & 0xFFFFFFFF
87 OP_MOV64, // mov64 rx, ra -> rx = ra & 0xFFFFFFFFFFFFFFFF
88} OpCode;
89
90Str op_str[] = {
91 [OP_HALT] = cstr("HALT "),
92 // Load ops.
93 [OP_LD8K] = cstr("LD8K "),
94 [OP_LD16K] = cstr("LD16K "),
95 [OP_LD32K] = cstr("LD32K "),
96 [OP_LD64K] = cstr("LD64K "),
97 [OP_LD8I] = cstr("LD8I "),
98 [OP_LD16I] = cstr("LD16I "),
99 [OP_LD32I] = cstr("LD32I "),
100 [OP_LD64I] = cstr("LD64I "),
101 [OP_LD8] = cstr("LD8 "),
102 [OP_LD16] = cstr("LD16 "),
103 [OP_LD32] = cstr("LD32 "),
104 [OP_LD64] = cstr("LD64 "),
105 // Store ops.
106 [OP_ST8I] = cstr("ST8I "),
107 [OP_ST16I] = cstr("ST16I "),
108 [OP_ST32I] = cstr("ST32I "),
109 [OP_ST64I] = cstr("ST64I "),
110 [OP_ST8] = cstr("ST8 "),
111 [OP_ST16] = cstr("ST16 "),
112 [OP_ST32] = cstr("ST32 "),
113 [OP_ST64] = cstr("ST64 "),
114 // Arithmetic.
115 [OP_ADDI] = cstr("ADDI "),
116 [OP_SUBI] = cstr("SUBI "),
117 [OP_MULI] = cstr("MULI "),
118 [OP_DIVI] = cstr("DIVI "),
119 [OP_MODI] = cstr("MODI "),
120 [OP_ADD] = cstr("ADD "),
121 [OP_SUB] = cstr("SUB "),
122 [OP_MUL] = cstr("MUL "),
123 [OP_DIV] = cstr("DIV "),
124 [OP_MOD] = cstr("MOD "),
125 [OP_ADDFI] = cstr("ADDFI "),
126 [OP_SUBFI] = cstr("SUBFI "),
127 [OP_MULFI] = cstr("MULFI "),
128 [OP_DIVFI] = cstr("DIVFI "),
129 [OP_MODFI] = cstr("MODFI "),
130 [OP_ADDF] = cstr("ADDF "),
131 [OP_SUBF] = cstr("SUBF "),
132 [OP_MULF] = cstr("MULF "),
133 [OP_DIVF] = cstr("DIVF "),
134 // Reg copy/move.
135 [OP_MODF] = cstr("MODF "),
136 [OP_MOV8] = cstr("MOV8 "),
137 [OP_MOV16] = cstr("MOV16 "),
138 [OP_MOV32] = cstr("MOV32 "),
139 [OP_MOV64] = cstr("MOV64 "),
140};
141 6
142void 7void
143disassemble_instruction(Instruction instruction) { 8disassemble_instruction(Instruction instruction) {
@@ -308,112 +173,4 @@ vm_run(VM *vm) {
308 } 173 }
309} 174}
310 175
311typedef enum { 176#endif // VM_C
312 COMP_CONST,
313 COMP_STRING,
314 COMP_REG,
315 COMP_ERR,
316} CompResultType;
317
318typedef struct CompResult {
319 sz idx;
320 CompResultType type;
321} CompResult;
322
323CompResult compile_expr(Chunk *chunk, Node *node);
324
325#define EMIT_OP(OP, DST, A, B, NODE, CHUNK) \
326 do { \
327 Instruction inst = (Instruction){ \
328 .op = (OP), \
329 .dst = (DST), \
330 .a = (A), \
331 .b = (B), \
332 }; \
333 array_push((CHUNK)->code, inst, (CHUNK)->storage); \
334 } while (0)
335
336CompResult
337compile_binary(OpCode op, Chunk *chunk, Node *node) {
338 CompResult comp_a = compile_expr(chunk, node->left);
339 CompResult comp_b = compile_expr(chunk, node->right);
340 sz reg_a;
341 sz reg_b;
342 switch (comp_a.type) {
343 case COMP_CONST: {
344 reg_a = chunk->reg_idx++;
345 EMIT_OP(OP_LD64K, reg_a, comp_a.idx, 0, node, chunk);
346 } break;
347 case COMP_REG: {
348 reg_a = comp_a.idx;
349 } break;
350 default: {
351 return (CompResult){.type = COMP_ERR};
352 } break;
353 }
354 switch (comp_b.type) {
355 case COMP_CONST: {
356 reg_b = chunk->reg_idx++;
357 EMIT_OP(OP_LD64K, reg_b, comp_b.idx, 0, node, chunk);
358 } break;
359 case COMP_REG: {
360 reg_b = comp_b.idx;
361 } break;
362 default: {
363 return (CompResult){.type = COMP_ERR};
364 } break;
365 }
366 sz reg_dst = comp_a.idx; // Less registers
367 // sz reg_dst = chunk->reg_idx++; // Better for optimization
368 EMIT_OP(op, reg_dst, reg_a, reg_b, node, chunk);
369 return (CompResult){.type = COMP_REG, .idx = reg_dst};
370}
371
372CompResult
373compile_expr(Chunk *chunk, Node *node) {
374 switch (node->kind) {
375 case NODE_ADD: return compile_binary(OP_ADD, chunk, node); break;
376 case NODE_SUB: return compile_binary(OP_SUB, chunk, node); break;
377 case NODE_MUL: return compile_binary(OP_MUL, chunk, node); break;
378 case NODE_DIV: return compile_binary(OP_DIV, chunk, node); break;
379 case NODE_MOD: return compile_binary(OP_MOD, chunk, node); break;
380 case NODE_TRUE:
381 case NODE_FALSE:
382 case NODE_NUM_FLOAT:
383 case NODE_NUM_INT: {
384 sz value = node->value.i;
385 // Make sure we don't have duplicated constants.
386 IntIntMap *map = intintmap_lookup(&chunk->intmap, value);
387 if (!map) {
388 map = intintmap_insert(&chunk->intmap, value,
389 chunk->const_idx++, chunk->storage);
390 Constant c = (Constant){.i = node->value.i};
391 array_push(chunk->constants, c, chunk->storage);
392 }
393 return (CompResult){
394 .type = COMP_CONST,
395 .idx = map->val,
396 };
397 } break;
398 case NODE_STRING: {
399 Str string = node->value.str;
400 // Make sure we don't have duplicated strings.
401 StrIntMap *map = strintmap_lookup(&chunk->strmap, string);
402 if (!map) {
403 map = strintmap_insert(&chunk->strmap, string, chunk->str_idx++,
404 chunk->storage);
405 array_push(chunk->strings, string, chunk->storage);
406 }
407 return (CompResult){
408 .type = COMP_STRING,
409 .idx = map->val,
410 };
411 } break;
412 default: {
413 eprintln("error: compilation not implemented for node %s",
414 node_str[node->kind]);
415 exit(EXIT_FAILURE);
416 } break;
417 }
418 return (CompResult){.type = COMP_ERR};
419}