How to solve ambiguity in with keywords as identifiers in grammar kit












1















I've been trying to write the graphql language grammar for grammarkit and I've found myself really stuck on an ambiguity issue for quite some time now. Keywords in graphql (such as: type, implements, scalar ) can also be names of types or fields. I.E.



type type implements type {}


At first I defined these keywords as tokens in the bnf but that'd mean the case above is invalid. But if I write these keywords directly as I'm describing the rule, It results in an ambiguity in the grammar.
An example of an issue I'm seeing based on this grammar below is if you define something like this



directive @foo on Baz | Bar
scalar Foobar @cool


the PSI viewer is telling me that in the position of @cool it's expecting a DirectiveAddtlLocation, which is a rule I don't even reference in the scalar rule. Is anyone familiar with grammarkit and have encountered something like this? I'd really appreciate some insight. Thank You.



Here's an excerpt of grammar for the error example I mentioned above.



{
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?









share|improve this question



























    1















    I've been trying to write the graphql language grammar for grammarkit and I've found myself really stuck on an ambiguity issue for quite some time now. Keywords in graphql (such as: type, implements, scalar ) can also be names of types or fields. I.E.



    type type implements type {}


    At first I defined these keywords as tokens in the bnf but that'd mean the case above is invalid. But if I write these keywords directly as I'm describing the rule, It results in an ambiguity in the grammar.
    An example of an issue I'm seeing based on this grammar below is if you define something like this



    directive @foo on Baz | Bar
    scalar Foobar @cool


    the PSI viewer is telling me that in the position of @cool it's expecting a DirectiveAddtlLocation, which is a rule I don't even reference in the scalar rule. Is anyone familiar with grammarkit and have encountered something like this? I'd really appreciate some insight. Thank You.



    Here's an excerpt of grammar for the error example I mentioned above.



    {
    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?









    share|improve this question

























      1












      1








      1








      I've been trying to write the graphql language grammar for grammarkit and I've found myself really stuck on an ambiguity issue for quite some time now. Keywords in graphql (such as: type, implements, scalar ) can also be names of types or fields. I.E.



      type type implements type {}


      At first I defined these keywords as tokens in the bnf but that'd mean the case above is invalid. But if I write these keywords directly as I'm describing the rule, It results in an ambiguity in the grammar.
      An example of an issue I'm seeing based on this grammar below is if you define something like this



      directive @foo on Baz | Bar
      scalar Foobar @cool


      the PSI viewer is telling me that in the position of @cool it's expecting a DirectiveAddtlLocation, which is a rule I don't even reference in the scalar rule. Is anyone familiar with grammarkit and have encountered something like this? I'd really appreciate some insight. Thank You.



      Here's an excerpt of grammar for the error example I mentioned above.



      {
      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?









      share|improve this question














      I've been trying to write the graphql language grammar for grammarkit and I've found myself really stuck on an ambiguity issue for quite some time now. Keywords in graphql (such as: type, implements, scalar ) can also be names of types or fields. I.E.



      type type implements type {}


      At first I defined these keywords as tokens in the bnf but that'd mean the case above is invalid. But if I write these keywords directly as I'm describing the rule, It results in an ambiguity in the grammar.
      An example of an issue I'm seeing based on this grammar below is if you define something like this



      directive @foo on Baz | Bar
      scalar Foobar @cool


      the PSI viewer is telling me that in the position of @cool it's expecting a DirectiveAddtlLocation, which is a rule I don't even reference in the scalar rule. Is anyone familiar with grammarkit and have encountered something like this? I'd really appreciate some insight. Thank You.



      Here's an excerpt of grammar for the error example I mentioned above.



      {
      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?






      intellij-idea graphql intellij-plugin ambiguous-grammar grammar-kit






      share|improve this question













      share|improve this question











      share|improve this question




      share|improve this question










      asked Jan 19 at 23:53









      JeffJeff

      82




      82
























          1 Answer
          1






          active

          oldest

          votes


















          0














          Once your grammar sees directive @TOKEN on IDENTIFIER, it consumes a sequence of DirectiveAddtlLocation. Each of those consists of an optional PIPE followed by an IDENTIFIER. As you note in your question, the GraphQL "keywords" are really just special cases of identifiers. So what's probably happening here is that, since you allow any token as an identifier, scalar and Foobar are both being consumed as DirectiveAddtlLocation and it's never actually getting to see a ScalarTypeDef.



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


          You can get around this by listing out the explicit set of allowed directive locations in your grammar. (You might even be able to get pretty far by just copying the grammar in Appendix B of the GraphQL spec and changing its syntax.)



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


          Now when you go to parse:



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


          (For all that the "identifier" vs. "keyword" distinction is a little weird, I'm pretty sure the GraphQL grammar isn't actually ambiguous; in every context where a free-form identifier is allowed, there's punctuation before a "keyword" could appear again, and in cases like this one there's unambiguous lists of not-quite-keywords that don't overlap.)






          share|improve this answer























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54272384%2fhow-to-solve-ambiguity-in-with-keywords-as-identifiers-in-grammar-kit%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            0














            Once your grammar sees directive @TOKEN on IDENTIFIER, it consumes a sequence of DirectiveAddtlLocation. Each of those consists of an optional PIPE followed by an IDENTIFIER. As you note in your question, the GraphQL "keywords" are really just special cases of identifiers. So what's probably happening here is that, since you allow any token as an identifier, scalar and Foobar are both being consumed as DirectiveAddtlLocation and it's never actually getting to see a ScalarTypeDef.



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


            You can get around this by listing out the explicit set of allowed directive locations in your grammar. (You might even be able to get pretty far by just copying the grammar in Appendix B of the GraphQL spec and changing its syntax.)



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


            Now when you go to parse:



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


            (For all that the "identifier" vs. "keyword" distinction is a little weird, I'm pretty sure the GraphQL grammar isn't actually ambiguous; in every context where a free-form identifier is allowed, there's punctuation before a "keyword" could appear again, and in cases like this one there's unambiguous lists of not-quite-keywords that don't overlap.)






            share|improve this answer




























              0














              Once your grammar sees directive @TOKEN on IDENTIFIER, it consumes a sequence of DirectiveAddtlLocation. Each of those consists of an optional PIPE followed by an IDENTIFIER. As you note in your question, the GraphQL "keywords" are really just special cases of identifiers. So what's probably happening here is that, since you allow any token as an identifier, scalar and Foobar are both being consumed as DirectiveAddtlLocation and it's never actually getting to see a ScalarTypeDef.



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


              You can get around this by listing out the explicit set of allowed directive locations in your grammar. (You might even be able to get pretty far by just copying the grammar in Appendix B of the GraphQL spec and changing its syntax.)



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


              Now when you go to parse:



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


              (For all that the "identifier" vs. "keyword" distinction is a little weird, I'm pretty sure the GraphQL grammar isn't actually ambiguous; in every context where a free-form identifier is allowed, there's punctuation before a "keyword" could appear again, and in cases like this one there's unambiguous lists of not-quite-keywords that don't overlap.)






              share|improve this answer


























                0












                0








                0







                Once your grammar sees directive @TOKEN on IDENTIFIER, it consumes a sequence of DirectiveAddtlLocation. Each of those consists of an optional PIPE followed by an IDENTIFIER. As you note in your question, the GraphQL "keywords" are really just special cases of identifiers. So what's probably happening here is that, since you allow any token as an identifier, scalar and Foobar are both being consumed as DirectiveAddtlLocation and it's never actually getting to see a ScalarTypeDef.



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


                You can get around this by listing out the explicit set of allowed directive locations in your grammar. (You might even be able to get pretty far by just copying the grammar in Appendix B of the GraphQL spec and changing its syntax.)



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


                Now when you go to parse:



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


                (For all that the "identifier" vs. "keyword" distinction is a little weird, I'm pretty sure the GraphQL grammar isn't actually ambiguous; in every context where a free-form identifier is allowed, there's punctuation before a "keyword" could appear again, and in cases like this one there's unambiguous lists of not-quite-keywords that don't overlap.)






                share|improve this answer













                Once your grammar sees directive @TOKEN on IDENTIFIER, it consumes a sequence of DirectiveAddtlLocation. Each of those consists of an optional PIPE followed by an IDENTIFIER. As you note in your question, the GraphQL "keywords" are really just special cases of identifiers. So what's probably happening here is that, since you allow any token as an identifier, scalar and Foobar are both being consumed as DirectiveAddtlLocation and it's never actually getting to see a ScalarTypeDef.



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


                You can get around this by listing out the explicit set of allowed directive locations in your grammar. (You might even be able to get pretty far by just copying the grammar in Appendix B of the GraphQL spec and changing its syntax.)



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


                Now when you go to parse:



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


                (For all that the "identifier" vs. "keyword" distinction is a little weird, I'm pretty sure the GraphQL grammar isn't actually ambiguous; in every context where a free-form identifier is allowed, there's punctuation before a "keyword" could appear again, and in cases like this one there's unambiguous lists of not-quite-keywords that don't overlap.)







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Jan 20 at 12:50









                David MazeDavid Maze

                13.2k31226




                13.2k31226






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54272384%2fhow-to-solve-ambiguity-in-with-keywords-as-identifiers-in-grammar-kit%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Liquibase includeAll doesn't find base path

                    How to use setInterval in EJS file?

                    Petrus Granier-Deferre