1 // Node vs browser behavior
3 if (typeof module
!== 'undefined') {
4 var types
= require('./types');
9 function Reader(tokens
) {
11 this.tokens
= tokens
.map(function (a
) { return a
; });
14 Reader
.prototype.next = function() { return this.tokens
[this.position
++]; }
15 Reader
.prototype.peek = function() { return this.tokens
[this.position
]; }
17 function tokenize(str
) {
18 var re
= /[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)/g;
20 while ((match
= re
.exec(str
)[1]) != '') {
21 if (match
[0] === ';') { continue; }
27 function read_atom (reader
) {
28 var token
= reader
.next();
29 //console.log("read_atom:", token);
30 if (token
.match(/^-?[0-9]+$/)) {
31 return parseInt(token
,10) // integer
32 } else if (token
.match(/^-?[0-9][0-9.]*$/)) {
33 return parseFloat(token
,10); // float
34 } else if (token
[0] === "\"") {
35 return token
.slice(1,token
.length
-1)
37 .replace(/\\n/g, "\n"); // string
38 } else if (token
=== "nil") {
40 } else if (token
=== "true") {
42 } else if (token
=== "false") {
45 return types
._symbol(token
); // symbol
49 // read list of tokens
50 function read_list(reader
, start
, end
) {
54 var token
= reader
.next();
55 if (token
!== start
) {
56 throw new Error("expected '" + start
+ "'");
58 while ((token
= reader
.peek()) !== end
) {
60 throw new Error("expected '" + end
+ "', got EOF");
62 ast
.push(read_form(reader
));
68 // read vector of tokens
69 function read_vector(reader
) {
70 var lst
= read_list(reader
, '[', ']');
71 return types
._vector
.apply(null, lst
);
74 // read hash-map key/value pairs
75 function read_hash_map(reader
) {
76 var lst
= read_list(reader
, '{', '}');
77 return types
._hash_map
.apply(null, lst
);
80 function read_form(reader
) {
81 var token
= reader
.peek();
83 // reader macros/transforms
84 case ';': return null; // Ignore comments
85 case '\'': reader
.next();
86 return [types
._symbol('quote'), read_form(reader
)];
87 case '`': reader
.next();
88 return [types
._symbol('quasiquote'), read_form(reader
)];
89 case '~': reader
.next();
90 return [types
._symbol('unquote'), read_form(reader
)];
91 case '~@': reader
.next();
92 return [types
._symbol('splice-unquote'), read_form(reader
)];
93 case '^': reader
.next();
94 var meta
= read_form(reader
);
95 return [types
._symbol('with-meta'), read_form(reader
), meta
];
96 case '@': reader
.next();
97 return [types
._symbol('deref'), read_form(reader
)];
100 case ')': throw new Error("unexpected ')'");
101 case '(': return read_list(reader
);
104 case ']': throw new Error("unexpected ']'");
105 case '[': return read_vector(reader
);
108 case '}': throw new Error("unexpected '}'");
109 case '{': return read_hash_map(reader
);
112 default: return read_atom(reader
);
116 function BlankException(msg
) {
119 function read_str(str
) {
120 var tokens
= tokenize(str
);
121 if (tokens
.length
=== 0) { throw new BlankException(); }
122 return read_form(new Reader(tokens
))
125 exports
.Reader
= reader
.Reader
= Reader
;
126 exports
.BlankException
= reader
.BlankException
= BlankException
;
127 exports
.tokenize
= reader
.tokenize
= tokenize
;
128 exports
.read_form
= reader
.read_form
= read_form
;
129 exports
.read_str
= reader
.read_str
= read_str
;