amber/js/boot.js in resin-0.3.0 vs amber/js/boot.js in resin-0.3.1

- old
+ new

@@ -31,11 +31,11 @@ | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ==================================================================== */ -/* Make that console is defined */ +/* Make sure that console is defined */ if (typeof console === "undefined") { this.console = { log: function() {}, warn: function() {}, @@ -45,24 +45,47 @@ }; } /* Smalltalk constructors definition */ -function SmalltalkObject(){} -function SmalltalkBehavior(){} -function SmalltalkClass(){} -function SmalltalkPackage(){} +function SmalltalkObject(){}; +function SmalltalkBehavior(){}; +function SmalltalkClass(){}; +function SmalltalkPackage(){}; function SmalltalkMetaclass(){ this.meta = true; -} -function SmalltalkMethod(){} -function SmalltalkNil(){} +}; +function SmalltalkMethod(){}; +function SmalltalkNil(){}; function SmalltalkSymbol(string){ this.value = string; -} +}; +function SmalltalkOrganizer() { + this.elements = []; +}; + +SmalltalkOrganizer.prototype.addElement = function(el) { + if(typeof el === 'undefined' || el === nil) { + return false; + } + if(this.elements.indexOf(el) == -1) { + this.elements.push(el); + } +}; + +SmalltalkOrganizer.prototype.removeElement = function(el) { + for(var i=0; i<this.elements.length; i++) { + if(this.elements[i] == el) { + this.elements.splice(i, 1); + break; + } + } +}; + + function Smalltalk(){ var st = this; /* This is the current call context object. While it is publicly available, @@ -106,10 +129,11 @@ /* Smalltalk package creation. To add a Package, use smalltalk.addPackage() */ function pkg(spec) { var that = new SmalltalkPackage(); that.pkgName = spec.pkgName; + that.organization = new SmalltalkOrganizer(); that.properties = spec.properties || {}; return that; }; /* Smalltalk class creation. A class is an instance of an automatically @@ -129,11 +153,11 @@ } return that; } function metaclass() { - var meta = setupClass(new SmalltalkMetaclass(), {}); + var meta = setupClass(new SmalltalkMetaclass(), {}) meta.instanceClass = new meta.fn; return meta; } function setupClass(that, spec) { @@ -141,10 +165,11 @@ that.iVarNames = spec.iVarNames || []; Object.defineProperty(that, "toString", { value: function() { return 'Smalltalk ' + this.className; }, configurable: true // no writable - in par with ES6 methods }); + that.organization = new SmalltalkOrganizer(); that.pkg = spec.pkg; Object.defineProperties(that.fn.prototype, { methods: { value: {}, enumerable: false, configurable: true, writable: true }, inheritedMethods: { value: {}, enumerable: false, configurable: true, writable: true }, klass: { value: that, enumerable: false, configurable: true, writable: true } @@ -318,23 +343,53 @@ superclass: superclass, pkg: pkg, iVarNames: iVarNames }); } + + pkg.organization.addElement(st[className]); }; - /* Add a method to a class */ + st.removeClass = function(klass) { + klass.pkg.organization.removeElement(klass); + delete st[klass.className]; + }; + /* Add/remove a method to/from a class */ + st.addMethod = function(jsSelector, method, klass) { Object.defineProperty(klass.fn.prototype, jsSelector, { value: method.fn, configurable: true, writable: true }); klass.fn.prototype.methods[method.selector] = method; method.methodClass = klass; method.jsSelector = jsSelector; + + klass.organization.addElement(method.category); }; + st.removeMethod = function(method) { + var protocol = method.category; + var klass = method.methodClass; + var methods = klass.fn.prototype.methods; + + delete klass.fn.prototype[method.selector._asSelector()]; + delete methods[method.selector]; + + var selectors = Object.keys(methods); + var shouldDeleteProtocol = true; + for(var i= 0, l = selectors.length; i<l; i++) { + if(methods[selectors[i]].category === protocol) { + shouldDeleteProtocol = false; + break; + }; + }; + if(shouldDeleteProtocol) { + klass.organization.removeElement(protocol) + }; + }; + /* Handles unhandled errors during message sends */ st.send = function(receiver, selector, args, klass) { if(st.thisContext) { return withContextSend(receiver, selector, args, klass); @@ -512,11 +567,11 @@ return object; }; /* Boolean assertion */ st.assert = function(boolean) { - if(boolean.klass === smalltalk.Boolean) { + if ((undefined !== boolean) && (boolean.klass === smalltalk.Boolean)) { return boolean; } else { smalltalk.NonBooleanReceiver._new()._object_(boolean)._signal(); } } @@ -526,16 +581,10 @@ this.receiver = receiver; this.selector = selector; this.method = method; this.temps = temps || {}; this.homeContext = home; - - this.resume = function() { - //Brutally set the receiver as thisContext, then re-enter the function - smalltalk.thisContext = this; - return this.method.apply(receiver, temps); - }; }; SmalltalkMethodContext.prototype.copy = function() { var home = this.homeContext; if(home) {home = home.copy()} @@ -546,10 +595,16 @@ this.temps, home ); }; +SmalltalkMethodContext.prototype.resume = function() { + //Brutally set the receiver as thisContext, then re-enter the function + smalltalk.thisContext = this; + return this.method.apply(receiver, temps); +}; + /* Global Smalltalk objects. */ var nil = new SmalltalkNil(); var smalltalk = new Smalltalk(); @@ -568,9 +623,10 @@ smalltalk.wrapClassName("Package", "Kernel", SmalltalkPackage, smalltalk.Object); smalltalk.wrapClassName("Behavior", "Kernel", SmalltalkBehavior, smalltalk.Object); smalltalk.wrapClassName("Class", "Kernel", SmalltalkClass, smalltalk.Behavior); smalltalk.wrapClassName("Metaclass", "Kernel", SmalltalkMetaclass, smalltalk.Behavior); smalltalk.wrapClassName("CompiledMethod", "Kernel", SmalltalkMethod, smalltalk.Object); +smalltalk.wrapClassName("Organizer", "Kernel-Objects", SmalltalkOrganizer, smalltalk.Object); smalltalk.Object.klass.superclass = smalltalk.Class; smalltalk.wrapClassName("Number", "Kernel", Number, smalltalk.Object); smalltalk.wrapClassName("BlockClosure", "Kernel", Function, smalltalk.Object);