diff options
-rw-r--r-- | bench/life.bad | 112 | ||||
-rw-r--r-- | bench/rule110.bad | 34 | ||||
-rw-r--r-- | bench/rule110.py | 12 | ||||
-rw-r--r-- | src/compiler.c | 1741 | ||||
-rw-r--r-- | src/lexer.c | 152 | ||||
-rw-r--r-- | src/main.c | 121 | ||||
-rw-r--r-- | src/parser.c | 500 | ||||
-rw-r--r-- | src/semantic.c | 735 | ||||
-rw-r--r-- | src/vm.c | 255 | ||||
-rw-r--r-- | tests/compilation.bad | 187 | ||||
-rw-r--r-- | tests/logic-shortcircuit.bad | 16 | ||||
-rw-r--r-- | tests/nested.bad | 18 | ||||
-rw-r--r-- | tests/pointers.bad | 36 | ||||
-rw-r--r-- | tests/recursion.bad | 19 |
14 files changed, 2804 insertions, 1134 deletions
diff --git a/bench/life.bad b/bench/life.bad index 3ca0697..eb5c99b 100644 --- a/bench/life.bad +++ b/bench/life.bad | |||
@@ -1,77 +1,71 @@ | |||
1 | ; This board is 8 * 8 = 64 cells. | 1 | ; This board is 8 * 8 = 64 cells. |
2 | ; let n_cells = 64 | 2 | ; let n_cells = 64 |
3 | ; let board: int[64] | 3 | ; let board_a: int[64] |
4 | ; let new_board: int[64] | 4 | ; let board_b: int[64] |
5 | ; let stride = 8 | 5 | ; let stride = 8 |
6 | 6 | ||
7 | ; This board is 32 * 32 = 1024 cells. | 7 | ; This board is 32 * 32 = 1024 cells. |
8 | let n_cells = 1024 | 8 | let n_cells = 1024 |
9 | let board: int[1024] | 9 | let board_a: Int[1024] |
10 | let new_board: int[1024] | 10 | let board_b: Int[1024] |
11 | let stride = 32 | 11 | let stride = 32 |
12 | 12 | ||
13 | ; Storing pointers to the front/backbuffer to avoid copying the board over. | ||
14 | let front = board_a | ||
15 | let back = board_b | ||
16 | |||
13 | ; Initialize glider | 17 | ; Initialize glider |
14 | set board[stride * 2 + 5] = 1 | 18 | set front[stride * 2 + 5] = 1 |
15 | set board[stride * 3 + 6] = 1 | 19 | set front[stride * 3 + 6] = 1 |
16 | set board[stride * 4 + 4] = 1 | 20 | set front[stride * 4 + 4] = 1 |
17 | set board[stride * 4 + 5] = 1 | 21 | set front[stride * 4 + 5] = 1 |
18 | set board[stride * 4 + 6] = 1 | 22 | set front[stride * 4 + 6] = 1 |
19 | 23 | ||
20 | let n_iter = 1000 | 24 | fun print_board(board: @Int) { |
21 | while n_iter > 0 { | 25 | for let i = 0 , i < n_cells , set i += 1 { |
22 | set n_iter = n_iter - 1 | 26 | if i % stride == 0 { |
23 | ; Print the board. | 27 | println("") |
24 | { | ||
25 | let i = 0 | ||
26 | while i < n_cells { | ||
27 | if i % stride == 0 { | ||
28 | println("") | ||
29 | } | ||
30 | if board[i] == 1 print("â– ") | ||
31 | else print("· ") | ||
32 | set i = i + 1 | ||
33 | } | 28 | } |
34 | println("") | 29 | if board[i] == 1 print("â– ") |
30 | else print("· ") | ||
35 | } | 31 | } |
32 | println("") | ||
33 | } | ||
36 | 34 | ||
37 | ; Update the board. | 35 | fun update_board() { |
38 | { | 36 | for let i = 0 , i < n_cells , set i += 1 { |
39 | let i = 0 | 37 | let left = if i > 0 front[i - 1] else 0 |
40 | while i < n_cells { | 38 | let right = if i < n_cells - 1 front[i + 1] else 0 |
41 | let left = if i > 0 board[i - 1] else 0 | 39 | let top = if i >= stride front[i - stride] else 0 |
42 | let right = if i < n_cells - 1 board[i + 1] else 0 | 40 | let topleft = if i >= stride front[i - stride - 1] else 0 |
43 | let top = if i >= stride board[i - stride] else 0 | 41 | let topright = if i >= stride front[i - stride + 1] else 0 |
44 | let topleft = if i >= stride board[i - stride - 1] else 0 | 42 | let bot = if i <= n_cells - stride front[i + stride] else 0 |
45 | let topright = if i >= stride board[i - stride + 1] else 0 | 43 | let botleft = if i <= n_cells - stride front[i + stride - 1] else 0 |
46 | let bot = if i <= n_cells - stride board[i + stride] else 0 | 44 | let botright = if i <= n_cells - stride front[i + stride + 1] else 0 |
47 | let botleft = if i <= n_cells - stride board[i + stride - 1] else 0 | ||
48 | let botright = if i <= n_cells - stride board[i + stride + 1] else 0 | ||
49 | |||
50 | let neig = left | ||
51 | + right | ||
52 | + top | ||
53 | + bot | ||
54 | + topleft | ||
55 | + topright | ||
56 | + botleft | ||
57 | + botright | ||
58 | |||
59 | cond { | ||
60 | board[i] == 0 && neig == 3 = set new_board[i] = 1 | ||
61 | board[i] == 1 && (neig == 2 || neig == 3) = set new_board[i] = 1 | ||
62 | else = set new_board[i] = 0 | ||
63 | } | ||
64 | 45 | ||
65 | set i = i + 1 | 46 | let neig = left |
66 | } | 47 | + right |
48 | + top | ||
49 | + bot | ||
50 | + topleft | ||
51 | + topright | ||
52 | + botleft | ||
53 | + botright | ||
67 | 54 | ||
68 | ; Copy the new board. | 55 | cond { |
69 | { | 56 | front[i] == 0 and neig == 3 = set back[i] = 1 |
70 | let i = 0 | 57 | front[i] == 1 and (neig == 2 or neig == 3) = set back[i] = 1 |
71 | while i < n_cells { | 58 | else = set back[i] = 0 |
72 | set board[i] = new_board[i] | ||
73 | set i = i + 1 | ||
74 | } | ||
75 | } | 59 | } |
76 | } | 60 | } |
61 | |||
62 | ; Swap boards. | ||
63 | let tmp = front | ||
64 | set front = back | ||
65 | set back = tmp | ||
66 | } | ||
67 | |||
68 | for let n_iter = 100 , n_iter > 0 , set n_iter -= 1 { | ||
69 | print_board(front) | ||
70 | update_board() | ||
77 | } | 71 | } |
diff --git a/bench/rule110.bad b/bench/rule110.bad index 14aa00e..9db0da5 100644 --- a/bench/rule110.bad +++ b/bench/rule110.bad | |||
@@ -1,26 +1,24 @@ | |||
1 | ; Parameters. | 1 | ; Parameters. |
2 | let line = 0b00000000000000000000000000000001 | 2 | let line = 0b00000000000000000000000000000001 |
3 | let max_iter = 30000 | 3 | let max_iter = 30 |
4 | 4 | ||
5 | let iter = 0 | 5 | ; Print current line. |
6 | while iter < max_iter { | 6 | fun print_line(line: Int) { |
7 | ; Print current line. | 7 | for let i = 0 , i < 64 , set i += 1 { |
8 | let i = 0 | 8 | let val = line >> 63 - i & 0b1 |
9 | while i < 64 { | ||
10 | let val = line >> (63 - i) & 0b1 | ||
11 | if val == 0b1 { | 9 | if val == 0b1 { |
12 | print("â–€ ") | 10 | print("â– ") |
13 | } else { | 11 | } else { |
14 | print(" ") | 12 | print("· ") |
15 | } | 13 | } |
16 | set i = i + 1 | ||
17 | } | 14 | } |
18 | println("") | 15 | println("") |
16 | } | ||
19 | 17 | ||
20 | ; Update next line | 18 | ; Get the next line. |
19 | fun next_line(line: Int): Int { | ||
21 | let next = 0 | 20 | let next = 0 |
22 | let j = 0 | 21 | for let j = 0 , j < 61 , set j += 1 { |
23 | while j < 61 { | ||
24 | let val = line >> 60 - j & 0b111 | 22 | let val = line >> 60 - j & 0b111 |
25 | set val = cond { | 23 | set val = cond { |
26 | val == 1 = 1 | 24 | val == 1 = 1 |
@@ -30,10 +28,12 @@ while iter < max_iter { | |||
30 | val == 6 = 1 | 28 | val == 6 = 1 |
31 | else = 0 | 29 | else = 0 |
32 | } | 30 | } |
33 | set next = next | val << 61 - j | 31 | set next |= val << 61 - j |
34 | set j = j + 1 | ||
35 | } | 32 | } |
36 | set line = next | 1 | 33 | next | 1 |
34 | } | ||
37 | 35 | ||
38 | set iter = iter + 1 | 36 | for let iter = 0 , iter < max_iter , set iter += 1 { |
37 | print_line(line) | ||
38 | set line = next_line(line) | ||
39 | } | 39 | } |
diff --git a/bench/rule110.py b/bench/rule110.py index a4fed06..eddcdbe 100644 --- a/bench/rule110.py +++ b/bench/rule110.py | |||
@@ -1,18 +1,18 @@ | |||
1 | line = 0b00000000000000000000000000000001 | 1 | line = 0b00000000000000000000000000000001 |
2 | max_iter = 30000 | 2 | max_iter = 30 |
3 | 3 | ||
4 | for iter in range(0, max_iter): | 4 | for iter in range(0, max_iter): |
5 | for i in range(0, 64): | 5 | for i in range(0, 64): |
6 | val = line >> (63 - i) & 0b1 | 6 | val = line >> 63 - i & 0b1 |
7 | if val == 0b1: | 7 | if val == 0b1: |
8 | print("â–€", end=" ") | 8 | print("â– ", end=" ") |
9 | else: | 9 | else: |
10 | print(".", end=" ") | 10 | print("·", end=" ") |
11 | print("") | 11 | print("") |
12 | 12 | ||
13 | next = 0 | 13 | next = 0 |
14 | for j in range(0, 61): | 14 | for j in range(0, 61): |
15 | val = (line >> (61 - j - 1)) & 0b111 | 15 | val = line >> 60 - j & 0b111 |
16 | if val == 1: | 16 | if val == 1: |
17 | val = 1 | 17 | val = 1 |
18 | elif val == 2: | 18 | elif val == 2: |
@@ -25,5 +25,5 @@ for iter in range(0, max_iter): | |||
25 | val = 1 | 25 | val = 1 |
26 | else: | 26 | else: |
27 | val = 0 | 27 | val = 0 |
28 | next = next | (val << (61 - j)) | 28 | next = next | val << 61 - j |
29 | line = next | 1 | 29 | line = next | 1 |
diff --git a/src/compiler.c b/src/compiler.c index 9b6a458..8745f6e 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,191 @@ 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 | // FIXME: this doesn't seem like the right way of handling pointer and | ||
474 | // array types. | ||
475 | base_type = str_remove_prefix(base_type, cstr("@")); | ||
476 | if (str_has_prefix(base_type, cstr("@"))) { | ||
477 | base_type = cstr("Ptr"); | ||
478 | } | ||
479 | } | ||
480 | StrTypeMap *t = strtype_lookup(&compiler->type_map, base_type); | ||
481 | sz size = t->val.size; | ||
482 | // An array. | ||
483 | if (arr_size) { | ||
484 | size *= arr_size; | ||
485 | // FIXME: this should be done on the static analysis, plus, | ||
486 | // we shouldn't be checking all these types by hand, but | ||
487 | // using the symbol tables. | ||
488 | type_name = str_remove_prefix(type_name, cstr("@")); | ||
489 | type_name = str_concat(cstr("[]"), type_name, chunk->storage); | ||
490 | } else if (str_has_prefix(type_name, cstr("@"))) { | ||
491 | t = strtype_lookup(&compiler->type_map, cstr("Ptr")); | ||
492 | size = t->val.size; | ||
493 | } | ||
494 | sz padding = -size & (WORD_SIZE - 1); | ||
495 | size += padding; | ||
496 | Variable var = (Variable){ | ||
497 | .name = name, | ||
498 | .type = t->val, | ||
499 | .type_name = type_name, | ||
500 | .size = size, | ||
501 | .offset = chunk->var_off, | ||
502 | .idx = idx, | ||
503 | }; | ||
504 | varmap_insert(&chunk->varmap, name, var, chunk->storage); | ||
505 | array_push(chunk->vars, var, chunk->storage); | ||
506 | chunk->var_off += size; | ||
507 | return idx; | ||
508 | } | ||
509 | |||
510 | void | ||
511 | emit_op(OpCode op, sz dst, sz a, sz b, Node *node, Chunk *chunk) { | ||
512 | Instruction inst = (Instruction){ | ||
513 | .op = op, | ||
514 | .dst = dst, | ||
515 | .a = a, | ||
516 | .b = b, | ||
517 | }; | ||
518 | array_push(chunk->code, inst, chunk->storage); | ||
519 | LineCol linecol = (LineCol){0}; | ||
520 | if (node) { | ||
521 | linecol = (LineCol){.line = node->line, .col = node->col}; | ||
522 | } | ||
523 | array_push(chunk->linecol, linecol, chunk->storage); | ||
524 | } | ||
525 | |||
526 | void | ||
527 | emit_sized_op(sz size, | ||
528 | OpCode op64, | ||
529 | OpCode op32, | ||
530 | OpCode op16, | ||
531 | OpCode op8, | ||
532 | sz dst, | ||
533 | sz a, | ||
534 | sz b, | ||
535 | Node *node, | ||
536 | Chunk *chunk) { | ||
537 | if (size == 8) { | ||
538 | emit_op(op64, dst, a, b, node, chunk); | ||
539 | } else if (size == 4) { | ||
540 | emit_op(op32, dst, a, b, node, chunk); | ||
541 | } else if (size == 2) { | ||
542 | emit_op(op16, dst, a, b, node, chunk); | ||
543 | } else if (size == 1) { | ||
544 | emit_op(op8, dst, a, b, node, chunk); | ||
545 | } | ||
546 | } | ||
547 | |||
548 | void | ||
549 | emit_fat_copy(Chunk *chunk, Node *node, sz dst_addr, sz src_addr) { | ||
550 | sz reg_dst = chunk->reg_idx++; | ||
551 | |||
552 | // Store the fat string pointer into the variable. | ||
553 | sz zero = add_constant(chunk, 0); | ||
554 | sz one = add_constant(chunk, 1); | ||
555 | |||
556 | // Get the value for the first word of the string | ||
557 | // pointer. | ||
558 | emit_op(OP_LD64I, reg_dst, src_addr, zero, node, chunk); | ||
559 | emit_op(OP_ST64I, reg_dst, dst_addr, zero, node, chunk); | ||
560 | emit_op(OP_LD64I, reg_dst, src_addr, one, node, chunk); | ||
561 | emit_op(OP_ST64I, reg_dst, dst_addr, one, node, chunk); | ||
562 | } | ||
563 | |||
564 | void disassemble_chunk(Chunk chunk); | ||
565 | |||
566 | void | ||
567 | emit_compile_err(Compiler *compiler, Chunk *chunk, Node *node) { | ||
568 | disassemble_chunk(*chunk); | ||
569 | eprintln("%s:%d:%d: error: compilation error on: %s", compiler->file_name, | ||
570 | node->line, node->col, node_str[node->kind]); | ||
571 | exit(EXIT_FAILURE); | ||
572 | } | ||
334 | 573 | ||
335 | CompResult | 574 | CompResult |
336 | compile_binary(Chunk *chunk, Node *node) { | 575 | compile_binary(Compiler *compiler, Chunk *chunk, Node *node) { |
337 | OpCode op = OP_HALT; | 576 | OpCode op = OP_HALT; |
338 | OpCode opi = OP_HALT; | 577 | OpCode opi = OP_HALT; |
339 | OpCode ldop = OP_LD64K; | 578 | OpCode ldop = OP_LDCONST; |
340 | switch (node->kind) { | 579 | switch (node->kind) { |
341 | // Arithmetic. | 580 | // Arithmetic. |
342 | case NODE_ADD: { | 581 | case NODE_ADD: { |
343 | if (str_eq(node->type, cstr("int"))) { | 582 | if (strset_lookup(&compiler->integer_types, node->type)) { |
344 | op = OP_ADD; | 583 | op = OP_ADD; |
345 | opi = OP_ADDI; | 584 | opi = OP_ADDI; |
346 | } else if (str_eq(node->type, cstr("f64"))) { | 585 | } else if (strset_lookup(&compiler->float_types, node->type)) { |
347 | op = OP_ADDF; | 586 | op = OP_ADDF; |
348 | opi = OP_ADDFI; | 587 | opi = OP_ADDFI; |
349 | } | 588 | } |
350 | } break; | 589 | } break; |
351 | case NODE_SUB: { | 590 | case NODE_SUB: { |
352 | if (str_eq(node->type, cstr("int"))) { | 591 | if (strset_lookup(&compiler->integer_types, node->type)) { |
353 | op = OP_SUB; | 592 | op = OP_SUB; |
354 | opi = OP_SUBI; | 593 | opi = OP_SUBI; |
355 | } else if (str_eq(node->type, cstr("f64"))) { | 594 | } else if (strset_lookup(&compiler->float_types, node->type)) { |
356 | op = OP_SUBF; | 595 | op = OP_SUBF; |
357 | opi = OP_SUBFI; | 596 | opi = OP_SUBFI; |
358 | } | 597 | } |
359 | } break; | 598 | } break; |
360 | case NODE_MUL: { | 599 | case NODE_MUL: { |
361 | if (str_eq(node->type, cstr("int"))) { | 600 | if (strset_lookup(&compiler->integer_types, node->type)) { |
362 | op = OP_MUL; | 601 | op = OP_MUL; |
363 | opi = OP_MULI; | 602 | opi = OP_MULI; |
364 | } else if (str_eq(node->type, cstr("f64"))) { | 603 | } else if (strset_lookup(&compiler->float_types, node->type)) { |
365 | op = OP_MULF; | 604 | op = OP_MULF; |
366 | opi = OP_MULFI; | 605 | opi = OP_MULFI; |
367 | } | 606 | } |
368 | } break; | 607 | } break; |
369 | case NODE_DIV: { | 608 | case NODE_DIV: { |
370 | if (str_eq(node->type, cstr("int"))) { | 609 | if (strset_lookup(&compiler->integer_types, node->type)) { |
371 | op = OP_DIV; | 610 | op = OP_DIV; |
372 | opi = OP_DIVI; | 611 | opi = OP_DIVI; |
373 | } else if (str_eq(node->type, cstr("f64"))) { | 612 | } else if (strset_lookup(&compiler->float_types, node->type)) { |
374 | op = OP_DIVF; | 613 | op = OP_DIVF; |
375 | opi = OP_DIVFI; | 614 | opi = OP_DIVFI; |
376 | } | 615 | } |
377 | } break; | 616 | } break; |
378 | case NODE_MOD: { | 617 | case NODE_MOD: { |
379 | if (str_eq(node->type, cstr("int"))) { | 618 | if (strset_lookup(&compiler->integer_types, node->type)) { |
380 | op = OP_MOD; | 619 | op = OP_MOD; |
381 | opi = OP_MODI; | 620 | opi = OP_MODI; |
382 | } else if (str_eq(node->type, cstr("f64"))) { | 621 | } else if (strset_lookup(&compiler->float_types, node->type)) { |
383 | op = OP_MODF; | 622 | op = OP_MODF; |
384 | opi = OP_MODFI; | 623 | opi = OP_MODFI; |
385 | } | 624 | } |
@@ -409,19 +648,15 @@ compile_binary(Chunk *chunk, Node *node) { | |||
409 | op = OP_GE; | 648 | op = OP_GE; |
410 | opi = OP_GEI; | 649 | opi = OP_GEI; |
411 | } break; | 650 | } 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. | 651 | // Bitwise. |
421 | case NODE_BITOR: { | 652 | case NODE_BITOR: { |
422 | op = OP_BITOR; | 653 | op = OP_BITOR; |
423 | opi = OP_BITORI; | 654 | opi = OP_BITORI; |
424 | } break; | 655 | } break; |
656 | case NODE_BITXOR: { | ||
657 | op = OP_BITXOR; | ||
658 | opi = OP_BITXORI; | ||
659 | } break; | ||
425 | case NODE_BITAND: { | 660 | case NODE_BITAND: { |
426 | op = OP_BITAND; | 661 | op = OP_BITAND; |
427 | opi = OP_BITANDI; | 662 | opi = OP_BITANDI; |
@@ -436,19 +671,20 @@ compile_binary(Chunk *chunk, Node *node) { | |||
436 | } break; | 671 | } break; |
437 | default: break; | 672 | default: break; |
438 | } | 673 | } |
439 | CompResult comp_a = compile_expr(chunk, node->left); | 674 | CompResult comp_a = compile_expr(compiler, chunk, node->binary.left); |
440 | CompResult comp_b = compile_expr(chunk, node->right); | 675 | CompResult comp_b = compile_expr(compiler, chunk, node->binary.right); |
441 | sz reg_a; | 676 | sz reg_a; |
442 | sz reg_b; | 677 | sz reg_b; |
443 | switch (comp_a.type) { | 678 | switch (comp_a.type) { |
444 | case COMP_CONST: { | 679 | case COMP_CONST: { |
445 | reg_a = chunk->reg_idx++; | 680 | reg_a = chunk->reg_idx++; |
446 | EMIT_OP(ldop, reg_a, comp_a.idx, 0, node, chunk); | 681 | emit_op(ldop, reg_a, comp_a.idx, 0, node, chunk); |
447 | } break; | 682 | } break; |
448 | case COMP_REG: { | 683 | case COMP_REG: { |
449 | reg_a = comp_a.idx; | 684 | reg_a = comp_a.idx; |
450 | } break; | 685 | } break; |
451 | default: { | 686 | default: { |
687 | emit_compile_err(compiler, chunk, node); | ||
452 | return (CompResult){.type = COMP_ERR}; | 688 | return (CompResult){.type = COMP_ERR}; |
453 | } break; | 689 | } break; |
454 | } | 690 | } |
@@ -461,16 +697,99 @@ compile_binary(Chunk *chunk, Node *node) { | |||
461 | reg_b = comp_b.idx; | 697 | reg_b = comp_b.idx; |
462 | } break; | 698 | } break; |
463 | default: { | 699 | default: { |
700 | emit_compile_err(compiler, chunk, node); | ||
464 | return (CompResult){.type = COMP_ERR}; | 701 | return (CompResult){.type = COMP_ERR}; |
465 | } break; | 702 | } break; |
466 | } | 703 | } |
467 | sz reg_dst = chunk->reg_idx++; // Better for optimization | 704 | sz reg_dst = chunk->reg_idx++; // Better for optimization |
468 | EMIT_OP(op, reg_dst, reg_a, reg_b, node, chunk); | 705 | emit_op(op, reg_dst, reg_a, reg_b, node, chunk); |
706 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | ||
707 | } | ||
708 | |||
709 | CompResult | ||
710 | compile_binary_logic(Compiler *compiler, Chunk *chunk, Node *node) { | ||
711 | // Logical functions have to shortcircuit once the answer is known. | ||
712 | OpCode op = OP_HALT; | ||
713 | OpCode opi = OP_HALT; | ||
714 | OpCode ldop = OP_LDCONST; | ||
715 | OpCode jmpop = OP_HALT; | ||
716 | OpCode jmpopi = OP_HALT; | ||
717 | bool default_value = false; | ||
718 | switch (node->kind) { | ||
719 | case NODE_AND: { | ||
720 | op = OP_AND; | ||
721 | opi = OP_ANDI; | ||
722 | jmpop = OP_JMPF; | ||
723 | jmpopi = OP_JMPFI; | ||
724 | default_value = false; | ||
725 | } break; | ||
726 | case NODE_OR: { | ||
727 | op = OP_OR; | ||
728 | opi = OP_ORI; | ||
729 | jmpop = OP_JMPT; | ||
730 | jmpopi = OP_JMPTI; | ||
731 | default_value = true; | ||
732 | } break; | ||
733 | default: break; | ||
734 | } | ||
735 | |||
736 | sz lab0 = chunk->labels_idx++; | ||
737 | sz lab1 = chunk->labels_idx++; | ||
738 | |||
739 | CompResult comp_a = compile_expr(compiler, chunk, node->binary.left); | ||
740 | sz reg_a; | ||
741 | switch (comp_a.type) { | ||
742 | case COMP_CONST: { | ||
743 | emit_op(jmpopi, lab0, comp_a.idx, 0, node->binary.left, chunk); | ||
744 | reg_a = chunk->reg_idx++; | ||
745 | emit_op(ldop, reg_a, comp_a.idx, 0, node, chunk); | ||
746 | } break; | ||
747 | case COMP_REG: { | ||
748 | emit_op(jmpop, lab0, comp_a.idx, 0, node->binary.left, chunk); | ||
749 | reg_a = comp_a.idx; | ||
750 | } break; | ||
751 | default: { | ||
752 | emit_compile_err(compiler, chunk, node); | ||
753 | return (CompResult){.type = COMP_ERR}; | ||
754 | } break; | ||
755 | } | ||
756 | |||
757 | CompResult comp_b = compile_expr(compiler, chunk, node->binary.right); | ||
758 | sz reg_b; | ||
759 | switch (comp_b.type) { | ||
760 | case COMP_CONST: { | ||
761 | reg_b = comp_b.idx; | ||
762 | op = opi; | ||
763 | } break; | ||
764 | case COMP_REG: { | ||
765 | reg_b = comp_b.idx; | ||
766 | } break; | ||
767 | default: { | ||
768 | emit_compile_err(compiler, chunk, node); | ||
769 | return (CompResult){.type = COMP_ERR}; | ||
770 | } break; | ||
771 | } | ||
772 | sz reg_dst = chunk->reg_idx++; | ||
773 | emit_op(op, reg_dst, reg_a, reg_b, node, chunk); | ||
774 | |||
775 | // Jump to the end of this comparison. | ||
776 | emit_op(OP_JMP, lab1, 0, 0, node, chunk); | ||
777 | sz pos0 = array_size(chunk->code); | ||
778 | |||
779 | // Load default value. | ||
780 | sz defaul_const = add_constant(chunk, default_value); | ||
781 | emit_op(ldop, reg_dst, defaul_const, 0, node, chunk); | ||
782 | sz pos1 = array_size(chunk->code); | ||
783 | |||
784 | // Register labels. | ||
785 | intintmap_insert(&chunk->labels, lab0, pos0, chunk->storage); | ||
786 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); | ||
787 | |||
469 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | 788 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; |
470 | } | 789 | } |
471 | 790 | ||
472 | CompResult | 791 | CompResult |
473 | compile_unary(Chunk *chunk, Node *node) { | 792 | compile_unary(Compiler *compiler, Chunk *chunk, Node *node) { |
474 | OpCode op = OP_HALT; | 793 | OpCode op = OP_HALT; |
475 | OpCode opi = OP_HALT; | 794 | OpCode opi = OP_HALT; |
476 | switch (node->kind) { | 795 | switch (node->kind) { |
@@ -484,7 +803,7 @@ compile_unary(Chunk *chunk, Node *node) { | |||
484 | } break; | 803 | } break; |
485 | default: break; | 804 | default: break; |
486 | } | 805 | } |
487 | CompResult comp_a = compile_expr(chunk, node->left); | 806 | CompResult comp_a = compile_expr(compiler, chunk, node->binary.left); |
488 | sz reg_a; | 807 | sz reg_a; |
489 | switch (comp_a.type) { | 808 | switch (comp_a.type) { |
490 | case COMP_CONST: { | 809 | case COMP_CONST: { |
@@ -495,42 +814,18 @@ compile_unary(Chunk *chunk, Node *node) { | |||
495 | reg_a = comp_a.idx; | 814 | reg_a = comp_a.idx; |
496 | } break; | 815 | } break; |
497 | default: { | 816 | default: { |
817 | emit_compile_err(compiler, chunk, node); | ||
498 | return (CompResult){.type = COMP_ERR}; | 818 | return (CompResult){.type = COMP_ERR}; |
499 | } break; | 819 | } break; |
500 | } | 820 | } |
501 | sz reg_dst = chunk->reg_idx++; | 821 | sz reg_dst = chunk->reg_idx++; |
502 | EMIT_OP(op, reg_dst, reg_a, 0, node, chunk); | 822 | emit_op(op, reg_dst, reg_a, 0, node, chunk); |
503 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | 823 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; |
504 | } | 824 | } |
505 | 825 | ||
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 | 826 | CompResult |
532 | compile_if(Chunk *chunk, Node *node) { | 827 | compile_if(Compiler *compiler, Chunk *chunk, Node *node) { |
533 | CompResult cond = compile_expr(chunk, node->cond_if); | 828 | CompResult cond = compile_expr(compiler, chunk, node->ifelse.cond); |
534 | OpCode jmpop; | 829 | OpCode jmpop; |
535 | switch (cond.type) { | 830 | switch (cond.type) { |
536 | case COMP_CONST: { | 831 | case COMP_CONST: { |
@@ -540,29 +835,35 @@ compile_if(Chunk *chunk, Node *node) { | |||
540 | jmpop = OP_JMPF; | 835 | jmpop = OP_JMPF; |
541 | } break; | 836 | } break; |
542 | default: { | 837 | default: { |
838 | emit_compile_err(compiler, chunk, node); | ||
543 | return (CompResult){.type = COMP_ERR}; | 839 | return (CompResult){.type = COMP_ERR}; |
544 | } break; | 840 | } break; |
545 | } | 841 | } |
546 | 842 | ||
547 | if (!str_eq(node->type, cstr("nil"))) { | 843 | if (!str_eq(node->type, cstr("nil")) && |
844 | !str_has_prefix(node->type, cstr("ret:")) && | ||
845 | !str_has_prefix(node->type, cstr("flow:"))) { | ||
548 | sz reg_dst = chunk->reg_idx++; | 846 | sz reg_dst = chunk->reg_idx++; |
549 | 847 | ||
550 | // Jump to the `false` branch. | 848 | // Jump to the `false` branch. |
551 | sz lab0 = chunk->labels_idx++; | 849 | sz lab0 = chunk->labels_idx++; |
552 | EMIT_OP(jmpop, lab0, cond.idx, 0, node->cond_if, chunk); | 850 | emit_op(jmpop, lab0, cond.idx, 0, node->ifelse.cond, chunk); |
553 | 851 | ||
554 | // Condition is true. | 852 | // Condition is true. |
555 | CompResult then_expr = compile_expr(chunk, node->cond_expr); | 853 | CompResult then_expr = |
854 | compile_expr(compiler, chunk, node->ifelse.expr_true); | ||
556 | switch (then_expr.type) { | 855 | switch (then_expr.type) { |
557 | case COMP_CONST: { | 856 | case COMP_CONST: { |
558 | EMIT_OP(OP_LD64K, reg_dst, then_expr.idx, 0, node->cond_if, | 857 | emit_op(OP_LDCONST, reg_dst, then_expr.idx, 0, |
559 | chunk); | 858 | node->ifelse.cond, chunk); |
560 | } break; | 859 | } break; |
561 | case COMP_REG: { | 860 | case COMP_REG: { |
562 | EMIT_OP(OP_MOV64, reg_dst, then_expr.idx, 0, node->cond_if, | 861 | emit_op(OP_MOV64, reg_dst, then_expr.idx, 0, node->ifelse.cond, |
563 | chunk); | 862 | chunk); |
564 | } break; | 863 | } break; |
864 | case COMP_RET: break; | ||
565 | default: { | 865 | default: { |
866 | emit_compile_err(compiler, chunk, node); | ||
566 | return (CompResult){.type = COMP_ERR}; | 867 | return (CompResult){.type = COMP_ERR}; |
567 | } break; | 868 | } break; |
568 | } | 869 | } |
@@ -570,20 +871,23 @@ compile_if(Chunk *chunk, Node *node) { | |||
570 | // Jump to the end of the expression. | 871 | // Jump to the end of the expression. |
571 | sz pos0 = array_size(chunk->code); | 872 | sz pos0 = array_size(chunk->code); |
572 | sz lab1 = chunk->labels_idx++; | 873 | sz lab1 = chunk->labels_idx++; |
573 | EMIT_OP(OP_JMP, lab1, 0, 0, node->cond_else, chunk); | 874 | emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk); |
574 | 875 | ||
575 | // Else expression. | 876 | // Else expression. |
576 | CompResult else_expr = compile_expr(chunk, node->cond_else); | 877 | CompResult else_expr = |
878 | compile_expr(compiler, chunk, node->ifelse.expr_else); | ||
577 | switch (else_expr.type) { | 879 | switch (else_expr.type) { |
578 | case COMP_CONST: { | 880 | case COMP_CONST: { |
579 | EMIT_OP(OP_LD64K, reg_dst, else_expr.idx, 0, node->cond_else, | 881 | emit_op(OP_LDCONST, reg_dst, else_expr.idx, 0, |
580 | chunk); | 882 | node->ifelse.expr_else, chunk); |
581 | } break; | 883 | } break; |
582 | case COMP_REG: { | 884 | case COMP_REG: { |
583 | EMIT_OP(OP_MOV64, reg_dst, else_expr.idx, 0, node->cond_else, | 885 | emit_op(OP_MOV64, reg_dst, else_expr.idx, 0, |
584 | chunk); | 886 | node->ifelse.expr_else, chunk); |
585 | } break; | 887 | } break; |
888 | case COMP_RET: break; | ||
586 | default: { | 889 | default: { |
890 | emit_compile_err(compiler, chunk, node); | ||
587 | return (CompResult){.type = COMP_ERR}; | 891 | return (CompResult){.type = COMP_ERR}; |
588 | } break; | 892 | } break; |
589 | } | 893 | } |
@@ -592,47 +896,44 @@ compile_if(Chunk *chunk, Node *node) { | |||
592 | // Update labels. | 896 | // Update labels. |
593 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage); | 897 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage); |
594 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); | 898 | 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}; | 899 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; |
598 | } | 900 | } |
599 | 901 | ||
600 | // Jump to the `false` branch. | 902 | // Jump to the `false` branch. |
601 | sz lab0 = chunk->labels_idx++; | 903 | sz lab0 = chunk->labels_idx++; |
602 | EMIT_OP(jmpop, lab0, cond.idx, 0, node->cond_if, chunk); | 904 | emit_op(jmpop, lab0, cond.idx, 0, node->ifelse.cond, chunk); |
603 | 905 | ||
604 | // Condition is true. | 906 | // Condition is true. |
605 | compile_expr(chunk, node->cond_expr); | 907 | compile_expr(compiler, chunk, node->ifelse.expr_true); |
606 | 908 | ||
607 | // Jump to the end of the expression. | 909 | // Jump to the end of the expression. |
608 | sz pos0 = array_size(chunk->code); | 910 | sz pos0 = array_size(chunk->code); |
609 | sz lab1 = chunk->labels_idx++; | 911 | sz lab1 = chunk->labels_idx++; |
610 | EMIT_OP(OP_JMP, lab1, 0, 0, node->cond_else, chunk); | 912 | emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk); |
611 | 913 | ||
612 | // Else expression. | 914 | // Else expression. |
613 | if (node->cond_else) { | 915 | if (node->ifelse.expr_else) { |
614 | compile_expr(chunk, node->cond_else); | 916 | compile_expr(compiler, chunk, node->ifelse.expr_else); |
615 | } | 917 | } |
616 | sz pos1 = array_size(chunk->code); | 918 | sz pos1 = array_size(chunk->code); |
617 | 919 | ||
618 | // Update labels. | 920 | // Update labels. |
619 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage); | 921 | 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); | 922 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); |
622 | intintmap_insert(&chunk->labels_rev, pos1, lab1, chunk->storage); | ||
623 | 923 | ||
624 | return (CompResult){.type = COMP_NIL}; | 924 | return (CompResult){.type = COMP_NIL}; |
625 | } | 925 | } |
626 | 926 | ||
627 | CompResult | 927 | CompResult |
628 | compile_cond(Chunk *chunk, Node *node) { | 928 | compile_cond(Compiler *compiler, Chunk *chunk, Node *node) { |
629 | if (str_eq(node->type, cstr("nil"))) { | 929 | if (str_eq(node->type, cstr("nil"))) { |
630 | sz lab1 = chunk->labels_idx++; | 930 | sz lab1 = chunk->labels_idx++; |
631 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 931 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
632 | // condition = expression | 932 | // condition = expression |
633 | Node *expr = node->match_cases[i]; | 933 | Node *expr = node->match.cases[i]; |
634 | if (expr->case_value) { | 934 | if (expr->case_entry.cond) { |
635 | CompResult cond = compile_expr(chunk, expr->case_value); | 935 | CompResult cond = |
936 | compile_expr(compiler, chunk, expr->case_entry.cond); | ||
636 | OpCode jmpop; | 937 | OpCode jmpop; |
637 | switch (cond.type) { | 938 | switch (cond.type) { |
638 | case COMP_CONST: { | 939 | case COMP_CONST: { |
@@ -642,42 +943,41 @@ compile_cond(Chunk *chunk, Node *node) { | |||
642 | jmpop = OP_JMPF; | 943 | jmpop = OP_JMPF; |
643 | } break; | 944 | } break; |
644 | default: { | 945 | default: { |
946 | emit_compile_err(compiler, chunk, node); | ||
645 | return (CompResult){.type = COMP_ERR}; | 947 | return (CompResult){.type = COMP_ERR}; |
646 | } break; | 948 | } break; |
647 | } | 949 | } |
648 | // Jump to the `next` branch. | 950 | // Jump to the `next` branch. |
649 | sz lab0 = chunk->labels_idx++; | 951 | sz lab0 = chunk->labels_idx++; |
650 | EMIT_OP(jmpop, lab0, cond.idx, 0, expr->case_expr, chunk); | 952 | emit_op(jmpop, lab0, cond.idx, 0, expr->case_entry.expr, chunk); |
651 | 953 | ||
652 | // Condition is true. | 954 | // Condition is true. |
653 | compile_expr(chunk, expr->case_expr); | 955 | compile_expr(compiler, chunk, expr->case_entry.expr); |
654 | if (i != array_size(node->match_cases) - 1) { | 956 | if (i != array_size(node->match.cases) - 1) { |
655 | // Jump to the end of the expression. | 957 | // Jump to the end of the expression. |
656 | sz pos0 = array_size(chunk->code); | 958 | sz pos0 = array_size(chunk->code); |
657 | EMIT_OP(OP_JMP, lab1, 0, 0, node->cond_else, chunk); | 959 | emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk); |
658 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, | 960 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, |
659 | chunk->storage); | 961 | chunk->storage); |
660 | intintmap_insert(&chunk->labels_rev, pos0 + 1, lab0, | ||
661 | chunk->storage); | ||
662 | } | 962 | } |
663 | } else { | 963 | } else { |
664 | compile_expr(chunk, expr->case_expr); | 964 | compile_expr(compiler, chunk, expr->case_entry.expr); |
665 | break; | 965 | break; |
666 | } | 966 | } |
667 | } | 967 | } |
668 | sz pos1 = array_size(chunk->code); | 968 | sz pos1 = array_size(chunk->code); |
669 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); | 969 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); |
670 | intintmap_insert(&chunk->labels_rev, pos1, lab1, chunk->storage); | ||
671 | return (CompResult){.type = COMP_NIL}; | 970 | return (CompResult){.type = COMP_NIL}; |
672 | } | 971 | } |
673 | 972 | ||
674 | sz reg_dst = chunk->reg_idx++; | 973 | sz reg_dst = chunk->reg_idx++; |
675 | sz lab1 = chunk->labels_idx++; | 974 | sz lab1 = chunk->labels_idx++; |
676 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 975 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
677 | // condition = expression | 976 | // condition = expression |
678 | Node *expr = node->match_cases[i]; | 977 | Node *expr = node->match.cases[i]; |
679 | if (expr->case_value) { | 978 | if (expr->case_entry.cond) { |
680 | CompResult cond = compile_expr(chunk, expr->case_value); | 979 | CompResult cond = |
980 | compile_expr(compiler, chunk, expr->case_entry.cond); | ||
681 | OpCode jmpop; | 981 | OpCode jmpop; |
682 | switch (cond.type) { | 982 | switch (cond.type) { |
683 | case COMP_CONST: { | 983 | case COMP_CONST: { |
@@ -687,49 +987,54 @@ compile_cond(Chunk *chunk, Node *node) { | |||
687 | jmpop = OP_JMPF; | 987 | jmpop = OP_JMPF; |
688 | } break; | 988 | } break; |
689 | default: { | 989 | default: { |
990 | emit_compile_err(compiler, chunk, node); | ||
690 | return (CompResult){.type = COMP_ERR}; | 991 | return (CompResult){.type = COMP_ERR}; |
691 | } break; | 992 | } break; |
692 | } | 993 | } |
693 | // Jump to the `next` branch. | 994 | // Jump to the `next` branch. |
694 | sz lab0 = chunk->labels_idx++; | 995 | sz lab0 = chunk->labels_idx++; |
695 | EMIT_OP(jmpop, lab0, cond.idx, 0, expr->case_expr, chunk); | 996 | emit_op(jmpop, lab0, cond.idx, 0, expr->case_entry.expr, chunk); |
696 | 997 | ||
697 | // Condition is true. | 998 | // Condition is true. |
698 | CompResult then_expr = compile_expr(chunk, expr->case_expr); | 999 | CompResult then_expr = |
1000 | compile_expr(compiler, chunk, expr->case_entry.expr); | ||
699 | switch (then_expr.type) { | 1001 | switch (then_expr.type) { |
700 | case COMP_CONST: { | 1002 | case COMP_CONST: { |
701 | EMIT_OP(OP_LD64K, reg_dst, then_expr.idx, 0, | 1003 | emit_op(OP_LDCONST, reg_dst, then_expr.idx, 0, |
702 | expr->case_expr, chunk); | 1004 | expr->case_entry.expr, chunk); |
703 | } break; | 1005 | } break; |
704 | case COMP_REG: { | 1006 | case COMP_REG: { |
705 | EMIT_OP(OP_MOV64, reg_dst, then_expr.idx, 0, | 1007 | emit_op(OP_MOV64, reg_dst, then_expr.idx, 0, |
706 | expr->case_expr, chunk); | 1008 | expr->case_entry.expr, chunk); |
707 | } break; | 1009 | } break; |
1010 | case COMP_RET: break; | ||
708 | default: { | 1011 | default: { |
1012 | emit_compile_err(compiler, chunk, node); | ||
709 | return (CompResult){.type = COMP_ERR}; | 1013 | return (CompResult){.type = COMP_ERR}; |
710 | } break; | 1014 | } break; |
711 | } | 1015 | } |
712 | if (i != array_size(node->match_cases) - 1) { | 1016 | if (i != array_size(node->match.cases) - 1) { |
713 | // Jump to the end of the expression. | 1017 | // Jump to the end of the expression. |
714 | sz pos0 = array_size(chunk->code); | 1018 | sz pos0 = array_size(chunk->code); |
715 | EMIT_OP(OP_JMP, lab1, 0, 0, node->cond_else, chunk); | 1019 | emit_op(OP_JMP, lab1, 0, 0, node->ifelse.expr_else, chunk); |
716 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, | 1020 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, |
717 | chunk->storage); | 1021 | chunk->storage); |
718 | intintmap_insert(&chunk->labels_rev, pos0 + 1, lab0, | ||
719 | chunk->storage); | ||
720 | } | 1022 | } |
721 | } else { | 1023 | } else { |
722 | CompResult then_expr = compile_expr(chunk, expr->case_expr); | 1024 | CompResult then_expr = |
1025 | compile_expr(compiler, chunk, expr->case_entry.expr); | ||
723 | switch (then_expr.type) { | 1026 | switch (then_expr.type) { |
724 | case COMP_CONST: { | 1027 | case COMP_CONST: { |
725 | EMIT_OP(OP_LD64K, reg_dst, then_expr.idx, 0, | 1028 | emit_op(OP_LDCONST, reg_dst, then_expr.idx, 0, |
726 | expr->case_expr, chunk); | 1029 | expr->case_entry.expr, chunk); |
727 | } break; | 1030 | } break; |
728 | case COMP_REG: { | 1031 | case COMP_REG: { |
729 | EMIT_OP(OP_MOV64, reg_dst, then_expr.idx, 0, | 1032 | emit_op(OP_MOV64, reg_dst, then_expr.idx, 0, |
730 | expr->case_expr, chunk); | 1033 | expr->case_entry.expr, chunk); |
731 | } break; | 1034 | } break; |
1035 | case COMP_RET: break; | ||
732 | default: { | 1036 | default: { |
1037 | emit_compile_err(compiler, chunk, node); | ||
733 | return (CompResult){.type = COMP_ERR}; | 1038 | return (CompResult){.type = COMP_ERR}; |
734 | } break; | 1039 | } break; |
735 | } | 1040 | } |
@@ -738,14 +1043,27 @@ compile_cond(Chunk *chunk, Node *node) { | |||
738 | } | 1043 | } |
739 | sz pos1 = array_size(chunk->code); | 1044 | sz pos1 = array_size(chunk->code); |
740 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); | 1045 | 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}; | 1046 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; |
743 | } | 1047 | } |
744 | 1048 | ||
745 | CompResult | 1049 | CompResult |
746 | compile_while(Chunk *chunk, Node *node) { | 1050 | compile_break(Compiler *compiler, Chunk *chunk, Node *node) { |
1051 | emit_op(OP_JMP, compiler->lab_post, 0, 0, node, chunk); | ||
1052 | return (CompResult){.type = COMP_NIL}; | ||
1053 | } | ||
1054 | |||
1055 | CompResult | ||
1056 | compile_continue(Compiler *compiler, Chunk *chunk, Node *node) { | ||
1057 | emit_op(OP_JMP, compiler->lab_pre, 0, 0, node, chunk); | ||
1058 | return (CompResult){.type = COMP_NIL}; | ||
1059 | } | ||
1060 | |||
1061 | CompResult | ||
1062 | compile_while(Compiler *compiler, Chunk *chunk, Node *node) { | ||
1063 | sz lab0 = chunk->labels_idx++; | ||
1064 | sz lab1 = chunk->labels_idx++; | ||
747 | sz pos1 = array_size(chunk->code); | 1065 | sz pos1 = array_size(chunk->code); |
748 | CompResult cond = compile_expr(chunk, node->while_cond); | 1066 | CompResult cond = compile_expr(compiler, chunk, node->loop.cond); |
749 | OpCode jmpop; | 1067 | OpCode jmpop; |
750 | switch (cond.type) { | 1068 | switch (cond.type) { |
751 | case COMP_CONST: { | 1069 | case COMP_CONST: { |
@@ -755,69 +1073,163 @@ compile_while(Chunk *chunk, Node *node) { | |||
755 | jmpop = OP_JMPF; | 1073 | jmpop = OP_JMPF; |
756 | } break; | 1074 | } break; |
757 | default: { | 1075 | default: { |
1076 | emit_compile_err(compiler, chunk, node); | ||
758 | return (CompResult){.type = COMP_ERR}; | 1077 | return (CompResult){.type = COMP_ERR}; |
759 | } break; | 1078 | } break; |
760 | } | 1079 | } |
761 | 1080 | ||
762 | // Jump to the `end of the loop` branch. | 1081 | // Jump to the `end of the loop` branch. |
763 | sz lab0 = chunk->labels_idx++; | 1082 | emit_op(jmpop, lab0, cond.idx, 0, node->loop.cond, chunk); |
764 | EMIT_OP(jmpop, lab0, cond.idx, 0, node->while_cond, chunk); | ||
765 | 1083 | ||
766 | // Condition is true. | 1084 | // Condition is true. |
767 | compile_expr(chunk, node->while_expr); | 1085 | compiler->lab_pre = lab1; |
1086 | compiler->lab_post = lab0; | ||
1087 | compile_expr(compiler, chunk, node->loop.expr); | ||
768 | sz pos0 = array_size(chunk->code); | 1088 | sz pos0 = array_size(chunk->code); |
769 | sz lab1 = chunk->labels_idx++; | 1089 | emit_op(OP_JMP, lab1, 0, 0, node, chunk); |
770 | EMIT_OP(OP_JMP, lab1, 0, 0, node, chunk); | ||
771 | 1090 | ||
772 | // Update labels. | 1091 | // Update labels. |
773 | intintmap_insert(&chunk->labels, lab0, pos0 + 1, chunk->storage); | 1092 | 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); | 1093 | intintmap_insert(&chunk->labels, lab1, pos1, chunk->storage); |
776 | intintmap_insert(&chunk->labels_rev, pos1, lab1, chunk->storage); | ||
777 | 1094 | ||
778 | // Return. | 1095 | // Return. |
779 | return (CompResult){.type = COMP_NIL}; | 1096 | return (CompResult){.type = COMP_NIL}; |
780 | } | 1097 | } |
781 | 1098 | ||
782 | CompResult | 1099 | CompResult |
783 | compile_funcall(Chunk *chunk, Node *node) { | 1100 | compile_tail_call(Compiler *compiler, Chunk *chunk, Node *node) { |
1101 | // Update the local parameters. | ||
1102 | for (sz i = 0; i < array_size(node->elements); i++) { | ||
1103 | Node *expr = node->elements[i]; | ||
1104 | CompResult result = compile_expr(compiler, chunk, expr); | ||
1105 | switch (result.type) { | ||
1106 | case COMP_CONST: { | ||
1107 | emit_op(OP_STLVARI, i, result.idx, 0, node, chunk); | ||
1108 | } break; | ||
1109 | case COMP_REG: { | ||
1110 | if (str_eq(expr->type, cstr("Str"))) { | ||
1111 | sz var_addr = chunk->reg_idx++; | ||
1112 | sz str_addr = result.idx; | ||
1113 | emit_op(OP_LDLADDR, var_addr, i, 0, node, chunk); | ||
1114 | emit_fat_copy(chunk, node, var_addr, str_addr); | ||
1115 | } else { | ||
1116 | emit_op(OP_STLVAR, i, result.idx, 0, node, chunk); | ||
1117 | } | ||
1118 | } break; | ||
1119 | case COMP_STRING: { | ||
1120 | sz var_addr = chunk->reg_idx++; | ||
1121 | sz str_addr = chunk->reg_idx++; | ||
1122 | emit_op(OP_LDLADDR, var_addr, i, 0, node, chunk); | ||
1123 | emit_op(OP_LDSTR, str_addr, result.idx, 0, node, chunk); | ||
1124 | emit_fat_copy(chunk, node, var_addr, str_addr); | ||
1125 | } break; | ||
1126 | default: { | ||
1127 | emit_compile_err(compiler, chunk, node); | ||
1128 | return (CompResult){.type = COMP_ERR}; | ||
1129 | } break; | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | emit_op(OP_RECUR, 0, 0, 0, node, chunk); | ||
1134 | return (CompResult){.type = COMP_NIL}; | ||
1135 | } | ||
1136 | |||
1137 | CompResult | ||
1138 | compile_funcall(Compiler *compiler, Chunk *chunk, Node *node) { | ||
784 | Str name = node->value.str; | 1139 | Str name = node->value.str; |
785 | 1140 | ||
786 | // Builtins. | 1141 | // Builtins. |
787 | if (str_eq(name, cstr("print")) || str_eq(name, cstr("println"))) { | 1142 | if (str_eq(name, cstr("print")) || str_eq(name, cstr("println"))) { |
788 | for (sz i = 0; i < array_size(node->elements); i++) { | 1143 | for (sz i = 0; i < array_size(node->elements); i++) { |
789 | Node *expr = node->elements[i]; | 1144 | Node *expr = node->elements[i]; |
790 | CompResult result = compile_expr(chunk, expr); | 1145 | Str type_name = expr->type; |
791 | if (str_eq(expr->type, cstr("int"))) { | 1146 | if (str_has_prefix(type_name, cstr("@"))) { |
1147 | type_name = cstr("Ptr"); | ||
1148 | } | ||
1149 | StrTypeMap *t = strtype_lookup(&compiler->type_map, type_name); | ||
1150 | Str type = t->val.unique_name; | ||
1151 | sz size = t->val.size; | ||
1152 | CompResult result = compile_expr(compiler, chunk, expr); | ||
1153 | if (strset_lookup(&compiler->signed_ints, type)) { | ||
792 | switch (result.type) { | 1154 | switch (result.type) { |
793 | case COMP_CONST: { | 1155 | case COMP_CONST: { |
794 | EMIT_OP(OP_PRINTS64I, result.idx, 0, 0, expr, chunk); | 1156 | emit_sized_op(size, OP_PRINTS64I, OP_PRINTS32I, |
1157 | OP_PRINTS16I, OP_PRINTS8I, result.idx, 0, | ||
1158 | 0, expr, chunk); | ||
795 | } break; | 1159 | } break; |
796 | case COMP_REG: { | 1160 | case COMP_REG: { |
797 | EMIT_OP(OP_PRINTS64, result.idx, 0, 0, expr, chunk); | 1161 | emit_sized_op(size, OP_PRINTS64, OP_PRINTS32, |
1162 | OP_PRINTS16, OP_PRINTS8, result.idx, 0, 0, | ||
1163 | expr, chunk); | ||
798 | } break; | 1164 | } break; |
799 | default: { | 1165 | default: { |
1166 | emit_compile_err(compiler, chunk, node); | ||
800 | return (CompResult){.type = COMP_ERR}; | 1167 | return (CompResult){.type = COMP_ERR}; |
801 | } break; | 1168 | } break; |
802 | } | 1169 | } |
803 | } else if (str_eq(expr->type, cstr("f64"))) { | 1170 | } else if (strset_lookup(&compiler->unsigned_ints, type)) { |
804 | switch (result.type) { | 1171 | switch (result.type) { |
805 | case COMP_CONST: { | 1172 | case COMP_CONST: { |
806 | EMIT_OP(OP_PRINTF64I, result.idx, 0, 0, expr, chunk); | 1173 | emit_sized_op(size, OP_PRINTU64I, OP_PRINTU32I, |
1174 | OP_PRINTU16I, OP_PRINTU8I, result.idx, 0, | ||
1175 | 0, expr, chunk); | ||
807 | } break; | 1176 | } break; |
808 | case COMP_REG: { | 1177 | case COMP_REG: { |
809 | EMIT_OP(OP_PRINTF64, result.idx, 0, 0, expr, chunk); | 1178 | emit_sized_op(size, OP_PRINTU64, OP_PRINTU32, |
1179 | OP_PRINTU16, OP_PRINTU8, result.idx, 0, 0, | ||
1180 | expr, chunk); | ||
810 | } break; | 1181 | } break; |
811 | default: { | 1182 | default: { |
1183 | emit_compile_err(compiler, chunk, node); | ||
812 | return (CompResult){.type = COMP_ERR}; | 1184 | return (CompResult){.type = COMP_ERR}; |
813 | } break; | 1185 | } break; |
814 | } | 1186 | } |
815 | } else if (str_eq(expr->type, cstr("str"))) { | 1187 | } else if (strset_lookup(&compiler->float_types, type)) { |
1188 | switch (result.type) { | ||
1189 | case COMP_CONST: { | ||
1190 | if (size == 8) { | ||
1191 | emit_op(OP_PRINTF64I, result.idx, 0, 0, expr, | ||
1192 | chunk); | ||
1193 | } else { | ||
1194 | emit_op(OP_PRINTF32I, result.idx, 0, 0, expr, | ||
1195 | chunk); | ||
1196 | } | ||
1197 | } break; | ||
1198 | case COMP_REG: { | ||
1199 | if (size == 8) { | ||
1200 | emit_op(OP_PRINTF64, result.idx, 0, 0, expr, chunk); | ||
1201 | } else { | ||
1202 | emit_op(OP_PRINTF32, result.idx, 0, 0, expr, chunk); | ||
1203 | } | ||
1204 | } break; | ||
1205 | default: { | ||
1206 | emit_compile_err(compiler, chunk, node); | ||
1207 | return (CompResult){.type = COMP_ERR}; | ||
1208 | } break; | ||
1209 | } | ||
1210 | } else if (str_eq(type, cstr("Str"))) { | ||
816 | switch (result.type) { | 1211 | switch (result.type) { |
817 | case COMP_STRING: { | 1212 | case COMP_STRING: { |
818 | EMIT_OP(OP_PRINTSTR, result.idx, 0, 0, expr, chunk); | 1213 | emit_op(OP_PRINTSTRI, result.idx, 0, 0, expr, chunk); |
1214 | } break; | ||
1215 | case COMP_REG: { | ||
1216 | emit_op(OP_PRINTSTR, result.idx, 0, 0, expr, chunk); | ||
1217 | } break; | ||
1218 | default: { | ||
1219 | emit_compile_err(compiler, chunk, node); | ||
1220 | return (CompResult){.type = COMP_ERR}; | ||
1221 | } break; | ||
1222 | } | ||
1223 | } else if (str_eq(type, cstr("Bool"))) { | ||
1224 | switch (result.type) { | ||
1225 | case COMP_CONST: { | ||
1226 | emit_op(OP_PRINTBOOLI, result.idx, 0, 0, expr, chunk); | ||
1227 | } break; | ||
1228 | case COMP_REG: { | ||
1229 | emit_op(OP_PRINTBOOL, result.idx, 0, 0, expr, chunk); | ||
819 | } break; | 1230 | } break; |
820 | default: { | 1231 | default: { |
1232 | emit_compile_err(compiler, chunk, node); | ||
821 | return (CompResult){.type = COMP_ERR}; | 1233 | return (CompResult){.type = COMP_ERR}; |
822 | } break; | 1234 | } break; |
823 | } | 1235 | } |
@@ -825,75 +1237,181 @@ compile_funcall(Chunk *chunk, Node *node) { | |||
825 | } | 1237 | } |
826 | if (str_eq(name, cstr("println"))) { | 1238 | if (str_eq(name, cstr("println"))) { |
827 | sz idx = add_string(chunk, cstr("\n")); | 1239 | sz idx = add_string(chunk, cstr("\n")); |
828 | EMIT_OP(OP_PRINTSTR, idx, 0, 0, node, chunk); | 1240 | emit_op(OP_PRINTSTRI, idx, 0, 0, node, chunk); |
829 | } | 1241 | } |
830 | return (CompResult){.type = COMP_NIL}; | 1242 | return (CompResult){.type = COMP_NIL}; |
831 | } | 1243 | } |
832 | 1244 | ||
833 | // TODO: need to find this on the parents, not just in the current chunk. | 1245 | FunctionMap *map = |
834 | FunctionMap *map = funcmap_lookup(&chunk->funmap, node->unique_name); | 1246 | funcmap_lookup(&compiler->main_chunk.funmap, node->unique_name); |
835 | if (!map) { | 1247 | if (!map) { |
836 | println("how come?"); | 1248 | emit_compile_err(compiler, chunk, node); |
1249 | return (CompResult){.type = COMP_ERR}; | ||
837 | } | 1250 | } |
838 | Function fun = map->val; | 1251 | Function fun = map->val; |
839 | 1252 | ||
1253 | // Check for tail recursive opportunities. | ||
1254 | if (str_eq(fun.name, node->unique_name) && | ||
1255 | str_eq(chunk->name, node->unique_name)) { | ||
1256 | Node *parent = node->parent; | ||
1257 | Node *current = node; | ||
1258 | bool tail_recursive = true; | ||
1259 | while (parent != NULL) { | ||
1260 | switch (parent->kind) { | ||
1261 | case NODE_BLOCK: { | ||
1262 | sz idx = array_size(parent->statements) - 1; | ||
1263 | if (parent->statements[idx] != node) { | ||
1264 | tail_recursive = false; | ||
1265 | break; | ||
1266 | } | ||
1267 | } break; | ||
1268 | case NODE_WHILE: { | ||
1269 | if (current == parent->loop.cond) { | ||
1270 | tail_recursive = false; | ||
1271 | break; | ||
1272 | } | ||
1273 | } break; | ||
1274 | case NODE_IF: { | ||
1275 | if (current == parent->ifelse.cond) { | ||
1276 | tail_recursive = false; | ||
1277 | break; | ||
1278 | } | ||
1279 | } break; | ||
1280 | case NODE_FUN: { | ||
1281 | sz idx = array_size(parent->func.body->statements) - 1; | ||
1282 | if (parent->func.body->statements[idx] != current) { | ||
1283 | tail_recursive = false; | ||
1284 | break; | ||
1285 | } | ||
1286 | break; | ||
1287 | } break; | ||
1288 | case NODE_MATCH: { | ||
1289 | if (current == parent->match.expr) { | ||
1290 | tail_recursive = false; | ||
1291 | break; | ||
1292 | } | ||
1293 | } break; | ||
1294 | case NODE_COND: break; | ||
1295 | case NODE_CASE_COND: { | ||
1296 | if (current == parent->case_entry.cond) { | ||
1297 | tail_recursive = false; | ||
1298 | break; | ||
1299 | } | ||
1300 | } break; | ||
1301 | default: { | ||
1302 | tail_recursive = false; | ||
1303 | break; | ||
1304 | } break; | ||
1305 | } | ||
1306 | parent = parent->parent; | ||
1307 | current = current->parent; | ||
1308 | } | ||
1309 | if (tail_recursive) { | ||
1310 | return compile_tail_call(compiler, chunk, node); | ||
1311 | } | ||
1312 | } | ||
1313 | |||
840 | // Reserve space for the return value if needed. | 1314 | // Reserve space for the return value if needed. |
841 | if (fun.return_arity > 0) { | 1315 | if (fun.return_arity > 0) { |
842 | // Put the return data into a register | 1316 | // Put the return data into a register |
843 | sz ret_size = add_constant(chunk, 8); | 1317 | sz ret_size = add_constant(chunk, 8); |
844 | EMIT_OP(OP_RESERVE, ret_size, 0, 0, node, chunk); | 1318 | emit_op(OP_RESERVE, ret_size, 0, 0, node, chunk); |
845 | } | 1319 | } |
846 | 1320 | ||
847 | // Send parameters to the stack. | 1321 | // Send parameters to the stack. |
848 | for (sz i = 0; i < array_size(node->elements); i++) { | 1322 | for (sz i = 0; i < array_size(node->elements); i++) { |
849 | Node *expr = node->elements[i]; | 1323 | Node *expr = node->elements[i]; |
850 | CompResult result = compile_expr(chunk, expr); | 1324 | CompResult result = compile_expr(compiler, chunk, expr); |
851 | // TODO: Assuming all values are 8 bytes... again. | 1325 | Str type_name = expr->type; |
1326 | if (str_has_prefix(type_name, cstr("@"))) { | ||
1327 | type_name = cstr("Ptr"); | ||
1328 | } | ||
1329 | StrTypeMap *t = strtype_lookup(&compiler->type_map, type_name); | ||
1330 | sz size = t->val.size; | ||
852 | switch (result.type) { | 1331 | switch (result.type) { |
853 | case COMP_CONST: { | 1332 | case COMP_CONST: { |
854 | EMIT_OP(OP_PUSHI, result.idx, 0, 0, expr, chunk); | 1333 | emit_op(OP_PUSHI, result.idx, 0, 0, expr, chunk); |
855 | } break; | 1334 | } break; |
856 | case COMP_REG: { | 1335 | case COMP_REG: { |
857 | EMIT_OP(OP_PUSH, result.idx, 0, 0, expr, chunk); | 1336 | if (str_eq(expr->type, cstr("Str"))) { |
1337 | sz str_addr = result.idx; | ||
1338 | // Store the fat string pointer into the stack. | ||
1339 | sz reg_dst = chunk->reg_idx++; | ||
1340 | sz zero = add_constant(chunk, 0); | ||
1341 | sz one = add_constant(chunk, 1); | ||
1342 | emit_sized_op(size, OP_LD64I, OP_LD32I, OP_LD16I, OP_LD8I, | ||
1343 | reg_dst, str_addr, zero, node, chunk); | ||
1344 | emit_op(OP_PUSH, reg_dst, 0, 0, expr, chunk); | ||
1345 | emit_sized_op(size, OP_LD64I, OP_LD32I, OP_LD16I, OP_LD8I, | ||
1346 | reg_dst, str_addr, one, node, chunk); | ||
1347 | emit_op(OP_PUSH, reg_dst, 0, 0, expr, chunk); | ||
1348 | } else { | ||
1349 | emit_op(OP_PUSH, result.idx, 0, 0, expr, chunk); | ||
1350 | } | ||
1351 | } break; | ||
1352 | case COMP_STRING: { | ||
1353 | // Get the address for the string value variable. | ||
1354 | sz str_addr = chunk->reg_idx++; | ||
1355 | emit_op(OP_LDSTR, str_addr, result.idx, 0, node->var.val, | ||
1356 | chunk); | ||
1357 | |||
1358 | // Store the fat string pointer into the stack. | ||
1359 | sz reg_dst = chunk->reg_idx++; | ||
1360 | sz zero = add_constant(chunk, 0); | ||
1361 | sz one = add_constant(chunk, 1); | ||
1362 | emit_op(OP_LD64I, reg_dst, str_addr, zero, node, chunk); | ||
1363 | emit_op(OP_PUSH, reg_dst, 0, 0, expr, chunk); | ||
1364 | emit_op(OP_LD64I, reg_dst, str_addr, one, node, chunk); | ||
1365 | emit_op(OP_PUSH, reg_dst, 0, 0, expr, chunk); | ||
858 | } break; | 1366 | } break; |
859 | default: { | 1367 | default: { |
1368 | emit_compile_err(compiler, chunk, node); | ||
860 | return (CompResult){.type = COMP_ERR}; | 1369 | return (CompResult){.type = COMP_ERR}; |
861 | } break; | 1370 | } break; |
862 | } | 1371 | } |
863 | } | 1372 | } |
864 | 1373 | ||
865 | // // TODO: prologue (how much space do we actually need)? we need the | 1374 | 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 | 1375 | ||
880 | // Only one return parameter for now. | 1376 | // Only one return parameter for now. |
881 | if (fun.return_arity > 0) { | 1377 | if (fun.return_arity > 0) { |
882 | // Put the return data into a register | 1378 | // Put the return data into a register |
883 | sz reg_dst = chunk->reg_idx++; | 1379 | sz reg_dst = chunk->reg_idx++; |
884 | EMIT_OP(OP_POP, reg_dst, 0, 0, node, chunk); | 1380 | emit_op(OP_POP, reg_dst, 0, 0, node, chunk); |
885 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | 1381 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; |
886 | } | 1382 | } |
887 | 1383 | ||
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}; | 1384 | return (CompResult){.type = COMP_NIL}; |
895 | } | 1385 | } |
896 | 1386 | ||
1387 | CompResult | ||
1388 | compile_return(Compiler *compiler, Chunk *chunk, Node *node) { | ||
1389 | for (sz i = 0; i < array_size(node->elements); i++) { | ||
1390 | Node *expr = node->elements[i]; | ||
1391 | CompResult res = compile_expr(compiler, chunk, expr); | ||
1392 | |||
1393 | // TODO: Only one return field for now, but this is the idea. | ||
1394 | // Put return values into memory. | ||
1395 | switch (res.type) { | ||
1396 | case COMP_CONST: { | ||
1397 | emit_op(OP_PUTRETI, res.idx, 0, 0, node, chunk); | ||
1398 | } break; | ||
1399 | case COMP_REG: { | ||
1400 | emit_op(OP_PUTRET, res.idx, 0, 0, node, chunk); | ||
1401 | } break; | ||
1402 | case COMP_NIL: break; | ||
1403 | default: { | ||
1404 | emit_compile_err(compiler, chunk, node); | ||
1405 | return (CompResult){.type = COMP_ERR}; | ||
1406 | } break; | ||
1407 | } | ||
1408 | break; | ||
1409 | } | ||
1410 | |||
1411 | emit_op(OP_RET, 0, 0, 0, node, chunk); | ||
1412 | return (CompResult){.type = COMP_RET}; | ||
1413 | } | ||
1414 | |||
897 | Chunk * | 1415 | Chunk * |
898 | chunk_alloc(Chunk *parent) { | 1416 | chunk_alloc(Chunk *parent) { |
899 | static sz chunk_idx = 1; | 1417 | static sz chunk_idx = 1; |
@@ -905,50 +1423,452 @@ chunk_alloc(Chunk *parent) { | |||
905 | return chunk; | 1423 | return chunk; |
906 | } | 1424 | } |
907 | 1425 | ||
908 | CompResult | 1426 | void |
909 | compile_function(Chunk *chunk, Node *node) { | 1427 | verify_chunk(Chunk *chunk) { |
910 | Chunk *func = chunk_alloc(chunk); | 1428 | if (chunk->const_idx >= 256) { |
911 | func->name = node->unique_name; | 1429 | eprintln("too many constants on chunk %s", chunk->id); |
1430 | exit(EXIT_FAILURE); | ||
1431 | } | ||
1432 | if (chunk->str_idx >= 256) { | ||
1433 | eprintln("too many strings on chunk %s", chunk->id); | ||
1434 | exit(EXIT_FAILURE); | ||
1435 | } | ||
1436 | if (chunk->reg_idx >= 256) { | ||
1437 | eprintln("too many registers used on chunk %s", chunk->id); | ||
1438 | exit(EXIT_FAILURE); | ||
1439 | } | ||
1440 | if (chunk->labels_idx >= 256) { | ||
1441 | eprintln("too many labels used on chunk %s", chunk->id); | ||
1442 | exit(EXIT_FAILURE); | ||
1443 | } | ||
1444 | if (chunk->fun_idx >= 256) { | ||
1445 | eprintln("too many functions on chunk %s", chunk->id); | ||
1446 | exit(EXIT_FAILURE); | ||
1447 | } | ||
1448 | } | ||
1449 | |||
1450 | void | ||
1451 | declare_function(Chunk *chunk, Node *node) { | ||
1452 | Str name = node->unique_name; | ||
1453 | FunctionMap *map = funcmap_lookup(&chunk->funmap, node->unique_name); | ||
1454 | if (map) { | ||
1455 | return; | ||
1456 | } | ||
912 | Function fun = (Function){ | 1457 | Function fun = (Function){ |
913 | .name = func->name, | 1458 | .name = name, |
914 | .index = chunk->fun_idx++, | 1459 | .index = chunk->fun_idx++, |
915 | .param_arity = array_size(node->func_params), | 1460 | .param_arity = array_size(node->func.params), |
916 | .return_arity = array_size(node->func_ret), | 1461 | .return_arity = array_size(node->func.ret), |
917 | }; | 1462 | }; |
918 | funcmap_insert(&chunk->funmap, func->name, fun, chunk->storage); | 1463 | funcmap_insert(&chunk->funmap, node->unique_name, fun, chunk->storage); |
1464 | } | ||
1465 | |||
1466 | CompResult | ||
1467 | compile_function(Compiler *compiler, Chunk *chunk, Node *node) { | ||
1468 | // The current activation record procedure for the VM is as follows: | ||
1469 | // | ||
1470 | // [caller][callee ] | ||
1471 | // [ .... ][ RET VAL ][ PARAMS ][ LOCALS ][ REGISTERS ][ RET META ] | ||
1472 | // ^ | ||
1473 | // frame pointer | ||
1474 | // | ||
1475 | // The caller is responsible for allocating the return memory and the | ||
1476 | // parameter memory and filling the param data before OP_CALL. | ||
1477 | // | ||
1478 | chunk = &compiler->main_chunk; | ||
1479 | Chunk *func = chunk_alloc(chunk); | ||
1480 | func->name = node->unique_name; | ||
1481 | declare_function(chunk, node); | ||
919 | array_push(chunk->functions, func, chunk->storage); | 1482 | array_push(chunk->functions, func, chunk->storage); |
920 | 1483 | ||
1484 | // Push arguments as locals. | ||
1485 | for (sz i = 0; i < array_size(node->func.params); i++) { | ||
1486 | Node *param = node->func.params[i]; | ||
1487 | Str name = param->unique_name; | ||
1488 | Str type = param->type; | ||
1489 | sz arr_size = 0; | ||
1490 | if (str_has_prefix(type, cstr("@"))) { | ||
1491 | if (param->var.type && param->var.type->kind == NODE_ARR_TYPE && | ||
1492 | param->var.type->sym.arr_size->value.i > 0) { | ||
1493 | arr_size = param->var.type->sym.arr_size->value.i; | ||
1494 | } | ||
1495 | } | ||
1496 | add_variable(compiler, func, name, type, arr_size); | ||
1497 | } | ||
1498 | func->param_off = func->var_off; | ||
1499 | |||
1500 | // Compiling the body. | ||
1501 | CompResult res = compile_expr(compiler, func, node->func.body); | ||
1502 | |||
921 | // Put return values into memory. | 1503 | // Put return values into memory. |
922 | CompResult res = compile_expr(func, node->func_body); | ||
923 | switch (res.type) { | 1504 | switch (res.type) { |
924 | case COMP_CONST: { | 1505 | case COMP_CONST: { |
925 | EMIT_OP(OP_PUTRETI, res.idx, 0, 0, node, func); | 1506 | emit_op(OP_PUTRETI, res.idx, 0, 0, node, func); |
926 | } break; | 1507 | } break; |
927 | case COMP_REG: { | 1508 | case COMP_REG: { |
928 | EMIT_OP(OP_PUTRET, res.idx, 0, 0, node, func); | 1509 | emit_op(OP_PUTRET, res.idx, 0, 0, node, func); |
929 | } break; | 1510 | } break; |
930 | default: break; | 1511 | default: break; |
931 | } | 1512 | } |
932 | 1513 | ||
933 | // TODO: handle captured locals/globals? | 1514 | emit_op(OP_RET, 0, 0, 0, node, func); |
934 | EMIT_OP(OP_RET, 0, 0, 0, node, func); | 1515 | verify_chunk(func); |
1516 | return (CompResult){.type = COMP_NIL}; | ||
1517 | } | ||
1518 | |||
1519 | CompResult | ||
1520 | compile_let(Compiler *compiler, Chunk *chunk, Node *node) { | ||
1521 | sz op_ldaddr = OP_LDLADDR; | ||
1522 | if (chunk == &compiler->main_chunk) { | ||
1523 | op_ldaddr = OP_LDGADDR; | ||
1524 | } | ||
1525 | Str name = node->unique_name; | ||
1526 | Str type_name = node->var.name->type; | ||
1527 | sz arr_size = 0; | ||
1528 | if (str_has_prefix(type_name, cstr("@"))) { | ||
1529 | if (node->var.type && node->var.type->kind == NODE_ARR_TYPE && | ||
1530 | node->var.type->sym.arr_size->value.i > 0) { | ||
1531 | arr_size = node->var.type->sym.arr_size->value.i; | ||
1532 | } | ||
1533 | } | ||
1534 | |||
1535 | sz idx = add_variable(compiler, chunk, name, type_name, arr_size); | ||
1536 | StrVarMap *map = varmap_lookup(&chunk->varmap, name); | ||
1537 | Variable var = map->val; | ||
1538 | Type type = map->val.type; | ||
1539 | |||
1540 | // Value. | ||
1541 | if (node->var.val) { | ||
1542 | CompResult res = compile_expr(compiler, chunk, node->var.val); | ||
1543 | switch (res.type) { | ||
1544 | case COMP_CONST: { | ||
1545 | sz reg_addr = chunk->reg_idx++; | ||
1546 | sz reg_dst = chunk->reg_idx++; | ||
1547 | emit_op(op_ldaddr, reg_addr, idx, 0, node, chunk); | ||
1548 | emit_op(OP_LDCONST, reg_dst, res.idx, 0, node, chunk); | ||
1549 | |||
1550 | emit_sized_op(type.size, OP_ST64K, OP_ST32K, OP_ST16K, OP_ST8K, | ||
1551 | reg_dst, reg_addr, 0, node, chunk); | ||
1552 | } break; | ||
1553 | case COMP_REG: { | ||
1554 | sz reg_addr = chunk->reg_idx++; | ||
1555 | sz reg_val = res.idx; | ||
1556 | // FIXME: Not working properly for array copies from a pointer | ||
1557 | // because the type is Ptr instead of S32? | ||
1558 | emit_op(op_ldaddr, reg_addr, idx, 0, node, chunk); | ||
1559 | emit_sized_op(type.size, OP_ST64K, OP_ST32K, OP_ST16K, OP_ST8K, | ||
1560 | reg_val, reg_addr, 0, node, chunk); | ||
1561 | if (type.size > 8) { | ||
1562 | sz reg_dst = chunk->reg_idx++; | ||
1563 | for (sz i = 0; i < var.size / 8; i++) { | ||
1564 | sz offset = add_constant(chunk, i); | ||
1565 | emit_op(OP_LD64I, reg_dst, reg_val, offset, node, | ||
1566 | chunk); | ||
1567 | emit_op(OP_ST64I, reg_dst, reg_addr, offset, node, | ||
1568 | chunk); | ||
1569 | } | ||
1570 | } | ||
1571 | } break; | ||
1572 | case COMP_STRING: { | ||
1573 | // Get the address for the string value variable. | ||
1574 | sz str_addr = chunk->reg_idx++; | ||
1575 | emit_op(OP_LDSTR, str_addr, res.idx, 0, node->var.val, chunk); | ||
1576 | |||
1577 | // Get the address for the local/global storage | ||
1578 | // variable. | ||
1579 | sz var_addr = chunk->reg_idx++; | ||
1580 | emit_op(op_ldaddr, var_addr, idx, 0, node, chunk); | ||
1581 | |||
1582 | // Copy the fat pointer. | ||
1583 | emit_fat_copy(chunk, node, var_addr, str_addr); | ||
1584 | } break; | ||
1585 | default: { | ||
1586 | emit_compile_err(compiler, chunk, node); | ||
1587 | return (CompResult){.type = COMP_ERR}; | ||
1588 | } break; | ||
1589 | } | ||
1590 | } | ||
1591 | |||
1592 | return (CompResult){.type = COMP_NIL}; | ||
1593 | } | ||
1594 | |||
1595 | CompResult | ||
1596 | compile_set(Compiler *compiler, Chunk *chunk, Node *node) { | ||
1597 | Str name = node->unique_name; | ||
1598 | StrVarMap *map = NULL; | ||
1599 | Chunk *next = chunk; | ||
1600 | while (next) { | ||
1601 | map = varmap_lookup(&next->varmap, name); | ||
1602 | if (map) { | ||
1603 | break; | ||
1604 | } | ||
1605 | next = chunk->parent; | ||
1606 | } | ||
1607 | if (!map) { | ||
1608 | emit_compile_err(compiler, chunk, node); | ||
1609 | return (CompResult){.type = COMP_ERR}; | ||
1610 | } | ||
1611 | sz op_ldaddr = OP_LDLADDR; | ||
1612 | sz op_ldvar = OP_LDLVAR; | ||
1613 | if (next == &compiler->main_chunk) { | ||
1614 | op_ldaddr = OP_LDGADDR; | ||
1615 | op_ldvar = OP_LDGVAR; | ||
1616 | } | ||
1617 | Variable var = map->val; | ||
1618 | Type type = map->val.type; | ||
1619 | sz idx = map->val.idx; | ||
1620 | |||
1621 | CompResult res = compile_expr(compiler, chunk, node->var.val); | ||
1622 | if (node->var.name->kind == NODE_SYMBOL_IDX) { | ||
1623 | // Value. | ||
1624 | sz reg_val; | ||
1625 | switch (res.type) { | ||
1626 | case COMP_CONST: { | ||
1627 | reg_val = chunk->reg_idx++; | ||
1628 | emit_op(OP_LDCONST, reg_val, res.idx, 0, node, chunk); | ||
1629 | } break; | ||
1630 | case COMP_REG: { | ||
1631 | reg_val = res.idx; | ||
1632 | } break; | ||
1633 | default: { | ||
1634 | emit_compile_err(compiler, chunk, node); | ||
1635 | return (CompResult){.type = COMP_ERR}; | ||
1636 | } break; | ||
1637 | } | ||
1638 | |||
1639 | // Address. | ||
1640 | sz reg_addr = chunk->reg_idx++; | ||
1641 | // Is this a pointer access or an array access? | ||
1642 | if (str_has_prefix(map->val.type_name, cstr("[]"))) { | ||
1643 | emit_op(op_ldaddr, reg_addr, map->val.idx, 0, node->var.val, chunk); | ||
1644 | } else { | ||
1645 | emit_op(op_ldvar, reg_addr, map->val.idx, 0, node->var.val, chunk); | ||
1646 | } | ||
1647 | |||
1648 | // Index. | ||
1649 | CompResult res_idx = | ||
1650 | compile_expr(compiler, chunk, node->var.name->sym.arr_size); | ||
1651 | switch (res_idx.type) { | ||
1652 | case COMP_CONST: { | ||
1653 | emit_sized_op(type.size, OP_ST64I, OP_ST32I, OP_ST16I, OP_ST8I, | ||
1654 | reg_val, reg_addr, res_idx.idx, node, chunk); | ||
1655 | } break; | ||
1656 | case COMP_REG: { | ||
1657 | emit_sized_op(type.size, OP_ST64, OP_ST32, OP_ST16, OP_ST8, | ||
1658 | reg_val, reg_addr, res_idx.idx, node, chunk); | ||
1659 | } break; | ||
1660 | case COMP_STRING: { | ||
1661 | // Get the address for the string value variable. | ||
1662 | sz str_addr = chunk->reg_idx++; | ||
1663 | emit_op(OP_LDSTR, str_addr, res.idx, 0, node->var.val, chunk); | ||
1664 | |||
1665 | // Get the address for the local/global storage | ||
1666 | // variable. | ||
1667 | sz var_addr = chunk->reg_idx++; | ||
1668 | emit_op(op_ldaddr, var_addr, idx, 0, node, chunk); | ||
1669 | |||
1670 | // Copy the fat pointer. | ||
1671 | emit_fat_copy(chunk, node, var_addr, str_addr); | ||
1672 | } break; | ||
1673 | default: { | ||
1674 | emit_compile_err(compiler, chunk, node); | ||
1675 | return (CompResult){.type = COMP_ERR}; | ||
1676 | } break; | ||
1677 | } | ||
1678 | return (CompResult){.type = COMP_NIL}; | ||
1679 | } else if (node->var.name->kind == NODE_DEREF) { | ||
1680 | // Value. | ||
1681 | sz reg_val; | ||
1682 | switch (res.type) { | ||
1683 | case COMP_CONST: { | ||
1684 | reg_val = chunk->reg_idx++; | ||
1685 | emit_op(OP_LDCONST, reg_val, res.idx, 0, node, chunk); | ||
1686 | } break; | ||
1687 | case COMP_REG: { | ||
1688 | reg_val = res.idx; | ||
1689 | } break; | ||
1690 | default: { | ||
1691 | emit_compile_err(compiler, chunk, node); | ||
1692 | return (CompResult){.type = COMP_ERR}; | ||
1693 | } break; | ||
1694 | } | ||
1695 | |||
1696 | Node *next = node->var.name->deref.next; | ||
1697 | sz n_deref = 0; | ||
1698 | while (next) { | ||
1699 | n_deref++; | ||
1700 | if (next->kind == NODE_SYMBOL) { | ||
1701 | break; | ||
1702 | } | ||
1703 | next = next->deref.next; | ||
1704 | } | ||
1705 | CompResult res = compile_expr(compiler, chunk, next); | ||
1706 | sz reg_src = res.idx; | ||
1707 | sz reg_dst = reg_src; | ||
1708 | for (sz i = 0; i < n_deref - 1; i++) { | ||
1709 | reg_dst = chunk->reg_idx++; | ||
1710 | emit_op(OP_LD64K, reg_dst, reg_src, 0, node, chunk); | ||
1711 | reg_src = reg_dst; | ||
1712 | } | ||
1713 | emit_sized_op(type.size, OP_ST64K, OP_ST32K, OP_ST16K, OP_ST8K, reg_val, | ||
1714 | reg_dst, 0, node, chunk); | ||
1715 | |||
1716 | return (CompResult){.type = COMP_NIL}; | ||
1717 | } | ||
1718 | |||
1719 | switch (res.type) { | ||
1720 | case COMP_CONST: { | ||
1721 | sz reg_addr = chunk->reg_idx++; | ||
1722 | sz reg_dst = chunk->reg_idx++; | ||
1723 | emit_op(op_ldaddr, reg_addr, idx, 0, node, chunk); | ||
1724 | emit_op(OP_LDCONST, reg_dst, res.idx, 0, node, chunk); | ||
1725 | emit_sized_op(type.size, OP_ST64K, OP_ST32K, OP_ST16K, OP_ST8K, | ||
1726 | reg_dst, reg_addr, 0, node, chunk); | ||
1727 | } break; | ||
1728 | case COMP_REG: { | ||
1729 | sz reg_addr = chunk->reg_idx++; | ||
1730 | sz reg_val = res.idx; | ||
1731 | emit_op(op_ldaddr, reg_addr, idx, 0, node, chunk); | ||
1732 | emit_sized_op(type.size, OP_ST64K, OP_ST32K, OP_ST16K, OP_ST8K, | ||
1733 | reg_val, reg_addr, 0, node, chunk); | ||
1734 | if (type.size > 8) { | ||
1735 | sz reg_dst = chunk->reg_idx++; | ||
1736 | for (sz i = 0; i < var.size / 8; i++) { | ||
1737 | sz offset = add_constant(chunk, i); | ||
1738 | emit_op(OP_LD64I, reg_dst, reg_val, offset, node, chunk); | ||
1739 | emit_op(OP_ST64I, reg_dst, reg_addr, offset, node, chunk); | ||
1740 | } | ||
1741 | } | ||
1742 | } break; | ||
1743 | case COMP_STRING: { | ||
1744 | // Get the address for the string value variable. | ||
1745 | sz str_addr = chunk->reg_idx++; | ||
1746 | emit_op(OP_LDSTR, str_addr, res.idx, 0, node->var.val, chunk); | ||
1747 | |||
1748 | // Get the address for the local/global storage | ||
1749 | // variable. | ||
1750 | sz var_addr = chunk->reg_idx++; | ||
1751 | emit_op(op_ldaddr, var_addr, idx, 0, node, chunk); | ||
1752 | |||
1753 | // Copy the fat pointer. | ||
1754 | emit_fat_copy(chunk, node, var_addr, str_addr); | ||
1755 | } break; | ||
1756 | default: { | ||
1757 | emit_compile_err(compiler, chunk, node); | ||
1758 | return (CompResult){.type = COMP_ERR}; | ||
1759 | } break; | ||
1760 | } | ||
935 | return (CompResult){.type = COMP_NIL}; | 1761 | return (CompResult){.type = COMP_NIL}; |
936 | } | 1762 | } |
937 | 1763 | ||
938 | CompResult | 1764 | CompResult |
939 | compile_expr(Chunk *chunk, Node *node) { | 1765 | compile_symbol(Compiler *compiler, Chunk *chunk, Node *node) { |
1766 | Str name = node->unique_name; | ||
1767 | StrVarMap *map = NULL; | ||
1768 | Chunk *next = chunk; | ||
1769 | while (next) { | ||
1770 | map = varmap_lookup(&next->varmap, name); | ||
1771 | if (map) { | ||
1772 | break; | ||
1773 | } | ||
1774 | next = next->parent; | ||
1775 | } | ||
1776 | if (!map) { | ||
1777 | emit_compile_err(compiler, chunk, node); | ||
1778 | return (CompResult){.type = COMP_ERR}; | ||
1779 | } | ||
1780 | sz op_ldaddr = OP_LDLADDR; | ||
1781 | if (next == &compiler->main_chunk) { | ||
1782 | op_ldaddr = OP_LDGADDR; | ||
1783 | } | ||
1784 | Variable var = map->val; | ||
1785 | Type type = map->val.type; | ||
1786 | sz reg_dst = chunk->reg_idx++; | ||
1787 | // TODO: ... | ||
1788 | // if (node->is_ptr || str_has_prefix(var.type_name, cstr("[]")) || | ||
1789 | // str_eq(var.type_name, cstr("Str"))) { | ||
1790 | // emit_op(op_ldaddr, reg_dst, var.idx, 0, node, chunk); | ||
1791 | // } else { | ||
1792 | sz reg_addr = chunk->reg_idx++; | ||
1793 | emit_op(op_ldaddr, reg_addr, var.idx, 0, node, chunk); | ||
1794 | emit_sized_op(type.size, OP_LD64K, OP_LD32K, OP_LD16K, OP_LD8K, reg_dst, | ||
1795 | reg_addr, 0, node, chunk); | ||
1796 | // } | ||
1797 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | ||
1798 | } | ||
1799 | |||
1800 | CompResult | ||
1801 | compile_symbol_idx(Compiler *compiler, Chunk *chunk, Node *node) { | ||
1802 | Str name = node->unique_name; | ||
1803 | StrVarMap *map = NULL; | ||
1804 | Chunk *next = chunk; | ||
1805 | while (next) { | ||
1806 | map = varmap_lookup(&next->varmap, name); | ||
1807 | if (map) { | ||
1808 | break; | ||
1809 | } | ||
1810 | next = next->parent; | ||
1811 | } | ||
1812 | if (!map) { | ||
1813 | eprintln("couldn't resolve symbol name: %s", name); | ||
1814 | emit_compile_err(compiler, chunk, node); | ||
1815 | return (CompResult){.type = COMP_ERR}; | ||
1816 | } | ||
1817 | sz op_ldaddr = OP_LDLADDR; | ||
1818 | sz op_ldvar = OP_LDLVAR; | ||
1819 | if (next == &compiler->main_chunk) { | ||
1820 | op_ldaddr = OP_LDGADDR; | ||
1821 | op_ldvar = OP_LDGVAR; | ||
1822 | } | ||
1823 | |||
1824 | // Destination. | ||
1825 | sz reg_dst = chunk->reg_idx++; | ||
1826 | |||
1827 | // Address. | ||
1828 | sz reg_addr = chunk->reg_idx++; | ||
1829 | if (str_has_prefix(map->val.type_name, cstr("[]"))) { | ||
1830 | emit_op(op_ldaddr, reg_addr, map->val.idx, 0, node->var.val, chunk); | ||
1831 | } else { | ||
1832 | emit_op(op_ldvar, reg_addr, map->val.idx, 0, node->var.val, chunk); | ||
1833 | } | ||
1834 | |||
1835 | Type type = map->val.type; | ||
1836 | |||
1837 | // Index. | ||
1838 | CompResult idx = compile_expr(compiler, chunk, node->sym.arr_size); | ||
1839 | switch (idx.type) { | ||
1840 | case COMP_CONST: { | ||
1841 | emit_sized_op(type.size, OP_LD64I, OP_LD32I, OP_LD16I, OP_LD8I, | ||
1842 | reg_dst, reg_addr, idx.idx, node, chunk); | ||
1843 | } break; | ||
1844 | case COMP_REG: { | ||
1845 | emit_sized_op(type.size, OP_LD64, OP_LD32, OP_LD16, OP_LD8, reg_dst, | ||
1846 | reg_addr, idx.idx, node, chunk); | ||
1847 | } break; | ||
1848 | default: { | ||
1849 | emit_compile_err(compiler, chunk, node); | ||
1850 | return (CompResult){.type = COMP_ERR}; | ||
1851 | } break; | ||
1852 | } | ||
1853 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | ||
1854 | } | ||
1855 | |||
1856 | CompResult | ||
1857 | compile_expr(Compiler *compiler, Chunk *chunk, Node *node) { | ||
940 | switch (node->kind) { | 1858 | switch (node->kind) { |
941 | case NODE_FUN: return compile_function(chunk, node); | 1859 | case NODE_BREAK: return compile_break(compiler, chunk, node); |
942 | case NODE_FUNCALL: return compile_funcall(chunk, node); | 1860 | case NODE_CONTINUE: return compile_continue(compiler, chunk, node); |
943 | case NODE_WHILE: return compile_while(chunk, node); | 1861 | case NODE_RETURN: return compile_return(compiler, chunk, node); |
944 | case NODE_IF: return compile_if(chunk, node); | 1862 | case NODE_FUN: return compile_function(compiler, chunk, node); |
945 | case NODE_COND: return compile_cond(chunk, node); | 1863 | case NODE_FUNCALL: return compile_funcall(compiler, chunk, node); |
1864 | case NODE_WHILE: return compile_while(compiler, chunk, node); | ||
1865 | case NODE_IF: return compile_if(compiler, chunk, node); | ||
1866 | case NODE_COND: return compile_cond(compiler, chunk, node); | ||
946 | // Logic. | 1867 | // Logic. |
947 | // case NODE_XOR: | ||
948 | case NODE_BITNOT: | 1868 | case NODE_BITNOT: |
949 | case NODE_NOT: return compile_unary(chunk, node); break; | 1869 | case NODE_NOT: return compile_unary(compiler, chunk, node); break; |
950 | case NODE_AND: | 1870 | case NODE_AND: |
951 | case NODE_OR: | 1871 | case NODE_OR: return compile_binary_logic(compiler, chunk, node); break; |
952 | case NODE_EQ: | 1872 | case NODE_EQ: |
953 | case NODE_NEQ: | 1873 | case NODE_NEQ: |
954 | case NODE_LT: | 1874 | case NODE_LT: |
@@ -957,6 +1877,7 @@ compile_expr(Chunk *chunk, Node *node) { | |||
957 | // Bitwise ops. | 1877 | // Bitwise ops. |
958 | case NODE_BITAND: | 1878 | case NODE_BITAND: |
959 | case NODE_BITOR: | 1879 | case NODE_BITOR: |
1880 | case NODE_BITXOR: | ||
960 | case NODE_BITLSHIFT: | 1881 | case NODE_BITLSHIFT: |
961 | case NODE_BITRSHIFT: | 1882 | case NODE_BITRSHIFT: |
962 | // Arithmetic. | 1883 | // Arithmetic. |
@@ -965,7 +1886,7 @@ compile_expr(Chunk *chunk, Node *node) { | |||
965 | case NODE_SUB: | 1886 | case NODE_SUB: |
966 | case NODE_MUL: | 1887 | case NODE_MUL: |
967 | case NODE_DIV: | 1888 | case NODE_DIV: |
968 | case NODE_MOD: return compile_binary(chunk, node); break; | 1889 | case NODE_MOD: return compile_binary(compiler, chunk, node); break; |
969 | case NODE_TRUE: | 1890 | case NODE_TRUE: |
970 | case NODE_FALSE: | 1891 | case NODE_FALSE: |
971 | case NODE_NUM_FLOAT: | 1892 | case NODE_NUM_FLOAT: |
@@ -986,192 +1907,74 @@ compile_expr(Chunk *chunk, Node *node) { | |||
986 | .idx = str_idx, | 1907 | .idx = str_idx, |
987 | }; | 1908 | }; |
988 | } break; | 1909 | } break; |
989 | case NODE_LET: { | 1910 | case NODE_LET: return compile_let(compiler, chunk, node); |
990 | sz idx = array_size(chunk->vars); | 1911 | case NODE_SET: return compile_set(compiler, chunk, node); |
991 | Str name = node->unique_name; | 1912 | case NODE_SYMBOL: return compile_symbol(compiler, chunk, node); |
992 | Str type = node->var_name->type; | 1913 | case NODE_SYMBOL_IDX: return compile_symbol_idx(compiler, chunk, node); |
993 | sz size = 8; | 1914 | case NODE_PTR: { |
994 | // TODO: get type storage from a table to consider all the basic | 1915 | // Load and return address of associated symbol. |
995 | // types as well as user defined ones. | 1916 | Str name = node->t.next->unique_name; |
996 | if (str_eq(type, cstr("str"))) { | 1917 | sz op_ldaddr = OP_LDLADDR; |
997 | size = 16; | 1918 | if (chunk == &compiler->main_chunk) { |
998 | } | 1919 | op_ldaddr = OP_LDGADDR; |
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 | } | 1920 | } |
1039 | 1921 | ||
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); | 1922 | StrVarMap *map = varmap_lookup(&chunk->varmap, name); |
1045 | if (!map) { | 1923 | if (!map) { |
1046 | eprintln("error: node_set: symbol name not found: %s", name); | 1924 | 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 | } | 1925 | } |
1117 | Variable var = map->val; | 1926 | 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 | 1927 | ||
1134 | // Destination. | ||
1135 | u8 reg_dst = chunk->reg_idx++; | ||
1136 | |||
1137 | // Address. | ||
1138 | sz reg_addr = chunk->reg_idx++; | 1928 | sz reg_addr = chunk->reg_idx++; |
1139 | if (str_has_prefix(map->val.type, cstr("[]"))) { | 1929 | 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, | 1930 | return (CompResult){.type = COMP_REG, .idx = reg_addr}; |
1141 | chunk); | 1931 | } break; |
1142 | } else { | 1932 | case NODE_DEREF: { |
1143 | EMIT_OP(OP_LDGVAR, reg_addr, map->val.idx, 0, node->var_val, | 1933 | Str type_name = node->type; |
1144 | chunk); | 1934 | if (str_has_prefix(type_name, cstr("@"))) { |
1935 | type_name = cstr("Ptr"); | ||
1145 | } | 1936 | } |
1146 | 1937 | StrTypeMap *t = strtype_lookup(&compiler->type_map, type_name); | |
1147 | // Index. | 1938 | sz size = t->val.size; |
1148 | CompResult idx = compile_expr(chunk, node->arr_size); | 1939 | |
1149 | switch (idx.type) { | 1940 | Node *next = node->deref.next; |
1150 | case COMP_CONST: { | 1941 | sz n_deref = 0; |
1151 | EMIT_OP(OP_LD64I, reg_dst, reg_addr, idx.idx, node, chunk); | 1942 | while (next) { |
1152 | } break; | 1943 | n_deref++; |
1153 | case COMP_REG: { | 1944 | if (next->kind == NODE_SYMBOL) { |
1154 | EMIT_OP(OP_LD64, reg_dst, reg_addr, idx.idx, node, chunk); | 1945 | break; |
1155 | } break; | 1946 | } |
1156 | default: { | 1947 | next = next->deref.next; |
1157 | return (CompResult){.type = COMP_ERR}; | 1948 | } |
1158 | } break; | 1949 | CompResult res = compile_symbol(compiler, chunk, next); |
1950 | sz reg_dst = res.idx; | ||
1951 | sz reg_src = res.idx; | ||
1952 | for (sz i = 0; i < n_deref; i++) { | ||
1953 | reg_dst = chunk->reg_idx++; | ||
1954 | if (i == n_deref - 1) { | ||
1955 | emit_sized_op(size, OP_LD64K, OP_LD32K, OP_LD16K, OP_LD8K, | ||
1956 | reg_dst, reg_src, 0, node, chunk); | ||
1957 | } else { | ||
1958 | emit_op(OP_LD64K, reg_dst, reg_src, 0, node, chunk); | ||
1959 | } | ||
1960 | reg_src = reg_dst; | ||
1159 | } | 1961 | } |
1160 | // TODO: hardcoding the type size for now (LD64/LD64I). | ||
1161 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; | 1962 | return (CompResult){.type = COMP_REG, .idx = reg_dst}; |
1162 | } break; | 1963 | } break; |
1163 | case NODE_BLOCK: { | 1964 | case NODE_BLOCK: { |
1164 | CompResult res; | 1965 | CompResult res; |
1165 | for (sz i = 0; i < array_size(node->elements); i++) { | 1966 | for (sz i = 0; i < array_size(node->elements); i++) { |
1166 | Node *root = node->elements[i]; | 1967 | Node *root = node->elements[i]; |
1167 | res = compile_expr(chunk, root); | 1968 | res = compile_expr(compiler, chunk, root); |
1168 | } | 1969 | } |
1169 | return res; | 1970 | return res; |
1170 | } break; | 1971 | } break; |
1972 | case NODE_NIL: return (CompResult){.type = COMP_NIL}; | ||
1171 | default: { | 1973 | default: { |
1172 | eprintln("error: compilation not implemented for node %s", | 1974 | eprintln("error: compilation not implemented for node %s", |
1173 | node_str[node->kind]); | 1975 | node_str[node->kind]); |
1174 | exit(EXIT_FAILURE); | 1976 | emit_compile_err(compiler, chunk, node); |
1977 | return (CompResult){.type = COMP_ERR}; | ||
1175 | } break; | 1978 | } break; |
1176 | } | 1979 | } |
1177 | return (CompResult){.type = COMP_ERR}; | 1980 | return (CompResult){.type = COMP_ERR}; |
@@ -1188,6 +1991,14 @@ disassemble_instruction(Instruction instruction) { | |||
1188 | case OP_MOV16: | 1991 | case OP_MOV16: |
1189 | case OP_MOV32: | 1992 | case OP_MOV32: |
1190 | case OP_MOV64: | 1993 | case OP_MOV64: |
1994 | case OP_LD8K: | ||
1995 | case OP_LD16K: | ||
1996 | case OP_LD32K: | ||
1997 | case OP_LD64K: | ||
1998 | case OP_ST8K: | ||
1999 | case OP_ST16K: | ||
2000 | case OP_ST32K: | ||
2001 | case OP_ST64K: | ||
1191 | println("%s r%d, r%d", op_str[instruction.op], instruction.dst, | 2002 | println("%s r%d, r%d", op_str[instruction.op], instruction.dst, |
1192 | instruction.a, instruction.b); | 2003 | instruction.a, instruction.b); |
1193 | break; | 2004 | break; |
@@ -1196,10 +2007,7 @@ disassemble_instruction(Instruction instruction) { | |||
1196 | println("%s l%d, r%d", op_str[instruction.op], instruction.dst, | 2007 | println("%s l%d, r%d", op_str[instruction.op], instruction.dst, |
1197 | instruction.a, instruction.b); | 2008 | instruction.a, instruction.b); |
1198 | break; | 2009 | break; |
1199 | case OP_LD8K: | 2010 | 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, | 2011 | println("%s r%d, c%d", op_str[instruction.op], instruction.dst, |
1204 | instruction.a, instruction.b); | 2012 | instruction.a, instruction.b); |
1205 | break; | 2013 | break; |
@@ -1233,6 +2041,7 @@ disassemble_instruction(Instruction instruction) { | |||
1233 | case OP_BITRSHIFTI: | 2041 | case OP_BITRSHIFTI: |
1234 | case OP_BITANDI: | 2042 | case OP_BITANDI: |
1235 | case OP_BITORI: | 2043 | case OP_BITORI: |
2044 | case OP_BITXORI: | ||
1236 | println("%s r%d, r%d, c%d", op_str[instruction.op], instruction.dst, | 2045 | println("%s r%d, r%d, c%d", op_str[instruction.op], instruction.dst, |
1237 | instruction.a, instruction.b); | 2046 | instruction.a, instruction.b); |
1238 | break; | 2047 | break; |
@@ -1266,19 +2075,28 @@ disassemble_instruction(Instruction instruction) { | |||
1266 | case OP_BITRSHIFT: | 2075 | case OP_BITRSHIFT: |
1267 | case OP_BITAND: | 2076 | case OP_BITAND: |
1268 | case OP_BITOR: | 2077 | case OP_BITOR: |
2078 | case OP_BITXOR: | ||
1269 | println("%s r%d, r%d, r%d", op_str[instruction.op], instruction.dst, | 2079 | println("%s r%d, r%d, r%d", op_str[instruction.op], instruction.dst, |
1270 | instruction.a, instruction.b); | 2080 | instruction.a, instruction.b); |
1271 | break; | 2081 | break; |
1272 | case OP_LDGVAR: | 2082 | case OP_LDGVAR: |
1273 | case OP_LDGADDR: | 2083 | case OP_LDGADDR: |
2084 | case OP_LDLVAR: | ||
2085 | case OP_LDLADDR: | ||
1274 | println("%s r%d, v%d", op_str[instruction.op], instruction.dst, | 2086 | println("%s r%d, v%d", op_str[instruction.op], instruction.dst, |
1275 | instruction.a, instruction.b); | 2087 | instruction.a, instruction.b); |
1276 | break; | 2088 | break; |
2089 | case OP_LDSTR: | ||
2090 | println("%s r%d, s%d", op_str[instruction.op], instruction.dst, | ||
2091 | instruction.a, instruction.b); | ||
2092 | break; | ||
1277 | case OP_STGVAR: | 2093 | case OP_STGVAR: |
2094 | case OP_STLVAR: | ||
1278 | println("%s v%d, r%d", op_str[instruction.op], instruction.dst, | 2095 | println("%s v%d, r%d", op_str[instruction.op], instruction.dst, |
1279 | instruction.a, instruction.b); | 2096 | instruction.a, instruction.b); |
1280 | break; | 2097 | break; |
1281 | case OP_STGVARI: | 2098 | case OP_STGVARI: |
2099 | case OP_STLVARI: | ||
1282 | println("%s v%d, c%d", op_str[instruction.op], instruction.dst, | 2100 | println("%s v%d, c%d", op_str[instruction.op], instruction.dst, |
1283 | instruction.a, instruction.b); | 2101 | instruction.a, instruction.b); |
1284 | break; | 2102 | break; |
@@ -1301,17 +2119,36 @@ disassemble_instruction(Instruction instruction) { | |||
1301 | println("%s l%d, c%d", op_str[instruction.op], instruction.dst, | 2119 | println("%s l%d, c%d", op_str[instruction.op], instruction.dst, |
1302 | instruction.a, instruction.b); | 2120 | instruction.a, instruction.b); |
1303 | break; | 2121 | break; |
2122 | case OP_PRINTS8: | ||
2123 | case OP_PRINTS16: | ||
2124 | case OP_PRINTS32: | ||
1304 | case OP_PRINTS64: | 2125 | case OP_PRINTS64: |
2126 | case OP_PRINTU8: | ||
2127 | case OP_PRINTU16: | ||
2128 | case OP_PRINTU32: | ||
2129 | case OP_PRINTU64: | ||
2130 | case OP_PRINTF32: | ||
1305 | case OP_PRINTF64: | 2131 | case OP_PRINTF64: |
1306 | case OP_PRINTSTR: | 2132 | case OP_PRINTSTR: |
2133 | case OP_PRINTBOOL: | ||
1307 | case OP_PUSH: | 2134 | case OP_PUSH: |
1308 | case OP_POP: | 2135 | case OP_POP: |
1309 | case OP_PUTRET: | 2136 | case OP_PUTRET: |
1310 | println("%s r%d", op_str[instruction.op], instruction.dst, | 2137 | println("%s r%d", op_str[instruction.op], instruction.dst, |
1311 | instruction.a, instruction.b); | 2138 | instruction.a, instruction.b); |
1312 | break; | 2139 | break; |
2140 | case OP_PRINTSTRI: | ||
2141 | case OP_PRINTS8I: | ||
2142 | case OP_PRINTS16I: | ||
2143 | case OP_PRINTS32I: | ||
1313 | case OP_PRINTS64I: | 2144 | case OP_PRINTS64I: |
2145 | case OP_PRINTU8I: | ||
2146 | case OP_PRINTU16I: | ||
2147 | case OP_PRINTU32I: | ||
2148 | case OP_PRINTU64I: | ||
2149 | case OP_PRINTF32I: | ||
1314 | case OP_PRINTF64I: | 2150 | case OP_PRINTF64I: |
2151 | case OP_PRINTBOOLI: | ||
1315 | case OP_RESERVE: | 2152 | case OP_RESERVE: |
1316 | case OP_PUSHI: | 2153 | case OP_PUSHI: |
1317 | case OP_PUTRETI: | 2154 | case OP_PUTRETI: |
@@ -1319,6 +2156,7 @@ disassemble_instruction(Instruction instruction) { | |||
1319 | instruction.a, instruction.b); | 2156 | instruction.a, instruction.b); |
1320 | break; | 2157 | break; |
1321 | case OP_RET: | 2158 | case OP_RET: |
2159 | case OP_RECUR: | ||
1322 | case OP_HALT: println("%s", op_str[instruction.op]); break; | 2160 | case OP_HALT: println("%s", op_str[instruction.op]); break; |
1323 | default: println("Unknown opcode %d", instruction.op); break; | 2161 | default: println("Unknown opcode %d", instruction.op); break; |
1324 | } | 2162 | } |
@@ -1336,11 +2174,25 @@ disassemble_chunk(Chunk chunk) { | |||
1336 | for (sz i = 0; i < array_size(chunk.code); i++) { | 2174 | for (sz i = 0; i < array_size(chunk.code); i++) { |
1337 | printf(" %.4ld:%.4ld %.4lx ", chunk.linecol[i].line, | 2175 | printf(" %.4ld:%.4ld %.4lx ", chunk.linecol[i].line, |
1338 | chunk.linecol[i].col, i); | 2176 | chunk.linecol[i].col, i); |
1339 | IntIntMap *label = intintmap_lookup(&chunk.labels_rev, i); | 2177 | IntIntMapIter lab_it = intintmap_iterator(chunk.labels, chunk.storage); |
1340 | if (label) { | 2178 | IntIntMap *m = intintmap_next(&lab_it, chunk.storage); |
1341 | printf(".L%.2ld ", label->val); | 2179 | Str labs = cstr(""); |
2180 | while (m) { | ||
2181 | if (m->val == i) { | ||
2182 | labs = str_concat(labs, cstr(".L"), chunk.storage); | ||
2183 | labs = str_concat(labs, str_from_int(m->key, chunk.storage), | ||
2184 | chunk.storage); | ||
2185 | break; | ||
2186 | } | ||
2187 | m = intintmap_next(&lab_it, chunk.storage); | ||
2188 | } | ||
2189 | if (labs.size) { | ||
2190 | print("%s", labs); | ||
2191 | for (sz i = 0; i < 7 - labs.size; i++) { | ||
2192 | print(" "); | ||
2193 | } | ||
1342 | } else { | 2194 | } else { |
1343 | printf(" %2s ", ""); | 2195 | printf(" "); |
1344 | } | 2196 | } |
1345 | disassemble_instruction(chunk.code[i]); | 2197 | disassemble_instruction(chunk.code[i]); |
1346 | } | 2198 | } |
@@ -1361,7 +2213,7 @@ disassemble_chunk(Chunk chunk) { | |||
1361 | for (sz i = 0; i < array_size(chunk.vars); i++) { | 2213 | 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, | 2214 | println(" %x{2}: [%x{4}:%x{4}] %s: %s", i, chunk.vars[i].offset, |
1363 | chunk.vars[i].offset + chunk.vars[i].size, | 2215 | chunk.vars[i].offset + chunk.vars[i].size, |
1364 | chunk.vars[i].name, chunk.vars[i].type); | 2216 | chunk.vars[i].name, chunk.vars[i].type_name); |
1365 | } | 2217 | } |
1366 | } | 2218 | } |
1367 | if (array_size(chunk.functions) > 0) { | 2219 | if (array_size(chunk.functions) > 0) { |
@@ -1378,4 +2230,75 @@ disassemble_chunk(Chunk chunk) { | |||
1378 | } | 2230 | } |
1379 | } | 2231 | } |
1380 | 2232 | ||
2233 | void | ||
2234 | bytecode_compiler(Compiler *compiler, Parser parser) { | ||
2235 | compiler->main_chunk = (Chunk){ | ||
2236 | .file_name = compiler->file_name, | ||
2237 | .storage = compiler->storage, | ||
2238 | .name = cstr(".main"), | ||
2239 | }; | ||
2240 | array_zero(compiler->main_chunk.constants, 256, compiler->storage); | ||
2241 | array_zero(compiler->main_chunk.code, 0xffff, compiler->storage); | ||
2242 | sz n_roots = array_size(parser.nodes); | ||
2243 | |||
2244 | // Fill up builtin types and tables. | ||
2245 | for (sz i = 0; i < LEN(builtin_types); i++) { | ||
2246 | Type type = builtin_types[i]; | ||
2247 | strtype_insert(&compiler->type_map, type.unique_name, type, | ||
2248 | compiler->storage); | ||
2249 | } | ||
2250 | Str unsigned_ints[] = { | ||
2251 | cstr("U8"), cstr("U16"), cstr("U32"), | ||
2252 | cstr("U64"), cstr("Ptr"), cstr("UInt"), | ||
2253 | }; | ||
2254 | for (sz i = 0; i < LEN(unsigned_ints); i++) { | ||
2255 | Str type = unsigned_ints[i]; | ||
2256 | strset_insert(&compiler->unsigned_ints, type, compiler->storage); | ||
2257 | } | ||
2258 | Str signed_ints[] = { | ||
2259 | cstr("S8"), cstr("S16"), cstr("S32"), cstr("S64"), cstr("Int"), | ||
2260 | }; | ||
2261 | for (sz i = 0; i < LEN(signed_ints); i++) { | ||
2262 | Str type = signed_ints[i]; | ||
2263 | strset_insert(&compiler->signed_ints, type, compiler->storage); | ||
2264 | } | ||
2265 | |||
2266 | // Do a first pass to setup the function declarations on the main scope. | ||
2267 | Chunk *chunk = &compiler->main_chunk; | ||
2268 | for (sz i = 0; i < n_roots; i++) { | ||
2269 | Node *root = parser.nodes[i]; | ||
2270 | if (root->kind == NODE_FUN) { | ||
2271 | declare_function(chunk, root); | ||
2272 | } | ||
2273 | } | ||
2274 | |||
2275 | // Compile all root expressions. | ||
2276 | CompResult res = {0}; | ||
2277 | for (sz i = 0; i < n_roots; i++) { | ||
2278 | Node *root = parser.nodes[i]; | ||
2279 | res = compile_expr(compiler, chunk, root); | ||
2280 | } | ||
2281 | |||
2282 | // Make sure the last result is on r0. | ||
2283 | sz res_reg = 0; | ||
2284 | bool is_nil = false; | ||
2285 | switch (res.type) { | ||
2286 | case COMP_CONST: { | ||
2287 | res_reg = chunk->reg_idx++; | ||
2288 | Instruction inst = | ||
2289 | (Instruction){.op = OP_LDCONST, .dst = res_reg, .a = res.idx}; | ||
2290 | array_push(chunk->code, inst, chunk->storage); | ||
2291 | } break; | ||
2292 | case COMP_REG: { | ||
2293 | res_reg = res.idx; | ||
2294 | } break; | ||
2295 | case COMP_NIL: { | ||
2296 | is_nil = true; | ||
2297 | } break; | ||
2298 | default: break; | ||
2299 | } | ||
2300 | emit_op(OP_HALT, res_reg, !is_nil, 0, NULL, chunk); | ||
2301 | verify_chunk(chunk); | ||
2302 | } | ||
2303 | |||
1381 | #endif // COMPILER_C | 2304 | #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,41 @@ | |||
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 | // } | 19 | // let a: @Int ; pointer to int |
20 | // TODO: fix semantics for the following expression: | 20 | // let b: @@Int ; pointer to pointer to int (etc.) |
21 | // let b = int | 21 | // let c: [123]Int ; static array -> @Int |
22 | // a type shouldn't be a valid symbol name | 22 | // let d: []Int ; slice / view -> struct Slice { u8* mem ; sz size ; } |
23 | // TODO: fix semantics for arrays: static arrays can't have size 0. | 23 | // let e: [...]Int ; dynamic array -> struct DArry { u8* mem ; sz size ; sz cap ; } |
24 | // TODO: consider making all tye types PascalCase: Int F64 Str... | 24 | // let f: [123]@Int ; static array of int pointers [](@Int) |
25 | // let g: @[123]Int ; pointer to a static array of integers @([123]Int) | ||
26 | // let h: #[Str:Int] ; Hash map of string keys and integer values | ||
27 | // let i: #[Str:@Int] ; Hash map of string keys and pointers to integer | ||
28 | // let j: #[@Str:Int] ; Hash map of string pointers to integers | ||
29 | // let k: @#[Str:Int] ; Pointer to a hash map of string to ints | ||
30 | // let l: (Int Int : Int) ; Function pointer == @(fun(Int,Int):Int) | ||
25 | // TODO: add a `const` keyword that can only take literals or constexpr values. | 31 | // TODO: add a `const` keyword that can only take literals or constexpr values. |
26 | // TODO: add assignment operators instead of `set` :=, +=, -= | 32 | // TODO: "first class functions" via function pointers |
27 | // TODO: add mifix operators ++ and -- | 33 | // TODO: convenient function calls per data type instead of methods: |
34 | // fun add(a: int, b: int): int a + b | ||
35 | // add(12, 34) == 12.add(34) | ||
36 | // concat(str, str): str | ||
37 | // "hello ".concat("world") ; "hello world" | ||
38 | // TODO: more numeric types | ||
39 | // TODO: structs and user defined types | ||
40 | // TODO: constant folding | ||
41 | // TODO: constexpr evaluation | ||
42 | // TODO: casting on demand (1:u16, 0x123:ptr, "hi":int ??? how to deal with | ||
43 | // unsafe casts?) | ||
44 | // TODO: for nil type returns, consider only allowing fun() {} and discarding | ||
45 | // fun(): nil and fun(): (). Only one way of doing things would be preferable. | ||
46 | // TODO: constexpr or const expressions could be evaluated with the bytecode | ||
47 | // interpreter if we are performing compilation. | ||
48 | // TODO: refactor compiler.c, the duplication is getting out of hand tbh, plus | ||
49 | // there are a lot of inconsistent naming things. | ||
28 | 50 | ||
29 | typedef enum ExecMode { | 51 | typedef enum ExecMode { |
30 | RUN_NORMAL, | 52 | RUN_NORMAL, |
@@ -56,6 +78,9 @@ process_file(Str path) { | |||
56 | sz errors = 0; | 78 | sz errors = 0; |
57 | 79 | ||
58 | // Lexer. | 80 | // Lexer. |
81 | #if DEBUG == 1 | ||
82 | println("lexing..."); | ||
83 | #endif | ||
59 | Scanner scanner = {.str = file.data}; | 84 | Scanner scanner = {.str = file.data}; |
60 | Token *tokens = NULL; | 85 | Token *tokens = NULL; |
61 | Token tok = {0}; | 86 | Token tok = {0}; |
@@ -79,6 +104,9 @@ process_file(Str path) { | |||
79 | } | 104 | } |
80 | 105 | ||
81 | // Parser. | 106 | // Parser. |
107 | #if DEBUG == 1 | ||
108 | println("parsing..."); | ||
109 | #endif | ||
82 | Parser parser = { | 110 | Parser parser = { |
83 | .tokens = tokens, | 111 | .tokens = tokens, |
84 | .storage = &lexer_arena, | 112 | .storage = &lexer_arena, |
@@ -106,6 +134,9 @@ process_file(Str path) { | |||
106 | } | 134 | } |
107 | 135 | ||
108 | // Semantic analysis. | 136 | // Semantic analysis. |
137 | #if DEBUG == 1 | ||
138 | println("semantic analysis..."); | ||
139 | #endif | ||
109 | Analyzer analyzer = (Analyzer){ | 140 | Analyzer analyzer = (Analyzer){ |
110 | .storage = &lexer_arena, | 141 | .storage = &lexer_arena, |
111 | .file_name = path, | 142 | .file_name = path, |
@@ -175,68 +206,26 @@ process_file(Str path) { | |||
175 | } | 206 | } |
176 | #endif | 207 | #endif |
177 | 208 | ||
178 | // TODO: Type checking. | ||
179 | |||
180 | // Compile roots. | 209 | // Compile roots. |
210 | #if DEBUG == 1 | ||
211 | println("compilation..."); | ||
212 | #endif | ||
181 | Arena bytecode_arena = arena_create(LEXER_MEM, os_allocator); | 213 | Arena bytecode_arena = arena_create(LEXER_MEM, os_allocator); |
182 | Chunk chunk = { | 214 | Compiler compiler = { |
183 | .file_name = path, | 215 | .file_name = path, |
184 | .storage = &bytecode_arena, | 216 | .storage = &bytecode_arena, |
185 | .name = cstr(".main"), | 217 | .integer_types = analyzer.integer_types, |
218 | .float_types = analyzer.float_types, | ||
219 | .numeric_types = analyzer.numeric_types, | ||
220 | .lab_pre = -1, | ||
221 | .lab_post = -1, | ||
186 | }; | 222 | }; |
187 | array_zero(chunk.constants, 256, &bytecode_arena); | 223 | bytecode_compiler(&compiler, parser); |
188 | array_zero(chunk.code, 0xffff, &bytecode_arena); | 224 | 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 | 225 | ||
235 | // Run bytecode on VM. | 226 | // Run bytecode on VM. |
236 | VM vm = {0}; | 227 | VM vm = {0}; |
237 | vm_init(&vm, &chunk); | 228 | 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); | 229 | vm_run(&vm); |
241 | #if DEBUG == 1 | 230 | #if DEBUG == 1 |
242 | println("MEMORY:\n%{Mem}", | 231 | println("MEMORY:\n%{Mem}", |
diff --git a/src/parser.c b/src/parser.c index 90adaf3..0323215 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. |
@@ -66,9 +68,12 @@ typedef enum NodeKind { | |||
66 | NODE_ARR_TYPE, | 68 | NODE_ARR_TYPE, |
67 | NODE_FIELD, | 69 | NODE_FIELD, |
68 | NODE_BLOCK, | 70 | NODE_BLOCK, |
71 | NODE_PTR, | ||
72 | NODE_DEREF, | ||
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. |
@@ -126,77 +132,115 @@ Str node_str[] = { | |||
126 | [NODE_SYMBOL_IDX] = cstr("SYMBOL[IDX]"), | 132 | [NODE_SYMBOL_IDX] = cstr("SYMBOL[IDX]"), |
127 | [NODE_FIELD] = cstr("FIELD"), | 133 | [NODE_FIELD] = cstr("FIELD"), |
128 | [NODE_BLOCK] = cstr("BLOCK"), | 134 | [NODE_BLOCK] = cstr("BLOCK"), |
135 | [NODE_PTR] = cstr("@"), | ||
136 | [NODE_DEREF] = cstr("DEREF"), | ||
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 | struct Node *arr_size; | ||
203 | } NodeSymbol; | ||
204 | |||
205 | typedef struct NodeType { | ||
206 | struct Node *next; | ||
207 | } NodeType; | ||
208 | |||
209 | typedef struct NodeDeref { | ||
210 | struct Node *next; | ||
211 | } NodeDeref; | ||
212 | |||
131 | typedef struct Node { | 213 | typedef struct Node { |
132 | sz id; | 214 | sz id; |
133 | sz line; | 215 | sz line; |
134 | sz col; | 216 | sz col; |
217 | struct Node *parent; | ||
135 | 218 | ||
136 | NodeKind kind; | 219 | NodeKind kind; |
220 | NodeLit value; | ||
137 | union { | 221 | union { |
138 | f64 d; | 222 | NodeBinary binary; |
139 | sz i; | 223 | NodeUnary unary; |
140 | u64 u; | 224 | NodeVariable var; |
141 | Str str; | 225 | NodeSymbol sym; |
142 | Str sym; | 226 | NodeLoop loop; |
143 | } value; | 227 | NodeIf ifelse; |
144 | union { | 228 | NodeField field; |
145 | struct { | 229 | NodeParam param; |
146 | struct Node *left; | 230 | NodeMatch match; |
147 | struct Node *right; | 231 | NodeCase case_entry; |
148 | }; | 232 | NodeFunction func; |
149 | struct { | 233 | NodeType t; |
150 | struct Node *next; | 234 | NodeDeref deref; |
151 | struct Node *arr_size; | ||
152 | }; | ||
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; | 235 | struct Node **struct_field; |
184 | struct Node **elements; | 236 | struct Node **elements; |
185 | struct Node **statements; | 237 | struct Node **statements; |
186 | struct Node **expressions; | 238 | struct Node **expressions; |
187 | struct Node **arguments; | 239 | 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 | }; | 240 | }; |
195 | bool is_ptr; | ||
196 | struct Scope *scope; | ||
197 | Str type; | 241 | Str type; |
198 | Str fun_params; | 242 | Str type_params; |
199 | Str fun_return; | 243 | Str type_returns; |
200 | Str unique_name; | 244 | Str unique_name; |
201 | } Node; | 245 | } Node; |
202 | 246 | ||
@@ -286,6 +330,7 @@ ParseRule parse_rules[] = { | |||
286 | [TOK_BITNOT] = {parse_unary, NULL, PREC_NONE}, | 330 | [TOK_BITNOT] = {parse_unary, NULL, PREC_NONE}, |
287 | [TOK_BITAND] = {NULL, parse_binary, PREC_BITLOGIC}, | 331 | [TOK_BITAND] = {NULL, parse_binary, PREC_BITLOGIC}, |
288 | [TOK_BITOR] = {NULL, parse_binary, PREC_BITLOGIC}, | 332 | [TOK_BITOR] = {NULL, parse_binary, PREC_BITLOGIC}, |
333 | [TOK_BITXOR] = {NULL, parse_binary, PREC_BITLOGIC}, | ||
289 | [TOK_BITLSHIFT] = {NULL, parse_binary, PREC_BITSHIFT}, | 334 | [TOK_BITLSHIFT] = {NULL, parse_binary, PREC_BITSHIFT}, |
290 | [TOK_BITRSHIFT] = {NULL, parse_binary, PREC_BITSHIFT}, | 335 | [TOK_BITRSHIFT] = {NULL, parse_binary, PREC_BITSHIFT}, |
291 | 336 | ||
@@ -308,6 +353,7 @@ ParseRule parse_rules[] = { | |||
308 | [TOK_MATCH] = {parse_keyword, NULL, PREC_NONE}, | 353 | [TOK_MATCH] = {parse_keyword, NULL, PREC_NONE}, |
309 | [TOK_COND] = {parse_keyword, NULL, PREC_NONE}, | 354 | [TOK_COND] = {parse_keyword, NULL, PREC_NONE}, |
310 | [TOK_WHILE] = {parse_keyword, NULL, PREC_NONE}, | 355 | [TOK_WHILE] = {parse_keyword, NULL, PREC_NONE}, |
356 | [TOK_FOR] = {parse_keyword, NULL, PREC_NONE}, | ||
311 | [TOK_CONTINUE] = {parse_keyword, NULL, PREC_NONE}, | 357 | [TOK_CONTINUE] = {parse_keyword, NULL, PREC_NONE}, |
312 | [TOK_BREAK] = {parse_keyword, NULL, PREC_NONE}, | 358 | [TOK_BREAK] = {parse_keyword, NULL, PREC_NONE}, |
313 | [TOK_FUN] = {parse_keyword, NULL, PREC_NONE}, | 359 | [TOK_FUN] = {parse_keyword, NULL, PREC_NONE}, |
@@ -437,7 +483,7 @@ parse_unary(Parser *parser) { | |||
437 | default: break; // Unreachable. | 483 | default: break; // Unreachable. |
438 | } | 484 | } |
439 | if (!node) return; | 485 | if (!node) return; |
440 | node->left = array_pop(parser->nodes); | 486 | node->unary.left = array_pop(parser->nodes); |
441 | array_push(parser->nodes, node, parser->storage); | 487 | array_push(parser->nodes, node, parser->storage); |
442 | } | 488 | } |
443 | 489 | ||
@@ -472,20 +518,28 @@ parse_type(Parser *parser) { | |||
472 | #endif | 518 | #endif |
473 | Node *node = node_alloc(parser, NODE_TYPE, prev); | 519 | Node *node = node_alloc(parser, NODE_TYPE, prev); |
474 | if (!node) return; | 520 | if (!node) return; |
475 | if (parse_match(parser, TOK_AT)) { | 521 | Node *child = node; |
476 | node->is_ptr = true; | 522 | while (parse_match(parser, TOK_AT)) { |
523 | Node *ptr_node = node_alloc(parser, NODE_PTR, parser->previous); | ||
524 | child->t.next = ptr_node; | ||
525 | child = ptr_node; | ||
477 | } | 526 | } |
478 | parse_consume(parser, TOK_SYMBOL, cstr("no type given for struct field")); | 527 | // TODO: arrays |
528 | // TODO: slices | ||
529 | // TODO: maps | ||
530 | // TODO: function pointer syntax: : (T T : R) | ||
531 | parse_consume(parser, TOK_SYMBOL, cstr("expected type name")); | ||
479 | node->value.sym = parser->previous.val; | 532 | node->value.sym = parser->previous.val; |
480 | // Optional array value? | 533 | // node->value.sym = parser->previous.val; |
481 | if (parse_match(parser, TOK_LSQUARE)) { | 534 | // // Optional array value? |
482 | node->kind = NODE_ARR_TYPE, | 535 | // if (parse_match(parser, TOK_LSQUARE)) { |
483 | parse_consume(parser, TOK_NUM_INT, cstr("no array size given")); | 536 | // node->kind = NODE_ARR_TYPE, |
484 | parse_number(parser); | 537 | // parse_consume(parser, TOK_NUM_INT, cstr("no array size given")); |
485 | node->arr_size = array_pop(parser->nodes); | 538 | // parse_number(parser); |
486 | parse_consume(parser, TOK_RSQUARE, | 539 | // node->sym.arr_size = array_pop(parser->nodes); |
487 | cstr("unmatched brackets ']' in array type")); | 540 | // parse_consume(parser, TOK_RSQUARE, |
488 | } | 541 | // cstr("unmatched brackets ']' in array type")); |
542 | // } | ||
489 | array_push(parser->nodes, node, parser->storage); | 543 | array_push(parser->nodes, node, parser->storage); |
490 | } | 544 | } |
491 | 545 | ||
@@ -510,16 +564,16 @@ parse_struct_field(Parser *parser) { | |||
510 | Node *subfield = array_pop(parser->nodes); | 564 | Node *subfield = array_pop(parser->nodes); |
511 | array_push(type->elements, subfield, parser->storage); | 565 | array_push(type->elements, subfield, parser->storage); |
512 | } | 566 | } |
513 | field->field_type = type; | 567 | field->field.type = type; |
514 | } else { | 568 | } else { |
515 | parse_type(parser); | 569 | parse_type(parser); |
516 | field->field_type = array_pop(parser->nodes); | 570 | field->field.type = array_pop(parser->nodes); |
517 | } | 571 | } |
518 | 572 | ||
519 | // Optional assignment. | 573 | // Optional assignment. |
520 | if (parse_match(parser, TOK_ASSIGN)) { | 574 | if (parse_match(parser, TOK_ASSIGN)) { |
521 | parse_expr(parser, PREC_LOW); | 575 | parse_expr(parser, PREC_LOW); |
522 | field->field_val = array_pop(parser->nodes); | 576 | field->field.val = array_pop(parser->nodes); |
523 | } | 577 | } |
524 | array_push(parser->nodes, field, parser->storage); | 578 | array_push(parser->nodes, field, parser->storage); |
525 | } | 579 | } |
@@ -546,10 +600,10 @@ parse_struct_lit_field(Parser *parser) { | |||
546 | Node *subfield = array_pop(parser->nodes); | 600 | Node *subfield = array_pop(parser->nodes); |
547 | array_push(type->elements, subfield, parser->storage); | 601 | array_push(type->elements, subfield, parser->storage); |
548 | } | 602 | } |
549 | field->field_val = type; | 603 | field->field.val = type; |
550 | } else { | 604 | } else { |
551 | parse_expr(parser, PREC_LOW); | 605 | parse_expr(parser, PREC_LOW); |
552 | field->field_val = array_pop(parser->nodes); | 606 | field->field.val = array_pop(parser->nodes); |
553 | } | 607 | } |
554 | array_push(parser->nodes, field, parser->storage); | 608 | array_push(parser->nodes, field, parser->storage); |
555 | } | 609 | } |
@@ -570,8 +624,8 @@ parse_keyword(Parser *parser) { | |||
570 | parse_consume(parser, TOK_SYMBOL, | 624 | parse_consume(parser, TOK_SYMBOL, |
571 | cstr("expected symbol name on let expression")); | 625 | cstr("expected symbol name on let expression")); |
572 | parse_symbol(parser); | 626 | parse_symbol(parser); |
573 | node->var_name = array_pop(parser->nodes); | 627 | node->var.name = array_pop(parser->nodes); |
574 | if (node->var_name->next) { | 628 | if (node->var.name->sym.next) { |
575 | parse_emit_err(parser, prev, | 629 | parse_emit_err(parser, prev, |
576 | cstr("invalid symbol name in let expression")); | 630 | cstr("invalid symbol name in let expression")); |
577 | return; | 631 | return; |
@@ -580,16 +634,16 @@ parse_keyword(Parser *parser) { | |||
580 | // Optional type declaration. | 634 | // Optional type declaration. |
581 | if (parse_match(parser, TOK_COLON)) { | 635 | if (parse_match(parser, TOK_COLON)) { |
582 | parse_type(parser); | 636 | parse_type(parser); |
583 | node->var_type = array_pop(parser->nodes); | 637 | node->var.type = array_pop(parser->nodes); |
584 | } | 638 | } |
585 | 639 | ||
586 | // Optional assignment. | 640 | // Optional assignment. |
587 | if (parse_match(parser, TOK_ASSIGN)) { | 641 | if (parse_match(parser, TOK_ASSIGN)) { |
588 | parse_expr(parser, PREC_LOW); | 642 | parse_expr(parser, PREC_LOW); |
589 | node->var_val = array_pop(parser->nodes); | 643 | node->var.val = array_pop(parser->nodes); |
590 | } | 644 | } |
591 | 645 | ||
592 | if (node->var_type == NULL && node->var_val == NULL) { | 646 | if (node->var.type == NULL && node->var.val == NULL) { |
593 | parse_emit_err(parser, prev, | 647 | parse_emit_err(parser, prev, |
594 | cstr("variable declaration must include type or " | 648 | cstr("variable declaration must include type or " |
595 | "value information")); | 649 | "value information")); |
@@ -599,13 +653,50 @@ parse_keyword(Parser *parser) { | |||
599 | node = node_alloc(parser, NODE_SET, prev); | 653 | node = node_alloc(parser, NODE_SET, prev); |
600 | if (!node) return; | 654 | if (!node) return; |
601 | parse_consume(parser, TOK_SYMBOL, | 655 | parse_consume(parser, TOK_SYMBOL, |
602 | cstr("expected symbol name on let expression")); | 656 | cstr("expected symbol name on set expression")); |
603 | parse_symbol(parser); | 657 | parse_symbol(parser); |
604 | node->var_name = array_pop(parser->nodes); | 658 | node->var.name = array_pop(parser->nodes); |
605 | parse_consume(parser, TOK_ASSIGN, | 659 | |
606 | cstr("expected assignment on set expression")); | 660 | if (parse_match(parser, TOK_ADD_ASSIGN) || |
607 | parse_expr(parser, PREC_LOW); | 661 | parse_match(parser, TOK_ADD_ASSIGN) || |
608 | node->var_val = array_pop(parser->nodes); | 662 | parse_match(parser, TOK_SUB_ASSIGN) || |
663 | parse_match(parser, TOK_MUL_ASSIGN) || | ||
664 | parse_match(parser, TOK_DIV_ASSIGN) || | ||
665 | parse_match(parser, TOK_MOD_ASSIGN) || | ||
666 | parse_match(parser, TOK_BITAND_ASSIGN) || | ||
667 | parse_match(parser, TOK_BITOR_ASSIGN) || | ||
668 | parse_match(parser, TOK_BITXOR_ASSIGN) || | ||
669 | parse_match(parser, TOK_BITLSHIFT_ASSIGN) || | ||
670 | parse_match(parser, TOK_BITRSHIFT_ASSIGN)) { | ||
671 | NodeKind kind = NODE_ERR; | ||
672 | switch (parser->previous.kind) { | ||
673 | case TOK_ADD_ASSIGN: kind = NODE_ADD; break; | ||
674 | case TOK_SUB_ASSIGN: kind = NODE_SUB; break; | ||
675 | case TOK_MUL_ASSIGN: kind = NODE_MUL; break; | ||
676 | case TOK_DIV_ASSIGN: kind = NODE_DIV; break; | ||
677 | case TOK_MOD_ASSIGN: kind = NODE_MOD; break; | ||
678 | case TOK_BITAND_ASSIGN: kind = NODE_BITAND; break; | ||
679 | case TOK_BITOR_ASSIGN: kind = NODE_BITOR; break; | ||
680 | case TOK_BITXOR_ASSIGN: kind = NODE_BITXOR; break; | ||
681 | case TOK_BITLSHIFT_ASSIGN: kind = NODE_BITLSHIFT; break; | ||
682 | case TOK_BITRSHIFT_ASSIGN: kind = NODE_BITRSHIFT; break; | ||
683 | default: break; | ||
684 | } | ||
685 | parse_expr(parser, PREC_LOW); | ||
686 | Node *value = array_pop(parser->nodes); | ||
687 | Node *sym = node_alloc(parser, NODE_SYMBOL, prev); | ||
688 | Node *op = node_alloc(parser, kind, prev); | ||
689 | op->binary.left = sym; | ||
690 | op->binary.right = value; | ||
691 | node->var.val = op; | ||
692 | sym->value = node->var.name->value; | ||
693 | sym->kind = node->var.name->kind; | ||
694 | } else { | ||
695 | parse_consume(parser, TOK_ASSIGN, | ||
696 | cstr("expected assignment on set expression")); | ||
697 | parse_expr(parser, PREC_LOW); | ||
698 | node->var.val = array_pop(parser->nodes); | ||
699 | } | ||
609 | } break; | 700 | } break; |
610 | case TOK_STRUCT: { | 701 | case TOK_STRUCT: { |
611 | node = node_alloc(parser, NODE_STRUCT, prev); | 702 | node = node_alloc(parser, NODE_STRUCT, prev); |
@@ -629,19 +720,19 @@ parse_keyword(Parser *parser) { | |||
629 | node = node_alloc(parser, NODE_IF, prev); | 720 | node = node_alloc(parser, NODE_IF, prev); |
630 | if (!node) return; | 721 | if (!node) return; |
631 | parse_expr(parser, PREC_LOW); | 722 | parse_expr(parser, PREC_LOW); |
632 | node->cond_if = array_pop(parser->nodes); | 723 | node->ifelse.cond = array_pop(parser->nodes); |
633 | parse_expr(parser, PREC_LOW); | 724 | parse_expr(parser, PREC_LOW); |
634 | node->cond_expr = array_pop(parser->nodes); | 725 | node->ifelse.expr_true = array_pop(parser->nodes); |
635 | if (parse_match(parser, TOK_ELSE)) { | 726 | if (parse_match(parser, TOK_ELSE)) { |
636 | parse_expr(parser, PREC_LOW); | 727 | parse_expr(parser, PREC_LOW); |
637 | node->cond_else = array_pop(parser->nodes); | 728 | node->ifelse.expr_else = array_pop(parser->nodes); |
638 | } | 729 | } |
639 | } break; | 730 | } break; |
640 | case TOK_MATCH: { | 731 | case TOK_MATCH: { |
641 | node = node_alloc(parser, NODE_MATCH, prev); | 732 | node = node_alloc(parser, NODE_MATCH, prev); |
642 | if (!node) return; | 733 | if (!node) return; |
643 | parse_expr(parser, PREC_LOW); | 734 | parse_expr(parser, PREC_LOW); |
644 | node->match_expr = array_pop(parser->nodes); | 735 | node->match.expr = array_pop(parser->nodes); |
645 | parse_consume(parser, TOK_LCURLY, | 736 | parse_consume(parser, TOK_LCURLY, |
646 | cstr("expected block of match cases")); | 737 | cstr("expected block of match cases")); |
647 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { | 738 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { |
@@ -653,13 +744,13 @@ parse_keyword(Parser *parser) { | |||
653 | parse_consume(parser, TOK_CASE, | 744 | parse_consume(parser, TOK_CASE, |
654 | cstr("expected case statement")); | 745 | cstr("expected case statement")); |
655 | parse_expr(parser, PREC_LOW); | 746 | parse_expr(parser, PREC_LOW); |
656 | tmp->case_value = array_pop(parser->nodes); | 747 | tmp->case_entry.cond = array_pop(parser->nodes); |
657 | } | 748 | } |
658 | parse_consume(parser, TOK_ASSIGN, | 749 | parse_consume(parser, TOK_ASSIGN, |
659 | cstr("malformed case statement")); | 750 | cstr("malformed case statement")); |
660 | parse_expr(parser, PREC_LOW); | 751 | parse_expr(parser, PREC_LOW); |
661 | tmp->case_expr = array_pop(parser->nodes); | 752 | tmp->case_entry.expr = array_pop(parser->nodes); |
662 | array_push(node->match_cases, tmp, parser->storage); | 753 | array_push(node->match.cases, tmp, parser->storage); |
663 | } | 754 | } |
664 | // TODO: Check that we only have literals on the match case, | 755 | // TODO: Check that we only have literals on the match case, |
665 | // this could be done on the analysis step, but also here... | 756 | // this could be done on the analysis step, but also here... |
@@ -683,7 +774,7 @@ parse_keyword(Parser *parser) { | |||
683 | field->value.sym = parser->previous.val; | 774 | field->value.sym = parser->previous.val; |
684 | if (parse_match(parser, TOK_ASSIGN)) { | 775 | if (parse_match(parser, TOK_ASSIGN)) { |
685 | parse_expr(parser, PREC_LOW); | 776 | parse_expr(parser, PREC_LOW); |
686 | field->field_val = array_pop(parser->nodes); | 777 | field->field.val = array_pop(parser->nodes); |
687 | } | 778 | } |
688 | array_push(node->struct_field, field, parser->storage); | 779 | array_push(node->struct_field, field, parser->storage); |
689 | } | 780 | } |
@@ -703,13 +794,13 @@ parse_keyword(Parser *parser) { | |||
703 | // Are we on the default case. | 794 | // Are we on the default case. |
704 | if (!parse_match(parser, TOK_ELSE)) { | 795 | if (!parse_match(parser, TOK_ELSE)) { |
705 | parse_expr(parser, PREC_LOW); | 796 | parse_expr(parser, PREC_LOW); |
706 | tmp->case_value = array_pop(parser->nodes); | 797 | tmp->case_entry.cond = array_pop(parser->nodes); |
707 | } | 798 | } |
708 | parse_consume(parser, TOK_ASSIGN, | 799 | parse_consume(parser, TOK_ASSIGN, |
709 | cstr("malformed case statement")); | 800 | cstr("malformed case statement")); |
710 | parse_expr(parser, PREC_LOW); | 801 | parse_expr(parser, PREC_LOW); |
711 | tmp->case_expr = array_pop(parser->nodes); | 802 | tmp->case_entry.expr = array_pop(parser->nodes); |
712 | array_push(node->match_cases, tmp, parser->storage); | 803 | array_push(node->match.cases, tmp, parser->storage); |
713 | } | 804 | } |
714 | } break; | 805 | } break; |
715 | case TOK_BREAK: { | 806 | case TOK_BREAK: { |
@@ -720,13 +811,47 @@ parse_keyword(Parser *parser) { | |||
720 | node = node_alloc(parser, NODE_CONTINUE, prev); | 811 | node = node_alloc(parser, NODE_CONTINUE, prev); |
721 | if (!node) return; | 812 | if (!node) return; |
722 | } break; | 813 | } break; |
814 | case TOK_FOR: { | ||
815 | node = node_alloc(parser, NODE_BLOCK, prev); | ||
816 | if (!node) return; | ||
817 | |||
818 | Node *node_while = node_alloc(parser, NODE_WHILE, prev); | ||
819 | if (!node_while) return; | ||
820 | Node *block = node_alloc(parser, NODE_BLOCK, prev); | ||
821 | if (!block) return; | ||
822 | |||
823 | parse_expr(parser, PREC_LOW); | ||
824 | Node *pre = array_pop(parser->nodes); | ||
825 | |||
826 | parse_expr(parser, PREC_LOW); | ||
827 | Node *cond = array_pop(parser->nodes); | ||
828 | |||
829 | parse_expr(parser, PREC_LOW); | ||
830 | Node *post = array_pop(parser->nodes); | ||
831 | |||
832 | // Body. | ||
833 | parse_consume(parser, TOK_LCURLY, | ||
834 | cstr("expected '{' on for loop statement")); | ||
835 | while (!parse_match(parser, TOK_RCURLY) && !parser->panic) { | ||
836 | parse_expr(parser, PREC_LOW); | ||
837 | Node *next = array_pop(parser->nodes); | ||
838 | array_push(block->statements, next, parser->storage); | ||
839 | } | ||
840 | array_push(block->statements, post, parser->storage); | ||
841 | |||
842 | // Put everything together | ||
843 | node_while->loop.cond = cond; | ||
844 | node_while->loop.expr = block; | ||
845 | array_push(node->statements, pre, parser->storage); | ||
846 | array_push(node->statements, node_while, parser->storage); | ||
847 | } break; | ||
723 | case TOK_WHILE: { | 848 | case TOK_WHILE: { |
724 | node = node_alloc(parser, NODE_WHILE, prev); | 849 | node = node_alloc(parser, NODE_WHILE, prev); |
725 | if (!node) return; | 850 | if (!node) return; |
726 | parse_expr(parser, PREC_LOW); | 851 | parse_expr(parser, PREC_LOW); |
727 | node->while_cond = array_pop(parser->nodes); | 852 | node->loop.cond = array_pop(parser->nodes); |
728 | parse_expr(parser, PREC_LOW); | 853 | parse_expr(parser, PREC_LOW); |
729 | node->while_expr = array_pop(parser->nodes); | 854 | node->loop.expr = array_pop(parser->nodes); |
730 | } break; | 855 | } break; |
731 | case TOK_FUN: { | 856 | case TOK_FUN: { |
732 | node = node_alloc(parser, NODE_FUN, prev); | 857 | node = node_alloc(parser, NODE_FUN, prev); |
@@ -735,7 +860,7 @@ parse_keyword(Parser *parser) { | |||
735 | Node *name = node_alloc(parser, NODE_SYMBOL, prev); | 860 | Node *name = node_alloc(parser, NODE_SYMBOL, prev); |
736 | if (!name) return; | 861 | if (!name) return; |
737 | name->value.sym = parser->previous.val; | 862 | name->value.sym = parser->previous.val; |
738 | node->func_name = name; | 863 | node->func.name = name; |
739 | parse_consume(parser, TOK_LPAREN, | 864 | parse_consume(parser, TOK_LPAREN, |
740 | cstr("expected '(' on function definition")); | 865 | cstr("expected '(' on function definition")); |
741 | // Parameters. | 866 | // Parameters. |
@@ -747,39 +872,41 @@ parse_keyword(Parser *parser) { | |||
747 | if (!name) return; | 872 | if (!name) return; |
748 | parse_consume(parser, TOK_SYMBOL, cstr("expected symbol name")); | 873 | parse_consume(parser, TOK_SYMBOL, cstr("expected symbol name")); |
749 | name->value.sym = parser->previous.val; | 874 | name->value.sym = parser->previous.val; |
750 | param->param_name = name; | 875 | param->param.name = name; |
751 | 876 | ||
752 | Node *type = node_alloc(parser, NODE_TYPE, prev); | 877 | Node *type = node_alloc(parser, NODE_TYPE, prev); |
753 | if (!type) return; | 878 | if (!type) return; |
754 | parse_consume(parser, TOK_COLON, cstr("expected param type")); | 879 | parse_consume(parser, TOK_COLON, cstr("expected param type")); |
755 | if (parse_match(parser, TOK_AT)) { | 880 | // TODO: reuse parse_type |
756 | type->is_ptr = true; | 881 | // if (parse_match(parser, TOK_AT)) { |
757 | } | 882 | // type->is_ptr = true; |
883 | // } | ||
758 | parse_consume(parser, TOK_SYMBOL, cstr("expected param type")); | 884 | parse_consume(parser, TOK_SYMBOL, cstr("expected param type")); |
759 | type->value.sym = parser->previous.val; | 885 | type->value.sym = parser->previous.val; |
760 | param->param_type = type; | 886 | param->param.type = type; |
761 | if (parse_match(parser, TOK_LSQUARE)) { | 887 | if (parse_match(parser, TOK_LSQUARE)) { |
762 | type->kind = NODE_ARR_TYPE, | 888 | type->kind = NODE_ARR_TYPE, |
763 | parse_consume(parser, TOK_NUM_INT, | 889 | parse_consume(parser, TOK_NUM_INT, |
764 | cstr("no array size given")); | 890 | cstr("no array size given")); |
765 | parse_number(parser); | 891 | parse_number(parser); |
766 | type->arr_size = array_pop(parser->nodes); | 892 | type->sym.arr_size = array_pop(parser->nodes); |
767 | parse_consume(parser, TOK_RSQUARE, | 893 | parse_consume(parser, TOK_RSQUARE, |
768 | cstr("unmatched brackets ']' in array type")); | 894 | cstr("unmatched brackets ']' in array type")); |
769 | } | 895 | } |
770 | array_push(node->func_params, param, parser->storage); | 896 | array_push(node->func.params, param, parser->storage); |
771 | } | 897 | } |
772 | parse_consume(parser, TOK_COLON, cstr("expected param type")); | ||
773 | 898 | ||
774 | // Return type(s). | 899 | // Return type(s). |
775 | if (!parse_match(parser, TOK_NIL)) { | 900 | if (parse_match(parser, TOK_COLON) && |
901 | !parse_match(parser, TOK_NIL)) { | ||
776 | if (parse_match(parser, TOK_LPAREN)) { | 902 | if (parse_match(parser, TOK_LPAREN)) { |
777 | while (!parse_match(parser, TOK_RPAREN) && !parser->panic) { | 903 | while (!parse_match(parser, TOK_RPAREN) && !parser->panic) { |
778 | Node *ret = node_alloc(parser, NODE_TYPE, prev); | 904 | Node *ret = node_alloc(parser, NODE_TYPE, prev); |
779 | if (!ret) return; | 905 | if (!ret) return; |
780 | if (parse_match(parser, TOK_AT)) { | 906 | // TODO: reuse parse_type |
781 | ret->is_ptr = true; | 907 | // if (parse_match(parser, TOK_AT)) { |
782 | } | 908 | // ret->is_ptr = true; |
909 | // } | ||
783 | parse_consume(parser, TOK_SYMBOL, | 910 | parse_consume(parser, TOK_SYMBOL, |
784 | cstr("expected type name")); | 911 | cstr("expected type name")); |
785 | ret->value.sym = parser->previous.val; | 912 | ret->value.sym = parser->previous.val; |
@@ -788,19 +915,20 @@ parse_keyword(Parser *parser) { | |||
788 | parse_consume(parser, TOK_NUM_INT, | 915 | parse_consume(parser, TOK_NUM_INT, |
789 | cstr("no array size given")); | 916 | cstr("no array size given")); |
790 | parse_number(parser); | 917 | parse_number(parser); |
791 | ret->arr_size = array_pop(parser->nodes); | 918 | ret->sym.arr_size = array_pop(parser->nodes); |
792 | parse_consume(parser, TOK_RSQUARE, | 919 | parse_consume(parser, TOK_RSQUARE, |
793 | cstr("unmatched brackets ']' in " | 920 | cstr("unmatched brackets ']' in " |
794 | "array type")); | 921 | "array type")); |
795 | } | 922 | } |
796 | array_push(node->func_ret, ret, parser->storage); | 923 | array_push(node->func.ret, ret, parser->storage); |
797 | } | 924 | } |
798 | } else { | 925 | } else { |
799 | Node *ret = node_alloc(parser, NODE_TYPE, prev); | 926 | Node *ret = node_alloc(parser, NODE_TYPE, prev); |
800 | if (!ret) return; | 927 | if (!ret) return; |
801 | if (parse_match(parser, TOK_AT)) { | 928 | // TODO: reuse parse_type |
802 | ret->is_ptr = true; | 929 | // if (parse_match(parser, TOK_AT)) { |
803 | } | 930 | // ret->is_ptr = true; |
931 | // } | ||
804 | parse_consume(parser, TOK_SYMBOL, | 932 | parse_consume(parser, TOK_SYMBOL, |
805 | cstr("expected type name")); | 933 | cstr("expected type name")); |
806 | ret->value.sym = parser->previous.val; | 934 | ret->value.sym = parser->previous.val; |
@@ -809,18 +937,18 @@ parse_keyword(Parser *parser) { | |||
809 | parse_consume(parser, TOK_NUM_INT, | 937 | parse_consume(parser, TOK_NUM_INT, |
810 | cstr("no array size given")); | 938 | cstr("no array size given")); |
811 | parse_number(parser); | 939 | parse_number(parser); |
812 | ret->arr_size = array_pop(parser->nodes); | 940 | ret->sym.arr_size = array_pop(parser->nodes); |
813 | parse_consume( | 941 | parse_consume( |
814 | parser, TOK_RSQUARE, | 942 | parser, TOK_RSQUARE, |
815 | cstr("unmatched brackets ']' in array type")); | 943 | cstr("unmatched brackets ']' in array type")); |
816 | } | 944 | } |
817 | array_push(node->func_ret, ret, parser->storage); | 945 | array_push(node->func.ret, ret, parser->storage); |
818 | } | 946 | } |
819 | } | 947 | } |
820 | 948 | ||
821 | // Body. | 949 | // Body. |
822 | parse_expr(parser, PREC_LOW); | 950 | parse_expr(parser, PREC_LOW); |
823 | node->func_body = array_pop(parser->nodes); | 951 | node->func.body = array_pop(parser->nodes); |
824 | } break; | 952 | } break; |
825 | case TOK_RETURN: { | 953 | case TOK_RETURN: { |
826 | node = node_alloc(parser, NODE_RETURN, prev); | 954 | node = node_alloc(parser, NODE_RETURN, prev); |
@@ -870,6 +998,9 @@ parse_binary(Parser *parser) { | |||
870 | case TOK_BITOR: { | 998 | case TOK_BITOR: { |
871 | node = node_alloc(parser, NODE_BITOR, prev); | 999 | node = node_alloc(parser, NODE_BITOR, prev); |
872 | } break; | 1000 | } break; |
1001 | case TOK_BITXOR: { | ||
1002 | node = node_alloc(parser, NODE_BITXOR, prev); | ||
1003 | } break; | ||
873 | case TOK_BITLSHIFT: { | 1004 | case TOK_BITLSHIFT: { |
874 | node = node_alloc(parser, NODE_BITLSHIFT, prev); | 1005 | node = node_alloc(parser, NODE_BITLSHIFT, prev); |
875 | } break; | 1006 | } break; |
@@ -882,8 +1013,8 @@ parse_binary(Parser *parser) { | |||
882 | } | 1013 | } |
883 | } | 1014 | } |
884 | if (!node) return; | 1015 | if (!node) return; |
885 | node->right = array_pop(parser->nodes); | 1016 | node->binary.right = array_pop(parser->nodes); |
886 | node->left = array_pop(parser->nodes); | 1017 | node->binary.left = array_pop(parser->nodes); |
887 | array_push(parser->nodes, node, parser->storage); | 1018 | array_push(parser->nodes, node, parser->storage); |
888 | } | 1019 | } |
889 | 1020 | ||
@@ -947,25 +1078,26 @@ parse_symbol(Parser *parser) { | |||
947 | print("parsing symbol "); | 1078 | print("parsing symbol "); |
948 | print_token(prev); | 1079 | print_token(prev); |
949 | #endif | 1080 | #endif |
1081 | // TODO: dereference operators. | ||
950 | if (prev.kind == TOK_AT) { | 1082 | if (prev.kind == TOK_AT) { |
1083 | Node *node = node_alloc(parser, NODE_PTR, parser->previous); | ||
1084 | if (!node) return; | ||
951 | parse_consume(parser, TOK_SYMBOL, | 1085 | parse_consume(parser, TOK_SYMBOL, |
952 | cstr("expected symbol after '.' operator")); | 1086 | cstr("expected symbol after '@' operator")); |
953 | parse_symbol(parser); | 1087 | parse_symbol(parser); |
954 | Node *node = array_pop(parser->nodes); | 1088 | node->t.next = array_pop(parser->nodes); |
955 | if (node) { | 1089 | array_push(parser->nodes, node, parser->storage); |
956 | node->is_ptr = true; | ||
957 | array_push(parser->nodes, node, parser->storage); | ||
958 | } | ||
959 | return; | 1090 | return; |
960 | } | 1091 | } |
961 | Node *node = node_alloc(parser, NODE_SYMBOL, prev); | 1092 | Node *node = node_alloc(parser, NODE_SYMBOL, prev); |
962 | if (!node) return; | 1093 | if (!node) return; |
1094 | node->value.sym = prev.val; | ||
963 | if (parse_match(parser, TOK_DOT)) { | 1095 | if (parse_match(parser, TOK_DOT)) { |
964 | // Symbol chain. | 1096 | // Symbol chain. |
965 | parse_consume(parser, TOK_SYMBOL, | 1097 | parse_consume(parser, TOK_SYMBOL, |
966 | cstr("expected symbol after '.' operator")); | 1098 | cstr("expected symbol after '.' operator")); |
967 | parse_symbol(parser); | 1099 | parse_symbol(parser); |
968 | node->next = array_pop(parser->nodes); | 1100 | node->sym.next = array_pop(parser->nodes); |
969 | } else if (parser->current.kind == TOK_COLON && | 1101 | } else if (parser->current.kind == TOK_COLON && |
970 | parse_peek(parser) == TOK_LCURLY) { | 1102 | parse_peek(parser) == TOK_LCURLY) { |
971 | parse_advance(parser); | 1103 | parse_advance(parser); |
@@ -979,9 +1111,10 @@ parse_symbol(Parser *parser) { | |||
979 | array_push(node->elements, field, parser->storage); | 1111 | array_push(node->elements, field, parser->storage); |
980 | } | 1112 | } |
981 | } else if (parse_match(parser, TOK_LSQUARE)) { | 1113 | } else if (parse_match(parser, TOK_LSQUARE)) { |
1114 | // FIXME: desugar into deref | ||
982 | node->kind = NODE_SYMBOL_IDX; | 1115 | node->kind = NODE_SYMBOL_IDX; |
983 | parse_expr(parser, PREC_LOW); | 1116 | parse_expr(parser, PREC_LOW); |
984 | node->arr_size = array_pop(parser->nodes); | 1117 | node->sym.arr_size = array_pop(parser->nodes); |
985 | parse_consume(parser, TOK_RSQUARE, | 1118 | parse_consume(parser, TOK_RSQUARE, |
986 | cstr("unmatched brackets ']' in array type")); | 1119 | cstr("unmatched brackets ']' in array type")); |
987 | if (parse_match(parser, TOK_DOT)) { | 1120 | if (parse_match(parser, TOK_DOT)) { |
@@ -989,7 +1122,7 @@ parse_symbol(Parser *parser) { | |||
989 | parse_consume(parser, TOK_SYMBOL, | 1122 | parse_consume(parser, TOK_SYMBOL, |
990 | cstr("expected symbol after '.' operator")); | 1123 | cstr("expected symbol after '.' operator")); |
991 | parse_symbol(parser); | 1124 | parse_symbol(parser); |
992 | node->next = array_pop(parser->nodes); | 1125 | node->sym.next = array_pop(parser->nodes); |
993 | } | 1126 | } |
994 | } else if (parse_match(parser, TOK_LPAREN)) { | 1127 | } else if (parse_match(parser, TOK_LPAREN)) { |
995 | node->kind = NODE_FUNCALL; | 1128 | node->kind = NODE_FUNCALL; |
@@ -1003,10 +1136,20 @@ parse_symbol(Parser *parser) { | |||
1003 | parse_consume(parser, TOK_SYMBOL, | 1136 | parse_consume(parser, TOK_SYMBOL, |
1004 | cstr("expected symbol after '.' operator")); | 1137 | cstr("expected symbol after '.' operator")); |
1005 | parse_symbol(parser); | 1138 | parse_symbol(parser); |
1006 | node->next = array_pop(parser->nodes); | 1139 | node->sym.next = array_pop(parser->nodes); |
1140 | } | ||
1141 | } else if (parse_match(parser, TOK_AT)) { | ||
1142 | Node *deref = node_alloc(parser, NODE_DEREF, prev); | ||
1143 | Node *start = deref; | ||
1144 | while (parse_match(parser, TOK_AT)) { | ||
1145 | Node *next = node_alloc(parser, NODE_DEREF, prev); | ||
1146 | deref->deref.next = next; | ||
1147 | deref = next; | ||
1007 | } | 1148 | } |
1149 | deref->deref.next = node; | ||
1150 | array_push(parser->nodes, start, parser->storage); | ||
1151 | return; | ||
1008 | } | 1152 | } |
1009 | node->value.sym = prev.val; | ||
1010 | array_push(parser->nodes, node, parser->storage); | 1153 | array_push(parser->nodes, node, parser->storage); |
1011 | } | 1154 | } |
1012 | 1155 | ||
@@ -1040,54 +1183,53 @@ graph_node(Node *node) { | |||
1040 | case NODE_ARR_TYPE: | 1183 | case NODE_ARR_TYPE: |
1041 | case NODE_FIELD: | 1184 | case NODE_FIELD: |
1042 | case NODE_TYPE: { | 1185 | case NODE_TYPE: { |
1043 | if (node->is_ptr) { | 1186 | print("| Name: %s", node->value.sym); |
1044 | print("| Name: @%s", node->value.sym); | ||
1045 | } else { | ||
1046 | print("| Name: %s", node->value.sym); | ||
1047 | } | ||
1048 | } break; | 1187 | } break; |
1049 | default: break; | 1188 | default: break; |
1050 | } | 1189 | } |
1190 | if (node->unique_name.size > 0) { | ||
1191 | print("| Unique Name: %s", node->unique_name); | ||
1192 | } | ||
1051 | if (node->type.size > 0) { | 1193 | if (node->type.size > 0) { |
1052 | print("| Type: %s", node->type); | 1194 | print("| Type: %s", node->type); |
1053 | } | 1195 | } |
1054 | if (node->fun_params.size > 0) { | 1196 | if (node->type_params.size > 0) { |
1055 | print("| Params: %s", node->fun_params); | 1197 | print("| Params: %s", node->type_params); |
1056 | } | 1198 | } |
1057 | if (node->fun_return.size > 0) { | 1199 | if (node->type_returns.size > 0) { |
1058 | print("| Return: %s", node->fun_return); | 1200 | print("| Return: %s", node->type_returns); |
1059 | } | 1201 | } |
1060 | println("\"];"); | 1202 | println("\"];"); |
1061 | 1203 | ||
1062 | switch (node->kind) { | 1204 | switch (node->kind) { |
1063 | case NODE_FUN: { | 1205 | case NODE_FUN: { |
1064 | for (sz i = 0; i < array_size(node->func_params); i++) { | 1206 | for (sz i = 0; i < array_size(node->func.params); i++) { |
1065 | Node *next = node->func_params[i]; | 1207 | Node *next = node->func.params[i]; |
1066 | println("%d:e->%d:w;", node->id, next->id); | 1208 | println("%d:e->%d:w;", node->id, next->id); |
1067 | graph_node(next); | 1209 | graph_node(next); |
1068 | } | 1210 | } |
1069 | for (sz i = 0; i < array_size(node->func_ret); i++) { | 1211 | for (sz i = 0; i < array_size(node->func.ret); i++) { |
1070 | Node *next = node->func_ret[i]; | 1212 | Node *next = node->func.ret[i]; |
1071 | println("%d:e->%d:w;", node->id, next->id); | 1213 | println("%d:e->%d:w;", node->id, next->id); |
1072 | graph_node(next); | 1214 | graph_node(next); |
1073 | } | 1215 | } |
1074 | if (node->func_name) { | 1216 | if (node->func.name) { |
1075 | println("%d:e->%d:w;", node->id, node->func_name->id); | 1217 | println("%d:e->%d:w;", node->id, node->func.name->id); |
1076 | graph_node(node->func_name); | 1218 | graph_node(node->func.name); |
1077 | } | 1219 | } |
1078 | if (node->func_body) { | 1220 | if (node->func.body) { |
1079 | println("%d:e->%d:w;", node->id, node->func_body->id); | 1221 | println("%d:e->%d:w;", node->id, node->func.body->id); |
1080 | graph_node(node->func_body); | 1222 | graph_node(node->func.body); |
1081 | } | 1223 | } |
1082 | } break; | 1224 | } break; |
1083 | case NODE_COND: | 1225 | case NODE_COND: |
1084 | case NODE_MATCH: { | 1226 | case NODE_MATCH: { |
1085 | if (node->match_expr) { | 1227 | if (node->match.expr) { |
1086 | println("%d:e->%d:w;", node->id, node->match_expr->id); | 1228 | println("%d:e->%d:w;", node->id, node->match.expr->id); |
1087 | graph_node(node->match_expr); | 1229 | graph_node(node->match.expr); |
1088 | } | 1230 | } |
1089 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 1231 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
1090 | Node *next = node->match_cases[i]; | 1232 | Node *next = node->match.cases[i]; |
1091 | println("%d:e->%d:w;", node->id, next->id); | 1233 | println("%d:e->%d:w;", node->id, next->id); |
1092 | graph_node(next); | 1234 | graph_node(next); |
1093 | } | 1235 | } |
@@ -1112,43 +1254,43 @@ graph_node(Node *node) { | |||
1112 | } | 1254 | } |
1113 | } break; | 1255 | } break; |
1114 | case NODE_IF: { | 1256 | case NODE_IF: { |
1115 | if (node->cond_if) { | 1257 | if (node->ifelse.cond) { |
1116 | println("%d:e->%d:w;", node->id, node->cond_if->id); | 1258 | println("%d:e->%d:w;", node->id, node->ifelse.cond->id); |
1117 | graph_node(node->cond_if); | 1259 | graph_node(node->ifelse.cond); |
1118 | } | 1260 | } |
1119 | if (node->cond_expr) { | 1261 | if (node->ifelse.expr_true) { |
1120 | println("%d:e->%d:w;", node->id, node->cond_expr->id); | 1262 | println("%d:e->%d:w;", node->id, node->ifelse.expr_true->id); |
1121 | graph_node(node->cond_expr); | 1263 | graph_node(node->ifelse.expr_true); |
1122 | } | 1264 | } |
1123 | if (node->cond_else) { | 1265 | if (node->ifelse.expr_else) { |
1124 | println("%d:e->%d:w;", node->id, node->cond_else->id); | 1266 | println("%d:e->%d:w;", node->id, node->ifelse.expr_else->id); |
1125 | graph_node(node->cond_else); | 1267 | graph_node(node->ifelse.expr_else); |
1126 | } | 1268 | } |
1127 | } break; | 1269 | } break; |
1128 | case NODE_FIELD: | 1270 | case NODE_FIELD: |
1129 | case NODE_SET: | 1271 | case NODE_SET: |
1130 | case NODE_LET: { | 1272 | case NODE_LET: { |
1131 | if (node->var_name) { | 1273 | if (node->var.name) { |
1132 | println("%d:e->%d:w;", node->id, node->var_name->id); | 1274 | println("%d:e->%d:w;", node->id, node->var.name->id); |
1133 | graph_node(node->var_name); | 1275 | graph_node(node->var.name); |
1134 | } | 1276 | } |
1135 | if (node->var_type) { | 1277 | if (node->var.type) { |
1136 | println("%d:e->%d:w;", node->id, node->var_type->id); | 1278 | println("%d:e->%d:w;", node->id, node->var.type->id); |
1137 | graph_node(node->var_type); | 1279 | graph_node(node->var.type); |
1138 | } | 1280 | } |
1139 | if (node->var_val) { | 1281 | if (node->var.val) { |
1140 | println("%d:e->%d:w;", node->id, node->var_val->id); | 1282 | println("%d:e->%d:w;", node->id, node->var.val->id); |
1141 | graph_node(node->var_val); | 1283 | graph_node(node->var.val); |
1142 | } | 1284 | } |
1143 | } break; | 1285 | } break; |
1144 | default: { | 1286 | default: { |
1145 | if (node->left) { | 1287 | if (node->binary.left) { |
1146 | println("%d:e->%d:w;", node->id, node->left->id); | 1288 | println("%d:e->%d:w;", node->id, node->binary.left->id); |
1147 | graph_node(node->left); | 1289 | graph_node(node->binary.left); |
1148 | } | 1290 | } |
1149 | if (node->right) { | 1291 | if (node->binary.right) { |
1150 | println("%d:e->%d:w;", node->id, node->right->id); | 1292 | println("%d:e->%d:w;", node->id, node->binary.right->id); |
1151 | graph_node(node->right); | 1293 | graph_node(node->binary.right); |
1152 | } | 1294 | } |
1153 | } break; | 1295 | } break; |
1154 | } | 1296 | } |
diff --git a/src/semantic.c b/src/semantic.c index a0231d5..cebf17a 100644 --- a/src/semantic.c +++ b/src/semantic.c | |||
@@ -39,6 +39,8 @@ 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; | ||
42 | } Fun; | 44 | } Fun; |
43 | 45 | ||
44 | typedef struct Enum { | 46 | typedef struct Enum { |
@@ -62,6 +64,7 @@ typedef struct Scope { | |||
62 | sz depth; | 64 | sz depth; |
63 | Str name; | 65 | Str name; |
64 | SymbolMap *symbols; | 66 | SymbolMap *symbols; |
67 | StrSet *types; | ||
65 | FunMap *funcs; | 68 | FunMap *funcs; |
66 | EnumMap *enums; | 69 | EnumMap *enums; |
67 | StructMap *structs; | 70 | StructMap *structs; |
@@ -75,6 +78,7 @@ typedef struct Analyzer { | |||
75 | Scope **scopes; | 78 | Scope **scopes; |
76 | StrSet *numeric_types; | 79 | StrSet *numeric_types; |
77 | StrSet *integer_types; | 80 | StrSet *integer_types; |
81 | StrSet *float_types; | ||
78 | bool err; | 82 | bool err; |
79 | } Analyzer; | 83 | } Analyzer; |
80 | 84 | ||
@@ -82,16 +86,19 @@ Scope * | |||
82 | typescope_alloc(Analyzer *a, Scope *parent) { | 86 | typescope_alloc(Analyzer *a, Scope *parent) { |
83 | Scope *scope = arena_calloc(sizeof(Scope), a->storage); | 87 | Scope *scope = arena_calloc(sizeof(Scope), a->storage); |
84 | scope->parent = parent; | 88 | scope->parent = parent; |
89 | if (parent != NULL) { | ||
90 | scope->name = parent->name; | ||
91 | } | ||
85 | scope->id = a->typescope_gen++; | 92 | scope->id = a->typescope_gen++; |
86 | scope->depth = parent == NULL ? 0 : parent->depth + 1; | 93 | scope->depth = parent == NULL ? 0 : parent->depth + 1; |
87 | array_push(a->scopes, scope, a->storage); | 94 | array_push(a->scopes, scope, a->storage); |
88 | return scope; | 95 | return scope; |
89 | } | 96 | } |
90 | 97 | ||
91 | SymbolMap * | 98 | StrSet * |
92 | find_type(Scope *scope, Str type) { | 99 | find_type(Scope *scope, Str type) { |
93 | while (scope != NULL) { | 100 | while (scope != NULL) { |
94 | SymbolMap *val = symmap_lookup(&scope->symbols, type); | 101 | StrSet *val = strset_lookup(&scope->types, type); |
95 | if (val != NULL) { | 102 | if (val != NULL) { |
96 | return val; | 103 | return val; |
97 | } | 104 | } |
@@ -276,7 +283,7 @@ Str type_inference(Analyzer *a, Node *node, Scope *scope); | |||
276 | 283 | ||
277 | void | 284 | void |
278 | typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | 285 | typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { |
279 | if (node->field_type->kind == NODE_COMPOUND_TYPE) { | 286 | if (node->field.type->kind == NODE_COMPOUND_TYPE) { |
280 | Str field_name = str_concat(symbol, cstr("."), a->storage); | 287 | Str field_name = str_concat(symbol, cstr("."), a->storage); |
281 | field_name = str_concat(field_name, node->value.str, a->storage); | 288 | field_name = str_concat(field_name, node->value.str, a->storage); |
282 | if (structmap_lookup(&scope->structs, field_name)) { | 289 | if (structmap_lookup(&scope->structs, field_name)) { |
@@ -285,8 +292,8 @@ typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | |||
285 | a->err = true; | 292 | a->err = true; |
286 | } | 293 | } |
287 | Str type = cstr("\\{ "); | 294 | Str type = cstr("\\{ "); |
288 | for (sz i = 0; i < array_size(node->field_type->elements); i++) { | 295 | for (sz i = 0; i < array_size(node->field.type->elements); i++) { |
289 | Node *field = node->field_type->elements[i]; | 296 | Node *field = node->field.type->elements[i]; |
290 | typecheck_field(a, field, scope, field_name); | 297 | typecheck_field(a, field, scope, field_name); |
291 | type = str_concat(type, field->type, a->storage); | 298 | type = str_concat(type, field->type, a->storage); |
292 | type = str_concat(type, cstr(" "), a->storage); | 299 | type = str_concat(type, cstr(" "), a->storage); |
@@ -296,16 +303,13 @@ typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | |||
296 | } else { | 303 | } else { |
297 | Str field_name = str_concat(symbol, cstr("."), a->storage); | 304 | Str field_name = str_concat(symbol, cstr("."), a->storage); |
298 | field_name = str_concat(field_name, node->value.str, a->storage); | 305 | field_name = str_concat(field_name, node->value.str, a->storage); |
299 | Str field_type = node->field_type->value.str; | 306 | Str field_type = node->field.type->value.str; |
300 | if (!find_type(scope, field_type)) { | 307 | if (!find_type(scope, field_type)) { |
301 | eprintln("%s:%d:%d: error: unknown type '%s'", a->file_name, | 308 | eprintln("%s:%d:%d: error: unknown type '%s'", a->file_name, |
302 | node->field_type->line, node->field_type->col, field_type); | 309 | node->field.type->line, node->field.type->col, field_type); |
303 | a->err = true; | 310 | a->err = true; |
304 | } | 311 | } |
305 | if (node->field_type->is_ptr) { | 312 | if (node->field.type->kind == NODE_ARR_TYPE) { |
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); | 313 | field_type = str_concat(cstr("@"), field_type, a->storage); |
310 | } | 314 | } |
311 | if (structmap_lookup(&scope->structs, field_name)) { | 315 | if (structmap_lookup(&scope->structs, field_name)) { |
@@ -313,8 +317,8 @@ typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | |||
313 | a->file_name, node->line, node->col, field_name); | 317 | a->file_name, node->line, node->col, field_name); |
314 | a->err = true; | 318 | a->err = true; |
315 | } | 319 | } |
316 | if (node->field_val) { | 320 | if (node->field.val) { |
317 | Str type = type_inference(a, node->field_val, scope); | 321 | Str type = type_inference(a, node->field.val, scope); |
318 | if (!str_eq(type, field_type)) { | 322 | if (!str_eq(type, field_type)) { |
319 | eprintln( | 323 | eprintln( |
320 | "%s:%d:%d: error: mismatched types in struct " | 324 | "%s:%d:%d: error: mismatched types in struct " |
@@ -329,7 +333,7 @@ typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | |||
329 | (Struct){ | 333 | (Struct){ |
330 | .name = field_name, | 334 | .name = field_name, |
331 | .type = field_type, | 335 | .type = field_type, |
332 | .val = node->field_val, | 336 | .val = node->field.val, |
333 | }, | 337 | }, |
334 | a->storage); | 338 | a->storage); |
335 | symmap_insert(&scope->symbols, field_name, | 339 | symmap_insert(&scope->symbols, field_name, |
@@ -341,10 +345,10 @@ typecheck_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | |||
341 | 345 | ||
342 | void | 346 | void |
343 | typecheck_lit_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | 347 | typecheck_lit_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { |
344 | if (node->field_val->kind == NODE_COMPOUND_TYPE) { | 348 | if (node->field.val->kind == NODE_COMPOUND_TYPE) { |
345 | Str type = cstr("\\{ "); | 349 | Str type = cstr("\\{ "); |
346 | for (sz i = 0; i < array_size(node->field_val->elements); i++) { | 350 | for (sz i = 0; i < array_size(node->field.val->elements); i++) { |
347 | Node *field = node->field_val->elements[i]; | 351 | Node *field = node->field.val->elements[i]; |
348 | Str field_name = str_concat(symbol, cstr("."), a->storage); | 352 | Str field_name = str_concat(symbol, cstr("."), a->storage); |
349 | field_name = str_concat(field_name, field->value.str, a->storage); | 353 | field_name = str_concat(field_name, field->value.str, a->storage); |
350 | typecheck_lit_field(a, field, scope, field_name); | 354 | typecheck_lit_field(a, field, scope, field_name); |
@@ -362,7 +366,7 @@ typecheck_lit_field(Analyzer *a, Node *node, Scope *scope, Str symbol) { | |||
362 | return; | 366 | return; |
363 | } | 367 | } |
364 | Str field_type = s->val.type; | 368 | Str field_type = s->val.type; |
365 | Str type = type_inference(a, node->field_val, scope); | 369 | Str type = type_inference(a, node->field.val, scope); |
366 | if (!str_eq(type, field_type)) { | 370 | if (!str_eq(type, field_type)) { |
367 | eprintln( | 371 | eprintln( |
368 | "%s:%d:%d: error: mismatched types in struct " | 372 | "%s:%d:%d: error: mismatched types in struct " |
@@ -384,17 +388,18 @@ typecheck_returns(Analyzer *a, Node *node, Str expected) { | |||
384 | switch (node->kind) { | 388 | switch (node->kind) { |
385 | case NODE_COND: | 389 | case NODE_COND: |
386 | case NODE_MATCH: { | 390 | case NODE_MATCH: { |
387 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 391 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
388 | Node *next = node->match_cases[i]; | 392 | Node *next = node->match.cases[i]; |
389 | typecheck_returns(a, next, expected); | 393 | typecheck_returns(a, next, expected); |
390 | } | 394 | } |
391 | } break; | 395 | } break; |
392 | case NODE_RETURN: { | 396 | case NODE_RETURN: { |
393 | bool err = !str_eq(node->type, expected); | 397 | Str type = str_remove_prefix(node->type, cstr("ret:")); |
398 | bool err = !str_eq(type, expected); | ||
394 | if (err) { | 399 | if (err) { |
395 | eprintln( | 400 | eprintln( |
396 | "%s:%d:%d: error: mismatched return type %s, expected %s", | 401 | "%s:%d:%d: error: mismatched return type %s, expected %s", |
397 | a->file_name, node->line, node->col, node->type, expected); | 402 | a->file_name, node->line, node->col, type, expected); |
398 | a->err = true; | 403 | a->err = true; |
399 | } | 404 | } |
400 | } break; | 405 | } break; |
@@ -405,17 +410,17 @@ typecheck_returns(Analyzer *a, Node *node, Str expected) { | |||
405 | } | 410 | } |
406 | } break; | 411 | } break; |
407 | case NODE_IF: { | 412 | case NODE_IF: { |
408 | if (node->cond_expr) { | 413 | if (node->ifelse.expr_true) { |
409 | typecheck_returns(a, node->cond_expr, expected); | 414 | typecheck_returns(a, node->ifelse.expr_true, expected); |
410 | } | 415 | } |
411 | if (node->cond_else) { | 416 | if (node->ifelse.expr_else) { |
412 | typecheck_returns(a, node->cond_else, expected); | 417 | typecheck_returns(a, node->ifelse.expr_else, expected); |
413 | } | 418 | } |
414 | } break; | 419 | } break; |
415 | case NODE_SET: | 420 | case NODE_SET: |
416 | case NODE_LET: { | 421 | case NODE_LET: { |
417 | if (node->var_val) { | 422 | if (node->var.val) { |
418 | typecheck_returns(a, node->var_val, expected); | 423 | typecheck_returns(a, node->var.val, expected); |
419 | } | 424 | } |
420 | } break; | 425 | } break; |
421 | case NODE_ADD: | 426 | case NODE_ADD: |
@@ -435,13 +440,14 @@ typecheck_returns(Analyzer *a, Node *node, Str expected) { | |||
435 | case NODE_BITNOT: | 440 | case NODE_BITNOT: |
436 | case NODE_BITAND: | 441 | case NODE_BITAND: |
437 | case NODE_BITOR: | 442 | case NODE_BITOR: |
443 | case NODE_BITXOR: | ||
438 | case NODE_BITLSHIFT: | 444 | case NODE_BITLSHIFT: |
439 | case NODE_BITRSHIFT: { | 445 | case NODE_BITRSHIFT: { |
440 | if (node->left) { | 446 | if (node->binary.left) { |
441 | typecheck_returns(a, node->left, expected); | 447 | typecheck_returns(a, node->binary.left, expected); |
442 | } | 448 | } |
443 | if (node->right) { | 449 | if (node->binary.right) { |
444 | typecheck_returns(a, node->right, expected); | 450 | typecheck_returns(a, node->binary.right, expected); |
445 | } | 451 | } |
446 | } break; | 452 | } break; |
447 | default: break; | 453 | default: break; |
@@ -452,66 +458,56 @@ Str | |||
452 | type_inference(Analyzer *a, Node *node, Scope *scope) { | 458 | type_inference(Analyzer *a, Node *node, Scope *scope) { |
453 | assert(a); | 459 | assert(a); |
454 | assert(scope); | 460 | assert(scope); |
455 | if (!node) { | 461 | if (!node || a->err) { |
456 | return cstr(""); | 462 | return cstr(""); |
457 | } | 463 | } |
458 | // NOTE: For now we are not going to do implicit numeric conversions. | ||
459 | switch (node->kind) { | 464 | switch (node->kind) { |
460 | case NODE_LET: { | 465 | case NODE_LET: { |
461 | node->type = cstr("nil"); | 466 | node->type = cstr("nil"); |
462 | Str symbol = node->var_name->value.str; | 467 | node->var.name->parent = node; |
468 | Str symbol = node->var.name->value.str; | ||
463 | if (symmap_lookup(&scope->symbols, symbol)) { | 469 | if (symmap_lookup(&scope->symbols, symbol)) { |
464 | eprintln( | 470 | eprintln( |
465 | "%s:%d:%d: error: symbol '%s' already exists in current " | 471 | "%s:%d:%d: error: symbol '%s' already exists in current " |
466 | "scope ", | 472 | "scope ", |
467 | a->file_name, node->var_name->line, node->var_name->col, | 473 | a->file_name, node->var.name->line, node->var.name->col, |
468 | symbol); | 474 | symbol); |
469 | a->err = true; | 475 | a->err = true; |
470 | return cstr(""); | 476 | return cstr(""); |
471 | } | 477 | } |
472 | if (node->var_type) { | 478 | if (node->var.type) { |
473 | Str type_name = node->var_type->value.str; | 479 | node->var.type->parent = node; |
474 | SymbolMap *type = find_type(scope, type_name); | 480 | Str type_name = type_inference(a, node->var.type, scope); |
475 | if (type == NULL) { | 481 | if (node->var.val) { |
476 | eprintln("%s:%d:%d: error: unknown type '%s'", a->file_name, | 482 | node->var.val->parent = node; |
477 | node->var_type->line, node->var_type->col, | 483 | Str type = type_inference(a, node->var.val, scope); |
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) { | 484 | if (!type.size) { |
493 | eprintln( | 485 | eprintln( |
494 | "%s:%d:%d: error: can't bind `nil` to variable " | 486 | "%s:%d:%d: error: can't bind `nil` to variable " |
495 | "'%s'", | 487 | "'%s'", |
496 | a->file_name, node->var_type->line, | 488 | a->file_name, node->var.type->line, |
497 | node->var_type->col, symbol); | 489 | node->var.type->col, symbol); |
498 | a->err = true; | 490 | a->err = true; |
499 | return cstr(""); | 491 | return cstr(""); |
500 | } | 492 | } |
501 | // TODO: Consider compatible types. | ||
502 | if (!str_eq(type, type_name)) { | 493 | if (!str_eq(type, type_name)) { |
503 | // Special case, enums can be treated as ints. | 494 | if (!(strset_lookup(&a->integer_types, type) && |
504 | FindEnumResult res = find_enum(scope, type_name); | 495 | strset_lookup(&a->integer_types, type_name)) || |
505 | if (!(res.map && str_eq(type, cstr("int")))) { | 496 | !(strset_lookup(&a->numeric_types, type) && |
506 | eprintln( | 497 | strset_lookup(&a->numeric_types, type_name))) { |
507 | "%s:%d:%d: error: type mismatch, trying to " | 498 | // Special case, enums can be treated as ints. |
508 | "assing " | 499 | FindEnumResult res = find_enum(scope, type_name); |
509 | "%s" | 500 | if (!(res.map && str_eq(type, cstr("Int")))) { |
510 | " to a variable of type %s", | 501 | eprintln( |
511 | a->file_name, node->var_type->line, | 502 | "%s:%d:%d: error: type mismatch, trying to " |
512 | node->var_type->col, type, type_name); | 503 | "assing " |
513 | a->err = true; | 504 | "%s" |
514 | return cstr(""); | 505 | " to a variable of type %s", |
506 | a->file_name, node->var.type->line, | ||
507 | node->var.type->col, type, type_name); | ||
508 | a->err = true; | ||
509 | return cstr(""); | ||
510 | } | ||
515 | } | 511 | } |
516 | } | 512 | } |
517 | } | 513 | } |
@@ -521,7 +517,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
521 | .kind = SYM_VAR, | 517 | .kind = SYM_VAR, |
522 | }, | 518 | }, |
523 | a->storage); | 519 | a->storage); |
524 | node->var_name->type = type_name; | 520 | node->var.name->type = type_name; |
525 | symbol = str_concat(cstr("."), symbol, a->storage); | 521 | symbol = str_concat(cstr("."), symbol, a->storage); |
526 | symbol = str_concat(symbol, str_from_int(scope->id, a->storage), | 522 | symbol = str_concat(symbol, str_from_int(scope->id, a->storage), |
527 | a->storage); | 523 | a->storage); |
@@ -530,13 +526,20 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
530 | } | 526 | } |
531 | 527 | ||
532 | // We don't know the type for this symbol, perform inference. | 528 | // We don't know the type for this symbol, perform inference. |
533 | Str type = type_inference(a, node->var_val, scope); | 529 | node->var.val->parent = node; |
534 | if (type.size) { | 530 | Str type = type_inference(a, node->var.val, scope); |
535 | symmap_insert(&scope->symbols, symbol, | 531 | if (!type.size || str_eq(type, cstr("nil")) || |
536 | (Symbol){.name = type, .kind = SYM_VAR}, | 532 | str_has_prefix(type, cstr("ret:"))) { |
537 | a->storage); | 533 | eprintln( |
538 | node->var_name->type = type; | 534 | "%s:%d:%d: error: can't bind `nil` to variable " |
535 | "'%s'", | ||
536 | a->file_name, node->line, node->col, symbol); | ||
537 | a->err = true; | ||
538 | return cstr(""); | ||
539 | } | 539 | } |
540 | symmap_insert(&scope->symbols, symbol, | ||
541 | (Symbol){.name = type, .kind = SYM_VAR}, a->storage); | ||
542 | node->var.name->type = type; | ||
540 | symbol = str_concat(cstr("."), symbol, a->storage); | 543 | symbol = str_concat(cstr("."), symbol, a->storage); |
541 | symbol = str_concat(symbol, str_from_int(scope->id, a->storage), | 544 | symbol = str_concat(symbol, str_from_int(scope->id, a->storage), |
542 | a->storage); | 545 | a->storage); |
@@ -544,18 +547,31 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
544 | return node->type; | 547 | return node->type; |
545 | } break; | 548 | } break; |
546 | case NODE_SET: { | 549 | case NODE_SET: { |
547 | Str name = type_inference(a, node->var_name, scope); | 550 | node->var.name->parent = node; |
548 | Str val = type_inference(a, node->var_val, scope); | 551 | node->var.val->parent = node; |
552 | Str name = type_inference(a, node->var.name, scope); | ||
553 | Str val = type_inference(a, node->var.val, scope); | ||
554 | if (str_has_prefix(name, cstr("@"))) { | ||
555 | name = cstr("Ptr"); | ||
556 | } | ||
557 | if (str_has_prefix(val, cstr("@"))) { | ||
558 | val = cstr("Ptr"); | ||
559 | } | ||
549 | if (!str_eq(name, val)) { | 560 | if (!str_eq(name, val)) { |
550 | eprintln( | 561 | if (!(strset_lookup(&a->integer_types, name) && |
551 | "%s:%d:%d: error: type mismatch, trying to assing " | 562 | strset_lookup(&a->integer_types, val)) || |
552 | "%s" | 563 | !(strset_lookup(&a->numeric_types, name) && |
553 | " to a variable of type %s", | 564 | strset_lookup(&a->numeric_types, val))) { |
554 | a->file_name, node->line, node->col, val, name); | 565 | eprintln( |
555 | a->err = true; | 566 | "%s:%d:%d: error: type mismatch, trying to assing " |
556 | return cstr(""); | 567 | "%s" |
568 | " to a variable of type %s", | ||
569 | a->file_name, node->line, node->col, val, name); | ||
570 | a->err = true; | ||
571 | return cstr(""); | ||
572 | } | ||
557 | } | 573 | } |
558 | Str symbol = node->var_name->value.str; | 574 | Str symbol = node->var.name->value.str; |
559 | FindSymbolResult sym = find_symbol(scope, symbol); | 575 | FindSymbolResult sym = find_symbol(scope, symbol); |
560 | node->unique_name = str_concat(cstr("."), symbol, a->storage); | 576 | node->unique_name = str_concat(cstr("."), symbol, a->storage); |
561 | node->unique_name = | 577 | node->unique_name = |
@@ -579,6 +595,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
579 | a->storage); | 595 | a->storage); |
580 | for (sz i = 0; i < array_size(node->struct_field); i++) { | 596 | for (sz i = 0; i < array_size(node->struct_field); i++) { |
581 | Node *field = node->struct_field[i]; | 597 | Node *field = node->struct_field[i]; |
598 | field->parent = node; | ||
582 | typecheck_field(a, field, scope, symbol); | 599 | typecheck_field(a, field, scope, symbol); |
583 | } | 600 | } |
584 | symmap_insert(&scope->symbols, symbol, | 601 | symmap_insert(&scope->symbols, symbol, |
@@ -600,11 +617,12 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
600 | enummap_insert(&scope->enums, symbol, | 617 | enummap_insert(&scope->enums, symbol, |
601 | (Enum){ | 618 | (Enum){ |
602 | .name = symbol, | 619 | .name = symbol, |
603 | .val = node->field_val, | 620 | .val = node->field.val, |
604 | }, | 621 | }, |
605 | a->storage); | 622 | a->storage); |
606 | for (sz i = 0; i < array_size(node->struct_field); i++) { | 623 | for (sz i = 0; i < array_size(node->struct_field); i++) { |
607 | Node *field = node->struct_field[i]; | 624 | Node *field = node->struct_field[i]; |
625 | field->parent = node; | ||
608 | Str field_name = str_concat(symbol, cstr("."), a->storage); | 626 | Str field_name = str_concat(symbol, cstr("."), a->storage); |
609 | field_name = | 627 | field_name = |
610 | str_concat(field_name, field->value.str, a->storage); | 628 | str_concat(field_name, field->value.str, a->storage); |
@@ -613,9 +631,9 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
613 | a->file_name, field->line, field->col, field_name); | 631 | a->file_name, field->line, field->col, field_name); |
614 | a->err = true; | 632 | a->err = true; |
615 | } | 633 | } |
616 | if (field->field_val) { | 634 | if (field->field.val) { |
617 | Str type = type_inference(a, field->field_val, scope); | 635 | Str type = type_inference(a, field->field.val, scope); |
618 | if (!str_eq(type, cstr("int"))) { | 636 | if (!str_eq(type, cstr("Int"))) { |
619 | eprintln( | 637 | eprintln( |
620 | "%s:%d:%d: error: non int enum value for '%s.%s'", | 638 | "%s:%d:%d: error: non int enum value for '%s.%s'", |
621 | a->file_name, field->line, field->col, symbol, | 639 | a->file_name, field->line, field->col, symbol, |
@@ -637,26 +655,34 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
637 | return node->type; | 655 | return node->type; |
638 | } break; | 656 | } break; |
639 | case NODE_IF: { | 657 | case NODE_IF: { |
640 | Str cond_type = type_inference(a, node->cond_if, scope); | 658 | node->ifelse.cond->parent = node; |
641 | if (!str_eq(cond_type, cstr("bool"))) { | 659 | node->ifelse.expr_true->parent = node; |
660 | Str cond_type = type_inference(a, node->ifelse.cond, scope); | ||
661 | if (!str_eq(cond_type, cstr("Bool"))) { | ||
642 | emit_semantic_error( | 662 | emit_semantic_error( |
643 | a, node->cond_if, | 663 | a, node->ifelse.cond, |
644 | cstr("non boolean expression on if condition")); | 664 | cstr("non boolean expression on if condition")); |
645 | return cstr(""); | 665 | return cstr(""); |
646 | } | 666 | } |
647 | if (node->cond_expr->kind == NODE_BLOCK) { | 667 | if (node->ifelse.expr_true->kind == NODE_BLOCK) { |
648 | node->type = type_inference(a, node->cond_expr, scope); | 668 | node->type = type_inference(a, node->ifelse.expr_true, scope); |
649 | } else { | 669 | } else { |
650 | Scope *next = typescope_alloc(a, scope); | 670 | Scope *next = typescope_alloc(a, scope); |
651 | node->type = type_inference(a, node->cond_expr, next); | 671 | node->type = type_inference(a, node->ifelse.expr_true, next); |
672 | } | ||
673 | if (str_has_prefix(node->type, cstr("ret:")) || | ||
674 | str_has_prefix(node->type, cstr("flow:"))) { | ||
675 | node->type = cstr("nil"); | ||
652 | } | 676 | } |
653 | if (node->cond_else) { | 677 | if (node->ifelse.expr_else) { |
678 | node->ifelse.expr_else->parent = node; | ||
654 | Str else_type; | 679 | Str else_type; |
655 | if (node->cond_else->kind == NODE_BLOCK) { | 680 | if (node->ifelse.expr_else->kind == NODE_BLOCK) { |
656 | else_type = type_inference(a, node->cond_else, scope); | 681 | else_type = |
682 | type_inference(a, node->ifelse.expr_else, scope); | ||
657 | } else { | 683 | } else { |
658 | Scope *next = typescope_alloc(a, scope); | 684 | Scope *next = typescope_alloc(a, scope); |
659 | else_type = type_inference(a, node->cond_else, next); | 685 | else_type = type_inference(a, node->ifelse.expr_else, next); |
660 | } | 686 | } |
661 | if (!str_eq(node->type, else_type)) { | 687 | if (!str_eq(node->type, else_type)) { |
662 | emit_semantic_error( | 688 | emit_semantic_error( |
@@ -664,9 +690,10 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
664 | return cstr(""); | 690 | return cstr(""); |
665 | } | 691 | } |
666 | } | 692 | } |
693 | |||
667 | // If it returns a value, verify it contains an `else` statement. | 694 | // If it returns a value, verify it contains an `else` statement. |
668 | if (!str_eq(node->type, cstr("nil"))) { | 695 | if (!str_eq(node->type, cstr("nil"))) { |
669 | if (!node->cond_else) { | 696 | if (!node->ifelse.expr_else) { |
670 | emit_semantic_error( | 697 | emit_semantic_error( |
671 | a, node, | 698 | a, node, |
672 | cstr("missing else statement in if expression")); | 699 | cstr("missing else statement in if expression")); |
@@ -676,25 +703,28 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
676 | return node->type; | 703 | return node->type; |
677 | } break; | 704 | } break; |
678 | case NODE_WHILE: { | 705 | case NODE_WHILE: { |
679 | Str cond_type = type_inference(a, node->while_cond, scope); | 706 | node->loop.cond->parent = node; |
680 | if (!str_eq(cond_type, cstr("bool"))) { | 707 | node->loop.expr->parent = node; |
708 | Str cond_type = type_inference(a, node->loop.cond, scope); | ||
709 | if (!str_eq(cond_type, cstr("Bool"))) { | ||
681 | emit_semantic_error( | 710 | emit_semantic_error( |
682 | a, node->cond_if, | 711 | a, node->loop.cond, |
683 | cstr("non boolean expression on while condition")); | 712 | cstr("non boolean expression on while condition")); |
684 | return cstr(""); | 713 | return cstr(""); |
685 | } | 714 | } |
686 | if (node->while_expr->kind != NODE_BLOCK) { | 715 | if (node->loop.expr->kind != NODE_BLOCK) { |
687 | scope = typescope_alloc(a, scope); | 716 | scope = typescope_alloc(a, scope); |
688 | } | 717 | } |
689 | type_inference(a, node->while_expr, scope); | 718 | type_inference(a, node->loop.expr, scope); |
690 | node->type = cstr("nil"); | 719 | node->type = cstr("nil"); |
691 | return node->type; | 720 | return node->type; |
692 | } break; | 721 | } break; |
693 | case NODE_COND: { | 722 | case NODE_COND: { |
694 | Str previous = cstr(""); | 723 | Str previous = cstr(""); |
695 | bool has_else = false; | 724 | bool has_else = false; |
696 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 725 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
697 | Node *expr = node->match_cases[i]; | 726 | Node *expr = node->match.cases[i]; |
727 | expr->parent = node; | ||
698 | Str next = type_inference(a, expr, scope); | 728 | Str next = type_inference(a, expr, scope); |
699 | if (i != 0 && !str_eq(next, previous)) { | 729 | if (i != 0 && !str_eq(next, previous)) { |
700 | emit_semantic_error( | 730 | emit_semantic_error( |
@@ -702,13 +732,15 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
702 | cstr("non-matching types for cond expressions")); | 732 | cstr("non-matching types for cond expressions")); |
703 | return cstr(""); | 733 | return cstr(""); |
704 | } | 734 | } |
705 | if (!expr->case_value) { | 735 | if (!expr->case_entry.cond) { |
706 | has_else = true; | 736 | has_else = true; |
707 | } | 737 | } |
708 | previous = next; | 738 | previous = next; |
709 | } | 739 | } |
710 | // If it returns a value, verify it contains an `else` statement. | 740 | // If it returns a value, verify it contains an `else` statement. |
711 | if (!str_eq(previous, cstr("nil"))) { | 741 | if (!str_eq(node->type, cstr("nil")) && |
742 | !str_has_prefix(node->type, cstr("ret:")) && | ||
743 | !str_has_prefix(node->type, cstr("flow:"))) { | ||
712 | if (!has_else) { | 744 | if (!has_else) { |
713 | emit_semantic_error( | 745 | emit_semantic_error( |
714 | a, node, | 746 | a, node, |
@@ -720,16 +752,18 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
720 | return node->type; | 752 | return node->type; |
721 | } break; | 753 | } break; |
722 | case NODE_MATCH: { | 754 | case NODE_MATCH: { |
723 | Str e = type_inference(a, node->match_expr, scope); | 755 | node->match.expr->parent = node; |
724 | if (str_eq(e, cstr("int"))) { | 756 | Str e = type_inference(a, node->match.expr, scope); |
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 | field->parent = node; |
729 | if (field->case_value->kind != NODE_NUM_INT && | 762 | if (field->case_entry.cond) { |
730 | field->case_value->kind != NODE_NUM_UINT) { | 763 | if (field->case_entry.cond->kind != NODE_NUM_INT && |
764 | field->case_entry.cond->kind != NODE_NUM_UINT) { | ||
731 | emit_semantic_error( | 765 | emit_semantic_error( |
732 | a, field->case_value, | 766 | a, field->case_entry.cond, |
733 | cstr( | 767 | cstr( |
734 | "non-integer or enum types on match case")); | 768 | "non-integer or enum types on match case")); |
735 | } | 769 | } |
@@ -740,24 +774,26 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
740 | FindEnumResult res = find_enum(scope, e); | 774 | FindEnumResult res = find_enum(scope, e); |
741 | Str enum_prefix = | 775 | Str enum_prefix = |
742 | str_concat(res.map->val.name, cstr("."), a->storage); | 776 | str_concat(res.map->val.name, cstr("."), a->storage); |
743 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 777 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
744 | Node *field = node->match_cases[i]; | 778 | Node *field = node->match.cases[i]; |
745 | if (field->case_value) { | 779 | field->parent = node; |
780 | if (field->case_entry.cond) { | ||
746 | Str field_name = str_concat( | 781 | Str field_name = str_concat( |
747 | enum_prefix, field->case_value->value.str, | 782 | enum_prefix, field->case_entry.cond->value.str, |
748 | a->storage); | 783 | a->storage); |
749 | if (!enummap_lookup(&res.scope->enums, field_name)) { | 784 | if (!enummap_lookup(&res.scope->enums, field_name)) { |
750 | eprintln("%s:%d:%d: error: unknown enum field '%s'", | 785 | eprintln("%s:%d:%d: error: unknown enum field '%s'", |
751 | a->file_name, field->case_value->line, | 786 | a->file_name, field->case_entry.cond->line, |
752 | field->case_value->col, field_name); | 787 | field->case_entry.cond->col, field_name); |
753 | a->err = true; | 788 | a->err = true; |
754 | } | 789 | } |
755 | } | 790 | } |
756 | } | 791 | } |
757 | } | 792 | } |
758 | Str previous = cstr(""); | 793 | Str previous = cstr(""); |
759 | for (sz i = 0; i < array_size(node->match_cases); i++) { | 794 | for (sz i = 0; i < array_size(node->match.cases); i++) { |
760 | Node *expr = node->match_cases[i]; | 795 | Node *expr = node->match.cases[i]; |
796 | expr->parent = node; | ||
761 | Str next = type_inference(a, expr, scope); | 797 | Str next = type_inference(a, expr, scope); |
762 | if (i != 0 && !str_eq(next, previous)) { | 798 | if (i != 0 && !str_eq(next, previous)) { |
763 | emit_semantic_error( | 799 | emit_semantic_error( |
@@ -771,29 +807,32 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
771 | return node->type; | 807 | return node->type; |
772 | } break; | 808 | } break; |
773 | case NODE_CASE_MATCH: { | 809 | case NODE_CASE_MATCH: { |
774 | if (node->case_expr->kind != NODE_BLOCK) { | 810 | if (node->case_entry.expr->kind != NODE_BLOCK) { |
775 | scope = typescope_alloc(a, scope); | 811 | scope = typescope_alloc(a, scope); |
776 | } | 812 | } |
777 | node->type = type_inference(a, node->case_expr, scope); | 813 | node->case_entry.expr->parent = node; |
814 | node->type = type_inference(a, node->case_entry.expr, scope); | ||
778 | return node->type; | 815 | return node->type; |
779 | } break; | 816 | } break; |
780 | case NODE_CASE_COND: { | 817 | case NODE_CASE_COND: { |
781 | if (node->case_value) { | 818 | node->case_entry.expr->parent = node; |
782 | Str cond = type_inference(a, node->case_value, scope); | 819 | if (node->case_entry.cond) { |
783 | if (!str_eq(cond, cstr("bool"))) { | 820 | node->case_entry.cond->parent = node; |
821 | Str cond = type_inference(a, node->case_entry.cond, scope); | ||
822 | if (!str_eq(cond, cstr("Bool"))) { | ||
784 | emit_semantic_error(a, node, | 823 | emit_semantic_error(a, node, |
785 | cstr("non-boolean case condition")); | 824 | cstr("non-boolean case condition")); |
786 | } | 825 | } |
787 | } | 826 | } |
788 | if (node->case_expr->kind != NODE_BLOCK) { | 827 | if (node->case_entry.expr->kind != NODE_BLOCK) { |
789 | scope = typescope_alloc(a, scope); | 828 | scope = typescope_alloc(a, scope); |
790 | } | 829 | } |
791 | node->type = type_inference(a, node->case_expr, scope); | 830 | node->type = type_inference(a, node->case_entry.expr, scope); |
792 | return node->type; | 831 | return node->type; |
793 | } break; | 832 | } break; |
794 | case NODE_TRUE: | 833 | case NODE_TRUE: |
795 | case NODE_FALSE: { | 834 | case NODE_FALSE: { |
796 | node->type = cstr("bool"); | 835 | node->type = cstr("Bool"); |
797 | return node->type; | 836 | return node->type; |
798 | } break; | 837 | } break; |
799 | case NODE_NIL: { | 838 | case NODE_NIL: { |
@@ -803,21 +842,23 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
803 | case NODE_NOT: | 842 | case NODE_NOT: |
804 | case NODE_AND: | 843 | case NODE_AND: |
805 | case NODE_OR: { | 844 | case NODE_OR: { |
806 | Str left = type_inference(a, node->left, scope); | 845 | node->binary.left->parent = node; |
807 | if (!str_eq(left, cstr("bool"))) { | 846 | Str left = type_inference(a, node->binary.left, scope); |
847 | if (!str_eq(left, cstr("Bool"))) { | ||
808 | emit_semantic_error(a, node, | 848 | emit_semantic_error(a, node, |
809 | cstr("expected bool on logic expression")); | 849 | cstr("expected bool on logic expression")); |
810 | return cstr(""); | 850 | return cstr(""); |
811 | } | 851 | } |
812 | if (node->right) { | 852 | if (node->binary.right) { |
813 | Str right = type_inference(a, node->right, scope); | 853 | node->binary.right->parent = node; |
814 | if (!str_eq(right, cstr("bool"))) { | 854 | Str right = type_inference(a, node->binary.right, scope); |
855 | if (!str_eq(right, cstr("Bool"))) { | ||
815 | emit_semantic_error( | 856 | emit_semantic_error( |
816 | a, node, cstr("expected bool on logic expression")); | 857 | a, node, cstr("expected bool on logic expression")); |
817 | return cstr(""); | 858 | return cstr(""); |
818 | } | 859 | } |
819 | } | 860 | } |
820 | node->type = cstr("bool"); | 861 | node->type = cstr("Bool"); |
821 | return node->type; | 862 | return node->type; |
822 | } break; | 863 | } break; |
823 | case NODE_EQ: | 864 | case NODE_EQ: |
@@ -826,18 +867,26 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
826 | case NODE_GT: | 867 | case NODE_GT: |
827 | case NODE_LE: | 868 | case NODE_LE: |
828 | case NODE_GE: { | 869 | case NODE_GE: { |
829 | Str left = type_inference(a, node->left, scope); | 870 | node->binary.left->parent = node; |
830 | Str right = type_inference(a, node->right, scope); | 871 | node->binary.right->parent = node; |
872 | Str left = type_inference(a, node->binary.left, scope); | ||
873 | Str right = type_inference(a, node->binary.right, scope); | ||
831 | if (!str_eq(left, right)) { | 874 | if (!str_eq(left, right)) { |
832 | emit_semantic_error( | 875 | if (!(strset_lookup(&a->integer_types, left) && |
833 | a, node, cstr("mismatched types on binary expression")); | 876 | strset_lookup(&a->integer_types, right)) || |
834 | return cstr(""); | 877 | !(strset_lookup(&a->numeric_types, left) && |
878 | strset_lookup(&a->numeric_types, right))) { | ||
879 | emit_semantic_error( | ||
880 | a, node, cstr("mismatched types on binary expression")); | ||
881 | return cstr(""); | ||
882 | } | ||
835 | } | 883 | } |
836 | node->type = cstr("bool"); | 884 | node->type = cstr("Bool"); |
837 | return node->type; | 885 | return node->type; |
838 | } break; | 886 | } break; |
839 | case NODE_BITNOT: { | 887 | case NODE_BITNOT: { |
840 | Str left = type_inference(a, node->left, scope); | 888 | node->binary.left->parent = node; |
889 | Str left = type_inference(a, node->binary.left, scope); | ||
841 | if (!strset_lookup(&a->integer_types, left)) { | 890 | if (!strset_lookup(&a->integer_types, left)) { |
842 | emit_semantic_error( | 891 | emit_semantic_error( |
843 | a, node, cstr("non integer type on bit twiddling expr")); | 892 | a, node, cstr("non integer type on bit twiddling expr")); |
@@ -848,10 +897,13 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
848 | } break; | 897 | } break; |
849 | case NODE_BITAND: | 898 | case NODE_BITAND: |
850 | case NODE_BITOR: | 899 | case NODE_BITOR: |
900 | case NODE_BITXOR: | ||
851 | case NODE_BITLSHIFT: | 901 | case NODE_BITLSHIFT: |
852 | case NODE_BITRSHIFT: { | 902 | case NODE_BITRSHIFT: { |
853 | Str left = type_inference(a, node->left, scope); | 903 | node->binary.left->parent = node; |
854 | Str right = type_inference(a, node->right, scope); | 904 | node->binary.right->parent = node; |
905 | Str left = type_inference(a, node->binary.left, scope); | ||
906 | Str right = type_inference(a, node->binary.right, scope); | ||
855 | if (!strset_lookup(&a->integer_types, left) || | 907 | if (!strset_lookup(&a->integer_types, left) || |
856 | !strset_lookup(&a->integer_types, right)) { | 908 | !strset_lookup(&a->integer_types, right)) { |
857 | emit_semantic_error( | 909 | emit_semantic_error( |
@@ -866,8 +918,17 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
866 | case NODE_DIV: | 918 | case NODE_DIV: |
867 | case NODE_MUL: | 919 | case NODE_MUL: |
868 | case NODE_MOD: { | 920 | case NODE_MOD: { |
869 | Str left = type_inference(a, node->left, scope); | 921 | node->binary.left->parent = node; |
870 | Str right = type_inference(a, node->right, scope); | 922 | node->binary.right->parent = node; |
923 | Str left = type_inference(a, node->binary.left, scope); | ||
924 | Str right = type_inference(a, node->binary.right, scope); | ||
925 | // Enable pointer arithmetic. | ||
926 | if (str_has_prefix(left, cstr("@"))) { | ||
927 | left = cstr("Ptr"); | ||
928 | } | ||
929 | if (str_has_prefix(right, cstr("@"))) { | ||
930 | right = cstr("Ptr"); | ||
931 | } | ||
871 | if (!strset_lookup(&a->numeric_types, left) || | 932 | if (!strset_lookup(&a->numeric_types, left) || |
872 | !strset_lookup(&a->numeric_types, right)) { | 933 | !strset_lookup(&a->numeric_types, right)) { |
873 | emit_semantic_error( | 934 | emit_semantic_error( |
@@ -875,59 +936,105 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
875 | return cstr(""); | 936 | return cstr(""); |
876 | } | 937 | } |
877 | if (!str_eq(left, right)) { | 938 | if (!str_eq(left, right)) { |
878 | emit_semantic_error( | 939 | if (!((strset_lookup(&a->integer_types, left) && |
879 | a, node, cstr("mismatched types on binary expression")); | 940 | strset_lookup(&a->integer_types, right)) || |
880 | return cstr(""); | 941 | (strset_lookup(&a->float_types, left) && |
942 | strset_lookup(&a->float_types, right)))) { | ||
943 | emit_semantic_error( | ||
944 | a, node, cstr("mismatched types on binary expression")); | ||
945 | return cstr(""); | ||
946 | } | ||
881 | } | 947 | } |
882 | node->type = left; | 948 | node->type = left; |
883 | return node->type; | 949 | return node->type; |
884 | } break; | 950 | } break; |
885 | case NODE_NUM_UINT: { | 951 | case NODE_NUM_UINT: { |
886 | node->type = cstr("int"); | 952 | node->type = cstr("UInt"); |
887 | return node->type; | 953 | return node->type; |
888 | } break; | 954 | } break; |
889 | case NODE_NUM_INT: { | 955 | case NODE_NUM_INT: { |
890 | node->type = cstr("int"); | 956 | node->type = cstr("Int"); |
891 | return node->type; | 957 | return node->type; |
892 | } break; | 958 | } break; |
893 | case NODE_NUM_FLOAT: { | 959 | case NODE_NUM_FLOAT: { |
894 | node->type = cstr("f64"); | 960 | node->type = cstr("F64"); |
895 | return node->type; | 961 | return node->type; |
896 | } break; | 962 | } break; |
897 | case NODE_STRING: { | 963 | case NODE_STRING: { |
898 | node->type = cstr("str"); | 964 | node->type = cstr("Str"); |
899 | return node->type; | 965 | return node->type; |
900 | } break; | 966 | } break; |
901 | case NODE_ARR_TYPE: | 967 | case NODE_ARR_TYPE: |
902 | case NODE_TYPE: { | 968 | case NODE_TYPE: { |
903 | SymbolMap *type = find_type(scope, node->value.str); | 969 | Str type = node->value.str; |
904 | if (!type) { | 970 | StrSet *set = find_type(scope, node->value.str); |
971 | if (!set) { | ||
905 | emit_semantic_error(a, node, cstr("unknown type")); | 972 | emit_semantic_error(a, node, cstr("unknown type")); |
906 | return cstr(""); | 973 | return cstr(""); |
907 | } | 974 | } |
908 | node->type = type->val.name; | 975 | Node *next = node->t.next; |
976 | while (next) { | ||
977 | if (next->kind == NODE_PTR) { | ||
978 | type = str_concat(cstr("@"), type, a->storage); | ||
979 | } | ||
980 | next = next->t.next; | ||
981 | } | ||
982 | node->type = type; | ||
983 | return node->type; | ||
984 | } break; | ||
985 | case NODE_DEREF: { | ||
986 | Node *next = node->deref.next; | ||
987 | Str amount = cstr("@"); | ||
988 | while (next) { | ||
989 | if (next->kind == NODE_SYMBOL) { | ||
990 | break; | ||
991 | } | ||
992 | next = next->deref.next; | ||
993 | amount = str_concat(cstr("@"), amount, a->storage); | ||
994 | } | ||
995 | Str symbol = next->value.str; | ||
996 | Str type = type_inference(a, next, scope); | ||
997 | if (!str_has_prefix(type, amount)) { | ||
998 | eprintln( | ||
999 | "%s:%d:%d: error: invalid type dereference %s from type %s", | ||
1000 | a->file_name, node->line, node->col, str_concat(symbol, amount, a->storage), type); | ||
1001 | a->err = true; | ||
1002 | return cstr(""); | ||
1003 | } | ||
1004 | type = str_remove_prefix(type, amount); | ||
1005 | node->value.str = next->value.str; | ||
1006 | node->unique_name = next->unique_name; | ||
1007 | node->type = type; | ||
909 | return node->type; | 1008 | return node->type; |
910 | } break; | 1009 | } break; |
911 | case NODE_SYMBOL_IDX: | 1010 | case NODE_SYMBOL_IDX: |
912 | case NODE_SYMBOL: { | 1011 | case NODE_SYMBOL: { |
913 | Str symbol = node->value.str; | 1012 | Str symbol = node->value.str; |
914 | SymbolMap *type = find_type(scope, symbol); | 1013 | |
915 | if (!type) { | 1014 | FindSymbolResult sym = find_symbol(scope, symbol); |
1015 | if (!sym.map) { | ||
916 | eprintln("%s:%d:%d: error: couldn't resolve symbol '%s'", | 1016 | eprintln("%s:%d:%d: error: couldn't resolve symbol '%s'", |
917 | a->file_name, node->line, node->col, symbol); | 1017 | a->file_name, node->line, node->col, symbol); |
918 | a->err = true; | 1018 | a->err = true; |
919 | return cstr(""); | 1019 | return cstr(""); |
920 | } | 1020 | } |
921 | 1021 | ||
922 | FindSymbolResult sym = find_symbol(scope, symbol); | 1022 | if (!str_eq(sym.scope->name, scope->name) && sym.scope->name.size) { |
1023 | eprintln( | ||
1024 | "%s:%d:%d: error: can't capture external local symbol '%s'", | ||
1025 | a->file_name, node->line, node->col, symbol); | ||
1026 | a->err = true; | ||
1027 | return cstr(""); | ||
1028 | } | ||
923 | node->unique_name = str_concat(cstr("."), symbol, a->storage); | 1029 | node->unique_name = str_concat(cstr("."), symbol, a->storage); |
924 | node->unique_name = | 1030 | node->unique_name = |
925 | str_concat(node->unique_name, | 1031 | str_concat(node->unique_name, |
926 | str_from_int(sym.scope->id, a->storage), a->storage); | 1032 | str_from_int(sym.scope->id, a->storage), a->storage); |
927 | 1033 | ||
928 | Str type_name = type->val.name; | 1034 | Str type_name = sym.map->val.name; |
929 | if (node->kind == NODE_SYMBOL_IDX) { | 1035 | if (node->kind == NODE_SYMBOL_IDX) { |
930 | Str idx_type = type_inference(a, node->arr_size, scope); | 1036 | node->sym.arr_size->parent = node; |
1037 | Str idx_type = type_inference(a, node->sym.arr_size, scope); | ||
931 | if (!strset_lookup(&a->integer_types, idx_type)) { | 1038 | if (!strset_lookup(&a->integer_types, idx_type)) { |
932 | emit_semantic_error( | 1039 | emit_semantic_error( |
933 | a, node, cstr("can't resolve non integer index")); | 1040 | a, node, cstr("can't resolve non integer index")); |
@@ -935,13 +1042,10 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
935 | } | 1042 | } |
936 | type_name = str_remove_prefix(type_name, cstr("@")); | 1043 | type_name = str_remove_prefix(type_name, cstr("@")); |
937 | } | 1044 | } |
938 | if (node->is_ptr) { | ||
939 | type_name = str_concat(cstr("@"), type_name, a->storage); | ||
940 | } | ||
941 | 1045 | ||
942 | FindEnumResult e = find_enum(scope, type_name); | 1046 | FindEnumResult e = find_enum(scope, type_name); |
943 | if (e.map && str_eq(symbol, type_name)) { | 1047 | if (e.map && str_eq(symbol, type_name)) { |
944 | if (!node->next) { | 1048 | if (!node->sym.next) { |
945 | eprintln( | 1049 | eprintln( |
946 | "%s:%d:%d: error: unspecified enum field for symbol " | 1050 | "%s:%d:%d: error: unspecified enum field for symbol " |
947 | "'%s'", | 1051 | "'%s'", |
@@ -951,20 +1055,21 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
951 | } | 1055 | } |
952 | // Check if there is a next and it matches the enum field. | 1056 | // Check if there is a next and it matches the enum field. |
953 | Str field = str_concat(type_name, cstr("."), a->storage); | 1057 | Str field = str_concat(type_name, cstr("."), a->storage); |
954 | field = str_concat(field, node->next->value.str, a->storage); | 1058 | field = |
1059 | str_concat(field, node->sym.next->value.str, a->storage); | ||
955 | if (!enummap_lookup(&e.scope->enums, field)) { | 1060 | if (!enummap_lookup(&e.scope->enums, field)) { |
956 | eprintln( | 1061 | eprintln( |
957 | "%s:%d:%d: error: unknown enum field for " | 1062 | "%s:%d:%d: error: unknown enum field for " |
958 | "'%s': %s", | 1063 | "'%s': %s", |
959 | a->file_name, node->line, node->col, symbol, | 1064 | a->file_name, node->line, node->col, symbol, |
960 | node->next->value.str); | 1065 | node->sym.next->value.str); |
961 | a->err = true; | 1066 | a->err = true; |
962 | return cstr(""); | 1067 | return cstr(""); |
963 | } | 1068 | } |
964 | 1069 | ||
965 | node->next->type = type_name; | 1070 | node->sym.next->type = type_name; |
966 | node->type = type_name; | 1071 | node->type = type_name; |
967 | return node->next->type; | 1072 | return node->sym.next->type; |
968 | } | 1073 | } |
969 | 1074 | ||
970 | FindStructResult s = find_struct(scope, type_name); | 1075 | FindStructResult s = find_struct(scope, type_name); |
@@ -977,11 +1082,11 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
977 | a->err = true; | 1082 | a->err = true; |
978 | return cstr(""); | 1083 | return cstr(""); |
979 | } else { | 1084 | } else { |
980 | if (node->next) { | 1085 | if (node->sym.next) { |
981 | Str chain = type_name; | 1086 | Str chain = type_name; |
982 | Node *next = node; | 1087 | Node *next = node; |
983 | while (next->next) { | 1088 | while (next->sym.next) { |
984 | next = next->next; | 1089 | next = next->sym.next; |
985 | chain = str_concat(chain, cstr("."), a->storage); | 1090 | chain = str_concat(chain, cstr("."), a->storage); |
986 | chain = | 1091 | chain = |
987 | str_concat(chain, next->value.str, a->storage); | 1092 | str_concat(chain, next->value.str, a->storage); |
@@ -997,8 +1102,9 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
997 | } | 1102 | } |
998 | Str field_type = field->val.type; | 1103 | Str field_type = field->val.type; |
999 | if (next->kind == NODE_SYMBOL_IDX) { | 1104 | if (next->kind == NODE_SYMBOL_IDX) { |
1105 | node->sym.arr_size->parent = node; | ||
1000 | Str idx_type = | 1106 | Str idx_type = |
1001 | type_inference(a, next->arr_size, scope); | 1107 | type_inference(a, next->sym.arr_size, scope); |
1002 | if (!strset_lookup(&a->integer_types, idx_type)) { | 1108 | if (!strset_lookup(&a->integer_types, idx_type)) { |
1003 | emit_semantic_error( | 1109 | emit_semantic_error( |
1004 | a, next, | 1110 | a, next, |
@@ -1016,6 +1122,12 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
1016 | node->type = type_name; | 1122 | node->type = type_name; |
1017 | return node->type; | 1123 | return node->type; |
1018 | } break; | 1124 | } break; |
1125 | case NODE_PTR: { | ||
1126 | Str type = type_inference(a, node->t.next, scope); | ||
1127 | type = str_concat(cstr("@"), type, a->storage); | ||
1128 | node->type = type; | ||
1129 | return node->type; | ||
1130 | } break; | ||
1019 | case NODE_STRUCT_LIT: { | 1131 | case NODE_STRUCT_LIT: { |
1020 | Str name = node->value.str; | 1132 | Str name = node->value.str; |
1021 | FindStructResult s = find_struct(scope, name); | 1133 | FindStructResult s = find_struct(scope, name); |
@@ -1029,6 +1141,7 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
1029 | StrSet *set = NULL; | 1141 | StrSet *set = NULL; |
1030 | for (sz i = 0; i < array_size(node->elements); i++) { | 1142 | for (sz i = 0; i < array_size(node->elements); i++) { |
1031 | Node *next = node->elements[i]; | 1143 | Node *next = node->elements[i]; |
1144 | next->parent = node; | ||
1032 | Str field_name = str_concat(name, cstr("."), a->storage); | 1145 | Str field_name = str_concat(name, cstr("."), a->storage); |
1033 | field_name = | 1146 | field_name = |
1034 | str_concat(field_name, next->value.str, a->storage); | 1147 | str_concat(field_name, next->value.str, a->storage); |
@@ -1066,25 +1179,56 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
1066 | 1179 | ||
1067 | // Check that actual parameters typecheck | 1180 | // Check that actual parameters typecheck |
1068 | Str args = cstr(""); | 1181 | Str args = cstr(""); |
1182 | |||
1183 | // Check function aritiy. | ||
1184 | sz arity_fun = array_size(fun->val.param_types); | ||
1185 | sz arity_call = array_size(node->elements); | ||
1186 | if (!str_eq(fun->val.param_type, cstr("..."))) { | ||
1187 | if (arity_fun != arity_call) { | ||
1188 | eprintln( | ||
1189 | "%s:%d:%d: error: wrong number of parameters for " | ||
1190 | "funcall: " | ||
1191 | "%s " | ||
1192 | "expected " | ||
1193 | "%d" | ||
1194 | " got %d", | ||
1195 | a->file_name, node->line, node->col, symbol, arity_fun, | ||
1196 | arity_call); | ||
1197 | a->err = true; | ||
1198 | return cstr(""); | ||
1199 | } | ||
1200 | } | ||
1069 | for (sz i = 0; i < array_size(node->elements); i++) { | 1201 | for (sz i = 0; i < array_size(node->elements); i++) { |
1070 | Node *expr = node->elements[i]; | 1202 | Node *expr = node->elements[i]; |
1203 | expr->parent = node; | ||
1071 | Str type = type_inference(a, expr, scope); | 1204 | Str type = type_inference(a, expr, scope); |
1072 | args = str_concat(args, type, a->storage); | 1205 | args = str_concat(args, type, a->storage); |
1073 | if (i != array_size(node->elements) - 1) { | 1206 | if (i != array_size(node->elements) - 1) { |
1074 | args = str_concat(args, cstr(","), a->storage); | 1207 | args = str_concat(args, cstr(","), a->storage); |
1075 | } | 1208 | } |
1209 | if (!str_eq(fun->val.param_type, cstr("..."))) { | ||
1210 | Str expected = fun->val.param_types[i]; | ||
1211 | if (!str_eq(type, expected)) { | ||
1212 | if (!(strset_lookup(&a->integer_types, type) && | ||
1213 | strset_lookup(&a->integer_types, expected)) || | ||
1214 | !(strset_lookup(&a->numeric_types, type) && | ||
1215 | strset_lookup(&a->numeric_types, expected))) { | ||
1216 | eprintln( | ||
1217 | "%s:%d:%d: error: mismatched parameter types: " | ||
1218 | "%s " | ||
1219 | "expected " | ||
1220 | "%s", | ||
1221 | a->file_name, node->line, node->col, type, | ||
1222 | expected); | ||
1223 | a->err = true; | ||
1224 | return cstr(""); | ||
1225 | } | ||
1226 | } | ||
1227 | } | ||
1076 | } | 1228 | } |
1077 | if (!args.size) { | 1229 | if (!args.size) { |
1078 | args = cstr("nil"); | 1230 | args = cstr("nil"); |
1079 | } | 1231 | } |
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; | 1232 | node->type = fun->val.return_type; |
1089 | return node->type; | 1233 | return node->type; |
1090 | } break; | 1234 | } break; |
@@ -1093,15 +1237,27 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
1093 | Str type; | 1237 | Str type; |
1094 | for (sz i = 0; i < array_size(node->elements); i++) { | 1238 | for (sz i = 0; i < array_size(node->elements); i++) { |
1095 | Node *expr = node->elements[i]; | 1239 | Node *expr = node->elements[i]; |
1240 | expr->parent = node; | ||
1096 | type = type_inference(a, expr, scope); | 1241 | type = type_inference(a, expr, scope); |
1242 | if (str_has_prefix(type, cstr("ret:")) || | ||
1243 | str_has_prefix(type, cstr("flow:"))) { | ||
1244 | break; | ||
1245 | } | ||
1097 | } | 1246 | } |
1098 | node->type = type; | 1247 | node->type = type; |
1099 | return node->type; | 1248 | return node->type; |
1100 | } break; | 1249 | } break; |
1101 | case NODE_RETURN: { | 1250 | case NODE_RETURN: { |
1102 | Str ret_type = cstr(""); | 1251 | if (!scope->name.size) { |
1252 | emit_semantic_error( | ||
1253 | a, node, cstr("return statement outside a function")); | ||
1254 | a->err = true; | ||
1255 | return cstr(""); | ||
1256 | } | ||
1257 | Str ret_type = cstr("ret:"); | ||
1103 | for (sz i = 0; i < array_size(node->elements); i++) { | 1258 | for (sz i = 0; i < array_size(node->elements); i++) { |
1104 | Node *expr = node->elements[i]; | 1259 | Node *expr = node->elements[i]; |
1260 | expr->parent = node; | ||
1105 | Str type = type_inference(a, expr, scope); | 1261 | Str type = type_inference(a, expr, scope); |
1106 | ret_type = str_concat(ret_type, type, a->storage); | 1262 | ret_type = str_concat(ret_type, type, a->storage); |
1107 | if (i != array_size(node->elements) - 1) { | 1263 | if (i != array_size(node->elements) - 1) { |
@@ -1114,118 +1270,151 @@ type_inference(Analyzer *a, Node *node, Scope *scope) { | |||
1114 | node->type = ret_type; | 1270 | node->type = ret_type; |
1115 | return node->type; | 1271 | return node->type; |
1116 | } break; | 1272 | } break; |
1273 | case NODE_CONTINUE: | ||
1274 | case NODE_BREAK: { | ||
1275 | // Check if we are inside a loop. | ||
1276 | Node *parent = node->parent; | ||
1277 | bool inside_loop = false; | ||
1278 | while (parent != NULL) { | ||
1279 | if (parent->kind == NODE_WHILE) { | ||
1280 | inside_loop = true; | ||
1281 | break; | ||
1282 | } | ||
1283 | parent = parent->parent; | ||
1284 | } | ||
1285 | if (!inside_loop) { | ||
1286 | eprintln( | ||
1287 | "%s:%d:%d: error: control flow statement outside a " | ||
1288 | "loop", | ||
1289 | a->file_name, node->line, node->col); | ||
1290 | a->err = true; | ||
1291 | return cstr(""); | ||
1292 | } | ||
1293 | node->type = cstr("flow:"); | ||
1294 | return node->type; | ||
1295 | } break; | ||
1117 | case NODE_FUN: { | 1296 | case NODE_FUN: { |
1118 | node->type = cstr("nil"); | 1297 | node->type = cstr("nil"); |
1119 | Scope *prev_scope = scope; | 1298 | Scope *prev_scope = scope; |
1120 | scope = typescope_alloc(a, scope); | 1299 | scope = typescope_alloc(a, scope); |
1121 | Str param_type = cstr(""); | 1300 | Str param_type = cstr(""); |
1122 | for (sz i = 0; i < array_size(node->func_params); i++) { | 1301 | Str symbol = node->func.name->value.str; |
1123 | Node *param = node->func_params[i]; | 1302 | Fun fun = (Fun){.name = symbol}; |
1124 | Str symbol = param->param_name->value.str; | 1303 | for (sz i = 0; i < array_size(node->func.params); i++) { |
1125 | Str type = param->param_type->value.str; | 1304 | Node *param = node->func.params[i]; |
1126 | if (param->param_type->is_ptr) { | 1305 | param->parent = node; |
1306 | Str symbol = param->param.name->value.str; | ||
1307 | Str type = param->param.type->value.str; | ||
1308 | if (param->param.type->kind == NODE_ARR_TYPE) { | ||
1127 | type = str_concat(cstr("@"), type, a->storage); | 1309 | type = str_concat(cstr("@"), type, a->storage); |
1128 | } | 1310 | } |
1129 | if (param->param_type->kind == NODE_ARR_TYPE) { | 1311 | param->param.name->type = |
1130 | type = str_concat(cstr("@"), type, a->storage); | 1312 | type_inference(a, param->param.type, scope); |
1131 | } | ||
1132 | param->param_name->type = | ||
1133 | type_inference(a, param->param_type, scope); | ||
1134 | param->type = type; | 1313 | param->type = type; |
1314 | array_push(fun.param_types, type, a->storage); | ||
1135 | symmap_insert(&scope->symbols, symbol, | 1315 | symmap_insert(&scope->symbols, symbol, |
1136 | (Symbol){.name = type, .kind = SYM_PARAM}, | 1316 | (Symbol){.name = type, .kind = SYM_PARAM}, |
1137 | a->storage); | 1317 | a->storage); |
1138 | param_type = str_concat(param_type, type, a->storage); | 1318 | param_type = str_concat(param_type, type, a->storage); |
1139 | if (i != array_size(node->func_params) - 1) { | 1319 | if (i != array_size(node->func.params) - 1) { |
1140 | param_type = str_concat(param_type, cstr(","), a->storage); | 1320 | param_type = str_concat(param_type, cstr(","), a->storage); |
1141 | } | 1321 | } |
1322 | symbol = str_concat(cstr("."), symbol, a->storage); | ||
1323 | symbol = str_concat(symbol, str_from_int(scope->id, a->storage), | ||
1324 | a->storage); | ||
1325 | param->unique_name = symbol; | ||
1142 | } | 1326 | } |
1143 | if (!param_type.size) { | 1327 | if (!param_type.size) { |
1144 | param_type = cstr("nil"); | 1328 | param_type = cstr("nil"); |
1145 | } | 1329 | } |
1146 | node->fun_params = param_type; | 1330 | node->type_params = param_type; |
1147 | 1331 | ||
1148 | Str ret_type = cstr(""); | 1332 | Str ret_type = cstr(""); |
1149 | for (sz i = 0; i < array_size(node->func_ret); i++) { | 1333 | for (sz i = 0; i < array_size(node->func.ret); i++) { |
1150 | Node *expr = node->func_ret[i]; | 1334 | Node *expr = node->func.ret[i]; |
1335 | expr->parent = node; | ||
1151 | Str type = type_inference(a, expr, scope); | 1336 | 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) { | 1337 | if (expr->kind == NODE_ARR_TYPE) { |
1156 | type = str_concat(cstr("@"), type, a->storage); | 1338 | type = str_concat(cstr("@"), type, a->storage); |
1157 | } | 1339 | } |
1158 | ret_type = str_concat(ret_type, type, a->storage); | 1340 | ret_type = str_concat(ret_type, type, a->storage); |
1159 | if (i != array_size(node->func_ret) - 1) { | 1341 | array_push(fun.return_types, ret_type, a->storage); |
1342 | if (i != array_size(node->func.ret) - 1) { | ||
1160 | ret_type = str_concat(ret_type, cstr(","), a->storage); | 1343 | ret_type = str_concat(ret_type, cstr(","), a->storage); |
1161 | } | 1344 | } |
1162 | } | 1345 | } |
1163 | if (!ret_type.size) { | 1346 | if (!ret_type.size) { |
1164 | ret_type = cstr("nil"); | 1347 | ret_type = cstr("nil"); |
1165 | } | 1348 | } |
1166 | node->fun_return = ret_type; | 1349 | node->type_returns = ret_type; |
1167 | 1350 | ||
1168 | Str symbol = node->func_name->value.str; | ||
1169 | if (prev_scope->parent != NULL) { | 1351 | if (prev_scope->parent != NULL) { |
1170 | if (symmap_lookup(&prev_scope->symbols, symbol)) { | 1352 | if (symmap_lookup(&prev_scope->symbols, symbol)) { |
1171 | eprintln( | 1353 | eprintln( |
1172 | "%s:%d:%d: error: function '%s' already defined in " | 1354 | "%s:%d:%d: error: function '%s' already defined in " |
1173 | "current " | 1355 | "current " |
1174 | "scope ", | 1356 | "scope ", |
1175 | a->file_name, node->var_name->line, node->var_name->col, | 1357 | a->file_name, node->var.name->line, node->var.name->col, |
1176 | symbol); | 1358 | symbol); |
1177 | a->err = true; | 1359 | a->err = true; |
1178 | return cstr(""); | 1360 | return cstr(""); |
1179 | } | 1361 | } |
1180 | symmap_insert(&scope->symbols, symbol, | 1362 | symmap_insert(&prev_scope->symbols, symbol, |
1181 | (Symbol){.name = symbol, .kind = SYM_FUN}, | 1363 | (Symbol){.name = symbol, .kind = SYM_FUN}, |
1182 | a->storage); | 1364 | a->storage); |
1183 | } | 1365 | } |
1184 | scope->name = symbol; | 1366 | scope->name = symbol; |
1185 | funmap_insert(&prev_scope->funcs, symbol, | 1367 | fun.param_type = param_type; |
1186 | (Fun){.name = symbol, | 1368 | fun.return_type = ret_type; |
1187 | .param_type = param_type, | 1369 | 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); | 1370 | symbol = str_concat(cstr("."), symbol, a->storage); |
1191 | symbol = str_concat(symbol, str_from_int(prev_scope->id, a->storage), | 1371 | symbol = str_concat( |
1192 | a->storage); | 1372 | symbol, str_from_int(prev_scope->id, a->storage), a->storage); |
1193 | node->unique_name = symbol; | 1373 | node->unique_name = symbol; |
1194 | 1374 | ||
1195 | if (node->func_body->kind == NODE_BLOCK) { | 1375 | if (node->func.body->kind == NODE_BLOCK) { |
1196 | Str type; | 1376 | Str type; |
1197 | for (sz i = 0; i < array_size(node->func_body->elements); i++) { | 1377 | for (sz i = 0; i < array_size(node->func.body->elements); i++) { |
1198 | Node *expr = node->func_body->elements[i]; | 1378 | Node *expr = node->func.body->elements[i]; |
1379 | expr->parent = node; | ||
1199 | type = type_inference(a, expr, scope); | 1380 | type = type_inference(a, expr, scope); |
1200 | } | 1381 | } |
1201 | if (!type.size) { | 1382 | if (!type.size) { |
1202 | type = cstr("nil"); | 1383 | type = cstr("nil"); |
1203 | } | 1384 | } |
1204 | node->func_body->type = type; | 1385 | node->func.body->type = type; |
1205 | } else { | 1386 | } else { |
1206 | type_inference(a, node->func_body, scope); | 1387 | node->func.body->parent = node; |
1388 | type_inference(a, node->func.body, scope); | ||
1207 | } | 1389 | } |
1208 | 1390 | ||
1209 | // Ensure main body return matches the prototype. | 1391 | // Ensure main body return matches the prototype. |
1210 | if (!str_eq(node->func_body->type, ret_type)) { | 1392 | Str type = str_remove_prefix(node->func.body->type, cstr("ret:")); |
1211 | eprintln( | 1393 | node->func.body->type = type; |
1212 | "%s:%d:%d: error: mismatched return type %s, expected %s", | 1394 | if (!str_eq(type, ret_type)) { |
1213 | a->file_name, node->line, node->col, node->func_body->type, | 1395 | if (!(strset_lookup(&a->integer_types, type) && |
1214 | ret_type); | 1396 | strset_lookup(&a->integer_types, ret_type)) || |
1215 | a->err = true; | 1397 | !(strset_lookup(&a->numeric_types, type) && |
1398 | strset_lookup(&a->numeric_types, ret_type))) { | ||
1399 | eprintln( | ||
1400 | "%s:%d:%d: error: mismatched return type %s, " | ||
1401 | "expected " | ||
1402 | "%s", | ||
1403 | a->file_name, node->line, node->col, type, ret_type); | ||
1404 | a->err = true; | ||
1405 | } | ||
1216 | } | 1406 | } |
1217 | 1407 | ||
1218 | // Ensure ALL return statements match the function prototype. | 1408 | // Ensure ALL return statements match the function prototype. |
1219 | typecheck_returns(a, node->func_body, ret_type); | 1409 | typecheck_returns(a, node->func.body, ret_type); |
1220 | |||
1221 | // TODO: should return statements be allowed on let blocks? | ||
1222 | return node->type; | 1410 | return node->type; |
1223 | } break; | 1411 | } break; |
1224 | default: { | 1412 | default: { |
1225 | emit_semantic_error(a, node, | 1413 | eprintln( |
1226 | cstr("type inference not implemented for this " | 1414 | "%s:%d:%d: error: type inference not implemented for node " |
1227 | "kind of expression")); | 1415 | "type: %s", |
1228 | println("KIND: %s", node_str[node->kind]); | 1416 | a->file_name, node->line, node->col, node_str[node->kind]); |
1417 | a->err = true; | ||
1229 | } break; | 1418 | } break; |
1230 | } | 1419 | } |
1231 | return cstr(""); | 1420 | return cstr(""); |
@@ -1254,48 +1443,92 @@ symbolic_analysis(Analyzer *a, Parser *parser) { | |||
1254 | a->storage); | 1443 | a->storage); |
1255 | } | 1444 | } |
1256 | Str builtin_types[] = { | 1445 | Str builtin_types[] = { |
1257 | cstr("u8"), cstr("s8"), cstr("u16"), cstr("s16"), | 1446 | cstr("U8"), cstr("S8"), cstr("U16"), cstr("S16"), |
1258 | cstr("u32"), cstr("s32"), cstr("u64"), cstr("s64"), | 1447 | cstr("U32"), cstr("S32"), cstr("U64"), cstr("S64"), |
1259 | cstr("f32"), cstr("f64"), cstr("ptr"), cstr("int"), | 1448 | cstr("F32"), cstr("F64"), cstr("Ptr"), cstr("Int"), |
1260 | cstr("uint"), cstr("str"), cstr("bool"), cstr("nil")}; | 1449 | cstr("UInt"), cstr("Str"), cstr("Bool"), cstr("Nil")}; |
1261 | for (sz i = 0; i < LEN(builtin_types); i++) { | 1450 | for (sz i = 0; i < LEN(builtin_types); i++) { |
1262 | Str type = builtin_types[i]; | 1451 | Str type = builtin_types[i]; |
1263 | symmap_insert(&scope->symbols, type, | 1452 | strset_insert(&scope->types, type, a->storage); |
1264 | (Symbol){.name = type, .kind = SYM_BUILTIN_TYPE}, | ||
1265 | a->storage); | ||
1266 | } | 1453 | } |
1267 | Str numeric_types[] = { | 1454 | Str numeric_types[] = { |
1268 | cstr("u8"), cstr("s8"), cstr("u16"), cstr("s16"), cstr("u32"), | 1455 | cstr("U8"), cstr("S8"), cstr("U16"), cstr("S16"), cstr("U32"), |
1269 | cstr("s32"), cstr("u64"), cstr("s64"), cstr("f32"), cstr("f64"), | 1456 | cstr("S32"), cstr("U64"), cstr("S64"), cstr("F32"), cstr("F64"), |
1270 | cstr("ptr"), cstr("int"), cstr("uint"), | 1457 | cstr("Ptr"), cstr("Int"), cstr("UInt"), |
1271 | }; | 1458 | }; |
1272 | for (sz i = 0; i < LEN(numeric_types); i++) { | 1459 | for (sz i = 0; i < LEN(numeric_types); i++) { |
1273 | Str type = numeric_types[i]; | 1460 | Str type = numeric_types[i]; |
1274 | strset_insert(&a->numeric_types, type, a->storage); | 1461 | strset_insert(&a->numeric_types, type, a->storage); |
1275 | } | 1462 | } |
1276 | Str integer_types[] = { | 1463 | Str integer_types[] = { |
1277 | cstr("u8"), cstr("s8"), cstr("u16"), cstr("s16"), | 1464 | cstr("U8"), cstr("S8"), cstr("U16"), cstr("S16"), |
1278 | cstr("u32"), cstr("s32"), cstr("u64"), cstr("s64"), | 1465 | cstr("U32"), cstr("S32"), cstr("U64"), cstr("S64"), |
1279 | cstr("ptr"), cstr("int"), cstr("uint"), | 1466 | cstr("Ptr"), cstr("Int"), cstr("UInt"), |
1280 | }; | 1467 | }; |
1281 | for (sz i = 0; i < LEN(integer_types); i++) { | 1468 | for (sz i = 0; i < LEN(integer_types); i++) { |
1282 | Str type = integer_types[i]; | 1469 | Str type = integer_types[i]; |
1283 | strset_insert(&a->integer_types, type, a->storage); | 1470 | strset_insert(&a->integer_types, type, a->storage); |
1284 | } | 1471 | } |
1472 | Str float_types[] = { | ||
1473 | cstr("F32"), | ||
1474 | cstr("F64"), | ||
1475 | }; | ||
1476 | for (sz i = 0; i < LEN(float_types); i++) { | ||
1477 | Str type = float_types[i]; | ||
1478 | strset_insert(&a->float_types, type, a->storage); | ||
1479 | } | ||
1285 | // Find top level function declarations. | 1480 | // Find top level function declarations. |
1286 | for (sz i = 0; i < array_size(parser->nodes); i++) { | 1481 | for (sz i = 0; i < array_size(parser->nodes); i++) { |
1287 | Node *root = parser->nodes[i]; | 1482 | Node *root = parser->nodes[i]; |
1288 | if (root->kind == NODE_FUN) { | 1483 | if (root->kind == NODE_FUN) { |
1289 | Str symbol = root->func_name->value.str; | 1484 | Str symbol = root->func.name->value.str; |
1290 | if (symmap_lookup(&scope->symbols, symbol)) { | 1485 | if (symmap_lookup(&scope->symbols, symbol)) { |
1291 | eprintln( | 1486 | eprintln( |
1292 | "%s:%d:%d: error: function '%s' already defined in " | 1487 | "%s:%d:%d: error: function '%s' already defined in " |
1293 | "current " | 1488 | "current " |
1294 | "scope ", | 1489 | "scope ", |
1295 | a->file_name, root->var_name->line, root->var_name->col, | 1490 | a->file_name, root->var.name->line, root->var.name->col, |
1296 | symbol); | 1491 | symbol); |
1297 | a->err = true; | 1492 | a->err = true; |
1298 | } | 1493 | } |
1494 | Fun fun = (Fun){.name = symbol}; | ||
1495 | Str param_type = cstr(""); | ||
1496 | for (sz i = 0; i < array_size(root->func.params); i++) { | ||
1497 | Node *param = root->func.params[i]; | ||
1498 | Str type = param->param.type->value.str; | ||
1499 | if (param->param.type->kind == NODE_ARR_TYPE) { | ||
1500 | type = str_concat(cstr("@"), type, a->storage); | ||
1501 | } | ||
1502 | array_push(fun.param_types, type, a->storage); | ||
1503 | param_type = str_concat(param_type, type, a->storage); | ||
1504 | if (i != array_size(root->func.params) - 1) { | ||
1505 | param_type = str_concat(param_type, cstr(","), a->storage); | ||
1506 | } | ||
1507 | } | ||
1508 | if (!param_type.size) { | ||
1509 | param_type = cstr("nil"); | ||
1510 | } | ||
1511 | root->type_params = param_type; | ||
1512 | |||
1513 | Str ret_type = cstr(""); | ||
1514 | for (sz i = 0; i < array_size(root->func.ret); i++) { | ||
1515 | Node *expr = root->func.ret[i]; | ||
1516 | Str type = expr->value.str; | ||
1517 | if (expr->kind == NODE_ARR_TYPE) { | ||
1518 | type = str_concat(cstr("@"), type, a->storage); | ||
1519 | } | ||
1520 | array_push(fun.return_types, ret_type, a->storage); | ||
1521 | ret_type = str_concat(ret_type, type, a->storage); | ||
1522 | if (i != array_size(root->func.ret) - 1) { | ||
1523 | ret_type = str_concat(ret_type, cstr(","), a->storage); | ||
1524 | } | ||
1525 | } | ||
1526 | if (!ret_type.size) { | ||
1527 | ret_type = cstr("nil"); | ||
1528 | } | ||
1529 | fun.param_type = param_type; | ||
1530 | fun.return_type = ret_type; | ||
1531 | funmap_insert(&scope->funcs, symbol, fun, a->storage); | ||
1299 | symmap_insert(&scope->symbols, symbol, | 1532 | symmap_insert(&scope->symbols, symbol, |
1300 | (Symbol){.name = symbol, .kind = SYM_FUN}, | 1533 | (Symbol){.name = symbol, .kind = SYM_FUN}, |
1301 | a->storage); | 1534 | 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]; |
diff --git a/tests/compilation.bad b/tests/compilation.bad index ea467d2..49a5492 100644 --- a/tests/compilation.bad +++ b/tests/compilation.bad | |||
@@ -1,93 +1,100 @@ | |||
1 | fun adder(a: int): int { | 1 | let a: Int = 32 |
2 | ; a + 1 | 2 | let ptr = @a |
3 | 4 | 3 | println("a " a) |
4 | } | 4 | println("ptr " ptr) |
5 | adder(2) | 5 | |
6 | ; let a = 1 | 6 | set ptr@ = 12 |
7 | ; let b = 8 | 7 | println("a " a) |
8 | 8 | println("ptr " ptr) | |
9 | ; a + b | 9 | |
10 | ; 1 + 2 | 10 | let ptr2 = @ptr |
11 | ; fun greet(name: str): nil { | 11 | set ptr2@@ = 6 |
12 | ; fun greet(name: str): nil { | 12 | println("a " a) |
13 | ; println("hello ") | 13 | println("ptr " ptr) |
14 | ; } | 14 | |
15 | 15 | ; let a: Int = 32 | |
16 | ; greet("alex") | 16 | ; let b: Int = 64 |
17 | ; greet("ding") | 17 | ; let ptr = @a |
18 | ; greet() | 18 | ; println("a " a) |
19 | ; if true { | 19 | ; println("b " b) |
20 | ; 1 | 20 | ; println("ptr " ptr) |
21 | ; nil | 21 | |
22 | ; } | 22 | ; println("ptr@ " ptr@) |
23 | ; let a = 1 | 23 | |
24 | ; let p = @a | 24 | ; { ; FIXME: This doesn't work yet |
25 | ; let arr: int[8] | 25 | ; set ptr@ = 12 |
26 | ; set p[0] = 2 | 26 | ; println(a) |
27 | 27 | ; println(b) | |
28 | ; let b = p[0] | 28 | ; println(ptr) |
29 | ; println("a: " a) | ||
30 | ; println("b: " b) | ||
31 | ; let i = 0 | ||
32 | ; while i < 8 { | ||
33 | ; set arr[i] = i | ||
34 | ; set i = i + 1 | ||
35 | ; } | ||
36 | ; println("arr[0]: " arr[0]) | ||
37 | ; println("arr[1]: " arr[1]) | ||
38 | |||
39 | ; let arr: int[8] | ||
40 | ; set arr[1] = 2 | ||
41 | |||
42 | ; let idx = 3 | ||
43 | ; set arr[idx] = 3 | ||
44 | |||
45 | ; println("arr[0]: " arr[0]) | ||
46 | ; println("arr[1]: " arr[1]) | ||
47 | ; println("arr[2]: " arr[2]) | ||
48 | ; println("arr[3]: " arr[3]) | ||
49 | |||
50 | ; arr[0] + arr[1] + arr[2] + arr[3] | ||
51 | |||
52 | ; set a = 2 | ||
53 | |||
54 | ; let a = cond { | ||
55 | ; 1 == 1 = 42 | ||
56 | ; 1 == 3 = 55 | ||
57 | ; 1 == 1 = 66 | ||
58 | ; else = 10 | ||
59 | ; } | 29 | ; } |
60 | 30 | ||
31 | ; set ptr += 8 | ||
32 | ; println(ptr@) | ||
33 | |||
34 | ; let a: Int = 32 | ||
35 | ; let b: @Int = @a | ||
36 | ; let c = @a | ||
37 | ; let d = @c | ||
38 | ; let e = a + b@ | ||
39 | ; let f = d@ | ||
40 | |||
41 | ; println("a -> " a) | ||
42 | ; println("b -> " b) | ||
43 | ; println("c -> " c) | ||
44 | ; println("d -> " d) | ||
45 | ; println("e -> " e) | ||
46 | ; println("f -> " f) | ||
47 | ; println("b@ -> " b@) | ||
48 | ; println("d@ -> " d@) | ||
49 | ; println("d@@ -> " d@@) | ||
50 | ; println("a == b@ and a == d@@ -> " a == b@ and a == d@@) | ||
51 | ; println("b == c and c == d@ -> " b == c and c == d@) | ||
52 | |||
53 | ; println("b[0] " b[0]) | ||
54 | ; println("c[0] " c[0]) | ||
55 | ; println("d[0] " d[0]) | ||
56 | |||
57 | ; let c = @a | ||
58 | ; let d = @c | ||
59 | ; let c: Int = a@ + 1 | ||
60 | ; let c: @@Int = @b | ||
61 | ; let d: @@@Int = @c | ||
62 | ; let static_array: [24]Int | ||
63 | ; let fun_ptr: (Int Int : Int) | ||
64 | |||
65 | ; let a: U16 = 0x0afafafafafafafafafa | ||
66 | ; println(a) | ||
67 | ; let a: U32 = -2 | ||
68 | ; ; let a: U32 = -2 + -1 | ||
69 | ; let b: @U32 = @a | ||
70 | ; ; let a = "hello" | ||
71 | ; ; let b = a | ||
72 | ; set a = 1 | ||
73 | ; let a = "hello" | ||
74 | ; let b = "world" | ||
75 | |||
76 | ; println(a) | ||
77 | ; println(b) | ||
78 | |||
79 | ; set b = a | ||
80 | ; set a = "WOOWOWO" | ||
81 | |||
82 | ; println(a) | ||
83 | ; println(b) | ||
84 | |||
85 | ; let a: S32[4] | ||
86 | ; set a[0] = 1 | ||
87 | ; set a[1] = 2 | ||
88 | ; set a[2] = 4 | ||
89 | ; set a[3] = 8 | ||
90 | ; let b = a | ||
91 | ; println(a[0] "--" a[1] "--" a[2] "--" a[3]) | ||
92 | ; println(b[0] "--" b[1] "--" b[2] "--" b[3]) | ||
93 | |||
94 | ; let a = 1 + 2 | ||
61 | ; a | 95 | ; a |
62 | 96 | ; let sum_int_uint: U16 = -2 + 0x5 | |
63 | ; let a = 8 | 97 | ; ; let sum_int_uint = -2 |
64 | ; let b = 16 | 98 | ; println(sum_int_uint) |
65 | ; let c = { | 99 | ; let varint: U16 = 0x0102030405060708 |
66 | ; let a = 32 | 100 | ; let varfloat: F32 = 1.0 |
67 | ; a + 8 | ||
68 | ; } | ||
69 | |||
70 | ; a + b + c | ||
71 | |||
72 | ; let a = 1 | ||
73 | ; if false { | ||
74 | ; set a = 2 | ||
75 | ; } | ||
76 | ; a | ||
77 | |||
78 | ; if true { | ||
79 | ; 1 + 2 | ||
80 | ; } else { | ||
81 | ; 3 + 4 | ||
82 | ; } | ||
83 | |||
84 | ; let a = 0 | ||
85 | ; while a < 10 { | ||
86 | ; set a = a + 1 | ||
87 | ; } | ||
88 | |||
89 | ; a | ||
90 | |||
91 | ; print(1) | ||
92 | ; println(1.0 + 2.0) | ||
93 | ; println("hello world " 1 " " 2.0 " wow!") | ||
diff --git a/tests/logic-shortcircuit.bad b/tests/logic-shortcircuit.bad new file mode 100644 index 0000000..a7e315e --- /dev/null +++ b/tests/logic-shortcircuit.bad | |||
@@ -0,0 +1,16 @@ | |||
1 | fun ret_true(): Bool { | ||
2 | print("ret_true ") | ||
3 | true | ||
4 | } | ||
5 | |||
6 | fun ret_false(): Bool { | ||
7 | print("ret_false ") | ||
8 | false | ||
9 | } | ||
10 | |||
11 | println("test1: " ret_true() and ret_false() and ret_true()) | ||
12 | println("test2: " ret_true() and ret_true() and ret_true()) | ||
13 | println("test3: " ret_false() and ret_true() and ret_true()) | ||
14 | println("test4: " ret_false() or ret_true() or ret_false()) | ||
15 | println("test5: " ret_true() or ret_true() or ret_false()) | ||
16 | println("test6: " ret_true() and (ret_true() or ret_false())) | ||
diff --git a/tests/nested.bad b/tests/nested.bad new file mode 100644 index 0000000..75eb967 --- /dev/null +++ b/tests/nested.bad | |||
@@ -0,0 +1,18 @@ | |||
1 | fun printer() println("wowo!") | ||
2 | |||
3 | let y = 4 | ||
4 | fun nested() { | ||
5 | fun adder(a: Int b: Int): Int { | ||
6 | fun printer() println("ho!") | ||
7 | printer() | ||
8 | printer() | ||
9 | printer() | ||
10 | y + a + b | ||
11 | } | ||
12 | for let i = 0, i < 2, set i += 1 { | ||
13 | println("i: " i " " adder(i, 2)) | ||
14 | } | ||
15 | } | ||
16 | |||
17 | nested() | ||
18 | printer() | ||
diff --git a/tests/pointers.bad b/tests/pointers.bad new file mode 100644 index 0000000..eda44b0 --- /dev/null +++ b/tests/pointers.bad | |||
@@ -0,0 +1,36 @@ | |||
1 | { | ||
2 | let a: Int = 32 | ||
3 | let b: @Int = @a | ||
4 | let c = @a | ||
5 | let d = @c | ||
6 | let e = a + b@ | ||
7 | let f = d@ | ||
8 | |||
9 | println("a -> " a) | ||
10 | println("b -> " b) | ||
11 | println("c -> " c) | ||
12 | println("d -> " d) | ||
13 | println("e -> " e) | ||
14 | println("f -> " f) | ||
15 | println("b@ -> " b@) | ||
16 | println("d@ -> " d@) | ||
17 | println("d@@ -> " d@@) | ||
18 | println("a == b@ and a == d@@ -> " a == b@ and a == d@@) | ||
19 | println("b == c and c == d@ -> " b == c and c == d@) | ||
20 | } | ||
21 | |||
22 | { | ||
23 | let a: Int = 32 | ||
24 | let ptr = @a | ||
25 | println("a " a) | ||
26 | println("ptr " ptr) | ||
27 | |||
28 | set ptr@ = 12 | ||
29 | println("a " a) | ||
30 | println("ptr " ptr) | ||
31 | |||
32 | let ptr2 = @ptr | ||
33 | set ptr2@@ = 6 | ||
34 | println("a " a) | ||
35 | println("ptr " ptr) | ||
36 | } | ||
diff --git a/tests/recursion.bad b/tests/recursion.bad new file mode 100644 index 0000000..0ab7fa0 --- /dev/null +++ b/tests/recursion.bad | |||
@@ -0,0 +1,19 @@ | |||
1 | fun recur(num: UInt) { | ||
2 | println("NUM: " num) | ||
3 | if num == 0 return(nil) | ||
4 | recur2(num - 1) | ||
5 | } | ||
6 | |||
7 | fun recur2(num: Int) { | ||
8 | println("NUM: " num) | ||
9 | if num == 0 return(nil) | ||
10 | recur(num - 1) | ||
11 | } | ||
12 | |||
13 | recur(5) | ||
14 | |||
15 | fun infrecur(msg: Str, num: Int) { | ||
16 | println("NUM: " msg " " num) | ||
17 | infrecur(msg num + 1) | ||
18 | } | ||
19 | infrecur(" -> " 8) | ||