From dff78441a02a1e4648fe58058a7b799c41fb63d3 Mon Sep 17 00:00:00 2001
From: Martin Entlicher <martin.entlicher@oracle.com>
Date: Thu, 26 Oct 2017 16:46:57 +0200
Subject: [PATCH] [GR-6010] Use the new Scope class after metadata deprecation,
 provide global scope.

---
 .../r/engine/TruffleRLanguageImpl.java        |  23 ++--
 .../oracle/truffle/r/runtime/env/RScope.java  | 110 ++++++++++--------
 .../truffle/r/test/tck/FastRDebugTest.java    |  23 +++-
 mx.fastr/suite.py                             |   2 +-
 4 files changed, 89 insertions(+), 69 deletions(-)

diff --git a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java
index 8fb818136f..6efb2f21fc 100644
--- a/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java
+++ b/com.oracle.truffle.r.engine/src/com/oracle/truffle/r/engine/TruffleRLanguageImpl.java
@@ -26,18 +26,17 @@ import java.util.HashMap;
 
 import com.oracle.truffle.api.CallTarget;
 import com.oracle.truffle.api.CompilerAsserts;
+import com.oracle.truffle.api.Scope;
 import com.oracle.truffle.api.TruffleLanguage;
 import com.oracle.truffle.api.frame.Frame;
 import com.oracle.truffle.api.instrumentation.Instrumenter;
 import com.oracle.truffle.api.instrumentation.ProvidedTags;
 import com.oracle.truffle.api.instrumentation.StandardTags;
-import com.oracle.truffle.api.metadata.ScopeProvider;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.api.source.SourceSection;
 import com.oracle.truffle.r.engine.interop.RForeignAccessFactoryImpl;
 import com.oracle.truffle.r.nodes.RASTBuilder;
 import com.oracle.truffle.r.nodes.builtin.RBuiltinPackages;
-import com.oracle.truffle.r.nodes.function.PromiseHelperNode;
 import com.oracle.truffle.r.nodes.instrumentation.RSyntaxTags;
 import com.oracle.truffle.r.runtime.ExitException;
 import com.oracle.truffle.r.runtime.FastROptions;
@@ -60,7 +59,7 @@ import com.oracle.truffle.r.runtime.nodes.RBaseNode;
 
 @TruffleLanguage.Registration(name = "R", id = "R", version = "3.3.2", mimeType = {RRuntime.R_APP_MIME, RRuntime.R_TEXT_MIME}, interactive = true)
 @ProvidedTags({StandardTags.CallTag.class, StandardTags.StatementTag.class, StandardTags.RootTag.class, RSyntaxTags.LoopTag.class})
