aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-10-28 12:00:24 +0200
committerBad Diode <bd@badd10de.dev>2021-10-28 12:00:24 +0200
commit8c8353dab0b4a7f6ed9332f968a5b5da67375f62 (patch)
tree9434e0197b32dbb6c65361bef920fb3190dcfc71
parentd04aea3c5875cd2859d6ab961256b11189c49839 (diff)
downloadbdl-8c8353dab0b4a7f6ed9332f968a5b5da67375f62.tar.gz
bdl-8c8353dab0b4a7f6ed9332f968a5b5da67375f62.zip
Add tentative implementation of captured variables
-rwxr-xr-xsrc/bytecode/compiler.h126
-rwxr-xr-xsrc/bytecode/vm.h19
2 files changed, 84 insertions, 61 deletions
diff --git a/src/bytecode/compiler.h b/src/bytecode/compiler.h
index 09e49a1..d35c7c6 100755
--- a/src/bytecode/compiler.h
+++ b/src/bytecode/compiler.h
@@ -9,7 +9,7 @@
9typedef struct Scope { 9typedef struct Scope {
10 StringView *params; 10 StringView *params;
11 StringView *locals; 11 StringView *locals;
12 StringView *captured; 12 Token *captured;
13} Scope; 13} Scope;
14 14
15typedef struct Compiler { 15typedef struct Compiler {
@@ -80,7 +80,7 @@ find_local_index(Scope *scope, Token tok) {
80ssize_t 80ssize_t
81find_captued_index(Scope *scope, Token tok) { 81find_captued_index(Scope *scope, Token tok) {
82 for (size_t i = 0; i < array_size(scope->captured); i++) { 82 for (size_t i = 0; i < array_size(scope->captured); i++) {
83 if (sv_equal(&tok.value, &scope->captured[i])) { 83 if (sv_equal(&tok.value, &scope->captured[i].value)) {
84 return i; 84 return i;
85 } 85 }
86 } 86 }
@@ -132,6 +132,54 @@ parse_fixnum(Chunk *chunk, Token tok) {
132 emit_constant(chunk, tok, FIXNUM_VAL(num * sign)); 132 emit_constant(chunk, tok, FIXNUM_VAL(num * sign));
133} 133}
134 134
135void
136parse_symbol(Chunk *chunk, Compiler *compiler, Token tok) {
137 if (compiler->scope_depth > 1) {
138 Scope *current_scope = get_current_scope(compiler);
139 ssize_t idx = -1;
140 // Check if the variable was already captured.
141 idx = find_captued_index(current_scope, tok);
142 if (idx >= 0) {
143 emit_constant(chunk, tok, FIXNUM_VAL(idx));
144 add_code(chunk, OP_CAPTURED, tok.line, tok.column);
145 return;
146 }
147
148 // Check current scope locals. If we find it, emit OP_LOCAL.
149 idx = find_local_index(current_scope, tok);
150 if (idx >= 0) {
151 emit_constant(chunk, tok, FIXNUM_VAL(idx));
152 add_code(chunk, OP_LOCAL, tok.line, tok.column);
153 return;
154 }
155
156 // Descend scopes, if we find the symbol at a different depth,
157 // we need to capture the variable.
158 size_t depth = compiler->scope_depth - 2;
159 while (depth > 0) {
160 Scope *scope = &compiler->scopes[depth];
161 idx = find_local_index(scope, tok);
162 if (idx >= 0) {
163 // Put captured variable on stack.
164 ssize_t captured_idx = array_size(current_scope->captured);
165 emit_constant(chunk, tok, FIXNUM_VAL(captured_idx));
166 add_code(chunk, OP_CAPTURED, tok.line, tok.column);
167 array_push(current_scope->captured, tok);
168 return;
169 }
170 depth--;
171 }
172
173 // TODO: Capture globals?
174
175 // NOTE: set! must know how to deal also with captured vars.
176 }
177
178 Object obj = make_symbol(tok.value);
179 emit_constant(chunk, tok, obj);
180 add_code(chunk, OP_GET, tok.line, tok.column);
181}
182
135void parse_tree(Chunk *chunk, Compiler *compiler); 183void parse_tree(Chunk *chunk, Compiler *compiler);
136 184
137void 185void
@@ -417,7 +465,29 @@ compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) {
417 parse_tree(fun.closure->chunk, compiler); 465 parse_tree(fun.closure->chunk, compiler);
418 } 466 }
419 add_code(fun.closure->chunk, OP_RETURN, start.line, start.column); 467 add_code(fun.closure->chunk, OP_RETURN, start.line, start.column);
420 emit_constant(chunk, start, fun); 468
469 // Prepare closure value capture.
470 Scope *scope = get_current_scope(compiler);
471 size_t n_captured = array_size(scope->captured);
472 if (n_captured > 0) {
473 compiler->scope_depth--;
474 for (ssize_t i = 0; i < n_captured; i++) {
475 Token tok = scope->captured[i];
476 print_token(tok);
477 parse_symbol(chunk, compiler, tok);
478 }
479 // Number of captured values.
480 emit_constant(chunk, tok, FIXNUM_VAL(n_captured));
481
482 // Push created lambda to stack.
483 emit_constant(chunk, start, fun);
484
485 // Emit capture local instruction.
486 add_code(chunk, OP_CAPTURE_LOCAL, tok.line, tok.column);
487 compiler->scope_depth++;
488 } else {
489 emit_constant(chunk, start, fun);
490 }
421 exit_scope(compiler); 491 exit_scope(compiler);
422} 492}
423 493
@@ -622,55 +692,7 @@ parse_tree(Chunk *chunk, Compiler *compiler) {
622 return; 692 return;
623 } break; 693 } break;
624 case TOKEN_SYMBOL: { 694 case TOKEN_SYMBOL: {
625 if (compiler->scope_depth > 1) { 695 parse_symbol(chunk, compiler, tok);
626 Scope *current_scope = get_current_scope(compiler);
627 ssize_t idx = -1;
628 // Check if the variable was already captured.
629 idx = find_captued_index(current_scope, tok);
630 if (idx >= 0) {
631 emit_constant(chunk, tok, FIXNUM_VAL(idx));
632 add_code(chunk, OP_CAPTURED, tok.line, tok.column);
633 return;
634 }
635
636 // Check current scope locals. If we find it, emit OP_LOCAL.
637 idx = find_local_index(current_scope, tok);
638 if (idx >= 0) {
639 emit_constant(chunk, tok, FIXNUM_VAL(idx));
640 add_code(chunk, OP_LOCAL, tok.line, tok.column);
641 return;
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.
669 }
670
671 Object obj = make_symbol(tok.value);
672 emit_constant(chunk, tok, obj);
673 add_code(chunk, OP_GET, tok.line, tok.column);
674 return; 696 return;
675 } break; 697 } break;
676 case TOKEN_NIL: { 698 case TOKEN_NIL: {
diff --git a/src/bytecode/vm.h b/src/bytecode/vm.h
index a32d0a1..f1c525d 100755
--- a/src/bytecode/vm.h
+++ b/src/bytecode/vm.h
@@ -177,8 +177,7 @@ vm_interpret(VM *vm) {
177 switch (instruction) { 177 switch (instruction) {
178 case OP_LOCAL: { 178 case OP_LOCAL: {
179 ssize_t idx = AS_FIXNUM(array_pop(vm->stack)); 179 ssize_t idx = AS_FIXNUM(array_pop(vm->stack));
180 CallFrame frame = vm->frames[array_size(vm->frames) - 1]; 180 array_push(vm->stack, vm->stack[frame->stack_offset + idx]);
181 array_push(vm->stack, vm->stack[frame.stack_offset + idx]);
182 } break; 181 } break;
183 case OP_CONSTANT: { 182 case OP_CONSTANT: {
184 u8 constant = *vm->pc++; 183 u8 constant = *vm->pc++;
@@ -186,15 +185,17 @@ vm_interpret(VM *vm) {
186 array_push(vm->stack, obj); 185 array_push(vm->stack, obj);
187 } break; 186 } break;
188 case OP_CAPTURED: { 187 case OP_CAPTURED: {
189 assert(false && "not implemented"); 188 ssize_t idx = AS_FIXNUM(array_pop(vm->stack));
189 array_push(vm->stack, frame->closure->values[idx]);
190 } break; 190 } break;
191 case OP_CAPTURE_LOCAL: { 191 case OP_CAPTURE_LOCAL: {
192 assert(false && "not implemented"); 192 Object proc = array_pop(vm->stack);
193 // Object value = array_pop(vm->stack); 193 ssize_t n_captured = AS_FIXNUM(array_pop(vm->stack));
194 // ssize_t idx = AS_FIXNUM(array_pop(vm->stack)); 194 for (size_t i = 0; i < n_captured; i++) {
195 // ssize_t depth = AS_FIXNUM(array_pop(vm->stack)); 195 Object value = array_pop(vm->stack);
196 // CallFrame frame = vm->frames[depth]; 196 array_push(proc.closure->values, value);
197 // vm->stack[frame.stack_offset + idx] = value; 197 }
198 array_push(vm->stack, proc);
198 } break; 199 } break;
199 case OP_DEF_LOCAL: { 200 case OP_DEF_LOCAL: {
200 Object value = array_pop(vm->stack); 201 Object value = array_pop(vm->stack);