Skip to content

Commit

Permalink
feat: command line interface options
Browse files Browse the repository at this point in the history
  • Loading branch information
Jabolol committed Dec 8, 2024
1 parent f68f185 commit 72e1b2d
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 33 deletions.
119 changes: 87 additions & 32 deletions app/Main.hs
Original file line number Diff line number Diff line change
@@ -1,39 +1,94 @@
{-# LANGUAGE NamedFieldPuns #-}

module Main where

import qualified Ast.Types as T
import qualified Ast.Parser as P
import qualified Codegen.Codegen as C
import qualified Control.Monad as M
import qualified Control.Monad.Trans.Except as E
import qualified Data.Text.Lazy as TL
import qualified LLVM.Pretty as P
import qualified LLVM.Pretty as LLVM
import qualified Options.Applicative as O
import qualified System.Exit as EX
import qualified System.IO as S

data CompileError
= ParseError String
| CodegenError String
deriving (Show)

data Options = Options
{ input :: Maybe FilePath,
out :: FilePath,
verbose :: Bool
}

optionsParser :: O.Parser Options
optionsParser =
Options
<$> O.optional
( O.strOption
( O.long "input"
<> O.short 'i'
<> O.metavar "FILENAME"
<> O.help "Input file to read from (defaults to STDIN)"
)
)
<*> O.strOption
( O.long "out"
<> O.metavar "FILENAME"
<> O.help "Output file for the generated LLVM IR"
<> O.value "demo/generated.ll"
)
<*> O.switch
( O.long "verbose"
<> O.short 'v'
<> O.help "Enable verbose logging"
)

optionsInfo :: O.ParserInfo Options
optionsInfo =
O.info
(O.helper <*> optionsParser)
( O.fullDesc
<> O.progDesc "A compiler that generates LLVM IR from a scheme-like language"
<> O.header "Scheme-to-LLVM Compiler"
)

compile :: String -> E.ExceptT CompileError IO String
compile input = do
ast <- case P.parse input of
Left err -> E.throwE $ ParseError (show err)
Right res -> return res

case C.codegen ast of
Left err -> E.throwE $ CodegenError (show err)
Right lmod -> return $ TL.unpack $ LLVM.ppllvm lmod

logMsg :: Bool -> String -> IO ()
logMsg verbose msg = M.when verbose $ S.hPutStrLn S.stderr ("[LOG] " ++ msg)

readInput :: Maybe FilePath -> IO String
readInput Nothing = getContents
readInput (Just filePath) = readFile filePath

handleError :: String -> String -> Bool -> IO a
handleError errType errMsg verbose = do
S.hPutStrLn S.stderr $ "Error: " ++ errMsg
logMsg verbose $ "Compilation failed during " ++ errType ++ "."
EX.exitWith $ EX.ExitFailure 84

main :: IO ()
main = do
let ast =
T.AST
[ T.Define "value" (T.Lit (T.LInt 21)),
T.Define
"$$generated"
( T.If
(T.Lit (T.LInt 1))
( T.Call
( T.Lambda
["x"]
( T.Seq
[ T.Define "example" (T.Lit (T.LInt 2)),
T.Op T.Mult (T.Var "x") (T.Var "example")
]
)
)
(T.Seq [T.Var "value"])
)
( T.Call
( T.Lambda ["y"] (T.Seq [T.Op T.Sub (T.Var "y") (T.Lit (T.LInt 1))])
)
(T.Seq [T.Lit (T.LInt 2)])
)
)
]

let output = case C.codegen ast of
Left err -> error (show err)
Right lmod -> TL.unpack $ P.ppllvm lmod
writeFile "demo/generated.ll" output
Options {input, out, verbose} <- O.execParser optionsInfo
source <- readInput input

logMsg verbose "Starting compilation..."
result <- E.runExceptT $ compile source

case result of
Left (ParseError err) -> handleError "parsing" err verbose
Left (CodegenError err) -> handleError "parsing" err verbose
Right llvm -> do
writeFile out llvm
logMsg verbose $ "Compilation successful! Output written to: " ++ out
3 changes: 2 additions & 1 deletion glados.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ library
base ^>=4.17.2.1,
bytestring >=0.11.2 && <0.12,
containers >=0.6.7 && <0.7,
llvm-hs-pretty >=0.9.0 && <0.10,
llvm-hs-pure >=9.0.0 && <9.1,
megaparsec >=9.7.0,
mtl >=2.2.2 && <2.3,
Expand All @@ -46,7 +45,9 @@ executable glados
base ^>=4.17.2.1,
glados,
llvm-hs-pretty >=0.9.0 && <0.10,
optparse-applicative >=0.18.1 && <0.19,
text,
transformers >=0.5.6 && <0.6,

hs-source-dirs: app
default-language: Haskell2010
Expand Down

0 comments on commit 72e1b2d

Please # to comment.