1 /*
   2  * Copyright (c) 2015, 2018, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import com.sun.tools.javac.code.Source.Feature;
  25 import com.sun.tools.javac.code.TypeTag;
  26 import com.sun.tools.javac.parser.JavacParser;
  27 import com.sun.tools.javac.parser.ParserFactory;
  28 import com.sun.tools.javac.parser.Tokens.Comment;
  29 import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle;
  30 import com.sun.tools.javac.parser.Tokens.Token;
  31 import static com.sun.tools.javac.parser.Tokens.TokenKind.CLASS;
  32 import static com.sun.tools.javac.parser.Tokens.TokenKind.COLON;
  33 import static com.sun.tools.javac.parser.Tokens.TokenKind.ENUM;
  34 import static com.sun.tools.javac.parser.Tokens.TokenKind.EOF;
  35 import static com.sun.tools.javac.parser.Tokens.TokenKind.IMPORT;
  36 import static com.sun.tools.javac.parser.Tokens.TokenKind.INTERFACE;
  37 import static com.sun.tools.javac.parser.Tokens.TokenKind.LPAREN;
  38 import static com.sun.tools.javac.parser.Tokens.TokenKind.MONKEYS_AT;
  39 import static com.sun.tools.javac.parser.Tokens.TokenKind.PACKAGE;
  40 import static com.sun.tools.javac.parser.Tokens.TokenKind.SEMI;
  41 import static com.sun.tools.javac.parser.Tokens.TokenKind.VOID;
  42 import com.sun.tools.javac.tree.JCTree;
  43 import com.sun.tools.javac.tree.JCTree.JCAnnotation;
  44 import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
  45 import com.sun.tools.javac.tree.JCTree.JCExpression;
  46 import com.sun.tools.javac.tree.JCTree.JCExpressionStatement;
  47 import com.sun.tools.javac.tree.JCTree.JCModifiers;
  48 import com.sun.tools.javac.tree.JCTree.JCPackageDecl;
  49 import com.sun.tools.javac.tree.JCTree.JCStatement;
  50 import com.sun.tools.javac.tree.JCTree.JCTypeParameter;
  51 import com.sun.tools.javac.tree.JCTree.JCVariableDecl;
  52 import com.sun.tools.javac.tree.JCTree.Tag;
  53 import static com.sun.tools.javac.tree.JCTree.Tag.IDENT;
  54 import com.sun.tools.javac.util.List;
  55 import com.sun.tools.javac.util.ListBuffer;
  56 import com.sun.tools.javac.util.Name;
  57 import com.sun.tools.javac.util.Position;
  58 import com.sun.tools.javac.resources.CompilerProperties.Errors;
  59 
  60 /**
  61  *
  62  * @author Robert Field
  63  */
  64 class TrialParser extends JavacParser {
  65 
  66     public TrialParser(ParserFactory fac,
  67             com.sun.tools.javac.parser.Lexer S,
  68             boolean keepDocComments,
  69             boolean keepLineMap,
  70             boolean keepEndPositions) {
  71         super(fac, S, keepDocComments, keepLineMap, keepEndPositions);
  72     }
  73 
  74     @Override
  75     public JCCompilationUnit parseCompilationUnit() {
  76         Token firstToken = token;
  77         JCModifiers mods = null;
  78         boolean seenImport = false;
  79         boolean seenPackage = false;
  80         ListBuffer<JCTree> defs = new ListBuffer<>();
  81         if (token.kind == MONKEYS_AT) {
  82             mods = modifiersOpt();
  83         }
  84 
  85         if (token.kind == PACKAGE) {
  86             int packagePos = token.pos;
  87             List<JCAnnotation> annotations = List.nil();
  88             seenPackage = true;
  89             if (mods != null) {
  90                 checkNoMods(mods.flags);
  91                 annotations = mods.annotations;
  92                 mods = null;
  93             }
  94             nextToken();
  95             JCExpression pid = qualident(false);
  96             accept(SEMI);
  97             JCPackageDecl pd = F.at(packagePos).PackageDecl(annotations, pid);
  98             attach(pd, firstToken.comment(CommentStyle.JAVADOC));
  99             storeEnd(pd, token.pos);
 100             defs.append(pd);
 101         }
 102 
 103         boolean firstTypeDecl = true;
 104         while (token.kind != EOF) {
 105             if (token.pos > 0 && token.pos <= endPosTable.errorEndPos) {
 106                 // error recovery
 107                 skip(true, false, false, false);
 108                 if (token.kind == EOF) {
 109                     break;
 110                 }
 111             }
 112             if (mods == null && token.kind == IMPORT) {
 113                 seenImport = true;
 114                 defs.append(importDeclaration());
 115                 break;
 116             } else {
 117                 Comment docComment = token.comment(CommentStyle.JAVADOC);
 118                 if (firstTypeDecl && !seenImport && !seenPackage) {
 119                     docComment = firstToken.comment(CommentStyle.JAVADOC);
 120                 }
 121                 List<? extends JCTree> udefs = aUnit(mods, docComment);
 122                 for (JCTree def : udefs) {
 123                     defs.append(def);
 124                 }
 125                 mods = null;
 126                 firstTypeDecl = false;
 127                 break;
 128             }
 129         }
 130         List<JCTree> rdefs = defs.toList();
 131         class TrialUnit extends JCCompilationUnit {
 132 
 133             public TrialUnit(List<JCTree> defs) {
 134                 super(defs);
 135             }
 136         }
 137         JCCompilationUnit toplevel = new TrialUnit(rdefs);
 138         if (rdefs.isEmpty()) {
 139             storeEnd(toplevel, S.prevToken().endPos);
 140         }
 141         toplevel.lineMap = S.getLineMap();
 142         this.endPosTable.setParser(null); // remove reference to parser
 143         toplevel.endPositions = this.endPosTable;
 144         return toplevel;
 145     }
 146 
 147     List<? extends JCTree> aUnit(JCModifiers pmods, Comment dc) {
 148         switch (token.kind) {
 149             case EOF:
 150                 return List.nil();
 151             case RBRACE:
 152             case CASE:
 153             case DEFAULT:
 154                 // These are illegal, fall through to handle as illegal statement
 155             case LBRACE:
 156             case IF:
 157             case FOR:
 158             case WHILE:
 159             case DO:
 160             case TRY:
 161             case SWITCH:
 162             case SYNCHRONIZED:
 163             case RETURN:
 164             case THROW:
 165             case BREAK:
 166             case CONTINUE:
 167             case SEMI:
 168             case ELSE:
 169             case FINALLY:
 170             case CATCH:
 171             case ASSERT:
 172                 return List.<JCTree>of(parseStatement());
 173             default:
 174                 JCModifiers mods = modifiersOpt(pmods);
 175                 if (token.kind == CLASS
 176                         || token.kind == INTERFACE
 177                         || token.kind == ENUM) {
 178                     return List.<JCTree>of(classOrRecordOrInterfaceOrEnumDeclaration(mods, dc));
 179                 } else {
 180                     int pos = token.pos;
 181                     List<JCTypeParameter> typarams = typeParametersOpt();
 182                 // if there are type parameters but no modifiers, save the start
 183                     // position of the method in the modifiers.
 184                     if (typarams.nonEmpty() && mods.pos == Position.NOPOS) {
 185                         mods.pos = pos;
 186                         storeEnd(mods, pos);
 187                     }
 188                     List<JCAnnotation> annosAfterParams = annotationsOpt(Tag.ANNOTATION);
 189 
 190                     if (annosAfterParams.nonEmpty()) {
 191                         checkSourceLevel(annosAfterParams.head.pos, Feature.ANNOTATIONS_AFTER_TYPE_PARAMS);
 192                         mods.annotations = mods.annotations.appendList(annosAfterParams);
 193                         if (mods.pos == Position.NOPOS) {
 194                             mods.pos = mods.annotations.head.pos;
 195                         }
 196                     }
 197 
 198                     Token prevToken = token;
 199                     pos = token.pos;
 200                     JCExpression t;
 201                     boolean isVoid = token.kind == VOID;
 202                     if (isVoid) {
 203                         t = to(F.at(pos).TypeIdent(TypeTag.VOID));
 204                         nextToken();
 205                     } else {
 206                         // return type of method, declared type of variable, or an expression
 207                         t = term(EXPR | TYPE);
 208                     }
 209                     if (token.kind == COLON && t.hasTag(IDENT)) {
 210                         // labelled statement
 211                         nextToken();
 212                         JCStatement stat = parseStatement();
 213                         return List.<JCTree>of(F.at(pos).Labelled(prevToken.name(), stat));
 214                     } else if ((isVoid || (lastmode & TYPE) != 0) && LAX_IDENTIFIER.accepts(token.kind)) {
 215                         // we have "Type Ident", so we can assume it is variable or method declaration
 216                         pos = token.pos;
 217                         Name name = ident();
 218                         if (token.kind == LPAREN) {
 219                         // method declaration
 220                             //mods.flags |= Flags.STATIC;
 221                             return List.of(methodDeclaratorRest(
 222                                     pos, mods, t, name, typarams,
 223                                     false, isVoid, dc));
 224                         } else if (!isVoid && typarams.isEmpty()) {
 225                         // variable declaration
 226                             //mods.flags |= Flags.STATIC;
 227                             List<JCTree> defs
 228                                     = variableDeclaratorsRest(pos, mods, t, name, false, dc,
 229                                             new ListBuffer<JCTree>(), true).toList();
 230                             accept(SEMI);
 231                             storeEnd(defs.last(), S.prevToken().endPos);
 232                             return defs;
 233                         } else {
 234                             // malformed declaration, return error
 235                             pos = token.pos;
 236                             List<JCTree> err = isVoid
 237                                     ? List.<JCTree>of(toP(F.at(pos).MethodDef(mods, name, t, typarams,
 238                                                             List.<JCVariableDecl>nil(), List.<JCExpression>nil(), null, null)))
 239                                     : null;
 240                             return List.<JCTree>of(syntaxError(token.pos, err, Errors.Expected(LPAREN)));
 241                         }
 242                     } else if (!typarams.isEmpty()) {
 243                         // type parameters on non-variable non-method -- error
 244                         return List.<JCTree>of(syntaxError(token.pos, Errors.IllegalStartOfType));
 245                     } else {
 246                         // expression-statement or expression to evaluate
 247                         accept(SEMI);
 248                         JCExpressionStatement expr = toP(F.at(pos).Exec(t));
 249                         return List.<JCTree>of(expr);
 250                     }
 251 
 252                 }
 253         }
 254     }
 255 }