]> git.lizzy.rs Git - nothing.git/blob - src/script/expr.c
TODO(#301)
[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     return dup_str;
25 }
26
27 struct Expr atom_as_expr(struct Atom *atom)
28 {
29     struct Expr expr = {
30         .type = EXPR_ATOM,
31         .atom = atom
32     };
33
34     return expr;
35 }
36
37 struct Expr cons_as_expr(struct Cons *cons)
38 {
39     struct Expr expr = {
40         .type = EXPR_CONS,
41         .cons = cons
42     };
43
44     return expr;
45 }
46
47 void print_atom_as_sexpr(struct Atom *atom)
48 {
49     assert(atom);
50
51     switch (atom->type) {
52     case ATOM_SYMBOL:
53         printf("%s", atom->sym);
54         break;
55
56     case ATOM_NUMBER:
57         printf("%f", atom->num);
58         break;
59
60     case ATOM_STRING:
61         printf("\"%s\"", atom->str);
62         break;
63     }
64 }
65
66 void print_cons_as_sexpr(struct Cons *head)
67 {
68     assert(head);
69
70     struct Cons *cons = head;
71
72     printf("(");
73     print_expr_as_sexpr(cons->car);
74
75     while (cons->cdr.type == EXPR_CONS) {
76         cons = cons->cdr.cons;
77         printf(" ");
78         print_expr_as_sexpr(cons->car);
79     }
80
81     if (cons->cdr.atom->type != ATOM_SYMBOL ||
82         strcmp("nil", cons->cdr.atom->sym) != 0) {
83         printf(" . ");
84         print_expr_as_sexpr(cons->cdr);
85     }
86
87     printf(")");
88 }
89
90 void print_expr_as_sexpr(struct Expr expr)
91 {
92     /* TODO(#296): print_expr_as_sexpr doesn't support lists */
93     switch (expr.type) {
94     case EXPR_ATOM:
95         print_atom_as_sexpr(expr.atom);
96         break;
97
98     case EXPR_CONS:
99         print_cons_as_sexpr(expr.cons);
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 }
116
117 struct Cons *create_cons(struct Expr car, struct Expr cdr)
118 {
119     struct Cons *cons = malloc(sizeof(struct Cons));
120     if (cons == NULL) {
121         return NULL;
122     }
123
124     cons->car = car;
125     cons->cdr = cdr;
126
127     return cons;
128 }
129
130 void destroy_cons(struct Cons *cons)
131 {
132     destroy_expr(cons->car);
133     destroy_expr(cons->cdr);
134     free(cons);
135 }
136
137 struct Atom *create_number_atom(float num)
138 {
139     struct Atom *atom = malloc(sizeof(struct Atom));
140     if (atom == NULL) {
141         return NULL;
142     }
143     atom->type = ATOM_NUMBER;
144     atom->num = num;
145     return atom;
146 }
147
148 struct Atom *create_string_atom(const char *str, const char *str_end)
149 {
150     struct Atom *atom = malloc(sizeof(struct Atom));
151     if (atom == NULL) {
152         return NULL;
153     }
154     atom->type = ATOM_STRING;
155     atom->str = string_duplicate(str, str_end);
156     if (atom->str == NULL) {
157         free(atom);
158         return NULL;
159     }
160
161     return atom;
162 }
163
164 struct Atom *create_symbol_atom(const char *sym, const char *sym_end)
165 {
166     struct Atom *atom = malloc(sizeof(struct Atom));
167     if (atom == NULL) {
168         return NULL;
169     }
170     atom->type = ATOM_SYMBOL;
171     atom->sym = string_duplicate(sym, sym_end);
172     if (atom->sym == NULL) {
173         free(atom);
174         return NULL;
175     }
176
177     return atom;
178 }
179
180 void destroy_atom(struct Atom *atom)
181 {
182     switch (atom->type) {
183     case ATOM_SYMBOL:
184     case ATOM_STRING: {
185         free(atom->str);
186     } break;
187
188     case ATOM_NUMBER: {
189         /* Nothing */
190     } break;
191     }
192
193     free(atom);
194 }