plsql: step2,3 basics.
[jackhill/mal.git] / plsql / step2_eval.sql
CommitLineData
7836cfa3
JM
1@io.sql
2@types.sql
3@reader.sql
4@printer.sql
5
6-- ---------------------------------------------------------
7-- step1_read_print.sql
8
9CREATE OR REPLACE PACKAGE mal_pkg IS
10
11FUNCTION MAIN(pwd varchar) RETURN integer;
12
13END mal_pkg;
14/
15
16CREATE OR REPLACE PACKAGE BODY mal_pkg IS
17
18FUNCTION MAIN(pwd varchar) RETURN integer IS
19 TYPE env_type IS TABLE OF mal_type INDEX BY varchar2(100);
20 repl_env env_type;
21
22 line varchar2(4000);
23
24 -- read
25 FUNCTION READ(line varchar) RETURN mal_type IS
26 BEGIN
27 RETURN reader_pkg.read_str(line);
28 END;
29
30 -- eval
31
32 -- forward declarations
33 FUNCTION EVAL(ast mal_type, env env_type) RETURN mal_type;
34 FUNCTION do_core_func(fn mal_type, args mal_seq_items_type) RETURN mal_type;
35
36 FUNCTION eval_ast(ast mal_type, env env_type) RETURN mal_type IS
37 i integer;
38 old_seq mal_seq_items_type;
39 new_seq mal_seq_items_type;
40 f mal_type;
41 BEGIN
42 IF ast.type_id = 7 THEN
43 RETURN env(TREAT(ast AS mal_str_type).val_str);
44 ELSIF ast.type_id IN (8,9) THEN
45 old_seq := TREAT(ast AS mal_seq_type).val_seq;
46 new_seq := mal_seq_items_type();
47 new_seq.EXTEND(old_seq.COUNT);
48 FOR i IN 1..old_seq.COUNT LOOP
49 new_seq(i) := EVAL(old_seq(i), env);
50 END LOOP;
51 RETURN mal_seq_type(ast.type_id, new_seq);
52 ELSE
53 RETURN ast;
54 END IF;
55 END;
56
57 FUNCTION EVAL(ast mal_type, env env_type) RETURN mal_type IS
58 el mal_type;
59 f mal_type;
60 args mal_seq_type;
61 BEGIN
62 IF ast.type_id <> 8 THEN
63 RETURN eval_ast(ast, env);
64 END IF;
65
66 -- apply
67 el := eval_ast(ast, env);
68 f := types_pkg.first(el);
69 args := TREAT(types_pkg.slice(el, 1) AS mal_seq_type);
70 RETURN do_core_func(f, args.val_seq);
71 END;
72
73 -- print
74 FUNCTION PRINT(exp mal_type) RETURN varchar IS
75 BEGIN
76 RETURN printer_pkg.pr_str(exp);
77 END;
78
79 -- stub to support wrap.sh
80 PROCEDURE env_vset(env integer, name varchar, val varchar) IS
81 BEGIN
82 RETURN;
83 END;
84
85 -- repl
86 FUNCTION mal_add(args mal_seq_items_type) RETURN mal_type IS
87 BEGIN
88 RETURN mal_int_type(3, TREAT(args(1) AS mal_int_type).val_int +
89 TREAT(args(2) AS mal_int_type).val_int);
90 END;
91
92 FUNCTION mal_subtract(args mal_seq_items_type) RETURN mal_type IS
93 BEGIN
94 RETURN mal_int_type(3, TREAT(args(1) AS mal_int_type).val_int -
95 TREAT(args(2) AS mal_int_type).val_int);
96 END;
97
98 FUNCTION mal_multiply(args mal_seq_items_type) RETURN mal_type IS
99 BEGIN
100 RETURN mal_int_type(3, TREAT(args(1) AS mal_int_type).val_int *
101 TREAT(args(2) AS mal_int_type).val_int);
102 END;
103
104 FUNCTION mal_divide(args mal_seq_items_type) RETURN mal_type IS
105 BEGIN
106 RETURN mal_int_type(3, TREAT(args(1) AS mal_int_type).val_int /
107 TREAT(args(2) AS mal_int_type).val_int);
108 END;
109
110 FUNCTION do_core_func(fn mal_type, args mal_seq_items_type) RETURN mal_type IS
111 fname varchar(100);
112 BEGIN
113 IF fn.type_id <> 11 THEN
114 raise_application_error(-20004,
115 'Invalid function call', TRUE);
116 END IF;
117
118 fname := TREAT(fn AS mal_str_type).val_str;
119 CASE
120 WHEN fname = '+' THEN RETURN mal_add(args);
121 WHEN fname = '-' THEN RETURN mal_subtract(args);
122 WHEN fname = '*' THEN RETURN mal_multiply(args);
123 WHEN fname = '/' THEN RETURN mal_divide(args);
124 ELSE raise_application_error(-20004,
125 'Invalid function call', TRUE);
126 END CASE;
127 END;
128
129 FUNCTION REP(line varchar) RETURN varchar IS
130 BEGIN
131 RETURN PRINT(EVAL(READ(line), repl_env));
132 END;
133
134BEGIN
135 repl_env('+') := mal_str_type(11, '+');
136 repl_env('-') := mal_str_type(11, '-');
137 repl_env('*') := mal_str_type(11, '*');
138 repl_env('/') := mal_str_type(11, '/');
139
140 WHILE true
141 LOOP
142 BEGIN
143 line := stream_readline('user> ', 0);
144 -- stream_writeline('line: [' || line || ']', 1);
145 IF line IS NULL THEN RETURN 0; END IF;
146 IF line IS NOT NULL THEN
147 stream_writeline(REP(line));
148 END IF;
149
150 EXCEPTION WHEN OTHERS THEN
151 IF SQLCODE = -20000 THEN
152 RETURN 0;
153 END IF;
154 stream_writeline('Error: ' || SQLERRM);
155 END;
156 END LOOP;
157END;
158
159END mal_pkg;
160/
161show errors;
162
163quit;