1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
#include "val.h"
#include "util.h"
#include <string.h>
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) {
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);
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'));
}
|