{-# LANGUAGE ApplicativeDo         #-}
{-# LANGUAGE ConstraintKinds       #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings     #-}
{-# LANGUAGE PolyKinds             #-}
{-# LANGUAGE RankNTypes            #-}
{-# LANGUAGE RecordWildCards       #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE TypeFamilies          #-}
{-# LANGUAGE UndecidableInstances  #-}

{-| Please read the "Dhall.Tutorial" module, which contains a tutorial explaining
    how to use the language, the compiler, and this library
-}

module Dhall
    (
    -- * Input
      input
    , inputWithSettings
    , inputFile
    , inputFileWithSettings
    , inputExpr
    , inputExprWithSettings
    , interpretExpr
    , interpretExprWithSettings
    , fromExpr
    , fromExprWithSettings
    , rootDirectory
    , sourceName
    , startingContext
    , substitutions
    , normalizer
    , newManager
    , defaultInputSettings
    , InputSettings
    , defaultEvaluateSettings
    , EvaluateSettings
    , HasEvaluateSettings(..)
    , detailed

    -- * Decoders
    , module Dhall.Marshal.Decode

    -- * Encoders
    , module Dhall.Marshal.Encode

    -- * Individual phases
    , parseWithSettings
    , resolveWithSettings
    , typecheckWithSettings
    , checkWithSettings
    , expectWithSettings
    , normalizeWithSettings

    -- * Miscellaneous
    , rawInput
    ) where

import Control.Applicative    (Alternative, empty)
import Control.Monad.Catch    (MonadThrow, throwM)
import Data.Either.Validation (Validation (..))
import Data.Void              (Void)
import Dhall.Import           (Imported (..))
import Dhall.Parser           (Src (..))
import Dhall.Syntax           (Expr (..), Import)
import Dhall.TypeCheck        (DetailedTypeError (..), TypeError)
import GHC.Generics
import Lens.Family            (LensLike', view)
import Prelude                hiding (maybe, sequence)
import System.FilePath        (takeDirectory)

import qualified Control.Exception
import qualified Control.Monad.Trans.State.Strict as State
import qualified Data.Text.IO
import qualified Dhall.Context
import qualified Dhall.Core                       as Core
import qualified Dhall.Import
import qualified Dhall.Parser
import qualified Dhall.Pretty.Internal
import qualified Dhall.Substitution
import qualified Dhall.TypeCheck
import qualified Lens.Family

import Dhall.Marshal.Decode
import Dhall.Marshal.Encode

-- | @since 1.16
data InputSettings = InputSettings
  { InputSettings -> FilePath
_rootDirectory :: FilePath
  , InputSettings -> FilePath
_sourceName :: FilePath
  , InputSettings -> EvaluateSettings
_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
defaultInputSettings = InputSettings
  { _rootDirectory :: FilePath
_rootDirectory = FilePath
"."
  , _sourceName :: FilePath
_sourceName = FilePath
"(input)"
  , _evaluateSettings :: EvaluateSettings
_evaluateSettings = EvaluateSettings
defaultEvaluateSettings
  }


-- | Access the directory to resolve imports relative to.
--
-- @since 1.16
rootDirectory
  :: (Functor f)
  => LensLike' f InputSettings FilePath
rootDirectory :: forall (f :: * -> *).
Functor f =>
LensLike' f InputSettings FilePath
rootDirectory FilePath -> f FilePath
k InputSettings
s =
  forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\FilePath
x -> InputSettings
s { _rootDirectory :: FilePath
_rootDirectory = FilePath
x }) (FilePath -> f FilePath
k (InputSettings -> FilePath
_rootDirectory InputSettings
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 :: forall (f :: * -> *).
Functor f =>
LensLike' f InputSettings FilePath
sourceName FilePath -> f FilePath
k InputSettings
s =
  forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\FilePath
x -> InputSettings
s { _sourceName :: FilePath
_sourceName = FilePath
x}) (FilePath -> f FilePath
k (InputSettings -> FilePath
_sourceName InputSettings
s))

-- | @since 1.16
data EvaluateSettings = EvaluateSettings
  { EvaluateSettings -> Substitutions Src Void
_substitutions   :: Dhall.Substitution.Substitutions Src Void
  , EvaluateSettings -> Context (Expr Src Void)
_startingContext :: Dhall.Context.Context (Expr Src Void)
  , EvaluateSettings -> Maybe (ReifiedNormalizer Void)
_normalizer      :: Maybe (Core.ReifiedNormalizer Void)
  , EvaluateSettings -> IO Manager
_newManager      :: IO Dhall.Import.Manager
  }

-- | Default evaluation settings: no extra entries in the initial
-- context, and no special normalizer behaviour.
--
-- @since 1.16
defaultEvaluateSettings :: EvaluateSettings
defaultEvaluateSettings :: EvaluateSettings
defaultEvaluateSettings = EvaluateSettings
  { _substitutions :: Substitutions Src Void
_substitutions   = forall s a. Substitutions s a
Dhall.Substitution.empty
  , _startingContext :: Context (Expr Src Void)
_startingContext = forall a. Context a
Dhall.Context.empty
  , _normalizer :: Maybe (ReifiedNormalizer Void)
_normalizer      = forall a. Maybe a
Nothing
  , _newManager :: IO Manager
_newManager      = IO Manager
Dhall.Import.defaultNewManager
  }

-- | 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 Void))
startingContext :: forall (f :: * -> *) s.
(Functor f, HasEvaluateSettings s) =>
LensLike' f s (Context (Expr Src Void))
startingContext = forall s (f :: * -> *).
(HasEvaluateSettings s, Functor f) =>
LensLike' f s EvaluateSettings
evaluateSettings forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *).
Functor f =>
LensLike' f EvaluateSettings (Context (Expr Src Void))
l
  where
    l :: (Functor f)
      => LensLike' f EvaluateSettings (Dhall.Context.Context (Expr Src Void))
    l :: forall (f :: * -> *).
Functor f =>
LensLike' f EvaluateSettings (Context (Expr Src Void))
l Context (Expr Src Void) -> f (Context (Expr Src Void))
k EvaluateSettings
s = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Context (Expr Src Void)
x -> EvaluateSettings
s { _startingContext :: Context (Expr Src Void)
_startingContext = Context (Expr Src Void)
x}) (Context (Expr Src Void) -> f (Context (Expr Src Void))
k (EvaluateSettings -> Context (Expr Src Void)
_startingContext EvaluateSettings
s))

-- | Access the custom substitutions.
--
-- @since 1.30
substitutions
  :: (Functor f, HasEvaluateSettings s)
  => LensLike' f s (Dhall.Substitution.Substitutions Src Void)
substitutions :: forall (f :: * -> *) s.
(Functor f, HasEvaluateSettings s) =>
LensLike' f s (Substitutions Src Void)
substitutions = forall s (f :: * -> *).
(HasEvaluateSettings s, Functor f) =>
LensLike' f s EvaluateSettings
evaluateSettings forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *).
Functor f =>
LensLike' f EvaluateSettings (Substitutions Src Void)
l
  where
    l :: (Functor f)
      => LensLike' f EvaluateSettings (Dhall.Substitution.Substitutions Src Void)
    l :: forall (f :: * -> *).
Functor f =>
LensLike' f EvaluateSettings (Substitutions Src Void)
l Substitutions Src Void -> f (Substitutions Src Void)
k EvaluateSettings
s = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Substitutions Src Void
x -> EvaluateSettings
s { _substitutions :: Substitutions Src Void
_substitutions = Substitutions Src Void
x }) (Substitutions Src Void -> f (Substitutions Src Void)
k (EvaluateSettings -> Substitutions Src Void
_substitutions EvaluateSettings
s))

-- | Access the custom normalizer.
--
-- @since 1.16
normalizer
  :: (Functor f, HasEvaluateSettings s)
  => LensLike' f s (Maybe (Core.ReifiedNormalizer Void))
normalizer :: forall (f :: * -> *) s.
(Functor f, HasEvaluateSettings s) =>
LensLike' f s (Maybe (ReifiedNormalizer Void))
normalizer = forall s (f :: * -> *).
(HasEvaluateSettings s, Functor f) =>
LensLike' f s EvaluateSettings
evaluateSettings forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *).
Functor f =>
LensLike' f EvaluateSettings (Maybe (ReifiedNormalizer Void))
l
  where
    l :: (Functor f)
      => LensLike' f EvaluateSettings (Maybe (Core.ReifiedNormalizer Void))
    l :: forall (f :: * -> *).
Functor f =>
LensLike' f EvaluateSettings (Maybe (ReifiedNormalizer Void))
l Maybe (ReifiedNormalizer Void)
-> f (Maybe (ReifiedNormalizer Void))
k EvaluateSettings
s = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\Maybe (ReifiedNormalizer Void)
x -> EvaluateSettings
s { _normalizer :: Maybe (ReifiedNormalizer Void)
_normalizer = Maybe (ReifiedNormalizer Void)
x }) (Maybe (ReifiedNormalizer Void)
-> f (Maybe (ReifiedNormalizer Void))
k (EvaluateSettings -> Maybe (ReifiedNormalizer Void)
_normalizer EvaluateSettings
s))

