1 -- ---------------------------------------------------------
11 -- ---------------------------------------------------------
16 CREATE FUNCTION mal.
READ(line
varchar) RETURNS integer AS $$
18 RETURN reader.
read_str(line
);
19 END; $$
LANGUAGE plpgsql
;
22 CREATE FUNCTION mal.
eval_ast(ast
integer, env
integer) RETURNS integer AS $$
33 SELECT type_id
INTO type FROM types.
value WHERE value_id
= ast
;
37 result := envs.
get(env
, ast
);
39 WHEN type IN (8, 9) THEN
41 SELECT val_seq
INTO seq
FROM types.
value WHERE value_id
= ast
;
42 -- Evaluate each entry creating a new sequence
43 FOR i
IN 1 ..
COALESCE(array_length(seq
, 1), 0) LOOP
44 eseq
[i
] := mal.
EVAL(seq
[i
], env
);
46 INSERT INTO types.
value (type_id
, val_seq
) VALUES (type, eseq
)
47 RETURNING value_id
INTO result;
51 SELECT val_hash
INTO hash
FROM types.
value WHERE value_id
= ast
;
52 -- Evaluate each value for every key/value
53 FOR kv
IN SELECT * FROM each(hash
) LOOP
54 e
:= mal.
EVAL(CAST(kv.
value AS integer), env
);
56 ehash
:= hstore(kv.
key, CAST(e
AS varchar));
58 ehash
:= ehash ||
hstore(kv.
key, CAST(e
AS varchar));
61 INSERT INTO types.
value (type_id
, val_hash
) VALUES (type, ehash
)
62 RETURNING value_id
INTO result;
69 END; $$
LANGUAGE plpgsql
;
71 CREATE FUNCTION mal.
EVAL(ast
integer, env
integer) RETURNS integer AS $$
85 -- PERFORM writeline(format('EVAL: %s [%s]', pr_str(ast), ast));
86 SELECT type_id
INTO type FROM types.
value WHERE value_id
= ast
;
88 RETURN mal.
eval_ast(ast
, env
);
90 IF types.
_count(ast
) = 0 THEN
94 a0
:= types.
_first(ast
);
95 IF types.
_symbol_Q(a0
) THEN
96 a0sym
:= (SELECT val_string
FROM types.
value WHERE value_id
= a0
);
98 a0sym
:= '__<*fn*>__';
102 WHEN a0sym
= 'def!' THEN
104 RETURN envs.
set(env
, types.
_nth(ast
, 1),
105 mal.
EVAL(types.
_nth(ast
, 2), env
));
107 WHEN a0sym
= 'let*' THEN
109 let_env
:= envs.
new(env
);
110 a1
:= types.
_nth(ast
, 1);
111 binds
:= (SELECT val_seq
FROM types.
value WHERE value_id
= a1
);
113 WHILE idx
< array_length(binds
, 1) LOOP
114 PERFORM envs.
set(let_env
, binds
[idx
],
115 mal.
EVAL(binds
[idx
+1], let_env
));
118 RETURN mal.
EVAL(types.
_nth(ast
, 2), let_env
);
122 el
:= mal.
eval_ast(ast
, env
);
123 SELECT val_string
INTO fname
FROM types.
value
124 WHERE value_id
= types.
_first(el
);
125 args
:= types.
_restArray(el
);
126 EXECUTE format('SELECT %s($1);', fname
)
127 INTO result USING args
;
131 END; $$
LANGUAGE plpgsql
;
134 CREATE FUNCTION mal.
PRINT(exp integer) RETURNS varchar AS $$
136 RETURN printer.
pr_str(exp);
137 END; $$
LANGUAGE plpgsql
;
142 CREATE FUNCTION mal.
intop(op
varchar, args
integer[]) RETURNS integer AS $$
143 DECLARE a
integer; b
integer; result integer;
145 SELECT val_int
INTO a
FROM types.
value WHERE value_id
= args
[1];
146 SELECT val_int
INTO b
FROM types.
value WHERE value_id
= args
[2];
147 EXECUTE format('INSERT INTO types.value (type_id, val_int)
149 RETURNING value_id;', op
) INTO result USING a
, b
;
151 END; $$
LANGUAGE plpgsql
;
153 CREATE FUNCTION mal.
add(args
integer[]) RETURNS integer AS $$
154 BEGIN RETURN mal.
intop('+', args
); END; $$
LANGUAGE plpgsql
;
155 CREATE FUNCTION mal.
subtract(args
integer[]) RETURNS integer AS $$
156 BEGIN RETURN mal.
intop('-', args
); END; $$
LANGUAGE plpgsql
;
157 CREATE FUNCTION mal.
multiply(args
integer[]) RETURNS integer AS $$
158 BEGIN RETURN mal.
intop('*', args
); END; $$
LANGUAGE plpgsql
;
159 CREATE FUNCTION mal.
divide(args
integer[]) RETURNS integer AS $$
160 BEGIN RETURN mal.
intop('/', args
); END; $$
LANGUAGE plpgsql
;
162 -- repl_env is environment 0
163 INSERT INTO envs.
env (env_id
, outer_id
, data)
164 VALUES (0, NULL, hstore(ARRAY['+', types.
_function('mal.add'),
165 '-', types.
_function('mal.subtract'),
166 '*', types.
_function('mal.multiply'),
167 '/', types.
_function('mal.divide')]));
169 CREATE FUNCTION mal.
REP(line
varchar) RETURNS varchar AS $$
171 RETURN mal.
PRINT(mal.
EVAL(mal.
READ(line
), 0));
172 END; $$
LANGUAGE plpgsql
;
174 CREATE FUNCTION mal.
MAIN(pwd
varchar) RETURNS integer AS $$
182 line
:= io.
readline('user> ', 0);
187 IF line
NOT IN ('', E
'\n') THEN
188 output := mal.
REP(line
);
189 PERFORM io.
writeline(output);
192 EXCEPTION WHEN OTHERS THEN
193 PERFORM io.
writeline('Error: ' || SQLERRM
);
196 END; $$
LANGUAGE plpgsql
;