3 {$H+} // Use AnsiString
23 function READ(const Str
: string) : TMal
;
25 READ
:= read_str(Str
);
29 // Forward declation since eval_ast call it
30 function EVAL(Ast
: TMal
; Env
: TEnv
) : TMal
; forward;
32 function eval_ast(Ast
: TMal
; Env
: TEnv
) : TMal
;
34 OldArr
, NewArr
: TMalArray
;
35 OldDict
, NewDict
: TMalDict
;
38 if Ast
is TMalSymbol
then
40 eval_ast
:= Env
.Get((Ast
as TMalSymbol
));
42 else if Ast
is TMalList
then
44 OldArr
:= (Ast
as TMalList
).Val
;
45 SetLength(NewArr
, Length(OldArr
));
46 for I
:= 0 to Length(OldArr
)-1 do
48 NewArr
[I
] := EVAL(OldArr
[I
], Env
);
50 if Ast
is TMalVector
then
51 eval_ast
:= TMalVector
.Create(NewArr
)
53 eval_ast
:= TMalList
.Create(NewArr
);
55 else if Ast
is TMalHashMap
then
57 OldDict
:= (Ast
as TMalHashMap
).Val
;
58 NewDict
:= TMalDict
.Create
;
60 while I
< OldDict
.Count
do
62 NewDict
[OldDict
.Keys
[I
]] := EVAL(OldDict
[OldDict
.Keys
[I
]], Env
);
65 eval_ast
:= TMalHashMap
.Create(NewDict
);
71 function EVAL(Ast
: TMal
; Env
: TEnv
) : TMal
;
85 if Ast
.ClassType
<> TMalList
then
86 Exit(eval_ast(Ast
, Env
));
89 Lst
:= (Ast
as TMalList
);
91 if Length(Arr
) = 0 then
93 if Arr
[0] is TMalSymbol
then
94 A0Sym
:= (Arr
[0] as TMalSymbol
).Val
96 A0Sym
:= '__<*fn*>__';
100 Exit(Env
.Add((Arr
[1] as TMalSymbol
), EVAL(Arr
[2], ENV
)));
103 LetEnv
:= TEnv
.Create(Env
);
104 Arr1
:= (Arr
[1] as TMalList
).Val
;
106 while I
< Length(Arr1
) do
108 LetEnv
.Add((Arr1
[I
] as TMalSymbol
), EVAL(Arr1
[I
+1], LetEnv
));
112 Ast
:= Arr
[2]; // TCO
116 eval_ast(TMalList
.Create(copy(Arr
,1, Length(Arr
)-2)), Env
);
117 Ast
:= Arr
[Length(Arr
)-1]; // TCO
121 Cond
:= EVAL(Arr
[1], Env
);
122 if (Cond
is TMalNil
) or (Cond
is TMalFalse
) then
123 if Length(Arr
) > 3 then
128 Ast
:= Arr
[2]; // TCO
132 Exit(TMalFunc
.Create(Arr
[2], Env
, (Arr
[1] as TMalList
)));
136 Arr
:= (eval_ast(Ast
, Env
) as TMalList
).Val
;
137 if Arr
[0] is TMalFunc
then
139 Fn
:= Arr
[0] as TMalFunc
;
140 if Length(Arr
) < 2 then
143 Args
:= copy(Arr
, 1, Length(Arr
)-1);
148 Env
:= TEnv
.Create(Fn
.Env
, Fn
.Params
, Args
);
149 Ast
:= Fn
.Ast
; // TCO
154 raise Exception
.Create('invalid apply');
161 function PRINT(Exp
: TMal
) : string;
163 PRINT
:= pr_str(Exp
, True);
167 function REP(Str
: string) : string;
169 REP
:= PRINT(EVAL(READ(Str
), Repl_Env
));
173 Repl_Env
:= TEnv
.Create
;
175 // core.pas: defined using Pascal
176 for I
:= 0 to core
.NS
.Count
-1 do
178 Key
:= core
.NS
.Keys
[I
];
179 Repl_Env
.Add(TMalSymbol
.Create(Key
),
180 TMalFunc
.Create(core
.NS
[Key
]));
183 // core.mal: defined using language itself
184 REP('(def! not (fn* (a) (if a false true)))');
189 Line
:= _readline('user> ');
190 if Line
= '' then continue
;
193 On E
: MalEOF
do Halt(0);
196 WriteLn('Error: ' + E
.message);
197 WriteLn('Backtrace:');
198 WriteLn(GetBacktrace(E
));