content: --
  -- a simple shell for loading plugins and evaluating their functions
  -- 
  
  import System.Plugins
  import API
  
  import Data.Either
  import Data.Char
  import Control.Monad            ( when )
  import System.Console.Readline  ( readline )
  import System.Exit              ( ExitCode(..), exitWith )
  
  
  source = "Plugin.hs"
  stub   = "Plugin.stub"
  
  sym = "resource"
  
  main = do
          status <- makeWith source stub []
          p <- case status of
                  MakeFailure e -> mapM_ putStrLn e >> error "failed to compile"
                  MakeSuccess _ obj -> do
                          m_v <- load obj ["."] [] sym
                          case m_v of
                                  LoadSuccess m v -> return (m,v)
                                  LoadFailure e   -> do mapM_ putStrLn e
                                                        error "failed to load"
          shell p
  
      where
          shell p@(m,v) = do 
  
              s <- readline "> "
              cmd <- case s of 
                  Nothing   -> exitWith ExitSuccess
                  Just ":q" -> exitWith ExitSuccess
                  Just s    -> return (chomp s)
  
              status <- makeWith source stub []   
              case status of 
                  MakeFailure e -> do 
                      mapM_ putStrLn e
                      shell p     -- print error and back to prompt
  
                  MakeSuccess NotReq o ->  do
                      p' <- eval cmd p
                      shell p'    -- eval str again
  
                  MakeSuccess ReComp o -> do
                      m_v' <- reload m sym
                      case m_v' of
                          LoadFailure e    -> mapM_ putStrLn e >> error "failed to load"
                          LoadSuccess _ v' -> do
                                  let p' = (m,v')
                                  p'' <- eval cmd p'
                                  shell p''
  
  --
  -- shell commands
  --
  eval "" p = return p
  
  eval ":clear" p = do
          let loop i = when (i < 40) (do putStr "\n" ; loop $! i+1)
          loop 0
          return p
  
  eval ":?"  p     = do
          putStrLn$"\":?\"\n"       ++
                   "\":quit\"\n"    ++
                   "\":clear\"\n"   ++
                   "\"foo\""
          return p
  
  eval s (m,v) = putStrLn ((function v) s) >> return (m,v)
  
  --
  -- strip trailing whitespace
  --
  chomp :: String -> String
  chomp [] = []
  chomp s | isSpace (last s) = chomp $! init s
          | otherwise        = s
  