src/share/classes/com/sun/tools/javac/parser/JavacParser.java

changeset 1436
f6f1fd261f57
parent 1433
4f9853659bf1
child 1444
170e486632d9
     1.1 --- a/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Nov 30 15:14:36 2012 +0000
     1.2 +++ b/src/share/classes/com/sun/tools/javac/parser/JavacParser.java	Fri Nov 30 15:14:48 2012 +0000
     1.3 @@ -124,6 +124,9 @@
     1.4          this.allowLambda = source.allowLambda();
     1.5          this.allowMethodReferences = source.allowMethodReferences();
     1.6          this.allowDefaultMethods = source.allowDefaultMethods();
     1.7 +        this.allowIntersectionTypesInCast =
     1.8 +                source.allowIntersectionTypesInCast() &&
     1.9 +                fac.options.isSet("allowIntersectionTypes");
    1.10          this.keepDocComments = keepDocComments;
    1.11          docComments = newDocCommentTable(keepDocComments, fac);
    1.12          this.keepLineMap = keepLineMap;
    1.13 @@ -197,6 +200,10 @@
    1.14       */
    1.15      boolean allowDefaultMethods;
    1.16  
    1.17 +    /** Switch: should we allow intersection types in cast?
    1.18 +     */
    1.19 +    boolean allowIntersectionTypesInCast;
    1.20 +
    1.21      /** Switch: should we keep docComments?
    1.22       */
    1.23      boolean keepDocComments;
    1.24 @@ -239,22 +246,38 @@
    1.25      }
    1.26  
    1.27      protected boolean peekToken(TokenKind tk) {
    1.28 -        return S.token(1).kind == tk;
    1.29 +        return peekToken(0, tk);
    1.30 +    }
    1.31 +
    1.32 +    protected boolean peekToken(int lookahead, TokenKind tk) {
    1.33 +        return S.token(lookahead + 1).kind == tk;
    1.34      }
    1.35  
    1.36      protected boolean peekToken(TokenKind tk1, TokenKind tk2) {
    1.37 -        return S.token(1).kind == tk1 &&
    1.38 -                S.token(2).kind == tk2;
    1.39 +        return peekToken(0, tk1, tk2);
    1.40 +    }
    1.41 +
    1.42 +    protected boolean peekToken(int lookahead, TokenKind tk1, TokenKind tk2) {
    1.43 +        return S.token(lookahead + 1).kind == tk1 &&
    1.44 +                S.token(lookahead + 2).kind == tk2;
    1.45      }
    1.46  
    1.47      protected boolean peekToken(TokenKind tk1, TokenKind tk2, TokenKind tk3) {
    1.48 -        return S.token(1).kind == tk1 &&
    1.49 -                S.token(2).kind == tk2 &&
    1.50 -                S.token(3).kind == tk3;
    1.51 +        return peekToken(0, tk1, tk2, tk3);
    1.52 +    }
    1.53 +
    1.54 +    protected boolean peekToken(int lookahead, TokenKind tk1, TokenKind tk2, TokenKind tk3) {
    1.55 +        return S.token(lookahead + 1).kind == tk1 &&
    1.56 +                S.token(lookahead + 2).kind == tk2 &&
    1.57 +                S.token(lookahead + 3).kind == tk3;
    1.58      }
    1.59  
    1.60      protected boolean peekToken(TokenKind... kinds) {
    1.61 -        for (int lookahead = 0 ; lookahead < kinds.length ; lookahead++) {
    1.62 +        return peekToken(0, kinds);
    1.63 +    }
    1.64 +
    1.65 +    protected boolean peekToken(int lookahead, TokenKind... kinds) {
    1.66 +        for (; lookahead < kinds.length ; lookahead++) {
    1.67              if (S.token(lookahead + 1).kind != kinds[lookahead]) {
    1.68                  return false;
    1.69              }
    1.70 @@ -966,102 +989,40 @@
    1.71              break;
    1.72          case LPAREN:
    1.73              if (typeArgs == null && (mode & EXPR) != 0) {
    1.74 -                if (peekToken(MONKEYS_AT) ||
    1.75 -                        peekToken(FINAL) ||
    1.76 -                        peekToken(RPAREN) ||
    1.77 -                        peekToken(IDENTIFIER, COMMA) ||
    1.78 -                        peekToken(IDENTIFIER, RPAREN, ARROW)) {
    1.79 -                    //implicit n-ary lambda
    1.80 -                    t = lambdaExpressionOrStatement(true, peekToken(MONKEYS_AT) || peekToken(FINAL), pos);
    1.81 -                    break;
    1.82 -                } else {
    1.83 -                    nextToken();
    1.84 -                    mode = EXPR | TYPE | NOPARAMS;
    1.85 -                    t = term3();
    1.86 -                    if ((mode & TYPE) != 0 && token.kind == LT) {
    1.87 -                        // Could be a cast to a parameterized type
    1.88 -                        JCTree.Tag op = JCTree.Tag.LT;
    1.89 -                        int pos1 = token.pos;
    1.90 -                        nextToken();
    1.91 -                        mode &= (EXPR | TYPE);
    1.92 -                        mode |= TYPEARG;
    1.93 -                        JCExpression t1 = term3();
    1.94 -                        if ((mode & TYPE) != 0 &&
    1.95 -                            (token.kind == COMMA || token.kind == GT)) {
    1.96 -                            mode = TYPE;
    1.97 -                            ListBuffer<JCExpression> args = new ListBuffer<JCExpression>();
    1.98 -                            args.append(t1);
    1.99 -                            while (token.kind == COMMA) {
   1.100 -                                nextToken();
   1.101 -                                args.append(typeArgument());
   1.102 -                            }
   1.103 -                            accept(GT);
   1.104 -                            t = toP(F.at(pos1).TypeApply(t, args.toList()));
   1.105 -                            checkGenerics();
   1.106 -                            mode = EXPR | TYPE; //could be a lambda or a method ref or a cast to a type
   1.107 -                            t = term3Rest(t, typeArgs);
   1.108 -                            if (token.kind == IDENTIFIER || token.kind == ELLIPSIS) {
   1.109 -                                //explicit lambda (w/ generic type)
   1.110 -                                mode = EXPR;
   1.111 -                                JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
   1.112 -                                if (token.kind == ELLIPSIS) {
   1.113 -                                    mods.flags = Flags.VARARGS;
   1.114 -                                    t = to(F.at(token.pos).TypeArray(t));
   1.115 -                                    nextToken();
   1.116 -                                }
   1.117 -                                t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
   1.118 -                                break;
   1.119 -                            }
   1.120 -                        } else if ((mode & EXPR) != 0) {
   1.121 -                            mode = EXPR;
   1.122 -                            JCExpression e = term2Rest(t1, TreeInfo.shiftPrec);
   1.123 -                            t = F.at(pos1).Binary(op, t, e);
   1.124 -                            t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
   1.125 -                        } else {
   1.126 -                            accept(GT);
   1.127 -                        }
   1.128 -                    } else if ((mode & TYPE) != 0 &&
   1.129 -                            (token.kind == IDENTIFIER || token.kind == ELLIPSIS)) {
   1.130 -                        //explicit lambda (w/ non-generic type)
   1.131 +                ParensResult pres = analyzeParens();
   1.132 +                switch (pres) {
   1.133 +                    case CAST:
   1.134 +                       accept(LPAREN);
   1.135 +                       mode = TYPE;
   1.136 +                       int pos1 = pos;
   1.137 +                       List<JCExpression> targets = List.of(t = term3());
   1.138 +                       while (token.kind == AMP) {
   1.139 +                           checkIntersectionTypesInCast();
   1.140 +                           accept(AMP);
   1.141 +                           targets = targets.prepend(term3());
   1.142 +                       }
   1.143 +                       if (targets.length() > 1) {
   1.144 +                           t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
   1.145 +                       }
   1.146 +                       accept(RPAREN);
   1.147 +                       mode = EXPR;
   1.148 +                       JCExpression t1 = term3();
   1.149 +                       return F.at(pos).TypeCast(t, t1);
   1.150 +                    case IMPLICIT_LAMBDA:
   1.151 +                    case EXPLICIT_LAMBDA:
   1.152 +                        t = lambdaExpressionOrStatement(true, pres == ParensResult.EXPLICIT_LAMBDA, pos);
   1.153 +                        break;
   1.154 +                    default: //PARENS
   1.155 +                        accept(LPAREN);
   1.156                          mode = EXPR;
   1.157 -                        JCModifiers mods = F.at(token.pos).Modifiers(Flags.PARAMETER);
   1.158 -                        if (token.kind == ELLIPSIS) {
   1.159 -                            mods.flags = Flags.VARARGS;
   1.160 -                            t = to(F.at(token.pos).TypeArray(t));
   1.161 -                            nextToken();
   1.162 -                        }
   1.163 -                        t = lambdaExpressionOrStatement(variableDeclaratorId(mods, t), pos);
   1.164 +                        t = termRest(term1Rest(term2Rest(term3(), TreeInfo.orPrec)));
   1.165 +                        accept(RPAREN);
   1.166 +                        t = toP(F.at(pos).Parens(t));
   1.167                          break;
   1.168 -                    } else {
   1.169 -                        t = termRest(term1Rest(term2Rest(t, TreeInfo.orPrec)));
   1.170 -                    }
   1.171 -                }
   1.172 -
   1.173 -                accept(RPAREN);
   1.174 -                lastmode = mode;
   1.175 -                mode = EXPR;
   1.176 -                if ((lastmode & EXPR) == 0) {
   1.177 -                    JCExpression t1 = term3();
   1.178 -                    return F.at(pos).TypeCast(t, t1);
   1.179 -                } else if ((lastmode & TYPE) != 0) {
   1.180 -                    switch (token.kind) {
   1.181 -                    /*case PLUSPLUS: case SUBSUB: */
   1.182 -                    case BANG: case TILDE:
   1.183 -                    case LPAREN: case THIS: case SUPER:
   1.184 -                    case INTLITERAL: case LONGLITERAL: case FLOATLITERAL:
   1.185 -                    case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL:
   1.186 -                    case TRUE: case FALSE: case NULL:
   1.187 -                        case NEW: case IDENTIFIER: case ASSERT: case ENUM:
   1.188 -                    case BYTE: case SHORT: case CHAR: case INT:
   1.189 -                    case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
   1.190 -                        JCExpression t1 = term3();
   1.191 -                        return F.at(pos).TypeCast(t, t1);
   1.192 -                    }
   1.193                  }
   1.194              } else {
   1.195                  return illegal();
   1.196              }
   1.197 -            t = toP(F.at(pos).Parens(t));
   1.198              break;
   1.199          case THIS:
   1.200              if ((mode & EXPR) != 0) {
   1.201 @@ -1346,6 +1307,138 @@
   1.202          }
   1.203      }
   1.204  
   1.205 +    /**
   1.206 +     * If we see an identifier followed by a '&lt;' it could be an unbound
   1.207 +     * method reference or a binary expression. To disambiguate, look for a
   1.208 +     * matching '&gt;' and see if the subsequent terminal is either '.' or '#'.
   1.209 +     */
   1.210 +    @SuppressWarnings("fallthrough")
   1.211 +    ParensResult analyzeParens() {
   1.212 +        int depth = 0;
   1.213 +        boolean type = false;
   1.214 +        for (int lookahead = 0 ; ; lookahead++) {
   1.215 +            TokenKind tk = S.token(lookahead).kind;
   1.216 +            switch (tk) {
   1.217 +                case EXTENDS: case SUPER: case COMMA:
   1.218 +                    type = true;
   1.219 +                case QUES: case DOT: case AMP:
   1.220 +                    //skip
   1.221 +                    break;
   1.222 +                case BYTE: case SHORT: case INT: case LONG: case FLOAT:
   1.223 +                case DOUBLE: case BOOLEAN: case CHAR:
   1.224 +                    if (peekToken(lookahead, RPAREN)) {
   1.225 +                        //Type, ')' -> cast
   1.226 +                        return ParensResult.CAST;
   1.227 +                    } else if (peekToken(lookahead, IDENTIFIER)) {
   1.228 +                        //Type, 'Identifier -> explicit lambda
   1.229 +                        return ParensResult.EXPLICIT_LAMBDA;
   1.230 +                    }
   1.231 +                    break;
   1.232 +                case LPAREN:
   1.233 +                    if (lookahead != 0) {
   1.234 +                        // '(' in a non-starting position -> parens
   1.235 +                        return ParensResult.PARENS;
   1.236 +                    } else if (peekToken(lookahead, RPAREN)) {
   1.237 +                        // '(', ')' -> explicit lambda
   1.238 +                        return ParensResult.EXPLICIT_LAMBDA;
   1.239 +                    }
   1.240 +                    break;
   1.241 +                case RPAREN:
   1.242 +                    // if we have seen something that looks like a type,
   1.243 +                    // then it's a cast expression
   1.244 +                    if (type) return ParensResult.CAST;
   1.245 +                    // otherwise, disambiguate cast vs. parenthesized expression
   1.246 +                    // based on subsequent token.
   1.247 +                    switch (S.token(lookahead + 1).kind) {
   1.248 +                        /*case PLUSPLUS: case SUBSUB: */
   1.249 +                        case BANG: case TILDE:
   1.250 +                        case LPAREN: case THIS: case SUPER:
   1.251 +                        case INTLITERAL: case LONGLITERAL: case FLOATLITERAL:
   1.252 +                        case DOUBLELITERAL: case CHARLITERAL: case STRINGLITERAL:
   1.253 +                        case TRUE: case FALSE: case NULL:
   1.254 +                            case NEW: case IDENTIFIER: case ASSERT: case ENUM:
   1.255 +                        case BYTE: case SHORT: case CHAR: case INT:
   1.256 +                        case LONG: case FLOAT: case DOUBLE: case BOOLEAN: case VOID:
   1.257 +                            return ParensResult.CAST;
   1.258 +                        default:
   1.259 +                            return ParensResult.PARENS;
   1.260 +                    }
   1.261 +                case IDENTIFIER:
   1.262 +                    if (peekToken(lookahead, IDENTIFIER)) {
   1.263 +                        // Identifier, Identifier -> explicit lambda
   1.264 +                        return ParensResult.EXPLICIT_LAMBDA;
   1.265 +                    } else if (peekToken(lookahead, RPAREN, ARROW)) {
   1.266 +                        // Identifier, ')' '->' -> implicit lambda
   1.267 +                        return ParensResult.IMPLICIT_LAMBDA;
   1.268 +                    }
   1.269 +                    break;
   1.270 +                case FINAL:
   1.271 +                case ELLIPSIS:
   1.272 +                case MONKEYS_AT:
   1.273 +                    //those can only appear in explicit lambdas
   1.274 +                    return ParensResult.EXPLICIT_LAMBDA;
   1.275 +                case LBRACKET:
   1.276 +                    if (peekToken(lookahead, RBRACKET, IDENTIFIER)) {
   1.277 +                        // '[', ']', Identifier -> explicit lambda
   1.278 +                        return ParensResult.EXPLICIT_LAMBDA;
   1.279 +                    } else if (peekToken(lookahead, RBRACKET, RPAREN) ||
   1.280 +                            peekToken(lookahead, RBRACKET, AMP)) {
   1.281 +                        // '[', ']', ')' -> cast
   1.282 +                        // '[', ']', '&' -> cast (intersection type)
   1.283 +                        return ParensResult.CAST;
   1.284 +                    } else if (peekToken(lookahead, RBRACKET)) {
   1.285 +                        //consume the ']' and skip
   1.286 +                        type = true;
   1.287 +                        lookahead++;
   1.288 +                        break;
   1.289 +                    } else {
   1.290 +                        return ParensResult.PARENS;
   1.291 +                    }
   1.292 +                case LT:
   1.293 +                    depth++; break;
   1.294 +                case GTGTGT:
   1.295 +                    depth--;
   1.296 +                case GTGT:
   1.297 +                    depth--;
   1.298 +                case GT:
   1.299 +                    depth--;
   1.300 +                    if (depth == 0) {
   1.301 +                        if (peekToken(lookahead, RPAREN) ||
   1.302 +                                peekToken(lookahead, AMP)) {
   1.303 +                            // '>', ')' -> cast
   1.304 +                            // '>', '&' -> cast
   1.305 +                            return ParensResult.CAST;
   1.306 +                        } else if (peekToken(lookahead, IDENTIFIER, COMMA) ||
   1.307 +                                peekToken(lookahead, IDENTIFIER, RPAREN, ARROW) ||
   1.308 +                                peekToken(lookahead, ELLIPSIS)) {
   1.309 +                            // '>', Identifier, ',' -> explicit lambda
   1.310 +                            // '>', Identifier, ')', '->' -> explicit lambda
   1.311 +                            // '>', '...' -> explicit lambda
   1.312 +                            return ParensResult.EXPLICIT_LAMBDA;
   1.313 +                        }
   1.314 +                        //it looks a type, but could still be (i) a cast to generic type,
   1.315 +                        //(ii) an unbound method reference or (iii) an explicit lambda
   1.316 +                        type = true;
   1.317 +                        break;
   1.318 +                    } else if (depth < 0) {
   1.319 +                        //unbalanced '<', '>' - not a generic type
   1.320 +                        return ParensResult.PARENS;
   1.321 +                    }
   1.322 +                    break;
   1.323 +                default:
   1.324 +                    //this includes EOF
   1.325 +                    return ParensResult.PARENS;
   1.326 +            }
   1.327 +        }
   1.328 +    }
   1.329 +
   1.330 +    enum ParensResult {
   1.331 +        CAST,
   1.332 +        EXPLICIT_LAMBDA,
   1.333 +        IMPLICIT_LAMBDA,
   1.334 +        PARENS;
   1.335 +    }
   1.336 +
   1.337      JCExpression lambdaExpressionOrStatement(JCVariableDecl firstParam, int pos) {
   1.338          ListBuffer<JCVariableDecl> params = new ListBuffer<JCVariableDecl>();
   1.339          params.append(firstParam);
   1.340 @@ -3386,6 +3479,12 @@
   1.341              allowDefaultMethods = true;
   1.342          }
   1.343      }
   1.344 +    void checkIntersectionTypesInCast() {
   1.345 +        if (!allowIntersectionTypesInCast) {
   1.346 +            log.error(token.pos, "intersection.types.in.cast.not.supported.in.source", source.name);
   1.347 +            allowIntersectionTypesInCast = true;
   1.348 +        }
   1.349 +    }
   1.350  
   1.351      /*
   1.352       * a functional source tree and end position mappings

mercurial