diff options
-rw-r--r-- | src/bytecode/chunk.c | 3 | ||||
-rwxr-xr-x | src/bytecode/chunk.h | 6 | ||||
-rwxr-xr-x | src/bytecode/compiler.h | 83 | ||||
-rwxr-xr-x | src/bytecode/debug.h | 6 | ||||
-rwxr-xr-x | src/bytecode/ops.h | 1 | ||||
-rwxr-xr-x | src/bytecode/vm.h | 18 |
6 files changed, 95 insertions, 22 deletions
diff --git a/src/bytecode/chunk.c b/src/bytecode/chunk.c index 8b87d0d..e566e78 100644 --- a/src/bytecode/chunk.c +++ b/src/bytecode/chunk.c | |||
@@ -9,6 +9,7 @@ chunk_init(StringView name) { | |||
9 | array_init(chunk->lines, 0); | 9 | array_init(chunk->lines, 0); |
10 | array_init(chunk->name, name.n); | 10 | array_init(chunk->name, name.n); |
11 | array_insert(chunk->name, name.start, name.n); | 11 | array_insert(chunk->name, name.start, name.n); |
12 | array_init(chunk->params, 0); | ||
12 | return chunk; | 13 | return chunk; |
13 | } | 14 | } |
14 | 15 | ||
@@ -22,6 +23,7 @@ chunk_free(Chunk *chunk) { | |||
22 | array_free(chunk->constants); | 23 | array_free(chunk->constants); |
23 | array_free(chunk->lines); | 24 | array_free(chunk->lines); |
24 | array_free(chunk->name); | 25 | array_free(chunk->name); |
26 | array_free(chunk->params); | ||
25 | free(chunk); | 27 | free(chunk); |
26 | } | 28 | } |
27 | 29 | ||
@@ -43,4 +45,3 @@ add_constant(Chunk *chunk, Object obj) { | |||
43 | array_push(chunk->constants, obj); | 45 | array_push(chunk->constants, obj); |
44 | return pos; | 46 | return pos; |
45 | } | 47 | } |
46 | |||
diff --git a/src/bytecode/chunk.h b/src/bytecode/chunk.h index 1e88ea0..a3e02d1 100755 --- a/src/bytecode/chunk.h +++ b/src/bytecode/chunk.h | |||
@@ -12,10 +12,16 @@ typedef struct LineInfo { | |||
12 | } LineInfo; | 12 | } LineInfo; |
13 | 13 | ||
14 | typedef struct Chunk { | 14 | typedef struct Chunk { |
15 | // Program code. | ||
15 | u8 *code; | 16 | u8 *code; |
17 | // Compile time constants. | ||
16 | Object *constants; | 18 | Object *constants; |
19 | // Contains debugging information for every code operation. | ||
17 | LineInfo *lines; | 20 | LineInfo *lines; |
21 | // Chunk name. | ||
18 | char *name; | 22 | char *name; |
23 | // Parameters | ||
24 | StringView *params; | ||
19 | } Chunk; | 25 | } Chunk; |
20 | 26 | ||
21 | #define NEW_CHUNK(NAME) chunk_init((StringView){(NAME), sizeof(NAME)}) | 27 | #define NEW_CHUNK(NAME) chunk_init((StringView){(NAME), sizeof(NAME)}) |
diff --git a/src/bytecode/compiler.h b/src/bytecode/compiler.h index e20b4f1..9389ab4 100755 --- a/src/bytecode/compiler.h +++ b/src/bytecode/compiler.h | |||
@@ -106,9 +106,6 @@ compile_list_binary_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) { | |||
106 | break; | 106 | break; |
107 | } | 107 | } |
108 | parse_tree(chunk, compiler); | 108 | parse_tree(chunk, compiler); |
109 | if (tok.type == TOKEN_SYMBOL) { | ||
110 | add_code(chunk, OP_GET, tok.line, tok.column); | ||
111 | } | ||
112 | n++; | 109 | n++; |
113 | } | 110 | } |
114 | emit_constant(chunk, start, FIXNUM_VAL(n)); | 111 | emit_constant(chunk, start, FIXNUM_VAL(n)); |
@@ -142,9 +139,6 @@ compile_list_unary_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) { | |||
142 | return; | 139 | return; |
143 | } | 140 | } |
144 | parse_tree(chunk, compiler); | 141 | parse_tree(chunk, compiler); |
145 | if (tok.type == TOKEN_SYMBOL) { | ||
146 | add_code(chunk, OP_GET, tok.line, tok.column); | ||
147 | } | ||
148 | add_code(chunk, op, start.line, start.column); | 142 | add_code(chunk, op, start.line, start.column); |
149 | n++; | 143 | n++; |
150 | if (n > 1) { | 144 | if (n > 1) { |
@@ -231,9 +225,6 @@ compile_declare_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) { | |||
231 | return; | 225 | return; |
232 | } | 226 | } |
233 | parse_tree(chunk, compiler); | 227 | parse_tree(chunk, compiler); |
234 | if (expr.type == TOKEN_SYMBOL) { | ||
235 | add_code(chunk, OP_GET, expr.line, expr.column); | ||
236 | } | ||
237 | if (peek_token(compiler).type != TOKEN_RPAREN) { | 228 | if (peek_token(compiler).type != TOKEN_RPAREN) { |
238 | error_push((Error){ | 229 | error_push((Error){ |
239 | .type = ERR_TYPE_COMPILER, | 230 | .type = ERR_TYPE_COMPILER, |
@@ -250,8 +241,44 @@ compile_declare_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) { | |||
250 | void | 241 | void |
251 | compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) { | 242 | compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) { |
252 | Object fun = make_lambda(name); | 243 | Object fun = make_lambda(name); |
253 | // FIXME: skipping arguments for now. Assuming nil. | 244 | |
254 | next_token(compiler); | 245 | // Prepeare parameters. |
246 | Token tok = next_token(compiler); | ||
247 | if (tok.type == TOKEN_LPAREN){ | ||
248 | while (has_next_token(compiler)) { | ||
249 | Token tok = next_token(compiler); | ||
250 | if (tok.type == TOKEN_EOF) { | ||
251 | error_push((Error){ | ||
252 | .type = ERR_TYPE_COMPILER, | ||
253 | .value = ERR_UNBALANCED_PAREN, | ||
254 | .line = start.line, | ||
255 | .col = start.column, | ||
256 | }); | ||
257 | return; | ||
258 | } | ||
259 | if (tok.type == TOKEN_RPAREN) { | ||
260 | break; | ||
261 | } | ||
262 | if (tok.type != TOKEN_SYMBOL) { | ||
263 | error_push((Error){ | ||
264 | .type = ERR_TYPE_COMPILER, | ||
265 | .value = ERR_WRONG_ARG_TYPE, | ||
266 | .line = tok.line, | ||
267 | .col = tok.column, | ||
268 | }); | ||
269 | return; | ||
270 | } | ||
271 | array_push(fun.chunk->params, tok.value); | ||
272 | } | ||
273 | } else if (tok.type != TOKEN_NIL) { | ||
274 | error_push((Error){ | ||
275 | .type = ERR_TYPE_COMPILER, | ||
276 | .value = ERR_WRONG_ARG_TYPE, | ||
277 | .line = tok.line, | ||
278 | .col = tok.column, | ||
279 | }); | ||
280 | return; | ||
281 | } | ||
255 | 282 | ||
256 | // Compile body. | 283 | // Compile body. |
257 | while (has_next_token(compiler)) { | 284 | while (has_next_token(compiler)) { |
@@ -297,6 +324,7 @@ compile_call_op(Chunk *chunk, Compiler *compiler, Token start, Token name) { | |||
297 | // FIXME: skipping arguments for now. Assuming nil. | 324 | // FIXME: skipping arguments for now. Assuming nil. |
298 | 325 | ||
299 | // Compile body. | 326 | // Compile body. |
327 | size_t n = 0; | ||
300 | while (has_next_token(compiler)) { | 328 | while (has_next_token(compiler)) { |
301 | Token tok = peek_token(compiler); | 329 | Token tok = peek_token(compiler); |
302 | if (tok.type == TOKEN_EOF) { | 330 | if (tok.type == TOKEN_EOF) { |
@@ -312,6 +340,7 @@ compile_call_op(Chunk *chunk, Compiler *compiler, Token start, Token name) { | |||
312 | next_token(compiler); | 340 | next_token(compiler); |
313 | break; | 341 | break; |
314 | } | 342 | } |
343 | parse_tree(chunk, compiler); | ||
315 | } | 344 | } |
316 | if (name.type == TOKEN_SYMBOL) { | 345 | if (name.type == TOKEN_SYMBOL) { |
317 | Object obj = make_symbol(name.value); | 346 | Object obj = make_symbol(name.value); |
@@ -471,8 +500,24 @@ parse_tree(Chunk *chunk, Compiler *compiler) { | |||
471 | return; | 500 | return; |
472 | } break; | 501 | } break; |
473 | case TOKEN_SYMBOL: { | 502 | case TOKEN_SYMBOL: { |
474 | Object obj = make_symbol(tok.value); | 503 | bool found = false; |
475 | emit_constant(chunk, tok, obj); | 504 | size_t idx = 0; |
505 | // NOTE: This is dumb and potentially slow. | ||
506 | for (size_t i = 0; i < array_size(chunk->params); i++) { | ||
507 | if (sv_equal(&tok.value, &chunk->params[i])) { | ||
508 | found = true; | ||
509 | idx = i; | ||
510 | break; | ||
511 | } | ||
512 | } | ||
513 | if (!found) { | ||
514 | Object obj = make_symbol(tok.value); | ||
515 | emit_constant(chunk, tok, obj); | ||
516 | return; | ||
517 | } | ||
518 | |||
519 | add_code(chunk, OP_LOCAL, tok.line, tok.column); | ||
520 | add_code(chunk, idx, tok.line, tok.column); | ||
476 | return; | 521 | return; |
477 | } break; | 522 | } break; |
478 | case TOKEN_NIL: { | 523 | case TOKEN_NIL: { |
@@ -500,14 +545,16 @@ compile(Token *tokens) { | |||
500 | .tokens = tokens, | 545 | .tokens = tokens, |
501 | .current = 0, | 546 | .current = 0, |
502 | }; | 547 | }; |
503 | Token start_tok = peek_token(&compiler); | 548 | Token main_start = peek_token(&compiler); |
504 | while (has_next_token(&compiler) && peek_token(&compiler).type != TOKEN_EOF) { | 549 | while (has_next_token(&compiler)) { |
550 | Token start = peek_token(&compiler); | ||
505 | parse_tree(chunk, &compiler); | 551 | parse_tree(chunk, &compiler); |
506 | if (peek_token(&compiler).type != TOKEN_EOF) { | 552 | if (peek_token(&compiler).type == TOKEN_EOF) { |
507 | add_code(chunk, OP_DROP, start_tok.line, start_tok.column); | 553 | break; |
508 | } | 554 | } |
555 | add_code(chunk, OP_DROP, start.line, start.column); | ||
509 | } | 556 | } |
510 | add_code(chunk, OP_RETURN, start_tok.line, start_tok.column); | 557 | add_code(chunk, OP_RETURN, main_start.line, main_start.column); |
511 | return chunk; | 558 | return chunk; |
512 | } | 559 | } |
513 | 560 | ||
diff --git a/src/bytecode/debug.h b/src/bytecode/debug.h index 8c4a2eb..06d48b0 100755 --- a/src/bytecode/debug.h +++ b/src/bytecode/debug.h | |||
@@ -10,6 +10,7 @@ size_t disassemble_instruction(Chunk *chunk, size_t offset); | |||
10 | static const char* ops_str[] = { | 10 | static const char* ops_str[] = { |
11 | // Load/store ops. | 11 | // Load/store ops. |
12 | [OP_CONSTANT] = "OP_CONSTANT", | 12 | [OP_CONSTANT] = "OP_CONSTANT", |
13 | [OP_LOCAL] = "OP_LOCAL", | ||
13 | [OP_DEF] = "OP_DEF", | 14 | [OP_DEF] = "OP_DEF", |
14 | [OP_SET] = "OP_SET", | 15 | [OP_SET] = "OP_SET", |
15 | [OP_GET] = "OP_GET", | 16 | [OP_GET] = "OP_GET", |
@@ -74,6 +75,11 @@ disassemble_instruction(Chunk *chunk, size_t offset) { | |||
74 | } | 75 | } |
75 | u8 instruction = chunk->code[offset]; | 76 | u8 instruction = chunk->code[offset]; |
76 | switch (instruction) { | 77 | switch (instruction) { |
78 | case OP_LOCAL: { | ||
79 | u8 local = chunk->code[offset + 1]; | ||
80 | printf("%-16s %4d\n", ops_str[instruction], local); | ||
81 | return offset + 2; | ||
82 | } break; | ||
77 | case OP_CONSTANT: { | 83 | case OP_CONSTANT: { |
78 | u8 constant = chunk->code[offset + 1]; | 84 | u8 constant = chunk->code[offset + 1]; |
79 | printf("%-16s %4d -> ", ops_str[instruction], constant); | 85 | printf("%-16s %4d -> ", ops_str[instruction], constant); |
diff --git a/src/bytecode/ops.h b/src/bytecode/ops.h index 7a43b91..501a37f 100755 --- a/src/bytecode/ops.h +++ b/src/bytecode/ops.h | |||
@@ -4,6 +4,7 @@ | |||
4 | typedef enum Ops { | 4 | typedef enum Ops { |
5 | // Load/store ops. | 5 | // Load/store ops. |
6 | OP_CONSTANT, | 6 | OP_CONSTANT, |
7 | OP_LOCAL, | ||
7 | OP_DEF, | 8 | OP_DEF, |
8 | OP_SET, | 9 | OP_SET, |
9 | OP_GET, | 10 | OP_GET, |
diff --git a/src/bytecode/vm.h b/src/bytecode/vm.h index 0ce6dec..98c94fa 100755 --- a/src/bytecode/vm.h +++ b/src/bytecode/vm.h | |||
@@ -19,6 +19,8 @@ typedef struct CallFrame { | |||
19 | // Object *locals; | 19 | // Object *locals; |
20 | // Return counter. | 20 | // Return counter. |
21 | u8 *rp; | 21 | u8 *rp; |
22 | // Starting point of the locals for this procedure. | ||
23 | size_t stack_offset; | ||
22 | } CallFrame; | 24 | } CallFrame; |
23 | 25 | ||
24 | typedef struct VM { | 26 | typedef struct VM { |
@@ -149,8 +151,7 @@ vm_interpret(VM *vm) { | |||
149 | return; | 151 | return; |
150 | } | 152 | } |
151 | 153 | ||
152 | u8 *last = frame->chunk->code + array_size(frame->chunk->code); | 154 | while (true) { |
153 | while (vm->pc < last) { | ||
154 | #ifdef DEBUG_TRACE_EXECUTION | 155 | #ifdef DEBUG_TRACE_EXECUTION |
155 | printf("stack: [ "); | 156 | printf("stack: [ "); |
156 | for (size_t i = 0; i < array_size(vm->stack); i++) { | 157 | for (size_t i = 0; i < array_size(vm->stack); i++) { |
@@ -164,6 +165,10 @@ vm_interpret(VM *vm) { | |||
164 | #endif | 165 | #endif |
165 | u8 instruction = *vm->pc++; | 166 | u8 instruction = *vm->pc++; |
166 | switch (instruction) { | 167 | switch (instruction) { |
168 | case OP_LOCAL: { | ||
169 | u8 local = *vm->pc++; | ||
170 | array_push(vm->stack, vm->stack[frame->stack_offset + local]); | ||
171 | } break; | ||
167 | case OP_CONSTANT: { | 172 | case OP_CONSTANT: { |
168 | u8 constant = *vm->pc++; | 173 | u8 constant = *vm->pc++; |
169 | Object obj = frame->chunk->constants[constant]; | 174 | Object obj = frame->chunk->constants[constant]; |
@@ -256,7 +261,11 @@ vm_interpret(VM *vm) { | |||
256 | } break; | 261 | } break; |
257 | case OP_CALL: { | 262 | case OP_CALL: { |
258 | Object proc = array_pop(vm->stack); | 263 | Object proc = array_pop(vm->stack); |
259 | CallFrame new_frame = (CallFrame){proc.chunk, vm->pc}; | 264 | CallFrame new_frame = (CallFrame){ |
265 | .chunk = proc.chunk, | ||
266 | .rp = vm->pc, | ||
267 | .stack_offset = array_size(vm->stack) - array_size(proc.chunk->params), | ||
268 | }; | ||
260 | array_push(vm->frames, new_frame); | 269 | array_push(vm->frames, new_frame); |
261 | frame = &vm->frames[array_size(vm->frames) - 1]; | 270 | frame = &vm->frames[array_size(vm->frames) - 1]; |
262 | vm->pc = frame->chunk->code; | 271 | vm->pc = frame->chunk->code; |
@@ -272,6 +281,9 @@ vm_interpret(VM *vm) { | |||
272 | } | 281 | } |
273 | vm->pc = frame->rp; | 282 | vm->pc = frame->rp; |
274 | array_head(vm->frames)->size--; | 283 | array_head(vm->frames)->size--; |
284 | Object ret = array_pop(vm->stack); | ||
285 | array_head(vm->stack)->size = frame->stack_offset; | ||
286 | array_push(vm->stack, ret); | ||
275 | frame = &vm->frames[array_size(vm->frames) - 1]; | 287 | frame = &vm->frames[array_size(vm->frames) - 1]; |
276 | } break; | 288 | } break; |
277 | case OP_DROP: { | 289 | case OP_DROP: { |