Refactor Main.hs in preparation of --inplace (see #40)

pull/51/head
Lennart Spitzner 2017-08-08 00:46:09 +02:00
parent 91b9a240f1
commit 69c50bebd3
1 changed files with 129 additions and 110 deletions

View File

@ -90,6 +90,7 @@ licenseDoc = PP.vcat $ List.intersperse
] ]
] ]
mainCmdParser :: CommandDesc () -> CmdParser Identity (IO ()) () mainCmdParser :: CommandDesc () -> CmdParser Identity (IO ()) ()
mainCmdParser helpDesc = do mainCmdParser helpDesc = do
addCmdSynopsis "haskell source pretty printer" addCmdSynopsis "haskell source pretty printer"
@ -116,10 +117,10 @@ mainCmdParser helpDesc = do
desc <- peekCmdDesc desc <- peekCmdDesc
addCmdImpl $ void $ do addCmdImpl $ void $ do
when printLicense $ do when printLicense $ do
liftIO $ print licenseDoc print licenseDoc
System.Exit.exitSuccess System.Exit.exitSuccess
when printVersion $ do when printVersion $ do
liftIO $ do do
putStrLn $ "brittany version " ++ showVersion version putStrLn $ "brittany version " ++ showVersion version
putStrLn $ "Copyright (C) 2016-2017 Lennart Spitzner" putStrLn $ "Copyright (C) 2016-2017 Lennart Spitzner"
putStrLn $ "There is NO WARRANTY, to the extent permitted by law." putStrLn $ "There is NO WARRANTY, to the extent permitted by law."
@ -132,22 +133,41 @@ mainCmdParser helpDesc = do
return Nothing return Nothing
[x] -> return $ Just x [x] -> return $ Just x
_ -> do _ -> do
liftIO $ putStrErrLn $ "more than one input, aborting" putStrErrLn $ "more than one input, aborting"
System.Exit.exitWith (System.Exit.ExitFailure 50) System.Exit.exitWith (System.Exit.ExitFailure 50)
outputPath <- case outputPaths of outputPathM <- case outputPaths of
[] -> do [] -> do
return Nothing return Nothing
[x] -> return $ Just x [x] -> return $ Just x
_ -> do _ -> do
liftIO $ putStrErrLn $ "more than one output, aborting" putStrErrLn $ "more than one output, aborting"
System.Exit.exitWith (System.Exit.ExitFailure 50) System.Exit.exitWith (System.Exit.ExitFailure 50)
config <- runMaybeT (readConfigs cmdlineConfig configPaths) >>= \case config <- runMaybeT (readConfigs cmdlineConfig configPaths) >>= \case
Nothing -> System.Exit.exitWith (System.Exit.ExitFailure 50) Nothing -> System.Exit.exitWith (System.Exit.ExitFailure 50)
Just x -> return x Just x -> return x
when (confUnpack $ _dconf_dump_config $ _conf_debug $ config) $ do when (confUnpack $ _dconf_dump_config $ _conf_debug $ config) $ do
trace (showConfigYaml config) $ return () trace (showConfigYaml config) $ return ()
eitherErrSucc <- coreIO putStrErrLn config suppressOutput inputPathM outputPathM
case eitherErrSucc of
Left errNo -> System.Exit.exitWith (System.Exit.ExitFailure errNo)
Right () -> pure ()
-- | The main IO parts for the default mode of operation, and after commandline
-- and config stuff is processed.
coreIO
:: (String -> IO ()) -- ^ error output function. In parallel operation, you
-- may want serialize the different outputs and
-- consequently not directly print to stderr.
-> Config -- ^ global program config.
-> Bool -- ^ whether to supress output (to stdout). Purely IO flag, so
-- currently not part of program config.
-> Maybe FilePath.FilePath -- ^ input filepath; stdin if Nothing.
-> Maybe FilePath.FilePath -- ^ output filepath; stdout if Nothing.
-> IO (Either Int ()) -- ^ Either an errorNo, or success.
coreIO putErrorLnIO config suppressOutput inputPathM outputPathM = EitherT.runEitherT $ do
let putErrorLn = liftIO . putErrorLnIO :: String -> EitherT.EitherT e IO ()
let ghcOptions = config & _conf_forward & _options_ghc & runIdentity let ghcOptions = config & _conf_forward & _options_ghc & runIdentity
liftIO $ do
-- there is a good of code duplication between the following code and the -- there is a good of code duplication between the following code and the
-- `pureModuleTransform` function. Unfortunately, there are also a good -- `pureModuleTransform` function. Unfortunately, there are also a good
-- amount of slight differences: This module is a bit more verbose, and -- amount of slight differences: This module is a bit more verbose, and
@ -165,7 +185,7 @@ mainCmdParser helpDesc = do
CPPModeAbort -> do CPPModeAbort -> do
return $ Left "Encountered -XCPP. Aborting." return $ Left "Encountered -XCPP. Aborting."
CPPModeWarn -> do CPPModeWarn -> do
putStrErrLn putErrorLnIO
$ "Warning: Encountered -XCPP." $ "Warning: Encountered -XCPP."
++ " Be warned that -XCPP is not supported and that" ++ " Be warned that -XCPP is not supported and that"
++ " brittany cannot check that its output is syntactically" ++ " brittany cannot check that its output is syntactically"
@ -179,14 +199,14 @@ mainCmdParser helpDesc = do
let hackF s = if "#include" `isPrefixOf` s then "-- BRITTANY_INCLUDE_HACK " ++ s else s let hackF s = if "#include" `isPrefixOf` s then "-- BRITTANY_INCLUDE_HACK " ++ s else s
let hackTransform = let hackTransform =
if hackAroundIncludes && not exactprintOnly then List.unlines . fmap hackF . List.lines else id if hackAroundIncludes && not exactprintOnly then List.unlines . fmap hackF . List.lines else id
inputString <- System.IO.hGetContents System.IO.stdin inputString <- liftIO $ System.IO.hGetContents System.IO.stdin
parseModuleFromString ghcOptions "stdin" cppCheckFunc (hackTransform inputString) liftIO $ parseModuleFromString ghcOptions "stdin" cppCheckFunc (hackTransform inputString)
Just p -> parseModule ghcOptions p cppCheckFunc Just p -> liftIO $ parseModule ghcOptions p cppCheckFunc
case parseResult of case parseResult of
Left left -> do Left left -> do
putStrErrLn "parse error:" putErrorLn "parse error:"
printErr left putErrorLn $ show left
System.Exit.exitWith (System.Exit.ExitFailure 60) EitherT.left 60
Right (anns, parsedSource, hasCPP) -> do Right (anns, parsedSource, hasCPP) -> do
when (config & _conf_debug .> _dconf_dump_ast_full .> confUnpack) $ do when (config & _conf_debug .> _dconf_dump_ast_full .> confUnpack) $ do
let val = printTreeWithCustom 100 (customLayouterF anns) parsedSource let val = printTreeWithCustom 100 (customLayouterF anns) parsedSource
@ -199,11 +219,9 @@ mainCmdParser helpDesc = do
let omitCheck = config & _conf_errorHandling .> _econf_omit_output_valid_check .> confUnpack let omitCheck = config & _conf_errorHandling .> _econf_omit_output_valid_check .> confUnpack
(ews, outRaw) <- if hasCPP || omitCheck (ews, outRaw) <- if hasCPP || omitCheck
then return $ pPrintModule config anns parsedSource then return $ pPrintModule config anns parsedSource
else pPrintModuleAndCheck config anns parsedSource else liftIO $ pPrintModuleAndCheck config anns parsedSource
let hackF s = fromMaybe s $ TextL.stripPrefix (TextL.pack "-- BRITTANY_INCLUDE_HACK ") s let hackF s = fromMaybe s $ TextL.stripPrefix (TextL.pack "-- BRITTANY_INCLUDE_HACK ") s
pure $ if hackAroundIncludes pure $ if hackAroundIncludes then (ews, TextL.unlines $ fmap hackF $ TextL.lines outRaw) else (ews, outRaw)
then (ews, TextL.unlines $ fmap hackF $ TextL.lines outRaw)
else (ews, outRaw)
let customErrOrder ErrorInput{} = 4 let customErrOrder ErrorInput{} = 4
customErrOrder LayoutWarning{} = 0 :: Int customErrOrder LayoutWarning{} = 0 :: Int
customErrOrder ErrorOutputCheck{} = 1 customErrOrder ErrorOutputCheck{} = 1
@ -213,31 +231,31 @@ mainCmdParser helpDesc = do
let groupedErrsWarns = Data.List.Extra.groupOn customErrOrder $ List.sortOn customErrOrder $ errsWarns let groupedErrsWarns = Data.List.Extra.groupOn customErrOrder $ List.sortOn customErrOrder $ errsWarns
groupedErrsWarns `forM_` \case groupedErrsWarns `forM_` \case
(ErrorOutputCheck{}:_) -> do (ErrorOutputCheck{}:_) -> do
putStrErrLn $ "ERROR: brittany pretty printer" ++ " returned syntactically invalid result." putErrorLn $ "ERROR: brittany pretty printer" ++ " returned syntactically invalid result."
(ErrorInput str:_) -> do (ErrorInput str:_) -> do
putStrErrLn $ "ERROR: parse error: " ++ str putErrorLn $ "ERROR: parse error: " ++ str
uns@(ErrorUnknownNode{}:_) -> do uns@(ErrorUnknownNode{}:_) -> do
putStrErrLn $ "ERROR: encountered unknown syntactical constructs:" putErrorLn $ "ERROR: encountered unknown syntactical constructs:"
uns `forM_` \case uns `forM_` \case
ErrorUnknownNode str ast -> do ErrorUnknownNode str ast -> do
putStrErrLn str putErrorLn str
when (config & _conf_debug & _dconf_dump_ast_unknown & confUnpack) $ do when (config & _conf_debug & _dconf_dump_ast_unknown & confUnpack) $ do
putStrErrLn $ " " ++ show (astToDoc ast) putErrorLn $ " " ++ show (astToDoc ast)
_ -> error "cannot happen (TM)" _ -> error "cannot happen (TM)"
warns@(LayoutWarning{}:_) -> do warns@(LayoutWarning{}:_) -> do
putStrErrLn $ "WARNINGS:" putErrorLn $ "WARNINGS:"
warns `forM_` \case warns `forM_` \case
LayoutWarning str -> putStrErrLn str LayoutWarning str -> putErrorLn str
_ -> error "cannot happen (TM)" _ -> error "cannot happen (TM)"
unused@(ErrorUnusedComment{}:_) -> do unused@(ErrorUnusedComment{}:_) -> do
putStrErrLn putErrorLn
$ "Error: detected unprocessed comments." $ "Error: detected unprocessed comments."
++ " The transformation output will most likely" ++ " The transformation output will most likely"
++ " not contain certain of the comments" ++ " not contain certain of the comments"
++ " present in the input haskell source file." ++ " present in the input haskell source file."
putStrErrLn $ "Affected are the following comments:" putErrorLn $ "Affected are the following comments:"
unused `forM_` \case unused `forM_` \case
ErrorUnusedComment str -> putStrErrLn str ErrorUnusedComment str -> putErrorLn str
_ -> error "cannot happen (TM)" _ -> error "cannot happen (TM)"
[] -> error "cannot happen" [] -> error "cannot happen"
-- TODO: don't output anything when there are errors unless user -- TODO: don't output anything when there are errors unless user
@ -248,11 +266,11 @@ mainCmdParser helpDesc = do
outputOnErrs = config & _conf_errorHandling & _econf_produceOutputOnErrors & confUnpack outputOnErrs = config & _conf_errorHandling & _econf_produceOutputOnErrors & confUnpack
shouldOutput = not suppressOutput && (not hasErrors || outputOnErrs) shouldOutput = not suppressOutput && (not hasErrors || outputOnErrs)
when shouldOutput $ addTraceSep (_conf_debug config) $ case outputPath of when shouldOutput $ addTraceSep (_conf_debug config) $ case outputPathM of
Nothing -> TextL.IO.putStr $ outLText Nothing -> liftIO $ TextL.IO.putStr $ outLText
Just p -> TextL.IO.writeFile p $ outLText Just p -> liftIO $ TextL.IO.writeFile p $ outLText
when hasErrors $ System.Exit.exitWith (System.Exit.ExitFailure 70) when hasErrors $ EitherT.left 70
where where
addTraceSep conf = addTraceSep conf =
if or if or
@ -269,6 +287,7 @@ mainCmdParser helpDesc = do
then trace "----" then trace "----"
else id else id
readConfigs :: CConfig Option -> [System.IO.FilePath] -> MaybeT IO Config readConfigs :: CConfig Option -> [System.IO.FilePath] -> MaybeT IO Config
readConfigs cmdlineConfig configPaths = do readConfigs cmdlineConfig configPaths = do
let defLocalConfigPath = "brittany.yaml" let defLocalConfigPath = "brittany.yaml"