############################################################################## # # Copyright (c) 2008-2009 Nexedi SA and Contributors. All Rights Reserved. # Vincent Pelletier <vincent@nexedi.com> # # WARNING: This program as such is intended to be used by professional # programmers who take the whole responsability of assessing all potential # consequences resulting from its eventual inadequacies and bugs # End users who are looking for a ready-to-use solution with commercial # garantees and support are strongly adviced to contract a Free Software # Service Company # # This program is Free Software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # ############################################################################## from ply import lex, yacc import os import sys from cStringIO import StringIO try: from zLOG import LOG except ImportError: def LOG(channel, level, message): print >>sys.stderr, message module_path = os.path.dirname(os.path.abspath(__file__)) class ParserOrLexerError(Exception): pass class LexerError(ParserOrLexerError): pass class ParserError(ParserOrLexerError): pass class lexer(object): def init(self, **kw): debug = kw.pop('debug', False) # Catch all logs with a cStringIO output = sys.stdout = sys.stderr = StringIO() self.lexer = lex.lex(object=self, **kw) self.parser = yacc.yacc(module=self, debug=debug, debugfile="%s.out" % (self.__class__.__name__, ), tabmodule="%s_parsetab" % (self.__class__.__name__, ), outputdir=module_path) sys.stdout, sys.stderr = sys.__stdout__, sys.__stderr__ # Emit all logs with regular Zope logging for line in output.getvalue().split('\n'): if len(line): LOG('lexer', 0, line) def t_error(self, t): raise LexerError, 'ERROR: Illegal character %r' % (t.value[0], ) def p_error(self, p): raise ParserError, 'Syntax error in input: %r' % (p, ) def input(self, string): self.lexer.input(string) def token(self): return self.lexer.token() tokens = ( 'OR', 'AND', 'NOT', 'COLUMN', 'STRING', 'WORD', 'OPERATOR', 'LEFT_PARENTHESE', 'RIGHT_PARENTHESE') t_ignore = ' ' def t_LEFT_PARENTHESE(self, t): r'\(' return t def t_RIGHT_PARENTHESE(self, t): r'\)' return t def t_OPERATOR(self, t): r'(>=?|<=?|!?=)' return t def t_STRING(self, t): r'"(\\.|[^\\"])*"' # Unescape value and strip surrounding quotes value_list = [] append = value_list.append escaped = False for char in t.value[1:-1]: if escaped: escaped = False if char != '"': append('\\') else: if char == '\\': escaped = True continue append(char) assert not escaped t.value = ''.join(value_list) return t def t_COLUMN(self, t): r'[^><= :\(\)"][^ :\(\)"]*:' t.value = t.value[:-1] return t def t_OR(self, t): r'OR' return t def t_AND(self, t): r'AND' return t def t_NOT(self, t): r'NOT' return t def t_WORD(self, t): r'[^><= :\(\)"][^ :\(\)"]*' return t def parse(self, *args, **kw): kw['lexer'] = self return self.parser.parse(*args, **kw) __call__ = parse def update_docstrings(klass): for property in dir(klass): if property.startswith('t_'): source = getattr(lexer, property, None) if callable(source): destination = getattr(klass, property) assert callable(destination) if destination.__doc__ is None: destination.im_func.__doc__ = source.__doc__