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