Java tutorial
// Copyright 2018 The Bazel Authors. All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.devtools.build.lib.skylarkdebug.server; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.devtools.build.lib.events.Location; import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos; import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos.ContinueExecutionResponse; import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos.DebugEvent; import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos.Error; import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos.EvaluateResponse; import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos.Frame; import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos.ListFramesResponse; import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos.PauseThreadResponse; import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos.PausedThread; import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos.Scope; import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos.SetBreakpointsResponse; import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos.StartDebuggingResponse; import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos.ThreadContinuedEvent; import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos.ThreadPausedEvent; import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos.Value; import com.google.devtools.build.lib.syntax.DebugFrame; import com.google.devtools.build.lib.syntax.Debuggable.Stepping; import java.util.Collection; import java.util.LinkedHashMap; import java.util.Map; import javax.annotation.Nullable; /** * Helper class for constructing event or response protos to be sent from the debug server to a * debugger client. */ final class DebugEventHelper { private DebugEventHelper() { } private static final long NO_SEQUENCE_NUMBER = 0; static DebugEvent error(String message) { return error(NO_SEQUENCE_NUMBER, message); } static DebugEvent error(long sequenceNumber, String message) { return DebugEvent.newBuilder().setSequenceNumber(sequenceNumber) .setError(Error.newBuilder().setMessage(message)).build(); } static DebugEvent setBreakpointsResponse(long sequenceNumber) { return DebugEvent.newBuilder().setSequenceNumber(sequenceNumber) .setSetBreakpoints(SetBreakpointsResponse.newBuilder()).build(); } static DebugEvent continueExecutionResponse(long sequenceNumber) { return DebugEvent.newBuilder().setSequenceNumber(sequenceNumber) .setContinueExecution(ContinueExecutionResponse.newBuilder()).build(); } static DebugEvent evaluateResponse(long sequenceNumber, Value value) { return DebugEvent.newBuilder().setSequenceNumber(sequenceNumber) .setEvaluate(EvaluateResponse.newBuilder().setResult(value)).build(); } static DebugEvent listFramesResponse(long sequenceNumber, Collection<Frame> frames) { return DebugEvent.newBuilder().setSequenceNumber(sequenceNumber) .setListFrames(ListFramesResponse.newBuilder().addAllFrame(frames)).build(); } static DebugEvent startDebuggingResponse(long sequenceNumber) { return DebugEvent.newBuilder().setSequenceNumber(sequenceNumber) .setStartDebugging(StartDebuggingResponse.newBuilder()).build(); } static DebugEvent pauseThreadResponse(long sequenceNumber) { return DebugEvent.newBuilder().setSequenceNumber(sequenceNumber) .setPauseThread(PauseThreadResponse.newBuilder()).build(); } static DebugEvent threadPausedEvent(PausedThread thread) { return DebugEvent.newBuilder().setThreadPaused(ThreadPausedEvent.newBuilder().setThread(thread)).build(); } static DebugEvent threadContinuedEvent(long threadId) { return DebugEvent.newBuilder().setThreadContinued(ThreadContinuedEvent.newBuilder().setThreadId(threadId)) .build(); } @Nullable static SkylarkDebuggingProtos.Location getLocationProto(@Nullable Location location) { if (location == null) { return null; } Location.LineAndColumn lineAndColumn = location.getStartLineAndColumn(); if (lineAndColumn == null) { return null; } return SkylarkDebuggingProtos.Location.newBuilder().setLineNumber(lineAndColumn.getLine()) .setColumnNumber(lineAndColumn.getColumn()).setPath(location.getPath().getPathString()).build(); } static SkylarkDebuggingProtos.Frame getFrameProto(DebugFrame frame) { SkylarkDebuggingProtos.Frame.Builder builder = SkylarkDebuggingProtos.Frame.newBuilder() .setFunctionName(frame.functionName()).addAllScope(getScopes(frame)); if (frame.location() != null) { builder.setLocation(getLocationProto(frame.location())); } return builder.build(); } private static ImmutableList<Scope> getScopes(DebugFrame frame) { ImmutableMap<String, Object> localVars = frame.lexicalFrameBindings(); if (localVars.isEmpty()) { return ImmutableList.of(getScope("global", frame.globalBindings())); } Map<String, Object> globalVars = new LinkedHashMap<>(frame.globalBindings()); // remove shadowed bindings localVars.keySet().forEach(globalVars::remove); return ImmutableList.of(getScope("local", localVars), getScope("global", globalVars)); } private static SkylarkDebuggingProtos.Scope getScope(String name, Map<String, Object> bindings) { SkylarkDebuggingProtos.Scope.Builder builder = SkylarkDebuggingProtos.Scope.newBuilder().setName(name); bindings.forEach((s, o) -> builder.addBinding(DebuggerSerialization.getValueProto(s, o))); return builder.build(); } static Stepping convertSteppingEnum(SkylarkDebuggingProtos.Stepping stepping) { switch (stepping) { case INTO: return Stepping.INTO; case OUT: return Stepping.OUT; case OVER: return Stepping.OVER; case NONE: return Stepping.NONE; case UNRECOGNIZED: // fall through to exception } throw new IllegalArgumentException("Unsupported stepping type"); } }