packages feed

dhall 1.14.0 → 1.15.0

raw patch · 80 files changed

+5431/−4088 lines, 80 filesdep +Diffdep +criteriondep +template-haskelldep −formattingdep ~ansi-terminaldep ~basedep ~doctestPVP ok

version bump matches the API change (PVP)

Dependencies added: Diff, criterion, template-haskell

Dependencies removed: formatting

Dependency ranges changed: ansi-terminal, base, doctest, megaparsec, prettyprinter, prettyprinter-ansi-terminal, text

API changes (from Hackage documentation)

- Dhall.Core: Parent :: FilePrefix
- Dhall.Core: instance Data.Semigroup.Semigroup (Dhall.Core.Chunks s a)
- Dhall.Core: instance Data.Semigroup.Semigroup Dhall.Core.Directory
- Dhall.Core: instance Data.Semigroup.Semigroup Dhall.Core.File
- Dhall.Core: instance Data.Semigroup.Semigroup Dhall.Core.Import
- Dhall.Core: instance Data.Semigroup.Semigroup Dhall.Core.ImportHashed
- Dhall.Core: instance Data.Semigroup.Semigroup Dhall.Core.ImportType
- Dhall.Core: instance Formatting.Buildable.Buildable Dhall.Core.Const
- Dhall.Core: instance Formatting.Buildable.Buildable Dhall.Core.Directory
- Dhall.Core: instance Formatting.Buildable.Buildable Dhall.Core.File
- Dhall.Core: instance Formatting.Buildable.Buildable Dhall.Core.FilePrefix
- Dhall.Core: instance Formatting.Buildable.Buildable Dhall.Core.Import
- Dhall.Core: instance Formatting.Buildable.Buildable Dhall.Core.ImportHashed
- Dhall.Core: instance Formatting.Buildable.Buildable Dhall.Core.ImportType
- Dhall.Core: instance Formatting.Buildable.Buildable Dhall.Core.Var
- Dhall.Core: instance Formatting.Buildable.Buildable a => Formatting.Buildable.Buildable (Dhall.Core.Expr s a)
- Dhall.Diff: instance Data.Semigroup.Semigroup Dhall.Diff.Diff
- Dhall.Import: instance GHC.Exception.Exception Dhall.Import.InternalError
- Dhall.Import: instance GHC.Exception.Exception Dhall.Import.PrettyHttpException
- Dhall.Import: instance GHC.Show.Show Dhall.Import.InternalError
- Dhall.Import: instance GHC.Show.Show Dhall.Import.PrettyHttpException
- Dhall.Import: newtype PrettyHttpException
- Dhall.Parser: instance (Data.Semigroup.Semigroup a, GHC.Base.Monoid a) => GHC.Base.Monoid (Dhall.Parser.Parser a)
- Dhall.Parser: instance Data.Semigroup.Semigroup a => Data.Semigroup.Semigroup (Dhall.Parser.Parser a)
- Dhall.Parser: instance Data.String.IsString a => Data.String.IsString (Dhall.Parser.Parser a)
- Dhall.Parser: instance Formatting.Buildable.Buildable Dhall.Parser.Src
- Dhall.Parser: instance GHC.Base.Alternative Dhall.Parser.Parser
- Dhall.Parser: instance GHC.Base.Applicative Dhall.Parser.Parser
- Dhall.Parser: instance GHC.Base.Functor Dhall.Parser.Parser
- Dhall.Parser: instance GHC.Base.Monad Dhall.Parser.Parser
- Dhall.Parser: instance GHC.Base.MonadPlus Dhall.Parser.Parser
- Dhall.Parser: instance GHC.Classes.Eq Dhall.Parser.Src
- Dhall.Parser: instance GHC.Show.Show Dhall.Parser.Src
- Dhall.Parser: instance Text.Megaparsec.Class.MonadParsec Data.Void.Void Data.Text.Internal.Lazy.Text Dhall.Parser.Parser
- Dhall.Parser: instance Text.Parser.Char.CharParsing Dhall.Parser.Parser
- Dhall.Parser: instance Text.Parser.Combinators.Parsing Dhall.Parser.Parser
- Dhall.Parser: instance Text.Parser.Token.TokenParsing Dhall.Parser.Parser
- Dhall.TypeCheck: instance (Formatting.Buildable.Buildable a, Formatting.Buildable.Buildable s, GHC.Classes.Eq a, Data.Text.Prettyprint.Doc.Internal.Pretty a) => Formatting.Buildable.Buildable (Dhall.TypeCheck.DetailedTypeError s a)
- Dhall.TypeCheck: instance (Formatting.Buildable.Buildable a, Formatting.Buildable.Buildable s, GHC.Classes.Eq a, Data.Text.Prettyprint.Doc.Internal.Pretty a) => Formatting.Buildable.Buildable (Dhall.TypeCheck.TypeError s a)
- Dhall.TypeCheck: instance (Formatting.Buildable.Buildable a, Formatting.Buildable.Buildable s, GHC.Classes.Eq a, Data.Text.Prettyprint.Doc.Internal.Pretty a) => GHC.Show.Show (Dhall.TypeCheck.DetailedTypeError s a)
- Dhall.TypeCheck: instance (Formatting.Buildable.Buildable a, Formatting.Buildable.Buildable s, GHC.Classes.Eq a, Data.Text.Prettyprint.Doc.Internal.Pretty a) => GHC.Show.Show (Dhall.TypeCheck.TypeError s a)
- Dhall.TypeCheck: instance (Formatting.Buildable.Buildable a, Formatting.Buildable.Buildable s, GHC.Classes.Eq a, Data.Text.Prettyprint.Doc.Internal.Pretty a, Data.Typeable.Internal.Typeable a, Data.Typeable.Internal.Typeable s) => GHC.Exception.Exception (Dhall.TypeCheck.DetailedTypeError s a)
- Dhall.TypeCheck: instance (Formatting.Buildable.Buildable a, Formatting.Buildable.Buildable s, GHC.Classes.Eq a, Data.Text.Prettyprint.Doc.Internal.Pretty a, Data.Typeable.Internal.Typeable a, Data.Typeable.Internal.Typeable s) => GHC.Exception.Exception (Dhall.TypeCheck.TypeError s a)
- Dhall.TypeCheck: instance (GHC.Show.Show a, GHC.Show.Show s) => GHC.Show.Show (Dhall.TypeCheck.TypeMessage s a)
- Dhall.TypeCheck: instance Formatting.Buildable.Buildable Dhall.TypeCheck.X
+ Dhall: inputExpr :: Text -> IO (Expr Src X)
+ Dhall: inputExprWith :: Context (Expr Src X) -> Normalizer X -> Text -> IO (Expr Src X)
+ Dhall: inputFrom :: FilePath -> Type a -> Text -> IO a
+ Dhall: inputFromWith :: FilePath -> Type a -> Context (Expr Src X) -> Normalizer X -> Text -> IO a
+ Dhall.Core: ImportAlt :: (Expr s a) -> (Expr s a) -> Expr s a
+ Dhall.Core: IntegerToDouble :: Expr s a
+ Dhall.Core: Missing :: ImportType
+ Dhall.Core: freeIn :: Eq a => Var -> Expr s a -> Bool
+ Dhall.Core: instance (Data.Data.Data s, Data.Data.Data a) => Data.Data.Data (Dhall.Core.Chunks s a)
+ Dhall.Core: instance (Data.Data.Data s, Data.Data.Data a) => Data.Data.Data (Dhall.Core.Expr s a)
+ Dhall.Core: instance Data.Data.Data Dhall.Core.Const
+ Dhall.Core: instance Data.Data.Data Dhall.Core.Var
+ Dhall.Core: instance Data.Text.Prettyprint.Doc.Internal.Pretty Dhall.Core.Const
+ Dhall.Core: instance Data.Text.Prettyprint.Doc.Internal.Pretty Dhall.Core.Directory
+ Dhall.Core: instance Data.Text.Prettyprint.Doc.Internal.Pretty Dhall.Core.File
+ Dhall.Core: instance Data.Text.Prettyprint.Doc.Internal.Pretty Dhall.Core.FilePrefix
+ Dhall.Core: instance Data.Text.Prettyprint.Doc.Internal.Pretty Dhall.Core.ImportHashed
+ Dhall.Core: instance Data.Text.Prettyprint.Doc.Internal.Pretty Dhall.Core.ImportType
+ Dhall.Core: instance Data.Text.Prettyprint.Doc.Internal.Pretty Dhall.Core.Var
+ Dhall.Core: instance GHC.Base.Semigroup (Dhall.Core.Chunks s a)
+ Dhall.Core: instance GHC.Base.Semigroup Dhall.Core.Directory
+ Dhall.Core: instance GHC.Base.Semigroup Dhall.Core.File
+ Dhall.Core: instance GHC.Base.Semigroup Dhall.Core.Import
+ Dhall.Core: instance GHC.Base.Semigroup Dhall.Core.ImportHashed
+ Dhall.Core: instance GHC.Base.Semigroup Dhall.Core.ImportType
+ Dhall.Diff: instance GHC.Base.Semigroup Dhall.Diff.Diff
+ Dhall.Format: format :: Maybe FilePath -> IO ()
+ Dhall.Freeze: freeze :: Maybe FilePath -> IO ()
+ Dhall.Freeze: hashImport :: Import -> IO Import
+ Dhall.Hash: hash :: IO ()
+ Dhall.Import: MissingImports :: [SomeException] -> MissingImports
+ Dhall.Import: data PrettyHttpException
+ Dhall.Import: instance GHC.Exception.Exception Dhall.Import.CannotImportHTTPURL
+ Dhall.Import: instance GHC.Exception.Exception Dhall.Import.MissingImports
+ Dhall.Import: instance GHC.Show.Show Dhall.Import.CannotImportHTTPURL
+ Dhall.Import: instance GHC.Show.Show Dhall.Import.MissingImports
+ Dhall.Import: newtype MissingImports
+ Dhall.Lint: lint :: Expr s Import -> Expr t Import
+ Dhall.Main: command :: Options -> IO ()
+ Dhall.Main: instance GHC.Exception.Exception Dhall.Main.ImportResolutionDisabled
+ Dhall.Main: instance GHC.Show.Show Dhall.Main.ImportResolutionDisabled
+ Dhall.Main: main :: IO ()
+ Dhall.Main: parseOptions :: Parser Options
+ Dhall.Main: parserInfoOptions :: ParserInfo Options
+ Dhall.Repl: repl :: Bool -> IO ()
+ Dhall.TH: staticDhallExpression :: Text -> Q Exp
+ Dhall.TypeCheck: instance (GHC.Classes.Eq a, Data.Text.Prettyprint.Doc.Internal.Pretty s, Data.Text.Prettyprint.Doc.Internal.Pretty a) => Data.Text.Prettyprint.Doc.Internal.Pretty (Dhall.TypeCheck.DetailedTypeError s a)
+ Dhall.TypeCheck: instance (GHC.Classes.Eq a, Data.Text.Prettyprint.Doc.Internal.Pretty s, Data.Text.Prettyprint.Doc.Internal.Pretty a) => Data.Text.Prettyprint.Doc.Internal.Pretty (Dhall.TypeCheck.TypeError s a)
+ Dhall.TypeCheck: instance (GHC.Classes.Eq a, Data.Text.Prettyprint.Doc.Internal.Pretty s, Data.Text.Prettyprint.Doc.Internal.Pretty a) => GHC.Show.Show (Dhall.TypeCheck.DetailedTypeError s a)
+ Dhall.TypeCheck: instance (GHC.Classes.Eq a, Data.Text.Prettyprint.Doc.Internal.Pretty s, Data.Text.Prettyprint.Doc.Internal.Pretty a) => GHC.Show.Show (Dhall.TypeCheck.TypeError s a)
+ Dhall.TypeCheck: instance (GHC.Classes.Eq a, Data.Text.Prettyprint.Doc.Internal.Pretty s, Data.Text.Prettyprint.Doc.Internal.Pretty a, Data.Typeable.Internal.Typeable s, Data.Typeable.Internal.Typeable a) => GHC.Exception.Exception (Dhall.TypeCheck.DetailedTypeError s a)
+ Dhall.TypeCheck: instance (GHC.Classes.Eq a, Data.Text.Prettyprint.Doc.Internal.Pretty s, Data.Text.Prettyprint.Doc.Internal.Pretty a, Data.Typeable.Internal.Typeable s, Data.Typeable.Internal.Typeable a) => GHC.Exception.Exception (Dhall.TypeCheck.TypeError s a)
+ Dhall.TypeCheck: instance (GHC.Show.Show s, GHC.Show.Show a) => GHC.Show.Show (Dhall.TypeCheck.TypeMessage s a)
+ Dhall.TypeCheck: instance Data.Data.Data Dhall.TypeCheck.X
- Dhall: InputType :: (a -> Expr Src X) -> Expr Src X -> InputType a
+ Dhall: InputType :: a -> Expr Src X -> Expr Src X -> InputType a
- Dhall: InterpretOptions :: (Text -> Text) -> (Text -> Text) -> InterpretOptions
+ Dhall: InterpretOptions :: Text -> Text -> Text -> Text -> InterpretOptions
- Dhall: Type :: (Expr Src X -> Maybe a) -> Expr Src X -> Type a
+ Dhall: Type :: Expr Src X -> Maybe a -> Expr Src X -> Type a
- Dhall: data Natural :: *
+ Dhall: data Natural
- Dhall: data Seq a :: * -> *
+ Dhall: data Seq a
- Dhall: data Text :: *
+ Dhall: data Text
- Dhall: data Vector a :: * -> *
+ Dhall: data Vector a
- Dhall.Core: Chunks :: [(Builder, Expr s a)] -> Builder -> Chunks s a
+ Dhall.Core: Chunks :: [(Text, Expr s a)] -> Text -> Chunks s a
- Dhall.Core: escapeText :: Builder -> Builder
+ Dhall.Core: escapeText :: Text -> Text
- Dhall.Import: PrettyHttpException :: HttpException -> PrettyHttpException
+ Dhall.Import: PrettyHttpException :: String -> Dynamic -> PrettyHttpException
- Dhall.Import: Status :: [Import] -> Map Import (Expr Src X) -> Maybe Manager -> Status
+ Dhall.Import: Status :: [Import] -> Map Import (Expr Src X) -> Maybe Dynamic -> Status
- Dhall.Import: [_manager] :: Status -> Maybe Manager
+ Dhall.Import: [_manager] :: Status -> Maybe Dynamic
- Dhall.TypeCheck: X :: (forall a. a) -> X
+ Dhall.TypeCheck: X :: forall a. a -> X

Files

CHANGELOG.md view
@@ -1,3 +1,54 @@+1.15.0++* BREAKING CHANGE TO THE API: Support alternative imports using new `?` operator+    * This adds a new constructor which affects exhaustive pattern matches+    * See: https://github.com/dhall-lang/dhall-haskell/pull/473+* BREAKING CHANGE TO THE API: Add `Integer/toDouble` built-in function+    * This adds a new constructor which affects exhaustive pattern matches+    * See: https://github.com/dhall-lang/dhall-haskell/pull/434+* BREAKING CHANGE TO THE API: Use strict `Text` instead of lazy `Text`+    * See: https://github.com/dhall-lang/dhall-haskell/pull/455+* BREAKING CHANGE TO THE API: Remove `Buildable` in favor of `Pretty`+    * See: https://github.com/dhall-lang/dhall-haskell/pull/459+* BREAKING CHANGE TO THE API: Removed the `Parent` constructor from `FilePrefix`+    * Instead, use `Here` with a `".."` prefix.+    * See: https://github.com/dhall-lang/dhall-haskell/pull/407+* BUG FIX: Disallow duplicate fields in records+    * See: https://github.com/dhall-lang/dhall-haskell/pull/430+* BUG FIX: Fix stripping of leading whitespace in multi-line strings+    * See: https://github.com/dhall-lang/dhall-haskell/pull/469+* BUG FIX: Fix formatting field access of an import+    * See: https://github.com/dhall-lang/dhall-haskell/pull/471+* Add `dhall freeze` command+    * See: https://github.com/dhall-lang/dhall-haskell/pull/486+* Add `dhall diff` command+    * See: https://github.com/dhall-lang/dhall-haskell/pull/442+* Add `dhall lint` command+    * See: https://github.com/dhall-lang/dhall-haskell/pull/484+* Change `dhall-repl`/`dhall-hash`/`dhall-format` to `dhall` subcommands+    * i.e. `dhall repl`/`dhall hash`/`dhall format`+    * See: https://github.com/dhall-lang/dhall-haskell/pull/435+    * See: https://github.com/dhall-lang/dhall-haskell/pull/452+* Add `with-http` cabal flag to disable support for remote imports+    * See: https://github.com/dhall-lang/dhall-haskell/pull/482+* Added `inputFrom` and `inputFromWith`+    * These allow naming the file that the expression is coming from for better+      error messages+    * See: https://github.com/dhall-lang/dhall-haskell/pull/464+* Performance improvements+    * See: https://github.com/dhall-lang/dhall-haskell/pull/420+* Tutorial recommends GitHub for Prelude instead of IPFS+    * See: https://github.com/dhall-lang/dhall-haskell/pull/479+* Pretty-print expressions in type errors+    * See: https://github.com/dhall-lang/dhall-haskell/pull/429+* Formatting improvements+    * See: https://github.com/dhall-lang/dhall-haskell/pull/398+    * See: https://github.com/dhall-lang/dhall-haskell/pull/458+* Diff improvements+    * See: https://github.com/dhall-lang/dhall-haskell/pull/455+    * See: https://github.com/dhall-lang/dhall-haskell/pull/470+    * See: https://github.com/dhall-lang/dhall-haskell/pull/478+ 1.14.0  * BREAKING CHANGE TO THE LANGUAGE: Switch grammar of `Natural` and `Integer`
+ Prelude/Integer/toDouble view
@@ -0,0 +1,12 @@+{-+Convert an `Integer` to the corresponding `Double`++Examples:++```+./toDouble -3 = -3.0++./toDouble +2 = 2.0+```+-}+let toDouble : Integer → Double = Integer/toDouble in toDouble
+ Prelude/Natural/toDouble view
@@ -0,0 +1,16 @@+{-+Convert a `Natural` number to the corresponding `Double`++Examples:++```+./toDouble 3 = 3.0++./toDouble 0 = 0.0+```+-}+    let toDouble+        : Natural → Double+        = λ(n : Natural) → Integer/toDouble (Natural/toInteger n)++in  toDouble
+ benchmark/deep-nested-large-record/BigEnum.dhall view
@@ -0,0 +1,302 @@+< A0 : {}+| A1 : {}+| A2 : {}+| A3 : {}+| A4 : {}+| A5 : {}+| A6 : {}+| A7 : {}+| A8 : {}+| A9 : {}+| A10 : {}+| A11 : {}+| A12 : {}+| A13 : {}+| A14 : {}+| A15 : {}+| A16 : {}+| A17 : {}+| A18 : {}+| A19 : {}+| A20 : {}+| A21 : {}+| A22 : {}+| A23 : {}+| A24 : {}+| A25 : {}+| A26 : {}+| A27 : {}+| A28 : {}+| A29 : {}+| A30 : {}+| A31 : {}+| A32 : {}+| A33 : {}+| A34 : {}+| A35 : {}+| A36 : {}+| A37 : {}+| A38 : {}+| A39 : {}+| A40 : {}+| A41 : {}+| A42 : {}+| A43 : {}+| A44 : {}+| A45 : {}+| A46 : {}+| A47 : {}+| A48 : {}+| A49 : {}+| A50 : {}+| A51 : {}+| A52 : {}+| A53 : {}+| A54 : {}+| A55 : {}+| A56 : {}+| A57 : {}+| A58 : {}+| A59 : {}+| A60 : {}+| A61 : {}+| A62 : {}+| A63 : {}+| A64 : {}+| A65 : {}+| A66 : {}+| A67 : {}+| A68 : {}+| A69 : {}+| A70 : {}+| A71 : {}+| A72 : {}+| A73 : {}+| A74 : {}+| A75 : {}+| A76 : {}+| A77 : {}+| A78 : {}+| A79 : {}+| A80 : {}+| A81 : {}+| A82 : {}+| A83 : {}+| A84 : {}+| A85 : {}+| A86 : {}+| A87 : {}+| A88 : {}+| A89 : {}+| A90 : {}+| A91 : {}+| A92 : {}+| A93 : {}+| A94 : {}+| A95 : {}+| A96 : {}+| A97 : {}+| A98 : {}+| A99 : {}+| A100 : {}+| A101 : {}+| A102 : {}+| A103 : {}+| A104 : {}+| A105 : {}+| A106 : {}+| A107 : {}+| A108 : {}+| A109 : {}+| A110 : {}+| A111 : {}+| A112 : {}+| A113 : {}+| A114 : {}+| A115 : {}+| A116 : {}+| A117 : {}+| A118 : {}+| A119 : {}+| A120 : {}+| A121 : {}+| A122 : {}+| A123 : {}+| A124 : {}+| A125 : {}+| A126 : {}+| A127 : {}+| A128 : {}+| A129 : {}+| A130 : {}+| A131 : {}+| A132 : {}+| A133 : {}+| A134 : {}+| A135 : {}+| A136 : {}+| A137 : {}+| A138 : {}+| A139 : {}+| A140 : {}+| A141 : {}+| A142 : {}+| A143 : {}+| A144 : {}+| A145 : {}+| A146 : {}+| A147 : {}+| A148 : {}+| A149 : {}+| A150 : {}+| A151 : {}+| A152 : {}+| A153 : {}+| A154 : {}+| A155 : {}+| A156 : {}+| A157 : {}+| A158 : {}+| A159 : {}+| A160 : {}+| A161 : {}+| A162 : {}+| A163 : {}+| A164 : {}+| A165 : {}+| A166 : {}+| A167 : {}+| A168 : {}+| A169 : {}+| A170 : {}+| A171 : {}+| A172 : {}+| A173 : {}+| A174 : {}+| A175 : {}+| A176 : {}+| A177 : {}+| A178 : {}+| A179 : {}+| A180 : {}+| A181 : {}+| A182 : {}+| A183 : {}+| A184 : {}+| A185 : {}+| A186 : {}+| A187 : {}+| A188 : {}+| A189 : {}+| A190 : {}+| A191 : {}+| A192 : {}+| A193 : {}+| A194 : {}+| A195 : {}+| A196 : {}+| A197 : {}+| A198 : {}+| A199 : {}+| A200 : {}+| A201 : {}+| A202 : {}+| A203 : {}+| A204 : {}+| A205 : {}+| A206 : {}+| A207 : {}+| A208 : {}+| A209 : {}+| A210 : {}+| A211 : {}+| A212 : {}+| A213 : {}+| A214 : {}+| A215 : {}+| A216 : {}+| A217 : {}+| A218 : {}+| A219 : {}+| A220 : {}+| A221 : {}+| A222 : {}+| A223 : {}+| A224 : {}+| A225 : {}+| A226 : {}+| A227 : {}+| A228 : {}+| A229 : {}+| A230 : {}+| A231 : {}+| A232 : {}+| A233 : {}+| A234 : {}+| A235 : {}+| A236 : {}+| A237 : {}+| A238 : {}+| A239 : {}+| A240 : {}+| A241 : {}+| A242 : {}+| A243 : {}+| A244 : {}+| A245 : {}+| A246 : {}+| A247 : {}+| A248 : {}+| A249 : {}+| A250 : {}+| A251 : {}+| A252 : {}+| A253 : {}+| A254 : {}+| A255 : {}+| A256 : {}+| A257 : {}+| A258 : {}+| A259 : {}+| A260 : {}+| A261 : {}+| A262 : {}+| A263 : {}+| A264 : {}+| A265 : {}+| A266 : {}+| A267 : {}+| A268 : {}+| A269 : {}+| A270 : {}+| A271 : {}+| A272 : {}+| A273 : {}+| A274 : {}+| A275 : {}+| A276 : {}+| A277 : {}+| A278 : {}+| A279 : {}+| A280 : {}+| A281 : {}+| A282 : {}+| A283 : {}+| A284 : {}+| A285 : {}+| A286 : {}+| A287 : {}+| A288 : {}+| A289 : {}+| A290 : {}+| A291 : {}+| A292 : {}+| A293 : {}+| A294 : {}+| A295 : {}+| A296 : {}+| A297 : {}+| A298 : {}+| A299 : {}+| A300 : {}+>
+ benchmark/deep-nested-large-record/LittleEnum.dhall view
@@ -0,0 +1,4 @@+< Foo : {}+| Bar : {}+| Baz : {}+>
+ benchmark/deep-nested-large-record/Main.hs view
@@ -0,0 +1,37 @@+{-# LANGUAGE OverloadedStrings #-}+module Main (main) where++import qualified Criterion as Criterion+import Criterion.Main (defaultMain)+import qualified Data.Sequence as Seq+import qualified Dhall.Core as Core+import qualified Dhall.Import as Import+import qualified Dhall.TypeCheck as TypeCheck++dhallPreludeImport :: Core.Import+dhallPreludeImport = Core.Import+  { Core.importMode = Core.Code+  , Core.importHashed = Core.ImportHashed+    { Core.hash = Nothing+    , Core.importType = Core.Local Core.Here $ Core.File+      { Core.directory = Core.Directory ["deep-nested-large-record", "benchmark"]+      , Core.file = "prelude.dhall"+      }+    }+  }++issue412 :: Core.Expr s TypeCheck.X -> Criterion.Benchmarkable+issue412 prelude = Criterion.whnf TypeCheck.typeOf expr+  where+    expr+      = Core.Let "prelude" Nothing prelude+      $ Core.ListLit Nothing+      $ Seq.replicate 5+      $ Core.Var (Core.V "prelude" 0) `Core.Field` "types" `Core.Field` "Little" `Core.Field` "Foo"++main :: IO ()+main = do+  prelude <- Import.load (Core.Embed dhallPreludeImport)+  defaultMain+    [ Criterion.bench "issue 412" (issue412 prelude)+    ]
+ benchmark/deep-nested-large-record/prelude.dhall view
@@ -0,0 +1,5 @@+{ types =+  { Big = constructors ./BigEnum.dhall+  , Little = constructors ./LittleEnum.dhall+  }+}
+ benchmark/examples/issue108.dhall view
@@ -0,0 +1,61 @@+λ(xs : List { cores : Natural, host : Text, key : Text, mandatoryFeatures : +List Text, platforms : List < AArch64_Linux : {} | ARMv5tel_Linux : {} | +ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux : {} | MIPS64el_Linux : {} | +PowerPC_Linux : {} | X86_64_Cygwin : {} | X86_64_Darwin : {} | X86_64_FreeBSD : +{} | X86_64_Linux : {} | X86_64_Solaris : {} >, speedFactor : Natural, +supportedFeatures : List Text, user : Optional Text }) → List/fold { cores : +Natural, host : Text, key : Text, mandatoryFeatures : List Text, platforms : +List < AArch64_Linux : {} | ARMv5tel_Linux : {} | ARMv7l_Linux : {} | +I686_Cygwin : {} | I686_Linux : {} | MIPS64el_Linux : {} | PowerPC_Linux : {} | +X86_64_Cygwin : {} | X86_64_Darwin : {} | X86_64_FreeBSD : {} | X86_64_Linux : +{} | X86_64_Solaris : {} >, speedFactor : Natural, supportedFeatures : List +Text, user : Optional Text } xs Text (λ(x : { cores : Natural, host : Text, +key : Text, mandatoryFeatures : List Text, platforms : List < AArch64_Linux : +{} | ARMv5tel_Linux : {} | ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux : +{} | MIPS64el_Linux : {} | PowerPC_Linux : {} | X86_64_Cygwin : {} | +X86_64_Darwin : {} | X86_64_FreeBSD : {} | X86_64_Linux : {} | X86_64_Solaris : +{} >, speedFactor : Natural, supportedFeatures : List Text, user : Optional +Text }) → λ(y : Text) → (Optional/fold Text x.user Text (λ(user : Text) +→ user ++ "@" ++ x.host ++ "") x.host ++ " " ++ (merge { Empty = λ(_ : {}) +→ "", NonEmpty = λ(result : Text) → result } (List/fold < AArch64_Linux : +{} | ARMv5tel_Linux : {} | ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux : +{} | MIPS64el_Linux : {} | PowerPC_Linux : {} | X86_64_Cygwin : {} | +X86_64_Darwin : {} | X86_64_FreeBSD : {} | X86_64_Linux : {} | X86_64_Solaris : +{} > x.platforms < Empty : {} | NonEmpty : Text > (λ(element : < AArch64_Linux +: {} | ARMv5tel_Linux : {} | ARMv7l_Linux : {} | I686_Cygwin : {} | I686_Linux +: {} | MIPS64el_Linux : {} | PowerPC_Linux : {} | X86_64_Cygwin : {} | +X86_64_Darwin : {} | X86_64_FreeBSD : {} | X86_64_Linux : {} | X86_64_Solaris : +{} >) → λ(status : < Empty : {} | NonEmpty : Text >) → merge { Empty = +λ(_ : {}) → < NonEmpty = merge { AArch64_Linux = λ(_ : {}) → +"aarch64-linux", ARMv5tel_Linux = λ(_ : {}) → "armv5tel-linux", ARMv7l_Linux += λ(_ : {}) → "armv7l-linux", I686_Cygwin = λ(_ : {}) → "i686-cygwin", +I686_Linux = λ(_ : {}) → "i686-linux", MIPS64el_Linux = λ(_ : {}) → +"mips64el-linux", PowerPC_Linux = λ(_ : {}) → "powerpc-linux", X86_64_Cygwin += λ(_ : {}) → "x86_64-cygwin", X86_64_Darwin = λ(_ : {}) → +"x86_64-darwin", X86_64_FreeBSD = λ(_ : {}) → "x86_64-freebsd", X86_64_Linux += λ(_ : {}) → "x86_64-linux", X86_64_Solaris = λ(_ : {}) → +"x86_64-solaris" } element | Empty : {} >, NonEmpty = λ(result : Text) → < +NonEmpty = (merge { AArch64_Linux = λ(_ : {}) → "aarch64-linux", +ARMv5tel_Linux = λ(_ : {}) → "armv5tel-linux", ARMv7l_Linux = λ(_ : {}) → +"armv7l-linux", I686_Cygwin = λ(_ : {}) → "i686-cygwin", I686_Linux = λ(_ : +{}) → "i686-linux", MIPS64el_Linux = λ(_ : {}) → "mips64el-linux", +PowerPC_Linux = λ(_ : {}) → "powerpc-linux", X86_64_Cygwin = λ(_ : {}) → +"x86_64-cygwin", X86_64_Darwin = λ(_ : {}) → "x86_64-darwin", X86_64_FreeBSD += λ(_ : {}) → "x86_64-freebsd", X86_64_Linux = λ(_ : {}) → +"x86_64-linux", X86_64_Solaris = λ(_ : {}) → "x86_64-solaris" } element) ++ +"," ++ result | Empty : {} > } status : < Empty : {} | NonEmpty : Text >) < +Empty = {=} | NonEmpty : Text >) : Text) ++ " " ++ x.key ++ " " ++ Integer/show +(Natural/toInteger x.cores) ++ " " ++ Integer/show (Natural/toInteger +x.speedFactor) ++ " " ++ (merge { Empty = λ(_ : {}) → "", NonEmpty = +λ(result : Text) → result } (List/fold Text x.supportedFeatures < Empty : {} +| NonEmpty : Text > (λ(element : Text) → λ(status : < Empty : {} | NonEmpty +: Text >) → merge { Empty = λ(_ : {}) → < NonEmpty = element | Empty : {} +>, NonEmpty = λ(result : Text) → < NonEmpty = element ++ "," ++ result | +Empty : {} > } status : < Empty : {} | NonEmpty : Text >) < Empty = {=} | +NonEmpty : Text >) : Text) ++ " " ++ (merge { Empty = λ(_ : {}) → "", +NonEmpty = λ(result : Text) → result } (List/fold Text x.mandatoryFeatures < +Empty : {} | NonEmpty : Text > (λ(element : Text) → λ(status : < Empty : {} +| NonEmpty : Text >) → merge { Empty = λ(_ : {}) → < NonEmpty = element | +Empty : {} >, NonEmpty = λ(result : Text) → < NonEmpty = element ++ "," ++ +result | Empty : {} > } status : < Empty : {} | NonEmpty : Text >) < Empty = +{=} | NonEmpty : Text >) : Text) ++ "\n") ++ y) ""
+ benchmark/parser/Main.hs view
@@ -0,0 +1,53 @@+{-# LANGUAGE OverloadedStrings #-}++module Main where++import Control.Monad (forM)+import Criterion.Main (defaultMain, bgroup, bench, whnf, nfIO)+import Data.Map (Map, foldrWithKey, singleton, unions)++import System.Directory++import qualified Criterion.Main as Criterion+import qualified Data.Text as T+import qualified Data.Text.IO as TIO+import qualified Dhall.Parser as Dhall++type PreludeFiles = Map FilePath T.Text++loadPreludeFiles :: IO PreludeFiles+loadPreludeFiles = loadDirectory "Prelude"+    where+        loadDirectory :: FilePath -> IO PreludeFiles+        loadDirectory dir =+            withCurrentDirectory dir $ do+                files <- getCurrentDirectory >>= listDirectory+                results <- forM files $ \file -> do+                    file' <- makeAbsolute file+                    doesExist <- doesFileExist file'+                    if doesExist+                       then loadFile file'+                       else loadDirectory file'+                pure $ unions results++        loadFile :: FilePath -> IO PreludeFiles+        loadFile path = singleton path <$> TIO.readFile path++benchParser :: PreludeFiles -> Criterion.Benchmark+benchParser =+      bgroup "exprFromText"+    . foldrWithKey (\name expr -> (benchExprFromText name expr :)) []++benchExprFromText :: String -> T.Text -> Criterion.Benchmark+benchExprFromText name expr =+    bench name $ whnf (Dhall.exprFromText "(input)") expr++main :: IO ()+main = do+    prelude <- loadPreludeFiles+    issue108 <- TIO.readFile "benchmark/examples/issue108.dhall"+    defaultMain+        [ benchParser prelude+        , bgroup "Issue #108" $+            [ benchExprFromText "108" issue108 ]+        ]
− dhall-format/Main.hs
@@ -1,130 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards   #-}--{-| Utility executable for pretty-printing Dhall code--    You typically want to use this to either:--    * improve the readability of Dhall code (either written or generated)-    * automatically format your Dhall code to avoid stylistic debates--    Note that this does not yet support:--    * Preserving all comments-        * Currently, this only preserves all leading comments and whitespace-          up until the last newline preceding the code-        * This lets you preserve a comment header but if you want to document-          subexpressions then you will need to split them into a separate-          file for now-    * Preserving multi-line strings (this reduces them to ordinary strings)--    See the @Dhall.Tutorial@ module for example usage--}-module Main where--import Control.Applicative (optional)-import Control.Exception (SomeException)-import Control.Monad (when)-import Data.Monoid ((<>))-import Data.Version (showVersion)-import Dhall.Parser (exprAndHeaderFromText)-import Dhall.Pretty (annToAnsiStyle, prettyExpr)-import Options.Applicative (Parser, ParserInfo)-import System.IO (stderr)-import System.Exit (exitFailure, exitSuccess)--import qualified Paths_dhall as Meta--import qualified Control.Exception-import qualified Data.Text.IO-import qualified Data.Text.Lazy-import qualified Data.Text.Lazy.IO-import qualified Data.Text.Prettyprint.Doc                 as Pretty-import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Pretty-import qualified Options.Applicative-import qualified System.Console.ANSI-import qualified System.IO--data Options = Options-    { version :: Bool-    , inplace :: Maybe FilePath-    }--parseOptions :: Parser Options-parseOptions = Options <$> parseVersion <*> optional parseInplace-  where-    parseVersion =-        Options.Applicative.switch-        (   Options.Applicative.long "version"-        <>  Options.Applicative.help "Display version and exit"-        )--    parseInplace =-        Options.Applicative.strOption-        (   Options.Applicative.long "inplace"-        <>  Options.Applicative.help "Modify the specified file in-place"-        <>  Options.Applicative.metavar "FILE"-        )--opts :: Pretty.LayoutOptions-opts =-    Pretty.defaultLayoutOptions-        { Pretty.layoutPageWidth = Pretty.AvailablePerLine 80 1.0 }--parserInfo :: ParserInfo Options-parserInfo =-    Options.Applicative.info-        (Options.Applicative.helper <*> parseOptions)-        (   Options.Applicative.progDesc "Formatter for the Dhall language"-        <>  Options.Applicative.fullDesc-        )--main :: IO ()-main = do-    Options {..} <- Options.Applicative.execParser parserInfo--    when version $ do-      putStrLn (showVersion Meta.version)-      exitSuccess--    let handler e = do-            let _ = e :: SomeException-            System.IO.hSetEncoding System.IO.stderr System.IO.utf8-            System.IO.hPrint stderr e-            System.Exit.exitFailure--    Control.Exception.handle handler (do-        case inplace of-            Just file -> do-                strictText <- Data.Text.IO.readFile file-                let lazyText = Data.Text.Lazy.fromStrict strictText-                (header, expr) <- case exprAndHeaderFromText "(stdin)" lazyText of-                    Left  err -> Control.Exception.throwIO err-                    Right x   -> return x--                let doc = Pretty.pretty header <> Pretty.pretty expr-                System.IO.withFile file System.IO.WriteMode (\handle -> do-                    Pretty.renderIO handle (Pretty.layoutSmart opts doc)-                    Data.Text.IO.hPutStrLn handle "" )-            Nothing -> do-                System.IO.hSetEncoding System.IO.stdin System.IO.utf8-                inText <- Data.Text.Lazy.IO.getContents--                (header, expr) <- case exprAndHeaderFromText "(stdin)" inText of-                    Left  err -> Control.Exception.throwIO err-                    Right x   -> return x--                let doc = Pretty.pretty header <> prettyExpr expr--                supportsANSI <- System.Console.ANSI.hSupportsANSI System.IO.stdout--                if supportsANSI-                  then-                    Pretty.renderIO-                      System.IO.stdout-                      (fmap annToAnsiStyle (Pretty.layoutSmart opts doc))-                  else-                    Pretty.renderIO-                      System.IO.stdout-                      (Pretty.layoutSmart opts (Pretty.unAnnotate doc))-                Data.Text.IO.putStrLn "")
− dhall-hash/Main.hs
@@ -1,104 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards   #-}--module Main where--import Control.Exception (SomeException)-import Control.Monad (when)-import Data.Monoid ((<>))-import Data.Version (showVersion)-import Dhall.Core (normalize)-import Dhall.Import (Imported(..), hashExpressionToCode, load)-import Dhall.Parser (Src, exprFromText)-import Dhall.TypeCheck (DetailedTypeError(..), TypeError, X)-import Options.Applicative (Parser, ParserInfo)-import System.IO (stderr)-import System.Exit (exitFailure, exitSuccess)--import qualified Paths_dhall as Meta--import qualified Control.Exception-import qualified Data.Text.Lazy.IO-import qualified Dhall.TypeCheck-import qualified Options.Applicative-import qualified System.IO--data Options = Options-    { explain :: Bool-    , version :: Bool-    }--parseOptions :: Parser Options-parseOptions = Options <$> parseExplain <*> parseVersion-  where-    parseExplain =-        Options.Applicative.switch-            (   Options.Applicative.long "explain"-            <>  Options.Applicative.help "Explain error messages in more detail"-            )--    parseVersion =-        Options.Applicative.switch-            (   Options.Applicative.long "version"-            <>  Options.Applicative.help "Display version and exit"-            )--parserInfo :: ParserInfo Options-parserInfo =-    Options.Applicative.info-        (Options.Applicative.helper <*> parseOptions)-        (   Options.Applicative.progDesc "Compute semantic hashes for Dhall expressions"-        <>  Options.Applicative.fullDesc-        )--main :: IO ()-main = do-    Options {..} <- Options.Applicative.execParser parserInfo--    when version $ do-      putStrLn (showVersion Meta.version)-      exitSuccess-    let handle =-                Control.Exception.handle handler2-            .   Control.Exception.handle handler1-            .   Control.Exception.handle handler0-          where-            handler0 e = do-                let _ = e :: TypeError Src X-                System.IO.hPutStrLn stderr ""-                if explain-                    then Control.Exception.throwIO (DetailedTypeError e)-                    else do-                        Data.Text.Lazy.IO.hPutStrLn stderr "\ESC[2mUse \"dhall --explain\" for detailed errors\ESC[0m"-                        Control.Exception.throwIO e--            handler1 (Imported ps e) = do-                let _ = e :: TypeError Src X-                System.IO.hPutStrLn stderr ""-                if explain-                    then Control.Exception.throwIO (Imported ps (DetailedTypeError e))-                    else do-                        Data.Text.Lazy.IO.hPutStrLn stderr "\ESC[2mUse \"dhall --explain\" for detailed errors\ESC[0m"-                        Control.Exception.throwIO (Imported ps e)--            handler2 e = do-                let _ = e :: SomeException-                System.IO.hSetEncoding System.IO.stderr System.IO.utf8-                System.IO.hPrint stderr e-                System.Exit.exitFailure--    handle (do-        System.IO.hSetEncoding System.IO.stdin System.IO.utf8-        inText <- Data.Text.Lazy.IO.getContents--        expr <- case exprFromText "(stdin)" inText of-            Left  err  -> Control.Exception.throwIO err-            Right expr -> return expr--        expr' <- load expr--        _ <- case Dhall.TypeCheck.typeOf expr' of-            Left  err -> Control.Exception.throwIO err-            Right _   -> return ()--        Data.Text.Lazy.IO.putStrLn (hashExpressionToCode (normalize expr')) )
− dhall-repl/Main.hs
@@ -1,251 +0,0 @@-{-# language FlexibleContexts #-}-{-# language NamedFieldPuns #-}-{-# language OverloadedStrings #-}--module Main ( main ) where--import Control.Exception ( SomeException(SomeException), displayException, throwIO )-import Control.Monad.IO.Class ( MonadIO, liftIO )-import Control.Monad.State.Class ( MonadState, get, modify )-import Control.Monad.State.Strict ( evalStateT )-import Data.List ( foldl' )--import qualified Data.Text.Lazy as LazyText-import qualified Data.Text.Prettyprint.Doc as Pretty-import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Pretty ( renderIO )-import qualified Dhall.Context-import qualified Dhall.Core as Dhall ( Var(V), Expr, normalize )-import qualified Dhall.Pretty-import qualified Dhall.Core as Expr ( Expr(..) )-import qualified Dhall.Import as Dhall-import qualified Dhall.Parser as Dhall-import qualified Dhall.TypeCheck as Dhall-import qualified System.Console.ANSI-import qualified System.Console.Haskeline.MonadException as Haskeline-import qualified System.Console.Repline as Repline-import qualified System.IO---main :: IO ()-main =-  evalStateT-    ( Repline.evalRepl-        "⊢ "-        ( dontCrash . eval )-        options-        ( Repline.Word completer )-        greeter-    )-    emptyEnv---data Env = Env-  { envBindings :: Dhall.Context.Context Binding-  , envIt :: Maybe Binding-  }---emptyEnv :: Env-emptyEnv =-  Env-    { envBindings = Dhall.Context.empty-    , envIt = Nothing-    }---data Binding = Binding-  { bindingExpr :: Dhall.Expr Dhall.Src Dhall.X-  , bindingType :: Dhall.Expr Dhall.Src Dhall.X-  }---envToContext :: Env -> Dhall.Context.Context Binding-envToContext Env{ envBindings, envIt } =-  case envIt of-    Nothing ->-      envBindings--    Just it ->-      Dhall.Context.insert "it" it envBindings---parseAndLoad-  :: ( MonadIO m, MonadState Env m )-  => String -> m ( Dhall.Expr Dhall.Src Dhall.X )-parseAndLoad src = do-  parsed <--    case Dhall.exprFromText "(stdin)" ( LazyText.pack src ) of-      Left e ->-        liftIO ( throwIO e )--      Right a ->-        return a--  liftIO ( Dhall.load parsed )---eval :: ( MonadIO m, MonadState Env m ) => String -> m ()-eval src = do-  loaded <--    parseAndLoad src--  exprType <--    typeCheck loaded--  expr <--    normalize loaded--  modify ( \e -> e { envIt = Just ( Binding expr exprType ) } )--  output System.IO.stdout expr----typeOf :: ( MonadIO m, MonadState Env m ) => [String] -> m ()-typeOf [] =-  liftIO ( putStrLn ":type requires an argument to check the type of" )---typeOf srcs = do-  loaded <--    parseAndLoad ( unwords srcs )--  exprType <--    typeCheck loaded--  exprType' <--    normalize exprType--  output System.IO.stdout exprType'----normalize-  :: MonadState Env m-  => Dhall.Expr Dhall.Src Dhall.X -> m ( Dhall.Expr t Dhall.X )-normalize e = do-  env <--    get--  return-    ( Dhall.normalize-        ( foldl'-            ( \a (k, Binding { bindingType, bindingExpr }) ->-                Expr.Let k ( Just bindingType ) bindingExpr a-            )-            e-            ( Dhall.Context.toList ( envToContext env ) )-        )-    )---typeCheck-  :: ( MonadIO m, MonadState Env m )-  => Dhall.Expr Dhall.Src Dhall.X -> m ( Dhall.Expr Dhall.Src Dhall.X )-typeCheck expr = do-  env <--    get--  case Dhall.typeWith ( bindingType <$> envToContext env ) expr of-    Left e ->-      liftIO ( throwIO e )--    Right a ->-      return a---addBinding :: ( MonadIO m, MonadState Env m ) => [String] -> m ()-addBinding (k : "=" : srcs) = do-  let-    varName =-      LazyText.pack k--  loaded <--    parseAndLoad ( unwords srcs )--  t <--    typeCheck loaded--  expr <--    normalize loaded--  modify-    ( \e ->-        e-          { envBindings =-              Dhall.Context.insert-                varName-                Binding { bindingType = t, bindingExpr = expr }-                ( envBindings e )-          }-    )--  output-    System.IO.stdout-    ( Expr.Annot ( Expr.Var ( Dhall.V varName 0 ) ) t )--addBinding _ =-  liftIO ( fail ":let should be of the form `:let x = y`" )--saveBinding :: ( MonadIO m, MonadState Env m ) => [String] -> m ()-saveBinding (file : "=" : tokens) = do-  loadedExpression <- parseAndLoad (unwords tokens)--  _ <- typeCheck loadedExpression--  normalizedExpression <- normalize loadedExpression--  let handler handle = output handle normalizedExpression--  liftIO (System.IO.withFile file System.IO.WriteMode handler)-saveBinding _ = fail ":save should be of the form `:save x = y`"---options-  :: ( Haskeline.MonadException m, MonadIO m, MonadState Env m )-  => Repline.Options m-options =-  [ ( "type", dontCrash . typeOf )-  , ( "let", dontCrash . addBinding )-  , ( "save", dontCrash . saveBinding )-  ]---completer :: Monad m => Repline.WordCompleter m-completer _ =-  return []---greeter :: MonadIO m => m ()-greeter =-  return ()---dontCrash :: ( MonadIO m, Haskeline.MonadException m ) => m () -> m ()-dontCrash m =-  Haskeline.catch-    m-    ( \ e@SomeException{} -> liftIO ( putStrLn ( displayException e ) ) )---output-    :: (Pretty.Pretty a, MonadIO m)-    => System.IO.Handle -> Dhall.Expr s a -> m ()-output handle expr = do-  liftIO (System.IO.hPutStrLn handle "")  -- Visual spacing--  let opts =-          Pretty.defaultLayoutOptions-              { Pretty.layoutPageWidth = Pretty.AvailablePerLine 80 1.0 }--  let stream = Pretty.layoutSmart opts (Dhall.Pretty.prettyExpr expr)-  supportsANSI <- liftIO (System.Console.ANSI.hSupportsANSI handle)-  let ansiStream =-          if supportsANSI-          then fmap Dhall.Pretty.annToAnsiStyle stream-          else Pretty.unAnnotateS stream--  liftIO (Pretty.renderIO handle ansiStream)-  liftIO (System.IO.hPutStrLn handle "") -- Pretty printing doesn't end with a new line--  liftIO (System.IO.hPutStrLn handle "")  -- Visual spacing
dhall.cabal view
@@ -1,6 +1,6 @@ Name: dhall-Version: 1.14.0-Cabal-Version: >=1.8.0.2+Version: 1.15.0+Cabal-Version: >=1.10 Build-Type: Simple Tested-With: GHC == 8.0.1 License: BSD3@@ -34,6 +34,7 @@     Prelude/Bool/show     Prelude/Double/show     Prelude/Integer/show+    Prelude/Integer/toDouble     Prelude/List/all     Prelude/List/any     Prelude/List/build@@ -63,6 +64,7 @@     Prelude/Natural/product     Prelude/Natural/show     Prelude/Natural/sum+    Prelude/Natural/toDouble     Prelude/Natural/toInteger     Prelude/Optional/all     Prelude/Optional/any@@ -95,6 +97,7 @@     tests/normalization/examples/Bool/show/*.dhall     tests/normalization/examples/Double/show/*.dhall     tests/normalization/examples/Integer/show/*.dhall+    tests/normalization/examples/Integer/toDouble/*.dhall     tests/normalization/examples/List/all/*.dhall     tests/normalization/examples/List/any/*.dhall     tests/normalization/examples/List/build/*.dhall@@ -123,6 +126,7 @@     tests/normalization/examples/Natural/product/*.dhall     tests/normalization/examples/Natural/show/*.dhall     tests/normalization/examples/Natural/sum/*.dhall+    tests/normalization/examples/Natural/toDouble/*.dhall     tests/normalization/examples/Natural/toInteger/*.dhall     tests/normalization/examples/Optional/all/*.dhall     tests/normalization/examples/Optional/any/*.dhall@@ -143,15 +147,24 @@     tests/normalization/examples/Text/concatSep/*.dhall     tests/normalization/simplifications/*.dhall     tests/parser/*.dhall+    tests/parser/failure/*.dhall     tests/regression/*.dhall     tests/tutorial/*.dhall     tests/typecheck/*.dhall     tests/typecheck/examples/Monoid/*.dhall+    tests/import/*.dhall+    benchmark/examples/*.dhall+    benchmark/deep-nested-large-record/*.dhall  Source-Repository head     Type: git     Location: https://github.com/dhall-lang/dhall-haskell +Flag with-http+  Description: Include support for importing dhall modules from HTTP URLs+  Default:     True+  Manual:      True+ Library     Hs-Source-Dirs: src     Build-Depends:@@ -162,101 +175,72 @@         containers                  >= 0.5.0.0  && < 0.6 ,         contravariant                              < 1.5 ,         cryptonite                  >= 0.23     && < 1.0 ,-        exceptions                  >= 0.8.3    && < 0.11,+        Diff                        >= 0.2      && < 0.4 ,         directory                   >= 1.3      && < 1.4 ,+        exceptions                  >= 0.8.3    && < 0.11,         filepath                    >= 1.4      && < 1.5 ,-        formatting                  >= 6.3      && < 6.4 ,-        http-client                 >= 0.4.30   && < 0.6 ,-        http-client-tls             >= 0.2.0    && < 0.4 ,+        haskeline                   >= 0.7.3.0  && < 0.8 ,         insert-ordered-containers   >= 0.2.1.0  && < 0.3 ,         lens-family-core            >= 1.0.0    && < 1.3 ,         megaparsec                  >= 6.1.1    && < 6.6 ,         memory                      >= 0.14     && < 0.15,+        mtl                         >= 2.2.1    && < 2.3 ,+        optparse-applicative                       < 0.15,         parsers                     >= 0.12.4   && < 0.13,         prettyprinter               >= 1.2.0.1  && < 1.3 ,         prettyprinter-ansi-terminal >= 1.1.1    && < 1.2 ,+        repline                     >= 0.1.6.0  && < 0.2 ,         scientific                  >= 0.3.0.0  && < 0.4 ,+        template-haskell                           < 2.14,         text                        >= 0.11.1.0 && < 1.3 ,         transformers                >= 0.2.0.0  && < 0.6 ,         unordered-containers        >= 0.1.3.0  && < 0.3 ,         vector                      >= 0.11.0.0 && < 0.13+    if flag(with-http)+      Build-Depends:+        http-client                 >= 0.4.30   && < 0.6 ,+        http-client-tls             >= 0.2.0    && < 0.4     if !impl(ghc >= 8.0)       Build-Depends: semigroups == 0.18.*+      Build-Depends: transformers == 0.4.2.*      Exposed-Modules:         Dhall,         Dhall.Context,         Dhall.Core,-        Dhall.Diff+        Dhall.Diff,+        Dhall.Format,+        Dhall.Freeze,+        Dhall.Hash,         Dhall.Import,+        Dhall.Lint,+        Dhall.Main         Dhall.Parser,         Dhall.Pretty,+        Dhall.Repl+        Dhall.TH,         Dhall.Tutorial,         Dhall.TypeCheck     Other-Modules:-        Dhall.Pretty.Internal-    GHC-Options: -Wall--Executable dhall-    Hs-Source-Dirs: dhall-    Main-Is: Main.hs-    Build-Depends:-        ansi-terminal                                    ,-        base                        >= 4        && < 5   ,-        dhall                                            ,-        optparse-applicative                       < 0.15,-        prettyprinter                                    ,-        prettyprinter-ansi-terminal >= 1.1.1    && < 1.2 ,-        megaparsec                                       ,-        text                        >= 0.11.1.0 && < 1.3-    GHC-Options: -Wall-    Other-Modules:+        Dhall.Pretty.Internal,+        Dhall.Parser.Expression,+        Dhall.Parser.Combinators,+        Dhall.Parser.Token,+        Dhall.Import.Types,         Paths_dhall+    if flag(with-http)+      Other-Modules:+        Dhall.Import.HTTP -Executable dhall-repl-    Hs-Source-Dirs: dhall-repl-    Main-Is: Main.hs-    Build-Depends:-        base             >= 4        && < 5   ,-        ansi-terminal                         ,-        dhall                                 ,-        haskeline        >= 0.7.3.0  && < 0.8 ,-        mtl              >= 2.2.1    && < 2.3 ,-        repline          >= 0.1.6.0  && < 0.2 ,-        prettyprinter                         ,-        prettyprinter-ansi-terminal           ,-        text-    if !impl(ghc >= 8.0)-      Build-Depends: transformers == 0.4.2.*     GHC-Options: -Wall+    Default-Language: Haskell2010 -Executable dhall-format-    Hs-Source-Dirs: dhall-format+Executable dhall+    Hs-Source-Dirs: dhall     Main-Is: Main.hs-    Build-Depends:-        base                        >= 4        && < 5   ,-        ansi-terminal                                    ,-        dhall                                            ,-        megaparsec                                       ,-        optparse-applicative                       < 0.15,-        prettyprinter               >= 1.2.0.1  && < 1.3 ,-        prettyprinter-ansi-terminal >= 1.1.1    && < 1.2 ,-        text                        >= 0.11.1.0 && < 1.3+    Build-Depends: base, dhall     GHC-Options: -Wall-    Other-Modules:-        Paths_dhall--Executable dhall-hash-    Hs-Source-Dirs: dhall-hash-    Main-Is: Main.hs-    Build-Depends:-        base                 >= 4        && < 5   ,-        dhall                                     ,-        optparse-applicative                < 0.15,-        megaparsec                                ,-        text                 >= 0.11.1.0 && < 1.3-    Other-Modules:-        Paths_dhall+    Default-Language: Haskell2010  Test-Suite tasty     Type: exitcode-stdio-1.0@@ -265,6 +249,7 @@     GHC-Options: -Wall     Other-Modules:         Format+        Import         Normalization         Parser         Regression@@ -281,6 +266,7 @@         tasty-hunit               >= 0.9.2    && < 0.11,         text                      >= 0.11.1.0 && < 1.3 ,         vector                    >= 0.11.0.0 && < 0.13+    Default-Language: Haskell2010  Test-Suite doctest     Type: exitcode-stdio-1.0@@ -289,4 +275,28 @@     GHC-Options: -Wall     Build-Depends:         base                      ,+        Diff    >= 0.2   && < 0.4 ,         doctest >= 0.7.0 && < 0.16+    Default-Language: Haskell2010++Benchmark dhall-parser+    Type: exitcode-stdio-1.0+    Main-Is: benchmark/parser/Main.hs+    Build-Depends:+        base                      >= 4        && < 5  ,+        containers                >= 0.5.0.0  && < 0.6,+        criterion                 >= 1.1      && < 1.5,+        dhall                                         ,+        directory                 >= 1.3      && < 1.4,+        text                      >= 0.11.1.0 && < 1.3+    Default-Language: Haskell2010++Benchmark deep-nested-large-record+    Type: exitcode-stdio-1.0+    Main-Is: benchmark/deep-nested-large-record/Main.hs+    Build-Depends:+        base                      >= 4        && < 5  ,+        containers                >= 0.5.0.0  && < 0.6,+        criterion                 >= 1.1      && < 1.5,+        dhall+    Default-Language: Haskell2010
dhall/Main.hs view
@@ -1,206 +1,6 @@-{-# LANGUAGE DeriveAnyClass     #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE OverloadedStrings  #-}-{-# LANGUAGE RecordWildCards    #-}- module Main where -import Control.Applicative ((<|>))-import Control.Exception (Exception, SomeException)-import Data.Monoid (mempty, (<>))-import Data.Text.Prettyprint.Doc (Pretty)-import Data.Typeable (Typeable)-import Data.Version (showVersion)-import Dhall.Core (Expr, Import)-import Dhall.Import (Imported(..), load)-import Dhall.Parser (Src)-import Dhall.Pretty (annToAnsiStyle, prettyExpr)-import Dhall.TypeCheck (DetailedTypeError(..), TypeError, X)-import Options.Applicative (Parser)-import System.Exit (exitFailure)-import System.IO (Handle)--import qualified Paths_dhall as Meta--import qualified Control.Exception-import qualified Data.Text.Lazy.IO-import qualified Data.Text.Prettyprint.Doc                 as Pretty-import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Pretty-import qualified Dhall.Core-import qualified Dhall.Parser-import qualified Dhall.TypeCheck-import qualified Options.Applicative-import qualified System.Console.ANSI-import qualified System.IO--data Options = Options-    { mode    :: Mode-    , explain :: Bool-    , plain   :: Bool-    }--data Mode = Default | Version | Resolve | Type | Normalize--parseOptions :: Parser Options-parseOptions = Options <$> parseMode <*> parseExplain <*> parsePlain-  where-    parseExplain =-        Options.Applicative.switch-            (   Options.Applicative.long "explain"-            <>  Options.Applicative.help "Explain error messages in more detail"-            )--    parsePlain =-        Options.Applicative.switch-            (   Options.Applicative.long "plain"-            <>  Options.Applicative.help "Disable syntax highlighting"-            )--parseMode :: Parser Mode-parseMode =-        subcommand "version"   "Display version"                 Version-    <|> subcommand "resolve"   "Resolve an expression's imports" Resolve-    <|> subcommand "type"      "Infer an expression's type"      Type-    <|> subcommand "normalize" "Normalize an expression"         Normalize-    <|> pure Default-  where-    subcommand name description mode =-        Options.Applicative.subparser-            (   Options.Applicative.command name parserInfo-            <>  Options.Applicative.metavar name-            )-      where-        parserInfo =-            Options.Applicative.info parser-                (   Options.Applicative.fullDesc-                <>  Options.Applicative.progDesc description-                )--        parser =-            Options.Applicative.helper <*> pure mode--opts :: Pretty.LayoutOptions-opts =-    Pretty.defaultLayoutOptions-        { Pretty.layoutPageWidth = Pretty.AvailablePerLine 80 1.0 }--data ImportResolutionDisabled =-    ImportResolutionDisabled deriving (Exception, Typeable)--instance Show ImportResolutionDisabled where-    show _ = "\nImport resolution is disabled"--throws :: Exception e => Either e a -> IO a-throws (Left  e) = Control.Exception.throwIO e-throws (Right a) = return a--getExpression :: IO (Expr Src Import)-getExpression = do-    inText <- Data.Text.Lazy.IO.getContents--    throws (Dhall.Parser.exprFromText "(stdin)" inText)--assertNoImports :: Expr Src Import -> IO (Expr Src X)-assertNoImports expression =-    throws (traverse (\_ -> Left ImportResolutionDisabled) expression)+import qualified Dhall.Main  main :: IO ()-main = do-    let parserInfo =-            Options.Applicative.info-                (Options.Applicative.helper <*> parseOptions)-                (   Options.Applicative.progDesc "Interpreter for the Dhall language"-                <>  Options.Applicative.fullDesc-                )--    Options {..} <- Options.Applicative.execParser parserInfo--    System.IO.hSetEncoding System.IO.stdin System.IO.utf8--    let handle =-                Control.Exception.handle handler2-            .   Control.Exception.handle handler1-            .   Control.Exception.handle handler0-          where-            handler0 e = do-                let _ = e :: TypeError Src X-                System.IO.hPutStrLn System.IO.stderr ""-                if explain-                    then Control.Exception.throwIO (DetailedTypeError e)-                    else do-                        Data.Text.Lazy.IO.hPutStrLn System.IO.stderr "\ESC[2mUse \"dhall --explain\" for detailed errors\ESC[0m"-                        Control.Exception.throwIO e--            handler1 (Imported ps e) = do-                let _ = e :: TypeError Src X-                System.IO.hPutStrLn System.IO.stderr ""-                if explain-                    then Control.Exception.throwIO (Imported ps (DetailedTypeError e))-                    else do-                        Data.Text.Lazy.IO.hPutStrLn System.IO.stderr "\ESC[2mUse \"dhall --explain\" for detailed errors\ESC[0m"-                        Control.Exception.throwIO (Imported ps e)--            handler2 e = do-                let _ = e :: SomeException-                System.IO.hSetEncoding System.IO.stderr System.IO.utf8-                System.IO.hPrint System.IO.stderr e-                System.Exit.exitFailure--    let render :: Pretty a => Handle -> Expr s a -> IO ()-        render h e = do-            let doc = prettyExpr e--            let layoutOptions = opts--            let stream = Pretty.layoutSmart layoutOptions doc--            supportsANSI <- System.Console.ANSI.hSupportsANSI h-            let ansiStream =-                    if supportsANSI && not plain-                    then fmap annToAnsiStyle stream-                    else Pretty.unAnnotateS stream--            Pretty.renderIO h ansiStream-            Data.Text.Lazy.IO.hPutStrLn h ""--    handle $ case mode of-        Version -> do-            putStrLn (showVersion Meta.version)--        Default -> do-            expression <- getExpression--            resolvedExpression <- load expression--            inferredType <- throws (Dhall.TypeCheck.typeOf resolvedExpression)--            render System.IO.stderr (Dhall.Core.normalize inferredType)--            Data.Text.Lazy.IO.hPutStrLn System.IO.stderr mempty--            render System.IO.stdout (Dhall.Core.normalize resolvedExpression)--        Resolve -> do-            expression <- getExpression--            resolvedExpression <- load expression--            render System.IO.stdout resolvedExpression--        Normalize -> do-            expression <- getExpression--            resolvedExpression <- assertNoImports expression--            _ <- throws (Dhall.TypeCheck.typeOf resolvedExpression)--            render System.IO.stdout (Dhall.Core.normalize resolvedExpression)--        Type -> do-            expression <- getExpression--            resolvedExpression <- assertNoImports expression--            inferredType <- throws (Dhall.TypeCheck.typeOf resolvedExpression)--            render System.IO.stdout (Dhall.Core.normalize inferredType)+main = Dhall.Main.main
doctest/Main.hs view
@@ -3,4 +3,4 @@ import qualified Test.DocTest  main :: IO ()-main = Test.DocTest.doctest [ "-isrc", "src/Dhall.hs" ]+main = Test.DocTest.doctest [ "-isrc", "src/Dhall.hs", "src/Dhall/Import.hs" ]
src/Dhall.hs view
@@ -19,7 +19,11 @@     (     -- * Input       input+    , inputFrom     , inputWith+    , inputFromWith+    , inputExpr+    , inputExprWith     , detailed      -- * Types@@ -72,7 +76,7 @@ import Data.Monoid ((<>)) import Data.Scientific (Scientific) import Data.Sequence (Seq)-import Data.Text.Lazy (Text)+import Data.Text (Text) import Data.Typeable (Typeable) import Data.Vector (Vector) import Data.Word (Word8, Word16, Word32, Word64)@@ -80,7 +84,6 @@ import Dhall.Import (Imported(..)) import Dhall.Parser (Src(..)) import Dhall.TypeCheck (DetailedTypeError(..), TypeError, X)-import Formatting.Buildable (Buildable(..)) import GHC.Generics import Numeric.Natural (Natural) import Prelude hiding (maybe, sequence)@@ -96,12 +99,12 @@ import qualified Data.Set import qualified Data.Text import qualified Data.Text.Lazy-import qualified Data.Text.Lazy.Builder import qualified Data.Vector import qualified Dhall.Context import qualified Dhall.Core import qualified Dhall.Import import qualified Dhall.Parser+import qualified Dhall.Pretty.Internal import qualified Dhall.TypeCheck  -- $setup@@ -154,9 +157,21 @@     -- ^ The Dhall program     -> IO a     -- ^ The decoded value in Haskell-input ty txt =-  inputWith ty Dhall.Context.empty (const Nothing) txt+input =+  inputFrom "(input)" +inputFrom+    :: FilePath+    -- ^ The source file to report locations from; only used in error messages+    -> Type a+    -- ^ The type of value to decode from Dhall to Haskell+    -> Text+    -- ^ The Dhall program+    -> IO a+    -- ^ The decoded value in Haskell+inputFrom filename ty txt =+  inputFromWith filename ty Dhall.Context.empty (const Nothing) txt+ {-| Extend 'input' with a custom typing context and normalization process.  -}@@ -170,13 +185,28 @@     -- ^ The Dhall program     -> IO a     -- ^ The decoded value in Haskell-inputWith (Type {..}) ctx n txt = do-    expr  <- throws (Dhall.Parser.exprFromText "(input)" txt)+inputWith =+  inputFromWith "(input)"++{-| Extend 'inputFrom' with a custom typing context and normalization process.++-}+inputFromWith+    :: FilePath+    -- ^ The source file to report locations from; only used in error messages+    -> Type a+    -- ^ The type of value to decode from Dhall to Haskell+    -> Dhall.Context.Context (Expr Src X)+    -- ^ The starting context for type-checking+    -> Dhall.Core.Normalizer X+    -> Text+    -- ^ The Dhall program+    -> IO a+    -- ^ The decoded value in Haskell+inputFromWith filename (Type {..}) ctx n txt = do+    expr  <- throws (Dhall.Parser.exprFromText filename txt)     expr' <- Dhall.Import.loadWithContext ctx n expr-    let suffix =-            ( Data.Text.Lazy.Builder.toLazyText-            . build-            ) expected+    let suffix = Dhall.Pretty.Internal.prettyToStrictText expected     let annot = case expr' of             Note (Src begin end bytes) _ ->                 Note (Src begin end bytes') (Annot expr' expected)@@ -189,6 +219,32 @@         Just x  -> return x         Nothing -> Control.Exception.throwIO InvalidType +{-| Similar to `input`, but without interpreting the Dhall `Expr` into a Haskell+    type.+-}+inputExpr+    :: Text+    -- ^ The Dhall program+    -> IO (Expr Src X)+    -- ^ The fully normalized AST+inputExpr = inputExprWith Dhall.Context.empty (const Nothing)++{-| Extend `inputExpr` with a custom typing context and normalization process.+-}+inputExprWith+    :: Dhall.Context.Context (Expr Src X)+    -- ^ The starting context for type-checking+    -> Dhall.Core.Normalizer X+    -> Text+    -- ^ The Dhall program+    -> IO (Expr Src X)+    -- ^ The fully normalized AST+inputExprWith ctx n txt = do+    expr  <- throws (Dhall.Parser.exprFromText "(input)" txt)+    expr' <- Dhall.Import.loadWithContext ctx n expr+    _ <- throws (Dhall.TypeCheck.typeWith ctx expr')+    pure (Dhall.Core.normalizeWith n expr')+ -- | Use this function to extract Haskell values directly from Dhall AST. --   The intended use case is to allow easy extraction of Dhall values for --   making the function `Dhall.Core.normalizeWith` easier to use.@@ -415,10 +471,10 @@ >>> input lazyText "\"Test\"" "Test" -}-lazyText :: Type Text+lazyText :: Type Data.Text.Lazy.Text lazyText = Type {..}   where-    extract (TextLit (Chunks [] t)) = pure (Data.Text.Lazy.Builder.toLazyText t)+    extract (TextLit (Chunks [] t)) = pure (Data.Text.Lazy.fromStrict t)     extract  _                      = empty      expected = Text@@ -428,7 +484,7 @@ >>> input strictText "\"Test\"" "Test" -}-strictText :: Type Data.Text.Text+strictText :: Type Text strictText = fmap Data.Text.Lazy.toStrict lazyText  {-| Decode a `Maybe`@@ -551,10 +607,10 @@ instance {-# OVERLAPS #-} Interpret [Char] where     autoWith _ = string -instance Interpret Text where+instance Interpret Data.Text.Lazy.Text where     autoWith _ = lazyText -instance Interpret Data.Text.Text where+instance Interpret Text where     autoWith _ = strictText  instance Interpret a => Interpret (Maybe a) where@@ -649,8 +705,8 @@         nR :: M1 i c2 f2 a         nR = undefined -        nameL = constructorModifier (Data.Text.Lazy.pack (conName nL))-        nameR = constructorModifier (Data.Text.Lazy.pack (conName nR))+        nameL = constructorModifier (Data.Text.pack (conName nL))+        nameR = constructorModifier (Data.Text.pack (conName nR))          extract (UnionLit name e _)             | name == nameL = fmap (L1 . M1) (extractL e)@@ -670,7 +726,7 @@         n :: M1 i c h a         n = undefined -        name = constructorModifier (Data.Text.Lazy.pack (conName n))+        name = constructorModifier (Data.Text.pack (conName n))          extract u@(UnionLit name' e _)             | name == name' = fmap (R1 . M1) (extractR e)@@ -689,7 +745,7 @@         n :: M1 i c f a         n = undefined -        name = constructorModifier (Data.Text.Lazy.pack (conName n))+        name = constructorModifier (Data.Text.pack (conName n))          extract u@(UnionLit name' e _)             | name == name' = fmap (L1 . M1) (extractL e)@@ -748,14 +804,14 @@     genericAutoWith opts@(InterpretOptions {..}) = do         name <- getSelName n         let extract (RecordLit m) = do-                    let name' = fieldModifier (Data.Text.Lazy.pack name)+                    let name' = fieldModifier (Data.Text.pack name)                     e <- Data.HashMap.Strict.InsOrd.lookup name' m                     fmap (M1 . K1) (extract' e)             extract _            = Nothing         let expected =                 Record (Data.HashMap.Strict.InsOrd.fromList [(key, expected')])               where-                key = fieldModifier (Data.Text.Lazy.pack name)+                key = fieldModifier (Data.Text.pack name)         pure (Type {..})       where         n :: M1 i s f a@@ -813,18 +869,18 @@          declared = Bool -instance Inject Text where+instance Inject Data.Text.Lazy.Text where     injectWith _ = InputType {..}       where         embed text =-            TextLit (Chunks [] (Data.Text.Lazy.Builder.fromLazyText text))+            TextLit (Chunks [] (Data.Text.Lazy.toStrict text))          declared = Text -instance Inject Data.Text.Text where+instance Inject Text where     injectWith _ = InputType {..}       where-        embed text = TextLit (Chunks [] (Data.Text.Lazy.Builder.fromText text))+        embed text = TextLit (Chunks [] text)          declared = Text @@ -961,8 +1017,8 @@         nR :: M1 i c2 f2 a         nR = undefined -        keyL = constructorModifier (Data.Text.Lazy.pack (conName nL))-        keyR = constructorModifier (Data.Text.Lazy.pack (conName nR))+        keyL = constructorModifier (Data.Text.pack (conName nL))+        keyR = constructorModifier (Data.Text.pack (conName nR))          InputType embedL declaredL = evalState (genericInjectWith options) 1         InputType embedR declaredR = evalState (genericInjectWith options) 1@@ -979,7 +1035,7 @@         nR :: M1 i c h a         nR = undefined -        keyR = constructorModifier (Data.Text.Lazy.pack (conName nR))+        keyR = constructorModifier (Data.Text.pack (conName nR))          declared = Union (Data.HashMap.Strict.InsOrd.insert keyR declaredR ktsL) @@ -998,7 +1054,7 @@         nL :: M1 i c f a         nL = undefined -        keyL = constructorModifier (Data.Text.Lazy.pack (conName nL))+        keyL = constructorModifier (Data.Text.pack (conName nL))          declared = Union (Data.HashMap.Strict.InsOrd.insert keyL declaredL ktsR) @@ -1049,7 +1105,7 @@  instance (Selector s, Inject a) => GenericInject (M1 S s (K1 i a)) where     genericInjectWith opts@(InterpretOptions {..}) = do-        name <- fieldModifier . Data.Text.Lazy.pack <$> getSelName n+        name <- fieldModifier . Data.Text.pack <$> getSelName n         let embed (M1 (K1 x)) =                 RecordLit (Data.HashMap.Strict.InsOrd.singleton name (embedIn x))         let declared =@@ -1102,7 +1158,7 @@     ( Data.Functor.Product.Product         ( Control.Applicative.Const             ( Data.HashMap.Strict.InsOrd.InsOrdHashMap-                Data.Text.Lazy.Text+                Text                 ( Expr Src X )             )         )@@ -1127,7 +1183,7 @@   -- | Parse a single field of a record.-field :: Data.Text.Lazy.Text -> Type a -> RecordType a+field :: Text -> Type a -> RecordType a field key valueType =   let     extractBody expr = do
src/Dhall/Context.hs view
@@ -12,7 +12,7 @@     , toList     ) where -import Data.Text.Lazy (Text)+import Data.Text (Text) import Prelude hiding (lookup)  {-| A @(Context a)@ associates `Text` labels with values of type @a@.  Each
src/Dhall/Core.hs view
@@ -1,12 +1,13 @@-{-# LANGUAGE BangPatterns      #-}-{-# LANGUAGE CPP               #-}-{-# LANGUAGE DeriveFoldable    #-}-{-# LANGUAGE DeriveFunctor     #-}-{-# LANGUAGE DeriveTraversable #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RankNTypes        #-}-{-# LANGUAGE RecordWildCards   #-}-{-# LANGUAGE UnicodeSyntax     #-}+{-# LANGUAGE BangPatterns       #-}+{-# LANGUAGE CPP                #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE DeriveFoldable     #-}+{-# LANGUAGE DeriveFunctor      #-}+{-# LANGUAGE DeriveTraversable  #-}+{-# LANGUAGE OverloadedStrings  #-}+{-# LANGUAGE RankNTypes         #-}+{-# LANGUAGE RecordWildCards    #-}+{-# LANGUAGE UnicodeSyntax      #-} {-# OPTIONS_GHC -Wall #-}  {-| This module contains the core calculus for the Dhall language.@@ -41,6 +42,7 @@     , isNormalized     , isNormalizedWith     , denote+    , freeIn      -- * Pretty-printing     , pretty@@ -58,6 +60,7 @@ import Control.Applicative (empty) import Crypto.Hash (SHA256) import Data.Bifunctor (Bifunctor(..))+import Data.Data (Data) import Data.Foldable import Data.HashMap.Strict.InsOrd (InsOrdHashMap) import Data.HashSet (HashSet)@@ -66,12 +69,10 @@ import Data.Semigroup (Semigroup(..)) import Data.Sequence (Seq, ViewL(..), ViewR(..)) import Data.Set (Set)-import Data.Text.Lazy (Text)-import Data.Text.Lazy.Builder (Builder)+import Data.Text (Text) import Data.Text.Prettyprint.Doc (Pretty) import Data.Traversable import {-# SOURCE #-} Dhall.Pretty.Internal-import Formatting.Buildable (Buildable(..)) import Numeric.Natural (Natural) import Prelude hiding (succ) @@ -82,7 +83,6 @@ import qualified Data.Sequence import qualified Data.Set import qualified Data.Text-import qualified Data.Text.Lazy.Builder     as Builder import qualified Data.Text.Prettyprint.Doc  as Pretty  {-| Constants for a pure type system@@ -102,15 +102,15 @@     Note that Dhall does not support functions from terms to types and therefore     Dhall is not a dependently typed language -}-data Const = Type | Kind deriving (Show, Eq, Bounded, Enum)+data Const = Type | Kind deriving (Show, Eq, Data, Bounded, Enum) -instance Buildable Const where-    build = buildConst+instance Pretty Const where+    pretty = Pretty.unAnnotate . prettyConst  {-| Internal representation of a directory that stores the path components in     reverse order -    In other words, the directory @/foo/bar/baz@ is encoded as+    In other words, the directory @\/foo\/bar\/baz@ is encoded as     @Directory { components = [ "baz", "bar", "foo" ] }@ -} newtype Directory = Directory { components :: [Text] }@@ -120,11 +120,11 @@     Directory components₀ <> Directory components₁ =         Directory (components₁ <> components₀) -instance Buildable Directory where-    build (Directory {..}) =-        foldMap buildComponent (reverse components)+instance Pretty Directory where+    pretty (Directory {..}) =+        foldMap prettyComponent (reverse components)       where-        buildComponent text = "/" <> build text+        prettyComponent text = "/" <> Pretty.pretty text  {-| A `File` is a `directory` followed by one additional path component     representing the `file` name@@ -134,8 +134,8 @@     , file      :: Text     } deriving (Eq, Ord, Show) -instance Buildable File where-    build (File {..}) = build directory <> "/" <> build file+instance Pretty File where+    pretty (File {..}) = Pretty.pretty directory <> "/" <> Pretty.pretty file  instance Semigroup File where     File directory₀ _ <> File directory₁ file =@@ -146,17 +146,14 @@     -- ^ Absolute path     | Here     -- ^ Path relative to @.@-    | Parent-    -- ^ Path relative to @..@     | Home     -- ^ Path relative to @~@     deriving (Eq, Ord, Show) -instance Buildable FilePrefix where-    build Absolute = ""-    build Here     = "."-    build Parent   = ".."-    build Home     = "~"+instance Pretty FilePrefix where+    pretty Absolute = ""+    pretty Here     = "."+    pretty Home     = "~"  -- | The type of import (i.e. local vs. remote vs. environment) data ImportType@@ -166,42 +163,34 @@     -- ^ URL of remote resource and optional headers stored in an import     | Env  Text     -- ^ Environment variable+    | Missing     deriving (Eq, Ord, Show) -parent :: File-parent = File { directory = Directory { components = [ ".." ] }, file = "" }- instance Semigroup ImportType where     Local prefix file₀ <> Local Here file₁ = Local prefix (file₀ <> file₁)      URL prefix file₀ suffix headers <> Local Here file₁ =         URL prefix (file₀ <> file₁) suffix headers -    Local prefix file₀ <> Local Parent file₁ =-        Local prefix (file₀ <> parent <> file₁)--    URL prefix file₀ suffix headers <> Local Parent file₁ =-        URL prefix (file₀ <> parent <> file₁) suffix headers-     _ <> import₁ =         import₁ -instance Buildable ImportType where-    build (Local prefix file) =-        build prefix <> build file <> " "+instance Pretty ImportType where+    pretty (Local prefix file) =+        Pretty.pretty prefix <> Pretty.pretty file -    build (URL prefix file suffix headers) =-            build prefix-        <>  build file-        <>  build suffix-        <>  foldMap buildHeaders headers-        <>  " "+    pretty (URL prefix file suffix headers) =+            Pretty.pretty prefix+        <>  Pretty.pretty file+        <>  Pretty.pretty suffix+        <>  foldMap prettyHeaders headers       where-        buildHeaders h = " using " <> build h+        prettyHeaders h = " using " <> Pretty.pretty h -    build (Env env) =-        "env:" <> build env <> " "+    pretty (Env env) = "env:" <> Pretty.pretty env +    pretty Missing = "missing"+ -- | How to interpret the import's contents (i.e. as Dhall code or raw text) data ImportMode = Code | RawText deriving (Eq, Ord, Show) @@ -215,11 +204,11 @@     ImportHashed _ importType₀ <> ImportHashed hash importType₁ =         ImportHashed hash (importType₀ <> importType₁) -instance Buildable ImportHashed where-    build (ImportHashed  Nothing p) =-      build p-    build (ImportHashed (Just h) p) =-      build p <> "sha256:" <> build (show h) <> " "+instance Pretty ImportHashed where+    pretty (ImportHashed  Nothing p) =+      Pretty.pretty p+    pretty (ImportHashed (Just h) p) =+      Pretty.pretty p <> " sha256:" <> Pretty.pretty (show h)  -- | Reference to an external resource data Import = Import@@ -231,16 +220,14 @@     Import importHashed₀ _ <> Import importHashed₁ code =         Import (importHashed₀ <> importHashed₁) code -instance Buildable Import where-    build (Import {..}) = build importHashed <> suffix+instance Pretty Import where+    pretty (Import {..}) = Pretty.pretty importHashed <> Pretty.pretty suffix       where+        suffix :: Text         suffix = case importMode of-            RawText -> "as Text"+            RawText -> " as Text"             Code    -> "" -instance Pretty Import where-    pretty import_ = Pretty.pretty (Builder.toLazyText (build import_))- -- | Type synonym for `Import`, provided for backwards compatibility type Path = Import @@ -279,13 +266,13 @@     appear as a numeric suffix. -} data Var = V Text !Integer-    deriving (Eq, Show)+    deriving (Data, Eq, Show)  instance IsString Var where     fromString str = V (fromString str) 0 -instance Buildable Var where-    build = buildVar+instance Pretty Var where+    pretty = Pretty.unAnnotate . prettyVar  -- | Syntax tree for expressions data Expr s a@@ -348,6 +335,8 @@     | IntegerLit Integer     -- | > IntegerShow                              ~  Integer/show     | IntegerShow+    -- | > IntegerToDouble                          ~  Integer/toDouble+    | IntegerToDouble     -- | > Double                                   ~  Double     | Double     -- | > DoubleLit n                              ~  n@@ -415,9 +404,11 @@     | Project (Expr s a) (Set Text)     -- | > Note s x                                 ~  e     | Note s (Expr s a)+    -- | > ImportAlt                                ~  e1 ? e2+    | ImportAlt (Expr s a) (Expr s a)     -- | > Embed import                             ~  import     | Embed a-    deriving (Functor, Foldable, Traversable, Show, Eq)+    deriving (Functor, Foldable, Traversable, Show, Eq, Data)  instance Applicative (Expr s) where     pure = Embed@@ -455,6 +446,7 @@     Integer              >>= _ = Integer     IntegerLit a         >>= _ = IntegerLit a     IntegerShow          >>= _ = IntegerShow+    IntegerToDouble      >>= _ = IntegerToDouble     Double               >>= _ = Double     DoubleLit a          >>= _ = DoubleLit a     DoubleShow           >>= _ = DoubleShow@@ -487,6 +479,7 @@     Field a b            >>= k = Field (a >>= k) b     Project a b          >>= k = Project (a >>= k) b     Note a b             >>= k = Note a (b >>= k)+    ImportAlt a b        >>= k = ImportAlt (a >>= k) (b >>= k)     Embed a              >>= k = k a  instance Bifunctor Expr where@@ -518,6 +511,7 @@     first _  Integer               = Integer     first _ (IntegerLit a        ) = IntegerLit a     first _  IntegerShow           = IntegerShow+    first _  IntegerToDouble       = IntegerToDouble     first _  Double                = Double     first _ (DoubleLit a         ) = DoubleLit a     first _  DoubleShow            = DoubleShow@@ -550,6 +544,7 @@     first k (Field a b           ) = Field (first k a) b     first k (Project a b         ) = Project (first k a) b     first k (Note a b            ) = Note (k a) (first k b)+    first k (ImportAlt a b       ) = ImportAlt (first k a) (first k b)     first _ (Embed a             ) = Embed a      second = fmap@@ -558,8 +553,8 @@     fromString str = Var (fromString str)  -- | The body of an interpolated @Text@ literal-data Chunks s a = Chunks [(Builder, Expr s a)] Builder-    deriving (Functor, Foldable, Traversable, Show, Eq)+data Chunks s a = Chunks [(Text, Expr s a)] Text+    deriving (Functor, Foldable, Traversable, Show, Eq, Data)  instance Data.Semigroup.Semigroup (Chunks s a) where     Chunks xysL zL <> Chunks         []    zR =@@ -589,9 +584,6 @@ -}  -- | Generates a syntactically valid Dhall program-instance Buildable a => Buildable (Expr s a) where-    build = buildExpr- instance Pretty a => Pretty (Expr s a) where     pretty = Pretty.unAnnotate . prettyExpr @@ -732,6 +724,7 @@ shift _ _ Integer = Integer shift _ _ (IntegerLit a) = IntegerLit a shift _ _ IntegerShow = IntegerShow+shift _ _ IntegerToDouble = IntegerToDouble shift _ _ Double = Double shift _ _ (DoubleLit a) = DoubleLit a shift _ _ DoubleShow = DoubleShow@@ -808,6 +801,10 @@ shift d v (Note a b) = Note a b'   where     b' = shift d v b+shift d v (ImportAlt a b) = ImportAlt a' b'+  where+    a' = shift d v a+    b' = shift d v b -- The Dhall compiler enforces that all embedded values are closed expressions -- and `shift` does nothing to a closed expression shift _ _ (Embed p) = Embed p@@ -888,6 +885,7 @@ subst _ _ Integer = Integer subst _ _ (IntegerLit a) = IntegerLit a subst _ _ IntegerShow = IntegerShow+subst _ _ IntegerToDouble = IntegerToDouble subst _ _ Double = Double subst _ _ (DoubleLit a) = DoubleLit a subst _ _ DoubleShow = DoubleShow@@ -955,6 +953,10 @@ subst x e (Note a b) = Note a b'   where     b' = subst x e b+subst x e (ImportAlt a b) = ImportAlt a' b'+  where+    a' = subst x e a+    b' = subst x e b -- The Dhall compiler enforces that all embedded values are closed expressions -- and `subst` does nothing to a closed expression subst _ _ (Embed p) = Embed p@@ -1093,6 +1095,8 @@     IntegerLit n alphaNormalize IntegerShow =     IntegerShow+alphaNormalize IntegerToDouble =+    IntegerToDouble alphaNormalize Double =     Double alphaNormalize (DoubleLit n) =@@ -1218,6 +1222,11 @@     Note s e₁   where     e₁ = alphaNormalize e₀+alphaNormalize (ImportAlt l₀ r₀) =+    ImportAlt l₁ r₁+  where+    l₁ = alphaNormalize l₀+    r₁ = alphaNormalize r₀ alphaNormalize (Embed a) =     Embed a @@ -1286,6 +1295,7 @@ denote  Integer               = Integer denote (IntegerLit a        ) = IntegerLit a denote  IntegerShow           = IntegerShow+denote  IntegerToDouble       = IntegerToDouble denote  Double                = Double denote (DoubleLit a         ) = DoubleLit a denote  DoubleShow            = DoubleShow@@ -1317,6 +1327,7 @@ denote (Constructors a      ) = Constructors (denote a) denote (Field a b           ) = Field (denote a) b denote (Project a b         ) = Project (denote a) b+denote (ImportAlt a b       ) = ImportAlt (denote a) (denote b) denote (Embed a             ) = Embed a  {-| Reduce an expression to its normal form, performing beta reduction and applying@@ -1385,12 +1396,13 @@             App NaturalOdd (NaturalLit n) -> BoolLit (odd n)             App NaturalToInteger (NaturalLit n) -> IntegerLit (toInteger n)             App NaturalShow (NaturalLit n) ->-                TextLit (Chunks [] (buildNatural n))+                TextLit (Chunks [] (Data.Text.pack (show n)))             App IntegerShow (IntegerLit n)-                | 0 <= n    -> TextLit (Chunks [] ("+" <> buildNumber n))-                | otherwise -> TextLit (Chunks [] (buildNumber n))+                | 0 <= n    -> TextLit (Chunks [] ("+" <> Data.Text.pack (show n)))+                | otherwise -> TextLit (Chunks [] (Data.Text.pack (show n)))+            App IntegerToDouble (IntegerLit n) -> DoubleLit (fromInteger n)             App DoubleShow (DoubleLit n) ->-                TextLit (Chunks [] (buildScientific n))+                TextLit (Chunks [] (Data.Text.pack (show n)))             App (App OptionalBuild _A₀) g ->                 loop (App (App (App g optional) just) nothing)               where@@ -1438,8 +1450,7 @@                 m = case Data.Sequence.viewr ys of                         _ :> y -> Just y                         _      -> Nothing-            App (App ListIndexed _A₀) (ListLit _A₁ as₀) ->-                loop (ListLit (Just _A₂) as₁)+            App (App ListIndexed _A₀) (ListLit _A₁ as₀) -> loop (ListLit t as₁)               where                 as₁ = Data.Sequence.mapWithIndex adapt as₀ @@ -1449,6 +1460,9 @@                           , ("value", _A₀)                           ] +                t | null as₀  = Just _A₂+                  | otherwise = Nothing+                 adapt n a_ =                     RecordLit (Data.HashMap.Strict.InsOrd.fromList kvs)                   where@@ -1542,6 +1556,7 @@     Integer -> Integer     IntegerLit n -> IntegerLit n     IntegerShow -> IntegerShow+    IntegerToDouble -> IntegerToDouble     Double -> Double     DoubleLit n -> DoubleLit n     DoubleShow -> DoubleShow@@ -1683,6 +1698,7 @@                     return (x, v)             r' -> Project r' xs     Note _ e' -> loop e'+    ImportAlt l _r -> loop l     Embed a -> Embed a  {-| Returns `True` if two expressions are α-equivalent and β-equivalent and@@ -1733,6 +1749,7 @@         App NaturalShow (NaturalLit _) -> False         App NaturalToInteger (NaturalLit _) -> False         App IntegerShow (IntegerLit _) -> False+        App IntegerToDouble (IntegerLit _) -> False         App DoubleShow (DoubleLit _) -> False         App (App OptionalBuild _) _ -> False         App (App ListBuild _) _ -> False@@ -1807,6 +1824,7 @@     Integer -> True     IntegerLit _ -> True     IntegerShow -> True+    IntegerToDouble -> True     Double -> True     DoubleLit _ -> True     DoubleShow -> True@@ -1894,8 +1912,27 @@                     else True             _ -> True     Note _ e' -> isNormalized e'+    ImportAlt l _r -> isNormalized l     Embed _ -> True +{-| Detect if the given variable is free within the given expression++>>> "x" `freeIn` "x"+True+>>> "x" `freeIn` "y"+False+>>> "x" `freeIn` Lam "x" (Const Type) "x"+False+-}+freeIn :: Eq a => Var -> Expr s a -> Bool+variable `freeIn` expression =+    Dhall.Core.shift 1 variable strippedExpression /= strippedExpression+  where+    denote' :: Expr t b -> Expr () b+    denote' = denote++    strippedExpression = denote' expression+ _ERROR :: String _ERROR = "\ESC[1;31mError\ESC[0m" @@ -1948,6 +1985,7 @@         , "Natural/show"         , "Integer"         , "Integer/show"+        , "Integer/toDouble"         , "Double"         , "Double/show"         , "Text"
src/Dhall/Diff.hs view
@@ -15,23 +15,27 @@     , Dhall.Diff.diff     ) where -import Data.Foldable (fold)+import Data.Foldable (fold, toList)+import Data.Function (on) import Data.HashMap.Strict.InsOrd (InsOrdHashMap)+import Data.List.NonEmpty (NonEmpty(..)) import Data.Monoid (Any(..)) import Data.Scientific (Scientific) import Data.Semigroup+import Data.Sequence (Seq) import Data.Set (Set) import Data.String (IsString(..))-import Data.Text.Lazy (Text)+import Data.Text (Text) import Data.Text.Prettyprint.Doc (Doc, Pretty)-import Data.List.NonEmpty (NonEmpty(..))-import Dhall.Core (Const(..), Expr(..), Var(..))+import Dhall.Core (Chunks (..), Const(..), Expr(..), Var(..)) import Dhall.Pretty.Internal (Ann) import Numeric.Natural (Natural) +import qualified Data.Algorithm.Diff        as Algo.Diff import qualified Data.HashMap.Strict.InsOrd as HashMap import qualified Data.List.NonEmpty import qualified Data.Set+import qualified Data.Text import qualified Data.Text.Prettyprint.Doc  as Pretty import qualified Dhall.Core import qualified Dhall.Pretty.Internal      as Internal@@ -157,7 +161,7 @@ diff :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Doc Ann diff l0 r0 = doc   where-    Diff {..} = diffExprA l0 r0+    Diff {..} = diffExpression l0 r0 <> hardline  diffPrimitive :: Eq a => (a -> Diff) -> a -> a -> Diff diffPrimitive f l r@@ -205,6 +209,9 @@      natural = diffInteger nL nR +diffPretty :: (Eq a, Pretty a) => a -> a -> Diff+diffPretty = diffPrimitive (token . Pretty.pretty)+ diffMaybe :: Diff -> (a -> a -> Diff) -> (Maybe a -> Maybe a -> Diff) diffMaybe _ _ Nothing Nothing =     mempty@@ -239,7 +246,7 @@     prefixes = l :| repeat (hardline <> m)  diffKeyVals-    :: Pretty a+    :: (Eq a, Pretty a)     => Diff     -> InsOrdHashMap Text (Expr s a)     -> InsOrdHashMap Text (Expr s a)@@ -263,7 +270,7 @@             <>  ignore             ] -    shared = HashMap.intersectionWith diffExprA kvsL kvsR+    shared = HashMap.intersectionWith diffExpression kvsL kvsR      diffFieldValues =         filter (not . same) (HashMap.foldMapWithKey adapt shared)@@ -285,23 +292,120 @@ angled :: [Diff] -> Diff angled = enclosed (langle <> " ") (pipe <> " ") rangle +bracketed :: [Diff] -> Diff+bracketed = enclosed (lbracket <> " ") (comma <> " ") rbracket++diffText :: Text -> Text -> Diff+diffText l r+  | null parts         = "\"\""+  | allDifferent parts = difference textSkeleton textSkeleton+  | allSame parts      = textSkeleton+  | otherwise          = "\"" <> foldMap prettyPart parts <> "\""+  where+    allDifferent = not . any isBoth+    allSame      = all isBoth++    -- TODO: check for color support from the TTY+    colorDiff colorCode chars =+            "\ESC["+        <>  colorCode+        <>  "m"+        <>  fromString chars+        <>  "\ESC[0m"++    prettyPart part =+      case part of+        -- Only present in left+        Algo.Diff.First  chars ->+            -- Red background+            (colorDiff "41" chars) { same = False }++        -- Only present in right+        Algo.Diff.Second chars ->+            -- Green background+            (colorDiff "42" chars) { same = False }++        -- Present in both+        Algo.Diff.Both _ chars ->+            -- Dim foreground+            colorDiff "2" chars++    parts = Algo.Diff.getGroupedDiff (Data.Text.unpack l) (Data.Text.unpack r)++diffChunks+    :: (Eq a, Pretty a)+    => Chunks s a -> Chunks s a -> Diff+diffChunks cL cR+  | null chunks             = "\"\""+  | [c] <- chunks           = c+  | otherwise               = align (enclosed "   " "++ " "" chunks)+  where+    toEitherList (Chunks te t) =+        concatMap (\(a, b) -> [Left a, Right b]) te ++ [Left t]++    diffTextSkeleton = difference textSkeleton textSkeleton++    chunks = zipWith chunkDiff (toEitherList cL) (toEitherList cR) ++    chunkDiff a b =+      case (a, b) of+        (Left  x, Left y ) -> diffText x y+        (Right x, Right y) -> diffExpression x y+        _                  -> diffTextSkeleton++diffList+    :: (Eq a, Pretty a)+    => Seq (Expr s a) -> Seq (Expr s a) -> Diff+diffList l r+  | allDifferent parts = difference listSkeleton listSkeleton+  | otherwise          = bracketed (foldMap diffPart parts)+  where+    allDifferent = not . any isBoth++    -- Sections of the list that are only in left, only in right, or in both+    parts =+        Algo.Diff.getGroupedDiffBy ((same .) . diffExpression) (toList l) (toList r)++    -- Render each element of a list using an extra rendering function f+    prettyElems f = map (f . token . Internal.prettyExpr)++    diffPart part =+      case part of+        -- Only present in left+        Algo.Diff.First  elements ->+            prettyElems minus elements++        -- Only present in right+        Algo.Diff.Second elements ->+            prettyElems plus  elements++        -- Present in both+        Algo.Diff.Both _ _        ->+            pure ignore++-- Helper function to check when a diff part is present on both sides+isBoth :: Algo.Diff.Diff a -> Bool+isBoth p+  | Algo.Diff.Both _ _ <- p = True+  | otherwise               = False+ diffRecord-    :: Pretty a+    :: (Eq a, Pretty a)     => InsOrdHashMap Text (Expr s a) -> InsOrdHashMap Text (Expr s a) -> Diff diffRecord kvsL kvsR = braced (diffKeyVals colon kvsL kvsR)  diffRecordLit-    :: Pretty a+    :: (Eq a, Pretty a)     => InsOrdHashMap Text (Expr s a) -> InsOrdHashMap Text (Expr s a) -> Diff diffRecordLit kvsL kvsR = braced (diffKeyVals equals kvsL kvsR)  diffUnion-    :: Pretty a+    :: (Eq a, Pretty a)     => InsOrdHashMap Text (Expr s a) -> InsOrdHashMap Text (Expr s a) -> Diff diffUnion kvsL kvsR = angled (diffKeyVals colon kvsL kvsR)  diffUnionLit-    :: Pretty a+    :: (Eq a, Pretty a)     => Text     -> Text     -> Expr s a@@ -315,11 +419,25 @@     <>  format " " (diffLabel kL kR)     <>  equals     <>  " "-    <>  format " " (diffExprA vL vR)+    <>  format " " (diffExpression vL vR)     <>  halfAngled (diffKeyVals equals kvsL kvsR)   where     halfAngled = enclosed (pipe <> " ") (pipe <> " ") rangle +listSkeleton :: Diff+listSkeleton =+        lbracket+    <>  " "+    <>  ignore+    <>  " "+    <>  rbracket++textSkeleton :: Diff+textSkeleton =+        "\""+    <>  ignore+    <>  "\""+ skeleton :: Pretty a => Expr s a -> Diff skeleton (Lam {}) =         lambda@@ -347,6 +465,12 @@     <>  rarrow     <>  " "     <>  ignore+skeleton (App Optional _) =+        "Optional "+    <>  ignore+skeleton (App List _) =+        "List "+    <>  ignore skeleton (App {}) =         ignore     <>  " "@@ -418,9 +542,7 @@     <>  " "     <>  ignore skeleton (TextLit {}) =-        "\""-    <>  ignore-    <>  "\""+        textSkeleton skeleton (TextAppend {}) =         ignore     <>  " "@@ -428,11 +550,7 @@     <>  " "     <>  ignore skeleton (ListLit {}) =-        lbracket-    <>  " "-    <>  ignore-    <>  " "-    <>  rbracket+        listSkeleton     <>  " "     <>  colon     <>  " "@@ -542,25 +660,8 @@ mismatch :: Pretty a => Expr s a -> Expr s a -> Diff mismatch l r = difference (skeleton l) (skeleton r) -diffExprA :: Pretty a => Expr s a -> Expr s a -> Diff-diffExprA l@(Annot {}) r@(Annot {}) =-    enclosed' "  " (colon <> " ") (docs l r)-  where-    docs (Annot aL bL) (Annot aR bR) =-        Data.List.NonEmpty.cons (align doc) (docs bL bR)-      where-        doc = diffExprB aL aR-    docs aL aR =-        diffExprB aL aR :| []-diffExprA l@(Annot {}) r =-    mismatch l r-diffExprA l r@(Annot {}) =-    mismatch l r-diffExprA l r =-    diffExprB l r--diffExprB :: Pretty a => Expr s a -> Expr s a -> Diff-diffExprB l@(Lam {}) r@(Lam {}) =+diffExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffExpression l@(Lam {}) r@(Lam {}) =     enclosed' "  " (rarrow <> " ") (docs l r)   where     docs (Lam aL bL cL) (Lam aR bR cR) =@@ -571,16 +672,16 @@             <>  format " " (diffLabel aL aR)             <>  colon             <>  " "-            <>  format mempty (diffExprA bL bR)+            <>  format mempty (diffExpression bL bR)             <>  rparen      docs aL aR =-        pure (diffExprC aL aR)-diffExprB l@(Lam {}) r =+        pure (diffExpression aL aR)+diffExpression l@(Lam {}) r =     mismatch l r-diffExprB l r@(Lam {}) =+diffExpression l r@(Lam {}) =     mismatch l r-diffExprB l@(BoolIf {}) r@(BoolIf {}) =+diffExpression l@(BoolIf {}) r@(BoolIf {}) =     enclosed' "      " (keyword "else" <> "  ") (docs l r)   where     docs (BoolIf aL bL cL) (BoolIf aR bR cR) =@@ -588,17 +689,35 @@       where         doc =   keyword "if"             <>  " "-            <>  format " " (diffExprA aL aR)+            <>  format " " (diffExpression aL aR)             <>  keyword "then"             <>  " "-            <>  diffExprA bL bR+            <>  diffExpression bL bR     docs aL aR =-        pure (diffExprB aL aR)-diffExprB l@(BoolIf {}) r =+        pure (diffExpression aL aR)+diffExpression l@(BoolIf {}) r =     mismatch l r-diffExprB l r@(BoolIf {}) =+diffExpression l r@(BoolIf {}) =     mismatch l r-diffExprB l@(Pi {}) r@(Pi {}) =+diffExpression l@(Let {}) r@(Let {}) =+    enclosed' "    " (keyword "in" <> "  ") (docs l r)+  where+    docs (Let aL bL cL dL) (Let aR bR cR dR) =+        Data.List.NonEmpty.cons (align doc) (docs dL dR)+      where+        doc =   keyword "let"+            <>  " "+            <>  format " " (diffLabel aL aR)+            <>  format " " (diffMaybe (colon <> " ") diffExpression bL bR)+            <>  equals+            <>  " "+            <>  diffExpression cL cR+    docs aL aR = pure (diffExpression aL aR)+diffExpression l@(Let {}) r =+    mismatch l r+diffExpression l r@(Let {}) =+    mismatch l r+diffExpression l@(Pi {}) r@(Pi {}) =     enclosed' "  " (rarrow <> " ") (docs l r)   where     docs (Pi aL bL cL) (Pi aR bR cR) =@@ -609,263 +728,274 @@             <>  format " " (diffLabel aL aR)             <>  colon             <>  " "-            <>  format mempty (diffExprA bL bR)+            <>  format mempty (diffExpression bL bR)             <>  rparen-    docs aL aR = pure (diffExprB aL aR)-diffExprB l@(Pi {}) r =+    docs aL aR = pure (diffExpression aL aR)+diffExpression l@(Pi {}) r =     mismatch l r-diffExprB l r@(Pi {}) =+diffExpression l r@(Pi {}) =     mismatch l r-diffExprB l@(Let {}) r@(Let {}) =-    enclosed' "    " (keyword "in" <> "  ") (docs l r)+diffExpression l r =+    diffAnnotatedExpression l r++diffAnnotatedExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffAnnotatedExpression (Merge aL bL cL) (Merge aR bR cR) = align doc   where-    docs (Let aL bL cL dL) (Let aR bR cR dR) =-        Data.List.NonEmpty.cons (align doc) (docs dL dR)-      where-        doc =   keyword "let"-            <>  " "-            <>  format " " (diffLabel aL aR)-            <>  format " " (diffMaybe (colon <> " ") diffExprA bL bR)-            <>  equals-            <>  " "-            <>  diffExprA cL cR-    docs aL aR = pure (diffExprB aL aR)-diffExprB l@(Let {}) r =-    mismatch l r-diffExprB l r@(Let {}) =-    mismatch l r--- TODO: Implement proper list diff-diffExprB l@(ListLit {}) r@(ListLit {}) =-    mismatch l r-diffExprB l@(ListLit {}) r =+    doc =   keyword "merge"+        <>  " "+        <>  format " " (diffImportExpression aL aR)+        <>  format " " (diffImportExpression bL bR)+        <>  diffMaybe (colon <> " ") diffApplicationExpression cL cR+diffAnnotatedExpression l@(Merge {}) r =     mismatch l r-diffExprB l r@(ListLit {}) =+diffAnnotatedExpression l r@(Merge {}) =     mismatch l r-diffExprB (OptionalLit aL bL) (OptionalLit aR bR) = align doc+diffAnnotatedExpression (ListLit aL@(Just _) bL) (ListLit aR bR) = align doc   where+    doc =   format " " (diffList bL bR)+        <>  format " " (diffMaybe (colon <> " ") (diffApplicationExpression `on` App List) aL aR)+diffAnnotatedExpression (ListLit aL bL) (ListLit aR@(Just _) bR) = align doc+  where+    doc =   format " " (diffList bL bR)+        <>  format " " (diffMaybe (colon <> " ") (diffApplicationExpression `on` App List) aL aR)+diffAnnotatedExpression (OptionalLit aL bL) (OptionalLit aR bR) =+    align doc+  where     doc =   lbracket         <>  " "-        <>  format " " (diffMaybe mempty diffExprA bL bR)+        <>  format " " (diffMaybe mempty diffExpression bL bR)         <>  rbracket         <>  " "         <>  colon         <>  " "-        <>  diffExprD (App Optional aL) (App Optional aR)-diffExprB l@(OptionalLit {}) r =+        <>  diffApplicationExpression (App Optional aL) (App Optional aR)+diffAnnotatedExpression l@(OptionalLit {}) r =     mismatch l r-diffExprB l r@(OptionalLit {}) =+diffAnnotatedExpression l r@(OptionalLit {}) =     mismatch l r-diffExprB (Merge aL bL cL) (Merge aR bR cR) = align doc+diffAnnotatedExpression l@(Annot {}) r@(Annot {}) =+    enclosed' "  " (colon <> " ") (docs l r)   where-    doc =   keyword "merge"-        <>  " "-        <>  format " " (diffExprE aL aR)-        <>  format " " (diffExprE bL bR)-        <>  diffMaybe (colon <> " ") diffExprE cL cR-diffExprB l@(Merge {}) r =+    docs (Annot aL bL) (Annot aR bR) =+        Data.List.NonEmpty.cons (align doc) (docs bL bR)+      where+        doc = diffOperatorExpression aL aR+    docs aL aR =+        diffExpression aL aR :| []+diffAnnotatedExpression l@(Annot {}) r =     mismatch l r-diffExprB l r@(Merge {}) =+diffAnnotatedExpression l r@(Annot {}) =     mismatch l r-diffExprB l r =-    diffExprC l r+diffAnnotatedExpression l r =+    diffOperatorExpression l r -diffExprC :: Pretty a => Expr s a -> Expr s a -> Diff-diffExprC = diffBoolOr+diffOperatorExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffOperatorExpression = diffOrExpression -diffBoolOr :: Pretty a => Expr s a -> Expr s a -> Diff-diffBoolOr l@(BoolOr {}) r@(BoolOr {}) =+diffOrExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffOrExpression l@(BoolOr {}) r@(BoolOr {}) =     enclosed' "    " (operator "||" <> "  ") (docs l r)   where     docs (BoolOr aL bL) (BoolOr aR bR) =-        Data.List.NonEmpty.cons (diffTextAppend aL aR) (docs bL bR)+        Data.List.NonEmpty.cons (diffTextAppendExpression aL aR) (docs bL bR)     docs aL aR =-        pure (diffTextAppend aL aR)-diffBoolOr l@(BoolOr {}) r =+        pure (diffTextAppendExpression aL aR)+diffOrExpression l@(BoolOr {}) r =     mismatch l r-diffBoolOr l r@(BoolOr {}) =+diffOrExpression l r@(BoolOr {}) =     mismatch l r-diffBoolOr l r =-    diffTextAppend l r+diffOrExpression l r =+    diffPlusExpression l r -diffTextAppend :: Pretty a => Expr s a -> Expr s a -> Diff-diffTextAppend l@(TextAppend {}) r@(TextAppend {}) =-    enclosed' "    " (operator "++" <> "  ") (docs l r)+diffPlusExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffPlusExpression l@(NaturalPlus {}) r@(NaturalPlus {}) =+    enclosed' "  " (operator "+" <> " ") (docs l r)   where-    docs (TextAppend aL bL) (TextAppend aR bR) =-        Data.List.NonEmpty.cons (diffNaturalPlus aL aR) (docs bL bR)+    docs (NaturalPlus aL bL) (NaturalPlus aR bR) =+        Data.List.NonEmpty.cons (diffListAppendExpression aL aR) (docs bL bR)     docs aL aR =-        pure (diffNaturalPlus aL aR)-diffTextAppend l@(TextAppend {}) r =+        pure (diffListAppendExpression aL aR)+diffPlusExpression l@(NaturalPlus {}) r =     mismatch l r-diffTextAppend l r@(TextAppend {}) =+diffPlusExpression l r@(NaturalPlus {}) =     mismatch l r-diffTextAppend l r =-    diffNaturalPlus l r+diffPlusExpression l r =+    diffTextAppendExpression l r -diffNaturalPlus :: Pretty a => Expr s a -> Expr s a -> Diff-diffNaturalPlus l@(NaturalPlus {}) r@(NaturalPlus {}) =-    enclosed' "  " (operator "+" <> " ") (docs l r)+diffTextAppendExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffTextAppendExpression l@(TextAppend {}) r@(TextAppend {}) =+    enclosed' "    " (operator "++" <> "  ") (docs l r)   where-    docs (NaturalPlus aL bL) (NaturalPlus aR bR) =-        Data.List.NonEmpty.cons (diffListAppend aL aR) (docs bL bR)+    docs (TextAppend aL bL) (TextAppend aR bR) =+        Data.List.NonEmpty.cons (diffPlusExpression aL aR) (docs bL bR)     docs aL aR =-        pure (diffListAppend aL aR)-diffNaturalPlus l@(NaturalPlus {}) r =+        pure (diffPlusExpression aL aR)+diffTextAppendExpression l@(TextAppend {}) r =     mismatch l r-diffNaturalPlus l r@(NaturalPlus {}) =+diffTextAppendExpression l r@(TextAppend {}) =     mismatch l r-diffNaturalPlus l r =-    diffListAppend l r+diffTextAppendExpression l r =+    diffListAppendExpression l r -diffListAppend :: Pretty a => Expr s a -> Expr s a -> Diff-diffListAppend l@(ListAppend {}) r@(ListAppend {}) =+diffListAppendExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffListAppendExpression l@(ListAppend {}) r@(ListAppend {}) =     enclosed' "  " (operator "#" <> " ") (docs l r)   where     docs (ListAppend aL bL) (ListAppend aR bR) =-        Data.List.NonEmpty.cons (diffBoolAnd aL aR) (docs bL bR)+        Data.List.NonEmpty.cons (diffAndExpression aL aR) (docs bL bR)     docs aL aR =-        pure (diffBoolAnd aL aR)-diffListAppend l@(ListAppend {}) r =+        pure (diffAndExpression aL aR)+diffListAppendExpression l@(ListAppend {}) r =     mismatch l r-diffListAppend l r@(ListAppend {}) =+diffListAppendExpression l r@(ListAppend {}) =     mismatch l r-diffListAppend l r =-    diffBoolAnd l r+diffListAppendExpression l r =+    diffAndExpression l r -diffBoolAnd :: Pretty a => Expr s a -> Expr s a -> Diff-diffBoolAnd l@(BoolAnd {}) r@(BoolAnd {}) =+diffAndExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffAndExpression l@(BoolAnd {}) r@(BoolAnd {}) =     enclosed' "    " (operator "&&" <> "  ") (docs l r)   where     docs (BoolAnd aL bL) (BoolAnd aR bR) =-        Data.List.NonEmpty.cons (diffCombine aL aR) (docs bL bR)+        Data.List.NonEmpty.cons (diffCombineExpression aL aR) (docs bL bR)     docs aL aR =-        pure (diffCombine aL aR)-diffBoolAnd l@(BoolAnd {}) r =+        pure (diffCombineExpression aL aR)+diffAndExpression l@(BoolAnd {}) r =     mismatch l r-diffBoolAnd l r@(BoolAnd {}) =+diffAndExpression l r@(BoolAnd {}) =     mismatch l r-diffBoolAnd l r =-    diffCombine l r+diffAndExpression l r =+    diffCombineExpression l r -diffCombine :: Pretty a => Expr s a -> Expr s a -> Diff-diffCombine l@(Combine {}) r@(Combine {}) =+diffCombineExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffCombineExpression l@(Combine {}) r@(Combine {}) =     enclosed' "  " (operator "∧" <> " ") (docs l r)   where     docs (Combine aL bL) (Combine aR bR) =-        Data.List.NonEmpty.cons (diffPrefer aL aR) (docs bL bR)+        Data.List.NonEmpty.cons (diffPreferExpression aL aR) (docs bL bR)     docs aL aR =-        pure (diffPrefer aL aR)-diffCombine l@(Combine {}) r =+        pure (diffPreferExpression aL aR)+diffCombineExpression l@(Combine {}) r =     mismatch l r-diffCombine l r@(Combine {}) =+diffCombineExpression l r@(Combine {}) =     mismatch l r-diffCombine l r =-    diffPrefer l r+diffCombineExpression l r =+    diffPreferExpression l r -diffPrefer :: Pretty a => Expr s a -> Expr s a -> Diff-diffPrefer l@(Prefer {}) r@(Prefer {}) =+diffPreferExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffPreferExpression l@(Prefer {}) r@(Prefer {}) =     enclosed' "  " (operator "⫽" <> " ") (docs l r)   where     docs (Prefer aL bL) (Prefer aR bR) =-        Data.List.NonEmpty.cons (diffCombineTypes aL aR) (docs bL bR)+        Data.List.NonEmpty.cons (diffCombineTypesExpression aL aR) (docs bL bR)     docs aL aR =-        pure (diffCombineTypes aL aR)-diffPrefer l@(Prefer {}) r =+        pure (diffCombineTypesExpression aL aR)+diffPreferExpression l@(Prefer {}) r =     mismatch l r-diffPrefer l r@(Prefer {}) =+diffPreferExpression l r@(Prefer {}) =     mismatch l r-diffPrefer l r =-    diffCombineTypes l r+diffPreferExpression l r =+    diffCombineTypesExpression l r -diffCombineTypes :: Pretty a => Expr s a -> Expr s a -> Diff-diffCombineTypes l@(CombineTypes {}) r@(CombineTypes {}) =+diffCombineTypesExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffCombineTypesExpression l@(CombineTypes {}) r@(CombineTypes {}) =     enclosed' "  " (operator "*" <> " ") (docs l r)   where     docs (CombineTypes aL bL) (CombineTypes aR bR) =-        Data.List.NonEmpty.cons (diffNaturalTimes aL aR) (docs bL bR)+        Data.List.NonEmpty.cons (diffTimesExpression aL aR) (docs bL bR)     docs aL aR =-        pure (diffNaturalTimes aL aR)-diffCombineTypes l@(CombineTypes {}) r =+        pure (diffTimesExpression aL aR)+diffCombineTypesExpression l@(CombineTypes {}) r =     mismatch l r-diffCombineTypes l r@(CombineTypes {}) =+diffCombineTypesExpression l r@(CombineTypes {}) =     mismatch l r-diffCombineTypes l r =-    diffNaturalTimes l r+diffCombineTypesExpression l r =+    diffTimesExpression l r -diffNaturalTimes :: Pretty a => Expr s a -> Expr s a -> Diff-diffNaturalTimes l@(NaturalTimes {}) r@(NaturalTimes {}) =+diffTimesExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffTimesExpression l@(NaturalTimes {}) r@(NaturalTimes {}) =     enclosed' "  " (operator "*" <> " ") (docs l r)   where     docs (NaturalTimes aL bL) (NaturalTimes aR bR) =-        Data.List.NonEmpty.cons (diffBoolEQ aL aR) (docs bL bR)+        Data.List.NonEmpty.cons (diffEqualExpression aL aR) (docs bL bR)     docs aL aR =-        pure (diffBoolEQ aL aR)-diffNaturalTimes l@(NaturalTimes {}) r =+        pure (diffEqualExpression aL aR)+diffTimesExpression l@(NaturalTimes {}) r =     mismatch l r-diffNaturalTimes l r@(NaturalTimes {}) =+diffTimesExpression l r@(NaturalTimes {}) =     mismatch l r-diffNaturalTimes l r =-    diffBoolEQ l r+diffTimesExpression l r =+    diffEqualExpression l r -diffBoolEQ :: Pretty a => Expr s a -> Expr s a -> Diff-diffBoolEQ l@(BoolEQ {}) r@(BoolEQ {}) =+diffEqualExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffEqualExpression l@(BoolEQ {}) r@(BoolEQ {}) =     enclosed' "    " (operator "==" <> "  ") (docs l r)   where     docs (BoolEQ aL bL) (BoolEQ aR bR) =-        Data.List.NonEmpty.cons (diffBoolNE aL aR) (docs bL bR)+        Data.List.NonEmpty.cons (diffNotEqualExpression aL aR) (docs bL bR)     docs aL aR =-        pure (diffBoolNE aL aR)-diffBoolEQ l@(BoolEQ {}) r =+        pure (diffNotEqualExpression aL aR)+diffEqualExpression l@(BoolEQ {}) r =     mismatch l r-diffBoolEQ l r@(BoolEQ {}) =+diffEqualExpression l r@(BoolEQ {}) =     mismatch l r-diffBoolEQ l r =-    diffBoolNE l r+diffEqualExpression l r =+    diffNotEqualExpression l r -diffBoolNE :: Pretty a => Expr s a -> Expr s a -> Diff-diffBoolNE l@(BoolNE {}) r@(BoolNE {}) =+diffNotEqualExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffNotEqualExpression l@(BoolNE {}) r@(BoolNE {}) =     enclosed' "    " (operator "!=" <> "  ") (docs l r)   where     docs (BoolNE aL bL) (BoolNE aR bR) =-        Data.List.NonEmpty.cons (diffExprD aL aR) (docs bL bR)+        Data.List.NonEmpty.cons (diffApplicationExpression aL aR) (docs bL bR)     docs aL aR =-        pure (diffExprD aL aR)-diffBoolNE l@(BoolNE {}) r =+        pure (diffApplicationExpression aL aR)+diffNotEqualExpression l@(BoolNE {}) r =     mismatch l r-diffBoolNE l r@(BoolNE {}) =+diffNotEqualExpression l r@(BoolNE {}) =     mismatch l r-diffBoolNE l r =-    diffExprD l r+diffNotEqualExpression l r =+    diffApplicationExpression l r -diffExprD :: Pretty a => Expr s a -> Expr s a -> Diff-diffExprD l@(App {}) r@(App {}) =+diffApplicationExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffApplicationExpression l@(App {}) r@(App {}) =     enclosed' mempty mempty (Data.List.NonEmpty.reverse (docs l r))   where     docs (App aL bL) (App aR bR) =-        Data.List.NonEmpty.cons (diffExprE bL bR) (docs aL aR)+        Data.List.NonEmpty.cons (diffImportExpression bL bR) (docs aL aR)     docs (Constructors aL) (Constructors aR) =-        diffExprE aL aR :| [ keyword "constructors" ]+        diffImportExpression aL aR :| [ keyword "constructors" ]     docs aL@(App {}) aR@(Constructors {}) =         pure (mismatch aL aR)     docs aL@(Constructors {}) aR@(App {}) =         pure (mismatch aL aR)     docs aL aR =-        pure (diffExprE aL aR)-diffExprD l@(App {}) r =+        pure (diffImportExpression aL aR)+diffApplicationExpression l@(App {}) r =     mismatch l r-diffExprD l r@(App {}) =+diffApplicationExpression l r@(App {}) =     mismatch l r-diffExprD l@(Constructors {}) r@(Constructors {}) =-    enclosed' mempty mempty (keyword "constructors" :| [ diffExprE l r ])-diffExprD l@(Constructors {}) r =+diffApplicationExpression l@(Constructors {}) r@(Constructors {}) =+    enclosed' mempty mempty (keyword "constructors" :| [ diffImportExpression l r ])+diffApplicationExpression l@(Constructors {}) r =     mismatch l r-diffExprD l r@(Constructors {}) =+diffApplicationExpression l r@(Constructors {}) =     mismatch l r-diffExprD l r =-    diffExprE l r+diffApplicationExpression l r =+    diffImportExpression l r -diffExprE :: Pretty a => Expr s a -> Expr s a -> Diff-diffExprE l@(Field {}) r@(Field {}) =+diffImportExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffImportExpression (Embed l) (Embed r) =+    diffPretty l r+diffImportExpression l@(Embed {}) r =+    mismatch l r+diffImportExpression l r@(Embed {}) =+    mismatch l r+diffImportExpression l r =+    diffSelectorExpression l r++diffSelectorExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffSelectorExpression l@(Field {}) r@(Field {}) =     enclosed' "  " (dot <> " ") (Data.List.NonEmpty.reverse (docs l r))   where     docs (Field aL bL) (Field aR bR) =@@ -873,12 +1003,12 @@     docs (Project aL bL) (Project aR bR) =         Data.List.NonEmpty.cons (diffLabels bL bR) (docs aL aR)     docs aL aR =-        pure (diffExprF aL aR)-diffExprE l@(Field {}) r =+        pure (diffPrimitiveExpression aL aR)+diffSelectorExpression l@(Field {}) r =     mismatch l r-diffExprE l r@(Field {}) =+diffSelectorExpression l r@(Field {}) =     mismatch l r-diffExprE l@(Project {}) r@(Project {}) =+diffSelectorExpression l@(Project {}) r@(Project {}) =     enclosed' "  " (dot <> " ") (Data.List.NonEmpty.reverse (docs l r))   where     docs (Field aL bL) (Field aR bR) =@@ -886,235 +1016,247 @@     docs (Project aL bL) (Project aR bR) =         Data.List.NonEmpty.cons (diffLabels bL bR) (docs aL aR)     docs aL aR =-        pure (diffExprF aL aR)-diffExprE l@(Project {}) r =+        pure (diffPrimitiveExpression aL aR)+diffSelectorExpression l@(Project {}) r =     mismatch l r-diffExprE l r@(Project {}) =+diffSelectorExpression l r@(Project {}) =     mismatch l r-diffExprE l r =-    diffExprF l r+diffSelectorExpression l r =+    diffPrimitiveExpression l r -diffExprF :: Pretty a => Expr s a -> Expr s a -> Diff-diffExprF (Var aL) (Var aR) =+diffPrimitiveExpression :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Diff+diffPrimitiveExpression (Var aL) (Var aR) =     diffVar aL aR-diffExprF l@(Var {}) r =+diffPrimitiveExpression l@(Var {}) r =     mismatch l r-diffExprF l r@(Var {}) =+diffPrimitiveExpression l r@(Var {}) =     mismatch l r-diffExprF (Const aL) (Const aR) =+diffPrimitiveExpression (Const aL) (Const aR) =     diffConst aL aR-diffExprF l@(Const {}) r =+diffPrimitiveExpression l@(Const {}) r =     mismatch l r-diffExprF l r@(Const {}) =+diffPrimitiveExpression l r@(Const {}) =     mismatch l r-diffExprF Bool Bool =+diffPrimitiveExpression Bool Bool =     "…"-diffExprF l@Bool r =+diffPrimitiveExpression l@Bool r =     mismatch l r-diffExprF l r@Bool =+diffPrimitiveExpression l r@Bool =     mismatch l r-diffExprF Natural Natural =+diffPrimitiveExpression Natural Natural =     "…"-diffExprF l@Natural r =+diffPrimitiveExpression l@Natural r =     mismatch l r-diffExprF l r@Natural =+diffPrimitiveExpression l r@Natural =     mismatch l r-diffExprF NaturalFold NaturalFold =+diffPrimitiveExpression NaturalFold NaturalFold =     "…"-diffExprF l@NaturalFold r =+diffPrimitiveExpression l@NaturalFold r =     mismatch l r-diffExprF l r@NaturalFold =+diffPrimitiveExpression l r@NaturalFold =     mismatch l r-diffExprF NaturalBuild NaturalBuild =+diffPrimitiveExpression NaturalBuild NaturalBuild =     "…"-diffExprF l@NaturalBuild r =+diffPrimitiveExpression l@NaturalBuild r =     mismatch l r-diffExprF l r@NaturalBuild =+diffPrimitiveExpression l r@NaturalBuild =     mismatch l r-diffExprF NaturalIsZero NaturalIsZero =+diffPrimitiveExpression NaturalIsZero NaturalIsZero =     "…"-diffExprF l@NaturalIsZero r =+diffPrimitiveExpression l@NaturalIsZero r =     mismatch l r-diffExprF l r@NaturalIsZero =+diffPrimitiveExpression l r@NaturalIsZero =     mismatch l r-diffExprF NaturalEven NaturalEven =+diffPrimitiveExpression NaturalEven NaturalEven =     "…"-diffExprF l@NaturalEven r =+diffPrimitiveExpression l@NaturalEven r =     mismatch l r-diffExprF l r@NaturalEven =+diffPrimitiveExpression l r@NaturalEven =     mismatch l r-diffExprF NaturalOdd NaturalOdd =+diffPrimitiveExpression NaturalOdd NaturalOdd =     "…"-diffExprF l@NaturalOdd r =+diffPrimitiveExpression l@NaturalOdd r =     mismatch l r-diffExprF l r@NaturalOdd =+diffPrimitiveExpression l r@NaturalOdd =     mismatch l r-diffExprF NaturalToInteger NaturalToInteger =+diffPrimitiveExpression NaturalToInteger NaturalToInteger =     "…"-diffExprF l@NaturalToInteger r =+diffPrimitiveExpression l@NaturalToInteger r =     mismatch l r-diffExprF l r@NaturalToInteger =+diffPrimitiveExpression l r@NaturalToInteger =     mismatch l r-diffExprF NaturalShow NaturalShow =+diffPrimitiveExpression NaturalShow NaturalShow =     "…"-diffExprF l@NaturalShow r =+diffPrimitiveExpression l@NaturalShow r =     mismatch l r-diffExprF l r@NaturalShow =+diffPrimitiveExpression l r@NaturalShow =     mismatch l r-diffExprF Integer Integer =+diffPrimitiveExpression Integer Integer =     "…"-diffExprF l@Integer r =+diffPrimitiveExpression l@Integer r =     mismatch l r-diffExprF l r@Integer =+diffPrimitiveExpression l r@Integer =     mismatch l r-diffExprF IntegerShow IntegerShow =+diffPrimitiveExpression IntegerShow IntegerShow =     "…"-diffExprF l@IntegerShow r =+diffPrimitiveExpression l@IntegerShow r =     mismatch l r-diffExprF l r@IntegerShow =+diffPrimitiveExpression l r@IntegerShow =     mismatch l r-diffExprF Double Double =+diffPrimitiveExpression IntegerToDouble IntegerToDouble =     "…"-diffExprF l@Double r =+diffPrimitiveExpression l@IntegerToDouble r =     mismatch l r-diffExprF l r@Double =+diffPrimitiveExpression l r@IntegerToDouble =     mismatch l r-diffExprF DoubleShow DoubleShow =+diffPrimitiveExpression Double Double =     "…"-diffExprF l@DoubleShow r =+diffPrimitiveExpression l@Double r =     mismatch l r-diffExprF l r@DoubleShow =+diffPrimitiveExpression l r@Double =     mismatch l r-diffExprF Text Text =+diffPrimitiveExpression DoubleShow DoubleShow =     "…"-diffExprF l@Text r =+diffPrimitiveExpression l@DoubleShow r =     mismatch l r-diffExprF l r@Text =+diffPrimitiveExpression l r@DoubleShow =     mismatch l r-diffExprF List List =+diffPrimitiveExpression Text Text =     "…"-diffExprF l@List r =+diffPrimitiveExpression l@Text r =     mismatch l r-diffExprF l r@List =+diffPrimitiveExpression l r@Text =     mismatch l r-diffExprF ListBuild ListBuild =+diffPrimitiveExpression List List =     "…"-diffExprF l@ListBuild r =+diffPrimitiveExpression l@List r =     mismatch l r-diffExprF l r@ListBuild =+diffPrimitiveExpression l r@List =     mismatch l r-diffExprF ListFold ListFold =+diffPrimitiveExpression (ListLit Nothing bL) (ListLit Nothing bR) = align doc+  where+    doc = format " " (diffList bL bR)+diffPrimitiveExpression l@(ListLit {}) r =+    mismatch l r+diffPrimitiveExpression l r@(ListLit {}) =+    mismatch l r+diffPrimitiveExpression ListBuild ListBuild =     "…"-diffExprF l@ListFold r =+diffPrimitiveExpression l@ListBuild r =     mismatch l r-diffExprF l r@ListFold =+diffPrimitiveExpression l r@ListBuild =     mismatch l r-diffExprF ListLength ListLength =+diffPrimitiveExpression ListFold ListFold =     "…"-diffExprF l@ListLength r =+diffPrimitiveExpression l@ListFold r =     mismatch l r-diffExprF l r@ListLength =+diffPrimitiveExpression l r@ListFold =     mismatch l r-diffExprF ListHead ListHead =+diffPrimitiveExpression ListLength ListLength =     "…"-diffExprF l@ListHead r =+diffPrimitiveExpression l@ListLength r =     mismatch l r-diffExprF l r@ListHead =+diffPrimitiveExpression l r@ListLength =     mismatch l r-diffExprF ListLast ListLast =+diffPrimitiveExpression ListHead ListHead =     "…"-diffExprF l@ListLast r =+diffPrimitiveExpression l@ListHead r =     mismatch l r-diffExprF l r@ListLast =+diffPrimitiveExpression l r@ListHead =     mismatch l r-diffExprF ListIndexed ListIndexed =+diffPrimitiveExpression ListLast ListLast =     "…"-diffExprF l@ListIndexed r =+diffPrimitiveExpression l@ListLast r =     mismatch l r-diffExprF l r@ListIndexed =+diffPrimitiveExpression l r@ListLast =     mismatch l r-diffExprF ListReverse ListReverse =+diffPrimitiveExpression ListIndexed ListIndexed =     "…"-diffExprF l@ListReverse r =+diffPrimitiveExpression l@ListIndexed r =     mismatch l r-diffExprF l r@ListReverse =+diffPrimitiveExpression l r@ListIndexed =     mismatch l r-diffExprF Optional Optional =+diffPrimitiveExpression ListReverse ListReverse =     "…"-diffExprF l@Optional r =+diffPrimitiveExpression l@ListReverse r =     mismatch l r-diffExprF l r@Optional =+diffPrimitiveExpression l r@ListReverse =     mismatch l r-diffExprF OptionalFold OptionalFold =+diffPrimitiveExpression Optional Optional =     "…"-diffExprF l@OptionalFold r =+diffPrimitiveExpression l@Optional r =     mismatch l r-diffExprF l r@OptionalFold =+diffPrimitiveExpression l r@Optional =     mismatch l r-diffExprF OptionalBuild OptionalBuild =+diffPrimitiveExpression OptionalFold OptionalFold =     "…"-diffExprF l@OptionalBuild r =+diffPrimitiveExpression l@OptionalFold r =     mismatch l r-diffExprF l r@OptionalBuild =+diffPrimitiveExpression l r@OptionalFold =     mismatch l r-diffExprF (BoolLit aL) (BoolLit aR) =+diffPrimitiveExpression OptionalBuild OptionalBuild =+    "…"+diffPrimitiveExpression l@OptionalBuild r =+    mismatch l r+diffPrimitiveExpression l r@OptionalBuild =+    mismatch l r+diffPrimitiveExpression (BoolLit aL) (BoolLit aR) =     diffBool aL aR-diffExprF l@(BoolLit {}) r =+diffPrimitiveExpression l@(BoolLit {}) r =     mismatch l r-diffExprF l r@(BoolLit {}) =+diffPrimitiveExpression l r@(BoolLit {}) =     mismatch l r-diffExprF (IntegerLit aL) (IntegerLit aR) =+diffPrimitiveExpression (IntegerLit aL) (IntegerLit aR) =     diffInteger aL aR-diffExprF l@(IntegerLit {}) r =+diffPrimitiveExpression l@(IntegerLit {}) r =     mismatch l r-diffExprF l r@(IntegerLit {}) =+diffPrimitiveExpression l r@(IntegerLit {}) =     mismatch l r-diffExprF (NaturalLit aL) (NaturalLit aR) =-    token (Internal.literal "+") <> diffNatural aL aR-diffExprF l@(NaturalLit {}) r =+diffPrimitiveExpression (NaturalLit aL) (NaturalLit aR) =+    diffNatural aL aR+diffPrimitiveExpression l@(NaturalLit {}) r =     mismatch l r-diffExprF l r@(NaturalLit {}) =+diffPrimitiveExpression l r@(NaturalLit {}) =     mismatch l r-diffExprF (DoubleLit aL) (DoubleLit aR) =+diffPrimitiveExpression (DoubleLit aL) (DoubleLit aR) =     diffScientific aL aR-diffExprF l@(DoubleLit {}) r =-    mismatch l r-diffExprF l r@(DoubleLit {}) =+diffPrimitiveExpression l@(DoubleLit {}) r =     mismatch l r--- TODO: Implement proper textual diff-diffExprF l@(TextLit {}) r@(TextLit {}) =+diffPrimitiveExpression l r@(DoubleLit {}) =     mismatch l r-diffExprF l@(TextLit {}) r =+diffPrimitiveExpression (TextLit l) (TextLit r) =+    diffChunks l r+diffPrimitiveExpression l@(TextLit {}) r =     mismatch l r-diffExprF l r@(TextLit {}) =+diffPrimitiveExpression l r@(TextLit {}) =     mismatch l r-diffExprF (Record aL) (Record aR) =+diffPrimitiveExpression (Record aL) (Record aR) =     diffRecord aL aR-diffExprF l@(Record {}) r =+diffPrimitiveExpression l@(Record {}) r =     mismatch l r-diffExprF l r@(Record {}) =+diffPrimitiveExpression l r@(Record {}) =     mismatch l r-diffExprF (RecordLit aL) (RecordLit aR) =+diffPrimitiveExpression (RecordLit aL) (RecordLit aR) =     diffRecordLit aL aR-diffExprF l@(RecordLit {}) r =+diffPrimitiveExpression l@(RecordLit {}) r =     mismatch l r-diffExprF l r@(RecordLit {}) =+diffPrimitiveExpression l r@(RecordLit {}) =     mismatch l r-diffExprF (Union aL) (Union aR) =+diffPrimitiveExpression (Union aL) (Union aR) =     diffUnion aL aR-diffExprF l@(Union {}) r =+diffPrimitiveExpression l@(Union {}) r =     mismatch l r-diffExprF l r@(Union {}) =+diffPrimitiveExpression l r@(Union {}) =     mismatch l r-diffExprF (UnionLit aL bL cL) (UnionLit aR bR cR) =+diffPrimitiveExpression (UnionLit aL bL cL) (UnionLit aR bR cR) =     diffUnionLit aL aR bL bR cL cR-diffExprF l@(UnionLit {}) r =+diffPrimitiveExpression l@(UnionLit {}) r =     mismatch l r-diffExprF l r@(UnionLit {}) =+diffPrimitiveExpression l r@(UnionLit {}) =     mismatch l r-diffExprF aL aR =+diffPrimitiveExpression aL aR =     if same doc     then ignore     else align ("( " <> doc <> hardline <> ")")   where-    doc = diffExprA aL aR+    doc = diffExpression aL aR
+ src/Dhall/Format.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE OverloadedStrings #-}++module Dhall.Format ( format ) where++import Dhall.Parser (exprAndHeaderFromText)+import Dhall.Pretty (annToAnsiStyle, prettyExpr)++import Data.Monoid ((<>))++import qualified Data.Text.Prettyprint.Doc                 as Pretty+import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Pretty+import qualified Control.Exception+import qualified Data.Text.IO+import qualified System.Console.ANSI+import qualified System.IO++opts :: Pretty.LayoutOptions+opts =+    Pretty.defaultLayoutOptions+        { Pretty.layoutPageWidth = Pretty.AvailablePerLine 80 1.0 }++format :: Maybe FilePath -> IO ()+format inplace = do+        case inplace of+            Just file -> do+                text <- Data.Text.IO.readFile file+                (header, expr) <- case exprAndHeaderFromText "(stdin)" text of+                    Left  err -> Control.Exception.throwIO err+                    Right x   -> return x++                let doc = Pretty.pretty header <> Pretty.pretty expr+                System.IO.withFile file System.IO.WriteMode (\handle -> do+                    Pretty.renderIO handle (Pretty.layoutSmart opts doc)+                    Data.Text.IO.hPutStrLn handle "" )+            Nothing -> do+                System.IO.hSetEncoding System.IO.stdin System.IO.utf8+                inText <- Data.Text.IO.getContents++                (header, expr) <- case exprAndHeaderFromText "(stdin)" inText of+                    Left  err -> Control.Exception.throwIO err+                    Right x   -> return x++                let doc = Pretty.pretty header <> prettyExpr expr++                supportsANSI <- System.Console.ANSI.hSupportsANSI System.IO.stdout++                if supportsANSI+                  then+                    Pretty.renderIO+                      System.IO.stdout+                      (fmap annToAnsiStyle (Pretty.layoutSmart opts doc))+                  else+                    Pretty.renderIO+                      System.IO.stdout+                      (Pretty.layoutSmart opts (Pretty.unAnnotate doc))
+ src/Dhall/Freeze.hs view
@@ -0,0 +1,76 @@+{-# LANGUAGE OverloadedStrings #-}++module Dhall.Freeze (+      freeze+    , hashImport+    ) where++import Dhall.Core+import Dhall.Import (load, hashExpression)+import Dhall.Parser (exprAndHeaderFromText, Src)+import Dhall.Pretty (annToAnsiStyle)++import System.Console.ANSI (hSupportsANSI)+import Data.Monoid ((<>))+import Data.Maybe (fromMaybe)+import Data.Text++import qualified Data.Text.Prettyprint.Doc                 as Pretty+import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Pretty+import qualified Control.Exception+import qualified Data.Text.IO+import qualified System.IO++opts :: Pretty.LayoutOptions+opts =+    Pretty.defaultLayoutOptions+        { Pretty.layoutPageWidth = Pretty.AvailablePerLine 80 1.0 }++readInput :: Maybe FilePath -> IO Text+readInput = maybe fromStdin Data.Text.IO.readFile+    where +        fromStdin = System.IO.hSetEncoding System.IO.stdin System.IO.utf8 >> Data.Text.IO.getContents++hashImport :: Import -> IO Import+hashImport import_ = do+    expression <- Dhall.Import.load (Embed import_)+    let expressionHash = Just (Dhall.Import.hashExpression expression)+    let newImportHashed = (importHashed import_) { hash = expressionHash }+    return $ import_ { importHashed = newImportHashed }++parseExpr :: String -> Text -> IO (Text, Expr Src Import)+parseExpr src txt =+    case exprAndHeaderFromText src txt of+        Left err -> Control.Exception.throwIO err+        Right x  -> return x++freezeExpr :: (Text, Expr s Import) -> IO (Text, Expr s Import)+freezeExpr (t, e) = do+    e' <- traverse hashImport e+    return (t, e')++writeExpr :: Maybe FilePath -> (Text, Expr s Import) -> IO ()+writeExpr inplace (header, expr) = do+    let doc = Pretty.pretty header <> Pretty.pretty expr+    let layoutOptions = opts+    let stream = Pretty.layoutSmart layoutOptions doc++    case inplace of+        Just f ->+            System.IO.withFile f System.IO.WriteMode (\h ->+                Pretty.renderIO h (annToAnsiStyle <$> stream))++        Nothing -> do+            supportsANSI <- System.Console.ANSI.hSupportsANSI System.IO.stdout+            if supportsANSI +               then +                 Pretty.renderIO System.IO.stdout (annToAnsiStyle <$> Pretty.layoutSmart opts doc)+               else+                 Pretty.renderIO System.IO.stdout (Pretty.layoutSmart opts (Pretty.unAnnotate doc)) ++freeze :: Maybe FilePath -> IO ()+freeze inplace = do+    expr <- readInput inplace+    parseExpr srcInfo expr >>= freezeExpr >>= writeExpr inplace+        where+            srcInfo = fromMaybe "(stdin)" inplace
+ src/Dhall/Hash.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE OverloadedStrings #-}++module Dhall.Hash ( hash ) where++import Dhall.Parser (exprFromText)+import Dhall.Import (hashExpressionToCode, load)++import qualified Control.Exception+import qualified Dhall.TypeCheck+import qualified Data.Text.IO+import qualified System.IO++hash :: IO ()+hash = do+        System.IO.hSetEncoding System.IO.stdin System.IO.utf8+        inText <- Data.Text.IO.getContents++        expr <- case exprFromText "(stdin)" inText of+            Left  err  -> Control.Exception.throwIO err+            Right expr -> return expr++        expr' <- load expr++        _ <- case Dhall.TypeCheck.typeOf expr' of+            Left  err -> Control.Exception.throwIO err+            Right _   -> return ()++        Data.Text.IO.putStrLn (hashExpressionToCode expr')
src/Dhall/Import.hs view
@@ -113,27 +113,24 @@     , PrettyHttpException(..)     , MissingFile(..)     , MissingEnvironmentVariable(..)+    , MissingImports(..)     ) where  import Control.Applicative (empty)-import Control.Exception (Exception, SomeException, throwIO)-import Control.Monad (join)-import Control.Monad.Catch (throwM, MonadCatch(catch))+import Control.Exception (Exception, SomeException, throwIO, toException)+import Control.Monad.Catch (throwM, MonadCatch(catch), catches, Handler(..)) import Control.Monad.IO.Class (MonadIO(..)) import Control.Monad.Trans.State.Strict (StateT) import Crypto.Hash (SHA256) import Data.CaseInsensitive (CI) import Data.List.NonEmpty (NonEmpty(..))-import Data.Map (Map) import Data.Semigroup (sconcat, (<>))-import Data.Text.Lazy (Text)-import Data.Text.Lazy.Builder (Builder)+import Data.Text (Text) #if MIN_VERSION_base(4,8,0) #else import Data.Traversable (traverse) #endif import Data.Typeable (Typeable)-import Formatting.Buildable (build) import System.FilePath ((</>)) import Dhall.Core     ( Expr(..)@@ -146,46 +143,38 @@     , ImportMode(..)     , Import(..)     )+#ifdef MIN_VERSION_http_client+import Dhall.Import.HTTP+#endif+import Dhall.Import.Types+ import Dhall.Parser (Parser(..), ParseError(..), Src(..)) import Dhall.TypeCheck (X(..))-import Lens.Family (LensLike') import Lens.Family.State.Strict (zoom)-#if MIN_VERSION_http_client(0,5,0)-import Network.HTTP.Client-    (HttpException(..), HttpExceptionContent(..), Manager)-#else-import Network.HTTP.Client (HttpException(..), Manager)-#endif -import qualified Control.Monad.Trans.State.Strict as State+import qualified Control.Monad.Trans.State.Strict        as State import qualified Crypto.Hash import qualified Data.ByteString import qualified Data.CaseInsensitive import qualified Data.Foldable-import qualified Data.List                        as List++import qualified Data.List                               as List import qualified Data.HashMap.Strict.InsOrd-import qualified Data.Map.Strict                  as Map+import qualified Data.Map.Strict                         as Map import qualified Data.Text.Encoding-import qualified Data.Text.Lazy                   as Text-import qualified Data.Text.Lazy.Builder           as Builder-import qualified Data.Text.Lazy.Encoding-import qualified Data.Text.Lazy.IO+import qualified Data.Text                               as Text+import qualified Data.Text.IO import qualified Dhall.Core import qualified Dhall.Parser import qualified Dhall.Context+import qualified Dhall.Pretty.Internal import qualified Dhall.TypeCheck-import qualified Network.HTTP.Client              as HTTP-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 -builderToString :: Builder -> String-builderToString = Text.unpack . Builder.toLazyText- -- | An import failed because of a cycle in the import graph newtype Cycle = Cycle     { cyclicImport :: Import  -- ^ The offending cyclic import@@ -196,7 +185,7 @@  instance Show Cycle where     show (Cycle import_) =-        "\nCyclic import: " ++ builderToString (build import_)+        "\nCyclic import: " ++ Dhall.Pretty.Internal.prettyToString import_  {-| Dhall tries to ensure that all expressions hosted on network endpoints are     weakly referentially transparent, meaning roughly that any two clients will@@ -232,7 +221,7 @@  instance Show ReferentiallyOpaque where     show (ReferentiallyOpaque import_) =-        "\nReferentially opaque import: " ++ builderToString (build import_)+        "\nReferentially opaque import: " ++ Dhall.Pretty.Internal.prettyToString import_  -- | Extend another exception with the current import stack data Imported e = Imported@@ -249,56 +238,11 @@         ++  show e       where         indent (n, import_) =-            take (2 * n) (repeat ' ') ++ "↳ " ++ builderToString (build import_)+            take (2 * n) (repeat ' ') ++ "↳ " ++ Dhall.Pretty.Internal.prettyToString import_         -- Canonicalize all imports         imports' = zip [0..] (drop 1 (reverse (canonicalizeAll imports))) --- | Newtype used to wrap `HttpException`s with a prettier `Show` instance-newtype PrettyHttpException = PrettyHttpException HttpException-    deriving (Typeable) -instance Exception PrettyHttpException--#if MIN_VERSION_http_client(0,5,0)-instance Show PrettyHttpException where-  show (PrettyHttpException (InvalidUrlException _ r)) =-    "\n"-    <>  "\ESC[1;31mError\ESC[0m: Invalid URL\n"-    <>  "\n"-    <>  "↳ " <> show r-  show (PrettyHttpException (HttpExceptionRequest _ e)) = case e of-    ConnectionFailure e' ->-      "\n"-      <>  "\ESC[1;31mError\ESC[0m: Wrong host\n"-      <>  "\n"-      <>  "↳ " <> show e'-    InvalidDestinationHost host ->-      "\n"-      <>  "\ESC[1;31mError\ESC[0m: Invalid host name\n"-      <>  "\n"-      <>  "↳ " <> show host-    ResponseTimeout ->-      "\ESC[1;31mError\ESC[0m: The host took too long to respond\n"-    e' -> "\n" <> show e'-#else-instance Show PrettyHttpException where-    show (PrettyHttpException e) = case e of-        FailedConnectionException2 _ _ _ e' ->-                "\n"-            <>  "\ESC[1;31mError\ESC[0m: Wrong host\n"-            <>  "\n"-            <>  "↳ " <> show e'-        InvalidDestinationHost host ->-                "\n"-            <>  "\ESC[1;31mError\ESC[0m: Invalid host name\n"-            <>  "\n"-            <>  "↳ " <> show host-        ResponseTimeout ->-                "\ESC[1;31mError\ESC[0m: The host took too long to respond\n"-        e' ->   "\n"-            <> show e'-#endif- -- | Exception thrown when an imported file is missing data MissingFile = MissingFile FilePath     deriving (Typeable)@@ -325,56 +269,61 @@         <>  "\n"         <>  "↳ " <> Text.unpack name --- | State threaded throughout the import process-data Status = Status-    { _stack   :: [Import]-    -- ^ Stack of `Import`s that we've imported along the way to get to the-    -- current point-    , _cache   :: Map Import (Expr Src X)-    -- ^ Cache of imported expressions in order to avoid importing the same-    --   expression twice with different values-    , _manager :: Maybe Manager-    -- ^ Cache for the `Manager` so that we only acquire it once-    }+-- | List of Exceptions we encounter while resolving Import Alternatives+newtype MissingImports = MissingImports [SomeException] --- | Default starting `Status`-emptyStatus :: Status-emptyStatus = Status [] Map.empty Nothing+instance Exception MissingImports -canonicalizeAll :: [Import] -> [Import]-canonicalizeAll = map canonicalizeImport . List.tails+instance Show MissingImports where+    show (MissingImports []) =+            "\n"+        <>  "\ESC[1;31mError\ESC[0m: No valid imports"+        <>  "\n"+    show (MissingImports [e]) = show e+    show (MissingImports es) =+            "\n"+        <>  "\ESC[1;31mError\ESC[0m: Failed to resolve imports. Error list:"+        <>  "\n"+        <>  concatMap (\e -> "\n" <> show e <> "\n") es+        <>  "\n" -stack :: Functor f => LensLike' f Status [Import]-stack k s = fmap (\x -> s { _stack = x }) (k (_stack s))+throwMissingImport :: (MonadCatch m, Exception e) => e -> m a+throwMissingImport e = throwM (MissingImports [(toException e)]) -cache :: Functor f => LensLike' f Status (Map Import (Expr Src X))-cache k s = fmap (\x -> s { _cache = x }) (k (_cache s)) -manager :: Functor f => LensLike' f Status (Maybe Manager)-manager k s = fmap (\x -> s { _manager = x }) (k (_manager s))+-- | Exception thrown when a HTTP url is imported but dhall was built without+-- the @with-http@ Cabal flag.+data CannotImportHTTPURL =+    CannotImportHTTPURL+        String+        (Maybe [(CI Data.ByteString.ByteString, Data.ByteString.ByteString)])+    deriving (Typeable) -needManager :: StateT Status IO Manager-needManager = do-    x <- zoom manager State.get-    case x of-        Just m  -> return m-        Nothing -> do-            let settings = HTTP.tlsManagerSettings-#if MIN_VERSION_http_client(0,5,0)-                    { HTTP.managerResponseTimeout = HTTP.responseTimeoutMicro (30 * 1000 * 1000) }  -- 30 seconds-#else-                    { HTTP.managerResponseTimeout = Just (30 * 1000 * 1000) }  -- 30 seconds-#endif-            m <- liftIO (HTTP.newManager settings)-            zoom manager (State.put (Just m))-            return m+instance Exception CannotImportHTTPURL +instance Show CannotImportHTTPURL where+    show (CannotImportHTTPURL url _mheaders) =+            "\n"+        <>  "\ESC[1;31mError\ESC[0m: Cannot import HTTP URL.\n"+        <>  "\n"+        <>  "Dhall was compiled without the 'with-http' flag.\n"+        <>  "\n"+        <>  "The requested URL was: "+        <>  url+        <>  "\n"++canonicalizeAll :: [Import] -> [Import]+canonicalizeAll = map canonicalizeImport . List.tails+ {-| > canonicalize (canonicalize x) = canonicalize x -} class Canonicalize path where     canonicalize :: path -> path +-- |+-- >>> canonicalize (Directory {components = ["..",".."]})+-- Directory {components = ["..",".."]} instance Canonicalize Directory where     canonicalize (Directory []) = Directory [] @@ -383,8 +332,12 @@      canonicalize (Directory (".." : components₀)) =         case canonicalize (Directory components₀) of-            Directory      []           -> Directory [ ".." ]-            Directory (_ : components₁) -> Directory components₁+            Directory [] ->+                Directory [ ".." ]+            Directory (".." : components₁) ->+                Directory (".." : ".." : components₁)+            Directory (_    : components₁) ->+                Directory components₁      canonicalize (Directory (component : components₀)) =         Directory (component : components₁)@@ -405,6 +358,9 @@     canonicalize (Env name) =         Env name +    canonicalize Missing =+        Missing+ instance Canonicalize ImportHashed where     canonicalize (ImportHashed hash importType) =         ImportHashed hash (canonicalize importType)@@ -439,10 +395,8 @@   :: Expr s a   -> Maybe (CI Data.ByteString.ByteString, Data.ByteString.ByteString) toHeader (RecordLit m) = do-    TextLit (Chunks [] keyBuilder  ) <- Data.HashMap.Strict.InsOrd.lookup "header" m-    TextLit (Chunks [] valueBuilder) <- Data.HashMap.Strict.InsOrd.lookup "value"  m-    let keyText   = Text.toStrict (Builder.toLazyText keyBuilder  )-    let valueText = Text.toStrict (Builder.toLazyText valueBuilder)+    TextLit (Chunks [] keyText  ) <- Data.HashMap.Strict.InsOrd.lookup "header" m+    TextLit (Chunks [] valueText) <- Data.HashMap.Strict.InsOrd.lookup "value"  m     let keyBytes   = Data.Text.Encoding.encodeUtf8 keyText     let valueBytes = Data.Text.Encoding.encodeUtf8 valueText     return (Data.CaseInsensitive.mk keyBytes, valueBytes)@@ -450,38 +404,6 @@     empty  -{-| This exception indicates that there was an internal error in Dhall's-    import-related logic-    the `expected` type then the `extract` function must succeed.  If not, then-    this exception is thrown--    This exception indicates that an invalid `Type` was provided to the `input`-    function--}-data InternalError = InternalError deriving (Typeable)--_ERROR :: String-_ERROR = "\ESC[1;31mError\ESC[0m"--instance Show InternalError where-    show InternalError = unlines-        [ _ERROR <> ": Compiler bug                                                        "-        , "                                                                                "-        , "Explanation: This error message means that there is a bug in the Dhall compiler."-        , "You didn't do anything wrong, but if you would like to see this problem fixed   "-        , "then you should report the bug at:                                              "-        , "                                                                                "-        , "https://github.com/dhall-lang/dhall-haskell/issues                              "-        , "                                                                                "-        , "Please include the following text in your bug report:                           "-        , "                                                                                "-        , "```                                                                             "-        , "Header extraction failed even though the header type-checked                    "-        , "```                                                                             "-        ]--instance Exception InternalError- -- | Exception thrown when an integrity check fails data HashMismatch = HashMismatch     { expectedHash :: Crypto.Hash.Digest SHA256@@ -519,10 +441,6 @@                 Absolute -> do                     return "/" -                Parent -> do-                    pwd <- System.Directory.getCurrentDirectory-                    return (FilePath.takeDirectory pwd)-                 Here -> do                     System.Directory.getCurrentDirectory @@ -536,26 +454,25 @@              if exists                 then return ()-                else throwIO (MissingFile path)+                else throwMissingImport (MissingFile path) -            text <- Data.Text.Lazy.IO.readFile path+            text <- Data.Text.IO.readFile path              return (path, text)          URL prefix file suffix maybeHeaders -> do-            m <- needManager--            let fileText = Builder.toLazyText (build file)+            let fileText = Dhall.Pretty.Internal.prettyToStrictText file             let url      = Text.unpack (prefix <> fileText <> suffix) -            request <- liftIO (HTTP.parseUrlThrow url)--            requestWithHeaders <- case maybeHeaders of-                Nothing           -> return request+            mheaders <- case maybeHeaders of+                Nothing            -> return Nothing                 Just importHashed_ -> do-                    expr <- loadStaticIO Dhall.Context.empty-                                         (const Nothing)-                                         (Import importHashed_ Code)+                    expr <- loadStaticWith+                        exprFromImport+                        Dhall.Context.empty+                        (const Nothing)+                        (Embed (Import importHashed_ Code))+                     let expected :: Expr Src X                         expected =                             App List@@ -564,10 +481,7 @@                                         [("header", Text), ("value", Text)]                                     )                                 )-                    let suffix_ =-                            ( Builder.toLazyText-                            . build-                            ) expected+                    let suffix_ = Dhall.Pretty.Internal.prettyToStrictText expected                     let annot = case expr of                             Note (Src begin end bytes) _ ->                                 Note (Src begin end bytes') (Annot expr expected)@@ -582,32 +496,27 @@                      let expr' = Dhall.Core.normalize expr -                    headers <- case toHeaders expr' of+                    case toHeaders expr' of                         Just headers -> do-                            return headers+                            return (Just headers)                         Nothing      -> do                             liftIO (throwIO InternalError) -                    let requestWithHeaders = request-                            { HTTP.requestHeaders = headers-                            }--                    return requestWithHeaders--            response <- liftIO (HTTP.httpLbs requestWithHeaders m)--            let bytes = HTTP.responseBody response--            case Data.Text.Lazy.Encoding.decodeUtf8' bytes of-                Left  err  -> liftIO (throwIO err)-                Right text -> return (url, text)+#ifdef MIN_VERSION_http_client+            fetchFromHttpUrl url mheaders+#else+            liftIO (throwIO (CannotImportHTTPURL url mheaders))+#endif          Env env -> liftIO $ do             x <- System.Environment.lookupEnv (Text.unpack env)             case x of                 Just string -> return (Text.unpack env, Text.pack string)-                Nothing     -> throwIO (MissingEnvironmentVariable env)+                Nothing     -> throwMissingImport (MissingEnvironmentVariable env) +        Missing -> liftIO $ do+            throwM (MissingImports [])+     case importMode of         Code -> do             let parser = unParser $ do@@ -623,29 +532,7 @@                     return expr          RawText -> do-            return (TextLit (Chunks [] (build text)))--{-| Load an `Import` as a \"dynamic\" expression (without resolving any imports)--}-loadDynamic-    :: forall m . MonadCatch m-    => (Import -> StateT Status m (Expr Src Import))-    -> Import-    -> StateT Status m (Expr Src Import)-loadDynamic from_import import_ = do-    imports <- zoom stack State.get--    let handler :: SomeException -> StateT Status m (Expr Src Import)-        handler e = throwM (Imported (import_:imports) e)--    from_import (canonicalizeImport (import_:imports)) `catch` handler--loadStaticIO-    :: Dhall.Context.Context (Expr Src X)-    -> Dhall.Core.Normalizer X-    -> Import-    -> StateT Status IO (Expr Src X)-loadStaticIO = loadStaticWith exprFromImport+            return (TextLit (Chunks [] text))  -- | Resolve all imports within an expression using a custom typing context and -- `Import`-resolving callback in arbitrary `MonadCatch` monad.@@ -656,7 +543,8 @@     -> Dhall.Core.Normalizer X     -> Expr Src Import     -> m (Expr Src X)-loadWith from_import ctx n = evalStatus (loadStaticWith from_import ctx n)+loadWith from_import ctx n expr =+    State.evalStateT (loadStaticWith from_import ctx n expr) emptyStatus  -- | Resolve all imports within an expression using a custom typing context. --@@ -666,48 +554,78 @@     -> Dhall.Core.Normalizer X     -> Expr Src Import     -> IO (Expr Src X)-loadWithContext ctx n = evalStatus (loadStaticIO ctx n)+loadWithContext ctx n expr =+    State.evalStateT (loadStaticWith exprFromImport ctx n expr) emptyStatus +-- | This loads a \"static\" expression (i.e. an expression free of imports) loadStaticWith     :: MonadCatch m     => (Import -> StateT Status m (Expr Src Import))     -> Dhall.Context.Context (Expr Src X)     -> Dhall.Core.Normalizer X-    -> Import+    -> Expr Src Import     -> StateT Status m (Expr Src X)-loadStaticWith from_import ctx n import_ = do+loadStaticWith from_import ctx n expr₀ = case expr₀ of+  Embed import_ -> do     imports <- zoom stack State.get -    let local (Import (ImportHashed _ (URL   {})) _) = False-        local (Import (ImportHashed _ (Local {})) _) = True-        local (Import (ImportHashed _ (Env   {})) _) = True+    let local (Import (ImportHashed _ (URL     {})) _) = False+        local (Import (ImportHashed _ (Local   {})) _) = True+        local (Import (ImportHashed _ (Env     {})) _) = True+        local (Import (ImportHashed _ (Missing {})) _) = True      let parent = canonicalizeImport imports     let here   = canonicalizeImport (import_:imports)      if local here && not (local parent)-        then throwM (Imported imports (ReferentiallyOpaque import_))+        then throwMissingImport (Imported imports (ReferentiallyOpaque import_))         else return ()      expr <- if here `elem` canonicalizeAll imports-        then throwM (Imported imports (Cycle import_))+        then throwMissingImport (Imported imports (Cycle import_))         else do             m <- zoom cache State.get             case Map.lookup here m of                 Just expr -> return expr                 Nothing   -> do-                    expr'  <- loadDynamic from_import import_-                    expr'' <- case traverse (\_ -> Nothing) expr' of-                        -- No imports left-                        Just expr -> return expr-                        -- Some imports left, so recurse-                        Nothing   -> do-                            let imports' = import_:imports-                            zoom stack (State.put imports')-                            expr'' <- fmap join (traverse (loadStaticWith from_import ctx n)-                                                           expr')-                            zoom stack (State.put imports)-                            return expr''+                    -- Here we have to match and unwrap the @MissingImports@+                    -- in a separate handler, otherwise we'd have it wrapped+                    -- in another @Imported@ when parsing a @missing@, because+                    -- we are representing it with an empty exception list+                    -- (which would not be empty if this would happen).+                    -- TODO: restructure the Exception hierarchy to prevent+                    -- this nesting from happening in the first place.+                    let handler₀+                            :: (MonadCatch m)+                            => MissingImports+                            -> StateT Status m (Expr Src Import)+                        handler₀ e@(MissingImports []) = throwM e+                        handler₀ (MissingImports [e]) =+                          throwMissingImport (Imported (import_:imports) e)+                        handler₀ (MissingImports es) = throwM+                          (MissingImports+                           (fmap+                             (\e -> (toException (Imported (import_:imports) e)))+                             es))+                        handler₁+                            :: (MonadCatch m)+                            => SomeException+                            -> StateT Status m (Expr Src Import)+                        handler₁ e =+                          throwMissingImport (Imported (import_:imports) e)++                    -- This loads a \"dynamic\" expression (i.e. an expression+                    -- that might still contain imports)+                    let loadDynamic =+                            from_import (canonicalizeImport (import_:imports))++                    expr' <- loadDynamic `catches` [ Handler handler₀, Handler handler₁ ]++                    let imports' = import_:imports+                    zoom stack (State.put imports')+                    expr'' <- loadStaticWith from_import ctx n expr'+                    zoom stack (State.put imports)+                     -- Type-check expressions here for three separate reasons:                     --                     --  * to verify that they are closed@@ -731,14 +649,80 @@             let actualHash = hashExpression expr             if expectedHash == actualHash                 then return ()-                else throwM (Imported (import_:imports) (HashMismatch {..}))+                else throwMissingImport (Imported (import_:imports) (HashMismatch {..}))      return expr+  ImportAlt a b -> loop a `catch` handler₀+    where+      handler₀ (MissingImports es₀) =+        loop b `catch` handler₁+        where+          handler₁ (MissingImports es₁) =+            throwM (MissingImports (es₀ ++ es₁))+  Const a              -> pure (Const a)+  Var a                -> pure (Var a)+  Lam a b c            -> Lam <$> pure a <*> loop b <*> loop c+  Pi a b c             -> Pi <$> pure a <*> loop b <*> loop c+  App a b              -> App <$> loop a <*> loop b+  Let a b c d          -> Let <$> pure a <*> mapM loop b <*> loop c <*> loop d+  Annot a b            -> Annot <$> loop a <*> loop b+  Bool                 -> pure Bool+  BoolLit a            -> pure (BoolLit a)+  BoolAnd a b          -> BoolAnd <$> loop a <*> loop b+  BoolOr a b           -> BoolOr <$> loop a <*> loop b+  BoolEQ a b           -> BoolEQ <$> loop a <*> loop b+  BoolNE a b           -> BoolNE <$> loop a <*> loop b+  BoolIf a b c         -> BoolIf <$> loop a <*> loop b <*> loop c+  Natural              -> pure Natural+  NaturalLit a         -> pure (NaturalLit a)+  NaturalFold          -> pure NaturalFold+  NaturalBuild         -> pure NaturalBuild+  NaturalIsZero        -> pure NaturalIsZero+  NaturalEven          -> pure NaturalEven+  NaturalOdd           -> pure NaturalOdd+  NaturalToInteger     -> pure NaturalToInteger+  NaturalShow          -> pure NaturalShow+  NaturalPlus a b      -> NaturalPlus <$> loop a <*> loop b+  NaturalTimes a b     -> NaturalTimes <$> loop a <*> loop b+  Integer              -> pure Integer+  IntegerLit a         -> pure (IntegerLit a)+  IntegerShow          -> pure IntegerShow+  IntegerToDouble      -> pure IntegerToDouble+  Double               -> pure Double+  DoubleLit a          -> pure (DoubleLit a)+  DoubleShow           -> pure DoubleShow+  Text                 -> pure Text+  TextLit (Chunks a b) -> fmap TextLit (Chunks <$> mapM (mapM loop) a <*> pure b)+  TextAppend a b       -> TextAppend <$> loop a <*> loop b+  List                 -> pure List+  ListLit a b          -> ListLit <$> mapM loop a <*> mapM loop b+  ListAppend a b       -> ListAppend <$> loop a <*> loop b+  ListBuild            -> pure ListBuild+  ListFold             -> pure ListFold+  ListLength           -> pure ListLength+  ListHead             -> pure ListHead+  ListLast             -> pure ListLast+  ListIndexed          -> pure ListIndexed+  ListReverse          -> pure ListReverse+  Optional             -> pure Optional+  OptionalLit a b      -> OptionalLit <$> loop a <*> mapM loop b+  OptionalFold         -> pure OptionalFold+  OptionalBuild        -> pure OptionalBuild+  Record a             -> Record <$> mapM loop a+  RecordLit a          -> RecordLit <$> mapM loop a+  Union a              -> Union <$> mapM loop a+  UnionLit a b c       -> UnionLit <$> pure a <*> loop b <*> mapM loop c+  Combine a b          -> Combine <$> loop a <*> loop b+  CombineTypes a b     -> CombineTypes <$> loop a <*> loop b+  Prefer a b           -> Prefer <$> loop a <*> loop b+  Merge a b c          -> Merge <$> loop a <*> loop b <*> mapM loop c+  Constructors a       -> Constructors <$> loop a+  Field a b            -> Field <$> loop a <*> pure b+  Project a b          -> Project <$> loop a <*> pure b+  Note a b             -> Note <$> pure a <*> loop b+  where+    loop = loadStaticWith from_import ctx n -evalStatus-    :: (Traversable f, Monad m, Monad f)-    => (a -> StateT Status m (f b)) -> f a -> m (f b)-evalStatus cb expr = State.evalStateT (fmap join (traverse cb expr)) emptyStatus  -- | Resolve all imports within an expression load :: Expr Src Import -> IO (Expr Src X)@@ -746,10 +730,10 @@  -- | Hash a fully resolved expression hashExpression :: Expr s X -> (Crypto.Hash.Digest SHA256)-hashExpression expr = Crypto.Hash.hashlazy actualBytes+hashExpression expr = Crypto.Hash.hash actualBytes   where     text = Dhall.Core.pretty (Dhall.Core.normalize expr)-    actualBytes = Data.Text.Lazy.Encoding.encodeUtf8 text+    actualBytes = Data.Text.Encoding.encodeUtf8 text  {-| Convenience utility to hash a fully resolved expression and return the     base-16 encoded hash with the @sha256:@ prefix
+ src/Dhall/Import/HTTP.hs view
@@ -0,0 +1,117 @@+{-# LANGUAGE CPP                 #-}+{-# LANGUAGE OverloadedStrings   #-}+{-# LANGUAGE RecordWildCards     #-}++module Dhall.Import.HTTP where++import Control.Exception (throwIO)+import Control.Monad (join)+import Control.Monad.IO.Class (MonadIO(..))+import Control.Monad.Trans.State.Strict (StateT)+import Data.ByteString (ByteString)+import Data.CaseInsensitive (CI)+import Data.Dynamic (fromDynamic, toDyn)+import Data.Semigroup ((<>))+import Lens.Family.State.Strict (zoom)++import qualified Control.Monad.Trans.State.Strict        as State+import qualified Data.Text                               as Text+import qualified Data.Text.Lazy+import qualified Data.Text.Lazy.Encoding++import Dhall.Import.Types++#if MIN_VERSION_http_client(0,5,0)+import Network.HTTP.Client+    (HttpException(..), HttpExceptionContent(..), Manager)+#else+import Network.HTTP.Client (HttpException(..), Manager)+#endif++import qualified Network.HTTP.Client                     as HTTP+import qualified Network.HTTP.Client.TLS                 as HTTP++mkPrettyHttpException :: HttpException -> PrettyHttpException+mkPrettyHttpException ex =+    PrettyHttpException (renderPrettyHttpException ex) (toDyn ex)++renderPrettyHttpException :: HttpException -> String+#if MIN_VERSION_http_client(0,5,0)+renderPrettyHttpException (InvalidUrlException _ r) =+  "\n"+  <>  "\ESC[1;31mError\ESC[0m: Invalid URL\n"+  <>  "\n"+  <>  "↳ " <> show r+renderPrettyHttpException (HttpExceptionRequest _ e) =+  case e of+    ConnectionFailure e' ->+      "\n"+      <>  "\ESC[1;31mError\ESC[0m: Wrong host\n"+      <>  "\n"+      <>  "↳ " <> show e'+    InvalidDestinationHost host ->+      "\n"+      <>  "\ESC[1;31mError\ESC[0m: Invalid host name\n"+      <>  "\n"+      <>  "↳ " <> show host+    ResponseTimeout ->+      "\ESC[1;31mError\ESC[0m: The host took too long to respond\n"+    e' -> "\n" <> show e'+#else+renderPrettyHttpException e = case e of+    FailedConnectionException2 _ _ _ e' ->+            "\n"+        <>  "\ESC[1;31mError\ESC[0m: Wrong host\n"+        <>  "\n"+        <>  "↳ " <> show e'+    InvalidDestinationHost host ->+            "\n"+        <>  "\ESC[1;31mError\ESC[0m: Invalid host name\n"+        <>  "\n"+        <>  "↳ " <> show host+    ResponseTimeout ->+            "\ESC[1;31mError\ESC[0m: The host took too long to respond\n"+    e' ->   "\n"+        <> show e'+#endif++needManager :: StateT Status IO Manager+needManager = do+    x <- zoom manager State.get+    case join (fmap fromDynamic x) of+        Just m  -> return m+        Nothing -> do+            let settings = HTTP.tlsManagerSettings++#ifdef MIN_VERSION_http_client+#if MIN_VERSION_http_client(0,5,0)+                    { HTTP.managerResponseTimeout = HTTP.responseTimeoutMicro (30 * 1000 * 1000) }  -- 30 seconds+#else+                    { HTTP.managerResponseTimeout = Just (30 * 1000 * 1000) }  -- 30 seconds+#endif+#endif+            m <- liftIO (HTTP.newManager settings)+            zoom manager (State.put (Just (toDyn m)))+            return m++fetchFromHttpUrl+    :: String+    -> Maybe [(CI ByteString, ByteString)]+    -> StateT Status IO (String, Text.Text)+fetchFromHttpUrl url mheaders = do+    m <- needManager++    request <- liftIO (HTTP.parseUrlThrow url)++    let requestWithHeaders =+            case mheaders of+              Nothing      -> request+              Just headers -> request { HTTP.requestHeaders = headers }++    response <- liftIO (HTTP.httpLbs requestWithHeaders m)++    let bytes = HTTP.responseBody response++    case Data.Text.Lazy.Encoding.decodeUtf8' bytes of+        Left  err  -> liftIO (throwIO err)+        Right text -> return (url, Data.Text.Lazy.toStrict text)
+ src/Dhall/Import/Types.hs view
@@ -0,0 +1,89 @@+{-# OPTIONS_GHC -Wall #-}++module Dhall.Import.Types where++import Control.Exception (Exception)+import Data.Dynamic+import Data.Map (Map)+import Data.Semigroup ((<>))+import Lens.Family (LensLike')++import qualified Data.Map as Map++import Dhall.Core (Import, Expr)+import Dhall.Parser (Src)+import Dhall.TypeCheck (X)+++-- | State threaded throughout the import process+data Status = Status+    { _stack   :: [Import]+    -- ^ Stack of `Import`s that we've imported along the way to get to the+    -- current point+    , _cache   :: Map Import (Expr Src X)+    -- ^ Cache of imported expressions in order to avoid importing the same+    --   expression twice with different values+    , _manager :: Maybe Dynamic+    -- ^ Cache for the HTTP `Manager` so that we only acquire it once+    }++-- | Default starting `Status`+emptyStatus :: Status+emptyStatus = Status [] Map.empty Nothing++stack :: Functor f => LensLike' f Status [Import]+stack k s = fmap (\x -> s { _stack = x }) (k (_stack s))++cache :: Functor f => LensLike' f Status (Map Import (Expr Src X))+cache k s = fmap (\x -> s { _cache = x }) (k (_cache s))++manager :: Functor f => LensLike' f Status (Maybe Dynamic)+manager k s = fmap (\x -> s { _manager = x }) (k (_manager s))++++{-| This exception indicates that there was an internal error in Dhall's+    import-related logic+    the `expected` type then the `extract` function must succeed.  If not, then+    this exception is thrown++    This exception indicates that an invalid `Type` was provided to the `input`+    function+-}+data InternalError = InternalError deriving (Typeable)+++instance Show InternalError where+    show InternalError = unlines+        [ _ERROR <> ": Compiler bug                                                        "+        , "                                                                                "+        , "Explanation: This error message means that there is a bug in the Dhall compiler."+        , "You didn't do anything wrong, but if you would like to see this problem fixed   "+        , "then you should report the bug at:                                              "+        , "                                                                                "+        , "https://github.com/dhall-lang/dhall-haskell/issues                              "+        , "                                                                                "+        , "Please include the following text in your bug report:                           "+        , "                                                                                "+        , "```                                                                             "+        , "Header extraction failed even though the header type-checked                    "+        , "```                                                                             "+        ]+      where+        _ERROR :: String+        _ERROR = "\ESC[1;31mError\ESC[0m"++instance Exception InternalError++-- | Wrapper around `HttpException`s with a prettier `Show` instance.+--+-- In order to keep the library API constant even when the @with-http@ Cabal+-- flag is disabled the pretty error message is pre-rendered and the real+-- 'HttpExcepion' is stored in a 'Dynamic'+data PrettyHttpException = PrettyHttpException String Dynamic+    deriving (Typeable)++instance Exception PrettyHttpException++instance Show PrettyHttpException where+  show (PrettyHttpException msg _) = msg
+ src/Dhall/Lint.hs view
@@ -0,0 +1,222 @@+module Dhall.Lint+    ( -- * Lint+      lint+    ) where++import Dhall.Core (Chunks(..), Expr(..), Import, Var(..))+import Dhall.TypeCheck (X(..))++import qualified Dhall.Core++lint :: Expr s Import -> Expr t Import+lint expression = loop (Dhall.Core.denote expression)+  where+    loop (Const a) =+        Const a+    loop (Var a) =+        Var a+    loop (Lam a b c) = Lam a b' c'+      where+        b' = loop b+        c' = loop c+    loop (Pi a b c) = Pi a b' c'+      where+        b' = loop b+        c' = loop c+    loop (App a b) = App a' b'+      where+        a' = loop a+        b' = loop b+    loop (Let a b c d)+        | not (V a 0 `Dhall.Core.freeIn` d) =+            loop d+        | otherwise =+            Let a b' c' d'+      where+        b' = fmap loop b+        c' =      loop c+        d' =      loop d+    loop (Annot a b) =+        Annot a' b'+      where+        a' = loop a+        b' = loop b+    loop Bool =+        Bool+    loop (BoolLit a) =+        BoolLit a+    loop (BoolAnd a b) =+        BoolAnd a' b'+      where+        a' = loop a+        b' = loop b+    loop (BoolOr a b) =+        BoolOr a' b'+      where+        a' = loop a+        b' = loop b+    loop (BoolEQ a b) =+        BoolEQ a' b'+      where+        a' = loop a+        b' = loop b+    loop (BoolNE a b) =+        BoolNE a' b'+      where+        a' = loop a+        b' = loop b+    loop (BoolIf a b c) =+        BoolIf a' b' c'+      where+        a' = loop a+        b' = loop b+        c' = loop c+    loop Natural =+        Natural+    loop (NaturalLit a) =+        NaturalLit a+    loop NaturalFold =+        NaturalFold+    loop NaturalBuild =+        NaturalBuild+    loop NaturalIsZero =+        NaturalIsZero+    loop NaturalEven =+        NaturalEven+    loop NaturalOdd =+        NaturalOdd+    loop NaturalToInteger =+        NaturalToInteger+    loop NaturalShow =+        NaturalShow+    loop (NaturalPlus a b) =+        NaturalPlus a' b'+      where+        a' = loop a+        b' = loop b+    loop (NaturalTimes a b) =+        NaturalTimes a' b'+      where+        a' = loop a+        b' = loop b+    loop Integer =+        Integer+    loop (IntegerLit a) =+        IntegerLit a+    loop IntegerShow =+        IntegerShow+    loop IntegerToDouble =+        IntegerToDouble+    loop Double =+        Double+    loop (DoubleLit a) =+        DoubleLit a+    loop DoubleShow =+        DoubleShow+    loop Text =+        Text+    loop (TextLit (Chunks a b)) =+        TextLit (Chunks a' b)+      where+        a' = fmap (fmap loop) a+    loop (TextAppend a b) =+        TextAppend a' b'+      where+        a' = loop a+        b' = loop b+    loop List =+        List+    loop (ListLit a b) =+        ListLit a' b'+      where+        a' = fmap loop a+        b' = fmap loop b+    loop (ListAppend a b) =+        ListAppend a' b'+      where+        a' = loop a+        b' = loop b+    loop ListBuild =+        ListBuild+    loop ListFold =+        ListFold+    loop ListLength =+        ListLength+    loop ListHead =+        ListHead+    loop ListLast =+        ListLast+    loop ListIndexed =+        ListIndexed+    loop ListReverse =+        ListReverse+    loop Optional =+        Optional+    loop (OptionalLit a b) =+        OptionalLit a' b'+      where+        a' =      loop a+        b' = fmap loop b+    loop OptionalFold =+        OptionalFold+    loop OptionalBuild =+        OptionalBuild+    loop (Record a) =+        Record a'+      where+        a' = fmap loop a+    loop (RecordLit a) =+        RecordLit a'+      where+        a' = fmap loop a+    loop (Union a) =+        Union a'+      where+        a' = fmap loop a+    loop (UnionLit a b c) =+        UnionLit a b' c'+      where+        b' =      loop b+        c' = fmap loop c+    loop (Combine a b) =+        Combine a' b'+      where+        a' = loop a+        b' = loop b+    loop (CombineTypes a b) =+        CombineTypes a' b'+      where+        a' = loop a+        b' = loop b+    loop (Prefer a b) =+        Prefer a' b'+      where+        a' = loop a+        b' = loop b+    loop (Merge a b c) =+        Merge a' b' c'+      where+        a' =      loop a+        b' =      loop b+        c' = fmap loop c+    loop (Constructors a) =+        Constructors a'+      where+        a' = loop a+    loop (Field a b) =+        Field a' b+      where+        a' = loop a+    loop (Project a b) =+        Project a' b+      where+        a' = loop a+    loop (Note a _) =+        absurd a+    loop (ImportAlt a b) =+        ImportAlt a' b'+      where+        a' = loop a+        b' = loop b+    loop (Embed a) =+        Embed a
+ src/Dhall/Main.hs view
@@ -0,0 +1,334 @@+{-# LANGUAGE DeriveAnyClass    #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards   #-}++module Dhall.Main+    ( -- Commands+      parseOptions+    , parserInfoOptions+    , command+    , main+    ) where++import Control.Applicative (optional, (<|>))+import Control.Exception (Exception, SomeException)+import Data.Monoid (mempty, (<>))+import Data.Text (Text)+import Data.Text.Prettyprint.Doc (Pretty)+import Data.Version (showVersion)+import Dhall.Core (Expr, Import)+import Dhall.Import (Imported(..), load)+import Dhall.Parser (Src)+import Dhall.Pretty (annToAnsiStyle, prettyExpr)+import Dhall.TypeCheck (DetailedTypeError(..), TypeError, X)+import Options.Applicative (Parser, ParserInfo)+import System.Exit (exitFailure)+import System.IO (Handle)++import qualified Paths_dhall as Meta++import qualified Control.Exception+import qualified Data.Text+import qualified Data.Text.IO+import qualified Data.Text.Prettyprint.Doc                 as Pretty+import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Pretty+import qualified Dhall+import qualified Dhall.Core+import qualified Dhall.Diff+import qualified Dhall.Format+import qualified Dhall.Freeze+import qualified Dhall.Hash+import qualified Dhall.Lint+import qualified Dhall.Parser+import qualified Dhall.Repl+import qualified Dhall.TypeCheck+import qualified Options.Applicative+import qualified System.Console.ANSI+import qualified System.IO++data Options = Options+    { mode    :: Mode+    , explain :: Bool+    , plain   :: Bool+    }++data Mode+    = Default+    | Version+    | Resolve+    | Type+    | Normalize+    | Repl+    | Format (Maybe FilePath)+    | Freeze (Maybe FilePath)+    | Hash+    | Diff Text Text+    | Lint (Maybe FilePath)++parseInplace :: Parser String+parseInplace =+        Options.Applicative.strOption+        (   Options.Applicative.long "inplace"+        <>  Options.Applicative.help "Modify the specified file in-place"+        <>  Options.Applicative.metavar "FILE"+        )++parseOptions :: Parser Options+parseOptions = Options <$> parseMode <*> parseExplain <*> parsePlain+  where+    parseExplain =+        Options.Applicative.switch+            (   Options.Applicative.long "explain"+            <>  Options.Applicative.help "Explain error messages in more detail"+            )++    parsePlain =+        Options.Applicative.switch+            (   Options.Applicative.long "plain"+            <>  Options.Applicative.help "Disable syntax highlighting"+            )+++parseMode :: Parser Mode+parseMode =+        subcommand "version"   "Display version"                 (pure Version)+    <|> subcommand "resolve"   "Resolve an expression's imports" (pure Resolve)+    <|> subcommand "type"      "Infer an expression's type"      (pure Type)+    <|> subcommand "normalize" "Normalize an expression"         (pure Normalize)+    <|> subcommand "repl"      "Interpret expressions in a REPL" (pure Repl)+    <|> subcommand "diff"      "Render the difference between the normal form of two expressions" diffParser+    <|> subcommand "hash"      "Compute semantic hashes for Dhall expressions" (pure Hash)+    <|> subcommand "lint"      "Improve Dhall code"              parseLint+    <|> formatSubcommand+    <|> freezeSubcommand+    <|> pure Default+  where+    subcommand name description modeParser =+        Options.Applicative.subparser+            (   Options.Applicative.command name parserInfo+            <>  Options.Applicative.metavar name+            )+      where+        parserInfo =+            Options.Applicative.info parser+                (   Options.Applicative.fullDesc+                <>  Options.Applicative.progDesc description+                )++        parser =+            Options.Applicative.helper <*> modeParser++    diffParser =+        Diff <$> argument "expr1" <*> argument "expr2"+      where+        argument =+                fmap Data.Text.pack+            .   Options.Applicative.strArgument+            .   Options.Applicative.metavar++    parseLint =+        Lint <$> optional parseInplace++    formatSubcommand =+        Options.Applicative.hsubparser+            (   Options.Applicative.command "format" parserInfo+            <>  Options.Applicative.metavar "format"+            )+      where parserInfo =+                Options.Applicative.info parserWithHelper+                    (   Options.Applicative.fullDesc+                    <>  Options.Applicative.progDesc "Formatter for the Dhall language"+                    )+            parserWithHelper = Options.Applicative.helper <*> parser+            parser = Format <$> optional parseInplace++    freezeSubcommand = subcommand "freeze" "Add hashes to all import statements of an expression" parseFreeze+        where+            parseFreeze = Freeze <$> optional parseInplace++opts :: Pretty.LayoutOptions+opts =+    Pretty.defaultLayoutOptions+        { Pretty.layoutPageWidth = Pretty.AvailablePerLine 80 1.0 }++data ImportResolutionDisabled = ImportResolutionDisabled deriving (Exception)++instance Show ImportResolutionDisabled where+    show _ = "\nImport resolution is disabled"++throws :: Exception e => Either e a -> IO a+throws (Left  e) = Control.Exception.throwIO e+throws (Right a) = return a++getExpression :: IO (Expr Src Import)+getExpression = do+    inText <- Data.Text.IO.getContents++    throws (Dhall.Parser.exprFromText "(stdin)" inText)++assertNoImports :: Expr Src Import -> IO (Expr Src X)+assertNoImports expression =+    throws (traverse (\_ -> Left ImportResolutionDisabled) expression)++parserInfoOptions :: ParserInfo Options+parserInfoOptions =+    Options.Applicative.info+        (Options.Applicative.helper <*> parseOptions)+        (   Options.Applicative.progDesc "Interpreter for the Dhall language"+        <>  Options.Applicative.fullDesc+        )++command :: Options -> IO ()+command (Options {..}) = do+    System.IO.hSetEncoding System.IO.stdin System.IO.utf8++    let handle =+                Control.Exception.handle handler2+            .   Control.Exception.handle handler1+            .   Control.Exception.handle handler0+          where+            handler0 e = do+                let _ = e :: TypeError Src X+                System.IO.hPutStrLn System.IO.stderr ""+                if explain+                    then Control.Exception.throwIO (DetailedTypeError e)+                    else do+                        Data.Text.IO.hPutStrLn System.IO.stderr "\ESC[2mUse \"dhall --explain\" for detailed errors\ESC[0m"+                        Control.Exception.throwIO e++            handler1 (Imported ps e) = do+                let _ = e :: TypeError Src X+                System.IO.hPutStrLn System.IO.stderr ""+                if explain+                    then Control.Exception.throwIO (Imported ps (DetailedTypeError e))+                    else do+                        Data.Text.IO.hPutStrLn System.IO.stderr "\ESC[2mUse \"dhall --explain\" for detailed errors\ESC[0m"+                        Control.Exception.throwIO (Imported ps e)++            handler2 e = do+                let _ = e :: SomeException+                System.IO.hSetEncoding System.IO.stderr System.IO.utf8+                System.IO.hPrint System.IO.stderr e+                System.Exit.exitFailure++    let render :: Pretty a => Handle -> Expr s a -> IO ()+        render h e = do+            let doc = prettyExpr e++            let layoutOptions = opts++            let stream = Pretty.layoutSmart layoutOptions doc++            supportsANSI <- System.Console.ANSI.hSupportsANSI h+            let ansiStream =+                    if supportsANSI && not plain+                    then fmap annToAnsiStyle stream+                    else Pretty.unAnnotateS stream++            Pretty.renderIO h ansiStream+            Data.Text.IO.hPutStrLn h ""++    handle $ case mode of+        Version -> do+            putStrLn (showVersion Meta.version)++        Default -> do+            expression <- getExpression++            resolvedExpression <- load expression++            inferredType <- throws (Dhall.TypeCheck.typeOf resolvedExpression)++            render System.IO.stderr (Dhall.Core.normalize inferredType)++            Data.Text.IO.hPutStrLn System.IO.stderr mempty++            render System.IO.stdout (Dhall.Core.normalize resolvedExpression)++        Resolve -> do+            expression <- getExpression++            resolvedExpression <- load expression++            render System.IO.stdout resolvedExpression++        Normalize -> do+            expression <- getExpression++            resolvedExpression <- assertNoImports expression++            _ <- throws (Dhall.TypeCheck.typeOf resolvedExpression)++            render System.IO.stdout (Dhall.Core.normalize resolvedExpression)++        Type -> do+            expression <- getExpression++            resolvedExpression <- assertNoImports expression++            inferredType <- throws (Dhall.TypeCheck.typeOf resolvedExpression)++            render System.IO.stdout (Dhall.Core.normalize inferredType)++        Repl -> do+            Dhall.Repl.repl explain++        Diff expr1 expr2 -> do+            expression1 <- Dhall.inputExpr expr1++            expression2 <- Dhall.inputExpr expr2++            let diff = Dhall.Diff.diffNormalized expression1 expression2+                prettyDiff = fmap annToAnsiStyle diff++            Pretty.hPutDoc System.IO.stdout prettyDiff++        Format inplace -> do+            Dhall.Format.format inplace++        Freeze inplace -> do+            Dhall.Freeze.freeze inplace++        Hash -> do+            Dhall.Hash.hash ++        Lint inplace -> do+            case inplace of+                Just file -> do+                    text <- Data.Text.IO.readFile file++                    (header, expression) <- throws (Dhall.Parser.exprAndHeaderFromText file text)++                    let lintedExpression = Dhall.Lint.lint expression++                    let doc = Pretty.pretty header <> Pretty.pretty lintedExpression++                    System.IO.withFile file System.IO.WriteMode (\h -> do+                        Pretty.renderIO h (Pretty.layoutSmart opts doc)+                        Data.Text.IO.hPutStrLn h "" )+                Nothing -> do+                    System.IO.hSetEncoding System.IO.stdin System.IO.utf8+                    text <- Data.Text.IO.getContents++                    (header, expression) <- throws (Dhall.Parser.exprAndHeaderFromText "(stdin)" text)++                    let lintedExpression = Dhall.Lint.lint expression++                    let doc = Pretty.pretty header <> prettyExpr lintedExpression++                    supportsANSI <- System.Console.ANSI.hSupportsANSI System.IO.stdout++                    if supportsANSI+                      then+                        Pretty.renderIO+                          System.IO.stdout+                          (fmap annToAnsiStyle (Pretty.layoutSmart opts doc))+                      else+                        Pretty.renderIO+                          System.IO.stdout+                          (Pretty.layoutSmart opts (Pretty.unAnnotate doc))++main :: IO ()+main = do+    options <- Options.Applicative.execParser parserInfoOptions+    command options
src/Dhall/Parser.hs view
@@ -1,1639 +1,83 @@-{-# LANGUAGE CPP                        #-}-{-# LANGUAGE DeriveDataTypeable         #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{-# LANGUAGE OverloadedStrings          #-}-{-# LANGUAGE RecordWildCards            #-}---- | This module contains Dhall's parsing logic--module Dhall.Parser (-    -- * Utilities-      exprFromText-    , exprAndHeaderFromText--    -- * Parsers-    , expr, exprA--    -- * Types-    , Src(..)-    , ParseError(..)-    , Parser(..)-    ) where--import Control.Applicative (Alternative(..), liftA2, optional)-import Control.Exception (Exception)-import Control.Monad (MonadPlus)-import Data.ByteArray.Encoding (Base(..))-import Data.Functor (void)-import Data.HashMap.Strict.InsOrd (InsOrdHashMap)-import Data.Scientific (Scientific)-import Data.Semigroup (Semigroup(..))-import Data.Sequence (ViewL(..))-import Data.Set (Set)-import Data.String (IsString(..))-import Data.Text.Lazy (Text)-import Data.Text.Lazy.Builder (Builder)-import Data.Void (Void)-import Dhall.Core-import Formatting.Buildable (Buildable(..))-import Numeric.Natural (Natural)-import Prelude hiding (const, pi)-import Text.Parser.Combinators (choice, try, (<?>))-import Text.Parser.Token (TokenParsing(..))--import qualified Control.Monad-import qualified Crypto.Hash-import qualified Data.ByteArray.Encoding-import qualified Data.ByteString-import qualified Data.ByteString.Lazy-import qualified Data.Char-import qualified Data.HashMap.Strict.InsOrd-import qualified Data.HashSet-import qualified Data.List-import qualified Data.List.NonEmpty-import qualified Data.Sequence-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 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---- | Source code extract-data Src = Src Text.Megaparsec.SourcePos Text.Megaparsec.SourcePos Text-  deriving (Eq, Show)--instance Buildable Src where-    build (Src begin _ text) =-            build text <> "\n"-        <>  "\n"-        <>  build (Text.Megaparsec.sourcePosPretty begin)-        <>  "\n"--{-| A `Parser` that is almost identical to-    @"Text.Megaparsec".`Text.Megaparsec.Parsec`@ except treating Haskell-style-    comments as whitespace--}-newtype Parser a = Parser { unParser :: Text.Megaparsec.Parsec Void Text a }-    deriving-    (   Functor-    ,   Applicative-    ,   Monad-    ,   Alternative-    ,   MonadPlus-    ,   Text.Megaparsec.MonadParsec Void Text-    )--instance Data.Semigroup.Semigroup a => Data.Semigroup.Semigroup (Parser a) where-    (<>) = liftA2 (<>)--instance (Data.Semigroup.Semigroup a, Monoid a) => Monoid (Parser a) where-    mempty = pure mempty--#if !(MIN_VERSION_base(4,11,0))-    mappend = (<>)-#endif--instance IsString a => IsString (Parser a) where-    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 (Text.Megaparsec.skipSome (Text.Megaparsec.Char.satisfy Data.Char.isSpace)))-            Text.Parser.Token.Style.haskellCommentStyle--    highlight _ = id--    semi = token (Text.Megaparsec.Char.char ';' <?> ";")--noted :: Parser (Expr Src a) -> Parser (Expr Src a)-noted parser = do-    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)--range :: (Semigroup a, Monoid a) => Int -> Int -> Parser a -> Parser a-range minimumBound maximumMatches parser =-    count minimumBound parser <> loop maximumMatches-  where-    loop 0 = mempty-    loop n = (parser <> loop (n - 1)) <|> mempty--option :: (Alternative f, Monoid a) => f a -> f a-option p = p <|> pure mempty--star :: (Alternative f, Monoid a) => f a -> f a-star p = plus p <|> pure mempty--plus :: (Alternative f, Monoid a) => f a -> f a-plus p = mappend <$> p <*> star p--satisfy :: (Char -> Bool) -> Parser Builder-satisfy predicate =-    fmap Data.Text.Lazy.Builder.singleton (Text.Parser.Char.satisfy predicate)--blockComment :: Parser ()-blockComment = do-    _ <- Text.Parser.Char.text "{-"-    blockCommentContinue--blockCommentChunk :: Parser ()-blockCommentChunk =-    choice-        [ blockComment  -- Nested block comment-        , character-        , endOfLine-        ]-  where-    character = void (Text.Parser.Char.satisfy predicate)-      where-        predicate c = '\x20' <= c && c <= '\x10FFFF' || c == '\n' || c == '\t'--    endOfLine = void (Text.Parser.Char.text "\r\n")--blockCommentContinue :: Parser ()-blockCommentContinue = endOfComment <|> continue-  where-    endOfComment = void (Text.Parser.Char.text "-}")--    continue = do-        blockCommentChunk-        blockCommentContinue--lineComment :: Parser ()-lineComment = do-    _ <- Text.Parser.Char.text "--"-    Text.Parser.Combinators.skipMany notEndOfLine-    endOfLine-    return ()-  where-    endOfLine =-            void (Text.Parser.Char.char '\n'  )-        <|> void (Text.Parser.Char.text "\r\n")--    notEndOfLine = void (Text.Parser.Char.satisfy predicate)-      where-        predicate c = ('\x20' <= c && c <= '\x10FFFF') || c == '\t'---whitespaceChunk :: Parser ()-whitespaceChunk =-    choice-        [ void (Text.Parser.Char.satisfy predicate)-        , void (Text.Parser.Char.text "\r\n")-        , lineComment-        , blockComment-        ] <?> "whitespace"-  where-    predicate c = c == ' ' || c == '\t' || c == '\n'--whitespace :: Parser ()-whitespace = Text.Parser.Combinators.skipMany whitespaceChunk--alpha :: Char -> Bool-alpha c = ('\x41' <= c && c <= '\x5A') || ('\x61' <= c && c <= '\x7A')--digit :: Char -> Bool-digit c = '\x30' <= c && c <= '\x39'--hexdig :: Char -> Bool-hexdig c =-        ('0' <= c && c <= '9')-    ||  ('A' <= c && c <= 'F')-    ||  ('a' <= c && c <= 'f')--hexNumber :: Parser Int-hexNumber = choice [ hexDigit, hexUpper, hexLower ]-  where-    hexDigit = do-        c <- Text.Parser.Char.satisfy predicate-        return (Data.Char.ord c - Data.Char.ord '0')-      where-        predicate c = '0' <= c && c <= '9'--    hexUpper = do-        c <- Text.Parser.Char.satisfy predicate-        return (10 + Data.Char.ord c - Data.Char.ord 'A')-      where-        predicate c = 'A' <= c && c <= 'F'--    hexLower = do-        c <- Text.Parser.Char.satisfy predicate-        return (10 + Data.Char.ord c - Data.Char.ord 'a')-      where-        predicate c = 'a' <= c && c <= 'f'--simpleLabel :: Parser Text-simpleLabel = try (do-    c  <- Text.Parser.Char.satisfy headCharacter-    cs <- many (Text.Parser.Char.satisfy tailCharacter)-    let string = c:cs-    let text = Data.Text.Lazy.pack string-    Control.Monad.guard (not (Data.HashSet.member text reservedIdentifiers))-    return text )-  where-    headCharacter c = alpha c || c == '_'--    tailCharacter c = alpha c || digit c || c == '_' || c == '-' || c == '/'--backtickLabel :: Parser Text-backtickLabel = do-    _ <- Text.Parser.Char.char '`'-    t <- some (Text.Parser.Char.satisfy predicate)-    _ <- Text.Parser.Char.char '`'-    return (Data.Text.Lazy.pack t)-  where-    predicate c = alpha c || digit c || elem c ("-/_:." :: String)--label :: Parser Text-label = (do-    t <- backtickLabel <|> simpleLabel-    whitespace-    return t ) <?> "label"--noDuplicates :: Ord a => [a] -> Parser (Set a)-noDuplicates = go Data.Set.empty-  where-    go found    []  = return found-    go found (x:xs) =-        if Data.Set.member x found-        then fail "Duplicate key"-        else go (Data.Set.insert x found) xs--labels :: Parser (Set Text)-labels = do-    _openBrace-    xs <- nonEmptyLabels <|> emptyLabels-    _closeBrace-    return xs-  where-    emptyLabels = pure Data.Set.empty--    nonEmptyLabels = do-        x  <- label-        xs <- many (do _ <- _comma; label)-        noDuplicates (x : xs)--doubleQuotedChunk :: Parser a -> Parser (Chunks Src a)-doubleQuotedChunk embedded =-    choice-        [ interpolation-        , unescapedCharacter-        , escapedCharacter-        ]-  where-    interpolation = do-        _ <- Text.Parser.Char.text "${"-        e <- completeExpression embedded-        _ <- Text.Parser.Char.char '}'-        return (Chunks [(mempty, e)] mempty)--    unescapedCharacter = do-        c <- Text.Parser.Char.satisfy predicate-        return (Chunks [] (Data.Text.Lazy.Builder.singleton c))-      where-        predicate c =-                ('\x20' <= c && c <= '\x21'    )-            ||  ('\x23' <= c && c <= '\x5B'    )-            ||  ('\x5D' <= c && c <= '\x10FFFF')--    escapedCharacter = do-        _ <- Text.Parser.Char.char '\\'-        c <- choice-            [ quotationMark-            , dollarSign-            , backSlash-            , forwardSlash-            , backSpace-            , formFeed-            , lineFeed-            , carriageReturn-            , tab-            , unicode-            ]-        return (Chunks [] (Data.Text.Lazy.Builder.singleton c))-      where-        quotationMark = Text.Parser.Char.char '"'--        dollarSign = Text.Parser.Char.char '$'--        backSlash = Text.Parser.Char.char '\\'--        forwardSlash = Text.Parser.Char.char '/'--        backSpace = do _ <- Text.Parser.Char.char 'b'; return '\b'--        formFeed = do _ <- Text.Parser.Char.char 'f'; return '\f'--        lineFeed = do _ <- Text.Parser.Char.char 'n'; return '\n'--        carriageReturn = do _ <- Text.Parser.Char.char 'r'; return '\r'--        tab = do _ <- Text.Parser.Char.char 't'; return '\t'--        unicode = do-            _  <- Text.Parser.Char.char 'u';-            n0 <- hexNumber-            n1 <- hexNumber-            n2 <- hexNumber-            n3 <- hexNumber-            let n = ((n0 * 16 + n1) * 16 + n2) * 16 + n3-            return (Data.Char.chr n)--doubleQuotedLiteral :: Parser a -> Parser (Chunks Src a)-doubleQuotedLiteral embedded = do-    _      <- Text.Parser.Char.char '"'-    chunks <- many (doubleQuotedChunk embedded)-    _      <- Text.Parser.Char.char '"'-    return (mconcat chunks)---- | Similar to `Dhall.Core.buildChunks` except that this doesn't bother to--- render interpolated expressions to avoid a `Buildable a` constraint.  The--- interpolated contents are not necessary for computing how much to dedent a--- multi-line string------ This also doesn't include the surrounding quotes since they would interfere--- with the whitespace detection-buildChunks :: Chunks s a -> Builder-buildChunks (Chunks a b) = foldMap buildChunk a <> escapeText b-  where-    buildChunk (c, _) = escapeText c <> "${x}"--dedent :: Chunks Src a -> Chunks Src a-dedent chunks0 = process chunks0-  where-    builder0 = buildChunks chunks0--    text0 = Data.Text.Lazy.Builder.toLazyText builder0--    lines0 = Data.Text.Lazy.lines text0--    isEmpty = Data.Text.Lazy.all Data.Char.isSpace--    nonEmptyLines = filter (not . isEmpty) lines0--    indentLength line =-        Data.Text.Lazy.length (Data.Text.Lazy.takeWhile Data.Char.isSpace line)--    shortestIndent = case nonEmptyLines of-        [] -> 0-        _  -> minimum (map indentLength nonEmptyLines)--    -- The purpose of this complicated `trimBegin`/`trimContinue` is to ensure-    -- that we strip leading whitespace without stripping whitespace after-    -- variable interpolation--    -- This is the trim function we use up until the first variable-    -- interpolation, dedenting all lines-    trimBegin =-          build-        . Data.Text.Lazy.intercalate "\n"-        . map (Data.Text.Lazy.drop shortestIndent)-        . Data.Text.Lazy.splitOn "\n"-        . Data.Text.Lazy.Builder.toLazyText--    -- This is the trim function we use after each variable interpolation-    -- where we indent each line except the first line (since it's not a true-    -- beginning of a line)-    trimContinue builder = build (Data.Text.Lazy.intercalate "\n" lines_)-      where-        text = Data.Text.Lazy.Builder.toLazyText builder--        lines_ = case Data.Text.Lazy.splitOn "\n" text of-            []   -> []-            l:ls -> l:map (Data.Text.Lazy.drop shortestIndent) ls--    -- This is the loop that drives whether or not to use `trimBegin` or-    -- `trimContinue`.  We call this function with `trimBegin`, but after the-    -- first interpolation we switch permanently to `trimContinue`-    process (Chunks ((x0, y0):xys) z) =-        Chunks ((trimBegin x0, y0):xys') (trimContinue z)-      where-        xys' = [ (trimContinue x, y) | (x, y) <- xys ]-    process (Chunks [] z) =-        Chunks [] (trimBegin z)--singleQuoteContinue :: Parser a -> Parser (Chunks Src a)-singleQuoteContinue embedded =-    choice-        [ escapeSingleQuotes-        , interpolation-        , escapeInterpolation-        , endLiteral-        , unescapedCharacter-        , tab-        , endOfLine-        ]-  where-        escapeSingleQuotes = do-            _ <- "'''" :: Parser Builder-            b <- singleQuoteContinue embedded-            return ("''" <> b)--        interpolation = do-            _ <- Text.Parser.Char.text "${"-            a <- completeExpression embedded-            _ <- Text.Parser.Char.char '}'-            b <- singleQuoteContinue embedded-            return (Chunks [(mempty, a)] mempty <> b)--        escapeInterpolation = do-            _ <- Text.Parser.Char.text "''${"-            b <- singleQuoteContinue embedded-            return ("${" <> b)--        endLiteral = do-            _ <- Text.Parser.Char.text "''"-            return mempty--        unescapedCharacter = do-            a <- satisfy predicate-            b <- singleQuoteContinue embedded-            return (Chunks [] a <> b)-          where-            predicate c = '\x20' <= c && c <= '\x10FFFF'--        endOfLine = do-            a <- "\n" <|> "\r\n"-            b <- singleQuoteContinue embedded-            return (Chunks [] a <> b)--        tab = do-            _ <- Text.Parser.Char.char '\t'-            b <- singleQuoteContinue embedded-            return ("\t" <> b)--singleQuoteLiteral :: Parser a -> Parser (Chunks Src a)-singleQuoteLiteral embedded = do-    _ <- Text.Parser.Char.text "''"--    -- This is technically not in the grammar, but it's still equivalent to the-    -- original grammar and an easy way to discard the first character if it's-    -- a newline-    _ <- optional endOfLine--    a <- singleQuoteContinue embedded--    return (dedent a)-  where-    endOfLine =-            void (Text.Parser.Char.char '\n'  )-        <|> void (Text.Parser.Char.text "\r\n")--textLiteral :: Parser a -> Parser (Expr Src a)-textLiteral embedded = (do-    literal <- doubleQuotedLiteral embedded <|> singleQuoteLiteral embedded-    whitespace-    return (TextLit literal) ) <?> "text literal"--reserved :: Data.Text.Text -> Parser ()-reserved x = do _ <- Text.Parser.Char.text x; whitespace--_if :: Parser ()-_if = reserved "if"--_then :: Parser ()-_then = reserved "then"--_else :: Parser ()-_else = reserved "else"--_let :: Parser ()-_let = reserved "let"--_in :: Parser ()-_in = reserved "in"--_as :: Parser ()-_as = reserved "as"--_using :: Parser ()-_using = reserved "using"--_merge :: Parser ()-_merge = reserved "merge"--_constructors :: Parser ()-_constructors = reserved "constructors"--_NaturalFold :: Parser ()-_NaturalFold = reserved "Natural/fold"--_NaturalBuild :: Parser ()-_NaturalBuild = reserved "Natural/build"--_NaturalIsZero :: Parser ()-_NaturalIsZero = reserved "Natural/isZero"--_NaturalEven :: Parser ()-_NaturalEven = reserved "Natural/even"--_NaturalOdd :: Parser ()-_NaturalOdd = reserved "Natural/odd"--_NaturalToInteger :: Parser ()-_NaturalToInteger = reserved "Natural/toInteger"--_NaturalShow :: Parser ()-_NaturalShow = reserved "Natural/show"--_IntegerShow :: Parser ()-_IntegerShow = reserved "Integer/show"--_DoubleShow :: Parser ()-_DoubleShow = reserved "Double/show"--_ListBuild :: Parser ()-_ListBuild = reserved "List/build"--_ListFold :: Parser ()-_ListFold = reserved "List/fold"--_ListLength :: Parser ()-_ListLength = reserved "List/length"--_ListHead :: Parser ()-_ListHead = reserved "List/head"--_ListLast :: Parser ()-_ListLast = reserved "List/last"--_ListIndexed :: Parser ()-_ListIndexed = reserved "List/indexed"--_ListReverse :: Parser ()-_ListReverse = reserved "List/reverse"--_OptionalFold :: Parser ()-_OptionalFold = reserved "Optional/fold"--_OptionalBuild :: Parser ()-_OptionalBuild = reserved "Optional/build"--_Bool :: Parser ()-_Bool = reserved "Bool"--_Optional :: Parser ()-_Optional = reserved "Optional"--_Natural :: Parser ()-_Natural = reserved "Natural"--_Integer :: Parser ()-_Integer = reserved "Integer"--_Double :: Parser ()-_Double = reserved "Double"--_Text :: Parser ()-_Text = reserved "Text"--_List :: Parser ()-_List = reserved "List"--_True :: Parser ()-_True = reserved "True"--_False :: Parser ()-_False = reserved "False"--_Type :: Parser ()-_Type = reserved "Type"--_Kind :: Parser ()-_Kind = reserved "Kind"--_equal :: Parser ()-_equal = reserved "="--_or :: Parser ()-_or = reserved "||"--_plus :: Parser ()-_plus = reserved "+"--_textAppend :: Parser ()-_textAppend = reserved "++"--_listAppend :: Parser ()-_listAppend = reserved "#"--_and :: Parser ()-_and = reserved "&&"--_times :: Parser ()-_times = reserved "*"--_doubleEqual :: Parser ()-_doubleEqual = reserved "=="--_notEqual :: Parser ()-_notEqual = reserved "!="--_dot :: Parser ()-_dot = reserved "."--_openBrace :: Parser ()-_openBrace = reserved "{"--_closeBrace :: Parser ()-_closeBrace = reserved "}"--_openBracket :: Parser ()-_openBracket = reserved "["--_closeBracket :: Parser ()-_closeBracket = reserved "]"--_openAngle :: Parser ()-_openAngle = reserved "<"--_closeAngle :: Parser ()-_closeAngle = reserved ">"--_bar :: Parser ()-_bar = reserved "|"--_comma :: Parser ()-_comma = reserved ","--_openParens :: Parser ()-_openParens = reserved "("--_closeParens :: Parser ()-_closeParens = reserved ")"--_colon :: Parser ()-_colon = reserved ":"--_at :: Parser ()-_at = reserved "@"--_combine :: Parser ()-_combine = do-    void (Text.Parser.Char.char '∧' <?> "\"∧\"") <|> void (Text.Parser.Char.text "/\\")-    whitespace--_combineTypes :: Parser ()-_combineTypes = do-    void (Text.Parser.Char.char '⩓' <?> "\"⩓\"") <|> void (Text.Parser.Char.text "//\\\\")-    whitespace--_prefer :: Parser ()-_prefer = do-    void (Text.Parser.Char.char '⫽' <?> "\"⫽\"") <|> void (Text.Parser.Char.text "//")-    whitespace--_lambda :: Parser ()-_lambda = do-    _ <- Text.Parser.Char.satisfy predicate-    whitespace-  where-    predicate 'λ'  = True-    predicate '\\' = True-    predicate _    = False--_forall :: Parser ()-_forall = do-    void (Text.Parser.Char.char '∀' <?> "\"∀\"") <|> void (Text.Parser.Char.text "forall")-    whitespace--_arrow :: Parser ()-_arrow = do-    void (Text.Parser.Char.char '→' <?> "\"→\"") <|> void (Text.Parser.Char.text "->")-    whitespace--doubleLiteral :: Parser Scientific-doubleLiteral = (do-    sign <-  fmap (\_ -> negate) (Text.Parser.Char.char '-')-         <|> pure id-    a    <-  Text.Parser.Token.scientific-    return (sign a) ) <?> "double literal"--integerLiteral :: Parser Integer-integerLiteral = (do-    let positive = fmap (\_ -> id    ) (Text.Parser.Char.char '+')-    let negative = fmap (\_ -> negate) (Text.Parser.Char.char '-')-    sign <- positive <|> negative-    a <- Text.Parser.Token.natural-    return (sign a) ) <?> "integer literal"--naturalLiteral :: Parser Natural-naturalLiteral = (do-    a <- Text.Parser.Token.natural-    return (fromIntegral a) ) <?> "natural literal"--identifier :: Parser Var-identifier = do-    x <- label--    let indexed = do-            _ <- Text.Parser.Char.char '@'-            Text.Parser.Token.natural--    n <- indexed <|> pure 0-    return (V x n)--pathCharacter :: Char -> Bool-pathCharacter c =-        ('\x21' <= c && c <= '\x22')-    ||  ('\x24' <= c && c <= '\x27')-    ||  ('\x2A' <= c && c <= '\x2B')-    ||  ('\x2D' <= c && c <= '\x2E')-    ||  ('\x30' <= c && c <= '\x3B')-    ||  c == '\x3D'-    ||  ('\x40' <= c && c <= '\x5A')-    ||  ('\x5E' <= c && c <= '\x7A')-    ||  c == '\x7C'-    ||  c == '\x7E'--pathComponent :: Parser Text-pathComponent = do-    _      <- "/" :: Parser Builder-    string <- some (Text.Parser.Char.satisfy pathCharacter)--    return (Data.Text.Lazy.pack string)--file_ :: Parser File-file_ = do-    path <- Data.List.NonEmpty.some1 pathComponent--    let directory = Directory (reverse (Data.List.NonEmpty.init path))-    let file      = Data.List.NonEmpty.last path--    return (File {..})--localRaw :: Parser ImportType-localRaw =-    choice-        [ parentPath-        , herePath-        , homePath-        , try absolutePath-        ]-  where-    parentPath = do-        _    <- ".." :: Parser Builder-        file <- file_--        return (Local Parent file)--    herePath = do-        _    <- "." :: Parser Builder-        file <- file_--        return (Local Here file)--    homePath = do-        _    <- "~" :: Parser Builder-        file <- file_--        return (Local Home file)--    absolutePath = do-        file <- file_--        return (Local Absolute file)--local :: Parser ImportType-local = do-    a <- localRaw-    whitespace-    return a--scheme :: Parser Builder-scheme = "http" <> option "s"--httpRaw :: Parser (Text, File, Text)-httpRaw = do-    prefix <- scheme <> "://" <> authority-    file   <- file_-    suffix <- option ("?" <> query) <> option ("#" <> fragment)--    let prefixText = Data.Text.Lazy.Builder.toLazyText prefix-    let suffixText = Data.Text.Lazy.Builder.toLazyText suffix--    return (prefixText, file, suffixText)--authority :: Parser Builder-authority = option (try (userinfo <> "@")) <> host <> option (":" <> port)--userinfo :: Parser Builder-userinfo = star (satisfy predicate <|> pctEncoded)-  where-    predicate c = unreserved c || subDelims c || c == ':'--host :: Parser Builder-host = choice [ ipLiteral, ipV4Address, regName ]--port :: Parser Builder-port = star (satisfy digit)--ipLiteral :: Parser Builder-ipLiteral = "[" <> (ipV6Address <|> ipVFuture) <> "]"--ipVFuture :: Parser Builder-ipVFuture = "v" <> plus (satisfy hexdig) <> "." <> plus (satisfy predicate)-  where-    predicate c = unreserved c || subDelims c || c == ':'--ipV6Address :: Parser Builder-ipV6Address =-    choice-        [ try alternative0-        , try alternative1-        , try alternative2-        , try alternative3-        , try alternative4-        , try alternative5-        , try alternative6-        , try alternative7-        ,     alternative8-        ]-  where-    alternative0 = count 6 (h16 <> ":") <> ls32--    alternative1 = "::" <> count 5 (h16 <> ":") <> ls32--    alternative2 = option h16 <> "::" <> count 4 (h16 <> ":") <> ls32--    alternative3 =-            option (range 0 1 (h16 <> ":") <> h16)-        <>  "::"-        <>  count 3 (h16 <> ":")-        <>  ls32--    alternative4 =-            option (range 0 2 (h16 <> ":") <> h16)-        <>  "::"-        <>  count 2 (h16 <> ":")-        <>  ls32--    alternative5 =-        option (range 0 3 (h16 <> ":") <> h16) <> "::" <> h16 <> ":" <> ls32--    alternative6 =-        option (range 0 4 (h16 <> ":") <> h16) <> "::" <> ls32--    alternative7 =-        option (range 0 5 (h16 <> ":") <> h16) <> "::" <> h16--    alternative8 =-        option (range 0 6 (h16 <> ":") <> h16) <> "::"--h16 :: Parser Builder-h16 = range 1 3 (satisfy hexdig)--ls32 :: Parser Builder-ls32 = (h16 <> ":" <> h16) <|> ipV4Address--ipV4Address :: Parser Builder-ipV4Address = decOctet <> "." <> decOctet <> "." <> decOctet <> "." <> decOctet--decOctet :: Parser Builder-decOctet =-    choice-        [ try alternative4-        , try alternative3-        , try alternative2-        , try alternative1-        ,     alternative0-        ]-  where-    alternative0 = satisfy digit--    alternative1 = satisfy predicate <> satisfy digit-      where-        predicate c = '\x31' <= c && c <= '\x39'--    alternative2 = "1" <> count 2 (satisfy digit)--    alternative3 = "2" <> satisfy predicate <> satisfy digit-      where-        predicate c = '\x30' <= c && c <= '\x34'--    alternative4 = "25" <> satisfy predicate-      where-        predicate c = '\x30' <= c && c <= '\x35'--regName :: Parser Builder-regName = star (satisfy predicate <|> pctEncoded)-  where-    predicate c = unreserved c || subDelims c--pchar :: Parser Builder-pchar = satisfy predicate <|> pctEncoded-  where-    predicate c = unreserved c || subDelims c || c == ':' || c == '@'--query :: Parser Builder-query = star (pchar <|> satisfy predicate)-  where-    predicate c = c == '/' || c == '?'--fragment :: Parser Builder-fragment = star (pchar <|> satisfy predicate)-  where-    predicate c = c == '/' || c == '?'--pctEncoded :: Parser Builder-pctEncoded = "%" <> count 2 (satisfy hexdig)--unreserved :: Char -> Bool-unreserved c =-    alpha c || digit c || c == '-' || c == '.' || c == '_' || c == '~'--subDelims :: Char -> Bool-subDelims c = c `elem` ("!$&'()*+,;=" :: String)--http :: Parser ImportType-http = do-    (prefix, path, suffix) <- httpRaw-    whitespace-    headers <- optional (do-        _using-        importHashed_ )-    return (URL prefix path suffix headers)--env :: Parser ImportType-env = do-    _ <- Text.Parser.Char.text "env:"-    a <- (alternative0 <|> alternative1)-    whitespace-    return (Env a)-  where-    alternative0 = do-        a <- bashEnvironmentVariable-        return (Data.Text.Lazy.Builder.toLazyText a)--    alternative1 = do-        _ <- Text.Parser.Char.char '"'-        a <- posixEnvironmentVariable-        _ <- Text.Parser.Char.char '"'-        return (Data.Text.Lazy.Builder.toLazyText a)--bashEnvironmentVariable :: Parser Builder-bashEnvironmentVariable = satisfy predicate0 <> star (satisfy predicate1)-  where-    predicate0 c = alpha c || c == '_'--    predicate1 c = alpha c || digit c || c == '_'--posixEnvironmentVariable :: Parser Builder-posixEnvironmentVariable = plus posixEnvironmentVariableCharacter--posixEnvironmentVariableCharacter :: Parser Builder-posixEnvironmentVariableCharacter =-    ("\\" <> satisfy predicate0) <|> satisfy predicate1-  where-    predicate0 c = c `elem` ("\"\\abfnrtv" :: String)--    predicate1 c =-            ('\x20' <= c && c <= '\x21')-        ||  ('\x23' <= c && c <= '\x3C')-        ||  ('\x3E' <= c && c <= '\x5B')-        ||  ('\x5D' <= c && c <= '\x7E')--expression :: Parser a -> Parser (Expr Src a)-expression embedded =-    (   noted-        ( choice-            [ alternative0-            , alternative1-            , alternative2-            , alternative3-            , alternative4-            ]-        )-    <|> alternative5-    ) <?> "expression"-  where-    alternative0 = do-        _lambda-        _openParens-        a <- label-        _colon-        b <- expression embedded-        _closeParens-        _arrow-        c <- expression embedded-        return (Lam a b c)--    alternative1 = do-        _if-        a <- expression embedded-        _then-        b <- expression embedded-        _else-        c <- expression embedded-        return (BoolIf a b c)--    alternative2 = do-        _let-        a <- label-        b <- optional (do-            _colon-            expression embedded )-        _equal-        c <- expression embedded-        _in-        d <- expression embedded-        return (Let a b c d)--    alternative3 = do-        _forall-        _openParens-        a <- label-        _colon-        b <- expression embedded-        _closeParens-        _arrow-        c <- expression embedded-        return (Pi a b c)--    alternative4 = do-        a <- try (do a <- operatorExpression embedded; _arrow; return a)-        b <- expression embedded-        return (Pi "_" a b)--    alternative5 = annotatedExpression embedded--annotatedExpression :: Parser a -> Parser (Expr Src a)-annotatedExpression embedded =-    noted-        ( choice-            [ alternative0-            , try alternative1-            , alternative2-            ]-        )-  where-    alternative0 = do-        _merge-        a <- selectorExpression embedded-        b <- selectorExpression embedded-        c <- optional (do-            _colon-            applicationExpression embedded )-        return (Merge a b c)--    alternative1 = (do-        _openBracket-        (emptyCollection embedded <|> nonEmptyOptional embedded) )-        <?> "list literal"--    alternative2 = do-        a <- operatorExpression embedded-        b <- optional (do _colon; expression embedded)-        case b of-            Nothing -> return a-            Just c  -> return (Annot a c)--emptyCollection :: Parser a -> Parser (Expr Src a)-emptyCollection embedded = do-    _closeBracket-    _colon-    a <- alternative0 <|> alternative1-    b <- selectorExpression embedded-    return (a b)-  where-    alternative0 = do-        _List-        return (\a -> ListLit (Just a) empty)--    alternative1 = do-        _Optional-        return (\a -> OptionalLit a empty)--nonEmptyOptional :: Parser a -> Parser (Expr Src a)-nonEmptyOptional embedded = do-    a <- expression embedded-    _closeBracket-    _colon-    _Optional-    b <- selectorExpression embedded-    return (OptionalLit b (pure a))--operatorExpression :: Parser a -> Parser (Expr Src a)-operatorExpression = orExpression--makeOperatorExpression-    :: (Parser a -> Parser (Expr Src a))-    -> Parser ()-    -> (Expr Src a -> Expr Src a -> Expr Src a)-    -> Parser a-    -> Parser (Expr Src a)-makeOperatorExpression subExpression operatorParser operator embedded =-    noted (do-        a <- subExpression embedded-        b <- many (do operatorParser; subExpression embedded)-        return (foldr1 operator (a:b)) )--orExpression :: Parser a -> Parser (Expr Src a)-orExpression =-    makeOperatorExpression plusExpression _or BoolOr--plusExpression :: Parser a -> Parser (Expr Src a)-plusExpression =-    makeOperatorExpression textAppendExpression _plus NaturalPlus--textAppendExpression :: Parser a -> Parser (Expr Src a)-textAppendExpression =-    makeOperatorExpression listAppendExpression _textAppend TextAppend--listAppendExpression :: Parser a -> Parser (Expr Src a)-listAppendExpression =-    makeOperatorExpression andExpression _listAppend ListAppend--andExpression :: Parser a -> Parser (Expr Src a)-andExpression =-    makeOperatorExpression combineExpression _and BoolAnd--combineExpression :: Parser a -> Parser (Expr Src a)-combineExpression =-    makeOperatorExpression preferExpression _combine Combine--preferExpression :: Parser a -> Parser (Expr Src a)-preferExpression =-    makeOperatorExpression combineTypesExpression _prefer Prefer--combineTypesExpression :: Parser a -> Parser (Expr Src a)-combineTypesExpression =-    makeOperatorExpression timesExpression _combineTypes CombineTypes--timesExpression :: Parser a -> Parser (Expr Src a)-timesExpression =-    makeOperatorExpression equalExpression _times NaturalTimes--equalExpression :: Parser a -> Parser (Expr Src a)-equalExpression =-    makeOperatorExpression notEqualExpression _doubleEqual BoolEQ--notEqualExpression :: Parser a -> Parser (Expr Src a)-notEqualExpression =-    makeOperatorExpression applicationExpression _notEqual BoolNE--applicationExpression :: Parser a -> Parser (Expr Src a)-applicationExpression embedded = do-    f <- (do _constructors; return Constructors) <|> return id-    a <- noted (selectorExpression embedded)-    b <- many (noted (selectorExpression embedded))-    return (foldl app (f a) b)-  where-    app nL@(Note (Src before _ bytesL) _) nR@(Note (Src _ after bytesR) _) =-        Note (Src before after (bytesL <> bytesR)) (App nL nR)-    app nL nR =-        App nL nR--selectorExpression :: Parser a -> Parser (Expr Src a)-selectorExpression embedded = noted (do-    a <- primitiveExpression embedded--    let left  x  e = Field   e x-    let right xs e = Project e xs-    b <- many (try (do _dot; fmap left label <|> fmap right labels))-    return (foldl (\e k -> k e) a b) )--primitiveExpression :: Parser a -> Parser (Expr Src a)-primitiveExpression embedded =-    noted-        ( choice-            [ alternative00-            , alternative01-            , alternative02-            , alternative03-            , alternative04-            , alternative05-            , alternative06-            , alternative07-            , alternative37--            , choice-                [ alternative08-                , alternative09-                , alternative10-                , alternative11-                , alternative12-                , alternative13-                , alternative14-                , alternative15-                , alternative16-                , alternative17-                , alternative18-                , alternative19-                , alternative20-                , alternative21-                , alternative22-                , alternative23-                , alternative24-                , alternative25-                , alternative26-                , alternative27-                , alternative28-                , alternative29-                , alternative30-                , alternative31-                , alternative32-                , alternative33-                , alternative34-                , alternative35-                , alternative36-                ] <?> "built-in expression"-            ]-        )-    <|> alternative38-  where-    alternative00 = do-        a <- try doubleLiteral-        return (DoubleLit a)--    alternative01 = do-        a <- try naturalLiteral-        return (NaturalLit a)--    alternative02 = do-        a <- try integerLiteral-        return (IntegerLit a)--    alternative03 = textLiteral embedded--    alternative04 = (do-        _openBrace-        a <- recordTypeOrLiteral embedded-        _closeBrace-        return a ) <?> "record type or literal"--    alternative05 = (do-        _openAngle-        a <- unionTypeOrLiteral embedded-        _closeAngle-        return a ) <?> "union type or literal"--    alternative06 = nonEmptyListLiteral embedded--    alternative07 = do-        a <- embedded-        return (Embed a)--    alternative08 = do-        _NaturalFold-        return NaturalFold--    alternative09 = do-        _NaturalBuild-        return NaturalBuild--    alternative10 = do-        _NaturalIsZero-        return NaturalIsZero--    alternative11 = do-        _NaturalEven-        return NaturalEven--    alternative12 = do-        _NaturalOdd-        return NaturalOdd--    alternative13 = do-        _NaturalToInteger-        return NaturalToInteger--    alternative14 = do-        _NaturalShow-        return NaturalShow--    alternative15 = do-        _IntegerShow-        return IntegerShow--    alternative16 = do-        _DoubleShow-        return DoubleShow--    alternative17 = do-        _ListBuild-        return ListBuild--    alternative18 = do-        _ListFold-        return ListFold--    alternative19 = do-        _ListLength-        return ListLength--    alternative20 = do-        _ListHead-        return ListHead--    alternative21 = do-        _ListLast-        return ListLast--    alternative22 = do-        _ListIndexed-        return ListIndexed--    alternative23 = do-        _ListReverse-        return ListReverse--    alternative24 = do-        _OptionalFold-        return OptionalFold--    alternative25 = do-        _OptionalBuild-        return OptionalBuild--    alternative26 = do-        _Bool-        return Bool--    alternative27 = do-        _Optional-        return Optional--    alternative28 = do-        _Natural-        return Natural--    alternative29 = do-        _Integer-        return Integer--    alternative30 = do-        _Double-        return Double--    alternative31 = do-        _Text-        return Text--    alternative32 = do-        _List-        return List--    alternative33 = do-        _True-        return (BoolLit True)--    alternative34 = do-        _False-        return (BoolLit False)--    alternative35 = do-        _Type-        return (Const Type)--    alternative36 = do-        _Kind-        return (Const Kind)--    alternative37 = do-        a <- identifier-        return (Var a)--    alternative38 = do-        _openParens-        a <- expression embedded-        _closeParens-        return a--recordTypeOrLiteral :: Parser a -> Parser (Expr Src a)-recordTypeOrLiteral embedded =-    choice-        [ alternative0-        , alternative1-        , alternative2-        ]-  where-    alternative0 = do-        _equal-        return (RecordLit Data.HashMap.Strict.InsOrd.empty)--    alternative1 = nonEmptyRecordTypeOrLiteral embedded--    alternative2 = return (Record Data.HashMap.Strict.InsOrd.empty)--nonEmptyRecordTypeOrLiteral :: Parser a -> Parser (Expr Src a)-nonEmptyRecordTypeOrLiteral embedded = do-    a <- label--    let nonEmptyRecordType = do-            _colon-            b <- expression embedded-            e <- many (do-                _comma-                c <- label-                _colon-                d <- expression embedded-                return (c, d) )-            return (Record (Data.HashMap.Strict.InsOrd.fromList ((a, b):e)))--    let nonEmptyRecordLiteral = do-            _equal-            b <- expression embedded-            e <- many (do-                _comma-                c <- label-                _equal-                d <- expression embedded-                return (c, d) )-            return (RecordLit (Data.HashMap.Strict.InsOrd.fromList ((a, b):e)))--    nonEmptyRecordType <|> nonEmptyRecordLiteral--unionTypeOrLiteral :: Parser a -> Parser (Expr Src a)-unionTypeOrLiteral embedded =-        nonEmptyUnionTypeOrLiteral embedded-    <|> return (Union Data.HashMap.Strict.InsOrd.empty)--nonEmptyUnionTypeOrLiteral :: Parser a -> Parser (Expr Src a)-nonEmptyUnionTypeOrLiteral embedded = do-    (f, kvs) <- loop-    m <- toMap kvs-    return (f m)-  where-    loop = do-        a <- label--        let alternative0 = do-                _equal-                b <- expression embedded-                kvs <- many (do-                    _bar-                    c <- label-                    _colon-                    d <- expression embedded-                    return (c, d) )-                return (UnionLit a b, kvs)--        let alternative1 = do-                _colon-                b <- expression embedded--                let alternative2 = do-                        _bar-                        (f, kvs) <- loop-                        return (f, (a, b):kvs)--                let alternative3 = return (Union, [(a, b)])--                alternative2 <|> alternative3--        alternative0 <|> alternative1--nonEmptyListLiteral :: Parser a -> Parser (Expr Src a)-nonEmptyListLiteral embedded = (do-    _openBracket-    a <- expression embedded-    b <- many (do _comma; expression embedded)-    _closeBracket-    return (ListLit Nothing (Data.Sequence.fromList (a:b))) ) <?> "list literal"--completeExpression :: Parser a -> Parser (Expr Src a)-completeExpression embedded = do-    whitespace-    expression embedded--toMap :: [(Text, a)] -> Parser (InsOrdHashMap Text a)-toMap kvs = do-    let adapt (k, v) = (k, pure v)-    let m = fromListWith (<|>) (fmap adapt kvs)-    let action k vs = case Data.Sequence.viewl vs of-            EmptyL  -> empty-            v :< vs' ->-                if null vs'-                then pure v-                else-                    Text.Parser.Combinators.unexpected-                        ("duplicate field: " ++ Data.Text.Lazy.unpack k)-    Data.HashMap.Strict.InsOrd.traverseWithKey action m-  where-    fromListWith combine = Data.List.foldl' snoc nil-      where-        nil = Data.HashMap.Strict.InsOrd.empty--        snoc m (k, v) = Data.HashMap.Strict.InsOrd.insertWith combine k v m---- | Parser for a top-level Dhall expression-expr :: Parser (Expr Src Import)-expr = exprA import_---- | Parser for a top-level Dhall expression. The expression is parameterized--- over any parseable type, allowing the language to be extended as needed.-exprA :: Parser a -> Parser (Expr Src a)-exprA = completeExpression--importType_ :: Parser ImportType-importType_ = choice [ local, http, env ]--importHashed_ :: Parser ImportHashed-importHashed_ = do-    importType <- importType_-    hash       <- optional importHash_-    return (ImportHashed {..})-  where-    importHash_ = do-        _ <- Text.Parser.Char.text "sha256:"-        builder <- count 64 (satisfy hexdig <?> "hex digit")-        whitespace-        let lazyText    = Data.Text.Lazy.Builder.toLazyText builder-        let lazyBytes16 = Data.Text.Lazy.Encoding.encodeUtf8 lazyText-        let strictBytes16 = Data.ByteString.Lazy.toStrict lazyBytes16-        strictBytes <- case Data.ByteArray.Encoding.convertFromBase Base16 strictBytes16 of-            Left  string      -> fail string-            Right strictBytes -> return (strictBytes :: Data.ByteString.ByteString)-        case Crypto.Hash.digestFromByteString strictBytes of-          Nothing -> fail "Invalid sha256 hash"-          Just h -> pure h--import_ :: Parser Import-import_ = (do-    importHashed <- importHashed_-    importMode   <- alternative <|> pure Code-    return (Import {..}) ) <?> "import"-  where-    alternative = do-        _as-        _Text-        return RawText---- | A parsing error-data ParseError = ParseError-    { unwrap :: Text.Megaparsec.ParseError Char Void-    , input  :: Text-    }--instance Show ParseError where-    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 :: String -> Text -> Either ParseError (Expr Src Import)-exprFromText delta text = fmap snd (exprAndHeaderFromText delta text)--{-| Like `exprFromText` but also returns the leading comments and whitespace-    (i.e. header) up to the last newline before the code begins--    In other words, if you have a Dhall file of the form:--> -- Comment 1-> {- Comment -} 2--    Then this will preserve @Comment 1@, but not @Comment 2@--    This is used by @dhall-format@ to preserve leading comments and whitespace--}-exprAndHeaderFromText-    :: String-    -> Text-    -> Either ParseError (Text, Expr Src Import)-exprAndHeaderFromText delta text = case result of-    Left errInfo   -> Left (ParseError { unwrap = errInfo, input = text })-    Right (txt, r) -> Right (Data.Text.Lazy.dropWhileEnd (/= '\n') txt, r)+{-# LANGUAGE RecordWildCards            #-}+-- | This module contains Dhall's parsing logic++module Dhall.Parser (+    -- * Utilities+      exprFromText+    , exprAndHeaderFromText++    -- * Parsers+    , expr, exprA++    -- * Types+    , Src(..)+    , ParseError(..)+    , Parser(..)+    ) where++import Control.Exception (Exception)+import Data.Semigroup (Semigroup(..))+import Data.Text (Text)+import Data.Void (Void)+import Dhall.Core+import Prelude hiding (const, pi)++import qualified Data.Text+import qualified Text.Megaparsec++import Dhall.Parser.Combinators+import Dhall.Parser.Token+import Dhall.Parser.Expression++-- | Parser for a top-level Dhall expression+expr :: Parser (Expr Src Import)+expr = exprA import_++-- | Parser for a top-level Dhall expression. The expression is parameterized+-- over any parseable type, allowing the language to be extended as needed.+exprA :: Parser a -> Parser (Expr Src a)+exprA = completeExpression++-- | A parsing error+data ParseError = ParseError+    { unwrap :: Text.Megaparsec.ParseError Char Void+    , input  :: Text+    }++instance Show ParseError where+    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+  :: String -- ^ User-friendly name describing the input expression,+            --   used in parsing error messages+  -> Text   -- ^ Input expression to parse+  -> Either ParseError (Expr Src Import)+exprFromText delta text = fmap snd (exprAndHeaderFromText delta text)++{-| Like `exprFromText` but also returns the leading comments and whitespace+    (i.e. header) up to the last newline before the code begins++    In other words, if you have a Dhall file of the form:++> -- Comment 1+> {- Comment -} 2++    Then this will preserve @Comment 1@, but not @Comment 2@++    This is used by @dhall-format@ to preserve leading comments and whitespace+-}+exprAndHeaderFromText+    :: String -- ^ User-friendly name describing the input expression,+              --   used in parsing error messages+    -> Text   -- ^ Input expression to parse+    -> Either ParseError (Text, Expr Src Import)+exprAndHeaderFromText delta text = case result of+    Left errInfo   -> Left (ParseError { unwrap = errInfo, input = text })+    Right (txt, r) -> Right (Data.Text.dropWhileEnd (/= '\n') txt, r)   where     parser = do         (bytes, _) <- Text.Megaparsec.match whitespace
+ src/Dhall/Parser/Combinators.hs view
@@ -0,0 +1,161 @@+{-# LANGUAGE CPP                        #-}+{-# LANGUAGE DeriveDataTypeable         #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE OverloadedStrings          #-}+{-# LANGUAGE RecordWildCards            #-}+module Dhall.Parser.Combinators where+++import           Control.Applicative        (Alternative (..), liftA2)+import           Control.Monad              (MonadPlus)+import           Data.Data                  (Data)+import           Data.HashMap.Strict.InsOrd (InsOrdHashMap)+import           Data.Semigroup             (Semigroup (..))+import           Data.Sequence              (ViewL (..))+import           Data.Set                   (Set)+import           Data.String                (IsString (..))+import           Data.Text                  (Text)+import           Data.Text.Prettyprint.Doc  (Pretty (..))+import           Data.Void                  (Void)+import           Prelude                    hiding (const, pi)+import           Text.Parser.Combinators    (try, (<?>))+import           Text.Parser.Token          (TokenParsing (..))++import qualified Data.Char+import qualified Data.HashMap.Strict.InsOrd+import qualified Data.List+import qualified Data.Sequence+import qualified Data.Set+import qualified Data.Text+import qualified Text.Megaparsec+import qualified Text.Megaparsec.Char+import qualified Text.Parser.Char+import qualified Text.Parser.Combinators+import qualified Text.Parser.Token.Style++-- | Source code extract+data Src = Src Text.Megaparsec.SourcePos Text.Megaparsec.SourcePos Text+  deriving (Data, Eq, Show)++instance Pretty Src where+    pretty (Src begin _ text) =+            pretty text <> "\n"+        <>  "\n"+        <>  pretty (Text.Megaparsec.sourcePosPretty begin)+        <>  "\n"++{-| A `Parser` that is almost identical to+    @"Text.Megaparsec".`Text.Megaparsec.Parsec`@ except treating Haskell-style+    comments as whitespace+-}+newtype Parser a = Parser { unParser :: Text.Megaparsec.Parsec Void Text a }+    deriving+    (   Functor+    ,   Applicative+    ,   Monad+    ,   Alternative+    ,   MonadPlus+    ,   Text.Megaparsec.MonadParsec Void Text+    )++instance Data.Semigroup.Semigroup a => Data.Semigroup.Semigroup (Parser a) where+    (<>) = liftA2 (<>)++instance (Data.Semigroup.Semigroup a, Monoid a) => Monoid (Parser a) where+    mempty = pure mempty++#if !(MIN_VERSION_base(4,11,0))+    mappend = (<>)+#endif++instance IsString a => IsString (Parser a) where+    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.unpack . Text.Megaparsec.Char.string . fromString++  text = Text.Megaparsec.Char.string++instance TokenParsing Parser where+    someSpace =+        Text.Parser.Token.Style.buildSomeSpaceParser+            (Parser (Text.Megaparsec.skipSome (Text.Megaparsec.Char.satisfy Data.Char.isSpace)))+            Text.Parser.Token.Style.haskellCommentStyle++    highlight _ = id++    semi = token (Text.Megaparsec.Char.char ';' <?> ";")++count :: (Semigroup a, Monoid a) => Int -> Parser a -> Parser a+count n parser = mconcat (replicate n parser)++range :: (Semigroup a, Monoid a) => Int -> Int -> Parser a -> Parser a+range minimumBound maximumMatches parser =+    count minimumBound parser <> loop maximumMatches+  where+    loop 0 = mempty+    loop n = (parser <> loop (n - 1)) <|> mempty++option :: (Alternative f, Monoid a) => f a -> f a+option p = p <|> pure mempty++star :: (Alternative f, Monoid a) => f a -> f a+star p = plus p <|> pure mempty++plus :: (Alternative f, Monoid a) => f a -> f a+plus p = mappend <$> p <*> star p++satisfy :: (Char -> Bool) -> Parser Text+satisfy = fmap Data.Text.singleton . Text.Parser.Char.satisfy++noDuplicates :: Ord a => [a] -> Parser (Set a)+noDuplicates = go Data.Set.empty+  where+    go found    []  = return found+    go found (x:xs) =+        if Data.Set.member x found+        then fail "Duplicate key"+        else go (Data.Set.insert x found) xs++toMap :: [(Text, a)] -> Parser (InsOrdHashMap Text a)+toMap kvs = do+    let adapt (k, v) = (k, pure v)+    let m = fromListWith (<|>) (fmap adapt kvs)+    let action k vs = case Data.Sequence.viewl vs of+            EmptyL  -> empty+            v :< vs' ->+                if null vs'+                then pure v+                else+                    Text.Parser.Combinators.unexpected+                        ("duplicate field: " ++ Data.Text.unpack k)+    Data.HashMap.Strict.InsOrd.traverseWithKey action m+  where+    fromListWith combine = Data.List.foldl' snoc nil+      where+        nil = Data.HashMap.Strict.InsOrd.empty++        snoc m (k, v) = Data.HashMap.Strict.InsOrd.insertWith combine k v m
+ src/Dhall/Parser/Expression.hs view
@@ -0,0 +1,863 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}+-- | Parsing Dhall expressions.+module Dhall.Parser.Expression where++import Control.Applicative (Alternative(..), optional)+import Data.ByteArray.Encoding (Base(..))+import Data.Functor (void)+import Data.Semigroup (Semigroup(..))+import Data.Text (Text)+import Dhall.Core+import Prelude hiding (const, pi)+import Text.Parser.Combinators (choice, try, (<?>))++import qualified Crypto.Hash+import qualified Data.ByteArray.Encoding+import qualified Data.ByteString+import qualified Data.Char+import qualified Data.HashMap.Strict.InsOrd+import qualified Data.Sequence+import qualified Data.Text+import qualified Data.Text.Encoding+import qualified Text.Megaparsec+import qualified Text.Parser.Char++import Dhall.Parser.Combinators+import Dhall.Parser.Token++noted :: Parser (Expr Src a) -> Parser (Expr Src a)+noted parser = do+    before      <- Text.Megaparsec.getPosition+    (tokens, e) <- Text.Megaparsec.match parser+    after       <- Text.Megaparsec.getPosition+    let src₀ = Src before after tokens+    case e of+        Note src₁ _ | src₀ == src₁ -> return e+        _                          -> return (Note src₀ e)++expression :: Parser a -> Parser (Expr Src a)+expression embedded =+    (   noted+        ( choice+            [ alternative0+            , alternative1+            , alternative2+            , alternative3+            , alternative4+            ]+        )+    <|> alternative5+    ) <?> "expression"+  where+    alternative0 = do+        _lambda+        _openParens+        a <- label+        _colon+        b <- expression embedded+        _closeParens+        _arrow+        c <- expression embedded+        return (Lam a b c)++    alternative1 = do+        _if+        a <- expression embedded+        _then+        b <- expression embedded+        _else+        c <- expression embedded+        return (BoolIf a b c)++    alternative2 = do+        _let+        a <- label+        b <- optional (do+            _colon+            expression embedded )+        _equal+        c <- expression embedded+        _in+        d <- expression embedded+        return (Let a b c d)++    alternative3 = do+        _forall+        _openParens+        a <- label+        _colon+        b <- expression embedded+        _closeParens+        _arrow+        c <- expression embedded+        return (Pi a b c)++    alternative4 = do+        a <- try (do a <- operatorExpression embedded; _arrow; return a)+        b <- expression embedded+        return (Pi "_" a b)++    alternative5 = annotatedExpression embedded++annotatedExpression :: Parser a -> Parser (Expr Src a)+annotatedExpression embedded =+    noted+        ( choice+            [ alternative0+            , try alternative1+            , alternative2+            ]+        )+  where+    alternative0 = do+        _merge+        a <- importExpression embedded+        b <- importExpression embedded+        c <- optional (do+            _colon+            applicationExpression embedded )+        return (Merge a b c)++    alternative1 = (do+        _openBracket+        (emptyCollection embedded <|> nonEmptyOptional embedded) )+        <?> "list literal"++    alternative2 = do+        a <- operatorExpression embedded+        b <- optional (do _colon; expression embedded)+        case b of+            Nothing -> return a+            Just c  -> return (Annot a c)++emptyCollection :: Parser a -> Parser (Expr Src a)+emptyCollection embedded = do+    _closeBracket+    _colon+    a <- alternative0 <|> alternative1+    b <- importExpression embedded+    return (a b)+  where+    alternative0 = do+        _List+        return (\a -> ListLit (Just a) empty)++    alternative1 = do+        _Optional+        return (\a -> OptionalLit a empty)++nonEmptyOptional :: Parser a -> Parser (Expr Src a)+nonEmptyOptional embedded = do+    a <- expression embedded+    _closeBracket+    _colon+    _Optional+    b <- importExpression embedded+    return (OptionalLit b (pure a))++operatorExpression :: Parser a -> Parser (Expr Src a)+operatorExpression = importAltExpression++makeOperatorExpression+    :: (Parser a -> Parser (Expr Src a))+    -> Parser ()+    -> (Expr Src a -> Expr Src a -> Expr Src a)+    -> Parser a+    -> Parser (Expr Src a)+makeOperatorExpression subExpression operatorParser operator embedded =+    noted (do+        a <- subExpression embedded+        b <- many (do operatorParser; subExpression embedded)+        return (foldr1 operator (a:b)) )++importAltExpression :: Parser a -> Parser (Expr Src a)+importAltExpression =+    makeOperatorExpression orExpression _importAlt ImportAlt++orExpression :: Parser a -> Parser (Expr Src a)+orExpression =+    makeOperatorExpression plusExpression _or BoolOr++plusExpression :: Parser a -> Parser (Expr Src a)+plusExpression =+    makeOperatorExpression textAppendExpression _plus NaturalPlus++textAppendExpression :: Parser a -> Parser (Expr Src a)+textAppendExpression =+    makeOperatorExpression listAppendExpression _textAppend TextAppend++listAppendExpression :: Parser a -> Parser (Expr Src a)+listAppendExpression =+    makeOperatorExpression andExpression _listAppend ListAppend++andExpression :: Parser a -> Parser (Expr Src a)+andExpression =+    makeOperatorExpression combineExpression _and BoolAnd++combineExpression :: Parser a -> Parser (Expr Src a)+combineExpression =+    makeOperatorExpression preferExpression _combine Combine++preferExpression :: Parser a -> Parser (Expr Src a)+preferExpression =+    makeOperatorExpression combineTypesExpression _prefer Prefer++combineTypesExpression :: Parser a -> Parser (Expr Src a)+combineTypesExpression =+    makeOperatorExpression timesExpression _combineTypes CombineTypes++timesExpression :: Parser a -> Parser (Expr Src a)+timesExpression =+    makeOperatorExpression equalExpression _times NaturalTimes++equalExpression :: Parser a -> Parser (Expr Src a)+equalExpression =+    makeOperatorExpression notEqualExpression _doubleEqual BoolEQ++notEqualExpression :: Parser a -> Parser (Expr Src a)+notEqualExpression =+    makeOperatorExpression applicationExpression _notEqual BoolNE++applicationExpression :: Parser a -> Parser (Expr Src a)+applicationExpression embedded = do+    f <- (do _constructors; return Constructors) <|> return id+    a <- noted (importExpression embedded)+    b <- many (noted (importExpression embedded))+    return (foldl app (f a) b)+  where+    app nL@(Note (Src before _ bytesL) _) nR@(Note (Src _ after bytesR) _) =+        Note (Src before after (bytesL <> bytesR)) (App nL nR)+    app nL nR =+        App nL nR++importExpression :: Parser a -> Parser (Expr Src a)+importExpression embedded = noted (choice [ alternative0, alternative1 ])+  where+    alternative0 = do+        a <- embedded+        return (Embed a)++    alternative1 = selectorExpression embedded++selectorExpression :: Parser a -> Parser (Expr Src a)+selectorExpression embedded = noted (do+    a <- primitiveExpression embedded++    let left  x  e = Field   e x+    let right xs e = Project e xs+    b <- many (try (do _dot; fmap left label <|> fmap right labels))+    return (foldl (\e k -> k e) a b) )++primitiveExpression :: Parser a -> Parser (Expr Src a)+primitiveExpression embedded =+    noted+        ( choice+            [ alternative00+            , alternative01+            , alternative02+            , alternative03+            , alternative04+            , alternative05+            , alternative06+            , alternative37++            , choice+                [ alternative08+                , alternative09+                , alternative10+                , alternative11+                , alternative12+                , alternative13+                , alternative14+                , alternative15+                , alternativeIntegerToDouble+                , alternative16+                , alternative17+                , alternative18+                , alternative19+                , alternative20+                , alternative21+                , alternative22+                , alternative23+                , alternative24+                , alternative25+                , alternative26+                , alternative27+                , alternative28+                , alternative29+                , alternative30+                , alternative31+                , alternative32+                , alternative33+                , alternative34+                , alternative35+                , alternative36+                ] <?> "built-in expression"+            ]+        )+    <|> alternative38+  where+    alternative00 = do+        a <- try doubleLiteral+        return (DoubleLit a)++    alternative01 = do+        a <- try naturalLiteral+        return (NaturalLit a)++    alternative02 = do+        a <- try integerLiteral+        return (IntegerLit a)++    alternative03 = textLiteral embedded++    alternative04 = (do+        _openBrace+        a <- recordTypeOrLiteral embedded+        _closeBrace+        return a ) <?> "record type or literal"++    alternative05 = (do+        _openAngle+        a <- unionTypeOrLiteral embedded+        _closeAngle+        return a ) <?> "union type or literal"++    alternative06 = nonEmptyListLiteral embedded++    alternative08 = do+        _NaturalFold+        return NaturalFold++    alternative09 = do+        _NaturalBuild+        return NaturalBuild++    alternative10 = do+        _NaturalIsZero+        return NaturalIsZero++    alternative11 = do+        _NaturalEven+        return NaturalEven++    alternative12 = do+        _NaturalOdd+        return NaturalOdd++    alternative13 = do+        _NaturalToInteger+        return NaturalToInteger++    alternative14 = do+        _NaturalShow+        return NaturalShow++    alternative15 = do+        _IntegerShow+        return IntegerShow++    alternativeIntegerToDouble = do+        _IntegerToDouble+        return IntegerToDouble++    alternative16 = do+        _DoubleShow+        return DoubleShow++    alternative17 = do+        _ListBuild+        return ListBuild++    alternative18 = do+        _ListFold+        return ListFold++    alternative19 = do+        _ListLength+        return ListLength++    alternative20 = do+        _ListHead+        return ListHead++    alternative21 = do+        _ListLast+        return ListLast++    alternative22 = do+        _ListIndexed+        return ListIndexed++    alternative23 = do+        _ListReverse+        return ListReverse++    alternative24 = do+        _OptionalFold+        return OptionalFold++    alternative25 = do+        _OptionalBuild+        return OptionalBuild++    alternative26 = do+        _Bool+        return Bool++    alternative27 = do+        _Optional+        return Optional++    alternative28 = do+        _Natural+        return Natural++    alternative29 = do+        _Integer+        return Integer++    alternative30 = do+        _Double+        return Double++    alternative31 = do+        _Text+        return Text++    alternative32 = do+        _List+        return List++    alternative33 = do+        _True+        return (BoolLit True)++    alternative34 = do+        _False+        return (BoolLit False)++    alternative35 = do+        _Type+        return (Const Type)++    alternative36 = do+        _Kind+        return (Const Kind)++    alternative37 = do+        a <- identifier+        return (Var a)++    alternative38 = do+        _openParens+        a <- expression embedded+        _closeParens+        return a+++doubleQuotedChunk :: Parser a -> Parser (Chunks Src a)+doubleQuotedChunk embedded =+    choice+        [ interpolation+        , unescapedCharacter+        , escapedCharacter+        ]+  where+    interpolation = do+        _ <- Text.Parser.Char.text "${"+        e <- completeExpression embedded+        _ <- Text.Parser.Char.char '}'+        return (Chunks [(mempty, e)] mempty)++    unescapedCharacter = do+        c <- Text.Parser.Char.satisfy predicate+        return (Chunks [] (Data.Text.singleton c))+      where+        predicate c =+                ('\x20' <= c && c <= '\x21'    )+            ||  ('\x23' <= c && c <= '\x5B'    )+            ||  ('\x5D' <= c && c <= '\x10FFFF')++    escapedCharacter = do+        _ <- Text.Parser.Char.char '\\'+        c <- choice+            [ quotationMark+            , dollarSign+            , backSlash+            , forwardSlash+            , backSpace+            , formFeed+            , lineFeed+            , carriageReturn+            , tab+            , unicode+            ]+        return (Chunks [] (Data.Text.singleton c))+      where+        quotationMark = Text.Parser.Char.char '"'++        dollarSign = Text.Parser.Char.char '$'++        backSlash = Text.Parser.Char.char '\\'++        forwardSlash = Text.Parser.Char.char '/'++        backSpace = do _ <- Text.Parser.Char.char 'b'; return '\b'++        formFeed = do _ <- Text.Parser.Char.char 'f'; return '\f'++        lineFeed = do _ <- Text.Parser.Char.char 'n'; return '\n'++        carriageReturn = do _ <- Text.Parser.Char.char 'r'; return '\r'++        tab = do _ <- Text.Parser.Char.char 't'; return '\t'++        unicode = do+            _  <- Text.Parser.Char.char 'u';+            n0 <- hexNumber+            n1 <- hexNumber+            n2 <- hexNumber+            n3 <- hexNumber+            let n = ((n0 * 16 + n1) * 16 + n2) * 16 + n3+            return (Data.Char.chr n)++doubleQuotedLiteral :: Parser a -> Parser (Chunks Src a)+doubleQuotedLiteral embedded = do+    _      <- Text.Parser.Char.char '"'+    chunks <- many (doubleQuotedChunk embedded)+    _      <- Text.Parser.Char.char '"'+    return (mconcat chunks)++singleQuoteContinue :: Parser a -> Parser (Chunks Src a)+singleQuoteContinue embedded =+    choice+        [ escapeSingleQuotes+        , interpolation+        , escapeInterpolation+        , endLiteral+        , unescapedCharacter+        , tab+        , endOfLine+        ]+  where+        escapeSingleQuotes = do+            _ <- "'''" :: Parser Text+            b <- singleQuoteContinue embedded+            return ("''" <> b)++        interpolation = do+            _ <- Text.Parser.Char.text "${"+            a <- completeExpression embedded+            _ <- Text.Parser.Char.char '}'+            b <- singleQuoteContinue embedded+            return (Chunks [(mempty, a)] mempty <> b)++        escapeInterpolation = do+            _ <- Text.Parser.Char.text "''${"+            b <- singleQuoteContinue embedded+            return ("${" <> b)++        endLiteral = do+            _ <- Text.Parser.Char.text "''"+            return mempty++        unescapedCharacter = do+            a <- satisfy predicate+            b <- singleQuoteContinue embedded+            return (Chunks [] a <> b)+          where+            predicate c = '\x20' <= c && c <= '\x10FFFF'++        endOfLine = do+            a <- "\n" <|> "\r\n"+            b <- singleQuoteContinue embedded+            return (Chunks [] a <> b)++        tab = do+            _ <- Text.Parser.Char.char '\t'+            b <- singleQuoteContinue embedded+            return ("\t" <> b)++singleQuoteLiteral :: Parser a -> Parser (Chunks Src a)+singleQuoteLiteral embedded = do+    _ <- Text.Parser.Char.text "''"++    -- This is technically not in the grammar, but it's still equivalent to the+    -- original grammar and an easy way to discard the first character if it's+    -- a newline+    _ <- optional endOfLine++    a <- singleQuoteContinue embedded++    return (dedent a)+  where+    endOfLine =+            void (Text.Parser.Char.char '\n'  )+        <|> void (Text.Parser.Char.text "\r\n")++textLiteral :: Parser a -> Parser (Expr Src a)+textLiteral embedded = (do+    literal <- doubleQuotedLiteral embedded <|> singleQuoteLiteral embedded+    whitespace+    return (TextLit literal) ) <?> "text literal"++recordTypeOrLiteral :: Parser a -> Parser (Expr Src a)+recordTypeOrLiteral embedded =+    choice+        [ alternative0+        , alternative1+        , alternative2+        ]+  where+    alternative0 = do+        _equal+        return (RecordLit Data.HashMap.Strict.InsOrd.empty)++    alternative1 = nonEmptyRecordTypeOrLiteral embedded++    alternative2 = return (Record Data.HashMap.Strict.InsOrd.empty)++nonEmptyRecordTypeOrLiteral :: Parser a -> Parser (Expr Src a)+nonEmptyRecordTypeOrLiteral embedded = do+    a <- label++    let nonEmptyRecordType = do+            _colon+            b <- expression embedded+            e <- many (do+                _comma+                c <- label+                _colon+                d <- expression embedded+                return (c, d) )+            m <- toMap ((a, b) : e)+            return (Record m)++    let nonEmptyRecordLiteral = do+            _equal+            b <- expression embedded+            e <- many (do+                _comma+                c <- label+                _equal+                d <- expression embedded+                return (c, d) )+            m <- toMap ((a, b) : e)+            return (RecordLit m)++    nonEmptyRecordType <|> nonEmptyRecordLiteral++unionTypeOrLiteral :: Parser a -> Parser (Expr Src a)+unionTypeOrLiteral embedded =+        nonEmptyUnionTypeOrLiteral embedded+    <|> return (Union Data.HashMap.Strict.InsOrd.empty)++nonEmptyUnionTypeOrLiteral :: Parser a -> Parser (Expr Src a)+nonEmptyUnionTypeOrLiteral embedded = do+    (f, kvs) <- loop+    m <- toMap kvs+    return (f m)+  where+    loop = do+        a <- label++        let alternative0 = do+                _equal+                b <- expression embedded+                kvs <- many (do+                    _bar+                    c <- label+                    _colon+                    d <- expression embedded+                    return (c, d) )+                return (UnionLit a b, kvs)++        let alternative1 = do+                _colon+                b <- expression embedded++                let alternative2 = do+                        _bar+                        (f, kvs) <- loop+                        return (f, (a, b):kvs)++                let alternative3 = return (Union, [(a, b)])++                alternative2 <|> alternative3++        alternative0 <|> alternative1++nonEmptyListLiteral :: Parser a -> Parser (Expr Src a)+nonEmptyListLiteral embedded = (do+    _openBracket+    a <- expression embedded+    b <- many (do _comma; expression embedded)+    _closeBracket+    return (ListLit Nothing (Data.Sequence.fromList (a:b))) ) <?> "list literal"++completeExpression :: Parser a -> Parser (Expr Src a)+completeExpression embedded = do+    whitespace+    expression embedded++env :: Parser ImportType+env = do+    _ <- Text.Parser.Char.text "env:"+    a <- (alternative0 <|> alternative1)+    whitespace+    return (Env a)+  where+    alternative0 = bashEnvironmentVariable++    alternative1 = do+        _ <- Text.Parser.Char.char '"'+        a <- posixEnvironmentVariable+        _ <- Text.Parser.Char.char '"'+        return a++localRaw :: Parser ImportType+localRaw =+    choice+        [ parentPath+        , herePath+        , homePath+        , try absolutePath+        ]+  where+    parentPath = do+        _    <- ".." :: Parser Text+        File (Directory segments) final <- file_++        return (Local Here (File (Directory (segments ++ [".."])) final))++    herePath = do+        _    <- "." :: Parser Text+        file <- file_++        return (Local Here file)++    homePath = do+        _    <- "~" :: Parser Text+        file <- file_++        return (Local Home file)++    absolutePath = do+        file <- file_++        return (Local Absolute file)++local :: Parser ImportType+local = do+    a <- localRaw+    whitespace+    return a++http :: Parser ImportType+http = do+    (prefix, path, suffix) <- httpRaw+    whitespace+    headers <- optional (do+        _using+        (importHashed_ <|> (_openParens *> importHashed_ <* _closeParens)) )+    return (URL prefix path suffix headers)++missing :: Parser ImportType+missing = do+  _missing+  return Missing++importType_ :: Parser ImportType+importType_ = choice [ local, http, env, missing ]++importHashed_ :: Parser ImportHashed+importHashed_ = do+    importType <- importType_+    hash       <- optional importHash_+    return (ImportHashed {..})+  where+    importHash_ = do+        _ <- Text.Parser.Char.text "sha256:"+        text <- count 64 (satisfy hexdig <?> "hex digit")+        whitespace+        let strictBytes16 = Data.Text.Encoding.encodeUtf8 text+        strictBytes <- case Data.ByteArray.Encoding.convertFromBase Base16 strictBytes16 of+            Left  string      -> fail string+            Right strictBytes -> return (strictBytes :: Data.ByteString.ByteString)+        case Crypto.Hash.digestFromByteString strictBytes of+          Nothing -> fail "Invalid sha256 hash"+          Just h  -> pure h++import_ :: Parser Import+import_ = (do+    importHashed <- importHashed_+    importMode   <- alternative <|> pure Code+    return (Import {..}) ) <?> "import"+  where+    alternative = do+        _as+        _Text+        return RawText++-- | Similar to `Dhall.Core.renderChunks` except that this doesn't bother to+-- render interpolated expressions to avoid a `Buildable a` constraint.  The+-- interpolated contents are not necessary for computing how much to dedent a+-- multi-line string+--+-- This also doesn't include the surrounding quotes since they would interfere+-- with the whitespace detection+renderChunks :: Chunks s a -> Text+renderChunks (Chunks a b) = foldMap renderChunk a <> b+  where+    renderChunk :: (Text, Expr s a) -> Text+    renderChunk (c, _) = c <> "${x}"++dedent :: Chunks Src a -> Chunks Src a+dedent chunks0 = process chunks0+  where+    text0 = renderChunks chunks0++    lines0 = Data.Text.lines text0++    isEmpty = Data.Text.all Data.Char.isSpace++    nonEmptyLines = filter (not . isEmpty) lines0++    indentLength line =+        Data.Text.length (Data.Text.takeWhile Data.Char.isSpace line)++    shortestIndent = case nonEmptyLines of+        [] -> 0+        _  -> minimum (map indentLength nonEmptyLines)++    -- The purpose of this complicated `trimBegin`/`trimContinue` is to ensure+    -- that we strip leading whitespace without stripping whitespace after+    -- variable interpolation++    -- This is the trim function we use up until the first variable+    -- interpolation, dedenting all lines+    trimBegin =+          Data.Text.intercalate "\n"+        . map (Data.Text.drop shortestIndent)+        . Data.Text.splitOn "\n"++    -- This is the trim function we use after each variable interpolation+    -- where we indent each line except the first line (since it's not a true+    -- beginning of a line)+    trimContinue text = Data.Text.intercalate "\n" lines_+      where+        lines_ = case Data.Text.splitOn "\n" text of+            []   -> []+            l:ls -> l:map (Data.Text.drop shortestIndent) ls++    -- This is the loop that drives whether or not to use `trimBegin` or+    -- `trimContinue`.  We call this function with `trimBegin`, but after the+    -- first interpolation we switch permanently to `trimContinue`+    process (Chunks ((x0, y0):xys) z) =+        Chunks ((trimBegin x0, y0):xys') (trimContinue z)+      where+        xys' = [ (trimContinue x, y) | (x, y) <- xys ]+    process (Chunks [] z) =+        Chunks [] (trimBegin z)
+ src/Dhall/Parser/Token.hs view
@@ -0,0 +1,616 @@+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE OverloadedStrings #-}+-- | Parse Dhall tokens. Even though we don't have a tokenizer per-se this+---  module is useful for keeping some small parsing utilities.+module Dhall.Parser.Token where++import           Dhall.Parser.Combinators++import Control.Applicative (Alternative(..))+import Data.Functor (void)+import Data.Semigroup (Semigroup(..))+import Data.Set (Set)+import Data.Text (Text)+import Dhall.Core+import Prelude hiding (const, pi)+import Text.Parser.Combinators (choice, try, (<?>))++import qualified Control.Monad+import qualified Data.Char+import qualified Data.HashSet+import qualified Data.List.NonEmpty+import qualified Data.Set+import qualified Data.Text+import qualified Text.Parser.Char+import qualified Text.Parser.Combinators++import Data.Scientific (Scientific)+import Numeric.Natural (Natural)+import Prelude hiding (const, pi)++import qualified Text.Parser.Token+++whitespace :: Parser ()+whitespace = Text.Parser.Combinators.skipMany whitespaceChunk++alpha :: Char -> Bool+alpha c = ('\x41' <= c && c <= '\x5A') || ('\x61' <= c && c <= '\x7A')++digit :: Char -> Bool+digit c = '\x30' <= c && c <= '\x39'++hexdig :: Char -> Bool+hexdig c =+        ('0' <= c && c <= '9')+    ||  ('A' <= c && c <= 'F')+    ||  ('a' <= c && c <= 'f')++doubleLiteral :: Parser Scientific+doubleLiteral = (do+    sign <-  fmap (\_ -> negate) (Text.Parser.Char.char '-')+         <|> pure id+    a    <-  Text.Parser.Token.scientific+    return (sign a) ) <?> "double literal"++integerLiteral :: Parser Integer+integerLiteral = (do+    let positive = fmap (\_ -> id    ) (Text.Parser.Char.char '+')+    let negative = fmap (\_ -> negate) (Text.Parser.Char.char '-')+    sign <- positive <|> negative+    a <- Text.Parser.Token.natural+    return (sign a) ) <?> "integer literal"++naturalLiteral :: Parser Natural+naturalLiteral = (do+    a <- Text.Parser.Token.natural+    return (fromIntegral a) ) <?> "natural literal"++identifier :: Parser Var+identifier = do+    x <- label++    let indexed = do+            _ <- Text.Parser.Char.char '@'+            Text.Parser.Token.natural++    n <- indexed <|> pure 0+    return (V x n)++whitespaceChunk :: Parser ()+whitespaceChunk =+    choice+        [ void (Text.Parser.Char.satisfy predicate)+        , void (Text.Parser.Char.text "\r\n")+        , lineComment+        , blockComment+        ] <?> "whitespace"+  where+    predicate c = c == ' ' || c == '\t' || c == '\n'++hexNumber :: Parser Int+hexNumber = choice [ hexDigit, hexUpper, hexLower ]+  where+    hexDigit = do+        c <- Text.Parser.Char.satisfy predicate+        return (Data.Char.ord c - Data.Char.ord '0')+      where+        predicate c = '0' <= c && c <= '9'++    hexUpper = do+        c <- Text.Parser.Char.satisfy predicate+        return (10 + Data.Char.ord c - Data.Char.ord 'A')+      where+        predicate c = 'A' <= c && c <= 'F'++    hexLower = do+        c <- Text.Parser.Char.satisfy predicate+        return (10 + Data.Char.ord c - Data.Char.ord 'a')+      where+        predicate c = 'a' <= c && c <= 'f'++lineComment :: Parser ()+lineComment = do+    _ <- Text.Parser.Char.text "--"+    Text.Parser.Combinators.skipMany notEndOfLine+    endOfLine+    return ()+  where+    endOfLine =+            void (Text.Parser.Char.char '\n'  )+        <|> void (Text.Parser.Char.text "\r\n")++    notEndOfLine = void (Text.Parser.Char.satisfy predicate)+      where+        predicate c = ('\x20' <= c && c <= '\x10FFFF') || c == '\t'++blockComment :: Parser ()+blockComment = do+    _ <- Text.Parser.Char.text "{-"+    blockCommentContinue++blockCommentChunk :: Parser ()+blockCommentChunk =+    choice+        [ blockComment  -- Nested block comment+        , character+        , endOfLine+        ]+  where+    character = void (Text.Parser.Char.satisfy predicate)+      where+        predicate c = '\x20' <= c && c <= '\x10FFFF' || c == '\n' || c == '\t'++    endOfLine = void (Text.Parser.Char.text "\r\n")++blockCommentContinue :: Parser ()+blockCommentContinue = endOfComment <|> continue+  where+    endOfComment = void (Text.Parser.Char.text "-}")++    continue = do+        blockCommentChunk+        blockCommentContinue+++simpleLabel :: Parser Text+simpleLabel = try (do+    c  <- Text.Parser.Char.satisfy headCharacter+    cs <- many (Text.Parser.Char.satisfy tailCharacter)+    let string = c:cs+    let text = Data.Text.pack string+    Control.Monad.guard (not (Data.HashSet.member text reservedIdentifiers))+    return text )+  where+    headCharacter c = alpha c || c == '_'++    tailCharacter c = alpha c || digit c || c == '_' || c == '-' || c == '/'++backtickLabel :: Parser Text+backtickLabel = do+    _ <- Text.Parser.Char.char '`'+    t <- some (Text.Parser.Char.satisfy predicate)+    _ <- Text.Parser.Char.char '`'+    return (Data.Text.pack t)+  where+    predicate c = alpha c || digit c || elem c ("-/_:." :: String)++labels :: Parser (Set Text)+labels = do+    _openBrace+    xs <- nonEmptyLabels <|> emptyLabels+    _closeBrace+    return xs+  where+    emptyLabels = pure Data.Set.empty++    nonEmptyLabels = do+        x  <- label+        xs <- many (do _ <- _comma; label)+        noDuplicates (x : xs)+++label :: Parser Text+label = (do+    t <- backtickLabel <|> simpleLabel+    whitespace+    return t ) <?> "label"++bashEnvironmentVariable :: Parser Text+bashEnvironmentVariable = satisfy predicate0 <> star (satisfy predicate1)+  where+    predicate0 c = alpha c || c == '_'++    predicate1 c = alpha c || digit c || c == '_'++posixEnvironmentVariable :: Parser Text+posixEnvironmentVariable = plus posixEnvironmentVariableCharacter++posixEnvironmentVariableCharacter :: Parser Text+posixEnvironmentVariableCharacter =+    ("\\" <> satisfy predicate0) <|> satisfy predicate1+  where+    predicate0 c = c `elem` ("\"\\abfnrtv" :: String)++    predicate1 c =+            ('\x20' <= c && c <= '\x21')+        ||  ('\x23' <= c && c <= '\x3C')+        ||  ('\x3E' <= c && c <= '\x5B')+        ||  ('\x5D' <= c && c <= '\x7E')++pathCharacter :: Char -> Bool+pathCharacter c =+        ('\x21' <= c && c <= '\x22')+    ||  ('\x24' <= c && c <= '\x27')+    ||  ('\x2A' <= c && c <= '\x2B')+    ||  ('\x2D' <= c && c <= '\x2E')+    ||  ('\x30' <= c && c <= '\x3B')+    ||  c == '\x3D'+    ||  ('\x40' <= c && c <= '\x5A')+    ||  ('\x5E' <= c && c <= '\x7A')+    ||  c == '\x7C'+    ||  c == '\x7E'++pathComponent :: Parser Text+pathComponent = do+    _      <- "/" :: Parser Text+    string <- some (Text.Parser.Char.satisfy pathCharacter)++    return (Data.Text.pack string)++file_ :: Parser File+file_ = do+    path <- Data.List.NonEmpty.some1 pathComponent++    let directory = Directory (reverse (Data.List.NonEmpty.init path))+    let file      = Data.List.NonEmpty.last path++    return (File {..})++scheme :: Parser Text+scheme = "http" <> option "s"++httpRaw :: Parser (Text, File, Text)+httpRaw = do+    prefixText <- scheme <> "://" <> authority+    file   <- file_+    suffixText <- option ("?" <> query) <> option ("#" <> fragment)++    return (prefixText, file, suffixText)++authority :: Parser Text+authority = option (try (userinfo <> "@")) <> host <> option (":" <> port)++userinfo :: Parser Text+userinfo = star (satisfy predicate <|> pctEncoded)+  where+    predicate c = unreserved c || subDelims c || c == ':'++host :: Parser Text+host = choice [ ipLiteral, ipV4Address, regName ]++port :: Parser Text+port = star (satisfy digit)++ipLiteral :: Parser Text+ipLiteral = "[" <> (ipV6Address <|> ipVFuture) <> "]"++ipVFuture :: Parser Text+ipVFuture = "v" <> plus (satisfy hexdig) <> "." <> plus (satisfy predicate)+  where+    predicate c = unreserved c || subDelims c || c == ':'++ipV6Address :: Parser Text+ipV6Address =+    choice+        [ try alternative0+        , try alternative1+        , try alternative2+        , try alternative3+        , try alternative4+        , try alternative5+        , try alternative6+        , try alternative7+        ,     alternative8+        ]+  where+    alternative0 = count 6 (h16 <> ":") <> ls32++    alternative1 = "::" <> count 5 (h16 <> ":") <> ls32++    alternative2 = option h16 <> "::" <> count 4 (h16 <> ":") <> ls32++    alternative3 =+            option (range 0 1 (h16 <> ":") <> h16)+        <>  "::"+        <>  count 3 (h16 <> ":")+        <>  ls32++    alternative4 =+            option (range 0 2 (h16 <> ":") <> h16)+        <>  "::"+        <>  count 2 (h16 <> ":")+        <>  ls32++    alternative5 =+        option (range 0 3 (h16 <> ":") <> h16) <> "::" <> h16 <> ":" <> ls32++    alternative6 =+        option (range 0 4 (h16 <> ":") <> h16) <> "::" <> ls32++    alternative7 =+        option (range 0 5 (h16 <> ":") <> h16) <> "::" <> h16++    alternative8 =+        option (range 0 6 (h16 <> ":") <> h16) <> "::"++h16 :: Parser Text+h16 = range 1 3 (satisfy hexdig)++ls32 :: Parser Text+ls32 = (h16 <> ":" <> h16) <|> ipV4Address++ipV4Address :: Parser Text+ipV4Address = decOctet <> "." <> decOctet <> "." <> decOctet <> "." <> decOctet++decOctet :: Parser Text+decOctet =+    choice+        [ try alternative4+        , try alternative3+        , try alternative2+        , try alternative1+        ,     alternative0+        ]+  where+    alternative0 = satisfy digit++    alternative1 = satisfy predicate <> satisfy digit+      where+        predicate c = '\x31' <= c && c <= '\x39'++    alternative2 = "1" <> count 2 (satisfy digit)++    alternative3 = "2" <> satisfy predicate <> satisfy digit+      where+        predicate c = '\x30' <= c && c <= '\x34'++    alternative4 = "25" <> satisfy predicate+      where+        predicate c = '\x30' <= c && c <= '\x35'++regName :: Parser Text+regName = star (satisfy predicate <|> pctEncoded)+  where+    predicate c = unreserved c || subDelims c++pchar :: Parser Text+pchar = satisfy predicate <|> pctEncoded+  where+    predicate c = unreserved c || subDelims c || c == ':' || c == '@'++query :: Parser Text+query = star (pchar <|> satisfy predicate)+  where+    predicate c = c == '/' || c == '?'++fragment :: Parser Text+fragment = star (pchar <|> satisfy predicate)+  where+    predicate c = c == '/' || c == '?'++pctEncoded :: Parser Text+pctEncoded = "%" <> count 2 (satisfy hexdig)++subDelims :: Char -> Bool+subDelims c = c `elem` ("!$&'()*+,;=" :: String)++unreserved :: Char -> Bool+unreserved c =+    alpha c || digit c || c == '-' || c == '.' || c == '_' || c == '~'++reserved :: Data.Text.Text -> Parser ()+reserved x = do _ <- Text.Parser.Char.text x; whitespace++_if :: Parser ()+_if = reserved "if"++_then :: Parser ()+_then = reserved "then"++_else :: Parser ()+_else = reserved "else"++_let :: Parser ()+_let = reserved "let"++_in :: Parser ()+_in = reserved "in"++_as :: Parser ()+_as = reserved "as"++_using :: Parser ()+_using = reserved "using"++_merge :: Parser ()+_merge = reserved "merge"++_constructors :: Parser ()+_constructors = reserved "constructors"++_NaturalFold :: Parser ()+_NaturalFold = reserved "Natural/fold"++_NaturalBuild :: Parser ()+_NaturalBuild = reserved "Natural/build"++_NaturalIsZero :: Parser ()+_NaturalIsZero = reserved "Natural/isZero"++_NaturalEven :: Parser ()+_NaturalEven = reserved "Natural/even"++_NaturalOdd :: Parser ()+_NaturalOdd = reserved "Natural/odd"++_NaturalToInteger :: Parser ()+_NaturalToInteger = reserved "Natural/toInteger"++_NaturalShow :: Parser ()+_NaturalShow = reserved "Natural/show"++_IntegerShow :: Parser ()+_IntegerShow = reserved "Integer/show"++_IntegerToDouble :: Parser ()+_IntegerToDouble = reserved "Integer/toDouble"++_DoubleShow :: Parser ()+_DoubleShow = reserved "Double/show"++_ListBuild :: Parser ()+_ListBuild = reserved "List/build"++_ListFold :: Parser ()+_ListFold = reserved "List/fold"++_ListLength :: Parser ()+_ListLength = reserved "List/length"++_ListHead :: Parser ()+_ListHead = reserved "List/head"++_ListLast :: Parser ()+_ListLast = reserved "List/last"++_ListIndexed :: Parser ()+_ListIndexed = reserved "List/indexed"++_ListReverse :: Parser ()+_ListReverse = reserved "List/reverse"++_OptionalFold :: Parser ()+_OptionalFold = reserved "Optional/fold"++_OptionalBuild :: Parser ()+_OptionalBuild = reserved "Optional/build"++_Bool :: Parser ()+_Bool = reserved "Bool"++_Optional :: Parser ()+_Optional = reserved "Optional"++_Natural :: Parser ()+_Natural = reserved "Natural"++_Integer :: Parser ()+_Integer = reserved "Integer"++_Double :: Parser ()+_Double = reserved "Double"++_Text :: Parser ()+_Text = reserved "Text"++_List :: Parser ()+_List = reserved "List"++_True :: Parser ()+_True = reserved "True"++_False :: Parser ()+_False = reserved "False"++_Type :: Parser ()+_Type = reserved "Type"++_Kind :: Parser ()+_Kind = reserved "Kind"++_equal :: Parser ()+_equal = reserved "="++_or :: Parser ()+_or = reserved "||"++_plus :: Parser ()+_plus = reserved "+"++_textAppend :: Parser ()+_textAppend = reserved "++"++_listAppend :: Parser ()+_listAppend = reserved "#"++_and :: Parser ()+_and = reserved "&&"++_times :: Parser ()+_times = reserved "*"++_doubleEqual :: Parser ()+_doubleEqual = reserved "=="++_notEqual :: Parser ()+_notEqual = reserved "!="++_dot :: Parser ()+_dot = reserved "."++_openBrace :: Parser ()+_openBrace = reserved "{"++_closeBrace :: Parser ()+_closeBrace = reserved "}"++_openBracket :: Parser ()+_openBracket = reserved "["++_closeBracket :: Parser ()+_closeBracket = reserved "]"++_openAngle :: Parser ()+_openAngle = reserved "<"++_closeAngle :: Parser ()+_closeAngle = reserved ">"++_bar :: Parser ()+_bar = reserved "|"++_comma :: Parser ()+_comma = reserved ","++_openParens :: Parser ()+_openParens = reserved "("++_closeParens :: Parser ()+_closeParens = reserved ")"++_colon :: Parser ()+_colon = reserved ":"++_at :: Parser ()+_at = reserved "@"++_missing :: Parser ()+_missing = reserved "missing"++_importAlt :: Parser ()+_importAlt = reserved "?"++_combine :: Parser ()+_combine = do+    void (Text.Parser.Char.char '∧' <?> "\"∧\"") <|> void (Text.Parser.Char.text "/\\")+    whitespace++_combineTypes :: Parser ()+_combineTypes = do+    void (Text.Parser.Char.char '⩓' <?> "\"⩓\"") <|> void (Text.Parser.Char.text "//\\\\")+    whitespace++_prefer :: Parser ()+_prefer = do+    void (Text.Parser.Char.char '⫽' <?> "\"⫽\"") <|> void (Text.Parser.Char.text "//")+    whitespace++_lambda :: Parser ()+_lambda = do+    _ <- Text.Parser.Char.satisfy predicate+    whitespace+  where+    predicate 'λ'  = True+    predicate '\\' = True+    predicate _    = False++_forall :: Parser ()+_forall = do+    void (Text.Parser.Char.char '∀' <?> "\"∀\"") <|> void (Text.Parser.Char.text "forall")+    whitespace++_arrow :: Parser ()+_arrow = do+    void (Text.Parser.Char.char '→' <?> "\"→\"") <|> void (Text.Parser.Char.text "->")+    whitespace
src/Dhall/Pretty/Internal.hs view
@@ -10,12 +10,7 @@       Ann(..)     , annToAnsiStyle     , prettyExpr-    , buildConst-    , buildVar-    , buildExpr-    , buildNatural-    , buildNumber-    , buildScientific+    , prettyVar     , pretty     , escapeText @@ -25,7 +20,11 @@     , prettyNatural     , prettyNumber     , prettyScientific+    , prettyToStrictText+    , prettyToString +    , docToStrictText+     , builtin     , keyword     , literal@@ -61,10 +60,8 @@ import Data.Monoid ((<>)) import Data.Scientific (Scientific) import Data.Set (Set)-import Data.Text.Lazy (Text)-import Data.Text.Lazy.Builder (Builder)+import Data.Text (Text) import Data.Text.Prettyprint.Doc (Doc, Pretty, space)-import Formatting.Buildable (Buildable(..)) import Numeric.Natural (Natural) import Prelude hiding (succ) import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Terminal@@ -74,10 +71,10 @@ import qualified Data.HashSet import qualified Data.List import qualified Data.Set-import qualified Data.Text.Lazy                        as Text-import qualified Data.Text.Lazy.Builder                as Builder-import qualified Data.Text.Prettyprint.Doc             as Pretty-import qualified Data.Text.Prettyprint.Doc.Render.Text as Pretty+import qualified Data.Text                               as Text+import qualified Data.Text.Prettyprint.Doc               as Pretty+import qualified Data.Text.Prettyprint.Doc.Render.Text   as Pretty+import qualified Data.Text.Prettyprint.Doc.Render.String as Pretty  {-| Annotation type used to tag elements in a pretty-printed document for     syntax highlighting purposes@@ -103,7 +100,7 @@  -- | Pretty print an expression prettyExpr :: Pretty a => Expr s a -> Doc Ann-prettyExpr = prettyExprA+prettyExpr = prettyExpression  {-| Internal utility for pretty-printing, used when generating element lists     to supply to `enclose` or `enclose'`.  This utility indicates that the@@ -313,25 +310,26 @@     short =         literal "\"" <> foldMap prettyChunk a <> literal (prettyText b <> "\"") -    hasNewLine builder = Text.any (== '\n') lazyText-      where-        lazyText = Builder.toLazyText builder+    hasNewLine = Text.any (== '\n')      prettyMultilineChunk (c, d) =-      prettyMultilineBuilder c <> dollar <> lbrace <> prettyExprA d <> rbrace+            prettyMultilineBuilder c+        <>  dollar+        <>  lbrace+        <>  prettyExpression d+        <>  rbrace      prettyMultilineBuilder builder = literal (mconcat docs)       where-        lazyText = Builder.toLazyText (escapeSingleQuotedText builder)--        lazyLines = Text.splitOn "\n" lazyText+        lazyLines = Text.splitOn "\n" (escapeSingleQuotedText builder)          docs =             Data.List.intersperse Pretty.hardline (fmap Pretty.pretty lazyLines) -    prettyChunk (c, d) = prettyText c <> syntax "${" <> prettyExprA d <> syntax rbrace+    prettyChunk (c, d) =+        prettyText c <> syntax "${" <> prettyExpression d <> syntax rbrace -    prettyText t = literal (Pretty.pretty (Builder.toLazyText (escapeText t)))+    prettyText t = literal (Pretty.pretty (escapeText t))  prettyConst :: Const -> Doc Ann prettyConst Type = builtin "Type"@@ -341,25 +339,8 @@ prettyVar (V x 0) = label (Pretty.unAnnotate (prettyLabel x)) prettyVar (V x n) = label (Pretty.unAnnotate (prettyLabel x <> "@" <> prettyNumber n)) -prettyExprA :: Pretty a => Expr s a -> Doc Ann-prettyExprA a0@(Annot _ _) =-    enclose'-        ""-        "  "-        (" " <> colon <> " ")-        (colon <> space)-        (fmap duplicate (docs a0))-  where-    docs (Annot a b) = prettyExprB a : docs b-    docs (Note  _ b) = docs b-    docs          b  = [ prettyExprB b ]-prettyExprA (Note _ a) =-    prettyExprA a-prettyExprA a0 =-    prettyExprB a0--prettyExprB :: Pretty a => Expr s a -> Doc Ann-prettyExprB a0@(Lam _ _ _) = arrows (fmap duplicate (docs a0))+prettyExpression :: Pretty a => Expr s a -> Doc Ann+prettyExpression a0@(Lam _ _ _) = arrows (fmap duplicate (docs a0))   where     docs (Lam a b c) = Pretty.group (Pretty.flatAlt long short) : docs c       where@@ -369,7 +350,7 @@                 <>  prettyLabel a                 <>  Pretty.hardline                 <>  (colon <> space)-                <>  prettyExprA b+                <>  prettyExpression b                 <>  Pretty.hardline                 <>  rparen                 )@@ -377,56 +358,54 @@         short = (lambda <> lparen)             <>  prettyLabel a             <>  (space <> colon <> space)-            <>  prettyExprA b+            <>  prettyExpression b             <>  rparen     docs (Note  _ c) = docs c-    docs          c  = [ prettyExprB c ]-prettyExprB a0@(BoolIf _ _ _) =-    enclose' "" "      " (space <> keyword "else" <> space) (Pretty.hardline <> keyword "else" <> "  ") (fmap duplicate (docs a0))+    docs          c  = [ prettyExpression c ]+prettyExpression a0@(BoolIf _ _ _) =+    Pretty.group (Pretty.flatAlt long short)   where-    docs (BoolIf a b c) =-        Pretty.group (Pretty.flatAlt long short) : docs c-      where-        long =-             Pretty.align-                (   (keyword "if" <> "    ")-                <>  prettyExprA a-                <>  Pretty.hardline-                <>  (keyword "then" <> "  ")-                <>  prettyExprA b-                )+    prefixesLong =+            "      "+        :   cycle+                [ Pretty.hardline <> keyword "then" <> "  "+                , Pretty.hardline <> keyword "else" <> "  "+                ] -        short = (keyword "if" <> " ")-            <>  prettyExprA a-            <>  (space <> keyword "then" <> space)-            <>  prettyExprA b-    docs (Note  _    c) = docs c-    docs             c  = [ prettyExprB c ]-prettyExprB a0@(Pi _ _ _) =-    arrows (fmap duplicate (docs a0))-  where-    docs (Pi "_" b c) = prettyExprC b : docs c-    docs (Pi a   b c) = Pretty.group (Pretty.flatAlt long short) : docs c+    prefixesShort =+            ""+        :   cycle+                [ space <> keyword "then" <> space+                , space <> keyword "else" <> space+                ]++    longLines = zipWith (<>) prefixesLong (docsLong a0)++    long =+        Pretty.align (mconcat (Data.List.intersperse Pretty.hardline longLines))++    short = mconcat (zipWith (<>) prefixesShort (docsShort a0))++    docsLong (BoolIf a b c) =+        docLong ++ docsLong c       where-        long =  forall <> space-            <>  Pretty.align-                (   lparen <> space-                <>  prettyLabel a-                <>  Pretty.hardline-                <>  colon <> space-                <>  prettyExprA b-                <>  Pretty.hardline-                <>  rparen-                )+        docLong =+            [   keyword "if" <> " " <> prettyExpression a+            ,   prettyExpression b+            ]+    docsLong (Note  _    c) = docsLong c+    docsLong             c  = [ prettyExpression c ] -        short = forall <> lparen-            <>  prettyLabel a-            <>  space <> colon <> space-            <>  prettyExprA b-            <>  rparen-    docs (Note _   c) = docs c-    docs           c  = [ prettyExprB c ]-prettyExprB a0@(Let _ _ _ _) =+    docsShort (BoolIf a b c) =+        docShort ++ docsShort c+      where+        docShort =+            [   keyword "if" <> " " <> prettyExpression a+            ,   prettyExpression b+            ]+    docsShort (Note  _    c) = docsShort c+    docsShort             c  = [ prettyExpression c ]+prettyExpression a0@(Let _ _ _ _) =     enclose' "" "    " (space <> keyword "in" <> space) (Pretty.hardline <> keyword "in" <> "  ")         (fmap duplicate (docs a0))   where@@ -439,13 +418,13 @@                 <>  space <> equals                 <>  Pretty.hardline                 <>  "  "-                <>  prettyExprA c+                <>  prettyExpression c                 )          short = keyword "let" <> space             <>  prettyLabel a             <>  (space <> equals <> space)-            <>  prettyExprA c+            <>  prettyExpression c     docs (Let a (Just b) c d) =         Pretty.group (Pretty.flatAlt long short) : docs d       where@@ -454,328 +433,381 @@                 (   prettyLabel a                 <>  Pretty.hardline                 <>  colon <> space-                <>  prettyExprA b+                <>  prettyExpression b                 <>  Pretty.hardline                 <>  equals <> space-                <>  prettyExprA c+                <>  prettyExpression c                 )          short = keyword "let" <> space             <>  prettyLabel a             <>  space <> colon <> space-            <>  prettyExprA b+            <>  prettyExpression b             <>  space <> equals <> space-            <>  prettyExprA c+            <>  prettyExpression c     docs (Note _ d)  =         docs d     docs d =-        [ prettyExprB d ]-prettyExprB (ListLit Nothing b) =-    list (map prettyExprA (Data.Foldable.toList b))-prettyExprB (ListLit (Just a) b) =-        list (map prettyExprA (Data.Foldable.toList b))-    <>  " : "-    <>  prettyExprD (App List a)-prettyExprB (OptionalLit a b) =-        list (map prettyExprA (Data.Foldable.toList b))-    <>  " : "-    <>  prettyExprD (App Optional a)-prettyExprB (Merge a b (Just c)) =+        [ prettyExpression d ]+prettyExpression a0@(Pi _ _ _) =+    arrows (fmap duplicate (docs a0))+  where+    docs (Pi "_" b c) = prettyOperatorExpression b : docs c+    docs (Pi a   b c) = Pretty.group (Pretty.flatAlt long short) : docs c+      where+        long =  forall <> space+            <>  Pretty.align+                (   lparen <> space+                <>  prettyLabel a+                <>  Pretty.hardline+                <>  colon <> space+                <>  prettyExpression b+                <>  Pretty.hardline+                <>  rparen+                )++        short = forall <> lparen+            <>  prettyLabel a+            <>  space <> colon <> space+            <>  prettyExpression b+            <>  rparen+    docs (Note _   c) = docs c+    docs           c  = [ prettyExpression c ]+prettyExpression (Note _ a) =+    prettyExpression a+prettyExpression a0 =+    prettyAnnotatedExpression a0++prettyAnnotatedExpression :: Pretty a => Expr s a -> Doc Ann+prettyAnnotatedExpression (Merge a b (Just c)) =     Pretty.group (Pretty.flatAlt long short)   where     long =         Pretty.align             (   keyword "merge"             <>  Pretty.hardline-            <>  prettyExprE a+            <>  prettyImportExpression a             <>  Pretty.hardline-            <>  prettyExprE b+            <>  prettyImportExpression b             <>  Pretty.hardline             <>  colon <> space-            <>  prettyExprD c+            <>  prettyApplicationExpression c             )      short = keyword "merge" <> space-        <>  prettyExprE a+        <>  prettyImportExpression a         <>  " "-        <>  prettyExprE b+        <>  prettyImportExpression b         <>  space <> colon <> space-        <>  prettyExprD c-prettyExprB (Merge a b Nothing) =+        <>  prettyApplicationExpression c+prettyAnnotatedExpression (Merge a b Nothing) =     Pretty.group (Pretty.flatAlt long short)   where     long =         Pretty.align             (   keyword "merge"             <>  Pretty.hardline-            <>  prettyExprE a+            <>  prettyImportExpression a             <>  Pretty.hardline-            <>  prettyExprE b+            <>  prettyImportExpression b             )      short = keyword "merge" <> space-        <>  prettyExprE a+        <>  prettyImportExpression a         <>  " "-        <>  prettyExprE b-prettyExprB (Note _ b) =-    prettyExprB b-prettyExprB a =-    prettyExprC a+        <>  prettyImportExpression b+prettyAnnotatedExpression a0@(Annot _ _) =+    enclose'+        ""+        "  "+        (" " <> colon <> " ")+        (colon <> space)+        (fmap duplicate (docs a0))+  where+    docs (Annot a b) = prettyOperatorExpression a : docs b+    docs (Note  _ b) = docs b+    docs          b  = [ prettyExpression b ]+prettyAnnotatedExpression (ListLit (Just a) b) =+        list (map prettyExpression (Data.Foldable.toList b))+    <>  " : "+    <>  prettyApplicationExpression (App List a)+prettyAnnotatedExpression (OptionalLit a b) =+        list (map prettyExpression (Data.Foldable.toList b))+    <>  " : "+    <>  prettyApplicationExpression (App Optional a)+prettyAnnotatedExpression (Note _ a) =+    prettyAnnotatedExpression a+prettyAnnotatedExpression a0 =+    prettyOperatorExpression a0 -prettyExprC :: Pretty a => Expr s a -> Doc Ann-prettyExprC = prettyExprC0+prettyOperatorExpression :: Pretty a => Expr s a -> Doc Ann+prettyOperatorExpression = prettyOrExpression -prettyExprC0 :: Pretty a => Expr s a -> Doc Ann-prettyExprC0 a0@(BoolOr _ _) =+prettyOrExpression :: Pretty a => Expr s a -> Doc Ann+prettyOrExpression a0@(BoolOr _ _) =     enclose' "" "    " (space <> operator "||" <> space) (operator "||" <> "  ") (fmap duplicate (docs a0))   where-    docs (BoolOr a b) = prettyExprC1 a : docs b+    docs (BoolOr a b) = prettyPlusExpression a : docs b     docs (Note   _ b) = docs b-    docs           b  = [ prettyExprC1 b ]-prettyExprC0 (Note _ a) =-    prettyExprC0 a-prettyExprC0 a0 =-    prettyExprC1 a0--prettyExprC1 :: Pretty a => Expr s a -> Doc Ann-prettyExprC1 a0@(TextAppend _ _) =-    enclose' "" "    " (" " <> operator "++" <> " ") (operator "++" <> "  ") (fmap duplicate (docs a0))-  where-    docs (TextAppend a b) = prettyExprC2 a : docs b-    docs (Note       _ b) = docs b-    docs               b  = [ prettyExprC2 b ]-prettyExprC1 (Note _ a) =-    prettyExprC1 a-prettyExprC1 a0 =-    prettyExprC2 a0+    docs           b  = [ prettyPlusExpression b ]+prettyOrExpression (Note _ a) =+    prettyOrExpression a+prettyOrExpression a0 =+    prettyPlusExpression a0 -prettyExprC2 :: Pretty a => Expr s a -> Doc Ann-prettyExprC2 a0@(NaturalPlus _ _) =+prettyPlusExpression :: Pretty a => Expr s a -> Doc Ann+prettyPlusExpression a0@(NaturalPlus _ _) =     enclose' "" "  " (" " <> operator "+" <> " ") (operator "+" <> " ") (fmap duplicate (docs a0))   where-    docs (NaturalPlus a b) = prettyExprC3 a : docs b+    docs (NaturalPlus a b) = prettyTextAppendExpression a : docs b     docs (Note        _ b) = docs b-    docs                b  = [ prettyExprC3 b ]-prettyExprC2 (Note _ a) =-    prettyExprC2 a-prettyExprC2 a0 =-    prettyExprC3 a0+    docs                b  = [ prettyTextAppendExpression b ]+prettyPlusExpression (Note _ a) =+    prettyPlusExpression a+prettyPlusExpression a0 =+    prettyTextAppendExpression a0 -prettyExprC3 :: Pretty a => Expr s a -> Doc Ann-prettyExprC3 a0@(ListAppend _ _) =+prettyTextAppendExpression :: Pretty a => Expr s a -> Doc Ann+prettyTextAppendExpression a0@(TextAppend _ _) =+    enclose' "" "    " (" " <> operator "++" <> " ") (operator "++" <> "  ") (fmap duplicate (docs a0))+  where+    docs (TextAppend a b) = prettyListAppendExpression a : docs b+    docs (Note       _ b) = docs b+    docs               b  = [ prettyListAppendExpression b ]+prettyTextAppendExpression (Note _ a) =+    prettyTextAppendExpression a+prettyTextAppendExpression a0 =+    prettyListAppendExpression a0++prettyListAppendExpression :: Pretty a => Expr s a -> Doc Ann+prettyListAppendExpression a0@(ListAppend _ _) =     enclose' "" "  " (" " <> operator "#" <> " ") (operator "#" <> " ") (fmap duplicate (docs a0))   where-    docs (ListAppend a b) = prettyExprC4 a : docs b+    docs (ListAppend a b) = prettyAndExpression a : docs b     docs (Note       _ b) = docs b-    docs               b  = [ prettyExprC4 b ]-prettyExprC3 (Note _ a) =-    prettyExprC3 a-prettyExprC3 a0 =-    prettyExprC4 a0+    docs               b  = [ prettyAndExpression b ]+prettyListAppendExpression (Note _ a) =+    prettyListAppendExpression a+prettyListAppendExpression a0 =+    prettyAndExpression a0 -prettyExprC4 :: Pretty a => Expr s a -> Doc Ann-prettyExprC4 a0@(BoolAnd _ _) =+prettyAndExpression :: Pretty a => Expr s a -> Doc Ann+prettyAndExpression a0@(BoolAnd _ _) =     enclose' "" "    " (" " <> operator "&&" <> " ") (operator "&&" <> "  ") (fmap duplicate (docs a0))   where-    docs (BoolAnd a b) = prettyExprC5 a : docs b+    docs (BoolAnd a b) = prettyCombineExpression a : docs b     docs (Note    _ b) = docs b-    docs            b  = [ prettyExprC5 b ]-prettyExprC4 (Note _ a) =-    prettyExprC4 a-prettyExprC4 a0 =-   prettyExprC5 a0+    docs            b  = [ prettyCombineExpression b ]+prettyAndExpression (Note _ a) =+    prettyAndExpression a+prettyAndExpression a0 =+   prettyCombineExpression a0 -prettyExprC5 :: Pretty a => Expr s a -> Doc Ann-prettyExprC5 a0@(Combine _ _) =+prettyCombineExpression :: Pretty a => Expr s a -> Doc Ann+prettyCombineExpression a0@(Combine _ _) =     enclose' "" "  " (" " <> operator "∧" <> " ") (operator "∧" <> " ") (fmap duplicate (docs a0))   where-    docs (Combine a b) = prettyExprC6 a : docs b+    docs (Combine a b) = prettyPreferExpression a : docs b     docs (Note    _ b) = docs b-    docs            b  = [ prettyExprC6 b ]-prettyExprC5 (Note _ a) =-    prettyExprC5 a-prettyExprC5 a0 =-    prettyExprC6 a0+    docs            b  = [ prettyPreferExpression b ]+prettyCombineExpression (Note _ a) =+    prettyCombineExpression a+prettyCombineExpression a0 =+    prettyPreferExpression a0 -prettyExprC6 :: Pretty a => Expr s a -> Doc Ann-prettyExprC6 a0@(Prefer _ _) =+prettyPreferExpression :: Pretty a => Expr s a -> Doc Ann+prettyPreferExpression a0@(Prefer _ _) =     enclose' "" "  " (" " <> operator "⫽" <> " ") (operator "⫽" <> " ") (fmap duplicate (docs a0))   where-    docs (Prefer a b) = prettyExprC7 a : docs b+    docs (Prefer a b) = prettyCombineTypesExpression a : docs b     docs (Note   _ b) = docs b-    docs           b  = [ prettyExprC7 b ]-prettyExprC6 (Note _ a) =-    prettyExprC6 a-prettyExprC6 a0 =-    prettyExprC7 a0+    docs           b  = [ prettyCombineTypesExpression b ]+prettyPreferExpression (Note _ a) =+    prettyPreferExpression a+prettyPreferExpression a0 =+    prettyCombineTypesExpression a0 -prettyExprC7 :: Pretty a => Expr s a -> Doc Ann-prettyExprC7 a0@(CombineTypes _ _) =+prettyCombineTypesExpression :: Pretty a => Expr s a -> Doc Ann+prettyCombineTypesExpression a0@(CombineTypes _ _) =     enclose' "" "  " (" " <> operator "⩓" <> " ") (operator "⩓" <> " ") (fmap duplicate (docs a0))   where-    docs (CombineTypes a b) = prettyExprC8 a : docs b+    docs (CombineTypes a b) = prettyTimesExpression a : docs b     docs (Note         _ b) = docs b-    docs                 b  = [ prettyExprC8 b ]-prettyExprC7 (Note _ a) =-    prettyExprC7 a-prettyExprC7 a0 =-    prettyExprC8 a0+    docs                 b  = [ prettyTimesExpression b ]+prettyCombineTypesExpression (Note _ a) =+    prettyCombineTypesExpression a+prettyCombineTypesExpression a0 =+    prettyTimesExpression a0 -prettyExprC8 :: Pretty a => Expr s a -> Doc Ann-prettyExprC8 a0@(NaturalTimes _ _) =+prettyTimesExpression :: Pretty a => Expr s a -> Doc Ann+prettyTimesExpression a0@(NaturalTimes _ _) =     enclose' "" "  " (" " <> operator "*" <> " ") (operator "*" <> " ") (fmap duplicate (docs a0))   where-    docs (NaturalTimes a b) = prettyExprC9 a : docs b+    docs (NaturalTimes a b) = prettyEqualExpression a : docs b     docs (Note         _ b) = docs b-    docs                 b  = [ prettyExprC9 b ]-prettyExprC8 (Note _ a) =-    prettyExprC8 a-prettyExprC8 a0 =-    prettyExprC9 a0+    docs                 b  = [ prettyEqualExpression b ]+prettyTimesExpression (Note _ a) =+    prettyTimesExpression a+prettyTimesExpression a0 =+    prettyEqualExpression a0 -prettyExprC9 :: Pretty a => Expr s a -> Doc Ann-prettyExprC9 a0@(BoolEQ _ _) =+prettyEqualExpression :: Pretty a => Expr s a -> Doc Ann+prettyEqualExpression a0@(BoolEQ _ _) =     enclose' "" "    " (" " <> operator "==" <> " ") (operator "==" <> "  ") (fmap duplicate (docs a0))   where-    docs (BoolEQ a b) = prettyExprC10 a : docs b+    docs (BoolEQ a b) = prettyNotEqualExpression a : docs b     docs (Note   _ b) = docs b-    docs           b  = [ prettyExprC10 b ]-prettyExprC9 (Note _ a) =-    prettyExprC9 a-prettyExprC9 a0 =-    prettyExprC10 a0+    docs           b  = [ prettyNotEqualExpression b ]+prettyEqualExpression (Note _ a) =+    prettyEqualExpression a+prettyEqualExpression a0 =+    prettyNotEqualExpression a0 -prettyExprC10 :: Pretty a => Expr s a -> Doc Ann-prettyExprC10 a0@(BoolNE _ _) =+prettyNotEqualExpression :: Pretty a => Expr s a -> Doc Ann+prettyNotEqualExpression a0@(BoolNE _ _) =     enclose' "" "    " (" " <> operator "!=" <> " ") (operator "!=" <> "  ") (fmap duplicate (docs a0))   where-    docs (BoolNE a b) = prettyExprD a : docs b+    docs (BoolNE a b) = prettyApplicationExpression a : docs b     docs (Note   _ b) = docs b-    docs           b  = [ prettyExprD b ]-prettyExprC10 (Note _ a) =-    prettyExprC10 a-prettyExprC10 a0 =-    prettyExprD a0+    docs           b  = [ prettyApplicationExpression b ]+prettyNotEqualExpression (Note _ a) =+    prettyNotEqualExpression a+prettyNotEqualExpression a0 =+    prettyApplicationExpression a0 -prettyExprD :: Pretty a => Expr s a -> Doc Ann-prettyExprD a0 = case a0 of+prettyApplicationExpression :: Pretty a => Expr s a -> Doc Ann+prettyApplicationExpression a0 = case a0 of     App _ _        -> result     Constructors _ -> result-    Note _ b       -> prettyExprD b-    _              -> prettyExprE a0+    Note _ b       -> prettyApplicationExpression b+    _              -> prettyImportExpression a0   where     result = enclose' "" "" " " "" (fmap duplicate (reverse (docs a0))) -    docs (App        a b) = prettyExprE b : docs a-    docs (Constructors b) = [ prettyExprE b , keyword "constructors" ]+    docs (App        a b) = prettyImportExpression b : docs a+    docs (Constructors b) = [ prettyImportExpression b , keyword "constructors" ]     docs (Note       _ b) = docs b-    docs               b  = [ prettyExprE b ]+    docs               b  = [ prettyImportExpression b ] -prettyExprE :: Pretty a => Expr s a -> Doc Ann-prettyExprE (Field   a b) = prettyExprE a <> dot <> prettyLabel b-prettyExprE (Project a b) = prettyExprE a <> dot <> prettyLabels b-prettyExprE (Note    _ b) = prettyExprE b-prettyExprE  a            = prettyExprF a+prettyImportExpression :: Pretty a => Expr s a -> Doc Ann+prettyImportExpression (Embed a) =+    Pretty.pretty a+prettyImportExpression (Note _ a) =+    prettyImportExpression a+prettyImportExpression a0 =+    prettySelectorExpression a0 -prettyExprF :: Pretty a => Expr s a -> Doc Ann-prettyExprF (Var a) =+prettySelectorExpression :: Pretty a => Expr s a -> Doc Ann+prettySelectorExpression (Field a b) =+    prettySelectorExpression a <> dot <> prettyLabel b+prettySelectorExpression (Project a b) =+    prettySelectorExpression a <> dot <> prettyLabels b+prettySelectorExpression (Note _ b) =+    prettySelectorExpression b+prettySelectorExpression a0 =+    prettyPrimitiveExpression a0++prettyPrimitiveExpression :: Pretty a => Expr s a -> Doc Ann+prettyPrimitiveExpression (Var a) =     prettyVar a-prettyExprF (Const k) =+prettyPrimitiveExpression (Const k) =     prettyConst k-prettyExprF Bool =+prettyPrimitiveExpression Bool =     builtin "Bool"-prettyExprF Natural =+prettyPrimitiveExpression Natural =     builtin "Natural"-prettyExprF NaturalFold =+prettyPrimitiveExpression NaturalFold =     builtin "Natural/fold"-prettyExprF NaturalBuild =+prettyPrimitiveExpression NaturalBuild =     builtin "Natural/build"-prettyExprF NaturalIsZero =+prettyPrimitiveExpression NaturalIsZero =     builtin "Natural/isZero"-prettyExprF NaturalEven =+prettyPrimitiveExpression NaturalEven =     builtin "Natural/even"-prettyExprF NaturalOdd =+prettyPrimitiveExpression NaturalOdd =     builtin "Natural/odd"-prettyExprF NaturalToInteger =+prettyPrimitiveExpression NaturalToInteger =     builtin "Natural/toInteger"-prettyExprF NaturalShow =+prettyPrimitiveExpression NaturalShow =     builtin "Natural/show"-prettyExprF Integer =+prettyPrimitiveExpression Integer =     builtin "Integer"-prettyExprF IntegerShow =+prettyPrimitiveExpression IntegerShow =     builtin "Integer/show"-prettyExprF Double =+prettyPrimitiveExpression IntegerToDouble =+    builtin "Integer/toDouble"+prettyPrimitiveExpression Double =     builtin "Double"-prettyExprF DoubleShow =+prettyPrimitiveExpression DoubleShow =     builtin "Double/show"-prettyExprF Text =+prettyPrimitiveExpression Text =     builtin "Text"-prettyExprF List =+prettyPrimitiveExpression List =     builtin "List"-prettyExprF ListBuild =+prettyPrimitiveExpression ListBuild =     builtin "List/build"-prettyExprF ListFold =+prettyPrimitiveExpression ListFold =     builtin "List/fold"-prettyExprF ListLength =+prettyPrimitiveExpression ListLength =     builtin "List/length"-prettyExprF ListHead =+prettyPrimitiveExpression ListHead =     builtin "List/head"-prettyExprF ListLast =+prettyPrimitiveExpression ListLast =     builtin "List/last"-prettyExprF ListIndexed =+prettyPrimitiveExpression ListIndexed =     builtin "List/indexed"-prettyExprF ListReverse =+prettyPrimitiveExpression ListReverse =     builtin "List/reverse"-prettyExprF Optional =+prettyPrimitiveExpression Optional =     builtin "Optional"-prettyExprF OptionalFold =+prettyPrimitiveExpression OptionalFold =     builtin "Optional/fold"-prettyExprF OptionalBuild =+prettyPrimitiveExpression OptionalBuild =     builtin "Optional/build"-prettyExprF (BoolLit True) =+prettyPrimitiveExpression (BoolLit True) =     builtin "True"-prettyExprF (BoolLit False) =+prettyPrimitiveExpression (BoolLit False) =     builtin "False"-prettyExprF (IntegerLit a)+prettyPrimitiveExpression (IntegerLit a)     | 0 <= a    = literal "+" <> prettyNumber a     | otherwise = prettyNumber a-prettyExprF (NaturalLit a) =+prettyPrimitiveExpression (NaturalLit a) =     prettyNatural a-prettyExprF (DoubleLit a) =+prettyPrimitiveExpression (DoubleLit a) =     prettyScientific a-prettyExprF (TextLit a) =+prettyPrimitiveExpression (TextLit a) =     prettyChunks a-prettyExprF (Record a) =+prettyPrimitiveExpression (Record a) =     prettyRecord a-prettyExprF (RecordLit a) =+prettyPrimitiveExpression (RecordLit a) =     prettyRecordLit a-prettyExprF (Union a) =+prettyPrimitiveExpression (Union a) =     prettyUnion a-prettyExprF (UnionLit a b c) =+prettyPrimitiveExpression (UnionLit a b c) =     prettyUnionLit a b c-prettyExprF (ListLit Nothing b) =-    list (map prettyExprA (Data.Foldable.toList b))-prettyExprF (Embed a) =-    Pretty.pretty a-prettyExprF (Note _ b) =-    prettyExprF b-prettyExprF a =+prettyPrimitiveExpression (ListLit Nothing b) =+    list (map prettyExpression (Data.Foldable.toList b))+prettyPrimitiveExpression (Note _ b) =+    prettyPrimitiveExpression b+prettyPrimitiveExpression a =     Pretty.group (Pretty.flatAlt long short)   where-    long = Pretty.align (lparen <> space <> prettyExprA a <> Pretty.hardline <> rparen)+    long =+        Pretty.align+            (lparen <> space <> prettyExpression a <> Pretty.hardline <> rparen) -    short = lparen <> prettyExprA a <> rparen+    short = lparen <> prettyExpression a <> rparen  prettyKeyValue :: Pretty a => Doc Ann -> (Text, Expr s a) -> (Doc Ann, Doc Ann) prettyKeyValue separator (key, value) =-    (   prettyLabel key <> " " <> separator <> " " <> prettyExprA value+    (   prettyLabel key <> " " <> separator <> " " <> prettyExpression value     ,       prettyLabel key         <>  " "         <>  separator         <>  long     )   where-    long = Pretty.hardline <> "    " <> prettyExprA value+    long = Pretty.hardline <> "    " <> prettyExpression value  prettyRecord :: Pretty a => InsOrdHashMap Text (Expr s a) -> Doc Ann prettyRecord =@@ -803,56 +835,27 @@  -- | Pretty-print a value pretty :: Pretty a => a -> Text-pretty = Pretty.renderLazy . Pretty.layoutPretty options . Pretty.pretty+pretty = Pretty.renderStrict . Pretty.layoutPretty options . Pretty.pretty   where    options = Pretty.LayoutOptions { Pretty.layoutPageWidth = Pretty.Unbounded } --- | Builder corresponding to the @label@ token in "Dhall.Parser"-buildLabel :: Text -> Builder-buildLabel l = case Text.uncons l of-    Just (h, t)-        | headCharacter h && Text.all tailCharacter t && not (Data.HashSet.member l reservedIdentifiers)-            -> build l-    _       -> "`" <> build l <> "`"----- | Builder corresponding to the @number@ token in "Dhall.Parser"-buildNumber :: Integer -> Builder-buildNumber a = build (show a)---- | Builder corresponding to the @natural@ token in "Dhall.Parser"-buildNatural :: Natural -> Builder-buildNatural a = build (show a)---- | Builder corresponding to the @double@ token in "Dhall.Parser"-buildScientific :: Scientific -> Builder-buildScientific = build . show---- | Builder corresponding to the @text@ token in "Dhall.Parser"-buildChunks :: Buildable a => Chunks s a -> Builder-buildChunks (Chunks a b) = "\"" <> foldMap buildChunk a <> escapeText b <> "\""-  where-    buildChunk (c, d) = escapeText c <> "${" <> buildExprA d <> "}"---- | Escape a `Builder` literal using Dhall's escaping rules for single-quoted+-- | Escape a `Text` literal using Dhall's escaping rules for single-quoted --   @Text@-escapeSingleQuotedText :: Builder -> Builder+escapeSingleQuotedText :: Text -> Text escapeSingleQuotedText inputBuilder = outputBuilder   where-    inputText = Builder.toLazyText inputBuilder--    outputText = substitute "${" "''${" (substitute "''" "'''" inputText)+    outputText = substitute "${" "''${" (substitute "''" "'''" inputBuilder) -    outputBuilder = Builder.fromLazyText outputText+    outputBuilder = outputText      substitute before after = Text.intercalate after . Text.splitOn before -{-| Escape a `Builder` literal using Dhall's escaping rules-  +{-| Escape a `Text` literal using Dhall's escaping rules+     Note that the result does not include surrounding quotes -}-escapeText :: Builder -> Builder-escapeText a = Builder.fromLazyText (Text.concatMap adapt text)+escapeText :: Text -> Text+escapeText text = Text.concatMap adapt text   where     adapt c         | '\x20' <= c && c <= '\x21' = Text.singleton c@@ -882,331 +885,16 @@         | n < 10    = Data.Char.chr (Data.Char.ord '0' + n)         | otherwise = Data.Char.chr (Data.Char.ord 'A' + n - 10) -    text = Builder.toLazyText a---- | Builder corresponding to the @expr@ parser in "Dhall.Parser"-buildExpr :: Buildable a => Expr s a -> Builder-buildExpr = buildExprA---- | Builder corresponding to the @exprA@ parser in "Dhall.Parser"-buildExprA :: Buildable a => Expr s a -> Builder-buildExprA (Annot a b) = buildExprB a <> " : " <> buildExprA b-buildExprA (Note  _ b) = buildExprA b-buildExprA a           = buildExprB a---- | Builder corresponding to the @exprB@ parser in "Dhall.Parser"-buildExprB :: Buildable a => Expr s a -> Builder-buildExprB (Lam a b c) =-        "λ("-    <>  buildLabel a-    <>  " : "-    <>  buildExprA b-    <>  ") → "-    <>  buildExprB c-buildExprB (BoolIf a b c) =-        "if "-    <>  buildExprA a-    <>  " then "-    <>  buildExprA b-    <>  " else "-    <>  buildExprA c-buildExprB (Pi "_" b c) =-        buildExprC b-    <>  " → "-    <>  buildExprB c-buildExprB (Pi a b c) =-        "∀("-    <>  buildLabel a-    <>  " : "-    <>  buildExprA b-    <>  ") → "-    <>  buildExprB c-buildExprB (Let a Nothing c d) =-        "let "-    <>  buildLabel a-    <>  " = "-    <>  buildExprA c-    <>  " in "-    <>  buildExprB d-buildExprB (Let a (Just b) c d) =-        "let "-    <>  buildLabel a-    <>  " : "-    <>  buildExprA b-    <>  " = "-    <>  buildExprA c-    <>  " in "-    <>  buildExprB d-buildExprB (ListLit Nothing b) =-    "[" <> buildElems (Data.Foldable.toList b) <> "]"-buildExprB (ListLit (Just a) b) =-    "[" <> buildElems (Data.Foldable.toList b) <> "] : List "  <> buildExprE a-buildExprB (OptionalLit a b) =-    "[" <> buildElems (Data.Foldable.toList b) <> "] : Optional "  <> buildExprE a-buildExprB (Merge a b (Just c)) =-    "merge " <> buildExprE a <> " " <> buildExprE b <> " : " <> buildExprD c-buildExprB (Merge a b Nothing) =-    "merge " <> buildExprE a <> " " <> buildExprE b-buildExprB (Note _ b) =-    buildExprB b-buildExprB a =-    buildExprC a---- | Builder corresponding to the @exprC@ parser in "Dhall.Parser"-buildExprC :: Buildable a => Expr s a -> Builder-buildExprC = buildExprC0---- | Builder corresponding to the @exprC0@ parser in "Dhall.Parser"-buildExprC0 :: Buildable a => Expr s a -> Builder-buildExprC0 (BoolOr a b) = buildExprC1 a <> " || " <> buildExprC0 b-buildExprC0 (Note   _ b) = buildExprC0 b-buildExprC0  a           = buildExprC1 a---- | Builder corresponding to the @exprC1@ parser in "Dhall.Parser"-buildExprC1 :: Buildable a => Expr s a -> Builder-buildExprC1 (TextAppend a b) = buildExprC2 a <> " ++ " <> buildExprC1 b-buildExprC1 (Note       _ b) = buildExprC1 b-buildExprC1  a               = buildExprC2 a---- | Builder corresponding to the @exprC2@ parser in "Dhall.Parser"-buildExprC2 :: Buildable a => Expr s a -> Builder-buildExprC2 (NaturalPlus a b) = buildExprC3 a <> " + " <> buildExprC2 b-buildExprC2 (Note        _ b) = buildExprC2 b-buildExprC2  a                = buildExprC3 a---- | Builder corresponding to the @exprC3@ parser in "Dhall.Parser"-buildExprC3 :: Buildable a => Expr s a -> Builder-buildExprC3 (ListAppend a b) = buildExprC4 a <> " # " <> buildExprC3 b-buildExprC3 (Note       _ b) = buildExprC3 b-buildExprC3  a               = buildExprC4 a---- | Builder corresponding to the @exprC4@ parser in "Dhall.Parser"-buildExprC4 :: Buildable a => Expr s a -> Builder-buildExprC4 (BoolAnd a b) = buildExprC5 a <> " && " <> buildExprC4 b-buildExprC4 (Note    _ b) = buildExprC4 b-buildExprC4  a            = buildExprC5 a---- | Builder corresponding to the @exprC5@ parser in "Dhall.Parser"-buildExprC5 :: Buildable a => Expr s a -> Builder-buildExprC5 (Combine   a b) = buildExprC6 a <> " ∧ " <> buildExprC5 b-buildExprC5 (Note      _ b) = buildExprC5 b-buildExprC5  a              = buildExprC6 a---- | Builder corresponding to the @exprC6@ parser in "Dhall.Parser"-buildExprC6 :: Buildable a => Expr s a -> Builder-buildExprC6 (Prefer a b) = buildExprC7 a <> " ⫽ " <> buildExprC6 b-buildExprC6 (Note   _ b) = buildExprC6 b-buildExprC6  a           = buildExprC7 a---- | Builder corresponding to the @exprC7@ parser in "Dhall.Parser"-buildExprC7 :: Buildable a => Expr s a -> Builder-buildExprC7 (CombineTypes a b) = buildExprC8 a <> " ⩓ " <> buildExprC7 b-buildExprC7 (Note         _ b) = buildExprC7 b-buildExprC7  a                 = buildExprC8 a---- | Builder corresponding to the @exprC8@ parser in "Dhall.Parser"-buildExprC8 :: Buildable a => Expr s a -> Builder-buildExprC8 (NaturalTimes a b) = buildExprC9 a <> " * " <> buildExprC8 b-buildExprC8 (Note         _ b) = buildExprC8 b-buildExprC8  a                 = buildExprC9 a---- | Builder corresponding to the @exprC9@ parser in "Dhall.Parser"-buildExprC9 :: Buildable a => Expr s a -> Builder-buildExprC9 (BoolEQ a b) = buildExprC10 a <> " == " <> buildExprC9 b-buildExprC9 (Note   _ b) = buildExprC9 b-buildExprC9  a           = buildExprC10 a---- | Builder corresponding to the @exprC10@ parser in "Dhall.Parser"-buildExprC10 :: Buildable a => Expr s a -> Builder-buildExprC10 (BoolNE a b) = buildExprD  a <> " != " <> buildExprC10 b-buildExprC10 (Note   _ b) = buildExprC10 b-buildExprC10  a           = buildExprD  a---- | Builder corresponding to the @exprD@ parser in "Dhall.Parser"-buildExprD :: Buildable a => Expr s a -> Builder-buildExprD (App        a b) = buildExprD a <> " " <> buildExprE b-buildExprD (Constructors b) = "constructors " <> buildExprE b-buildExprD (Note       _ b) = buildExprD b-buildExprD  a               = buildExprE a---- | Builder corresponding to the @exprE@ parser in "Dhall.Parser"-buildExprE :: Buildable a => Expr s a -> Builder-buildExprE (Field a b) = buildExprE a <> "." <> buildLabel b-buildExprE (Note  _ b) = buildExprE b-buildExprE  a          = buildExprF a---- | Builder corresponding to the @exprF@ parser in "Dhall.Parser"-buildExprF :: Buildable a => Expr s a -> Builder-buildExprF (Var a) =-    buildVar a-buildExprF (Const k) =-    buildConst k-buildExprF Bool =-    "Bool"-buildExprF Natural =-    "Natural"-buildExprF NaturalFold =-    "Natural/fold"-buildExprF NaturalBuild =-    "Natural/build"-buildExprF NaturalIsZero =-    "Natural/isZero"-buildExprF NaturalEven =-    "Natural/even"-buildExprF NaturalOdd =-    "Natural/odd"-buildExprF NaturalToInteger =-    "Natural/toInteger"-buildExprF NaturalShow =-    "Natural/show"-buildExprF Integer =-    "Integer"-buildExprF IntegerShow =-    "Integer/show"-buildExprF Double =-    "Double"-buildExprF DoubleShow =-    "Double/show"-buildExprF Text =-    "Text"-buildExprF List =-    "List"-buildExprF ListBuild =-    "List/build"-buildExprF ListFold =-    "List/fold"-buildExprF ListLength =-    "List/length"-buildExprF ListHead =-    "List/head"-buildExprF ListLast =-    "List/last"-buildExprF ListIndexed =-    "List/indexed"-buildExprF ListReverse =-    "List/reverse"-buildExprF Optional =-    "Optional"-buildExprF OptionalFold =-    "Optional/fold"-buildExprF OptionalBuild =-    "Optional/build"-buildExprF (BoolLit True) =-    "True"-buildExprF (BoolLit False) =-    "False"-buildExprF (IntegerLit a)-    | 0 <= a    = "+" <> buildNumber a-    | otherwise = buildNumber a-buildExprF (NaturalLit a) =-    buildNatural a-buildExprF (DoubleLit a) =-    buildScientific a-buildExprF (TextLit a) =-    buildChunks a-buildExprF (Record a) =-    buildRecord a-buildExprF (RecordLit a) =-    buildRecordLit a-buildExprF (Union a) =-    buildUnion a-buildExprF (UnionLit a b c) =-    buildUnionLit a b c-buildExprF (ListLit Nothing b) =-    "[" <> buildElems (Data.Foldable.toList b) <> "]"-buildExprF (Embed a) =-    build a-buildExprF (Note _ b) =-    buildExprF b-buildExprF a =-    "(" <> buildExprA a <> ")"---- | Builder corresponding to the @const@ parser in "Dhall.Parser"-buildConst :: Const -> Builder-buildConst Type = "Type"-buildConst Kind = "Kind"---- | Builder corresponding to the @var@ parser in "Dhall.Parser"-buildVar :: Var -> Builder-buildVar (V x 0) = buildLabel x-buildVar (V x n) = buildLabel x <> "@" <> buildNumber n---- | Builder corresponding to the @elems@ parser in "Dhall.Parser"-buildElems :: Buildable a => [Expr s a] -> Builder-buildElems   []   = ""-buildElems   [a]  = buildExprA a-buildElems (a:bs) = buildExprA a <> ", " <> buildElems bs---- | Builder corresponding to the @recordLit@ parser in "Dhall.Parser"-buildRecordLit :: Buildable a => InsOrdHashMap Text (Expr s a) -> Builder-buildRecordLit a | Data.HashMap.Strict.InsOrd.null a =-    "{=}"-buildRecordLit a =-    "{ " <> buildFieldValues (Data.HashMap.Strict.InsOrd.toList a) <> " }"---- | Builder corresponding to the @fieldValues@ parser in "Dhall.Parser"-buildFieldValues :: Buildable a => [(Text, Expr s a)] -> Builder-buildFieldValues    []  = ""-buildFieldValues   [a]  = buildFieldValue a-buildFieldValues (a:bs) = buildFieldValue a <> ", " <> buildFieldValues bs---- | Builder corresponding to the @fieldValue@ parser in "Dhall.Parser"-buildFieldValue :: Buildable a => (Text, Expr s a) -> Builder-buildFieldValue (a, b) = buildLabel a <> " = " <> buildExprA b---- | Builder corresponding to the @record@ parser in "Dhall.Parser"-buildRecord :: Buildable a => InsOrdHashMap Text (Expr s a) -> Builder-buildRecord a | Data.HashMap.Strict.InsOrd.null a =-    "{}"-buildRecord a =-    "{ " <> buildFieldTypes (Data.HashMap.Strict.InsOrd.toList a) <> " }"---- | Builder corresponding to the @fieldTypes@ parser in "Dhall.Parser"-buildFieldTypes :: Buildable a => [(Text, Expr s a)] -> Builder-buildFieldTypes    []  = ""-buildFieldTypes   [a]  = buildFieldType a-buildFieldTypes (a:bs) = buildFieldType a <> ", " <> buildFieldTypes bs---- | Builder corresponding to the @fieldType@ parser in "Dhall.Parser"-buildFieldType :: Buildable a => (Text, Expr s a) -> Builder-buildFieldType (a, b) = buildLabel a <> " : " <> buildExprA b---- | Builder corresponding to the @union@ parser in "Dhall.Parser"-buildUnion :: Buildable a => InsOrdHashMap Text (Expr s a) -> Builder-buildUnion a | Data.HashMap.Strict.InsOrd.null a =-    "<>"-buildUnion a =-    "< " <> buildAlternativeTypes (Data.HashMap.Strict.InsOrd.toList a) <> " >"---- | Builder corresponding to the @alternativeTypes@ parser in "Dhall.Parser"-buildAlternativeTypes :: Buildable a => [(Text, Expr s a)] -> Builder-buildAlternativeTypes [] =-    ""-buildAlternativeTypes [a] =-    buildAlternativeType a-buildAlternativeTypes (a:bs) =-    buildAlternativeType a <> " | " <> buildAlternativeTypes bs+prettyToString :: Pretty a => a -> String+prettyToString =+    Pretty.renderString . Pretty.layoutPretty options . Pretty.pretty+  where+   options = Pretty.LayoutOptions { Pretty.layoutPageWidth = Pretty.Unbounded } --- | Builder corresponding to the @alternativeType@ parser in "Dhall.Parser"-buildAlternativeType :: Buildable a => (Text, Expr s a) -> Builder-buildAlternativeType (a, b) = buildLabel a <> " : " <> buildExprA b+docToStrictText :: Doc ann -> Text.Text+docToStrictText = Pretty.renderStrict . Pretty.layoutPretty options+  where+   options = Pretty.LayoutOptions { Pretty.layoutPageWidth = Pretty.Unbounded } --- | Builder corresponding to the @unionLit@ parser in "Dhall.Parser"-buildUnionLit-    :: Buildable a-    => Text -> Expr s a -> InsOrdHashMap Text (Expr s a) -> Builder-buildUnionLit a b c-    | Data.HashMap.Strict.InsOrd.null c =-            "< "-        <>  buildLabel a-        <>  " = "-        <>  buildExprA b-        <>  " >"-    | otherwise =-            "< "-        <>  buildLabel a-        <>  " = "-        <>  buildExprA b-        <>  " | "-        <>  buildAlternativeTypes (Data.HashMap.Strict.InsOrd.toList c)-        <>  " >"+prettyToStrictText :: Pretty a => a -> Text.Text+prettyToStrictText = docToStrictText . Pretty.pretty
src/Dhall/Pretty/Internal.hs-boot view
@@ -1,31 +1,18 @@ module Dhall.Pretty.Internal where -import Data.Scientific (Scientific)-import Data.Text.Lazy (Text)-import Data.Text.Lazy.Builder (Builder)+import Data.Text (Text) import Data.Text.Prettyprint.Doc (Pretty, Doc)-import Formatting.Buildable (Buildable)-import Numeric.Natural (Natural)-import Prelude  import {-# SOURCE #-} Dhall.Core  data Ann -buildConst :: Const -> Builder--buildVar :: Var -> Builder+prettyVar :: Var -> Doc Ann -buildExpr :: Buildable a => Expr s a -> Builder+prettyConst :: Const -> Doc Ann  prettyExpr :: Pretty a => Expr s a -> Doc Ann -buildNatural :: Natural -> Builder--buildNumber :: Integer -> Builder--buildScientific :: Scientific -> Builder- pretty :: Pretty a => a -> Text -escapeText :: Builder -> Builder+escapeText :: Text -> Text
+ src/Dhall/Repl.hs view
@@ -0,0 +1,258 @@+{-# language FlexibleContexts #-}+{-# language NamedFieldPuns #-}+{-# language OverloadedStrings #-}++module Dhall.Repl ( repl ) where++import Control.Exception ( SomeException(SomeException), displayException, throwIO )+import Control.Monad.IO.Class ( MonadIO, liftIO )+import Control.Monad.State.Class ( MonadState, get, modify )+import Control.Monad.State.Strict ( evalStateT )+import Data.List ( foldl' )++import qualified Data.Text as Text+import qualified Data.Text.Prettyprint.Doc as Pretty+import qualified Data.Text.Prettyprint.Doc.Render.Terminal as Pretty ( renderIO )+import qualified Dhall+import qualified Dhall.Context+import qualified Dhall.Core as Dhall ( Var(V), Expr, normalize )+import qualified Dhall.Pretty+import qualified Dhall.Core as Expr ( Expr(..) )+import qualified Dhall.Import as Dhall+import qualified Dhall.Parser as Dhall+import qualified Dhall.TypeCheck as Dhall+import qualified System.Console.ANSI+import qualified System.Console.Haskeline.MonadException as Haskeline+import qualified System.Console.Repline as Repline+import qualified System.IO+++repl :: Bool -> IO ()+repl explain = if explain then Dhall.detailed io else io+  where+    io =+      evalStateT+        ( Repline.evalRepl+            "⊢ "+            ( dontCrash . eval )+            options+        ( Repline.Word completer )+            greeter+        )+        (emptyEnv { explain })+++data Env = Env+  { envBindings :: Dhall.Context.Context Binding+  , envIt :: Maybe Binding+  , explain :: Bool+  }+++emptyEnv :: Env+emptyEnv =+  Env+    { envBindings = Dhall.Context.empty+    , envIt = Nothing+    , explain = False+    }+++data Binding = Binding+  { bindingExpr :: Dhall.Expr Dhall.Src Dhall.X+  , bindingType :: Dhall.Expr Dhall.Src Dhall.X+  }+++envToContext :: Env -> Dhall.Context.Context Binding+envToContext Env{ envBindings, envIt } =+  case envIt of+    Nothing ->+      envBindings++    Just it ->+      Dhall.Context.insert "it" it envBindings+++parseAndLoad+  :: ( MonadIO m, MonadState Env m )+  => String -> m ( Dhall.Expr Dhall.Src Dhall.X )+parseAndLoad src = do+  parsed <-+    case Dhall.exprFromText "(stdin)" ( Text.pack src ) of+      Left e ->+        liftIO ( throwIO e )++      Right a ->+        return a++  liftIO ( Dhall.load parsed )+++eval :: ( MonadIO m, MonadState Env m ) => String -> m ()+eval src = do+  loaded <-+    parseAndLoad src++  exprType <-+    typeCheck loaded++  expr <-+    normalize loaded++  modify ( \e -> e { envIt = Just ( Binding expr exprType ) } )++  output System.IO.stdout expr++++typeOf :: ( MonadIO m, MonadState Env m ) => [String] -> m ()+typeOf [] =+  liftIO ( putStrLn ":type requires an argument to check the type of" )+++typeOf srcs = do+  loaded <-+    parseAndLoad ( unwords srcs )++  exprType <-+    typeCheck loaded++  exprType' <-+    normalize exprType++  output System.IO.stdout exprType'++++normalize+  :: MonadState Env m+  => Dhall.Expr Dhall.Src Dhall.X -> m ( Dhall.Expr t Dhall.X )+normalize e = do+  env <-+    get++  return+    ( Dhall.normalize+        ( foldl'+            ( \a (k, Binding { bindingType, bindingExpr }) ->+                Expr.Let k ( Just bindingType ) bindingExpr a+            )+            e+            ( Dhall.Context.toList ( envToContext env ) )+        )+    )+++typeCheck+  :: ( MonadIO m, MonadState Env m )+  => Dhall.Expr Dhall.Src Dhall.X -> m ( Dhall.Expr Dhall.Src Dhall.X )+typeCheck expr = do+  env <-+    get++  let wrap = if explain env then Dhall.detailed else id++  case Dhall.typeWith ( bindingType <$> envToContext env ) expr of+    Left e ->+      liftIO ( wrap (throwIO e) )++    Right a ->+      return a+++addBinding :: ( MonadIO m, MonadState Env m ) => [String] -> m ()+addBinding (k : "=" : srcs) = do+  let+    varName =+      Text.pack k++  loaded <-+    parseAndLoad ( unwords srcs )++  t <-+    typeCheck loaded++  expr <-+    normalize loaded++  modify+    ( \e ->+        e+          { envBindings =+              Dhall.Context.insert+                varName+                Binding { bindingType = t, bindingExpr = expr }+                ( envBindings e )+          }+    )++  output+    System.IO.stdout+    ( Expr.Annot ( Expr.Var ( Dhall.V varName 0 ) ) t )++addBinding _ =+  liftIO ( fail ":let should be of the form `:let x = y`" )++saveBinding :: ( MonadIO m, MonadState Env m ) => [String] -> m ()+saveBinding (file : "=" : tokens) = do+  loadedExpression <- parseAndLoad (unwords tokens)++  _ <- typeCheck loadedExpression++  normalizedExpression <- normalize loadedExpression++  let handler handle = output handle normalizedExpression++  liftIO (System.IO.withFile file System.IO.WriteMode handler)+saveBinding _ = fail ":save should be of the form `:save x = y`"+++options+  :: ( Haskeline.MonadException m, MonadIO m, MonadState Env m )+  => Repline.Options m+options =+  [ ( "type", dontCrash . typeOf )+  , ( "let", dontCrash . addBinding )+  , ( "save", dontCrash . saveBinding )+  ]+++completer :: Monad m => Repline.WordCompleter m+completer _ =+  return []+++greeter :: MonadIO m => m ()+greeter =+  return ()+++dontCrash :: ( MonadIO m, Haskeline.MonadException m ) => m () -> m ()+dontCrash m =+  Haskeline.catch+    m+    ( \ e@SomeException{} -> liftIO ( putStrLn ( displayException e ) ) )+++output+    :: (Pretty.Pretty a, MonadIO m)+    => System.IO.Handle -> Dhall.Expr s a -> m ()+output handle expr = do+  liftIO (System.IO.hPutStrLn handle "")  -- Visual spacing++  let opts =+          Pretty.defaultLayoutOptions+              { Pretty.layoutPageWidth = Pretty.AvailablePerLine 80 1.0 }++  let stream = Pretty.layoutSmart opts (Dhall.Pretty.prettyExpr expr)+  supportsANSI <- liftIO (System.Console.ANSI.hSupportsANSI handle)+  let ansiStream =+          if supportsANSI+          then fmap Dhall.Pretty.annToAnsiStyle stream+          else Pretty.unAnnotateS stream++  liftIO (Pretty.renderIO handle ansiStream)+  liftIO (System.IO.hPutStrLn handle "") -- Pretty printing doesn't end with a new line++  liftIO (System.IO.hPutStrLn handle "")  -- Visual spacing
+ src/Dhall/TH.hs view
@@ -0,0 +1,44 @@+{-# LANGUAGE TemplateHaskell #-}++{-| This module provides `staticDhallExpression` which can be used to resolve+    all of an expression’s imports at compile time, allowing one to reference+    Dhall expressions from Haskell without having a runtime dependency on the+    location of Dhall files.++    For example, given a file “Some/Type.dhall” containing++        < This : Natural | Other : ../Other/Type.dhall >++    rather than duplicating the AST manually in a Haskell `Type`, you can do++        Dhall.Type+        (\case+            UnionLit "This" _ _  -> ...+            UnionLit "Other" _ _ -> ...)+        $(staticDhallExpression "../../Some/Type.dhall")++    This would create the Dhall Expr AST from the `Type.dhall` file at compile+    time with all imports resolved, making it easy to keep your Dhall configs+    and Haskell interpreters in sync.+-}+module Dhall.TH where++import Control.Monad+import Data.Typeable+import Language.Haskell.TH.Quote (dataToExpQ) -- 7.10 compatibility.+import Language.Haskell.TH.Syntax++import qualified Data.Text as Text+import qualified Dhall++-- | This fully resolves, type checks, and normalizes the expression, so the+--   resulting AST is self-contained.+staticDhallExpression :: Text.Text -> Q Exp+staticDhallExpression =+    dataToExpQ (\a -> liftText <$> cast a) <=< runIO . Dhall.inputExpr+  where+    -- A workaround for a problem in TemplateHaskell (see+    -- https://stackoverflow.com/questions/38143464/cant-find-inerface-file-declaration-for-variable)+    liftText = fmap (AppE (VarE 'Text.pack)) . lift . Text.unpack++
src/Dhall/Tutorial.hs view
@@ -423,26 +423,26 @@ -- > Cyclic import: ./file1 -- -- You can also import expressions by URL.  For example, you can find a Dhall--- expression hosted at this URL using @ipfs@:+-- expression hosted at this GitHub URL: ----- <https://ipfs.io/ipfs/QmVf6hhTCXc9y2pRvhUmLk3AZYEgjeAz5PNwjt1GBYqsVB>+-- <https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True> ----- > $ curl https://ipfs.io/ipfs/QmVf6hhTCXc9y2pRvhUmLk3AZYEgjeAz5PNwjt1GBYqsVB+-- > $ curl https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True -- > True -- -- ... and you can reference that expression either directly: ----- > >>> input auto "https://ipfs.io/ipfs/QmVf6hhTCXc9y2pRvhUmLk3AZYEgjeAz5PNwjt1GBYqsVB" :: IO Bool+-- > >>> input auto "https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True" :: IO Bool -- > True --  -- ... or inside of a larger expression: ----- > >>> input auto "False == https://ipfs.io/ipfs/QmVf6hhTCXc9y2pRvhUmLk3AZYEgjeAz5PNwjt1GBYqsVB" :: IO Bool+-- > >>> input auto "False == https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True" :: IO Bool -- > False ----- You're not limited to hosting Dhall expressions on @ipfs@.  You can host a--- Dhall expression anywhere that you can host UTF8-encoded text on the web, such--- as Github, a pastebin, or your own web server.+-- You're not limited to hosting Dhall expressions on GitHub.  You can host a+-- Dhall expression anywhere that you can host UTF8-encoded text on the web,+-- as a pastebin, or your own web server. -- -- You can also import Dhall expressions from environment variables, too: --@@ -483,12 +483,12 @@ -- -- __Exercise:__ There is a @not@ function hosted online here: ----- <https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/Bool/not>+-- <https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Bool/not> -- -- Visit that link and read the documentation.  Then try to guess what this -- code returns: ----- > >>> input auto "https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/Bool/not https://ipfs.io/ipfs/QmVf6hhTCXc9y2pRvhUmLk3AZYEgjeAz5PNwjt1GBYqsVB" :: IO Bool+-- > >>> input auto "https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Bool/not https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True" :: IO Bool -- > ??? -- -- Run the code to test your guess@@ -1017,7 +1017,7 @@ -- You can also use @let@ expressions to rename imports, like this: -- -- > $ dhall--- > let not = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/Bool/not+-- > let not = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Bool/not -- > in  not True -- > <Ctrl-D> -- > Bool@@ -1375,7 +1375,7 @@ -- complex example: -- -- > $ dhall--- >     let Prelude/List/map = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/map+-- >     let Prelude/List/map = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/map -- > in  λ(f : Natural → Natural) → Prelude/List/map Natural Natural f [1, 2, 3] -- > <Ctrl-D> -- > ∀(f : Natural → Natural) → List Natural@@ -1399,11 +1399,11 @@ -- __Exercise__: The Dhall Prelude provides a @replicate@ function which you can -- find here: ----- <https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/replicate>+-- <https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/replicate> -- -- Test what the following Dhall expression normalizes to: ----- > let replicate = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/replicate+-- > let replicate = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/replicate -- > in  replicate 10 -- -- __Exercise__: If you have a lot of spare time, try to \"break the compiler\" by@@ -1503,10 +1503,10 @@ -- >  -- > 1 ----- You can compute the Hash for any import by using the @dhall-hash@ utility--- installed by this package.  For example:+-- You can compute the Hash for any import by using the hash subcommand +-- of this package.  For example: ----- > dhall-hash <<< './bar'+-- > dhall hash <<< './bar' -- > sha256:6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b -- -- Then you can paste that output into your code after the import@@ -1551,7 +1551,26 @@ -- behavior-preserving.  This provides an easy way to detect refactoring errors -- that you might accidentally introduce.  The hash not only protects you -- from attackers, but also protects against human error, too!-+--+-- If you have a file which either doesn't already use hashed imports,+-- or you changed some of the imports and want to update the hashes you can use the+-- freeze command to either add or update hashes:+--+-- > cat foo.dhall+-- ''+-- let replicate =+--       https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate+--+-- in  replicate 5+-- ''+-- > dhall freeze --inplace ./foo.dhall+-- > cat ./foo.dhall+-- ''+-- let replicate =+--       https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate sha256:b0e3ec1797b32c80c0bcb7e8254b08c7e9e35e75e6b410c7ac21477ab90167ad +-- in  replicate 5+-- ''+-- -- $rawText -- -- Sometimes you want to import the contents of a raw text file as a Dhall@@ -1599,7 +1618,7 @@  -- $format ----- This package also provides a @dhall-format@ executable that you can use to+-- A format subcommand is also available that you can use to  -- automatically format Dhall expressions.  For example, we can take the -- following unformatted Dhall expression: --@@ -1616,9 +1635,9 @@ -- > z) (y.diff (n + List/length { index : Natural, value : a } kvs)) }) { count =  -- > 0, diff = λ(_ : Natural) → nil }).diff 0) ----- ... and run the expression through the @dhall-format@ executable:+-- ... and run the expression through the the formatter: ----- > $ dhall-format < ./unformatted+-- > $ dhall format < ./unformatted -- >   λ(a : Type) -- > → λ(kvss : List (List { index : Natural, value : a })) -- > → List/build@@ -1654,12 +1673,12 @@ -- The executable formats expressions without resolving, type-checking, or -- normalizing them: ----- > $ dhall-format--- > let replicate = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/replicate +-- > $ dhall format+-- > let replicate = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/replicate  -- > in replicate 5 (List (List Natural)) (replicate 5 (List Natural) (replicate 5 Natural 1)) -- > <Ctrl-D> -- >     let replicate =--- >           https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/replicate +-- >           https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/replicate  -- >  -- > in  replicate -- >     5@@ -1669,7 +1688,7 @@ -- You can also use the formatter to modify files in place using the -- @--inplace@ flag (i.e. for formatting source code): ----- > $ dhall-format --inplace ./unformatted+-- > $ dhall format --inplace ./unformatted -- > $ cat ./unformatted -- >   λ(a : Type) -- > → λ(kvss : List (List { index : Natural, value : a }))@@ -1707,7 +1726,7 @@ -- Currently, the formatter only preserves leading comments and whitespace -- up until the last newline preceding the code.  In other words: ----- > $ dhall-format+-- > $ dhall format -- > {- This comment will be preserved by the formatter -} -- > -- ... and this comment will be preserved, too -- > {- This comment will *NOT* be preserved -} 1@@ -1717,12 +1736,12 @@ -- > -- ... and this comment will be preserved, too -- > 1 ----- Note that you do not need to use @dhall-format@ to format the output of the+-- Note that you do not need to format the output of the -- @dhall@ interpreter.  The interpreter already automatically formats -- multi-line expressions, too: -- -- > $ dhall--- > let replicate = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/replicate +-- > let replicate = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/replicate  -- > in replicate 5 (List (List Natural)) (replicate 5 (List Natural) (replicate 5 Natural 1)) -- > <Ctrl-D> -- > List (List (List Natural))@@ -2336,7 +2355,7 @@ -- -- Rules: ----- > let Prelude/List/concat = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/concat+-- > let Prelude/List/concat = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/concat -- > -- > List/fold a (Prelude/List/concat a xss) b c -- >     = List/fold (List a) xss b (λ(x : List a) → List/fold a x b c)@@ -2405,10 +2424,10 @@ -- -- Rules: ----- > let Prelude/Optional/head  = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/Optional/head--- > let Prelude/List/concat    = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/concat--- > let Prelude/List/concatMap = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/concatMap--- > let Prelude/List/map       = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/map+-- > let Prelude/Optional/head  = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Optional/head+-- > let Prelude/List/concat    = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/concat+-- > let Prelude/List/concatMap = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/concatMap+-- > let Prelude/List/map       = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/map -- >  -- > List/head a (Prelude/List/concat a xss) = -- >     Prelude/Optional/head a (Prelude/List/map (List a) (Optional a) (List/head a) xss)@@ -2436,10 +2455,10 @@ -- -- Rules: ----- > let Prelude/Optional/last  = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/Optional/last--- > let Prelude/List/concat    = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/concat--- > let Prelude/List/concatMap = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/concatMap--- > let Prelude/List/map       = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/map+-- > let Prelude/Optional/last  = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Optional/last+-- > let Prelude/List/concat    = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/concat+-- > let Prelude/List/concatMap = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/concatMap+-- > let Prelude/List/map       = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/map -- >  -- > List/last a (Prelude/List/concat a xss) = -- >     Prelude/Optional/last a (Prelude/List/map (List a) (Optional a) (List/last a) xss)@@ -2467,9 +2486,9 @@ -- -- Rules: ----- > let Prelude/List/shifted = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/shifted--- > let Prelude/List/concat  = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/concat--- > let Prelude/List/map     = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/map+-- > let Prelude/List/shifted = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/shifted+-- > let Prelude/List/concat  = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/concat+-- > let Prelude/List/map     = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/map -- >  -- > List/indexed a (Prelude/List/concat a xss) = -- >     Prelude/List/shifted a (Prelude/List/map (List a) (List { index : Natural, value : a }) (List/indexed a) xss)@@ -2492,9 +2511,9 @@ -- -- Rules: ----- > let Prelude/List/map       = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/map--- > let Prelude/List/concat    = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/concat--- > let Prelude/List/concatMap = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/List/concatMap+-- > let Prelude/List/map       = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/map+-- > let Prelude/List/concat    = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/concat+-- > let Prelude/List/concatMap = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/List/concatMap -- >  -- > List/reverse a (Prelude/List/concat a xss) -- >     = Prelude/List/concat a (List/reverse (List a) (Prelude/List/map (List a) (List a) (List/reverse a) xss))@@ -2552,7 +2571,7 @@ -- -- ... which currenty redirects to: ----- <https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude>+-- <https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75> -- -- There is nothing \"official\" or \"standard\" about this Prelude other than -- the fact that it is mentioned in this tutorial.  The \"Prelude\" is just a@@ -2563,12 +2582,12 @@ -- subdirectories.  For example, the @Bool@ subdirectory has a @not@ file -- located here: ----- <https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/Bool/not>+-- <https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Bool/not> -- -- The @not@ function is just a UTF8-encoded text file hosted online with the -- following contents ----- > $ curl https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/Bool/not+-- > $ curl https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Bool/not -- > {- -- > Flip the value of a `Bool` -- > @@ -2601,7 +2620,7 @@ -- You can use this @not@ function either directly: -- -- > $ dhall--- > https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/Bool/not True+-- > https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Bool/not True -- > <Ctrl-D> -- > Bool -- > @@ -2610,7 +2629,7 @@ -- ... or assign the URL to a shorter name: -- -- > $ dhall--- > let Bool/not = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/Bool/not+-- > let Bool/not = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Bool/not -- > in  Bool/not True -- > <Ctrl-D> -- > Bool@@ -2621,7 +2640,7 @@ -- consistency and documentation, such as @Prelude\/Natural\/even@, which -- re-exports the built-in @Natural/even@ function: ----- > $ curl https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/Natural/even+-- > $ curl https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/Natural/even -- > {- -- > Returns `True` if a number if even and returns `False` otherwise -- > @@ -2638,11 +2657,10 @@ -- >  -- > in  even ----- You can also download the Prelude locally to your filesystem if you prefer--- using local relative paths instead of URLs.  For example, you can use @wget@,--- like this:+-- You can also clone the Prelude locally to your filesystem if you prefer+-- using `git clone`, like this: ----- > $ wget -np -nH -r --cut-dirs=2 https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/+-- > $ git clone https://github.com/dhall-lang/Prelude.git -- > $ tree Prelude -- > Prelude -- > ├── Bool@@ -2653,16 +2671,20 @@ -- > │   ├── not -- > │   ├── odd -- > │   ├── or+-- > │   ├── package.dhall -- > │   └── show -- > ├── Double+-- > │   ├── package.dhall -- > │   └── show -- > ├── Integer+-- > │   ├── package.dhall -- > │   └── show -- > ├── List -- > │   ├── all -- > │   ├── any -- > │   ├── build -- > │   ├── concat+-- > │   ├── concatMap -- > │   ├── filter -- > │   ├── fold -- > │   ├── generate@@ -2673,6 +2695,7 @@ -- > │   ├── length -- > │   ├── map -- > │   ├── null+-- > │   ├── package.dhall -- > │   ├── replicate -- > │   ├── reverse -- > │   ├── shifted@@ -2685,33 +2708,46 @@ -- > │   ├── fold -- > │   ├── isZero -- > │   ├── odd+-- > │   ├── package.dhall -- > │   ├── product -- > │   ├── show -- > │   ├── sum -- > │   └── toInteger -- > ├── Optional+-- > │   ├── None+-- > │   ├── Some+-- > │   ├── all+-- > │   ├── any -- > │   ├── build -- > │   ├── concat+-- > │   ├── filter -- > │   ├── fold -- > │   ├── head -- > │   ├── last+-- > │   ├── length -- > │   ├── map+-- > │   ├── null+-- > │   ├── package.dhall -- > │   ├── toList -- > │   └── unzip+-- > ├── Record+-- > │   ├── keyText+-- > │   ├── keyValue+-- > │   └── package.dhall -- > ├── Text--- > │   └── concat--- > └── index.html------ ... or if you have an @ipfs@ daemon running, you can mount the Prelude--- locally like this:------ > $ ipfs mount--- > $ cd /ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude+-- > │   ├── concat+-- > │   ├── concatMap+-- > │   ├── concatMapSep+-- > │   ├── concatSep+-- > │   └── package.dhall+-- > └── package.dhall+-- > +-- > 8 directories, 70 files -- -- Browse the Prelude online to learn more by seeing what functions are -- available and reading their inline documentation: ----- <https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude>+-- <https://github.com/dhall-lang/Prelude> -- -- __Exercise__: Try to use a new Prelude function that has not been covered -- previously in this tutorial@@ -2720,7 +2756,7 @@ -- convenience: -- -- > $ dhall--- >     let Prelude = https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/package.dhall+-- >     let Prelude = https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/package.dhall -- > -- > in    λ(x : Text) -- >     → Prelude.`List`.length Text (Prelude.`List`.replicate 10 Text x)@@ -2735,7 +2771,7 @@ -- -- __Exercise__: Browse the Prelude by running: ----- > $ dhall <<< 'https://ipfs.io/ipfs/QmV5MMfZehF4Z1EC4hK1s4yjE81kZV5hxypcuqfh9qcDMB/Prelude/package.dhall'+-- > $ dhall <<< 'https://raw.githubusercontent.com/dhall-lang/Prelude/35deff0d41f2bf86c42089c6ca16665537f54d75/package.dhall'  -- $conclusion --
src/Dhall/TypeCheck.hs view
@@ -22,47 +22,43 @@     ) where  import Control.Exception (Exception)+import Data.Data (Data(..)) import Data.Foldable (forM_, toList) import Data.Monoid ((<>)) import Data.Sequence (Seq, ViewL(..)) import Data.Set (Set)-import Data.Text.Lazy (Text)-import Data.Text.Lazy.Builder (Builder)+import Data.Text (Text) import Data.Text.Prettyprint.Doc (Doc, Pretty(..)) import Data.Traversable (forM) import Data.Typeable (Typeable) import Dhall.Core (Const(..), Chunks(..), Expr(..), Var(..)) import Dhall.Context (Context)-import Formatting.Buildable (Buildable(..))+import Dhall.Pretty (Ann)  import qualified Data.Foldable+import qualified Data.HashMap.Strict import qualified Data.HashMap.Strict.InsOrd import qualified Data.Sequence import qualified Data.Set-import qualified Data.Text.Lazy                        as Text-import qualified Data.Text.Lazy.Builder                as Builder-import qualified Data.Text.Prettyprint.Doc             as Pretty-import qualified Data.Text.Prettyprint.Doc.Render.Text as Pretty+import qualified Data.Text                               as Text+import qualified Data.Text.Prettyprint.Doc               as Pretty+import qualified Data.Text.Prettyprint.Doc.Render.String as Pretty import qualified Dhall.Context import qualified Dhall.Core import qualified Dhall.Diff-import qualified Dhall.Pretty import qualified Dhall.Pretty.Internal  traverseWithIndex_ :: Applicative f => (Int -> a -> f b) -> Seq a -> f () traverseWithIndex_ k xs =     Data.Foldable.sequenceA_ (Data.Sequence.mapWithIndex k xs) -docToLazyText :: Doc a -> Text-docToLazyText = Pretty.renderLazy . Pretty.layoutPretty opts-  where-    opts = Pretty.LayoutOptions { Pretty.layoutPageWidth = Pretty.Unbounded }- axiom :: Const -> Either (TypeError s a) Const axiom Type = return Kind axiom Kind = Left (TypeError Dhall.Context.empty (Const Kind) Untyped)  rule :: Const -> Const -> Either () Const+-- This forbids dependent types. If this ever changes, then the fast+-- path in the Let case of typeWithA will become unsound. rule Type Kind = Left () rule Type Type = return Type rule Kind Kind = return Kind@@ -74,6 +70,9 @@     `typeWith` does not necessarily normalize the type since full normalization     is not necessary for just type-checking.  If you actually care about the     returned type then you may want to `Dhall.Core.normalize` it afterwards.++    The supplied `Context` records the types of the names in scope. If+    these are ill-typed, the return value may be ill-typed. -} typeWith :: Context (Expr s X) -> Expr s X -> Either (TypeError s X) (Expr s X) typeWith ctx expr = do@@ -102,7 +101,8 @@         case Dhall.Context.lookup x n ctx of             Nothing -> Left (TypeError ctx e (UnboundVariable x))             Just a  -> do-                _ <- loop ctx a+                -- Note: no need to typecheck the value we're+                -- returning; that is done at insertion time.                 return a     loop ctx   (Lam x _A  b     ) = do         _ <- loop ctx _A@@ -154,11 +154,34 @@                     then return ()                     else Left (TypeError ctx e (AnnotMismatch a0 nf_A0 nf_A1))             Nothing -> return ()++        t <- loop ctx _A1+         let a1 = Dhall.Core.normalize a0         let a2 = Dhall.Core.shift 1 (V x 0) a1-        let b1 = Dhall.Core.subst (V x 0) a2 b0-        let b2 = Dhall.Core.shift (-1) (V x 0) b1-        loop ctx b2++        -- The catch-all branch directly implements the Dhall+        -- specification as written; it is necessary to substitute in+        -- types in order to get 'dependent let' behaviour and to+        -- allow type synonyms (see #69). However, doing a full+        -- substitution is slow if the value is large and used many+        -- times. If the value being substitued in is a term (i.e.,+        -- its type is a Type), then we can get a very significant+        -- speed-up by doing the type-checking once at binding-time,+        -- as opposed to doing it at every use site (see #412).+        case Dhall.Core.normalize t of+          Const Type -> do+            let ctx' = fmap (Dhall.Core.shift 1 (V x 0)) (Dhall.Context.insert x (Dhall.Core.normalize _A1) ctx)+            _B0 <- loop ctx' b0+            let _B1 = Dhall.Core.subst (V x 0) a2 _B0+            let _B2 = Dhall.Core.shift (-1) (V x 0) _B1+            return _B2++          _ -> do+            let b1 = Dhall.Core.subst (V x 0) a2 b0+            let b2 = Dhall.Core.shift (-1) (V x 0) b1+            loop ctx b2+     loop ctx e@(Annot x t       ) = do         _ <- loop ctx t @@ -298,6 +321,8 @@         return Integer     loop _      IntegerShow  = do         return (Pi "_" Integer Text)+    loop _      IntegerToDouble = do+        return (Pi "_" Integer Double)     loop _      Double            = do         return (Const Type)     loop _     (DoubleLit _     ) = do@@ -498,13 +523,19 @@                 kts <- Data.HashMap.Strict.InsOrd.traverseWithKey process kvs                 return (Record kts)     loop ctx e@(Union     kts   ) = do-        let process (k, t) = do+        let process k t = do                 s <- fmap Dhall.Core.normalize (loop ctx t)                 case s of                     Const Type -> return ()                     Const Kind -> return ()                     _          -> Left (TypeError ctx e (InvalidAlternativeType k t))-        mapM_ process (Data.HashMap.Strict.InsOrd.toList kts)+        -- toList from insert-ordered-containers does some work to+        -- ensure that the elements do follow insertion order. In this+        -- instance, insertion order doesn't matter: we only need to+        -- peek at each element to make sure it is well-typed. If+        -- there are multiple type errors, it does not matter which+        -- gets reported first here.+        Data.HashMap.Strict.foldrWithKey (\ k t prev -> prev >> process k t) (Right ()) (Data.HashMap.Strict.InsOrd.toHashMap kts)         return (Const Type)     loop ctx e@(UnionLit k v kts) = do         case Data.HashMap.Strict.InsOrd.lookup k kts of@@ -700,7 +731,7 @@                     Just t' -> return t'                     Nothing -> Left (TypeError ctx e (MissingField x t))             _ -> do-                let text = docToLazyText (Dhall.Pretty.Internal.prettyLabel x)+                let text = Dhall.Pretty.Internal.docToStrictText (Dhall.Pretty.Internal.prettyLabel x)                 Left (TypeError ctx e (NotARecord text r t))     loop ctx e@(Project r xs    ) = do         t <- fmap Dhall.Core.normalize (loop ctx r)@@ -715,12 +746,14 @@                 let adapt = Record . Data.HashMap.Strict.InsOrd.fromList                 fmap adapt (traverse process (Data.Set.toList xs))             _ -> do-                let text = docToLazyText (Dhall.Pretty.Internal.prettyLabels xs)+                let text = Dhall.Pretty.Internal.docToStrictText (Dhall.Pretty.Internal.prettyLabels xs)                 Left (TypeError ctx e (NotARecord text r t))     loop ctx   (Note s e'       ) = case loop ctx e' of         Left (TypeError ctx' (Note s' e'') m) -> Left (TypeError ctx' (Note s' e'') m)         Left (TypeError ctx'          e''  m) -> Left (TypeError ctx' (Note s  e'') m)         Right r                               -> Right r+    loop ctx   (ImportAlt l _r  ) =+       fmap Dhall.Core.normalize (loop ctx l)     loop _     (Embed p         ) = Right $ tpa p  {-| `typeOf` is the same as `typeWith` with an empty context, meaning that the@@ -739,8 +772,10 @@ instance Eq X where   _ == _ = True -instance Buildable X where-    build = absurd+instance Data X where+    dataTypeOf = absurd+    gunfold _ _ _ = undefined+    toConstr = absurd  instance Pretty X where     pretty = absurd@@ -799,46 +834,37 @@     | NoDependentTypes (Expr s a) (Expr s a)     deriving (Show) -shortTypeMessage :: (Buildable a, Eq a, Pretty a) => TypeMessage s a -> Builder+shortTypeMessage :: (Eq a, Pretty a) => TypeMessage s a -> Doc Ann shortTypeMessage msg =-    "\ESC[1;31mError\ESC[0m: " <> build short <> "\n"+    "\ESC[1;31mError\ESC[0m: " <> short <> "\n"   where     ErrorMessages {..} = prettyTypeMessage msg -longTypeMessage :: (Buildable a, Eq a, Pretty a) => TypeMessage s a -> Builder+longTypeMessage :: (Eq a, Pretty a) => TypeMessage s a -> Doc Ann longTypeMessage msg =-        "\ESC[1;31mError\ESC[0m: " <> build short <> "\n"+        "\ESC[1;31mError\ESC[0m: " <> short <> "\n"     <>  "\n"     <>  long   where     ErrorMessages {..} = prettyTypeMessage msg  data ErrorMessages = ErrorMessages-    { short :: Builder+    { short :: Doc Ann     -- ^ Default succinct 1-line explanation of what went wrong-    , long  :: Builder+    , long  :: Doc Ann     -- ^ Longer and more detailed explanation of the error     } -_NOT :: Builder+_NOT :: Doc ann _NOT = "\ESC[1mnot\ESC[0m" -prettyDiff :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Builder-prettyDiff exprL exprR = builder-  where-    doc =-        fmap Dhall.Pretty.annToAnsiStyle (Dhall.Diff.diffNormalized exprL exprR)--    opts = Pretty.LayoutOptions { Pretty.layoutPageWidth = Pretty.Unbounded }--    stream = Pretty.layoutPretty opts doc--    lazyText = Pretty.renderLazy stream+insert :: Pretty a => a -> Doc Ann+insert expression = "↳ " <> Pretty.align (Pretty.pretty expression) -    builder = Builder.fromLazyText lazyText+prettyDiff :: (Eq a, Pretty a) => Expr s a -> Expr s a -> Doc Ann+prettyDiff exprL exprR = Dhall.Diff.diffNormalized exprL exprR -prettyTypeMessage-    :: (Buildable a, Eq a, Pretty a) => TypeMessage s a -> ErrorMessages+prettyTypeMessage :: (Eq a, Pretty a) => TypeMessage s a -> ErrorMessages prettyTypeMessage (UnboundVariable _) = ErrorMessages {..}   -- We do not need to print variable name here. For the discussion see:   -- https://github.com/dhall-lang/dhall-haskell/pull/116@@ -942,7 +968,17 @@         \    │  (x : Bool) → Bool │                                                      \n\         \    └────────────────────┘                                                      \n\         \      ⇧                                                                         \n\-        \      A ❰∀❱ or ❰forall❱ here would transform this into a valid function type    \n"+        \      A ❰∀❱ or ❰forall❱ here would transform this into a valid function type    \n\+        \                                                                                \n\+        \                                                                                \n\+        \● You forgot to prefix a file path with ❰./❱:                                   \n\+        \                                                                                \n\+        \                                                                                \n\+        \    ┌────────────────────┐                                                      \n\+        \    │ path/to/file.dhall │                                                      \n\+        \    └────────────────────┘                                                      \n\+        \      ⇧                                                                         \n\+        \      This should be ❰./path/to/file.dhall❱                                     \n"  prettyTypeMessage (InvalidInputType expr) = ErrorMessages {..}   where@@ -1007,11 +1043,11 @@         \                                                                                \n\         \You annotated a function input with the following expression:                   \n\         \                                                                                \n\-        \↳ " <> txt <> "                                                                 \n\+        \" <> txt <> "\n\         \                                                                                \n\         \... which is neither a type nor a kind                                          \n"       where-        txt  = build expr+        txt = insert expr  prettyTypeMessage (InvalidOutputType expr) = ErrorMessages {..}   where@@ -1086,11 +1122,11 @@         \                                                                                \n\         \You specified that your function outputs a:                                     \n\         \                                                                                \n\-        \↳ " <> txt <> "                                                                 \n\+        \" <> txt <> "\n\         \                                                                                \n\         \... which is neither a type nor a kind:                                         \n"       where-        txt = build expr+        txt = insert expr  prettyTypeMessage (NotAFunction expr0 expr1) = ErrorMessages {..}   where@@ -1219,16 +1255,16 @@         \                                                                                \n\         \You tried to use the following expression as a function:                        \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... but this expression's type is:                                              \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... which is not a function type                                                \n"       where-        txt0 = build expr0-        txt1 = build expr1+        txt0 = insert expr0+        txt1 = insert expr1  prettyTypeMessage (TypeMismatch expr0 expr1 expr2 expr3) = ErrorMessages {..}   where@@ -1345,24 +1381,24 @@         \                                                                                \n\         \You tried to invoke the following function:                                     \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... which expects an argument of type or kind:                                  \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... on the following argument:                                                  \n\         \                                                                                \n\-        \↳ " <> txt2 <> "                                                                \n\+        \" <> txt2 <> "\n\         \                                                                                \n\         \... which has a different type or kind:                                         \n\         \                                                                                \n\-        \↳ " <> txt3 <> "                                                                \n"+        \" <> txt3 <> "\n"       where-        txt0 = build expr0-        txt1 = build expr1-        txt2 = build expr2-        txt3 = build expr3+        txt0 = insert expr0+        txt1 = insert expr1+        txt2 = insert expr2+        txt3 = insert expr3  prettyTypeMessage (AnnotMismatch expr0 expr1 expr2) = ErrorMessages {..}   where@@ -1447,19 +1483,19 @@         \                                                                                \n\         \You or the interpreter annotated this expression:                               \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... with this type or kind:                                                     \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... but the inferred type or kind of the expression is actually:                \n\         \                                                                                \n\-        \↳ " <> txt2 <> "                                                                \n"+        \" <> txt2 <> "\n"       where-        txt0 = build expr0-        txt1 = build expr1-        txt2 = build expr2+        txt0 = insert expr0+        txt1 = insert expr1+        txt2 = insert expr2  prettyTypeMessage Untyped = ErrorMessages {..}   where@@ -1547,16 +1583,16 @@         \                                                                                \n\         \Your ❰if❱ expression begins with the following predicate:                       \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... that has type:                                                              \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... but the predicate must instead have type ❰Bool❱                             \n"       where-        txt0 = build expr0-        txt1 = build expr1+        txt0 = insert expr0+        txt1 = insert expr1  prettyTypeMessage (IfBranchMustBeTerm b expr0 expr1 expr2) =     ErrorMessages {..}@@ -1628,22 +1664,22 @@         \                                                                                \n\         \Your ❰" <> txt0 <> "❱ branch of your ❰if❱ expression is:                        \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... which has kind:                                                             \n\         \                                                                                \n\-        \↳ " <> txt2 <> "                                                                \n\+        \" <> txt2 <> "\n\         \                                                                                \n\         \... of sort:                                                                    \n\         \                                                                                \n\-        \↳ " <> txt3 <> "                                                                \n\+        \" <> txt3 <> "\n\         \                                                                                \n\         \... and is not a term.  Therefore your ❰if❱ expression is not valid             \n"       where         txt0 = if b then "then" else "else"-        txt1 = build expr0-        txt2 = build expr1-        txt3 = build expr2+        txt1 = insert expr0+        txt2 = insert expr1+        txt3 = insert expr2  prettyTypeMessage (IfBranchMismatch expr0 expr1 expr2 expr3) =     ErrorMessages {..}@@ -1701,26 +1737,26 @@         \                                                                                \n\         \Your ❰if❱ expression has the following ❰then❱ branch:                           \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... which has type:                                                             \n\         \                                                                                \n\-        \↳ " <> txt2 <> "                                                                \n\+        \" <> txt2 <> "\n\         \                                                                                \n\         \... and the following ❰else❱ branch:                                            \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... which has a different type:                                                 \n\         \                                                                                \n\-        \↳ " <> txt3 <> "                                                                \n\+        \" <> txt3 <> "\n\         \                                                                                \n\         \Fix your ❰then❱ and ❰else❱ branches to have matching types                      \n"       where-        txt0 = build expr0-        txt1 = build expr1-        txt2 = build expr2-        txt3 = build expr3+        txt0 = insert expr0+        txt1 = insert expr1+        txt2 = insert expr2+        txt3 = insert expr3  prettyTypeMessage (InvalidListType expr0) = ErrorMessages {..}   where@@ -1766,11 +1802,11 @@         \                                                                                \n\         \You declared that the ❰List❱'s elements should have type:                       \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... which is not a ❰Type❱                                                       \n"       where-        txt0 = build expr0+        txt0 = insert expr0  prettyTypeMessage MissingListType = do     ErrorMessages {..}@@ -1825,15 +1861,15 @@         \                                                                                \n\         \Your first ❰List❱ element has this type:                                        \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... but the element at index #" <> txt1 <> " has this type instead:             \n\         \                                                                                \n\-        \↳ " <> txt3 <> "                                                                \n"+        \" <> txt3 <> "\n"       where-        txt0 = build expr0-        txt1 = build i-        txt3 = build expr2+        txt0 = insert expr0+        txt1 = pretty i+        txt3 = insert expr2  prettyTypeMessage (InvalidListElement i expr0 _expr1 expr2) =     ErrorMessages {..}@@ -1864,15 +1900,15 @@         \                                                                                \n\         \Your ❰List❱ elements should have this type:                                     \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... but the element at index #" <> txt1 <> " has this type instead:             \n\         \                                                                                \n\-        \↳ " <> txt3 <> "                                                                \n"+        \" <> txt3 <> "\n"       where-        txt0 = build expr0-        txt1 = build i-        txt3 = build expr2+        txt0 = insert expr0+        txt1 = pretty i+        txt3 = insert expr2  prettyTypeMessage (InvalidOptionalType expr0) = ErrorMessages {..}   where@@ -1920,11 +1956,11 @@         \                                                                                \n\         \You declared that the ❰Optional❱ element should have type:                      \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... which is not a ❰Type❱                                                       \n"       where-        txt0 = build expr0+        txt0 = insert expr0  prettyTypeMessage (InvalidOptionalElement expr0 expr1 expr2) = ErrorMessages {..}   where@@ -1953,19 +1989,19 @@         \                                                                                \n\         \Your ❰Optional❱ element should have this type:                                  \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... but the element you provided:                                               \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... has this type instead:                                                      \n\         \                                                                                \n\-        \↳ " <> txt2 <> "                                                                \n"+        \" <> txt2 <> "\n"       where-        txt0 = build expr0-        txt1 = build expr1-        txt2 = build expr2+        txt0 = insert expr0+        txt1 = insert expr1+        txt2 = insert expr2  prettyTypeMessage (InvalidFieldType k expr0) = ErrorMessages {..}   where@@ -1999,16 +2035,16 @@         \                                                                                \n\         \You provided a record type with a field named:                                  \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... annotated with the following expression:                                    \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... which is neither a ❰Type❱ nor a ❰Kind❱                                      \n"       where-        txt0 = build k-        txt1 = build expr0+        txt0 = insert k+        txt1 = insert expr0  prettyTypeMessage (FieldAnnotationMismatch k0 expr0 k1 expr1 c) = ErrorMessages {..}   where@@ -2043,26 +2079,26 @@         \                                                                                \n\         \You provided a record type with a field named:                                  \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... annotated with the following expression:                                    \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... which is a " <> here <> " whereas another field named:                      \n\         \                                                                                \n\-        \↳ " <> txt2 <> "                                                                \n\+        \" <> txt2 <> "\n\         \                                                                                \n\         \... annotated with the following expression:                                    \n\         \                                                                                \n\-        \↳ " <> txt3 <> "                                                                \n\+        \" <> txt3 <> "\n\         \                                                                                \n\         \... is a " <> there <> ", which does not match                                  \n"       where-        txt0 = build k0-        txt1 = build expr0-        txt2 = build k1-        txt3 = build expr1+        txt0 = insert k0+        txt1 = insert expr0+        txt2 = insert k1+        txt3 = insert expr1          here = case c of             Type -> "❰Type❱"@@ -2105,26 +2141,26 @@         \                                                                                \n\         \You provided a record with a field named:                                       \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... whose value was:                                                            \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... which is a " <> here <> " whereas another field named:                      \n\         \                                                                                \n\-        \↳ " <> txt2 <> "                                                                \n\+        \" <> txt2 <> "\n\         \                                                                                \n\         \... whose value was:                                                            \n\         \                                                                                \n\-        \↳ " <> txt3 <> "                                                                \n\+        \" <> txt3 <> "\n\         \                                                                                \n\         \... is a " <> there <> ", which does not match                                  \n"       where-        txt0 = build k0-        txt1 = build expr0-        txt2 = build k1-        txt3 = build expr1+        txt0 = insert k0+        txt1 = insert expr0+        txt2 = insert k1+        txt3 = insert expr1          here = case c of             Type -> "term"@@ -2160,16 +2196,16 @@         \                                                                                \n\         \You provided a record literal with a field named:                               \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... whose value is:                                                             \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... which is not a term or ❰Type❱                                               \n"       where-        txt0 = build k-        txt1 = build expr0+        txt0 = insert k+        txt1 = insert expr0  prettyTypeMessage (InvalidAlternativeType k expr0) = ErrorMessages {..}   where@@ -2222,16 +2258,16 @@         \                                                                                \n\         \You provided a union literal with an alternative named:                         \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... whose value is:                                                             \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... which is not a term                                                         \n"       where-        txt0 = build k-        txt1 = build expr0+        txt0 = insert k+        txt1 = insert expr0  prettyTypeMessage (InvalidAlternative k expr0) = ErrorMessages {..}   where@@ -2284,14 +2320,14 @@         \                                                                                \n\         \You provided a union type with an alternative named:                            \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... annotated with the following expression which is not a type:                \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n"+        \" <> txt1 <> "\n"       where-        txt0 = build k-        txt1 = build expr0+        txt0 = insert k+        txt1 = insert expr0  prettyTypeMessage (ListAppendMismatch expr0 expr1) = ErrorMessages {..}   where@@ -2325,16 +2361,16 @@         \                                                                                \n\         \You tried to append a ❰List❱ thas has elements of type:                         \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... with another ❰List❱ that has elements of type:                              \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... and those two types do not match                                            \n"       where-        txt0 = build expr0-        txt1 = build expr1+        txt0 = insert expr0+        txt1 = insert expr1  prettyTypeMessage (DuplicateAlternative k) = ErrorMessages {..}   where@@ -2358,9 +2394,9 @@         \                                                                                \n\         \You have more than one alternative named:                                       \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n"+        \" <> txt0 <> "\n"       where-        txt0 = build k+        txt0 = insert k  prettyTypeMessage (MustCombineARecord c expr0 expr1) = ErrorMessages {..}   where@@ -2408,15 +2444,15 @@         \                                                                                \n\         \You tried to combine the following value:                                       \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... which is not a record, but is actually a:                                   \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n"+        \" <> txt1 <> "\n"       where-        op   = build c-        txt0 = build expr0-        txt1 = build expr1+        op   = pretty c+        txt0 = insert expr0+        txt1 = insert expr1  prettyTypeMessage (CombineTypesRequiresRecordType expr0 expr1) =     ErrorMessages {..}@@ -2446,16 +2482,16 @@         \                                                                                \n\         \You tried to supply the following argument:                                     \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... which normalized to:                                                        \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... which is not a record type literal                                          \n"       where-        txt0 = build expr0-        txt1 = build expr1+        txt0 = insert expr0+        txt1 = insert expr1  prettyTypeMessage (RecordTypeMismatch const0 const1 expr0 expr1) =     ErrorMessages {..}@@ -2489,24 +2525,24 @@         \                                                                                \n\         \You tried to combine the following record type:                                 \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... with this record types:                                                     \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... but the former record type is a:                                            \n\         \                                                                                \n\-        \↳ " <> txt2 <> "                                                                \n\+        \" <> txt2 <> "\n\         \                                                                                \n\         \... but the latter record type is a:                                            \n\         \                                                                                \n\-        \↳ " <> txt3 <> "                                                                \n"+        \" <> txt3 <> "\n"       where-        txt0 = build expr0-        txt1 = build expr1-        txt2 = build const0-        txt3 = build const1+        txt0 = insert expr0+        txt1 = insert expr1+        txt2 = insert const0+        txt3 = insert const1  prettyTypeMessage (FieldCollision k) = ErrorMessages {..}   where@@ -2579,11 +2615,11 @@         \                                                                                \n\         \You combined two records that share the following field:                        \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... which is not allowed                                                        \n"       where-        txt0 = build k+        txt0 = insert k  prettyTypeMessage (MustMergeARecord expr0 expr1) = ErrorMessages {..}   where@@ -2631,14 +2667,14 @@         \                                                                                \n\         \You provided the following handler:                                             \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... which is not a record, but is actually a value of type:                     \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n"+        \" <> txt1 <> "\n"       where-        txt0 = build expr0-        txt1 = build expr1+        txt0 = insert expr0+        txt1 = insert expr1  prettyTypeMessage (MustMergeUnion expr0 expr1) = ErrorMessages {..}   where@@ -2671,14 +2707,14 @@         \                                                                                \n\         \You tried to ❰merge❱ this expression:                                           \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... which is not a union, but is actually a value of type:                      \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n"+        \" <> txt1 <> "\n"       where-        txt0 = build expr0-        txt1 = build expr1+        txt0 = insert expr0+        txt1 = insert expr1  prettyTypeMessage (UnusedHandler ks) = ErrorMessages {..}   where@@ -2714,11 +2750,11 @@         \                                                                                \n\         \You provided the following handlers:                                            \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... which had no matching alternatives in the union you tried to ❰merge❱        \n"       where-        txt0 = build (Text.intercalate ", " (Data.Set.toList ks))+        txt0 = insert (Text.intercalate ", " (Data.Set.toList ks))  prettyTypeMessage (MissingHandler ks) = ErrorMessages {..}   where@@ -2756,9 +2792,9 @@         \                                                                                \n\         \You need to supply the following handlers:                                      \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n"+        \" <> txt0 <> "\n"       where-        txt0 = build (Text.intercalate ", " (Data.Set.toList ks))+        txt0 = insert (Text.intercalate ", " (Data.Set.toList ks))  prettyTypeMessage MissingMergeType =     ErrorMessages {..}@@ -2838,19 +2874,19 @@         \                                                                                \n\         \Your handler for the following alternative:                                     \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... needs to accept an input value of type:                                     \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... but actually accepts an input value of a different type:                    \n\         \                                                                                \n\-        \↳ " <> txt2 <> "                                                                \n"+        \" <> txt2 <> "\n"       where-        txt0 = build expr0-        txt1 = build expr1-        txt2 = build expr2+        txt0 = insert expr0+        txt1 = insert expr1+        txt2 = insert expr2  prettyTypeMessage (InvalidHandlerOutputType expr0 expr1 expr2) =     ErrorMessages {..}@@ -2902,19 +2938,19 @@         \                                                                                \n\         \Your handler for the following alternative:                                     \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... needs to return an output value of type:                                    \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... but actually returns an output value of a different type:                   \n\         \                                                                                \n\-        \↳ " <> txt2 <> "                                                                \n"+        \" <> txt2 <> "\n"       where-        txt0 = build expr0-        txt1 = build expr1-        txt2 = build expr2+        txt0 = insert expr0+        txt1 = insert expr1+        txt2 = insert expr2  prettyTypeMessage (HandlerOutputTypeMismatch key0 expr0 key1 expr1) =     ErrorMessages {..}@@ -2962,16 +2998,16 @@         \                                                                                \n\         \The handler for the ❰" <> txt0 <> "❱ alternative has this output type:          \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... but the handler for the ❰" <> txt2 <> "❱ alternative has this output type instead:\n\         \                                                                                \n\-        \↳ " <> txt3 <> "                                                                \n"+        \" <> txt3 <> "\n"       where-        txt0 = build key0-        txt1 = build expr0-        txt2 = build key1-        txt3 = build expr1+        txt0 = pretty key0+        txt1 = insert expr0+        txt2 = pretty key1+        txt3 = insert expr1  prettyTypeMessage (HandlerNotAFunction k expr0) = ErrorMessages {..}   where@@ -3003,16 +3039,16 @@         \                                                                                \n\         \Your handler for this alternative:                                              \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... has the following type:                                                     \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... which is not the type of a function                                         \n"       where-        txt0 = build k-        txt1 = build expr0+        txt0 = insert k+        txt1 = insert expr0  prettyTypeMessage (ConstructorsRequiresAUnionType expr0 expr1) = ErrorMessages {..}   where@@ -3055,16 +3091,16 @@         \                                                                                \n\         \You tried to supply the following argument:                                     \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... which normalized to:                                                        \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... which is not a union type literal                                           \n"       where-        txt0 = build expr0-        txt1 = build expr1+        txt0 = insert expr0+        txt1 = insert expr1   prettyTypeMessage (NotARecord lazyText0 expr0 expr1) = ErrorMessages {..}   where@@ -3113,19 +3149,19 @@         \                                                                                \n\         \You tried to access the field(s):                                               \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... on the following expression which is not a record:                          \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... but is actually an expression of type:                                      \n\         \                                                                                \n\-        \↳ " <> txt2 <> "                                                                \n"+        \" <> txt2 <> "\n"       where-        txt0 = build lazyText0-        txt1 = build expr0-        txt2 = build expr1+        txt0 = insert lazyText0+        txt1 = insert expr0+        txt2 = insert expr1  prettyTypeMessage (MissingField k expr0) = ErrorMessages {..}   where@@ -3157,14 +3193,14 @@         \                                                                                \n\         \You tried to access a field named:                                              \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... but the field is missing because the record only defines the following fields:\n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n"+        \" <> txt1 <> "\n"       where-        txt0 = build k-        txt1 = build expr0+        txt0 = insert k+        txt1 = insert expr0  prettyTypeMessage (CantAnd expr0 expr1) =         buildBooleanOperator "&&" expr0 expr1@@ -3231,16 +3267,14 @@         \                                                                                \n\         \You interpolated this expression:                                               \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... which does not have type ❰Text❱ but instead has type:                       \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n"+        \" <> txt1 <> "\n"       where-        txt0 = build expr0-        txt1 = build expr1-- +        txt0 = insert expr0+        txt1 = insert expr1  prettyTypeMessage (CantTextAppend expr0 expr1) = ErrorMessages {..}   where@@ -3279,14 +3313,14 @@         \                                                                                \n\         \You provided this argument:                                                     \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... which does not have type ❰Text❱ but instead has type:                       \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n"+        \" <> txt1 <> "\n"       where-        txt0 = build expr0-        txt1 = build expr1+        txt0 = insert expr0+        txt1 = insert expr1  prettyTypeMessage (CantListAppend expr0 expr1) = ErrorMessages {..}   where@@ -3307,14 +3341,14 @@         \                                                                                \n\         \You provided this argument:                                                     \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... which is not a ❰List❱ but instead has type:                                 \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n"+        \" <> txt1 <> "\n"       where-        txt0 = build expr0-        txt1 = build expr1+        txt0 = insert expr0+        txt1 = insert expr1  prettyTypeMessage (CantAdd expr0 expr1) =         buildNaturalOperator "+" expr0 expr1@@ -3351,18 +3385,18 @@         \                                                                                \n\         \Your function type is invalid because the input has type:                       \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... and the output has kind:                                                    \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n\+        \" <> txt1 <> "\n\         \                                                                                \n\         \... which makes this a forbidden dependent function type                        \n"       where-        txt0 = build expr0-        txt1 = build expr1+        txt0 = insert expr0+        txt1 = insert expr1 -buildBooleanOperator :: Buildable a => Text -> Expr s a -> Expr s a -> ErrorMessages+buildBooleanOperator :: Pretty a => Text -> Expr s a -> Expr s a -> ErrorMessages buildBooleanOperator operator expr0 expr1 = ErrorMessages {..}   where     short = "❰" <> txt2 <> "❱ only works on ❰Bool❱s"@@ -3380,18 +3414,18 @@         \                                                                                \n\         \You provided this argument:                                                     \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... which does not have type ❰Bool❱ but instead has type:                       \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n"+        \" <> txt1 <> "\n"       where-        txt0 = build expr0-        txt1 = build expr1+        txt0 = insert expr0+        txt1 = insert expr1 -    txt2 = build operator+    txt2 = pretty operator -buildNaturalOperator :: Buildable a => Text -> Expr s a -> Expr s a -> ErrorMessages+buildNaturalOperator :: Pretty a => Text -> Expr s a -> Expr s a -> ErrorMessages buildNaturalOperator operator expr0 expr1 = ErrorMessages {..}   where     short = "❰" <> txt2 <> "❱ only works on ❰Natural❱s"@@ -3441,50 +3475,55 @@         \                                                                                \n\         \You provided this argument:                                                     \n\         \                                                                                \n\-        \↳ " <> txt0 <> "                                                                \n\+        \" <> txt0 <> "\n\         \                                                                                \n\         \... which does not have type ❰Natural❱ but instead has type:                    \n\         \                                                                                \n\-        \↳ " <> txt1 <> "                                                                \n"+        \" <> txt1 <> "\n"       where-        txt0 = build expr0-        txt1 = build expr1+        txt0 = insert expr0+        txt1 = insert expr1 -    txt2 = build operator+    txt2 = pretty operator  -- | A structured type error that includes context data TypeError s a = TypeError     { context     :: Context (Expr s a)     , current     :: Expr s a     , typeMessage :: TypeMessage s a-    } deriving (Typeable)+    } -instance (Buildable a, Buildable s, Eq a, Pretty a) => Show (TypeError s a) where-    show = Text.unpack . Builder.toLazyText . build+instance (Eq a, Pretty s, Pretty a) => Show (TypeError s a) where+    show = Pretty.renderString . Pretty.layoutPretty options . Pretty.pretty+      where+        options =+            Pretty.LayoutOptions+                { Pretty.layoutPageWidth = Pretty.AvailablePerLine 80 1.0 } -instance (Buildable a, Buildable s, Eq a, Pretty a, Typeable a, Typeable s) => Exception (TypeError s a)+instance (Eq a, Pretty s, Pretty a, Typeable s, Typeable a) => Exception (TypeError s a) -instance (Buildable a, Buildable s, Eq a, Pretty a) => Buildable (TypeError s a) where-    build (TypeError ctx expr msg)-        =   "\n"-        <>  (   if  Text.null (Builder.toLazyText (buildContext ctx))-                then ""-                else buildContext ctx <> "\n"+instance (Eq a, Pretty s, Pretty a) => Pretty (TypeError s a) where+    pretty (TypeError ctx expr msg)+        = Pretty.unAnnotate+            ("\n"+            <>  (   if null (Dhall.Context.toList ctx)+                    then ""+                    else prettyContext ctx <> "\n"+                )+            <>  shortTypeMessage msg <> "\n"+            <>  source             )-        <>  shortTypeMessage msg <> "\n"-        <>  source       where-        buildKV (key, val) = build key <> " : " <> build val+        prettyKV (key, val) = pretty key <> " : " <> pretty val -        buildContext =-                build-            .   Text.unlines-            .   map (Builder.toLazyText . buildKV)+        prettyContext =+                Pretty.vsep+            .   map prettyKV             .   reverse             .   Dhall.Context.toList          source = case expr of-            Note s _ -> build s+            Note s _ -> pretty s             _        -> mempty  {-| Newtype used to wrap error messages so that they render with a more@@ -3493,34 +3532,39 @@ newtype DetailedTypeError s a = DetailedTypeError (TypeError s a)     deriving (Typeable) -instance (Buildable a, Buildable s, Eq a, Pretty a) => Show (DetailedTypeError s a) where-    show = Text.unpack . Builder.toLazyText . build+instance (Eq a, Pretty s, Pretty a) => Show (DetailedTypeError s a) where+    show = Pretty.renderString . Pretty.layoutPretty options . Pretty.pretty+      where+        options =+            Pretty.LayoutOptions+                { Pretty.layoutPageWidth = Pretty.AvailablePerLine 80 1.0 } -instance (Buildable a, Buildable s, Eq a, Pretty a, Typeable a, Typeable s) => Exception (DetailedTypeError s a)+instance (Eq a, Pretty s, Pretty a, Typeable s, Typeable a) => Exception (DetailedTypeError s a) -instance (Buildable a, Buildable s, Eq a, Pretty a) => Buildable (DetailedTypeError s a) where-    build (DetailedTypeError (TypeError ctx expr msg))-        =   "\n"-        <>  (   if  Text.null (Builder.toLazyText (buildContext ctx))-                then ""-                else buildContext ctx <> "\n"+instance (Eq a, Pretty s, Pretty a) => Pretty (DetailedTypeError s a) where+    pretty (DetailedTypeError (TypeError ctx expr msg))+        = Pretty.unAnnotate+            (   "\n"+            <>  (   if  null (Dhall.Context.toList ctx)+                    then ""+                    else prettyContext ctx <> "\n"+                )+            <>  longTypeMessage msg <> "\n"+            <>  "────────────────────────────────────────────────────────────────────────────────\n"+            <>  "\n"+            <>  source             )-        <>  longTypeMessage msg <> "\n"-        <>  "────────────────────────────────────────────────────────────────────────────────\n"-        <>  "\n"-        <>  source       where-        buildKV (key, val) = build key <> " : " <> build val+        prettyKV (key, val) = pretty key <> " : " <> pretty val -        buildContext =-                build-            .   Text.unlines-            .   map (Builder.toLazyText . buildKV)+        prettyContext =+                Pretty.vsep+            .   map prettyKV             .   reverse             .   Dhall.Context.toList          source = case expr of-            Note s _ -> build s+            Note s _ -> pretty s             _        -> mempty  {-| This function verifies that a custom context is well-formed so that
tests/Format.hs view
@@ -8,7 +8,7 @@  import qualified Control.Exception import qualified Data.Text-import qualified Data.Text.Lazy.IO+import qualified Data.Text.IO import qualified Data.Text.Prettyprint.Doc import qualified Data.Text.Prettyprint.Doc.Render.Text import qualified Dhall.Parser@@ -36,6 +36,24 @@         , should             "correctly format the empty record literal"             "emptyRecord"+        , should+            "indent then/else to the same column"+            "ifThenElse"+        , should+            "handle indenting long imports correctly without trailing space per line"+            "importLines"+        , should+            "handle indenting small imports correctly without trailing space inline"+            "importLines2"+        , should+            "not remove parentheses when accessing a field of a record"+            "importAccess"+        , should+            "handle formatting sha256 imports correctly"+            "sha256Printing"+        , should+            "handle formatting of Import suffix correctly"+            "importSuffix"         ]  opts :: Data.Text.Prettyprint.Doc.LayoutOptions@@ -52,7 +70,7 @@                 Data.Text.unpack ("./tests/format/" <> basename <> "A.dhall")         let outputFile =                 Data.Text.unpack ("./tests/format/" <> basename <> "B.dhall")-        inputText <- Data.Text.Lazy.IO.readFile inputFile+        inputText <- Data.Text.IO.readFile inputFile          expr <- case Dhall.Parser.exprFromText mempty inputText of             Left  err  -> Control.Exception.throwIO err@@ -60,9 +78,9 @@          let doc        = Data.Text.Prettyprint.Doc.pretty expr         let docStream  = Data.Text.Prettyprint.Doc.layoutSmart opts doc-        let actualText = Data.Text.Prettyprint.Doc.Render.Text.renderLazy docStream+        let actualText = Data.Text.Prettyprint.Doc.Render.Text.renderStrict docStream -        expectedText <- Data.Text.Lazy.IO.readFile outputFile+        expectedText <- Data.Text.IO.readFile outputFile          let message =                 "The formatted expression did not match the expected output"
+ tests/Import.hs view
@@ -0,0 +1,70 @@+{-# LANGUAGE OverloadedStrings #-}++module Import where++import Data.Text (Text)+import Test.Tasty (TestTree)+import Dhall.Import (MissingImports(..))+import Control.Exception (catch, throwIO)+import Data.Monoid ((<>))++import qualified Data.Text+import qualified Data.Text.IO+import qualified Dhall.Parser+import qualified Dhall.Import+import qualified Test.Tasty+import qualified Test.Tasty.HUnit++importTests :: TestTree+importTests =+    Test.Tasty.testGroup "import tests"+        [ Test.Tasty.testGroup "import alternatives"+            [ shouldFail+                3+                "alternative of several unset env variables"+                "./tests/import/alternativeEnv.dhall"+            , shouldFail+                1+                "alternative of env variable and missing"+                "./tests/import/alternativeEnvMissing.dhall"+            , shouldFail+                0+                "just missing"+                "./tests/import/missing.dhall"+            , shouldNotFail+                "alternative of env variable, missing, and a Natural"+                "./tests/import/alternativeEnvNatural.dhall"+            , shouldNotFail+                "alternative of env variable and a Natural"+                "./tests/import/alternativeEnvSimple.dhall"+            , shouldNotFail+                "alternative of a Natural and missing"+                "./tests/import/alternativeNatural.dhall"+            ]+        ]++shouldNotFail :: Text -> FilePath -> TestTree+shouldNotFail name path = Test.Tasty.HUnit.testCase (Data.Text.unpack name) (do+    text <- Data.Text.IO.readFile path+    actualExpr <- case Dhall.Parser.exprFromText mempty text of+                     Left  err  -> throwIO err+                     Right expr -> return expr+    _ <- Dhall.Import.load actualExpr+    return ())++shouldFail :: Int -> Text -> FilePath -> TestTree+shouldFail failures name path = Test.Tasty.HUnit.testCase (Data.Text.unpack name) (do+    text <- Data.Text.IO.readFile path+    actualExpr <- case Dhall.Parser.exprFromText mempty text of+                     Left  err  -> throwIO err+                     Right expr -> return expr+    catch+      (do+          _ <- Dhall.Import.load actualExpr+          fail "Import should have failed, but it succeeds")+      (\(MissingImports es) -> case length es == failures of+                                True -> pure ()+                                False -> fail ("Should have failed "+                                               <> show failures+                                               <> " times, but failed with: \n"+                                               <> show es)) )
tests/Normalization.hs view
@@ -4,12 +4,12 @@ module Normalization (normalizationTests) where  import Data.Monoid ((<>))-import Data.Text.Lazy (Text)+import Data.Text (Text) import Dhall.Core (Expr) import Dhall.TypeCheck (X)  import qualified Control.Exception-import qualified Data.Text.Lazy+import qualified Data.Text import qualified Dhall.Core import qualified Dhall.Import import qualified Dhall.Parser@@ -19,7 +19,7 @@ import Dhall.Context import Test.Tasty import Test.Tasty.HUnit-import Util +import Util  normalizationTests :: TestTree normalizationTests =@@ -32,6 +32,7 @@         , shouldNormalize "Optional build/fold fusion" "optionalBuildFold"         , customization         , shouldNormalize "a remote-systems.conf builder" "remoteSystems"+        , shouldNormalize "multi-line strings correctly" "multiLine"         ]  tutorialExamples :: TestTree@@ -68,6 +69,8 @@         , shouldNormalize "Double/show" "./examples/Double/show/1"         , shouldNormalize "Integer/show" "./examples/Integer/show/0"         , shouldNormalize "Integer/show" "./examples/Integer/show/1"+        , shouldNormalize "Integer/toDouble" "./examples/Integer/toDouble/0"+        , shouldNormalize "Integer/toDouble" "./examples/Integer/toDouble/1"         , shouldNormalize "List/all" "./examples/List/all/0"         , shouldNormalize "List/all" "./examples/List/all/1"         , shouldNormalize "List/any" "./examples/List/any/0"@@ -87,6 +90,8 @@         , shouldNormalize "List/generate" "./examples/List/generate/1"         , shouldNormalize "List/head" "./examples/List/head/0"         , shouldNormalize "List/head" "./examples/List/head/1"+        , shouldNormalize "List/indexed" "./examples/List/indexed/0"+        , shouldNormalize "List/indexed" "./examples/List/indexed/1"         , shouldNormalize "List/iterate" "./examples/List/iterate/0"         , shouldNormalize "List/iterate" "./examples/List/iterate/1"         , shouldNormalize "List/last" "./examples/List/last/0"@@ -124,6 +129,8 @@         , shouldNormalize "Natural/show" "./examples/Natural/show/1"         , shouldNormalize "Natural/sum" "./examples/Natural/sum/0"         , shouldNormalize "Natural/sum" "./examples/Natural/sum/1"+        , shouldNormalize "Natural/toDouble" "./examples/Natural/toDouble/0"+        , shouldNormalize "Natural/toDouble" "./examples/Natural/toDouble/1"         , shouldNormalize "Natural/toInteger" "./examples/Natural/toInteger/0"         , shouldNormalize "Natural/toInteger" "./examples/Natural/toInteger/1"         , shouldNormalize "Optional/all" "./examples/Optional/all/0"@@ -199,11 +206,11 @@  simpleCustomization :: TestTree simpleCustomization = testCase "simpleCustomization" $ do-  let tyCtx  = insert "min" (Pi "_" Natural (Pi "_" Natural Natural)) empty +  let tyCtx  = insert "min" (Pi "_" Natural (Pi "_" Natural Natural)) empty       valCtx e = case e of                     (App (App (Var (V "min" 0)) (NaturalLit x)) (NaturalLit y)) -> Just (NaturalLit (min x y))                     _ -> Nothing-  e <- codeWith tyCtx "min (min 11 12) 8 + 1" +  e <- codeWith tyCtx "min (min 11 12) 8 + 1"   assertNormalizesToWith valCtx e "9"  nestedReduction :: TestTree@@ -215,7 +222,7 @@       valCtx e = case e of                     (App (App (Var (V "min" 0)) (NaturalLit x)) (NaturalLit y)) -> Just (NaturalLit (min x y))                     (App (Var (V "wurble" 0)) (NaturalLit x)) -> Just-                        (App (Var (V "fiveorless" 0)) (NaturalPlus (NaturalLit x) (NaturalLit 2))) +                        (App (Var (V "fiveorless" 0)) (NaturalPlus (NaturalLit x) (NaturalLit 2)))                     (App (Var (V "fiveorless" 0)) (NaturalLit x)) -> Just                         (App (App (Var (V "min" 0)) (NaturalLit x)) (NaturalPlus (NaturalLit 3) (NaturalLit 2)))                     _ -> Nothing@@ -224,7 +231,7 @@  should :: Text -> Text -> TestTree should name basename =-    Test.Tasty.HUnit.testCase (Data.Text.Lazy.unpack name) $ do+    Test.Tasty.HUnit.testCase (Data.Text.unpack name) $ do         let actualCode   = "./tests/normalization/" <> basename <> "A.dhall"         let expectedCode = "./tests/normalization/" <> basename <> "B.dhall" 
tests/Parser.hs view
@@ -7,7 +7,7 @@  import qualified Control.Exception import qualified Data.Text-import qualified Data.Text.Lazy.IO+import qualified Data.Text.IO import qualified Dhall.Parser import qualified Test.Tasty import qualified Test.Tasty.HUnit@@ -125,6 +125,9 @@                 "builtins"                 "./tests/parser/builtins.dhall"             , shouldParse+                "import alternatives"+                "./tests/parser/importAlt.dhall"+            , shouldParse                 "large expression"                 "./tests/parser/largeExpression.dhall"             , shouldParse@@ -133,12 +136,31 @@             , shouldParse                 "interpolated expressions with leading whitespace"                 "./tests/parser/template.dhall"+            , shouldNotParse+                "records with duplicate fields"+                "./tests/parser/failure/duplicateFields.dhall"+            , shouldParse+                "collections with type annotations containing imports"+                "./tests/parser/collectionImportType.dhall"+            , shouldParse+                "a parenthesized custom header import"+                "./tests/parser/parenthesizeUsing.dhall"+            , shouldNotParse+                "accessing a field of an import without parentheses"+                "./tests/parser/failure/importAccess.dhall"             ]         ]  shouldParse :: Text -> FilePath -> TestTree shouldParse name path = Test.Tasty.HUnit.testCase (Data.Text.unpack name) (do-    text <- Data.Text.Lazy.IO.readFile path+    text <- Data.Text.IO.readFile path     case Dhall.Parser.exprFromText mempty text of         Left err -> Control.Exception.throwIO err         Right _  -> return () )++shouldNotParse :: Text -> FilePath -> TestTree+shouldNotParse name path = Test.Tasty.HUnit.testCase (Data.Text.unpack name) (do+    text <- Data.Text.IO.readFile path+    case Dhall.Parser.exprFromText mempty text of+        Left  _ -> return ()+        Right _ -> fail "Unexpected successful parser" )
tests/Tests.hs view
@@ -6,6 +6,7 @@ import Tutorial (tutorialTests) import TypeCheck (typecheckTests) import Format (formatTests)+import Import (importTests) import Test.Tasty  allTests :: TestTree@@ -17,6 +18,7 @@         , tutorialTests         , formatTests         , typecheckTests+        , importTests         ]  main :: IO ()
tests/TypeCheck.hs view
@@ -3,11 +3,11 @@ module TypeCheck where  import Data.Monoid (mempty, (<>))-import Data.Text.Lazy (Text)+import Data.Text (Text) import Test.Tasty (TestTree)  import qualified Control.Exception-import qualified Data.Text.Lazy+import qualified Data.Text import qualified Dhall.Core import qualified Dhall.Import import qualified Dhall.Parser@@ -47,7 +47,7 @@  should :: Text -> Text -> TestTree should name basename =-    Test.Tasty.HUnit.testCase (Data.Text.Lazy.unpack name) $ do+    Test.Tasty.HUnit.testCase (Data.Text.unpack name) $ do         let actualCode   = "./tests/typecheck/" <> basename <> "A.dhall"         let expectedCode = "./tests/typecheck/" <> basename <> "B.dhall" 
tests/Util.hs view
@@ -16,7 +16,6 @@ import qualified Data.Functor import           Data.Bifunctor (first) import           Data.Text (Text)-import qualified Data.Text.Lazy import qualified Dhall.Core import           Dhall.Core (Expr, Normalizer) import qualified Dhall.Context@@ -28,19 +27,18 @@ import           Dhall.TypeCheck (X) import           Test.Tasty.HUnit -normalize' :: Expr Src X -> Data.Text.Lazy.Text+normalize' :: Expr Src X -> Text normalize' = Dhall.Core.pretty . Dhall.Core.normalize -normalizeWith' :: Normalizer X -> Expr Src X -> Data.Text.Lazy.Text+normalizeWith' :: Normalizer X -> Expr Src X -> Text normalizeWith' ctx = Dhall.Core.pretty . Dhall.Core.normalizeWith ctx -code :: Data.Text.Text -> IO (Expr Src X)+code :: Text -> IO (Expr Src X) code = codeWith Dhall.Context.empty -codeWith :: Context (Expr Src X) -> Data.Text.Text -> IO (Expr Src X)-codeWith ctx strictText = do-    let lazyText = Data.Text.Lazy.fromStrict strictText-    expr0 <- case Dhall.Parser.exprFromText mempty lazyText of+codeWith :: Context (Expr Src X) -> Text -> IO (Expr Src X)+codeWith ctx expr = do+    expr0 <- case Dhall.Parser.exprFromText mempty expr of         Left parseError -> Control.Exception.throwIO parseError         Right expr0     -> return expr0     expr1 <- Dhall.Import.load expr0@@ -49,19 +47,19 @@         Right _        -> return ()     return expr1 -equivalent :: Data.Text.Text -> Data.Text.Text -> IO ()+equivalent :: Text -> Text -> IO () equivalent text0 text1 = do     expr0 <- fmap Dhall.Core.normalize (Util.code text0) :: IO (Expr X X)     expr1 <- fmap Dhall.Core.normalize (Util.code text1) :: IO (Expr X X)     assertEqual "Expressions are not equivalent" expr0 expr1 -assertNormalizesTo :: Expr Src X -> Data.Text.Lazy.Text -> IO ()-assertNormalizesTo e expected = do +assertNormalizesTo :: Expr Src X -> Text -> IO ()+assertNormalizesTo e expected = do   assertBool msg (not $ Dhall.Core.isNormalized e)   normalize' e @?= expected   where msg = "Given expression is already in normal form" -assertNormalizesToWith :: Normalizer X -> Expr Src X -> Data.Text.Lazy.Text -> IO ()+assertNormalizesToWith :: Normalizer X -> Expr Src X -> Text -> IO () assertNormalizesToWith ctx e expected = do   assertBool msg (not $ Dhall.Core.isNormalizedWith ctx (first (const ()) e))   normalizeWith' ctx e @?= expected
+ tests/format/ifThenElseA.dhall view
@@ -0,0 +1,2 @@+if True then if True then if True then 1 else 2 else if True then 3 else 4+else if True then if True then 5 else 6 else if True then 7 else 8
+ tests/format/ifThenElseB.dhall view
@@ -0,0 +1,13 @@+      if True++then  if True then if True then 1 else 2 else if True then 3 else 4++else  if True++then  if True then 5 else 6++else  if True++then  7++else  8
+ tests/format/importAccessA.dhall view
@@ -0,0 +1,1 @@+(./testImport).hello
+ tests/format/importAccessB.dhall view
@@ -0,0 +1,1 @@+(./testImport).hello
+ tests/format/importLines2A.dhall view
@@ -0,0 +1,2 @@+let _ = ./emptyRecordA.dhall+in let _ = ./emptyRecordA.dhall in 123
+ tests/format/importLines2B.dhall view
@@ -0,0 +1,1 @@+let _ = ./emptyRecordA.dhall in let _ = ./emptyRecordA.dhall in 123
+ tests/format/importLinesA.dhall view
@@ -0,0 +1,7 @@+let _ = ./emptyRecordA.dhall+in  let _ = ./emptyRecordA.dhall+in  let _ = ./emptyRecordA.dhall+in  let _ = ./emptyRecordA.dhall+in  let _ = ./emptyRecordA.dhall+in  let _ = ./emptyRecordA.dhall+in  123
+ tests/format/importLinesB.dhall view
@@ -0,0 +1,13 @@+    let _ = ./emptyRecordA.dhall++in  let _ = ./emptyRecordA.dhall++in  let _ = ./emptyRecordA.dhall++in  let _ = ./emptyRecordA.dhall++in  let _ = ./emptyRecordA.dhall++in  let _ = ./emptyRecordA.dhall++in  123
+ tests/format/importSuffixA.dhall view
@@ -0,0 +1,1 @@+let a = env:AAA      as Text in a
+ tests/format/importSuffixB.dhall view
@@ -0,0 +1,1 @@+let a = env:AAA as Text in a
+ tests/format/sha256PrintingA.dhall view
@@ -0,0 +1,2 @@+let replicate =+    https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate sha256:b0e3ec1797b32c80c0bcb7e8254b08c7e9e35e75e6b410c7ac21477ab90167ad in  replicate 5
+ tests/format/sha256PrintingB.dhall view
@@ -0,0 +1,4 @@+    let replicate =+          https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate sha256:b0e3ec1797b32c80c0bcb7e8254b08c7e9e35e75e6b410c7ac21477ab90167ad++in  replicate 5
+ tests/import/alternativeEnv.dhall view
@@ -0,0 +1,1 @@+env:UNSET1 as Text ? env:UNSET2 ? missing ? env:UNSET3
+ tests/import/alternativeEnvMissing.dhall view
@@ -0,0 +1,1 @@+env:UNSET ? missing
+ tests/import/alternativeEnvNatural.dhall view
@@ -0,0 +1,1 @@+env:UNSET1 as Text ? env:UNSET2 ? missing ? env:UNSET3 ? 2
+ tests/import/alternativeEnvSimple.dhall view
@@ -0,0 +1,1 @@+env:UNSET ? 3
+ tests/import/alternativeNatural.dhall view
@@ -0,0 +1,1 @@+4 ? missing
+ tests/import/missing.dhall view
@@ -0,0 +1,1 @@+missing
+ tests/normalization/examples/Integer/toDouble/0A.dhall view
@@ -0,0 +1,1 @@+../../../../../Prelude/Integer/toDouble -3
+ tests/normalization/examples/Integer/toDouble/0B.dhall view
@@ -0,0 +1,1 @@+-3.0
+ tests/normalization/examples/Integer/toDouble/1A.dhall view
@@ -0,0 +1,1 @@+../../../../../Prelude/Integer/toDouble +2
+ tests/normalization/examples/Integer/toDouble/1B.dhall view
@@ -0,0 +1,1 @@+2.0
tests/normalization/examples/List/indexed/0A.dhall view
@@ -1,1 +1,1 @@-../../../../../Prelude/List/indexed Bool ([] : List Bool)+../../../../../Prelude/List/indexed Bool [ True, False, True ]
tests/normalization/examples/List/indexed/0B.dhall view
@@ -1,4 +1,4 @@-[ { index = +0, value = True }-, { index = +1, value = False }-, { index = +2, valu;e = True }+[ { index = 0, value = True }+, { index = 1, value = False }+, { index = 2, value = True } ]
+ tests/normalization/examples/Natural/toDouble/0A.dhall view
@@ -0,0 +1,1 @@+../../../../../Prelude/Natural/toDouble 3
+ tests/normalization/examples/Natural/toDouble/0B.dhall view
@@ -0,0 +1,1 @@+3.0
+ tests/normalization/examples/Natural/toDouble/1A.dhall view
@@ -0,0 +1,1 @@+../../../../../Prelude/Natural/toDouble 0
+ tests/normalization/examples/Natural/toDouble/1B.dhall view
@@ -0,0 +1,1 @@+0.0
+ tests/normalization/multiLineA.dhall view
@@ -0,0 +1,4 @@+''+ foo+bar+''
+ tests/normalization/multiLineB.dhall view
@@ -0,0 +1,4 @@+''+ foo+bar+''
+ tests/parser/collectionImportType.dhall view
@@ -0,0 +1,3 @@+{ example0 = [] : Optional ./type.dhall+, example1 = [] : List ./type.dhall+}
+ tests/parser/failure/duplicateFields.dhall view
@@ -0,0 +1,1 @@+{ a = 1, a = 2 }
+ tests/parser/failure/importAccess.dhall view
@@ -0,0 +1,1 @@+./testImport .hello
+ tests/parser/importAlt.dhall view
@@ -0,0 +1,1 @@+env:UNSET1 as Text ? env:UNSET2 ? missing ? env:UNSET3 ? 2
+ tests/parser/parenthesizeUsing.dhall view
@@ -0,0 +1,1 @@+https://raw.githubusercontent.com/dhall-lang/Prelude/c79c2bc3c46f129cc5b6d594ce298a381bcae92c/List/replicate using (./a.dhall sha256:16173e984d35ee3ffd8b6b79167df89480e67d1cd03ea5d0fc93689e4d928e61) sha256:b0e3ec1797b32c80c0bcb7e8254b08c7e9e35e75e6b410c7ac21477ab90167ad
tests/parser/urls.dhall view
@@ -2,6 +2,7 @@ , https://john:doe@example.com:8080/foo/bar?qux=0#xyzzy , http://prelude.dhall-lang.org/package.dhall , https://ipfs.io/ipfs/QmQ8w5PLcsNz56dMvRtq54vbuPe9cNnCCUXAQp6xLc6Ccx/Prelude+, https://raw.githubusercontent.com/dhall-lang/dhall-haskell/18e4e9a18dc53271146df3ccf5b4177c3552236b/examples/True , https://127.0.0.1/index.dhall , https://[::]/index.dhall , https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]/tutorial.dhall