Bug 876776 - Import latest version of js/examples/jorendb.js. DONTBUILD
This commit is contained in:
@@ -5,12 +5,13 @@
|
|||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* jorendb is a simple command-line debugger for shell-js programs. It is
|
* jorendb is a simple command-line debugger for shell-js programs. It is
|
||||||
* intended as a demo of the Debugger object (as there are no shell js programs to
|
* intended as a demo of the Debugger object (as there are no shell js programs
|
||||||
* speak of).
|
* to speak of).
|
||||||
*
|
*
|
||||||
* To run it: $JS -d path/to/this/file/jorendb.js
|
* To run it: $JS -d path/to/this/file/jorendb.js
|
||||||
* To run some JS code under it, try:
|
* To run some JS code under it, try:
|
||||||
@@ -18,367 +19,492 @@
|
|||||||
* Execution will stop at debugger statements and you'll get a jorendb prompt.
|
* Execution will stop at debugger statements and you'll get a jorendb prompt.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(function () {
|
// Debugger state.
|
||||||
var debuggerSource = "(" + function () {
|
var focusedFrame = null;
|
||||||
// Debugger state.
|
var topFrame = null;
|
||||||
var focusedFrame = null;
|
var debuggeeValues = {};
|
||||||
var topFrame = null;
|
var nextDebuggeeValueIndex = 1;
|
||||||
var debuggeeValues = [null];
|
var lastExc = null;
|
||||||
var lastExc = null;
|
|
||||||
|
|
||||||
// Convert a debuggee value v to a string.
|
// Cleanup functions to run when we next re-enter the repl.
|
||||||
function dvToString(v) {
|
var replCleanups = [];
|
||||||
return (typeof v !== 'object' || v === null) ? uneval(v) : "[object " + v.class + "]";
|
|
||||||
|
// Convert a debuggee value v to a string.
|
||||||
|
function dvToString(v) {
|
||||||
|
return (typeof v !== 'object' || v === null) ? uneval(v) : "[object " + v.class + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
function showDebuggeeValue(dv) {
|
||||||
|
var dvrepr = dvToString(dv);
|
||||||
|
var i = nextDebuggeeValueIndex++;
|
||||||
|
debuggeeValues["$" + i] = dv;
|
||||||
|
print("$" + i + " = " + dvrepr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(Debugger.Frame.prototype, "num", {
|
||||||
|
configurable: true,
|
||||||
|
enumerable: false,
|
||||||
|
get: function () {
|
||||||
|
var i = 0;
|
||||||
|
for (var f = topFrame; f && f !== this; f = f.older)
|
||||||
|
i++;
|
||||||
|
return f === null ? undefined : i;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function showDebuggeeValue(dv) {
|
Debugger.Frame.prototype.frameDescription = function frameDescription() {
|
||||||
var dvrepr = dvToString(dv);
|
if (this.type == "call")
|
||||||
var i = debuggeeValues.length;
|
return ((this.callee.name || '<anonymous>') +
|
||||||
debuggeeValues[i] = dv;
|
"(" + this.arguments.map(dvToString).join(", ") + ")");
|
||||||
print("$" + i + " = " + dvrepr);
|
else
|
||||||
}
|
return this.type + " code";
|
||||||
|
}
|
||||||
|
|
||||||
Object.defineProperty(Debugger.Frame.prototype, "num", {
|
Debugger.Frame.prototype.positionDescription = function positionDescription() {
|
||||||
configurable: true,
|
if (this.script) {
|
||||||
enumerable: false,
|
var line = this.script.getOffsetLine(this.offset);
|
||||||
get: function () {
|
if (this.script.url)
|
||||||
var i = 0;
|
return this.script.url + ":" + line;
|
||||||
for (var f = topFrame; f && f !== this; f = f.older)
|
return "line " + line;
|
||||||
i++;
|
}
|
||||||
return f === null ? undefined : i;
|
return null;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
function framePosition(f) {
|
Debugger.Frame.prototype.fullDescription = function fullDescription() {
|
||||||
if (!f.script)
|
var fr = this.frameDescription();
|
||||||
return f.type + " code";
|
var pos = this.positionDescription();
|
||||||
return (f.script.url || f.type + " code") + ":" + f.script.getOffsetLine(f.offset);
|
if (pos)
|
||||||
}
|
return fr + ", " + pos;
|
||||||
|
return fr;
|
||||||
|
}
|
||||||
|
|
||||||
function callDescription(f) {
|
Object.defineProperty(Debugger.Frame.prototype, "line", {
|
||||||
return ((f.callee.name || '<anonymous>') +
|
configurable: true,
|
||||||
"(" + f.arguments.map(dvToString).join(", ") + ")");
|
enumerable: false,
|
||||||
}
|
get: function() {
|
||||||
|
if (this.script)
|
||||||
function showFrame(f, n) {
|
return this.script.getOffsetLine(this.offset);
|
||||||
if (f === undefined || f === null) {
|
|
||||||
f = focusedFrame;
|
|
||||||
if (f === null) {
|
|
||||||
print("No stack.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (n === undefined) {
|
|
||||||
n = f.num;
|
|
||||||
if (n === undefined)
|
|
||||||
throw new Error("Internal error: frame not on stack");
|
|
||||||
}
|
|
||||||
|
|
||||||
var me = '#' + n;
|
|
||||||
if (f.type === "call")
|
|
||||||
me += ' ' + callDescription(f);
|
|
||||||
me += ' ' + framePosition(f);
|
|
||||||
print(me);
|
|
||||||
}
|
|
||||||
|
|
||||||
function saveExcursion(fn) {
|
|
||||||
var tf = topFrame, ff = focusedFrame;
|
|
||||||
try {
|
|
||||||
return fn();
|
|
||||||
} finally {
|
|
||||||
topFrame = tf;
|
|
||||||
focusedFrame = ff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function quitCommand() {
|
|
||||||
dbg.enabled = false;
|
|
||||||
quit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function backtraceCommand() {
|
|
||||||
if (topFrame === null)
|
|
||||||
print("No stack.");
|
|
||||||
for (var i = 0, f = topFrame; f; i++, f = f.older)
|
|
||||||
showFrame(f, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
function printCommand(rest) {
|
|
||||||
if (focusedFrame === null) {
|
|
||||||
// This is super bogus, need a way to create an env wrapping the debuggeeGlobal
|
|
||||||
// and eval against that.
|
|
||||||
var nonwrappedValue;
|
|
||||||
try {
|
|
||||||
nonwrappedValue = debuggeeGlobal.eval(rest);
|
|
||||||
} catch (exc) {
|
|
||||||
print("Exception caught.");
|
|
||||||
nonwrappedValue = exc;
|
|
||||||
}
|
|
||||||
if (typeof nonwrappedValue !== "object" || nonwrappedValue === null) {
|
|
||||||
// primitive value, no sweat
|
|
||||||
print(" " + uneval(nonwrappedValue));
|
|
||||||
} else {
|
|
||||||
// junk for now
|
|
||||||
print(" " + Object.prototype.toString.call(nonwrappedValue));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// This is the real deal.
|
|
||||||
var cv = saveExcursion(function () {
|
|
||||||
return focusedFrame.eval(rest);
|
|
||||||
});
|
|
||||||
if (cv === null) {
|
|
||||||
if (!dbg.enabled)
|
|
||||||
return [cv];
|
|
||||||
print("Debuggee died.");
|
|
||||||
} else if ('return' in cv) {
|
|
||||||
if (!dbg.enabled)
|
|
||||||
return [undefined];
|
|
||||||
showDebuggeeValue(cv.return);
|
|
||||||
} else {
|
|
||||||
if (!dbg.enabled)
|
|
||||||
return [cv];
|
|
||||||
print("Exception caught. (To rethrow it, type 'throw'.)");
|
|
||||||
lastExc = cv.throw;
|
|
||||||
showDebuggeeValue(lastExc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function detachCommand() {
|
|
||||||
dbg.enabled = false;
|
|
||||||
return [undefined];
|
|
||||||
}
|
|
||||||
|
|
||||||
function continueCommand() {
|
|
||||||
if (focusedFrame === null) {
|
|
||||||
print("No stack.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return [undefined];
|
|
||||||
}
|
|
||||||
|
|
||||||
function throwCommand(rest) {
|
|
||||||
var v;
|
|
||||||
if (focusedFrame !== topFrame) {
|
|
||||||
print("To throw, you must select the newest frame (use 'frame 0').");
|
|
||||||
return;
|
|
||||||
} else if (focusedFrame === null) {
|
|
||||||
print("No stack.");
|
|
||||||
return;
|
|
||||||
} else if (rest === '') {
|
|
||||||
return [{throw: lastExc}];
|
|
||||||
} else {
|
|
||||||
var cv = saveExcursion(function () { return focusedFrame.eval(rest); });
|
|
||||||
if (cv === null) {
|
|
||||||
if (!dbg.enabled)
|
|
||||||
return [cv];
|
|
||||||
print("Debuggee died while determining what to throw. Stopped.");
|
|
||||||
} else if ('return' in cv) {
|
|
||||||
return [{throw: cv.return}];
|
|
||||||
} else {
|
|
||||||
if (!dbg.enabled)
|
|
||||||
return [cv];
|
|
||||||
print("Exception determining what to throw. Stopped.");
|
|
||||||
showDebuggeeValue(cv.throw);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function frameCommand(rest) {
|
|
||||||
var n, f;
|
|
||||||
if (rest.match(/[0-9]+/)) {
|
|
||||||
n = +rest;
|
|
||||||
f = topFrame;
|
|
||||||
if (f === null) {
|
|
||||||
print("No stack.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (var i = 0; i < n && f; i++) {
|
|
||||||
if (!f.older) {
|
|
||||||
print("There is no frame " + rest + ".");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
f.older.younger = f;
|
|
||||||
f = f.older;
|
|
||||||
}
|
|
||||||
focusedFrame = f;
|
|
||||||
showFrame(f, n);
|
|
||||||
} else if (rest !== '') {
|
|
||||||
if (topFrame === null)
|
|
||||||
print("No stack.");
|
|
||||||
else
|
|
||||||
showFrame();
|
|
||||||
} else {
|
|
||||||
print("do what now?");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function debugmeCommand() {
|
|
||||||
var meta = newGlobal("new-compartment");
|
|
||||||
meta.debuggeeGlobal = this;
|
|
||||||
meta.debuggerSource = debuggerSource;
|
|
||||||
meta.prompt = prompt.replace('(', '(meta-');
|
|
||||||
meta.eval(debuggerSource);
|
|
||||||
}
|
|
||||||
|
|
||||||
function upCommand() {
|
|
||||||
if (focusedFrame === null)
|
|
||||||
print("No stack.");
|
|
||||||
else if (focusedFrame.older === null)
|
|
||||||
print("Initial frame selected; you cannot go up.");
|
|
||||||
else {
|
|
||||||
focusedFrame.older.younger = focusedFrame;
|
|
||||||
focusedFrame = focusedFrame.older;
|
|
||||||
showFrame();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function downCommand() {
|
|
||||||
if (focusedFrame === null)
|
|
||||||
print("No stack.");
|
|
||||||
else if (!focusedFrame.younger)
|
|
||||||
print("Youngest frame selected; you cannot go down.");
|
|
||||||
else {
|
|
||||||
focusedFrame = focusedFrame.younger;
|
|
||||||
showFrame();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function forcereturnCommand(rest) {
|
|
||||||
var v;
|
|
||||||
var f = focusedFrame;
|
|
||||||
if (f !== topFrame) {
|
|
||||||
print("To forcereturn, you must select the newest frame (use 'frame 0').");
|
|
||||||
} else if (f === null) {
|
|
||||||
print("Nothing on the stack.");
|
|
||||||
} else if (rest === '') {
|
|
||||||
return [{return: undefined}];
|
|
||||||
} else {
|
|
||||||
var cv = saveExcursion(function () { return f.eval(rest); });
|
|
||||||
if (cv === null) {
|
|
||||||
if (!dbg.enabled)
|
|
||||||
return [cv];
|
|
||||||
print("Debuggee died while determining what to forcereturn. Stopped.");
|
|
||||||
} else if ('return' in cv) {
|
|
||||||
return [{return: cv.return}];
|
|
||||||
} else {
|
|
||||||
if (!dbg.enabled)
|
|
||||||
return [cv];
|
|
||||||
print("Error determining what to forcereturn. Stopped.");
|
|
||||||
showDebuggeeValue(cv.throw);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the table of commands.
|
|
||||||
var commands = {};
|
|
||||||
var commandArray = [
|
|
||||||
backtraceCommand, "bt", "where",
|
|
||||||
continueCommand, "c",
|
|
||||||
detachCommand,
|
|
||||||
debugmeCommand,
|
|
||||||
downCommand, "d",
|
|
||||||
forcereturnCommand,
|
|
||||||
frameCommand, "f",
|
|
||||||
printCommand, "p",
|
|
||||||
quitCommand, "q",
|
|
||||||
throwCommand, "t",
|
|
||||||
upCommand, "u"
|
|
||||||
];
|
|
||||||
var last = null;
|
|
||||||
for (var i = 0; i < commandArray.length; i++) {
|
|
||||||
var cmd = commandArray[i];
|
|
||||||
if (typeof cmd === "string")
|
|
||||||
commands[cmd] = last;
|
|
||||||
else
|
else
|
||||||
last = commands[cmd.name.replace(/Command$/, '')] = cmd;
|
return null;
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Break cmd into two parts: its first word and everything else.
|
function callDescription(f) {
|
||||||
function breakcmd(cmd) {
|
return ((f.callee.name || '<anonymous>') +
|
||||||
cmd = cmd.trimLeft();
|
"(" + f.arguments.map(dvToString).join(", ") + ")");
|
||||||
var m = /\s/.exec(cmd);
|
}
|
||||||
if (m === null)
|
|
||||||
return [cmd, ''];
|
function showFrame(f, n) {
|
||||||
return [cmd.slice(0, m.index), cmd.slice(m.index).trimLeft()];
|
if (f === undefined || f === null) {
|
||||||
|
f = focusedFrame;
|
||||||
|
if (f === null) {
|
||||||
|
print("No stack.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (n === undefined) {
|
||||||
|
n = f.num;
|
||||||
|
if (n === undefined)
|
||||||
|
throw new Error("Internal error: frame not on stack");
|
||||||
|
}
|
||||||
|
|
||||||
function runcmd(cmd) {
|
print('#' + n + " " + f.fullDescription());
|
||||||
var pieces = breakcmd(cmd);
|
}
|
||||||
if (pieces[0] === "")
|
|
||||||
return undefined;
|
|
||||||
|
|
||||||
var first = pieces[0], rest = pieces[1];
|
function saveExcursion(fn) {
|
||||||
if (!commands.hasOwnProperty(first)) {
|
var tf = topFrame, ff = focusedFrame;
|
||||||
print("unrecognized command '" + first + "'");
|
try {
|
||||||
return undefined;
|
return fn();
|
||||||
|
} finally {
|
||||||
|
topFrame = tf;
|
||||||
|
focusedFrame = ff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Evaluate an expression in the Debugger global
|
||||||
|
function evalCommand(expr) {
|
||||||
|
eval(expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
function quitCommand() {
|
||||||
|
dbg.enabled = false;
|
||||||
|
quit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function backtraceCommand() {
|
||||||
|
if (topFrame === null)
|
||||||
|
print("No stack.");
|
||||||
|
for (var i = 0, f = topFrame; f; i++, f = f.older)
|
||||||
|
showFrame(f, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
function printCommand(rest) {
|
||||||
|
// This is the real deal.
|
||||||
|
var cv = saveExcursion(
|
||||||
|
() => focusedFrame == null
|
||||||
|
? debuggeeGlobalWrapper.evalInGlobalWithBindings(rest, debuggeeValues)
|
||||||
|
: focusedFrame.evalWithBindings(rest, debuggeeValues));
|
||||||
|
if (cv === null) {
|
||||||
|
if (!dbg.enabled)
|
||||||
|
return [cv];
|
||||||
|
print("Debuggee died.");
|
||||||
|
} else if ('return' in cv) {
|
||||||
|
if (!dbg.enabled)
|
||||||
|
return [undefined];
|
||||||
|
showDebuggeeValue(cv.return);
|
||||||
|
} else {
|
||||||
|
if (!dbg.enabled)
|
||||||
|
return [cv];
|
||||||
|
print("Exception caught. (To rethrow it, type 'throw'.)");
|
||||||
|
lastExc = cv.throw;
|
||||||
|
showDebuggeeValue(lastExc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function detachCommand() {
|
||||||
|
dbg.enabled = false;
|
||||||
|
return [undefined];
|
||||||
|
}
|
||||||
|
|
||||||
|
function continueCommand() {
|
||||||
|
if (focusedFrame === null) {
|
||||||
|
print("No stack.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return [undefined];
|
||||||
|
}
|
||||||
|
|
||||||
|
function throwCommand(rest) {
|
||||||
|
var v;
|
||||||
|
if (focusedFrame !== topFrame) {
|
||||||
|
print("To throw, you must select the newest frame (use 'frame 0').");
|
||||||
|
return;
|
||||||
|
} else if (focusedFrame === null) {
|
||||||
|
print("No stack.");
|
||||||
|
return;
|
||||||
|
} else if (rest === '') {
|
||||||
|
return [{throw: lastExc}];
|
||||||
|
} else {
|
||||||
|
var cv = saveExcursion(function () { return focusedFrame.eval(rest); });
|
||||||
|
if (cv === null) {
|
||||||
|
if (!dbg.enabled)
|
||||||
|
return [cv];
|
||||||
|
print("Debuggee died while determining what to throw. Stopped.");
|
||||||
|
} else if ('return' in cv) {
|
||||||
|
return [{throw: cv.return}];
|
||||||
|
} else {
|
||||||
|
if (!dbg.enabled)
|
||||||
|
return [cv];
|
||||||
|
print("Exception determining what to throw. Stopped.");
|
||||||
|
showDebuggeeValue(cv.throw);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function frameCommand(rest) {
|
||||||
|
var n, f;
|
||||||
|
if (rest.match(/[0-9]+/)) {
|
||||||
|
n = +rest;
|
||||||
|
f = topFrame;
|
||||||
|
if (f === null) {
|
||||||
|
print("No stack.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (var i = 0; i < n && f; i++) {
|
||||||
|
if (!f.older) {
|
||||||
|
print("There is no frame " + rest + ".");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
f.older.younger = f;
|
||||||
|
f = f.older;
|
||||||
|
}
|
||||||
|
focusedFrame = f;
|
||||||
|
showFrame(f, n);
|
||||||
|
} else if (rest !== '') {
|
||||||
|
if (topFrame === null)
|
||||||
|
print("No stack.");
|
||||||
|
else
|
||||||
|
showFrame();
|
||||||
|
} else {
|
||||||
|
print("do what now?");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var cmd = commands[first];
|
function upCommand() {
|
||||||
if (cmd.length === 0 && rest !== '') {
|
if (focusedFrame === null)
|
||||||
print("this command cannot take an argument");
|
print("No stack.");
|
||||||
return undefined;
|
else if (focusedFrame.older === null)
|
||||||
}
|
print("Initial frame selected; you cannot go up.");
|
||||||
|
else {
|
||||||
|
focusedFrame.older.younger = focusedFrame;
|
||||||
|
focusedFrame = focusedFrame.older;
|
||||||
|
showFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return cmd(rest);
|
function downCommand() {
|
||||||
|
if (focusedFrame === null)
|
||||||
|
print("No stack.");
|
||||||
|
else if (!focusedFrame.younger)
|
||||||
|
print("Youngest frame selected; you cannot go down.");
|
||||||
|
else {
|
||||||
|
focusedFrame = focusedFrame.younger;
|
||||||
|
showFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function forcereturnCommand(rest) {
|
||||||
|
var v;
|
||||||
|
var f = focusedFrame;
|
||||||
|
if (f !== topFrame) {
|
||||||
|
print("To forcereturn, you must select the newest frame (use 'frame 0').");
|
||||||
|
} else if (f === null) {
|
||||||
|
print("Nothing on the stack.");
|
||||||
|
} else if (rest === '') {
|
||||||
|
return [{return: undefined}];
|
||||||
|
} else {
|
||||||
|
var cv = saveExcursion(function () { return f.eval(rest); });
|
||||||
|
if (cv === null) {
|
||||||
|
if (!dbg.enabled)
|
||||||
|
return [cv];
|
||||||
|
print("Debuggee died while determining what to forcereturn. Stopped.");
|
||||||
|
} else if ('return' in cv) {
|
||||||
|
return [{return: cv.return}];
|
||||||
|
} else {
|
||||||
|
if (!dbg.enabled)
|
||||||
|
return [cv];
|
||||||
|
print("Error determining what to forcereturn. Stopped.");
|
||||||
|
showDebuggeeValue(cv.throw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function printPop(f, c) {
|
||||||
|
var fdesc = f.fullDescription();
|
||||||
|
if (c.return) {
|
||||||
|
print("frame returning (still selected): " + fdesc);
|
||||||
|
showDebuggeeValue(c.return);
|
||||||
|
} else if (c.throw) {
|
||||||
|
print("frame threw exception: " + fdesc);
|
||||||
|
showDebuggeeValue(c.throw);
|
||||||
|
print("(To rethrow it, type 'throw'.)");
|
||||||
|
lastExc = c.throw;
|
||||||
|
} else {
|
||||||
|
print("frame was terminated: " + fdesc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set |prop| on |obj| to |value|, but then restore its current value
|
||||||
|
// when we next enter the repl.
|
||||||
|
function setUntilRepl(obj, prop, value) {
|
||||||
|
var saved = obj[prop];
|
||||||
|
obj[prop] = value;
|
||||||
|
replCleanups.push(function () { obj[prop] = saved; });
|
||||||
|
}
|
||||||
|
|
||||||
|
function doStepOrNext(kind) {
|
||||||
|
var startFrame = topFrame;
|
||||||
|
var startLine = startFrame.line;
|
||||||
|
print("stepping in: " + startFrame.fullDescription());
|
||||||
|
print("starting line: " + uneval(startLine));
|
||||||
|
|
||||||
|
function stepPopped(completion) {
|
||||||
|
// Note that we're popping this frame; we need to watch for
|
||||||
|
// subsequent step events on its caller.
|
||||||
|
this.reportedPop = true;
|
||||||
|
printPop(this, completion);
|
||||||
|
topFrame = focusedFrame = this;
|
||||||
|
return repl();
|
||||||
|
}
|
||||||
|
|
||||||
|
function stepEntered(newFrame) {
|
||||||
|
print("entered frame: " + newFrame.fullDescription());
|
||||||
|
topFrame = focusedFrame = newFrame;
|
||||||
|
return repl();
|
||||||
|
}
|
||||||
|
|
||||||
|
function stepStepped() {
|
||||||
|
print("stepStepped: " + this.fullDescription());
|
||||||
|
// If we've changed frame or line, then report that.
|
||||||
|
if (this !== startFrame || this.line != startLine) {
|
||||||
|
topFrame = focusedFrame = this;
|
||||||
|
if (focusedFrame != startFrame)
|
||||||
|
print(focusedFrame.fullDescription());
|
||||||
|
return repl();
|
||||||
}
|
}
|
||||||
|
|
||||||
function repl() {
|
// Otherwise, let execution continue.
|
||||||
var cmd;
|
return undefined;
|
||||||
for (;;) {
|
}
|
||||||
print("\n" + prompt);
|
|
||||||
cmd = readline();
|
|
||||||
if (cmd === null)
|
|
||||||
break;
|
|
||||||
|
|
||||||
try {
|
if (kind.step)
|
||||||
var result = runcmd(cmd);
|
setUntilRepl(dbg, 'onEnterFrame', stepEntered);
|
||||||
if (result === undefined)
|
|
||||||
; // do nothing
|
// If we're stepping after an onPop, watch for steps and pops in the
|
||||||
else if (Array.isArray(result))
|
// next-older frame; this one is done.
|
||||||
return result[0];
|
var stepFrame = startFrame.reportedPop ? startFrame.older : startFrame;
|
||||||
else
|
if (!stepFrame || !stepFrame.script)
|
||||||
throw new Error("Internal error: result of runcmd wasn't array or undefined");
|
stepFrame = null;
|
||||||
} catch (exc) {
|
if (stepFrame) {
|
||||||
print("*** Internal error: exception in the debugger code.");
|
setUntilRepl(stepFrame, 'onStep', stepStepped);
|
||||||
print(" " + exc);
|
setUntilRepl(stepFrame, 'onPop', stepPopped);
|
||||||
var me = prompt.replace(/^\((.*)\)$/, function (a, b) { return b; });
|
}
|
||||||
print("Debug " + me + "? (y/n)");
|
|
||||||
if (readline().match(/^\s*y/i) !== null)
|
// Let the program continue!
|
||||||
debugMe();
|
return [undefined];
|
||||||
else
|
}
|
||||||
print("ok, ignoring error");
|
|
||||||
}
|
function stepCommand() { return doStepOrNext({step:true}); }
|
||||||
}
|
function nextCommand() { return doStepOrNext({next:true}); }
|
||||||
|
|
||||||
|
// Build the table of commands.
|
||||||
|
var commands = {};
|
||||||
|
var commandArray = [
|
||||||
|
backtraceCommand, "bt", "where",
|
||||||
|
continueCommand, "c",
|
||||||
|
detachCommand,
|
||||||
|
downCommand, "d",
|
||||||
|
forcereturnCommand,
|
||||||
|
frameCommand, "f",
|
||||||
|
nextCommand, "n",
|
||||||
|
printCommand, "p",
|
||||||
|
quitCommand, "q",
|
||||||
|
stepCommand, "s",
|
||||||
|
throwCommand, "t",
|
||||||
|
upCommand, "u",
|
||||||
|
helpCommand, "h",
|
||||||
|
evalCommand, "!",
|
||||||
|
];
|
||||||
|
var last = null;
|
||||||
|
for (var i = 0; i < commandArray.length; i++) {
|
||||||
|
var cmd = commandArray[i];
|
||||||
|
if (typeof cmd === "string")
|
||||||
|
commands[cmd] = last;
|
||||||
|
else
|
||||||
|
last = commands[cmd.name.replace(/Command$/, '')] = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
function helpCommand(rest) {
|
||||||
|
print("Available commands:");
|
||||||
|
var printcmd = function(group) {
|
||||||
|
print(" " + group.join(", "));
|
||||||
|
}
|
||||||
|
|
||||||
|
var group = [];
|
||||||
|
for (var cmd of commandArray) {
|
||||||
|
if (typeof cmd === "string") {
|
||||||
|
group.push(cmd);
|
||||||
|
} else {
|
||||||
|
if (group.length) printcmd(group);
|
||||||
|
group = [ cmd.name.replace(/Command$/, '') ];
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
printcmd(group);
|
||||||
|
}
|
||||||
|
|
||||||
var dbg = new Debugger(debuggeeGlobal);
|
// Break cmd into two parts: its first word and everything else. If it begins
|
||||||
dbg.onDebuggerStatement = function (frame) {
|
// with punctuation, treat that as a separate word.
|
||||||
return saveExcursion(function () {
|
function breakcmd(cmd) {
|
||||||
topFrame = focusedFrame = frame;
|
cmd = cmd.trimLeft();
|
||||||
print("'debugger' statement hit.");
|
if ("!@#$%^&*_+=/?.,<>:;'\"".indexOf(cmd.substr(0, 1)) != -1)
|
||||||
showFrame();
|
return [cmd.substr(0, 1), cmd.substr(1).trimLeft()];
|
||||||
return repl();
|
var m = /\s/.exec(cmd);
|
||||||
});
|
if (m === null)
|
||||||
};
|
return [cmd, ''];
|
||||||
dbg.onThrow = function (frame, exc) {
|
return [cmd.slice(0, m.index), cmd.slice(m.index).trimLeft()];
|
||||||
return saveExcursion(function () {
|
}
|
||||||
topFrame = focusedFrame = frame;
|
|
||||||
print("Unwinding due to exception. (Type 'c' to continue unwinding.)");
|
|
||||||
showFrame();
|
|
||||||
print("Exception value is:");
|
|
||||||
showDebuggeeValue(exc);
|
|
||||||
return repl();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
repl();
|
|
||||||
} + ")();"
|
|
||||||
|
|
||||||
print("jorendb version -0.0");
|
function runcmd(cmd) {
|
||||||
var g = newGlobal("new-compartment");
|
var pieces = breakcmd(cmd);
|
||||||
g.debuggeeGlobal = this;
|
if (pieces[0] === "")
|
||||||
g.prompt = '(jorendb)';
|
return undefined;
|
||||||
g.debuggerSource = debuggerSource;
|
|
||||||
g.eval(debuggerSource);
|
var first = pieces[0], rest = pieces[1];
|
||||||
})();
|
if (!commands.hasOwnProperty(first)) {
|
||||||
|
print("unrecognized command '" + first + "'");
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cmd = commands[first];
|
||||||
|
if (cmd.length === 0 && rest !== '') {
|
||||||
|
print("this command cannot take an argument");
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd(rest);
|
||||||
|
}
|
||||||
|
|
||||||
|
function repl() {
|
||||||
|
while (replCleanups.length > 0)
|
||||||
|
replCleanups.pop()();
|
||||||
|
|
||||||
|
var cmd;
|
||||||
|
for (;;) {
|
||||||
|
putstr("\n" + prompt);
|
||||||
|
cmd = readline();
|
||||||
|
if (cmd === null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
var result = runcmd(cmd);
|
||||||
|
if (result === undefined)
|
||||||
|
; // do nothing
|
||||||
|
else if (Array.isArray(result))
|
||||||
|
return result[0];
|
||||||
|
else
|
||||||
|
throw new Error("Internal error: result of runcmd wasn't array or undefined");
|
||||||
|
} catch (exc) {
|
||||||
|
print("*** Internal error: exception in the debugger code.");
|
||||||
|
print(" " + exc);
|
||||||
|
print(exc.stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var dbg = new Debugger();
|
||||||
|
dbg.onDebuggerStatement = function (frame) {
|
||||||
|
return saveExcursion(function () {
|
||||||
|
topFrame = focusedFrame = frame;
|
||||||
|
print("'debugger' statement hit.");
|
||||||
|
showFrame();
|
||||||
|
return repl();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
dbg.onThrow = function (frame, exc) {
|
||||||
|
return saveExcursion(function () {
|
||||||
|
topFrame = focusedFrame = frame;
|
||||||
|
print("Unwinding due to exception. (Type 'c' to continue unwinding.)");
|
||||||
|
showFrame();
|
||||||
|
print("Exception value is:");
|
||||||
|
showDebuggeeValue(exc);
|
||||||
|
return repl();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// The depth of jorendb nesting.
|
||||||
|
var jorendbDepth;
|
||||||
|
if (typeof jorendbDepth == 'undefined') jorendbDepth = 0;
|
||||||
|
|
||||||
|
var debuggeeGlobal = newGlobal("new-compartment");
|
||||||
|
debuggeeGlobal.jorendbDepth = jorendbDepth + 1;
|
||||||
|
var debuggeeGlobalWrapper = dbg.addDebuggee(debuggeeGlobal);
|
||||||
|
|
||||||
|
print("jorendb version -0.0");
|
||||||
|
prompt = '(' + Array(jorendbDepth+1).join('meta-') + 'jorendb) ';
|
||||||
|
|
||||||
|
var args = arguments;
|
||||||
|
while(args.length > 0) {
|
||||||
|
var arg = args.shift();
|
||||||
|
if (arg == '-f') {
|
||||||
|
arg = args.shift();
|
||||||
|
debuggeeGlobal.evaluate(read(arg), { fileName: arg, lineNumber: 1 });
|
||||||
|
} else if (arg == '-e') {
|
||||||
|
arg = args.shift();
|
||||||
|
debuggeeGlobal.eval(arg);
|
||||||
|
} else {
|
||||||
|
throw("jorendb does not implement command-line argument '" + arg + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repl();
|
||||||
|
|||||||
Reference in New Issue
Block a user