]> git.lizzy.rs Git - nothing.git/blob - src/script/interpreter.c
(#326) error as struct Expr
[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 eval_atom(Gc *gc, struct Expr scope, struct Atom *atom)
33 {
34     (void) scope;
35     (void) gc;
36
37     /* TODO(#314): Evaluating symbols is not implemented */
38     switch (atom->type) {
39     case ATOM_NUMBER:
40     case ATOM_SYMBOL:
41     case ATOM_STRING:
42         return eval_success(atom_as_expr(atom), scope);
43     }
44
45     return eval_failure(CONS(gc,
46                              SYMBOL(gc, "unexpected-expression"),
47                              atom_as_expr(atom)),
48                         scope);
49 }
50
51 static struct EvalResult eval_args(Gc *gc, struct Expr scope, struct Expr args)
52 {
53     (void) scope;
54     (void) args;
55
56     switch(args.type) {
57     case EXPR_ATOM:
58         return eval_atom(gc, scope, args.atom);
59
60     case EXPR_CONS: {
61         struct EvalResult car = eval(gc, scope, args.cons->car);
62         if (car.is_error) {
63             return car;
64         }
65
66         struct EvalResult cdr = eval_args(gc, scope, args.cons->cdr);
67         if (cdr.is_error) {
68             return cdr;
69         }
70
71         return eval_success(cons_as_expr(create_cons(gc, car.expr, cdr.expr)), scope);
72     }
73
74     default: {}
75     }
76
77     return eval_failure(CONS(gc,
78                              SYMBOL(gc, "unexpected-expression"),
79                              args),
80                         scope);
81 }
82
83 static struct EvalResult plus_op(Gc *gc, struct Expr args, struct Expr scope)
84 {
85     float result = 0.0f;
86
87     while (!nil_p(args)) {
88         if (args.type != EXPR_CONS) {
89             return eval_failure(CONS(gc,
90                                      SYMBOL(gc, "expected-cons"),
91                                      args),
92                                 scope);
93         }
94
95         if (args.cons->car.type != EXPR_ATOM ||
96             args.cons->car.atom->type != ATOM_NUMBER) {
97             return eval_failure(CONS(gc,
98                                      SYMBOL(gc, "expected-number"),
99                                      args.cons->car),
100                                 scope);
101         }
102
103         result += args.cons->car.atom->num;
104         args = args.cons->cdr;
105     }
106
107     return eval_success(atom_as_expr(create_number_atom(gc, result)), scope);
108 }
109
110 static struct EvalResult eval_funcall(Gc *gc, struct Expr scope, struct Cons *cons)
111 {
112     assert(cons);
113     (void) scope;
114
115     if (!symbol_p(cons->car)) {
116         return eval_failure(CONS(gc,
117                                  SYMBOL(gc, "expected-symbol"),
118                                  cons->car),
119                             scope);
120     }
121
122     /* TODO(#323): set builtin function is not implemented */
123     if (strcmp(cons->car.atom->sym, "+") == 0) {
124         struct EvalResult args = eval_args(gc, scope, cons->cdr);
125         if (args.is_error) {
126             return args;
127         }
128         return plus_op(gc, args.expr, scope);
129     }
130
131     return eval_failure(CONS(gc,
132                              SYMBOL(gc, "unknown-function"),
133                              cons->car),
134                         scope);
135 }
136
137 struct EvalResult eval(Gc *gc, struct Expr scope, struct Expr expr)
138 {
139     switch(expr.type) {
140     case EXPR_ATOM:
141         return eval_atom(gc, scope, expr.atom);
142
143     case EXPR_CONS:
144         return eval_funcall(gc, scope, expr.cons);
145
146     default: {}
147     }
148
149     return eval_failure(CONS(gc,
150                              SYMBOL(gc, "unexpected-expression"),
151                              expr),
152                         scope);
153 }