Commit | Line | Data |
---|---|---|
31690700 JM |
1 | // Node vs browser behavior |
2 | var types = {}; | |
3 | if (typeof module === 'undefined') { | |
4 | var exports = types; | |
5 | } | |
6 | ||
17e1c5f9 | 7 | // General functions |
ea81a808 JM |
8 | |
9 | function _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 | 28 | function _sequential_Q(lst) { return _list_Q(lst) || _vector_Q(lst); } |
31690700 JM |
29 | |
30 | ||
ea81a808 JM |
31 | function _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 |
57 | function _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 | |
88 | function _nil_Q(a) { return a === null ? true : false; } | |
89 | function _true_Q(a) { return a === true ? true : false; } | |
90 | function _false_Q(a) { return a === false ? true : false; } | |
9e1b1752 | 91 | function _number_Q(obj) { return typeof obj === 'number'; } |
4c14a8b8 JM |
92 | function _string_Q(obj) { |
93 | return typeof obj === 'string' && obj[0] !== '\u029e'; | |
94 | } | |
ea81a808 | 95 | |
31690700 JM |
96 | |
97 | // Symbols | |
98 | function Symbol(name) { | |
99 | this.value = name; | |
100 | return this; | |
101 | } | |
102 | Symbol.prototype.toString = function() { return this.value; } | |
ea81a808 JM |
103 | function _symbol(name) { return new Symbol(name); } |
104 | function _symbol_Q(obj) { return obj instanceof Symbol; } | |
31690700 JM |
105 | |
106 | ||
b8ee29b2 | 107 | // Keywords |
dbac60df JM |
108 | function _keyword(obj) { |
109 | if (typeof obj === 'string' && obj[0] === '\u029e') { | |
110 | return obj; | |
111 | } else { | |
112 | return "\u029e" + obj; | |
113 | } | |
114 | } | |
b8ee29b2 JM |
115 | function _keyword_Q(obj) { |
116 | return typeof obj === 'string' && obj[0] === '\u029e'; | |
117 | } | |
118 | ||
119 | ||
31690700 | 120 | // Functions |
a34b0200 JM |
121 | function _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 |
131 | function _function_Q(obj) { return typeof obj == "function"; } |
132 | Function.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 |
140 | function _fn_Q(obj) { return _function_Q(obj) && !obj._ismacro_; } |
141 | function _macro_Q(obj) { return _function_Q(obj) && !!obj._ismacro_; } | |
31690700 JM |
142 | |
143 | ||
ea81a808 JM |
144 | // Lists |
145 | function _list() { return Array.prototype.slice.call(arguments, 0); } | |
146 | function _list_Q(obj) { return Array.isArray(obj) && !obj.__isvector__; } | |
31690700 JM |
147 | |
148 | ||
149 | // Vectors | |
ea81a808 | 150 | function _vector() { |
31690700 JM |
151 | var v = Array.prototype.slice.call(arguments, 0); |
152 | v.__isvector__ = true; | |
153 | return v; | |
154 | } | |
6301e0b6 | 155 | function _vector_Q(obj) { return Array.isArray(obj) && !!obj.__isvector__; } |
31690700 | 156 | |
31690700 JM |
157 | |
158 | ||
159 | // Hash Maps | |
ea81a808 | 160 | function _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 | 167 | function _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 | 174 | function _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 | 188 | function _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 | |
198 | function Atom(val) { this.val = val; } | |
ea81a808 JM |
199 | function _atom(val) { return new Atom(val); } |
200 | function _atom_Q(atm) { return atm instanceof Atom; } | |
201 | ||
202 | ||
203 | // Exports | |
204 | exports._obj_type = types._obj_type = _obj_type; | |
205 | exports._sequential_Q = types._sequential_Q = _sequential_Q; | |
206 | exports._equal_Q = types._equal_Q = _equal_Q; | |
207 | exports._clone = types._clone = _clone; | |
208 | exports._nil_Q = types._nil_Q = _nil_Q; | |
209 | exports._true_Q = types._true_Q = _true_Q; | |
210 | exports._false_Q = types._false_Q = _false_Q; | |
9e1b1752 | 211 | exports._number_Q = types._number_Q = _number_Q; |
4c14a8b8 | 212 | exports._string_Q = types._string_Q = _string_Q; |
ea81a808 JM |
213 | exports._symbol = types._symbol = _symbol; |
214 | exports._symbol_Q = types._symbol_Q = _symbol_Q; | |
b8ee29b2 JM |
215 | exports._keyword = types._keyword = _keyword; |
216 | exports._keyword_Q = types._keyword_Q = _keyword_Q; | |
ea81a808 JM |
217 | exports._function = types._function = _function; |
218 | exports._function_Q = types._function_Q = _function_Q; | |
9e1b1752 VS |
219 | exports._fn_Q = types._fn_Q = _fn_Q; |
220 | exports._macro_Q = types._macro_Q = _macro_Q; | |
ea81a808 JM |
221 | exports._list = types._list = _list; |
222 | exports._list_Q = types._list_Q = _list_Q; | |
223 | exports._vector = types._vector = _vector; | |
224 | exports._vector_Q = types._vector_Q = _vector_Q; | |
225 | exports._hash_map = types._hash_map = _hash_map; | |
226 | exports._hash_map_Q = types._hash_map_Q = _hash_map_Q; | |
227 | exports._assoc_BANG = types._assoc_BANG = _assoc_BANG; | |
228 | exports._dissoc_BANG = types._dissoc_BANG = _dissoc_BANG; | |
229 | exports._atom = types._atom = _atom; | |
230 | exports._atom_Q = types._atom_Q = _atom_Q; |