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; } | |
4c14a8b8 JM |
91 | function _string_Q(obj) { |
92 | return typeof obj === 'string' && obj[0] !== '\u029e'; | |
93 | } | |
ea81a808 | 94 | |
31690700 JM |
95 | |
96 | // Symbols | |
97 | function Symbol(name) { | |
98 | this.value = name; | |
99 | return this; | |
100 | } | |
101 | Symbol.prototype.toString = function() { return this.value; } | |
ea81a808 JM |
102 | function _symbol(name) { return new Symbol(name); } |
103 | function _symbol_Q(obj) { return obj instanceof Symbol; } | |
31690700 JM |
104 | |
105 | ||
b8ee29b2 | 106 | // Keywords |
dbac60df JM |
107 | function _keyword(obj) { |
108 | if (typeof obj === 'string' && obj[0] === '\u029e') { | |
109 | return obj; | |
110 | } else { | |
111 | return "\u029e" + obj; | |
112 | } | |
113 | } | |
b8ee29b2 JM |
114 | function _keyword_Q(obj) { |
115 | return typeof obj === 'string' && obj[0] === '\u029e'; | |
116 | } | |
117 | ||
118 | ||
31690700 | 119 | // Functions |
a34b0200 JM |
120 | function _function(Eval, Env, ast, env, params) { |
121 | var fn = function() { | |
122 | return Eval(ast, new Env(env, params, arguments)); | |
31690700 | 123 | }; |
a34b0200 JM |
124 | fn.__meta__ = null; |
125 | fn.__ast__ = ast; | |
126 | fn.__gen_env__ = function(args) { return new Env(env, params, args); }; | |
6301e0b6 | 127 | fn._ismacro_ = false; |
a34b0200 | 128 | return fn; |
31690700 | 129 | } |
ea81a808 JM |
130 | function _function_Q(obj) { return typeof obj == "function"; } |
131 | Function.prototype.clone = function() { | |
132 | var that = this; | |
133 | var temp = function () { return that.apply(this, arguments); }; | |
134 | for( key in this ) { | |
135 | temp[key] = this[key]; | |
136 | } | |
137 | return temp; | |
138 | }; | |
31690700 JM |
139 | |
140 | ||
ea81a808 JM |
141 | // Lists |
142 | function _list() { return Array.prototype.slice.call(arguments, 0); } | |
143 | function _list_Q(obj) { return Array.isArray(obj) && !obj.__isvector__; } | |
31690700 JM |
144 | |
145 | ||
146 | // Vectors | |
ea81a808 | 147 | function _vector() { |
31690700 JM |
148 | var v = Array.prototype.slice.call(arguments, 0); |
149 | v.__isvector__ = true; | |
150 | return v; | |
151 | } | |
6301e0b6 | 152 | function _vector_Q(obj) { return Array.isArray(obj) && !!obj.__isvector__; } |
31690700 | 153 | |
31690700 JM |
154 | |
155 | ||
156 | // Hash Maps | |
ea81a808 | 157 | function _hash_map() { |
31690700 JM |
158 | if (arguments.length % 2 === 1) { |
159 | throw new Error("Odd number of hash map arguments"); | |
160 | } | |
161 | var args = [{}].concat(Array.prototype.slice.call(arguments, 0)); | |
ea81a808 | 162 | return _assoc_BANG.apply(null, args); |
31690700 | 163 | } |
ea81a808 | 164 | function _hash_map_Q(hm) { |
31690700 JM |
165 | return typeof hm === "object" && |
166 | !Array.isArray(hm) && | |
ea81a808 | 167 | !(hm === null) && |
b8ee29b2 | 168 | !(hm instanceof Symbol) && |
31690700 JM |
169 | !(hm instanceof Atom); |
170 | } | |
ea81a808 | 171 | function _assoc_BANG(hm) { |
31690700 JM |
172 | if (arguments.length % 2 !== 1) { |
173 | throw new Error("Odd number of assoc arguments"); | |
174 | } | |
175 | for (var i=1; i<arguments.length; i+=2) { | |
176 | var ktoken = arguments[i], | |
177 | vtoken = arguments[i+1]; | |
31690700 JM |
178 | if (typeof ktoken !== "string") { |
179 | throw new Error("expected hash-map key string, got: " + (typeof ktoken)); | |
180 | } | |
181 | hm[ktoken] = vtoken; | |
182 | } | |
183 | return hm; | |
184 | } | |
ea81a808 | 185 | function _dissoc_BANG(hm) { |
31690700 JM |
186 | for (var i=1; i<arguments.length; i++) { |
187 | var ktoken = arguments[i]; | |
188 | delete hm[ktoken]; | |
189 | } | |
190 | return hm; | |
191 | } | |
192 | ||
31690700 JM |
193 | |
194 | // Atoms | |
195 | function Atom(val) { this.val = val; } | |
ea81a808 JM |
196 | function _atom(val) { return new Atom(val); } |
197 | function _atom_Q(atm) { return atm instanceof Atom; } | |
198 | ||
199 | ||
200 | // Exports | |
201 | exports._obj_type = types._obj_type = _obj_type; | |
202 | exports._sequential_Q = types._sequential_Q = _sequential_Q; | |
203 | exports._equal_Q = types._equal_Q = _equal_Q; | |
204 | exports._clone = types._clone = _clone; | |
205 | exports._nil_Q = types._nil_Q = _nil_Q; | |
206 | exports._true_Q = types._true_Q = _true_Q; | |
207 | exports._false_Q = types._false_Q = _false_Q; | |
4c14a8b8 | 208 | exports._string_Q = types._string_Q = _string_Q; |
ea81a808 JM |
209 | exports._symbol = types._symbol = _symbol; |
210 | exports._symbol_Q = types._symbol_Q = _symbol_Q; | |
b8ee29b2 JM |
211 | exports._keyword = types._keyword = _keyword; |
212 | exports._keyword_Q = types._keyword_Q = _keyword_Q; | |
ea81a808 JM |
213 | exports._function = types._function = _function; |
214 | exports._function_Q = types._function_Q = _function_Q; | |
215 | exports._list = types._list = _list; | |
216 | exports._list_Q = types._list_Q = _list_Q; | |
217 | exports._vector = types._vector = _vector; | |
218 | exports._vector_Q = types._vector_Q = _vector_Q; | |
219 | exports._hash_map = types._hash_map = _hash_map; | |
220 | exports._hash_map_Q = types._hash_map_Q = _hash_map_Q; | |
221 | exports._assoc_BANG = types._assoc_BANG = _assoc_BANG; | |
222 | exports._dissoc_BANG = types._dissoc_BANG = _dissoc_BANG; | |
223 | exports._atom = types._atom = _atom; | |
224 | exports._atom_Q = types._atom_Q = _atom_Q; |