Commit | Line | Data |
---|---|---|
494792ab JM |
1 | -- --------------------------------------------------------- |
2 | -- step4_if_fn_do.sql | |
3 | ||
5340418b | 4 | \i init.sql |
53105a77 | 5 | \i io.sql |
5340418b JM |
6 | \i types.sql |
7 | \i reader.sql | |
8 | \i printer.sql | |
494792ab | 9 | \i envs.sql |
5340418b JM |
10 | \i core.sql |
11 | ||
12 | -- --------------------------------------------------------- | |
494792ab JM |
13 | |
14 | CREATE SCHEMA mal; | |
5340418b JM |
15 | |
16 | -- read | |
494792ab | 17 | CREATE FUNCTION mal.READ(line varchar) RETURNS integer AS $$ |
5340418b | 18 | BEGIN |
494792ab | 19 | RETURN reader.read_str(line); |
5340418b JM |
20 | END; $$ LANGUAGE plpgsql; |
21 | ||
22 | -- eval | |
494792ab | 23 | CREATE FUNCTION mal.eval_ast(ast integer, env integer) RETURNS integer AS $$ |
5340418b JM |
24 | DECLARE |
25 | type integer; | |
b642c0db JM |
26 | seq integer[]; |
27 | eseq integer[]; | |
28 | hash hstore; | |
29 | ehash hstore; | |
30 | kv RECORD; | |
5340418b JM |
31 | e integer; |
32 | result integer; | |
33 | BEGIN | |
494792ab | 34 | SELECT type_id INTO type FROM types.value WHERE value_id = ast; |
5340418b JM |
35 | CASE |
36 | WHEN type = 7 THEN | |
37 | BEGIN | |
494792ab | 38 | result := envs.get(env, ast); |
5340418b | 39 | END; |
b642c0db | 40 | WHEN type IN (8, 9) THEN |
5340418b | 41 | BEGIN |
494792ab | 42 | SELECT val_seq INTO seq FROM types.value WHERE value_id = ast; |
b642c0db JM |
43 | -- Evaluate each entry creating a new sequence |
44 | FOR i IN 1 .. COALESCE(array_length(seq, 1), 0) LOOP | |
494792ab | 45 | eseq[i] := mal.EVAL(seq[i], env); |
b642c0db | 46 | END LOOP; |
494792ab | 47 | INSERT INTO types.value (type_id, val_seq) VALUES (type, eseq) |
97c0256d | 48 | RETURNING value_id INTO result; |
b642c0db JM |
49 | END; |
50 | WHEN type = 10 THEN | |
51 | BEGIN | |
494792ab | 52 | SELECT val_hash INTO hash FROM types.value WHERE value_id = ast; |
b642c0db JM |
53 | -- Evaluate each value for every key/value |
54 | FOR kv IN SELECT * FROM each(hash) LOOP | |
494792ab | 55 | e := mal.EVAL(CAST(kv.value AS integer), env); |
b642c0db JM |
56 | IF ehash IS NULL THEN |
57 | ehash := hstore(kv.key, CAST(e AS varchar)); | |
58 | ELSE | |
59 | ehash := ehash || hstore(kv.key, CAST(e AS varchar)); | |
60 | END IF; | |
5340418b | 61 | END LOOP; |
494792ab | 62 | INSERT INTO types.value (type_id, val_hash) VALUES (type, ehash) |
b642c0db | 63 | RETURNING value_id INTO result; |
5340418b JM |
64 | END; |
65 | ELSE | |
66 | result := ast; | |
67 | END CASE; | |
68 | ||
69 | RETURN result; | |
70 | END; $$ LANGUAGE plpgsql; | |
71 | ||
494792ab | 72 | CREATE FUNCTION mal.EVAL(ast integer, env integer) RETURNS integer AS $$ |
5340418b JM |
73 | DECLARE |
74 | type integer; | |
75 | a0 integer; | |
76 | a0sym varchar; | |
77 | a1 integer; | |
78 | let_env integer; | |
b642c0db | 79 | idx integer; |
5340418b | 80 | binds integer[]; |
5340418b JM |
81 | el integer; |
82 | fn integer; | |
83 | fname varchar; | |
84 | args integer[]; | |
85 | cond integer; | |
86 | fast integer; | |
87 | fparams integer; | |
88 | fenv integer; | |
89 | result integer; | |
90 | BEGIN | |
494792ab JM |
91 | -- PERFORM writeline(format('EVAL: %s [%s]', pr_str(ast), ast)); |
92 | SELECT type_id INTO type FROM types.value WHERE value_id = ast; | |
5340418b | 93 | IF type <> 8 THEN |
494792ab JM |
94 | RETURN mal.eval_ast(ast, env); |
95 | END IF; | |
96 | IF types._count(ast) = 0 THEN | |
97 | RETURN ast; | |
5340418b JM |
98 | END IF; |
99 | ||
494792ab JM |
100 | a0 := types._first(ast); |
101 | IF types._symbol_Q(a0) THEN | |
102 | a0sym := (SELECT val_string FROM types.value WHERE value_id = a0); | |
5340418b JM |
103 | ELSE |
104 | a0sym := '__<*fn*>__'; | |
105 | END IF; | |
106 | ||
5340418b JM |
107 | CASE |
108 | WHEN a0sym = 'def!' THEN | |
109 | BEGIN | |
494792ab JM |
110 | RETURN envs.set(env, types._nth(ast, 1), |
111 | mal.EVAL(types._nth(ast, 2), env)); | |
5340418b JM |
112 | END; |
113 | WHEN a0sym = 'let*' THEN | |
114 | BEGIN | |
494792ab JM |
115 | let_env := envs.new(env); |
116 | a1 := types._nth(ast, 1); | |
117 | binds := (SELECT val_seq FROM types.value WHERE value_id = a1); | |
b642c0db JM |
118 | idx := 1; |
119 | WHILE idx < array_length(binds, 1) LOOP | |
494792ab JM |
120 | PERFORM envs.set(let_env, binds[idx], |
121 | mal.EVAL(binds[idx+1], let_env)); | |
b642c0db | 122 | idx := idx + 2; |
5340418b | 123 | END LOOP; |
494792ab | 124 | RETURN mal.EVAL(types._nth(ast, 2), let_env); |
5340418b JM |
125 | END; |
126 | WHEN a0sym = 'do' THEN | |
127 | BEGIN | |
494792ab JM |
128 | el := mal.eval_ast(types._rest(ast), env); |
129 | RETURN types._nth(el, types._count(el)-1); | |
5340418b JM |
130 | END; |
131 | WHEN a0sym = 'if' THEN | |
132 | BEGIN | |
494792ab JM |
133 | cond := mal.EVAL(types._nth(ast, 1), env); |
134 | SELECT type_id INTO type FROM types.value WHERE value_id = cond; | |
5340418b | 135 | IF type = 0 OR type = 1 THEN -- nil or false |
494792ab JM |
136 | IF types._count(ast) > 3 THEN |
137 | RETURN mal.EVAL(types._nth(ast, 3), env); | |
5340418b JM |
138 | ELSE |
139 | RETURN 0; -- nil | |
140 | END IF; | |
141 | ELSE | |
494792ab | 142 | RETURN mal.EVAL(types._nth(ast, 2), env); |
5340418b JM |
143 | END IF; |
144 | END; | |
145 | WHEN a0sym = 'fn*' THEN | |
146 | BEGIN | |
494792ab | 147 | RETURN types._malfunc(types._nth(ast, 2), types._nth(ast, 1), env); |
5340418b JM |
148 | END; |
149 | ELSE | |
150 | BEGIN | |
494792ab | 151 | el := mal.eval_ast(ast, env); |
4facce82 | 152 | SELECT type_id, val_string, ast_id, params_id, env_id |
b642c0db | 153 | INTO type, fname, fast, fparams, fenv |
494792ab JM |
154 | FROM types.value WHERE value_id = types._first(el); |
155 | args := types._restArray(el); | |
5340418b JM |
156 | IF type = 11 THEN |
157 | EXECUTE format('SELECT %s($1);', fname) | |
158 | INTO result USING args; | |
159 | RETURN result; | |
160 | ELSIF type = 12 THEN | |
494792ab | 161 | RETURN mal.EVAL(fast, envs.new(fenv, fparams, args)); |
5340418b JM |
162 | ELSE |
163 | RAISE EXCEPTION 'Invalid function call'; | |
164 | END IF; | |
165 | END; | |
166 | END CASE; | |
167 | END; $$ LANGUAGE plpgsql; | |
168 | ||
169 | ||
494792ab | 170 | CREATE FUNCTION mal.PRINT(exp integer) RETURNS varchar AS $$ |
5340418b | 171 | BEGIN |
494792ab | 172 | RETURN printer.pr_str(exp); |
5340418b JM |
173 | END; $$ LANGUAGE plpgsql; |
174 | ||
175 | ||
176 | -- repl | |
177 | ||
178 | -- repl_env is environment 0 | |
179 | ||
494792ab | 180 | CREATE FUNCTION mal.REP(line varchar) RETURNS varchar AS $$ |
5340418b | 181 | BEGIN |
494792ab | 182 | RETURN mal.PRINT(mal.EVAL(mal.READ(line), 0)); |
5340418b JM |
183 | END; $$ LANGUAGE plpgsql; |
184 | ||
185 | -- core.sql: defined using SQL (in core.sql) | |
186 | -- repl_env is created and populated with core functions in by core.sql | |
187 | ||
188 | -- core.mal: defined using the language itself | |
494792ab | 189 | SELECT mal.REP('(def! not (fn* (a) (if a false true)))') \g '/dev/null' |
5340418b | 190 | |
494792ab | 191 | CREATE FUNCTION mal.MAIN(pwd varchar) RETURNS integer AS $$ |
53105a77 | 192 | DECLARE |
494792ab JM |
193 | line varchar; |
194 | output varchar; | |
53105a77 JM |
195 | BEGIN |
196 | WHILE true | |
197 | LOOP | |
198 | BEGIN | |
494792ab JM |
199 | line := io.readline('user> ', 0); |
200 | IF line IS NULL THEN | |
201 | PERFORM io.close(1); | |
202 | RETURN 0; | |
203 | END IF; | |
204 | IF line NOT IN ('', E'\n') THEN | |
205 | output := mal.REP(line); | |
206 | PERFORM io.writeline(output); | |
53105a77 JM |
207 | END IF; |
208 | ||
209 | EXCEPTION WHEN OTHERS THEN | |
494792ab | 210 | PERFORM io.writeline('Error: ' || SQLERRM); |
53105a77 JM |
211 | END; |
212 | END LOOP; | |
213 | END; $$ LANGUAGE plpgsql; |