indigo-0.3.0: src/Indigo/Frontend/Language.hs
-- SPDX-FileCopyrightText: 2020 Tocqueville Group
--
-- SPDX-License-Identifier: LicenseRef-MIT-TQ
-- | Frontend statements's functions of the Indigo Language.
module Indigo.Frontend.Language
( -- * Assignment and modifications
new
, setVar
, setField
, (+=)
, (-=)
, (*=)
, (<<<=)
, (>>>=)
, (&&=)
, (||=)
, (^=)
, (=:)
-- * Storage Fields
, getStorageField
, setStorageField
, updateStorageField
-- * Conditional
, if_
, when
, unless
, ifSome
, ifNone
, whenSome
, whenNone
, ifRight
, ifLeft
, whenRight
, whenLeft
, ifCons
-- * Case
, case_
, caseRec
, entryCase
, entryCaseRec
, entryCaseSimple
, (//->)
, (#=)
-- * Scope
, scope
, defFunction
, defContract
, defNamedPureLambda1
, defNamedLambda1
, defNamedLambda0
, defNamedEffLambda1
-- * Loop
, while
, whileLeft
, forEach
-- * Contract call
, selfCalling
, contractCalling
-- * Documentation
, doc
, docGroup
, docStorage
, contractName
, contractGeneral
, contractGeneralDefault
, finalizeParamCallingDoc
-- * Short-handed doc item
, anchor
, description
, example
-- * Side-effects operations
, transferTokens
, setDelegate
, createContract
, createLorentzContract
-- * Failures
, failWith
, assert
, failCustom
, failCustom_
, failUnexpected_
, assertCustom
, assertCustom_
, assertSome
, assertNone
, assertRight
, assertLeft
-- * Re-exports
, ReturnableValue
, RetVars
-- * Comments
, comment
, justComment
, commentAroundFun
, commentAroundStmt
-- * Blocks
, IndigoFunction
, IndigoProcedure
, IndigoEntrypoint
-- * Helpers
, liftIndigoState
) where
import qualified Indigo.Backend as B
import Indigo.Backend.Case hiding (caseRec, entryCaseRec)
import Indigo.Backend.Lambda
import Indigo.Backend.Scope
import Indigo.Compilation (compileIndigoContract)
import Indigo.Frontend.Program
import Indigo.Frontend.Statement
import Indigo.Internal hiding (SetField, (>>))
import Indigo.Lorentz
import Indigo.Prelude
import Lorentz.Entrypoints.Helpers (RequireSumType)
import qualified Lorentz.Instr as L
import qualified Lorentz.Run as L
import qualified Michelson.Typed as MT
import qualified Michelson.Typed.Arith as M
import Michelson.Typed.Haskell.Instr.Sum (CaseClauseParam(..), CtorField(..))
import Util.Markdown (toAnchor)
import Util.TypeLits (AppendSymbol)
import Util.TypeTuple.Class
oneIndigoM :: StatementF IndigoM a -> IndigoM a
oneIndigoM st = IndigoM (Instr st)
liftIndigoState :: (forall inp. SomeIndigoState inp) -> IndigoM ()
liftIndigoState code = IndigoM (Instr $ LiftIndigoState code)
varModification
:: (IsExpr ey y, IsObject x)
=> ([y, x] :-> '[x]) -> Var x -> ey -> IndigoM ()
varModification act v = oneIndigoM . VarModification act v . toExpr
----------------------------------------------------------------------------
-- Var creation and assignment
----------------------------------------------------------------------------
-- | Create a new variable with the result of the given expression as its initial value.
new :: IsExpr ex x => ex -> IndigoM (Var x)
new = oneIndigoM . NewVar . toExpr
-- | Set the given variable to the result of the given expression.
setVar :: IsExpr ex x => Var x -> ex -> IndigoM ()
setVar v = oneIndigoM . SetVar v . toExpr
infixr 0 =:
(=:) :: IsExpr ex x => Var x -> ex -> IndigoM ()
v =: e = setVar v e
setField
:: ( ex :~> ftype
, IsObject dt
, IsObject ftype
, HasField dt fname ftype
)
=> Var dt -> Label fname -> ex -> IndigoM ()
setField v fName = oneIndigoM . SetField v fName . toExpr
(+=)
:: ( IsExpr ex1 n, IsObject m
, ArithOpHs M.Add n m, ArithResHs M.Add n m ~ m
) => Var m -> ex1 -> IndigoM ()
(+=) = varModification L.add
(-=)
:: ( IsExpr ex1 n, IsObject m
, ArithOpHs M.Sub n m, ArithResHs M.Sub n m ~ m
) => Var m -> ex1 -> IndigoM ()
(-=) = varModification L.sub
(*=)
:: ( IsExpr ex1 n, IsObject m
, ArithOpHs M.Mul n m, ArithResHs M.Mul n m ~ m
) => Var m -> ex1 -> IndigoM ()
(*=) = varModification L.mul
(||=)
:: ( IsExpr ex1 n, IsObject m
, ArithOpHs M.Or n m, ArithResHs M.Or n m ~ m
) => Var m -> ex1 -> IndigoM ()
(||=) = varModification L.or
(&&=)
:: ( IsExpr ex1 n, IsObject m
, ArithOpHs M.And n m, ArithResHs M.And n m ~ m
) => Var m -> ex1 -> IndigoM ()
(&&=) = varModification L.and
(^=)
:: ( IsExpr ex1 n, IsObject m
, ArithOpHs M.Xor n m, ArithResHs M.Xor n m ~ m
) => Var m -> ex1 -> IndigoM ()
(^=) = varModification L.xor
(<<<=)
:: ( IsExpr ex1 n, IsObject m
, ArithOpHs M.Lsl n m, ArithResHs M.Lsl n m ~ m
) => Var m -> ex1 -> IndigoM ()
(<<<=) = varModification L.lsl
(>>>=)
:: ( IsExpr ex1 n, IsObject m
, ArithOpHs M.Lsr n m, ArithResHs M.Lsr n m ~ m
) => Var m -> ex1 -> IndigoM ()
(>>>=) = varModification L.lsr
----------------------------------------------------------------------------
-- Storage Fields
----------------------------------------------------------------------------
-- | Sets a storage field to a new value.
setStorageField
:: forall store name ftype ex.
( HasStorage store
, ex :~> ftype
, IsObject store
, IsObject ftype
, HasField store name ftype
)
=> Label name -> ex -> IndigoM ()
setStorageField field expr = setField (storageVar @store) field expr
-- | Updates a storage field by using an updating 'IndigoM'.
updateStorageField
:: forall store ftype fname fex.
( HasStorage store
, fex :~> ftype
, HasField store fname ftype
, IsObject store
, IsObject ftype
)
=> Label fname
-> (Var ftype -> IndigoM fex)
-> IndigoM ()
updateStorageField field upd = scope $ do
let storage = storageVar @store
fieldVar <- new$ storage #! field
expr <- upd fieldVar
setField storage field expr
-- | Get a field from the storage, returns a variable.
--
-- Note that the storage type almost always needs to be specified.
getStorageField
:: forall store ftype fname .
( HasStorage store
, HasField store fname ftype
)
=> Label fname -> IndigoM (Var ftype)
getStorageField field = new$ storageVar @store #! field
----------------------------------------------------------------------------
-- Conditional
----------------------------------------------------------------------------
if_
:: forall a b ex . (IfConstraint a b, ex :~> Bool)
=> ex
-> IndigoM a
-> IndigoM b
-> IndigoM (RetVars a)
if_ ex tb fb = oneIndigoM $ If (toExpr ex) tb fb
-- | Run the instruction when the condition is met, do nothing otherwise.
when :: (exc :~> Bool) => exc -> IndigoM () -> IndigoM ()
when cond expr = if_ cond expr (return ())
-- | Reverse of 'when'.
unless :: (exc :~> Bool) => exc -> IndigoM () -> IndigoM ()
unless cond expr = if_ cond (return ()) expr
ifSome
:: forall x a b ex . (KnownValue x, ex :~> Maybe x, IfConstraint a b)
=> ex
-> (Var x -> IndigoM a)
-> IndigoM b
-> IndigoM (RetVars a)
ifSome ex tb fb = oneIndigoM $ IfSome (toExpr ex) tb fb
ifNone
:: forall x a b ex . (KnownValue x, ex :~> Maybe x, IfConstraint a b)
=> ex
-> IndigoM b
-> (Var x -> IndigoM a)
-> IndigoM (RetVars a)
ifNone ex fb tb = ifSome (toExpr ex) tb fb
-- | Run the instruction when the given expression returns 'Just' a value,
-- do nothing otherwise.
whenSome
:: forall x exa .
( KnownValue x
, exa :~> Maybe x
)
=> exa
-> (Var x -> IndigoM ())
-> IndigoM ()
whenSome c f = ifSome c f (return ())
-- | Run the instruction when the given expression returns 'Nothing',
-- do nothing otherwise.
whenNone
:: forall x exa .
( KnownValue x
, exa :~> Maybe x
)
=> exa
-> IndigoM ()
-> IndigoM ()
whenNone c f = ifSome c (\_ -> return ()) f
ifRight
:: forall x y a b ex .
( KnownValue x
, KnownValue y
, ex :~> Either y x
, IfConstraint a b
)
=> ex
-> (Var x -> IndigoM a)
-> (Var y -> IndigoM b)
-> IndigoM (RetVars a)
ifRight ex rb lb = oneIndigoM $ IfRight (toExpr ex) rb lb
ifLeft
:: forall x y a b ex .
( KnownValue x
, KnownValue y
, ex :~> Either y x
, IfConstraint a b
)
=> ex
-> (Var y -> IndigoM b)
-> (Var x -> IndigoM a)
-> IndigoM (RetVars a)
ifLeft ex lb rb = ifRight ex rb lb
whenRight
:: forall x y ex .
( KnownValue x
, KnownValue y
, ex :~> Either y x
)
=> ex
-> (Var x -> IndigoM ())
-> IndigoM ()
whenRight c f = ifRight c f (\_ -> return ())
whenLeft
:: forall x y ex .
( KnownValue x
, KnownValue y
, ex :~> Either y x
)
=> ex
-> (Var y -> IndigoM ())
-> IndigoM ()
whenLeft c f = ifRight c (\_ -> return ()) f
ifCons
:: forall x a b ex . (KnownValue x, ex :~> List x, IfConstraint a b)
=> ex
-> (Var x -> Var (List x) -> IndigoM a)
-> IndigoM b
-> IndigoM (RetVars a)
ifCons ex tb fb = oneIndigoM $ IfCons (toExpr ex) tb fb
----------------------------------------------------------------------------
-- Case
----------------------------------------------------------------------------
-- | A case statement for indigo. See examples for a sample usage.
caseRec
:: forall dt guard ret clauses .
( CaseCommonF (IndigoMCaseClauseL IndigoM) dt ret clauses
, guard :~> dt
)
=> guard
-> clauses
-> IndigoM (RetVars ret)
caseRec g = oneIndigoM . Case (toExpr g)
-- | 'caseRec' for tuples.
case_
:: forall dt guard ret clauses.
( CaseCommonF (IndigoMCaseClauseL IndigoM) dt ret clauses
, RecFromTuple clauses
, guard :~> dt
)
=> guard
-> IsoRecTuple clauses
-> IndigoM (RetVars ret)
case_ g = caseRec (toExpr g) . recFromTuple @clauses
-- | 'caseRec' for pattern-matching on parameter.
entryCaseRec
:: forall dt entrypointKind guard ret clauses .
( CaseCommonF (IndigoMCaseClauseL IndigoM) dt ret clauses
, DocumentEntrypoints entrypointKind dt
, guard :~> dt
)
=> Proxy entrypointKind
-> guard
-> clauses
-> IndigoM (RetVars ret)
entryCaseRec proxy g cls = oneIndigoM $ EntryCase proxy (toExpr g) cls
-- | 'entryCaseRec' for tuples.
entryCase
:: forall dt entrypointKind guard ret clauses .
( CaseCommonF (IndigoMCaseClauseL IndigoM) dt ret clauses
, RecFromTuple clauses
, DocumentEntrypoints entrypointKind dt
, guard :~> dt
)
=> Proxy entrypointKind
-> guard
-> IsoRecTuple clauses
-> IndigoM (RetVars ret)
entryCase proxy g = entryCaseRec proxy g . recFromTuple @clauses
entryCaseSimple
:: forall cp guard ret clauses .
( CaseCommonF (IndigoMCaseClauseL IndigoM) cp ret clauses
, RecFromTuple clauses
, DocumentEntrypoints PlainEntrypointsKind cp
, NiceParameterFull cp
, RequireFlatParamEps cp
, guard :~> cp
)
=> guard
-> IsoRecTuple clauses
-> IndigoM (RetVars ret)
entryCaseSimple g = oneIndigoM . EntryCaseSimple (toExpr g) . recFromTuple @clauses
{-# DEPRECATED (//->) "use '#=' instead" #-}
-- | An alias for '#=' kept only for backward compatibility.
(//->)
:: ( name ~ (AppendSymbol "c" ctor)
, KnownValue x
, ScopeCodeGen retBr
, ret ~ RetExprs retBr
, RetOutStack ret ~ RetOutStack retBr
)
=> Label name
-> (Var x -> IndigoM retBr)
-> IndigoMCaseClauseL IndigoM ret ('CaseClauseParam ctor ('OneField x))
(//->) cName b = OneFieldIndigoMCaseClauseL cName b
infixr 0 //->
-- | Use this instead of '/->'.
--
-- This operator is like '/->' but wraps a body into 'IndigoAnyOut',
-- which is needed for two reasons: to allow having any output stack
-- and to allow returning not exactly the same values.
--
-- It has the added benefit of not being an arrow, so in case the body of the
-- clause is a lambda there won't be several.
(#=)
:: ( name ~ (AppendSymbol "c" ctor)
, KnownValue x
, ScopeCodeGen retBr
, ret ~ RetExprs retBr
, RetOutStack ret ~ RetOutStack retBr
)
=> Label name
-> (Var x -> IndigoM retBr)
-> IndigoMCaseClauseL IndigoM ret ('CaseClauseParam ctor ('OneField x))
(#=) cName b = OneFieldIndigoMCaseClauseL cName b
infixr 0 #=
----------------------------------------------------------------------------
-- Scope & Functions
----------------------------------------------------------------------------
-- | Utility type for an 'IndigoM' that adds one element to the stack and returns
-- a variable pointing at it.
type IndigoFunction ret = IndigoM (RetVars ret)
-- | Utility type for an 'IndigoM' that does not modify the stack (only the
-- values in it) and returns nothing.
type IndigoProcedure = IndigoM ()
type IndigoEntrypoint param = param -> IndigoProcedure
scope
:: forall a . ScopeCodeGen a
=> IndigoM a
-> IndigoFunction a
scope = oneIndigoM . Scope
-- | Alias for 'scope' we use in the tutorial.
defFunction
:: forall a . ScopeCodeGen a
=> IndigoM a
-> IndigoFunction a
defFunction = scope
-- | A more specific version of 'defFunction' meant to more easily create
-- 'IndigoContract's.
--
-- Used in the tutorial. The 'HasSideEffects' constraint is
-- specified to avoid the warning for redundant constraints.
defContract
:: (HasSideEffects => IndigoM ())
-> (HasSideEffects => IndigoProcedure)
defContract = scope
-- | Family of @defNamed*LambdaN@ functions put an Indigo computation
-- on the stack to later call it avoiding code duplication.
-- @defNamed*LambdaN@ takes a computation with N arguments.
-- This family of functions add some overhead to contract byte size
-- for every call of the function,
-- therefore, DON'T use @defNamed*LambdaN@ if:
-- * Your computation is pretty small.
-- It would be cheaper just to inline it, so use 'defFunction'.
-- * Your computation is called only once, in this case also use 'defFunction'.
--
-- Also, pay attention that @defNamed*LambdaN@ accepts a string that is
-- a name of the passed computation. Be careful and make sure that all
-- declared computations have different names.
-- Later the name will be removed.
--
-- Pay attention, that lambda argument will be evaluated
-- to variable before lambda calling.
--
-- TODO Approach with lambda names has critical pitfall:
-- in case if a function takes @Label name@, lambda body
-- won't be regenerated for every different label.
-- So be carefully, this will be fixed in a following issue.
defNamedEffLambda1
:: forall st argExpr res .
( ToExpr argExpr
, Typeable res
, ExecuteLambdaEff1C st (ExprType argExpr) res
, CreateLambdaEff1C st (ExprType argExpr) res
)
=> String
-> (Var (ExprType argExpr) -> IndigoM res)
-> (argExpr -> IndigoM (RetVars res))
defNamedEffLambda1 lName body = \ex ->
oneIndigoM $ LambdaCall1 (EffLambda (Proxy @st)) lName body (toExpr ex)
-- | Like defNamedEffLambda1 but doesn't make side effects.
defNamedLambda1
:: forall st argExpr res .
( ToExpr argExpr
, Typeable res
, ExecuteLambda1C st (ExprType argExpr) res
, CreateLambda1C st (ExprType argExpr) res)
=> String
-> (Var (ExprType argExpr) -> IndigoM res)
-> (argExpr -> IndigoM (RetVars res))
defNamedLambda1 lName body = \ex ->
oneIndigoM $ LambdaCall1 (StorageLambda (Proxy @st)) lName body (toExpr ex)
-- | Like defNamedLambda1 but doesn't take an argument.
defNamedLambda0
:: forall st res .
( Typeable res
, ExecuteLambda1C st () res
, CreateLambda1C st () res)
=> String
-> IndigoM res
-> IndigoM (RetVars res)
defNamedLambda0 lName body =
oneIndigoM $ LambdaCall1 (StorageLambda (Proxy @st)) lName (\(_ :: Var ()) -> body) (C ())
-- | Like defNamedEffLambda1 but doesn't modify storage and doesn't make side effects.
defNamedPureLambda1
:: forall argExpr res .
( ToExpr argExpr
, Typeable res
, ExecuteLambdaPure1C (ExprType argExpr) res
, CreateLambdaPure1C (ExprType argExpr) res)
=> String
-> (Var (ExprType argExpr) -> IndigoM res)
-> (argExpr -> IndigoM (RetVars res))
defNamedPureLambda1 lName body = \ex ->
oneIndigoM $ LambdaCall1 PureLambda lName body (toExpr ex)
----------------------------------------------------------------------------
-- Loop
----------------------------------------------------------------------------
-- | While statement.
while :: forall ex . ex :~> Bool => ex -> IndigoM () -> IndigoM ()
while e body = oneIndigoM $ While (toExpr e) body
whileLeft
:: forall x y ex .
( ex :~> Either y x
, KnownValue y
, KnownValue x
)
=> ex
-> (Var y -> IndigoM ())
-> IndigoM (Var x)
whileLeft e body = oneIndigoM $ WhileLeft (toExpr e) body
-- | For statements to iterate over a container.
forEach
:: forall a e . (IterOpHs a, KnownValue (IterOpElHs a), e :~> a)
=> e -> (Var (IterOpElHs a) -> IndigoM ())
-> IndigoM ()
forEach container body = oneIndigoM $ ForEach (toExpr container) body
----------------------------------------------------------------------------
-- Documentation
----------------------------------------------------------------------------
-- | Put a document item.
doc :: DocItem di => di -> IndigoM ()
doc di = liftIndigoState $ toSIS $ B.doc di
-- | Group documentation built in the given piece of code
-- into a block dedicated to one thing, e.g. to one entrypoint.
docGroup :: DocGrouping -> IndigoM () -> IndigoM ()
docGroup = oneIndigoM ... DocGroup
-- | Insert documentation of the contract's storage type. The type
-- should be passed using type applications.
docStorage :: forall storage. TypeHasDoc storage => IndigoM ()
docStorage = liftIndigoState $ toSIS $ B.docStorage @storage
-- | Give a name to the given contract. Apply it to the whole contract code.
contractName :: Text -> IndigoM () -> IndigoM ()
contractName = oneIndigoM ... ContractName
-- | Attach general info to the given contract.
contractGeneral :: IndigoM () -> IndigoM ()
contractGeneral = oneIndigoM . ContractGeneral
-- | Attach default general info to the contract documentation.
contractGeneralDefault :: IndigoM ()
contractGeneralDefault = liftIndigoState $ toSIS $ B.contractGeneralDefault
-- | Indigo version for the homonym Lorentz function.
finalizeParamCallingDoc
:: forall param.
( ToExpr param
, NiceParameterFull (ExprType param)
, RequireSumType (ExprType param)
, HasCallStack
)
=> (Var (ExprType param) -> IndigoM ()) -> param -> IndigoM ()
finalizeParamCallingDoc i = oneIndigoM . FinalizeParamCallingDoc i . toExpr
-- | Put a 'DDescription' doc item.
description :: Markdown -> IndigoM ()
description = doc . DDescription
-- | Put a 'DAnchor' doc item.
anchor :: Text -> IndigoM ()
anchor = doc . DAnchor . toAnchor
-- | Put a 'DEntrypointExample' doc item.
example :: forall a. NiceParameter a => a -> IndigoM ()
example = doc . mkDEntrypointExample
----------------------------------------------------------------------------
-- Contract call
----------------------------------------------------------------------------
selfCalling
:: forall p mname.
( NiceParameterFull p
, KnownValue (GetEntrypointArgCustom p mname)
)
=> EntrypointRef mname
-> IndigoM (Var (ContractRef (GetEntrypointArgCustom p mname)))
selfCalling = oneIndigoM ... SelfCalling (Proxy @p)
contractCalling
:: forall cp epRef epArg addr exAddr.
( HasEntrypointArg cp epRef epArg
, ToTAddress cp addr
, ToT addr ~ ToT Address
, exAddr :~> addr
, KnownValue epArg
)
=> epRef -> exAddr -> IndigoM (Var (Maybe (ContractRef epArg)))
contractCalling epRef = oneIndigoM . ContractCalling (Proxy @cp) epRef . toExpr
----------------------------------------------------------------------------
-- Side-effects operations
----------------------------------------------------------------------------
transferTokens
:: (IsExpr exp p, IsExpr exm Mutez, IsExpr exc (ContractRef p), NiceParameter p, HasSideEffects)
=> exp -> exm -> exc -> IndigoM ()
transferTokens ep em ec = oneIndigoM $
TransferTokens (toExpr ep) (toExpr em) (toExpr ec)
setDelegate :: (HasSideEffects, IsExpr ex (Maybe KeyHash)) => ex -> IndigoM ()
setDelegate = oneIndigoM . SetDelegate . toExpr
-- | Create contract using default compilation options for Lorentz compiler.
--
-- See "Lorentz.Run".
createContract
:: ( IsObject st
, IsExpr exk (Maybe KeyHash), IsExpr exm Mutez, IsExpr exs st
, NiceStorage st, NiceParameterFull param
, HasSideEffects
)
=> (HasStorage st => Var param -> IndigoM ())
-> exk
-> exm
-> exs
-> IndigoM (Var Address)
createContract iCtr ek em es = oneIndigoM $
CreateContract (defaultContract $ compileIndigoContract iCtr) (toExpr ek) (toExpr em) (toExpr es)
-- | Create contract from raw Lorentz 'L.Contract'.
createLorentzContract
:: ( IsObject st
, IsExpr exk (Maybe KeyHash), IsExpr exm Mutez, IsExpr exs st
, NiceStorage st, NiceParameterFull param
, HasSideEffects
)
=> L.Contract param st
-> exk
-> exm
-> exs
-> IndigoM (Var Address)
createLorentzContract lCtr ek em es = oneIndigoM $
CreateContract lCtr (toExpr ek) (toExpr em) (toExpr es)
----------------------------------------------------------------------------
-- Error
----------------------------------------------------------------------------
failWith
:: forall ret a ex . (IsExpr ex a, ReturnableValue ret)
=> ex -> IndigoM (RetVars ret)
failWith = oneIndigoM . FailOver (Proxy @ret) (toSIS . B.failWith) . toExpr
failUsing_
:: forall ret x. (IsError x, ReturnableValue ret)
=> x -> IndigoM (RetVars ret)
failUsing_ x = oneIndigoM $ Fail (Proxy @ret) (toSIS $ B.failUsing_ x)
failCustom
:: forall ret tag err ex.
( ReturnableValue ret
, err ~ ErrorArg tag
, CustomErrorHasDoc tag
, NiceConstant err
, ex :~> err
)
=> Label tag -> ex -> IndigoM (RetVars ret)
failCustom l = oneIndigoM . FailOver (Proxy @ret) (toSIS . B.failCustom l) . toExpr
failCustom_
:: forall ret tag notVoidErrorMsg.
( ReturnableValue ret
, RequireNoArgError tag notVoidErrorMsg
, CustomErrorHasDoc tag
)
=> Label tag -> IndigoM (RetVars ret)
failCustom_ tag = oneIndigoM $ Fail (Proxy @ret) (toSIS $ B.failCustom_ tag)
failUnexpected_
:: forall ret. ReturnableValue ret
=> MText -> IndigoM (RetVars ret)
failUnexpected_ tx = oneIndigoM $ Fail (Proxy @ret) (toSIS $ B.failUnexpected_ tx)
assert
:: forall x ex.
( IsError x
, IsExpr ex Bool
)
=> x -> ex -> IndigoM ()
assert err ex = if_ ex (return ()) (failUsing_ @() err)
assertCustom
:: forall tag err errEx ex .
( err ~ ErrorArg tag
, CustomErrorHasDoc tag
, NiceConstant err
, IsExpr errEx err
, IsExpr ex Bool
)
=> Label tag -> errEx -> ex -> IndigoM ()
assertCustom tag errEx ex = if_ ex (return ()) (failCustom @() tag errEx)
assertCustom_
:: forall tag notVoidErrorMsg ex.
( RequireNoArgError tag notVoidErrorMsg
, CustomErrorHasDoc tag
, IsExpr ex Bool
)
=> Label tag -> ex -> IndigoM ()
assertCustom_ tag ex = if_ ex (return ()) (failCustom_ @() tag)
assertSome
:: forall x err ex.
( IsError err
, KnownValue x
, ex :~> Maybe x
)
=> err -> ex -> IndigoM ()
assertSome err ex = ifSome ex (\_ -> failUsing_ @() err) (return ())
assertNone
:: forall x err ex.
( IsError err
, KnownValue x
, ex :~> Maybe x
)
=> err -> ex -> IndigoM ()
assertNone err ex = ifSome ex (\_ -> return ()) (failUsing_ @() err)
assertRight
:: forall x y err ex.
( IsError err
, KnownValue x
, KnownValue y
, ex :~> Either y x
)
=> err -> ex -> IndigoM ()
assertRight err ex = ifRight ex (\_ -> failUsing_ @() err) (\_ -> return ())
assertLeft
:: forall x y err ex.
( IsError err
, KnownValue x
, KnownValue y
, ex :~> Either y x
)
=> err -> ex -> IndigoM ()
assertLeft err ex = ifRight ex (\_ -> return ()) (\_ -> failUsing_ @() err)
----------------------------------------------------------------------------
-- Comments
----------------------------------------------------------------------------
-- | Add a comment in a generated Michelson code
justComment :: Text -> IndigoM ()
justComment = comment . MT.JustComment
-- | Add a comment in a generated Michelson code
comment :: MT.CommentType -> IndigoM ()
comment t = liftIndigoState $ toSIS (B.comment t)
-- | Add a comment before and after the given Indigo function code.
-- The first argument is the name of the function.
commentAroundFun :: Text -> IndigoM a -> IndigoM a
commentAroundFun fName body =
comment (MT.FunctionStarts fName) >>
body >>=
\res -> res <$ comment (MT.FunctionEnds fName)
-- | Add a comment before and after the given Indigo statement code.
-- The first argument is the name of the statement.
commentAroundStmt :: Text -> IndigoM a -> IndigoM a
commentAroundStmt sName body =
comment (MT.StatementStarts sName) >>
body >>=
\res -> res <$ comment (MT.StatementEnds sName)