@SuppressWarnings("fallthrough")
ParensResult analyzeParens() {
int depth = 0;
boolean type = false;
outer: for (int lookahead = 0 ; ; lookahead++) {
TokenKind tk = S.token(lookahead).kind;
switch (tk) {
case COMMA:
type = true;
case EXTENDS: case SUPER: case DOT: case AMP:
//skip
break;
case QUES:
if (peekToken(lookahead, EXTENDS) ||
peekToken(lookahead, SUPER)) {
//wildcards
type = true;
}
break;
case BYTE: case SHORT: case INT: case LONG: case FLOAT:
case DOUBLE: case BOOLEAN: case CHAR:
if (peekToken(lookahead, RPAREN)) {
//Type, ')' -> cast
return ParensResult.CAST;
} else if (peekToken(lookahead, LAX_IDENTIFIER)) {
//Type, Identifier/'_'/'assert'/'enum' -> explicit lambda
return ParensResult.EXPLICIT_LAMBDA;
}
break;
case LPAREN:
if (lookahead != 0) {
// '(' in a non-starting position -> parens
return ParensResult.PARENS;
} else if (peekToken(lookahead, RPAREN)) {
// '(', ')' -> explicit lambda
return ParensResult.EXPLICIT_LAMBDA;
}
break;
case RPAREN:
// if we have seen something that looks like a type,
// then it's a cast expression
if (type) return ParensResult.CAST;
// otherwise, disambiguate cast vs. parenthesized expression
// based on subsequent token.
switch (S.token(lookahead + 1).kind) {
/*case PLUSPLUS: case SUBSUB: */
case BANG: case TILDE:
case LPAREN: case THIS: case SUPER:
case INTLITERAL: case LONGLITERAL: case FLOATLITERAL:
case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL:
case TRUE: case FALSE: case NULL:
case NEW: case IDENTIFIER: case ASSERT: case ENUM: case UNDERSCORE:
case BYTE: case SHORT: case CHAR: case INT:
case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
return ParensResult.CAST;
default:
return ParensResult.PARENS;
}
case UNDERSCORE:
case ASSERT:
case ENUM:
case IDENTIFIER:
if (peekToken(lookahead, LAX_IDENTIFIER)) {
// Identifier, Identifier/'_'/'assert'/'enum' -> explicit lambda
return ParensResult.EXPLICIT_LAMBDA;
} else if (peekToken(lookahead, RPAREN, ARROW)) {
// Identifier, ')' '->' -> implicit lambda
return ParensResult.IMPLICIT_LAMBDA;
}
type = false;
break;
case FINAL:
case ELLIPSIS:
//those can only appear in explicit lambdas
return ParensResult.EXPLICIT_LAMBDA;
case MONKEYS_AT:
type = true;
lookahead += 1; //skip '@'
while (peekToken(lookahead, DOT)) {
lookahead += 2;
}
if (peekToken(lookahead, LPAREN)) {
lookahead++;
//skip annotation values
int nesting = 0;
for (; ; lookahead++) {
TokenKind tk2 = S.token(lookahead).kind;
switch (tk2) {
case EOF:
return ParensResult.PARENS;
case LPAREN:
nesting++;