Changes between Version 1 and Version 2 of Ghc/Hooks


Ignore:
Timestamp:
Sep 4, 2013 10:08:17 PM (8 months ago)
Author:
nominolo
Comment:

Add example code and implementation sketch

Legend:

Unmodified
Added
Removed
Modified
  • Ghc/Hooks

    v1 v2  
    1313Instead we identify "interesting" places inside the compiler and allow users of the GHC API to specify a call-back that gets invoked when execution reaches that place.  For example, instead of calling {{{typecheckRename}}} function directly, we first look up whether there is a hook specified for and if so call that function instead.  The hook may choose to perform its own renaming and type checking passes (unlikely) or call the GHC's {{{typecheckRename}}} function and inspect its output and generate additional files on disk. 
    1414 
     15== Example == 
     16 
     17{{{ 
     18... 
     19  withGhc libdir $ do 
     20    dflags0 <- getSessionDynFlags 
     21    let dflags1 = dflags0{ hooks = insertHook LocateLibHook myLocateLib 
     22                                 . insertHook LinkDynLibHook myLinkDynLibHook 
     23                                 $ hooks dflags0 } 
     24    setSessionDynFlags dflags1 
     25... 
     26 
     27myLocateLib :: DynFlags -> Bool -> [FilePath] -> String -> IO LibrarySpec 
     28myLocateLib ... 
     29 
     30myLinkDynLibHook :: DynFlags -> [FilePath] -> [PackageId] -> IO () 
     31myLinkDynLibHook dflags paths ids = do  
     32 
     33}}}                                                .  
     34 
     35The two functions will be called whenever GHC needs to locate or link a dynamically loaded library. 
     36 
    1537== The Hook datatype == 
    1638 
    1739Each hook has a potentially different type from all the other hooks. Additionally, we need to be able to communicate hooks to all the locations where they may be invoked. This is achieved by storing the list of hooks in the {{{DynFlags}}}.  This, however, means that hooks cannot be defined as an ADT, as that would lead to huge cyclic imports (the data types used by the hooks will depend on {{{DynFlags}}}, but the {{{DynFlags}}} will depend on the hook data type.  Instead we {{{Hooks}}} is an untyped key-value store.  The keys are single constructor types and the {{{Hooks}}} map is indexed by their {{{TypeRep}}}.  We recover the hook type via a type family: 
    1840 
     41{{{ 
     42--- Implementation Sketch ----------------------- 
     43data Hook = forall a. Hook TypeRep a 
     44 
     45type Hooks = Map TypeRep Hook 
     46 
     47type family HookType a :: * 
     48 
     49insertHook :: forall a. Typeable a => a -> HookType a -> Hooks -> Hooks 
     50insertHook key value hooks = 
     51  let hook = Hook (typeOf key) value in 
     52  Map.insert (typeOf key) hook hooks 
     53 
     54lookupHook :: forall a. Typeable a => Hooks -> Maybe (HookType a) 
     55lookupHook hooks = 
     56  let key = typeOf (undefined :: a) in 
     57  case Map.lookup key of 
     58     Nothing -> Nothing 
     59     Just (Hook _ h) -> Just (unsafeCoerce h :: HookType a)  -- the tricky bit 
     60}}} 
     61 
     62{{{ 
     63-- usage: 
     64data LocateLibHook = LocateLibHook deriving Typeable 
     65 
     66type instance HookType LocateLibHook = DynFlags -> Bool -> [FilePath] -> String -> IO LibrarySpec 
     67}}} 
     68 
     69== TODO: List all currently available hooks == 
     70