Skip to content
Snippets Groups Projects
Commit e2f701c9 authored by Tomas Stupka's avatar Tomas Stupka
Browse files

[GR-4809] Need a mechanism to provide help for FastR builtins.

PullRequest: fastr/1327
parents 4d4b4a89 c6349086
No related branches found
No related tags found
No related merge requests found
Showing
with 120 additions and 92 deletions
......@@ -99,8 +99,10 @@ import com.oracle.truffle.r.nodes.builtin.fastr.FastRContext;
import com.oracle.truffle.r.nodes.builtin.fastr.FastRContextFactory;
import com.oracle.truffle.r.nodes.builtin.fastr.FastRDebug;
import com.oracle.truffle.r.nodes.builtin.fastr.FastRDebugNodeGen;
import com.oracle.truffle.r.nodes.builtin.fastr.FastRHelp;
import com.oracle.truffle.r.nodes.builtin.fastr.FastRHelpNodeGen;
import com.oracle.truffle.r.nodes.builtin.fastr.FastRHelp.FastRHelpPath;
import com.oracle.truffle.r.nodes.builtin.fastr.FastRHelp.FastRHelpRd;
import com.oracle.truffle.r.nodes.builtin.fastr.FastRHelpFactory.FastRHelpPathNodeGen;
import com.oracle.truffle.r.nodes.builtin.fastr.FastRHelpFactory.FastRHelpRdNodeGen;
import com.oracle.truffle.r.nodes.builtin.fastr.FastRIdentity;
import com.oracle.truffle.r.nodes.builtin.fastr.FastRIdentityNodeGen;
import com.oracle.truffle.r.nodes.builtin.fastr.FastRInspect;
......@@ -431,7 +433,8 @@ public class BasePackage extends RBuiltinPackage {
add(FastrDqrls.class, FastrDqrlsNodeGen::create);
add(FastRDebug.class, FastRDebugNodeGen::create);
add(FastRSetBreakpoint.class, FastRSetBreakpointNodeGen::create);
add(FastRHelp.class, FastRHelpNodeGen::create);
add(FastRHelpPath.class, FastRHelpPathNodeGen::create);
add(FastRHelpRd.class, FastRHelpRdNodeGen::create);
add(FastRIdentity.class, FastRIdentityNodeGen::create);
add(FastROptionBuiltin.class, FastROptionBuiltin::create);
add(FastRTry.class, FastRTryNodeGen::create);
......
......@@ -16,7 +16,11 @@ An interop byte value. Error in case the given value can't be converted to a byt
Marks a R value to be converted to byte when passed over to a foreign language.
}
\examples{
as.external.byte(123)
javaByte <- as.external.byte(123)
## used to pass a java byte to a java method call
byteClass <- new.java.class('java.lang.Byte')
byteClass$valueOf(javaByte)
}
\seealso{
\code{\link{as.external.char}}, \code{\link{as.external.float}}, \code{\link{as.external.long}}, \code{\link{as.external.short}}
......
......@@ -16,7 +16,11 @@ An interop char value. Error in case the given value can't be converted to a cha
Marks a R value to be converted to char when passed over to a foreign language.
}
\examples{
as.external.char('a')
javaChar <- as.external.char(123)
## used to pass a java char to a java method call
charClass <- new.java.class('java.lang.Character')
charClass$valueOf(javaChar)
}
\seealso{
\code{\link{as.external.byte}}, \code{\link{as.external.float}}, \code{\link{as.external.long}}, \code{\link{as.external.short}}
......
......@@ -16,7 +16,11 @@ An interop float value. Error in case the given value can't be converted to a fl
Marks a R value to be converted to float when passed over to a foreign language.
}
\examples{
as.external.float(1.1)
javaFloat <- as.external.float(123)
## used to pass a java float to a java method call
floatClass <- new.java.class('java.lang.Float')
floatClass$valueOf(javaFloat)
}
\seealso{
\code{\link{as.external.byte}}, \code{\link{as.external.char}}, \code{\link{as.external.long}}, \code{\link{as.external.short}}
......
......@@ -16,7 +16,11 @@ An interop long value. Error in case the given value can't be converted to a lon
Marks a R value to be converted to long when passed over to a foreign language.
}
\examples{
as.external.long(123)
javaLong <- as.external.long(123)
## used to pass a java long to a java method call
longClass <- new.java.class('java.lang.Long')
longClass$valueOf(javaLong)
}
\seealso{
\code{\link{as.external.byte}}, \code{\link{as.external.char}}, \code{\link{as.external.float}}, \code{\link{as.external.short}}
......
......@@ -16,7 +16,11 @@ An interop short value. Error in case the given value can't be converted to a sh
Marks a R value to be converted to short when passed over to a foreign language.
}
\examples{
as.external.short(123)
javaShort <- as.external.short(123)
## used to pass a java short to a java method call
shortClass <- new.java.class('java.lang.Short')
shortClass$valueOf(javaShort)
}
\seealso{
\code{\link{as.external.byte}}, \code{\link{as.external.char}}, \code{\link{as.external.short}}, \code{\link{as.external.long}}
......
......@@ -18,7 +18,9 @@ An external object representing a java array. Error in case the array could not
Converts a R vector or list to a java array.
}
\examples{
as.java.array(c(1, 2, 3), 'java.lang.Double')
as.java.array(c(1, 2, 3))
as.java.array(c(1L, 2L, 3L), 'int')
as.java.array(c(1L, 2L, 3L), 'java.lang.Integer')
}
\seealso{
\code{\link{new.java.array}}, \code{\link{is.external.array}}
......
......@@ -17,5 +17,5 @@ Determines whether the passed external object can be executed.
}
\examples{
javaClass <- new.java.class('java.util.Collections')
is.external.executable(javaClass$addAll())
is.external.executable(javaClass$addAll)
}
......@@ -20,6 +20,7 @@ Creates a new java array given by the class name and length or dimensions.
\examples{
new.java.array('java.lang.Double', 10)
new.java.array('java.lang.Double', c(2, 3))
new.java.array('int', c(2L, 3L))
}
\seealso{
\code{\link{as.java.array}}, \code{\link{is.external.array}}
......
......@@ -39,30 +39,57 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@RBuiltin(name = ".fastr.interop.getHelpRd", visibility = ON, kind = PRIMITIVE, parameterNames = {"builtinName"}, behavior = COMPLEX)
public abstract class FastRHelp extends RBuiltinNode.Arg1 {
public class FastRHelp {
static {
Casts casts = new Casts(FastRHelp.class);
casts.arg("builtinName").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
@RBuiltin(name = ".fastr.interop.helpPath", visibility = ON, kind = PRIMITIVE, parameterNames = {"builtinName"}, behavior = COMPLEX)
public abstract static class FastRHelpPath extends RBuiltinNode.Arg1 {
static {
Casts casts = new Casts(FastRHelpPath.class);
casts.arg("builtinName").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
}
@Specialization()
@TruffleBoundary
public Object helpPath(String builtinName) {
String path = "/com/oracle/truffle/r/nodes/builtin/base/Rd/" + builtinName + ".Rd";
try (InputStream in = getClass().getResourceAsStream(path)) {
if (in != null) {
return path;
}
} catch (IOException ex) {
}
return RNull.instance;
}
}
@Specialization()
@TruffleBoundary
public Object isExternal(String builtinName) {
InputStream in = getClass().getResourceAsStream("/com/oracle/truffle/r/nodes/builtin/fastr/Rd/" + builtinName + ".Rd");
if (in != null) {
try (BufferedReader r = new BufferedReader(new InputStreamReader(in))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
sb.append(line).append("\n");
@RBuiltin(name = ".fastr.interop.helpRd", visibility = ON, kind = PRIMITIVE, parameterNames = {"path"}, behavior = COMPLEX)
public abstract static class FastRHelpRd extends RBuiltinNode.Arg1 {
static {
Casts casts = new Casts(FastRHelpRd.class);
casts.arg("path").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst();
}
@Specialization()
@TruffleBoundary
public Object getHelpRdPath(String path) {
try (InputStream in = getClass().getResourceAsStream(path)) {
if (in != null) {
try (BufferedReader r = new BufferedReader(new InputStreamReader(in))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
sb.append(line).append("\n");
}
return sb.toString();
}
}
return sb.toString();
} catch (IOException ex) {
RError.warning(this, RError.Message.GENERIC, "problems while reading " + builtinName + ".Rd", ex.getMessage());
RError.warning(this, RError.Message.GENERIC, "problems while reading " + path, ex.getMessage());
}
return RNull.instance;
}
return RNull.instance;
}
}
......@@ -33,72 +33,30 @@ setBreakpoint <- function (srcfile, line, nameonly = TRUE, envir = parent.frame(
}), asNamespace("utils"))
eval(expression({
help <- function (topic, package = NULL, lib.loc = NULL, verbose = getOption("verbose"), try.all.packages = getOption("help.try.all.packages"), help_type = getOption("help_type")) {
types <- c("text", "html", "pdf")
if (!missing(package))
if (is.name(y <- substitute(package)))
package <- as.character(y)
if (missing(topic)) {
if (!is.null(package)) {
help_type <- if (!length(help_type))
"text"
else match.arg(tolower(help_type), types)
if (interactive() && help_type == "html") {
port <- tools::startDynamicHelp(NA)
if (port <= 0L)
return(library(help = package, lib.loc = lib.loc, character.only = TRUE))
browser <- if (.Platform$GUI == "AQUA") {
get("aqua.browser", envir = as.environment("tools:RGUI"))
}
else getOption("browser")
browseURL(paste0("http://127.0.0.1:", port, "/library/", package, "/html/00Index.html"), browser)
return(invisible())
}
else return(library(help = package, lib.loc = lib.loc, character.only = TRUE))
index.search.orig <- utils:::index.search
index.search <- function (topic, paths, firstOnly = FALSE)
{
res <- index.search.orig(topic, paths, firstOnly)
if(length(res) == 0) {
fastrHelpRd <- .fastr.interop.helpPath(topic)
if(!is.null(fastrHelpRd)) {
res <- fastrHelpRd
}
if (!is.null(lib.loc))
return(library(lib.loc = lib.loc))
topic <- "help"
package <- "utils"
lib.loc <- .Library
}
ischar <- tryCatch(is.character(topic) && length(topic) == 1L, error = identity)
if (inherits(ischar, "error"))
ischar <- FALSE
if (!ischar) {
reserved <- c("TRUE", "FALSE", "NULL", "Inf", "NaN", "NA", "NA_integer_", "NA_real_", "NA_complex_", "NA_character_")
stopic <- deparse(substitute(topic))
if (!is.name(substitute(topic)) && !stopic %in% reserved)
stop("'topic' should be a name, length-one character vector or reserved word")
topic <- stopic
}
# Fastr >>>>
fastrHelpRd <- .fastr.interop.getHelpRd(topic)
if (!is.null(fastrHelpRd)) {
fastrHelpRd <- tools::parse_Rd(textConnection(fastrHelpRd))
cat("==== R Help on ‘", topic, "’ ====\n", sep = "")
return(tools::Rd2txt(fastrHelpRd))
}
# Fastr <<<<
help_type <- if (!length(help_type))
"text"
else match.arg(tolower(help_type), types)
paths <- index.search(topic, find.package(if (is.null(package))
loadedNamespaces()
else package, lib.loc, verbose = verbose))
tried_all_packages <- FALSE
if (!length(paths) && is.logical(try.all.packages) && !is.na(try.all.packages) && try.all.packages && is.null(package) && is.null(lib.loc)) {
for (lib in .libPaths()) {
packages <- .packages(TRUE, lib)
packages <- packages[is.na(match(packages, .packages()))]
paths <- c(paths, index.search(topic, file.path(lib, packages)))
}
paths <- paths[nzchar(paths)]
tried_all_packages <- TRUE
res
}
}), asNamespace("utils"))
eval(expression({
.getHelpFile.orig <- utils:::.getHelpFile
.getHelpFile <- function (file)
{
fastrHelpRd <- .fastr.interop.helpRd(file)
if(!is.null(fastrHelpRd)) {
return(tools::parse_Rd(textConnection(fastrHelpRd)))
}
paths <- unique(paths)
attributes(paths) <- list(call = match.call(), topic = topic, tried_all_packages = tried_all_packages, type = help_type)
class(paths) <- "help_files_with_topic"
paths
.getHelpFile.orig(file)
}
}), asNamespace("utils"))
\ No newline at end of file
......@@ -33,6 +33,7 @@ import com.oracle.truffle.r.runtime.conn.SeekableMemoryByteChannel;
import com.oracle.truffle.r.test.TestBase;
import java.io.File;
import org.junit.After;
import static org.junit.Assert.assertTrue;
public class TestInterop extends TestBase {
......@@ -105,6 +106,22 @@ public class TestInterop extends TestBase {
"cat('Error in fo@bitLength :\n cannot get a slot (\"bitLength\") from an object of type \"external object\"\n')");
}
@Test
public void testHelp() {
assertHelpResult(fastREval("?as.external.byte", null, false), "==== R Help on ‘as.external.byte’ ====", "converted to a byte", "byteClass$valueOf(javaByte)");
assertHelpResult(fastREval("help(as.external.byte)", null, false), "==== R Help on ‘as.external.byte’ ====", "converted to a byte", "byteClass$valueOf(javaByte)");
assertHelpResult(fastREval("example(as.external.byte)", null, false), null, "byteClass$valueOf(javaByte)", "[1] 123");
}
private void assertHelpResult(String result, String startsWith, String... contains) {
if (startsWith != null) {
assertTrue(result.startsWith(startsWith));
}
for (String s : contains) {
assertTrue(result.contains(s));
}
}
/**
* Used for testing interop functionality.
*/
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment