diff --git a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/RScope.java b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/RScope.java index ced4f106a5be00264f3977fb9608df5ea6e5b75e..d44fd73c8796a4725c679e55032c7030a1be91f6 100644 --- a/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/RScope.java +++ b/com.oracle.truffle.r.runtime/src/com/oracle/truffle/r/runtime/env/RScope.java @@ -36,6 +36,7 @@ import com.oracle.truffle.api.nodes.Node; import com.oracle.truffle.r.runtime.ArgumentsSignature; import com.oracle.truffle.r.runtime.RArguments; import com.oracle.truffle.r.runtime.RInternalError; +import com.oracle.truffle.r.runtime.context.RContext; import com.oracle.truffle.r.runtime.data.RFunction; import com.oracle.truffle.r.runtime.data.RStringVector; import com.oracle.truffle.r.runtime.env.REnvironment.PutException; @@ -64,8 +65,20 @@ public final class RScope extends AbstractScope { @Override protected String getName() { - // TODO promises (= closure) - return "function"; + // just to be sure + if (env == REnvironment.emptyEnv()) { + return "empty environment"; + } + + assert env.getFrame() != null; + RFunction function = RArguments.getFunction(env.getFrame()); + if (function != null) { + String name = function.getName(); + return "function environment" + (name != null ? " for function " + name : ""); + } else { + String name = env.getName(); + return "explicit environment" + (name != null ? ": " + name : ""); + } } @Override @@ -103,8 +116,20 @@ public final class RScope extends AbstractScope { } private static String[] collectArgs(REnvironment env) { - ArgumentsSignature signature = RArguments.getSignature(env.getFrame()); - return signature.getNames(); + + if (env != REnvironment.emptyEnv()) { + assert RArguments.isRFrame(env.getFrame()); + RFunction f = RArguments.getFunction(env.getFrame()); + if (f != null) { + return RContext.getRRuntimeASTAccess().getArgumentsSignature(f).getNames(); + } else { + ArgumentsSignature suppliedSignature = RArguments.getSuppliedSignature(env.getFrame()); + if (suppliedSignature != null) { + return suppliedSignature.getNames(); + } + } + } + return new String[0]; } public static RScope createScope(Node node, Frame frame) { @@ -274,7 +299,7 @@ public final class RScope extends AbstractScope { @Override public ForeignAccess getForeignAccess() { - return VariableNamesMessageResolutionForeign.ACCESS; + return ArgumentNamesMessageResolutionForeign.ACCESS; } public static boolean isInstance(TruffleObject obj) { diff --git a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java index cf4d6207f54c143c1a15b360595f851e546d86c9..134b0b01d3aeaa3f7ebe0ea709c59639fd178f46 100644 --- a/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java +++ b/com.oracle.truffle.r.test/src/com/oracle/truffle/r/test/tck/FastRDebugTest.java @@ -29,6 +29,7 @@ import static org.junit.Assert.assertTrue; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.Arrays; import java.util.HashSet; import java.util.LinkedList; import java.util.Set; @@ -320,6 +321,39 @@ public class FastRDebugTest { assertExecutedOK(); } + @Test + public void testScopeArguments() throws Throwable { + final Source source = RSource.fromTextInternal("main <- function(a, b, c, d) {\n" + + " x <- 10L\n" + + "}\n" + + "closure <- function() {\n" + + " x <<- 123L\n" + + " x\n" + + "}\n", + + RSource.Internal.DEBUGTEST_DEBUG); + engine.eval(source); + + // @formatter:on + run.addLast(() -> { + assertNull(suspendedEvent); + assertNotNull(debuggerSession); + debuggerSession.suspendNextExecution(); + }); + + assertArguments(1, "main(1, 2, 3, 4)"); + + stepInto(1); + assertArguments(2, "x <- 10L", "a", "b", "c", "d"); + continueExecution(); + performWork(); + + final Source evalSource = RSource.fromTextInternal("main(1, 2, 3, 4)\n", RSource.Internal.DEBUGTEST_EVAL); + engine.eval(evalSource); + + assertExecutedOK(); + } + @Test public void testChangedScopeChain() throws Throwable { final Source source = RSource.fromTextInternal("main <- function(e) {\n" + @@ -461,6 +495,35 @@ public class FastRDebugTest { }); } + private void assertArguments(final int line, final String code, final String... expectedArgs) { + run.addLast(() -> { + try { + final DebugStackFrame frame = suspendedEvent.getTopStackFrame(); + + DebugScope scope = frame.getScope(); + + Set<String> actualIdentifiers = new HashSet<>(); + scope.getArguments().forEach((x) -> actualIdentifiers.add(x.getName())); + + assertEquals(line + ": " + code, expectedArgs.length, actualIdentifiers.size()); + + Set<String> expectedIds = new HashSet<>(Arrays.asList(expectedArgs)); + Assert.assertEquals(expectedIds, actualIdentifiers); + + if (!run.isEmpty()) { + run.removeFirst().run(); + } + } catch (RuntimeException | Error e) { + + final DebugStackFrame frame = suspendedEvent.getTopStackFrame(); + frame.forEach(var -> { + System.out.println(var); + }); + throw e; + } + }); + } + private void compareScope(final int line, final String code, boolean includeAncestors, boolean completeMatch, final Object[] expectedFrame) { final DebugStackFrame frame = suspendedEvent.getTopStackFrame();