4 import types
.Types
.MalType
;
6 import types
.MalException
;
7 import printer
.Printer
;
12 static function BoolFn(v
) {
13 if (v
) { return MalTrue
; }
14 else { return MalFalse
; }
17 static function BoolOp(op
) {
18 return function(args
:Array
<MalType
>) {
19 return switch (args
) {
20 case [MalInt(a
), MalInt(b
)]: BoolFn(op(a
,b
));
21 case _
: throw "Invalid boolean op call";
27 static function NumOp(op
) {
28 return function(args
:Array
<MalType
>) {
29 return switch (args
) {
30 case [MalInt(a
), MalInt(b
)]: MalInt(op(a
,b
));
31 case _
: throw "Invalid numeric op call";
37 static var start
= Timer
.stamp();
38 static function time_ms(args
) {
39 return MalInt(Std
.int(1000 * (Timer
.stamp()-start
)));
42 static function equal_Q(args
) {
43 return BoolFn(_equal_Q(args
[0],args
[1]));
46 static function pr_str(args
) {
48 args
.map(function(s
) { return Printer
.pr_str(s
,true); }).join(" ")
51 static function str(args
) {
53 args
.map(function(s
) { return Printer
.pr_str(s
,false); }).join("")
56 static function prn(args
) {
57 Compat
.println(args
.map(function(s
) { return Printer
.pr_str(s
,true); }).join(" "));
60 static function println(args
) {
61 Compat
.println(args
.map(function(s
) { return Printer
.pr_str(s
,false); }).join(" "));
65 static function symbol(args
) {
66 return switch (args
[0]) {
67 case MalString(s
): MalSymbol(s
);
68 case MalSymbol(_
): args
[0];
69 case _
: throw "Invalid symbol call";
73 static function keyword(args
) {
74 return switch (args
[0]) {
76 if (keyword_Q(args
[0])) {
79 MalString("\x7f" + s
);
81 case _
: throw "Invalid keyword call";
85 static function read_string(args
) {
86 return switch (args
[0]) {
87 case MalString(s
): Reader
.read_str(s
);
88 case _
: throw "invalid read_str call";
92 static function readline(args
) {
93 return switch (args
[0]) {
94 case MalString(prompt
):
96 MalString(Compat
.readline(prompt
));
97 } catch (exc
:haxe
.io
.Eof
) {
100 case _
: throw "invalid readline call";
104 static function slurp(args
) {
105 return switch (args
[0]) {
107 MalString(Compat
.slurp(s
));
108 case _
: throw "invalid slurp call";
112 // sequential functions
113 static function sequential_Q(args
) {
114 return BoolFn(list_Q(args
[0]) ||
vector_Q(args
[0]));
117 static function cons(args
) {
118 return switch [args
[0], args
[1]] {
119 case [a
, MalList(l
)] |
121 MalList([a
].concat(l
));
124 case _
: throw "Invalid cons call";
128 static function do_concat(args
:Array
<MalType
>) {
129 var res
:Array
<MalType
> = [];
132 case MalList(l
) |
MalVector(l
):
137 throw "concat called with non-sequence";
143 static function nth(args
) {
144 return switch [args
[0], args
[1]] {
145 case [seq
, MalInt(idx
)]:
147 case _
: throw "Invalid nth call";
151 static function empty_Q(args
) {
152 return switch (args
[0]) {
153 case MalList(l
) |
MalVector(l
):
154 if (l
.length
== 0) { MalTrue
; }
156 case MalNil
: MalTrue
;
161 static function count(args
) {
162 return switch (args
[0]) {
163 case MalList(l
) |
MalVector(l
): MalInt(l
.length
);
164 case MalNil
: MalInt(0);
165 case _
: throw "count called on non-sequence";
169 static function apply(args
) {
170 return switch [args
[0], args
[args
.length
-1]] {
171 case [MalFunc(f
,_
,_
,_
,_
), MalList(l
)] |
172 [MalFunc(f
,_
,_
,_
,_
), MalVector(l
)]:
173 var fargs
= args
.slice(1,args
.length
-1).concat(l
);
175 case _
: throw "Invalid apply call";
179 static function do_map(args
) {
180 return switch [args
[0], args
[1]] {
181 case [MalFunc(f
,_
,_
,_
,_
), MalList(l
)] |
182 [MalFunc(f
,_
,_
,_
,_
), MalVector(l
)]:
183 return MalList(l
.map(function(x
) { return f([x
]); }));
184 case _
: throw "Invalid map call";
188 static function conj(args
) {
189 return switch (args
[0]) {
191 var elems
= args
.slice(1);
193 MalList(elems
.concat(l
));
195 MalVector(l
.concat(args
.slice(1)));
196 case _
: throw "Invalid conj call";
200 static function seq(args
) {
201 return switch (args
[0]) {
203 l
.length
> 0 ? args
[0] : nil
;
205 l
.length
> 0 ?
MalList(l
.slice(0)) : nil
;
207 if (s
.length
== 0) { return nil
; }
208 MalList(s
.split("").map(function(c
) { return MalString(c
); }));
211 case _
: throw "seq: called on non-sequence";
216 // hash-map functions
218 public static function get(hm
:MalType
, key
:MalType
) {
219 return switch [hm
, key
] {
220 case [MalHashMap(m
), MalString(k
)]:
226 case [nil
, MalString(k
)]:
228 case _
: throw "invalid get call";
232 public static function assoc(args
) {
233 return switch (args
[0]) {
235 var new_m
= _clone(args
[0]);
236 MalHashMap(assoc_BANG(new_m
, args
.slice(1)));
237 case _
: throw "invalid assoc call";
241 public static function dissoc(args
) {
242 return switch (args
[0]) {
244 var new_m
= _clone(args
[0]);
245 MalHashMap(dissoc_BANG(new_m
, args
.slice(1)));
246 case _
: throw "invalid dissoc call";
250 public static function contains_Q(hm
:MalType
, key
:MalType
) {
251 return switch [hm
, key
] {
252 case [MalHashMap(m
), MalString(k
)]:
254 case _
: throw "invalid contains? call";
258 public static function keys(hm
:MalType
) {
261 MalList([for (k
in m
.keys()) MalString(k
)]);
262 case _
: throw "invalid keys call";
266 public static function vals(hm
:MalType
) {
269 MalList([for (k
in m
.keys()) m
[k
]]);
270 case _
: throw "invalid vals call";
274 // metadata functions
275 static function meta(args
) {
276 return switch (args
[0]) {
277 case MalFunc(f
,_
,_
,_
,_
,meta
): meta
;
278 case _
: throw "meta called on non-function";
282 static function with_meta(args
) {
283 return switch (args
[0]) {
284 case MalFunc(f
,a
,e
,p
,mac
,_
):
285 MalFunc(f
,a
,e
,p
,mac
,args
[1]);
286 case _
: throw "with_meta called on non-function";
294 static function deref(args
) {
295 return switch (args
[0]) {
296 case MalAtom(v
): v
.val
;
297 case _
: throw "deref called on non-atom";
301 static function reset_BANG(args
) {
302 return switch (args
[0]) {
303 case MalAtom(v
): v
.val
= args
[1];
304 case _
: throw "reset! called on non-atom";
308 static function swap_BANG(args
) {
309 return switch [args
[0], args
[1]] {
310 case [MalAtom(v
), MalFunc(f
,_
,_
,_
,_
)]:
311 var fargs
= [v
.val
].concat(args
.slice(2));
314 case _
: throw "swap! called on non-atom";
319 public static var ns
:Map
<String
,Array
<MalType
> -> MalType
> = [
320 "=" => function(a
) { return BoolFn(_equal_Q(a
[0],a
[1])); },
321 "throw" => function(a
) { throw new MalException(a
[0]); },
323 "nil?" => function(a
) { return BoolFn(nil_Q(a
[0])); },
324 "true?" => function(a
) { return BoolFn(true_Q(a
[0])); },
325 "false?" => function(a
) { return BoolFn(false_Q(a
[0])); },
326 "string?" => function(a
) { return BoolFn(string_Q(a
[0])); },
328 "symbol?" => function(a
) { return BoolFn(symbol_Q(a
[0])); },
329 "keyword" => keyword
,
330 "keyword?" => function(a
) { return BoolFn(keyword_Q(a
[0])); },
335 "println" => println
,
336 "read-string" => read_string
,
337 "readline" => readline
,
340 "<" => BoolOp(function(a
,b
) {return a
<b
;}),
341 "<=" => BoolOp(function(a
,b
) {return a
<=b
;}),
342 ">" => BoolOp(function(a
,b
) {return a
>b
;}),
343 ">=" => BoolOp(function(a
,b
) {return a
>=b
;}),
344 "+" => NumOp(function(a
,b
) {return a
+b
;}),
345 "-" => NumOp(function(a
,b
) {return a
-b
;}),
346 "*" => NumOp(function(a
,b
) {return a
*b
;}),
347 "/" => NumOp(function(a
,b
) {return Std
.int(a
/b
);}),
348 "time-ms" => time_ms
,
350 "list" => function(a
) { return MalList(a
); },
351 "list?" => function(a
) { return BoolFn(list_Q(a
[0])); },
352 "vector" => function(a
) { return MalVector(a
); },
353 "vector?" => function(a
) { return BoolFn(vector_Q(a
[0])); },
354 "hash-map" => hash_map
,
355 "map?" => function(a
) { return BoolFn(hash_map_Q(a
[0])); },
358 "get" => function(a
) { return get(a
[0],a
[1]); },
359 "contains?" => function(a
) { return BoolFn(contains_Q(a
[0], a
[1])); },
360 "keys" => function(a
) { return keys(a
[0]); } ,
361 "vals" => function(a
) { return vals(a
[0]); } ,
363 "sequential?" => sequential_Q
,
365 "concat" => do_concat
,
367 "first" => function(a
) { return first(a
[0]); },
368 "rest" => function(a
) { return rest(a
[0]); },
378 "with-meta" => with_meta
,
379 "atom" => function(a
) { return MalAtom({val
:a
[0]}); },
380 "atom?" => function(a
) { return BoolFn(atom_Q(a
[0])); },
382 "reset!" => reset_BANG
,