Преглед на файлове

Niladic jsOverride: works in interpreter.

Plus small fix to interpreter supersend.
Herby Vojčík преди 4 години
родител
ревизия
37473d1701
променени са 7 файла, в които са добавени 175 реда и са изтрити 22 реда
  1. 1 0
      lang/API-CHANGES.txt
  2. 96 16
      lang/src/Compiler-Interpreter.js
  3. 32 6
      lang/src/Compiler-Interpreter.st
  4. 8 0
      lang/src/Compiler-Tests.js
  5. 10 0
      lang/src/Compiler-Tests.st
  6. 24 0
      lang/src/Kernel-Classes.js
  7. 4 0
      lang/src/Kernel-Classes.st

+ 1 - 0
lang/API-CHANGES.txt

@@ -11,6 +11,7 @@
   + beJavaScriptSubclassOf:
   + beJavaScriptSubclassOf:
   + javaScriptConstructor
   + javaScriptConstructor
   + javaScriptConstructor:
   + javaScriptConstructor:
+  + superPrototype
 + BlockClosure >>
 + BlockClosure >>
   + tryIfTrue:catch:
   + tryIfTrue:catch:
 + ProtoObject >>
 + ProtoObject >>

+ 96 - 16
lang/src/Compiler-Interpreter.js

@@ -2829,30 +2829,66 @@ $globals.ASTInterpreter);
 
 
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
-selector: "sendMessage:to:superSend:",
+selector: "sendJavaScript:superMessage:to:",
 protocol: "private",
 protocol: "private",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aMessage", "anObject", "aBoolean"],
-source: "sendMessage: aMessage to: anObject superSend: aBoolean\x0a\x09| method |\x0a\x09\x0a\x09aBoolean ifFalse: [ ^ aMessage sendTo: anObject ].\x0a\x09anObject class superclass ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].\x0a\x09\x0a\x09method := (self context method methodClass superclass lookupSelector: aMessage selector)\x0a\x09\x09ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].\x0a\x09\x09\x0a\x09^ method sendTo: anObject arguments: aMessage arguments",
+args: ["aString", "aMessage", "anObject"],
+source: "sendJavaScript: aString superMessage: aMessage to: anObject\x0a\x09| methodBlock parent |\x0a\x09\x0a\x09parent := self context method methodClass superPrototype.\x0a\x09parent ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].\x0a\x09\x0a\x09methodBlock := (parent at: aString)\x0a\x09\x09ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].\x0a\x09\x09\x0a\x09^ methodBlock applyTo: anObject arguments: aMessage arguments",
 referencedClasses: [],
 referencedClasses: [],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["ifFalse:", "sendTo:", "ifNil:", "superclass", "class", "messageNotUnderstood:receiver:", "lookupSelector:", "methodClass", "method", "context", "selector", "sendTo:arguments:", "arguments"]
