plsql: Fix readline/output async. Improve arg mode.
[jackhill/mal.git] / plsql / step6_file.sql
CommitLineData
06951f55
JM
1@io.sql
2@types.sql
3@reader.sql
4@printer.sql
5@env.sql
6@core.sql
7
0fc03918 8CREATE OR REPLACE PACKAGE mal IS
06951f55 9
10cc781f 10FUNCTION MAIN(args varchar DEFAULT '()') RETURN integer;
06951f55 11
0fc03918 12END mal;
06951f55
JM
13/
14
0fc03918 15CREATE OR REPLACE PACKAGE BODY mal IS
06951f55 16
10cc781f 17FUNCTION MAIN(args varchar DEFAULT '()') RETURN integer IS
6a085103
JM
18 M mem_type; -- general mal value memory pool
19 H types.map_entry_table; -- hashmap memory pool
20 E env_pkg.env_entry_table; -- mal env memory pool
06951f55 21 repl_env integer;
0fc03918 22 x integer;
02936b42 23 line CLOB;
06951f55
JM
24 core_ns core_ns_type;
25 cidx integer;
10cc781f 26 argv mal_seq_items_type;
06951f55
JM
27
28 -- read
0fc03918 29 FUNCTION READ(line varchar) RETURN integer IS
06951f55 30 BEGIN
6a085103 31 RETURN reader.read_str(M, H, line);
06951f55
JM
32 END;
33
34 -- eval
35
36 -- forward declarations
0fc03918 37 FUNCTION EVAL(orig_ast integer, orig_env integer) RETURN integer;
150011e4 38 FUNCTION do_builtin(fn integer, args mal_seq_items_type) RETURN integer;
06951f55 39
0fc03918 40 FUNCTION eval_ast(ast integer, env integer) RETURN integer IS
6a085103
JM
41 i integer;
42 old_seq mal_seq_items_type;
43 new_seq mal_seq_items_type;
44 new_hm integer;
45 old_midx integer;
46 new_midx integer;
47 k varchar2(256);
06951f55 48 BEGIN
0fc03918 49 IF M(ast).type_id = 7 THEN
10cc781f 50 RETURN env_pkg.env_get(M, E, env, ast);
0fc03918
JM
51 ELSIF M(ast).type_id IN (8,9) THEN
52 old_seq := TREAT(M(ast) AS mal_seq_type).val_seq;
06951f55
JM
53 new_seq := mal_seq_items_type();
54 new_seq.EXTEND(old_seq.COUNT);
55 FOR i IN 1..old_seq.COUNT LOOP
56 new_seq(i) := EVAL(old_seq(i), env);
57 END LOOP;
0fc03918 58 RETURN types.seq(M, M(ast).type_id, new_seq);
6a085103
JM
59 ELSIF M(ast).type_id IN (10) THEN
60 new_hm := types.hash_map(M, H, mal_seq_items_type());
61 old_midx := TREAT(M(ast) AS mal_map_type).map_idx;
62 new_midx := TREAT(M(new_hm) AS mal_map_type).map_idx;
63
64 k := H(old_midx).FIRST();
65 WHILE k IS NOT NULL LOOP
66 H(new_midx)(k) := EVAL(H(old_midx)(k), env);
67 k := H(old_midx).NEXT(k);
68 END LOOP;
69 RETURN new_hm;
06951f55
JM
70 ELSE
71 RETURN ast;
72 END IF;
73 END;
74
0fc03918
JM
75 FUNCTION EVAL(orig_ast integer, orig_env integer) RETURN integer IS
76 ast integer := orig_ast;
77 env integer := orig_env;
78 el integer;
79 a0 integer;
150011e4 80 a0sym varchar2(100);
06951f55
JM
81 seq mal_seq_items_type;
82 let_env integer;
06951f55 83 i integer;
0fc03918
JM
84 f integer;
85 cond integer;
06951f55 86 malfn malfunc_type;
150011e4 87 args mal_seq_items_type;
06951f55 88 BEGIN
0fc03918 89 WHILE TRUE LOOP
6a085103 90 -- stream_writeline('EVAL: ' || printer.pr_str(M, ast));
0fc03918 91 IF M(ast).type_id <> 8 THEN
06951f55
JM
92 RETURN eval_ast(ast, env);
93 END IF;
6a085103
JM
94 IF types.count(M, ast) = 0 THEN
95 RETURN ast; -- empty list just returned
96 END IF;
06951f55
JM
97
98 -- apply
0fc03918
JM
99 a0 := types.first(M, ast);
100 if M(a0).type_id = 7 THEN -- symbol
101 a0sym := TREAT(M(a0) AS mal_str_type).val_str;
06951f55
JM
102 ELSE
103 a0sym := '__<*fn*>__';
104 END IF;
105
106 CASE
107 WHEN a0sym = 'def!' THEN
10cc781f 108 RETURN env_pkg.env_set(M, E, env,
0fc03918 109 types.nth(M, ast, 1), EVAL(types.nth(M, ast, 2), env));
06951f55 110 WHEN a0sym = 'let*' THEN
10cc781f 111 let_env := env_pkg.env_new(M, E, env);
0fc03918 112 seq := TREAT(M(types.nth(M, ast, 1)) AS mal_seq_type).val_seq;
06951f55
JM
113 i := 1;
114 WHILE i <= seq.COUNT LOOP
10cc781f 115 x := env_pkg.env_set(M, E, let_env,
06951f55
JM
116 seq(i), EVAL(seq(i+1), let_env));
117 i := i + 2;
118 END LOOP;
0fc03918
JM
119 env := let_env;
120 ast := types.nth(M, ast, 2); -- TCO
06951f55 121 WHEN a0sym = 'do' THEN
0fc03918
JM
122 x := types.slice(M, ast, 1, types.count(M, ast)-2);
123 x := eval_ast(x, env);
124 ast := types.nth(M, ast, types.count(M, ast)-1); -- TCO
06951f55 125 WHEN a0sym = 'if' THEN
0fc03918
JM
126 cond := EVAL(types.nth(M, ast, 1), env);
127 IF cond = 1 OR cond = 2 THEN -- nil or false
128 IF types.count(M, ast) > 3 THEN
6a085103 129 ast := types.nth(M, ast, 3); -- TCO
06951f55 130 ELSE
0fc03918 131 RETURN 1; -- nil
06951f55
JM
132 END IF;
133 ELSE
6a085103 134 ast := types.nth(M, ast, 2); -- TCO
06951f55
JM
135 END IF;
136 WHEN a0sym = 'fn*' THEN
0fc03918
JM
137 RETURN types.malfunc(M, types.nth(M, ast, 2),
138 types.nth(M, ast, 1),
06951f55
JM
139 env);
140 ELSE
141 el := eval_ast(ast, env);
0fc03918 142 f := types.first(M, el);
150011e4 143 args := TREAT(M(types.slice(M, el, 1)) AS mal_seq_type).val_seq;
0fc03918
JM
144 IF M(f).type_id = 12 THEN
145 malfn := TREAT(M(f) AS malfunc_type);
10cc781f 146 env := env_pkg.env_new(M, E, malfn.env,
06951f55 147 malfn.params, args);
0fc03918 148 ast := malfn.ast; -- TCO
06951f55
JM
149 ELSE
150 RETURN do_builtin(f, args);
151 END IF;
152 END CASE;
153
0fc03918
JM
154 END LOOP;
155
06951f55
JM
156 END;
157
158 -- hack to get around lack of function references
0fc03918
JM
159 -- functions that require special access to repl_env or EVAL
160 -- are implemented directly here, otherwise, core.do_core_fn
06951f55 161 -- is called.
150011e4 162 FUNCTION do_builtin(fn integer, args mal_seq_items_type) RETURN integer IS
06951f55 163 fname varchar2(100);
150011e4 164 val integer;
0fc03918 165 f integer;
06951f55
JM
166 malfn malfunc_type;
167 fargs mal_seq_items_type;
168 fn_env integer;
169 BEGIN
0fc03918 170 fname := TREAT(M(fn) AS mal_str_type).val_str;
06951f55
JM
171 CASE
172 WHEN fname = 'do_eval' THEN
150011e4 173 RETURN EVAL(args(1), repl_env);
06951f55 174 WHEN fname = 'swap!' THEN
150011e4
JM
175 val := TREAT(M(args(1)) AS mal_atom_type).val;
176 f := args(2);
06951f55
JM
177 -- slice one extra at the beginning that will be changed
178 -- to the value of the atom
150011e4
JM
179 fargs := TREAT(M(types.slice(M, args, 1)) AS mal_seq_type).val_seq;
180 fargs(1) := val;
0fc03918
JM
181 IF M(f).type_id = 12 THEN
182 malfn := TREAT(M(f) AS malfunc_type);
10cc781f 183 fn_env := env_pkg.env_new(M, E, malfn.env,
150011e4
JM
184 malfn.params, fargs);
185 val := EVAL(malfn.ast, fn_env);
06951f55 186 ELSE
150011e4 187 val := do_builtin(f, fargs);
06951f55 188 END IF;
150011e4
JM
189 M(args(1)) := mal_atom_type(13, val);
190 RETURN val;
06951f55 191 ELSE
6a085103 192 RETURN core.do_core_func(M, H, fn, args);
06951f55
JM
193 END CASE;
194 END;
195
196
197 -- print
0fc03918 198 FUNCTION PRINT(exp integer) RETURN varchar IS
06951f55 199 BEGIN
6a085103 200 RETURN printer.pr_str(M, H, exp);
06951f55
JM
201 END;
202
203 -- repl
204 FUNCTION REP(line varchar) RETURN varchar IS
205 BEGIN
206 RETURN PRINT(EVAL(READ(line), repl_env));
207 END;
208
209BEGIN
6a085103 210 -- initialize memory pools
0fc03918 211 M := types.mem_new();
6a085103 212 H := types.map_entry_table();
10cc781f 213 E := env_pkg.env_entry_table();
0fc03918 214
10cc781f
JM
215 repl_env := env_pkg.env_new(M, E, NULL);
216
6a085103 217 argv := TREAT(M(reader.read_str(M, H, args)) AS mal_seq_type).val_seq;
06951f55
JM
218
219 -- core.EXT: defined using PL/SQL
0fc03918 220 core_ns := core.get_core_ns();
06951f55 221 FOR cidx IN 1..core_ns.COUNT LOOP
10cc781f 222 x := env_pkg.env_set(M, E, repl_env,
0fc03918
JM
223 types.symbol(M, core_ns(cidx)),
224 types.func(M, core_ns(cidx)));
06951f55 225 END LOOP;
10cc781f 226 x := env_pkg.env_set(M, E, repl_env,
0fc03918
JM
227 types.symbol(M, 'eval'),
228 types.func(M, 'do_eval'));
10cc781f 229 x := env_pkg.env_set(M, E, repl_env,
0fc03918 230 types.symbol(M, '*ARGV*'),
10cc781f 231 types.slice(M, argv, 1));
06951f55
JM
232
233 -- core.mal: defined using the language itself
234 line := REP('(def! not (fn* (a) (if a false true)))');
235 line := REP('(def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) ")")))))');
236
10cc781f 237 IF argv.COUNT() > 0 THEN
8119e744
JM
238 BEGIN
239 line := REP('(load-file "' ||
240 TREAT(M(argv(1)) AS mal_str_type).val_str ||
241 '")');
242 io.close(1); -- close output stream
243 RETURN 0;
244 EXCEPTION WHEN OTHERS THEN
245 io.writeline('Error: ' || SQLERRM);
246 io.writeline(dbms_utility.format_error_backtrace);
247 io.close(1); -- close output stream
248 RAISE;
249 END;
10cc781f
JM
250 END IF;
251
06951f55
JM
252 WHILE true LOOP
253 BEGIN
02936b42
JM
254 line := io.readline('user> ', 0);
255 IF line = EMPTY_CLOB() THEN CONTINUE; END IF;
06951f55 256 IF line IS NOT NULL THEN
02936b42 257 io.writeline(REP(line));
06951f55
JM
258 END IF;
259
260 EXCEPTION WHEN OTHERS THEN
8119e744
JM
261 IF SQLCODE = -20001 THEN -- io read stream closed
262 io.close(1); -- close output stream
06951f55
JM
263 RETURN 0;
264 END IF;
02936b42
JM
265 io.writeline('Error: ' || SQLERRM);
266 io.writeline(dbms_utility.format_error_backtrace);
06951f55
JM
267 END;
268 END LOOP;
269END;
270
0fc03918 271END mal;
06951f55
JM
272/
273show errors;
274
275quit;