Ada: add variable length args (bind)
[jackhill/mal.git] / ada / envs.adb
CommitLineData
09c532ba 1with Ada.Text_IO;
13ce1681 2with Types;
9a6f4925
CM
3with Unchecked_Deallocation;
4
5package body Envs is
6
7
13ce1681
CM
8 function Is_Null (E : Env_Handle) return Boolean is
9 use Smart_Pointers;
10 begin
11 return Smart_Pointer (E) = Null_Smart_Pointer;
12 end Is_Null;
13
14
15 function New_Env (Outer : Env_Handle) return Env_Handle is
16 use Smart_Pointers;
17 Level : Natural;
18 begin
19 if Is_Null (Outer) then
20 Level := 0;
21 else
22 Level := Deref (Outer).Level + 1;
23 end if;
24 if Debug then
25 Ada.Text_IO.Put_Line
26 ("Envs: Creating at level " & Natural'Image (Level));
27 end if;
28 return Env_Handle (Smart_Pointers.New_Ptr (new Env'
29 (Base_Class with The_Map => String_Mal_Hash.Empty_Map,
30 Outer_Env => Outer,
31 Level => Level)));
32 end New_Env;
33
34
35 procedure Set
36 (E : Env_Handle;
37 Key : String;
38 Elem : Smart_Pointers.Smart_Pointer) is
39 begin
40 if Debug then
41 Ada.Text_IO.Put_Line
42 ("Envs: Setting " & Key &
43 " to " & Types.Deref (Elem).To_String &
44 " at level " & Natural'Image (Deref (E).Level));
45 end if;
9a6f4925 46 String_Mal_Hash.Include
13ce1681 47 (Container => Deref (E).The_Map,
9a6f4925 48 Key => Ada.Strings.Unbounded.To_Unbounded_String (Key),
13ce1681 49 New_Item => Elem);
c4b822cd 50 end Set;
9a6f4925 51
09c532ba 52
13ce1681
CM
53 function Get (E : Env_Handle; Key: String)
54 return Smart_Pointers.Smart_Pointer is
55
56 use String_Mal_Hash;
57 C : Cursor;
09c532ba 58
13ce1681
CM
59 begin
60
61 if Debug then
62 Ada.Text_IO.Put_Line
63 ("Envs: Finding " & Key &
64 " at level " & Natural'Image (Deref (E).Level));
65 end if;
09c532ba 66
13ce1681
CM
67 C := Find (Deref (E).The_Map,
68 Ada.Strings.Unbounded.To_Unbounded_String (Key));
09c532ba 69
13ce1681
CM
70 if C = No_Element then
71
72 if Is_Null (Deref (E).Outer_Env) then
73 raise Not_Found;
09c532ba 74 else
13ce1681 75 return Get (Deref (E).Outer_Env, Key);
09c532ba
CM
76 end if;
77
13ce1681
CM
78 else
79 return Element (C);
80 end if;
09c532ba 81
c4b822cd 82 end Get;
9a6f4925
CM
83
84
efaad1ce
CM
85 procedure Set_Outer
86 (E : Env_Handle; Outer_Env : Env_Handle) is
87 begin
88 -- Attempt to avoid making loops.
89 if Deref (E).Level /= 0 then
90 Deref (E).Outer_Env := Outer_Env;
91 end if;
92 end Set_Outer;
93
94
95 function To_String (E : Env_Handle) return String is
96 use String_Mal_Hash, Ada.Strings.Unbounded;
97 C : Cursor;
98 Res : Unbounded_String;
99 begin
100 C := First (Deref (E).The_Map);
101 while C /= No_Element loop
102 Append (Res, Key (C) & " => " & Types.To_String (Types.Deref (Element (C)).all) & ", ");
103 C := Next (C);
104 end loop;
105 return To_String (Res);
106 end To_String;
107
108
13ce1681
CM
109 -- Sym and Exprs are lists. Bind Sets Keys in Syms to the corresponding
110 -- expression in Exprs.
111 procedure Bind (E : Env_Handle; Syms, Exprs : Types.List_Mal_Type) is
112 use Types;
113 S, Expr : List_Mal_Type;
a90ea3c7 114 First_Sym : Atom_Ptr;
13ce1681
CM
115 begin
116 S := Syms;
117 Expr := Exprs;
a90ea3c7
CM
118 while not Is_Null (S) loop
119 First_Sym := Deref_Atom (Car (S));
120 if First_Sym.Get_Atom = "&" then
121 S := Deref_List (Cdr (S)).all;
122 First_Sym := Deref_Atom (Car (S));
123 Set (E, First_Sym.Get_Atom, New_List_Mal_Type (Expr));
124 exit;
125 end if;
126 Set (E, First_Sym.Get_Atom, Car (Expr));
13ce1681 127 S := Deref_List (Cdr (S)).all;
a90ea3c7 128 exit when Is_Null (Expr);
13ce1681
CM
129 Expr := Deref_List (Cdr (Expr)).all;
130 end loop;
131 end Bind;
132
133
9a6f4925
CM
134 function String_Hash (Key : Ada.Strings.Unbounded.Unbounded_String)
135 return Ada.Containers.Hash_Type is
9a6f4925
CM
136 use Ada.Containers;
137 Res : Ada.Containers.Hash_Type;
138 Str_Len : Natural;
139 begin
140 Res := 0;
141 Str_Len := Ada.Strings.Unbounded.Length (Key);
142 for I in 1..Str_Len loop
143 Res := Res * 16 +
144 Character'Pos (Ada.Strings.Unbounded.Element (Key, I));
145 end loop;
146 return Res;
147 end String_Hash;
148
149
150 procedure New_Env is
151 begin
13ce1681 152 Current := New_Env (Current);
9a6f4925
CM
153 end New_Env;
154
155
13ce1681 156 procedure Free is new Unchecked_Deallocation (Env, Env_Ptr);
9a6f4925
CM
157
158 procedure Delete_Env is
159 begin
efaad1ce
CM
160 if Debug then
161 Ada.Text_IO.Put_Line ("Deleting env at level " & Natural'Image (Deref (Current).Level));
162 end if;
13ce1681
CM
163 -- Always leave one Env!
164 if not Is_Null (Deref (Current).Outer_Env) then
165 Current := Deref (Current).Outer_Env;
166 -- The old Current is finalized *if* there are no references to it.
167 -- Note closures may refer to the old env.
09c532ba 168 end if;
9a6f4925
CM
169 end Delete_Env;
170
171
13ce1681
CM
172 function Get_Current return Env_Handle is
173 begin
174 return Current;
175 end Get_Current;
176
177
178 function Deref (SP : Env_Handle) return Env_Ptr is
179 begin
180 return Env_Ptr (Smart_Pointers.Deref (Smart_Pointers.Smart_Pointer (SP)));
181 end Deref;
182
183
9a6f4925 184end Envs;