| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311 | 
							- // Copyright (c) 2008, 2010 Alessandro Warth <awarth@cs.ucla.edu>
 
- DEBUG = false;
 
- // getTag: object -> unique id
 
- // tagToRef: unique id -> object
 
- // Note: this hashing scheme causes a huge memory leak (all b/c JS doesn't support weak references)
 
- (function() {
 
-   var numIdx = 0, tagToRef = {}
 
-   var _getTag = function(r) {
 
-     if (r === null || r === undefined)
 
-       return r
 
-     switch (typeof r) {
 
-       case "boolean": return r == true ? "Btrue" : "Bfalse"
 
-       case "string":  return "S" + r
 
-       case "number":  return "N" + r
 
-       default:        return r.hasOwnProperty("_id_") ? r._id_ : r._id_ = "R" + numIdx++
 
-     }
 
-   }
 
-   getTag = function(r) {
 
-     var tag = _getTag(r)
 
-     tagToRef[tag] = r
 
-     return tag
 
-   }
 
-   getRef = function(t) {
 
-     return tagToRef[t]
 
-   }
 
- })()
 
- // implementation of possible worlds
 
- worldProto = {}
 
- baseWorld = thisWorld = (function() {
 
-   var writes = {}
 
-   return {
 
-     parent: worldProto,
 
-     writes: writes,
 
-     hasOwn: function(r, p) {
 
-       var id = getTag(r)
 
-       return writes.hasOwnProperty(id) && writes[id].hasOwnProperty(p)
 
-     },
 
-     has: function(r, p) {
 
-       return this.hasOwn(r, p) ||
 
-              r !== Object.prototype && this.has(r === null || r === undefined ? Object.prototype : r.parent, p)
 
-     },
 
-     props: function(r, ps) {
 
-       var id = getTag(r)
 
-       if (writes.hasOwnProperty(id))
 
-         for (var p in writes[id])
 
-           if (writes[id].hasOwnProperty(p))
 
-             ps[p] = true
 
-       if (r !== Object.prototype)
 
-         this.props(r === null || r === undefined ? Object.prototype : r.parent, ps)
 
-       return ps
 
-     },
 
-     _get: function(r, p) {
 
-       var id = getTag(r)
 
-       if (DEBUG) console.log("? top-level world looking up " + id + "." + p)
 
-       if (writes.hasOwnProperty(id) && writes[id].hasOwnProperty(p))
 
-         return writes[id][p]
 
-       else if (r !== Object.prototype)
 
-         return thisWorld._get(r === null || r === undefined ? Object.prototype : r.parent, p)
 
-       else
 
-         return undefined
 
-     },
 
-     get: function(r, p) {
 
-       // the top-level world's commit operation is a no-op, so reads don't have to be recorded
 
-       if (typeof r === "string" && (typeof p === "number" || p === "length"))
 
-         return r[p]
 
-       else
 
-         return this._get(r, p)
 
-     },
 
-     set: function(r, p, v) {
 
-       if (typeof r === "string" && (typeof p === "number" || p === "length"))
 
-         throw "the indices and length of a string are immutable, and you tried to change them!"
 
-       var id = getTag(r)
 
-       if (DEBUG) console.log("! top-level world assigning to " + id + "." + p)
 
-       if (!writes.hasOwnProperty(id))
 
-         writes[id] = {}
 
-       writes[id][p] = v
 
-       return v
 
-     },
 
-     commit: function() { },
 
-     sprout: function() {
 
-       var parentWorld = this, writes = {}, reads = {}
 
-       return {
 
-         parent: worldProto,
 
-         writes: writes,
 
-         reads:  reads,
 
-         hasOwn: function(r, p) {
 
-           var id = getTag(r)
 
-           return writes.hasOwnProperty(id) && writes[id].hasOwnProperty(p) ||
 
-                  reads.hasOwnProperty(id)  && reads[id].hasOwnProperty(p)  ||
 
-                  parentWorld.hasOwn(r, p)
 
-         },
 
-         has: function(r, p) {
 
-           return this.hasOwn(r, p) ||
 
-                  r !== Object.prototype && this.has(r === null || r === undefined ? Object.prototype : r.parent, p)
 
-         },
 
-         props: function(r, ps) {
 
-           var id = getTag(r)
 
-           if (writes.hasOwnProperty(id))
 
-             for (var p in writes[id])
 
-               if (writes[id].hasOwnProperty(p))
 
-                 ps[p] = true
 
-           if (reads.hasOwnProperty(id))
 
-             for (var p in reads[id])
 
-               if (reads[id].hasOwnProperty(p))
 
-                 ps[p] = true
 
-           if (r !== Object.prototype)
 
-             this.props(r === null || r === undefined ? Object.prototype : r.parent, ps)
 
-           parentWorld.props(r, ps)
 
-           return ps
 
-         },
 
-         _get: function(r, p) {
 
-           var id = getTag(r)
 
-           if (DEBUG) console.log("? child world looking up " + id + "." + p)
 
-           if      (writes.hasOwnProperty(id) && writes[id].hasOwnProperty(p))
 
-             return writes[id][p]
 
-           else if (reads.hasOwnProperty(id)  && reads[id].hasOwnProperty(p))
 
-             return reads[id][p]
 
-           else
 
-             return parentWorld._get(r, p)
 
-         },
 
-         get: function(r, p) {
 
-           if (typeof r === "string" && (typeof p === "number" || p === "length"))
 
-             return r[p]
 
-           var id = getTag(r), ans = this._get(r, p)
 
-           if (!reads.hasOwnProperty(id)) {
 
-             reads[id] = {}
 
-             if (!reads[id].hasOwnProperty(p))
 
-               reads[id][p] = ans
 
-           }
 
-           return ans
 
-         },
 
-         set: function(r, p, v) {
 
-           if (typeof r === "string" && (typeof p === "number" || p === "length"))
 
-             throw "the indices and length of a string are immutable, and you tried to change them!"
 
-           var id = getTag(r)
 
-           if (DEBUG) console.log("! child world assigning to " + id + "." + p)
 
-           if (!writes.hasOwnProperty(id))
 
-             writes[id] = {}
 
-           writes[id][p] = v
 
-           return v
 
-         },
 
-         commit: function() {
 
-           // serializability check
 
-           for (var id in reads) {
 
-             if (!reads.hasOwnProperty(id))
 
-               continue
 
-             for (var p in reads[id]) {
 
-               if (!reads[id].hasOwnProperty(p))
 
-                 continue
 
-               else if (reads[id][p] !== parentWorld._get(getRef(id), p))
 
-                 throw "commit failed"
 
-             }
 
-           }
 
-           // propagation of side effects
 
-           for (var id in writes) {
 
-             if (!writes.hasOwnProperty(id))
 
-               continue
 
-             for (var p in writes[id]) {
 
-               if (!writes[id].hasOwnProperty(p))
 
-                 continue
 
-               if (!parentWorld.writes.hasOwnProperty(id))
 
-                 parentWorld.writes[id] = {}
 
-               if (DEBUG) console.log("committing " + id + "." + p)
 
-               parentWorld.writes[id][p] = writes[id][p]
 
-             }
 
-           }
 
-           writes = {}
 
-           reads  = {}
 
-         },
 
-         sprout: parentWorld.sprout
 
-       }
 
-     }
 
-   }
 
- })()
 
