1 with Ada
.Environment_Variables
;
2 with Ada
.Text_IO
.Unbounded_IO
;
7 with Garbage_Collected
;
16 procedure Step4_If_Fn_Do
is
18 Dbgeval
: constant Boolean := Ada
.Environment_Variables
.Exists
("dbgeval");
21 use all type Types
.Kind_Type
;
22 use type Types
.Strings
.Instance
;
24 function Read
return Types
.T_Array
with Inline
;
26 function Eval
(Ast
: in Types
.T
;
27 Env
: in Envs
.Ptr
) return Types
.T
;
29 procedure Print
(Ast
: in Types
.T
) with Inline
;
31 procedure Rep
(Env
: in Envs
.Ptr
) with Inline
;
33 function Eval_Map
(Source
: in Types
.Maps
.Instance
;
34 Env
: in Envs
.Ptr
) return Types
.T
;
35 function Eval_Vector
(Source
: in Types
.Sequences
.Instance
;
36 Env
: in Envs
.Ptr
) return Types
.T
;
37 -- Helpers for the Eval function.
39 procedure Exec
(Script
: in String;
40 Env
: in Envs
.Ptr
) with Inline
;
41 -- Read the script, eval its elements, but ignore the result.
43 ----------------------------------------------------------------------
45 function Eval
(Ast
: in Types
.T
;
46 Env
: in Envs
.Ptr
) return Types
.T
52 Ada
.Text_IO
.Put
("EVAL: ");
54 Envs
.Dump_Stack
(Env
.all);
58 when Kind_Nil | Kind_Atom | Kind_Boolean | Kind_Number | Types
.Kind_Key
59 | Kind_Macro | Types
.Kind_Function
=>
62 return Env
.all.Get
(Ast
.Str
);
64 return Eval_Map
(Ast
.Map
.all, Env
);
66 return Eval_Vector
(Ast
.Sequence
.all, Env
);
72 if Ast
.Sequence
.all.Length
= 0 then
75 First
:= Ast
.Sequence
.all.Data
(1);
78 -- Ast is a non-empty list, First is its first element.
81 if First
.Str
.all = "if" then
82 Err
.Check
(Ast
.Sequence
.all.Length
in 3 .. 4,
83 "expected 2 or 3 parameters");
85 Tst
: constant Types
.T
:= Eval
(Ast
.Sequence
.all.Data
(2), Env
);
87 if Tst
/= Types
.Nil
and Tst
/= (Kind_Boolean
, False) then
88 return Eval
(Ast
.Sequence
.all.Data
(3), Env
);
89 elsif Ast
.Sequence
.all.Length
= 3 then
92 return Eval
(Ast
.Sequence
.all.Data
(4), Env
);
95 elsif First
.Str
.all = "let*" then
96 Err
.Check
(Ast
.Sequence
.all.Length
= 3
97 and then Ast
.Sequence
.all.Data
(2).Kind
in Types
.Kind_Sequence
,
98 "expected a sequence then a value");
100 Bindings
: Types
.T_Array
101 renames Ast
.Sequence
.all.Data
(2).Sequence
.all.Data
;
102 New_Env
: constant Envs
.Ptr
:= Envs
.New_Env
(Outer
=> Env
);
104 Err
.Check
(Bindings
'Length mod 2 = 0, "expected even binds");
105 for I
in 0 .. Bindings
'Length / 2 - 1 loop
106 New_Env
.all.Set
(Bindings
(Bindings
'First + 2 * I
),
107 Eval
(Bindings
(Bindings
'First + 2 * I
+ 1), New_Env
));
108 -- This call checks key kind.
110 return Eval
(Ast
.Sequence
.all.Data
(3), New_Env
);
112 elsif First
.Str
.all = "def!" then
113 Err
.Check
(Ast
.Sequence
.all.Length
= 3, "expected 2 parameters");
115 Key
: Types
.T
renames Ast
.Sequence
.all.Data
(2);
116 Val
: constant Types
.T
:= Eval
(Ast
.Sequence
.all.Data
(3), Env
);
118 Env
.all.Set
(Key
, Val
); -- Check key kind.
121 -- do is a built-in function, shortening this test cascade.
122 elsif First
.Str
.all = "fn*" then
123 Err
.Check
(Ast
.Sequence
.all.Length
= 3, "expected 2 parameters");
125 Params
: Types
.T
renames Ast
.Sequence
.all.Data
(2);
127 Err
.Check
(Params
.Kind
in Types
.Kind_Sequence
,
128 "first argument of fn* must be a sequence");
129 return Types
.Fns
.New_Function
130 (Params
=> Params
.Sequence
,
131 Ast
=> Ast
.Sequence
.all.Data
(3),
135 First
:= Eval
(First
, Env
);
138 First
:= Eval
(First
, Env
);
142 -- Ast is a non-empty list,
143 -- First is its non-special evaluated first element.
144 Err
.Check
(First
.Kind
in Types
.Kind_Function
,
145 "first element must be a function");
146 -- We are applying a function. Evaluate its arguments.
148 Args
: Types
.T_Array
(2 .. Ast
.Sequence
.all.Length
);
150 for I
in Args
'Range loop
151 Args
(I
) := Eval
(Ast
.Sequence
.all.Data
(I
), Env
);
153 if First
.Kind
= Kind_Builtin
then
154 return First
.Builtin
.all (Args
);
156 return First
.Fn
.all.Apply
(Args
);
160 Err
.Add_Trace_Line
("eval", Ast
);
164 function Eval_Map
(Source
: in Types
.Maps
.Instance
;
165 Env
: in Envs
.Ptr
) return Types
.T
167 use all type Types
.Maps
.Cursor
;
168 -- Copy the whole map so that keys are not hashed again.
169 Result
: constant Types
.T
:= Types
.Maps
.New_Map
(Source
);
170 Position
: Types
.Maps
.Cursor
:= Result
.Map
.all.First
;
172 while Has_Element
(Position
) loop
173 Result
.Map
.all.Replace_Element
(Position
,
174 Eval
(Element
(Position
), Env
));
180 function Eval_Vector
(Source
: in Types
.Sequences
.Instance
;
181 Env
: in Envs
.Ptr
) return Types
.T
183 Ref
: constant Types
.Sequence_Ptr
184 := Types
.Sequences
.Constructor
(Source
.Length
);
186 for I
in Source
.Data
'Range loop
187 Ref
.all.Data
(I
) := Eval
(Source
.Data
(I
), Env
);
189 return (Kind_Vector
, Ref
);
192 procedure Exec
(Script
: in String;
197 for Expression
of Reader
.Read_Str
(Script
) loop
198 Result
:= Eval
(Expression
, Env
);
200 pragma Unreferenced
(Result
);
203 procedure Print
(Ast
: in Types
.T
) is
205 Ada
.Text_IO
.Unbounded_IO
.Put_Line
(Printer
.Pr_Str
(Ast
));
208 function Read
return Types
.T_Array
209 is (Reader
.Read_Str
(Readline
.Input
("user> ")));
211 procedure Rep
(Env
: in Envs
.Ptr
) is
213 for Expression
of Read
loop
214 Print
(Eval
(Expression
, Env
));
218 ----------------------------------------------------------------------
220 Startup
: constant String
221 := "(def! not (fn* (a) (if a false true)))";
222 Repl
: constant Envs
.Ptr
:= Envs
.New_Env
;
224 -- Show the Eval function to other packages.
225 Types
.Fns
.Eval_Cb
:= Eval
'Unrestricted_Access;
226 -- Add Core functions into the top environment.
227 Core
.NS_Add_To_Repl
(Repl
);
228 -- Native startup procedure.
229 Exec
(Startup
, Repl
);
230 -- Execute user commands.
235 when Readline
.End_Of_File
=>
238 Ada
.Text_IO
.Unbounded_IO
.Put
(Err
.Trace
);
240 -- Other exceptions are really unexpected.
243 Err
.Data
:= Types
.Nil
;
245 Garbage_Collected
.Clean
;
247 Ada
.Text_IO
.New_Line
;
249 -- If assertions are enabled, check deallocations.
250 -- Normal runs do not need to deallocate before termination.
251 -- Beware that all pointers are now dangling.
252 pragma Debug
(Garbage_Collected
.Clean
);
253 Garbage_Collected
.Check_Allocations
;