Browse Source

Direct implementation of #beJavaScriptSubclassOf:.

Herby Vojčík 4 years ago
parent
commit
1a99c804ab
4 changed files with 51 additions and 48 deletions
  1. 2 2
      lang/API-CHANGES.txt
  2. 5 3
      lang/base/kernel-runtime.js
  3. 31 31
      lang/src/Kernel-Classes.js
  4. 13 12
      lang/src/Kernel-Classes.st

+ 2 - 2
lang/API-CHANGES.txt

@@ -6,8 +6,8 @@
   + beJavaScriptSubclassOf:
   + javaScriptConstructor
   + javaScriptConstructor:
-+ ClassBuilder >>
-  + javaScriptSubclassOf:
++ amber/boot api >>
+  + detachClass(klass)
 
 
 0.23.2:

+ 5 - 3
lang/base/kernel-runtime.js

@@ -68,13 +68,16 @@ define(function () {
 
         var detachedRootClasses = [];
 
-        function markClassDetachedRoot (klass) {
+        function detachClass (klass) {
             klass.detachedRoot = true;
             detachedRootClasses = traitsOrClasses.filter(function (klass) {
                 return klass.detachedRoot;
             });
+            initClass(klass);
         }
 
+        st.detachClass = detachClass;
+
         emit.selectorsAdded = function (newSelectors) {
             installNewSelectors(newSelectors, detachedRootClasses);
         };
@@ -150,10 +153,9 @@ define(function () {
         /* Manually set the constructor of an existing Smalltalk klass, making it a detached root class. */
 
         st.setClassConstructor = this.setClassConstructor = function (klass, constructor) {
-            markClassDetachedRoot(klass);
             klass.fn = constructor;
+            detachClass(klass);
             installIvarCompat(klass);
-            initClass(klass);
             klass.subclasses.forEach(reprotoFn(constructor));
         };
 

+ 31 - 31
lang/src/Kernel-Classes.js

@@ -252,17 +252,18 @@ selector: "beJavaScriptSubclassOf:",
 protocol: "accessing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aJavaScriptFunction"],
-source: "beJavaScriptSubclassOf: aJavaScriptFunction\x0a\x09\x22Set the JS constructor to subclass of aJavaScriptFunction.\x0a\x09That way I stay part of (simulated) Smalltalk hierarchy,\x0a\x09but my instances will physically be instanceof aJavaScriptFunction.\x22\x0a\x09\x0a\x09self javaScriptConstructor:\x0a\x09\x09(ClassBuilder new javaScriptSubclassOf: aJavaScriptFunction)",
-referencedClasses: ["ClassBuilder"],
+source: "beJavaScriptSubclassOf: aJavaScriptFunction\x0a\x09\x22Reparent the JS constructor's prototype to aJavaScriptFunction's one,\x0a\x09plus bookkeeping. That way I stay part of (simulated) Smalltalk hierarchy,\x0a\x09but my instances will physically be instanceof aJavaScriptFunction.\x22\x0a\x0a\x09self makeJavaScriptConstructorSubclassOf: aJavaScriptFunction.\x0a\x09Smalltalk core detachClass: self",
+referencedClasses: ["Smalltalk"],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["javaScriptConstructor:", "javaScriptSubclassOf:", "new"]
+messageSends: ["makeJavaScriptConstructorSubclassOf:", "detachClass:", "core"]
 }, function ($methodClass){ return function (aJavaScriptFunction){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-$self._javaScriptConstructor_($recv($recv($globals.ClassBuilder)._new())._javaScriptSubclassOf_(aJavaScriptFunction));
+$self._makeJavaScriptConstructorSubclassOf_(aJavaScriptFunction);
+$recv($recv($globals.Smalltalk)._core())._detachClass_(self);
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"beJavaScriptSubclassOf:",{aJavaScriptFunction:aJavaScriptFunction})});
@@ -570,6 +571,32 @@ catch(e) {if(e===$early)return e[0]; throw e}
 }; }),
 $globals.Behavior);
 
