From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- js/examples/jorendb.js | 891 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 891 insertions(+) create mode 100644 js/examples/jorendb.js (limited to 'js/examples') diff --git a/js/examples/jorendb.js b/js/examples/jorendb.js new file mode 100644 index 000000000..06965ccef --- /dev/null +++ b/js/examples/jorendb.js @@ -0,0 +1,891 @@ +/* -*- indent-tabs-mode: nil; js-indent-level: 4 -*- + * vim: set ts=8 sw=4 et tw=78: + * + * jorendb - A toy command-line debugger for shell-js programs. + * + * 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/. + */ + +/* + * 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). + * + * To run it: $JS -d path/to/this/file/jorendb.js + * To run some JS code under it, try: + * (jorendb) print load("my-script-to-debug.js") + * Execution will stop at debugger statements and you'll get a jorendb prompt. + */ + +// Debugger state. +var focusedFrame = null; +var topFrame = null; +var debuggeeValues = {}; +var nextDebuggeeValueIndex = 1; +var lastExc = null; +var todo = []; +var activeTask; +var options = { 'pretty': true, + 'emacs': (os.getenv('EMACS') == 't') }; +var rerun = true; + +// Cleanup functions to run when we next re-enter the repl. +var replCleanups = []; + +// Redirect debugger printing functions to go to the original output +// destination, unaffected by any redirects done by the debugged script. +var initialOut = os.file.redirect(); +var initialErr = os.file.redirectErr(); + +function wrap(global, name) { + var orig = global[name]; + global[name] = function(...args) { + + var oldOut = os.file.redirect(initialOut); + var oldErr = os.file.redirectErr(initialErr); + try { + return orig.apply(global, args); + } finally { + os.file.redirect(oldOut); + os.file.redirectErr(oldErr); + } + }; +} +wrap(this, 'print'); +wrap(this, 'printErr'); +wrap(this, 'putstr'); + +// Convert a debuggee value v to a string. +function dvToString(v) { + return (typeof v !== 'object' || v === null) ? uneval(v) : "[object " + v.class + "]"; +} + +function summaryObject(dv) { + var obj = {}; + for (var name of dv.getOwnPropertyNames()) { + var v = dv.getOwnPropertyDescriptor(name).value; + if (v instanceof Debugger.Object) { + v = "(...)"; + } + obj[name] = v; + } + return obj; +} + +function debuggeeValueToString(dv, style) { + var dvrepr = dvToString(dv); + if (!style.pretty || (typeof dv !== 'object')) + return [dvrepr, undefined]; + + if (dv.class == "Error") { + let errval = debuggeeGlobalWrapper.executeInGlobalWithBindings("$" + i + ".toString()", debuggeeValues); + return [dvrepr, errval.return]; + } + + if (style.brief) + return [dvrepr, JSON.stringify(summaryObject(dv), null, 4)]; + + let str = debuggeeGlobalWrapper.executeInGlobalWithBindings("JSON.stringify(v, null, 4)", {v: dv}); + if ('throw' in str) { + if (style.noerror) + return [dvrepr, undefined]; + + let substyle = {}; + Object.assign(substyle, style); + substyle.noerror = true; + return [dvrepr, debuggeeValueToString(str.throw, substyle)]; + } + + return [dvrepr, str.return]; +} + +// Problem! Used to do [object Object] followed by details. Now just details? + +function showDebuggeeValue(dv, style={pretty: options.pretty}) { + var i = nextDebuggeeValueIndex++; + debuggeeValues["$" + i] = dv; + let [brief, full] = debuggeeValueToString(dv, style); + print("$" + i + " = " + brief); + if (full !== undefined) + print(full); +} + +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; + } + }); + +Debugger.Frame.prototype.frameDescription = function frameDescription() { + if (this.type == "call") + return ((this.callee.name || '') + + "(" + this.arguments.map(dvToString).join(", ") + ")"); + else + return this.type + " code"; +} + +Debugger.Frame.prototype.positionDescription = function positionDescription() { + if (this.script) { + var line = this.script.getOffsetLocation(this.offset).lineNumber; + if (this.script.url) + return this.script.url + ":" + line; + return "line " + line; + } + return null; +} + +Debugger.Frame.prototype.location = function () { + if (this.script) { + var { lineNumber, columnNumber, isEntryPoint } = this.script.getOffsetLocation(this.offset); + if (this.script.url) + return this.script.url + ":" + lineNumber; + return null; + } + 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.getOffsetLocation(this.offset).lineNumber; + else + return null; + } + }); + +function callDescription(f) { + return ((f.callee.name || '') + + "(" + f.arguments.map(dvToString).join(", ") + ")"); +} + +function showFrame(f, n) { + 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"); + } + + print('#' + n + " " + f.fullDescription()); +} + +function saveExcursion(fn) { + var tf = topFrame, ff = focusedFrame; + try { + return fn(); + } finally { + topFrame = tf; + focusedFrame = ff; + } +} + +function parseArgs(str) { + return str.split(" "); +} + +function describedRv(r, desc) { + desc = "[" + desc + "] "; + if (r === undefined) { + print(desc + "Returning undefined"); + } else if (r === null) { + print(desc + "Returning null"); + } else if (r.length === undefined) { + print(desc + "Returning object " + JSON.stringify(r)); + } else { + print(desc + "Returning length-" + r.length + " list"); + if (r.length > 0) { + print(" " + r[0]); + } + } + return r; +} + +// Rerun the program (reloading it from the file) +function runCommand(args) { + print("Restarting program"); + if (args) + activeTask.scriptArgs = parseArgs(args); + rerun = true; + for (var f = topFrame; f; f = f.older) { + if (f.older) { + f.onPop = () => null; + } else { + f.onPop = () => ({ 'return': 0 }); + } + } + //return describedRv([{ 'return': 0 }], "runCommand"); + return null; +} + +// 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 setCommand(rest) { + var space = rest.indexOf(' '); + if (space == -1) { + print("Invalid set