-- | Access the HTTP manager initializer.
--
-- @since 1.36
newManager
  :: (Functor f, HasEvaluateSettings s)
  => LensLike' f s (IO Dhall.Import.Manager)
newManager :: forall (f :: * -> *) s.
(Functor f, HasEvaluateSettings s) =>
LensLike' f s (IO Manager)
newManager = forall s (f :: * -> *).
(HasEvaluateSettings s, Functor f) =>
LensLike' f s EvaluateSettings
evaluateSettings forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *).
Functor f =>
LensLike' f EvaluateSettings (IO Manager)
l
  where
    l :: (Functor f)
      => LensLike' f EvaluateSettings (IO Dhall.Import.Manager)
    l :: forall (f :: * -> *).
Functor f =>
LensLike' f EvaluateSettings (IO Manager)
l IO Manager -> f (IO Manager)
k EvaluateSettings
s = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\IO Manager
x -> EvaluateSettings
s { _newManager :: IO Manager
_newManager = IO Manager
x }) (IO Manager -> f (IO Manager)
k (EvaluateSettings -> IO Manager
_newManager EvaluateSettings
s))

-- | @since 1.16
class HasEvaluateSettings s where
  evaluateSettings
    :: (Functor f)
    => LensLike' f s EvaluateSettings

instance HasEvaluateSettings InputSettings where
  evaluateSettings :: forall (f :: * -> *).