-}, function ($methodClass){ return function (aMessage,anObject,aBoolean){
+messageSends: ["superPrototype", "methodClass", "method", "context", "ifNil:", "messageNotUnderstood:receiver:", "at:", "applyTo:arguments:", "arguments"]
+}, function ($methodClass){ return function (aString,aMessage,anObject){
 var self=this,$self=this;
 var self=this,$self=this;
-var method;
+var methodBlock,parent;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 var $1,$2;
 var $1,$2;
-if(!$core.assert(aBoolean)){
-return $recv(aMessage)._sendTo_(anObject);
-}
-$1=[$recv($recv(anObject)._class())._superclass()
+parent=$recv($recv($recv($self._context())._method())._methodClass())._superPrototype();
+$1=parent;
+if($1 == null || $1.a$nil){
+return [$self._messageNotUnderstood_receiver_(aMessage,anObject)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx1.sendIdx["superclass"]=1
+,$ctx1.sendIdx["messageNotUnderstood:receiver:"]=1
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 ][0];
 ][0];
+} else {
+$1;
+}
+$2=$recv(parent)._at_(aString);
+if($2 == null || $2.a$nil){
+return $self._messageNotUnderstood_receiver_(aMessage,anObject);
+} else {
+methodBlock=$2;
+}
+return $recv(methodBlock)._applyTo_arguments_(anObject,$recv(aMessage)._arguments());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"sendJavaScript:superMessage:to:",{aString:aString,aMessage:aMessage,anObject:anObject,methodBlock:methodBlock,parent:parent})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.ASTInterpreter);
+
+$core.addMethod(
+$core.method({
+selector: "sendSuperMessage:to:",
+protocol: "private",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aMessage", "anObject"],
+source: "sendSuperMessage: aMessage to: anObject\x0a\x09| method parent |\x0a\x09\x0a\x09parent := self context method methodClass superclass.\x0a\x09parent ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].\x0a\x09\x0a\x09method := (parent lookupSelector: aMessage selector)\x0a\x09\x09ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].\x0a\x09\x09\x0a\x09^ method sendTo: anObject arguments: aMessage arguments",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["superclass", "methodClass", "method", "context", "ifNil:", "messageNotUnderstood:receiver:", "lookupSelector:", "selector", "sendTo:arguments:", "arguments"]
+}, function ($methodClass){ return function (aMessage,anObject){
+var self=this,$self=this;
+var method,parent;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1,$2;
+parent=$recv($recv($recv($self._context())._method())._methodClass())._superclass();
+$1=parent;
 if($1 == null || $1.a$nil){
 if($1 == null || $1.a$nil){
 return [$self._messageNotUnderstood_receiver_(aMessage,anObject)
 return [$self._messageNotUnderstood_receiver_(aMessage,anObject)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -2862,7 +2898,7 @@ return [$self._messageNotUnderstood_receiver_(aMessage,anObject)
 } else {
 } else {
 $1;
 $1;
 }
 }
-$2=$recv($recv($recv($recv($self._context())._method())._methodClass())._superclass())._lookupSelector_($recv(aMessage)._selector());
+$2=$recv(parent)._lookupSelector_($recv(aMessage)._selector());
 if($2 == null || $2.a$nil){
 if($2 == null || $2.a$nil){
 return $self._messageNotUnderstood_receiver_(aMessage,anObject);
 return $self._messageNotUnderstood_receiver_(aMessage,anObject);
 } else {
 } else {
@@ -2870,7 +2906,7 @@ method=$2;
 }
 }
 return $recv(method)._sendTo_arguments_(anObject,$recv(aMessage)._arguments());
 return $recv(method)._sendTo_arguments_(anObject,$recv(aMessage)._arguments());
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"sendMessage:to:superSend:",{aMessage:aMessage,anObject:anObject,aBoolean:aBoolean,method:method})});
+}, function($ctx1) {$ctx1.fill(self,"sendSuperMessage:to:",{aMessage:aMessage,anObject:anObject,method:method,parent:parent})});
 //>>excludeEnd("ctx");
 //>>excludeEnd("ctx");
 }; }),
 }; }),
 $globals.ASTInterpreter);
 $globals.ASTInterpreter);
@@ -3311,11 +3347,11 @@ selector: "visitSendNode:",
 protocol: "visiting",
 protocol: "visiting",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aNode"],
 args: ["aNode"],
-source: "visitSendNode: aNode\x0a\x09| receiver args message result |\x0a\x09\x0a\x09args := aNode arguments collect: [ :each | self pop ].\x0a\x09receiver := self peek.\x0a\x09\x0a\x09message := self\x0a\x09\x09messageFromSendNode: aNode\x0a\x09\x09arguments: args reversed.\x0a\x09\x0a\x09result := self sendMessage: message to: receiver superSend: aNode superSend.\x0a\x09\x0a\x09\x22For cascade sends, push the reciever if the send is not the last one\x22\x0a\x09aNode isSideEffect ifFalse: [ self pop; push: result ]",
+source: "visitSendNode: aNode\x0a\x09| receiver args message result |\x0a\x09\x0a\x09args := aNode arguments collect: [ :each | self pop ].\x0a\x09receiver := self peek.\x0a\x09\x0a\x09message := self\x0a\x09\x09messageFromSendNode: aNode\x0a\x09\x09arguments: args reversed.\x0a\x09\x0a\x09result := aNode superSend\x0a\x09\x09ifFalse: [ message sendTo: receiver ]\x0a\x09\x09ifTrue: [ aNode receiver binding isJavaScriptSuper\x0a\x09\x09\x09ifFalse: [ self sendSuperMessage: message to: receiver ]\x0a\x09\x09\x09ifTrue: [ self sendJavaScript: aNode javaScriptSelector superMessage: message to: receiver ] ].\x0a\x09\x0a\x09\x22For cascade sends, push the reciever if the send is not the last one\x22\x0a\x09aNode isSideEffect ifFalse: [ self pop; push: result ]",
 referencedClasses: [],
 referencedClasses: [],
 //>>excludeEnd("ide");
 //>>excludeEnd("ide");
 pragmas: [],
 pragmas: [],
