10 -- ---------------------------------------------------------
11 -- step1_read_print.sql
14 CREATE OR REPLACE FUNCTION READ(line
varchar) RETURNS integer AS $$
16 RETURN read_str(line
);
17 END; $$
LANGUAGE plpgsql
;
20 CREATE OR REPLACE FUNCTION is_pair(ast
integer) RETURNS boolean AS $$
22 RETURN _sequential_Q(ast
) AND _count(ast
) > 0;
23 END; $$
LANGUAGE plpgsql
;
25 CREATE OR REPLACE FUNCTION quasiquote(ast
integer) RETURNS integer AS $$
30 IF NOT is_pair(ast
) THEN
31 RETURN _list(ARRAY[_symbolv('quote'), ast
]);
34 IF _symbol_Q(a0
) AND a0
= _symbolv('unquote') THEN
38 IF _symbol_Q(a00
) AND a00
= _symbolv('splice-unquote') THEN
39 RETURN _list(ARRAY[_symbolv('concat'),
41 quasiquote(_rest(ast
))]);
44 RETURN _list(ARRAY[_symbolv('cons'),
45 quasiquote(_first(ast
)),
46 quasiquote(_rest(ast
))]);
48 END; $$
LANGUAGE plpgsql
;
50 CREATE OR REPLACE FUNCTION eval_ast(ast
integer, env
integer) RETURNS integer AS $$
57 dst_coll_id
integer = NULL;
61 SELECT type_id
INTO type FROM value WHERE value_id
= ast
;
65 result := env_get(env
, ast
);
67 WHEN type = 8 OR type = 9 THEN
69 src_coll_id
:= (SELECT collection_id
FROM value WHERE value_id
= ast
);
70 FOR vid
, i
IN (SELECT value_id
, idx
FROM collection
71 WHERE collection_id
= src_coll_id
)
74 IF dst_coll_id
IS NULL THEN
75 dst_coll_id
:= COALESCE((SELECT Max(collection_id
)
76 FROM collection
)+1,0);
78 -- Evaluated each entry
79 INSERT INTO collection (collection_id
, idx
, value_id
)
80 VALUES (dst_coll_id
, i
, e
);
82 -- Create value entry pointing to new collection
83 INSERT INTO value (type_id
, collection_id
)
84 VALUES (type, dst_coll_id
)
85 RETURNING value_id
INTO result;
92 END; $$
LANGUAGE plpgsql
;
94 CREATE OR REPLACE FUNCTION EVAL(ast
integer, env
integer) RETURNS integer AS $$
114 --RAISE NOTICE 'EVAL: % [%]', pr_str(ast), ast;
115 SELECT type_id
INTO type FROM value WHERE value_id
= ast
;
117 RETURN eval_ast(ast
, env
);
121 IF _symbol_Q(a0
) THEN
122 a0sym
:= (SELECT string.
value FROM string
123 INNER JOIN value ON value.val_string_id
=string.string_id
124 WHERE value.value_id
= a0
);
126 a0sym
:= '__<*fn*>__';
129 --RAISE NOTICE 'ast: %, a0sym: %', ast, a0sym;
131 WHEN a0sym
= 'def!' THEN
133 RETURN env_set(env
, _nth(ast
, 1), EVAL(_nth(ast
, 2), env
));
135 WHEN a0sym
= 'let*' THEN
137 let_env
:= env_new(env
);
139 binds
:= ARRAY(SELECT collection.value_id
FROM collection
INNER JOIN value
140 ON collection.collection_id
=value.collection_id
141 WHERE value.value_id
= a1
142 AND (collection.idx
% 2) = 0
143 ORDER BY collection.idx
);
144 exprs
:= ARRAY(SELECT collection.value_id
FROM collection
INNER JOIN value
145 ON collection.collection_id
=value.collection_id
146 WHERE value.value_id
= a1
147 AND (collection.idx
% 2) = 1
148 ORDER BY collection.idx
);
149 FOR idx
IN array_lower(binds
, 1) ..
array_upper(binds
, 1)
151 PERFORM
env_set(let_env
, binds
[idx
], EVAL(exprs
[idx
], let_env
));
157 WHEN a0sym
= 'quote' THEN
161 WHEN a0sym
= 'quasiquote' THEN
163 ast
:= quasiquote(_nth(ast
, 1));
166 WHEN a0sym
= 'do' THEN
168 PERFORM
eval_ast(_slice(ast
, 1, _count(ast
)-1), env
);
169 ast
:= _nth(ast
, _count(ast
)-1);
172 WHEN a0sym
= 'if' THEN
174 cond
:= EVAL(_nth(ast
, 1), env
);
175 SELECT type_id
INTO type FROM value WHERE value_id
= cond
;
176 IF type = 0 OR type = 1 THEN -- nil or false
177 IF _count(ast
) > 3 THEN
188 WHEN a0sym
= 'fn*' THEN
190 RETURN _function(_nth(ast
, 2), _nth(ast
, 1), env
);
194 el
:= eval_ast(ast
, env
);
195 SELECT type_id
, collection_id
, function_name
197 FROM value WHERE value_id
= _first(el
);
198 args
:= _restArray(el
);
200 EXECUTE format('SELECT %s($1);', fname
)
201 INTO result USING args
;
204 SELECT value_id
, params_id
, env_id
205 INTO fast
, fparams
, fenv
207 WHERE collection_id
= fn
;
208 env
:= env_new_bindings(fenv
, fparams
, args
);
212 RAISE
EXCEPTION 'Invalid function call';
217 END; $$
LANGUAGE plpgsql
;
220 CREATE OR REPLACE FUNCTION PRINT(exp integer) RETURNS varchar AS $$
223 END; $$
LANGUAGE plpgsql
;
228 -- repl_env is environment 0
230 CREATE OR REPLACE FUNCTION REP(line
varchar) RETURNS varchar AS $$
232 RETURN PRINT(EVAL(READ(line
), 0));
233 END; $$
LANGUAGE plpgsql
;
235 -- core.sql: defined using SQL (in core.sql)
236 -- repl_env is created and populated with core functions in by core.sql
237 CREATE OR REPLACE FUNCTION mal_eval(args
integer[]) RETURNS integer AS $$
239 RETURN EVAL(args
[1], 0);
240 END; $$
LANGUAGE plpgsql
;
241 INSERT INTO value (type_id
, function_name
) VALUES (11, 'mal_eval');
243 SELECT env_vset(0, 'eval',
244 (SELECT value_id
FROM value
245 WHERE function_name
= 'mal_eval')) \g
'/dev/null'
246 -- *ARGV* values are set by RUN
247 SELECT env_vset(0, '*ARGV*', READ('()'));
250 -- core.mal: defined using the language itself
251 SELECT REP('(def! not (fn* (a) (if a false true)))') \g
'/dev/null'
252 SELECT REP('(def! load-file (fn* (f) (eval (read-string (str "(do " (slurp f) ")")))))') \g
'/dev/null'
254 CREATE OR REPLACE FUNCTION RUN(argstring
varchar) RETURNS void
AS $$
258 allargs
:= READ(argstring
);
259 PERFORM
env_vset(0, '*ARGV*', _rest(allargs
));
260 PERFORM
REP('(load-file ' ||
pr_str(_first(allargs
)) ||
')');
262 END; $$
LANGUAGE plpgsql
;