Commit | Line | Data |
---|---|---|
821930db JM |
1 | import scala.collection.mutable |
2 | import scala.io.Source | |
3 | ||
a816262a JM |
4 | import types.{MalList, _list, _list_Q, |
5 | MalVector, _vector, _vector_Q, | |
6 | MalHashMap, _hash_map_Q, _hash_map, | |
7 | Func, MalFunction} | |
821930db JM |
8 | import printer._pr_list |
9 | ||
10 | object core { | |
11 | def mal_throw(a: List[Any]) = { | |
12 | throw new types.MalException(printer._pr_str(a(0))).init(a(0)) | |
13 | } | |
14 | ||
15 | // Scalar functions | |
16 | def keyword(a: List[Any]) = { | |
17 | "\u029e" + a(0).asInstanceOf[String] | |
18 | } | |
19 | ||
20 | def keyword_Q(a: List[Any]) = { | |
21 | a(0) match { | |
8e32dbb6 | 22 | case s: String => s.length != 0 && s(0) == '\u029e' |
821930db JM |
23 | case _ => false |
24 | } | |
25 | } | |
26 | ||
8e32dbb6 JM |
27 | def string_Q(a: List[Any]) = { |
28 | a(0) match { | |
29 | case s: String => s.length == 0 || s(0) != '\u029e' | |
30 | case _ => false | |
31 | } | |
32 | } | |
a816262a | 33 | |
a58f416a VS |
34 | def fn_Q(a: List[Any]) = { |
35 | a(0) match { | |
36 | case s: Func => true | |
37 | case s: MalFunction => !s.asInstanceOf[MalFunction].ismacro | |
38 | case _ => false | |
39 | } | |
40 | } | |
41 | ||
42 | def macro_Q(a: List[Any]) = { | |
43 | a(0) match { | |
44 | case s: MalFunction => s.asInstanceOf[MalFunction].ismacro | |
45 | case _ => false | |
46 | } | |
47 | } | |
48 | ||
a816262a JM |
49 | // number functions |
50 | def _bool_op(a: List[Any], op: (Long, Long) => Boolean) = { | |
51 | op(a(0).asInstanceOf[Long],a(1).asInstanceOf[Long]) | |
52 | } | |
53 | ||
54 | def _num_op(a: List[Any], op: (Long, Long) => Long) = { | |
55 | op(a(0).asInstanceOf[Long],a(1).asInstanceOf[Long]) | |
56 | } | |
57 | ||
a58f416a VS |
58 | def number_Q(a: List[Any]) = { |
59 | a(0).isInstanceOf[Long] || a(0).isInstanceOf[Double] | |
60 | } | |
61 | ||
a816262a | 62 | |
821930db JM |
63 | // string functions |
64 | def read_string(a: List[Any]) = { | |
65 | reader.read_str(a(0).asInstanceOf[String]) | |
66 | } | |
67 | ||
68 | def slurp(a: List[Any]) = { | |
a816262a | 69 | Source.fromFile(a(0).asInstanceOf[String]).getLines.mkString("\n") + "\n" |
821930db JM |
70 | } |
71 | ||
72 | // Hash Map functions | |
73 | def assoc(a: List[Any]): Any = { | |
a816262a | 74 | a(0).asInstanceOf[MalHashMap] ++ _hash_map(a.drop(1):_*) |
821930db JM |
75 | } |
76 | ||
77 | def dissoc(a: List[Any]): Any = { | |
a816262a JM |
78 | var kSet = a.drop(1).toSet |
79 | a(0).asInstanceOf[MalHashMap] | |
821930db JM |
80 | .filterKeys{ !kSet.contains(_) } |
81 | } | |
82 | ||
83 | def get(a: List[Any]): Any = { | |
a816262a | 84 | val hm = a(0).asInstanceOf[MalHashMap] |
821930db | 85 | val key = a(1).asInstanceOf[String] |
a816262a | 86 | if (hm != null && hm.value.contains(key)) hm(key) else null |
821930db JM |
87 | } |
88 | ||
89 | def contains_Q(a: List[Any]): Any = { | |
a816262a | 90 | a(0).asInstanceOf[MalHashMap].value |
821930db JM |
91 | .contains(a(1).asInstanceOf[String]) |
92 | } | |
93 | ||
94 | ||
95 | // sequence functions | |
a816262a JM |
96 | def concat(a: List[Any]): Any = { |
97 | _list((for (sq <- a) yield types._toIter(sq)).flatten:_*) | |
821930db JM |
98 | } |
99 | ||
100 | def nth(a: List[Any]): Any = { | |
a816262a JM |
101 | val lst = a(0).asInstanceOf[MalList].value |
102 | val idx = a(1).asInstanceOf[Long] | |
821930db | 103 | if (idx < lst.length) { |
a816262a | 104 | lst(idx.toInt) |
821930db JM |
105 | } else { |
106 | throw new Exception("nth: index out of range") | |
107 | } | |
108 | } | |
109 | ||
110 | def first(a: List[Any]): Any = { | |
c36d5b39 DM |
111 | a(0) match { |
112 | case null => null | |
113 | case ml: MalList => { | |
114 | val lst = ml.value | |
115 | if (lst.length > 0) lst(0) else null | |
116 | } | |
117 | } | |
821930db JM |
118 | } |
119 | ||
a816262a JM |
120 | def rest(a: List[Any]): Any = { |
121 | a(0) match { | |
c36d5b39 | 122 | case null => _list() |
a816262a JM |
123 | case ml: MalList => _list(ml.drop(1).value:_*) |
124 | } | |
125 | } | |
126 | ||
127 | def empty_Q(a: List[Any]): Any = { | |
128 | a(0) match { | |
129 | case null => true | |
130 | case ml: MalList => ml.value.isEmpty | |
131 | } | |
132 | } | |
133 | ||
134 | def count(a: List[Any]): Any = { | |
135 | a(0) match { | |
136 | case null => 0 | |
137 | case ml: MalList => ml.value.length.asInstanceOf[Long] | |
138 | } | |
139 | } | |
140 | ||
821930db JM |
141 | def apply(a: List[Any]): Any = { |
142 | a match { | |
143 | case f :: rest => { | |
144 | var args1 = rest.slice(0,rest.length-1) | |
a816262a | 145 | var args = args1 ++ rest(rest.length-1).asInstanceOf[MalList].value |
821930db JM |
146 | types._apply(f, args) |
147 | } | |
148 | case _ => throw new Exception("invalid apply call") | |
149 | } | |
150 | } | |
151 | ||
152 | def do_map(a: List[Any]): Any = { | |
153 | a match { | |
154 | case f :: seq :: Nil => { | |
dbac60df JM |
155 | var res = seq.asInstanceOf[MalList].map(x => types._apply(f,List(x))); |
156 | _list(res.value:_*) | |
821930db JM |
157 | } |
158 | case _ => throw new Exception("invalid map call") | |
159 | } | |
160 | } | |
161 | ||
8e32dbb6 JM |
162 | def conj(a: List[Any]): Any = { |
163 | a(0) match { | |
164 | case mv: MalVector => { | |
165 | _vector(mv.value ++ a.slice(1,a.length):_*) | |
166 | } | |
167 | case ml: MalList => { | |
168 | _list(a.slice(1,a.length).reverse ++ ml.value:_*) | |
169 | } | |
170 | } | |
171 | } | |
172 | ||
173 | def seq(a: List[Any]): Any = { | |
174 | a(0) match { | |
175 | case mv: MalVector => { | |
176 | if (mv.value.length == 0) null else _list(mv.value:_*) | |
177 | } | |
178 | case ml: MalList => { | |
179 | if (ml.value.length == 0) null else ml | |
180 | } | |
181 | case ms: String => { | |
182 | if (ms.length == 0) null else _list(ms.split("(?!^)"):_*) | |
183 | } | |
184 | case null => null | |
185 | case _ => throw new Exception("seq: called on non-sequence") | |
186 | } | |
187 | } | |
188 | ||
821930db | 189 | |
a816262a JM |
190 | // meta functions |
191 | def with_meta(a: List[Any]): Any = { | |
192 | val meta: Any = a(1) | |
193 | a(0) match { | |
194 | case ml: MalList => { | |
195 | val new_ml = ml.clone() | |
196 | new_ml.meta = meta | |
197 | new_ml | |
198 | } | |
199 | case hm: MalHashMap => { | |
200 | val new_hm = hm.clone() | |
201 | new_hm.meta = meta | |
202 | new_hm | |
203 | } | |
204 | case fn: Func => { | |
205 | val new_fn = fn.clone() | |
206 | new_fn.meta = meta | |
207 | new_fn | |
208 | } | |
209 | case fn: MalFunction => { | |
210 | val new_fn = fn.clone() | |
211 | new_fn.meta = meta | |
212 | new_fn | |
213 | } | |
214 | case _ => throw new Exception("no meta support for " + a(0).getClass) | |
215 | } | |
216 | } | |
217 | ||
218 | def meta(a: List[Any]): Any = { | |
219 | a(0) match { | |
220 | case ml: MalList => ml.meta | |
221 | case hm: MalHashMap => hm.meta | |
222 | case fn: Func => fn.meta | |
223 | case fn: MalFunction => fn.meta | |
224 | case _ => throw new Exception("no meta support for " + a(0).getClass) | |
225 | } | |
226 | } | |
227 | ||
228 | ||
821930db JM |
229 | // atom functions |
230 | def reset_BANG(a: List[Any]): Any = { | |
231 | a(0).asInstanceOf[types.Atom].value = a(1) | |
232 | a(1) | |
233 | } | |
234 | ||
235 | def swap_BANG(a: List[Any]): Any = { | |
236 | a match { | |
237 | case a0 :: f :: rest => { | |
238 | val atm = a0.asInstanceOf[types.Atom] | |
239 | val args = atm.value +: rest | |
240 | atm.value = types._apply(f, args) | |
241 | atm.value | |
242 | } | |
243 | case _ => throw new Exception("invalid swap! call") | |
244 | } | |
245 | } | |
246 | ||
247 | ||
a816262a | 248 | val ns: Map[String, (List[Any]) => Any] = Map( |
821930db JM |
249 | "=" -> ((a: List[Any]) => types._equal_Q(a(0), a(1))), |
250 | "throw" -> mal_throw _, | |
251 | "nil?" -> ((a: List[Any]) => a(0) == null), | |
252 | "true?" -> ((a: List[Any]) => a(0) == true), | |
253 | "false?" -> ((a: List[Any]) => a(0) == false), | |
a58f416a | 254 | "number?" -> number_Q _, |
8e32dbb6 | 255 | "string?" -> string_Q _, |
821930db JM |
256 | "symbol" -> ((a: List[Any]) => Symbol(a(0).asInstanceOf[String])), |
257 | "symbol?" -> ((a: List[Any]) => a(0).isInstanceOf[Symbol]), | |
258 | "keyword" -> keyword _, | |
259 | "keyword?" -> keyword_Q _, | |
a58f416a VS |
260 | "fn?" -> fn_Q, |
261 | "macro?" -> macro_Q, | |
821930db JM |
262 | |
263 | "pr-str" -> ((a: List[Any]) => _pr_list(a, true, " ")), | |
264 | "str" -> ((a: List[Any]) => _pr_list(a, false, "")), | |
265 | "prn" -> ((a: List[Any]) => { println(_pr_list(a, true, " ")); null}), | |
266 | "println" -> ((a: List[Any]) => { println(_pr_list(a, false, " ")); null}), | |
a816262a | 267 | "readline" -> ((a: List[Any]) => readLine(a(0).asInstanceOf[String])), |
821930db JM |
268 | "read-string" -> read_string _, |
269 | "slurp" -> slurp _, | |
a816262a JM |
270 | |
271 | "<" -> ((a: List[Any]) => _bool_op(a, _ < _)), | |
272 | "<=" -> ((a: List[Any]) => _bool_op(a, _ <= _)), | |
273 | ">" -> ((a: List[Any]) => _bool_op(a, _ > _)), | |
274 | ">=" -> ((a: List[Any]) => _bool_op(a, _ >= _)), | |
275 | "+" -> ((a: List[Any]) => _num_op(a, _ + _)), | |
276 | "-" -> ((a: List[Any]) => _num_op(a, _ - _)), | |
277 | "*" -> ((a: List[Any]) => _num_op(a, _ * _)), | |
278 | "/" -> ((a: List[Any]) => _num_op(a, _ / _)), | |
279 | "time-ms" -> ((a: List[Any]) => System.currentTimeMillis), | |
280 | ||
281 | "list" -> ((a: List[Any]) => _list(a:_*)), | |
282 | "list?" -> ((a: List[Any]) => _list_Q(a(0))), | |
283 | "vector" -> ((a: List[Any]) => _vector(a:_*)), | |
284 | "vector?" -> ((a: List[Any]) => _vector_Q(a(0))), | |
285 | "hash-map" -> ((a: List[Any]) => _hash_map(a:_*)), | |
286 | "map?" -> ((a: List[Any]) => _hash_map_Q(a(0))), | |
821930db JM |
287 | "assoc" -> assoc _, |
288 | "dissoc" -> dissoc _, | |
289 | "get" -> get _, | |
290 | "contains?" -> contains_Q _, | |
a816262a JM |
291 | "keys" -> ((a: List[Any]) => a(0).asInstanceOf[MalHashMap].keys), |
292 | "vals" -> ((a: List[Any]) => a(0).asInstanceOf[MalHashMap].vals), | |
821930db JM |
293 | |
294 | "sequential?" -> ((a: List[Any]) => types._sequential_Q(a(0))), | |
a816262a | 295 | "cons" -> ((a: List[Any]) => a(0) +: a(1).asInstanceOf[MalList]), |
821930db JM |
296 | "concat" -> concat _, |
297 | "nth" -> nth _, | |
298 | "first" -> first _, | |
a816262a JM |
299 | "rest" -> rest _, |
300 | "empty?" -> empty_Q _, | |
301 | "count" -> count _, | |
821930db JM |
302 | "apply" -> apply _, |
303 | "map" -> do_map _, | |
304 | ||
8e32dbb6 JM |
305 | "conj" -> conj _, |
306 | "seq" -> seq _, | |
307 | ||
a816262a JM |
308 | "with-meta" -> with_meta _, |
309 | "meta" -> meta _, | |
821930db JM |
310 | "atom" -> ((a: List[Any]) => new types.Atom(a(0))), |
311 | "atom?" -> ((a: List[Any]) => a(0).isInstanceOf[types.Atom]), | |
312 | "deref" -> ((a: List[Any]) => a(0).asInstanceOf[types.Atom].value), | |
313 | "reset!" -> reset_BANG _, | |
314 | "swap!" -> swap_BANG _ | |
315 | ) | |
316 | } | |
317 | ||
318 | // vim:ts=2:sw=2 |