DISABLE FDs (REMOVE ME).
[jackhill/mal.git] / js / types.js
CommitLineData
31690700
JM
1// Node vs browser behavior
2var types = {};
3if (typeof module === 'undefined') {
4 var exports = types;
5}
6
17e1c5f9 7// General functions
ea81a808
JM
8
9function _obj_type(obj) {
10 if (_symbol_Q(obj)) { return 'symbol'; }
11 else if (_list_Q(obj)) { return 'list'; }
12 else if (_vector_Q(obj)) { return 'vector'; }
13 else if (_hash_map_Q(obj)) { return 'hash-map'; }
14 else if (_nil_Q(obj)) { return 'nil'; }
15 else if (_true_Q(obj)) { return 'true'; }
16 else if (_false_Q(obj)) { return 'false'; }
17 else if (_atom_Q(obj)) { return 'atom'; }
31690700
JM
18 else {
19 switch (typeof(obj)) {
20 case 'number': return 'number';
21 case 'function': return 'function';
b8ee29b2 22 case 'string': return obj[0] == '\u029e' ? 'keyword' : 'string';
31690700
JM
23 default: throw new Error("Unknown type '" + typeof(obj) + "'");
24 }
25 }
26}
27
ea81a808 28function _sequential_Q(lst) { return _list_Q(lst) || _vector_Q(lst); }
31690700
JM
29
30
ea81a808
JM
31function _equal_Q (a, b) {
32 var ota = _obj_type(a), otb = _obj_type(b);
33 if (!(ota === otb || (_sequential_Q(a) && _sequential_Q(b)))) {
31690700
JM
34 return false;
35 }
36 switch (ota) {
37 case 'symbol': return a.value === b.value;
38 case 'list':
39 case 'vector':
40 if (a.length !== b.length) { return false; }
41 for (var i=0; i<a.length; i++) {
ea81a808 42 if (! _equal_Q(a[i], b[i])) { return false; }
31690700
JM
43 }
44 return true;
45 case 'hash-map':
a0b63ee4
JM
46 if (Object.keys(a).length !== Object.keys(b).length) { return false; }
47 for (var k in a) {
48 if (! _equal_Q(a[k], b[k])) { return false; }
31690700
JM
49 }
50 return true;
51 default:
52 return a === b;
53 }
54}
55
56
ea81a808
JM
57function _clone (obj) {
58 var new_obj;
59 switch (_obj_type(obj)) {
60 case 'list':
61 new_obj = obj.slice(0);
62 break;
63 case 'vector':
64 new_obj = obj.slice(0);
65 new_obj.__isvector__ = true;
66 break;
67 case 'hash-map':
68 new_obj = {};
69 for (var k in obj) {
70 if (obj.hasOwnProperty(k)) { new_obj[k] = obj[k]; }
71 }
72 break;
73 case 'function':
74 new_obj = obj.clone();
75 break;
76 default:
77 throw new Error("clone of non-collection: " + _obj_type(obj));
78 }
2ab1e584
JM
79 Object.defineProperty(new_obj, "__meta__", {
80 enumerable: false,
81 writable: true
82 });
ea81a808
JM
83 return new_obj;
84}
85
86
87// Scalars
88function _nil_Q(a) { return a === null ? true : false; }
89function _true_Q(a) { return a === true ? true : false; }
90function _false_Q(a) { return a === false ? true : false; }
9e1b1752 91function _number_Q(obj) { return typeof obj === 'number'; }
4c14a8b8
JM
92function _string_Q(obj) {
93 return typeof obj === 'string' && obj[0] !== '\u029e';
94}
ea81a808 95
31690700
JM
96
97// Symbols
98function Symbol(name) {
99 this.value = name;
100 return this;
101}
102Symbol.prototype.toString = function() { return this.value; }
ea81a808
JM
103function _symbol(name) { return new Symbol(name); }
104function _symbol_Q(obj) { return obj instanceof Symbol; }
31690700
JM
105
106
b8ee29b2 107// Keywords
dbac60df
JM
108function _keyword(obj) {
109 if (typeof obj === 'string' && obj[0] === '\u029e') {
110 return obj;
111 } else {
112 return "\u029e" + obj;
113 }
114}
b8ee29b2
JM
115function _keyword_Q(obj) {
116 return typeof obj === 'string' && obj[0] === '\u029e';
117}
118
119
31690700 120// Functions
a34b0200
JM
121function _function(Eval, Env, ast, env, params) {
122 var fn = function() {
123 return Eval(ast, new Env(env, params, arguments));
31690700 124 };
a34b0200
JM
125 fn.__meta__ = null;
126 fn.__ast__ = ast;
127 fn.__gen_env__ = function(args) { return new Env(env, params, args); };
6301e0b6 128 fn._ismacro_ = false;
a34b0200 129 return fn;
31690700 130}
ea81a808
JM
131function _function_Q(obj) { return typeof obj == "function"; }
132Function.prototype.clone = function() {
133 var that = this;
134 var temp = function () { return that.apply(this, arguments); };
135 for( key in this ) {
136 temp[key] = this[key];
137 }
138 return temp;
139};
9e1b1752
VS
140function _fn_Q(obj) { return _function_Q(obj) && !obj._ismacro_; }
141function _macro_Q(obj) { return _function_Q(obj) && !!obj._ismacro_; }
31690700
JM
142
143
ea81a808
JM
144// Lists
145function _list() { return Array.prototype.slice.call(arguments, 0); }
146function _list_Q(obj) { return Array.isArray(obj) && !obj.__isvector__; }
31690700
JM
147
148
149// Vectors
ea81a808 150function _vector() {
31690700
JM
151 var v = Array.prototype.slice.call(arguments, 0);
152 v.__isvector__ = true;
153 return v;
154}
6301e0b6 155function _vector_Q(obj) { return Array.isArray(obj) && !!obj.__isvector__; }
31690700 156
31690700
JM
157
158
159// Hash Maps
ea81a808 160function _hash_map() {
31690700
JM
161 if (arguments.length % 2 === 1) {
162 throw new Error("Odd number of hash map arguments");
163 }
164 var args = [{}].concat(Array.prototype.slice.call(arguments, 0));
ea81a808 165 return _assoc_BANG.apply(null, args);
31690700 166}
ea81a808 167function _hash_map_Q(hm) {
31690700
JM
168 return typeof hm === "object" &&
169 !Array.isArray(hm) &&
ea81a808 170 !(hm === null) &&
b8ee29b2 171 !(hm instanceof Symbol) &&
31690700
JM
172 !(hm instanceof Atom);
173}
ea81a808 174function _assoc_BANG(hm) {
31690700
JM
175 if (arguments.length % 2 !== 1) {
176 throw new Error("Odd number of assoc arguments");
177 }
178 for (var i=1; i<arguments.length; i+=2) {
179 var ktoken = arguments[i],
180 vtoken = arguments[i+1];
31690700
JM
181 if (typeof ktoken !== "string") {
182 throw new Error("expected hash-map key string, got: " + (typeof ktoken));
183 }
184 hm[ktoken] = vtoken;
185 }
186 return hm;
187}
ea81a808 188function _dissoc_BANG(hm) {
31690700
JM
189 for (var i=1; i<arguments.length; i++) {
190 var ktoken = arguments[i];
191 delete hm[ktoken];
192 }
193 return hm;
194}
195
31690700
JM
196
197// Atoms
198function Atom(val) { this.val = val; }
ea81a808
JM
199function _atom(val) { return new Atom(val); }
200function _atom_Q(atm) { return atm instanceof Atom; }
201
202
203// Exports
204exports._obj_type = types._obj_type = _obj_type;
205exports._sequential_Q = types._sequential_Q = _sequential_Q;
206exports._equal_Q = types._equal_Q = _equal_Q;
207exports._clone = types._clone = _clone;
208exports._nil_Q = types._nil_Q = _nil_Q;
209exports._true_Q = types._true_Q = _true_Q;
210exports._false_Q = types._false_Q = _false_Q;
9e1b1752 211exports._number_Q = types._number_Q = _number_Q;
4c14a8b8 212exports._string_Q = types._string_Q = _string_Q;
ea81a808
JM
213exports._symbol = types._symbol = _symbol;
214exports._symbol_Q = types._symbol_Q = _symbol_Q;
b8ee29b2
JM
215exports._keyword = types._keyword = _keyword;
216exports._keyword_Q = types._keyword_Q = _keyword_Q;
ea81a808
JM
217exports._function = types._function = _function;
218exports._function_Q = types._function_Q = _function_Q;
9e1b1752
VS
219exports._fn_Q = types._fn_Q = _fn_Q;
220exports._macro_Q = types._macro_Q = _macro_Q;
ea81a808
JM
221exports._list = types._list = _list;
222exports._list_Q = types._list_Q = _list_Q;
223exports._vector = types._vector = _vector;
224exports._vector_Q = types._vector_Q = _vector_Q;
225exports._hash_map = types._hash_map = _hash_map;
226exports._hash_map_Q = types._hash_map_Q = _hash_map_Q;
227exports._assoc_BANG = types._assoc_BANG = _assoc_BANG;
228exports._dissoc_BANG = types._dissoc_BANG = _dissoc_BANG;
229exports._atom = types._atom = _atom;
230exports._atom_Q = types._atom_Q = _atom_Q;