#include "val.h" #include "mem.h" #include "util.h" #include typedef struct _reader { State *S; int len; char *c; } Reader; static void next(Reader *R) { if(*R->c == '\0') ERROR("end of string reached"); R->c++; } static bool is_ws(char x) { return x == ' ' || x == '\t' || x == '\n';} static bool is_num(char x) { return '0' <= x && x <= '9'; } static bool is_special(char x) { switch(x) { case '(': case ')': case '[': case ']': case '"': return true; break; default: return false; break; } } static bool is_normal(char x) { return !(is_ws(x) || is_special(x)); } static void skipws(Reader *R) { while (is_ws(*R->c)) next(R); } static Val symbol(Reader *R); static Val string(Reader *R); static Val list(Reader *R, char closer); // en("quote", x) -> (quote x) etc // i guess in the good universe this is just cons or whatver static Val en(Reader *R, char *sym, Val v) { ObjArr *a = objarr_new(R->S); objarr_append(R->S, a, VAL_OBJ(objstring_copy_cstr(R->S, sym))); objarr_append(R->S, a, v); return VAL_OBJ(a); } static Val expr(Reader *R) { skipws(R); switch (*R->c) { case '"': next(R); return string(R); break; case '(': next(R); return list(R, ')'); break; case '[': next(R); return en(R, "arrlit", list(R, ']')); break; case '\'': next(R); return en(R, "quote", expr(R)); break; default: return symbol(R); break; } } static Val symbol(Reader *R) { char *start = R->c; int len = 0; bool num = true; while (is_normal(*R->c)) { num &= is_num(*R->c); len += 1; next(R); } // i LOVE 0-terminated strings char *tmp = malloc(len+1); memcpy(tmp, start, len); tmp[len] = 0; if (num) { int x = atoi(tmp); free(tmp); return VAL_NUM((double)x); } else { Val v; if (0 == strcmp(tmp, "nil")) v = VAL_NIL; else if (0 == strcmp(tmp, "true")) v = VAL_TRUE; else if (0 == strcmp(tmp, "false")) v = VAL_FALSE; else v = VAL_OBJ(objstring_copy(R->S, start, len)); free(tmp); return v; } } static Val string(Reader *R) { struct { size_t len; size_t cap; char *d; } str; str.len = 0; str.cap = 0; str.d = NULL; #define append(c) do { ENSURE_CAP(R->S, str, char, str.cap+1); str.d[str.len++] = c; } while (0) while (*R->c != '"') { if (*R->c == '\\') { next(R); switch (*R->c) { case '\\': append('\\'); break; case 't': append('\t'); break; case 'n': append('\n'); break; case '"': append('"'); break; } next(R); } else { append(*R->c); next(R); } } append('\0'); #undef append next(R); ObjString *s = objstring_take(R->S, str.d, str.len-1); return en(R, "quote", VAL_OBJ(s)); } static Val list(Reader *R, char closer) { ObjArr *a = objarr_new(R->S); while (true) { skipws(R); if (*R->c == closer) { if (closer != '\0') next(R); return VAL_OBJ(a); } objarr_append(R->S, a, expr(R)); } } // both need null terminated strings Val read_expr(State *S, char *str) { Reader r = (Reader){.S=S, .c=str}; return expr(&r); } ObjArr *read_exprs(State *S, char *str) { Reader r = (Reader){.S=S, .c=str}; return AS_ARR(list(&r, '\0')); }