diff options
Diffstat (limited to 'src/bytecode')
-rwxr-xr-x | src/bytecode/compiler.h | 126 | ||||
-rwxr-xr-x | src/bytecode/vm.h | 19 |
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 @@ | |||
9 | typedef struct Scope { | 9 | typedef 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 | ||
15 | typedef struct Compiler { | 15 | typedef struct Compiler { |
@@ -80,7 +80,7 @@ find_local_index(Scope *scope, Token tok) { | |||
80 | ssize_t | 80 | ssize_t |
81 | find_captued_index(Scope *scope, Token tok) { | 81 | find_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 | ||
135 | void | ||
136 | parse_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 | |||
135 | void parse_tree(Chunk *chunk, Compiler *compiler); | 183 | void parse_tree(Chunk *chunk, Compiler *compiler); |
136 | 184 | ||
137 | void | 185 | void |
@@ -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); |