lambdabot-4.0: scripts/BotPP.hs
{-# OPTIONS -O -funbox-strict-fields #-}
-- Copyright (c) 2006 Don Stewart - http://www.cse.unsw.edu.au/~dons
-- GPL version 2 or later (see http://www.gnu.org/copyleft/gpl.html)
--
-- Implements a preprocessor for plugins, filling in commonly required
-- syntax.
--
-- Currently only useful for plugins that only:
-- import Plugin
-- and have () for state.
--
-- Also used to generate the modules list in Modules.hs
--
import System.Environment
import Data.Char
import Data.List
import Data.ByteString.Char8 (pack, ByteString)
import qualified Data.ByteString.Char8 as B -- crank it up, yeah!
main = do
[_,i,o] <- getArgs
B.readFile i >>= \l -> B.writeFile o $ expand (B.length l) 0 l
--
-- tricksy non-copying implementation.
--
expand :: Int -> Int -> ByteString -> ByteString
expand l n xs
| n `seq` xs `seq` False = undefined -- strict
| l == n = xs -- not found
| pLUGIN `B.isPrefixOf` (B.drop n xs) = B.concat $ pref : render name ++ [B.tail rest]
| mODULES `B.isPrefixOf` (B.drop n xs) = B.concat $ pref : modules name' ++ [B.tail rest']
| otherwise = expand l (n+1) xs
where pref = B.take n xs -- accumulating an offset
pLUGIN = pack "PLUGIN "
(name, rest) = B.breakChar '\n' (B.drop (n+B.length pLUGIN) xs)
mODULES = pack "MODULES "
(name', rest') = B.breakChar '\n' (B.drop (n+B.length mODULES) xs)
--
-- render the plugin boiler plate
--
render :: ByteString -> [ByteString]
render name =
pack "newtype " : name :
pack "Module = " : name : pack "Module () \n\
\\n\
\theModule :: MODULE \n\
\theModule = MODULE $ " : name : pack "Module () \n" : []
--
-- Collect all the plugin names, and generate the Modules.hs file
--
modules :: ByteString -> [ByteString]
modules s =
[pack "module Modules where\n"
,pack "import Lambdabot\n"
,pack "\n"]
++ (concatMap importify ms) ++
[pack "loadStaticModules :: LB ()\n"
,pack "loadStaticModules = do\n"]
++ (concatMap instalify ms) ++
[pack "plugins :: [String]\n"
,pack "plugins = []\n"]
where ms = sort $ B.split ' ' s
importify x = [pack "import qualified Plugin.", x, B.singleton '\n']
instalify x = [pack " ircInstallModule Plugin.",x
,pack ".theModule \""
,B.map toLower x
, pack "\"\n"]