如何在语法工具包中使用关键字作为标识符解决歧义

时间:2019-01-19 23:53:36

标签: intellij-idea graphql intellij-plugin ambiguous-grammar grammar-kit

我一直在尝试为grammarkit编写graphql语言语法,而我发现自己已经很长时间以来一直陷入歧义问题。 graphql中的关键字(例如:server.servlet.context-path=/auth server.use-forward-headers=true typeimplements)也可以是类型或字段的名称。 I.E。

scalar

首先,我在bnf中将这些关键字定义为type type implements type {} ,但这意味着上述情况无效。但是,如果我在描述规则时直接写这些关键字,则会在语法上产生歧义。  我在下面的语法基础上看到的一个问题示例是,如果您定义了这样的内容

tokens

PSI查看器告诉我,在directive @foo on Baz | Bar scalar Foobar @cool 的位置上,期望的是@cool,这是我在标量规则中甚至没有引用的规则。有谁熟悉grammarkit并遇到这样的事情?我真的很感谢一些见识。谢谢。

这是我上面提到的错误示例的语法摘录。

DirectiveAddtlLocation

1 个答案:

答案 0 :(得分:0)

一旦您的语法看到directive @TOKEN on IDENTIFIER,它就会消耗DirectiveAddtlLocation的序列。其中的每一个都包含一个可选的PIPE,后跟一个IDENTIFIER。正如您在问题中指出的那样,GraphQL“关键字”实际上只是标识符的特殊情况。因此,这里可能发生的事情是,由于您允许任何令牌作为标识符,因此scalarFoobar都以DirectiveAddtlLocation的形式被使用,实际上并没有看到{{1} }。

ScalarTypeDef

您可以通过列出语法中的explicit set of allowed directive locations来解决此问题。 (您甚至可以只复制Appendix B of the GraphQL spec中的语法并更改其语法就可以走得很远。)

# Parses the same as:
directive @foo on Bar | Baz | scalar | Foobar
@cool  # <-- ?????

现在,当您解析时:

DirectiveLocation ::= ExecutableDirectiveLocation | TypeSystemDirectiveLocation
ExecutableDirectiveLocation ::= 'QUERY' | 'MUTATION' | ...
TypeSystemDirectiveLocation ::= 'SCHEMA' | 'SCALAR' | ...

(对于“标识符”与“关键字”的区别有点奇怪,我很确定GraphQL语法实际上并不模棱两可;在允许使用自由格式标识符的每种情况下,标点符号再次出现“关键字”之前,在这种情况下,就会出现不重复的不重复关键字的明确列表。)