if (! this['plt']) { this['plt'] = {}; } // FIXME: there's a circularity between this module and helpers, and that circularly // should not be there! (function (scope) { ////////////////////////////////////////////////////////////////////// var types = {}; scope['types'] = types; // helpers refers to plt.helpers. var helpers = scope['helpers']; var getEqHashCode = helpers.getEqHashCode, // makeLowLevelEqHash: -> hashtable // Constructs an eq hashtable that uses Moby's getEqHashCode function. makeLowLevelEqHash = helpers.makeLowLevelEqHash; var toWrittenString = helpers.toWrittenString; var toDisplayedString = helpers.toDisplayedString; var toDomNode = helpers.toDomNode; scope.link.ready('helpers', function() { helpers = scope['helpers']; getEqHashCode = helpers.getEqHashCode; makeLowLevelEqHash = helpers.makeLowLevelEqHash; toWrittenString = helpers.toWrittenString; toDisplayedString = helpers.toDisplayedString; toDomNode = helpers.toDomNode; }); var appendChild = function(parent, child) { parent.appendChild(child); }; ////////////////////////////////////////////////////////////////////// // Union/find for circular equality testing. var UnionFind = function() { // this.parenMap holds the arrows from an arbitrary pointer // to its parent. this.parentMap = makeLowLevelEqHash(); } // find: ptr -> UnionFindNode // Returns the representative for this ptr. UnionFind.prototype.find = function(ptr) { var parent = (this.parentMap.containsKey(ptr) ? this.parentMap.get(ptr) : ptr); if (parent === ptr) { return parent; } else { var rep = this.find(parent); // Path compression: this.parentMap.put(ptr, rep); return rep; } }; // merge: ptr ptr -> void // Merge the representative nodes for ptr1 and ptr2. UnionFind.prototype.merge = function(ptr1, ptr2) { this.parentMap.put(this.find(ptr1), this.find(ptr2)); }; ////////////////////////////////////////////////////////////////////// var StructType = function(name, type, numberOfArgs, numberOfFields, firstField, applyGuard, constructor, predicate, accessor, mutator) { this.name = name; this.type = type; this.numberOfArgs = numberOfArgs; this.numberOfFields = numberOfFields; this.firstField = firstField; this.applyGuard = applyGuard; this.constructor = constructor; this.predicate = predicate; this.accessor = accessor; this.mutator = mutator; }; StructType.prototype.toString = function(cache) { return '#'; }; StructType.prototype.isEqual = function(other, aUnionFind) { return this === other; }; var makeStructureType = function(theName, parentType, initFieldCnt, autoFieldCnt, autoV, guard) { var defaultGuard = function(args, name, k) { return k(args); }; // If no parent type given, then the parent type is Struct if ( !parentType ) { parentType = ({ type: Struct, numberOfArgs: 0, numberOfFields: 0, firstField: 0, applyGuard: defaultGuard }); } // if there's no guard, use the default one if (!guard) { guard = defaultGuard; } var numParentArgs = parentType.numberOfArgs; // Create a new struct type inheriting from the parent var aStruct = function(name, args) { parentType.type.call(this, name, args); for (var i = 0; i < initFieldCnt; i++) { this._fields.push(args[i+numParentArgs]); } for (var i = 0; i < autoFieldCnt; i++) { this._fields.push(autoV); } }; aStruct.prototype = helpers.heir(parentType.type.prototype); // Set type, necessary for equality checking aStruct.prototype.type = aStruct; // construct and return the new type var newType = new StructType(theName, aStruct, initFieldCnt + numParentArgs, initFieldCnt + autoFieldCnt, parentType.firstField + parentType.numberOfFields, function(args, name, k) { return guard(args, name, function(result) { var parentArgs = result.slice(0, parentType.numberOfArgs); var restArgs = result.slice(parentType.numberOfArgs); return parentType.applyGuard(parentArgs, name, function(parentRes) { return k( parentRes.concat(restArgs) ); }); }); }, function() { var args = helpers.map(function(x) { return x; }, arguments); return newType.applyGuard(args, Symbol.makeInstance(theName), function(res) { return new aStruct(theName, res); }); }, function(x) { return x instanceof aStruct; }, function(x, i) { return x._fields[i + this.firstField]; }, function(x, i, v) { x._fields[i + this.firstField] = v; }); return newType; }; var Struct = function(constructorName, fields) { this._constructorName = constructorName; this._fields = []; }; Struct.prototype.toWrittenString = function(cache) { cache.put(this, true); var buffer = []; buffer.push("("); buffer.push(this._constructorName); for(var i = 0; i < this._fields.length; i++) { buffer.push(" "); buffer.push(toWrittenString(this._fields[i], cache)); } buffer.push(")"); return buffer.join(""); }; Struct.prototype.toDisplayedString = function(cache) { return toWrittenString(this, cache); }; Struct.prototype.toDomNode = function(cache) { cache.put(this, true); var node = document.createElement("div"); node.appendChild(document.createTextNode("(")); node.appendChild(document.createTextNode(this._constructorName)); for(var i = 0; i < this._fields.length; i++) { node.appendChild(document.createTextNode(" ")); appendChild(node, toDomNode(this._fields[i], cache)); } node.appendChild(document.createTextNode(")")); return node; }; Struct.prototype.isEqual = function(other, aUnionFind) { if ( other.type == undefined || this.type !== other.type || !(other instanceof this.type) ) { return false; } for (var i = 0; i < this._fields.length; i++) { if (! isEqual(this._fields[i], other._fields[i], aUnionFind)) { return false; } } return true; } Struct.prototype.type = Struct; ////////////////////////////////////////////////////////////////////// // Regular expressions. var RegularExpression = function(pattern) { this.pattern = pattern; }; var ByteRegularExpression = function(pattern) { this.pattern = pattern; }; ////////////////////////////////////////////////////////////////////// // Paths var Path = function(p) { this.path = p; }; Path.prototype.toString = function() { return this.path; }; ////////////////////////////////////////////////////////////////////// // Bytes var Bytes = function(bts, mutable) { // bytes: arrayof [0-255] this.bytes = bts; this.mutable = (mutable === undefined) ? false : mutable; }; Bytes.prototype.get = function(i) { return this.bytes[i]; }; Bytes.prototype.set = function(i, b) { if (this.mutable) { this.bytes[i] = b; } }; Bytes.prototype.length = function() { return this.bytes.length; }; Bytes.prototype.copy = function(mutable) { return new Bytes(this.bytes.slice(0), mutable); }; Bytes.prototype.subbytes = function(start, end) { if (end == null || end == undefined) { end = this.bytes.length; } return new Bytes( this.bytes.slice(start, end), true ); }; Bytes.prototype.isEqual = function(other) { if (! (other instanceof Bytes)) { return false; } if (this.bytes.length != other.bytes.length) { return false; } var A = this.bytes; var B = other.bytes; var n = this.bytes.length; for (var i = 0; i < n; i++) { if (A[i] !== B[i]) return false; } return true; }; Bytes.prototype.toString = function(cache) { var ret = ''; for (var i = 0; i < this.bytes.length; i++) { ret += String.fromCharCode(this.bytes[i]); } return ret; }; Bytes.prototype.toDisplayedString = Bytes.prototype.toString; Bytes.prototype.toWrittenString = function() { var ret = ['#"']; for (var i = 0; i < this.bytes.length; i++) { ret.push( escapeByte(this.bytes[i]) ); } ret.push('"'); return ret.join(''); }; var escapeByte = function(aByte) { var ret = []; var returnVal; switch(aByte) { case 7: returnVal = '\\a'; break; case 8: returnVal = '\\b'; break; case 9: returnVal = '\\t'; break; case 10: returnVal = '\\n'; break; case 11: returnVal = '\\v'; break; case 12: returnVal = '\\f'; break; case 13: returnVal = '\\r'; break; case 34: returnVal = '\\"'; break; case 92: returnVal = '\\\\'; break; default: if (aByte >= 32 && aByte <= 126) { returnVal = String.fromCharCode(aByte); } else { ret.push( '\\' + aByte.toString(8) ); } break; } return returnVal; }; ////////////////////////////////////////////////////////////////////// // Boxes var Box = function(x, mutable) { this.val = x; this.mutable = mutable; }; Box.prototype.unbox = function() { return this.val; }; Box.prototype.set = function(newVal) { if (this.mutable) { this.val = newVal; } }; Box.prototype.toString = function(cache) { cache.put(this, true); return "#&" + toWrittenString(this.val, cache); }; Box.prototype.toWrittenString = function(cache) { cache.put(this, true); return "#&" + toWrittenString(this.val, cache); }; Box.prototype.toDisplayedString = function(cache) { cache.put(this, true); return "#&" + toDisplayedString(this.val, cache); }; Box.prototype.toDomNode = function(cache) { cache.put(this, true); var parent = document.createElement("span"); parent.appendChild(document.createTextNode('#&')); parent.appendChild(toDomNode(this.val, cache)); return parent; }; Box.prototype.isEqual = function(other, aUnionFind) { return ((other instanceof Box) && isEqual(this.val, other.val, aUnionFind)); }; ////////////////////////////////////////////////////////////////////// // Placeholders: same thing as boxes. Distinct type just to support make-reader-graph. var Placeholder = function(x, mutable) { this.val = x; }; Placeholder.prototype.ref = function() { return this.val; }; Placeholder.prototype.set = function(newVal) { this.val = newVal; }; Placeholder.prototype.toString = function(cache) { return "#"; }; Placeholder.prototype.toWrittenString = function(cache) { return "#"; }; Placeholder.prototype.toDisplayedString = function(cache) { return "#"; }; Placeholder.prototype.toDomNode = function(cache) { var parent = document.createElement("span"); parent.appendChild(document.createTextNode('#')); return parent; }; Placeholder.prototype.isEqual = function(other, aUnionFind) { return ((other instanceof Placeholder) && isEqual(this.val, other.val, aUnionFind)); }; ////////////////////////////////////////////////////////////////////// // We are reusing the built-in Javascript boolean class here. Logic = { TRUE : true, FALSE : false }; var isBoolean = function(x) { return (x === true || x === false); } // WARNING // WARNING: we are extending the built-in Javascript boolean class here! // WARNING Boolean.prototype.toWrittenString = function(cache) { if (this.valueOf()) { return "true"; } return "false"; }; Boolean.prototype.toDisplayedString = Boolean.prototype.toWrittenString; Boolean.prototype.toString = function(cache) { return this.valueOf() ? "true" : "false"; }; Boolean.prototype.isEqual = function(other, aUnionFind){ return this == other; }; // Chars // Char: string -> Char Char = function(val){ this.val = val; }; // The characters less than 256 must be eq?, according to the // documentation: // http://docs.racket-lang.org/reference/characters.html var _CharCache = {}; for (var i = 0; i < 256; i++) { _CharCache[String.fromCharCode(i)] = new Char(String.fromCharCode(i)); } // makeInstance: 1-character string -> Char Char.makeInstance = function(val){ if (_CharCache[val]) { return _CharCache[val]; } return new Char(val); }; Char.prototype.toString = function(cache) { var code = this.val.charCodeAt(0); var returnVal; switch (code) { case 0: returnVal = '#\\nul'; break; case 8: returnVal = '#\\backspace'; break; case 9: returnVal = '#\\tab'; break; case 10: returnVal = '#\\newline'; break; case 11: returnVal = '#\\vtab'; break; case 12: returnVal = '#\\page'; break; case 13: returnVal = '#\\return'; break; case 20: returnVal = '#\\space'; break; case 127: returnVal = '#\\rubout'; break; default: if (code >= 32 && code <= 126) { returnVal = ("#\\" + this.val); } else { var numStr = code.toString(16).toUpperCase(); while (numStr.length < 4) { numStr = '0' + numStr; } returnVal = ('#\\u' + numStr); } break; } return returnVal; }; Char.prototype.toWrittenString = Char.prototype.toString; Char.prototype.toDisplayedString = function (cache) { return this.val; }; Char.prototype.getValue = function() { return this.val; }; Char.prototype.isEqual = function(other, aUnionFind){ return other instanceof Char && this.val == other.val; }; ////////////////////////////////////////////////////////////////////// // Symbols ////////////////////////////////////////////////////////////////////// var Symbol = function(val) { this.val = val; }; var symbolCache = {}; // makeInstance: string -> Symbol. Symbol.makeInstance = function(val) { // To ensure that we can eq? symbols with equal values. if (!(val in symbolCache)) { symbolCache[val] = new Symbol(val); } else { } return symbolCache[val]; }; Symbol.prototype.isEqual = function(other, aUnionFind) { return other instanceof Symbol && this.val == other.val; }; Symbol.prototype.toString = function(cache) { return this.val; }; Symbol.prototype.toWrittenString = function(cache) { return this.val; }; Symbol.prototype.toDisplayedString = function(cache) { return this.val; }; ////////////////////////////////////////////////////////////////////// // Keywords var Keyword = function(val) { this.val = val; }; var keywordCache = {}; // makeInstance: string -> Keyword. Keyword.makeInstance = function(val) { // To ensure that we can eq? symbols with equal values. if (!(val in keywordCache)) { keywordCache[val] = new Keyword(val); } else { } return keywordCache[val]; }; Keyword.prototype.isEqual = function(other, aUnionFind) { return other instanceof Keyword && this.val == other.val; }; Keyword.prototype.toString = function(cache) { return this.val; }; Keyword.prototype.toWrittenString = function(cache) { return this.val; }; Keyword.prototype.toDisplayedString = function(cache) { return this.val; }; ////////////////////////////////////////////////////////////////////// Empty = function() { }; Empty.EMPTY = new Empty(); Empty.prototype.isEqual = function(other, aUnionFind) { return other instanceof Empty; }; Empty.prototype.reverse = function() { return this; }; Empty.prototype.first = function() { helpers.raise(types.incompleteExn( types.exnFailContract, "first can't be applied on empty.", [])); }; Empty.prototype.rest = function() { helpers.raise(types.incompleteExn( types.exnFailContract, "rest can't be applied on empty.", [])); }; Empty.prototype.isEmpty = function() { return true; }; Empty.prototype.toWrittenString = function(cache) { return "empty"; }; Empty.prototype.toDisplayedString = function(cache) { return "empty"; }; Empty.prototype.toString = function(cache) { return "()"; }; // Empty.append: (listof X) -> (listof X) Empty.prototype.append = function(b){ return b; }; ////////////////////////////////////////////////////////////////////// // Cons Pairs var Cons = function(f, r) { this.first = f; this.rest = r; }; Cons.prototype.reverse = function() { var lst = this; var ret = Empty.EMPTY; while (!lst.isEmpty()){ ret = Cons.makeInstance(lst.first, ret); lst = lst.rest; } return ret; }; Cons.makeInstance = function(f, r) { return new Cons(f, r); }; // FIXME: can we reduce the recursion on this? Cons.prototype.isEqual = function(other, aUnionFind) { if (! (other instanceof Cons)) { return Logic.FALSE; } return (isEqual(this.first, other.first, aUnionFind) && isEqual(this.rest, other.rest, aUnionFind)); }; Cons.prototype.isEmpty = function() { return false; }; // Cons.append: (listof X) -> (listof X) Cons.prototype.append = function(b){ if (b === Empty.EMPTY) return this; var ret = b; var lst = this.reverse(); while ( !lst.isEmpty() ) { ret = Cons.makeInstance(lst.first, ret); lst = lst.rest; } return ret; }; Cons.prototype.toWrittenString = function(cache) { cache.put(this, true); var texts = []; var p = this; while ( p instanceof Cons ) { texts.push(toWrittenString(p.first, cache)); p = p.rest; if (typeof(p) === 'object' && cache.containsKey(p)) { break; } } if ( p !== Empty.EMPTY ) { texts.push('.'); texts.push(toWrittenString(p, cache)); } return "(" + texts.join(" ") + ")"; }; Cons.prototype.toString = Cons.prototype.toWrittenString; Cons.prototype.toDisplayedString = function(cache) { cache.put(this, true); var texts = []; var p = this; while ( p instanceof Cons ) { texts.push(toDisplayedString(p.first, cache)); p = p.rest; if (typeof(p) === 'object' && cache.containsKey(p)) { break; } } if ( p !== Empty.EMPTY ) { texts.push('.'); texts.push(toDisplayedString(p, cache)); } return "(" + texts.join(" ") + ")"; }; Cons.prototype.toDomNode = function(cache) { cache.put(this, true); var node = document.createElement("span"); node.appendChild(document.createTextNode("(")); var p = this; while ( p instanceof Cons ) { appendChild(node, toDomNode(p.first, cache)); p = p.rest; if ( p !== Empty.EMPTY ) { appendChild(node, document.createTextNode(" ")); } if (typeof(p) === 'object' && cache.containsKey(p)) { break; } } if ( p !== Empty.EMPTY ) { appendChild(node, document.createTextNode(".")); appendChild(node, document.createTextNode(" ")); appendChild(node, toDomNode(p, cache)); } node.appendChild(document.createTextNode(")")); return node; }; // isList: Any -> Boolean // Returns true if x is a list (a chain of pairs terminated by EMPTY). var isList = function(x) { while (x !== Empty.EMPTY) { if (x instanceof Cons){ x = x.rest; } else { return false; } } return true; }; ////////////////////////////////////////////////////////////////////// Vector = function(n, initialElements) { this.elts = new Array(n); if (initialElements) { for (var i = 0; i < n; i++) { this.elts[i] = initialElements[i]; } } else { for (var i = 0; i < n; i++) { this.elts[i] = undefined; } } this.mutable = true; }; Vector.makeInstance = function(n, elts) { return new Vector(n, elts); } Vector.prototype.length = function() { return this.elts.length; }; Vector.prototype.ref = function(k) { return this.elts[k]; }; Vector.prototype.set = function(k, v) { this.elts[k] = v; }; Vector.prototype.isEqual = function(other, aUnionFind) { if (other != null && other != undefined && other instanceof Vector) { if (other.length() != this.length()) { return false } for (var i = 0; i < this.length(); i++) { if (! isEqual(this.elts[i], other.elts[i], aUnionFind)) { return false; } } return true; } else { return false; } }; Vector.prototype.toList = function() { var ret = Empty.EMPTY; for (var i = this.length() - 1; i >= 0; i--) { ret = Cons.makeInstance(this.elts[i], ret); } return ret; }; Vector.prototype.toWrittenString = function(cache) { cache.put(this, true); var texts = []; for (var i = 0; i < this.length(); i++) { texts.push(toWrittenString(this.ref(i), cache)); } return "#(" + texts.join(" ") + ")"; }; Vector.prototype.toDisplayedString = function(cache) { cache.put(this, true); var texts = []; for (var i = 0; i < this.length(); i++) { texts.push(toDisplayedString(this.ref(i), cache)); } return "#(" + texts.join(" ") + ")"; }; Vector.prototype.toDomNode = function(cache) { cache.put(this, true); var node = document.createElement("span"); node.appendChild(document.createTextNode("#(")); for (var i = 0; i < this.length(); i++) { appendChild(node, toDomNode(this.ref(i), cache)); if (i !== this.length()-1) { appendChild(node, document.createTextNode(" ")); } } node.appendChild(document.createTextNode(")")); return node; }; ////////////////////////////////////////////////////////////////////// // Now using mutable strings var Str = function(chars) { this.chars = chars; this.length = chars.length; this.mutable = true; } Str.makeInstance = function(chars) { return new Str(chars); } Str.fromString = function(s) { return Str.makeInstance(s.split("")); } Str.prototype.toString = function() { return this.chars.join(""); } Str.prototype.toWrittenString = function(cache) { return escapeString(this.toString()); } Str.prototype.toDisplayedString = Str.prototype.toString; Str.prototype.copy = function() { return Str.makeInstance(this.chars.slice(0)); } Str.prototype.substring = function(start, end) { if (end == null || end == undefined) { end = this.length; } return Str.makeInstance( this.chars.slice(start, end) ); } Str.prototype.charAt = function(index) { return this.chars[index]; } Str.prototype.charCodeAt = function(index) { return this.chars[index].charCodeAt(0); } Str.prototype.replace = function(expr, newStr) { return Str.fromString( this.toString().replace(expr, newStr) ); } Str.prototype.isEqual = function(other, aUnionFind) { if ( !(other instanceof Str || typeof(other) == 'string') ) { return false; } return this.toString() === other.toString(); } Str.prototype.set = function(i, c) { this.chars[i] = c; } Str.prototype.toUpperCase = function() { return Str.fromString( this.chars.join("").toUpperCase() ); } Str.prototype.toLowerCase = function() { return Str.fromString( this.chars.join("").toLowerCase() ); } Str.prototype.match = function(regexpr) { return this.toString().match(regexpr); } //var _quoteReplacingRegexp = new RegExp("[\"\\\\]", "g"); var escapeString = function(s) { return '"' + replaceUnprintableStringChars(s) + '"'; // return '"' + s.replace(_quoteReplacingRegexp, // function(match, submatch, index) { // return "\\" + match; // }) + '"'; }; var replaceUnprintableStringChars = function(s) { var ret = []; for (var i = 0; i < s.length; i++) { var val = s.charCodeAt(i); switch(val) { case 7: ret.push('\\a'); break; case 8: ret.push('\\b'); break; case 9: ret.push('\\t'); break; case 10: ret.push('\\n'); break; case 11: ret.push('\\v'); break; case 12: ret.push('\\f'); break; case 13: ret.push('\\r'); break; case 34: ret.push('\\"'); break; case 92: ret.push('\\\\'); break; default: if (val >= 32 && val <= 126) { ret.push( s.charAt(i) ); } else { var numStr = val.toString(16).toUpperCase(); while (numStr.length < 4) { numStr = '0' + numStr; } ret.push('\\u' + numStr); } break; } } return ret.join(''); }; /* // Strings // For the moment, we just reuse Javascript strings. String = String; String.makeInstance = function(s) { return s.valueOf(); }; // WARNING // WARNING: we are extending the built-in Javascript string class here! // WARNING String.prototype.isEqual = function(other, aUnionFind){ return this == other; }; var _quoteReplacingRegexp = new RegExp("[\"\\\\]", "g"); String.prototype.toWrittenString = function(cache) { return '"' + this.replace(_quoteReplacingRegexp, function(match, submatch, index) { return "\\" + match; }) + '"'; }; String.prototype.toDisplayedString = function(cache) { return this; }; */ ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// // Hashtables var EqHashTable = function(inputHash) { this.hash = makeLowLevelEqHash(); this.mutable = true; }; EqHashTable = EqHashTable; EqHashTable.prototype.toWrittenString = function(cache) { var keys = this.hash.keys(); var ret = []; for (var i = 0; i < keys.length; i++) { var keyStr = toWrittenString(keys[i], cache); var valStr = toWrittenString(this.hash.get(keys[i]), cache); ret.push('(' + keyStr + ' . ' + valStr + ')'); } return ('#hasheq(' + ret.join(' ') + ')'); }; EqHashTable.prototype.toDisplayedString = function(cache) { var keys = this.hash.keys(); var ret = []; for (var i = 0; i < keys.length; i++) { var keyStr = toDisplayedString(keys[i], cache); var valStr = toDisplayedString(this.hash.get(keys[i]), cache); ret.push('(' + keyStr + ' . ' + valStr + ')'); } return ('#hasheq(' + ret.join(' ') + ')'); }; EqHashTable.prototype.isEqual = function(other, aUnionFind) { if ( !(other instanceof EqHashTable) ) { return false; } if (this.hash.keys().length != other.hash.keys().length) { return false; } var keys = this.hash.keys(); for (var i = 0; i < keys.length; i++){ if ( !(other.hash.containsKey(keys[i]) && isEqual(this.hash.get(keys[i]), other.hash.get(keys[i]), aUnionFind)) ) { return false; } } return true; }; var EqualHashTable = function(inputHash) { this.hash = new _Hashtable(function(x) { return toWrittenString(x); }, function(x, y) { return isEqual(x, y, new UnionFind()); }); this.mutable = true; }; EqualHashTable = EqualHashTable; EqualHashTable.prototype.toWrittenString = function(cache) { var keys = this.hash.keys(); var ret = []; for (var i = 0; i < keys.length; i++) { var keyStr = toWrittenString(keys[i], cache); var valStr = toWrittenString(this.hash.get(keys[i]), cache); ret.push('(' + keyStr + ' . ' + valStr + ')'); } return ('#hash(' + ret.join(' ') + ')'); }; EqualHashTable.prototype.toDisplayedString = function(cache) { var keys = this.hash.keys(); var ret = []; for (var i = 0; i < keys.length; i++) { var keyStr = toDisplayedString(keys[i], cache); var valStr = toDisplayedString(this.hash.get(keys[i]), cache); ret.push('(' + keyStr + ' . ' + valStr + ')'); } return ('#hash(' + ret.join(' ') + ')'); }; EqualHashTable.prototype.isEqual = function(other, aUnionFind) { if ( !(other instanceof EqualHashTable) ) { return false; } if (this.hash.keys().length != other.hash.keys().length) { return false; } var keys = this.hash.keys(); for (var i = 0; i < keys.length; i++){ if (! (other.hash.containsKey(keys[i]) && isEqual(this.hash.get(keys[i]), other.hash.get(keys[i]), aUnionFind))) { return false; } } return true; }; ////////////////////////////////////////////////////////////////////// var JsValue = function(name, val) { this.name = name; this.val = val; }; JsValue.prototype.toString = function() { return '#'; }; JsValue.prototype.toDomNode = function(cache) { return toDomNode(this.val, cache); }; JsValue.prototype.isEqual = function(other, aUnionFind) { return (this.val === other.val); }; // unbox: jsvalue -> any // Unwraps the value out of the JsValue box. JsValue.prototype.unbox = function() { return this.val; }; var WrappedSchemeValue = function(val) { this.val = val; }; WrappedSchemeValue.prototype.toString = function() { return toString(this.val); }; WrappedSchemeValue.prototype.toWrittenString = function(cache) { return toWrittenString(this.val, cache); }; WrappedSchemeValue.prototype.toDisplayedString = function(cache) { return toDisplayedString(this.val, cache); }; // unbox: jsvalue -> any // Unwraps the value out of the WrappedSchemeValue box. WrappedSchemeValue.prototype.unbox = function() { return this.val; }; ////////////////////////////////////////////////////////////////////// var WorldConfig = function(startup, shutdown, startupArgs) { this.startup = startup; this.shutdown = shutdown; this.startupArgs = startupArgs; }; WorldConfig.prototype.toString = function() { return '#'; }; WorldConfig.prototype.isEqual = function(other, aUnionFind) { return ( isEqual(this.startup, other.startup, aUnionFind) && isEqual(this.shutdown, other.shutdown, aUnionFind) && isEqual(this.shutdownArg, other.shutdownArg, aUnionFind) && isEqual(this.restartArg, other.restartArg, aUnionFind) ); }; var Effect = makeStructureType('effect', false, 0, 0, false, false); Effect.type.prototype.invokeEffect = function() { helpers.raise(types.incompleteExn( types.exnFail, 'effect type created without using make-effect-type', [])); }; var makeEffectType = function(name, superType, initFieldCnt, impl, guard) { if ( !superType ) { superType = Effect; } var newType = makeStructureType(name, superType, initFieldCnt, 0, false, guard); var lastFieldIndex = newType.firstField + newType.numberOfFields; newType.type.prototype.invokeEffect = function(aBigBang, k) { var schemeChangeWorld = new PrimProc('update-world', 1, false, false, function(worldUpdater) { helpers.check(worldUpdater, helpers.procArityContains(1), 'update-world', 'procedure (arity 1)', 1); return new INTERNAL_PAUSE( function(caller, onSuccess, onFail) { aBigBang.changeWorld(function(w, k2) { caller(worldUpdater, [w], k2, function(e) { throw e; }, 'change-world (effect)'); }, function() { onSuccess(VOID_VALUE, 'restarting (change-world (effect))'); }); }); }); var args = this._fields.slice(0, lastFieldIndex); args.unshift(schemeChangeWorld); return aBigBang.caller(impl, args, k, function(e) { throw e; }, 'invoking effect ' + name); } return newType; }; var RenderEffect = makeStructureType('render-effect', false, 0, 0, false, false); RenderEffect.type.prototype.callImplementation = function(caller, k) { helpers.raise(types.incompleteExn( types.exnFail, 'render effect created without using make-render-effect-type', [])); }; var makeRenderEffectType = function(name, superType, initFieldCnt, impl, guard) { if ( !superType ) { superType = RenderEffect; } var newType = makeStructureType(name, superType, initFieldCnt, 0, false, guard); var lastFieldIndex = newType.firstField + newType.numberOfFields; newType.type.prototype.callImplementation = function(caller, k) { var args = this._fields.slice(0, lastFieldIndex); caller(impl, args, k); } return newType; }; ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// var isNumber = jsnums.isSchemeNumber; var isReal = jsnums.isReal; var isRational = jsnums.isRational; var isComplex = isNumber; var isInteger = jsnums.isInteger; var isNatural = function(x) { return (jsnums.isExact(x) && isInteger(x) && jsnums.greaterThanOrEqual(x, 0)); }; var isNonNegativeReal = function(x) { return isReal(x) && jsnums.greaterThanOrEqual(x, 0); }; var isString = function(s) { return (typeof s === 'string' || s instanceof Str); } // isEqual: X Y -> boolean // Returns true if the objects are equivalent; otherwise, returns false. var isEqual = function(x, y, aUnionFind) { if (x === y) { return true; } if (isNumber(x) && isNumber(y)) { return jsnums.eqv(x, y); } if (isString(x) && isString(y)) { return x.toString() === y.toString(); } if (x == undefined || x == null) { return (y == undefined || y == null); } if ( typeof(x) == 'object' && typeof(y) == 'object' && x.isEqual && y.isEqual) { if (typeof (aUnionFind) === 'undefined') { aUnionFind = new UnionFind(); } if (aUnionFind.find(x) === aUnionFind.find(y)) { return true; } else { aUnionFind.merge(x, y); return x.isEqual(y, aUnionFind); } } return false; }; // liftToplevelToFunctionValue: primitive-function string fixnum scheme-value -> scheme-value // Lifts a primitive toplevel or module-bound value to a scheme value. var liftToplevelToFunctionValue = function(primitiveF, name, minArity, procedureArityDescription) { if (! primitiveF._mobyLiftedFunction) { var lifted = function(args) { return primitiveF.apply(null, args.slice(0, minArity).concat([args.slice(minArity)])); }; lifted.isEqual = function(other, cache) { return this === other; } lifted.toWrittenString = function(cache) { return "#"; }; lifted.toDisplayedString = lifted.toWrittenString; lifted.procedureArity = procedureArityDescription; primitiveF._mobyLiftedFunction = lifted; } return primitiveF._mobyLiftedFunction; }; ////////////////////////////////////////////////////////////////////// var ThreadCell = function(v, isPreserved) { this.v = v; this.isPreserved = isPreserved || false; }; ////////////////////////////////////////////////////////////////////// // Wrapper around functions that return multiple values. var ValuesWrapper = function(elts) { this.elts = elts; }; ValuesWrapper.prototype.toDomNode = function(cache) { var parent = document.createElement("span"); parent.style["white-space"] = "pre"; if ( this.elts.length > 0 ) { parent.appendChild( toDomNode(this.elts[0], cache) ); for (var i = 1; i < this.elts.length; i++) { parent.appendChild( document.createTextNode('\n') ); parent.appendChild( toDomNode(this.elts[i], cache) ); } } return parent; }; ValuesWrapper.prototype.isEqual = function(other, aUnionFind) { if (! other instanceof ValuesWrapper) { return false; } if (this.elts.length !== other.elts.length) { return false; } for (var i = 0; i < this.elts.length; i++) { if (! isEqual(this.elts[i], other.elts[i], aUnionFind)) { return false; } } return true; }; var UndefinedValue = function() { }; UndefinedValue.prototype.toString = function() { return "#"; }; var UNDEFINED_VALUE = new UndefinedValue(); var VoidValue = function() {}; VoidValue.prototype.toString = function() { return "#"; }; var VOID_VALUE = new VoidValue(); var EofValue = function() {}; EofValue.prototype.toString = function() { return "#"; } var EOF_VALUE = new EofValue(); var ClosureValue = function(name, numParams, paramTypes, isRest, closureVals, body) { this.name = name; this.numParams = numParams; this.paramTypes = paramTypes; this.isRest = isRest; this.closureVals = closureVals; this.body = body; }; ClosureValue.prototype.toString = function() { if (this.name !== undefined && this.name !== Empty.EMPTY) { return helpers.format("#", [this.name]); } else { return "#"; } }; var CaseLambdaValue = function(name, closures) { this.name = name; this.closures = closures; }; CaseLambdaValue.prototype.toString = function() { if (this.name !== undefined && this.name !== Empty.EMPTY) { return helpers.format("#", [this.name]); } else { return "#"; } }; var ContinuationClosureValue = function(vstack, cstack) { this.name = types.EMPTY; this.vstack = vstack.slice(0); this.cstack = cstack.slice(0); }; ContinuationClosureValue.prototype.toString = function() { if (this.name !== Empty.EMPTY) { return helpers.format("#", [this.name]); } else { return "#"; } }; ////////////////////////////////////////////////////////////////////// var PrefixValue = function() { this.slots = []; this.definedMask = []; }; PrefixValue.prototype.addSlot = function(v) { if (v === undefined) { this.slots.push(types.UNDEFINED); this.definedMask.push(false); } else { this.slots.push(v); if (v instanceof GlobalBucket) { if (v.value === types.UNDEFINED) { this.definedMask.push(false); } else { this.definedMask.push(true); } } else if (v instanceof NamedSlot) { if (v.value === types.UNDEFINED) { this.definedMask.push(false); } else { this.definedMask.push(true); } } else { this.definedMask.push(true); } } }; PrefixValue.prototype.ref = function(n) { if (this.slots[n] instanceof GlobalBucket) { if (this.definedMask[n]) { return this.slots[n].value; } else { helpers.raise(types.incompleteExn( types.exnFailContractVariable, "reference to an identifier before its definition: " + this.slots[n].name, [this.slots[n].name])); } } else if (this.slots[n] instanceof NamedSlot) { if (this.definedMask[n]) { return this.slots[n].value; } else { helpers.raise(types.incompleteExn( types.exnFailContractVariable, "reference to an identifier before its definition: " + this.slots[n].name, [this.slots[n].name])); } } else { if (this.definedMask[n]) { return this.slots[n]; } else { helpers.raise(types.incompleteExn( types.exnFailContractVariable, "variable has not been defined", [false])); } } }; PrefixValue.prototype.lookup = function(name) { for (var i = 0; i < this.slots.length; i++) { if (this.slots[i] instanceof NamedSlot) { if (this.slots[i].name === name) { return this.slots[i].value; } } else if (this.slots[i] instanceof GlobalBucket) { if (this.slots[i].name === name) { return this.slots[i].value; } } }; return types.UNDEFINED; }; PrefixValue.prototype.set = function(n, v) { if (this.slots[n] instanceof GlobalBucket) { this.slots[n].value = v; this.definedMask[n] = true; } else if (this.slots[n] instanceof NamedSlot) { this.slots[n].value = v; this.definedMask[n] = true; } else { this.slots[n] = v; this.definedMask[n] = true; } }; PrefixValue.prototype.length = function() { return this.slots.length; }; var GlobalBucket = function(name, value) { this.name = name; this.value = value; }; var NamedSlot = function(name, value) { this.name = name; this.value = value; }; var ModuleVariableRecord = function(resolvedModuleName, variableName) { this.resolvedModuleName = resolvedModuleName; this.variableName = variableName; }; ////////////////////////////////////////////////////////////////////// var Namespace = function() { this.prefixes = []; this.bindings = {}; }; Namespace.prototype.addPrefix = function(prefixValue) { this.prefixes.push(prefixValue); }; Namespace.prototype.getVariableValue = function(name) { // FIXME: fill me in. // first, look in bindings. // if not there, then look into each of the prefixes. }; Namespace.prototype.setVariableValue = function(name, value) { // FIXME: fill me in. this.bindings[name] = value; }; ////////////////////////////////////////////////////////////////////// var VariableReference = function(prefix, pos) { this.prefix = prefix; this.pos = pos; }; VariableReference.prototype.ref = function() { return this.prefix.ref(this.pos); }; VariableReference.prototype.set = function(v) { this.prefix.set(this.pos, v); } ////////////////////////////////////////////////////////////////////// // Continuation Marks var ContMarkRecordControl = function(dict) { this.dict = dict || makeLowLevelEqHash(); }; ContMarkRecordControl.prototype.invoke = function(state) { // No-op: the record will simply pop off the control stack. }; ContMarkRecordControl.prototype.update = function(key, val) { var newDict = makeLowLevelEqHash(); // FIXME: what's the javascript idiom for hash key copy? // Maybe we should use a rbtree instead? var oldKeys = this.dict.keys(); for (var i = 0; i < oldKeys.length; i++) { newDict.put( oldKeys[i], this.dict.get(oldKeys[i]) ); } newDict.put(key, val); return new ContMarkRecordControl(newDict); }; var ContinuationMarkSet = function(dict) { this.dict = dict; } ContinuationMarkSet.prototype.toDomNode = function(cache) { var dom = document.createElement("span"); dom.appendChild(document.createTextNode('#')); return dom; }; ContinuationMarkSet.prototype.toWrittenString = function(cache) { return '#'; }; ContinuationMarkSet.prototype.toDisplayedString = function(cache) { return '#'; }; ContinuationMarkSet.prototype.ref = function(key) { if ( this.dict.containsKey(key) ) { return this.dict.get(key); } return []; }; ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////// var PrimProc = function(name, numParams, isRest, usesState, impl) { this.name = name; this.numParams = numParams; this.isRest = isRest; this.usesState = usesState; this.impl = impl; }; PrimProc.prototype.toString = function() { return ("#"); }; PrimProc.prototype.toWrittenString = function(cache) { return ("#"); }; PrimProc.prototype.toDisplayedString = function(cache) { return ("#"); }; PrimProc.prototype.toDomNode = function(cache) { var div = document.createElement("span"); div.appendChild(document.createTextNode("#")); return div; }; var CasePrimitive = function(name, cases) { this.name = name; this.cases = cases; }; CasePrimitive.prototype.toDomNode = function(cache) { var div = document.createElement("span"); div.appendChild(document.createTextNode("#")); return div; }; CasePrimitive.prototype.toWrittenString = function(cache) { return ("#"); }; CasePrimitive.prototype.toDisplayedString = function(cache) { return ("#"); }; ////////////////////////////////////////////////////////////////////// var makeOptionPrimitive = function(name, numArgs, defaultVals, usesState, bodyF) { var makeNthPrimitive = function(n) { return new PrimProc(name, numArgs + n, false, usesState, function() { var expectedNumArgs = numArgs + n + (usesState ? 1 : 0); assert.equal(arguments.length, expectedNumArgs); var args = [arguments]; for (var i = 0; i < arguments.length; i++) { args.push(arguments[i]); } var startDefaults = i - numArgs - (usesState ? 1 : 0); return bodyF.apply( bodyF, args.concat(defaultVals.slice(startDefaults))); }); }; var cases = []; for (var i = 0; i <= defaultVals.length; i++) { cases.push(makeNthPrimitive(i)); } return new CasePrimitive(name, cases); }; // Struct Procedure types var StructProc = function(type, name, numParams, isRest, usesState, impl) { PrimProc.call(this, name, numParams, isRest, usesState, impl); this.type = type; }; StructProc.prototype = helpers.heir(PrimProc.prototype); var StructConstructorProc = function() { StructProc.apply(this, arguments); }; StructConstructorProc.prototype = helpers.heir(StructProc.prototype); var StructPredicateProc = function() { StructProc.apply(this, arguments); }; StructPredicateProc.prototype = helpers.heir(StructProc.prototype); var StructAccessorProc = function() { StructProc.apply(this, arguments); }; StructAccessorProc.prototype = helpers.heir(StructProc.prototype); var StructMutatorProc = function() { StructProc.apply(this, arguments); }; StructMutatorProc.prototype = helpers.heir(StructProc.prototype); ////////////////////////////////////////////////////////////////////// // INTERNAL_CALL // used for interaction between the Primitives and the interpreter (callPrimitiveProcedure). // Don't confuse this with CallControl. var INTERNAL_CALL = function(operator, operands, k) { this.operator = operator; this.operands = operands; this.k = k; }; // INTERNAL_PAUSE // used for interaction between the Primitive functions and the // interpreter. // Halts the interpreter, but passing onPause the functions necessary // to restart computation. var INTERNAL_PAUSE = function(onPause) { this.onPause = onPause; }; ////////////////////////////////////////////////////////////////////// // ContinuationPromptTag: symbol | false -> ContinuationPromptTag var ContinuationPromptTag = function(sym) { this.sym = sym; }; var defaultContinuationPromptTag = new ContinuationPromptTag(); var defaultContinuationPromptTagHandler = new PrimProc( 'default-continuation-prompt-tag-handler', 1, false, true, function(aState, thunk) { aState.pushControl( new control.ApplicationControl( new control.ConstantControl(thunk), [])); }); ////////////////////////////////////////////////////////////////////// var makeList = function() { var result = Empty.EMPTY; for(var i = arguments.length-1; i >= 0; i--) { result = Cons.makeInstance(arguments[i], result); } return result; }; var makeVector = function(arguments) { return Vector.makeInstance(arguments.length, arguments); }; var makeVectorImmutable = function(arguments) { var v = Vector.makeInstance(arguments.length, arguments); v.mutable = false; return v; }; var makeString = function(s) { if (s instanceof Str) { return s; } else if (s instanceof Array) { // for (var i = 0; i < s.length; i++) { // if ( typeof s[i] !== 'string' || s[i].length != 1 ) { // return undefined; // } // } return Str.makeInstance(s); } else if (typeof s === 'string') { return Str.fromString(s); } else { throw types.internalError('makeString expects and array of 1-character strings or a string;' + ' given ' + s.toString(), false); } } var makeHashEq = function(lst) { var newHash = new EqHashTable(); while ( !lst.isEmpty() ) { newHash.hash.put(lst.first.first, lst.first.rest); lst = lst.rest; } return newHash; } var makeHashEqual = function(lst) { var newHash = new EqualHashTable(); while ( !lst.isEmpty() ) { newHash.hash.put(lst.first.first, lst.first.rest); lst = lst.rest; } return newHash; } var Color = makeStructureType('color', false, 3, 0, false, false); var ArityAtLeast = makeStructureType('arity-at-least', false, 1, 0, false, function(args, name, k) { helpers.check(args[0], function(x) { return ( jsnums.isExact(x) && jsnums.isInteger(x) && jsnums.greaterThanOrEqual(x, 0) ); }, name, 'exact non-negative integer', 1); return k(args); }); ////////////////////////////////////////////////////////////////////// var readerGraph = function(x, objectHash, n) { if (typeof(x) === 'object' && objectHash.containsKey(x)) { return objectHash.get(x); } if (types.isPair(x)) { var consPair = types.cons(x.first, x.rest); objectHash.put(x, consPair); consPair.f = readerGraph(x.first, objectHash, n+1); consPair.r = readerGraph(x.rest, objectHash, n+1); return consPair; } if (types.isVector(x)) { var len = x.length(); var aVector = types.vector(len, x.elts); objectHash.put(x, aVector); for (var i = 0; i < len; i++) { aVector.elts[i] = readerGraph(aVector.elts[i], objectHash, n+1); } return aVector; } if (types.isBox(x)) { var aBox = types.box(x.unbox()); objectHash.put(x, aBox); aBox.val = readerGraph(x.unbox(), objectHash, n+1); return aBox; } if (types.isHash(x)) { throw new Error("make-reader-graph of hash not implemented yet"); } if (types.isStruct(x)) { var aStruct = helpers.clone(x); objectHash.put(x, aStruct); for(var i = 0 ;i < x._fields.length; i++) { x._fields[i] = readerGraph(x._fields[i], objectHash, n+1); } return aStruct; } if (types.isPlaceholder(x)) { return readerGraph(x.ref(), objectHash, n+1); } return x; }; ////////////////////////////////////////////////////////////////////// types.exceptionHandlerKey = new Symbol("exnh"); types.symbol = Symbol.makeInstance; types.rational = jsnums.makeRational; types.floatpoint = jsnums.makeFloat; types.complex = jsnums.makeComplex; types.bignum = jsnums.makeBignum; types.list = makeList; types.vector = makeVector; types.vectorImmutable = makeVectorImmutable; types.regexp = function(p) { return new RegularExpression(p) ; } types.byteRegexp = function(p) { return new ByteRegularExpression(p) ; } types.character = Char.makeInstance; types['string'] = makeString; types.box = function(x) { return new Box(x, true); }; types.placeholder = function(x) { return new Placeholder(x); }; types.boxImmutable = function(x) { return new Box(x, false); }; types.path = function(x) { return new Path(x); }; types.bytes = function(x, mutable) { return new Bytes(x, mutable); }; types.bytesImmutable = function(x) { return new Bytes(x, false); }; types.keyword = function(k) { return new Keyword(k); }; types.pair = function(x, y) { return Cons.makeInstance(x, y); }; types.hash = makeHashEqual; types.hashEq = makeHashEq; types.jsValue = function(name, val) { return new JsValue(name, val); }; types.wrappedSchemeValue = function(val) { return new WrappedSchemeValue(val); }; types.color = Color.constructor; types.colorRed = function(x) { return Color.accessor(x, 0); }; types.colorGreen = function(x) { return Color.accessor(x, 1); }; types.colorBlue = function(x) { return Color.accessor(x, 2); }; types.arityAtLeast = ArityAtLeast.constructor; types.arityAtLeastValue = function(arity) { return ArityAtLeast.accessor(arity, 0); }; types.FALSE = Logic.FALSE; types.TRUE = Logic.TRUE; types.EMPTY = Empty.EMPTY; types.isEqual = isEqual; types.isNumber = isNumber; types.isReal = jsnums.isReal; types.isBoolean = isBoolean; types.isRational = jsnums.isRational; types.isComplex = isNumber; types.isInteger = jsnums.isInteger; types.isNatural = isNatural; types.isNonNegativeReal = isNonNegativeReal; types.isSymbol = function(x) { return x instanceof Symbol; }; types.isChar = function(x) { return x instanceof Char; }; types.isString = isString; types.isPair = function(x) { return x instanceof Cons; }; types.isList = isList; types.isEmpty = function(x) { return x === Empty.EMPTY; }; types.isVector = function(x) { return x instanceof Vector; }; types.isBox = function(x) { return x instanceof Box; }; types.isPlaceholder = function(x) { return x instanceof Placeholder; }; types.isHash = function(x) { return (x instanceof EqHashTable || x instanceof EqualHashTable); }; types.isByteString = function(x) { return x instanceof Bytes; }; types.isStruct = function(x) { return x instanceof Struct; }; types.isArityAtLeast = ArityAtLeast.predicate; types.isColor = Color.predicate; types.isFunction = function(x) { return (x instanceof PrimProc || x instanceof CasePrimitive || x instanceof ClosureValue || x instanceof CaseLambdaValue || x instanceof ContinuationClosureValue); }; types.isJsValue = function(x) { return x instanceof JsValue; }; types.isWrappedSchemeValue = function(x) { return x instanceof WrappedSchemeValue; }; types.UnionFind = UnionFind; types.cons = Cons.makeInstance; types.UNDEFINED = UNDEFINED_VALUE; types.VOID = VOID_VALUE; types.EOF = EOF_VALUE; types.ValuesWrapper = ValuesWrapper; types.ClosureValue = ClosureValue; types.ContinuationPromptTag = ContinuationPromptTag; types.defaultContinuationPromptTag = defaultContinuationPromptTag; types.defaultContinuationPromptTagHandler = defaultContinuationPromptTagHandler; types.ContinuationClosureValue = ContinuationClosureValue; types.CaseLambdaValue = CaseLambdaValue; types.PrimProc = PrimProc; types.CasePrimitive = CasePrimitive; types.makeOptionPrimitive = makeOptionPrimitive; types.internalCall = function(op, args, k) { return new INTERNAL_CALL(op, args, k); }; types.isInternalCall = function(x) { return (x instanceof INTERNAL_CALL); }; types.internalPause = function(onPause) { return new INTERNAL_PAUSE(onPause) }; types.isInternalPause = function(x) { return (x instanceof INTERNAL_PAUSE); }; types.contMarkRecordControl = function(dict) { return new ContMarkRecordControl(dict); }; types.isContMarkRecordControl = function(x) { return x instanceof ContMarkRecordControl; }; types.continuationMarkSet = function(dict) { return new ContinuationMarkSet(dict); }; types.isContinuationMarkSet = function(x) { return x instanceof ContinuationMarkSet; }; types.isContinuationPromptTag = function(x) { return x instanceof ContinuationPromptTag; }; types.PrefixValue = PrefixValue; types.GlobalBucket = GlobalBucket; types.NamedSlot = NamedSlot; types.ModuleVariableRecord = ModuleVariableRecord; types.VariableReference = VariableReference; types.Box = Box; types.Placeholder = Placeholder; types.ThreadCell = ThreadCell; types.makeStructureType = makeStructureType; types.isStructType = function(x) { return x instanceof StructType; }; types.StructProc = StructProc; types.StructConstructorProc = StructConstructorProc; types.StructPredicateProc = StructPredicateProc; types.StructAccessorProc = StructAccessorProc; types.StructMutatorProc = StructMutatorProc; types.makeLowLevelEqHash = makeLowLevelEqHash; // Error type exports var InternalError = function(val, contMarks) { this.val = val; this.contMarks = (contMarks ? contMarks : false); } types.internalError = function(v, contMarks) { return new InternalError(v, contMarks); }; types.isInternalError = function(x) { return x instanceof InternalError; }; var SchemeError = function(val) { this.val = val; } types.schemeError = function(v) { return new SchemeError(v); }; types.isSchemeError = function(v) { return v instanceof SchemeError; }; var IncompleteExn = function(constructor, msg, otherArgs) { this.constructor = constructor; this.msg = msg; this.otherArgs = otherArgs; }; types.incompleteExn = function(constructor, msg, args) { return new IncompleteExn(constructor, msg, args); }; types.isIncompleteExn = function(x) { return x instanceof IncompleteExn; }; var Exn = makeStructureType('exn', false, 2, 0, false, function(args, name, k) { helpers.check(args[0], isString, name, 'string', 1); helpers.check(args[1], types.isContinuationMarkSet, name, 'continuation mark set', 2); return k(args); }); types.exn = Exn.constructor; types.isExn = Exn.predicate; types.exnMessage = function(exn) { return Exn.accessor(exn, 0); }; types.exnContMarks = function(exn) { return Exn.accessor(exn, 1); }; types.exnSetContMarks = function(exn, v) { Exn.mutator(exn, 1, v); }; // (define-struct (exn:break exn) (continuation)) var ExnBreak = makeStructureType('exn:break', Exn, 1, 0, false, function(args, name, k) { helpers.check(args[2], function(x) { return x instanceof ContinuationClosureValue; }, name, 'continuation', 3); return k(args); }); types.exnBreak = ExnBreak.constructor; types.isExnBreak = ExnBreak.predicate; types.exnBreakContinuation = function(exn) { return ExnBreak.accessor(exn, 0); }; var ExnFail = makeStructureType('exn:fail', Exn, 0, 0, false, false); types.exnFail = ExnFail.constructor; types.isExnFail = ExnFail.predicate; var ExnFailContract = makeStructureType('exn:fail:contract', ExnFail, 0, 0, false, false); types.exnFailContract = ExnFailContract.constructor; types.isExnFailContract = ExnFailContract.predicate; var ExnFailContractArity = makeStructureType('exn:fail:contract:arity', ExnFailContract, 0, 0, false, false); types.exnFailContractArity = ExnFailContractArity.constructor; types.isExnFailContractArity = ExnFailContractArity.predicate; var ExnFailContractVariable = makeStructureType('exn:fail:contract:variable', ExnFailContract, 1, 0, false, false); types.exnFailContractVariable = ExnFailContractVariable.constructor; types.isExnFailContractVariable = ExnFailContractVariable.predicate; types.exnFailContractVariableId = function(exn) { return ExnFailContractVariable.accessor(exn, 0); }; var ExnFailContractDivisionByZero = makeStructureType('exn:fail:contract:divide-by-zero', ExnFailContract, 0, 0, false, false); types.exnFailContractDivisionByZero = ExnFailContractDivisionByZero.constructor; types.isExnFailContractDivisionByZero = ExnFailContractDivisionByZero.predicate; /////////////////////////////////////// // World-specific exports // big bang info to be passed into a make-world-config startup argument var BigBangInfo = makeStructureType('bb-info', false, 2, 0, false, function(args, name, k) { helpers.check(args[0], helpers.procArityContains(1), name, 'procedure (arity 1)', 1); helpers.check(args[1], types.isJsValue, name, 'js-object', 2); return k(args); }); types.BigBangInfo = BigBangInfo; types.makeBigBangInfo = BigBangInfo.constructor; types.isBigBangInfo = BigBangInfo.predicate; types.bbInfoChangeWorld = function(info) { return BigBangInfo.accessor(info, 0); }; types.bbInfoToplevelNode = function(info) { return BigBangInfo.accessor(info, 1); }; // World config information for user-defined configurations types.worldConfig = function(startup, shutdown, pause, restart) { return new WorldConfig(startup, shutdown, pause, restart); }; types.isWorldConfig = function(x) { return x instanceof WorldConfig; }; // exporting information to create effect types types.makeEffectType = makeEffectType; types.isEffectType = function(x) { return ((x instanceof StructType)&& x.type.prototype.invokeEffect) ? true : false; }; types.isEffect = Effect.predicate; // exporting functions to create render effect types types.makeRenderEffectType = makeRenderEffectType; types.isRenderEffectType = function(x) { return (x instanceof StructType && x.type.prototype.callImplementation) ? true : false; }; types.isRenderEffect = RenderEffect.predicate; types.readerGraph = readerGraph; scope.link.announceReady('types'); })(this['plt']);