aboutsummaryrefslogtreecommitdiff
path: root/js/types.js
diff options
context:
space:
mode:
authorJoel Martin <github@martintribe.org>2014-04-02 22:23:37 -0500
committerJoel Martin <github@martintribe.org>2014-04-02 22:23:37 -0500
commitea81a8087bcd7953b083a2be9db447f75e7ebf56 (patch)
tree6cf47a2dbd55d42efc4a901eaabdec952f40ce89 /js/types.js
parent1617910ad342a55762f3ddabb975849d843cff85 (diff)
downloadmal-ea81a8087bcd7953b083a2be9db447f75e7ebf56.tar.gz
mal-ea81a8087bcd7953b083a2be9db447f75e7ebf56.zip
All: split types into types, env, printer, core.
- types: low-level mapping to the implementation language. - core: functions on types that are exposed directly to mal. - printer: implementation called by pr-str, str, prn, println. - env: the environment implementation - Also, unindent all TCO while loops so that the diff of step4 and step5 are minimized.
Diffstat (limited to 'js/types.js')
-rw-r--r--js/types.js423
1 files changed, 97 insertions, 326 deletions
diff --git a/js/types.js b/js/types.js
index 18fad0a..7fd2962 100644
--- a/js/types.js
+++ b/js/types.js
@@ -7,59 +7,17 @@ if (typeof module === 'undefined') {
var print = exports.print = function () { console.log.apply(console, arguments); };
}
-// General utility functions
-
-// Clone a function
-Function.prototype.clone = function() {
- var that = this;
- var temp = function () { return that.apply(this, arguments); };
- for( key in this ) {
- temp[key] = this[key];
- }
- return temp;
-};
-
-function _clone (obj) {
- var new_obj;
- switch (obj_type(obj)) {
- case 'list':
- new_obj = obj.slice(0);
- break;
- case 'vector':
- new_obj = obj.slice(0);
- new_obj.__isvector__ = true;
- break;
- case 'hash-map':
- new_obj = {};
- for (var k in obj) {
- if (obj.hasOwnProperty(k)) { new_obj[k] = obj[k]; }
- }
- break;
- case 'function':
- new_obj = obj.clone();
- break;
- default:
- throw new Error("clone of non-collection: " + obj_type(obj));
- }
- return new_obj;
-}
-
-
-
-
-function nil_Q(a) { return a === null ? true : false; }
-function true_Q(a) { return a === true ? true : false; }
-function false_Q(a) { return a === false ? true : false; }
-
-function obj_type(obj) {
- if (symbol_Q(obj)) { return 'symbol'; }
- else if (list_Q(obj)) { return 'list'; }
- else if (vector_Q(obj)) { return 'vector'; }
- else if (hash_map_Q(obj)) { return 'hash-map'; }
- else if (nil_Q(obj)) { return 'nil'; }
- else if (true_Q(obj)) { return 'true'; }
- else if (false_Q(obj)) { return 'false'; }
- else if (atom_Q(obj)) { return 'atom'; }
+// General fucnctions
+
+function _obj_type(obj) {
+ if (_symbol_Q(obj)) { return 'symbol'; }
+ else if (_list_Q(obj)) { return 'list'; }
+ else if (_vector_Q(obj)) { return 'vector'; }
+ else if (_hash_map_Q(obj)) { return 'hash-map'; }
+ else if (_nil_Q(obj)) { return 'nil'; }
+ else if (_true_Q(obj)) { return 'true'; }
+ else if (_false_Q(obj)) { return 'false'; }
+ else if (_atom_Q(obj)) { return 'atom'; }
else {
switch (typeof(obj)) {
case 'number': return 'number';
@@ -70,82 +28,12 @@ function obj_type(obj) {
}
}
-function _pr_str(obj, print_readably) {
- if (typeof print_readably === 'undefined') { print_readably = true; }
- var _r = print_readably;
- var ot = obj_type(obj);
- switch (ot) {
- case 'list':
- var ret = obj.map(function(e) { return _pr_str(e,_r); });
- return "(" + ret.join(' ') + ")";
- case 'vector':
- var ret = obj.map(function(e) { return _pr_str(e,_r); });
- return "[" + ret.join(' ') + "]";
- case 'hash-map':
- var ret = [];
- for (var k in obj) {
- ret.push(_pr_str(k,_r), _pr_str(obj[k],_r));
- }
- return "{" + ret.join(' ') + "}";
- case 'string':
- if (print_readably) {
- return '"' + obj.replace(/\\/, "\\\\").replace(/"/g, '\\"') + '"';
- } else {
- return obj;
- }
- case 'nil':
- return "nil";
- case 'atom':
- return "(atom " + _pr_str(obj.val,_r) + ")";
- default:
- return obj.toString();
- }
-}
-
-function pr_str() {
- return Array.prototype.map.call(arguments,function(exp) {
- return _pr_str(exp, true);
- }).join(" ");
-}
-
-function str() {
- return Array.prototype.map.call(arguments,function(exp) {
- return _pr_str(exp, false);
- }).join("");
-}
-
-function prn() {
- print.apply({}, Array.prototype.map.call(arguments,function(exp) {
- return _pr_str(exp, true);
- }));
-}
-
-function println() {
- print.apply({}, Array.prototype.map.call(arguments,function(exp) {
- return _pr_str(exp, false);
- }));
-}
-
-function with_meta(obj, m) {
- var new_obj = _clone(obj);
- new_obj.__meta__ = m;
- return new_obj;
-}
-
-function meta(obj) {
- // TODO: support symbols and atoms
- if ((!sequential_Q(obj)) &&
- (!(hash_map_Q(obj))) &&
- (!(function_Q(obj)))) {
- throw new Error("attempt to get metadata from: " + obj_type(obj));
- }
- return obj.__meta__;
-}
+function _sequential_Q(lst) { return _list_Q(lst) || _vector_Q(lst); }
-function equal_Q (a, b) {
- var ota = obj_type(a), otb = obj_type(b);
- if (!(ota === otb || (sequential_Q(a) && sequential_Q(b)))) {
+function _equal_Q (a, b) {
+ var ota = _obj_type(a), otb = _obj_type(b);
+ if (!(ota === otb || (_sequential_Q(a) && _sequential_Q(b)))) {
return false;
}
switch (ota) {
@@ -154,7 +42,7 @@ function equal_Q (a, b) {
case 'vector':
if (a.length !== b.length) { return false; }
for (var i=0; i<a.length; i++) {
- if (! equal_Q(a[i], b[i])) { return false; }
+ if (! _equal_Q(a[i], b[i])) { return false; }
}
return true;
case 'hash-map':
@@ -172,6 +60,37 @@ function equal_Q (a, b) {
}
+function _clone (obj) {
+ var new_obj;
+ switch (_obj_type(obj)) {
+ case 'list':
+ new_obj = obj.slice(0);
+ break;
+ case 'vector':
+ new_obj = obj.slice(0);
+ new_obj.__isvector__ = true;
+ break;
+ case 'hash-map':
+ new_obj = {};
+ for (var k in obj) {
+ if (obj.hasOwnProperty(k)) { new_obj[k] = obj[k]; }
+ }
+ break;
+ case 'function':
+ new_obj = obj.clone();
+ break;
+ default:
+ throw new Error("clone of non-collection: " + _obj_type(obj));
+ }
+ return new_obj;
+}
+
+
+// Scalars
+function _nil_Q(a) { return a === null ? true : false; }
+function _true_Q(a) { return a === true ? true : false; }
+function _false_Q(a) { return a === false ? true : false; }
+
// Symbols
function Symbol(name) {
@@ -179,68 +98,61 @@ function Symbol(name) {
return this;
}
Symbol.prototype.toString = function() { return this.value; }
-
-function symbol(name) { return new Symbol(name); }
-
-function symbol_Q(obj) { return obj instanceof Symbol; }
+function _symbol(name) { return new Symbol(name); }
+function _symbol_Q(obj) { return obj instanceof Symbol; }
// Functions
-function new_function(func, exp, env, params) {
+function _function(Eval, Env, exp, env, params) {
var f = function() {
// TODO: figure out why this throws with 'and' macro
//throw new Error("Attempt to invoke mal function directly");
- return func(exp, new Env(env, params, arguments));
+ return Eval(exp, new Env(env, params, arguments));
};
f.__meta__ = {exp: exp, env: env, params: params};
return f;
-
}
-function function_Q(f) { return typeof f == "function"; }
-
+function _function_Q(obj) { return typeof obj == "function"; }
+Function.prototype.clone = function() {
+ var that = this;
+ var temp = function () { return that.apply(this, arguments); };
+ for( key in this ) {
+ temp[key] = this[key];
+ }
+ return temp;
+};
-// Errors/Exceptions
-function mal_throw(exc) { throw exc; }
+// Lists
+function _list() { return Array.prototype.slice.call(arguments, 0); }
+function _list_Q(obj) { return Array.isArray(obj) && !obj.__isvector__; }
// Vectors
-function vector() {
+function _vector() {
var v = Array.prototype.slice.call(arguments, 0);
v.__isvector__ = true;
return v;
}
+function _vector_Q(obj) { return Array.isArray(obj) && obj.__isvector__; }
-function vector_Q(v) { return Array.isArray(v) && v.__isvector__; }
-
-
-// Lists
-
-function list() {
- return Array.prototype.slice.call(arguments, 0);
-}
-
-function list_Q(lst) { return Array.isArray(lst) && !lst.__isvector__; }
// Hash Maps
-
-function hash_map() {
+function _hash_map() {
if (arguments.length % 2 === 1) {
throw new Error("Odd number of hash map arguments");
}
var args = [{}].concat(Array.prototype.slice.call(arguments, 0));
- return assoc_BANG.apply(null, args);
+ return _assoc_BANG.apply(null, args);
}
-
-function hash_map_Q(hm) {
+function _hash_map_Q(hm) {
return typeof hm === "object" &&
!Array.isArray(hm) &&
- !(hm === null) &&
+ !(hm === null) &&
!(hm instanceof Atom);
}
-
-function assoc_BANG(hm) {
+function _assoc_BANG(hm) {
if (arguments.length % 2 !== 1) {
throw new Error("Odd number of assoc arguments");
}
@@ -258,14 +170,7 @@ function assoc_BANG(hm) {
}
return hm;
}
-
-function assoc(src_hm) {
- var hm = _clone(src_hm);
- var args = [hm].concat(Array.prototype.slice.call(arguments, 1));
- return assoc_BANG.apply(null, args);
-}
-
-function dissoc_BANG(hm) {
+function _dissoc_BANG(hm) {
for (var i=1; i<arguments.length; i++) {
var ktoken = arguments[i];
delete hm[ktoken];
@@ -273,166 +178,32 @@ function dissoc_BANG(hm) {
return hm;
}
-function dissoc(src_hm) {
- var hm = _clone(src_hm);
- var args = [hm].concat(Array.prototype.slice.call(arguments, 1));
- return dissoc_BANG.apply(null, args);
-}
-
-function get(hm, key) {
- if (key in hm) {
- return hm[key];
- } else {
- return null;
- }
-}
-
-function contains_Q(hm, key) {
- if (key in hm) { return true; } else { return false; }
-}
-
-function keys(hm) { return Object.keys(hm); }
-function vals(hm) { return Object.keys(hm).map(function(k) { return hm[k]; }); }
-
// Atoms
function Atom(val) { this.val = val; }
-function atom(val) { return new Atom(val); }
-function atom_Q(atm) { return atm instanceof Atom; }
-function deref(atm) { return atm.val; }
-function reset_BANG(atm, val) { return atm.val = val; }
-function swap_BANG(atm, f) {
- var args = [atm.val].concat(Array.prototype.slice.call(arguments, 2));
- atm.val = f.apply(f, args);
- return atm.val;
-}
-
-
-// Sequence operations
-function sequential_Q(lst) { return list_Q(lst) || vector_Q(lst); }
-
-function nth(lst, idx) { return lst[idx]; }
-
-function count(s) {
- if (Array.isArray(s)) { return s.length; }
- else { return Object.keys(s).length; }
-}
-
-function empty_Q(lst) { return lst.length === 0; }
-
-function cons(a, b) { return [a].concat(b); }
-
-function concat(lst) {
- lst = lst || [];
- return lst.concat.apply(lst, Array.prototype.slice.call(arguments, 1));
-}
-
-function conj(lst) {
- if (list_Q(lst)) {
- return Array.prototype.slice.call(arguments, 1).reverse().concat(lst);
- } else {
- var v = lst.concat(Array.prototype.slice.call(arguments, 1));
- v.__isvector__ = true;
- return v;
- }
-}
-
-function first(lst) { return lst[0]; }
-
-function rest(lst) { return lst.slice(1); }
-
-
-
-// General list related functions
-function apply(f) {
- var args = Array.prototype.slice.call(arguments, 1);
- return f.apply(f, args.slice(0, args.length-1).concat(args[args.length-1]));
-}
-
-function map(f, lst) {
- return lst.map(function(el){ return f(el); });
-}
-
-
-// Env implementation
-function Env(outer, binds, exprs) {
- this.data = {};
- this.outer = outer || null;
-
- if (binds && exprs) {
- // Returns a new Env with symbols in binds bound to
- // corresponding values in exprs
- // TODO: check types of binds and exprs and compare lengths
- for (var i=0; i<binds.length;i++) {
- if (binds[i].value === "&") {
- // variable length arguments
- this.data[binds[i+1].value] = Array.prototype.slice.call(exprs, i);
- break;
- } else {
- this.data[binds[i].value] = exprs[i];
- }
- }
- }
- return this;
-}
-Env.prototype.find = function (key) {
- if (key in this.data) { return this; }
- else if (this.outer) { return this.outer.find(key); }
- else { return null; }
-};
-Env.prototype.set = function(key, value) { this.data[key] = value; return value; },
-Env.prototype.get = function(key) {
- var env = this.find(key);
- if (!env) { throw new Error("'" + key + "' not found"); }
- return env.data[key];
-};
-
-// types.ns is namespace of type functions
-var ns = {'pr-str': pr_str, 'str': str, 'prn': prn, 'println': println,
- 'with-meta': with_meta, 'meta': meta,
- type: obj_type, '=': equal_Q,
- symbol: symbol, 'symbol?': symbol_Q,
- 'nil?': nil_Q, 'true?': true_Q, 'false?': false_Q,
- '<' : function(a,b){return a<b;},
- '<=' : function(a,b){return a<=b;},
- '>' : function(a,b){return a>b;},
- '>=' : function(a,b){return a>=b;},
- '+' : function(a,b){return a+b;},
- '-' : function(a,b){return a-b;},
- '*' : function(a,b){return a*b;},
- '/' : function(a,b){return a/b;},
- 'throw': mal_throw,
- 'list': list, 'list?': list_Q,
- 'vector': vector, 'vector?': vector_Q,
- 'hash-map': hash_map, 'map?': hash_map_Q,
- 'assoc': assoc, 'dissoc': dissoc, 'get': get,
- 'contains?': contains_Q, 'keys': keys, 'vals': vals,
- 'atom': atom, 'atom?': atom_Q,
- "deref": deref, "reset!": reset_BANG, "swap!": swap_BANG,
- 'sequential?': sequential_Q, 'cons': cons, 'nth': nth,
- 'empty?': empty_Q, 'count': count, 'concat': concat,
- 'conj': conj, 'first': first, 'rest': rest,
- 'apply': apply, 'map': map};
-
-exports.ns = types.ns = ns;
-exports._pr_str = types._pr_str = _pr_str;
-exports.prn = types.prn = prn;
-exports.Env = types.Env = Env;
-
-exports.symbol = types.symbol = symbol;
-exports.symbol_Q = types.symbol_Q = symbol_Q;
-exports.hash_map = types.hash_map = hash_map;
-exports.hash_map_Q = types.hash_map_Q = hash_map_Q;
-exports.new_function = types.new_function = new_function;
-exports.list = types.list = list;
-exports.list_Q = types.list_Q = list_Q;
-exports.vector = types.vector = vector;
-exports.vector_Q = types.vector_Q = vector_Q;
-
-exports.sequential_Q = types.sequential_Q = sequential_Q;
-exports.cons = types.cons = cons;
-exports.concat = types.concat = concat;
-exports.first = types.first = first;
-exports.rest = types.rest = rest;
-exports.apply = types.apply = apply;
-exports.map = types.map = map;
+function _atom(val) { return new Atom(val); }
+function _atom_Q(atm) { return atm instanceof Atom; }
+
+
+// Exports
+exports._obj_type = types._obj_type = _obj_type;
+exports._sequential_Q = types._sequential_Q = _sequential_Q;
+exports._equal_Q = types._equal_Q = _equal_Q;
+exports._clone = types._clone = _clone;
+exports._nil_Q = types._nil_Q = _nil_Q;
+exports._true_Q = types._true_Q = _true_Q;
+exports._false_Q = types._false_Q = _false_Q;
+exports._symbol = types._symbol = _symbol;
+exports._symbol_Q = types._symbol_Q = _symbol_Q;
+exports._function = types._function = _function;
+exports._function_Q = types._function_Q = _function_Q;
+exports._list = types._list = _list;
+exports._list_Q = types._list_Q = _list_Q;
+exports._vector = types._vector = _vector;
+exports._vector_Q = types._vector_Q = _vector_Q;
+exports._hash_map = types._hash_map = _hash_map;
+exports._hash_map_Q = types._hash_map_Q = _hash_map_Q;
+exports._assoc_BANG = types._assoc_BANG = _assoc_BANG;
+exports._dissoc_BANG = types._dissoc_BANG = _dissoc_BANG;
+exports._atom = types._atom = _atom;
+exports._atom_Q = types._atom_Q = _atom_Q;