7 Commits 9a35214ee6 ... 25f05d294d

Author SHA1 Message Date
  Herby Vojčík 25f05d294d DRY 4 years ago
  Herby Vojčík 01ae5c0265 Optimize some uses of #and:. 4 years ago
  Herby Vojčík a512c9d830 Refactor: Put responsibility where it's due. 4 years ago
  Herby Vojčík 10e50375bf Refactor: Put responsibility where it's due. 4 years ago
  Herby Vojčík 75feddedce Remove message never sent. 4 years ago
  Herby Vojčík eab0e5857a Remove ivar that was never used. 4 years ago
  Herby Vojčík 908203de93 Simplify #validateAssigment. 4 years ago

+ 12 - 1
lang/API-CHANGES.txt

@@ -14,19 +14,25 @@
 + ExternallyKnownVar >>
   + isExternallyKnownVar
 + SemanticAnalyzer >>
+  + errorInvalidAssignment:
   + isVariableKnown:inPackage:
 + ScopeVar >>
   + isExternallyKnownVar
 + SequenceableCollection >>
   + copyWithFirst:
 + SmalltalkImage >>
-  + do:on:do:
   + isError:
+  + try:ifTrue:catch:
 + amber/boot api >>
   + detachClass(klass)
 + amber/helpers exports >>
   + $nil
 
+- AliasVar >>
+  - node
+  - node:
+- ArgVar >>
+  - isArgVar
 - Error >>
   - beSmalltalkError
   - isSmalltalkError
@@ -39,7 +45,9 @@
 - MethodLexicalScope >>
   - unknownVariables
 - ScopeVar >>
+  - isArgVar
   - isUnknownVar
+  - validateAssignment
 - SemanticAnalyzer >>
   - isVariableUndefined:inPackage:
 - SendNode >>
@@ -47,6 +55,9 @@
   - shouldBeInlined:
 - UnknownVar >>
   - isUnknownVar
+- VariableNode >>
+  - beAssigned
+  - isArgument
 - amber/boot api >>
   - addElement(arraySet, el)
   - removeElement(arraySet, el)

+ 11 - 65
lang/src/Compiler-AST.js

@@ -2008,31 +2008,25 @@ selector: "superSend",
 protocol: "accessing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "superSend\x0a\x09^ self receiver notNil and: [ self receiver isSuper ]",
+source: "superSend\x0a\x09^ self receiver ifNil: [ false ] ifNotNil: [ :recv | recv isSuper ]",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["and:", "notNil", "receiver", "isSuper"]
+messageSends: ["ifNil:ifNotNil:", "receiver", "isSuper"]
 }, function ($methodClass){ return function (){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $2,$1;
-$2=$self._receiver();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["receiver"]=1;
-//>>excludeEnd("ctx");
-$1=$recv($2)._notNil();
-return $recv($1)._and_((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $recv($self._receiver())._isSuper();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
-//>>excludeEnd("ctx");
-}));
+var $1,$receiver;
+$1=$self._receiver();
+if(($receiver = $1) == null || $receiver.a$nil){
+return false;
+} else {
+var recv;
+recv=$receiver;
+return $recv(recv)._isSuper();
+}
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"superSend",{})});
 //>>excludeEnd("ctx");
@@ -2425,31 +2419,6 @@ return self;
 }; }),
 $globals.VariableNode);
 
