]> git.lizzy.rs Git - nothing.git/blob - src/script/interpreter.c
c3a3816bf4db32ced9ca8d477150b0cb58a9d794
[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(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(atom_as_expr(atom)));
41     }
42
43     return eval_failure("Unexpected expression", clone_expr(atom_as_expr(atom)));
44 }
45
46 static struct EvalResult eval_args(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(scope, args.atom);
54
55     case EXPR_CONS: {
56         struct EvalResult car = eval(scope, args.cons->car);
57         if (car.is_error) {
58             return car;
59         }
60
61         struct EvalResult cdr = eval_args(scope, args.cons->cdr);
62         if (cdr.is_error) {
63             destroy_expr(car.expr);
64             return cdr;
65         }
66
67         return eval_success(cons_as_expr(create_cons(car.expr, cdr.expr)));
68     }
69
70     default: {}
71     }
72
73     return eval_failure("Unexpected expression", clone_expr(args));
74 }
75
76 static struct EvalResult plus_op(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(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(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(result)));
95 }
96
97 static struct EvalResult eval_funcall(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(cons->car));
104     }
105
106     if (strcmp(cons->car.atom->sym, "+") == 0) {
107         struct EvalResult args = eval_args(scope, cons->cdr);
108         if (args.is_error) {
109             return args;
110         }
111         return plus_op(args.expr);
112     }
113
114     return eval_failure("Unknown function", clone_expr(cons->car));
115 }
116
117 /* TODO: eval does not return new scope after the evaluation */
118 struct EvalResult eval(struct Expr scope, struct Expr expr)
119 {
120     switch(expr.type) {
121     case EXPR_ATOM:
122         return eval_atom(scope, expr.atom);
123
124     case EXPR_CONS:
125         return eval_funcall(scope, expr.cons);
126
127     default: {}
128     }
129
130     return eval_failure("Unexpected expression", clone_expr(expr));
131 }
132
133 void print_eval_error(FILE *stream, struct EvalResult result)
134 {
135     if (!result.is_error) {
136         return;
137     }
138
139     fprintf(stream, "%s\n", result.error);
140     print_expr_as_sexpr(result.expr);
141 }