1 -- ---------------------------------------------------------
6 CREATE FUNCTION reader.
tokenize(str
varchar) RETURNS varchar[] AS $$
8 re
varchar = E
'[[:space:] ,]*(~@|[\\[\\]{}()\'`~@]|"(?:[\\\\].|[^\\\\"])*"?|;[^\n]*|[^\\s \\[\\]{}()\'"`~@,;]*)';
10 RETURN ARRAY(SELECT tok
FROM
11 (SELECT (regexp_matches(str
, re
, 'g'))[1] AS tok
) AS x
12 WHERE tok
<> '' AND tok
NOT LIKE ';%');
13 END; $$
LANGUAGE plpgsql
IMMUTABLE;
16 -- takes a tokens array and position
17 -- returns new position and value_id
18 CREATE FUNCTION reader.
read_atom(tokens
varchar[],
19 INOUT pos
integer, OUT result integer) AS $$
27 -- RAISE NOTICE 'read_atom: %', token;
28 IF token = 'nil' THEN -- nil
30 ELSIF
token = 'false' THEN -- false
32 ELSIF
token = 'true' THEN -- true
34 ELSIF
token ~
'^-?[0-9][0-9]*$' THEN -- integer
36 INSERT INTO types.
value (type_id
, val_int
)
37 VALUES (3, CAST(token AS integer))
38 RETURNING value_id
INTO result;
39 ELSIF
token ~
'^"(?:[\\\\].|[^\\\\"])*"' THEN -- string
41 str
:= substring(token FROM 2 FOR (char_length(token)-2));
42 str
:= replace(str
, '\\', chr(CAST(x
'7f' AS integer)));
43 str
:= replace(str
, '\"', '"');
44 str
:= replace(str
, '\n', E
'\n');
45 str
:= replace(str
, chr(CAST(x
'7f' AS integer)), E
'\\');
46 result := types.
_stringv(str
);
47 ELSIF
token ~
'^".*' THEN -- unclosed string
48 RAISE
EXCEPTION 'expected ''"'', got EOF';
49 ELSIF
token ~
'^:.*' THEN -- keyword
51 result := types.
_keywordv(substring(token FROM 2 FOR (char_length(token)-1)));
54 result := types.
_symbolv(token);
56 END; $$
LANGUAGE plpgsql
;
59 -- takes a tokens array, type (8, 9, 10), first and last characters
61 -- returns new position and value_id for a list (8), vector (9) or
63 CREATE FUNCTION reader.
read_seq(tokens
varchar[], first varchar, last varchar,
64 INOUT p
integer, OUT items
integer[]) AS $$
72 IF token <> first THEN
73 RAISE
EXCEPTION 'expected ''%'', got EOF', first;
75 items
:= ARRAY[]::integer[];
77 IF p
> array_length(tokens
, 1) THEN
78 RAISE
EXCEPTION 'expected ''%'', got EOF', last;
81 IF token = last THEN EXIT
; END IF;
82 SELECT * FROM reader.
read_form(tokens
, p
) INTO p
, item_id
;
83 items
:= array_append(items
, item_id
);
87 END; $$
LANGUAGE plpgsql
;
90 -- takes a tokens array and position
91 -- returns new position and value_id
92 CREATE FUNCTION reader.
read_form(tokens
varchar[],
93 INOUT pos
integer, OUT result integer) AS $$
99 token := tokens
[pos
]; -- peek
101 WHEN token = '''' THEN
104 SELECT * FROM reader.
read_form(tokens
, pos
) INTO pos
, vid
;
105 result := types.
_list(ARRAY[types.
_symbolv('quote'), vid
]);
107 WHEN token = '`' THEN
110 SELECT * FROM reader.
read_form(tokens
, pos
) INTO pos
, vid
;
111 result := types.
_list(ARRAY[types.
_symbolv('quasiquote'), vid
]);
113 WHEN token = '~' THEN
116 SELECT * FROM reader.
read_form(tokens
, pos
) INTO pos
, vid
;
117 result := types.
_list(ARRAY[types.
_symbolv('unquote'), vid
]);
119 WHEN token = '~@' THEN
122 SELECT * FROM reader.
read_form(tokens
, pos
) INTO pos
, vid
;
123 result := types.
_list(ARRAY[types.
_symbolv('splice-unquote'), vid
]);
125 WHEN token = '^' THEN
128 SELECT * FROM reader.
read_form(tokens
, pos
) INTO pos
, meta
;
129 SELECT * FROM reader.
read_form(tokens
, pos
) INTO pos
, vid
;
130 result := types.
_list(ARRAY[types.
_symbolv('with-meta'), vid
, meta
]);
132 WHEN token = '@' THEN
135 SELECT * FROM reader.
read_form(tokens
, pos
) INTO pos
, vid
;
136 result := types.
_list(ARRAY[types.
_symbolv('deref'), vid
]);
140 WHEN token = ')' THEN
141 RAISE
EXCEPTION 'unexpected '')''';
142 WHEN token = '(' THEN
144 SELECT p
, types.
_list(items
)
145 FROM reader.
read_seq(tokens
, '(', ')', pos
) INTO pos
, result;
149 WHEN token = ']' THEN
150 RAISE
EXCEPTION 'unexpected '']''';
151 WHEN token = '[' THEN
153 SELECT p
, types.
_vector(items
)
154 FROM reader.
read_seq(tokens
, '[', ']', pos
) INTO pos
, result;
158 WHEN token = '}' THEN
159 RAISE
EXCEPTION 'unexpected ''}''';
160 WHEN token = '{' THEN
162 SELECT p
, types.
_hash_map(items
)
163 FROM reader.
read_seq(tokens
, '{', '}', pos
) INTO pos
, result;
168 SELECT * FROM reader.
read_atom(tokens
, pos
) INTO pos
, result;
170 END; $$
LANGUAGE plpgsql
;
174 -- returns a new value_id
175 CREATE FUNCTION reader.
read_str(str
varchar) RETURNS integer AS $$
181 tokens
:= reader.
tokenize(str
);
182 -- RAISE NOTICE 'read_str first: %', tokens[1];
184 SELECT * FROM reader.
read_form(tokens
, pos
) INTO pos
, ast
;
185 -- RAISE NOTICE 'pos after read_atom: %', pos;
187 END; $$
LANGUAGE plpgsql
;