Merge branch 'dev'

pull/121/head 0.9.0.1
Lennart Spitzner 2018-02-14 17:30:25 +01:00
commit 34036cbb74
21 changed files with 280 additions and 109 deletions

View File

@ -115,7 +115,7 @@ matrix:
#- env: BUILD=stack ARGS="--resolver lts-7" #- env: BUILD=stack ARGS="--resolver lts-7"
# compiler: ": #stack 8.0.1" # compiler: ": #stack 8.0.1"
# addons: {apt: {packages: [libgmp-dev]}} # addons: {apt: {packages: [libgmp-dev]}}
- env: BUILD=stack ARGS="--resolver lts-8" - env: BUILD=stack ARGS="--stack-yaml stack-8.0.2.yaml"
compiler: ": #stack 8.0.2" compiler: ": #stack 8.0.2"
addons: {apt: {packages: [libgmp-dev]}} addons: {apt: {packages: [libgmp-dev]}}
@ -178,7 +178,7 @@ before_install:
# echo 'jobs: $ncpus' >> $HOME/.cabal/config # echo 'jobs: $ncpus' >> $HOME/.cabal/config
#fi #fi
- PKGNAME='brittany' - PKGNAME='brittany'
- JOBS='2' - JOBS='1'
- | - |
function better_wait() { function better_wait() {
date date
@ -209,7 +209,7 @@ install:
set -ex set -ex
case "$BUILD" in case "$BUILD" in
stack) stack)
stack --no-terminal --install-ghc $ARGS test --bench --only-dependencies stack -j$JOBS --no-terminal --install-ghc $ARGS test --bench --only-dependencies
;; ;;
cabal*) cabal*)
cabal --version cabal --version
@ -250,6 +250,8 @@ install:
cabal --version cabal --version
travis_retry cabal update -v travis_retry cabal update -v
echo 'packages: .' > cabal.project echo 'packages: .' > cabal.project
echo 'package brittany' > cabal.project.local
echo ' ghc-options: -Werror' >> cabal.project.local
rm -f cabal.project.freeze rm -f cabal.project.freeze
cabal new-build -j$JOBS --enable-test --enable-benchmarks --dep cabal new-build -j$JOBS --enable-test --enable-benchmarks --dep
cabal new-build -j$JOBS --disable-tests --disable-benchmarks --dep cabal new-build -j$JOBS --disable-tests --disable-benchmarks --dep
@ -262,12 +264,12 @@ script:
set -ex set -ex
case "$BUILD" in case "$BUILD" in
stack) stack)
better_wait stack --no-terminal $ARGS test --bench --no-run-benchmarks --haddock --no-haddock-deps --ghc-options="-j1 +RTS -M500M -RTS" better_wait stack -j$JOBS --no-terminal $ARGS test --bench --no-run-benchmarks --haddock --no-haddock-deps --ghc-options="-j1 +RTS -M500M -RTS -Werror"
;; ;;
cabal) cabal)
if [ -f configure.ac ]; then autoreconf -i; fi if [ -f configure.ac ]; then autoreconf -i; fi
cabal configure --enable-tests --enable-benchmarks -v # -v2 provides useful information for debugging cabal configure --enable-tests --enable-benchmarks -v # -v2 provides useful information for debugging
better_wait cabal build -j$JOBS --ghc-options="-j1 +RTS -M500M -RTS" # this builds all libraries and executables (including tests/benchmarks) better_wait cabal build -j$JOBS --ghc-options="-j1 +RTS -M500M -RTS -Werror" # this builds all libraries and executables (including tests/benchmarks)
cabal test cabal test
;; ;;
cabaldist) cabaldist)

View File

