Browse Source

Clean error handling.

Herby Vojčík 4 years ago
parent
commit
f0fb187fb6

+ 1 - 0
CHANGELOG

@@ -2,6 +2,7 @@
 ===================================
 
 * $core.removeClass returns removed class.
+* Cleaned error-handling code.
 
 Commits: https://lolg.it/amber/amber/commits/0.24.1
 

+ 1 - 1
cli/package.json

@@ -36,7 +36,7 @@
   "dependencies": {
     "@ambers/grunt-init-amber-project": ">=0.22.11",
     "@ambers/sdk": ">=0.10.5",
-    "@ambers/lang": ">=0.22.2"
+    "@ambers/lang": ">0.24.0"
   },
   "peerDependencies": {
     "grunt-init": "^0.3.1",

+ 21 - 11
cli/src/AmberCli.js

@@ -2725,18 +2725,17 @@ selector: "eval:on:",
 protocol: "actions",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["buffer", "anObject"],
-source: "eval: buffer on: anObject\x0a\x09| result |\x0a\x09buffer ifNotEmpty: [\x0a\x09\x09[result := Compiler new evaluateExpression: buffer on: anObject]\x0a\x09\x09\x09tryCatch: [:e |\x0a\x09\x09\x09\x09e isSmalltalkError\x0a\x09\x09\x09\x09\x09ifTrue: [ e pass ]\x0a\x09\x09\x09\x09\x09ifFalse: [ process stdout write: e jsStack ]]].\x0a\x09^ result",
-referencedClasses: ["Compiler"],
+source: "eval: buffer on: anObject\x0a\x09| result |\x0a\x09buffer ifNotEmpty: [\x0a\x09\x09[result := Compiler new evaluateExpression: buffer on: anObject]\x0a\x09\x09\x09tryIfTrue: [ :e | (Smalltalk isError: e) not or: [ e context isNil ] ]\x0a\x09\x09\x09catch: [ :e | process stdout write: e jsStack ]].\x0a\x09^ result",
+referencedClasses: ["Compiler", "Smalltalk"],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["ifNotEmpty:", "tryCatch:", "evaluateExpression:on:", "new", "ifTrue:ifFalse:", "isSmalltalkError", "pass", "write:", "stdout", "jsStack"]
+messageSends: ["ifNotEmpty:", "tryIfTrue:catch:", "evaluateExpression:on:", "new", "or:", "not", "isError:", "isNil", "context", "write:", "stdout", "jsStack"]
 }, function ($methodClass){ return function (buffer,anObject){
 var self=this,$self=this;
 var result;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
 $recv(buffer)._ifNotEmpty_((function(){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx2) {
@@ -2750,19 +2749,30 @@ return result;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx3) {$ctx3.fillBlock({},$ctx2,2)});
 //>>excludeEnd("ctx");
-}))._tryCatch_((function(e){
+}))._tryIfTrue_catch_((function(e){
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx3) {
 //>>excludeEnd("ctx");
-$1=$recv(e)._isSmalltalkError();
-if($core.assert($1)){
-return $recv(e)._pass();
-} else {
-return $recv($recv(process)._stdout())._write_($recv(e)._jsStack());
-}
+return $recv($recv($recv($globals.Smalltalk)._isError_(e))._not())._or_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx4) {
+//>>excludeEnd("ctx");
+return $recv($recv(e)._context())._isNil();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx4) {$ctx4.fillBlock({},$ctx3,4)});
+//>>excludeEnd("ctx");
+}));
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx3) {$ctx3.fillBlock({e:e},$ctx2,3)});
 //>>excludeEnd("ctx");
+}),(function(e){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx3) {
+//>>excludeEnd("ctx");
+return $recv($recv(process)._stdout())._write_($recv(e)._jsStack());
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx3) {$ctx3.fillBlock({e:e},$ctx2,5)});
+//>>excludeEnd("ctx");
 }));
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});

