aboutsummaryrefslogtreecommitdiffstats
path: root/src/bytecode/compiler.h
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-10-28 10:40:22 +0200
committerBad Diode <bd@badd10de.dev>2021-10-28 10:40:22 +0200
commitd04aea3c5875cd2859d6ab961256b11189c49839 (patch)
tree911b6df338dde38ed28c447cfba999bcc3cb1743 /src/bytecode/compiler.h
parent4515d21211263a2c7367ec20ec01ce9efaae1d18 (diff)
downloadbdl-d04aea3c5875cd2859d6ab961256b11189c49839.tar.gz
bdl-d04aea3c5875cd2859d6ab961256b11189c49839.zip
Prepare for closure capture
Diffstat (limited to 'src/bytecode/compiler.h')
-rwxr-xr-xsrc/bytecode/compiler.h72
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 @@
9typedef struct Scope { 9typedef struct Scope {
10 StringView *params; 10 StringView *params;
11 StringView *locals; 11 StringView *locals;
12 StringView *captured;
12} Scope; 13} Scope;
13 14
14typedef struct Compiler { 15typedef 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
38void 40void
@@ -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
45Scope * 48Scope *
@@ -74,6 +77,16 @@ find_local_index(Scope *scope, Token tok) {
74 return -1; 77 return -1;
75} 78}
76 79
80ssize_t
81find_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
77void 90void
78emit_constant(Chunk *chunk, Token tok, Object obj) { 91emit_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) {
329void 342void
330compile_lambda(Chunk *chunk, Compiler *compiler, Token start, StringView name) { 343compile_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);