1

我一直在尝试为 Grammarkit 编写 graphql 语言语法,但我发现自己在很长一段时间内都陷入了歧义问题。graphql 中的关键字(例如:、、、typeimplementsscalar可以是类型或字段的名称。IE

type type implements type {}

起初我tokens在 bnf 中定义了这些关键字,但这意味着上面的情况是无效的。但是如果我在描述规则时直接写这些关键字,就会导致语法上的歧义。我根据下面的语法看到的一个问题示例是,如果您定义了这样的内容

directive @foo on Baz | Bar
scalar Foobar @cool

PSI 查看器告诉我,在@cool它的位置期待 a DirectiveAddtlLocation,这是我什至在标量规则中都没有引用的规则。有没有人熟悉语法包并遇到过这样的事情?我真的很感激一些见解。谢谢你。

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

{
    tokens=[
            LEFT_PAREN='('
            RIGHT_PAREN=')'
            PIPE='|'
            AT='@'
            IDENTIFIER="regexp:[_A-Za-z][_0-9A-Za-z]*"
            WHITE_SPACE = 'regexp:\s+'
    ]
}

Document ::= Definition*
Definition ::=  DirectiveTypeDef | ScalarTypeDef
NamedTypeDef ::= IDENTIFIER

// I.E. @foo @bar(a: 10) @baz
DirectivesDeclSet ::= DirectiveDecl+
DirectiveDecl ::= AT TypeName

// I.E. directive @example on FIELD_DEFINITION | ARGUMENT_DEFINITION
DirectiveTypeDef ::= 'directive' AT NamedTypeDef DirectiveLocationsConditionDef
DirectiveLocationsConditionDef ::= 'on' DirectiveLocation DirectiveAddtlLocation*
DirectiveLocation ::= IDENTIFIER
DirectiveAddtlLocation ::= PIPE? DirectiveLocation

TypeName ::= IDENTIFIER

// I.E. scalar DateTime @foo
ScalarTypeDef ::= 'scalar' NamedTypeDef DirectivesDeclSet?
4

1 回答 1

0

一旦你的语法看到directive @TOKEN on IDENTIFIER,它就会消耗一个DirectiveAddtlLocation. 每一个都包含一个可选的,PIPE后跟一个IDENTIFIER. 正如您在问题中指出的那样,GraphQL“关键字”实际上只是标识符的特殊情况。所以这里可能发生的事情是,因为您允许任何令牌作为标识符,scalar并且Foobar都被用作DirectiveAddtlLocation并且它实际上永远不会看到ScalarTypeDef.

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

您可以通过在语法中列出明确的允许指令位置集来解决此问题。(您甚至可以通过复制GraphQL 规范附录 B 中的语法并更改其语法来获得相当大的进展。)

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

现在当你去解析时:

directive @foo on QUERY | MUTATION
# "scalar" is not a directive location, so the DirectiveTypeDef must end
scalar Foobar @cool

(尽管“标识符”与“关键字”的区别有点奇怪,但我很确定 GraphQL 语法实际上并没有模棱两可;在每个允许使用自由格式标识符的上下文中,“关键字”可能会再次出现,在这种情况下,会有不重叠的不完全关键字的明确列表。)

于 2019-01-20T12:50:08.883 回答