diff options
author | Bad Diode <bd@badd10de.dev> | 2021-10-28 12:00:24 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-10-28 12:00:24 +0200 |
commit | 8c8353dab0b4a7f6ed9332f968a5b5da67375f62 (patch) | |
tree | 9434e0197b32dbb6c65361bef920fb3190dcfc71 /src/bytecode/compiler.h | |
parent | d04aea3c5875cd2859d6ab961256b11189c49839 (diff) | |
download | bdl-8c8353dab0b4a7f6ed9332f968a5b5da67375f62.tar.gz bdl-8c8353dab0b4a7f6ed9332f968a5b5da67375f62.zip |
Add tentative implementation of captured variables
Diffstat (limited to 'src/bytecode/compiler.h')
-rwxr-xr-x | src/bytecode/compiler.h | 126 |
1 files changed, 74 insertions, 52 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: { |