618 lines
20 KiB
Haskell
618 lines
20 KiB
Haskell
{-# LANGUAGE AllowAmbiguousTypes #-}
|
|
{-# LANGUAGE ConstraintKinds #-}
|
|
{-# LANGUAGE DataKinds #-}
|
|
{-# LANGUAGE DeriveAnyClass #-}
|
|
{-# LANGUAGE DeriveDataTypeable #-}
|
|
{-# LANGUAGE DeriveFoldable #-}
|
|
{-# LANGUAGE DeriveFunctor #-}
|
|
{-# LANGUAGE DeriveGeneric #-}
|
|
{-# LANGUAGE DeriveTraversable #-}
|
|
{-# LANGUAGE FlexibleContexts #-}
|
|
{-# LANGUAGE FlexibleInstances #-}
|
|
{-# LANGUAGE FunctionalDependencies #-}
|
|
{-# LANGUAGE GADTs #-}
|
|
{-# LANGUAGE LambdaCase #-}
|
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
|
{-# LANGUAGE OverloadedStrings #-}
|
|
{-# LANGUAGE PatternSynonyms #-}
|
|
{-# LANGUAGE RankNTypes #-}
|
|
{-# LANGUAGE ScopedTypeVariables #-}
|
|
{-# LANGUAGE StandaloneDeriving #-}
|
|
{-# LANGUAGE TemplateHaskell #-}
|
|
{-# LANGUAGE TypeApplications #-}
|
|
{-# LANGUAGE TypeFamilies #-}
|
|
{-# LANGUAGE TypeOperators #-}
|
|
{-# LANGUAGE UndecidableInstances #-}
|
|
{-# LANGUAGE ViewPatterns #-}
|
|
|
|
{-# OPTIONS_GHC -Wno-missing-signatures #-}
|
|
{-# OPTIONS_GHC -Wno-missing-pattern-synonym-signatures #-}
|
|
|
|
module Nix.Value where
|
|
|
|
import Control.Comonad
|
|
import Control.Exception
|
|
import Control.Monad
|
|
import Control.Monad.Free
|
|
import Control.Monad.Trans.Class
|
|
import Control.Monad.Trans.Except
|
|
import qualified Data.Aeson as A
|
|
import Data.Align
|
|
import Data.Eq.Deriving
|
|
import Data.Functor.Classes
|
|
import Data.Functor.Identity
|
|
import Data.HashMap.Lazy ( HashMap )
|
|
import qualified Data.HashMap.Lazy as M
|
|
import Data.Text ( Text )
|
|
import Data.These
|
|
import Data.Typeable ( Typeable )
|
|
import GHC.Generics
|
|
import Lens.Family2
|
|
import Lens.Family2.Stock
|
|
import Lens.Family2.TH
|
|
import Nix.Atoms
|
|
import Nix.Expr.Types
|
|
import Nix.Expr.Types.Annotated
|
|
import Nix.Frames
|
|
import Nix.String
|
|
import Nix.Thunk
|
|
import Nix.Utils
|
|
|
|
-- | An 'NValue' is the most reduced form of an 'NExpr' after evaluation is
|
|
-- completed. 's' is related to the type of errors that might occur during
|
|
-- construction or use of a value.
|
|
data NValueF p m r
|
|
= NVConstantF NAtom
|
|
-- | A string has a value and a context, which can be used to record what a
|
|
-- string has been build from
|
|
| NVStrF NixString
|
|
| NVPathF FilePath
|
|
| NVListF [r]
|
|
| NVSetF (AttrSet r) (AttrSet SourcePos)
|
|
| NVClosureF (Params ()) (m p -> m r)
|
|
-- ^ A function is a closed set of parameters representing the "call
|
|
-- signature", used at application time to check the type of arguments
|
|
-- passed to the function. Since it supports default values which may
|
|
-- depend on other values within the final argument set, this
|
|
-- dependency is represented as a set of pending evaluations. The
|
|
-- arguments are finally normalized into a set which is passed to the
|
|
-- function.
|
|
--
|
|
-- Note that 'm r' is being used here because effectively a function
|
|
-- and its set of default arguments is "never fully evaluated". This
|
|
-- enforces in the type that it must be re-evaluated for each call.
|
|
| NVBuiltinF String (m p -> m r)
|
|
-- ^ A builtin function is itself already in normal form. Also, it may
|
|
-- or may not choose to evaluate its argument in the production of a
|
|
-- result.
|
|
deriving (Generic, Typeable, Functor)
|
|
|
|
-- | This 'Foldable' instance only folds what the value actually is known to
|
|
-- contain at time of fold.
|
|
instance Foldable (NValueF p m) where
|
|
foldMap f = \case
|
|
NVConstantF _ -> mempty
|
|
NVStrF _ -> mempty
|
|
NVPathF _ -> mempty
|
|
NVListF l -> foldMap f l
|
|
NVSetF s _ -> foldMap f s
|
|
NVClosureF _ _ -> mempty
|
|
NVBuiltinF _ _ -> mempty
|
|
|
|
bindNValueF
|
|
:: (Monad m, Monad n)
|
|
=> (forall x . n x -> m x)
|
|
-> (a -> n b)
|
|
-> NValueF p m a
|
|
-> n (NValueF p m b)
|
|
bindNValueF transform f = \case
|
|
NVConstantF a -> pure $ NVConstantF a
|
|
NVStrF s -> pure $ NVStrF s
|
|
NVPathF p -> pure $ NVPathF p
|
|
NVListF l -> NVListF <$> traverse f l
|
|
NVSetF s p -> NVSetF <$> traverse f s <*> pure p
|
|
NVClosureF p g -> pure $ NVClosureF p (transform . f <=< g)
|
|
NVBuiltinF s g -> pure $ NVBuiltinF s (transform . f <=< g)
|
|
|
|
lmapNValueF :: Functor m => (b -> a) -> NValueF a m r -> NValueF b m r
|
|
lmapNValueF f = \case
|
|
NVConstantF a -> NVConstantF a
|
|
NVStrF s -> NVStrF s
|
|
NVPathF p -> NVPathF p
|
|
NVListF l -> NVListF l
|
|
NVSetF s p -> NVSetF s p
|
|
NVClosureF p g -> NVClosureF p (g . fmap f)
|
|
NVBuiltinF s g -> NVBuiltinF s (g . fmap f)
|
|
|
|
liftNValueF
|
|
:: (MonadTrans u, Monad m)
|
|
=> (forall x . u m x -> m x)
|
|
-> NValueF p m a
|
|
-> NValueF p (u m) a
|
|
liftNValueF run = \case
|
|
NVConstantF a -> NVConstantF a
|
|
NVStrF s -> NVStrF s
|
|
NVPathF p -> NVPathF p
|
|
NVListF l -> NVListF l
|
|
NVSetF s p -> NVSetF s p
|
|
NVClosureF p g -> NVClosureF p $ lift . g . run
|
|
NVBuiltinF s g -> NVBuiltinF s $ lift . g . run
|
|
|
|
unliftNValueF
|
|
:: (MonadTrans u, Monad m)
|
|
=> (forall x . u m x -> m x)
|
|
-> NValueF p (u m) a
|
|
-> NValueF p m a
|
|
unliftNValueF run = \case
|
|
NVConstantF a -> NVConstantF a
|
|
NVStrF s -> NVStrF s
|
|
NVPathF p -> NVPathF p
|
|
NVListF l -> NVListF l
|
|
NVSetF s p -> NVSetF s p
|
|
NVClosureF p g -> NVClosureF p $ run . g . lift
|
|
NVBuiltinF s g -> NVBuiltinF s $ run . g . lift
|
|
|
|
type MonadDataContext f (m :: * -> *)
|
|
= (Comonad f, Applicative f, Traversable f, Monad m)
|
|
|
|
-- | At the time of constructor, the expected arguments to closures are values
|
|
-- that may contain thunks. The type of such thunks are fixed at that time.
|
|
newtype NValue' t f m a = NValue { _nValue :: f (NValueF (NValue t f m) m a) }
|
|
deriving (Generic, Typeable, Functor, Foldable)
|
|
|
|
instance Show r => Show (NValueF p m r) where
|
|
showsPrec = flip go where
|
|
go (NVConstantF atom ) = showsCon1 "NVConstant" atom
|
|
go (NVStrF ns ) = showsCon1 "NVStr" (hackyStringIgnoreContext ns)
|
|
go (NVListF lst ) = showsCon1 "NVList" lst
|
|
go (NVSetF attrs _) = showsCon1 "NVSet" attrs
|
|
go (NVClosureF p _) = showsCon1 "NVClosure" p
|
|
go (NVPathF p ) = showsCon1 "NVPath" p
|
|
go (NVBuiltinF name _ ) = showsCon1 "NVBuiltin" name
|
|
|
|
showsCon1 :: Show a => String -> a -> Int -> String -> String
|
|
showsCon1 con a d =
|
|
showParen (d > 10) $ showString (con ++ " ") . showsPrec 11 a
|
|
|
|
instance (Comonad f, Show a) => Show (NValue' t f m a) where
|
|
show (NValue (extract -> v)) = show v
|
|
|
|
type NValue t f m = NValue' t f m t
|
|
|
|
bindNValue
|
|
:: (Traversable f, Monad m, Monad n)
|
|
=> (forall x . n x -> m x)
|
|
-> (a -> n b)
|
|
-> NValue' t f m a
|
|
-> n (NValue' t f m b)
|
|
bindNValue transform f (NValue v) =
|
|
NValue <$> traverse (bindNValueF transform f) v
|
|
|
|
liftNValue
|
|
:: (MonadTrans u, Monad m, Functor (u m), Functor f)
|
|
=> (forall x . u m x -> m x)
|
|
-> NValue' t f m a
|
|
-> NValue' t f (u m) a
|
|
liftNValue run (NValue v) =
|
|
NValue (fmap (lmapNValueF (unliftNValue run) . liftNValueF run) v)
|
|
|
|
unliftNValue
|
|
:: (MonadTrans u, Monad m, Functor (u m), Functor f)
|
|
=> (forall x . u m x -> m x)
|
|
-> NValue' t f (u m) a
|
|
-> NValue' t f m a
|
|
unliftNValue run (NValue v) =
|
|
NValue (fmap (lmapNValueF (liftNValue run) . unliftNValueF run) v)
|
|
|
|
-- | An 'NValueNF' is a fully evaluated value in normal form. An 'NValue f t m' is
|
|
-- a value in head normal form, where only the "top layer" has been
|
|
-- evaluated. An action of type 'm (NValue f t m)' is a pending evualation that
|
|
-- has yet to be performed. An 't' is either a pending evaluation, or
|
|
-- a value in head normal form. A 'NThunkSet' is a set of mappings from keys
|
|
-- to thunks.
|
|
--
|
|
-- The 'Free' structure is used here to represent the possibility that
|
|
-- cycles may appear during normalization.
|
|
|
|
type NValueNF t f m = Free (NValue' t f m) t
|
|
|
|
iterNValue
|
|
:: forall t f m a r
|
|
. MonadDataContext f m
|
|
=> (a -> (NValue' t f m a -> r) -> r)
|
|
-> (NValue' t f m r -> r)
|
|
-> NValue' t f m a
|
|
-> r
|
|
iterNValue k f = f . fmap (\a -> k a (iterNValue k f))
|
|
|
|
iterNValueM
|
|
:: (MonadDataContext f m, Monad n)
|
|
=> (forall x . n x -> m x)
|
|
-> (a -> (NValue' t f m a -> n r) -> n r)
|
|
-> (NValue' t f m r -> n r)
|
|
-> NValue' t f m a
|
|
-> n r
|
|
iterNValueM transform k f =
|
|
f <=< bindNValue transform (\a -> k a (iterNValueM transform k f))
|
|
|
|
iterNValueNF
|
|
:: MonadDataContext f m
|
|
=> (t -> r)
|
|
-> (NValue' t f m r -> r)
|
|
-> NValueNF t f m
|
|
-> r
|
|
iterNValueNF k f = iter f . fmap k
|
|
|
|
sequenceNValueNF
|
|
:: (Functor n, Traversable f, Monad m, Monad n)
|
|
=> (forall x . n x -> m x)
|
|
-> Free (NValue' t f m) (n a)
|
|
-> n (Free (NValue' t f m) a)
|
|
sequenceNValueNF transform = go
|
|
where
|
|
go (Pure a ) = Pure <$> a
|
|
go (Free fa) = Free <$> bindNValue transform go fa
|
|
|
|
iterNValueNFM
|
|
:: forall f m n t r
|
|
. (MonadDataContext f m, Monad n)
|
|
=> (forall x . n x -> m x)
|
|
-> (t -> n r)
|
|
-> (NValue' t f m (n r) -> n r)
|
|
-> NValueNF t f m
|
|
-> n r
|
|
iterNValueNFM transform k f v =
|
|
iterM f =<< sequenceNValueNF transform (fmap k v)
|
|
|
|
nValueFromNF
|
|
:: (MonadThunk t m (NValue t f m), MonadDataContext f m)
|
|
=> NValueNF t f m
|
|
-> NValue t f m
|
|
nValueFromNF = iterNValueNF f (fmap wrapValue)
|
|
where
|
|
f t = query t cyc id
|
|
cyc = nvStr (principledMakeNixStringWithoutContext "<CYCLE>")
|
|
|
|
nValueToNF
|
|
:: (MonadThunk t m (NValue t f m), MonadDataContext f m)
|
|
=> (t -> (NValue t f m -> NValueNF t f m) -> NValueNF t f m)
|
|
-> NValue t f m
|
|
-> NValueNF t f m
|
|
nValueToNF k = iterNValue k Free
|
|
|
|
nValueToNFM
|
|
:: (MonadDataContext f m, Monad n)
|
|
=> (forall x . n x -> m x)
|
|
-> (t -> (NValue t f m -> n (NValueNF t f m)) -> n (NValueNF t f m))
|
|
-> NValue t f m
|
|
-> n (NValueNF t f m)
|
|
nValueToNFM transform k = iterNValueM transform k $ pure . Free
|
|
|
|
pattern NVConstant x <- NValue (extract -> NVConstantF x)
|
|
pattern NVConstantNF x <- Free (NValue (extract -> NVConstantF x))
|
|
|
|
nvConstant :: Applicative f => NAtom -> NValue t f m
|
|
nvConstant x = NValue (pure (NVConstantF x))
|
|
nvConstantNF :: Applicative f => NAtom -> NValueNF t f m
|
|
nvConstantNF x = Free (NValue (pure (NVConstantF x)))
|
|
|
|
pattern NVStr ns <- NValue (extract -> NVStrF ns)
|
|
pattern NVStrNF ns <- Free (NValue (extract -> NVStrF ns))
|
|
|
|
nvStr :: Applicative f => NixString -> NValue t f m
|
|
nvStr ns = NValue (pure (NVStrF ns))
|
|
nvStrNF :: Applicative f => NixString -> NValueNF t f m
|
|
nvStrNF ns = Free (NValue (pure (NVStrF ns)))
|
|
|
|
pattern NVPath x <- NValue (extract -> NVPathF x)
|
|
pattern NVPathNF x <- Free (NValue (extract -> NVPathF x))
|
|
|
|
nvPath :: Applicative f => FilePath -> NValue t f m
|
|
nvPath x = NValue (pure (NVPathF x))
|
|
nvPathNF :: Applicative f => FilePath -> NValueNF t f m
|
|
nvPathNF x = Free (NValue (pure (NVPathF x)))
|
|
|
|
pattern NVList l <- NValue (extract -> NVListF l)
|
|
pattern NVListNF l <- Free (NValue (extract -> NVListF l))
|
|
|
|
nvList :: Applicative f => [t] -> NValue t f m
|
|
nvList l = NValue (pure (NVListF l))
|
|
nvListNF :: Applicative f => [NValueNF t f m] -> NValueNF t f m
|
|
nvListNF l = Free (NValue (pure (NVListF l)))
|
|
|
|
pattern NVSet s x <- NValue (extract -> NVSetF s x)
|
|
pattern NVSetNF s x <- Free (NValue (extract -> NVSetF s x))
|
|
|
|
nvSet :: Applicative f
|
|
=> HashMap Text t -> HashMap Text SourcePos -> NValue t f m
|
|
nvSet s x = NValue (pure (NVSetF s x))
|
|
nvSetNF :: Applicative f
|
|
=> HashMap Text (NValueNF t f m) -> HashMap Text SourcePos -> NValueNF t f m
|
|
nvSetNF s x = Free (NValue (pure (NVSetF s x)))
|
|
|
|
pattern NVClosure x f <- NValue (extract -> NVClosureF x f)
|
|
pattern NVClosureNF x f <- Free (NValue (extract -> NVClosureF x f))
|
|
|
|
nvClosure :: Applicative f
|
|
=> Params () -> (m (NValue t f m) -> m t) -> NValue t f m
|
|
nvClosure x f = NValue (pure (NVClosureF x f))
|
|
nvClosureNF :: Applicative f
|
|
=> Params () -> (m (NValue t f m) -> m (NValueNF t f m)) -> NValueNF t f m
|
|
nvClosureNF x f = Free (NValue (pure (NVClosureF x f)))
|
|
|
|
pattern NVBuiltin name f <- NValue (extract -> NVBuiltinF name f)
|
|
pattern NVBuiltinNF name f <- Free (NValue (extract -> NVBuiltinF name f))
|
|
|
|
nvBuiltin :: Applicative f
|
|
=> String -> (m (NValue t f m) -> m t) -> NValue t f m
|
|
nvBuiltin name f = NValue (pure (NVBuiltinF name f))
|
|
nvBuiltinNF :: Applicative f
|
|
=> String -> (m (NValue t f m) -> m (NValueNF t f m)) -> NValueNF t f m
|
|
nvBuiltinNF name f = Free (NValue (pure (NVBuiltinF name f)))
|
|
|
|
checkComparable
|
|
:: (Framed e m, MonadDataErrorContext t f m)
|
|
=> NValue t f m
|
|
-> NValue t f m
|
|
-> m ()
|
|
checkComparable x y = case (x, y) of
|
|
(NVConstant (NFloat _), NVConstant (NInt _)) -> pure ()
|
|
(NVConstant (NInt _), NVConstant (NFloat _)) -> pure ()
|
|
(NVConstant (NInt _), NVConstant (NInt _)) -> pure ()
|
|
(NVConstant (NFloat _), NVConstant (NFloat _)) -> pure ()
|
|
(NVStr _, NVStr _) -> pure ()
|
|
(NVPath _, NVPath _) -> pure ()
|
|
_ -> throwError $ Comparison x y
|
|
|
|
thunkEqM :: (MonadThunk t m (NValue t f m), Comonad f) => t -> t -> m Bool
|
|
thunkEqM lt rt = force lt $ \lv -> force rt $ \rv ->
|
|
let unsafePtrEq = case (lt, rt) of
|
|
(thunkId -> lid, thunkId -> rid) | lid == rid -> return True
|
|
_ -> valueEqM lv rv
|
|
in case (lv, rv) of
|
|
(NVClosure _ _, NVClosure _ _) -> unsafePtrEq
|
|
(NVList _ , NVList _ ) -> unsafePtrEq
|
|
(NVSet _ _ , NVSet _ _ ) -> unsafePtrEq
|
|
_ -> valueEqM lv rv
|
|
|
|
builtin
|
|
:: forall m f t
|
|
. (MonadThunk t m (NValue t f m), MonadDataContext f m)
|
|
=> String
|
|
-> (m (NValue t f m) -> m (NValue t f m))
|
|
-> m (NValue t f m)
|
|
builtin name f = return $ nvBuiltin name $ thunk . f
|
|
|
|
builtin2
|
|
:: (MonadThunk t m (NValue t f m), MonadDataContext f m)
|
|
=> String
|
|
-> (m (NValue t f m) -> m (NValue t f m) -> m (NValue t f m))
|
|
-> m (NValue t f m)
|
|
builtin2 name f = builtin name (builtin name . f)
|
|
|
|
builtin3
|
|
:: (MonadThunk t m (NValue t f m), MonadDataContext f m)
|
|
=> String
|
|
-> ( m (NValue t f m)
|
|
-> m (NValue t f m)
|
|
-> m (NValue t f m)
|
|
-> m (NValue t f m)
|
|
)
|
|
-> m (NValue t f m)
|
|
builtin3 name f =
|
|
builtin name $ \a -> builtin name $ \b -> builtin name $ \c -> f a b c
|
|
|
|
isClosureNF :: Comonad f => NValueNF t f m -> Bool
|
|
isClosureNF NVClosureNF{} = True
|
|
isClosureNF _ = False
|
|
|
|
-- | Checks whether two containers are equal, using the given item equality
|
|
-- predicate. If there are any item slots that don't match between the two
|
|
-- containers, the result will be False.
|
|
alignEqM
|
|
:: (Align f, Traversable f, Monad m)
|
|
=> (a -> b -> m Bool)
|
|
-> f a
|
|
-> f b
|
|
-> m Bool
|
|
alignEqM eq fa fb = fmap (either (const False) (const True)) $ runExceptT $ do
|
|
pairs <- forM (Data.Align.align fa fb) $ \case
|
|
These a b -> return (a, b)
|
|
_ -> throwE ()
|
|
forM_ pairs $ \(a, b) -> guard =<< lift (eq a b)
|
|
|
|
alignEq :: (Align f, Traversable f) => (a -> b -> Bool) -> f a -> f b -> Bool
|
|
alignEq eq fa fb = runIdentity $ alignEqM (\x y -> Identity (eq x y)) fa fb
|
|
|
|
isDerivationM :: Monad m => (t -> m (Maybe NixString)) -> AttrSet t -> m Bool
|
|
isDerivationM f m = case M.lookup "type" m of
|
|
Nothing -> pure False
|
|
Just t -> do
|
|
mres <- f t
|
|
case mres of
|
|
-- We should probably really make sure the context is empty here
|
|
-- but the C++ implementation ignores it.
|
|
Just s -> pure $ principledStringIgnoreContext s == "derivation"
|
|
Nothing -> pure False
|
|
|
|
isDerivation :: Monad m => (t -> Maybe NixString) -> AttrSet t -> Bool
|
|
isDerivation f = runIdentity . isDerivationM (\x -> Identity (f x))
|
|
|
|
valueFEqM
|
|
:: Monad n
|
|
=> (AttrSet a -> AttrSet a -> n Bool)
|
|
-> (a -> a -> n Bool)
|
|
-> NValueF p m a
|
|
-> NValueF p m a
|
|
-> n Bool
|
|
valueFEqM attrsEq eq = curry $ \case
|
|
(NVConstantF (NFloat x), NVConstantF (NInt y) ) -> pure $ x == fromInteger y
|
|
(NVConstantF (NInt x), NVConstantF (NFloat y)) -> pure $ fromInteger x == y
|
|
(NVConstantF lc , NVConstantF rc ) -> pure $ lc == rc
|
|
(NVStrF ls, NVStrF rs) ->
|
|
pure $ principledStringIgnoreContext ls == principledStringIgnoreContext rs
|
|
(NVListF ls , NVListF rs ) -> alignEqM eq ls rs
|
|
(NVSetF lm _, NVSetF rm _) -> attrsEq lm rm
|
|
(NVPathF lp , NVPathF rp ) -> pure $ lp == rp
|
|
_ -> pure False
|
|
|
|
valueFEq
|
|
:: (AttrSet a -> AttrSet a -> Bool)
|
|
-> (a -> a -> Bool)
|
|
-> NValueF p m a
|
|
-> NValueF p m a
|
|
-> Bool
|
|
valueFEq attrsEq eq x y = runIdentity $ valueFEqM
|
|
(\x' y' -> Identity (attrsEq x' y'))
|
|
(\x' y' -> Identity (eq x' y'))
|
|
x
|
|
y
|
|
|
|
compareAttrSetsM
|
|
:: Monad m
|
|
=> (t -> m (Maybe NixString))
|
|
-> (t -> t -> m Bool)
|
|
-> AttrSet t
|
|
-> AttrSet t
|
|
-> m Bool
|
|
compareAttrSetsM f eq lm rm = do
|
|
isDerivationM f lm >>= \case
|
|
True -> isDerivationM f rm >>= \case
|
|
True
|
|
| Just lp <- M.lookup "outPath" lm, Just rp <- M.lookup "outPath" rm -> eq
|
|
lp
|
|
rp
|
|
_ -> compareAttrs
|
|
_ -> compareAttrs
|
|
where compareAttrs = alignEqM eq lm rm
|
|
|
|
compareAttrSets
|
|
:: (t -> Maybe NixString)
|
|
-> (t -> t -> Bool)
|
|
-> AttrSet t
|
|
-> AttrSet t
|
|
-> Bool
|
|
compareAttrSets f eq lm rm = runIdentity
|
|
$ compareAttrSetsM (\t -> Identity (f t)) (\x y -> Identity (eq x y)) lm rm
|
|
|
|
valueEqM
|
|
:: (MonadThunk t m (NValue t f m), Comonad f)
|
|
=> NValue t f m
|
|
-> NValue t f m
|
|
-> m Bool
|
|
valueEqM (NValue (extract -> x)) (NValue (extract -> y)) = valueFEqM
|
|
(compareAttrSetsM f thunkEqM)
|
|
thunkEqM
|
|
x
|
|
y
|
|
where
|
|
f t = force t $ \case
|
|
NVStr s -> pure $ Just s
|
|
_ -> pure Nothing
|
|
|
|
valueNFEq :: Comonad f => NValueNF t f m -> NValueNF t f m -> Bool
|
|
valueNFEq (Pure _) (Pure _) = False
|
|
valueNFEq (Pure _) (Free _) = False
|
|
valueNFEq (Free _) (Pure _) = False
|
|
valueNFEq (Free (NValue (extract -> x))) (Free (NValue (extract -> y))) =
|
|
valueFEq (compareAttrSets f valueNFEq) valueNFEq x y
|
|
where
|
|
f (Pure _ ) = Nothing
|
|
f (Free (NVStr s)) = Just s
|
|
f _ = Nothing
|
|
|
|
data TStringContext = NoContext | HasContext
|
|
deriving Show
|
|
|
|
data ValueType
|
|
= TInt
|
|
| TFloat
|
|
| TBool
|
|
| TNull
|
|
| TString TStringContext
|
|
| TList
|
|
| TSet
|
|
| TClosure
|
|
| TPath
|
|
| TBuiltin
|
|
deriving Show
|
|
|
|
valueType :: NValueF a m r -> ValueType
|
|
valueType = \case
|
|
NVConstantF a -> case a of
|
|
NInt _ -> TInt
|
|
NFloat _ -> TFloat
|
|
NBool _ -> TBool
|
|
NNull -> TNull
|
|
NVStrF ns | stringHasContext ns -> TString HasContext
|
|
| otherwise -> TString NoContext
|
|
NVListF{} -> TList
|
|
NVSetF{} -> TSet
|
|
NVClosureF{} -> TClosure
|
|
NVPathF{} -> TPath
|
|
NVBuiltinF{} -> TBuiltin
|
|
|
|
describeValue :: ValueType -> String
|
|
describeValue = \case
|
|
TInt -> "an integer"
|
|
TFloat -> "a float"
|
|
TBool -> "a boolean"
|
|
TNull -> "a null"
|
|
TString NoContext -> "a string"
|
|
TString HasContext -> "a string with context"
|
|
TList -> "a list"
|
|
TSet -> "an attr set"
|
|
TClosure -> "a function"
|
|
TPath -> "a path"
|
|
TBuiltin -> "a builtin function"
|
|
|
|
instance Eq1 (NValueF p m) where
|
|
liftEq _ (NVConstantF x) (NVConstantF y) = x == y
|
|
liftEq _ (NVStrF x) (NVStrF y) = x == y
|
|
liftEq eq (NVListF x) (NVListF y) = liftEq eq x y
|
|
liftEq eq (NVSetF x _ ) (NVSetF y _ ) = liftEq eq x y
|
|
liftEq _ (NVPathF x ) (NVPathF y ) = x == y
|
|
liftEq _ _ _ = False
|
|
|
|
instance Comonad f => Show1 (NValue' t f m) where
|
|
liftShowsPrec sp sl p = \case
|
|
NVConstant atom -> showsUnaryWith showsPrec "NVConstantF" p atom
|
|
NVStr ns ->
|
|
showsUnaryWith showsPrec "NVStrF" p (hackyStringIgnoreContext ns)
|
|
NVList lst -> showsUnaryWith (liftShowsPrec sp sl) "NVListF" p lst
|
|
NVSet attrs _ -> showsUnaryWith (liftShowsPrec sp sl) "NVSetF" p attrs
|
|
NVPath path -> showsUnaryWith showsPrec "NVPathF" p path
|
|
NVClosure c _ -> showsUnaryWith showsPrec "NVClosureF" p c
|
|
NVBuiltin name _ -> showsUnaryWith showsPrec "NVBuiltinF" p name
|
|
_ -> error "Pattern synonyms mask coverage"
|
|
|
|
data ValueFrame t f m
|
|
= ForcingThunk
|
|
| ConcerningValue (NValue t f m)
|
|
| Comparison (NValue t f m) (NValue t f m)
|
|
| Addition (NValue t f m) (NValue t f m)
|
|
| Multiplication (NValue t f m) (NValue t f m)
|
|
| Division (NValue t f m) (NValue t f m)
|
|
| Coercion ValueType ValueType
|
|
| CoercionToJson (NValue t f m)
|
|
| CoercionFromJson A.Value
|
|
| ExpectationNF ValueType (NValueNF t f m)
|
|
| Expectation ValueType (NValue t f m)
|
|
deriving (Show, Typeable)
|
|
|
|
type MonadDataErrorContext t f m
|
|
= (Show t, Typeable t, Typeable m, Typeable f, MonadDataContext f m)
|
|
|
|
instance MonadDataErrorContext t f m => Exception (ValueFrame t f m)
|
|
|
|
$(makeTraversals ''NValueF)
|
|
$(makeLenses ''NValue')
|
|
|
|
key
|
|
:: (Traversable f, Applicative g)
|
|
=> VarName
|
|
-> LensLike' g (NValue' t f m a) (Maybe a)
|
|
key k = nValue . traverse . _NVSetF . _1 . hashAt k
|
|
|
|
$(deriveEq1 ''NValue')
|