#include "val.h" #include "util.h" #include typedef struct _reader { char *c; State *S; } Reader; static void next(Reader *R) { CHECK(*R->c != '\0',"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 '\'': 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); #define STR(S, s) (VAL_OBJ(objstring_copy_cstr(S, s))) 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); ObjArr *a = AS_ARR(list(R, ']')); objarr_insert(R->S, a, 0, STR(R->S, "arr")); return VAL_OBJ(a); 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); } if (num) { // c moment char *tmp = malloc(len+1); memcpy(tmp, start, len); tmp[len] = 0; int x = atoi(tmp); free(tmp); return VAL_NUM((double)x); } else { ObjString *o = objstring_copy(R->S, start, len); return VAL_OBJ(o); } } static Val string(Reader *R) { char *start = R->c; int len = 0; // todo, escape sequences while (*R->c != '"') { len += 1; next(R); } next(R); ObjString *s = objstring_copy(R->S, start, len); ObjArr *a = objarr_new(R->S); objarr_append(R->S, a, STR(R->S, "quote")); objarr_append(R->S, a, VAL_OBJ(s)); return VAL_OBJ(a); } static Val list(Reader *R, char closer) { ObjArr *a = objarr_new(R->S); while (true) { skipws(R); if (*R->c == closer) { next(R); return VAL_OBJ(a); } objarr_append(R->S, a, expr(R)); } } Val read_expr(State *S, char *str) { Reader r = (Reader){.S=S, .c=str}; return expr(&r); }