|
@@ -100,6 +100,7 @@ function inherits(child, parent) {
|
|
|
constructor: { value: child,
|
|
|
enumerable: false, configurable: true, writable: true }
|
|
|
});
|
|
|
+ return child;
|
|
|
}
|
|
|
|
|
|
inherits(SmalltalkBehavior, SmalltalkObject);
|
|
@@ -156,6 +157,7 @@ function Smalltalk() {
|
|
|
var dnu = {
|
|
|
methods: [],
|
|
|
selectors: [],
|
|
|
+ checker: Object.create(null),
|
|
|
|
|
|
get: function (string) {
|
|
|
var index = this.selectors.indexOf(string);
|
|
@@ -164,11 +166,16 @@ function Smalltalk() {
|
|
|
}
|
|
|
this.selectors.push(string);
|
|
|
var selector = st.selector(string);
|
|
|
+ this.checker[selector] = true;
|
|
|
var method = {jsSelector: selector, fn: this.createHandler(selector)};
|
|
|
this.methods.push(method);
|
|
|
return method;
|
|
|
},
|
|
|
|
|
|
+ isSelector: function (selector) {
|
|
|
+ return this.checker[selector];
|
|
|
+ },
|
|
|
+
|
|
|
|
|
|
|
|
|
createHandler: function (selector) {
|
|
@@ -218,7 +225,7 @@ function Smalltalk() {
|
|
|
spec = spec || {};
|
|
|
var meta = metaclass(spec);
|
|
|
var that = meta.instanceClass;
|
|
|
- that.fn = spec.fn || function() {};
|
|
|
+ that.fn = spec.fn || inherits(function () {}, spec.superclass.fn);
|
|
|
setupClass(that, spec);
|
|
|
|
|
|
that.className = spec.className;
|
|
@@ -234,10 +241,7 @@ function Smalltalk() {
|
|
|
function metaclass(spec) {
|
|
|
spec = spec || {};
|
|
|
var that = new SmalltalkMetaclass();
|
|
|
- inherits(
|
|
|
- that.fn = function() {},
|
|
|
- spec.superclass ? spec.superclass.klass.fn : SmalltalkClass
|
|
|
- );
|
|
|
+ that.fn = inherits(function () {}, spec.superclass ? spec.superclass.klass.fn : SmalltalkClass);
|
|
|
that.instanceClass = new that.fn();
|
|
|
setupClass(that);
|
|
|
return that;
|
|
@@ -291,10 +295,7 @@ function Smalltalk() {
|
|
|
|
|
|
st.initClass = function(klass) {
|
|
|
if(klass.wrapped) {
|
|
|
- klass.inheritedMethods = {};
|
|
|
copySuperclass(klass);
|
|
|
- } else {
|
|
|
- installSuperclass(klass);
|
|
|
}
|
|
|
|
|
|
if(klass === st.Object || klass.wrapped) {
|
|
@@ -309,25 +310,31 @@ function Smalltalk() {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- function installSuperclass(klass) {
|
|
|
-
|
|
|
- if(klass.fn.prototype._yourself) { return; }
|
|
|
-
|
|
|
- if(klass.superclass && klass.superclass !== nil) {
|
|
|
- inherits(klass.fn, klass.superclass.fn);
|
|
|
- wireKlass(klass);
|
|
|
- reinstallMethods(klass);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
function copySuperclass(klass, superclass) {
|
|
|
+ var inheritedMethods = {};
|
|
|
+ deinstallAllMethods(klass);
|
|
|
for (superclass = superclass || klass.superclass;
|
|
|
superclass && superclass !== nil;
|
|
|
superclass = superclass.superclass) {
|
|
|
for (var keys = Object.keys(superclass.methods), i = 0; i < keys.length; i++) {
|
|
|
- inheritMethodIfAbsent(superclass.methods[keys[i]], klass);
|
|
|
+ inheritMethodIfAbsent(superclass.methods[keys[i]]);
|
|
|
}
|
|
|
}
|
|
|
+ reinstallMethods(klass);
|
|
|
+
|
|
|
+ function inheritMethodIfAbsent(method) {
|
|
|
+ var selector = method.selector;
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if(klass.methods.hasOwnProperty(selector) || inheritedMethods.hasOwnProperty(selector)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ installMethod(method, klass);
|
|
|
+ inheritedMethods[method.selector] = true;
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
function installMethod(method, klass) {
|
|
@@ -337,15 +344,14 @@ function Smalltalk() {
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- function inheritMethodIfAbsent(method, klass) {
|
|
|
- var selector = method.selector;
|
|
|
-
|
|
|
- if(klass.methods.hasOwnProperty(selector) || klass.inheritedMethods.hasOwnProperty(selector)) {
|
|
|
- return;
|
|
|
+ function deinstallAllMethods(klass) {
|
|
|
+ var proto = klass.fn.prototype;
|
|
|
+ for(var keys = Object.getOwnPropertyNames(proto), i=0; i<keys.length; i++) {
|
|
|
+ var key = keys[i];
|
|
|
+ if (dnu.isSelector(key)) {
|
|
|
+ proto[key] = null;
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- installMethod(method, klass);
|
|
|
- klass.inheritedMethods[method.selector] = true;
|
|
|
}
|
|
|
|
|
|
function reinstallMethods(klass) {
|
|
@@ -375,6 +381,20 @@ function Smalltalk() {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ function propagateMethodChange(klass) {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ if (initialized) {
|
|
|
+ st.allSubclasses(klass).forEach(function (subclass) {
|
|
|
+ st.initClass(subclass);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
|
|
|
|
|
@@ -541,15 +561,7 @@ function Smalltalk() {
|
|
|
|
|
|
klass.organization.elements.addElement(method.category);
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- if(initialized) {
|
|
|
- st.allSubclasses(klass).forEach(function(subclass) {
|
|
|
- st.initClass(subclass);
|
|
|
- });
|
|
|
- }
|
|
|
+ propagateMethodChange(klass);
|
|
|
|
|
|
for(var i=0; i<method.messageSends.length; i++) {
|
|
|
var dnuHandler = dnu.get(method.messageSends[i]);
|
|
@@ -561,16 +573,19 @@ function Smalltalk() {
|
|
|
|
|
|
st.removeMethod = function(method, klass) {
|
|
|
if (klass !== method.methodClass) {
|
|
|
- throw new Error(
|
|
|
- "Refusing to remove method "
|
|
|
- + method.methodClass.className+">>"+method.selector
|
|
|
- + " from different class "
|
|
|
- + klass.className);
|
|
|
- }
|
|
|
+ throw new Error(
|
|
|
+ "Refusing to remove method "
|
|
|
+ + method.methodClass.className+">>"+method.selector
|
|
|
+ + " from different class "
|
|
|
+ + klass.className);
|
|
|
+ }
|
|
|
|
|
|
delete klass.fn.prototype[st.selector(method.selector)];
|
|
|
delete klass.methods[method.selector];
|
|
|
|
|
|
+ st.initClass(klass);
|
|
|
+ propagateMethodChange(klass);
|
|
|
+
|
|
|
|
|
|
|
|
|
};
|