6 package body Evaluation
is
10 procedure Add_Defs
(Defs
: List_Mal_Type
; Env
: Envs
.Env_Handle
) is
14 Ada
.Text_IO
.Put_Line
("Add_Defs " & To_String
(Defs
));
17 while not Is_Null
(D
) loop
18 L
:= Deref_List
(Cdr
(D
)).all;
21 Deref_Atom
(Car
(D
)).Get_Atom
,
23 D
:= Deref_List
(Cdr
(L
)).all;
28 function Def_Fn
(Args
: List_Mal_Type
; Env
: Envs
.Env_Handle
)
30 Name
, Fn_Body
, Res
: Mal_Handle
;
33 pragma Assert
(Deref
(Name
).Sym_Type
= Atom
,
34 "Def_Fn: expected atom as name");
35 Fn_Body
:= Car
(Deref_List
(Cdr
(Args
)).all);
36 Res
:= Eval
(Fn_Body
, Env
);
37 Envs
.Set
(Envs
.Get_Current
, Deref_Atom
(Name
).Get_Atom
, Res
);
42 function Def_Macro
(Args
: List_Mal_Type
; Env
: Envs
.Env_Handle
)
44 Name
, Fn_Body
, Res
: Mal_Handle
;
45 Lambda_P
: Lambda_Ptr
;
48 pragma Assert
(Deref
(Name
).Sym_Type
= Atom
,
49 "Def_Macro: expected atom as name");
50 Fn_Body
:= Car
(Deref_List
(Cdr
(Args
)).all);
51 Res
:= Eval
(Fn_Body
, Env
);
52 Lambda_P
:= Deref_Lambda
(Res
);
53 Lambda_P
.Set_Is_Macro
(True);
54 Envs
.Set
(Envs
.Get_Current
, Deref_Atom
(Name
).Get_Atom
, Res
);
59 function Macro_Expand
(Ast
: Mal_Handle
; Env
: Envs
.Env_Handle
)
72 if Deref
(Res
).Sym_Type
/= List
then
76 LMT
:= Deref_List
(Res
).all;
78 -- Get the macro in the list from the env
79 -- or return null if not applicable.
80 LP
:= Get_Macro
(Res
, E
);
82 exit when LP
= null or else not LP
.Get_Is_Macro
;
85 Fn_List
: Mal_Handle
:= Cdr
(LMT
);
86 Params
: List_Mal_Type
;
88 E
:= Envs
.New_Env
(E
);
90 Params
:= Deref_List
(LP
.Get_Params
).all;
91 if Envs
.Bind
(E
, Params
, Deref_List
(Fn_List
).all) then
93 Res
:= Eval
(LP
.Get_Expr
, E
);
106 function Let_Processing
(Args
: List_Mal_Type
; Env
: Envs
.Env_Handle
)
108 Defs
, Expr
, Res
: Mal_Handle
;
111 E
:= Envs
.New_Env
(Env
);
113 Add_Defs
(Deref_List
(Defs
).all, E
);
114 Expr
:= Car
(Deref_List
(Cdr
(Args
)).all);
115 Res
:= Eval
(Expr
, E
);
120 function Eval_As_Boolean
(MH
: Mal_Handle
) return Boolean is
123 case Deref
(MH
).Sym_Type
is
125 Res
:= Deref_Bool
(MH
).Get_Bool
;
127 return not (Deref_Atom
(MH
).Get_Atom
= "nil");
130 -- L : List_Mal_Type;
132 -- L := Deref_List (MH).all;
133 -- Res := not Is_Null (L);
135 when others => -- Everything else
143 (Ast
: Mal_Handle
; Env
: Envs
.Env_Handle
)
146 function Call_Eval
(A
: Mal_Handle
) return Mal_Handle
is
148 return Eval
(A
, Env
);
153 case Deref
(Ast
).Sym_Type
is
158 Sym
: Mal_String
:= Deref_Atom
(Ast
).Get_Atom
;
160 -- if keyword or nil (which may represent False)...
164 return Envs
.Get
(Env
, Sym
);
167 when Envs
.Not_Found
=>
168 raise Envs
.Not_Found
with (" '" & Sym
& "' not found ");
173 return Map
(Call_Eval
'Unrestricted_Access, Deref_List
(Ast
).all);
177 -- Evaluating a lambda in a different Env.
180 New_Env
: Envs
.Env_Handle
;
182 L
:= Deref_Lambda
(Ast
);
184 -- Make the current Lambda's env the outer of the env param.
185 Envs
.Set_Outer
(New_Env
, L
.Get_Env
);
186 -- Make the Lambda's Env.
191 when others => return Ast
;
198 function Do_Processing
(Do_List
: List_Mal_Type
; Env
: Envs
.Env_Handle
)
201 Res
: Mal_Handle
:= Smart_Pointers
.Null_Smart_Pointer
;
204 Ada
.Text_IO
.Put_Line
("Do-ing " & To_String
(Do_List
));
207 while not Is_Null
(D
) loop
208 Res
:= Eval
(Car
(D
), Env
);
209 D
:= Deref_List
(Cdr
(D
)).all;
215 function Quasi_Quote_Processing
(Param
: Mal_Handle
) return Mal_Handle
is
216 Res
, First_Elem
, FE_0
: Mal_Handle
;
217 D
, Ast
: List_Mal_Type
;
222 Ada
.Text_IO
.Put_Line
("QuasiQt " & Deref
(Param
).To_String
);
225 -- Create a New List for the result...
226 Res
:= New_List_Mal_Type
(List_List
);
227 L
:= Deref_List
(Res
);
229 -- This is the equivalent of Is_Pair
230 if Deref
(Param
).Sym_Type
/= List
or else
231 Is_Null
(Deref_List
(Param
).all) then
233 -- return a new list containing: a symbol named "quote" and ast.
234 L
.Append
(New_Atom_Mal_Type
("quote"));
240 -- Ast is a non-empty list at this point.
242 Ast
:= Deref_List
(Param
).all;
244 First_Elem
:= Car
(Ast
);
246 -- if the first element of ast is a symbol named "unquote":
247 if Deref
(First_Elem
).Sym_Type
= Atom
and then
248 Deref_Atom
(First_Elem
).Get_Atom
= "unquote" then
250 -- return the second element of ast.`
251 D
:= Deref_List
(Cdr
(Ast
)).all;
256 -- if the first element of first element of `ast` (`ast[0][0]`)
257 -- is a symbol named "splice-unquote"
258 if Deref
(First_Elem
).Sym_Type
= List
and then
259 not Is_Null
(Deref_List
(First_Elem
).all) then
261 D
:= Deref_List
(First_Elem
).all;
264 if Deref
(FE_0
).Sym_Type
= Atom
and then
265 Deref_Atom
(FE_0
).Get_Atom
= "splice-unquote" then
267 -- return a new list containing: a symbol named "concat",
268 L
.Append
(New_Atom_Mal_Type
("concat"));
270 -- the second element of first element of ast (ast[0][1]),
271 D
:= Deref_List
(Cdr
(D
)).all;
274 -- and the result of calling quasiquote with
275 -- the second through last element of ast.
276 L
.Append
(Quasi_Quote_Processing
(Cdr
(Ast
)));
284 -- otherwise: return a new list containing: a symbol named "cons",
285 L
.Append
(New_Atom_Mal_Type
("cons"));
287 -- the result of calling quasiquote on first element of ast (ast[0]),
288 L
.Append
(Quasi_Quote_Processing
(Car
(Ast
)));
290 -- and result of calling quasiquote with the second through last element of ast.
291 L
.Append
(Quasi_Quote_Processing
(Cdr
(Ast
)));
295 end Quasi_Quote_Processing
;
298 function Catch_Processing
299 (Try_Line
: Mal_Handle
;
301 Env
: Envs
.Env_Handle
)
304 L
, CL
, CL2
, CL3
: List_Mal_Type
;
306 New_Env
: Envs
.Env_Handle
;
310 L
:= Deref_List
(Try_Line
).all;
312 -- CL is the list with the catch in.
313 CL
:= Deref_List
(C
).all;
315 CL2
:= Deref_List
(Cdr
(CL
)).all;
316 New_Env
:= Envs
.New_Env
(Env
);
317 Envs
.Set
(New_Env
, Deref_Atom
(Car
(CL2
)).Get_Atom
, ExStr
);
319 CL3
:= Deref_List
(Cdr
(CL2
)).all;
320 return Eval
(Car
(CL3
), New_Env
);
321 end Catch_Processing
;
323 Mal_Exception_Value
: Mal_Handle
;
325 function Eval
(AParam
: Mal_Handle
; AnEnv
: Envs
.Env_Handle
)
328 Env
: Envs
.Env_Handle
;
329 First_Elem
: Mal_Handle
;
338 Ada
.Text_IO
.Put_Line
("Evaling " & Deref
(Param
).To_String
);
341 Param
:= Macro_Expand
(Param
, Env
);
344 Ada
.Text_IO
.Put_Line
("After expansion " & Deref
(Param
).To_String
);
347 if Deref
(Param
).Sym_Type
= List
and then
348 Deref_List
(Param
).all.Get_List_Type
= List_List
then
351 L
: Mal_Handle
:= Param
;
352 LMT
, Rest_List
: List_Mal_Type
;
353 First_Elem
, Rest_Handle
: Mal_Handle
;
356 LMT
:= Deref_List
(L
).all;
358 First_Elem
:= Car
(LMT
);
360 Rest_Handle
:= Cdr
(LMT
);
362 Rest_List
:= Deref_List
(Rest_Handle
).all;
364 case Deref
(First_Elem
).Sym_Type
is
366 when Int | Floating | Bool | Str
=>
375 Atom_P
:= Deref_Atom
(First_Elem
);
376 if Atom_P
.Get_Atom
= "def!" then
377 return Def_Fn
(Rest_List
, Env
);
378 elsif Atom_P
.Get_Atom
= "defmacro!" then
379 return Def_Macro
(Rest_List
, Env
);
380 elsif Atom_P
.Get_Atom
= "macroexpand" then
381 return Macro_Expand
(Car
(Rest_List
), Env
);
382 elsif Atom_P
.Get_Atom
= "let*" then
383 return Let_Processing
(Rest_List
, Env
);
384 elsif Atom_P
.Get_Atom
= "do" then
385 return Do_Processing
(Rest_List
, Env
);
386 elsif Atom_P
.Get_Atom
= "if" then
388 Args
: List_Mal_Type
:= Rest_List
;
390 Cond
, True_Part
, False_Part
: Mal_Handle
;
392 pragma Assert
(Length
(Args
) = 2 or Length
(Args
) = 3,
393 "If_Processing: not 2 or 3 parameters");
397 Cond
:= Eval
(Car
(Args
), Env
);
399 Cond_Bool
:= Eval_As_Boolean
(Cond
);
402 L
:= Deref_List
(Cdr
(Args
)).all;
406 -- was: return Eval (Car (L), Env);
408 if Length
(Args
) = 3 then
409 L
:= Deref_List
(Cdr
(Args
)).all;
410 L
:= Deref_List
(Cdr
(L
)).all;
414 -- was: return Eval (Car (L), Env);
416 return New_Atom_Mal_Type
("nil");
421 elsif Atom_P
.Get_Atom
= "quote" then
422 return Car
(Rest_List
);
423 elsif Atom_P
.Get_Atom
= "quasiquote" then
424 Param
:= Quasi_Quote_Processing
(Car
(Rest_List
));
426 elsif Atom_P
.Get_Atom
= "try*" then
430 return Eval
(Car
(Rest_List
), Env
);
432 when Mal_Exception
=>
433 Res
:= Catch_Processing
437 Mal_Exception_Value
:= Smart_Pointers
.Null_Smart_Pointer
;
440 return Catch_Processing
443 (Ada
.Exceptions
.Exception_Message
(E
)),
446 elsif Atom_P
.Get_Atom
= "throw" then
447 Mal_Exception_Value
:= Eval
(Car
(Rest_List
), Env
);
449 else -- not a special form
456 Res
:= Eval_Ast
(L
, Env
);
459 -- was: return Eval (Res, Env);
468 (Deref_Func
(First_Elem
).all,
475 LP
: Lambda_Ptr
:= Deref_Lambda
(First_Elem
);
476 Fn_List
: Mal_Handle
:= Cdr
(LMT
);
477 Params
: List_Mal_Type
;
480 E
:= Envs
.New_Env
(LP
.Get_Env
);
481 Params
:= Deref_List
(LP
.Get_Params
).all;
482 if Envs
.Bind
(E
, Params
, Deref_List
(Fn_List
).all) then
484 Param
:= LP
.Get_Expr
;
487 -- was: return Eval (LP.Get_Expr, E);
497 -- First elem in the list is a list.
498 -- Eval it and then insert it as first elem in the list and
501 Evaled_List
: Mal_Handle
;
504 Evaled_List
:= Eval
(First_Elem
, Env
);
505 if Is_Null
(Evaled_List
) then
507 elsif Deref
(Evaled_List
).Sym_Type
= Lambda
then
508 E
:= Deref_Lambda
(Evaled_List
).Get_Env
;
513 Param
:= Prepend
(Evaled_List
, Rest_List
);
517 -- Evaled_List := Prepend (Evaled_List, Rest_List);
518 -- return Eval (Evaled_List, E);
521 when Error
=> return First_Elem
;
523 when Node
=> return New_Error_Mal_Type
("Evaluating a node");
525 when Unitary
=> null; -- Not yet impl
531 elsif Deref
(Param
).Sym_Type
= Unitary
then
533 UMT
: Types
.Unitary_Mal_Type
;
535 UMT
:= Deref_Unitary
(Param
).all;
540 Param
:= Quasi_Quote_Processing
(UMT
.Get_Op
);
550 return Eval_Ast
(Param
, Env
);