Browse Source

Compiler: Explictly mark "side-effect" sends.

Side-effect sends are those who ditch the result
and keep the reciever for a next send;
eg. all but last send in a cascade.
Herby Vojčík 4 years ago
parent
commit
e80743e00f

+ 3 - 0
lang/API-CHANGES.txt

@@ -40,6 +40,9 @@
 + ScopeVar >>
   + asReceiver
   + isExternallyKnownVar
++ SendNode >>
+  + beSideEffect
+  + isSideEffect
 + SequenceableCollection >>
   + copyWithFirst:
 + SmalltalkImage >>

+ 49 - 37
lang/src/Compiler-AST.js

@@ -39,24 +39,6 @@ return $recv($self._positionEnd()).__gt_eq(aPoint);
 }; }),
 $globals.ASTNode);
 
-$core.addMethod(
-$core.method({
-selector: "isCascadeNode",
-protocol: "testing",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isCascadeNode\x0a\x09^ false",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: []
-}, function ($methodClass){ return function (){
-var self=this,$self=this;
-return false;
-
-}; }),
-$globals.ASTNode);
-
 $core.addMethod(
 $core.method({
 selector: "isImmutable",
@@ -868,24 +850,6 @@ return $recv(aVisitor)._visitCascadeNode_(self);
 }; }),
 $globals.CascadeNode);
 
-$core.addMethod(
-$core.method({
-selector: "isCascadeNode",
-protocol: "testing",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isCascadeNode\x0a\x09^ true",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: []
-}, function ($methodClass){ return function (){
-var self=this,$self=this;
-return true;
-
-}; }),
-$globals.CascadeNode);
-
 $core.addMethod(
 $core.method({
 selector: "receiver",
@@ -1564,7 +1528,7 @@ $globals.ReturnNode);
 
 
 
-$core.addClass("SendNode", $globals.ASTNode, ["selector", "arguments", "receiver", "index"], "Compiler-AST");
+$core.addClass("SendNode", $globals.ASTNode, ["selector", "arguments", "receiver", "index", "isSideEffect"], "Compiler-AST");
 //>>excludeStart("ide", pragmas.excludeIdeData);
 $globals.SendNode.comment="I represent an message send node.";
 //>>excludeEnd("ide");
@@ -1640,6 +1604,25 @@ return self;
 }; }),
 $globals.SendNode);
 
+$core.addMethod(
+$core.method({
+selector: "beSideEffect",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "beSideEffect\x0a\x09isSideEffect := true",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: []
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+$self.isSideEffect=true;
+return self;
+
+}; }),
+$globals.SendNode);
+
 $core.addMethod(
 $core.method({
 selector: "dagChildren",
@@ -1733,6 +1716,35 @@ return true;
 }; }),
 $globals.SendNode);
 
