Merge pull request #406 from chr15m/lib-alias-hacks
[jackhill/mal.git] / plsql / step2_eval.sql
CommitLineData
7836cfa3
JM
1@io.sql
2@types.sql
3@reader.sql
4@printer.sql
5
0fc03918 6CREATE OR REPLACE PACKAGE mal IS
7836cfa3 7
10cc781f 8FUNCTION MAIN(args varchar DEFAULT '()') RETURN integer;
7836cfa3 9
0fc03918 10END mal;
7836cfa3
JM
11/
12
0fc03918 13CREATE OR REPLACE PACKAGE BODY mal IS
7836cfa3 14
10cc781f 15FUNCTION MAIN(args varchar DEFAULT '()') RETURN integer IS
2866f9a8 16 M types.mal_table; -- general mal value memory pool
6a085103 17 H types.map_entry_table; -- hashmap memory pool
2866f9a8
JM
18 TYPE env_T IS TABLE OF integer INDEX BY varchar2(100);
19 repl_env env_T;
02936b42 20 line CLOB;
7836cfa3
JM
21
22 -- read
0fc03918 23 FUNCTION READ(line varchar) RETURN integer IS
7836cfa3 24 BEGIN
6a085103 25 RETURN reader.read_str(M, H, line);
7836cfa3
JM
26 END;
27
28 -- eval
29
30 -- forward declarations
2866f9a8
JM
31 FUNCTION EVAL(ast integer, env env_T) RETURN integer;
32 FUNCTION do_core_func(fn integer, args mal_vals)
0fc03918 33 RETURN integer;
7836cfa3 34
2866f9a8 35 FUNCTION eval_ast(ast integer, env env_T) RETURN integer IS
6a085103 36 i integer;
2866f9a8
JM
37 old_seq mal_vals;
38 new_seq mal_vals;
6a085103
JM
39 new_hm integer;
40 old_midx integer;
41 new_midx integer;
42 k varchar2(256);
7836cfa3 43 BEGIN
0fc03918 44 IF M(ast).type_id = 7 THEN
2866f9a8 45 RETURN env(TREAT(M(ast) AS mal_str_T).val_str);
0fc03918 46 ELSIF M(ast).type_id IN (8,9) THEN
2866f9a8
JM
47 old_seq := TREAT(M(ast) AS mal_seq_T).val_seq;
48 new_seq := mal_vals();
7836cfa3
JM
49 new_seq.EXTEND(old_seq.COUNT);
50 FOR i IN 1..old_seq.COUNT LOOP
51 new_seq(i) := EVAL(old_seq(i), env);
52 END LOOP;
0fc03918 53 RETURN types.seq(M, M(ast).type_id, new_seq);
6a085103 54 ELSIF M(ast).type_id IN (10) THEN
2866f9a8
JM
55 new_hm := types.hash_map(M, H, mal_vals());
56 old_midx := TREAT(M(ast) AS mal_map_T).map_idx;
57 new_midx := TREAT(M(new_hm) AS mal_map_T).map_idx;
6a085103
JM
58
59 k := H(old_midx).FIRST();
60 WHILE k IS NOT NULL LOOP
61 H(new_midx)(k) := EVAL(H(old_midx)(k), env);
62 k := H(old_midx).NEXT(k);
63 END LOOP;
64 RETURN new_hm;
7836cfa3
JM
65 ELSE
66 RETURN ast;
67 END IF;
68 END;
69
2866f9a8 70 FUNCTION EVAL(ast integer, env env_T) RETURN integer IS
0fc03918
JM
71 el integer;
72 f integer;
2866f9a8 73 args mal_vals;
7836cfa3 74 BEGIN
0fc03918 75 IF M(ast).type_id <> 8 THEN
7836cfa3
JM
76 RETURN eval_ast(ast, env);
77 END IF;
6a085103
JM
78 IF types.count(M, ast) = 0 THEN
79 RETURN ast; -- empty list just returned
80 END IF;
7836cfa3
JM
81
82 -- apply
83 el := eval_ast(ast, env);
0fc03918 84 f := types.first(M, el);
2866f9a8 85 args := TREAT(M(types.slice(M, el, 1)) AS mal_seq_T).val_seq;
150011e4 86 RETURN do_core_func(f, args);
7836cfa3
JM
87 END;
88
89 -- print
0fc03918 90 FUNCTION PRINT(exp integer) RETURN varchar IS
7836cfa3 91 BEGIN
6a085103 92 RETURN printer.pr_str(M, H, exp);
7836cfa3
JM
93 END;
94
7836cfa3 95 -- repl
2866f9a8 96 FUNCTION mal_add(args mal_vals) RETURN integer IS
7836cfa3 97 BEGIN
2866f9a8
JM
98 RETURN types.int(M, TREAT(M(args(1)) AS mal_int_T).val_int +
99 TREAT(M(args(2)) AS mal_int_T).val_int);
7836cfa3
JM
100 END;
101
2866f9a8 102 FUNCTION mal_subtract(args mal_vals) RETURN integer IS
7836cfa3 103 BEGIN
2866f9a8
JM
104 RETURN types.int(M, TREAT(M(args(1)) AS mal_int_T).val_int -
105 TREAT(M(args(2)) AS mal_int_T).val_int);
7836cfa3
JM
106 END;
107
2866f9a8 108 FUNCTION mal_multiply(args mal_vals) RETURN integer IS
7836cfa3 109 BEGIN
2866f9a8
JM
110 RETURN types.int(M, TREAT(M(args(1)) AS mal_int_T).val_int *
111 TREAT(M(args(2)) AS mal_int_T).val_int);
7836cfa3
JM
112 END;
113
2866f9a8 114 FUNCTION mal_divide(args mal_vals) RETURN integer IS
7836cfa3 115 BEGIN
2866f9a8
JM
116 RETURN types.int(M, TREAT(M(args(1)) AS mal_int_T).val_int /
117 TREAT(M(args(2)) AS mal_int_T).val_int);
7836cfa3
JM
118 END;
119
2866f9a8 120 FUNCTION do_core_func(fn integer, args mal_vals)
0fc03918 121 RETURN integer IS
02936b42 122 fname varchar(256);
7836cfa3 123 BEGIN
0fc03918 124 IF M(fn).type_id <> 11 THEN
7836cfa3
JM
125 raise_application_error(-20004,
126 'Invalid function call', TRUE);
127 END IF;
128
2866f9a8 129 fname := TREAT(M(fn) AS mal_str_T).val_str;
9fc524f1 130 CASE
7836cfa3
JM
131 WHEN fname = '+' THEN RETURN mal_add(args);
132 WHEN fname = '-' THEN RETURN mal_subtract(args);
133 WHEN fname = '*' THEN RETURN mal_multiply(args);
134 WHEN fname = '/' THEN RETURN mal_divide(args);
135 ELSE raise_application_error(-20004,
136 'Invalid function call', TRUE);
137 END CASE;
138 END;
139
140 FUNCTION REP(line varchar) RETURN varchar IS
141 BEGIN
142 RETURN PRINT(EVAL(READ(line), repl_env));
143 END;
144
145BEGIN
6a085103 146 -- initialize memory pools
0fc03918 147 M := types.mem_new();
6a085103 148 H := types.map_entry_table();
0fc03918
JM
149
150 repl_env('+') := types.func(M, '+');
151 repl_env('-') := types.func(M, '-');
152 repl_env('*') := types.func(M, '*');
153 repl_env('/') := types.func(M, '/');
7836cfa3 154
9fc524f1 155 WHILE true LOOP
7836cfa3 156 BEGIN
02936b42
JM
157 line := io.readline('user> ', 0);
158 IF line = EMPTY_CLOB() THEN CONTINUE; END IF;
7836cfa3 159 IF line IS NOT NULL THEN
02936b42 160 io.writeline(REP(line));
7836cfa3
JM
161 END IF;
162
163 EXCEPTION WHEN OTHERS THEN
8119e744
JM
164 IF SQLCODE = -20001 THEN -- io read stream closed
165 io.close(1); -- close output stream
7836cfa3
JM
166 RETURN 0;
167 END IF;
02936b42
JM
168 io.writeline('Error: ' || SQLERRM);
169 io.writeline(dbms_utility.format_error_backtrace);
7836cfa3
JM
170 END;
171 END LOOP;
172END;
173
0fc03918 174END mal;
7836cfa3
JM
175/
176show errors;
177
178quit;