diff options
author | Bad Diode <bd@badd10de.dev> | 2021-11-15 22:33:53 +0100 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-11-15 22:33:53 +0100 |
commit | 62984fb580b9e355cf9eacf9de53bff8c895c0b5 (patch) | |
tree | 913df113b13d66328262dc5075f2b9925db46c4a | |
parent | 26f1b9c35d337c0814158077fdc8f56b817e0b14 (diff) | |
download | bdl-62984fb580b9e355cf9eacf9de53bff8c895c0b5.tar.gz bdl-62984fb580b9e355cf9eacf9de53bff8c895c0b5.zip |
Add initial boilerplate for closure capture
-rw-r--r-- | src/compiler.h | 20 | ||||
-rw-r--r-- | src/parser.c | 32 | ||||
-rw-r--r-- | src/parser.h | 1 |
3 files changed, 48 insertions, 5 deletions
diff --git a/src/compiler.h b/src/compiler.h index 1312d99..e91798a 100644 --- a/src/compiler.h +++ b/src/compiler.h | |||
@@ -508,18 +508,30 @@ compile_lambda(Object *obj) { | |||
508 | current_context = prev_context; | 508 | current_context = prev_context; |
509 | current_env = prev_env; | 509 | current_env = prev_env; |
510 | 510 | ||
511 | // Create tagged pointer with this lambda procedure. | 511 | // Add function address. |
512 | context_printf(" mov rax, %s\n", name); | 512 | context_printf(" mov rax, %s\n", name); |
513 | context_printf(" mov [r15], rax\n"); | 513 | context_printf(" mov [r15], rax\n"); |
514 | context_printf(" mov rax, %ld\n", array_size(obj->env->captured)); | ||
515 | context_printf(" mov [r15 + 8], rax\n"); | ||
516 | |||
517 | // Add captured variables to the heap. | ||
518 | for (size_t i = 0; i < array_size(obj->env->captured); i++) { | ||
519 | ssize_t idx = find_var_index(current_env->locals, obj->env->captured[i]); | ||
520 | context_printf(" mov rax, [rbp + %ld]\n", 8 * idx); | ||
521 | context_printf(" mov [r15 + %ld], rax\n", 8 * (i + 2)); | ||
522 | // TODO: What about capturing captured variables or parameters? | ||
523 | assert(idx != -1 && "unexpected index"); | ||
524 | } | ||
525 | |||
526 | // Create tagged pointer with this lambda procedure. | ||
514 | context_printf(" mov rax, r15\n"); | 527 | context_printf(" mov rax, r15\n"); |
515 | context_printf(" or rax, %zu\n", LAMBDA_TAG); | 528 | context_printf(" or rax, %zu\n", LAMBDA_TAG); |
516 | 529 | ||
517 | // Push compiled object to the stack. | 530 | // Push compiled object to the stack. |
518 | context_printf(" push rax\n"); | 531 | context_printf(" push rax\n"); |
519 | 532 | ||
520 | // TODO: When we add closed variables they will be stored here, for now just | 533 | // Adjust the heap pointer depending on the number of variables captured. |
521 | // incrementing by a 64 bit pointer size, as that is what we are storing. | 534 | context_printf(" add r15, %ld\n", 8 * (array_size(obj->env->captured) + 2)); |
522 | context_printf(" add r15, 8\n"); | ||
523 | 535 | ||
524 | context_printf(" ;; <-- compile_lambda\n"); | 536 | context_printf(" ;; <-- compile_lambda\n"); |
525 | } | 537 | } |
diff --git a/src/parser.c b/src/parser.c index 0968ccd..e72675f 100644 --- a/src/parser.c +++ b/src/parser.c | |||
@@ -474,6 +474,14 @@ insert_params(Environment *env, Object *symbol) { | |||
474 | } | 474 | } |
475 | 475 | ||
476 | void | 476 | void |
477 | insert_captured(Environment *env, Object *symbol) { | ||
478 | if (find_var_index(env->captured, symbol) != -1) { | ||
479 | return; | ||
480 | } | ||
481 | array_push(env->captured, symbol); | ||
482 | } | ||
483 | |||
484 | void | ||
477 | semantic_analysis(Environment *env, Object *obj, Errors *errors) { | 485 | semantic_analysis(Environment *env, Object *obj, Errors *errors) { |
478 | if (obj == NULL || obj->visited) { | 486 | if (obj == NULL || obj->visited) { |
479 | return; | 487 | return; |
@@ -481,7 +489,27 @@ semantic_analysis(Environment *env, Object *obj, Errors *errors) { | |||
481 | obj->visited = true; | 489 | obj->visited = true; |
482 | switch (obj->type) { | 490 | switch (obj->type) { |
483 | case OBJ_TYPE_SYMBOL: { | 491 | case OBJ_TYPE_SYMBOL: { |
484 | Object *found = symbol_in_env(env, obj); | 492 | Object *found = NULL; |
493 | |||
494 | Environment *cur_env = env; | ||
495 | while (cur_env != NULL) { | ||
496 | ssize_t idx = find_var_index(cur_env->locals, obj); | ||
497 | if (idx != -1) { | ||
498 | found = cur_env->local_values[idx]; | ||
499 | if (cur_env != env && cur_env->parent != NULL) { | ||
500 | insert_captured(env, obj); | ||
501 | } | ||
502 | break; | ||
503 | } | ||
504 | idx = find_var_index(cur_env->params, obj); | ||
505 | if (idx != -1) { | ||
506 | found = cur_env->params[idx]; | ||
507 | break; | ||
508 | } | ||
509 | cur_env = cur_env->parent; | ||
510 | } | ||
511 | |||
512 | // Check if symbol is in other environments. | ||
485 | if (found == NULL) { | 513 | if (found == NULL) { |
486 | error_push(errors, (Error){ | 514 | error_push(errors, (Error){ |
487 | .type = ERR_TYPE_PARSER, | 515 | .type = ERR_TYPE_PARSER, |
@@ -645,6 +673,7 @@ env_alloc(Environment *parent) { | |||
645 | array_init(env->locals, 0); | 673 | array_init(env->locals, 0); |
646 | array_init(env->local_values, 0); | 674 | array_init(env->local_values, 0); |
647 | array_init(env->params, 0); | 675 | array_init(env->params, 0); |
676 | array_init(env->captured, 0); | ||
648 | env->parent = parent; | 677 | env->parent = parent; |
649 | array_push(environments, env); | 678 | array_push(environments, env); |
650 | return env; | 679 | return env; |
@@ -687,6 +716,7 @@ free_objects(void) { | |||
687 | array_free(env->locals); | 716 | array_free(env->locals); |
688 | array_free(env->local_values); | 717 | array_free(env->local_values); |
689 | array_free(env->params); | 718 | array_free(env->params); |
719 | array_free(env->captured); | ||
690 | free(env); | 720 | free(env); |
691 | } | 721 | } |
692 | array_free(environments); | 722 | array_free(environments); |
diff --git a/src/parser.h b/src/parser.h index ca7260b..60a307c 100644 --- a/src/parser.h +++ b/src/parser.h | |||
@@ -7,6 +7,7 @@ typedef struct Environment { | |||
7 | struct Object **locals; | 7 | struct Object **locals; |
8 | struct Object **local_values; | 8 | struct Object **local_values; |
9 | struct Object **params; | 9 | struct Object **params; |
10 | struct Object **captured; | ||
10 | struct Environment *parent; | 11 | struct Environment *parent; |
11 | } Environment; | 12 | } Environment; |
12 | 13 | ||