Bug 876776 - Import latest version of js/examples/jorendb.js. DONTBUILD

This commit is contained in:
Steve Fink
2013-06-04 12:14:17 -07:00
parent 11439d7086
commit 955b3ad89f

View File

@@ -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();