Add function pureModuleTransform
parent
2dfa691f9e
commit
5dbe0f2c9c
|
@ -108,6 +108,7 @@ library {
|
||||||
, cmdargs >=0.10.14 && <0.11
|
, cmdargs >=0.10.14 && <0.11
|
||||||
, czipwith >=1.0.0.0 && <1.1
|
, czipwith >=1.0.0.0 && <1.1
|
||||||
, unordered-containers >=0.2.7 && <0.3
|
, unordered-containers >=0.2.7 && <0.3
|
||||||
|
, ghc-boot-th >=8.0.1 && <8.1
|
||||||
}
|
}
|
||||||
default-extensions: {
|
default-extensions: {
|
||||||
CPP
|
CPP
|
||||||
|
@ -169,9 +170,9 @@ executable brittany
|
||||||
, cmdargs
|
, cmdargs
|
||||||
, czipwith
|
, czipwith
|
||||||
, unordered-containers
|
, unordered-containers
|
||||||
|
, ghc-boot-th
|
||||||
, hspec >=2.4.1 && <2.5
|
, hspec >=2.4.1 && <2.5
|
||||||
, filepath >=1.4.1.0 && <1.5
|
, filepath >=1.4.1.0 && <1.5
|
||||||
, ghc-boot-th >=8.0.1 && <8.1
|
|
||||||
}
|
}
|
||||||
hs-source-dirs: src-brittany
|
hs-source-dirs: src-brittany
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
|
@ -248,6 +249,7 @@ test-suite unittests
|
||||||
, cmdargs
|
, cmdargs
|
||||||
, czipwith
|
, czipwith
|
||||||
, unordered-containers
|
, unordered-containers
|
||||||
|
, ghc-boot-th
|
||||||
, hspec >=2.4.1 && <2.5
|
, hspec >=2.4.1 && <2.5
|
||||||
}
|
}
|
||||||
ghc-options: -Wall
|
ghc-options: -Wall
|
||||||
|
@ -322,6 +324,7 @@ test-suite littests
|
||||||
, cmdargs
|
, cmdargs
|
||||||
, czipwith
|
, czipwith
|
||||||
, unordered-containers
|
, unordered-containers
|
||||||
|
, ghc-boot-th
|
||||||
, hspec >=2.4.1 && <2.5
|
, hspec >=2.4.1 && <2.5
|
||||||
, parsec >=3.1.11 && <3.2
|
, parsec >=3.1.11 && <3.2
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,11 @@ mainCmdParser helpDesc = do
|
||||||
trace (showConfigYaml config) $ return ()
|
trace (showConfigYaml config) $ return ()
|
||||||
let ghcOptions = config & _conf_forward & _options_ghc & runIdentity
|
let ghcOptions = config & _conf_forward & _options_ghc & runIdentity
|
||||||
liftIO $ do
|
liftIO $ do
|
||||||
|
-- there is a good of code duplication between the following code and the
|
||||||
|
-- `pureModuleTransform` function. Unfortunately, there are also a good
|
||||||
|
-- amount of slight differences: This module is a bit more verbose, and
|
||||||
|
-- it tries to use the full-blown `parseModule` function which supports
|
||||||
|
-- CPP (but requires the input to be a file..).
|
||||||
let cppMode = config & _conf_preprocessor & _ppconf_CPPMode & runIdentity & Semigroup.getLast
|
let cppMode = config & _conf_preprocessor & _ppconf_CPPMode & runIdentity & Semigroup.getLast
|
||||||
-- the flag will do the following: insert a marker string
|
-- the flag will do the following: insert a marker string
|
||||||
-- ("-- BRITTANY_INCLUDE_HACK ") right before any lines starting with
|
-- ("-- BRITTANY_INCLUDE_HACK ") right before any lines starting with
|
||||||
|
@ -147,21 +152,15 @@ mainCmdParser helpDesc = 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
|
||||||
trace ("---- ast ----\n" ++ show val) $ return ()
|
trace ("---- ast ----\n" ++ show val) $ return ()
|
||||||
-- mapM_ printErr (Map.toList anns)
|
|
||||||
-- let L _ (HsModule name exports imports decls _ _) = parsedSource
|
|
||||||
-- let someDecls = take 3 decls
|
|
||||||
-- -- let out = ExactPrint.exactPrint parsedSource anns
|
|
||||||
-- let out = do
|
|
||||||
-- decl <- someDecls
|
|
||||||
-- ExactPrint.exactPrint decl anns
|
|
||||||
let omitCheck = config & _conf_errorHandling .> _econf_omit_output_valid_check .> confUnpack
|
|
||||||
(errsWarns, outLText) <- do
|
(errsWarns, outLText) <- do
|
||||||
|
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 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 then (ews, TextL.unlines $ fmap hackF $ TextL.lines outRaw) else (ews, outRaw)
|
pure $ if hackAroundIncludes then (ews, TextL.unlines $ fmap hackF $ TextL.lines outRaw) else (ews, outRaw)
|
||||||
let customErrOrder LayoutWarning{} = 0 :: Int
|
let customErrOrder LayoutErrorInput{} = 4
|
||||||
|
customErrOrder LayoutWarning{} = 0 :: Int
|
||||||
customErrOrder LayoutErrorOutputCheck{} = 1
|
customErrOrder LayoutErrorOutputCheck{} = 1
|
||||||
customErrOrder LayoutErrorUnusedComment{} = 2
|
customErrOrder LayoutErrorUnusedComment{} = 2
|
||||||
customErrOrder LayoutErrorUnknownNode{} = 3
|
customErrOrder LayoutErrorUnknownNode{} = 3
|
||||||
|
@ -170,6 +169,8 @@ mainCmdParser helpDesc = do
|
||||||
groupedErrsWarns `forM_` \case
|
groupedErrsWarns `forM_` \case
|
||||||
(LayoutErrorOutputCheck{}:_) -> do
|
(LayoutErrorOutputCheck{}:_) -> do
|
||||||
putStrErrLn $ "ERROR: brittany pretty printer" ++ " returned syntactically invalid result."
|
putStrErrLn $ "ERROR: brittany pretty printer" ++ " returned syntactically invalid result."
|
||||||
|
(LayoutErrorInput str:_) -> do
|
||||||
|
putStrErrLn $ "ERROR: parse error: " ++ str
|
||||||
uns@(LayoutErrorUnknownNode{}:_) -> do
|
uns@(LayoutErrorUnknownNode{}:_) -> do
|
||||||
putStrErrLn $ "ERROR: encountered unknown syntactical constructs:"
|
putStrErrLn $ "ERROR: encountered unknown syntactical constructs:"
|
||||||
uns `forM_` \case
|
uns `forM_` \case
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
{-# LANGUAGE DataKinds #-}
|
{-# LANGUAGE DataKinds #-}
|
||||||
|
|
||||||
module Language.Haskell.Brittany
|
module Language.Haskell.Brittany
|
||||||
( parsePrintModule
|
( pureModuleTransform
|
||||||
|
, parsePrintModule
|
||||||
, pPrintModule
|
, pPrintModule
|
||||||
, pPrintModuleAndCheck
|
, pPrintModuleAndCheck
|
||||||
-- re-export from utils:
|
-- re-export from utils:
|
||||||
|
@ -18,7 +19,10 @@ import qualified Language.Haskell.GHC.ExactPrint as ExactPrint
|
||||||
import qualified Language.Haskell.GHC.ExactPrint.Types as ExactPrint.Types
|
import qualified Language.Haskell.GHC.ExactPrint.Types as ExactPrint.Types
|
||||||
import qualified Language.Haskell.GHC.ExactPrint.Parsers as ExactPrint.Parsers
|
import qualified Language.Haskell.GHC.ExactPrint.Parsers as ExactPrint.Parsers
|
||||||
|
|
||||||
import qualified Data.Generics as SYB
|
import Data.Data
|
||||||
|
import Control.Monad.Trans.Either
|
||||||
|
import Data.HList.HList
|
||||||
|
import Data.CZipWith
|
||||||
|
|
||||||
import qualified Data.Text.Lazy.Builder as Text.Builder
|
import qualified Data.Text.Lazy.Builder as Text.Builder
|
||||||
|
|
||||||
|
@ -45,10 +49,73 @@ import RdrName ( RdrName(..) )
|
||||||
import GHC ( runGhc, GenLocated(L), moduleNameString )
|
import GHC ( runGhc, GenLocated(L), moduleNameString )
|
||||||
import SrcLoc ( SrcSpan )
|
import SrcLoc ( SrcSpan )
|
||||||
import HsSyn
|
import HsSyn
|
||||||
|
import qualified DynFlags as GHC
|
||||||
|
import qualified GHC.LanguageExtensions.Type as GHC
|
||||||
|
|
||||||
import Data.HList.HList
|
|
||||||
|
|
||||||
|
|
||||||
|
-- | Exposes the transformation in an pseudo-pure fashion. The signature
|
||||||
|
-- contains `IO` due to the GHC API not exposing a pure parsing function, but
|
||||||
|
-- there should be no observable effects.
|
||||||
|
--
|
||||||
|
-- Note that this function ignores/resets all config values regarding
|
||||||
|
-- debugging, i.e. it will never use `trace`/write to stderr.
|
||||||
|
pureModuleTransform :: CConfig Option -> Text -> IO (Either [LayoutError] Text)
|
||||||
|
pureModuleTransform oConfigRaw inputText = runEitherT $ do
|
||||||
|
let configRaw = cZipWith fromOptionIdentity staticDefaultConfig oConfigRaw
|
||||||
|
let config = configRaw { _conf_debug = _conf_debug staticDefaultConfig }
|
||||||
|
let ghcOptions = config & _conf_forward & _options_ghc & runIdentity
|
||||||
|
let config_pp = config & _conf_preprocessor
|
||||||
|
let cppMode = config_pp & _ppconf_CPPMode & confUnpack
|
||||||
|
let hackAroundIncludes = config_pp & _ppconf_hackAroundIncludes & confUnpack
|
||||||
|
(anns, parsedSource, hasCPP) <- do
|
||||||
|
let hackF s = if "#include" `isPrefixOf` s
|
||||||
|
then "-- BRITTANY_INCLUDE_HACK " ++ s
|
||||||
|
else s
|
||||||
|
let hackTransform = if hackAroundIncludes
|
||||||
|
then List.unlines . fmap hackF . List.lines
|
||||||
|
else id
|
||||||
|
let cppCheckFunc dynFlags = if GHC.xopt GHC.Cpp dynFlags
|
||||||
|
then case cppMode of
|
||||||
|
CPPModeAbort -> return $ Left "Encountered -XCPP. Aborting."
|
||||||
|
CPPModeWarn -> return $ Right True
|
||||||
|
CPPModeNowarn -> return $ Right True
|
||||||
|
else return $ Right False
|
||||||
|
parseResult <- lift $ parseModuleFromString
|
||||||
|
ghcOptions
|
||||||
|
"stdin"
|
||||||
|
cppCheckFunc
|
||||||
|
(hackTransform $ Text.unpack inputText)
|
||||||
|
case parseResult of
|
||||||
|
Left err -> left $ [LayoutErrorInput err]
|
||||||
|
Right x -> pure $ x
|
||||||
|
(errsWarns, outputTextL) <- do
|
||||||
|
let omitCheck =
|
||||||
|
config
|
||||||
|
& _conf_errorHandling
|
||||||
|
& _econf_omit_output_valid_check
|
||||||
|
& confUnpack
|
||||||
|
(ews, outRaw) <- if hasCPP || omitCheck
|
||||||
|
then return $ pPrintModule config anns parsedSource
|
||||||
|
else lift $ pPrintModuleAndCheck config anns parsedSource
|
||||||
|
let hackF s = fromMaybe s
|
||||||
|
$ TextL.stripPrefix (TextL.pack "-- BRITTANY_INCLUDE_HACK ") s
|
||||||
|
pure $ if hackAroundIncludes
|
||||||
|
then (ews, TextL.unlines $ fmap hackF $ TextL.lines outRaw)
|
||||||
|
else (ews, outRaw)
|
||||||
|
let customErrOrder LayoutErrorInput{} = 4
|
||||||
|
customErrOrder LayoutWarning{} = 0 :: Int
|
||||||
|
customErrOrder LayoutErrorOutputCheck{} = 1
|
||||||
|
customErrOrder LayoutErrorUnusedComment{} = 2
|
||||||
|
customErrOrder LayoutErrorUnknownNode{} = 3
|
||||||
|
let hasErrors =
|
||||||
|
case config & _conf_errorHandling & _econf_Werror & confUnpack of
|
||||||
|
False -> 0 < maximum (-1 : fmap customErrOrder errsWarns)
|
||||||
|
True -> not $ null errsWarns
|
||||||
|
if hasErrors
|
||||||
|
then left $ errsWarns
|
||||||
|
else pure $ TextL.toStrict outputTextL
|
||||||
|
|
||||||
|
|
||||||
-- LayoutErrors can be non-fatal warnings, thus both are returned instead
|
-- LayoutErrors can be non-fatal warnings, thus both are returned instead
|
||||||
-- of an Either.
|
-- of an Either.
|
||||||
|
@ -115,7 +182,11 @@ parsePrintModule conf filename input = do
|
||||||
case parseResult of
|
case parseResult of
|
||||||
Left (_ , s ) -> return $ Left $ "parsing error: " ++ s
|
Left (_ , s ) -> return $ Left $ "parsing error: " ++ s
|
||||||
Right (anns, parsedModule) -> do
|
Right (anns, parsedModule) -> do
|
||||||
let omitCheck = conf & _conf_errorHandling .> _econf_omit_output_valid_check .> confUnpack
|
let omitCheck =
|
||||||
|
conf
|
||||||
|
& _conf_errorHandling
|
||||||
|
.> _econf_omit_output_valid_check
|
||||||
|
.> confUnpack
|
||||||
(errs, ltext) <- if omitCheck
|
(errs, ltext) <- if omitCheck
|
||||||
then return $ pPrintModule conf anns parsedModule
|
then return $ pPrintModule conf anns parsedModule
|
||||||
else pPrintModuleAndCheck conf anns parsedModule
|
else pPrintModuleAndCheck conf anns parsedModule
|
||||||
|
@ -124,6 +195,7 @@ parsePrintModule conf filename input = do
|
||||||
else
|
else
|
||||||
let
|
let
|
||||||
errStrs = errs <&> \case
|
errStrs = errs <&> \case
|
||||||
|
LayoutErrorInput str -> str
|
||||||
LayoutErrorUnusedComment str -> str
|
LayoutErrorUnusedComment str -> str
|
||||||
LayoutWarning str -> str
|
LayoutWarning str -> str
|
||||||
LayoutErrorUnknownNode str _ -> str
|
LayoutErrorUnknownNode str _ -> str
|
||||||
|
@ -131,6 +203,7 @@ parsePrintModule conf filename input = do
|
||||||
in
|
in
|
||||||
Left $ "pretty printing error(s):\n" ++ List.unlines errStrs
|
Left $ "pretty printing error(s):\n" ++ List.unlines errStrs
|
||||||
|
|
||||||
|
|
||||||
-- this approach would for with there was a pure GHC.parseDynamicFilePragma.
|
-- this approach would for with there was a pure GHC.parseDynamicFilePragma.
|
||||||
-- Unfortunately that does not exist yet, so we cannot provide a nominally
|
-- Unfortunately that does not exist yet, so we cannot provide a nominally
|
||||||
-- pure interface.
|
-- pure interface.
|
||||||
|
@ -215,7 +288,7 @@ ppModule lmod@(L loc m@(HsModule _name _exports _imports decls _ _)) = do
|
||||||
ppmMoveToExactLoc $ ExactPrint.Types.DP (eofX - cmX, eofY - cmY)
|
ppmMoveToExactLoc $ ExactPrint.Types.DP (eofX - cmX, eofY - cmY)
|
||||||
_ -> return ()
|
_ -> return ()
|
||||||
|
|
||||||
withTransformedAnns :: SYB.Data ast => ast -> PPM () -> PPM ()
|
withTransformedAnns :: Data ast => ast -> PPM () -> PPM ()
|
||||||
withTransformedAnns ast m = do
|
withTransformedAnns ast m = do
|
||||||
-- TODO: implement `local` for MultiReader/MultiRWS
|
-- TODO: implement `local` for MultiReader/MultiRWS
|
||||||
readers@(conf :+: anns :+: HNil) <- MultiRWSS.mGetRawR
|
readers@(conf :+: anns :+: HNil) <- MultiRWSS.mGetRawR
|
||||||
|
|
|
@ -115,10 +115,17 @@ instance Show LayoutState where
|
||||||
-- }
|
-- }
|
||||||
|
|
||||||
data LayoutError
|
data LayoutError
|
||||||
= LayoutErrorUnusedComment String
|
= LayoutErrorInput String
|
||||||
|
-- ^ parsing failed
|
||||||
|
| LayoutErrorUnusedComment String
|
||||||
|
-- ^ internal error: some comment went missing
|
||||||
| LayoutWarning String
|
| LayoutWarning String
|
||||||
|
-- ^ some warning
|
||||||
| forall ast . Data.Data.Data ast => LayoutErrorUnknownNode String ast
|
| forall ast . Data.Data.Data ast => LayoutErrorUnknownNode String ast
|
||||||
|
-- ^ internal error: pretty-printing is not implemented for type of node
|
||||||
|
-- in the syntax-tree
|
||||||
| LayoutErrorOutputCheck
|
| LayoutErrorOutputCheck
|
||||||
|
-- ^ checking the output for syntactic validity failed
|
||||||
|
|
||||||
data BriSpacing = BriSpacing
|
data BriSpacing = BriSpacing
|
||||||
{ _bs_spacePastLineIndent :: Int -- space in the current,
|
{ _bs_spacePastLineIndent :: Int -- space in the current,
|
||||||
|
|
Loading…
Reference in New Issue