Ada: fix Makefile and re-write early steps to remove some dependencies
[jackhill/mal.git] / ada / step2_eval.adb
CommitLineData
988812a6
CM
1with Ada.Containers.Hashed_Maps;
2with Ada.Strings.Unbounded.Hash;
9a6f4925
CM
3with Ada.Text_IO;
4with Ada.IO_Exceptions;
6d91af72 5with Ada.Exceptions;
9a6f4925
CM
6with Printer;
7with Reader;
18e21187 8with Smart_Pointers;
9a6f4925
CM
9with Types;
10
11procedure Step2_Eval is
12
18e21187
CM
13 use Types;
14
988812a6
CM
15 -- primitive functions on Smart_Pointer,
16 function "+" is new Arith_Op ("+", "+");
17 function "-" is new Arith_Op ("-", "-");
18 function "*" is new Arith_Op ("*", "*");
19 function "/" is new Arith_Op ("/", "/");
20
21 -- Take a list with two parameters and produce a single result
22 -- using the Op access-to-function parameter.
23 function Reduce2
24 (Op : Binary_Func_Access; LH : Mal_Handle)
25 return Mal_Handle is
26 Left, Right : Mal_Handle;
27 L, Rest_List : List_Mal_Type;
28 begin
29 L := Deref_List (LH).all;
30 Left := Car (L);
31 Rest_List := Deref_List (Cdr (L)).all;
32 Right := Car (Rest_List);
33 return Op (Left, Right);
34 end Reduce2;
35
36
37 function Plus (Rest_Handle : Mal_Handle)
38 return Types.Mal_Handle is
39 begin
40 return Reduce2 (Step2_Eval."+"'Unrestricted_Access, Rest_Handle);
41 end Plus;
42
43
44 function Minus (Rest_Handle : Mal_Handle)
45 return Types.Mal_Handle is
46 begin
47 return Reduce2 (Step2_Eval."-"'Unrestricted_Access, Rest_Handle);
48 end Minus;
49
50
51 function Mult (Rest_Handle : Mal_Handle)
52 return Types.Mal_Handle is
53 begin
54 return Reduce2 (Step2_Eval."*"'Unrestricted_Access, Rest_Handle);
55 end Mult;
56
57
58 function Divide (Rest_Handle : Mal_Handle)
59 return Types.Mal_Handle is
60 begin
61 return Reduce2 (Step2_Eval."/"'Unrestricted_Access, Rest_Handle);
62 end Divide;
63
64
65 package String_Mal_Hash is new Ada.Containers.Hashed_Maps
66 (Key_Type => Ada.Strings.Unbounded.Unbounded_String,
67 Element_Type => Smart_Pointers.Smart_Pointer,
68 Hash => Ada.Strings.Unbounded.Hash,
69 Equivalent_Keys => Ada.Strings.Unbounded."=",
70 "=" => Smart_Pointers."=");
71
72 Not_Found : exception;
73
74 function Get (M : String_Mal_Hash.Map; K : String) return Mal_Handle is
75 use String_Mal_Hash;
76 C : Cursor;
77 begin
78 C := Find (M, Ada.Strings.Unbounded.To_Unbounded_String (K));
79 if C = No_Element then
80 raise Not_Found;
81 else
82 return Element (C);
83 end if;
84 end Get;
85
86
87 Repl_Env : String_Mal_Hash.Map;
88
89
90 function Eval (Param : Types.Mal_Handle; Env : String_Mal_Hash.Map)
18e21187
CM
91 return Types.Mal_Handle;
92
988812a6 93
18e21187
CM
94 Debug : Boolean := False;
95
96
b5bad5ea
CM
97 function Read (Param : String) return Types.Mal_Handle is
98 begin
99 return Reader.Read_Str (Param);
100 end Read;
18e21187
CM
101
102
18e21187 103 function Eval_Ast
988812a6 104 (Ast : Mal_Handle; Env : String_Mal_Hash.Map)
18e21187
CM
105 return Mal_Handle is
106
107 function Call_Eval (A : Mal_Handle) return Mal_Handle is
108 begin
109 return Eval (A, Env);
110 end Call_Eval;
111
112 begin
113
114 case Deref (Ast).Sym_Type is
115
116 when Sym =>
117
118 declare
119 Sym : Mal_String := Deref_Sym (Ast).Get_Sym;
120 begin
121 -- if keyword, return it. Otherwise look it up in the environment.
122 if Sym(1) = ':' then
123 return Ast;
124 else
988812a6 125 return Get (Env, Sym);
18e21187
CM
126 end if;
127 exception
988812a6
CM
128 when Not_Found =>
129 raise Not_Found with (" '" & Sym & "' not found ");
18e21187
CM
130 end;
131
132 when List =>
133
134 return Map (Call_Eval'Unrestricted_Access, Deref_List_Class (Ast).all);
135
136 when others => return Ast;
137
138 end case;
139
140 end Eval_Ast;
141
142
988812a6 143 function Eval (Param : Mal_Handle; Env : String_Mal_Hash.Map)
18e21187
CM
144 return Mal_Handle is
145 First_Elem : Mal_Handle;
146 begin
147
148 if Debug then
149 Ada.Text_IO.Put_Line ("Evaling " & Deref (Param).To_String);
150 end if;
151
152 if Deref (Param).Sym_Type = List and then
153 Deref_List (Param).Get_List_Type = List_List then
154
155 declare
156 Evaled_H, First_Param : Mal_Handle;
157 Evaled_List : List_Mal_Type;
158 begin
159 Evaled_H := Eval_Ast (Param, Env);
160 Evaled_List := Deref_List (Evaled_H).all;
161 First_Param := Car (Evaled_List);
1c28e560 162 return Call_Func (Deref_Func (First_Param).all, Cdr (Evaled_List));
18e21187
CM
163 end;
164
165 else -- Not a List_List
166
167 return Eval_Ast (Param, Env);
168
169 end if;
170
171 end Eval;
9a6f4925
CM
172
173
fbad73cb 174 function Print (Param : Types.Mal_Handle) return String is
9a6f4925
CM
175 begin
176 return Printer.Pr_Str (Param);
177 end Print;
178
18e21187 179
988812a6 180 function Rep (Param : String; Env : String_Mal_Hash.Map) return String is
fbad73cb 181 AST, Evaluated_AST : Types.Mal_Handle;
9a6f4925
CM
182 begin
183
184 AST := Read (Param);
185
186 if Types.Is_Null (AST) then
187 return "";
188 else
b5bad5ea 189 Evaluated_AST := Eval (AST, Env);
9a6f4925
CM
190 return Print (Evaluated_AST);
191 end if;
192
193 end Rep;
194
18e21187 195
9a6f4925
CM
196 S : String (1..Reader.Max_Line_Len);
197 Last : Natural;
198
199begin
200
988812a6
CM
201 String_Mal_Hash.Include
202 (Container => Repl_Env,
203 Key => Ada.Strings.Unbounded.To_Unbounded_String ("+"),
204 New_Item => New_Func_Mal_Type ("+", Plus'Unrestricted_access));
205
206 String_Mal_Hash.Include
207 (Container => Repl_Env,
208 Key => Ada.Strings.Unbounded.To_Unbounded_String ("-"),
209 New_Item => New_Func_Mal_Type ("-", Minus'Unrestricted_access));
210
211 String_Mal_Hash.Include
212 (Container => Repl_Env,
213 Key => Ada.Strings.Unbounded.To_Unbounded_String ("*"),
214 New_Item => New_Func_Mal_Type ("*", Mult'Unrestricted_access));
215
216 String_Mal_Hash.Include
217 (Container => Repl_Env,
218 Key => Ada.Strings.Unbounded.To_Unbounded_String ("/"),
219 New_Item => New_Func_Mal_Type ("/", Divide'Unrestricted_access));
9a6f4925
CM
220
221 loop
6d91af72
CM
222 begin
223 Ada.Text_IO.Put ("user> ");
224 Ada.Text_IO.Get_Line (S, Last);
b5bad5ea 225 Ada.Text_IO.Put_Line (Rep (S (1..Last), Repl_Env));
6d91af72
CM
226 exception
227 when Ada.IO_Exceptions.End_Error => raise;
228 when E : others =>
229 Ada.Text_IO.Put_Line
230 (Ada.Text_IO.Standard_Error,
231 Ada.Exceptions.Exception_Information (E));
232 end;
9a6f4925
CM
233 end loop;
234
235exception
236 when Ada.IO_Exceptions.End_Error => null;
237 -- i.e. exit without textual output
238end Step2_Eval;