packages feed

dhall 1.15.1 → 1.16.0

raw patch · 20 files changed

+345/−183 lines, 20 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- 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: inputWith :: Type a -> Context (Expr Src X) -> Normalizer X -> Text -> IO a
+ Dhall: class HasEvaluateSettings s
+ Dhall: data EvaluateSettings
+ Dhall: data InputSettings
+ Dhall: defaultEvaluateSettings :: EvaluateSettings
+ Dhall: defaultInputSettings :: InputSettings
+ Dhall: inputExprWithSettings :: InputSettings -> Text -> IO (Expr Src X)
+ Dhall: inputFile :: Type a -> FilePath -> IO a
+ Dhall: inputFileWithSettings :: EvaluateSettings -> Type a -> FilePath -> IO a
+ Dhall: inputWithSettings :: InputSettings -> Type a -> Text -> IO a
+ Dhall: instance Dhall.HasEvaluateSettings Dhall.EvaluateSettings
+ Dhall: instance Dhall.HasEvaluateSettings Dhall.InputSettings
+ Dhall: normalizer :: (Functor f, HasEvaluateSettings s) => LensLike' f s (ReifiedNormalizer X)
+ Dhall: rootDirectory :: (Functor f) => LensLike' f InputSettings FilePath
+ Dhall: sourceName :: (Functor f) => LensLike' f InputSettings FilePath
+ Dhall: startingContext :: (Functor f, HasEvaluateSettings s) => LensLike' f s (Context (Expr Src X))
+ Dhall.Core: ReifiedNormalizer :: Normalizer a -> ReifiedNormalizer a
+ Dhall.Core: [getReifiedNormalizer] :: ReifiedNormalizer a -> Normalizer a
+ Dhall.Core: data ReifiedNormalizer a
+ Dhall.Import: loadDirWith :: MonadCatch m => FilePath -> (Import -> StateT Status m (Expr Src Import)) -> Context (Expr Src X) -> Normalizer X -> Expr Src Import -> m (Expr Src X)
+ Dhall.Pretty: layoutOpts :: LayoutOptions
- Dhall.Import: Imported :: [Import] -> e -> Imported e
+ Dhall.Import: Imported :: NonEmpty Import -> e -> Imported e
- Dhall.Import: Status :: [Import] -> Map Import (Expr Src X) -> Maybe Dynamic -> Status
+ Dhall.Import: Status :: NonEmpty Import -> Map Import (Expr Src X) -> Maybe Dynamic -> Status
- Dhall.Import: [_stack] :: Status -> [Import]
+ Dhall.Import: [_stack] :: Status -> NonEmpty Import
- Dhall.Import: [importStack] :: Imported e -> [Import]
+ Dhall.Import: [importStack] :: Imported e -> NonEmpty Import
- Dhall.Import: emptyStatus :: Status
+ Dhall.Import: emptyStatus :: FilePath -> Status

Files

