Replace trifecta with megaparsec (#268)

The long-term motivation for this change is so that we can eventually use a
separate `attoparsec`-based lexing step to greatly increase parsing speed since
the `trifecta`/`parsers` API doesn't allow tokens other than `Char`.

The secondary motivation for this is that `megaparsec` is a smaller dependency
that is more actively maintained.
This commit is contained in:
Oliver Charles 2018-03-27 17:09:20 +01:00 committed by Gabriel Gonzalez
parent 0ffe854d6d
commit 922e20e6ab
12 changed files with 150 additions and 140 deletions

View File

@ -1,12 +1,11 @@
{ mkDerivation, ansi-terminal, ansi-wl-pprint, base
, base16-bytestring, bytestring, case-insensitive, containers
, contravariant, cryptonite, deepseq, directory, exceptions
, filepath, formatting, haskeline, http-client, http-client-tls
, insert-ordered-containers, lens-family-core, memory, mtl
, optparse-generic, parsers, prettyprinter
, prettyprinter-ansi-terminal, repline, scientific, stdenv, tasty
, tasty-hunit, text, transformers, trifecta, unordered-containers
, vector
{ mkDerivation, ansi-terminal, base, base16-bytestring, bytestring
, case-insensitive, containers, contravariant, cryptonite, deepseq
, directory, exceptions, filepath, formatting, haskeline
, http-client, http-client-tls, insert-ordered-containers
, lens-family-core, megaparsec, memory, mtl, optparse-generic
, parsers, prettyprinter, prettyprinter-ansi-terminal, repline
, scientific, stdenv, tasty, tasty-hunit, text, transformers
, unordered-containers, vector
}:
mkDerivation {
pname = "dhall";
@ -15,16 +14,16 @@ mkDerivation {
isLibrary = true;
isExecutable = true;
libraryHaskellDepends = [
ansi-wl-pprint base base16-bytestring bytestring case-insensitive
ansi-terminal base base16-bytestring bytestring case-insensitive
containers contravariant cryptonite directory exceptions filepath
formatting http-client http-client-tls insert-ordered-containers
lens-family-core memory parsers prettyprinter
prettyprinter-ansi-terminal scientific text transformers trifecta
lens-family-core megaparsec memory parsers prettyprinter
prettyprinter-ansi-terminal scientific text transformers
unordered-containers vector
];
executableHaskellDepends = [
ansi-terminal base haskeline mtl optparse-generic prettyprinter
prettyprinter-ansi-terminal repline text trifecta
ansi-terminal base haskeline megaparsec mtl optparse-generic
prettyprinter prettyprinter-ansi-terminal repline text
];
testHaskellDepends = [
base deepseq insert-ordered-containers prettyprinter tasty

View File

@ -36,7 +36,6 @@ import Dhall.Pretty (annToAnsiStyle, prettyExpr)
import Options.Generic (Generic, ParseRecord, Wrapped, type (<?>)(..), (:::))
import System.IO (stderr)
import System.Exit (exitFailure, exitSuccess)
import Text.Trifecta.Delta (Delta(..))
import qualified Paths_dhall as Meta
@ -80,7 +79,7 @@ main = do
Just file -> do
strictText <- Data.Text.IO.readFile file
let lazyText = Data.Text.Lazy.fromStrict strictText
(header, expr) <- case exprAndHeaderFromText (Directed "(stdin)" 0 0 0 0) lazyText of
(header, expr) <- case exprAndHeaderFromText "(stdin)" lazyText of
Left err -> Control.Exception.throwIO err
Right x -> return x
@ -92,7 +91,7 @@ main = do
System.IO.hSetEncoding System.IO.stdin System.IO.utf8
inText <- Data.Text.Lazy.IO.getContents
(header, expr) <- case exprAndHeaderFromText (Directed "(stdin)" 0 0 0 0) inText of
(header, expr) <- case exprAndHeaderFromText "(stdin)" inText of
Left err -> Control.Exception.throwIO err
Right x -> return x

View File

@ -18,7 +18,6 @@ import Dhall.TypeCheck (DetailedTypeError(..), TypeError, X)
import Options.Generic (Generic, ParseRecord, Wrapped, type (<?>)(..), (:::))
import System.IO (stderr)
import System.Exit (exitFailure, exitSuccess)
import Text.Trifecta.Delta (Delta(..))
import qualified Paths_dhall as Meta
@ -74,7 +73,7 @@ main = do
System.IO.hSetEncoding System.IO.stdin System.IO.utf8
inText <- Data.Text.Lazy.IO.getContents
expr <- case exprFromText (Directed "(stdin)" 0 0 0 0) inText of
expr <- case exprFromText "(stdin)" inText of
Left err -> Control.Exception.throwIO err
Right expr -> return expr

View File

@ -24,7 +24,6 @@ import qualified System.Console.ANSI
import qualified System.Console.Haskeline.MonadException as Haskeline
import qualified System.Console.Repline as Repline
import qualified System.IO
import qualified Text.Trifecta.Delta as Trifecta
main :: IO ()
@ -75,7 +74,7 @@ parseAndLoad
=> String -> m ( Dhall.Expr Dhall.Src Dhall.X )
parseAndLoad src = do
parsed <-
case Dhall.exprFromText ( Trifecta.Columns 0 0 ) ( LazyText.pack src ) of
case Dhall.exprFromText "(stdin)" ( LazyText.pack src ) of
Left e ->
liftIO ( throwIO e )

View File

@ -154,7 +154,7 @@ Library
Hs-Source-Dirs: src
Build-Depends:
base >= 4.9.0.0 && < 5 ,
ansi-wl-pprint < 0.7 ,
ansi-terminal >= 0.6.3.1 && < 0.8 ,
base16-bytestring < 0.2 ,
bytestring < 0.11,
case-insensitive < 1.3 ,
@ -169,6 +169,7 @@ Library
http-client-tls >= 0.2.0 && < 0.4 ,
insert-ordered-containers >= 0.1.0.1 && < 0.3 ,
lens-family-core >= 1.0.0 && < 1.3 ,
megaparsec >= 6.1.1 && < 6.5 ,
memory >= 0.14 && < 0.15,
parsers >= 0.12.4 && < 0.13,
prettyprinter >= 1.2.0.1 && < 1.3 ,
@ -176,7 +177,6 @@ Library
scientific >= 0.3.0.0 && < 0.4 ,
text >= 0.11.1.0 && < 1.3 ,
transformers >= 0.2.0.0 && < 0.6 ,
trifecta >= 1.6 && < 1.8 ,
unordered-containers >= 0.1.3.0 && < 0.3 ,
vector >= 0.11.0.0 && < 0.13
Exposed-Modules:
@ -202,7 +202,7 @@ Executable dhall
optparse-generic >= 1.1.1 && < 1.4 ,
prettyprinter ,
prettyprinter-ansi-terminal >= 1.1.1 && < 1.2 ,
trifecta >= 1.6 && < 1.8 ,
megaparsec >= 6.4.0 && < 6.5 ,
text >= 0.11.1.0 && < 1.3
GHC-Options: -Wall -Wcompat
Other-Modules:
@ -220,8 +220,7 @@ Executable dhall-repl
repline >= 0.1.6.0 && < 0.2 ,
prettyprinter ,
prettyprinter-ansi-terminal ,
text ,
trifecta
text
GHC-Options: -Wall -Wcompat
Executable dhall-format
@ -231,10 +230,10 @@ Executable dhall-format
base >= 4 && < 5 ,
ansi-terminal >= 0.6.3.1 && < 0.9 ,
dhall ,
megaparsec >= 6.4.0 && < 6.5 ,
optparse-generic >= 1.1.1 && < 1.4 ,
prettyprinter >= 1.2.0.1 && < 1.3 ,
prettyprinter-ansi-terminal >= 1.1.1 && < 1.2 ,
trifecta >= 1.6 && < 1.8 ,
text >= 0.11.1.0 && < 1.3
GHC-Options: -Wall -Wcompat
Other-Modules:
@ -247,7 +246,7 @@ Executable dhall-hash
base >= 4 && < 5 ,
dhall ,
optparse-generic >= 1.1.1 && < 1.4,
trifecta >= 1.6 && < 1.8,
megaparsec >= 6.4.0 && < 6.5 ,
text >= 0.11.1.0 && < 1.3
Other-Modules:
Paths_dhall

View File

@ -19,7 +19,6 @@ import Dhall.Pretty (annToAnsiStyle, prettyExpr)
import Dhall.TypeCheck (DetailedTypeError(..), TypeError, X)
import Options.Generic (Generic, ParseRecord, Wrapped, type (<?>)(..), (:::))
import System.Exit (exitFailure, exitSuccess)
import Text.Trifecta.Delta (Delta(..))
import qualified Paths_dhall as Meta
@ -86,7 +85,7 @@ main = do
System.IO.hSetEncoding System.IO.stdin System.IO.utf8
inText <- Data.Text.Lazy.IO.getContents
expr <- case Dhall.Parser.exprFromText (Directed "(stdin)" 0 0 0 0) inText of
expr <- case Dhall.Parser.exprFromText "(stdin)" inText of
Left err -> Control.Exception.throwIO err
Right x -> return x

24
nix/megaparsec.nix Normal file
View File

@ -0,0 +1,24 @@
{ mkDerivation, base, bytestring, case-insensitive, containers
, criterion, deepseq, hspec, hspec-expectations, mtl
, parser-combinators, QuickCheck, scientific, stdenv, text
, transformers, weigh
}:
mkDerivation {
pname = "megaparsec";
version = "6.4.1";
sha256 = "de40015dac65c2707a0bd65b7974da4d0cc00593d8bdebc0d58319761ee21370";
revision = "2";
editedCabalFile = "0vh4l2kl9nfxlr8l82qicldybwiv6vbksi3jdk0xjzxmkvgm0jnf";
libraryHaskellDepends = [
base bytestring case-insensitive containers deepseq mtl
parser-combinators scientific text transformers
];
testHaskellDepends = [
base bytestring containers hspec hspec-expectations mtl QuickCheck
scientific text transformers
];
benchmarkHaskellDepends = [ base criterion deepseq text weigh ];
homepage = "https://github.com/mrkkrp/megaparsec";
description = "Monadic parser combinators";
license = stdenv.lib.licenses.bsd2;
}

View File

@ -0,0 +1,10 @@
{ mkDerivation, base, stdenv }:
mkDerivation {
pname = "parser-combinators";
version = "0.4.0";
sha256 = "b124e9411de085972e4d9ae8254299e8e773e964b2798eb400d5cf6814f8f3ab";
libraryHaskellDepends = [ base ];
homepage = "https://github.com/mrkkrp/parser-combinators";
description = "Lightweight package providing commonly useful parser combinators";
license = stdenv.lib.licenses.bsd3;
}

View File

@ -21,6 +21,12 @@ let
prettyprinter =
haskellPackagesNew.callPackage ./nix/prettyprinter.nix { };
parser-combinators =
haskellPackagesNew.callPackage ./nix/parser-combinators.nix { };
megaparsec =
haskellPackagesNew.callPackage ./nix/megaparsec.nix { };
};
};
};

View File

@ -82,10 +82,8 @@ import Formatting.Buildable (Buildable(..))
import GHC.Generics
import Numeric.Natural (Natural)
import Prelude hiding (maybe, sequence)
import Text.Trifecta.Delta (Delta(..))
import qualified Control.Exception
import qualified Data.ByteString.Lazy
import qualified Data.Foldable
import qualified Data.HashMap.Strict.InsOrd
import qualified Data.Scientific
@ -94,7 +92,6 @@ import qualified Data.Set
import qualified Data.Text
import qualified Data.Text.Lazy
import qualified Data.Text.Lazy.Builder
import qualified Data.Text.Lazy.Encoding
import qualified Data.Vector
import qualified Dhall.Context
import qualified Dhall.Core
@ -166,13 +163,10 @@ inputWith
-> IO a
-- ^ The decoded value in Haskell
inputWith (Type {..}) ctx n txt = do
let delta = Directed "(input)" 0 0 0 0
expr <- throws (Dhall.Parser.exprFromText delta txt)
expr <- throws (Dhall.Parser.exprFromText "(input)" txt)
expr' <- Dhall.Import.loadWithContext ctx expr
let suffix =
( Data.ByteString.Lazy.toStrict
. Data.Text.Lazy.Encoding.encodeUtf8
. Data.Text.Lazy.Builder.toLazyText
( Data.Text.Lazy.Builder.toLazyText
. build
) expected
let annot = case expr' of

View File

@ -157,15 +157,11 @@ import Network.HTTP.Client
#else
import Network.HTTP.Client (HttpException(..), Manager)
#endif
import Text.Trifecta (Result(..))
import Text.Trifecta.Delta (Delta(..))
import qualified Control.Monad.Trans.State.Strict as State
import qualified Crypto.Hash
import qualified Data.ByteArray
import qualified Data.ByteString
import qualified Data.ByteString.Char8
import qualified Data.ByteString.Lazy
import qualified Data.CaseInsensitive
import qualified Data.Foldable
import qualified Data.List as List
@ -186,9 +182,9 @@ import qualified Network.HTTP.Client.TLS as HTTP
import qualified System.Environment
import qualified System.Directory
import qualified System.FilePath as FilePath
import qualified Text.Megaparsec
import qualified Text.Parser.Combinators
import qualified Text.Parser.Token
import qualified Text.Trifecta
builderToString :: Builder -> String
builderToString = Text.unpack . Builder.toLazyText
@ -554,23 +550,6 @@ instance Show HashMismatch where
<> "\n"
<> "" <> show actualHash <> "\n"
parseFromFileEx
:: Text.Trifecta.Parser a
-> FilePath
-> IO (Text.Trifecta.Result a)
parseFromFileEx parser path = do
text <- Data.Text.Lazy.IO.readFile path
let lazyBytes = Data.Text.Lazy.Encoding.encodeUtf8 text
let strictBytes = Data.ByteString.Lazy.toStrict lazyBytes
let delta = Directed bytesPath 0 0 0 0
return (Text.Trifecta.parseByteString parser delta strictBytes)
where
bytesPath = Data.ByteString.Char8.pack path
-- | Parse an expression from a `Path` containing a Dhall program
exprFromPath :: Path -> StateT Status IO (Expr Src Path)
exprFromPath (Path {..}) = case pathType of
@ -592,18 +571,18 @@ exprFromPath (Path {..}) = case pathType of
-- Unfortunately, GHC throws an `InappropriateType` exception
-- when trying to read a directory, but does not export the
-- exception, so I must resort to a more heavy-handed `catch`
let handler :: IOException -> IO (Result (Expr Src Path))
let handler :: IOException -> IO Text
handler e = do
-- If the fallback fails, reuse the original exception
-- to avoid user confusion
parseFromFileEx parser (path </> "@")
Data.Text.Lazy.IO.readFile (path </> "@")
`onException` throwIO e
x <- parseFromFileEx parser path `catch` handler
case x of
Failure errInfo -> do
throwIO (ParseError (Text.Trifecta._errDoc errInfo))
Success expr -> do
text <- Data.Text.Lazy.IO.readFile path `catch` handler
case Text.Megaparsec.parse parser path text of
Left errInfo -> do
throwIO (ParseError errInfo text)
Right expr -> do
return expr
RawText -> do
text <- Data.Text.IO.readFile path
@ -637,9 +616,7 @@ exprFromPath (Path {..}) = case pathType of
)
)
let suffix =
( Data.ByteString.Lazy.toStrict
. Data.Text.Lazy.Encoding.encodeUtf8
. Builder.toLazyText
( Builder.toLazyText
. build
) expected
let annot = case expr of
@ -671,16 +648,13 @@ exprFromPath (Path {..}) = case pathType of
Right text -> return text
case pathMode of
Code -> do
let urlBytes = Data.Text.Lazy.Encoding.encodeUtf8 url
let delta =
Directed (Data.ByteString.Lazy.toStrict urlBytes) 0 0 0 0
case Text.Trifecta.parseString parser delta (Text.unpack text) of
Failure err -> do
Code ->
case Text.Megaparsec.parse parser (Text.unpack url) text of
Left err -> do
-- Also try the fallback in case of a parse error, since
-- the parse error might signify that this URL points to
-- a directory list
let err' = ParseError (Text.Trifecta._errDoc err)
let err' = ParseError err text
request' <- liftIO (HTTP.parseUrlThrow (Text.unpack url))
@ -695,25 +669,23 @@ exprFromPath (Path {..}) = case pathType of
Left _ -> liftIO (throwIO err')
Right text' -> return text'
case Text.Trifecta.parseString parser delta (Text.unpack text') of
Failure _ -> liftIO (throwIO err')
Success expr -> return expr
Success expr -> return expr
case Text.Megaparsec.parse parser (Text.unpack url) text' of
Left _ -> liftIO (throwIO err')
Right expr -> return expr
Right expr -> return expr
RawText -> do
return (TextLit (Chunks [] (build text)))
Env env -> liftIO (do
x <- System.Environment.lookupEnv (Text.unpack env)
case x of
Just str -> do
let text = Text.pack str
case pathMode of
Code -> do
let envBytes = Data.Text.Lazy.Encoding.encodeUtf8 env
let delta =
Directed (Data.ByteString.Lazy.toStrict envBytes) 0 0 0 0
case Text.Trifecta.parseString parser delta str of
Failure errInfo -> do
throwIO (ParseError (Text.Trifecta._errDoc errInfo))
Success expr -> do
Code ->
case Text.Megaparsec.parse parser (Text.unpack env) text of
Left errInfo -> do
throwIO (ParseError errInfo text)
Right expr -> do
return expr
RawText -> return (TextLit (Chunks [] (build str)))
Nothing -> throwIO (MissingEnvironmentVariable env) )

View File

@ -23,7 +23,6 @@ module Dhall.Parser (
import Control.Applicative (Alternative(..), liftA2, optional)
import Control.Exception (Exception)
import Control.Monad (MonadPlus)
import Data.ByteString (ByteString)
import Data.Functor (void)
import Data.HashMap.Strict.InsOrd (InsOrdHashMap)
import Data.Sequence (ViewL(..))
@ -32,17 +31,13 @@ import Data.Scientific (Scientific)
import Data.String (IsString(..))
import Data.Text.Lazy (Text)
import Data.Text.Lazy.Builder (Builder)
import Data.Typeable (Typeable)
import Data.Void (Void)
import Dhall.Core
import Formatting.Buildable (Buildable(..))
import Numeric.Natural (Natural)
import Prelude hiding (const, pi)
import Text.PrettyPrint.ANSI.Leijen (Doc)
import Text.Parser.Combinators (choice, try, (<?>))
import Text.Parser.Token (TokenParsing(..))
import Text.Trifecta
(CharParsing, DeltaParsing, MarkParsing, Parsing, Result(..))
import Text.Trifecta.Delta (Delta)
import qualified Control.Monad
import qualified Crypto.Hash
@ -53,46 +48,39 @@ import qualified Data.HashSet
import qualified Data.List
import qualified Data.Sequence
import qualified Data.Text
import qualified Data.Text.Encoding
import qualified Data.Text.Lazy
import qualified Data.Text.Lazy.Builder
import qualified Data.Text.Lazy.Encoding
import qualified Text.Megaparsec
import qualified Text.Megaparsec.Char
import qualified Text.Parser.Char
import qualified Text.Parser.Combinators
import qualified Text.Parser.Token
import qualified Text.Parser.Token.Style
import qualified Text.PrettyPrint.ANSI.Leijen
import qualified Text.Trifecta
-- | Source code extract
data Src = Src Delta Delta ByteString deriving (Eq, Show)
data Src = Src Text.Megaparsec.SourcePos Text.Megaparsec.SourcePos Text
deriving (Eq, Show)
instance Buildable Src where
build (Src begin _ bytes) =
build (Src begin _ text) =
build text <> "\n"
<> "\n"
<> build (show (Text.PrettyPrint.ANSI.Leijen.pretty begin))
<> build (show begin)
<> "\n"
where
bytes' = Data.ByteString.Lazy.fromStrict bytes
text = Data.Text.Lazy.strip (Data.Text.Lazy.Encoding.decodeUtf8 bytes')
{-| A `Parser` that is almost identical to
@"Text.Trifecta".`Text.Trifecta.Parser`@ except treating Haskell-style
@"Text.Megaparsec".`Text.Megaparsec.Parsec`@ except treating Haskell-style
comments as whitespace
-}
newtype Parser a = Parser { unParser :: Text.Trifecta.Parser a }
newtype Parser a = Parser { unParser :: Text.Megaparsec.Parsec Void Text a }
deriving
( Functor
, Applicative
, Monad
, Alternative
, MonadPlus
, Parsing
, CharParsing
, DeltaParsing
, MarkParsing Delta
, Text.Megaparsec.MonadParsec Void Text
)
instance Data.Semigroup.Semigroup a => Data.Semigroup.Semigroup (Parser a) where
@ -106,26 +94,52 @@ instance (Data.Semigroup.Semigroup a, Monoid a) => Monoid (Parser a) where
#endif
instance IsString a => IsString (Parser a) where
fromString x = fmap fromString (Text.Parser.Char.string x)
fromString x = fromString x <$ Text.Megaparsec.Char.string (fromString x)
instance Text.Parser.Combinators.Parsing Parser where
try = Text.Megaparsec.try
(<?>) = (Text.Megaparsec.<?>)
skipMany = Text.Megaparsec.skipMany
skipSome = Text.Megaparsec.skipSome
unexpected = fail
eof = Parser Text.Megaparsec.eof
notFollowedBy = Text.Megaparsec.notFollowedBy
instance Text.Parser.Char.CharParsing Parser where
satisfy = Parser . Text.Megaparsec.Char.satisfy
char = Text.Megaparsec.Char.char
notChar = Text.Megaparsec.Char.char
anyChar = Text.Megaparsec.Char.anyChar
string = fmap Data.Text.Lazy.unpack . Text.Megaparsec.Char.string . fromString
text = fmap Data.Text.Lazy.toStrict . Text.Megaparsec.Char.string . Data.Text.Lazy.fromStrict
instance TokenParsing Parser where
someSpace =
Text.Parser.Token.Style.buildSomeSpaceParser
(Parser someSpace)
(Parser (Text.Megaparsec.skipSome (Text.Megaparsec.Char.satisfy Data.Char.isSpace)))
Text.Parser.Token.Style.haskellCommentStyle
nesting (Parser m) = Parser (nesting m)
highlight _ = id
semi = Parser semi
highlight h (Parser m) = Parser (highlight h m)
semi = token (Text.Megaparsec.Char.char ';' <?> ";")
noted :: Parser (Expr Src a) -> Parser (Expr Src a)
noted parser = do
before <- Text.Trifecta.position
(e, bytes) <- Text.Trifecta.slicedWith (,) parser
after <- Text.Trifecta.position
return (Note (Src before after bytes) e)
before <- Text.Megaparsec.getPosition
(tokens, e) <- Text.Megaparsec.match parser
after <- Text.Megaparsec.getPosition
return (Note (Src before after tokens) e)
count :: (Semigroup a, Monoid a) => Int -> Parser a -> Parser a
count n parser = mconcat (replicate n parser)
@ -1531,16 +1545,19 @@ import_ = (do
return RawText
-- | A parsing error
newtype ParseError = ParseError Doc deriving (Typeable)
data ParseError = ParseError
{ unwrap :: Text.Megaparsec.ParseError Char Void
, input :: Text
}
instance Show ParseError where
show (ParseError doc) =
"\n\ESC[1;31mError\ESC[0m: Invalid input\n\n" <> show doc
show (ParseError {..}) =
"\n\ESC[1;31mError\ESC[0m: Invalid input\n\n" <> Text.Megaparsec.parseErrorPretty' input unwrap
instance Exception ParseError
-- | Parse an expression from `Text` containing a Dhall program
exprFromText :: Delta -> Text -> Either ParseError (Expr Src Path)
exprFromText :: String -> Text -> Either ParseError (Expr Src Path)
exprFromText delta text = fmap snd (exprAndHeaderFromText delta text)
{-| Like `exprFromText` but also returns the leading comments and whitespace
@ -1556,24 +1573,17 @@ exprFromText delta text = fmap snd (exprAndHeaderFromText delta text)
This is used by @dhall-format@ to preserve leading comments and whitespace
-}
exprAndHeaderFromText
:: Delta
:: String
-> Text
-> Either ParseError (Text, Expr Src Path)
exprAndHeaderFromText delta text = case result of
Failure errInfo -> Left (ParseError (Text.Trifecta._errDoc errInfo))
Success (bytes, r) -> case Data.Text.Encoding.decodeUtf8' bytes of
Left errInfo -> Left (ParseError (fromString (show errInfo)))
Right txt -> do
let stripped = Data.Text.dropWhileEnd (/= '\n') txt
let lazyText = Data.Text.Lazy.fromStrict stripped
Right (lazyText, r)
Left errInfo -> Left (ParseError { unwrap = errInfo, input = text })
Right (txt, r) -> Right (Data.Text.Lazy.dropWhileEnd (/= '\n') txt, r)
where
string = Data.Text.Lazy.unpack text
parser = unParser (do
bytes <- Text.Trifecta.slicedWith (\_ x -> x) whitespace
parser = do
(bytes, _) <- Text.Megaparsec.match whitespace
r <- expr
Text.Parser.Combinators.eof
return (bytes, r) )
Text.Megaparsec.eof
return (bytes, r)
result = Text.Trifecta.parseString parser delta string
result = Text.Megaparsec.parse (unParser parser) delta text