# HG changeset patch
# User Sylvain Thénault <sylvain.thenault@logilab.fr>
# Date 1276162677 -7200
#      Thu Jun 10 11:37:57 2010 +0200
# Branch stable
# Node ID c225f5dc1a7efe912be190a374b9b18d89a585bf
# Parent  0314d8a14d0d3f75381ff455e86a86cc2740168f
fix rule order so 'HAVING (X op Y)' is now parseable while 'HAVING (1+2) op Y' isn't anymore parseable... At some point we should consider more advanced parsing system than yapps.

diff --git a/parser.g b/parser.g
--- a/parser.g
+++ b/parser.g
@@ -268,8 +268,16 @@
 rule exprs_not<<S>>: NOT balanced_expr<<S>> {{ return Not(balanced_expr) }}
                    | balanced_expr<<S>>     {{ return balanced_expr }}
 
-rule balanced_expr<<S>>: expr_add<<S>> expr_op<<S>>       {{ expr_op.insert(0, expr_add); return expr_op }}
-                       | r"\(" logical_expr<<S>> r"\)" {{ return logical_expr }}
+#// XXX ambiguity, expr_add may also have '(' as first token. Hence
+#// put "(" logical_expr<<S>> ")" rule first. We can then parse:
+#//
+#//   Any T2 WHERE T1 relation T2 HAVING (1 < COUNT(T1));
+#//
+#// but not
+#//
+#//   Any T2 WHERE T1 relation T2 HAVING (1+2) < COUNT(T1);
+rule balanced_expr<<S>>: r"\(" logical_expr<<S>> r"\)" {{ return logical_expr }}
+                       | expr_add<<S>> expr_op<<S>>    {{ expr_op.insert(0, expr_add); return expr_op }}
 
 # // cant use expr<<S>> without introducing some ambiguities
 rule expr_op<<S>>: CMP_OP expr_add<<S>> {{ return Comparison(CMP_OP.upper(), expr_add) }}
diff --git a/parser.py b/parser.py
--- a/parser.py
+++ b/parser.py
@@ -519,9 +519,17 @@
     def balanced_expr(self, S, _parent=None):
         _context = self.Context(_parent, self._scanner, 'balanced_expr', [S])
         _token = self._peek('r"\\("', 'NULL', 'DATE', 'DATETIME', 'TRUE', 'FALSE', 'FLOAT', 'INT', 'STRING', 'SUBSTITUTE', 'VARIABLE', 'E_TYPE', 'FUNCTION', context=_context)
-        expr_add = self.expr_add(S, _context)
-        expr_op = self.expr_op(S, _context)
-        expr_op.insert(0, expr_add); return expr_op
+        if _token == 'r"\\("':
+            self._scan('r"\\("', context=_context)
+            logical_expr = self.logical_expr(S, _context)
+            self._scan('r"\\)"', context=_context)
+            return logical_expr
+        elif 1:
+            expr_add = self.expr_add(S, _context)
+            expr_op = self.expr_op(S, _context)
+            expr_op.insert(0, expr_add); return expr_op
+        else:
+            raise runtime.SyntaxError(_token[0], 'Could not match balanced_expr')
 
     def expr_op(self, S, _parent=None):
         _context = self.Context(_parent, self._scanner, 'expr_op', [S])
diff --git a/test/unittest_parser.py b/test/unittest_parser.py
--- a/test/unittest_parser.py
+++ b/test/unittest_parser.py
@@ -133,6 +133,21 @@
     ' GROUPBY T2'
     ' WHERE T1 relation T2'
     ' HAVING 1 < COUNT(T1) OR COUNT(T1) IN (3,4);',
+
+    'Any T2'
+    ' GROUPBY T2'
+    ' WHERE T1 relation T2'
+    ' HAVING (COUNT(T1) IN (1,2)) OR (COUNT(T1) IN (3,4));',
+
+    'Any T2'
+    ' GROUPBY T2'
+    ' WHERE T1 relation T2'
+    ' HAVING (1 < COUNT(T1) OR COUNT(T1) IN (3,4));',
+
+    'Any T2'
+    ' GROUPBY T2'
+    ' WHERE T1 relation T2'
+    ' HAVING 1+2 < COUNT(T1);',
     )
 
 class ParserHercule(TestCase):