diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,9 @@
+### 3.1.15.0
+
+- Add `INLINABLE` pragmas to most overloaded combinators
+- Support recent versions of dependencies
+- Fix memory leak in `>>=` https://github.com/haskell/parsec/issues/127
+
 ### 3.1.14.0
 
 - Add `parseFromFile` to `Text.Parsec.Text.Lazy` and `Text.Parsec.Text` (#103, #104).
diff --git a/parsec.cabal b/parsec.cabal
--- a/parsec.cabal
+++ b/parsec.cabal
@@ -1,6 +1,6 @@
 cabal-version:  1.12
 name:           parsec
-version:        3.1.14.0
+version:        3.1.15.0
 
 synopsis:       Monadic parser combinators
 description:    Parsec is designed from scratch as an industrial-strength parser
@@ -17,16 +17,16 @@
                 the legacy @parsec-2@ API and may be removed at some point in
                 the future.
 
-license:        BSD3
+license:        BSD2
 license-file:   LICENSE
 author:         Daan Leijen <daan@microsoft.com>, Paolo Martini <paolo@nemail.it>, Antoine Latter <aslatter@gmail.com>
-maintainer:     Herbert Valerio Riedel <hvr@gnu.org>
+maintainer:     Oleg Grenrus <oleg.grenrus@iki.fi>, Herbert Valerio Riedel <hvr@gnu.org>
 homepage:       https://github.com/haskell/parsec
 bug-reports:    https://github.com/haskell/parsec/issues
 category:       Parsing
 
 build-type:     Simple
-tested-with:    GHC ==8.6.1 || ==8.4.3 || ==8.2.2 || ==8.0.2 || ==7.10.3 || ==7.8.4 || ==7.6.3 || ==7.4.2 || ==7.4.1
+tested-with:    GHC ==9.2.1 || ==9.0.1 || ==8.10.7 || ==8.8.4 || ==8.6.5 || ==8.4.4 || ==8.2.2 || ==8.0.2 || ==7.10.3 || ==7.8.4 || ==7.6.3 || ==7.4.2 || ==7.4.1
 
 extra-source-files: ChangeLog.md, README.md
 
@@ -64,11 +64,12 @@
         Text.ParserCombinators.Parsec.Token
 
     build-depends:
-        base       >= 4.5.0   && < 4.14,
+        base       >= 4.5.0   && < 4.17,
         mtl        >= 1.1.1   && < 2.3,
-        bytestring >= 0.9.2.1 && < 0.11,
+        bytestring >= 0.9.2.1 && < 0.12,
         text      (>= 0.11.3.1 && < 0.12)
                || (>= 1.0.0.0  && < 1.3)
+               || (>= 2.0 && < 2.1)
 
     default-language: Haskell2010
     other-extensions:
@@ -92,7 +93,7 @@
           ghc-options: -Wnoncanonical-monadfail-instances
     else
         -- provide/emulate `Control.Monad.Fail` and `Semigroup` API for pre-GHC8
-        build-depends: fail == 4.9.*, semigroups >= 0.18 && < 0.20
+        build-depends: fail == 4.9.*, semigroups >= 0.18 && < 0.21
 
         if impl(ghc >= 7.10)
             ghc-options: -fno-warn-trustworthy-safe
@@ -117,9 +118,8 @@
         mtl,
         parsec,
         -- dependencies whose version bounds are not inherited via lib:parsec
-        HUnit                == 1.6.* || (>= 1.3.1.2 && < 1.4),
-        test-framework       == 0.8.*,
-        test-framework-hunit == 0.3.*
+        tasty >= 1.4 && < 1.5,
+        tasty-hunit >= 0.10 && < 0.11
 
     default-language: Haskell2010
 
@@ -128,3 +128,10 @@
         ghc-options: -Wcompat -Wnoncanonical-monad-instances -Wnoncanonical-monadfail-instances
     else
         build-depends: semigroups
+
+test-suite parsec-issue127
+    default-language: Haskell2010
+    type: exitcode-stdio-1.0
+    main-is: issue127.hs
+    hs-source-dirs: test
+    build-depends: base, parsec
diff --git a/src/Text/Parsec/ByteString.hs b/src/Text/Parsec/ByteString.hs
--- a/src/Text/Parsec/ByteString.hs
+++ b/src/Text/Parsec/ByteString.hs
@@ -18,10 +18,10 @@
     ( Parser, GenParser, parseFromFile
     ) where
 
+import qualified Data.ByteString.Char8 as C
+
 import Text.Parsec.Error
 import Text.Parsec.Prim
-
-import qualified Data.ByteString.Char8 as C
 
 type Parser = Parsec C.ByteString ()
 type GenParser t st = Parsec C.ByteString st
diff --git a/src/Text/Parsec/ByteString/Lazy.hs b/src/Text/Parsec/ByteString/Lazy.hs
--- a/src/Text/Parsec/ByteString/Lazy.hs
+++ b/src/Text/Parsec/ByteString/Lazy.hs
@@ -18,10 +18,10 @@
     ( Parser, GenParser, parseFromFile
     ) where
 
+import qualified Data.ByteString.Lazy.Char8 as C
+
 import Text.Parsec.Error
 import Text.Parsec.Prim
-
-import qualified Data.ByteString.Lazy.Char8 as C
 
 type Parser = Parsec C.ByteString ()
 type GenParser t st = Parsec C.ByteString st
diff --git a/src/Text/Parsec/Char.hs b/src/Text/Parsec/Char.hs
--- a/src/Text/Parsec/Char.hs
+++ b/src/Text/Parsec/Char.hs
@@ -16,13 +16,14 @@
 
 module Text.Parsec.Char where
 
-import Data.Char
-import Text.Parsec.Pos
-import Text.Parsec.Prim
+import Data.Char (isSpace, isUpper, isLower, isAlphaNum, isAlpha, isDigit, isHexDigit, isOctDigit)
 #if !(MIN_VERSION_base(4,8,0))
 import Control.Applicative ((*>))
 #endif
 
+import Text.Parsec.Pos
+import Text.Parsec.Prim
+
 -- | @oneOf cs@ succeeds if the current character is in the supplied
 -- list of characters @cs@. Returns the parsed character. See also
 -- 'satisfy'.
@@ -30,6 +31,7 @@
 -- >   vowel  = oneOf "aeiou"
 
 oneOf :: (Stream s m Char) => [Char] -> ParsecT s u m Char
+{-# INLINABLE oneOf #-}
 oneOf cs            = satisfy (\c -> elem c cs)
 
 -- | As the dual of 'oneOf', @noneOf cs@ succeeds if the current
@@ -39,28 +41,33 @@
 -- >  consonant = noneOf "aeiou"
 
 noneOf :: (Stream s m Char) => [Char] -> ParsecT s u m Char
+{-# INLINABLE noneOf #-}
 noneOf cs           = satisfy (\c -> not (elem c cs))
 
 -- | Skips /zero/ or more white space characters. See also 'skipMany'.
 
 spaces :: (Stream s m Char) => ParsecT s u m ()
+{-# INLINABLE spaces #-}
 spaces              = skipMany space        <?> "white space"
 
 -- | Parses a white space character (any character which satisfies 'isSpace')
 -- Returns the parsed character.
 
 space :: (Stream s m Char) => ParsecT s u m Char
+{-# INLINABLE space #-}
 space               = satisfy isSpace       <?> "space"
 
 -- | Parses a newline character (\'\\n\'). Returns a newline character.
 
 newline :: (Stream s m Char) => ParsecT s u m Char
+{-# INLINABLE newline #-}
 newline             = char '\n'             <?> "lf new-line"
 
 -- | Parses a carriage return character (\'\\r\') followed by a newline character (\'\\n\').
 -- Returns a newline character.
 
 crlf :: (Stream s m Char) => ParsecT s u m Char
+{-# INLINABLE crlf #-}
 crlf                = char '\r' *> char '\n' <?> "crlf new-line"
 
 -- | Parses a CRLF (see 'crlf') or LF (see 'newline') end-of-line.
@@ -70,23 +77,27 @@
 --
 
 endOfLine :: (Stream s m Char) => ParsecT s u m Char
+{-# INLINABLE endOfLine #-}
 endOfLine           = newline <|> crlf       <?> "new-line"
 
 -- | Parses a tab character (\'\\t\'). Returns a tab character.
 
 tab :: (Stream s m Char) => ParsecT s u m Char
+{-# INLINABLE tab #-}
 tab                 = char '\t'             <?> "tab"
 
 -- | Parses an upper case letter (according to 'isUpper').
 -- Returns the parsed character.
 
 upper :: (Stream s m Char) => ParsecT s u m Char
+{-# INLINABLE upper #-}
 upper               = satisfy isUpper       <?> "uppercase letter"
 
 -- | Parses a lower case character (according to 'isLower').
 -- Returns the parsed character.
 
 lower :: (Stream s m Char) => ParsecT s u m Char
+{-# INLINABLE lower #-}
 lower               = satisfy isLower       <?> "lowercase letter"
 
 -- | Parses a alphabetic or numeric Unicode characters
@@ -97,6 +108,7 @@
 -- but not by 'digit'.
 
 alphaNum :: (Stream s m Char => ParsecT s u m Char)
+{-# INLINABLE alphaNum #-}
 alphaNum            = satisfy isAlphaNum    <?> "letter or digit"
 
 -- | Parses an alphabetic Unicode characters (lower-case, upper-case and title-case letters,
@@ -104,23 +116,27 @@
 -- Returns the parsed character.
 
 letter :: (Stream s m Char) => ParsecT s u m Char
+{-# INLINABLE letter #-}
 letter              = satisfy isAlpha       <?> "letter"
 
 -- | Parses an ASCII digit. Returns the parsed character.
 
 digit :: (Stream s m Char) => ParsecT s u m Char
+{-# INLINABLE digit #-}
 digit               = satisfy isDigit       <?> "digit"
 
 -- | Parses a hexadecimal digit (a digit or a letter between \'a\' and
 -- \'f\' or \'A\' and \'F\'). Returns the parsed character.
 
 hexDigit :: (Stream s m Char) => ParsecT s u m Char
+{-# INLINABLE hexDigit #-}
 hexDigit            = satisfy isHexDigit    <?> "hexadecimal digit"
 
 -- | Parses an octal digit (a character between \'0\' and \'7\'). Returns
 -- the parsed character.
 
 octDigit :: (Stream s m Char) => ParsecT s u m Char
+{-# INLINABLE octDigit #-}
 octDigit            = satisfy isOctDigit    <?> "octal digit"
 
 -- | @char c@ parses a single character @c@. Returns the parsed
@@ -129,11 +145,13 @@
 -- >  semiColon  = char ';'
 
 char :: (Stream s m Char) => Char -> ParsecT s u m Char
+{-# INLINABLE char #-}
 char c              = satisfy (==c)  <?> show [c]
 
 -- | This parser succeeds for any character. Returns the parsed character.
 
 anyChar :: (Stream s m Char) => ParsecT s u m Char
+{-# INLINABLE anyChar #-}
 anyChar             = satisfy (const True)
 
 -- | The parser @satisfy f@ succeeds for any character for which the
@@ -144,6 +162,7 @@
 -- >  oneOf cs  = satisfy (\c -> c `elem` cs)
 
 satisfy :: (Stream s m Char) => (Char -> Bool) -> ParsecT s u m Char
+{-# INLINABLE satisfy #-}
 satisfy f           = tokenPrim (\c -> show [c])
                                 (\pos c _cs -> updatePosChar pos c)
                                 (\c -> if f c then Just c else Nothing)
@@ -155,4 +174,5 @@
 -- >              <|> string "mod"
 
 string :: (Stream s m Char) => String -> ParsecT s u m String
+{-# INLINABLE string #-}
 string s            = tokens show updatePosString s
diff --git a/src/Text/Parsec/Combinator.hs b/src/Text/Parsec/Combinator.hs
--- a/src/Text/Parsec/Combinator.hs
+++ b/src/Text/Parsec/Combinator.hs
@@ -42,15 +42,17 @@
     , parserTrace, parserTraced
     ) where
 
-import Control.Monad
-import Text.Parsec.Prim
+import Control.Monad (mzero, liftM)
 import Debug.Trace (trace)
 
+import Text.Parsec.Prim
+
 -- | @choice ps@ tries to apply the parsers in the list @ps@ in order,
 -- until one of them succeeds. Returns the value of the succeeding
 -- parser.
 
 choice :: (Stream s m t) => [ParsecT s u m a] -> ParsecT s u m a
+{-# INLINABLE choice #-}
 choice ps           = foldr (<|>) mzero ps
 
 -- | @option x p@ tries to apply parser @p@. If @p@ fails without
@@ -62,6 +64,7 @@
 -- >                          })
 
 option :: (Stream s m t) => a -> ParsecT s u m a -> ParsecT s u m a
+{-# INLINABLE option #-}
 option x p          = p <|> return x
 
 -- | @optionMaybe p@ tries to apply parser @p@.  If @p@ fails without
@@ -69,6 +72,7 @@
 -- 'Just' the value returned by @p@.
 
 optionMaybe :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m (Maybe a)
+{-# INLINABLE optionMaybe #-}
 optionMaybe p       = option Nothing (liftM Just p)
 
 -- | @optional p@ tries to apply parser @p@.  It will parse @p@ or nothing.
@@ -76,6 +80,7 @@
 -- of @p@.
 
 optional :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m ()
+{-# INLINABLE optional #-}
 optional p          = do{ _ <- p; return ()} <|> return ()
 
 -- | @between open close p@ parses @open@, followed by @p@ and @close@.
@@ -85,6 +90,7 @@
 
 between :: (Stream s m t) => ParsecT s u m open -> ParsecT s u m close
             -> ParsecT s u m a -> ParsecT s u m a
+{-# INLINABLE between #-}
 between open close p
                     = do{ _ <- open; x <- p; _ <- close; return x }
 
@@ -92,6 +98,7 @@
 -- its result.
 
 skipMany1 :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m ()
+{-# INLINABLE skipMany1 #-}
 skipMany1 p         = do{ _ <- p; skipMany p }
 {-
 skipMany p          = scan
@@ -105,6 +112,7 @@
 -- >  word  = many1 letter
 
 many1 :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m [a]
+{-# INLINABLE many1 #-}
 many1 p             = do{ x <- p; xs <- many p; return (x:xs) }
 {-
 many p              = scan id
@@ -122,12 +130,14 @@
 -- >  commaSep p  = p `sepBy` (symbol ",")
 
 sepBy :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m sep -> ParsecT s u m [a]
+{-# INLINABLE sepBy #-}
 sepBy p sep         = sepBy1 p sep <|> return []
 
 -- | @sepBy1 p sep@ parses /one/ or more occurrences of @p@, separated
 -- by @sep@. Returns a list of values returned by @p@.
 
 sepBy1 :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m sep -> ParsecT s u m [a]
+{-# INLINABLE sepBy1 #-}
 sepBy1 p sep        = do{ x <- p
                         ; xs <- many (sep >> p)
                         ; return (x:xs)
@@ -139,6 +149,7 @@
 -- returned by @p@.
 
 sepEndBy1 :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m sep -> ParsecT s u m [a]
+{-# INLINABLE sepEndBy1 #-}
 sepEndBy1 p sep     = do{ x <- p
                         ; do{ _ <- sep
                             ; xs <- sepEndBy p sep
@@ -154,6 +165,7 @@
 -- >  haskellStatements  = haskellStatement `sepEndBy` semi
 
 sepEndBy :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m sep -> ParsecT s u m [a]
+{-# INLINABLE sepEndBy #-}
 sepEndBy p sep      = sepEndBy1 p sep <|> return []
 
 
@@ -161,6 +173,7 @@
 -- and ended by @sep@. Returns a list of values returned by @p@.
 
 endBy1 :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m sep -> ParsecT s u m [a]
+{-# INLINABLE endBy1 #-}
 endBy1 p sep        = many1 (do{ x <- p; _ <- sep; return x })
 
 -- | @endBy p sep@ parses /zero/ or more occurrences of @p@, separated
@@ -169,6 +182,7 @@
 -- >   cStatements  = cStatement `endBy` semi
 
 endBy :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m sep -> ParsecT s u m [a]
+{-# INLINABLE endBy #-}
 endBy p sep         = many (do{ x <- p; _ <- sep; return x })
 
 -- | @count n p@ parses @n@ occurrences of @p@. If @n@ is smaller or
@@ -176,6 +190,7 @@
 -- @n@ values returned by @p@.
 
 count :: (Stream s m t) => Int -> ParsecT s u m a -> ParsecT s u m [a]
+{-# INLINABLE count #-}
 count n p           | n <= 0    = return []
                     | otherwise = sequence (replicate n p)
 
@@ -186,6 +201,7 @@
 -- returned.
 
 chainr :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m (a -> a -> a) -> a -> ParsecT s u m a
+{-# INLINABLE chainr #-}
 chainr p op x       = chainr1 p op <|> return x
 
 -- | @chainl p op x@ parses /zero/ or more occurrences of @p@,
@@ -195,6 +211,7 @@
 -- returned.
 
 chainl :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m (a -> a -> a) -> a -> ParsecT s u m a
+{-# INLINABLE chainl #-}
 chainl p op x       = chainl1 p op <|> return x
 
 -- | @chainl1 p op@ parses /one/ or more occurrences of @p@,
@@ -214,6 +231,7 @@
 -- >          <|> do{ symbol "-"; return (-) }
 
 chainl1 :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m (a -> a -> a) -> ParsecT s u m a
+{-# INLINABLE chainl1 #-}
 chainl1 p op        = do{ x <- p; rest x }
                     where
                       rest x    = do{ f <- op
@@ -228,6 +246,7 @@
 -- by @p@.
 
 chainr1 :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m (a -> a -> a) -> ParsecT s u m a
+{-# INLINABLE chainr1 #-}
 chainr1 p op        = scan
                     where
                       scan      = do{ x <- p; rest x }
@@ -245,6 +264,7 @@
 -- used to implement 'eof'. Returns the accepted token.
 
 anyToken :: (Stream s m t, Show t) => ParsecT s u m t
+{-# INLINABLE anyToken #-}
 anyToken            = tokenPrim show (\pos _tok _toks -> pos) Just
 
 -- | This parser only succeeds at the end of the input. This is not a
@@ -253,6 +273,7 @@
 -- >  eof  = notFollowedBy anyToken <?> "end of input"
 
 eof :: (Stream s m t, Show t) => ParsecT s u m ()
+{-# INLINABLE eof #-}
 eof                 = notFollowedBy anyToken <?> "end of input"
 
 -- | @notFollowedBy p@ only succeeds when parser @p@ fails. This parser
@@ -279,6 +300,7 @@
 -- for more details.
 
 notFollowedBy :: (Stream s m t, Show a) => ParsecT s u m a -> ParsecT s u m ()
+{-# INLINABLE notFollowedBy #-}
 notFollowedBy p     = try (do{ c <- try p; unexpected (show c) }
                            <|> return ()
                           )
@@ -295,6 +317,7 @@
 --    therefore the use of the 'try' combinator.
 
 manyTill :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m end -> ParsecT s u m [a]
+{-# INLINABLE manyTill #-}
 manyTill p end      = scan
                     where
                       scan  = do{ _ <- end; return [] }
@@ -311,6 +334,7 @@
 --
 -- @since 3.1.12.0
 parserTrace :: (Show t, Stream s m t) => String -> ParsecT s u m ()
+{-# INLINABLE parserTrace #-}
 parserTrace s = pt <|> return ()
     where
         pt = try $ do
@@ -332,6 +356,7 @@
 --
 -- @since 3.1.12.0
 parserTraced :: (Stream s m t, Show t) => String -> ParsecT s u m b -> ParsecT s u m b
+{-# INLINABLE parserTraced #-}
 parserTraced s p = do
   parserTrace s
   p <|> trace (s ++ " backtracked") (fail s)
diff --git a/src/Text/Parsec/Expr.hs b/src/Text/Parsec/Expr.hs
--- a/src/Text/Parsec/Expr.hs
+++ b/src/Text/Parsec/Expr.hs
@@ -96,6 +96,7 @@
                       => OperatorTable s u m a
                       -> ParsecT s u m a
                       -> ParsecT s u m a
+{-# INLINABLE buildExpressionParser #-}
 buildExpressionParser operators simpleExpr
     = foldl (makeParser) simpleExpr operators
     where
diff --git a/src/Text/Parsec/Perm.hs b/src/Text/Parsec/Perm.hs
--- a/src/Text/Parsec/Perm.hs
+++ b/src/Text/Parsec/Perm.hs
@@ -41,15 +41,15 @@
     , (<|?>), (<$?>)
     ) where
 
-import Text.Parsec
-
-import Control.Monad.Identity
+import Control.Monad.Identity ( Identity )
 #if MIN_VERSION_base(4,7,0)
 import Data.Typeable ( Typeable )
 #else
 -- For GHC 7.6
 import Data.Typeable ( Typeable3 )
 #endif
+
+import Text.Parsec
 
 infixl 1 <||>, <|?>
 infixl 2 <$$>, <$?>
diff --git a/src/Text/Parsec/Prim.hs b/src/Text/Parsec/Prim.hs
--- a/src/Text/Parsec/Prim.hs
+++ b/src/Text/Parsec/Prim.hs
@@ -99,15 +99,15 @@
 import qualified Data.Monoid as Monoid ( Monoid(..) )
 
 import qualified Control.Applicative as Applicative ( Applicative(..), Alternative(..), liftA2 )
-import Control.Monad hiding (sequence)
-import Control.Monad.Trans
-import Control.Monad.Identity hiding (sequence)
+import Control.Monad (MonadPlus (..), ap, void, liftM)
+import Control.Monad.Trans (MonadTrans (lift), MonadIO (liftIO))
+import Control.Monad.Identity (Identity, runIdentity)
 import qualified Control.Monad.Fail as Fail
 
-import Control.Monad.Reader.Class
-import Control.Monad.State.Class
-import Control.Monad.Cont.Class
-import Control.Monad.Error.Class
+import Control.Monad.Reader.Class (MonadReader (..))
+import Control.Monad.State.Class (MonadState (..))
+import Control.Monad.Cont.Class (MonadCont (..))
+import Control.Monad.Error.Class (MonadError (..))
 
 import Text.Parsec.Pos
 import Text.Parsec.Error
@@ -149,13 +149,14 @@
              }
 #if MIN_VERSION_base(4,7,0)
      deriving ( Typeable )
-     -- GHC 7.6 doesn't like deriving instances of Typeabl1 for types with
+     -- GHC 7.6 doesn't like deriving instances of Typeable for types with
      -- non-* type-arguments.
 #endif
 
 -- | Low-level unpacking of the ParsecT type. To run your parser, please look to
 -- runPT, runP, runParserT, runParser and other such functions.
 runParsecT :: Monad m => ParsecT s u m a -> State s u -> m (Consumed (m (Reply s u a)))
+{-# INLINABLE runParsecT #-}
 runParsecT p s = unParser p s cok cerr eok eerr
     where cok a s' err = return . Consumed . return $ Ok a s' err
           cerr err = return . Consumed . return $ Error err
@@ -164,6 +165,7 @@
 
 -- | Low-level creation of the ParsecT type. You really shouldn't have to do this.
 mkPT :: Monad m => (State s u -> m (Consumed (m (Reply s u a)))) -> ParsecT s u m a
+{-# INLINABLE mkPT #-}
 mkPT k = ParsecT $ \s cok cerr eok eerr -> do
            cons <- k s
            case cons of
@@ -316,7 +318,9 @@
   = ParsecT $ \s cok cerr eok eerr ->
     let
         -- consumed-okay case for m
-        mcok x s err =
+        mcok x s err
+          | errorIsUnknown err = unParser (k x) s cok cerr cok cerr
+          | otherwise =
             let
                  -- if (k x) consumes, those go straigt up
                  pcok = cok
@@ -333,7 +337,9 @@
             in  unParser (k x) s pcok pcerr peok peerr
 
         -- empty-ok case for m
-        meok x s err =
+        meok x s err
+          | errorIsUnknown err = unParser (k x) s cok cerr eok eerr
+          | otherwise =
             let
                 -- in these cases, (k x) can return as empty
                 pcok = cok
@@ -586,6 +592,7 @@
       -> (t -> SourcePos)         -- ^ Computes the position of a token.
       -> (t -> Maybe a)           -- ^ Matching function for the token to parse.
       -> Parsec s u a
+{-# INLINABLE token #-}
 token showToken tokpos test = tokenPrim showToken nextpos test
     where
         nextpos _ tok ts = case runIdentity (uncons ts) of
@@ -698,6 +705,7 @@
 
 runPT :: (Stream s m t)
       => ParsecT s u m a -> u -> SourceName -> s -> m (Either ParseError a)
+{-# INLINABLE runPT #-}
 runPT p u name s
     = do res <- runParsecT p (State s (initialPos name) u)
          r <- parserReply res
diff --git a/src/Text/Parsec/Text.hs b/src/Text/Parsec/Text.hs
--- a/src/Text/Parsec/Text.hs
+++ b/src/Text/Parsec/Text.hs
@@ -19,9 +19,10 @@
     ) where
 
 import qualified Data.Text as Text
+import qualified Data.Text.IO as T
+
 import Text.Parsec.Prim
 import Text.Parsec.Error
-import Data.Text.IO as T
 
 type Parser = Parsec Text.Text ()
 type GenParser st = Parsec Text.Text st
diff --git a/src/Text/Parsec/Text/Lazy.hs b/src/Text/Parsec/Text/Lazy.hs
--- a/src/Text/Parsec/Text/Lazy.hs
+++ b/src/Text/Parsec/Text/Lazy.hs
@@ -19,9 +19,10 @@
     ) where
 
 import qualified Data.Text.Lazy as Text
+import qualified Data.Text.Lazy.IO as TL
+
 import Text.Parsec.Prim
 import Text.Parsec.Error
-import Data.Text.Lazy.IO as TL
 
 type Parser = Parsec Text.Text ()
 type GenParser st = Parsec Text.Text st
diff --git a/src/Text/Parsec/Token.hs b/src/Text/Parsec/Token.hs
--- a/src/Text/Parsec/Token.hs
+++ b/src/Text/Parsec/Token.hs
@@ -34,7 +34,8 @@
 import Data.Typeable ( Typeable )
 #endif
 import Data.List ( nub, sort )
-import Control.Monad.Identity
+import Control.Monad.Identity (Identity)
+
 import Text.Parsec.Prim
 import Text.Parsec.Char
 import Text.Parsec.Combinator
@@ -171,7 +172,7 @@
 
         stringLiteral    :: ParsecT s u m String,
 
-        -- | This lexeme parser parses a natural number (a positive whole
+        -- | This lexeme parser parses a natural number (a non-negative whole
         -- number). Returns the value of the number. The number can be
         -- specified in 'decimal', 'hexadecimal' or
         -- 'octal'. The number is parsed according to the grammar
@@ -357,6 +358,7 @@
 
 makeTokenParser :: (Stream s m Char)
                 => GenLanguageDef s u m -> GenTokenParser s u m
+{-# INLINABLE makeTokenParser #-}
 makeTokenParser languageDef
     = TokenParser{ identifier = identifier
                  , reserved = reserved
diff --git a/src/Text/ParserCombinators/Parsec/Expr.hs b/src/Text/ParserCombinators/Parsec/Expr.hs
--- a/src/Text/ParserCombinators/Parsec/Expr.hs
+++ b/src/Text/ParserCombinators/Parsec/Expr.hs
@@ -25,7 +25,7 @@
 import qualified Text.Parsec.Expr as N
 import Text.ParserCombinators.Parsec(GenParser)
 
-import Control.Monad.Identity
+import Control.Monad.Identity (Identity)
 
 data Operator tok st a   = Infix  (GenParser tok st (a -> a -> a)) Assoc
                          | Prefix (GenParser tok st (a -> a))
diff --git a/test/Bugs.hs b/test/Bugs.hs
--- a/test/Bugs.hs
+++ b/test/Bugs.hs
@@ -3,14 +3,14 @@
        ( bugs
        ) where
 
-import Test.Framework
+import Test.Tasty
 
 import qualified Bugs.Bug2
 import qualified Bugs.Bug6
 import qualified Bugs.Bug9
 import qualified Bugs.Bug35
 
-bugs :: [Test]
+bugs :: [TestTree]
 bugs = [ Bugs.Bug2.main
        , Bugs.Bug6.main
        , Bugs.Bug9.main
diff --git a/test/Bugs/Bug2.hs b/test/Bugs/Bug2.hs
--- a/test/Bugs/Bug2.hs
+++ b/test/Bugs/Bug2.hs
@@ -3,16 +3,15 @@
        ( main
        ) where
 
-import Test.HUnit hiding ( Test )
-import Test.Framework
-import Test.Framework.Providers.HUnit
+import Test.Tasty
+import Test.Tasty.HUnit
 
 import Text.Parsec
 import Text.Parsec.String
 import qualified Text.Parsec.Token as P
 import Text.Parsec.Language (haskellDef)
 
-main :: Test
+main :: TestTree
 main =
   testCase "Control Char Parsing (#2)" $
   parseString "\"test\\^Bstring\"" @?= "test\^Bstring"
diff --git a/test/Bugs/Bug35.hs b/test/Bugs/Bug35.hs
--- a/test/Bugs/Bug35.hs
+++ b/test/Bugs/Bug35.hs
@@ -6,9 +6,8 @@
 import Text.Parsec.String
 import qualified Text.Parsec.Token as Token
 
-import Test.HUnit hiding (Test)
-import Test.Framework
-import Test.Framework.Providers.HUnit
+import Test.Tasty
+import Test.Tasty.HUnit
 
 trickyFloats :: [String]
 trickyFloats =
@@ -36,5 +35,5 @@
 testBatch = mapM_ testFloat trickyFloats
     where testFloat x = parse float "" x @?= Right (read x :: Double)
 
-main :: Test
+main :: TestTree
 main = testCase "Quality of output of Text.Parsec.Token.float (#35)" testBatch
diff --git a/test/Bugs/Bug6.hs b/test/Bugs/Bug6.hs
--- a/test/Bugs/Bug6.hs
+++ b/test/Bugs/Bug6.hs
@@ -3,16 +3,15 @@
        ( main
        ) where
 
-import Test.HUnit hiding ( Test )
-import Test.Framework
-import Test.Framework.Providers.HUnit
+import Test.Tasty
+import Test.Tasty.HUnit
 
 import Text.Parsec
 import Text.Parsec.String
 
 import Util
 
-main :: Test
+main :: TestTree
 main =
   testCase "Look-ahead preserving error location (#6)" $
   parseErrors variable "return" @?= ["'return' is a reserved keyword"]
diff --git a/test/Bugs/Bug9.hs b/test/Bugs/Bug9.hs
--- a/test/Bugs/Bug9.hs
+++ b/test/Bugs/Bug9.hs
@@ -7,16 +7,15 @@
 import           Text.Parsec.String             (Parser)
 import qualified Text.Parsec.Token              as P
 
-import           Test.Framework
-import           Test.Framework.Providers.HUnit
-import           Test.HUnit                     hiding (Test)
+import           Test.Tasty
+import           Test.Tasty.HUnit
 
 import           Util
 
 data Expr = Const Integer | Op Expr Expr
   deriving Show
 
-main :: Test
+main :: TestTree
 main =
   testCase "Tracing of current position in error message (#9)"
   $ result @?= ["unexpected '>'","expecting operator or end of input"]
diff --git a/test/Features.hs b/test/Features.hs
--- a/test/Features.hs
+++ b/test/Features.hs
@@ -2,11 +2,11 @@
        ( features
        ) where
 
-import Test.Framework
+import Test.Tasty
 
 import qualified Features.Feature80
 
-features :: [Test]
+features :: [TestTree]
 features = [
              Features.Feature80.main
            ]
diff --git a/test/Features/Feature80.hs b/test/Features/Feature80.hs
--- a/test/Features/Feature80.hs
+++ b/test/Features/Feature80.hs
@@ -4,13 +4,12 @@
 import           Control.Monad.Identity
 import           Data.List.NonEmpty
 import           Data.Semigroup
-import           Test.Framework
-import           Test.Framework.Providers.HUnit
-import           Test.HUnit                     hiding (Test)
+import           Test.Tasty
+import           Test.Tasty.HUnit
 
 import           Text.Parsec
 
-main :: Test
+main :: TestTree
 main =
   testCase "Monoid instance (#80)" $ do
     parseString (as <> bs) "aabbb" @?= "aabbb"
diff --git a/test/Main.hs b/test/Main.hs
--- a/test/Main.hs
+++ b/test/Main.hs
@@ -1,12 +1,12 @@
 
-import Test.Framework
+import Test.Tasty
 
 import Bugs ( bugs )
 import Features ( features )
 
 main :: IO ()
 main = do
-  defaultMain
+  defaultMain $ testGroup "All"
     [ testGroup "Bugs" bugs
     , testGroup "Features" features
     ]
diff --git a/test/issue127.hs b/test/issue127.hs
new file mode 100644
--- /dev/null
+++ b/test/issue127.hs
@@ -0,0 +1,13 @@
+module Main (main) where
+  
+import Text.Parsec
+import System.Environment (getArgs)
+import Control.Monad (replicateM_)
+
+main :: IO ()
+main = do
+  n <- getArgs >>= \args -> return $ case args of
+      arg : _ -> read arg
+      _       -> 1000000
+
+  print $ runParser (replicateM_ n $ return ()) () "test" ""
