Add stackframe requests to debugger

Summary:
Release note: none

- move id into DebuggerRequest
- create DebuggerResponse types
- stackframe request from UI
- Prepack compute stack frames and send back
Closes https://github.com/facebook/prepack/pull/1126

Differential Revision: D6232933

Pulled By: JWZ2018

fbshipit-source-id: d14d9da82b8b03dc77bc5a41d62faf026594e315
This commit is contained in:
Wuhan Zhou 2017-11-03 10:47:46 -07:00 committed by Facebook Github Bot
parent 4944f2e939
commit 3334237ab7
11 changed files with 326 additions and 53 deletions

View File

@ -25,7 +25,7 @@ export default function(opts: RealmOptions = {}, debugChannel: void | DebugChann
let r = new Realm(opts);
if (debugChannel) {
if (debugChannel.debuggerIsAttached()) {
r.debuggerInstance = new DebugServer(debugChannel);
r.debuggerInstance = new DebugServer(debugChannel, r);
}
}

View File

@ -16,15 +16,17 @@ import invariant from "../invariant.js";
import type { DebugChannel } from "./channel/DebugChannel.js";
import { DebugMessage } from "./channel/DebugMessage.js";
import { DebuggerError } from "./DebuggerError.js";
import type { DebuggerRequest } from "./types.js";
import type { DebuggerRequest, StackframeArguments, Stackframe } from "./types.js";
import type { Realm } from "./../realm.js";
export class DebugServer {
constructor(channel: DebugChannel) {
constructor(channel: DebugChannel, realm: Realm) {
this._breakpoints = new BreakpointCollection();
this._previousExecutedLine = 0;
this._previousExecutedCol = 0;
this._lastRunRequestID = 0;
this._channel = channel;
this._realm = realm;
this.waitForRun();
}
// the collection of breakpoints
@ -35,6 +37,7 @@ export class DebugServer {
// the channel to communicate with the adapter
_channel: DebugChannel;
_lastRunRequestID: number;
_realm: Realm;
/* Block until adapter says to run
/* runCondition: a function that determines whether the adapter has told
@ -110,38 +113,76 @@ export class DebugServer {
// Process a command from a debugger. Returns whether Prepack should unblock
// if it is blocked
processDebuggerCommand(request: DebuggerRequest) {
let requestID = request.id;
let command = request.command;
let args = request.arguments;
switch (command) {
case DebugMessage.BREAKPOINT_ADD_COMMAND:
invariant(args.kind === "breakpoint");
this._breakpoints.addBreakpoint(args.filePath, args.line, args.column);
this._channel.sendBreakpointAcknowledge(DebugMessage.BREAKPOINT_ADD_ACKNOWLEDGE, args);
this._channel.sendBreakpointAcknowledge(DebugMessage.BREAKPOINT_ADD_ACKNOWLEDGE, requestID, args);
break;
case DebugMessage.BREAKPOINT_REMOVE_COMMAND:
invariant(args.kind === "breakpoint");
this._breakpoints.removeBreakpoint(args.filePath, args.line, args.column);
this._channel.sendBreakpointAcknowledge(DebugMessage.BREAKPOINT_REMOVE_ACKNOWLEDGE, args);
this._channel.sendBreakpointAcknowledge(DebugMessage.BREAKPOINT_REMOVE_ACKNOWLEDGE, requestID, args);
break;
case DebugMessage.BREAKPOINT_ENABLE_COMMAND:
invariant(args.kind === "breakpoint");
this._breakpoints.enableBreakpoint(args.filePath, args.line, args.column);
this._channel.sendBreakpointAcknowledge(DebugMessage.BREAKPOINT_ENABLE_ACKNOWLEDGE, args);
this._channel.sendBreakpointAcknowledge(DebugMessage.BREAKPOINT_ENABLE_ACKNOWLEDGE, requestID, args);
break;
case DebugMessage.BREAKPOINT_DISABLE_COMMAND:
invariant(args.kind === "breakpoint");
this._breakpoints.disableBreakpoint(args.filePath, args.line, args.column);
this._channel.sendBreakpointAcknowledge(DebugMessage.BREAKPOINT_DISABLE_ACKNOWLEDGE, args);
this._channel.sendBreakpointAcknowledge(DebugMessage.BREAKPOINT_DISABLE_ACKNOWLEDGE, requestID, args);
break;
case DebugMessage.PREPACK_RUN_COMMAND:
invariant(args.kind === "run");
return true;
case DebugMessage.STACKFRAMES_COMMAND:
invariant(args.kind === "stackframe");
this.processStackframesCommand(requestID, args);
break;
default:
throw new DebuggerError("Invalid command", "Invalid command from adapter: " + command);
}
return false;
}
processStackframesCommand(requestID: number, args: StackframeArguments) {
let frameInfos: Array<Stackframe> = [];
let loc = this._realm.currentLocation;
// the UI displays the current frame as index 0, so we iterate backwards
// from the current frame
for (let i = this._realm.contextStack.length - 1; i >= 0; i--) {
let frame = this._realm.contextStack[i];
let functionName = "(anonymous function)";
if (frame.function && frame.function.__originalName) {
functionName = frame.function.__originalName;
}
let fileName = "unknown";
let line = 0;
let column = 0;
if (loc && loc.source) {
fileName = loc.source;
line = loc.start.line;
column = loc.start.column;
}
let frameInfo: Stackframe = {
id: this._realm.contextStack.length - 1 - i,
functionName: functionName,
fileName: fileName,
line: line,
column: column,
};
frameInfos.push(frameInfo);
loc = frame.loc;
}
this._channel.sendStackframeResponse(requestID, frameInfos);
}
shutdown() {
//let the adapter know Prepack is done running
this._channel.sendPrepackFinish();

View File

@ -24,7 +24,7 @@ import type { DebuggerOptions } from "./../../options.js";
import { getDebuggerOptions } from "./../../prepack-options.js";
import invariant from "./../../invariant.js";
import { DebugMessage } from "./../channel/DebugMessage.js";
import type { BreakpointArguments } from "./../types.js";
import type { BreakpointArguments, DebuggerResponse } from "./../types.js";
import { DebuggerConstants } from "./../DebuggerConstants.js";
/* An implementation of an debugger adapter adhering to the VSCode Debug protocol
@ -132,12 +132,22 @@ class PrepackDebugSession extends LoggingDebugSession {
}
_registerMessageCallbacks() {
this._adapterChannel.registerChannelEvent(DebugMessage.PREPACK_READY_RESPONSE, (message: string) => {
this._adapterChannel.registerChannelEvent(DebugMessage.PREPACK_READY_RESPONSE, (response: DebuggerResponse) => {
this.sendEvent(new StoppedEvent("entry", DebuggerConstants.PREPACK_THREAD_ID));
});
this._adapterChannel.registerChannelEvent(DebugMessage.BREAKPOINT_STOPPED_RESPONSE, (description: string) => {
this.sendEvent(new StoppedEvent("breakpoint " + description, DebuggerConstants.PREPACK_THREAD_ID));
});
this._adapterChannel.registerChannelEvent(
DebugMessage.BREAKPOINT_STOPPED_RESPONSE,
(response: DebuggerResponse) => {
let result = response.result;
invariant(result.kind === "breakpoint-stopped");
this.sendEvent(
new StoppedEvent(
"breakpoint " + `${result.filePath} ${result.line}:${result.column}`,
DebuggerConstants.PREPACK_THREAD_ID
)
);
}
);
}
_addRequestCallback(requestID: number, callback: string => void) {
@ -166,7 +176,7 @@ class PrepackDebugSession extends LoggingDebugSession {
*/
continueRequest(response: DebugProtocol.ContinueResponse, args: DebugProtocol.ContinueArguments): void {
// send a Run request to Prepack and try to send the next request
this._adapterChannel.run(response.request_seq, (message: string) => {
this._adapterChannel.run(response.request_seq, (dbgResponse: DebuggerResponse) => {
this.sendResponse(response);
});
}
@ -193,7 +203,33 @@ class PrepackDebugSession extends LoggingDebugSession {
};
breakpointInfos.push(breakpointInfo);
}
this._adapterChannel.setBreakpoints(response.request_seq, breakpointInfos, (message: string) => {
this._adapterChannel.setBreakpoints(response.request_seq, breakpointInfos, (dbgResponse: DebuggerResponse) => {
this.sendResponse(response);
});
}
stackTraceRequest(response: DebugProtocol.StackTraceResponse, args: DebugProtocol.StackTraceArguments): void {
this._adapterChannel.getStackFrames(response.request_seq, (dbgResponse: DebuggerResponse) => {
let result = dbgResponse.result;
invariant(result.kind === "stackframe");
let frameInfos = result.stackframes;
let frames: Array<DebugProtocol.StackFrame> = [];
for (const frameInfo of frameInfos) {
let source: DebugProtocol.Source = {
path: frameInfo.fileName,
};
let frame: DebugProtocol.StackFrame = {
id: frameInfo.id,
name: frameInfo.functionName,
source: source,
line: frameInfo.line,
column: frameInfo.column,
};
frames.push(frame);
}
response.body = {
stackFrames: frames,
};
this.sendResponse(response);
});
}

View File

@ -16,7 +16,7 @@ import EventEmitter from "events";
import invariant from "./../../invariant.js";
import { DebugMessage } from "./DebugMessage.js";
import { DebuggerConstants } from "./../DebuggerConstants.js";
import type { BreakpointArguments } from "./../types.js";
import type { BreakpointArguments, DebuggerResponse } from "./../types.js";
//Channel used by the debug adapter to communicate with Prepack
export class AdapterChannel {
@ -32,7 +32,7 @@ export class AdapterChannel {
_ioWrapper: FileIOWrapper;
_marshaller: MessageMarshaller;
_queue: Queue;
_pendingRequestCallbacks: { [number]: (string) => void };
_pendingRequestCallbacks: { [number]: (DebuggerResponse) => void };
_prepackWaiting: boolean;
_eventEmitter: EventEmitter;
@ -46,22 +46,30 @@ export class AdapterChannel {
let parts = message.split(" ");
let requestID = parseInt(parts[0], 10);
invariant(!isNaN(requestID));
let prefix = parts[1];
if (prefix === DebugMessage.PREPACK_READY_RESPONSE) {
let messageType = parts[1];
if (messageType === DebugMessage.PREPACK_READY_RESPONSE) {
let result = this._marshaller.unmarshallReadyResponse(requestID);
this._prepackWaiting = true;
this._eventEmitter.emit(DebugMessage.PREPACK_READY_RESPONSE);
this._eventEmitter.emit(DebugMessage.PREPACK_READY_RESPONSE, result);
this.trySendNextRequest();
} else if (prefix === DebugMessage.BREAKPOINT_ADD_ACKNOWLEDGE) {
this._eventEmitter.emit(DebugMessage.BREAKPOINT_ADD_ACKNOWLEDGE, requestID, message);
} else if (messageType === DebugMessage.BREAKPOINT_ADD_ACKNOWLEDGE) {
let dbgResponse = this._marshaller.unmarshallBreakpointAddResponse(requestID);
this._eventEmitter.emit(DebugMessage.BREAKPOINT_ADD_ACKNOWLEDGE, requestID, dbgResponse);
// Prepack acknowledged adding a breakpoint
this._prepackWaiting = true;
this._processRequestCallback(requestID, message);
this._processRequestCallback(requestID, dbgResponse);
this.trySendNextRequest();
} else if (prefix === DebugMessage.BREAKPOINT_STOPPED_RESPONSE) {
this._eventEmitter.emit(DebugMessage.BREAKPOINT_STOPPED_RESPONSE, parts.slice(2).join(" "));
} else if (messageType === DebugMessage.BREAKPOINT_STOPPED_RESPONSE) {
let dbgResponse = this._marshaller.unmarshallBreakpointStoppedResponse(requestID, parts.slice(2));
this._eventEmitter.emit(DebugMessage.BREAKPOINT_STOPPED_RESPONSE, dbgResponse);
// Prepack stopped on a breakpoint
this._prepackWaiting = true;
this._processRequestCallback(requestID, message);
this._processRequestCallback(requestID, dbgResponse);
this.trySendNextRequest();
} else if (messageType === DebugMessage.STACKFRAMES_RESPONSE) {
let dbgResponse = this._marshaller.unmarshallStackframesResponse(requestID, parts.slice(2).join(" "));
this._prepackWaiting = true;
this._processRequestCallback(requestID, dbgResponse);
this.trySendNextRequest();
}
}
@ -79,38 +87,44 @@ export class AdapterChannel {
return true;
}
_addRequestCallback(requestID: number, callback: string => void) {
_addRequestCallback(requestID: number, callback: DebuggerResponse => void) {
invariant(!(requestID in this._pendingRequestCallbacks), "Request ID already exists in pending requests");
this._pendingRequestCallbacks[requestID] = callback;
}
_processRequestCallback(requestID: number, message: string) {
_processRequestCallback(requestID: number, response: DebuggerResponse) {
invariant(
requestID in this._pendingRequestCallbacks,
"Request ID does not exist in pending requests: " + requestID
);
let callback = this._pendingRequestCallbacks[requestID];
callback(message);
callback(response);
}
registerChannelEvent(event: string, listener: (message: string) => void) {
registerChannelEvent(event: string, listener: (response: DebuggerResponse) => void) {
this._eventEmitter.addListener(event, listener);
}
run(requestID: number, callback: string => void) {
run(requestID: number, callback: DebuggerResponse => void) {
this._queue.enqueue(this._marshaller.marshallContinueRequest(requestID));
this.trySendNextRequest();
this._addRequestCallback(requestID, callback);
}
setBreakpoints(requestID: number, breakpoints: Array<BreakpointArguments>, callback: string => void) {
setBreakpoints(requestID: number, breakpoints: Array<BreakpointArguments>, callback: DebuggerResponse => void) {
for (const breakpoint of breakpoints) {
this._queue.enqueue(this._marshaller.marshallSetBreakpointsRequest(breakpoint));
this._queue.enqueue(this._marshaller.marshallSetBreakpointsRequest(requestID, breakpoint));
}
this.trySendNextRequest();
this._addRequestCallback(requestID, callback);
}
getStackFrames(requestID: number, callback: DebuggerResponse => void) {
this._queue.enqueue(this._marshaller.marshallStackFramesRequest(requestID));
this.trySendNextRequest();
this._addRequestCallback(requestID, callback);
}
writeOut(contents: string) {
this._ioWrapper.writeOutSync(contents);
}

View File

@ -13,7 +13,14 @@ import { FileIOWrapper } from "./FileIOWrapper.js";
import { DebugMessage } from "./DebugMessage.js";
import { MessageMarshaller } from "./MessageMarshaller.js";
import { DebuggerError } from "./../DebuggerError.js";
import type { DebuggerRequest, DebuggerRequestArguments, BreakpointArguments, RunArguments } from "./../types.js";
import type {
DebuggerRequest,
DebuggerRequestArguments,
BreakpointArguments,
RunArguments,
StackframeArguments,
Stackframe,
} from "./../types.js";
//Channel used by the DebugServer in Prepack to communicate with the debug adapter
export class DebugChannel {
@ -69,18 +76,24 @@ export class DebugChannel {
this._lastRunRequestID = requestID;
let runArgs: RunArguments = {
kind: "run",
requestID: requestID,
};
args = runArgs;
break;
case DebugMessage.BREAKPOINT_ADD_COMMAND:
args = this._marshaller.unmarshallBreakpointArguments(requestID, parts.slice(2));
break;
case DebugMessage.STACKFRAMES_COMMAND:
let stackFrameArgs: StackframeArguments = {
kind: "stackframe",
};
args = stackFrameArgs;
break;
default:
throw new DebuggerError("Invalid command", "Invalid command from adapter: " + command);
}
invariant(args !== undefined);
let result: DebuggerRequest = {
id: requestID,
command: command,
arguments: args,
};
@ -95,21 +108,24 @@ export class DebugChannel {
this._requestReceived = false;
}
sendBreakpointAcknowledge(prefix: string, args: BreakpointArguments): void {
sendBreakpointAcknowledge(messageType: string, requestID: number, args: BreakpointArguments): void {
this.writeOut(
this._marshaller.marshallBreakpointAcknowledge(args.requestID, prefix, args.filePath, args.line, args.column)
this._marshaller.marshallBreakpointAcknowledge(requestID, messageType, args.filePath, args.line, args.column)
);
}
sendBreakpointStopped(filePath: string, line: number, column: number): void {
let breakpointInfo: BreakpointArguments = {
requestID: this._lastRunRequestID,
kind: "breakpoint",
filePath: filePath,
line: line,
column: column,
};
this.writeOut(this._marshaller.marshallBreakpointStopped(breakpointInfo));
this.writeOut(this._marshaller.marshallBreakpointStopped(this._lastRunRequestID, breakpointInfo));
}
sendStackframeResponse(requestID: number, stackframes: Array<Stackframe>): void {
this.writeOut(this._marshaller.marshallStackFramesResponse(requestID, stackframes));
}
sendPrepackFinish(): void {

View File

@ -24,14 +24,20 @@ export class DebugMessage {
static BREAKPOINT_ENABLE_COMMAND: string = "Breakpoint-enable-command";
// Command to disable a breakpoint
static BREAKPOINT_DISABLE_COMMAND: string = "Breakpoint-disable-command";
// Command to fetch stack frames
static STACKFRAMES_COMMAND: string = "Stackframes-command";
/* Messages from Prepack to adapter */
/* Messages from Prepack to adapter with requested information */
// Respond to the adapter that Prepack is ready
static PREPACK_READY_RESPONSE: string = "PrepackReady";
// Respond to the adapter that Prepack is finished
static PREPACK_FINISH_RESPONSE: string = "PrepackFinish";
// Respond to the adapter that Prepack has stopped on a breakpoint
static BREAKPOINT_STOPPED_RESPONSE: string = "Breakpoint-stopped";
static BREAKPOINT_STOPPED_RESPONSE: string = "Breakpoint-stopped-response";
// Respond to the adapter with the request stackframes
static STACKFRAMES_RESPONSE: string = "Stackframes-response";
/* Messages from Prepack to adapter to acknowledge having received the request */
// Acknowledgement for setting a breakpoint
static BREAKPOINT_ADD_ACKNOWLEDGE: string = "Breakpoint-add-acknowledge";
// Acknowledgement for removing a breakpoint

View File

@ -9,8 +9,17 @@
/* @flow */
import { DebugMessage } from "./DebugMessage.js";
import type { BreakpointArguments } from "./../types.js";
import type {
BreakpointArguments,
Stackframe,
DebuggerResponse,
StackframeResult,
BreakpointAddResult,
BreakpointStoppedResult,
ReadyResult,
} from "./../types.js";
import invariant from "./../../invariant.js";
import { DebuggerError } from "./../DebuggerError.js";
export class MessageMarshaller {
marshallBreakpointAcknowledge(
@ -23,8 +32,8 @@ export class MessageMarshaller {
return `${requestID} ${prefix} ${filePath} ${line} ${column}`;
}
marshallBreakpointStopped(args: BreakpointArguments): string {
return `${args.requestID} ${DebugMessage.BREAKPOINT_STOPPED_RESPONSE} ${args.filePath} ${args.line}:${args.column}`;
marshallBreakpointStopped(requestID: number, args: BreakpointArguments): string {
return `${requestID} ${DebugMessage.BREAKPOINT_STOPPED_RESPONSE} ${args.filePath} ${args.line} ${args.column}`;
}
marshallPrepackFinish(requestID: number): string {
@ -39,8 +48,16 @@ export class MessageMarshaller {
return `${requestID} ${DebugMessage.PREPACK_RUN_COMMAND}`;
}
marshallSetBreakpointsRequest(args: BreakpointArguments): string {
return `${args.requestID} ${DebugMessage.BREAKPOINT_ADD_COMMAND} ${args.filePath} ${args.line} ${args.column}`;
marshallSetBreakpointsRequest(requestID: number, args: BreakpointArguments): string {
return `${requestID} ${DebugMessage.BREAKPOINT_ADD_COMMAND} ${args.filePath} ${args.line} ${args.column}`;
}
marshallStackFramesRequest(requestID: number): string {
return `${requestID} ${DebugMessage.STACKFRAMES_COMMAND}`;
}
marshallStackFramesResponse(requestID: number, stackframes: Array<Stackframe>) {
return `${requestID} ${DebugMessage.STACKFRAMES_RESPONSE} ${JSON.stringify(stackframes)}`;
}
unmarshallBreakpointArguments(requestID: number, parts: Array<string>): BreakpointArguments {
@ -55,7 +72,6 @@ export class MessageMarshaller {
}
let result: BreakpointArguments = {
requestID: requestID,
kind: "breakpoint",
filePath: filePath,
line: lineNum,
@ -63,4 +79,71 @@ export class MessageMarshaller {
};
return result;
}
unmarshallStackframesResponse(requestID: number, responseBody: string): DebuggerResponse {
try {
let frames = JSON.parse(responseBody);
invariant(Array.isArray(frames), "Stack frames is not an array");
for (const frame of frames) {
invariant(frame.hasOwnProperty("id"), "Stack frame is missing id");
invariant(frame.hasOwnProperty("fileName"), "Stack frame is missing filename");
invariant(frame.hasOwnProperty("line"), "Stack frame is missing line number");
invariant(frame.hasOwnProperty("column"), "Stack frame is missing column number");
invariant(frame.hasOwnProperty("functionName"), "Stack frame is missing function name");
}
let result: StackframeResult = {
kind: "stackframe",
stackframes: frames,
};
let dbgResponse: DebuggerResponse = {
id: requestID,
result: result,
};
return dbgResponse;
} catch (e) {
throw new DebuggerError("Invalid response", e.message);
}
}
unmarshallBreakpointAddResponse(requestID: number): DebuggerResponse {
let result: BreakpointAddResult = {
kind: "breakpoint-add",
};
let dbgResponse: DebuggerResponse = {
id: requestID,
result: result,
};
return dbgResponse;
}
unmarshallBreakpointStoppedResponse(requestID: number, parts: Array<string>): DebuggerResponse {
invariant(parts.length === 3, "Incorrect number of arguments in breakpoint stopped response");
let filePath = parts[0];
let line = parseInt(parts[1], 10);
invariant(!isNaN(line), "Invalid line number");
let column = parseInt(parts[2], 10);
invariant(!isNaN(column), "Invalid column number");
let result: BreakpointStoppedResult = {
kind: "breakpoint-stopped",
filePath: filePath,
line: line,
column: column,
};
let dbgResponse: DebuggerResponse = {
id: requestID,
result: result,
};
return dbgResponse;
}
unmarshallReadyResponse(requestID: number): DebuggerResponse {
let result: ReadyResult = {
kind: "ready",
};
let dbgResponse: DebuggerResponse = {
id: requestID,
result: result,
};
return dbgResponse;
}
}

View File

@ -13,6 +13,7 @@ import readline from "readline";
import child_process from "child_process";
import * as DebugProtocol from "vscode-debugprotocol";
import { DataHandler } from "./DataHandler.js";
import { DebuggerConstants } from "./../DebuggerConstants";
//separator for messages according to the protocol
const TWO_CRLF = "\r\n\r\n";
@ -131,6 +132,20 @@ export class UISession {
_processResponse(response: DebugProtocol.Response) {
if (response.command === "threads") {
this._processThreadsResponse(((response: any): DebugProtocol.ThreadsResponse));
} else if (response.command === "stackTrace") {
//flow doesn't have type refinement for interfaces, so must do a cast here
this._processStackTraceResponse(((response: any): DebugProtocol.StackTraceResponse));
}
}
_processStackTraceResponse(response: DebugProtocol.StackTraceResponse) {
let frames = response.body.stackFrames;
for (const frame of frames) {
if (frame.source && frame.source.path) {
this._uiOutput(`${frame.id}: ${frame.name} ${frame.source.path} ${frame.line}:${frame.column}`);
} else {
this._uiOutput(`${frame.id}: ${frame.name} unknown source`);
}
}
}
@ -155,7 +170,7 @@ export class UISession {
if (parts.length !== 1) return false;
let continueArgs: DebugProtocol.ContinueArguments = {
// Prepack will only have 1 thread, this argument will be ignored
threadId: 1,
threadId: DebuggerConstants.PREPACK_THREAD_ID,
};
this._sendContinueRequest(continueArgs);
break;
@ -174,6 +189,14 @@ export class UISession {
this._sendBreakpointRequest(filePath, line, column);
}
break;
case "stackframes":
// format: stackFrames
let stackFrameArgs: DebugProtocol.StackTraceArguments = {
// Prepack will only have 1 thread, this argument will be ignored
threadId: DebuggerConstants.PREPACK_THREAD_ID,
};
this._sendStackFramesRequest(stackFrameArgs);
break;
case "threads":
if (parts.length !== 1) return false;
this._sendThreadsRequest();
@ -267,6 +290,17 @@ export class UISession {
this._packageAndSend(json);
}
_sendStackFramesRequest(args: DebugProtocol.StackTraceArguments) {
let message = {
type: "request",
seq: this._sequenceNum,
command: "stackTrace",
arguments: args,
};
let json = JSON.stringify(message);
this._packageAndSend(json);
}
_sendThreadsRequest() {
let message = {
type: "request",

View File

@ -10,14 +10,14 @@
/* @flow */
export type DebuggerRequest = {
id: number,
command: string,
arguments: DebuggerRequestArguments,
};
export type DebuggerRequestArguments = BreakpointArguments | RunArguments;
export type DebuggerRequestArguments = BreakpointArguments | RunArguments | StackframeArguments;
export type BreakpointArguments = {
requestID: number,
kind: "breakpoint",
filePath: string,
line: number,
@ -25,6 +25,44 @@ export type BreakpointArguments = {
};
export type RunArguments = {
requestID: number,
kind: "run",
};
export type StackframeArguments = {
kind: "stackframe",
};
export type Stackframe = {
id: number,
fileName: string,
line: number,
column: number,
functionName: string,
};
export type DebuggerResponse = {
id: number,
result: DebuggerResponseResult,
};
export type DebuggerResponseResult = ReadyResult | StackframeResult | BreakpointAddResult | BreakpointStoppedResult;
export type ReadyResult = {
kind: "ready",
};
export type StackframeResult = {
kind: "stackframe",
stackframes: Array<Stackframe>,
};
export type BreakpointAddResult = {
kind: "breakpoint-add",
};
export type BreakpointStoppedResult = {
kind: "breakpoint-stopped",
filePath: string,
line: number,
column: number,
};

View File

@ -9,7 +9,7 @@
/* @flow */
import type { Intrinsics, PropertyBinding, Descriptor } from "./types.js";
import type { Intrinsics, PropertyBinding, Descriptor, DebugServerType } from "./types.js";
import { CompilerDiagnostic, type ErrorHandlerResult, type ErrorHandler, FatalError } from "./errors.js";
import {
AbstractObjectValue,
@ -44,7 +44,6 @@ import seedrandom from "seedrandom";
import { Generator, PreludeGenerator } from "./utils/generator.js";
import type { BabelNode, BabelNodeSourceLocation, BabelNodeLVal, BabelNodeStatement } from "babel-types";
import * as t from "babel-types";
import { DebugServer } from "./debugger/Debugger.js";
export type Bindings = Map<Binding, void | Value>;
export type EvaluationResult = Completion | Reference | Value;
@ -267,7 +266,7 @@ export class Realm {
globalSymbolRegistry: Array<{ $Key: string, $Symbol: SymbolValue }>;
debuggerInstance: DebugServer | void;
debuggerInstance: DebugServerType | void;
// to force flow to type the annotations
isCompatibleWith(compatibility: Compatibility): boolean {

View File

@ -24,6 +24,7 @@ import type {
AbstractObjectValue,
} from "./values/index.js";
import { ObjectValue } from "./values/index.js";
import { BabelNode } from "babel-types";
export const ElementSize = {
Float32: 4,
@ -283,3 +284,8 @@ export type ObjectKind =
| TypedArrayKind
| "ReactElement";
// TODO #26 #712: Promises. All kinds of iterators. Generators.
export type DebugServerType = {
checkForActions: BabelNode => void,
shutdown: () => void,
};