在pyparsing中实现属性访问运算符

时间:2018-07-27 09:35:08

标签: python pyparsing

我正在尝试实现用于编写自定义条件表达式的DSL,其中包括用于某些对象和属性的关键字。例如:

user.foo.bar or user.baz

user是用当前用户对象替换的关键字。我还基于existing sample实现了orandnot运算符。

我已经实现了如下属性访问:

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)
])

虽然可行,但它也允许foo.bar之类的无意义的表达式。属性访问必须以受支持的关键字之一(例如user)开头,否则它们应该无效。如何重新实现语法以限制该语法?

1 个答案:

答案 0 :(得分:2)

使用infixNotation使您不必要地困难。 infixNotation对于定义多个具有不同优先级(即操作顺序)的不同中缀运算符很有用。但是属性访问只有一个运算符(.),并且可以通过OneOrMore轻松实现:

property_access_expr = user + OneOrMore('.' + identifier)
property_access_expr.setParseAction(PropertyAccess)

要更改这种语法,需要对PropertyAccess类进行较小的修改。以前,输入是嵌套列表,但现在是平面列表。因此,我们必须将t[0][0::2]更改为t[0::2]

class PropertyAccess:
    def __init__(self, t):
        self.value = reduce(lambda o, p: getattr(o, p, None), t[0::2])

现在语法正确地仅分析了以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)