From 8c8353dab0b4a7f6ed9332f968a5b5da67375f62 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Thu, 28 Oct 2021 12:00:24 +0200 Subject: Add tentative implementation of captured variables --- src/bytecode/compiler.h | 126 ++++++++++++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 52 deletions(-) (limited to 'src/bytecode/compiler.h') 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 @@ typedef struct Scope { StringView *params; StringView *locals; - StringView *captured; + Token *captured; } Scope; typedef struct Compiler { @@ -80,7 +80,7 @@ find_local_index(Scope *scope, Token tok) { ssize_t find_captued_index(Scope *scope, Token tok) { for (size_t i = 0; i < array_size(scope->captured); i++) { - if (sv_equal(&tok.value, &scope->captured[i])) { + if (sv_equal(&tok.value, &scope->captured[i].value)) { return i; } } @@ -132,6 +132,54 @@ parse_fixnum(Chunk *chunk, Token tok) { emit_constant(chunk, tok, FIXNUM_VAL(num * sign)); } +void +parse_symbol(Chunk *chunk, Compiler *compiler, Token tok) { + if (compiler->scope_depth > 1) { + Scope *current_scope = get_current_scope(compiler); + ssize_t idx = -1; + // Check if the variable was already captured. + idx = find_captued_index(current_scope, tok); + if (idx >= 0) { + emit_constant(chunk, tok, FIXNUM_VAL(idx)); + add_code(chunk, OP_CAPTURED, tok.line, tok.column); + return; + } + + // Check current scope locals. If we find it, emit OP_LOCAL. + idx = find_local_index(current_scope, tok); + if (idx >= 0) { + emit_constant(chunk, tok, FIXNUM_VAL(idx)); + add_code(chunk, OP_LOCAL, tok.line, tok.column); + return; + } + + // Descend scopes, if we find the symbol at a different depth, + // we need to capture the variable. + size_t depth = compiler->scope_depth - 2; + while (depth > 0) { + Scope *scope = &compiler->scopes[depth]; + idx = find_local_index(scope, tok); + if (idx >= 0) { + // Put captured variable on stack. + ssize_t captured_idx = array_size(current_scope->captured); + emit_constant(chunk, tok, FIXNUM_VAL(captured_idx)); + add_code(chunk, OP_CAPTURED, tok.line, tok.column); + array_push(current_scope->captured, tok); + return; + } + depth--; + } + + // TODO: Capture globals? + + // NOTE: set! must know how to deal also with captured vars. + } + + Object obj = make_symbol(tok.value); + emit_constant(chunk, tok, obj); + add_code(chunk, OP_GET, tok.line, tok.column); +} + void parse_tree(Chunk *chunk, Compiler *compiler); void @@ -417,7 +465,29 @@ compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) { parse_tree(fun.closure->chunk, compiler); } add_code(fun.closure->chunk, OP_RETURN, start.line, start.column); - emit_constant(chunk, start, fun); + + // Prepare closure value capture. + Scope *scope = get_current_scope(compiler); + size_t n_captured = array_size(scope->captured); + if (n_captured > 0) { + compiler->scope_depth--; + for (ssize_t i = 0; i < n_captured; i++) { + Token tok = scope->captured[i]; + print_token(tok); + parse_symbol(chunk, compiler, tok); + } + // Number of captured values. + emit_constant(chunk, tok, FIXNUM_VAL(n_captured)); + + // Push created lambda to stack. + emit_constant(chunk, start, fun); + + // Emit capture local instruction. + add_code(chunk, OP_CAPTURE_LOCAL, tok.line, tok.column); + compiler->scope_depth++; + } else { + emit_constant(chunk, start, fun); + } exit_scope(compiler); } @@ -622,55 +692,7 @@ parse_tree(Chunk *chunk, Compiler *compiler) { return; } break; case TOKEN_SYMBOL: { - if (compiler->scope_depth > 1) { - Scope *current_scope = get_current_scope(compiler); - ssize_t idx = -1; - // Check if the variable was already captured. - idx = find_captued_index(current_scope, tok); - if (idx >= 0) { - emit_constant(chunk, tok, FIXNUM_VAL(idx)); - add_code(chunk, OP_CAPTURED, tok.line, tok.column); - return; - } - - // Check current scope locals. If we find it, emit OP_LOCAL. - idx = find_local_index(current_scope, tok); - if (idx >= 0) { - emit_constant(chunk, tok, FIXNUM_VAL(idx)); - add_code(chunk, OP_LOCAL, tok.line, tok.column); - return; - } - - // Descend scopes, if we find the symbol at a different depth, - // we need to capture the variable. - size_t depth = compiler->scope_depth - 2; - while (depth > 0) { - Scope *scope = &compiler->scopes[depth]; - idx = find_local_index(scope, tok); - if (idx >= 0) { - // Capture this local. - emit_constant(chunk, tok, FIXNUM_VAL(idx)); - emit_constant(chunk, tok, FIXNUM_VAL(depth)); - add_code(chunk, OP_CAPTURE_LOCAL, tok.line, tok.column); - - // Put captured variable on stack. - ssize_t captured_idx = array_size(current_scope->captured); - emit_constant(chunk, tok, FIXNUM_VAL(captured_idx)); - add_code(chunk, OP_CAPTURED, tok.line, tok.column); - array_push(current_scope->captured, tok.value); - return; - } - depth--; - } - - // TODO: Capture globals? - - // NOTE: set! must know how to deal also with captured vars. - } - - Object obj = make_symbol(tok.value); - emit_constant(chunk, tok, obj); - add_code(chunk, OP_GET, tok.line, tok.column); + parse_symbol(chunk, compiler, tok); return; } break; case TOKEN_NIL: { -- cgit v1.2.1