diff options
-rwxr-xr-x | src/bytecode/compiler.h | 57 | ||||
-rw-r--r-- | src/bytecode/hashtable.h | 4 | ||||
-rwxr-xr-x | src/bytecode/main.c | 11 | ||||
-rw-r--r-- | src/bytecode/objects.c | 10 | ||||
-rwxr-xr-x | src/bytecode/vm.h | 61 |
5 files changed, 99 insertions, 44 deletions
diff --git a/src/bytecode/compiler.h b/src/bytecode/compiler.h index 4130269..2c7827f 100755 --- a/src/bytecode/compiler.h +++ b/src/bytecode/compiler.h | |||
@@ -14,7 +14,7 @@ Token next_token(Compiler *compiler); | |||
14 | Token peek_token(const Compiler *compiler); | 14 | Token peek_token(const Compiler *compiler); |
15 | bool has_next_token(const Compiler *compiler); | 15 | bool has_next_token(const Compiler *compiler); |
16 | 16 | ||
17 | Object compile(Token *tokens); | 17 | Chunk * compile(Token *tokens); |
18 | 18 | ||
19 | Token | 19 | Token |
20 | peek_token(const Compiler *compiler) { | 20 | peek_token(const Compiler *compiler) { |
@@ -248,6 +248,49 @@ compile_declare_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) { | |||
248 | } | 248 | } |
249 | 249 | ||
250 | void | 250 | void |
251 | compile_fun_op(Chunk *chunk, Compiler *compiler, Token start) { | ||
252 | Token name = peek_token(compiler); | ||
253 | if (name.type != TOKEN_SYMBOL) { | ||
254 | error_push((Error){ | ||
255 | .type = ERR_TYPE_COMPILER, | ||
256 | .value = ERR_WRONG_ARG_TYPE, | ||
257 | .line = start.line, | ||
258 | .col = start.column, | ||
259 | }); | ||
260 | return; | ||
261 | } | ||
262 | parse_tree(chunk, compiler); | ||
263 | |||
264 | // TODO: compile lambda expression. | ||
265 | Object fun = make_lambda(name.value); | ||
266 | // FIXME: skipping arguments for now. Assuming nil. | ||
267 | next_token(compiler); | ||
268 | |||
269 | // Compile body. | ||
270 | while (has_next_token(compiler)) { | ||
271 | Token tok = peek_token(compiler); | ||
272 | if (tok.type == TOKEN_EOF) { | ||
273 | error_push((Error){ | ||
274 | .type = ERR_TYPE_COMPILER, | ||
275 | .value = ERR_UNBALANCED_PAREN, | ||
276 | .line = start.line, | ||
277 | .col = start.column, | ||
278 | }); | ||
279 | return; | ||
280 | } | ||
281 | if (tok.type == TOKEN_RPAREN) { | ||
282 | next_token(compiler); | ||
283 | break; | ||
284 | } | ||
285 | parse_tree(fun.chunk, compiler); | ||
286 | } | ||
287 | add_code(fun.chunk, OP_RETURN, start.line, start.column); | ||
288 | |||
289 | emit_constant(chunk, start, fun); | ||
290 | add_code(chunk, OP_DEF, start.line, start.column); | ||
291 | } | ||
292 | |||
293 | void | ||
251 | compile_if_op(Chunk *chunk, Compiler *compiler, Token start) { | 294 | compile_if_op(Chunk *chunk, Compiler *compiler, Token start) { |
252 | Token tok = peek_token(compiler); | 295 | Token tok = peek_token(compiler); |
253 | if (tok.type == TOKEN_EOF) { | 296 | if (tok.type == TOKEN_EOF) { |
@@ -332,6 +375,7 @@ parse_list(Chunk *chunk, Compiler *compiler, Token start) { | |||
332 | case TOKEN_NEWLINE: { compile_list_simple_op(chunk, compiler, start, OP_NEWLINE); } break; | 375 | case TOKEN_NEWLINE: { compile_list_simple_op(chunk, compiler, start, OP_NEWLINE); } break; |
333 | case TOKEN_DEF: { compile_declare_op(chunk, compiler, start, OP_DEF); } break; | 376 | case TOKEN_DEF: { compile_declare_op(chunk, compiler, start, OP_DEF); } break; |
334 | case TOKEN_SET: { compile_declare_op(chunk, compiler, start, OP_SET); } break; | 377 | case TOKEN_SET: { compile_declare_op(chunk, compiler, start, OP_SET); } break; |
378 | case TOKEN_FUN: { compile_fun_op(chunk, compiler, start); } break; | ||
335 | case TOKEN_IF: { compile_if_op(chunk, compiler, start); } break; | 379 | case TOKEN_IF: { compile_if_op(chunk, compiler, start); } break; |
336 | default: { | 380 | default: { |
337 | error_push((Error){ | 381 | error_push((Error){ |
@@ -415,19 +459,20 @@ parse_tree(Chunk *chunk, Compiler *compiler) { | |||
415 | return; | 459 | return; |
416 | } | 460 | } |
417 | 461 | ||
418 | Object | 462 | Chunk * |
419 | compile(Token *tokens) { | 463 | compile(Token *tokens) { |
420 | Object main = make_lambda((StringView){"main", sizeof("main")}); | 464 | Chunk *chunk = NULL; |
465 | chunk = NEW_CHUNK("main"); | ||
421 | Compiler compiler = (Compiler){ | 466 | Compiler compiler = (Compiler){ |
422 | .tokens = tokens, | 467 | .tokens = tokens, |
423 | .current = 0, | 468 | .current = 0, |
424 | }; | 469 | }; |
425 | Token start_tok = peek_token(&compiler); | 470 | Token start_tok = peek_token(&compiler); |
426 | while (has_next_token(&compiler) && peek_token(&compiler).type != TOKEN_EOF) { | 471 | while (has_next_token(&compiler) && peek_token(&compiler).type != TOKEN_EOF) { |
427 | parse_tree(main.chunk, &compiler); | 472 | parse_tree(chunk, &compiler); |
428 | } | 473 | } |
429 | add_code(main.chunk, OP_RETURN, start_tok.line, start_tok.column); | 474 | add_code(chunk, OP_RETURN, start_tok.line, start_tok.column); |
430 | return main; | 475 | return chunk; |
431 | } | 476 | } |
432 | 477 | ||
433 | #endif // BDL_COMPILER_H | 478 | #endif // BDL_COMPILER_H |
diff --git a/src/bytecode/hashtable.h b/src/bytecode/hashtable.h index 48665d3..1f47666 100644 --- a/src/bytecode/hashtable.h +++ b/src/bytecode/hashtable.h | |||
@@ -112,7 +112,7 @@ _ht_insert(HashTable *table, Object key, Object value) { | |||
112 | 112 | ||
113 | if (!update) { | 113 | if (!update) { |
114 | array_push(table->keys, object_copy(key)); | 114 | array_push(table->keys, object_copy(key)); |
115 | array_push(table->values, object_copy(value)); | 115 | array_push(table->values, value); |
116 | pairs[probe_position].key = &table->keys[array_size(table->keys) - 1]; | 116 | pairs[probe_position].key = &table->keys[array_size(table->keys) - 1]; |
117 | pairs[probe_position].value = &table->values[array_size(table->values) - 1]; | 117 | pairs[probe_position].value = &table->values[array_size(table->values) - 1]; |
118 | } else { | 118 | } else { |
@@ -155,7 +155,6 @@ _ht_maybe_grow(HashTable *table) { | |||
155 | Object key = old_keys[i]; | 155 | Object key = old_keys[i]; |
156 | Object value = old_values[i]; | 156 | Object value = old_values[i]; |
157 | object_free(key); | 157 | object_free(key); |
158 | object_free(value); | ||
159 | } | 158 | } |
160 | array_free(old_keys); | 159 | array_free(old_keys); |
161 | array_free(old_values); | 160 | array_free(old_values); |
@@ -205,7 +204,6 @@ ht_free(HashTable *table) { | |||
205 | Object key = table->keys[i]; | 204 | Object key = table->keys[i]; |
206 | Object value = table->values[i]; | 205 | Object value = table->values[i]; |
207 | object_free(key); | 206 | object_free(key); |
208 | object_free(value); | ||
209 | } | 207 | } |
210 | array_free(table->keys); | 208 | array_free(table->keys); |
211 | array_free(table->values); | 209 | array_free(table->values); |
diff --git a/src/bytecode/main.c b/src/bytecode/main.c index e4cf643..7cb0a2a 100755 --- a/src/bytecode/main.c +++ b/src/bytecode/main.c | |||
@@ -45,27 +45,26 @@ process_source(const StringView *source) { | |||
45 | } | 45 | } |
46 | 46 | ||
47 | // Compile chunk. | 47 | // Compile chunk. |
48 | Object main = compile(tokens); | 48 | Chunk *main = compile(tokens); |
49 | if (errors_n != 0) { | 49 | if (errors_n != 0) { |
50 | object_free(main); | 50 | chunk_free(main); |
51 | array_free(tokens); | 51 | array_free(tokens); |
52 | return; | 52 | return; |
53 | } | 53 | } |
54 | 54 | ||
55 | #ifdef DEBUG | 55 | #ifdef DEBUG |
56 | disassemble_chunk(main.chunk); | 56 | disassemble_chunk(main); |
57 | #endif | 57 | #endif |
58 | 58 | ||
59 | // Interpret chunk. | 59 | // Interpret chunk. |
60 | CallFrame frame = (CallFrame){ | 60 | CallFrame frame = (CallFrame){ |
61 | .procedure = main, | 61 | .chunk = main, |
62 | .pc = main.chunk->code, | ||
63 | }; | 62 | }; |
64 | array_push(vm.frames, frame); | 63 | array_push(vm.frames, frame); |
65 | vm_interpret(&vm); | 64 | vm_interpret(&vm); |
66 | 65 | ||
67 | // Free resources. | 66 | // Free resources. |
68 | object_free(main); | 67 | chunk_free(main); |
69 | array_free(tokens); | 68 | array_free(tokens); |
70 | } | 69 | } |
71 | 70 | ||
diff --git a/src/bytecode/objects.c b/src/bytecode/objects.c index 14dc057..e446fb0 100644 --- a/src/bytecode/objects.c +++ b/src/bytecode/objects.c | |||
@@ -120,6 +120,16 @@ object_copy(Object src) { | |||
120 | array_insert(copy.text, src.text, array_size(src.text)); | 120 | array_insert(copy.text, src.text, array_size(src.text)); |
121 | return copy; | 121 | return copy; |
122 | } break; | 122 | } break; |
123 | case OBJ_TYPE_LAMBDA: { | ||
124 | Object copy = src; | ||
125 | StringView name = (StringView){ | ||
126 | .start = src.chunk->name, | ||
127 | .n = array_size(src.chunk->name), | ||
128 | }; | ||
129 | // TODO: copy full chunk? | ||
130 | // copy.chunk = chunk_init(name); | ||
131 | return copy; | ||
132 | } break; | ||
123 | default: { break; } break; | 133 | default: { break; } break; |
124 | } | 134 | } |
125 | return src; | 135 | return src; |
diff --git a/src/bytecode/vm.h b/src/bytecode/vm.h index 23c3d89..f7852de 100755 --- a/src/bytecode/vm.h +++ b/src/bytecode/vm.h | |||
@@ -13,17 +13,20 @@ | |||
13 | 13 | ||
14 | typedef struct CallFrame { | 14 | typedef struct CallFrame { |
15 | // Current code being run. | 15 | // Current code being run. |
16 | Object procedure; | 16 | Chunk *chunk; |
17 | // Current program counter for this call. | 17 | // Current program counter for this call. |
18 | u8 *pc; | ||
19 | // Ref to stack. Is this really needed? | 18 | // Ref to stack. Is this really needed? |
20 | // Object *stack; | 19 | // Object *locals; |
20 | // Return counter. | ||
21 | u8 *rp; | ||
21 | } CallFrame; | 22 | } CallFrame; |
22 | 23 | ||
23 | typedef struct VM { | 24 | typedef struct VM { |
24 | CallFrame *frames; | 25 | CallFrame *frames; |
25 | // Stack. | 26 | // Stack. |
26 | Object *stack; | 27 | Object *stack; |
28 | // Program counter. | ||
29 | u8 *pc; | ||
27 | // Global variables. | 30 | // Global variables. |
28 | HashTable *globals; | 31 | HashTable *globals; |
29 | } VM; | 32 | } VM; |
@@ -37,9 +40,6 @@ void | |||
37 | vm_init(VM *vm) { | 40 | vm_init(VM *vm) { |
38 | *vm = (VM){0}; | 41 | *vm = (VM){0}; |
39 | array_init(vm->frames, VM_FRAMES_CAP); | 42 | array_init(vm->frames, VM_FRAMES_CAP); |
40 | for (size_t i = 0; i < array_cap(vm->frames); i++) { | ||
41 | vm->frames[i] = (CallFrame){0}; | ||
42 | } | ||
43 | array_init(vm->stack, VM_STACK_CAP); | 43 | array_init(vm->stack, VM_STACK_CAP); |
44 | vm->globals = ht_init(); | 44 | vm->globals = ht_init(); |
45 | } | 45 | } |
@@ -62,16 +62,16 @@ vm_reset(VM *vm) { | |||
62 | error_push((Error){ \ | 62 | error_push((Error){ \ |
63 | .type = ERR_TYPE_RUNTIME, \ | 63 | .type = ERR_TYPE_RUNTIME, \ |
64 | .value = ERR_WRONG_ARG_TYPE, \ | 64 | .value = ERR_WRONG_ARG_TYPE, \ |
65 | .line = chunk->lines[frame->pc - chunk->code - 1].line, \ | 65 | .line = frame->chunk->lines[vm->pc - frame->chunk->code - 1].line, \ |
66 | .col = chunk->lines[frame->pc - chunk->code - 1].col, \ | 66 | .col = frame->chunk->lines[vm->pc - frame->chunk->code - 1].col, \ |
67 | }) | 67 | }) |
68 | 68 | ||
69 | #define SYMBOL_NOT_FOUND_ERR() \ | 69 | #define SYMBOL_NOT_FOUND_ERR() \ |
70 | error_push((Error){ \ | 70 | error_push((Error){ \ |
71 | .type = ERR_TYPE_RUNTIME, \ | 71 | .type = ERR_TYPE_RUNTIME, \ |
72 | .value = ERR_SYMBOL_NOT_FOUND, \ | 72 | .value = ERR_SYMBOL_NOT_FOUND, \ |
73 | .line = chunk->lines[frame->pc - chunk->code - 1].line, \ | 73 | .line = frame->chunk->lines[vm->pc - frame->chunk->code - 1].line, \ |
74 | .col = chunk->lines[frame->pc - chunk->code - 1].col, \ | 74 | .col = frame->chunk->lines[vm->pc - frame->chunk->code - 1].col, \ |
75 | }) | 75 | }) |
76 | 76 | ||
77 | #define FIXNUM_ARITHMETIC_OP(OP) \ | 77 | #define FIXNUM_ARITHMETIC_OP(OP) \ |
@@ -137,9 +137,9 @@ vm_reset(VM *vm) { | |||
137 | void | 137 | void |
138 | vm_interpret(VM *vm) { | 138 | vm_interpret(VM *vm) { |
139 | CallFrame *frame = &vm->frames[array_size(vm->frames) - 1]; | 139 | CallFrame *frame = &vm->frames[array_size(vm->frames) - 1]; |
140 | Chunk *chunk = frame->procedure.chunk; | 140 | vm->pc = frame->chunk->code; |
141 | 141 | ||
142 | if (chunk->code == NULL || array_size(chunk->code) == 0) { | 142 | if (frame->chunk->code == NULL || array_size(frame->chunk->code) == 0) { |
143 | error_push((Error){ | 143 | error_push((Error){ |
144 | .type = ERR_TYPE_RUNTIME, | 144 | .type = ERR_TYPE_RUNTIME, |
145 | .value = ERR_EMPTY_CHUNK, | 145 | .value = ERR_EMPTY_CHUNK, |
@@ -147,8 +147,8 @@ vm_interpret(VM *vm) { | |||
147 | return; | 147 | return; |
148 | } | 148 | } |
149 | 149 | ||
150 | u8 *last = chunk->code + array_size(chunk->code); | 150 | u8 *last = frame->chunk->code + array_size(frame->chunk->code); |
151 | while (frame->pc < last) { | 151 | while (vm->pc < last) { |
152 | #ifdef DEBUG_TRACE_EXECUTION | 152 | #ifdef DEBUG_TRACE_EXECUTION |
153 | printf("stack: [ "); | 153 | printf("stack: [ "); |
154 | for (size_t i = 0; i < array_size(vm->stack); i++) { | 154 | for (size_t i = 0; i < array_size(vm->stack); i++) { |
@@ -158,13 +158,13 @@ vm_interpret(VM *vm) { | |||
158 | } | 158 | } |
159 | } | 159 | } |
160 | printf(" ]\nop: "); | 160 | printf(" ]\nop: "); |
161 | disassemble_instruction(chunk, (frame->pc - chunk->code)); | 161 | disassemble_instruction(frame->chunk, (vm->pc - frame->chunk->code)); |
162 | #endif | 162 | #endif |
163 | u8 instruction = *frame->pc++; | 163 | u8 instruction = *vm->pc++; |
164 | switch (instruction) { | 164 | switch (instruction) { |
165 | case OP_CONSTANT: { | 165 | case OP_CONSTANT: { |
166 | u8 constant = *frame->pc++; | 166 | u8 constant = *vm->pc++; |
167 | Object obj = chunk->constants[constant]; | 167 | Object obj = frame->chunk->constants[constant]; |
168 | array_push(vm->stack, obj); | 168 | array_push(vm->stack, obj); |
169 | } break; | 169 | } break; |
170 | case OP_DEF: { | 170 | case OP_DEF: { |
@@ -209,17 +209,17 @@ vm_interpret(VM *vm) { | |||
209 | case OP_LESS_EQUAL: { FIXNUM_COMPARE_OP(<=); } break; | 209 | case OP_LESS_EQUAL: { FIXNUM_COMPARE_OP(<=); } break; |
210 | case OP_GREATER_EQUAL: { FIXNUM_COMPARE_OP(>=); } break; | 210 | case OP_GREATER_EQUAL: { FIXNUM_COMPARE_OP(>=); } break; |
211 | case OP_JUMP: { | 211 | case OP_JUMP: { |
212 | u16 a = *frame->pc++; | 212 | u16 a = *vm->pc++; |
213 | u16 b = *frame->pc++; | 213 | u16 b = *vm->pc++; |
214 | s16 offset = (a << 8) | b; | 214 | s16 offset = (a << 8) | b; |
215 | frame->pc += offset; | 215 | vm->pc += offset; |
216 | } break; | 216 | } break; |
217 | case OP_JUMP_IF_FALSE: { | 217 | case OP_JUMP_IF_FALSE: { |
218 | u16 a = *frame->pc++; | 218 | u16 a = *vm->pc++; |
219 | u16 b = *frame->pc++; | 219 | u16 b = *vm->pc++; |
220 | s16 offset = (a << 8) | b; | 220 | s16 offset = (a << 8) | b; |
221 | if (IS_FALSE(array_pop(vm->stack))) { | 221 | if (IS_FALSE(array_pop(vm->stack))) { |
222 | frame->pc += offset; | 222 | vm->pc += offset; |
223 | } | 223 | } |
224 | } break; | 224 | } break; |
225 | case OP_DISPLAY: { | 225 | case OP_DISPLAY: { |
@@ -253,15 +253,18 @@ vm_interpret(VM *vm) { | |||
253 | printf("\n"); | 253 | printf("\n"); |
254 | } break; | 254 | } break; |
255 | case OP_RETURN: { | 255 | case OP_RETURN: { |
256 | printf("\n"); | 256 | if (frame->rp != NULL) { |
257 | // TODO: restore previous call frame. | ||
258 | vm->pc = frame->rp; | ||
259 | } | ||
257 | return; | 260 | return; |
258 | } break; | 261 | } break; |
259 | default: { | 262 | default: { |
260 | error_push((Error){ | 263 | error_push((Error){ |
261 | .type = ERR_TYPE_RUNTIME, | 264 | .type = ERR_TYPE_RUNTIME, |
262 | .value = ERR_NOT_IMPLEMENTED, | 265 | .value = ERR_NOT_IMPLEMENTED, |
263 | .line = chunk->lines[frame->pc - chunk->code - 1].line, | 266 | .line = frame->chunk->lines[vm->pc - frame->chunk->code - 1].line, |
264 | .col = chunk->lines[frame->pc - chunk->code - 1].col, | 267 | .col = frame->chunk->lines[vm->pc - frame->chunk->code - 1].col, |
265 | }); | 268 | }); |
266 | return; | 269 | return; |
267 | } break; | 270 | } break; |
@@ -271,8 +274,8 @@ vm_interpret(VM *vm) { | |||
271 | error_push((Error){ | 274 | error_push((Error){ |
272 | .type = ERR_TYPE_RUNTIME, | 275 | .type = ERR_TYPE_RUNTIME, |
273 | .value = ERR_PC_OOB, | 276 | .value = ERR_PC_OOB, |
274 | .line = chunk->lines[0].line, | 277 | .line = frame->chunk->lines[0].line, |
275 | .col = chunk->lines[0].col, | 278 | .col = frame->chunk->lines[0].col, |
276 | }); | 279 | }); |
277 | } | 280 | } |
278 | 281 | ||