Add lrexlib-pcre through luarocks.
[jackhill/mal.git] / impls / 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
2866f9a8 18 M types.mal_table; -- general mal value memory pool
6a085103
JM
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;
2866f9a8 24 core_ns core_ns_T;
06951f55 25 cidx integer;
2866f9a8 26 argv mal_vals;
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;
2866f9a8 38 FUNCTION do_builtin(fn integer, args mal_vals) RETURN integer;
06951f55 39
0fc03918 40 FUNCTION eval_ast(ast integer, env integer) RETURN integer IS
6a085103 41 i integer;
2866f9a8
JM
42 old_seq mal_vals;
43 new_seq mal_vals;
6a085103
JM
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 51 ELSIF M(ast).type_id IN (8,9) THEN
2866f9a8
JM
52 old_seq := TREAT(M(ast) AS mal_seq_T).val_seq;
53 new_seq := mal_vals();
06951f55
JM
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 59 ELSIF M(ast).type_id IN (10) THEN
2866f9a8
JM
60 new_hm := types.hash_map(M, H, mal_vals());
61 old_midx := TREAT(M(ast) AS mal_map_T).map_idx;
62 new_midx := TREAT(M(new_hm) AS mal_map_T).map_idx;
6a085103
JM
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);
2866f9a8 81 seq mal_vals;
06951f55 82 let_env integer;
06951f55 83 i integer;
0fc03918
JM
84 f integer;
85 cond integer;
2866f9a8
JM
86 malfn mal_func_T;
87 args mal_vals;
06951f55 88 BEGIN
0fc03918 89 WHILE TRUE LOOP
2866f9a8 90 -- io.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
2866f9a8 101 a0sym := TREAT(M(a0) AS mal_str_T).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);
2866f9a8 112 seq := TREAT(M(types.nth(M, ast, 1)) AS mal_seq_T).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);
2866f9a8 143 args := TREAT(M(types.slice(M, el, 1)) AS mal_seq_T).val_seq;
0fc03918 144 IF M(f).type_id = 12 THEN
2866f9a8 145 malfn := TREAT(M(f) AS mal_func_T);
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.
2866f9a8 162 FUNCTION do_builtin(fn integer, args mal_vals) RETURN integer IS
06951f55 163 fname varchar2(100);
150011e4 164 val integer;
0fc03918 165 f integer;
2866f9a8
JM
166 malfn mal_func_T;
167 fargs mal_vals;
06951f55
JM
168 fn_env integer;
169 BEGIN
2866f9a8 170 fname := TREAT(M(fn) AS mal_str_T).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
2866f9a8 175 val := TREAT(M(args(1)) AS mal_atom_T).val;
150011e4 176 f := args(2);
06951f55
JM
177 -- slice one extra at the beginning that will be changed
178 -- to the value of the atom
2866f9a8 179 fargs := TREAT(M(types.slice(M, args, 1)) AS mal_seq_T).val_seq;
150011e4 180 fargs(1) := val;
0fc03918 181 IF M(f).type_id = 12 THEN
2866f9a8 182 malfn := TREAT(M(f) AS mal_func_T);
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;
2866f9a8 189 RETURN types.atom_reset(M, args(1), val);
06951f55 190 ELSE
6a085103 191 RETURN core.do_core_func(M, H, fn, args);
06951f55
JM
192 END CASE;
193 END;
194
195
196 -- print
0fc03918 197 FUNCTION PRINT(exp integer) RETURN varchar IS
06951f55 198 BEGIN
6a085103 199 RETURN printer.pr_str(M, H, exp);
06951f55
JM
200 END;
201
202 -- repl
203 FUNCTION REP(line varchar) RETURN varchar IS
204 BEGIN
205 RETURN PRINT(EVAL(READ(line), repl_env));
206 END;
207
208BEGIN
6a085103 209 -- initialize memory pools
0fc03918 210 M := types.mem_new();
6a085103 211 H := types.map_entry_table();
10cc781f 212 E := env_pkg.env_entry_table();
0fc03918 213
10cc781f
JM
214 repl_env := env_pkg.env_new(M, E, NULL);
215
2866f9a8 216 argv := TREAT(M(reader.read_str(M, H, args)) AS mal_seq_T).val_seq;
06951f55
JM
217
218 -- core.EXT: defined using PL/SQL
0fc03918 219 core_ns := core.get_core_ns();
06951f55 220 FOR cidx IN 1..core_ns.COUNT LOOP
10cc781f 221 x := env_pkg.env_set(M, E, repl_env,
0fc03918
JM
222 types.symbol(M, core_ns(cidx)),
223 types.func(M, core_ns(cidx)));
06951f55 224 END LOOP;
10cc781f 225 x := env_pkg.env_set(M, E, repl_env,
0fc03918
JM
226 types.symbol(M, 'eval'),
227 types.func(M, 'do_eval'));
10cc781f 228 x := env_pkg.env_set(M, E, repl_env,
0fc03918 229 types.symbol(M, '*ARGV*'),
10cc781f 230 types.slice(M, argv, 1));
06951f55
JM
231
232 -- core.mal: defined using the language itself
233 line := REP('(def! not (fn* (a) (if a false true)))');
e6d41de4 234 line := REP('(def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) "\nnil)")))))');
06951f55 235
10cc781f 236 IF argv.COUNT() > 0 THEN
8119e744
JM
237 BEGIN
238 line := REP('(load-file "' ||
2866f9a8 239 TREAT(M(argv(1)) AS mal_str_T).val_str ||
8119e744
JM
240 '")');
241 io.close(1); -- close output stream
242 RETURN 0;
243 EXCEPTION WHEN OTHERS THEN
244 io.writeline('Error: ' || SQLERRM);
245 io.writeline(dbms_utility.format_error_backtrace);
246 io.close(1); -- close output stream
247 RAISE;
248 END;
10cc781f
JM
249 END IF;
250
06951f55
JM
251 WHILE true LOOP
252 BEGIN
02936b42
JM
253 line := io.readline('user> ', 0);
254 IF line = EMPTY_CLOB() THEN CONTINUE; END IF;
06951f55 255 IF line IS NOT NULL THEN
02936b42 256 io.writeline(REP(line));
06951f55
JM
257 END IF;
258
259 EXCEPTION WHEN OTHERS THEN
8119e744
JM
260 IF SQLCODE = -20001 THEN -- io read stream closed
261 io.close(1); -- close output stream
06951f55
JM
262 RETURN 0;
263 END IF;
02936b42
JM
264 io.writeline('Error: ' || SQLERRM);
265 io.writeline(dbms_utility.format_error_backtrace);
06951f55
JM
266 END;
267 END LOOP;
268END;
269
0fc03918 270END mal;
06951f55
JM
271/
272show errors;
273
274quit;