+ 2 - 4
cli/src/AmberCli.st

@@ -1103,10 +1103,8 @@ eval: buffer on: anObject
 	| result |
 	buffer ifNotEmpty: [
 		[result := Compiler new evaluateExpression: buffer on: anObject]
-			tryCatch: [:e |
-				e isSmalltalkError
-					ifTrue: [ e pass ]
-					ifFalse: [ process stdout write: e jsStack ]]].
+			tryIfTrue: [ :e | (Smalltalk isError: e) not or: [ e context isNil ] ]
+			catch: [ :e | process stdout write: e jsStack ]].
 	^ result
 !
 

+ 14 - 0
lang/API-CHANGES.txt

@@ -8,11 +8,25 @@
   + beJavaScriptSubclassOf:
   + javaScriptConstructor
   + javaScriptConstructor:
++ BlockClosure >>
+  + tryIfTrue:catch:
++ SmalltalkImage >>
+  + do:on:do:
+  + isError:
 + amber/boot api >>
   + detachClass(klass)
 + amber/helpers exports >>
   + $nil
 
+- Error >>
+  - beSmalltalkError
+  - isSmalltalkError
+- JavaScriptError >>
+  - shouldBeStubbed
+  - wrap
+- MethodContext
+  - stubHere
+  - stubToAtMost:
 - amber/boot api >>
   - addElement(arraySet, el)
   - removeElement(arraySet, el)

+ 2 - 113
lang/src/Kernel-Exceptions.js

@@ -51,25 +51,6 @@ return self;
 }; }),
 $globals.Error);
 
-$core.addMethod(
-$core.method({
-selector: "beSmalltalkError",
-protocol: "accessing",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "beSmalltalkError\x0a\x09smalltalkError := true",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: []
-}, function ($methodClass){ return function (){
-var self=this,$self=this;
-$self.smalltalkError=true;
-return self;
-
-}; }),
-$globals.Error);
-
 $core.addMethod(
 $core.method({
 selector: "beUnhandled",
@@ -168,29 +149,6 @@ return true;
 }; }),
 $globals.Error);
 
