aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-10-28 10:40:22 +0200
committerBad Diode <bd@badd10de.dev>2021-10-28 10:40:22 +0200
commitd04aea3c5875cd2859d6ab961256b11189c49839 (patch)
tree911b6df338dde38ed28c447cfba999bcc3cb1743
parent4515d21211263a2c7367ec20ec01ce9efaae1d18 (diff)
downloadbdl-d04aea3c5875cd2859d6ab961256b11189c49839.tar.gz
bdl-d04aea3c5875cd2859d6ab961256b11189c49839.zip
Prepare for closure capture
-rwxr-xr-xMakefile4
-rw-r--r--src/bytecode/chunk.c2
-rwxr-xr-xsrc/bytecode/compiler.h72
-rwxr-xr-xsrc/bytecode/debug.h2
-rw-r--r--src/bytecode/hashtable.h4
-rwxr-xr-xsrc/bytecode/main.c3
-rw-r--r--src/bytecode/objects.c29
-rwxr-xr-xsrc/bytecode/objects.h30
-rwxr-xr-xsrc/bytecode/ops.h3
-rwxr-xr-xsrc/bytecode/vm.h53
10 files changed, 139 insertions, 63 deletions
diff --git a/Makefile b/Makefile
index 30784b2..05656f9 100755
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@ CFLAGS += $(INC_FLAGS)
20LDFLAGS := 20LDFLAGS :=
21LDLIBS := 21LDLIBS :=
22RELEASE_CFLAGS := -DNDEBUG -O2 -static 22RELEASE_CFLAGS := -DNDEBUG -O2 -static
23DEBUG_CFLAGS := -DDEBUG -O0 -g -fsanitize=address 23DEBUG_CFLAGS := -DDEBUG -O0 -g
24 24
25.PHONY: build tests run clean 25.PHONY: build tests run clean
26 26
@@ -30,6 +30,8 @@ DEBUG_CFLAGS := -DDEBUG -O0 -g -fsanitize=address
30DEBUG ?= 0 30DEBUG ?= 0
31ifeq ($(DEBUG), 1) 31ifeq ($(DEBUG), 1)
32 CFLAGS += $(DEBUG_CFLAGS) 32 CFLAGS += $(DEBUG_CFLAGS)
33else ifeq ($(DEBUG), 2)
34 CFLAGS += $(DEBUG_CFLAGS) -fsanitize=address
33else 35else
34 CFLAGS += $(RELEASE_CFLAGS) 36 CFLAGS += $(RELEASE_CFLAGS)
35endif 37endif
diff --git a/src/bytecode/chunk.c b/src/bytecode/chunk.c
index 8ff6acf..af4a3a2 100644
--- a/src/bytecode/chunk.c
+++ b/src/bytecode/chunk.c
@@ -19,7 +19,7 @@ chunk_free(Chunk *chunk) {
19 array_free(chunk->code); 19 array_free(chunk->code);
20 for (size_t i = 0; i < array_size(chunk->constants); i++) { 20 for (size_t i = 0; i < array_size(chunk->constants); i++) {
21 Object obj = chunk->constants[i]; 21 Object obj = chunk->constants[i];
22 object_free(obj); 22 object_free(&obj);
23 } 23 }
24 array_free(chunk->constants); 24 array_free(chunk->constants);
25 array_free(chunk->lines); 25 array_free(chunk->lines);
diff --git a/src/bytecode/compiler.h b/src/bytecode/compiler.h
index 124c345..09e49a1 100755
--- a/src/bytecode/compiler.h
+++ b/src/bytecode/compiler.h
@@ -9,6 +9,7 @@
9typedef struct Scope { 9typedef struct Scope {
10 StringView *params; 10 StringView *params;
11 StringView *locals; 11 StringView *locals;
12 StringView *captured;
12} Scope; 13} Scope;
13 14
14typedef struct Compiler { 15typedef struct Compiler {
@@ -33,6 +34,7 @@ enter_scope(Compiler *compiler) {
33 Scope *scope = &compiler->scopes[compiler->scope_depth++]; 34 Scope *scope = &compiler->scopes[compiler->scope_depth++];
34 array_init(scope->params, 0); 35 array_init(scope->params, 0);
35 array_init(scope->locals, 0); 36 array_init(scope->locals, 0);
37 array_init(scope->captured, 0);
36} 38}
37 39
38void 40void
@@ -40,6 +42,7 @@ exit_scope(Compiler *compiler) {
40 Scope *scope = &compiler->scopes[--compiler->scope_depth]; 42 Scope *scope = &compiler->scopes[--compiler->scope_depth];
41 array_free(scope->params); 43 array_free(scope->params);
42 array_free(scope->locals); 44 array_free(scope->locals);
45 array_free(scope->captured);
43} 46}
44 47
45Scope * 48Scope *
@@ -74,6 +77,16 @@ find_local_index(Scope *scope, Token tok) {
74 return -1; 77 return -1;
75} 78}
76 79
80ssize_t
81find_captued_index(Scope *scope, Token tok) {
82 for (size_t i = 0; i < array_size(scope->captured); i++) {
83 if (sv_equal(&tok.value, &scope->captured[i])) {
84 return i;
85 }
86 }
87 return -1;
88}
89
77void 90void
78emit_constant(Chunk *chunk, Token tok, Object obj) { 91emit_constant(Chunk *chunk, Token tok, Object obj) {
79 size_t prev_size = array_size(chunk->constants); 92 size_t prev_size = array_size(chunk->constants);
@@ -84,7 +97,7 @@ emit_constant(Chunk *chunk, Token tok, Object obj) {
84 // If the non value constant was already present we need to properly free 97 // If the non value constant was already present we need to properly free
85 // the memory from the object given to this function. 98 // the memory from the object given to this function.
86 if (prev_size == array_size(chunk->constants)) { 99 if (prev_size == array_size(chunk->constants)) {
87 object_free(obj); 100 object_free(&obj);
88 } 101 }
89} 102}
90 103
@@ -329,7 +342,8 @@ compile_declare_op(Chunk *chunk, Compiler *compiler, Token start, Ops op) {
329void 342void
330compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) { 343compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) {
331 enter_scope(compiler); 344 enter_scope(compiler);
332 Object fun = make_lambda(name); 345 Chunk *proc_chunk = chunk_init(name);
346 Object fun = make_lambda(proc_chunk);
333 347
334 // Prepeare parameters. 348 // Prepeare parameters.
335 Token tok = next_token(compiler); 349 Token tok = next_token(compiler);
@@ -371,8 +385,8 @@ compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) {
371 } 385 }
372 array_push(scope->params, tok.value); 386 array_push(scope->params, tok.value);
373 array_push(scope->locals, tok.value); 387 array_push(scope->locals, tok.value);
374 fun.chunk->n_params++; 388 fun.closure->chunk->n_params++;
375 fun.chunk->n_locals++; 389 fun.closure->chunk->n_locals++;
376 } 390 }
377 } else if (tok.type != TOKEN_NIL) { 391 } else if (tok.type != TOKEN_NIL) {
378 error_push((Error){ 392 error_push((Error){
@@ -400,9 +414,9 @@ compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) {
400 next_token(compiler); 414 next_token(compiler);
401 break; 415 break;
402 } 416 }
403 parse_tree(fun.chunk, compiler); 417 parse_tree(fun.closure->chunk, compiler);
404 } 418 }
405 add_code(fun.chunk, OP_RETURN, start.line, start.column); 419 add_code(fun.closure->chunk, OP_RETURN, start.line, start.column);
406 emit_constant(chunk, start, fun); 420 emit_constant(chunk, start, fun);
407 exit_scope(compiler); 421 exit_scope(compiler);
408} 422}
@@ -609,23 +623,49 @@ parse_tree(Chunk *chunk, Compiler *compiler) {
609 } break; 623 } break;
610 case TOKEN_SYMBOL: { 624 case TOKEN_SYMBOL: {
611 if (compiler->scope_depth > 1) { 625 if (compiler->scope_depth > 1) {
612 size_t depth = compiler->scope_depth - 1; 626 Scope *current_scope = get_current_scope(compiler);
613 ssize_t idx = -1; 627 ssize_t idx = -1;
614 do { 628 // Check if the variable was already captured.
615 Scope *scope = &compiler->scopes[depth]; 629 idx = find_captued_index(current_scope, tok);
616 idx = find_local_index(scope, tok); 630 if (idx >= 0) {
617 if (idx >= 0) { 631 emit_constant(chunk, tok, FIXNUM_VAL(idx));
618 break; 632 add_code(chunk, OP_CAPTURED, tok.line, tok.column);
619 } 633 return;
620 depth--; 634 }
621 } while (depth > 0);
622 635
636 // Check current scope locals. If we find it, emit OP_LOCAL.
637 idx = find_local_index(current_scope, tok);
623 if (idx >= 0) { 638 if (idx >= 0) {
624 emit_constant(chunk, tok, FIXNUM_VAL(depth));
625 emit_constant(chunk, tok, FIXNUM_VAL(idx)); 639 emit_constant(chunk, tok, FIXNUM_VAL(idx));
626 add_code(chunk, OP_LOCAL, tok.line, tok.column); 640 add_code(chunk, OP_LOCAL, tok.line, tok.column);
627 return; 641 return;
628 } 642 }
643
644 // Descend scopes, if we find the symbol at a different depth,
645 // we need to capture the variable.
646 size_t depth = compiler->scope_depth - 2;
647 while (depth > 0) {
648 Scope *scope = &compiler->scopes[depth];
649 idx = find_local_index(scope, tok);
650 if (idx >= 0) {
651 // Capture this local.
652 emit_constant(chunk, tok, FIXNUM_VAL(idx));
653 emit_constant(chunk, tok, FIXNUM_VAL(depth));
654 add_code(chunk, OP_CAPTURE_LOCAL, tok.line, tok.column);
655
656 // Put captured variable on stack.
657 ssize_t captured_idx = array_size(current_scope->captured);
658 emit_constant(chunk, tok, FIXNUM_VAL(captured_idx));
659 add_code(chunk, OP_CAPTURED, tok.line, tok.column);
660 array_push(current_scope->captured, tok.value);
661 return;
662 }
663 depth--;
664 }
665
666 // TODO: Capture globals?
667
668 // NOTE: set! must know how to deal also with captured vars.
629 } 669 }
630 670
631 Object obj = make_symbol(tok.value); 671 Object obj = make_symbol(tok.value);
diff --git a/src/bytecode/debug.h b/src/bytecode/debug.h
index e34b65f..7078744 100755
--- a/src/bytecode/debug.h
+++ b/src/bytecode/debug.h
@@ -11,6 +11,8 @@ 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_LOCAL] = "OP_LOCAL",
14 [OP_CAPTURED] = "OP_CAPTURED",
15 [OP_CAPTURE_LOCAL] = "OP_CAPTURE_LOCAL",
14 [OP_DEF_LOCAL] = "OP_DEF_LOCAL", 16 [OP_DEF_LOCAL] = "OP_DEF_LOCAL",
15 [OP_SET_LOCAL] = "OP_SET_LOCAL", 17 [OP_SET_LOCAL] = "OP_SET_LOCAL",
16 [OP_DEF] = "OP_DEF", 18 [OP_DEF] = "OP_DEF",
diff --git a/src/bytecode/hashtable.h b/src/bytecode/hashtable.h
index 1f55048..7c0c380 100644
--- a/src/bytecode/hashtable.h
+++ b/src/bytecode/hashtable.h
@@ -151,7 +151,7 @@ _ht_maybe_grow(HashTable *table) {
151 // Free old arrays. 151 // Free old arrays.
152 array_free(old_pairs); 152 array_free(old_pairs);
153 for (size_t i = 0; i < array_size(old_keys); i++) { 153 for (size_t i = 0; i < array_size(old_keys); i++) {
154 object_free(old_keys[i]); 154 object_free(&old_keys[i]);
155 } 155 }
156 array_free(old_keys); 156 array_free(old_keys);
157 array_free(old_values); 157 array_free(old_values);
@@ -198,7 +198,7 @@ ht_free(HashTable *table) {
198 } 198 }
199 array_free(table->pairs); 199 array_free(table->pairs);
200 for (size_t i = 0; i < array_size(table->keys); i++) { 200 for (size_t i = 0; i < array_size(table->keys); i++) {
201 object_free(table->keys[i]); 201 object_free(&table->keys[i]);
202 } 202 }
203 array_free(table->keys); 203 array_free(table->keys);
204 array_free(table->values); 204 array_free(table->values);
diff --git a/src/bytecode/main.c b/src/bytecode/main.c
index 7f2042e..4b80f71 100755
--- a/src/bytecode/main.c
+++ b/src/bytecode/main.c
@@ -57,8 +57,9 @@ process_source(const StringView *source) {
57#endif 57#endif
58 58
59 // Interpret chunk. 59 // Interpret chunk.
60 Object main_proc = make_lambda(main);
60 CallFrame frame = (CallFrame){ 61 CallFrame frame = (CallFrame){
61 .chunk = main, 62 .closure = main_proc.closure,
62 }; 63 };
63 array_push(vm.frames, frame); 64 array_push(vm.frames, frame);
64 vm_interpret(&vm); 65 vm_interpret(&vm);
diff --git a/src/bytecode/objects.c b/src/bytecode/objects.c
index 3b4a2eb..c2fb989 100644
--- a/src/bytecode/objects.c
+++ b/src/bytecode/objects.c
@@ -23,11 +23,13 @@ make_symbol(StringView sv) {
23} 23}
24 24
25Object 25Object
26make_lambda(StringView name) { 26make_lambda(Chunk *chunk) {
27 Object obj = { 27 Object obj = {
28 .type = OBJ_TYPE_LAMBDA, 28 .type = OBJ_TYPE_LAMBDA,
29 .chunk = chunk_init(name),
30 }; 29 };
30 obj.closure = malloc(sizeof(Closure));
31 obj.closure->chunk = chunk;
32 array_init(obj.closure->values, 0);
31 return obj; 33 return obj;
32} 34}
33 35
@@ -58,8 +60,9 @@ object_display(Object obj) {
58 // printf(")"); 60 // printf(")");
59 } break; 61 } break;
60 case OBJ_TYPE_LAMBDA: { 62 case OBJ_TYPE_LAMBDA: {
63 Chunk *chunk = obj.closure->chunk;
61 printf("#{procedure:%.*s}", 64 printf("#{procedure:%.*s}",
62 (int)array_size(obj.chunk->name), obj.chunk->name); 65 (int)array_size(chunk->name), chunk->name);
63 } break; 66 } break;
64 case OBJ_TYPE_ERR: { 67 case OBJ_TYPE_ERR: {
65 printf("#{error}"); 68 printf("#{error}");
@@ -69,13 +72,21 @@ object_display(Object obj) {
69} 72}
70 73
71void 74void
72object_free(Object obj) { 75object_free(Object *obj) {
73 if (IS_STRING(obj) || IS_SYMBOL(obj)) { 76 if (IS_STRING(*obj) || IS_SYMBOL(*obj)) {
74 array_free(obj.text); 77 array_free(obj->text);
75 return; 78 return;
76 } 79 }
77 if (IS_LAMBDA(obj)) { 80 if (IS_LAMBDA(*obj)) {
78 chunk_free(obj.chunk); 81 Closure *closure = obj->closure;
82 for (size_t i = 0; i < array_size(closure->values); i++) {
83 object_free(&closure->values[i]);
84 }
85 array_free(closure->values);
86 // NOTE: we are leaking memory without this, we'll need a GC
87 // soon...
88 // chunk_free(closure->chunk);
89 free(closure);
79 } 90 }
80} 91}
81 92
@@ -104,7 +115,7 @@ object_equal(Object a, Object b) {
104 } 115 }
105 } break; 116 } break;
106 case OBJ_TYPE_LAMBDA: { 117 case OBJ_TYPE_LAMBDA: {
107 return a.chunk == b.chunk; 118 return a.closure == b.closure;
108 } break; 119 } break;
109 default: { 120 default: {
110 return false; 121 return false;
diff --git a/src/bytecode/objects.h b/src/bytecode/objects.h
index 6c286b5..a9a7d0f 100755
--- a/src/bytecode/objects.h
+++ b/src/bytecode/objects.h
@@ -17,6 +17,20 @@ typedef enum ObjectType {
17 OBJ_TYPE_ERR, 17 OBJ_TYPE_ERR,
18} ObjectType; 18} ObjectType;
19 19
20typedef struct Object Object;
21
22typedef struct Closure {
23 // Non-owning reference to a chunk.
24 Chunk *chunk;
25 // Captured values for this closure.
26 Object *values;
27} Closure;
28
29// typdef struct ConsCell {
30// struct Object *car;
31// struct Object *cdr;
32// } ConsCell;
33
20typedef struct Object { 34typedef struct Object {
21 ObjectType type; 35 ObjectType type;
22 bool marked; 36 bool marked;
@@ -29,26 +43,18 @@ typedef struct Object {
29 char *text; 43 char *text;
30 44
31 // OBJ_TYPE_PAIR 45 // OBJ_TYPE_PAIR
32 // struct { 46 // ConsCell *cons_cell;
33 // struct Object *car;
34 // struct Object *cdr;
35 // };
36 47
37 // OBJ_TYPE_LAMBDA 48 // OBJ_TYPE_LAMBDA
38 Chunk *chunk; 49 Closure *closure;
39 // struct {
40 // struct Object *params;
41 // struct Object *body;
42 // struct Environment *env;
43 // };
44 }; 50 };
45} Object; 51} Object;
46 52
47Object make_string(StringView sv); 53Object make_string(StringView sv);
48Object make_symbol(StringView sv); 54Object make_symbol(StringView sv);
49Object make_lambda(StringView name); 55Object make_lambda(Chunk *chunk);
50void object_display(Object obj); 56void object_display(Object obj);
51void object_free(Object obj); 57void object_free(Object *obj);
52bool object_equal(Object a, Object b); 58bool object_equal(Object a, Object b);
53Object object_copy(Object src); 59Object object_copy(Object src);
54 60
diff --git a/src/bytecode/ops.h b/src/bytecode/ops.h
index 52c774a..d45c27e 100755
--- a/src/bytecode/ops.h
+++ b/src/bytecode/ops.h
@@ -5,6 +5,9 @@ typedef enum Ops {
5 // Load/store ops. 5 // Load/store ops.
6 OP_CONSTANT, 6 OP_CONSTANT,
7 OP_LOCAL, 7 OP_LOCAL,
8 OP_CAPTURED,
9 OP_CAPTURE_LOCAL,
10 // OP_SET_CAPTURED,
8 OP_DEF_LOCAL, 11 OP_DEF_LOCAL,
9 OP_SET_LOCAL, 12 OP_SET_LOCAL,
10 OP_DEF, 13 OP_DEF,
diff --git a/src/bytecode/vm.h b/src/bytecode/vm.h
index 3fba3d7..a32d0a1 100755
--- a/src/bytecode/vm.h
+++ b/src/bytecode/vm.h
@@ -13,7 +13,7 @@
13 13
14typedef struct CallFrame { 14typedef struct CallFrame {
15 // Current code being run. 15 // Current code being run.
16 Chunk *chunk; 16 Closure *closure;
17 // Current program counter for this call. 17 // Current program counter for this call.
18 // Ref to stack. Is this really needed? 18 // Ref to stack. Is this really needed?
19 // Object *locals; 19 // Object *locals;
@@ -65,7 +65,7 @@ vm_reset(VM *vm) {
65 fprintf(stderr, "stack trace:\n"); \ 65 fprintf(stderr, "stack trace:\n"); \
66 for (ssize_t i = array_size(vm->frames) - 1; i >= 0 ; i--) { \ 66 for (ssize_t i = array_size(vm->frames) - 1; i >= 0 ; i--) { \
67 CallFrame frame = vm->frames[i]; \ 67 CallFrame frame = vm->frames[i]; \
68 Chunk *chunk = frame.chunk; \ 68 Chunk *chunk = frame.closure->chunk; \
69 size_t instruction = vm->pc - chunk->code - 1; \ 69 size_t instruction = vm->pc - chunk->code - 1; \
70 fprintf(stderr, "\t%-4ld -> ", i); \ 70 fprintf(stderr, "\t%-4ld -> ", i); \
71 fprintf(stderr, "%.*s",(int)array_size(chunk->name), chunk->name); \ 71 fprintf(stderr, "%.*s",(int)array_size(chunk->name), chunk->name); \
@@ -80,8 +80,8 @@ vm_reset(VM *vm) {
80 error_push((Error){ \ 80 error_push((Error){ \
81 .type = ERR_TYPE_RUNTIME, \ 81 .type = ERR_TYPE_RUNTIME, \
82 .value = (ERR), \ 82 .value = (ERR), \
83 .line = frame->chunk->lines[vm->pc - frame->chunk->code - 1].line, \ 83 .line = chunk->lines[vm->pc - chunk->code - 1].line, \
84 .col = frame->chunk->lines[vm->pc - frame->chunk->code - 1].col, \ 84 .col = chunk->lines[vm->pc - chunk->code - 1].col, \
85 }); \ 85 }); \
86 STACK_TRACE() \ 86 STACK_TRACE() \
87 return 87 return
@@ -149,10 +149,11 @@ vm_reset(VM *vm) {
149void 149void
150vm_interpret(VM *vm) { 150vm_interpret(VM *vm) {
151 CallFrame *frame = &vm->frames[0]; 151 CallFrame *frame = &vm->frames[0];
152 vm->pc = frame->chunk->code; 152 Chunk *chunk = frame->closure->chunk;
153 vm->pc = chunk->code;
153 frame->rp = NULL; 154 frame->rp = NULL;
154 155
155 if (frame->chunk->code == NULL || array_size(frame->chunk->code) == 0) { 156 if (chunk->code == NULL || array_size(chunk->code) == 0) {
156 error_push((Error){ 157 error_push((Error){
157 .type = ERR_TYPE_RUNTIME, 158 .type = ERR_TYPE_RUNTIME,
158 .value = ERR_EMPTY_CHUNK, 159 .value = ERR_EMPTY_CHUNK,
@@ -170,22 +171,31 @@ vm_interpret(VM *vm) {
170 } 171 }
171 } 172 }
172 printf(" ]\nop: "); 173 printf(" ]\nop: ");
173 disassemble_instruction(frame->chunk, (vm->pc - frame->chunk->code)); 174 disassemble_instruction(chunk, (vm->pc - chunk->code));
174#endif 175#endif
175 u8 instruction = *vm->pc++; 176 u8 instruction = *vm->pc++;
176 switch (instruction) { 177 switch (instruction) {
177 case OP_LOCAL: { 178 case OP_LOCAL: {
178 ssize_t idx = AS_FIXNUM(array_pop(vm->stack)); 179 ssize_t idx = AS_FIXNUM(array_pop(vm->stack));
179 ssize_t depth = AS_FIXNUM(array_pop(vm->stack)); 180 CallFrame frame = vm->frames[array_size(vm->frames) - 1];
180 depth = array_size(vm->frames) - depth;
181 CallFrame frame = vm->frames[depth];
182 array_push(vm->stack, vm->stack[frame.stack_offset + idx]); 181 array_push(vm->stack, vm->stack[frame.stack_offset + idx]);
183 } break; 182 } break;
184 case OP_CONSTANT: { 183 case OP_CONSTANT: {
185 u8 constant = *vm->pc++; 184 u8 constant = *vm->pc++;
186 Object obj = frame->chunk->constants[constant]; 185 Object obj = chunk->constants[constant];
187 array_push(vm->stack, obj); 186 array_push(vm->stack, obj);
188 } break; 187 } break;
188 case OP_CAPTURED: {
189 assert(false && "not implemented");
190 } break;
191 case OP_CAPTURE_LOCAL: {
192 assert(false && "not implemented");
193 // Object value = array_pop(vm->stack);
194 // ssize_t idx = AS_FIXNUM(array_pop(vm->stack));
195 // ssize_t depth = AS_FIXNUM(array_pop(vm->stack));
196 // CallFrame frame = vm->frames[depth];
197 // vm->stack[frame.stack_offset + idx] = value;
198 } break;
189 case OP_DEF_LOCAL: { 199 case OP_DEF_LOCAL: {
190 Object value = array_pop(vm->stack); 200 Object value = array_pop(vm->stack);
191 ssize_t idx = AS_FIXNUM(array_pop(vm->stack)); 201 ssize_t idx = AS_FIXNUM(array_pop(vm->stack));
@@ -194,8 +204,7 @@ vm_interpret(VM *vm) {
194 case OP_SET_LOCAL: { 204 case OP_SET_LOCAL: {
195 Object value = array_pop(vm->stack); 205 Object value = array_pop(vm->stack);
196 ssize_t idx = AS_FIXNUM(array_pop(vm->stack)); 206 ssize_t idx = AS_FIXNUM(array_pop(vm->stack));
197 ssize_t depth = AS_FIXNUM(array_pop(vm->stack)); 207 CallFrame frame = vm->frames[array_size(vm->frames) - 1];
198 CallFrame frame = vm->frames[depth];
199 vm->stack[frame.stack_offset + idx] = value; 208 vm->stack[frame.stack_offset + idx] = value;
200 } break; 209 } break;
201 case OP_DEF: { 210 case OP_DEF: {
@@ -290,8 +299,8 @@ vm_interpret(VM *vm) {
290 // Check the number of arguments is correct. 299 // Check the number of arguments is correct.
291 // NOTE: This is probably better handled at compilation, but for 300 // NOTE: This is probably better handled at compilation, but for
292 // now this is simpler to implement. 301 // now this is simpler to implement.
293 ssize_t n_params = proc.chunk->n_params; 302 ssize_t n_params = proc.closure->chunk->n_params;
294 ssize_t n_locals = proc.chunk->n_locals - n_params; 303 ssize_t n_locals = proc.closure->chunk->n_locals - n_params;
295 if (n_args < n_params) { 304 if (n_args < n_params) {
296 RUNTIME_ERROR(ERR_NOT_ENOUGH_ARGS); 305 RUNTIME_ERROR(ERR_NOT_ENOUGH_ARGS);
297 } else if (n_args > n_params) { 306 } else if (n_args > n_params) {
@@ -299,20 +308,21 @@ vm_interpret(VM *vm) {
299 } 308 }
300 309
301#ifdef DEBUG 310#ifdef DEBUG
302 disassemble_chunk(proc.chunk); 311 disassemble_chunk(proc.closure->chunk);
303 printf("n_locals: %ld\n", n_locals); 312 printf("n_locals: %ld\n", n_locals);
304 printf("n_params: %ld\n", n_params); 313 printf("n_params: %ld\n", n_params);
305#endif 314#endif
306 // Tail-call optimization. 315 // Tail-call optimization.
307 if (proc.chunk != frame->chunk || *vm->pc != OP_RETURN) { 316 if (proc.closure->chunk != chunk || *vm->pc != OP_RETURN) {
308 // Prepare new call frame. 317 // Prepare new call frame.
309 CallFrame new_frame = (CallFrame){ 318 CallFrame new_frame = (CallFrame){
310 .chunk = proc.chunk, 319 .closure = proc.closure,
311 .rp = vm->pc, 320 .rp = vm->pc,
312 .stack_offset = array_size(vm->stack) - n_params, 321 .stack_offset = array_size(vm->stack) - n_params,
313 }; 322 };
314 array_push(vm->frames, new_frame); 323 array_push(vm->frames, new_frame);
315 frame = &vm->frames[array_size(vm->frames) - 1]; 324 frame = &vm->frames[array_size(vm->frames) - 1];
325 chunk = frame->closure->chunk;
316 326
317 // Prepare local slots. 327 // Prepare local slots.
318 for (ssize_t i = 0; i < n_locals; i++) { 328 for (ssize_t i = 0; i < n_locals; i++) {
@@ -330,7 +340,7 @@ vm_interpret(VM *vm) {
330 size_t offset = frame->stack_offset + n_params + n_locals; 340 size_t offset = frame->stack_offset + n_params + n_locals;
331 array_head(vm->stack)->size = offset; 341 array_head(vm->stack)->size = offset;
332 } 342 }
333 vm->pc = frame->chunk->code; 343 vm->pc = chunk->code;
334 } break; 344 } break;
335 case OP_RETURN: { 345 case OP_RETURN: {
336 if (frame->rp == NULL) { 346 if (frame->rp == NULL) {
@@ -347,6 +357,7 @@ vm_interpret(VM *vm) {
347 array_head(vm->stack)->size = frame->stack_offset; 357 array_head(vm->stack)->size = frame->stack_offset;
348 array_push(vm->stack, ret); 358 array_push(vm->stack, ret);
349 frame = &vm->frames[array_size(vm->frames) - 1]; 359 frame = &vm->frames[array_size(vm->frames) - 1];
360 chunk = frame->closure->chunk;
350 } break; 361 } break;
351 case OP_DROP: { 362 case OP_DROP: {
352 array_head(vm->stack)->size = 0; 363 array_head(vm->stack)->size = 0;
@@ -360,8 +371,8 @@ vm_interpret(VM *vm) {
360 error_push((Error){ 371 error_push((Error){
361 .type = ERR_TYPE_RUNTIME, 372 .type = ERR_TYPE_RUNTIME,
362 .value = ERR_PC_OOB, 373 .value = ERR_PC_OOB,
363 .line = frame->chunk->lines[0].line, 374 .line = chunk->lines[0].line,
364 .col = frame->chunk->lines[0].col, 375 .col = chunk->lines[0].col,
365 }); 376 });
366} 377}
367 378