aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2021-10-14 17:05:37 +0200
committerBad Diode <bd@badd10de.dev>2021-10-14 17:05:37 +0200
commit530ed15ec941194e661010498cf30b7842710939 (patch)
treeccd1d771350453b59049e06ac224728f321f2b15
parentab23395b1fc88bbc63bef88de3477cc316857ace (diff)
downloadbdl-530ed15ec941194e661010498cf30b7842710939.tar.gz
bdl-530ed15ec941194e661010498cf30b7842710939.zip
Fix lambda and closures
-rw-r--r--examples/variables.bdl56
-rw-r--r--src/bootstrap/environment.c52
-rw-r--r--src/bootstrap/primitives.c55
3 files changed, 131 insertions, 32 deletions
diff --git a/examples/variables.bdl b/examples/variables.bdl
index 6097368..2e2543a 100644
--- a/examples/variables.bdl
+++ b/examples/variables.bdl
@@ -14,3 +14,59 @@
14(print "(error? (set! a 42)) -> ") (error? (set! a 42)) 14(print "(error? (set! a 42)) -> ") (error? (set! a 42))
15(print "a -> ") a 15(print "a -> ") a
16(print "(error? (set! b 99)) -> ") (error? (set! b 99)) 16(print "(error? (set! b 99)) -> ") (error? (set! b 99))
17(lambda (a b) (+ 10 a b))
18
19(def a 20)
20((lambda (a b) (+ 10 a b)) 1 2)
21((lambda (a b) (+ 10 a b)) a 3)
22(def myfun (lambda (a b) (+ a b)))
23(myfun 6 9)
24(+ 1 (myfun 10 (myfun a a)) 30)
25(myfun 10 (myfun 5 0))
26
27;; Closures.
28(def make-counter (lambda ()
29 (def value 0)
30 (def counter (lambda ()
31 (set! value (+ value 1))
32 value))
33 counter))
34
35(def counter-a (make-counter))
36(def counter-b (make-counter))
37(counter-a)
38(counter-a)
39(counter-b)
40(counter-b)
41(counter-b)
42(counter-b)
43(counter-a)
44
45;; Fibonacci.
46(def fib (lambda (n)
47 (if (<= n 2)
48 1
49 (+ (fib (- n 1)) (fib (- n 2))))))
50(fib 15)
51
52;; Lambda capture.
53(def a 20)
54(def b (lambda ()
55 (display a)
56 (newline)
57 (def a 42)
58 (display a)
59 (newline)))
60
61(b)
62(b)
63
64
65;; Infinite loop. (For teseting purposes)
66; (def test (lambda (n)
67; (print "ITER\n")
68; (if (<= n 2)
69; 'ok
70; (test (+ n 1)))))
71
72; (test 3)
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
63Object *
64env_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
63ssize_t 82ssize_t
64env_symbol_index_in_current_env(Environment *env, Object *symbol) { 83env_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
93void
94env_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
103Environment *
104env_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
1Object * 3Object *
2eval(Environment* env, Object *root) { 4eval(Environment* env, Object *root) {
3tailcall:
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;
49eval_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
743Object * 736Object *
@@ -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