packages feed

ivor-0.1.5: Ivor/Plugin.lhs

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