diff options
author | Bad Diode <bd@badd10de.dev> | 2021-10-14 17:05:37 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-10-14 17:05:37 +0200 |
commit | 530ed15ec941194e661010498cf30b7842710939 (patch) | |
tree | ccd1d771350453b59049e06ac224728f321f2b15 /src | |
parent | ab23395b1fc88bbc63bef88de3477cc316857ace (diff) | |
download | bdl-530ed15ec941194e661010498cf30b7842710939.tar.gz bdl-530ed15ec941194e661010498cf30b7842710939.zip |
Fix lambda and closures
Diffstat (limited to 'src')
-rw-r--r-- | src/bootstrap/environment.c | 52 | ||||
-rw-r--r-- | src/bootstrap/primitives.c | 55 |
2 files changed, 75 insertions, 32 deletions
diff --git a/src/bootstrap/environment.c b/src/bootstrap/environment.c index 99dd7fd..e111753 100644 --- a/src/bootstrap/environment.c +++ b/src/bootstrap/environment.c | |||
@@ -60,8 +60,27 @@ env_lookup(Environment *env, Object *symbol) { | |||
60 | return obj_err; | 60 | return obj_err; |
61 | } | 61 | } |
62 | 62 | ||
63 | Object * | ||
64 | env_update(Environment *env, Object *symbol, Object *value) { | ||
65 | while (env != NULL) { | ||
66 | for (size_t i = 0; i < env->size; i++) { | ||
67 | EnvEntry entry = env->buf[i]; | ||
68 | if (obj_eq(symbol, entry.symbol)) { | ||
69 | env->buf[i].value = obj_duplicate(value); | ||
70 | return obj_nil; | ||
71 | } | ||
72 | } | ||
73 | env = env->parent; | ||
74 | } | ||
75 | error_push((Error){ | ||
76 | .type = ERR_TYPE_RUNTIME, | ||
77 | .value = ERR_SYMBOL_NOT_FOUND, | ||
78 | }); | ||
79 | return obj_err; | ||
80 | } | ||
81 | |||
63 | ssize_t | 82 | ssize_t |
64 | env_symbol_index_in_current_env(Environment *env, Object *symbol) { | 83 | env_index_current(Environment *env, Object *symbol) { |
65 | for (size_t i = 0; i < env->size; i++) { | 84 | for (size_t i = 0; i < env->size; i++) { |
66 | EnvEntry entry = env->buf[i]; | 85 | EnvEntry entry = env->buf[i]; |
67 | if (obj_eq(symbol, entry.symbol)) { | 86 | if (obj_eq(symbol, entry.symbol)) { |
@@ -70,3 +89,34 @@ env_symbol_index_in_current_env(Environment *env, Object *symbol) { | |||
70 | } | 89 | } |
71 | return -1; | 90 | return -1; |
72 | } | 91 | } |
92 | |||
93 | void | ||
94 | env_add_or_update_current(Environment *env, Object *symbol, Object *value) { | ||
95 | ssize_t index = env_index_current(env, symbol); | ||
96 | if (index == -1) { | ||
97 | env_add_symbol(env, obj_duplicate(symbol), obj_duplicate(value)); | ||
98 | } else { | ||
99 | env->buf[index].value = obj_duplicate(value); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | Environment * | ||
104 | env_extend(Environment *parent, Environment *extra) { | ||
105 | Environment *env = env_create(parent); | ||
106 | for (size_t i = 0; i < extra->size; i++) { | ||
107 | EnvEntry entry = extra->buf[i]; | ||
108 | Environment *tmp = env; | ||
109 | ssize_t idx = -1; | ||
110 | while (tmp != NULL) { | ||
111 | idx = env_index_current(tmp, entry.symbol); | ||
112 | if (idx != -1) { | ||
113 | break; | ||
114 | } | ||
115 | tmp = tmp->parent; | ||
116 | } | ||
117 | if (idx == -1) { | ||
118 | env_add_symbol(env, obj_duplicate(entry.symbol), obj_duplicate(entry.value)); | ||
119 | } | ||
120 | } | ||
121 | return env; | ||
122 | } | ||
diff --git a/src/bootstrap/primitives.c b/src/bootstrap/primitives.c index 461799e..4ef56d5 100644 --- a/src/bootstrap/primitives.c +++ b/src/bootstrap/primitives.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #define DEBUG_OBJ(MSG,OBJ) printf((MSG)); display(OBJ); printf("\n"); | ||
2 | |||
1 | Object * | 3 | Object * |
2 | eval(Environment* env, Object *root) { | 4 | eval(Environment* env, Object *root) { |
3 | tailcall: | ||
4 | switch (root->type) { | 5 | switch (root->type) { |
5 | case OBJ_TYPE_ERR: | 6 | case OBJ_TYPE_ERR: |
6 | case OBJ_TYPE_PROCEDURE: | 7 | case OBJ_TYPE_PROCEDURE: |
@@ -35,17 +36,26 @@ tailcall: | |||
35 | if (val->type == OBJ_TYPE_PROCEDURE) { | 36 | if (val->type == OBJ_TYPE_PROCEDURE) { |
36 | return val->proc(env, root->cdr); | 37 | return val->proc(env, root->cdr); |
37 | } | 38 | } |
39 | if (val->type == OBJ_TYPE_LAMBDA) { | ||
40 | goto eval_lambda; | ||
41 | } | ||
38 | error_push((Error){ | 42 | error_push((Error){ |
39 | .type = ERR_TYPE_RUNTIME, | 43 | .type = ERR_TYPE_RUNTIME, |
40 | .value = ERR_OBJ_NOT_CALLABLE, | 44 | .value = ERR_OBJ_NOT_CALLABLE, |
41 | }); | 45 | }); |
42 | return obj_err; | 46 | return obj_err; |
43 | } | 47 | } |
44 | Object* lambda = eval(env, root->car); | 48 | Object* lambda; |
49 | eval_lambda: | ||
50 | lambda = eval(env, root->car); | ||
51 | if (lambda == obj_err) { | ||
52 | return obj_err; | ||
53 | } | ||
45 | if (lambda->type == OBJ_TYPE_LAMBDA) { | 54 | if (lambda->type == OBJ_TYPE_LAMBDA) { |
46 | Object *fun = lambda; | 55 | Object *fun = lambda; |
47 | Object *args = root->cdr; | 56 | Object *args = root->cdr; |
48 | Object *params = fun->args; | 57 | Object *params = fun->args; |
58 | env = env_extend(fun->env, env); | ||
49 | while (params != obj_nil) { | 59 | while (params != obj_nil) { |
50 | if (args == obj_nil) { | 60 | if (args == obj_nil) { |
51 | error_push((Error){ | 61 | error_push((Error){ |
@@ -66,12 +76,7 @@ tailcall: | |||
66 | }); | 76 | }); |
67 | return obj_err; | 77 | return obj_err; |
68 | } | 78 | } |
69 | ssize_t index = env_symbol_index_in_current_env(fun->env, symbol); | 79 | env_add_or_update_current(env, symbol, value); |
70 | if (index == -1) { | ||
71 | env_add_symbol(fun->env, obj_duplicate(symbol), obj_duplicate(value)); | ||
72 | } else { | ||
73 | fun->env->buf[index].value = obj_duplicate(value); | ||
74 | } | ||
75 | args = args->cdr; | 80 | args = args->cdr; |
76 | params = params->cdr; | 81 | params = params->cdr; |
77 | } | 82 | } |
@@ -82,10 +87,14 @@ tailcall: | |||
82 | }); | 87 | }); |
83 | return obj_err; | 88 | return obj_err; |
84 | } | 89 | } |
85 | |||
86 | env = fun->env; | ||
87 | root = fun->body; | 90 | root = fun->body; |
88 | goto tailcall; | 91 | while (root->cdr != obj_nil) { |
92 | if (eval(env, root->car) == obj_err) { | ||
93 | return obj_err; | ||
94 | }; | ||
95 | root = root->cdr; | ||
96 | } | ||
97 | return eval(env, root->car); | ||
89 | } | 98 | } |
90 | } break; | 99 | } break; |
91 | } | 100 | } |
@@ -693,13 +702,7 @@ proc_define(Environment *env, Object *obj) { | |||
693 | return obj_err; | 702 | return obj_err; |
694 | } | 703 | } |
695 | 704 | ||
696 | // Make a copy of the symbol and to make them permanent in the environment. | 705 | env_add_or_update_current(env, symbol, value); |
697 | ssize_t index = env_symbol_index_in_current_env(env, symbol); | ||
698 | if (index == -1) { | ||
699 | env_add_symbol(env, obj_duplicate(symbol), obj_duplicate(value)); | ||
700 | } else { | ||
701 | env->buf[index].value = obj_duplicate(value); | ||
702 | } | ||
703 | return obj_nil; | 706 | return obj_nil; |
704 | } | 707 | } |
705 | 708 | ||
@@ -727,17 +730,7 @@ proc_set(Environment *env, Object *obj) { | |||
727 | return obj_err; | 730 | return obj_err; |
728 | } | 731 | } |
729 | 732 | ||
730 | ssize_t index = env_symbol_index_in_current_env(env, symbol); | 733 | return env_update(env, symbol, value); |
731 | if (index == -1) { | ||
732 | error_push((Error){ | ||
733 | .type = ERR_TYPE_RUNTIME, | ||
734 | .value = ERR_SYMBOL_NOT_FOUND, | ||
735 | }); | ||
736 | return obj_err; | ||
737 | } | ||
738 | |||
739 | env->buf[index].value = obj_duplicate(value); | ||
740 | return obj_nil; | ||
741 | } | 734 | } |
742 | 735 | ||
743 | Object * | 736 | Object * |
@@ -757,11 +750,11 @@ proc_lambda(Environment *env, Object *obj) { | |||
757 | }); | 750 | }); |
758 | return obj_err; | 751 | return obj_err; |
759 | } | 752 | } |
760 | Object *body = obj->cdr->car; | 753 | Object *body = obj->cdr; |
761 | Object *fun = alloc_object(OBJ_TYPE_LAMBDA); | 754 | Object *fun = alloc_object(OBJ_TYPE_LAMBDA); |
762 | fun->args = obj_duplicate(args); | 755 | fun->args = obj_duplicate(args); |
763 | fun->body = obj_duplicate(body); | 756 | fun->body = obj_duplicate(body); |
764 | fun->env = env_create(env); | 757 | fun->env = env; |
765 | return fun; | 758 | return fun; |
766 | } | 759 | } |
767 | 760 | ||