From f30eb4b5ff03e201d5c0a52912130db0215deacf Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Fri, 22 Sep 2017 23:43:43 +0200 Subject: [PATCH] Use semantic lookahead for the module productions The new keyword are only "restricted keywords" and can still be used as identifiers. --- pmd-java/etc/grammar/Java.jjt | 41 +++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/pmd-java/etc/grammar/Java.jjt b/pmd-java/etc/grammar/Java.jjt index c06cf10bc9..77b608a17e 100644 --- a/pmd-java/etc/grammar/Java.jjt +++ b/pmd-java/etc/grammar/Java.jjt @@ -379,6 +379,14 @@ public class JavaParser { return res; } + /** + * Semantic lookahead to check if the next identifier is a + * specific restricted keyword. + */ + private boolean isKeyword(String keyword) { + return getToken(1).kind == IDENTIFIER && getToken(1).image.equals(keyword); + } + public Map getSuppressMap() { return token_source.getSuppressMap(); } @@ -497,7 +505,17 @@ TOKEN : | < VOLATILE: "volatile" > | < WHILE: "while" > | < STRICTFP: "strictfp" > -| < OPEN: "open" > +} + + +/* Restricted Keywords */ +// Note: These are commented out, since these keywords +// can still be used as identifiers. +// see isKeyword() semantic lookup +/* +TOKEN : +{ + < OPEN: "open" > | < MODULE: "module" > | < REQUIRES: "requires" > | < TRANSITIVE: "transitive" > @@ -508,6 +526,7 @@ TOKEN : | < PROVIDES: "provides" > | < WITH: "with" > } +*/ /* LITERALS */ @@ -1311,7 +1330,7 @@ ASTCompilationUnit CompilationUnit() : [ LOOKAHEAD( ( Annotation() )* "package" ) PackageDeclaration() ( EmptyStatement() )* ] ( ImportDeclaration() ( EmptyStatement() )* )* ( LOOKAHEAD(2) TypeDeclaration() ( EmptyStatement() )* )* - [ ModuleDeclaration() ( EmptyStatement() )* ] + [ LOOKAHEAD({isKeyword("open") || isKeyword("module") || getToken(1).kind == AT}) ModuleDeclaration() ( EmptyStatement() )* ] ( < "\u001a" > )? ( < "~[]" > )? @@ -1378,7 +1397,7 @@ void TypeDeclaration(): ( ClassOrInterfaceDeclaration(modifiers) | - EnumDeclaration(modifiers) + LOOKAHEAD({isKeyword("enum")}) EnumDeclaration(modifiers) | AnnotationTypeDeclaration(modifiers) ) @@ -1486,7 +1505,7 @@ void ClassOrInterfaceBodyDeclaration(): { LOOKAHEAD(["static"] "{" ) Initializer() | modifiers = Modifiers() ( LOOKAHEAD(3) ClassOrInterfaceDeclaration(modifiers) - | LOOKAHEAD(3) EnumDeclaration(modifiers) + | LOOKAHEAD({isKeyword("enum")}) EnumDeclaration(modifiers) | LOOKAHEAD( [ TypeParameters() ] "(" ) ConstructorDeclaration(modifiers) | LOOKAHEAD( Type() ( "[" "]" )* ( "," | "=" | ";" ) ) FieldDeclaration(modifiers) | LOOKAHEAD(2) MethodDeclaration(modifiers) @@ -2405,7 +2424,7 @@ void ModuleDeclaration(): checkForBadModuleUsage(); } { - ( Annotation() )* ["open" {jjtThis.setOpen(true);}] "module" + ( Annotation() )* [LOOKAHEAD({isKeyword("open")}) {jjtThis.setOpen(true);}] LOOKAHEAD({isKeyword("module")}) t= { s.append(t.image); } ( "." t= { s.append('.').append(t.image); } )* { jjtThis.setImage(s.toString()); } "{" (ModuleDirective())* "}" @@ -2414,14 +2433,14 @@ void ModuleDeclaration(): void ModuleDirective(): {} { - ( "requires" { jjtThis.setType(ASTModuleDirective.DirectiveType.REQUIRES); } - ("transitive" { jjtThis.setRequiresModifier(ASTModuleDirective.RequiresModifier.TRANSITIVE); } | + ( LOOKAHEAD({isKeyword("requires")}) { jjtThis.setType(ASTModuleDirective.DirectiveType.REQUIRES); } + (LOOKAHEAD({isKeyword("transitive")}) { jjtThis.setRequiresModifier(ASTModuleDirective.RequiresModifier.TRANSITIVE); } | "static" { jjtThis.setRequiresModifier(ASTModuleDirective.RequiresModifier.STATIC); } )? ModuleName() ";" ) - | ( "exports" { jjtThis.setType(ASTModuleDirective.DirectiveType.EXPORTS); } Name() [ "to" ModuleName() ("," ModuleName())*] ";" ) - | ( "opens" { jjtThis.setType(ASTModuleDirective.DirectiveType.OPENS); } Name() [ "to" ModuleName() ("," ModuleName())*] ";" ) - | ( "uses" { jjtThis.setType(ASTModuleDirective.DirectiveType.USES); } Name() ";" ) - | ( "provides" { jjtThis.setType(ASTModuleDirective.DirectiveType.PROVIDES); } Name() "with" Name() ("," Name() )* ";" ) + | ( LOOKAHEAD({isKeyword("exports")}) { jjtThis.setType(ASTModuleDirective.DirectiveType.EXPORTS); } Name() [ LOOKAHEAD({isKeyword("to")}) ModuleName() ("," ModuleName())*] ";" ) + | ( LOOKAHEAD({isKeyword("opens")}) { jjtThis.setType(ASTModuleDirective.DirectiveType.OPENS); } Name() [ LOOKAHEAD({isKeyword("to")}) ModuleName() ("," ModuleName())*] ";" ) + | ( LOOKAHEAD({isKeyword("uses")}) { jjtThis.setType(ASTModuleDirective.DirectiveType.USES); } Name() ";" ) + | ( LOOKAHEAD({isKeyword("provides")}) { jjtThis.setType(ASTModuleDirective.DirectiveType.PROVIDES); } Name() LOOKAHEAD({isKeyword("with")}) Name() ("," Name() )* ";" ) } // Similar to Name()