Functor f =>
LensLike' f InputSettings EvaluateSettings
evaluateSettings EvaluateSettings -> f EvaluateSettings
k InputSettings
s =
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\EvaluateSettings
x -> InputSettings
s { _evaluateSettings :: EvaluateSettings
_evaluateSettings = EvaluateSettings
x }) (EvaluateSettings -> f EvaluateSettings
k (InputSettings -> EvaluateSettings
_evaluateSettings InputSettings
s))

instance HasEvaluateSettings EvaluateSettings where
  evaluateSettings :: forall (f :: * -> *).
Functor f =>
LensLike' f EvaluateSettings EvaluateSettings
evaluateSettings = forall a. a -> a
id

-- | Parse an expression, using the supplied `InputSettings`
parseWithSettings :: MonadThrow m => InputSettings -> Text -> m (Expr Src Import)
parseWithSettings :: forall (m :: * -> *).
MonadThrow m =>
InputSettings -> Text -> m (Expr Src Import)
parseWithSettings InputSettings
settings Text
text =
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM forall (m :: * -> *) a. Monad m => a -> m a
return (FilePath -> Text -> Either ParseError (Expr Src Import)
Dhall.Parser.exprFromText (forall a s t b. FoldLike a s t a b -> s -> a
view forall (f :: * -> *).
Functor f =>
LensLike' f InputSettings FilePath
sourceName InputSettings
settings) Text
text)

-- | Type-check an expression, using the supplied `InputSettings`
typecheckWithSettings :: MonadThrow m => InputSettings -> Expr Src Void -> m ()
typecheckWithSettings :: forall (m :: * -> *).
MonadThrow m =>
InputSettings -> Expr Src Void -> m ()
typecheckWithSettings InputSettings
settings Expr Src Void
expression =
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. a -> b -> a
const ()) (forall s.
Context (Expr s Void)
-> Expr s Void -> Either (TypeError s Void) (Expr s Void)
Dhall.TypeCheck.typeWith (forall a s t b. FoldLike a s t a b -> s -> a
view forall (f :: * -> *) s.
(Functor f, HasEvaluateSettings s) =>
LensLike' f s (Context (Expr Src Void))
startingContext InputSettings
settings) Expr Src Void
expression)

{-| Type-check an expression against a type provided as a Dhall expreession,
    using the supplied `InputSettings`
-}
checkWithSettings ::
    MonadThrow m =>
    -- | The input settings
    InputSettings ->
    -- | The expected type of the expression
    Expr Src Void ->
    -- | The expression to check
    Expr Src Void ->
    m ()
