]> git.phdru.name Git - phdru.name/cgi-bin/blog-ru/search-tags.git/commitdiff
Allow 'NOT ' and 'not '
authorOleg Broytman <phd@phdru.name>
Sun, 22 Jun 2014 15:32:58 +0000 (19:32 +0400)
committerOleg Broytman <phd@phdru.name>
Sun, 22 Jun 2014 15:32:58 +0000 (19:32 +0400)
ChangeLog
TODO
parser/grammar
parser/parser.py
parser/test_lexer.py
parser/test_parser.py

index 5b2e9ebebd12b5ccfc1ceeb5e1af64e86f3ccf32..649b099ffe8e4c26311e6e0c9c3e23782e5fd0c4 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,6 @@
 Version 0.3 (2014-06-??)
 
-   Allow '&&', '||', ' AND ', ' and ', ' OR ' and ' or '.
+   Allow '&&', '||', ' AND ', ' and ', ' OR ', ' or ', 'NOT ' and 'not '.
 
 Version 0.2 (2014-06-06)
 
diff --git a/TODO b/TODO
index 19857359a1d56ec6046a99389a0e605ce1d4eac6..0126e734e80cd2878ee0a08bc6abf5b982301f15 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,3 +1 @@
-Allow 'NOT ' and 'not '.
-
 Forbid stupid expressions: double NOT, extra parens and so on.
index b88b9eddfa5fcada98134fe649558c167fd93a85..14753c88e28544d5252a74dc38a142fc11e20d83 100644 (file)
@@ -10,7 +10,7 @@
 #  !(TAG | TAG)
 # Allowed operators: conjunction - & && AND and
 #                    disjunction - | || OR or
-#                    negation    - !
+#                    negation    - ! NOT not
 # This  is a simple version of the grammar and it allows
 # rather stupid expressions, like !!TAG or ((TAG)); in the future
 # it will be fixed by making the grammar more complex and stricter.
@@ -33,6 +33,7 @@ expression : NAME
            | expression SP0 OR_OP SP0 expression
            | l_expression or_word r_expression
            | NOT_OP SP0 expression
+           | not_word r_expression
            | expression_parens
 
 l_expression : expression_parens
@@ -53,6 +54,9 @@ and_word : 'A' 'N' 'D'
 or_word : 'O' 'R'
         | 'o' 'r'
 
+not_word : 'N' 'O' 'T'
+         | 'n' 'o' 't'
+
 SP0 : SP1 | empty
 
 empty :
index cf463da5b63433082a0fd360b23586871232506e..e214698a60d156e3721ba851ca1371a17feba260 100644 (file)
@@ -4,9 +4,11 @@ from ply import lex, yacc
 
 literals = '()'
 
-tokens = ('NAME', 'AND_OP', 'OR_OP', 'NOT_OP', 'SP1')
+tokens = ('OP_WORD', 'NAME', 'AND_OP', 'OR_OP', 'NOT_OP', 'SP1')
 
-t_NAME = '([a-z][a-z0-9_]*)|AND|OR|NOT'
+t_OP_WORD = '(AND|and|OR|or|NOT|not)'
+
+t_NAME = '([a-z][a-z0-9_]*)'
 
 t_AND_OP = '&'
 
@@ -39,6 +41,8 @@ def p_expression_op_word(p):
         p[0] = ('AND', p[1], p[3])
     elif p[2] in ('OR', 'or'):
         p[0] = ('OR', p[1], p[3])
+    else:
+        raise ValueError(p)
 
 def p_expression_or_or(p):
     """expression : expression SP0 OR_OP OR_OP SP0 expression"""
@@ -52,6 +56,13 @@ def p_expression_not(p):
     """expression : NOT_OP SP0 expression"""
     p[0] = ('NOT', p[3])
 
+def p_expression_not_word(p):
+    """expression : op_word r_expression"""
+    if p[1] in ('NOT', 'not'):
+        p[0] = ('NOT', p[2])
+    else:
+        raise ValueError(p)
+
 def p_expression_in_parens(p):
     """expression : expression_parens"""
     p[0] = p[1]
@@ -83,8 +94,8 @@ def p_expression_parens(p):
     p[0] = ('PARENS', p[3])
 
 def p_op_word(p):
-    """op_word : NAME"""
-    if p[1] in ('AND', 'and', 'OR', 'or'):
+    """op_word : OP_WORD"""
+    if p[1] in ('AND', 'and', 'OR', 'or', 'NOT', 'not'):
         p[0] = p[1]
     else:
         raise SyntaxError
index c31593eeaaff45439b00301951d3ac49c82e2cc7..ba46ee61229cd4a91b269cebe6dc0305e08fe9fe 100755 (executable)
@@ -74,7 +74,7 @@ class TestLexer(unittest.TestCase):
         self.assertEqual(lextoken.lineno, 1)
         self.assertEqual(lextoken.lexpos, 3)
         lextoken = tokens[2]
-        self.assertEqual(lextoken.type, 'NAME')
+        self.assertEqual(lextoken.type, 'OP_WORD')
         self.assertEqual(lextoken.value, 'and')
         self.assertEqual(lextoken.lineno, 1)
         self.assertEqual(lextoken.lexpos, 4)
index c6d353e5f81f2f91afe8c6b60e29425dd64685e2..4696047338be02e8f749ebae22d5fb39b7e4f5cf 100755 (executable)
@@ -39,6 +39,12 @@ class TestParser(unittest.TestCase):
         self.assertEqual(parser.parse('xxx OR yyy'),
             ('OR', ('NAME', 'xxx'), ('NAME', 'yyy'))
         )
+        self.assertEqual(parser.parse('not xxx'),
+            ('NOT', ('NAME', 'xxx'))
+        )
+        self.assertEqual(parser.parse('NOT xxx'),
+            ('NOT', ('NAME', 'xxx'))
+        )
 
     def test_05_bad_expression(self):
         self.assertIs(parser.parse('!(xxx&yyy'), None)