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 
TrialParser(ParserFactory fac, com.sun.tools.javac.parser.Lexer S, boolean keepDocComments, boolean keepLineMap, boolean keepEndPositions)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
parseCompilationUnit()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 
aUnit(JCModifiers pmods, Comment dc)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(classOrInterfaceOrEnumDeclaration(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 }
256