1
1
mirror of https://github.com/kanaka/mal.git synced 2024-11-10 12:47:45 +03:00
mal/plsql/step4_if_fn_do.sql

204 lines
6.0 KiB
MySQL
Raw Normal View History

2016-04-05 09:29:14 +03:00
@io.sql
@types.sql
@reader.sql
@printer.sql
@env.sql
@core.sql
CREATE OR REPLACE PACKAGE mal IS
2016-04-05 09:29:14 +03:00
FUNCTION MAIN(args varchar DEFAULT '()') RETURN integer;
2016-04-05 09:29:14 +03:00
END mal;
2016-04-05 09:29:14 +03:00
/
CREATE OR REPLACE PACKAGE BODY mal IS
2016-04-05 09:29:14 +03:00
FUNCTION MAIN(args varchar DEFAULT '()') RETURN integer IS
M types.mal_table; -- 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 09:29:14 +03:00
repl_env integer;
x integer;
line CLOB;
core_ns core_ns_T;
2016-04-05 09:29:14 +03:00
cidx integer;
-- read
FUNCTION READ(line varchar) RETURN integer IS
2016-04-05 09:29:14 +03:00
BEGIN
RETURN reader.read_str(M, H, line);
2016-04-05 09:29:14 +03:00
END;
-- eval
-- forward declarations
FUNCTION EVAL(ast integer, env integer) RETURN integer;
2016-04-05 09:29:14 +03:00
FUNCTION eval_ast(ast integer, env integer) RETURN integer IS
i integer;
old_seq mal_vals;
new_seq mal_vals;
new_hm integer;
old_midx integer;
new_midx integer;
k varchar2(256);
2016-04-05 09:29:14 +03:00
BEGIN
IF M(ast).type_id = 7 THEN
RETURN env_pkg.env_get(M, E, env, ast);
ELSIF M(ast).type_id IN (8,9) THEN
old_seq := TREAT(M(ast) AS mal_seq_T).val_seq;
new_seq := mal_vals();
2016-04-05 09:29:14 +03:00
new_seq.EXTEND(old_seq.COUNT);
FOR i IN 1..old_seq.COUNT LOOP
new_seq(i) := EVAL(old_seq(i), env);
END LOOP;
RETURN types.seq(M, M(ast).type_id, new_seq);
ELSIF M(ast).type_id IN (10) THEN
new_hm := types.hash_map(M, H, mal_vals());
old_midx := TREAT(M(ast) AS mal_map_T).map_idx;
new_midx := TREAT(M(new_hm) AS mal_map_T).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 09:29:14 +03:00
ELSE
RETURN ast;
END IF;
END;
FUNCTION EVAL(ast integer, env integer) RETURN integer IS
el integer;
a0 integer;
a0sym varchar2(100);
seq mal_vals;
2016-04-05 09:29:14 +03:00
let_env integer;
i integer;
f integer;
fn_env integer;
cond integer;
malfn mal_func_T;
args mal_vals;
2016-04-05 09:29:14 +03:00
BEGIN
IF M(ast).type_id <> 8 THEN
2016-04-05 09:29:14 +03:00
RETURN eval_ast(ast, env);
END IF;
IF types.count(M, ast) = 0 THEN
RETURN ast; -- empty list just returned
END IF;
2016-04-05 09:29:14 +03:00
-- apply
a0 := types.first(M, ast);
if M(a0).type_id = 7 THEN -- symbol
a0sym := TREAT(M(a0) AS mal_str_T).val_str;
2016-04-05 09:29:14 +03:00
ELSE
a0sym := '__<*fn*>__';
END IF;
CASE
WHEN a0sym = 'def!' THEN
RETURN env_pkg.env_set(M, E, env,
types.nth(M, ast, 1), EVAL(types.nth(M, ast, 2), env));
2016-04-05 09:29:14 +03:00
WHEN a0sym = 'let*' THEN
let_env := env_pkg.env_new(M, E, env);
seq := TREAT(M(types.nth(M, ast, 1)) AS mal_seq_T).val_seq;
2016-04-05 09:29:14 +03:00
i := 1;
WHILE i <= seq.COUNT LOOP
x := env_pkg.env_set(M, E, let_env,
2016-04-05 09:29:14 +03:00
seq(i), EVAL(seq(i+1), let_env));
i := i + 2;
END LOOP;
RETURN EVAL(types.nth(M, ast, 2), let_env);
2016-04-05 09:29:14 +03:00
WHEN a0sym = 'do' THEN
el := eval_ast(types.slice(M, ast, 1), env);
RETURN types.nth(M, el, types.count(M, el)-1);
2016-04-05 09:29:14 +03:00
WHEN a0sym = 'if' THEN
cond := EVAL(types.nth(M, ast, 1), env);
IF cond = 1 OR cond = 2 THEN -- nil or false
IF types.count(M, ast) > 3 THEN
RETURN EVAL(types.nth(M, ast, 3), env);
2016-04-05 09:29:14 +03:00
ELSE
RETURN 1; -- nil
2016-04-05 09:29:14 +03:00
END IF;
ELSE
RETURN EVAL(types.nth(M, ast, 2), env);
2016-04-05 09:29:14 +03:00
END IF;
WHEN a0sym = 'fn*' THEN
RETURN types.malfunc(M, types.nth(M, ast, 2),
types.nth(M, ast, 1),
2016-04-05 09:29:14 +03:00
env);
ELSE
el := eval_ast(ast, env);
f := types.first(M, el);
args := TREAT(M(types.slice(M, el, 1)) AS mal_seq_T).val_seq;
IF M(f).type_id = 12 THEN
malfn := TREAT(M(f) AS mal_func_T);
fn_env := env_pkg.env_new(M, E, malfn.env,
2016-04-05 09:29:14 +03:00
malfn.params, args);
RETURN EVAL(malfn.ast, fn_env);
ELSE
RETURN core.do_core_func(M, H, f, args);
2016-04-05 09:29:14 +03:00
END IF;
END CASE;
END;
-- print
FUNCTION PRINT(exp integer) RETURN varchar IS
2016-04-05 09:29:14 +03:00
BEGIN
RETURN printer.pr_str(M, H, exp);
2016-04-05 09:29:14 +03:00
END;
-- repl
2016-04-05 09:29:14 +03:00
FUNCTION REP(line varchar) RETURN varchar IS
BEGIN
RETURN PRINT(EVAL(READ(line), repl_env));
END;
BEGIN
-- initialize memory pools
M := types.mem_new();
H := types.map_entry_table();
E := env_pkg.env_entry_table();
repl_env := env_pkg.env_new(M, E, NULL);
2016-04-05 09:29:14 +03:00
-- core.EXT: defined using PL/SQL
core_ns := core.get_core_ns();
2016-04-05 09:29:14 +03:00
FOR cidx IN 1..core_ns.COUNT LOOP
x := env_pkg.env_set(M, E, repl_env,
types.symbol(M, core_ns(cidx)),
types.func(M, core_ns(cidx)));
2016-04-05 09:29:14 +03:00
END LOOP;
-- core.mal: defined using the language itself
line := REP('(def! not (fn* (a) (if a false true)))');
WHILE true LOOP
BEGIN
line := io.readline('user> ', 0);
IF line = EMPTY_CLOB() THEN CONTINUE; END IF;
2016-04-05 09:29:14 +03:00
IF line IS NOT NULL THEN
io.writeline(REP(line));
2016-04-05 09:29:14 +03:00
END IF;
EXCEPTION WHEN OTHERS THEN
IF SQLCODE = -20001 THEN -- io read stream closed
io.close(1); -- close output stream
2016-04-05 09:29:14 +03:00
RETURN 0;
END IF;
io.writeline('Error: ' || SQLERRM);
io.writeline(dbms_utility.format_error_backtrace);
2016-04-05 09:29:14 +03:00
END;
END LOOP;
END;
END mal;
2016-04-05 09:29:14 +03:00
/
show errors;
quit;