ddc-core-tetra-0.4.2.1: DDC/Core/Tetra/Transform/Curry/Callable.hs
module DDC.Core.Tetra.Transform.Curry.Callable
( Callable (..)
, CallableSource (..)
, typeOfCallable
, consOfCallable
, takeCallablesOfModule
, takeCallableFromImport
, takeCallableFromSuper)
where
import DDC.Core.Tetra.Transform.Curry.Error
import DDC.Core.Module
import DDC.Core.Exp
import DDC.Core.Exp.Annot.AnTEC
import Control.Monad
import Data.Maybe
import Data.Map (Map)
import qualified DDC.Core.Call as Call
import qualified DDC.Core.Tetra.Prim as E
import qualified Data.Map as Map
-- | Enough information to call a super.
--
-- Callable supers are must use the standard call convention,
-- with their type parameters, value parameters and boxings in that order.
--
data Callable
-- | A directly callable super in the current module.
= Callable
{ callableSource :: CallableSource
, callableType :: Type E.Name
, callableCons :: [Call.Cons E.Name] }
deriving (Show)
-- | The source of a callable super.
data CallableSource
-- | Callable super is defined in the current module.
= CallableSuperLocal
-- | Callable thing is a super
| CallableSuperOther
-- | Callable super is imported from sea land.
| CallableImportSea
deriving Show
-- | Take the Tetra type of a callable thing.
typeOfCallable :: Callable -> Type E.Name
typeOfCallable (Callable _ t _) = t
-- | Take the call constructors from a `Callable`.
consOfCallable :: Callable -> [Call.Cons E.Name]
consOfCallable (Callable _ _ cs) = cs
-- Get callable things from the current module.
takeCallablesOfModule
:: Module (AnTEC a E.Name) E.Name
-> Either Error (Map E.Name Callable)
takeCallablesOfModule mm
= do
-- Get callables from imported things.
nsCallableImport
<- liftM catMaybes
$ mapM (uncurry takeCallableFromImport)
$ moduleImportValues mm
-- Get callable top-level supers.
nsCallableSuperLocal
<- mapM (uncurry takeCallableFromSuper)
$ mapTopBinds (\b x -> (b, x)) mm
return $ Map.fromList $ nsCallableSuperLocal ++ nsCallableImport
-- | Take a `Callable` from an `ImportValue`, or Nothing if there isn't one.
takeCallableFromImport
:: E.Name -- ^ Name of the imported thing.
-> ImportValue E.Name -- ^ Import definition.
-> Either Error (Maybe (E.Name, Callable))
takeCallableFromImport n im
-- A thing imported from some other module.
-- We determine the call pattern from its type and arity information,
-- which comes in the interface file. We need the arity information
-- because the super may return a functional value, which we cannot
-- direct from its logical type alone.
| ImportValueModule _ _ tThing (Just arity) <- im
, (nTypes, nValues, nBoxes) <- arity
= case Call.takeStdCallConsFromTypeArity tThing nTypes nValues nBoxes of
Nothing
-> Left $ ErrorSuperArityMismatch n tThing (nTypes, nValues, nBoxes)
Just cs
-> return $ Just (n, Callable CallableSuperOther tThing cs)
-- A thing imported from sea land.
-- We determine the call pattern directly from the type.
-- Things imported from Sea land do not return functional values,
-- so every parameter in the type is a real parameter in the call pattern.
--
-- ISSUE #348: Restrict types of things that can be foreign imported.
-- The parameter and result type of imported functions should have
-- primitive type only, but we don't check this fact. We should also
-- check that each imported function has the standard call pattern.
--
| ImportValueSea _ ty <- im
= let cs = Call.takeCallConsFromType ty
in return $ Just (n, Callable CallableImportSea ty cs)
| otherwise
= return Nothing
-- | Take the standard call pattern from the body of a super combinator.
takeCallableFromSuper
:: Bind E.Name
-> Exp a E.Name
-> Either Error (E.Name, Callable)
takeCallableFromSuper (BName n t) xx
= do let cs = Call.takeCallConsFromExp xx
return $ (n, Callable CallableSuperLocal t cs)
takeCallableFromSuper b _
= Left $ ErrorSuperUnnamed b