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:
parent
0ffe854d6d
commit
922e20e6ab
27
default.nix
27
default.nix
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 )
|
||||
|
||||
|
|
13
dhall.cabal
13
dhall.cabal
|
@ -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
|
||||
|
|
|
@ -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
24
nix/megaparsec.nix
Normal 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;
|
||||
}
|
10
nix/parser-combinators.nix
Normal file
10
nix/parser-combinators.nix
Normal 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;
|
||||
}
|
|
@ -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 { };
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
10
src/Dhall.hs
10
src/Dhall.hs
|
@ -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
|
||||
|
|
|
@ -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) )
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue
Block a user