Changeset 451

Show
Ignore:
Timestamp:
08/21/07 07:25:45 (11 months ago)
Author:
athomas
Message:

pyndexter: Added sub-expression and attr:value support to the query parser.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • pyndexter/trunk/pyndexter/__init__.py

    r450 r451  
    196196 
    197197 
     198    # TODO Separate lexer and parser identifiers 
    198199    NULL = 0 
    199200    TERM = 1 
     
    201202    AND = 3 
    202203    OR = 4 
     204    ATTR = 5 
     205    BEGINSUB = 6 
     206    ENDSUB = 7 
    203207 
    204208    __slots__ = ('type', 'value', 'left', 'right') 
     
    211215 
    212216    def __repr__(self): 
    213         type_map = ('null', 'term', 'not', 'and', 'or') 
     217        type_map = {self.NULL: 'null', self.TERM: 'term', self.NOT: 'not', 
     218                    self.AND: 'and', self.OR: 'or', self.ATTR: 'attr'} 
    214219        def show(node, depth=0): 
    215220            if node.type == QueryNode.TERM: 
    216221                text = '%s("%s"' % ('  ' * depth, node.value) 
     222            elif node.type == QueryNode.ATTR: 
     223                text = '%s(%s:"%s"' % ('  ' * depth, node.value[0], node.value[1]) 
    217224            else: 
    218                 text = "%s(%s%s" % ('  ' * depth, type_map[node.type], node.value and ' "%s"' % node.value or "") 
     225                text = "%s(%s%s" % ('  ' * depth, type_map[node.type], node.value and ' "%s"' % (node.value,) or "") 
    219226            if node.left or node.right: 
    220227                text += "\n" 
     
    244251        -<term>           exclude documents containing this term 
    245252        <term> or <term>  return documents matching either term 
     253        <attr>:<term>     return documents with term in the specified attribute 
    246254 
    247255    eg. 
     
    270278    """ 
    271279 
    272     _tokenise_re = re.compile(r"(?P<ex>-)|(?P<or>or)|\"(?P<dq>(?:\\.|[^\"])*)\"|'(?P<sq>(?:\\.|[^'])*)'|(?P<te>(?:\S)+)", re.I) 
     280    _tokenise_re = re.compile(r"(?P<ex>-)|(?P<or>or)|\"(?P<dq>(?:\\.|[^\"])*)\"|'(?P<sq>(?:\\.|[^'])*)'|(?P<ss>\()|(?P<se>\))|(?P<at>\w+?:\w+)|(?P<te>\w+)", re.I) 
    273281    _group_map = {'dq': QueryNode.TERM, 'sq': QueryNode.TERM, 'te': QueryNode.TERM, 
    274                   'ex': QueryNode.NOT, 'or': QueryNode.OR} 
     282                  'ex': QueryNode.NOT, 'or': QueryNode.OR, 'at': QueryNode.ATTR, 
     283                  'ss': QueryNode.BEGINSUB, 'se': QueryNode.ENDSUB} 
    275284 
    276285    def __init__(self, phrase): 
     
    286295 
    287296    def parse(self, tokens): 
    288         # TODO: add support for sub-expressions eg. "(a b) or c" 
    289297        left = self.parse_unary(tokens) 
    290298        if tokens: 
     299            if tokens[0][0] == QueryNode.ENDSUB: 
     300                return left 
    291301            if tokens[0][0] == QueryNode.OR: 
    292302                tokens.pop(0) 
     
    307317        if not tokens: 
    308318            return None 
     319        if tokens[0][0] == QueryNode.BEGINSUB: 
     320            tokens.pop(0) 
     321            node = self.parse(tokens) 
     322            if not tokens or tokens[0][0] != QueryNode.ENDSUB: 
     323                raise InvalidQuery('Expected ) at end of sub-expression') 
     324            tokens.pop(0) 
     325            return node 
    309326        if tokens[0][0] == QueryNode.NOT: 
    310327            tokens.pop(0) 
     
    322339        if not tokens: 
    323340            raise InvalidQuery('Unexpected end of string') 
     341        if tokens[0][0] == QueryNode.ATTR: 
     342            token = tokens.pop(0) 
     343            attr, value = token[1].split(':', 1) 
     344            return QueryNode(QueryNode.ATTR, (attr, value)) 
    324345        if tokens[0][0] in (QueryNode.TERM, QueryNode.OR): 
    325346            token = tokens.pop(0) 
     
    350371        from compiler import ast, misc, pycodegen 
    351372 
     373        # TODO Make Query.ATTR work 
    352374        def _generate(node): 
    353375            if node.type == node.TERM: