]> git.lizzy.rs Git - nothing.git/blob - src/script/interpreter.c
Introduce length_of_list
[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 eval_funcall(Gc *gc, struct Scope *scope, struct Cons *cons)
131 {
132     assert(cons);
133     (void) scope;
134
135     if (!symbol_p(cons->car)) {
136         return eval_failure(CONS(gc,
137                                  SYMBOL(gc, "expected-symbol"),
138                                  cons->car));
139     }
140
141     /* TODO(#323): set builtin function is not implemented */
142     if (strcmp(cons->car.atom->sym, "+") == 0) {
143         struct EvalResult args = eval_all_args(gc, scope, cons->cdr);
144         if (args.is_error) {
145             return args;
146         }
147         return plus_op(gc, args.expr);
148     } else if (strcmp(cons->car.atom->sym, "set") == 0) {
149         struct Expr args = cons->cdr;
150         struct EvalResult n = length(gc, args);
151
152         if (n.is_error) {
153             return n;
154         }
155
156         if (n.expr.atom->num != 2) {
157             return eval_failure(list(gc, 3,
158                                      SYMBOL(gc, "wrong-number-of-arguments"),
159                                      SYMBOL(gc, "set"),
160                                      NUMBER(gc, n.expr.atom->num)));
161         }
162
163         struct Expr name = args.cons->car;
164         if (!symbol_p(name)) {
165             return eval_failure(list(gc, 3,
166                                      SYMBOL(gc, "wrong-type-argument"),
167                                      SYMBOL(gc, "symbolp"),
168                                      name));
169         }
170
171         struct EvalResult value = eval(gc, scope, args.cons->cdr.cons->car);
172         if (value.is_error) {
173             return value;
174         }
175
176         set_scope_value(gc, scope, name, value.expr);
177
178         return eval_success(value.expr);
179     }
180
181     return eval_failure(CONS(gc,
182                              SYMBOL(gc, "unknown-function"),
183                              cons->car));
184 }
185
186 struct EvalResult eval(Gc *gc, struct Scope *scope, struct Expr expr)
187 {
188     switch(expr.type) {
189     case EXPR_ATOM:
190         return eval_atom(gc, scope, expr.atom);
191
192     case EXPR_CONS:
193         return eval_funcall(gc, scope, expr.cons);
194
195     default: {}
196     }
197
198     return eval_failure(CONS(gc,
199                              SYMBOL(gc, "unexpected-expression"),
200                              expr));
201 }