-messageSends: ["collect:", "arguments", "pop", "peek", "messageFromSendNode:arguments:", "reversed", "sendMessage:to:superSend:", "superSend", "ifFalse:", "isSideEffect", "push:"]
+messageSends: ["collect:", "arguments", "pop", "peek", "messageFromSendNode:arguments:", "reversed", "ifFalse:ifTrue:", "superSend", "sendTo:", "isJavaScriptSuper", "binding", "receiver", "sendSuperMessage:to:", "sendJavaScript:superMessage:to:", "javaScriptSelector", "ifFalse:", "isSideEffect", "push:"]
 }, function ($methodClass){ return function (aNode){
 }, function ($methodClass){ return function (aNode){
 var self=this,$self=this;
 var self=this,$self=this;
 var receiver,args,message,result;
 var receiver,args,message,result;
@@ -3337,7 +3373,15 @@ return [$self._pop()
 }));
 }));
 receiver=$self._peek();
 receiver=$self._peek();
 message=$self._messageFromSendNode_arguments_(aNode,$recv(args)._reversed());
 message=$self._messageFromSendNode_arguments_(aNode,$recv(args)._reversed());
-result=$self._sendMessage_to_superSend_(message,receiver,$recv(aNode)._superSend());
+if($core.assert($recv(aNode)._superSend())){
+if($core.assert($recv($recv($recv(aNode)._receiver())._binding())._isJavaScriptSuper())){
+result=$self._sendJavaScript_superMessage_to_($recv(aNode)._javaScriptSelector(),message,receiver);
+} else {
+result=$self._sendSuperMessage_to_(message,receiver);
+}
+} else {
+result=$recv(message)._sendTo_(receiver);
+}
 if(!$core.assert($recv(aNode)._isSideEffect())){
 if(!$core.assert($recv(aNode)._isSideEffect())){
 $self._pop();
 $self._pop();
 $self._push_(result);
 $self._push_(result);
@@ -3972,6 +4016,24 @@ return true;
 }; }),
 }; }),
 $globals.JSStatementNode);
 $globals.JSStatementNode);
 
 
+$core.addMethod(
+$core.method({
+selector: "isJavaScriptSuper",
+protocol: "*Compiler-Interpreter",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "isJavaScriptSuper\x0a\x09^ true",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: []
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+return true;
+
+}; }),
+$globals.JavaScriptSuperVar);
+
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
 selector: "inContext:",
 selector: "inContext:",
@@ -4099,6 +4161,24 @@ return $recv(aContext)._localAt_("self");
 }; }),
 }; }),
 $globals.SuperVar);
 $globals.SuperVar);
 
 
+$core.addMethod(
+$core.method({
+selector: "isJavaScriptSuper",
+protocol: "*Compiler-Interpreter",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "isJavaScriptSuper\x0a\x09^ false",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: []
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+return false;
+
+}; }),
+$globals.SuperVar);
+
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
 selector: "inContext:put:",
 selector: "inContext:put:",

+ 32 - 6
lang/src/Compiler-Interpreter.st

@@ -736,13 +736,25 @@ messageNotUnderstood: aMessage receiver: anObject
 		signal
 		signal
 !
 !
 
 
