Merge pull request #383 from asarhaddon/ada2tco-do
[jackhill/mal.git] / vhdl / step5_tco.vhdl
CommitLineData
36e91db4
DM
1entity step5_tco is
2end entity step5_tco;
3
4library STD;
5use STD.textio.all;
6library WORK;
7use WORK.pkg_readline.all;
8use WORK.types.all;
9use WORK.printer.all;
10use WORK.reader.all;
11use WORK.env.all;
12use WORK.core.all;
13
14architecture test of step5_tco is
15 procedure mal_READ(str: in string; ast: out mal_val_ptr; err: out mal_val_ptr) is
16 begin
17 read_str(str, ast, err);
18 end procedure mal_READ;
19
20 -- Forward declaration
21 procedure EVAL(in_ast: inout mal_val_ptr; in_env: inout env_ptr; result: out mal_val_ptr; err: out mal_val_ptr);
22
23 procedure eval_ast_seq(ast_seq: inout mal_seq_ptr; env: inout env_ptr; result: inout mal_seq_ptr; err: out mal_val_ptr) is
24 variable eval_err: mal_val_ptr;
25 begin
26 result := new mal_seq(0 to ast_seq'length - 1);
27 for i in result'range loop
28 EVAL(ast_seq(i), env, result(i), eval_err);
29 if eval_err /= null then
30 err := eval_err;
31 return;
32 end if;
33 end loop;
34 end procedure eval_ast_seq;
35
36 procedure eval_ast(ast: inout mal_val_ptr; env: inout env_ptr; result: out mal_val_ptr; err: out mal_val_ptr) is
37 variable key, val, eval_err, env_err: mal_val_ptr;
38 variable new_seq: mal_seq_ptr;
39 variable i: integer;
40 begin
41 case ast.val_type is
42 when mal_symbol =>
43 env_get(env, ast, val, env_err);
44 if env_err /= null then
45 err := env_err;
46 return;
47 end if;
48 result := val;
49 return;
50 when mal_list | mal_vector | mal_hashmap =>
51 eval_ast_seq(ast.seq_val, env, new_seq, eval_err);
52 if eval_err /= null then
53 err := eval_err;
54 return;
55 end if;
56 new_seq_obj(ast.val_type, new_seq, result);
57 return;
58 when others =>
59 result := ast;
60 return;
61 end case;
62 end procedure eval_ast;
63
64 procedure EVAL(in_ast: inout mal_val_ptr; in_env: inout env_ptr; result: out mal_val_ptr; err: out mal_val_ptr) is
65 variable i: integer;
66 variable ast, evaled_ast, a0, call_args, val, vars, sub_err, fn: mal_val_ptr;
67 variable env, let_env, fn_env: env_ptr;
68 begin
69 ast := in_ast;
70 env := in_env;
71 loop
72 if ast.val_type /= mal_list then
73 eval_ast(ast, env, result, err);
74 return;
75 end if;
76
77 if ast.seq_val'length = 0 then
78 result := ast;
79 return;
80 end if;
81
82 a0 := ast.seq_val(0);
83 if a0.val_type = mal_symbol then
84 if a0.string_val.all = "def!" then
85 EVAL(ast.seq_val(2), env, val, sub_err);
86 if sub_err /= null then
87 err := sub_err;
88 return;
89 end if;
90 env_set(env, ast.seq_val(1), val);
91 result := val;
92 return;
93
94 elsif a0.string_val.all = "let*" then
95 vars := ast.seq_val(1);
96 new_env(let_env, env);
97 i := 0;
98 while i < vars.seq_val'length loop
99 EVAL(vars.seq_val(i + 1), let_env, val, sub_err);
100 if sub_err /= null then
101 err := sub_err;
102 return;
103 end if;
104 env_set(let_env, vars.seq_val(i), val);
105 i := i + 2;
106 end loop;
107 env := let_env;
108 ast := ast.seq_val(2);
109 next; -- TCO
110
111 elsif a0.string_val.all = "do" then
112 for i in 1 to ast.seq_val'high - 1 loop
113 EVAL(ast.seq_val(i), env, result, sub_err);
114 if sub_err /= null then
115 err := sub_err;
116 return;
117 end if;
118 end loop;
119 ast := ast.seq_val(ast.seq_val'high);
120 next; -- TCO
121
122 elsif a0.string_val.all = "if" then
123 EVAL(ast.seq_val(1), env, val, sub_err);
124 if sub_err /= null then
125 err := sub_err;
126 return;
127 end if;
128 if val.val_type = mal_nil or val.val_type = mal_false then
129 if ast.seq_val'length > 3 then
130 ast := ast.seq_val(3);
131 else
132 new_nil(result);
133 return;
134 end if;
135 else
136 ast := ast.seq_val(2);
137 end if;
138 next; -- TCO
139
140 elsif a0.string_val.all = "fn*" then
141 new_fn(ast.seq_val(2), ast.seq_val(1), env, result);
142 return;
143
144 end if;
145 end if;
146
147 eval_ast(ast, env, evaled_ast, sub_err);
148 if sub_err /= null then
149 err := sub_err;
150 return;
151 end if;
152 seq_drop_prefix(evaled_ast, 1, call_args);
153 fn := evaled_ast.seq_val(0);
154 case fn.val_type is
155 when mal_nativefn =>
156 eval_native_func(fn, call_args, result, err);
157 return;
158 when mal_fn =>
159 new_env(fn_env, fn.func_val.f_env, fn.func_val.f_args, call_args);
160 env := fn_env;
161 ast := fn.func_val.f_body;
162 next; -- TCO
163 when others =>
164 new_string("not a function", err);
165 return;
166 end case;
167 end loop;
168 end procedure EVAL;
169
170 procedure mal_PRINT(exp: inout mal_val_ptr; result: out line) is
171 begin
172 pr_str(exp, true, result);
173 end procedure mal_PRINT;
174
175 procedure RE(str: in string; env: inout env_ptr; result: out mal_val_ptr; err: out mal_val_ptr) is
176 variable ast, read_err: mal_val_ptr;
177 begin
178 mal_READ(str, ast, read_err);
179 if read_err /= null then
180 err := read_err;
181 result := null;
182 return;
183 end if;
184 if ast = null then
185 result := null;
186 return;
187 end if;
188 EVAL(ast, env, result, err);
189 end procedure RE;
190
191 procedure REP(str: in string; env: inout env_ptr; result: out line; err: out mal_val_ptr) is
192 variable eval_res, eval_err: mal_val_ptr;
193 begin
194 RE(str, env, eval_res, eval_err);
195 if eval_err /= null then
196 err := eval_err;
197 result := null;
198 return;
199 end if;
200 mal_PRINT(eval_res, result);
201 end procedure REP;
202
203 procedure repl is
204 variable is_eof: boolean;
205 variable input_line, result: line;
206 variable dummy_val, err: mal_val_ptr;
207 variable outer, repl_env: env_ptr;
208 begin
209 outer := null;
210 new_env(repl_env, outer);
211
212 -- core.EXT: defined using VHDL (see core.vhdl)
213 define_core_functions(repl_env);
214
215 -- core.mal: defined using the language itself
216 RE("(def! not (fn* (a) (if a false true)))", repl_env, dummy_val, err);
217
218 loop
219 mal_readline("user> ", is_eof, input_line);
220 exit when is_eof;
221 next when input_line'length = 0;
222 REP(input_line.all, repl_env, result, err);
223 if err /= null then
224 pr_str(err, false, result);
225 result := new string'("Error: " & result.all);
226 end if;
227 if result /= null then
228 mal_printline(result.all);
229 end if;
230 deallocate(result);
231 deallocate(err);
232 end loop;
233 mal_printline("");
234 end procedure repl;
235
236begin
237 repl;
238end architecture test;