7115050: Add parser support for lambda expressions

Mon, 28 Nov 2011 15:56:42 +0000

author
mcimadamore
date
Mon, 28 Nov 2011 15:56:42 +0000
changeset 1144
9448fe783fd2
parent 1143
ec59a2ce9114
child 1145
3343b22e2761

7115050: Add parser support for lambda expressions
Summary: Add support for parsing lambda expressions to JavacParser
Reviewed-by: jjg

src/share/classes/com/sun/tools/javac/code/Source.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/comp/Attr.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/parser/JavacParser.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/parser/Lexer.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/parser/Scanner.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/parser/Tokens.java file | annotate | diff | comparison | revisions
src/share/classes/com/sun/tools/javac/resources/compiler.properties file | annotate | diff | comparison | revisions
test/tools/javac/diags/examples/CatchWithoutTry.java file | annotate | diff | comparison | revisions
test/tools/javac/diags/examples/LambdaNotSupported.java file | annotate | diff | comparison | revisions
test/tools/javac/diags/examples/NotAStatement.java file | annotate | diff | comparison | revisions
test/tools/javac/generics/rare/6665356/T6665356.out file | annotate | diff | comparison | revisions
test/tools/javac/lambda/LambdaParserTest.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/classes/com/sun/tools/javac/code/Source.java	Thu Nov 24 13:38:40 2011 +0000
     1.2 +++ b/src/share/classes/com/sun/tools/javac/code/Source.java	Mon Nov 28 15:56:42 2011 +0000
     1.3 @@ -194,6 +194,9 @@
     1.4      public boolean allowObjectToPrimitiveCast() {
     1.5          return compareTo(JDK1_7) >= 0;
     1.6      }
     1.7 +    public boolean allowLambda() {
     1.8 +        return compareTo(JDK1_8) >= 0;
     1.9 +    }
    1.10      public static SourceVersion toSourceVersion(Source source) {
    1.11          switch(source) {
    1.12          case JDK1_2:
     2.1 --- a/src/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Nov 24 13:38:40 2011 +0000
     2.2 +++ b/src/share/classes/com/sun/tools/javac/comp/Attr.java	Mon Nov 28 15:56:42 2011 +0000
     2.3 @@ -1975,6 +1975,11 @@
     2.4          result = check(tree, owntype, VAL, pkind, pt);
     2.5      }
     2.6  
     2.7 +    @Override
     2.8 +    public void visitLambda(JCLambda that) {
     2.9 +        throw new UnsupportedOperationException("Lambda expression not supported yet");
    2.10 +    }
    2.11 +
    2.12      public void visitParens(JCParens tree) {
    2.13          Type owntype = attribTree(tree.expr, env, pkind, pt);
    2.14          result = check(tree, owntype, pkind, pkind, pt);
     3.1 --- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Thu Nov 24 13:38:40 2011 +0000
     3.2 +++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Mon Nov 28 15:56:42 2011 +0000
     3.3 @@ -110,6 +110,8 @@
     3.4          this.allowDiamond = source.allowDiamond();
     3.5          this.allowMulticatch = source.allowMulticatch();
     3.6          this.allowStringFolding = fac.options.getBoolean("allowStringFolding", true);
     3.7 +        this.allowLambda = source.allowLambda() &&
     3.8 +                fac.options.isSet("allowLambda");
     3.9          this.keepDocComments = keepDocComments;
    3.10          docComments = keepDocComments ? new HashMap<JCTree,String>() : null;
    3.11          this.keepLineMap = keepLineMap;
    3.12 @@ -166,6 +168,10 @@
    3.13       */
    3.14      boolean allowStringFolding;
    3.15  
    3.16 +    /** Switch: should we recognize lambda expressions?
    3.17 +     */
    3.18 +    boolean allowLambda;
    3.19 +
    3.20      /** Switch: should we keep docComments?
    3.21       */
    3.22      boolean keepDocComments;
    3.23 @@ -203,6 +209,30 @@
    3.24          token = S.token();
    3.25      }
    3.26  
    3.27 +    protected boolean peekToken(TokenKind tk) {
    3.28 +        return S.token(1).kind == tk;
    3.29 +    }
    3.30 +
    3.31 +    protected boolean peekToken(TokenKind tk1, TokenKind tk2) {
    3.32 +        return S.token(1).kind == tk1 &&
    3.33 +                S.token(2).kind == tk2;
    3.34 +    }
    3.35 +
    3.36 +    protected boolean peekToken(TokenKind tk1, TokenKind tk2, TokenKind tk3) {
    3.37 +        return S.token(1).kind == tk1 &&
    3.38 +                S.token(2).kind == tk2 &&
    3.39 +                S.token(3).kind == tk3;
    3.40 +    }
    3.41 +
    3.42 +    protected boolean peekToken(TokenKind... kinds) {
    3.43 +        for (int lookahead = 0 ; lookahead < kinds.length ; lookahead++) {
    3.44 +            if (S.token(lookahead + 1).kind != kinds[lookahead]) {
    3.45 +                return false;
    3.46 +            }
    3.47 +        }
    3.48 +        return true;
    3.49 +    }
    3.50 +
    3.51      /* ---------- error recovery -------------- */
    3.52  
    3.53      private JCErroneous errorTree;
    3.54 @@ -849,6 +879,8 @@
    3.55       *                 | [TypeArguments] THIS [Arguments]
    3.56       *                 | [TypeArguments] SUPER SuperSuffix
    3.57       *                 | NEW [TypeArguments] Creator
    3.58 +     *                 | "(" Arguments ")" "->" ( Expression | Block )
    3.59 +     *                 | Ident "->" ( Expression | Block )
    3.60       *                 | Ident { "." Ident }
    3.61       *                   [ "[" ( "]" BracketsOpt "." CLASS | Expression "]" )
    3.62       *                   | Arguments
    3.63 @@ -897,48 +929,75 @@
    3.64              break;
    3.65          case LPAREN:
    3.66              if (typeArgs == null && (mode & EXPR) != 0) {
    3.67 -                nextToken();
    3.68 -                mode = EXPR | TYPE | NOPARAMS;
    3.69 -                t = term3();
    3.70 -                if ((mode & TYPE) != 0 && token.kind == LT) {
    3.71 -                    // Could be a cast to a parameterized type
    3.72 -                    JCTree.Tag op = JCTree.Tag.LT;
    3.73 -                    int pos1 = token.pos;
    3.74 +                if (peekToken(FINAL) ||
    3.75 +                        peekToken(RPAREN) ||
    3.76 +                        peekToken(IDENTIFIER, COMMA) ||
    3.77 +                        peekToken(IDENTIFIER, RPAREN, ARROW)) {
    3.78 +                    //implicit n-ary lambda
    3.79 +                    t = lambdaExpressionOrStatement(true, peekToken(FINAL), pos);
    3.80 +                    break;
    3.81 +                } else {
    3.82                      nextToken();
    3.83 -                    mode &= (EXPR | TYPE);
    3.84 -                    mode |= TYPEARG;
    3.85 -                    JCExpression t1 = term3();
    3.86 -                    if ((mode & TYPE) != 0 &&
    3.87 -                        (token.kind == COMMA || token.kind == GT)) {
    3.88 -                        mode = TYPE;
    3.89 -                        ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
    3.90 -                        args.append(t1);
    3.91 -                        while (token.kind == COMMA) {
    3.92 +                    mode = EXPR | TYPE | NOPARAMS;
    3.93 +                    t = term3();
    3.94 +                    if ((mode & TYPE) != 0 && token.kind == LT) {
    3.95 +                        // Could be a cast to a parameterized type
    3.96 +                        JCTree.Tag op = JCTree.Tag.LT;
    3.97 +                        int pos1 = token.pos;
    3.98 +                        nextToken();
    3.99 +                        mode &= (EXPR | TYPE);
   3.100 +                        mode |= TYPEARG;
   3.101 +                        JCExpression t1 = term3();
   3.102 +                        if ((mode & TYPE) != 0 &&
   3.103 +                            (token.kind == COMMA || token.kind == GT)) {
   3.104 +                            mode = TYPE;
   3.105 +                            ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
   3.106 +                            args.append(t1);
   3.107 +                            while (token.kind == COMMA) {
   3.108 +                                nextToken();
   3.109 +                                args.append(typeArgument());
   3.110 +                            }
   3.111 +                            accept(GT);
   3.112 +                            t = toP(F.at(pos1).TypeApply(t, args.toList()));
   3.113 +                            checkGenerics();
   3.114 +                            mode = EXPR | TYPE; //could be a lambda or a method ref or a cast to a type
   3.115 +                            t = term3Rest(t, typeArgs);
   3.116 +                            if (token.kind == IDENTIFIER || token.kind == ELLIPSIS) {
   3.117 +                                //explicit lambda (w/ generic type)
   3.118 +                                mode = EXPR;
   3.119 +                                JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
   3.120 +                                if (token.kind == ELLIPSIS) {
   3.121 +                                    mods.flags = Flags.VARARGS;
   3.122 +                                    t = to(F.at(token.pos).TypeArray(t));
   3.123 +                                    nextToken();
   3.124 +                                }
   3.125 +                                t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
   3.126 +                                break;
   3.127 +                            }
   3.128 +                        } else {
   3.129 +                            Assert.check((mode & EXPR) != 0);
   3.130 +                            mode = EXPR;
   3.131 +                            JCExpression e = term2Rest(t1, TreeInfo.shiftPrec);
   3.132 +                            t = F.at(pos1).Binary(op, t, e);
   3.133 +                            t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
   3.134 +                        }
   3.135 +                    } else if ((mode & TYPE) != 0 &&
   3.136 +                            (token.kind == IDENTIFIER || token.kind == ELLIPSIS)) {
   3.137 +                        //explicit lambda (w/ non-generic type)
   3.138 +                        mode = EXPR;
   3.139 +                        JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
   3.140 +                        if (token.kind == ELLIPSIS) {
   3.141 +                            mods.flags = Flags.VARARGS;
   3.142 +                            t = to(F.at(token.pos).TypeArray(t));
   3.143                              nextToken();
   3.144 -                            args.append(typeArgument());
   3.145                          }
   3.146 -                        accept(GT);
   3.147 -                        t = toP(F.at(pos1).TypeApply(t, args.toList()));
   3.148 -                        checkGenerics();
   3.149 -                        while (token.kind == DOT) {
   3.150 -                            nextToken();
   3.151 -                            mode = TYPE;
   3.152 -                            t = toP(F.at(token.pos).Select(t, ident()));
   3.153 -                            t = typeArgumentsOpt(t);
   3.154 -                        }
   3.155 -                        t = bracketsOpt(toP(t));
   3.156 -                    } else if ((mode & EXPR) != 0) {
   3.157 -                        mode = EXPR;
   3.158 -                        JCExpression e = term2Rest(t1, TreeInfo.shiftPrec);
   3.159 -                        t = F.at(pos1).Binary(op, t, e);
   3.160 +                        t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
   3.161 +                        break;
   3.162 +                    } else {
   3.163                          t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
   3.164 -                    } else {
   3.165 -                        accept(GT);
   3.166                      }
   3.167                  }
   3.168 -                else {
   3.169 -                    t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
   3.170 -                }
   3.171 +
   3.172                  accept(RPAREN);
   3.173                  lastmode = mode;
   3.174                  mode = EXPR;
   3.175 @@ -953,14 +1012,16 @@
   3.176                      case INTLITERAL: case LONGLITERAL: case FLOATLITERAL:
   3.177                      case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL:
   3.178                      case TRUE: case FALSE: case NULL:
   3.179 -                    case NEW: case IDENTIFIER: case ASSERT: case ENUM:
   3.180 +                        case NEW: case IDENTIFIER: case ASSERT: case ENUM:
   3.181                      case BYTE: case SHORT: case CHAR: case INT:
   3.182                      case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
   3.183                          JCExpression t1 = term3();
   3.184                          return F.at(pos).TypeCast(t, t1);
   3.185                      }
   3.186                  }
   3.187 -            } else return illegal();
   3.188 +            } else {
   3.189 +                return illegal();
   3.190 +            }
   3.191              t = toP(F.at(pos).Parens(t));
   3.192              break;
   3.193          case THIS:
   3.194 @@ -1003,75 +1064,79 @@
   3.195              break;
   3.196          case IDENTIFIER: case ASSERT: case ENUM:
   3.197              if (typeArgs != null) return illegal();
   3.198 -            t = toP(F.at(token.pos).Ident(ident()));
   3.199 -            loop: while (true) {
   3.200 -                pos = token.pos;
   3.201 -                switch (token.kind) {
   3.202 -                case LBRACKET:
   3.203 -                    nextToken();
   3.204 -                    if (token.kind == RBRACKET) {
   3.205 +            if ((mode & EXPR) != 0 && peekToken(ARROW)) {
   3.206 +                t = lambdaExpressionOrStatement(false, false, pos);
   3.207 +            } else {
   3.208 +                t = toP(F.at(token.pos).Ident(ident()));
   3.209 +                loop: while (true) {
   3.210 +                    pos = token.pos;
   3.211 +                    switch (token.kind) {
   3.212 +                    case LBRACKET:
   3.213                          nextToken();
   3.214 -                        t = bracketsOpt(t);
   3.215 -                        t = toP(F.at(pos).TypeArray(t));
   3.216 -                        t = bracketsSuffix(t);
   3.217 -                    } else {
   3.218 +                        if (token.kind == RBRACKET) {
   3.219 +                            nextToken();
   3.220 +                            t = bracketsOpt(t);
   3.221 +                            t = toP(F.at(pos).TypeArray(t));
   3.222 +                            t = bracketsSuffix(t);
   3.223 +                        } else {
   3.224 +                            if ((mode & EXPR) != 0) {
   3.225 +                                mode = EXPR;
   3.226 +                                JCExpression t1 = term();
   3.227 +                                t = to(F.at(pos).Indexed(t, t1));
   3.228 +                            }
   3.229 +                            accept(RBRACKET);
   3.230 +                        }
   3.231 +                        break loop;
   3.232 +                    case LPAREN:
   3.233                          if ((mode & EXPR) != 0) {
   3.234                              mode = EXPR;
   3.235 -                            JCExpression t1 = term();
   3.236 -                            t = to(F.at(pos).Indexed(t, t1));
   3.237 +                            t = arguments(typeArgs, t);
   3.238 +                            typeArgs = null;
   3.239                          }
   3.240 -                        accept(RBRACKET);
   3.241 +                        break loop;
   3.242 +                    case DOT:
   3.243 +                        nextToken();
   3.244 +                        int oldmode = mode;
   3.245 +                        mode &= ~NOPARAMS;
   3.246 +                        typeArgs = typeArgumentsOpt(EXPR);
   3.247 +                        mode = oldmode;
   3.248 +                        if ((mode & EXPR) != 0) {
   3.249 +                            switch (token.kind) {
   3.250 +                            case CLASS:
   3.251 +                                if (typeArgs != null) return illegal();
   3.252 +                                mode = EXPR;
   3.253 +                                t = to(F.at(pos).Select(t, names._class));
   3.254 +                                nextToken();
   3.255 +                                break loop;
   3.256 +                            case THIS:
   3.257 +                                if (typeArgs != null) return illegal();
   3.258 +                                mode = EXPR;
   3.259 +                                t = to(F.at(pos).Select(t, names._this));
   3.260 +                                nextToken();
   3.261 +                                break loop;
   3.262 +                            case SUPER:
   3.263 +                                mode = EXPR;
   3.264 +                                t = to(F.at(pos).Select(t, names._super));
   3.265 +                                t = superSuffix(typeArgs, t);
   3.266 +                                typeArgs = null;
   3.267 +                                break loop;
   3.268 +                            case NEW:
   3.269 +                                if (typeArgs != null) return illegal();
   3.270 +                                mode = EXPR;
   3.271 +                                int pos1 = token.pos;
   3.272 +                                nextToken();
   3.273 +                                if (token.kind == LT) typeArgs = typeArguments(false);
   3.274 +                                t = innerCreator(pos1, typeArgs, t);
   3.275 +                                typeArgs = null;
   3.276 +                                break loop;
   3.277 +                            }
   3.278 +                        }
   3.279 +                        // typeArgs saved for next loop iteration.
   3.280 +                        t = toP(F.at(pos).Select(t, ident()));
   3.281 +                        break;
   3.282 +                    default:
   3.283 +                        break loop;
   3.284                      }
   3.285 -                    break loop;
   3.286 -                case LPAREN:
   3.287 -                    if ((mode & EXPR) != 0) {
   3.288 -                        mode = EXPR;
   3.289 -                        t = arguments(typeArgs, t);
   3.290 -                        typeArgs = null;
   3.291 -                    }
   3.292 -                    break loop;
   3.293 -                case DOT:
   3.294 -                    nextToken();
   3.295 -                    int oldmode = mode;
   3.296 -                    mode &= ~NOPARAMS;
   3.297 -                    typeArgs = typeArgumentsOpt(EXPR);
   3.298 -                    mode = oldmode;
   3.299 -                    if ((mode & EXPR) != 0) {
   3.300 -                        switch (token.kind) {
   3.301 -                        case CLASS:
   3.302 -                            if (typeArgs != null) return illegal();
   3.303 -                            mode = EXPR;
   3.304 -                            t = to(F.at(pos).Select(t, names._class));
   3.305 -                            nextToken();
   3.306 -                            break loop;
   3.307 -                        case THIS:
   3.308 -                            if (typeArgs != null) return illegal();
   3.309 -                            mode = EXPR;
   3.310 -                            t = to(F.at(pos).Select(t, names._this));
   3.311 -                            nextToken();
   3.312 -                            break loop;
   3.313 -                        case SUPER:
   3.314 -                            mode = EXPR;
   3.315 -                            t = to(F.at(pos).Select(t, names._super));
   3.316 -                            t = superSuffix(typeArgs, t);
   3.317 -                            typeArgs = null;
   3.318 -                            break loop;
   3.319 -                        case NEW:
   3.320 -                            if (typeArgs != null) return illegal();
   3.321 -                            mode = EXPR;
   3.322 -                            int pos1 = token.pos;
   3.323 -                            nextToken();
   3.324 -                            if (token.kind == LT) typeArgs = typeArguments(false);
   3.325 -                            t = innerCreator(pos1, typeArgs, t);
   3.326 -                            typeArgs = null;
   3.327 -                            break loop;
   3.328 -                        }
   3.329 -                    }
   3.330 -                    // typeArgs saved for next loop iteration.
   3.331 -                    t = toP(F.at(pos).Select(t, ident()));
   3.332 -                    break;
   3.333 -                default:
   3.334 -                    break loop;
   3.335                  }
   3.336              }
   3.337              if (typeArgs != null) illegal();
   3.338 @@ -1105,6 +1170,10 @@
   3.339          default:
   3.340              return illegal();
   3.341          }
   3.342 +        return term3Rest(t, typeArgs);
   3.343 +    }
   3.344 +
   3.345 +    JCExpression term3Rest(JCExpression t, List<JCExpression> typeArgs) {
   3.346          if (typeArgs != null) illegal();
   3.347          while (true) {
   3.348              int pos1 = token.pos;
   3.349 @@ -1162,6 +1231,50 @@
   3.350          return toP(t);
   3.351      }
   3.352  
   3.353 +    JCExpression lambdaExpressionOrStatement(JCVariableDecl firstParam, int pos) {
   3.354 +        ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
   3.355 +        params.append(firstParam);
   3.356 +        JCVariableDecl lastParam = firstParam;
   3.357 +        while ((lastParam.mods.flags & Flags.VARARGS) == 0 && token.kind == COMMA) {
   3.358 +            nextToken();
   3.359 +            params.append(lastParam = formalParameter());
   3.360 +        }
   3.361 +        accept(RPAREN);
   3.362 +        return lambdaExpressionOrStatementRest(params.toList(), pos);
   3.363 +    }
   3.364 +
   3.365 +    JCExpression lambdaExpressionOrStatement(boolean hasParens, boolean explicitParams, int pos) {
   3.366 +        List<JCVariableDecl> params = explicitParams ?
   3.367 +                formalParameters() :
   3.368 +                implicitParameters(hasParens);
   3.369 +
   3.370 +        return lambdaExpressionOrStatementRest(params, pos);
   3.371 +    }
   3.372 +
   3.373 +    JCExpression lambdaExpressionOrStatementRest(List<JCVariableDecl> args, int pos) {
   3.374 +        if (token.kind != ARROW) {
   3.375 +            //better error recovery
   3.376 +            return F.at(pos).Erroneous(args);
   3.377 +        }
   3.378 +
   3.379 +        checkLambda();
   3.380 +        accept(ARROW);
   3.381 +
   3.382 +        return token.kind == LBRACE ?
   3.383 +            lambdaStatement(args, pos, pos) :
   3.384 +            lambdaExpression(args, pos);
   3.385 +    }
   3.386 +
   3.387 +    JCExpression lambdaStatement(List<JCVariableDecl> args, int pos, int pos2) {
   3.388 +        JCBlock block = block(pos2, 0);
   3.389 +        return toP(F.at(pos).Lambda(args, block));
   3.390 +    }
   3.391 +
   3.392 +    JCExpression lambdaExpression(List<JCVariableDecl> args, int pos) {
   3.393 +        JCTree expr = parseExpression();
   3.394 +        return toP(F.at(pos).Lambda(args, expr));
   3.395 +    }
   3.396 +
   3.397      /** SuperSuffix = Arguments | "." [TypeArguments] Ident [Arguments]
   3.398       */
   3.399      JCExpression superSuffix(List<JCExpression> typeArgs, JCExpression t) {
   3.400 @@ -2779,6 +2892,24 @@
   3.401          return params.toList();
   3.402      }
   3.403  
   3.404 +    List<JCVariableDecl> implicitParameters(boolean hasParens) {
   3.405 +        if (hasParens) {
   3.406 +            accept(LPAREN);
   3.407 +        }
   3.408 +        ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
   3.409 +        if (token.kind != RPAREN && token.kind != ARROW) {
   3.410 +            params.append(implicitParameter());
   3.411 +            while (token.kind == COMMA) {
   3.412 +                nextToken();
   3.413 +                params.append(implicitParameter());
   3.414 +            }
   3.415 +        }
   3.416 +        if (hasParens) {
   3.417 +            accept(RPAREN);
   3.418 +        }
   3.419 +        return params.toList();
   3.420 +    }
   3.421 +
   3.422      JCModifiers optFinal(long flags) {
   3.423          JCModifiers mods = modifiersOpt();
   3.424          checkNoMods(mods.flags & ~(Flags.FINAL | Flags.DEPRECATED));
   3.425 @@ -2801,6 +2932,11 @@
   3.426          return variableDeclaratorId(mods, type);
   3.427      }
   3.428  
   3.429 +    protected JCVariableDecl implicitParameter() {
   3.430 +        JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
   3.431 +        return variableDeclaratorId(mods, null);
   3.432 +    }
   3.433 +
   3.434  /* ---------- auxiliary methods -------------- */
   3.435  
   3.436      void error(int pos, String key, Object ... args) {
   3.437 @@ -3024,6 +3160,12 @@
   3.438              allowTWR = true;
   3.439          }
   3.440      }
   3.441 +    void checkLambda() {
   3.442 +        if (!allowLambda) {
   3.443 +            log.error(token.pos, "lambda.not.supported.in.source", source.name);
   3.444 +            allowLambda = true;
   3.445 +        }
   3.446 +    }
   3.447  
   3.448      /*
   3.449       * a functional source tree and end position mappings
     4.1 --- a/src/share/classes/com/sun/tools/javac/parser/Lexer.java	Thu Nov 24 13:38:40 2011 +0000
     4.2 +++ b/src/share/classes/com/sun/tools/javac/parser/Lexer.java	Mon Nov 28 15:56:42 2011 +0000
     4.3 @@ -50,6 +50,11 @@
     4.4      Token token();
     4.5  
     4.6      /**
     4.7 +     * Return token with given lookahead.
     4.8 +     */
     4.9 +    Token token(int lookahead);
    4.10 +
    4.11 +    /**
    4.12       * Return the last character position of the previous token.
    4.13       */
    4.14      Token prevToken();
     5.1 --- a/src/share/classes/com/sun/tools/javac/parser/Scanner.java	Thu Nov 24 13:38:40 2011 +0000
     5.2 +++ b/src/share/classes/com/sun/tools/javac/parser/Scanner.java	Mon Nov 28 15:56:42 2011 +0000
     5.3 @@ -26,8 +26,9 @@
     5.4  package com.sun.tools.javac.parser;
     5.5  
     5.6  import java.nio.*;
     5.7 +import java.util.List;
     5.8 +import java.util.ArrayList;
     5.9  
    5.10 -import com.sun.tools.javac.util.*;
    5.11  import com.sun.tools.javac.util.Position.LineMap;
    5.12  import com.sun.tools.javac.parser.JavaTokenizer.*;
    5.13  
    5.14 @@ -53,6 +54,10 @@
    5.15       */
    5.16      private Token prevToken;
    5.17  
    5.18 +    /** Buffer of saved tokens (used during lookahead)
    5.19 +     */
    5.20 +    private List<Token> savedTokens = new ArrayList<Token>();
    5.21 +
    5.22      private JavaTokenizer tokenizer;
    5.23      /**
    5.24       * Create a scanner from the input array.  This method might
    5.25 @@ -80,16 +85,35 @@
    5.26      }
    5.27  
    5.28      public Token token() {
    5.29 -        return token;
    5.30 +        return token(0);
    5.31      }
    5.32  
    5.33 +    public Token token(int lookahead) {
    5.34 +        if (lookahead == 0) {
    5.35 +            return token;
    5.36 +        } else {
    5.37 +            ensureLookahead(lookahead);
    5.38 +            return savedTokens.get(lookahead - 1);
    5.39 +        }
    5.40 +    }
    5.41 +    //where
    5.42 +        private void ensureLookahead(int lookahead) {
    5.43 +            for (int i = savedTokens.size() ; i < lookahead ; i ++) {
    5.44 +                savedTokens.add(tokenizer.readToken());
    5.45 +            }
    5.46 +        }
    5.47 +
    5.48      public Token prevToken() {
    5.49          return prevToken;
    5.50      }
    5.51  
    5.52      public void nextToken() {
    5.53          prevToken = token;
    5.54 -        token = tokenizer.readToken();
    5.55 +        if (!savedTokens.isEmpty()) {
    5.56 +            token = savedTokens.remove(0);
    5.57 +        } else {
    5.58 +            token = tokenizer.readToken();
    5.59 +        }
    5.60      }
    5.61  
    5.62      public Token split() {
     6.1 --- a/src/share/classes/com/sun/tools/javac/parser/Tokens.java	Thu Nov 24 13:38:40 2011 +0000
     6.2 +++ b/src/share/classes/com/sun/tools/javac/parser/Tokens.java	Mon Nov 28 15:56:42 2011 +0000
     6.3 @@ -176,6 +176,7 @@
     6.4          TRUE("true", Tag.NAMED),
     6.5          FALSE("false", Tag.NAMED),
     6.6          NULL("null", Tag.NAMED),
     6.7 +        ARROW("->"),
     6.8          LPAREN("("),
     6.9          RPAREN(")"),
    6.10          LBRACE("{"),
     7.1 --- a/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Nov 24 13:38:40 2011 +0000
     7.2 +++ b/src/share/classes/com/sun/tools/javac/resources/compiler.properties	Mon Nov 28 15:56:42 2011 +0000
     7.3 @@ -1945,6 +1945,11 @@
     7.4      strings in switch are not supported in -source {0}\n\
     7.5      (use -source 7 or higher to enable strings in switch)
     7.6  
     7.7 +# 0: string
     7.8 +compiler.err.lambda.not.supported.in.source=\
     7.9 +    lambda expressions are not supported in -source {0}\n\
    7.10 +    (use -source 8 or higher to enable lambda expressions)
    7.11 +
    7.12  ########################################
    7.13  # Diagnostics for verbose resolution
    7.14  # used by Resolve (debug only)
     8.1 --- a/test/tools/javac/diags/examples/CatchWithoutTry.java	Thu Nov 24 13:38:40 2011 +0000
     8.2 +++ b/test/tools/javac/diags/examples/CatchWithoutTry.java	Mon Nov 28 15:56:42 2011 +0000
     8.3 @@ -1,5 +1,5 @@
     8.4  /*
     8.5 - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
     8.6 + * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
     8.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     8.8   *
     8.9   * This code is free software; you can redistribute it and/or modify it
    8.10 @@ -23,7 +23,6 @@
    8.11  
    8.12  // key: compiler.err.catch.without.try
    8.13  // key: compiler.err.expected
    8.14 -// key: compiler.err.not.stmt
    8.15  
    8.16  class CatchWithoutTry {
    8.17      void m() {
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/test/tools/javac/diags/examples/LambdaNotSupported.java	Mon Nov 28 15:56:42 2011 +0000
     9.3 @@ -0,0 +1,29 @@
     9.4 +/*
     9.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
     9.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     9.7 + *
     9.8 + * This code is free software; you can redistribute it and/or modify it
     9.9 + * under the terms of the GNU General Public License version 2 only, as
    9.10 + * published by the Free Software Foundation.
    9.11 + *
    9.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    9.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    9.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    9.15 + * version 2 for more details (a copy is included in the LICENSE file that
    9.16 + * accompanied this code).
    9.17 + *
    9.18 + * You should have received a copy of the GNU General Public License version
    9.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    9.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    9.21 + *
    9.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    9.23 + * or visit www.oracle.com if you need additional information or have any
    9.24 + * questions.
    9.25 + */
    9.26 +
    9.27 +// key: compiler.err.lambda.not.supported.in.source
    9.28 +// options: -source 7 -Xlint:-options
    9.29 +
    9.30 +class LambdaNotSupported {
    9.31 +    S s = ()->{};
    9.32 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/test/tools/javac/diags/examples/NotAStatement.java	Mon Nov 28 15:56:42 2011 +0000
    10.3 @@ -0,0 +1,30 @@
    10.4 +/*
    10.5 + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
    10.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    10.7 + *
    10.8 + * This code is free software; you can redistribute it and/or modify it
    10.9 + * under the terms of the GNU General Public License version 2 only, as
   10.10 + * published by the Free Software Foundation.
   10.11 + *
   10.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   10.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   10.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   10.15 + * version 2 for more details (a copy is included in the LICENSE file that
   10.16 + * accompanied this code).
   10.17 + *
   10.18 + * You should have received a copy of the GNU General Public License version
   10.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   10.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   10.21 + *
   10.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   10.23 + * or visit www.oracle.com if you need additional information or have any
   10.24 + * questions.
   10.25 + */
   10.26 +
   10.27 +// key: compiler.err.not.stmt
   10.28 +
   10.29 +class NotAStatement {
   10.30 +    void m() {
   10.31 +        x + 1;
   10.32 +    }
   10.33 +}
    11.1 --- a/test/tools/javac/generics/rare/6665356/T6665356.out	Thu Nov 24 13:38:40 2011 +0000
    11.2 +++ b/test/tools/javac/generics/rare/6665356/T6665356.out	Mon Nov 28 15:56:42 2011 +0000
    11.3 @@ -1,5 +1,5 @@
    11.4  T6665356.java:17:37: compiler.err.improperly.formed.type.param.missing
    11.5  T6665356.java:18:40: compiler.err.improperly.formed.type.inner.raw.param
    11.6 -T6665356.java:26:23: compiler.err.improperly.formed.type.param.missing
    11.7 +T6665356.java:26:22: compiler.err.improperly.formed.type.param.missing
    11.8  T6665356.java:27:25: compiler.err.improperly.formed.type.inner.raw.param
    11.9  4 errors
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/test/tools/javac/lambda/LambdaParserTest.java	Mon Nov 28 15:56:42 2011 +0000
    12.3 @@ -0,0 +1,276 @@
    12.4 +/*
    12.5 + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
    12.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    12.7 + *
    12.8 + * This code is free software; you can redistribute it and/or modify it
    12.9 + * under the terms of the GNU General Public License version 2 only, as
   12.10 + * published by the Free Software Foundation.
   12.11 + *
   12.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
   12.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   12.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   12.15 + * version 2 for more details (a copy is included in the LICENSE file that
   12.16 + * accompanied this code).
   12.17 + *
   12.18 + * You should have received a copy of the GNU General Public License version
   12.19 + * 2 along with this work; if not, write to the Free Software Foundation,
   12.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   12.21 + *
   12.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   12.23 + * or visit www.oracle.com if you need additional information or have any
   12.24 + * questions.
   12.25 + */
   12.26 +
   12.27 +/*
   12.28 + * @test
   12.29 + * @bug 7115050
   12.30 + * @summary Add parser support for lambda expressions
   12.31 + */
   12.32 +
   12.33 +import com.sun.source.util.JavacTask;
   12.34 +import java.net.URI;
   12.35 +import java.util.Arrays;
   12.36 +import javax.tools.Diagnostic;
   12.37 +import javax.tools.JavaCompiler;
   12.38 +import javax.tools.JavaFileObject;
   12.39 +import javax.tools.SimpleJavaFileObject;
   12.40 +import javax.tools.StandardJavaFileManager;
   12.41 +import javax.tools.ToolProvider;
   12.42 +
   12.43 +public class LambdaParserTest {
   12.44 +
   12.45 +    static int checkCount = 0;
   12.46 +
   12.47 +    enum LambdaKind {
   12.48 +        NILARY_EXPR("()->x"),
   12.49 +        NILARY_STMT("()->{ return x; }"),
   12.50 +        ONEARY_SHORT_EXPR("x->x"),
   12.51 +        ONEARY_SHORT_STMT("x->{ return x; }"),
   12.52 +        ONEARY_EXPR("(#M1 #T1 x)->x"),
   12.53 +        ONEARY_STMT("(#M1 #T1 x)->{ return x; }"),
   12.54 +        TWOARY_EXPR("(#M1 #T1 x, #M2 #T2 y)->x"),
   12.55 +        TWOARY_STMT("(#M1 #T1 x, #M2 #T2 y)->{ return x; }");
   12.56 +
   12.57 +        String lambdaTemplate;
   12.58 +
   12.59 +        LambdaKind(String lambdaTemplate) {
   12.60 +            this.lambdaTemplate = lambdaTemplate;
   12.61 +        }
   12.62 +
   12.63 +        String getLambdaString(LambdaParameterKind pk1, LambdaParameterKind pk2,
   12.64 +                ModifierKind mk1, ModifierKind mk2) {
   12.65 +            return lambdaTemplate.replaceAll("#M1", mk1.modifier)
   12.66 +                    .replaceAll("#M2", mk2.modifier)
   12.67 +                    .replaceAll("#T1", pk1.parameterType)
   12.68 +                    .replaceAll("#T2", pk2.parameterType);
   12.69 +        }
   12.70 +
   12.71 +        int arity() {
   12.72 +            switch (this) {
   12.73 +                case NILARY_EXPR:
   12.74 +                case NILARY_STMT: return 0;
   12.75 +                case ONEARY_SHORT_EXPR:
   12.76 +                case ONEARY_SHORT_STMT:
   12.77 +                case ONEARY_EXPR:
   12.78 +                case ONEARY_STMT: return 1;
   12.79 +                case TWOARY_EXPR:
   12.80 +                case TWOARY_STMT: return 2;
   12.81 +                default: throw new AssertionError("Invalid lambda kind " + this);
   12.82 +            }
   12.83 +        }
   12.84 +
   12.85 +        boolean isShort() {
   12.86 +            return this == ONEARY_SHORT_EXPR ||
   12.87 +                    this == ONEARY_SHORT_STMT;
   12.88 +        }
   12.89 +    }
   12.90 +
   12.91 +    enum LambdaParameterKind {
   12.92 +        IMPLICIT(""),
   12.93 +        EXPLIICT_SIMPLE("A"),
   12.94 +        EXPLICIT_VARARGS("A..."),
   12.95 +        EXPLICIT_GENERIC1("A<X>"),
   12.96 +        EXPLICIT_GENERIC3("A<? extends X, ? super Y>");
   12.97 +
   12.98 +        String parameterType;
   12.99 +
  12.100 +        LambdaParameterKind(String parameterType) {
  12.101 +            this.parameterType = parameterType;
  12.102 +        }
  12.103 +
  12.104 +        boolean explicit() {
  12.105 +            return this != IMPLICIT;
  12.106 +        }
  12.107 +    }
  12.108 +
  12.109 +    enum ModifierKind {
  12.110 +        NONE(""),
  12.111 +        FINAL("final"),
  12.112 +        PUBLIC("public");
  12.113 +
  12.114 +        String modifier;
  12.115 +
  12.116 +        ModifierKind(String modifier) {
  12.117 +            this.modifier = modifier;
  12.118 +        }
  12.119 +
  12.120 +        boolean compatibleWith(LambdaParameterKind pk) {
  12.121 +            switch (this) {
  12.122 +                case PUBLIC: return false;
  12.123 +                case FINAL: return pk != LambdaParameterKind.IMPLICIT;
  12.124 +                case NONE: return true;
  12.125 +                default: throw new AssertionError("Invalid modifier kind " + this);
  12.126 +            }
  12.127 +        }
  12.128 +    }
  12.129 +
  12.130 +    enum ExprKind {
  12.131 +        NONE("#L#S"),
  12.132 +        SINGLE_PAREN1("(#L#S)"),
  12.133 +        SINGLE_PAREN2("(#L)#S"),
  12.134 +        DOUBLE_PAREN1("((#L#S))"),
  12.135 +        DOUBLE_PAREN2("((#L)#S)"),
  12.136 +        DOUBLE_PAREN3("((#L))#S");
  12.137 +
  12.138 +        String expressionTemplate;
  12.139 +
  12.140 +        ExprKind(String expressionTemplate) {
  12.141 +            this.expressionTemplate = expressionTemplate;
  12.142 +        }
  12.143 +
  12.144 +        String expressionString(LambdaParameterKind pk1, LambdaParameterKind pk2,
  12.145 +                ModifierKind mk1, ModifierKind mk2, LambdaKind lk, SubExprKind sk) {
  12.146 +            return expressionTemplate.replaceAll("#L", lk.getLambdaString(pk1, pk2, mk1, mk2))
  12.147 +                    .replaceAll("#S", sk.subExpression);
  12.148 +        }
  12.149 +    }
  12.150 +
  12.151 +    enum SubExprKind {
  12.152 +        NONE(""),
  12.153 +        SELECT_FIELD(".f"),
  12.154 +        SELECT_METHOD(".f()"),
  12.155 +        SELECT_NEW(".new Foo()"),
  12.156 +        POSTINC("++"),
  12.157 +        POSTDEC("--");
  12.158 +
  12.159 +        String subExpression;
  12.160 +
  12.161 +        SubExprKind(String subExpression) {
  12.162 +            this.subExpression = subExpression;
  12.163 +        }
  12.164 +    }
  12.165 +
  12.166 +    public static void main(String... args) throws Exception {
  12.167 +
  12.168 +        //create default shared JavaCompiler - reused across multiple compilations
  12.169 +        JavaCompiler comp = ToolProvider.getSystemJavaCompiler();
  12.170 +        StandardJavaFileManager fm = comp.getStandardFileManager(null, null, null);
  12.171 +
  12.172 +        for (LambdaKind lk : LambdaKind.values()) {
  12.173 +            for (LambdaParameterKind pk1 : LambdaParameterKind.values()) {
  12.174 +                if (lk.arity() < 1 && pk1 != LambdaParameterKind.IMPLICIT) continue;
  12.175 +                for (LambdaParameterKind pk2 : LambdaParameterKind.values()) {
  12.176 +                    if (lk.arity() < 2 && pk2 != LambdaParameterKind.IMPLICIT) continue;
  12.177 +                    for (ModifierKind mk1 : ModifierKind.values()) {
  12.178 +                        if (mk1 != ModifierKind.NONE && lk.isShort()) continue;
  12.179 +                        if (lk.arity() < 1 && mk1 != ModifierKind.NONE) continue;
  12.180 +                        for (ModifierKind mk2 : ModifierKind.values()) {
  12.181 +                            if (lk.arity() < 2 && mk2 != ModifierKind.NONE) continue;
  12.182 +                            for (SubExprKind sk : SubExprKind.values()) {
  12.183 +                                for (ExprKind ek : ExprKind.values()) {
  12.184 +                                    new LambdaParserTest(pk1, pk2, mk1, mk2, lk, sk, ek)
  12.185 +                                            .run(comp, fm);
  12.186 +                                }
  12.187 +                            }
  12.188 +                        }
  12.189 +                    }
  12.190 +                }
  12.191 +            }
  12.192 +        }
  12.193 +        System.out.println("Total check executed: " + checkCount);
  12.194 +    }
  12.195 +
  12.196 +    LambdaParameterKind pk1;
  12.197 +    LambdaParameterKind pk2;
  12.198 +    ModifierKind mk1;
  12.199 +    ModifierKind mk2;
  12.200 +    LambdaKind lk;
  12.201 +    SubExprKind sk;
  12.202 +    ExprKind ek;
  12.203 +    JavaSource source;
  12.204 +    DiagnosticChecker diagChecker;
  12.205 +
  12.206 +    LambdaParserTest(LambdaParameterKind pk1, LambdaParameterKind pk2, ModifierKind mk1,
  12.207 +            ModifierKind mk2, LambdaKind lk, SubExprKind sk, ExprKind ek) {
  12.208 +        this.pk1 = pk1;
  12.209 +        this.pk2 = pk2;
  12.210 +        this.mk1 = mk1;
  12.211 +        this.mk2 = mk2;
  12.212 +        this.lk = lk;
  12.213 +        this.sk = sk;
  12.214 +        this.ek = ek;
  12.215 +        this.source = new JavaSource();
  12.216 +        this.diagChecker = new DiagnosticChecker();
  12.217 +    }
  12.218 +
  12.219 +    class JavaSource extends SimpleJavaFileObject {
  12.220 +
  12.221 +        String template = "class Test {\n" +
  12.222 +                          "   SAM s = #E;\n" +
  12.223 +                          "}";
  12.224 +
  12.225 +        String source;
  12.226 +
  12.227 +        public JavaSource() {
  12.228 +            super(URI.create("myfo:/Test.java"), JavaFileObject.Kind.SOURCE);
  12.229 +            source = template.replaceAll("#E", ek.expressionString(pk1, pk2, mk1, mk2, lk, sk));
  12.230 +        }
  12.231 +
  12.232 +        @Override
  12.233 +        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
  12.234 +            return source;
  12.235 +        }
  12.236 +    }
  12.237 +
  12.238 +    void run(JavaCompiler tool, StandardJavaFileManager fm) throws Exception {
  12.239 +        JavacTask ct = (JavacTask)tool.getTask(null, fm, diagChecker,
  12.240 +                Arrays.asList("-XDallowLambda"), null, Arrays.asList(source));
  12.241 +        try {
  12.242 +            ct.parse();
  12.243 +        } catch (Throwable ex) {
  12.244 +            throw new AssertionError("Error thron when parsing the following source:\n" + source.getCharContent(true));
  12.245 +        }
  12.246 +        check();
  12.247 +    }
  12.248 +
  12.249 +    void check() {
  12.250 +        checkCount++;
  12.251 +
  12.252 +        boolean errorExpected = (lk.arity() > 0 && !mk1.compatibleWith(pk1)) ||
  12.253 +                (lk.arity() > 1 && !mk2.compatibleWith(pk2));
  12.254 +
  12.255 +        if (lk.arity() == 2 &&
  12.256 +                (pk1.explicit() != pk2.explicit() ||
  12.257 +                pk1 == LambdaParameterKind.EXPLICIT_VARARGS)) {
  12.258 +            errorExpected = true;
  12.259 +        }
  12.260 +
  12.261 +        if (errorExpected != diagChecker.errorFound) {
  12.262 +            throw new Error("invalid diagnostics for source:\n" +
  12.263 +                source.getCharContent(true) +
  12.264 +                "\nFound error: " + diagChecker.errorFound +
  12.265 +                "\nExpected error: " + errorExpected);
  12.266 +        }
  12.267 +    }
  12.268 +
  12.269 +    static class DiagnosticChecker implements javax.tools.DiagnosticListener<JavaFileObject> {
  12.270 +
  12.271 +        boolean errorFound;
  12.272 +
  12.273 +        public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
  12.274 +            if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
  12.275 +                errorFound = true;
  12.276 +            }
  12.277 +        }
  12.278 +    }
  12.279 +}

mercurial