#include "IPUlisp.h" #include #include "format.h" #include #include #ifdef __IPU__ #include "../libIPUpy/ipusetjmp.h" #else #include #endif /* Fixed semispaces replace mmap. Each tile has its own copy of these globals. */ static uint64_t heap_a[65536 / 8], heap_b[65536 / 8]; static const unsigned char *input; static size_t input_len, input_pos, output_pos, output_cap; static char *output_buf; static int overflow; static jmp_buf recovery; static int input_get(void) { return input_pos == input_len ? EOF : input[input_pos++]; } static int input_unget(int c, FILE *unused) { (void)unused; if (c != EOF && input_pos) --input_pos; return c; } static int output_vprintf(const char *fmt, va_list ap) { size_t left = output_cap - output_pos; int n = vsnprintf(output_buf + output_pos, left, fmt, ap); if (n < 0) { overflow = 1; return n; } if ((size_t)n >= left) { output_pos = output_cap - 1; overflow = 1; } else output_pos += n; return n; } static int output_printf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); int n = output_vprintf(fmt, ap); va_end(ap); return n; } static int output_fprintf(FILE *unused, const char *fmt, ...) { (void)unused; va_list ap; va_start(ap, fmt); int n = output_vprintf(fmt, ap); va_end(ap); return n; } static __attribute__((noreturn)) void error(char *fmt, ...) { output_printf("Error: "); va_list ap; va_start(ap, fmt); output_vprintf(fmt, ap); va_end(ap); output_printf("\n"); longjmp(recovery, 1); } #define IPULISP_EMBEDDED #define getchar input_get #define ungetc input_unget #define printf output_printf #define fprintf output_fprintf #include "vendor/minilisp.c" #undef getchar #undef ungetc #undef printf #undef fprintf /* A persistent explicit GC root survives both vertex calls and error unwinding. */ static void *roots[4]; static int initialized; int IPUlisp_eval(const char *source, size_t length, char *output, size_t capacity, unsigned tile, int reset, int stress_gc) { if (!capacity) return 2; input = (const unsigned char *)source; input_len = length; input_pos = output_pos = 0; output_buf = output; output_cap = capacity; output[0] = 0; overflow = 0; always_gc = stress_gc != 0; if (setjmp(recovery)) { gc_running = false; roots[2] = NULL; return 1; } void *root = roots; Obj **env = (Obj **)&roots[1]; Obj **expr = (Obj **)&roots[2]; if (reset || !initialized) { initialized = 0; memory = heap_a; from_space = NULL; mem_nused = collection_count = 0; gc_running = false; Symbols = Nil; roots[0] = roots[1] = roots[2] = NULL; roots[3] = ROOT_END; *env = make_env(root, &Nil, &Nil); define_constants(root, env); define_primitives(root, env); add_primitive(root, env, "list", eval_list); { DEFINE2(sym, value); *sym = intern(root, "__tileid"); *value = make_int(root, (int)tile); add_variable(root, env, sym, value); } initialized = 1; } for (;;) { *expr = read_expr(root); if (!*expr) break; if (*expr == Cparen || *expr == Dot) error("Stray parenthesis or dot"); print(eval(root, env, expr)); output_printf("\n"); } return overflow ? 2 : 0; } unsigned IPUlisp_collections(void) { return collection_count; }