-----------------------------------------------------------------------------
-- |
-- Module      :  Language.C
-- Copyright   :  (c) 2008 Benedikt Huber
--                [1995..2007]
--                   Manuel M. T. Chakravarty
--                   Duncan Coutts
--                   Betram Felgenhauer
-- License     :  BSD-style
-- Maintainer  : benedikt.huber@gmail.com
-- Stability   : experimental
-- Portability : ghc
--
-- Library for analysing and generating C code.
--
-- See <http://www.sivity.net/projects/language.c>
-----------------------------------------------------------------------------
module Language.C (
    parseCFile, parseCFilePre, -- maybe change ?
    module Language.C.Data,
    module Language.C.Syntax,
    module Language.C.Pretty,
    module Language.C.Parser,
)
where
import Language.C.Data
import Language.C.Syntax
import Language.C.Pretty
import Language.C.Parser
import Language.C.System.Preprocess

-- | preprocess (if necessary) and parse a C source file
--
--   > Synopsis: parseCFile preprocesssor tmp-dir? cpp-opts file
--   > Example:  parseCFile (newGCC "gcc") Nothing ["-I/usr/include/gtk-2.0"] my-gtk-exts.c
parseCFile :: (Preprocessor cpp) => cpp -> Maybe FilePath -> [String] -> FilePath -> IO (Either ParseError CTranslUnit)
parseCFile :: cpp
-> Maybe FilePath
-> [FilePath]
-> FilePath
-> IO (Either ParseError CTranslUnit)
parseCFile cpp :: cpp
cpp tmp_dir_opt :: Maybe FilePath
tmp_dir_opt args :: [FilePath]
args input_file :: FilePath
input_file = do
    InputStream
input_stream <- if Bool -> Bool
not (FilePath -> Bool
isPreprocessed FilePath
input_file)
                        then  let cpp_args :: CppArgs
cpp_args = ([FilePath] -> FilePath -> CppArgs
rawCppArgs [FilePath]
args FilePath
input_file) { cppTmpDir :: Maybe FilePath
cppTmpDir = Maybe FilePath
tmp_dir_opt }
                              in  cpp -> CppArgs -> IO (Either ExitCode InputStream)
forall cpp.
Preprocessor cpp =>
cpp -> CppArgs -> IO (Either ExitCode InputStream)
runPreprocessor cpp
cpp CppArgs
cpp_args IO (Either ExitCode InputStream)
-> (Either ExitCode InputStream -> IO InputStream)
-> IO InputStream
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Either ExitCode InputStream -> IO InputStream
forall (m :: * -> *) a a.
(MonadFail m, Show a) =>
Either a a -> m a
handleCppError
                        else  FilePath -> IO InputStream
readInputStream FilePath
input_file
    Either ParseError CTranslUnit -> IO (Either ParseError CTranslUnit)
forall (m :: * -> *) a. Monad m => a -> m a
return(Either ParseError CTranslUnit
 -> IO (Either ParseError CTranslUnit))
-> Either ParseError CTranslUnit
-> IO (Either ParseError CTranslUnit)
forall a b. (a -> b) -> a -> b
$ InputStream -> Position -> Either ParseError CTranslUnit
parseC InputStream
input_stream (FilePath -> Position
initPos FilePath
input_file)
    where
    handleCppError :: Either a a -> m a
handleCppError (Left exitCode :: a
exitCode) = FilePath -> m a
forall (m :: * -> *) a. MonadFail m => FilePath -> m a
fail (FilePath -> m a) -> FilePath -> m a
forall a b. (a -> b) -> a -> b
$ "Preprocessor failed with " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ a -> FilePath
forall a. Show a => a -> FilePath
show a
exitCode
    handleCppError (Right ok :: a
ok)      = a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
ok

-- | parse an already preprocessed C file
--
--   > Synopsis: parseCFilePre file.i
parseCFilePre :: FilePath -> IO (Either ParseError CTranslUnit)
parseCFilePre :: FilePath -> IO (Either ParseError CTranslUnit)
parseCFilePre file :: FilePath
file = do
    InputStream
input_stream <- FilePath -> IO InputStream
readInputStream FilePath
file
    Either ParseError CTranslUnit -> IO (Either ParseError CTranslUnit)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either ParseError CTranslUnit
 -> IO (Either ParseError CTranslUnit))
-> Either ParseError CTranslUnit
-> IO (Either ParseError CTranslUnit)
forall a b. (a -> b) -> a -> b
$ InputStream -> Position -> Either ParseError CTranslUnit
parseC InputStream
input_stream (FilePath -> Position
initPos FilePath
file)