diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java index cc668a856e86c2abd0db1876c3b47278f2739e20..c47155062d8634fd1b9d7b965304af8a6ccc7779 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/EmbeddedConsoleHandler.java @@ -38,7 +38,7 @@ import com.oracle.truffle.r.runtime.ffi.RFFIFactory; * have be lazy about that. * */ -public class EmbeddedConsoleHandler implements ConsoleHandler { +public class EmbeddedConsoleHandler extends ConsoleHandler { private final RStartParams startParams; /** diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleCompleter.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleCompleter.java index 2c18397bf7f432a3a4d80572fef3d634c022cdb6..eaeeb329ea451ca404e91fe0c99f69592298e2e8 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleCompleter.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleCompleter.java @@ -22,20 +22,23 @@ */ package com.oracle.truffle.r.engine.shell; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + import com.oracle.truffle.api.frame.MaterializedFrame; import com.oracle.truffle.r.nodes.function.PromiseHelperNode; import com.oracle.truffle.r.runtime.RCaller; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.context.ConsoleHandler; import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.context.RContext.RCloseable; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RList; import com.oracle.truffle.r.runtime.data.RPromise; import com.oracle.truffle.r.runtime.data.model.RAbstractStringVector; import com.oracle.truffle.r.runtime.env.REnvironment; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; + import jline.console.completer.Completer; public class JLineConsoleCompleter implements Completer { @@ -64,50 +67,54 @@ public class JLineConsoleCompleter implements Completer { return cursor; } - private static int completeImpl(String buffer, int cursor, List<CharSequence> candidates) { + @SuppressWarnings("try") + private int completeImpl(String buffer, int cursor, List<CharSequence> candidates) { if (buffer.isEmpty()) { return cursor; } - REnvironment utils = REnvironment.getRegisteredNamespace("utils"); - Object o = utils.get(".completeToken"); - if (o instanceof RPromise) { - o = PromiseHelperNode.evaluateSlowPath(null, (RPromise) o); - } - RFunction completeToken; - if (o instanceof RFunction) { - completeToken = (RFunction) o; - } else { - return cursor; - } + try (RCloseable c = RContext.withinContext(console.getContext())) { - o = utils.get(".CompletionEnv"); - if (!(o instanceof RPromise)) { - return cursor; - } - REnvironment env = (REnvironment) PromiseHelperNode.evaluateSlowPath(null, (RPromise) o); - int start = getStart(buffer, env, cursor); - env.safePut("start", start); - env.safePut("end", cursor); - env.safePut("linebuffer", buffer); - env.safePut("token", buffer.substring(start, cursor)); - - MaterializedFrame callingFrame = REnvironment.globalEnv().getFrame(); - RContext.getEngine().evalFunction(completeToken, callingFrame, RCaller.createInvalid(callingFrame), null, new Object[]{}); - - o = env.get("comps"); - if (!(o instanceof RAbstractStringVector)) { - return cursor; - } + REnvironment utils = REnvironment.getRegisteredNamespace("utils"); + Object o = utils.get(".completeToken"); + if (o instanceof RPromise) { + o = PromiseHelperNode.evaluateSlowPath(null, (RPromise) o); + } + RFunction completeToken; + if (o instanceof RFunction) { + completeToken = (RFunction) o; + } else { + return cursor; + } + + o = utils.get(".CompletionEnv"); + if (!(o instanceof RPromise)) { + return cursor; + } + REnvironment env = (REnvironment) PromiseHelperNode.evaluateSlowPath(null, (RPromise) o); + int start = getStart(buffer, env, cursor); + env.safePut("start", start); + env.safePut("end", cursor); + env.safePut("linebuffer", buffer); + env.safePut("token", buffer.substring(start, cursor)); + + MaterializedFrame callingFrame = REnvironment.globalEnv().getFrame(); + RContext.getEngine().evalFunction(completeToken, callingFrame, RCaller.createInvalid(callingFrame), null, new Object[]{}); + + o = env.get("comps"); + if (!(o instanceof RAbstractStringVector)) { + return cursor; + } - RAbstractStringVector comps = (RAbstractStringVector) o; - List<String> ret = new ArrayList<>(comps.getLength()); - for (int i = 0; i < comps.getLength(); i++) { - ret.add(comps.getDataAt(i)); + RAbstractStringVector comps = (RAbstractStringVector) o; + List<String> ret = new ArrayList<>(comps.getLength()); + for (int i = 0; i < comps.getLength(); i++) { + ret.add(comps.getDataAt(i)); + } + Collections.sort(ret, String.CASE_INSENSITIVE_ORDER); + candidates.addAll(ret); + return start; } - Collections.sort(ret, String.CASE_INSENSITIVE_ORDER); - candidates.addAll(ret); - return start; } private static int getStart(String buffer, REnvironment env, int cursor) { diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java index 18ced0d667c767e10df4217d3bdd630da2cbb77e..6353be6e9a9fc9199ef8dea6a3744c386a8f8908 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/JLineConsoleHandler.java @@ -39,7 +39,7 @@ import jline.console.UserInterruptException; import jline.console.history.FileHistory; import jline.console.history.History; -class JLineConsoleHandler implements ConsoleHandler { +class JLineConsoleHandler extends ConsoleHandler { private final ConsoleReader console; private final boolean isInteractive; private final PrintWriter printWriter; diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java index c686273f3d38addd4f03ec62f4606c3a1f119595..0f98a4dbcbd93f27024760beeb60afca1f0b1afe 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/RCommand.java @@ -54,11 +54,13 @@ import com.oracle.truffle.r.runtime.Utils.DebugExitException; import com.oracle.truffle.r.runtime.context.ConsoleHandler; import com.oracle.truffle.r.runtime.context.ContextInfo; import com.oracle.truffle.r.runtime.context.DefaultConsoleHandler; +import com.oracle.truffle.r.runtime.context.Engine; import com.oracle.truffle.r.runtime.context.Engine.IncompleteSourceException; import com.oracle.truffle.r.runtime.context.Engine.ParseException; import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.context.RContext.ContextKind; import com.oracle.truffle.r.runtime.data.RLogicalVector; +import com.oracle.truffle.r.runtime.data.RStringVector; import jline.console.UserInterruptException; @@ -190,6 +192,7 @@ public class RCommand { private static final Source GET_ECHO = RSource.fromTextInternal("invisible(getOption('echo'))", RSource.Internal.GET_ECHO); private static final Source QUIT_EOF = RSource.fromTextInternal("quit(\"default\", 0L, TRUE)", RSource.Internal.QUIT_EOF); + private static final Source GET_CONTINUE_PROMPT = RSource.fromTextInternal("invisible(getOption('continue'))", RSource.Internal.GET_CONTINUE_PROMPT); /** * The read-eval-print loop, which can take input from a console, command line expression or a @@ -221,10 +224,10 @@ public class RCommand { continue; } - String continuePrompt = getContinuePrompt(); + String continuePrompt = getContinuePrompt(vm); StringBuffer sb = new StringBuffer(input); Source source = RSource.fromTextInternal(sb.toString(), RSource.Internal.SHELL_INPUT); - boolean hasExecutor = RContext.getInstance().hasExecutor(); + boolean hasExecutor = hasExectuor(vm); while (true) { lastStatus = 0; try { @@ -320,7 +323,21 @@ public class RCommand { } } - private static String getContinuePrompt() { - return RRuntime.asString(RRuntime.asAbstractVector(RContext.getInstance().stateROptions.getValue("continue"))); + private static String getContinuePrompt(PolyglotEngine vm) { + PolyglotEngine.Value echoValue = vm.eval(GET_CONTINUE_PROMPT); + Object echo = echoValue.get(); + if (echo instanceof String) { + return (String) echo; + } else if (echo instanceof TruffleObject) { + RStringVector promptVec = echoValue.as(RStringVector.class); + return promptVec.getDataAt(0); + } else { + throw RInternalError.shouldNotReachHere(); + } + } + + private static boolean hasExectuor(PolyglotEngine vm) { + return vm.eval(Engine.GET_CONTEXT).as(RContext.class).hasExecutor(); } + } diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/StringConsoleHandler.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/StringConsoleHandler.java index 51af0bead26b43b0fa393bd666900a01a7a1fcc2..271b69345df92e9297e4d81391d5fece14eff410 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/StringConsoleHandler.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/shell/StringConsoleHandler.java @@ -28,13 +28,15 @@ import java.util.List; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; import com.oracle.truffle.r.runtime.context.ConsoleHandler; +import com.oracle.truffle.r.runtime.context.RContext; -class StringConsoleHandler implements ConsoleHandler { +class StringConsoleHandler extends ConsoleHandler { private final PrintStream output; private final List<String> lines; private final String inputDescription; private String prompt; private int currentLine; + private RContext ctx; StringConsoleHandler(List<String> lines, OutputStream output, String inputDescription) { this.lines = lines; @@ -103,4 +105,14 @@ class StringConsoleHandler implements ConsoleHandler { public String getInputDescription() { return inputDescription; } + + @Override + public void setContext(RContext ctx) { + this.ctx = ctx; + } + + @Override + public RContext getContext() { + return ctx; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java index e1ef2d2fc9afa9196652aa5e6cec3fb6600fdc12..16f3e223d16b0c343dba84208bd6e57da4c54d0e 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RSource.java @@ -56,6 +56,7 @@ public class RSource { SHELL_INPUT("<shell_input>"), EXPRESSION_INPUT("<expression_input>"), GET_ECHO("<get_echo>"), + GET_CONTINUE_PROMPT("<get_continue_prompt>"), QUIT_EOF("<<quit_eof>>"), STARTUP_SHUTDOWN("<startup/shutdown>"), REPL_WRAPPER("<repl wrapper>"), diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ConsoleHandler.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ConsoleHandler.java index c30feafca92621778beef7300111b91d03aab0b7..cd21de478bcbbc641621ce8c4e41ec50082b40e5 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ConsoleHandler.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ConsoleHandler.java @@ -31,24 +31,27 @@ import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; * implementations for different contexts. Since I/O is involved, all methods are tagged with * {@link TruffleBoundary} as a hint that so should the associated implementation methods. */ -public interface ConsoleHandler { +public abstract class ConsoleHandler { + + private RContext ctx; + /** * Normal output with a new line. */ @TruffleBoundary - void println(String s); + public abstract void println(String s); /** * Normal output without a newline. */ @TruffleBoundary - void print(String s); + public abstract void print(String s); /** * Formatted output. */ @TruffleBoundary - default void printf(String format, Object... args) { + public void printf(String format, Object... args) { print(String.format(format, args)); } @@ -58,20 +61,20 @@ public interface ConsoleHandler { * @param s */ @TruffleBoundary - void printErrorln(String s); + public abstract void printErrorln(String s); /** * Error output without a newline. */ @TruffleBoundary - void printError(String s); + public abstract void printError(String s); /** * Read a line of input, newline is <b>NOT</b> included in result. Returns null if * {@link #isInteractive() == false}. TODO worry about "\r\n"? */ @TruffleBoundary - String readLine(); + public abstract String readLine(); /** * Denote whether the FastR instance is running in 'interactive' mode. This can be set in a @@ -79,27 +82,35 @@ public interface ConsoleHandler { * final once set. */ @TruffleBoundary - boolean isInteractive(); + public abstract boolean isInteractive(); /** * Get the current prompt. */ @TruffleBoundary - String getPrompt(); + public abstract String getPrompt(); /** * Set the R prompt. */ @TruffleBoundary - void setPrompt(String prompt); + public abstract void setPrompt(String prompt); + + public abstract String getInputDescription(); - String getInputDescription(); + public void setContext(RContext ctx) { + this.ctx = ctx; + } + + public RContext getContext() { + return ctx; + } - default void setHistoryFrom(@SuppressWarnings("unused") File file) { + public void setHistoryFrom(@SuppressWarnings("unused") File file) { // by default, do nothing } - default void flushHistory() { + public void flushHistory() { // by default, do nothing } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java index 93ef3ba544ff1b8f3799caae8fc1aa1ebf65e5d7..5a680554e95df9da0769f3809a8e8aedc9e2dff5 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/ContextInfo.java @@ -94,6 +94,13 @@ public final class ContextInfo { } PolyglotEngine newVM = builder.config("application/x-r", CONFIG_KEY, this).build(); this.vm = newVM; + + // retrieve context and set for console handler + if (consoleHandler != null) { + RContext ctx = newVM.eval(Engine.GET_CONTEXT).as(RContext.class); + consoleHandler.setContext(ctx); + } + return newVM; } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/DefaultConsoleHandler.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/DefaultConsoleHandler.java index 18f2a36cceb1ed6df87252416c914869ebb2d624..3bb4b182ccaf24cfbba29e1930d0fa3308614bf5 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/DefaultConsoleHandler.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/DefaultConsoleHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2017, 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 @@ -29,7 +29,7 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; -public class DefaultConsoleHandler implements ConsoleHandler { +public class DefaultConsoleHandler extends ConsoleHandler { private final BufferedReader in; private final PrintStream out; diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/shell/TestJLineConsoleCompleter.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/shell/TestJLineConsoleCompleter.java index e7d55912a9dfb820431d590ee1ffa684acb7c531..015fa4ff405ce362e1a4378cbb4b82877f07e0e0 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/shell/TestJLineConsoleCompleter.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/engine/shell/TestJLineConsoleCompleter.java @@ -118,7 +118,8 @@ public class TestJLineConsoleCompleter { } } - private class DummyConsoleHandler implements ConsoleHandler { + private class DummyConsoleHandler extends ConsoleHandler { + @Override public void println(String s) { } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java index 0b51a3d92da5c30b1872b21f4e31c429aeaa6403..ca61843663b6891e0e6bfea2f7358a2495c30ee8 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/generate/FastRSession.java @@ -66,7 +66,7 @@ public final class FastRSession implements RSession { * A (virtual) console handler that collects the output in a {@link StringBuilder} for * comparison. It does not separate error output as the test analysis doesn't need it. */ - public static class TestConsoleHandler implements ConsoleHandler { + public static class TestConsoleHandler extends ConsoleHandler { private final StringBuilder buffer = new StringBuilder(); private final Deque<String> input = new ArrayDeque<>();