diff --git a/js-assembler/runtime-src/baselib-boxes.js b/js-assembler/runtime-src/baselib-boxes.js index e73e09f..95625b0 100644 --- a/js-assembler/runtime-src/baselib-boxes.js +++ b/js-assembler/runtime-src/baselib-boxes.js @@ -43,7 +43,6 @@ }; Box.prototype.toDomNode = function(params) { - params.put(this, true); var parent = document.createElement("span"); parent.appendChild(document.createTextNode('#&')); parent.appendChild(params.recur(this.val)); diff --git a/js-assembler/runtime-src/baselib-format.js b/js-assembler/runtime-src/baselib-format.js index 950471e..39b09ee 100644 --- a/js-assembler/runtime-src/baselib-format.js +++ b/js-assembler/runtime-src/baselib-format.js @@ -202,13 +202,18 @@ var ToDomNodeParameters = function(params) { if (! params) { params = {}; } - this.cache = baselib.hashes.makeLowLevelEqHash(); var k; for (k in params) { if (params.hasOwnProperty(k)) { this[k] = params[k]; } } + if (this.cache === undefined) { + this.cache = baselib.hashes.makeLowLevelEqHash(); + } + if (this.cycles === undefined) { + this.cycles = baselib.hashes.makeLowLevelEqHash(); + } if (this.depth === undefined) { this.depth = 0; } @@ -221,6 +226,8 @@ ToDomNodeParameters.prototype.incrementDepth = function() { return new ToDomNodeParameters({ mode : this.mode, depth: this.depth + 1, + cache: this.cache, + cycles: this.cycles, objectCounter: this.objectCounter }); }; @@ -241,6 +248,10 @@ return this.cache.containsKey(x); }; + ToDomNodeParameters.prototype.seesOldCycle = function(x) { + return this.cycles.containsKey(x); + }; + ToDomNodeParameters.prototype.get = function(x) { return this.cache.get(x); }; @@ -249,9 +260,8 @@ return this.cache.remove(x); }; - ToDomNodeParameters.prototype.put = function(x) { - this.objectCounter++; - return this.cache.put(x, this.objectCounter); + ToDomNodeParameters.prototype.put = function(x, v) { + return this.cache.put(x, v); }; ToDomNodeParameters.prototype.recur = function(x) { @@ -354,9 +364,23 @@ // toDomNode: scheme-value -> dom-node var toDomNode = function(x, params) { - var node; + var node, retval; params = coerseToParams(params); + if (x === null) { + node = document.createElement("span"); + node.appendChild(document.createTextNode("#")); + $(node).addClass("null"); + return node; + } + + if (x === undefined) { + node = document.createElement("span"); + node.appendChild(document.createTextNode("#")); + $(node).addClass("undefined"); + return node; + } + if (baselib.numbers.isSchemeNumber(x)) { node = numberToDomNode(x, params); $(node).addClass("number"); @@ -383,20 +407,6 @@ return node; } - if (x === null) { - node = document.createElement("span"); - node.appendChild(document.createTextNode("#")); - $(node).addClass("null"); - return node; - } - - if (x === undefined) { - node = document.createElement("span"); - node.appendChild(document.createTextNode("#")); - $(node).addClass("undefined"); - return node; - } - if (baselib.functions.isProcedure(x)) { node = document.createElement("span"); node.appendChild(document.createTextNode('#')); @@ -410,31 +420,52 @@ return node; } + if (x.nodeType) { + return x; + } + + + // Otherwise, we know the value is an object. - if (params.containsKey(x)) { + + // If we're along a print path with a loop, we need to stop + // and return the key. + if (params.seesOldCycle(x)) { node = document.createElement("span"); - node.appendChild(document.createTextNode("#" + params.get(x))); + node.appendChild(document.createTextNode("#" + params.cycles.get(x) + "#")); + $(node).addClass("cycle"); return node; } - var returnVal; - if (x.nodeType) { - returnVal = x; - } else if (x.toDomNode) { - returnVal = x.toDomNode(params); - } else if (params.getMode() === 'write' && x.toWrittenString) { + + // If we see a fresh cycle, register it. + if (params.containsKey(x)) { + $('').text('#' + params.objectCounter +'=') + .prependTo(params.get(x)); + + params.cycles.put(x, params.objectCounter); + params.objectCounter++; + node = document.createElement("span"); - node.appendChild(document.createTextNode(x.toWrittenString(params))); - returnVal = node; - } else if (params.getMode() === 'display' && x.toDisplayedString) { - node = document.createElement("span"); - node.appendChild(document.createTextNode(x.toDisplayedString(params))); - returnVal = node; - } else { - node = document.createElement("span"); - node.appendChild(document.createTextNode(x.toString())); - returnVal = node; + node.appendChild(document.createTextNode("#" + params.cycles.get(x) + "#")); + $(node).addClass("cycle"); + return node; } - return returnVal; + + node = document.createElement("span"); + params.put(x, node); + if (x.toDomNode) { + node.appendChild(x.toDomNode(params)); + } else if (params.getMode() === 'write' && x.toWrittenString) { + node.appendChild(document.createTextNode( + x.toWrittenString(params))); + } else if (params.getMode() === 'display' && x.toDisplayedString) { + node.appendChild(document.createTextNode( + x.toDisplayedString(params))); + } else { + node.appendChild(document.createTextNode(x.toString())); + } + params.remove(x); + return node; }; diff --git a/js-assembler/runtime-src/baselib-lists.js b/js-assembler/runtime-src/baselib-lists.js index 1dee31f..51d1b29 100644 --- a/js-assembler/runtime-src/baselib-lists.js +++ b/js-assembler/runtime-src/baselib-lists.js @@ -1,3 +1,4 @@ +/*global $*/ /*jslint browser: true, unparam: true, vars: true, plusplus: true, maxerr: 50, indent: 4 */ @@ -7,10 +8,7 @@ var exports = {}; baselib.lists = exports; - - - var Empty = function () { }; Empty.EMPTY = new Empty(); @@ -48,12 +46,10 @@ } }; - // Empty.append: (listof X) -> (listof X) Empty.prototype.append = function (b) { return b; }; - @@ -79,7 +75,6 @@ } return ret; }; - // FIXME: can we reduce the recursion on this? Cons.prototype.equals = function (other, aUnionFind) { @@ -89,9 +84,7 @@ return (baselib.equality.equals(this.first, other.first, aUnionFind) && baselib.equality.equals(this.rest, other.rest, aUnionFind)); }; - - // Cons.append: (listof X) -> (listof X) Cons.prototype.append = function (b) { @@ -104,10 +97,9 @@ ret = makePair(lst.first, ret); lst = lst.rest; } - return ret; }; - + Cons.prototype.toWrittenString = function (cache) { cache.put(this, true); @@ -150,26 +142,68 @@ Cons.prototype.toDomNode = function (params) { - params.put(this, true); - var node = document.createElement("span"); - node.appendChild(document.createTextNode("(")); + var node; + + var subelts = [], dottedPair = false, i; var p = this; while (p instanceof Cons) { - node.appendChild(params.recur(p.first)); + subelts.push(params.recur(p.first)); p = p.rest; - if (p !== EMPTY) { - node.appendChild(document.createTextNode(" ")); - } if (typeof (p) === 'object' && params.containsKey(p)) { break; } } if (p !== EMPTY) { - node.appendChild(document.createTextNode(".")); - node.appendChild(document.createTextNode(" ")); - node.appendChild(params.recur(p)); + dottedPair = true; + subelts.push(params.recur(p)); } + + if (params.getMode() === 'constructor') { + if (dottedPair) { + node = subelts[subelts.length - 1]; + for (i = subelts.length - 2; i >= 0; i--) { + node = $('') + .text("(cons ") + .append(subelts[i]) + .append(" ") + .append(node) + .append(")").get(0); + } + return node; + } else { + node = document.createElement("span"); + node.appendChild(document.createTextNode("(")); + node.appendChild(document.createTextElement("list")); + node.appendChild(document.createTextElement(" ")); + node.appendChild(subelts[0]); + for (i = 1; i < subelts.length; i++) { + node.appendChild(document.createTextElement(" ")); + node.appendChild(subelts[i]); + } + node.appendChild(document.createTextNode(")")); + return node; + } + } + + node = document.createElement('span'); + if (params.getMode() === 'print') { + node.appendChild(document.createTextNode("'")); + } + node.appendChild(document.createTextNode("(")); + node.appendChild(subelts[0]); + if (subelts.length > 1) { + for (i = 1; i < subelts.length - 1; i++) { + node.appendChild(document.createTextNode(" ")); + node.appendChild(subelts[i]); + } + if (dottedPair) { + node.appendChild(document.createTextNode(" ")); + node.appendChild(document.createTextNode(".")); + } + node.appendChild(document.createTextNode(" ")); + node.appendChild(subelts[subelts.length - 1]); + } node.appendChild(document.createTextNode(")")); return node; }; @@ -202,7 +236,7 @@ // isList: Any -> Boolean // Returns true if x is a list (a chain of pairs terminated by EMPTY). - var isList = function (x) { + var isList = function (x) { var tortoise, hare; tortoise = hare = x; if (hare === EMPTY) { return true; } diff --git a/js-assembler/runtime-src/baselib-structs.js b/js-assembler/runtime-src/baselib-structs.js index ec138a2..17ff175 100644 --- a/js-assembler/runtime-src/baselib-structs.js +++ b/js-assembler/runtime-src/baselib-structs.js @@ -33,7 +33,6 @@ Struct.prototype.toDomNode = function (params) { var node = document.createElement("span"), i; - params.put(this, true); $(node).append(document.createTextNode("(")); $(node).append(document.createTextNode(this._constructorName)); for(i = 0; i < this._fields.length; i++) { diff --git a/js-assembler/runtime-src/baselib-vectors.js b/js-assembler/runtime-src/baselib-vectors.js index dd09c18..54b8119 100644 --- a/js-assembler/runtime-src/baselib-vectors.js +++ b/js-assembler/runtime-src/baselib-vectors.js @@ -84,7 +84,6 @@ Vector.prototype.toDomNode = function (params) { var node = document.createElement("span"), i; - params.put(this, true); node.appendChild(document.createTextNode("#(")); for (i = 0; i < this.length(); i++) { node.appendChild(params.recur(this.ref(i))); diff --git a/tests/more-tests/sharing.expected b/tests/more-tests/sharing.expected index bd6f4c7..00b60fb 100644 --- a/tests/more-tests/sharing.expected +++ b/tests/more-tests/sharing.expected @@ -24,3 +24,5 @@ jane true false +#0=(1 . #0#) +#0=(1 2 . #0#) diff --git a/tests/more-tests/sharing.rkt b/tests/more-tests/sharing.rkt index 3a95aa6..7c1916c 100644 --- a/tests/more-tests/sharing.rkt +++ b/tests/more-tests/sharing.rkt @@ -78,4 +78,16 @@ (shared ([a (cons 1 a)]) (begin (displayln (pair? a)) - (displayln (list? a)))) \ No newline at end of file + (displayln (list? a)))) + + + + +(shared ([a (cons 1 a)]) + a) + + + +(shared ([a (cons 1 b)] + [b (cons 2 a)]) + a)