8 CREATE OR REPLACE PACKAGE mal
IS
10 FUNCTION MAIN(args
varchar DEFAULT '()') RETURN integer;
15 CREATE OR REPLACE PACKAGE BODY mal
IS
17 FUNCTION MAIN(args
varchar DEFAULT '()') RETURN integer IS
18 M types.mal_table
; -- 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
28 FUNCTION READ(line
varchar) RETURN integer IS
30 RETURN reader.
read_str(M
, H
, line
);
35 -- forward declarations
36 FUNCTION EVAL(ast
integer, env
integer) RETURN integer;
38 FUNCTION eval_ast(ast
integer, env
integer) RETURN integer IS
47 IF M(ast
).type_id
= 7 THEN
48 RETURN env_pkg.
env_get(M
, E
, env
, ast
);
49 ELSIF
M(ast
).type_id
IN (8,9) THEN
50 old_seq
:= TREAT(M(ast
) AS mal_seq_T
).val_seq
;
51 new_seq
:= mal_vals();
52 new_seq.
EXTEND(old_seq.
COUNT);
53 FOR i
IN 1..old_seq.
COUNT LOOP
54 new_seq(i
) := EVAL(old_seq(i
), env
);
56 RETURN types.
seq(M
, M(ast
).type_id
, new_seq
);
57 ELSIF
M(ast
).type_id
IN (10) THEN
58 new_hm
:= types.
hash_map(M
, H
, mal_vals());
59 old_midx
:= TREAT(M(ast
) AS mal_map_T
).map_idx
;
60 new_midx
:= TREAT(M(new_hm
) AS mal_map_T
).map_idx
;
62 k
:= H(old_midx
).
FIRST();
63 WHILE k
IS NOT NULL LOOP
64 H(new_midx
)(k
) := EVAL(H(old_midx
)(k
), env
);
65 k
:= H(old_midx
).
NEXT(k
);
73 FUNCTION EVAL(ast
integer, env
integer) RETURN integer IS
86 IF M(ast
).type_id
<> 8 THEN
87 RETURN eval_ast(ast
, env
);
89 IF types.
count(M
, ast
) = 0 THEN
90 RETURN ast
; -- empty list just returned
94 a0
:= types.
first(M
, ast
);
95 if M(a0
).type_id
= 7 THEN -- symbol
96 a0sym
:= TREAT(M(a0
) AS mal_str_T
).val_str
;
98 a0sym
:= '__<*fn*>__';
102 WHEN a0sym
= 'def!' THEN
103 RETURN env_pkg.
env_set(M
, E
, env
,
104 types.
nth(M
, ast
, 1), EVAL(types.
nth(M
, ast
, 2), env
));
105 WHEN a0sym
= 'let*' THEN
106 let_env
:= env_pkg.
env_new(M
, E
, env
);
107 seq
:= TREAT(M(types.
nth(M
, ast
, 1)) AS mal_seq_T
).val_seq
;
109 WHILE i
<= seq.
COUNT LOOP
110 x
:= env_pkg.
env_set(M
, E
, let_env
,
111 seq(i
), EVAL(seq(i
+1), let_env
));
114 RETURN EVAL(types.
nth(M
, ast
, 2), let_env
);
115 WHEN a0sym
= 'do' THEN
116 el
:= eval_ast(types.
slice(M
, ast
, 1), env
);
117 RETURN types.
nth(M
, el
, types.
count(M
, el
)-1);
118 WHEN a0sym
= 'if' THEN
119 cond
:= EVAL(types.
nth(M
, ast
, 1), env
);
120 IF cond
= 1 OR cond
= 2 THEN -- nil or false
121 IF types.
count(M
, ast
) > 3 THEN
122 RETURN EVAL(types.
nth(M
, ast
, 3), env
);
127 RETURN EVAL(types.
nth(M
, ast
, 2), env
);
129 WHEN a0sym
= 'fn*' THEN
130 RETURN types.
malfunc(M
, types.
nth(M
, ast
, 2),
131 types.
nth(M
, ast
, 1),
134 el
:= eval_ast(ast
, env
);
135 f
:= types.
first(M
, el
);
136 args
:= TREAT(M(types.
slice(M
, el
, 1)) AS mal_seq_T
).val_seq
;
137 IF M(f
).type_id
= 12 THEN
138 malfn
:= TREAT(M(f
) AS mal_func_T
);
139 fn_env
:= env_pkg.
env_new(M
, E
, malfn.env
,
141 RETURN EVAL(malfn.ast
, fn_env
);
143 RETURN core.
do_core_func(M
, H
, f
, args
);
150 FUNCTION PRINT(exp integer) RETURN varchar IS
152 RETURN printer.
pr_str(M
, H
, exp);
156 FUNCTION REP(line
varchar) RETURN varchar IS
158 RETURN PRINT(EVAL(READ(line
), repl_env
));
162 -- initialize memory pools
163 M
:= types.
mem_new();
164 H
:= types.
map_entry_table();
165 E
:= env_pkg.
env_entry_table();
167 repl_env
:= env_pkg.
env_new(M
, E
, NULL);
169 -- core.EXT: defined using PL/SQL
170 core_ns
:= core.
get_core_ns();
171 FOR cidx
IN 1..core_ns.
COUNT LOOP
172 x
:= env_pkg.
env_set(M
, E
, repl_env
,
173 types.
symbol(M
, core_ns(cidx
)),
174 types.
func(M
, core_ns(cidx
)));
177 -- core.mal: defined using the language itself
178 line
:= REP('(def! not (fn* (a) (if a false true)))');
182 line
:= io.
readline('user> ', 0);
183 IF line
= EMPTY_CLOB() THEN CONTINUE; END IF;
184 IF line
IS NOT NULL THEN
185 io.
writeline(REP(line
));
188 EXCEPTION WHEN OTHERS THEN
189 IF SQLCODE = -20001 THEN -- io read stream closed
190 io.
close(1); -- close output stream
193 io.
writeline('Error: ' || SQLERRM
);
194 io.
writeline(dbms_utility.format_error_backtrace
);