|
|
|
@ -503,6 +503,14 @@ public class JavaParser {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// make the top node a child of the second node on the stack
|
|
|
|
|
private void injectTop() {
|
|
|
|
|
AbstractJavaNode top = (AbstractJavaNode) jjtree.popNode();
|
|
|
|
|
AbstractJavaNode prev = (AbstractJavaNode) jjtree.peekNode();
|
|
|
|
|
prev.jjtAddChild(top, prev.jjtGetNumChildren());
|
|
|
|
|
prev.jjtSetLastToken(top.jjtGetLastToken());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
PARSER_END(JavaParser)
|
|
|
|
|
|
|
|
|
@ -2101,7 +2109,8 @@ void ClassOrInterfaceType() #void:
|
|
|
|
|
be sure that the last segment is a type name.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
( AmbiguousName() [ TypeArguments() ]) #ClassOrInterfaceType(>1)
|
|
|
|
|
AmbiguousName()
|
|
|
|
|
[ TypeArguments() #ClassOrInterfaceType(2) ]
|
|
|
|
|
{
|
|
|
|
|
// At this point the first ClassOrInterfaceType may be on top of the stack,
|
|
|
|
|
// but its image is not set. If it is on the stack we need to shrink the bounds
|
|
|
|
@ -2122,18 +2131,19 @@ void ClassOrInterfaceType() #void:
|
|
|
|
|
executes a loop. That scheme preserves the position of type arguments and annotations.
|
|
|
|
|
See #1150.
|
|
|
|
|
*/
|
|
|
|
|
( LOOKAHEAD(2)
|
|
|
|
|
(
|
|
|
|
|
"."
|
|
|
|
|
(TypeAnnotation())*
|
|
|
|
|
<IDENTIFIER> { jjtThis.setImage(getToken(0).getImage()); }
|
|
|
|
|
{jjtree.extendLeft();} // We'll enclose the previous segment
|
|
|
|
|
[ LOOKAHEAD( "<" ) TypeArguments() ]
|
|
|
|
|
) #ClassOrInterfaceType
|
|
|
|
|
)*
|
|
|
|
|
( LOOKAHEAD(2) "." ClassTypeSegment() )*
|
|
|
|
|
{ forceTypeContext(); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ClassTypeSegment() #ClassOrInterfaceType:
|
|
|
|
|
{}
|
|
|
|
|
{
|
|
|
|
|
TypeAnnotationList()
|
|
|
|
|
<IDENTIFIER>
|
|
|
|
|
// We'll enclose the previous segment
|
|
|
|
|
{ setLastTokenImage(jjtThis); jjtree.extendLeft();}
|
|
|
|
|
[ TypeArguments() ]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TypeArguments():
|
|
|
|
|
{}
|
|
|
|
@ -2478,31 +2488,57 @@ void PrimaryPrefix() #void :
|
|
|
|
|
Literal()
|
|
|
|
|
| "this" #ThisExpression
|
|
|
|
|
| "super" #SuperExpression
|
|
|
|
|
| UnqualifiedAllocationExpr()
|
|
|
|
|
| ("void" "." "class") #ClassLiteral
|
|
|
|
|
| (PrimitiveType() [ Dims() ] ) #ArrayType(>1)
|
|
|
|
|
(
|
|
|
|
|
MethodReference()
|
|
|
|
|
| "." "class" #ClassLiteral(1)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// todo we can probably simplify the lambda lookaheads
|
|
|
|
|
| LOOKAHEAD( <IDENTIFIER> "->", {!inSwitchLabel} ) LambdaExpression()
|
|
|
|
|
| LOOKAHEAD( "(" <IDENTIFIER> ( "," <IDENTIFIER> )* ")" "->" , {!inSwitchLabel} ) LambdaExpression()
|
|
|
|
|
| LOOKAHEAD( LambdaParameterList() "->", {!inSwitchLabel} ) LambdaExpression()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| ("(" Expression() ")") #ParenthesizedExpression
|
|
|
|
|
| UnqualifiedAllocationExpr()
|
|
|
|
|
| LOOKAHEAD( TypeOrVoid() "." "class" )
|
|
|
|
|
(TypeOrVoid() "." "class") #ClassLiteral
|
|
|
|
|
| LOOKAHEAD( ReferenceType() "::" [TypeArguments()] "new" )
|
|
|
|
|
ReferenceType() MethodReference()
|
|
|
|
|
//| LOOKAHEAD( TypeOrVoid() "." "class" )
|
|
|
|
|
// (TypeOrVoid() "." "class") #ClassLiteral
|
|
|
|
|
//| LOOKAHEAD( ReferenceType() "::" [TypeArguments()] "new" )
|
|
|
|
|
// ReferenceType() MethodReference()
|
|
|
|
|
// not a constructor reference, and is just a sequence of identifiers: could be an expression or a type
|
|
|
|
|
| LOOKAHEAD( Name() "::" )
|
|
|
|
|
AmbiguousName() MethodReference()
|
|
|
|
|
//| LOOKAHEAD( Name() "::" )
|
|
|
|
|
// AmbiguousName() MethodReference()
|
|
|
|
|
// we know it's not just a sequence of identifiers, so if
|
|
|
|
|
// ReferenceType matches, there are type parameters or annots,
|
|
|
|
|
// which means we shouldn't parse as an ambiguous name otherwise
|
|
|
|
|
// we choke on the type parameters
|
|
|
|
|
| LOOKAHEAD( ReferenceType() "::" )
|
|
|
|
|
ReferenceType() MethodReference()
|
|
|
|
|
| AmbiguousName() [ LOOKAHEAD("." "super" ".")
|
|
|
|
|
// The LHS of this or super is necessarily a type name, ie ambiguous
|
|
|
|
|
// Having this here instead of in PrimarySuffix makes the grammar more
|
|
|
|
|
// restrictive and also allows ExplicitConstructorInvocation to be parsed
|
|
|
|
|
"." "super" #SuperExpression(1) MemberSelector()
|
|
|
|
|
]
|
|
|
|
|
//| LOOKAHEAD( ReferenceType() "::" )
|
|
|
|
|
// ReferenceType() MethodReference()
|
|
|
|
|
| AmbiguousName() [ PrimaryStep2() ]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step right after the *first* ambiguous name if any
|
|
|
|
|
// then we have more options than a primary suffix,
|
|
|
|
|
// we can still expect the rest of a type name +
|
|
|
|
|
void PrimaryStep2() #void:
|
|
|
|
|
{}
|
|
|
|
|
{
|
|
|
|
|
{forceTypeContext();} TypeArguments() {injectTop();} ( "." ClassTypeSegment() )* MethodReference()
|
|
|
|
|
| MethodReference()
|
|
|
|
|
| ArgumentList() #MethodCall(2)
|
|
|
|
|
| "." (
|
|
|
|
|
{forceTypeContext();} "class" #ClassLiteral(1)
|
|
|
|
|
| "this" #ThisExpression(1)
|
|
|
|
|
| MemberSelector()
|
|
|
|
|
// we need to lookahead for the dot after "super", because in qualified
|
|
|
|
|
// super constructor invocation the "super" might be followed by a "("
|
|
|
|
|
| LOOKAHEAD("super" ".") "super" #SuperExpression(1) "." MemberSelector()
|
|
|
|
|
)
|
|
|
|
|
| LOOKAHEAD("@" | "[" "]") {forceTypeContext();} Dims() #ArrayType(2) (MethodReference() | "." "class" #ClassLiteral(1))
|
|
|
|
|
| "[" Expression() "]" #ArrayAccess(2)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -2516,38 +2552,39 @@ void PrimarySuffix() #void :
|
|
|
|
|
{}
|
|
|
|
|
{
|
|
|
|
|
MethodReference()
|
|
|
|
|
| ArgumentList() #MethodCall(2)
|
|
|
|
|
| ("[" Expression() "]") #ArrayAccess(2)
|
|
|
|
|
//| ArgumentList() #MethodCall(2)
|
|
|
|
|
| "[" Expression() "]" #ArrayAccess(2)
|
|
|
|
|
// all the following start with a "."
|
|
|
|
|
| LOOKAHEAD(2) "." "this" #ThisExpression(1)
|
|
|
|
|
| LOOKAHEAD(2) QualifiedAllocationExpr()
|
|
|
|
|
| LOOKAHEAD("." [TypeArguments()] <IDENTIFIER>) MemberSelector() // more complex method call patterns
|
|
|
|
|
//| LOOKAHEAD(2) "." "this" #ThisExpression(1)
|
|
|
|
|
| "." MemberSelector()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SuffixLAhead() #void:
|
|
|
|
|
{}
|
|
|
|
|
{
|
|
|
|
|
// not "super", otherwise runs into conflicts with ExplicitConstructorInvocation
|
|
|
|
|
"." ("new" | "this" | [ TypeArguments() ] <IDENTIFIER>)
|
|
|
|
|
"." ("new" | <IDENTIFIER> | "<")
|
|
|
|
|
| "::"
|
|
|
|
|
| "["
|
|
|
|
|
| "("
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MemberSelector() #void :
|
|
|
|
|
{}
|
|
|
|
|
{
|
|
|
|
|
QualifiedAllocationExpr()
|
|
|
|
|
// if there are type arguments, this is a method call
|
|
|
|
|
LOOKAHEAD(2) ("." {jjtree.extendLeft();} TypeArguments() <IDENTIFIER> {setLastTokenImage (jjtThis) ;} ArgumentList()) #MethodCall
|
|
|
|
|
| LOOKAHEAD(3) ("." {jjtree.extendLeft();} <IDENTIFIER> {setLastTokenImage(jjtThis);} ArgumentList()) #MethodCall
|
|
|
|
|
| ("." {jjtree.extendLeft();} <IDENTIFIER> {setLastTokenImage(jjtThis);}) #FieldAccess
|
|
|
|
|
| (TypeArguments() <IDENTIFIER> {setLastTokenImage(jjtThis);} ArgumentList()) #MethodCall(3)
|
|
|
|
|
| LOOKAHEAD(2) (<IDENTIFIER> {setLastTokenImage(jjtThis);} ArgumentList()) #MethodCall(2)
|
|
|
|
|
| (<IDENTIFIER> {setLastTokenImage(jjtThis);}) #FieldAccess(1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MethodReference(): // LHS is injected
|
|
|
|
|
{checkForBadMethodReferenceUsage();}
|
|
|
|
|
{
|
|
|
|
|
"::" {jjtree.extendLeft();}
|
|
|
|
|
[TypeArguments()] ( "new" | <IDENTIFIER>) {setLastTokenImage(jjtThis);}
|
|
|
|
|
[TypeArguments()]
|
|
|
|
|
( "new" | <IDENTIFIER> ) {setLastTokenImage(jjtThis);}
|
|
|
|
|
{/*empty*/}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LambdaExpression():
|
|
|
|
@ -2640,7 +2677,6 @@ void ArgumentList() :
|
|
|
|
|
void QualifiedAllocationExpr() #ConstructorCall:
|
|
|
|
|
{}
|
|
|
|
|
{
|
|
|
|
|
"."
|
|
|
|
|
"new"
|
|
|
|
|
{jjtree.extendLeft();}
|
|
|
|
|
[ TypeArguments() ]
|
|
|
|
|