{-# LANGUAGE GADTs, TemplateHaskell, KindSignatures #-} module UHC.Light.Compiler.EHC.ASTPipeline ( module UHC.Light.Compiler.EHC.ASTTypes , ASTType (..) , ASTScope (..) , ASTFileContent (..) , ASTHandlerKey , ASTFileUse (..) , ASTSuffixKey , ASTFileTiming (..) , ASTAvailableFile (..) , astfileuseReadTiming , ASTSemFlowStage (..) , ASTAlreadyFlowIntoCRSIFromToInfo, ASTAlreadyFlowIntoCRSIInfo , ASTTrf (..) , ASTPipe (..), emptyASTPipe , TmChoice (..) , ASTBuildPlan (..) , mkBuildPlan , astplMbSubPlan , astplFind , mkASTPipeForASTTypes , astpTypes , astpFind , ASTPipeBldCfg (..), emptyASTPipeBldCfg , astpipe_EH_from_HS , astpipeForCfg , astpipeForEHCOpts , ASTPipeHowChoice (..) ) where import UHC.Light.Compiler.Base.Common import UHC.Light.Compiler.Base.Optimize import UHC.Light.Compiler.Base.Target import UHC.Light.Compiler.Opts.Base import qualified Data.Set as Set import Data.Monoid import UHC.Util.Pretty import UHC.Util.FPath import UHC.Util.Utils import UHC.Light.Compiler.EHC.ASTTypes {-# LINE 37 "src/ehc/EHC/ASTPipeline.chs" #-} -- | An 'Enum' of all types of ast we can deal with. -- Order matters, ordering corresponds to 'can be generated from'. -- 20150804: made more explicit via `ASTPipe`. data ASTType = ASTType_HS | ASTType_EH | ASTType_Core | ASTType_CoreRun | ASTType_ExecCoreRun | ASTType_C | ASTType_O | ASTType_LibO | ASTType_ExecO | ASTType_HI | ASTType_Unknown deriving (Eq, Ord, Enum, Typeable, Generic, Bounded) instance Hashable ASTType instance DataAndConName ASTType instance Show ASTType where show = showUnprefixed 1 instance PP ASTType where pp = pp . show {-# LINE 85 "src/ehc/EHC/ASTPipeline.chs" #-} -- | How much AST data ASTScope = ASTScope_Single -- ^ single module | ASTScope_Whole -- ^ whole program --- | ASTScope_Any -- ^ any/arbitrary of above deriving (Eq, Ord, Enum, Typeable, Generic, Bounded) instance Hashable ASTScope instance DataAndConName ASTScope instance Show ASTScope where show = showUnprefixed 1 instance PP ASTScope where pp = pp . show {-# LINE 103 "src/ehc/EHC/ASTPipeline.chs" #-} -- | File content variations of ast we can deal with (in principle) data ASTFileContent = ASTFileContent_Text -- ^ textual, readable input/output | ASTFileContent_ASTText -- ^ textual, readable AST output | ASTFileContent_LitText -- ^ textual, readable input | ASTFileContent_Binary -- ^ binary/serialized input/output | ASTFileContent_Unknown deriving (Eq, Ord, Enum, Typeable, Generic, Bounded) instance Hashable ASTFileContent instance DataAndConName ASTFileContent instance Show ASTFileContent where show = showUnprefixed 1 instance PP ASTFileContent where pp = pp . show {-# LINE 123 "src/ehc/EHC/ASTPipeline.chs" #-} -- | Combination of 'ASTType' and 'ASTFileContent' as key into map of handlers type ASTHandlerKey = (ASTType, ASTFileContent) {-# LINE 128 "src/ehc/EHC/ASTPipeline.chs" #-} -- | File usage variations of ast data ASTFileUse = ASTFileUse_Cache -- ^ internal use cache on file | ASTFileUse_Dump -- ^ output: dumped, possibly usable as src later on | ASTFileUse_Target -- ^ output: as target of compilation | ASTFileUse_Src -- ^ input: src file | ASTFileUse_SrcImport -- ^ input: import stuff only from src file | ASTFileUse_Unknown -- ^ unknown deriving (Eq, Ord, Enum, Typeable, Generic, Bounded) instance Hashable ASTFileUse instance DataAndConName ASTFileUse instance Show ASTFileUse where show = showUnprefixed 1 instance PP ASTFileUse where pp = pp . show {-# LINE 149 "src/ehc/EHC/ASTPipeline.chs" #-} -- | Key for allowed suffixes, multiples allowed to cater for different suffixes type ASTSuffixKey = (ASTFileContent, ASTFileUse) {-# LINE 154 "src/ehc/EHC/ASTPipeline.chs" #-} -- | File timing variations of ast data ASTFileTiming = ASTFileTiming_Prev -- ^ previously generated | ASTFileTiming_Current -- ^ current one deriving (Eq, Ord, Enum, Typeable, Generic, Bounded) instance Hashable ASTFileTiming instance DataAndConName ASTFileTiming instance Show ASTFileTiming where show = showUnprefixed 1 instance PP ASTFileTiming where pp = pp . show {-# LINE 171 "src/ehc/EHC/ASTPipeline.chs" #-} -- | Available File for AST (as checked when first searching for a file) data ASTAvailableFile = ASTAvailableFile { _astavailfFPath :: FPath , _astavailfType :: ASTType , _astavailfContent :: ASTFileContent , _astavailfUse :: ASTFileUse -- , _astavailfTiming :: ASTFileTiming } deriving (Eq, Ord, Typeable, Generic) instance Hashable ASTAvailableFile instance Show ASTAvailableFile where show (ASTAvailableFile f t c u {- tm -}) = "(" ++ [head (show t), head (show c), head (show u)] ++ ")" instance PP ASTAvailableFile where pp (ASTAvailableFile f t c u {- tm -}) = f >#< ppParensCommas [pp t, pp c, pp u] {-# LINE 197 "src/ehc/EHC/ASTPipeline.chs" #-} -- | The timing when read astfileuseReadTiming :: ASTFileUse -> ASTFileTiming astfileuseReadTiming ASTFileUse_Cache = ASTFileTiming_Prev astfileuseReadTiming _ = ASTFileTiming_Current {-# LINE 208 "src/ehc/EHC/ASTPipeline.chs" #-} -- | An 'Enum' of the stage semantic results are flown into global state data ASTSemFlowStage = --- | per module ASTSemFlowStage_PerModule | --- | between subsequent module compilations ASTSemFlowStage_BetweenModule deriving (Eq, Ord, Typeable, Generic) instance Hashable ASTSemFlowStage instance DataAndConName ASTSemFlowStage instance Show ASTSemFlowStage where show = showUnprefixed 1 instance PP ASTSemFlowStage where pp = pp . show {-# LINE 233 "src/ehc/EHC/ASTPipeline.chs" #-} -- | Key for remembering what already has flown into global state type ASTAlreadyFlowIntoCRSIFromToInfo = ( Maybe ASTType -- possible 'to ast' , ASTType -- 'from ast' ) -- | Key for remembering what already has flown into global state type ASTAlreadyFlowIntoCRSIInfo = ( ASTSemFlowStage , Maybe ASTAlreadyFlowIntoCRSIFromToInfo -- possible extra context ) {-# LINE 251 "src/ehc/EHC/ASTPipeline.chs" #-} -- | Description of transformation data ASTTrf where --- | Optimize, valid for some scopes only ASTTrf_Optim :: [ASTScope] -> ASTTrf --- | Check and adapt (source usually) ASTTrf_Check :: ASTTrf deriving (Eq, Ord, Typeable, Generic) instance Hashable ASTTrf instance Show ASTTrf where show (ASTTrf_Optim scs) = "Optim" ++ show scs show (ASTTrf_Check ) = "Check" instance PP ASTTrf where pp (ASTTrf_Optim scs) = "Optim" >#< ppBracketsCommas scs pp trf = pp (show trf) {-# LINE 272 "src/ehc/EHC/ASTPipeline.chs" #-} -- | Description of transformation data ASTPipeHowChoice = ASTPipeHowChoice_Avail -- ^ First available | ASTPipeHowChoice_Overr -- ^ First available, but with priority to commandline specified (i.e. overridden) | ASTPipeHowChoice_Newer -- ^ First newest available, based on timestamps and imports; this triggers recompilation based on module import dependencies deriving (Eq, Ord, Typeable, Generic, Enum, Bounded) instance Hashable ASTPipeHowChoice instance DataAndConName ASTPipeHowChoice instance Show ASTPipeHowChoice where show = showUnprefixed 1 instance PP ASTPipeHowChoice where pp = pp . show {-# LINE 290 "src/ehc/EHC/ASTPipeline.chs" #-} -- | Description of build pipelines data ASTPipe where --- | From source file. 20150904: astpTiming is ignored, derived from astpUse ASTPipe_Src :: { astpUse :: ASTFileUse, astpTiming :: ASTFileTiming, astpType :: ASTType } -> ASTPipe --- | Derived from (a different ast type) ASTPipe_Derived :: { astpType :: ASTType, astpPipe :: ASTPipe } -> ASTPipe --- | Linked/combined as a library ASTPipe_Library :: { astpType :: ASTType, astpPipe :: ASTPipe } -> ASTPipe --- | Transformation on same AST ASTPipe_Trf :: { astpType :: ASTType, astpTrf :: ASTTrf, astpPipe :: ASTPipe } -> ASTPipe --- | Aggregrate of various different AST ASTPipe_Compound :: { astpType :: ASTType, astpPipes :: [ASTPipe] } -> ASTPipe --- | No pipe ASTPipe_Empty :: ASTPipe --- | From previously cached on file -- ASTPipe_Cached :: { astpType :: ASTType } -> ASTPipe --- | Side effect inverse of ASTPipe_Cached, i.e. write/cache on file ASTPipe_Cache :: { astpType :: ASTType, astpPipe :: ASTPipe } -> ASTPipe --- | Choose between first available, left biased, left one is src/cached, right one may be more complex/derived ASTPipe_Choose :: { astpHow :: ASTPipeHowChoice, astpType :: ASTType, astpPipe1 :: ASTPipe, astpPipe2 :: ASTPipe } -> ASTPipe --- | Whole program linked ASTPipe_Whole :: { astpType :: ASTType, astpPipe :: ASTPipe } -> ASTPipe deriving (Eq, Ord, Typeable, Generic) emptyASTPipe :: ASTPipe emptyASTPipe = ASTPipe_Empty instance Hashable ASTPipe instance Show ASTPipe where show p = case p of ASTPipe_Src u tm t -> "Sr(" ++ show u ++ "," ++ show tm ++ "," ++ show t ++ ")." ASTPipe_Derived t p' -> "Dr-" ++ show p' ASTPipe_Library t p' -> "Lb-" ++ show p' ASTPipe_Trf t tr p' -> "Tr(" ++ show tr ++ ")-" ++ show p' ASTPipe_Compound t ps -> "Cm(" ++ show t ++ ")" ++ show ps ASTPipe_Empty -> "" -- ASTPipe_Cached t -> "Cd(" ++ show t ++ ")." ASTPipe_Cache t p' -> "Ch-" ++ show p' ASTPipe_Choose h t p1 p2 -> "{(" ++ show h ++ ")1:" ++ show p1 ++ ",2:" ++ show p2 ++ "}" ASTPipe_Whole t p' -> "Wh-" ++ show p' instance PP ASTPipe where pp p = case p of ASTPipe_Src u tm t -> "Src" >#< u >#< tm >#< t ASTPipe_Derived t p' -> "Deriv" >#< t >-< indent 2 p' ASTPipe_Library t p' -> "Lib" >#< t >-< indent 2 p' ASTPipe_Trf t tr p' -> "Trf" >#< t >#< tr >-< indent 2 p' ASTPipe_Compound t ps -> "All" >#< t >-< indent 2 (ppCurlysCommasBlock ps) ASTPipe_Empty -> pp "Emp" -- ASTPipe_Cached t -> "Cached" >#< t ASTPipe_Cache t p' -> "Cache" >#< t >-< indent 2 p' ASTPipe_Choose h t p1 p2 -> "Choose" >#< h >#< t >-< indent 2 (p1 >-< p2) ASTPipe_Whole t p' -> "Whole" >#< t >-< indent 2 p' {-# LINE 366 "src/ehc/EHC/ASTPipeline.chs" #-} -- | Fix of possible choices in an ASTPipe (based on time info) data TmChoice = Choice_End -- ^ base case | Choice_Src ASTAvailableFile -- ^ base case: src file | Choice_No TmChoice -- ^ no choice made | Choices [TmChoice] -- ^ compound | Choice_L TmChoice -- ^ fst (of ASTPipe_Choose) | Choice_R TmChoice -- ^ snd (of ASTPipe_Choose) deriving (Eq, Ord, Typeable, Generic) instance Hashable TmChoice instance Show TmChoice where show (Choice_End ) = "." show (Choice_Src s) = "S" ++ show s show (Choice_No c) = "-" ++ show c show (Choices cs) = show cs show (Choice_L c) = "L" ++ show c show (Choice_R c) = "R" ++ show c instance PP TmChoice where pp = pp . show {-# LINE 399 "src/ehc/EHC/ASTPipeline.chs" #-} data ASTBuildPlan = ASTBuildPlan { _astbplPipe :: ASTPipe -- ^ the pipe and its choices , _astbplChoice :: TmChoice -- ^ the choices made based on time info } deriving (Eq, Ord, Typeable, Generic) instance Hashable ASTBuildPlan instance Show ASTBuildPlan where show (ASTBuildPlan p c) = "Plan [" ++ show c ++ ", " ++ show p ++ "]" instance PP ASTBuildPlan where pp (ASTBuildPlan p c) = "Plan" >#< (c >-< p) {-# LINE 416 "src/ehc/EHC/ASTPipeline.chs" #-} mkBuildPlan :: ASTPipe -> TmChoice -> ASTBuildPlan mkBuildPlan = ASTBuildPlan {-# LINE 421 "src/ehc/EHC/ASTPipeline.chs" #-} -- | Extract a subplan (i.e. from which is derived), if any astplMbSubPlan :: ASTBuildPlan -> Maybe ASTBuildPlan astplMbSubPlan pl = case pl of ASTBuildPlan (ASTPipe_Derived {astpPipe =p'}) (Choice_No c') -> Just $ mkBuildPlan p' c' ASTBuildPlan (ASTPipe_Trf {astpPipe =p'}) (Choice_No c') -> Just $ mkBuildPlan p' c' ASTBuildPlan (ASTPipe_Choose {astpPipe1=p'}) (Choice_L c') -> Just $ mkBuildPlan p' c' ASTBuildPlan (ASTPipe_Choose {astpPipe2=p'}) (Choice_R c') -> Just $ mkBuildPlan p' c' ASTBuildPlan (ASTPipe_Cache {astpPipe =p'}) (Choice_No c') -> Just $ mkBuildPlan p' c' ASTBuildPlan (ASTPipe_Whole {astpPipe =p'}) (Choice_No c') -> Just $ mkBuildPlan p' c' _ -> Nothing {-# LINE 438 "src/ehc/EHC/ASTPipeline.chs" #-} -- | Find occurrence of predicate, yielding a new plan corresponding to the predicate, and astplFind :: (ASTPipe -> Maybe x) -> ASTBuildPlan -> Maybe (ASTBuildPlan, x) astplFind pred = fnd where fnd pl@(ASTBuildPlan p c) = case pred p of Just res -> Just (pl, res) _ -> astplMbSubPlan pl >>= fnd {-# LINE 452 "src/ehc/EHC/ASTPipeline.chs" #-} -- | Construct a (dummy) pipe for which `astpTypes` will yield the given ASTTypes mkASTPipeForASTTypes :: [ASTType] -> ASTPipe mkASTPipeForASTTypes ts@(t:_) = ASTPipe_Compound t $ map (flip ASTPipe_Compound []) ts {-# LINE 458 "src/ehc/EHC/ASTPipeline.chs" #-} -- | Fold over ASTPipe astpFold :: (ASTPipe -> x) -> (x -> x -> x) -> x -> ASTPipe -> x astpFold getx cmbx dfltx p = extr p where extr ASTPipe_Empty = dfltx extr p = foldr1 cmbx $ getx p : (map extr $ subs p) subs (ASTPipe_Derived {astpPipe =p }) = [p] subs (ASTPipe_Library {astpPipe =p }) = [p] subs (ASTPipe_Trf {astpPipe =p }) = [p] subs (ASTPipe_Compound{astpPipes=ps}) = ps subs (ASTPipe_Cache {astpPipe =p }) = [p] subs (ASTPipe_Whole {astpPipe =p }) = [p] subs (ASTPipe_Choose {astpPipe1=p1, astpPipe2=p2}) = [p1, p2] subs _ = [] -- | Fold monoidal over ASTPipe astpFoldMonoid :: Monoid x => (ASTPipe -> x) -> ASTPipe -> x astpFoldMonoid getx p = astpFold getx mappend mempty p {-# LINE 482 "src/ehc/EHC/ASTPipeline.chs" #-} -- | Extract all ASTTypes. astpTypes :: ASTPipe -> Set.Set ASTType astpTypes = astpFoldMonoid (Set.singleton . astpType) {-# LINE 488 "src/ehc/EHC/ASTPipeline.chs" #-} -- | Find occurrence of predicate astpFind :: (ASTPipe -> Maybe ASTPipe) -> ASTPipe -> Maybe ASTPipe astpFind pred = astpFold pred (>>) Nothing {-# LINE 498 "src/ehc/EHC/ASTPipeline.chs" #-} data ASTPipeBldCfg = ASTPipeBldCfg { apbcfgTarget :: Target , apbcfgOptimScope :: OptimizationScope , apbcfgLinkingStyle :: LinkingStyle , apbcfgRunOnly :: Bool , apbcfgLoadOnly :: Bool } emptyASTPipeBldCfg = ASTPipeBldCfg defaultTarget OptimizationScope_PerModule LinkingStyle_Exec False False {-# LINE 523 "src/ehc/EHC/ASTPipeline.chs" #-} astpipe_HS_src = ASTPipe_Src ASTFileUse_Src ASTFileTiming_Current ASTType_HS astpipe_EH_from_HS = ASTPipe_Derived ASTType_EH astpipe_HS_src astpipe_EH = astpipe_EH_from_HS {-# LINE 531 "src/ehc/EHC/ASTPipeline.chs" #-} astpipe_Core_from_EH :: ASTPipeBldCfg -> ASTPipe astpipe_Core_from_EH apbcfg = ASTPipe_Cache ASTType_Core $ optim $ ASTPipe_Derived ASTType_Core astpipe_EH where optim --- | apbcfgOptimScope apbcfg == OptimizationScope_WholeCore = id | otherwise = ASTPipe_Trf ASTType_Core $ ASTTrf_Optim [ASTScope_Single] {-# LINE 547 "src/ehc/EHC/ASTPipeline.chs" #-} astpipe_Core_src :: ASTPipe astpipe_Core_src = ASTPipe_Src ASTFileUse_Src ASTFileTiming_Current ASTType_Core {-# LINE 552 "src/ehc/EHC/ASTPipeline.chs" #-} astpipe_Core_cached :: ASTPipe astpipe_Core_cached = ASTPipe_Src ASTFileUse_Cache ASTFileTiming_Prev ASTType_Core {-# LINE 557 "src/ehc/EHC/ASTPipeline.chs" #-} astpipe_Core :: ASTPipeBldCfg -> ASTPipe astpipe_Core apbcfg = apbcfgLoadChoice apbcfg ASTType_Core astpipe_Core_src $ ( if apbcfgLoadOnly apbcfg then astpipe_Core_cached else whole $ ASTPipe_Choose ASTPipeHowChoice_Newer ASTType_Core (ASTPipe_Compound ASTType_Core [astpipe_HI_cached, astpipe_Core_cached]) $ astpipe_Core_from_EH apbcfg ) where whole | apbcfgOptimScope apbcfg == OptimizationScope_WholeCore && not (apbcfgLoadOnly apbcfg) = (ASTPipe_Trf ASTType_Core $ ASTTrf_Optim [ASTScope_Whole]) . ASTPipe_Whole ASTType_Core | otherwise = id cached | apbcfgLoadOnly apbcfg = ASTPipe_Choose ASTPipeHowChoice_Newer ASTType_Core astpipe_Core_cached | otherwise = ASTPipe_Choose ASTPipeHowChoice_Newer ASTType_Core (ASTPipe_Compound ASTType_Core [astpipe_HI_cached, astpipe_Core_cached]) {-# LINE 598 "src/ehc/EHC/ASTPipeline.chs" #-} astpipe_CoreRun_src :: ASTPipe astpipe_CoreRun_src = ASTPipe_Trf ASTType_CoreRun ASTTrf_Check $ ASTPipe_Src ASTFileUse_Src ASTFileTiming_Current ASTType_CoreRun {-# LINE 607 "src/ehc/EHC/ASTPipeline.chs" #-} astpipe_CoreRun_cached :: ASTPipe astpipe_CoreRun_cached = ASTPipe_Trf ASTType_CoreRun ASTTrf_Check $ ASTPipe_Src ASTFileUse_Cache ASTFileTiming_Prev ASTType_CoreRun {-# LINE 616 "src/ehc/EHC/ASTPipeline.chs" #-} astpipe_CoreRun_from_Core :: ASTPipeBldCfg -> ASTPipe astpipe_CoreRun_from_Core apbcfg = ASTPipe_Derived ASTType_CoreRun $ astpipe_Core apbcfg {-# LINE 622 "src/ehc/EHC/ASTPipeline.chs" #-} astpipe_CoreRun :: ASTPipeBldCfg -> ASTPipe astpipe_CoreRun apbcfg = apbcfgLoadChoice apbcfg ASTType_CoreRun astpipe_CoreRun_src $ apbcfgLoadChoice apbcfg ASTType_CoreRun astpipe_CoreRun_cached $ astpipe_CoreRun_from_Core apbcfg {-# LINE 647 "src/ehc/EHC/ASTPipeline.chs" #-} astpipe_HI_cached :: ASTPipe astpipe_HI_cached = ASTPipe_Src ASTFileUse_Cache ASTFileTiming_Prev ASTType_HI astpipe_HI :: ASTPipeBldCfg -> ASTPipe astpipe_HI apbcfg = ASTPipe_Choose ASTPipeHowChoice_Newer ASTType_HI astpipe_HI_cached $ ASTPipe_Cache ASTType_HI $ ASTPipe_Derived ASTType_HI $ ASTPipe_Compound ASTType_HI $ [astpipe_HS_src, astpipe_EH] ++ [astpipe_Core_from_EH apbcfg] {-# LINE 689 "src/ehc/EHC/ASTPipeline.chs" #-} astpipe_C_src :: ASTPipe astpipe_C_src = ASTPipe_Src ASTFileUse_Src ASTFileTiming_Current ASTType_C {-# LINE 732 "src/ehc/EHC/ASTPipeline.chs" #-} apbcfgLoadChoice :: ASTPipeBldCfg -> ASTType -> ASTPipe -> ASTPipe -> ASTPipe apbcfgLoadChoice apbcfg -- t p1 p2 | apbcfgLoadOnly apbcfg = ASTPipe_Choose ASTPipeHowChoice_Overr | otherwise = ASTPipe_Choose ASTPipeHowChoice_Newer {-# LINE 745 "src/ehc/EHC/ASTPipeline.chs" #-} -- | Construct a ASTPipe from build config astpipeForCfg :: ASTPipeBldCfg -> ASTPipe astpipeForCfg apbcfg = if onlyrun then cmb base else cmb $ base ++ [astpipe_HI $ apbcfg {apbcfgOptimScope = OptimizationScope_PerModule}] where (base, topty) = case apbcfgTarget apbcfg of Target_None_Core_AsIs --- | onlyrun -> ([astpipe_Core_src], ASTType_Core) | onlyrun -> ([astpipe_CoreRun apbcfg], ASTType_CoreRun) | otherwise -> ([astpipe_Core apbcfg], ASTType_Core) Target_None_Core_CoreRun -> ([astpipe_CoreRun apbcfg], ASTType_CoreRun) _ -> ([astpipe_EH], ASTType_EH) cmb [p] = p cmb ps = ASTPipe_Compound topty ps -- 20150806: hackish solution for running core, done to be able to try out new build framework onlyrun = apbcfgRunOnly apbcfg {-# LINE 795 "src/ehc/EHC/ASTPipeline.chs" #-} -- | Construct a ASTPipe from compilers options, see `astpipeForCfg` astpipeForEHCOpts :: EHCOpts -> ASTPipe astpipeForEHCOpts opts = astpipeForCfg $ emptyASTPipeBldCfg { apbcfgTarget = ehcOptTarget opts , apbcfgOptimScope = ehcOptOptimizationScope opts , apbcfgLinkingStyle = ehcOptLinkingStyle opts , apbcfgRunOnly = CoreOpt_Run `elem` ehcOptCoreOpts opts , apbcfgLoadOnly = CoreOpt_LoadOnly `elem` ehcOptCoreOpts opts }