-$core.addMethod(
-$core.method({
-selector: "isSmalltalkError",
-protocol: "testing",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "isSmalltalkError\x0a\x09^ smalltalkError == true",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["=="]
-}, function ($methodClass){ return function (){
-var self=this,$self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-return $recv($self.smalltalkError).__eq_eq(true);
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"isSmalltalkError",{})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.Error);
-
 $core.addMethod(
 $core.method({
 selector: "jsStack",
@@ -324,11 +282,11 @@ selector: "signal",
 protocol: "signaling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: [],
-source: "signal\x0a\x09self beUnhandled; context: thisContext; beSmalltalkError; basicSignal",
+source: "signal\x0a\x09self beUnhandled; context: thisContext; basicSignal",
 referencedClasses: [],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["beUnhandled", "context:", "beSmalltalkError", "basicSignal"]
+messageSends: ["beUnhandled", "context:", "basicSignal"]
 }, function ($methodClass){ return function (){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -336,7 +294,6 @@ return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 $self._beUnhandled();
 $self._context_($core.getThisContext());
-$self._beSmalltalkError();
 $self._basicSignal();
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
@@ -680,74 +637,6 @@ return self;
 }; }),
 $globals.JavaScriptException);
 
-$core.addMethod(
-$core.method({
-selector: "shouldBeStubbed",
-protocol: "testing",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "shouldBeStubbed\x0a\x09<inlineJS: 'return $self.exception instanceof RangeError'>",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [["inlineJS:", ["return $self.exception instanceof RangeError"]]],
-messageSends: []
-}, function ($methodClass){ return function (){
-var self=this,$self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-return $self.exception instanceof RangeError;
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"shouldBeStubbed",{})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.JavaScriptException);
-
-$core.addMethod(
-$core.method({
-selector: "wrap",
-protocol: "error handling",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "wrap\x0a\x09[ self signal ] tryCatch:\x0a\x09\x09[ self shouldBeStubbed ifTrue: [ self context stubToAtMost: 100 ] ]",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["tryCatch:", "signal", "ifTrue:", "shouldBeStubbed", "stubToAtMost:", "context"]
-}, function ($methodClass){ return function (){
-var self=this,$self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-var $1;
-$recv((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $self._signal();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
-//>>excludeEnd("ctx");
-}))._tryCatch_((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-$1=$self._shouldBeStubbed();
-if($core.assert($1)){
-return $recv($self._context())._stubToAtMost_((100));
-}
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,2)});
-//>>excludeEnd("ctx");
-}));
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"wrap",{})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.JavaScriptException);
-
 
 $core.addMethod(
 $core.method({

+ 1 - 22
lang/src/Kernel-Exceptions.st

@@ -16,10 +16,6 @@ beHandled
 	amberHandled := true
 !
 
-beSmalltalkError
-	smalltalkError := true
-!
-
 beUnhandled
 	amberHandled := false
 !
@@ -91,7 +87,7 @@ resignal
 !
 
 signal
-	self beUnhandled; context: thisContext; beSmalltalkError; basicSignal
+	self beUnhandled; context: thisContext; basicSignal
 !
 
 signal: aString
@@ -104,10 +100,6 @@ isError
 	^ true
 !
 
-isSmalltalkError
-	^ smalltalkError == true
-!
-
 wasHandled
 	^ amberHandled == true
 ! !
@@ -177,19 +169,6 @@ messageText
 	<inlineJS: 'return "JavaScript exception: " + $self.exception.toString()'>
 ! !
 
-!JavaScriptException methodsFor: 'error handling'!
-
-wrap
-	[ self signal ] tryCatch:
-		[ self shouldBeStubbed ifTrue: [ self context stubToAtMost: 100 ] ]
-! !
-
-!JavaScriptException methodsFor: 'testing'!
-
-shouldBeStubbed
-	<inlineJS: 'return $self.exception instanceof RangeError'>
-! !
-
 !JavaScriptException class methodsFor: 'instance creation'!
 
 on: anException

+ 76 - 11
lang/src/Kernel-Infrastructure.js

@@ -2967,26 +2967,18 @@ selector: "asSmalltalkException:",
 protocol: "error handling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anObject"],
-source: "asSmalltalkException: anObject\x0a\x09\x22A JavaScript exception may be thrown.\x0a\x09We then need to convert it back to a Smalltalk object\x22\x0a\x09\x0a\x09^ ((self isSmalltalkObject: anObject) and: [ anObject isError ])\x0a\x09\x09ifTrue: [ anObject ]\x0a\x09\x09ifFalse: [ JavaScriptException on: anObject ]",
+source: "asSmalltalkException: anObject\x0a\x09\x22A JavaScript exception may be thrown.\x0a\x09We then need to convert it back to a Smalltalk object\x22\x0a\x09\x0a\x09^ (self isError: anObject)\x0a\x09\x09ifTrue: [ anObject ]\x0a\x09\x09ifFalse: [ JavaScriptException on: anObject ]",
 referencedClasses: ["JavaScriptException"],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["ifTrue:ifFalse:", "and:", "isSmalltalkObject:", "isError", "on:"]
+messageSends: ["ifTrue:ifFalse:", "isError:", "on:"]
 }, function ($methodClass){ return function (anObject){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
 var $1;
-$1=$recv($self._isSmalltalkObject_(anObject))._and_((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $recv(anObject)._isError();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
-//>>excludeEnd("ctx");
-}));
+$1=$self._isError_(anObject);
 if($core.assert($1)){
 return anObject;
 } else {
@@ -3251,6 +3243,47 @@ 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:",
@@ -3329,6 +3362,38 @@ return self;
 }; }),
 $globals.SmalltalkImage);
 
