8 CREATE OR REPLACE PACKAGE mal
IS
10 FUNCTION MAIN(pwd
varchar) RETURN integer;
15 CREATE OR REPLACE PACKAGE BODY mal
IS
17 FUNCTION MAIN(pwd
varchar) RETURN integer IS
27 FUNCTION READ(line
varchar) RETURN integer IS
29 RETURN reader.
read_str(M
, line
);
34 -- forward declarations
35 FUNCTION EVAL(orig_ast
integer, orig_env
integer) RETURN integer;
36 FUNCTION do_builtin(fn
integer, args mal_seq_type
) RETURN integer;
38 FUNCTION is_pair(ast
integer) RETURN BOOLEAN IS
40 RETURN M(ast
).type_id
IN (8,9) AND types.
count(M
, ast
) > 0;
43 FUNCTION quasiquote(ast
integer) RETURN integer IS
47 IF NOT is_pair(ast
) THEN
48 RETURN types.
list(M
, types.
symbol(M
, 'quote'), ast
);
50 a0
:= types.
nth(M
, ast
, 0);
51 IF M(a0
).type_id
= 7 AND
52 TREAT(m(a0
) AS mal_str_type
).val_str
= 'unquote' THEN
53 RETURN types.
nth(M
, ast
, 1);
54 ELSIF
is_pair(a0
) THEN
55 a00
:= types.
nth(M
, a0
, 0);
56 IF M(a00
).type_id
= 7 AND
57 TREAT(M(a00
) AS mal_str_type
).val_str
= 'splice-unquote' THEN
58 RETURN types.
list(M
, types.
symbol(M
, 'concat'),
60 quasiquote(types.
slice(M
, ast
, 1)));
63 RETURN types.
list(M
, types.
symbol(M
, 'cons'),
65 quasiquote(types.
slice(M
, ast
, 1)));
69 FUNCTION eval_ast(ast
integer, env
integer) RETURN integer IS
71 old_seq mal_seq_items_type
;
72 new_seq mal_seq_items_type
;
74 IF M(ast
).type_id
= 7 THEN
75 RETURN env_pkg.
env_get(M
, env_mem
, env
, ast
);
76 ELSIF
M(ast
).type_id
IN (8,9) THEN
77 old_seq
:= TREAT(M(ast
) AS mal_seq_type
).val_seq
;
78 new_seq
:= mal_seq_items_type();
79 new_seq.
EXTEND(old_seq.
COUNT);
80 FOR i
IN 1..old_seq.
COUNT LOOP
81 new_seq(i
) := EVAL(old_seq(i
), env
);
83 RETURN types.
seq(M
, M(ast
).type_id
, new_seq
);
89 FUNCTION EVAL(orig_ast
integer, orig_env
integer) RETURN integer IS
90 ast
integer := orig_ast
;
91 env
integer := orig_env
;
95 seq mal_seq_items_type
;
104 IF M(ast
).type_id
<> 8 THEN
105 RETURN eval_ast(ast
, env
);
109 a0
:= types.
first(M
, ast
);
110 if M(a0
).type_id
= 7 THEN -- symbol
111 a0sym
:= TREAT(M(a0
) AS mal_str_type
).val_str
;
113 a0sym
:= '__<*fn*>__';
117 WHEN a0sym
= 'def!' THEN
118 RETURN env_pkg.
env_set(M
, env_mem
, env
,
119 types.
nth(M
, ast
, 1), EVAL(types.
nth(M
, ast
, 2), env
));
120 WHEN a0sym
= 'let*' THEN
121 let_env
:= env_pkg.
env_new(M
, env_mem
, env
);
122 seq
:= TREAT(M(types.
nth(M
, ast
, 1)) AS mal_seq_type
).val_seq
;
124 WHILE i
<= seq.
COUNT LOOP
125 x
:= env_pkg.
env_set(M
, env_mem
, let_env
,
126 seq(i
), EVAL(seq(i
+1), let_env
));
130 ast
:= types.
nth(M
, ast
, 2); -- TCO
131 WHEN a0sym
= 'quote' THEN
132 RETURN types.
nth(M
, ast
, 1);
133 WHEN a0sym
= 'quasiquote' THEN
134 RETURN EVAL(quasiquote(types.
nth(M
, ast
, 1)), env
);
135 WHEN a0sym
= 'do' THEN
136 x
:= types.
slice(M
, ast
, 1, types.
count(M
, ast
)-2);
137 x
:= eval_ast(x
, env
);
138 ast
:= types.
nth(M
, ast
, types.
count(M
, ast
)-1); -- TCO
139 WHEN a0sym
= 'if' THEN
140 cond
:= EVAL(types.
nth(M
, ast
, 1), env
);
141 IF cond
= 1 OR cond
= 2 THEN -- nil or false
142 IF types.
count(M
, ast
) > 3 THEN
143 ast
:= EVAL(types.
nth(M
, ast
, 3), env
); -- TCO
148 ast
:= EVAL(types.
nth(M
, ast
, 2), env
); -- TCO
150 WHEN a0sym
= 'fn*' THEN
151 RETURN types.
malfunc(M
, types.
nth(M
, ast
, 2),
152 types.
nth(M
, ast
, 1),
155 el
:= eval_ast(ast
, env
);
156 f
:= types.
first(M
, el
);
157 args
:= TREAT(M(types.
slice(M
, el
, 1)) AS mal_seq_type
);
158 IF M(f
).type_id
= 12 THEN
159 malfn
:= TREAT(M(f
) AS malfunc_type
);
160 env
:= env_pkg.
env_new(M
, env_mem
, malfn.env
,
162 ast
:= malfn.ast
; -- TCO
164 RETURN do_builtin(f
, args
);
172 -- hack to get around lack of function references
173 -- functions that require special access to repl_env or EVAL
174 -- are implemented directly here, otherwise, core.do_core_fn
176 FUNCTION do_builtin(fn
integer, args mal_seq_type
) RETURN integer IS
178 sargs mal_seq_items_type
:= args.val_seq
;
182 fargs mal_seq_items_type
;
185 fname
:= TREAT(M(fn
) AS mal_str_type
).val_str
;
187 WHEN fname
= 'do_eval' THEN
188 RETURN EVAL(sargs(1), repl_env
);
189 WHEN fname
= 'swap!' THEN
190 aval
:= TREAT(M(sargs(1)) AS mal_atom_type
).val
;
192 -- slice one extra at the beginning that will be changed
193 -- to the value of the atom
194 fargs
:= TREAT(M(types.
slice(M
, sargs
, 1)) AS mal_seq_type
).val_seq
;
196 IF M(f
).type_id
= 12 THEN
197 malfn
:= TREAT(M(f
) AS malfunc_type
);
198 fn_env
:= env_pkg.
env_new(M
, env_mem
, malfn.env
,
200 mal_seq_type(8, fargs
));
201 aval
:= EVAL(malfn.ast
, fn_env
);
203 aval
:= do_builtin(f
, mal_seq_type(8, fargs
));
205 M(sargs(1)) := mal_atom_type(13, aval
);
208 RETURN core.
do_core_func(M
, fn
, sargs
);
214 FUNCTION PRINT(exp integer) RETURN varchar IS
216 RETURN printer.
pr_str(M
, exp);
220 FUNCTION REP(line
varchar) RETURN varchar IS
222 RETURN PRINT(EVAL(READ(line
), repl_env
));
226 M
:= types.
mem_new();
227 env_mem
:= env_mem_type();
229 repl_env
:= env_pkg.
env_new(M
, env_mem
, NULL);
231 -- core.EXT: defined using PL/SQL
232 core_ns
:= core.
get_core_ns();
233 FOR cidx
IN 1..core_ns.
COUNT LOOP
234 x
:= env_pkg.
env_set(M
, env_mem
, repl_env
,
235 types.
symbol(M
, core_ns(cidx
)),
236 types.
func(M
, core_ns(cidx
)));
238 x
:= env_pkg.
env_set(M
, env_mem
, repl_env
,
239 types.
symbol(M
, 'eval'),
240 types.
func(M
, 'do_eval'));
241 x
:= env_pkg.
env_set(M
, env_mem
, repl_env
,
242 types.
symbol(M
, '*ARGV*'),
245 -- core.mal: defined using the language itself
246 line
:= REP('(def! not (fn* (a) (if a false true)))');
247 line
:= REP('(def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) ")")))))');
251 line
:= stream_readline('user> ', 0);
252 IF line
IS NULL THEN CONTINUE; END IF;
253 IF line
IS NOT NULL THEN
254 stream_writeline(REP(line
));
257 EXCEPTION WHEN OTHERS THEN
258 IF SQLCODE = -20000 THEN
261 stream_writeline('Error: ' || SQLERRM
);
262 stream_writeline(dbms_utility.format_error_backtrace
);