diff --git a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/Launcher.java b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/Launcher.java deleted file mode 100644 index 6e73843f7b4bea548187d329a4859a74ef0979fc..0000000000000000000000000000000000000000 --- a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/Launcher.java +++ /dev/null @@ -1,503 +0,0 @@ -/* - * Copyright (c) 2017, 2018, 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. - * - * 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 com.oracle.truffle.r.launcher; - -import static java.lang.Integer.max; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.graalvm.options.OptionCategory; -import org.graalvm.options.OptionDescriptor; -import org.graalvm.options.OptionDescriptors; -import org.graalvm.polyglot.Engine; -import org.graalvm.polyglot.Instrument; -import org.graalvm.polyglot.Language; - -public abstract class Launcher { - private static final boolean STATIC_VERBOSE = Boolean.getBoolean("org.graalvm.launcher.verbose"); - - private Engine tempEngine; - - private final boolean verbose; - - private boolean help; - private boolean helpDebug; - private boolean helpExpert; - private boolean helpTools; - private boolean helpLanguages; - - private OptionCategory helpCategory; - private VersionAction versionAction = VersionAction.None; - - protected enum VersionAction { - None, - PrintAndExit, - PrintAndContinue - } - - public Launcher() { - verbose = STATIC_VERBOSE || Boolean.valueOf(System.getenv("VERBOSE_GRAALVM_LAUNCHERS")); - } - - private Engine getTempEngine() { - if (tempEngine == null) { - tempEngine = Engine.create(); - } - return tempEngine; - } - - void setHelpCategory(OptionCategory helpCategory) { - this.helpCategory = helpCategory; - } - - protected void setVersionAction(VersionAction versionAction) { - this.versionAction = versionAction; - } - - private static class AbortException extends RuntimeException { - static final long serialVersionUID = 4681646279864737876L; - - AbortException(String message) { - super(message, null); - } - - @SuppressWarnings("sync-override") - @Override - public final Throwable fillInStackTrace() { - return null; - } - } - - protected AbortException exit() { - return abort(null, 0); - } - - protected AbortException abort(String message) { - return abort(message, 1); - } - - protected AbortException abort(String message, int exitCode) { - if (message != null) { - System.err.println("ERROR: " + message); - } - System.exit(exitCode); - throw new AbortException(message); - } - - protected abstract void printHelp(OptionCategory maxCategory); - - protected abstract void printVersion(); - - protected abstract void collectArguments(Set<String> options); - - protected static void printPolyglotVersions() { - Engine engine = Engine.create(); - System.out.println("GraalVM Polyglot Engine Version " + engine.getVersion()); - printLanguages(engine, true); - printInstruments(engine, true); - } - - protected boolean isVerbose() { - return verbose; - } - - final boolean runPolyglotAction() { - OptionCategory maxCategory = helpDebug ? OptionCategory.DEBUG : (helpExpert ? OptionCategory.EXPERT : (helpCategory != null ? helpCategory : OptionCategory.USER)); - - switch (versionAction) { - case PrintAndContinue: - printVersion(); - return false; - case PrintAndExit: - printVersion(); - return true; - case None: - break; - } - boolean printDefaultHelp = helpCategory != null || help || ((helpExpert || helpDebug) && !helpTools && !helpLanguages); - Engine tmpEngine = null; - if (printDefaultHelp) { - printHelp(maxCategory); - // @formatter:off - System.out.println(); - System.out.println("Runtime Options:"); - printOption("--polyglot", "Run with all other guest languages accessible."); - // not applicable at the moment - // printOption("--native", "Run using the native launcher with limited Java access (default)."); - // printOption("--native.[option]", "Pass options to the native image; for example, '--native.Xmx1G'. To see available options, use '--native.help'."); - printOption("--jvm", "Run on the Java Virtual Machine with Java access."); - // not applicable at the moment - // printOption("--jvm.[option]", "Pass options to the JVM; for example, '--jvm.classpath=myapp.jar'. To see available options. use '--jvm.help'."); - printOption("--help", "Print this help message."); - printOption("--help:languages", "Print options for all installed languages."); - printOption("--help:tools", "Print options for all installed tools."); - printOption("--help:expert", "Print additional engine options for experts."); - if (helpExpert || helpDebug) { - printOption("--help:debug", "Print additional engine options for debugging."); - } - printOption("--version", "Print version information and exit."); - printOption("--show-version", "Print version information and continue execution."); - // @formatter:on - if (tmpEngine == null) { - tmpEngine = Engine.create(); - } - List<PrintableOption> engineOptions = new ArrayList<>(); - for (OptionDescriptor descriptor : tmpEngine.getOptions()) { - if (!descriptor.getName().startsWith("engine.") && !descriptor.getName().startsWith("compiler.")) { - continue; - } - if (descriptor.getCategory().ordinal() <= maxCategory.ordinal()) { - engineOptions.add(asPrintableOption(descriptor)); - } - } - if (!engineOptions.isEmpty()) { - printOptions(engineOptions, "Engine options:", 2); - } - } - - if (helpLanguages) { - if (tmpEngine == null) { - tmpEngine = Engine.create(); - } - printLanguageOptions(tmpEngine, maxCategory); - } - - if (helpTools) { - if (tmpEngine == null) { - tmpEngine = Engine.create(); - } - printInstrumentOptions(tmpEngine, maxCategory); - } - - if (printDefaultHelp || helpLanguages || helpTools) { - System.out.println("\nSee http://www.oracle.com/technetwork/oracle-labs/program-languages/overview/index.html for more information."); - return true; - } - - return false; - } - - private static void printInstrumentOptions(Engine engine, OptionCategory maxCategory) { - Map<Instrument, List<PrintableOption>> instrumentsOptions = new HashMap<>(); - List<Instrument> instruments = sortedInstruments(engine); - for (Instrument instrument : instruments) { - List<PrintableOption> options = new ArrayList<>(); - for (OptionDescriptor descriptor : instrument.getOptions()) { - if (descriptor.getCategory().ordinal() <= maxCategory.ordinal()) { - options.add(asPrintableOption(descriptor)); - } - } - if (!options.isEmpty()) { - instrumentsOptions.put(instrument, options); - } - } - if (!instrumentsOptions.isEmpty()) { - System.out.println(); - System.out.println("Tool options:"); - for (Instrument instrument : instruments) { - List<PrintableOption> options = instrumentsOptions.get(instrument); - if (options != null) { - printOptions(options, " " + instrument.getName() + ":", 4); - } - } - } - } - - private static void printLanguageOptions(Engine engine, OptionCategory maxCategory) { - Map<Language, List<PrintableOption>> languagesOptions = new HashMap<>(); - List<Language> languages = sortedLanguages(engine); - for (Language language : languages) { - List<PrintableOption> options = new ArrayList<>(); - for (OptionDescriptor descriptor : language.getOptions()) { - if (descriptor.getCategory().ordinal() <= maxCategory.ordinal()) { - options.add(asPrintableOption(descriptor)); - } - } - if (!options.isEmpty()) { - languagesOptions.put(language, options); - } - } - if (!languagesOptions.isEmpty()) { - System.out.println(); - System.out.println("Language Options:"); - for (Language language : languages) { - List<PrintableOption> options = languagesOptions.get(language); - if (options != null) { - printOptions(options, " " + language.getName() + ":", 4); - } - } - } - } - - protected boolean parsePolyglotOption(String defaultOptionPrefix, Map<String, String> options, String arg) { - switch (arg) { - case "--help": - help = true; - return true; - case "--help:debug": - helpDebug = true; - return true; - case "--help:expert": - helpExpert = true; - return true; - case "--help:tools": - helpTools = true; - return true; - case "--help:languages": - helpLanguages = true; - return true; - case "--version": - versionAction = VersionAction.PrintAndExit; - return true; - case "--show-version": - versionAction = VersionAction.PrintAndContinue; - return true; - // case "--polyglot": - // case "--jvm": - // case "--native": - // return false; - default: - // getLanguageId() or null? - if (arg.length() <= 2 || !arg.startsWith("--")) { - return false; - } - int eqIdx = arg.indexOf('='); - String key; - String value; - if (eqIdx < 0) { - key = arg.substring(2); - value = null; - } else { - key = arg.substring(2, eqIdx); - value = arg.substring(eqIdx + 1); - } - - if (value == null) { - value = "true"; - } - int index = key.indexOf('.'); - String group = key; - if (index >= 0) { - group = group.substring(0, index); - } - OptionDescriptor descriptor = findPolyglotOptionDescriptor(group, key); - if (descriptor == null) { - if (defaultOptionPrefix != null) { - descriptor = findPolyglotOptionDescriptor(defaultOptionPrefix, defaultOptionPrefix + "." + key); - } - if (descriptor == null) { - return false; - } - } - try { - descriptor.getKey().getType().convert(value); - } catch (IllegalArgumentException e) { - throw abort(String.format("Invalid argument %s specified. %s'", arg, e.getMessage())); - } - options.put(key, value); - return true; - } - } - - private OptionDescriptor findPolyglotOptionDescriptor(String group, String key) { - OptionDescriptors descriptors = null; - switch (group) { - case "compiler": - case "engine": - descriptors = getTempEngine().getOptions(); - break; - default: - Engine engine = getTempEngine(); - if (engine.getLanguages().containsKey(group)) { - descriptors = engine.getLanguages().get(group).getOptions(); - } else if (engine.getInstruments().containsKey(group)) { - descriptors = engine.getInstruments().get(group).getOptions(); - } - break; - } - if (descriptors == null) { - return null; - } - return descriptors.get(key); - } - - protected static List<Language> sortedLanguages(Engine engine) { - List<Language> languages = new ArrayList<>(engine.getLanguages().values()); - languages.sort(Comparator.comparing(Language::getId)); - return languages; - } - - protected static List<Instrument> sortedInstruments(Engine engine) { - List<Instrument> instruments = new ArrayList<>(engine.getInstruments().values()); - instruments.sort(Comparator.comparing(Instrument::getId)); - return instruments; - } - - protected static void printOption(OptionCategory maxCategory, OptionDescriptor descriptor) { - if (descriptor.getCategory().ordinal() <= maxCategory.ordinal()) { - printOption(asPrintableOption(descriptor)); - } - } - - protected static PrintableOption asPrintableOption(OptionDescriptor descriptor) { - StringBuilder key = new StringBuilder("--"); - key.append(descriptor.getName()); - Object defaultValue = descriptor.getKey().getDefaultValue(); - if (defaultValue instanceof Boolean && defaultValue == Boolean.FALSE) { - // nothing to print - } else { - key.append("=<"); - key.append(descriptor.getKey().getType().getName()); - key.append(">"); - } - return new PrintableOption(key.toString(), descriptor.getHelp()); - } - - protected static void printOption(String option, String description) { - printOption(option, description, 2); - } - - protected static void printOption(String option, String description, int indentation) { - StringBuilder indent = new StringBuilder(indentation); - for (int i = 0; i < indentation; i++) { - indent.append(' '); - } - String desc = description != null ? description : ""; - if (option.length() >= 45 && description != null) { - System.out.println(String.format("%s%s%n%s%-45s%s", indent, option, indent, "", desc)); - } else { - System.out.println(String.format("%s%-45s%s", indent, option, desc)); - } - } - - protected static void printOption(PrintableOption option) { - printOption(option, 2); - } - - protected static void printOption(PrintableOption option, int indentation) { - printOption(option.option, option.description, indentation); - } - - private static final class PrintableOption implements Comparable<PrintableOption> { - final String option; - final String description; - - private PrintableOption(String option, String description) { - this.option = option; - this.description = description; - } - - @Override - public int compareTo(PrintableOption o) { - return this.option.compareTo(o.option); - } - } - - private static void printOptions(List<PrintableOption> options, String title, int indentation) { - Collections.sort(options); - System.out.println(title); - for (PrintableOption option : options) { - printOption(option, indentation); - } - } - - protected enum OS { - Darwin, - Linux, - Solaris; - - private static OS findCurrent() { - final String name = System.getProperty("os.name"); - if (name.equals("Linux")) { - return Linux; - } - if (name.equals("SunOS")) { - return Solaris; - } - if (name.equals("Mac OS X") || name.equals("Darwin")) { - return Darwin; - } - throw new IllegalArgumentException("unknown OS: " + name); - } - - private static final OS current = findCurrent(); - - public static OS getCurrent() { - return current; - } - } - - protected static void printLanguages(Engine engine, boolean printWhenEmpty) { - if (engine.getLanguages().isEmpty()) { - if (printWhenEmpty) { - System.out.println(" Installed Languages: none"); - } - } else { - System.out.println(" Installed Languages:"); - List<Language> languages = new ArrayList<>(engine.getLanguages().size()); - int nameLength = 0; - for (Language language : engine.getLanguages().values()) { - languages.add(language); - nameLength = max(nameLength, language.getName().length()); - } - languages.sort(Comparator.comparing(Language::getId)); - String langFormat = " %-" + nameLength + "s%s version %s%n"; - for (Language language : languages) { - String version = language.getVersion(); - if (version == null || version.length() == 0) { - version = ""; - } - System.out.printf(langFormat, language.getName().isEmpty() ? "Unnamed" : language.getName(), version); - } - } - } - - protected static void printInstruments(Engine engine, boolean printWhenEmpty) { - if (engine.getInstruments().isEmpty()) { - if (printWhenEmpty) { - System.out.println(" Installed Tools: none"); - } - } else { - System.out.println(" Installed Tools:"); - List<Instrument> instruments = sortedInstruments(engine); - int nameLength = 0; - for (Instrument instrument : instruments) { - nameLength = max(nameLength, instrument.getName().length()); - } - String instrumentFormat = " %-" + nameLength + "s version %s%n"; - for (Instrument instrument : instruments) { - String version = instrument.getVersion(); - if (version == null || version.length() == 0) { - version = ""; - } - System.out.printf(instrumentFormat, instrument.getName().isEmpty() ? "Unnamed" : instrument.getName(), version); - } - } - } -} diff --git a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RAbstractLauncher.java b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RAbstractLauncher.java new file mode 100644 index 0000000000000000000000000000000000000000..87fa2f782a004ac798a80ee58f034c7f0cbd388f --- /dev/null +++ b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RAbstractLauncher.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2018, 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. + * + * 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 com.oracle.truffle.r.launcher; + +import java.io.Closeable; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.graalvm.launcher.AbstractLanguageLauncher; +import org.graalvm.options.OptionCategory; +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.Context.Builder; + +import com.oracle.truffle.r.launcher.RCmdOptions.Client; +import com.oracle.truffle.r.launcher.RCmdOptions.RCmdOption; + +public abstract class RAbstractLauncher extends AbstractLanguageLauncher implements Closeable { + + private final Client client; + protected final InputStream inStream; + protected final OutputStream outStream; + protected final OutputStream errStream; + protected RCmdOptions options; + private boolean useJVM; + protected ConsoleHandler consoleHandler; + protected Context context; + + RAbstractLauncher(Client client, String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) { + this.client = client; + assert env == null : "re-enble environment variables"; + this.inStream = inStream; + this.outStream = outStream; + this.errStream = errStream; + } + + @Override + protected List<String> preprocessArguments(List<String> arguments, Map<String, String> polyglotOptions) { + boolean[] recognizedArgsIndices = new boolean[arguments.size()]; + this.options = RCmdOptions.parseArguments(client, arguments.toArray(new String[arguments.size()]), true, recognizedArgsIndices); + List<String> unrecognizedArgs = new ArrayList<>(); + for (int i = 0; i < arguments.size(); i++) { + if ("--jvm".equals(arguments.get(i))) { + useJVM = true; + } else if (!recognizedArgsIndices[i]) { + unrecognizedArgs.add(arguments.get(i)); + } + } + + return unrecognizedArgs; + } + + protected abstract String[] getArguments(); + + @Override + protected void launch(Builder contextBuilder) { + this.consoleHandler = RCommand.createConsoleHandler(options, null, inStream, outStream); + this.context = contextBuilder.allowAllAccess(true).allowHostAccess(useJVM).arguments("R", getArguments()).in(consoleHandler.createInputStream()).out( + outStream).err(errStream).build(); + this.consoleHandler.setContext(context); + } + + @Override + protected String getLanguageId() { + return "R"; + } + + @Override + protected void printHelp(OptionCategory maxCategory) { + RCmdOptions.printHelp(client); + } + + @Override + protected void collectArguments(Set<String> opts) { + for (RCmdOption option : RCmdOption.values()) { + if (option.shortName != null) { + opts.add(option.shortName); + } + if (option.plainName != null) { + opts.add(option.plainName); + } + } + } + + @Override + public void close() { + if (context != null) { + context.close(); + } + } +} diff --git a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCmdOptions.java b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCmdOptions.java index f402d46bd91411a36d0dc25b14d08bc825acf36b..d0cb3e769d91cdb1e8247b2779919f8775cb31d8 100644 --- a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCmdOptions.java +++ b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCmdOptions.java @@ -268,25 +268,44 @@ public final class RCmdOptions { * {@code args[0]} and we do not want to parse that! */ public static RCmdOptions parseArguments(Client client, String[] args, boolean reparse) { + return parseArguments(client, args, reparse, null); + } + + public static RCmdOptions parseArguments(Client client, String[] args, boolean reparse, boolean[] recognizedArgsIndices) { + assert recognizedArgsIndices == null || recognizedArgsIndices.length == args.length; + EnumMap<RCmdOption, Object> options = new EnumMap<>(RCmdOption.class); + if (recognizedArgsIndices != null) { + recognizedArgsIndices[0] = true; + } int i = 1; // skip the first argument (the command) int firstNonOptionArgIndex = args.length; while (i < args.length) { final String arg = args[i]; MatchResult result = matchOption(arg); if (result == null) { - // for Rscript, this means we are done - if (client == Client.RSCRIPT) { + boolean isOption = arg.startsWith("--") || arg.startsWith("-"); + if (!isOption && client == Client.RSCRIPT) { + // for Rscript, this means we are done + if (recognizedArgsIndices != null) { + recognizedArgsIndices[i] = true; + } firstNonOptionArgIndex = i; break; } if (!reparse) { // GnuR does not abort, simply issues a warning System.out.printf("WARNING: unknown option '%s'%n", arg); + if (recognizedArgsIndices != null) { + recognizedArgsIndices[i] = true; + } } i++; continue; } else { + if (recognizedArgsIndices != null) { + recognizedArgsIndices[i] = true; + } RCmdOption option = result.option; if (result.matchedShort && i == args.length - 1) { System.out.println("usage:"); @@ -302,6 +321,9 @@ public final class RCmdOptions { if (result.matchedShort) { i++; setValue(options, option, args[i]); + if (recognizedArgsIndices != null) { + recognizedArgsIndices[i] = true; + } } else { if (option.type == RCmdOptionType.BOOLEAN) { setValue(options, option, true); @@ -318,6 +340,14 @@ public final class RCmdOptions { } } } + + if (recognizedArgsIndices != null) { + // mark the all non-option arguments (the tail) as recognized + for (int j = firstNonOptionArgIndex; j < recognizedArgsIndices.length; j++) { + recognizedArgsIndices[j] = true; + } + } + // adjust for inserted executable name return new RCmdOptions(options, args, firstNonOptionArgIndex); } diff --git a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java index 1a1fdc1f067af61e4118964bba654dcfcbcfc698..3b9e23dc93c426900cb0beb1e03f77b80d0e5e98 100644 --- a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java +++ b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RCommand.java @@ -30,15 +30,11 @@ import java.io.OutputStream; import java.nio.file.Files; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; import java.util.List; -import java.util.Map; -import java.util.Set; import java.util.function.Supplier; -import org.graalvm.options.OptionCategory; import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.Context.Builder; import org.graalvm.polyglot.PolyglotException; import org.graalvm.polyglot.Source; @@ -47,37 +43,6 @@ import com.oracle.truffle.r.launcher.RCmdOptions.RCmdOption; import jline.console.UserInterruptException; -class RLauncher extends Launcher { - - private final Client client; - - RLauncher(Client client) { - this.client = client; - } - - @Override - protected void printHelp(OptionCategory maxCategory) { - RCmdOptions.printHelp(client); - } - - @Override - protected void printVersion() { - RCmdOptions.printVersion(); - } - - @Override - protected void collectArguments(Set<String> options) { - for (RCmdOption option : RCmdOption.values()) { - if (option.shortName != null) { - options.add(option.shortName); - } - if (option.plainName != null) { - options.add(option.plainName); - } - } - } -} - /* * TODO: * @@ -89,40 +54,25 @@ class RLauncher extends Launcher { /** * Emulates the (Gnu)R command as precisely as possible. */ -public class RCommand { - - // CheckStyle: stop system..print check - public static RuntimeException fatal(String message, Object... args) { - System.out.println("FATAL: " + String.format(message, args)); - System.exit(-1); - return new RuntimeException(); - } +public class RCommand extends RAbstractLauncher { - public static RuntimeException fatal(Throwable t, String message, Object... args) { - t.printStackTrace(); - System.out.println("FATAL: " + String.format(message, args)); - System.exit(-1); - return null; + RCommand(String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) { + super(Client.R, env, inStream, outStream, errStream); } - public static void main(String[] args) { - try { - System.exit(doMain(prependCommand(args), null, System.in, System.out, System.err)); - // never returns - throw fatal("main should never return"); - } catch (Throwable t) { - throw fatal(t, "error during REPL execution"); - } + @Override + protected String[] getArguments() { + return options.getArguments(); } - static String[] prependCommand(String[] args) { - String[] result = new String[args.length + 1]; - result[0] = "R"; - System.arraycopy(args, 0, result, 1, args.length); - return result; + @Override + protected void launch(Builder contextBuilder) { + super.launch(contextBuilder); + StartupTiming.timestamp("VM Created"); + StartupTiming.printSummary(); } - public static int doMain(String[] args, String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) { + private int execute(String[] args) { StartupTiming.timestamp("Main Entered"); ArrayList<String> argsList = new ArrayList<>(Arrays.asList(args)); if (System.console() != null) { @@ -143,34 +93,8 @@ public class RCommand { } } - boolean useJVM = false; - RLauncher launcher = new RLauncher(Client.R); - Map<String, String> polyglotOptions = new HashMap<>(); - Iterator<String> iterator = argsList.iterator(); - if (iterator.hasNext()) { - iterator.next(); // skip first argument - while (iterator.hasNext()) { - String arg = iterator.next(); - if ("--jvm".equals(arg)) { - useJVM = true; - iterator.remove(); - } else if (launcher.parsePolyglotOption("R", polyglotOptions, arg)) { - iterator.remove(); - } - } - } - if (launcher.runPolyglotAction()) { - return 0; - } - RCmdOptions options = RCmdOptions.parseArguments(Client.R, argsList.toArray(new String[argsList.size()]), false); - assert env == null || env.length == 0 : "re-enable setting environments"; - ConsoleHandler consoleHandler = createConsoleHandler(options, null, inStream, outStream); - try (Context context = Context.newBuilder().allowAllAccess(true).allowHostAccess(useJVM).options(polyglotOptions).arguments("R", options.getArguments()).in( - consoleHandler.createInputStream()).out(outStream).err(errStream).build()) { - consoleHandler.setContext(context); - StartupTiming.timestamp("VM Created"); - StartupTiming.printSummary(); - + launch(argsList.toArray(new String[0])); + if (context != null) { File srcFile = null; String fileOption = options.getString(RCmdOption.FILE); if (fileOption != null) { @@ -178,6 +102,45 @@ public class RCommand { } return readEvalPrint(context, consoleHandler, srcFile); + } else { + return 0; + } + } + + // CheckStyle: stop system..print check + public static RuntimeException fatal(String message, Object... args) { + System.out.println("FATAL: " + String.format(message, args)); + System.exit(-1); + return new RuntimeException(); + } + + public static RuntimeException fatal(Throwable t, String message, Object... args) { + t.printStackTrace(); + System.out.println("FATAL: " + String.format(message, args)); + System.exit(-1); + return null; + } + + static String[] prependCommand(String[] args) { + String[] result = new String[args.length + 1]; + result[0] = "R"; + System.arraycopy(args, 0, result, 1, args.length); + return result; + } + + public static void main(String[] args) { + try { + System.exit(doMain(prependCommand(args), null, System.in, System.out, System.err)); + // never returns + throw fatal("main should never return"); + } catch (Throwable t) { + throw fatal(t, "error during REPL execution"); + } + } + + public static int doMain(String[] args, String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) { + try (RCommand rcmd = new RCommand(env, inStream, outStream, errStream)) { + return rcmd.execute(args); } } diff --git a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RscriptCommand.java b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RscriptCommand.java index 15c4be2c6404f3332c001d5db43c0e262e069cb5..1142e820780741f27816f2bfb1d0c9fa69a62769 100644 --- a/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RscriptCommand.java +++ b/com.oracle.truffle.r.launcher/src/com/oracle/truffle/r/launcher/RscriptCommand.java @@ -26,14 +26,10 @@ import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; +import java.util.Collections; +import java.util.List; import java.util.Map; -import org.graalvm.options.OptionCategory; -import org.graalvm.polyglot.Context; - import com.oracle.truffle.r.launcher.RCmdOptions.Client; import com.oracle.truffle.r.launcher.RCmdOptions.RCmdOption; @@ -43,11 +39,43 @@ import com.oracle.truffle.r.launcher.RCmdOptions.RCmdOption; * way but the effect is similar. * */ -public class RscriptCommand { +public final class RscriptCommand extends RAbstractLauncher { + + private String[] rScriptArguments; + + RscriptCommand(String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) { + super(Client.RSCRIPT, env, inStream, outStream, errStream); + } + + @Override + protected List<String> preprocessArguments(List<String> arguments, Map<String, String> polyglotOptions) { + List<String> unrecognizedArgs = super.preprocessArguments(arguments, polyglotOptions); + try { + this.rScriptArguments = preprocessRScriptOptions(options); + return unrecognizedArgs; + } catch (PrintHelp e) { + return Collections.singletonList("--help"); + } + } + + @Override + protected String[] getArguments() { + return rScriptArguments; + } + + protected int execute(String[] args) { + launch(args); + if (context != null) { + String fileOption = options.getString(RCmdOption.FILE); + return RCommand.readEvalPrint(context, consoleHandler, fileOption != null ? new File(fileOption) : null); + } else { + return 0; + } + } // CheckStyle: stop system..print check - private static String[] preprocessRScriptOptions(RLauncher launcher, RCmdOptions options) { + private static String[] preprocessRScriptOptions(RCmdOptions options) throws PrintHelp { String[] arguments = options.getArguments(); int resultArgsLength = arguments.length; int firstNonOptionArgIndex = options.getFirstNonOptionArgIndex(); @@ -61,11 +89,7 @@ public class RscriptCommand { // Either -e options are set or first non-option arg is a file if (options.getStringList(RCmdOption.EXPR) == null) { if (firstNonOptionArgIndex == resultArgsLength) { - launcher.setHelpCategory(OptionCategory.USER); - // does not return - if (launcher.runPolyglotAction()) { - System.exit(1); - } + throw new PrintHelp(); } else { options.setValue(RCmdOption.FILE, arguments[firstNonOptionArgIndex]); } @@ -99,50 +123,18 @@ public class RscriptCommand { return adjArgs.toArray(new String[adjArgs.size()]); } + @SuppressWarnings("serial") + static class PrintHelp extends Exception { + } + public static void main(String[] args) { System.exit(doMain(RCommand.prependCommand(args), null, System.in, System.out, System.err)); throw RCommand.fatal("should not reach here"); } public static int doMain(String[] args, String[] env, InputStream inStream, OutputStream outStream, OutputStream errStream) { - assert env == null : "re-enble environment variables"; - - ArrayList<String> argsList = new ArrayList<>(Arrays.asList(args)); - RLauncher launcher = new RLauncher(Client.RSCRIPT) { - @Override - protected void printVersion() { - System.out.print("R scripting front-end version "); - System.out.print(RVersionNumber.FULL); - System.out.println(RVersionNumber.RELEASE_DATE); - } - }; - boolean useJVM = false; - Map<String, String> polyglotOptions = new HashMap<>(); - Iterator<String> iterator = argsList.iterator(); - if (iterator.hasNext()) { - iterator.next(); // skip first argument - while (iterator.hasNext()) { - String arg = iterator.next(); - if ("--jvm".equals(arg)) { - useJVM = true; - iterator.remove(); - } else if (launcher.parsePolyglotOption("R", polyglotOptions, arg)) { - iterator.remove(); - } - } - } - if (launcher.runPolyglotAction()) { - return 0; - } - RCmdOptions options = RCmdOptions.parseArguments(Client.RSCRIPT, argsList.toArray(new String[argsList.size()]), false); - String[] arguments = preprocessRScriptOptions(launcher, options); - - ConsoleHandler consoleHandler = RCommand.createConsoleHandler(options, null, inStream, outStream); - try (Context context = Context.newBuilder().allowAllAccess(true).allowHostAccess(useJVM).options(polyglotOptions).arguments("R", arguments).in(consoleHandler.createInputStream()).out( - outStream).err(errStream).build()) { - consoleHandler.setContext(context); - String fileOption = options.getString(RCmdOption.FILE); - return RCommand.readEvalPrint(context, consoleHandler, fileOption != null ? new File(fileOption) : null); + try (RscriptCommand rcmd = new RscriptCommand(env, inStream, outStream, errStream)) { + return rcmd.execute(args); } } } diff --git a/mx.fastr/suite.py b/mx.fastr/suite.py index 7e17fff9837880a077c7eb7b3c5904bb0a86be44..3d7ca02b4b00d7c08a2ce76cafbfbc1b28b5dd72 100644 --- a/mx.fastr/suite.py +++ b/mx.fastr/suite.py @@ -231,6 +231,7 @@ suite = { "sourceDirs" : ["src"], "dependencies" : [ "sdk:GRAAL_SDK", + "sdk:LAUNCHER_COMMON", "truffle:JLINE", ], "checkstyle" : "com.oracle.truffle.r.runtime",