-$core.addMethod(
-$core.method({
-selector: "beAssigned",
-protocol: "accessing",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "beAssigned\x0a\x09self binding validateAssignment.\x0a\x09assigned := true",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["validateAssignment", "binding"]
-}, function ($methodClass){ return function (){
-var self=this,$self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-$recv($self._binding())._validateAssignment();
-$self.assigned=true;
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"beAssigned",{})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.VariableNode);
-
 $core.addMethod(
 $core.method({
 selector: "binding",
@@ -2487,29 +2456,6 @@ return self;
 }; }),
 $globals.VariableNode);
 
-$core.addMethod(
-$core.method({
-selector: "isArgument",
-protocol: "testing",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isArgument\x0a\x09^ self binding isArgVar",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["isArgVar", "binding"]
-}, function ($methodClass){ return function (){
-var self=this,$self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-return $recv($self._binding())._isArgVar();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"isArgument",{})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.VariableNode);
-
 $core.addMethod(
 $core.method({
 selector: "isImmutable",

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

@@ -482,7 +482,7 @@ selector: aString
 !
 
 superSend
-	^ self receiver notNil and: [ self receiver isSuper ]
+	^ self receiver ifNil: [ false ] ifNotNil: [ :recv | recv isSuper ]
 ! !
 
 !SendNode methodsFor: 'testing'!
@@ -611,11 +611,6 @@ assigned: aBoolean
 	assigned := aBoolean
 !
 
-beAssigned
-	self binding validateAssignment.
-	assigned := true
-!
-
 binding
 	^ binding
 !
@@ -630,10 +625,6 @@ navigationLink
 
 !VariableNode methodsFor: 'testing'!
 
-isArgument
-	^ self binding isArgVar
-!
-
 isImmutable
 	^ self binding isImmutable
 !

+ 50 - 133
lang/src/Compiler-Semantic.js

@@ -346,31 +346,25 @@ selector: "isInlined",
 protocol: "testing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "isInlined\x0a\x09^ self instruction notNil and: [\x0a\x09\x09self instruction isInlined ]",
+source: "isInlined\x0a\x09^ self instruction ifNil: [ false ] ifNotNil: [ :instr | instr isInlined ]",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["and:", "notNil", "instruction", "isInlined"]
+messageSends: ["ifNil:ifNotNil:", "instruction", "isInlined"]
 }, function ($methodClass){ return function (){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $2,$1;
-$2=$self._instruction();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["instruction"]=1;
-//>>excludeEnd("ctx");
-$1=$recv($2)._notNil();
-return $recv($1)._and_((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $recv($self._instruction())._isInlined();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
-//>>excludeEnd("ctx");
-}));
+var $1,$receiver;
+$1=$self._instruction();
+if(($receiver = $1) == null || $receiver.a$nil){
+return false;
+} else {
+var instr;
+instr=$receiver;
+return $recv(instr)._isInlined();
+}
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"isInlined",{})});
 //>>excludeEnd("ctx");
@@ -1077,24 +1071,6 @@ return $recv($self._name())._asVariableName();
 }; }),
 $globals.ScopeVar);
 
-$core.addMethod(
-$core.method({
-selector: "isArgVar",
-protocol: "testing",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isArgVar\x0a\x09^ false",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: []
-}, function ($methodClass){ return function (){
-var self=this,$self=this;
-return false;
-
-}; }),
-$globals.ScopeVar);
-
 $core.addMethod(
 $core.method({
 selector: "isClassRefVar",
@@ -1313,44 +1289,6 @@ return self;
 }; }),
 $globals.ScopeVar);
 
-$core.addMethod(
-$core.method({
-selector: "validateAssignment",
-protocol: "testing",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "validateAssignment\x0a\x09(self isArgVar or: [ self isPseudoVar ]) ifTrue: [\x0a\x09\x09InvalidAssignmentError new\x0a\x09\x09\x09variableName: self name;\x0a\x09\x09\x09signal]",
-referencedClasses: ["InvalidAssignmentError"],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["ifTrue:", "or:", "isArgVar", "isPseudoVar", "variableName:", "new", "name", "signal"]
-}, function ($methodClass){ return function (){
-var self=this,$self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-var $1,$2;
-$1=$recv($self._isArgVar())._or_((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $self._isPseudoVar();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
-//>>excludeEnd("ctx");
-}));
-if($core.assert($1)){
-$2=$recv($globals.InvalidAssignmentError)._new();
-$recv($2)._variableName_($self._name());
-$recv($2)._signal();
-}
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"validateAssignment",{})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.ScopeVar);
-
 
 $core.addMethod(
 $core.method({
@@ -1379,7 +1317,7 @@ return $recv($1)._yourself();
 $globals.ScopeVar.a$cls);
 
 
-$core.addClass("AliasVar", $globals.ScopeVar, ["node"], "Compiler-Semantic");
+$core.addClass("AliasVar", $globals.ScopeVar, [], "Compiler-Semantic");
 //>>excludeStart("ide", pragmas.excludeIdeData);
 $globals.AliasVar.comment="I am an internally defined variable by the compiler";
 //>>excludeEnd("ide");
@@ -1401,67 +1339,12 @@ return true;
 }; }),
 $globals.AliasVar);
 