+$core.addMethod(
+$core.method({
+selector: "isError:",
+protocol: "testing",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["anObject"],
+source: "isError: anObject\x0a\x09(self isSmalltalkObject: anObject) and: [ anObject isError ]",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [],
+messageSends: ["and:", "isSmalltalkObject:", "isError"]
+}, function ($methodClass){ return function (anObject){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+$recv($self._isSmalltalkObject_(anObject))._and_((function(){
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx2) {
+//>>excludeEnd("ctx");
+return $recv(anObject)._isError();
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
+//>>excludeEnd("ctx");
+}));
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"isError:",{anObject:anObject})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.SmalltalkImage);
+
 $core.addMethod(
 $core.method({
 selector: "isSmalltalkObject:",

+ 17 - 1
lang/src/Kernel-Infrastructure.st

@@ -911,9 +911,21 @@ asSmalltalkException: anObject
 	"A JavaScript exception may be thrown.
 	We then need to convert it back to a Smalltalk object"
 	
-	^ ((self isSmalltalkObject: anObject) and: [ anObject isError ])
+	^ (self isError: anObject)
 		ifTrue: [ 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."
+	
+	| smalltalkError |
+	^ actionBlock
+		tryIfTrue: [ :error |
+			smalltalkError := self asSmalltalkException: error.
+			smalltalkError isKindOf: anErrorClass ]
+		catch: [ aBlock value: smalltalkError ]
 ! !
 
 !SmalltalkImage methodsFor: 'globals'!
@@ -1046,6 +1058,10 @@ existsJsGlobal: aString
 	^ Platform includesGlobal: aString
 !
 
+isError: anObject
+	(self isSmalltalkObject: anObject) and: [ anObject isError ]
+!
+
 isSmalltalkObject: anObject
 	"Consider anObject a Smalltalk object if it has a 'a$cls' property.
 	Note that this may be unaccurate"

+ 36 - 90
lang/src/Kernel-Methods.js

@@ -345,33 +345,17 @@ selector: "on:do:",
 protocol: "error handling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anErrorClass", "aBlock"],
-source: "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^ self tryCatch: [ :error | | smalltalkError |\x0a\x09\x09smalltalkError := Smalltalk asSmalltalkException: error.\x0a\x09\x09(smalltalkError isKindOf: anErrorClass)\x0a\x09\x09ifTrue: [ aBlock value: smalltalkError ]\x0a\x09\x09ifFalse: [ smalltalkError pass ] ]",
+source: "on: anErrorClass do: aBlock\x0a\x09^ Smalltalk do: self on: anErrorClass do: aBlock",
 referencedClasses: ["Smalltalk"],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["tryCatch:", "asSmalltalkException:", "ifTrue:ifFalse:", "isKindOf:", "value:", "pass"]
+messageSends: ["do:on:do:"]
 }, function ($methodClass){ return function (anErrorClass,aBlock){
 var self=this,$self=this;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-return $self._tryCatch_((function(error){
-var smalltalkError;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-smalltalkError=$recv($globals.Smalltalk)._asSmalltalkException_(error);
-$1=$recv(smalltalkError)._isKindOf_(anErrorClass);
-if($core.assert($1)){
-return $recv(aBlock)._value_(smalltalkError);
-} else {
-return $recv(smalltalkError)._pass();
-}
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({error:error,smalltalkError:smalltalkError},$ctx1,1)});
-//>>excludeEnd("ctx");
-}));
+return $recv($globals.Smalltalk)._do_on_do_(self,anErrorClass,aBlock);
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 }, function($ctx1) {$ctx1.fill(self,"on:do:",{anErrorClass:anErrorClass,aBlock:aBlock})});
 //>>excludeEnd("ctx");
@@ -492,6 +476,39 @@ return self;
 }; }),
 $globals.BlockClosure);
 
