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