checkWithSettings :: forall (m :: * -> *).
MonadThrow m =>
InputSettings -> Expr Src Void -> Expr Src Void -> m ()
checkWithSettings InputSettings
settings Expr Src Void
type_ Expr Src Void
expression = do
    let suffix :: Text
suffix = forall a. Pretty a => a -> Text
Dhall.Pretty.Internal.prettyToStrictText Expr Src Void
type_

    let annotated :: Expr Src Void
annotated = case Expr Src Void
expression of
            Note (Src SourcePos
begin SourcePos
end Text
bytes) Expr Src Void
_ ->
                forall s a. s -> Expr s a -> Expr s a
Note (SourcePos -> SourcePos -> Text -> Src
Src SourcePos
begin SourcePos
end Text
bytes') (forall s a. Expr s a -> Expr s a -> Expr s a
Annot Expr Src Void
expression Expr Src Void
type_)
              where
                bytes' :: Text
bytes' = Text
bytes forall a. Semigroup a => a -> a -> a
<> Text
" : " forall a. Semigroup a => a -> a -> a
<> Text
suffix
            Expr Src Void
_ ->
                forall s a. Expr s a -> Expr s a -> Expr s a
Annot Expr Src Void
expression Expr Src Void
type_

    forall (m :: * -> *).
MonadThrow m =>
InputSettings -> Expr Src Void -> m ()
typecheckWithSettings InputSettings
settings Expr Src Void
annotated

{-| Type-check an expression against a `Decoder`'s expected type, using the
    supplied `InputSettings`.
    This is equivalent of using the 'expected' type of a @Decoder@ as the second
    argument to 'checkWithSettings'.
-}
expectWithSettings :: MonadThrow m => InputSettings -> Decoder a -> Expr Src Void -> m ()
expectWithSettings :: forall (m :: * -> *) a.
MonadThrow m =>
InputSettings -> Decoder a -> Expr Src Void -> m ()
expectWithSettings InputSettings
settings Decoder{Expector (Expr Src Void)
Expr Src Void -> Extractor Src Void a
expected :: forall a. Decoder a -> Expector (Expr Src Void)
extract :: forall a. Decoder a -> Expr Src Void -> Extractor Src Void a
expected :: Expector (Expr Src Void)
extract :: Expr Src Void -> Extractor Src Void a
..} Expr Src Void
expression = do
    Expr Src Void
expected' <- case Expector (Expr Src Void)
expected of
        Success Expr Src Void
x -> forall (m :: * -> *) a. Monad m => a -> m a
return Expr Src Void
x
        Failure ExpectedTypeErrors
e -> forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM ExpectedTypeErrors
e

    forall (m :: * -> *).
MonadThrow m =>
InputSettings -> Expr Src Void -> Expr Src Void -> m ()
checkWithSettings InputSettings
settings Expr Src Void
expected' Expr Src Void
expression

{-| Resolve an expression, using the supplied `InputSettings`

    Note that this also applies any substitutions specified in the
    `InputSettings`
-}
resolveWithSettings :: InputSettings -> Expr Src Import -> IO (Expr Src Void)
resolveWithSettings :: InputSettings -> Expr Src Import -> IO (Expr Src Void)
resolveWithSettings InputSettings
settings Expr Src Import
expression = do
    let InputSettings{FilePath
EvaluateSettings
_evaluateSettings :: EvaluateSettings
_sourceName :: FilePath
_rootDirectory :: FilePath
_evaluateSettings :: InputSettings -> EvaluateSettings
_sourceName :: InputSettings -> FilePath
_rootDirectory :: InputSettings -> FilePath
..} = InputSettings
settings

    let EvaluateSettings{Maybe (ReifiedNormalizer Void)
IO Manager
Context (Expr Src Void)
Substitutions Src Void
_newManager :: IO Manager
_normalizer :: Maybe (ReifiedNormalizer Void)
_startingContext :: Context (Expr Src Void)
_substitutions :: Substitutions Src Void
_newManager :: EvaluateSettings -> IO Manager
_normalizer :: EvaluateSettings -> Maybe (ReifiedNormalizer Void)
_startingContext :: EvaluateSettings -> Context (Expr Src Void)
_substitutions :: EvaluateSettings -> Substitutions Src Void
..} = EvaluateSettings
_evaluateSettings

    let transform :: Status -> Status
transform =
               forall s t a b. ASetter s t a b -> b -> s -> t
