{-# 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