All: split types into types, env, printer, core.
[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'),
7 printer = require('./printer');
8}
9
10// Errors/Exceptions
11function mal_throw(exc) { throw exc; }
12
13
14// String functions
15function pr_str() {
16 return Array.prototype.map.call(arguments,function(exp) {
17 return printer._pr_str(exp, true);
18 }).join(" ");
19}
20
21function str() {
22 return Array.prototype.map.call(arguments,function(exp) {
23 return printer._pr_str(exp, false);
24 }).join("");
25}
26
27function prn() {
28 printer.print.apply({}, Array.prototype.map.call(arguments,function(exp) {
29 return printer._pr_str(exp, true);
30 }));
31}
32
33function println() {
34 printer.print.apply({}, Array.prototype.map.call(arguments,function(exp) {
35 return printer._pr_str(exp, false);
36 }));
37}
38
39
40// Hash Map functions
41function assoc(src_hm) {
42 var hm = types._clone(src_hm);
43 var args = [hm].concat(Array.prototype.slice.call(arguments, 1));
44 return types._assoc_BANG.apply(null, args);
45}
46
47function dissoc(src_hm) {
48 var hm = types._clone(src_hm);
49 var args = [hm].concat(Array.prototype.slice.call(arguments, 1));
50 return types._dissoc_BANG.apply(null, args);
51}
52
53function get(hm, key) {
54 if (key in hm) {
55 return hm[key];
56 } else {
57 return null;
58 }
59}
60
61function contains_Q(hm, key) {
62 if (key in hm) { return true; } else { return false; }
63}
64
65function keys(hm) { return Object.keys(hm); }
66function vals(hm) { return Object.keys(hm).map(function(k) { return hm[k]; }); }
67
68
69// Sequence functions
70function cons(a, b) { return [a].concat(b); }
71
72function concat(lst) {
73 lst = lst || [];
74 return lst.concat.apply(lst, Array.prototype.slice.call(arguments, 1));
75}
76
77function nth(lst, idx) { return lst[idx]; }
78
79function first(lst) { return lst[0]; }
80
81function rest(lst) { return lst.slice(1); }
82
83function empty_Q(lst) { return lst.length === 0; }
84
85function count(s) {
86 if (Array.isArray(s)) { return s.length; }
87 else { return Object.keys(s).length; }
88}
89
90function conj(lst) {
91 if (types._list_Q(lst)) {
92 return Array.prototype.slice.call(arguments, 1).reverse().concat(lst);
93 } else {
94 var v = lst.concat(Array.prototype.slice.call(arguments, 1));
95 v.__isvector__ = true;
96 return v;
97 }
98}
99
100function apply(f) {
101 var args = Array.prototype.slice.call(arguments, 1);
102 return f.apply(f, args.slice(0, args.length-1).concat(args[args.length-1]));
103}
104
105function map(f, lst) {
106 return lst.map(function(el){ return f(el); });
107}
108
109
110// Metadata functions
111function with_meta(obj, m) {
112 var new_obj = types._clone(obj);
113 new_obj.__meta__ = m;
114 return new_obj;
115}
116
117function meta(obj) {
118 // TODO: support symbols and atoms
119 if ((!types._sequential_Q(obj)) &&
120 (!(types._hash_map_Q(obj))) &&
121 (!(types._function_Q(obj)))) {
122 throw new Error("attempt to get metadata from: " + types._obj_type(obj));
123 }
124 return obj.__meta__;
125}
126
127
128// Atom functions
129function deref(atm) { return atm.val; }
130function reset_BANG(atm, val) { return atm.val = val; }
131function swap_BANG(atm, f) {
132 var args = [atm.val].concat(Array.prototype.slice.call(arguments, 2));
133 atm.val = f.apply(f, args);
134 return atm.val;
135}
136
137
138// types.ns is namespace of type functions
139var ns = {'type': types._obj_type,
140 '=': types._equal_Q,
141 'throw': mal_throw,
142 'nil?': types._nil_Q,
143 'true?': types._true_Q,
144 'false?': types._false_Q,
145 'symbol': types._symbol,
146 'symbol?': types._symbol_Q,
147 'pr-str': pr_str,
148 'str': str,
149 'prn': prn,
150 'println': println,
151 '<' : function(a,b){return a<b;},
152 '<=' : function(a,b){return a<=b;},
153 '>' : function(a,b){return a>b;},
154 '>=' : function(a,b){return a>=b;},
155 '+' : function(a,b){return a+b;},
156 '-' : function(a,b){return a-b;},
157 '*' : function(a,b){return a*b;},
158 '/' : function(a,b){return a/b;},
159
160 'list': types._list,
161 'list?': types._list_Q,
162 'vector': types._vector,
163 'vector?': types._vector_Q,
164 'hash-map': types._hash_map,
165 'map?': types._hash_map_Q,
166 'assoc': assoc,
167 'dissoc': dissoc,
168 'get': get,
169 'contains?': contains_Q,
170 'keys': keys,
171 'vals': vals,
172
173 'sequential?': types._sequential_Q,
174 'cons': cons,
175 'concat': concat,
176 'nth': nth,
177 'first': first,
178 'rest': rest,
179 'empty?': empty_Q,
180 'count': count,
181 'conj': conj,
182 'apply': apply,
183 'map': map,
184
185 'with-meta': with_meta,
186 'meta': meta,
187 'atom': types._atom,
188 'atom?': types._atom_Q,
189 "deref": deref,
190 "reset!": reset_BANG,
191 "swap!": swap_BANG};
192
193exports.ns = core.ns = ns;