12 procedure Step9_Try
is
16 function Eval
(AParam
: Types
.Mal_Handle
; AnEnv
: Envs
.Env_Handle
)
17 return Types
.Mal_Handle
;
19 Debug
: Boolean := False;
22 function Read
(Param
: String) return Types
.Mal_Handle
is
24 return Reader
.Read_Str
(Param
);
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
= Sym
,
34 "Def_Fn: expected atom as name");
35 Fn_Body
:= Nth
(Args
, 1);
36 Res
:= Eval
(Fn_Body
, Env
);
37 Envs
.Set
(Env
, Deref_Sym
(Name
).Get_Sym
, 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
= Sym
,
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
(Env
, Deref_Sym
(Name
).Get_Sym
, 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 Eval_As_Boolean
(MH
: Mal_Handle
) return Boolean is
109 case Deref
(MH
).Sym_Type
is
111 Res
:= Deref_Bool
(MH
).Get_Bool
;
116 -- L : List_Mal_Type;
118 -- L := Deref_List (MH).all;
119 -- Res := not Is_Null (L);
121 when others => -- Everything else
129 (Ast
: Mal_Handle
; Env
: Envs
.Env_Handle
)
132 function Call_Eval
(A
: Mal_Handle
) return Mal_Handle
is
134 return Eval
(A
, Env
);
139 case Deref
(Ast
).Sym_Type
is
144 Sym
: Mal_String
:= Deref_Sym
(Ast
).Get_Sym
;
146 -- if keyword, return it. Otherwise look it up in the environment.
150 return Envs
.Get
(Env
, Sym
);
153 when Envs
.Not_Found
=>
154 raise Envs
.Not_Found
with ("'" & Sym
& "' not found");
159 return Map
(Call_Eval
'Unrestricted_Access, Deref_List_Class
(Ast
).all);
161 when others => return Ast
;
167 function Starts_With
(Ast
: Mal_Handle
; Symbol
: String) return Boolean is
170 if Deref
(Ast
).Sym_Type
/= List
171 or else Deref_List_Class
(Ast
).Get_List_Type
/= List_List
172 or else Deref_List
(Ast
).Is_Null
176 A0
:= Deref_List
(Ast
).Car
;
177 return Deref
(A0
).Sym_Type
= Sym
178 and then Deref_Sym
(A0
).Get_Sym
= Symbol
;
181 function Quasi_Quote_Processing
(Param
: Mal_Handle
) return Mal_Handle
is
182 Res
, Elt
, New_Res
: Mal_Handle
;
187 Ada
.Text_IO
.Put_Line
("QuasiQt " & Deref
(Param
).To_String
);
190 if Deref
(Param
).Sym_Type
not in Sym | List
then
191 -- No need to quote, Eval would not affect these anyway.
195 if Deref
(Param
).Sym_Type
/= List
or else
196 Deref_List_Class
(Param
).Get_List_Type
= Hashed_List
then
198 -- return a new list containing: a symbol named "quote" and ast.
199 Res
:= New_List_Mal_Type
(List_List
);
200 L
:= Deref_List
(Res
);
201 L
.Append
(New_Symbol_Mal_Type
("quote"));
207 -- if the first element of ast is a symbol named "unquote":
208 if Starts_With
(Param
, "unquote") then
209 -- return the second element of ast.`
210 return Deref_List_Class
(Param
).Nth
(1);
214 Res
:= New_List_Mal_Type
(List_List
);
216 for I
in reverse 0 .. Deref_List_Class
(Param
).Length
- 1 loop
217 Elt
:= Deref_List_Class
(Param
).Nth
(I
);
218 New_Res
:= New_List_Mal_Type
(List_List
);
219 L
:= Deref_List
(New_Res
);
220 if Starts_With
(Elt
, "splice-unquote") then
221 L
.Append
(New_Symbol_Mal_Type
("concat"));
222 L
.Append
(Deref_List
(Elt
).Nth
(1));
224 L
.Append
(New_Symbol_Mal_Type
("cons"));
225 L
.Append
(Quasi_Quote_Processing
(Elt
));
231 if Deref_List_Class
(Param
).Get_List_Type
= Vector_List
then
232 New_Res
:= New_List_Mal_Type
(List_List
);
233 L
:= Deref_List
(New_Res
);
234 L
.Append
(New_Symbol_Mal_Type
("vec"));
241 end Quasi_Quote_Processing
;
244 function Catch_Processing
245 (Try_Line
: Mal_Handle
;
247 Env
: Envs
.Env_Handle
)
250 L
, CL
, CL2
, CL3
: List_Mal_Type
;
252 New_Env
: Envs
.Env_Handle
;
256 L
:= Deref_List
(Try_Line
).all;
258 -- CL is the list with the catch in.
259 CL
:= Deref_List
(C
).all;
261 CL2
:= Deref_List
(Cdr
(CL
)).all;
262 New_Env
:= Envs
.New_Env
(Env
);
263 Envs
.Set
(New_Env
, Deref_Sym
(Car
(CL2
)).Get_Sym
, ExStr
);
265 CL3
:= Deref_List
(Cdr
(CL2
)).all;
266 return Eval
(Car
(CL3
), New_Env
);
267 end Catch_Processing
;
270 function Eval
(AParam
: Mal_Handle
; AnEnv
: Envs
.Env_Handle
)
273 Env
: Envs
.Env_Handle
;
274 First_Param
, Rest_Params
: Mal_Handle
;
275 Rest_List
, Param_List
: List_Mal_Type
;
284 Ada
.Text_IO
.Put_Line
("Evaling " & Deref
(Param
).To_String
);
287 Param
:= Macro_Expand
(Param
, Env
);
290 Ada
.Text_IO
.Put_Line
("After expansion " & Deref
(Param
).To_String
);
293 if Deref
(Param
).Sym_Type
= List
and then
294 Deref_List
(Param
).Get_List_Type
= List_List
then
296 Param_List
:= Deref_List
(Param
).all;
298 -- Deal with empty list..
299 if Param_List
.Length
= 0 then
303 First_Param
:= Car
(Param_List
);
304 Rest_Params
:= Cdr
(Param_List
);
305 Rest_List
:= Deref_List
(Rest_Params
).all;
307 if Deref
(First_Param
).Sym_Type
= Sym
and then
308 Deref_Sym
(First_Param
).Get_Sym
= "def!" then
309 return Def_Fn
(Rest_List
, Env
);
310 elsif Deref
(First_Param
).Sym_Type
= Sym
and then
311 Deref_Sym
(First_Param
).Get_Sym
= "defmacro!" then
312 return Def_Macro
(Rest_List
, Env
);
313 elsif Deref
(First_Param
).Sym_Type
= Sym
and then
314 Deref_Sym
(First_Param
).Get_Sym
= "macroexpand" then
315 return Macro_Expand
(Car
(Rest_List
), Env
);
316 elsif Deref
(First_Param
).Sym_Type
= Sym
and then
317 Deref_Sym
(First_Param
).Get_Sym
= "let*" then
319 Defs
, Expr
, Res
: Mal_Handle
;
322 E
:= Envs
.New_Env
(Env
);
323 Defs
:= Car
(Rest_List
);
324 Deref_List_Class
(Defs
).Add_Defs
(E
);
325 Expr
:= Car
(Deref_List
(Cdr
(Rest_List
)).all);
330 -- Res := Eval (Expr, E);
333 elsif Deref
(First_Param
).Sym_Type
= Sym
and then
334 Deref_Sym
(First_Param
).Get_Sym
= "do" then
341 Ada
.Text_IO
.Put_Line
("Do-ing " & To_String
(Rest_List
));
344 if Is_Null
(Rest_List
) then
348 -- Loop processes Evals all but last entry
352 D
:= Deref_List
(Cdr
(D
)).all;
353 exit when Is_Null
(D
);
361 elsif Deref
(First_Param
).Sym_Type
= Sym
and then
362 Deref_Sym
(First_Param
).Get_Sym
= "if" then
364 Args
: List_Mal_Type
:= Rest_List
;
366 Cond
, True_Part
, False_Part
: Mal_Handle
;
368 pragma Assert
(Length
(Args
) = 2 or Length
(Args
) = 3,
369 "If_Processing: not 2 or 3 parameters");
373 Cond
:= Eval
(Car
(Args
), Env
);
375 Cond_Bool
:= Eval_As_Boolean
(Cond
);
378 L
:= Deref_List
(Cdr
(Args
)).all;
382 -- was: return Eval (Car (L), Env);
384 if Length
(Args
) = 3 then
385 L
:= Deref_List
(Cdr
(Args
)).all;
386 L
:= Deref_List
(Cdr
(L
)).all;
390 -- was: return Eval (Car (L), Env);
392 return New_Nil_Mal_Type
;
397 elsif Deref
(First_Param
).Sym_Type
= Sym
and then
398 Deref_Sym
(First_Param
).Get_Sym
= "fn*" then
400 return New_Lambda_Mal_Type
401 (Params
=> Car
(Rest_List
),
402 Expr
=> Nth
(Rest_List
, 1),
405 elsif Deref
(First_Param
).Sym_Type
= Sym
and then
406 Deref_Sym
(First_Param
).Get_Sym
= "quote" then
408 return Car
(Rest_List
);
410 elsif Deref
(First_Param
).Sym_Type
= Sym
and then
411 Deref_Sym
(First_Param
).Get_Sym
= "quasiquoteexpand" then
413 return Quasi_Quote_Processing
(Car
(Rest_List
));
415 elsif Deref
(First_Param
).Sym_Type
= Sym
and then
416 Deref_Sym
(First_Param
).Get_Sym
= "quasiquote" then
418 Param
:= Quasi_Quote_Processing
(Car
(Rest_List
));
421 elsif Deref
(First_Param
).Sym_Type
= Sym
and then
422 Deref_Sym
(First_Param
).Get_Sym
= "try*" then
424 if Length
(Rest_List
) = 1 then
425 return Eval
(Car
(Rest_List
), Env
);
430 return Eval
(Car
(Rest_List
), Env
);
432 when Mal_Exception
=>
433 Res
:= Catch_Processing
435 Types
.Mal_Exception_Value
,
437 Types
.Mal_Exception_Value
:=
438 Smart_Pointers
.Null_Smart_Pointer
;
441 return Catch_Processing
444 (Ada
.Exceptions
.Exception_Message
(E
)),
450 -- The APPLY section.
452 Evaled_H
: Mal_Handle
;
454 Evaled_H
:= Eval_Ast
(Param
, Env
);
456 Param_List
:= Deref_List
(Evaled_H
).all;
458 First_Param
:= Car
(Param_List
);
459 Rest_Params
:= Cdr
(Param_List
);
460 Rest_List
:= Deref_List
(Rest_Params
).all;
462 if Deref
(First_Param
).Sym_Type
= Func
then
463 return Call_Func
(Deref_Func
(First_Param
).all, Rest_Params
);
464 elsif Deref
(First_Param
).Sym_Type
= Lambda
then
469 Param_Names
: List_Mal_Type
;
474 L
:= Deref_Lambda
(First_Param
).all;
475 E
:= Envs
.New_Env
(L
.Get_Env
);
477 Param_Names
:= Deref_List
(L
.Get_Params
).all;
479 if Envs
.Bind
(E
, Param_Names
, Deref_List
(Rest_Params
).all) then
484 -- was: return Eval (L.Get_Expr, E);
488 raise Runtime_Exception
with "Bind failed in Apply";
494 else -- neither a Lambda or a Func
495 raise Runtime_Exception
with "Deref called on non-Func/Lambda";
502 else -- not a List_List
504 return Eval_Ast
(Param
, Env
);
511 function Print
(Param
: Types
.Mal_Handle
) return String is
513 return Printer
.Pr_Str
(Param
);
516 function Rep
(Param
: String; Env
: Envs
.Env_Handle
) return String is
517 AST
, Evaluated_AST
: Types
.Mal_Handle
;
522 if Types
.Is_Null
(AST
) then
525 Evaluated_AST
:= Eval
(AST
, Env
);
526 return Print
(Evaluated_AST
);
532 Repl_Env
: Envs
.Env_Handle
;
535 -- These two ops use Repl_Env directly.
538 procedure RE
(Str
: Mal_String
) is
539 Discarded
: Mal_Handle
;
541 Discarded
:= Eval
(Read
(Str
), Repl_Env
);
545 function Do_Eval
(Rest_Handle
: Mal_Handle
)
546 return Types
.Mal_Handle
is
547 First_Param
: Mal_Handle
;
548 Rest_List
: Types
.List_Mal_Type
;
550 Rest_List
:= Deref_List
(Rest_Handle
).all;
551 First_Param
:= Car
(Rest_List
);
552 return Eval_Callback
.Eval
.all (First_Param
, Repl_Env
);
556 Cmd_Args
, File_Param
: Natural;
557 Command_Args
: Types
.Mal_Handle
;
558 Command_List
: Types
.List_Ptr
;
559 File_Processed
: Boolean := False;
563 -- Save a function pointer back to the Eval function.
564 -- Can't use 'Access here because of Ada rules but 'Unrestricted_Access is OK
565 -- as we know Eval will be in scope for the lifetime of the program.
566 Eval_Callback
.Eval
:= Eval
'Unrestricted_Access;
568 Repl_Env
:= Envs
.New_Env
;
570 -- Core init also creates the first environment.
571 -- This is needed for the def!'s below.
572 Core
.Init
(Repl_Env
);
574 -- Register the eval command. This needs to be done here rather than Core.Init
575 -- as it requires direct access to Repl_Env.
576 Envs
.Set
(Repl_Env
, "eval", New_Func_Mal_Type
("eval", Do_Eval
'Unrestricted_Access));
578 RE
("(def! not (fn* (a) (if a false true)))");
579 RE
("(def! load-file (fn* (f) (eval (read-string (str ""(do "" (slurp f) ""\nnil)"")))))");
580 RE
("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw ""odd number of forms to cond"")) (cons 'cond (rest (rest xs)))))))");
582 -- Command line processing.
585 Command_Args
:= Types
.New_List_Mal_Type
(Types
.List_List
);
586 Command_List
:= Types
.Deref_List
(Command_Args
);
588 while Ada
.Command_Line
.Argument_Count
> Cmd_Args
loop
590 Cmd_Args
:= Cmd_Args
+ 1;
591 if Ada
.Command_Line
.Argument
(Cmd_Args
) = "-d" then
593 elsif Ada
.Command_Line
.Argument
(Cmd_Args
) = "-e" then
595 elsif not File_Processed
then
596 File_Param
:= Cmd_Args
;
597 File_Processed
:= True;
600 (Types
.New_String_Mal_Type
(Ada
.Command_Line
.Argument
(Cmd_Args
)));
605 Envs
.Set
(Repl_Env
, "*ARGV*", Command_Args
);
607 if File_Processed
then
608 RE
("(load-file """ & Ada
.Command_Line
.Argument
(File_Param
) & """)");
612 Ada
.Text_IO
.Put
("user> ");
613 exit when Ada
.Text_IO
.End_Of_File
;
614 Ada
.Text_IO
.Put_Line
(Rep
(Ada
.Text_IO
.Get_Line
, Repl_Env
));
618 (Ada
.Text_IO
.Standard_Error
,
619 "Error: " & Ada
.Exceptions
.Exception_Information
(E
));
620 if Types
.Mal_Exception_Value
/= Smart_Pointers
.Null_Smart_Pointer
then
622 (Ada
.Text_IO
.Standard_Error
,
623 Printer
.Pr_Str
(Types
.Mal_Exception_Value
));
624 Types
.Mal_Exception_Value
:= Smart_Pointers
.Null_Smart_Pointer
;