packages feed

ddc-core-tetra-0.4.2.1: DDC/Core/Tetra/Transform/Curry/CallSuper.hs

module DDC.Core.Tetra.Transform.Curry.CallSuper
        ( makeCallSuperSaturated
        , makeCallSuperUnder)
where
import DDC.Core.Tetra.Transform.Curry.Error
import DDC.Core.Tetra.Prim
import DDC.Core.Exp.Annot
import qualified DDC.Type.Transform.Instantiate as T
import qualified DDC.Core.Tetra.Compounds       as C
import qualified DDC.Core.Call                  as Call


---------------------------------------------------------------------------------------------------
-- | Fully saturated application.
--
--   When the eliminators at the call site exactly match the way the super
--   is constructed then we can call the super directly. In the generated
--   object code we do a standard function call.
--
makeCallSuperSaturated
        :: Name                 -- ^ Name of super to call.
        -> [Call.Cons Name]     -- ^ How the super is constructed.
        -> [Call.Elim () Name]  -- ^ Eliminators at call site.
        -> Either Error (Exp () Name)

makeCallSuperSaturated nF cs es
 | length es == length cs
 , and  $ zipWith Call.elimForCons es cs
 = return $ foldl Call.applyElim (XVar () (UName nF)) es

 | otherwise     
 = Left   $ ErrorSuperCallPatternMismatch nF Nothing (Just cs) es


---------------------------------------------------------------------------------------------------
-- | Under saturated application.
--
--   When we don't have enough eliminators to match all the constructors
--   in the function header then the application is under-saturated.
--
--   We build a PAP object to store the arguments we have at the moment,
--   and the runtime will wait until we have the full set until calling
--   the underlying super.
--
--   This only works for supers in the standard form,
--    eg /\(a1 : k1). .. /\(a2 : k1). \(x1 : t1). .. \(x2 : t2). box
--
--   At the call site we must provide type arguments to satify
--   all the type parameters, but don't need to supply all the value
--   arguments, or to run the box. We restrict the call pattern this
--   way to make the runtime easier to write, and so that we can implement
--   PAP construction and elimination using primitives with straightforward
--   types. 
--
makeCallSuperUnder
        :: Name                 -- ^ Name of super to call.
        -> Type Name            -- ^ Type of super.
        -> [Call.Cons Name]     -- ^ How the super is constructed.
        -> [Call.Elim () Name]  -- ^ Eliminators at call site.
        -> Either Error (Maybe (Exp () Name))

makeCallSuperUnder nF tF cs es
 -- We have no eliminators at all, 
 -- so this is just a reference to a top-level super that is not 
 -- being applied.
 --  | []   <- es
 -- = return $ Just $ XVar () (UName nF)


 -- We have more constructors than eliminators.
 | length es <  length cs

 -- The super and call  must be in standard form.
 , Just (esType, esValue,  esRuns) <- Call.splitStdCallElims es
 , Just (csType, _csValue, _cBox)  <- Call.splitStdCallCons  cs

 -- There must be types to satisfy all of the type parameters of the super.
 , length esType == length csType

 -- Instantiate the type of the function.
 , Just tF_inst  <- T.instantiateTs tF [t | Call.ElimType _ _ t <- esType]
 = let
        -- Split the quantifiers, parameter type, and body type
        -- from the type of the super.
        (tsParam,  tResult) = C.takeTFunArgResult tF_inst

        iArity          = length cs
        xsArgType       = [XType at t  | Call.ElimType  _ at t  <- esType]
        xsArgValue      = [x           | Call.ElimValue _ x     <- esValue]

        -- Split the value parameters into ones accepted by the super,
        -- and ones that are accepted by the returned closures.
        (tsParamLam, tsParamClo) 
                        = splitAt iArity tsParam
        
        -- Build the type of the returned value.
        tResult'        = C.tFunOfParamResult tsParamClo tResult
        
        -- Instantiate all the type parameters.
        xFunAPP         = C.xApps () (XVar () (UName nF)) xsArgType

        -- Split types of the super parameters into the ones that can be
        -- satisfied by this application, and the remaining parameters that
        -- are still waiting for arguments.
        (tsParamSat, tsParamRemain)     
                        = splitAt (length xsArgValue) tsParamLam

        -- The type of the result after performing this application.
        -- If there are remaining, un-saturated parameters the result
        -- type will still be a function.
        tResultClo      = C.tFunOfParamResult tsParamRemain tResult'

   in   case tsParamLam of
         -- We should have at least one argument to apply. 
         -- If not then the arity information is wrong or the super we were
         -- told to call doesn't have any parameters. Either case is a bug.
         [] -> error $ "ddc-core-tetra.makeCallSuperUnder: no arguments to apply."

         tParamFirst : tsParamRest
          -> let tSuperResult    = C.tFunOfParamResult tsParamRest tResult'
             in return
                 $ Just
                 $ makeRuns () (length esRuns)
                 $ C.xApps  () (C.xFunCurry () tsParamSat tResultClo 
                               (C.xFunCReify () tParamFirst tSuperResult xFunAPP))
                               xsArgValue

 | otherwise
 = return $ Nothing