-sendMessage: aMessage to: anObject superSend: aBoolean
-	| method |
+sendJavaScript: aString superMessage: aMessage to: anObject
+	| methodBlock parent |
 	
 	
-	aBoolean ifFalse: [ ^ aMessage sendTo: anObject ].
-	anObject class superclass ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
+	parent := self context method methodClass superPrototype.
+	parent ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
 	
 	
-	method := (self context method methodClass superclass lookupSelector: aMessage selector)
+	methodBlock := (parent at: aString)
+		ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
+		
+	^ methodBlock applyTo: anObject arguments: aMessage arguments
+!
+
+sendSuperMessage: aMessage to: anObject
+	| method parent |
+	
+	parent := self context method methodClass superclass.
+	parent ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
+	
+	method := (parent lookupSelector: aMessage selector)
 		ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
 		ifNil: [ ^ self messageNotUnderstood: aMessage receiver: anObject ].
 		
 		
 	^ method sendTo: anObject arguments: aMessage arguments
 	^ method sendTo: anObject arguments: aMessage arguments
@@ -872,7 +884,11 @@ visitSendNode: aNode
 		messageFromSendNode: aNode
 		messageFromSendNode: aNode
 		arguments: args reversed.
 		arguments: args reversed.
 	
 	
-	result := self sendMessage: message to: receiver superSend: aNode superSend.
+	result := aNode superSend
+		ifFalse: [ message sendTo: receiver ]
+		ifTrue: [ aNode receiver binding isJavaScriptSuper
+			ifFalse: [ self sendSuperMessage: message to: receiver ]
+			ifTrue: [ self sendJavaScript: aNode javaScriptSelector superMessage: message to: receiver ] ].
 	
 	
 	"For cascade sends, push the reciever if the send is not the last one"
 	"For cascade sends, push the reciever if the send is not the last one"
 	aNode isSideEffect ifFalse: [ self pop; push: result ]
 	aNode isSideEffect ifFalse: [ self pop; push: result ]
@@ -1057,6 +1073,12 @@ isSteppingNode
 	^ true
 	^ true
 ! !
 ! !
 
 
+!JavaScriptSuperVar methodsFor: '*Compiler-Interpreter'!
+
+isJavaScriptSuper
+	^ true
+! !
+
 !PseudoVar methodsFor: '*Compiler-Interpreter'!
 !PseudoVar methodsFor: '*Compiler-Interpreter'!
 
 
 inContext: aContext
 inContext: aContext
@@ -1085,6 +1107,10 @@ isSteppingNode
 
 
 inContext: aContext
 inContext: aContext
 	^ aContext localAt: 'self'
 	^ aContext localAt: 'self'
+!
+
+isJavaScriptSuper
+	^ false
 ! !
 ! !
 
 
 !TempVar methodsFor: '*Compiler-Interpreter'!
 !TempVar methodsFor: '*Compiler-Interpreter'!

+ 8 - 0
lang/src/Compiler-Tests.js

@@ -2021,9 +2021,15 @@ return $recv([$self._name()
 $globals.AbstractJavaScriptGatewayTest.a$cls);
 $globals.AbstractJavaScriptGatewayTest.a$cls);
 
 
 
 
+$core.addClass("DebuggedJSGTest", $globals.AbstractJavaScriptGatewayTest, [], "Compiler-Tests");
+
+
 $core.addClass("InlinedJSGTest", $globals.AbstractJavaScriptGatewayTest, [], "Compiler-Tests");
 $core.addClass("InlinedJSGTest", $globals.AbstractJavaScriptGatewayTest, [], "Compiler-Tests");
 
 
 
 
+$core.addClass("InterpretedJSGTest", $globals.AbstractJavaScriptGatewayTest, [], "Compiler-Tests");
+
+
 $core.addClass("PlainJSGTest", $globals.AbstractJavaScriptGatewayTest, [], "Compiler-Tests");
 $core.addClass("PlainJSGTest", $globals.AbstractJavaScriptGatewayTest, [], "Compiler-Tests");
 
 
 
 
