plsql: keyword/vector/hash-map. Other deferrables.
[jackhill/mal.git] / plsql / core.sql
1 PROMPT 'core.sql start';
2
3 CREATE OR REPLACE TYPE core_ns_type IS TABLE OF varchar2(100);
4 /
5
6 CREATE OR REPLACE PACKAGE core IS
7
8 FUNCTION do_core_func(M IN OUT NOCOPY mem_type,
9 H IN OUT NOCOPY types.map_entry_table,
10 fn integer,
11 a mal_seq_items_type) RETURN integer;
12
13 FUNCTION get_core_ns RETURN core_ns_type;
14
15 END core;
16 /
17
18
19 CREATE OR REPLACE PACKAGE BODY core AS
20
21 -- general functions
22 FUNCTION equal_Q(M IN OUT NOCOPY mem_type,
23 H IN OUT NOCOPY types.map_entry_table,
24 args mal_seq_items_type) RETURN integer IS
25 BEGIN
26 RETURN types.tf(types.equal_Q(M, H, args(1), args(2)));
27 END;
28
29 -- scalar functiosn
30 FUNCTION symbol(M IN OUT NOCOPY mem_type,
31 val integer) RETURN integer IS
32 BEGIN
33 RETURN types.symbol(M, TREAT(M(val) AS mal_str_type).val_str);
34 END;
35
36 FUNCTION keyword(M IN OUT NOCOPY mem_type,
37 val integer) RETURN integer IS
38 BEGIN
39 IF types.string_Q(M, val) THEN
40 RETURN types.keyword(M, TREAT(M(val) AS mal_str_type).val_str);
41 ELSIF types.keyword_Q(M, val) THEN
42 RETURN val;
43 ELSE
44 raise_application_error(-20009,
45 'invalid keyword call', TRUE);
46 END IF;
47 END;
48
49
50 -- string functions
51 FUNCTION pr_str(M IN OUT NOCOPY mem_type,
52 H IN OUT NOCOPY types.map_entry_table,
53 args mal_seq_items_type) RETURN integer IS
54 BEGIN
55 RETURN types.string(M, printer.pr_str_seq(M, H, args, ' ', TRUE));
56 END;
57
58 FUNCTION str(M IN OUT NOCOPY mem_type,
59 H IN OUT NOCOPY types.map_entry_table,
60 args mal_seq_items_type) RETURN integer IS
61 BEGIN
62 RETURN types.string(M, printer.pr_str_seq(M, H, args, '', FALSE));
63 END;
64
65 FUNCTION prn(M IN OUT NOCOPY mem_type,
66 H IN OUT NOCOPY types.map_entry_table,
67 args mal_seq_items_type) RETURN integer IS
68 BEGIN
69 stream_writeline(printer.pr_str_seq(M, H, args, ' ', TRUE));
70 RETURN 1; -- nil
71 END;
72
73 FUNCTION println(M IN OUT NOCOPY mem_type,
74 H IN OUT NOCOPY types.map_entry_table,
75 args mal_seq_items_type) RETURN integer IS
76 BEGIN
77 stream_writeline(printer.pr_str_seq(M, H, args, ' ', FALSE));
78 RETURN 1; -- nil
79 END;
80
81 FUNCTION read_string(M IN OUT NOCOPY mem_type,
82 H IN OUT NOCOPY types.map_entry_table,
83 args mal_seq_items_type) RETURN integer IS
84 BEGIN
85 RETURN reader.read_str(M, H, TREAT(M(args(1)) AS mal_str_type).val_str);
86 END;
87
88 FUNCTION readline(M IN OUT NOCOPY mem_type,
89 prompt integer) RETURN integer IS
90 input varchar2(4000);
91 BEGIN
92 input := stream_readline(TREAT(M(prompt) AS mal_str_type).val_str, 0);
93 RETURN types.string(M, input);
94 EXCEPTION WHEN OTHERS THEN
95 IF SQLCODE = -20001 THEN -- io streams closed
96 RETURN 1; -- nil
97 ELSE
98 RAISE;
99 END IF;
100 END;
101
102 FUNCTION slurp(M IN OUT NOCOPY mem_type,
103 args mal_seq_items_type) RETURN integer IS
104 content varchar2(4000);
105 BEGIN
106 -- stream_writeline('here1: ' || TREAT(args(1) AS mal_str_type).val_str);
107 content := file_open_and_read(TREAT(M(args(1)) AS mal_str_type).val_str);
108 content := REPLACE(content, '\n', chr(10));
109 RETURN types.string(M, content);
110 END;
111
112
113 -- numeric functions
114 FUNCTION lt(M IN OUT NOCOPY mem_type,
115 args mal_seq_items_type) RETURN integer IS
116 BEGIN
117 RETURN types.tf(TREAT(M(args(1)) AS mal_int_type).val_int <
118 TREAT(M(args(2)) AS mal_int_type).val_int);
119 END;
120
121 FUNCTION lte(M IN OUT NOCOPY mem_type,
122 args mal_seq_items_type) RETURN integer IS
123 BEGIN
124 RETURN types.tf(TREAT(M(args(1)) AS mal_int_type).val_int <=
125 TREAT(M(args(2)) AS mal_int_type).val_int);
126 END;
127
128 FUNCTION gt(M IN OUT NOCOPY mem_type,
129 args mal_seq_items_type) RETURN integer IS
130 BEGIN
131 RETURN types.tf(TREAT(M(args(1)) AS mal_int_type).val_int >
132 TREAT(M(args(2)) AS mal_int_type).val_int);
133 END;
134
135 FUNCTION gte(M IN OUT NOCOPY mem_type,
136 args mal_seq_items_type) RETURN integer IS
137 BEGIN
138 RETURN types.tf(TREAT(M(args(1)) AS mal_int_type).val_int >=
139 TREAT(M(args(2)) AS mal_int_type).val_int);
140 END;
141
142 FUNCTION add(M IN OUT NOCOPY mem_type,
143 args mal_seq_items_type) RETURN integer IS
144 BEGIN
145 RETURN types.int(M, TREAT(M(args(1)) AS mal_int_type).val_int +
146 TREAT(M(args(2)) AS mal_int_type).val_int);
147 END;
148
149 FUNCTION subtract(M IN OUT NOCOPY mem_type,
150 args mal_seq_items_type) RETURN integer IS
151 BEGIN
152 RETURN types.int(M, TREAT(M(args(1)) AS mal_int_type).val_int -
153 TREAT(M(args(2)) AS mal_int_type).val_int);
154 END;
155
156 FUNCTION multiply(M IN OUT NOCOPY mem_type,
157 args mal_seq_items_type) RETURN integer IS
158 BEGIN
159 RETURN types.int(M, TREAT(M(args(1)) AS mal_int_type).val_int *
160 TREAT(M(args(2)) AS mal_int_type).val_int);
161 END;
162
163 FUNCTION divide(M IN OUT NOCOPY mem_type,
164 args mal_seq_items_type) RETURN integer IS
165 BEGIN
166 RETURN types.int(M, TREAT(M(args(1)) AS mal_int_type).val_int /
167 TREAT(M(args(2)) AS mal_int_type).val_int);
168 END;
169
170 FUNCTION time_ms(M IN OUT NOCOPY mem_type) RETURN integer IS
171 now integer;
172 BEGIN
173 -- SELECT (SYSDATE - TO_DATE('01-01-1970 00:00:00', 'DD-MM-YYYY HH24:MI:SS')) * 24 * 60 * 60 * 1000
174 -- INTO now FROM DUAL;
175 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'))
176 INTO now
177 FROM dual;
178 RETURN types.int(M, now);
179 END;
180
181 -- hash-map functions
182 FUNCTION assoc(M IN OUT NOCOPY mem_type,
183 H IN OUT NOCOPY types.map_entry_table,
184 hm integer,
185 kvs mal_seq_items_type) RETURN integer IS
186 new_hm integer;
187 midx integer;
188 BEGIN
189 new_hm := types.clone(M, H, hm);
190 midx := TREAT(M(new_hm) AS mal_map_type).map_idx;
191 -- Add the new key/values
192 midx := types.assoc_BANG(M, H, midx, kvs);
193 RETURN new_hm;
194 END;
195
196 FUNCTION dissoc(M IN OUT NOCOPY mem_type,
197 H IN OUT NOCOPY types.map_entry_table,
198 hm integer,
199 ks mal_seq_items_type) RETURN integer IS
200 new_hm integer;
201 midx integer;
202 BEGIN
203 new_hm := types.clone(M, H, hm);
204 midx := TREAT(M(new_hm) AS mal_map_type).map_idx;
205 -- Remove the keys
206 midx := types.dissoc_BANG(M, H, midx, ks);
207 RETURN new_hm;
208 END;
209
210
211 FUNCTION get(M IN OUT NOCOPY mem_type,
212 H IN OUT NOCOPY types.map_entry_table,
213 hm integer, key integer) RETURN integer IS
214 midx integer;
215 k varchar2(256);
216 val integer;
217 BEGIN
218 IF M(hm).type_id = 0 THEN
219 RETURN 1; -- nil
220 END IF;
221 midx := TREAT(M(hm) AS mal_map_type).map_idx;
222 k := TREAT(M(key) AS mal_str_type).val_str;
223 IF H(midx).EXISTS(k) THEN
224 RETURN H(midx)(k);
225 ELSE
226 RETURN 1; -- nil
227 END IF;
228 END;
229
230 FUNCTION contains_Q(M IN OUT NOCOPY mem_type,
231 H IN OUT NOCOPY types.map_entry_table,
232 hm integer, key integer) RETURN integer IS
233 midx integer;
234 k varchar2(256);
235 val integer;
236 BEGIN
237 midx := TREAT(M(hm) AS mal_map_type).map_idx;
238 k := TREAT(M(key) AS mal_str_type).val_str;
239 RETURN types.tf(H(midx).EXISTS(k));
240 END;
241
242 FUNCTION keys(M IN OUT NOCOPY mem_type,
243 H IN OUT NOCOPY types.map_entry_table,
244 hm integer) RETURN integer IS
245 midx integer;
246 k varchar2(256);
247 ks mal_seq_items_type;
248 val integer;
249 BEGIN
250 midx := TREAT(M(hm) AS mal_map_type).map_idx;
251 ks := mal_seq_items_type();
252
253 k := H(midx).FIRST();
254 WHILE k IS NOT NULL LOOP
255 ks.EXTEND();
256 ks(ks.COUNT()) := types.string(M, k);
257 k := H(midx).NEXT(k);
258 END LOOP;
259
260 RETURN types.seq(M, 8, ks);
261 END;
262
263 FUNCTION vals(M IN OUT NOCOPY mem_type,
264 H IN OUT NOCOPY types.map_entry_table,
265 hm integer) RETURN integer IS
266 midx integer;
267 k varchar2(256);
268 ks mal_seq_items_type;
269 val integer;
270 BEGIN
271 midx := TREAT(M(hm) AS mal_map_type).map_idx;
272 ks := mal_seq_items_type();
273
274 k := H(midx).FIRST();
275 WHILE k IS NOT NULL LOOP
276 ks.EXTEND();
277 ks(ks.COUNT()) := H(midx)(k);
278 k := H(midx).NEXT(k);
279 END LOOP;
280
281 RETURN types.seq(M, 8, ks);
282 END;
283
284
285 -- sequence functions
286 FUNCTION cons(M IN OUT NOCOPY mem_type,
287 args mal_seq_items_type) RETURN integer IS
288 new_items mal_seq_items_type;
289 len integer;
290 i integer;
291 BEGIN
292 new_items := mal_seq_items_type();
293 len := types.count(M, args(2));
294 new_items.EXTEND(len+1);
295 new_items(1) := args(1);
296 FOR i IN 1..len LOOP
297 new_items(i+1) := TREAT(M(args(2)) AS mal_seq_type).val_seq(i);
298 END LOOP;
299 RETURN types.seq(M, 8, new_items);
300 END;
301
302 FUNCTION concat(M IN OUT NOCOPY mem_type,
303 args mal_seq_items_type) RETURN integer IS
304 new_items mal_seq_items_type;
305 cur_len integer;
306 seq_len integer;
307 i integer;
308 j integer;
309 BEGIN
310 new_items := mal_seq_items_type();
311 cur_len := 0;
312 FOR i IN 1..args.COUNT() LOOP
313 seq_len := types.count(M, args(i));
314 new_items.EXTEND(seq_len);
315 FOR j IN 1..seq_len LOOP
316 new_items(cur_len + j) := types.nth(M, args(i), j-1);
317 END LOOP;
318 cur_len := cur_len + seq_len;
319 END LOOP;
320 RETURN types.seq(M, 8, new_items);
321 END;
322
323
324 FUNCTION nth(M IN OUT NOCOPY mem_type,
325 val integer,
326 ival integer) RETURN integer IS
327 idx integer;
328 BEGIN
329 idx := TREAT(M(ival) AS mal_int_type).val_int;
330 RETURN types.nth(M, val, idx);
331 END;
332
333 FUNCTION first(M IN OUT NOCOPY mem_type,
334 val integer) RETURN integer IS
335 BEGIN
336 IF val = 1 OR types.count(M, val) = 0 THEN
337 RETURN 1; -- nil
338 ELSE
339 RETURN types.first(M, val);
340 END IF;
341 END;
342
343 FUNCTION rest(M IN OUT NOCOPY mem_type,
344 val integer) RETURN integer IS
345 BEGIN
346 IF val = 1 OR types.count(M, val) = 0 THEN
347 RETURN types.list(M);
348 ELSE
349 RETURN types.slice(M, val, 1);
350 END IF;
351 END;
352
353 FUNCTION do_count(M IN OUT NOCOPY mem_type,
354 val integer) RETURN integer IS
355 BEGIN
356 IF M(val).type_id = 0 THEN
357 RETURN types.int(M, 0);
358 ELSE
359 RETURN types.int(M, types.count(M, val));
360 END IF;
361 END;
362
363
364 FUNCTION conj(M IN OUT NOCOPY mem_type,
365 seq integer,
366 vals mal_seq_items_type) RETURN integer IS
367 type_id integer;
368 slen integer;
369 items mal_seq_items_type;
370 BEGIN
371 type_id := M(seq).type_id;
372 slen := types.count(M, seq);
373 items := mal_seq_items_type();
374 items.EXTEND(slen + vals.COUNT());
375 CASE
376 WHEN type_id = 8 THEN
377 FOR i IN 1..vals.COUNT() LOOP
378 items(i) := vals(vals.COUNT + 1 - i);
379 END LOOP;
380 FOR i IN 1..slen LOOP
381 items(vals.COUNT() + i) := types.nth(M, seq, i-1);
382 END LOOP;
383 WHEN type_id = 9 THEN
384 FOR i IN 1..slen LOOP
385 items(i) := types.nth(M, seq, i-1);
386 END LOOP;
387 FOR i IN 1..vals.COUNT() LOOP
388 items(slen + i) := vals(i);
389 END LOOP;
390 ELSE
391 raise_application_error(-20009,
392 'conj: not supported on type ' || type_id, TRUE);
393 END CASE;
394 RETURN types.seq(M, type_id, items);
395 END;
396
397 FUNCTION seq(M IN OUT NOCOPY mem_type,
398 val integer) RETURN integer IS
399 type_id integer;
400 new_val integer;
401 str varchar2(4000);
402 str_items mal_seq_items_type;
403 BEGIN
404 type_id := M(val).type_id;
405 CASE
406 WHEN type_id = 8 THEN
407 IF types.count(M, val) = 0 THEN
408 RETURN 1; -- nil
409 END IF;
410 RETURN val;
411 WHEN type_id = 9 THEN
412 IF types.count(M, val) = 0 THEN
413 RETURN 1; -- nil
414 END IF;
415 RETURN types.seq(M, 8, TREAT(M(val) AS mal_seq_type).val_seq);
416 WHEN types.string_Q(M, val) THEN
417 str := TREAT(M(val) AS mal_str_type).val_str;
418 IF str IS NULL THEN
419 RETURN 1; -- nil
420 END IF;
421 str_items := mal_seq_items_type();
422 str_items.EXTEND(LENGTH(str));
423 FOR i IN 1..LENGTH(str) LOOP
424 str_items(i) := types.string(M, SUBSTR(str, i, 1));
425 END LOOP;
426 RETURN types.seq(M, 8, str_items);
427 WHEN type_id = 0 THEN
428 RETURN 1; -- nil
429 ELSE
430 raise_application_error(-20009,
431 'seq: not supported on type ' || type_id, TRUE);
432 END CASE;
433 END;
434
435 -- atom functions
436 FUNCTION reset_BANG(M IN OUT NOCOPY mem_type,
437 atm integer,
438 new_val integer) RETURN integer IS
439 BEGIN
440 M(atm) := mal_atom_type(13, new_val);
441 RETURN new_val;
442 END;
443
444 -- metadata functions
445 FUNCTION meta(M IN OUT NOCOPY mem_type,
446 val integer) RETURN integer IS
447 type_id integer;
448 BEGIN
449 type_id := M(val).type_id;
450 IF type_id IN (8,9) THEN -- list/vector
451 RETURN TREAT(M(val) AS mal_seq_type).meta;
452 ELSIF type_id = 10 THEN -- hash-map
453 RETURN TREAT(M(val) AS mal_map_type).meta;
454 ELSIF type_id = 11 THEN -- native function
455 RETURN 1; -- nil
456 ELSIF type_id = 12 THEN -- mal function
457 RETURN TREAT(M(val) AS malfunc_type).meta;
458 ELSE
459 raise_application_error(-20006,
460 'meta: metadata not supported on type', TRUE);
461 END IF;
462 END;
463
464 -- general native function case/switch
465 FUNCTION do_core_func(M IN OUT NOCOPY mem_type,
466 H IN OUT NOCOPY types.map_entry_table,
467 fn integer,
468 a mal_seq_items_type) RETURN integer IS
469 fname varchar(100);
470 idx integer;
471 BEGIN
472 IF M(fn).type_id <> 11 THEN
473 raise_application_error(-20004,
474 'Invalid function call', TRUE);
475 END IF;
476
477 fname := TREAT(M(fn) AS mal_str_type).val_str;
478
479 CASE
480 WHEN fname = '=' THEN RETURN equal_Q(M, H, a);
481
482 WHEN fname = 'nil?' THEN RETURN types.tf(a(1) = 1);
483 WHEN fname = 'false?' THEN RETURN types.tf(a(1) = 2);
484 WHEN fname = 'true?' THEN RETURN types.tf(a(1) = 3);
485 WHEN fname = 'string?' THEN RETURN types.tf(types.string_Q(M, a(1)));
486 WHEN fname = 'symbol' THEN RETURN symbol(M, a(1));
487 WHEN fname = 'symbol?' THEN RETURN types.tf(M(a(1)).type_id = 7);
488 WHEN fname = 'keyword' THEN RETURN keyword(M, a(1));
489 WHEN fname = 'keyword?' THEN RETURN types.tf(types.keyword_Q(M, a(1)));
490
491 WHEN fname = 'pr-str' THEN RETURN pr_str(M, H, a);
492 WHEN fname = 'str' THEN RETURN str(M, H, a);
493 WHEN fname = 'prn' THEN RETURN prn(M, H, a);
494 WHEN fname = 'println' THEN RETURN println(M, H, a);
495 WHEN fname = 'read-string' THEN RETURN read_string(M, H, a);
496 WHEN fname = 'readline' THEN RETURN readline(M, a(1));
497 WHEN fname = 'slurp' THEN RETURN slurp(M, a);
498
499 WHEN fname = '<' THEN RETURN lt(M, a);
500 WHEN fname = '<=' THEN RETURN lte(M, a);
501 WHEN fname = '>' THEN RETURN gt(M, a);
502 WHEN fname = '>=' THEN RETURN gte(M, a);
503 WHEN fname = '+' THEN RETURN add(M, a);
504 WHEN fname = '-' THEN RETURN subtract(M, a);
505 WHEN fname = '*' THEN RETURN multiply(M, a);
506 WHEN fname = '/' THEN RETURN divide(M, a);
507 WHEN fname = 'time-ms' THEN RETURN time_ms(M);
508
509 WHEN fname = 'list' THEN RETURN types.seq(M, 8, a);
510 WHEN fname = 'list?' THEN RETURN types.tf(M(a(1)).type_id = 8);
511 WHEN fname = 'vector' THEN RETURN types.seq(M, 9, a);
512 WHEN fname = 'vector?' THEN RETURN types.tf(M(a(1)).type_id = 9);
513 WHEN fname = 'hash-map' THEN RETURN types.hash_map(M, H, a);
514 WHEN fname = 'assoc' THEN RETURN assoc(M, H, a(1), types.islice(a, 1));
515 WHEN fname = 'dissoc' THEN RETURN dissoc(M, H, a(1), types.islice(a, 1));
516 WHEN fname = 'map?' THEN RETURN types.tf(M(a(1)).type_id = 10);
517 WHEN fname = 'get' THEN RETURN get(M, H, a(1), a(2));
518 WHEN fname = 'contains?' THEN RETURN contains_Q(M, H, a(1), a(2));
519 WHEN fname = 'keys' THEN RETURN keys(M, H, a(1));
520 WHEN fname = 'vals' THEN RETURN vals(M, H, a(1));
521
522 WHEN fname = 'sequential?' THEN RETURN types.tf(M(a(1)).type_id IN (8,9));
523 WHEN fname = 'cons' THEN RETURN cons(M, a);
524 WHEN fname = 'concat' THEN RETURN concat(M, a);
525 WHEN fname = 'nth' THEN RETURN nth(M, a(1), a(2));
526 WHEN fname = 'first' THEN RETURN first(M, a(1));
527 WHEN fname = 'rest' THEN RETURN rest(M, a(1));
528 WHEN fname = 'empty?' THEN RETURN types.tf(0 = types.count(M, a(1)));
529 WHEN fname = 'count' THEN RETURN do_count(M, a(1));
530
531 WHEN fname = 'conj' THEN RETURN conj(M, a(1), types.islice(a, 1));
532 WHEN fname = 'seq' THEN RETURN seq(M, a(1));
533
534 WHEN fname = 'meta' THEN RETURN meta(M, a(1));
535 WHEN fname = 'with-meta' THEN RETURN types.clone(M, H, a(1), a(2));
536 WHEN fname = 'atom' THEN RETURN types.atom_new(M, a(1));
537 WHEN fname = 'atom?' THEN RETURN types.tf(M(a(1)).type_id = 13);
538 WHEN fname = 'deref' THEN RETURN TREAT(M(a(1)) AS mal_atom_type).val;
539 WHEN fname = 'reset!' THEN RETURN reset_BANG(M, a(1), a(2));
540
541 ELSE raise_application_error(-20004, 'Invalid function call', TRUE);
542 END CASE;
543 END;
544
545 FUNCTION get_core_ns RETURN core_ns_type IS
546 BEGIN
547 RETURN core_ns_type(
548 '=',
549 'throw',
550
551 'nil?',
552 'true?',
553 'false?',
554 'string?',
555 'symbol',
556 'symbol?',
557 'keyword',
558 'keyword?',
559
560 'pr-str',
561 'str',
562 'prn',
563 'println',
564 'read-string',
565 'readline',
566 'slurp',
567
568 '<',
569 '<=',
570 '>',
571 '>=',
572 '+',
573 '-',
574 '*',
575 '/',
576 'time-ms',
577
578 'list',
579 'list?',
580 'vector',
581 'vector?',
582 'hash-map',
583 'assoc',
584 'dissoc',
585 'map?',
586 'get',
587 'contains?',
588 'keys',
589 'vals',
590
591 'sequential?',
592 'cons',
593 'concat',
594 'nth',
595 'first',
596 'rest',
597 'empty?',
598 'count',
599 'apply', -- defined in step do_builtin function
600 'map', -- defined in step do_builtin function
601
602 'conj',
603 'seq',
604
605 'meta',
606 'with-meta',
607 'atom',
608 'atom?',
609 'deref',
610 'reset!',
611 'swap!' -- defined in step do_builtin function
612 );
613 END;
614
615 END core;
616 /
617 show errors;
618
619 PROMPT 'core.sql finished';