2 # -*- coding: utf-8 -*-
5 # - a "tree" (more precisely a predecessor map, typically computed thanks to a DFS)
6 # - a set of needed fields (those queried by the user)
8 # Copyright (C) UPMC Paris Universitas
10 # Jordan Augé <jordan.auge@lip6.fr>
11 # Marc-Olivier Buob <marc-olivier.buob@lip6.fr>
13 import pyparsing as pp
16 from manifold.util.predicate import Predicate
17 from types import StringTypes
19 # XXX When to use Keyword vs. Regex vs. CaselessLiteral
20 # XXX capitalization ?
22 # Instead of CaselessLiteral, try using CaselessKeyword. Keywords are better
23 # choice for grammar keywords, since they inherently avoid mistaking the leading
24 # 'in' of 'inside' as the keyword 'in' in your grammar.
29 def __new__(cls, *args, **kwargs):
30 if len(args) == 1 and isinstance(args[0], StringTypes):
31 return ClauseStringParser().parse(args[0])
32 return super(Clause, cls).__new__(cls, *args, **kwargs)
34 def __init__(self, *args, **kwargs):
37 self.operator = Predicate.operators[args[0]]
38 self.operands = [args[1]]
40 self.operator = Predicate.operators[args[1]]
41 self.operands = [args[0], args[2]]
43 raise Exception, "Clause can only be unary or binary"
45 def opstr(self, operator):
46 ops = [string for string, op in Predicate.operators.items() if op == operator]
47 return ops[0] if ops else ''
50 if len(self.operands) == 1:
51 return "%s(%s)" % (self.operator, self.operands[0])
53 return "(%s %s %s)" % (self.operands[0], self.opstr(self.operator), self.operands[1])
55 class ClauseStringParser(object):
62 #integer = pp.Word(nums)
63 #floatNumber = pp.Regex(r'\d+(\.\d*)?([eE]\d+)?')
64 point = pp.Literal( "." )
65 e = pp.CaselessLiteral( "E" )
67 # Regex string representing the set of possible operators
68 # Example : ">=|<=|!=|>|<|="
69 OPERATOR_RX = '|'.join([re.sub('\|', '\|', o) for o in Predicate.operators.keys()])
72 field = pp.Word(pp.alphanums + '_')
73 operator = pp.Regex(OPERATOR_RX).setName("operator")
74 value = pp.QuotedString('"') #| pp.Combine( pp.Word( "+-"+ pp.nums, pp.nums) + pp.Optional( point + pp.Optional( pp.Word( pp.nums ) ) ) + pp.Optional( e + pp.Word( "+-"+pp.nums, pp.nums ) ) )
76 predicate = (field + operator + value).setParseAction(self.handlePredicate)
78 # clause of predicates
79 and_op = pp.CaselessLiteral("and") | pp.Keyword("&&")
80 or_op = pp.CaselessLiteral("or") | pp.Keyword("||")
81 not_op = pp.Keyword("!")
83 predicate_precedence_list = [
84 (not_op, 1, pp.opAssoc.RIGHT, lambda x: self.handleClause(*x)),
85 (and_op, 2, pp.opAssoc.LEFT, lambda x: self.handleClause(*x)),
86 (or_op, 2, pp.opAssoc.LEFT, lambda x: self.handleClause(*x))
88 clause = pp.operatorPrecedence(predicate, predicate_precedence_list)
92 def handlePredicate(self, args):
93 return Predicate(*args)
95 def handleClause(self, args):
98 def parse(self, string):
99 return self.bnf.parseString(string,parseAll=True)
101 if __name__ == "__main__":
102 print ClauseStringParser().parse('country == "Europe" || ts > "01-01-2007" && country == "France"')
103 print Clause('country == "Europe" || ts > "01-01-2007" && country == "France"')