{-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE UndecidableInstances #-} -- just for the type equality constraint {-# LANGUAGE GADTs #-} module PlutusCore.Quote ( runQuoteT , runQuote , freshUnique , freshName , freshTyName , freshenName , freshenTyName , QuoteT (..) , Quote , MonadQuote , FreshState , liftQuote , markNonFreshBelow , markNonFresh , markNonFreshMax ) where import PlutusPrelude import PlutusCore.Name import Control.Monad.Except import Control.Monad.Morph as MM import Control.Monad.Reader import Control.Monad.State import Control.Monad.Trans.Maybe import Control.Monad.Writer import Data.Functor.Identity import Data.Set (Set) import Data.Set qualified as Set import Data.Text qualified as Text import Hedgehog (GenT, PropertyT) -- | The state contains the "next" 'Unique' that should be used for a name type FreshState = Unique emptyFreshState :: FreshState emptyFreshState :: FreshState emptyFreshState = Int -> FreshState Unique Int 0 -- | The "quotation" monad transformer. Within this monad you can do safe construction of PLC terms using quasiquotation, -- fresh-name generation, and parsing. newtype QuoteT m a = QuoteT { QuoteT m a -> StateT FreshState m a unQuoteT :: StateT FreshState m a } deriving (a -> QuoteT m b -> QuoteT m a (a -> b) -> QuoteT m a -> QuoteT m b (forall a b. (a -> b) -> QuoteT m a -> QuoteT m b) -> (forall a b. a -> QuoteT m b -> QuoteT m a) -> Functor (QuoteT m) forall a b. a -> QuoteT m b -> QuoteT m a forall a b. (a -> b) -> QuoteT m a -> QuoteT m b forall (m :: * -> *) a b. Functor m => a -> QuoteT m b -> QuoteT m a forall (m :: * -> *) a b. Functor m => (a -> b) -> QuoteT m a -> QuoteT m b forall (f :: * -> *). (forall a b. (a -> b) -> f a -> f b) -> (forall a b. a -> f b -> f a) -> Functor f <$ :: a -> QuoteT m b -> QuoteT m a $c<$ :: forall (m :: * -> *) a b. Functor m => a -> QuoteT m b -> QuoteT m a fmap :: (a -> b) -> QuoteT m a -> QuoteT m b $cfmap :: forall (m :: * -> *) a b. Functor m => (a -> b) -> QuoteT m a -> QuoteT m b Functor, Functor (QuoteT m) a -> QuoteT m a Functor (QuoteT m) -> (forall a. a -> QuoteT m a) -> (forall a b. QuoteT m (a -> b) -> QuoteT m a -> QuoteT m b) -> (forall a b c. (a -> b -> c) -> QuoteT m a -> QuoteT m b -> QuoteT m c) -> (forall a b. QuoteT m a -> QuoteT m b -> QuoteT m b) -> (forall a b. QuoteT m a -> QuoteT m b -> QuoteT m a) -> Applicative (QuoteT m) QuoteT m a -> QuoteT m b -> QuoteT m b QuoteT m a -> QuoteT m b -> QuoteT m a QuoteT m (a -> b) -> QuoteT m a -> QuoteT m b (a -> b -> c) -> QuoteT m a -> QuoteT m b -> QuoteT m c forall a. a -> QuoteT m a forall a b. QuoteT m a -> QuoteT m b -> QuoteT m a forall a b. QuoteT m a -> QuoteT m b -> QuoteT m b forall a b. QuoteT m (a -> b) -> QuoteT m a -> QuoteT m b forall a b c. (a -> b -> c) -> QuoteT m a -> QuoteT m b -> QuoteT m c forall (m :: * -> *). Monad m => Functor (QuoteT m) forall (m :: * -> *) a. Monad m => a -> QuoteT m a forall (m :: * -> *) a b. Monad m => QuoteT m a -> QuoteT m b -> QuoteT m a forall (m :: * -> *) a b. Monad m => QuoteT m a -> QuoteT m b -> QuoteT m b forall (m :: * -> *) a b. Monad m => QuoteT m (a -> b) -> QuoteT m a -> QuoteT m b forall (m :: * -> *) a b c. Monad m => (a -> b -> c) -> QuoteT m a -> QuoteT m b -> QuoteT m c forall (f :: * -> *). Functor f -> (forall a. a -> f a) -> (forall a b. f (a -> b) -> f a -> f b) -> (forall a b c. (a -> b -> c) -> f a -> f b -> f c) -> (forall a b. f a -> f b -> f b) -> (forall a b. f a -> f b -> f a) -> Applicative f <* :: QuoteT m a -> QuoteT m b -> QuoteT m a $c<* :: forall (m :: * -> *) a b. Monad m => QuoteT m a -> QuoteT m b -> QuoteT m a *> :: QuoteT m a -> QuoteT m b -> QuoteT m b $c*> :: forall (m :: * -> *) a b. Monad m => QuoteT m a -> QuoteT m b -> QuoteT m b liftA2 :: (a -> b -> c) -> QuoteT m a -> QuoteT m b -> QuoteT m c $cliftA2 :: forall (m :: * -> *) a b c. Monad m => (a -> b -> c) -> QuoteT m a -> QuoteT m b -> QuoteT m c <*> :: QuoteT m (a -> b) -> QuoteT m a -> QuoteT m b $c<*> :: forall (m :: * -> *) a b. Monad m => QuoteT m (a -> b) -> QuoteT m a -> QuoteT m b pure :: a -> QuoteT m a $cpure :: forall (m :: * -> *) a. Monad m => a -> QuoteT m a $cp1Applicative :: forall (m :: * -> *). Monad m => Functor (QuoteT m) Applicative, Applicative (QuoteT m) a -> QuoteT m a Applicative (QuoteT m) -> (forall a b. QuoteT m a -> (a -> QuoteT m b) -> QuoteT m b) -> (forall a b. QuoteT m a -> QuoteT m b -> QuoteT m b) -> (forall a. a -> QuoteT m a) -> Monad (QuoteT m) QuoteT m a -> (a -> QuoteT m b) -> QuoteT m b QuoteT m a -> QuoteT m b -> QuoteT m b forall a. a -> QuoteT m a forall a b. QuoteT m a -> QuoteT m b -> QuoteT m b forall a b. QuoteT m a -> (a -> QuoteT m b) -> QuoteT m b forall (m :: * -> *). Monad m => Applicative (QuoteT m) forall (m :: * -> *) a. Monad m => a -> QuoteT m a forall (m :: * -> *) a b. Monad m => QuoteT m a -> QuoteT m b -> QuoteT m b forall (m :: * -> *) a b. Monad m => QuoteT m a -> (a -> QuoteT m b) -> QuoteT m b forall (m :: * -> *). Applicative m -> (forall a b. m a -> (a -> m b) -> m b) -> (forall a b. m a -> m b -> m b) -> (forall a. a -> m a) -> Monad m return :: a -> QuoteT m a $creturn :: forall (m :: * -> *) a. Monad m => a -> QuoteT m a >> :: QuoteT m a -> QuoteT m b -> QuoteT m b $c>> :: forall (m :: * -> *) a b. Monad m => QuoteT m a -> QuoteT m b -> QuoteT m b >>= :: QuoteT m a -> (a -> QuoteT m b) -> QuoteT m b $c>>= :: forall (m :: * -> *) a b. Monad m => QuoteT m a -> (a -> QuoteT m b) -> QuoteT m b $cp1Monad :: forall (m :: * -> *). Monad m => Applicative (QuoteT m) Monad, m a -> QuoteT m a (forall (m :: * -> *) a. Monad m => m a -> QuoteT m a) -> MonadTrans QuoteT forall (m :: * -> *) a. Monad m => m a -> QuoteT m a forall (t :: (* -> *) -> * -> *). (forall (m :: * -> *) a. Monad m => m a -> t m a) -> MonadTrans t lift :: m a -> QuoteT m a $clift :: forall (m :: * -> *) a. Monad m => m a -> QuoteT m a MonadTrans, (forall a. m a -> n a) -> QuoteT m b -> QuoteT n b (forall (m :: * -> *) (n :: * -> *) b. Monad m => (forall a. m a -> n a) -> QuoteT m b -> QuoteT n b) -> MFunctor QuoteT forall k (t :: (* -> *) -> k -> *). (forall (m :: * -> *) (n :: * -> *) (b :: k). Monad m => (forall a. m a -> n a) -> t m b -> t n b) -> MFunctor t forall (m :: * -> *) (n :: * -> *) b. Monad m => (forall a. m a -> n a) -> QuoteT m b -> QuoteT n b hoist :: (forall a. m a -> n a) -> QuoteT m b -> QuoteT n b $choist :: forall (m :: * -> *) (n :: * -> *) b. Monad m => (forall a. m a -> n a) -> QuoteT m b -> QuoteT n b MM.MFunctor, MonadError e, MonadReader r, Monad (QuoteT m) Monad (QuoteT m) -> (forall a. IO a -> QuoteT m a) -> MonadIO (QuoteT m) IO a -> QuoteT m a forall a. IO a -> QuoteT m a forall (m :: * -> *). Monad m -> (forall a. IO a -> m a) -> MonadIO m forall (m :: * -> *). MonadIO m => Monad (QuoteT m) forall (m :: * -> *) a. MonadIO m => IO a -> QuoteT m a liftIO :: IO a -> QuoteT m a $cliftIO :: forall (m :: * -> *) a. MonadIO m => IO a -> QuoteT m a $cp1MonadIO :: forall (m :: * -> *). MonadIO m => Monad (QuoteT m) MonadIO, MonadWriter w) -- Need to write this by hand, deriving wants to derive the one for DefState instance MonadState s m => MonadState s (QuoteT m) where get :: QuoteT m s get = m s -> QuoteT m s forall (t :: (* -> *) -> * -> *) (m :: * -> *) a. (MonadTrans t, Monad m) => m a -> t m a lift m s forall s (m :: * -> *). MonadState s m => m s get put :: s -> QuoteT m () put = m () -> QuoteT m () forall (t :: (* -> *) -> * -> *) (m :: * -> *) a. (MonadTrans t, Monad m) => m a -> t m a lift (m () -> QuoteT m ()) -> (s -> m ()) -> s -> QuoteT m () forall b c a. (b -> c) -> (a -> b) -> a -> c . s -> m () forall s (m :: * -> *). MonadState s m => s -> m () put state :: (s -> (a, s)) -> QuoteT m a state = m a -> QuoteT m a forall (t :: (* -> *) -> * -> *) (m :: * -> *) a. (MonadTrans t, Monad m) => m a -> t m a lift (m a -> QuoteT m a) -> ((s -> (a, s)) -> m a) -> (s -> (a, s)) -> QuoteT m a forall b c a. (b -> c) -> (a -> b) -> a -> c . (s -> (a, s)) -> m a forall s (m :: * -> *) a. MonadState s m => (s -> (a, s)) -> m a state -- | A monad that allows lifting of quoted expressions. class Monad m => MonadQuote m where liftQuote :: Quote a -> m a -- This means we don't have to implement it when we're writing an instance for a MonadTrans monad. We can't just -- add an instance declaration for that, because it overlaps with the base instance. default liftQuote :: (MonadQuote n, MonadTrans t, t n ~ m) => Quote a -> m a liftQuote = n a -> t n a forall (t :: (* -> *) -> * -> *) (m :: * -> *) a. (MonadTrans t, Monad m) => m a -> t m a lift (n a -> t n a) -> (Quote a -> n a) -> Quote a -> t n a forall b c a. (b -> c) -> (a -> b) -> a -> c . Quote a -> n a forall (m :: * -> *) a. MonadQuote m => Quote a -> m a liftQuote instance (Monad m) => MonadQuote (QuoteT m) where liftQuote :: Quote a -> QuoteT m a liftQuote = (forall a. Identity a -> m a) -> Quote a -> QuoteT m a forall k (t :: (* -> *) -> k -> *) (m :: * -> *) (n :: * -> *) (b :: k). (MFunctor t, Monad m) => (forall a. m a -> n a) -> t m b -> t n b MM.hoist (a -> m a forall (f :: * -> *) a. Applicative f => a -> f a pure (a -> m a) -> (Identity a -> a) -> Identity a -> m a forall b c a. (b -> c) -> (a -> b) -> a -> c . Identity a -> a forall a. Identity a -> a runIdentity) instance MonadQuote m => MonadQuote (StateT s m) instance MonadQuote m => MonadQuote (MaybeT m) instance MonadQuote m => MonadQuote (ExceptT e m) instance MonadQuote m => MonadQuote (ReaderT r m) instance MonadQuote m => MonadQuote (GenT m) instance MonadQuote m => MonadQuote (PropertyT m) -- | Run a quote from an empty identifier state. Note that the resulting term cannot necessarily -- be safely combined with other terms - that should happen inside 'QuoteT'. runQuoteT :: Monad m => QuoteT m a -> m a runQuoteT :: QuoteT m a -> m a runQuoteT QuoteT m a q = StateT FreshState m a -> FreshState -> m a forall (m :: * -> *) s a. Monad m => StateT s m a -> s -> m a evalStateT (QuoteT m a -> StateT FreshState m a forall (m :: * -> *) a. QuoteT m a -> StateT FreshState m a unQuoteT QuoteT m a q) FreshState emptyFreshState -- | A non-transformer version of 'QuoteT'. type Quote = QuoteT Identity -- | See 'runQuoteT'. runQuote :: Quote a -> a runQuote :: Quote a -> a runQuote = Identity a -> a forall a. Identity a -> a runIdentity (Identity a -> a) -> (Quote a -> Identity a) -> Quote a -> a forall b c a. (b -> c) -> (a -> b) -> a -> c . Quote a -> Identity a forall (m :: * -> *) a. Monad m => QuoteT m a -> m a runQuoteT -- | Get a fresh 'Unique'. freshUnique :: MonadQuote m => m Unique freshUnique :: m FreshState freshUnique = Quote FreshState -> m FreshState forall (m :: * -> *) a. MonadQuote m => Quote a -> m a liftQuote (Quote FreshState -> m FreshState) -> Quote FreshState -> m FreshState forall a b. (a -> b) -> a -> b $ do FreshState nextU <- StateT FreshState Identity FreshState -> Quote FreshState forall (m :: * -> *) a. StateT FreshState m a -> QuoteT m a QuoteT StateT FreshState Identity FreshState forall s (m :: * -> *). MonadState s m => m s get StateT FreshState Identity () -> QuoteT Identity () forall (m :: * -> *) a. StateT FreshState m a -> QuoteT m a QuoteT (StateT FreshState Identity () -> QuoteT Identity ()) -> StateT FreshState Identity () -> QuoteT Identity () forall a b. (a -> b) -> a -> b $ FreshState -> StateT FreshState Identity () forall s (m :: * -> *). MonadState s m => s -> m () put (FreshState -> StateT FreshState Identity ()) -> FreshState -> StateT FreshState Identity () forall a b. (a -> b) -> a -> b $ Int -> FreshState Unique (FreshState -> Int unUnique FreshState nextU Int -> Int -> Int forall a. Num a => a -> a -> a + Int 1) FreshState -> Quote FreshState forall (f :: * -> *) a. Applicative f => a -> f a pure FreshState nextU -- | Get a fresh 'Name', given the annotation and the 'Text.Text' name. freshName :: MonadQuote m => Text.Text -> m Name freshName :: Text -> m Name freshName Text str = Text -> FreshState -> Name Name Text str (FreshState -> Name) -> m FreshState -> m Name forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> m FreshState forall (m :: * -> *). MonadQuote m => m FreshState freshUnique -- | Make a copy of the given 'Name' that is distinct from the old one. freshenName :: MonadQuote m => Name -> m Name freshenName :: Name -> m Name freshenName (Name Text str FreshState _) = Text -> FreshState -> Name Name Text str (FreshState -> Name) -> m FreshState -> m Name forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> m FreshState forall (m :: * -> *). MonadQuote m => m FreshState freshUnique -- | Get a fresh 'TyName', given the annotation and the 'Text.Text' name. freshTyName :: MonadQuote m => Text.Text -> m TyName freshTyName :: Text -> m TyName freshTyName = (Name -> TyName) -> m Name -> m TyName forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b fmap Name -> TyName TyName (m Name -> m TyName) -> (Text -> m Name) -> Text -> m TyName forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> Text -> m Name forall (m :: * -> *). MonadQuote m => Text -> m Name freshName -- | Make a copy of the given 'TyName' that is distinct from the old one. freshenTyName :: MonadQuote m => TyName -> m TyName freshenTyName :: TyName -> m TyName freshenTyName (TyName Name name) = Name -> TyName TyName (Name -> TyName) -> m Name -> m TyName forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b <$> Name -> m Name forall (m :: * -> *). MonadQuote m => Name -> m Name freshenName Name name -- | Mark a all 'Unique's less than the given 'Unique' as used, so they will not be generated in future. markNonFreshBelow :: MonadQuote m => Unique -> m () markNonFreshBelow :: FreshState -> m () markNonFreshBelow = QuoteT Identity () -> m () forall (m :: * -> *) a. MonadQuote m => Quote a -> m a liftQuote (QuoteT Identity () -> m ()) -> (FreshState -> QuoteT Identity ()) -> FreshState -> m () forall b c a. (b -> c) -> (a -> b) -> a -> c . StateT FreshState Identity () -> QuoteT Identity () forall (m :: * -> *) a. StateT FreshState m a -> QuoteT m a QuoteT (StateT FreshState Identity () -> QuoteT Identity ()) -> (FreshState -> StateT FreshState Identity ()) -> FreshState -> QuoteT Identity () forall b c a. (b -> c) -> (a -> b) -> a -> c . (FreshState -> FreshState) -> StateT FreshState Identity () forall s (m :: * -> *). MonadState s m => (s -> s) -> m () modify ((FreshState -> FreshState) -> StateT FreshState Identity ()) -> (FreshState -> FreshState -> FreshState) -> FreshState -> StateT FreshState Identity () forall b c a. (b -> c) -> (a -> b) -> a -> c . FreshState -> FreshState -> FreshState forall a. Ord a => a -> a -> a max -- | Mark a given 'Unique' (and implicitly all 'Unique's less than it) as used, so they will not be generated in future. markNonFresh :: MonadQuote m => Unique -> m () markNonFresh :: FreshState -> m () markNonFresh = FreshState -> m () forall (m :: * -> *). MonadQuote m => FreshState -> m () markNonFreshBelow (FreshState -> m ()) -> (FreshState -> FreshState) -> FreshState -> m () forall b c a. (b -> c) -> (a -> b) -> a -> c . FreshState -> FreshState forall a. Enum a => a -> a succ -- | Mark the maximal 'Unique' from a set of 'Unique's (and implicitly all 'Unique's less than it) -- as used, so they will not be generated in future. markNonFreshMax :: MonadQuote m => Set Unique -> m () markNonFreshMax :: Set FreshState -> m () markNonFreshMax = FreshState -> m () forall (m :: * -> *). MonadQuote m => FreshState -> m () markNonFresh (FreshState -> m ()) -> (Set FreshState -> FreshState) -> Set FreshState -> m () forall b c a. (b -> c) -> (a -> b) -> a -> c . FreshState -> Maybe FreshState -> FreshState forall a. a -> Maybe a -> a fromMaybe (Int -> FreshState Unique Int 0) (Maybe FreshState -> FreshState) -> (Set FreshState -> Maybe FreshState) -> Set FreshState -> FreshState forall b c a. (b -> c) -> (a -> b) -> a -> c . Set FreshState -> Maybe FreshState forall a. Set a -> Maybe a Set.lookupMax