uhc-light-1.1.7.1: src/UHC/Light/Compiler/Core/API.hs
{-# LINE 2 "src/ehc/Core/API.chs" #-}
-- | Core Public API (provisional)
--
-- Intended for constructing basic Core Programs.
-- This module does not offer any way to inspect the built Core Programs (on purpose), but the
-- EHXX.Core module does.
--
-- Invariants:
-- - Constructor applications (mkCon) always have to be fully saturated. (Should we handle this internally?)
-- - Haskell constructor names must be unambigous per module (mkHSCTag)
-- - TODO Tag ordering ?? What exactly are the invariants?
--
-- TODO Use AbstractCore instead of directly using the Constructors in the implementation
module UHC.Light.Compiler.Core.API
(
-- Opts
EHCOpts
, defaultEHCOpts
-- * Core AST
-- | The datatypes making up a Core program.
, CModule
, CImport
, CDeclMeta
, CDataCon
, CExpr
, CBind
, CAlt
, CPat
, CPatFld
-- Base.Common
, CTag
-- Base.HsName
, HsName
-- * Names
-- | Names in UHC have to be of the form P1.P2....Pn.Ident . All names
-- in module M must have the form M.Ident . Datatype and constructor names
-- have to start with an uppercase letter, functions with a lowercase letter.
, mkUniqueHsName
, mkHsName
, mkHsName1
, addHsNamePrefix
-- * Construction functions
-- ** Constants
, acoreUnit
, acoreInt
, acoreBuiltinInteger -- TODO acoreInt2 or acoreBuiltinInteger ?
, acoreBuiltinString
, acoreBuiltinError
, acoreBuiltinUndefined
-- ** Variables
, acoreVar
-- ** Let Bindings
, acoreLet1Plain
, acoreLet1Strict
, acoreLetRec
-- ** Case
-- | Scrutinizes an expression and executes the appropriate alternative.
-- The scrutinee of a case statement is required to be in WHNF (weak head normal form).
, acoreCaseDflt
, acoreAlt
, acorePatCon
, acorePatRestEmpty
, acorePatFldBind
-- ** Abstraction
, acoreLam
-- ** Application
, acoreApp
-- ** Datatypes
, acoreTagTup
-- ** Binds/Bounds
, acoreBind1
, acoreBind1Nm1
-- ** Module
, makeModule
, makeImport
, makeMetaData
, makeMetaDataCon
-- * Utilities
, makeMain
)
where
import qualified Data.Map as M
import Data.List
import Data.Ord
import UHC.Light.Compiler.AbstractCore hiding (acoreCaseDflt)
import qualified UHC.Light.Compiler.AbstractCore as AC
import UHC.Light.Compiler.Base.Common
import UHC.Light.Compiler.Base.HsName
import UHC.Light.Compiler.Core hiding (acoreCaseDflt)
import UHC.Light.Compiler.Opts
-- | Creates a new Core name. All names generated with this function live in
-- the "Core API" namespace and will not collide with names in other namespaces.
-- Names in the "Core API" namespace cannot be called from Haskell code.
--
-- Use this function to create names used only inside Core code generated by your own Compiler,
-- e.g. module-scoped or local functions.
mkUniqueHsName :: String -- ^ Name prefix. Used to distinguish names generated by different API consumers,
-- but may also be used to differentiate between different varieties by one API consumer.
-- Use reverse-dns notation if possible, e.g. "nl.uu.agda.identOfVarietyA"
-> [String] -- ^ The module prefix.
-> String -- ^ The name to make unique.
-> HsName
-- UHC expects names to be of the _Modf variety. If _Base/hsnFromString is used
-- instead things start to break, e.g. calling functions defined in other packages.
mkUniqueHsName prefix = hsnMkModf1 (M.singleton HsNameUniqifier_CoreAPI [HsNameUnique_String prefix])
-- | Creates a new Core name. The generated name lives in the default namespace,
-- hence may clash with Haskell-defined names.
mkHsName :: [String] -- ^ The module prefix.
-> String -- ^ The local name of the identifier.
-> HsName
mkHsName = hsnMkModf1 M.empty
-- | Creates a new Core name. The generated name lives in the default namespace,
-- hence may clash with Haskell-defined names.
mkHsName1 :: String
-> HsName
mkHsName1 nm = mkHsName (init xs) (last xs)
-- TODO there is probably something like that somewhere in UHC?
where xs = splitBy '.' nm
splitBy :: Eq a => a -> [a] -> [[a]]
splitBy sep = (foldr (\x (a1:as) -> if x == sep then ([]:a1:as) else ((x:a1):as)) [[]])
-- | Adds an additional prefix to a 'HsName'. This can be used to derive a new
-- unique name from an existing name.
addHsNamePrefix :: String -> HsName -> HsName
addHsNamePrefix prefix name = hsnUniqifyStr HsNameUniqifier_CoreAPI prefix name
-- | Local helper function. Converts string names to HsNames.
hsnMkModf1 :: HsNameUniqifierMp -> [String] -> String -> HsName
-- UHC expects names to be of the _Modf variety. If _Base/hsnFromString is used
-- instead things start to break, e.g. calling functions defined in other packages.
hsnMkModf1 uniq mods nm = hsnMkModf mods (hsnFromString nm) uniq
-- TODO how should we handle the type?
-- | Creates the unit expresssion.
acoreUnit :: EHCOpts -> CExpr
acoreUnit _ = acoreTup []
-- TODO verify that this sorting is always correct (see also AbstractCore/Utils.chs)
-- | A Case expression, possibly with a default value.
acoreCaseDflt :: AbstractCore e m b bound boundmeta bcat mbind t p pr pf a
=> e -- ^ The scrutinee. Required to be in WHNF.
-> [a] -- ^ The alternatives.
-> Maybe e -- ^ The default value. (TODO what is the behaviour if it is Nothing?)
-> e
acoreCaseDflt e as def =
AC.acoreCaseDflt e (sortBy (comparing (getTag . fst . acoreUnAlt)) as) def
where -- gets the for constructors, or returns 0 if this is not a constructor pattern
-- TODO is this always safe?
getTag t = case acorePatMbCon t of
Just (tag, _, _) -> ctagTag tag
Nothing -> 0
-- | Creates a module.
makeModule :: HsName -- ^ The name of the module.
-> [CImport] -- ^ The imports (only direct imports, not transitive ones).
-> [CDeclMeta] -- ^ The meta information.
-> CExpr -- ^ The body of the module.
-> CModule
makeModule = CModule_Mod
-- | Creates an import.
makeImport :: HsName -- ^ The module to import.
-> CImport
makeImport = CImport_Import
-- | Creates the metadata for one datatype.
makeMetaData :: HsName -- ^ The name of the dataype.
-> [CDataCon] -- ^ The constructors of the dataype.
-> CDeclMeta
makeMetaData = CDeclMeta_Data
-- | Creates the metadata for one constructor.
makeMetaDataCon :: HsName -- ^ The fully qualified name of the constructor.
-> Int -- ^ The tag of this constructor.
-> Int -- ^ The arity of this constructor.
-> CDataCon
makeMetaDataCon = CDataCon_Con
-- | Creates the main entry point, calling the given function when run. The given
-- function to call has to be in scope (either define it in the same module,
-- or import it).
makeMain :: HsName -- ^ The function containing the user code to call.
-> CExpr
makeMain main = mainEhc
where mainEhc = acoreLet1Plain mainNm
(acoreApp (acoreVar $ hsnMkModf ["UHC", "Run"] (hsnFromString "ehcRunMain") M.empty) [acoreVar main])
(acoreVar mainNm)
mainNm = hsnMkModf [] (hsnFromString "main") M.empty