summaryrefslogtreecommitdiff
path: root/read.c
blob: b3fc5a3cdfa76fd2b2ba6e557e6beb1813dcc84f (plain)
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 '\'': 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'));
}