1- {-# LANGUAGE TemplateHaskellQuotes #-}
21{-# LANGUAGE DerivingStrategies #-}
3- module PlutusTx.Enum.TH ( Enum ( .. ), deriveEnum ) where
2+ {-# LANGUAGE TemplateHaskellQuotes #-}
43
5- import PlutusTx.Enum.Class
6- import PlutusTx.Trace
7- import Prelude hiding (Eq , (==) , (&&) , Bool (True ), Enum (.. ))
4+ module PlutusTx.Enum.TH (Enum (.. ), deriveEnum ) where
5+
6+ import Control.Monad
7+ import Data.Deriving.Internal (varTToName )
88import Data.Foldable
9+ import Data.Tuple
910import Language.Haskell.TH as TH
1011import Language.Haskell.TH.Datatype as TH
11- import Data.Deriving.Internal (varTToName )
12- import Control.Monad
13- import Data.Tuple
12+ import PlutusTx.Enum.Class
13+ import PlutusTx.ErrorCodes
14+ import PlutusTx.Trace
15+ import Prelude hiding (Bool (True ), Enum (.. ), Eq , (&&) , (==) )
1416
1517data SuccPred = Succ | Pred
16- deriving stock Show
18+ deriving stock ( Show )
1719
1820{-| Derive PlutusTx.Enum typeclass for datatypes, much like `deriving stock Enum` does for Haskell
1921
20- Note: requires enabling OverloadedStrings language extension
21- -}
22+ Note: requires enabling OverloadedStrings language extension -}
2223deriveEnum :: TH. Name -> TH. Q [TH. Dec ]
2324deriveEnum name = do
2425 TH. DatatypeInfo
@@ -35,60 +36,73 @@ deriveEnum name = do
3536 instanceType :: TH. Type
3637 instanceType = TH. AppT (TH. ConT ''Enum) $ foldl' TH. AppT (TH. ConT tyConName) tyVars
3738
38- table = zip (fmap IntegerL [0 .. ]) (fmap constructorName cons)
39+ table = zip (fmap IntegerL [0 .. ]) (fmap constructorName cons)
3940
4041 when (null cons) $
41- fail $ " Can't make a derived instance of `Enum "
42- ++ show tyConName
43- ++ " `: "
44- ++ show tyConName
45- ++ " must must be an enumeration type (an enumeration consists of one or more nullary, non-GADT constructors)"
46-
47- pure <$> instanceD (pure [] ) (pure instanceType)
48- [
49- funD 'succ (fmap (deriveSuccPred Succ ) (zip cons (tail (Just <$> cons) ++ [Nothing ])))
50- , TH. pragInlD 'succ TH. Inlinable TH. FunLike TH. AllPhases
51-
52- , funD 'pred (fmap (deriveSuccPred Pred ) (zip cons (Nothing : init (Just <$> cons))))
53- , TH. pragInlD 'pred TH. Inlinable TH. FunLike TH. AllPhases
54-
55- , funD 'toEnum $ fmap deriveToEnum table <> [pure toEnumDefaultClause]
56- , TH. pragInlD 'toEnum TH. Inlinable TH. FunLike TH. AllPhases
57-
58- , funD 'fromEnum $ fmap (deriveFromEnum . swap) table
59- , TH. pragInlD 'fromEnum TH. Inlinable TH. FunLike TH. AllPhases
60-
61- ]
42+ fail $
43+ " Can't make a derived instance of `Enum "
44+ ++ show tyConName
45+ ++ " `: "
46+ ++ show tyConName
47+ ++ " must must be an enumeration type (an enumeration consists of one or more nullary, non-GADT constructors)"
48+
49+ pure
50+ <$> instanceD
51+ (pure [] )
52+ (pure instanceType)
53+ [ funD 'succ (fmap (deriveSuccPred Succ ) (zip cons (tail (Just <$> cons) ++ [Nothing ])))
54+ , TH. pragInlD 'succ TH. Inlinable TH. FunLike TH. AllPhases
55+ , funD 'pred (fmap (deriveSuccPred Pred ) (zip cons (Nothing : init (Just <$> cons))))
56+ , TH. pragInlD 'pred TH. Inlinable TH. FunLike TH. AllPhases
57+ , funD 'toEnum $ fmap deriveToEnum table <> [pure toEnumDefaultClause]
58+ , TH. pragInlD 'toEnum TH. Inlinable TH. FunLike TH. AllPhases
59+ , funD 'fromEnum $ fmap (deriveFromEnum . swap) table
60+ , TH. pragInlD 'fromEnum TH. Inlinable TH. FunLike TH. AllPhases
61+ ]
6262
6363toEnumDefaultClause :: Clause
64- toEnumDefaultClause = TH. Clause [WildP ] (TH. NormalB $
65- AppE (VarE 'traceError) (LitE $ StringL " tag is outside of enumeration's range" )
66- ) []
64+ toEnumDefaultClause =
65+ TH. Clause
66+ [WildP ]
67+ ( TH. NormalB $
68+ AppE (VarE 'traceError) (VarE 'toEnumBadArgumentError)
69+ )
70+ []
6771
6872deriveToEnum :: (Lit , Name ) -> Q Clause
69- deriveToEnum (l,n) = pure (TH. Clause [LitP l] (NormalB $ ConE n) [] )
73+ deriveToEnum (l, n) = pure (TH. Clause [LitP l] (NormalB $ ConE n) [] )
7074
7175deriveFromEnum :: (Name , Lit ) -> Q Clause
72- deriveFromEnum (n,l) = pure (TH. Clause [ConP n [] [] ] (NormalB $ LitE l) [] )
76+ deriveFromEnum (n, l) = pure (TH. Clause [ConP n [] [] ] (NormalB $ LitE l) [] )
7377
7478deriveSuccPred :: SuccPred -> (ConstructorInfo , Maybe ConstructorInfo ) -> Q Clause
75- deriveSuccPred succPred ( ConstructorInfo {constructorName = nameL, constructorFields = [] }
76- , Nothing )
77- = pure (TH. Clause [ConP nameL [] [] ]
78- (NormalB $ AppE (VarE 'traceError) (LitE $ StringL $ show succPred
79- ++ " {" ++ show nameL ++ " }: tried to take "
80- ++ show succPred
81- ++ " of "
82- ++ case succPred of { Succ -> " last" ; Pred -> " first" }
83- ++ " tag in enumeration" ))
84- [] )
85-
86- deriveSuccPred _ ( ConstructorInfo {constructorName = nameL, constructorFields = [] }
87- , Just ConstructorInfo {constructorName = nameR, constructorFields = [] }
88- )
89- = pure (TH. Clause [ConP nameL [] [] ]
79+ deriveSuccPred
80+ succPred
81+ ( ConstructorInfo {constructorName = nameL, constructorFields = [] }
82+ , Nothing
83+ ) =
84+ pure
85+ ( TH. Clause
86+ [ConP nameL [] [] ]
87+ ( NormalB $
88+ AppE
89+ (VarE 'traceError)
90+ ( VarE $ case succPred of
91+ Succ -> 'succBadArgumentError
92+ Pred -> 'predBadArgumentError
93+ )
94+ )
95+ []
96+ )
97+ deriveSuccPred
98+ _
99+ ( ConstructorInfo {constructorName = nameL, constructorFields = [] }
100+ , Just ConstructorInfo {constructorName = nameR, constructorFields = [] }
101+ ) =
102+ pure
103+ ( TH. Clause
104+ [ConP nameL [] [] ]
90105 (NormalB $ ConE nameR)
91106 []
92- )
93-
107+ )
94108deriveSuccPred _ _ = fail " Can't make a derived instance of Enum when constructor has fields"
0 commit comments