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
;
84 if Ast
.ClassType
<> TMalList
then
85 Exit(eval_ast(Ast
, Env
));
88 Lst
:= (Ast
as TMalList
);
90 if Length(Arr
) = 0 then
92 if Arr
[0] is TMalSymbol
then
93 A0Sym
:= (Arr
[0] as TMalSymbol
).Val
95 A0Sym
:= '__<*fn*>__';
99 EVAL
:= Env
.Add((Arr
[1] as TMalSymbol
), EVAL(Arr
[2], ENV
));
102 LetEnv
:= TEnv
.Create(Env
);
103 Arr1
:= (Arr
[1] as TMalList
).Val
;
105 while I
< Length(Arr1
) do
107 LetEnv
.Add((Arr1
[I
] as TMalSymbol
), EVAL(Arr1
[I
+1], LetEnv
));
110 EVAL
:= EVAL(Arr
[2], LetEnv
);
114 Arr
:= (eval_ast(Lst
.Rest
, Env
) as TMalList
).Val
;
115 EVAL
:= Arr
[Length(Arr
)-1];
119 Cond
:= EVAL(Arr
[1], Env
);
120 if (Cond
is TMalNil
) or (Cond
is TMalFalse
) then
121 if Length(Arr
) > 3 then
122 EVAL
:= EVAL(Arr
[3], Env
)
124 EVAL
:= TMalNil
.Create
126 EVAL
:= EVAL(Arr
[2], Env
);
130 EVAL
:= TMalFunc
.Create(Arr
[2], Env
, (Arr
[1] as TMalList
))
134 Arr
:= (eval_ast(Ast
, Env
) as TMalList
).Val
;
135 if Arr
[0] is TMalFunc
then
137 Fn
:= Arr
[0] as TMalFunc
;
138 if Length(Arr
) < 2 then
141 Args
:= copy(Arr
, 1, Length(Arr
)-1);
146 FnEnv
:= TEnv
.Create(Fn
.Env
, Fn
.Params
, Args
);
147 EVAL
:= EVAL(Fn
.Ast
, FnEnv
);
152 raise Exception
.Create('invalid apply');
158 function PRINT(Exp
: TMal
) : string;
160 PRINT
:= pr_str(Exp
, True);
164 function REP(Str
: string) : string;
166 REP
:= PRINT(EVAL(READ(Str
), Repl_Env
));
170 Repl_Env
:= TEnv
.Create
;
172 // core.pas: defined using Pascal
173 for I
:= 0 to core
.NS
.Count
-1 do
175 Key
:= core
.NS
.Keys
[I
];
176 Repl_Env
.Add(TMalSymbol
.Create(Key
),
177 TMalFunc
.Create(core
.NS
[Key
]));
180 // core.mal: defined using language itself
181 REP('(def! not (fn* (a) (if a false true)))');
186 Line
:= _readline('user> ');
187 if Line
= '' then continue
;
190 On E
: MalEOF
do Halt(0);
193 WriteLn('Error: ' + E
.message);
194 WriteLn('Backtrace:');
195 WriteLn(GetBacktrace(E
));