-$core.addMethod(
-$core.method({
-selector: "node",
-protocol: "accessing",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "node\x0a\x09^ node",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: []
-}, function ($methodClass){ return function (){
-var self=this,$self=this;
-return $self.node;
-
-}; }),
-$globals.AliasVar);
-
-$core.addMethod(
-$core.method({
-selector: "node:",
-protocol: "accessing",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["aNode"],
-source: "node: aNode\x0a\x09node := aNode",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: []
-}, function ($methodClass){ return function (aNode){
-var self=this,$self=this;
-$self.node=aNode;
-return self;
-
-}; }),
-$globals.AliasVar);
-
 
 
 $core.addClass("ArgVar", $globals.ScopeVar, [], "Compiler-Semantic");
 //>>excludeStart("ide", pragmas.excludeIdeData);
 $globals.ArgVar.comment="I am an argument of a method or block.";
 //>>excludeEnd("ide");
-$core.addMethod(
-$core.method({
-selector: "isArgVar",
-protocol: "testing",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isArgVar\x0a\x09^ true",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: []
-}, function ($methodClass){ return function (){
-var self=this,$self=this;
-return true;
-
-}; }),
-$globals.ArgVar);
-
 $core.addMethod(
 $core.method({
 selector: "isImmutable",
@@ -1957,6 +1840,33 @@ return $1;
 }; }),
 $globals.SemanticAnalyzer);
 
+$core.addMethod(
+$core.method({
+selector: "errorInvalidAssignment:",
+protocol: "error handling",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["aString"],
+source: "errorInvalidAssignment: aString\x0a\x09InvalidAssignmentError new\x0a\x09\x09variableName: aString;\x0a\x09\x09signal",
+referencedClasses: ["InvalidAssignmentError"],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["variableName:", "new", "signal"]
+}, function ($methodClass){ return function (aString){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+var $1;
+$1=$recv($globals.InvalidAssignmentError)._new();
+$recv($1)._variableName_(aString);
+$recv($1)._signal();
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"errorInvalidAssignment:",{aString:aString})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.SemanticAnalyzer);
+
 $core.addMethod(
 $core.method({
 selector: "errorShadowingVariable:",
@@ -2348,16 +2258,18 @@ selector: "visitAssignmentNode:",
 protocol: "visiting",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aNode"],
-source: "visitAssignmentNode: aNode\x0a\x09super visitAssignmentNode: aNode.\x0a\x09aNode left beAssigned",
+source: "visitAssignmentNode: aNode\x0a\x09| lhs |\x0a\x09super visitAssignmentNode: aNode.\x0a\x09lhs := aNode left.\x0a\x09lhs isImmutable ifTrue: [ self errorInvalidAssignment: lhs value ].\x0a\x09lhs assigned: true",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["visitAssignmentNode:", "beAssigned", "left"]
+messageSends: ["visitAssignmentNode:", "left", "ifTrue:", "isImmutable", "errorInvalidAssignment:", "value", "assigned:"]
 }, function ($methodClass){ return function (aNode){
 var self=this,$self=this;
+var lhs;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
+var $1;
 (
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = true,
@@ -2366,10 +2278,15 @@ $ctx1.supercall = true,
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 $ctx1.supercall = false;
 //>>excludeEnd("ctx");;
-$recv($recv(aNode)._left())._beAssigned();
+lhs=$recv(aNode)._left();
+$1=$recv(lhs)._isImmutable();
+if($core.assert($1)){
+$self._errorInvalidAssignment_($recv(lhs)._value());
+}
+$recv(lhs)._assigned_(true);
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"visitAssignmentNode:",{aNode:aNode})});
+}, function($ctx1) {$ctx1.fill(self,"visitAssignmentNode:",{aNode:aNode,lhs:lhs})});
 //>>excludeEnd("ctx");
 }; }),
 $globals.SemanticAnalyzer);

+ 12 - 29
lang/src/Compiler-Semantic.st

@@ -117,8 +117,7 @@ isBlockScope
 !
 
 isInlined
