parser grammar JavaParser; options {backtrack=true; memoize=true; tokenVocab=JavaLexer;} // starting point for parsing a java file /* The annotations are separated out to make parsing faster, but must be associated with a packageDeclaration or a typeDeclaration (and not an empty one). */ compilationUnit : annotations ( packageDeclaration importDeclaration* typeDeclaration* | classOrInterfaceDeclaration typeDeclaration* ) | packageDeclaration? importDeclaration* typeDeclaration* ; packageDeclaration : 'package' qualifiedName ';' ; importDeclaration : 'import' 'static'? qualifiedName ('.' '*')? ';' ; typeDeclaration : classOrInterfaceDeclaration | ';' ; classOrInterfaceDeclaration : classOrInterfaceModifiers (classDeclaration | interfaceDeclaration) ; classOrInterfaceModifiers : classOrInterfaceModifier* ; classOrInterfaceModifier : annotation // class or interface | 'public' // class or interface | 'protected' // class or interface | 'private' // class or interface | 'abstract' // class or interface | 'static' // class or interface | 'final' // class only -- does not apply to interfaces | 'strictfp' // class or interface ; modifiers : modifier* ; classDeclaration : normalClassDeclaration | enumDeclaration ; normalClassDeclaration : 'class' Identifier typeParameters? ('extends' type)? ('implements' typeList)? classBody ; typeParameters : '<' typeParameter (',' typeParameter)* '>' ; typeParameter : Identifier ('extends' typeBound)? ; typeBound : type ('&' type)* ; enumDeclaration : ENUM Identifier ('implements' typeList)? enumBody ; enumBody : '{' enumConstants? ','? enumBodyDeclarations? '}' ; enumConstants : enumConstant (',' enumConstant)* ; enumConstant : annotations? Identifier arguments? classBody? ; enumBodyDeclarations : ';' (classBodyDeclaration)* ; interfaceDeclaration : normalInterfaceDeclaration | annotationTypeDeclaration ; normalInterfaceDeclaration : 'interface' Identifier typeParameters? ('extends' typeList)? interfaceBody ; typeList : type (',' type)* ; classBody : '{' classBodyDeclaration* '}' ; interfaceBody : '{' interfaceBodyDeclaration* '}' ; classBodyDeclaration : ';' | 'static'? block | modifiers memberDecl ; memberDecl : genericMethodOrConstructorDecl | memberDeclaration | 'void' Identifier voidMethodDeclaratorRest | Identifier constructorDeclaratorRest | interfaceDeclaration | classDeclaration ; memberDeclaration : type (methodDeclaration | fieldDeclaration) ; genericMethodOrConstructorDecl : typeParameters genericMethodOrConstructorRest ; genericMethodOrConstructorRest : (type | 'void') Identifier methodDeclaratorRest | Identifier constructorDeclaratorRest ; methodDeclaration : Identifier methodDeclaratorRest ; fieldDeclaration : variableDeclarators ';' ; interfaceBodyDeclaration : modifiers interfaceMemberDecl | ';' ; interfaceMemberDecl : interfaceMethodOrFieldDecl | interfaceGenericMethodDecl | 'void' Identifier voidInterfaceMethodDeclaratorRest | interfaceDeclaration | classDeclaration ; interfaceMethodOrFieldDecl : type Identifier interfaceMethodOrFieldRest ; interfaceMethodOrFieldRest : constantDeclaratorsRest ';' | interfaceMethodDeclaratorRest ; methodDeclaratorRest : formalParameters ('[' ']')* ('throws' qualifiedNameList)? ( methodBody | ';' ) ; voidMethodDeclaratorRest : formalParameters ('throws' qualifiedNameList)? ( methodBody | ';' ) ; interfaceMethodDeclaratorRest : formalParameters ('[' ']')* ('throws' qualifiedNameList)? ';' ; interfaceGenericMethodDecl : typeParameters (type | 'void') Identifier interfaceMethodDeclaratorRest ; voidInterfaceMethodDeclaratorRest : formalParameters ('throws' qualifiedNameList)? ';' ; constructorDeclaratorRest : formalParameters ('throws' qualifiedNameList)? constructorBody ; constantDeclarator : Identifier constantDeclaratorRest ; variableDeclarators : variableDeclarator (',' variableDeclarator)* ; variableDeclarator : variableDeclaratorId ('=' variableInitializer)? ; constantDeclaratorsRest : constantDeclaratorRest (',' constantDeclarator)* ; constantDeclaratorRest : ('[' ']')* '=' variableInitializer ; variableDeclaratorId : Identifier ('[' ']')* ; variableInitializer : arrayInitializer | expression ; arrayInitializer : '{' (variableInitializer (',' variableInitializer)* (',')? )? '}' ; modifier : annotation | 'public' | 'protected' | 'private' | 'static' | 'abstract' | 'final' | 'native' | 'synchronized' | 'transient' | 'volatile' | 'strictfp' ; packageOrTypeName : qualifiedName ; enumConstantName : Identifier ; typeName : qualifiedName ; type : classOrInterfaceType ('[' ']')* | primitiveType ('[' ']')* ; classOrInterfaceType : Identifier typeArguments? ('.' Identifier typeArguments? )* ; primitiveType : 'boolean' | 'char' | 'byte' | 'short' | 'int' | 'long' | 'float' | 'double' ; variableModifier : 'final' | annotation ; typeArguments : '<' typeArgument (',' typeArgument)* '>' ; typeArgument : type | '?' (('extends' | 'super') type)? ; qualifiedNameList : qualifiedName (',' qualifiedName)* ; formalParameters : '(' formalParameterDecls? ')' ; formalParameterDecls : variableModifiers type formalParameterDeclsRest ; formalParameterDeclsRest : variableDeclaratorId (',' formalParameterDecls)? | '...' variableDeclaratorId ; methodBody : block ; constructorBody : '{' explicitConstructorInvocation? blockStatement* '}' ; explicitConstructorInvocation : nonWildcardTypeArguments? ('this' | 'super') arguments ';' | primary '.' nonWildcardTypeArguments? 'super' arguments ';' ; qualifiedName : Identifier ('.' Identifier)* ; literal : integerLiteral | FloatingPointLiteral | CharacterLiteral | StringLiteral | booleanLiteral | 'null' ; integerLiteral : HexLiteral | OctalLiteral | DecimalLiteral ; booleanLiteral : 'true' | 'false' ; // ANNOTATIONS annotations : annotation+ ; annotation : '@' annotationName ( '(' ( elementValuePairs | elementValue )? ')' )? ; annotationName : Identifier ('.' Identifier)* ; elementValuePairs : elementValuePair (',' elementValuePair)* ; elementValuePair : Identifier '=' elementValue ; elementValue : conditionalExpression | annotation | elementValueArrayInitializer ; elementValueArrayInitializer : '{' (elementValue (',' elementValue)*)? (',')? '}' ; annotationTypeDeclaration : '@' 'interface' Identifier annotationTypeBody ; annotationTypeBody : '{' (annotationTypeElementDeclaration)* '}' ; annotationTypeElementDeclaration : modifiers annotationTypeElementRest ; annotationTypeElementRest : type annotationMethodOrConstantRest ';' | normalClassDeclaration ';'? | normalInterfaceDeclaration ';'? | enumDeclaration ';'? | annotationTypeDeclaration ';'? ; annotationMethodOrConstantRest : annotationMethodRest | annotationConstantRest ; annotationMethodRest : Identifier '(' ')' defaultValue? ; annotationConstantRest : variableDeclarators ; defaultValue : 'default' elementValue ; // STATEMENTS / BLOCKS block : '{' blockStatement* '}' ; blockStatement : localVariableDeclarationStatement | classOrInterfaceDeclaration | statement ; localVariableDeclarationStatement : localVariableDeclaration ';' ; localVariableDeclaration : variableModifiers type variableDeclarators ; variableModifiers : variableModifier* ; statement : block | ASSERT expression (':' expression)? ';' | 'if' parExpression statement (options {k=1;}:'else' statement)? | 'for' '(' forControl ')' statement | 'while' parExpression statement | 'do' statement 'while' parExpression ';' | 'try' block ( catches 'finally' block | catches | 'finally' block ) | 'switch' parExpression '{' switchBlockStatementGroups '}' | 'synchronized' parExpression block | 'return' expression? ';' | 'throw' expression ';' | 'break' Identifier? ';' | 'continue' Identifier? ';' | ';' | statementExpression ';' | Identifier ':' statement ; catches : catchClause (catchClause)* ; catchClause : 'catch' '(' formalParameter ')' block ; formalParameter : variableModifiers type variableDeclaratorId ; switchBlockStatementGroups : (switchBlockStatementGroup)* ; /* The change here (switchLabel -> switchLabel+) technically makes this grammar ambiguous; but with appropriately greedy parsing it yields the most appropriate AST, one in which each group, except possibly the last one, has labels and statements. */ switchBlockStatementGroup : switchLabel+ blockStatement* ; switchLabel : 'case' constantExpression ':' | 'case' enumConstantName ':' | 'default' ':' ; forControl options {k=3;} // be efficient for common case: for (ID ID : ID) ... : enhancedForControl | forInit? ';' expression? ';' forUpdate? ; forInit : localVariableDeclaration | expressionList ; enhancedForControl : variableModifiers type Identifier ':' expression ; forUpdate : expressionList ; // EXPRESSIONS parExpression : '(' expression ')' ; expressionList : expression (',' expression)* ; statementExpression : expression ; constantExpression : expression ; expression : conditionalExpression (assignmentOperator expression)? ; assignmentOperator : '=' | '+=' | '-=' | '*=' | '/=' | '&=' | '|=' | '^=' | '%=' | '<' '<' '=' | '>' '>' '>' '=' | '>' '>' '=' /* | ('<' '<' '=')=> t1='<' t2='<' t3='=' { $t1.getLine() == $t2.getLine() && $t1.getCharPositionInLine() + 1 == $t2.getCharPositionInLine() && $t2.getLine() == $t3.getLine() && $t2.getCharPositionInLine() + 1 == $t3.getCharPositionInLine() }? | ('>' '>' '>' '=')=> t1='>' t2='>' t3='>' t4='=' { $t1.getLine() == $t2.getLine() && $t1.getCharPositionInLine() + 1 == $t2.getCharPositionInLine() && $t2.getLine() == $t3.getLine() && $t2.getCharPositionInLine() + 1 == $t3.getCharPositionInLine() && $t3.getLine() == $t4.getLine() && $t3.getCharPositionInLine() + 1 == $t4.getCharPositionInLine() }? | ('>' '>' '=')=> t1='>' t2='>' t3='=' { $t1.getLine() == $t2.getLine() && $t1.getCharPositionInLine() + 1 == $t2.getCharPositionInLine() && $t2.getLine() == $t3.getLine() && $t2.getCharPositionInLine() + 1 == $t3.getCharPositionInLine() }? */ ; conditionalExpression : conditionalOrExpression ( '?' conditionalExpression ':' conditionalExpression )? ; conditionalOrExpression : conditionalAndExpression ( '||' conditionalAndExpression )* ; conditionalAndExpression : inclusiveOrExpression ( '&&' inclusiveOrExpression )* ; inclusiveOrExpression : exclusiveOrExpression ( '|' exclusiveOrExpression )* ; exclusiveOrExpression : andExpression ( '^' andExpression )* ; andExpression : equalityExpression ( '&' equalityExpression )* ; equalityExpression : instanceOfExpression ( ('==' | '!=') instanceOfExpression )* ; instanceOfExpression : relationalExpression ('instanceof' type)? ; relationalExpression : shiftExpression ( relationalOp shiftExpression )* ; relationalOp : '<' '=' | '>' '=' | '<' | '>' ; /* relationalOp : ('<' '=')=> t1='<' t2='=' { $t1.getLine() == $t2.getLine() && $t1.getCharPositionInLine() + 1 == $t2.getCharPositionInLine() }? | ('>' '=')=> t1='>' t2='=' { $t1.getLine() == $t2.getLine() && $t1.getCharPositionInLine() + 1 == $t2.getCharPositionInLine() }? | '<' | '>' ; */ shiftExpression : additiveExpression ( shiftOp additiveExpression )* ; shiftOp : '<' '<' | '>' '>' '>' | '>' '>' ; /* shiftOp : ('<' '<')=> t1='<' t2='<' { $t1.getLine() == $t2.getLine() && $t1.getCharPositionInLine() + 1 == $t2.getCharPositionInLine() }? | ('>' '>' '>')=> t1='>' t2='>' t3='>' { $t1.getLine() == $t2.getLine() && $t1.getCharPositionInLine() + 1 == $t2.getCharPositionInLine() && $t2.getLine() == $t3.getLine() && $t2.getCharPositionInLine() + 1 == $t3.getCharPositionInLine() }? | ('>' '>')=> t1='>' t2='>' { $t1.getLine() == $t2.getLine() && $t1.getCharPositionInLine() + 1 == $t2.getCharPositionInLine() }? ; */ additiveExpression : multiplicativeExpression ( ('+' | '-') multiplicativeExpression )* ; multiplicativeExpression : unaryExpression ( ( '*' | '/' | '%' ) unaryExpression )* ; unaryExpression : '+' unaryExpression | '-' unaryExpression | '++' unaryExpression | '--' unaryExpression | unaryExpressionNotPlusMinus ; unaryExpressionNotPlusMinus : '~' unaryExpression | '!' unaryExpression | castExpression | primary selector* ('++'|'--')? ; castExpression : '(' primitiveType ')' unaryExpression | '(' (type | expression) ')' unaryExpressionNotPlusMinus ; primary : parExpression | 'this' ('.' Identifier)* identifierSuffix? | 'super' superSuffix | literal | 'new' creator | Identifier ('.' Identifier)* identifierSuffix? | primitiveType ('[' ']')* '.' 'class' | 'void' '.' 'class' ; identifierSuffix : ('[' ']')+ '.' 'class' | ('[' expression ']')+ // can also be matched by selector, but do here | arguments | '.' 'class' | '.' explicitGenericInvocation | '.' 'this' | '.' 'super' arguments | '.' 'new' innerCreator ; creator : nonWildcardTypeArguments createdName classCreatorRest | createdName (arrayCreatorRest | classCreatorRest) ; createdName : classOrInterfaceType | primitiveType ; innerCreator : nonWildcardTypeArguments? Identifier classCreatorRest ; arrayCreatorRest : '[' ( ']' ('[' ']')* arrayInitializer | expression ']' ('[' expression ']')* ('[' ']')* ) ; classCreatorRest : arguments classBody? ; explicitGenericInvocation : nonWildcardTypeArguments Identifier arguments ; nonWildcardTypeArguments : '<' typeList '>' ; selector : '.' Identifier arguments? | '.' 'this' | '.' 'super' superSuffix | '.' 'new' innerCreator | '[' expression ']' ; superSuffix : arguments | '.' Identifier arguments? ; arguments : '(' expressionList? ')' ;