When a Skylark macro creates a native rule, it also sets the following rule attributes: generator_{function, name, location}
--
MOS_MIGRATED_REVID=102139196
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/Environment.java b/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
index f16d35e..ed30671 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/Environment.java
@@ -23,8 +23,10 @@
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -104,22 +106,40 @@
@Nullable protected EventHandler eventHandler;
/**
+ * A stack trace containing the current history of functions and the calling rule.
+ *
+ * <p>For the rule, the stack trace has two elements: one for the call to the rule in the BUILD
+ * file and one for the actual rule implementation.
+ */
+ private Deque<StackTraceElement> stackTrace;
+
+ /**
* Constructs an empty root non-Skylark environment.
* The root environment is also the global environment.
*/
- public Environment() {
+ public Environment(Deque<StackTraceElement> stackTrace) {
this.parent = null;
this.importedExtensions = new HashMap<>();
+ this.stackTrace = stackTrace;
setupGlobal();
}
+ public Environment() {
+ this(new LinkedList<StackTraceElement>());
+ }
+
/**
* Constructs an empty child environment.
*/
- public Environment(Environment parent) {
+ public Environment(Environment parent, Deque<StackTraceElement> stackTrace) {
Preconditions.checkNotNull(parent);
this.parent = parent;
this.importedExtensions = new HashMap<>();
+ this.stackTrace = stackTrace;
+ }
+
+ public Environment(Environment parent) {
+ this(parent, new LinkedList<StackTraceElement>());
}
/**
@@ -301,12 +321,60 @@
update(symbol.getName(), value);
}
+ public ImmutableList<StackTraceElement> getStackTrace() {
+ return ImmutableList.copyOf(stackTrace);
+ }
+
+ protected Deque<StackTraceElement> getCopyOfStackTrace() {
+ return new LinkedList<>(stackTrace);
+ }
+
/**
- * Return the current stack trace (list of functions).
+ * Adds the given element to the stack trace (iff the stack is empty) and returns whether it was
+ * successful.
*/
- public ImmutableList<BaseFunction> getStackTrace() {
- // Empty list, since this environment does not allow function definition
- // (see SkylarkEnvironment)
- return ImmutableList.of();
+ public boolean tryAddingStackTraceRoot(StackTraceElement element) {
+ if (stackTrace.isEmpty()) {
+ stackTrace.add(element);
+ return true;
+ }
+ return false;
+ }
+
+ public void addToStackTrace(StackTraceElement element) {
+ stackTrace.add(element);
+ }
+
+ /**
+ * Removes the only remaining element from the stack trace.
+ *
+ * <p>This particular element describes the outer-most calling function (usually a rule).
+ *
+ * <p> This method is required since {@link FuncallExpression} does not create a new {@link
+ * Environment}, hence it has to add and remove its {@link StackTraceElement} from an existing
+ * one.
+ */
+ public void removeStackTraceRoot() {
+ Preconditions.checkArgument(stackTrace.size() == 1);
+ stackTrace.clear();
+ }
+
+ public void removeStackTraceElement() {
+ // TODO(fwe): find out why the precond doesn't work
+ // Preconditions.checkArgument(stackTrace.size() > 1);
+ stackTrace.removeLast();
+ }
+
+ /**
+ * Returns whether the given {@link BaseFunction} is part of this {@link Environment}'s stack
+ * trace.
+ */
+ public boolean stackTraceContains(BaseFunction function) {
+ for (StackTraceElement element : stackTrace) {
+ if (element.hasFunction(function)) {
+ return true;
+ }
+ }
+ return false;
}
}