- worldStack = [thisWorld]
 
- // Lexical scopes
 
- GlobalScope = function() { }
 
- GlobalScope.prototype = {
 
-   parent:    Object.prototype,
 
-   hasOwn:    function(n)    { return thisWorld.hasOwn(this, n)  },
 
-   has:       function(n)    { return thisWorld.has(this, n)     },
 
-   get:       function(n)    { return thisWorld.get(this, n)     },
 
-   set:       function(n, v) { return thisWorld.set(this, n, v)  },
 
-   decl:      function(n, v) { return baseWorld.set(this, n, v)  },
 
-   makeChild: function()     { return new ActivationRecord(this) }
 
- }
 
- ActivationRecord = function(parent) { this.parent = parent }
 
- ActivationRecord.prototype = new GlobalScope()
 
- ActivationRecord.prototype.get = function(n)    { return thisWorld.has(this, n) ?
 
-                                                            thisWorld.get(this, n) :
 
-                                                            this.parent.get(n)          }
 
- ActivationRecord.prototype.set = function(n, v) { return thisWorld.has(this, n) ?
 
-                                                            thisWorld.set(this, n, v) :
 
-                                                            this.parent.set(n, v)       }
 
- thisScope = new GlobalScope()
 
- // Sends
 
- send = function(sel, recv, args) {
 
-   //alert("doing a send, sel=" + sel + ", recv=" + recv + ", args=" + args)
 
-   return thisWorld.get(recv, sel).apply(recv, args)
 
- }
 
- // New
 
- Function.prototype.worldsNew = function() {
 
-   var r = {parent: thisWorld.get(this, "prototype")}
 
-   this.apply(r, arguments)
 
-   return r
 
- }
 
- // instanceof
 
- instanceOf = function(x, C) {
 
-   var p = x.parent, Cp = thisWorld.get(C, "prototype")
 
-   while (p != undefined) {
 
-     if (p == Cp)
 
-       return true
 
-     p = p.parent
 
-   }
 
-   return false
 
- }
 
