DISABLE FDs (REMOVE ME).
[jackhill/mal.git] / vhdl / types.vhdl
CommitLineData
36e91db4
DM
1library STD;
2use STD.textio.all;
3
4package 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);
76end package types;
77
78package 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;
378end package body types;