> {-# OPTIONS_GHC -fglasgow-exts #-} > -- | > -- Module : Ivor.Plugin > -- Copyright : Edwin Brady > -- Licence : BSD-style (see LICENSE in the distribution) > -- > -- Maintainer : eb@dcs.st-and.ac.uk > -- Stability : experimental > -- Portability : portable > -- > -- Plugin loader > module Ivor.Plugin(Ivor.Plugin.load) where > import Ivor.TT > import Ivor.ShellState > import System.Plugins as Plugins > import Text.ParserCombinators.Parsec > -- | Load the given plugin file (which should be a full path to a .o or > -- .hs file) and update the Context. If it is a .hs file, it will be > -- compiled if necessary. > -- Plugins must contain the symbol > -- @plugin_context :: Monad m => Context -> m Context@ > -- which updates the context. It may optionally contain symbols > -- @plugin_parser :: Parser ViewTerm@ > -- which adds new parsing rules, > -- @plugin_shell :: ShellState -> IO ShellState@ > -- which updates the shell > -- @plugin_commands :: IO [(String, String -> COntext -> IO (String, Context))]@ > -- which adds new user defined commands (which may need to do some setting up themselves, hence the IO) > -- Returns the new context and the extra parsing rules and commands, if any. > load :: FilePath -> Context -> IO (Context, > Maybe (Parser ViewTerm), > Maybe (ShellState -> IO ShellState), > Maybe (IO [(String, String -> Context -> IO (String, Context))])) > load fn ctxt = do > objIn <- compilePlugin fn > obj <- case objIn of > Left errs -> fail errs > Right ok -> return ok > contextMod <- Plugins.load_ obj [] "plugin_context" > -- mv <- Plugins.load fn [] ["/Users/edwin/.ghc/i386-darwin-6.6.1/package.conf"] "initialise" > (mod, contextFn) <- case contextMod of > LoadFailure msg -> fail $ "Plugin loading failed: " ++ > show msg > LoadSuccess mod v -> return (mod, v) > parserMod <- Plugins.reload mod "plugin_parser" > parserules <- case parserMod of > LoadFailure msg -> return Nothing > LoadSuccess _ v -> return $ Just v > cmdMod <- Plugins.reload mod "plugin_commands" > cmds <- case cmdMod of > LoadFailure msg -> return Nothing > LoadSuccess _ v -> return $ Just v > shellMod <- Plugins.reload mod "plugin_shell" > shellfn <- case shellMod of > LoadFailure msg -> return Nothing > LoadSuccess _ v -> return $ Just v > ctxt' <- case contextFn ctxt of > Just x -> return x > Nothing -> fail "Error in running plugin_context" > return $ (ctxt', parserules, shellfn, cmds) Make a .o from a .hs, so that we can load Haskell source as well as object files > compilePlugin :: FilePath -> IO (Either String FilePath) > compilePlugin hs > | isExt ".hs" hs || isExt ".lhs" hs = > do status <- makeAll hs [] > case status of > MakeSuccess c out -> return $ Right out > MakeFailure errs -> return $ Left (concat (map (++"\n") errs)) > | isExt ".o" hs = return $ Right hs > | elem '.' hs = return (Left $ "unrecognised file type " ++ hs) > | otherwise = compilePlugin (hs++".o") > where isExt ext fn = case span (/='.') fn of > (file, e) -> ext == e