Как только ваша грамматика видит directive @TOKEN on IDENTIFIER
, она потребляет последовательность DirectiveAddtlLocation
.Каждый из них состоит из необязательного PIPE
, за которым следует IDENTIFIER
.Как вы заметили в своем вопросе, «ключевые слова» GraphQL - это на самом деле просто особые случаи идентификаторов.Так что, вероятно, здесь происходит то, что, поскольку вы допускаете любой токен в качестве идентификатора, scalar
и Foobar
оба потребляются как DirectiveAddtlLocation
, и на самом деле никогда не получается увидеть ScalarTypeDef
.
# Parses the same as:
directive @foo on Bar | Baz | scalar | Foobar
@cool # <-- ?????
Вы можете обойти это, перечислив явный набор разрешенных директивных положений в вашей грамматике.(Возможно, вы даже сможете продвинуться далеко вперед, просто скопировав грамматику в Приложении B спецификации GraphQL и изменив ее синтаксис.)
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 на самом деле не является неоднозначной; в любом контексте, где произвольная формаИдентификатор разрешен, есть пунктуация, прежде чем «ключевое слово» может появиться снова, и в подобных случаях есть однозначные списки не совсем ключевых слов, которые не перекрываются.)