diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler.c | 1781 | ||||
-rw-r--r-- | src/lexer.c | 152 | ||||
-rw-r--r-- | src/main.c | 132 | ||||
-rw-r--r-- | src/parser.c | 743 | ||||
-rw-r--r-- | src/semantic.c | 843 | ||||
-rw-r--r-- | src/vm.c | 255 |
6 files changed, 2795 insertions, 1111 deletions
diff --git a/src/compiler.c b/src/compiler.c index 9b6a458..65429b0 100644 --- a/src/compiler.c +++ b/src/compiler.c | |||
@@ -5,21 +5,58 @@ | |||
5 | 5 | ||
6 | #include "parser.c" | 6 | #include "parser.c" |
7 | 7 | ||
8 | typedef 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 | |||
8 | typedef struct Variable { | 15 | typedef 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 | |||
26 | Type 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 | |||
16 | MAPDEF(StrVarMap, varmap, Str, Variable, str_hash, str_eq) | 52 | MAPDEF(StrVarMap, varmap, Str, Variable, str_hash, str_eq) |
53 | MAPDEF(StrTypeMap, strtype, Str, Type, str_hash, str_eq) | ||
17 | 54 | ||
18 | typedef struct Instruction { | 55 | typedef 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 | ||
25 | typedef union Constant { | 62 | typedef union Constant { |
@@ -49,8 +86,7 @@ typedef struct Chunk { | |||
49 | struct Chunk *parent; | 86 | struct Chunk *parent; |
50 | 87 | ||
51 | Instruction *code; | 88 | Instruction *code; |
52 | IntIntMap *labels; // label -> chunk_index | 89 | IntIntMap *labels; // label -> chunk_index |
53 | IntIntMap *labels_rev; // chunk_index -> label | ||
54 | sz labels_idx; | 90 | sz labels_idx; |
55 | 91 | ||
56 | // Constant values that fit in 64 bits. | 92 | // Constant values that fit in 64 bits. |
@@ -67,6 +103,7 @@ typedef struct Chunk { | |||
67 | Variable *vars; | 103 | Variable *vars; |
68 | StrVarMap *varmap; | 104 | StrVarMap *varmap; |
69 | sz var_off; | 105 | sz var_off; |
106 | sz param_off; | ||
70 | 107 | ||
71 | // Number of registers currently used in this chunk. | 108 | // Number of registers currently used in this chunk. |
72 | sz reg_idx; | 109 | sz reg_idx; |
@@ -82,6 +119,24 @@ typedef struct Chunk { | |||
82 | LineCol *linecol; | 119 | LineCol *linecol; |
83 | } Chunk; | 120 | } Chunk; |
84 | 121 | ||
122 | typedef 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 | |||
85 | typedef enum OpCode { | 140 | typedef enum OpCode { |
86 | // OP DST A B | 141 | // OP DST A B |
87 | // --------------------------------------------------------------- | 142 | // --------------------------------------------------------------- |
@@ -92,8 +147,14 @@ typedef enum OpCode { | |||
92 | OP_STGVAR, // stgvar vx, ra | 147 | OP_STGVAR, // stgvar vx, ra |
93 | OP_LDGVAR, // ldgvar rx, va | 148 | OP_LDGVAR, // ldgvar rx, va |
94 | OP_LDGADDR, // ldgaddr 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 | ||
95 | // Functions. | 155 | // Functions. |
96 | OP_CALL, // call fx ; Bumps the stack pointer by cx | 156 | OP_CALL, // call fx ; Call the function fx |
157 | OP_RECUR, // recur ; Jump to the beginning of the function. | ||
97 | OP_RET, // ret ; Returns from current function | 158 | OP_RET, // ret ; Returns from current function |
98 | OP_RESERVE, // reserve cx ; Increments the stack pointer by cx bytes | 159 | OP_RESERVE, // reserve cx ; Increments the stack pointer by cx bytes |
99 | OP_POP, // pop rx ; Pops the last value of the stack into rx. | 160 | OP_POP, // pop rx ; Pops the last value of the stack into rx. |
@@ -102,32 +163,56 @@ typedef enum OpCode { | |||
102 | OP_PUTRET, // putret rx ; Put rx into the return value memory. | 163 | OP_PUTRET, // putret rx ; Put rx into the return value memory. |
103 | OP_PUTRETI, // putreti cx ; Put cx into the return value memory. | 164 | OP_PUTRETI, // putreti cx ; Put cx into the return value memory. |
104 | // Printing values with builtin print/println functions. | 165 | // Printing values with builtin print/println functions. |
105 | OP_PRINTSTR, // p rx | 166 | OP_PRINTSTR, // p rx |
106 | OP_PRINTS64, // p rx | 167 | OP_PRINTSTRI, // p cx |
107 | OP_PRINTF64, // p rx | 168 | OP_PRINTS8, // p rx |
108 | OP_PRINTS64I, // p cx | 169 | OP_PRINTS8I, // p cx |
109 | OP_PRINTF64I, // 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 | ||
110 | // Load/Store instructions. | 190 | // Load/Store instructions. |
111 | OP_LD8K, // ld8k rx, ca -> u8 rx = ca | 191 | OP_LDCONST, // ldconst rx, ca -> u64 rx = ca |
112 | OP_LD16K, // ld16k rx, ca -> u16 rx = ca | 192 | OP_LD8K, // ld8k rx, ra -> u8 *p = ra; rx = *p |
113 | OP_LD32K, // ld32k rx, ca -> u32 rx = ca | 193 | OP_LD16K, // ld16k rx, ra -> u16 *p = ra; rx = *p |
114 | OP_LD64K, // ld64k rx, ca -> u64 rx = ca | 194 | OP_LD32K, // ld32k rx, ra -> u32 *p = ra; rx = *p |
115 | OP_LD8I, // ld8i rx, ra, cb -> u8 *p = ra; rx = p[cb] | 195 | OP_LD64K, // ld64k rx, ra -> u64 *p = ra; rx = *p |
116 | OP_LD16I, // ld16i rx, ra, cb -> u16 *p = ra; rx = p[cb] | 196 | OP_ST8K, // ld8k rx, ra -> u8 *p = ra; *p = rx |
117 | OP_LD32I, // ld32i rx, ra, cb -> u32 *p = ra; rx = p[cb] | 197 | OP_ST16K, // ld16k rx, ra -> u16 *p = ra; *p = rx |
118 | OP_LD64I, // ld64i rx, ra, cb -> u64 *p = ra; rx = p[cb] | 198 | OP_ST32K, // ld32k rx, ra -> u32 *p = ra; *p = rx |
119 | OP_LD8, // ld8 rx, ra, rb -> u8 *p = ra; rx = p[rb] | 199 | OP_ST64K, // ld64k rx, ra -> u64 *p = ra; *p = rx |
120 | OP_LD16, // ld16 rx, ra, rb -> u16 *p = ra; rx = p[rb] | 200 | OP_LD8I, // ld8i rx, ra, cb -> u8 *p = ra; rx = p[cb] |
121 | OP_LD32, // ld32 rx, ra, rb -> u32 *p = ra; rx = p[rb] | 201 | OP_LD16I, // ld16i rx, ra, cb -> u16 *p = ra; rx = p[cb] |
122 | OP_LD64, // ld64 rx, ra, rb -> u64 *p = ra; rx = p[rb] | 202 | OP_LD32I, // ld32i rx, ra, cb -> u32 *p = ra; rx = p[cb] |
123 | OP_ST8I, // st8i rx, ra, cb -> u8 *p = ra; p[cb] = rx | 203 | OP_LD64I, // ld64i rx, ra, cb -> u64 *p = ra; rx = p[cb] |
124 | OP_ST16I, // st16i rx, ra, cb -> u16 *p = ra; p[cb] = rx | 204 | OP_LD8, // ld8 rx, ra, rb -> u8 *p = ra; rx = p[rb] |
125 | OP_ST32I, // st32i rx, ra, cb -> u32 *p = ra; p[cb] = rx | 205 | OP_LD16, // ld16 rx, ra, rb -> u16 *p = ra; rx = p[rb] |
126 | OP_ST64I, // st64i rx, ra, cb -> u64 *p = ra; p[cb] = rx | 206 | OP_LD32, // ld32 rx, ra, rb -> u32 *p = ra; rx = p[rb] |
127 | OP_ST8, // st8 rx, ra, rb -> u8 *p = ra; p[rb] = rx | 207 | OP_LD64, // ld64 rx, ra, rb -> u64 *p = ra; rx = p[rb] |
128 | OP_ST16, // st16 rx, ra, rb -> u16 *p = ra; p[rb] = rx | 208 | OP_ST8I, // st8i rx, ra, cb -> u8 *p = ra; p[cb] = rx |
129 | OP_ST32, // st32 rx, ra, rb -> u32 *p = ra; p[rb] = rx | 209 | OP_ST16I, // st16i rx, ra, cb -> u16 *p = ra; p[cb] = rx |
130 | OP_ST64, // st64 rx, ra, rb -> u64 *p = ra; p[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 | ||
131 | // Integer arithmetic (only int/s64 for now). | 216 | // Integer arithmetic (only int/s64 for now). |
132 | OP_ADDI, // addk rx, ra, cb | 217 | OP_ADDI, // addk rx, ra, cb |
133 | OP_SUBI, // subk rx, ra, cb | 218 | OP_SUBI, // subk rx, ra, cb |
@@ -179,11 +264,13 @@ typedef enum OpCode { | |||
179 | OP_BITRSHIFTI, // shri rx, ra, cb | 264 | OP_BITRSHIFTI, // shri rx, ra, cb |
180 | OP_BITANDI, // bandi rx, ra, cb | 265 | OP_BITANDI, // bandi rx, ra, cb |
181 | OP_BITORI, // bori rx, ra, cb | 266 | OP_BITORI, // bori rx, ra, cb |
267 | OP_BITXORI, // bxor rx, ra, cb | ||
182 | OP_BITNOTI, // bnoti rx, ca | 268 | OP_BITNOTI, // bnoti rx, ca |
183 | OP_BITLSHIFT, // shl rx, ra, rb | 269 | OP_BITLSHIFT, // shl rx, ra, rb |
184 | OP_BITRSHIFT, // shr rx, ra, rb | 270 | OP_BITRSHIFT, // shr rx, ra, rb |
185 | OP_BITAND, // band rx, ra, rb | 271 | OP_BITAND, // band rx, ra, rb |
186 | OP_BITOR, // bor rx, ra, rb | 272 | OP_BITOR, // bor rx, ra, rb |
273 | OP_BITXOR, // bxor rx, ra, rb | ||
187 | OP_BITNOT, // bnot rx, ra | 274 | OP_BITNOT, // bnot rx, ra |
188 | // Jump instructions. | 275 | // Jump instructions. |
189 | OP_JMP, // jmp lx ; jmp to label lx | 276 | OP_JMP, // jmp lx ; jmp to label lx |
@@ -191,6 +278,7 @@ typedef enum OpCode { | |||
191 | OP_JMPT, // jmpt lx, rx ; jmp to label lx if rx is true | 278 | OP_JMPT, // jmpt lx, rx ; jmp to label lx if rx is true |
192 | OP_JMPFI, // jmpf lx, cx ; jmp to label lx if rx is false | 279 | OP_JMPFI, // jmpf lx, cx ; jmp to label lx if rx is false |
193 | OP_JMPTI, // jmpt lx, cx ; jmp to label lx if rx is true | 280 | OP_JMPTI, // jmpt lx, cx ; jmp to label lx if rx is true |
281 | _OP_NUM, | ||
194 | } OpCode; | 282 | } OpCode; |
195 | 283 | ||
196 | Str op_str[] = { | 284 | Str op_str[] = { |
@@ -200,25 +288,55 @@ Str op_str[] = { | |||
200 | [OP_STGVARI] = cstr("STGVARI "), | 288 | [OP_STGVARI] = cstr("STGVARI "), |
201 | [OP_LDGVAR] = cstr("LDGVAR "), | 289 | [OP_LDGVAR] = cstr("LDGVAR "), |
202 | [OP_LDGADDR] = cstr("LDGADDR "), | 290 | [OP_LDGADDR] = cstr("LDGADDR "), |
203 | [OP_PRINTSTR] = cstr("PRNTSTR "), | 291 | [OP_STLVAR] = cstr("STLVAR "), |
204 | [OP_PRINTS64] = cstr("PRNTS64 "), | 292 | [OP_STLVARI] = cstr("STLVARI "), |
205 | [OP_PRINTF64] = cstr("PRNTF64 "), | 293 | [OP_LDLVAR] = cstr("LDLVAR "), |
206 | [OP_PRINTS64I] = cstr("PRNTS64I"), | 294 | [OP_LDLADDR] = cstr("LDLADDR "), |
207 | [OP_PRINTF64I] = cstr("PRNTF64I"), | 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"), | ||
208 | [OP_PUTRET] = cstr("PUTRET "), | 320 | [OP_PUTRET] = cstr("PUTRET "), |
209 | [OP_PUTRETI] = cstr("PUTRETI "), | 321 | [OP_PUTRETI] = cstr("PUTRETI "), |
210 | // Functions. | 322 | // Functions. |
211 | [OP_CALL] = cstr("CALL "), | 323 | [OP_CALL] = cstr("CALL "), |
324 | [OP_RECUR] = cstr("RECUR "), | ||
212 | [OP_RET] = cstr("RET "), | 325 | [OP_RET] = cstr("RET "), |
213 | [OP_RESERVE] = cstr("RESERVE "), | 326 | [OP_RESERVE] = cstr("RESERVE "), |
214 | [OP_POP] = cstr("POP "), | 327 | [OP_POP] = cstr("POP "), |
215 | [OP_PUSH] = cstr("PUSH "), | 328 | [OP_PUSH] = cstr("PUSH "), |
216 | [OP_PUSHI] = cstr("PUSHI "), | 329 | [OP_PUSHI] = cstr("PUSHI "), |
217 | // Load ops. | 330 | // Load ops. |
331 | [OP_LDCONST] = cstr("LDCONST "), | ||
218 | [OP_LD8K] = cstr("LD8K "), | 332 | [OP_LD8K] = cstr("LD8K "), |
219 | [OP_LD16K] = cstr("LD16K "), | 333 | [OP_LD16K] = cstr("LD16K "), |
220 | [OP_LD32K] = cstr("LD32K "), | 334 | [OP_LD32K] = cstr("LD32K "), |
221 | [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 "), | ||
222 | [OP_LD8I] = cstr("LD8I "), | 340 | [OP_LD8I] = cstr("LD8I "), |
223 | [OP_LD16I] = cstr("LD16I "), | 341 | [OP_LD16I] = cstr("LD16I "), |
224 | [OP_LD32I] = cstr("LD32I "), | 342 | [OP_LD32I] = cstr("LD32I "), |
@@ -286,11 +404,13 @@ Str op_str[] = { | |||
286 | [OP_BITRSHIFTI] = cstr("RSHI "), | 404 | [OP_BITRSHIFTI] = cstr("RSHI "), |
287 | [OP_BITANDI] = cstr("BANDI "), | 405 | [OP_BITANDI] = cstr("BANDI "), |
288 | [OP_BITORI] = cstr("BORI "), | 406 | [OP_BITORI] = cstr("BORI "), |
407 | [OP_BITXORI] = cstr("BXORI "), | ||
289 | [OP_BITNOTI] = cstr("BNOTI "), | 408 | [OP_BITNOTI] = cstr("BNOTI "), |
290 | [OP_BITLSHIFT] = cstr("LSH "), | 409 | [OP_BITLSHIFT] = cstr("LSH "), |
291 | [OP_BITRSHIFT] = cstr("RSH "), | 410 | [OP_BITRSHIFT] = cstr("RSH "), |
292 | [OP_BITAND] = cstr("BAND "), | 411 | [OP_BITAND] = cstr("BAND "), |
293 | [OP_BITOR] = cstr("BOR "), | 412 | [OP_BITOR] = cstr("BOR "), |
413 | [OP_BITXOR] = cstr("XBOR "), | ||
294 | [OP_BITNOT] = cstr("BNOT "), | 414 | [OP_BITNOT] = cstr("BNOT "), |
295 | // Jump instructions. | 415 | // Jump instructions. |
296 | [OP_JMP] = cstr("JMP "), | 416 | [OP_JMP] = cstr("JMP "), |
@@ -305,6 +425,7 @@ typedef enum { | |||
305 | COMP_CONST, | 425 | COMP_CONST, |
306 | COMP_STRING, | 426 | COMP_STRING, |
307 | COMP_REG, | 427 | COMP_REG, |
428 | COMP_RET, | ||
308 | COMP_ERR, | 429 | COMP_ERR, |
309 | } CompResultType; | 430 | } CompResultType; |
310 | 431 | ||
@@ -313,73 +434,195 @@ typedef struct CompResult { | |||
313 | CompResultType type; | 434 | CompResultType type; |
314 | } CompResult; | 435 | } CompResult; |
315 | 436 | ||
316 | CompResult compile_expr(Chunk *chunk, Node *node); | 437 | CompResult compile_expr(Compiler *compiler, Chunk *chunk, Node *node); |
317 | 438 | ||
318 | #define EMIT_OP(OP, DST, A, B, NODE, CHUNK) \ | 439 | sz |
319 | do { \ | 440 | add_constant(Chunk *chunk, sz value) { |
320 | Instruction inst = (Instruction){ \ | 441 | IntIntMap *map = intintmap_lookup(&chunk->intmap, value); |
321 | .op = (OP), \ | 442 | // Make sure we don't have duplicated constants. |
322 | .dst = (DST), \ | 443 | if (!map) { |
323 | .a = (A), \ | 444 | map = intintmap_insert(&chunk->intmap, value, chunk->const_idx++, |
324 | .b = (B), \ | 445 | chunk->storage); |
325 | }; \ | 446 | Constant c = (Constant){.i = value}; |
326 | array_push((CHUNK)->code, inst, (CHUNK)->storage); \ | 447 | array_push(chunk->constants, c, chunk->storage); |
327 | LineCol linecol = (LineCol){0}; \ | 448 | } |
328 | if (NODE) { \ | 449 | return map->val; |
329 | Node *_node = (NODE); \ | 450 | } |
330 | linecol = (LineCol){.line = _node->line, .col = _node->col}; \ | 451 | |
331 | } \ | 452 | sz |
332 | array_push((CHUNK)->linecol, linecol, (CHUNK)->storage); \ | 453 | add_string(Chunk *chunk, Str string) { |
333 | } while (0) | 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 | |||
464 | sz | ||
465 | add_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 | |||
514 | void | ||
515 | emit_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 | |||
530 | void | ||
531 | emit_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 | |||
552 | void | ||
553 | emit_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 | |||
568 | void disassemble_chunk(Chunk chunk); | ||
569 | |||
570 | void | ||
571 | emit_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 | } | ||
334 | 577 | ||
335 | CompResult | 578 | CompResult |
336 | compile_binary(Chunk *chunk, Node *node) { | 579 | compile_binary(Compiler *compiler, Chunk *chunk, Node *node) { |
337 | OpCode op = OP_HALT; | 580 | OpCode op = OP_HALT; |
338 | OpCode opi = OP_HALT; | 581 | OpCode opi = OP_HALT; |
339 | OpCode ldop = OP_LD64K; | 582 | OpCode ldop = OP_LDCONST; |
340 | switch (node->kind) { | 583 | switch (node->kind) { |
341 | // Arithmetic. | 584 | // Arithmetic. |
342 | case NODE_ADD: { | 585 | case NODE_ADD: { |
343 | if (str_eq(node->type, cstr("int"))) { | 586 | if (strset_lookup(&compiler->integer_types, node->type)) { |
344 | op = OP_ADD; | 587 | op = OP_ADD; |
345 | opi = OP_ADDI; | 588 | opi = OP_ADDI; |
346 | } else if (str_eq(node->type, cstr("f64"))) { | 589 | } else if (strset_lookup(&compiler->float_types, node->type)) { |
347 | op = OP_ADDF; | 590 | op = OP_ADDF; |
348 | opi = OP_ADDFI; | 591 | opi = OP_ADDFI; |
349 | } | 592 | } |
350 | } break; | 593 | } break; |
351 | case NODE_SUB: { | 594 | case NODE_SUB: { |
352 | if (str_eq(node->type, cstr("int"))) { | 595 | if (strset_lookup(&compiler->integer_types, node->type)) { |
353 | op = OP_SUB; | 596 | op = OP_SUB; |
354 | opi = OP_SUBI; | 597 | opi = OP_SUBI; |
355 | } else if (str_eq(node->type, cstr("f64"))) { | 598 | } else if (strset_lookup(&compiler->float_types, node->type)) { |
356 | op = OP_SUBF; | 599 | op = OP_SUBF; |
357 | opi = OP_SUBFI; | 600 | opi = OP_SUBFI; |
358 | } | 601 | } |
359 | } break; | 602 | } break; |
360 | case NODE_MUL: { | 603 | case NODE_MUL: { |
361 | if (str_eq(node->type, cstr("int"))) { | 604 | if (strset_lookup(&compiler->integer_types, node->type)) { |
362 | op = OP_MUL; | 605 | op = OP_MUL; |
363 | opi = OP_MULI; | 606 | opi = OP_MULI; |
364 | } else if (str_eq(node->type, cstr("f64"))) { | 607 | } else if (strset_lookup(&compiler->float_types, node->type)) { |
365 | op = OP_MULF; | 608 | op = OP_MULF; |
366 | opi = OP_MULFI; | 609 | opi = OP_MULFI; |
367 | } | 610 | } |
368 | } break; | 611 | } break; |
369 | case NODE_DIV: { | 612 | case NODE_DIV: { |
370 | if (str_eq(node->type, cstr("int"))) { | 613 | if (strset_lookup(&compiler->integer_types, node->type)) { |
371 | op = OP_DIV; | 614 | op = OP_DIV; |
372 | opi = OP_DIVI; | 615 | opi = OP_DIVI; |
373 | } else if (str_eq(node->type, cstr("f64"))) { | 616 | } else if (strset_lookup(&compiler->float_types, node->type)) { |
374 | op = OP_DIVF; | 617 | op = OP_DIVF; |
375 | opi = OP_DIVFI; | 618 | opi = OP_DIVFI; |
376 | } | 619 | } |
377 | } break; | 620 | } break; |
378 | case NODE_MOD: { | 621 | case NODE_MOD: { |
379 | if (str_eq(node->type, cstr("int"))) { | 622 | if (strset_lookup(&compiler->integer_types, node->type)) { |
380 | op = OP_MOD; | 623 | op = OP_MOD; |
381 | opi = OP_MODI; | 624 | opi = OP_MODI; |
382 | } else if (str_eq(node->type, cstr("f64"))) { | 625 | } else if (strset_lookup(&compiler->float_types, node->type)) { |
383 | op = OP_MODF; | 626 | op = OP_MODF; |
384 | opi = OP_MODFI; | 627 | opi = OP_MODFI; |
385 | } | 628 | } |
@@ -409,19 +652,15 @@ compile_binary(Chunk *chunk, Node *node) { | |||
409 | op = OP_GE; | 652 | op = OP_GE; |
410 | opi = OP_GEI; | 653 | opi = OP_GEI; |
411 | } break; | 654 | } break; |
412 | case NODE_AND: { | ||
413 | op = OP_AND; | ||
414 | opi = OP_ANDI; | ||
415 | } break; | ||
416 | case NODE_OR: { | ||
417 | op = OP_OR; | ||
418 | opi = OP_ORI; | ||
419 | } break; | ||
420 | // Bitwise. | 655 | // Bitwise. |
421 | case NODE_BITOR: { | 656 | case NODE_BITOR: { |
422 | op = OP_BITOR; | 657 | op = OP_BITOR; |
423 | opi = OP_BITORI; | 658 | opi = OP_BITORI; |
424 | } break; | 659 | } break; |
660 | case NODE_BITXOR: { | ||
661 | op = OP_BITXOR; | ||
662 | opi = OP_BITXORI; | ||
663 | } break; | ||
425 | case NODE_BITAND: { | 664 | case NODE_BITAND: { |
426 | op = OP_BITAND; | 665 | op = OP_BITAND; |
427 | opi = OP_BITANDI; | 666 | opi = OP_BITANDI; |
@@ -436,19 +675,20 @@ compile_binary(Chunk *chunk, Node *node) { | |||
436 | } break; | 675 | } break; |
437 | default: break; | 676 | default: break; |
438 | } | 677 | } |
439 | CompResult comp_a = compile_expr(chunk, node->left); | 678 | CompResult comp_a = compile_expr(compiler, chunk, node->binary.left); |
440 | CompResult comp_b = compile_expr(chunk, node->right); | 679 | CompResult comp_b = compile_expr(compiler, chunk, node->binary.right); |
441 | sz reg_a; | 680 | sz reg_a; |
442 | sz reg_b; | 681 | sz reg_b; |
443 | switch (comp_a.type) { | 682 | switch (comp_a.type) { |
444 | case COMP_CONST: { | 683 | case COMP_CONST: { |
445 | reg_a = chunk->reg_idx++; | 684 | reg_a = chunk->reg_idx++; |
446 | EMIT_OP(ldop, reg_a, comp_a.idx, 0, node, chunk); | 685 | emit_op(ldop, reg_a, comp_a.idx, 0, node, chunk); |
447 | } break; | 686 | } break; |
448 | case COMP_REG: { | 687 | case COMP_REG: { |
449 | reg_a = comp_a.idx; | 688 | reg_a = comp_a.idx; |
450 | } break; | 689 | } break; |
451 | default: { | 690 | default: { |
691 | emit_compile_err(compiler, chunk, node); | ||
452 | return (CompResult){.type = COMP_ERR}; | 692 | return (CompResult){.type = COMP_ERR}; |
453 | } break; | 693 | } break; |
454 | } | 694 | } |
@@ -461,16 +701,99 @@ compile_binary(Chunk *chunk, Node *node) { | |||
461 | reg_b = comp_b.idx; | 701 | reg_b = comp_b.idx; |
462 | } break; | 702 | } break; |
463 | default: { | 703 | default: { |
704 | emit_compile_err(compiler, chunk, node); | ||
464 | return (CompResult){.type = COMP_ERR}; | 705 | return (CompResult){.type = COMP_ERR}; |
465 | } break; | 706 | } break; |
466 | } | 707 | } |
467 | sz reg_dst = chunk->reg_idx++; // Better for optimization | 708 | sz reg_dst = chunk->reg_idx++; // Better for optimization |
468 | EMIT_OP(op, reg_dst, reg_a, reg_b, node, chunk); | 709 | emit_op(op, reg_dst, reg_a, reg_b, node, chunk); |
710 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | ||
711 | } | ||
712 | |||
713 | CompResult | ||
714 | compile_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 | |||
469 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | 792 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; |
470 | } | 793 | } |
471 | 794 | ||
472 | CompResult | 795 | CompResult |
473 | compile_unary(Chunk *chunk, Node *node) { | 796 | compile_unary(Compiler *compiler, Chunk *chunk, Node *node) { |
474 | OpCode op = OP_HALT; | 797 | OpCode op = OP_HALT; |
475 | OpCode opi = OP_HALT; | 798 | OpCode opi = OP_HALT; |
476 | switch (node->kind) { | 799 | switch (node->kind) { |
@@ -484,7 +807,7 @@ compile_unary(Chunk *chunk, Node *node) { | |||
484 | } break; | 807 | } break; |
485 | default: break; | 808 | default: break; |
486 | } | 809 | } |
487 | CompResult comp_a = compile_expr(chunk, node->left); | 810 | CompResult comp_a = compile_expr(compiler, chunk, node->binary.left); |
488 | sz reg_a; | 811 | sz reg_a; |
489 | switch (comp_a.type) { | 812 | switch (comp_a.type) { |
490 | case COMP_CONST: { | 813 | case COMP_CONST: { |
@@ -495,42 +818,18 @@ compile_unary(Chunk *chunk, Node *node) { | |||
495 | reg_a = comp_a.idx; | 818 | reg_a = comp_a.idx; |
496 | } break; | 819 | } break; |
497 | default: { | 820 | default: { |
821 | emit_compile_err(compiler, chunk, node); | ||
498 | return (CompResult){.type = COMP_ERR}; | 822 | return (CompResult){.type = COMP_ERR}; |
499 | } break; | 823 | } break; |
500 | } | 824 | } |
501 | sz reg_dst = chunk->reg_idx++; | 825 | sz reg_dst = chunk->reg_idx++; |
502 | EMIT_OP(op, reg_dst, reg_a, 0, node, chunk); | 826 | emit_op(op, reg_dst, reg_a, 0, node, chunk); |
503 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | 827 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; |
504 | } | 828 | } |
505 | 829 | ||
506 | sz | ||
507 | add_constant(Chunk *chunk, sz value) { | ||
508 | IntIntMap *map = intintmap_lookup(&chunk->intmap, value); | ||
509 | // Make sure we don't have duplicated constants. | ||
510 | if (!map) { | ||
511 | map = intintmap_insert(&chunk->intmap, value, chunk->const_idx++, | ||
512 | chunk->storage); | ||
513 | Constant c = (Constant){.i = value}; | ||
514 | array_push(chunk->constants, c, chunk->storage); | ||
515 | } | ||
516 | return map->val; | ||
517 | } | ||
518 | |||
519 | sz | ||
520 | add_string(Chunk *chunk, Str string) { | ||
521 | // Make sure we don't have duplicated string. | ||
522 | StrIntMap *map = strintmap_lookup(&chunk->strmap, string); | ||
523 | if (!map) { | ||
524 | map = strintmap_insert(&chunk->strmap, string, chunk->str_idx++, | ||
525 | chunk->storage); | ||
526 | array_push(chunk->strings, string, chunk->storage); | ||
527 | } | ||
528 | return map->val; | ||
529 | } | ||
530 | |||
531 | CompResult | 830 | CompResult |
532 | compile_if(Chunk *chunk, Node *node) { | 831 | compile_if(Compiler *compiler, Chunk *chunk, Node *node) { |
533 | CompResult cond = compile_expr(chunk, node->cond_if); | 832 | CompResult cond = compile_expr(compiler, chunk, node->ifelse.cond); |
534 | OpCode jmpop; | 833 | OpCode jmpop; |
535 | switch (cond.type) { | 834 | switch (cond.type) { |
536 | case COMP_CONST: { | 835 | case COMP_CONST: { |
@@ -540,29 +839,35 @@ compile_if(Chunk *chunk, Node *node) { | |||
540 | jmpop = OP_JMPF; | 839 | jmpop = OP_JMPF; |
541 | } break; | 840 | } break; |
542 | default: { | 841 | default: { |
842 | emit_compile_err(compiler, chunk, node); | ||
543 | return (CompResult){.type = COMP_ERR}; | 843 | return (CompResult){.type = COMP_ERR}; |
544 | } break; | 844 | } break; |
545 | } | 845 | } |
546 | 846 | ||
547 | if (!str_eq(node->type, cstr("nil"))) { | 847 | if (!str_eq(node->type, cstr("nil")) && |
848 | !str_has_prefix(node->type, cstr("ret:")) && | ||
849 | !str_has_prefix(node->type, cstr("flow:"))) { | ||
548 | sz reg_dst = chunk->reg_idx++; | 850 | sz reg_dst = chunk->reg_idx++; |
549 | 851 | ||
550 | // Jump to the `false` branch. | 852 | // Jump to the `false` branch. |
551 | sz lab0 = chunk->labels_idx++; | 853 | sz lab0 = chunk->labels_idx++; |
552 | EMIT_OP(jmpop, lab0, cond.idx, 0, node->cond_if, chunk); | 854 | emit_op(jmpop, lab0, cond.idx, 0, node->ifelse.cond, chunk); |
553 | 855 | ||
554 | // Condition is true. | 856 | // Condition is true. |
555 | CompResult then_expr = compile_expr(chunk, node->cond_expr); | 857 | CompResult then_expr = |
858 | compile_expr(compiler, chunk, node->ifelse.expr_true); | ||
556 | switch (then_expr.type) { | 859 | switch (then_expr.type) { |
557 | case COMP_CONST: { | 860 | case COMP_CONST: { |
558 | EMIT_OP(OP_LD64K, reg_dst, then_expr.idx, 0, node->cond_if, | 861 | emit_op(OP_LDCONST, reg_dst, then_expr.idx, 0, |
559 | chunk); | 862 | node->ifelse.cond, chunk); |
560 | } break; | 863 | } break; |
561 | case COMP_REG: { | 864 | case COMP_REG: { |
562 | 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, |
563 | chunk); | 866 | chunk); |
564 | } break; | 867 | } break; |
868 | case COMP_RET: break; | ||
565 | default: { | 869 | default: { |
870 | emit_compile_err(compiler, chunk, node); | ||
566 | return (CompResult){.type = COMP_ERR}; | 871 | return (CompResult){.type = COMP_ERR}; |
567 | } break; | 872 | } break; |
568 | } | 873 | } |
@@ -570,20 +875,23 @@ compile_if(Chunk *chunk, Node *node) { | |||
570 | // Jump to the end of the expression. | 875 | // Jump to the end of the expression. |
571 | sz pos0 = array_size(chunk->code); | 876 | sz pos0 = array_size(chunk->code); |
572 | sz lab1 = chunk->labels_idx++; | 877 | sz lab1 = chunk->labels_idx++; |
573 | EMIT_OP(OP_JMP, lab1, 0, 0, node->cond_else, chunk); | 878 | emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk); |
574 | 879 | ||
575 | // Else expression. | 880 | // Else expression. |
576 | CompResult else_expr = compile_expr(chunk, node->cond_else); | 881 | CompResult else_expr = |
882 | compile_expr(compiler, chunk, node->ifelse.expr_else); | ||
577 | switch (else_expr.type) { | 883 | switch (else_expr.type) { |
578 | case COMP_CONST: { | 884 | case COMP_CONST: { |
579 | EMIT_OP(OP_LD64K, reg_dst, else_expr.idx, 0, node->cond_else, | 885 | emit_op(OP_LDCONST, reg_dst, else_expr.idx, 0, |
580 | chunk); | 886 | node->ifelse.expr_else, chunk); |
581 | } break; | 887 | } break; |
582 | case COMP_REG: { | 888 | case COMP_REG: { |
583 | EMIT_OP(OP_MOV64, reg_dst, else_expr.idx, 0, node->cond_else, | 889 | emit_op(OP_MOV64, reg_dst, else_expr.idx, 0, |
584 | chunk); | 890 | node->ifelse.expr_else, chunk); |
585 | } break; | 891 | } break; |
892 | case COMP_RET: break; | ||
586 | default: { | 893 | default: { |
894 | emit_compile_err(compiler, chunk, node); | ||
587 | return (CompResult){.type = COMP_ERR}; | 895 | return (CompResult){.type = COMP_ERR}; |
588 | } break; | 896 | } break; |
589 | } | 897 | } |
@@ -592,47 +900,44 @@ compile_if(Chunk *chunk, Node *node) { | |||
592 | // Update labels. | 900 | // Update labels. |
593 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage); | 901 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage); |
594 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); | 902 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); |
595 | intintmap_insert(&chunk->labels_rev, pos0 + 1, lab0, chunk->storage); | ||
596 | intintmap_insert(&chunk->labels_rev, pos1, lab1, chunk->storage); | ||
597 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | 903 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; |
598 | } | 904 | } |
599 | 905 | ||
600 | // Jump to the `false` branch. | 906 | // Jump to the `false` branch. |
601 | sz lab0 = chunk->labels_idx++; | 907 | sz lab0 = chunk->labels_idx++; |
602 | EMIT_OP(jmpop, lab0, cond.idx, 0, node->cond_if, chunk); | 908 | emit_op(jmpop, lab0, cond.idx, 0, node->ifelse.cond, chunk); |
603 | 909 | ||
604 | // Condition is true. | 910 | // Condition is true. |
605 | compile_expr(chunk, node->cond_expr); | 911 | compile_expr(compiler, chunk, node->ifelse.expr_true); |
606 | 912 | ||
607 | // Jump to the end of the expression. | 913 | // Jump to the end of the expression. |
608 | sz pos0 = array_size(chunk->code); | 914 | sz pos0 = array_size(chunk->code); |
609 | sz lab1 = chunk->labels_idx++; | 915 | sz lab1 = chunk->labels_idx++; |
610 | EMIT_OP(OP_JMP, lab1, 0, 0, node->cond_else, chunk); | 916 | emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk); |
611 | 917 | ||
612 | // Else expression. | 918 | // Else expression. |
613 | if (node->cond_else) { | 919 | if (node->ifelse.expr_else) { |
614 | compile_expr(chunk, node->cond_else); | 920 | compile_expr(compiler, chunk, node->ifelse.expr_else); |
615 | } | 921 | } |
616 | sz pos1 = array_size(chunk->code); | 922 | sz pos1 = array_size(chunk->code); |
617 | 923 | ||
618 | // Update labels. | 924 | // Update labels. |
619 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage); | 925 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage); |
620 | intintmap_insert(&chunk->labels_rev, pos0 + 1, lab0, chunk->storage); | ||
621 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); | 926 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); |
622 | intintmap_insert(&chunk->labels_rev, pos1, lab1, chunk->storage); | ||
623 | 927 | ||
624 | return (CompResult){.type = COMP_NIL}; | 928 | return (CompResult){.type = COMP_NIL}; |
625 | } | 929 | } |
626 | 930 | ||
627 | CompResult | 931 | CompResult |
628 | compile_cond(Chunk *chunk, Node *node) { | 932 | compile_cond(Compiler *compiler, Chunk *chunk, Node *node) { |
629 | if (str_eq(node->type, cstr("nil"))) { | 933 | if (str_eq(node->type, cstr("nil"))) { |
630 | sz lab1 = chunk->labels_idx++; | 934 | sz lab1 = chunk->labels_idx++; |
631 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 935 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
632 | // condition = expression | 936 | // condition = expression |
633 | Node *expr = node->match_cases[i]; | 937 | Node *expr = node->match.cases[i]; |
634 | if (expr->case_value) { | 938 | if (expr->case_entry.cond) { |
635 | CompResult cond = compile_expr(chunk, expr->case_value); | 939 | CompResult cond = |
940 | compile_expr(compiler, chunk, expr->case_entry.cond); | ||
636 | OpCode jmpop; | 941 | OpCode jmpop; |
637 | switch (cond.type) { | 942 | switch (cond.type) { |
638 | case COMP_CONST: { | 943 | case COMP_CONST: { |
@@ -642,42 +947,41 @@ compile_cond(Chunk *chunk, Node *node) { | |||
642 | jmpop = OP_JMPF; | 947 | jmpop = OP_JMPF; |
643 | } break; | 948 | } break; |
644 | default: { | 949 | default: { |
950 | emit_compile_err(compiler, chunk, node); | ||
645 | return (CompResult){.type = COMP_ERR}; | 951 | return (CompResult){.type = COMP_ERR}; |
646 | } break; | 952 | } break; |
647 | } | 953 | } |
648 | // Jump to the `next` branch. | 954 | // Jump to the `next` branch. |
649 | sz lab0 = chunk->labels_idx++; | 955 | sz lab0 = chunk->labels_idx++; |
650 | EMIT_OP(jmpop, lab0, cond.idx, 0, expr->case_expr, chunk); | 956 | emit_op(jmpop, lab0, cond.idx, 0, expr->case_entry.expr, chunk); |
651 | 957 | ||
652 | // Condition is true. | 958 | // Condition is true. |
653 | compile_expr(chunk, expr->case_expr); | 959 | compile_expr(compiler, chunk, expr->case_entry.expr); |
654 | if (i != array_size(node->match_cases) - 1) { | 960 | if (i != array_size(node->match.cases) - 1) { |
655 | // Jump to the end of the expression. | 961 | // Jump to the end of the expression. |
656 | sz pos0 = array_size(chunk->code); | 962 | sz pos0 = array_size(chunk->code); |
657 | EMIT_OP(OP_JMP, lab1, 0, 0, node->cond_else, chunk); | 963 | emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk); |
658 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, | 964 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, |
659 | chunk->storage); | 965 | chunk->storage); |
660 | intintmap_insert(&chunk->labels_rev, pos0 + 1, lab0, | ||
661 | chunk->storage); | ||
662 | } | 966 | } |
663 | } else { | 967 | } else { |
664 | compile_expr(chunk, expr->case_expr); | 968 | compile_expr(compiler, chunk, expr->case_entry.expr); |
665 | break; | 969 | break; |
666 | } | 970 | } |
667 | } | 971 | } |
668 | sz pos1 = array_size(chunk->code); | 972 | sz pos1 = array_size(chunk->code); |
669 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); | 973 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); |
670 | intintmap_insert(&chunk->labels_rev, pos1, lab1, chunk->storage); | ||
671 | return (CompResult){.type = COMP_NIL}; | 974 | return (CompResult){.type = COMP_NIL}; |
672 | } | 975 | } |
673 | 976 | ||
674 | sz reg_dst = chunk->reg_idx++; | 977 | sz reg_dst = chunk->reg_idx++; |
675 | sz lab1 = chunk->labels_idx++; | 978 | sz lab1 = chunk->labels_idx++; |
676 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 979 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
677 | // condition = expression | 980 | // condition = expression |
678 | Node *expr = node->match_cases[i]; | 981 | Node *expr = node->match.cases[i]; |
679 | if (expr->case_value) { | 982 | if (expr->case_entry.cond) { |
680 | CompResult cond = compile_expr(chunk, expr->case_value); | 983 | CompResult cond = |
984 | compile_expr(compiler, chunk, expr->case_entry.cond); | ||
681 | OpCode jmpop; | 985 | OpCode jmpop; |
682 | switch (cond.type) { | 986 | switch (cond.type) { |
683 | case COMP_CONST: { | 987 | case COMP_CONST: { |
@@ -687,49 +991,54 @@ compile_cond(Chunk *chunk, Node *node) { | |||
687 | jmpop = OP_JMPF; | 991 | jmpop = OP_JMPF; |
688 | } break; | 992 | } break; |
689 | default: { | 993 | default: { |
994 | emit_compile_err(compiler, chunk, node); | ||
690 | return (CompResult){.type = COMP_ERR}; | 995 | return (CompResult){.type = COMP_ERR}; |
691 | } break; | 996 | } break; |
692 | } | 997 | } |
693 | // Jump to the `next` branch. | 998 | // Jump to the `next` branch. |
694 | sz lab0 = chunk->labels_idx++; | 999 | sz lab0 = chunk->labels_idx++; |
695 | EMIT_OP(jmpop, lab0, cond.idx, 0, expr->case_expr, chunk); | 1000 | emit_op(jmpop, lab0, cond.idx, 0, expr->case_entry.expr, chunk); |
696 | 1001 | ||
697 | // Condition is true. | 1002 | // Condition is true. |
698 | CompResult then_expr = compile_expr(chunk, expr->case_expr); | 1003 | CompResult then_expr = |
1004 | compile_expr(compiler, chunk, expr->case_entry.expr); | ||
699 | switch (then_expr.type) { | 1005 | switch (then_expr.type) { |
700 | case COMP_CONST: { | 1006 | case COMP_CONST: { |
701 | EMIT_OP(OP_LD64K, reg_dst, then_expr.idx, 0, | 1007 | emit_op(OP_LDCONST, reg_dst, then_expr.idx, 0, |
702 | expr->case_expr, chunk); | 1008 | expr->case_entry.expr, chunk); |
703 | } break; | 1009 | } break; |
704 | case COMP_REG: { | 1010 | case COMP_REG: { |
705 | EMIT_OP(OP_MOV64, reg_dst, then_expr.idx, 0, | 1011 | emit_op(OP_MOV64, reg_dst, then_expr.idx, 0, |
706 | expr->case_expr, chunk); | 1012 | expr->case_entry.expr, chunk); |
707 | } break; | 1013 | } break; |
1014 | case COMP_RET: break; | ||
708 | default: { | 1015 | default: { |
1016 | emit_compile_err(compiler, chunk, node); | ||
709 | return (CompResult){.type = COMP_ERR}; | 1017 | return (CompResult){.type = COMP_ERR}; |
710 | } break; | 1018 | } break; |
711 | } | 1019 | } |
712 | if (i != array_size(node->match_cases) - 1) { | 1020 | if (i != array_size(node->match.cases) - 1) { |
713 | // Jump to the end of the expression. | 1021 | // Jump to the end of the expression. |
714 | sz pos0 = array_size(chunk->code); | 1022 | sz pos0 = array_size(chunk->code); |
715 | EMIT_OP(OP_JMP, lab1, 0, 0, node->cond_else, chunk); | 1023 | emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk); |
716 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, | 1024 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, |
717 | chunk->storage); | 1025 | chunk->storage); |
718 | intintmap_insert(&chunk->labels_rev, pos0 + 1, lab0, | ||
719 | chunk->storage); | ||
720 | } | 1026 | } |
721 | } else { | 1027 | } else { |
722 | CompResult then_expr = compile_expr(chunk, expr->case_expr); | 1028 | CompResult then_expr = |
1029 | compile_expr(compiler, chunk, expr->case_entry.expr); | ||
723 | switch (then_expr.type) { | 1030 | switch (then_expr.type) { |
724 | case COMP_CONST: { | 1031 | case COMP_CONST: { |
725 | EMIT_OP(OP_LD64K, reg_dst, then_expr.idx, 0, | 1032 | emit_op(OP_LDCONST, reg_dst, then_expr.idx, 0, |
726 | expr->case_expr, chunk); | 1033 | expr->case_entry.expr, chunk); |
727 | } break; | 1034 | } break; |
728 | case COMP_REG: { | 1035 | case COMP_REG: { |
729 | EMIT_OP(OP_MOV64, reg_dst, then_expr.idx, 0, | 1036 | emit_op(OP_MOV64, reg_dst, then_expr.idx, 0, |
730 | expr->case_expr, chunk); | 1037 | expr->case_entry.expr, chunk); |
731 | } break; | 1038 | } break; |
1039 | case COMP_RET: break; | ||
732 | default: { | 1040 | default: { |
1041 | emit_compile_err(compiler, chunk, node); | ||
733 | return (CompResult){.type = COMP_ERR}; | 1042 | return (CompResult){.type = COMP_ERR}; |
734 | } break; | 1043 | } break; |
735 | } | 1044 | } |
@@ -738,14 +1047,27 @@ compile_cond(Chunk *chunk, Node *node) { | |||
738 | } | 1047 | } |
739 | sz pos1 = array_size(chunk->code); | 1048 | sz pos1 = array_size(chunk->code); |
740 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); | 1049 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); |
741 | intintmap_insert(&chunk->labels_rev, pos1, lab1, chunk->storage); | ||
742 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | 1050 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; |
743 | } | 1051 | } |
744 | 1052 | ||
745 | CompResult | 1053 | CompResult |
746 | compile_while(Chunk *chunk, Node *node) { | 1054 | compile_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 | |||
1059 | CompResult | ||
1060 | compile_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 | |||
1065 | CompResult | ||
1066 | compile_while(Compiler *compiler, Chunk *chunk, Node *node) { | ||
1067 | sz lab0 = chunk->labels_idx++; | ||
1068 | sz lab1 = chunk->labels_idx++; | ||
747 | sz pos1 = array_size(chunk->code); | 1069 | sz pos1 = array_size(chunk->code); |
748 | CompResult cond = compile_expr(chunk, node->while_cond); | 1070 | CompResult cond = compile_expr(compiler, chunk, node->loop.cond); |
749 | OpCode jmpop; | 1071 | OpCode jmpop; |
750 | switch (cond.type) { | 1072 | switch (cond.type) { |
751 | case COMP_CONST: { | 1073 | case COMP_CONST: { |
@@ -755,69 +1077,164 @@ compile_while(Chunk *chunk, Node *node) { | |||
755 | jmpop = OP_JMPF; | 1077 | jmpop = OP_JMPF; |
756 | } break; | 1078 | } break; |
757 | default: { | 1079 | default: { |
1080 | emit_compile_err(compiler, chunk, node); | ||
758 | return (CompResult){.type = COMP_ERR}; | 1081 | return (CompResult){.type = COMP_ERR}; |
759 | } break; | 1082 | } break; |
760 | } | 1083 | } |
761 | 1084 | ||
762 | // Jump to the `end of the loop` branch. | 1085 | // Jump to the `end of the loop` branch. |
763 | sz lab0 = chunk->labels_idx++; | 1086 | emit_op(jmpop, lab0, cond.idx, 0, node->loop.cond, chunk); |
764 | EMIT_OP(jmpop, lab0, cond.idx, 0, node->while_cond, chunk); | ||
765 | 1087 | ||
766 | // Condition is true. | 1088 | // Condition is true. |
767 | compile_expr(chunk, node->while_expr); | 1089 | compiler->lab_pre = lab1; |
1090 | compiler->lab_post = lab0; | ||
1091 | compile_expr(compiler, chunk, node->loop.expr); | ||
768 | sz pos0 = array_size(chunk->code); | 1092 | sz pos0 = array_size(chunk->code); |
769 | sz lab1 = chunk->labels_idx++; | 1093 | emit_op(OP_JMP, lab1, 0, 0, node, chunk); |
770 | EMIT_OP(OP_JMP, lab1, 0, 0, node, chunk); | ||
771 | 1094 | ||
772 | // Update labels. | 1095 | // Update labels. |
773 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage); | 1096 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage); |
774 | intintmap_insert(&chunk->labels_rev, pos0 + 1, lab0, chunk->storage); | ||
775 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); | 1097 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); |
776 | intintmap_insert(&chunk->labels_rev, pos1, lab1, chunk->storage); | ||
777 | 1098 | ||
778 | // Return. | 1099 | // Return. |
779 | return (CompResult){.type = COMP_NIL}; | 1100 | return (CompResult){.type = COMP_NIL}; |
780 | } | 1101 | } |
781 | 1102 | ||
782 | CompResult | 1103 | CompResult |
783 | compile_funcall(Chunk *chunk, Node *node) { | 1104 | compile_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 | |||
1141 | CompResult | ||
1142 | compile_funcall(Compiler *compiler, Chunk *chunk, Node *node) { | ||
784 | Str name = node->value.str; | 1143 | Str name = node->value.str; |
785 | 1144 | ||
786 | // Builtins. | 1145 | // Builtins. |
787 | if (str_eq(name, cstr("print")) || str_eq(name, cstr("println"))) { | 1146 | if (str_eq(name, cstr("print")) || str_eq(name, cstr("println"))) { |
788 | for (sz i = 0; i < array_size(node->elements); i++) { | 1147 | for (sz i = 0; i < array_size(node->elements); i++) { |
789 | Node *expr = node->elements[i]; | 1148 | Node *expr = node->elements[i]; |
790 | CompResult result = compile_expr(chunk, expr); | 1149 | Str type_name = expr->type; |
791 | if (str_eq(expr->type, cstr("int"))) { | 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)) { | ||
792 | switch (result.type) { | 1176 | switch (result.type) { |
793 | case COMP_CONST: { | 1177 | case COMP_CONST: { |
794 | EMIT_OP(OP_PRINTS64I, result.idx, 0, 0, expr, chunk); | 1178 | emit_sized_op(size, OP_PRINTU64I, OP_PRINTU32I, |
1179 | OP_PRINTU16I, OP_PRINTU8I, result.idx, 0, | ||
1180 | 0, expr, chunk); | ||
795 | } break; | 1181 | } break; |
796 | case COMP_REG: { | 1182 | case COMP_REG: { |
797 | EMIT_OP(OP_PRINTS64, result.idx, 0, 0, expr, chunk); | 1183 | emit_sized_op(size, OP_PRINTU64, OP_PRINTU32, |
1184 | OP_PRINTU16, OP_PRINTU8, result.idx, 0, 0, | ||
1185 | expr, chunk); | ||
798 | } break; | 1186 | } break; |
799 | default: { | 1187 | default: { |
1188 | emit_compile_err(compiler, chunk, node); | ||
800 | return (CompResult){.type = COMP_ERR}; | 1189 | return (CompResult){.type = COMP_ERR}; |
801 | } break; | 1190 | } break; |
802 | } | 1191 | } |
803 | } else if (str_eq(expr->type, cstr("f64"))) { | 1192 | } else if (strset_lookup(&compiler->float_types, type)) { |
804 | switch (result.type) { | 1193 | switch (result.type) { |
805 | case COMP_CONST: { | 1194 | case COMP_CONST: { |
806 | EMIT_OP(OP_PRINTF64I, result.idx, 0, 0, expr, chunk); | 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 | } | ||
807 | } break; | 1202 | } break; |
808 | case COMP_REG: { | 1203 | case COMP_REG: { |
809 | EMIT_OP(OP_PRINTF64, result.idx, 0, 0, expr, chunk); | 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 | } | ||
810 | } break; | 1209 | } break; |
811 | default: { | 1210 | default: { |
1211 | emit_compile_err(compiler, chunk, node); | ||
812 | return (CompResult){.type = COMP_ERR}; | 1212 | return (CompResult){.type = COMP_ERR}; |
813 | } break; | 1213 | } break; |
814 | } | 1214 | } |
815 | } else if (str_eq(expr->type, cstr("str"))) { | 1215 | } else if (str_eq(type, cstr("Str"))) { |
816 | switch (result.type) { | 1216 | switch (result.type) { |
817 | case COMP_STRING: { | 1217 | case COMP_STRING: { |
818 | EMIT_OP(OP_PRINTSTR, result.idx, 0, 0, expr, chunk); | 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); | ||
819 | } break; | 1222 | } break; |
820 | default: { | 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); | ||
821 | return (CompResult){.type = COMP_ERR}; | 1238 | return (CompResult){.type = COMP_ERR}; |
822 | } break; | 1239 | } break; |
823 | } | 1240 | } |
@@ -825,75 +1242,217 @@ compile_funcall(Chunk *chunk, Node *node) { | |||
825 | } | 1242 | } |
826 | if (str_eq(name, cstr("println"))) { | 1243 | if (str_eq(name, cstr("println"))) { |
827 | sz idx = add_string(chunk, cstr("\n")); | 1244 | sz idx = add_string(chunk, cstr("\n")); |
828 | EMIT_OP(OP_PRINTSTR, idx, 0, 0, node, chunk); | 1245 | emit_op(OP_PRINTSTRI, idx, 0, 0, node, chunk); |
829 | } | 1246 | } |
830 | return (CompResult){.type = COMP_NIL}; | 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); | ||
1282 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | ||
831 | } | 1283 | } |
832 | 1284 | ||
833 | // TODO: need to find this on the parents, not just in the current chunk. | 1285 | FunctionMap *map = |
834 | FunctionMap *map = funcmap_lookup(&chunk->funmap, node->unique_name); | 1286 | funcmap_lookup(&compiler->main_chunk.funmap, node->unique_name); |
835 | if (!map) { | 1287 | if (!map) { |
836 | println("how come?"); | 1288 | emit_compile_err(compiler, chunk, node); |
1289 | return (CompResult){.type = COMP_ERR}; | ||
837 | } | 1290 | } |
838 | Function fun = map->val; | 1291 | Function fun = map->val; |
839 | 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 | |||
840 | // Reserve space for the return value if needed. | 1354 | // Reserve space for the return value if needed. |
841 | if (fun.return_arity > 0) { | 1355 | if (fun.return_arity > 0) { |
842 | // Put the return data into a register | 1356 | // Put the return data into a register |
843 | sz ret_size = add_constant(chunk, 8); | 1357 | sz ret_size = add_constant(chunk, 8); |
844 | EMIT_OP(OP_RESERVE, ret_size, 0, 0, node, chunk); | 1358 | emit_op(OP_RESERVE, ret_size, 0, 0, node, chunk); |
845 | } | 1359 | } |
846 | 1360 | ||
847 | // Send parameters to the stack. | 1361 | // Send parameters to the stack. |
848 | for (sz i = 0; i < array_size(node->elements); i++) { | 1362 | for (sz i = 0; i < array_size(node->elements); i++) { |
849 | Node *expr = node->elements[i]; | 1363 | Node *expr = node->elements[i]; |
850 | CompResult result = compile_expr(chunk, expr); | 1364 | CompResult result = compile_expr(compiler, chunk, expr); |
851 | // TODO: Assuming all values are 8 bytes... again. | 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; | ||
852 | switch (result.type) { | 1372 | switch (result.type) { |
853 | case COMP_CONST: { | 1373 | case COMP_CONST: { |
854 | EMIT_OP(OP_PUSHI, result.idx, 0, 0, expr, chunk); | 1374 | emit_op(OP_PUSHI, result.idx, 0, 0, expr, chunk); |
855 | } break; | 1375 | } break; |
856 | case COMP_REG: { | 1376 | case COMP_REG: { |
857 | EMIT_OP(OP_PUSH, result.idx, 0, 0, expr, chunk); | 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); | ||
858 | } break; | 1407 | } break; |
859 | default: { | 1408 | default: { |
1409 | emit_compile_err(compiler, chunk, node); | ||
860 | return (CompResult){.type = COMP_ERR}; | 1410 | return (CompResult){.type = COMP_ERR}; |
861 | } break; | 1411 | } break; |
862 | } | 1412 | } |
863 | } | 1413 | } |
864 | 1414 | ||
865 | // // TODO: prologue (how much space do we actually need)? we need the | 1415 | emit_op(OP_CALL, fun.index, 0, 0, node, chunk); |
866 | // symbol | ||
867 | // // table, arity and return parameters boy. | ||
868 | // // FIXME: assuming all values are 8 bytes for now... | ||
869 | // sz alloc_size = (fun.param_arity + fun.return_arity) * 8; | ||
870 | // sz alloc_const = add_constant(chunk, alloc_size); | ||
871 | // if (alloc_size > 0) { | ||
872 | // // EMIT_OP(OP_RESERVE, alloc_const, 0, 0, node, chunk); | ||
873 | // } | ||
874 | |||
875 | // // println("FUNCALL: unique name: %s", node->unique_name); | ||
876 | // // println("FUN: param_arity: %d", fun.param_arity); | ||
877 | // // println("FUN: return_arity: %d", fun.return_arity); | ||
878 | EMIT_OP(OP_CALL, fun.index, 0, 0, node, chunk); | ||
879 | 1416 | ||
880 | // Only one return parameter for now. | 1417 | // Only one return parameter for now. |
881 | if (fun.return_arity > 0) { | 1418 | if (fun.return_arity > 0) { |
882 | // Put the return data into a register | 1419 | // Put the return data into a register |
883 | sz reg_dst = chunk->reg_idx++; | 1420 | sz reg_dst = chunk->reg_idx++; |
884 | EMIT_OP(OP_POP, reg_dst, 0, 0, node, chunk); | 1421 | emit_op(OP_POP, reg_dst, 0, 0, node, chunk); |
885 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | 1422 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; |
886 | } | 1423 | } |
887 | 1424 | ||
888 | // if (alloc_size > 0) { | ||
889 | // // EMIT_OP(OP_POP, alloc_const, 0, 0, node, chunk); | ||
890 | // } | ||
891 | // TODO: epilogue (how much space do we actually need)? we need to remove | ||
892 | // the AR data here after using it. If we only have one return parameter we | ||
893 | // can put it in a register but what if that's not actually the case? | ||
894 | return (CompResult){.type = COMP_NIL}; | 1425 | return (CompResult){.type = COMP_NIL}; |
895 | } | 1426 | } |
896 | 1427 | ||
1428 | CompResult | ||
1429 | compile_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 | |||
897 | Chunk * | 1456 | Chunk * |
898 | chunk_alloc(Chunk *parent) { | 1457 | chunk_alloc(Chunk *parent) { |
899 | static sz chunk_idx = 1; | 1458 | static sz chunk_idx = 1; |
@@ -905,50 +1464,451 @@ chunk_alloc(Chunk *parent) { | |||
905 | return chunk; | 1464 | return chunk; |
906 | } | 1465 | } |
907 | 1466 | ||
908 | CompResult | 1467 | void |
909 | compile_function(Chunk *chunk, Node *node) { | 1468 | verify_chunk(Chunk *chunk) { |
910 | Chunk *func = chunk_alloc(chunk); | 1469 | if (chunk->const_idx >= 256) { |
911 | func->name = node->unique_name; | 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 | |||
1491 | void | ||
1492 | declare_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 | } | ||
912 | Function fun = (Function){ | 1498 | Function fun = (Function){ |
913 | .name = func->name, | 1499 | .name = name, |
914 | .index = chunk->fun_idx++, | 1500 | .index = chunk->fun_idx++, |
915 | .param_arity = array_size(node->func_params), | 1501 | .param_arity = array_size(node->func.params), |
916 | .return_arity = array_size(node->func_ret), | 1502 | .return_arity = array_size(node->func.ret), |
917 | }; | 1503 | }; |
918 | funcmap_insert(&chunk->funmap, func->name, fun, chunk->storage); | 1504 | funcmap_insert(&chunk->funmap, node->unique_name, fun, chunk->storage); |
1505 | } | ||
1506 | |||
1507 | CompResult | ||
1508 | compile_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); | ||
919 | array_push(chunk->functions, func, chunk->storage); | 1523 | array_push(chunk->functions, func, chunk->storage); |
920 | 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 | |||
921 | // Put return values into memory. | 1543 | // Put return values into memory. |
922 | CompResult res = compile_expr(func, node->func_body); | ||
923 | switch (res.type) { | 1544 | switch (res.type) { |
924 | case COMP_CONST: { | 1545 | case COMP_CONST: { |
925 | EMIT_OP(OP_PUTRETI, res.idx, 0, 0, node, func); | 1546 | emit_op(OP_PUTRETI, res.idx, 0, 0, node, func); |
926 | } break; | 1547 | } break; |
927 | case COMP_REG: { | 1548 | case COMP_REG: { |
928 | EMIT_OP(OP_PUTRET, res.idx, 0, 0, node, func); | 1549 | emit_op(OP_PUTRET, res.idx, 0, 0, node, func); |
929 | } break; | 1550 | } break; |
930 | default: break; | 1551 | default: break; |
931 | } | 1552 | } |
932 | 1553 | ||
933 | // TODO: handle captured locals/globals? | 1554 | emit_op(OP_RET, 0, 0, 0, node, func); |
934 | EMIT_OP(OP_RET, 0, 0, 0, node, func); | 1555 | verify_chunk(func); |
935 | return (CompResult){.type = COMP_NIL}; | 1556 | return (CompResult){.type = COMP_NIL}; |
936 | } | 1557 | } |
937 | 1558 | ||
938 | CompResult | 1559 | CompResult |
939 | compile_expr(Chunk *chunk, Node *node) { | 1560 | compile_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 | |||
1634 | CompResult | ||
1635 | compile_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 | } | ||
1803 | return (CompResult){.type = COMP_NIL}; | ||
1804 | } | ||
1805 | |||
1806 | CompResult | ||
1807 | compile_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 | |||
1896 | CompResult | ||
1897 | compile_expr(Compiler *compiler, Chunk *chunk, Node *node) { | ||
940 | switch (node->kind) { | 1898 | switch (node->kind) { |
941 | case NODE_FUN: return compile_function(chunk, node); | 1899 | case NODE_BREAK: return compile_break(compiler, chunk, node); |
942 | case NODE_FUNCALL: return compile_funcall(chunk, node); | 1900 | case NODE_CONTINUE: return compile_continue(compiler, chunk, node); |
943 | case NODE_WHILE: return compile_while(chunk, node); | 1901 | case NODE_RETURN: return compile_return(compiler, chunk, node); |
944 | case NODE_IF: return compile_if(chunk, node); | 1902 | case NODE_FUN: return compile_function(compiler, chunk, node); |
945 | case NODE_COND: return compile_cond(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); | ||
946 | // Logic. | 1907 | // Logic. |
947 | // case NODE_XOR: | ||
948 | case NODE_BITNOT: | 1908 | case NODE_BITNOT: |
949 | case NODE_NOT: return compile_unary(chunk, node); break; | 1909 | case NODE_NOT: return compile_unary(compiler, chunk, node); break; |
950 | case NODE_AND: | 1910 | case NODE_AND: |
951 | case NODE_OR: | 1911 | case NODE_OR: return compile_binary_logic(compiler, chunk, node); break; |
952 | case NODE_EQ: | 1912 | case NODE_EQ: |
953 | case NODE_NEQ: | 1913 | case NODE_NEQ: |
954 | case NODE_LT: | 1914 | case NODE_LT: |
@@ -957,6 +1917,7 @@ compile_expr(Chunk *chunk, Node *node) { | |||
957 | // Bitwise ops. | 1917 | // Bitwise ops. |
958 | case NODE_BITAND: | 1918 | case NODE_BITAND: |
959 | case NODE_BITOR: | 1919 | case NODE_BITOR: |
1920 | case NODE_BITXOR: | ||
960 | case NODE_BITLSHIFT: | 1921 | case NODE_BITLSHIFT: |
961 | case NODE_BITRSHIFT: | 1922 | case NODE_BITRSHIFT: |
962 | // Arithmetic. | 1923 | // Arithmetic. |
@@ -965,7 +1926,7 @@ compile_expr(Chunk *chunk, Node *node) { | |||
965 | case NODE_SUB: | 1926 | case NODE_SUB: |
966 | case NODE_MUL: | 1927 | case NODE_MUL: |
967 | case NODE_DIV: | 1928 | case NODE_DIV: |
968 | case NODE_MOD: return compile_binary(chunk, node); break; | 1929 | case NODE_MOD: return compile_binary(compiler, chunk, node); break; |
969 | case NODE_TRUE: | 1930 | case NODE_TRUE: |
970 | case NODE_FALSE: | 1931 | case NODE_FALSE: |
971 | case NODE_NUM_FLOAT: | 1932 | case NODE_NUM_FLOAT: |
@@ -986,192 +1947,74 @@ compile_expr(Chunk *chunk, Node *node) { | |||
986 | .idx = str_idx, | 1947 | .idx = str_idx, |
987 | }; | 1948 | }; |
988 | } break; | 1949 | } break; |
989 | case NODE_LET: { | 1950 | case NODE_LET: return compile_let(compiler, chunk, node); |
990 | sz idx = array_size(chunk->vars); | 1951 | case NODE_SET: return compile_set(compiler, chunk, node); |
991 | Str name = node->unique_name; | 1952 | case NODE_SYMBOL: return compile_symbol(compiler, chunk, node); |
992 | Str type = node->var_name->type; | 1953 | case NODE_PTR: { |
993 | sz size = 8; | 1954 | // Load and return address of associated symbol. |
994 | // TODO: get type storage from a table to consider all the basic | 1955 | Str name = node->t.next->unique_name; |
995 | // types as well as user defined ones. | 1956 | sz op_ldaddr = OP_LDLADDR; |
996 | if (str_eq(type, cstr("str"))) { | 1957 | if (chunk == &compiler->main_chunk) { |
997 | size = 16; | 1958 | op_ldaddr = OP_LDGADDR; |
998 | } | ||
999 | if (str_has_prefix(type, cstr("@"))) { | ||
1000 | if (node->var_type && node->var_type->kind == NODE_ARR_TYPE && | ||
1001 | node->var_type->arr_size->value.i > 0) { | ||
1002 | // TODO: get the proper storage size for the multiplication. | ||
1003 | size *= node->var_type->arr_size->value.i; | ||
1004 | // FIXME: this should be done on the static analysis, plus, | ||
1005 | // we shouldn't be checking all these types by hand, but | ||
1006 | // using the symbol tables. | ||
1007 | type = str_remove_prefix(type, cstr("@")); | ||
1008 | type = str_concat(cstr("[]"), type, chunk->storage); | ||
1009 | } | ||
1010 | } | ||
1011 | Variable var = (Variable){ | ||
1012 | .name = name, | ||
1013 | .type = type, | ||
1014 | .size = size, | ||
1015 | .offset = chunk->var_off, | ||
1016 | .idx = idx, | ||
1017 | }; | ||
1018 | varmap_insert(&chunk->varmap, name, var, chunk->storage); | ||
1019 | array_push(chunk->vars, var, chunk->storage); | ||
1020 | chunk->var_off += size; | ||
1021 | |||
1022 | // Value. | ||
1023 | if (node->var_val) { | ||
1024 | CompResult res = compile_expr(chunk, node->var_val); | ||
1025 | switch (res.type) { | ||
1026 | case COMP_CONST: { | ||
1027 | EMIT_OP(OP_STGVARI, idx, res.idx, 0, node->var_val, | ||
1028 | chunk); | ||
1029 | } break; | ||
1030 | case COMP_REG: { | ||
1031 | EMIT_OP(OP_STGVAR, idx, res.idx, 0, node->var_val, | ||
1032 | chunk); | ||
1033 | } break; | ||
1034 | default: { | ||
1035 | return (CompResult){.type = COMP_ERR}; | ||
1036 | } break; | ||
1037 | } | ||
1038 | } | 1959 | } |
1039 | 1960 | ||
1040 | return (CompResult){.type = COMP_NIL}; | ||
1041 | } break; | ||
1042 | case NODE_SET: { | ||
1043 | Str name = node->unique_name; | ||
1044 | StrVarMap *map = varmap_lookup(&chunk->varmap, name); | 1961 | StrVarMap *map = varmap_lookup(&chunk->varmap, name); |
1045 | if (!map) { | 1962 | if (!map) { |
1046 | eprintln("error: node_set: symbol name not found: %s", name); | 1963 | emit_compile_err(compiler, chunk, node); |
1047 | } | ||
1048 | CompResult res = compile_expr(chunk, node->var_val); | ||
1049 | if (node->var_name->kind == NODE_SYMBOL_IDX) { | ||
1050 | // Value. | ||
1051 | sz reg_val; | ||
1052 | switch (res.type) { | ||
1053 | case COMP_CONST: { | ||
1054 | reg_val = chunk->reg_idx++; | ||
1055 | EMIT_OP(OP_LD64K, reg_val, res.idx, 0, node, chunk); | ||
1056 | } break; | ||
1057 | case COMP_REG: { | ||
1058 | reg_val = res.idx; | ||
1059 | } break; | ||
1060 | default: { | ||
1061 | return (CompResult){.type = COMP_ERR}; | ||
1062 | } break; | ||
1063 | } | ||
1064 | |||
1065 | // Address. | ||
1066 | sz reg_addr = chunk->reg_idx++; | ||
1067 | // Is this a pointer access or an array access? | ||
1068 | if (str_has_prefix(map->val.type, cstr("[]"))) { | ||
1069 | EMIT_OP(OP_LDGADDR, reg_addr, map->val.idx, 0, | ||
1070 | node->var_val, chunk); | ||
1071 | } else { | ||
1072 | EMIT_OP(OP_LDGVAR, reg_addr, map->val.idx, 0, node->var_val, | ||
1073 | chunk); | ||
1074 | } | ||
1075 | |||
1076 | // Index. | ||
1077 | CompResult idx = compile_expr(chunk, node->var_name->arr_size); | ||
1078 | switch (idx.type) { | ||
1079 | case COMP_CONST: { | ||
1080 | EMIT_OP(OP_ST64I, reg_val, reg_addr, idx.idx, node, | ||
1081 | chunk); | ||
1082 | } break; | ||
1083 | case COMP_REG: { | ||
1084 | EMIT_OP(OP_ST64, reg_val, reg_addr, idx.idx, node, | ||
1085 | chunk); | ||
1086 | } break; | ||
1087 | default: { | ||
1088 | return (CompResult){.type = COMP_ERR}; | ||
1089 | } break; | ||
1090 | } | ||
1091 | // TODO: offset should be in bytes, in this case we are assuming | ||
1092 | // 64bit types, hence ST64 | ||
1093 | return (CompResult){.type = COMP_NIL}; | ||
1094 | } | ||
1095 | switch (res.type) { | ||
1096 | case COMP_CONST: { | ||
1097 | EMIT_OP(OP_STGVARI, map->val.idx, res.idx, 0, node->var_val, | ||
1098 | chunk); | ||
1099 | } break; | ||
1100 | case COMP_REG: { | ||
1101 | EMIT_OP(OP_STGVAR, map->val.idx, res.idx, 0, node->var_val, | ||
1102 | chunk); | ||
1103 | } break; | ||
1104 | default: { | ||
1105 | return (CompResult){.type = COMP_ERR}; | ||
1106 | } break; | ||
1107 | } | ||
1108 | return (CompResult){.type = COMP_NIL}; | ||
1109 | } break; | ||
1110 | case NODE_SYMBOL: { | ||
1111 | Str name = node->unique_name; | ||
1112 | StrVarMap *map = varmap_lookup(&chunk->varmap, name); | ||
1113 | if (!map) { | ||
1114 | println("error: unreachable... name: %s", name); | ||
1115 | exit(EXIT_FAILURE); | ||
1116 | } | 1964 | } |
1117 | Variable var = map->val; | 1965 | Variable var = map->val; |
1118 | u8 reg_dst = chunk->reg_idx++; | ||
1119 | if (node->is_ptr) { | ||
1120 | EMIT_OP(OP_LDGADDR, reg_dst, var.idx, 0, node, chunk); | ||
1121 | } else { | ||
1122 | EMIT_OP(OP_LDGVAR, reg_dst, var.idx, 0, node, chunk); | ||
1123 | } | ||
1124 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | ||
1125 | } break; | ||
1126 | case NODE_SYMBOL_IDX: { | ||
1127 | Str name = node->unique_name; | ||
1128 | StrVarMap *map = varmap_lookup(&chunk->varmap, name); | ||
1129 | if (!map) { | ||
1130 | println("error: unreachable... name: %s", name); | ||
1131 | exit(EXIT_FAILURE); | ||
1132 | } | ||
1133 | 1966 | ||
1134 | // Destination. | ||
1135 | u8 reg_dst = chunk->reg_idx++; | ||
1136 | |||
1137 | // Address. | ||
1138 | sz reg_addr = chunk->reg_idx++; | 1967 | sz reg_addr = chunk->reg_idx++; |
1139 | if (str_has_prefix(map->val.type, cstr("[]"))) { | 1968 | emit_op(op_ldaddr, reg_addr, var.idx, 0, node, chunk); |
1140 | EMIT_OP(OP_LDGADDR, reg_addr, map->val.idx, 0, node->var_val, | 1969 | return (CompResult){.type = COMP_REG, .idx = reg_addr}; |
1141 | chunk); | 1970 | } break; |
1142 | } else { | 1971 | case NODE_DEREF: { |
1143 | EMIT_OP(OP_LDGVAR, reg_addr, map->val.idx, 0, node->var_val, | 1972 | Str type_name = node->type; |
1144 | chunk); | 1973 | if (str_has_prefix(type_name, cstr("@")) || |
1974 | str_has_prefix(type_name, cstr("["))) { | ||
1975 | type_name = cstr("Ptr"); | ||
1145 | } | 1976 | } |
1146 | 1977 | StrTypeMap *t = strtype_lookup(&compiler->type_map, type_name); | |
1147 | // Index. | 1978 | sz size = t->val.size; |
1148 | CompResult idx = compile_expr(chunk, node->arr_size); | 1979 | |
1149 | switch (idx.type) { | 1980 | Node *next = node->deref.next; |
1150 | case COMP_CONST: { | 1981 | sz n_deref = 0; |
1151 | EMIT_OP(OP_LD64I, reg_dst, reg_addr, idx.idx, node, chunk); | 1982 | while (next) { |
1152 | } break; | 1983 | n_deref++; |
1153 | case COMP_REG: { | 1984 | if (next->kind == NODE_SYMBOL) { |
1154 | EMIT_OP(OP_LD64, reg_dst, reg_addr, idx.idx, node, chunk); | 1985 | break; |
1155 | } break; | 1986 | } |
1156 | default: { | 1987 | next = next->deref.next; |
1157 | return (CompResult){.type = COMP_ERR}; | 1988 | } |
1158 | } break; | 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; | ||
1159 | } | 2001 | } |
1160 | // TODO: hardcoding the type size for now (LD64/LD64I). | ||
1161 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | 2002 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; |
1162 | } break; | 2003 | } break; |
1163 | case NODE_BLOCK: { | 2004 | case NODE_BLOCK: { |
1164 | CompResult res; | 2005 | CompResult res; |
1165 | for (sz i = 0; i < array_size(node->elements); i++) { | 2006 | for (sz i = 0; i < array_size(node->elements); i++) { |
1166 | Node *root = node->elements[i]; | 2007 | Node *root = node->elements[i]; |
1167 | res = compile_expr(chunk, root); | 2008 | res = compile_expr(compiler, chunk, root); |
1168 | } | 2009 | } |
1169 | return res; | 2010 | return res; |
1170 | } break; | 2011 | } break; |
2012 | case NODE_NIL: return (CompResult){.type = COMP_NIL}; | ||
1171 | default: { | 2013 | default: { |
1172 | eprintln("error: compilation not implemented for node %s", | 2014 | eprintln("error: compilation not implemented for node %s", |
1173 | node_str[node->kind]); | 2015 | node_str[node->kind]); |
1174 | exit(EXIT_FAILURE); | 2016 | emit_compile_err(compiler, chunk, node); |
2017 | return (CompResult){.type = COMP_ERR}; | ||
1175 | } break; | 2018 | } break; |
1176 | } | 2019 | } |
1177 | return (CompResult){.type = COMP_ERR}; | 2020 | return (CompResult){.type = COMP_ERR}; |
@@ -1188,6 +2031,14 @@ disassemble_instruction(Instruction instruction) { | |||
1188 | case OP_MOV16: | 2031 | case OP_MOV16: |
1189 | case OP_MOV32: | 2032 | case OP_MOV32: |
1190 | case OP_MOV64: | 2033 | case OP_MOV64: |
2034 | case OP_LD8K: | ||
2035 | case OP_LD16K: | ||
2036 | case OP_LD32K: | ||
2037 | case OP_LD64K: | ||
2038 | case OP_ST8K: | ||
2039 | case OP_ST16K: | ||
2040 | case OP_ST32K: | ||
2041 | case OP_ST64K: | ||
1191 | println("%s r%d, r%d", op_str[instruction.op], instruction.dst, | 2042 | println("%s r%d, r%d", op_str[instruction.op], instruction.dst, |
1192 | instruction.a, instruction.b); | 2043 | instruction.a, instruction.b); |
1193 | break; | 2044 | break; |
@@ -1196,10 +2047,7 @@ disassemble_instruction(Instruction instruction) { | |||
1196 | println("%s l%d, r%d", op_str[instruction.op], instruction.dst, | 2047 | println("%s l%d, r%d", op_str[instruction.op], instruction.dst, |
1197 | instruction.a, instruction.b); | 2048 | instruction.a, instruction.b); |
1198 | break; | 2049 | break; |
1199 | case OP_LD8K: | 2050 | case OP_LDCONST: |
1200 | case OP_LD16K: | ||
1201 | case OP_LD32K: | ||
1202 | case OP_LD64K: | ||
1203 | 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, |
1204 | instruction.a, instruction.b); | 2052 | instruction.a, instruction.b); |
1205 | break; | 2053 | break; |
@@ -1233,6 +2081,7 @@ disassemble_instruction(Instruction instruction) { | |||
1233 | case OP_BITRSHIFTI: | 2081 | case OP_BITRSHIFTI: |
1234 | case OP_BITANDI: | 2082 | case OP_BITANDI: |
1235 | case OP_BITORI: | 2083 | case OP_BITORI: |
2084 | case OP_BITXORI: | ||
1236 | 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, |
1237 | instruction.a, instruction.b); | 2086 | instruction.a, instruction.b); |
1238 | break; | 2087 | break; |
@@ -1266,19 +2115,28 @@ disassemble_instruction(Instruction instruction) { | |||
1266 | case OP_BITRSHIFT: | 2115 | case OP_BITRSHIFT: |
1267 | case OP_BITAND: | 2116 | case OP_BITAND: |
1268 | case OP_BITOR: | 2117 | case OP_BITOR: |
2118 | case OP_BITXOR: | ||
1269 | 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, |
1270 | instruction.a, instruction.b); | 2120 | instruction.a, instruction.b); |
1271 | break; | 2121 | break; |
1272 | case OP_LDGVAR: | 2122 | case OP_LDGVAR: |
1273 | case OP_LDGADDR: | 2123 | case OP_LDGADDR: |
2124 | case OP_LDLVAR: | ||
2125 | case OP_LDLADDR: | ||
1274 | 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, |
1275 | instruction.a, instruction.b); | 2127 | instruction.a, instruction.b); |
1276 | 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; | ||
1277 | case OP_STGVAR: | 2133 | case OP_STGVAR: |
2134 | case OP_STLVAR: | ||
1278 | 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, |
1279 | instruction.a, instruction.b); | 2136 | instruction.a, instruction.b); |
1280 | break; | 2137 | break; |
1281 | case OP_STGVARI: | 2138 | case OP_STGVARI: |
2139 | case OP_STLVARI: | ||
1282 | 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, |
1283 | instruction.a, instruction.b); | 2141 | instruction.a, instruction.b); |
1284 | break; | 2142 | break; |
@@ -1301,17 +2159,36 @@ disassemble_instruction(Instruction instruction) { | |||
1301 | println("%s l%d, c%d", op_str[instruction.op], instruction.dst, | 2159 | println("%s l%d, c%d", op_str[instruction.op], instruction.dst, |
1302 | instruction.a, instruction.b); | 2160 | instruction.a, instruction.b); |
1303 | break; | 2161 | break; |
2162 | case OP_PRINTS8: | ||
2163 | case OP_PRINTS16: | ||
2164 | case OP_PRINTS32: | ||
1304 | case OP_PRINTS64: | 2165 | case OP_PRINTS64: |
2166 | case OP_PRINTU8: | ||
2167 | case OP_PRINTU16: | ||
2168 | case OP_PRINTU32: | ||
2169 | case OP_PRINTU64: | ||
2170 | case OP_PRINTF32: | ||
1305 | case OP_PRINTF64: | 2171 | case OP_PRINTF64: |
1306 | case OP_PRINTSTR: | 2172 | case OP_PRINTSTR: |
2173 | case OP_PRINTBOOL: | ||
1307 | case OP_PUSH: | 2174 | case OP_PUSH: |
1308 | case OP_POP: | 2175 | case OP_POP: |
1309 | case OP_PUTRET: | 2176 | case OP_PUTRET: |
1310 | println("%s r%d", op_str[instruction.op], instruction.dst, | 2177 | println("%s r%d", op_str[instruction.op], instruction.dst, |
1311 | instruction.a, instruction.b); | 2178 | instruction.a, instruction.b); |
1312 | break; | 2179 | break; |
2180 | case OP_PRINTSTRI: | ||
2181 | case OP_PRINTS8I: | ||
2182 | case OP_PRINTS16I: | ||
2183 | case OP_PRINTS32I: | ||
1313 | case OP_PRINTS64I: | 2184 | case OP_PRINTS64I: |
2185 | case OP_PRINTU8I: | ||
2186 | case OP_PRINTU16I: | ||
2187 | case OP_PRINTU32I: | ||
2188 | case OP_PRINTU64I: | ||
2189 | case OP_PRINTF32I: | ||
1314 | case OP_PRINTF64I: | 2190 | case OP_PRINTF64I: |
2191 | case OP_PRINTBOOLI: | ||
1315 | case OP_RESERVE: | 2192 | case OP_RESERVE: |
1316 | case OP_PUSHI: | 2193 | case OP_PUSHI: |
1317 | case OP_PUTRETI: | 2194 | case OP_PUTRETI: |
@@ -1319,6 +2196,7 @@ disassemble_instruction(Instruction instruction) { | |||
1319 | instruction.a, instruction.b); | 2196 | instruction.a, instruction.b); |
1320 | break; | 2197 | break; |
1321 | case OP_RET: | 2198 | case OP_RET: |
2199 | case OP_RECUR: | ||
1322 | case OP_HALT: println("%s", op_str[instruction.op]); break; | 2200 | case OP_HALT: println("%s", op_str[instruction.op]); break; |
1323 | default: println("Unknown opcode %d", instruction.op); break; | 2201 | default: println("Unknown opcode %d", instruction.op); break; |
1324 | } | 2202 | } |
@@ -1336,11 +2214,25 @@ disassemble_chunk(Chunk chunk) { | |||
1336 | for (sz i = 0; i < array_size(chunk.code); i++) { | 2214 | for (sz i = 0; i < array_size(chunk.code); i++) { |
1337 | printf(" %.4ld:%.4ld %.4lx ", chunk.linecol[i].line, | 2215 | printf(" %.4ld:%.4ld %.4lx ", chunk.linecol[i].line, |
1338 | chunk.linecol[i].col, i); | 2216 | chunk.linecol[i].col, i); |
1339 | IntIntMap *label = intintmap_lookup(&chunk.labels_rev, i); | 2217 | IntIntMapIter lab_it = intintmap_iterator(chunk.labels, chunk.storage); |
1340 | if (label) { | 2218 | IntIntMap *m = intintmap_next(&lab_it, chunk.storage); |
1341 | printf(".L%.2ld ", label->val); | 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 | } | ||
1342 | } else { | 2234 | } else { |
1343 | printf(" %2s ", ""); | 2235 | printf(" "); |
1344 | } | 2236 | } |
1345 | disassemble_instruction(chunk.code[i]); | 2237 | disassemble_instruction(chunk.code[i]); |
1346 | } | 2238 | } |
@@ -1361,7 +2253,7 @@ disassemble_chunk(Chunk chunk) { | |||
1361 | for (sz i = 0; i < array_size(chunk.vars); i++) { | 2253 | for (sz i = 0; i < array_size(chunk.vars); i++) { |
1362 | println(" %x{2}: [%x{4}:%x{4}] %s: %s", i, chunk.vars[i].offset, | 2254 | println(" %x{2}: [%x{4}:%x{4}] %s: %s", i, chunk.vars[i].offset, |
1363 | chunk.vars[i].offset + chunk.vars[i].size, | 2255 | chunk.vars[i].offset + chunk.vars[i].size, |
1364 | chunk.vars[i].name, chunk.vars[i].type); | 2256 | chunk.vars[i].name, chunk.vars[i].type_name); |
1365 | } | 2257 | } |
1366 | } | 2258 | } |
1367 | if (array_size(chunk.functions) > 0) { | 2259 | if (array_size(chunk.functions) > 0) { |
@@ -1378,4 +2270,75 @@ disassemble_chunk(Chunk chunk) { | |||
1378 | } | 2270 | } |
1379 | } | 2271 | } |
1380 | 2272 | ||
2273 | void | ||
2274 | bytecode_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); | ||
2342 | } | ||
2343 | |||
1381 | #endif // COMPILER_C | 2344 | #endif // COMPILER_C |
diff --git a/src/lexer.c b/src/lexer.c index 2feba2a..84b69e7 100644 --- a/src/lexer.c +++ b/src/lexer.c | |||
@@ -41,18 +41,24 @@ typedef enum TokenKind { | |||
41 | TOK_STRUCT, // struct | 41 | TOK_STRUCT, // struct |
42 | TOK_TRUE, // true | 42 | TOK_TRUE, // true |
43 | TOK_WHILE, // while | 43 | TOK_WHILE, // while |
44 | TOK_FOR, // for | ||
44 | 45 | ||
45 | // Arithmetic ops. | 46 | // Arithmetic ops. |
46 | TOK_ADD, // + | 47 | TOK_ADD, // + |
47 | TOK_SUB, // - | 48 | TOK_SUB, // - |
48 | TOK_MUL, // * | 49 | TOK_MUL, // * |
49 | TOK_DIV, // / | 50 | TOK_DIV, // / |
50 | TOK_MOD, // % | 51 | TOK_MOD, // % |
52 | TOK_ADD_ASSIGN, // += | ||
53 | TOK_SUB_ASSIGN, // -= | ||
54 | TOK_MUL_ASSIGN, // *= | ||
55 | TOK_DIV_ASSIGN, // /= | ||
56 | TOK_MOD_ASSIGN, // %= | ||
51 | 57 | ||
52 | // Logical ops. | 58 | // Logical ops. |
53 | TOK_NOT, // ! | 59 | TOK_NOT, // ! |
54 | TOK_AND, // && | 60 | TOK_AND, // and |
55 | TOK_OR, // || | 61 | TOK_OR, // or |
56 | TOK_EQ, // == | 62 | TOK_EQ, // == |
57 | TOK_NEQ, // != | 63 | TOK_NEQ, // != |
58 | TOK_LT, // < | 64 | TOK_LT, // < |
@@ -61,11 +67,17 @@ typedef enum TokenKind { | |||
61 | TOK_GE, // >= | 67 | TOK_GE, // >= |
62 | 68 | ||
63 | // Bitwise ops. | 69 | // Bitwise ops. |
64 | TOK_BITNOT, // ~ | 70 | TOK_BITNOT, // ~ |
65 | TOK_BITAND, // & | 71 | TOK_BITAND, // & |
66 | TOK_BITOR, // | | 72 | TOK_BITOR, // | |
67 | TOK_BITLSHIFT, // << | 73 | TOK_BITXOR, // ^ |
68 | TOK_BITRSHIFT, // >> | 74 | TOK_BITLSHIFT, // << |
75 | TOK_BITRSHIFT, // >> | ||
76 | TOK_BITAND_ASSIGN, // &= | ||
77 | TOK_BITOR_ASSIGN, // |= | ||
78 | TOK_BITXOR_ASSIGN, // ^= | ||
79 | TOK_BITLSHIFT_ASSIGN, // <<= | ||
80 | TOK_BITRSHIFT_ASSIGN, // >>= | ||
69 | 81 | ||
70 | // Special ops. | 82 | // Special ops. |
71 | TOK_COLON, // : | 83 | TOK_COLON, // : |
@@ -113,6 +125,7 @@ Str token_str[] = { | |||
113 | [TOK_STRUCT] = cstr("STRUCT"), | 125 | [TOK_STRUCT] = cstr("STRUCT"), |
114 | [TOK_TRUE] = cstr("TRUE"), | 126 | [TOK_TRUE] = cstr("TRUE"), |
115 | [TOK_WHILE] = cstr("WHILE"), | 127 | [TOK_WHILE] = cstr("WHILE"), |
128 | [TOK_FOR] = cstr("FOR"), | ||
116 | 129 | ||
117 | // Arithmetic ops. | 130 | // Arithmetic ops. |
118 | [TOK_ADD] = cstr("ADD"), | 131 | [TOK_ADD] = cstr("ADD"), |
@@ -120,6 +133,11 @@ Str token_str[] = { | |||
120 | [TOK_MUL] = cstr("MUL"), | 133 | [TOK_MUL] = cstr("MUL"), |
121 | [TOK_DIV] = cstr("DIV"), | 134 | [TOK_DIV] = cstr("DIV"), |
122 | [TOK_MOD] = cstr("MOD"), | 135 | [TOK_MOD] = cstr("MOD"), |
136 | [TOK_ADD_ASSIGN] = cstr("ADD_ASSIGN"), | ||
137 | [TOK_SUB_ASSIGN] = cstr("SUB_ASSIGN"), | ||
138 | [TOK_MUL_ASSIGN] = cstr("MUL_ASSIGN"), | ||
139 | [TOK_DIV_ASSIGN] = cstr("DIV_ASSIGN"), | ||
140 | [TOK_MOD_ASSIGN] = cstr("MOD_ASSIGN"), | ||
123 | 141 | ||
124 | // Logical ops. | 142 | // Logical ops. |
125 | [TOK_NOT] = cstr("NOT"), | 143 | [TOK_NOT] = cstr("NOT"), |
@@ -136,8 +154,14 @@ Str token_str[] = { | |||
136 | [TOK_BITNOT] = cstr("BITNOT"), | 154 | [TOK_BITNOT] = cstr("BITNOT"), |
137 | [TOK_BITAND] = cstr("BITAND"), | 155 | [TOK_BITAND] = cstr("BITAND"), |
138 | [TOK_BITOR] = cstr("BITOR"), | 156 | [TOK_BITOR] = cstr("BITOR"), |
157 | [TOK_BITXOR] = cstr("BITXOR"), | ||
139 | [TOK_BITLSHIFT] = cstr("BITLSHIFT"), | 158 | [TOK_BITLSHIFT] = cstr("BITLSHIFT"), |
140 | [TOK_BITRSHIFT] = cstr("BITRSHIFT"), | 159 | [TOK_BITRSHIFT] = cstr("BITRSHIFT"), |
160 | [TOK_BITAND_ASSIGN] = cstr("BITAND_ASSIGN"), | ||
161 | [TOK_BITOR_ASSIGN] = cstr("BITOR_ASSIGN"), | ||
162 | [TOK_BITXOR_ASSIGN] = cstr("BITXOR_ASSIGN"), | ||
163 | [TOK_BITLSHIFT_ASSIGN] = cstr("BITLSHIFT_ASSIGN"), | ||
164 | [TOK_BITRSHIFT_ASSIGN] = cstr("BITRSHIFT_ASSIGN"), | ||
141 | 165 | ||
142 | // Special ops. | 166 | // Special ops. |
143 | [TOK_COLON] = cstr("COLON"), | 167 | [TOK_COLON] = cstr("COLON"), |
@@ -432,6 +456,10 @@ scan_token(Scanner *scanner) { | |||
432 | *scanner = current; | 456 | *scanner = current; |
433 | return emit_token_number(scanner); | 457 | return emit_token_number(scanner); |
434 | } | 458 | } |
459 | if (p == '=') { | ||
460 | scan_next(scanner); | ||
461 | return emit_token(current, scanner, TOK_ADD_ASSIGN); | ||
462 | } | ||
435 | return emit_token(current, scanner, TOK_ADD); | 463 | return emit_token(current, scanner, TOK_ADD); |
436 | }; | 464 | }; |
437 | case '-': { | 465 | case '-': { |
@@ -440,11 +468,33 @@ scan_token(Scanner *scanner) { | |||
440 | *scanner = current; | 468 | *scanner = current; |
441 | return emit_token_number(scanner); | 469 | return emit_token_number(scanner); |
442 | } | 470 | } |
471 | if (p == '=') { | ||
472 | scan_next(scanner); | ||
473 | return emit_token(current, scanner, TOK_SUB_ASSIGN); | ||
474 | } | ||
443 | return emit_token(current, scanner, TOK_SUB); | 475 | return emit_token(current, scanner, TOK_SUB); |
444 | }; | 476 | }; |
445 | case '*': return emit_token(current, scanner, TOK_MUL); | 477 | case '*': { |
446 | case '/': return emit_token(current, scanner, TOK_DIV); | 478 | if (scan_peek(scanner) == '=') { |
447 | case '%': return emit_token(current, scanner, TOK_MOD); | 479 | scan_next(scanner); |
480 | return emit_token(current, scanner, TOK_MUL_ASSIGN); | ||
481 | } | ||
482 | return emit_token(current, scanner, TOK_MUL); | ||
483 | } | ||
484 | case '/': { | ||
485 | if (scan_peek(scanner) == '=') { | ||
486 | scan_next(scanner); | ||
487 | return emit_token(current, scanner, TOK_DIV_ASSIGN); | ||
488 | } | ||
489 | return emit_token(current, scanner, TOK_DIV); | ||
490 | } | ||
491 | case '%': { | ||
492 | if (scan_peek(scanner) == '=') { | ||
493 | scan_next(scanner); | ||
494 | return emit_token(current, scanner, TOK_MOD_ASSIGN); | ||
495 | } | ||
496 | return emit_token(current, scanner, TOK_MOD); | ||
497 | } | ||
448 | case '!': { | 498 | case '!': { |
449 | if (scan_peek(scanner) == '=') { | 499 | if (scan_peek(scanner) == '=') { |
450 | scan_next(scanner); | 500 | scan_next(scanner); |
@@ -467,6 +517,10 @@ scan_token(Scanner *scanner) { | |||
467 | } | 517 | } |
468 | if (p == '<') { | 518 | if (p == '<') { |
469 | scan_next(scanner); | 519 | scan_next(scanner); |
520 | if (scan_peek(scanner) == '=') { | ||
521 | scan_next(scanner); | ||
522 | return emit_token(current, scanner, TOK_BITLSHIFT_ASSIGN); | ||
523 | } | ||
470 | return emit_token(current, scanner, TOK_BITLSHIFT); | 524 | return emit_token(current, scanner, TOK_BITLSHIFT); |
471 | } | 525 | } |
472 | return emit_token(current, scanner, TOK_LT); | 526 | return emit_token(current, scanner, TOK_LT); |
@@ -479,22 +533,33 @@ scan_token(Scanner *scanner) { | |||
479 | } | 533 | } |
480 | if (p == '>') { | 534 | if (p == '>') { |
481 | scan_next(scanner); | 535 | scan_next(scanner); |
536 | if (scan_peek(scanner) == '=') { | ||
537 | scan_next(scanner); | ||
538 | return emit_token(current, scanner, TOK_BITRSHIFT_ASSIGN); | ||
539 | } | ||
482 | return emit_token(current, scanner, TOK_BITRSHIFT); | 540 | return emit_token(current, scanner, TOK_BITRSHIFT); |
483 | } | 541 | } |
484 | return emit_token(current, scanner, TOK_GT); | 542 | return emit_token(current, scanner, TOK_GT); |
485 | }; | 543 | }; |
486 | case '~': return emit_token(current, scanner, TOK_BITNOT); | 544 | case '~': return emit_token(current, scanner, TOK_BITNOT); |
545 | case '^': { | ||
546 | if (scan_peek(scanner) == '=') { | ||
547 | scan_next(scanner); | ||
548 | return emit_token(current, scanner, TOK_BITXOR_ASSIGN); | ||
549 | } | ||
550 | return emit_token(current, scanner, TOK_BITXOR); | ||
551 | }; | ||
487 | case '&': { | 552 | case '&': { |
488 | if (scan_peek(scanner) == '&') { | 553 | if (scan_peek(scanner) == '=') { |
489 | scan_next(scanner); | 554 | scan_next(scanner); |
490 | return emit_token(current, scanner, TOK_AND); | 555 | return emit_token(current, scanner, TOK_BITOR_ASSIGN); |
491 | } | 556 | } |
492 | return emit_token(current, scanner, TOK_BITAND); | 557 | return emit_token(current, scanner, TOK_BITAND); |
493 | }; | 558 | }; |
494 | case '|': { | 559 | case '|': { |
495 | if (scan_peek(scanner) == '|') { | 560 | if (scan_peek(scanner) == '=') { |
496 | scan_next(scanner); | 561 | scan_next(scanner); |
497 | return emit_token(current, scanner, TOK_OR); | 562 | return emit_token(current, scanner, TOK_BITOR_ASSIGN); |
498 | } | 563 | } |
499 | return emit_token(current, scanner, TOK_BITOR); | 564 | return emit_token(current, scanner, TOK_BITOR); |
500 | }; | 565 | }; |
@@ -535,78 +600,91 @@ scan_token(Scanner *scanner) { | |||
535 | return emit_token_err(¤t, cstr("unexpected character")); | 600 | return emit_token_err(¤t, cstr("unexpected character")); |
536 | } | 601 | } |
537 | switch (val.mem[0]) { | 602 | switch (val.mem[0]) { |
603 | case 'a': { | ||
604 | if (str_eq(val, cstr("and"))) { | ||
605 | return emit_token(current, scanner, TOK_AND); | ||
606 | } | ||
607 | } break; | ||
538 | case 'b': { | 608 | case 'b': { |
539 | if (str_has_prefix(val, cstr("break"))) { | 609 | if (str_eq(val, cstr("break"))) { |
540 | return emit_token(current, scanner, TOK_BREAK); | 610 | return emit_token(current, scanner, TOK_BREAK); |
541 | } | 611 | } |
542 | } break; | 612 | } break; |
543 | case 'c': { | 613 | case 'c': { |
544 | if (str_has_prefix(val, cstr("case"))) { | 614 | if (str_eq(val, cstr("case"))) { |
545 | return emit_token(current, scanner, TOK_CASE); | 615 | return emit_token(current, scanner, TOK_CASE); |
546 | } | 616 | } |
547 | if (str_has_prefix(val, cstr("continue"))) { | 617 | if (str_eq(val, cstr("continue"))) { |
548 | return emit_token(current, scanner, TOK_CONTINUE); | 618 | return emit_token(current, scanner, TOK_CONTINUE); |
549 | } | 619 | } |
550 | if (str_has_prefix(val, cstr("cond"))) { | 620 | if (str_eq(val, cstr("cond"))) { |
551 | return emit_token(current, scanner, TOK_COND); | 621 | return emit_token(current, scanner, TOK_COND); |
552 | } | 622 | } |
553 | } break; | 623 | } break; |
554 | case 'e': { | 624 | case 'e': { |
555 | if (str_has_prefix(val, cstr("else"))) { | 625 | if (str_eq(val, cstr("else"))) { |
556 | return emit_token(current, scanner, TOK_ELSE); | 626 | return emit_token(current, scanner, TOK_ELSE); |
557 | } | 627 | } |
558 | if (str_has_prefix(val, cstr("enum"))) { | 628 | if (str_eq(val, cstr("enum"))) { |
559 | return emit_token(current, scanner, TOK_ENUM); | 629 | return emit_token(current, scanner, TOK_ENUM); |
560 | } | 630 | } |
561 | } break; | 631 | } break; |
562 | case 'f': { | 632 | case 'f': { |
563 | if (str_has_prefix(val, cstr("false"))) { | 633 | if (str_eq(val, cstr("false"))) { |
564 | return emit_token(current, scanner, TOK_FALSE); | 634 | return emit_token(current, scanner, TOK_FALSE); |
565 | } | 635 | } |
566 | if (str_has_prefix(val, cstr("fun"))) { | 636 | if (str_eq(val, cstr("fun"))) { |
567 | return emit_token(current, scanner, TOK_FUN); | 637 | return emit_token(current, scanner, TOK_FUN); |
568 | } | 638 | } |
639 | if (str_eq(val, cstr("for"))) { | ||
640 | return emit_token(current, scanner, TOK_FOR); | ||
641 | } | ||
569 | } break; | 642 | } break; |
570 | case 'i': { | 643 | case 'i': { |
571 | if (str_has_prefix(val, cstr("if"))) { | 644 | if (str_eq(val, cstr("if"))) { |
572 | return emit_token(current, scanner, TOK_IF); | 645 | return emit_token(current, scanner, TOK_IF); |
573 | } | 646 | } |
574 | } break; | 647 | } break; |
575 | case 'l': { | 648 | case 'l': { |
576 | if (str_has_prefix(val, cstr("let"))) { | 649 | if (str_eq(val, cstr("let"))) { |
577 | return emit_token(current, scanner, TOK_LET); | 650 | return emit_token(current, scanner, TOK_LET); |
578 | } | 651 | } |
579 | } break; | 652 | } break; |
580 | case 'm': { | 653 | case 'm': { |
581 | if (str_has_prefix(val, cstr("match"))) { | 654 | if (str_eq(val, cstr("match"))) { |
582 | return emit_token(current, scanner, TOK_MATCH); | 655 | return emit_token(current, scanner, TOK_MATCH); |
583 | } | 656 | } |
584 | } break; | 657 | } break; |
585 | case 'n': { | 658 | case 'n': { |
586 | if (str_has_prefix(val, cstr("nil"))) { | 659 | if (str_eq(val, cstr("nil"))) { |
587 | return emit_token(current, scanner, TOK_NIL); | 660 | return emit_token(current, scanner, TOK_NIL); |
588 | } | 661 | } |
589 | } break; | 662 | } break; |
590 | case 'r': { | 663 | case 'r': { |
591 | if (str_has_prefix(val, cstr("return"))) { | 664 | if (str_eq(val, cstr("return"))) { |
592 | return emit_token(current, scanner, TOK_RETURN); | 665 | return emit_token(current, scanner, TOK_RETURN); |
593 | } | 666 | } |
594 | } break; | 667 | } break; |
595 | case 's': { | 668 | case 's': { |
596 | if (str_has_prefix(val, cstr("set"))) { | 669 | if (str_eq(val, cstr("set"))) { |
597 | return emit_token(current, scanner, TOK_SET); | 670 | return emit_token(current, scanner, TOK_SET); |
598 | } | 671 | } |
599 | if (str_has_prefix(val, cstr("struct"))) { | 672 | if (str_eq(val, cstr("struct"))) { |
600 | return emit_token(current, scanner, TOK_STRUCT); | 673 | return emit_token(current, scanner, TOK_STRUCT); |
601 | } | 674 | } |
602 | } break; | 675 | } break; |
603 | case 't': { | 676 | case 't': { |
604 | if (str_has_prefix(val, cstr("true"))) { | 677 | if (str_eq(val, cstr("true"))) { |
605 | return emit_token(current, scanner, TOK_TRUE); | 678 | return emit_token(current, scanner, TOK_TRUE); |
606 | } | 679 | } |
607 | } break; | 680 | } break; |
681 | case 'o': { | ||
682 | if (str_eq(val, cstr("or"))) { | ||
683 | return emit_token(current, scanner, TOK_OR); | ||
684 | } | ||
685 | } break; | ||
608 | case 'w': { | 686 | case 'w': { |
609 | if (str_has_prefix(val, cstr("while"))) { | 687 | if (str_eq(val, cstr("while"))) { |
610 | return emit_token(current, scanner, TOK_WHILE); | 688 | return emit_token(current, scanner, TOK_WHILE); |
611 | } | 689 | } |
612 | } break; | 690 | } break; |
@@ -628,4 +706,4 @@ print_tokens(Str path, Token *tokens) { | |||
628 | } | 706 | } |
629 | } | 707 | } |
630 | 708 | ||
631 | #endif // LEXER_C | 709 | #endif // LEXER_C |
@@ -12,19 +12,49 @@ | |||
12 | // TODO: unions | 12 | // TODO: unions |
13 | // TODO: embed (binary file) and include (source file) | 13 | // TODO: embed (binary file) and include (source file) |
14 | // TODO: revisit ast parsing for pointers and arrays (I think I'm missing corner | 14 | // TODO: revisit ast parsing for pointers and arrays (I think I'm missing corner |
15 | // cases). | 15 | // cases): |
16 | // TODO: for loops? | 16 | // []Int vs Int[], @sym vs sym@. On the right dereference, on the left |
17 | // for i = 0 , i < 10 , i++ { | 17 | // declaration or taking the address/reference of a variable. Similar |
18 | // | 18 | // to what Odin does. |
19 | // let a: @Int ; pointer to int | ||
20 | // let b: @@Int ; pointer to pointer to int (etc.) | ||
21 | // let c: [123]Int ; static array -> @Int | ||
22 | // let m: [32][32]Int ; multi-dimensional-arrays | ||
23 | // let d: []Int ; slice / view -> struct Slice { u8* mem ; sz size ; } | ||
24 | // let e: [...]Int ; dynamic array -> struct DArry { u8* mem ; sz size ; sz cap ; } | ||
25 | // let f: [123]@Int ; static array of int pointers [](@Int) | ||
26 | // let g: @[123]Int ; pointer to a static array of integers @([123]Int) | ||
27 | // let h: #[Str:Int] ; Hash map of string keys and integer values | ||
28 | // let i: #[Str:@Int] ; Hash map of string keys and pointers to integer | ||
29 | // let j: #[@Str:Int] ; Hash map of string pointers to integers | ||
30 | // let k: @#[Str:Int] ; Pointer to a hash map of string to ints | ||
31 | // let l: (Int Int : Int) ; Function pointer == @(fun(Int,Int):Int) | ||
32 | // TODO: constexpr or const expressions could be evaluated with the bytecode | ||
33 | // interpreter if we are performing compilation. | ||
34 | // TODO: "first class functions" via function pointers | ||
35 | // TODO: convenient function calls per data type instead of methods: | ||
36 | // fun add(a: int, b: int): int a + b | ||
37 | // add(12, 34) == 12.add(34) | ||
38 | // concat(str, str): str | ||
39 | // "hello ".concat("world") ; "hello world" | ||
40 | // TODO: structs and user defined types | ||
41 | // TODO: constant folding | ||
42 | // TODO: casting on demand (1:u16, 0x123:ptr, "hi":int ??? how to deal with | ||
43 | // unsafe casts?) | ||
44 | // TODO: extract table generation from compiler into the semantic analyzer, | ||
45 | // compiler should only focus on translating things to bytecode/linear ir. | ||
46 | // TODO: sizeof function doesn't work well for arrays and variables. | ||
47 | // TODO: store more parameters for variables, for example | ||
48 | // TODO: don't allow overwriting default types with other symbols within a scope | ||
49 | // { | ||
50 | // let Int = 0.0 | ||
19 | // } | 51 | // } |
20 | // TODO: fix semantics for the following expression: | 52 | // TODO: This shouldn't be possible |
21 | // let b = int | 53 | // let b = 4 |
22 | // a type shouldn't be a valid symbol name | 54 | // let a: [32]U8 = @b |
23 | // TODO: fix semantics for arrays: static arrays can't have size 0. | 55 | // TODO: Properly reference and dereference multiple chains of arrays: |
24 | // TODO: consider making all tye types PascalCase: Int F64 Str... | 56 | // let a: [32][32]Int ; The size is not correct at the moment for this. |
25 | // TODO: add a `const` keyword that can only take literals or constexpr values. | 57 | // a[1][2] ? |
26 | // TODO: add assignment operators instead of `set` :=, +=, -= | ||
27 | // TODO: add mifix operators ++ and -- | ||
28 | 58 | ||
29 | typedef enum ExecMode { | 59 | typedef enum ExecMode { |
30 | RUN_NORMAL, | 60 | RUN_NORMAL, |
@@ -56,6 +86,9 @@ process_file(Str path) { | |||
56 | sz errors = 0; | 86 | sz errors = 0; |
57 | 87 | ||
58 | // Lexer. | 88 | // Lexer. |
89 | #if DEBUG == 1 | ||
90 | println("lexing..."); | ||
91 | #endif | ||
59 | Scanner scanner = {.str = file.data}; | 92 | Scanner scanner = {.str = file.data}; |
60 | Token *tokens = NULL; | 93 | Token *tokens = NULL; |
61 | Token tok = {0}; | 94 | Token tok = {0}; |
@@ -79,6 +112,9 @@ process_file(Str path) { | |||
79 | } | 112 | } |
80 | 113 | ||
81 | // Parser. | 114 | // Parser. |
115 | #if DEBUG == 1 | ||
116 | println("parsing..."); | ||
117 | #endif | ||
82 | Parser parser = { | 118 | Parser parser = { |
83 | .tokens = tokens, | 119 | .tokens = tokens, |
84 | .storage = &lexer_arena, | 120 | .storage = &lexer_arena, |
@@ -92,9 +128,6 @@ process_file(Str path) { | |||
92 | println("ROOT: %d", ctr++); | 128 | println("ROOT: %d", ctr++); |
93 | #endif | 129 | #endif |
94 | parse_expr(&parser, PREC_LOW); | 130 | parse_expr(&parser, PREC_LOW); |
95 | if (parser.panic) { | ||
96 | break; | ||
97 | } | ||
98 | } | 131 | } |
99 | parse_consume(&parser, TOK_EOF, cstr("expected end of file")); | 132 | parse_consume(&parser, TOK_EOF, cstr("expected end of file")); |
100 | if (parser.err) { | 133 | if (parser.err) { |
@@ -106,6 +139,9 @@ process_file(Str path) { | |||
106 | } | 139 | } |
107 | 140 | ||
108 | // Semantic analysis. | 141 | // Semantic analysis. |
142 | #if DEBUG == 1 | ||
143 | println("semantic analysis..."); | ||
144 | #endif | ||
109 | Analyzer analyzer = (Analyzer){ | 145 | Analyzer analyzer = (Analyzer){ |
110 | .storage = &lexer_arena, | 146 | .storage = &lexer_arena, |
111 | .file_name = path, | 147 | .file_name = path, |
@@ -175,68 +211,26 @@ process_file(Str path) { | |||
175 | } | 211 | } |
176 | #endif | 212 | #endif |
177 | 213 | ||
178 | // TODO: Type checking. | ||
179 | |||
180 | // Compile roots. | 214 | // Compile roots. |
215 | #if DEBUG == 1 | ||
216 | println("compilation..."); | ||
217 | #endif | ||
181 | Arena bytecode_arena = arena_create(LEXER_MEM, os_allocator); | 218 | Arena bytecode_arena = arena_create(LEXER_MEM, os_allocator); |
182 | Chunk chunk = { | 219 | Compiler compiler = { |
183 | .file_name = path, | 220 | .file_name = path, |
184 | .storage = &bytecode_arena, | 221 | .storage = &bytecode_arena, |
185 | .name = cstr(".main"), | 222 | .integer_types = analyzer.integer_types, |
223 | .float_types = analyzer.float_types, | ||
224 | .numeric_types = analyzer.numeric_types, | ||
225 | .lab_pre = -1, | ||
226 | .lab_post = -1, | ||
186 | }; | 227 | }; |
187 | array_zero(chunk.constants, 256, &bytecode_arena); | 228 | bytecode_compiler(&compiler, parser); |
188 | array_zero(chunk.code, 0xffff, &bytecode_arena); | 229 | disassemble_chunk(compiler.main_chunk); |
189 | sz n_roots = array_size(parser.nodes); | ||
190 | CompResult res = {0}; | ||
191 | for (sz i = 0; i < n_roots; i++) { | ||
192 | // The parser stores the root nodes as a stack. | ||
193 | Node *root = parser.nodes[i]; | ||
194 | res = compile_expr(&chunk, root); | ||
195 | if (res.type == COMP_ERR) { | ||
196 | eprintln("compilation error..."); | ||
197 | exit(EXIT_FAILURE); | ||
198 | } | ||
199 | } | ||
200 | // Make sure the last result is on r0. | ||
201 | sz res_reg = 0; | ||
202 | bool is_nil = false; | ||
203 | switch (res.type) { | ||
204 | case COMP_CONST: { | ||
205 | res_reg = chunk.reg_idx++; | ||
206 | Instruction inst = | ||
207 | (Instruction){.op = OP_LD64K, .dst = res_reg, .a = res.idx}; | ||
208 | array_push(chunk.code, inst, chunk.storage); | ||
209 | } break; | ||
210 | case COMP_REG: { | ||
211 | res_reg = res.idx; | ||
212 | } break; | ||
213 | case COMP_NIL: { | ||
214 | is_nil = true; | ||
215 | } break; | ||
216 | default: break; | ||
217 | } | ||
218 | EMIT_OP(OP_HALT, res_reg, !is_nil, 0, NULL, &chunk); | ||
219 | |||
220 | if (chunk.const_idx >= 256) { | ||
221 | eprintln("too many constants on chunk %s", chunk.id); | ||
222 | exit(EXIT_FAILURE); | ||
223 | } | ||
224 | if (chunk.str_idx >= 256) { | ||
225 | eprintln("too many strings on chunk %s", chunk.id); | ||
226 | exit(EXIT_FAILURE); | ||
227 | } | ||
228 | if (chunk.reg_idx >= 256) { | ||
229 | eprintln("too many registers used on chunk %s", chunk.id); | ||
230 | exit(EXIT_FAILURE); | ||
231 | } | ||
232 | |||
233 | disassemble_chunk(chunk); | ||
234 | 230 | ||
235 | // Run bytecode on VM. | 231 | // Run bytecode on VM. |
236 | VM vm = {0}; | 232 | VM vm = {0}; |
237 | vm_init(&vm, &chunk); | 233 | vm_init(&vm, &compiler.main_chunk); |
238 | // println("VM REGISTERS BEFORE:\n%{Mem}", | ||
239 | // &(Array){.mem = (u8 *)&vm.regs, sizeof(vm.regs)}); | ||
240 | vm_run(&vm); | 234 | vm_run(&vm); |
241 | #if DEBUG == 1 | 235 | #if DEBUG == 1 |
242 | println("MEMORY:\n%{Mem}", | 236 | println("MEMORY:\n%{Mem}", |
diff --git a/src/parser.c b/src/parser.c index 90adaf3..05a00e7 100644 --- a/src/parser.c +++ b/src/parser.c | |||
@@ -9,6 +9,7 @@ | |||
9 | // | 9 | // |
10 | 10 | ||
11 | typedef enum NodeKind { | 11 | typedef enum NodeKind { |
12 | NODE_ERR, | ||
12 | // Arithmetic. | 13 | // Arithmetic. |
13 | NODE_ADD, | 14 | NODE_ADD, |
14 | NODE_SUB, | 15 | NODE_SUB, |
@@ -29,6 +30,7 @@ typedef enum NodeKind { | |||
29 | NODE_BITNOT, | 30 | NODE_BITNOT, |
30 | NODE_BITAND, | 31 | NODE_BITAND, |
31 | NODE_BITOR, | 32 | NODE_BITOR, |
33 | NODE_BITXOR, | ||
32 | NODE_BITLSHIFT, | 34 | NODE_BITLSHIFT, |
33 | NODE_BITRSHIFT, | 35 | NODE_BITRSHIFT, |
34 | // Literals. | 36 | // Literals. |
@@ -60,15 +62,18 @@ typedef enum NodeKind { | |||
60 | NODE_FUNCALL, | 62 | NODE_FUNCALL, |
61 | NODE_RETURN, | 63 | NODE_RETURN, |
62 | // Helpers. | 64 | // Helpers. |
63 | NODE_SYMBOL_IDX, | ||
64 | NODE_TYPE, | 65 | NODE_TYPE, |
65 | NODE_COMPOUND_TYPE, | 66 | NODE_COMPOUND_TYPE, |
66 | NODE_ARR_TYPE, | ||
67 | NODE_FIELD, | 67 | NODE_FIELD, |
68 | NODE_BLOCK, | 68 | NODE_BLOCK, |
69 | NODE_PTR, | ||
70 | NODE_DEREF, | ||
71 | NODE_ARR, | ||
72 | NODE_INDEX, | ||
69 | } NodeKind; | 73 | } NodeKind; |
70 | 74 | ||
71 | Str node_str[] = { | 75 | Str node_str[] = { |
76 | [NODE_ERR] = cstr("ERR"), | ||
72 | // Arithmetic. | 77 | // Arithmetic. |
73 | [NODE_ADD] = cstr("ADD"), | 78 | [NODE_ADD] = cstr("ADD"), |
74 | [NODE_SUB] = cstr("SUB"), | 79 | [NODE_SUB] = cstr("SUB"), |
@@ -89,6 +94,7 @@ Str node_str[] = { | |||
89 | [NODE_BITNOT] = cstr("BITNOT"), | 94 | [NODE_BITNOT] = cstr("BITNOT"), |
90 | [NODE_BITAND] = cstr("BITAND"), | 95 | [NODE_BITAND] = cstr("BITAND"), |
91 | [NODE_BITOR] = cstr("BITOR"), | 96 | [NODE_BITOR] = cstr("BITOR"), |
97 | [NODE_BITXOR] = cstr("BITXOR"), | ||
92 | [NODE_BITLSHIFT] = cstr("BITLSHIFT"), | 98 | [NODE_BITLSHIFT] = cstr("BITLSHIFT"), |
93 | [NODE_BITRSHIFT] = cstr("BITRSHIFT"), | 99 | [NODE_BITRSHIFT] = cstr("BITRSHIFT"), |
94 | // Literals. | 100 | // Literals. |
@@ -122,81 +128,137 @@ Str node_str[] = { | |||
122 | // Helpers. | 128 | // Helpers. |
123 | [NODE_TYPE] = cstr("TYPE"), | 129 | [NODE_TYPE] = cstr("TYPE"), |
124 | [NODE_COMPOUND_TYPE] = cstr("COMPOUND TYPE"), | 130 | [NODE_COMPOUND_TYPE] = cstr("COMPOUND TYPE"), |
125 | [NODE_ARR_TYPE] = cstr("TYPE (ARR)"), | ||
126 | [NODE_SYMBOL_IDX] = cstr("SYMBOL[IDX]"), | ||
127 | [NODE_FIELD] = cstr("FIELD"), | 131 | [NODE_FIELD] = cstr("FIELD"), |
128 | [NODE_BLOCK] = cstr("BLOCK"), | 132 | [NODE_BLOCK] = cstr("BLOCK"), |
133 | [NODE_PTR] = cstr("@"), | ||
134 | [NODE_DEREF] = cstr("DEREF"), | ||
135 | [NODE_ARR] = cstr("ARR"), | ||
136 | [NODE_INDEX] = cstr("INDEX"), | ||
129 | }; | 137 | }; |
130 | 138 | ||
139 | typedef union NodeLit { | ||
140 | f64 d; | ||
141 | sz i; | ||
142 | u64 u; | ||
143 | Str str; | ||
144 | Str sym; | ||
145 | } NodeLit; | ||
146 | |||
147 | typedef struct NodeBinary { | ||
148 | struct Node *left; | ||
149 | struct Node *right; | ||
150 | } NodeBinary; | ||
151 | |||
152 | typedef struct NodeUnary { | ||
153 | struct Node *left; | ||
154 | } NodeUnary; | ||
155 | |||
156 | typedef struct NodeVariable { | ||
157 | struct Node *name; | ||
158 | struct Node *type; | ||
159 | struct Node *val; | ||
160 | } NodeVariable; | ||
161 | |||
162 | typedef struct NodeLoop { | ||
163 | struct Node *cond; | ||
164 | struct Node *expr; | ||
165 | } NodeLoop; | ||
166 | |||
167 | typedef struct NodeIf { | ||
168 | struct Node *cond; | ||
169 | struct Node *expr_true; | ||
170 | struct Node *expr_else; | ||
171 | } NodeIf; | ||
172 | |||
173 | typedef struct NodeField { | ||
174 | struct Node *type; | ||
175 | struct Node *val; | ||
176 | } NodeField; | ||
177 | |||
178 | typedef struct NodeParam { | ||
179 | struct Node *name; | ||
180 | struct Node *type; | ||
181 | } NodeParam; | ||
182 | |||
183 | typedef struct NodeMatch { | ||
184 | struct Node *expr; | ||
185 | struct Node **cases; | ||
186 | } NodeMatch; | ||
187 | |||
188 | typedef struct NodeCase { | ||
189 | struct Node *cond; | ||
190 | struct Node *expr; | ||
191 | } NodeCase; | ||
192 | |||
193 | typedef struct NodeFunction { | ||
194 | struct Node *name; | ||
195 | struct Node **params; | ||
196 | struct Node **ret; | ||
197 | struct Node *body; | ||
198 | } NodeFunction; | ||
199 | |||
200 | typedef struct NodeSymbol { | ||
201 | struct Node *next; | ||
202 | } NodeSymbol; | ||
203 | |||
204 | typedef struct NodeIndex { | ||
205 | struct Node *next; | ||
206 | struct Node *value; | ||
207 | } NodeIndex; | ||
208 | |||
209 | typedef struct NodeType { | ||
210 | struct Node *next; | ||
211 | } NodeType; | ||
212 | |||
213 | typedef struct NodeDeref { | ||
214 | struct Node *next; | ||
215 | } NodeDeref; | ||
216 | |||
217 | typedef enum { | ||
218 | NODE_ARR_STATIC, | ||
219 | NODE_ARR_DYNAMIC, | ||
220 | NODE_ARR_SLICE, | ||
221 | } NodeArrKind; | ||
222 | |||
223 | typedef struct NodeArr { | ||
224 | struct Node *next; | ||
225 | struct Node *size; | ||
226 | NodeArrKind kind; | ||
227 | } NodeArr; | ||
228 | |||
131 | typedef struct Node { | 229 | typedef struct Node { |
132 | sz id; | 230 | sz id; |
133 | sz line; | 231 | sz line; |
134 | sz col; | 232 | sz col; |
233 | struct Node *parent; | ||
135 | 234 | ||
136 | NodeKind kind; | 235 | NodeKind kind; |
236 | NodeLit value; | ||
137 | union { | 237 | union { |
138 | f64 d; | 238 | NodeBinary binary; |
139 | sz i; | 239 | NodeUnary unary; |
140 | u64 u; | 240 | NodeVariable var; |
141 | Str str; | 241 | NodeSymbol sym; |
142 | Str sym; | 242 | NodeLoop loop; |
143 | } value; | 243 | NodeIf ifelse; |
144 | union { | 244 | NodeField field; |
145 | struct { | 245 | NodeParam param; |
146 | struct Node *left; | 246 | NodeMatch match; |
147 | struct Node *right; | 247 | NodeCase case_entry; |
148 | }; | 248 | NodeFunction func; |
149 | struct { | 249 | NodeType t; |
150 | struct Node *next; | 250 | NodeIndex idx; |
151 | struct Node *arr_size; | 251 | NodeDeref deref; |
152 | }; | 252 | NodeArr array; |
153 | struct { | ||
154 | struct Node *var_name; | ||
155 | struct Node *var_type; | ||
156 | struct Node *var_val; | ||
157 | }; | ||
158 | struct { | ||
159 | struct Node *while_cond; | ||
160 | struct Node *while_expr; | ||
161 | }; | ||
162 | struct { | ||
163 | struct Node *cond_if; | ||
164 | struct Node *cond_expr; | ||
165 | struct Node *cond_else; | ||
166 | }; | ||
167 | struct { | ||
168 | struct Node *field_type; | ||
169 | struct Node *field_val; | ||
170 | }; | ||
171 | struct { | ||
172 | struct Node *param_name; | ||
173 | struct Node *param_type; | ||
174 | }; | ||
175 | struct { | ||
176 | struct Node *match_expr; | ||
177 | struct Node **match_cases; | ||
178 | }; | ||
179 | struct { | ||
180 | struct Node *case_value; | ||
181 | struct Node *case_expr; | ||
182 | }; | ||
183 | struct Node **struct_field; | 253 | struct Node **struct_field; |
184 | struct Node **elements; | 254 | struct Node **elements; |
185 | struct Node **statements; | 255 | struct Node **statements; |
186 | struct Node **expressions; | 256 | struct Node **expressions; |
187 | struct Node **arguments; | 257 | struct Node **arguments; |
188 | struct { | ||
189 | struct Node *func_name; | ||
190 | struct Node **func_params; | ||
191 | struct Node **func_ret; | ||
192 | struct Node *func_body; | ||
193 | }; | ||
194 | }; | 258 | }; |
195 | bool is_ptr; | ||
196 | struct Scope *scope; | ||
197 | Str type; | 259 | Str type; |
198 | Str fun_params; | 260 | Str type_params; |
199 | Str fun_return; | 261 | Str type_returns; |
200 | Str unique_name; | 262 | Str unique_name; |
201 | } Node; | 263 | } Node; |
202 | 264 | ||
@@ -286,6 +348,7 @@ ParseRule parse_rules[] = { | |||
286 | [TOK_BITNOT] = {parse_unary, NULL, PREC_NONE}, | 348 | [TOK_BITNOT] = {parse_unary, NULL, PREC_NONE}, |
287 | [TOK_BITAND] = {NULL, parse_binary, PREC_BITLOGIC}, | 349 | [TOK_BITAND] = {NULL, parse_binary, PREC_BITLOGIC}, |
288 | [TOK_BITOR] = {NULL, parse_binary, PREC_BITLOGIC}, | 350 | [TOK_BITOR] = {NULL, parse_binary, PREC_BITLOGIC}, |
351 | [TOK_BITXOR] = {NULL, parse_binary, PREC_BITLOGIC}, | ||
289 | [TOK_BITLSHIFT] = {NULL, parse_binary, PREC_BITSHIFT}, | 352 | [TOK_BITLSHIFT] = {NULL, parse_binary, PREC_BITSHIFT}, |
290 | [TOK_BITRSHIFT] = {NULL, parse_binary, PREC_BITSHIFT}, | 353 | [TOK_BITRSHIFT] = {NULL, parse_binary, PREC_BITSHIFT}, |
291 | 354 | ||
@@ -308,6 +371,7 @@ ParseRule parse_rules[] = { | |||
308 | [TOK_MATCH] = {parse_keyword, NULL, PREC_NONE}, | 371 | [TOK_MATCH] = {parse_keyword, NULL, PREC_NONE}, |
309 | [TOK_COND] = {parse_keyword, NULL, PREC_NONE}, | 372 | [TOK_COND] = {parse_keyword, NULL, PREC_NONE}, |
310 | [TOK_WHILE] = {parse_keyword, NULL, PREC_NONE}, | 373 | [TOK_WHILE] = {parse_keyword, NULL, PREC_NONE}, |
374 | [TOK_FOR] = {parse_keyword, NULL, PREC_NONE}, | ||
311 | [TOK_CONTINUE] = {parse_keyword, NULL, PREC_NONE}, | 375 | [TOK_CONTINUE] = {parse_keyword, NULL, PREC_NONE}, |
312 | [TOK_BREAK] = {parse_keyword, NULL, PREC_NONE}, | 376 | [TOK_BREAK] = {parse_keyword, NULL, PREC_NONE}, |
313 | [TOK_FUN] = {parse_keyword, NULL, PREC_NONE}, | 377 | [TOK_FUN] = {parse_keyword, NULL, PREC_NONE}, |
@@ -318,7 +382,6 @@ ParseRule parse_rules[] = { | |||
318 | 382 | ||
319 | Node * | 383 | Node * |
320 | node_alloc(Parser *parser, NodeKind kind, Token tok) { | 384 | node_alloc(Parser *parser, NodeKind kind, Token tok) { |
321 | if (parser->panic) return NULL; | ||
322 | static sz id = 0; | 385 | static sz id = 0; |
323 | Node *node = arena_calloc((sz)sizeof(Node), parser->storage); | 386 | Node *node = arena_calloc((sz)sizeof(Node), parser->storage); |
324 | node->id = id++; | 387 | node->id = id++; |
@@ -388,20 +451,44 @@ parse_block(Parser *parser) { | |||
388 | print_token(parser->previous); | 451 | print_token(parser->previous); |
389 | #endif | 452 | #endif |
390 | Node *block = node_alloc(parser, NODE_BLOCK, parser->previous); | 453 | Node *block = node_alloc(parser, NODE_BLOCK, parser->previous); |
391 | if (!block) return; | ||
392 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { | 454 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { |
393 | parse_expr(parser, PREC_LOW); | 455 | parse_expr(parser, PREC_LOW); |
394 | Node *next = array_pop(parser->nodes); | 456 | Node *next = array_pop(parser->nodes); |
457 | next->parent = block; | ||
395 | array_push(block->statements, next, parser->storage); | 458 | array_push(block->statements, next, parser->storage); |
396 | } | 459 | } |
397 | array_push(parser->nodes, block, parser->storage); | 460 | array_push(parser->nodes, block, parser->storage); |
398 | } | 461 | } |
399 | 462 | ||
400 | void | 463 | void |
464 | parser_sync(Parser *parser) { | ||
465 | parser->panic = false; | ||
466 | while (parser->current.kind != TOK_EOF) { | ||
467 | switch (parser->current.kind) { | ||
468 | case TOK_FUN: | ||
469 | case TOK_LET: | ||
470 | case TOK_SET: | ||
471 | case TOK_STRUCT: | ||
472 | case TOK_ENUM: | ||
473 | case TOK_FOR: | ||
474 | case TOK_IF: | ||
475 | case TOK_WHILE: | ||
476 | case TOK_BREAK: | ||
477 | case TOK_CONTINUE: | ||
478 | case TOK_COND: | ||
479 | case TOK_MATCH: | ||
480 | case TOK_CASE: | ||
481 | case TOK_RETURN: return; | ||
482 | default: break; | ||
483 | } | ||
484 | parse_advance(parser); | ||
485 | } | ||
486 | } | ||
487 | |||
488 | void | ||
401 | parse_expr(Parser *parser, ParsePrecedence precedence) { | 489 | parse_expr(Parser *parser, ParsePrecedence precedence) { |
402 | parse_advance(parser); | 490 | parse_advance(parser); |
403 | // TODO: synchronize panic mode on keywords. | 491 | if (parser->panic) parser_sync(parser); |
404 | if (parser->panic) return; | ||
405 | ParseFn prefix = parse_rules[parser->previous.kind].prefix; | 492 | ParseFn prefix = parse_rules[parser->previous.kind].prefix; |
406 | if (prefix == NULL) { | 493 | if (prefix == NULL) { |
407 | parse_emit_err(parser, parser->previous, cstr("expected expression")); | 494 | parse_emit_err(parser, parser->previous, cstr("expected expression")); |
@@ -436,8 +523,8 @@ parse_unary(Parser *parser) { | |||
436 | case TOK_BITNOT: node = node_alloc(parser, NODE_BITNOT, prev); break; | 523 | case TOK_BITNOT: node = node_alloc(parser, NODE_BITNOT, prev); break; |
437 | default: break; // Unreachable. | 524 | default: break; // Unreachable. |
438 | } | 525 | } |
439 | if (!node) return; | 526 | node->unary.left = array_pop(parser->nodes); |
440 | node->left = array_pop(parser->nodes); | 527 | node->unary.left->parent = node; |
441 | array_push(parser->nodes, node, parser->storage); | 528 | array_push(parser->nodes, node, parser->storage); |
442 | } | 529 | } |
443 | 530 | ||
@@ -459,7 +546,6 @@ parse_literal(Parser *parser) { | |||
459 | case TOK_NIL: node = node_alloc(parser, NODE_NIL, prev); break; | 546 | case TOK_NIL: node = node_alloc(parser, NODE_NIL, prev); break; |
460 | default: return; // Unreachable. | 547 | default: return; // Unreachable. |
461 | } | 548 | } |
462 | if (!node) return; | ||
463 | array_push(parser->nodes, node, parser->storage); | 549 | array_push(parser->nodes, node, parser->storage); |
464 | } | 550 | } |
465 | 551 | ||
@@ -471,21 +557,50 @@ parse_type(Parser *parser) { | |||
471 | print_token(prev); | 557 | print_token(prev); |
472 | #endif | 558 | #endif |
473 | Node *node = node_alloc(parser, NODE_TYPE, prev); | 559 | Node *node = node_alloc(parser, NODE_TYPE, prev); |
474 | if (!node) return; | 560 | Node *child = node; |
475 | if (parse_match(parser, TOK_AT)) { | 561 | while (parse_match(parser, TOK_AT) || parse_match(parser, TOK_LSQUARE)) { |
476 | node->is_ptr = true; | 562 | switch (parser->previous.kind) { |
563 | case TOK_AT: { | ||
564 | Node *ptr_node = node_alloc(parser, NODE_PTR, parser->previous); | ||
565 | ptr_node->parent = child; | ||
566 | child->t.next = ptr_node; | ||
567 | child = ptr_node; | ||
568 | } break; | ||
569 | case TOK_LSQUARE: { | ||
570 | Node *ptr_node = node_alloc(parser, NODE_ARR, parser->previous); | ||
571 | if (parse_match(parser, TOK_NUM_INT)) { | ||
572 | // Static array. | ||
573 | parse_number(parser); | ||
574 | ptr_node->array.size = array_pop(parser->nodes); | ||
575 | ptr_node->array.kind = NODE_ARR_STATIC; | ||
576 | ptr_node->array.size->parent = ptr_node; | ||
577 | parse_consume(parser, TOK_RSQUARE, | ||
578 | cstr("unmatched brackets ']' in array type")); | ||
579 | } else if (parse_match(parser, TOK_RSQUARE)) { | ||
580 | // Slice. | ||
581 | ptr_node->array.kind = NODE_ARR_SLICE; | ||
582 | } else { | ||
583 | // Dynamic array. | ||
584 | parse_consume(parser, TOK_DOT, cstr("invalid array type")); | ||
585 | parse_consume(parser, TOK_DOT, cstr("invalid array type")); | ||
586 | parse_consume(parser, TOK_DOT, cstr("invalid array type")); | ||
587 | parse_consume(parser, TOK_RSQUARE, | ||
588 | cstr("unmatched brackets ']' in array type")); | ||
589 | ptr_node->array.kind = NODE_ARR_DYNAMIC; | ||
590 | } | ||
591 | ptr_node->parent = child; | ||
592 | child->t.next = ptr_node; | ||
593 | child = ptr_node; | ||
594 | } break; | ||
595 | default: { | ||
596 | parse_emit_err(parser, prev, cstr("unimplemented")); | ||
597 | } break; | ||
598 | } | ||
477 | } | 599 | } |
478 | parse_consume(parser, TOK_SYMBOL, cstr("no type given for struct field")); | 600 | // TODO: maps |
601 | // TODO: function pointer syntax: : (T T : R) | ||
602 | parse_consume(parser, TOK_SYMBOL, cstr("expected type name")); | ||
479 | node->value.sym = parser->previous.val; | 603 | node->value.sym = parser->previous.val; |
480 | // Optional array value? | ||
481 | if (parse_match(parser, TOK_LSQUARE)) { | ||
482 | node->kind = NODE_ARR_TYPE, | ||
483 | parse_consume(parser, TOK_NUM_INT, cstr("no array size given")); | ||
484 | parse_number(parser); | ||
485 | node->arr_size = array_pop(parser->nodes); | ||
486 | parse_consume(parser, TOK_RSQUARE, | ||
487 | cstr("unmatched brackets ']' in array type")); | ||
488 | } | ||
489 | array_push(parser->nodes, node, parser->storage); | 604 | array_push(parser->nodes, node, parser->storage); |
490 | } | 605 | } |
491 | 606 | ||
@@ -497,29 +612,31 @@ parse_struct_field(Parser *parser) { | |||
497 | print_token(parser->previous); | 612 | print_token(parser->previous); |
498 | #endif | 613 | #endif |
499 | Node *field = node_alloc(parser, NODE_FIELD, parser->current); | 614 | Node *field = node_alloc(parser, NODE_FIELD, parser->current); |
500 | if (!field) return; | ||
501 | parse_consume(parser, TOK_SYMBOL, | 615 | parse_consume(parser, TOK_SYMBOL, |
502 | cstr("expected symbol name on struct field")); | 616 | cstr("expected symbol name on struct field")); |
503 | field->value.sym = parser->previous.val; | 617 | field->value.sym = parser->previous.val; |
504 | parse_consume(parser, TOK_COLON, cstr("expected type in struct field")); | 618 | parse_consume(parser, TOK_COLON, cstr("expected type in struct field")); |
505 | if (parse_match(parser, TOK_LCURLY)) { | 619 | if (parse_match(parser, TOK_LCURLY)) { |
506 | Node *type = node_alloc(parser, NODE_COMPOUND_TYPE, parser->current); | 620 | Node *type = node_alloc(parser, NODE_COMPOUND_TYPE, parser->current); |
507 | if (!type) return; | 621 | type->parent = field; |
508 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { | 622 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { |
509 | parse_struct_field(parser); | 623 | parse_struct_field(parser); |
510 | Node *subfield = array_pop(parser->nodes); | 624 | Node *subfield = array_pop(parser->nodes); |
625 | subfield->parent = type; | ||
511 | array_push(type->elements, subfield, parser->storage); | 626 | array_push(type->elements, subfield, parser->storage); |
512 | } | 627 | } |
513 | field->field_type = type; | 628 | field->field.type = type; |
514 | } else { | 629 | } else { |
515 | parse_type(parser); | 630 | parse_type(parser); |
516 | field->field_type = array_pop(parser->nodes); | 631 | field->field.type = array_pop(parser->nodes); |
632 | field->field.type->parent = field; | ||
517 | } | 633 | } |
518 | 634 | ||
519 | // Optional assignment. | 635 | // Optional assignment. |
520 | if (parse_match(parser, TOK_ASSIGN)) { | 636 | if (parse_match(parser, TOK_ASSIGN)) { |
521 | parse_expr(parser, PREC_LOW); | 637 | parse_expr(parser, PREC_LOW); |
522 | field->field_val = array_pop(parser->nodes); | 638 | field->field.val = array_pop(parser->nodes); |
639 | field->field.val->parent = field; | ||
523 | } | 640 | } |
524 | array_push(parser->nodes, field, parser->storage); | 641 | array_push(parser->nodes, field, parser->storage); |
525 | } | 642 | } |
@@ -532,7 +649,6 @@ parse_struct_lit_field(Parser *parser) { | |||
532 | print_token(parser->previous); | 649 | print_token(parser->previous); |
533 | #endif | 650 | #endif |
534 | Node *field = node_alloc(parser, NODE_FIELD, parser->current); | 651 | Node *field = node_alloc(parser, NODE_FIELD, parser->current); |
535 | if (!field) return; | ||
536 | parse_consume(parser, TOK_SYMBOL, | 652 | parse_consume(parser, TOK_SYMBOL, |
537 | cstr("expected symbol name on struct field")); | 653 | cstr("expected symbol name on struct field")); |
538 | field->value.sym = parser->previous.val; | 654 | field->value.sym = parser->previous.val; |
@@ -540,16 +656,18 @@ parse_struct_lit_field(Parser *parser) { | |||
540 | cstr("expected field value on struct literal")); | 656 | cstr("expected field value on struct literal")); |
541 | if (parse_match(parser, TOK_LCURLY)) { | 657 | if (parse_match(parser, TOK_LCURLY)) { |
542 | Node *type = node_alloc(parser, NODE_COMPOUND_TYPE, parser->current); | 658 | Node *type = node_alloc(parser, NODE_COMPOUND_TYPE, parser->current); |
543 | if (!type) return; | 659 | type->parent = field; |
544 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { | 660 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { |
545 | parse_struct_lit_field(parser); | 661 | parse_struct_lit_field(parser); |
546 | Node *subfield = array_pop(parser->nodes); | 662 | Node *subfield = array_pop(parser->nodes); |
663 | subfield->parent = type; | ||
547 | array_push(type->elements, subfield, parser->storage); | 664 | array_push(type->elements, subfield, parser->storage); |
548 | } | 665 | } |
549 | field->field_val = type; | 666 | field->field.val = type; |
550 | } else { | 667 | } else { |
551 | parse_expr(parser, PREC_LOW); | 668 | parse_expr(parser, PREC_LOW); |
552 | field->field_val = array_pop(parser->nodes); | 669 | field->field.val = array_pop(parser->nodes); |
670 | field->field.val->parent = field; | ||
553 | } | 671 | } |
554 | array_push(parser->nodes, field, parser->storage); | 672 | array_push(parser->nodes, field, parser->storage); |
555 | } | 673 | } |
@@ -566,12 +684,12 @@ parse_keyword(Parser *parser) { | |||
566 | switch (prev.kind) { | 684 | switch (prev.kind) { |
567 | case TOK_LET: { | 685 | case TOK_LET: { |
568 | node = node_alloc(parser, NODE_LET, prev); | 686 | node = node_alloc(parser, NODE_LET, prev); |
569 | if (!node) return; | ||
570 | parse_consume(parser, TOK_SYMBOL, | 687 | parse_consume(parser, TOK_SYMBOL, |
571 | cstr("expected symbol name on let expression")); | 688 | cstr("expected symbol name on let expression")); |
572 | parse_symbol(parser); | 689 | parse_symbol(parser); |
573 | node->var_name = array_pop(parser->nodes); | 690 | node->var.name = array_pop(parser->nodes); |
574 | if (node->var_name->next) { | 691 | node->var.name->parent = node; |
692 | if (node->var.name->sym.next) { | ||
575 | parse_emit_err(parser, prev, | 693 | parse_emit_err(parser, prev, |
576 | cstr("invalid symbol name in let expression")); | 694 | cstr("invalid symbol name in let expression")); |
577 | return; | 695 | return; |
@@ -580,16 +698,18 @@ parse_keyword(Parser *parser) { | |||
580 | // Optional type declaration. | 698 | // Optional type declaration. |
581 | if (parse_match(parser, TOK_COLON)) { | 699 | if (parse_match(parser, TOK_COLON)) { |
582 | parse_type(parser); | 700 | parse_type(parser); |
583 | node->var_type = array_pop(parser->nodes); | 701 | node->var.type = array_pop(parser->nodes); |
702 | node->var.type->parent = node; | ||
584 | } | 703 | } |
585 | 704 | ||
586 | // Optional assignment. | 705 | // Optional assignment. |
587 | if (parse_match(parser, TOK_ASSIGN)) { | 706 | if (parse_match(parser, TOK_ASSIGN)) { |
588 | parse_expr(parser, PREC_LOW); | 707 | parse_expr(parser, PREC_LOW); |
589 | node->var_val = array_pop(parser->nodes); | 708 | node->var.val = array_pop(parser->nodes); |
709 | node->var.val->parent = node; | ||
590 | } | 710 | } |
591 | 711 | ||
592 | if (node->var_type == NULL && node->var_val == NULL) { | 712 | if (node->var.type == NULL && node->var.val == NULL) { |
593 | parse_emit_err(parser, prev, | 713 | parse_emit_err(parser, prev, |
594 | cstr("variable declaration must include type or " | 714 | cstr("variable declaration must include type or " |
595 | "value information")); | 715 | "value information")); |
@@ -597,19 +717,58 @@ parse_keyword(Parser *parser) { | |||
597 | } break; | 717 | } break; |
598 | case TOK_SET: { | 718 | case TOK_SET: { |
599 | node = node_alloc(parser, NODE_SET, prev); | 719 | node = node_alloc(parser, NODE_SET, prev); |
600 | if (!node) return; | ||
601 | parse_consume(parser, TOK_SYMBOL, | 720 | parse_consume(parser, TOK_SYMBOL, |
602 | cstr("expected symbol name on let expression")); | 721 | cstr("expected symbol name on set expression")); |
603 | parse_symbol(parser); | 722 | parse_symbol(parser); |
604 | node->var_name = array_pop(parser->nodes); | 723 | node->var.name = array_pop(parser->nodes); |
605 | parse_consume(parser, TOK_ASSIGN, | 724 | node->var.name->parent = node; |
606 | cstr("expected assignment on set expression")); | 725 | |
607 | parse_expr(parser, PREC_LOW); | 726 | if (parse_match(parser, TOK_ADD_ASSIGN) || |
608 | node->var_val = array_pop(parser->nodes); | 727 | parse_match(parser, TOK_ADD_ASSIGN) || |
728 | parse_match(parser, TOK_SUB_ASSIGN) || | ||
729 | parse_match(parser, TOK_MUL_ASSIGN) || | ||
730 | parse_match(parser, TOK_DIV_ASSIGN) || | ||
731 | parse_match(parser, TOK_MOD_ASSIGN) || | ||
732 | parse_match(parser, TOK_BITAND_ASSIGN) || | ||
733 | parse_match(parser, TOK_BITOR_ASSIGN) || | ||
734 | parse_match(parser, TOK_BITXOR_ASSIGN) || | ||
735 | parse_match(parser, TOK_BITLSHIFT_ASSIGN) || | ||
736 | parse_match(parser, TOK_BITRSHIFT_ASSIGN)) { | ||
737 | NodeKind kind = NODE_ERR; | ||
738 | switch (parser->previous.kind) { | ||
739 | case TOK_ADD_ASSIGN: kind = NODE_ADD; break; | ||
740 | case TOK_SUB_ASSIGN: kind = NODE_SUB; break; | ||
741 | case TOK_MUL_ASSIGN: kind = NODE_MUL; break; | ||
742 | case TOK_DIV_ASSIGN: kind = NODE_DIV; break; | ||
743 | case TOK_MOD_ASSIGN: kind = NODE_MOD; break; | ||
744 | case TOK_BITAND_ASSIGN: kind = NODE_BITAND; break; | ||
745 | case TOK_BITOR_ASSIGN: kind = NODE_BITOR; break; | ||
746 | case TOK_BITXOR_ASSIGN: kind = NODE_BITXOR; break; | ||
747 | case TOK_BITLSHIFT_ASSIGN: kind = NODE_BITLSHIFT; break; | ||
748 | case TOK_BITRSHIFT_ASSIGN: kind = NODE_BITRSHIFT; break; | ||
749 | default: break; | ||
750 | } | ||
751 | parse_expr(parser, PREC_LOW); | ||
752 | Node *value = array_pop(parser->nodes); | ||
753 | Node *sym = node_alloc(parser, NODE_SYMBOL, prev); | ||
754 | Node *op = node_alloc(parser, kind, prev); | ||
755 | op->binary.left = sym; | ||
756 | op->binary.right = value; | ||
757 | sym->parent = op; | ||
758 | value->parent = op; | ||
759 | node->var.val = op; | ||
760 | node->var.val->parent = node; | ||
761 | sym->value = node->var.name->value; | ||
762 | sym->kind = node->var.name->kind; | ||
763 | } else { | ||
764 | parse_consume(parser, TOK_ASSIGN, | ||
765 | cstr("expected assignment on set expression")); | ||
766 | parse_expr(parser, PREC_LOW); | ||
767 | node->var.val = array_pop(parser->nodes); | ||
768 | } | ||
609 | } break; | 769 | } break; |
610 | case TOK_STRUCT: { | 770 | case TOK_STRUCT: { |
611 | node = node_alloc(parser, NODE_STRUCT, prev); | 771 | node = node_alloc(parser, NODE_STRUCT, prev); |
612 | if (!node) return; | ||
613 | parse_consume(parser, TOK_SYMBOL, | 772 | parse_consume(parser, TOK_SYMBOL, |
614 | cstr("expected symbol name on struct definition")); | 773 | cstr("expected symbol name on struct definition")); |
615 | // Just consume this to avoid conflicts with struct literals. | 774 | // Just consume this to avoid conflicts with struct literals. |
@@ -621,54 +780,53 @@ parse_keyword(Parser *parser) { | |||
621 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { | 780 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { |
622 | parse_struct_field(parser); | 781 | parse_struct_field(parser); |
623 | Node *field = array_pop(parser->nodes); | 782 | Node *field = array_pop(parser->nodes); |
624 | 783 | field->parent = node; | |
625 | array_push(node->struct_field, field, parser->storage); | 784 | array_push(node->struct_field, field, parser->storage); |
626 | } | 785 | } |
627 | } break; | 786 | } break; |
628 | case TOK_IF: { | 787 | case TOK_IF: { |
629 | node = node_alloc(parser, NODE_IF, prev); | 788 | node = node_alloc(parser, NODE_IF, prev); |
630 | if (!node) return; | ||
631 | parse_expr(parser, PREC_LOW); | 789 | parse_expr(parser, PREC_LOW); |
632 | node->cond_if = array_pop(parser->nodes); | 790 | node->ifelse.cond = array_pop(parser->nodes); |
791 | node->ifelse.cond->parent = node; | ||
633 | parse_expr(parser, PREC_LOW); | 792 | parse_expr(parser, PREC_LOW); |
634 | node->cond_expr = array_pop(parser->nodes); | 793 | node->ifelse.expr_true = array_pop(parser->nodes); |
794 | node->ifelse.expr_true->parent = node; | ||
635 | if (parse_match(parser, TOK_ELSE)) { | 795 | if (parse_match(parser, TOK_ELSE)) { |
636 | parse_expr(parser, PREC_LOW); | 796 | parse_expr(parser, PREC_LOW); |
637 | node->cond_else = array_pop(parser->nodes); | 797 | node->ifelse.expr_else = array_pop(parser->nodes); |
798 | node->ifelse.expr_else->parent = node; | ||
638 | } | 799 | } |
639 | } break; | 800 | } break; |
640 | case TOK_MATCH: { | 801 | case TOK_MATCH: { |
641 | node = node_alloc(parser, NODE_MATCH, prev); | 802 | node = node_alloc(parser, NODE_MATCH, prev); |
642 | if (!node) return; | ||
643 | parse_expr(parser, PREC_LOW); | 803 | parse_expr(parser, PREC_LOW); |
644 | node->match_expr = array_pop(parser->nodes); | 804 | node->match.expr = array_pop(parser->nodes); |
805 | node->match.expr->parent = node; | ||
645 | parse_consume(parser, TOK_LCURLY, | 806 | parse_consume(parser, TOK_LCURLY, |
646 | cstr("expected block of match cases")); | 807 | cstr("expected block of match cases")); |
647 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { | 808 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { |
648 | Node *tmp = | 809 | Node *tmp = |
649 | node_alloc(parser, NODE_CASE_MATCH, parser->previous); | 810 | node_alloc(parser, NODE_CASE_MATCH, parser->previous); |
650 | if (!tmp) return; | 811 | tmp->parent = node; |
651 | // Are we on the default case. | 812 | // Are we on the default case. |
652 | if (!parse_match(parser, TOK_ELSE)) { | 813 | if (!parse_match(parser, TOK_ELSE)) { |
653 | parse_consume(parser, TOK_CASE, | 814 | parse_consume(parser, TOK_CASE, |
654 | cstr("expected case statement")); | 815 | cstr("expected case statement")); |
655 | parse_expr(parser, PREC_LOW); | 816 | parse_expr(parser, PREC_LOW); |
656 | tmp->case_value = array_pop(parser->nodes); | 817 | tmp->case_entry.cond = array_pop(parser->nodes); |
818 | tmp->case_entry.cond->parent = tmp; | ||
657 | } | 819 | } |
658 | parse_consume(parser, TOK_ASSIGN, | 820 | parse_consume(parser, TOK_ASSIGN, |
659 | cstr("malformed case statement")); | 821 | cstr("malformed case statement")); |
660 | parse_expr(parser, PREC_LOW); | 822 | parse_expr(parser, PREC_LOW); |
661 | tmp->case_expr = array_pop(parser->nodes); | 823 | tmp->case_entry.expr = array_pop(parser->nodes); |
662 | array_push(node->match_cases, tmp, parser->storage); | 824 | tmp->case_entry.expr->parent = tmp; |
825 | array_push(node->match.cases, tmp, parser->storage); | ||
663 | } | 826 | } |
664 | // TODO: Check that we only have literals on the match case, | ||
665 | // this could be done on the analysis step, but also here... | ||
666 | // TODO: Check that there are no multiple default or duplicated | ||
667 | // cases. | ||
668 | } break; | 827 | } break; |
669 | case TOK_ENUM: { | 828 | case TOK_ENUM: { |
670 | node = node_alloc(parser, NODE_ENUM, prev); | 829 | node = node_alloc(parser, NODE_ENUM, prev); |
671 | if (!node) return; | ||
672 | parse_consume(parser, TOK_SYMBOL, | 830 | parse_consume(parser, TOK_SYMBOL, |
673 | cstr("expected symbol name on enum definition")); | 831 | cstr("expected symbol name on enum definition")); |
674 | // Just consume this to avoid conflicts with struct literals. | 832 | // Just consume this to avoid conflicts with struct literals. |
@@ -677,13 +835,14 @@ parse_keyword(Parser *parser) { | |||
677 | cstr("expected '{' on enum definition")); | 835 | cstr("expected '{' on enum definition")); |
678 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { | 836 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { |
679 | Node *field = node_alloc(parser, NODE_FIELD, parser->current); | 837 | Node *field = node_alloc(parser, NODE_FIELD, parser->current); |
680 | if (!field) return; | 838 | field->parent = node; |
681 | parse_consume(parser, TOK_SYMBOL, | 839 | parse_consume(parser, TOK_SYMBOL, |
682 | cstr("expected symbol name on enum definition")); | 840 | cstr("expected symbol name on enum definition")); |
683 | field->value.sym = parser->previous.val; | 841 | field->value.sym = parser->previous.val; |
684 | if (parse_match(parser, TOK_ASSIGN)) { | 842 | if (parse_match(parser, TOK_ASSIGN)) { |
685 | parse_expr(parser, PREC_LOW); | 843 | parse_expr(parser, PREC_LOW); |
686 | field->field_val = array_pop(parser->nodes); | 844 | field->field.val = array_pop(parser->nodes); |
845 | field->field.val->parent = field; | ||
687 | } | 846 | } |
688 | array_push(node->struct_field, field, parser->storage); | 847 | array_push(node->struct_field, field, parser->storage); |
689 | } | 848 | } |
@@ -693,144 +852,133 @@ parse_keyword(Parser *parser) { | |||
693 | } break; | 852 | } break; |
694 | case TOK_COND: { | 853 | case TOK_COND: { |
695 | node = node_alloc(parser, NODE_COND, prev); | 854 | node = node_alloc(parser, NODE_COND, prev); |
696 | if (!node) return; | ||
697 | parse_consume(parser, TOK_LCURLY, | 855 | parse_consume(parser, TOK_LCURLY, |
698 | cstr("expected '{' on cond expression")); | 856 | cstr("expected '{' on cond expression")); |
699 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { | 857 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { |
700 | Node *tmp = | 858 | Node *tmp = |
701 | node_alloc(parser, NODE_CASE_COND, parser->previous); | 859 | node_alloc(parser, NODE_CASE_COND, parser->previous); |
702 | if (!tmp) return; | 860 | tmp->parent = node; |
703 | // Are we on the default case. | 861 | // Are we on the default case. |
704 | if (!parse_match(parser, TOK_ELSE)) { | 862 | if (!parse_match(parser, TOK_ELSE)) { |
705 | parse_expr(parser, PREC_LOW); | 863 | parse_expr(parser, PREC_LOW); |
706 | tmp->case_value = array_pop(parser->nodes); | 864 | tmp->case_entry.cond = array_pop(parser->nodes); |
865 | tmp->case_entry.cond->parent = tmp; | ||
707 | } | 866 | } |
708 | parse_consume(parser, TOK_ASSIGN, | 867 | parse_consume(parser, TOK_ASSIGN, |
709 | cstr("malformed case statement")); | 868 | cstr("malformed case statement")); |
710 | parse_expr(parser, PREC_LOW); | 869 | parse_expr(parser, PREC_LOW); |
711 | tmp->case_expr = array_pop(parser->nodes); | 870 | tmp->case_entry.expr = array_pop(parser->nodes); |
712 | array_push(node->match_cases, tmp, parser->storage); | 871 | tmp->case_entry.expr->parent = tmp; |
872 | array_push(node->match.cases, tmp, parser->storage); | ||
713 | } | 873 | } |
714 | } break; | 874 | } break; |
715 | case TOK_BREAK: { | 875 | case TOK_BREAK: { |
716 | node = node_alloc(parser, NODE_BREAK, prev); | 876 | node = node_alloc(parser, NODE_BREAK, prev); |
717 | if (!node) return; | ||
718 | } break; | 877 | } break; |
719 | case TOK_CONTINUE: { | 878 | case TOK_CONTINUE: { |
720 | node = node_alloc(parser, NODE_CONTINUE, prev); | 879 | node = node_alloc(parser, NODE_CONTINUE, prev); |
721 | if (!node) return; | 880 | } break; |
881 | case TOK_FOR: { | ||
882 | node = node_alloc(parser, NODE_BLOCK, prev); | ||
883 | |||
884 | Node *node_while = node_alloc(parser, NODE_WHILE, prev); | ||
885 | node_while->parent = node; | ||
886 | Node *block = node_alloc(parser, NODE_BLOCK, prev); | ||
887 | block->parent = node_while; | ||
888 | |||
889 | parse_expr(parser, PREC_LOW); | ||
890 | Node *pre = array_pop(parser->nodes); | ||
891 | pre->parent = node; | ||
892 | |||
893 | parse_expr(parser, PREC_LOW); | ||
894 | Node *cond = array_pop(parser->nodes); | ||
895 | cond->parent = node_while; | ||
896 | |||
897 | parse_expr(parser, PREC_LOW); | ||
898 | Node *post = array_pop(parser->nodes); | ||
899 | post->parent = block; | ||
900 | |||
901 | // Body. | ||
902 | parse_consume(parser, TOK_LCURLY, | ||
903 | cstr("expected '{' on for loop statement")); | ||
904 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { | ||
905 | parse_expr(parser, PREC_LOW); | ||
906 | Node *next = array_pop(parser->nodes); | ||
907 | next->parent = block; | ||
908 | array_push(block->statements, next, parser->storage); | ||
909 | } | ||
910 | array_push(block->statements, post, parser->storage); | ||
911 | |||
912 | // Put everything together | ||
913 | node_while->loop.cond = cond; | ||
914 | node_while->loop.expr = block; | ||
915 | array_push(node->statements, pre, parser->storage); | ||
916 | array_push(node->statements, node_while, parser->storage); | ||
722 | } break; | 917 | } break; |
723 | case TOK_WHILE: { | 918 | case TOK_WHILE: { |
724 | node = node_alloc(parser, NODE_WHILE, prev); | 919 | node = node_alloc(parser, NODE_WHILE, prev); |
725 | if (!node) return; | ||
726 | parse_expr(parser, PREC_LOW); | 920 | parse_expr(parser, PREC_LOW); |
727 | node->while_cond = array_pop(parser->nodes); | 921 | node->loop.cond = array_pop(parser->nodes); |
922 | node->loop.cond->parent = node; | ||
728 | parse_expr(parser, PREC_LOW); | 923 | parse_expr(parser, PREC_LOW); |
729 | node->while_expr = array_pop(parser->nodes); | 924 | node->loop.expr = array_pop(parser->nodes); |
925 | node->loop.expr->parent = node; | ||
730 | } break; | 926 | } break; |
731 | case TOK_FUN: { | 927 | case TOK_FUN: { |
732 | node = node_alloc(parser, NODE_FUN, prev); | 928 | node = node_alloc(parser, NODE_FUN, prev); |
733 | if (!node) return; | ||
734 | parse_consume(parser, TOK_SYMBOL, cstr("expected function name")); | 929 | parse_consume(parser, TOK_SYMBOL, cstr("expected function name")); |
735 | Node *name = node_alloc(parser, NODE_SYMBOL, prev); | 930 | Node *name = node_alloc(parser, NODE_SYMBOL, prev); |
736 | if (!name) return; | 931 | name->parent = node; |
737 | name->value.sym = parser->previous.val; | 932 | name->value.sym = parser->previous.val; |
738 | node->func_name = name; | 933 | node->func.name = name; |
739 | parse_consume(parser, TOK_LPAREN, | 934 | parse_consume(parser, TOK_LPAREN, |
740 | cstr("expected '(' on function definition")); | 935 | cstr("expected '(' on function definition")); |
741 | // Parameters. | 936 | // Parameters. |
742 | while (!parse_match(parser, TOK_RPAREN) && !parser->panic) { | 937 | while (!parse_match(parser, TOK_RPAREN) && !parser->panic) { |
743 | Node *param = | 938 | Node *param = |
744 | node_alloc(parser, NODE_FUN_PARAM, parser->current); | 939 | node_alloc(parser, NODE_FUN_PARAM, parser->current); |
745 | if (!param) return; | 940 | param->parent = node; |
941 | |||
942 | // Name. | ||
746 | Node *name = node_alloc(parser, NODE_SYMBOL, prev); | 943 | Node *name = node_alloc(parser, NODE_SYMBOL, prev); |
747 | if (!name) return; | ||
748 | parse_consume(parser, TOK_SYMBOL, cstr("expected symbol name")); | 944 | parse_consume(parser, TOK_SYMBOL, cstr("expected symbol name")); |
749 | name->value.sym = parser->previous.val; | 945 | name->value.sym = parser->previous.val; |
750 | param->param_name = name; | ||
751 | 946 | ||
752 | Node *type = node_alloc(parser, NODE_TYPE, prev); | 947 | // Type. |
753 | if (!type) return; | ||
754 | parse_consume(parser, TOK_COLON, cstr("expected param type")); | 948 | parse_consume(parser, TOK_COLON, cstr("expected param type")); |
755 | if (parse_match(parser, TOK_AT)) { | 949 | parse_type(parser); |
756 | type->is_ptr = true; | 950 | |
757 | } | 951 | // Put everything together. |
758 | parse_consume(parser, TOK_SYMBOL, cstr("expected param type")); | 952 | param->param.name = name; |
759 | type->value.sym = parser->previous.val; | 953 | param->param.type = array_pop(parser->nodes); |
760 | param->param_type = type; | 954 | param->param.name->parent = param; |
761 | if (parse_match(parser, TOK_LSQUARE)) { | 955 | param->param.type->parent = param; |
762 | type->kind = NODE_ARR_TYPE, | 956 | array_push(node->func.params, param, parser->storage); |
763 | parse_consume(parser, TOK_NUM_INT, | ||
764 | cstr("no array size given")); | ||
765 | parse_number(parser); | ||
766 | type->arr_size = array_pop(parser->nodes); | ||
767 | parse_consume(parser, TOK_RSQUARE, | ||
768 | cstr("unmatched brackets ']' in array type")); | ||
769 | } | ||
770 | array_push(node->func_params, param, parser->storage); | ||
771 | } | 957 | } |
772 | parse_consume(parser, TOK_COLON, cstr("expected param type")); | ||
773 | 958 | ||
774 | // Return type(s). | 959 | // Return type(s). |
775 | if (!parse_match(parser, TOK_NIL)) { | 960 | // NOTE: We are setup here for multiple return values, but we are |
776 | if (parse_match(parser, TOK_LPAREN)) { | 961 | // currently only considering a single one for simplicity. |
777 | while (!parse_match(parser, TOK_RPAREN) && !parser->panic) { | 962 | if (parse_match(parser, TOK_COLON)) { |
778 | Node *ret = node_alloc(parser, NODE_TYPE, prev); | 963 | parse_type(parser); |
779 | if (!ret) return; | 964 | Node *ret = array_pop(parser->nodes); |
780 | if (parse_match(parser, TOK_AT)) { | 965 | ret->parent = node; |
781 | ret->is_ptr = true; | 966 | array_push(node->func.ret, ret, parser->storage); |
782 | } | ||
783 | parse_consume(parser, TOK_SYMBOL, | ||
784 | cstr("expected type name")); | ||
785 | ret->value.sym = parser->previous.val; | ||
786 | if (parse_match(parser, TOK_LSQUARE)) { | ||
787 | ret->kind = NODE_ARR_TYPE, | ||
788 | parse_consume(parser, TOK_NUM_INT, | ||
789 | cstr("no array size given")); | ||
790 | parse_number(parser); | ||
791 | ret->arr_size = array_pop(parser->nodes); | ||
792 | parse_consume(parser, TOK_RSQUARE, | ||
793 | cstr("unmatched brackets ']' in " | ||
794 | "array type")); | ||
795 | } | ||
796 | array_push(node->func_ret, ret, parser->storage); | ||
797 | } | ||
798 | } else { | ||
799 | Node *ret = node_alloc(parser, NODE_TYPE, prev); | ||
800 | if (!ret) return; | ||
801 | if (parse_match(parser, TOK_AT)) { | ||
802 | ret->is_ptr = true; | ||
803 | } | ||
804 | parse_consume(parser, TOK_SYMBOL, | ||
805 | cstr("expected type name")); | ||
806 | ret->value.sym = parser->previous.val; | ||
807 | if (parse_match(parser, TOK_LSQUARE)) { | ||
808 | ret->kind = NODE_ARR_TYPE, | ||
809 | parse_consume(parser, TOK_NUM_INT, | ||
810 | cstr("no array size given")); | ||
811 | parse_number(parser); | ||
812 | ret->arr_size = array_pop(parser->nodes); | ||
813 | parse_consume( | ||
814 | parser, TOK_RSQUARE, | ||
815 | cstr("unmatched brackets ']' in array type")); | ||
816 | } | ||
817 | array_push(node->func_ret, ret, parser->storage); | ||
818 | } | ||
819 | } | 967 | } |
820 | 968 | ||
821 | // Body. | 969 | // Body. |
822 | parse_expr(parser, PREC_LOW); | 970 | parse_expr(parser, PREC_LOW); |
823 | node->func_body = array_pop(parser->nodes); | 971 | node->func.body = array_pop(parser->nodes); |
824 | } break; | 972 | } break; |
825 | case TOK_RETURN: { | 973 | case TOK_RETURN: { |
826 | node = node_alloc(parser, NODE_RETURN, prev); | 974 | node = node_alloc(parser, NODE_RETURN, prev); |
827 | if (!node) return; | ||
828 | parse_consume(parser, TOK_LPAREN, | 975 | parse_consume(parser, TOK_LPAREN, |
829 | cstr("expected '(' after return")); | 976 | cstr("expected '(' after return")); |
830 | while (!parse_match(parser, TOK_RPAREN) && !parser->panic) { | 977 | while (!parse_match(parser, TOK_RPAREN) && !parser->panic) { |
831 | parse_expr(parser, PREC_LOW); | 978 | parse_expr(parser, PREC_LOW); |
832 | array_push(node->expressions, array_pop(parser->nodes), | 979 | Node *val = array_pop(parser->nodes); |
833 | parser->storage); | 980 | val->parent = node; |
981 | array_push(node->expressions, val, parser->storage); | ||
834 | } | 982 | } |
835 | } break; | 983 | } break; |
836 | default: return; // Unreachable. | 984 | default: return; // Unreachable. |
@@ -870,6 +1018,9 @@ parse_binary(Parser *parser) { | |||
870 | case TOK_BITOR: { | 1018 | case TOK_BITOR: { |
871 | node = node_alloc(parser, NODE_BITOR, prev); | 1019 | node = node_alloc(parser, NODE_BITOR, prev); |
872 | } break; | 1020 | } break; |
1021 | case TOK_BITXOR: { | ||
1022 | node = node_alloc(parser, NODE_BITXOR, prev); | ||
1023 | } break; | ||
873 | case TOK_BITLSHIFT: { | 1024 | case TOK_BITLSHIFT: { |
874 | node = node_alloc(parser, NODE_BITLSHIFT, prev); | 1025 | node = node_alloc(parser, NODE_BITLSHIFT, prev); |
875 | } break; | 1026 | } break; |
@@ -881,9 +1032,10 @@ parse_binary(Parser *parser) { | |||
881 | return; | 1032 | return; |
882 | } | 1033 | } |
883 | } | 1034 | } |
884 | if (!node) return; | 1035 | node->binary.right = array_pop(parser->nodes); |
885 | node->right = array_pop(parser->nodes); | 1036 | node->binary.left = array_pop(parser->nodes); |
886 | node->left = array_pop(parser->nodes); | 1037 | node->binary.right->parent = node; |
1038 | node->binary.left->parent = node; | ||
887 | array_push(parser->nodes, node, parser->storage); | 1039 | array_push(parser->nodes, node, parser->storage); |
888 | } | 1040 | } |
889 | 1041 | ||
@@ -901,22 +1053,18 @@ parse_number(Parser *parser) { | |||
901 | if (str_has_prefix(prev.val, cstr("0x")) || | 1053 | if (str_has_prefix(prev.val, cstr("0x")) || |
902 | str_has_prefix(prev.val, cstr("0b"))) { | 1054 | str_has_prefix(prev.val, cstr("0b"))) { |
903 | node = node_alloc(parser, NODE_NUM_UINT, prev); | 1055 | node = node_alloc(parser, NODE_NUM_UINT, prev); |
904 | if (!node) return; | ||
905 | node->value.u = str_to_uint(prev.val); | 1056 | node->value.u = str_to_uint(prev.val); |
906 | } else { | 1057 | } else { |
907 | node = node_alloc(parser, NODE_NUM_INT, prev); | 1058 | node = node_alloc(parser, NODE_NUM_INT, prev); |
908 | if (!node) return; | ||
909 | node->value.i = str_to_int(prev.val); | 1059 | node->value.i = str_to_int(prev.val); |
910 | } | 1060 | } |
911 | } break; | 1061 | } break; |
912 | case TOK_NUM_FLOAT: { | 1062 | case TOK_NUM_FLOAT: { |
913 | node = node_alloc(parser, NODE_NUM_FLOAT, prev); | 1063 | node = node_alloc(parser, NODE_NUM_FLOAT, prev); |
914 | if (!node) return; | ||
915 | node->value.d = str_to_float(prev.val); | 1064 | node->value.d = str_to_float(prev.val); |
916 | } break; | 1065 | } break; |
917 | case TOK_CHAR: { | 1066 | case TOK_CHAR: { |
918 | node = node_alloc(parser, NODE_NUM_INT, prev); | 1067 | node = node_alloc(parser, NODE_NUM_INT, prev); |
919 | if (!node) return; | ||
920 | node->value.i = prev.val.mem[1]; | 1068 | node->value.i = prev.val.mem[1]; |
921 | } break; | 1069 | } break; |
922 | default: break; | 1070 | default: break; |
@@ -933,7 +1081,6 @@ parse_string(Parser *parser) { | |||
933 | print_token(prev); | 1081 | print_token(prev); |
934 | #endif | 1082 | #endif |
935 | Node *node = node_alloc(parser, NODE_STRING, prev); | 1083 | Node *node = node_alloc(parser, NODE_STRING, prev); |
936 | if (!node) return; | ||
937 | node->value.str = str_remove_prefix(prev.val, cstr("\"")); | 1084 | node->value.str = str_remove_prefix(prev.val, cstr("\"")); |
938 | node->value.str = str_remove_suffix(node->value.str, cstr("\"")); | 1085 | node->value.str = str_remove_suffix(node->value.str, cstr("\"")); |
939 | array_push(parser->nodes, node, parser->storage); | 1086 | array_push(parser->nodes, node, parser->storage); |
@@ -947,25 +1094,27 @@ parse_symbol(Parser *parser) { | |||
947 | print("parsing symbol "); | 1094 | print("parsing symbol "); |
948 | print_token(prev); | 1095 | print_token(prev); |
949 | #endif | 1096 | #endif |
1097 | // Dereference operators. | ||
950 | if (prev.kind == TOK_AT) { | 1098 | if (prev.kind == TOK_AT) { |
1099 | Node *node = node_alloc(parser, NODE_PTR, parser->previous); | ||
951 | parse_consume(parser, TOK_SYMBOL, | 1100 | parse_consume(parser, TOK_SYMBOL, |
952 | cstr("expected symbol after '.' operator")); | 1101 | cstr("expected symbol after '@' operator")); |
953 | parse_symbol(parser); | 1102 | parse_symbol(parser); |
954 | Node *node = array_pop(parser->nodes); | 1103 | node->t.next = array_pop(parser->nodes); |
955 | if (node) { | 1104 | node->t.next->parent = node; |
956 | node->is_ptr = true; | 1105 | array_push(parser->nodes, node, parser->storage); |
957 | array_push(parser->nodes, node, parser->storage); | ||
958 | } | ||
959 | return; | 1106 | return; |
960 | } | 1107 | } |
1108 | |||
961 | Node *node = node_alloc(parser, NODE_SYMBOL, prev); | 1109 | Node *node = node_alloc(parser, NODE_SYMBOL, prev); |
962 | if (!node) return; | 1110 | node->value.sym = prev.val; |
963 | if (parse_match(parser, TOK_DOT)) { | 1111 | if (parse_match(parser, TOK_DOT)) { |
964 | // Symbol chain. | 1112 | // Symbol chain. |
965 | parse_consume(parser, TOK_SYMBOL, | 1113 | parse_consume(parser, TOK_SYMBOL, |
966 | cstr("expected symbol after '.' operator")); | 1114 | cstr("expected symbol after '.' operator")); |
967 | parse_symbol(parser); | 1115 | parse_symbol(parser); |
968 | node->next = array_pop(parser->nodes); | 1116 | node->sym.next = array_pop(parser->nodes); |
1117 | node->sym.next->parent = node; | ||
969 | } else if (parser->current.kind == TOK_COLON && | 1118 | } else if (parser->current.kind == TOK_COLON && |
970 | parse_peek(parser) == TOK_LCURLY) { | 1119 | parse_peek(parser) == TOK_LCURLY) { |
971 | parse_advance(parser); | 1120 | parse_advance(parser); |
@@ -976,37 +1125,62 @@ parse_symbol(Parser *parser) { | |||
976 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { | 1125 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { |
977 | parse_struct_lit_field(parser); | 1126 | parse_struct_lit_field(parser); |
978 | Node *field = array_pop(parser->nodes); | 1127 | Node *field = array_pop(parser->nodes); |
1128 | field->parent = node; | ||
979 | array_push(node->elements, field, parser->storage); | 1129 | array_push(node->elements, field, parser->storage); |
980 | } | 1130 | } |
981 | } else if (parse_match(parser, TOK_LSQUARE)) { | 1131 | } else if (parse_match(parser, TOK_LSQUARE)) { |
982 | node->kind = NODE_SYMBOL_IDX; | 1132 | Node *index = node_alloc(parser, NODE_INDEX, prev); |
1133 | Node *start = index; | ||
983 | parse_expr(parser, PREC_LOW); | 1134 | parse_expr(parser, PREC_LOW); |
984 | node->arr_size = array_pop(parser->nodes); | ||
985 | parse_consume(parser, TOK_RSQUARE, | 1135 | parse_consume(parser, TOK_RSQUARE, |
986 | cstr("unmatched brackets ']' in array type")); | 1136 | cstr("unmatched brackets ']' in array type")); |
987 | if (parse_match(parser, TOK_DOT)) { | 1137 | index->idx.value = array_pop(parser->nodes); |
988 | // Symbol chain. | 1138 | index->idx.value->parent = start; |
989 | parse_consume(parser, TOK_SYMBOL, | 1139 | while (parse_match(parser, TOK_LSQUARE)) { |
990 | cstr("expected symbol after '.' operator")); | 1140 | Node *next = node_alloc(parser, NODE_INDEX, prev); |
991 | parse_symbol(parser); | 1141 | parse_expr(parser, PREC_LOW); |
992 | node->next = array_pop(parser->nodes); | 1142 | parse_consume(parser, TOK_RSQUARE, |
1143 | cstr("unmatched brackets ']' in array type")); | ||
1144 | next->idx.value = array_pop(parser->nodes); | ||
1145 | next->parent = index; | ||
1146 | index->idx.next = next; | ||
1147 | index = next; | ||
993 | } | 1148 | } |
1149 | |||
1150 | index->idx.next = node; | ||
1151 | index->idx.next->parent = index; | ||
1152 | array_push(parser->nodes, start, parser->storage); | ||
1153 | return; | ||
994 | } else if (parse_match(parser, TOK_LPAREN)) { | 1154 | } else if (parse_match(parser, TOK_LPAREN)) { |
995 | node->kind = NODE_FUNCALL; | 1155 | node->kind = NODE_FUNCALL; |
996 | while (!parse_match(parser, TOK_RPAREN) && !parser->panic) { | 1156 | while (!parse_match(parser, TOK_RPAREN) && !parser->panic) { |
997 | parse_expr(parser, PREC_LOW); | 1157 | parse_expr(parser, PREC_LOW); |
998 | array_push(node->arguments, array_pop(parser->nodes), | 1158 | Node *arg = array_pop(parser->nodes); |
999 | parser->storage); | 1159 | arg->parent = node; |
1160 | array_push(node->arguments, arg, parser->storage); | ||
1000 | } | 1161 | } |
1001 | if (parse_match(parser, TOK_DOT)) { | 1162 | if (parse_match(parser, TOK_DOT)) { |
1002 | // Symbol chain. | 1163 | // Symbol chain. |
1003 | parse_consume(parser, TOK_SYMBOL, | 1164 | parse_consume(parser, TOK_SYMBOL, |
1004 | cstr("expected symbol after '.' operator")); | 1165 | cstr("expected symbol after '.' operator")); |
1005 | parse_symbol(parser); | 1166 | parse_symbol(parser); |
1006 | node->next = array_pop(parser->nodes); | 1167 | node->sym.next = array_pop(parser->nodes); |
1168 | node->sym.next->parent = node; | ||
1169 | } | ||
1170 | } else if (parse_match(parser, TOK_AT)) { | ||
1171 | Node *deref = node_alloc(parser, NODE_DEREF, prev); | ||
1172 | Node *start = deref; | ||
1173 | while (parse_match(parser, TOK_AT)) { | ||
1174 | Node *next = node_alloc(parser, NODE_DEREF, prev); | ||
1175 | next->parent = deref; | ||
1176 | deref->deref.next = next; | ||
1177 | deref = next; | ||
1007 | } | 1178 | } |
1179 | deref->deref.next = node; | ||
1180 | deref->deref.next->parent = deref; | ||
1181 | array_push(parser->nodes, start, parser->storage); | ||
1182 | return; | ||
1008 | } | 1183 | } |
1009 | node->value.sym = prev.val; | ||
1010 | array_push(parser->nodes, node, parser->storage); | 1184 | array_push(parser->nodes, node, parser->storage); |
1011 | } | 1185 | } |
1012 | 1186 | ||
@@ -1032,62 +1206,71 @@ graph_node(Node *node) { | |||
1032 | case NODE_NUM_UINT: print("| Value: %x", node->value.u); break; | 1206 | case NODE_NUM_UINT: print("| Value: %x", node->value.u); break; |
1033 | case NODE_NUM_FLOAT: print("| Value: %f{2}", node->value.d); break; | 1207 | case NODE_NUM_FLOAT: print("| Value: %f{2}", node->value.d); break; |
1034 | case NODE_STRING: print("| Value: %s", node->value.str); break; | 1208 | case NODE_STRING: print("| Value: %s", node->value.str); break; |
1035 | case NODE_SYMBOL_IDX: | ||
1036 | case NODE_STRUCT: | 1209 | case NODE_STRUCT: |
1037 | case NODE_STRUCT_LIT: print("| Name: %s", node->value.sym); break; | 1210 | case NODE_STRUCT_LIT: print("| Name: %s", node->value.sym); break; |
1038 | case NODE_SYMBOL: | 1211 | case NODE_SYMBOL: |
1039 | case NODE_FUNCALL: | 1212 | case NODE_FUNCALL: |
1040 | case NODE_ARR_TYPE: | ||
1041 | case NODE_FIELD: | 1213 | case NODE_FIELD: |
1042 | case NODE_TYPE: { | 1214 | case NODE_TYPE: { |
1043 | if (node->is_ptr) { | 1215 | print("| Name: %s", node->value.sym); |
1044 | print("| Name: @%s", node->value.sym); | 1216 | } break; |
1045 | } else { | 1217 | case NODE_ARR: { |
1046 | print("| Name: %s", node->value.sym); | 1218 | if (node->array.kind == NODE_ARR_STATIC) { |
1219 | print("| Static [%d]", node->array.size->value.i); | ||
1220 | } else if (node->array.kind == NODE_ARR_SLICE) { | ||
1221 | print("| Slice []"); | ||
1222 | } else if (node->array.kind == NODE_ARR_DYNAMIC) { | ||
1223 | print("| Dynamic [...]"); | ||
1047 | } | 1224 | } |
1048 | } break; | 1225 | } break; |
1049 | default: break; | 1226 | default: break; |
1050 | } | 1227 | } |
1228 | if (node->unique_name.size > 0) { | ||
1229 | print("| Unique Name: %s", node->unique_name); | ||
1230 | } | ||
1051 | if (node->type.size > 0) { | 1231 | if (node->type.size > 0) { |
1052 | print("| Type: %s", node->type); | 1232 | print("| Type: %s", node->type); |
1053 | } | 1233 | } |
1054 | if (node->fun_params.size > 0) { | 1234 | if (node->type_params.size > 0) { |
1055 | print("| Params: %s", node->fun_params); | 1235 | print("| Params: %s", node->type_params); |
1056 | } | 1236 | } |
1057 | if (node->fun_return.size > 0) { | 1237 | if (node->type_returns.size > 0) { |
1058 | print("| Return: %s", node->fun_return); | 1238 | print("| Return: %s", node->type_returns); |
1059 | } | 1239 | } |
1060 | println("\"];"); | 1240 | println("\"];"); |
1061 | 1241 | ||
1242 | if (node->parent) { | ||
1243 | println("%d:w->%d:e;", node->id, node->parent->id); | ||
1244 | } | ||
1062 | switch (node->kind) { | 1245 | switch (node->kind) { |
1063 | case NODE_FUN: { | 1246 | case NODE_FUN: { |
1064 | for (sz i = 0; i < array_size(node->func_params); i++) { | 1247 | for (sz i = 0; i < array_size(node->func.params); i++) { |
1065 | Node *next = node->func_params[i]; | 1248 | Node *next = node->func.params[i]; |
1066 | println("%d:e->%d:w;", node->id, next->id); | 1249 | println("%d:e->%d:w;", node->id, next->id); |
1067 | graph_node(next); | 1250 | graph_node(next); |
1068 | } | 1251 | } |
1069 | for (sz i = 0; i < array_size(node->func_ret); i++) { | 1252 | for (sz i = 0; i < array_size(node->func.ret); i++) { |
1070 | Node *next = node->func_ret[i]; | 1253 | Node *next = node->func.ret[i]; |
1071 | println("%d:e->%d:w;", node->id, next->id); | 1254 | println("%d:e->%d:w;", node->id, next->id); |
1072 | graph_node(next); | 1255 | graph_node(next); |
1073 | } | 1256 | } |
1074 | if (node->func_name) { | 1257 | if (node->func.name) { |
1075 | println("%d:e->%d:w;", node->id, node->func_name->id); | 1258 | println("%d:e->%d:w;", node->id, node->func.name->id); |
1076 | graph_node(node->func_name); | 1259 | graph_node(node->func.name); |
1077 | } | 1260 | } |
1078 | if (node->func_body) { | 1261 | if (node->func.body) { |
1079 | println("%d:e->%d:w;", node->id, node->func_body->id); | 1262 | println("%d:e->%d:w;", node->id, node->func.body->id); |
1080 | graph_node(node->func_body); | 1263 | graph_node(node->func.body); |
1081 | } | 1264 | } |
1082 | } break; | 1265 | } break; |
1083 | case NODE_COND: | 1266 | case NODE_COND: |
1084 | case NODE_MATCH: { | 1267 | case NODE_MATCH: { |
1085 | if (node->match_expr) { | 1268 | if (node->match.expr) { |
1086 | println("%d:e->%d:w;", node->id, node->match_expr->id); | 1269 | println("%d:e->%d:w;", node->id, node->match.expr->id); |
1087 | graph_node(node->match_expr); | 1270 | graph_node(node->match.expr); |
1088 | } | 1271 | } |
1089 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 1272 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
1090 | Node *next = node->match_cases[i]; | 1273 | Node *next = node->match.cases[i]; |
1091 | println("%d:e->%d:w;", node->id, next->id); | 1274 | println("%d:e->%d:w;", node->id, next->id); |
1092 | graph_node(next); | 1275 | graph_node(next); |
1093 | } | 1276 | } |
@@ -1112,43 +1295,43 @@ graph_node(Node *node) { | |||
1112 | } | 1295 | } |
1113 | } break; | 1296 | } break; |
1114 | case NODE_IF: { | 1297 | case NODE_IF: { |
1115 | if (node->cond_if) { | 1298 | if (node->ifelse.cond) { |
1116 | println("%d:e->%d:w;", node->id, node->cond_if->id); | 1299 | println("%d:e->%d:w;", node->id, node->ifelse.cond->id); |
1117 | graph_node(node->cond_if); | 1300 | graph_node(node->ifelse.cond); |
1118 | } | 1301 | } |
1119 | if (node->cond_expr) { | 1302 | if (node->ifelse.expr_true) { |
1120 | println("%d:e->%d:w;", node->id, node->cond_expr->id); | 1303 | println("%d:e->%d:w;", node->id, node->ifelse.expr_true->id); |
1121 | graph_node(node->cond_expr); | 1304 | graph_node(node->ifelse.expr_true); |
1122 | } | 1305 | } |
1123 | if (node->cond_else) { | 1306 | if (node->ifelse.expr_else) { |
1124 | println("%d:e->%d:w;", node->id, node->cond_else->id); | 1307 | println("%d:e->%d:w;", node->id, node->ifelse.expr_else->id); |
1125 | graph_node(node->cond_else); | 1308 | graph_node(node->ifelse.expr_else); |
1126 | } | 1309 | } |
1127 | } break; | 1310 | } break; |
1128 | case NODE_FIELD: | 1311 | case NODE_FIELD: |
1129 | case NODE_SET: | 1312 | case NODE_SET: |
1130 | case NODE_LET: { | 1313 | case NODE_LET: { |
1131 | if (node->var_name) { | 1314 | if (node->var.name) { |
1132 | println("%d:e->%d:w;", node->id, node->var_name->id); | 1315 | println("%d:e->%d:w;", node->id, node->var.name->id); |
1133 | graph_node(node->var_name); | 1316 | graph_node(node->var.name); |
1134 | } | 1317 | } |
1135 | if (node->var_type) { | 1318 | if (node->var.type) { |
1136 | println("%d:e->%d:w;", node->id, node->var_type->id); | 1319 | println("%d:e->%d:w;", node->id, node->var.type->id); |
1137 | graph_node(node->var_type); | 1320 | graph_node(node->var.type); |
1138 | } | 1321 | } |
1139 | if (node->var_val) { | 1322 | if (node->var.val) { |
1140 | println("%d:e->%d:w;", node->id, node->var_val->id); | 1323 | println("%d:e->%d:w;", node->id, node->var.val->id); |
1141 | graph_node(node->var_val); | 1324 | graph_node(node->var.val); |
1142 | } | 1325 | } |
1143 | } break; | 1326 | } break; |
1144 | default: { | 1327 | default: { |
1145 | if (node->left) { | 1328 | if (node->binary.left) { |
1146 | println("%d:e->%d:w;", node->id, node->left->id); | 1329 | println("%d:e->%d:w;", node->id, node->binary.left->id); |
1147 | graph_node(node->left); | 1330 | graph_node(node->binary.left); |
1148 | } | 1331 | } |
1149 | if (node->right) { | 1332 | if (node->binary.right) { |
1150 | println("%d:e->%d:w;", node->id, node->right->id); | 1333 | println("%d:e->%d:w;", node->id, node->binary.right->id); |
1151 | graph_node(node->right); | 1334 | graph_node(node->binary.right); |
1152 | } | 1335 | } |
1153 | } break; | 1336 | } break; |
1154 | } | 1337 | } |
diff --git a/src/semantic.c b/src/semantic.c index a0231d5..2e2735f 100644 --- a/src/semantic.c +++ b/src/semantic.c | |||
@@ -39,6 +39,10 @@ typedef struct Fun { | |||
39 | Str name; | 39 | Str name; |
40 | Str param_type; | 40 | Str param_type; |
41 | Str return_type; | 41 | Str return_type; |
42 | Str *param_types; | ||
43 | Str *return_types; | ||
44 | sz param_arity; | ||
45 | sz return_arity; | ||
42 | } Fun; | 46 | } Fun; |
43 | 47 | ||
44 | typedef struct Enum { | 48 | typedef struct Enum { |
@@ -62,6 +66,7 @@ typedef struct Scope { | |||
62 | sz depth; | 66 | sz depth; |
63 | Str name; | 67 | Str name; |
64 | SymbolMap *symbols; | 68 | SymbolMap *symbols; |
69 | StrSet *types; | ||
65 | FunMap *funcs; | 70 | FunMap *funcs; |
66 | EnumMap *enums; | 71 | EnumMap *enums; |
67 | StructMap *structs; | 72 | StructMap *structs; |
@@ -75,6 +80,7 @@ typedef struct Analyzer { | |||
75 | Scope **scopes; | 80 | Scope **scopes; |
76 | StrSet *numeric_types; | 81 | StrSet *numeric_types; |
77 | StrSet *integer_types; | 82 | StrSet *integer_types; |
83 | StrSet *float_types; | ||
78 | bool err; | 84 | bool err; |
79 | } Analyzer; | 85 | } Analyzer; |
80 | 86 | ||
@@ -82,16 +88,19 @@ Scope * | |||
82 | typescope_alloc(Analyzer *a, Scope *parent) { | 88 | typescope_alloc(Analyzer *a, Scope *parent) { |
83 | Scope *scope = arena_calloc(sizeof(Scope), a->storage); | 89 | Scope *scope = arena_calloc(sizeof(Scope), a->storage); |
84 | scope->parent = parent; | 90 | scope->parent = parent; |
91 | if (parent != NULL) { | ||
92 | scope->name = parent->name; | ||
93 | } | ||
85 | scope->id = a->typescope_gen++; | 94 | scope->id = a->typescope_gen++; |
86 | scope->depth = parent == NULL ? 0 : parent->depth + 1; | 95 | scope->depth = parent == NULL ? 0 : parent->depth + 1; |
87 | array_push(a->scopes, scope, a->storage); | 96 | array_push(a->scopes, scope, a->storage); |
88 | return scope; | 97 | return scope; |
89 | } | 98 | } |
90 | 99 | ||
91 | SymbolMap * | 100 | StrSet * |
92 | find_type(Scope *scope, Str type) { | 101 | find_type(Scope *scope, Str type) { |
93 | while (scope != NULL) { | 102 | while (scope != NULL) { |
94 | SymbolMap *val = symmap_lookup(&scope->symbols, type); | 103 | StrSet *val = strset_lookup(&scope->types, type); |
95 | if (val != NULL) { | 104 | if (val != NULL) { |
96 | return val; | 105 | return val; |
97 | } | 106 | } |
@@ -276,7 +285,7 @@ Str type_inference(Analyzer *a, Node *node, Scope *scope); | |||
276 | 285 | ||
277 | void | 286 | void |
278 | typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | 287 | typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { |
279 | if (node->field_type->kind == NODE_COMPOUND_TYPE) { | 288 | if (node->field.type->kind == NODE_COMPOUND_TYPE) { |
280 | Str field_name = str_concat(symbol, cstr("."), a->storage); | 289 | Str field_name = str_concat(symbol, cstr("."), a->storage); |
281 | field_name = str_concat(field_name, node->value.str, a->storage); | 290 | field_name = str_concat(field_name, node->value.str, a->storage); |
282 | if (structmap_lookup(&scope->structs, field_name)) { | 291 | if (structmap_lookup(&scope->structs, field_name)) { |
@@ -285,8 +294,8 @@ typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | |||
285 | a->err = true; | 294 | a->err = true; |
286 | } | 295 | } |
287 | Str type = cstr("\\{ "); | 296 | Str type = cstr("\\{ "); |
288 | for (sz i = 0; i < array_size(node->field_type->elements); i++) { | 297 | for (sz i = 0; i < array_size(node->field.type->elements); i++) { |
289 | Node *field = node->field_type->elements[i]; | 298 | Node *field = node->field.type->elements[i]; |
290 | typecheck_field(a, field, scope, field_name); | 299 | typecheck_field(a, field, scope, field_name); |
291 | type = str_concat(type, field->type, a->storage); | 300 | type = str_concat(type, field->type, a->storage); |
292 | type = str_concat(type, cstr(" "), a->storage); | 301 | type = str_concat(type, cstr(" "), a->storage); |
@@ -296,25 +305,19 @@ typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | |||
296 | } else { | 305 | } else { |
297 | Str field_name = str_concat(symbol, cstr("."), a->storage); | 306 | Str field_name = str_concat(symbol, cstr("."), a->storage); |
298 | field_name = str_concat(field_name, node->value.str, a->storage); | 307 | field_name = str_concat(field_name, node->value.str, a->storage); |
299 | Str field_type = node->field_type->value.str; | 308 | Str field_type = node->field.type->value.str; |
300 | if (!find_type(scope, field_type)) { | 309 | if (!find_type(scope, field_type)) { |
301 | eprintln("%s:%d:%d: error: unknown type '%s'", a->file_name, | 310 | eprintln("%s:%d:%d: error: unknown type '%s'", a->file_name, |
302 | node->field_type->line, node->field_type->col, field_type); | 311 | node->field.type->line, node->field.type->col, field_type); |
303 | a->err = true; | 312 | a->err = true; |
304 | } | 313 | } |
305 | if (node->field_type->is_ptr) { | ||
306 | field_type = str_concat(cstr("@"), field_type, a->storage); | ||
307 | } | ||
308 | if (node->field_type->kind == NODE_ARR_TYPE) { | ||
309 | field_type = str_concat(cstr("@"), field_type, a->storage); | ||
310 | } | ||
311 | if (structmap_lookup(&scope->structs, field_name)) { | 314 | if (structmap_lookup(&scope->structs, field_name)) { |
312 | eprintln("%s:%d:%d: error: struct field '%s' already exists", | 315 | eprintln("%s:%d:%d: error: struct field '%s' already exists", |
313 | a->file_name, node->line, node->col, field_name); | 316 | a->file_name, node->line, node->col, field_name); |
314 | a->err = true; | 317 | a->err = true; |
315 | } | 318 | } |
316 | if (node->field_val) { | 319 | if (node->field.val) { |
317 | Str type = type_inference(a, node->field_val, scope); | 320 | Str type = type_inference(a, node->field.val, scope); |
318 | if (!str_eq(type, field_type)) { | 321 | if (!str_eq(type, field_type)) { |
319 | eprintln( | 322 | eprintln( |
320 | "%s:%d:%d: error: mismatched types in struct " | 323 | "%s:%d:%d: error: mismatched types in struct " |
@@ -329,7 +332,7 @@ typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | |||
329 | (Struct){ | 332 | (Struct){ |
330 | .name = field_name, | 333 | .name = field_name, |
331 | .type = field_type, | 334 | .type = field_type, |
332 | .val = node->field_val, | 335 | .val = node->field.val, |
333 | }, | 336 | }, |
334 | a->storage); | 337 | a->storage); |
335 | symmap_insert(&scope->symbols, field_name, | 338 | symmap_insert(&scope->symbols, field_name, |
@@ -341,10 +344,10 @@ typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | |||
341 | 344 | ||
342 | void | 345 | void |
343 | typecheck_lit_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | 346 | typecheck_lit_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { |
344 | if (node->field_val->kind == NODE_COMPOUND_TYPE) { | 347 | if (node->field.val->kind == NODE_COMPOUND_TYPE) { |
345 | Str type = cstr("\\{ "); | 348 | Str type = cstr("\\{ "); |
346 | for (sz i = 0; i < array_size(node->field_val->elements); i++) { | 349 | for (sz i = 0; i < array_size(node->field.val->elements); i++) { |
347 | Node *field = node->field_val->elements[i]; | 350 | Node *field = node->field.val->elements[i]; |
348 | Str field_name = str_concat(symbol, cstr("."), a->storage); | 351 | Str field_name = str_concat(symbol, cstr("."), a->storage); |
349 | field_name = str_concat(field_name, field->value.str, a->storage); | 352 | field_name = str_concat(field_name, field->value.str, a->storage); |
350 | typecheck_lit_field(a, field, scope, field_name); | 353 | typecheck_lit_field(a, field, scope, field_name); |
@@ -362,7 +365,7 @@ typecheck_lit_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | |||
362 | return; | 365 | return; |
363 | } | 366 | } |
364 | Str field_type = s->val.type; | 367 | Str field_type = s->val.type; |
365 | Str type = type_inference(a, node->field_val, scope); | 368 | Str type = type_inference(a, node->field.val, scope); |
366 | if (!str_eq(type, field_type)) { | 369 | if (!str_eq(type, field_type)) { |
367 | eprintln( | 370 | eprintln( |
368 | "%s:%d:%d: error: mismatched types in struct " | 371 | "%s:%d:%d: error: mismatched types in struct " |
@@ -384,17 +387,18 @@ typecheck_returns(Analyzer *a, Node *node, Str expected) { | |||
384 | switch (node->kind) { | 387 | switch (node->kind) { |
385 | case NODE_COND: | 388 | case NODE_COND: |
386 | case NODE_MATCH: { | 389 | case NODE_MATCH: { |
387 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 390 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
388 | Node *next = node->match_cases[i]; | 391 | Node *next = node->match.cases[i]; |
389 | typecheck_returns(a, next, expected); | 392 | typecheck_returns(a, next, expected); |
390 | } | 393 | } |
391 | } break; | 394 | } break; |
392 | case NODE_RETURN: { | 395 | case NODE_RETURN: { |
393 | bool err = !str_eq(node->type, expected); | 396 | Str type = str_remove_prefix(node->type, cstr("ret:")); |
397 | bool err = !str_eq(type, expected); | ||
394 | if (err) { | 398 | if (err) { |
395 | eprintln( | 399 | eprintln( |
396 | "%s:%d:%d: error: mismatched return type %s, expected %s", | 400 | "%s:%d:%d: error: mismatched return type %s, expected %s", |
397 | a->file_name, node->line, node->col, node->type, expected); | 401 | a->file_name, node->line, node->col, type, expected); |
398 | a->err = true; | 402 | a->err = true; |
399 | } | 403 | } |
400 | } break; | 404 | } break; |
@@ -405,17 +409,17 @@ typecheck_returns(Analyzer *a, Node *node, Str expected) { | |||
405 | } | 409 | } |
406 | } break; | 410 | } break; |
407 | case NODE_IF: { | 411 | case NODE_IF: { |
408 | if (node->cond_expr) { | 412 | if (node->ifelse.expr_true) { |
409 | typecheck_returns(a, node->cond_expr, expected); | 413 | typecheck_returns(a, node->ifelse.expr_true, expected); |
410 | } | 414 | } |
411 | if (node->cond_else) { | 415 | if (node->ifelse.expr_else) { |
412 | typecheck_returns(a, node->cond_else, expected); | 416 | typecheck_returns(a, node->ifelse.expr_else, expected); |
413 | } | 417 | } |
414 | } break; | 418 | } break; |
415 | case NODE_SET: | 419 | case NODE_SET: |
416 | case NODE_LET: { | 420 | case NODE_LET: { |
417 | if (node->var_val) { | 421 | if (node->var.val) { |
418 | typecheck_returns(a, node->var_val, expected); | 422 | typecheck_returns(a, node->var.val, expected); |
419 | } | 423 | } |
420 | } break; | 424 | } break; |
421 | case NODE_ADD: | 425 | case NODE_ADD: |
@@ -435,13 +439,14 @@ typecheck_returns(Analyzer *a, Node *node, Str expected) { | |||
435 | case NODE_BITNOT: | 439 | case NODE_BITNOT: |
436 | case NODE_BITAND: | 440 | case NODE_BITAND: |
437 | case NODE_BITOR: | 441 | case NODE_BITOR: |
442 | case NODE_BITXOR: | ||
438 | case NODE_BITLSHIFT: | 443 | case NODE_BITLSHIFT: |
439 | case NODE_BITRSHIFT: { | 444 | case NODE_BITRSHIFT: { |
440 | if (node->left) { | 445 | if (node->binary.left) { |
441 | typecheck_returns(a, node->left, expected); | 446 | typecheck_returns(a, node->binary.left, expected); |
442 | } | 447 | } |
443 | if (node->right) { | 448 | if (node->binary.right) { |
444 | typecheck_returns(a, node->right, expected); | 449 | typecheck_returns(a, node->binary.right, expected); |
445 | } | 450 | } |
446 | } break; | 451 | } break; |
447 | default: break; | 452 | default: break; |
@@ -452,66 +457,65 @@ Str | |||
452 | type_inference(Analyzer *a, Node *node, Scope *scope) { | 457 | type_inference(Analyzer *a, Node *node, Scope *scope) { |
453 | assert(a); | 458 | assert(a); |
454 | assert(scope); | 459 | assert(scope); |
455 | if (!node) { | 460 | if (!node || a->err) { |
456 | return cstr(""); | 461 | return cstr(""); |
457 | } | 462 | } |
458 | // NOTE: For now we are not going to do implicit numeric conversions. | ||
459 | switch (node->kind) { | 463 | switch (node->kind) { |
460 | case NODE_LET: { | 464 | case NODE_LET: { |
461 | node->type = cstr("nil"); | 465 | node->type = cstr("nil"); |
462 | Str symbol = node->var_name->value.str; | 466 | Str symbol = node->var.name->value.str; |
463 | if (symmap_lookup(&scope->symbols, symbol)) { | 467 | if (symmap_lookup(&scope->symbols, symbol)) { |
464 | eprintln( | 468 | eprintln( |
465 | "%s:%d:%d: error: symbol '%s' already exists in current " | 469 | "%s:%d:%d: error: symbol '%s' already exists in current " |
466 | "scope ", | 470 | "scope ", |
467 | a->file_name, node->var_name->line, node->var_name->col, | 471 | a->file_name, node->var.name->line, node->var.name->col, |
468 | symbol); | 472 | symbol); |
469 | a->err = true; | 473 | a->err = true; |
470 | return cstr(""); | 474 | return cstr(""); |
471 | } | 475 | } |
472 | if (node->var_type) { | 476 | if (node->var.type) { |
473 | Str type_name = node->var_type->value.str; | 477 | Str type_name = type_inference(a, node->var.type, scope); |
474 | SymbolMap *type = find_type(scope, type_name); | 478 | if (node->var.val) { |
475 | if (type == NULL) { | 479 | Str type = type_inference(a, node->var.val, scope); |
476 | eprintln("%s:%d:%d: error: unknown type '%s'", a->file_name, | ||
477 | node->var_type->line, node->var_type->col, | ||
478 | type_name); | ||
479 | a->err = true; | ||
480 | return cstr(""); | ||
481 | } | ||
482 | if (node->var_type->is_ptr) { | ||
483 | type_name = str_concat(cstr("@"), type_name, a->storage); | ||
484 | } | ||
485 | if (node->var_type->kind == NODE_ARR_TYPE) { | ||
486 | type_name = str_concat(cstr("@"), type_name, a->storage); | ||
487 | // TODO: typecheck size | ||
488 | // TODO: register array in scope | ||
489 | } | ||
490 | if (node->var_val) { | ||
491 | Str type = type_inference(a, node->var_val, scope); | ||
492 | if (!type.size) { | 480 | if (!type.size) { |
493 | eprintln( | 481 | eprintln( |
494 | "%s:%d:%d: error: can't bind `nil` to variable " | 482 | "%s:%d:%d: error: can't bind `nil` to variable " |
495 | "'%s'", | 483 | "'%s'", |
496 | a->file_name, node->var_type->line, | 484 | a->file_name, node->var.type->line, |
497 | node->var_type->col, symbol); | 485 | node->var.type->col, symbol); |
498 | a->err = true; | 486 | a->err = true; |
499 | return cstr(""); | 487 | return cstr(""); |
500 | } | 488 | } |
501 | // TODO: Consider compatible types. | ||
502 | if (!str_eq(type, type_name)) { | 489 | if (!str_eq(type, type_name)) { |
503 | // Special case, enums can be treated as ints. | 490 | // TODO: ensure that we only assign compatible arrays, |
504 | FindEnumResult res = find_enum(scope, type_name); | 491 | // for pointers this was ok but not anymore. |
505 | if (!(res.map && str_eq(type, cstr("int")))) { | 492 | Str type_a = type; |
506 | eprintln( | 493 | Str type_b = type_name; |
507 | "%s:%d:%d: error: type mismatch, trying to " | 494 | if (str_has_prefix(type_a, cstr("@")) || |
508 | "assing " | 495 | str_has_prefix(type_a, cstr("["))) { |
509 | "%s" | 496 | type_a = cstr("Ptr"); |
510 | " to a variable of type %s", | 497 | } |
511 | a->file_name, node->var_type->line, | 498 | if (str_has_prefix(type_b, cstr("@")) || |
512 | node->var_type->col, type, type_name); | 499 | str_has_prefix(type_b, cstr("["))) { |
513 | a->err = true; | 500 | type_b = cstr("Ptr"); |
514 | return cstr(""); | 501 | } |
502 | if (!(strset_lookup(&a->integer_types, type_a) && | ||
503 | strset_lookup(&a->integer_types, type_b)) || | ||
504 | !(strset_lookup(&a->numeric_types, type_a) && | ||
505 | strset_lookup(&a->numeric_types, type_b))) { | ||
506 | // Special case, enums can be treated as ints. | ||
507 | FindEnumResult res = find_enum(scope, type_name); | ||
508 | if (!(res.map && str_eq(type, cstr("Int")))) { | ||
509 | eprintln( | ||
510 | "%s:%d:%d: error: type mismatch, trying to " | ||
511 | "assing " | ||
512 | "%s" | ||
513 | " to a variable of type %s", | ||
514 | a->file_name, node->var.type->line, | ||
515 | node->var.type->col, type, type_name); | ||
516 | a->err = true; | ||
517 | return cstr(""); | ||
518 | } | ||
515 | } | 519 | } |
516 | } | 520 | } |
517 | } | 521 | } |
@@ -521,7 +525,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
521 | .kind = SYM_VAR, | 525 | .kind = SYM_VAR, |
522 | }, | 526 | }, |
523 | a->storage); | 527 | a->storage); |
524 | node->var_name->type = type_name; | 528 | node->var.name->type = type_name; |
525 | symbol = str_concat(cstr("."), symbol, a->storage); | 529 | symbol = str_concat(cstr("."), symbol, a->storage); |
526 | symbol = str_concat(symbol, str_from_int(scope->id, a->storage), | 530 | symbol = str_concat(symbol, str_from_int(scope->id, a->storage), |
527 | a->storage); | 531 | a->storage); |
@@ -530,13 +534,19 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
530 | } | 534 | } |
531 | 535 | ||
532 | // We don't know the type for this symbol, perform inference. | 536 | // We don't know the type for this symbol, perform inference. |
533 | Str type = type_inference(a, node->var_val, scope); | 537 | Str type = type_inference(a, node->var.val, scope); |
534 | if (type.size) { | 538 | if (!type.size || str_eq(type, cstr("nil")) || |
535 | symmap_insert(&scope->symbols, symbol, | 539 | str_has_prefix(type, cstr("ret:"))) { |
536 | (Symbol){.name = type, .kind = SYM_VAR}, | 540 | eprintln( |
537 | a->storage); | 541 | "%s:%d:%d: error: can't bind `nil` to variable " |
538 | node->var_name->type = type; | 542 | "'%s'", |
543 | a->file_name, node->line, node->col, symbol); | ||
544 | a->err = true; | ||
545 | return cstr(""); | ||
539 | } | 546 | } |
547 | symmap_insert(&scope->symbols, symbol, | ||
548 | (Symbol){.name = type, .kind = SYM_VAR}, a->storage); | ||
549 | node->var.name->type = type; | ||
540 | symbol = str_concat(cstr("."), symbol, a->storage); | 550 | symbol = str_concat(cstr("."), symbol, a->storage); |
541 | symbol = str_concat(symbol, str_from_int(scope->id, a->storage), | 551 | symbol = str_concat(symbol, str_from_int(scope->id, a->storage), |
542 | a->storage); | 552 | a->storage); |
@@ -544,23 +554,38 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
544 | return node->type; | 554 | return node->type; |
545 | } break; | 555 | } break; |
546 | case NODE_SET: { | 556 | case NODE_SET: { |
547 | Str name = type_inference(a, node->var_name, scope); | 557 | Str name = type_inference(a, node->var.name, scope); |
548 | Str val = type_inference(a, node->var_val, scope); | 558 | Str val = type_inference(a, node->var.val, scope); |
559 | if (str_has_prefix(name, cstr("@")) || | ||
560 | str_has_prefix(name, cstr("["))) { | ||
561 | name = cstr("Ptr"); | ||
562 | } | ||
563 | if (str_has_prefix(val, cstr("@")) || | ||
564 | str_has_prefix(val, cstr("["))) { | ||
565 | val = cstr("Ptr"); | ||
566 | } | ||
549 | if (!str_eq(name, val)) { | 567 | if (!str_eq(name, val)) { |
550 | eprintln( | 568 | if (!(strset_lookup(&a->integer_types, name) && |
551 | "%s:%d:%d: error: type mismatch, trying to assing " | 569 | strset_lookup(&a->integer_types, val)) || |
552 | "%s" | 570 | !(strset_lookup(&a->numeric_types, name) && |
553 | " to a variable of type %s", | 571 | strset_lookup(&a->numeric_types, val))) { |
554 | a->file_name, node->line, node->col, val, name); | 572 | eprintln( |
555 | a->err = true; | 573 | "%s:%d:%d: error: type mismatch, trying to assing " |
556 | return cstr(""); | 574 | "%s" |
575 | " to a variable of type %s", | ||
576 | a->file_name, node->line, node->col, val, name); | ||
577 | a->err = true; | ||
578 | return cstr(""); | ||
579 | } | ||
557 | } | 580 | } |
558 | Str symbol = node->var_name->value.str; | 581 | Str symbol = node->var.name->value.str; |
559 | FindSymbolResult sym = find_symbol(scope, symbol); | 582 | FindSymbolResult sym = find_symbol(scope, symbol); |
560 | node->unique_name = str_concat(cstr("."), symbol, a->storage); | 583 | if (sym.map) { |
561 | node->unique_name = | 584 | node->unique_name = str_concat(cstr("."), symbol, a->storage); |
562 | str_concat(node->unique_name, | 585 | node->unique_name = str_concat( |
563 | str_from_int(sym.scope->id, a->storage), a->storage); | 586 | node->unique_name, str_from_int(sym.scope->id, a->storage), |
587 | a->storage); | ||
588 | } | ||
564 | node->type = cstr("nil"); | 589 | node->type = cstr("nil"); |
565 | return node->type; | 590 | return node->type; |
566 | } break; | 591 | } break; |
@@ -600,7 +625,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
600 | enummap_insert(&scope->enums, symbol, | 625 | enummap_insert(&scope->enums, symbol, |
601 | (Enum){ | 626 | (Enum){ |
602 | .name = symbol, | 627 | .name = symbol, |
603 | .val = node->field_val, | 628 | .val = node->field.val, |
604 | }, | 629 | }, |
605 | a->storage); | 630 | a->storage); |
606 | for (sz i = 0; i < array_size(node->struct_field); i++) { | 631 | for (sz i = 0; i < array_size(node->struct_field); i++) { |
@@ -613,9 +638,9 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
613 | a->file_name, field->line, field->col, field_name); | 638 | a->file_name, field->line, field->col, field_name); |
614 | a->err = true; | 639 | a->err = true; |
615 | } | 640 | } |
616 | if (field->field_val) { | 641 | if (field->field.val) { |
617 | Str type = type_inference(a, field->field_val, scope); | 642 | Str type = type_inference(a, field->field.val, scope); |
618 | if (!str_eq(type, cstr("int"))) { | 643 | if (!str_eq(type, cstr("Int"))) { |
619 | eprintln( | 644 | eprintln( |
620 | "%s:%d:%d: error: non int enum value for '%s.%s'", | 645 | "%s:%d:%d: error: non int enum value for '%s.%s'", |
621 | a->file_name, field->line, field->col, symbol, | 646 | a->file_name, field->line, field->col, symbol, |
@@ -637,26 +662,31 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
637 | return node->type; | 662 | return node->type; |
638 | } break; | 663 | } break; |
639 | case NODE_IF: { | 664 | case NODE_IF: { |
640 | Str cond_type = type_inference(a, node->cond_if, scope); | 665 | Str cond_type = type_inference(a, node->ifelse.cond, scope); |
641 | if (!str_eq(cond_type, cstr("bool"))) { | 666 | if (!str_eq(cond_type, cstr("Bool"))) { |
642 | emit_semantic_error( | 667 | emit_semantic_error( |
643 | a, node->cond_if, | 668 | a, node->ifelse.cond, |
644 | cstr("non boolean expression on if condition")); | 669 | cstr("non boolean expression on if condition")); |
645 | return cstr(""); | 670 | return cstr(""); |
646 | } | 671 | } |
647 | if (node->cond_expr->kind == NODE_BLOCK) { | 672 | if (node->ifelse.expr_true->kind == NODE_BLOCK) { |
648 | node->type = type_inference(a, node->cond_expr, scope); | 673 | node->type = type_inference(a, node->ifelse.expr_true, scope); |
649 | } else { | 674 | } else { |
650 | Scope *next = typescope_alloc(a, scope); | 675 | Scope *next = typescope_alloc(a, scope); |
651 | node->type = type_inference(a, node->cond_expr, next); | 676 | node->type = type_inference(a, node->ifelse.expr_true, next); |
652 | } | 677 | } |
653 | if (node->cond_else) { | 678 | if (str_has_prefix(node->type, cstr("ret:")) || |
679 | str_has_prefix(node->type, cstr("flow:"))) { | ||
680 | node->type = cstr("nil"); | ||
681 | } | ||
682 | if (node->ifelse.expr_else) { | ||
654 | Str else_type; | 683 | Str else_type; |
655 | if (node->cond_else->kind == NODE_BLOCK) { | 684 | if (node->ifelse.expr_else->kind == NODE_BLOCK) { |
656 | else_type = type_inference(a, node->cond_else, scope); | 685 | else_type = |
686 | type_inference(a, node->ifelse.expr_else, scope); | ||
657 | } else { | 687 | } else { |
658 | Scope *next = typescope_alloc(a, scope); | 688 | Scope *next = typescope_alloc(a, scope); |
659 | else_type = type_inference(a, node->cond_else, next); | 689 | else_type = type_inference(a, node->ifelse.expr_else, next); |
660 | } | 690 | } |
661 | if (!str_eq(node->type, else_type)) { | 691 | if (!str_eq(node->type, else_type)) { |
662 | emit_semantic_error( | 692 | emit_semantic_error( |
@@ -664,9 +694,10 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
664 | return cstr(""); | 694 | return cstr(""); |
665 | } | 695 | } |
666 | } | 696 | } |
697 | |||
667 | // If it returns a value, verify it contains an `else` statement. | 698 | // If it returns a value, verify it contains an `else` statement. |
668 | if (!str_eq(node->type, cstr("nil"))) { | 699 | if (!str_eq(node->type, cstr("nil"))) { |
669 | if (!node->cond_else) { | 700 | if (!node->ifelse.expr_else) { |
670 | emit_semantic_error( | 701 | emit_semantic_error( |
671 | a, node, | 702 | a, node, |
672 | cstr("missing else statement in if expression")); | 703 | cstr("missing else statement in if expression")); |
@@ -676,25 +707,25 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
676 | return node->type; | 707 | return node->type; |
677 | } break; | 708 | } break; |
678 | case NODE_WHILE: { | 709 | case NODE_WHILE: { |
679 | Str cond_type = type_inference(a, node->while_cond, scope); | 710 | Str cond_type = type_inference(a, node->loop.cond, scope); |
680 | if (!str_eq(cond_type, cstr("bool"))) { | 711 | if (!str_eq(cond_type, cstr("Bool"))) { |
681 | emit_semantic_error( | 712 | emit_semantic_error( |
682 | a, node->cond_if, | 713 | a, node->loop.cond, |
683 | cstr("non boolean expression on while condition")); | 714 | cstr("non boolean expression on while condition")); |
684 | return cstr(""); | 715 | return cstr(""); |
685 | } | 716 | } |
686 | if (node->while_expr->kind != NODE_BLOCK) { | 717 | if (node->loop.expr->kind != NODE_BLOCK) { |
687 | scope = typescope_alloc(a, scope); | 718 | scope = typescope_alloc(a, scope); |
688 | } | 719 | } |
689 | type_inference(a, node->while_expr, scope); | 720 | type_inference(a, node->loop.expr, scope); |
690 | node->type = cstr("nil"); | 721 | node->type = cstr("nil"); |
691 | return node->type; | 722 | return node->type; |
692 | } break; | 723 | } break; |
693 | case NODE_COND: { | 724 | case NODE_COND: { |
694 | Str previous = cstr(""); | 725 | Str previous = cstr(""); |
695 | bool has_else = false; | 726 | bool has_else = false; |
696 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 727 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
697 | Node *expr = node->match_cases[i]; | 728 | Node *expr = node->match.cases[i]; |
698 | Str next = type_inference(a, expr, scope); | 729 | Str next = type_inference(a, expr, scope); |
699 | if (i != 0 && !str_eq(next, previous)) { | 730 | if (i != 0 && !str_eq(next, previous)) { |
700 | emit_semantic_error( | 731 | emit_semantic_error( |
@@ -702,13 +733,15 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
702 | cstr("non-matching types for cond expressions")); | 733 | cstr("non-matching types for cond expressions")); |
703 | return cstr(""); | 734 | return cstr(""); |
704 | } | 735 | } |
705 | if (!expr->case_value) { | 736 | if (!expr->case_entry.cond) { |
706 | has_else = true; | 737 | has_else = true; |
707 | } | 738 | } |
708 | previous = next; | 739 | previous = next; |
709 | } | 740 | } |
710 | // If it returns a value, verify it contains an `else` statement. | 741 | // If it returns a value, verify it contains an `else` statement. |
711 | if (!str_eq(previous, cstr("nil"))) { | 742 | if (!str_eq(node->type, cstr("nil")) && |
743 | !str_has_prefix(node->type, cstr("ret:")) && | ||
744 | !str_has_prefix(node->type, cstr("flow:"))) { | ||
712 | if (!has_else) { | 745 | if (!has_else) { |
713 | emit_semantic_error( | 746 | emit_semantic_error( |
714 | a, node, | 747 | a, node, |
@@ -720,16 +753,16 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
720 | return node->type; | 753 | return node->type; |
721 | } break; | 754 | } break; |
722 | case NODE_MATCH: { | 755 | case NODE_MATCH: { |
723 | Str e = type_inference(a, node->match_expr, scope); | 756 | Str e = type_inference(a, node->match.expr, scope); |
724 | if (str_eq(e, cstr("int"))) { | 757 | if (str_eq(e, cstr("Int"))) { |
725 | // Integer matching. | 758 | // Integer matching. |
726 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 759 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
727 | Node *field = node->match_cases[i]; | 760 | Node *field = node->match.cases[i]; |
728 | if (field->case_value) { | 761 | if (field->case_entry.cond) { |
729 | if (field->case_value->kind != NODE_NUM_INT && | 762 | if (field->case_entry.cond->kind != NODE_NUM_INT && |
730 | field->case_value->kind != NODE_NUM_UINT) { | 763 | field->case_entry.cond->kind != NODE_NUM_UINT) { |
731 | emit_semantic_error( | 764 | emit_semantic_error( |
732 | a, field->case_value, | 765 | a, field->case_entry.cond, |
733 | cstr( | 766 | cstr( |
734 | "non-integer or enum types on match case")); | 767 | "non-integer or enum types on match case")); |
735 | } | 768 | } |
@@ -740,24 +773,24 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
740 | FindEnumResult res = find_enum(scope, e); | 773 | FindEnumResult res = find_enum(scope, e); |
741 | Str enum_prefix = | 774 | Str enum_prefix = |
742 | str_concat(res.map->val.name, cstr("."), a->storage); | 775 | str_concat(res.map->val.name, cstr("."), a->storage); |
743 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 776 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
744 | Node *field = node->match_cases[i]; | 777 | Node *field = node->match.cases[i]; |
745 | if (field->case_value) { | 778 | if (field->case_entry.cond) { |
746 | Str field_name = str_concat( | 779 | Str field_name = str_concat( |
747 | enum_prefix, field->case_value->value.str, | 780 | enum_prefix, field->case_entry.cond->value.str, |
748 | a->storage); | 781 | a->storage); |
749 | if (!enummap_lookup(&res.scope->enums, field_name)) { | 782 | if (!enummap_lookup(&res.scope->enums, field_name)) { |
750 | eprintln("%s:%d:%d: error: unknown enum field '%s'", | 783 | eprintln("%s:%d:%d: error: unknown enum field '%s'", |
751 | a->file_name, field->case_value->line, | 784 | a->file_name, field->case_entry.cond->line, |
752 | field->case_value->col, field_name); | 785 | field->case_entry.cond->col, field_name); |
753 | a->err = true; | 786 | a->err = true; |
754 | } | 787 | } |
755 | } | 788 | } |
756 | } | 789 | } |
757 | } | 790 | } |
758 | Str previous = cstr(""); | 791 | Str previous = cstr(""); |
759 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 792 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
760 | Node *expr = node->match_cases[i]; | 793 | Node *expr = node->match.cases[i]; |
761 | Str next = type_inference(a, expr, scope); | 794 | Str next = type_inference(a, expr, scope); |
762 | if (i != 0 && !str_eq(next, previous)) { | 795 | if (i != 0 && !str_eq(next, previous)) { |
763 | emit_semantic_error( | 796 | emit_semantic_error( |
@@ -771,29 +804,29 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
771 | return node->type; | 804 | return node->type; |
772 | } break; | 805 | } break; |
773 | case NODE_CASE_MATCH: { | 806 | case NODE_CASE_MATCH: { |
774 | if (node->case_expr->kind != NODE_BLOCK) { | 807 | if (node->case_entry.expr->kind != NODE_BLOCK) { |
775 | scope = typescope_alloc(a, scope); | 808 | scope = typescope_alloc(a, scope); |
776 | } | 809 | } |
777 | node->type = type_inference(a, node->case_expr, scope); | 810 | node->type = type_inference(a, node->case_entry.expr, scope); |
778 | return node->type; | 811 | return node->type; |
779 | } break; | 812 | } break; |
780 | case NODE_CASE_COND: { | 813 | case NODE_CASE_COND: { |
781 | if (node->case_value) { | 814 | if (node->case_entry.cond) { |
782 | Str cond = type_inference(a, node->case_value, scope); | 815 | Str cond = type_inference(a, node->case_entry.cond, scope); |
783 | if (!str_eq(cond, cstr("bool"))) { | 816 | if (!str_eq(cond, cstr("Bool"))) { |
784 | emit_semantic_error(a, node, | 817 | emit_semantic_error(a, node, |
785 | cstr("non-boolean case condition")); | 818 | cstr("non-boolean case condition")); |
786 | } | 819 | } |
787 | } | 820 | } |
788 | if (node->case_expr->kind != NODE_BLOCK) { | 821 | if (node->case_entry.expr->kind != NODE_BLOCK) { |
789 | scope = typescope_alloc(a, scope); | 822 | scope = typescope_alloc(a, scope); |
790 | } | 823 | } |
791 | node->type = type_inference(a, node->case_expr, scope); | 824 | node->type = type_inference(a, node->case_entry.expr, scope); |
792 | return node->type; | 825 | return node->type; |
793 | } break; | 826 | } break; |
794 | case NODE_TRUE: | 827 | case NODE_TRUE: |
795 | case NODE_FALSE: { | 828 | case NODE_FALSE: { |
796 | node->type = cstr("bool"); | 829 | node->type = cstr("Bool"); |
797 | return node->type; | 830 | return node->type; |
798 | } break; | 831 | } break; |
799 | case NODE_NIL: { | 832 | case NODE_NIL: { |
@@ -803,21 +836,21 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
803 | case NODE_NOT: | 836 | case NODE_NOT: |
804 | case NODE_AND: | 837 | case NODE_AND: |
805 | case NODE_OR: { | 838 | case NODE_OR: { |
806 | Str left = type_inference(a, node->left, scope); | 839 | Str left = type_inference(a, node->binary.left, scope); |
807 | if (!str_eq(left, cstr("bool"))) { | 840 | if (!str_eq(left, cstr("Bool"))) { |
808 | emit_semantic_error(a, node, | 841 | emit_semantic_error(a, node, |
809 | cstr("expected bool on logic expression")); | 842 | cstr("expected bool on logic expression")); |
810 | return cstr(""); | 843 | return cstr(""); |
811 | } | 844 | } |
812 | if (node->right) { | 845 | if (node->binary.right) { |
813 | Str right = type_inference(a, node->right, scope); | 846 | Str right = type_inference(a, node->binary.right, scope); |
814 | if (!str_eq(right, cstr("bool"))) { | 847 | if (!str_eq(right, cstr("Bool"))) { |
815 | emit_semantic_error( | 848 | emit_semantic_error( |
816 | a, node, cstr("expected bool on logic expression")); | 849 | a, node, cstr("expected bool on logic expression")); |
817 | return cstr(""); | 850 | return cstr(""); |
818 | } | 851 | } |
819 | } | 852 | } |
820 | node->type = cstr("bool"); | 853 | node->type = cstr("Bool"); |
821 | return node->type; | 854 | return node->type; |
822 | } break; | 855 | } break; |
823 | case NODE_EQ: | 856 | case NODE_EQ: |
@@ -826,18 +859,23 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
826 | case NODE_GT: | 859 | case NODE_GT: |
827 | case NODE_LE: | 860 | case NODE_LE: |
828 | case NODE_GE: { | 861 | case NODE_GE: { |
829 | Str left = type_inference(a, node->left, scope); | 862 | Str left = type_inference(a, node->binary.left, scope); |
830 | Str right = type_inference(a, node->right, scope); | 863 | Str right = type_inference(a, node->binary.right, scope); |
831 | if (!str_eq(left, right)) { | 864 | if (!str_eq(left, right)) { |
832 | emit_semantic_error( | 865 | if (!(strset_lookup(&a->integer_types, left) && |
833 | a, node, cstr("mismatched types on binary expression")); | 866 | strset_lookup(&a->integer_types, right)) || |
834 | return cstr(""); | 867 | !(strset_lookup(&a->numeric_types, left) && |
868 | strset_lookup(&a->numeric_types, right))) { | ||
869 | emit_semantic_error( | ||
870 | a, node, cstr("mismatched types on binary expression")); | ||
871 | return cstr(""); | ||
872 | } | ||
835 | } | 873 | } |
836 | node->type = cstr("bool"); | 874 | node->type = cstr("Bool"); |
837 | return node->type; | 875 | return node->type; |
838 | } break; | 876 | } break; |
839 | case NODE_BITNOT: { | 877 | case NODE_BITNOT: { |
840 | Str left = type_inference(a, node->left, scope); | 878 | Str left = type_inference(a, node->binary.left, scope); |
841 | if (!strset_lookup(&a->integer_types, left)) { | 879 | if (!strset_lookup(&a->integer_types, left)) { |
842 | emit_semantic_error( | 880 | emit_semantic_error( |
843 | a, node, cstr("non integer type on bit twiddling expr")); | 881 | a, node, cstr("non integer type on bit twiddling expr")); |
@@ -848,10 +886,11 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
848 | } break; | 886 | } break; |
849 | case NODE_BITAND: | 887 | case NODE_BITAND: |
850 | case NODE_BITOR: | 888 | case NODE_BITOR: |
889 | case NODE_BITXOR: | ||
851 | case NODE_BITLSHIFT: | 890 | case NODE_BITLSHIFT: |
852 | case NODE_BITRSHIFT: { | 891 | case NODE_BITRSHIFT: { |
853 | Str left = type_inference(a, node->left, scope); | 892 | Str left = type_inference(a, node->binary.left, scope); |
854 | Str right = type_inference(a, node->right, scope); | 893 | Str right = type_inference(a, node->binary.right, scope); |
855 | if (!strset_lookup(&a->integer_types, left) || | 894 | if (!strset_lookup(&a->integer_types, left) || |
856 | !strset_lookup(&a->integer_types, right)) { | 895 | !strset_lookup(&a->integer_types, right)) { |
857 | emit_semantic_error( | 896 | emit_semantic_error( |
@@ -866,8 +905,15 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
866 | case NODE_DIV: | 905 | case NODE_DIV: |
867 | case NODE_MUL: | 906 | case NODE_MUL: |
868 | case NODE_MOD: { | 907 | case NODE_MOD: { |
869 | Str left = type_inference(a, node->left, scope); | 908 | Str left = type_inference(a, node->binary.left, scope); |
870 | Str right = type_inference(a, node->right, scope); | 909 | Str right = type_inference(a, node->binary.right, scope); |
910 | // Enable pointer arithmetic. | ||
911 | if (str_has_prefix(left, cstr("@"))) { | ||
912 | left = cstr("Ptr"); | ||
913 | } | ||
914 | if (str_has_prefix(right, cstr("@"))) { | ||
915 | right = cstr("Ptr"); | ||
916 | } | ||
871 | if (!strset_lookup(&a->numeric_types, left) || | 917 | if (!strset_lookup(&a->numeric_types, left) || |
872 | !strset_lookup(&a->numeric_types, right)) { | 918 | !strset_lookup(&a->numeric_types, right)) { |
873 | emit_semantic_error( | 919 | emit_semantic_error( |
@@ -875,73 +921,149 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
875 | return cstr(""); | 921 | return cstr(""); |
876 | } | 922 | } |
877 | if (!str_eq(left, right)) { | 923 | if (!str_eq(left, right)) { |
878 | emit_semantic_error( | 924 | if (!((strset_lookup(&a->integer_types, left) && |
879 | a, node, cstr("mismatched types on binary expression")); | 925 | strset_lookup(&a->integer_types, right)) || |
880 | return cstr(""); | 926 | (strset_lookup(&a->float_types, left) && |
927 | strset_lookup(&a->float_types, right)))) { | ||
928 | emit_semantic_error( | ||
929 | a, node, cstr("mismatched types on binary expression")); | ||
930 | return cstr(""); | ||
931 | } | ||
881 | } | 932 | } |
882 | node->type = left; | 933 | node->type = left; |
883 | return node->type; | 934 | return node->type; |
884 | } break; | 935 | } break; |
885 | case NODE_NUM_UINT: { | 936 | case NODE_NUM_UINT: { |
886 | node->type = cstr("int"); | 937 | node->type = cstr("UInt"); |
887 | return node->type; | 938 | return node->type; |
888 | } break; | 939 | } break; |
889 | case NODE_NUM_INT: { | 940 | case NODE_NUM_INT: { |
890 | node->type = cstr("int"); | 941 | node->type = cstr("Int"); |
891 | return node->type; | 942 | return node->type; |
892 | } break; | 943 | } break; |
893 | case NODE_NUM_FLOAT: { | 944 | case NODE_NUM_FLOAT: { |
894 | node->type = cstr("f64"); | 945 | node->type = cstr("F64"); |
895 | return node->type; | 946 | return node->type; |
896 | } break; | 947 | } break; |
897 | case NODE_STRING: { | 948 | case NODE_STRING: { |
898 | node->type = cstr("str"); | 949 | node->type = cstr("Str"); |
899 | return node->type; | 950 | return node->type; |
900 | } break; | 951 | } break; |
901 | case NODE_ARR_TYPE: | ||
902 | case NODE_TYPE: { | 952 | case NODE_TYPE: { |
903 | SymbolMap *type = find_type(scope, node->value.str); | 953 | Str base_type = node->value.str; |
904 | if (!type) { | 954 | StrSet *set = find_type(scope, node->value.str); |
955 | if (!set) { | ||
905 | emit_semantic_error(a, node, cstr("unknown type")); | 956 | emit_semantic_error(a, node, cstr("unknown type")); |
906 | return cstr(""); | 957 | return cstr(""); |
907 | } | 958 | } |
908 | node->type = type->val.name; | 959 | Node *next = node->t.next; |
960 | Str type = cstr(""); | ||
961 | while (next) { | ||
962 | switch (next->kind) { | ||
963 | case NODE_PTR: { | ||
964 | Str suffix = cstr("@"); | ||
965 | type = str_concat(type, suffix, a->storage); | ||
966 | } break; | ||
967 | case NODE_ARR: { | ||
968 | Str suffix = cstr("["); | ||
969 | switch (next->array.kind) { | ||
970 | case NODE_ARR_STATIC: { | ||
971 | suffix = str_concat( | ||
972 | suffix, | ||
973 | str_from_int(next->array.size->value.i, | ||
974 | a->storage), | ||
975 | a->storage); | ||
976 | suffix = | ||
977 | str_concat(suffix, cstr("]"), a->storage); | ||
978 | } break; | ||
979 | default: { | ||
980 | emit_semantic_error(a, node, | ||
981 | cstr("unimplemented")); | ||
982 | return cstr(""); | ||
983 | } break; | ||
984 | } | ||
985 | type = str_concat(type, suffix, a->storage); | ||
986 | } break; | ||
987 | default: break; | ||
988 | } | ||
989 | next = next->t.next; | ||
990 | } | ||
991 | type = str_concat(type, base_type, a->storage); | ||
992 | node->type = type; | ||
993 | return node->type; | ||
994 | } break; | ||
995 | case NODE_DEREF: { | ||
996 | Node *next = node->deref.next; | ||
997 | Str amount = cstr("@"); | ||
998 | while (next) { | ||
999 | if (next->kind == NODE_SYMBOL) { | ||
1000 | break; | ||
1001 | } | ||
1002 | next = next->deref.next; | ||
1003 | amount = str_concat(cstr("@"), amount, a->storage); | ||
1004 | } | ||
1005 | Str symbol = next->value.str; | ||
1006 | Str type = type_inference(a, next, scope); | ||
1007 | if (str_has_prefix(type, cstr("["))) { | ||
1008 | str_split(&type, cstr("]")); | ||
1009 | type = str_concat(cstr("@"), type, a->storage); | ||
1010 | } | ||
1011 | if (!str_has_prefix(type, amount)) { | ||
1012 | eprintln( | ||
1013 | "%s:%d:%d: error: invalid type dereference %s from type %s", | ||
1014 | a->file_name, node->line, node->col, | ||
1015 | str_concat(symbol, amount, a->storage), type); | ||
1016 | a->err = true; | ||
1017 | return cstr(""); | ||
1018 | } | ||
1019 | type = str_remove_prefix(type, amount); | ||
1020 | node->value.str = next->value.str; | ||
1021 | node->unique_name = next->unique_name; | ||
1022 | node->type = type; | ||
909 | return node->type; | 1023 | return node->type; |
910 | } break; | 1024 | } break; |
911 | case NODE_SYMBOL_IDX: | ||
912 | case NODE_SYMBOL: { | 1025 | case NODE_SYMBOL: { |
913 | Str symbol = node->value.str; | 1026 | Str symbol = node->value.str; |
914 | SymbolMap *type = find_type(scope, symbol); | 1027 | |
915 | if (!type) { | 1028 | FindSymbolResult sym = find_symbol(scope, symbol); |
1029 | if (!sym.map) { | ||
916 | eprintln("%s:%d:%d: error: couldn't resolve symbol '%s'", | 1030 | eprintln("%s:%d:%d: error: couldn't resolve symbol '%s'", |
917 | a->file_name, node->line, node->col, symbol); | 1031 | a->file_name, node->line, node->col, symbol); |
918 | a->err = true; | 1032 | a->err = true; |
919 | return cstr(""); | 1033 | return cstr(""); |
920 | } | 1034 | } |
921 | 1035 | ||
922 | FindSymbolResult sym = find_symbol(scope, symbol); | 1036 | if (!str_eq(sym.scope->name, scope->name) && sym.scope->name.size) { |
1037 | eprintln( | ||
1038 | "%s:%d:%d: error: can't capture external local symbol '%s'", | ||
1039 | a->file_name, node->line, node->col, symbol); | ||
1040 | a->err = true; | ||
1041 | return cstr(""); | ||
1042 | } | ||
923 | node->unique_name = str_concat(cstr("."), symbol, a->storage); | 1043 | node->unique_name = str_concat(cstr("."), symbol, a->storage); |
924 | node->unique_name = | 1044 | node->unique_name = |
925 | str_concat(node->unique_name, | 1045 | str_concat(node->unique_name, |
926 | str_from_int(sym.scope->id, a->storage), a->storage); | 1046 | str_from_int(sym.scope->id, a->storage), a->storage); |
927 | 1047 | ||
928 | Str type_name = type->val.name; | 1048 | Str type_name = sym.map->val.name; |
929 | if (node->kind == NODE_SYMBOL_IDX) { | 1049 | // if (node->kind == NODE_SYMBOL_IDX) { |
930 | Str idx_type = type_inference(a, node->arr_size, scope); | 1050 | // // TODO: get rid of NODE_SYMBOL_IDX, use deref instead |
931 | if (!strset_lookup(&a->integer_types, idx_type)) { | 1051 | // Str idx_type = type_inference(a, node->sym.arr_size, scope); |
932 | emit_semantic_error( | 1052 | // if (!strset_lookup(&a->integer_types, idx_type)) { |
933 | a, node, cstr("can't resolve non integer index")); | 1053 | // emit_semantic_error( |
934 | return cstr(""); | 1054 | // a, node, cstr("can't resolve non integer index")); |
935 | } | 1055 | // return cstr(""); |
936 | type_name = str_remove_prefix(type_name, cstr("@")); | 1056 | // } |
937 | } | 1057 | // if (str_has_prefix(type_name, cstr("@"))) { |
938 | if (node->is_ptr) { | 1058 | // type_name = str_remove_prefix(type_name, cstr("@")); |
939 | type_name = str_concat(cstr("@"), type_name, a->storage); | 1059 | // } else if (str_has_prefix(type_name, cstr("["))) { |
940 | } | 1060 | // str_split(&type_name, cstr("]")); |
1061 | // } | ||
1062 | // } | ||
941 | 1063 | ||
942 | FindEnumResult e = find_enum(scope, type_name); | 1064 | FindEnumResult e = find_enum(scope, type_name); |
943 | if (e.map && str_eq(symbol, type_name)) { | 1065 | if (e.map && str_eq(symbol, type_name)) { |
944 | if (!node->next) { | 1066 | if (!node->sym.next) { |
945 | eprintln( | 1067 | eprintln( |
946 | "%s:%d:%d: error: unspecified enum field for symbol " | 1068 | "%s:%d:%d: error: unspecified enum field for symbol " |
947 | "'%s'", | 1069 | "'%s'", |
@@ -951,20 +1073,21 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
951 | } | 1073 | } |
952 | // Check if there is a next and it matches the enum field. | 1074 | // Check if there is a next and it matches the enum field. |
953 | Str field = str_concat(type_name, cstr("."), a->storage); | 1075 | Str field = str_concat(type_name, cstr("."), a->storage); |
954 | field = str_concat(field, node->next->value.str, a->storage); | 1076 | field = |
1077 | str_concat(field, node->sym.next->value.str, a->storage); | ||
955 | if (!enummap_lookup(&e.scope->enums, field)) { | 1078 | if (!enummap_lookup(&e.scope->enums, field)) { |
956 | eprintln( | 1079 | eprintln( |
957 | "%s:%d:%d: error: unknown enum field for " | 1080 | "%s:%d:%d: error: unknown enum field for " |
958 | "'%s': %s", | 1081 | "'%s': %s", |
959 | a->file_name, node->line, node->col, symbol, | 1082 | a->file_name, node->line, node->col, symbol, |
960 | node->next->value.str); | 1083 | node->sym.next->value.str); |
961 | a->err = true; | 1084 | a->err = true; |
962 | return cstr(""); | 1085 | return cstr(""); |
963 | } | 1086 | } |
964 | 1087 | ||
965 | node->next->type = type_name; | 1088 | node->sym.next->type = type_name; |
966 | node->type = type_name; | 1089 | node->type = type_name; |
967 | return node->next->type; | 1090 | return node->sym.next->type; |
968 | } | 1091 | } |
969 | 1092 | ||
970 | FindStructResult s = find_struct(scope, type_name); | 1093 | FindStructResult s = find_struct(scope, type_name); |
@@ -977,11 +1100,11 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
977 | a->err = true; | 1100 | a->err = true; |
978 | return cstr(""); | 1101 | return cstr(""); |
979 | } else { | 1102 | } else { |
980 | if (node->next) { | 1103 | if (node->sym.next) { |
981 | Str chain = type_name; | 1104 | Str chain = type_name; |
982 | Node *next = node; | 1105 | Node *next = node; |
983 | while (next->next) { | 1106 | while (next->sym.next) { |
984 | next = next->next; | 1107 | next = next->sym.next; |
985 | chain = str_concat(chain, cstr("."), a->storage); | 1108 | chain = str_concat(chain, cstr("."), a->storage); |
986 | chain = | 1109 | chain = |
987 | str_concat(chain, next->value.str, a->storage); | 1110 | str_concat(chain, next->value.str, a->storage); |
@@ -996,18 +1119,18 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
996 | return cstr(""); | 1119 | return cstr(""); |
997 | } | 1120 | } |
998 | Str field_type = field->val.type; | 1121 | Str field_type = field->val.type; |
999 | if (next->kind == NODE_SYMBOL_IDX) { | 1122 | // if (next->kind == NODE_SYMBOL_IDX) { |
1000 | Str idx_type = | 1123 | // Str idx_type = |
1001 | type_inference(a, next->arr_size, scope); | 1124 | // type_inference(a, next->sym.arr_size, scope); |
1002 | if (!strset_lookup(&a->integer_types, idx_type)) { | 1125 | // if (!strset_lookup(&a->integer_types, idx_type)) { |
1003 | emit_semantic_error( | 1126 | // emit_semantic_error( |
1004 | a, next, | 1127 | // a, next, |
1005 | cstr("can't resolve non integer index")); | 1128 | // cstr("can't resolve non integer index")); |
1006 | return cstr(""); | 1129 | // return cstr(""); |
1007 | } | 1130 | // } |
1008 | field_type = | 1131 | // field_type = |
1009 | str_remove_prefix(field_type, cstr("@")); | 1132 | // str_remove_prefix(field_type, cstr("@")); |
1010 | } | 1133 | // } |
1011 | node->type = field_type; | 1134 | node->type = field_type; |
1012 | return node->type; | 1135 | return node->type; |
1013 | } | 1136 | } |
@@ -1016,6 +1139,12 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
1016 | node->type = type_name; | 1139 | node->type = type_name; |
1017 | return node->type; | 1140 | return node->type; |
1018 | } break; | 1141 | } break; |
1142 | case NODE_PTR: { | ||
1143 | Str type = type_inference(a, node->t.next, scope); | ||
1144 | type = str_concat(cstr("@"), type, a->storage); | ||
1145 | node->type = type; | ||
1146 | return node->type; | ||
1147 | } break; | ||
1019 | case NODE_STRUCT_LIT: { | 1148 | case NODE_STRUCT_LIT: { |
1020 | Str name = node->value.str; | 1149 | Str name = node->value.str; |
1021 | FindStructResult s = find_struct(scope, name); | 1150 | FindStructResult s = find_struct(scope, name); |
@@ -1064,27 +1193,56 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
1064 | str_concat(node->unique_name, | 1193 | str_concat(node->unique_name, |
1065 | str_from_int(sym.scope->id, a->storage), a->storage); | 1194 | str_from_int(sym.scope->id, a->storage), a->storage); |
1066 | 1195 | ||
1067 | // Check that actual parameters typecheck | 1196 | // Check function aritiy. |
1068 | Str args = cstr(""); | 1197 | sz arity_fun = fun->val.param_arity; |
1198 | sz arity_call = array_size(node->elements); | ||
1199 | if (arity_fun != -1) { | ||
1200 | if (arity_fun != arity_call) { | ||
1201 | eprintln( | ||
1202 | "%s:%d:%d: error: wrong number of parameters for " | ||
1203 | "funcall: " | ||
1204 | "%s " | ||
1205 | "expected " | ||
1206 | "%d" | ||
1207 | " got %d", | ||
1208 | a->file_name, node->line, node->col, symbol, arity_fun, | ||
1209 | arity_call); | ||
1210 | a->err = true; | ||
1211 | return cstr(""); | ||
1212 | } | ||
1213 | } | ||
1214 | |||
1215 | if (sym.map->val.kind == SYM_BUILTIN_FUN && | ||
1216 | str_eq(fun->key, cstr("sizeof"))) { | ||
1217 | // Node *expr = node->elements[0]; | ||
1218 | // Str type = type_inference(a, expr, scope); | ||
1219 | node->type = fun->val.return_type; | ||
1220 | return node->type; | ||
1221 | } | ||
1222 | |||
1069 | for (sz i = 0; i < array_size(node->elements); i++) { | 1223 | for (sz i = 0; i < array_size(node->elements); i++) { |
1070 | Node *expr = node->elements[i]; | 1224 | Node *expr = node->elements[i]; |
1071 | Str type = type_inference(a, expr, scope); | 1225 | Str type = type_inference(a, expr, scope); |
1072 | args = str_concat(args, type, a->storage); | 1226 | if (!str_eq(fun->val.param_type, cstr("..."))) { |
1073 | if (i != array_size(node->elements) - 1) { | 1227 | Str expected = fun->val.param_types[i]; |
1074 | args = str_concat(args, cstr(","), a->storage); | 1228 | if (!str_eq(type, expected)) { |
1229 | if (!(strset_lookup(&a->integer_types, type) && | ||
1230 | strset_lookup(&a->integer_types, expected)) || | ||
1231 | !(strset_lookup(&a->numeric_types, type) && | ||
1232 | strset_lookup(&a->numeric_types, expected))) { | ||
1233 | eprintln( | ||
1234 | "%s:%d:%d: error: mismatched parameter types: " | ||
1235 | "%s " | ||
1236 | "expected " | ||
1237 | "%s", | ||
1238 | a->file_name, node->line, node->col, type, | ||
1239 | expected); | ||
1240 | a->err = true; | ||
1241 | return cstr(""); | ||
1242 | } | ||
1243 | } | ||
1075 | } | 1244 | } |
1076 | } | 1245 | } |
1077 | if (!args.size) { | ||
1078 | args = cstr("nil"); | ||
1079 | } | ||
1080 | Str expected = fun->val.param_type; | ||
1081 | if (!str_eq(args, expected) && !str_eq(expected, cstr("..."))) { | ||
1082 | eprintln( | ||
1083 | "%s:%d:%d: error: mismatched parameter types: %s expected " | ||
1084 | "%s", | ||
1085 | a->file_name, node->line, node->col, args, expected); | ||
1086 | a->err = true; | ||
1087 | } | ||
1088 | node->type = fun->val.return_type; | 1246 | node->type = fun->val.return_type; |
1089 | return node->type; | 1247 | return node->type; |
1090 | } break; | 1248 | } break; |
@@ -1094,12 +1252,22 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
1094 | for (sz i = 0; i < array_size(node->elements); i++) { | 1252 | for (sz i = 0; i < array_size(node->elements); i++) { |
1095 | Node *expr = node->elements[i]; | 1253 | Node *expr = node->elements[i]; |
1096 | type = type_inference(a, expr, scope); | 1254 | type = type_inference(a, expr, scope); |
1255 | if (str_has_prefix(type, cstr("ret:")) || | ||
1256 | str_has_prefix(type, cstr("flow:"))) { | ||
1257 | break; | ||
1258 | } | ||
1097 | } | 1259 | } |
1098 | node->type = type; | 1260 | node->type = type; |
1099 | return node->type; | 1261 | return node->type; |
1100 | } break; | 1262 | } break; |
1101 | case NODE_RETURN: { | 1263 | case NODE_RETURN: { |
1102 | Str ret_type = cstr(""); | 1264 | if (!scope->name.size) { |
1265 | emit_semantic_error( | ||
1266 | a, node, cstr("return statement outside a function")); | ||
1267 | a->err = true; | ||
1268 | return cstr(""); | ||
1269 | } | ||
1270 | Str ret_type = cstr("ret:"); | ||
1103 | for (sz i = 0; i < array_size(node->elements); i++) { | 1271 | for (sz i = 0; i < array_size(node->elements); i++) { |
1104 | Node *expr = node->elements[i]; | 1272 | Node *expr = node->elements[i]; |
1105 | Str type = type_inference(a, expr, scope); | 1273 | Str type = type_inference(a, expr, scope); |
@@ -1114,123 +1282,156 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
1114 | node->type = ret_type; | 1282 | node->type = ret_type; |
1115 | return node->type; | 1283 | return node->type; |
1116 | } break; | 1284 | } break; |
1285 | case NODE_CONTINUE: | ||
1286 | case NODE_BREAK: { | ||
1287 | // Check if we are inside a loop. | ||
1288 | Node *parent = node->parent; | ||
1289 | bool inside_loop = false; | ||
1290 | while (parent != NULL) { | ||
1291 | if (parent->kind == NODE_WHILE) { | ||
1292 | inside_loop = true; | ||
1293 | break; | ||
1294 | } | ||
1295 | parent = parent->parent; | ||
1296 | } | ||
1297 | if (!inside_loop) { | ||
1298 | eprintln( | ||
1299 | "%s:%d:%d: error: control flow statement outside a " | ||
1300 | "loop", | ||
1301 | a->file_name, node->line, node->col); | ||
1302 | a->err = true; | ||
1303 | return cstr(""); | ||
1304 | } | ||
1305 | node->type = cstr("flow:"); | ||
1306 | return node->type; | ||
1307 | } break; | ||
1117 | case NODE_FUN: { | 1308 | case NODE_FUN: { |
1118 | node->type = cstr("nil"); | 1309 | node->type = cstr("nil"); |
1119 | Scope *prev_scope = scope; | 1310 | Scope *prev_scope = scope; |
1120 | scope = typescope_alloc(a, scope); | 1311 | scope = typescope_alloc(a, scope); |
1121 | Str param_type = cstr(""); | 1312 | Str param_type = cstr(""); |
1122 | for (sz i = 0; i < array_size(node->func_params); i++) { | 1313 | Str symbol = node->func.name->value.str; |
1123 | Node *param = node->func_params[i]; | 1314 | Fun fun = (Fun){.name = symbol}; |
1124 | Str symbol = param->param_name->value.str; | 1315 | for (sz i = 0; i < array_size(node->func.params); i++) { |
1125 | Str type = param->param_type->value.str; | 1316 | Node *param = node->func.params[i]; |
1126 | if (param->param_type->is_ptr) { | 1317 | Str symbol = param->param.name->value.str; |
1127 | type = str_concat(cstr("@"), type, a->storage); | 1318 | Str type = param->param.type->value.str; |
1128 | } | 1319 | param->param.name->type = |
1129 | if (param->param_type->kind == NODE_ARR_TYPE) { | 1320 | type_inference(a, param->param.type, scope); |
1130 | type = str_concat(cstr("@"), type, a->storage); | ||
1131 | } | ||
1132 | param->param_name->type = | ||
1133 | type_inference(a, param->param_type, scope); | ||
1134 | param->type = type; | 1321 | param->type = type; |
1322 | array_push(fun.param_types, type, a->storage); | ||
1135 | symmap_insert(&scope->symbols, symbol, | 1323 | symmap_insert(&scope->symbols, symbol, |
1136 | (Symbol){.name = type, .kind = SYM_PARAM}, | 1324 | (Symbol){.name = type, .kind = SYM_PARAM}, |
1137 | a->storage); | 1325 | a->storage); |
1138 | param_type = str_concat(param_type, type, a->storage); | 1326 | param_type = str_concat(param_type, type, a->storage); |
1139 | if (i != array_size(node->func_params) - 1) { | 1327 | if (i != array_size(node->func.params) - 1) { |
1140 | param_type = str_concat(param_type, cstr(","), a->storage); | 1328 | param_type = str_concat(param_type, cstr(","), a->storage); |
1141 | } | 1329 | } |
1330 | symbol = str_concat(cstr("."), symbol, a->storage); | ||
1331 | symbol = str_concat(symbol, str_from_int(scope->id, a->storage), | ||
1332 | a->storage); | ||
1333 | param->unique_name = symbol; | ||
1142 | } | 1334 | } |
1143 | if (!param_type.size) { | 1335 | if (!param_type.size) { |
1144 | param_type = cstr("nil"); | 1336 | param_type = cstr("nil"); |
1145 | } | 1337 | } |
1146 | node->fun_params = param_type; | 1338 | node->type_params = param_type; |
1339 | fun.param_arity = array_size(node->func.params); | ||
1147 | 1340 | ||
1148 | Str ret_type = cstr(""); | 1341 | Str ret_type = cstr(""); |
1149 | for (sz i = 0; i < array_size(node->func_ret); i++) { | 1342 | for (sz i = 0; i < array_size(node->func.ret); i++) { |
1150 | Node *expr = node->func_ret[i]; | 1343 | Node *expr = node->func.ret[i]; |
1151 | Str type = type_inference(a, expr, scope); | 1344 | Str type = type_inference(a, expr, scope); |
1152 | if (expr->is_ptr) { | ||
1153 | type = str_concat(cstr("@"), type, a->storage); | ||
1154 | } | ||
1155 | if (expr->kind == NODE_ARR_TYPE) { | ||
1156 | type = str_concat(cstr("@"), type, a->storage); | ||
1157 | } | ||
1158 | ret_type = str_concat(ret_type, type, a->storage); | 1345 | ret_type = str_concat(ret_type, type, a->storage); |
1159 | if (i != array_size(node->func_ret) - 1) { | 1346 | array_push(fun.return_types, ret_type, a->storage); |
1347 | if (i != array_size(node->func.ret) - 1) { | ||
1160 | ret_type = str_concat(ret_type, cstr(","), a->storage); | 1348 | ret_type = str_concat(ret_type, cstr(","), a->storage); |
1161 | } | 1349 | } |
1162 | } | 1350 | } |
1351 | fun.return_arity = array_size(node->func.ret); | ||
1163 | if (!ret_type.size) { | 1352 | if (!ret_type.size) { |
1164 | ret_type = cstr("nil"); | 1353 | ret_type = cstr("nil"); |
1165 | } | 1354 | } |
1166 | node->fun_return = ret_type; | 1355 | node->type_returns = ret_type; |
1167 | 1356 | ||
1168 | Str symbol = node->func_name->value.str; | ||
1169 | if (prev_scope->parent != NULL) { | 1357 | if (prev_scope->parent != NULL) { |
1170 | if (symmap_lookup(&prev_scope->symbols, symbol)) { | 1358 | if (symmap_lookup(&prev_scope->symbols, symbol)) { |
1171 | eprintln( | 1359 | eprintln( |
1172 | "%s:%d:%d: error: function '%s' already defined in " | 1360 | "%s:%d:%d: error: function '%s' already defined in " |
1173 | "current " | 1361 | "current " |
1174 | "scope ", | 1362 | "scope ", |
1175 | a->file_name, node->var_name->line, node->var_name->col, | 1363 | a->file_name, node->var.name->line, node->var.name->col, |
1176 | symbol); | 1364 | symbol); |
1177 | a->err = true; | 1365 | a->err = true; |
1178 | return cstr(""); | 1366 | return cstr(""); |
1179 | } | 1367 | } |
1180 | symmap_insert(&scope->symbols, symbol, | 1368 | symmap_insert(&prev_scope->symbols, symbol, |
1181 | (Symbol){.name = symbol, .kind = SYM_FUN}, | 1369 | (Symbol){.name = symbol, .kind = SYM_FUN}, |
1182 | a->storage); | 1370 | a->storage); |
1183 | } | 1371 | } |
1184 | scope->name = symbol; | 1372 | scope->name = symbol; |
1185 | funmap_insert(&prev_scope->funcs, symbol, | 1373 | fun.param_type = param_type; |
1186 | (Fun){.name = symbol, | 1374 | fun.return_type = ret_type; |
1187 | .param_type = param_type, | 1375 | funmap_insert(&prev_scope->funcs, symbol, fun, a->storage); |
1188 | .return_type = ret_type}, | ||
1189 | a->storage); | ||
1190 | symbol = str_concat(cstr("."), symbol, a->storage); | 1376 | symbol = str_concat(cstr("."), symbol, a->storage); |
1191 | symbol = str_concat(symbol, str_from_int(prev_scope->id, a->storage), | 1377 | symbol = str_concat( |
1192 | a->storage); | 1378 | symbol, str_from_int(prev_scope->id, a->storage), a->storage); |
1193 | node->unique_name = symbol; | 1379 | node->unique_name = symbol; |
1194 | 1380 | ||
1195 | if (node->func_body->kind == NODE_BLOCK) { | 1381 | if (node->func.body->kind == NODE_BLOCK) { |
1196 | Str type; | 1382 | Str type; |
1197 | for (sz i = 0; i < array_size(node->func_body->elements); i++) { | 1383 | for (sz i = 0; i < array_size(node->func.body->elements); i++) { |
1198 | Node *expr = node->func_body->elements[i]; | 1384 | Node *expr = node->func.body->elements[i]; |
1199 | type = type_inference(a, expr, scope); | 1385 | type = type_inference(a, expr, scope); |
1200 | } | 1386 | } |
1201 | if (!type.size) { | 1387 | if (!type.size) { |
1202 | type = cstr("nil"); | 1388 | type = cstr("nil"); |
1203 | } | 1389 | } |
1204 | node->func_body->type = type; | 1390 | node->func.body->type = type; |
1205 | } else { | 1391 | } else { |
1206 | type_inference(a, node->func_body, scope); | 1392 | type_inference(a, node->func.body, scope); |
1207 | } | 1393 | } |
1208 | 1394 | ||
1209 | // Ensure main body return matches the prototype. | 1395 | // Ensure main body return matches the prototype. |
1210 | if (!str_eq(node->func_body->type, ret_type)) { | 1396 | Str type = str_remove_prefix(node->func.body->type, cstr("ret:")); |
1211 | eprintln( | 1397 | node->func.body->type = type; |
1212 | "%s:%d:%d: error: mismatched return type %s, expected %s", | 1398 | if (!str_eq(type, ret_type)) { |
1213 | a->file_name, node->line, node->col, node->func_body->type, | 1399 | if (!(strset_lookup(&a->integer_types, type) && |
1214 | ret_type); | 1400 | strset_lookup(&a->integer_types, ret_type)) || |
1215 | a->err = true; | 1401 | !(strset_lookup(&a->numeric_types, type) && |
1402 | strset_lookup(&a->numeric_types, ret_type))) { | ||
1403 | eprintln( | ||
1404 | "%s:%d:%d: error: mismatched return type %s, " | ||
1405 | "expected " | ||
1406 | "%s", | ||
1407 | a->file_name, node->line, node->col, type, ret_type); | ||
1408 | a->err = true; | ||
1409 | } | ||
1216 | } | 1410 | } |
1217 | 1411 | ||
1218 | // Ensure ALL return statements match the function prototype. | 1412 | // Ensure ALL return statements match the function prototype. |
1219 | typecheck_returns(a, node->func_body, ret_type); | 1413 | typecheck_returns(a, node->func.body, ret_type); |
1220 | |||
1221 | // TODO: should return statements be allowed on let blocks? | ||
1222 | return node->type; | 1414 | return node->type; |
1223 | } break; | 1415 | } break; |
1224 | default: { | 1416 | default: { |
1225 | emit_semantic_error(a, node, | 1417 | eprintln( |
1226 | cstr("type inference not implemented for this " | 1418 | "%s:%d:%d: error: type inference not implemented for node " |
1227 | "kind of expression")); | 1419 | "type: %s", |
1228 | println("KIND: %s", node_str[node->kind]); | 1420 | a->file_name, node->line, node->col, node_str[node->kind]); |
1421 | a->err = true; | ||
1229 | } break; | 1422 | } break; |
1230 | } | 1423 | } |
1231 | return cstr(""); | 1424 | return cstr(""); |
1232 | } | 1425 | } |
1233 | 1426 | ||
1427 | typedef struct BuiltinFun { | ||
1428 | Str name; | ||
1429 | Str param_type; | ||
1430 | Str return_type; | ||
1431 | sz param_arity; | ||
1432 | sz return_arity; | ||
1433 | } BuiltinFun; | ||
1434 | |||
1234 | void | 1435 | void |
1235 | symbolic_analysis(Analyzer *a, Parser *parser) { | 1436 | symbolic_analysis(Analyzer *a, Parser *parser) { |
1236 | Scope *scope = typescope_alloc(a, NULL); | 1437 | Scope *scope = typescope_alloc(a, NULL); |
@@ -1238,64 +1439,114 @@ symbolic_analysis(Analyzer *a, Parser *parser) { | |||
1238 | assert(parser); | 1439 | assert(parser); |
1239 | 1440 | ||
1240 | // Fill builtin tables. | 1441 | // Fill builtin tables. |
1241 | Str builtin_functions[] = { | 1442 | BuiltinFun builtin_functions[] = { |
1242 | cstr("print"), | 1443 | {cstr("print"), cstr("..."), cstr("nil"), -1, 0}, |
1243 | cstr("println"), | 1444 | {cstr("println"), cstr("..."), cstr("nil"), -1, 0}, |
1445 | {cstr("sizeof"), cstr(":"), cstr("Int"), 1, 1}, | ||
1244 | }; | 1446 | }; |
1245 | for (sz i = 0; i < LEN(builtin_functions); i++) { | 1447 | for (sz i = 0; i < LEN(builtin_functions); i++) { |
1246 | Str symbol = builtin_functions[i]; | 1448 | Str symbol = builtin_functions[i].name; |
1449 | Str param_type = builtin_functions[i].param_type; | ||
1450 | Str return_type = builtin_functions[i].return_type; | ||
1451 | sz param_arity = builtin_functions[i].param_arity; | ||
1452 | sz return_arity = builtin_functions[i].return_arity; | ||
1247 | symmap_insert(&scope->symbols, symbol, | 1453 | symmap_insert(&scope->symbols, symbol, |
1248 | (Symbol){.name = symbol, .kind = SYM_BUILTIN_FUN}, | 1454 | (Symbol){.name = symbol, .kind = SYM_BUILTIN_FUN}, |
1249 | a->storage); | 1455 | a->storage); |
1250 | funmap_insert(&scope->funcs, symbol, | 1456 | funmap_insert(&scope->funcs, symbol, |
1251 | (Fun){.name = symbol, | 1457 | (Fun){ |
1252 | .param_type = cstr("..."), | 1458 | .name = symbol, |
1253 | .return_type = cstr("nil")}, | 1459 | .param_type = param_type, |
1460 | .return_type = return_type, | ||
1461 | .param_arity = param_arity, | ||
1462 | .return_arity = return_arity, | ||
1463 | }, | ||
1254 | a->storage); | 1464 | a->storage); |
1255 | } | 1465 | } |
1256 | Str builtin_types[] = { | 1466 | Str builtin_types[] = { |
1257 | cstr("u8"), cstr("s8"), cstr("u16"), cstr("s16"), | 1467 | cstr("U8"), cstr("S8"), cstr("U16"), cstr("S16"), |
1258 | cstr("u32"), cstr("s32"), cstr("u64"), cstr("s64"), | 1468 | cstr("U32"), cstr("S32"), cstr("U64"), cstr("S64"), |
1259 | cstr("f32"), cstr("f64"), cstr("ptr"), cstr("int"), | 1469 | cstr("F32"), cstr("F64"), cstr("Ptr"), cstr("Int"), |
1260 | cstr("uint"), cstr("str"), cstr("bool"), cstr("nil")}; | 1470 | cstr("UInt"), cstr("Str"), cstr("Bool"), cstr("Nil")}; |
1261 | for (sz i = 0; i < LEN(builtin_types); i++) { | 1471 | for (sz i = 0; i < LEN(builtin_types); i++) { |
1262 | Str type = builtin_types[i]; | 1472 | Str type = builtin_types[i]; |
1263 | symmap_insert(&scope->symbols, type, | 1473 | symmap_insert(&scope->symbols, type, |
1264 | (Symbol){.name = type, .kind = SYM_BUILTIN_TYPE}, | 1474 | (Symbol){.name = cstr("nil"), .kind = SYM_BUILTIN_TYPE}, |
1265 | a->storage); | 1475 | a->storage); |
1476 | strset_insert(&scope->types, type, a->storage); | ||
1266 | } | 1477 | } |
1267 | Str numeric_types[] = { | 1478 | Str numeric_types[] = { |
1268 | cstr("u8"), cstr("s8"), cstr("u16"), cstr("s16"), cstr("u32"), | 1479 | cstr("U8"), cstr("S8"), cstr("U16"), cstr("S16"), cstr("U32"), |
1269 | cstr("s32"), cstr("u64"), cstr("s64"), cstr("f32"), cstr("f64"), | 1480 | cstr("S32"), cstr("U64"), cstr("S64"), cstr("F32"), cstr("F64"), |
1270 | cstr("ptr"), cstr("int"), cstr("uint"), | 1481 | cstr("Ptr"), cstr("Int"), cstr("UInt"), |
1271 | }; | 1482 | }; |
1272 | for (sz i = 0; i < LEN(numeric_types); i++) { | 1483 | for (sz i = 0; i < LEN(numeric_types); i++) { |
1273 | Str type = numeric_types[i]; | 1484 | Str type = numeric_types[i]; |
1274 | strset_insert(&a->numeric_types, type, a->storage); | 1485 | strset_insert(&a->numeric_types, type, a->storage); |
1275 | } | 1486 | } |
1276 | Str integer_types[] = { | 1487 | Str integer_types[] = { |
1277 | cstr("u8"), cstr("s8"), cstr("u16"), cstr("s16"), | 1488 | cstr("U8"), cstr("S8"), cstr("U16"), cstr("S16"), |
1278 | cstr("u32"), cstr("s32"), cstr("u64"), cstr("s64"), | 1489 | cstr("U32"), cstr("S32"), cstr("U64"), cstr("S64"), |
1279 | cstr("ptr"), cstr("int"), cstr("uint"), | 1490 | cstr("Ptr"), cstr("Int"), cstr("UInt"), |
1280 | }; | 1491 | }; |
1281 | for (sz i = 0; i < LEN(integer_types); i++) { | 1492 | for (sz i = 0; i < LEN(integer_types); i++) { |
1282 | Str type = integer_types[i]; | 1493 | Str type = integer_types[i]; |
1283 | strset_insert(&a->integer_types, type, a->storage); | 1494 | strset_insert(&a->integer_types, type, a->storage); |
1284 | } | 1495 | } |
1496 | Str float_types[] = { | ||
1497 | cstr("F32"), | ||
1498 | cstr("F64"), | ||
1499 | }; | ||
1500 | for (sz i = 0; i < LEN(float_types); i++) { | ||
1501 | Str type = float_types[i]; | ||
1502 | strset_insert(&a->float_types, type, a->storage); | ||
1503 | } | ||
1285 | // Find top level function declarations. | 1504 | // Find top level function declarations. |
1286 | for (sz i = 0; i < array_size(parser->nodes); i++) { | 1505 | for (sz i = 0; i < array_size(parser->nodes); i++) { |
1287 | Node *root = parser->nodes[i]; | 1506 | Node *root = parser->nodes[i]; |
1288 | if (root->kind == NODE_FUN) { | 1507 | if (root->kind == NODE_FUN) { |
1289 | Str symbol = root->func_name->value.str; | 1508 | Str symbol = root->func.name->value.str; |
1290 | if (symmap_lookup(&scope->symbols, symbol)) { | 1509 | if (symmap_lookup(&scope->symbols, symbol)) { |
1291 | eprintln( | 1510 | eprintln( |
1292 | "%s:%d:%d: error: function '%s' already defined in " | 1511 | "%s:%d:%d: error: function '%s' already defined in " |
1293 | "current " | 1512 | "current " |
1294 | "scope ", | 1513 | "scope ", |
1295 | a->file_name, root->var_name->line, root->var_name->col, | 1514 | a->file_name, root->var.name->line, root->var.name->col, |
1296 | symbol); | 1515 | symbol); |
1297 | a->err = true; | 1516 | a->err = true; |
1298 | } | 1517 | } |
1518 | Fun fun = (Fun){.name = symbol}; | ||
1519 | Str param_type = cstr(""); | ||
1520 | for (sz i = 0; i < array_size(root->func.params); i++) { | ||
1521 | Node *param = root->func.params[i]; | ||
1522 | Str type = param->param.type->value.str; | ||
1523 | array_push(fun.param_types, type, a->storage); | ||
1524 | param_type = str_concat(param_type, type, a->storage); | ||
1525 | if (i != array_size(root->func.params) - 1) { | ||
1526 | param_type = str_concat(param_type, cstr(","), a->storage); | ||
1527 | } | ||
1528 | } | ||
1529 | if (!param_type.size) { | ||
1530 | param_type = cstr("nil"); | ||
1531 | } | ||
1532 | root->type_params = param_type; | ||
1533 | |||
1534 | Str ret_type = cstr(""); | ||
1535 | for (sz i = 0; i < array_size(root->func.ret); i++) { | ||
1536 | Node *expr = root->func.ret[i]; | ||
1537 | Str type = expr->value.str; | ||
1538 | array_push(fun.return_types, ret_type, a->storage); | ||
1539 | ret_type = str_concat(ret_type, type, a->storage); | ||
1540 | if (i != array_size(root->func.ret) - 1) { | ||
1541 | ret_type = str_concat(ret_type, cstr(","), a->storage); | ||
1542 | } | ||
1543 | } | ||
1544 | if (!ret_type.size) { | ||
1545 | ret_type = cstr("nil"); | ||
1546 | } | ||
1547 | fun.param_type = param_type; | ||
1548 | fun.return_type = ret_type; | ||
1549 | funmap_insert(&scope->funcs, symbol, fun, a->storage); | ||
1299 | symmap_insert(&scope->symbols, symbol, | 1550 | symmap_insert(&scope->symbols, symbol, |
1300 | (Symbol){.name = symbol, .kind = SYM_FUN}, | 1551 | (Symbol){.name = symbol, .kind = SYM_FUN}, |
1301 | a->storage); | 1552 | a->storage); |
@@ -5,8 +5,9 @@ | |||
5 | #include "compiler.c" | 5 | #include "compiler.c" |
6 | 6 | ||
7 | #define N_CONST 256 | 7 | #define N_CONST 256 |
8 | #define STACK_SIZE KB(64) | 8 | #define STACK_SIZE MB(4) |
9 | typedef struct VM { | 9 | typedef struct VM { |
10 | Chunk *main; | ||
10 | Chunk *chunk; | 11 | Chunk *chunk; |
11 | u8 stack[STACK_SIZE]; | 12 | u8 stack[STACK_SIZE]; |
12 | Instruction *ip; | 13 | Instruction *ip; |
@@ -20,6 +21,7 @@ vm_init(VM *vm, Chunk *chunk) { | |||
20 | assert(vm); | 21 | assert(vm); |
21 | assert(chunk); | 22 | assert(chunk); |
22 | assert(chunk->code); | 23 | assert(chunk->code); |
24 | vm->main = chunk; | ||
23 | vm->chunk = chunk; | 25 | vm->chunk = chunk; |
24 | vm->ip = vm->chunk->code; | 26 | vm->ip = vm->chunk->code; |
25 | vm->fp = (u64 *)vm->stack; | 27 | vm->fp = (u64 *)vm->stack; |
@@ -75,7 +77,7 @@ vm_run(VM *vm) { | |||
75 | #endif | 77 | #endif |
76 | 78 | ||
77 | switch (instruction.op) { | 79 | switch (instruction.op) { |
78 | case OP_LD64K: { | 80 | case OP_LDCONST: { |
79 | u8 dst = instruction.dst; | 81 | u8 dst = instruction.dst; |
80 | u8 src_a = instruction.a; | 82 | u8 src_a = instruction.a; |
81 | vm->regs[dst].i = vm->chunk->constants[src_a].i; | 83 | vm->regs[dst].i = vm->chunk->constants[src_a].i; |
@@ -83,6 +85,7 @@ vm_run(VM *vm) { | |||
83 | case OP_NOT: OP_UNARY(!, i) break; | 85 | case OP_NOT: OP_UNARY(!, i) break; |
84 | case OP_BITNOT: OP_UNARY(~, i) break; | 86 | case OP_BITNOT: OP_UNARY(~, i) break; |
85 | case OP_BITOR: OP_BINARY(|, i) break; | 87 | case OP_BITOR: OP_BINARY(|, i) break; |
88 | case OP_BITXOR: OP_BINARY(^, i) break; | ||
86 | case OP_BITAND: OP_BINARY(&, i) break; | 89 | case OP_BITAND: OP_BINARY(&, i) break; |
87 | case OP_BITLSHIFT: OP_BINARY(<<, i) break; | 90 | case OP_BITLSHIFT: OP_BINARY(<<, i) break; |
88 | case OP_BITRSHIFT: OP_BINARY(>>, i) break; | 91 | case OP_BITRSHIFT: OP_BINARY(>>, i) break; |
@@ -113,6 +116,7 @@ vm_run(VM *vm) { | |||
113 | case OP_NOTI: OP_UNARY_CONST(!, i) break; | 116 | case OP_NOTI: OP_UNARY_CONST(!, i) break; |
114 | case OP_BITNOTI: OP_UNARY_CONST(~, i) break; | 117 | case OP_BITNOTI: OP_UNARY_CONST(~, i) break; |
115 | case OP_BITORI: OP_BINARY_CONST(|, i) break; | 118 | case OP_BITORI: OP_BINARY_CONST(|, i) break; |
119 | case OP_BITXORI: OP_BINARY_CONST(^, i) break; | ||
116 | case OP_BITANDI: OP_BINARY_CONST(&, i) break; | 120 | case OP_BITANDI: OP_BINARY_CONST(&, i) break; |
117 | case OP_BITLSHIFTI: OP_BINARY_CONST(<<, i) break; | 121 | case OP_BITLSHIFTI: OP_BINARY_CONST(<<, i) break; |
118 | case OP_BITRSHIFTI: OP_BINARY_CONST(>>, i) break; | 122 | case OP_BITRSHIFTI: OP_BINARY_CONST(>>, i) break; |
@@ -140,22 +144,66 @@ vm_run(VM *vm) { | |||
140 | vm->regs[dst].f = | 144 | vm->regs[dst].f = |
141 | fmod(vm->regs[src_a].f, vm->chunk->constants[src_b].f); | 145 | fmod(vm->regs[src_a].f, vm->chunk->constants[src_b].f); |
142 | } break; | 146 | } break; |
147 | case OP_STGVAR: { | ||
148 | u8 dst = instruction.dst; | ||
149 | u8 src = instruction.a; | ||
150 | Variable var = vm->main->vars[dst]; | ||
151 | s64 *stack = (s64 *)&vm->stack[var.offset]; | ||
152 | *stack = vm->regs[src].i; | ||
153 | } break; | ||
154 | case OP_STGVARI: { | ||
155 | u8 dst = instruction.dst; | ||
156 | u8 src = instruction.a; | ||
157 | Variable var = vm->main->vars[dst]; | ||
158 | s64 *stack = (s64 *)&vm->stack[var.offset]; | ||
159 | *stack = vm->chunk->constants[src].i; | ||
160 | } break; | ||
143 | case OP_LDGVAR: { | 161 | case OP_LDGVAR: { |
144 | u8 dst = instruction.dst; | 162 | u8 dst = instruction.dst; |
145 | u8 src = instruction.a; | 163 | u8 src = instruction.a; |
146 | Variable var = vm->chunk->vars[src]; | 164 | Variable var = vm->main->vars[src]; |
147 | s64 *stack = (s64 *)&vm->stack[var.offset]; | 165 | s64 *stack = (s64 *)&vm->stack[var.offset]; |
148 | vm->regs[dst].i = *stack; | 166 | vm->regs[dst].i = *stack; |
149 | } break; | 167 | } break; |
150 | case OP_LDGADDR: { | 168 | case OP_LDGADDR: { |
151 | u8 dst = instruction.dst; | 169 | u8 dst = instruction.dst; |
152 | u8 src = instruction.a; | 170 | u8 src = instruction.a; |
153 | Variable var = vm->chunk->vars[src]; | 171 | Variable var = vm->main->vars[src]; |
154 | s64 *stack = (s64 *)&vm->stack[var.offset]; | 172 | s64 *stack = (s64 *)&vm->stack[var.offset]; |
155 | vm->regs[dst].ptr = (ptrsize)stack; | 173 | vm->regs[dst].ptr = (ptrsize)stack; |
156 | } break; | 174 | } break; |
175 | case OP_STLVAR: { | ||
176 | u8 dst = instruction.dst; | ||
177 | u8 src = instruction.a; | ||
178 | Variable var = vm->chunk->vars[dst]; | ||
179 | vm->fp[var.offset / 8] = vm->regs[src].i; | ||
180 | } break; | ||
181 | case OP_STLVARI: { | ||
182 | u8 dst = instruction.dst; | ||
183 | u8 src = instruction.a; | ||
184 | Variable var = vm->chunk->vars[dst]; | ||
185 | vm->fp[var.offset / 8] = vm->chunk->constants[src].i; | ||
186 | } break; | ||
187 | case OP_LDLVAR: { | ||
188 | u8 dst = instruction.dst; | ||
189 | u8 src = instruction.a; | ||
190 | Variable var = vm->chunk->vars[src]; | ||
191 | vm->regs[dst].i = vm->fp[var.offset / 8]; | ||
192 | } break; | ||
193 | case OP_LDLADDR: { | ||
194 | u8 dst = instruction.dst; | ||
195 | u8 src = instruction.a; | ||
196 | Variable var = vm->chunk->vars[src]; | ||
197 | vm->regs[dst].i = (ptrsize)&vm->fp[var.offset / 8]; | ||
198 | } break; | ||
199 | case OP_LDSTR: { | ||
200 | u8 dst = instruction.dst; | ||
201 | u8 src = instruction.a; | ||
202 | Str *str = &vm->chunk->strings[src]; | ||
203 | vm->regs[dst].ptr = (ptrsize)str; | ||
204 | } break; | ||
157 | case OP_ST64I: { | 205 | case OP_ST64I: { |
158 | sz value = vm->regs[instruction.dst].i; | 206 | sz value = vm->regs[instruction.dst].ptr; |
159 | s64 *addr = (s64 *)vm->regs[instruction.a].ptr; | 207 | s64 *addr = (s64 *)vm->regs[instruction.a].ptr; |
160 | sz offset = vm->chunk->constants[instruction.b].i; | 208 | sz offset = vm->chunk->constants[instruction.b].i; |
161 | addr[offset] = value; | 209 | addr[offset] = value; |
@@ -166,6 +214,42 @@ vm_run(VM *vm) { | |||
166 | sz offset = vm->regs[instruction.b].i; | 214 | sz offset = vm->regs[instruction.b].i; |
167 | addr[offset] = value; | 215 | addr[offset] = value; |
168 | } break; | 216 | } break; |
217 | case OP_ST16I: { | ||
218 | sz value = vm->regs[instruction.dst].ptr; | ||
219 | s16 *addr = (s16 *)vm->regs[instruction.a].ptr; | ||
220 | sz offset = vm->chunk->constants[instruction.b].i; | ||
221 | addr[offset] = value; | ||
222 | } break; | ||
223 | case OP_ST16: { | ||
224 | sz value = vm->regs[instruction.dst].i; | ||
225 | s16 *addr = (s16 *)vm->regs[instruction.a].ptr; | ||
226 | sz offset = vm->regs[instruction.b].i; | ||
227 | addr[offset] = value; | ||
228 | } break; | ||
229 | case OP_ST8I: { | ||
230 | sz value = vm->regs[instruction.dst].ptr; | ||
231 | s8 *addr = (s8 *)vm->regs[instruction.a].ptr; | ||
232 | sz offset = vm->chunk->constants[instruction.b].i; | ||
233 | addr[offset] = value; | ||
234 | } break; | ||
235 | case OP_ST8: { | ||
236 | sz value = vm->regs[instruction.dst].i; | ||
237 | s8 *addr = (s8 *)vm->regs[instruction.a].ptr; | ||
238 | sz offset = vm->regs[instruction.b].i; | ||
239 | addr[offset] = value; | ||
240 | } break; | ||
241 | case OP_ST32I: { | ||
242 | sz value = vm->regs[instruction.dst].ptr; | ||
243 | s32 *addr = (s32 *)vm->regs[instruction.a].ptr; | ||
244 | sz offset = vm->chunk->constants[instruction.b].i; | ||
245 | addr[offset] = value; | ||
246 | } break; | ||
247 | case OP_ST32: { | ||
248 | sz value = vm->regs[instruction.dst].i; | ||
249 | s32 *addr = (s32 *)vm->regs[instruction.a].ptr; | ||
250 | sz offset = vm->regs[instruction.b].i; | ||
251 | addr[offset] = value; | ||
252 | } break; | ||
169 | case OP_LD64I: { | 253 | case OP_LD64I: { |
170 | s64 *addr = (s64 *)vm->regs[instruction.a].ptr; | 254 | s64 *addr = (s64 *)vm->regs[instruction.a].ptr; |
171 | sz offset = vm->chunk->constants[instruction.b].i; | 255 | sz offset = vm->chunk->constants[instruction.b].i; |
@@ -176,19 +260,67 @@ vm_run(VM *vm) { | |||
176 | sz offset = vm->regs[instruction.b].i; | 260 | sz offset = vm->regs[instruction.b].i; |
177 | vm->regs[instruction.dst].i = addr[offset]; | 261 | vm->regs[instruction.dst].i = addr[offset]; |
178 | } break; | 262 | } break; |
179 | case OP_STGVAR: { | 263 | case OP_LD32I: { |
180 | u8 dst = instruction.dst; | 264 | s32 *addr = (s32 *)vm->regs[instruction.a].ptr; |
181 | u8 src = instruction.a; | 265 | sz offset = vm->chunk->constants[instruction.b].i; |
182 | Variable var = vm->chunk->vars[dst]; | 266 | vm->regs[instruction.dst].i = addr[offset]; |
183 | s64 *stack = (s64 *)&vm->stack[var.offset]; | ||
184 | *stack = vm->regs[src].i; | ||
185 | } break; | 267 | } break; |
186 | case OP_STGVARI: { | 268 | case OP_LD32: { |
187 | u8 dst = instruction.dst; | 269 | s32 *addr = (s32 *)vm->regs[instruction.a].ptr; |
188 | u8 src = instruction.a; | 270 | sz offset = vm->regs[instruction.b].i; |
189 | Variable var = vm->chunk->vars[dst]; | 271 | vm->regs[instruction.dst].i = addr[offset]; |
190 | s64 *stack = (s64 *)&vm->stack[var.offset]; | 272 | } break; |
191 | *stack = vm->chunk->constants[src].i; | 273 | case OP_LD16I: { |
274 | s16 *addr = (s16 *)vm->regs[instruction.a].ptr; | ||
275 | sz offset = vm->chunk->constants[instruction.b].i; | ||
276 | vm->regs[instruction.dst].i = addr[offset]; | ||
277 | } break; | ||
278 | case OP_LD16: { | ||
279 | s16 *addr = (s16 *)vm->regs[instruction.a].ptr; | ||
280 | sz offset = vm->regs[instruction.b].i; | ||
281 | vm->regs[instruction.dst].i = addr[offset]; | ||
282 | } break; | ||
283 | case OP_LD8I: { | ||
284 | s8 *addr = (s8 *)vm->regs[instruction.a].ptr; | ||
285 | sz offset = vm->chunk->constants[instruction.b].i; | ||
286 | vm->regs[instruction.dst].i = addr[offset]; | ||
287 | } break; | ||
288 | case OP_LD8: { | ||
289 | s8 *addr = (s8 *)vm->regs[instruction.a].ptr; | ||
290 | sz offset = vm->regs[instruction.b].i; | ||
291 | vm->regs[instruction.dst].i = addr[offset]; | ||
292 | } break; | ||
293 | case OP_LD8K: { | ||
294 | s8 *addr = (s8 *)vm->regs[instruction.a].ptr; | ||
295 | vm->regs[instruction.dst].i = *addr; | ||
296 | } break; | ||
297 | case OP_LD16K: { | ||
298 | s16 *addr = (s16 *)vm->regs[instruction.a].ptr; | ||
299 | vm->regs[instruction.dst].i = *addr; | ||
300 | } break; | ||
301 | case OP_LD32K: { | ||
302 | s32 *addr = (s32 *)vm->regs[instruction.a].ptr; | ||
303 | vm->regs[instruction.dst].i = *addr; | ||
304 | } break; | ||
305 | case OP_LD64K: { | ||
306 | s64 *addr = (s64 *)vm->regs[instruction.a].ptr; | ||
307 | vm->regs[instruction.dst].i = *addr; | ||
308 | } break; | ||
309 | case OP_ST8K: { | ||
310 | s8 *addr = (s8 *)vm->regs[instruction.a].ptr; | ||
311 | *addr = vm->regs[instruction.dst].i; | ||
312 | } break; | ||
313 | case OP_ST16K: { | ||
314 | s16 *addr = (s16 *)vm->regs[instruction.a].ptr; | ||
315 | *addr = vm->regs[instruction.dst].i; | ||
316 | } break; | ||
317 | case OP_ST32K: { | ||
318 | s32 *addr = (s32 *)vm->regs[instruction.a].ptr; | ||
319 | *addr = vm->regs[instruction.dst].i; | ||
320 | } break; | ||
321 | case OP_ST64K: { | ||
322 | s64 *addr = (s64 *)vm->regs[instruction.a].ptr; | ||
323 | *addr = vm->regs[instruction.dst].i; | ||
192 | } break; | 324 | } break; |
193 | case OP_JMP: { | 325 | case OP_JMP: { |
194 | u8 dst = instruction.dst; | 326 | u8 dst = instruction.dst; |
@@ -247,14 +379,88 @@ vm_run(VM *vm) { | |||
247 | u8 src = instruction.a; | 379 | u8 src = instruction.a; |
248 | vm->regs[dst].i = vm->regs[src].i & 0xFF; | 380 | vm->regs[dst].i = vm->regs[src].i & 0xFF; |
249 | } break; | 381 | } break; |
382 | case OP_PRINTS8: { | ||
383 | u8 idx = instruction.dst; | ||
384 | print("%d", vm->regs[idx].i & 0xFF); | ||
385 | } break; | ||
386 | case OP_PRINTS16: { | ||
387 | u8 idx = instruction.dst; | ||
388 | print("%d", vm->regs[idx].i & 0xFFFF); | ||
389 | } break; | ||
390 | case OP_PRINTS32: { | ||
391 | u8 idx = instruction.dst; | ||
392 | print("%d", vm->regs[idx].i & 0xFFFFFFFF); | ||
393 | } break; | ||
250 | case OP_PRINTS64: { | 394 | case OP_PRINTS64: { |
251 | u8 idx = instruction.dst; | 395 | u8 idx = instruction.dst; |
252 | print("%d", vm->regs[idx].i); | 396 | print("%d", vm->regs[idx].i); |
253 | } break; | 397 | } break; |
398 | case OP_PRINTU8: { | ||
399 | u8 idx = instruction.dst; | ||
400 | print("%x", vm->regs[idx].u & 0xFF); | ||
401 | } break; | ||
402 | case OP_PRINTU16: { | ||
403 | u8 idx = instruction.dst; | ||
404 | print("%x", vm->regs[idx].u & 0xFFFF); | ||
405 | } break; | ||
406 | case OP_PRINTU32: { | ||
407 | u8 idx = instruction.dst; | ||
408 | print("%x", vm->regs[idx].u & 0xFFFFFFFF); | ||
409 | } break; | ||
410 | case OP_PRINTU64: { | ||
411 | u8 idx = instruction.dst; | ||
412 | print("%x", vm->regs[idx].u); | ||
413 | } break; | ||
414 | case OP_PRINTS8I: { | ||
415 | u8 idx = instruction.dst; | ||
416 | print("%d", vm->chunk->constants[idx].i & 0xFF); | ||
417 | } break; | ||
418 | case OP_PRINTS16I: { | ||
419 | u8 idx = instruction.dst; | ||
420 | print("%d", vm->chunk->constants[idx].i & 0xFFFF); | ||
421 | } break; | ||
422 | case OP_PRINTS32I: { | ||
423 | u8 idx = instruction.dst; | ||
424 | print("%d", vm->chunk->constants[idx].i & 0xFFFFFFFF); | ||
425 | } break; | ||
254 | case OP_PRINTS64I: { | 426 | case OP_PRINTS64I: { |
255 | u8 idx = instruction.dst; | 427 | u8 idx = instruction.dst; |
256 | print("%d", vm->chunk->constants[idx].i); | 428 | print("%d", vm->chunk->constants[idx].i); |
257 | } break; | 429 | } break; |
430 | case OP_PRINTU8I: { | ||
431 | u8 idx = instruction.dst; | ||
432 | print("%x", vm->chunk->constants[idx].u & 0xFF); | ||
433 | } break; | ||
434 | case OP_PRINTU16I: { | ||
435 | u8 idx = instruction.dst; | ||
436 | print("%x", vm->chunk->constants[idx].u & 0xFFFF); | ||
437 | } break; | ||
438 | case OP_PRINTU32I: { | ||
439 | u8 idx = instruction.dst; | ||
440 | print("%x", vm->chunk->constants[idx].u & 0xFFFFFFFF); | ||
441 | } break; | ||
442 | case OP_PRINTU64I: { | ||
443 | u8 idx = instruction.dst; | ||
444 | print("%x", vm->chunk->constants[idx].u); | ||
445 | } break; | ||
446 | case OP_PRINTBOOL: { | ||
447 | u8 idx = instruction.dst; | ||
448 | bool val = vm->regs[idx].i; | ||
449 | if (val) { | ||
450 | print("true"); | ||
451 | } else { | ||
452 | print("false"); | ||
453 | } | ||
454 | } break; | ||
455 | case OP_PRINTBOOLI: { | ||
456 | u8 idx = instruction.dst; | ||
457 | bool val = vm->chunk->constants[idx].i; | ||
458 | if (val) { | ||
459 | print("true"); | ||
460 | } else { | ||
461 | print("false"); | ||
462 | } | ||
463 | } break; | ||
258 | case OP_PRINTF64: { | 464 | case OP_PRINTF64: { |
259 | u8 idx = instruction.dst; | 465 | u8 idx = instruction.dst; |
260 | printf("%f", vm->regs[idx].f); | 466 | printf("%f", vm->regs[idx].f); |
@@ -265,6 +471,11 @@ vm_run(VM *vm) { | |||
265 | } break; | 471 | } break; |
266 | case OP_PRINTSTR: { | 472 | case OP_PRINTSTR: { |
267 | u8 idx = instruction.dst; | 473 | u8 idx = instruction.dst; |
474 | Str *string = (Str *)vm->regs[idx].ptr; | ||
475 | print("%s", *string); | ||
476 | } break; | ||
477 | case OP_PRINTSTRI: { | ||
478 | u8 idx = instruction.dst; | ||
268 | Str string = vm->chunk->strings[idx]; | 479 | Str string = vm->chunk->strings[idx]; |
269 | print("%s", string); | 480 | print("%s", string); |
270 | } break; | 481 | } break; |
@@ -299,7 +510,7 @@ vm_run(VM *vm) { | |||
299 | } break; | 510 | } break; |
300 | case OP_CALL: { | 511 | case OP_CALL: { |
301 | u8 dst = instruction.dst; | 512 | u8 dst = instruction.dst; |
302 | Chunk *func = vm->chunk->functions[dst]; | 513 | Chunk *func = vm->main->functions[dst]; |
303 | 514 | ||
304 | ptrsize chunk_addr = (ptrsize)vm->chunk; | 515 | ptrsize chunk_addr = (ptrsize)vm->chunk; |
305 | ptrsize ip_addr = (ptrsize)vm->ip; | 516 | ptrsize ip_addr = (ptrsize)vm->ip; |
@@ -307,8 +518,9 @@ vm_run(VM *vm) { | |||
307 | ptrsize old_fp = (ptrsize)vm->fp; | 518 | ptrsize old_fp = (ptrsize)vm->fp; |
308 | 519 | ||
309 | // Allocate space for the locals. | 520 | // Allocate space for the locals. |
310 | vm->fp = (u64 *)vm->sp; | 521 | memset(vm->sp, 0, func->var_off - func->param_off); |
311 | vm->sp += func->var_off; // FIXME: - func->n_params! | 522 | vm->fp = (u64 *)(vm->sp - func->param_off); |
523 | vm->sp += func->var_off - func->param_off; | ||
312 | vm->chunk = func; | 524 | vm->chunk = func; |
313 | vm->ip = func->code; | 525 | vm->ip = func->code; |
314 | vm->regs = (Constant *)vm->sp; | 526 | vm->regs = (Constant *)vm->sp; |
@@ -324,6 +536,9 @@ vm_run(VM *vm) { | |||
324 | p[3] = old_fp; | 536 | p[3] = old_fp; |
325 | vm->sp += sizeof(ptrsize) * 4; | 537 | vm->sp += sizeof(ptrsize) * 4; |
326 | } break; | 538 | } break; |
539 | case OP_RECUR: { | ||
540 | vm->ip = vm->chunk->code; | ||
541 | } break; | ||
327 | case OP_RET: { | 542 | case OP_RET: { |
328 | u64 *p = (u64 *)vm->sp; | 543 | u64 *p = (u64 *)vm->sp; |
329 | ptrsize chunk_addr = p[-4]; | 544 | ptrsize chunk_addr = p[-4]; |