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