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