ddc-source-tetra-0.4.3.1: DDC/Source/Tetra/Convert/Clause.hs
module DDC.Source.Tetra.Convert.Clause
( collectSigsFromClauses
, collectBoundVarsFromClauses
, makeBindingFromClause)
where
import DDC.Source.Tetra.Convert.Error
import DDC.Source.Tetra.Convert.Base
import qualified DDC.Source.Tetra.Exp as S
-- | Collect type signatures defined in a clause group.
collectSigsFromClauses :: [S.Clause] -> [(S.BindVar, S.Type)]
collectSigsFromClauses cls
= go cls
where go (S.SSig _ b t : cls')
= (b, t) : go cls'
go (_ : cls') = go cls'
go [] = []
-- | Collect binders for values defined in a clause group.
collectBoundVarsFromClauses :: [S.Clause] -> [S.BindVar]
collectBoundVarsFromClauses cls
= go cls
where go (S.SLet _ (S.XBindVarMT b _) _ _ : cls')
= b : go cls'
go (_ : cls') = go cls'
go [] = []
-- | Strip a let-binding from a clause.
makeBindingFromClause
:: [(S.BindVar, S.Type)] -- ^ Type signatures in the same group.
-> [ S.BindVar ] -- ^ Bound values defined in the same group.
-> S.Clause -- ^ Clause to consider.
-> ConvertM S.Source
(Maybe (S.BindVarMT, (SP, S.Exp)))
-- ^ Let-bindings with attached signatures.
makeBindingFromClause sigs vals cc
= case cc of
S.SLet sp bm@(S.XBindVarMT b mtHas) ps [S.GExp x]
-- See if there was a type signature specified in the same group.
| Just tSig <- lookup b sigs
-> case mtHas of
-- If the binder was already directly annotated with a signature
-- then throw an error, as it might conflict with the separate
-- signature provided in the same group.
Just _ -> Left $ ErrorMultipleSignatures sp b
-- The binder was not directly annotated,
-- so attach the provided signature.
Nothing
-> case wrapParams ps x of
Nothing -> Left $ ErrorConvertSugaredClause cc
Just x' -> return $ Just $ ( S.XBindVarMT b (Just tSig), (sp, x'))
-- We don't have a separate signature for this binding.
| otherwise
-> case wrapParams ps x of
Nothing -> Left $ ErrorConvertSugaredClause cc
Just x' -> return $ Just $ (bm, (sp, x'))
-- Some let binding with an expression that should have
-- been desugared earlier.
S.SLet{} -> Left $ ErrorConvertSugaredClause cc
-- Check that signatures in the clause group have associated bindings.
-- If we find a signature without a binding then one or
-- the other is probably mis-spelled.
S.SSig sp b _
| elem b vals -> return Nothing
| otherwise -> Left $ ErrorTypeSignatureLacksBinding sp b
-- | Wrap an expression with lambda abstractions for each
-- of the given parameters.
wrapParams :: [S.Param] -> S.Exp -> Maybe S.Exp
wrapParams [] x
= pure x
wrapParams (p:ps) x
= case p of
S.MType b mt
-> S.XLAM (S.XBindVarMT b mt) <$> wrapParams ps x
S.MWitness b mt
-> S.XLam (S.XBindVarMT b mt) <$> wrapParams ps x
S.MValue S.PDefault mt
-> S.XLam (S.XBindVarMT S.BNone mt) <$> wrapParams ps x
S.MValue (S.PVar b) mt
-> S.XLam (S.XBindVarMT b mt) <$> wrapParams ps x
-- Some pattern that should have been desugared earlier.
S.MValue _ _
-> Nothing