CHANGELOG.md view
@@ -1,3 +1,12 @@+1.16.0++* BREAKING CHANGE: Consolidate `input` family of functions+    * These now take a record of options+    * This also `_stack` field of the `Status` type from `[Import]` to+      `NonEmpty Import`+* Permit `$` in quoted variable names+    * See: https://github.com/dhall-lang/dhall-haskell/pull/510+ 1.15.1  * Fix infinite loop when formatting expressions containing `?`
dhall.cabal view
@@ -1,5 +1,5 @@ Name: dhall-Version: 1.15.1+Version: 1.16.0 Cabal-Version: >=1.10 Build-Type: Simple Tested-With: GHC == 8.0.1
src/Dhall.hs view
@@ -19,11 +19,20 @@     (     -- * Input       input-    , inputFrom-    , inputWith-    , inputFromWith+    , inputWithSettings+    , inputFile+    , inputFileWithSettings     , inputExpr-    , inputExprWith+    , inputExprWithSettings+    , rootDirectory+    , sourceName+    , startingContext+    , normalizer+    , defaultInputSettings+    , InputSettings+    , defaultEvaluateSettings+    , EvaluateSettings+    , HasEvaluateSettings     , detailed      -- * Types@@ -85,8 +94,10 @@ import Dhall.Parser (Src(..)) import Dhall.TypeCheck (DetailedTypeError(..), TypeError, X) import GHC.Generics+import Lens.Family (LensLike', view) import Numeric.Natural (Natural) import Prelude hiding (maybe, sequence)+import System.FilePath (takeDirectory)  import qualified Control.Applicative import qualified Control.Exception@@ -98,6 +109,7 @@ import qualified Data.Sequence import qualified Data.Set import qualified Data.Text+import qualified Data.Text.IO import qualified Data.Text.Lazy import qualified Data.Vector import qualified Dhall.Context@@ -135,6 +147,98 @@  instance Exception InvalidType +-- | @since 1.16+data InputSettings = InputSettings+  { _rootDirectory :: FilePath+  , _sourceName :: FilePath+  , _evaluateSettings :: EvaluateSettings+  }++-- | Default input settings: resolves imports relative to @.@ (the+-- current working directory), report errors as coming from @(input)@,+-- and default evaluation settings from 'defaultEvaluateSettings'.+--+-- @since 1.16+defaultInputSettings :: InputSettings+defaultInputSettings = InputSettings+  { _rootDirectory = "."+  , _sourceName = "(input)"+  , _evaluateSettings = defaultEvaluateSettings+  }++-- | Access the directory to resolve imports relative to.+--+-- @since 1.16+rootDirectory+  :: (Functor f)+  => LensLike' f InputSettings FilePath+rootDirectory k s =+  fmap (\x -> s { _rootDirectory = x }) (k (_rootDirectory s))++-- | Access the name of the source to report locations from; this is+-- only used in error messages, so it's okay if this is a best guess+-- or something symbolic.+--+-- @since 1.16+sourceName+  :: (Functor f)+  => LensLike' f InputSettings FilePath+sourceName k s =+  fmap (\x -> s { _sourceName = x}) (k (_sourceName s))++-- | @since 1.16+data EvaluateSettings = EvaluateSettings+  { _startingContext :: Dhall.Context.Context (Expr Src X)+  , _normalizer :: Dhall.Core.ReifiedNormalizer X+  }++-- | Default evaluation settings: no extra entries in the initial+-- context, and no special normalizer behaviour.+--+-- @since 1.16+defaultEvaluateSettings :: EvaluateSettings+defaultEvaluateSettings = EvaluateSettings+  { _startingContext = Dhall.Context.empty+  , _normalizer = Dhall.Core.ReifiedNormalizer (const Nothing)+  }++-- | Access the starting context used for evaluation and type-checking.+--+-- @since 1.16+startingContext+  :: (Functor f, HasEvaluateSettings s)+  => LensLike' f s (Dhall.Context.Context (Expr Src X))+startingContext = evaluateSettings . l+  where+    l :: (Functor f)+      => LensLike' f EvaluateSettings (Dhall.Context.Context (Expr Src X))+    l k s = fmap (\x -> s { _startingContext = x}) (k (_startingContext s))++-- | Access the custom normalizer.+--+-- @since 1.16+normalizer+  :: (Functor f, HasEvaluateSettings s)+  => LensLike' f s (Dhall.Core.ReifiedNormalizer X)+normalizer = evaluateSettings . l+  where+    l :: (Functor f)+      => LensLike' f EvaluateSettings (Dhall.Core.ReifiedNormalizer X)+    l k s = fmap (\x -> s { _normalizer = x }) (k (_normalizer s))++-- | @since 1.16+class HasEvaluateSettings s where+  evaluateSettings+    :: (Functor f)+    => LensLike' f s EvaluateSettings++instance HasEvaluateSettings InputSettings where+  evaluateSettings k s =+    fmap (\x -> s { _evaluateSettings = x }) (k (_evaluateSettings s))++instance HasEvaluateSettings EvaluateSettings where+  evaluateSettings = id+ {-| Type-check and evaluate a Dhall program, decoding the result into Haskell      The first argument determines the type of value that you decode:@@ -149,6 +253,8 @@  >>> input auto "True" :: IO Bool True++    This uses the settings from 'defaultInputSettings'. -} input     :: Type a@@ -158,54 +264,30 @@     -> IO a     -- ^ The decoded value in Haskell 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.---}-inputWith-    :: 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-inputWith =-  inputFromWith "(input)"+  inputWithSettings defaultInputSettings -{-| Extend 'inputFrom' with a custom typing context and normalization process.+{-| Extend 'input' with a root directory to resolve imports relative+    to, a file to mention in errors as the source, a custom typing+    context, and a custom normalization process. +@since 1.16 -}-inputFromWith-    :: FilePath-    -- ^ The source file to report locations from; only used in error messages+inputWithSettings+    :: InputSettings     -> 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+inputWithSettings settings (Type {..}) txt = do+    expr  <- throws (Dhall.Parser.exprFromText (view sourceName settings) txt)+    expr' <- Dhall.Import.loadDirWith+               (view rootDirectory settings)+               Dhall.Import.exprFromImport+               (view startingContext settings)+               (Dhall.Core.getReifiedNormalizer (view normalizer settings))+               expr     let suffix = Dhall.Pretty.Internal.prettyToStrictText expected     let annot = case expr' of             Note (Src begin end bytes) _ ->@@ -214,36 +296,85 @@                 bytes' = bytes <> " : " <> suffix             _ ->                 Annot expr' expected-    _ <- throws (Dhall.TypeCheck.typeWith ctx annot)-    case extract (Dhall.Core.normalizeWith n expr') of+    _ <- throws (Dhall.TypeCheck.typeWith (view startingContext settings) annot)+    case extract (Dhall.Core.normalizeWith (Dhall.Core.getReifiedNormalizer (view normalizer settings)) expr') of         Just x  -> return x         Nothing -> Control.Exception.throwIO InvalidType +{-| Type-check and evaluate a Dhall program that is read from the+    file-system.++    This uses the settings from 'defaultEvaluateSettings'.++    @since 1.16+-}+inputFile+  :: Type a+  -- ^ The type of value to decode from Dhall to Haskell+  -> FilePath+  -- ^ The path to the Dhall program.+  -> IO a+  -- ^ The decoded value in Haskell.+inputFile =+  inputFileWithSettings defaultEvaluateSettings++{-| Extend 'inputFile' with a custom typing context and a custom+    normalization process.++@since 1.16+-}+inputFileWithSettings+  :: EvaluateSettings+  -> Type a+  -- ^ The type of value to decode from Dhall to Haskell+  -> FilePath+  -- ^ The path to the Dhall program.+  -> IO a+  -- ^ The decoded value in Haskell.+inputFileWithSettings settings ty path = do+  text <- Data.Text.IO.readFile path+  let inputSettings = InputSettings+        { _rootDirectory = takeDirectory path+        , _sourceName = path+        , _evaluateSettings = settings+        }+  inputWithSettings inputSettings ty text+ {-| Similar to `input`, but without interpreting the Dhall `Expr` into a Haskell     type.++    Uses the settings from 'defaultInputSettings'. -} inputExpr     :: Text     -- ^ The Dhall program     -> IO (Expr Src X)     -- ^ The fully normalized AST-inputExpr = inputExprWith Dhall.Context.empty (const Nothing)+inputExpr =+  inputExprWithSettings defaultInputSettings -{-| Extend `inputExpr` with a custom typing context and normalization process.+{-| Extend 'inputExpr' with a root directory to resolve imports relative+    to, a file to mention in errors as the source, a custom typing+    context, and a custom normalization process.++@since 1.16 -}-inputExprWith-    :: Dhall.Context.Context (Expr Src X)-    -- ^ The starting context for type-checking-    -> Dhall.Core.Normalizer X+inputExprWithSettings+    :: InputSettings     -> 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')+inputExprWithSettings settings txt = do+    expr  <- throws (Dhall.Parser.exprFromText (view sourceName settings) txt)+    expr' <- Dhall.Import.loadDirWith+               (view rootDirectory settings)+               Dhall.Import.exprFromImport+               (view startingContext settings)+               (Dhall.Core.getReifiedNormalizer (view normalizer settings))+               expr+    _ <- throws (Dhall.TypeCheck.typeWith (view startingContext settings) expr')+    pure (Dhall.Core.normalizeWith (Dhall.Core.getReifiedNormalizer (view normalizer settings)) 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@@ -263,8 +394,6 @@     case extract (Dhall.Core.normalize expr) of         Just x  -> pure x         Nothing -> empty--  {-| Use this to provide more detailed error messages 
src/Dhall/Core.hs view
@@ -36,6 +36,7 @@     , normalize     , normalizeWith     , Normalizer+    , ReifiedNormalizer (..)     , judgmentallyEqual     , subst     , shift@@ -1713,6 +1714,11 @@ -- | Use this to wrap you embedded functions (see `normalizeWith`) to make them --   polymorphic enough to be used. type Normalizer a = forall s. Expr s a -> Maybe (Expr s a)++-- | A reified 'Normalizer', which can be stored in structures without+-- running into impredicative polymorphism.+data ReifiedNormalizer a = ReifiedNormalizer+  { getReifiedNormalizer :: Normalizer a }  -- | Check if an expression is in a normal form given a context of evaluation. --   Unlike `isNormalized`, this will fully normalize and traverse through the expression.
src/Dhall/Format.hs view
@@ -3,7 +3,7 @@ module Dhall.Format ( format ) where  import Dhall.Parser (exprAndHeaderFromText)-import Dhall.Pretty (annToAnsiStyle, prettyExpr)+import Dhall.Pretty (annToAnsiStyle, prettyExpr, layoutOpts)  import Data.Monoid ((<>)) @@ -14,11 +14,6 @@ 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@@ -30,10 +25,9 @@                  let doc = Pretty.pretty header <> Pretty.pretty expr                 System.IO.withFile file System.IO.WriteMode (\handle -> do-                    Pretty.renderIO handle (Pretty.layoutSmart opts doc)+                    Pretty.renderIO handle (Pretty.layoutSmart layoutOpts 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@@ -48,8 +42,8 @@                   then                     Pretty.renderIO                       System.IO.stdout-                      (fmap annToAnsiStyle (Pretty.layoutSmart opts doc))+                      (fmap annToAnsiStyle (Pretty.layoutSmart layoutOpts doc))                   else                     Pretty.renderIO                       System.IO.stdout-                      (Pretty.layoutSmart opts (Pretty.unAnnotate doc))+                      (Pretty.layoutSmart layoutOpts (Pretty.unAnnotate doc))
src/Dhall/Freeze.hs view
@@ -8,7 +8,7 @@ import Dhall.Core import Dhall.Import (load, hashExpression) import Dhall.Parser (exprAndHeaderFromText, Src)-import Dhall.Pretty (annToAnsiStyle)+import Dhall.Pretty (annToAnsiStyle, layoutOpts)  import System.Console.ANSI (hSupportsANSI) import Data.Monoid ((<>))@@ -21,15 +21,8 @@ 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+readInput = maybe Data.Text.IO.getContents Data.Text.IO.readFile  hashImport :: Import -> IO Import hashImport import_ = do@@ -52,8 +45,7 @@ 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+    let stream = Pretty.layoutSmart layoutOpts doc      case inplace of         Just f ->@@ -64,9 +56,9 @@             supportsANSI <- System.Console.ANSI.hSupportsANSI System.IO.stdout             if supportsANSI                 then -                 Pretty.renderIO System.IO.stdout (annToAnsiStyle <$> Pretty.layoutSmart opts doc)+                 Pretty.renderIO System.IO.stdout (annToAnsiStyle <$> Pretty.layoutSmart layoutOpts doc)                else-                 Pretty.renderIO System.IO.stdout (Pretty.layoutSmart opts (Pretty.unAnnotate doc)) +                 Pretty.renderIO System.IO.stdout (Pretty.layoutSmart layoutOpts (Pretty.unAnnotate doc))   freeze :: Maybe FilePath -> IO () freeze inplace = do
src/Dhall/Hash.hs view
@@ -8,11 +8,9 @@ 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
src/Dhall/Import.hs view
@@ -102,6 +102,7 @@       exprFromImport     , load     , loadWith+    , loadDirWith     , loadWithContext     , hashExpression     , hashExpressionToCode@@ -158,8 +159,8 @@ import qualified Data.CaseInsensitive import qualified Data.Foldable -import qualified Data.List                               as List import qualified Data.HashMap.Strict.InsOrd+import qualified Data.List.NonEmpty                      as NonEmpty import qualified Data.Map.Strict                         as Map import qualified Data.Text.Encoding import qualified Data.Text                               as Text@@ -225,23 +226,23 @@  -- | Extend another exception with the current import stack data Imported e = Imported-    { importStack :: [Import] -- ^ Imports resolved so far, in reverse order-    , nested      :: e        -- ^ The nested exception+    { importStack :: NonEmpty Import -- ^ Imports resolved so far, in reverse order+    , nested      :: e               -- ^ The nested exception     } deriving (Typeable)  instance Exception e => Exception (Imported e)  instance Show e => Show (Imported e) where     show (Imported imports e) =-            (case imports of [] -> ""; _ -> "\n")-        ++  unlines (map indent imports')-        ++  show e+           concat (zipWith indent [0..] toDisplay)+        ++ show e       where-        indent (n, import_) =-            take (2 * n) (repeat ' ') ++ "↳ " ++ Dhall.Pretty.Internal.prettyToString import_-        -- Canonicalize all imports-        imports' = zip [0..] (drop 1 (reverse (canonicalizeAll imports)))-+        indent n import_ =+            "\n" ++ replicate (2 * n) ' ' ++ "↳ " ++ Dhall.Pretty.Internal.prettyToString import_+        canonical = NonEmpty.toList (canonicalizeAll imports)+        -- Tthe final (outermost) import is fake to establish the base+        -- directory. Also, we need outermost-first.+        toDisplay = drop 1 (reverse canonical)  -- | Exception thrown when an imported file is missing data MissingFile = MissingFile FilePath@@ -312,8 +313,10 @@         <>  url         <>  "\n" -canonicalizeAll :: [Import] -> [Import]-canonicalizeAll = map canonicalizeImport . List.tails+canonicalizeAll :: NonEmpty Import -> NonEmpty Import+canonicalizeAll = NonEmpty.scanr1 step+  where+    step a parent = canonicalizeImport (a :| [parent])  {-| > canonicalize (canonicalize x) = canonicalize x@@ -369,18 +372,9 @@     canonicalize (Import importHashed importMode) =         Import (canonicalize importHashed) importMode -canonicalizeImport :: [Import] -> Import+canonicalizeImport :: NonEmpty Import -> Import canonicalizeImport imports =-    canonicalize (sconcat (defaultImport :| reverse imports))-  where-    defaultImport =-        Import-            { importMode   = Code-            , importHashed = ImportHashed-                { hash       = Nothing-                , importType = Local Here (File (Directory []) ".")-                }-            }+    canonicalize (sconcat (NonEmpty.reverse imports))  toHeaders   :: Expr s a@@ -534,8 +528,11 @@         RawText -> do             return (TextLit (Chunks [] text)) --- | Resolve all imports within an expression using a custom typing context and--- `Import`-resolving callback in arbitrary `MonadCatch` monad.+-- | Resolve all imports within an expression using a custom typing+-- context and `Import`-resolving callback in arbitrary `MonadCatch`+-- monad.+--+-- This resolves imports relative to @.@ (the current working directory). loadWith     :: MonadCatch m     => (Import -> StateT Status m (Expr Src Import))@@ -544,10 +541,27 @@     -> Expr Src Import     -> m (Expr Src X) loadWith from_import ctx n expr =-    State.evalStateT (loadStaticWith from_import ctx n expr) emptyStatus+    loadDirWith "." from_import ctx n expr --- | Resolve all imports within an expression using a custom typing context.+-- | Resolve all imports within an expression using a custom typing+-- context and `Import`-resolving callback in arbitrary `MonadCatch`+-- monad, relative to a given directory. --+-- @since 1.16+loadDirWith+    :: MonadCatch m+    => FilePath+    -> (Import -> StateT Status m (Expr Src Import))+    -> Dhall.Context.Context (Expr Src X)+    -> Dhall.Core.Normalizer X+    -> Expr Src Import+    -> m (Expr Src X)+loadDirWith dir from_import ctx n expr = do+    State.evalStateT (loadStaticWith from_import ctx n expr) (emptyStatus dir)++-- | Resolve all imports within an expression, relative to @.@ (the+-- current working directory), using a custom typing context.+-- -- @load = loadWithContext Dhall.Context.empty@ loadWithContext     :: Dhall.Context.Context (Expr Src X)@@ -555,8 +569,9 @@     -> Expr Src Import     -> IO (Expr Src X) loadWithContext ctx n expr =-    State.evalStateT (loadStaticWith exprFromImport ctx n expr) emptyStatus+    loadDirWith "." exprFromImport ctx n expr + -- | This loads a \"static\" expression (i.e. an expression free of imports) loadStaticWith     :: MonadCatch m@@ -574,8 +589,9 @@         local (Import (ImportHashed _ (Env     {})) _) = True         local (Import (ImportHashed _ (Missing {})) _) = True -    let parent = canonicalizeImport imports-    let here   = canonicalizeImport (import_:imports)+    let parent   = canonicalizeImport imports+    let imports' = NonEmpty.cons import_ imports+    let here     = canonicalizeImport imports'      if local here && not (local parent)         then throwMissingImport (Imported imports (ReferentiallyOpaque import_))@@ -601,27 +617,26 @@                             -> StateT Status m (Expr Src Import)                         handler₀ e@(MissingImports []) = throwM e                         handler₀ (MissingImports [e]) =-                          throwMissingImport (Imported (import_:imports) e)+                          throwMissingImport (Imported imports' e)                         handler₀ (MissingImports es) = throwM                           (MissingImports                            (fmap-                             (\e -> (toException (Imported (import_:imports) e)))+                             (\e -> (toException (Imported imports' e)))                              es))                         handler₁                             :: (MonadCatch m)                             => SomeException                             -> StateT Status m (Expr Src Import)                         handler₁ e =-                          throwMissingImport (Imported (import_:imports) e)+                          throwMissingImport (Imported imports' e)                      -- This loads a \"dynamic\" expression (i.e. an expression                     -- that might still contain imports)                     let loadDynamic =-                            from_import (canonicalizeImport (import_:imports))+                            from_import here                      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)@@ -637,7 +652,7 @@                     -- There is no need to check expressions that have been                     -- cached, since they have already been checked                     expr''' <- case Dhall.TypeCheck.typeWith ctx expr'' of-                        Left  err -> throwM (Imported (import_:imports) err)+                        Left  err -> throwM (Imported imports' err)                         Right _   -> return (Dhall.Core.normalizeWith n expr'')                     zoom cache (State.put $! Map.insert here expr''' m)                     return expr'''@@ -649,7 +664,7 @@             let actualHash = hashExpression expr             if expectedHash == actualHash                 then return ()-                else throwMissingImport (Imported (import_:imports) (HashMismatch {..}))+                else throwMissingImport (Imported imports' (HashMismatch {..}))      return expr   ImportAlt a b -> loop a `catch` handler₀
src/Dhall/Import/Types.hs view
@@ -1,23 +1,30 @@+{-# LANGUAGE OverloadedStrings   #-} {-# OPTIONS_GHC -Wall #-}  module Dhall.Import.Types where  import Control.Exception (Exception) import Data.Dynamic+import Data.List.NonEmpty (NonEmpty) import Data.Map (Map) import Data.Semigroup ((<>)) import Lens.Family (LensLike')+import System.FilePath (isRelative, splitDirectories)  import qualified Data.Map as Map+import qualified Data.Text -import Dhall.Core (Import, Expr)+import Dhall.Core+  ( Directory (..), Expr, File (..), FilePrefix (..), Import (..)+  , ImportHashed (..), ImportMode (..), ImportType (..)+  ) import Dhall.Parser (Src) import Dhall.TypeCheck (X)   -- | State threaded throughout the import process data Status = Status-    { _stack   :: [Import]+    { _stack   :: NonEmpty Import     -- ^ Stack of `Import`s that we've imported along the way to get to the     -- current point     , _cache   :: Map Import (Expr Src X)@@ -27,11 +34,26 @@     -- ^ Cache for the HTTP `Manager` so that we only acquire it once     } --- | Default starting `Status`-emptyStatus :: Status-emptyStatus = Status [] Map.empty Nothing+-- | Default starting `Status`, importing relative to the given directory.+emptyStatus :: FilePath -> Status+emptyStatus dir = Status (pure rootImport) Map.empty Nothing+  where+    prefix = if isRelative dir+      then Here+      else Absolute+    pathComponents = fmap Data.Text.pack (reverse (splitDirectories dir))+    dirAsFile = File (Directory pathComponents) "."+    -- Fake import to set the directory we're relative to.+    rootImport = Import+      { importHashed = ImportHashed+        { hash = Nothing+        , importType = Local prefix dirAsFile+        }+      , importMode = Code+      } -stack :: Functor f => LensLike' f Status [Import]++stack :: Functor f => LensLike' f Status (NonEmpty Import) stack k s = fmap (\x -> s { _stack = x }) (k (_stack s))  cache :: Functor f => LensLike' f Status (Map Import (Expr Src X))
src/Dhall/Main.hs view
@@ -19,7 +19,7 @@ import Dhall.Core (Expr, Import) import Dhall.Import (Imported(..), load) import Dhall.Parser (Src)-import Dhall.Pretty (annToAnsiStyle, prettyExpr)+import Dhall.Pretty (annToAnsiStyle, prettyExpr, layoutOpts) import Dhall.TypeCheck (DetailedTypeError(..), TypeError, X) import Options.Applicative (Parser, ParserInfo) import System.Exit (exitFailure)@@ -42,6 +42,7 @@ import qualified Dhall.Parser import qualified Dhall.Repl import qualified Dhall.TypeCheck+import qualified GHC.IO.Encoding import qualified Options.Applicative import qualified System.Console.ANSI import qualified System.IO@@ -146,11 +147,6 @@         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@@ -180,7 +176,7 @@  command :: Options -> IO () command (Options {..}) = do-    System.IO.hSetEncoding System.IO.stdin System.IO.utf8+    GHC.IO.Encoding.setLocaleEncoding System.IO.utf8      let handle =                 Control.Exception.handle handler2@@ -207,7 +203,6 @@              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 @@ -215,9 +210,7 @@         render h e = do             let doc = prettyExpr e -            let layoutOptions = opts--            let stream = Pretty.layoutSmart layoutOptions doc+            let stream = Pretty.layoutSmart layoutOpts doc              supportsANSI <- System.Console.ANSI.hSupportsANSI h             let ansiStream =@@ -304,10 +297,9 @@                     let doc = Pretty.pretty header <> Pretty.pretty lintedExpression                      System.IO.withFile file System.IO.WriteMode (\h -> do-                        Pretty.renderIO h (Pretty.layoutSmart opts doc)+                        Pretty.renderIO h (Pretty.layoutSmart layoutOpts 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)@@ -322,11 +314,11 @@                       then                         Pretty.renderIO                           System.IO.stdout-                          (fmap annToAnsiStyle (Pretty.layoutSmart opts doc))+                          (fmap annToAnsiStyle (Pretty.layoutSmart layoutOpts doc))                       else                         Pretty.renderIO                           System.IO.stdout-                          (Pretty.layoutSmart opts (Pretty.unAnnotate doc))+                          (Pretty.layoutSmart layoutOpts (Pretty.unAnnotate doc))  main :: IO () main = do
src/Dhall/Parser/Token.hs view
@@ -173,7 +173,7 @@     _ <- Text.Parser.Char.char '`'     return (Data.Text.pack t)   where-    predicate c = alpha c || digit c || elem c ("-/_:." :: String)+    predicate c = alpha c || digit c || elem c ("$-/_:." :: String)  labels :: Parser (Set Text) labels = do
src/Dhall/Pretty.hs view
@@ -1,6 +1,13 @@ {-| This module contains logic for pretty-printing expressions, including     support for syntax highlighting -}-module Dhall.Pretty ( Ann(..), annToAnsiStyle, prettyExpr ) where+module Dhall.Pretty ( Ann(..), annToAnsiStyle, prettyExpr, layoutOpts ) where  import Dhall.Pretty.Internal+import qualified Data.Text.Prettyprint.Doc as Pretty++layoutOpts :: Pretty.LayoutOptions+layoutOpts =+    Pretty.defaultLayoutOptions+        { Pretty.layoutPageWidth = Pretty.AvailablePerLine 80 1.0 }+
src/Dhall/Repl.hs view
@@ -241,11 +241,7 @@ 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)+  let stream = Pretty.layoutSmart Dhall.Pretty.layoutOpts (Dhall.Pretty.prettyExpr expr)   supportsANSI <- liftIO (System.Console.ANSI.hSupportsANSI handle)   let ansiStream =           if supportsANSI
src/Dhall/TH.hs view
@@ -23,22 +23,23 @@ -} 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+import qualified GHC.IO.Encoding+import qualified System.IO  -- | 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+staticDhallExpression text = do+    runIO (GHC.IO.Encoding.setLocaleEncoding System.IO.utf8)+    expression <- runIO (Dhall.inputExpr text)+    dataToExpQ (\a -> liftText <$> cast a) expression   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/TypeCheck.hs view
@@ -33,7 +33,7 @@ import Data.Typeable (Typeable) import Dhall.Core (Const(..), Chunks(..), Expr(..), Var(..)) import Dhall.Context (Context)-import Dhall.Pretty (Ann)+import Dhall.Pretty (Ann, layoutOpts)  import qualified Data.Foldable import qualified Data.HashMap.Strict@@ -3494,11 +3494,7 @@     }  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 }+    show = Pretty.renderString . Pretty.layoutPretty layoutOpts . Pretty.pretty  instance (Eq a, Pretty s, Pretty a, Typeable s, Typeable a) => Exception (TypeError s a) @@ -3533,11 +3529,7 @@     deriving (Typeable)  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 }+    show = Pretty.renderString . Pretty.layoutPretty layoutOpts . Pretty.pretty  instance (Eq a, Pretty s, Pretty a, Typeable s, Typeable a) => Exception (DetailedTypeError s a) 
tests/Format.hs view
@@ -12,6 +12,7 @@ import qualified Data.Text.Prettyprint.Doc import qualified Data.Text.Prettyprint.Doc.Render.Text import qualified Dhall.Parser+import qualified Dhall.Pretty import qualified Test.Tasty import qualified Test.Tasty.HUnit @@ -56,13 +57,6 @@             "importSuffix"         ] -opts :: Data.Text.Prettyprint.Doc.LayoutOptions-opts =-    Data.Text.Prettyprint.Doc.defaultLayoutOptions-        { Data.Text.Prettyprint.Doc.layoutPageWidth =-            Data.Text.Prettyprint.Doc.AvailablePerLine 80 1.0-        }- should :: Text -> Text -> TestTree should name basename =     Test.Tasty.HUnit.testCase (Data.Text.unpack name) $ do@@ -77,7 +71,7 @@             Right expr -> return expr          let doc        = Data.Text.Prettyprint.Doc.pretty expr-        let docStream  = Data.Text.Prettyprint.Doc.layoutSmart opts doc+        let docStream  = Data.Text.Prettyprint.Doc.layoutSmart Dhall.Pretty.layoutOpts doc         let actualText = Data.Text.Prettyprint.Doc.Render.Text.renderStrict docStream          expectedText <- Data.Text.IO.readFile outputFile
tests/Import.hs view
@@ -10,6 +10,7 @@  import qualified Data.Text import qualified Data.Text.IO+import qualified Dhall.Context import qualified Dhall.Parser import qualified Dhall.Import import qualified Test.Tasty@@ -41,6 +42,12 @@                 "alternative of a Natural and missing"                 "./tests/import/alternativeNatural.dhall"             ]+        , Test.Tasty.testGroup "import relative to argument"+            [ shouldNotFailRelative+                "works"+                "./tests/import/data/foo/bar"+                "./tests/import/relative.dhall"+            ]         ]  shouldNotFail :: Text -> FilePath -> TestTree@@ -50,6 +57,15 @@                      Left  err  -> throwIO err                      Right expr -> return expr     _ <- Dhall.Import.load actualExpr+    return ())++shouldNotFailRelative :: Text -> FilePath -> FilePath -> TestTree+shouldNotFailRelative name dir path = Test.Tasty.HUnit.testCase (Data.Text.unpack name) (do+    text <- Data.Text.IO.readFile path+    expr <- case Dhall.Parser.exprFromText mempty text of+                     Left  err  -> throwIO err+                     Right expr -> return expr+    _ <- Dhall.Import.loadDirWith dir Dhall.Import.exprFromImport Dhall.Context.empty (const Nothing) expr     return ())  shouldFail :: Int -> Text -> FilePath -> TestTree
tests/Regression.hs view
@@ -14,6 +14,7 @@ import qualified Dhall.Context import qualified Dhall.Core import qualified Dhall.Parser+import qualified Dhall.Pretty import qualified Dhall.TypeCheck import qualified System.Timeout import qualified Test.Tasty@@ -141,19 +142,12 @@     Just _ <- System.Timeout.timeout 1000000 (Control.Exception.evaluate $!! text)     return () ) -opts :: Data.Text.Prettyprint.Doc.LayoutOptions-opts =-    Data.Text.Prettyprint.Doc.defaultLayoutOptions-        { Data.Text.Prettyprint.Doc.layoutPageWidth =-            Data.Text.Prettyprint.Doc.AvailablePerLine 80 1.0-        }- issue216 :: TestTree issue216 = Test.Tasty.HUnit.testCase "Issue #216" (do     -- Verify that pretty-printing preserves string interpolation     e <- Util.code "./tests/regression/issue216a.dhall"     let doc       = Data.Text.Prettyprint.Doc.pretty e-    let docStream = Data.Text.Prettyprint.Doc.layoutSmart opts doc+    let docStream = Data.Text.Prettyprint.Doc.layoutSmart Dhall.Pretty.layoutOpts doc     let text0 = Data.Text.Prettyprint.Doc.Render.Text.renderLazy docStream      text1 <- Data.Text.Lazy.IO.readFile "./tests/regression/issue216b.dhall"
+ tests/import/relative.dhall view
@@ -0,0 +1,2 @@+-- This file assumes its base directory is actually ./data/foo/bar/+./a.dhall : Natural
tests/parser/quotedLabel.dhall view
@@ -1,1 +1,4 @@-{ example1 = let `let` = 1 in `let`, example2 = let `:.` = 1 in `:.` }+{ example1 = let `let` = 1 in `let`+, example2 = let `:.` = 1 in `:.`+, example3 = let `$ref` = 1 in `$ref`+}