-public final class TruffleRLanguageImpl extends TruffleRLanguage implements ScopeProvider<RContext> {
+public final class TruffleRLanguageImpl extends TruffleRLanguage {
 
     private final HashMap<String, RFunction> builtinFunctionCache = new HashMap<>();
 
@@ -201,15 +200,6 @@ public final class TruffleRLanguageImpl extends TruffleRLanguage implements Scop
 
     private static final R2Foreign r2foreign = R2ForeignNodeGen.create();
 
-    @Override
-    protected Object lookupSymbol(RContext context, String symbolName) {
-        Object value = context.stateREnvironment.getGlobalEnv().get(symbolName);
-        if (value instanceof RPromise) {
-            value = PromiseHelperNode.evaluateSlowPath((RPromise) value);
-        }
-        return value != null ? r2foreign.execute(value) : null;
-    }
-
     @Override
     protected Object getLanguageGlobal(RContext context) {
         // TODO: what's the meaning of "language global" for R?
@@ -225,7 +215,12 @@ public final class TruffleRLanguageImpl extends TruffleRLanguage implements Scop
     }
 
     @Override
-    public AbstractScope findScope(RContext langContext, Node node, Frame frame) {
-        return RScope.createScope(node, frame);
+    public Iterable<Scope> findLocalScopes(RContext langContext, Node node, Frame frame) {
+        return RScope.createLocalScopes(langContext, node, frame);
+    }
+
+    @Override
+    protected Iterable<Scope> findTopScopes(RContext langContext) {
+        return RScope.createTopScopes(langContext);
     }
 }
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 b8cb17148d..cb2d3141e1 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
@@ -22,7 +22,12 @@
  */
 package com.oracle.truffle.r.runtime.env;
 
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
 import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
+import com.oracle.truffle.api.Scope;
 import com.oracle.truffle.api.frame.Frame;
 import com.oracle.truffle.api.frame.MaterializedFrame;
 import com.oracle.truffle.api.interop.ForeignAccess;
@@ -35,7 +40,6 @@ import com.oracle.truffle.api.interop.TruffleObject;
 import com.oracle.truffle.api.interop.UnknownIdentifierException;
 import com.oracle.truffle.api.interop.UnsupportedMessageException;
 import com.oracle.truffle.api.interop.UnsupportedTypeException;
-import com.oracle.truffle.api.metadata.ScopeProvider.AbstractScope;
 import com.oracle.truffle.api.nodes.Node;
 import com.oracle.truffle.r.runtime.ArgumentsSignature;
 import com.oracle.truffle.r.runtime.RArguments;
@@ -52,7 +56,7 @@ import com.oracle.truffle.r.runtime.env.frame.REnvTruffleFrameAccess;
  * Represents a variable scope for external tools like a debugger.<br>
  * This is basically a view on R environments.
  */
-public final class RScope extends AbstractScope {
+public final class RScope {
 
     private final Node current;
     private REnvironment env;
@@ -70,7 +74,6 @@ public final class RScope extends AbstractScope {
         this.env = env;
     }
 
-    @Override
     protected String getName() {
         // just to be sure
         if (env == REnvironment.emptyEnv()) {
@@ -88,13 +91,11 @@ public final class RScope extends AbstractScope {
         }
     }
 
-    @Override
     protected Node getNode() {
         return current;
     }
 
-    @Override
-    protected Object getVariables(Frame frame) {
+    protected Object getVariables() {
         return new EnvVariablesObject(env, false);
     }
 
@@ -105,25 +106,72 @@ public final class RScope extends AbstractScope {
         return null;
     }
 
-    @Override
-    protected Object getArguments(Frame frame) {
+    protected Object getArguments() {
         return new EnvVariablesObject(env, true);
     }
 
-    @Override
-    protected AbstractScope findParent() {
+    protected RScope findParent() {
         if (env == REnvironment.emptyEnv() || env.getParent() == REnvironment.emptyEnv()) {
             return null;
         }
         return new RScope(env.getParent());
     }
 
-    public static AbstractScope createScope(Node node, Frame frame) {
+    public static Iterable<Scope> createLocalScopes(RContext context, Node node, Frame frame) {
         REnvironment env = getEnv(frame);
+        if (env == context.stateREnvironment.getGlobalEnv()) {
+            return Collections.emptySet();
+        }
         if (env != null && env != REnvironment.emptyEnv()) {
-            return new RScope(node.getRootNode(), env);
+            RScope scope = new RScope(node.getRootNode(), env);
+            return createScopes(scope, context.stateREnvironment.getGlobalEnv());
         }
-        return new GenericScope(node, frame.materialize());
+        MaterializedFrame mFrame = frame.materialize();
+        String name = node.getRootNode().getName();
+        if (name == null) {
+            name = "local";
+        }
+        return Collections.singleton(Scope.newBuilder(name, new GenericVariablesObject(mFrame, false)).node(node).arguments(new GenericVariablesObject(mFrame, true)).build());
+    }
+
+    public static Iterable<Scope> createTopScopes(RContext context) {
+        REnvironment env = context.stateREnvironment.getGlobalEnv();
+        RScope scope = new RScope(env);
+        return createScopes(scope, null);
+    }
+
+    private static Iterable<Scope> createScopes(RScope scope, REnvironment toEnv) {
+        return new Iterable<Scope>() {
+            @Override
+            public Iterator<Scope> iterator() {
+                return new Iterator<Scope>() {
+                    private RScope previousScope;
+                    private RScope nextScope = scope;
+
+                    @Override
+                    public boolean hasNext() {
+                        if (nextScope == null) {
+                            nextScope = previousScope.findParent();
+                            if (nextScope != null && nextScope.env == toEnv) {
+                                nextScope = null;
+                            }
+                        }
+                        return nextScope != null;
+                    }
+
+                    @Override
+                    public Scope next() {
+                        if (!hasNext()) {
+                            throw new NoSuchElementException();
+                        }
+                        Scope vscope = Scope.newBuilder(nextScope.getName(), nextScope.getVariables()).node(nextScope.getNode()).arguments(nextScope.getArguments()).build();
+                        previousScope = nextScope;
+                        nextScope = null;
+                        return vscope;
+                    }
+                };
+            }
+        };
     }
 
     /**
@@ -138,42 +186,6 @@ public final class RScope extends AbstractScope {
         return obj;
     }
 
-    private static final class GenericScope extends AbstractScope {
-
-        private final MaterializedFrame mFrame;
-        private final Node node;
-
-        protected GenericScope(Node node, MaterializedFrame frame) {
-            this.node = node;
-            this.mFrame = frame;
-        }
-
-        @Override
-        protected String getName() {
-            return node.getRootNode().getName();
-        }
-
-        @Override
-        protected Node getNode() {
-            return node;
-        }
-
-        @Override
-        protected Object getVariables(Frame frame) {
-            return new GenericVariablesObject(mFrame, false);
-        }
-
-        @Override
-        protected Object getArguments(Frame frame) {
-            return new GenericVariablesObject(mFrame, true);
-        }
-
-        @Override
-        protected AbstractScope findParent() {
-            return null;
-        }
-    }
-
     abstract static class VariablesObject implements TruffleObject {
 
         private final REnvFrameAccess frameAccess;
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 b1fbb4910b..71fe0d2b1b 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
@@ -582,6 +582,9 @@ public class FastRDebugTest {
                 final DebugStackFrame frame = suspendedEvent.getTopStackFrame();
 
                 DebugScope scope = frame.getScope();
+                if (scope == null) {
+                    scope = suspendedEvent.getSession().getTopScope("application/x-r");
+                }
 
                 Set<String> actualIdentifiers = new HashSet<>();
                 scope.getArguments().forEach((x) -> actualIdentifiers.add(x.getName()));
@@ -627,11 +630,21 @@ public class FastRDebugTest {
             Object expectedValue = expectedFrame[i + 1];
             String expectedValueStr = (expectedValue != null) ? expectedValue.toString() : null;
             DebugScope scope = frame.getScope();
-            DebugValue value;
-            do {
-                value = scope.getDeclaredValue(expectedIdentifier);
-                scope = scope.getParent();
-            } while (includeAncestors && value == null && scope != null && !REnvironment.baseEnv().getName().equals(scope.getName()));
+            DebugValue value = null;
+            if (scope != null) {
+                do {
+                    value = scope.getDeclaredValue(expectedIdentifier);
+                    scope = scope.getParent();
+                } while (includeAncestors && value == null && scope != null && !REnvironment.baseEnv().getName().equals(scope.getName()));
+            }
+            if (value == null) {
+                // Ask the top scope:
+                scope = suspendedEvent.getSession().getTopScope("application/x-r");
+                do {
+                    value = scope.getDeclaredValue(expectedIdentifier);
+                    scope = scope.getParent();
+                } while (includeAncestors && value == null && scope != null && !REnvironment.baseEnv().getName().equals(scope.getName()));
+            }
             assertNotNull("identifier \"" + expectedIdentifier + "\" not found", value);
             String valueStr = value.as(String.class);
             assertEquals(expectedValueStr, valueStr);
diff --git a/mx.fastr/suite.py b/mx.fastr/suite.py
index bfb8500be9..fcbca55fbf 100644
--- a/mx.fastr/suite.py
+++ b/mx.fastr/suite.py
@@ -29,7 +29,7 @@ suite = {
             {
                "name" : "truffle",
                "subdir" : True,
-               "version" : "f7eb693d02cc090cbaab6ec9dfce0b5d9d22b716",
+               "version" : "d1bb9076f1fa6af71c60be140f980794596a75b4",
                "urls" : [
                     {"url" : "https://github.com/graalvm/graal", "kind" : "git"},
                     {"url" : "https://curio.ssw.jku.at/nexus/content/repositories/snapshots", "kind" : "binary"},
-- 
GitLab