294 lines
15 KiB
JavaScript
294 lines
15 KiB
JavaScript
"use strict";
|
|
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
exports.DebugServer = undefined;
|
|
|
|
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
|
|
* Copyright (c) 2017-present, Facebook, Inc.
|
|
* All rights reserved.
|
|
*
|
|
* This source code is licensed under the BSD-style license found in the
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
*/
|
|
|
|
var _BreakpointManager = require("./BreakpointManager.js");
|
|
|
|
var _Breakpoint = require("./Breakpoint.js");
|
|
|
|
var _invariant = require("../invariant.js");
|
|
|
|
var _invariant2 = _interopRequireDefault(_invariant);
|
|
|
|
var _DebugMessage = require("./channel/DebugMessage.js");
|
|
|
|
var _DebuggerError = require("./DebuggerError.js");
|
|
|
|
var _realm = require("./../realm.js");
|
|
|
|
var _VariableManager = require("./VariableManager.js");
|
|
|
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
|
|
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
|
|
var DebugServer = exports.DebugServer = function () {
|
|
function DebugServer(channel, realm) {
|
|
_classCallCheck(this, DebugServer);
|
|
|
|
this._breakpoints = new _BreakpointManager.BreakpointManager();
|
|
this._previousExecutedLine = 0;
|
|
this._previousExecutedCol = 0;
|
|
this._lastRunRequestID = 0;
|
|
this._channel = channel;
|
|
this._realm = realm;
|
|
this._variableManager = new _VariableManager.VariableManager(realm);
|
|
this.waitForRun();
|
|
}
|
|
// the collection of breakpoints
|
|
|
|
// the channel to communicate with the adapter
|
|
|
|
|
|
_createClass(DebugServer, [{
|
|
key: "waitForRun",
|
|
|
|
/* Block until adapter says to run
|
|
/* ast: the current ast node we are stopped on
|
|
*/
|
|
value: function waitForRun(ast) {
|
|
var keepRunning = false;
|
|
var request = void 0;
|
|
while (!keepRunning) {
|
|
request = this._channel.readIn();
|
|
keepRunning = this.processDebuggerCommand(request, ast);
|
|
}
|
|
}
|
|
|
|
// Checking if the debugger needs to take any action on reaching this ast node
|
|
|
|
}, {
|
|
key: "checkForActions",
|
|
value: function checkForActions(ast) {
|
|
this.checkForBreakpoint(ast);
|
|
|
|
// last step: set the current location as the previously executed line
|
|
if (ast.loc && ast.loc.source !== null) {
|
|
this._previousExecutedFile = ast.loc.source;
|
|
this._previousExecutedLine = ast.loc.start.line;
|
|
this._previousExecutedCol = ast.loc.start.column;
|
|
}
|
|
}
|
|
|
|
// Try to find a breakpoint at the given location and check if we should stop on it
|
|
|
|
}, {
|
|
key: "findStoppableBreakpoint",
|
|
value: function findStoppableBreakpoint(filePath, lineNum, colNum) {
|
|
var breakpoint = this._breakpoints.getBreakpoint(filePath, lineNum, colNum);
|
|
if (breakpoint && breakpoint.enabled) {
|
|
// checking if this is the same file and line we stopped at last time
|
|
// if so, we should skip it this time
|
|
// Note: for the case when the debugger is supposed to stop on the same
|
|
// breakpoint consecutively (e.g. the statement is in a loop), some other
|
|
// ast node (e.g. block, loop) must have been checked in between so
|
|
// previousExecutedFile and previousExecutedLine will have changed
|
|
if (breakpoint.column !== 0) {
|
|
// this is a column breakpoint
|
|
if (filePath === this._previousExecutedFile && lineNum === this._previousExecutedLine && colNum === this._previousExecutedCol) {
|
|
return null;
|
|
}
|
|
} else {
|
|
// this is a line breakpoint
|
|
if (filePath === this._previousExecutedFile && lineNum === this._previousExecutedLine) {
|
|
return null;
|
|
}
|
|
}
|
|
return breakpoint;
|
|
}
|
|
return null;
|
|
}
|
|
}, {
|
|
key: "checkForBreakpoint",
|
|
value: function checkForBreakpoint(ast) {
|
|
if (ast.loc && ast.loc.source) {
|
|
var location = ast.loc;
|
|
var filePath = location.source;
|
|
if (filePath === null) return;
|
|
var lineNum = location.start.line;
|
|
var colNum = location.start.column;
|
|
// Check whether there is a breakpoint we need to stop on here
|
|
var breakpoint = this.findStoppableBreakpoint(filePath, lineNum, colNum);
|
|
if (breakpoint === null) return;
|
|
// Tell the adapter that Prepack has stopped on this breakpoint
|
|
this._channel.sendBreakpointStopped(breakpoint.filePath, breakpoint.line, breakpoint.column);
|
|
// Wait for the adapter to tell us to run again
|
|
this.waitForRun(ast);
|
|
}
|
|
}
|
|
|
|
// Process a command from a debugger. Returns whether Prepack should unblock
|
|
// if it is blocked
|
|
|
|
}, {
|
|
key: "processDebuggerCommand",
|
|
value: function processDebuggerCommand(request, ast) {
|
|
var requestID = request.id;
|
|
var command = request.command;
|
|
var args = request.arguments;
|
|
switch (command) {
|
|
case _DebugMessage.DebugMessage.BREAKPOINT_ADD_COMMAND:
|
|
(0, _invariant2.default)(args.kind === "breakpoint");
|
|
this._breakpoints.addBreakpointMulti(args.breakpoints);
|
|
this._channel.sendBreakpointsAcknowledge(_DebugMessage.DebugMessage.BREAKPOINT_ADD_ACKNOWLEDGE, requestID, args);
|
|
break;
|
|
case _DebugMessage.DebugMessage.BREAKPOINT_REMOVE_COMMAND:
|
|
(0, _invariant2.default)(args.kind === "breakpoint");
|
|
this._breakpoints.removeBreakpointMulti(args.breakpoints);
|
|
this._channel.sendBreakpointsAcknowledge(_DebugMessage.DebugMessage.BREAKPOINT_REMOVE_ACKNOWLEDGE, requestID, args);
|
|
break;
|
|
case _DebugMessage.DebugMessage.BREAKPOINT_ENABLE_COMMAND:
|
|
(0, _invariant2.default)(args.kind === "breakpoint");
|
|
this._breakpoints.enableBreakpointMulti(args.breakpoints);
|
|
this._channel.sendBreakpointsAcknowledge(_DebugMessage.DebugMessage.BREAKPOINT_ENABLE_ACKNOWLEDGE, requestID, args);
|
|
break;
|
|
case _DebugMessage.DebugMessage.BREAKPOINT_DISABLE_COMMAND:
|
|
(0, _invariant2.default)(args.kind === "breakpoint");
|
|
this._breakpoints.disableBreakpointMulti(args.breakpoints);
|
|
this._channel.sendBreakpointsAcknowledge(_DebugMessage.DebugMessage.BREAKPOINT_DISABLE_ACKNOWLEDGE, requestID, args);
|
|
break;
|
|
case _DebugMessage.DebugMessage.PREPACK_RUN_COMMAND:
|
|
(0, _invariant2.default)(args.kind === "run");
|
|
this._onDebuggeeResume();
|
|
return true;
|
|
case _DebugMessage.DebugMessage.STACKFRAMES_COMMAND:
|
|
(0, _invariant2.default)(args.kind === "stackframe");
|
|
(0, _invariant2.default)(ast !== undefined);
|
|
this.processStackframesCommand(requestID, args, ast);
|
|
break;
|
|
case _DebugMessage.DebugMessage.SCOPES_COMMAND:
|
|
(0, _invariant2.default)(args.kind === "scopes");
|
|
this.processScopesCommand(requestID, args);
|
|
break;
|
|
case _DebugMessage.DebugMessage.VARIABLES_COMMAND:
|
|
(0, _invariant2.default)(args.kind === "variables");
|
|
this.processVariablesCommand(requestID, args);
|
|
break;
|
|
default:
|
|
throw new _DebuggerError.DebuggerError("Invalid command", "Invalid command from adapter: " + command);
|
|
}
|
|
return false;
|
|
}
|
|
}, {
|
|
key: "processStackframesCommand",
|
|
value: function processStackframesCommand(requestID, args, ast) {
|
|
var frameInfos = [];
|
|
var loc = this._getFrameLocation(ast.loc);
|
|
var fileName = loc.fileName;
|
|
var line = loc.line;
|
|
var column = loc.column;
|
|
|
|
// the UI displays the current frame as index 0, so we iterate backwards
|
|
// from the current frame
|
|
for (var i = this._realm.contextStack.length - 1; i >= 0; i--) {
|
|
var frame = this._realm.contextStack[i];
|
|
var functionName = "(anonymous function)";
|
|
if (frame.function && frame.function.__originalName) {
|
|
functionName = frame.function.__originalName;
|
|
}
|
|
|
|
var frameInfo = {
|
|
id: this._realm.contextStack.length - 1 - i,
|
|
functionName: functionName,
|
|
fileName: fileName,
|
|
line: line,
|
|
column: column
|
|
};
|
|
frameInfos.push(frameInfo);
|
|
loc = this._getFrameLocation(frame.loc);
|
|
fileName = loc.fileName;
|
|
line = loc.line;
|
|
column = loc.column;
|
|
}
|
|
this._channel.sendStackframeResponse(requestID, frameInfos);
|
|
}
|
|
}, {
|
|
key: "_getFrameLocation",
|
|
value: function _getFrameLocation(loc) {
|
|
var fileName = "unknown";
|
|
var line = 0;
|
|
var column = 0;
|
|
if (loc && loc.source) {
|
|
fileName = loc.source;
|
|
line = loc.start.line;
|
|
column = loc.start.column;
|
|
}
|
|
return {
|
|
fileName: fileName,
|
|
line: line,
|
|
column: column
|
|
};
|
|
}
|
|
}, {
|
|
key: "processScopesCommand",
|
|
value: function processScopesCommand(requestID, args) {
|
|
// first check that frameId is in the valid range
|
|
if (args.frameId < 0 || args.frameId >= this._realm.contextStack.length) {
|
|
throw new _DebuggerError.DebuggerError("Invalid command", "Invalid frame id for scopes request: " + args.frameId);
|
|
}
|
|
// here the frameId is in reverse order of the contextStack, ie frameId 0
|
|
// refers to last element of contextStack
|
|
var stackIndex = this._realm.contextStack.length - 1 - args.frameId;
|
|
var context = this._realm.contextStack[stackIndex];
|
|
(0, _invariant2.default)(context instanceof _realm.ExecutionContext);
|
|
var scopes = [];
|
|
if (context.variableEnvironment) {
|
|
// get a new mapping for this collection of variables
|
|
var variableRef = this._variableManager.getReferenceForValue(context.variableEnvironment);
|
|
var scope = {
|
|
name: "Locals",
|
|
variablesReference: variableRef,
|
|
expensive: false
|
|
};
|
|
scopes.push(scope);
|
|
}
|
|
if (context.lexicalEnvironment) {
|
|
// get a new mapping for this collection of variables
|
|
var _variableRef = this._variableManager.getReferenceForValue(context.lexicalEnvironment);
|
|
var _scope = {
|
|
name: "Globals",
|
|
variablesReference: _variableRef,
|
|
expensive: false
|
|
};
|
|
scopes.push(_scope);
|
|
}
|
|
this._channel.sendScopesResponse(requestID, scopes);
|
|
}
|
|
}, {
|
|
key: "processVariablesCommand",
|
|
value: function processVariablesCommand(requestID, args) {
|
|
var variables = this._variableManager.getVariablesByReference(args.variablesReference);
|
|
this._channel.sendVariablesResponse(requestID, variables);
|
|
}
|
|
|
|
// actions that need to happen before Prepack can resume
|
|
|
|
}, {
|
|
key: "_onDebuggeeResume",
|
|
value: function _onDebuggeeResume() {
|
|
// resets the variable manager
|
|
this._variableManager.clean();
|
|
}
|
|
}, {
|
|
key: "shutdown",
|
|
value: function shutdown() {
|
|
//let the adapter know Prepack is done running
|
|
this._channel.sendPrepackFinish();
|
|
}
|
|
}]);
|
|
|
|
return DebugServer;
|
|
}();
|
|
//# sourceMappingURL=Debugger.js.map
|