Lens.Family.set forall (f :: * -> *).
Functor f =>
LensLike' f Status (Substitutions Src Void)
Dhall.Import.substitutions   Substitutions Src Void
_substitutions
            forall b c a. (b -> c) -> (a -> b) -> a -> c
.  forall s t a b. ASetter s t a b -> b -> s -> t
Lens.Family.set forall (f :: * -> *).
Functor f =>
LensLike' f Status (Maybe (ReifiedNormalizer Void))
Dhall.Import.normalizer      Maybe (ReifiedNormalizer Void)
_normalizer
            forall b c a. (b -> c) -> (a -> b) -> a -> c
.  forall s t a b. ASetter s t a b -> b -> s -> t
Lens.Family.set forall (f :: * -> *).
Functor f =>
LensLike' f Status (Context (Expr Src Void))
Dhall.Import.startingContext Context (Expr Src Void)
_startingContext

    let status :: Status
status = Status -> Status
transform (IO Manager -> FilePath -> Status
Dhall.Import.emptyStatusWithManager IO Manager
_newManager FilePath
_rootDirectory)

    Expr Src Void
resolved <- forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m a
State.evalStateT (Expr Src Import -> StateT Status IO (Expr Src Void)
Dhall.Import.loadWith Expr Src Import
expression) Status
status

    pure (forall s a. Expr s a -> Substitutions s a -> Expr s a
Dhall.Substitution.substitute Expr Src Void
resolved (forall a s t b. FoldLike a s t a b -> s -> a
view forall (f :: * -> *) s.
(Functor f, HasEvaluateSettings s) =>
LensLike' f s (Substitutions Src Void)
substitutions InputSettings
settings))

-- | Normalize an expression, using the supplied `InputSettings`
normalizeWithSettings :: InputSettings -> Expr Src Void -> Expr Src Void
normalizeWithSettings :: InputSettings -> Expr Src Void -> Expr Src Void
normalizeWithSettings InputSettings
settings =
    forall a s t.
Eq a =>
Maybe (ReifiedNormalizer a) -> Expr s a -> Expr t a
Core.normalizeWith (forall a s t b. FoldLike a s t a b -> s -> a
view forall (f :: * -> *) s.
(Functor f, HasEvaluateSettings s) =>
LensLike' f s (Maybe (ReifiedNormalizer Void))
normalizer InputSettings
settings)

{-| Type-check and evaluate a Dhall program, decoding the result into Haskell

    The first argument determines the type of value that you decode:

>>> input integer "+2"
2
>>> input (vector double) "[1.0, 2.0]"
[1.0,2.0]

    Use `auto` to automatically select which type to decode based on the
    inferred return type:

>>> input auto "True" :: IO Bool
True

    This uses the settings from 'defaultInputSettings'.
-}
input
    :: Decoder a
    -- ^ The decoder for the Dhall value
    -> Text
    -- ^ The Dhall program
    -> IO a
    -- ^ The decoded value in Haskell
input :: forall a. Decoder a -> Text -> IO a
input =
  forall a. InputSettings -> Decoder a -> Text -> IO a
inputWithSettings InputSettings
defaultInputSettings

{-| 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
-}
inputWithSettings
    :: InputSettings
    -> Decoder a
    -- ^ The decoder for the Dhall value
    -> Text
    -- ^ The Dhall program
    -> IO a
    -- ^ The decoded value in Haskell
inputWithSettings :: forall a. InputSettings -> Decoder a -> Text -> IO a
inputWithSettings InputSettings
settings decoder :: Decoder a
decoder@Decoder{Expector (Expr Src Void)
Expr Src Void -> Extractor Src Void a
expected :: Expector (Expr Src Void)
extract :: Expr Src Void -> Extractor Src Void a
expected :: forall a. Decoder a -> Expector (Expr Src Void)
extract :: forall a. Decoder a -> Expr Src Void -> Extractor Src Void a
..} Text
text = do
    Expr Src Import
parsed <- forall (m :: * -> *).
MonadThrow m =>
InputSettings -> Text -> m (Expr Src Import)
parseWithSettings InputSettings
settings Text
text

    Expr Src Void
resolved <- InputSettings -> Expr Src Import -> IO (Expr Src Void)
resolveWithSettings InputSettings
settings Expr Src Import
parsed

    forall (m :: * -> *) a.
