diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java index 161c25219a125d9b88ffdf8373e9b68867f40466..a3211b25f002f996ba8a590a1eb0d774a3d48d18 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/RRuntimeASTAccessImpl.java @@ -68,11 +68,11 @@ import com.oracle.truffle.r.runtime.RDeparse; import com.oracle.truffle.r.runtime.RError; import com.oracle.truffle.r.runtime.RInternalError; import com.oracle.truffle.r.runtime.RRuntimeASTAccess; +import com.oracle.truffle.r.runtime.RSource; import com.oracle.truffle.r.runtime.ReturnException; import com.oracle.truffle.r.runtime.Utils; import com.oracle.truffle.r.runtime.context.Engine; import com.oracle.truffle.r.runtime.context.RContext; -import com.oracle.truffle.r.runtime.data.RArgsValuesAndNames; import com.oracle.truffle.r.runtime.data.RAttributable; import com.oracle.truffle.r.runtime.data.RAttributesLayout; import com.oracle.truffle.r.runtime.data.RComplex; @@ -211,9 +211,8 @@ class RRuntimeASTAccessImpl implements RRuntimeASTAccess { result = ((RSyntaxFunction) s).getSyntaxBody(); break; case 3: - // TODO: handle srcref properly - for now, clearly mark an erroneous access to - // this piece of data - return new RArgsValuesAndNames(new String[]{"DUMMY UNIMPLEMENTED SRCREF"}, ArgumentsSignature.get("dummy")); + // srcref + return RSource.createSrcRef(s.getLazySourceSection()); default: throw RInternalError.shouldNotReachHere(); } diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleCallHelper.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleCallHelper.java index 4347e0e1d93e8037e661457abe394ac6e3e48b1d..2daf1027e71e2c4417abbf0132afe938e5f5546e 100644 --- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleCallHelper.java +++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/interop/ffi/TruffleCallHelper.java @@ -26,14 +26,13 @@ import java.nio.charset.StandardCharsets; import com.oracle.truffle.api.interop.TruffleObject; import com.oracle.truffle.api.interop.java.JavaInterop; -import com.oracle.truffle.r.engine.interop.NativeRawArray; import com.oracle.truffle.r.engine.interop.NativeCharArray; import com.oracle.truffle.r.engine.interop.NativeDoubleArray; import com.oracle.truffle.r.engine.interop.NativeIntegerArray; import com.oracle.truffle.r.engine.interop.NativeLogicalArray; +import com.oracle.truffle.r.engine.interop.NativeRawArray; import com.oracle.truffle.r.runtime.REnvVars; import com.oracle.truffle.r.runtime.RInternalError; -import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RDataFactory; import com.oracle.truffle.r.runtime.data.RDouble; import com.oracle.truffle.r.runtime.data.RInteger; diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java index 9fcf43914e98f05039582e68d6acd43abf911c10..db7e5ccde4c21aab408c99a48f9d8e9425055daf 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/RErrorHandling.java @@ -584,8 +584,6 @@ public class RErrorHandling { /* * Warnings generally do not prevent results being printed. However, this call into R will * destroy any visibility setting made by the calling builtin prior to this call. - * - * TODO: it's not clear whether this is still the case with the optimized visibility scheme */ ContextStateImpl errorHandlingState = getRErrorHandlingState(); RFunction f = errorHandlingState.getDotSignalSimpleWarning(); 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 75b14bc3ea0c23fdb5a510a1e391312e01113ad8..db3bbbbf036a6e8fa9768d26047bc02f4a035bc2 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 @@ -30,6 +30,13 @@ import java.net.URL; import com.oracle.truffle.api.source.Source; import com.oracle.truffle.api.source.SourceSection; +import com.oracle.truffle.r.runtime.context.RContext; +import com.oracle.truffle.r.runtime.data.RDataFactory; +import com.oracle.truffle.r.runtime.data.RIntVector; +import com.oracle.truffle.r.runtime.data.RNull; +import com.oracle.truffle.r.runtime.env.REnvironment; +import com.oracle.truffle.r.runtime.env.REnvironment.PutException; +import com.oracle.truffle.r.runtime.nodes.RSyntaxNode; /** * A facade for the creation of Truffle {@link Source} objects, which is complicated in R due the @@ -202,4 +209,44 @@ public class RSource { } } + public static Object createSrcRef(SourceSection src) { + if (src == null) { + return RNull.instance; + } + if (src == RSyntaxNode.INTERNAL || src == RSyntaxNode.LAZY_DEPARSE || src == RSyntaxNode.SOURCE_UNAVAILABLE) { + return RNull.instance; + } + Source source = src.getSource(); + REnvironment env = RContext.getInstance().sourceRefEnvironments.get(source); + if (env == null) { + env = RDataFactory.createNewEnv("src"); + env.setClassAttr(RDataFactory.createStringVector(new String[]{"srcfilecopy", "srcfile"}, true)); + try { + env.put("filename", source.getPath() == null ? "" : source.getPath()); + env.put("fixedNewlines", RRuntime.LOGICAL_TRUE); + String[] lines = new String[source.getLineCount()]; + for (int i = 0; i < lines.length; i++) { + lines[i] = source.getCode(i + 1); + } + env.put("lines", RDataFactory.createStringVector(lines, true)); + } catch (PutException e) { + throw RInternalError.shouldNotReachHere(e); + } + RContext.getInstance().sourceRefEnvironments.put(source, env); + } + /* + * TODO: it's unclear what the exact format is, experimentally it is (first line, first + * column, last line, last column, first column, last column, first line, last line). the + * second pair of columns is likely bytes instead of chars, and the second pair of lines + * parsed as opposed to "real" lines (may be modified by #line). + */ + int startLine = src.getStartLine(); + int startColumn = src.getStartColumn(); + int endLine = src.getEndLine(); + int endColumn = src.getEndColumn(); + RIntVector ref = RDataFactory.createIntVector(new int[]{startLine, startColumn, endLine, endColumn, startColumn, endColumn, startLine, endLine}, true); + ref.setAttr("srcfile", env); + ref.setClassAttr(RDataFactory.createStringVector("srcref")); + return ref; + } } diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java index b1564503a07ba5c8c0f57fe63d872dfa0d2f448c..a140e87e36be058b7b0406c79f936edaa940e5b8 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/context/RContext.java @@ -418,6 +418,7 @@ public final class RContext extends ExecutionContext implements TruffleObject { private ContextState stateRFFI; public final WeakHashMap<String, WeakReference<String>> stringMap = new WeakHashMap<>(); + public final WeakHashMap<Source, REnvironment> sourceRefEnvironments = new WeakHashMap<>(); private ContextState[] contextStates() { return new ContextState[]{stateREnvVars, stateRProfile, stateROptions, stateREnvironment, stateRErrorHandling, stateRConnection, stateStdConnections, stateRNG, stateRFFI, stateRSerialize, 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 dc3c97220c2c5ee01180d4c307d570c1f7fae073..69fdd243266d3aba66cbe211ec459ee8f8bc92d8 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 @@ -58762,6 +58762,34 @@ NULL ##com.oracle.truffle.r.test.functions.TestFunctions.testReturn# #{ f<-function() { return(invisible(2)) } ; f() } +##com.oracle.truffle.r.test.functions.TestFunctions.testSrcref# +#1<<<NEWLINE>>>f <- quote(function(x, y) <<<NEWLINE>>> a + <<<NEWLINE>>> foooo); as.list(f); as.list(f)[[4]]; unclass(as.list(f)[[4]]); class(as.list(f)[[4]]) +[1] 1 +[[1]] +`function` + +[[2]] +[[2]]$x + + +[[2]]$y + + + +[[3]] +a + foooo + +[[4]] +function(x, y) + a + + foooo + +function(x, y) + a + + foooo +[1] 1 12 3 6 12 6 1 3 +[1] "srcref" + ##com.oracle.truffle.r.test.functions.TestFunctions.testStateTransitions# #{ f<-function(x) { l<-length(x); x[1]<-1 }; y<-c(42,7); f(y); y } [1] 42 7 diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestFunctions.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestFunctions.java index 78259d758de8733c7c38a1d39a2de73cf1c607ce..d3cd786a1aac0d087ab49eaae5efb38f7f1912f9 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestFunctions.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/functions/TestFunctions.java @@ -400,4 +400,9 @@ public class TestFunctions extends TestBase { public void testConversions() { assertEval("{ x<-quote(list(...)); l<-list(); l[[2]]<-x; names(l)<-c(\"...\"); f<-as.function(l); f(7, 42) }"); } + + @Test + public void testSrcref() { + assertEval("1\nf <- quote(function(x, y) \n a + \n foooo); as.list(f); as.list(f)[[4]]; unclass(as.list(f)[[4]]); class(as.list(f)[[4]])"); + } }