X-Git-Url: https://git.distorted.org.uk/~mdw/dep-ui/blobdiff_plain/5a0d36b9f9bcc3791114155e2a3b2657528cea19..261767039202e3afc8155f87c018241b65ce798b:/dep.js diff --git a/dep.js b/dep.js index f4b0ff9..989e871 100644 --- a/dep.js +++ b/dep.js @@ -18,13 +18,26 @@ * GNU Library General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, see . + * along with this program; if not, see . */ var DEP = { }; (function () { /*----- Utility functions and classes -------------------------------------*/ +DEP.DEBUG = false; +function blather(msg) { + /* Report MSG to the log if we're debugging. */ + if (DEP.DEBUG) console.log(";; " + msg); +} +function show(what, value) { + /* Report that WHAT has the value VALUE, if we're debugging; and, + * regardless, return VALUE. + */ + blather(what + " = " + value); + return value; +} + function dolist(list, func) { /* Apply FUNC to each element of LIST, discarding the results. * @@ -118,7 +131,7 @@ var F_CHANGED = 4; // Changed in current phase. var F_RECOMPUTING = 8; // Currently being recomputed. var F_QUEUED = 16; // Queued for recomputation. -var BAD = Tag('BAD') // Used for the value of `bad' deps. +var BAD = new Tag('BAD'); // Used for the value of `bad' deps. var DELAYED = []; // Actions delayed by `with_frozen'. var PENDING = []; // Deps awaiting recomputation. @@ -178,7 +191,7 @@ function Dep(value, maybefunc) { func = value; f |= F_QUEUED; } else { - val = value; + val = value === undefined ? BAD : value; func = null; f |= F_VALUE | F_DEPS; } @@ -203,9 +216,11 @@ function Dep(value, maybefunc) { this._dependencies = { }; // Set of objects we depend on. // If we have a recomputation function then exercise it. + blather("new dep " + me); if (func !== null) { with_frozen(function () { PENDING.push(me); + blather("push new dep " + me); }); } } @@ -235,7 +250,7 @@ Dep.prototype = { s += ' #' + this._seq; // The value, or some kind of marker that it doesn't have one. - if (!(f & F_VALUE)) s += ' #{out-of-date}'; + if (!(f & F_VALUE)) s += ' #{stale}'; else if (v === BAD) s += ' #{bad}'; else s += ' ' + v.toString(); @@ -255,7 +270,7 @@ Dep.prototype = { * If the receiver isn't up-to-date then we synthesize the flags. */ - if (this.state === 'ready') return F_VALUE | F_DEPS; + if (STATE === 'ready') return F_VALUE | F_DEPS; else if (this._generation === GENERATION) return this.__flags; else if (this._value_function === null) return F_VALUE | F_DEPS; else return 0; @@ -268,6 +283,7 @@ Dep.prototype = { * function which doesn't handle propagation or anything like that. */ + blather("_update " + this + ": " + value); if (value === BAD ? this._value === BAD : (this._value !== BAD && @@ -293,8 +309,9 @@ Dep.prototype = { this._dependencies = { }; return try_finally(function () { EVALUATING = me; - return orelse(function () { return me._value_function(); }, - function () { return BAD; }); + return show("_new_value for " + me, + orelse(function () { return me._value_function(); }, + function () { return show("ret", BAD); })); }, function() { EVALUATING = old; }); @@ -394,14 +411,15 @@ Dep.prototype = { var val; - if (state === 'recomputing') { + if (STATE === 'recomputing') { + this._force(); if (EVALUATING) { this._dependents[EVALUATING._seq] = EVALUATING; EVALUATING._dependencies[this._seq] = this; } - this._force(); } val = this._value; + blather("value " + this + ": " + val); if (val === BAD) throw BAD; return val; }, @@ -444,7 +462,7 @@ Dep.prototype = { function orelse(thunk, errthunk) { /* Call THUNK. If it succeeds, then return its result. If THUNK - * reads a bad dep then call ERRTHINK and return its result instead. + * reads a bad dep then call ERRTHUNK and return its result instead. */ var e; @@ -469,8 +487,9 @@ function recompute_pending() { */ var d, f; - - state = 'recomputing'; + var old_state = STATE; + STATE = 'recomputing'; + blather("STATE <- :recomputing"); try_finally(function () { while (PENDING.length) { d = PENDING.shift(); @@ -487,7 +506,10 @@ function recompute_pending() { while (PENDING.length) { d = PENDING.shift(); d._value = BAD; + blather("recompute_pending mark " + d); } + STATE = old_state; + blather("STATE <- :" + old_state); }); } @@ -497,14 +519,13 @@ function with_frozen(body, delay) { * If the BODY function changes any dep values (using D.set_value(...)) * then dependents won't be updated until the BODY completes. * - * It's very - * bad to do this during a recomputation phase. If DELAY is true, then the - * BODY is delayed until the recomputation completes; otherwise you get an - * exception. + * It's very bad to do this during a recomputation phase. If DELAY is + * true, then the BODY is delayed until the recomputation completes; + * otherwise you get an exception. */ var op, val; - var old_delayed, old_pending; + var old_delayed, old_pending, old_state; switch (STATE) { case 'frozen': @@ -517,6 +538,9 @@ function with_frozen(body, delay) { case 'ready': old_delayed = DELAYED; old_pending = PENDING; + old_state = STATE; + STATE = "frozen"; + blather("STATE <- :frozen"); try_finally(function () { DELAYED = []; PENDING = []; @@ -531,6 +555,8 @@ function with_frozen(body, delay) { }, function () { DELAYED = old_delayed; PENDING = old_pending; + STATE = old_state; + blather("STATE <- :" + old_state); }); break; }