-	^ self instruction notNil and: [
-		self instruction isInlined ]
+	^ self instruction ifNil: [ false ] ifNotNil: [ :instr | instr isInlined ]
 !
 
 isMethodScope
@@ -236,10 +235,6 @@ scope: aScope
 
 !ScopeVar methodsFor: 'testing'!
 
-isArgVar
-	^ false
-!
-
 isClassRefVar
 	^ false
 !
@@ -270,13 +265,6 @@ isSuper
 
 isTempVar
 	^ false
-!
-
-validateAssignment
-	(self isArgVar or: [ self isPseudoVar ]) ifTrue: [
-		InvalidAssignmentError new
-			variableName: self name;
-			signal]
 ! !
 
 !ScopeVar class methodsFor: 'instance creation'!
@@ -288,21 +276,11 @@ on: aString
 ! !
 
 ScopeVar subclass: #AliasVar
-	slots: {#node}
+	slots: {}
 	package: 'Compiler-Semantic'!
 !AliasVar commentStamp!
 I am an internally defined variable by the compiler!
 
-!AliasVar methodsFor: 'accessing'!
-
-node
-	^ node
-!
-
-node: aNode
-	node := aNode
-! !
-
 !AliasVar methodsFor: 'testing'!
 
 isImmutable
@@ -317,10 +295,6 @@ I am an argument of a method or block.!
 
 !ArgVar methodsFor: 'testing'!
 
-isArgVar
-	^ true
-!
-
 isImmutable
 	^ true
 ! !
@@ -498,6 +472,12 @@ thePackage: aPackage
 
 !SemanticAnalyzer methodsFor: 'error handling'!
 
+errorInvalidAssignment: aString
+	InvalidAssignmentError new
+		variableName: aString;
+		signal
+!
+
 errorShadowingVariable: aString
 	ShadowingVariableError new
 		variableName: aString;
@@ -585,8 +565,11 @@ isVariableKnown: aString inPackage: aPackage
 !SemanticAnalyzer methodsFor: 'visiting'!
 
 visitAssignmentNode: aNode
+	| lhs |
 	super visitAssignmentNode: aNode.
-	aNode left beAssigned
+	lhs := aNode left.
+	lhs isImmutable ifTrue: [ self errorInvalidAssignment: lhs value ].
+	lhs assigned: true
 !
 
 visitBlockNode: aNode

+ 17 - 38
lang/src/Kernel-Classes.js

@@ -326,35 +326,29 @@ selector: "canUnderstand:",
 protocol: "testing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aSelector"],
-source: "canUnderstand: aSelector\x0a\x09^ (self includesSelector: aSelector asString) or: [\x0a\x09\x09self superclass notNil and: [ self superclass canUnderstand: aSelector ]]",
+source: "canUnderstand: aSelector\x0a\x09^ (self includesSelector: aSelector asString) or: [\x0a\x09\x09self superclass ifNil: [ false ] ifNotNil: [ :superClass | superClass canUnderstand: aSelector ]]",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["or:", "includesSelector:", "asString", "and:", "notNil", "superclass", "canUnderstand:"]
+messageSends: ["or:", "includesSelector:", "asString", "ifNil:ifNotNil:", "superclass", "canUnderstand:"]
 }, function ($methodClass){ return function (aSelector){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $2,$1;
+var $1,$receiver;
 return $recv($self._includesSelector_($recv(aSelector)._asString()))._or_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
 //>>excludeEnd("ctx");
-$2=$self._superclass();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx2.sendIdx["superclass"]=1;
-//>>excludeEnd("ctx");
-$1=$recv($2)._notNil();
-return $recv($1)._and_((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx3) {
-//>>excludeEnd("ctx");
-return $recv($self._superclass())._canUnderstand_(aSelector);
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
-//>>excludeEnd("ctx");
-}));
+$1=$self._superclass();
+if(($receiver = $1) == null || $receiver.a$nil){
+return false;
+} else {
+var superClass;
+superClass=$receiver;
+return $recv(superClass)._canUnderstand_(aSelector);
+}
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
 //>>excludeEnd("ctx");
@@ -402,40 +396,25 @@ selector: "inheritsFrom:",
 protocol: "testing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aClass"],
