module Michelson.Untyped.Entrypoints
( EpName (..)
, pattern DefEpName
, isDefEpName
, epNameFromParamAnn
, epNameToParamAnn
, epNameFromRefAnn
, epNameFromSelfAnn
, epNameToRefAnn
, EpNameFromRefAnnError (..)
, buildEpName
, unsafeBuildEpName
, mkEntrypointsMap
) where
import Data.Aeson.TH (deriveJSON)
import qualified Data.Map as Map
import Fmt (Buildable(..), pretty, (+|), (|+))
import Test.QuickCheck (Arbitrary(..), suchThatMap)
import Michelson.Untyped.Annotation
import Michelson.Untyped.Type
import Util.Aeson
import Util.CLI
newtype EpName = EpNameUnsafe { EpName -> Text
unEpName :: Text }
deriving stock (Int -> EpName -> ShowS
[EpName] -> ShowS
EpName -> String
(Int -> EpName -> ShowS)
-> (EpName -> String) -> ([EpName] -> ShowS) -> Show EpName
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [EpName] -> ShowS
$cshowList :: [EpName] -> ShowS
show :: EpName -> String
$cshow :: EpName -> String
showsPrec :: Int -> EpName -> ShowS
$cshowsPrec :: Int -> EpName -> ShowS
Show, EpName -> EpName -> Bool
(EpName -> EpName -> Bool)
-> (EpName -> EpName -> Bool) -> Eq EpName
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: EpName -> EpName -> Bool
$c/= :: EpName -> EpName -> Bool
== :: EpName -> EpName -> Bool
$c== :: EpName -> EpName -> Bool
Eq, Eq EpName
Eq EpName =>
(EpName -> EpName -> Ordering)
-> (EpName -> EpName -> Bool)
-> (EpName -> EpName -> Bool)
-> (EpName -> EpName -> Bool)
-> (EpName -> EpName -> Bool)
-> (EpName -> EpName -> EpName)
-> (EpName -> EpName -> EpName)
-> Ord EpName
EpName -> EpName -> Bool
EpName -> EpName -> Ordering
EpName -> EpName -> EpName
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: EpName -> EpName -> EpName
$cmin :: EpName -> EpName -> EpName
max :: EpName -> EpName -> EpName
$cmax :: EpName -> EpName -> EpName
>= :: EpName -> EpName -> Bool
$c>= :: EpName -> EpName -> Bool
> :: EpName -> EpName -> Bool
$c> :: EpName -> EpName -> Bool
<= :: EpName -> EpName -> Bool
$c<= :: EpName -> EpName -> Bool
< :: EpName -> EpName -> Bool
$c< :: EpName -> EpName -> Bool
compare :: EpName -> EpName -> Ordering
$ccompare :: EpName -> EpName -> Ordering
$cp1Ord :: Eq EpName
Ord, (forall x. EpName -> Rep EpName x)
-> (forall x. Rep EpName x -> EpName) -> Generic EpName
forall x. Rep EpName x -> EpName
forall x. EpName -> Rep EpName x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep EpName x -> EpName
$cfrom :: forall x. EpName -> Rep EpName x
Generic)
instance NFData EpName
deriveJSON morleyAesonOptions ''EpName
pattern DefEpName :: EpName
pattern $bDefEpName :: EpName
$mDefEpName :: forall r. EpName -> (Void# -> r) -> (Void# -> r) -> r
DefEpName = EpNameUnsafe ""
isDefEpName :: EpName -> Bool
isDefEpName :: EpName -> Bool
isDefEpName epName :: EpName
epName = EpName
epName EpName -> EpName -> Bool
forall a. Eq a => a -> a -> Bool
== EpName
DefEpName Bool -> Bool -> Bool
|| EpName
epName EpName -> EpName -> Bool
forall a. Eq a => a -> a -> Bool
== Text -> EpName
EpNameUnsafe "default"
instance Buildable EpName where
build :: EpName -> Builder
build = \case
DefEpName -> "<default>"
EpNameUnsafe name :: Text
name -> Text -> Builder
forall p. Buildable p => p -> Builder
build Text
name
epNameFromParamAnn :: FieldAnn -> Maybe EpName
epNameFromParamAnn :: FieldAnn -> Maybe EpName
epNameFromParamAnn an :: FieldAnn
an@(Annotation a :: Text
a)
| FieldAnn
an FieldAnn -> FieldAnn -> Bool
forall a. Eq a => a -> a -> Bool
== FieldAnn
forall k (a :: k). Annotation a
noAnn = Maybe EpName
forall a. Maybe a
Nothing
| Text
a Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== "default" = EpName -> Maybe EpName
forall a. a -> Maybe a
Just (Text -> EpName
EpNameUnsafe "")
| Bool
otherwise = EpName -> Maybe EpName
forall a. a -> Maybe a
Just (EpName -> Maybe EpName) -> EpName -> Maybe EpName
forall a b. (a -> b) -> a -> b
$ Text -> EpName
EpNameUnsafe Text
a
epNameToParamAnn :: EpName -> FieldAnn
epNameToParamAnn :: EpName -> FieldAnn
epNameToParamAnn (EpNameUnsafe name :: Text
name)
| Text
name Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== "" = Text -> FieldAnn
forall k (a :: k). HasCallStack => Text -> Annotation a
ann "default"
| Bool
otherwise = Text -> FieldAnn
forall k (a :: k). HasCallStack => Text -> Annotation a
ann Text
name
data EpNameFromRefAnnError
= InEpNameBadAnnotation FieldAnn
deriving stock (Int -> EpNameFromRefAnnError -> ShowS
[EpNameFromRefAnnError] -> ShowS
EpNameFromRefAnnError -> String
(Int -> EpNameFromRefAnnError -> ShowS)
-> (EpNameFromRefAnnError -> String)
-> ([EpNameFromRefAnnError] -> ShowS)
-> Show EpNameFromRefAnnError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [EpNameFromRefAnnError] -> ShowS
$cshowList :: [EpNameFromRefAnnError] -> ShowS
show :: EpNameFromRefAnnError -> String
$cshow :: EpNameFromRefAnnError -> String
showsPrec :: Int -> EpNameFromRefAnnError -> ShowS
$cshowsPrec :: Int -> EpNameFromRefAnnError -> ShowS
Show, EpNameFromRefAnnError -> EpNameFromRefAnnError -> Bool
(EpNameFromRefAnnError -> EpNameFromRefAnnError -> Bool)
-> (EpNameFromRefAnnError -> EpNameFromRefAnnError -> Bool)
-> Eq EpNameFromRefAnnError
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: EpNameFromRefAnnError -> EpNameFromRefAnnError -> Bool
$c/= :: EpNameFromRefAnnError -> EpNameFromRefAnnError -> Bool
== :: EpNameFromRefAnnError -> EpNameFromRefAnnError -> Bool
$c== :: EpNameFromRefAnnError -> EpNameFromRefAnnError -> Bool
Eq, (forall x. EpNameFromRefAnnError -> Rep EpNameFromRefAnnError x)
-> (forall x. Rep EpNameFromRefAnnError x -> EpNameFromRefAnnError)
-> Generic EpNameFromRefAnnError
forall x. Rep EpNameFromRefAnnError x -> EpNameFromRefAnnError
forall x. EpNameFromRefAnnError -> Rep EpNameFromRefAnnError x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep EpNameFromRefAnnError x -> EpNameFromRefAnnError
$cfrom :: forall x. EpNameFromRefAnnError -> Rep EpNameFromRefAnnError x
Generic)
instance NFData EpNameFromRefAnnError
instance Buildable EpNameFromRefAnnError where
build :: EpNameFromRefAnnError -> Builder
build = \case
InEpNameBadAnnotation (Annotation an :: Text
an) ->
"Invalid entrypoint reference `" Builder -> Builder -> Builder
forall b. FromBuilder b => Builder -> Builder -> b
+| Text
an Text -> Builder -> Builder
forall a b. (Buildable a, FromBuilder b) => a -> Builder -> b
|+ "`"
epNameFromRefAnn :: FieldAnn -> Either EpNameFromRefAnnError EpName
epNameFromRefAnn :: FieldAnn -> Either EpNameFromRefAnnError EpName
epNameFromRefAnn an :: FieldAnn
an@(Annotation a :: Text
a)
| Text
a Text -> Text -> Bool
forall a. Eq a => a -> a -> Bool
== "default" = EpNameFromRefAnnError -> Either EpNameFromRefAnnError EpName
forall a b. a -> Either a b
Left (EpNameFromRefAnnError -> Either EpNameFromRefAnnError EpName)
-> EpNameFromRefAnnError -> Either EpNameFromRefAnnError EpName
forall a b. (a -> b) -> a -> b
$ FieldAnn -> EpNameFromRefAnnError
InEpNameBadAnnotation FieldAnn
an
| Bool
otherwise = EpName -> Either EpNameFromRefAnnError EpName
forall a b. b -> Either a b
Right (EpName -> Either EpNameFromRefAnnError EpName)
-> EpName -> Either EpNameFromRefAnnError EpName
forall a b. (a -> b) -> a -> b
$ Text -> EpName
EpNameUnsafe Text
a
epNameFromSelfAnn :: FieldAnn -> EpName
epNameFromSelfAnn :: FieldAnn -> EpName
epNameFromSelfAnn (Annotation a :: Text
a) = Text -> EpName
EpNameUnsafe Text
a
epNameToRefAnn :: EpName -> FieldAnn
epNameToRefAnn :: EpName -> FieldAnn
epNameToRefAnn (EpNameUnsafe name :: Text
name) = Text -> FieldAnn
forall k (a :: k). HasCallStack => Text -> Annotation a
ann Text
name
buildEpName :: Text -> Either String EpName
buildEpName :: Text -> Either String EpName
buildEpName txt :: Text
txt = do
FieldAnn
annotation <-
Text -> Either Text FieldAnn
forall k (a :: k). Text -> Either Text (Annotation a)
mkAnnotation Text
txt
Either Text FieldAnn
-> (Either Text FieldAnn -> Either String FieldAnn)
-> Either String FieldAnn
forall a b. a -> (a -> b) -> b
& (Text -> String) -> Either Text FieldAnn -> Either String FieldAnn
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (String -> ShowS
forall a. Monoid a => a -> a -> a
mappend "Failed to parse entrypoint: " ShowS -> (Text -> String) -> Text -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
forall a b. (Buildable a, FromBuilder b) => a -> b
pretty)
FieldAnn -> Either EpNameFromRefAnnError EpName
epNameFromRefAnn FieldAnn
annotation
Either EpNameFromRefAnnError EpName
-> (Either EpNameFromRefAnnError EpName -> Either String EpName)
-> Either String EpName
forall a b. a -> (a -> b) -> b
& (EpNameFromRefAnnError -> String)
-> Either EpNameFromRefAnnError EpName -> Either String EpName
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first EpNameFromRefAnnError -> String
forall a b. (Buildable a, FromBuilder b) => a -> b
pretty
unsafeBuildEpName :: HasCallStack => Text -> EpName
unsafeBuildEpName :: Text -> EpName
unsafeBuildEpName = (String -> EpName)
-> (EpName -> EpName) -> Either String EpName -> EpName
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Text -> EpName
forall a. HasCallStack => Text -> a
error (Text -> EpName) -> (String -> Text) -> String -> EpName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
forall a b. (Buildable a, FromBuilder b) => a -> b
pretty) EpName -> EpName
forall a. a -> a
id (Either String EpName -> EpName)
-> (Text -> Either String EpName) -> Text -> EpName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Either String EpName
buildEpName
instance Arbitrary FieldAnn => Arbitrary EpName where
arbitrary :: Gen EpName
arbitrary = Gen FieldAnn
forall a. Arbitrary a => Gen a
arbitrary Gen FieldAnn -> (FieldAnn -> Maybe EpName) -> Gen EpName
forall a b. Gen a -> (a -> Maybe b) -> Gen b
`suchThatMap` (Either EpNameFromRefAnnError EpName -> Maybe EpName
forall l r. Either l r -> Maybe r
rightToMaybe (Either EpNameFromRefAnnError EpName -> Maybe EpName)
-> (FieldAnn -> Either EpNameFromRefAnnError EpName)
-> FieldAnn
-> Maybe EpName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FieldAnn -> Either EpNameFromRefAnnError EpName
epNameFromRefAnn)
instance HasCLReader EpName where
getReader :: ReadM EpName
getReader = (String -> Either String EpName) -> ReadM EpName
forall a. (String -> Either String a) -> ReadM a
eitherReader (Text -> Either String EpName
buildEpName (Text -> Either String EpName)
-> (String -> Text) -> String -> Either String EpName
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
forall a. ToText a => a -> Text
toText)
getMetavar :: String
getMetavar = "ENTRYPOINT"
mkEntrypointsMap :: Type -> Map EpName Type
mkEntrypointsMap :: Type -> Map EpName Type
mkEntrypointsMap (Type t :: T
t _) = case T
t of
TOr f1 :: FieldAnn
f1 f2 :: FieldAnn
f2 t1 :: Type
t1 t2 :: Type
t2 -> FieldAnn -> Type -> Map EpName Type
extractSubmap FieldAnn
f1 Type
t1 Map EpName Type -> Map EpName Type -> Map EpName Type
forall a. Semigroup a => a -> a -> a
<> FieldAnn -> Type -> Map EpName Type
extractSubmap FieldAnn
f2 Type
t2
_ -> Map EpName Type
forall a. Monoid a => a
mempty
where
extractSubmap :: FieldAnn -> Type -> Map EpName Type
extractSubmap :: FieldAnn -> Type -> Map EpName Type
extractSubmap f1 :: FieldAnn
f1 t1 :: Type
t1 = let
innerMap :: Map EpName Type
innerMap = Type -> Map EpName Type
mkEntrypointsMap Type
t1
in case FieldAnn -> Maybe EpName
epNameFromParamAnn FieldAnn
f1 of
Just epName :: EpName
epName -> EpName -> Type -> Map EpName Type
forall k a. k -> a -> Map k a
Map.singleton EpName
epName Type
t1 Map EpName Type -> Map EpName Type -> Map EpName Type
forall a. Semigroup a => a -> a -> a
<> Map EpName Type
innerMap
Nothing -> Map EpName Type
innerMap