langtools/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java
changeset 33362 65ec6de1d6b4
child 34752 9c262a013456
equal deleted inserted replaced
33361:1c96344ecd49 33362:65ec6de1d6b4
       
     1 /*
       
     2  * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 package jdk.jshell;
       
    26 
       
    27 import com.sun.tools.javac.code.TypeTag;
       
    28 import com.sun.tools.javac.parser.JavacParser;
       
    29 import com.sun.tools.javac.parser.ParserFactory;
       
    30 import com.sun.tools.javac.parser.Tokens.Comment;
       
    31 import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle;
       
    32 import com.sun.tools.javac.parser.Tokens.Token;
       
    33 import static com.sun.tools.javac.parser.Tokens.TokenKind.CLASS;
       
    34 import static com.sun.tools.javac.parser.Tokens.TokenKind.COLON;
       
    35 import static com.sun.tools.javac.parser.Tokens.TokenKind.ENUM;
       
    36 import static com.sun.tools.javac.parser.Tokens.TokenKind.EOF;
       
    37 import static com.sun.tools.javac.parser.Tokens.TokenKind.IMPORT;
       
    38 import static com.sun.tools.javac.parser.Tokens.TokenKind.INTERFACE;
       
    39 import static com.sun.tools.javac.parser.Tokens.TokenKind.LPAREN;
       
    40 import static com.sun.tools.javac.parser.Tokens.TokenKind.MONKEYS_AT;
       
    41 import static com.sun.tools.javac.parser.Tokens.TokenKind.PACKAGE;
       
    42 import static com.sun.tools.javac.parser.Tokens.TokenKind.SEMI;
       
    43 import static com.sun.tools.javac.parser.Tokens.TokenKind.VOID;
       
    44 import com.sun.tools.javac.tree.JCTree;
       
    45 import com.sun.tools.javac.tree.JCTree.JCAnnotation;
       
    46 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
       
    47 import com.sun.tools.javac.tree.JCTree.JCExpression;
       
    48 import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
       
    49 import com.sun.tools.javac.tree.JCTree.JCModifiers;
       
    50 import com.sun.tools.javac.tree.JCTree.JCPackageDecl;
       
    51 import com.sun.tools.javac.tree.JCTree.JCStatement;
       
    52 import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
       
    53 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
       
    54 import com.sun.tools.javac.tree.JCTree.Tag;
       
    55 import static com.sun.tools.javac.tree.JCTree.Tag.IDENT;
       
    56 import com.sun.tools.javac.util.List;
       
    57 import com.sun.tools.javac.util.ListBuffer;
       
    58 import com.sun.tools.javac.util.Name;
       
    59 import com.sun.tools.javac.util.Position;
       
    60 
       
    61 /**
       
    62  * This is a subclass of JavacParser which overrides one method with a modified
       
    63  * verson of that method designed to allow parsing of one "snippet" of Java
       
    64  * code without the surrounding context of class, method, etc.
       
    65  * Accepts an expression, a statement, an import, or the declaration of a
       
    66  * method, variable, or type (class, interface, ...).
       
    67  */
       
    68 class ReplParser extends JavacParser {
       
    69 
       
    70     public ReplParser(ParserFactory fac,
       
    71             com.sun.tools.javac.parser.Lexer S,
       
    72             boolean keepDocComments,
       
    73             boolean keepLineMap,
       
    74             boolean keepEndPositions) {
       
    75         super(fac, S, keepDocComments, keepLineMap, keepEndPositions);
       
    76     }
       
    77 
       
    78     /**
       
    79      * As faithful a clone of the overridden method as possible while still
       
    80      * achieving the goal of allowing the parse of a stand-alone snippet.
       
    81      * As a result, some variables are assigned and never used, tests are
       
    82      * always true, loops don't, etc.  This is to allow easy transition as the
       
    83      * underlying method changes.
       
    84      * @return a snippet wrapped in a compilation unit
       
    85      */
       
    86     @Override
       
    87     public JCCompilationUnit parseCompilationUnit() {
       
    88         Token firstToken = token;
       
    89         JCModifiers mods = null;
       
    90         boolean seenImport = false;
       
    91         boolean seenPackage = false;
       
    92         ListBuffer<JCTree> defs = new ListBuffer<>();
       
    93         if (token.kind == MONKEYS_AT) {
       
    94             mods = modifiersOpt();
       
    95         }
       
    96 
       
    97         if (token.kind == PACKAGE) {
       
    98             int packagePos = token.pos;
       
    99             List<JCAnnotation> annotations = List.nil();
       
   100             seenPackage = true;
       
   101             if (mods != null) {
       
   102                 checkNoMods(mods.flags);
       
   103                 annotations = mods.annotations;
       
   104                 mods = null;
       
   105             }
       
   106             nextToken();
       
   107             JCExpression pid = qualident(false);
       
   108             accept(SEMI);
       
   109             JCPackageDecl pd = F.at(packagePos).PackageDecl(annotations, pid);
       
   110             attach(pd, firstToken.comment(CommentStyle.JAVADOC));
       
   111             storeEnd(pd, token.pos);
       
   112             defs.append(pd);
       
   113         }
       
   114 
       
   115         boolean firstTypeDecl = true;
       
   116         while (token.kind != EOF) {
       
   117             if (token.pos > 0 && token.pos <= endPosTable.errorEndPos) {
       
   118                 // error recovery
       
   119                 skip(true, false, false, false);
       
   120                 if (token.kind == EOF) {
       
   121                     break;
       
   122                 }
       
   123             }
       
   124             if (mods == null && token.kind == IMPORT) {
       
   125                 seenImport = true;
       
   126                 defs.append(importDeclaration());
       
   127             } else {
       
   128                 Comment docComment = token.comment(CommentStyle.JAVADOC);
       
   129                 if (firstTypeDecl && !seenImport && !seenPackage) {
       
   130                     docComment = firstToken.comment(CommentStyle.JAVADOC);
       
   131                 }
       
   132                 List<? extends JCTree> udefs = replUnit(mods, docComment);
       
   133                // if (def instanceof JCExpressionStatement)
       
   134                 //     def = ((JCExpressionStatement)def).expr;
       
   135                 for (JCTree def : udefs) {
       
   136                     defs.append(def);
       
   137                 }
       
   138                 mods = null;
       
   139                 firstTypeDecl = false;
       
   140             }
       
   141             break;  // Remove to process more than one snippet
       
   142         }
       
   143         List<JCTree> rdefs = defs.toList();
       
   144         class ReplUnit extends JCCompilationUnit {
       
   145 
       
   146             public ReplUnit(List<JCTree> defs) {
       
   147                 super(defs);
       
   148             }
       
   149         }
       
   150         JCCompilationUnit toplevel = new ReplUnit(rdefs);
       
   151         if (rdefs.isEmpty()) {
       
   152             storeEnd(toplevel, S.prevToken().endPos);
       
   153         }
       
   154         toplevel.lineMap = S.getLineMap();
       
   155         this.endPosTable.setParser(null); // remove reference to parser
       
   156         toplevel.endPositions = this.endPosTable;
       
   157         return toplevel;
       
   158     }
       
   159 
       
   160     @SuppressWarnings("fallthrough")
       
   161      List<? extends JCTree> replUnit(JCModifiers pmods, Comment dc) {
       
   162         switch (token.kind) {
       
   163             case EOF:
       
   164                 return List.nil();
       
   165             case RBRACE:
       
   166             case CASE:
       
   167             case DEFAULT:
       
   168                 // These are illegal, fall through to handle as illegal statement
       
   169             case LBRACE:
       
   170             case IF:
       
   171             case FOR:
       
   172             case WHILE:
       
   173             case DO:
       
   174             case TRY:
       
   175             case SWITCH:
       
   176             case RETURN:
       
   177             case THROW:
       
   178             case BREAK:
       
   179             case CONTINUE:
       
   180             case SEMI:
       
   181             case ELSE:
       
   182             case FINALLY:
       
   183             case CATCH:
       
   184             case ASSERT:
       
   185                 return List.<JCTree>of(parseStatement());
       
   186             case SYNCHRONIZED:
       
   187                 if (peekToken(LPAREN)) {
       
   188                     return List.<JCTree>of(parseStatement());
       
   189                 }
       
   190                 //fall-through
       
   191             default:
       
   192                 JCModifiers mods = modifiersOpt(pmods);
       
   193                 if (token.kind == CLASS
       
   194                         || token.kind == INTERFACE
       
   195                         || token.kind == ENUM) {
       
   196                     return List.<JCTree>of(classOrInterfaceOrEnumDeclaration(mods, dc));
       
   197                 } else {
       
   198                     int pos = token.pos;
       
   199                     List<JCTypeParameter> typarams = typeParametersOpt();
       
   200                     // if there are type parameters but no modifiers, save the start
       
   201                     // position of the method in the modifiers.
       
   202                     if (typarams.nonEmpty() && mods.pos == Position.NOPOS) {
       
   203                         mods.pos = pos;
       
   204                         storeEnd(mods, pos);
       
   205                     }
       
   206                     List<JCAnnotation> annosAfterParams = annotationsOpt(Tag.ANNOTATION);
       
   207 
       
   208                     if (annosAfterParams.nonEmpty()) {
       
   209                         checkAnnotationsAfterTypeParams(annosAfterParams.head.pos);
       
   210                         mods.annotations = mods.annotations.appendList(annosAfterParams);
       
   211                         if (mods.pos == Position.NOPOS) {
       
   212                             mods.pos = mods.annotations.head.pos;
       
   213                         }
       
   214                     }
       
   215 
       
   216                     Token prevToken = token;
       
   217                     pos = token.pos;
       
   218                     JCExpression t;
       
   219                     boolean isVoid = token.kind == VOID;
       
   220                     if (isVoid) {
       
   221                         t = to(F.at(pos).TypeIdent(TypeTag.VOID));
       
   222                         nextToken();
       
   223                     } else {
       
   224                         // return type of method, declared type of variable, or an expression
       
   225                         t = term(EXPR | TYPE);
       
   226                     }
       
   227                     if (token.kind == COLON && t.hasTag(IDENT)) {
       
   228                         // labelled statement
       
   229                         nextToken();
       
   230                         JCStatement stat = parseStatement();
       
   231                         return List.<JCTree>of(F.at(pos).Labelled(prevToken.name(), stat));
       
   232                     } else if ((isVoid || (lastmode & TYPE) != 0) && LAX_IDENTIFIER.accepts(token.kind)) {
       
   233                         // we have "Type Ident", so we can assume it is variable or method declaration
       
   234                         pos = token.pos;
       
   235                         Name name = ident();
       
   236                         if (token.kind == LPAREN) {
       
   237                         // method declaration
       
   238                             //mods.flags |= Flags.STATIC;
       
   239                             return List.of(methodDeclaratorRest(
       
   240                                     pos, mods, t, name, typarams,
       
   241                                     false, isVoid, dc));
       
   242                         } else if (!isVoid && typarams.isEmpty()) {
       
   243                         // variable declaration
       
   244                             //mods.flags |= Flags.STATIC;
       
   245                             List<JCTree> defs
       
   246                                     = variableDeclaratorsRest(pos, mods, t, name, false, dc,
       
   247                                             new ListBuffer<JCTree>()).toList();
       
   248                             accept(SEMI);
       
   249                             storeEnd(defs.last(), S.prevToken().endPos);
       
   250                             return defs;
       
   251                         } else {
       
   252                             // malformed declaration, return error
       
   253                             pos = token.pos;
       
   254                             List<JCTree> err = isVoid
       
   255                                     ? List.<JCTree>of(toP(F.at(pos).MethodDef(mods, name, t, typarams,
       
   256                                                             List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, null)))
       
   257                                     : null;
       
   258                             return List.<JCTree>of(syntaxError(token.pos, err, "expected", LPAREN));
       
   259                         }
       
   260                     } else if (!typarams.isEmpty()) {
       
   261                         // type parameters on non-variable non-method -- error
       
   262                         return List.<JCTree>of(syntaxError(token.pos, "illegal.start.of.type"));
       
   263                     } else {
       
   264                         // expression-statement or expression to evaluate
       
   265                         JCExpressionStatement expr = toP(F.at(pos).Exec(t));
       
   266                         return List.<JCTree>of(expr);
       
   267                     }
       
   268 
       
   269                 }
       
   270         }
       
   271     }
       
   272 }