From 3169070063b2cb877200117ebb384269d73bcb93 Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Mon, 24 Mar 2014 16:32:24 -0500 Subject: Current state of mal for Clojure West lighting talk. --- js/types.js | 429 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 429 insertions(+) create mode 100644 js/types.js (limited to 'js/types.js') diff --git a/js/types.js b/js/types.js new file mode 100644 index 0000000..062b0dd --- /dev/null +++ b/js/types.js @@ -0,0 +1,429 @@ +// Node vs browser behavior +var types = {}; +if (typeof module === 'undefined') { + var exports = types; +} + +// 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'; } + else { + switch (typeof(obj)) { + case 'number': return 'number'; + case 'function': return 'function'; + case 'string': return 'string'; + default: throw new Error("Unknown type '" + typeof(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() { + console.log.apply(console, Array.prototype.map.call(arguments,function(exp) { + return _pr_str(exp, true); + })); +} + +function println() { + console.log.apply(console, 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 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) { + case 'symbol': return a.value === b.value; + case 'list': + case 'vector': + if (a.length !== b.length) { return false; } + for (var i=0; i' : 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; -- cgit v1.2.3