2 Copyright © 2023 Simon Forman
4 This file is part of Thun
6 Thun is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 Thun is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with Thun. If not see <http://www.gnu.org/licenses/>.
31 const char *BLANKS = " \t";
32 const char *FALSE = "false";
33 const char *TRUE = "true";
37 reallocate_function (void *ptr, __attribute__((unused)) size_t old_size, size_t new_size) {
38 return GC_REALLOC(ptr, new_size);
43 deallocate_function (void *ptr, __attribute__((unused)) size_t size) {
49 my_callback(GC_PTR void_obj, __attribute__((unused)) GC_PTR void_environment) {
50 mpz_t *obj = (mpz_t*)void_obj;
56 push_integer_from_str(char *str, JoyList tail)
58 JoyList el = newJoyList;
59 el->head.kind = joyInt;
60 mpz_init_set_str(el->head.value.i, str, 10);
61 GC_register_finalizer(el->head.value.i, my_callback, NULL, NULL, NULL);
67 /* Pre-declare so we can use it in print_node(). */
69 print_list(JoyList el);
77 gmp_printf("%Zd", j.value.i);
80 printf("%s", j.value.symbol);
90 print_list(j.value.el);
100 print_list(JoyList el)
103 print_node(el->head);
113 trim_leading_blanks(char *str)
115 size_t offset = strspn(str, BLANKS);
116 return (offset == strlen(str)) ? NULL : (str + offset);
121 make_non_list_node(char *text, size_t size)
124 const struct dict_entry *interned;
125 JoyList node = newJoyList;
127 interned = in_word_set(text, size);
129 node->head.kind = joySymbol;
130 node->head.value.symbol = interned->name;
134 sym = GC_malloc(size + 1); /* one more for the zero, right? */
135 strncat(sym, text, size);
137 if (!strncmp(sym, FALSE, 6)) { /* I know it's wrong to hardcode the length here. Sorry. */
138 /* If head was a pointer we could reuse Boolean singletons... */
139 node->head.kind = joyFalse;
140 node->head.value.boolean = 0;
142 } else if (!strncmp(sym, TRUE, 5)) { /* I know it's wrong to hardcode the length here. Sorry. */
143 node->head.kind = joyTrue;
144 node->head.value.boolean = 1;
146 } else if (mpz_init_set_str(node->head.value.i, sym, 10)) {
147 /* Non-zero (-1) return value means the string is not an int. */
148 mpz_clear(node->head.value.i);
149 node->head.kind = joySymbol;
150 node->head.value.symbol = sym;
153 node->head.kind = joyInt;
154 GC_register_finalizer(node->head.value.i, my_callback, NULL, NULL, NULL);
160 /* Create a new list_node with a joyList head. */
162 make_list_node(JoyList el)
164 JoyList node = newJoyList;
165 node->head.kind = joyList;
166 node->head.value.el = el;
172 ██████╗ █████╗ ██████╗ ███████╗███████╗██████╗
173 ██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔════╝██╔══██╗
174 ██████╔╝███████║██████╔╝███████╗█████╗ ██████╔╝
175 ██╔═══╝ ██╔══██║██╔══██╗╚════██║██╔══╝ ██╔══██╗
176 ██║ ██║ ██║██║ ██║███████║███████╗██║ ██║
177 ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚══════╝╚═╝ ╚═╝
182 parse_list(char **text)
185 Extract terms from the text until a closing bracket is found.
189 JoyList result = EMPTY_LIST;
191 /* NULL string input? */
193 printf("Missing ']' bracket. A\n");
197 *text = trim_leading_blanks(*text);
200 printf("Missing ']' bracket. B\n");
204 /* Look for blanks or brackets. */
205 rest = strpbrk(*text, " []");
207 rest now points to a space or '[' or ']' after a term,
208 -or- it is NULL if the rest of the string is a single term
209 with no spaces nor brackets. If that's the case then we're
210 missing a closing bracket!
213 printf("Missing ']' bracket. C\n");
217 /* How many chars have we got? */
221 result = make_non_list_node(*text, diff);
223 } else if ('[' == rest[0]) {
225 result = make_list_node(parse_list(text));
226 } else if (']' == rest[0]) {
230 result->tail = parse_list(text);
235 Get the next node from the text, updating text
236 to point to the rest of the, uh, text.
239 parse_node(char **text)
245 /* NULL string input? */
246 if (NULL == *text) return EMPTY_LIST;
248 *text = trim_leading_blanks(*text);
251 if (NULL == *text) return EMPTY_LIST;
253 /* Look for blanks or brackets. */
254 rest = strpbrk(*text, " []");
256 rest now points to a space or '[' or ']' after a term,
257 -or- it is NULL if the rest of the string is a single term
258 with no spaces nor brackets. If that's the case then we're
259 done, and we can just return a list with one symbol in it.
262 thing = make_non_list_node(*text, strlen(*text));
267 /* How many chars have we got? */
271 thing = make_non_list_node(*text, diff);
275 if ('[' == rest[0]) {
277 return make_list_node(parse_list(text));
279 if (']' == rest[0]) {
280 printf("Extra ']' bracket.\n");
283 printf("Should be unreachable.");
289 text_to_expression(char *text)
291 JoyList result, head, tail;
293 result = parse_node(&text);
295 tail = parse_node(&text);
296 while (NULL != tail) {
299 tail = parse_node(&text);
305 void add(JoyList *stack, JoyList *expression) {stack = expression;}
306 void branch(JoyList *stack, JoyList *expression) {stack = expression;}
307 void clear(JoyList *stack, JoyList *expression) {stack = expression;}
308 void div_joyfunc(JoyList *stack, JoyList *expression) {stack = expression;}
309 void eq(JoyList *stack, JoyList *expression) {
310 printf("Hey there from eq!\n");
313 void ge(JoyList *stack, JoyList *expression) {stack = expression;}
314 void gt(JoyList *stack, JoyList *expression) {stack = expression;}
315 void le(JoyList *stack, JoyList *expression) {stack = expression;}
316 void lt(JoyList *stack, JoyList *expression) {stack = expression;}
317 void mod(JoyList *stack, JoyList *expression) {stack = expression;}
318 void mul(JoyList *stack, JoyList *expression) {stack = expression;}
319 void neq(JoyList *stack, JoyList *expression) {stack = expression;}
320 void sub(JoyList *stack, JoyList *expression) {stack = expression;}
321 void truthy(JoyList *stack, JoyList *expression) {stack = expression;}
325 push_thing(JoyType *term, JoyList *stack) {
326 JoyList node = newJoyList;
327 node->head = *term; /* Copies data, right? */
334 joy(JoyList *stack, JoyList *expression)
338 const struct dict_entry *interned;
340 while (*expression) {
341 term = &((*expression)->head);
342 *expression = (*expression)->tail;
343 switch (term->kind) {
348 push_thing(term, stack);
352 sym = term->value.symbol;
353 interned = in_word_set(sym, strlen(sym));
355 printf("Unknown: %s\n", sym);
358 interned->func(stack, expression);
368 JoyList stack = EMPTY_LIST;
369 JoyList expression = EMPTY_LIST;
371 mp_set_memory_functions(
373 &reallocate_function,
377 line = (char *)GC_malloc(1025);
381 status = gets_s(line, 1025);
382 if (NULL == status) {
386 > Upon successful completion, fgets(), gets_s(), and gets() return a
387 pointer to the string. If end-of-file occurs before any characters are
388 read, they return NULL and the buffer contents remain unchanged. If an
389 error occurs, they return NULL and the buffer contents are indeterminate.
390 The fgets(), gets_s(), and gets() functions do not distinguish between
391 end-of-file and error, and callers must use feof(3) and ferror(3) to
392 determine which occurred.
394 TODO: "use feof(3) and ferror(3)"...
400 expression = text_to_expression(line);
401 joy(&stack, &expression);