UNPKG

soy

Version:

experimental lisp which supports both s-expressions and smalltalk esque syntax

1,268 lines (1,167 loc) 38.9 kB
(function() { var CompileEnv, Env, InPort, None, Procedure, StringIO, Symbol, SyntaxError, add_globals, all, arity, atom, compile, cons, current_dir, demand, desugar, dict_keys, dict_to_string, dict_values, eof_object, expand, expand_quasiquote, fs, gensymid, getVar, global_env, isQuote, is_key_value_pair, is_pair, isa, k, load, macro_table, parse, quotes, read, specialForms, string_encode, string_escape, sym, symbol_table, to_string, type, unbox, unzip, v, zip, _and, _append, _begin, _colon, _comma, _commaat, _compile, _cons, _define, _defmacro, _dict, _enum_at, _eval, _hash, _hat, _if, _key, _key_value_pair, _lambda, _list, _load, _percent, _period, _pipe, _quasiquote, _quote, _ref, _ref2, _semicolon, _set, _tilda, _unquote, _unquotesplicing, __indexOf = Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, __slice = Array.prototype.slice; fs = require('fs'); None = void 0; current_dir = './'; Symbol = (function() { function Symbol(str) { this.str = str; } return Symbol; })(); symbol_table = {}; sym = function(s) { if (s instanceof Symbol) return s; if (!symbol_table[s]) symbol_table[s] = new Symbol(s); return symbol_table[s]; }; specialForms = "load enum-at compile key dict cons append list quote if set! define lambda key-value-pair begin defmacro | ; : . , ~ & % ^ # ,@".split(' '); _ref = specialForms.map(sym), _load = _ref[0], _enum_at = _ref[1], _compile = _ref[2], _key = _ref[3], _dict = _ref[4], _cons = _ref[5], _append = _ref[6], _list = _ref[7], _quote = _ref[8], _if = _ref[9], _set = _ref[10], _define = _ref[11], _lambda = _ref[12], _key_value_pair = _ref[13], _begin = _ref[14], _defmacro = _ref[15], _pipe = _ref[16], _semicolon = _ref[17], _colon = _ref[18], _period = _ref[19], _comma = _ref[20], _tilda = _ref[21], _and = _ref[22], _percent = _ref[23], _hat = _ref[24], _hash = _ref[25], _commaat = _ref[26]; _ref2 = "quasiquote unquote unquote-splicing".split(' ').map(sym), _quasiquote = _ref2[0], _unquote = _ref2[1], _unquotesplicing = _ref2[2]; quotes = { "'": _quote, "`": _quasiquote, ",": _unquote, ",@": _unquotesplicing }; isQuote = function(token) {}; eof_object = new Symbol('#<eof-object>'); InPort = (function() { InPort.prototype.tokenizer = /\s*(,@|[('`,)]|"(?:[\\].|[^\\"])*"|;|[^\s('"`,;)]*)(.*)/; function InPort(file) { this.file = file; this.line = ''; } InPort.prototype.next_token = function() { var oldLine, parts, specialChar, token, _, _i, _len, _ref3, _ref4; while (true) { if (this.line === '') this.line = this.file.readline(); if (this.line === '' || this.line === void 0) return eof_object; oldLine = this.line; _ref3 = this.line.match(this.tokenizer), _ = _ref3[0], token = _ref3[1], this.line = _ref3[2]; if (oldLine === this.line) return eof_object; if (token[0] === '"') return token; if (("" + (parseFloat(token))) === token) return token; if (__indexOf.call(token, "{") >= 0 && token !== "{") { if (token[0] === "{") { this.line = token.slice(1) + this.line; token = "{"; } else { parts = token.split("{"); token = parts.shift(); this.line = "{" + parts.join(" { ") + " " + this.line; } } if (__indexOf.call(token, "}") >= 0 && token !== "}") { if (token[-1] === "}") { token = token.slice(0, -1); this.line += " } "; } else { parts = token.split("}"); token = parts.shift(); this.line = " } " + parts.join(" } ") + " " + this.line; } } if (__indexOf.call(token, "[") >= 0 && token !== "[") { if (token[0] === "[") { this.line = token.slice(1) + this.line; token = "["; } else { parts = token.split("["); token = parts.shift(); this.line = "[" + parts.join(" [ ") + " " + this.line; } } if (__indexOf.call(token, "]") >= 0 && token !== "]") { if (token[-1] === "]") { token = token.slice(0, -1); this.line += " ] "; } else { parts = token.split("]"); token = parts.shift(); this.line = " ] " + parts.join(" ] ") + " " + this.line; } } if (token === "[") { token = "("; this.line = "squarelambda " + this.line; } if (token === "]") token = ")"; if (token === "{") { token = "("; this.line = "dict " + this.line; } if (token === "}") token = ")"; _ref4 = ['|', ';', ':', '.', ',@', ',', '~', '&', '%', '^']; for (_i = 0, _len = _ref4.length; _i < _len; _i++) { specialChar = _ref4[_i]; if (String(Number(token)) === token) break; if (token === specialChar) break; if (__indexOf.call(token, specialChar) >= 0 && token !== specialChar) { parts = token.split(specialChar); token = parts.shift(); this.line = specialChar + " " + parts.join(" " + specialChar + " ") + " " + this.line; break; } } if (token !== '') return token; } }; return InPort; })(); StringIO = (function() { function StringIO(string) { this.index = 0; this.lines = string.trim().split("\n"); } StringIO.prototype.readline = function() { var line; line = this.lines[this.index++]; if (line.trim().length === 0 && this.index < this.lines.length) { return this.readline(); } else { return line; } }; return StringIO; })(); Env = (function() { function Env(parms, args, outer) { if (parms == null) parms = []; if (args == null) args = []; if (outer == null) outer = false; this.values = {}; this.outer = outer; if (isa(parms, "Symbol")) { this.values[to_string(parms)] = args; } else { if (args.length !== parms.length) { throw "Expected " + (to_string(parms)) + ", given " + (to_string(args)); } if (parms.length > 0) this.values = zip(parms, args); } } Env.prototype.toString = function() { var key, val; return to_string((function() { var _ref3, _results; _ref3 = this.values; _results = []; for (key in _ref3) { val = _ref3[key]; _results.push(push([key, "" + (to_string(val))])); } return _results; }).call(this)); }; Env.prototype.update = function(values) { this.values = values; return this; }; Env.prototype.find = function(key, couldBeNew) { if (couldBeNew == null) couldBeNew = false; if (isa(key, "Symbol")) key = to_string(key); if (this.values[key] != null) return this; if (!this.outer && !couldBeNew) throw "Could not find " + key; if (this.outer) { try { return this.outer.find(key); } catch (e) { if (couldBeNew) { return this; } else { throw e; } } } return this; }; Env.prototype.at = function(key) { if (isa(key, "Symbol")) key = to_string(key); if (this.values[key] != null) return this.values[key]; throw "Could not find " + key + " in " + (to_string(dict_keys(this.values))); }; Env.prototype.setAt = function(key, val, couldBeNew) { if (couldBeNew == null) couldBeNew = false; if (isa(key, "Symbol")) key = to_string(key); return this.find(key, couldBeNew).values[key] = val; }; return Env; })(); Procedure = (function() { function Procedure(parms, exp, env) { this.parms = parms; this.exp = exp; this.env = env; } Procedure.prototype.toString = function() { return to_string([_lambda, this.parms, this.exp]); }; Procedure.prototype.applyProc = function(args) { return _eval(this.exp, new Env(this.parms, args, this.env)); }; Procedure.prototype.apply = function(ctx, args) { return this.applyProc(args); }; Procedure.prototype.arity = function() { return this.parms.length; }; return Procedure; })(); SyntaxError = function(msg) { return msg; }; parse = function(inport) { if (type(inport) === "string") inport = new InPort(new StringIO(inport)); return read(inport); }; read = function(inport) { var read_ahead, token1; read_ahead = function(token) { var L; if (token === '(') { L = []; while (true) { token = inport.next_token(); if (token === ')') { return L; } else { L.push(read_ahead(token)); } } } else if (token === ')') { throw SyntaxError('unexpected )'); } else if (quotes[token]) { return [quotes[token], read(inport)]; } else if (token === eof_object) { throw SyntaxError('unexpected EOF in list'); } else { return atom(token); } }; token1 = inport.next_token(); if (token1 === eof_object) { return eof_object; } else { return read_ahead(token1); } }; string_escape = function(string) { return string; }; string_encode = function(string) { return "\"" + string + "\""; }; type = (function() { var classToType, name, _i, _len, _ref3; classToType = {}; _ref3 = "Boolean Number String Function Array Date RegExp Undefined Null".split(" "); for (_i = 0, _len = _ref3.length; _i < _len; _i++) { name = _ref3[_i]; classToType["[object " + name + "]"] = name.toLowerCase(); } return function(obj) { var strType; strType = Object.prototype.toString.call(obj); return classToType[strType] || "object"; }; })(); isa = function(x, testType) { return testType === "Symbol" && x instanceof Symbol || testType === "Func" && (x instanceof Procedure || type(x) === "function") || testType === "Procedure" && x instanceof Procedure || testType === "Boolean" && type(x) === "boolean" || testType === "String" && type(x) === "string" || testType === "Number" && type(x) === "number" || testType === "List" && type(x) === "array" || testType === "Object" && type(x) === "object"; }; atom = function(token) { if (token === '#t') return true; if (token === '#f') return false; if (token[0] === '"') return string_escape(token.slice(1, -1)); if (String(Number(token)) === token) return Number(token); return sym(token); }; dict_keys = function(x) { var k, keys, v; keys = []; for (k in x) { v = x[k]; keys.push(k); } return keys; }; dict_values = function(x) { var k, v, vals; vals = []; for (k in x) { v = x[k]; vals.push(v); } return vals; }; dict_to_string = function(x, haveSeen) { var k, v; if (haveSeen == null) haveSeen = []; return "{" + (((function() { var _results; _results = []; for (k in x) { v = x[k]; _results.push("" + (to_string(k)) + ": " + (isa(v, "Object") ? (__indexOf.call(haveSeen, v) >= 0 ? "<CIRCULAR>" : dict_to_string(v, haveSeen.concat([v]))) : to_string(v))); } return _results; })()).join(" ")) + "}"; }; to_string = function(x) { if (x === true) return "#t"; if (x === false) return "#f"; if (isa(x, "Symbol")) return x.str; if (isa(x, "String")) return string_encode(x); if (isa(x, "List")) return "(" + (x.map(to_string).join(' ')) + ")"; if (isa(x, "Number")) return Number(x); if (isa(x, "Procedure")) return x.toString(); if (isa(x, "Object")) return dict_to_string(x); return String(x); }; unbox = function(item) { if (item.length === 1 && isa(item[0], 'List')) item = item[0]; return item; }; demand = function(x, predicate, msg) { if (msg == null) msg = 'wrong length'; if (!predicate) throw "" + (to_string(x)) + ": " + msg; }; all = function(pred, items) { var item, _i, _len; for (_i = 0, _len = items.length; _i < _len; _i++) { item = items[_i]; if (!pred(item)) return false; } return true; }; is_pair = function(x) { return isa(x, "List") && x.length > 0; }; is_key_value_pair = function(x) { if (isa(x, "Object") && x.key && x.value) { return true; } else { return false; } }; cons = function(x, y) { return [x].concat(y); }; macro_table = {}; macro_table['let'] = { applyProc: function(args) { var atom, body, pos, vals, vars, _len; vars = []; vals = []; for (pos = 0, _len = args.length; pos < _len; pos++) { atom = args[pos]; if (!(is_pair(atom)) || !(atom[0] === _key_value_pair)) break; vars.push(atom[1]); vals.push(atom[2]); } body = args.slice(pos); if (!(is_pair(body[0])) && body.length === 1) { body = body[0]; } else { body = unbox(body); } return [[_lambda, vars, body]].concat(vals); } }; macro_table['let*'] = { applyProc: function(args) { if (is_pair(args[0]) && args[0][0] === _key_value_pair) { return [[_lambda, [args[0][1]], macro_table['let*'].applyProc(args.slice(1))], args[0][2]]; } else { return args; } } }; gensymid = 0; add_globals = function(env) { return env.update({ 'gensym': function() { return sym("__SGENSYM__" + (gensymid++)); }, 'enum-at': function(d, dkey) { dkey = to_string(dkey); if (isa(dkey, "Number")) dkey = parseInt(dkey); if (isa(dkey, "Number") && dkey < 0) dkey = d.length + dkey; return d[dkey]; }, '+': function(x, y) { return Number(x) + Number(y); }, '-': function(x, y) { return x - y; }, '*': function(x, y) { return x * y; }, '/': function(x, y) { return x / y; }, 'and': function() { var arg, args, result, _i, _len; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; result = true; for (_i = 0, _len = args.length; _i < _len; _i++) { arg = args[_i]; if (!arg) result = false; } return result; }, 'or': function() { var arg, args, result, _i, _len; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; result = false; for (_i = 0, _len = args.length; _i < _len; _i++) { arg = args[_i]; if (arg) result = true; } return result; }, 'set-dict-prop': function(o, k, v) { o[k] = v; return o; }, 'string->symbol': function(x) { return sym(x); }, 'string-encode': function(x) { if (isa(x, "Symbol")) { return x.str; } else { return JSON.stringify(x); } }, 'key': function(x) { return x; }, 'not': function(x) { return !x; }, '>': function(x, y) { return x > y; }, '<': function(x, y) { return x < y; }, '>=': function(x, y) { return x >= y; }, '<=': function(x, y) { return x <= y; }, '=': function(x, y) { return x === y; }, 'sqrt': function(x) { return Math.sqrt(x); }, 'abs': function(x) { return Math.abs(x); }, 'equal?': function(x, y) { return x === y; }, 'eq?': function(x, y) { return x === y; }, 'length': function(x) { return x.length; }, 'cons': function(x, y) { return cons(x, y); }, 'car': function(x) { return x[0]; }, 'cdr': function(x) { if ((x.slice != null) && x.length) { return x.slice(1); } else { } }, 'append': function(x, y) { return x.concat(y); }, 'list': function() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return args; }, 'list?': function(x) { return isa(x, "List"); }, 'key-value-pair': function(k, v) { return { key: k, value: v }; }, 'key-value-pair?': function(x) { return is_key_value_pair(x); }, 'dict': function() { var args, d, kv, _i, _len; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; d = {}; for (_i = 0, _len = args.length; _i < _len; _i++) { kv = args[_i]; d[kv.key] = kv.value; } return d; }, 'atom?': function(x) { return !(is_pair(x)) && (!(x.length === 0)); }, 'null?': function(x) { return x.length === 0; }, 'symbol?': function(x) { return isa(x, "Symbol"); }, 'boolean?': function(x) { return isa(x, "Boolean"); }, 'pair?': function(x) { return is_pair(x); }, 'port?': function(x) { return isa(x, "File"); }, 'map': function(fn, arr) { var item, _i, _len, _results; _results = []; for (_i = 0, _len = arr.length; _i < _len; _i++) { item = arr[_i]; _results.push(fn.apply({}, [item])); } return _results; }, 'filter': function(fn, arr) { var item, _i, _len, _results; _results = []; for (_i = 0, _len = arr.length; _i < _len; _i++) { item = arr[_i]; if (fn.apply({}, [item])) _results.push(item); } return _results; }, 'join': function(tok, arr) { return arr.join(tok); }, 'map-dict': function(fn, dict) { var key, result, val; result = []; for (key in dict) { val = dict[key]; result.push(fn.apply({}, [key, val])); } return result; }, 'str': function() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; return args.join(""); }, 'apply': function(func, args) { return func.apply({}, args); }, 'eval': function(x) { return _eval(expand(x)); }, 'load': function(x) { return load(x); }, 'compile': function(lang, x) { return compile(lang, expand(x)); }, 'compile-file': function(file) { return compile(parse(new InPort(new FileIn(file)))); }, 'call/cc': function(x) { return callcc(x); }, 'open-input-file': function(f) { return new FileIn(f); }, 'close-input-port': function(p) { return p.close(); }, 'open-output-file': function(f) { return new FileOut(f); }, 'close-output-port': function(p) { return p.close(); }, 'eof-object?': function(x) { return x === _eof_object; }, 'read-char': function() { return readchar(); }, 'read': function(x) { return parse(x); }, 'value': function(x) { return x; }, 'print': function(x) { return console.log(to_string(x)); }, 'file-write': function(name, content) { return require("fs").writeFileSync(name, content, "UTF-8"); }, 'display': function(x, port) { return port.pr(isa(x, "String") ? x : to_string(x)); }, 'require': function(f) { return require(to_string(f)); }, 'file-contents': function(f) { return require("fs").readFileSync(f, "UTF-8"); } }); }; global_env = add_globals(new Env()); arity = function(x) { if (isa(x, "Procedure")) { return x.arity(); } else { return x.length; } }; _eval = function(x, env) { var alt, applyTerm, conseq, dkey, dkey1, dkey2, exp, exps, key, lst, obj, proc, result, str, term, test, val, vars, _, _i, _j, _k, _l, _len, _len2, _len3, _len4, _len5, _m, _ref3; if (env == null) env = false; env || (env = global_env); while (true) { if (isa(x, "Symbol")) { return env.find(x).at(x); } else if (!isa(x, "List")) { return x; } else if (x[0] === _quote) { _ = x[0], exp = x[1]; return exp; } else if (x[0] === _if) { _ = x[0], test = x[1], conseq = x[2], alt = x[3]; return _eval((_eval(test, env) ? conseq : alt), env); } else if (x[0] === _set) { _ = x[0], key = x[1], exp = x[2]; env.find(key, true).setAt(key, _eval(exp, env)); return None; } else if (x[0] === _define) { _ = x[0], key = x[1], exp = x[2]; env.setAt(key, _eval(exp, env), true); return None; } else if (x[0] === _lambda) { _ = x[0], vars = x[1], exp = x[2]; return new Procedure(vars, exp, env); } else if (x[0] === _begin) { val = false; _ref3 = x.slice(1); for (_i = 0, _len = _ref3.length; _i < _len; _i++) { exp = _ref3[_i]; val = _eval(exp, env); } return val; } else { exps = (function() { var _j, _len2, _results; _results = []; for (_j = 0, _len2 = x.length; _j < _len2; _j++) { exp = x[_j]; _results.push(_eval(exp, env)); } return _results; })(); proc = exps.shift(); if (isa(proc, "Procedure")) { x = proc.exp; env = new Env(proc.parms, exps, proc.env); } else if (proc.apply) { return proc.apply({}, exps); } else { if (isa(proc, "Boolean")) { if (proc) { return exps[0]; } else { if (exps[1] != null) { return exps[1]; } else { return false; } } } if (isa(proc, "Number")) { result = proc; for (_j = 0, _len2 = exps.length; _j < _len2; _j++) { term = exps[_j]; if (applyTerm) { result = applyTerm.apply({}, [result, term]); applyTerm = false; } else if (isa(term, "Number")) { result *= term; } else { if (isa(term, "Func")) { if (arity(term) === 1) { result = term.apply({}, [result]); } else { applyTerm = term; } } else { throw new Error("encountered " + term + " when evaluating application of Number expected Number of Func"); } } } if (applyTerm) { result = (function(r, t) { return function(y) { return t.apply({}, [r, y]); }; })(result, applyTerm); applyTerm = false; } return result; } if (exps.length && isa(exps[0], "Func")) { return exps[0].apply({}, [proc].concat(exps.slice(1))); } if (isa(proc, "Object") && isa(exps[0], "Object")) { result = proc; for (_k = 0, _len3 = exps.length; _k < _len3; _k++) { obj = exps[_k]; if (isa(obj, "Object")) { result = _eval([sym("extends"), result, obj]); } else { throw "Only objects may be extended to each other"; } } return result; } if (isa(proc, "List") && isa(exps[0], "List")) { result = proc; for (_l = 0, _len4 = exps.length; _l < _len4; _l++) { lst = exps[_l]; if (isa(lst, "List")) { result = result.concat(lst); } else { throw "only lists may be appended to lists"; } } return result; } if (isa(proc, "String") && isa(exps[0], "String")) { result = proc; for (_m = 0, _len5 = exps.length; _m < _len5; _m++) { str = exps[_m]; if (isa(str, "String")) { result += str; } else { throw "only strings may be concat to strings"; } } return result; } if (exps.length === 1) { dkey = to_string(exps.shift()); if (isa(dkey, "Number")) dkey = parseInt(dkey); if (isa(dkey, "Number") && dkey < 0) dkey = proc.length + dkey; return proc[dkey]; } if (exps.length === 2) { dkey1 = to_string(exps.shift()); dkey2 = to_string(exps.shift()); if (isa(dkey1, "Number")) dkey1 = parseInt(dkey1); if (isa(dkey2, "Number")) dkey2 = parseInt(dkey2); return proc.slice(dkey1, dkey2 + 1 || 9e9); } throw (to_string(proc)) + " can not be used as function"; } } } }; desugar = function(x) { var body, pos, token, _len, _len2, _len3, _len4, _len5, _len6; for (pos = 0, _len = x.length; pos < _len; pos++) { token = x[pos]; if (isa(token, 'List')) x[pos] = desugar(token); } if (x[0] === sym("squarelambda")) { if (!(__indexOf.call(x, _pipe) >= 0)) { return desugar([_lambda, _pipe].concat(x.slice(1))); } else { return desugar([_lambda].concat(x.slice(1))); } } for (pos = 0, _len2 = x.length; pos < _len2; pos++) { token = x[pos]; if (token === _semicolon) { return desugar([x.slice(0, (pos - 1) + 1 || 9e9)].concat(x.slice(pos + 1))); } } for (pos = 0, _len3 = x.length; pos < _len3; pos++) { token = x[pos]; if (token === _period) { if (pos === 0) { if (!x[1]) throw "Missing param for dot expression "; return desugar([[_key, x[1]]].concat(x.slice(2))); } else { return desugar((pos > 1 ? x.slice(0, (pos - 2) + 1 || 9e9) : []).concat([[_enum_at, x[pos - 1], [_key, x[pos + 1]]]]).concat(x.slice(pos + 2))); } } } for (pos = 0, _len4 = x.length; pos < _len4; pos++) { token = x[pos]; if (token === _comma) { return desugar([x.slice(0, (pos - 1) + 1 || 9e9)].concat(x.slice(pos + 1))); } } for (pos = 0, _len5 = x.length; pos < _len5; pos++) { token = x[pos]; if (token === _pipe) { body = x.slice(pos + 1); if (!(is_pair(body[0])) && body.length === 1) { body = body[0]; } else { body = unbox(body); } return desugar([x[0], unbox(x.slice(1, (pos - 1) + 1 || 9e9)), body]); } } for (pos = 0, _len6 = x.length; pos < _len6; pos++) { token = x[pos]; if (token === _colon) { return (pos > 1 ? x.slice(0, (pos - 2) + 1 || 9e9) : []).concat([[_key_value_pair, x[pos - 1], x[pos + 1]]]).concat(desugar(x.slice(pos + 2))); } } return x; }; load = function(filename, wrap) { var fileContent, loadDir, oldDir, _ref3; if (wrap == null) wrap = true; if (typeof window !== "undefined" && window !== null) { fileContent = document.getElementById("soy-script-" + filename).textContent; } else { filename = ((_ref3 = filename[0]) === '.' || _ref3 === '/' ? '' : current_dir) + filename; if (filename.slice(-4) !== ".soy") filename += ".soy"; loadDir = filename.split('/').slice(0, -1).join('/') + '/'; oldDir = current_dir; current_dir = loadDir; fileContent = require("fs").readFileSync(filename, "UTF-8").trim(); current_dir = oldDir; } return parse(wrap ? "(begin " + fileContent + ")" : fileContent); }; expand = function(x, toplevel) { var arg, args, atom, body, bodyExp, def, exp, f, item, lam, leaf, macroed, newBody, pos, proc, result, v, vars, xi, _i, _len, _len2, _len3, _ref3, _ref4; if (toplevel == null) toplevel = false; if (isa(x, "List")) demand(x, x.length > 0); if (!isa(x, "List")) { return x; } else if (x[0] === _quote) { demand(x, x.length === 2); return x; } else if (x[0] === _load) { return expand(desugar(load(expand(x[1])))); } else if (x[0] === _key) { return [_quote, x[1]]; } else if (x[0] === _key_value_pair) { return [_key_value_pair, (isa(x[1], "Symbol") ? x[1].str : expand(x[1])), expand(x[2])]; } else if (x[0] === _dict) { _ref3 = x.slice(1); for (pos = 0, _len = _ref3.length; pos < _len; pos++) { atom = _ref3[pos]; if (!(isa(atom, "List")) || (isa(atom, "List") && atom[0] !== _key_value_pair)) { x[0] = _list; } x[pos + 1] = expand(atom); } return x; } else if (x[0] === _if) { if (x.length === 3) x.push(None); demand(x, x.length === 4); return (function() { var _i, _len2, _results; _results = []; for (_i = 0, _len2 = x.length; _i < _len2; _i++) { item = x[_i]; _results.push(expand(item)); } return _results; })(); } else if (x[0] === _set) { demand(x, x.length === 3); v = x[1]; demand(x, isa(v, "Symbol"), "Can set! only a symbol"); return [_set, v, expand(x[2])]; } else if (x[0] === _define || x[0] === _defmacro) { demand(x, x.length >= 3); def = x[0], v = x[1], body = 3 <= x.length ? __slice.call(x, 2) : []; if (isa(v, "List")) { _ref4 = v[0], f = _ref4[0], args = 2 <= _ref4.length ? __slice.call(_ref4, 1) : []; return expand([_define, f, [_lambda, args, body]]); } else { demand(x, x.length === 3); demand(x, isa(v, "Symbol"), "can define only a symbol"); exp = expand(x[2]); if (def === _defmacro) { proc = _eval(exp); demand(x, isa(proc, "Procedure"), "macro must be a procedure"); macro_table[to_string(v)] = proc; return None; } else { return [_define, v, exp]; } } } else if (x[0] === _begin) { if (x.length === 1) { return None; } else { result = []; for (_i = 0, _len2 = x.length; _i < _len2; _i++) { xi = x[_i]; result.push(expand(xi, toplevel)); } return result; } } else if (x[0] === _lambda) { demand(x, x.length >= 3); lam = x[0], vars = x[1], body = 3 <= x.length ? __slice.call(x, 2) : []; demand(x, (isa(vars, "List") && all((function(v) { return isa(v, "Symbol"); }), vars)) || isa(vars, "Symbol"), "illegal lambda argument list"); bodyExp = expand(body.length === 1 ? body[0] : [_begin].concat(body)); if (__indexOf.call(vars, _and) >= 0) { if (vars[vars.length - 2] !== _and) throw "& must be before last arg"; newBody = []; for (pos = 0, _len3 = vars.length; pos < _len3; pos++) { arg = vars[pos]; if (arg === _and) break; newBody.push([_key_value_pair, arg, [sym("_s_args"), pos]]); } newBody.push([_key_value_pair, vars[pos + 1], [sym("_s_args"), pos, -1]]); newBody.push(bodyExp); vars = sym("_s_args"); bodyExp = macro_table["let"].applyProc(newBody); } return [_lambda, vars, bodyExp]; } else if (x[0] === _quasiquote) { demand(x, x.length === 2); return expand(expand_quasiquote(x[1])); } else if (isa(x[0], "Symbol") && macro_table[to_string(x[0])]) { macroed = macro_table[to_string(x[0])].applyProc(x.slice(1)); return expand(macroed, toplevel); } else { return (function() { var _j, _len4, _results; _results = []; for (_j = 0, _len4 = x.length; _j < _len4; _j++) { leaf = x[_j]; _results.push(expand(leaf)); } return _results; })(); } }; expand_quasiquote = function(x) { if (!is_pair(x)) return [_quote, x]; demand(x, x[0] !== _unquotesplicing, "can't splice here"); if (x[0] === _unquote) { demand(x, x.length === 2); return x[1]; } else if (is_pair(x[0]) && x[0][0] === _unquotesplicing) { demand(x[0], x[0].length === 2); return [_append, x[0][1], expand_quasiquote(x.slice(1))]; } else { if (x[0] === _quasiquote) { return expand_quasiquote(expand_quasiquote(x.slice(1))[1]); } else { return [_cons, expand_quasiquote(x[0]), expand_quasiquote(x.slice(1))]; } } }; zip = function(a, b) { var i, result, x, _fn, _len; result = {}; _fn = function(x, i) { return result[to_string(x)] = b[i]; }; for (i = 0, _len = a.length; i < _len; i++) { x = a[i]; _fn(x, i); } return result; }; unzip = function(arr) { var a, b, x, _i, _len; a = []; b = []; for (_i = 0, _len = arr.length; _i < _len; _i++) { x = arr[_i]; a.push(x[0]); b.push(x[1]); } return [a, b]; }; getVar = function(sym) { var c, newVar, ord, _i, _len, _ref3; newVar = ''; _ref3 = (sym.str ? sym.str.split("") : sym.split("")); for (_i = 0, _len = _ref3.length; _i < _len; _i++) { c = _ref3[_i]; ord = (c + '').charCodeAt(0); if ((ord >= 65 && ord <= 90) || (ord >= 97 && ord <= 122)) { newVar += c; } else { newVar += "_" + ord + "_"; } } return newVar; }; CompileEnv = (function() { function CompileEnv(parent, defs) { if (parent == null) parent = None; if (defs == null) defs = []; this._defs = {}; this._uses = []; if (defs.length) this.defs(defs); if (parent === None) { this._sets = dict_keys(global_env.values); } else { parent.child = this; } } CompileEnv.prototype.defs = function(vname) { var v, _i, _len, _ref3; _ref3 = (type(vname) === "array" ? vname : [v]); for (_i = 0, _len = _ref3.length; _i < _len; _i++) { v = _ref3[_i]; this._defs[to_string(v)] = true; } return this; }; CompileEnv.prototype.uses = function(vname) { var v, _i, _len, _ref3; _ref3 = (type(vname) === "array" ? vname : [v]); for (_i = 0, _len = _ref3.length; _i < _len; _i++) { v = _ref3[_i]; if (!this._defs[to_string(v)]) this._uses[to_string(v)] = true; } return this; }; CompileEnv.prototype.removeUse = function(vname) { if (this._uses[vname]) delete this._uses[vname]; return this; }; CompileEnv.prototype.getLexicalUses = function() { if (this.child) this.uses(this.child.getLexicalUses()); return dict_keys(this._uses); }; return CompileEnv; })(); compile = function(targetLang, x, env) { var alt, cexp, conseq, exp, exps, last, test, v, val, vars, _, _i, _len, _ref3; if (env == null) env = false; env || (env = new CompileEnv); if (isa(x, "Symbol")) { env.uses(x); return getVar(x); } else if (!(isa(x, "List"))) { return to_string(x); } else if (x[0] === _quote) { _ = x[0], exp = x[1]; if (exp instanceof Symbol) { return exp.str; } else { return to_string(x); } } else if (x[0] === _if) { _ = x[0], test = x[1], conseq = x[2], alt = x[3]; return "(" + (compile(targetLang, test, env)) + ") ? (" + (compile(targetLang, conseq, env)) + ") : (" + (compile(targetLang, alt, env)) + ")"; } else if (x[0] === _set) { _ = x[0], v = x[1], exp = x[2]; env.uses(v); return "" + (getVar(v)) + " = " + (compile(targetLang, exp, env)) + ";"; } else if (x[0] === _define) { _ = x[0], v = x[1], exp = x[2]; env.defs(v); return "var " + (getVar(v)) + " = " + (compile(targetLang, exp, env)) + ";"; } else if (x[0] === _lambda) { _ = x[0], vars = x[1], exp = x[2]; cexp = compile(targetLang, [_begin, exp], new CompileEnv(env, vars)); console.log("VARS", vars); return "function(" + (((function() { var _i, _len, _results; _results = []; for (_i = 0, _len = vars.length; _i < _len; _i++) { v = vars[_i]; _results.push(getVar(v)); } return _results; })()).join(",")) + "){" + cexp + "}"; } else if (x[0] === _enum_at) { return "" + (compile(targetLang, x[1], env)) + "." + (compile(targetLang, x[2], env)); } else if (x[0] === _begin) { val = []; last = x.pop(); _ref3 = x.slice(1); for (_i = 0, _len = _ref3.length; _i < _len; _i++) { exp = _ref3[_i]; val.push(compile(targetLang, exp, env)); } if (isa(last, "List")) { cexp = compile(targetLang, last, new CompileEnv(env)); last = "new Soy.Bounce(function() {return " + cexp + "})"; } else { last = compile(targetLang, last, env); } return "" + (val.join("" + '\n')) + "; return " + last + ";"; } else { exps = (function() { var _j, _len2, _results; _results = []; for (_j = 0, _len2 = x.length; _j < _len2; _j++) { exp = x[_j]; _results.push(compile(targetLang, exp, env)); } return _results; })(); if (exps[0] === 'apply') { env.removeUse('apply'); exps.shift(); } if (exps[0].indexOf(".") !== -1) { return "" + exps[0] + "(" + (exps.slice(1).join(',')) + ")"; } else { return "Soy.apply(" + exps[0] + ", [" + (exps.slice(1).join(',')) + "])"; } } }; _eval(expand(desugar(load(typeof window !== "undefined" && window !== null ? "radicle" : __dirname + "/radicle.soy"), true))); exports.setCurrentDir = function(d) { return current_dir = d; }; exports.topLevel = global_env; exports.load = load; exports.parse = parse; exports.read = read; exports.desugar = desugar; exports.expand = expand; exports.eval = _eval; exports.to_string = to_string; exports.compile = compile; exports.readEval = function(frm) { return _eval(expand(desugar(parse(frm)))); }; if (typeof window !== "undefined" && window !== null) { for (k in global_env) { v = global_env[k]; window[getVar(k)] = v; } } }).call(this);