Skip to content

Commit e9c6cbe

Browse files
authored
Merge pull request #9 from cloudblue/fix/LITE-25309_fix-or-chain
LITE-25309 fix ambiguous parsing of comma-separated expressions
2 parents a0d3bf1 + 4f8fa4d commit e9c6cbe

File tree

2 files changed

+28
-22
lines changed

2 files changed

+28
-22
lines changed

py_rql/grammar.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@
1212
"""
1313

1414
RQL_GRAMMAR = r"""
15-
start: term?
15+
start: _top_term?
16+
17+
_top_term: term
18+
| term_and_comma
1619
1720
term: expr_term
1821
| logical
@@ -34,7 +37,6 @@
3437
3538
_and: _AND? _logical_exp
3639
| term ("&" term)+
37-
| term (_COMMA term)+
3840
3941
or_op: _or
4042
| _L_BRACE _or _R_BRACE
@@ -47,6 +49,11 @@
4749
4850
not_op: _NOT _L_BRACE expr_term _R_BRACE
4951
52+
// Separated rule for the "and" expression in comma style on the top level to avoid ambiguous parsing
53+
term_and_comma: logical_and_comma -> term
54+
logical_and_comma: and_op_comma -> logical
55+
and_op_comma: term (_COMMA term)+ -> and_op
56+
5057
comp: comp_term _L_BRACE prop _COMMA val _R_BRACE
5158
| prop _EQUALITY comp_term _EQUALITY val
5259
| prop _EQUALITY val

tests/test_parser/test_logical.py

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,6 @@ def test_logical_nesting_or(query):
135135
'((p1=v1,or(p2=v2,p3=v3),and(p4=v4,p5=v5)))',
136136
'(p1=v1,or(p2=v2,p3=v3),and(p4=v4,p5=v5))',
137137
'and(p1=v1,or(p2=v2,p3=v3),and(p4=v4,p5=v5))',
138-
'p1=v1&(p2=v2|p3=v3)&(p4=v4,p5=v5)',
139138
'p1=v1,(p2=v2|p3=v3),(p4=v4,p5=v5)',
140139
])
141140
def test_logical_nesting_and(query):
@@ -147,20 +146,16 @@ def test_logical_nesting_and(query):
147146
assert result == {
148147
and_grammar_key: [
149148
('eq', 'p1', 'v1'),
149+
{
150+
or_grammar_key: [
151+
('eq', 'p2', 'v2'),
152+
('eq', 'p3', 'v3'),
153+
],
154+
},
150155
{
151156
and_grammar_key: [
152-
{
153-
or_grammar_key: [
154-
('eq', 'p2', 'v2'),
155-
('eq', 'p3', 'v3'),
156-
],
157-
},
158-
{
159-
and_grammar_key: [
160-
('eq', 'p4', 'v4'),
161-
('eq', 'p5', 'v5'),
162-
],
163-
},
157+
('eq', 'p4', 'v4'),
158+
('eq', 'p5', 'v5'),
164159
],
165160
},
166161
],
@@ -173,23 +168,26 @@ def test_and_chain():
173168
and_grammar_key = LogicalOperators.get_grammar_key(LogicalOperators.AND)
174169
assert result == {
175170
and_grammar_key: [
176-
(ComparisonOperators.NE, 'p1', 'v1'),
177171
{
178172
and_grammar_key: [
173+
(ComparisonOperators.NE, 'p1', 'v1'),
179174
(ComparisonOperators.GE, 'p2', 'and'),
180-
(ComparisonOperators.EQ, 'or', 'v3'),
181175
],
182176
},
177+
(ComparisonOperators.EQ, 'or', 'v3'),
183178
],
184179
}
185-
186-
assert result == logical_transform('(ne(p1,v1)&(p2=ge=and,or=v3))')
180+
assert result == logical_transform('((ne(p1,v1)&p2=ge=and),or=v3)')
187181

188182

189-
def test_or_chain():
190-
q = '(ne(p1,v1)|(p2=ge=and;or=v3))'
183+
@pytest.mark.parametrize('query', (
184+
'(ne(p1,v1)|(p2=ge=and;or=v3)|p4=v4)',
185+
'or(ne(p1,v1),(ge(p2,and);or=v3),p4=v4)',
186+
))
187+
def test_or_chain(query):
191188
or_grammar_key = LogicalOperators.get_grammar_key(LogicalOperators.OR)
192-
assert logical_transform(q) == {
189+
result = logical_transform(query)
190+
assert result == {
193191
or_grammar_key: [
194192
(ComparisonOperators.NE, 'p1', 'v1'),
195193
{
@@ -198,5 +196,6 @@ def test_or_chain():
198196
(ComparisonOperators.EQ, 'or', 'v3'),
199197
],
200198
},
199+
(ComparisonOperators.EQ, 'p4', 'v4'),
201200
],
202201
}

0 commit comments

Comments
 (0)