From 37c36ab873476ce9649c5063316de873ea692d0d Mon Sep 17 00:00:00 2001
From: Vincent Pelletier <vincent@nexedi.com>
Date: Tue, 5 May 2009 12:22:24 +0000
Subject: [PATCH] Make AdvancedSearchTextParser behaviour relative to unknown
 column names coherent with AdvancedSearchtextDetector's behaviour. Update
 embeded test.

git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@26803 20353a03-c40f-0410-a6d1-a30d3c3de9de
---
 .../SearchText/AdvancedSearchTextParser.py    | 57 ++++++++++++++++++-
 .../SearchText/SearchTextParser.py            |  9 ++-
 product/ZSQLCatalog/SearchText/lexer.py       |  4 +-
 3 files changed, 64 insertions(+), 6 deletions(-)

diff --git a/product/ZSQLCatalog/SearchText/AdvancedSearchTextParser.py b/product/ZSQLCatalog/SearchText/AdvancedSearchTextParser.py
index da4f27e99f..18ab4f6bd7 100644
--- a/product/ZSQLCatalog/SearchText/AdvancedSearchTextParser.py
+++ b/product/ZSQLCatalog/SearchText/AdvancedSearchTextParser.py
@@ -148,6 +148,48 @@ verifyClass(IColumnNode, ColumnNode)
 
 class AdvancedSearchTextParser(lexer):
 
+  # IMPORTANT:
+  # In short: Don't remove any token definition below even if they look
+  # useless.
+  # In detail: The lex methods below are redefined here because of ply nice
+  # feature of prioritizing tokens using the *line* *number* at which they
+  # are defined. As we inherit those methods from another class from another
+  # file (which doesn't match this file's content, of course) we must redefine
+  # wrapper methods to enforce token priority. Kudos to ply for so much
+  # customisable behaviour. Not.
+
+  def t_LEFT_PARENTHESE(self, t):
+    return lexer.t_LEFT_PARENTHESE(self, t)
+
+  def t_RIGHT_PARENTHESE(self, t):
+    return lexer.t_RIGHT_PARENTHESE(self, t)
+
+  def t_OPERATOR(self, t):
+    return lexer.t_OPERATOR(self, t)
+
+  def t_STRING(self, t):
+    return lexer.t_STRING(self, t)
+
+  def t_COLUMN(self, t):
+    if self.isColumn(t.value[:-1]):
+      t = lexer.t_COLUMN(self, t)
+    else:
+      # t is a non-existing column, so it should be taken as a string prefix.
+      t.type = 'STRING_PREFIX'
+    return t
+
+  def t_OR(self, t):
+    return lexer.t_OR(self, t)
+
+  def t_AND(self, t):
+    return lexer.t_AND(self, t)
+
+  def t_NOT(self, t):
+    return lexer.t_NOT(self, t)
+
+  def t_WORD(self, t):
+    return lexer.t_WORD(self, t)
+
   def p_seach_text(self, p):
     '''search_text : and_expression
                    | and_expression OR search_text'''
@@ -225,8 +267,19 @@ class AdvancedSearchTextParser(lexer):
 
   def p_string(self, p):
     '''string : WORD
-              | STRING'''
-    p[0] = p[1]
+              | STRING
+              | STRING_PREFIX string'''
+    if len(p) == 3:
+      p[0] = p[1] + p[2]
+    else:
+      p[0] = p[1]
+
+  def __call__(self, input, is_column, *args, **kw):
+    self.isColumn = is_column
+    try:
+      return self.parse(input, *args, **kw)
+    finally:
+      self.isColumn = None
 
 update_docstrings(AdvancedSearchTextParser)
 
diff --git a/product/ZSQLCatalog/SearchText/SearchTextParser.py b/product/ZSQLCatalog/SearchText/SearchTextParser.py
index 335f81c7a5..37fc0b1bc4 100755
--- a/product/ZSQLCatalog/SearchText/SearchTextParser.py
+++ b/product/ZSQLCatalog/SearchText/SearchTextParser.py
@@ -72,7 +72,7 @@ def isAdvancedSearchText(input, is_column):
 @profiler_decorator
 def _parse(input, is_column, *args, **kw):
   if isAdvancedSearchText(input, is_column):
-    result = getAdvancedSearchTextParser()(input, *args, **kw)
+    result = getAdvancedSearchTextParser()(input, is_column, *args, **kw)
   else:
     result = None
   return result
@@ -222,7 +222,7 @@ if __name__ == '__main__':
     ('(a AND b) OR (c AND (d OR e))',
                                   ComplexQuery([ComplexQuery([Query(None, 'a'), Query(None, 'b')], operator='and'), ComplexQuery([Query(None, 'c'), ComplexQuery([Query(None, 'd'), Query(None, 'e')], operator='or')], operator='and')], operator='or')),
     ('(foo:"") (bar:baz)',        ComplexQuery([Query('foo', ''), Query('bar', 'baz')], operator='and')),
-    ('(foo:"") (OR:bar)',         ComplexQuery([Query('foo', ''), Query('OR', 'bar')], operator='and')),
+    ('(foo:"") (OR:bar)',         ComplexQuery([Query('foo', ''), Query(None, 'OR:bar')], operator='and')),
 #    ('foo: OR',                   ['foo', 'or']),
 #    ('foo: OR ',                  ['foo', 'or']),
 #    ('(foo:)',                    ['foo', '']),
@@ -328,12 +328,15 @@ if __name__ == '__main__':
         print '  Detector: %r' % (detector_result, )
       if detector_result:
         print '  LEX:'
-        lexer = getAdvancedSearchTextParser().lexer
+        advanced_parser = getAdvancedSearchTextParser()
+        lexer = advanced_parser.lexer
+        advanced_parser.isColumn = isColumn
         lexer.input(input)
         while 1:
           tok = lexer.token()
           if not tok: break      # No more input
           print '    %s' % (tok, )
+        advanced_parser.isColumn = None
         print '  YACC:'
         print '    %r' % (parse(input, debug=2), )
       else:
diff --git a/product/ZSQLCatalog/SearchText/lexer.py b/product/ZSQLCatalog/SearchText/lexer.py
index 2da29fa7fa..b558a34d30 100644
--- a/product/ZSQLCatalog/SearchText/lexer.py
+++ b/product/ZSQLCatalog/SearchText/lexer.py
@@ -82,6 +82,7 @@ class lexer(object):
     'NOT',
     'COLUMN',
     'STRING',
+    'STRING_PREFIX',
     'WORD',
     'OPERATOR',
     'LEFT_PARENTHESE',
@@ -146,7 +147,8 @@ class lexer(object):
     kw['lexer'] = self
     return self.parser.parse(*args, **kw)
 
-  __call__ = parse
+  def __call__(self, input, is_column, *args, **kw):
+    raise NotImplementedError
 
 def update_docstrings(klass):
   for property in dir(klass):
-- 
2.30.9