Fixed Skylark stack trace:

- Moved registration mechanism from BaseFunction into ASTNode / Statement / Expression
- Added more details about statements/expressions to the output trace (including if's)
- Fixed wrong locations

--
MOS_MIGRATED_REVID=102841164
diff --git a/src/main/java/com/google/devtools/build/lib/syntax/ASTNode.java b/src/main/java/com/google/devtools/build/lib/syntax/ASTNode.java
index 2fa492e..754035e 100644
--- a/src/main/java/com/google/devtools/build/lib/syntax/ASTNode.java
+++ b/src/main/java/com/google/devtools/build/lib/syntax/ASTNode.java
@@ -28,6 +28,35 @@
 
   protected ASTNode() {}
 
+  /**
+   * Returns whether this node represents a new scope, e.g. a function call.
+   */
+  protected boolean isNewScope()  {
+    return false;
+  }
+
+  /**
+   * Returns an exception which should be thrown instead of the original one.
+   */
+  protected final EvalException handleException(Exception original) {
+    // If there is already a non-empty stack trace, we only add this node iff it describes a
+    // new scope (e.g. FuncallExpression).
+    if (original instanceof EvalExceptionWithStackTrace && isNewScope()) {
+      EvalExceptionWithStackTrace real = (EvalExceptionWithStackTrace) original;
+      real.registerNode(this);
+      return real;
+    }
+
+    // If the exception is an instance of a subclass of EvalException (such as
+    // ReturnStatement.ReturnException and FlowStatement.FlowException), we just return it
+    // unchanged.
+    if (original instanceof EvalException && !original.getClass().equals(EvalException.class)) {
+      return (EvalException) original;
+    }
+
+    return new EvalExceptionWithStackTrace(original, this);
+  }
+
   @VisibleForTesting  // productionVisibility = Visibility.PACKAGE_PRIVATE
   public void setLocation(Location location) {
     this.location = location;