- // Some globals, etc.
 
- wObject  = function() { }
 
- thisScope.decl("Object",  wObject)
 
- thisWorld.set(wObject, "prototype", Object.prototype)
 
- thisWorld.set(Object.prototype, "hasOwn", function(p) { return thisWorld.has(this, p) })
 
- thisWorld.set(Object.prototype, "toString", function() { return "" + this })
 
- thisWorld.set(worldProto, "sprout",   function() { return this.sprout()                   })
 
- thisWorld.set(worldProto, "commit",   function() { return this.commit()                   })
 
- thisWorld.set(worldProto, "toString", function() { return "[World " + this.getTag() + "]" })
 
- wWorld    = function() { }; thisScope.decl("World",    wWorld);    thisWorld.set(wWorld,    "prototype", worldProto)
 
- wBoolean  = function() { }; thisScope.decl("Boolean",  wBoolean);  thisWorld.set(wBoolean,  "prototype", {parent: Object.prototype})
 
- wNumber   = function() { }; thisScope.decl("Number",   wNumber);   thisWorld.set(wNumber,   "prototype", {parent: Object.prototype})
 
- wString   = function() { }; thisScope.decl("String",   wString);   thisWorld.set(wString,   "prototype", {parent: Object.prototype})
 
- wArray    = function() { }; thisScope.decl("Array",    wArray);    thisWorld.set(wArray,    "prototype", {parent: Object.prototype})
 
- wFunction = function() { }; thisScope.decl("Function", wFunction); thisWorld.set(wFunction, "prototype", {parent: Object.prototype})
 
- Boolean.prototype.parent   = thisWorld.get(wBoolean,   "prototype")
 
- Number.prototype.parent    = thisWorld.get(wNumber,    "prototype")
 
- String.prototype.parent    = thisWorld.get(wString,    "prototype")
 
- Function.prototype.parent  = thisWorld.get(wFunction,  "prototype")
 
- // Don't need to do this for Array because Worlds/JS arrays are not JS arrays
 
- thisWorld.set(wString, "fromCharCode", function(x) { return String.fromCharCode(x) })
 
- thisWorld.set(String.prototype.parent, "charCodeAt", function(x) { return this.charCodeAt(x) })
 
- thisWorld.set(Function.prototype.parent, "apply", function(recv, args) {
 
-   var jsArgs
 
-   if (args && thisWorld.get(args, "length") > 0) {
 
-     jsArgs = []
 
-     for (var idx = 0; idx < thisWorld.get(args, "length"); idx++)
 
-       jsArgs.push(thisWorld.get(args, idx))
 
-   }
 
-   return this.apply(recv, jsArgs)
 
- })
 
- thisWorld.set(Function.prototype.parent, "call", function(recv) {
 
-   var jsArgs = []
 
-   for (var idx = 1; idx < arguments.length; idx++)
 
-     jsArgs.push(arguments[idx])
 
-   return this.apply(recv, jsArgs)
 
- })
 
- thisScope.decl("null",      null)
 
- thisScope.decl("undefined", undefined)
 
- thisScope.decl("true",      true)
 
- thisScope.decl("false",     false)
 
- thisScope.decl("jsEval",  function(s) { return eval(thisWorld.get(s, "toString").call(s))    })
 
- thisScope.decl("print",   function(s) { print(thisWorld.get(s, "toString").call(s))          })
 
- thisScope.decl("alert",   function(s) { alert(thisWorld.get(s, "toString").call(s))          })
 
- thisScope.decl("prompt",  function(s) { return prompt(thisWorld.get(s, "toString").call(s))  })
 
- thisScope.decl("confirm", function(s) { return confirm(thisWorld.get(s, "toString").call(s)) })
 
- thisScope.decl("parseInt",   function(s) { return parseInt(s)   })
 
- thisScope.decl("parseFloat", function(s) { return parseFloat(s) })
 
- WorldsConsole = {}
 
- thisScope.decl("console", WorldsConsole)
 
- thisWorld.set(WorldsConsole, "log", function(s) { Transcript.show(thisWorld.get(s, "toString").apply(s)) })
 
- Array.prototype.toWJSArray = function() {
 
-   var r = wArray.worldsNew()
 
-   for (var idx = 0; idx < this.length; idx++)
 
-     thisWorld.set(r, idx, this[idx])
 
-   thisWorld.set(r, "length", this.length)
 
-   return r
 
- }
 
- Object.prototype.toWJSObject = function() {
 
-   var r = wObject.worldsNew()
 
-   for (var p in this)
 
-     if (this.hasOwnProperty(p))
 
-       thisWorld.set(r, p, this[p])
 
-   return r
 
- }
 
 
  |