I'm trying to implement a DSL for writing custom condition expressions, which include keywords for certain objects and properties on those. E.g.:
user.foo.bar or user.baz
user
is a keyword which is substituted with the current user object. I've also implemented or
, and
and not
operators just fine based on the existing sample.
I have implemented property access like this:
from pyparsing import infixNotation, opAssoc, Keyword, Word, alphas
class User:
pass
class PropertyAccess:
def __init__(self, t):
self.value = reduce(lambda o, p: getattr(o, p, None), t[0][0::2])
user = Keyword('user')
user.setParseAction(User)
identifier = Word(alphas + '_')
property_access_expr = infixNotation(user | identifier, [
('.', 2, opAssoc.LEFT, PropertyAccess)
])
While this works, it also allows expressions like foo.bar
, which are nonsensical. A property access must start with one of the supported keywords like user
, otherwise they should be invalid. How can I reimplement the grammar to restrict that?
You're making the task needlessly difficult by using infixNotation
. infixNotation
is useful for defining multiple different infix operators with different priorities (i.e. order of operations). But property access has only a single operator (.
), and is easily implemented with OneOrMore
:
property_access_expr = user + OneOrMore('.' + identifier)
property_access_expr.setParseAction(PropertyAccess)
Changing the grammar like this requires a minor modification of the PropertyAccess
class. Previously the input was a nested list, but now it is a flat list. Consequently, we have to change t[0][0::2]
to t[0::2]
.
class PropertyAccess:
def __init__(self, t):
self.value = reduce(lambda o, p: getattr(o, p, None), t[0::2])
Now the grammar correctly parses only attribute access that starts with user.
:
>>> property_access_expr.parseString('user.foo.bar')
([<__main__.PropertyAccess object at 0x0000000002DD4048>], {})
>>> property_access_expr.parseString('foo.bar')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
pyparsing.ParseException: Expected "user" (at char 0), (line:1, col:1)