+$core.addMethod(
+$core.method({
+selector: "makeJavaScriptConstructorSubclassOf:",
+protocol: "private",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["javaScriptClass"],
+source: "makeJavaScriptConstructorSubclassOf: javaScriptClass\x0a\x09<inlineJS: '\x0a\x09\x09Object.setPrototypeOf($self.fn.prototype, javaScriptClass.prototype);\x0a\x09'>",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [["inlineJS:", ["\x0a\x09\x09Object.setPrototypeOf($self.fn.prototype, javaScriptClass.prototype);\x0a\x09"]]],
+messageSends: []
+}, function ($methodClass){ return function (javaScriptClass){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+
+		Object.setPrototypeOf($self.fn.prototype, javaScriptClass.prototype);
+	;
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"makeJavaScriptConstructorSubclassOf:",{javaScriptClass:javaScriptClass})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.Behavior);
+
 $core.addMethod(
 $core.method({
 selector: "new",
@@ -1758,33 +1785,6 @@ return self;
 }; }),
 $globals.ClassBuilder);
 
-$core.addMethod(
-$core.method({
-selector: "javaScriptSubclassOf:",
-protocol: "class definition",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["javaScriptClass"],
-source: "javaScriptSubclassOf: javaScriptClass\x0a\x09<inlineJS: '\x0a\x09\x09var subclass = function () {};\x0a\x09\x09subclass.prototype = Object.create(javaScriptClass.prototype);\x0a\x09\x09return subclass;'>",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [["inlineJS:", ["\x0a\x09\x09var subclass = function () {};\x0a\x09\x09subclass.prototype = Object.create(javaScriptClass.prototype);\x0a\x09\x09return subclass;"]]],
-messageSends: []
-}, function ($methodClass){ return function (javaScriptClass){
-var self=this,$self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-
-		var subclass = function () {};
-		subclass.prototype = Object.create(javaScriptClass.prototype);
-		return subclass;;
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"javaScriptSubclassOf:",{javaScriptClass:javaScriptClass})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.ClassBuilder);
-
 $core.addMethod(
 $core.method({
 selector: "migrateClass:superclass:",

+ 13 - 12
lang/src/Kernel-Classes.st

@@ -53,12 +53,12 @@ basicOrganization: aClassOrganizer
 !
 
 beJavaScriptSubclassOf: aJavaScriptFunction
-	"Set the JS constructor to subclass of aJavaScriptFunction.
-	That way I stay part of (simulated) Smalltalk hierarchy,
+	"Reparent the JS constructor's prototype to aJavaScriptFunction's one,
+	plus bookkeeping. That way I stay part of (simulated) Smalltalk hierarchy,
 	but my instances will physically be instanceof aJavaScriptFunction."
-	
-	self javaScriptConstructor:
-		(ClassBuilder new javaScriptSubclassOf: aJavaScriptFunction)
+
+	self makeJavaScriptConstructorSubclassOf: aJavaScriptFunction.
+	Smalltalk core detachClass: self
 !
 
 instanceVariableNames
@@ -148,6 +148,14 @@ new
 	^ self basicNew initialize
 ! !
 
+!Behavior methodsFor: 'private'!
+
+makeJavaScriptConstructorSubclassOf: javaScriptClass
+	<inlineJS: '
+		Object.setPrototypeOf($self.fn.prototype, javaScriptClass.prototype);
+	'>
+! !
+
 !Behavior methodsFor: 'testing'!
 
 canUnderstand: aSelector
@@ -374,13 +382,6 @@ class: aClass slots: aCollection
 			yourself)
 !
 
-javaScriptSubclassOf: javaScriptClass
-	<inlineJS: '
-		var subclass = function () {};
-		subclass.prototype = Object.create(javaScriptClass.prototype);
-		return subclass;'>
-!
-
 superclass: aClass subclass: className
 	^ self superclass: aClass subclass: className slots: #() package: nil
 !