]> git.lizzy.rs Git - nothing.git/blob - src/script/expr.c
1ecec674efccfc9a362b050dee8a5d4fd1ba1d82
[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 #include "str.h"
11
12 struct Expr atom_as_expr(struct Atom *atom)
13 {
14     struct Expr expr = {
15         .type = EXPR_ATOM,
16         .atom = atom
17     };
18
19     return expr;
20 }
21
22 struct Expr cons_as_expr(struct Cons *cons)
23 {
24     struct Expr expr = {
25         .type = EXPR_CONS,
26         .cons = cons
27     };
28
29     return expr;
30 }
31
32 struct Expr void_expr(void)
33 {
34     struct Expr expr = {
35         .type = EXPR_VOID
36     };
37
38     return expr;
39 }
40
41 void print_atom_as_sexpr(struct Atom *atom)
42 {
43     assert(atom);
44
45     switch (atom->type) {
46     case ATOM_SYMBOL:
47         printf("%s", atom->sym);
48         break;
49
50     case ATOM_NUMBER:
51         printf("%ld", atom->num);
52         break;
53
54     case ATOM_STRING:
55         printf("\"%s\"", atom->str);
56         break;
57
58     case ATOM_NATIVE:
59         printf("<native>");
60         break;
61     }
62 }
63
64 void print_cons_as_sexpr(struct Cons *head)
65 {
66     assert(head);
67
68     struct Cons *cons = head;
69
70     printf("(");
71     print_expr_as_sexpr(cons->car);
72
73     while (cons->cdr.type == EXPR_CONS) {
74         cons = cons->cdr.cons;
75         printf(" ");
76         print_expr_as_sexpr(cons->car);
77     }
78
79     if (cons->cdr.atom->type != ATOM_SYMBOL ||
80         strcmp("nil", cons->cdr.atom->sym) != 0) {
81         printf(" . ");
82         print_expr_as_sexpr(cons->cdr);
83     }
84
85     printf(")");
86 }
87
88 void print_expr_as_sexpr(struct Expr expr)
89 {
90     switch (expr.type) {
91     case EXPR_ATOM:
92         print_atom_as_sexpr(expr.atom);
93         break;
94
95     case EXPR_CONS:
96         print_cons_as_sexpr(expr.cons);
97         break;
98
99     case EXPR_VOID:
100         break;
101     }
102 }
103
104 void destroy_expr(struct Expr expr)
105 {
106     switch (expr.type) {
107     case EXPR_ATOM:
108         destroy_atom(expr.atom);
109         break;
110
111     case EXPR_CONS:
112         destroy_cons(expr.cons);
113         break;
114
115     case EXPR_VOID:
116         break;
117     }
118 }
119
120 struct Cons *create_cons(Gc *gc, struct Expr car, struct Expr cdr)
121 {
122     struct Cons *cons = malloc(sizeof(struct Cons));
123     if (cons == NULL) {
124         return NULL;
125     }
126
127     cons->car = car;
128     cons->cdr = cdr;
129
130     if (gc_add_expr(gc, cons_as_expr(cons)) < 0) {
131         free(cons);
132         return NULL;
133     }
134
135     return cons;
136 }
137
138 void destroy_cons(struct Cons *cons)
139 {
140     free(cons);
141 }
142
143 struct Atom *create_number_atom(Gc *gc, long int num)
144 {
145     struct Atom *atom = malloc(sizeof(struct Atom));
146     if (atom == NULL) {
147         return NULL;
148     }
149     atom->type = ATOM_NUMBER;
150     atom->num = num;
151
152     if (gc_add_expr(gc, atom_as_expr(atom)) < 0) {
153         free(atom);
154         return NULL;
155     }
156
157     return atom;
158 }
159
160 struct Atom *create_string_atom(Gc *gc, const char *str, const char *str_end)
161 {
162     struct Atom *atom = malloc(sizeof(struct Atom));
163
164     if (atom == NULL) {
165         goto error;
166     }
167
168     atom->type = ATOM_STRING;
169     atom->str = string_duplicate(str, str_end);
170
171     if (atom->str == NULL) {
172         goto error;
173     }
174
175     if (gc_add_expr(gc, atom_as_expr(atom)) < 0) {
176         goto error;
177     }
178
179     return atom;
180
181 error:
182     if (atom != NULL) {
183         if (atom->str != NULL) {
184             free(atom->str);
185         }
186         free(atom);
187     }
188
189     return NULL;
190 }
191
192 struct Atom *create_symbol_atom(Gc *gc, const char *sym, const char *sym_end)
193 {
194     struct Atom *atom = malloc(sizeof(struct Atom));
195
196     if (atom == NULL) {
197         goto error;
198     }
199
200     atom->type = ATOM_SYMBOL;
201     atom->sym = string_duplicate(sym, sym_end);
202
203     if (atom->sym == NULL) {
204         goto error;
205     }
206
207     if (gc_add_expr(gc, atom_as_expr(atom)) < 0) {
208         goto error;
209     }
210
211     return atom;
212
213 error:
214     if (atom != NULL) {
215         if (atom->sym != NULL) {
216             free(atom->sym);
217         }
218         free(atom);
219     }
220
221     return NULL;
222 }
223
224 struct Atom *create_native_atom(Gc *gc, NativeFunction fun, void *param)
225 {
226     struct Atom *atom = malloc(sizeof(struct Atom));
227
228     if (atom == NULL) {
229         goto error;
230     }
231
232     atom->type = ATOM_NATIVE;
233     atom->native.fun = fun;
234     atom->native.param = param;
235
236     if (gc_add_expr(gc, atom_as_expr(atom)) < 0) {
237         goto error;
238     }
239
240     return atom;
241
242 error:
243     if (atom != NULL) {
244         free(atom);
245     }
246
247     return NULL;
248 }
249
250 void destroy_atom(struct Atom *atom)
251 {
252     switch (atom->type) {
253     case ATOM_SYMBOL:
254     case ATOM_STRING: {
255         free(atom->str);
256     } break;
257
258     case ATOM_NATIVE:
259     case ATOM_NUMBER: {
260         /* Nothing */
261     } break;
262     }
263
264     free(atom);
265 }
266
267 static int atom_as_sexpr(struct Atom *atom, char *output, size_t n)
268 {
269     assert(atom);
270     assert(output);
271
272     switch (atom->type) {
273     case ATOM_SYMBOL:
274         return snprintf(output, n, "%s", atom->sym);
275
276     case ATOM_NUMBER:
277         return snprintf(output, n, "%ld", atom->num);
278
279     case ATOM_STRING:
280         return snprintf(output, n, "\"%s\"", atom->str);
281
282     case ATOM_NATIVE:
283         return snprintf(output, n, "<native>");
284     }
285
286     return 0;
287 }
288
289 static int cons_as_sexpr(struct Cons *head, char *output, size_t n)
290 {
291     assert(head);
292     assert(output);
293
294     /* TODO(#378): cons_as_sexpr does not handle encoding errors of snprintf */
295
296     struct Cons *cons = head;
297
298     int m = (int) n;
299
300     int c = snprintf(output, n, "(");
301     if (m - c <= c) {
302         return c;
303     }
304
305     c += expr_as_sexpr(cons->car, output + c, (size_t) (m - c));
306     if (m - c <= 0) {
307         return c;
308     }
309
310     while (cons->cdr.type == EXPR_CONS) {
311         cons = cons->cdr.cons;
312
313         c += snprintf(output + c, (size_t) (m - c), " ");
314         if (m - c <= 0) {
315             return c;
316         }
317
318         c += expr_as_sexpr(cons->car, output + c, (size_t) (m - c));
319         if (m - c <= 0) {
320             return c;
321         }
322     }
323
324     if (cons->cdr.atom->type != ATOM_SYMBOL ||
325         strcmp("nil", cons->cdr.atom->sym) != 0) {
326
327         c += snprintf(output + c, (size_t) (m - c), " . ");
328         if (m - c <= 0) {
329             return c;
330         }
331
332         c += expr_as_sexpr(cons->cdr, output + c, (size_t) (m - c));
333         if (m - c <= 0) {
334             return c;
335         }
336     }
337
338     c += snprintf(output + c, (size_t) (m - c), ")");
339     if (m - c <= 0) {
340         return c;
341     }
342
343     return c;
344 }
345
346 int expr_as_sexpr(struct Expr expr, char *output, size_t n)
347 {
348     switch(expr.type) {
349     case EXPR_ATOM:
350         return atom_as_sexpr(expr.atom, output, n);
351
352     case EXPR_CONS:
353         return cons_as_sexpr(expr.cons, output, n);
354
355     case EXPR_VOID:
356         return 0;
357     }
358
359     return 0;
360 }