Commit | Line | Data |
---|---|---|
36e91db4 DM |
1 | library STD; |
2 | use STD.textio.all; | |
3 | ||
4 | package types is | |
5 | ||
6 | procedure debugline(l: inout line); | |
7 | procedure debug(str: in string); | |
8 | procedure debug(ch: in character); | |
9 | procedure debug(i: in integer); | |
10 | ||
11 | type mal_type_tag is (mal_nil, mal_true, mal_false, mal_number, | |
12 | mal_symbol, mal_string, mal_keyword, | |
13 | mal_list, mal_vector, mal_hashmap, | |
14 | mal_atom, mal_nativefn, mal_fn); | |
15 | ||
16 | -- Forward declarations | |
17 | type mal_val; | |
18 | type mal_seq; | |
19 | type mal_func; | |
20 | type env_record; | |
21 | ||
22 | type mal_val_ptr is access mal_val; | |
23 | type mal_seq_ptr is access mal_seq; | |
24 | type mal_func_ptr is access mal_func; | |
25 | type env_ptr is access env_record; | |
26 | ||
27 | type mal_val is record | |
28 | val_type: mal_type_tag; | |
29 | number_val: integer; -- For types: number | |
30 | string_val: line; -- For types: symbol, string, keyword, nativefn | |
31 | seq_val: mal_seq_ptr; -- For types: list, vector, hashmap, atom | |
32 | func_val: mal_func_ptr; -- For fn | |
33 | meta_val: mal_val_ptr; | |
34 | end record mal_val; | |
35 | ||
36 | type mal_seq is array (natural range <>) of mal_val_ptr; | |
37 | ||
38 | type mal_func is record | |
39 | f_body: mal_val_ptr; | |
40 | f_args: mal_val_ptr; | |
41 | f_env: env_ptr; | |
42 | f_is_macro: boolean; | |
43 | end record mal_func; | |
44 | ||
45 | type env_record is record | |
46 | outer: env_ptr; | |
47 | data: mal_val_ptr; | |
48 | end record env_record; | |
49 | ||
50 | procedure new_nil(obj: out mal_val_ptr); | |
51 | procedure new_true(obj: out mal_val_ptr); | |
52 | procedure new_false(obj: out mal_val_ptr); | |
53 | procedure new_boolean(b: in boolean; obj: out mal_val_ptr); | |
54 | procedure new_number(v: in integer; obj: out mal_val_ptr); | |
55 | procedure new_symbol(name: in string; obj: out mal_val_ptr); | |
56 | procedure new_symbol(name: inout line; obj: out mal_val_ptr); | |
57 | procedure new_string(name: in string; obj: out mal_val_ptr); | |
58 | procedure new_string(name: inout line; obj: out mal_val_ptr); | |
59 | procedure new_keyword(name: in string; obj: out mal_val_ptr); | |
60 | procedure new_keyword(name: inout line; obj: out mal_val_ptr); | |
61 | procedure new_nativefn(name: in string; obj: out mal_val_ptr); | |
62 | procedure new_fn(body_ast: inout mal_val_ptr; args: inout mal_val_ptr; env: inout env_ptr; obj: out mal_val_ptr); | |
63 | procedure new_seq_obj(seq_type: in mal_type_tag; seq: inout mal_seq_ptr; obj: out mal_val_ptr); | |
64 | procedure new_one_element_list(val: inout mal_val_ptr; obj: out mal_val_ptr); | |
65 | procedure new_empty_hashmap(obj: out mal_val_ptr); | |
66 | procedure new_atom(val: inout mal_val_ptr; obj: out mal_val_ptr); | |
67 | ||
68 | procedure hashmap_copy(hashmap: inout mal_val_ptr; obj: out mal_val_ptr); | |
69 | procedure hashmap_get(hashmap: inout mal_val_ptr; key: inout mal_val_ptr; val: out mal_val_ptr); | |
70 | procedure hashmap_contains(hashmap: inout mal_val_ptr; key: inout mal_val_ptr; ok: out boolean); | |
71 | procedure hashmap_put(hashmap: inout mal_val_ptr; key: inout mal_val_ptr; val: inout mal_val_ptr); | |
72 | procedure hashmap_delete(hashmap: inout mal_val_ptr; key: inout mal_val_ptr); | |
73 | procedure seq_drop_prefix(src: inout mal_val_ptr; prefix_length: in integer; result: out mal_val_ptr); | |
74 | function is_sequential_type(t: in mal_type_tag) return boolean; | |
75 | procedure equal_q(a: inout mal_val_ptr; b: inout mal_val_ptr; result: out boolean); | |
76 | end package types; | |
77 | ||
78 | package body types is | |
79 | ||
80 | procedure debugline(l: inout line) is | |
81 | variable l2: line; | |
82 | begin | |
83 | l2 := new string(1 to 7 + l'length); | |
84 | l2(1 to l2'length) := "DEBUG: " & l.all; | |
85 | writeline(output, l2); | |
86 | end procedure debugline; | |
87 | ||
88 | procedure debug(str: in string) is | |
89 | variable d: line; | |
90 | begin | |
91 | write(d, str); | |
92 | debugline(d); | |
93 | end procedure debug; | |
94 | ||
95 | procedure debug(ch: in character) is | |
96 | variable d: line; | |
97 | begin | |
98 | write(d, ch); | |
99 | debugline(d); | |
100 | end procedure debug; | |
101 | ||
102 | procedure debug(i: in integer) is | |
103 | variable d: line; | |
104 | begin | |
105 | write(d, i); | |
106 | debugline(d); | |
107 | end procedure debug; | |
108 | ||
109 | procedure new_nil(obj: out mal_val_ptr) is | |
110 | begin | |
111 | obj := new mal_val'(val_type => mal_nil, number_val => 0, string_val => null, seq_val => null, func_val => null, meta_val => null); | |
112 | end procedure new_nil; | |
113 | ||
114 | procedure new_true(obj: out mal_val_ptr) is | |
115 | begin | |
116 | obj := new mal_val'(val_type => mal_true, number_val => 0, string_val => null, seq_val => null, func_val => null, meta_val => null); | |
117 | end procedure new_true; | |
118 | ||
119 | procedure new_false(obj: out mal_val_ptr) is | |
120 | begin | |
121 | obj := new mal_val'(val_type => mal_false, number_val => 0, string_val => null, seq_val => null, func_val => null, meta_val => null); | |
122 | end procedure new_false; | |
123 | ||
124 | procedure new_boolean(b: in boolean; obj: out mal_val_ptr) is | |
125 | begin | |
126 | if b then | |
127 | new_true(obj); | |
128 | else | |
129 | new_false(obj); | |
130 | end if; | |
131 | end procedure new_boolean; | |
132 | ||
133 | procedure new_number(v: in integer; obj: out mal_val_ptr) is | |
134 | begin | |
135 | obj := new mal_val'(val_type => mal_number, number_val => v, string_val => null, seq_val => null, func_val => null, meta_val => null); | |
136 | end procedure new_number; | |
137 | ||
138 | procedure new_symbol(name: in string; obj: out mal_val_ptr) is | |
139 | begin | |
140 | obj := new mal_val'(val_type => mal_symbol, number_val => 0, string_val => new string'(name), seq_val => null, func_val => null, meta_val => null); | |
141 | end procedure new_symbol; | |
142 | ||
143 | procedure new_symbol(name: inout line; obj: out mal_val_ptr) is | |
144 | begin | |
145 | obj := new mal_val'(val_type => mal_symbol, number_val => 0, string_val => name, seq_val => null, func_val => null, meta_val => null); | |
146 | end procedure new_symbol; | |
147 | ||
148 | procedure new_string(name: in string; obj: out mal_val_ptr) is | |
149 | begin | |
150 | obj := new mal_val'(val_type => mal_string, number_val => 0, string_val => new string'(name), seq_val => null, func_val => null, meta_val => null); | |
151 | end procedure new_string; | |
152 | ||
153 | procedure new_string(name: inout line; obj: out mal_val_ptr) is | |
154 | begin | |
155 | obj := new mal_val'(val_type => mal_string, number_val => 0, string_val => name, seq_val => null, func_val => null, meta_val => null); | |
156 | end procedure new_string; | |
157 | ||
158 | procedure new_keyword(name: in string; obj: out mal_val_ptr) is | |
159 | begin | |
160 | obj := new mal_val'(val_type => mal_keyword, number_val => 0, string_val => new string'(name), seq_val => null, func_val => null, meta_val => null); | |
161 | end procedure new_keyword; | |
162 | ||
163 | procedure new_keyword(name: inout line; obj: out mal_val_ptr) is | |
164 | begin | |
165 | obj := new mal_val'(val_type => mal_keyword, number_val => 0, string_val => name, seq_val => null, func_val => null, meta_val => null); | |
166 | end procedure new_keyword; | |
167 | ||
168 | procedure new_nativefn(name: in string; obj: out mal_val_ptr) is | |
169 | begin | |
170 | obj := new mal_val'(val_type => mal_nativefn, number_val => 0, string_val => new string'(name), seq_val => null, func_val => null, meta_val => null); | |
171 | end procedure new_nativefn; | |
172 | ||
173 | procedure new_fn(body_ast: inout mal_val_ptr; args: inout mal_val_ptr; env: inout env_ptr; obj: out mal_val_ptr) is | |
174 | variable f: mal_func_ptr; | |
175 | begin | |
176 | f := new mal_func'(f_body => body_ast, f_args => args, f_env => env, f_is_macro => false); | |
177 | obj := new mal_val'(val_type => mal_fn, number_val => 0, string_val => null, seq_val => null, func_val => f, meta_val => null); | |
178 | end procedure new_fn; | |
179 | ||
180 | procedure new_seq_obj(seq_type: in mal_type_tag; seq: inout mal_seq_ptr; obj: out mal_val_ptr) is | |
181 | begin | |
182 | obj := new mal_val'(val_type => seq_type, number_val => 0, string_val => null, seq_val => seq, func_val => null, meta_val => null); | |
183 | end procedure new_seq_obj; | |
184 | ||
185 | procedure new_one_element_list(val: inout mal_val_ptr; obj: out mal_val_ptr) is | |
186 | variable seq: mal_seq_ptr; | |
187 | begin | |
188 | seq := new mal_seq(0 to 0); | |
189 | seq(0) := val; | |
190 | new_seq_obj(mal_list, seq, obj); | |
191 | end procedure new_one_element_list; | |
192 | ||
193 | procedure new_empty_hashmap(obj: out mal_val_ptr) is | |
194 | variable seq: mal_seq_ptr; | |
195 | begin | |
196 | seq := new mal_seq(0 to -1); | |
197 | new_seq_obj(mal_hashmap, seq, obj); | |
198 | end procedure new_empty_hashmap; | |
199 | ||
200 | procedure new_atom(val: inout mal_val_ptr; obj: out mal_val_ptr) is | |
201 | variable atom_seq: mal_seq_ptr; | |
202 | begin | |
203 | atom_seq := new mal_seq(0 to 0); | |
204 | atom_seq(0) := val; | |
205 | new_seq_obj(mal_atom, atom_seq, obj); | |
206 | end procedure new_atom; | |
207 | ||
208 | procedure hashmap_copy(hashmap: inout mal_val_ptr; obj: out mal_val_ptr) is | |
209 | variable new_seq: mal_seq_ptr; | |
210 | begin | |
211 | new_seq := new mal_seq(hashmap.seq_val'range); | |
212 | new_seq(new_seq'range) := hashmap.seq_val(hashmap.seq_val'range); | |
213 | new_seq_obj(mal_hashmap, new_seq, obj); | |
214 | end procedure hashmap_copy; | |
215 | ||
216 | procedure hashmap_get(hashmap: inout mal_val_ptr; key: inout mal_val_ptr; val: out mal_val_ptr) is | |
217 | variable i: natural; | |
218 | variable curr_key: mal_val_ptr; | |
219 | begin | |
220 | i := 0; | |
221 | while i < hashmap.seq_val'length loop | |
222 | curr_key := hashmap.seq_val(i); | |
223 | if key.val_type = curr_key.val_type and key.string_val.all = curr_key.string_val.all then | |
224 | val := hashmap.seq_val(i + 1); | |
225 | return; | |
226 | end if; | |
227 | i := i + 2; | |
228 | end loop; | |
229 | val := null; | |
230 | end procedure hashmap_get; | |
231 | ||
232 | procedure hashmap_contains(hashmap: inout mal_val_ptr; key: inout mal_val_ptr; ok: out boolean) is | |
233 | variable val: mal_val_ptr; | |
234 | begin | |
235 | hashmap_get(hashmap, key, val); | |
236 | if val = null then | |
237 | ok := false; | |
238 | else | |
239 | ok := true; | |
240 | end if; | |
241 | end procedure hashmap_contains; | |
242 | ||
243 | procedure hashmap_put(hashmap: inout mal_val_ptr; key: inout mal_val_ptr; val: inout mal_val_ptr) is | |
244 | variable i: natural; | |
245 | variable curr_key: mal_val_ptr; | |
246 | variable new_seq: mal_seq_ptr; | |
247 | begin | |
248 | i := 0; | |
249 | while i < hashmap.seq_val'length loop | |
250 | curr_key := hashmap.seq_val(i); | |
251 | if key.val_type = curr_key.val_type and key.string_val.all = curr_key.string_val.all then | |
252 | hashmap.seq_val(i + 1) := val; | |
253 | return; | |
254 | end if; | |
255 | i := i + 2; | |
256 | end loop; | |
257 | -- Not found so far, need to extend the seq | |
258 | new_seq := new mal_seq(0 to hashmap.seq_val'length + 1); | |
259 | for i in hashmap.seq_val'range loop | |
260 | new_seq(i) := hashmap.seq_val(i); | |
261 | end loop; | |
262 | new_seq(new_seq'length - 2) := key; | |
263 | new_seq(new_seq'length - 1) := val; | |
264 | deallocate(hashmap.seq_val); | |
265 | hashmap.seq_val := new_seq; | |
266 | end procedure hashmap_put; | |
267 | ||
268 | procedure hashmap_delete(hashmap: inout mal_val_ptr; key: inout mal_val_ptr) is | |
269 | variable i, dst_i: natural; | |
270 | variable curr_key: mal_val_ptr; | |
271 | variable new_seq: mal_seq_ptr; | |
272 | variable found: boolean; | |
273 | begin | |
274 | hashmap_contains(hashmap, key, found); | |
275 | if not found then | |
276 | return; | |
277 | end if; | |
278 | i := 0; | |
279 | dst_i := 0; | |
280 | new_seq := new mal_seq(0 to hashmap.seq_val'high - 2); | |
281 | while i < hashmap.seq_val'length loop | |
282 | curr_key := hashmap.seq_val(i); | |
283 | if key.val_type = curr_key.val_type and key.string_val.all = curr_key.string_val.all then | |
284 | i := i + 2; | |
285 | else | |
286 | new_seq(dst_i to dst_i + 1) := hashmap.seq_val(i to i + 1); | |
287 | dst_i := dst_i + 2; | |
288 | i := i + 2; | |
289 | end if; | |
290 | end loop; | |
291 | deallocate(hashmap.seq_val); | |
292 | hashmap.seq_val := new_seq; | |
293 | end procedure hashmap_delete; | |
294 | ||
295 | procedure seq_drop_prefix(src: inout mal_val_ptr; prefix_length: in integer; result: out mal_val_ptr) is | |
296 | variable seq: mal_seq_ptr; | |
297 | begin | |
298 | seq := new mal_seq(0 to src.seq_val'length - 1 - prefix_length); | |
299 | for i in seq'range loop | |
300 | seq(i) := src.seq_val(i + prefix_length); | |
301 | end loop; | |
302 | new_seq_obj(src.val_type, seq, result); | |
303 | end procedure seq_drop_prefix; | |
304 | ||
305 | function is_sequential_type(t: in mal_type_tag) return boolean is | |
306 | begin | |
307 | return t = mal_list or t = mal_vector; | |
308 | end function is_sequential_type; | |
309 | ||
310 | procedure equal_seq_q(a: inout mal_val_ptr; b: inout mal_val_ptr; result: out boolean) is | |
311 | variable i: integer; | |
312 | variable is_element_equal: boolean; | |
313 | begin | |
314 | if a.seq_val'length = b.seq_val'length then | |
315 | for i in a.seq_val'range loop | |
316 | equal_q(a.seq_val(i), b.seq_val(i), is_element_equal); | |
317 | if not is_element_equal then | |
318 | result := false; | |
319 | return; | |
320 | end if; | |
321 | end loop; | |
322 | result := true; | |
323 | else | |
324 | result := false; | |
325 | end if; | |
326 | end procedure equal_seq_q; | |
327 | ||
328 | procedure equal_hashmap_q(a: inout mal_val_ptr; b: inout mal_val_ptr; result: out boolean) is | |
329 | variable i: integer; | |
330 | variable is_value_equal: boolean; | |
331 | variable b_val: mal_val_ptr; | |
332 | begin | |
333 | if a.seq_val'length = b.seq_val'length then | |
334 | i := 0; | |
335 | while i < a.seq_val'length loop | |
336 | hashmap_get(b, a.seq_val(i), b_val); | |
337 | if b_val = null then | |
338 | result := false; | |
339 | return; | |
340 | else | |
341 | equal_q(a.seq_val(i + 1), b_val, is_value_equal); | |
342 | if not is_value_equal then | |
343 | result := false; | |
344 | return; | |
345 | end if; | |
346 | end if; | |
347 | i := i + 2; | |
348 | end loop; | |
349 | result := true; | |
350 | else | |
351 | result := false; | |
352 | end if; | |
353 | end procedure equal_hashmap_q; | |
354 | ||
355 | procedure equal_q(a: inout mal_val_ptr; b: inout mal_val_ptr; result: out boolean) is | |
356 | begin | |
357 | if is_sequential_type(a.val_type) and is_sequential_type(b.val_type) then | |
358 | equal_seq_q(a, b, result); | |
359 | elsif a.val_type = b.val_type then | |
360 | case a.val_type is | |
361 | when mal_nil | mal_true | mal_false => | |
362 | result := true; | |
363 | when mal_number => | |
364 | result := a.number_val = b.number_val; | |
365 | when mal_symbol | mal_string | mal_keyword => | |
366 | result := a.string_val.all = b.string_val.all; | |
367 | when mal_hashmap => | |
368 | equal_hashmap_q(a, b, result); | |
369 | when mal_atom => | |
370 | equal_q(a.seq_val(0), b.seq_val(0), result); | |
371 | when others => | |
372 | result := false; | |
373 | end case; | |
374 | else | |
375 | result := false; | |
376 | end if; | |
377 | end procedure equal_q; | |
378 | end package body types; |