diff options
author | Bad Diode <bd@badd10de.dev> | 2021-10-28 10:40:22 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-10-28 10:40:22 +0200 |
commit | d04aea3c5875cd2859d6ab961256b11189c49839 (patch) | |
tree | 911b6df338dde38ed28c447cfba999bcc3cb1743 /src/bytecode/compiler.h | |
parent | 4515d21211263a2c7367ec20ec01ce9efaae1d18 (diff) | |
download | bdl-d04aea3c5875cd2859d6ab961256b11189c49839.tar.gz bdl-d04aea3c5875cd2859d6ab961256b11189c49839.zip |
Prepare for closure capture
Diffstat (limited to 'src/bytecode/compiler.h')
-rwxr-xr-x | src/bytecode/compiler.h | 72 |
1 files changed, 56 insertions, 16 deletions
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 @@ | |||
9 | typedef struct Scope { | 9 | typedef struct Scope { |
10 | StringView *params; | 10 | StringView *params; |
11 | StringView *locals; | 11 | StringView *locals; |
12 | StringView *captured; | ||
12 | } Scope; | 13 | } Scope; |
13 | 14 | ||
14 | typedef struct Compiler { | 15 | typedef 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 | ||
38 | void | 40 | void |
@@ -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 | ||
45 | Scope * | 48 | Scope * |
@@ -74,6 +77,16 @@ find_local_index(Scope *scope, Token tok) { | |||
74 | return -1; | 77 | return -1; |
75 | } | 78 | } |
76 | 79 | ||
80 | ssize_t | ||
81 | find_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 | |||
77 | void | 90 | void |
78 | emit_constant(Chunk *chunk, Token tok, Object obj) { | 91 | emit_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) { | |||
329 | void | 342 | void |
330 | compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) { | 343 | compile_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); |