aboutsummaryrefslogtreecommitdiff
path: root/js/reader.js
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-03-24 16:32:24 -0500
committerJoel Martin <github@martintribe.org>2014-03-24 16:32:24 -0500
commit3169070063b2cb877200117ebb384269d73bcb93 (patch)
tree23de3db1ea5c37afd21a45b6ed7771f56a08c0c4 /js/reader.js
downloadmal-3169070063b2cb877200117ebb384269d73bcb93.tar.gz
mal-3169070063b2cb877200117ebb384269d73bcb93.zip
Current state of mal for Clojure West lighting talk.
Diffstat (limited to 'js/reader.js')
-rw-r--r--js/reader.js127
1 files changed, 127 insertions, 0 deletions
diff --git a/js/reader.js b/js/reader.js
new file mode 100644
index 0000000..da51088
--- /dev/null
+++ b/js/reader.js
@@ -0,0 +1,127 @@
+// 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, '"'); // 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(types.vector, lst);
+}
+
+// read hash-map key/value pairs
+function read_hash_map(reader) {
+ var lst = read_list(reader, '{', '}');
+ return types.hash_map.apply(types.hash_map, 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;