]> git.lizzy.rs Git - nothing.git/blob - src/script/interpreter.c
(#311) Implement eval_atom
[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     switch (atom->type) {
36     case ATOM_NUMBER:
37     case ATOM_STRING:
38         return eval_success(atom_as_expr(atom));
39
40     case ATOM_SYMBOL:
41         /* TODO: Evaluating symbols is not implemented */
42         return eval_failure("Evaluating symbols is not implemented",
43                             atom_as_expr(atom));
44     }
45
46     return eval_failure("Unexpected expression", atom_as_expr(atom));
47 }
48
49 static struct EvalResult eval_args(struct Expr scope, struct Expr args)
50 {
51     (void) scope;
52     (void) args;
53
54     switch(args.type) {
55     case EXPR_ATOM:
56         return eval_atom(scope, args.atom);
57
58     case EXPR_CONS: {
59         struct EvalResult car = eval(scope, args.cons->car);
60         if (car.is_error) {
61             return car;
62         }
63
64         struct EvalResult cdr = eval_args(scope, args.cons->cdr);
65         if (cdr.is_error) {
66             return cdr;
67         }
68
69         /* TODO: memory leak */
70         return eval_success(cons_as_expr(create_cons(car.expr, cdr.expr)));
71     }
72
73     default: {}
74     }
75
76     return eval_failure("Unexpected expression", args);
77 }
78
79 static struct EvalResult plus_op(struct Expr args)
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);
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);
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(result)));
98 }
99
100 static struct EvalResult eval_funcall(struct Expr scope, struct Cons *cons)
101 {
102     assert(cons);
103     (void) scope;
104
105     if (cons->car.type != EXPR_ATOM && cons->car.atom->type != ATOM_SYMBOL) {
106         return eval_failure("Not a function", cons->car);
107     }
108
109     if (strcmp(cons->car.atom->sym, "+")) {
110         struct EvalResult args = eval_args(scope, cons->cdr);
111         if (args.is_error) {
112             return args;
113         }
114         return plus_op(args.expr);
115     }
116
117     return eval_failure("Unknown function", cons->car);
118 }
119
120 struct EvalResult eval(struct Expr scope, struct Expr expr)
121 {
122     switch(expr.type) {
123     case EXPR_ATOM:
124         return eval_atom(scope, expr.atom);
125
126     case EXPR_CONS:
127         return eval_funcall(scope, expr.cons);
128
129     default: {}
130     }
131
132     return eval_failure("Unexpected expression", expr);
133 }