MonadThrow m =>
InputSettings -> Decoder a -> Expr Src Void -> m ()
expectWithSettings InputSettings
settings Decoder a
decoder Expr Src Void
resolved

    let normalized :: Expr Src Void
normalized = InputSettings -> Expr Src Void -> Expr Src Void
normalizeWithSettings InputSettings
settings Expr Src Void
resolved

    case Expr Src Void -> Extractor Src Void a
extract Expr Src Void
normalized of
        Success a
x -> forall (m :: * -> *) a. Monad m => a -> m a
return a
x
        Failure ExtractErrors Src Void
e -> forall e a. Exception e => e -> IO a
Control.Exception.throwIO ExtractErrors Src Void
e

{-| Type-check and evaluate a Dhall program that is read from the
    file-system.

    This uses the settings from 'defaultEvaluateSettings'.

    @since 1.16
-}
inputFile
  :: Decoder a
  -- ^ The decoder for the Dhall value
  -> FilePath
  -- ^ The path to the Dhall program.
  -> IO a
  -- ^ The decoded value in Haskell.
inputFile :: forall a. Decoder a -> FilePath -> IO a
inputFile =
  forall a. EvaluateSettings -> Decoder a -> FilePath -> IO a
inputFileWithSettings EvaluateSettings
defaultEvaluateSettings

{-| Extend 'inputFile' with a custom typing context and a custom
    normalization process.

@since 1.16
-}
inputFileWithSettings
  :: EvaluateSettings
  -> Decoder a
  -- ^ The decoder for the Dhall value
  -> FilePath
  -- ^ The path to the Dhall program.
  -> IO a
  -- ^ The decoded value in Haskell.
inputFileWithSettings :: forall a. EvaluateSettings -> Decoder a -> FilePath -> IO a
inputFileWithSettings EvaluateSettings
settings Decoder a
ty FilePath
path = do
  Text
text <- FilePath -> IO Text
Data.Text.IO.readFile FilePath
path
  let inputSettings :: InputSettings
inputSettings = InputSettings
        { _rootDirectory :: FilePath
_rootDirectory = FilePath -> FilePath
takeDirectory FilePath
path
        , _sourceName :: FilePath
_sourceName = FilePath
path
        , _evaluateSettings :: EvaluateSettings
_evaluateSettings = EvaluateSettings
settings
        }
  forall a. InputSettings -> Decoder a -> Text -> IO a
inputWithSettings InputSettings
inputSettings Decoder a
ty Text
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 Void)
    -- ^ The fully normalized AST
inputExpr :: Text -> IO (Expr Src Void)
inputExpr =
  InputSettings -> Text -> IO (Expr Src Void)
inputExprWithSettings InputSettings
defaultInputSettings

{-| 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
-}
inputExprWithSettings
    :: InputSettings
    -> Text
    -- ^ The Dhall program
    -> IO (Expr Src Void)
    -- ^ The fully normalized AST
inputExprWithSettings :: InputSettings -> Text -> IO (Expr Src Void)
inputExprWithSettings InputSettings
settings Text
text = do
    Expr Src Import
parsed <- forall (m :: * -> *).
MonadThrow m =>
InputSettings -> Text -> m (Expr Src Import)
parseWithSettings InputSettings
settings Text
text

    Expr Src Void
resolved <- InputSettings -> Expr Src Import -> IO (Expr Src Void)
resolveWithSettings InputSettings
settings Expr Src Import
parsed

    ()
_ <- forall (m :: * -> *).
MonadThrow m =>
InputSettings -> Expr Src Void -> m ()
typecheckWithSettings InputSettings
settings Expr Src Void
resolved

    pure (forall a s t.
Eq a =>
Maybe (ReifiedNormalizer a) -> Expr s a -> Expr t a
Core.normalizeWith (forall a s t b. FoldLike a s t a b -> s -> a
view forall (f :: * -> *) s.
(Functor f, HasEvaluateSettings s) =>
LensLike' f s (Maybe (ReifiedNormalizer Void))
normalizer InputSettings
settings) Expr Src Void
resolved)

{-| Interpret a Dhall Expression

    This takes care of import resolution, type-checking, and normalization
-}
interpretExpr :: Expr Src Import -> IO (Expr Src Void)
interpretExpr :: Expr Src Import -> IO (Expr Src Void)
interpretExpr = InputSettings -> Expr Src Import -> IO (Expr Src Void)
interpretExprWithSettings InputSettings
defaultInputSettings