@ -1,5 +1,21 @@
# Revision history for brittany # Revision history for brittany
## 0.9.0.1 -- February 2018
* Support `TupleSections` (thanks to Matthew Piziak)
* Bugfixes:
- Fix Shebang handling with stdin input (#92)
- Fix bug that effectively deleted strict/lazy matches (BangPatterns) (#116)
- Fix infix operator whitespace bug (#101, #114)
- Fix help command output and its layouting (#103)
- Fix crash when config dir does not exist yet (#115)
* Layouting changes:
- no space after opening non-tuple parenthesis even for multi-line case
- use spaces around infix operators (applies to sections and in pattern
matches)
- Let-in is layouted more flexibly in fewer lines, if possible
(thanks to Evan Borden)
## 0.9.0.0 -- December 2017 ## 0.9.0.0 -- December 2017
* Change default global config path (use XDG spec) * Change default global config path (use XDG spec)

View File

@ -1,5 +1,5 @@
name: brittany name: brittany
version: 0.9.0.0 version: 0.9.0.1
synopsis: Haskell source code formatter synopsis: Haskell source code formatter
description: { description: {
See <https://github.com/lspitzner/brittany/blob/master/README.md the README>. See <https://github.com/lspitzner/brittany/blob/master/README.md the README>.
@ -82,7 +82,7 @@ library {
{ base >=4.9 && <4.11 { base >=4.9 && <4.11
, ghc >=8.0.1 && <8.3 , ghc >=8.0.1 && <8.3
, ghc-paths >=0.1.0.9 && <0.2 , ghc-paths >=0.1.0.9 && <0.2
, ghc-exactprint >=0.5.3.0 && <0.6 , ghc-exactprint >=0.5.6.0 && <0.5.7
, transformers >=0.5.2.0 && <0.6 , transformers >=0.5.2.0 && <0.6
, containers >=0.5.7.1 && <0.6 , containers >=0.5.7.1 && <0.6
, mtl >=2.2.1 && <2.3 , mtl >=2.2.1 && <2.3
@ -94,7 +94,7 @@ library {
, pretty >=1.1.3.3 && <1.2 , pretty >=1.1.3.3 && <1.2
, bytestring >=0.10.8.1 && <0.11 , bytestring >=0.10.8.1 && <0.11
, directory >=1.2.6.2 && <1.4 , directory >=1.2.6.2 && <1.4
, butcher >=1.2 && <1.3 , butcher >=1.3 && <1.4
, yaml >=0.8.18 && <0.9 , yaml >=0.8.18 && <0.9
, aeson >=1.0.1.0 && <1.3 , aeson >=1.0.1.0 && <1.3
, extra >=1.4.10 && <1.7 , extra >=1.4.10 && <1.7

View File

@ -5,12 +5,12 @@ extra-source-files: ChangeLog.md
cabal-version: >=1.10 cabal-version: >=1.10
executable doc-svg-gen executable doc-svg-gen
buildable: True buildable: False
main-is: Main.hs main-is: Main.hs
-- other-modules: -- other-modules:
-- other-extensions: -- other-extensions:
build-depends: build-depends:
{ base >=4.9 && <4.10 { base >=4.9 && <4.11
, text , text
, graphviz >=2999.19.0.0 , graphviz >=2999.19.0.0
} }

View File

@ -82,9 +82,10 @@ helpDoc = PP.vcat $ List.intersperse
] ]
, parDocW , parDocW
[ "This program is written carefully and contains safeguards to ensure" [ "This program is written carefully and contains safeguards to ensure"
, "the transformation does not change semantics (or the syntax tree at all)" , "the output is syntactically valid and that no comments are removed."
, "and that no comments are removed." , "Nonetheless, this is a young project, and there will always be bugs,"
, "Nonetheless, this is a young project, and there will always be bugs." , "and ensuring that the transformation never changes semantics of the"
, "transformed source is currently not possible."
, "Please do check the output and do not let brittany override your large" , "Please do check the output and do not let brittany override your large"
, "codebase without having backups." , "codebase without having backups."
] ]
@ -140,16 +141,16 @@ mainCmdParser helpDesc = do
"" ""
["write-mode"] ["write-mode"]
"(display|inplace)" "(display|inplace)"
Flag ( flagHelp
{ _flag_help = Just $ PP.vcat ( PP.vcat
[ PP.text "display: output for any input(s) goes to stdout" [ PP.text "display: output for any input(s) goes to stdout"
, PP.text "inplace: override respective input file (without backup!)" , PP.text "inplace: override respective input file (without backup!)"
] ]
, _flag_default = Just Display )
} <> flagDefault Display
inputParams <- addParamNoFlagStrings "PATH" (paramHelpStr "paths to input haskell source files") )
inputParams <- addParamNoFlagStrings "PATH" (paramHelpStr "paths to input/inout haskell source files")
reorderStop reorderStop
desc <- peekCmdDesc
addCmdImpl $ void $ do addCmdImpl $ void $ do
when printLicense $ do when printLicense $ do
print licenseDoc print licenseDoc
@ -161,7 +162,7 @@ mainCmdParser helpDesc = do
putStrLn $ "There is NO WARRANTY, to the extent permitted by law." putStrLn $ "There is NO WARRANTY, to the extent permitted by law."
System.Exit.exitSuccess System.Exit.exitSuccess
when printHelp $ do when printHelp $ do
liftIO $ print $ ppHelpShallow desc liftIO $ putStrLn $ PP.renderStyle PP.style { PP.ribbonsPerLine = 1.0 } $ ppHelpShallow helpDesc
System.Exit.exitSuccess System.Exit.exitSuccess
let inputPaths = if null inputParams then [Nothing] else map Just inputParams let inputPaths = if null inputParams then [Nothing] else map Just inputParams
@ -281,7 +282,7 @@ coreIO putErrorLnIO config suppressOutput inputPathM outputPathM = ExceptT.runEx
putErrorLn 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 some of the comments"
++ " present in the input haskell source file." ++ " present in the input haskell source file."
putErrorLn $ "Affected are the following comments:" putErrorLn $ "Affected are the following comments:"
unused `forM_` \case unused `forM_` \case
@ -346,7 +347,7 @@ readConfigs cmdlineConfig configPaths = do
userConfigXdg <- readConfig userConfigPathXdg userConfigXdg <- readConfig userConfigPathXdg
let userConfig = userConfigSimple <|> userConfigXdg let userConfig = userConfigSimple <|> userConfigXdg
when (Data.Maybe.isNothing userConfig) $ do when (Data.Maybe.isNothing userConfig) $ do
liftIO $ Directory.createDirectoryIfMissing False userBritPathXdg liftIO $ Directory.createDirectoryIfMissing True userBritPathXdg
writeDefaultConfig userConfigPathXdg writeDefaultConfig userConfigPathXdg
-- rightmost has highest priority -- rightmost has highest priority
pure $ [userConfig, localConfig] pure $ [userConfig, localConfig]

View File

@ -355,6 +355,9 @@ func (x:xr) = x
#pending #pending
func (x :+: xr) = x func (x :+: xr) = x
#test normal infix constructor
func (x `Foo` xr) = x
############################################################################### ###############################################################################
############################################################################### ###############################################################################
@ -476,9 +479,23 @@ func = (`abc` 1)
#group tuples #group tuples
### ###
#test 1 #test pair
func = (abc, def) func = (abc, def)
#test pair section left
func = (abc, )
#test pair section right
func = (, abc)
#test quintuple section long
myTupleSection =
( verylaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaargefirstelement
,
, verylaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaargethirdelement
,
)
#test 2 #test 2
#pending #pending
func = (lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd func = (lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd

View File

@ -513,3 +513,15 @@ cs0 = 0 : [ c / Interval n | c <- cs | n <- [1..] ]
#test issue 70 #test issue 70
{-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TemplateHaskell #-}
deriveFromJSON (unPrefix "assignPost") ''AssignmentPost deriveFromJSON (unPrefix "assignPost") ''AssignmentPost
#test issue 116
{-# LANGUAGE BangPatterns #-}
func = do
let !forced = some
pure ()
#test let-in-hanging
spanKey p q = case minViewWithKey q of
Just ((k, _), q') | p k ->
let (kas, q'') = spanKey p q' in ((k, a) : kas, q'')
_ -> ([], q)

View File

@ -173,6 +173,7 @@ defaultTestConfig = Config
, _lconfig_columnAlignMode = coerce (ColumnAlignModeMajority 0.7) , _lconfig_columnAlignMode = coerce (ColumnAlignModeMajority 0.7)
, _lconfig_alignmentLimit = coerce (30 :: Int) , _lconfig_alignmentLimit = coerce (30 :: Int)
, _lconfig_alignmentBreakOnMultiline = coerce True , _lconfig_alignmentBreakOnMultiline = coerce True
, _lconfig_hangingTypeSignature = coerce False
} }
, _conf_errorHandling = (_conf_errorHandling staticDefaultConfig) , _conf_errorHandling = (_conf_errorHandling staticDefaultConfig)
{ _econf_omit_output_valid_check = coerce True { _econf_omit_output_valid_check = coerce True

View File

@ -510,6 +510,11 @@ func = (abc, def)
func = (lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd func = (lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd
, lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd) , lakjsdlajsdljasdlkjasldjasldjasldjalsdjlaskjd)
#test let in on single line
foo =
let longIdentifierForShortValue = 1
in longIdentifierForShortValue + longIdentifierForShortValue
############################################################################### ###############################################################################

View File

@ -55,6 +55,7 @@ defaultTestConfig = Config
, _lconfig_columnAlignMode = coerce (ColumnAlignModeMajority 0.7) , _lconfig_columnAlignMode = coerce (ColumnAlignModeMajority 0.7)
, _lconfig_alignmentLimit = coerce (30 :: Int) , _lconfig_alignmentLimit = coerce (30 :: Int)
, _lconfig_alignmentBreakOnMultiline = coerce True , _lconfig_alignmentBreakOnMultiline = coerce True
, _lconfig_hangingTypeSignature = coerce False
} }
, _conf_errorHandling = (_conf_errorHandling staticDefaultConfig) , _conf_errorHandling = (_conf_errorHandling staticDefaultConfig)
{ _econf_ExactPrintFallback = coerce ExactPrintFallbackModeNever { _econf_ExactPrintFallback = coerce ExactPrintFallbackModeNever

View File

@ -61,6 +61,11 @@ import qualified GHC.LanguageExtensions.Type as GHC
-- --
-- Note that this function ignores/resets all config values regarding -- Note that this function ignores/resets all config values regarding
-- debugging, i.e. it will never use `trace`/write to stderr. -- debugging, i.e. it will never use `trace`/write to stderr.
--
-- Note that the ghc parsing function used internally currently is wrapped in
-- `mask_`, so cannot be killed easily. If you don't control the input, you
-- may wish to put some proper upper bound on the input's size as a timeout
-- won't do.
parsePrintModule :: Config -> Text -> IO (Either [BrittanyError] Text) parsePrintModule :: Config -> Text -> IO (Either [BrittanyError] Text)
parsePrintModule configRaw inputText = runExceptT $ do parsePrintModule configRaw inputText = runExceptT $ do
let config = configRaw { _conf_debug = _conf_debug staticDefaultConfig } let config = configRaw { _conf_debug = _conf_debug staticDefaultConfig }

View File

@ -352,7 +352,11 @@ alignColsLines bridocs = do -- colInfos `forM_` \colInfo -> do
-- maxZipper xs [] = xs -- maxZipper xs [] = xs
-- maxZipper (x:xr) (y:yr) = max x y : maxZipper xr yr -- maxZipper (x:xr) (y:yr) = max x y : maxZipper xr yr
colAggregation :: [Int] -> Int colAggregation :: [Int] -> Int
colAggregation xs = maximum [ x | x <- xs, x < minimum xs + alignMax ] colAggregation [] = 0 -- this probably cannot happen the way we call
-- this function, because _cbs_map only ever
-- contains nonempty Seqs.
colAggregation xs = maximum [ x | x <- xs, x <= minimum xs + alignMax' ]
where alignMax' = max 0 alignMax
processedMap :: ColMap2 processedMap :: ColMap2
processedMap = processedMap =

View File

@ -63,6 +63,7 @@ staticDefaultConfig = Config
, _lconfig_columnAlignMode = coerce (ColumnAlignModeMajority 0.7) , _lconfig_columnAlignMode = coerce (ColumnAlignModeMajority 0.7)
, _lconfig_alignmentLimit = coerce (30 :: Int) , _lconfig_alignmentLimit = coerce (30 :: Int)
, _lconfig_alignmentBreakOnMultiline = coerce True , _lconfig_alignmentBreakOnMultiline = coerce True
, _lconfig_hangingTypeSignature = coerce False
} }
, _conf_errorHandling = ErrorHandlingConfig , _conf_errorHandling = ErrorHandlingConfig
{ _econf_produceOutputOnErrors = coerce False { _econf_produceOutputOnErrors = coerce False
@ -104,7 +105,7 @@ configParser = do
cols <- addFlagReadParams "" ["columns"] "AMOUNT" (flagHelpStr "target max columns (80 is an old default for this)") cols <- addFlagReadParams "" ["columns"] "AMOUNT" (flagHelpStr "target max columns (80 is an old default for this)")
importCol <- addFlagReadParams "" ["import-col"] "N" (flagHelpStr "column to align import lists at") importCol <- addFlagReadParams "" ["import-col"] "N" (flagHelpStr "column to align import lists at")
dumpConfig <- addSimpleBoolFlag "" ["dump-config"] (flagHelp $ parDoc "dump the programs full config (commandline + file + defaults)") dumpConfig <- addSimpleBoolFlag "" ["dump-config"] (flagHelp $ parDoc "dump the programs full config (merged commandline + file + defaults)")
dumpAnnotations <- addSimpleBoolFlag "" ["dump-annotations"] (flagHelp $ parDoc "dump the full annotations returned by ghc-exactprint") dumpAnnotations <- addSimpleBoolFlag "" ["dump-annotations"] (flagHelp $ parDoc "dump the full annotations returned by ghc-exactprint")
dumpUnknownAST <- addSimpleBoolFlag "" ["dump-ast-unknown"] (flagHelp $ parDoc "dump the ast for any nodes not transformed, but copied as-is by brittany") dumpUnknownAST <- addSimpleBoolFlag "" ["dump-ast-unknown"] (flagHelp $ parDoc "dump the ast for any nodes not transformed, but copied as-is by brittany")
dumpCompleteAST <- addSimpleBoolFlag "" ["dump-ast-full"] (flagHelp $ parDoc "dump the full ast") dumpCompleteAST <- addSimpleBoolFlag "" ["dump-ast-full"] (flagHelp $ parDoc "dump the full ast")
@ -118,9 +119,9 @@ configParser = do
dumpBriDocIndent <- addSimpleBoolFlag "" ["dump-bridoc-indent"] (flagHelp $ parDoc "dump the partially transformed bridoc: after transformation: indent") dumpBriDocIndent <- addSimpleBoolFlag "" ["dump-bridoc-indent"] (flagHelp $ parDoc "dump the partially transformed bridoc: after transformation: indent")
dumpBriDocFinal <- addSimpleBoolFlag "" ["dump-bridoc-final"] (flagHelp $ parDoc "dump the post-transformation bridoc") dumpBriDocFinal <- addSimpleBoolFlag "" ["dump-bridoc-final"] (flagHelp $ parDoc "dump the post-transformation bridoc")
outputOnErrors <- addSimpleBoolFlag "" ["output-on-errors"] (flagHelp $ parDoc "even when there are errors, produce output (or try to to the degree possible") outputOnErrors <- addSimpleBoolFlag "" ["output-on-errors"] (flagHelp $ parDoc "even when there are errors, produce output (or try to to the degree possible)")
wError <- addSimpleBoolFlag "" ["werror"] (flagHelp $ parDoc "treat warnings as errors") wError <- addSimpleBoolFlag "" ["werror"] (flagHelp $ parDoc "treat warnings as errors")
omitValidCheck <- addSimpleBoolFlag "" ["omit-output-check"] (flagHelp $ parDoc "omit checking if the output is syntactically valid; for dev on brittany") omitValidCheck <- addSimpleBoolFlag "" ["omit-output-check"] (flagHelp $ parDoc "omit checking if the output is syntactically valid (debugging)")
roundtripOnly <- addSimpleBoolFlag "" ["exactprint-only"] (flagHelp $ parDoc "do not reformat, but exclusively use exactprint to roundtrip (debugging)") roundtripOnly <- addSimpleBoolFlag "" ["exactprint-only"] (flagHelp $ parDoc "do not reformat, but exclusively use exactprint to roundtrip (debugging)")
@ -156,6 +157,7 @@ configParser = do
, _lconfig_columnAlignMode = mempty , _lconfig_columnAlignMode = mempty
, _lconfig_alignmentLimit = mempty , _lconfig_alignmentLimit = mempty
, _lconfig_alignmentBreakOnMultiline = mempty , _lconfig_alignmentBreakOnMultiline = mempty
, _lconfig_hangingTypeSignature = mempty
} }
, _conf_errorHandling = ErrorHandlingConfig , _conf_errorHandling = ErrorHandlingConfig
{ _econf_produceOutputOnErrors = wrapLast $ falseToNothing outputOnErrors { _econf_produceOutputOnErrors = wrapLast $ falseToNothing outputOnErrors

View File

@ -73,6 +73,17 @@ data CLayoutConfig f = LayoutConfig
-- short <- some more stuff -- short <- some more stuff
-- that requires two lines -- that requires two lines
-- loooooooong <- stuff -- loooooooong <- stuff
, _lconfig_hangingTypeSignature :: f (Last Bool)
-- Do not put "::" in a new line, and use hanging indentation for the
-- signature, i.e.:
-- func :: SomeLongStuff
-- -> SomeLongStuff
-- instead of the usual
-- func
-- :: SomeLongStuff
-- -> SomeLongStuff
-- As usual for hanging indentation, the result will be
-- context-sensitive (in the function name).
} }
deriving (Generic) deriving (Generic)

View File

@ -24,11 +24,17 @@ import qualified DynFlags as GHC
import qualified GHC as GHC hiding (parseModule) import qualified GHC as GHC hiding (parseModule)
import qualified Parser as GHC import qualified Parser as GHC
import qualified SrcLoc as GHC import qualified SrcLoc as GHC
import qualified FastString as GHC
import qualified GHC as GHC hiding (parseModule)
import qualified Lexer as GHC
import qualified StringBuffer as GHC
import qualified Outputable as GHC
import RdrName ( RdrName(..) ) import RdrName ( RdrName(..) )
import HsSyn import HsSyn
import SrcLoc ( SrcSpan, Located ) import SrcLoc ( SrcSpan, Located )
import RdrName ( RdrName(..) ) import RdrName ( RdrName(..) )
import qualified Language.Haskell.GHC.ExactPrint as ExactPrint import qualified Language.Haskell.GHC.ExactPrint as ExactPrint
import qualified Language.Haskell.GHC.ExactPrint.Annotate as ExactPrint import qualified Language.Haskell.GHC.ExactPrint.Annotate as ExactPrint
import qualified Language.Haskell.GHC.ExactPrint.Types as ExactPrint import qualified Language.Haskell.GHC.ExactPrint.Types as ExactPrint
@ -37,6 +43,8 @@ import qualified Language.Haskell.GHC.ExactPrint.Preprocess as ExactPrint
import qualified Language.Haskell.GHC.ExactPrint.Delta as ExactPrint import qualified Language.Haskell.GHC.ExactPrint.Delta as ExactPrint
import qualified Data.Generics as SYB import qualified Data.Generics as SYB
import Control.Exception
-- import Data.Generics.Schemes -- import Data.Generics.Schemes
@ -85,7 +93,14 @@ parseModuleFromString
-> String -> String
-> IO (Either String (ExactPrint.Anns, GHC.ParsedSource, a)) -> IO (Either String (ExactPrint.Anns, GHC.ParsedSource, a))
parseModuleFromString args fp dynCheck str = parseModuleFromString args fp dynCheck str =
ExactPrint.ghcWrapper $ ExceptT.runExceptT $ do -- We mask here because otherwise using `throwTo` (i.e. for a timeout) will
-- produce nasty looking errors ("ghc panic"). The `mask_` makes it so we
-- cannot kill the parsing thread - not very nice. But i'll
-- optimistically assume that most of the time brittany uses noticable or
-- longer time, the majority of the time is not spend in parsing, but in
-- bridoc transformation stuff.
-- (reminder to update note on `parsePrintModule` if this changes.)
mask_ $ ExactPrint.ghcWrapper $ ExceptT.runExceptT $ do
dflags0 <- lift $ ExactPrint.initDynFlagsPure fp str dflags0 <- lift $ ExactPrint.initDynFlagsPure fp str
(dflags1, leftover, warnings) <- lift (dflags1, leftover, warnings) <- lift
$ GHC.parseDynamicFlagsCmdLine dflags0 (GHC.noLoc <$> args) $ GHC.parseDynamicFlagsCmdLine dflags0 (GHC.noLoc <$> args)
@ -97,12 +112,12 @@ parseModuleFromString args fp dynCheck str =
$ ExceptT.throwE $ ExceptT.throwE
$ "when parsing ghc flags: encountered warnings: " $ "when parsing ghc flags: encountered warnings: "
++ show (warnings <&> \(L _ s) -> s) ++ show (warnings <&> \(L _ s) -> s)
x <- ExceptT.ExceptT $ liftIO $ dynCheck dflags1 dynCheckRes <- ExceptT.ExceptT $ liftIO $ dynCheck dflags1
either (\(span, err) -> ExceptT.throwE $ show span ++ ": " ++ err) let res = ExactPrint.parseModuleFromStringInternal dflags1 fp str
(\(a, m) -> pure (a, m, x)) case res of
$ ExactPrint.parseWith dflags1 fp GHC.parseModule str Left (span, err) -> ExceptT.throwE $ show span ++ ": " ++ err
Right (a , m ) -> pure (a, m, dynCheckRes)
-----------
commentAnnFixTransformGlob :: SYB.Data ast => ast -> ExactPrint.Transform () commentAnnFixTransformGlob :: SYB.Data ast => ast -> ExactPrint.Transform ()
commentAnnFixTransformGlob ast = do commentAnnFixTransformGlob ast = do

View File

@ -52,6 +52,22 @@ layoutSig lsig@(L _loc sig) = case sig of
let nameStr = Text.intercalate (Text.pack ", ") $ nameStrs let nameStr = Text.intercalate (Text.pack ", ") $ nameStrs
typeDoc <- docSharedWrapper layoutType typ typeDoc <- docSharedWrapper layoutType typ
hasComments <- hasAnyCommentsBelow lsig hasComments <- hasAnyCommentsBelow lsig
shouldBeHanging <- mAsk
<&> _conf_layout
.> _lconfig_hangingTypeSignature
.> confUnpack
if shouldBeHanging
then docSeq
[ appSep $ docWrapNodeRest lsig $ docLit nameStr
, docSetBaseY $ docLines
[ docCols
ColTyOpPrefix
[ docLit $ Text.pack ":: "
, docAddBaseY (BrIndentSpecial 3) $ typeDoc
]
]
]
else
docAlt docAlt
$ [ docSeq $ [ docSeq
[ appSep $ docWrapNodeRest lsig $ docLit nameStr [ appSep $ docWrapNodeRest lsig $ docLit nameStr
@ -176,10 +192,11 @@ layoutPatternBind
-> BriDocNumbered -> BriDocNumbered
-> LMatch RdrName (LHsExpr RdrName) -> LMatch RdrName (LHsExpr RdrName)
-> ToBriDocM BriDocNumbered -> ToBriDocM BriDocNumbered
layoutPatternBind mIdStr binderDoc lmatch@(L _ match@(Match _ pats _ (GRHSs grhss whereBinds))) = do layoutPatternBind mIdStr binderDoc lmatch@(L _ match@(Match fixityOrCtx pats _ (GRHSs grhss whereBinds))) = do
patDocs <- pats `forM` \p -> fmap return $ colsWrapPat =<< layoutPat p patDocs <- pats `forM` \p -> fmap return $ colsWrapPat =<< layoutPat p
let isInfix = isInfixMatch match let isInfix = isInfixMatch match
patDoc <- docWrapNodePrior lmatch $ case (mIdStr, patDocs) of let mIdStr' = fixPatternBindIdentifier fixityOrCtx <$> mIdStr
patDoc <- docWrapNodePrior lmatch $ case (mIdStr', patDocs) of
(Just idStr, p1 : pr) | isInfix -> docCols (Just idStr, p1 : pr) | isInfix -> docCols
ColPatternsFuncInfix ColPatternsFuncInfix
( [appSep $ docForceSingleline p1, appSep $ docLit idStr] ( [appSep $ docForceSingleline p1, appSep $ docLit idStr]
@ -204,6 +221,28 @@ layoutPatternBind mIdStr binderDoc lmatch@(L _ match@(Match _ pats _ (GRHSs grhs
mWhereDocs mWhereDocs
hasComments hasComments
#if MIN_VERSION_ghc(8,2,0) /* ghc-8.2 */
fixPatternBindIdentifier
:: HsMatchContext (NameOrRdrName RdrName) -> Text -> Text
fixPatternBindIdentifier ctx idStr = case ctx of
(FunRhs _ _ SrcLazy ) -> Text.cons '~' idStr
(FunRhs _ _ SrcStrict ) -> Text.cons '!' idStr
(FunRhs _ _ NoSrcStrict) -> idStr
(StmtCtxt ctx1 ) -> fixPatternBindIdentifier' ctx1
_ -> idStr
where
-- I have really no idea if this path ever occurs, but better safe than
-- risking another "drop bangpatterns" bugs.
fixPatternBindIdentifier' = \case
(PatGuard ctx1) -> fixPatternBindIdentifier ctx1 idStr
(ParStmtCtxt ctx1) -> fixPatternBindIdentifier' ctx1
(TransStmtCtxt ctx1) -> fixPatternBindIdentifier' ctx1
_ -> idStr
#else /* ghc-8.0 */
fixPatternBindIdentifier :: MatchFixity RdrName -> Text -> Text
fixPatternBindIdentifier _ x = x
#endif
layoutPatternBindFinal layoutPatternBindFinal
:: Maybe Text :: Maybe Text
-> BriDocNumbered -> BriDocNumbered
@ -261,10 +300,13 @@ layoutPatternBindFinal alignmentToken binderDoc mPatDoc clauseDocs mWhereDocs ha
] ]
let singleLineGuardsDoc guards = appSep $ case guards of let singleLineGuardsDoc guards = appSep $ case guards of
[] -> docEmpty [] -> docEmpty
[g] -> docSeq [appSep $ docLit $ Text.pack "|", return g] [g] -> docSeq
[appSep $ docLit $ Text.pack "|", docForceSingleline $ return g]
gs -> docSeq gs -> docSeq
$ [appSep $ docLit $ Text.pack "|"] $ [appSep $ docLit $ Text.pack "|"]
++ List.intersperse docCommaSep (return <$> gs) ++ (List.intersperse docCommaSep
(docForceSingleline . return <$> gs)
)
indentPolicy <- mAsk indentPolicy <- mAsk
<&> _conf_layout <&> _conf_layout

View File

@ -327,7 +327,7 @@ layoutExpr lexpr@(L _ expr) = do
] ]
, docSetBaseY $ docLines , docSetBaseY $ docLines
[ docCols ColOpPrefix [ docCols ColOpPrefix
[ docParenLSep [ docLit $ Text.pack "("
, docAddBaseY (BrIndentSpecial 2) innerExpDoc , docAddBaseY (BrIndentSpecial 2) innerExpDoc
] ]
, docLit $ Text.pack ")" , docLit $ Text.pack ")"
@ -341,9 +341,9 @@ layoutExpr lexpr@(L _ expr) = do
opDoc <- docSharedWrapper layoutExpr op opDoc <- docSharedWrapper layoutExpr op
rightDoc <- docSharedWrapper layoutExpr right rightDoc <- docSharedWrapper layoutExpr right
docSeq [opDoc, docSeparator, rightDoc] docSeq [opDoc, docSeparator, rightDoc]
ExplicitTuple args boxity ExplicitTuple args boxity -> do
| Just argExprs <- args `forM` (\case (L _ (Present e)) -> Just e; _ -> Nothing) -> do let argExprs = fmap (\case (L _ (Present e)) -> Just e; (L _ (Missing PlaceHolder)) -> Nothing) args
argDocs <- docSharedWrapper layoutExpr `mapM` argExprs argDocs <- docSharedWrapper (maybe docEmpty layoutExpr) `mapM` argExprs
hasComments <- hasAnyCommentsBelow lexpr hasComments <- hasAnyCommentsBelow lexpr
let (openLit, closeLit) = case boxity of let (openLit, closeLit) = case boxity of
Boxed -> (docLit $ Text.pack "(", docLit $ Text.pack ")") Boxed -> (docLit $ Text.pack "(", docLit $ Text.pack ")")
@ -385,8 +385,6 @@ layoutExpr lexpr@(L _ expr) = do
end = closeLit end = closeLit
in docSetBaseY $ docLines $ [start] ++ linesM ++ [lineN] ++ [end] in docSetBaseY $ docLines $ [start] ++ linesM ++ [lineN] ++ [end]
] ]
ExplicitTuple{} ->
unknownNodeError "ExplicitTuple|.." lexpr
HsCase cExp (MG lmatches@(L _ matches) _ _ _) -> do HsCase cExp (MG lmatches@(L _ matches) _ _ _) -> do
cExpDoc <- docSharedWrapper layoutExpr cExp cExpDoc <- docSharedWrapper layoutExpr cExp
binderDoc <- docLit $ Text.pack "->" binderDoc <- docLit $ Text.pack "->"
@ -533,6 +531,10 @@ layoutExpr lexpr@(L _ expr) = do
HsLet binds exp1 -> do HsLet binds exp1 -> do
expDoc1 <- docSharedWrapper layoutExpr exp1 expDoc1 <- docSharedWrapper layoutExpr exp1
mBindDocs <- layoutLocalBinds binds mBindDocs <- layoutLocalBinds binds
let
ifIndentLeftElse :: a -> a -> a
ifIndentLeftElse x y =
if indentPolicy == IndentPolicyLeft then x else y
-- this `docSetIndentLevel` might seem out of place, but is here due to -- this `docSetIndentLevel` might seem out of place, but is here due to
-- ghc-exactprint's DP handling of "let" in particular. -- ghc-exactprint's DP handling of "let" in particular.
-- Just pushing another indentation level is a straightforward approach -- Just pushing another indentation level is a straightforward approach
@ -540,39 +542,36 @@ layoutExpr lexpr@(L _ expr) = do
-- if "let" is moved horizontally as part of the transformation, as the -- if "let" is moved horizontally as part of the transformation, as the
-- comments before the first let item are moved horizontally with it. -- comments before the first let item are moved horizontally with it.
docSetIndentLevel $ case mBindDocs of docSetIndentLevel $ case mBindDocs of
Just [bindDoc] -> docAltFilter Just [bindDoc] -> docAlt
[ ( True [ docSeq
, docSeq
[ appSep $ docLit $ Text.pack "let" [ appSep $ docLit $ Text.pack "let"
, appSep $ docForceSingleline $ return bindDoc , appSep $ docForceSingleline $ return bindDoc
, appSep $ docLit $ Text.pack "in" , appSep $ docLit $ Text.pack "in"
, docForceSingleline $ expDoc1 , docForceSingleline $ expDoc1
] ]
)
, ( indentPolicy /= IndentPolicyLeft
, docLines , docLines
[ docAlt
[ docSeq [ docSeq
[ appSep $ docLit $ Text.pack "let" [ appSep $ docLit $ Text.pack "let"
, docSetBaseAndIndent $ return bindDoc , ifIndentLeftElse docForceSingleline docSetBaseAndIndent
$ return bindDoc
] ]
, docSeq
[ appSep $ docLit $ Text.pack "in "
, docSetBaseY $ expDoc1
]
]
)
, ( True
, docLines
[ docAddBaseY BrIndentRegular
$ docPar
(appSep $ docLit $ Text.pack "let")
(docSetBaseAndIndent $ return bindDoc)
, docAddBaseY BrIndentRegular , docAddBaseY BrIndentRegular
$ docPar $ docPar
(appSep $ docLit $ Text.pack "in") (docLit $ Text.pack "let")
(docSetBaseAndIndent $ return bindDoc)
]
, docAlt
[ docSeq
[ appSep $ docLit $ Text.pack $ ifIndentLeftElse "in" "in "
, ifIndentLeftElse docForceSingleline docSetBaseAndIndent expDoc1
]
, docAddBaseY BrIndentRegular
$ docPar
(docLit $ Text.pack "in")
(docSetBaseY $ expDoc1) (docSetBaseY $ expDoc1)
] ]
) ]
] ]
Just bindDocs@(_:_) -> docAltFilter Just bindDocs@(_:_) -> docAltFilter
--either --either

View File

@ -24,12 +24,26 @@ import Language.Haskell.Brittany.Internal.Layouters.Type
-- | layouts patterns (inside function bindings, case alternatives, let
-- bindings or do notation). E.g. for input
-- > case computation of
-- > (warnings, Success a b) -> ..
-- This part ^^^^^^^^^^^^^^^^^^^^^^^ of the syntax tree is layouted by
-- 'layoutPat'. Similarly for
-- > func abc True 0 = []
-- ^^^^^^^^^^ this part
-- We will use `case .. of` as the imagined prefix to the examples used in
-- the different cases below.
layoutPat :: ToBriDocC (Pat RdrName) (Seq BriDocNumbered) layoutPat :: ToBriDocC (Pat RdrName) (Seq BriDocNumbered)
layoutPat lpat@(L _ pat) = docWrapNode lpat $ case pat of layoutPat lpat@(L _ pat) = docWrapNode lpat $ case pat of
WildPat _ -> fmap Seq.singleton $ docLit $ Text.pack "_" WildPat _ -> fmap Seq.singleton $ docLit $ Text.pack "_"
-- _ -> expr
VarPat n -> fmap Seq.singleton $ docLit $ lrdrNameToText n VarPat n -> fmap Seq.singleton $ docLit $ lrdrNameToText n
-- abc -> expr
LitPat lit -> fmap Seq.singleton $ allocateNode $ litBriDoc lit LitPat lit -> fmap Seq.singleton $ allocateNode $ litBriDoc lit
-- 0 -> expr
ParPat inner -> do ParPat inner -> do
-- (nestedpat) -> expr
left <- docLit $ Text.pack "(" left <- docLit $ Text.pack "("
right <- docLit $ Text.pack ")" right <- docLit $ Text.pack ")"
innerDocs <- colsWrapPat =<< layoutPat inner innerDocs <- colsWrapPat =<< layoutPat inner
@ -49,6 +63,7 @@ layoutPat lpat@(L _ pat) = docWrapNode lpat $ case pat of
-- xN' <- docSeq [return xN, docLit $ Text.pack ")"] -- xN' <- docSeq [return xN, docLit $ Text.pack ")"]
-- return $ (x1' Seq.<| middle) Seq.|> xN' -- return $ (x1' Seq.<| middle) Seq.|> xN'
ConPatIn lname (PrefixCon args) -> do ConPatIn lname (PrefixCon args) -> do
-- Abc a b c -> expr
let nameDoc = lrdrNameToText lname let nameDoc = lrdrNameToText lname
argDocs <- layoutPat `mapM` args argDocs <- layoutPat `mapM` args
if null argDocs if null argDocs
@ -61,15 +76,19 @@ layoutPat lpat@(L _ pat) = docWrapNode lpat $ case pat of
$ fmap colsWrapPat argDocs $ fmap colsWrapPat argDocs
return $ x1 Seq.<| xR return $ x1 Seq.<| xR
ConPatIn lname (InfixCon left right) -> do ConPatIn lname (InfixCon left right) -> do
let nameDoc = lrdrNameToText lname -- a :< b -> expr
leftDoc <- colsWrapPat =<< layoutPat left nameDoc <- lrdrNameToTextAnn lname
leftDoc <- appSep . colsWrapPat =<< layoutPat left
rightDoc <- colsWrapPat =<< layoutPat right rightDoc <- colsWrapPat =<< layoutPat right
middle <- docLit nameDoc middle <- appSep $ docLit nameDoc
return $ Seq.empty Seq.|> leftDoc Seq.|> middle Seq.|> rightDoc return $ Seq.empty Seq.|> leftDoc Seq.|> middle Seq.|> rightDoc
ConPatIn lname (RecCon (HsRecFields [] Nothing)) -> do ConPatIn lname (RecCon (HsRecFields [] Nothing)) -> do
-- Abc{} -> expr
let t = lrdrNameToText lname let t = lrdrNameToText lname
fmap Seq.singleton $ docLit $ t <> Text.pack "{}" fmap Seq.singleton $ docLit $ t <> Text.pack "{}"
ConPatIn lname (RecCon (HsRecFields fs@(_:_) Nothing)) -> do ConPatIn lname (RecCon (HsRecFields fs@(_:_) Nothing)) -> do
-- Abc { a = locA, b = locB, c = locC } -> expr1
-- Abc { a, b, c } -> expr2
let t = lrdrNameToText lname let t = lrdrNameToText lname
fds <- fs `forM` \(L _ (HsRecField (L _ (FieldOcc lnameF _)) fPat pun)) -> do fds <- fs `forM` \(L _ (HsRecField (L _ (FieldOcc lnameF _)) fPat pun)) -> do
fExpDoc <- if pun fExpDoc <- if pun
@ -91,12 +110,14 @@ layoutPat lpat@(L _ pat) = docWrapNode lpat $ case pat of
, docLit $ Text.pack "}" , docLit $ Text.pack "}"
] ]
ConPatIn lname (RecCon (HsRecFields [] (Just 0))) -> do ConPatIn lname (RecCon (HsRecFields [] (Just 0))) -> do
-- Abc { .. } -> expr
let t = lrdrNameToText lname let t = lrdrNameToText lname
fmap Seq.singleton $ docSeq fmap Seq.singleton $ docSeq
[ appSep $ docLit t [ appSep $ docLit t
, docLit $ Text.pack "{..}" , docLit $ Text.pack "{..}"
] ]
ConPatIn lname (RecCon (HsRecFields fs@(_:_) (Just dotdoti))) | dotdoti == length fs -> do ConPatIn lname (RecCon (HsRecFields fs@(_:_) (Just dotdoti))) | dotdoti == length fs -> do
-- Abc { a = locA, .. }
let t = lrdrNameToText lname let t = lrdrNameToText lname
fds <- fs `forM` \(L _ (HsRecField (L _ (FieldOcc lnameF _)) fPat pun)) -> do fds <- fs `forM` \(L _ (HsRecField (L _ (FieldOcc lnameF _)) fPat pun)) -> do
fExpDoc <- if pun fExpDoc <- if pun
@ -117,16 +138,20 @@ layoutPat lpat@(L _ pat) = docWrapNode lpat $ case pat of
, docLit $ Text.pack "..}" , docLit $ Text.pack "..}"
] ]
TuplePat args boxity _ -> do TuplePat args boxity _ -> do
-- (nestedpat1, nestedpat2, nestedpat3) -> expr
-- (#nestedpat1, nestedpat2, nestedpat3#) -> expr
case boxity of case boxity of
Boxed -> wrapPatListy args "(" ")" Boxed -> wrapPatListy args "(" ")"
Unboxed -> wrapPatListy args "(#" "#)" Unboxed -> wrapPatListy args "(#" "#)"
AsPat asName asPat -> do AsPat asName asPat -> do
-- bind@nestedpat -> expr
wrapPatPrepend asPat (docLit $ lrdrNameToText asName <> Text.pack "@") wrapPatPrepend asPat (docLit $ lrdrNameToText asName <> Text.pack "@")
#if MIN_VERSION_ghc(8,2,0) /* ghc-8.2 */ #if MIN_VERSION_ghc(8,2,0) /* ghc-8.2 */
SigPatIn pat1 (HsWC _ (HsIB _ ty1 _)) -> do SigPatIn pat1 (HsWC _ (HsIB _ ty1 _)) -> do
#else /* ghc-8.0 */ #else /* ghc-8.0 */
SigPatIn pat1 (HsIB _ (HsWC _ _ ty1)) -> do SigPatIn pat1 (HsIB _ (HsWC _ _ ty1)) -> do
#endif #endif
-- i :: Int -> expr
patDocs <- layoutPat pat1 patDocs <- layoutPat pat1
tyDoc <- docSharedWrapper layoutType ty1 tyDoc <- docSharedWrapper layoutType ty1
case Seq.viewr patDocs of case Seq.viewr patDocs of
@ -146,12 +171,17 @@ layoutPat lpat@(L _ pat) = docWrapNode lpat $ case pat of
] ]
return $ xR Seq.|> xN' return $ xR Seq.|> xN'
ListPat elems _ _ -> ListPat elems _ _ ->
-- [] -> expr1
-- [nestedpat1, nestedpat2, nestedpat3] -> expr2
wrapPatListy elems "[" "]" wrapPatListy elems "[" "]"
BangPat pat1 -> do BangPat pat1 -> do
-- !nestedpat -> expr
wrapPatPrepend pat1 (docLit $ Text.pack "!") wrapPatPrepend pat1 (docLit $ Text.pack "!")
LazyPat pat1 -> do LazyPat pat1 -> do
-- ~nestedpat -> expr
wrapPatPrepend pat1 (docLit $ Text.pack "~") wrapPatPrepend pat1 (docLit $ Text.pack "~")
NPat llit@(L _ (OverLit olit _ _ _)) mNegative _ _ -> do NPat llit@(L _ (OverLit olit _ _ _)) mNegative _ _ -> do
-- -13 -> expr
litDoc <- docWrapNode llit $ allocateNode $ overLitValBriDoc olit litDoc <- docWrapNode llit $ allocateNode $ overLitValBriDoc olit
negDoc <- docLit $ Text.pack "-" negDoc <- docLit $ Text.pack "-"
pure $ case mNegative of pure $ case mNegative of

View File

@ -46,6 +46,9 @@ traceFunctionWith name s1 s2 f x =
putStrErrLn :: String -> IO () putStrErrLn :: String -> IO ()
putStrErrLn s = hPutStrLn stderr s putStrErrLn s = hPutStrLn stderr s
putStrErr :: String -> IO ()
putStrErr s = hPutStr stderr s
printErr :: Show a => a -> IO () printErr :: Show a => a -> IO ()
printErr = putStrErrLn . show printErr = putStrErrLn . show

12
stack-8.0.2.yaml Normal file
View File

@ -0,0 +1,12 @@
resolver: lts-9.0
extra-deps:
- monad-memo-0.4.1
- czipwith-1.0.0.0
- butcher-1.3.0.0
- data-tree-print-0.1.0.0
- deque-0.2
- ghc-exactprint-0.5.6.0
packages:
- .

View File

@ -1,11 +1,4 @@
resolver: lts-9.0 resolver: lts-10.0
extra-deps:
- monad-memo-0.4.1
- czipwith-1.0.0.0
- butcher-1.2.0.0
- data-tree-print-0.1.0.0
- deque-0.2
packages: packages:
- . - .