+$core.addMethod(
+$core.method({
+selector: "tryIfTrue:catch:",
+protocol: "error handling",
+//>>excludeStart("ide", pragmas.excludeIdeData);
+args: ["anotherBlock", "aBlock"],
+source: "tryIfTrue: anotherBlock catch: aBlock\x0a\x09<inlineJS: '\x0a\x09\x09try {\x0a\x09\x09\x09return $self._value();\x0a\x09\x09} catch(error) {\x0a\x09\x09\x09// pass non-local returns undetected\x0a\x09\x09\x09if (Array.isArray(error) && error.length === 1) throw error;\x0a\x09\x09\x09if (!anotherBlock._value_(error)) throw error;\x0a\x09\x09\x09return aBlock._value_(error);\x0a\x09\x09}\x0a\x09'>",
+referencedClasses: [],
+//>>excludeEnd("ide");
+pragmas: [["inlineJS:", ["\x0a\x09\x09try {\x0a\x09\x09\x09return $self._value();\x0a\x09\x09} catch(error) {\x0a\x09\x09\x09// pass non-local returns undetected\x0a\x09\x09\x09if (Array.isArray(error) && error.length === 1) throw error;\x0a\x09\x09\x09if (!anotherBlock._value_(error)) throw error;\x0a\x09\x09\x09return aBlock._value_(error);\x0a\x09\x09}\x0a\x09"]]],
+messageSends: []
+}, function ($methodClass){ return function (anotherBlock,aBlock){
+var self=this,$self=this;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+return $core.withContext(function($ctx1) {
+//>>excludeEnd("ctx");
+
+		try {
+			return $self._value();
+		} catch(error) {
+			// pass non-local returns undetected
+			if (Array.isArray(error) && error.length === 1) throw error;
+			if (!anotherBlock._value_(error)) throw error;
+			return aBlock._value_(error);
+		}
+	;
+return self;
+//>>excludeStart("ctx", pragmas.excludeDebugContexts);
+}, function($ctx1) {$ctx1.fill(self,"tryIfTrue:catch:",{anotherBlock:anotherBlock,aBlock:aBlock})});
+//>>excludeEnd("ctx");
+}; }),
+$globals.BlockClosure);
+
 $core.addMethod(
 $core.method({
 selector: "value",
@@ -2570,77 +2587,6 @@ return $self.sendIdx;
 }; }),
 $globals.MethodContext);
 
