packages feed

rail-compiler-editor-0.2.0.0: src/RailCompiler/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 CodeOptimization    as CodeOpt
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 . CodeOpt.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 . CodeOpt.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 . CodeOpt.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."