plsql: self-hosting. Long strings, refactor io.
[jackhill/mal.git] / plsql / core.sql
dissimilarity index 78%
index 9878c24..efae394 100644 (file)
-PROMPT 'core.sql start';
-
-CREATE OR REPLACE TYPE core_ns_type IS TABLE OF varchar2(100);
-/
-
-CREATE OR REPLACE PACKAGE core_pkg IS
-
-FUNCTION do_core_func(fn mal_type, args mal_seq_items_type) RETURN mal_type;
-
-FUNCTION get_core_ns RETURN core_ns_type;
-
-END core_pkg;
-/
-
-
-CREATE OR REPLACE PACKAGE BODY core_pkg AS
-
--- general functions
-FUNCTION equal_Q(args mal_seq_items_type) RETURN mal_type IS
-BEGIN
-    RETURN types_pkg.wraptf(types_pkg.equal_Q(args(1), args(2)));
-END;
-
--- string functions
-FUNCTION pr_str(args mal_seq_items_type) RETURN mal_type IS
-BEGIN
-    RETURN mal_str_type(5, printer_pkg.pr_str_seq(args, ' ', TRUE));
-END;
-
-FUNCTION str(args mal_seq_items_type) RETURN mal_type IS
-BEGIN
-    RETURN mal_str_type(5, printer_pkg.pr_str_seq(args, '', FALSE));
-END;
-
-FUNCTION prn(args mal_seq_items_type) RETURN mal_type IS
-BEGIN
-    stream_writeline(printer_pkg.pr_str_seq(args, ' ', TRUE));
-    RETURN mal_type(0);
-END;
-
-FUNCTION println(args mal_seq_items_type) RETURN mal_type IS
-BEGIN
-    stream_writeline(printer_pkg.pr_str_seq(args, ' ', FALSE));
-    RETURN mal_type(0);
-END;
-
-FUNCTION read_string(args mal_seq_items_type) RETURN mal_type IS
-BEGIN
-    RETURN reader_pkg.read_str(TREAT(args(1) AS mal_str_type).val_str);
-END;
-
-FUNCTION slurp(args mal_seq_items_type) RETURN mal_type IS
-    content  varchar2(4000);
-BEGIN
-    -- stream_writeline('here1: ' || TREAT(args(1) AS mal_str_type).val_str);
-    content := file_open_and_read(TREAT(args(1) AS mal_str_type).val_str);
-    content := REPLACE(content, '\n', chr(10));
-    RETURN mal_str_type(5, content);
-END;
-
-
--- numeric functions
-FUNCTION lt(args mal_seq_items_type) RETURN mal_type IS
-BEGIN
-    RETURN types_pkg.wraptf(TREAT(args(1) AS mal_int_type).val_int <
-                            TREAT(args(2) AS mal_int_type).val_int);
-END;
-
-FUNCTION lte(args mal_seq_items_type) RETURN mal_type IS
-BEGIN
-    RETURN types_pkg.wraptf(TREAT(args(1) AS mal_int_type).val_int <=
-                            TREAT(args(2) AS mal_int_type).val_int);
-END;
-
-FUNCTION gt(args mal_seq_items_type) RETURN mal_type IS
-BEGIN
-    RETURN types_pkg.wraptf(TREAT(args(1) AS mal_int_type).val_int >
-                            TREAT(args(2) AS mal_int_type).val_int);
-END;
-
-FUNCTION gte(args mal_seq_items_type) RETURN mal_type IS
-BEGIN
-    RETURN types_pkg.wraptf(TREAT(args(1) AS mal_int_type).val_int >=
-                            TREAT(args(2) AS mal_int_type).val_int);
-END;
-
-FUNCTION add(args mal_seq_items_type) RETURN mal_type IS
-BEGIN
-    RETURN mal_int_type(3, TREAT(args(1) AS mal_int_type).val_int +
-                           TREAT(args(2) AS mal_int_type).val_int);
-END;
-
-FUNCTION subtract(args mal_seq_items_type) RETURN mal_type IS
-BEGIN
-    RETURN mal_int_type(3, TREAT(args(1) AS mal_int_type).val_int -
-                           TREAT(args(2) AS mal_int_type).val_int);
-END;
-
-FUNCTION multiply(args mal_seq_items_type) RETURN mal_type IS
-BEGIN
-    RETURN mal_int_type(3, TREAT(args(1) AS mal_int_type).val_int *
-                           TREAT(args(2) AS mal_int_type).val_int);
-END;
-
-FUNCTION divide(args mal_seq_items_type) RETURN mal_type IS
-BEGIN
-    RETURN mal_int_type(3, TREAT(args(1) AS mal_int_type).val_int /
-                           TREAT(args(2) AS mal_int_type).val_int);
-END;
-
--- general native function case/switch
-FUNCTION do_core_func(fn mal_type, args mal_seq_items_type) RETURN mal_type IS
-    fname  varchar(100);
-BEGIN
-    IF fn.type_id <> 11 THEN
-        raise_application_error(-20004,
-            'Invalid function call', TRUE);
-    END IF;
-
-    fname := TREAT(fn AS mal_str_type).val_str;
-
-    CASE
-    WHEN fname = '='           THEN RETURN equal_Q(args);
-
-    WHEN fname = 'pr-str'      THEN RETURN pr_str(args);
-    WHEN fname = 'str'         THEN RETURN str(args);
-    WHEN fname = 'prn'         THEN RETURN prn(args);
-    WHEN fname = 'println'     THEN RETURN println(args);
-    WHEN fname = 'read-string' THEN RETURN read_string(args);
-    WHEN fname = 'slurp'       THEN RETURN slurp(args);
-
-    WHEN fname = '<'  THEN RETURN lt(args);
-    WHEN fname = '<=' THEN RETURN lte(args);
-    WHEN fname = '>'  THEN RETURN gt(args);
-    WHEN fname = '>=' THEN RETURN gte(args);
-    WHEN fname = '+' THEN RETURN add(args);
-    WHEN fname = '-' THEN RETURN subtract(args);
-    WHEN fname = '*' THEN RETURN multiply(args);
-    WHEN fname = '/' THEN RETURN divide(args);
-
-    WHEN fname = 'list' THEN RETURN types_pkg.list(args);
-    WHEN fname = 'list?' THEN RETURN types_pkg.wraptf(args(1).type_id = 8);
-
-    WHEN fname = 'empty?' THEN
-        RETURN types_pkg.wraptf(0 = types_pkg.count(args(1)));
-    WHEN fname = 'count' THEN
-        IF args(1).type_id = 0 THEN
-            RETURN mal_int_type(3, 0);
-        ELSE
-            RETURN mal_int_type(3, types_pkg.count(args(1)));
-        END IF;
-
-    ELSE raise_application_error(-20004,
-            'Invalid function call', TRUE);
-    END CASE;
-END;
-
-FUNCTION get_core_ns RETURN core_ns_type IS
-BEGIN
-    RETURN core_ns_type(
-        '=',
-
-        'pr-str',
-        'str',
-        'prn',
-        'println',
-        'read-string',
-        'slurp',
-
-        '<',
-        '<=',
-        '>',
-        '>=',
-        '+',
-        '-',
-        '*',
-        '/',
-
-        'list',
-        'list?',
-
-        'empty?',
-        'count',
-
-        -- defined in step do_builtin function
-        'atom',
-        'atom?',
-        'deref',
-        'reset!',
-        'swap!');
-END;
-
-END core_pkg;
-/
-show errors;
-
-PROMPT 'core.sql finished';
+PROMPT 'core.sql start';
+
+CREATE OR REPLACE TYPE core_ns_type IS TABLE OF varchar2(100);
+/
+
+CREATE OR REPLACE PACKAGE core IS
+
+FUNCTION do_core_func(M IN OUT NOCOPY mem_type,
+                      H IN OUT NOCOPY types.map_entry_table,
+                      fn integer,
+                      a mal_seq_items_type) RETURN integer;
+
+FUNCTION get_core_ns RETURN core_ns_type;
+
+END core;
+/
+
+
+CREATE OR REPLACE PACKAGE BODY core AS
+
+-- general functions
+FUNCTION equal_Q(M IN OUT NOCOPY mem_type,
+                 H IN OUT NOCOPY types.map_entry_table,
+                 args mal_seq_items_type) RETURN integer IS
+BEGIN
+    RETURN types.tf(types.equal_Q(M, H, args(1), args(2)));
+END;
+
+-- scalar functiosn
+FUNCTION symbol(M IN OUT NOCOPY mem_type,
+                val integer) RETURN integer IS
+BEGIN
+    RETURN types.symbol(M, TREAT(M(val) AS mal_str_type).val_str);
+END;
+
+FUNCTION keyword(M IN OUT NOCOPY mem_type,
+                 val integer) RETURN integer IS
+BEGIN
+    IF types.string_Q(M, val) THEN
+        RETURN types.keyword(M, TREAT(M(val) AS mal_str_type).val_str);
+    ELSIF types.keyword_Q(M, val) THEN
+        RETURN val;
+    ELSE
+        raise_application_error(-20009,
+            'invalid keyword call', TRUE);
+    END IF;
+END;
+
+
+-- string functions
+FUNCTION pr_str(M IN OUT NOCOPY mem_type,
+                H IN OUT NOCOPY types.map_entry_table,
+                args mal_seq_items_type) RETURN integer IS
+BEGIN
+    RETURN types.string(M, printer.pr_str_seq(M, H, args, ' ', TRUE));
+END;
+
+FUNCTION str(M IN OUT NOCOPY mem_type,
+             H IN OUT NOCOPY types.map_entry_table,
+             args mal_seq_items_type) RETURN integer IS
+BEGIN
+    RETURN types.string(M, printer.pr_str_seq(M, H, args, '', FALSE));
+END;
+
+FUNCTION prn(M IN OUT NOCOPY mem_type,
+             H IN OUT NOCOPY types.map_entry_table,
+             args mal_seq_items_type) RETURN integer IS
+BEGIN
+    stream_writeline(printer.pr_str_seq(M, H, args, ' ', TRUE));
+    RETURN 1;  -- nil
+END;
+
+FUNCTION println(M IN OUT NOCOPY mem_type,
+                 H IN OUT NOCOPY types.map_entry_table,
+                 args mal_seq_items_type) RETURN integer IS
+BEGIN
+    stream_writeline(printer.pr_str_seq(M, H, args, ' ', FALSE));
+    RETURN 1;  -- nil
+END;
+
+FUNCTION read_string(M IN OUT NOCOPY mem_type,
+                     H IN OUT NOCOPY types.map_entry_table,
+                     args mal_seq_items_type) RETURN integer IS
+BEGIN
+    IF M(args(1)).type_id = 5 THEN
+        RETURN reader.read_str(M, H,
+            TREAT(M(args(1)) AS mal_str_type).val_str);
+    ELSE
+        RETURN reader.read_str(M, H,
+            TREAT(M(args(1)) AS mal_long_str_type).val_long_str);
+    END IF;
+END;
+
+FUNCTION readline(M IN OUT NOCOPY mem_type,
+                  prompt integer) RETURN integer IS
+    input  CLOB;
+BEGIN
+    input := stream_readline(TREAT(M(prompt) AS mal_str_type).val_str, 0);
+    RETURN types.string(M, input);
+EXCEPTION WHEN OTHERS THEN
+    IF SQLCODE = -20001 THEN  -- io streams closed
+        RETURN 1;  -- nil
+    ELSE
+        RAISE;
+    END IF;
+END;
+
+FUNCTION slurp(M IN OUT NOCOPY mem_type,
+               args mal_seq_items_type) RETURN integer IS
+    content  CLOB;
+BEGIN
+    content := io.file_open_and_read(TREAT(M(args(1)) AS mal_str_type).val_str);
+    content := REPLACE(content, '\n', chr(10));
+    RETURN types.string(M, content);
+END;
+
+
+-- numeric functions
+FUNCTION lt(M IN OUT NOCOPY mem_type,
+            args mal_seq_items_type) RETURN integer IS
+BEGIN
+    RETURN types.tf(TREAT(M(args(1)) AS mal_int_type).val_int <
+                        TREAT(M(args(2)) AS mal_int_type).val_int);
+END;
+
+FUNCTION lte(M IN OUT NOCOPY mem_type,
+             args mal_seq_items_type) RETURN integer IS
+BEGIN
+    RETURN types.tf(TREAT(M(args(1)) AS mal_int_type).val_int <=
+                        TREAT(M(args(2)) AS mal_int_type).val_int);
+END;
+
+FUNCTION gt(M IN OUT NOCOPY mem_type,
+            args mal_seq_items_type) RETURN integer IS
+BEGIN
+    RETURN types.tf(TREAT(M(args(1)) AS mal_int_type).val_int >
+                        TREAT(M(args(2)) AS mal_int_type).val_int);
+END;
+
+FUNCTION gte(M IN OUT NOCOPY mem_type,
+             args mal_seq_items_type) RETURN integer IS
+BEGIN
+    RETURN types.tf(TREAT(M(args(1)) AS mal_int_type).val_int >=
+                        TREAT(M(args(2)) AS mal_int_type).val_int);
+END;
+
+FUNCTION add(M IN OUT NOCOPY mem_type,
+             args mal_seq_items_type) RETURN integer IS
+BEGIN
+    RETURN types.int(M, TREAT(M(args(1)) AS mal_int_type).val_int +
+                        TREAT(M(args(2)) AS mal_int_type).val_int);
+END;
+
+FUNCTION subtract(M IN OUT NOCOPY mem_type,
+                  args mal_seq_items_type) RETURN integer IS
+BEGIN
+    RETURN types.int(M, TREAT(M(args(1)) AS mal_int_type).val_int -
+                        TREAT(M(args(2)) AS mal_int_type).val_int);
+END;
+
+FUNCTION multiply(M IN OUT NOCOPY mem_type,
+                  args mal_seq_items_type) RETURN integer IS
+BEGIN
+    RETURN types.int(M, TREAT(M(args(1)) AS mal_int_type).val_int *
+                        TREAT(M(args(2)) AS mal_int_type).val_int);
+END;
+
+FUNCTION divide(M IN OUT NOCOPY mem_type,
+                args mal_seq_items_type) RETURN integer IS
+BEGIN
+    RETURN types.int(M, TREAT(M(args(1)) AS mal_int_type).val_int /
+                        TREAT(M(args(2)) AS mal_int_type).val_int);
+END;
+
+FUNCTION time_ms(M IN OUT NOCOPY mem_type) RETURN integer IS
+    now  integer;
+BEGIN
+    -- SELECT (SYSDATE - TO_DATE('01-01-1970 00:00:00', 'DD-MM-YYYY HH24:MI:SS')) * 24 * 60 * 60 * 1000
+    --    INTO now FROM DUAL;
+    SELECT extract(day from(sys_extract_utc(systimestamp) - to_timestamp('1970-01-01', 'YYYY-MM-DD'))) * 86400000 + to_number(to_char(sys_extract_utc(systimestamp), 'SSSSSFF3'))
+        INTO now
+        FROM dual;
+    RETURN types.int(M, now);
+END;
+
+-- hash-map functions
+FUNCTION assoc(M IN OUT NOCOPY mem_type,
+               H IN OUT NOCOPY types.map_entry_table,
+               hm integer,
+               kvs mal_seq_items_type) RETURN integer IS
+    new_hm    integer;
+    midx      integer;
+BEGIN
+    new_hm := types.clone(M, H, hm);
+    midx := TREAT(M(new_hm) AS mal_map_type).map_idx;
+    -- Add the new key/values
+    midx := types.assoc_BANG(M, H, midx, kvs);
+    RETURN new_hm;
+END;
+
+FUNCTION dissoc(M IN OUT NOCOPY mem_type,
+                H IN OUT NOCOPY types.map_entry_table,
+                hm integer,
+                ks mal_seq_items_type) RETURN integer IS
+    new_hm    integer;
+    midx      integer;
+BEGIN
+    new_hm := types.clone(M, H, hm);
+    midx := TREAT(M(new_hm) AS mal_map_type).map_idx;
+    -- Remove the keys
+    midx := types.dissoc_BANG(M, H, midx, ks);
+    RETURN new_hm;
+END;
+
+
+FUNCTION get(M IN OUT NOCOPY mem_type,
+             H IN OUT NOCOPY types.map_entry_table,
+             hm integer, key integer) RETURN integer IS
+    midx  integer;
+    k     varchar2(256);
+    val   integer;
+BEGIN
+    IF M(hm).type_id = 0 THEN
+        RETURN 1;  -- nil
+    END IF;
+    midx := TREAT(M(hm) AS mal_map_type).map_idx;
+    k := TREAT(M(key) AS mal_str_type).val_str;
+    IF H(midx).EXISTS(k) THEN
+        RETURN H(midx)(k);
+    ELSE
+        RETURN 1;  -- nil
+    END IF;
+END;
+
+FUNCTION contains_Q(M IN OUT NOCOPY mem_type,
+             H IN OUT NOCOPY types.map_entry_table,
+             hm integer, key integer) RETURN integer IS
+    midx  integer;
+    k     varchar2(256);
+    val   integer;
+BEGIN
+    midx := TREAT(M(hm) AS mal_map_type).map_idx;
+    k := TREAT(M(key) AS mal_str_type).val_str;
+    RETURN types.tf(H(midx).EXISTS(k));
+END;
+
+FUNCTION keys(M IN OUT NOCOPY mem_type,
+              H IN OUT NOCOPY types.map_entry_table,
+              hm integer) RETURN integer IS
+    midx  integer;
+    k     varchar2(256);
+    ks    mal_seq_items_type;
+    val   integer;
+BEGIN
+    midx := TREAT(M(hm) AS mal_map_type).map_idx;
+    ks := mal_seq_items_type();
+
+    k := H(midx).FIRST();
+    WHILE k IS NOT NULL LOOP
+        ks.EXTEND();
+        ks(ks.COUNT()) := types.string(M, k);
+        k := H(midx).NEXT(k);
+    END LOOP;
+
+    RETURN types.seq(M, 8, ks);
+END;
+
+FUNCTION vals(M IN OUT NOCOPY mem_type,
+              H IN OUT NOCOPY types.map_entry_table,
+              hm integer) RETURN integer IS
+    midx  integer;
+    k     varchar2(256);
+    ks    mal_seq_items_type;
+    val   integer;
+BEGIN
+    midx := TREAT(M(hm) AS mal_map_type).map_idx;
+    ks := mal_seq_items_type();
+
+    k := H(midx).FIRST();
+    WHILE k IS NOT NULL LOOP
+        ks.EXTEND();
+        ks(ks.COUNT()) := H(midx)(k);
+        k := H(midx).NEXT(k);
+    END LOOP;
+
+    RETURN types.seq(M, 8, ks);
+END;
+
+
+-- sequence functions
+FUNCTION cons(M IN OUT NOCOPY mem_type,
+              args mal_seq_items_type) RETURN integer IS
+    new_items  mal_seq_items_type;
+    len        integer;
+    i          integer;
+BEGIN
+    new_items := mal_seq_items_type();
+    len := types.count(M, args(2));
+    new_items.EXTEND(len+1);
+    new_items(1) := args(1);
+    FOR i IN 1..len LOOP
+        new_items(i+1) := TREAT(M(args(2)) AS mal_seq_type).val_seq(i);
+    END LOOP;
+    RETURN types.seq(M, 8, new_items);
+END;
+
+FUNCTION concat(M IN OUT NOCOPY mem_type,
+                args mal_seq_items_type) RETURN integer IS
+    new_items  mal_seq_items_type;
+    cur_len    integer;
+    seq_len    integer;
+    i          integer;
+    j          integer;
+BEGIN
+    new_items := mal_seq_items_type();
+    cur_len := 0;
+    FOR i IN 1..args.COUNT() LOOP
+        seq_len := types.count(M, args(i));
+        new_items.EXTEND(seq_len);
+        FOR j IN 1..seq_len LOOP
+            new_items(cur_len + j) := types.nth(M, args(i), j-1);
+        END LOOP;
+        cur_len := cur_len + seq_len;
+    END LOOP;
+    RETURN types.seq(M, 8, new_items);
+END;
+
+
+FUNCTION nth(M IN OUT NOCOPY mem_type,
+             val integer,
+             ival integer) RETURN integer IS
+    idx  integer;
+BEGIN
+    idx := TREAT(M(ival) AS mal_int_type).val_int;
+    RETURN types.nth(M, val, idx);
+END;
+
+FUNCTION first(M IN OUT NOCOPY mem_type,
+               val integer) RETURN integer IS
+BEGIN
+    IF val = 1 OR types.count(M, val) = 0 THEN
+        RETURN 1;  -- nil
+    ELSE
+        RETURN types.first(M, val);
+    END IF;
+END;
+
+FUNCTION rest(M IN OUT NOCOPY mem_type,
+              val integer) RETURN integer IS
+BEGIN
+    IF val = 1 OR types.count(M, val) = 0 THEN
+        RETURN types.list(M);
+    ELSE
+        RETURN types.slice(M, val, 1);
+    END IF;
+END;
+
+FUNCTION do_count(M IN OUT NOCOPY mem_type,
+               val integer) RETURN integer IS
+BEGIN
+    IF M(val).type_id = 0 THEN
+        RETURN types.int(M, 0);
+    ELSE
+        RETURN types.int(M, types.count(M, val));
+    END IF;
+END;
+
+
+FUNCTION conj(M IN OUT NOCOPY mem_type,
+              seq integer,
+              vals mal_seq_items_type) RETURN integer IS
+    type_id  integer;
+    slen     integer;
+    items    mal_seq_items_type;
+BEGIN
+    type_id := M(seq).type_id;
+    slen := types.count(M, seq);
+    items := mal_seq_items_type();
+    items.EXTEND(slen + vals.COUNT());
+    CASE
+    WHEN type_id = 8 THEN
+        FOR i IN 1..vals.COUNT() LOOP
+            items(i) := vals(vals.COUNT + 1 - i);
+        END LOOP;
+        FOR i IN 1..slen LOOP
+            items(vals.COUNT() + i) := types.nth(M, seq, i-1);
+        END LOOP;
+    WHEN type_id = 9 THEN
+        FOR i IN 1..slen LOOP
+            items(i) := types.nth(M, seq, i-1);
+        END LOOP;
+        FOR i IN 1..vals.COUNT() LOOP
+            items(slen + i) := vals(i);
+        END LOOP;
+    ELSE
+        raise_application_error(-20009,
+            'conj: not supported on type ' || type_id, TRUE);
+    END CASE;
+    RETURN types.seq(M, type_id, items);
+END;
+
+FUNCTION seq(M IN OUT NOCOPY mem_type,
+             val integer) RETURN integer IS
+    type_id    integer;
+    new_val    integer;
+    str        CLOB;
+    str_items  mal_seq_items_type;
+BEGIN
+    type_id := M(val).type_id;
+    CASE
+    WHEN type_id = 8 THEN
+        IF types.count(M, val) = 0 THEN
+            RETURN 1;  -- nil
+        END IF;
+        RETURN val;
+    WHEN type_id = 9 THEN
+        IF types.count(M, val) = 0 THEN
+            RETURN 1;  -- nil
+        END IF;
+        RETURN types.seq(M, 8, TREAT(M(val) AS mal_seq_type).val_seq);
+    WHEN types.string_Q(M, val) THEN
+        str := TREAT(M(val) AS mal_str_type).val_str;
+        IF str IS NULL THEN
+            RETURN 1;  -- nil
+        END IF;
+        str_items := mal_seq_items_type();
+        str_items.EXTEND(LENGTH(str));
+        FOR i IN 1..LENGTH(str) LOOP
+            str_items(i) := types.string(M, SUBSTR(str, i, 1));
+        END LOOP;
+        RETURN types.seq(M, 8, str_items);
+    WHEN type_id = 0 THEN
+        RETURN 1;  -- nil
+    ELSE
+        raise_application_error(-20009,
+            'seq: not supported on type ' || type_id, TRUE);
+    END CASE;
+END;
+
+-- atom functions
+FUNCTION reset_BANG(M IN OUT NOCOPY mem_type,
+                    atm integer,
+                    new_val integer) RETURN integer IS
+BEGIN
+    M(atm) := mal_atom_type(13, new_val);
+    RETURN new_val;
+END;
+
+-- metadata functions
+FUNCTION meta(M IN OUT NOCOPY mem_type,
+              val integer) RETURN integer IS
+    type_id  integer;
+BEGIN
+    type_id := M(val).type_id;
+    IF type_id IN (8,9) THEN  -- list/vector
+        RETURN TREAT(M(val) AS mal_seq_type).meta;
+    ELSIF type_id = 10 THEN   -- hash-map
+        RETURN TREAT(M(val) AS mal_map_type).meta;
+    ELSIF type_id = 11 THEN   -- native function
+        RETURN 1;  -- nil
+    ELSIF type_id = 12 THEN   -- mal function
+        RETURN TREAT(M(val) AS malfunc_type).meta;
+    ELSE
+        raise_application_error(-20006,
+            'meta: metadata not supported on type', TRUE);
+    END IF;
+END;
+
+-- general native function case/switch
+FUNCTION do_core_func(M IN OUT NOCOPY mem_type,
+                      H IN OUT NOCOPY types.map_entry_table,
+                      fn integer,
+                      a mal_seq_items_type) RETURN integer IS
+    fname  varchar(256);
+    idx    integer;
+BEGIN
+    IF M(fn).type_id <> 11 THEN
+        raise_application_error(-20004,
+            'Invalid function call', TRUE);
+    END IF;
+
+    fname := TREAT(M(fn) AS mal_str_type).val_str;
+
+    CASE
+    WHEN fname = '='           THEN RETURN equal_Q(M, H, a);
+
+    WHEN fname = 'nil?'        THEN RETURN types.tf(a(1) = 1);
+    WHEN fname = 'false?'      THEN RETURN types.tf(a(1) = 2);
+    WHEN fname = 'true?'       THEN RETURN types.tf(a(1) = 3);
+    WHEN fname = 'string?'     THEN RETURN types.tf(types.string_Q(M, a(1)));
+    WHEN fname = 'symbol'      THEN RETURN symbol(M, a(1));
+    WHEN fname = 'symbol?'     THEN RETURN types.tf(M(a(1)).type_id = 7);
+    WHEN fname = 'keyword'     THEN RETURN keyword(M, a(1));
+    WHEN fname = 'keyword?'    THEN RETURN types.tf(types.keyword_Q(M, a(1)));
+
+    WHEN fname = 'pr-str'      THEN RETURN pr_str(M, H, a);
+    WHEN fname = 'str'         THEN RETURN str(M, H, a);
+    WHEN fname = 'prn'         THEN RETURN prn(M, H, a);
+    WHEN fname = 'println'     THEN RETURN println(M, H, a);
+    WHEN fname = 'read-string' THEN RETURN read_string(M, H, a);
+    WHEN fname = 'readline'    THEN RETURN readline(M, a(1));
+    WHEN fname = 'slurp'       THEN RETURN slurp(M, a);
+
+    WHEN fname = '<'           THEN RETURN lt(M, a);
+    WHEN fname = '<='          THEN RETURN lte(M, a);
+    WHEN fname = '>'           THEN RETURN gt(M, a);
+    WHEN fname = '>='          THEN RETURN gte(M, a);
+    WHEN fname = '+'           THEN RETURN add(M, a);
+    WHEN fname = '-'           THEN RETURN subtract(M, a);
+    WHEN fname = '*'           THEN RETURN multiply(M, a);
+    WHEN fname = '/'           THEN RETURN divide(M, a);
+    WHEN fname = 'time-ms'     THEN RETURN time_ms(M);
+
+    WHEN fname = 'list'        THEN RETURN types.seq(M, 8, a);
+    WHEN fname = 'list?'       THEN RETURN types.tf(M(a(1)).type_id = 8);
+    WHEN fname = 'vector'      THEN RETURN types.seq(M, 9, a);
+    WHEN fname = 'vector?'     THEN RETURN types.tf(M(a(1)).type_id = 9);
+    WHEN fname = 'hash-map'    THEN RETURN types.hash_map(M, H, a);
+    WHEN fname = 'assoc'       THEN RETURN assoc(M, H, a(1), types.islice(a, 1));
+    WHEN fname = 'dissoc'      THEN RETURN dissoc(M, H, a(1), types.islice(a, 1));
+    WHEN fname = 'map?'        THEN RETURN types.tf(M(a(1)).type_id = 10);
+    WHEN fname = 'get'         THEN RETURN get(M, H, a(1), a(2));
+    WHEN fname = 'contains?'   THEN RETURN contains_Q(M, H, a(1), a(2));
+    WHEN fname = 'keys'        THEN RETURN keys(M, H, a(1));
+    WHEN fname = 'vals'        THEN RETURN vals(M, H, a(1));
+
+    WHEN fname = 'sequential?' THEN RETURN types.tf(M(a(1)).type_id IN (8,9));
+    WHEN fname = 'cons'        THEN RETURN cons(M, a);
+    WHEN fname = 'concat'      THEN RETURN concat(M, a);
+    WHEN fname = 'nth'         THEN RETURN nth(M, a(1), a(2));
+    WHEN fname = 'first'       THEN RETURN first(M, a(1));
+    WHEN fname = 'rest'        THEN RETURN rest(M, a(1));
+    WHEN fname = 'empty?'      THEN RETURN types.tf(0 = types.count(M, a(1)));
+    WHEN fname = 'count'       THEN RETURN do_count(M, a(1));
+
+    WHEN fname = 'conj'        THEN RETURN conj(M, a(1), types.islice(a, 1));
+    WHEN fname = 'seq'         THEN RETURN seq(M, a(1));
+
+    WHEN fname = 'meta'        THEN RETURN meta(M, a(1));
+    WHEN fname = 'with-meta'   THEN RETURN types.clone(M, H, a(1), a(2));
+    WHEN fname = 'atom'        THEN RETURN types.atom_new(M, a(1));
+    WHEN fname = 'atom?'       THEN RETURN types.tf(M(a(1)).type_id = 13);
+    WHEN fname = 'deref'       THEN RETURN TREAT(M(a(1)) AS mal_atom_type).val;
+    WHEN fname = 'reset!'      THEN RETURN reset_BANG(M, a(1), a(2));
+
+    ELSE raise_application_error(-20004, 'Invalid function call', TRUE);
+    END CASE;
+END;
+
+FUNCTION get_core_ns RETURN core_ns_type IS
+BEGIN
+    RETURN core_ns_type(
+        '=',
+        'throw',
+
+        'nil?',
+        'true?',
+        'false?',
+        'string?',
+        'symbol',
+        'symbol?',
+        'keyword',
+        'keyword?',
+
+        'pr-str',
+        'str',
+        'prn',
+        'println',
+        'read-string',
+        'readline',
+        'slurp',
+
+        '<',
+        '<=',
+        '>',
+        '>=',
+        '+',
+        '-',
+        '*',
+        '/',
+        'time-ms',
+
+        'list',
+        'list?',
+        'vector',
+        'vector?',
+        'hash-map',
+        'assoc',
+        'dissoc',
+        'map?',
+        'get',
+        'contains?',
+        'keys',
+        'vals',
+
+        'sequential?',
+        'cons',
+        'concat',
+        'nth',
+        'first',
+        'rest',
+        'empty?',
+        'count',
+        'apply',   -- defined in step do_builtin function
+        'map',     -- defined in step do_builtin function
+
+        'conj',
+        'seq',
+
+        'meta',
+        'with-meta',
+        'atom',
+        'atom?',
+        'deref',
+        'reset!',
+        'swap!'    -- defined in step do_builtin function
+    );
+END;
+
+END core;
+/
+show errors;
+
+PROMPT 'core.sql finished';