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
120
121
122
123
124
125
126
127
128
129
|
// Node vs browser behavior
var reader = {};
if (typeof module !== 'undefined') {
var types = require('./types');
} else {
var exports = reader;
}
function Reader(tokens) {
// copy
this.tokens = tokens.map(function (a) { return a; });
this.position = 0;
}
Reader.prototype.next = function() { return this.tokens[this.position++]; }
Reader.prototype.peek = function() { return this.tokens[this.position]; }
function tokenize(str) {
var re = /[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)/g;
var results = [];
while ((match = re.exec(str)[1]) != '') {
if (match[0] === ';') { continue; }
results.push(match);
}
return results;
}
function read_atom (reader) {
var token = reader.next();
//console.log("read_atom:", token);
if (token.match(/^-?[0-9]+$/)) {
return parseInt(token,10) // integer
} else if (token.match(/^-?[0-9][0-9.]*$/)) {
return parseFloat(token,10); // float
} else if (token[0] === "\"") {
return token.slice(1,token.length-1)
.replace(/\\"/g, '"')
.replace(/\\n/g, "\n"); // string
} else if (token === "nil") {
return null;
} else if (token === "true") {
return true;
} else if (token === "false") {
return false;
} else {
return types._symbol(token); // symbol
}
}
// read list of tokens
function read_list(reader, start, end) {
start = start || '(';
end = end || ')';
var ast = [];
var token = reader.next();
if (token !== start) {
throw new Error("expected '" + start + "'");
}
while ((token = reader.peek()) !== end) {
if (!token) {
throw new Error("expected '" + end + "', got EOF");
}
ast.push(read_form(reader));
}
reader.next();
return ast;
}
// read vector of tokens
function read_vector(reader) {
var lst = read_list(reader, '[', ']');
return types._vector.apply(null, lst);
}
// read hash-map key/value pairs
function read_hash_map(reader) {
var lst = read_list(reader, '{', '}');
return types._hash_map.apply(null, lst);
}
function read_form(reader) {
var token = reader.peek();
switch (token) {
// reader macros/transforms
case ';': return null; // Ignore comments
case '\'': reader.next();
return [types._symbol('quote'), read_form(reader)];
case '`': reader.next();
return [types._symbol('quasiquote'), read_form(reader)];
case '~': reader.next();
return [types._symbol('unquote'), read_form(reader)];
case '~@': reader.next();
return [types._symbol('splice-unquote'), read_form(reader)];
case '^': reader.next();
var meta = read_form(reader);
return [types._symbol('with-meta'), read_form(reader), meta];
case '@': reader.next();
return [types._symbol('deref'), read_form(reader)];
// list
case ')': throw new Error("unexpected ')'");
case '(': return read_list(reader);
// vector
case ']': throw new Error("unexpected ']'");
case '[': return read_vector(reader);
// hash-map
case '}': throw new Error("unexpected '}'");
case '{': return read_hash_map(reader);
// atom
default: return read_atom(reader);
}
}
function BlankException(msg) {
}
function read_str(str) {
var tokens = tokenize(str);
if (tokens.length === 0) { throw new BlankException(); }
return read_form(new Reader(tokens))
}
exports.Reader = reader.Reader = Reader;
exports.BlankException = reader.BlankException = BlankException;
exports.tokenize = reader.tokenize = tokenize;
exports.read_form = reader.read_form = read_form;
exports.read_str = reader.read_str = read_str;
|