-source: "inheritsFrom: aClass\x0a\x09self superclass ifNil: [ ^ false ].\x0a\x0a\x09^ aClass == self superclass or: [ \x0a\x09\x09self superclass inheritsFrom: aClass ]",
+source: "inheritsFrom: aClass\x0a\x09^ self superclass\x0a\x09\x09ifNil: [ false ]\x0a\x09\x09ifNotNil: [ :superClass | superClass includesBehavior: aClass ]",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["ifNil:", "superclass", "or:", "==", "inheritsFrom:"]
+messageSends: ["ifNil:ifNotNil:", "superclass", "includesBehavior:"]
 }, function ($methodClass){ return function (aClass){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1,$3,$2,$receiver;
+var $1,$receiver;
 $1=$self._superclass();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["superclass"]=1;
-//>>excludeEnd("ctx");
 if(($receiver = $1) == null || $receiver.a$nil){
 return false;
 } else {
-$1;
+var superClass;
+superClass=$receiver;
+return $recv(superClass)._includesBehavior_(aClass);
 }
-$3=$self._superclass();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["superclass"]=2;
-//>>excludeEnd("ctx");
-$2=$recv(aClass).__eq_eq($3);
-return $recv($2)._or_((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $recv($self._superclass())._inheritsFrom_(aClass);
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)});
-//>>excludeEnd("ctx");
-}));
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"inheritsFrom:",{aClass:aClass})});
 //>>excludeEnd("ctx");

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

@@ -171,7 +171,7 @@ makeJavaScriptConstructorSubclassOf: javaScriptClass
 
 canUnderstand: aSelector
 	^ (self includesSelector: aSelector asString) or: [
-		self superclass notNil and: [ self superclass canUnderstand: aSelector ]]
+		self superclass ifNil: [ false ] ifNotNil: [ :superClass | superClass canUnderstand: aSelector ]]
 !
 
 includesBehavior: aClass
@@ -180,10 +180,9 @@ includesBehavior: aClass
 !
 
 inheritsFrom: aClass
-	self superclass ifNil: [ ^ false ].
-
-	^ aClass == self superclass or: [ 
-		self superclass inheritsFrom: aClass ]
+	^ self superclass
+		ifNil: [ false ]
+		ifNotNil: [ :superClass | superClass includesBehavior: aClass ]
 !
 
 isBehavior

+ 4 - 14
lang/src/Kernel-Helpers.js

@@ -196,29 +196,19 @@ selector: "canProcessPragma:",
 protocol: "pragma processing",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aMessage"],
-source: "canProcessPragma: aMessage\x0a\x09| selector |\x0a\x09selector := aMessage selector.\x0a\x09^ (self respondsTo: selector) and: [\x0a\x09\x09(self class superclass canUnderstand: selector) not]",
+source: "canProcessPragma: aMessage\x0a\x09^ self class includesSelector: aMessage selector",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["selector", "and:", "respondsTo:", "not", "canUnderstand:", "superclass", "class"]
+messageSends: ["includesSelector:", "class", "selector"]
 }, function ($methodClass){ return function (aMessage){
 var self=this,$self=this;
-var selector;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-selector=$recv(aMessage)._selector();
-return $recv($self._respondsTo_(selector))._and_((function(){
+return $recv($self._class())._includesSelector_($recv(aMessage)._selector());
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $recv($recv($recv($self._class())._superclass())._canUnderstand_(selector))._not();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
-//>>excludeEnd("ctx");
-}));
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"canProcessPragma:",{aMessage:aMessage,selector:selector})});
+}, function($ctx1) {$ctx1.fill(self,"canProcessPragma:",{aMessage:aMessage})});
 //>>excludeEnd("ctx");
 }; }),
 $globals.TPragmator);

+ 1 - 4
lang/src/Kernel-Helpers.st

@@ -56,10 +56,7 @@ Trait named: #TPragmator
 !TPragmator methodsFor: 'pragma processing'!
 
 canProcessPragma: aMessage
-	| selector |
-	selector := aMessage selector.
-	^ (self respondsTo: selector) and: [
-		(self class superclass canUnderstand: selector) not]
+	^ self class includesSelector: aMessage selector
 !
 
 processPragma: aMessage

+ 44 - 41
lang/src/Kernel-Infrastructure.js