+$core.addMethod(
+$core.method({
+selector: "isSideEffect",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "isSideEffect\x0a\x09^ isSideEffect ifNil: [ false ]",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["ifNil:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1,$receiver;
+$1=$self.isSideEffect;
+if(($receiver = $1) == null || $receiver.a$nil){
+return false;
+} else {
+return $1;
+}
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"isSideEffect",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.SendNode);
+
 $core.addMethod(
 $core.method({
 selector: "navigationLink",

+ 9 - 11
lang/src/Compiler-AST.st

@@ -100,10 +100,6 @@ inPosition: aPoint
 		self positionEnd >= aPoint ])
 !
 
-isCascadeNode
-	^ false
-!
-
 isImmutable
 	^ false
 !
@@ -214,12 +210,6 @@ receiver: aNode
 	receiver := aNode
 ! !
 
-!CascadeNode methodsFor: 'testing'!
-
-isCascadeNode
-	^ true
-! !
-
 !CascadeNode methodsFor: 'visiting'!
 
 acceptDagVisitor: aVisitor
@@ -391,7 +381,7 @@ acceptDagVisitor: aVisitor
 ! !
 
 ASTNode subclass: #SendNode
-	slots: {#selector. #arguments. #receiver. #index}
+	slots: {#selector. #arguments. #receiver. #index. #isSideEffect}
 	package: 'Compiler-AST'!
 !SendNode commentStamp!
 I represent an message send node.!
@@ -406,6 +396,10 @@ arguments: aCollection
 	arguments := aCollection
 !
 
+beSideEffect
+	isSideEffect := true
+!
+
 dagChildren
 	self receiver ifNil: [ ^ self arguments copy ].
 	
@@ -420,6 +414,10 @@ index: anInteger
 	index := anInteger
 !
 
+isSideEffect
+	^ isSideEffect ifNil: [ false ]
+!
+
 navigationLink
 	^ self selector
 !

+ 3 - 57
lang/src/Compiler-Interpreter.js

@@ -3335,11 +3335,11 @@ selector: "visitSendNode:",
 protocol: "visiting",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 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\x09(aNode isCascadeSendNode and: [ aNode isLastChild not ])\x0a\x09\x09ifFalse: [ 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 := 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 ]",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["collect:", "arguments", "pop", "peek", "messageFromSendNode:arguments:", "reversed", "sendMessage:to:superSend:", "superSend", "ifFalse:", "and:", "isCascadeSendNode", "not", "isLastChild", "push:"]
+messageSends: ["collect:", "arguments", "pop", "peek", "messageFromSendNode:arguments:", "reversed", "sendMessage:to:superSend:", "superSend", "ifFalse:", "isSideEffect", "push:"]
 }, function ($methodClass){ return function (aNode){
 var self=this,$self=this;
 var receiver,args,message,result;
@@ -3363,15 +3363,7 @@ return [$self._pop()
 receiver=$self._peek();
 message=$self._messageFromSendNode_arguments_(aNode,$recv(args)._reversed());
 result=$self._sendMessage_to_superSend_(message,receiver,$recv(aNode)._superSend());
-$1=$recv($recv(aNode)._isCascadeSendNode())._and_((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $recv($recv(aNode)._isLastChild())._not();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)});
-//>>excludeEnd("ctx");
-}));
+$1=$recv(aNode)._isSideEffect();
 if(!$core.assert($1)){
 $self._pop();
 $self._push_(result);
@@ -3789,29 +3781,6 @@ $globals.ASTPCNodeVisitor);
 
 $core.setTraitComposition([{trait: $globals.TMethodContext}], $globals.AIContext);
 
-$core.addMethod(
-$core.method({
-selector: "isLastChild",
-protocol: "*Compiler-Interpreter",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isLastChild\x0a\x09^ self parent dagChildren last = self",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["=", "last", "dagChildren", "parent"]
-}, function ($methodClass){ return function (){
-var self=this,$self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-return $recv($recv($recv($self._parent())._dagChildren())._last()).__eq(self);
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"isLastChild",{})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.ASTNode);
-
 $core.addMethod(
 $core.method({
 selector: "isSteppingNode",
@@ -3968,29 +3937,6 @@ return true;
 }; }),
 $globals.JSStatementNode);
 
-$core.addMethod(
-$core.method({
-selector: "isCascadeSendNode",
-protocol: "*Compiler-Interpreter",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isCascadeSendNode\x0a\x09^ self parent isCascadeNode",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["isCascadeNode", "parent"]
-}, function ($methodClass){ return function (){
-var self=this,$self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-return $recv($self._parent())._isCascadeNode();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"isCascadeSendNode",{})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.SendNode);
-
 $core.addMethod(
 $core.method({
 selector: "isSteppingNode",

+ 1 - 10
lang/src/Compiler-Interpreter.st

@@ -878,8 +878,7 @@ visitSendNode: aNode
 	result := self sendMessage: message to: receiver superSend: aNode superSend.
 	
 	"For cascade sends, push the reciever if the send is not the last one"
-	(aNode isCascadeSendNode and: [ aNode isLastChild not ])
-		ifFalse: [ self pop; push: result ]
+	aNode isSideEffect ifFalse: [ self pop; push: result ]
 !
 
 visitValueNode: aNode
@@ -975,10 +974,6 @@ AIContext setTraitComposition: {TMethodContext} asTraitComposition!
 
 !ASTNode methodsFor: '*Compiler-Interpreter'!
 
-isLastChild
-	^ self parent dagChildren last = self
-!
-
 isSteppingNode
 	^ false
 !
@@ -1031,10 +1026,6 @@ isSteppingNode
 
 !SendNode methodsFor: '*Compiler-Interpreter'!
 
-isCascadeSendNode
-	^ self parent isCascadeNode
-!
-
 isSteppingNode
 	^ true
 ! !

+ 16 - 3
lang/src/Compiler-Semantic.js

@@ -2332,17 +2332,30 @@ selector: "visitCascadeNode:",
 protocol: "visiting",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aNode"],
-source: "visitCascadeNode: aNode\x0a\x09aNode receiver: aNode dagChildren first receiver.\x0a\x09super visitCascadeNode: aNode",
+source: "visitCascadeNode: aNode\x0a\x09aNode receiver: aNode dagChildren first receiver.\x0a\x09aNode dagChildren allButLast do: [ :each | each beSideEffect ].\x0a\x09super visitCascadeNode: aNode",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["receiver:", "receiver", "first", "dagChildren", "visitCascadeNode:"]
+messageSends: ["receiver:", "receiver", "first", "dagChildren", "do:", "allButLast", "beSideEffect", "visitCascadeNode:"]
 }, function ($methodClass){ return function (aNode){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-$recv(aNode)._receiver_($recv($recv($recv(aNode)._dagChildren())._first())._receiver());
+$recv(aNode)._receiver_($recv($recv([$recv(aNode)._dagChildren()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["dagChildren"]=1
+//>>excludeEnd("ctx");
+][0])._first())._receiver());
+$recv($recv($recv(aNode)._dagChildren())._allButLast())._do_((function(each){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv(each)._beSideEffect();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({each:each},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
 [(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,

+ 1 - 0
lang/src/Compiler-Semantic.st

@@ -584,6 +584,7 @@ visitBlockNode: aNode
 
 visitCascadeNode: aNode
 	aNode receiver: aNode dagChildren first receiver.
+	aNode dagChildren allButLast do: [ :each | each beSideEffect ].
 	super visitCascadeNode: aNode
 !