packages feed

rail-compiler-editor-0.3.0.0: src/RailCompiler-command/Main.hs

{- |
Module      : Main.hs
Description : .
Maintainer  : (c) Christopher Pockrandt, Nicolas Lehmann, Tobias Kranz
License     : MIT

Stability   : stable

Entrypoint of the rail2llvm-compiler. Contains main-function.

See also:
--https://www.haskell.org/ghc/docs/7.8.2/html/libraries/base-4.7.0.0/System-Console-GetOpt.html
--http://leiffrenzel.de/papers/commandline-options-in-haskell.html (Outdated!)

-}
module Main( main ) where

-- imports --
import System.Environment
import System.Exit
import System.Console.GetOpt
import Data.Maybe( fromMaybe )
import InterfaceDT                   as IDT
import qualified Preprocessor        as PreProc
import qualified Lexer
import qualified SyntacticalAnalysis as SynAna
import qualified SemanticalAnalysis  as SemAna
import qualified IntermediateCode    as InterCode
import qualified Backend

-- defining the option settings for the main-function
data Options = Options  {
    optInput     :: IO String,
    optOutput    :: String -> IO (),
    optASTOutput :: String -> IO (),
    compile      :: Bool,
    impAST       :: Bool,
    expAST       :: Bool
  }

-- default Options
defaultOptions :: Options
defaultOptions   = Options {
    optInput     = getContents,
    optOutput    = putStr,
    optASTOutput = putStr,
    compile      = False,
    impAST       = False,
    expAST       = False
    
  }

-- usageInfo
options :: [OptDescr (Options -> IO Options)]
options = [
    --Option ['V'] ["version"] (NoArg  showVersion)      "show version number",
    Option "h" ["help"     ] (NoArg  showHelp         ) "display Help Text",
    Option "i" ["input"    ] (ReqArg setInput  "FILE" ) "input file (don't set to use stdin')",
    Option "o" ["output"   ] (ReqArg setOutput "FILE" ) "output file (don't set to use stdout')",
    Option "c" ["compile"  ] (NoArg  setCompile       ) "compile 'rail' to 'llvm'",
    Option [ ] ["exportAST"] (OptArg setExpAST "FILE" ) "export frontend AST (don't offer a File to use stdout) \n(dont set with --importAST)",
    Option [ ] ["importAST"] (NoArg setImpAST         ) "import frontend AST and compile to llvm\nautosets -c \n(set input via -i; (dont set with --exportAST)\n\nset -c with --exportAST and get both: the AST and the llvm code"    
  ]

-- output for the help-function
showHelp _ = do
  putStrLn "rail2llvm--haskell-compiler (development version)"
  putStr "https://github.com/SWP-Ubau-SoSe2014-Haskell/SWPSoSe14\n\n"
  putStr $ usageInfo "Usage: main [OPTION...]" options  
  exitSuccess

-- options-getter for optional output for exprotAST
getOut (Just arg) = writeFile arg
getOut Nothing = putStr

-- options-setters
setInput  arg opt = return opt { optInput     = readFile arg }
setOutput arg opt = return opt { optOutput    = writeFile arg }
setExpAST arg opt = return opt { optASTOutput = getOut arg, expAST = True}
setImpAST     opt = return opt { impAST       = True, compile = True }
setCompile    opt = return opt { compile      = True }

-- main-function --
main = do args <- getArgs
          let (actions,nonOpts,msgs) = getOpt RequireOrder options args
          -- intercept errors
          if msgs /= []
          then error $ concat msgs ++ usageInfo "Usage: main [OPTION...]" options
          -- unrecognized arguments error
          else if nonOpts /= [] 
            then error $ "unrecognized arguments: " ++ unwords nonOpts ++ "\nUsage: For basic information, try the `--help' option."
            else do opts <- foldl (>>=) (return defaultOptions) actions
                    -- option aliases
                    let Options { optInput = input, optOutput = output,  optASTOutput = outputAST, compile = cmpl, impAST = imp, expAST = exp} = opts
                    inputWithoutIO <- input
                    -- importAST and exportAST can't be set together (error)
                    if imp && exp 
                    then do error "No export of the imported AST (Usage: For basic information, try the `--help' option.)'"
                            exitSuccess
                    -- compile a file
                    else if cmpl 
                         then do let transform (IBO x) = x
                                 -- compile an imported AST to a LLVM-file
                                 if imp
                                 then transform (Backend.process . InterCode.process . SemAna.process . SynAna.process . Lexer.toAST $ inputWithoutIO) >>= output
                                 -- compile a RAIL-file to an AST as an export-file
                                 else if exp
                                      then do outputAST (Lexer.fromAST . Lexer.process . PreProc.process $ IIP inputWithoutIO)
                                              transform (Backend.process . InterCode.process . SemAna.process . SynAna.process . Lexer.process . PreProc.process $ IIP inputWithoutIO) >>= output
                                      -- compile a RAIL-file to a LLVM-file
                                      else transform (Backend.process . InterCode.process . SemAna.process . SynAna.process . Lexer.process . PreProc.process $ IIP inputWithoutIO) >>= output
                         -- exportAST (without compiling it to llvm)
                         else if exp
                              then outputAST (Lexer.fromAST . Lexer.process . PreProc.process $ IIP inputWithoutIO)
                              -- missing argument error
                              else error "Error. Set atleast -c or --importAST or --exportAST."