]> git.lizzy.rs Git - nothing.git/blob - src/script/interpreter.c
Merge pull request #331 from tsoding/314
[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, struct Expr scope)
11 {
12     struct EvalResult result = {
13         .is_error = false,
14         .expr = expr,
15         .scope = scope,
16     };
17
18     return result;
19 }
20
21 struct EvalResult eval_failure(struct Expr error, struct Expr scope)
22 {
23     struct EvalResult result = {
24         .is_error = true,
25         .expr = error,
26         .scope = scope
27     };
28
29     return result;
30 }
31
32 static struct EvalResult length(Gc *gc, struct Expr scope, struct Expr obj)
33 {
34     if (!list_p(obj)) {
35         return eval_failure(list(gc, 3,
36                                  SYMBOL(gc, "wrong-argument-type"),
37                                  SYMBOL(gc, "listp"),
38                                  obj),
39                             scope);
40     }
41
42     long int count = 0;
43
44     while (!nil_p(obj)) {
45         count++;
46         obj = obj.cons->cdr;
47     }
48
49     return eval_success(NUMBER(gc, count), scope);
50 }
51
52 static struct EvalResult eval_atom(Gc *gc, struct Expr scope, struct Atom *atom)
53 {
54     (void) scope;
55     (void) gc;
56
57     switch (atom->type) {
58     case ATOM_NUMBER:
59     case ATOM_STRING:
60         return eval_success(atom_as_expr(atom), scope);
61
62     case ATOM_SYMBOL: {
63         if (nil_p(atom_as_expr(atom))) {
64             return eval_success(atom_as_expr(atom), scope);
65         }
66
67         struct Expr value = get_scope_value(scope, atom_as_expr(atom));
68
69         if (nil_p(value)) {
70             return eval_failure(CONS(gc,
71                                      SYMBOL(gc, "void-variable"),
72                                      atom_as_expr(atom)),
73                                 scope);
74         }
75
76         return eval_success(value.cons->cdr, scope);
77     }
78     }
79
80     return eval_failure(CONS(gc,
81                              SYMBOL(gc, "unexpected-expression"),
82                              atom_as_expr(atom)),
83                         scope);
84 }
85
86 static struct EvalResult eval_all_args(Gc *gc, struct Expr scope, struct Expr args)
87 {
88     (void) scope;
89     (void) args;
90
91     switch(args.type) {
92     case EXPR_ATOM:
93         return eval_atom(gc, scope, args.atom);
94
95     case EXPR_CONS: {
96         struct EvalResult car = eval(gc, scope, args.cons->car);
97         if (car.is_error) {
98             return car;
99         }
100
101         struct EvalResult cdr = eval_all_args(gc, scope, args.cons->cdr);
102         if (cdr.is_error) {
103             return cdr;
104         }
105
106         return eval_success(cons_as_expr(create_cons(gc, car.expr, cdr.expr)), scope);
107     }
108
109     default: {}
110     }
111
112     return eval_failure(CONS(gc,
113                              SYMBOL(gc, "unexpected-expression"),
114                              args),
115                         scope);
116 }
117
118 static struct EvalResult plus_op(Gc *gc, struct Expr args, struct Expr scope)
119 {
120     long int result = 0.0f;
121
122     while (!nil_p(args)) {
123         if (args.type != EXPR_CONS) {
124             return eval_failure(CONS(gc,
125                                      SYMBOL(gc, "expected-cons"),
126                                      args),
127                                 scope);
128         }
129
130         if (args.cons->car.type != EXPR_ATOM ||
131             args.cons->car.atom->type != ATOM_NUMBER) {
132             return eval_failure(CONS(gc,
133                                      SYMBOL(gc, "expected-number"),
134                                      args.cons->car),
135                                 scope);
136         }
137
138         result += args.cons->car.atom->num;
139         args = args.cons->cdr;
140     }
141
142     return eval_success(atom_as_expr(create_number_atom(gc, result)), scope);
143 }
144
145 static struct EvalResult eval_funcall(Gc *gc, struct Expr scope, struct Cons *cons)
146 {
147     assert(cons);
148     (void) scope;
149
150     if (!symbol_p(cons->car)) {
151         return eval_failure(CONS(gc,
152                                  SYMBOL(gc, "expected-symbol"),
153                                  cons->car),
154                             scope);
155     }
156
157     /* TODO(#323): set builtin function is not implemented */
158     if (strcmp(cons->car.atom->sym, "+") == 0) {
159         struct EvalResult args = eval_all_args(gc, scope, cons->cdr);
160         if (args.is_error) {
161             return args;
162         }
163         return plus_op(gc, args.expr, scope);
164     } else if (strcmp(cons->car.atom->sym, "set") == 0) {
165         struct Expr args = cons->cdr;
166         struct EvalResult n = length(gc, scope, args);
167
168         if (n.is_error) {
169             return n;
170         }
171         scope = n.scope;
172
173         if (n.expr.atom->num != 2) {
174             return eval_failure(list(gc, 3,
175                                      SYMBOL(gc, "wrong-number-of-arguments"),
176                                      SYMBOL(gc, "set"),
177                                      NUMBER(gc, n.expr.atom->num)),
178                                 scope);
179         }
180
181         struct Expr name = args.cons->car;
182         if (!symbol_p(name)) {
183             return eval_failure(list(gc, 3,
184                                      SYMBOL(gc, "wrong-type-argument"),
185                                      SYMBOL(gc, "symbolp"),
186                                      name),
187                                 scope);
188         }
189
190         struct EvalResult value = eval(gc, scope, args.cons->cdr.cons->car);
191         if (value.is_error) {
192             return value;
193         }
194         scope = value.scope;
195
196         return eval_success(value.expr, set_scope_value(gc, scope, name, value.expr));
197     }
198
199     return eval_failure(CONS(gc,
200                              SYMBOL(gc, "unknown-function"),
201                              cons->car),
202                         scope);
203 }
204
205 struct EvalResult eval(Gc *gc, struct Expr scope, struct Expr expr)
206 {
207     switch(expr.type) {
208     case EXPR_ATOM:
209         return eval_atom(gc, scope, expr.atom);
210
211     case EXPR_CONS:
212         return eval_funcall(gc, scope, expr.cons);
213
214     default: {}
215     }
216
217     return eval_failure(CONS(gc,
218                              SYMBOL(gc, "unexpected-expression"),
219                              expr),
220                         scope);
221 }