我正在尝试实现用于编写自定义条件表达式的DSL,其中包括用于某些对象和属性的关键字。例如:
user.foo.bar or user.baz
user
是用当前用户对象替换的关键字。我还基于existing sample实现了or
,and
和not
运算符。
我已经实现了如下属性访问:
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
)开头,否则它们应该无效。如何重新实现语法以限制该语法?
答案 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)