blob: 5a10526fe5ba1e5076833f7466fd799b863bff4b [file] [log] [blame]
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.api.tree;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Reader;
import java.net.URL;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import jdk.nashorn.api.scripting.NashornException;
import jdk.nashorn.api.scripting.ScriptObjectMirror;
import jdk.nashorn.internal.ir.FunctionNode;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ErrorManager;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.ParserException;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.Source;
import jdk.nashorn.internal.runtime.options.Options;
final class ParserImpl implements Parser {
private final ScriptEnvironment env;
private final boolean moduleMode;
ParserImpl(final String... args) throws IllegalArgumentException {
Objects.requireNonNull(args);
// handle the parser specific "--es6-module" option
boolean seenModuleOption = false;
for (int idx = 0; idx < args.length; idx++) {
final String opt = args[idx];
if (opt.equals("--es6-module")) {
seenModuleOption = true;
/*
* Nashorn parser does not understand parser API specific
* option. This option implies --language=es6. So, we change
* the option to --language=es6. Note that if user specified
* --language=es6 explicitly, that is okay. Nashorn tolerates
* repeated options!
*/
args[idx] = "--language=es6";
break;
}
}
this.moduleMode = seenModuleOption;
// append "--parse-only to signal to the Nashorn that it
// is being used in "parse only" mode.
final String[] newArgs = Arrays.copyOf(args, args.length + 1, String[].class);
newArgs[args.length] = "--parse-only";
final Options options = new Options("nashorn");
options.process(newArgs);
this.env = new ScriptEnvironment(options,
new PrintWriter(System.out), new PrintWriter(System.err));
}
@Override
public CompilationUnitTree parse(final File file, final DiagnosticListener listener) throws IOException, NashornException {
if (moduleMode) {
return parseModule(file, listener);
}
final Source src = Source.sourceFor(Objects.requireNonNull(file).getName(), file);
return translate(makeParser(src, listener).parse());
}
@Override
public CompilationUnitTree parse(final Path path, final DiagnosticListener listener) throws IOException, NashornException {
if (moduleMode) {
return parseModule(path, listener);
}
final Source src = Source.sourceFor(Objects.requireNonNull(path).toString(), path);
return translate(makeParser(src, listener).parse());
}
@Override
public CompilationUnitTree parse(final URL url, final DiagnosticListener listener) throws IOException, NashornException {
if (moduleMode) {
return parseModule(url, listener);
}
final Source src = Source.sourceFor(url.toString(), url);
return translate(makeParser(src, listener).parse());
}
@Override
public CompilationUnitTree parse(final String name, final Reader reader, final DiagnosticListener listener) throws IOException, NashornException {
if (moduleMode) {
return parseModule(name, reader, listener);
}
final Source src = Source.sourceFor(Objects.requireNonNull(name), Objects.requireNonNull(reader));
return translate(makeParser(src, listener).parse());
}
@Override
public CompilationUnitTree parse(final String name, final String code, final DiagnosticListener listener) throws NashornException {
if (moduleMode) {
return parseModule(name, code, listener);
}
final Source src = Source.sourceFor(name, code);
return translate(makeParser(src, listener).parse());
}
@Override
public CompilationUnitTree parse(final ScriptObjectMirror scriptObj, final DiagnosticListener listener) throws NashornException {
if (moduleMode) {
return parseModule(scriptObj, listener);
}
final Map<?, ?> map = Objects.requireNonNull(scriptObj);
if (map.containsKey("script") && map.containsKey("name")) {
final String script = JSType.toString(map.get("script"));
final String name = JSType.toString(map.get("name"));
final Source src = Source.sourceFor(name, script);
return translate(makeParser(src, listener).parse());
} else {
throw new IllegalArgumentException("can't find 'script' and 'name' properties");
}
}
private CompilationUnitTree parseModule(final File file, final DiagnosticListener listener) throws IOException, NashornException {
final Source src = Source.sourceFor(Objects.requireNonNull(file).getName(), file);
return makeModule(src, listener);
}
private CompilationUnitTree parseModule(final Path path, final DiagnosticListener listener) throws IOException, NashornException {
final Source src = Source.sourceFor(Objects.requireNonNull(path).toString(), path);
return makeModule(src, listener);
}
private CompilationUnitTree parseModule(final URL url, final DiagnosticListener listener) throws IOException, NashornException {
final Source src = Source.sourceFor(url.toString(), url);
return makeModule(src, listener);
}
private CompilationUnitTree parseModule(final String name, final Reader reader, final DiagnosticListener listener) throws IOException, NashornException {
final Source src = Source.sourceFor(Objects.requireNonNull(name), Objects.requireNonNull(reader));
return makeModule(src, listener);
}
private CompilationUnitTree parseModule(final String name, final String code, final DiagnosticListener listener) throws NashornException {
final Source src = Source.sourceFor(name, code);
return makeModule(src, listener);
}
private CompilationUnitTree parseModule(final ScriptObjectMirror scriptObj, final DiagnosticListener listener) throws NashornException {
final Map<?, ?> map = Objects.requireNonNull(scriptObj);
if (map.containsKey("script") && map.containsKey("name")) {
final String script = JSType.toString(map.get("script"));
final String name = JSType.toString(map.get("name"));
final Source src = Source.sourceFor(name, script);
return makeModule(src, listener);
} else {
throw new IllegalArgumentException("can't find 'script' and 'name' properties");
}
}
private CompilationUnitTree makeModule(final Source src, final DiagnosticListener listener) {
final FunctionNode modFunc = makeParser(src, listener).parseModule(src.getName());
return new IRTranslator().translate(modFunc);
}
private jdk.nashorn.internal.parser.Parser makeParser(final Source source, final DiagnosticListener listener) {
final ErrorManager errMgr = listener != null ? new ListenerErrorManager(listener) : new Context.ThrowErrorManager();
return new jdk.nashorn.internal.parser.Parser(env, source, errMgr);
}
private static class ListenerErrorManager extends ErrorManager {
private final DiagnosticListener listener;
ListenerErrorManager(final DiagnosticListener listener) {
// null check
listener.getClass();
this.listener = listener;
}
@Override
public void error(final String msg) {
error(new ParserException(msg));
}
@Override
public void error(final ParserException e) {
listener.report(new DiagnosticImpl(e, Diagnostic.Kind.ERROR));
}
@Override
public void warning(final String msg) {
warning(new ParserException(msg));
}
@Override
public void warning(final ParserException e) {
listener.report(new DiagnosticImpl(e, Diagnostic.Kind.WARNING));
}
}
private static CompilationUnitTree translate(final FunctionNode node) {
return new IRTranslator().translate(node);
}
}