diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,34 @@
+### 3.1.18.0
+
+- Drop support for GHCs prior 8.6.5
+
+### 3.1.17.0
+
+- Move `many1 :: ParsecT s u m a -> ParsecT s u m [a]` to `Text.Parsec.Prim`.
+  Drop `Stream` constraint requirement.
+- Change the position comparison in `mergeError` to not compare source names.
+  This doesn't alter reported error positions when only a single source is parsed.
+  This fixes performance issue caused by long source names.
+- Add `Exception ParseError` instance
+
+### 3.1.16.0
+
+- Add `tokens'` and `string'` combinators which don't consume the prefix.
+
+### 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).
+
+- Clarify Haddock documentation in various places (#105,#101,#102).
+
+- Add support for `base-4.13`.
+
 ### 3.1.13.0
 
 - Add official support for [`SafeHaskell`](http://downloads.haskell.org/~ghc/latest/docs/html/users_guide/safe_haskell.html)
@@ -45,7 +76,7 @@
 
 ### 3.1.9
 
-- Many and various updates to documentation and package description (inlcuding
+- Many and various updates to documentation and package description (including
   the homepage links).
 - Add an `Eq` instance for `ParseError`
 - Fixed a regression from 3.1.6: `runP` is again exported from module
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -19,9 +19,9 @@
   thanks to Microsoft Research).
 * [Using Parsec](http://book.realworldhaskell.org/read/using-parsec.html),
   chapter 16 of [Real World Haskell](http://book.realworldhaskell.org/).
-* [An introduction to the Parsec library](http://kunigami.wordpress.com/2014/01/21/an-introduction-to-the-parsec-library)
+* [An introduction to the Parsec library](https://www.kuniga.me/blog/2014/01/21/an-introduction-to-the-parsec-library.html)
   on Kunigami's blog.
-* [An introduction to parsing text in Haskell with Parsec](http://unbui.lt/#!/post/haskell-parsec-basics) on Wilson's blog.
+* [An introduction to parsing text in Haskell with Parsec](https://jsdw.me/posts/haskell-parsec-basics/) on Wilson's blog.
 * Differences between Parsec and
   [Attoparsec](http://hackage.haskell.org/package/attoparsec)
   (Haskell's other prominent parser library) as explained in
diff --git a/parsec.cabal b/parsec.cabal
--- a/parsec.cabal
+++ b/parsec.cabal
@@ -1,127 +1,179 @@
-cabal-version:  1.12
-name:           parsec
-version:        3.1.13.0
+cabal-version:      1.12
+name:               parsec
+version:            3.1.18.0
+synopsis:           Monadic parser combinators
+description:
+  Parsec is designed from scratch as an industrial-strength parser
+  library.  It is simple, safe, well documented (on the package
+  homepage), has extensive libraries, good error messages,
+  and is fast.  It is defined as a monad transformer that can be
+  stacked on arbitrary monads, and it is also parametric in the
+  input stream type.
+  .
+  The main entry point is the "Text.Parsec" module which provides
+  defaults for parsing 'Char'acter data.
+  .
+  The "Text.ParserCombinators.Parsec" module hierarchy contains
+  the legacy @parsec-2@ API and may be removed at some point in
+  the future.
 
-synopsis:       Monadic parser combinators
-description:    Parsec is designed from scratch as an industrial-strength parser
-                library.  It is simple, safe, well documented (on the package
-                homepage), has extensive libraries, good error messages,
-                and is fast.  It is defined as a monad transformer that can be
-                stacked on arbitrary monads, and it is also parametric in the
-                input stream type.
-                .
-                The main entry point is the "Text.Parsec" module which provides
-                defaults for parsing 'Char'acter data.
-                .
-                The "Text.ParserCombinators.Parsec" module hierarchy contains
-                the legacy @parsec-2@ API and may be removed at some point in
-                the future.
+license:            BSD2
+license-file:       LICENSE
+author:
+  Daan Leijen <daan@microsoft.com>, Paolo Martini <paolo@nemail.it>, Antoine Latter <aslatter@gmail.com>
 
-license:        BSD3
-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>
-homepage:       https://github.com/hvr/parsec
-bug-reports:    https://github.com/hvr/parsec/issues
-category:       Parsing
+maintainer:
+  Oleg Grenrus <oleg.grenrus@iki.fi>, Herbert Valerio Riedel <hvr@gnu.org>
 
-build-type:     Simple
-tested-with:    GHC ==8.4.1 || ==8.2.2 || ==8.0.2 || ==7.10.3 || ==7.8.4 || ==7.6.3 || ==7.4.2
+homepage:           https://github.com/haskell/parsec
+bug-reports:        https://github.com/haskell/parsec/issues
+category:           Parsing
+build-type:         Simple
+tested-with:
+  GHC ==8.6.5
+   || ==8.8.4
+   || ==8.10.7
+   || ==9.0.2
+   || ==9.2.8
+   || ==9.4.8
+   || ==9.6.4
+   || ==9.8.2
+   || ==9.10.1
+   || ==9.12.1
 
-extra-source-files: ChangeLog.md, README.md
+extra-source-files:
+  ChangeLog.md
+  README.md
 
 source-repository head
-    type: git
-    location: https://github.com/hvr/parsec
+  type:     git
+  location: https://github.com/haskell/parsec
 
 library
-    hs-source-dirs: src
-    exposed-modules:
-        Text.Parsec
-        Text.Parsec.String
-        Text.Parsec.ByteString
-        Text.Parsec.ByteString.Lazy
-        Text.Parsec.Text
-        Text.Parsec.Text.Lazy
-        Text.Parsec.Pos
-        Text.Parsec.Error
-        Text.Parsec.Prim
-        Text.Parsec.Char
-        Text.Parsec.Combinator
-        Text.Parsec.Token
-        Text.Parsec.Expr
-        Text.Parsec.Language
-        Text.Parsec.Perm
-        Text.ParserCombinators.Parsec
-        Text.ParserCombinators.Parsec.Char
-        Text.ParserCombinators.Parsec.Combinator
-        Text.ParserCombinators.Parsec.Error
-        Text.ParserCombinators.Parsec.Expr
-        Text.ParserCombinators.Parsec.Language
-        Text.ParserCombinators.Parsec.Perm
-        Text.ParserCombinators.Parsec.Pos
-        Text.ParserCombinators.Parsec.Prim
-        Text.ParserCombinators.Parsec.Token
+  hs-source-dirs:   src
+  exposed-modules:
+    Text.Parsec
+    Text.Parsec.ByteString
+    Text.Parsec.ByteString.Lazy
+    Text.Parsec.Char
+    Text.Parsec.Combinator
+    Text.Parsec.Error
+    Text.Parsec.Expr
+    Text.Parsec.Language
+    Text.Parsec.Perm
+    Text.Parsec.Pos
+    Text.Parsec.Prim
+    Text.Parsec.String
+    Text.Parsec.Text
+    Text.Parsec.Text.Lazy
+    Text.Parsec.Token
+    Text.ParserCombinators.Parsec
+    Text.ParserCombinators.Parsec.Char
+    Text.ParserCombinators.Parsec.Combinator
+    Text.ParserCombinators.Parsec.Error
+    Text.ParserCombinators.Parsec.Expr
+    Text.ParserCombinators.Parsec.Language
+    Text.ParserCombinators.Parsec.Perm
+    Text.ParserCombinators.Parsec.Pos
+    Text.ParserCombinators.Parsec.Prim
+    Text.ParserCombinators.Parsec.Token
 
-    build-depends:
-        base       >= 4.5.1   && < 4.12,
-        mtl        >= 1.1.1   && < 2.3,
-        bytestring >= 0.9.2.1 && < 0.11,
-        text       >= 0.11.3  && < 1.3
+  build-depends:
+      base        >=4.12.0.0 && <4.22
+    , bytestring  >=0.10.8.2 && <0.13
+    , mtl         >=2.2.2    && <2.4
+    , text        >=1.2.3.0  && <1.3  || >=2.0 && <2.2
 
-    default-language: Haskell2010
-    other-extensions:
-        CPP
-        DeriveDataTypeable
-        ExistentialQuantification
-        FlexibleContexts
-        FlexibleInstances
-        FunctionalDependencies
-        MultiParamTypeClasses
-        PolymorphicComponents
-        StandaloneDeriving
-        Safe
-        Trustworthy
-        UndecidableInstances
+  default-language: Haskell2010
+  other-extensions:
+    CPP
+    DeriveDataTypeable
+    ExistentialQuantification
+    FlexibleContexts
+    FlexibleInstances
+    FunctionalDependencies
+    MultiParamTypeClasses
+    PolymorphicComponents
+    Safe
+    StandaloneDeriving
+    Trustworthy
+    UndecidableInstances
 
-    ghc-options: -Wall
-    if impl(ghc >= 8.0)
-        ghc-options: -Wcompat -Wnoncanonical-monad-instances -Wnoncanonical-monadfail-instances -Wno-trustworthy-safe
-    else
-        -- provide/emulate `Control.Monad.Fail` and `Semigroup` API for pre-GHC8
-        build-depends: fail == 4.9.*, semigroups == 0.18.*
+  ghc-options:      -Wall
+  ghc-options:
+    -Wcompat -Wnoncanonical-monad-instances -Wno-trustworthy-safe
 
-        if impl(ghc >= 7.10)
-            ghc-options: -fno-warn-trustworthy-safe
+  if impl(ghc <8.8)
+    ghc-options: -Wnoncanonical-monadfail-instances
 
-test-suite parsec.
-    type: exitcode-stdio-1.0
+-- these flags may abort compilation with GHC-8.10
+-- https://gitlab.haskell.org/ghc/ghc/-/merge_requests/3295
+-- https://gitlab.haskell.org/ghc/ghc/-/issues/22728
+-- if impl(ghc >= 9.0)
+--    -- ghc-options: -Winferred-safe-imports -Wmissing-safe-haskell-mode
 
-    hs-source-dirs: test
-    main-is: Main.hs
-    other-modules:
-        Bugs
-        Bugs.Bug2
-        Bugs.Bug6
-        Bugs.Bug9
-        Bugs.Bug35
-        Features
-        Features.Feature80
-        Util
+test-suite parsec-tests
+  type:             exitcode-stdio-1.0
+  hs-source-dirs:   test
+  main-is:          Main.hs
+  other-modules:
+    Bugs
+    Bugs.Bug2
+    Bugs.Bug35
+    Bugs.Bug6
+    Bugs.Bug9
+    Features
+    Features.Feature150
+    Features.Feature80
+    Util
 
-    build-depends:
-        base,
-        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.*
+  build-depends:
+      base
+    , mtl
+    , parsec
+    , tasty        >=1.4  && <1.6
+    , tasty-hunit  >=0.10 && <0.11
 
-    default-language: Haskell2010
+  -- dependencies whose version bounds are not inherited via lib:parsec
+  default-language: Haskell2010
+  ghc-options:      -Wall
 
-    ghc-options: -Wall
-    if impl(ghc >= 8.0)
-        ghc-options: -Wcompat -Wnoncanonical-monad-instances -Wnoncanonical-monadfail-instances
-    else
-        build-depends: semigroups == 0.18.*
+  if impl(ghc >=8.0)
+    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
+
+test-suite parsec-issue171
+  default-language: Haskell2010
+  type:             exitcode-stdio-1.0
+  main-is:          issue171.hs
+  hs-source-dirs:   test
+  build-depends:
+      base
+    , deepseq
+    , parsec
+    , tasty
+    , tasty-hunit
+
+test-suite parsec-issue175
+  default-language: Haskell2010
+  type:             exitcode-stdio-1.0
+  main-is:          issue175.hs
+  hs-source-dirs:   test
+  build-depends:
+      base
+    , parsec
+    , tasty
+    , tasty-hunit
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
@@ -10,7 +10,7 @@
 -- Stability   :  provisional
 -- Portability :  portable
 --
--- Convinience definitions for working with 'C.ByteString's.
+-- Convenience definitions for working with 'C.ByteString's.
 --
 -----------------------------------------------------------------------------
 
@@ -18,11 +18,11 @@
     ( 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
 
@@ -36,7 +36,7 @@
 -- >                  Right xs  -> print (sum xs)
 -- >              }
 
-parseFromFile :: Parser a -> String -> IO (Either ParseError a)
+parseFromFile :: Parser a -> FilePath -> IO (Either ParseError a)
 parseFromFile p fname
     = do input <- C.readFile fname
          return (runP p () fname input)
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
@@ -10,7 +10,7 @@
 -- Stability   :  provisional
 -- Portability :  portable
 --
--- Convinience definitions for working with lazy 'C.ByteString's.
+-- Convenience definitions for working with lazy 'C.ByteString's.
 --
 -----------------------------------------------------------------------------
 
@@ -18,11 +18,11 @@
     ( 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
 
@@ -35,7 +35,8 @@
 -- >                  Left err  -> print err
 -- >                  Right xs  -> print (sum xs)
 -- >              }
-parseFromFile :: Parser a -> String -> IO (Either ParseError a)
+
+parseFromFile :: Parser a -> FilePath -> IO (Either ParseError a)
 parseFromFile p fname
     = do input <- C.readFile fname
          return (runP p () fname input)
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
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP, FlexibleContexts, Safe #-}
+{-# LANGUAGE FlexibleContexts, Safe #-}
 
 -----------------------------------------------------------------------------
 -- |
@@ -16,12 +16,10 @@
 
 module Text.Parsec.Char where
 
-import Data.Char
+import Data.Char (isSpace, isUpper, isLower, isAlphaNum, isAlpha, isDigit, isHexDigit, isOctDigit)
+
 import Text.Parsec.Pos
 import Text.Parsec.Prim
-#if !(MIN_VERSION_base(4,8,0))
-import Control.Applicative ((*>))
-#endif
 
 -- | @oneOf cs@ succeeds if the current character is in the supplied
 -- list of characters @cs@. Returns the parsed character. See also
@@ -30,6 +28,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 +38,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,52 +74,66 @@
 --
 
 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 letter or digit (a character between \'0\' and \'9\')
+-- | Parses a alphabetic or numeric Unicode characters
 -- according to 'isAlphaNum'. Returns the parsed character.
+--
+-- Note that numeric digits outside the ASCII range (such as arabic-indic digits like e.g. \"٤\" or @U+0664@),
+-- as well as numeric characters which aren't digits, are parsed by this function
+-- but not by 'digit'.
 
 alphaNum :: (Stream s m Char => ParsecT s u m Char)
+{-# INLINABLE alphaNum #-}
 alphaNum            = satisfy isAlphaNum    <?> "letter or digit"
 
--- | Parses a letter (an upper case or lower case character according
--- to 'isAlpha'). Returns the parsed character.
+-- | Parses an alphabetic Unicode characters (lower-case, upper-case and title-case letters,
+-- plus letters of caseless scripts and modifiers letters according to 'isAlpha').
+-- Returns the parsed character.
 
 letter :: (Stream s m Char) => ParsecT s u m Char
+{-# INLINABLE letter #-}
 letter              = satisfy isAlpha       <?> "letter"
 
--- | Parses a digit. Returns the parsed character.
+-- | 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
@@ -124,11 +142,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
@@ -139,15 +159,31 @@
 -- >  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)
 
--- | @string s@ parses a sequence of characters given by @s@. Returns
+-- | @'string' s@ parses a sequence of characters given by @s@. Returns
 -- the parsed string (i.e. @s@).
 --
 -- >  divOrMod    =   string "div"
 -- >              <|> string "mod"
+--
+-- Consider using 'string''.
 
 string :: (Stream s m Char) => String -> ParsecT s u m String
+{-# INLINABLE string #-}
 string s            = tokens show updatePosString s
+
+-- | @'string'' s@ parses a sequence of characters given by @s@.
+-- Doesn't consume matching prefix.
+--
+-- >  carOrCdr    =   string' "car"
+-- >              <|> string' "cdr"
+--
+-- @since 3.1.16.0
+
+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
@@ -99,35 +106,20 @@
                       scan  = do{ p; scan } <|> return ()
 -}
 
--- | @many1 p@ applies the parser @p@ /one/ or more times. Returns a
--- list of the returned values of @p@.
---
--- >  word  = many1 letter
-
-many1 :: (Stream s m t) => ParsecT s u m a -> ParsecT s u m [a]
-many1 p             = do{ x <- p; xs <- many p; return (x:xs) }
-{-
-many p              = scan id
-                    where
-                      scan f    = do{ x <- p
-                                    ; scan (\tail -> f (x:tail))
-                                    }
-                                <|> return (f [])
--}
-
-
 -- | @sepBy p sep@ parses /zero/ or more occurrences of @p@, separated
 -- by @sep@. Returns a list of values returned by @p@.
 --
 -- >  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 +131,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 +147,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 +155,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 +164,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 +172,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 +183,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 +193,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 +213,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 +228,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 +246,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 +255,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 +282,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 +299,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 +316,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 +338,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/Error.hs b/src/Text/Parsec/Error.hs
--- a/src/Text/Parsec/Error.hs
+++ b/src/Text/Parsec/Error.hs
@@ -25,8 +25,10 @@
     , mergeError
     ) where
 
+import Control.Exception ( Exception )
 import Data.List ( nub, sort )
 import Data.Typeable ( Typeable )
+import qualified Data.Monoid as Mon
 
 import Text.Parsec.Pos
 
@@ -145,12 +147,17 @@
     | null msgs2 && not (null msgs1) = e1
     | null msgs1 && not (null msgs2) = e2
     | otherwise
-    = case pos1 `compare` pos2 of
+      -- perfectly we'd compare the consumed token count
+      -- https://github.com/haskell/parsec/issues/175
+    = case compareErrorPos pos1 pos2 of
         -- select the longest match
         EQ -> ParseError pos1 (msgs1 ++ msgs2)
         GT -> e1
         LT -> e2
 
+compareErrorPos :: SourcePos -> SourcePos -> Ordering
+compareErrorPos x y = Mon.mappend (compare (sourceLine x) (sourceLine y)) (compare (sourceColumn x) (sourceColumn y))
+
 instance Show ParseError where
     show err
         = show (errorPos err) ++ ":" ++
@@ -164,6 +171,9 @@
         where
           messageStrs = map messageString . errorMessages
 
+-- | @since 3.1.17.0
+instance Exception ParseError
+
 -- Language independent show function
 
 --  TODO
@@ -189,12 +199,12 @@
 
       showExpect      = showMany msgExpecting expect
       showUnExpect    = showMany msgUnExpected unExpect
-      showSysUnExpect | not (null unExpect) ||
-                        null sysUnExpect = ""
-                      | null firstMsg    = msgUnExpected ++ " " ++ msgEndOfInput
-                      | otherwise        = msgUnExpected ++ " " ++ firstMsg
-          where
-              firstMsg  = messageString (head sysUnExpect)
+      showSysUnExpect
+          | not (null unExpect)      = ""
+          | []      <- sysUnExpect   = ""
+          | msg : _ <- sysUnExpect
+          , null (messageString msg) = msgUnExpected ++ " " ++ msgEndOfInput
+          | msg : _ <- sysUnExpect   = msgUnExpected ++ " " ++ messageString msg
 
       showMessages      = showMany "" messages
 
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
@@ -1,4 +1,3 @@
-{-# LANGUAGE CPP #-}
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE Safe #-}
 
@@ -46,9 +45,7 @@
 data Operator s u m a   = Infix (ParsecT s u m (a -> a -> a)) Assoc
                         | Prefix (ParsecT s u m (a -> a))
                         | Postfix (ParsecT s u m (a -> a))
-#if MIN_VERSION_base(4,7,0)
     deriving ( Typeable )
-#endif
 
 -- | An @OperatorTable s u m a@ is a list of @Operator s u m a@
 -- lists. The list is ordered in descending
@@ -96,6 +93,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/Language.hs b/src/Text/Parsec/Language.hs
--- a/src/Text/Parsec/Language.hs
+++ b/src/Text/Parsec/Language.hs
@@ -98,7 +98,7 @@
 -- Haskell
 -----------------------------------------------------------
 
--- | A lexer for the haskell language.
+-- | A lexer for the Haskell language.
 
 haskell :: TokenParser st
 haskell      = makeTokenParser haskellDef
@@ -135,7 +135,7 @@
 -- Mondrian
 -----------------------------------------------------------
 
--- | A lexer for the mondrian language.
+-- | A lexer for the Mondrian language.
 
 mondrian :: TokenParser st
 mondrian    = makeTokenParser mondrianDef
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
@@ -1,4 +1,3 @@
-{-# LANGUAGE CPP #-}
 {-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE FlexibleContexts #-}
@@ -23,6 +22,12 @@
 -- by Arthur Baars, Andres Loh and Doaitse Swierstra.
 -- Published as a functional pearl at the Haskell Workshop 2001.
 --
+-- From the abstract: 
+--
+-- A permutation phrase is a sequence of elements (possibly of different types) 
+-- in which each element occurs exactly once and the order is irrelevant. 
+-- Some of the permutable elements may be optional.
+--
 -----------------------------------------------------------------------------
 
 
@@ -35,15 +40,9 @@
     , (<|?>), (<$?>)
     ) where
 
-import Text.Parsec
-
-import Control.Monad.Identity
-#if MIN_VERSION_base(4,7,0)
+import Control.Monad.Identity ( Identity )
 import Data.Typeable ( Typeable )
-#else
--- For GHC 7.6
-import Data.Typeable ( Typeable3 )
-#endif
+import Text.Parsec
 
 infixl 1 <||>, <|?>
 infixl 2 <$$>, <$?>
@@ -131,20 +130,12 @@
 -- using 'permute'.
 
 data StreamPermParser s st a = Perm (Maybe a) [StreamBranch s st a]
-#if MIN_VERSION_base(4,7,0)
     deriving ( Typeable )
-#else
-deriving instance Typeable3 StreamPermParser
-#endif
 
 -- type Branch st a = StreamBranch String st a
 
 data StreamBranch s st a = forall b. Branch (StreamPermParser s st (b -> a)) (Parsec s st b)
-#if MIN_VERSION_base(4,7,0)
     deriving ( Typeable )
-#else
-deriving instance Typeable3 StreamBranch
-#endif
 
 -- | The parser @permute perm@ parses a permutation of parser described
 -- by @perm@. For example, suppose we want to parse a permutation of:
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
@@ -53,6 +53,7 @@
     , lookAhead
     , Stream(..)
     , tokens
+    , tokens'
     , try
     , token
     , tokenPrim
@@ -60,6 +61,7 @@
     , many
     , skipMany
     , manyAccum
+    , many1
     , runPT
     , runP
     , runParserT
@@ -99,15 +101,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
@@ -147,15 +149,12 @@
               -> (ParseError -> m b)                   -- empty err
               -> m b
              }
-#if MIN_VERSION_base(4,7,0)
      deriving ( Typeable )
-     -- GHC 7.6 doesn't like deriving instances of Typeabl1 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 +163,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
@@ -218,11 +218,7 @@
     --  discarding the first.
     (<>)     = Applicative.liftA2 (Semigroup.<>)
 
-#if MIN_VERSION_base(4,8,0)
     sconcat  = fmap Semigroup.sconcat . sequence
-#else
-    sconcat  = fmap (Semigroup.sconcat . NE.fromList) . sequence . NE.toList
-#endif
     stimes b = Semigroup.sconcat . NE.fromList . genericReplicate b
 
 -- | The 'Monoid' instance for 'ParsecT' is used for the same purposes as
@@ -267,11 +263,19 @@
     empty = mzero
     (<|>) = mplus
 
+    -- TODO: https://github.com/haskell/parsec/issues/179
+    -- investigate what's wrong with haddock
+    --
+    -- many = many
+    -- some = many1
+
 instance Monad (ParsecT s u m) where
     return = Applicative.pure
     p >>= f = parserBind p f
     (>>) = (Applicative.*>)
+#if !MIN_VERSION_base(4,13,0)
     fail = Fail.fail
+#endif
 
 -- | @since 3.1.12.0
 instance Fail.MonadFail (ParsecT s u m) where
@@ -314,9 +318,11 @@
   = 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
+                 -- if (k x) consumes, those go straight up
                  pcok = cok
                  pcerr = cerr
 
@@ -331,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
@@ -515,6 +523,46 @@
                 | tok == x  -> walk toks xs
                 | otherwise -> eerr $ errExpect x
 
+-- | Like 'tokens', but doesn't consume matching prefix.
+--
+-- @since 3.1.16.0
+tokens' :: (Stream s m t, Eq t)
+       => ([t] -> String)      -- Pretty print a list of tokens
+       -> (SourcePos -> [t] -> SourcePos)
+       -> [t]                  -- List of tokens to parse
+       -> ParsecT s u m [t]
+{-# INLINE tokens' #-}
+tokens' _ _ []
+    = ParsecT $ \s _ _ eok _ ->
+      eok [] s $ unknownError s
+tokens' showTokens nextposs tts@(tok:toks)
+    = ParsecT $ \(State input pos u) cok _cerr _eok eerr ->
+    let
+        errEof = (setErrorMessage (Expect (showTokens tts))
+                  (newErrorMessage (SysUnExpect "") pos))
+
+        errExpect x = (setErrorMessage (Expect (showTokens tts))
+                       (newErrorMessage (SysUnExpect (showTokens [x])) pos))
+
+        walk []     rs = ok rs
+        walk (t:ts) rs = do
+          sr <- uncons rs
+          case sr of
+            Nothing                 -> eerr $ errEof
+            Just (x,xs) | t == x    -> walk ts xs
+                        | otherwise -> eerr $ errExpect x
+
+        ok rs = let pos' = nextposs pos tts
+                    s' = State rs pos' u
+                in cok tts s' (newErrorUnknown pos')
+    in do
+        sr <- uncons input
+        case sr of
+            Nothing         -> eerr $ errEof
+            Just (x,xs)
+                | tok == x  -> walk toks xs
+                | otherwise -> eerr $ errExpect x
+
 -- | The parser @try p@ behaves like parser @p@, except that it
 -- pretends that it hasn't consumed any input when an error occurs.
 --
@@ -584,6 +632,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
@@ -665,6 +714,15 @@
   = do xs <- manyAccum (:) p
        return (reverse xs)
 
+-- | @many1 p@ applies the parser @p@ /one/ or more times. Returns a
+-- list of the returned values of @p@.
+--
+-- >  word  = many1 letter
+
+many1 :: ParsecT s u m a -> ParsecT s u m [a]
+{-# INLINABLE many1 #-}
+many1 p = do{ x <- p; xs <- many p; return (x:xs) }
+
 -- | @skipMany p@ applies the parser @p@ /zero/ or more times, skipping
 -- its result.
 --
@@ -696,6 +754,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/String.hs b/src/Text/Parsec/String.hs
--- a/src/Text/Parsec/String.hs
+++ b/src/Text/Parsec/String.hs
@@ -33,7 +33,7 @@
 -- >                  Left err  -> print err
 -- >                  Right xs  -> print (sum xs)
 -- >              }
-parseFromFile :: Parser a -> String -> IO (Either ParseError a)
+parseFromFile :: Parser a -> FilePath -> IO (Either ParseError a)
 parseFromFile p fname
     = do input <- readFile fname
          return (runP p () fname input)
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
@@ -10,16 +10,36 @@
 -- Stability   :  provisional
 -- Portability :  portable
 --
--- Convinience definitions for working with 'Text.Text'.
+-- Convenience definitions for working with 'Text.Text'.
 --
 -----------------------------------------------------------------------------
 
 module Text.Parsec.Text
-    ( Parser, GenParser
+    ( Parser, GenParser, parseFromFile
     ) where
 
 import qualified Data.Text as Text
+import qualified Data.Text.IO as T
+
 import Text.Parsec.Prim
+import Text.Parsec.Error
 
 type Parser = Parsec Text.Text ()
 type GenParser st = Parsec Text.Text st
+
+-- | @parseFromFile p filePath@ runs a strict text parser @p@ on the
+-- input read from @filePath@ using 'Data.Text.IO.readFile'. Returns either a 'ParseError'
+-- ('Left') or a value of type @a@ ('Right').
+--
+-- >  main    = do{ result <- parseFromFile numbers "digits.txt"
+-- >              ; case result of
+-- >                  Left err  -> print err
+-- >                  Right xs  -> print (sum xs)
+-- >              }
+--
+-- @since 3.1.14.0
+
+parseFromFile :: Parser a -> FilePath -> IO (Either ParseError a)
+parseFromFile p fname
+    = do input <- T.readFile fname
+         return (runP p () fname input)
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
@@ -15,11 +15,31 @@
 -----------------------------------------------------------------------------
 
 module Text.Parsec.Text.Lazy
-    ( Parser, GenParser
+    ( Parser, GenParser, parseFromFile
     ) where
 
 import qualified Data.Text.Lazy as Text
+import qualified Data.Text.Lazy.IO as TL
+
 import Text.Parsec.Prim
+import Text.Parsec.Error
 
 type Parser = Parsec Text.Text ()
 type GenParser st = Parsec Text.Text st
+
+-- | @parseFromFile p filePath@ runs a strict text parser @p@ on the
+-- input read from @filePath@ using 'Data.Text.Lazy.IO.readFile'. Returns either a 'ParseError'
+-- ('Left') or a value of type @a@ ('Right').
+--
+-- >  main    = do{ result <- parseFromFile numbers "digits.txt"
+-- >              ; case result of
+-- >                  Left err  -> print err
+-- >                  Right xs  -> print (sum xs)
+-- >              }
+--
+-- @since 3.1.14.0
+
+parseFromFile :: Parser a -> FilePath -> IO (Either ParseError a)
+parseFromFile p fname
+    = do input <- TL.readFile fname
+         return (runP p () fname input)
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
@@ -1,5 +1,3 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE DeriveDataTypeable #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE PolymorphicComponents #-}
 {-# LANGUAGE Safe #-}
@@ -30,11 +28,10 @@
     ) where
 
 import Data.Char ( isAlpha, toLower, toUpper, isSpace, digitToInt )
-#if MIN_VERSION_base(4,7,0)
 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
@@ -106,9 +103,7 @@
     caseSensitive  :: Bool
 
     }
-#if MIN_VERSION_base(4,7,0)
     deriving ( Typeable )
-#endif
 
 -----------------------------------------------------------
 -- A first class module: TokenParser
@@ -171,7 +166,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
@@ -201,19 +196,19 @@
 
         naturalOrFloat   :: ParsecT s u m (Either Integer Double),
 
-        -- | Parses a positive whole number in the decimal system. Returns the
+        -- | Parses a non-negative whole number in the decimal system. Returns the
         -- value of the number.
 
         decimal          :: ParsecT s u m Integer,
 
-        -- | Parses a positive whole number in the hexadecimal system. The number
-        -- should be prefixed with \"0x\" or \"0X\". Returns the value of the
+        -- | Parses a non-negative whole number in the hexadecimal system. The
+        -- number should be prefixed with \"x\" or \"X\". Returns the value of the
         -- number.
 
         hexadecimal      :: ParsecT s u m Integer,
 
-        -- | Parses a positive whole number in the octal system. The number
-        -- should be prefixed with \"0o\" or \"0O\". Returns the value of the
+        -- | Parses a non-negative whole number in the octal system. The number
+        -- should be prefixed with \"o\" or \"O\". Returns the value of the
         -- number.
 
         octal            :: ParsecT s u m Integer,
@@ -316,9 +311,7 @@
 
         commaSep1        :: forall a . ParsecT s u m a -> ParsecT s u m [a]
     }
-#if MIN_VERSION_base(4,7,0)
     deriving ( Typeable )
-#endif
 
 -----------------------------------------------------------
 -- Given a LanguageDef, create a token parser.
@@ -329,7 +322,7 @@
 -- defined using the definitions in the @language@ record.
 --
 -- The use of this function is quite stylized - one imports the
--- appropiate language definition and selects the lexical parsers that
+-- appropriate language definition and selects the lexical parsers that
 -- are needed from the resulting 'GenTokenParser'.
 --
 -- >  module Main where
@@ -357,6 +350,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"]
@@ -25,7 +24,7 @@
     result :: [String]
     result = parseErrors parseTopLevel "4 >> 5"
 
--- Syntax analaysis
+-- Syntax analysis
 
 parseTopLevel :: Parser Expr
 parseTopLevel = parseExpr <* eof
diff --git a/test/Features.hs b/test/Features.hs
--- a/test/Features.hs
+++ b/test/Features.hs
@@ -2,11 +2,13 @@
        ( features
        ) where
 
-import Test.Framework
+import Test.Tasty
 
 import qualified Features.Feature80
+import qualified Features.Feature150
 
-features :: [Test]
-features = [
-             Features.Feature80.main
-           ]
+features :: [TestTree]
+features =
+    [ Features.Feature80.main
+    , Features.Feature150.main
+    ]
diff --git a/test/Features/Feature150.hs b/test/Features/Feature150.hs
new file mode 100644
--- /dev/null
+++ b/test/Features/Feature150.hs
@@ -0,0 +1,46 @@
+module Features.Feature150 ( main ) where
+
+import           Control.Applicative ((*>))
+import           Control.Monad.Identity
+import           Test.Tasty
+import           Test.Tasty.HUnit
+
+import           Text.Parsec
+
+main :: TestTree
+main =
+  testCase "string' (#150)" $ do
+    parseString (boot <|> bool) "boot" @?= "boot"
+    parseFail   (boot <|> bool) "bool" @?= "no parse"
+    parseFail   (boot <|> bool) "booz" @?= "no parse"
+
+    parseString (boot' <|> bool') "boot" @?= "boot"
+    parseString (boot' <|> bool') "bool" @?= "bool"
+    parseFail   (boot' <|> bool') "booz" @?= "no parse"
+
+    parseString (boot' <|> bool' <|> char 'b' *> many anyChar) "boomerang" @?= "oomerang"
+
+ where
+    boot :: ParsecT String () Identity String
+    boot = string "boot"
+
+    bool :: ParsecT String () Identity String
+    bool = string "bool"
+
+    boot' :: ParsecT String () Identity String
+    boot' = string' "boot"
+
+    bool' :: ParsecT String () Identity String
+    bool' = string' "bool"
+
+    parseString :: ParsecT String () Identity String -> String -> String
+    parseString p input =
+      case parse p "Example" input of
+        Left{}    -> error "Parse failure"
+        Right str -> str
+
+    parseFail :: ParsecT String () Identity String -> String -> String
+    parseFail p input =
+      case parse p "Example" input of
+        Left{}  -> "no parse"
+        Right _ -> error "Parsed but shouldn't"
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,14 @@
+-- this should run in constant memory
+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" ""
diff --git a/test/issue171.hs b/test/issue171.hs
new file mode 100644
--- /dev/null
+++ b/test/issue171.hs
@@ -0,0 +1,29 @@
+-- this should be fast
+module Main (main) where
+
+import Control.DeepSeq (NFData (..))
+import System.CPUTime (getCPUTime)
+import Text.Printf (printf)
+import Test.Tasty (defaultMain)
+import Test.Tasty.HUnit (testCaseSteps, assertBool)
+
+import Text.Parsec
+import Text.Parsec.String (Parser)
+
+main :: IO ()
+main = defaultMain $ testCaseSteps "issue-171" $ \info -> do
+  time0 <- getCPUTime
+  check $ concat $ replicate 100000 "a "
+  time1 <- getCPUTime
+  let diff = (time1 - time0) `div` 1000000000
+  info $ printf "%d milliseconds\n" diff
+  assertBool "" (diff < 200)
+
+parser :: Parser [String]
+parser = many (char 'a' <|> char 'b') `sepBy` char ' '
+
+check :: String -> IO ()
+check s = putStrLn $ either onError (const "") $ parse parser {- important: pass input as SourceName -} s s
+
+onError :: ParseError -> String
+onError err = rnf (show err) `seq` "error"
diff --git a/test/issue175.hs b/test/issue175.hs
new file mode 100644
--- /dev/null
+++ b/test/issue175.hs
@@ -0,0 +1,26 @@
+module Main (main) where
+
+import Text.Parsec
+import Text.Parsec.Error
+import Text.Parsec.String (Parser)
+import Text.Parsec.Pos (newPos)
+
+import Test.Tasty (defaultMain)
+import Test.Tasty.HUnit (assertFailure, testCaseSteps, (@?=))
+
+main :: IO ()
+main = defaultMain $ testCaseSteps "issue175" $ \info -> do
+    case parse p "" "x" of
+        Right _ -> assertFailure "Unexpected success"
+        -- with setPosition the "longest match" is arbitrary
+        -- megaparsec tracks consumed tokens separately, but we don't.
+        -- so our position is arbitrary.
+        Left err -> do
+            info $ show err
+            errorPos err @?= newPos "aaa" 9 1  -- can be arbitrary
+            length (errorMessages err) @?= 2
+
+p :: Parser Char
+p = p1 <|> p2 where
+    p1 = setPosition (newPos "aaa" 9 1) >> char 'a'
+    p2 = setPosition (newPos "zzz" 1 1) >> char 'b'
