3 {$H+} // Use AnsiString
18 TCoreDict
= specialize TFPGMap
<string,TMalCallable
>;
21 EVAL
: function (A
: TMal
; E
: TEnv
) : TMal
;
24 ////////////////////////////////////////////////////////////
30 function equal_Q(Args
: TMalArray
) : TMal
;
32 equal_Q
:= wrap_tf(_equal_Q(Args
[0], Args
[1]));
35 function throw(Args
: TMalArray
) : TMal
;
37 raise TMalException
.Create(Args
[0]);
38 throw
:= TMalNil
.Create
; // Not reached
43 function nil_Q(Args
: TMalArray
) : TMal
;
45 nil_Q
:= wrap_tf(Args
[0] is TMalNil
);
47 function true_Q(Args
: TMalArray
) : TMal
;
49 true_Q
:= wrap_tf(Args
[0] is TMalTrue
);
51 function false_Q(Args
: TMalArray
) : TMal
;
53 false_Q
:= wrap_tf(Args
[0] is TMalFalse
);
55 function string_Q(Args
: TMalArray
) : TMal
;
57 string_Q
:= wrap_tf(_string_Q(Args
[0]));
59 function symbol(Args
: TMalArray
) : TMal
;
61 if Args
[0] is TMalSymbol
then
63 else if Args
[0] is TMalString
then
64 symbol
:= TMalSymbol
.Create((Args
[0] as TMalString
).Val
)
66 raise Exception
.Create('Invalid symbol call');
68 function symbol_Q(Args
: TMalArray
) : TMal
;
70 symbol_Q
:= wrap_tf(Args
[0] is TMalSymbol
);
72 function keyword(Args
: TMalArray
) : TMal
;
74 if ((Args
[0] is TMalString
) and not _string_Q(Args
[0])) then
76 else if Args
[0] is TMalString
then
77 keyword
:= TMalString
.Create(#127 + (Args
[0] as TMalString
).Val
)
79 raise Exception
.Create('Invalid keyword call');
81 function keyword_Q(Args
: TMalArray
) : TMal
;
83 keyword_Q
:= wrap_tf((Args
[0] is TMalString
) and not _string_Q(Args
[0]));
88 function do_pr_str(Args
: TMalArray
) : TMal
;
90 do_pr_str
:= TMalString
.Create(pr_str_array(Args
, true, ' '));
92 function str(Args
: TMalArray
) : TMal
;
94 str
:= TMalString
.Create(pr_str_array(Args
, false, ''));
96 function prn(Args
: TMalArray
) : TMal
;
98 WriteLn(pr_str_array(Args
, true, ' '));
99 prn
:= TMalNil
.Create
;
101 function println(Args
: TMalArray
) : TMal
;
103 WriteLn(pr_str_array(Args
, false, ' '));
104 println
:= TMalNil
.Create
;
107 function read_string(Args
: TMalArray
) : TMal
;
109 read_string
:= read_str((Args
[0] as TMalString
).Val
);
111 function do_readline(Args
: TMalArray
) : TMal
;
116 Prompt
:= (Args
[0] as TMalString
).Val
;
118 Line
:= _readline(Prompt
);
119 do_readline
:= TMalString
.Create(Line
);
121 On E
: MalEOF
do do_readline
:= TMalNil
.Create
;
124 function slurp(Args
: TMalArray
) : TMal
;
128 StrL
:= TStringList
.Create
;
129 StrL
.LoadFromFile((Args
[0] as TMalString
).Val
);
130 slurp
:= TMalString
.Create(StrL
.Text);
135 function lt(Args
: TMalArray
) : TMal
;
137 lt
:= wrap_tf((Args
[0] as TMalInt
).Val
< (Args
[1] as TMalInt
).Val
);
139 function lte(Args
: TMalArray
) : TMal
;
141 lte
:= wrap_tf((Args
[0] as TMalInt
).Val
<= (Args
[1] as TMalInt
).Val
);
143 function gt(Args
: TMalArray
) : TMal
;
145 gt
:= wrap_tf((Args
[0] as TMalInt
).Val
> (Args
[1] as TMalInt
).Val
);
147 function gte(Args
: TMalArray
) : TMal
;
149 gte
:= wrap_tf((Args
[0] as TMalInt
).Val
>= (Args
[1] as TMalInt
).Val
);
152 function add(Args
: TMalArray
) : TMal
;
154 add
:= TMalInt
.Create((Args
[0] as TMalInt
).Val
+
155 (Args
[1] as TMalInt
).Val
);
157 function subtract(Args
: TMalArray
) : TMal
;
159 subtract
:= TMalInt
.Create((Args
[0] as TMalInt
).Val
-
160 (Args
[1] as TMalInt
).Val
);
162 function multiply(Args
: TMalArray
) : TMal
;
164 multiply
:= TMalInt
.Create((Args
[0] as TMalInt
).Val
*
165 (Args
[1] as TMalInt
).Val
);
167 function divide(Args
: TMalArray
) : TMal
;
169 divide
:= TMalInt
.Create((Args
[0] as TMalInt
).Val
div
170 (Args
[1] as TMalInt
).Val
);
172 function time_ms(Args
: TMalArray
) : TMal
;
174 time_ms
:= TMalInt
.Create(Trunc(TimeStampToMSecs(DateTimeToTimeStamp(Now
))));
177 // Collection functions
179 function list(Args
: TMalArray
) : TMal
;
181 list
:= TMalList
.Create(Args
);
183 function list_Q(Args
: TMalArray
) : TMal
;
185 list_Q
:= wrap_tf(Args
[0].ClassType
= TMalList
);
187 function vector(Args
: TMalArray
) : TMal
;
189 vector
:= TMalVector
.Create(Args
);
191 function vector_Q(Args
: TMalArray
) : TMal
;
193 vector_Q
:= wrap_tf(Args
[0].ClassType
= TMalVector
);
195 function hash_map(Args
: TMalArray
) : TMal
;
197 hash_map
:= TMalHashMap
.Create(Args
);
199 function map_Q(Args
: TMalArray
) : TMal
;
201 map_Q
:= wrap_tf(Args
[0].ClassType
= TMalHashMap
);
203 function assoc(Args
: TMalArray
) : TMal
;
205 OrigHM
, NewHM
: TMalHashMap
;
207 OrigHM
:= (Args
[0] as TMalHashMap
);
208 NewHM
:= TMalHashMap
.Clone(OrigHM
);
209 assoc
:= NewHM
.assoc_BANG(copy(Args
, 1, Length(Args
)));
211 function dissoc(Args
: TMalArray
) : TMal
;
213 OrigHM
, NewHM
: TMalHashMap
;
215 OrigHM
:= (Args
[0] as TMalHashMap
);
216 NewHM
:= TMalHashMap
.Clone(OrigHM
);
217 dissoc
:= NewHM
.dissoc_BANG(copy(Args
, 1, Length(Args
)));
219 function get(Args
: TMalArray
) : TMal
;
223 if Args
[0] is TMalNil
then Exit(TMalNil
.Create
);
224 HM
:= (Args
[0] as TMalHashMap
);
225 if HM
.Val
.IndexOf((Args
[1] as TMalString
).Val
) >= 0 then
226 get
:= HM
.Val
[(Args
[1] as TMalString
).Val
]
228 get
:= TMalNil
.Create
;
230 function contains_Q(Args
: TMalArray
) : TMal
;
234 if Args
[0] is TMalNil
then Exit(TMalFalse
.Create
);
235 HM
:= (Args
[0] as TMalHashMap
);
236 contains_Q
:= wrap_tf(HM
.Val
.IndexOf((Args
[1] as TMalString
).Val
) >= 0);
238 function keys(Args
: TMalArray
) : TMal
;
244 Dict
:= (Args
[0] as TMalHashMap
).Val
;
245 SetLength(Arr
, Dict
.Count
);
246 for I
:= 0 to Dict
.Count
-1 do
247 Arr
[I
] := TMalString
.Create(Dict
.Keys
[I
]);
248 keys
:= TMalList
.Create(Arr
);
250 function vals(Args
: TMalArray
) : TMal
;
256 Dict
:= (Args
[0] as TMalHashMap
).Val
;
257 SetLength(Arr
, Dict
.Count
);
258 for I
:= 0 to Dict
.Count
-1 do
259 Arr
[I
] := Dict
[Dict
.Keys
[I
]];
260 vals
:= TMalList
.Create(Arr
);
264 // Sequence functions
266 function sequential_Q(Args
: TMalArray
) : TMal
;
268 sequential_Q
:= wrap_tf(_sequential_Q(Args
[0]));
270 function cons(Args
: TMalArray
) : TMal
;
272 Res
, Src
: TMalArray
;
275 Src
:= (Args
[1] as TMalList
).Val
;
276 SetLength(Res
, 1 + Length(Src
));
278 for I
:= 1 to Length(Src
) do
280 cons
:= TMalList
.Create(Res
);
282 function do_concat(Args
: TMalArray
) : TMal
;
288 for I
:= 0 to Length(Args
)-1 do
290 Res
:= _concat(Res
, (Args
[I
] as TMalList
).Val
);
292 do_concat
:= TMalList
.Create(Res
);
294 function nth(Args
: TMalArray
) : TMal
;
299 Arr
:= (Args
[0] as TMalList
).Val
;
300 Idx
:= (Args
[1] as TMalInt
).Val
;
301 if Idx
>= Length(Arr
) then
302 raise Exception
.Create('nth: index out of range')
306 function first(Args
: TMalArray
) : TMal
;
310 if Args
[0] is TMalNil
then Exit(TMalNil
.Create
);
311 Arr
:= (Args
[0] as TMalList
).Val
;
312 if Length(Arr
) = 0 then
313 first
:= TMalNil
.Create
315 first
:= (Args
[0] as TMalList
).Val
[0];
317 function rest(Args
: TMalArray
) : TMal
;
319 if Args
[0] is TMalNil
then Exit(_list());
320 rest
:= (Args
[0] as TMalList
).Rest();
323 function empty_Q(Args
: TMalArray
) : TMal
;
325 if Args
[0] is TMalNil
then
326 empty_Q
:= TMalTrue
.Create
327 else if Args
[0] is TMalList
then
328 empty_Q
:= wrap_tf(Length((Args
[0] as TMalList
).Val
) = 0)
329 else raise Exception
.Create('invalid empty? call');
331 function count(Args
: TMalArray
) : TMal
;
333 if Args
[0] is TMalNil
then
334 count
:= TMalInt
.Create(0)
335 else if Args
[0] is TMalList
then
336 count
:= TMalInt
.Create(Length((Args
[0] as TMalList
).Val
))
337 else raise Exception
.Create('invalid count call');
340 function map(Args
: TMalArray
) : TMal
;
344 Src
, Res
: TMalArray
;
347 Fn
:= (Args
[0] as TMalFunc
);
348 Src
:= (Args
[1] as TMalList
).Val
;
350 SetLength(Res
, Length(Src
));
352 for I
:= 0 to Length(Src
)-1 do
355 Res
[I
] := Fn
.Val(FArgs
);
358 for I
:= 0 to Length(Src
)-1 do
361 Res
[I
] := EVAL(Fn
.Ast
, TEnv
.Create(Fn
.Env
, Fn
.Params
, FArgs
));
363 map
:= TMalList
.Create(Res
);
365 function apply(Args
: TMalArray
) : TMal
;
368 LastArgs
: TMalArray
;
372 Fn
:= (Args
[0] as TMalFunc
);
373 LastArgs
:= (Args
[Length(Args
)-1] as TMalList
).Val
;
374 SetLength(FArgs
, Length(LastArgs
) + Length(Args
) - 2);
375 for I
:= 0 to Length(Args
)-3 do
376 FArgs
[I
] := Args
[I
+1];
377 for I
:= 0 to Length(LastArgs
)-1 do
378 FArgs
[Length(Args
)-2 + I
] := LastArgs
[I
];
380 apply
:= Fn
.Val(FArgs
)
382 apply
:= EVAL(Fn
.Ast
, TEnv
.Create(Fn
.Env
, Fn
.Params
, FArgs
));
385 function conj(Args
: TMalArray
) : TMal
;
390 if Args
[0] is TMalVector
then
391 conj
:= TMalVector
.Create(_concat((Args
[0] as TMalList
).Val
,
392 copy(Args
, 1, Length(Args
))))
393 else if Args
[0] is TMalList
then
395 SetLength(Vals
, Length(Args
)-1);
396 for I
:= 1 to Length(Args
)-1 do
397 Vals
[I
-1] := Args
[Length(Args
) - I
];
398 conj
:= TMalList
.Create(_concat(Vals
, (Args
[0] as TMalList
).Val
));
401 raise Exception
.Create('conj: called on non-sequence');
403 function seq(Args
: TMalArray
) : TMal
;
409 if Args
[0] is TMalVector
then
411 if Length((Args
[0] as TMalVector
).Val
) = 0 then
412 Exit(TMalNil
.Create
);
413 seq
:= TMalList
.Create((Args
[0] as TMalVector
).Val
);
415 else if Args
[0] is TMalList
then
417 if Length((Args
[0] as TMalList
).Val
) = 0 then
418 Exit(TMalNil
.Create
);
421 else if _string_Q(Args
[0]) then
423 Str
:= (Args
[0] as TMalString
).Val
;
424 if Length(Str
) = 0 then
425 Exit(TMalNil
.Create
);
426 SetLength(Arr
, Length(Str
));
427 for I
:= 0 to Length(Str
) do
428 Arr
[I
] := TMalString
.Create(Str
[I
+1]);
429 seq
:= TMalList
.Create(Arr
);
431 else if Args
[0] is TMalNil
then
436 raise Exception
.Create('seq: called on non-sequence');
440 // Metadata functions
442 function meta(Args
: TMalArray
) : TMal
;
444 if Args
[0] is TMalFunc
then
445 meta
:= (Args
[0] as TMalFunc
).Meta
446 else if Args
[0] is TMalList
then
447 meta
:= (Args
[0] as TMalList
).Meta
448 else if Args
[0] is TMalHashMap
then
449 meta
:= (Args
[0] as TMalHashMap
).Meta
451 raise Exception
.Create('meta not supported on ' + Args
[0].ClassName
);
454 meta
:= TMalNil
.Create
;
456 function with_meta(Args
: TMalArray
) : TMal
;
463 if Args
[0] is TMalFunc
then
465 Fn
:= TMalFunc
.Clone(Args
[0] as TMalFunc
);
469 else if Args
[0] is TMalVector
then
471 Vec
:= TMalVector
.Clone(Args
[0] as TMalVector
);
475 else if Args
[0] is TMalList
then
477 Lst
:= TMalList
.Clone(Args
[0] as TMalList
);
481 else if Args
[0] is TMalHashMap
then
483 HM
:= TMalHashMap
.Clone(Args
[0] as TMalHashMap
);
488 raise Exception
.Create('with-meta call on non-mal function');
493 function atom(Args
: TMalArray
) : TMal
;
495 atom
:= TMalAtom
.Create(Args
[0]);
497 function atom_Q(Args
: TMalArray
) : TMal
;
499 atom_Q
:= wrap_tf(Args
[0] is TMalAtom
);
501 function deref(Args
: TMalArray
) : TMal
;
503 deref
:= (Args
[0] as TMalAtom
).Val
;
505 function reset_BANG(Args
: TMalArray
) : TMal
;
507 (Args
[0] as TMalAtom
).Val
:= Args
[1];
508 reset_BANG
:= Args
[1];
511 function swap_BANG(Args
: TMalArray
) : TMal
;
518 Atm
:= (Args
[0] as TMalAtom
);
519 Fn
:= (Args
[1] as TMalFunc
);
520 SetLength(FArgs
, Length(Args
)-1);
522 for I
:= 1 to Length(Args
)-2 do
523 FArgs
[I
] := Args
[I
+1];
526 Atm
.Val
:= Fn
.Val(FArgs
)
528 Atm
.Val
:= EVAL(Fn
.Ast
, TEnv
.Create(Fn
.Env
, Fn
.Params
, FArgs
));
529 swap_BANG
:= Atm
.Val
;
533 ////////////////////////////////////////////////////////////
537 NS
:= TCoreDict
.Create
;
539 NS
['throw'] := @throw
;
541 NS
['nil?'] := @nil_Q
;
542 NS
['true?'] := @true_Q
;
543 NS
['false?'] := @false_Q
;
544 NS
['string?'] := @string_Q
;
545 NS
['symbol'] := @symbol
;
546 NS
['symbol?'] := @symbol_Q
;
547 NS
['keyword'] := @keyword
;
548 NS
['keyword?'] := @keyword_Q
;
550 NS
['pr-str'] := @do_pr_str
;
553 NS
['println'] := @println
;
554 NS
['read-string'] := @read_string
;
555 NS
['readline'] := @do_readline
;
556 NS
['slurp'] := @slurp
;
563 NS
['-'] := @subtract
;
564 NS
['*'] := @multiply
;
566 NS
['time-ms'] := @time_ms
;
569 NS
['list?'] := @list_Q
;
570 NS
['vector'] := @vector
;
571 NS
['vector?'] := @vector_Q
;
572 NS
['hash-map'] := @hash_map
;
573 NS
['map?'] := @map_Q
;
574 NS
['assoc'] := @assoc
;
575 NS
['dissoc'] := @dissoc
;
577 NS
['contains?'] := @contains_Q
;
581 NS
['sequential?'] := @sequential_Q
;
583 NS
['concat'] := @do_concat
;
585 NS
['first'] := @first
;
587 NS
['empty?'] := @empty_Q
;
588 NS
['count'] := @count
;
589 NS
['apply'] := @apply
;
596 NS
['with-meta'] := @with_meta
;
598 NS
['atom?'] := @atom_Q
;
599 NS
['deref'] := @deref
;
600 NS
['reset!'] := @reset_BANG
;
601 NS
['swap!'] := @swap_BANG
;