Merge pull request #370 from asarhaddon/hide-gensym-counter
[jackhill/mal.git] / scala / core.scala
CommitLineData
821930db
JM
1import scala.collection.mutable
2import scala.io.Source
3
a816262a
JM
4import types.{MalList, _list, _list_Q,
5 MalVector, _vector, _vector_Q,
6 MalHashMap, _hash_map_Q, _hash_map,
7 Func, MalFunction}
821930db
JM
8import printer._pr_list
9
10object 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