-$core.addMethod(
-$core.method({
-selector: "stubHere",
-protocol: "accessing",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: [],
-source: "stubHere\x0a\x09homeContext := JSObjectProxy undefined",
-referencedClasses: ["JSObjectProxy"],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["undefined"]
-}, function ($methodClass){ return function (){
-var self=this,$self=this;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-$self.homeContext=$recv($globals.JSObjectProxy)._undefined();
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"stubHere",{})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.MethodContext);
-
-$core.addMethod(
-$core.method({
-selector: "stubToAtMost:",
-protocol: "error handling",
-//>>excludeStart("ide", pragmas.excludeIdeData);
-args: ["anInteger"],
-source: "stubToAtMost: anInteger\x0a\x09| context |\x0a\x09context := self.\x0a\x09anInteger timesRepeat: [ context := context ifNotNil: [ context home ] ].\x0a\x09context ifNotNil: [ context stubHere ]",
-referencedClasses: [],
-//>>excludeEnd("ide");
-pragmas: [],
-messageSends: ["timesRepeat:", "ifNotNil:", "home", "stubHere"]
-}, function ($methodClass){ return function (anInteger){
-var self=this,$self=this;
-var context;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx1) {
-//>>excludeEnd("ctx");
-var $1,$2,$receiver;
-context=self;
-$recv(anInteger)._timesRepeat_((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-$1=context;
-if(($receiver = $1) == null || $receiver.a$nil){
-context=$1;
-} else {
-context=$recv(context)._home();
-}
-return context;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
-//>>excludeEnd("ctx");
-}));
-$2=context;
-if(($receiver = $2) == null || $receiver.a$nil){
-$2;
-} else {
-$recv(context)._stubHere();
-}
-return self;
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"stubToAtMost:",{anInteger:anInteger,context:context})});
-//>>excludeEnd("ctx");
-}; }),
-$globals.MethodContext);
-
 $core.addMethod(
 $core.method({
 selector: "supercall",

+ 14 - 21
lang/src/Kernel-Methods.st

@@ -103,14 +103,7 @@ provided
 !BlockClosure methodsFor: 'error handling'!
 
 on: anErrorClass do: aBlock
-	"All exceptions thrown in the Smalltalk stack are cought.
-	Convert all JS exceptions to JavaScriptException instances."
-	
-	^ self tryCatch: [ :error | | smalltalkError |
-		smalltalkError := Smalltalk asSmalltalkException: error.
-		(smalltalkError isKindOf: anErrorClass)
-		ifTrue: [ aBlock value: smalltalkError ]
-		ifFalse: [ smalltalkError pass ] ]
+	^ Smalltalk do: self on: anErrorClass do: aBlock
 !
 
 tryCatch: aBlock
@@ -123,6 +116,19 @@ tryCatch: aBlock
 			return aBlock._value_(error);
 		}
 	'>
+!
+
+tryIfTrue: anotherBlock catch: aBlock
+	<inlineJS: '
+		try {
+			return $self._value();
+		} catch(error) {
+			// pass non-local returns undetected
+			if (Array.isArray(error) && error.length === 1) throw error;
+			if (!!anotherBlock._value_(error)) throw error;
+			return aBlock._value_(error);
+		}
+	'>
 ! !
 
 !BlockClosure methodsFor: 'evaluating'!
@@ -665,23 +671,10 @@ sendIndexes
 	^ sendIdx
 !
 
-stubHere
-	homeContext := JSObjectProxy undefined
-!
-
 supercall
 	^ supercall = true
 ! !
 
-!MethodContext methodsFor: 'error handling'!
-
-stubToAtMost: anInteger
-	| context |
-	context := self.
-	anInteger timesRepeat: [ context := context ifNotNil: [ context home ] ].
-	context ifNotNil: [ context stubHere ]
-! !
-
 Object subclass: #NativeFunction
 	slots: {}
 	package: 'Kernel-Methods'!

+ 16 - 45
lang/src/Platform-Services.js

@@ -735,32 +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\x09aBlock tryCatch: [ :exception | \x0a\x09\x09(exception isKindOf: (self classNamed: anErrorClass name))\x0a\x09\x09\x09ifTrue: [ exceptionBlock value: exception ]\x0a \x09\x09\x09ifFalse: [ exception pass ] ]",
-referencedClasses: [],
+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"],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["tryCatch:", "ifTrue:ifFalse:", "isKindOf:", "classNamed:", "name", "value:", "pass"]
+messageSends: ["do: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");
-var $1;
-$recv(aBlock)._tryCatch_((function(exception){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-$1=$recv(exception)._isKindOf_($self._classNamed_($recv(anErrorClass)._name()));
-if($core.assert($1)){
-return $recv(exceptionBlock)._value_(exception);
-} else {
-return $recv(exception)._pass();
-}
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({exception:exception},$ctx1,1)});
-//>>excludeEnd("ctx");
-}));
-return self;
+return $recv($globals.Smalltalk)._do_on_do_(aBlock,$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");
@@ -1427,43 +1412,29 @@ selector: "handleError:",
 protocol: "error handling",
 //>>excludeStart("ide", pragmas.excludeIdeData);
 args: ["anError"],
-source: "handleError: anError\x0a\x09([ anError isSmalltalkError ] tryCatch: [ false ])\x0a\x09\x09ifTrue: [ self handleUnhandledError: anError ]\x0a\x09\x09ifFalse: [\x0a\x09\x09\x09| smalltalkError |\x0a\x09\x09\x09smalltalkError := JavaScriptException on: anError.\x0a\x09\x09\x09smalltalkError wrap.\x0a\x09\x09\x09self handleUnhandledError: smalltalkError ]",
-referencedClasses: ["JavaScriptException"],
+source: "handleError: anError\x0a\x09| smalltalkError |\x0a\x09smalltalkError := Smalltalk asSmalltalkException: anError.\x0a\x09smalltalkError context ifNil: [ smalltalkError context: thisContext ].\x0a\x09self handleUnhandledError: smalltalkError",
+referencedClasses: ["Smalltalk"],
 //>>excludeEnd("ide");
 pragmas: [],
-messageSends: ["ifTrue:ifFalse:", "tryCatch:", "isSmalltalkError", "handleUnhandledError:", "on:", "wrap"]
+messageSends: ["asSmalltalkException:", "ifNil:", "context", "context:", "handleUnhandledError:"]
 }, function ($methodClass){ return function (anError){
 var self=this,$self=this;
+var smalltalkError;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
 return $core.withContext(function($ctx1) {
 //>>excludeEnd("ctx");
-var $1;
-$1=$recv((function(){
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-return $core.withContext(function($ctx2) {
-//>>excludeEnd("ctx");
-return $recv(anError)._isSmalltalkError();
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx2) {$ctx2.fillBlock({},$ctx1,1)});
-//>>excludeEnd("ctx");
-}))._tryCatch_((function(){
-return false;
-
-}));
-if($core.assert($1)){
-$self._handleUnhandledError_(anError);
-//>>excludeStart("ctx", pragmas.excludeDebugContexts);
-$ctx1.sendIdx["handleUnhandledError:"]=1;
-//>>excludeEnd("ctx");
+var $1,$receiver;
+smalltalkError=$recv($globals.Smalltalk)._asSmalltalkException_(anError);
+$1=$recv(smalltalkError)._context();
+if(($receiver = $1) == null || $receiver.a$nil){
+$recv(smalltalkError)._context_($core.getThisContext());
 } else {
-var smalltalkError;
-smalltalkError=$recv($globals.JavaScriptException)._on_(anError);
-$recv(smalltalkError)._wrap();
-$self._handleUnhandledError_(smalltalkError);
+$1;
 }
+$self._handleUnhandledError_(smalltalkError);
 return self;
 //>>excludeStart("ctx", pragmas.excludeDebugContexts);
-}, function($ctx1) {$ctx1.fill(self,"handleError:",{anError:anError})});
+}, function($ctx1) {$ctx1.fill(self,"handleError:",{anError:anError,smalltalkError:smalltalkError})});
 //>>excludeEnd("ctx");
 }; }),
 $globals.ErrorHandler.a$cls);

+ 5 - 11
lang/src/Platform-Services.st

@@ -257,10 +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"
 	
-	aBlock tryCatch: [ :exception | 
-		(exception isKindOf: (self classNamed: anErrorClass name))
-			ifTrue: [ exceptionBlock value: exception ]
- 			ifFalse: [ exception pass ] ]
+	^ Smalltalk do: aBlock on: (self classNamed: anErrorClass name) do: exceptionBlock
 ! !
 
 !Environment methodsFor: 'evaluating'!
@@ -359,13 +356,10 @@ Registered service instances must implement `#handleError:` to perform an action
 !ErrorHandler class methodsFor: 'error handling'!
 
 handleError: anError
-	([ anError isSmalltalkError ] tryCatch: [ false ])
-		ifTrue: [ self handleUnhandledError: anError ]
-		ifFalse: [
-			| smalltalkError |
-			smalltalkError := JavaScriptException on: anError.
-			smalltalkError wrap.
-			self handleUnhandledError: smalltalkError ]
+	| smalltalkError |
+	smalltalkError := Smalltalk asSmalltalkException: anError.
+	smalltalkError context ifNil: [ smalltalkError context: thisContext ].
+	self handleUnhandledError: smalltalkError
 !
 
 handleUnhandledError: anError