Browse Source

In <jsOverride:args:>, args can be permutated.

Herby Vojčík 4 years ago
parent
commit
1d76f230e7

+ 38 - 1
lang/src/Compiler-AST.js

@@ -977,7 +977,7 @@ $globals.DynamicDictionaryNode);
 
 
 
-$core.addClass("SendNode", $globals.ExpressionNode, ["selector", "arguments", "receiver", "index", "javaScriptSelector", "isSideEffect"], "Compiler-AST");
+$core.addClass("SendNode", $globals.ExpressionNode, ["selector", "arguments", "receiver", "index", "javaScriptSelector", "argumentSwitcher", "isSideEffect"], "Compiler-AST");
 //>>excludeStart("ide", pragmas.excludeIdeData);
 $globals.SendNode.comment="I represent an message send node.";
 //>>excludeEnd("ide");
@@ -1004,6 +1004,43 @@ return $recv(aVisitor)._visitSendNode_(self);
 }; }),
 $globals.SendNode);
 
+$core.addMethod(
+$core.method({
+selector: "argumentSwitcher",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "argumentSwitcher\x0a\x09^ argumentSwitcher",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: []
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+return $self.argumentSwitcher;
+
+}; }),
+$globals.SendNode);
+
+$core.addMethod(
+$core.method({
+selector: "argumentSwitcher:",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aJSFunction"],
+source: "argumentSwitcher: aJSFunction\x0a\x09argumentSwitcher := aJSFunction",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: []
+}, function ($methodClass){ return function (aJSFunction){
+var self=this,$self=this;
+$self.argumentSwitcher=aJSFunction;
+return self;
+
+}; }),
+$globals.SendNode);
+
 $core.addMethod(
 $core.method({
 selector: "arguments",

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

@@ -256,13 +256,21 @@ acceptDagVisitor: aVisitor
 ! !
 
 ExpressionNode subclass: #SendNode
-	slots: {#selector. #arguments. #receiver. #index. #javaScriptSelector. #isSideEffect}
+	slots: {#selector. #arguments. #receiver. #index. #javaScriptSelector. #argumentSwitcher. #isSideEffect}
 	package: 'Compiler-AST'!
 !SendNode commentStamp!
 I represent an message send node.!
 
 !SendNode methodsFor: 'accessing'!
 
+argumentSwitcher
+	^ argumentSwitcher
+!
+
+argumentSwitcher: aJSFunction
+	argumentSwitcher := aJSFunction
+!
+
 arguments
 	^ arguments ifNil: [ arguments := #() ]
 !

+ 193 - 23
lang/src/Compiler-IR.js

@@ -863,11 +863,11 @@ selector: "visitSendNode:",
 protocol: "visiting",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aNode"],
-source: "visitSendNode: aNode\x0a\x09| send |\x0a\x09send := IRSend new.\x0a\x09send\x0a\x09\x09selector: aNode selector;\x0a\x09\x09javaScriptSelector: aNode javaScriptSelector;\x0a\x09\x09index: aNode index.\x0a\x09\x0a\x09(self aliasTemporally: aNode dagChildren) do: [ :each | send add: each ].\x0a\x0a\x09^ send",
+source: "visitSendNode: aNode\x0a\x09| send |\x0a\x09send := IRSend new.\x0a\x09send\x0a\x09\x09selector: aNode selector;\x0a\x09\x09javaScriptSelector: aNode javaScriptSelector;\x0a\x09\x09argumentSwitcher: aNode argumentSwitcher;\x0a\x09\x09index: aNode index.\x0a\x09\x0a\x09(self aliasTemporally: aNode dagChildren) do: [ :each | send add: each ].\x0a\x0a\x09^ send",
 referencedClasses: ["IRSend"],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["new", "selector:", "selector", "javaScriptSelector:", "javaScriptSelector", "index:", "index", "do:", "aliasTemporally:", "dagChildren", "add:"]
+messageSends: ["new", "selector:", "selector", "javaScriptSelector:", "javaScriptSelector", "argumentSwitcher:", "argumentSwitcher", "index:", "index", "do:", "aliasTemporally:", "dagChildren", "add:"]
 }, function ($methodClass){ return function (aNode){
 var self=this,$self=this;
 var send;
@@ -879,6 +879,7 @@ send=$recv($globals.IRSend)._new();
 $1=send;
 $recv($1)._selector_($recv(aNode)._selector());
 $recv($1)._javaScriptSelector_($recv(aNode)._javaScriptSelector());
+$recv($1)._argumentSwitcher_($recv(aNode)._argumentSwitcher());
 $recv($1)._index_($recv(aNode)._index());
 $recv($self._aliasTemporally_($recv(aNode)._dagChildren()))._do_((function(each){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -2659,7 +2660,7 @@ $globals.IRTempDeclaration);
 
 
 
-$core.addClass("IRSend", $globals.IRInstruction, ["selector", "javaScriptSelector", "index"], "Compiler-IR");
+$core.addClass("IRSend", $globals.IRInstruction, ["selector", "javaScriptSelector", "argumentSwitcher", "index"], "Compiler-IR");
 //>>excludeStart("ide", pragmas.excludeIdeData);
 $globals.IRSend.comment="I am a message send instruction.";
 //>>excludeEnd("ide");
@@ -2686,6 +2687,43 @@ return $recv(aVisitor)._visitIRSend_(self);
 }; }),
 $globals.IRSend);
 
+$core.addMethod(
+$core.method({
+selector: "argumentSwitcher",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "argumentSwitcher\x0a\x09^ argumentSwitcher",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: []
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+return $self.argumentSwitcher;
+
+}; }),
+$globals.IRSend);
+
+$core.addMethod(
+$core.method({
+selector: "argumentSwitcher:",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aJSFunction"],
+source: "argumentSwitcher: aJSFunction\x0a\x09argumentSwitcher := aJSFunction",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: []
+}, function ($methodClass){ return function (aJSFunction){
+var self=this,$self=this;
+$self.argumentSwitcher=aJSFunction;
+return self;
+
+}; }),
+$globals.IRSend);
+
 $core.addMethod(
 $core.method({
 selector: "arguments",
@@ -3365,41 +3403,84 @@ selector: "jsOverride:args:",
 protocol: "pragmas",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aString", "aCollection"],
-source: "jsOverride: aString args: aCollection\x0a\x09| argList |\x0a\x09self irMethod arguments = aCollection ifFalse: [\x0a\x09\x09CompilerError signal: 'Argument mismatch in <jsOverride:args:>.' ].\x0a\x09argList := ',' join: aCollection.\x0a\x09self irMethod attachments\x0a\x09\x09at: aString\x0a\x09\x09put: (NativeFunction\x0a\x09\x09\x09constructorNamed: #Function\x0a\x09\x09\x09value: argList\x0a\x09\x09\x09value: 'return this.', irMethod selector asJavaScriptMethodName, '(', argList, ')')",
+source: "jsOverride: aString args: aCollection\x0a\x09| myArgs |\x0a\x09myArgs := self irMethod arguments.\x0a\x09myArgs size = aCollection size ifFalse: [\x0a\x09\x09CompilerError signal: 'Should have ', self irMethod arguments size, ' args in <jsOverride:args:>.' ].\x0a\x09myArgs asSet = aCollection asSet ifFalse: [\x0a\x09\x09CompilerError signal: 'Argument mismatch in <jsOverride:args:>.' ].\x0a\x09self irMethod attachments\x0a\x09\x09at: aString\x0a\x09\x09put: (NativeFunction\x0a\x09\x09\x09constructorNamed: #Function\x0a\x09\x09\x09value: (',' join: aCollection)\x0a\x09\x09\x09value: 'return this.', irMethod selector asJavaScriptMethodName, '(', (',' join: myArgs), ')')",
 referencedClasses: ["CompilerError", "NativeFunction"],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["ifFalse:", "=", "arguments", "irMethod", "signal:", "join:", "at:put:", "attachments", "constructorNamed:value:value:", ",", "asJavaScriptMethodName", "selector"]
+messageSends: ["arguments", "irMethod", "ifFalse:", "=", "size", "signal:", ",", "asSet", "at:put:", "attachments", "constructorNamed:value:value:", "join:", "asJavaScriptMethodName", "selector"]
 }, function ($methodClass){ return function (aString,aCollection){
 var self=this,$self=this;
-var argList;
+var myArgs;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-if(!$core.assert($recv($recv([$self._irMethod()
+myArgs=[$recv([$self._irMethod()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 ,$ctx1.sendIdx["irMethod"]=1
 //>>excludeEnd("ctx");
-][0])._arguments()).__eq(aCollection))){
+][0])._arguments()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["arguments"]=1
+//>>excludeEnd("ctx");
+][0];
+if(!$core.assert([$recv([$recv(myArgs)._size()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["size"]=1
+//>>excludeEnd("ctx");
+][0]).__eq([$recv(aCollection)._size()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["size"]=2
+//>>excludeEnd("ctx");
+][0])
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["="]=1
+//>>excludeEnd("ctx");
+][0])){
+[$recv($globals.CompilerError)._signal_([$recv(["Should have ".__comma($recv($recv([$self._irMethod()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["irMethod"]=2
+//>>excludeEnd("ctx");
+][0])._arguments())._size())
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx[","]=2
+//>>excludeEnd("ctx");
+][0]).__comma(" args in <jsOverride:args:>.")
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx[","]=1
+//>>excludeEnd("ctx");
+][0])
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["signal:"]=1
+//>>excludeEnd("ctx");
+][0];
+}
+if(!$core.assert($recv([$recv(myArgs)._asSet()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["asSet"]=1
+//>>excludeEnd("ctx");
+][0]).__eq($recv(aCollection)._asSet()))){
 $recv($globals.CompilerError)._signal_("Argument mismatch in <jsOverride:args:>.");
 }
-argList=","._join_(aCollection);
-$recv($recv($self._irMethod())._attachments())._at_put_(aString,$recv($globals.NativeFunction)._constructorNamed_value_value_("Function",argList,[$recv([$recv([$recv("return this.".__comma($recv($recv($self.irMethod)._selector())._asJavaScriptMethodName())).__comma("(")
+$recv($recv($self._irMethod())._attachments())._at_put_(aString,$recv($globals.NativeFunction)._constructorNamed_value_value_("Function",[","._join_(aCollection)
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx1.sendIdx[","]=3
+,$ctx1.sendIdx["join:"]=1
 //>>excludeEnd("ctx");
-][0]).__comma(argList)
+][0],[$recv([$recv([$recv("return this.".__comma($recv($recv($self.irMethod)._selector())._asJavaScriptMethodName())).__comma("(")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx1.sendIdx[","]=2
+,$ctx1.sendIdx[","]=5
+//>>excludeEnd("ctx");
+][0]).__comma(","._join_(myArgs))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx[","]=4
 //>>excludeEnd("ctx");
 ][0]).__comma(")")
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx1.sendIdx[","]=1
+,$ctx1.sendIdx[","]=3
 //>>excludeEnd("ctx");
 ][0]));
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"jsOverride:args:",{aString:aString,aCollection:aCollection,argList:argList})});
+}, function($ctx1) {$ctx1.fill(self,"jsOverride:args:",{aString:aString,aCollection:aCollection,myArgs:myArgs})});
 //>>excludeEnd("ctx");
 }; }),
 $globals.IRLatePragmator);
@@ -4654,18 +4735,22 @@ selector: "visitSuperSend:",
 protocol: "visiting",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anIRSend"],
-source: "visitSuperSend: anIRSend\x0a\x09self stream\x0a\x09\x09nextPutAll: anIRSend receiver variable lookupAsJavaScriptSource, '.';\x0a\x09\x09nextPutAll: anIRSend javaScriptSelector, '.call'.\x0a\x09self\x0a\x09\x09visitInstructionList: {anIRSend receiver asReceiver}, anIRSend arguments\x0a\x09\x09enclosedBetween: '(' and: ')'",
+source: "visitSuperSend: anIRSend\x0a\x09self stream\x0a\x09\x09nextPutAll: anIRSend receiver variable lookupAsJavaScriptSource, '.';\x0a\x09\x09nextPutAll: anIRSend javaScriptSelector.\x0a\x09anIRSend arguments\x0a\x09\x09ifEmpty: [\x0a\x09\x09\x09self stream nextPutAll: '.call('.\x0a\x09\x09\x09self visitReceiver: anIRSend receiver.\x0a\x09\x09\x09self stream nextPutAll: ')' ]\x0a\x09\x09ifNotEmpty: [\x0a\x09\x09\x09anIRSend argumentSwitcher\x0a\x09\x09\x09\x09ifNil: [\x0a\x09\x09\x09\x09\x09self stream nextPutAll: '.call('.\x0a\x09\x09\x09\x09\x09self visitReceiver: anIRSend receiver.\x0a\x09\x09\x09\x09\x09self\x0a\x09\x09\x09\x09\x09\x09visitInstructionList: anIRSend arguments\x0a\x09\x09\x09\x09\x09\x09enclosedBetween: ',' and: ')' ]\x0a\x09\x09\x09\x09ifNotNil: [ :switcher |\x0a\x09\x09\x09\x09\x09self stream nextPutAll: '.apply('.\x0a\x09\x09\x09\x09\x09self visitReceiver: anIRSend receiver.\x0a\x09\x09\x09\x09\x09self\x0a\x09\x09\x09\x09\x09\x09visitInstructionList: anIRSend arguments\x0a\x09\x09\x09\x09\x09\x09enclosedBetween: ',(', switcher asJavaScriptSource, ')('\x0a\x09\x09\x09\x09\x09\x09and: '))' ] ]\x0a",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["nextPutAll:", "stream", ",", "lookupAsJavaScriptSource", "variable", "receiver", "javaScriptSelector", "visitInstructionList:enclosedBetween:and:", "asReceiver", "arguments"]
+messageSends: ["nextPutAll:", "stream", ",", "lookupAsJavaScriptSource", "variable", "receiver", "javaScriptSelector", "ifEmpty:ifNotEmpty:", "arguments", "visitReceiver:", "ifNil:ifNotNil:", "argumentSwitcher", "visitInstructionList:enclosedBetween:and:", "asJavaScriptSource"]
 }, function ($methodClass){ return function (anIRSend){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=$self._stream();
+var $1,$2;
+$1=[$self._stream()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["stream"]=1
+//>>excludeEnd("ctx");
+][0];
 [$recv($1)._nextPutAll_([$recv($recv($recv([$recv(anIRSend)._receiver()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 ,$ctx1.sendIdx["receiver"]=1
@@ -4679,12 +4764,97 @@ $1=$self._stream();
 ,$ctx1.sendIdx["nextPutAll:"]=1
 //>>excludeEnd("ctx");
 ][0];
-$recv($1)._nextPutAll_([$recv($recv(anIRSend)._javaScriptSelector()).__comma(".call")
+[$recv($1)._nextPutAll_($recv(anIRSend)._javaScriptSelector())
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-,$ctx1.sendIdx[","]=2
+,$ctx1.sendIdx["nextPutAll:"]=2
 //>>excludeEnd("ctx");
-][0]);
-$self._visitInstructionList_enclosedBetween_and_($recv([$recv($recv(anIRSend)._receiver())._asReceiver()]).__comma($recv(anIRSend)._arguments()),"(",")");
+][0];
+$recv([$recv(anIRSend)._arguments()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["arguments"]=1
+//>>excludeEnd("ctx");
+][0])._ifEmpty_ifNotEmpty_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+[$recv([$self._stream()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["stream"]=2
+//>>excludeEnd("ctx");
+][0])._nextPutAll_(".call(")
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["nextPutAll:"]=3
+//>>excludeEnd("ctx");
+][0];
+[$self._visitReceiver_([$recv(anIRSend)._receiver()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["receiver"]=2
+//>>excludeEnd("ctx");
+][0])
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["visitReceiver:"]=1
+//>>excludeEnd("ctx");
+][0];
+return [$recv([$self._stream()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["stream"]=3
+//>>excludeEnd("ctx");
+][0])._nextPutAll_(")")
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["nextPutAll:"]=4
+//>>excludeEnd("ctx");
+][0];
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}),(function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+$2=$recv(anIRSend)._argumentSwitcher();
+if($2 == null || $2.a$nil){
+[$recv([$self._stream()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["stream"]=4
+//>>excludeEnd("ctx");
+][0])._nextPutAll_(".call(")
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["nextPutAll:"]=5
+//>>excludeEnd("ctx");
+][0];
+[$self._visitReceiver_([$recv(anIRSend)._receiver()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["receiver"]=3
+//>>excludeEnd("ctx");
+][0])
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["visitReceiver:"]=2
+//>>excludeEnd("ctx");
+][0];
+return [$self._visitInstructionList_enclosedBetween_and_([$recv(anIRSend)._arguments()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["arguments"]=2
+//>>excludeEnd("ctx");
+][0],",",")")
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["visitInstructionList:enclosedBetween:and:"]=1
+//>>excludeEnd("ctx");
+][0];
+} else {
+var switcher;
+switcher=$2;
+$recv($self._stream())._nextPutAll_(".apply(");
+$self._visitReceiver_($recv(anIRSend)._receiver());
+return $self._visitInstructionList_enclosedBetween_and_($recv(anIRSend)._arguments(),[$recv(",(".__comma($recv(switcher)._asJavaScriptSource())).__comma(")(")
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx[","]=2
+//>>excludeEnd("ctx");
+][0],"))");
+}
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)});
+//>>excludeEnd("ctx");
+}));
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"visitSuperSend:",{anIRSend:anIRSend})});

+ 38 - 10
lang/src/Compiler-IR.st

@@ -219,6 +219,7 @@ visitSendNode: aNode
 	send
 		selector: aNode selector;
 		javaScriptSelector: aNode javaScriptSelector;
+		argumentSwitcher: aNode argumentSwitcher;
 		index: aNode index.
 	
 	(self aliasTemporally: aNode dagChildren) do: [ :each | send add: each ].
@@ -676,13 +677,21 @@ acceptDagVisitor: aVisitor
 ! !
 
 IRInstruction subclass: #IRSend
-	slots: {#selector. #javaScriptSelector. #index}
+	slots: {#selector. #javaScriptSelector. #argumentSwitcher. #index}
 	package: 'Compiler-IR'!
 !IRSend commentStamp!
 I am a message send instruction.!
 
 !IRSend methodsFor: 'accessing'!
 
+argumentSwitcher
+	^ argumentSwitcher
+!
+
+argumentSwitcher: aJSFunction
+	argumentSwitcher := aJSFunction
+!
+
 arguments
 	^ self dagChildren allButFirst
 !
@@ -882,16 +891,18 @@ jsOverride: aString
 !
 
 jsOverride: aString args: aCollection
-	| argList |
-	self irMethod arguments = aCollection ifFalse: [
+	| myArgs |
+	myArgs := self irMethod arguments.
+	myArgs size = aCollection size ifFalse: [
+		CompilerError signal: 'Should have ', self irMethod arguments size, ' args in <jsOverride:args:>.' ].
+	myArgs asSet = aCollection asSet ifFalse: [
 		CompilerError signal: 'Argument mismatch in <jsOverride:args:>.' ].
-	argList := ',' join: aCollection.
 	self irMethod attachments
 		at: aString
 		put: (NativeFunction
 			constructorNamed: #Function
-			value: argList
-			value: 'return this.', irMethod selector asJavaScriptMethodName, '(', argList, ')')
+			value: (',' join: aCollection)
+			value: 'return this.', irMethod selector asJavaScriptMethodName, '(', (',' join: myArgs), ')')
 ! !
 
 ParentFakingPathDagVisitor subclass: #IRVisitor
@@ -1135,10 +1146,27 @@ visitSend: anIRSend
 visitSuperSend: anIRSend
 	self stream
 		nextPutAll: anIRSend receiver variable lookupAsJavaScriptSource, '.';
-		nextPutAll: anIRSend javaScriptSelector, '.call'.
-	self
-		visitInstructionList: {anIRSend receiver asReceiver}, anIRSend arguments
-		enclosedBetween: '(' and: ')'
+		nextPutAll: anIRSend javaScriptSelector.
+	anIRSend arguments
+		ifEmpty: [
+			self stream nextPutAll: '.call('.
+			self visitReceiver: anIRSend receiver.
+			self stream nextPutAll: ')' ]
+		ifNotEmpty: [
+			anIRSend argumentSwitcher
+				ifNil: [
+					self stream nextPutAll: '.call('.
+					self visitReceiver: anIRSend receiver.
+					self
+						visitInstructionList: anIRSend arguments
+						enclosedBetween: ',' and: ')' ]
+				ifNotNil: [ :switcher |
+					self stream nextPutAll: '.apply('.
+					self visitReceiver: anIRSend receiver.
+					self
+						visitInstructionList: anIRSend arguments
+						enclosedBetween: ',(', switcher asJavaScriptSource, ')('
+						and: '))' ] ]
 ! !
 
 Object subclass: #JSStream

+ 141 - 12
lang/src/Compiler-Semantic.js

@@ -4,7 +4,81 @@ var $pkg = $core.addPackage("Compiler-Semantic");
 $pkg.innerEval = function (expr) { return eval(expr); };
 $pkg.transport = {"type":"amd","amdNamespace":"amber/core"};
 
-$core.addClass("JSSuperSendVisitor", $globals.NodeVisitor, ["selector", "property"], "Compiler-Semantic");
+$core.addClass("JSSuperSendVisitor", $globals.NodeVisitor, ["selector", "arguments", "property", "args"], "Compiler-Semantic");
+$core.addMethod(
+$core.method({
+selector: "args",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "args\x0a\x09^ args",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: []
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+return $self.args;
+
+}; }),
+$globals.JSSuperSendVisitor);
+
+$core.addMethod(
+$core.method({
+selector: "args:",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aCollection"],
+source: "args: aCollection\x0a\x09args := aCollection",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: []
+}, function ($methodClass){ return function (aCollection){
+var self=this,$self=this;
+$self.args=aCollection;
+return self;
+
+}; }),
+$globals.JSSuperSendVisitor);
+
+$core.addMethod(
+$core.method({
+selector: "arguments",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "arguments\x0a\x09^ arguments",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: []
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+return $self.arguments;
+
+}; }),
+$globals.JSSuperSendVisitor);
+
+$core.addMethod(
+$core.method({
+selector: "arguments:",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aCollection"],
+source: "arguments: aCollection\x0a\x09arguments := aCollection",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: []
+}, function ($methodClass){ return function (aCollection){
+var self=this,$self=this;
+$self.arguments=aCollection;
+return self;
+
+}; }),
+$globals.JSSuperSendVisitor);
+
 $core.addMethod(
 $core.method({
 selector: "property",
@@ -79,23 +153,55 @@ return self;
 }; }),
 $globals.JSSuperSendVisitor);
 
+$core.addMethod(
+$core.method({
+selector: "switcherFrom:to:",
+protocol: "accessing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aCollection", "anotherCollection"],
+source: "switcherFrom: aCollection to: anotherCollection\x0a\x09^ NativeFunction\x0a\x09\x09constructorNamed: #Function\x0a\x09\x09value: (',' join: aCollection)\x0a\x09\x09value: 'return [', (',' join: anotherCollection), ']'",
+referencedClasses: ["NativeFunction"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["constructorNamed:value:value:", "join:", ","]
+}, function ($methodClass){ return function (aCollection,anotherCollection){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $recv($globals.NativeFunction)._constructorNamed_value_value_("Function",[","._join_(aCollection)
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["join:"]=1
+//>>excludeEnd("ctx");
+][0],[$recv("return [".__comma(","._join_(anotherCollection))).__comma("]")
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx[","]=1
+//>>excludeEnd("ctx");
+][0]);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"switcherFrom:to:",{aCollection:aCollection,anotherCollection:anotherCollection})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.JSSuperSendVisitor);
+
 $core.addMethod(
 $core.method({
 selector: "visitMethodNode:",
 protocol: "accessing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aNode"],
-source: "visitMethodNode: aNode\x0a\x09self selector: aNode selector.\x0a\x09^ super visitMethodNode: aNode",
+source: "visitMethodNode: aNode\x0a\x09self selector: aNode selector.\x0a\x09self arguments: aNode arguments.\x0a\x09^ super visitMethodNode: aNode",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["selector:", "selector", "visitMethodNode:"]
+messageSends: ["selector:", "selector", "arguments:", "arguments", "visitMethodNode:"]
 }, function ($methodClass){ return function (aNode){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 $self._selector_($recv(aNode)._selector());
+$self._arguments_($recv(aNode)._arguments());
 return [(
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
@@ -117,25 +223,29 @@ selector: "visitSendNode:",
 protocol: "accessing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aNode"],
-source: "visitSendNode: aNode\x0a\x09| receiver |\x0a\x09receiver := aNode receiver.\x0a\x09receiver isSuper ifTrue: [\x0a\x09\x09aNode selector = self selector ifTrue: [\x0a\x09\x09\x09| old |\x0a\x09\x09\x09old := receiver binding.\x0a\x09\x09\x09receiver binding: (\x0a\x09\x09\x09\x09JavaScriptSuperVar new\x0a\x09\x09\x09\x09\x09scope: old scope;\x0a\x09\x09\x09\x09\x09name: old name;\x0a\x09\x09\x09\x09\x09yourself ).\x0a\x09\x09\x09aNode javaScriptSelector: self property ] ].\x0a\x09^ super visitSendNode: aNode",
+source: "visitSendNode: aNode\x0a\x09| receiver |\x0a\x09receiver := aNode receiver.\x0a\x09receiver isSuper ifTrue: [\x0a\x09\x09aNode selector = self selector ifTrue: [\x0a\x09\x09\x09| old |\x0a\x09\x09\x09old := receiver binding.\x0a\x09\x09\x09receiver binding: (\x0a\x09\x09\x09\x09JavaScriptSuperVar new\x0a\x09\x09\x09\x09\x09scope: old scope;\x0a\x09\x09\x09\x09\x09name: old name;\x0a\x09\x09\x09\x09\x09yourself ).\x0a\x09\x09\x09self args ifNotNil: [ :myArgs |\x0a\x09\x09\x09\x09myArgs = self arguments ifFalse: [\x0a\x09\x09\x09\x09\x09aNode argumentSwitcher:\x0a\x09\x09\x09\x09\x09\x09(self switcherFrom: self arguments to: myArgs) ] ].\x0a\x09\x09\x09aNode javaScriptSelector: self property ] ].\x0a\x09^ super visitSendNode: aNode",
 referencedClasses: ["JavaScriptSuperVar"],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["receiver", "ifTrue:", "isSuper", "=", "selector", "binding", "binding:", "scope:", "new", "scope", "name:", "name", "yourself", "javaScriptSelector:", "property", "visitSendNode:"]
+messageSends: ["receiver", "ifTrue:", "isSuper", "=", "selector", "binding", "binding:", "scope:", "new", "scope", "name:", "name", "yourself", "ifNotNil:", "args", "ifFalse:", "arguments", "argumentSwitcher:", "switcherFrom:to:", "javaScriptSelector:", "property", "visitSendNode:"]
 }, function ($methodClass){ return function (aNode){
 var self=this,$self=this;
 var receiver;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$2;
+var $1,$2,$3;
 receiver=$recv(aNode)._receiver();
 if($core.assert($recv(receiver)._isSuper())){
-if($core.assert($recv([$recv(aNode)._selector()
+if($core.assert([$recv([$recv(aNode)._selector()
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 ,$ctx1.sendIdx["selector"]=1
 //>>excludeEnd("ctx");
-][0]).__eq($self._selector()))){
+][0]).__eq($self._selector())
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["="]=1
+//>>excludeEnd("ctx");
+][0])){
 var old;
 old=$recv(receiver)._binding();
 $1=receiver;
@@ -143,6 +253,20 @@ $2=$recv($globals.JavaScriptSuperVar)._new();
 $recv($2)._scope_($recv(old)._scope());
 $recv($2)._name_($recv(old)._name());
 $recv($1)._binding_($recv($2)._yourself());
+$3=$self._args();
+if($3 == null || $3.a$nil){
+$3;
+} else {
+var myArgs;
+myArgs=$3;
+if(!$core.assert($recv(myArgs).__eq([$self._arguments()
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx1.sendIdx["arguments"]=1
+//>>excludeEnd("ctx");
+][0]))){
+$recv(aNode)._argumentSwitcher_($self._switcherFrom_to_($self._arguments(),myArgs));
+}
+}
 $recv(aNode)._javaScriptSelector_($self._property());
 }
 }
@@ -2940,17 +3064,22 @@ selector: "jsOverride:args:",
 protocol: "*Compiler-Semantic",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aString", "aCollection"],
-source: "jsOverride: aString args: aCollection\x0a\x09^ self jsOverride: aString",
-referencedClasses: [],
+source: "jsOverride: aString args: aCollection\x0a\x09(JSSuperSendVisitor new property: aString; args: aCollection; yourself)\x0a\x09\x09visit: self methodNode",
+referencedClasses: ["JSSuperSendVisitor"],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["jsOverride:"]
+messageSends: ["visit:", "property:", "new", "args:", "yourself", "methodNode"]
 }, function ($methodClass){ return function (aString,aCollection){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-return $self._jsOverride_(aString);
+var $1;
+$1=$recv($globals.JSSuperSendVisitor)._new();
+$recv($1)._property_(aString);
+$recv($1)._args_(aCollection);
+$recv($recv($1)._yourself())._visit_($self._methodNode());
+return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"jsOverride:args:",{aString:aString,aCollection:aCollection})});
 //>>excludeEnd("ctx");

+ 31 - 2
lang/src/Compiler-Semantic.st

@@ -1,10 +1,26 @@
 Smalltalk createPackage: 'Compiler-Semantic'!
 NodeVisitor subclass: #JSSuperSendVisitor
-	slots: {#selector. #property}
+	slots: {#selector. #arguments. #property. #args}
 	package: 'Compiler-Semantic'!
 
 !JSSuperSendVisitor methodsFor: 'accessing'!
 
+args
+	^ args
+!
+
+args: aCollection
+	args := aCollection
+!
+
+arguments
+	^ arguments
+!
+
+arguments: aCollection
+	arguments := aCollection
+!
+
 property
 	^ property
 !
@@ -21,8 +37,16 @@ selector: anObject
 	selector := anObject
 !
 
+switcherFrom: aCollection to: anotherCollection
+	^ NativeFunction
+		constructorNamed: #Function
+		value: (',' join: aCollection)
+		value: 'return [', (',' join: anotherCollection), ']'
+!
+
 visitMethodNode: aNode
 	self selector: aNode selector.
+	self arguments: aNode arguments.
 	^ super visitMethodNode: aNode
 !
 
@@ -38,6 +62,10 @@ visitSendNode: aNode
 					scope: old scope;
 					name: old name;
 					yourself ).
+			self args ifNotNil: [ :myArgs |
+				myArgs = self arguments ifFalse: [
+					aNode argumentSwitcher:
+						(self switcherFrom: self arguments to: myArgs) ] ].
 			aNode javaScriptSelector: self property ] ].
 	^ super visitSendNode: aNode
 ! !
@@ -754,6 +782,7 @@ jsOverride: aString
 !
 
 jsOverride: aString args: aCollection
-	^ self jsOverride: aString
+	(JSSuperSendVisitor new property: aString; args: aCollection; yourself)
+		visit: self methodNode
 ! !
 

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

@@ -1967,6 +1967,57 @@ return self;
 }; }),
 $globals.AbstractJavaScriptGatewayTest);
 
+$core.addMethod(
+$core.method({
+selector: "testDyadicSuperDifferentNamesPermutated",
+protocol: "tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testDyadicSuperDifferentNamesPermutated\x0a\x09theClass := ObjectMock subclass: #ObjectMock2 slots: #() package: 'Compiler-Tests'.\x0a\x09theClass beJavaScriptSubclassOf: self jsConstructor.\x0a\x09receiver := ObjectMock2 new foo: 'should be shadowed'; yourself.\x0a\x09self while: 'bar: anObject baz: anotherObject\x0a\x09\x09<jsOverride: #foo args: #(anotherObject anObject)>\x0a\x09\x09^ super bar: anObject baz: anotherObject' should: [\x0a\x09\x09self shouldnt: [ receiver bar: 3 baz: 4 ] raise: Error.\x0a\x09\x09self assert: (receiver bar: 4 baz: true) equals: 'true,4' ]",
+referencedClasses: ["ObjectMock", "ObjectMock2", "Error"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["subclass:slots:package:", "beJavaScriptSubclassOf:", "jsConstructor", "foo:", "new", "yourself", "while:should:", "shouldnt:raise:", "bar:baz:", "assert:equals:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1;
+$self.theClass=$recv($globals.ObjectMock)._subclass_slots_package_("ObjectMock2",[],"Compiler-Tests");
+$recv($self.theClass)._beJavaScriptSubclassOf_($self._jsConstructor());
+$1=$recv($globals.ObjectMock2)._new();
+$recv($1)._foo_("should be shadowed");
+$self.receiver=$recv($1)._yourself();
+$self._while_should_("bar: anObject baz: anotherObject\x0a\x09\x09<jsOverride: #foo args: #(anotherObject anObject)>\x0a\x09\x09^ super bar: anObject baz: anotherObject",(function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+$self._shouldnt_raise_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return [$recv($self.receiver)._bar_baz_((3),(4))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx3.sendIdx["bar:baz:"]=1
+//>>excludeEnd("ctx");
+][0];
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
+//>>excludeEnd("ctx");
+}),$globals.Error);
+return $self._assert_equals_($recv($self.receiver)._bar_baz_((4),true),"true,4");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testDyadicSuperDifferentNamesPermutated",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.AbstractJavaScriptGatewayTest);
+
 $core.addMethod(
 $core.method({
 selector: "testMonadicSuperDifferentNames",
@@ -2127,6 +2178,57 @@ return self;
 }; }),
 $globals.AbstractJavaScriptGatewayTest);
 
+$core.addMethod(
+$core.method({
+selector: "testTriadicSuperDifferentNamesPermutated",
+protocol: "tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testTriadicSuperDifferentNamesPermutated\x0a\x09theClass := ObjectMock subclass: #ObjectMock2 slots: #() package: 'Compiler-Tests'.\x0a\x09theClass beJavaScriptSubclassOf: self jsConstructor.\x0a\x09receiver := ObjectMock2 new foo: 'should be shadowed'; yourself.\x0a\x09self while: 'bar: anObject baz: anotherObject moo: yao\x0a\x09\x09<jsOverride: #foo args: #(yao anObject anotherObject)>\x0a\x09\x09^ super bar: anObject baz: anotherObject moo: yao' should: [\x0a\x09\x09self shouldnt: [ receiver bar: 3 baz: 4 moo: 5 ] raise: Error.\x0a\x09\x09self assert: (receiver bar: 4 baz: true moo: 'hello') equals: 'hello,4' ]",
+referencedClasses: ["ObjectMock", "ObjectMock2", "Error"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["subclass:slots:package:", "beJavaScriptSubclassOf:", "jsConstructor", "foo:", "new", "yourself", "while:should:", "shouldnt:raise:", "bar:baz:moo:", "assert:equals:"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1;
+$self.theClass=$recv($globals.ObjectMock)._subclass_slots_package_("ObjectMock2",[],"Compiler-Tests");
+$recv($self.theClass)._beJavaScriptSubclassOf_($self._jsConstructor());
+$1=$recv($globals.ObjectMock2)._new();
+$recv($1)._foo_("should be shadowed");
+$self.receiver=$recv($1)._yourself();
+$self._while_should_("bar: anObject baz: anotherObject moo: yao\x0a\x09\x09<jsOverride: #foo args: #(yao anObject anotherObject)>\x0a\x09\x09^ super bar: anObject baz: anotherObject moo: yao",(function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+$self._shouldnt_raise_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return [$recv($self.receiver)._bar_baz_moo_((3),(4),(5))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx3.sendIdx["bar:baz:moo:"]=1
+//>>excludeEnd("ctx");
+][0];
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
+//>>excludeEnd("ctx");
+}),$globals.Error);
+return $self._assert_equals_($recv($self.receiver)._bar_baz_moo_((4),true,"hello"),"hello,4");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testTriadicSuperDifferentNamesPermutated",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.AbstractJavaScriptGatewayTest);
+
 $core.addMethod(
 $core.method({
 selector: "theClass",
@@ -2729,6 +2831,85 @@ return self;
 }; }),
 $globals.AbstractCodeGeneratorInstallTest);
 
+$core.addMethod(
+$core.method({
+selector: "testDyadicJSOverrideDifferentNamesPermutated",
+protocol: "tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testDyadicJSOverrideDifferentNamesPermutated\x0a\x09receiver := ObjectMock new.\x0a\x09receiver foo: 4.\x0a\x09self while: 'quux: anInteger foo: anotherInteger\x0a\x09\x09<jsOverride: #mux args: #(anotherInteger anInteger)>\x0a\x09\x09^ (foo := foo * anInteger + anotherInteger)' should: [\x0a\x09\x09self should: [ receiver mux ] raise: MessageNotUnderstood.\x0a\x09\x09self should: [ receiver mux: 2 and: -1 ] raise: MessageNotUnderstood.\x0a\x09\x09self assert: (receiver basicPerform: #mux withArguments: #(-2 2)) equals: 6.\x0a\x09\x09self assert: (receiver quux: 1 foo: 4) equals: 10.\x0a\x09\x09self should: [ receiver basicPerform: #quux ] raise: Error.\x0a\x09\x09self assert: receiver foo equals: 10 ]",
+referencedClasses: ["ObjectMock", "MessageNotUnderstood", "Error"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["new", "foo:", "while:should:", "should:raise:", "mux", "mux:and:", "assert:equals:", "basicPerform:withArguments:", "quux:foo:", "basicPerform:", "foo"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self.receiver=$recv($globals.ObjectMock)._new();
+$recv($self.receiver)._foo_((4));
+$self._while_should_("quux: anInteger foo: anotherInteger\x0a\x09\x09<jsOverride: #mux args: #(anotherInteger anInteger)>\x0a\x09\x09^ (foo := foo * anInteger + anotherInteger)",(function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+[$self._should_raise_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv($self.receiver)._mux();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
+//>>excludeEnd("ctx");
+}),$globals.MessageNotUnderstood)
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["should:raise:"]=1
+//>>excludeEnd("ctx");
+][0];
+[$self._should_raise_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv($self.receiver)._mux_and_((2),(-1));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,3)});
+//>>excludeEnd("ctx");
+}),$globals.MessageNotUnderstood)
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["should:raise:"]=2
+//>>excludeEnd("ctx");
+][0];
+[$self._assert_equals_($recv($self.receiver)._basicPerform_withArguments_("mux",[(-2), (2)]),(6))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["assert:equals:"]=1
+//>>excludeEnd("ctx");
+][0];
+[$self._assert_equals_($recv($self.receiver)._quux_foo_((1),(4)),(10))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["assert:equals:"]=2
+//>>excludeEnd("ctx");
+][0];
+$self._should_raise_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv($self.receiver)._basicPerform_("quux");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,4)});
+//>>excludeEnd("ctx");
+}),$globals.Error);
+return $self._assert_equals_($recv($self.receiver)._foo(),(10));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testDyadicJSOverrideDifferentNamesPermutated",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.AbstractCodeGeneratorInstallTest);
+
 $core.addMethod(
 $core.method({
 selector: "testDyadicJSOverrideInOneArg",
@@ -3178,6 +3359,85 @@ return self;
 }; }),
 $globals.AbstractCodeGeneratorInstallTest);
 
