1 |
|
%% Copyright (c) 2023 Peter Morgan <peter.james.morgan@gmail.com> |
2 |
|
%% |
3 |
|
%% Licensed under the Apache License, Version 2.0 (the "License"); |
4 |
|
%% you may not use this file except in compliance with the License. |
5 |
|
%% You may obtain a copy of the License at |
6 |
|
%% |
7 |
|
%% http://www.apache.org/licenses/LICENSE-2.0 |
8 |
|
%% |
9 |
|
%% Unless required by applicable law or agreed to in writing, software |
10 |
|
%% distributed under the License is distributed on an "AS IS" BASIS, |
11 |
|
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 |
|
%% See the License for the specific language governing permissions and |
13 |
|
%% limitations under the License. |
14 |
|
|
15 |
|
|
16 |
|
-module(pgsqlp_scalar). |
17 |
|
-feature(maybe_expr, enable). |
18 |
|
|
19 |
|
|
20 |
|
-export([column_references/0]). |
21 |
|
-export([expression/0]). |
22 |
|
-export([function_call/0]). |
23 |
|
-import(scran_branch, [alt/1]). |
24 |
|
-import(scran_character_complete, [digit1/0]). |
25 |
|
-import(scran_character_complete, [multispace0/0]). |
26 |
|
-import(scran_character_complete, [multispace1/0]). |
27 |
|
-import(scran_character_complete, [re/1]). |
28 |
|
-import(scran_character_complete, [tag/1]). |
29 |
|
-import(scran_character_complete, [tag_no_case/1]). |
30 |
|
-import(scran_combinator, [is_not/1]). |
31 |
|
-import(scran_combinator, [map_parser/2]). |
32 |
|
-import(scran_combinator, [map_result/2]). |
33 |
|
-import(scran_combinator, [opt/1]). |
34 |
|
-import(scran_multi, [many1/1]). |
35 |
|
-import(scran_multi, [separated_list0/2]). |
36 |
|
-import(scran_multi, [separated_list1/2]). |
37 |
|
-import(scran_result, [kv/2]). |
38 |
|
-import(scran_sequence, [delimited/3]). |
39 |
|
-import(scran_sequence, [pair/2]). |
40 |
|
-import(scran_sequence, [preceded/2]). |
41 |
|
-import(scran_sequence, [separated_pair/3]). |
42 |
|
-import(scran_sequence, [sequence/1]). |
43 |
|
-import(scran_sequence, [terminated/2]). |
44 |
|
-include_lib("kernel/include/logger.hrl"). |
45 |
|
|
46 |
|
|
47 |
|
expression() -> |
48 |
1010 |
fun |
49 |
|
(Input) -> |
50 |
177 |
(alt([in_expression(), |
51 |
|
operator_invocation(), |
52 |
|
function_call(), |
53 |
|
column_reference(), |
54 |
|
conditional(), |
55 |
|
type_cast(), |
56 |
|
group_subexpression(), |
57 |
|
literal_value()]))(Input) |
58 |
|
end. |
59 |
|
|
60 |
|
group_subexpression() -> |
61 |
346 |
fun |
62 |
|
(Input) -> |
63 |
159 |
(kv(?FUNCTION_NAME, |
64 |
|
delimited( |
65 |
|
sequence([multispace0(), |
66 |
|
tag("("), |
67 |
|
multispace0()]), |
68 |
|
expression(), |
69 |
|
sequence([multispace0(), |
70 |
|
tag(")")]))))(Input) |
71 |
|
|
72 |
|
end. |
73 |
|
|
74 |
|
conditional() -> |
75 |
177 |
fun |
76 |
|
(Input) -> |
77 |
70 |
(alt([case_expression()]))(Input) |
78 |
|
end. |
79 |
|
|
80 |
|
case_expression() -> |
81 |
70 |
fun |
82 |
|
(Input) -> |
83 |
70 |
(kv(?FUNCTION_NAME, |
84 |
|
terminated( |
85 |
|
preceded( |
86 |
|
sequence( |
87 |
|
[multispace0(), |
88 |
|
tag_no_case("CASE")]), |
89 |
|
|
90 |
|
sequence( |
91 |
|
[kv(clauses, |
92 |
|
many1( |
93 |
|
sequence( |
94 |
|
[kv(condition, |
95 |
|
preceded( |
96 |
|
sequence( |
97 |
|
[multispace1(), |
98 |
|
tag_no_case("WHEN"), |
99 |
|
multispace1()]), |
100 |
|
expression())), |
101 |
|
|
102 |
|
kv(then, |
103 |
|
preceded( |
104 |
|
sequence( |
105 |
|
[multispace1(), |
106 |
|
tag_no_case("THEN"), |
107 |
|
multispace1()]), |
108 |
|
expression()))]))), |
109 |
|
|
110 |
|
opt(kv(otherwise, |
111 |
|
preceded( |
112 |
|
sequence( |
113 |
|
[multispace1(), |
114 |
|
tag_no_case("ELSE"), |
115 |
|
multispace1()]), |
116 |
|
expression())))])), |
117 |
|
sequence( |
118 |
|
[multispace1(), |
119 |
|
tag_no_case("END"), |
120 |
|
multispace0()]))))(Input) |
121 |
|
end. |
122 |
|
|
123 |
|
type_cast() -> |
124 |
346 |
fun |
125 |
|
(Input) -> |
126 |
273 |
(kv(?FUNCTION_NAME, |
127 |
|
sequence( |
128 |
|
[alt([literal_value()]), |
129 |
|
preceded( |
130 |
|
tag_no_case("::"), |
131 |
|
type_name())])))(Input) |
132 |
|
end. |
133 |
|
|
134 |
|
|
135 |
|
function_call() -> |
136 |
367 |
fun |
137 |
|
(Input) -> |
138 |
365 |
(kv(?FUNCTION_NAME, |
139 |
|
sequence([function_name(), function_args()])))(Input) |
140 |
|
end. |
141 |
|
|
142 |
|
|
143 |
|
function_name() -> |
144 |
365 |
fun |
145 |
|
(Input) -> |
146 |
365 |
(kv(?FUNCTION_NAME, |
147 |
|
alt([map_result( |
148 |
|
separated_pair(schema_name(), tag("."), name()), |
149 |
|
fun erlang:list_to_tuple/1), |
150 |
|
|
151 |
|
tag_no_case("ANY"), |
152 |
|
|
153 |
|
name()])))(Input) |
154 |
|
end. |
155 |
|
|
156 |
|
|
157 |
|
function_args() -> |
158 |
365 |
fun |
159 |
|
(Input) -> |
160 |
194 |
(kv(?FUNCTION_NAME, |
161 |
|
delimited( |
162 |
|
tag("("), |
163 |
|
separated_list0( |
164 |
|
sequence([tag(","), multispace0()]), |
165 |
|
expression()), |
166 |
|
tag(")"))))(Input) |
167 |
|
end. |
168 |
|
|
169 |
|
|
170 |
|
operator_invocation() -> |
171 |
177 |
fun |
172 |
|
(Input) -> |
173 |
169 |
(kv(?FUNCTION_NAME, infix_operator()))(Input) |
174 |
|
end. |
175 |
|
|
176 |
|
|
177 |
|
infix_operator() -> |
178 |
169 |
fun |
179 |
|
(Input) -> |
180 |
169 |
(infix_operator( |
181 |
|
preceded( |
182 |
|
multispace0(), |
183 |
|
operator()), |
184 |
|
|
185 |
|
preceded( |
186 |
|
multispace0(), |
187 |
|
alt([function_call(), |
188 |
|
in_expression(), |
189 |
|
type_cast(), |
190 |
|
column_reference(), |
191 |
|
group_subexpression(), |
192 |
|
literal_value()]))))(Input) |
193 |
|
end. |
194 |
|
|
195 |
|
|
196 |
|
infix_operator(OperatorParser, ExpressionParser) -> |
197 |
169 |
fun |
198 |
|
(Input) -> |
199 |
169 |
?LOG_DEBUG( |
200 |
|
#{input => Input, |
201 |
|
operator_parser => scran_debug:pp(OperatorParser), |
202 |
169 |
expression_parser => scran_debug:pp(ExpressionParser)}), |
203 |
|
|
204 |
169 |
maybe |
205 |
169 |
{OperatorInput, LHS} ?= ExpressionParser(Input), |
206 |
162 |
{RHSInput, Operator} ?= OperatorParser(OperatorInput), |
207 |
40 |
{NextIterationInput, RHS} ?= ExpressionParser(RHSInput), |
208 |
|
|
209 |
|
|
210 |
40 |
(kv(?FUNCTION_NAME, |
211 |
|
?FUNCTION_NAME( |
212 |
|
OperatorParser, |
213 |
|
ExpressionParser, |
214 |
|
[RHS, {operator, Operator}, LHS])))(NextIterationInput) |
215 |
|
end |
216 |
|
end. |
217 |
|
|
218 |
|
infix_operator(OperatorParser, ExpressionParser, A) -> |
219 |
62 |
fun |
220 |
|
(Input) -> |
221 |
62 |
?LOG_DEBUG( |
222 |
|
#{input => Input, |
223 |
|
operator_parser => scran_debug:pp(OperatorParser), |
224 |
|
expression_parser => scran_debug:pp(ExpressionParser), |
225 |
62 |
a => A}), |
226 |
|
|
227 |
62 |
maybe |
228 |
62 |
{ExpressionInput, Operator} ?= OperatorParser(Input), |
229 |
25 |
{NextIterationInput, Expression} ?= ExpressionParser(ExpressionInput), |
230 |
|
|
231 |
22 |
?LOG_DEBUG(#{operator => Operator, expression => Expression}), |
232 |
|
|
233 |
22 |
(?FUNCTION_NAME( |
234 |
|
OperatorParser, |
235 |
|
ExpressionParser, |
236 |
|
[Expression, {operator, Operator} | A]))(NextIterationInput) |
237 |
|
|
238 |
|
else |
239 |
|
nomatch -> |
240 |
40 |
{Input, lists:reverse(A)} |
241 |
|
end |
242 |
|
end. |
243 |
|
|
244 |
|
operator() -> |
245 |
169 |
fun |
246 |
|
(Input) -> |
247 |
224 |
(alt( |
248 |
|
[re("[\\+\\-\\*\\/\\<\\>\\=\\~\\!\\@\\#\\%\\^\\&\\|\\`\\?]{1,63}"), |
249 |
|
tag_no_case("AND NOT"), |
250 |
|
tag_no_case("AND"), |
251 |
|
tag_no_case("OR"), |
252 |
|
tag_no_case("NOT")]))(Input) |
253 |
|
end. |
254 |
|
|
255 |
|
|
256 |
|
column_references() -> |
257 |
399 |
fun |
258 |
|
(Input) -> |
259 |
391 |
(kv(?FUNCTION_NAME, |
260 |
|
separated_list1( |
261 |
|
sequence([tag(","), multispace0()]), |
262 |
|
column_reference())))(Input) |
263 |
|
end. |
264 |
|
|
265 |
|
|
266 |
|
column_reference() -> |
267 |
737 |
fun |
268 |
|
(Input) -> |
269 |
804 |
(kv(?FUNCTION_NAME, |
270 |
|
map_result( |
271 |
|
separated_list1( |
272 |
|
tag("."), |
273 |
|
name()), |
274 |
|
fun erlang:list_to_tuple/1)))(Input) |
275 |
|
end. |
276 |
|
|
277 |
|
|
278 |
|
in_expression() -> |
279 |
346 |
fun |
280 |
|
(Input) -> |
281 |
389 |
(kv(in, |
282 |
|
pair( |
283 |
|
column_references(), |
284 |
|
preceded( |
285 |
|
sequence( |
286 |
|
[multispace1(), |
287 |
|
tag_no_case("IN"), |
288 |
|
multispace1()]), |
289 |
|
delimited( |
290 |
|
sequence([tag("("), multispace0()]), |
291 |
|
separated_list0( |
292 |
|
sequence([tag(","), multispace0()]), |
293 |
|
expression()), |
294 |
|
sequence([multispace0(), tag(")")]))))))(Input) |
295 |
|
end. |
296 |
|
|
297 |
|
|
298 |
|
literal_value() -> |
299 |
619 |
fun |
300 |
|
(Input) -> |
301 |
421 |
(alt([null_literal(), |
302 |
|
string_literal(), |
303 |
|
numeric_literal(), |
304 |
|
boolean_literal()]))(Input) |
305 |
|
end. |
306 |
|
|
307 |
|
|
308 |
|
null_literal() -> |
309 |
421 |
fun |
310 |
|
(Input) -> |
311 |
421 |
(kv(?FUNCTION_NAME, tag_no_case("null")))(Input) |
312 |
|
end. |
313 |
|
|
314 |
|
string_literal() -> |
315 |
421 |
fun |
316 |
|
(Input) -> |
317 |
401 |
(kv(?FUNCTION_NAME, |
318 |
|
delimited( |
319 |
|
tag("'"), |
320 |
|
re("[a-z_]*"), |
321 |
|
tag("'"))))(Input) |
322 |
|
end. |
323 |
|
|
324 |
|
numeric_literal() -> |
325 |
421 |
fun |
326 |
|
(Input) -> |
327 |
271 |
(kv(?FUNCTION_NAME, |
328 |
|
map_result( |
329 |
|
digit1(), |
330 |
|
fun erlang:binary_to_integer/1)))(Input) |
331 |
|
end. |
332 |
|
|
333 |
|
boolean_literal() -> |
334 |
421 |
fun |
335 |
|
(Input) -> |
336 |
172 |
(kv(?FUNCTION_NAME, |
337 |
|
map_result( |
338 |
|
alt([tag_no_case("true"), tag_no_case("false")]), |
339 |
|
fun |
340 |
|
(Term) -> |
341 |
32 |
binary_to_existing_atom(string:lowercase(Term)) |
342 |
|
end)))(Input) |
343 |
|
end. |
344 |
|
|
345 |
|
type_name() -> |
346 |
273 |
fun |
347 |
|
(Input) -> |
348 |
5 |
(kv(?FUNCTION_NAME, |
349 |
|
separated_list0( |
350 |
|
tag("."), |
351 |
|
re("[a-z_][a-z0-9_]*"))))(Input) |
352 |
|
end. |
353 |
|
|
354 |
|
|
355 |
|
schema_name() -> |
356 |
365 |
fun |
357 |
|
(Input) -> |
358 |
365 |
(name())(Input) |
359 |
|
end. |
360 |
|
|
361 |
|
|
362 |
|
name() -> |
363 |
1899 |
fun |
364 |
|
(Input) -> |
365 |
1940 |
(map_parser( |
366 |
|
re("[a-z_]+"), |
367 |
|
is_not(pgsqlp:reserved())))(Input) |
368 |
|
end. |