indigo-0.2.1: src/Indigo/Backend/Case.hs
-- SPDX-FileCopyrightText: 2020 Tocqueville Group
--
-- SPDX-License-Identifier: LicenseRef-MIT-TQ
{-# OPTIONS_GHC -Wno-redundant-constraints #-}
-- | High level statements of Indigo language.
module Indigo.Backend.Case
( caseRec
, entryCaseRec
, entryCaseSimpleRec
, IndigoCaseClauseL
, CaseCommonF
, CaseCommon
, IndigoAnyOut (..)
) where
import Data.Vinyl.Core (RMap(..))
import Util.Type (type (++))
import Util.TypeLits (AppendSymbol)
import Indigo.Backend.Prelude
import Indigo.Backend.Scope
import Indigo.Internal
import Indigo.Lorentz
import qualified Lorentz.ADT as L
import qualified Lorentz.Entrypoints.Doc as L
import qualified Lorentz.Instr as L
import Michelson.Typed.Haskell.Instr.Sum
(CaseClauseParam(..), CaseClauses, CtorField(..), InstrCaseC)
-- | This type is analogous to the 'CaseClauseL' type but instead of wrapping a Lorentz
-- instruction, this wraps an Indigo value with the same input/output types.
data IndigoCaseClauseL ret (param :: CaseClauseParam) where
OneFieldIndigoCaseClauseL
:: (forall inp . MetaData inp -> CaseClauseL inp (RetOutStack ret ++ inp) ('CaseClauseParam ctor ('OneField x)))
-> IndigoCaseClauseL ret ('CaseClauseParam ctor ('OneField x))
data IndigoAnyOut x ret = forall retBranch .
( ScopeCodeGen retBranch
, RetOutStack ret ~ RetOutStack retBranch
) =>
IndigoAnyOut (forall inp . SomeIndigoState (x : inp) retBranch)
instance
( name ~ AppendSymbol "c" ctor
, KnownValue x
)
=>
CaseArrow
name
(Var x -> IndigoAnyOut x ret)
(IndigoCaseClauseL ret ('CaseClauseParam ctor ('OneField x)))
where
(/->) _ ind =
OneFieldIndigoCaseClauseL (\(md :: MetaData inp) ->
-- Create a reference to the top of stack
let (varCase, mdCaseBody) = pushRefMd md in
-- Pass the reference to the case body
case ind varCase of
IndigoAnyOut (SomeIndigoState body :: SomeIndigoState (x : inp) retBr) ->
case body mdCaseBody of
SomeGenCode gc ->
CaseClauseL $
-- Compute returning expressions and clean up everything
compileScope gc #
-- Remove @x@ from the stack too
liftClear' @(ClassifyReturnValue retBr) @retBr @(x & inp) @inp L.drop
)
-- This constraint is shared by all @case*@ functions.
type CaseCommonF f dt ret clauses =
( InstrCaseC dt
, RMap (CaseClauses dt)
, clauses ~ Rec (f ret) (CaseClauses dt)
, ScopeCodeGen ret
)
type CaseCommon dt ret clauses = CaseCommonF IndigoCaseClauseL dt ret clauses
-- | A case statement for indigo. See examples for a sample usage.
caseRec
:: forall dt inp ret clauses . CaseCommon dt ret clauses
=> Expr dt
-> clauses
-> IndigoState inp (RetOutStack ret ++ inp) (RetVars ret)
caseRec g cls = IndigoState $ \md ->
let cdG = gcCode $ runIndigoState (compileExpr g) md in
finalizeStatement @ret md (cdG # L.case_ (toCaseClauseL md cls))
-- | 'case_' for pattern-matching on parameter.
entryCaseRec
:: forall dt entrypointKind inp ret clauses .
( CaseCommon dt ret clauses
, DocumentEntrypoints entrypointKind dt
)
=> Proxy entrypointKind
-> Expr dt
-> clauses
-> IndigoState inp (RetOutStack ret ++ inp) (RetVars ret)
entryCaseRec proxy g cls = IndigoState $ \md ->
let cdG = gcCode $ runIndigoState (compileExpr g) md in
finalizeStatement @ret md (cdG # L.entryCase_ proxy (toCaseClauseL md cls))
-- | 'entryCase_' for contracts with flat parameter.
entryCaseSimpleRec
:: forall cp inp ret clauses .
( CaseCommon cp ret clauses
, DocumentEntrypoints PlainEntrypointsKind cp
, NiceParameterFull cp
, RequireFlatParamEps cp
)
=> Expr cp
-> clauses
-> IndigoState inp (RetOutStack ret ++ inp) (RetVars ret)
entryCaseSimpleRec g cls = IndigoState $ \md ->
let cdG = gcCode $ runIndigoState (compileExpr g) md in
finalizeStatement @ret md (cdG # L.entryCaseSimple_ (toCaseClauseL md cls))
toCaseClauseL
:: forall inp ret cs .
MetaData inp
-> Rec (IndigoCaseClauseL ret) cs
-> Rec (CaseClauseL inp (RetOutStack ret ++ inp)) cs
toCaseClauseL _ RNil = RNil
toCaseClauseL md (OneFieldIndigoCaseClauseL fn :& rest) = fn md :& toCaseClauseL md rest