]> git.lizzy.rs Git - nothing.git/blob - src/script/interpreter.c
TODO(#322)
[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
9 struct EvalResult eval_success(struct Expr expr)
10 {
11     struct EvalResult result = {
12         .is_error = false,
13         .expr = expr,
14         .error = NULL
15     };
16
17     return result;
18 }
19
20 struct EvalResult eval_failure(const char *error, struct Expr expr)
21 {
22     struct EvalResult result = {
23         .is_error = true,
24         .error = error,
25         .expr = expr
26     };
27
28     return result;
29 }
30
31 static struct EvalResult eval_atom(Gc *gc, struct Expr scope, struct Atom *atom)
32 {
33     (void) scope;
34
35     /* TODO(#314): Evaluating symbols is not implemented */
36     switch (atom->type) {
37     case ATOM_NUMBER:
38     case ATOM_SYMBOL:
39     case ATOM_STRING:
40         /* TODO(#322): get rid of unnecessary clone_expr from interpreter */
41         return eval_success(clone_expr(gc, atom_as_expr(atom)));
42     }
43
44     return eval_failure("Unexpected expression", clone_expr(gc, atom_as_expr(atom)));
45 }
46
47 static struct EvalResult eval_args(Gc *gc, struct Expr scope, struct Expr args)
48 {
49     (void) scope;
50     (void) args;
51
52     switch(args.type) {
53     case EXPR_ATOM:
54         return eval_atom(gc, scope, args.atom);
55
56     case EXPR_CONS: {
57         struct EvalResult car = eval(gc, scope, args.cons->car);
58         if (car.is_error) {
59             return car;
60         }
61
62         struct EvalResult cdr = eval_args(gc, scope, args.cons->cdr);
63         if (cdr.is_error) {
64             return cdr;
65         }
66
67         return eval_success(cons_as_expr(create_cons(gc, car.expr, cdr.expr)));
68     }
69
70     default: {}
71     }
72
73     return eval_failure("Unexpected expression", clone_expr(gc, args));
74 }
75
76 static struct EvalResult plus_op(Gc *gc, struct Expr args)
77 {
78     float result = 0.0f;
79
80     while (!nil_p(args)) {
81         if (args.type != EXPR_CONS) {
82             return eval_failure("Expected cons", clone_expr(gc, args));
83         }
84
85         if (args.cons->car.type != EXPR_ATOM ||
86             args.cons->car.atom->type != ATOM_NUMBER) {
87             return eval_failure("Expected number", clone_expr(gc, args.cons->car));
88         }
89
90         result += args.cons->car.atom->num;
91         args = args.cons->cdr;
92     }
93
94     return eval_success(atom_as_expr(create_number_atom(gc, result)));
95 }
96
97 static struct EvalResult eval_funcall(Gc *gc, struct Expr scope, struct Cons *cons)
98 {
99     assert(cons);
100     (void) scope;
101
102     if (!symbol_p(cons->car)) {
103         return eval_failure("Expected symbol", clone_expr(gc, cons->car));
104     }
105
106     /* TODO: set builtin function is not implemented */
107     /* depends on #317 */
108     if (strcmp(cons->car.atom->sym, "+") == 0) {
109         struct EvalResult args = eval_args(gc, scope, cons->cdr);
110         if (args.is_error) {
111             return args;
112         }
113         return plus_op(gc, args.expr);
114     }
115
116     return eval_failure("Unknown function", clone_expr(gc, cons->car));
117 }
118
119 /* TODO(#317): eval does not return new scope after the evaluation */
120 struct EvalResult eval(Gc *gc, struct Expr scope, struct Expr expr)
121 {
122     switch(expr.type) {
123     case EXPR_ATOM:
124         return eval_atom(gc, scope, expr.atom);
125
126     case EXPR_CONS:
127         return eval_funcall(gc, scope, expr.cons);
128
129     default: {}
130     }
131
132     return eval_failure("Unexpected expression", clone_expr(gc, expr));
133 }
134
135 void print_eval_error(FILE *stream, struct EvalResult result)
136 {
137     if (!result.is_error) {
138         return;
139     }
140
141     fprintf(stream, "%s\n", result.error);
142     print_expr_as_sexpr(result.expr);
143 }