diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java index 1670fad52945019ecf3c76ff840c658ab0925a50..f7a538efcb30b60ecc2e58b55c4394d720d35ad2 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/base/BasePackage.java @@ -354,6 +354,7 @@ public class BasePackage extends RBuiltinPackage { add(FastRTry.class, FastRTryNodeGen::create); add(FastRInspect.class, FastRInspectNodeGen::create); add(FastRInterop.Eval.class, FastRInteropFactory.EvalNodeGen::create); + add(FastRInterop.EvalFile.class, FastRInteropFactory.EvalFileNodeGen::create); add(FastRInterop.Export.class, FastRInteropFactory.ExportNodeGen::create); add(FastRInterop.HasSize.class, FastRInteropFactory.HasSizeNodeGen::create); add(FastRInterop.Import.class, FastRInteropFactory.ImportNodeGen::create); diff --git a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java index ce5c3dae4dc188754d89052895ff69e884dd5d6c..f0a1eaaf6eadefcfdc832fa191210af6fe13681e 100644 --- a/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java +++ b/com.oracle.truffle.r.nodes.builtin/src/com/oracle/truffle/r/nodes/builtin/fastr/FastRInterop.java @@ -31,6 +31,9 @@ import static com.oracle.truffle.r.runtime.RVisibility.ON; import static com.oracle.truffle.r.runtime.builtins.RBehavior.COMPLEX; import static com.oracle.truffle.r.runtime.builtins.RBuiltinKind.PRIMITIVE; +import java.io.File; +import java.io.IOException; + import com.oracle.truffle.api.CallTarget; import com.oracle.truffle.api.CompilerAsserts; import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; @@ -44,6 +47,7 @@ import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.nodes.DirectCallNode; import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.api.source.Source; +import com.oracle.truffle.api.source.Source.Builder; import com.oracle.truffle.r.nodes.builtin.CastBuilder; import com.oracle.truffle.r.nodes.builtin.CastBuilder.Predef; import com.oracle.truffle.r.nodes.builtin.RBuiltinNode; @@ -99,6 +103,46 @@ public class FastRInterop { } } + @RBuiltin(name = ".fastr.interop.evalFile", visibility = OFF, kind = PRIMITIVE, parameterNames = {"path", "mimeType"}, behavior = COMPLEX) + public abstract static class EvalFile extends RBuiltinNode { + + @Override + protected void createCasts(CastBuilder casts) { + casts.arg("path").mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst(); + casts.arg("mimeType").allowMissing().mustBe(stringValue()).asStringVector().mustBe(singleElement()).findFirst(); + } + + protected CallTarget parse(String path, String mimeType) { + CompilerAsserts.neverPartOfCompilation(); + + File file = new File(path); + try { + Builder<IOException, RuntimeException, RuntimeException> sourceBuilder = Source.newBuilder(file).name(file.getName()).internal(); + if (mimeType != null) { + sourceBuilder.mimeType(mimeType); + } + Source sourceObject = sourceBuilder.build(); + return RContext.getInstance().getEnv().parse(sourceObject); + } catch (IOException e) { + throw RError.error(this, Message.GENERIC, "Error reading file: " + e.getMessage()); + } catch (Throwable t) { + throw RError.error(this, Message.GENERIC, "Error while parsing: " + t.getMessage()); + } + } + + @Specialization + @TruffleBoundary + protected Object eval(String path, @SuppressWarnings("unused") RMissing missing) { + return parse(path, null).call(); + } + + @Specialization + @TruffleBoundary + protected Object eval(String path, String mimeType) { + return parse(path, mimeType).call(); + } + } + @RBuiltin(name = ".fastr.interop.export", visibility = OFF, kind = PRIMITIVE, parameterNames = {"name", "value"}, behavior = COMPLEX) public abstract static class Export extends RBuiltinNode { diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test index 8191e482278b2673d2ed8c0291d57969c952ca8a..c46aae65e00a8572a16547834981372ab0e2eb3e 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/ExpectedTestOutput.test @@ -111348,6 +111348,16 @@ a b c d e #if (length(grep("FastR", R.Version()$version.string)) != 1) { as.character(123) } else { .fastr.interop.eval('application/x-r', 'as.character(123)') } [1] "123" +##com.oracle.truffle.r.test.library.fastr.TestInterop.testInteropEvalFile# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { cat('[1] "Error reading file: /a/b.R"\n') } else { tryCatch(.fastr.interop.evalFile("/a/b.R"), error = function(e) e$message) } +[1] "Error reading file: /a/b.R" + +##com.oracle.truffle.r.test.library.fastr.TestInterop.testInteropEvalFile# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { x<-c(1);cat(x) } else { fileConn<-file("testScript.R");writeLines(c("x<-c(1)","cat(x)"), fileConn);close(fileConn);.fastr.interop.evalFile("testScript.R") } +1 +##com.oracle.truffle.r.test.library.fastr.TestInterop.testInteropEvalFile# +#if (length(grep("FastR", R.Version()$version.string)) != 1) { x<-c(1);cat(x) } else { fileConn<-file("testScript.R");writeLines(c("x<-c(1)","cat(x)"), fileConn);close(fileConn);.fastr.interop.evalFile("testScript.R","application/x-r") } +1 ##com.oracle.truffle.r.test.library.fastr.TestInterop.testInteropExport# #if (length(grep("FastR", R.Version()$version.string)) != 1) { invisible() } else { .fastr.interop.export('foo', 'foo') } diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInterop.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInterop.java index 4633fbe6cea36712abcfa82e76de810cfd1160d8..2250149cb2075b762143b4d249ff3d3c5a5ddc6c 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInterop.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/library/fastr/TestInterop.java @@ -47,6 +47,14 @@ public class TestInterop extends TestBase { assertEvalFastR(".fastr.interop.export('foo', new.env())", "invisible()"); } + @Test + public void testInteropEvalFile() { + assertEvalFastR("fileConn<-file(\"testScript.R\");writeLines(c(\"x<-c(1)\",\"cat(x)\"), fileConn);close(fileConn);.fastr.interop.evalFile(\"testScript.R\",\"application/x-r\")", + "x<-c(1);cat(x)"); + assertEvalFastR("fileConn<-file(\"testScript.R\");writeLines(c(\"x<-c(1)\",\"cat(x)\"), fileConn);close(fileConn);.fastr.interop.evalFile(\"testScript.R\")", "x<-c(1);cat(x)"); + assertEvalFastR("tryCatch(.fastr.interop.evalFile(\"/a/b.R\"), error = function(e) e$message)", "cat('[1] \"Error reading file: /a/b.R\"\\n')"); + } + /** * Used for testing interop functionality. */