-- | Like `interpretExpr`, but customizable using `InputSettings`
interpretExprWithSettings
    :: InputSettings -> Expr Src Import -> IO (Expr Src Void)
interpretExprWithSettings :: InputSettings -> Expr Src Import -> IO (Expr Src Void)
interpretExprWithSettings InputSettings
settings Expr Src Import
parsed = do
    Expr Src Void
resolved <- InputSettings -> Expr Src Import -> IO (Expr Src Void)
resolveWithSettings InputSettings
settings Expr Src Import
parsed

    forall (m :: * -> *).
MonadThrow m =>
InputSettings -> Expr Src Void -> m ()
typecheckWithSettings InputSettings
settings Expr Src Void
resolved

    pure (forall a s t.
Eq a =>
Maybe (ReifiedNormalizer a) -> Expr s a -> Expr t a
Core.normalizeWith (forall a s t b. FoldLike a s t a b -> s -> a
view forall (f :: * -> *) s.
(Functor f, HasEvaluateSettings s) =>
LensLike' f s (Maybe (ReifiedNormalizer Void))
normalizer InputSettings
settings) Expr Src Void
resolved)

{- | Decode a Dhall expression

    This takes care of import resolution, type-checking and normalization
-}
fromExpr :: Decoder a -> Expr Src Import -> IO a
fromExpr :: forall a. Decoder a -> Expr Src Import -> IO a
fromExpr = forall a. InputSettings -> Decoder a -> Expr Src Import -> IO a
fromExprWithSettings InputSettings
defaultInputSettings

-- | Like `fromExpr`, but customizable using `InputSettings`
fromExprWithSettings :: InputSettings -> Decoder a -> Expr Src Import -> IO a
fromExprWithSettings :: forall a. InputSettings -> Decoder a -> Expr Src Import -> IO a
fromExprWithSettings InputSettings
settings decoder :: Decoder a
decoder@Decoder{Expector (Expr Src Void)
Expr Src Void -> Extractor Src Void a
expected :: Expector (Expr Src Void)
extract :: Expr Src Void -> Extractor Src Void a
expected :: forall a. Decoder a -> Expector (Expr Src Void)
extract :: forall a. Decoder a -> Expr Src Void -> Extractor Src Void a
..} Expr Src Import
expression = do
    Expr Src Void
resolved <- InputSettings -> Expr Src Import -> IO (Expr Src Void)
resolveWithSettings InputSettings
settings Expr Src Import
expression

    forall (m :: * -> *) a.
MonadThrow m =>
InputSettings -> Decoder a -> Expr Src Void -> m ()
expectWithSettings InputSettings
settings Decoder a
decoder Expr Src Void
resolved

    let normalized :: Expr Src Void
normalized = forall a s t.
Eq a =>
Maybe (ReifiedNormalizer a) -> Expr s a -> Expr t a
Core.normalizeWith (forall a s t b. FoldLike a s t a b -> s -> a
view forall (f :: * -> *) s.
(Functor f, HasEvaluateSettings s) =>
LensLike' f s (Maybe (ReifiedNormalizer Void))
normalizer InputSettings
settings) Expr Src Void
resolved

    case Expr Src Void -> Extractor Src Void a
extract Expr Src Void
normalized of
        Success a
x -> forall (m :: * -> *) a. Monad m => a -> m a
return a
x
        Failure ExtractErrors Src Void
e -> forall e a. Exception e => e -> IO a
Control.Exception.throwIO ExtractErrors Src Void
e

-- | 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 `Core.normalizeWith` easier to use.
--
--   For other use cases, use `input` from "Dhall" module. It will give you
--   a much better user experience.
rawInput
    :: Alternative f
    => Decoder a
    -- ^ The decoder for the Dhall value
    -> Expr s Void
    -- ^ a closed form Dhall program, which evaluates to the expected type
    -> f a
    -- ^ The decoded value in Haskell
rawInput :: forall (f :: * -> *) a s.
Alternative f =>
Decoder a -> Expr s Void -> f a
rawInput (Decoder {Expector (Expr Src Void)
Expr Src Void -> Extractor Src Void a
expected :: Expector (Expr Src Void)
extract :: Expr Src Void -> Extractor Src Void a
expected :: forall a. Decoder a -> Expector (Expr Src Void)
extract :: forall a. Decoder a -> Expr Src Void -> Extractor Src Void a
..}) Expr s Void
expr =
    case Expr Src Void -> Extractor Src Void a
