Grammar-Kit: difficulty with pin and recover

I've read all the documentation available on using grammar-kit, especially the explanations on the HOW-TO about recover and pin and just cannot get it to function properly. I've been on this for a couple days now and figure it's about time I got some help.

I am trying to implement a custom language plugin for the D language. I have gotten the basics of the lexer and parser completed. Currently I am stuck when trying to get it to recover from a bad statement at the top of the file so that it doesn't nuke the rest of the psi tree. Without any pin/recoverWhile tags this is what it looks like currently. This is the expected output, and the psi tree for the entire file is as expected.

Now, when I remove a semicolon on the first import, rather than breaking the entire psi tree, I would like it to recover on the next semicolon. I have a root production that represents most statements called DeclDef and every DeclDef (to my knowledge) ends with either a semicolon ';' or a right curly brace '}'. From what I read, since the DeclDef is a "loop" in the main module production, I should place the recover while on it and then put pins on all the productions below. This production now looks like this:

private DeclDef ::=
StaticConstructor |
SharedStaticConstructor |
AttributeSpecifier |
Declaration |
Constructor |
Destructor |
Postblit |
Allocator |
Deallocator |
Invariant |
UnitTest |
AliasThis |
StaticDestructor |
SharedStaticDestructor |
ConditionalDeclaration |
DebugSpecificaiton |
VersionSpecification |
StaticAssert |
TemplateDeclaration |
TemplateMixinDeclaration |
TemplateMixin |
MixinDeclaration |
SEMICOLON_OP
{recoverWhile=DeclDefRecover}
private DeclDefRecover ::= !(SEMICOLON_OP | CURLY_BRACE_RIGHT)

Under the DeclDef production, there is `Declaration` which contains `ImportDeclarationX`. Since only one of the productions across all of the productions in DeclDef starts with IMPORT_KEYWORD, I pin it at 1 like so:

private ImportDeclarationX ::=
ImportDeclaration |
(STATIC IMPORT_KEYWORD ImportList SEMICOLON_OP)

ImportDeclaration ::=
IMPORT_KEYWORD ImportList SEMICOLON_OP
{pin=1}

However, this seems to have entirely broken my psi tree. These changes cause:

Only the first statement is as expected, a IMPORT_DECLARATION and every else is unexpected tokens and dummy blocks. What am I doing wrong? Changing the pin or removing it altogether does not appear to do anything at all, so something I am doing with the recoverWhile is just wrong.

Please sign in to leave a comment.