Merge pull request #273 from wasamasa/r7rs-implementation
[jackhill/mal.git] / js / core.js
CommitLineData
ea81a808
JM
1// Node vs browser behavior
2var core = {};
3if (typeof module === 'undefined') {
4 var exports = core;
5} else {
6 var types = require('./types'),
8cb5cda4
JM
7 readline = require('./node_readline'),
8 reader = require('./reader'),
d953db84
DM
9 printer = require('./printer'),
10 interop = require('./interop');
ea81a808
JM
11}
12
13// Errors/Exceptions
14function mal_throw(exc) { throw exc; }
15
16
17// String functions
18function pr_str() {
19 return Array.prototype.map.call(arguments,function(exp) {
20 return printer._pr_str(exp, true);
21 }).join(" ");
22}
23
24function str() {
25 return Array.prototype.map.call(arguments,function(exp) {
26 return printer._pr_str(exp, false);
27 }).join("");
28}
29
30function prn() {
31b44161 31 printer.println.apply({}, Array.prototype.map.call(arguments,function(exp) {
ea81a808
JM
32 return printer._pr_str(exp, true);
33 }));
34}
35
36function println() {
31b44161 37 printer.println.apply({}, Array.prototype.map.call(arguments,function(exp) {
ea81a808
JM
38 return printer._pr_str(exp, false);
39 }));
40}
41
8cb5cda4 42function slurp(f) {
b58698b2
JM
43 if (typeof require !== 'undefined') {
44 return require('fs').readFileSync(f, 'utf-8');
45 } else {
46 var req = new XMLHttpRequest();
47 req.open("GET", f, false);
48 req.send();
49 if (req.status == 200) {
50 return req.responseText;
51 } else {
52 throw new Error("Failed to slurp file: " + f);
53 }
54 }
8cb5cda4
JM
55}
56
ea81a808 57
db4c329a
JM
58// Number functions
59function time_ms() { return new Date().getTime(); }
60
61
ea81a808
JM
62// Hash Map functions
63function assoc(src_hm) {
64 var hm = types._clone(src_hm);
65 var args = [hm].concat(Array.prototype.slice.call(arguments, 1));
66 return types._assoc_BANG.apply(null, args);
67}
68
69function dissoc(src_hm) {
70 var hm = types._clone(src_hm);
71 var args = [hm].concat(Array.prototype.slice.call(arguments, 1));
72 return types._dissoc_BANG.apply(null, args);
73}
74
75function get(hm, key) {
7e9a2883 76 if (hm != null && key in hm) {
ea81a808
JM
77 return hm[key];
78 } else {
79 return null;
80 }
81}
82
83function contains_Q(hm, key) {
84 if (key in hm) { return true; } else { return false; }
85}
86
87function keys(hm) { return Object.keys(hm); }
88function vals(hm) { return Object.keys(hm).map(function(k) { return hm[k]; }); }
89
90
91// Sequence functions
92function cons(a, b) { return [a].concat(b); }
93
94function concat(lst) {
95 lst = lst || [];
96 return lst.concat.apply(lst, Array.prototype.slice.call(arguments, 1));
97}
98
b8ee29b2
JM
99function nth(lst, idx) {
100 if (idx < lst.length) { return lst[idx]; }
101 else { throw new Error("nth: index out of range"); }
102}
ea81a808 103
8d1e25ac 104function first(lst) { return (lst === null) ? null : lst[0]; }
ea81a808 105
8d1e25ac 106function rest(lst) { return (lst == null) ? [] : lst.slice(1); }
ea81a808
JM
107
108function empty_Q(lst) { return lst.length === 0; }
109
110function count(s) {
111 if (Array.isArray(s)) { return s.length; }
b8ee29b2
JM
112 else if (s === null) { return 0; }
113 else { return Object.keys(s).length; }
ea81a808
JM
114}
115
116function conj(lst) {
117 if (types._list_Q(lst)) {
118 return Array.prototype.slice.call(arguments, 1).reverse().concat(lst);
119 } else {
120 var v = lst.concat(Array.prototype.slice.call(arguments, 1));
121 v.__isvector__ = true;
122 return v;
123 }
124}
125
4c14a8b8
JM
126function seq(obj) {
127 if (types._list_Q(obj)) {
128 return obj.length > 0 ? obj : null;
129 } else if (types._vector_Q(obj)) {
130 return obj.length > 0 ? Array.prototype.slice.call(obj, 0): null;
131 } else if (types._string_Q(obj)) {
132 return obj.length > 0 ? obj.split('') : null;
133 } else if (obj === null) {
134 return null;
135 } else {
136 throw new Error("seq: called on non-sequence");
137 }
138}
139
140
ea81a808
JM
141function apply(f) {
142 var args = Array.prototype.slice.call(arguments, 1);
143 return f.apply(f, args.slice(0, args.length-1).concat(args[args.length-1]));
144}
145
146function map(f, lst) {
147 return lst.map(function(el){ return f(el); });
148}
149
150
151// Metadata functions
152function with_meta(obj, m) {
153 var new_obj = types._clone(obj);
154 new_obj.__meta__ = m;
155 return new_obj;
156}
157
158function meta(obj) {
159 // TODO: support symbols and atoms
160 if ((!types._sequential_Q(obj)) &&
161 (!(types._hash_map_Q(obj))) &&
162 (!(types._function_Q(obj)))) {
163 throw new Error("attempt to get metadata from: " + types._obj_type(obj));
164 }
165 return obj.__meta__;
166}
167
168
169// Atom functions
170function deref(atm) { return atm.val; }
171function reset_BANG(atm, val) { return atm.val = val; }
172function swap_BANG(atm, f) {
173 var args = [atm.val].concat(Array.prototype.slice.call(arguments, 2));
174 atm.val = f.apply(f, args);
175 return atm.val;
176}
177
d953db84
DM
178function js_eval(str) {
179 return interop.js_to_mal(eval(str.toString()));
180}
181
182function js_method_call(object_method_str) {
183 var args = Array.prototype.slice.call(arguments, 1),
184 r = interop.resolve_js(object_method_str),
185 obj = r[0], f = r[1];
186 var res = f.apply(obj, args);
187 return interop.js_to_mal(res);
188}
ea81a808
JM
189
190// types.ns is namespace of type functions
191var ns = {'type': types._obj_type,
192 '=': types._equal_Q,
193 'throw': mal_throw,
194 'nil?': types._nil_Q,
195 'true?': types._true_Q,
196 'false?': types._false_Q,
4c14a8b8 197 'string?': types._string_Q,
ea81a808
JM
198 'symbol': types._symbol,
199 'symbol?': types._symbol_Q,
b8ee29b2
JM
200 'keyword': types._keyword,
201 'keyword?': types._keyword_Q,
8cb5cda4 202
ea81a808
JM
203 'pr-str': pr_str,
204 'str': str,
205 'prn': prn,
206 'println': println,
8cb5cda4
JM
207 'readline': readline.readline,
208 'read-string': reader.read_str,
209 'slurp': slurp,
ea81a808
JM
210 '<' : function(a,b){return a<b;},
211 '<=' : function(a,b){return a<=b;},
212 '>' : function(a,b){return a>b;},
213 '>=' : function(a,b){return a>=b;},
214 '+' : function(a,b){return a+b;},
215 '-' : function(a,b){return a-b;},
216 '*' : function(a,b){return a*b;},
217 '/' : function(a,b){return a/b;},
db4c329a 218 "time-ms": time_ms,
ea81a808
JM
219
220 'list': types._list,
221 'list?': types._list_Q,
222 'vector': types._vector,
223 'vector?': types._vector_Q,
224 'hash-map': types._hash_map,
225 'map?': types._hash_map_Q,
226 'assoc': assoc,
227 'dissoc': dissoc,
228 'get': get,
229 'contains?': contains_Q,
230 'keys': keys,
231 'vals': vals,
232
233 'sequential?': types._sequential_Q,
234 'cons': cons,
235 'concat': concat,
236 'nth': nth,
237 'first': first,
238 'rest': rest,
239 'empty?': empty_Q,
240 'count': count,
ea81a808
JM
241 'apply': apply,
242 'map': map,
4c14a8b8 243
6301e0b6 244 'conj': conj,
4c14a8b8 245 'seq': seq,
ea81a808
JM
246
247 'with-meta': with_meta,
248 'meta': meta,
249 'atom': types._atom,
250 'atom?': types._atom_Q,
251 "deref": deref,
252 "reset!": reset_BANG,
d953db84
DM
253 "swap!": swap_BANG,
254
255 'js-eval': js_eval,
256 '.': js_method_call
257};
ea81a808
JM
258
259exports.ns = core.ns = ns;