Commit | Line | Data |
---|---|---|
09c532ba | 1 | with Ada.Text_IO; |
13ce1681 | 2 | with Types; |
9a6f4925 CM |
3 | with Unchecked_Deallocation; |
4 | ||
5 | package 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 | 184 | end Envs; |