@@ -3243,47 +3243,6 @@ return self;
 }; }),
 $globals.SmalltalkImage);
 
-$core.addMethod(
-$core.method({
-selector: "do:on:do:",
-protocol: "error handling",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["actionBlock", "anErrorClass", "aBlock"],
-source: "do: actionBlock on: anErrorClass do: aBlock\x0a\x09\x22All exceptions thrown in the Smalltalk stack are cought.\x0a\x09Convert all JS exceptions to JavaScriptException instances.\x22\x0a\x09\x0a\x09| smalltalkError |\x0a\x09^ actionBlock\x0a\x09\x09tryIfTrue: [ :error |\x0a\x09\x09\x09smalltalkError := self asSmalltalkException: error.\x0a\x09\x09\x09smalltalkError isKindOf: anErrorClass ]\x0a\x09\x09catch: [ aBlock value: smalltalkError ]",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["tryIfTrue:catch:", "asSmalltalkException:", "isKindOf:", "value:"]
-}, function ($methodClass){ return function (actionBlock,anErrorClass,aBlock){
-var self=this,$self=this;
-var smalltalkError;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-return $recv(actionBlock)._tryIfTrue_catch_((function(error){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-smalltalkError=$self._asSmalltalkException_(error);
-return $recv(smalltalkError)._isKindOf_(anErrorClass);
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({error:error},$ctx1,1)});
-//>>excludeEnd("ctx");
-}),(function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $recv(aBlock)._value_(smalltalkError);
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)});
-//>>excludeEnd("ctx");
-}));
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"do:on:do:",{actionBlock:actionBlock,anErrorClass:anErrorClass,aBlock:aBlock,smalltalkError:smalltalkError})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.SmalltalkImage);
-
 $core.addMethod(
 $core.method({
 selector: "existsJsGlobal:",
@@ -3924,6 +3883,50 @@ return self;
 }; }),
 $globals.SmalltalkImage);
 
+$core.addMethod(
+$core.method({
+selector: "try:ifTrue:catch:",
+protocol: "error handling",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["actionBlock", "aBlock", "anotherBlock"],
+source: "try: actionBlock ifTrue: aBlock catch: anotherBlock\x0a\x09\x22Similar to BlockClosure >> tryifTrue:catch:, but\x0a\x09converts all JS exceptions to JavaScriptException instances.\x22\x0a\x09\x0a\x09| smalltalkError |\x0a\x09^ actionBlock\x0a\x09\x09tryIfTrue: [ :error |\x0a\x09\x09\x09smalltalkError := self asSmalltalkException: error.\x0a\x09\x09\x09aBlock value: smalltalkError ]\x0a\x09\x09catch: [ anotherBlock value: smalltalkError ]",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["tryIfTrue:catch:", "asSmalltalkException:", "value:"]
+}, function ($methodClass){ return function (actionBlock,aBlock,anotherBlock){
+var self=this,$self=this;
+var smalltalkError;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+return $recv(actionBlock)._tryIfTrue_catch_((function(error){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+smalltalkError=$self._asSmalltalkException_(error);
+return $recv(aBlock)._value_(smalltalkError);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+$ctx2.sendIdx["value:"]=1;
+//>>excludeEnd("ctx");
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({error:error},$ctx1,1)});
+//>>excludeEnd("ctx");
+}),(function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv(anotherBlock)._value_(smalltalkError);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)});
+//>>excludeEnd("ctx");
+}));
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"try:ifTrue:catch:",{actionBlock:actionBlock,aBlock:aBlock,anotherBlock:anotherBlock,smalltalkError:smalltalkError})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.SmalltalkImage);
+
 $core.addMethod(
 $core.method({
 selector: "tryAdoptPackageDescriptorsBeyond:",

+ 5 - 5
lang/src/Kernel-Infrastructure.st

@@ -916,16 +916,16 @@ asSmalltalkException: anObject
 		ifFalse: [ JavaScriptException on: anObject ]
 !
 
-do: actionBlock on: anErrorClass do: aBlock
-	"All exceptions thrown in the Smalltalk stack are cought.
-	Convert all JS exceptions to JavaScriptException instances."
+try: actionBlock ifTrue: aBlock catch: anotherBlock
+	"Similar to BlockClosure >> tryifTrue:catch:, but
+	converts all JS exceptions to JavaScriptException instances."
 	
 	| smalltalkError |
 	^ actionBlock
 		tryIfTrue: [ :error |
 			smalltalkError := self asSmalltalkException: error.
-			smalltalkError isKindOf: anErrorClass ]
-		catch: [ aBlock value: smalltalkError ]
+			aBlock value: smalltalkError ]
+		catch: [ anotherBlock value: smalltalkError ]
 ! !
 
 !SmalltalkImage methodsFor: 'globals'!

+ 11 - 3
lang/src/Kernel-Methods.js

@@ -345,17 +345,25 @@ selector: "on:do:",
 protocol: "error handling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anErrorClass", "aBlock"],
-source: "on: anErrorClass do: aBlock\x0a\x09^ Smalltalk do: self on: anErrorClass do: aBlock",
+source: "on: anErrorClass do: aBlock\x0a\x09^ Smalltalk try: self ifTrue: [ :err | err isKindOf: anErrorClass ] catch: aBlock",
 referencedClasses: ["Smalltalk"],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["do:on:do:"]
+messageSends: ["try:ifTrue:catch:", "isKindOf:"]
 }, function ($methodClass){ return function (anErrorClass,aBlock){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-return $recv($globals.Smalltalk)._do_on_do_(self,anErrorClass,aBlock);
+return $recv($globals.Smalltalk)._try_ifTrue_catch_(self,(function(err){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv(err)._isKindOf_(anErrorClass);
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({err:err},$ctx1,1)});
+//>>excludeEnd("ctx");
+}),aBlock);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"on:do:",{anErrorClass:anErrorClass,aBlock:aBlock})});
 //>>excludeEnd("ctx");

