ddc-core-tetra-0.4.2.1: DDC/Core/Tetra/Convert/Exp/Alt.hs
module DDC.Core.Tetra.Convert.Exp.Alt
(convertAlt)
where
import DDC.Core.Tetra.Convert.Exp.Base
import DDC.Core.Tetra.Convert.Data
import DDC.Core.Tetra.Convert.Type
import DDC.Core.Tetra.Convert.Error
import DDC.Core.Exp.Annot
import DDC.Type.DataDef
import DDC.Core.Check (AnTEC(..))
import DDC.Control.Monad.Check (throw)
import qualified DDC.Core.Tetra.Prim as E
import qualified DDC.Core.Salt.Name as A
import qualified DDC.Core.Salt.Compounds as A
import qualified Data.Map as Map
-- | Convert a Tetra alternative to Salt.
convertAlt
:: Show a
=> a -- ^ Annotation from case expression.
-> Bound E.Name -- ^ Bound of scrutinee.
-> Type E.Name -- ^ Type of scrutinee
-> ExpContext -- ^ Context of enclosing case-expression.
-> Context a -- ^ Type context of the conversion.
-> Alt (AnTEC a E.Name) E.Name -- ^ Alternative to convert.
-> ConvertM a (Alt a A.Name)
convertAlt a uScrut tScrut ectx ctx alt
= let pp = contextPlatform ctx
defs = contextDataDefs ctx
kenv = contextKindEnv ctx
convertX = contextConvertExp ctx
tctx = typeContext ctx
in case alt of
-- Match against the unit constructor.
-- This is baked into the langauge and doesn't have a real name,
-- so we need to handle it separately.
AAlt (PData dc []) x
| DaConUnit <- dc
-> do xBody <- convertX ectx ctx x
let dcTag = DaConPrim (A.NamePrimLit $ A.PrimLitTag 0) A.tTag
return $ AAlt (PData dcTag []) xBody
-- Match against literal unboxed values.
AAlt (PData dc []) x
| Just nCtor <- takeNameOfDaCon dc
, E.isNameLit nCtor
-> do dc' <- convertDaCon tctx dc
xBody1 <- convertX ectx ctx x
return $ AAlt (PData dc' []) xBody1
-- Match against user-defined algebraic data.
AAlt (PData dc bsFields) x
| Just nCtor <- takeNameOfDaCon dc
, Just ctorDef <- Map.lookup nCtor $ dataDefsCtors defs
-> do
-- Convert the scrutinee.
uScrut' <- convertDataU uScrut
>>= maybe (throw $ ErrorInvalidBound uScrut) return
-- Get the tag of this alternative.
let iTag = fromIntegral $ dataCtorTag ctorDef
let dcTag = DaConPrim (A.NamePrimLit $ A.PrimLitTag iTag) A.tTag
-- Get the address of the payload.
bsFields' <- mapM (convertDataB tctx) bsFields
-- Convert the right of the alternative,
-- with all all the pattern variables in scope.
let ctx' = extendsTypeEnv bsFields ctx
xBody1 <- convertX ectx ctx' x
-- Determine the prime region of the scrutinee.
-- This is the region the associated Salt object is in.
trPrime <- saltPrimeRegionOfDataType kenv tScrut
-- Wrap the body expression with let-bindings that bind
-- each of the fields of the data constructor.
xBody2 <- destructData pp a ctorDef uScrut' trPrime
bsFields' xBody1
return $ AAlt (PData dcTag []) xBody2
-- Default alternative.
AAlt PDefault x
-> do x' <- convertX ectx ctx x
return $ AAlt PDefault x'
-- Invalid alternative.
-- Maybe we don't have the definition for the data constructor
-- being matched against.
AAlt{}
-> throw $ ErrorInvalidAlt alt