mirror of
https://github.com/kanaka/mal.git
synced 2024-09-20 10:07:45 +03:00
604 lines
16 KiB
SQL
604 lines
16 KiB
SQL
-- ---------------------------------------------------------
|
|
-- persistent values
|
|
|
|
BEGIN
|
|
EXECUTE IMMEDIATE 'DROP TYPE mal_T FORCE';
|
|
EXCEPTION
|
|
WHEN OTHERS THEN IF SQLCODE != -4043 THEN RAISE; END IF;
|
|
END;
|
|
/
|
|
|
|
-- list of types for type_id
|
|
-- 0: nil
|
|
-- 1: false
|
|
-- 2: true
|
|
-- 3: integer
|
|
-- 4: float
|
|
-- 5: string
|
|
-- 6: long string (CLOB)
|
|
-- 7: symbol
|
|
-- 8: list
|
|
-- 9: vector
|
|
-- 10: hashmap
|
|
-- 11: function
|
|
-- 12: malfunc
|
|
-- 13: atom
|
|
|
|
-- nil (0), false (1), true (2)
|
|
CREATE OR REPLACE TYPE mal_T FORCE AS OBJECT (
|
|
type_id integer
|
|
) NOT FINAL;
|
|
/
|
|
|
|
-- general nested table of mal values (integers)
|
|
-- used frequently for argument passing
|
|
CREATE OR REPLACE TYPE mal_vals FORCE AS TABLE OF integer;
|
|
/
|
|
|
|
|
|
-- integer (3)
|
|
CREATE OR REPLACE TYPE mal_int_T FORCE UNDER mal_T (
|
|
val_int integer
|
|
) FINAL;
|
|
/
|
|
|
|
-- string/keyword (5,6), symbol (7)
|
|
CREATE OR REPLACE TYPE mal_str_T FORCE UNDER mal_T (
|
|
val_str varchar2(4000)
|
|
) NOT FINAL;
|
|
/
|
|
|
|
CREATE OR REPLACE TYPE mal_long_str_T FORCE UNDER mal_str_T (
|
|
val_long_str CLOB -- long character object (for larger than 4000 chars)
|
|
) FINAL;
|
|
/
|
|
show errors;
|
|
|
|
-- list (8), vector (9)
|
|
CREATE OR REPLACE TYPE mal_seq_T FORCE UNDER mal_T (
|
|
val_seq mal_vals,
|
|
meta integer
|
|
) FINAL;
|
|
/
|
|
|
|
CREATE OR REPLACE TYPE mal_map_T FORCE UNDER mal_T (
|
|
map_idx integer, -- index into map entry table
|
|
meta integer
|
|
) FINAL;
|
|
/
|
|
|
|
-- malfunc (12)
|
|
CREATE OR REPLACE TYPE mal_func_T FORCE UNDER mal_T (
|
|
ast integer,
|
|
params integer,
|
|
env integer,
|
|
is_macro integer,
|
|
meta integer
|
|
) FINAL;
|
|
/
|
|
|
|
-- atom (13)
|
|
CREATE OR REPLACE TYPE mal_atom_T FORCE UNDER mal_T (
|
|
val integer -- index into mal_table
|
|
);
|
|
/
|
|
|
|
|
|
-- ---------------------------------------------------------
|
|
|
|
CREATE OR REPLACE PACKAGE types IS
|
|
-- memory pool for mal_objects (non-hash-map)
|
|
TYPE mal_table IS TABLE OF mal_T;
|
|
|
|
-- memory pool for hash-map objects
|
|
TYPE map_entry IS TABLE OF integer INDEX BY varchar2(256);
|
|
TYPE map_entry_table IS TABLE OF map_entry;
|
|
|
|
-- general functions
|
|
FUNCTION mem_new RETURN mal_table;
|
|
|
|
FUNCTION tf(val boolean) RETURN integer;
|
|
FUNCTION equal_Q(M IN OUT NOCOPY mal_table,
|
|
H IN OUT NOCOPY map_entry_table,
|
|
a integer, b integer) RETURN boolean;
|
|
|
|
FUNCTION clone(M IN OUT NOCOPY mal_table,
|
|
H IN OUT NOCOPY map_entry_table,
|
|
obj integer,
|
|
meta integer DEFAULT 1) RETURN integer;
|
|
|
|
-- scalar functions
|
|
FUNCTION int(M IN OUT NOCOPY mal_table, num integer) RETURN integer;
|
|
FUNCTION string(M IN OUT NOCOPY mal_table, name varchar) RETURN integer;
|
|
FUNCTION string_Q(M IN OUT NOCOPY mal_table, val integer) RETURN boolean;
|
|
FUNCTION symbol(M IN OUT NOCOPY mal_table, name varchar) RETURN integer;
|
|
FUNCTION keyword(M IN OUT NOCOPY mal_table, name varchar) RETURN integer;
|
|
FUNCTION keyword_Q(M IN OUT NOCOPY mal_table, val integer) RETURN boolean;
|
|
|
|
-- sequence functions
|
|
FUNCTION seq(M IN OUT NOCOPY mal_table,
|
|
type_id integer,
|
|
items mal_vals,
|
|
meta integer DEFAULT 1) RETURN integer;
|
|
FUNCTION list(M IN OUT NOCOPY mal_table) RETURN integer;
|
|
FUNCTION list(M IN OUT NOCOPY mal_table,
|
|
a integer) RETURN integer;
|
|
FUNCTION list(M IN OUT NOCOPY mal_table,
|
|
a integer, b integer) RETURN integer;
|
|
FUNCTION list(M IN OUT NOCOPY mal_table,
|
|
a integer, b integer, c integer) RETURN integer;
|
|
|
|
FUNCTION first(M IN OUT NOCOPY mal_table,
|
|
seq integer) RETURN integer;
|
|
FUNCTION slice(M IN OUT NOCOPY mal_table,
|
|
seq integer,
|
|
idx integer,
|
|
last integer DEFAULT NULL) RETURN integer;
|
|
FUNCTION slice(M IN OUT NOCOPY mal_table,
|
|
items mal_vals,
|
|
idx integer) RETURN integer;
|
|
FUNCTION islice(items mal_vals,
|
|
idx integer) RETURN mal_vals;
|
|
FUNCTION nth(M IN OUT NOCOPY mal_table,
|
|
seq integer, idx integer) RETURN integer;
|
|
|
|
FUNCTION count(M IN OUT NOCOPY mal_table,
|
|
seq integer) RETURN integer;
|
|
|
|
FUNCTION atom_new(M IN OUT NOCOPY mal_table,
|
|
val integer) RETURN integer;
|
|
FUNCTION atom_reset(M IN OUT NOCOPY mal_table,
|
|
atm integer,
|
|
val integer) RETURN integer;
|
|
|
|
-- hash-map functions
|
|
FUNCTION assoc_BANG(M IN OUT NOCOPY mal_table,
|
|
H IN OUT NOCOPY map_entry_table,
|
|
midx integer,
|
|
kvs mal_vals) RETURN integer;
|
|
FUNCTION dissoc_BANG(M IN OUT NOCOPY mal_table,
|
|
H IN OUT NOCOPY map_entry_table,
|
|
midx integer,
|
|
ks mal_vals) RETURN integer;
|
|
FUNCTION hash_map(M IN OUT NOCOPY mal_table,
|
|
H IN OUT NOCOPY map_entry_table,
|
|
kvs mal_vals,
|
|
meta integer DEFAULT 1) RETURN integer;
|
|
|
|
-- function functions
|
|
FUNCTION func(M IN OUT NOCOPY mal_table, name varchar) RETURN integer;
|
|
FUNCTION malfunc(M IN OUT NOCOPY mal_table,
|
|
ast integer,
|
|
params integer,
|
|
env integer,
|
|
is_macro integer DEFAULT 0,
|
|
meta integer DEFAULT 1) RETURN integer;
|
|
END types;
|
|
/
|
|
show errors;
|
|
|
|
|
|
CREATE OR REPLACE PACKAGE BODY types IS
|
|
|
|
-- ---------------------------------------------------------
|
|
-- general functions
|
|
|
|
FUNCTION mem_new RETURN mal_table IS
|
|
BEGIN
|
|
-- initialize mal type memory pool
|
|
-- 1 -> nil
|
|
-- 2 -> false
|
|
-- 3 -> true
|
|
RETURN mal_table(mal_T(0), mal_T(1), mal_T(2));
|
|
END;
|
|
|
|
FUNCTION tf(val boolean) RETURN integer IS
|
|
BEGIN
|
|
IF val THEN
|
|
RETURN 3; -- true
|
|
ELSE
|
|
RETURN 2; -- false
|
|
END IF;
|
|
END;
|
|
|
|
FUNCTION equal_Q(M IN OUT NOCOPY mal_table,
|
|
H IN OUT NOCOPY map_entry_table,
|
|
a integer, b integer) RETURN boolean IS
|
|
atyp integer;
|
|
btyp integer;
|
|
aseq mal_vals;
|
|
bseq mal_vals;
|
|
amidx integer;
|
|
bmidx integer;
|
|
i integer;
|
|
k varchar2(256);
|
|
BEGIN
|
|
atyp := M(a).type_id;
|
|
btyp := M(b).type_id;
|
|
IF NOT (atyp = btyp OR (atyp IN (8,9) AND btyp IN (8,9))) THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
|
|
CASE
|
|
WHEN atyp IN (0,1,2) THEN
|
|
RETURN TRUE;
|
|
WHEN atyp = 3 THEN
|
|
RETURN TREAT(M(a) AS mal_int_T).val_int =
|
|
TREAT(M(b) AS mal_int_T).val_int;
|
|
WHEN atyp IN (5,6,7) THEN
|
|
IF TREAT(M(a) AS mal_str_T).val_str IS NULL AND
|
|
TREAT(M(b) AS mal_str_T).val_str IS NULL THEN
|
|
RETURN TRUE;
|
|
ELSE
|
|
RETURN TREAT(M(a) AS mal_str_T).val_str =
|
|
TREAT(M(b) AS mal_str_T).val_str;
|
|
END IF;
|
|
WHEN atyp IN (8,9) THEN
|
|
aseq := TREAT(M(a) AS mal_seq_T).val_seq;
|
|
bseq := TREAT(M(b) AS mal_seq_T).val_seq;
|
|
IF aseq.COUNT <> bseq.COUNT THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
FOR i IN 1..aseq.COUNT LOOP
|
|
IF NOT equal_Q(M, H, aseq(i), bseq(i)) THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
END LOOP;
|
|
RETURN TRUE;
|
|
WHEN atyp = 10 THEN
|
|
amidx := TREAT(M(a) AS mal_map_T).map_idx;
|
|
bmidx := TREAT(M(b) AS mal_map_T).map_idx;
|
|
IF H(amidx).COUNT() <> H(bmidx).COUNT() THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
|
|
k := H(amidx).FIRST();
|
|
WHILE k IS NOT NULL LOOP
|
|
IF H(amidx)(k) IS NULL OR H(bmidx)(k) IS NULL THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
IF NOT equal_Q(M, H, H(amidx)(k), H(bmidx)(k)) THEN
|
|
RETURN FALSE;
|
|
END IF;
|
|
k := H(amidx).NEXT(k);
|
|
END LOOP;
|
|
RETURN TRUE;
|
|
ELSE
|
|
RETURN FALSE;
|
|
END CASE;
|
|
END;
|
|
|
|
FUNCTION clone(M IN OUT NOCOPY mal_table,
|
|
H IN OUT NOCOPY map_entry_table,
|
|
obj integer,
|
|
meta integer DEFAULT 1) RETURN integer IS
|
|
type_id integer;
|
|
new_hm integer;
|
|
old_midx integer;
|
|
new_midx integer;
|
|
k varchar2(256);
|
|
malfn mal_func_T;
|
|
BEGIN
|
|
type_id := M(obj).type_id;
|
|
CASE
|
|
WHEN type_id IN (8,9) THEN -- list/vector
|
|
RETURN seq(M, type_id,
|
|
TREAT(M(obj) AS mal_seq_T).val_seq,
|
|
meta);
|
|
WHEN type_id = 10 THEN -- hash-map
|
|
new_hm := types.hash_map(M, H, mal_vals(), meta);
|
|
old_midx := TREAT(M(obj) 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) := H(old_midx)(k);
|
|
k := H(old_midx).NEXT(k);
|
|
END LOOP;
|
|
|
|
RETURN new_hm;
|
|
WHEN type_id = 12 THEN -- mal function
|
|
malfn := TREAT(M(obj) AS mal_func_T);
|
|
RETURN types.malfunc(M,
|
|
malfn.ast,
|
|
malfn.params,
|
|
malfn.env,
|
|
malfn.is_macro,
|
|
meta);
|
|
ELSE
|
|
raise_application_error(-20008,
|
|
'clone not supported for type ' || type_id, TRUE);
|
|
END CASE;
|
|
END;
|
|
|
|
|
|
-- ---------------------------------------------------------
|
|
-- scalar functions
|
|
|
|
|
|
FUNCTION int(M IN OUT NOCOPY mal_table, num integer) RETURN integer IS
|
|
BEGIN
|
|
M.EXTEND();
|
|
M(M.COUNT()) := mal_int_T(3, num);
|
|
RETURN M.COUNT();
|
|
END;
|
|
|
|
FUNCTION string(M IN OUT NOCOPY mal_table, name varchar) RETURN integer IS
|
|
BEGIN
|
|
M.EXTEND();
|
|
IF LENGTH(name) <= 4000 THEN
|
|
M(M.COUNT()) := mal_str_T(5, name);
|
|
ELSE
|
|
M(M.COUNT()) := mal_long_str_T(6, NULL, name);
|
|
END IF;
|
|
RETURN M.COUNT();
|
|
END;
|
|
|
|
FUNCTION string_Q(M IN OUT NOCOPY mal_table, val integer) RETURN boolean IS
|
|
str CLOB;
|
|
BEGIN
|
|
IF M(val).type_id IN (5,6) THEN
|
|
IF M(val).type_id = 5 THEN
|
|
str := TREAT(M(val) AS mal_str_T).val_str;
|
|
ELSE
|
|
str := TREAT(M(val) AS mal_long_str_T).val_long_str;
|
|
END IF;
|
|
IF str IS NULL OR
|
|
str = EMPTY_CLOB() OR
|
|
SUBSTR(str, 1, 1) <> chr(127) THEN
|
|
RETURN TRUE;
|
|
ELSE
|
|
RETURN FALSE;
|
|
END IF;
|
|
ELSE
|
|
RETURN FALSE;
|
|
END IF;
|
|
END;
|
|
|
|
FUNCTION symbol(M IN OUT NOCOPY mal_table, name varchar) RETURN integer IS
|
|
BEGIN
|
|
M.EXTEND();
|
|
M(M.COUNT()) := mal_str_T(7, name);
|
|
RETURN M.COUNT();
|
|
END;
|
|
|
|
FUNCTION keyword(M IN OUT NOCOPY mal_table, name varchar) RETURN integer IS
|
|
BEGIN
|
|
M.EXTEND();
|
|
M(M.COUNT()) := mal_str_T(5, chr(127) || name);
|
|
RETURN M.COUNT();
|
|
END;
|
|
|
|
FUNCTION keyword_Q(M IN OUT NOCOPY mal_table, val integer) RETURN boolean IS
|
|
str CLOB;
|
|
BEGIN
|
|
IF M(val).type_id = 5 THEN
|
|
str := TREAT(M(val) AS mal_str_T).val_str;
|
|
IF LENGTH(str) > 0 AND SUBSTR(str, 1, 1) = chr(127) THEN
|
|
RETURN TRUE;
|
|
ELSE
|
|
RETURN FALSE;
|
|
END IF;
|
|
ELSE
|
|
RETURN FALSE;
|
|
END IF;
|
|
END;
|
|
|
|
|
|
-- ---------------------------------------------------------
|
|
-- sequence functions
|
|
|
|
FUNCTION seq(M IN OUT NOCOPY mal_table,
|
|
type_id integer,
|
|
items mal_vals,
|
|
meta integer DEFAULT 1) RETURN integer IS
|
|
BEGIN
|
|
M.EXTEND();
|
|
M(M.COUNT()) := mal_seq_T(type_id, items, meta);
|
|
RETURN M.COUNT();
|
|
END;
|
|
|
|
-- list:
|
|
-- return a mal list
|
|
FUNCTION list(M IN OUT NOCOPY mal_table) RETURN integer IS
|
|
BEGIN
|
|
M.EXTEND();
|
|
M(M.COUNT()) := mal_seq_T(8, mal_vals(), 1);
|
|
RETURN M.COUNT();
|
|
END;
|
|
|
|
FUNCTION list(M IN OUT NOCOPY mal_table,
|
|
a integer) RETURN integer IS
|
|
BEGIN
|
|
M.EXTEND();
|
|
M(M.COUNT()) := mal_seq_T(8, mal_vals(a), 1);
|
|
RETURN M.COUNT();
|
|
END;
|
|
|
|
FUNCTION list(M IN OUT NOCOPY mal_table,
|
|
a integer, b integer) RETURN integer IS
|
|
BEGIN
|
|
M.EXTEND();
|
|
M(M.COUNT()) := mal_seq_T(8, mal_vals(a, b), 1);
|
|
RETURN M.COUNT();
|
|
END;
|
|
|
|
FUNCTION list(M IN OUT NOCOPY mal_table,
|
|
a integer, b integer, c integer) RETURN integer IS
|
|
BEGIN
|
|
M.EXTEND();
|
|
M(M.COUNT()) := mal_seq_T(8, mal_vals(a, b, c), 1);
|
|
RETURN M.COUNT();
|
|
END;
|
|
|
|
FUNCTION first(M IN OUT NOCOPY mal_table,
|
|
seq integer) RETURN integer IS
|
|
BEGIN
|
|
RETURN TREAT(M(seq) AS mal_seq_T).val_seq(1);
|
|
END;
|
|
|
|
FUNCTION slice(M IN OUT NOCOPY mal_table,
|
|
seq integer,
|
|
idx integer,
|
|
last integer DEFAULT NULL) RETURN integer IS
|
|
old_items mal_vals;
|
|
new_items mal_vals;
|
|
i integer;
|
|
final_idx integer;
|
|
BEGIN
|
|
old_items := TREAT(M(seq) AS mal_seq_T).val_seq;
|
|
new_items := mal_vals();
|
|
IF last IS NULL THEN
|
|
final_idx := old_items.COUNT();
|
|
ELSE
|
|
final_idx := last + 1;
|
|
END IF;
|
|
IF final_idx > idx THEN
|
|
new_items.EXTEND(final_idx - idx);
|
|
FOR i IN idx+1..final_idx LOOP
|
|
new_items(i-idx) := old_items(i);
|
|
END LOOP;
|
|
END IF;
|
|
M.EXTEND();
|
|
M(M.COUNT()) := mal_seq_T(8, new_items, 1);
|
|
RETURN M.COUNT();
|
|
END;
|
|
|
|
FUNCTION slice(M IN OUT NOCOPY mal_table,
|
|
items mal_vals,
|
|
idx integer) RETURN integer IS
|
|
new_items mal_vals;
|
|
BEGIN
|
|
new_items := islice(items, idx);
|
|
M.EXTEND();
|
|
M(M.COUNT()) := mal_seq_T(8, new_items, 1);
|
|
RETURN M.COUNT();
|
|
END;
|
|
|
|
FUNCTION islice(items mal_vals,
|
|
idx integer) RETURN mal_vals IS
|
|
new_items mal_vals;
|
|
i integer;
|
|
BEGIN
|
|
new_items := mal_vals();
|
|
IF items.COUNT > idx THEN
|
|
new_items.EXTEND(items.COUNT - idx);
|
|
FOR i IN idx+1..items.COUNT LOOP
|
|
new_items(i-idx) := items(i);
|
|
END LOOP;
|
|
END IF;
|
|
RETURN new_items;
|
|
END;
|
|
|
|
|
|
FUNCTION nth(M IN OUT NOCOPY mal_table,
|
|
seq integer, idx integer) RETURN integer IS
|
|
BEGIN
|
|
RETURN TREAT(M(seq) AS mal_seq_T).val_seq(idx+1);
|
|
END;
|
|
|
|
FUNCTION count(M IN OUT NOCOPY mal_table,
|
|
seq integer) RETURN integer IS
|
|
BEGIN
|
|
RETURN TREAT(M(seq) AS mal_seq_T).val_seq.COUNT;
|
|
END;
|
|
|
|
-- ---------------------------------------------------------
|
|
-- hash-map functions
|
|
|
|
FUNCTION assoc_BANG(M IN OUT NOCOPY mal_table,
|
|
H IN OUT NOCOPY map_entry_table,
|
|
midx integer,
|
|
kvs mal_vals) RETURN integer IS
|
|
i integer;
|
|
BEGIN
|
|
IF MOD(kvs.COUNT(), 2) = 1 THEN
|
|
raise_application_error(-20007,
|
|
'odd number of arguments to assoc', TRUE);
|
|
END IF;
|
|
|
|
i := 1;
|
|
WHILE i <= kvs.COUNT() LOOP
|
|
H(midx)(TREAT(M(kvs(i)) AS mal_str_T).val_str) := kvs(i+1);
|
|
i := i + 2;
|
|
END LOOP;
|
|
RETURN midx;
|
|
END;
|
|
|
|
FUNCTION dissoc_BANG(M IN OUT NOCOPY mal_table,
|
|
H IN OUT NOCOPY map_entry_table,
|
|
midx integer,
|
|
ks mal_vals) RETURN integer IS
|
|
i integer;
|
|
BEGIN
|
|
FOR i IN 1..ks.COUNT() LOOP
|
|
H(midx).DELETE(TREAT(M(ks(i)) AS mal_str_T).val_str);
|
|
END LOOP;
|
|
RETURN midx;
|
|
END;
|
|
|
|
FUNCTION hash_map(M IN OUT NOCOPY mal_table,
|
|
H IN OUT NOCOPY map_entry_table,
|
|
kvs mal_vals,
|
|
meta integer DEFAULT 1) RETURN integer IS
|
|
midx integer;
|
|
BEGIN
|
|
H.EXTEND();
|
|
midx := H.COUNT();
|
|
midx := assoc_BANG(M, H, midx, kvs);
|
|
|
|
M.EXTEND();
|
|
M(M.COUNT()) := mal_map_T(10, midx, meta);
|
|
RETURN M.COUNT();
|
|
END;
|
|
|
|
|
|
-- ---------------------------------------------------------
|
|
-- function functions
|
|
|
|
FUNCTION func(M IN OUT NOCOPY mal_table, name varchar) RETURN integer IS
|
|
BEGIN
|
|
M.EXTEND();
|
|
M(M.COUNT()) := mal_str_T(11, name);
|
|
RETURN M.COUNT();
|
|
END;
|
|
|
|
FUNCTION malfunc(M IN OUT NOCOPY mal_table,
|
|
ast integer,
|
|
params integer,
|
|
env integer,
|
|
is_macro integer DEFAULT 0,
|
|
meta integer DEFAULT 1) RETURN integer IS
|
|
BEGIN
|
|
M.EXTEND();
|
|
M(M.COUNT()) := mal_func_T(12, ast, params, env, is_macro, meta);
|
|
RETURN M.COUNT();
|
|
END;
|
|
|
|
|
|
-- ---------------------------------------------------------
|
|
-- atom functions
|
|
|
|
FUNCTION atom_new(M IN OUT NOCOPY mal_table,
|
|
val integer) RETURN integer IS
|
|
aidx integer;
|
|
BEGIN
|
|
M.EXTEND();
|
|
M(M.COUNT()) := mal_atom_T(13, val);
|
|
RETURN M.COUNT();
|
|
END;
|
|
|
|
FUNCTION atom_reset(M IN OUT NOCOPY mal_table,
|
|
atm integer,
|
|
val integer) RETURN integer IS
|
|
BEGIN
|
|
M(atm) := mal_atom_T(13, val);
|
|
RETURN val;
|
|
END;
|
|
|
|
|
|
|
|
END types;
|
|
/
|
|
show errors;
|