]> git.lizzy.rs Git - nothing.git/blob - src/script/interpreter.c
Merge pull request #319 from tsoding/gc
[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         return eval_success(clone_expr(gc, atom_as_expr(atom)));
41     }
42
43     return eval_failure("Unexpected expression", clone_expr(gc, atom_as_expr(atom)));
44 }
45
46 static struct EvalResult eval_args(Gc *gc, struct Expr scope, struct Expr args)
47 {
48     (void) scope;
49     (void) args;
50
51     switch(args.type) {
52     case EXPR_ATOM:
53         return eval_atom(gc, scope, args.atom);
54
55     case EXPR_CONS: {
56         struct EvalResult car = eval(gc, scope, args.cons->car);
57         if (car.is_error) {
58             return car;
59         }
60
61         struct EvalResult cdr = eval_args(gc, scope, args.cons->cdr);
62         if (cdr.is_error) {
63             return cdr;
64         }
65
66         return eval_success(cons_as_expr(create_cons(gc, car.expr, cdr.expr)));
67     }
68
69     default: {}
70     }
71
72     return eval_failure("Unexpected expression", clone_expr(gc, args));
73 }
74
75 static struct EvalResult plus_op(Gc *gc, struct Expr args)
76 {
77     float result = 0.0f;
78
79     while (!nil_p(args)) {
80         if (args.type != EXPR_CONS) {
81             return eval_failure("Expected cons", clone_expr(gc, args));
82         }
83
84         if (args.cons->car.type != EXPR_ATOM ||
85             args.cons->car.atom->type != ATOM_NUMBER) {
86             return eval_failure("Expected number", clone_expr(gc, args.cons->car));
87         }
88
89         result += args.cons->car.atom->num;
90         args = args.cons->cdr;
91     }
92
93     return eval_success(atom_as_expr(create_number_atom(gc, result)));
94 }
95
96 static struct EvalResult eval_funcall(Gc *gc, struct Expr scope, struct Cons *cons)
97 {
98     assert(cons);
99     (void) scope;
100
101     if (!symbol_p(cons->car)) {
102         return eval_failure("Expected symbol", clone_expr(gc, cons->car));
103     }
104
105     if (strcmp(cons->car.atom->sym, "+") == 0) {
106         struct EvalResult args = eval_args(gc, scope, cons->cdr);
107         if (args.is_error) {
108             return args;
109         }
110         return plus_op(gc, args.expr);
111     }
112
113     return eval_failure("Unknown function", clone_expr(gc, cons->car));
114 }
115
116 /* TODO(#317): eval does not return new scope after the evaluation */
117 struct EvalResult eval(Gc *gc, struct Expr scope, struct Expr expr)
118 {
119     switch(expr.type) {
120     case EXPR_ATOM:
121         return eval_atom(gc, scope, expr.atom);
122
123     case EXPR_CONS:
124         return eval_funcall(gc, scope, expr.cons);
125
126     default: {}
127     }
128
129     return eval_failure("Unexpected expression", clone_expr(gc, expr));
130 }
131
132 void print_eval_error(FILE *stream, struct EvalResult result)
133 {
134     if (!result.is_error) {
135         return;
136     }
137
138     fprintf(stream, "%s\n", result.error);
139     print_expr_as_sexpr(result.expr);
140 }