extract (forall a s t. Eq a => Expr s a -> Expr t a
Core.normalize Expr s Void
expr) of
        Success a
x  -> forall (f :: * -> *) a. Applicative f => a -> f a
pure a
x
        Failure ExtractErrors Src Void
_e -> forall (f :: * -> *) a. Alternative f => f a
empty

{-| Use this to provide more detailed error messages

>> input auto "True" :: IO Integer
> *** Exception: Error: Expression doesn't match annotation
>
> True : Integer
>
> (input):1:1

>> detailed (input auto "True") :: IO Integer
> *** Exception: Error: Expression doesn't match annotation
>
> Explanation: You can annotate an expression with its type or kind using the
> ❰:❱ symbol, like this:
>
>
>     ┌───────┐
>     │ x : t │  ❰x❱ is an expression and ❰t❱ is the annotated type or kind of ❰x❱
>     └───────┘
>
> The type checker verifies that the expression's type or kind matches the
> provided annotation
>
> For example, all of the following are valid annotations that the type checker
> accepts:
>
>
>     ┌─────────────┐
>     │ 1 : Natural │  ❰1❱ is an expression that has type ❰Natural❱, so the type
>     └─────────────┘  checker accepts the annotation
>
>
>     ┌───────────────────────┐
>     │ Natural/even 2 : Bool │  ❰Natural/even 2❱ has type ❰Bool❱, so the type
>     └───────────────────────┘  checker accepts the annotation
>
>
>     ┌────────────────────┐
>     │ List : Type → Type │  ❰List❱ is an expression that has kind ❰Type → Type❱,
>     └────────────────────┘  so the type checker accepts the annotation
>
>
>     ┌──────────────────┐
>     │ List Text : Type │  ❰List Text❱ is an expression that has kind ❰Type❱, so
>     └──────────────────┘  the type checker accepts the annotation
>
>
> However, the following annotations are not valid and the type checker will
> reject them:
>
>
>     ┌──────────┐
>     │ 1 : Text │  The type checker rejects this because ❰1❱ does not have type
>     └──────────┘  ❰Text❱
>
>
>     ┌─────────────┐
>     │ List : Type │  ❰List❱ does not have kind ❰Type❱
>     └─────────────┘
>
>
> You or the interpreter annotated this expression:
>
> ↳ True
>
> ... with this type or kind:
>
> ↳ Integer
>
> ... but the inferred type or kind of the expression is actually:
>
> ↳ Bool
>
> Some common reasons why you might get this error:
>
> ● The Haskell Dhall interpreter implicitly inserts a top-level annotation
>   matching the expected type
>
>   For example, if you run the following Haskell code:
>
>
>     ┌───────────────────────────────┐
>     │ >>> input auto "1" :: IO Text │
>     └───────────────────────────────┘
>
>
>   ... then the interpreter will actually type check the following annotated
>   expression:
>
>
>     ┌──────────┐
>     │ 1 : Text │
>     └──────────┘
>
>
>   ... and then type-checking will fail
>
> ────────────────────────────────────────────────────────────────────────────────
>
> True : Integer
>
> (input):1:1

-}
detailed :: IO a -> IO a
detailed :: forall a. IO a -> IO a
detailed =
    forall e a. Exception e => (e -> IO a) -> IO a -> IO a
Control.Exception.handle forall a. TypeError Src Void -> IO a
handler1 forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e a. Exception e => (e -> IO a) -> IO a -> IO a
Control.Exception.handle forall a. Imported (TypeError Src Void) -> IO a
handler0
  where
    handler0 :: Imported (TypeError Src Void) -> IO a
    handler0 :: forall a. Imported (TypeError Src Void) -> IO a
handler0 (Imported NonEmpty Chained
ps TypeError Src Void
e) =
        forall e a. Exception e => e -> IO a
Control.Exception.throwIO (forall e. NonEmpty Chained -> e -> Imported e
Imported NonEmpty Chained
ps (forall s a. TypeError s a -> DetailedTypeError s a
DetailedTypeError TypeError Src Void
e))

    handler1 :: TypeError Src Void -> IO a
    handler1 :: forall a. TypeError Src Void -> IO a
handler1 TypeError Src Void
e = forall e a. Exception e => e -> IO a
Control.Exception.throwIO (forall s a. TypeError s a -> DetailedTypeError s a
DetailedTypeError TypeError Src Void
e)