@@ -4181,5 +4187,7 @@ $core.setTraitComposition([{trait: $globals.TASTParsingTest}], $globals.ASTPosit
 $core.setTraitComposition([{trait: $globals.TASTCompilingTest}], $globals.AbstractCodeGeneratorInstallTest);
 $core.setTraitComposition([{trait: $globals.TASTCompilingTest}], $globals.AbstractCodeGeneratorInstallTest);
 $core.setTraitComposition([{trait: $globals.TCTNonInlined}], $globals.CodeGeneratorInstallTest);
 $core.setTraitComposition([{trait: $globals.TCTNonInlined}], $globals.CodeGeneratorInstallTest);
 $core.setTraitComposition([{trait: $globals.TCTInlined}], $globals.InliningCodeGeneratorInstallTest);
 $core.setTraitComposition([{trait: $globals.TCTInlined}], $globals.InliningCodeGeneratorInstallTest);
+$core.setTraitComposition([{trait: $globals.TCTNonInlined}, {trait: $globals.TCTInterpreted}], $globals.InterpretedJSGTest);
+$core.setTraitComposition([{trait: $globals.TCTNonInlined}, {trait: $globals.TCTDebugged}], $globals.DebuggedJSGTest);
 
 
 });
 });

+ 10 - 0
lang/src/Compiler-Tests.st

@@ -518,10 +518,18 @@ isAbstract
 	^ self name = AbstractJavaScriptGatewayTest name
 	^ self name = AbstractJavaScriptGatewayTest name
 ! !
 ! !
 
 
+AbstractJavaScriptGatewayTest subclass: #DebuggedJSGTest
+	slots: {}
+	package: 'Compiler-Tests'!
+
 AbstractJavaScriptGatewayTest subclass: #InlinedJSGTest
 AbstractJavaScriptGatewayTest subclass: #InlinedJSGTest
 	slots: {}
 	slots: {}
 	package: 'Compiler-Tests'!
 	package: 'Compiler-Tests'!
 
 
+AbstractJavaScriptGatewayTest subclass: #InterpretedJSGTest
+	slots: {}
+	package: 'Compiler-Tests'!
+
 AbstractJavaScriptGatewayTest subclass: #PlainJSGTest
 AbstractJavaScriptGatewayTest subclass: #PlainJSGTest
 	slots: {}
 	slots: {}
 	package: 'Compiler-Tests'!
 	package: 'Compiler-Tests'!
@@ -1125,5 +1133,7 @@ ASTPositionTest setTraitComposition: {TASTParsingTest} asTraitComposition!
 AbstractCodeGeneratorInstallTest setTraitComposition: {TASTCompilingTest} asTraitComposition!
 AbstractCodeGeneratorInstallTest setTraitComposition: {TASTCompilingTest} asTraitComposition!
 CodeGeneratorInstallTest setTraitComposition: {TCTNonInlined} asTraitComposition!
 CodeGeneratorInstallTest setTraitComposition: {TCTNonInlined} asTraitComposition!
 InliningCodeGeneratorInstallTest setTraitComposition: {TCTInlined} asTraitComposition!
 InliningCodeGeneratorInstallTest setTraitComposition: {TCTInlined} asTraitComposition!
+InterpretedJSGTest setTraitComposition: {TCTNonInlined. TCTInterpreted} asTraitComposition!
+DebuggedJSGTest setTraitComposition: {TCTNonInlined. TCTDebugged} asTraitComposition!
 ! !
 ! !
 
 

+ 24 - 0
lang/src/Kernel-Classes.js

@@ -692,6 +692,30 @@ return self;
 }; }),
 }; }),
 $globals.Behavior);
 $globals.Behavior);
 
 
+$core.addMethod(
+$core.method({
+selector: "superPrototype",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "superPrototype\x0a\x09<inlineJS: 'return Object.getPrototypeOf($self.fn.prototype)'>",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [["inlineJS:", ["return Object.getPrototypeOf($self.fn.prototype)"]]],
+messageSends: []
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return Object.getPrototypeOf($self.fn.prototype);
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"superPrototype",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.Behavior);
+
 $core.addMethod(
 $core.addMethod(
 $core.method({
 $core.method({
 selector: "superclass",
 selector: "superclass",

+ 4 - 0
lang/src/Kernel-Classes.st

@@ -117,6 +117,10 @@ subclasses
 	self subclassResponsibility
 	self subclassResponsibility
 !
 !
 
 
+superPrototype
+	<inlineJS: 'return Object.getPrototypeOf($self.fn.prototype)'>
+!
+
 superclass
 superclass
 	^ superclass
 	^ superclass
 !
 !