+$core.addMethod(
+$core.method({
+selector: "testTriadicJSOverrideDifferentNamesPermutated",
+protocol: "tests",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: [],
+source: "testTriadicJSOverrideDifferentNamesPermutated\x0a\x09receiver := ObjectMock new.\x0a\x09receiver foo: 4.\x0a\x09self while: 'quux: anInteger foo: anotherInteger bar: yaInt\x0a\x09\x09<jsOverride: #mux args: #(yaInt anInteger anotherInteger)>\x0a\x09\x09^ (foo := foo * anInteger + anotherInteger - yaInt)' should: [\x0a\x09\x09self should: [ receiver mux ] raise: MessageNotUnderstood.\x0a\x09\x09self should: [ receiver mux: 2 and: -1 and: 0 ] raise: MessageNotUnderstood.\x0a\x09\x09self assert: (receiver basicPerform: #mux withArguments: #(5 2 3)) equals: 6.\x0a\x09\x09self assert: (receiver quux: 1 foo: 4 bar: 20) equals: -10.\x0a\x09\x09self should: [ receiver basicPerform: #quux ] raise: Error.\x0a\x09\x09self assert: receiver foo equals: -10 ]",
+referencedClasses: ["ObjectMock", "MessageNotUnderstood", "Error"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["new", "foo:", "while:should:", "should:raise:", "mux", "mux:and:and:", "assert:equals:", "basicPerform:withArguments:", "quux:foo:bar:", "basicPerform:", "foo"]
+}, function ($methodClass){ return function (){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$self.receiver=$recv($globals.ObjectMock)._new();
+$recv($self.receiver)._foo_((4));
+$self._while_should_("quux: anInteger foo: anotherInteger bar: yaInt\x0a\x09\x09<jsOverride: #mux args: #(yaInt anInteger anotherInteger)>\x0a\x09\x09^ (foo := foo * anInteger + anotherInteger - yaInt)",(function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+[$self._should_raise_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv($self.receiver)._mux();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
+//>>excludeEnd("ctx");
+}),$globals.MessageNotUnderstood)
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["should:raise:"]=1
+//>>excludeEnd("ctx");
+][0];
+[$self._should_raise_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv($self.receiver)._mux_and_and_((2),(-1),(0));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,3)});
+//>>excludeEnd("ctx");
+}),$globals.MessageNotUnderstood)
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["should:raise:"]=2
+//>>excludeEnd("ctx");
+][0];
+[$self._assert_equals_($recv($self.receiver)._basicPerform_withArguments_("mux",[(5), (2), (3)]),(6))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["assert:equals:"]=1
+//>>excludeEnd("ctx");
+][0];
+[$self._assert_equals_($recv($self.receiver)._quux_foo_bar_((1),(4),(20)),(-10))
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+,$ctx2.sendIdx["assert:equals:"]=2
+//>>excludeEnd("ctx");
+][0];
+$self._should_raise_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv($self.receiver)._basicPerform_("quux");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({},$ctx2,4)});
+//>>excludeEnd("ctx");
+}),$globals.Error);
+return $self._assert_equals_($recv($self.receiver)._foo(),(-10));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"testTriadicJSOverrideDifferentNamesPermutated",{})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.AbstractCodeGeneratorInstallTest);
+
 
 $core.addMethod(
 $core.method({

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

@@ -507,6 +507,17 @@ testDyadicSuperDifferentNamesNested
 		self assert: (receiver bar: 4 baz: true) equals: '4,true' ]
 !
 
+testDyadicSuperDifferentNamesPermutated
+	theClass := ObjectMock subclass: #ObjectMock2 slots: #() package: 'Compiler-Tests'.
+	theClass beJavaScriptSubclassOf: self jsConstructor.
+	receiver := ObjectMock2 new foo: 'should be shadowed'; yourself.
+	self while: 'bar: anObject baz: anotherObject
+		<jsOverride: #foo args: #(anotherObject anObject)>
+		^ super bar: anObject baz: anotherObject' should: [
+		self shouldnt: [ receiver bar: 3 baz: 4 ] raise: Error.
+		self assert: (receiver bar: 4 baz: true) equals: 'true,4' ]
+!
+
 testMonadicSuperDifferentNames
 	theClass := ObjectMock subclass: #ObjectMock2 slots: #() package: 'Compiler-Tests'.
 	theClass beJavaScriptSubclassOf: self jsConstructor.
@@ -541,6 +552,17 @@ testNiladicSuperNested
 		should: 'foo <jsOverride: #foo> ^ [ super foo ] value'
 		receiver: (ObjectMock2 new foo: 'should be shadowed'; yourself)
 		return: 'undefined,undefined'
+!
+
+testTriadicSuperDifferentNamesPermutated
+	theClass := ObjectMock subclass: #ObjectMock2 slots: #() package: 'Compiler-Tests'.
+	theClass beJavaScriptSubclassOf: self jsConstructor.
+	receiver := ObjectMock2 new foo: 'should be shadowed'; yourself.
+	self while: 'bar: anObject baz: anotherObject moo: yao
+		<jsOverride: #foo args: #(yao anObject anotherObject)>
+		^ super bar: anObject baz: anotherObject moo: yao' should: [
+		self shouldnt: [ receiver bar: 3 baz: 4 moo: 5 ] raise: Error.
+		self assert: (receiver bar: 4 baz: true moo: 'hello') equals: 'hello,4' ]
 ! !
 
 !AbstractJavaScriptGatewayTest class methodsFor: 'testing'!
