From 51106474122d0e5aec8e3d5da5bb66cfe8062f55 Mon Sep 17 00:00:00 2001 From: Michael Trotter Date: Sat, 9 Apr 2016 16:50:47 -0600 Subject: [PATCH 1/2] Initial pass on catch rewriting; needs review! --- src/Control/Monad/Aff.js | 138 +++++++++++++++------------------------ 1 file changed, 53 insertions(+), 85 deletions(-) diff --git a/src/Control/Monad/Aff.js b/src/Control/Monad/Aff.js index 0829cc3..b5b6603 100644 --- a/src/Control/Monad/Aff.js +++ b/src/Control/Monad/Aff.js @@ -16,18 +16,13 @@ exports._cancelWith = function (nonCanceler, aff, canceler1) { result = result || bool; if (cancellations === 2 && !errored) { - try { - success(result); - } catch (err) { - error(err); - } + success(result); } }; var f = function(err) { if (!errored) { errored = true; - error(err); } }; @@ -60,13 +55,7 @@ exports._setTimeout = function (nonCanceler, millis, aff) { return canceler(e)(s, f); } else { clear(timeout); - - try { - s(true); - } catch (err) { - f(err); - } - + s(true); return nonCanceler; } }; @@ -83,13 +72,7 @@ exports._forkAff = function (nonCanceler, aff) { return function(success, error) { var canceler = aff(voidF, voidF); - - try { - success(canceler); - } catch (err) { - error(err); - } - + success(canceler); return nonCanceler; }; } @@ -98,12 +81,16 @@ exports._forkAll = function (nonCanceler, foldl, affs) { var voidF = function(){}; return function(success, error) { - var cancelers = foldl(function(acc) { - return function(aff) { - acc.push(aff(voidF, voidF)); - return acc; - } - })([])(affs); + try { + var cancelers = foldl(function(acc) { + return function(aff) { + acc.push(aff(voidF, voidF)); + return acc; + } + })([])(affs); + } catch (err) { + error(err) + } var canceler = function(e) { return function(success, error) { @@ -116,11 +103,7 @@ exports._forkAll = function (nonCanceler, foldl, affs) { result = result || bool; if (cancellations === cancelers.length && !errored) { - try { - success(result); - } catch (err) { - error(err); - } + success(result); } }; @@ -139,42 +122,32 @@ exports._forkAll = function (nonCanceler, foldl, affs) { }; }; - try { - success(canceler); - } catch (err) { - error(err); - } - + success(canceler); return nonCanceler; }; } exports._makeAff = function (cb) { return function(success, error) { - return cb(function(e) { - return function() { - error(e); - }; - })(function(v) { - return function() { - try { + try { + return cb(function(e) { + return function() { + error(e); + }; + })(function(v) { + return function() { success(v); - } catch (err) { - error(err); - } - }; - })(); + }; + })(); + } catch (err) { + error(err); + } } } exports._pure = function (nonCanceler, v) { return function(success, error) { - try { - success(v); - } catch (err) { - error(err); - } - + success(v); return nonCanceler; }; } @@ -182,20 +155,24 @@ exports._pure = function (nonCanceler, v) { exports._throwError = function (nonCanceler, e) { return function(success, error) { error(e); - return nonCanceler; }; } exports._fmap = function (f, aff) { return function(success, error) { - return aff(function(v) { - try { - success(f(v)); - } catch (err) { - error(err); - } - }, error); + try { + return aff(function(v) { + try { + var v2 = f(v); + } catch (err) { + error(err) + } + success(v2); + }, error); + } catch (err) { + error(err); + } }; } @@ -231,11 +208,7 @@ exports._bind = function (alwaysCanceler, aff, f) { } else { return canceler1(e)(function(bool) { if (bool || isCanceled) { - try { - s(true); - } catch (err) { - f(err); - } + s(true); } else { onCanceler = function(canceler) { canceler(e)(s, f); @@ -250,30 +223,22 @@ exports._bind = function (alwaysCanceler, aff, f) { exports._attempt = function (Left, Right, aff) { return function(success, error) { - return aff(function(v) { - try { + try { + return aff(function(v) { success(Right(v)); - } catch (err) { - error(err); - } - }, function(e) { - try { + }, function(e) { success(Left(e)); - } catch (err) { - error(err); - } - }); + }); + } catch (err) { + success(Left(err)); + } }; } exports._runAff = function (errorT, successT, aff) { return function() { return aff(function(v) { - try { - successT(v)(); - } catch (err) { - errorT(err)(); - } + successT(v)(); }, function(e) { errorT(e)(); }); @@ -282,12 +247,15 @@ exports._runAff = function (errorT, successT, aff) { exports._liftEff = function (nonCanceler, e) { return function(success, error) { + var result; try { - success(e()); + result = e(); } catch (err) { error(err); + return nonCanceler; } + success(result); return nonCanceler; }; } From 09f6c373dd93c20ded5d046c75bc0895dfa6c16a Mon Sep 17 00:00:00 2001 From: Michael Trotter Date: Sat, 9 Apr 2016 23:45:21 -0600 Subject: [PATCH 2/2] Adds tests for makeAff paths --- bower.json | 3 +++ test/Test/Main.js | 5 +++++ test/Test/Main.purs | 27 ++++++++++++++++++++++----- 3 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 test/Test/Main.js diff --git a/bower.json b/bower.json index 03fbf79..1499e9f 100644 --- a/bower.json +++ b/bower.json @@ -21,5 +21,8 @@ "purescript-exceptions": "^1.0.0", "purescript-functions": "^1.0.0", "purescript-transformers": "^1.0.0" + }, + "devDependencies": { + "purescript-partial": "^1.1.2" } } diff --git a/test/Test/Main.js b/test/Test/Main.js new file mode 100644 index 0000000..69489bc --- /dev/null +++ b/test/Test/Main.js @@ -0,0 +1,5 @@ +"use strict"; + +exports.synchronousUnexpectedThrowError = function() { + throw new Error("ok"); +}; diff --git a/test/Test/Main.purs b/test/Test/Main.purs index 71e3c05..0e75f44 100644 --- a/test/Test/Main.purs +++ b/test/Test/Main.purs @@ -4,19 +4,19 @@ import Prelude import Control.Alt ((<|>)) import Control.Apply ((*>)) -import Control.Monad.Aff (Aff, runAff, later, later', forkAff, forkAll, Canceler(..), cancel, attempt, finally, apathize) +import Control.Monad.Aff (Aff, runAff, makeAff, later, later', forkAff, forkAll, Canceler(..), cancel, attempt, finally, apathize) import Control.Monad.Aff.AVar (AVAR, makeVar, makeVar', putVar, modifyVar, takeVar, killVar) import Control.Monad.Aff.Console (log) import Control.Monad.Aff.Par (Par(..), runPar) import Control.Monad.Cont.Class (callCC) import Control.Monad.Eff (Eff) import Control.Monad.Eff.Console (CONSOLE) -import Control.Monad.Eff.Exception (EXCEPTION, throwException, error) +import Control.Monad.Eff.Exception (EXCEPTION, throwException, error, message) import Control.Monad.Error.Class (throwError) import Control.Monad.Rec.Class (tailRecM) - -import Data.Either (Either(..), either) +import Data.Either (Either(..), either, fromLeft, fromRight) import Data.Unfoldable (replicate) +import Partial.Unsafe (unsafePartial) type Test a = forall e. Aff (console :: CONSOLE | e) a type TestAVar a = forall e. Aff (console :: CONSOLE, avar :: AVAR | e) a @@ -30,6 +30,21 @@ test_sequencing n = do later' 100 (log (show (n / 10) <> " seconds left")) test_sequencing (n - 1) +foreign import synchronousUnexpectedThrowError :: forall e. Eff e Unit + +test_makeAff :: Test Unit +test_makeAff = unsafePartial do + s <- attempt $ makeAff \reject resolve -> resolve "ok" + log $ "makeAff success is " <> fromRight s + + asyncF <- attempt $ makeAff \reject resolve -> reject (error "ok") + log $ "makeAff asynchronous failure is " <> message (fromLeft asyncF) + + asyncF <- attempt $ makeAff \reject resolve -> synchronousUnexpectedThrowError + log $ "makeAff synchronous failure is " <> message (fromLeft asyncF) + + log "Success: makeAff is ok" + test_pure :: Test Unit test_pure = do pure unit @@ -60,7 +75,6 @@ test_killFirstForked = do b <- c `cancel` (error "Just die") log (if b then "Success: Killed first forked" else "Failure: Couldn't kill first forked") - test_killVar :: TestAVar Unit test_killVar = do v <- makeVar @@ -180,6 +194,9 @@ main = runAff throwException (const (pure unit)) $ do log "Testing pure" test_pure + log "Testing makeAff" + test_makeAff + log "Testing attempt" test_attempt