diff options
author | Bad Diode <bd@badd10de.dev> | 2021-10-16 21:56:00 +0200 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2021-10-16 21:56:00 +0200 |
commit | 54060b06acd084f75bfda00517479902a5652391 (patch) | |
tree | 1dae8d79b8ea7627dcd3647b8bc4035a19f0260d /src/bootstrap | |
parent | bb58afb57221eb0316d6ee14e19c5f4c4a822ba1 (diff) | |
download | bdl-54060b06acd084f75bfda00517479902a5652391.tar.gz bdl-54060b06acd084f75bfda00517479902a5652391.zip |
Add explicit TCO for lambda and if procedure
Diffstat (limited to 'src/bootstrap')
-rw-r--r-- | src/bootstrap/gc.c | 4 | ||||
-rw-r--r-- | src/bootstrap/primitives.c | 53 |
2 files changed, 45 insertions, 12 deletions
diff --git a/src/bootstrap/gc.c b/src/bootstrap/gc.c index 6e15c63..b63ee2b 100644 --- a/src/bootstrap/gc.c +++ b/src/bootstrap/gc.c | |||
@@ -35,7 +35,7 @@ alloc_env(void) { | |||
35 | if (gc.envs.size < gc.envs.cap) { | 35 | if (gc.envs.size < gc.envs.cap) { |
36 | return &gc.envs.buf[gc.envs.size++]; | 36 | return &gc.envs.buf[gc.envs.size++]; |
37 | } | 37 | } |
38 | printf("error: not enough room for more environments\n"); | 38 | fprintf(stderr, "error: not enough room for more environments\n"); |
39 | return NULL; | 39 | return NULL; |
40 | } | 40 | } |
41 | 41 | ||
@@ -188,7 +188,7 @@ alloc_object(ObjectType type) { | |||
188 | if (gc.available_slots == 0) { | 188 | if (gc.available_slots == 0) { |
189 | mark_and_sweep(); | 189 | mark_and_sweep(); |
190 | if (gc.available_slots == 0) { | 190 | if (gc.available_slots == 0) { |
191 | printf("NOT MORE MEMORY AVAILABLE WHERE IS YOUR GOD NOW MWAHAHA\n"); | 191 | fprintf(stderr, "NOT MORE MEMORY AVAILABLE WHERE IS YOUR GOD NOW MWAHAHA\n"); |
192 | dump_gc(); | 192 | dump_gc(); |
193 | exit(EXIT_FAILURE); | 193 | exit(EXIT_FAILURE); |
194 | // TODO: grow heap tables. | 194 | // TODO: grow heap tables. |
diff --git a/src/bootstrap/primitives.c b/src/bootstrap/primitives.c index abb87e7..a814e40 100644 --- a/src/bootstrap/primitives.c +++ b/src/bootstrap/primitives.c | |||
@@ -1,7 +1,12 @@ | |||
1 | #define DEBUG_OBJ(MSG,OBJ) printf((MSG)); display(OBJ); printf("\n"); | 1 | #define DEBUG_OBJ(MSG,OBJ) printf((MSG)); display(OBJ); printf("\n"); |
2 | 2 | ||
3 | Object * proc_if(Environment *env, Object *obj); | ||
4 | |||
3 | Object * | 5 | Object * |
4 | eval(Environment* env, Object *root) { | 6 | eval(Environment *env, Object *root) { |
7 | Object* lambda; | ||
8 | bool recursion_active = false; | ||
9 | eval_start: | ||
5 | switch (root->type) { | 10 | switch (root->type) { |
6 | case OBJ_TYPE_ERR: | 11 | case OBJ_TYPE_ERR: |
7 | case OBJ_TYPE_PROCEDURE: | 12 | case OBJ_TYPE_PROCEDURE: |
@@ -34,9 +39,35 @@ eval(Environment* env, Object *root) { | |||
34 | return obj_err; | 39 | return obj_err; |
35 | } | 40 | } |
36 | if (val->type == OBJ_TYPE_PROCEDURE) { | 41 | if (val->type == OBJ_TYPE_PROCEDURE) { |
42 | // TODO: This is very messy, needs refactoring. | ||
43 | if (val->proc == proc_if) { | ||
44 | Object *obj = root->cdr; | ||
45 | if (obj == obj_nil || obj->cdr == obj_nil) { | ||
46 | error_push((Error){ | ||
47 | .type = ERR_TYPE_RUNTIME, | ||
48 | .value = ERR_NOT_ENOUGH_ARGS, | ||
49 | }); | ||
50 | return obj_err; | ||
51 | } | ||
52 | Object *car = obj->car; | ||
53 | Object *cdr = obj->cdr; | ||
54 | Object *condition = eval(env, car); | ||
55 | if (condition == obj_err) { | ||
56 | return obj_err; | ||
57 | } | ||
58 | if (condition == obj_true) { | ||
59 | root = cdr->car; | ||
60 | } else if (cdr->cdr != obj_nil) { | ||
61 | root = cdr->cdr->car; | ||
62 | } else { | ||
63 | return obj_nil; | ||
64 | } | ||
65 | goto eval_start; | ||
66 | } | ||
37 | return val->proc(env, root->cdr); | 67 | return val->proc(env, root->cdr); |
38 | } | 68 | } |
39 | if (val->type == OBJ_TYPE_LAMBDA) { | 69 | if (val->type == OBJ_TYPE_LAMBDA) { |
70 | lambda = val; | ||
40 | goto eval_lambda; | 71 | goto eval_lambda; |
41 | } | 72 | } |
42 | error_push((Error){ | 73 | error_push((Error){ |
@@ -45,17 +76,19 @@ eval(Environment* env, Object *root) { | |||
45 | }); | 76 | }); |
46 | return obj_err; | 77 | return obj_err; |
47 | } | 78 | } |
48 | Object* lambda; | ||
49 | eval_lambda: | ||
50 | lambda = eval(env, root->car); | 79 | lambda = eval(env, root->car); |
51 | if (lambda == obj_err) { | 80 | if (lambda == obj_err) { |
52 | return obj_err; | 81 | return obj_err; |
53 | } | 82 | } |
54 | if (lambda->type == OBJ_TYPE_LAMBDA) { | 83 | if (lambda->type == OBJ_TYPE_LAMBDA) { |
55 | Object *fun = lambda; | 84 | Object *args; |
56 | Object *args = root->cdr; | 85 | eval_lambda: |
57 | Object *params = fun->params; | 86 | args = root->cdr; |
58 | env = env_extend(fun->env, env); | 87 | Object *params = lambda->params; |
88 | if (!recursion_active) { | ||
89 | env = env_extend(lambda->env, env); | ||
90 | recursion_active = true; | ||
91 | } | ||
59 | while (params != obj_nil) { | 92 | while (params != obj_nil) { |
60 | if (args == obj_nil) { | 93 | if (args == obj_nil) { |
61 | error_push((Error){ | 94 | error_push((Error){ |
@@ -87,15 +120,15 @@ eval_lambda: | |||
87 | }); | 120 | }); |
88 | return obj_err; | 121 | return obj_err; |
89 | } | 122 | } |
90 | root = fun->body; | 123 | root = lambda->body; |
91 | while (root->cdr != obj_nil) { | 124 | while (root->cdr != obj_nil) { |
92 | if (eval(env, root->car) == obj_err) { | 125 | if (eval(env, root->car) == obj_err) { |
93 | return obj_err; | 126 | return obj_err; |
94 | }; | 127 | }; |
95 | root = root->cdr; | 128 | root = root->cdr; |
96 | } | 129 | } |
97 | root = eval(env, root->car); | 130 | root = root->car; |
98 | return root; | 131 | goto eval_start; |
99 | } | 132 | } |
100 | } break; | 133 | } break; |
101 | } | 134 | } |