3 {$H+} // Use AnsiString
10 // Ancestor of all Mal types
12 type TMal
= class(TObject
);
15 // Some general type definitions
18 TMalArray
= array of TMal
;
19 // TODO: use http://bugs.freepascal.org/view.php?id=27206 when
20 // incorporated into FPC
21 TMalDict
= specialize TFPGMap
<string,TMal
>;
23 type TMalException
= class(Exception
)
27 constructor Create(V
: TMal
);
33 type TMalNil
= class(TMal
);
34 type TMalTrue
= class(TMal
);
35 type TMalFalse
= class(TMal
);
37 type TMalInt
= class(TMal
)
41 constructor Create(V
: int64);
44 type TMalString
= class(TMal
)
48 constructor Create(V
: string);
51 type TMalSymbol
= class(TMal
)
55 constructor Create(V
: string);
59 type TMalList
= class(TMal
)
65 constructor Create(V
: TMalArray
);
66 function Rest() : TMalList
;
68 constructor Clone(L
: TMalList
);
71 type TMalVector
= class(TMalList
)
74 type TMalAtom
= class(TMal
)
78 constructor Create(V
: TMal
);
81 type TMalHashMap
= class(TMal
)
87 constructor Create(V
: TMalDict
);
88 constructor Create(V
: TMalArray
);
90 constructor Clone(HM
: TMalHashMap
);
92 function assoc_BANG(KVs
: TMalArray
) : TMal
;
93 function dissoc_BANG(Ks
: TMalArray
) : TMal
;
97 // General type functions
99 function GetBacktrace(E
: Exception
) : string;
101 function wrap_tf(x
: Boolean) : TMal
;
103 function _equal_Q(A
: TMal
; B
: TMal
) : Boolean;
105 function _sequential_Q(Obj
: TMal
) : Boolean;
107 function _list() : TMalList
;
108 function _list(A
: TMal
) : TMalList
;
109 function _list(A
: TMal
; B
: TMal
) : TMalList
;
110 function _list(A
: TMal
; B
: TMal
; C
: TMal
) : TMalList
;
112 function _concat(A
: TMalArray
; B
: TMalArray
) : TMalArray
;
114 function _string_Q(Obj
: TMal
) : Boolean;
116 ////////////////////////////////////////////////////////////
120 constructor TMalException
.Create(V
: TMal
);
122 inherited Create('MalException');
130 constructor TMalInt
.Create(V
: int64);
136 constructor TMalString
.Create(V
: string);
142 constructor TMalSymbol
.Create(V
: string);
148 constructor TMalList
.Create();
151 SetLength(Self
.Val
, 0);
154 constructor TMalList
.Create(V
: TMalArray
);
160 constructor TMalList
.Clone(L
: TMalList
);
163 Self
.Val
:= copy(L
.Val
, 0, Length(L
.Val
));
167 function TMalList
.Rest() : TMalList
;
169 if Length(Val
) <= 1 then
170 Rest
:= (_list() as TMalList
)
172 Rest
:= TMalList
.Create(copy(Val
, 1, Length(Val
)-1));
177 constructor TMalHashMap
.Create();
180 Self
.Val
:= TMalDict
.Create
;
183 constructor TMalHashMap
.Create(V
: TMalDict
);
189 function TMalHashMap
.assoc_BANG(KVs
: TMalArray
) : TMal
;
194 while I
< Length(KVs
) do
196 Self
.Val
[(KVs
[I
] as TMalString
).Val
] := KVs
[I
+1];
202 function TMalHashMap
.dissoc_BANG(Ks
: TMalArray
) : TMal
;
206 for I
:= 0 to Length(Ks
)-1 do
207 Self
.Val
.Remove((Ks
[I
] as TMalString
).Val
);
212 constructor TMalHashMap
.Create(V
: TMalArray
);
218 constructor TMalHashMap
.Clone(HM
: TMalHashMap
);
224 while I
< HM
.Val
.Count
do
226 Self
.Val
[HM
.Val
.Keys
[I
]] := HM
.Val
[HM
.Val
.Keys
[I
]];
234 constructor TMalAtom
.Create(V
: TMal
);
241 // General type functions
244 function GetBacktrace(E
: Exception
) : string;
249 GetBacktrace
:= BackTraceStrFunc(ExceptAddr
);
250 Frames
:= ExceptFrames
;
251 for I
:= 0 to ExceptFrameCount
- 1 do
252 GetBacktrace
:= GetBacktrace
+ #10 + BackTraceStrFunc(Frames
[I
]);
255 function wrap_tf(x
: Boolean) : TMal
;
257 if x
= true then wrap_tf
:= TMalTrue
.Create
258 else wrap_tf
:= TMalFalse
.Create
;
261 function _equal_Q(A
: TMal
; B
: TMal
) : Boolean;
264 ArrA
, ArrB
: TMalArray
;
265 DictA
, DictB
: TMalDict
;
268 if not ((A
.ClassType
= B
.ClassType
) or
269 ((A
is TMalList
) and (B
is TMalList
))) then
273 if A
is TMalList
then
275 ArrA
:= (A
as TMalList
).Val
;
276 ArrB
:= (B
as TMalList
).Val
;
277 if Length(ArrA
) <> Length(ArrB
) then
279 for I
:= 0 to Length(ArrA
)-1 do
280 if not _equal_Q(ArrA
[I
], ArrB
[I
]) then
284 else if A
is TMalHashMap
then
286 DictA
:= (A
as TMalHashMap
).Val
;
287 DictB
:= (B
as TMalHashMap
).Val
;
288 if DictA
.Count
<> DictB
.Count
then
290 for I
:= 0 to DictA
.Count
-1 do
292 Key
:= DictA
.Keys
[I
];
293 if DictB
.IndexOf(Key
) < 0 then
295 if not _equal_Q(DictA
[Key
], DictB
[Key
]) then
300 else if A
is TMalString
then
301 _equal_Q
:= (A
as TMalString
).Val
= (B
as TMalString
).Val
302 else if A
is TMalSymbol
then
303 _equal_Q
:= (A
as TMalSymbol
).Val
= (B
as TMalSymbol
).Val
304 else if A
is TMalInt
then
305 _equal_Q
:= (A
as TMalInt
).Val
= (B
as TMalInt
).Val
306 else if A
is TMalNil
then
307 _equal_Q
:= B
is TMalNil
308 else if A
is TMalTrue
then
309 _equal_Q
:= B
is TMalTrue
310 else if A
is TMalFalse
then
311 _equal_Q
:= B
is TMalFalse
317 function _sequential_Q(Obj
: TMal
) : Boolean;
319 _sequential_Q
:= Obj
is TMalList
;
323 function _list() : TMalList
;
328 _list
:= TMalList
.Create(Arr
);
331 function _list(A
: TMal
) : TMalList
;
337 _list
:= TMalList
.Create(Arr
);
340 function _list(A
: TMal
; B
: TMal
) : TMalList
;
347 _list
:= TMalList
.Create(Arr
);
350 function _list(A
: TMal
; B
: TMal
; C
: TMal
) : TMalList
;
358 _list
:= TMalList
.Create(Arr
);
361 function _concat(A
: TMalArray
; B
: TMalArray
) : TMalArray
;
366 SetLength(Res
, Length(A
) + Length(B
));
367 for I
:= 0 to Length(A
)-1 do
369 for I
:= 0 to Length(B
)-1 do
370 Res
[I
+Length(A
)] := B
[I
];
374 function _string_Q(Obj
: TMal
) : Boolean;
378 if (Obj
is TMalString
) then
380 Str
:= (Obj
as TMalString
).Val
;
381 _string_Q
:= (Length(Str
) = 0) or (Str
[1] <> #127)