Commit | Line | Data |
---|---|---|
7836cfa3 JM |
1 | @io.sql |
2 | @types.sql | |
3 | @reader.sql | |
4 | @printer.sql | |
5 | ||
0fc03918 | 6 | CREATE OR REPLACE PACKAGE mal IS |
7836cfa3 | 7 | |
10cc781f | 8 | FUNCTION MAIN(args varchar DEFAULT '()') RETURN integer; |
7836cfa3 | 9 | |
0fc03918 | 10 | END mal; |
7836cfa3 JM |
11 | / |
12 | ||
0fc03918 | 13 | CREATE OR REPLACE PACKAGE BODY mal IS |
7836cfa3 | 14 | |
10cc781f | 15 | FUNCTION 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 | ||
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 | ||
145 | BEGIN | |
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; | |
172 | END; | |
173 | ||
0fc03918 | 174 | END mal; |
7836cfa3 JM |
175 | / |
176 | show errors; | |
177 | ||
178 | quit; |