{-# LANGUAGE RankNTypes      #-}
{-# LANGUAGE RecordWildCards #-}

{-| This module contains the core calculus for the Dhall language.

    Dhall is essentially a fork of the @morte@ compiler but with more built-in
    functionality, better error messages, and Haskell integration
-}

module Dhall.Core (
    -- * Syntax
      Const(..)
    , Directory(..)
    , File(..)
    , FilePrefix(..)
    , Import(..)
    , ImportHashed(..)
    , ImportMode(..)
    , ImportType(..)
    , URL(..)
    , Scheme(..)
    , DhallDouble(..)
    , Var(..)
    , Binding(..)
    , makeBinding
    , Chunks(..)
    , PreferAnnotation(..)
    , RecordField(..)
    , makeRecordField
    , FunctionBinding(..)
    , makeFunctionBinding
    , FieldSelection (..)
    , makeFieldSelection
    , WithComponent (..)
    , Expr(..)

    -- * Normalization
    , alphaNormalize
    , normalize
    , normalizeWith
    , normalizeWithM
    , Normalizer
    , NormalizerM
    , ReifiedNormalizer (..)
    , judgmentallyEqual
    , subst
    , shift
    , isNormalized
    , isNormalizedWith
    , denote
    , renote
    , shallowDenote
    , freeIn

    -- * Pretty-printing
    , pretty

    -- * Optics
    , subExpressions
    , subExpressionsWith
    , chunkExprs
    , bindingExprs
    , recordFieldExprs
    , functionBindingExprs

    -- * Let-blocks
    , multiLet
    , wrapInLets
    , MultiLet(..)

    -- * Miscellaneous
    , internalError
    , reservedIdentifiers
    , escapeText
    , pathCharacter
    , throws
    , Eval.textShow
    , censorExpression
    , censorText
    ) where

import Control.Exception      (Exception)
import Control.Monad.IO.Class (MonadIO (..))
import Data.Text              (Text)
import Dhall.Normalize
import Dhall.Pretty.Internal
import Dhall.Src              (Src (..))
import Dhall.Syntax
import Instances.TH.Lift      ()
import Lens.Family            (over)
import Prettyprinter          (Pretty)

import qualified Control.Exception
import qualified Data.Text
import qualified Dhall.Eval        as Eval

-- | Pretty-print a value
pretty :: Pretty a => a -> Text
pretty :: forall a. Pretty a => a -> Text
pretty = forall a. Pretty a => a -> Text
pretty_
{-# INLINE pretty #-}

{-| Escape a `Data.Text.Text` literal using Dhall's escaping rules

    Note that the result does not include surrounding quotes
-}
escapeText :: Text -> Text
escapeText :: Text -> Text
escapeText = Text -> Text
escapeText_
{-# INLINE escapeText #-}


{-| Utility used to implement the @--censor@ flag, by:

    * Replacing all `Src` text with spaces
    * Replacing all `Dhall.Syntax.Text` literals inside type errors with spaces
-}
censorExpression :: Expr Src a -> Expr Src a
censorExpression :: forall a. Expr Src a -> Expr Src a
censorExpression (TextLit Chunks Src a
chunks) = forall s a. Chunks s a -> Expr s a
TextLit (forall a. Chunks Src a -> Chunks Src a
censorChunks Chunks Src a
chunks)
censorExpression (Note Src
src     Expr Src a
e) = forall s a. s -> Expr s a -> Expr s a
Note (Src -> Src
censorSrc Src
src) (forall a. Expr Src a -> Expr Src a
censorExpression Expr Src a
e)
censorExpression  Expr Src a
e               = forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
over forall (f :: * -> *) s a.
Applicative f =>
(Expr s a -> f (Expr s a)) -> Expr s a -> f (Expr s a)
subExpressions forall a. Expr Src a -> Expr Src a
censorExpression Expr Src a
e

censorChunks :: Chunks Src a -> Chunks Src a
censorChunks :: forall a. Chunks Src a -> Chunks Src a
censorChunks (Chunks [(Text, Expr Src a)]
xys Text
z) = forall s a. [(Text, Expr s a)] -> Text -> Chunks s a
Chunks [(Text, Expr Src a)]
xys' Text
z'
  where
    z' :: Text
z' = Text -> Text
censorText Text
z

    xys' :: [(Text, Expr Src a)]
xys' = [ (Text -> Text
censorText Text
x, forall a. Expr Src a -> Expr Src a
censorExpression Expr Src a
y) | (Text
x, Expr Src a
y) <- [(Text, Expr Src a)]
xys ]

{-| Utility used to censor `Data.Text.Text` by replacing all characters with a
    space
-}
censorText :: Text -> Text
censorText :: Text -> Text
censorText = (Char -> Char) -> Text -> Text
Data.Text.map (\Char
_ -> Char
' ')

censorSrc :: Src -> Src
censorSrc :: Src -> Src
censorSrc (Src { srcText :: Src -> Text
srcText = Text
oldText, SourcePos
srcEnd :: Src -> SourcePos
srcStart :: Src -> SourcePos
srcEnd :: SourcePos
srcStart :: SourcePos
.. }) = Src { srcText :: Text
srcText = Text
newText, SourcePos
srcEnd :: SourcePos
srcStart :: SourcePos
srcEnd :: SourcePos
srcStart :: SourcePos
.. }
  where
    newText :: Text
newText = Text -> Text
censorText Text
oldText

{-| Convenience utility for converting `Either`-based exceptions to `IO`-based
    exceptions
-}
throws :: (Exception e, MonadIO io) => Either e a -> io a
throws :: forall e (io :: * -> *) a.
(Exception e, MonadIO io) =>
Either e a -> io a
throws (Left  e
e) = forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (forall e a. Exception e => e -> IO a
Control.Exception.throwIO e
e)
throws (Right a
r) = forall (m :: * -> *) a. Monad m => a -> m a
return a
r
{-# INLINABLE throws #-}

{- $setup
>>> import qualified Codec.Serialise
>>> import qualified Dhall.Binary
>>> import Data.SpecialValues
>>> import Test.QuickCheck (Arbitrary(..), oneof, elements)
>>> :{
  instance Arbitrary DhallDouble where
    arbitrary = fmap DhallDouble (oneof [ arbitrary, elements specialValues ])
:}
-}