-- ---------------------------------------------------------
-- reader.sql
-CREATE OR REPLACE FUNCTION
- tokenize(str varchar) RETURNS varchar[] AS $$
+CREATE SCHEMA reader;
+
+CREATE FUNCTION reader.tokenize(str varchar) RETURNS varchar[] AS $$
DECLARE
re varchar = E'[[:space:] ,]*(~@|[\\[\\]{}()\'`~@]|"(?:[\\\\].|[^\\\\"])*"|;[^\n]*|[^\\s \\[\\]{}()\'"`~@,;]*)';
BEGIN
RETURN ARRAY(SELECT tok FROM
(SELECT (regexp_matches(str, re, 'g'))[1] AS tok) AS x
WHERE tok <> '' AND tok NOT LIKE ';%');
-END; $$ LANGUAGE plpgsql;
+END; $$ LANGUAGE plpgsql IMMUTABLE;
-- read_atom:
-- takes a tokens array and position
-- returns new position and value_id
-CREATE OR REPLACE FUNCTION
- read_atom(tokens varchar[], INOUT pos integer, OUT result integer) AS $$
+CREATE FUNCTION reader.read_atom(tokens varchar[],
+ INOUT pos integer, OUT result integer) AS $$
DECLARE
str_id integer;
str varchar;
token := tokens[pos];
pos := pos + 1;
-- RAISE NOTICE 'read_atom: %', token;
- IF token = 'nil' THEN
+ IF token = 'nil' THEN -- nil
result := 0;
- ELSIF token = 'false' THEN
+ ELSIF token = 'false' THEN -- false
result := 1;
- ELSIF token = 'true' THEN
+ ELSIF token = 'true' THEN -- true
result := 2;
- ELSIF token ~ '^-?[0-9][0-9]*$' THEN
+ ELSIF token ~ '^-?[0-9][0-9]*$' THEN -- integer
-- integer
- INSERT INTO value (type_id, val_int)
+ INSERT INTO types.value (type_id, val_int)
VALUES (3, CAST(token AS integer))
RETURNING value_id INTO result;
- ELSIF token ~ '^".*"' THEN
+ ELSIF token ~ '^".*"' THEN -- string
-- string
str := substring(token FROM 2 FOR (char_length(token)-2));
+ str := replace(str, '\\', chr(CAST(x'7f' AS integer)));
str := replace(str, '\"', '"');
str := replace(str, '\n', E'\n');
- str := replace(str, '\\', E'\\');
- result := _stringv(str);
+ str := replace(str, chr(CAST(x'7f' AS integer)), E'\\');
+ result := types._stringv(str);
+ ELSIF token ~ '^:.*' THEN -- keyword
+ -- keyword
+ result := types._keywordv(substring(token FROM 2 FOR (char_length(token)-1)));
ELSE
-- symbol
- result := _symbolv(token);
+ result := types._symbolv(token);
END IF;
END; $$ LANGUAGE plpgsql;
-- read_seq:
--- takes a tokens array, type (8,9), first and last characters and position
--- returns new position and value_id (or a list)
-CREATE OR REPLACE FUNCTION
- read_seq(tokens varchar[], type integer, first varchar, last varchar,
- INOUT pos integer, OUT result integer) AS $$
+-- takes a tokens array, type (8, 9, 10), first and last characters
+-- and position
+-- returns new position and value_id for a list (8), vector (9) or
+-- hash-map (10)
+CREATE FUNCTION reader.read_seq(tokens varchar[], first varchar, last varchar,
+ INOUT p integer, OUT items integer[]) AS $$
DECLARE
- list_id integer = NULL;
token varchar;
- idx integer = 0;
+ key varchar = NULL;
item_id integer;
BEGIN
- token := tokens[pos];
- pos := pos + 1;
+ token := tokens[p];
+ p := p + 1;
IF token <> first THEN
RAISE EXCEPTION 'expected ''%''', first;
END IF;
+ items := ARRAY[]::integer[];
LOOP
- IF pos > array_length(tokens, 1) THEN
+ IF p > array_length(tokens, 1) THEN
RAISE EXCEPTION 'expected ''%''', last;
END IF;
- token := tokens[pos];
+ token := tokens[p];
IF token = last THEN EXIT; END IF;
- SELECT * FROM read_form(tokens, pos) INTO pos, item_id;
- IF list_id IS NULL THEN
- list_id := (SELECT COALESCE(Max(collection_id), 0) FROM collection)+1;
- END IF;
- INSERT INTO collection (collection_id, idx, value_id)
- VALUES (list_id, idx, item_id);
- idx := idx + 1;
+ SELECT * FROM reader.read_form(tokens, p) INTO p, item_id;
+ items := array_append(items, item_id);
END LOOP;
- -- Create new list referencing list_id
- INSERT INTO value (type_id, collection_id)
- VALUES (type, list_id)
- RETURNING value_id INTO result;
- pos := pos + 1;
+ p := p + 1;
END; $$ LANGUAGE plpgsql;
-- read_form:
-- takes a tokens array and position
-- returns new position and value_id
-CREATE OR REPLACE FUNCTION
- read_form(tokens varchar[], INOUT pos integer, OUT result integer) AS $$
+CREATE FUNCTION reader.read_form(tokens varchar[],
+ INOUT pos integer, OUT result integer) AS $$
DECLARE
vid integer;
meta integer;
WHEN token = '''' THEN
BEGIN
pos := pos + 1;
- SELECT * FROM read_form(tokens, pos) INTO pos, vid;
- result := _list(ARRAY[_symbolv('quote'), vid]);
+ SELECT * FROM reader.read_form(tokens, pos) INTO pos, vid;
+ result := types._list(ARRAY[types._symbolv('quote'), vid]);
END;
WHEN token = '`' THEN
BEGIN
pos := pos + 1;
- SELECT * FROM read_form(tokens, pos) INTO pos, vid;
- result := _list(ARRAY[_symbolv('quasiquote'), vid]);
+ SELECT * FROM reader.read_form(tokens, pos) INTO pos, vid;
+ result := types._list(ARRAY[types._symbolv('quasiquote'), vid]);
END;
WHEN token = '~' THEN
BEGIN
pos := pos + 1;
- SELECT * FROM read_form(tokens, pos) INTO pos, vid;
- result := _list(ARRAY[_symbolv('unquote'), vid]);
+ SELECT * FROM reader.read_form(tokens, pos) INTO pos, vid;
+ result := types._list(ARRAY[types._symbolv('unquote'), vid]);
END;
WHEN token = '~@' THEN
BEGIN
pos := pos + 1;
- SELECT * FROM read_form(tokens, pos) INTO pos, vid;
- result := _list(ARRAY[_symbolv('splice-unquote'), vid]);
+ SELECT * FROM reader.read_form(tokens, pos) INTO pos, vid;
+ result := types._list(ARRAY[types._symbolv('splice-unquote'), vid]);
END;
WHEN token = '^' THEN
BEGIN
pos := pos + 1;
- SELECT * FROM read_form(tokens, pos) INTO pos, meta;
- SELECT * FROM read_form(tokens, pos) INTO pos, vid;
- result := _list(ARRAY[_symbolv('with-meta'), vid, meta]);
+ SELECT * FROM reader.read_form(tokens, pos) INTO pos, meta;
+ SELECT * FROM reader.read_form(tokens, pos) INTO pos, vid;
+ result := types._list(ARRAY[types._symbolv('with-meta'), vid, meta]);
END;
WHEN token = '@' THEN
BEGIN
pos := pos + 1;
- SELECT * FROM read_form(tokens, pos) INTO pos, vid;
- result := _list(ARRAY[_symbolv('deref'), vid]);
+ SELECT * FROM reader.read_form(tokens, pos) INTO pos, vid;
+ result := types._list(ARRAY[types._symbolv('deref'), vid]);
END;
-- list
RAISE EXCEPTION 'unexpected '')''';
WHEN token = '(' THEN
BEGIN
- SELECT * FROM read_seq(tokens, 8, '(', ')', pos) INTO pos, result;
+ SELECT p, types._list(items)
+ FROM reader.read_seq(tokens, '(', ')', pos) INTO pos, result;
END;
-- vector
RAISE EXCEPTION 'unexpected '']''';
WHEN token = '[' THEN
BEGIN
- SELECT * FROM read_seq(tokens, 9, '[', ']', pos) INTO pos, result;
+ SELECT p, types._vector(items)
+ FROM reader.read_seq(tokens, '[', ']', pos) INTO pos, result;
+ END;
+
+ -- hash-map
+ WHEN token = '}' THEN
+ RAISE EXCEPTION 'unexpected ''}''';
+ WHEN token = '{' THEN
+ BEGIN
+ SELECT p, types._hash_map(items)
+ FROM reader.read_seq(tokens, '{', '}', pos) INTO pos, result;
END;
--
ELSE
- SELECT * FROM read_atom(tokens, pos) INTO pos, result;
+ SELECT * FROM reader.read_atom(tokens, pos) INTO pos, result;
END CASE;
END; $$ LANGUAGE plpgsql;
-- read_str:
-- takes a string
-- returns a new value_id
-CREATE OR REPLACE FUNCTION
- read_str(str varchar) RETURNS integer AS $$
+CREATE FUNCTION reader.read_str(str varchar) RETURNS integer AS $$
DECLARE
tokens varchar[];
pos integer;
ast integer;
BEGIN
- tokens := tokenize(str);
+ tokens := reader.tokenize(str);
-- RAISE NOTICE 'read_str first: %', tokens[1];
pos := 1;
- SELECT * FROM read_form(tokens, pos) INTO pos, ast;
+ SELECT * FROM reader.read_form(tokens, pos) INTO pos, ast;
-- RAISE NOTICE 'pos after read_atom: %', pos;
RETURN ast;
END; $$ LANGUAGE plpgsql;