diff options
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/syntax/Environment.java')
-rw-r--r-- | src/main/java/com/google/devtools/build/lib/syntax/Environment.java | 90 |
1 files changed, 89 insertions, 1 deletions
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 c536a688b3..6f84188b4b 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 @@ -16,6 +16,7 @@ package com.google.devtools.build.lib.syntax; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; import com.google.devtools.build.lib.cmdline.Label; @@ -31,10 +32,12 @@ import com.google.devtools.build.lib.syntax.Mutability.MutabilityException; import com.google.devtools.build.lib.util.Fingerprint; import com.google.devtools.build.lib.util.Pair; import com.google.devtools.build.lib.util.SpellChecker; +import com.google.devtools.build.lib.vfs.PathFragment; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; import java.util.LinkedHashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; @@ -75,7 +78,7 @@ import javax.annotation.Nullable; * that the words "dynamic" and "static" refer to the point of view of the source code, and here we * have a dual point of view. */ -public final class Environment implements Freezable { +public final class Environment implements Freezable, Debuggable { /** * A phase for enabling or disabling certain builtin functions @@ -1150,6 +1153,91 @@ public final class Environment implements Freezable { return vars; } + private static final class EvalEventHandler implements EventHandler { + List<String> messages = new ArrayList<>(); + + @Override + public void handle(Event event) { + if (event.getKind() == EventKind.ERROR) { + messages.add(event.getMessage()); + } + } + } + + @Override + public Object evaluate(String expression) throws EvalException, InterruptedException { + ParserInputSource inputSource = + ParserInputSource.create(expression, PathFragment.create("<debug eval>")); + EvalEventHandler eventHandler = new EvalEventHandler(); + Expression expr = Parser.parseExpression(inputSource, eventHandler); + if (!eventHandler.messages.isEmpty()) { + throw new EvalException(expr.getLocation(), eventHandler.messages.get(0)); + } + return expr.eval(this); + } + + @Override + public ImmutableList<DebugFrame> listFrames(Location currentLocation) { + ImmutableList.Builder<DebugFrame> frameListBuilder = ImmutableList.builder(); + + Continuation currentContinuation = continuation; + Frame currentFrame = currentFrame(); + + // if there's a continuation then the current frame is a lexical frame + while (currentContinuation != null) { + frameListBuilder.add( + DebugFrame.builder() + .setLexicalFrameBindings(ImmutableMap.copyOf(currentFrame.getTransitiveBindings())) + .setGlobalBindings(ImmutableMap.copyOf(getGlobals().getTransitiveBindings())) + .setFunctionName(currentContinuation.function.getFullName()) + .setLocation(currentLocation) + .build()); + + currentFrame = currentContinuation.lexicalFrame; + currentLocation = currentContinuation.caller.getLocation(); + currentContinuation = currentContinuation.continuation; + } + + frameListBuilder.add( + DebugFrame.builder() + .setGlobalBindings(ImmutableMap.copyOf(getGlobals().getTransitiveBindings())) + .setFunctionName("<top level>") + .setLocation(currentLocation) + .build()); + + return frameListBuilder.build(); + } + + @Override + @Nullable + public ReadyToPause stepControl(Stepping stepping) { + final Continuation pausedContinuation = continuation; + + switch (stepping) { + case NONE: + return null; + case INTO: + // pause at the very next statement + return env -> true; + case OVER: + return env -> isAt(env, pausedContinuation) || isOutside(env, pausedContinuation); + case OUT: + // if we're at the outer-most frame, same as NONE + return pausedContinuation == null ? null : env -> isOutside(env, pausedContinuation); + } + throw new IllegalArgumentException("Unsupported stepping type: " + stepping); + } + + /** Returns true if {@code env} is in a parent frame of {@code pausedContinuation}. */ + private static boolean isOutside(Environment env, @Nullable Continuation pausedContinuation) { + return pausedContinuation != null && env.continuation == pausedContinuation.continuation; + } + + /** Returns true if {@code env} is at the same frame as {@code pausedContinuation. */ + private static boolean isAt(Environment env, @Nullable Continuation pausedContinuation) { + return env.continuation == pausedContinuation; + } + @Override public int hashCode() { throw new UnsupportedOperationException(); // avoid nondeterminism |