+ 1 - 1
lang/src/Kernel-Methods.st

@@ -103,7 +103,7 @@ provided
 !BlockClosure methodsFor: 'error handling'!
 
 on: anErrorClass do: aBlock
-	^ Smalltalk do: self on: anErrorClass do: aBlock
+	^ Smalltalk try: self ifTrue: [ :err | err isKindOf: anErrorClass ] catch: aBlock
 !
 
 tryCatch: aBlock

+ 4 - 4
lang/src/Platform-Services.js

@@ -735,17 +735,17 @@ selector: "evaluate:on:do:",
 protocol: "error handling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["aBlock", "anErrorClass", "exceptionBlock"],
-source: "evaluate: aBlock on: anErrorClass do: exceptionBlock\x0a\x09\x22Evaluate a block and catch exceptions happening on the environment stack\x22\x0a\x09\x0a\x09^ Smalltalk do: aBlock on: (self classNamed: anErrorClass name) do: exceptionBlock",
-referencedClasses: ["Smalltalk"],
+source: "evaluate: aBlock on: anErrorClass do: exceptionBlock\x0a\x09\x22Evaluate a block and catch exceptions happening on the environment stack\x22\x0a\x09\x0a\x09^ aBlock on: (self classNamed: anErrorClass name) do: exceptionBlock",
+referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["do:on:do:", "classNamed:", "name"]
+messageSends: ["on:do:", "classNamed:", "name"]
 }, function ($methodClass){ return function (aBlock,anErrorClass,exceptionBlock){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-return $recv($globals.Smalltalk)._do_on_do_(aBlock,$self._classNamed_($recv(anErrorClass)._name()),exceptionBlock);
+return $recv(aBlock)._on_do_($self._classNamed_($recv(anErrorClass)._name()),exceptionBlock);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"evaluate:on:do:",{aBlock:aBlock,anErrorClass:anErrorClass,exceptionBlock:exceptionBlock})});
 //>>excludeEnd("ctx");

+ 1 - 1
lang/src/Platform-Services.st

@@ -257,7 +257,7 @@ compileMethod: sourceCode for: class protocol: protocol
 evaluate: aBlock on: anErrorClass do: exceptionBlock
 	"Evaluate a block and catch exceptions happening on the environment stack"
 	
-	^ Smalltalk do: aBlock on: (self classNamed: anErrorClass name) do: exceptionBlock
+	^ aBlock on: (self classNamed: anErrorClass name) do: exceptionBlock
 ! !
 
 !Environment methodsFor: 'evaluating'!