2016-04-05 07:37:52 +03:00
|
|
|
@io.sql
|
|
|
|
@types.sql
|
|
|
|
@reader.sql
|
|
|
|
@printer.sql
|
|
|
|
@env.sql
|
|
|
|
|
2016-04-07 09:22:15 +03:00
|
|
|
CREATE OR REPLACE PACKAGE mal IS
|
2016-04-05 07:37:52 +03:00
|
|
|
|
2016-04-29 08:11:59 +03:00
|
|
|
FUNCTION MAIN(args varchar DEFAULT '()') RETURN integer;
|
2016-04-05 07:37:52 +03:00
|
|
|
|
2016-04-07 09:22:15 +03:00
|
|
|
END mal;
|
2016-04-05 07:37:52 +03:00
|
|
|
/
|
|
|
|
|
2016-04-07 09:22:15 +03:00
|
|
|
CREATE OR REPLACE PACKAGE BODY mal IS
|
2016-04-05 07:37:52 +03:00
|
|
|
|
2016-04-29 08:11:59 +03:00
|
|
|
FUNCTION MAIN(args varchar DEFAULT '()') RETURN integer IS
|
2016-05-03 07:56:48 +03:00
|
|
|
M mem_type; -- general mal value memory pool
|
|
|
|
H types.map_entry_table; -- hashmap memory pool
|
|
|
|
E env_pkg.env_entry_table; -- mal env memory pool
|
2016-04-05 07:37:52 +03:00
|
|
|
repl_env integer;
|
2016-04-07 09:22:15 +03:00
|
|
|
x integer;
|
2016-04-05 07:37:52 +03:00
|
|
|
line varchar2(4000);
|
|
|
|
|
|
|
|
-- read
|
2016-04-07 09:22:15 +03:00
|
|
|
FUNCTION READ(line varchar) RETURN integer IS
|
2016-04-05 07:37:52 +03:00
|
|
|
BEGIN
|
2016-05-03 07:56:48 +03:00
|
|
|
RETURN reader.read_str(M, H, line);
|
2016-04-05 07:37:52 +03:00
|
|
|
END;
|
|
|
|
|
|
|
|
-- eval
|
|
|
|
|
|
|
|
-- forward declarations
|
2016-04-07 09:22:15 +03:00
|
|
|
FUNCTION EVAL(ast integer, env integer) RETURN integer;
|
|
|
|
FUNCTION do_core_func(fn integer, args mal_seq_items_type)
|
|
|
|
RETURN integer;
|
2016-04-05 07:37:52 +03:00
|
|
|
|
2016-04-07 09:22:15 +03:00
|
|
|
FUNCTION eval_ast(ast integer, env integer) RETURN integer IS
|
2016-05-03 07:56:48 +03:00
|
|
|
i integer;
|
|
|
|
old_seq mal_seq_items_type;
|
|
|
|
new_seq mal_seq_items_type;
|
|
|
|
new_hm integer;
|
|
|
|
old_midx integer;
|
|
|
|
new_midx integer;
|
|
|
|
k varchar2(256);
|
2016-04-05 07:37:52 +03:00
|
|
|
BEGIN
|
2016-04-07 09:22:15 +03:00
|
|
|
IF M(ast).type_id = 7 THEN
|
2016-04-29 08:11:59 +03:00
|
|
|
RETURN env_pkg.env_get(M, E, env, ast);
|
2016-04-07 09:22:15 +03:00
|
|
|
ELSIF M(ast).type_id IN (8,9) THEN
|
|
|
|
old_seq := TREAT(M(ast) AS mal_seq_type).val_seq;
|
2016-04-05 07:37:52 +03:00
|
|
|
new_seq := mal_seq_items_type();
|
|
|
|
new_seq.EXTEND(old_seq.COUNT);
|
|
|
|
FOR i IN 1..old_seq.COUNT LOOP
|
|
|
|
new_seq(i) := EVAL(old_seq(i), env);
|
|
|
|
END LOOP;
|
2016-04-07 09:22:15 +03:00
|
|
|
RETURN types.seq(M, M(ast).type_id, new_seq);
|
2016-05-03 07:56:48 +03:00
|
|
|
ELSIF M(ast).type_id IN (10) THEN
|
|
|
|
new_hm := types.hash_map(M, H, mal_seq_items_type());
|
|
|
|
old_midx := TREAT(M(ast) AS mal_map_type).map_idx;
|
|
|
|
new_midx := TREAT(M(new_hm) AS mal_map_type).map_idx;
|
|
|
|
|
|
|
|
k := H(old_midx).FIRST();
|
|
|
|
WHILE k IS NOT NULL LOOP
|
|
|
|
H(new_midx)(k) := EVAL(H(old_midx)(k), env);
|
|
|
|
k := H(old_midx).NEXT(k);
|
|
|
|
END LOOP;
|
|
|
|
RETURN new_hm;
|
2016-04-05 07:37:52 +03:00
|
|
|
ELSE
|
|
|
|
RETURN ast;
|
|
|
|
END IF;
|
|
|
|
END;
|
|
|
|
|
2016-04-07 09:22:15 +03:00
|
|
|
FUNCTION EVAL(ast integer, env integer) RETURN integer IS
|
|
|
|
el integer;
|
|
|
|
a0 integer;
|
2016-04-29 06:36:24 +03:00
|
|
|
a0sym varchar2(100);
|
2016-04-05 07:37:52 +03:00
|
|
|
seq mal_seq_items_type;
|
|
|
|
let_env integer;
|
|
|
|
i integer;
|
2016-04-07 09:22:15 +03:00
|
|
|
f integer;
|
2016-04-29 06:36:24 +03:00
|
|
|
args mal_seq_items_type;
|
2016-04-05 07:37:52 +03:00
|
|
|
BEGIN
|
2016-04-07 09:22:15 +03:00
|
|
|
IF M(ast).type_id <> 8 THEN
|
2016-04-05 07:37:52 +03:00
|
|
|
RETURN eval_ast(ast, env);
|
|
|
|
END IF;
|
2016-05-03 07:56:48 +03:00
|
|
|
IF types.count(M, ast) = 0 THEN
|
|
|
|
RETURN ast; -- empty list just returned
|
|
|
|
END IF;
|
2016-04-05 07:37:52 +03:00
|
|
|
|
|
|
|
-- apply
|
2016-04-07 09:22:15 +03:00
|
|
|
a0 := types.first(M, ast);
|
|
|
|
if M(a0).type_id = 7 THEN -- symbol
|
|
|
|
a0sym := TREAT(M(a0) AS mal_str_type).val_str;
|
2016-04-05 07:37:52 +03:00
|
|
|
ELSE
|
|
|
|
a0sym := '__<*fn*>__';
|
|
|
|
END IF;
|
|
|
|
|
|
|
|
CASE
|
|
|
|
WHEN a0sym = 'def!' THEN
|
2016-04-29 08:11:59 +03:00
|
|
|
RETURN env_pkg.env_set(M, E, env,
|
2016-04-07 09:22:15 +03:00
|
|
|
types.nth(M, ast, 1), EVAL(types.nth(M, ast, 2), env));
|
2016-04-05 07:37:52 +03:00
|
|
|
WHEN a0sym = 'let*' THEN
|
2016-04-29 08:11:59 +03:00
|
|
|
let_env := env_pkg.env_new(M, E, env);
|
2016-04-07 09:22:15 +03:00
|
|
|
seq := TREAT(M(types.nth(M, ast, 1)) AS mal_seq_type).val_seq;
|
2016-04-05 07:37:52 +03:00
|
|
|
i := 1;
|
|
|
|
WHILE i <= seq.COUNT LOOP
|
2016-04-29 08:11:59 +03:00
|
|
|
x := env_pkg.env_set(M, E, let_env,
|
2016-04-05 07:37:52 +03:00
|
|
|
seq(i), EVAL(seq(i+1), let_env));
|
|
|
|
i := i + 2;
|
|
|
|
END LOOP;
|
2016-04-07 09:22:15 +03:00
|
|
|
RETURN EVAL(types.nth(M, ast, 2), let_env);
|
2016-04-05 07:37:52 +03:00
|
|
|
ELSE
|
|
|
|
el := eval_ast(ast, env);
|
2016-04-07 09:22:15 +03:00
|
|
|
f := types.first(M, el);
|
2016-04-29 06:36:24 +03:00
|
|
|
args := TREAT(M(types.slice(M, el, 1)) AS mal_seq_type).val_seq;
|
|
|
|
RETURN do_core_func(f, args);
|
2016-04-05 07:37:52 +03:00
|
|
|
END CASE;
|
|
|
|
|
|
|
|
END;
|
|
|
|
|
|
|
|
-- print
|
2016-04-07 09:22:15 +03:00
|
|
|
FUNCTION PRINT(exp integer) RETURN varchar IS
|
2016-04-05 07:37:52 +03:00
|
|
|
BEGIN
|
2016-05-03 07:56:48 +03:00
|
|
|
RETURN printer.pr_str(M, H, exp);
|
2016-04-05 07:37:52 +03:00
|
|
|
END;
|
|
|
|
|
|
|
|
-- repl
|
2016-04-07 09:22:15 +03:00
|
|
|
FUNCTION mal_add(args mal_seq_items_type) RETURN integer IS
|
2016-04-05 07:37:52 +03:00
|
|
|
BEGIN
|
2016-04-07 09:22:15 +03:00
|
|
|
RETURN types.int(M, TREAT(M(args(1)) AS mal_int_type).val_int +
|
|
|
|
TREAT(M(args(2)) AS mal_int_type).val_int);
|
2016-04-05 07:37:52 +03:00
|
|
|
END;
|
|
|
|
|
2016-04-07 09:22:15 +03:00
|
|
|
FUNCTION mal_subtract(args mal_seq_items_type) RETURN integer IS
|
2016-04-05 07:37:52 +03:00
|
|
|
BEGIN
|
2016-04-07 09:22:15 +03:00
|
|
|
RETURN types.int(M, TREAT(M(args(1)) AS mal_int_type).val_int -
|
|
|
|
TREAT(M(args(2)) AS mal_int_type).val_int);
|
2016-04-05 07:37:52 +03:00
|
|
|
END;
|
|
|
|
|
2016-04-07 09:22:15 +03:00
|
|
|
FUNCTION mal_multiply(args mal_seq_items_type) RETURN integer IS
|
2016-04-05 07:37:52 +03:00
|
|
|
BEGIN
|
2016-04-07 09:22:15 +03:00
|
|
|
RETURN types.int(M, TREAT(M(args(1)) AS mal_int_type).val_int *
|
|
|
|
TREAT(M(args(2)) AS mal_int_type).val_int);
|
2016-04-05 07:37:52 +03:00
|
|
|
END;
|
|
|
|
|
2016-04-07 09:22:15 +03:00
|
|
|
FUNCTION mal_divide(args mal_seq_items_type) RETURN integer IS
|
2016-04-05 07:37:52 +03:00
|
|
|
BEGIN
|
2016-04-07 09:22:15 +03:00
|
|
|
RETURN types.int(M, TREAT(M(args(1)) AS mal_int_type).val_int /
|
|
|
|
TREAT(M(args(2)) AS mal_int_type).val_int);
|
2016-04-05 07:37:52 +03:00
|
|
|
END;
|
|
|
|
|
2016-04-07 09:22:15 +03:00
|
|
|
FUNCTION do_core_func(fn integer, args mal_seq_items_type)
|
|
|
|
RETURN integer IS
|
2016-04-05 07:37:52 +03:00
|
|
|
fname varchar(100);
|
|
|
|
BEGIN
|
2016-04-07 09:22:15 +03:00
|
|
|
IF M(fn).type_id <> 11 THEN
|
2016-04-05 07:37:52 +03:00
|
|
|
raise_application_error(-20004,
|
|
|
|
'Invalid function call', TRUE);
|
|
|
|
END IF;
|
|
|
|
|
2016-04-07 09:22:15 +03:00
|
|
|
fname := TREAT(M(fn) AS mal_str_type).val_str;
|
2016-04-05 07:37:52 +03:00
|
|
|
CASE
|
|
|
|
WHEN fname = '+' THEN RETURN mal_add(args);
|
|
|
|
WHEN fname = '-' THEN RETURN mal_subtract(args);
|
|
|
|
WHEN fname = '*' THEN RETURN mal_multiply(args);
|
|
|
|
WHEN fname = '/' THEN RETURN mal_divide(args);
|
|
|
|
ELSE raise_application_error(-20004,
|
|
|
|
'Invalid function call', TRUE);
|
|
|
|
END CASE;
|
|
|
|
END;
|
|
|
|
|
|
|
|
FUNCTION REP(line varchar) RETURN varchar IS
|
|
|
|
BEGIN
|
|
|
|
RETURN PRINT(EVAL(READ(line), repl_env));
|
|
|
|
END;
|
|
|
|
|
|
|
|
BEGIN
|
2016-05-03 07:56:48 +03:00
|
|
|
-- initialize memory pools
|
2016-04-07 09:22:15 +03:00
|
|
|
M := types.mem_new();
|
2016-05-03 07:56:48 +03:00
|
|
|
H := types.map_entry_table();
|
2016-04-29 08:11:59 +03:00
|
|
|
E := env_pkg.env_entry_table();
|
|
|
|
|
|
|
|
repl_env := env_pkg.env_new(M, E, NULL);
|
|
|
|
x := env_pkg.env_set(M, E, repl_env, types.symbol(M, '+'),
|
|
|
|
types.func(M, '+'));
|
|
|
|
x := env_pkg.env_set(M, E, repl_env, types.symbol(M, '-'),
|
|
|
|
types.func(M, '-'));
|
|
|
|
x := env_pkg.env_set(M, E, repl_env, types.symbol(M, '*'),
|
|
|
|
types.func(M, '*'));
|
|
|
|
x := env_pkg.env_set(M, E, repl_env, types.symbol(M, '/'),
|
|
|
|
types.func(M, '/'));
|
2016-04-05 07:37:52 +03:00
|
|
|
|
2016-04-05 09:29:14 +03:00
|
|
|
WHILE true LOOP
|
2016-04-05 07:37:52 +03:00
|
|
|
BEGIN
|
|
|
|
line := stream_readline('user> ', 0);
|
2016-04-07 09:22:15 +03:00
|
|
|
IF line IS NULL THEN CONTINUE; END IF;
|
2016-04-05 07:37:52 +03:00
|
|
|
IF line IS NOT NULL THEN
|
|
|
|
stream_writeline(REP(line));
|
|
|
|
END IF;
|
|
|
|
|
|
|
|
EXCEPTION WHEN OTHERS THEN
|
2016-04-29 06:36:24 +03:00
|
|
|
IF SQLCODE = -20001 THEN -- io streams closed
|
2016-04-05 07:37:52 +03:00
|
|
|
RETURN 0;
|
|
|
|
END IF;
|
|
|
|
stream_writeline('Error: ' || SQLERRM);
|
|
|
|
stream_writeline(dbms_utility.format_error_backtrace);
|
|
|
|
END;
|
|
|
|
END LOOP;
|
|
|
|
END;
|
|
|
|
|
2016-04-07 09:22:15 +03:00
|
|
|
END mal;
|
2016-04-05 07:37:52 +03:00
|
|
|
/
|
|
|
|
show errors;
|
|
|
|
|
|
|
|
quit;
|