--- a/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Thu Nov 24 13:38:40 2011 +0000
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/JavacParser.java Mon Nov 28 15:56:42 2011 +0000
@@ -110,6 +110,8 @@
this.allowDiamond = source.allowDiamond();
this.allowMulticatch = source.allowMulticatch();
this.allowStringFolding = fac.options.getBoolean("allowStringFolding", true);
+ this.allowLambda = source.allowLambda() &&
+ fac.options.isSet("allowLambda");
this.keepDocComments = keepDocComments;
docComments = keepDocComments ? new HashMap<JCTree,String>() : null;
this.keepLineMap = keepLineMap;
@@ -166,6 +168,10 @@
*/
boolean allowStringFolding;
+ /** Switch: should we recognize lambda expressions?
+ */
+ boolean allowLambda;
+
/** Switch: should we keep docComments?
*/
boolean keepDocComments;
@@ -203,6 +209,30 @@
token = S.token();
}
+ protected boolean peekToken(TokenKind tk) {
+ return S.token(1).kind == tk;
+ }
+
+ protected boolean peekToken(TokenKind tk1, TokenKind tk2) {
+ return S.token(1).kind == tk1 &&
+ S.token(2).kind == tk2;
+ }
+
+ protected boolean peekToken(TokenKind tk1, TokenKind tk2, TokenKind tk3) {
+ return S.token(1).kind == tk1 &&
+ S.token(2).kind == tk2 &&
+ S.token(3).kind == tk3;
+ }
+
+ protected boolean peekToken(TokenKind... kinds) {
+ for (int lookahead = 0 ; lookahead < kinds.length ; lookahead++) {
+ if (S.token(lookahead + 1).kind != kinds[lookahead]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
/* ---------- error recovery -------------- */
private JCErroneous errorTree;
@@ -849,6 +879,8 @@
* | [TypeArguments] THIS [Arguments]
* | [TypeArguments] SUPER SuperSuffix
* | NEW [TypeArguments] Creator
+ * | "(" Arguments ")" "->" ( Expression | Block )
+ * | Ident "->" ( Expression | Block )
* | Ident { "." Ident }
* [ "[" ( "]" BracketsOpt "." CLASS | Expression "]" )
* | Arguments
@@ -897,48 +929,75 @@
break;
case LPAREN:
if (typeArgs == null && (mode & EXPR) != 0) {
- nextToken();
- mode = EXPR | TYPE | NOPARAMS;
- t = term3();
- if ((mode & TYPE) != 0 && token.kind == LT) {
- // Could be a cast to a parameterized type
- JCTree.Tag op = JCTree.Tag.LT;
- int pos1 = token.pos;
+ if (peekToken(FINAL) ||
+ peekToken(RPAREN) ||
+ peekToken(IDENTIFIER, COMMA) ||
+ peekToken(IDENTIFIER, RPAREN, ARROW)) {
+ //implicit n-ary lambda
+ t = lambdaExpressionOrStatement(true, peekToken(FINAL), pos);
+ break;
+ } else {
nextToken();
- mode &= (EXPR | TYPE);
- mode |= TYPEARG;
- JCExpression t1 = term3();
- if ((mode & TYPE) != 0 &&
- (token.kind == COMMA || token.kind == GT)) {
- mode = TYPE;
- ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
- args.append(t1);
- while (token.kind == COMMA) {
+ mode = EXPR | TYPE | NOPARAMS;
+ t = term3();
+ if ((mode & TYPE) != 0 && token.kind == LT) {
+ // Could be a cast to a parameterized type
+ JCTree.Tag op = JCTree.Tag.LT;
+ int pos1 = token.pos;
+ nextToken();
+ mode &= (EXPR | TYPE);
+ mode |= TYPEARG;
+ JCExpression t1 = term3();
+ if ((mode & TYPE) != 0 &&
+ (token.kind == COMMA || token.kind == GT)) {
+ mode = TYPE;
+ ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
+ args.append(t1);
+ while (token.kind == COMMA) {
+ nextToken();
+ args.append(typeArgument());
+ }
+ accept(GT);
+ t = toP(F.at(pos1).TypeApply(t, args.toList()));
+ checkGenerics();
+ mode = EXPR | TYPE; //could be a lambda or a method ref or a cast to a type
+ t = term3Rest(t, typeArgs);
+ if (token.kind == IDENTIFIER || token.kind == ELLIPSIS) {
+ //explicit lambda (w/ generic type)
+ mode = EXPR;
+ JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
+ if (token.kind == ELLIPSIS) {
+ mods.flags = Flags.VARARGS;
+ t = to(F.at(token.pos).TypeArray(t));
+ nextToken();
+ }
+ t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
+ break;
+ }
+ } else {
+ Assert.check((mode & EXPR) != 0);
+ mode = EXPR;
+ JCExpression e = term2Rest(t1, TreeInfo.shiftPrec);
+ t = F.at(pos1).Binary(op, t, e);
+ t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
+ }
+ } else if ((mode & TYPE) != 0 &&
+ (token.kind == IDENTIFIER || token.kind == ELLIPSIS)) {
+ //explicit lambda (w/ non-generic type)
+ mode = EXPR;
+ JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
+ if (token.kind == ELLIPSIS) {
+ mods.flags = Flags.VARARGS;
+ t = to(F.at(token.pos).TypeArray(t));
nextToken();
- args.append(typeArgument());
}
- accept(GT);
- t = toP(F.at(pos1).TypeApply(t, args.toList()));
- checkGenerics();
- while (token.kind == DOT) {
- nextToken();
- mode = TYPE;
- t = toP(F.at(token.pos).Select(t, ident()));
- t = typeArgumentsOpt(t);
- }
- t = bracketsOpt(toP(t));
- } else if ((mode & EXPR) != 0) {
- mode = EXPR;
- JCExpression e = term2Rest(t1, TreeInfo.shiftPrec);
- t = F.at(pos1).Binary(op, t, e);
+ t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
+ break;
+ } else {
t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
- } else {
- accept(GT);
}
}
- else {
- t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
- }
+
accept(RPAREN);
lastmode = mode;
mode = EXPR;
@@ -953,14 +1012,16 @@
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 NEW: case IDENTIFIER: case ASSERT: case ENUM:
case BYTE: case SHORT: case CHAR: case INT:
case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
JCExpression t1 = term3();
return F.at(pos).TypeCast(t, t1);
}
}
- } else return illegal();
+ } else {
+ return illegal();
+ }
t = toP(F.at(pos).Parens(t));
break;
case THIS:
@@ -1003,75 +1064,79 @@
break;
case IDENTIFIER: case ASSERT: case ENUM:
if (typeArgs != null) return illegal();
- t = toP(F.at(token.pos).Ident(ident()));
- loop: while (true) {
- pos = token.pos;
- switch (token.kind) {
- case LBRACKET:
- nextToken();
- if (token.kind == RBRACKET) {
+ if ((mode & EXPR) != 0 && peekToken(ARROW)) {
+ t = lambdaExpressionOrStatement(false, false, pos);
+ } else {
+ t = toP(F.at(token.pos).Ident(ident()));
+ loop: while (true) {
+ pos = token.pos;
+ switch (token.kind) {
+ case LBRACKET:
nextToken();
- t = bracketsOpt(t);
- t = toP(F.at(pos).TypeArray(t));
- t = bracketsSuffix(t);
- } else {
+ if (token.kind == RBRACKET) {
+ nextToken();
+ t = bracketsOpt(t);
+ t = toP(F.at(pos).TypeArray(t));
+ t = bracketsSuffix(t);
+ } else {
+ if ((mode & EXPR) != 0) {
+ mode = EXPR;
+ JCExpression t1 = term();
+ t = to(F.at(pos).Indexed(t, t1));
+ }
+ accept(RBRACKET);
+ }
+ break loop;
+ case LPAREN:
if ((mode & EXPR) != 0) {
mode = EXPR;
- JCExpression t1 = term();
- t = to(F.at(pos).Indexed(t, t1));
+ t = arguments(typeArgs, t);
+ typeArgs = null;
}
- accept(RBRACKET);
- }
- break loop;
- case LPAREN:
- if ((mode & EXPR) != 0) {
- mode = EXPR;
- t = arguments(typeArgs, t);
- typeArgs = null;
+ break loop;
+ case DOT:
+ nextToken();
+ int oldmode = mode;
+ mode &= ~NOPARAMS;
+ typeArgs = typeArgumentsOpt(EXPR);
+ mode = oldmode;
+ if ((mode & EXPR) != 0) {
+ switch (token.kind) {
+ case CLASS:
+ if (typeArgs != null) return illegal();
+ mode = EXPR;
+ t = to(F.at(pos).Select(t, names._class));
+ nextToken();
+ break loop;
+ case THIS:
+ if (typeArgs != null) return illegal();
+ mode = EXPR;
+ t = to(F.at(pos).Select(t, names._this));
+ nextToken();
+ break loop;
+ case SUPER:
+ mode = EXPR;
+ t = to(F.at(pos).Select(t, names._super));
+ t = superSuffix(typeArgs, t);
+ typeArgs = null;
+ break loop;
+ case NEW:
+ if (typeArgs != null) return illegal();
+ mode = EXPR;
+ int pos1 = token.pos;
+ nextToken();
+ if (token.kind == LT) typeArgs = typeArguments(false);
+ t = innerCreator(pos1, typeArgs, t);
+ typeArgs = null;
+ break loop;
+ }
+ }
+ // typeArgs saved for next loop iteration.
+ t = toP(F.at(pos).Select(t, ident()));
+ break;
+ default:
+ break loop;
}
- break loop;
- case DOT:
- nextToken();
- int oldmode = mode;
- mode &= ~NOPARAMS;
- typeArgs = typeArgumentsOpt(EXPR);
- mode = oldmode;
- if ((mode & EXPR) != 0) {
- switch (token.kind) {
- case CLASS:
- if (typeArgs != null) return illegal();
- mode = EXPR;
- t = to(F.at(pos).Select(t, names._class));
- nextToken();
- break loop;
- case THIS:
- if (typeArgs != null) return illegal();
- mode = EXPR;
- t = to(F.at(pos).Select(t, names._this));
- nextToken();
- break loop;
- case SUPER:
- mode = EXPR;
- t = to(F.at(pos).Select(t, names._super));
- t = superSuffix(typeArgs, t);
- typeArgs = null;
- break loop;
- case NEW:
- if (typeArgs != null) return illegal();
- mode = EXPR;
- int pos1 = token.pos;
- nextToken();
- if (token.kind == LT) typeArgs = typeArguments(false);
- t = innerCreator(pos1, typeArgs, t);
- typeArgs = null;
- break loop;
- }
- }
- // typeArgs saved for next loop iteration.
- t = toP(F.at(pos).Select(t, ident()));
- break;
- default:
- break loop;
}
}
if (typeArgs != null) illegal();
@@ -1105,6 +1170,10 @@
default:
return illegal();
}
+ return term3Rest(t, typeArgs);
+ }
+
+ JCExpression term3Rest(JCExpression t, List<JCExpression> typeArgs) {
if (typeArgs != null) illegal();
while (true) {
int pos1 = token.pos;
@@ -1162,6 +1231,50 @@
return toP(t);
}
+ JCExpression lambdaExpressionOrStatement(JCVariableDecl firstParam, int pos) {
+ ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
+ params.append(firstParam);
+ JCVariableDecl lastParam = firstParam;
+ while ((lastParam.mods.flags & Flags.VARARGS) == 0 && token.kind == COMMA) {
+ nextToken();
+ params.append(lastParam = formalParameter());
+ }
+ accept(RPAREN);
+ return lambdaExpressionOrStatementRest(params.toList(), pos);
+ }
+
+ JCExpression lambdaExpressionOrStatement(boolean hasParens, boolean explicitParams, int pos) {
+ List<JCVariableDecl> params = explicitParams ?
+ formalParameters() :
+ implicitParameters(hasParens);
+
+ return lambdaExpressionOrStatementRest(params, pos);
+ }
+
+ JCExpression lambdaExpressionOrStatementRest(List<JCVariableDecl> args, int pos) {
+ if (token.kind != ARROW) {
+ //better error recovery
+ return F.at(pos).Erroneous(args);
+ }
+
+ checkLambda();
+ accept(ARROW);
+
+ return token.kind == LBRACE ?
+ lambdaStatement(args, pos, pos) :
+ lambdaExpression(args, pos);
+ }
+
+ JCExpression lambdaStatement(List<JCVariableDecl> args, int pos, int pos2) {
+ JCBlock block = block(pos2, 0);
+ return toP(F.at(pos).Lambda(args, block));
+ }
+
+ JCExpression lambdaExpression(List<JCVariableDecl> args, int pos) {
+ JCTree expr = parseExpression();
+ return toP(F.at(pos).Lambda(args, expr));
+ }
+
/** SuperSuffix = Arguments | "." [TypeArguments] Ident [Arguments]
*/
JCExpression superSuffix(List<JCExpression> typeArgs, JCExpression t) {
@@ -2779,6 +2892,24 @@
return params.toList();
}
+ List<JCVariableDecl> implicitParameters(boolean hasParens) {
+ if (hasParens) {
+ accept(LPAREN);
+ }
+ ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
+ if (token.kind != RPAREN && token.kind != ARROW) {
+ params.append(implicitParameter());
+ while (token.kind == COMMA) {
+ nextToken();
+ params.append(implicitParameter());
+ }
+ }
+ if (hasParens) {
+ accept(RPAREN);
+ }
+ return params.toList();
+ }
+
JCModifiers optFinal(long flags) {
JCModifiers mods = modifiersOpt();
checkNoMods(mods.flags & ~(Flags.FINAL | Flags.DEPRECATED));
@@ -2801,6 +2932,11 @@
return variableDeclaratorId(mods, type);
}
+ protected JCVariableDecl implicitParameter() {
+ JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
+ return variableDeclaratorId(mods, null);
+ }
+
/* ---------- auxiliary methods -------------- */
void error(int pos, String key, Object ... args) {
@@ -3024,6 +3160,12 @@
allowTWR = true;
}
}
+ void checkLambda() {
+ if (!allowLambda) {
+ log.error(token.pos, "lambda.not.supported.in.source", source.name);
+ allowLambda = true;
+ }
+ }
/*
* a functional source tree and end position mappings