12 procedure Step6_File
is
17 function Read
(Param
: String) return Types
.Mal_Handle
is
19 return Reader
.Read_Str
(Param
);
23 -- Forward declaration of Eval.
24 function Eval
(AParam
: Types
.Mal_Handle
; AnEnv
: Envs
.Env_Handle
)
25 return Types
.Mal_Handle
;
28 Debug
: Boolean := False;
31 function Def_Fn
(Args
: List_Mal_Type
; Env
: Envs
.Env_Handle
)
33 Name
, Fn_Body
, Res
: Mal_Handle
;
36 pragma Assert
(Deref
(Name
).Sym_Type
= Sym
,
37 "Def_Fn: expected atom as name");
38 Fn_Body
:= Nth
(Args
, 1);
39 Res
:= Eval
(Fn_Body
, Env
);
40 Envs
.Set
(Env
, Deref_Sym
(Name
).Get_Sym
, Res
);
45 function Eval_As_Boolean
(MH
: Mal_Handle
) return Boolean is
48 case Deref
(MH
).Sym_Type
is
50 Res
:= Deref_Bool
(MH
).Get_Bool
;
57 -- L := Deref_List (MH).all;
58 -- Res := not Is_Null (L);
60 when others => -- Everything else
68 (Ast
: Mal_Handle
; Env
: Envs
.Env_Handle
)
71 function Call_Eval
(A
: Mal_Handle
) return Mal_Handle
is
78 case Deref
(Ast
).Sym_Type
is
83 Sym
: Mal_String
:= Deref_Sym
(Ast
).Get_Sym
;
85 -- if keyword, return it. Otherwise look it up in the environment.
89 return Envs
.Get
(Env
, Sym
);
92 when Envs
.Not_Found
=>
93 raise Envs
.Not_Found
with ("'" & Sym
& "' not found");
98 return Map
(Call_Eval
'Unrestricted_Access, Deref_List_Class
(Ast
).all);
100 when others => return Ast
;
107 function Eval
(AParam
: Mal_Handle
; AnEnv
: Envs
.Env_Handle
)
110 Env
: Envs
.Env_Handle
;
111 First_Param
, Rest_Params
: Mal_Handle
;
112 Rest_List
, Param_List
: List_Mal_Type
;
121 Ada
.Text_IO
.Put_Line
("Evaling " & Deref
(Param
).To_String
);
124 if Deref
(Param
).Sym_Type
= List
and then
125 Deref_List
(Param
).Get_List_Type
= List_List
then
127 Param_List
:= Deref_List
(Param
).all;
129 -- Deal with empty list..
130 if Param_List
.Length
= 0 then
134 First_Param
:= Car
(Param_List
);
135 Rest_Params
:= Cdr
(Param_List
);
136 Rest_List
:= Deref_List
(Rest_Params
).all;
138 if Deref
(First_Param
).Sym_Type
= Sym
and then
139 Deref_Sym
(First_Param
).Get_Sym
= "def!" then
140 return Def_Fn
(Rest_List
, Env
);
141 elsif Deref
(First_Param
).Sym_Type
= Sym
and then
142 Deref_Sym
(First_Param
).Get_Sym
= "let*" then
144 Defs
, Expr
, Res
: Mal_Handle
;
147 E
:= Envs
.New_Env
(Env
);
148 Defs
:= Car
(Rest_List
);
149 Deref_List_Class
(Defs
).Add_Defs
(E
);
150 Expr
:= Car
(Deref_List
(Cdr
(Rest_List
)).all);
155 -- Res := Eval (Expr, E);
158 elsif Deref
(First_Param
).Sym_Type
= Sym
and then
159 Deref_Sym
(First_Param
).Get_Sym
= "do" then
166 Ada
.Text_IO
.Put_Line
("Do-ing " & To_String
(Rest_List
));
169 if Is_Null
(Rest_List
) then
173 -- Loop processes Evals all but last entry
177 D
:= Deref_List
(Cdr
(D
)).all;
178 exit when Is_Null
(D
);
186 elsif Deref
(First_Param
).Sym_Type
= Sym
and then
187 Deref_Sym
(First_Param
).Get_Sym
= "if" then
189 Args
: List_Mal_Type
:= Rest_List
;
191 Cond
, True_Part
, False_Part
: Mal_Handle
;
193 pragma Assert
(Length
(Args
) = 2 or Length
(Args
) = 3,
194 "If_Processing: not 2 or 3 parameters");
198 Cond
:= Eval
(Car
(Args
), Env
);
200 Cond_Bool
:= Eval_As_Boolean
(Cond
);
203 L
:= Deref_List
(Cdr
(Args
)).all;
207 -- was: return Eval (Car (L), Env);
209 if Length
(Args
) = 3 then
210 L
:= Deref_List
(Cdr
(Args
)).all;
211 L
:= Deref_List
(Cdr
(L
)).all;
215 -- was: return Eval (Car (L), Env);
217 return New_Nil_Mal_Type
;
222 elsif Deref
(First_Param
).Sym_Type
= Sym
and then
223 Deref_Sym
(First_Param
).Get_Sym
= "fn*" then
225 return New_Lambda_Mal_Type
226 (Params
=> Car
(Rest_List
),
227 Expr
=> Nth
(Rest_List
, 1),
232 -- The APPLY section.
234 Evaled_H
: Mal_Handle
;
236 Evaled_H
:= Eval_Ast
(Param
, Env
);
238 Param_List
:= Deref_List
(Evaled_H
).all;
240 First_Param
:= Car
(Param_List
);
241 Rest_Params
:= Cdr
(Param_List
);
242 Rest_List
:= Deref_List
(Rest_Params
).all;
244 if Deref
(First_Param
).Sym_Type
= Func
then
245 return Call_Func
(Deref_Func
(First_Param
).all, Rest_Params
);
246 elsif Deref
(First_Param
).Sym_Type
= Lambda
then
251 Param_Names
: List_Mal_Type
;
256 L
:= Deref_Lambda
(First_Param
).all;
257 E
:= Envs
.New_Env
(L
.Get_Env
);
259 Param_Names
:= Deref_List
(L
.Get_Params
).all;
261 if Envs
.Bind
(E
, Param_Names
, Deref_List
(Rest_Params
).all) then
266 -- was: return Eval (L.Get_Expr, E);
270 raise Runtime_Exception
with "Bind failed in Apply";
276 else -- neither a Lambda or a Func
277 raise Runtime_Exception
with "Deref called on non-Func/Lambda";
284 else -- not a List_List
286 return Eval_Ast
(Param
, Env
);
293 function Print
(Param
: Types
.Mal_Handle
) return String is
295 return Printer
.Pr_Str
(Param
);
298 function Rep
(Param
: String; Env
: Envs
.Env_Handle
) return String is
299 AST
, Evaluated_AST
: Types
.Mal_Handle
;
304 if Types
.Is_Null
(AST
) then
307 Evaluated_AST
:= Eval
(AST
, Env
);
308 return Print
(Evaluated_AST
);
314 Repl_Env
: Envs
.Env_Handle
;
317 -- These two ops use Repl_Env directly.
320 procedure RE
(Str
: Mal_String
) is
321 Discarded
: Mal_Handle
;
323 Discarded
:= Eval
(Read
(Str
), Repl_Env
);
327 function Do_Eval
(Rest_Handle
: Mal_Handle
)
328 return Types
.Mal_Handle
is
329 First_Param
: Mal_Handle
;
330 Rest_List
: Types
.List_Mal_Type
;
332 Rest_List
:= Deref_List
(Rest_Handle
).all;
333 First_Param
:= Car
(Rest_List
);
334 return Eval_Callback
.Eval
.all (First_Param
, Repl_Env
);
338 Cmd_Args
, File_Param
: Natural;
339 Command_Args
: Types
.Mal_Handle
;
340 Command_List
: Types
.List_Ptr
;
341 File_Processed
: Boolean := False;
345 -- Save a function pointer back to the Eval function.
346 -- Can't use 'Access here because of Ada rules but 'Unrestricted_Access is OK
347 -- as we know Eval will be in scope for the lifetime of the program.
348 Eval_Callback
.Eval
:= Eval
'Unrestricted_Access;
350 Repl_Env
:= Envs
.New_Env
;
352 -- Core init also creates the first environment.
353 -- This is needed for the def!'s below.
354 Core
.Init
(Repl_Env
);
356 -- Register the eval command. This needs to be done here rather than Core.Init
357 -- as it requires direct access to Repl_Env.
358 Envs
.Set
(Repl_Env
, "eval", New_Func_Mal_Type
("eval", Do_Eval
'Unrestricted_Access));
360 RE
("(def! not (fn* (a) (if a false true)))");
361 RE
("(def! load-file (fn* (f) (eval (read-string (str ""(do "" (slurp f) ""\nnil)"")))))");
363 -- Command line processing.
366 Command_Args
:= Types
.New_List_Mal_Type
(Types
.List_List
);
367 Command_List
:= Types
.Deref_List
(Command_Args
);
369 while Ada
.Command_Line
.Argument_Count
> Cmd_Args
loop
371 Cmd_Args
:= Cmd_Args
+ 1;
372 if Ada
.Command_Line
.Argument
(Cmd_Args
) = "-d" then
374 elsif Ada
.Command_Line
.Argument
(Cmd_Args
) = "-e" then
376 elsif not File_Processed
then
377 File_Param
:= Cmd_Args
;
378 File_Processed
:= True;
381 (Types
.New_String_Mal_Type
(Ada
.Command_Line
.Argument
(Cmd_Args
)));
386 Envs
.Set
(Repl_Env
, "*ARGV*", Command_Args
);
388 if File_Processed
then
389 RE
("(load-file """ & Ada
.Command_Line
.Argument
(File_Param
) & """)");
393 Ada
.Text_IO
.Put
("user> ");
394 exit when Ada
.Text_IO
.End_Of_File
;
395 Ada
.Text_IO
.Put_Line
(Rep
(Ada
.Text_IO
.Get_Line
, Repl_Env
));
399 (Ada
.Text_IO
.Standard_Error
,
400 "Error: " & Ada
.Exceptions
.Exception_Information
(E
));
401 if Types
.Mal_Exception_Value
/= Smart_Pointers
.Null_Smart_Pointer
then
403 (Ada
.Text_IO
.Standard_Error
,
404 Printer
.Pr_Str
(Types
.Mal_Exception_Value
));
405 Types
.Mal_Exception_Value
:= Smart_Pointers
.Null_Smart_Pointer
;