ParserImpl.java revision 1739:4a6a1fd3d3dd
1/*
2 * Copyright (c) 2016, 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 */
25package jdk.nashorn.api.tree;
26
27import java.io.File;
28import java.io.IOException;
29import java.io.PrintWriter;
30import java.io.Reader;
31import java.net.URL;
32import java.nio.file.Path;
33import java.util.Arrays;
34import java.util.Map;
35import java.util.Objects;
36import jdk.nashorn.api.scripting.NashornException;
37import jdk.nashorn.api.scripting.ScriptObjectMirror;
38import jdk.nashorn.internal.ir.FunctionNode;
39import jdk.nashorn.internal.runtime.Context;
40import jdk.nashorn.internal.runtime.ErrorManager;
41import jdk.nashorn.internal.runtime.JSType;
42import jdk.nashorn.internal.runtime.ParserException;
43import jdk.nashorn.internal.runtime.ScriptEnvironment;
44import jdk.nashorn.internal.runtime.Source;
45import jdk.nashorn.internal.runtime.options.Options;
46
47final class ParserImpl implements Parser {
48
49    private final ScriptEnvironment env;
50    private final boolean moduleMode;
51
52    ParserImpl(final String... args) throws IllegalArgumentException {
53        Objects.requireNonNull(args);
54
55        // handle the parser specific "--es6-module" option
56        boolean seenModuleOption = false;
57        for (int idx = 0; idx < args.length; idx++) {
58            final String opt = args[idx];
59            if (opt.equals("--es6-module")) {
60                seenModuleOption = true;
61                /*
62                 * Nashorn parser does not understand parser API specific
63                 * option. This option implies --language=es6. So, we change
64                 * the option to --language=es6. Note that if user specified
65                 * --language=es6 explicitly, that is okay. Nashorn tolerates
66                 * repeated options!
67                 */
68                args[idx] = "--language=es6";
69                break;
70            }
71        }
72        this.moduleMode = seenModuleOption;
73
74        // append "--parse-only to signal to the Nashorn that it
75        // is being used in "parse only" mode.
76        String[] newArgs = Arrays.copyOf(args, args.length + 1, String[].class);
77        newArgs[args.length] = "--parse-only";
78        Options options = new Options("nashorn");
79        options.process(newArgs);
80        this.env = new ScriptEnvironment(options,
81                new PrintWriter(System.out), new PrintWriter(System.err));
82    }
83
84    @Override
85    public CompilationUnitTree parse(final File file, final DiagnosticListener listener) throws IOException, NashornException {
86        if (moduleMode) {
87            return parseModule(file, listener);
88        }
89        final Source src = Source.sourceFor(Objects.requireNonNull(file).getName(), file);
90        return translate(makeParser(src, listener).parse());
91    }
92
93    @Override
94    public CompilationUnitTree parse(final Path path, final DiagnosticListener listener) throws IOException, NashornException {
95        if (moduleMode) {
96            return parseModule(path, listener);
97        }
98        final Source src = Source.sourceFor(Objects.requireNonNull(path).toString(), path);
99        return translate(makeParser(src, listener).parse());
100    }
101
102    @Override
103    public CompilationUnitTree parse(final URL url, final DiagnosticListener listener) throws IOException, NashornException {
104        if (moduleMode) {
105            return parseModule(url, listener);
106        }
107        final Source src = Source.sourceFor(url.toString(), url);
108        return translate(makeParser(src, listener).parse());
109    }
110
111    @Override
112    public CompilationUnitTree parse(final String name, final Reader reader, final DiagnosticListener listener) throws IOException, NashornException {
113        if (moduleMode) {
114            return parseModule(name, reader, listener);
115        }
116        final Source src = Source.sourceFor(Objects.requireNonNull(name), Objects.requireNonNull(reader));
117        return translate(makeParser(src, listener).parse());
118    }
119
120    @Override
121    public CompilationUnitTree parse(final String name, final String code, final DiagnosticListener listener) throws NashornException {
122        if (moduleMode) {
123            return parseModule(name, code, listener);
124        }
125        final Source src = Source.sourceFor(name, code);
126        return translate(makeParser(src, listener).parse());
127    }
128
129    @Override
130    public CompilationUnitTree parse(final ScriptObjectMirror scriptObj, final DiagnosticListener listener) throws NashornException {
131        if (moduleMode) {
132            return parseModule(scriptObj, listener);
133        }
134        final Map<?, ?> map = Objects.requireNonNull(scriptObj);
135        if (map.containsKey("script") && map.containsKey("name")) {
136            final String script = JSType.toString(map.get("script"));
137            final String name = JSType.toString(map.get("name"));
138            final Source src = Source.sourceFor(name, script);
139            return translate(makeParser(src, listener).parse());
140        } else {
141            throw new IllegalArgumentException("can't find 'script' and 'name' properties");
142        }
143    }
144
145    private CompilationUnitTree parseModule(File file, DiagnosticListener listener) throws IOException, NashornException {
146        final Source src = Source.sourceFor(Objects.requireNonNull(file).getName(), file);
147        return makeModule(src, listener);
148    }
149
150    private CompilationUnitTree parseModule(Path path, DiagnosticListener listener) throws IOException, NashornException {
151        final Source src = Source.sourceFor(Objects.requireNonNull(path).toString(), path);
152        return makeModule(src, listener);
153    }
154
155    private CompilationUnitTree parseModule(URL url, DiagnosticListener listener) throws IOException, NashornException {
156        final Source src = Source.sourceFor(url.toString(), url);
157        return makeModule(src, listener);
158    }
159
160    private CompilationUnitTree parseModule(String name, Reader reader, DiagnosticListener listener) throws IOException, NashornException {
161        final Source src = Source.sourceFor(Objects.requireNonNull(name), Objects.requireNonNull(reader));
162        return makeModule(src, listener);
163    }
164
165    private CompilationUnitTree parseModule(String name, String code, DiagnosticListener listener) throws NashornException {
166        final Source src = Source.sourceFor(name, code);
167        return makeModule(src, listener);
168    }
169
170    private CompilationUnitTree parseModule(ScriptObjectMirror scriptObj, DiagnosticListener listener) throws NashornException {
171        final Map<?, ?> map = Objects.requireNonNull(scriptObj);
172        if (map.containsKey("script") && map.containsKey("name")) {
173            final String script = JSType.toString(map.get("script"));
174            final String name = JSType.toString(map.get("name"));
175            final Source src = Source.sourceFor(name, script);
176            return makeModule(src, listener);
177        } else {
178            throw new IllegalArgumentException("can't find 'script' and 'name' properties");
179        }
180    }
181
182    private CompilationUnitTree makeModule(Source src, DiagnosticListener listener) {
183        final FunctionNode modFunc = makeParser(src, listener).parseModule(src.getName());
184        return new IRTranslator().translate(modFunc);
185    }
186
187    private jdk.nashorn.internal.parser.Parser makeParser(final Source source, final DiagnosticListener listener) {
188        final ErrorManager errMgr = listener != null ? new ListenerErrorManager(listener) : new Context.ThrowErrorManager();
189        return new jdk.nashorn.internal.parser.Parser(env, source, errMgr);
190    }
191
192    private static class ListenerErrorManager extends ErrorManager {
193
194        private final DiagnosticListener listener;
195
196        ListenerErrorManager(final DiagnosticListener listener) {
197            // null check
198            listener.getClass();
199            this.listener = listener;
200        }
201
202        @Override
203        public void error(final String msg) {
204            error(new ParserException(msg));
205        }
206
207        @Override
208        public void error(final ParserException e) {
209            listener.report(new DiagnosticImpl(e, Diagnostic.Kind.ERROR));
210        }
211
212        @Override
213        public void warning(final String msg) {
214            warning(new ParserException(msg));
215        }
216
217        @Override
218        public void warning(final ParserException e) {
219            listener.report(new DiagnosticImpl(e, Diagnostic.Kind.WARNING));
220        }
221    }
222
223    private static CompilationUnitTree translate(final FunctionNode node) {
224        return new IRTranslator().translate(node);
225    }
226}
227