mirror of
https://github.com/kanaka/mal.git
synced 2024-11-11 00:52:44 +03:00
494792abe4
- move each file to a schema namespace. Don't recreate DB, just the schemas. This is much faster and avoids the error about user still using the DB when recreating the DB. - combine RUN and MAIN_LOOP into MAIN routine. - add open column to streams table - close stream 1 in MAIN
163 lines
4.9 KiB
PL/PgSQL
163 lines
4.9 KiB
PL/PgSQL
-- ---------------------------------------------------------
|
|
-- step2_eval.sql
|
|
|
|
\i init.sql
|
|
\i io.sql
|
|
\i types.sql
|
|
\i reader.sql
|
|
\i printer.sql
|
|
|
|
-- ---------------------------------------------------------
|
|
|
|
CREATE SCHEMA mal;
|
|
|
|
-- read
|
|
CREATE FUNCTION mal.READ(line varchar) RETURNS integer AS $$
|
|
BEGIN
|
|
RETURN reader.read_str(line);
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
-- eval
|
|
CREATE FUNCTION mal.eval_ast(ast integer, env hstore) RETURNS integer AS $$
|
|
DECLARE
|
|
type integer;
|
|
symkey varchar;
|
|
seq integer[];
|
|
eseq integer[];
|
|
hash hstore;
|
|
ehash hstore;
|
|
kv RECORD;
|
|
e integer;
|
|
result integer;
|
|
BEGIN
|
|
SELECT type_id INTO type FROM types.value WHERE value_id = ast;
|
|
CASE
|
|
WHEN type = 7 THEN
|
|
BEGIN
|
|
symkey := types._valueToString(ast);
|
|
IF env ? symkey THEN
|
|
result := env -> symkey;
|
|
ELSE
|
|
RAISE EXCEPTION '''%'' not found', symkey;
|
|
END IF;
|
|
END;
|
|
WHEN type IN (8, 9) THEN
|
|
BEGIN
|
|
SELECT val_seq INTO seq FROM types.value WHERE value_id = ast;
|
|
-- Evaluate each entry creating a new sequence
|
|
FOR i IN 1 .. COALESCE(array_length(seq, 1), 0) LOOP
|
|
eseq[i] := mal.EVAL(seq[i], env);
|
|
END LOOP;
|
|
INSERT INTO types.value (type_id, val_seq) VALUES (type, eseq)
|
|
RETURNING value_id INTO result;
|
|
END;
|
|
WHEN type = 10 THEN
|
|
BEGIN
|
|
SELECT val_hash INTO hash FROM types.value WHERE value_id = ast;
|
|
-- Evaluate each value for every key/value
|
|
FOR kv IN SELECT * FROM each(hash) LOOP
|
|
e := mal.EVAL(CAST(kv.value AS integer), env);
|
|
IF ehash IS NULL THEN
|
|
ehash := hstore(kv.key, CAST(e AS varchar));
|
|
ELSE
|
|
ehash := ehash || hstore(kv.key, CAST(e AS varchar));
|
|
END IF;
|
|
END LOOP;
|
|
INSERT INTO types.value (type_id, val_hash) VALUES (type, ehash)
|
|
RETURNING value_id INTO result;
|
|
END;
|
|
ELSE
|
|
result := ast;
|
|
END CASE;
|
|
|
|
RETURN result;
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
CREATE FUNCTION mal.EVAL(ast integer, env hstore) RETURNS integer AS $$
|
|
DECLARE
|
|
type integer;
|
|
el integer;
|
|
fname varchar;
|
|
args integer[];
|
|
result integer;
|
|
BEGIN
|
|
SELECT type_id INTO type FROM types.value WHERE value_id = ast;
|
|
IF type <> 8 THEN
|
|
RETURN mal.eval_ast(ast, env);
|
|
END IF;
|
|
IF types._count(ast) = 0 THEN
|
|
RETURN ast;
|
|
END IF;
|
|
|
|
el := mal.eval_ast(ast, env);
|
|
SELECT val_string INTO fname FROM types.value
|
|
WHERE value_id = types._first(el);
|
|
args := types._restArray(el);
|
|
EXECUTE format('SELECT %s($1);', fname) INTO result USING args;
|
|
RETURN result;
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
-- print
|
|
CREATE FUNCTION mal.PRINT(exp integer) RETURNS varchar AS $$
|
|
BEGIN
|
|
RETURN printer.pr_str(exp);
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
-- repl
|
|
|
|
CREATE FUNCTION mal.intop(op varchar, args integer[]) RETURNS integer AS $$
|
|
DECLARE a integer; b integer; result integer;
|
|
BEGIN
|
|
SELECT val_int INTO a FROM types.value WHERE value_id = args[1];
|
|
SELECT val_int INTO b FROM types.value WHERE value_id = args[2];
|
|
EXECUTE format('INSERT INTO types.value (type_id, val_int)
|
|
VALUES (3, $1 %s $2)
|
|
RETURNING value_id;', op) INTO result USING a, b;
|
|
RETURN result;
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
CREATE FUNCTION mal.add(args integer[]) RETURNS integer AS $$
|
|
BEGIN RETURN mal.intop('+', args); END; $$ LANGUAGE plpgsql;
|
|
CREATE FUNCTION mal.subtract(args integer[]) RETURNS integer AS $$
|
|
BEGIN RETURN mal.intop('-', args); END; $$ LANGUAGE plpgsql;
|
|
CREATE FUNCTION mal.multiply(args integer[]) RETURNS integer AS $$
|
|
BEGIN RETURN mal.intop('*', args); END; $$ LANGUAGE plpgsql;
|
|
CREATE FUNCTION mal.divide(args integer[]) RETURNS integer AS $$
|
|
BEGIN RETURN mal.intop('/', args); END; $$ LANGUAGE plpgsql;
|
|
|
|
|
|
CREATE FUNCTION mal.REP(env hstore, line varchar) RETURNS varchar AS $$
|
|
BEGIN
|
|
RETURN mal.PRINT(mal.EVAL(mal.READ(line), env));
|
|
END; $$ LANGUAGE plpgsql;
|
|
|
|
CREATE FUNCTION mal.MAIN(pwd varchar) RETURNS integer AS $$
|
|
DECLARE
|
|
repl_env hstore;
|
|
line varchar;
|
|
output varchar;
|
|
BEGIN
|
|
repl_env := hstore(ARRAY[
|
|
'+', types._function('mal.add'),
|
|
'-', types._function('mal.subtract'),
|
|
'*', types._function('mal.multiply'),
|
|
'/', types._function('mal.divide')]);
|
|
WHILE true LOOP
|
|
BEGIN
|
|
line := io.readline('user> ', 0);
|
|
IF line IS NULL THEN
|
|
PERFORM io.close(1);
|
|
RETURN 0;
|
|
END IF;
|
|
IF line NOT IN ('', E'\n') THEN
|
|
output := mal.REP(repl_env, line);
|
|
PERFORM io.writeline(output);
|
|
END IF;
|
|
|
|
EXCEPTION WHEN OTHERS THEN
|
|
PERFORM io.writeline('Error: ' || SQLERRM);
|
|
END;
|
|
END LOOP;
|
|
END; $$ LANGUAGE plpgsql;
|