plpgsql: steps 4-6.
[jackhill/mal.git] / plpgsql / step2_eval.sql
1 \i init.sql
2 \i types.sql
3 \i reader.sql
4 \i printer.sql
5
6 -- ---------------------------------------------------------
7 -- step1_read_print.sql
8
9 -- read
10 CREATE OR REPLACE FUNCTION READ(line varchar) RETURNS integer AS $$
11 BEGIN
12 RETURN read_str(line);
13 END; $$ LANGUAGE plpgsql;
14
15 -- eval
16 CREATE OR REPLACE FUNCTION just_add(args integer[]) RETURNS integer AS $$
17 BEGIN RETURN args[1] + args[2]; END; $$ LANGUAGE plpgsql;
18
19 CREATE OR REPLACE FUNCTION eval_ast(ast integer, env integer) RETURNS integer AS $$
20 DECLARE
21 type integer;
22 symkey varchar;
23 vid integer;
24 i integer;
25 src_coll_id integer;
26 dst_coll_id integer = NULL;
27 e integer;
28 result integer;
29 BEGIN
30 SELECT type_id INTO type FROM value WHERE value_id = ast;
31 CASE
32 WHEN type = 7 THEN
33 BEGIN
34 symkey := _vstring(ast);
35 SELECT e.value_id FROM env e INTO result
36 WHERE e.env_id = env
37 AND e.key = symkey;
38 IF result IS NULL THEN
39 RAISE EXCEPTION '''%'' not found', symkey;
40 END IF;
41 END;
42 WHEN type = 8 OR type = 9 THEN
43 BEGIN
44 src_coll_id := (SELECT collection_id FROM value WHERE value_id = ast);
45 FOR vid, i IN (SELECT value_id, idx FROM collection
46 WHERE collection_id = src_coll_id)
47 LOOP
48 e := EVAL(vid, env);
49 IF dst_coll_id IS NULL THEN
50 dst_coll_id := COALESCE((SELECT Max(collection_id)
51 FROM collection)+1,0);
52 END IF;
53 -- Evaluated each entry
54 INSERT INTO collection (collection_id, idx, value_id)
55 VALUES (dst_coll_id, i, e);
56 END LOOP;
57 -- Create value entry pointing to new collection
58 INSERT INTO value (type_id, collection_id)
59 VALUES (type, dst_coll_id)
60 RETURNING value_id INTO result;
61 END;
62 ELSE
63 result := ast;
64 END CASE;
65
66 RETURN result;
67 END; $$ LANGUAGE plpgsql;
68
69 CREATE OR REPLACE FUNCTION EVAL(ast integer, env integer) RETURNS integer AS $$
70 DECLARE
71 type integer;
72 el integer;
73 fname varchar;
74 args integer[];
75 result integer;
76 BEGIN
77 SELECT type_id INTO type FROM value WHERE value_id = ast;
78 IF type <> 8 THEN
79 RETURN eval_ast(ast, env);
80 END IF;
81
82 el := eval_ast(ast, env);
83 SELECT function_name INTO fname FROM value WHERE value_id = _first(el);
84 args := _restArray(el);
85 -- RAISE NOTICE 'fname: %, args: %', fname, args;
86 EXECUTE format('SELECT %s($1);', fname)
87 INTO result USING args;
88 RETURN result;
89 END; $$ LANGUAGE plpgsql;
90
91 -- print
92 CREATE OR REPLACE FUNCTION PRINT(exp integer) RETURNS varchar AS $$
93 BEGIN
94 RETURN pr_str(exp);
95 END; $$ LANGUAGE plpgsql;
96
97
98 -- repl
99
100 -- env table
101 CREATE TABLE env (
102 env_id integer NOT NULL,
103 key varchar NOT NULL,
104 value_id integer NOT NULL
105 );
106
107 CREATE OR REPLACE FUNCTION env_vset(env integer, name varchar, val integer)
108 RETURNS void AS $$
109 BEGIN
110 INSERT INTO env (env_id, key, value_id) VALUES (env, name, val);
111 END; $$ LANGUAGE plpgsql;
112
113
114 CREATE OR REPLACE FUNCTION mal_intop(op varchar, args integer[]) RETURNS integer AS $$
115 DECLARE a integer; b integer; result integer;
116 BEGIN
117 SELECT val_int INTO a FROM value WHERE value_id = args[1];
118 SELECT val_int INTO b FROM value WHERE value_id = args[2];
119 EXECUTE format('INSERT INTO value (type_id, val_int) VALUES (3, $1 %s $2)
120 RETURNING value_id;', op) INTO result USING a, b;
121 RETURN result;
122 END; $$ LANGUAGE plpgsql;
123
124 CREATE OR REPLACE FUNCTION mal_add(args integer[]) RETURNS integer AS $$
125 BEGIN RETURN mal_intop('+', args); END; $$ LANGUAGE plpgsql;
126 CREATE OR REPLACE FUNCTION mal_subtract(args integer[]) RETURNS integer AS $$
127 BEGIN RETURN mal_intop('-', args); END; $$ LANGUAGE plpgsql;
128 CREATE OR REPLACE FUNCTION mal_multiply(args integer[]) RETURNS integer AS $$
129 BEGIN RETURN mal_intop('*', args); END; $$ LANGUAGE plpgsql;
130 CREATE OR REPLACE FUNCTION mal_divide(args integer[]) RETURNS integer AS $$
131 BEGIN RETURN mal_intop('/', args); END; $$ LANGUAGE plpgsql;
132
133 INSERT INTO value (type_id, function_name) VALUES (11, 'mal_add');
134 INSERT INTO value (type_id, function_name) VALUES (11, 'mal_subtract');
135 INSERT INTO value (type_id, function_name) VALUES (11, 'mal_multiply');
136 INSERT INTO value (type_id, function_name) VALUES (11, 'mal_divide');
137
138 -- repl_env is environment 0
139 SELECT env_vset(0, '+', (SELECT value_id FROM value WHERE function_name = 'mal_add'));
140 SELECT env_vset(0, '-', (SELECT value_id FROM value WHERE function_name = 'mal_subtract'));
141 SELECT env_vset(0, '*', (SELECT value_id FROM value WHERE function_name = 'mal_multiply'));
142 SELECT env_vset(0, '/', (SELECT value_id FROM value WHERE function_name = 'mal_divide'));
143
144
145 CREATE OR REPLACE FUNCTION REP(line varchar) RETURNS varchar AS $$
146 DECLARE
147 output varchar;
148 BEGIN
149 -- RAISE NOTICE 'line is %', line;
150 -- output := 'line: ' || line;
151 RETURN PRINT(EVAL(READ(line), 0));
152 END; $$ LANGUAGE plpgsql;