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",