]> git.lizzy.rs Git - nothing.git/blob - src/script/expr.c
Integrate GC with expr creation
[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 static struct Atom *clone_atom(Gc *gc, struct Atom *atom)
51 {
52     assert(atom);
53
54     switch(atom->type) {
55     case ATOM_NUMBER:
56         return create_number_atom(gc, atom->num);
57
58     case ATOM_STRING:
59         return create_string_atom(gc, atom->str, NULL);
60
61     case ATOM_SYMBOL:
62         return create_symbol_atom(gc, atom->sym, NULL);
63     }
64
65     return atom;
66 }
67
68 struct Expr clone_expr(Gc *gc, struct Expr expr)
69 {
70     switch (expr.type) {
71     case EXPR_ATOM:
72         return atom_as_expr(clone_atom(gc, expr.atom));
73
74     case EXPR_CONS:
75         return cons_as_expr(
76             create_cons(gc,
77                 clone_expr(gc, expr.cons->car),
78                 clone_expr(gc, expr.cons->cdr)));
79
80     default: {}
81     }
82
83     return expr;
84 }
85
86 struct Expr void_expr(void)
87 {
88     struct Expr expr = {
89         .type = EXPR_VOID
90     };
91
92     return expr;
93 }
94
95 void print_atom_as_sexpr(struct Atom *atom)
96 {
97     assert(atom);
98
99     switch (atom->type) {
100     case ATOM_SYMBOL:
101         printf("%s", atom->sym);
102         break;
103
104     case ATOM_NUMBER:
105         printf("%f", atom->num);
106         break;
107
108     case ATOM_STRING:
109         printf("\"%s\"", atom->str);
110         break;
111     }
112 }
113
114 void print_cons_as_sexpr(struct Cons *head)
115 {
116     assert(head);
117
118     struct Cons *cons = head;
119
120     printf("(");
121     print_expr_as_sexpr(cons->car);
122
123     while (cons->cdr.type == EXPR_CONS) {
124         cons = cons->cdr.cons;
125         printf(" ");
126         print_expr_as_sexpr(cons->car);
127     }
128
129     if (cons->cdr.atom->type != ATOM_SYMBOL ||
130         strcmp("nil", cons->cdr.atom->sym) != 0) {
131         printf(" . ");
132         print_expr_as_sexpr(cons->cdr);
133     }
134
135     printf(")");
136 }
137
138 void print_expr_as_sexpr(struct Expr expr)
139 {
140     /* TODO(#296): print_expr_as_sexpr doesn't support lists */
141     switch (expr.type) {
142     case EXPR_ATOM:
143         print_atom_as_sexpr(expr.atom);
144         break;
145
146     case EXPR_CONS:
147         print_cons_as_sexpr(expr.cons);
148         break;
149
150     case EXPR_VOID:
151         break;
152     }
153
154     printf("\n");
155 }
156
157 void destroy_expr_rec(struct Expr expr)
158 {
159     switch (expr.type) {
160     case EXPR_ATOM:
161         destroy_atom(expr.atom);
162         break;
163
164     case EXPR_CONS:
165         destroy_cons_rec(expr.cons);
166         break;
167
168     case EXPR_VOID:
169         break;
170     }
171 }
172
173 void destroy_expr(struct Expr expr)
174 {
175     switch (expr.type) {
176     case EXPR_ATOM:
177         destroy_atom(expr.atom);
178         break;
179
180     case EXPR_CONS:
181         destroy_cons(expr.cons);
182         break;
183
184     case EXPR_VOID:
185         break;
186     }
187 }
188
189 struct Cons *create_cons(Gc *gc, struct Expr car, struct Expr cdr)
190 {
191     struct Cons *cons = malloc(sizeof(struct Cons));
192     if (cons == NULL) {
193         return NULL;
194     }
195
196     cons->car = car;
197     cons->cdr = cdr;
198
199     if (gc_add_expr(gc, cons_as_expr(cons)) < 0) {
200         free(cons);
201         return NULL;
202     }
203
204     return cons;
205 }
206
207 void destroy_cons_rec(struct Cons *cons)
208 {
209     destroy_expr_rec(cons->car);
210     destroy_expr_rec(cons->cdr);
211     free(cons);
212 }
213
214 void destroy_cons(struct Cons *cons)
215 {
216     free(cons);
217 }
218
219 struct Atom *create_number_atom(Gc *gc, float num)
220 {
221     struct Atom *atom = malloc(sizeof(struct Atom));
222     if (atom == NULL) {
223         return NULL;
224     }
225     atom->type = ATOM_NUMBER;
226     atom->num = num;
227
228     if (gc_add_expr(gc, atom_as_expr(atom)) < 0) {
229         free(atom);
230         return NULL;
231     }
232
233     return atom;
234 }
235
236 struct Atom *create_string_atom(Gc *gc, const char *str, const char *str_end)
237 {
238     struct Atom *atom = malloc(sizeof(struct Atom));
239
240     if (atom == NULL) {
241         goto error;
242     }
243
244     atom->type = ATOM_STRING;
245     atom->str = string_duplicate(str, str_end);
246
247     if (atom->str == NULL) {
248         goto error;
249     }
250
251     if (gc_add_expr(gc, atom_as_expr(atom)) < 0) {
252         goto error;
253     }
254
255     return atom;
256
257 error:
258     if (atom != NULL) {
259         if (atom->str != NULL) {
260             free(atom->str);
261         }
262         free(atom);
263     }
264
265     return NULL;
266 }
267
268 struct Atom *create_symbol_atom(Gc *gc, const char *sym, const char *sym_end)
269 {
270     struct Atom *atom = malloc(sizeof(struct Atom));
271
272     if (atom == NULL) {
273         goto error;
274     }
275
276     atom->type = ATOM_SYMBOL;
277     atom->sym = string_duplicate(sym, sym_end);
278
279     if (atom->sym == NULL) {
280         goto error;
281     }
282
283     if (gc_add_expr(gc, atom_as_expr(atom)) < 0) {
284         goto error;
285     }
286
287     return atom;
288
289 error:
290     if (atom != NULL) {
291         if (atom->sym != NULL) {
292             free(atom->sym);
293         }
294         free(atom);
295     }
296
297     return NULL;
298 }
299
300 void destroy_atom(struct Atom *atom)
301 {
302     switch (atom->type) {
303     case ATOM_SYMBOL:
304     case ATOM_STRING: {
305         free(atom->str);
306     } break;
307
308     case ATOM_NUMBER: {
309         /* Nothing */
310     } break;
311     }
312
313     free(atom);
314 }