berp-0.0.1: src/Berp/Main.hs
-----------------------------------------------------------------------------
-- |
-- Module : Main
-- Copyright : (c) 2010 Bernie Pope
-- License : BSD-style
-- Maintainer : florbitous@gmail.com
-- Stability : experimental
-- Portability : ghc
--
-- The Main module of Berp. Both the compiler and the interactive interpreter
-- are started from here.
--
-----------------------------------------------------------------------------
module Main where
import Language.Python.Version3.Parser (parseModule)
import Language.Python.Common.AST (ModuleSpan)
import Data.Maybe (maybe)
import Control.Monad (when)
import Control.Applicative ((<$>))
import Language.Haskell.Exts.Pretty
import Berp.Compile.Compile (compiler)
import System.Console.ParseArgs
(Argtype (..), argDataOptional, argDataDefaulted, Arg (..)
, gotArg, getArg, parseArgsIO, ArgsComplete (..), Args(..))
import System.Cmd (system)
import System.Exit (ExitCode (..), exitWith)
import System.FilePath ((</>), (<.>), takeBaseName)
import System.Directory (removeFile)
import Berp.Interpreter.Repl (repl)
main :: IO ()
main = do
let args = [withGHC, help, clobber, clean, showHaskell, compile, inputFile]
argMap <- parseArgsIO ArgsComplete args
giveHelp argMap
maybeInputDetails <- getInputDetails argMap
case maybeInputDetails of
Nothing -> repl
Just (sourceName, fileContents) ->
compileAndExecute argMap sourceName fileContents
compileAndExecute :: Args ArgIndex -> FilePath -> String -> IO ()
compileAndExecute argMap sourceName fileContents = do
pyModule <- parseAndCheckErrors fileContents sourceName
haskellSrc <- prettyPrint <$> compiler pyModule
when (gotArg argMap ShowHaskell) $ do
putStrLn haskellSrc
exitWith ExitSuccess
let outputName = takeBaseName sourceName
haskellFilename = outputName <.> "hs"
interfaceFilename = outputName <.> "hi"
objectFilename = outputName <.> "o"
exeFilename = "." </> outputName
writeFile haskellFilename (haskellSrc ++ "\n")
exitCodeCompile <- system $ ghcCommand argMap "-O2" "-v0" haskellFilename
when (gotArg argMap Compile) $ exitWith ExitSuccess
case exitCodeCompile of
ExitFailure {} -> exitWith exitCodeCompile
ExitSuccess -> do
exeStatus <- system exeFilename
let tempFiles = [haskellFilename, interfaceFilename, objectFilename]
when (gotArg argMap Clean) $ do
mapM_ removeFile tempFiles
when (gotArg argMap Clobber) $ do
mapM_ removeFile (exeFilename : tempFiles)
exitWith exeStatus
parseAndCheckErrors :: String -> FilePath -> IO ModuleSpan
parseAndCheckErrors fileContents sourceName =
case parseModule fileContents sourceName of
Left e -> error $ show e
Right (pyModule, _comments) -> return pyModule
getInputDetails :: Args ArgIndex -> IO (Maybe (FilePath, String))
getInputDetails argMap =
case getArg argMap InputFile of
Nothing -> return Nothing
Just inputFileName -> do
cs <- readFile inputFileName
return $ Just (inputFileName, cs)
giveHelp :: Args ArgIndex -> IO ()
giveHelp argMap =
if gotArg argMap Help
then error $ argsUsage argMap
else return ()
ghcCommand :: Args ArgIndex -> String -> String -> String -> String
ghcCommand argMap optimise verbosity inputFile =
unwords [ghcName, "--make", optimise, verbosity, inputFile]
where
ghcName = maybe "ghc" id (getArg argMap WithGHC)
data ArgIndex
= Help
| ShowHaskell
| InputFile
| Compile
| Clobber
| Clean
| WithGHC
deriving (Eq, Ord, Show)
help :: Arg ArgIndex
help =
Arg
{ argIndex = Help
, argAbbr = Just 'h'
, argName = Just "help"
, argData = Nothing
, argDesc = "Display a help message."
}
showHaskell :: Arg ArgIndex
showHaskell =
Arg
{ argIndex = ShowHaskell
, argAbbr = Just 't'
, argName = Just "showhaskell"
, argData = Nothing
, argDesc = "Output translated Haskell code on standard output and exit."
}
inputFile :: Arg ArgIndex
inputFile =
Arg
{ argIndex = InputFile
, argAbbr = Nothing
, argName = Nothing
, argData = argDataOptional "input file" ArgtypeString
, argDesc = "Name of the input Python file."
}
compile :: Arg ArgIndex
compile =
Arg
{ argIndex = Compile
, argAbbr = Just 'c'
, argName = Just "compile"
, argData = Nothing
, argDesc = "Compile the input program, but do not run it."
}
clobber :: Arg ArgIndex
clobber =
Arg
{ argIndex = Clobber
, argAbbr = Nothing
, argName = Just "clobber"
, argData = Nothing
, argDesc = "Remove all compiler generated files after the compiled program has run."
}
clean :: Arg ArgIndex
clean =
Arg
{ argIndex = Clean
, argAbbr = Nothing
, argName = Just "clean"
, argData = Nothing
, argDesc = "Remove all compiler generated files except the executable after the compiled program has run."
}
withGHC :: Arg ArgIndex
withGHC =
Arg
{ argIndex = WithGHC
, argAbbr = Nothing
, argName = Just "with-ghc"
, argData = argDataDefaulted "filepath to ghc" ArgtypeString "ghc"
, argDesc = "Specify the filepath of ghc."
}