Grammar for optional keyword only at top of file

I have a grammar that handles various types of declarations;

scriptFile ::= topLevelDeclaration* mainLevelDeclaration*


private topLevelDeclaration ::= (enumDeclaration | variableDeclaration)
private mainLevelDeclaration ::= (functionDeclaration | enumDeclaration | variableDeclaration)

enumDeclaration ::= 'enum' identifier enumBlock
variableDeclaration ::= typeSpecifier identifier ['=' expr]
functionDeclaration ::= typeSpecifier 'function' identifier functionBlock
etc...

I would for variableDeclaration and enumDeclaration to support an optional prefix keyword 'global', but only in topLevelDeclaration.  I understand there are a number of ways to do this, but I want to make sure the Psi tree is efficient and there are some hoops I'd rather not jump through:
1) I don't want an extra level of nesting (global/non-global) when resolving references at file level. (this happens I go do something like "topLevelDeclaration ::= ['global'] (enumDeclaration | variableDeclaration)"
2) I want usage of 'global' in a mainLevelDeclaration to cause a syntax error. (this rules out "enumDeclaration ::= ['global'] 'enum' identifier enumBlock")
3) I want the parsing to be as fast/efficient as possible (I haven't found any good resources regarding this... just some mention that use of "pin" is good, and use of recoverWith should be sparing)
4) I'd like my eventual solution to work with stubs.

So far what I've come up with is:

private topLevelDeclaration ::= (enumDeclaration | variableDeclaration | ...)
private mainLevelDeclaration ::= (functionDeclaration | mainLevelEnumDeclaration | mainLevelVariableDeclaration | ...)


globalModifier ::= 'global' // using this instead of 'global' directly causes 'getGlobalModifier()' to be generated in ScriptVariableDeclaration, which seems convenient


variableDeclaration ::= [globalModifier] typeSpecifier identifier ['=' expr]

private mainLevelVariableDeclaration !globalModifier variableDeclaration { elementType = variableDeclaration }

This seems to follow the constraints, except I am unsure of the efficiency of using ['global'] and !'global' as shown above.  Any pointers in the right direction would be appreciated.

Please sign in to leave a comment.