]> git.lizzy.rs Git - nothing.git/blob - src/script/interpreter.c
Support lambdas
[nothing.git] / src / script / interpreter.c
1 #include <assert.h>
2 #include <math.h>
3 #include <string.h>
4
5 #include "./builtins.h"
6 #include "./expr.h"
7 #include "./interpreter.h"
8 #include "./scope.h"
9
10 struct EvalResult eval_success(struct Expr expr)
11 {
12     struct EvalResult result = {
13         .is_error = false,
14         .expr = expr,
15     };
16
17     return result;
18 }
19
20 struct EvalResult eval_failure(struct Expr error)
21 {
22     struct EvalResult result = {
23         .is_error = true,
24         .expr = error,
25     };
26
27     return result;
28 }
29
30 static struct EvalResult length(Gc *gc, struct Expr obj)
31 {
32     if (!list_p(obj)) {
33         return eval_failure(list(gc, 3,
34                                  SYMBOL(gc, "wrong-argument-type"),
35                                  SYMBOL(gc, "listp"),
36                                  obj));
37     }
38
39     return eval_success(NUMBER(gc, length_of_list(obj)));
40 }
41
42 static struct EvalResult eval_atom(Gc *gc, struct Scope *scope, struct Atom *atom)
43 {
44     (void) scope;
45     (void) gc;
46
47     switch (atom->type) {
48     case ATOM_NUMBER:
49     case ATOM_STRING:
50         return eval_success(atom_as_expr(atom));
51
52     case ATOM_SYMBOL: {
53         if (nil_p(atom_as_expr(atom))) {
54             return eval_success(atom_as_expr(atom));
55         }
56
57         struct Expr value = get_scope_value(scope, atom_as_expr(atom));
58
59         if (nil_p(value)) {
60             return eval_failure(CONS(gc,
61                                      SYMBOL(gc, "void-variable"),
62                                      atom_as_expr(atom)));
63         }
64
65         return eval_success(value.cons->cdr);
66     }
67     }
68
69     return eval_failure(CONS(gc,
70                              SYMBOL(gc, "unexpected-expression"),
71                              atom_as_expr(atom)));
72 }
73
74 static struct EvalResult eval_all_args(Gc *gc, struct Scope *scope, struct Expr args)
75 {
76     (void) scope;
77     (void) args;
78
79     switch(args.type) {
80     case EXPR_ATOM:
81         return eval_atom(gc, scope, args.atom);
82
83     case EXPR_CONS: {
84         struct EvalResult car = eval(gc, scope, args.cons->car);
85         if (car.is_error) {
86             return car;
87         }
88
89         struct EvalResult cdr = eval_all_args(gc, scope, args.cons->cdr);
90         if (cdr.is_error) {
91             return cdr;
92         }
93
94         return eval_success(cons_as_expr(create_cons(gc, car.expr, cdr.expr)));
95     }
96
97     default: {}
98     }
99
100     return eval_failure(CONS(gc,
101                              SYMBOL(gc, "unexpected-expression"),
102                              args));
103 }
104
105 static struct EvalResult plus_op(Gc *gc, struct Expr args)
106 {
107     long int result = 0.0f;
108
109     while (!nil_p(args)) {
110         if (args.type != EXPR_CONS) {
111             return eval_failure(CONS(gc,
112                                      SYMBOL(gc, "expected-cons"),
113                                      args));
114         }
115
116         if (args.cons->car.type != EXPR_ATOM ||
117             args.cons->car.atom->type != ATOM_NUMBER) {
118             return eval_failure(CONS(gc,
119                                      SYMBOL(gc, "expected-number"),
120                                      args.cons->car));
121         }
122
123         result += args.cons->car.atom->num;
124         args = args.cons->cdr;
125     }
126
127     return eval_success(atom_as_expr(create_number_atom(gc, result)));
128 }
129
130 static struct EvalResult call_callable(Gc *gc,
131                                        struct Scope *scope,
132                                        struct Expr callable,
133                                        struct Expr args) {
134     if (!callable_p(callable)) {
135         return eval_failure(CONS(gc,
136                                  SYMBOL(gc, "expected-callable"),
137                                  callable));
138     }
139
140     if (!list_p(args)) {
141         return eval_failure(CONS(gc,
142                                  SYMBOL(gc, "expected-list"),
143                                  args));
144     }
145
146     struct Expr vars = callable.cons->cdr.cons->car;
147
148     if (length_of_list(args) != length_of_list(vars)) {
149         return eval_failure(CONS(gc,
150                                  SYMBOL(gc, "wrong-number-of-arguments"),
151                                  NUMBER(gc, length_of_list(args))));
152     }
153
154     push_scope_frame(gc, scope, vars, args);
155     struct Expr body = callable.cons->cdr.cons->cdr;
156
157     struct EvalResult result = eval_success(NIL(gc));
158
159     while (!nil_p(body)) {
160         print_expr_as_sexpr(body.cons->car);
161         result = eval(gc, scope, body.cons->car);
162         if (result.is_error) {
163             return result;
164         }
165         body = body.cons->cdr;
166     }
167
168     pop_scope_frame(gc, scope);
169
170     return result;
171 }
172
173 static struct EvalResult eval_funcall(Gc *gc, struct Scope *scope, struct Cons *cons)
174 {
175     assert(cons);
176     (void) scope;
177
178     if (symbol_p(cons->car)) {
179         if (strcmp(cons->car.atom->sym, "+") == 0) {
180             struct EvalResult args = eval_all_args(gc, scope, cons->cdr);
181             if (args.is_error) {
182                 return args;
183             }
184             return plus_op(gc, args.expr);
185         } else if (strcmp(cons->car.atom->sym, "set") == 0) {
186             struct Expr args = cons->cdr;
187             struct EvalResult n = length(gc, args);
188
189             if (n.is_error) {
190                 return n;
191             }
192
193             if (n.expr.atom->num != 2) {
194                 return eval_failure(list(gc, 3,
195                                          SYMBOL(gc, "wrong-number-of-arguments"),
196                                          SYMBOL(gc, "set"),
197                                          NUMBER(gc, n.expr.atom->num)));
198             }
199
200             struct Expr name = args.cons->car;
201             if (!symbol_p(name)) {
202                 return eval_failure(list(gc, 3,
203                                          SYMBOL(gc, "wrong-type-argument"),
204                                          SYMBOL(gc, "symbolp"),
205                                          name));
206             }
207
208             struct EvalResult value = eval(gc, scope, args.cons->cdr.cons->car);
209             if (value.is_error) {
210                 return value;
211             }
212
213             set_scope_value(gc, scope, name, value.expr);
214
215             return eval_success(value.expr);
216         } else if (strcmp(cons->car.atom->sym, "quote") == 0) {
217             /* TODO: quote does not check the amout of it's arguments */
218             return eval_success(cons->cdr.cons->car);
219         } else if (strcmp(cons->car.atom->sym, "lambda") == 0) {
220             return eval_success(cons_as_expr(cons));
221         } else {
222             struct EvalResult r = eval_all_args(gc, scope, cons_as_expr(cons));
223
224             if (r.is_error) {
225                 return r;
226             }
227
228             if (!callable_p(r.expr.cons->car)) {
229                 return eval_failure(CONS(gc,
230                                          SYMBOL(gc, "not-callable"),
231                                          r.expr.cons->car));
232             }
233
234             return call_callable(gc, scope, r.expr.cons->car, r.expr.cons->cdr);
235         }
236     } else if (callable_p(cons->car)) {
237         /* TODO: Call cons->car */
238     }
239
240     return eval_failure(CONS(gc,
241                              SYMBOL(gc, "unknown-function"),
242                              cons->car));
243 }
244
245 struct EvalResult eval(Gc *gc, struct Scope *scope, struct Expr expr)
246 {
247     switch(expr.type) {
248     case EXPR_ATOM:
249         return eval_atom(gc, scope, expr.atom);
250
251     case EXPR_CONS:
252         return eval_funcall(gc, scope, expr.cons);
253
254     default: {}
255     }
256
257     return eval_failure(CONS(gc,
258                              SYMBOL(gc, "unexpected-expression"),
259                              expr));
260 }