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
* 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
* intended as a demo of the Debugger object (as there are no shell js programs to
* speak of).
* intended as a demo of the Debugger object (as there are no shell js programs
* to speak of).
*
* To run it: $JS -d path/to/this/file/jorendb.js
* To run some JS code under it, try:
@@ -18,14 +19,16 @@
* Execution will stop at debugger statements and you'll get a jorendb prompt.
*/
(function () {
var debuggerSource = "(" + function () {
// Debugger state.
var focusedFrame = null;
var topFrame = null;
var debuggeeValues = [null];
var debuggeeValues = {};
var nextDebuggeeValueIndex = 1;
var lastExc = null;
// Cleanup functions to run when we next re-enter the repl.
var replCleanups = [];
// Convert a debuggee value v to a string.
function dvToString(v) {
return (typeof v !== 'object' || v === null) ? uneval(v) : "[object " + v.class + "]";
@@ -33,8 +36,8 @@
function showDebuggeeValue(dv) {
var dvrepr = dvToString(dv);
var i = debuggeeValues.length;
debuggeeValues[i] = dv;
var i = nextDebuggeeValueIndex++;
debuggeeValues["$" + i] = dv;
print("$" + i + " = " + dvrepr);
}
@@ -49,12 +52,43 @@
}
});
function framePosition(f) {
if (!f.script)
return f.type + " code";
return (f.script.url || f.type + " code") + ":" + f.script.getOffsetLine(f.offset);
Debugger.Frame.prototype.frameDescription = function frameDescription() {
if (this.type == "call")
return ((this.callee.name || '<anonymous>') +
"(" + this.arguments.map(dvToString).join(", ") + ")");
else
return this.type + " code";
}
Debugger.Frame.prototype.positionDescription = function positionDescription() {
if (this.script) {
var line = this.script.getOffsetLine(this.offset);
if (this.script.url)
return this.script.url + ":" + line;
return "line " + line;
}
return null;
}
Debugger.Frame.prototype.fullDescription = function fullDescription() {
var fr = this.frameDescription();
var pos = this.positionDescription();
if (pos)
return fr + ", " + pos;
return fr;
}
Object.defineProperty(Debugger.Frame.prototype, "line", {
configurable: true,
enumerable: false,
get: function() {
if (this.script)
return this.script.getOffsetLine(this.offset);
else
return null;
}
});
function callDescription(f) {
return ((f.callee.name || '<anonymous>') +
"(" + f.arguments.map(dvToString).join(", ") + ")");
@@ -74,11 +108,7 @@
throw new Error("Internal error: frame not on stack");
}
var me = '#' + n;
if (f.type === "call")
me += ' ' + callDescription(f);
me += ' ' + framePosition(f);
print(me);
print('#' + n + " " + f.fullDescription());
}
function saveExcursion(fn) {
@@ -91,6 +121,11 @@
}
}
// Evaluate an expression in the Debugger global
function evalCommand(expr) {
eval(expr);
}
function quitCommand() {
dbg.enabled = false;
quit(0);
@@ -104,28 +139,11 @@
}
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);
});
var cv = saveExcursion(
() => focusedFrame == null
? debuggeeGlobalWrapper.evalInGlobalWithBindings(rest, debuggeeValues)
: focusedFrame.evalWithBindings(rest, debuggeeValues));
if (cv === null) {
if (!dbg.enabled)
return [cv];
@@ -142,7 +160,6 @@
showDebuggeeValue(lastExc);
}
}
}
function detachCommand() {
dbg.enabled = false;
@@ -214,14 +231,6 @@
}
}
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.");
@@ -271,20 +280,101 @@
}
}
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();
}
// Otherwise, let execution continue.
return undefined;
}
if (kind.step)
setUntilRepl(dbg, 'onEnterFrame', stepEntered);
// If we're stepping after an onPop, watch for steps and pops in the
// next-older frame; this one is done.
var stepFrame = startFrame.reportedPop ? startFrame.older : startFrame;
if (!stepFrame || !stepFrame.script)
stepFrame = null;
if (stepFrame) {
setUntilRepl(stepFrame, 'onStep', stepStepped);
setUntilRepl(stepFrame, 'onPop', stepPopped);
}
// Let the program continue!
return [undefined];
}
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,
debugmeCommand,
downCommand, "d",
forcereturnCommand,
frameCommand, "f",
nextCommand, "n",
printCommand, "p",
quitCommand, "q",
stepCommand, "s",
throwCommand, "t",
upCommand, "u"
upCommand, "u",
helpCommand, "h",
evalCommand, "!",
];
var last = null;
for (var i = 0; i < commandArray.length; i++) {
@@ -295,9 +385,30 @@
last = commands[cmd.name.replace(/Command$/, '')] = cmd;
}
// Break cmd into two parts: its first word and everything else.
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);
}
// Break cmd into two parts: its first word and everything else. If it begins
// with punctuation, treat that as a separate word.
function breakcmd(cmd) {
cmd = cmd.trimLeft();
if ("!@#$%^&*_+=/?.,<>:;'\"".indexOf(cmd.substr(0, 1)) != -1)
return [cmd.substr(0, 1), cmd.substr(1).trimLeft()];
var m = /\s/.exec(cmd);
if (m === null)
return [cmd, ''];
@@ -325,12 +436,15 @@
}
function repl() {
while (replCleanups.length > 0)
replCleanups.pop()();
var cmd;
for (;;) {
print("\n" + prompt);
putstr("\n" + prompt);
cmd = readline();
if (cmd === null)
break;
return null;
try {
var result = runcmd(cmd);
@@ -343,17 +457,12 @@
} catch (exc) {
print("*** Internal error: exception in the debugger code.");
print(" " + exc);
var me = prompt.replace(/^\((.*)\)$/, function (a, b) { return b; });
print("Debug " + me + "? (y/n)");
if (readline().match(/^\s*y/i) !== null)
debugMe();
else
print("ok, ignoring error");
print(exc.stack);
}
}
}
var dbg = new Debugger(debuggeeGlobal);
var dbg = new Debugger();
dbg.onDebuggerStatement = function (frame) {
return saveExcursion(function () {
topFrame = focusedFrame = frame;
@@ -372,13 +481,30 @@
return repl();
});
};
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");
var g = newGlobal("new-compartment");
g.debuggeeGlobal = this;
g.prompt = '(jorendb)';
g.debuggerSource = debuggerSource;
g.eval(debuggerSource);
})();
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();