closes #72295: add some missing operators

  • & (bitwise AND),

  • (bitwise OR),
  • # (bitwise XOR),

  • << (bitwise left shift),

  • >> (bitwise right shift)

  • % (modulo),

  • ^ (power),

authorSylvain Thénault <sylvain.thenault@logilab.fr>
changeset4990981c1826
branchstable
phasepublic
hiddenno
parent revision#540cf0442346 fix Comparison.as_string to considerer its optional attribute
child revision#7decc7f6c23f closes #72052: new optional 'optcomparisons' key in variable stinfo
files modified by this revision
ChangeLog
nodes.py
parser.g
parser.py
# HG changeset patch
# User Sylvain Thénault <sylvain.thenault@logilab.fr>
# Date 1312294936 -7200
# Tue Aug 02 16:22:16 2011 +0200
# Branch stable
# Node ID 4990981c18262742f4df575ec51421d2afdcbd85
# Parent 540cf04423467cc96996e05ce4393be0c8c3eee4
closes #72295: add some missing operators

* & (bitwise AND),
* | (bitwise OR),
* # (bitwise XOR),
* << (bitwise left shift),
* >> (bitwise right shift)
* % (modulo),
* ^ (power),

diff --git a/ChangeLog b/ChangeLog
@@ -1,10 +1,19 @@
1  ChangeLog for RQL
2  =================
3 
4  	--
5      * fix Comparison.as_string to considerer its optional attribute
6 +    * add some missing operators (#72295):
7 +
8 +      * % (modulo),
9 +      * ^ (power),
10 +      * & (bitwise AND),
11 +      * | (bitwise OR),
12 +      * # (bitwise XOR),
13 +      * << (bitwise left shift),
14 +      * >> (bitwise right shift)
15 
16  2011-07-27  --  0.29.1
17      * #70264: remove_group_var renamed into remove_group_term and fixed
18        implementation
19 
diff --git a/nodes.py b/nodes.py
@@ -481,11 +481,11 @@
20              from rql.undo import SetOptionalOperation
21              root.undo_manager.add_operation(SetOptionalOperation(self, self.optional))
22          self.optional= value
23 
24 
25 -OPERATORS = frozenset(('=', '!=', '<', '<=', '>=', '>', 'ILIKE', 'LIKE', 'REGEXP'))
26 +CMP_OPERATORS = frozenset(('=', '!=', '<', '<=', '>=', '>', 'ILIKE', 'LIKE', 'REGEXP'))
27 
28  class Comparison(HSMixin, Node):
29      """handle comparisons:
30 
31       <, <=, =, >=, > LIKE and ILIKE operators have a unique children.
@@ -494,11 +494,11 @@
32 
33      def __init__(self, operator, value=None, optional=None):
34          Node.__init__(self)
35          if operator == '~=':
36              operator = 'ILIKE'
37 -        assert operator in OPERATORS, operator
38 +        assert operator in CMP_OPERATORS, operator
39          self.operator = operator.encode()
40          self.optional = optional
41          if value is not None:
42              self.append(value)
43 
diff --git a/parser.g b/parser.g
@@ -69,11 +69,11 @@
44      token INSERT:      r'(?i)INSERT'
45      token UNION:       r'(?i)UNION'
46      token DISTINCT:    r'(?i)DISTINCT'
47      token WITH:        r'(?i)WITH'
48      token WHERE:       r'(?i)WHERE'
49 -    token BEING:          r'(?i)BEING'
50 +    token BEING:       r'(?i)BEING'
51      token OR:          r'(?i)OR'
52      token AND:         r'(?i)AND'
53      token NOT:         r'(?i)NOT'
54      token GROUPBY:     r'(?i)GROUPBY'
55      token HAVING:      r'(?i)HAVING'
@@ -87,12 +87,13 @@
56      token TRUE:        r'(?i)TRUE'
57      token FALSE:       r'(?i)FALSE'
58      token NULL:        r'(?i)NULL'
59      token EXISTS:      r'(?i)EXISTS'
60      token CMP_OP:      r'(?i)<=|<|>=|>|!=|=|~=|LIKE|ILIKE|REGEXP'
61 -    token ADD_OP:      r'\+|-'
62 -    token MUL_OP:      r'\*|/'
63 +    token ADD_OP:      r'\+|-|\||#'
64 +    token MUL_OP:      r'\*|/|%|&'
65 +    token POW_OP:      r'\^|>>|<<'
66      token FUNCTION:    r'[A-Za-z_]+\s*(?=\()'
67      token R_TYPE:      r'[a-z_][a-z0-9_]*'
68      token E_TYPE:      r'[A-Z][A-Za-z0-9]*[a-z]+[0-9]*'
69      token VARIABLE:    r'[A-Z][A-Z0-9_]*'
70      token COLALIAS:    r'[A-Z][A-Z0-9_]*\.\d+'
@@ -315,12 +316,16 @@
71  rule expr_add<<S>>: expr_mul<<S>>          {{ node = expr_mul }}
72                      ( ADD_OP expr_mul<<S>> {{ node = MathExpression( ADD_OP, node, expr_mul ) }}
73                      )*                     {{ return node }}
74 
75 
76 -rule expr_mul<<S>>: expr_base<<S>>          {{ node = expr_base }}
77 -                    ( MUL_OP expr_base<<S>> {{ node = MathExpression( MUL_OP, node, expr_base) }}
78 +rule expr_mul<<S>>: expr_pow<<S>>          {{ node = expr_pow }}
79 +                    ( MUL_OP expr_pow<<S>> {{ node = MathExpression( MUL_OP, node, expr_pow) }}
80 +                    )*                     {{ return node }}
81 +
82 +rule expr_pow<<S>>: expr_base<<S>>          {{ node = expr_base }}
83 +                    ( POW_OP expr_base<<S>> {{ node = MathExpression( MUL_OP, node, expr_base) }}
84                      )*                      {{ return node }}
85 
86 
87  rule expr_base<<S>>: const                     {{ return const }}
88                     | var<<S>>                  {{ return var }}
diff --git a/parser.py b/parser.py
@@ -94,12 +94,13 @@
89          ('TRUE', re.compile('(?i)TRUE')),
90          ('FALSE', re.compile('(?i)FALSE')),
91          ('NULL', re.compile('(?i)NULL')),
92          ('EXISTS', re.compile('(?i)EXISTS')),
93          ('CMP_OP', re.compile('(?i)<=|<|>=|>|!=|=|~=|LIKE|ILIKE|REGEXP')),
94 -        ('ADD_OP', re.compile('\\+|-')),
95 -        ('MUL_OP', re.compile('\\*|/')),
96 +        ('ADD_OP', re.compile('\\+|-|\\||#')),
97 +        ('MUL_OP', re.compile('\\*|/|%|&')),
98 +        ('POW_OP', re.compile('\\^|>>|<<')),
99          ('FUNCTION', re.compile('[A-Za-z_]+\\s*(?=\\()')),
100          ('R_TYPE', re.compile('[a-z_][a-z0-9_]*')),
101          ('E_TYPE', re.compile('[A-Z][A-Za-z0-9]*[a-z]+[0-9]*')),
102          ('VARIABLE', re.compile('[A-Z][A-Z0-9_]*')),
103          ('COLALIAS', re.compile('[A-Z][A-Z0-9_]*\\.\\d+')),
@@ -549,11 +550,11 @@
104 
105      def decl_vars(self, R, _parent=None):
106          _context = self.Context(_parent, self._scanner, 'decl_vars', [R])
107          E_TYPE = self._scan('E_TYPE', context=_context)
108          var = self.var(R, _context)
109 -        while self._peek("','", 'R_TYPE', 'QMARK', 'WHERE', '":"', 'CMP_OP', "'IN'", 'HAVING', "';'", 'MUL_OP', 'BEING', 'WITH', 'GROUPBY', 'ORDERBY', 'ADD_OP', 'LIMIT', 'OFFSET', 'r"\\)"', 'SORT_DESC', 'SORT_ASC', 'AND', 'OR', context=_context) == "','":
110 +        while self._peek("','", 'R_TYPE', 'QMARK', 'WHERE', '":"', 'CMP_OP', "'IN'", 'HAVING', "';'", 'POW_OP', 'BEING', 'WITH', 'GROUPBY', 'ORDERBY', 'MUL_OP', 'LIMIT', 'OFFSET', 'ADD_OP', 'r"\\)"', 'SORT_DESC', 'SORT_ASC', 'AND', 'OR', context=_context) == "','":
111              R.add_main_variable(E_TYPE, var)
112              self._scan("','", context=_context)
113              E_TYPE = self._scan('E_TYPE', context=_context)
114              var = self.var(R, _context)
115          R.add_main_variable(E_TYPE, var)
@@ -596,14 +597,24 @@
116              node = MathExpression( ADD_OP, node, expr_mul )
117          return node
118 
119      def expr_mul(self, S, _parent=None):
120          _context = self.Context(_parent, self._scanner, 'expr_mul', [S])
121 +        expr_pow = self.expr_pow(S, _context)
122 +        node = expr_pow
123 +        while self._peek('MUL_OP', 'ADD_OP', 'QMARK', 'r"\\)"', "','", 'SORT_DESC', 'SORT_ASC', 'CMP_OP', 'R_TYPE', "'IN'", 'GROUPBY', 'ORDERBY', 'WHERE', 'LIMIT', 'OFFSET', 'HAVING', "';'", 'WITH', 'AND', 'OR', context=_context) == 'MUL_OP':
124 +            MUL_OP = self._scan('MUL_OP', context=_context)
125 +            expr_pow = self.expr_pow(S, _context)
126 +            node = MathExpression( MUL_OP, node, expr_pow)
127 +        return node
128 +
129 +    def expr_pow(self, S, _parent=None):
130 +        _context = self.Context(_parent, self._scanner, 'expr_pow', [S])
131          expr_base = self.expr_base(S, _context)
132          node = expr_base
133 -        while self._peek('MUL_OP', 'ADD_OP', 'QMARK', 'r"\\)"', "','", 'SORT_DESC', 'SORT_ASC', 'CMP_OP', 'R_TYPE', "'IN'", 'GROUPBY', 'ORDERBY', 'WHERE', 'LIMIT', 'OFFSET', 'HAVING', "';'", 'WITH', 'AND', 'OR', context=_context) == 'MUL_OP':
134 -            MUL_OP = self._scan('MUL_OP', context=_context)
135 +        while self._peek('POW_OP', 'MUL_OP', 'ADD_OP', 'QMARK', 'r"\\)"', "','", 'SORT_DESC', 'SORT_ASC', 'CMP_OP', 'R_TYPE', "'IN'", 'GROUPBY', 'ORDERBY', 'WHERE', 'LIMIT', 'OFFSET', 'HAVING', "';'", 'WITH', 'AND', 'OR', context=_context) == 'POW_OP':
136 +            POW_OP = self._scan('POW_OP', context=_context)
137              expr_base = self.expr_base(S, _context)
138              node = MathExpression( MUL_OP, node, expr_base)
139          return node
140 
141      def expr_base(self, S, _parent=None):