Merge pull request #345 from asarhaddon/ada.2
[jackhill/mal.git] / objpascal / core.pas
CommitLineData
0067158f
JM
1unit core;
2
3{$H+} // Use AnsiString
4
5interface
6
7uses Classes,
8 sysutils,
9 fgl,
bc6a1f15 10 mal_readline,
0067158f
JM
11 mal_types,
12 mal_func,
13 mal_env,
14 reader,
15 printer;
16
17type
18 TCoreDict = specialize TFPGMap<string,TMalCallable>;
19
20var
21 EVAL : function (A: TMal; E: TEnv) : TMal;
22 NS : TCoreDict;
23
24////////////////////////////////////////////////////////////
25
26implementation
27
28// General functions
29
30function equal_Q(Args: TMalArray) : TMal;
31begin
32 equal_Q := wrap_tf(_equal_Q(Args[0], Args[1]));
33end;
34
35function throw(Args: TMalArray) : TMal;
36begin
37 raise TMalException.Create(Args[0]);
38 throw := TMalNil.Create; // Not reached
39end;
40
41// Scalar functions
42
43function nil_Q(Args: TMalArray) : TMal;
44begin
45 nil_Q := wrap_tf(Args[0] is TMalNil);
46end;
47function true_Q(Args: TMalArray) : TMal;
48begin
49 true_Q := wrap_tf(Args[0] is TMalTrue);
50end;
51function false_Q(Args: TMalArray) : TMal;
52begin
53 false_Q := wrap_tf(Args[0] is TMalFalse);
54end;
dcd79884
VS
55function number_Q(Args: TMalArray) : TMal;
56begin
57 number_Q := wrap_tf(Args[0] is TMalInt);
58end;
0067158f
JM
59function string_Q(Args: TMalArray) : TMal;
60begin
61 string_Q := wrap_tf(_string_Q(Args[0]));
62end;
63function symbol(Args: TMalArray) : TMal;
64begin
65 if Args[0] is TMalSymbol then
66 symbol := Args[0]
67 else if Args[0] is TMalString then
68 symbol := TMalSymbol.Create((Args[0] as TMalString).Val)
69 else
70 raise Exception.Create('Invalid symbol call');
71end;
72function symbol_Q(Args: TMalArray) : TMal;
73begin
74 symbol_Q := wrap_tf(Args[0] is TMalSymbol);
75end;
76function keyword(Args: TMalArray) : TMal;
77begin
78 if ((Args[0] is TMalString) and not _string_Q(Args[0])) then
79 keyword := Args[0]
80 else if Args[0] is TMalString then
81 keyword := TMalString.Create(#127 + (Args[0] as TMalString).Val)
82 else
83 raise Exception.Create('Invalid keyword call');
84end;
85function keyword_Q(Args: TMalArray) : TMal;
86begin
87 keyword_Q := wrap_tf((Args[0] is TMalString) and not _string_Q(Args[0]));
88end;
dcd79884
VS
89function fn_Q(Args: TMalArray) : TMal;
90begin
91 if Args[0] is TMalFunc then
92 fn_Q := wrap_tf(not (Args[0] as TMalFunc).isMacro)
93 else
94 fn_Q := TMalFalse.Create;
95end;
96
97function macro_Q(Args: TMalArray) : TMal;
98begin
99 if Args[0] is TMalFunc then
100 macro_Q := wrap_tf((Args[0] as TMalFunc).isMacro)
101 else
102 macro_Q := TMalFalse.Create;
103end;
104
0067158f
JM
105
106// String functions
107
108function do_pr_str(Args: TMalArray) : TMal;
109begin
110 do_pr_str := TMalString.Create(pr_str_array(Args, true, ' '));
111end;
112function str(Args: TMalArray) : TMal;
113begin
114 str := TMalString.Create(pr_str_array(Args, false, ''));
115end;
116function prn(Args: TMalArray) : TMal;
117begin
118 WriteLn(pr_str_array(Args, true, ' '));
119 prn := TMalNil.Create;
120end;
121function println(Args: TMalArray) : TMal;
122begin
123 WriteLn(pr_str_array(Args, false, ' '));
124 println := TMalNil.Create;
125end;
126
127function read_string(Args: TMalArray) : TMal;
128begin
129 read_string := read_str((Args[0] as TMalString).Val);
130end;
131function do_readline(Args: TMalArray) : TMal;
132var
bc6a1f15
JM
133 Prompt : string;
134 Line : string;
0067158f 135begin
bc6a1f15
JM
136 Prompt := (Args[0] as TMalString).Val;
137 try
138 Line := _readline(Prompt);
0067158f 139 do_readline := TMalString.Create(Line);
bc6a1f15
JM
140 except
141 On E : MalEOF do do_readline := TMalNil.Create;
142 end;
0067158f
JM
143end;
144function slurp(Args: TMalArray) : TMal;
145var
146 StrL : TStringList;
147begin
148 StrL := TStringList.Create;
149 StrL.LoadFromFile((Args[0] as TMalString).Val);
150 slurp := TMalString.Create(StrL.Text);
151end;
152
153// Math functions
154
155function lt(Args: TMalArray) : TMal;
156begin
157 lt := wrap_tf((Args[0] as TMalInt).Val < (Args[1] as TMalInt).Val);
158end;
159function lte(Args: TMalArray) : TMal;
160begin
161 lte := wrap_tf((Args[0] as TMalInt).Val <= (Args[1] as TMalInt).Val);
162end;
163function gt(Args: TMalArray) : TMal;
164begin
165 gt := wrap_tf((Args[0] as TMalInt).Val > (Args[1] as TMalInt).Val);
166end;
167function gte(Args: TMalArray) : TMal;
168begin
169 gte := wrap_tf((Args[0] as TMalInt).Val >= (Args[1] as TMalInt).Val);
170end;
171
172function add(Args: TMalArray) : TMal;
173begin
174 add := TMalInt.Create((Args[0] as TMalInt).Val +
175 (Args[1] as TMalInt).Val);
176end;
177function subtract(Args: TMalArray) : TMal;
178begin
179 subtract := TMalInt.Create((Args[0] as TMalInt).Val -
180 (Args[1] as TMalInt).Val);
181end;
182function multiply(Args: TMalArray) : TMal;
183begin
184 multiply := TMalInt.Create((Args[0] as TMalInt).Val *
185 (Args[1] as TMalInt).Val);
186end;
187function divide(Args: TMalArray) : TMal;
188begin
189 divide := TMalInt.Create((Args[0] as TMalInt).Val div
190 (Args[1] as TMalInt).Val);
191end;
192function time_ms(Args: TMalArray) : TMal;
193begin
194 time_ms := TMalInt.Create(Trunc(TimeStampToMSecs(DateTimeToTimeStamp(Now))));
195end;
196
197// Collection functions
198
199function list(Args: TMalArray) : TMal;
200begin
201 list := TMalList.Create(Args);
202end;
203function list_Q(Args: TMalArray) : TMal;
204begin
205 list_Q := wrap_tf(Args[0].ClassType = TMalList);
206end;
207function vector(Args: TMalArray) : TMal;
208begin
209 vector := TMalVector.Create(Args);
210end;
211function vector_Q(Args: TMalArray) : TMal;
212begin
213 vector_Q := wrap_tf(Args[0].ClassType = TMalVector);
214end;
215function hash_map(Args: TMalArray) : TMal;
216begin
217 hash_map := TMalHashMap.Create(Args);
218end;
219function map_Q(Args: TMalArray) : TMal;
220begin
221 map_Q := wrap_tf(Args[0].ClassType = TMalHashMap);
222end;
223function assoc(Args: TMalArray) : TMal;
224var
225 OrigHM, NewHM : TMalHashMap;
226begin
227 OrigHM := (Args[0] as TMalHashMap);
228 NewHM := TMalHashMap.Clone(OrigHM);
229 assoc := NewHM.assoc_BANG(copy(Args, 1, Length(Args)));
230end;
231function dissoc(Args: TMalArray) : TMal;
232var
233 OrigHM, NewHM : TMalHashMap;
234begin
235 OrigHM := (Args[0] as TMalHashMap);
236 NewHM := TMalHashMap.Clone(OrigHM);
237 dissoc := NewHM.dissoc_BANG(copy(Args, 1, Length(Args)));
238end;
239function get(Args: TMalArray) : TMal;
240var
241 HM : TMalHashMap;
242begin
243 if Args[0] is TMalNil then Exit(TMalNil.Create);
244 HM := (Args[0] as TMalHashMap);
245 if HM.Val.IndexOf((Args[1] as TMalString).Val) >= 0 then
246 get := HM.Val[(Args[1] as TMalString).Val]
247 else
248 get := TMalNil.Create;
249end;
250function contains_Q(Args: TMalArray) : TMal;
251var
252 HM : TMalHashMap;
253begin
254 if Args[0] is TMalNil then Exit(TMalFalse.Create);
255 HM := (Args[0] as TMalHashMap);
256 contains_Q := wrap_tf(HM.Val.IndexOf((Args[1] as TMalString).Val) >= 0);
257end;
258function keys(Args: TMalArray) : TMal;
259var
260 Dict : TMalDict;
261 Arr : TMalArray;
262 I : longint;
263begin
264 Dict := (Args[0] as TMalHashMap).Val;
265 SetLength(Arr, Dict.Count);
266 for I := 0 to Dict.Count-1 do
267 Arr[I] := TMalString.Create(Dict.Keys[I]);
268 keys := TMalList.Create(Arr);
269end;
270function vals(Args: TMalArray) : TMal;
271var
272 Dict : TMalDict;
273 Arr : TMalArray;
274 I : longint;
275begin
276 Dict := (Args[0] as TMalHashMap).Val;
277 SetLength(Arr, Dict.Count);
278 for I := 0 to Dict.Count-1 do
279 Arr[I] := Dict[Dict.Keys[I]];
280 vals := TMalList.Create(Arr);
281end;
282
283
284// Sequence functions
285
286function sequential_Q(Args: TMalArray) : TMal;
287begin
288 sequential_Q := wrap_tf(_sequential_Q(Args[0]));
289end;
290function cons(Args: TMalArray) : TMal;
291var
292 Res, Src : TMalArray;
293 I : longint;
294begin
295 Src := (Args[1] as TMalList).Val;
296 SetLength(Res, 1 + Length(Src));
297 Res[0] := Args[0];
298 for I := 1 to Length(Src) do
299 Res[I] := Src[I-1];
300 cons := TMalList.Create(Res);
301end;
302function do_concat(Args: TMalArray) : TMal;
303var
304 Res : TMalArray;
305 I : longint;
306begin
307 SetLength(Res, 0);
308 for I := 0 to Length(Args)-1 do
309 begin
310 Res := _concat(Res, (Args[I] as TMalList).Val);
311 end;
312 do_concat := TMalList.Create(Res);
313end;
314function nth(Args: TMalArray) : TMal;
315var
316 Arr : TMalArray;
317 Idx : longint;
318begin
319 Arr := (Args[0] as TMalList).Val;
320 Idx := (Args[1] as TMalInt).Val;
321 if Idx >= Length(Arr) then
322 raise Exception.Create('nth: index out of range')
323 else
324 nth := Arr[Idx];
325end;
326function first(Args: TMalArray) : TMal;
327var
328 Arr : TMalArray;
329begin
330 if Args[0] is TMalNil then Exit(TMalNil.Create);
331 Arr := (Args[0] as TMalList).Val;
332 if Length(Arr) = 0 then
333 first := TMalNil.Create
334 else
335 first := (Args[0] as TMalList).Val[0];
336end;
337function rest(Args: TMalArray) : TMal;
338begin
339 if Args[0] is TMalNil then Exit(_list());
340 rest := (Args[0] as TMalList).Rest();
341end;
342
343function empty_Q(Args: TMalArray) : TMal;
344begin
345 if Args[0] is TMalNil then
346 empty_Q := TMalTrue.Create
347 else if Args[0] is TMalList then
348 empty_Q := wrap_tf(Length((Args[0] as TMalList).Val) = 0)
349 else raise Exception.Create('invalid empty? call');
350end;
351function count(Args: TMalArray) : TMal;
352begin
353 if Args[0] is TMalNil then
354 count := TMalInt.Create(0)
355 else if Args[0] is TMalList then
356 count := TMalInt.Create(Length((Args[0] as TMalList).Val))
357 else raise Exception.Create('invalid count call');
358end;
359
360function map(Args: TMalArray) : TMal;
361var
362 Fn : TMalFunc;
363 FArgs : TMalArray;
364 Src, Res : TMalArray;
365 I : longint;
366begin
367 Fn := (Args[0] as TMalFunc);
368 Src := (Args[1] as TMalList).Val;
369 SetLength(FArgs, 1);
370 SetLength(Res, Length(Src));
371 if Fn.Ast = nil then
372 for I := 0 to Length(Src)-1 do
373 begin
374 FArgs[0] := Src[I];
375 Res[I] := Fn.Val(FArgs);
376 end
377 else
378 for I := 0 to Length(Src)-1 do
379 begin
380 FArgs[0] := Src[I];
381 Res[I] := EVAL(Fn.Ast, TEnv.Create(Fn.Env, Fn.Params, FArgs));
382 end;
383 map := TMalList.Create(Res);
384end;
385function apply(Args: TMalArray) : TMal;
386var
387 Fn : TMalFunc;
388 LastArgs : TMalArray;
389 FArgs : TMalArray;
390 I : longint;
391begin
392 Fn := (Args[0] as TMalFunc);
393 LastArgs := (Args[Length(Args)-1] as TMalList).Val;
394 SetLength(FArgs, Length(LastArgs) + Length(Args) - 2);
395 for I := 0 to Length(Args)-3 do
396 FArgs[I] := Args[I+1];
397 for I := 0 to Length(LastArgs)-1 do
398 FArgs[Length(Args)-2 + I] := LastArgs[I];
399 if Fn.Ast = nil then
400 apply := Fn.Val(FArgs)
401 else
402 apply := EVAL(Fn.Ast, TEnv.Create(Fn.Env, Fn.Params, FArgs));
403end;
404
405function conj(Args: TMalArray) : TMal;
406var
407 I : longint;
408 Vals : TMalArray;
409begin
410 if Args[0] is TMalVector then
411 conj := TMalVector.Create(_concat((Args[0] as TMalList).Val,
412 copy(Args, 1, Length(Args))))
413 else if Args[0] is TMalList then
414 begin
415 SetLength(Vals, Length(Args)-1);
416 for I := 1 to Length(Args)-1 do
417 Vals[I-1] := Args[Length(Args) - I];
418 conj := TMalList.Create(_concat(Vals, (Args[0] as TMalList).Val));
419 end
420 else
421 raise Exception.Create('conj: called on non-sequence');
422end;
423function seq(Args: TMalArray) : TMal;
424var
425 Str : string;
426 Arr : TMalArray;
427 I : longint;
428begin
429 if Args[0] is TMalVector then
430 begin
431 if Length((Args[0] as TMalVector).Val) = 0 then
432 Exit(TMalNil.Create);
433 seq := TMalList.Create((Args[0] as TMalVector).Val);
434 end
435 else if Args[0] is TMalList then
436 begin
437 if Length((Args[0] as TMalList).Val) = 0 then
438 Exit(TMalNil.Create);
439 seq := Args[0]
440 end
441 else if _string_Q(Args[0]) then
442 begin
443 Str := (Args[0] as TMalString).Val;
444 if Length(Str) = 0 then
445 Exit(TMalNil.Create);
446 SetLength(Arr, Length(Str));
447 for I := 0 to Length(Str) do
448 Arr[I] := TMalString.Create(Str[I+1]);
449 seq := TMalList.Create(Arr);
450 end
451 else if Args[0] is TMalNil then
452 begin
453 seq := Args[0];
454 end
455 else
456 raise Exception.Create('seq: called on non-sequence');
457end;
458
459
460// Metadata functions
461
462function meta(Args: TMalArray) : TMal;
463begin
464 if Args[0] is TMalFunc then
465 meta := (Args[0] as TMalFunc).Meta
466 else if Args[0] is TMalList then
467 meta := (Args[0] as TMalList).Meta
468 else if Args[0] is TMalHashMap then
469 meta := (Args[0] as TMalHashMap).Meta
470 else
471 raise Exception.Create('meta not supported on ' + Args[0].ClassName);
472
473 if meta = nil then
474 meta := TMalNil.Create;
475end;
476function with_meta(Args: TMalArray) : TMal;
477var
478 Fn : TMalFunc;
479 Vec : TMalVector;
480 Lst : TMalList;
481 HM : TMalHashMap;
482begin
483 if Args[0] is TMalFunc then
484 begin
485 Fn := TMalFunc.Clone(Args[0] as TMalFunc);
486 Fn.Meta := Args[1];
487 with_meta := Fn;
488 end
489 else if Args[0] is TMalVector then
490 begin
491 Vec := TMalVector.Clone(Args[0] as TMalVector);
492 Vec.Meta := Args[1];
493 with_meta := Vec;
494 end
495 else if Args[0] is TMalList then
496 begin
497 Lst := TMalList.Clone(Args[0] as TMalList);
498 Lst.Meta := Args[1];
499 with_meta := Lst;
500 end
501 else if Args[0] is TMalHashMap then
502 begin
503 HM := TMalHashMap.Clone(Args[0] as TMalHashMap);
504 HM.Meta := Args[1];
505 with_meta := HM;
506 end
507 else
508 raise Exception.Create('with-meta call on non-mal function');
509end;
510
511// Atom functions
512
513function atom(Args: TMalArray) : TMal;
514begin
515 atom := TMalAtom.Create(Args[0]);
516end;
517function atom_Q(Args: TMalArray) : TMal;
518begin
519 atom_Q := wrap_tf(Args[0] is TMalAtom);
520end;
521function deref(Args: TMalArray) : TMal;
522begin
523 deref := (Args[0] as TMalAtom).Val;
524end;
525function reset_BANG(Args: TMalArray) : TMal;
526begin
527 (Args[0] as TMalAtom).Val := Args[1];
528 reset_BANG := Args[1];
529end;
530
531function swap_BANG(Args: TMalArray) : TMal;
532var
533 Atm : TMalAtom;
534 Fn : TMalFunc;
535 FArgs : TMalArray;
536 I : longint;
537begin
538 Atm := (Args[0] as TMalAtom);
539 Fn := (Args[1] as TMalFunc);
540 SetLength(FArgs, Length(Args)-1);
541 FArgs[0] := Atm.Val;
542 for I := 1 to Length(Args)-2 do
543 FArgs[I] := Args[I+1];
544
545 if Fn.Ast = nil then
546 Atm.Val := Fn.Val(FArgs)
547 else
548 Atm.Val := EVAL(Fn.Ast, TEnv.Create(Fn.Env, Fn.Params, FArgs));
549 swap_BANG := Atm.Val;
550end;
551
552
553////////////////////////////////////////////////////////////
554
555initialization
556begin
557 NS := TCoreDict.Create;
558 NS['='] := @equal_Q;
559 NS['throw'] := @throw;
560
561 NS['nil?'] := @nil_Q;
562 NS['true?'] := @true_Q;
563 NS['false?'] := @false_Q;
dcd79884 564 NS['number?'] := @number_Q;
0067158f
JM
565 NS['string?'] := @string_Q;
566 NS['symbol'] := @symbol;
567 NS['symbol?'] := @symbol_Q;
568 NS['keyword'] := @keyword;
569 NS['keyword?'] := @keyword_Q;
dcd79884
VS
570 NS['fn?'] := @fn_Q;
571 NS['macro?'] := @macro_Q;
0067158f
JM
572
573 NS['pr-str'] := @do_pr_str;
574 NS['str'] := @str;
575 NS['prn'] := @prn;
576 NS['println'] := @println;
577 NS['read-string'] := @read_string;
578 NS['readline'] := @do_readline;
579 NS['slurp'] := @slurp;
580
581 NS['<'] := @lt;
582 NS['<='] := @lte;
583 NS['>'] := @gt;
584 NS['>='] := @gte;
585 NS['+'] := @add;
586 NS['-'] := @subtract;
587 NS['*'] := @multiply;
588 NS['/'] := @divide;
589 NS['time-ms'] := @time_ms;
590
591 NS['list'] := @list;
592 NS['list?'] := @list_Q;
593 NS['vector'] := @vector;
594 NS['vector?'] := @vector_Q;
595 NS['hash-map'] := @hash_map;
596 NS['map?'] := @map_Q;
597 NS['assoc'] := @assoc;
598 NS['dissoc'] := @dissoc;
599 NS['get'] := @get;
600 NS['contains?'] := @contains_Q;
601 NS['keys'] := @keys;
602 NS['vals'] := @vals;
603
604 NS['sequential?'] := @sequential_Q;
605 NS['cons'] := @cons;
606 NS['concat'] := @do_concat;
607 NS['nth'] := @nth;
608 NS['first'] := @first;
609 NS['rest'] := @rest;
610 NS['empty?'] := @empty_Q;
611 NS['count'] := @count;
612 NS['apply'] := @apply;
613 NS['map'] := @map;
614
615 NS['conj'] := @conj;
616 NS['seq'] := @seq;
617
618 NS['meta'] := @meta;
619 NS['with-meta'] := @with_meta;
620 NS['atom'] := @atom;
621 NS['atom?'] := @atom_Q;
622 NS['deref'] := @deref;
623 NS['reset!'] := @reset_BANG;
624 NS['swap!'] := @swap_BANG;
625end
626
627end.