aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-11-15 22:33:53 +0100
committerBad Diode <bd@badd10de.dev>2021-11-15 22:33:53 +0100
commit62984fb580b9e355cf9eacf9de53bff8c895c0b5 (patch)
tree913df113b13d66328262dc5075f2b9925db46c4a
parent26f1b9c35d337c0814158077fdc8f56b817e0b14 (diff)
downloadbdl-62984fb580b9e355cf9eacf9de53bff8c895c0b5.tar.gz
bdl-62984fb580b9e355cf9eacf9de53bff8c895c0b5.zip
Add initial boilerplate for closure capture
-rw-r--r--src/compiler.h20
-rw-r--r--src/parser.c32
-rw-r--r--src/parser.h1
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
476void 476void
477insert_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
484void
477semantic_analysis(Environment *env, Object *obj, Errors *errors) { 485semantic_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