Commit | Line | Data |
---|---|---|
06951f55 JM |
1 | @io.sql |
2 | @types.sql | |
3 | @reader.sql | |
4 | @printer.sql | |
5 | @env.sql | |
6 | @core.sql | |
7 | ||
8 | CREATE OR REPLACE PACKAGE mal_pkg IS | |
9 | ||
10 | FUNCTION MAIN(pwd varchar) RETURN integer; | |
11 | ||
12 | END mal_pkg; | |
13 | / | |
14 | ||
15 | CREATE OR REPLACE PACKAGE BODY mal_pkg IS | |
16 | ||
17 | FUNCTION MAIN(pwd varchar) RETURN integer IS | |
18 | env_mem env_mem_type; | |
19 | atom_mem atom_mem_type; | |
20 | repl_env integer; | |
21 | line varchar2(4000); | |
22 | x mal_type; | |
23 | core_ns core_ns_type; | |
24 | cidx integer; | |
25 | ||
26 | -- read | |
27 | FUNCTION READ(line varchar) RETURN mal_type IS | |
28 | BEGIN | |
29 | RETURN reader_pkg.read_str(line); | |
30 | END; | |
31 | ||
32 | -- eval | |
33 | ||
34 | -- forward declarations | |
35 | FUNCTION EVAL(ast mal_type, env integer) RETURN mal_type; | |
36 | FUNCTION do_builtin(fn mal_type, args mal_seq_type) RETURN mal_type; | |
37 | ||
38 | FUNCTION eval_ast(ast mal_type, env integer) RETURN mal_type IS | |
39 | i integer; | |
40 | old_seq mal_seq_items_type; | |
41 | new_seq mal_seq_items_type; | |
42 | f mal_type; | |
43 | BEGIN | |
44 | IF ast.type_id = 7 THEN | |
45 | RETURN env_pkg.env_get(env_mem, env, ast); | |
46 | ELSIF ast.type_id IN (8,9) THEN | |
47 | old_seq := TREAT(ast AS mal_seq_type).val_seq; | |
48 | new_seq := mal_seq_items_type(); | |
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; | |
53 | RETURN mal_seq_type(ast.type_id, new_seq); | |
54 | ELSE | |
55 | RETURN ast; | |
56 | END IF; | |
57 | END; | |
58 | ||
59 | FUNCTION EVAL(ast mal_type, env integer) RETURN mal_type IS | |
60 | el mal_type; | |
61 | a0 mal_type; | |
62 | a0sym varchar2(4000); | |
63 | seq mal_seq_items_type; | |
64 | let_env integer; | |
65 | fn_env integer; | |
66 | i integer; | |
67 | cond mal_type; | |
68 | f mal_type; | |
69 | malfn malfunc_type; | |
70 | args mal_seq_type; | |
71 | BEGIN | |
72 | IF ast.type_id <> 8 THEN | |
73 | RETURN eval_ast(ast, env); | |
74 | END IF; | |
75 | ||
76 | -- apply | |
77 | a0 := types_pkg.first(ast); | |
78 | if a0.type_id = 7 THEN -- symbol | |
79 | a0sym := TREAT(a0 AS mal_str_type).val_str; | |
80 | ELSE | |
81 | a0sym := '__<*fn*>__'; | |
82 | END IF; | |
83 | ||
84 | CASE | |
85 | WHEN a0sym = 'def!' THEN | |
86 | RETURN env_pkg.env_set(env_mem, env, | |
87 | types_pkg.nth(ast, 1), EVAL(types_pkg.nth(ast, 2), env)); | |
88 | WHEN a0sym = 'let*' THEN | |
89 | let_env := env_pkg.env_new(env_mem, env); | |
90 | seq := TREAT(types_pkg.nth(ast, 1) AS mal_seq_type).val_seq; | |
91 | i := 1; | |
92 | WHILE i <= seq.COUNT LOOP | |
93 | x := env_pkg.env_set(env_mem, let_env, | |
94 | seq(i), EVAL(seq(i+1), let_env)); | |
95 | i := i + 2; | |
96 | END LOOP; | |
97 | RETURN EVAL(types_pkg.nth(ast, 2), let_env); | |
98 | WHEN a0sym = 'do' THEN | |
99 | el := eval_ast(types_pkg.slice(ast, 1), env); | |
100 | RETURN types_pkg.nth(el, types_pkg.count(el)-1); | |
101 | WHEN a0sym = 'if' THEN | |
102 | cond := EVAL(types_pkg.nth(ast, 1), env); | |
103 | IF cond.type_id = 0 OR cond.type_id = 1 THEN | |
104 | IF types_pkg.count(ast) > 3 THEN | |
105 | RETURN EVAL(types_pkg.nth(ast, 3), env); | |
106 | ELSE | |
107 | RETURN mal_type(0); | |
108 | END IF; | |
109 | ELSE | |
110 | RETURN EVAL(types_pkg.nth(ast, 2), env); | |
111 | END IF; | |
112 | WHEN a0sym = 'fn*' THEN | |
113 | RETURN malfunc_type(12, types_pkg.nth(ast, 2), | |
114 | types_pkg.nth(ast, 1), | |
115 | env); | |
116 | ELSE | |
117 | el := eval_ast(ast, env); | |
118 | f := types_pkg.first(el); | |
119 | args := TREAT(types_pkg.slice(el, 1) AS mal_seq_type); | |
120 | IF f.type_id = 12 THEN | |
121 | malfn := TREAT(f AS malfunc_type); | |
122 | fn_env := env_pkg.env_new(env_mem, malfn.env, | |
123 | malfn.params, args); | |
124 | RETURN EVAL(malfn.ast, fn_env); | |
125 | ELSE | |
126 | RETURN do_builtin(f, args); | |
127 | END IF; | |
128 | END CASE; | |
129 | ||
130 | END; | |
131 | ||
132 | -- hack to get around lack of function references | |
133 | -- functions that require special access to repl_env of atom_mem | |
134 | -- are implemented directly here, otherwise, core_pkg.do_core_fn | |
135 | -- is called. | |
136 | FUNCTION do_builtin(fn mal_type, args mal_seq_type) RETURN mal_type IS | |
137 | fname varchar2(100); | |
138 | sargs mal_seq_items_type := args.val_seq; | |
139 | aidx integer; | |
140 | f mal_type; | |
141 | malfn malfunc_type; | |
142 | fargs mal_seq_items_type; | |
143 | fn_env integer; | |
144 | BEGIN | |
145 | fname := TREAT(fn AS mal_str_type).val_str; | |
146 | CASE | |
147 | WHEN fname = 'do_eval' THEN | |
148 | RETURN EVAL(sargs(1), repl_env); | |
149 | WHEN fname = 'atom' THEN | |
150 | RETURN types_pkg.atom_new(atom_mem, sargs(1)); | |
151 | WHEN fname = 'atom?' THEN | |
152 | RETURN types_pkg.wraptf(sargs(1).type_id = 13); | |
153 | WHEN fname = 'deref' THEN | |
154 | aidx := TREAT(sargs(1) AS atom_type).val; | |
155 | RETURN atom_mem(aidx); | |
156 | WHEN fname = 'reset!' THEN | |
157 | aidx := TREAT(sargs(1) AS atom_type).val; | |
158 | atom_mem(aidx) := sargs(2); | |
159 | RETURN sargs(2); | |
160 | WHEN fname = 'swap!' THEN | |
161 | aidx := TREAT(sargs(1) AS atom_type).val; | |
162 | f := sargs(2); | |
163 | -- slice one extra at the beginning that will be changed | |
164 | -- to the value of the atom | |
165 | fargs := TREAT(types_pkg.slice(sargs, 1) AS mal_seq_type).val_seq; | |
166 | fargs(1) := atom_mem(aidx); | |
167 | IF f.type_id = 12 THEN | |
168 | malfn := TREAT(f AS malfunc_type); | |
169 | fn_env := env_pkg.env_new(env_mem, malfn.env, | |
170 | malfn.params, | |
171 | mal_seq_type(8, fargs)); | |
172 | atom_mem(aidx) := EVAL(malfn.ast, fn_env); | |
173 | RETURN atom_mem(aidx); | |
174 | ELSE | |
175 | atom_mem(aidx) := do_builtin(f, mal_seq_type(8, fargs)); | |
176 | RETURN atom_mem(aidx); | |
177 | END IF; | |
178 | ELSE | |
179 | RETURN core_pkg.do_core_func(fn, sargs); | |
180 | END CASE; | |
181 | END; | |
182 | ||
183 | ||
184 | ||
185 | FUNCTION PRINT(exp mal_type) RETURN varchar IS | |
186 | BEGIN | |
187 | if exp.type_id = 13 THEN | |
188 | -- hack to get around fact that atom_mem is not visible | |
189 | -- from printer_pkg | |
190 | RETURN '(atom ' || printer_pkg.pr_str( | |
191 | atom_mem(TREAT(exp AS atom_type).val), TRUE) || ')'; | |
192 | ELSE | |
193 | RETURN printer_pkg.pr_str(exp); | |
194 | END IF; | |
195 | END; | |
196 | ||
197 | -- repl | |
198 | FUNCTION REP(line varchar) RETURN varchar IS | |
199 | BEGIN | |
200 | RETURN PRINT(EVAL(READ(line), repl_env)); | |
201 | END; | |
202 | ||
203 | BEGIN | |
204 | env_mem := env_mem_type(); | |
205 | atom_mem := atom_mem_type(); | |
206 | repl_env := env_pkg.env_new(env_mem, NULL); | |
207 | ||
208 | -- core.EXT: defined using PL/SQL | |
209 | core_ns := core_pkg.get_core_ns(); | |
210 | FOR cidx IN 1..core_ns.COUNT LOOP | |
211 | x := env_pkg.env_set(env_mem, repl_env, | |
212 | types_pkg.symbol(core_ns(cidx)), | |
213 | mal_str_type(11, core_ns(cidx))); | |
214 | END LOOP; | |
215 | x := env_pkg.env_set(env_mem, repl_env, | |
216 | types_pkg.symbol('eval'), | |
217 | mal_str_type(11, 'do_eval')); | |
218 | x := env_pkg.env_set(env_mem, repl_env, | |
219 | types_pkg.symbol('*ARGV*'), | |
220 | mal_seq_type(8, mal_seq_items_type())); | |
221 | ||
222 | -- core.mal: defined using the language itself | |
223 | line := REP('(def! not (fn* (a) (if a false true)))'); | |
224 | line := REP('(def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) ")")))))'); | |
225 | ||
226 | WHILE true LOOP | |
227 | BEGIN | |
228 | line := stream_readline('user> ', 0); | |
229 | -- stream_writeline('line: [' || line || ']', 1); | |
230 | IF line IS NULL THEN RETURN 0; END IF; | |
231 | IF line IS NOT NULL THEN | |
232 | stream_writeline(REP(line)); | |
233 | END IF; | |
234 | ||
235 | EXCEPTION WHEN OTHERS THEN | |
236 | IF SQLCODE = -20000 THEN | |
237 | RETURN 0; | |
238 | END IF; | |
239 | stream_writeline('Error: ' || SQLERRM); | |
240 | stream_writeline(dbms_utility.format_error_backtrace); | |
241 | END; | |
242 | END LOOP; | |
243 | END; | |
244 | ||
245 | END mal_pkg; | |
246 | / | |
247 | show errors; | |
248 | ||
249 | quit; |