6 CREATE OR REPLACE PACKAGE mal
IS
8 FUNCTION MAIN(args
varchar DEFAULT '()') RETURN integer;
13 CREATE OR REPLACE PACKAGE BODY mal
IS
15 FUNCTION MAIN(args
varchar DEFAULT '()') RETURN integer IS
16 M types.mal_table
; -- general mal value memory pool
17 H types.map_entry_table
; -- hashmap memory pool
18 TYPE env_T
IS TABLE OF integer INDEX BY varchar2(100);
23 FUNCTION READ(line
varchar) RETURN integer IS
25 RETURN reader.
read_str(M
, H
, line
);
30 -- forward declarations
31 FUNCTION EVAL(ast
integer, env env_T
) RETURN integer;
32 FUNCTION do_core_func(fn
integer, args mal_vals
)
35 FUNCTION eval_ast(ast
integer, env env_T
) RETURN integer IS
44 IF M(ast
).type_id
= 7 THEN
45 RETURN env(TREAT(M(ast
) AS mal_str_T
).val_str
);
46 ELSIF
M(ast
).type_id
IN (8,9) THEN
47 old_seq
:= TREAT(M(ast
) AS mal_seq_T
).val_seq
;
48 new_seq
:= mal_vals();
49 new_seq.
EXTEND(old_seq.
COUNT);
50 FOR i
IN 1..old_seq.
COUNT LOOP
51 new_seq(i
) := EVAL(old_seq(i
), env
);
53 RETURN types.
seq(M
, M(ast
).type_id
, new_seq
);
54 ELSIF
M(ast
).type_id
IN (10) THEN
55 new_hm
:= types.
hash_map(M
, H
, mal_vals());
56 old_midx
:= TREAT(M(ast
) AS mal_map_T
).map_idx
;
57 new_midx
:= TREAT(M(new_hm
) AS mal_map_T
).map_idx
;
59 k
:= H(old_midx
).
FIRST();
60 WHILE k
IS NOT NULL LOOP
61 H(new_midx
)(k
) := EVAL(H(old_midx
)(k
), env
);
62 k
:= H(old_midx
).
NEXT(k
);
70 FUNCTION EVAL(ast
integer, env env_T
) RETURN integer IS
75 IF M(ast
).type_id
<> 8 THEN
76 RETURN eval_ast(ast
, env
);
78 IF types.
count(M
, ast
) = 0 THEN
79 RETURN ast
; -- empty list just returned
83 el
:= eval_ast(ast
, env
);
84 f
:= types.
first(M
, el
);
85 args
:= TREAT(M(types.
slice(M
, el
, 1)) AS mal_seq_T
).val_seq
;
86 RETURN do_core_func(f
, args
);
90 FUNCTION PRINT(exp integer) RETURN varchar IS
92 RETURN printer.
pr_str(M
, H
, exp);
96 FUNCTION mal_add(args mal_vals
) RETURN integer IS
98 RETURN types.
int(M
, TREAT(M(args(1)) AS mal_int_T
).val_int
+
99 TREAT(M(args(2)) AS mal_int_T
).val_int
);
102 FUNCTION mal_subtract(args mal_vals
) RETURN integer IS
104 RETURN types.
int(M
, TREAT(M(args(1)) AS mal_int_T
).val_int
-
105 TREAT(M(args(2)) AS mal_int_T
).val_int
);
108 FUNCTION mal_multiply(args mal_vals
) RETURN integer IS
110 RETURN types.
int(M
, TREAT(M(args(1)) AS mal_int_T
).val_int
*
111 TREAT(M(args(2)) AS mal_int_T
).val_int
);
114 FUNCTION mal_divide(args mal_vals
) RETURN integer IS
116 RETURN types.
int(M
, TREAT(M(args(1)) AS mal_int_T
).val_int
/
117 TREAT(M(args(2)) AS mal_int_T
).val_int
);
120 FUNCTION do_core_func(fn
integer, args mal_vals
)
124 IF M(fn
).type_id
<> 11 THEN
125 raise_application_error(-20004,
126 'Invalid function call', TRUE);
129 fname
:= TREAT(M(fn
) AS mal_str_T
).val_str
;
131 WHEN fname
= '+' THEN RETURN mal_add(args
);
132 WHEN fname
= '-' THEN RETURN mal_subtract(args
);
133 WHEN fname
= '*' THEN RETURN mal_multiply(args
);
134 WHEN fname
= '/' THEN RETURN mal_divide(args
);
135 ELSE raise_application_error(-20004,
136 'Invalid function call', TRUE);
140 FUNCTION REP(line
varchar) RETURN varchar IS
142 RETURN PRINT(EVAL(READ(line
), repl_env
));
146 -- initialize memory pools
147 M
:= types.
mem_new();
148 H
:= types.
map_entry_table();
150 repl_env('+') := types.
func(M
, '+');
151 repl_env('-') := types.
func(M
, '-');
152 repl_env('*') := types.
func(M
, '*');
153 repl_env('/') := types.
func(M
, '/');
157 line
:= io.
readline('user> ', 0);
158 IF line
= EMPTY_CLOB() THEN CONTINUE; END IF;
159 IF line
IS NOT NULL THEN
160 io.
writeline(REP(line
));
163 EXCEPTION WHEN OTHERS THEN
164 IF SQLCODE = -20001 THEN -- io read stream closed
165 io.
close(1); -- close output stream
168 io.
writeline('Error: ' || SQLERRM
);
169 io.
writeline(dbms_utility.format_error_backtrace
);