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);
boolean seenModuleOption = false;
for (int idx = 0; idx < args.length; idx++) {
final String opt = args[idx];
if (opt.equals("--es6-module")) {
seenModuleOption = true;
args[idx] = "--language=es6";
break;
}
}
this.moduleMode = seenModuleOption;
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) {
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);
}
}