]> git.lizzy.rs Git - nothing.git/blob - src/script/expr.c
Introduce ids for rigid_rects
[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     case ATOM_NATIVE:
77         printf("<native>");
78         break;
79     }
80 }
81
82 void print_cons_as_sexpr(struct Cons *head)
83 {
84     assert(head);
85
86     struct Cons *cons = head;
87
88     printf("(");
89     print_expr_as_sexpr(cons->car);
90
91     while (cons->cdr.type == EXPR_CONS) {
92         cons = cons->cdr.cons;
93         printf(" ");
94         print_expr_as_sexpr(cons->car);
95     }
96
97     if (cons->cdr.atom->type != ATOM_SYMBOL ||
98         strcmp("nil", cons->cdr.atom->sym) != 0) {
99         printf(" . ");
100         print_expr_as_sexpr(cons->cdr);
101     }
102
103     printf(")");
104 }
105
106 void print_expr_as_sexpr(struct Expr expr)
107 {
108     /* TODO(#296): print_expr_as_sexpr doesn't support lists */
109     switch (expr.type) {
110     case EXPR_ATOM:
111         print_atom_as_sexpr(expr.atom);
112         break;
113
114     case EXPR_CONS:
115         print_cons_as_sexpr(expr.cons);
116         break;
117
118     case EXPR_VOID:
119         break;
120     }
121 }
122
123 void destroy_expr(struct Expr expr)
124 {
125     switch (expr.type) {
126     case EXPR_ATOM:
127         destroy_atom(expr.atom);
128         break;
129
130     case EXPR_CONS:
131         destroy_cons(expr.cons);
132         break;
133
134     case EXPR_VOID:
135         break;
136     }
137 }
138
139 struct Cons *create_cons(Gc *gc, struct Expr car, struct Expr cdr)
140 {
141     struct Cons *cons = malloc(sizeof(struct Cons));
142     if (cons == NULL) {
143         return NULL;
144     }
145
146     cons->car = car;
147     cons->cdr = cdr;
148
149     if (gc_add_expr(gc, cons_as_expr(cons)) < 0) {
150         free(cons);
151         return NULL;
152     }
153
154     return cons;
155 }
156
157 void destroy_cons(struct Cons *cons)
158 {
159     free(cons);
160 }
161
162 struct Atom *create_number_atom(Gc *gc, long int num)
163 {
164     struct Atom *atom = malloc(sizeof(struct Atom));
165     if (atom == NULL) {
166         return NULL;
167     }
168     atom->type = ATOM_NUMBER;
169     atom->num = num;
170
171     if (gc_add_expr(gc, atom_as_expr(atom)) < 0) {
172         free(atom);
173         return NULL;
174     }
175
176     return atom;
177 }
178
179 struct Atom *create_string_atom(Gc *gc, const char *str, const char *str_end)
180 {
181     struct Atom *atom = malloc(sizeof(struct Atom));
182
183     if (atom == NULL) {
184         goto error;
185     }
186
187     atom->type = ATOM_STRING;
188     atom->str = string_duplicate(str, str_end);
189
190     if (atom->str == NULL) {
191         goto error;
192     }
193
194     if (gc_add_expr(gc, atom_as_expr(atom)) < 0) {
195         goto error;
196     }
197
198     return atom;
199
200 error:
201     if (atom != NULL) {
202         if (atom->str != NULL) {
203             free(atom->str);
204         }
205         free(atom);
206     }
207
208     return NULL;
209 }
210
211 struct Atom *create_symbol_atom(Gc *gc, const char *sym, const char *sym_end)
212 {
213     struct Atom *atom = malloc(sizeof(struct Atom));
214
215     if (atom == NULL) {
216         goto error;
217     }
218
219     atom->type = ATOM_SYMBOL;
220     atom->sym = string_duplicate(sym, sym_end);
221
222     if (atom->sym == NULL) {
223         goto error;
224     }
225
226     if (gc_add_expr(gc, atom_as_expr(atom)) < 0) {
227         goto error;
228     }
229
230     return atom;
231
232 error:
233     if (atom != NULL) {
234         if (atom->sym != NULL) {
235             free(atom->sym);
236         }
237         free(atom);
238     }
239
240     return NULL;
241 }
242
243 struct Atom *create_native_atom(Gc *gc, NativeFunction fun)
244 {
245     struct Atom *atom = malloc(sizeof(struct Atom));
246
247     if (atom == NULL) {
248         goto error;
249     }
250
251     atom->type = ATOM_NATIVE;
252     atom->fun = fun;
253
254     if (gc_add_expr(gc, atom_as_expr(atom)) < 0) {
255         goto error;
256     }
257
258     return atom;
259
260 error:
261     if (atom != NULL) {
262         free(atom);
263     }
264
265     return NULL;
266 }
267
268 void destroy_atom(struct Atom *atom)
269 {
270     switch (atom->type) {
271     case ATOM_SYMBOL:
272     case ATOM_STRING: {
273         free(atom->str);
274     } break;
275
276     case ATOM_NATIVE:
277     case ATOM_NUMBER: {
278         /* Nothing */
279     } break;
280     }
281
282     free(atom);
283 }