]> git.lizzy.rs Git - nothing.git/blob - src/script/expr.c
Support lambdas
[nothing.git] / src / script / expr.c
1 #include <assert.h>
2 #include <ctype.h>
3 #include <stdarg.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include "script/expr.h"
9 #include "script/gc.h"
10
11 static char *string_duplicate(const char *str,
12                               const char *str_end)
13 {
14     if (str_end != NULL && str > str_end) {
15         return NULL;
16     }
17
18     const size_t n = str_end == NULL ? strlen(str) : (size_t) (str_end - str);
19     char *dup_str = malloc(sizeof(char) * (n + 1));
20     if (dup_str == NULL) {
21         return NULL;
22     }
23
24     memcpy(dup_str, str, n);
25     dup_str[n] = '\0';
26
27     return dup_str;
28 }
29
30 struct Expr atom_as_expr(struct Atom *atom)
31 {
32     struct Expr expr = {
33         .type = EXPR_ATOM,
34         .atom = atom
35     };
36
37     return expr;
38 }
39
40 struct Expr cons_as_expr(struct Cons *cons)
41 {
42     struct Expr expr = {
43         .type = EXPR_CONS,
44         .cons = cons
45     };
46
47     return expr;
48 }
49
50 struct Expr void_expr(void)
51 {
52     struct Expr expr = {
53         .type = EXPR_VOID
54     };
55
56     return expr;
57 }
58
59 void print_atom_as_sexpr(struct Atom *atom)
60 {
61     assert(atom);
62
63     switch (atom->type) {
64     case ATOM_SYMBOL:
65         printf("%s", atom->sym);
66         break;
67
68     case ATOM_NUMBER:
69         printf("%ld", atom->num);
70         break;
71
72     case ATOM_STRING:
73         printf("\"%s\"", atom->str);
74         break;
75     }
76 }
77
78 void print_cons_as_sexpr(struct Cons *head)
79 {
80     assert(head);
81
82     struct Cons *cons = head;
83
84     printf("(");
85     print_expr_as_sexpr(cons->car);
86
87     while (cons->cdr.type == EXPR_CONS) {
88         cons = cons->cdr.cons;
89         printf(" ");
90         print_expr_as_sexpr(cons->car);
91     }
92
93     if (cons->cdr.atom->type != ATOM_SYMBOL ||
94         strcmp("nil", cons->cdr.atom->sym) != 0) {
95         printf(" . ");
96         print_expr_as_sexpr(cons->cdr);
97     }
98
99     printf(")");
100 }
101
102 void print_expr_as_sexpr(struct Expr expr)
103 {
104     /* TODO(#296): print_expr_as_sexpr doesn't support lists */
105     switch (expr.type) {
106     case EXPR_ATOM:
107         print_atom_as_sexpr(expr.atom);
108         break;
109
110     case EXPR_CONS:
111         print_cons_as_sexpr(expr.cons);
112         break;
113
114     case EXPR_VOID:
115         break;
116     }
117 }
118
119 void destroy_expr(struct Expr expr)
120 {
121     switch (expr.type) {
122     case EXPR_ATOM:
123         destroy_atom(expr.atom);
124         break;
125
126     case EXPR_CONS:
127         destroy_cons(expr.cons);
128         break;
129
130     case EXPR_VOID:
131         break;
132     }
133 }
134
135 struct Cons *create_cons(Gc *gc, struct Expr car, struct Expr cdr)
136 {
137     struct Cons *cons = malloc(sizeof(struct Cons));
138     if (cons == NULL) {
139         return NULL;
140     }
141
142     cons->car = car;
143     cons->cdr = cdr;
144
145     if (gc_add_expr(gc, cons_as_expr(cons)) < 0) {
146         free(cons);
147         return NULL;
148     }
149
150     return cons;
151 }
152
153 void destroy_cons(struct Cons *cons)
154 {
155     free(cons);
156 }
157
158 struct Atom *create_number_atom(Gc *gc, long int num)
159 {
160     struct Atom *atom = malloc(sizeof(struct Atom));
161     if (atom == NULL) {
162         return NULL;
163     }
164     atom->type = ATOM_NUMBER;
165     atom->num = num;
166
167     if (gc_add_expr(gc, atom_as_expr(atom)) < 0) {
168         free(atom);
169         return NULL;
170     }
171
172     return atom;
173 }
174
175 struct Atom *create_string_atom(Gc *gc, const char *str, const char *str_end)
176 {
177     struct Atom *atom = malloc(sizeof(struct Atom));
178
179     if (atom == NULL) {
180         goto error;
181     }
182
183     atom->type = ATOM_STRING;
184     atom->str = string_duplicate(str, str_end);
185
186     if (atom->str == NULL) {
187         goto error;
188     }
189
190     if (gc_add_expr(gc, atom_as_expr(atom)) < 0) {
191         goto error;
192     }
193
194     return atom;
195
196 error:
197     if (atom != NULL) {
198         if (atom->str != NULL) {
199             free(atom->str);
200         }
201         free(atom);
202     }
203
204     return NULL;
205 }
206
207 struct Atom *create_symbol_atom(Gc *gc, const char *sym, const char *sym_end)
208 {
209     struct Atom *atom = malloc(sizeof(struct Atom));
210
211     if (atom == NULL) {
212         goto error;
213     }
214
215     atom->type = ATOM_SYMBOL;
216     atom->sym = string_duplicate(sym, sym_end);
217
218     if (atom->sym == NULL) {
219         goto error;
220     }
221
222     if (gc_add_expr(gc, atom_as_expr(atom)) < 0) {
223         goto error;
224     }
225
226     return atom;
227
228 error:
229     if (atom != NULL) {
230         if (atom->sym != NULL) {
231             free(atom->sym);
232         }
233         free(atom);
234     }
235
236     return NULL;
237 }
238
239 void destroy_atom(struct Atom *atom)
240 {
241     switch (atom->type) {
242     case ATOM_SYMBOL:
243     case ATOM_STRING: {
244         free(atom->str);
245     } break;
246
247     case ATOM_NUMBER: {
248         /* Nothing */
249     } break;
250     }
251
252     free(atom);
253 }