@@ -726,6 +748,20 @@ testDyadicJSOverrideDifferentNames
 		self assert: receiver foo equals: 10 ]
 !
 
+testDyadicJSOverrideDifferentNamesPermutated
+	receiver := ObjectMock new.
+	receiver foo: 4.
+	self while: 'quux: anInteger foo: anotherInteger
+		<jsOverride: #mux args: #(anotherInteger anInteger)>
+		^ (foo := foo * anInteger + anotherInteger)' should: [
+		self should: [ receiver mux ] raise: MessageNotUnderstood.
+		self should: [ receiver mux: 2 and: -1 ] raise: MessageNotUnderstood.
+		self assert: (receiver basicPerform: #mux withArguments: #(-2 2)) equals: 6.
+		self assert: (receiver quux: 1 foo: 4) equals: 10.
+		self should: [ receiver basicPerform: #quux ] raise: Error.
+		self assert: receiver foo equals: 10 ]
+!
+
 testDyadicJSOverrideInOneArg
 	receiver := ObjectMock new.
 	self
@@ -828,6 +864,20 @@ testNiladicJSOverrideInOneArg
 
 testPragmaInBlock
 	self shouldntInstall: 'foo ^ [ < fooBar > 4 ] value' andRaise: ParseError
+!
+
+testTriadicJSOverrideDifferentNamesPermutated
+	receiver := ObjectMock new.
+	receiver foo: 4.
+	self while: 'quux: anInteger foo: anotherInteger bar: yaInt
+		<jsOverride: #mux args: #(yaInt anInteger anotherInteger)>
+		^ (foo := foo * anInteger + anotherInteger - yaInt)' should: [
+		self should: [ receiver mux ] raise: MessageNotUnderstood.
+		self should: [ receiver mux: 2 and: -1 and: 0 ] raise: MessageNotUnderstood.
+		self assert: (receiver basicPerform: #mux withArguments: #(5 2 3)) equals: 6.
+		self assert: (receiver quux: 1 foo: 4 bar: 20) equals: -10.
+		self should: [ receiver basicPerform: #quux ] raise: Error.
+		self assert: receiver foo equals: -10 ]
 ! !
 
 !AbstractCodeGeneratorInstallTest class methodsFor: 'testing'!