Browse Source

Trait method changes are propagated.

Herbert Vojčík 7 years ago
parent
commit
44f21f037e
2 changed files with 58 additions and 0 deletions
  1. 49 0
      support/kernel-fundamentals.js
  2. 9 0
      support/kernel-language.js

+ 49 - 0
support/kernel-fundamentals.js

@@ -425,6 +425,55 @@ define(['./compatibility'], function () {
         }
 
         this.updateMethod = updateMethod;
+
+        function aliasesOfSelector (selector, traitAliases) {
+            if (!traitAliases) return [selector];
+            var result = Object.keys(traitAliases).filter(function (aliasSelector) {
+                return traitAliases[aliasSelector] === selector
+            });
+            if (!traitAliases[selector]) result.push(selector);
+            return result;
+        }
+
+        function applyTraitMethodAddition (selector, method, traitTransformation, obj) {
+            var changes = aliasesOfSelector(selector, traitTransformation.aliases);
+            changes.forEach(function (aliasSelector) {
+                obj[aliasSelector] = aliased(aliasSelector, method);
+            });
+            var traitExclusions = traitTransformation.exclusions;
+            if (traitExclusions && traitExclusions.indexOf(selector) !== -1) {
+                delete obj[selector];
+            }
+            return changes;
+        }
+
+        function applyTraitMethodDeletion (selector, traitTransformation, obj) {
+            var changes = aliasesOfSelector(selector, traitTransformation.aliases);
+            changes.forEach(function (aliasSelector) {
+                delete obj[aliasSelector];
+            });
+            return changes;
+        }
+
+        function traitMethodChanged (selector, method, trait, behaviorBody) {
+            var traitComposition = behaviorBody.traitComposition,
+                chain = behaviorBody.localMethods,
+                changes = [];
+            for (var i = traitComposition.length - 1; i >= 0; --i) {
+                chain = Object.getPrototypeOf(chain);
+                var traitTransformation = traitComposition[i];
+                if (traitTransformation.trait !== trait) continue;
+                changes.push.apply(changes, method ?
+                    applyTraitMethodAddition(selector, method, traitTransformation, chain) :
+                    applyTraitMethodDeletion(selector, traitTransformation, chain));
+            }
+            // assert(chain === null);
+            changes.forEach(function (each) {
+                updateMethod(each, behaviorBody);
+            });
+        }
+
+        this.traitMethodChanged = traitMethodChanged;
     }
 
     function ArraySetBrik (brikz, st) {

+ 9 - 0
support/kernel-language.js

@@ -64,6 +64,7 @@ define(['./compatibility'], function () {
         var coreFns = brikz.root.coreFns;
         var SmalltalkBehaviorBody = brikz.behaviors.BehaviorBody;
         var setupMethods = brikz.composition.setupMethods;
+        var traitMethodChanged = brikz.composition.traitMethodChanged;
         var buildBehaviorBody = brikz.behaviors.buildBehaviorBody;
         var addElement = brikz.arraySet.addElement;
         var removeElement = brikz.arraySet.removeElement;
@@ -85,9 +86,17 @@ define(['./compatibility'], function () {
             if (st._traitRemoved) st._traitRemoved(this);
         });
         defineMethod(SmalltalkTrait, "methodAdded", function (method) {
+            var self = this;
+            this.traitUsers.forEach(function (each) {
+                traitMethodChanged(method.selector, method, self, each);
+            });
             if (st._traitMethodAdded) st._traitMethodAdded(method, this);
         });
         defineMethod(SmalltalkTrait, "methodRemoved", function (method) {
+            var self = this;
+            this.traitUsers.forEach(function (each) {
+                traitMethodChanged(method.selector, null, self, each);
+            });
             if (st._traitMethodRemoved) st._traitMethodRemoved(method, this);
         });
         defineMethod(SmalltalkTrait, "addUser", function (behaviorBody) {