]> git.lizzy.rs Git - nothing.git/blob - src/script/interpreter.c
(#311) Implement clone_expr
[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: 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(atom_as_expr(atom));
41     }
42
43     return eval_failure("Unexpected expression", 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             return cdr;
64         }
65
66         /* TODO: memory leak */
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", 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", 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", 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 (cons->car.type != EXPR_ATOM && cons->car.atom->type != ATOM_SYMBOL) {
103         return eval_failure("Not a function", 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", cons->car);
115 }
116
117 struct EvalResult eval(struct Expr scope, struct Expr expr)
118 {
119     switch(expr.type) {
120     case EXPR_ATOM:
121         return eval_atom(scope, expr.atom);
122
123     case EXPR_CONS:
124         return eval_funcall(scope, expr.cons);
125
126     default: {}
127     }
128
129     return eval_failure("Unexpected expression", 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 }