packages feed

wxcore-0.10.1: wxdirect/src/CompileSTC.hs

module CompileSTC ( compileSTC ) where

import Text.ParserCombinators.Parsec
import qualified Text.ParserCombinators.Parsec.Token as P
import Text.ParserCombinators.Parsec.Language

import Data.Char
import Data.List
import Control.Monad

import Types

compileSTC :: Bool       -- ^ Verbose
           -> FilePath   -- ^ Outputdir
           -> [FilePath] -- ^ Input files (stc.h)
           -> IO ()
compileSTC verbose outputDir inputs = do
  dfs <- mapM parseH inputs
  let (ds,fs) = unzip dfs
      d = concat ds --currently unused
      f = concat fs
      h_target = outputDir ++ "include/stc_gen.h"
      cpp_target = outputDir ++ "src/stc_gen.cpp"
  putStrLn $ "generating: " ++ h_target
  writeFile h_target $ (glue "\n\n" $ map headerfunc f) ++ "\n"
  putStrLn $ "generating: " ++ cpp_target
  writeFile cpp_target $ (glue "\n" $ map cppfunc f) ++ "\n"
  when verbose $
       putStrLn $ "Wrote type macros and c wrappers for " ++ show (length f) ++ " functions."

parseH fname = do putStrLn ("parsing: " ++ fname)
		  input <- liftM lines $ readFile fname
		  let (defs, cpp) = partitionDefines $ input
		  case parse plines fname (unlines cpp) of
		    Left err -> print err >> return ([],[])
		    Right funcs -> return (defs,filter convertable funcs)

-- returns a list of defenitions, see Types.Def
-- and a new list of lines without #define's
partitionDefines :: [String] -> ([Def], [String])
partitionDefines lns = (defs, cpp)
    where (rdefs, cpp) = partition ("#define wxSTC_" `isPrefixOf`) lns
	  defs = map (toDef . (drop $ length "#define ")) rdefs
	  toDef x = let (name,value) = break (==' ') x
                    in Def name (read value) DefInt

plines = whiteSpace >> many1 pfunc

pfunc :: Parser (String, String, [(String, String)])
pfunc = do ret <- identifier
	   stars <- option "" $ symbol "*"
	   func <- identifier
	   args <- parens $ commaSep $ arg
	   symbol ";"
	   return (ret ++ stars,func,args)
    where arg = do option "" $ try $ symbol "const"
		   t <- identifier
		   stars <- option "" $ symbol "*"
		   option "" $ symbol "&"
		   name <- identifier
		   return (t ++ stars, name)

{-----------------------------------------------------------------------------------------
   The lexer
-----------------------------------------------------------------------------------------}

lexer :: P.TokenParser ()
lexer
  = P.makeTokenParser $ javaStyle

whiteSpace    = P.whiteSpace lexer
lexeme        = P.lexeme lexer
symbol        = P.symbol lexer
parens        = P.parens lexer
semi          = P.semi lexer
comma         = P.comma lexer
commaSep      = P.commaSep lexer
identifier    = P.identifier lexer
reserved      = P.reserved lexer


{-----------------------------------------------------------------------------------------
   code gen
-----------------------------------------------------------------------------------------}

convertable (t,f,a) = elem t ["int", "bool", "void"]

glue str strs = concat $ intersperse str strs

-- CPP function generator (Creates functions that can be exported as C functions)

cppfunc x = macro x ++ arguments x ++ "\n" ++ body x 

macro (ret, func, args) = "EWXWEXPORT(" ++ ret ++ ", wxStyledTextCtrl_" ++ func ++ ")"

arguments (ret, func, args) = "(" ++ glue ", " params ++ ")"
	where 
	params = "void* _obj" : rest
	rest = map transType args

	transType ("int",      n) = "int "   ++ n
	transType ("bool",     n) = "bool "  ++ n
	transType ("void",     n) = "void "  ++ n
	-- transType ("wxString", n) = "char* " ++ n
	transType ("wxString", n) = "wxChar* " ++ n
	transType ("wxPoint",  n) = glue ", " ["int " ++ n ++ p | p <- ["_x","_y"]]
	transType ("wxColour", n) = glue ", " ["int " ++ n ++ c | c <- ["_r","_g","_b"]]
	transType (_,          n) = "void* " ++ n
		
body (ret, func, args) = "{\n" ++ "#ifdef wxUSE_STC\n  "
                         ++ maybeReturn ++ " ((wxStyledTextCtrl*) _obj)->"
                         ++ func ++ "(" ++ glue ", " params ++ ");\n"
                         ++ maybeElse ++ "#endif\n}"
	where 
	maybeReturn = if ret == "void" then "" else "return"
	maybeElse = if ret == "void" then "" else "#else\n  return NULL;\n"
	params = map transParam args
	transParam ("int",       n) = n
	transParam ("bool",      n) = n
	transParam ("void",      n) = n
	transParam ("wxString",  n) = n
	transParam ("wxPoint",   n) = "wxPoint(" ++ n ++ "_x," ++ n ++ "_y)"
	transParam ("wxColour",  n) = "wxColour(" ++ n ++ "_r," ++ n ++ "_g," ++ n ++ "_b)"
	transParam ("wxSTCDoc*", n) = n
	transParam (t,           n) = "*(" ++ t ++ "*) " ++ n
      
-- Generator for functions signatures with type macros

headerfunc (ret, func, args) = returnType ret ++ " wxStyledTextCtrl_" ++ func 
                               ++ "(" ++ glue ", " params ++ ");"
	where
	
	returnType "bool"  = "TBool"
	returnType "int"   = "int"
	returnType "void"  = "void"
	returnType _       = error "wtf?"

	params = "TSelf(wxStyledTextCtrl) _obj" : rest
	rest = map transType args
	
	transType ("bool",     n) = "TBool "   ++ n
	transType ("int",      n) = "int "     ++ n
	transType ("int*",     n) = "int* "    ++ n
	transType ("void",     n) = "void "    ++ n
	transType ("char*",    n) = "TString " ++ n
	-- transType ("wchar_t*", n) = "TString " ++ n
	-- transType ("wxChar*",  n) = "TString " ++ n
	transType ("wxString", n) = "TString " ++ n
	transType ("wxPoint",  n) = "TPoint(" ++ n ++ "_x," ++ n ++ "_y)"
	transType ("wxColour", n) = "TColorRGB(" ++ n ++ "_r," ++ n ++ "_g," ++ n ++ "_b)"
	transType (t,          n) | "*" `isSuffixOf` t = "TClass(" ++ init t ++ ") " ++ n
                            | otherwise = "TClass(" ++ t ++ ") " ++ n