stablememo

stablename
Lennart Spitzner 2016-07-24 23:14:00 +02:00
commit 5e9744ad15
29 changed files with 7492 additions and 0 deletions

11
.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
*.prof
*.aux
*.eventlog
*.hp
*.ps
/*.pdf
dist/
local/
.cabal-sandbox/
.stack-work/
cabal.sandbox.config

5
ChangeLog.md Normal file
View File

@ -0,0 +1,5 @@
# Revision history for brittany
## 0.1.0.0 -- YYYY-mm-dd
* First version. Released on an unsuspecting world.

2
Setup.hs Normal file
View File

@ -0,0 +1,2 @@
import Distribution.Simple
main = defaultMain

232
brittany.cabal Normal file
View File

@ -0,0 +1,232 @@
name: brittany
version: 0.1.0.0
-- synopsis:
-- description:
license: AllRightsReserved
-- license-file: LICENSE
author: Lennart Spitzner
maintainer: lsp@informatik.uni-kiel.de
-- copyright:
category: Language
build-type: Simple
extra-source-files: ChangeLog.md
cabal-version: >=1.10
flag brittany-dev
description: dev options
default: False
flag brittany-dev-lib
description: set buildable false for anything but lib
default: False
library {
default-language:
Haskell2010
hs-source-dirs:
src
exposed-modules: {
Language.Haskell.Brittany.Prelude
Language.Haskell.Brittany
Language.Haskell.Brittany.Types
Language.Haskell.Brittany.Utils
Language.Haskell.Brittany.Config
Language.Haskell.Brittany.Config.Types
Language.Haskell.Brittany.LayoutBasics
Language.Haskell.Brittany.BriLayouter
Language.Haskell.Brittany.Layouters.Type
Language.Haskell.Brittany.Layouters.Decl
Language.Haskell.Brittany.Layouters.Expr
Language.Haskell.Brittany.Layouters.Stmt
Language.Haskell.Brittany.Layouters.Pattern
}
ghc-options: {
-Wall
-fprof-auto -fprof-cafs -fno-spec-constr
-j
-fno-warn-unused-imports
-fno-warn-orphans
}
if flag(brittany-dev) {
ghc-options: -O0 -Werror -fobject-code
}
build-depends:
{ base >=4.9 && <4.10
-- , ghc-parser >=0.1 && <0.2
, ghc
, ghc-paths
, ghc-exactprint
, stable-memo
, transformers
, containers
, qualified-prelude
, mtl
, text
, multistate
, syb
, neat-interpolation
, hspec
, data-tree-print
, pretty
, bytestring
, directory
, lens
, butcher
, yaml
, extra
, uniplate
, strict
, unsafe
}
default-extensions: {
CPP
NoImplicitPrelude
GADTs
FlexibleContexts
FlexibleInstances
ScopedTypeVariables
MonadComprehensions
LambdaCase
MultiWayIf
KindSignatures
}
include-dirs:
srcinc
}
executable brittany
if flag(brittany-dev-lib) {
buildable: False
} else {
buildable: True
}
main-is: Main.hs
-- other-modules:
-- other-extensions:
build-depends:
{ brittany
, base >=4.9 && <4.10
-- , ghc-parser >=0.1 && <0.2
, ghc
, ghc-paths
, ghc-exactprint
, stable-memo
, transformers
, containers
, qualified-prelude
, mtl
, text
, multistate
, syb
, neat-interpolation
, hspec
, data-tree-print
, pretty
, bytestring
, directory
, lens
, butcher
, yaml
, extra
, uniplate
, strict
}
hs-source-dirs: src-brittany
default-language: Haskell2010
default-extensions: {
CPP
NoImplicitPrelude
GADTs
FlexibleContexts
FlexibleInstances
ScopedTypeVariables
MonadComprehensions
LambdaCase
MultiWayIf
KindSignatures
}
ghc-options: {
-Wall
-fprof-auto -fprof-cafs -fno-spec-constr
-j
-fno-warn-unused-imports
-fno-warn-orphans
-rtsopts
}
if flag(brittany-dev) {
ghc-options: -O0 -Werror -fobject-code
}
test-suite unittests
if flag(brittany-dev-lib) {
buildable: False
} else {
buildable: True
}
type: exitcode-stdio-1.0
default-language: Haskell2010
build-depends:
{ brittany
, base >=4.9 && <4.10
-- , ghc-parser >=0.1 && <0.2
, ghc
, ghc-paths
, ghc-exactprint
, stable-memo
, transformers
, containers
, qualified-prelude
, mtl
, text
, multistate
, syb
, neat-interpolation
, hspec
, data-tree-print
, pretty
, bytestring
, directory
, lens
, butcher
, yaml
, extra
, uniplate
, strict
}
ghc-options: -Wall
main-is: TestMain.hs
other-modules: IdentityTests
TestUtils
AsymptoticPerfTests
hs-source-dirs: src-unittests
default-extensions: {
CPP
NoImplicitPrelude
GADTs
FlexibleContexts
FlexibleInstances
ScopedTypeVariables
MonadComprehensions
LambdaCase
MultiWayIf
KindSignatures
}
ghc-options: {
-Wall
-fprof-auto -fprof-cafs -fno-spec-constr
-j
-fno-warn-unused-imports
-fno-warn-orphans
}
if flag(brittany-dev) {
ghc-options: -O0 -Werror -fobject-code
}

205
src-brittany/Main.hs Normal file
View File

@ -0,0 +1,205 @@
{-# LANGUAGE DataKinds #-}
module Main where
#include "prelude.inc"
import DynFlags ( getDynFlags )
import GHC ( runGhc, GenLocated(L), moduleNameString )
import qualified Parser as GHC.Parser
import RdrName ( RdrName(..) )
import Control.Monad.IO.Class
import GHC.Paths (libdir)
import HsSyn
import SrcLoc ( SrcSpan, Located )
-- import Outputable ( ppr, runSDoc )
-- import DynFlags ( unsafeGlobalDynFlags )
import qualified Language.Haskell.GHC.ExactPrint as ExactPrint
import qualified Language.Haskell.GHC.ExactPrint.Annotate as ExactPrint.Annotate
import qualified Language.Haskell.GHC.ExactPrint.Types as ExactPrint.Types
import qualified Language.Haskell.GHC.ExactPrint.Parsers as ExactPrint.Parsers
import qualified Data.Map as Map
import qualified Data.Text.Lazy.Builder as Text.Builder
import qualified Debug.Trace as Trace
import Language.Haskell.Brittany.Types
import Language.Haskell.Brittany.LayoutBasics
import Language.Haskell.Brittany
import Language.Haskell.Brittany.Config
import Language.Haskell.Brittany.Config.Types
import Language.Haskell.Brittany.Utils
import qualified Text.PrettyPrint as PP
import DataTreePrint
import UI.Butcher.Monadic
import qualified System.Exit
import Paths_brittany
main :: IO ()
main = mainFromCmdParser mainCmdParser
mainCmdParser :: CmdParser Identity (IO ()) ()
mainCmdParser = do
addCmdSynopsis "haskell source pretty printer"
addCmdHelp $ PP.vcat $ List.intersperse (PP.text "")
[ parDoc $ "Transforms one haskell module by reformatting"
++ " (parts of) the source code, while preserving the"
++ " parts not transformed."
++ " Especially, comments are preserved completely"
++ " and newlines are in many cases."
, parDoc $ "Based on ghc-exactprint, thus supporting all that"
++ " ghc does."
]
-- addCmd "debugArgs" $ do
addHelpCommand
-- addButcherDebugCommand
reorderStart
printHelp <- addSimpleBoolFlag "" ["help"] mempty
printVersion <- addSimpleBoolFlag "" ["version"] mempty
inputPaths <- addFlagStringParam "i" ["input"] "PATH" (flagHelpStr "path to input haskell source file")
outputPaths <- addFlagStringParam "o" ["output"] "PATH" (flagHelpStr "output file path")
configPaths <- addFlagStringParam "" ["config-file"] "PATH" (flagHelpStr "path to config file") -- TODO: allow default on addFlagStringParam ?
cmdlineConfig <- configParser
suppressOutput <- addSimpleBoolFlag "" ["suppress-output"] (flagHelp $ parDoc "suppress the regular output, i.e. the transformed haskell source")
_verbosity <- addSimpleCountFlag "v" ["verbose"] (flagHelp $ parDoc "[currently without effect; TODO]")
reorderStop
desc <- peekCmdDesc
addCmdImpl $ void $ do
when printVersion $ do
liftIO $ putStrLn $ "brittany version " ++ showVersion version
System.Exit.exitSuccess
when printHelp $ do
liftIO $ print $ ppHelpShallow desc
System.Exit.exitSuccess
-- runGhc (Just libdir) $ do
-- dynflags <- getDynFlags
-- input <- liftIO $ readFile "local/Sample.hs"
-- let parseOutput = runParser dynflags parserModule input
-- liftIO $ case parseOutput of
-- Failure msg strloc -> do
-- putStrLn "some failed parse"
-- putStrLn msg
-- print strloc
-- Parsed a -> putStrLn "some successful parse."
-- Partial a (x,y) -> do
-- putStrLn "some partial parse"
-- print x
-- print y
inputPathM <- case inputPaths of
[] -> do
return Nothing
[x] -> return $ Just x
_ -> do
liftIO $ putStrLn $ "more than one input, aborting"
System.Exit.exitWith (System.Exit.ExitFailure 50)
outputPath <- case outputPaths of
[] -> do
return Nothing
[x] -> return $ Just x
_ -> do
liftIO $ putStrLn $ "more than one output, aborting"
System.Exit.exitWith (System.Exit.ExitFailure 50)
let configPath = maybe "brittany.yaml" id $ listToMaybe $ reverse configPaths
config <- do
may <- runMaybeT $ readMergePersConfig cmdlineConfig configPath
case may of
Nothing -> System.Exit.exitWith (System.Exit.ExitFailure 50)
Just x -> return x
when (runIdentity $ _dconf_dump_config $ _conf_debug $ config) $ do
trace (showTree config) $ return ()
liftIO $ do
parseResult <- case inputPathM of
Nothing -> ExactPrint.Parsers.parseModuleFromString "stdin"
=<< System.IO.hGetContents System.IO.stdin
Just p -> ExactPrint.parseModule p
case parseResult of
Left left -> do
putStrLn "parse error:"
print left
System.Exit.exitWith (System.Exit.ExitFailure 60)
Right (anns, parsedSource) -> do
when (config & _conf_debug .> _dconf_dump_ast_full .> runIdentity) $ do
let val = printTreeWithCustom 100 (customLayouterF anns) parsedSource
trace ("---- ast ----\n" ++ show val) $ return ()
-- mapM_ print (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 (errsWarns, outLText) = pPrintModule config anns parsedSource
let customErrOrder LayoutWarning{} = 0 :: Int
customErrOrder LayoutErrorUnusedComment{} = 1
customErrOrder LayoutErrorUnknownNode{} = 2
when (not $ null errsWarns) $ do
let groupedErrsWarns = Data.List.Extra.groupOn customErrOrder
$ List.sortOn customErrOrder
$ errsWarns
groupedErrsWarns `forM_` \case
uns@(LayoutErrorUnknownNode{}:_) -> do
putStrLn $ "ERROR: encountered unknown syntactical constructs:"
uns `forM_` \case
LayoutErrorUnknownNode str ast -> do
putStrLn str
putStrLn $ " " ++ show (astToDoc ast)
_ -> error "cannot happen (TM)"
warns@(LayoutWarning{}:_) -> do
putStrLn $ "WARNINGS:"
warns `forM_` \case
LayoutWarning str -> putStrLn str
_ -> error "cannot happen (TM)"
unused@(LayoutErrorUnusedComment{}:_) -> do
putStrLn $ "Error: detected unprocessed comments. the transformation "
++ "output will most likely not contain certain of the comments "
++ "present in the input haskell source file."
putStrLn $ "Affected are the following comments:"
unused `forM_` \case
LayoutErrorUnusedComment str -> putStrLn str
_ -> error "cannot happen (TM)"
[] -> error "cannot happen"
-- TODO: don't output anything when there are errors unless user
-- adds some override?
let hasErrors = case config
& _conf_errorHandling
& _econf_Werror
& runIdentity of
False -> 0 < maximum (-1 : fmap customErrOrder errsWarns)
True -> not $ null errsWarns
outputOnErrs = config
& _conf_errorHandling
& _econf_produceOutputOnErrors
& runIdentity
let shouldOutput = not suppressOutput
&& (not hasErrors || outputOnErrs)
when shouldOutput $ addTraceSep (_conf_debug config) $ case outputPath of
Nothing -> TextL.IO.putStr $ outLText
Just p -> TextL.IO.writeFile p $ outLText
when hasErrors $
System.Exit.exitWith (System.Exit.ExitFailure 70)
where
addTraceSep conf = if foldr1 (||)
[ runIdentity $ _dconf_dump_annotations conf
, runIdentity $ _dconf_dump_ast_unknown conf
, runIdentity $ _dconf_dump_ast_full conf
, runIdentity $ _dconf_dump_bridoc_raw conf
, runIdentity $ _dconf_dump_bridoc_simpl_alt conf
, runIdentity $ _dconf_dump_bridoc_simpl_floating conf
, runIdentity $ _dconf_dump_bridoc_simpl_columns conf
, runIdentity $ _dconf_dump_bridoc_simpl_indent conf
, runIdentity $ _dconf_dump_bridoc_final conf
]
then trace "----"
else id

4
src-idemtests/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
iterOne/
iterTwo/
brittany
report.txt

17
src-idemtests/README Normal file
View File

@ -0,0 +1,17 @@
idempotency testing on real-life examples, i.e. checks that brittany(x) is
equal to brittany(brittany(x)) for some x's. The idea is that these testcases
are not yet transformed, i.e. that x is not brittany(x). This can capture
certain bugs that are not detected by checking that brittany behaves as
identity on "well-formed" input.
to run:
- put a "brittany" executable into this directory.
- cd into this directory.
- ./run.sh
report.txt will contain the results.
note that only the configuration in brittany.yaml is tested, which contains
the default settings. ideally this would be managed in some other, more
transparent fashion.

View File

@ -0,0 +1,23 @@
_conf_errorHandling:
_econf_Werror: false
_econf_produceOutputOnErrors: false
_conf_layout:
_lconfig_indentPolicy: IndentPolicyFree
_lconfig_cols: 80
_lconfig_indentAmount: 2
_lconfig_importColumn: 60
_lconfig_altChooser: AltChooserShallowBest
_lconfig_indentWhereSpecial: true
_lconfig_indentListSpecial: true
_conf_debug:
_dconf_dump_annotations: false
_dconf_dump_bridoc_simpl_par: false
_dconf_dump_bridoc_simpl_indent: false
_dconf_dump_bridoc_simpl_floating: false
_dconf_dump_ast_full: false
_dconf_dump_bridoc_simpl_columns: false
_dconf_dump_ast_unknown: false
_dconf_dump_bridoc_simpl_alt: false
_dconf_dump_bridoc_final: false
_dconf_dump_bridoc_raw: false
_dconf_dump_config: false

View File

@ -0,0 +1,747 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE MonadComprehensions #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE KindSignatures #-}
module Language.Haskell.Brittany.LayoutBasics
( processDefault
, layoutByExact
-- , layoutByExactR
, descToBlockStart
, descToBlockMinMax
, descToMinMax
, rdrNameToText
, lrdrNameToText
, lrdrNameToTextAnn
, askIndent
, calcLayoutMin
, calcLayoutMax
, getCurRemaining
, layoutWriteAppend
, layoutWriteAppendMultiline
, layoutWriteNewline
, layoutWriteNewlinePlain
, layoutWriteEnsureNewline
, layoutWriteEnsureBlock
, layoutWriteEnsureBlockPlusN
, layoutWithAddIndent
, layoutWithAddIndentBlock
, layoutWithAddIndentN
, layoutWithAddIndentNBlock
, layoutWithNonParamIndent
, layoutWriteEnsureAbsoluteN
, layoutAddSepSpace
, moveToExactAnn
, moveToExactAnn'
, setOpIndent
, stringLayouter
, layoutWritePriorComments
, layoutWritePostComments
, layoutIndentRestorePostComment
, layoutWritePriorCommentsRestore
, layoutWritePostCommentsRestore
, extractCommentsPrior
, extractCommentsPost
, applyLayouter
, applyLayouterRestore
, filterAnns
, layouterFToLayouterM
, ppmMoveToExactLoc
, customLayouterF
, docEmpty
, docLit
, docAlt
, docSeq
, docPar
-- , docCols
, docPostComment
, docWrapNode
, briDocByExact
, fromMaybeIdentity
, foldedAnnKeys
)
where
-- more imports here..
import qualified Language.Haskell.GHC.ExactPrint as ExactPrint
import qualified Language.Haskell.GHC.ExactPrint.Annotate as ExactPrint.Annotate
import qualified Language.Haskell.GHC.ExactPrint.Types as ExactPrint.Types
import qualified Language.Haskell.GHC.ExactPrint.Utils as ExactPrint.Utils
import Language.Haskell.GHC.ExactPrint.Types ( AnnKey, Annotation )
import qualified Data.Text.Lazy.Builder as Text.Builder
import Language.Haskell.Brittany.Config.Types
import Language.Haskell.Brittany.Types
import Language.Haskell.Brittany.Utils
import RdrName ( RdrName(..) )
import GHC ( runGhc, GenLocated(L), moduleNameString )
import qualified Outputable as GHC
import qualified DynFlags as GHC
import qualified FastString as GHC
import qualified SrcLoc as GHC
import SrcLoc ( SrcSpan )
import OccName ( occNameString )
import Name ( getOccString )
import Module ( moduleName )
import ApiAnnotation ( AnnKeywordId(..) )
import Data.Data
import Data.Generics.Schemes
import Data.Generics.Aliases
import DataTreePrint
import qualified Text.PrettyPrint as PP
import Data.Function ( fix )
processDefault :: (ExactPrint.Annotate.Annotate ast, MonadMultiWriter
Text.Builder.Builder m,
MonadMultiReader ExactPrint.Types.Anns m)
=> GenLocated SrcSpan ast
-> m ()
processDefault x = do
anns <- mAsk
let str = ExactPrint.exactPrint x anns
-- this hack is here so our print-empty-module trick does not add
-- a newline at the start if there actually is no module header / imports
-- / anything.
-- TODO: instead the appropriate annotation could be removed when "cleaning"
-- the module (header). This would remove the need for this hack!
--test
case str of
"\n" -> return ()
_ -> mTell $ Text.Builder.fromString $ str
layoutByExact :: ( MonadMultiReader Config m
, MonadMultiReader (ExactPrint.Types.Anns) m
, ExactPrint.Annotate.Annotate ast
)
=> GenLocated SrcSpan ast -> m Layouter
layoutByExact x = do
anns <- mAsk
trace (showTreeWithCustom (customLayouterF anns) x) $ layoutByExactR x
-- trace (ExactPrint.Utils.showAnnData anns 2 x) $ layoutByExactR x
layoutByExactR :: (MonadMultiReader Config m
, MonadMultiReader (ExactPrint.Types.Anns) m
, ExactPrint.Annotate.Annotate ast)
=> GenLocated SrcSpan ast -> m Layouter
layoutByExactR x = do
indent <- askIndent
anns <- mAsk
let t = Text.pack $ ExactPrint.exactPrint x anns
let tlines = Text.lines $ t <> Text.pack "\n"
tlineCount = length tlines
let len = indent + maximum (Text.length <$> tlines)
return $ Layouter
{ _layouter_desc = LayoutDesc Nothing $ Just $ BlockDesc AllSameIndent len len Nothing
, _layouter_func = \_ -> do
-- layoutWriteEnsureBlock
layoutWriteAppend $ Text.pack $ "{-" ++ show (ExactPrint.Types.mkAnnKey x, Map.lookup (ExactPrint.Types.mkAnnKey x) anns) ++ "-}"
zip [1..] tlines `forM_` \(i, l) -> do
layoutWriteAppend $ l
unless (i==tlineCount) layoutWriteNewline
do
let subKeys = foldedAnnKeys x
state <- mGet
let filterF k _ = not $ k `Set.member` subKeys
mSet $ state
{ _lstate_commentsPrior = Map.filterWithKey filterF
$ _lstate_commentsPrior state
, _lstate_commentsPost = Map.filterWithKey filterF
$ _lstate_commentsPost state
}
, _layouter_ast = x
}
briDocByExact :: (ExactPrint.Annotate.Annotate ast,
MonadMultiReader Config m,
MonadMultiReader ExactPrint.Types.Anns m
) => GenLocated SrcSpan ast -> m BriDoc
briDocByExact ast = do
anns <- mAsk
traceIfDumpConf "ast" _dconf_dump_ast_unknown
(printTreeWithCustom 100 (customLayouterF anns) ast)
return $ docExt ast anns
descToBlockStart :: LayoutDesc -> Maybe BlockStart
descToBlockStart (LayoutDesc _ (Just (BlockDesc bs _ _ _))) = Just bs
descToBlockStart (LayoutDesc (Just line) _) = Just $ RestOfLine line
descToBlockStart _ = Nothing
descToBlockMinMax :: LayoutDesc -> Maybe (Int, Int)
descToBlockMinMax (LayoutDesc _ (Just (BlockDesc _ bmin bmax _))) = Just (bmin, bmax)
descToBlockMinMax _ = Nothing
descToMinMax :: Int -> LayoutDesc -> Maybe (Int, Int)
descToMinMax p (LayoutDesc _ (Just (BlockDesc start bmin bmax _))) =
Just (max rolMin bmin, max rolMin bmax)
where
rolMin = case start of
RestOfLine rol -> p + _lColumns_min rol
AllSameIndent -> 0
descToMinMax p (LayoutDesc (Just (LayoutColumns _ _ lmin)) _) =
Just (len, len)
where
len = p + lmin
descToMinMax _ _ =
Nothing
rdrNameToText :: RdrName -> Text
-- rdrNameToText = Text.pack . show . flip runSDoc unsafeGlobalDynFlags . ppr
rdrNameToText ( Unqual occname ) = Text.pack $ occNameString occname
rdrNameToText ( Qual mname occname ) = Text.pack $ moduleNameString mname
++ "."
++ occNameString occname
rdrNameToText ( Orig modul occname ) = Text.pack $ moduleNameString (moduleName modul)
++ occNameString occname
rdrNameToText ( Exact name ) = Text.pack $ getOccString name
lrdrNameToText :: GenLocated l RdrName -> Text
lrdrNameToText (L _ n) = rdrNameToText n
lrdrNameToTextAnn :: ( MonadMultiReader Config m
, MonadMultiReader (Map AnnKey Annotation) m
)
=> GenLocated SrcSpan RdrName
-> m Text
lrdrNameToTextAnn ast@(L _ n) = do
anns <- mAsk
let t = rdrNameToText n
let hasUni x (ExactPrint.Types.G y, _) = x==y
hasUni _ _ = False
-- TODO: in general: we should _always_ process all annotaiton stuff here.
-- whatever we don't probably should have had some effect on the
-- output. in such cases, resorting to byExact is probably the safe
-- choice.
return $ case Map.lookup (ExactPrint.Types.mkAnnKey ast) anns of
Nothing -> traceShow "Nothing" t
Just (ExactPrint.Types.Ann _ _ _ aks _ _) -> if
| any (hasUni AnnBackquote) aks -> Text.pack "`" <> t <> Text.pack "`"
| any (hasUni AnnOpenP) aks -> Text.pack "(" <> t <> Text.pack ")"
| otherwise -> t
askIndent :: (MonadMultiReader Config m) => m Int
askIndent = runIdentity . _lconfig_indentAmount . _conf_layout <$> mAsk
-- minimum block width, judged from block info or line, whichever is
-- available.
-- example: calcLayoutMin doBlock ~~~ atomically $ do
-- foo
-- ## indent
-- ############# linepre
-- ############### result (in this case)
calcLayoutMin :: Int -- basic indentation amount
-> Int -- currently used width in current line (after indent)
-- used to accurately calc placing of the current-line
-- stuff ("do" in the above example) and its width.
-> LayoutDesc
-> Int
calcLayoutMin indent linePre (LayoutDesc line block) = case (line, block) of
(_, Just (BlockDesc AllSameIndent m _ _)) -> indent + m
(_, Just (BlockDesc (RestOfLine inl) m _ _)) -> max (linePre + _lColumns_min inl) (indent + m)
(Just s, _) -> indent + _lColumns_min s
_ -> error "bad LayoutDesc mnasdoiucxvlkjasd"
-- see
calcLayoutMax :: Int -- basic indentation amount
-> Int -- currently used width in current line (after indent)
-- used to accurately calc placing of the current-line
-- stuff ("do" in the above example) and its width.
-> LayoutDesc
-> Int
calcLayoutMax indent linePre (LayoutDesc line block) = case (line, block) of
(Just s, _) -> linePre + _lColumns_min s
(_, Just (BlockDesc AllSameIndent _ m _)) -> indent + m
(_, Just (BlockDesc (RestOfLine inl) _ m _)) -> max (linePre + _lColumns_min inl) (indent + m)
_ -> error "bad LayoutDesc msdnfgouvadnfoiu"
getCurRemaining :: ( MonadMultiReader Config m
, MonadMultiState LayoutState m
)
=> m Int
getCurRemaining = do
cols <- mAsk <&> _conf_layout .> _lconfig_cols .> runIdentity
clc <- _lstate_curLineCols <$> mGet
return $ cols - clc
layoutWriteAppend :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m)
=> Text
-> m ()
layoutWriteAppend t = do
state <- mGet
if _lstate_addSepSpace state
then do
mSet $ state { _lstate_curLineCols = _lstate_curLineCols state + Text.length t + 1
, _lstate_addSepSpace = False
}
mTell $ Text.Builder.fromText $ Text.pack " " <> t
else do
mSet $ state { _lstate_curLineCols = _lstate_curLineCols state + Text.length t }
mTell $ Text.Builder.fromText t
layoutWriteAppendMultiline :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m)
=> Text
-> m ()
layoutWriteAppendMultiline t = case Text.lines t of
[] -> return ()
(l:lr) -> do
layoutWriteAppend l
lr `forM_` \x -> do
layoutWriteNewlinePlain
layoutWriteAppend x
-- adds a newline and adds spaces to reach the current indentation level.
-- TODO: rename newline -> newlineBlock and newlinePlain -> newline
layoutWriteNewline :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m)
=> m ()
layoutWriteNewline = do
state <- mGet
mSet $ state { _lstate_curLineCols = _lstate_indent state
, _lstate_commentCol = Nothing
, _lstate_addSepSpace = False
}
mTell $ Text.Builder.fromString $ "\n" ++ replicate (_lstate_indent state) ' '
-- | does _not_ add spaces to again reach the current indentation levels.
layoutWriteNewlinePlain :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m)
=> m ()
layoutWriteNewlinePlain = do
state <- mGet
mSet $ state { _lstate_curLineCols = 0
, _lstate_commentCol = Nothing
, _lstate_addSepSpace = False
}
mTell $ Text.Builder.fromString $ "\n"
layoutWriteEnsureNewline :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m)
=> m ()
layoutWriteEnsureNewline = do
state <- mGet
when (_lstate_curLineCols state /= _lstate_indent state)
$ layoutWriteNewline
layoutWriteEnsureBlock :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m)
=> m ()
layoutWriteEnsureBlock = do
state <- mGet
let diff = _lstate_curLineCols state - _lstate_indent state
if diff>0
then layoutWriteNewline
else if diff<0
then do
layoutWriteAppend $ Text.pack $ replicate (negate diff) ' '
mSet $ state { _lstate_curLineCols = _lstate_indent state
, _lstate_addSepSpace = False
}
else return ()
layoutWriteEnsureAbsoluteN :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m)
=> Int -> m ()
layoutWriteEnsureAbsoluteN n = do
state <- mGet
let diff = n - _lstate_curLineCols state
if diff>0
then do
layoutWriteAppend $ Text.pack $ replicate diff ' '
mSet $ state { _lstate_curLineCols = n
, _lstate_addSepSpace = False
}
else return ()
layoutWriteEnsureBlockPlusN :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m)
=> Int -> m ()
layoutWriteEnsureBlockPlusN n = do
state <- mGet
let diff = _lstate_curLineCols state - _lstate_indent state - n
if diff>0
then layoutWriteNewline
else if diff<0
then do
layoutWriteAppend $ Text.pack $ replicate (negate diff) ' '
mSet $ state { _lstate_addSepSpace = False }
else return ()
layoutWithAddIndent :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m
,MonadMultiReader Config m)
=> m ()
-> m ()
layoutWithAddIndent m = do
amount <- mAsk <&> _conf_layout .> _lconfig_indentAmount .> runIdentity
state <- mGet
mSet state { _lstate_indent = _lstate_indent state + amount }
m
do
s <- mGet
mSet $ s { _lstate_indent = _lstate_indent state }
layoutWithAddIndentBlock :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m
,MonadMultiReader Config m)
=> m ()
-> m ()
layoutWithAddIndentBlock m = do
amount <- mAsk <&> _conf_layout .> _lconfig_indentAmount .> runIdentity
state <- mGet
mSet state { _lstate_indent = _lstate_indent state + amount }
layoutWriteEnsureBlock
m
do
s <- mGet
mSet $ s { _lstate_indent = _lstate_indent state }
layoutWithAddIndentNBlock :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m)
=> Int
-> m ()
-> m ()
layoutWithAddIndentNBlock amount m = do
state <- mGet
mSet state { _lstate_indent = _lstate_indent state + amount }
layoutWriteEnsureBlock
m
do
s <- mGet
mSet $ s { _lstate_indent = _lstate_indent state }
layoutWithAddIndentN :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m)
=> Int
-> m ()
-> m ()
layoutWithAddIndentN amount m = do
state <- mGet
mSet state { _lstate_indent = _lstate_indent state + amount }
m
do
s <- mGet
mSet $ s { _lstate_indent = _lstate_indent state }
layoutAddSepSpace :: MonadMultiState LayoutState m => m ()
layoutAddSepSpace = do
state <- mGet
mSet $ state { _lstate_addSepSpace = True }
moveToExactAnn :: (Data.Data.Data x,
MonadMultiWriter Text.Builder.Builder m,
MonadMultiState LayoutState m,
MonadMultiReader (Map AnnKey Annotation) m) => GenLocated SrcSpan x -> m ()
moveToExactAnn ast = do
anns <- mAsk
case Map.lookup (ExactPrint.Types.mkAnnKey ast) anns of
Nothing -> return ()
Just ann -> do
let ExactPrint.Types.DP (x, _y) = ExactPrint.Types.annEntryDelta ann
replicateM_ x $ layoutWriteNewline
-- TODO: when refactoring is complete, the other version of this method
-- can probably be removed.
moveToExactAnn' :: (MonadMultiWriter Text.Builder.Builder m,
MonadMultiState LayoutState m,
MonadMultiReader (Map AnnKey Annotation) m) => AnnKey -> m ()
moveToExactAnn' annKey = do
anns <- mAsk
case Map.lookup annKey anns of
Nothing -> return ()
Just ann -> do
-- curY <- mGet <&> _lstate_curLineCols
let ExactPrint.Types.DP (x, _y) = ExactPrint.Types.annEntryDelta ann
replicateM_ x $ layoutWriteNewline
-- when (x/=0) $ do
-- replicateM_ x $ layoutWriteNewlinePlain
-- mModify $ \s -> s { _lstate_curLineCols = curY }
-- mTell $ Text.Builder.fromString $ replicate curY ' '
ppmMoveToExactLoc :: MonadMultiWriter Text.Builder.Builder m
=> ExactPrint.Types.DeltaPos
-> m ()
ppmMoveToExactLoc (ExactPrint.Types.DP (x,y)) = do
replicateM_ x $ mTell $ Text.Builder.fromString "\n"
replicateM_ y $ mTell $ Text.Builder.fromString " "
layoutWithNonParamIndent :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m)
=> LayoutFuncParams -> m () -> m ()
layoutWithNonParamIndent params m = do
case _params_opIndent params of
Nothing -> m
Just x -> layoutWithAddIndentN x m
setOpIndent :: Int -> LayoutDesc -> LayoutFuncParams -> LayoutFuncParams
setOpIndent i desc p = p
{ _params_opIndent = Just $ case _bdesc_opIndentFloatUp =<< _ldesc_block desc of
Nothing -> i
Just j -> max i j
}
stringLayouter :: Data.Data.Data ast
=> GenLocated SrcSpan ast -> Text -> Layouter
stringLayouter ast t = Layouter
{ _layouter_desc = LayoutDesc
{ _ldesc_line = Just $ LayoutColumns
{ _lColumns_key = ColumnKeyUnique
, _lColumns_lengths = [Text.length t]
, _lColumns_min = Text.length t
}
, _ldesc_block = Nothing
}
, _layouter_func = \_ -> do
layoutWritePriorCommentsRestore ast
layoutWriteAppend t
layoutWritePostComments ast
, _layouter_ast = ast
}
layoutWritePriorComments :: (Data.Data.Data ast,
MonadMultiWriter Text.Builder.Builder m,
MonadMultiState LayoutState m)
=> GenLocated SrcSpan ast -> m ()
layoutWritePriorComments ast = do
mAnn <- do
state <- mGet
let key = ExactPrint.Types.mkAnnKey ast
let m = _lstate_commentsPrior state
let mAnn = Map.lookup key m
mSet $ state { _lstate_commentsPrior = Map.delete key m }
return mAnn
case mAnn of
Nothing -> return ()
Just priors -> do
when (not $ null priors) $ do
state <- mGet
mSet $ state { _lstate_commentCol = Just $ _lstate_curLineCols state }
priors `forM_` \( ExactPrint.Types.Comment comment _ _
, ExactPrint.Types.DP (x, y)
) -> do
replicateM_ x layoutWriteNewlinePlain
layoutWriteAppend $ Text.pack $ replicate y ' '
layoutWriteAppendMultiline $ Text.pack $ comment
-- this currently only extracs from the `annsDP` field of Annotations.
-- per documentation, this seems sufficient, as the
-- "..`annFollowingComments` are only added by AST transformations ..".
layoutWritePostComments :: (Data.Data.Data ast,
MonadMultiWriter Text.Builder.Builder m,
MonadMultiState LayoutState m)
=> GenLocated SrcSpan ast -> m ()
layoutWritePostComments ast = do
mAnn <- do
state <- mGet
let key = ExactPrint.Types.mkAnnKey ast
let m = _lstate_commentsPost state
let mAnn = Map.lookup key m
mSet $ state { _lstate_commentsPost = Map.delete key m }
return mAnn
case mAnn of
Nothing -> return ()
Just posts -> do
when (not $ null posts) $ do
state <- mGet
mSet $ state { _lstate_commentCol = Just $ _lstate_curLineCols state }
posts `forM_` \( ExactPrint.Types.Comment comment _ _
, ExactPrint.Types.DP (x, y)
) -> do
replicateM_ x layoutWriteNewlinePlain
layoutWriteAppend $ Text.pack $ replicate y ' '
layoutWriteAppendMultiline $ Text.pack $ comment
layoutIndentRestorePostComment :: ( Monad m
, MonadMultiState LayoutState m
, MonadMultiWriter Text.Builder.Builder m
)
=> m ()
layoutIndentRestorePostComment = do
mCommentCol <- _lstate_commentCol <$> mGet
case mCommentCol of
Nothing -> return ()
Just commentCol -> do
layoutWriteNewlinePlain
layoutWriteAppend $ Text.pack $ replicate commentCol ' '
layoutWritePriorCommentsRestore :: (Data.Data.Data ast,
MonadMultiWriter Text.Builder.Builder m,
MonadMultiState LayoutState m)
=> GenLocated SrcSpan ast -> m ()
layoutWritePriorCommentsRestore x = do
layoutWritePriorComments x
layoutIndentRestorePostComment
layoutWritePostCommentsRestore :: (Data.Data.Data ast,
MonadMultiWriter Text.Builder.Builder m,
MonadMultiState LayoutState m)
=> GenLocated SrcSpan ast -> m ()
layoutWritePostCommentsRestore x = do
layoutWritePostComments x
layoutIndentRestorePostComment
extractCommentsPrior :: ExactPrint.Types.Anns -> PriorMap
extractCommentsPrior anns = flip Map.mapMaybe anns $ \ann ->
[r | let r = ExactPrint.Types.annPriorComments ann, not (null r)]
extractCommentsPost :: ExactPrint.Types.Anns -> PostMap
extractCommentsPost anns = flip Map.mapMaybe anns $ \ann ->
[r
| let
r = ExactPrint.Types.annsDP ann
>>= \case
(ExactPrint.Types.AnnComment comment, dp) -> [(comment, dp)]
_ -> []
, not (null r)
]
applyLayouter :: Layouter -> LayoutFuncParams -> LayoutM ()
applyLayouter l@(Layouter _ _ ast) params = do
-- (always) write the prior comments at this point.
layoutWritePriorCommentsRestore ast
-- run the real stuff.
_layouter_func l params
-- if the _layouter_func has not done so already at some point
-- (there are nodes for which this makes sense),
-- write the post comments.
-- effect is `return ()` if there are no postComments.
layoutWritePostComments ast
applyLayouterRestore :: Layouter -> LayoutFuncParams -> LayoutM ()
applyLayouterRestore l@(Layouter _ _ ast) params = do
-- (always) write the prior comments at this point.
layoutWritePriorCommentsRestore ast
-- run the real stuff.
_layouter_func l params
-- if the _layouter_func has not done so already at some point
-- (there are nodes for which this makes sense),
-- write the post comments.
-- effect is `return ()` if there are no postComments.
layoutWritePostCommentsRestore ast
foldedAnnKeys :: Data.Data.Data ast
=> ast
-> Set ExactPrint.Types.AnnKey
foldedAnnKeys ast = everything
Set.union
(\x -> maybe
Set.empty
Set.singleton
[ gmapQi 1 (\t -> ExactPrint.Types.mkAnnKey $ L l t) x
| typeRepTyCon (typeOf (L () ())) == (typeRepTyCon (typeOf x))
, l <- gmapQi 0 cast x
]
)
ast
filterAnns :: Data.Data.Data ast
=> ast
-> ExactPrint.Types.Anns
-> ExactPrint.Types.Anns
filterAnns ast anns =
Map.filterWithKey (\k _ -> k `Set.member` foldedAnnKeys ast) anns
layouterFToLayouterM :: MultiReader '[Config, ExactPrint.Types.Anns] a -> LayoutM a
layouterFToLayouterM m = do
settings <- mAsk
anns <- mAsk
return $ runIdentity
$ runMultiReaderTNil
$ Control.Monad.Trans.MultiReader.Lazy.withMultiReader anns
$ Control.Monad.Trans.MultiReader.Lazy.withMultiReader settings
$ m
-- new BriDoc stuff
docEmpty :: BriDoc
docEmpty = BDEmpty
docLit :: Text -> BriDoc
docLit t = BDLit t
docExt :: ExactPrint.Annotate.Annotate ast
=> GenLocated SrcSpan ast -> ExactPrint.Types.Anns -> BriDoc
docExt x anns = BDExternal
(ExactPrint.Types.mkAnnKey x)
(foldedAnnKeys x)
(Text.pack $ ExactPrint.exactPrint x anns)
docAlt :: [BriDoc] -> BriDoc
docAlt = BDAlt
docSeq :: [BriDoc] -> BriDoc
docSeq = BDSeq
docPostComment :: Data.Data.Data ast
=> GenLocated SrcSpan ast
-> BriDoc
-> BriDoc
docPostComment ast bd = BDAnnotationPost (ExactPrint.Types.mkAnnKey ast) bd
docWrapNode :: Data.Data.Data ast
=> GenLocated SrcSpan ast
-> BriDoc
-> BriDoc
docWrapNode ast bd = BDAnnotationPrior (ExactPrint.Types.mkAnnKey ast)
$ BDAnnotationPost (ExactPrint.Types.mkAnnKey ast)
$ bd
docPar :: BriDoc
-> BriDoc
-> BriDoc
docPar line indented = BDPar BrIndentNone line indented
-- docPar :: BriDoc
-- -> BrIndent
-- -> [BriDoc]
-- -> BriDoc
-- docPar = BDPar
-- docCols :: ColSig
-- -> [BriDoc]
-- -> BriDoc
-- docCols = BDCols
fromMaybeIdentity :: Identity a -> Maybe a -> Identity a
fromMaybeIdentity x y = Data.Coerce.coerce
$ fromMaybe (Data.Coerce.coerce x) y

36
src-idemtests/run.sh Executable file
View File

@ -0,0 +1,36 @@
#!/bin/bash
# set -x
set -e
rm report.txt &> /dev/null || true
mkdir iterOne &> /dev/null || true
mkdir iterTwo &> /dev/null || true
for FILE in ./cases/*
do
NAME=$(basename "$FILE")
ITERNAMEONE="./iterOne/$NAME"
ITERNAMETWO="./iterTwo/$NAME"
if ! ./brittany -i "$FILE" -o "$ITERNAMEONE"
then
echo "FAILED step 1 for $FILE" | tee -a report.txt
continue
fi
if ! ./brittany -i "$ITERNAMEONE" -o "$ITERNAMETWO"
then
echo "FAILED step 2 for $FILE" | tee -a report.txt
continue
fi
if ! diff "$ITERNAMEONE" "$ITERNAMETWO" > diff.temp
then
echo "FAILED diff for $FILE with diff:" | tee -a report.txt
cat diff.temp | tee -a report.txt
echo "# meld $(realpath $ITERNAMEONE) $(realpath $ITERNAMETWO)" | tee -a report.txt
continue
fi
echo "success for $FILE" | tee -a report.txt
done
rm diff.temp

View File

@ -0,0 +1,31 @@
{-# LANGUAGE QuasiQuotes #-}
module AsymptoticPerfTests
( asymptoticPerfTest
)
where
#include "prelude.inc"
import Test.Hspec
import NeatInterpolation
import Language.Haskell.Brittany
import TestUtils
asymptoticPerfTest :: Spec
asymptoticPerfTest = do
it "1000 do statements" $ roundTripEqualWithTimeout 50000 $
( Text.pack "func = do\n")
<> Text.replicate 1000 (Text.pack " statement\n")
it "1000 do nestings" $ roundTripEqualWithTimeout 500000 $
( Text.pack "func = ")
<> mconcat ([0..999] <&> \(i::Int) -> (Text.replicate (2*i) (Text.pack " ") <> Text.pack "do\n"))
<> Text.replicate 2000 (Text.pack " ") <> Text.pack "return\n"
<> Text.replicate 2002 (Text.pack " ") <> Text.pack "()"

View File

@ -0,0 +1,537 @@
{-# LANGUAGE QuasiQuotes #-}
module IdentityTests
( identityTests
)
where
#include "prelude.inc"
import Test.Hspec
import NeatInterpolation
import Language.Haskell.Brittany
import TestUtils
identityTests :: Spec
identityTests = do
describe "type signatures" $ typeSignatureTests
describe "equation" $ do
describe "basic" $ basicEquationTests
describe "patterns" $ patternTests
describe "guards" $ guardTests
describe "expression" $ do
describe "basic" $ basicExpressionTests
describe "do statements" $ doStatementTests
describe "alignment" $ alignmentTests
describe "regression" $ regressionTests
typeSignatureTests :: Spec
typeSignatureTests = do
it "simple001" $ roundTripEqual $
[text|
func :: a -> a
|]
it "long typeVar" $ roundTripEqual $
[text|
func
:: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
-> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
|]
it "keep linebreak mode" $ roundTripEqual $
[text|
func
:: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
-> lakjsdlkjasldkj
-> lakjsdlkjasldkj
|]
it "simple parens 1" $ roundTripEqual $
[text|
func :: ((a))
|]
it "simple parens 2" $ roundTripEqual $
[text|
func :: (a -> a) -> a
|]
it "simple parens 3" $ roundTripEqual $
[text|
func :: a -> (a -> a)
|]
it "did anyone say parentheses?" $ roundTripEqual $
[text|
func :: (((((((((())))))))))
|]
before_ pending $ it "give me more!" $ roundTripEqual $
-- current output is.. funny. wonder if that can/needs to be improved..
[text|
func :: ((((((((((((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))))))))))))
|]
it "unit" $ roundTripEqual $
[text|
func :: ()
|]
-- ################################################################## --
-- ################################################################## --
-- ################################################################## --
it "paren'd func 1" $ roundTripEqual $
[text|
func
:: ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
-> lakjsdlkjasldkj
-> lakjsdlkjasldkj
)
|]
it "paren'd func 2" $ roundTripEqual $
[text|
func
:: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
-> (lakjsdlkjasldkj -> lakjsdlkjasldkj)
|]
it "paren'd func 3" $ roundTripEqual $
[text|
func
:: (lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd -> lakjsdlkjasldkj)
-> lakjsdlkjasldkj
|]
it "paren'd func 4" $ roundTripEqual $
[text|
func
:: ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
-> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
)
-> lakjsdlkjasldkj
|]
it "paren'd func 5" $ roundTripEqual $
[text|
func
:: ( ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
-> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
)
)
|]
-- ################################################################## --
-- ################################################################## --
-- ################################################################## --
it "type application 1" $ roundTripEqual $
[text|
func :: asd -> Either a b
|]
it "type application 2" $ roundTripEqual $
[text|
func
:: asd
-> Either
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
|]
it "type application 3" $ roundTripEqual $
[text|
func
:: asd
-> Trither
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
|]
it "type application 4" $ roundTripEqual $
[text|
func
:: Trither
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
-> asd
|]
it "type application 5" $ roundTripEqual $
[text|
func
:: Trither
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
(lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd -> asd)
|]
it "type application 6" $ roundTripEqual $
[text|
func
:: Trither
asd
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
-> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
)
|]
it "type application paren 1" $ roundTripEqual $
[text|
func
:: asd
-> ( Trither
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
)
|]
it "type application paren 2" $ roundTripEqual $
[text|
func
:: asd
-> ( Trither
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
)
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
|]
it "type application paren 3" $ roundTripEqual $
[text|
func
:: ( Trither
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
)
lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
-> asd
|]
-- ################################################################## --
-- ################################################################## --
-- ################################################################## --
it "list simple" $ roundTripEqual $
[text|
func :: [a -> b]
|]
it "list func" $ roundTripEqual $
[text|
func
:: [ lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
-> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
]
|]
it "list paren" $ roundTripEqual $
[text|
func
:: [ ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
-> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
)
]
|]
-- ################################################################## --
-- ################################################################## --
-- ################################################################## --
it "tuple type 1" $ roundTripEqual $
[text|
func :: (a, b, c)
|]
it "tuple type 2" $ roundTripEqual $
[text|
func :: ((a, b, c), (a, b, c), (a, b, c))
|]
it "tuple type long" $ roundTripEqual $
[text|
func
:: ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
, lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
, lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
)
|]
it "tuple type nested" $ roundTripEqual $
[text|
func
:: ( ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
, (lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd)
, lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
)
)
|]
it "tuple type function" $ roundTripEqual $
[text|
func
:: [ ( lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
, lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
, lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
)
]
|]
-- ################################################################## --
-- ################################################################## --
-- ################################################################## --
before_ pending $ it "type operator stuff" $ roundTripEqual $
[text|
test050 :: a :+: b
test051 :: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
:+: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
test052 :: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
-> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
:+: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
-> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
|]
-- ################################################################## --
-- ################################################################## --
-- ################################################################## --
it "forall oneliner" $ roundTripEqual $
[text|
{-# LANGUAGE ScopedTypeVariables #-}
--this comment is necessary for whatever reason..
func :: forall (a :: *) b . a -> b
|]
it "language pragma issue" $ roundTripEqual $
[text|
{-# LANGUAGE ScopedTypeVariables #-}
func :: forall (a :: *) b . a -> b
|]
it "comments 1" $ roundTripEqual $
[text|
func :: a -> b -- comment
|]
it "comments 2" $ roundTripEqual $
[text|
funcA :: a -> b -- comment A
funcB :: a -> b -- comment B
|]
before_ pending $ it "comments all" $ roundTripEqual $
[text|
-- a
func -- b
:: -- c
a -- d
-> -- e
( -- f
c -- g
, -- h
d -- i
) -- j
-- k
|]
-- ################################################################## --
-- ################################################################## --
-- ################################################################## --
it "ImplicitParams 1" $ roundTripEqual $
[text|
{-# LANGUAGE ImplicitParams #-}
func :: (?asd::Int) -> ()
|]
it "ImplicitParams 2" $ roundTripEqual $
[text|
{-# LANGUAGE ImplicitParams #-}
func
:: ( ?asd
:: lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
-> lkasdlkjalsdjlakjsdlkjasldkjalskdjlkajsd
)
-> ()
|]
-- some basic testing of different kinds of equations.
-- some focus on column layouting for multiple-equation definitions.
-- (that part probably is not implemented in any way yet.)
basicEquationTests :: Spec
basicEquationTests = do
it "basic 1" $ roundTripEqual $
[text|
func x = x
|]
it "infix 1" $ roundTripEqual $
[text|
x *** y = x
|]
it "symbol prefix" $ roundTripEqual $
[text|
(***) x y = x
|]
patternTests :: Spec
patternTests = do
it "wildcard" $ roundTripEqual $
[text|
func _ = x
|]
before_ pending $ it "simple long pattern" $ roundTripEqual $
[text|
func reallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongvariable
= x
|]
before_ pending $ it "simple multiline pattern" $ roundTripEqual $
[text|
func reallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongvariable
reallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongvariable
= x
|]
before_ pending $ it "another multiline pattern" $ roundTripEqual $
[text|
func reallyreallyreallyreallyreallyreallyreallyreallyreallyreallylongvariable
a
b
= x
|]
before_ pending $ it "simple constructor" $ roundTripEqual $
[text|
func (A a) = a
|]
before_ pending $ it "list constructor" $ roundTripEqual $
[text|
func (x:xr) = x
|]
before_ pending $ it "some other constructor symbol" $ roundTripEqual $
[text|
func (x:+:xr) = x
|]
guardTests :: Spec
guardTests = do
it "simple guard" $ roundTripEqual $
[text|
func | True = x
|]
basicExpressionTests :: Spec
basicExpressionTests = do
it "var" $ roundTripEqual $
[text|
func = x
|]
describe "infix op" $ do
it "1" $ roundTripEqual $
[text|
func = x + x
|]
before_ pending $ it "long" $ roundTripEqual $
[text|
func = mweroiuxlskdfjlksjdflkjsdfljksldkjflkjsdflkj
+ mweroiuxlskdfjlksjdflkjsdfljksldkjflkjsdflkj
|]
before_ pending $ it "long keep linemode 1" $ roundTripEqual $
[text|
func = mweroiuxlskdfjlksjdflkjsdfljksldkjflkjsdflkj
+ mweroiuxlskdfjlksj
+ mweroiuxlskdfjlksj
|]
before_ pending $ it "long keep linemode 2" $ roundTripEqual $
[text|
func = mweroiuxlskdfjlksj
+ mweroiuxlskdfjlksj
+ mweroiuxlskdfjlksjdflkjsdfljksldkjflkjsdflkj
|]
it "literals" $ roundTripEqual $
[text|
func = 1
func = "abc"
func = 1.1e5
func = 'x'
func = 981409823458910394810928414192837123987123987123
|]
it "lambdacase" $ roundTripEqual $
[text|
{-# LANGUAGE LambdaCase #-}
func = \case
FooBar -> x
Baz -> y
|]
doStatementTests :: Spec
doStatementTests = do
it "simple" $ roundTripEqual $
[text|
func = do
stmt
stmt
|]
it "bind" $ roundTripEqual $
[text|
func = do
x <- stmt
stmt x
|]
it "let" $ roundTripEqual $
[text|
func = do
let x = 13
stmt x
|]
return ()
alignmentTests :: Spec
alignmentTests = do
return ()
regressionTests :: Spec
regressionTests = do
it "newlines-comment" $ do
roundTripEqual $
[text|
func = do
abc <- foo
--abc
return ()
|]
it "parenthesis-around-unit" $ do
roundTripEqual $
[text|
func = (())
|]
it "let-defs indentation" $ do
roundTripEqual $
[text|
func = do
let foo True = True
foo _ = False
return ()
|]
it "record update indentation" $ do
roundTripEqual $
[text|
func = do
s <- mGet
mSet $ s
{ _lstate_indent = _lstate_indent state
}
|]
it "post-indent comment" $ do
roundTripEqual $
[text|
func = do
-- abc
-- def
return ()
|]
it "post-unindent comment" $ do
roundTripEqual $
[text|
func = do
do
return ()
-- abc
-- def
return ()
|]
it "CPP empty comment case" $ do
pendingWith "CPP parsing needs fixing for roundTripEqual"
roundTripEqual $
[text|
{-# LANGUAGE CPP #-}
module Test where
func = do
#if FOO
let x = 13
#endif
stmt x
|]
-- really, the following should be handled by forcing the Alt to multiline
-- because there are comments. as long as this is not implemented though,
-- we should ensure the trivial solution works.
it "comment inline placement (temporary)" $ do
roundTripEqual $
[text|
func :: Int -> -- basic indentation amount
Int -> -- currently used width in current line (after indent)
-- used to accurately calc placing of the current-line
LayoutDesc -> Int
|]

26
src-unittests/TestMain.hs Normal file
View File

@ -0,0 +1,26 @@
{-# LANGUAGE QuasiQuotes #-}
module Main where
#include "prelude.inc"
import Test.Hspec
import NeatInterpolation
import Language.Haskell.Brittany
import IdentityTests
import AsymptoticPerfTests
main :: IO ()
main = hspec $ tests
tests :: Spec
tests = do
describe "identity roundtrips" $ identityTests
describe "asymptotic perf roundtrips" $ asymptoticPerfTest

View File

@ -0,0 +1,51 @@
{-# LANGUAGE QuasiQuotes #-}
module TestUtils where
#include "prelude.inc"
import Test.Hspec
import NeatInterpolation
import Language.Haskell.Brittany
import Language.Haskell.Brittany.Config.Types
import System.Timeout ( timeout )
roundTripEqual :: Text -> Expectation
roundTripEqual t = fmap (fmap PPTextWrapper) (parsePrintModule defaultTestConfig "TestFakeFileName.hs" t)
`shouldReturn` Right (PPTextWrapper t)
roundTripEqualWithTimeout :: Int -> Text -> Expectation
roundTripEqualWithTimeout time t =
timeout time action `shouldReturn` Just (Right (PPTextWrapper t))
where
action = fmap (fmap PPTextWrapper)
(parsePrintModule defaultTestConfig "TestFakeFileName.hs" t)
newtype PPTextWrapper = PPTextWrapper Text
deriving Eq
instance Show PPTextWrapper where
show (PPTextWrapper t) = "\n" ++ Text.unpack t
defaultTestConfig :: Config
defaultTestConfig = Config
{ _conf_debug = _conf_debug staticDefaultConfig
, _conf_layout = LayoutConfig
{ _lconfig_cols = Identity 80
, _lconfig_indentPolicy = Identity IndentPolicyFree
, _lconfig_indentAmount = Identity 2
, _lconfig_indentWhereSpecial = Identity True
, _lconfig_indentListSpecial = Identity True
, _lconfig_importColumn = Identity 60
, _lconfig_altChooser = Identity $ AltChooserBoundedSearch 3
}
, _conf_errorHandling = _conf_errorHandling staticDefaultConfig
}

View File

@ -0,0 +1,195 @@
{-# LANGUAGE DataKinds #-}
module Language.Haskell.Brittany
( parsePrintModule
, pPrintModule
)
where
#include "prelude.inc"
import DynFlags ( getDynFlags )
import GHC ( runGhc, GenLocated(L), moduleNameString )
import qualified Parser as GHC
import qualified ApiAnnotation as GHC
import qualified DynFlags as GHC
import qualified FastString as GHC
import qualified GHC as GHC hiding (parseModule)
import qualified HeaderInfo as GHC
import qualified Lexer as GHC
import qualified MonadUtils as GHC
import qualified Outputable as GHC
import qualified Parser as GHC
import qualified SrcLoc as GHC
import qualified StringBuffer as GHC
import RdrName ( RdrName(..) )
import Control.Monad.IO.Class
import GHC.Paths (libdir)
import HsSyn
import SrcLoc ( SrcSpan, Located )
-- import Outputable ( ppr, runSDoc )
-- import DynFlags ( unsafeGlobalDynFlags )
import ApiAnnotation ( AnnKeywordId(..) )
import qualified Language.Haskell.GHC.ExactPrint as ExactPrint
import qualified Language.Haskell.GHC.ExactPrint.Annotate as ExactPrint.Annotate
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.Preprocess as ExactPrint.Preprocess
import qualified Data.Map as Map
import qualified Data.Text.Lazy.Builder as Text.Builder
import qualified Debug.Trace as Trace
import Language.Haskell.Brittany.Types
import Language.Haskell.Brittany.Config.Types
import Language.Haskell.Brittany.LayoutBasics
import Language.Haskell.Brittany.Layouters.Type
import Language.Haskell.Brittany.Layouters.Decl
import Language.Haskell.Brittany.Utils
import Language.Haskell.Brittany.BriLayouter
-- LayoutErrors can be non-fatal warnings, thus both are returned instead
-- of an Either.
-- This should be cleaned up once it is clear what kinds of errors really
-- can occur.
pPrintModule
:: Config
-> ExactPrint.Types.Anns
-> GHC.ParsedSource
-> ([LayoutError], TextL.Text)
pPrintModule conf anns parsedModule =
let ((out, errs), debugStrings)
= runIdentity
$ MultiRWSS.runMultiRWSTNil
$ MultiRWSS.withMultiWriterAW
$ MultiRWSS.withMultiWriterAW
$ MultiRWSS.withMultiWriterW
$ MultiRWSS.withMultiReader anns
$ MultiRWSS.withMultiReader conf
$ do
traceIfDumpConf "bridoc annotations" _dconf_dump_annotations $ annsDoc anns
ppModule parsedModule
tracer = if Seq.null debugStrings
then id
else trace ("---- DEBUGMESSAGES ---- ")
. foldr (seq . join trace) id debugStrings
in tracer $ (errs, Text.Builder.toLazyText out)
-- unless () $ do
--
-- debugStrings `forM_` \s ->
-- trace s $ return ()
-- used for testing mostly, currently.
parsePrintModule
:: Config
-> String
-> Text
-> IO (Either String Text)
parsePrintModule conf filename input = do
let inputStr = Text.unpack input
parseResult <- ExactPrint.Parsers.parseModuleFromString filename inputStr
case parseResult of
Left (_, s) -> return $ Left $ "parsing error: " ++ s
Right (anns, parsedModule) ->
let (errs, ltext) = pPrintModule conf anns parsedModule
in return $ if null errs
then Right $ TextL.toStrict $ ltext
else
let errStrs = errs <&> \case
LayoutErrorUnusedComment str -> str
LayoutWarning str -> str
LayoutErrorUnknownNode str _ -> str
in Left $ "pretty printing error(s):\n" ++ List.unlines errStrs
-- this approach would for with there was a pure GHC.parseDynamicFilePragma.
-- Unfortunately that does not exist yet, so we cannot provide a nominally
-- pure interface.
-- parsePrintModule :: Text -> Either String Text
-- parsePrintModule input = do
-- let dflags = GHC.unsafeGlobalDynFlags
-- let fakeFileName = "SomeTestFakeFileName.hs"
-- let pragmaInfo = GHC.getOptions
-- dflags
-- (GHC.stringToStringBuffer $ Text.unpack input)
-- fakeFileName
-- (dflags1, _, _) <- GHC.parseDynamicFilePragma dflags pragmaInfo
-- let parseResult = ExactPrint.Parsers.parseWith
-- dflags1
-- fakeFileName
-- GHC.parseModule
-- inputStr
-- case parseResult of
-- Left (_, s) -> Left $ "parsing error: " ++ s
-- Right (anns, parsedModule) -> do
-- let (out, errs) = runIdentity
-- $ runMultiRWSTNil
-- $ Control.Monad.Trans.MultiRWS.Lazy.withMultiWriterAW
-- $ Control.Monad.Trans.MultiRWS.Lazy.withMultiWriterW
-- $ Control.Monad.Trans.MultiRWS.Lazy.withMultiReader anns
-- $ ppModule parsedModule
-- if (not $ null errs)
-- then do
-- let errStrs = errs <&> \case
-- LayoutErrorUnusedComment str -> str
-- Left $ "pretty printing error(s):\n" ++ List.unlines errStrs
-- else return $ TextL.toStrict $ Text.Builder.toLazyText out
ppModule :: GenLocated SrcSpan (HsModule RdrName) -> PPM ()
ppModule lmod@(L loc m@(HsModule _name _exports _imports decls _ _)) = do
let emptyModule = L loc m { hsmodDecls = [] }
(anns', post) <- do
anns <- mAsk
-- evil partiality. but rather unlikely.
return $ case Map.lookup (ExactPrint.Types.mkAnnKey lmod) anns of
Nothing -> (anns, [])
Just mAnn ->
let
modAnnsDp = ExactPrint.Types.annsDP mAnn
isWhere (ExactPrint.Types.G AnnWhere) = True
isWhere _ = False
isEof (ExactPrint.Types.G AnnEofPos) = True
isEof _ = False
whereInd = List.findIndex (isWhere . fst) modAnnsDp
eofInd = List.findIndex (isEof . fst) modAnnsDp
(pre, post) = case (whereInd, eofInd) of
(Nothing, Nothing) -> ([], modAnnsDp)
(Just i, Nothing) -> List.splitAt (i+1) modAnnsDp
(Nothing, Just _i) -> ([], modAnnsDp)
(Just i, Just j) -> List.splitAt (min (i+1) j) modAnnsDp
mAnn' = mAnn { ExactPrint.Types.annsDP = pre }
anns' = Map.insert (ExactPrint.Types.mkAnnKey lmod) mAnn' anns
in (anns', post)
MultiRWSS.withMultiReader anns' $ processDefault emptyModule
decls `forM_` ppDecl
let
finalComments = filter (fst .> \case ExactPrint.Types.AnnComment{} -> True
_ -> False)
post
post `forM_` \case
(ExactPrint.Types.AnnComment (ExactPrint.Types.Comment cmStr _ _), l) -> do
ppmMoveToExactLoc l
mTell $ Text.Builder.fromString cmStr
(ExactPrint.Types.G AnnEofPos, (ExactPrint.Types.DP (eofX,eofY))) ->
let cmX = foldl' (\acc (_, ExactPrint.Types.DP (x, _)) -> acc+x) 0 finalComments
in ppmMoveToExactLoc $ ExactPrint.Types.DP (eofX - cmX, eofY)
_ -> return ()
ppDecl :: LHsDecl RdrName -> PPM ()
ppDecl d@(L loc decl) = case decl of
SigD sig -> do
-- runLayouter $ Old.layoutSig (L loc sig)
briDoc <- briDocMToPPM $ layoutSig (L loc sig)
layoutBriDoc d briDoc
ValD bind -> do
-- Old.layoutBind (L loc bind)
briDoc <- fmap (either BDLines id) $ briDocMToPPM $ layoutBind (L loc bind)
layoutBriDoc d briDoc
_ ->
briDocMToPPM (briDocByExactNoComment d) >>= layoutBriDoc d

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,164 @@
module Language.Haskell.Brittany.Config
( ConfigF(..)
, DebugConfigF(..)
, LayoutConfigF(..)
, DebugConfig
, LayoutConfig
, Config
, configParser
, staticDefaultConfig
, readMergePersConfig
)
where
#include "prelude.inc"
import DynFlags ( getDynFlags )
import GHC ( runGhc, GenLocated(L), moduleNameString )
import qualified Parser as GHC
import qualified ApiAnnotation as GHC
import qualified DynFlags as GHC
import qualified FastString as GHC
import qualified GHC as GHC hiding (parseModule)
import qualified HeaderInfo as GHC
import qualified Lexer as GHC
import qualified MonadUtils as GHC
import qualified Outputable as GHC
import qualified Parser as GHC
import qualified SrcLoc as GHC
import qualified StringBuffer as GHC
import RdrName ( RdrName(..) )
import Control.Monad.IO.Class
import GHC.Paths (libdir)
import HsSyn
import SrcLoc ( SrcSpan, Located )
-- import Outputable ( ppr, runSDoc )
-- import DynFlags ( unsafeGlobalDynFlags )
import ApiAnnotation ( AnnKeywordId(..) )
import qualified Language.Haskell.GHC.ExactPrint as ExactPrint
import qualified Language.Haskell.GHC.ExactPrint.Annotate as ExactPrint.Annotate
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.Preprocess as ExactPrint.Preprocess
import qualified Data.Map as Map
import qualified Data.Text.Lazy.Builder as Text.Builder
import qualified Debug.Trace as Trace
import Language.Haskell.Brittany.Types
import Language.Haskell.Brittany.LayoutBasics
-- import Data.Aeson
import GHC.Generics
import Control.Lens
import qualified Data.Yaml
import UI.Butcher.Monadic
import Language.Haskell.Brittany.Config.Types
import Language.Haskell.Brittany.Utils
configParser :: CmdParser Identity out (ConfigF Maybe)
configParser = do
-- TODO: why does the default not trigger; ind never should be []!!
ind <- addFlagReadParam "" ["indent"] "AMOUNT"
(flagHelpStr "spaces per indentation level")
cols <- addFlagReadParam "" ["columns"] "AMOUNT"
(flagHelpStr "target max columns (80 is an old default for this)")
importCol <- addFlagReadParam "" ["import-col"] "N"
(flagHelpStr "column to align import lists at")
dumpConfig <- addSimpleBoolFlag "" ["dump-config"] (flagHelp $ parDoc "dump the programs full config (commandline + file + defaults)")
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")
dumpCompleteAST <- addSimpleBoolFlag "" ["dump-ast-full"] (flagHelp $ parDoc "dump the full ast")
dumpBriDocRaw <- addSimpleBoolFlag "" ["dump-bridoc-raw"] (flagHelp $ parDoc "dump the pre-transformation bridoc")
dumpBriDocAlt <- addSimpleBoolFlag "" ["dump-bridoc-alt"] (flagHelp $ parDoc "dump the partially transformed bridoc: after transformation: alt")
dumpBriDocPar <- addSimpleBoolFlag "" ["dump-bridoc-par"] (flagHelp $ parDoc "dump the partially transformed bridoc: after transformation: par")
dumpBriDocFloating <- addSimpleBoolFlag "" ["dump-bridoc-floating"] (flagHelp $ parDoc "dump the partially transformed bridoc: after transformation: floating")
dumpBriDocColumns <- addSimpleBoolFlag "" ["dump-bridoc-columns"] (flagHelp $ parDoc "dump the partially transformed bridoc: after transformation: columns")
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")
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")
return $ Config
{ _conf_debug = DebugConfig
{ _dconf_dump_config = falseToNothing dumpConfig
, _dconf_dump_annotations = falseToNothing dumpAnnotations
, _dconf_dump_ast_unknown = falseToNothing dumpUnknownAST
, _dconf_dump_ast_full = falseToNothing dumpCompleteAST
, _dconf_dump_bridoc_raw = falseToNothing dumpBriDocRaw
, _dconf_dump_bridoc_simpl_alt = falseToNothing dumpBriDocAlt
, _dconf_dump_bridoc_simpl_par = falseToNothing dumpBriDocPar
, _dconf_dump_bridoc_simpl_floating = falseToNothing dumpBriDocFloating
, _dconf_dump_bridoc_simpl_columns = falseToNothing dumpBriDocColumns
, _dconf_dump_bridoc_simpl_indent = falseToNothing dumpBriDocIndent
, _dconf_dump_bridoc_final = falseToNothing dumpBriDocFinal
}
, _conf_layout = LayoutConfig
{ _lconfig_cols = listLastMaybe cols
, _lconfig_indentPolicy = Nothing
, _lconfig_indentAmount = listLastMaybe ind
, _lconfig_indentWhereSpecial = Nothing -- falseToNothing _
, _lconfig_indentListSpecial = Nothing -- falseToNothing _
, _lconfig_importColumn = listLastMaybe importCol
, _lconfig_altChooser = Nothing
}
, _conf_errorHandling = ErrorHandlingConfig
{ _econf_produceOutputOnErrors = falseToNothing outputOnErrors
, _econf_Werror = falseToNothing wError
}
}
where falseToNothing = Bool.bool Nothing (Just True)
listLastMaybe = listToMaybe . reverse
-- configParser :: Parser Config
-- configParser = Config
-- <$> option (eitherReader $ maybe (Left "required <int>!") Right . readMaybe)
-- (long "indent" <> value 2 <> metavar "AMOUNT" <> help "spaces per indentation level")
-- <*> (Bar
-- <$> switch (long "bara" <> help "bara help")
-- <*> switch (long "barb")
-- <*> flag 3 5 (long "barc")
-- )
--
-- configParserInfo :: ParserInfo Config
-- configParserInfo = ParserInfo
-- { infoParser = configParser
-- , infoFullDesc = True
-- , infoProgDesc = return $ PP.text "a haskell code formatting utility based on ghc-exactprint"
-- , infoHeader = return $ PP.text "brittany"
-- , infoFooter = empty
-- , infoFailureCode = (-55)
-- , infoIntersperse = True
-- }
readMergePersConfig :: ConfigF Maybe -> System.IO.FilePath -> MaybeT IO Config
readMergePersConfig conf path = do
exists <- liftIO $ System.Directory.doesFileExist path
if exists
then do
contents <- liftIO $ ByteString.readFile path -- no lazy IO, tyvm.
fileConf <- case Data.Yaml.decodeEither contents of
Left e -> do
liftIO $ putStrLn $ "error reading in brittany config from " ++ path ++ ":"
liftIO $ putStrLn e
mzero
Right x -> return x
return $ cZip fromMaybeIdentity staticDefaultConfig
$ cZip (<|>) conf fileConf
else do
liftIO $ ByteString.writeFile path
$ Data.Yaml.encode
$ cMap (Just . runIdentity) staticDefaultConfig
return $ cZip fromMaybeIdentity staticDefaultConfig
$ conf

View File

@ -0,0 +1,225 @@
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE DeriveDataTypeable #-}
module Language.Haskell.Brittany.Config.Types
where
#include "prelude.inc"
import Data.Yaml
import GHC.Generics
import Control.Lens
import Data.Data ( Data )
data DebugConfigF f = DebugConfig
{ _dconf_dump_config :: f Bool
, _dconf_dump_annotations :: f Bool
, _dconf_dump_ast_unknown :: f Bool
, _dconf_dump_ast_full :: f Bool
, _dconf_dump_bridoc_raw :: f Bool
, _dconf_dump_bridoc_simpl_alt :: f Bool
, _dconf_dump_bridoc_simpl_floating :: f Bool
, _dconf_dump_bridoc_simpl_par :: f Bool
, _dconf_dump_bridoc_simpl_columns :: f Bool
, _dconf_dump_bridoc_simpl_indent :: f Bool
, _dconf_dump_bridoc_final :: f Bool
}
deriving (Generic)
data LayoutConfigF f = LayoutConfig
{ _lconfig_cols :: f Int -- the thing that has default 80.
, _lconfig_indentPolicy :: f IndentPolicy
, _lconfig_indentAmount :: f Int
, _lconfig_indentWhereSpecial :: f Bool -- indent where only 1 sometimes (TODO).
, _lconfig_indentListSpecial :: f Bool -- use some special indentation for ","
-- when creating zero-indentation
-- multi-line list literals.
, _lconfig_importColumn :: f Int
, _lconfig_altChooser :: f AltChooser
}
deriving (Generic)
data ErrorHandlingConfigF f = ErrorHandlingConfig
{ _econf_produceOutputOnErrors :: f Bool
, _econf_Werror :: f Bool
}
deriving (Generic)
data ConfigF f = Config
{ _conf_debug :: DebugConfigF f
, _conf_layout :: LayoutConfigF f
, _conf_errorHandling :: ErrorHandlingConfigF f
}
deriving (Generic)
-- i wonder if any Show1 stuff could be leveraged.
deriving instance Show (DebugConfigF Identity)
deriving instance Show (LayoutConfigF Identity)
deriving instance Show (ErrorHandlingConfigF Identity)
deriving instance Show (ConfigF Identity)
deriving instance Show (DebugConfigF Maybe)
deriving instance Show (LayoutConfigF Maybe)
deriving instance Show (ErrorHandlingConfigF Maybe)
deriving instance Show (ConfigF Maybe)
deriving instance Data (DebugConfigF Identity)
deriving instance Data (LayoutConfigF Identity)
deriving instance Data (ErrorHandlingConfigF Identity)
deriving instance Data (ConfigF Identity)
type Config = ConfigF Identity
type DebugConfig = DebugConfigF Identity
type LayoutConfig = LayoutConfigF Identity
type ErrorHandlingConfig = ErrorHandlingConfigF Identity
instance FromJSON (DebugConfigF Maybe)
instance ToJSON (DebugConfigF Maybe)
instance FromJSON IndentPolicy
instance ToJSON IndentPolicy
instance FromJSON AltChooser
instance ToJSON AltChooser
instance FromJSON (LayoutConfigF Maybe)
instance ToJSON (LayoutConfigF Maybe)
instance FromJSON (ErrorHandlingConfigF Maybe)
instance ToJSON (ErrorHandlingConfigF Maybe)
instance FromJSON (ConfigF Maybe)
instance ToJSON (ConfigF Maybe)
-- instance Monoid DebugConfig where
-- mempty = DebugConfig Nothing Nothing
-- DebugConfig x1 x2 `mappend` DebugConfig y1 y2
-- = DebugConfig (y1 <|> x1)
-- (y2 <|> x2)
--
-- instance Monoid LayoutConfig where
-- mempty = LayoutConfig Nothing Nothing Nothing Nothing Nothing Nothing
-- LayoutConfig x1 x2 x3 x4 x5 x6 `mappend` LayoutConfig y1 y2 y3 y4 y5 y6
-- = LayoutConfig (y1 <|> x1)
-- (y2 <|> x2)
-- (y3 <|> x3)
-- (y4 <|> x4)
-- (y5 <|> x5)
-- (y6 <|> x6)
--
-- instance Monoid Config where
-- mempty = Config
-- { _conf_debug = mempty
-- , _conf_layout = mempty
-- }
-- mappend c1 c2 = Config
-- { _conf_debug = _conf_debug c1 <> _conf_debug c2
-- , _conf_layout = _conf_layout c1 <> _conf_layout c2
-- }
data IndentPolicy = IndentPolicyLeft -- never create a new indentation at more
-- than old indentation + amount
| IndentPolicyFree -- can create new indentations whereever
| IndentPolicyMultiple -- can create indentations only
-- at any n * amount.
deriving (Show, Generic, Data)
data AltChooser = AltChooserSimpleQuick -- always choose last alternative.
-- leads to tons of sparsely filled
-- lines.
| AltChooserShallowBest -- choose the first matching alternative
-- using the simplest spacing
-- information for the children.
| AltChooserBoundedSearch Int
-- choose the first matching alternative
-- using a bounded list of recursive
-- options having sufficient space.
deriving (Show, Generic, Data)
staticDefaultConfig :: Config
staticDefaultConfig = Config
{ _conf_debug = DebugConfig
{ _dconf_dump_config = Identity False
, _dconf_dump_annotations = Identity False
, _dconf_dump_ast_unknown = Identity False
, _dconf_dump_ast_full = Identity False
, _dconf_dump_bridoc_raw = Identity False
, _dconf_dump_bridoc_simpl_alt = Identity False
, _dconf_dump_bridoc_simpl_floating = Identity False
, _dconf_dump_bridoc_simpl_par = Identity False
, _dconf_dump_bridoc_simpl_columns = Identity False
, _dconf_dump_bridoc_simpl_indent = Identity False
, _dconf_dump_bridoc_final = Identity False
}
, _conf_layout = LayoutConfig
{ _lconfig_cols = Identity 80
, _lconfig_indentPolicy = Identity IndentPolicyFree
, _lconfig_indentAmount = Identity 2
, _lconfig_indentWhereSpecial = Identity True
, _lconfig_indentListSpecial = Identity True
, _lconfig_importColumn = Identity 60
, _lconfig_altChooser = Identity $ AltChooserBoundedSearch 3
}
, _conf_errorHandling = ErrorHandlingConfig
{ _econf_produceOutputOnErrors = Identity False
, _econf_Werror = Identity False
}
}
-- TODO: automate writing instances for this to get
-- the above Monoid instance for free.
-- potentially look at http://hackage.haskell.org/package/fieldwise-0.1.0.0/docs/src/Data-Fieldwise.html#deriveFieldwise
class CZip k where
cZip :: (forall a . f a -> g a -> h a) -> k f -> k g -> k h
instance CZip DebugConfigF where
cZip f (DebugConfig x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11)
(DebugConfig y1 y2 y3 y4 y5 y6 y7 y8 y9 y10 y11) = DebugConfig
(f x1 y1)
(f x2 y2)
(f x3 y3)
(f x4 y4)
(f x5 y5)
(f x6 y6)
(f x7 y7)
(f x8 y8)
(f x9 y9)
(f x10 y10)
(f x11 y11)
instance CZip LayoutConfigF where
cZip f (LayoutConfig x1 x2 x3 x4 x5 x6 x7)
(LayoutConfig y1 y2 y3 y4 y5 y6 y7) = LayoutConfig
(f x1 y1)
(f x2 y2)
(f x3 y3)
(f x4 y4)
(f x5 y5)
(f x6 y6)
(f x7 y7)
instance CZip ErrorHandlingConfigF where
cZip f (ErrorHandlingConfig x1 x2)
(ErrorHandlingConfig y1 y2) = ErrorHandlingConfig
(f x1 y1)
(f x2 y2)
instance CZip ConfigF where
cZip f (Config x1 x2 x3) (Config y1 y2 y3) = Config
(cZip f x1 y1)
(cZip f x2 y2)
(cZip f x3 y3)
cMap :: CZip k => (forall a . f a -> g a) -> k f -> k g
cMap f c = cZip (\_ -> f) c c
makeLenses ''DebugConfigF
makeLenses ''ConfigF
makeLenses ''LayoutConfigF

View File

@ -0,0 +1,769 @@
#define INSERTTRACES 0
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
#if !INSERTTRACES
{-# OPTIONS_GHC -Wno-redundant-constraints #-}
#endif
module Language.Haskell.Brittany.LayoutBasics
( processDefault
, rdrNameToText
, lrdrNameToText
, lrdrNameToTextAnn
, askIndent
, getCurRemaining
, layoutWriteAppend
, layoutWriteAppendMultiline
, layoutWriteNewlineBlock
, layoutWriteNewline
, layoutWriteEnsureNewline
, layoutWriteEnsureBlock
, layoutWriteEnsureBlockPlusN
, layoutWithAddBaseCol
, layoutWithAddBaseColBlock
, layoutWithAddBaseColN
, layoutWithAddBaseColNBlock
, layoutSetBaseColCur
, layoutSetIndentLevel
, layoutWriteEnsureAbsoluteN
, layoutAddSepSpace
, layoutMoveToIndentCol
, layoutSetCommentCol
, moveToExactAnn
, layoutWritePriorComments
, layoutWritePostComments
, layoutIndentRestorePostComment
, layoutWritePriorCommentsRestore
, layoutWritePostCommentsRestore
, layoutRemoveIndentLevelLinger
, extractCommentsPrior
, extractCommentsPost
, fixMoveToLineByIsNewline
, filterAnns
, ppmMoveToExactLoc
, docEmpty
, docLit
, docAlt
, docSeq
, docPar
, docPostComment
, docWrapNode
, briDocByExact
, briDocByExactNoComment
, fromMaybeIdentity
, foldedAnnKeys
, unknownNodeError
, appSep
, docCommaSep
, docParenLSep
, spacifyDocs
, briDocMToPPM
)
where
#include "prelude.inc"
import qualified Language.Haskell.GHC.ExactPrint as ExactPrint
import qualified Language.Haskell.GHC.ExactPrint.Annotate as ExactPrint.Annotate
import qualified Language.Haskell.GHC.ExactPrint.Types as ExactPrint.Types
import qualified Language.Haskell.GHC.ExactPrint.Utils as ExactPrint.Utils
import Language.Haskell.GHC.ExactPrint.Types ( AnnKey, Annotation )
import qualified Data.Text.Lazy.Builder as Text.Builder
import Language.Haskell.Brittany.Config.Types
import Language.Haskell.Brittany.Types
import Language.Haskell.Brittany.Utils
import RdrName ( RdrName(..) )
import GHC ( runGhc, GenLocated(L), moduleNameString )
import qualified Outputable as GHC
import qualified DynFlags as GHC
import qualified FastString as GHC
import qualified SrcLoc as GHC
import SrcLoc ( SrcSpan )
import OccName ( occNameString )
import Name ( getOccString )
import Module ( moduleName )
import ApiAnnotation ( AnnKeywordId(..) )
import Data.Data
import Data.Generics.Schemes
import Data.Generics.Aliases
import DataTreePrint
import qualified Text.PrettyPrint as PP
import Data.Function ( fix )
processDefault :: (ExactPrint.Annotate.Annotate ast, MonadMultiWriter
Text.Builder.Builder m,
MonadMultiReader ExactPrint.Types.Anns m)
=> GenLocated SrcSpan ast
-> m ()
processDefault x = do
anns <- mAsk
let str = ExactPrint.exactPrint x anns
-- this hack is here so our print-empty-module trick does not add
-- a newline at the start if there actually is no module header / imports
-- / anything.
-- TODO: instead the appropriate annotation could be removed when "cleaning"
-- the module (header). This would remove the need for this hack!
case str of
"\n" -> return ()
_ -> mTell $ Text.Builder.fromString $ str
briDocByExact :: (ExactPrint.Annotate.Annotate ast,
MonadMultiReader Config m,
MonadMultiReader ExactPrint.Types.Anns m
) => GenLocated SrcSpan ast -> m BriDoc
briDocByExact ast = do
anns <- mAsk
traceIfDumpConf "ast" _dconf_dump_ast_unknown
(printTreeWithCustom 100 (customLayouterF anns) ast)
return $ docExt ast anns True
briDocByExactNoComment :: (ExactPrint.Annotate.Annotate ast,
MonadMultiReader Config m,
MonadMultiReader ExactPrint.Types.Anns m
) => GenLocated SrcSpan ast -> m BriDoc
briDocByExactNoComment ast = do
anns <- mAsk
traceIfDumpConf "ast" _dconf_dump_ast_unknown
(printTreeWithCustom 100 (customLayouterF anns) ast)
return $ docExt ast anns False
rdrNameToText :: RdrName -> Text
-- rdrNameToText = Text.pack . show . flip runSDoc unsafeGlobalDynFlags . ppr
rdrNameToText ( Unqual occname ) = Text.pack $ occNameString occname
rdrNameToText ( Qual mname occname ) = Text.pack $ moduleNameString mname
++ "."
++ occNameString occname
rdrNameToText ( Orig modul occname ) = Text.pack $ moduleNameString (moduleName modul)
++ occNameString occname
rdrNameToText ( Exact name ) = Text.pack $ getOccString name
lrdrNameToText :: GenLocated l RdrName -> Text
lrdrNameToText (L _ n) = rdrNameToText n
lrdrNameToTextAnn :: ( MonadMultiReader Config m
, MonadMultiReader (Map AnnKey Annotation) m
)
=> GenLocated SrcSpan RdrName
-> m Text
lrdrNameToTextAnn ast@(L _ n) = do
anns <- mAsk
let t = rdrNameToText n
let hasUni x (ExactPrint.Types.G y, _) = x==y
hasUni _ _ = False
-- TODO: in general: we should _always_ process all annotaiton stuff here.
-- whatever we don't probably should have had some effect on the
-- output. in such cases, resorting to byExact is probably the safe
-- choice.
return $ case Map.lookup (ExactPrint.Types.mkAnnKey ast) anns of
Nothing -> t
Just (ExactPrint.Types.Ann _ _ _ aks _ _) -> case n of
Exact{} -> t
_ | any (hasUni AnnBackquote) aks -> Text.pack "`" <> t <> Text.pack "`"
_ | any (hasUni AnnOpenP) aks -> Text.pack "(" <> t <> Text.pack ")"
_ | otherwise -> t
askIndent :: (MonadMultiReader Config m) => m Int
askIndent = runIdentity . _lconfig_indentAmount . _conf_layout <$> mAsk
getCurRemaining :: ( MonadMultiReader Config m
, MonadMultiState LayoutState m
)
=> m Int
getCurRemaining = do
cols <- mAsk <&> _conf_layout .> _lconfig_cols .> runIdentity
clc <- _lstate_curY <$> mGet
return $ cols - clc
layoutWriteAppend :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m)
=> Text
-> m ()
layoutWriteAppend t = do
#if INSERTTRACES
tellDebugMessShow ("layoutWriteAppend", t)
#endif
state <- mGet
case _lstate_addSepSpace state of
Just i -> do
#if INSERTTRACES
tellDebugMessShow ("inserting spaces: ", i)
#endif
mSet $ state { _lstate_curY = _lstate_curY state + Text.length t + i
, _lstate_addSepSpace = Nothing
, _lstate_isNewline = NewLineStateNo
}
mTell $ Text.Builder.fromText $ Text.pack (replicate i ' ') <> t
Nothing -> do
#if INSERTTRACES
tellDebugMessShow ("inserting no spaces")
#endif
mSet $ state { _lstate_curY = _lstate_curY state + Text.length t
, _lstate_isNewline = NewLineStateNo
}
mTell $ Text.Builder.fromText t
layoutWriteAppendSpaces :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m)
=> Int
-> m ()
layoutWriteAppendSpaces i = do
#if INSERTTRACES
tellDebugMessShow ("layoutWriteAppendSpaces", i)
#endif
unless (i==0) $ do
state <- mGet
mSet $ state { _lstate_addSepSpace = Just
$ maybe i (+i)
$ _lstate_addSepSpace state
}
layoutWriteAppendMultiline :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m)
=> Text
-> m ()
layoutWriteAppendMultiline t = do
#if INSERTTRACES
tellDebugMessShow ("layoutWriteAppendMultiline", t)
#endif
case Text.lines t of
[] ->
layoutWriteAppend t -- need to write empty, too.
(l:lr) -> do
layoutWriteAppend l
lr `forM_` \x -> do
layoutWriteNewline
layoutWriteAppend x
-- adds a newline and adds spaces to reach the base column.
layoutWriteNewlineBlock :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m)
=> m ()
layoutWriteNewlineBlock = do
#if INSERTTRACES
tellDebugMessShow ("layoutWriteNewlineBlock")
#endif
state <- mGet
mSet $ state { _lstate_curY = 0 -- _lstate_baseY state
, _lstate_addSepSpace = Just $ _lstate_baseY state
, _lstate_inhibitMTEL = False
, _lstate_isNewline = NewLineStateYes
}
mTell $ Text.Builder.fromString $ "\n" -- ++ replicate (_lstate_baseY state) ' '
layoutMoveToIndentCol :: ( MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m) => Int -> m ()
layoutMoveToIndentCol i = do
#if INSERTTRACES
tellDebugMessShow ("layoutMoveToIndentCol", i)
#endif
state <- mGet
mSet $ state
{ _lstate_addSepSpace = Just
$ if _lstate_isNewline state == NewLineStateNo
then i
else _lstate_indLevelLinger state + i - _lstate_curY state
}
-- | does _not_ add spaces to again reach the current base column.
layoutWriteNewline :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m)
=> m ()
layoutWriteNewline = do
#if INSERTTRACES
tellDebugMessShow ("layoutWriteNewline")
#endif
state <- mGet
mSet $ state { _lstate_curY = 0
, _lstate_addSepSpace = Nothing
, _lstate_inhibitMTEL = False
, _lstate_isNewline = NewLineStateYes
}
mTell $ Text.Builder.fromString $ "\n"
layoutWriteEnsureNewline :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m)
=> m ()
layoutWriteEnsureNewline = do
#if INSERTTRACES
tellDebugMessShow ("layoutWriteEnsureNewline")
#endif
state <- mGet
when (_lstate_curY state /= _lstate_baseY state)
$ layoutWriteNewlineBlock
layoutWriteEnsureBlock :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m)
=> m ()
layoutWriteEnsureBlock = do
#if INSERTTRACES
tellDebugMessShow ("layoutWriteEnsureBlock")
#endif
state <- mGet
let diff = case _lstate_addSepSpace state of
Nothing -> _lstate_curY state - _lstate_baseY state
Just sp -> _lstate_baseY state - sp - _lstate_curY state
-- when (diff>0) $ layoutWriteNewlineBlock
when (diff>0) $ do
mSet $ state { _lstate_addSepSpace = Just
$ _lstate_baseY state
- _lstate_curY state
}
layoutWriteEnsureAbsoluteN :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m)
=> Int -> m ()
layoutWriteEnsureAbsoluteN n = do
#if INSERTTRACES
tellDebugMessShow ("layoutWriteEnsureAbsoluteN", n)
#endif
state <- mGet
let diff = n - _lstate_curY state
when (diff>0) $ do
mSet $ state { _lstate_addSepSpace = Just diff -- this always sets to
-- at least (Just 1), so we won't
-- overwrite any old value in any
-- bad way.
}
layoutWriteEnsureBlockPlusN :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m)
=> Int -> m ()
layoutWriteEnsureBlockPlusN n = do
#if INSERTTRACES
tellDebugMessShow ("layoutWriteEnsureBlockPlusN", n)
#endif
state <- mGet
let diff = _lstate_curY state - _lstate_baseY state - n
if diff>0
then layoutWriteNewlineBlock
else if diff<0
then do
layoutWriteAppendSpaces $ negate diff
else return ()
layoutSetBaseColInternal :: ( MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m
) => Int -> m ()
layoutSetBaseColInternal i = do
#if INSERTTRACES
tellDebugMessShow ("layoutSetBaseColInternal", i)
#endif
mModify $ \s -> s { _lstate_baseY = i }
layoutSetIndentLevelInternal :: ( MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m
) => Int -> m ()
layoutSetIndentLevelInternal i = do
#if INSERTTRACES
tellDebugMessShow ("layoutSetIndentLevelInternal", i)
#endif
mModify $ \s -> s { _lstate_indLevelLinger = _lstate_indLevel s
, _lstate_indLevel = i
}
layoutRemoveIndentLevelLinger :: ( MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m
) => m ()
layoutRemoveIndentLevelLinger = do
#if INSERTTRACES
tellDebugMessShow ("layoutRemoveIndentLevelLinger")
#endif
mModify $ \s -> s { _lstate_indLevelLinger = _lstate_indLevel s
}
layoutWithAddBaseCol :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m
,MonadMultiReader Config m
, MonadMultiWriter (Seq String) m)
=> m ()
-> m ()
layoutWithAddBaseCol m = do
#if INSERTTRACES
tellDebugMessShow ("layoutWithAddBaseCol")
#endif
amount <- mAsk <&> _conf_layout .> _lconfig_indentAmount .> runIdentity
state <- mGet
layoutSetBaseColInternal $ _lstate_baseY state + amount
m
layoutSetBaseColInternal $ _lstate_baseY state
layoutWithAddBaseColBlock :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m
,MonadMultiReader Config m
, MonadMultiWriter (Seq String) m)
=> m ()
-> m ()
layoutWithAddBaseColBlock m = do
#if INSERTTRACES
tellDebugMessShow ("layoutWithAddBaseColBlock")
#endif
amount <- mAsk <&> _conf_layout .> _lconfig_indentAmount .> runIdentity
state <- mGet
layoutSetBaseColInternal $ _lstate_baseY state + amount
layoutWriteEnsureBlock
m
layoutSetBaseColInternal $ _lstate_baseY state
layoutWithAddBaseColNBlock :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m)
=> Int
-> m ()
-> m ()
layoutWithAddBaseColNBlock amount m = do
#if INSERTTRACES
tellDebugMessShow ("layoutWithAddBaseColNBlock", amount)
#endif
state <- mGet
layoutSetBaseColInternal $ _lstate_baseY state + amount
layoutWriteEnsureBlock
m
layoutSetBaseColInternal $ _lstate_baseY state
layoutWithAddBaseColN :: (MonadMultiWriter
Text.Builder.Builder m,
MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m)
=> Int
-> m ()
-> m ()
layoutWithAddBaseColN amount m = do
#if INSERTTRACES
tellDebugMessShow ("layoutWithAddBaseColN", amount)
#endif
state <- mGet
layoutSetBaseColInternal $ _lstate_baseY state + amount
m
layoutSetBaseColInternal $ _lstate_baseY state
layoutSetBaseColCur :: (MonadMultiState
LayoutState m,
MonadMultiWriter (Seq String) m)
=> m () -> m ()
layoutSetBaseColCur m = do
#if INSERTTRACES
tellDebugMessShow ("layoutSetBaseColCur")
#endif
state <- mGet
layoutSetBaseColInternal $ case _lstate_addSepSpace state of
Nothing -> _lstate_curY state
Just i -> _lstate_curY state + i
m
layoutSetBaseColInternal $ _lstate_baseY state
layoutSetIndentLevel :: (MonadMultiState
LayoutState m,
MonadMultiWriter (Seq String) m)
=> m () -> m ()
layoutSetIndentLevel m = do
#if INSERTTRACES
tellDebugMessShow ("layoutSetIndentLevel")
#endif
state <- mGet
layoutSetIndentLevelInternal $ _lstate_curY state + fromMaybe 0 (_lstate_addSepSpace state)
m
layoutSetIndentLevelInternal $ _lstate_indLevel state
-- why are comment indentations relative to the previous indentation on
-- the first node of an additional indentation, and relative to the outer
-- indentation after the last node of some indented stuff? sure does not
-- make sense.
layoutRemoveIndentLevelLinger
layoutAddSepSpace :: (MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m)
=> m ()
layoutAddSepSpace = do
#if INSERTTRACES
tellDebugMessShow ("layoutAddSepSpace")
#endif
state <- mGet
mSet $ state { _lstate_addSepSpace = Just $ fromMaybe 1 $ _lstate_addSepSpace state }
-- TODO: when refactoring is complete, the other version of this method
-- can probably be removed.
moveToExactAnn :: (MonadMultiWriter Text.Builder.Builder m,
MonadMultiState LayoutState m,
MonadMultiReader (Map AnnKey Annotation) m
, MonadMultiWriter (Seq String) m) => AnnKey -> m ()
moveToExactAnn annKey = do
#if INSERTTRACES
tellDebugMessShow ("moveToExactAnn'", annKey)
#endif
anns <- mAsk
case Map.lookup annKey anns of
Nothing -> return ()
Just ann -> do
-- curY <- mGet <&> _lstate_curY
let ExactPrint.Types.DP (x, _y) = ExactPrint.Types.annEntryDelta ann
fixedX <- fixMoveToLineByIsNewline x
replicateM_ fixedX $ layoutWriteNewlineBlock
fixMoveToLineByIsNewline :: MonadMultiState
LayoutState m => Int -> m Int
fixMoveToLineByIsNewline x = do
newLineState <- mGet <&> _lstate_isNewline
return $ if newLineState == NewLineStateYes
then x-1
else x
ppmMoveToExactLoc :: MonadMultiWriter Text.Builder.Builder m
=> ExactPrint.Types.DeltaPos
-> m ()
ppmMoveToExactLoc (ExactPrint.Types.DP (x,y)) = do
replicateM_ x $ mTell $ Text.Builder.fromString "\n"
replicateM_ y $ mTell $ Text.Builder.fromString " "
layoutSetCommentCol :: ( MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m )
=> m ()
layoutSetCommentCol = do
state <- mGet
let col = _lstate_curY state
+ fromMaybe 0 (_lstate_addSepSpace state)
#if INSERTTRACES
tellDebugMessShow ("layoutSetCommentCol", col)
#endif
mSet state { _lstate_commentCol = Just col }
layoutWritePriorComments :: (Data.Data.Data ast,
MonadMultiWriter Text.Builder.Builder m,
MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m)
=> GenLocated SrcSpan ast -> m ()
layoutWritePriorComments ast = do
mAnn <- do
state <- mGet
let key = ExactPrint.Types.mkAnnKey ast
let m = _lstate_commentsPrior state
let mAnn = Map.lookup key m
mSet $ state { _lstate_commentsPrior = Map.delete key m }
return mAnn
case mAnn of
Nothing -> return ()
Just priors -> do
when (not $ null priors) $ do
state <- mGet
mSet $ state { _lstate_commentCol = Just $ _lstate_curY state }
priors `forM_` \( ExactPrint.Types.Comment comment _ _
, ExactPrint.Types.DP (x, y)
) -> do
replicateM_ x layoutWriteNewline
layoutWriteAppendSpaces y
layoutWriteAppendMultiline $ Text.pack $ comment
-- this currently only extracs from the `annsDP` field of Annotations.
-- per documentation, this seems sufficient, as the
-- "..`annFollowingComments` are only added by AST transformations ..".
layoutWritePostComments :: (Data.Data.Data ast,
MonadMultiWriter Text.Builder.Builder m,
MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m)
=> GenLocated SrcSpan ast -> m ()
layoutWritePostComments ast = do
mAnn <- do
state <- mGet
let key = ExactPrint.Types.mkAnnKey ast
let m = _lstate_commentsPost state
let mAnn = Map.lookup key m
mSet $ state { _lstate_commentsPost = Map.delete key m }
return mAnn
case mAnn of
Nothing -> return ()
Just posts -> do
when (not $ null posts) $ do
state <- mGet
mSet $ state { _lstate_commentCol = Just $ _lstate_curY state }
posts `forM_` \( ExactPrint.Types.Comment comment _ _
, ExactPrint.Types.DP (x, y)
) -> do
replicateM_ x layoutWriteNewline
layoutWriteAppend $ Text.pack $ replicate y ' '
layoutWriteAppendMultiline $ Text.pack $ comment
layoutIndentRestorePostComment :: ( Monad m
, MonadMultiState LayoutState m
, MonadMultiWriter Text.Builder.Builder m
, MonadMultiWriter (Seq String) m
)
=> m ()
layoutIndentRestorePostComment = do
isNotNewline <- mGet <&> _lstate_isNewline .> (==NewLineStateNo)
mCommentCol <- _lstate_commentCol <$> mGet
mModify $ \s -> s { _lstate_commentCol = Nothing }
case mCommentCol of
Just commentCol | isNotNewline -> do
layoutWriteNewline
layoutWriteAppend $ Text.pack $ replicate commentCol ' '
_ -> return ()
layoutWritePriorCommentsRestore :: (Data.Data.Data ast,
MonadMultiWriter Text.Builder.Builder m,
MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m)
=> GenLocated SrcSpan ast -> m ()
layoutWritePriorCommentsRestore x = do
layoutWritePriorComments x
layoutIndentRestorePostComment
layoutWritePostCommentsRestore :: (Data.Data.Data ast,
MonadMultiWriter Text.Builder.Builder m,
MonadMultiState LayoutState m
, MonadMultiWriter (Seq String) m)
=> GenLocated SrcSpan ast -> m ()
layoutWritePostCommentsRestore x = do
layoutWritePostComments x
layoutIndentRestorePostComment
extractCommentsPrior :: ExactPrint.Types.Anns -> PriorMap
extractCommentsPrior anns = flip Map.mapMaybe anns $ \ann ->
[r | let r = ExactPrint.Types.annPriorComments ann, not (null r)]
extractCommentsPost :: ExactPrint.Types.Anns -> PostMap
extractCommentsPost anns = flip Map.mapMaybe anns $ \ann ->
[r
| let r = ExactPrint.Types.annsDP ann >>= \case
(ExactPrint.Types.AnnComment comment, dp) -> [(comment, dp)]
_ -> []
, not (null r)
]
foldedAnnKeys :: Data.Data.Data ast
=> ast
-> Set ExactPrint.Types.AnnKey
foldedAnnKeys ast = everything
Set.union
(\x -> maybe
Set.empty
Set.singleton
[ gmapQi 1 (\t -> ExactPrint.Types.mkAnnKey $ L l t) x
| locTyCon == typeRepTyCon (typeOf x)
, l <- gmapQi 0 cast x
]
)
ast
where
locTyCon = typeRepTyCon (typeOf (L () ()))
filterAnns :: Data.Data.Data ast
=> ast
-> ExactPrint.Types.Anns
-> ExactPrint.Types.Anns
filterAnns ast anns =
Map.filterWithKey (\k _ -> k `Set.member` foldedAnnKeys ast) anns
-- new BriDoc stuff
docEmpty :: BriDoc
docEmpty = BDEmpty
docLit :: Text -> BriDoc
docLit t = BDLit t
docExt :: ExactPrint.Annotate.Annotate ast
=> GenLocated SrcSpan ast -> ExactPrint.Types.Anns -> Bool -> BriDoc
docExt x anns shouldAddComment = BDExternal
(ExactPrint.Types.mkAnnKey x)
(foldedAnnKeys x)
shouldAddComment
(Text.pack $ ExactPrint.exactPrint x anns)
docAlt :: [BriDoc] -> BriDoc
docAlt = BDAlt
docSeq :: [BriDoc] -> BriDoc
docSeq = BDSeq
appSep :: BriDoc -> BriDoc
appSep x = BDSeq [x, BDSeparator]
docCommaSep :: BriDoc
docCommaSep = appSep $ BDLit $ Text.pack ","
docParenLSep :: BriDoc
docParenLSep = appSep $ BDLit $ Text.pack "("
docPostComment :: Data.Data.Data ast
=> GenLocated SrcSpan ast
-> BriDoc
-> BriDoc
docPostComment ast bd = BDAnnotationPost (ExactPrint.Types.mkAnnKey ast) bd
docWrapNode :: Data.Data.Data ast
=> GenLocated SrcSpan ast
-> BriDoc
-> BriDoc
docWrapNode ast bd = BDAnnotationPrior (ExactPrint.Types.mkAnnKey ast)
$ BDAnnotationPost (ExactPrint.Types.mkAnnKey ast)
$ bd
docPar :: BriDoc
-> BriDoc
-> BriDoc
docPar line indented = BDPar BrIndentNone line indented
fromMaybeIdentity :: Identity a -> Maybe a -> Identity a
fromMaybeIdentity x y = Data.Coerce.coerce
$ fromMaybe (Data.Coerce.coerce x) y
unknownNodeError
:: MonadMultiWriter [LayoutError] m
=> Data.Data.Data ast => String -> ast -> m BriDoc
unknownNodeError infoStr ast = do
mTell $ [LayoutErrorUnknownNode infoStr ast]
return $ BDLit $ Text.pack "{- BRITTANY ERROR UNHANDLED SYNTACTICAL CONSTRUCT -}"
spacifyDocs :: [BriDoc] -> [BriDoc]
spacifyDocs [] = []
spacifyDocs ds = fmap appSep (List.init ds) ++ [List.last ds]
briDocMToPPM :: ToBriDocM a -> PPM a
briDocMToPPM m = do
readers <- MultiRWSS.mGetRawR
let ((x, errs), debugs) = runIdentity
$ MultiRWSS.runMultiRWSTNil
$ MultiRWSS.withMultiReaders readers
$ MultiRWSS.withMultiWriterAW
$ MultiRWSS.withMultiWriterAW
$ m
mTell debugs
mTell errs
return x

View File

@ -0,0 +1,264 @@
{-# LANGUAGE DataKinds #-}
module Language.Haskell.Brittany.Layouters.Decl
( layoutSig
, layoutBind
, layoutLocalBinds
, layoutGuardLStmt
, layoutGrhs
)
where
#include "prelude.inc"
import Language.Haskell.Brittany.Types
import Language.Haskell.Brittany.LayoutBasics
import RdrName ( RdrName(..) )
import GHC ( runGhc, GenLocated(L), moduleNameString )
import SrcLoc ( SrcSpan )
import HsSyn
import Name
import Language.Haskell.GHC.ExactPrint.Types ( mkAnnKey )
import Language.Haskell.Brittany.Layouters.Type
import {-# SOURCE #-} Language.Haskell.Brittany.Layouters.Expr
import Language.Haskell.Brittany.Layouters.Pattern
import Bag ( mapBagM )
layoutSig :: ToBriDoc Sig
layoutSig lsig@(L _loc sig) = case sig of
TypeSig names (HsIB _ (HsWC _ _ typ)) -> do
nameStrs <- names `forM` lrdrNameToTextAnn
let nameStr = Text.intercalate (Text.pack ", ") $ nameStrs
typeDoc <- layoutType typ
return $ docWrapNode lsig $ docAlt
[ docSeq
[ docPostComment lsig $ docLit nameStr
, docLit $ Text.pack " :: "
, BDForceSingleline typeDoc
]
, BDAddBaseY BrIndentRegular
$ docPar
(docPostComment lsig $ docLit nameStr)
( BDCols ColTyOpPrefix
[ docLit $ Text.pack ":: "
, BDAddBaseY (BrIndentSpecial 3) $ typeDoc
]
)
]
_ -> briDocByExact lsig -- TODO: should not be necessary
layoutGuardLStmt :: ToBriDoc' (Stmt RdrName (LHsExpr RdrName))
layoutGuardLStmt lgstmt@(L _ stmtLR) = case stmtLR of
BodyStmt body _ _ _ -> layoutExpr body
_ -> briDocByExact lgstmt -- TODO
layoutGrhs :: Maybe BriDoc -> ToBriDoc' (GRHS RdrName (LHsExpr RdrName))
layoutGrhs mPatPart lgrhs@(L _ (GRHS guards body)) = do
bodyDoc <- BDAddBaseY BrIndentRegular <$> layoutExpr body
let patPart = fromMaybe BDEmpty mPatPart
docWrapNode lgrhs <$> case guards of
[] ->
return $ BDCols ColEquation
[appSep $ patPart, BDSeq [appSep $ BDLit $ Text.pack "=", bodyDoc]]
[guard1] -> do
guardDoc1 <- layoutGuardLStmt guard1
return $ BDAlt
[ BDCols ColGuardedEquation
[ patPart
, BDSeq [appSep $ BDLit $ Text.pack "|", appSep $ guardDoc1]
, BDSeq [appSep $ BDLit $ Text.pack "=", bodyDoc]
]
, BDAddBaseY BrIndentRegular
$ docPar patPart
$ BDSeq
[ appSep $ BDLit $ Text.pack "|"
, appSep $ guardDoc1
, appSep $ BDSeq [BDLit $ Text.pack "="]
, bodyDoc
]
, BDAddBaseY BrIndentRegular
$ docPar patPart
$ BDLines
[ BDSeq [appSep $ BDLit $ Text.pack "|", guardDoc1]
, BDSeq [appSep $ BDLit $ Text.pack "=", bodyDoc]
]
]
(guard1:guardr) -> do
guardDoc1 <- layoutGuardLStmt guard1
guardDocr <- layoutGuardLStmt `mapM` guardr
let hat = BDCols ColGuardedEquation
[appSep $ patPart, BDSeq [appSep $ BDLit $ Text.pack "|", guardDoc1]]
middle = guardDocr <&> \gd -> BDCols ColGuardedEquation
[BDEmpty, BDSeq [appSep $ BDLit $ Text.pack ",", gd]]
last = BDCols ColGuardedEquation
[BDEmpty, BDSeq [appSep $ BDLit $ Text.pack "=", bodyDoc]]
return $ BDAlt
[ BDCols ColGuardedEquation
[ appSep $ BDForceSingleline patPart
, BDSeq $ [appSep $ BDLit $ Text.pack "|", appSep $ BDForceSingleline guardDoc1]
++ (guardDocr >>= \gd ->
[appSep $ BDLit $ Text.pack ",", appSep $ BDForceSingleline gd])
, BDSeq [appSep $ BDLit $ Text.pack "=", bodyDoc]
]
, BDLines $ [hat] ++ middle ++ [last]
]
layoutBind :: ToBriDocC (HsBindLR RdrName RdrName) (Either [BriDoc] BriDoc)
layoutBind lbind@(L _ bind) = case bind of
FunBind fId (MG (L _ matches) _ _ _) _ _ [] -> do
funcPatDocs <- matches `forM` \(L _ match@(Match _
pats
_mType -- not an actual type sig
(GRHSs grhss whereBinds))) -> do
let isInfix = isInfixMatch match
let mId = fId
idStr <- lrdrNameToTextAnn mId
patDocs <- pats `forM` layoutPat
let funcPatternPartLine = case patDocs of
(p1:pr) | isInfix -> BDCols ColFuncPatternsInfix
( [ appSep $ BDForceSingleline p1
, appSep $ BDLit idStr
]
++ (pr <&> (\p -> appSep $ BDForceSingleline p))
)
ps -> BDCols ColFuncPatternsPrefix
$ appSep (BDLit $ idStr)
: (ps <&> (\p -> BDSeq [BDForceSingleline p, BDSeparator]))
grhssDocsNoInd <- do
case grhss of
[grhs1] -> layoutGrhs (Just funcPatternPartLine) grhs1
(grhs1:grhsr) -> do
grhsDoc1 <- layoutGrhs (Just funcPatternPartLine) grhs1
grhsDocr <- layoutGrhs Nothing `mapM` grhsr
return $ BDLines $ grhsDoc1 : grhsDocr
[] -> error "layoutBind grhssDocsNoInd"
let grhssDocs = BDAlt [grhssDocsNoInd {-, grhssDocsInd TODO-}]
layoutLocalBinds whereBinds >>= \case
Nothing -> return $ grhssDocs
Just whereDocs -> do
return $ docPar grhssDocs
$ BDEnsureIndent BrIndentRegular
$ BDAddBaseY BrIndentRegular
$ docPar (BDLit $ Text.pack "where")
$ BDSetIndentLevel $ BDLines whereDocs
return $ Left $ case funcPatDocs of
[] -> []
[x1] -> [docWrapNode lbind x1]
(x1:xs) | (xL:xMR) <- reverse xs ->
[ BDAnnotationPrior (mkAnnKey lbind) $ x1 ]
++ reverse xMR
++ [ BDAnnotationPost (mkAnnKey lbind) $ xL ]
_ -> error "cannot happen (TM)"
PatBind pat (GRHSs grhss whereBinds) _ _ ([], []) -> do
patDoc <- layoutPat pat
mWhereDocs <- layoutLocalBinds whereBinds
grhssDocsNoInd <- do
case grhss of
[grhs1] -> layoutGrhs (Just $ appSep patDoc) grhs1
(grhs1:grhsr) -> do
grhsDoc1 <- layoutGrhs (Just $ appSep patDoc) grhs1
grhsDocr <- layoutGrhs Nothing `mapM` grhsr
return $ BDLines $ grhsDoc1 : grhsDocr
[] -> error "layoutBind grhssDocsNoInd"
let grhssDocs = BDAlt [grhssDocsNoInd {-, grhssDocsInd TODO-}]
case mWhereDocs of
Nothing ->
return $ Right grhssDocs
Just whereDocs -> do
return $ Right
$ BDAddBaseY BrIndentRegular
$ docPar grhssDocs
$ BDAddBaseY BrIndentRegular
$ docPar (BDLit $ Text.pack "where")
$ BDSetIndentLevel $ BDLines whereDocs
_ -> Right <$> briDocByExact lbind
layoutLocalBinds :: ToBriDocC (HsLocalBindsLR RdrName RdrName) (Maybe [BriDoc])
layoutLocalBinds (L _ binds) = case binds of
HsValBinds (ValBindsIn lhsBindsLR []) ->
Just . (>>= either id return) . Data.Foldable.toList <$> mapBagM layoutBind lhsBindsLR -- TODO: fix ordering
x@(HsValBinds (ValBindsIn{})) ->
Just . (:[]) <$> unknownNodeError "HsValBinds (ValBindsIn _ (_:_))" x
x@(HsValBinds (ValBindsOut _binds _lsigs)) ->
-- i _think_ this case never occurs in non-processed ast
Just . (:[]) <$> unknownNodeError "HsValBinds ValBindsOut{}" x
x@(HsIPBinds _ipBinds) ->
Just . (:[]) <$> unknownNodeError "HsIPBinds" x
EmptyLocalBinds ->
return $ Nothing
-- layoutBind :: LayouterFType' (HsBindLR RdrName RdrName)
-- layoutBind lbind@(L _ bind) = case bind of
-- #if MIN_VERSION_ghc(8,0,0)
-- FunBind fId (MG (L _ matches) _ _ _) _ _ [] -> do
-- #else
-- FunBind fId fInfix (MG matches _ _ _) _ _ [] -> do
-- #endif
-- return $ Layouter
-- { _layouter_desc = LayoutDesc
-- { _ldesc_line = Nothing -- no parent
-- , _ldesc_block = Nothing -- no parent
-- }
-- , _layouter_func = \_params -> do
-- layoutWritePriorCommentsRestore lbind
-- moveToExactAnn lbind
-- -- remaining <- getCurRemaining
-- #if MIN_VERSION_ghc(8,0,0)
-- matches `forM_` \(L _ match@(Match _
-- pats
-- mType
-- (GRHSs grhss (L _ whereBinds)))) -> do
-- let isInfix = isInfixMatch match
-- let mId = fId
-- #else
-- matches `forM_` \(L _ (Match mIdInfix
-- pats
-- mType
-- (GRHSs grhss whereBinds))) -> do
-- let isInfix = maybe fInfix snd mIdInfix
-- let mId = maybe fId fst mIdInfix
-- #endif
-- idStr <- lrdrNameToTextAnn mId
-- patLays <- pats `forM` \p -> layouterFToLayouterM $ layoutPat p
-- case patLays of
-- (p1:pr) | isInfix -> do
-- applyLayouter p1 defaultParams
-- layoutWriteAppend $ (Text.pack " ") <> idStr
-- pr `forM_` \p -> do
-- layoutWriteAppend $ Text.pack " "
-- applyLayouter p defaultParams
-- ps -> do
-- layoutWriteAppend $ idStr
-- ps `forM_` \p -> do
-- layoutWriteAppend $ Text.pack " "
-- applyLayouter p defaultParams
-- case mType of
-- Nothing -> return ()
-- Just t -> do
-- tLay <- layouterFToLayouterM $ layoutType t
-- layoutWriteAppend $ Text.pack " :: "
-- applyLayouter tLay defaultParams
-- grhss `forM_` \case
-- L _ (GRHS [] body) -> do
-- layoutWriteAppend $ Text.pack " = "
-- l <- layouterFToLayouterM $ layoutExpr body
-- layoutWithAddIndent $ do
-- applyLayouter l defaultParams
-- grhs -> do
-- l <- layoutByExact grhs
-- applyLayouter l defaultParams
-- case whereBinds of
-- HsValBinds valBinds -> undefined valBinds -- TODO
-- HsIPBinds ipBinds -> undefined ipBinds -- TODO
-- EmptyLocalBinds -> return ()
-- layoutWritePostCommentsRestore lbind
-- , _layouter_ast = lbind
-- }
-- _ -> layoutByExact lbind

View File

@ -0,0 +1,649 @@
{-# LANGUAGE DataKinds #-}
module Language.Haskell.Brittany.Layouters.Expr
( layoutExpr
, litBriDoc
)
where
#include "prelude.inc"
import Language.Haskell.Brittany.Types
import Language.Haskell.Brittany.LayoutBasics
import RdrName ( RdrName(..) )
import GHC ( runGhc, GenLocated(L), moduleNameString )
import SrcLoc ( SrcSpan )
import HsSyn
import Name
import qualified FastString
import BasicTypes
import Language.Haskell.Brittany.Layouters.Pattern
import Language.Haskell.Brittany.Layouters.Decl
import Language.Haskell.Brittany.Layouters.Stmt
layoutExpr :: ToBriDoc HsExpr
layoutExpr lexpr@(L _ expr) = fmap (docWrapNode lexpr)
$ case expr of
HsVar vname -> do
BDLit <$> lrdrNameToTextAnn vname
HsUnboundVar var -> return $ case var of
OutOfScope oname _ -> BDLit $ Text.pack $ occNameString oname
TrueExprHole oname -> BDLit $ Text.pack $ occNameString oname
HsRecFld{} -> do
-- TODO
briDocByExact lexpr
HsOverLabel{} -> do
-- TODO
briDocByExact lexpr
HsIPVar{} -> do
-- TODO
briDocByExact lexpr
HsOverLit (OverLit olit _ _ _) -> do
return $ overLitValBriDoc olit
HsLit lit -> do
return $ litBriDoc lit
HsLam (MG (L _ [L _ (Match _ pats _ (GRHSs [L _ (GRHS [] body)] (L _ EmptyLocalBinds)))]) _ _ _) -> do
patDocs <- pats `forM` layoutPat
bodyDoc <- BDAddBaseY BrIndentRegular <$> layoutExpr body
let funcPatternPartLine =
BDCols ColCasePattern
$ (patDocs <&> (\p -> BDSeq [BDForceSingleline p, BDSeparator]))
return $ BDAlt
[ BDSeq
[ BDLit $ Text.pack "\\"
, funcPatternPartLine
, appSep $ BDLit $ Text.pack "->"
, bodyDoc
]
-- TODO
]
HsLam{} ->
unknownNodeError "HsLam too complex" lexpr
HsLamCase _ (MG (L _ matches) _ _ _) -> do
funcPatDocs <- matches `forM` \(L _ (Match _
pats
_mType -- not an actual type sig
(GRHSs grhss whereBinds))) -> do
patDocs <- pats `forM` layoutPat
let funcPatternPartLine = case patDocs of
ps -> BDCols ColFuncPatternsPrefix
$ (ps <&> (\p -> BDSeq [BDForceSingleline p, BDSeparator]))
grhssDocsNoInd <- do
case grhss of
[grhs1] -> layoutGrhsLCase (Just funcPatternPartLine) grhs1
(grhs1:grhsr) -> do
grhsDoc1 <- layoutGrhsLCase (Just funcPatternPartLine) grhs1
grhsDocr <- layoutGrhsLCase Nothing `mapM` grhsr
return $ BDLines $ grhsDoc1 : grhsDocr
[] -> error "layoutBind grhssDocsNoInd"
let grhssDocs = BDAlt [grhssDocsNoInd {-, grhssDocsInd TODO-}]
layoutLocalBinds whereBinds >>= \case
Nothing -> return $ grhssDocs
Just whereDocs -> do
return $ BDAddBaseY BrIndentRegular
$ docPar grhssDocs
$ BDAddBaseY BrIndentRegular
$ docPar (BDLit $ Text.pack "where")
$ BDSetIndentLevel $ BDLines whereDocs
return $ BDAddBaseY BrIndentRegular $ docPar
(BDLit $ Text.pack "\\case")
(BDLines funcPatDocs)
HsApp exp1 exp2 -> do
-- TODO: if expDoc1 is some literal, we may want to create a BDCols here.
expDoc1 <- layoutExpr exp1
expDoc2 <- layoutExpr exp2
return $ BDAlt
[ BDSeq [appSep $ BDForceSingleline expDoc1, BDForceSingleline expDoc2]
, BDAddBaseY BrIndentRegular
$ docPar
expDoc1
expDoc2
]
HsAppType{} -> do
-- TODO
briDocByExact lexpr
HsAppTypeOut{} -> do
-- TODO
briDocByExact lexpr
OpApp expLeft expOp _ expRight -> do
expDocLeft <- layoutExpr expLeft
expDocOp <- layoutExpr expOp
expDocRight <- layoutExpr expRight
return $ BDAlt
[ BDSeq
[ appSep $ BDForceSingleline expDocLeft
, appSep $ BDForceSingleline expDocOp
, BDForceSingleline expDocRight
]
, BDAddBaseY BrIndentRegular
$ docPar
expDocLeft
-- TODO: turn this into BDCols?
(BDSeq [appSep $ expDocOp, expDocRight])
]
NegApp{} -> do
-- TODO
briDocByExact lexpr
HsPar innerExp -> do
innerExpDoc <- layoutExpr innerExp
return $ BDAlt
[ BDSeq
[ BDLit $ Text.pack "("
, BDForceSingleline innerExpDoc
, BDLit $ Text.pack ")"
]
-- TODO
]
SectionL{} -> do
-- TODO
briDocByExact lexpr
SectionR{} -> do
-- TODO
briDocByExact lexpr
ExplicitTuple args boxity
| Just argExprs <- args `forM` (\case (L _ (Present e)) -> Just e; _ -> Nothing) -> do
argDocs <- layoutExpr `mapM` argExprs
return $ case boxity of
Boxed -> BDAlt
[ BDSeq
$ [ BDLit $ Text.pack "(" ]
++ List.intersperse (appSep $ BDLit $ Text.pack ",") argDocs
++ [ BDLit $ Text.pack ")"]
-- TODO
]
Unboxed -> BDAlt
[ BDSeq
$ [ BDLit $ Text.pack "(#" ]
++ List.intersperse (appSep $ BDLit $ Text.pack ",") argDocs
++ [ BDLit $ Text.pack "#)"]
-- TODO
]
ExplicitTuple{} ->
unknownNodeError "ExplicitTuple|.." lexpr
HsCase cExp (MG (L _ matches) _ _ _) -> do
cExpDoc <- layoutExpr cExp
funcPatDocs <- matches `forM` \(L _ (Match _
pats
_mType -- not an actual type sig
(GRHSs grhss whereBinds))) -> do
patDocs <- pats `forM` layoutPat
let funcPatternPartLine =
BDCols ColCasePattern
$ (patDocs <&> (\p -> BDSeq [BDForceSingleline p, BDSeparator]))
grhssDocsNoInd <- do
case grhss of
[grhs1] -> layoutGrhsCase (Just funcPatternPartLine) grhs1
(grhs1:grhsr) -> do
grhsDoc1 <- layoutGrhsCase (Just funcPatternPartLine) grhs1
grhsDocr <- layoutGrhsCase Nothing `mapM` grhsr
return $ BDLines $ grhsDoc1 : grhsDocr
[] -> error "layoutBind grhssDocsNoInd"
let grhssDocs = BDAlt [grhssDocsNoInd {-, grhssDocsInd TODO-}]
layoutLocalBinds whereBinds >>= \case
Nothing -> return $ grhssDocs
Just lhsBindsLRDoc -> do
return $ BDAddBaseY BrIndentRegular
$ docPar grhssDocs
$ BDAddBaseY BrIndentRegular
$ docPar (BDLit $ Text.pack "where")
$ BDSetIndentLevel $ BDLines lhsBindsLRDoc
return $ BDAlt
[ BDAddBaseY BrIndentRegular
$ docPar
( BDSeq
[ appSep $ BDLit $ Text.pack "case"
, appSep $ BDForceSingleline cExpDoc
, BDLit $ Text.pack "of"
])
(BDSetIndentLevel $ BDLines funcPatDocs)
, docPar
( BDAddBaseY BrIndentRegular
$ docPar (BDLit $ Text.pack "case") cExpDoc
)
( BDAddBaseY BrIndentRegular
$ docPar (BDLit $ Text.pack "of")
(BDSetIndentLevel $ BDLines funcPatDocs)
)
]
HsIf _ ifExpr thenExpr elseExpr -> do
ifExprDoc <- layoutExpr ifExpr
thenExprDoc <- layoutExpr thenExpr
elseExprDoc <- layoutExpr elseExpr
return $ BDAlt
[ BDSeq
[ appSep $ BDLit $ Text.pack "if"
, appSep $ BDForceSingleline ifExprDoc
, appSep $ BDLit $ Text.pack "then"
, appSep $ BDForceSingleline thenExprDoc
, appSep $ BDLit $ Text.pack "else"
, BDForceSingleline elseExprDoc
]
, BDAddBaseY BrIndentRegular
$ docPar
( BDAddBaseY (BrIndentSpecial 3)
$ BDSeq [appSep $ BDLit $ Text.pack "if", ifExprDoc])
(BDLines
[ BDAddBaseY BrIndentRegular
$ BDAlt
[ BDSeq [appSep $ BDLit $ Text.pack "then", BDForceSingleline thenExprDoc]
, BDAddBaseY BrIndentRegular
$ docPar (BDLit $ Text.pack "then") thenExprDoc
]
, BDAddBaseY BrIndentRegular
$ BDAlt
[ BDSeq [appSep $ BDLit $ Text.pack "else", BDForceSingleline elseExprDoc]
, BDAddBaseY BrIndentRegular
$ docPar (BDLit $ Text.pack "else") elseExprDoc
]
])
, BDLines
[ BDAddBaseY (BrIndentSpecial 3)
$ BDSeq [appSep $ BDLit $ Text.pack "if", ifExprDoc]
, BDAddBaseY BrIndentRegular
$ docPar (BDLit $ Text.pack "then") thenExprDoc
, BDAddBaseY BrIndentRegular
$ docPar (BDLit $ Text.pack "else") elseExprDoc
]
]
HsMultiIf _ cases -> do
caseDocs <- cases `forM` layoutGrhsMWIf
return $ BDAddBaseY BrIndentRegular $ docPar
(BDLit $ Text.pack "if")
(BDLines caseDocs)
HsLet{} -> do
-- TODO
briDocByExact lexpr
HsDo DoExpr (L _ stmts) _ -> do
stmtDocs <- layoutStmt `mapM` stmts
return $ BDAddBaseY BrIndentRegular
$ docPar
(BDLit $ Text.pack "do")
(BDSetIndentLevel $ BDLines stmtDocs)
HsDo x (L _ stmts) _ | case x of { ListComp -> True
; MonadComp -> True
; _ -> False } -> do
stmtDocs <- layoutStmt `mapM` stmts
return $ BDAlt
[ BDSeq
[ appSep $ BDLit $ Text.pack "["
, appSep $ BDForceSingleline $ List.last stmtDocs
, appSep $ BDLit $ Text.pack "|"
, BDSeq $ List.intersperse docCommaSep
$ fmap BDForceSingleline $ List.init stmtDocs
, BDLit $ Text.pack "]"
]
, let
start = BDCols ColListComp
[appSep $ BDLit $ Text.pack "[", List.last stmtDocs]
(s1:sM) = List.init stmtDocs
line1 = BDCols ColListComp
[appSep $ BDLit $ Text.pack "|", s1]
lineM = sM <&> \d ->
BDCols ColListComp [docCommaSep, d]
end = BDLit $ Text.pack "]"
in BDSetBaseY $ BDLines $ [start, line1] ++ lineM ++ [end]
]
HsDo{} -> do
-- TODO
briDocByExact lexpr
ExplicitList _ _ elems@(_:_) -> do
elemDocs <- elems `forM` layoutExpr
return $ BDAlt
[ BDSeq
$ [BDLit $ Text.pack "["]
++ List.intersperse docCommaSep (BDForceSingleline <$> elemDocs)
++ [BDLit $ Text.pack "]"]
, let
start = BDCols ColList
[appSep $ BDLit $ Text.pack "[", List.head elemDocs]
lines = List.tail elemDocs <&> \d ->
BDCols ColList [docCommaSep, d]
end = BDLit $ Text.pack "]"
in BDSetBaseY $ BDLines $ [start] ++ lines ++ [end]
]
ExplicitList _ _ [] ->
return $ BDLit $ Text.pack "[]"
ExplicitPArr{} -> do
-- TODO
briDocByExact lexpr
RecordCon lname _ _ (HsRecFields [] Nothing) -> do
let t = lrdrNameToText lname
return $ BDLit $ t <> Text.pack "{}"
RecordCon lname _ _ (HsRecFields fs@(_:_) Nothing) -> do
let t = lrdrNameToText lname
(fd1:fdr) <- fs `forM` \(L _ (HsRecField (L _ (FieldOcc lnameF _)) fExpr _)) -> do
fExpDoc <- layoutExpr fExpr
return $ (lrdrNameToText lnameF, fExpDoc)
return $ BDAlt
[ BDAddBaseY BrIndentRegular
$ docPar
(BDLit t)
(BDLines $ let
line1 = BDCols ColRecUpdate
[ appSep $ BDLit $ Text.pack "{"
, appSep $ BDLit $ fst fd1
, BDSeq [ appSep $ BDLit $ Text.pack "="
, BDAddBaseY BrIndentRegular $ snd fd1
]
]
lineR = fdr <&> \(fText, fDoc) -> BDCols ColRecUpdate
[ appSep $ BDLit $ Text.pack ","
, appSep $ BDLit $ fText
, BDSeq [ appSep $ BDLit $ Text.pack "="
, BDAddBaseY BrIndentRegular fDoc
]
]
lineN = BDLit $ Text.pack "}"
in [line1] ++ lineR ++ [lineN])
-- TODO oneliner (?)
]
RecordCon{} ->
unknownNodeError "RecordCon with puns" lexpr
RecordUpd rExpr [] _ _ _ _ -> do
rExprDoc <- layoutExpr rExpr
return $ BDSeq [rExprDoc, BDLit $ Text.pack "{}"]
RecordUpd rExpr fields@(_:_) _ _ _ _ -> do
rExprDoc <- layoutExpr rExpr
rF1:rFr <- fields `forM` \(L _ (HsRecField (L _ ambName) rFExpr _)) -> do
rFExpDoc <- layoutExpr rFExpr
return $ case ambName of
Unambiguous n _ -> (lrdrNameToText n, rFExpDoc)
Ambiguous n _ -> (lrdrNameToText n, rFExpDoc)
return $ BDAlt
[ BDAddBaseY BrIndentRegular
$ docPar
rExprDoc
(BDLines $ let
line1 = BDCols ColRecUpdate
[ appSep $ BDLit $ Text.pack "{"
, appSep $ BDLit $ fst rF1
, BDSeq [ appSep $ BDLit $ Text.pack "="
, BDAddBaseY BrIndentRegular $ snd rF1
]
]
lineR = rFr <&> \(fText, fDoc) -> BDCols ColRecUpdate
[ appSep $ BDLit $ Text.pack ","
, appSep $ BDLit $ fText
, BDSeq [ appSep $ BDLit $ Text.pack "="
, BDAddBaseY BrIndentRegular fDoc
]
]
lineN = BDLit $ Text.pack "}"
in [line1] ++ lineR ++ [lineN])
-- TODO oneliner (?)
]
ExprWithTySig{} -> do
-- TODO
briDocByExact lexpr
ExprWithTySigOut{} -> do
-- TODO
briDocByExact lexpr
ArithSeq _ Nothing info ->
case info of
From e1 -> do
e1Doc <- layoutExpr e1
return $ BDSeq
[ BDLit $ Text.pack "["
, BDForceSingleline e1Doc
, BDLit $ Text.pack "..]"
]
FromThen e1 e2 -> do
e1Doc <- layoutExpr e1
e2Doc <- layoutExpr e2
return $ BDSeq
[ BDLit $ Text.pack "["
, BDForceSingleline e1Doc
, BDLit $ Text.pack ","
, BDForceSingleline e2Doc
, BDLit $ Text.pack "..]"
]
FromTo e1 eN -> do
e1Doc <- layoutExpr e1
eNDoc <- layoutExpr eN
return $ BDSeq
[ BDLit $ Text.pack "["
, BDForceSingleline e1Doc
, BDLit $ Text.pack ".."
, BDForceSingleline eNDoc
, BDLit $ Text.pack "]"
]
FromThenTo e1 e2 eN -> do
e1Doc <- layoutExpr e1
e2Doc <- layoutExpr e2
eNDoc <- layoutExpr eN
return $ BDSeq
[ BDLit $ Text.pack "["
, BDForceSingleline e1Doc
, BDLit $ Text.pack ","
, BDForceSingleline e2Doc
, BDLit $ Text.pack ".."
, BDForceSingleline eNDoc
, BDLit $ Text.pack "]"
]
ArithSeq{} ->
unknownNodeError "ArithSeq" lexpr
PArrSeq{} -> do
-- TODO
briDocByExact lexpr
HsSCC{} -> do
-- TODO
briDocByExact lexpr
HsCoreAnn{} -> do
-- TODO
briDocByExact lexpr
HsBracket{} -> do
-- TODO
briDocByExact lexpr
HsRnBracketOut{} -> do
-- TODO
briDocByExact lexpr
HsTcBracketOut{} -> do
-- TODO
briDocByExact lexpr
HsSpliceE{} -> do
-- TODO
briDocByExact lexpr
HsProc{} -> do
-- TODO
briDocByExact lexpr
HsStatic{} -> do
-- TODO
briDocByExact lexpr
HsArrApp{} -> do
-- TODO
briDocByExact lexpr
HsArrForm{} -> do
-- TODO
briDocByExact lexpr
HsTick{} -> do
-- TODO
briDocByExact lexpr
HsBinTick{} -> do
-- TODO
briDocByExact lexpr
HsTickPragma{} -> do
-- TODO
briDocByExact lexpr
EWildPat{} -> do
-- TODO
briDocByExact lexpr
EAsPat{} -> do
-- TODO
briDocByExact lexpr
EViewPat{} -> do
-- TODO
briDocByExact lexpr
ELazyPat{} -> do
-- TODO
briDocByExact lexpr
HsWrap{} -> do
-- TODO
briDocByExact lexpr
layoutGrhsCase :: Maybe BriDoc -> ToBriDoc' (GRHS RdrName (LHsExpr RdrName))
layoutGrhsCase mPatPart lgrhs@(L _ (GRHS guards body)) = do
bodyDoc <- BDAddBaseY BrIndentRegular
<$> layoutExpr body
let patPart = fromMaybe BDEmpty mPatPart
docWrapNode lgrhs <$> case guards of
[] ->
return $ BDCols ColEquation [patPart, BDSeq [appSep $ BDLit $ Text.pack "->", bodyDoc]]
[guard1] -> do
guardDoc1 <- layoutGuardLStmt guard1
return $ BDAlt
[ BDCols ColGuardedEquation
[ patPart
, BDSeq [BDLit $ Text.pack "| ", appSep $ guardDoc1]
, BDSeq [appSep $ BDLit $ Text.pack "->", bodyDoc]
]
, BDAddBaseY BrIndentRegular
$ docPar patPart
$ BDSeq
[ BDLit $ Text.pack "| "
, guardDoc1
, appSep $ BDSeq [BDLit $ Text.pack "->"]
, bodyDoc
]
, BDAddBaseY BrIndentRegular
$ docPar patPart
$ BDLines
[ BDSeq [appSep $ BDLit $ Text.pack "|", appSep guardDoc1]
, BDSeq [appSep $ BDLit $ Text.pack "->", bodyDoc]
]
]
(guard1:guardr) -> do
guardDoc1 <- layoutGuardLStmt guard1
guardDocr <- layoutGuardLStmt `mapM` guardr
let hat = BDCols ColGuardedEquation
[patPart, BDSeq [appSep $ BDLit $ Text.pack "|", appSep guardDoc1]]
middle = guardDocr <&> \gd -> BDCols ColGuardedEquation
[BDEmpty, BDSeq [appSep $ BDLit $ Text.pack ",", gd]]
last = BDCols ColGuardedEquation
[BDEmpty, BDSeq [appSep $ BDLit $ Text.pack "->", bodyDoc]]
return $ BDAlt
[ BDCols ColGuardedEquation
[ BDForceSingleline patPart
, BDSeq $ [appSep $ BDLit $ Text.pack "|", appSep $ BDForceSingleline guardDoc1]
++ (guardDocr >>= \gd ->
[appSep $ BDLit $ Text.pack ",", BDForceSingleline gd])
, BDSeq [appSep $ BDLit $ Text.pack "->", bodyDoc]
]
, BDLines $ [hat] ++ middle ++ [last]
]
layoutGrhsMWIf :: ToBriDoc' (GRHS RdrName (LHsExpr RdrName))
layoutGrhsMWIf lgrhs@(L _ (GRHS guards body)) = do
bodyDoc <- BDAddBaseY BrIndentRegular
<$> layoutExpr body
docWrapNode lgrhs <$> case guards of
[] ->
unknownNodeError "layoutGrhsMWIf no guards" lgrhs
[guard1] -> do
guardDoc1 <- layoutGuardLStmt guard1
return $ BDAlt
[ BDCols ColGuardedEquation
[ BDSeq [appSep $ BDLit $ Text.pack "|", appSep $ BDForceSingleline guardDoc1]
, BDSeq [appSep $ BDLit $ Text.pack "->", bodyDoc]
]
, BDLines
[ BDSeq [appSep $ BDLit $ Text.pack "|", appSep guardDoc1, BDLit $ Text.pack "->"]
, BDEnsureIndent BrIndentRegular $ bodyDoc
]
]
(guard1:guardr) -> do
guardDoc1 <- layoutGuardLStmt guard1
guardDocr <- layoutGuardLStmt `mapM` guardr
let hat = BDCols ColGuardedEquation
[BDSeq [appSep $ BDLit $ Text.pack "|", guardDoc1]]
middle = guardDocr <&> \gd -> BDCols ColGuardedEquation
[BDSeq [appSep $ BDLit $ Text.pack " ,", appSep gd, BDLit $ Text.pack "->"]]
last = BDCols ColGuardedEquation
[BDSeq [BDLit $ Text.pack " ", bodyDoc]]
return $ BDAlt
[ BDCols ColGuardedEquation
[ BDSeq $ [appSep $ BDLit $ Text.pack "|", BDForceSingleline guardDoc1]
++ (guardDocr >>= \gd ->
[appSep $ BDLit $ Text.pack ",", BDForceSingleline gd])
, BDSeq [appSep $ BDLit $ Text.pack "->", bodyDoc]
]
, BDLines $ [hat] ++ middle ++ [last]
]
layoutGrhsLCase :: Maybe BriDoc -> ToBriDoc' (GRHS RdrName (LHsExpr RdrName))
layoutGrhsLCase mPatPart lgrhs@(L _ (GRHS guards body)) = do
bodyDoc <- BDAddBaseY BrIndentRegular <$> layoutExpr body
let patPart = fromMaybe BDEmpty mPatPart
docWrapNode lgrhs <$> case guards of
[] ->
return $ BDCols ColEquation [patPart, BDSeq [appSep $ BDLit $ Text.pack "->", bodyDoc]]
[guard1] -> do
guardDoc1 <- layoutGuardLStmt guard1
return $ BDAlt
[ BDCols ColGuardedEquation
[ patPart
, BDSeq [appSep $ BDLit $ Text.pack "|", appSep guardDoc1]
, BDSeq [appSep $ BDLit $ Text.pack "->", bodyDoc]
]
, BDAddBaseY BrIndentRegular
$ docPar patPart
$ BDSeq
[ BDLit $ Text.pack "| "
, guardDoc1
, appSep $ BDSeq [BDLit $ Text.pack "->"]
, bodyDoc
]
, BDAddBaseY BrIndentRegular
$ docPar patPart
$ BDLines
[ BDSeq [appSep $ BDLit $ Text.pack "|", appSep guardDoc1]
, BDSeq [appSep $ BDLit $ Text.pack "->", bodyDoc]
]
]
(guard1:guardr) -> do
guardDoc1 <- layoutGuardLStmt guard1
guardDocr <- layoutGuardLStmt `mapM` guardr
let hat = BDCols ColGuardedEquation
[patPart, BDSeq [appSep $ BDLit $ Text.pack "|", guardDoc1]]
middle = guardDocr <&> \gd -> BDCols ColGuardedEquation
[BDEmpty, BDSeq [appSep $ BDLit $ Text.pack ",", gd]]
last = BDCols ColGuardedEquation
[BDEmpty, BDSeq [appSep $ BDLit $ Text.pack "->", bodyDoc]]
return $ BDAlt
[ BDCols ColGuardedEquation
[ BDForceSingleline patPart
, BDSeq $ [appSep $ BDLit $ Text.pack "|", appSep $ BDForceSingleline guardDoc1]
++ (guardDocr >>= \gd ->
[appSep $ BDLit $ Text.pack ",", appSep $ BDForceSingleline gd])
, BDSeq [appSep $ BDLit $ Text.pack "->", bodyDoc]
]
, BDLines $ [hat] ++ middle ++ [last]
]
litBriDoc :: HsLit -> BriDoc
litBriDoc = \case
HsChar t _c -> BDLit $ Text.pack t -- BDLit $ Text.pack $ ['\'', c, '\'']
HsCharPrim t _c -> BDLit $ Text.pack t -- BDLit $ Text.pack $ ['\'', c, '\'']
HsString t _fastString -> BDLit $ Text.pack t -- BDLit $ Text.pack $ FastString.unpackFS fastString
HsStringPrim t _byteString -> BDLit $ Text.pack t -- BDLit $ Text.pack $ Data.ByteString.Char8.unpack byteString
HsInt t _i -> BDLit $ Text.pack t -- BDLit $ Text.pack $ show i
HsIntPrim t _i -> BDLit $ Text.pack t -- BDLit $ Text.pack $ show i
HsWordPrim t _i -> BDLit $ Text.pack t -- BDLit $ Text.pack $ show i
HsInt64Prim t _i -> BDLit $ Text.pack t -- BDLit $ Text.pack $ show i
HsWord64Prim t _i -> BDLit $ Text.pack t -- BDLit $ Text.pack $ show i
HsInteger t _i _type -> BDLit $ Text.pack t -- BDLit $ Text.pack $ show i
HsRat (FL t _) _type -> BDLit $ Text.pack t
HsFloatPrim (FL t _) -> BDLit $ Text.pack t
HsDoublePrim (FL t _) -> BDLit $ Text.pack t
overLitValBriDoc :: OverLitVal -> BriDoc
overLitValBriDoc = \case
HsIntegral t _ -> BDLit $ Text.pack t
HsFractional (FL t _) -> BDLit $ Text.pack t
HsIsString t _ -> BDLit $ Text.pack t

View File

@ -0,0 +1,28 @@
{-# LANGUAGE DataKinds #-}
module Language.Haskell.Brittany.Layouters.Expr
( layoutExpr
, litBriDoc
)
where
#include "prelude.inc"
import Language.Haskell.Brittany.Types
import Language.Haskell.Brittany.LayoutBasics
import RdrName ( RdrName(..) )
import GHC ( runGhc, GenLocated(L), moduleNameString )
import SrcLoc ( SrcSpan )
import HsSyn
import Name
layoutExpr :: ToBriDoc HsExpr
-- layoutStmt :: ToBriDoc' (StmtLR RdrName RdrName (LHsExpr RdrName))
litBriDoc :: HsLit -> BriDoc

View File

@ -0,0 +1,76 @@
{-# LANGUAGE DataKinds #-}
module Language.Haskell.Brittany.Layouters.Pattern
( layoutPat
)
where
#include "prelude.inc"
import Language.Haskell.Brittany.Types
import Language.Haskell.Brittany.LayoutBasics
import RdrName ( RdrName(..) )
import GHC ( runGhc, GenLocated(L), moduleNameString )
import SrcLoc ( SrcSpan )
import HsSyn
import Name
import BasicTypes
import {-# SOURCE #-} Language.Haskell.Brittany.Layouters.Expr
layoutPat :: ToBriDoc Pat
layoutPat lpat@(L _ pat) = fmap (docWrapNode lpat) $ case pat of
WildPat _ -> return $ BDLit $ Text.pack "_"
VarPat n -> return $ BDLit $ lrdrNameToText n
LitPat lit -> return $ litBriDoc lit
ParPat inner -> do
innerDoc <- layoutPat inner
return $ BDSeq
[ BDLit $ Text.pack "("
, innerDoc
, BDLit $ Text.pack ")"
]
ConPatIn lname (PrefixCon args) -> do
let nameDoc = lrdrNameToText lname
argDocs <- layoutPat `mapM` args
return $ BDSeq $
appSep (BDLit nameDoc) : spacifyDocs argDocs
ConPatIn lname (InfixCon left right) -> do
let nameDoc = lrdrNameToText lname
leftDoc <- layoutPat left
rightDoc <- layoutPat right
return $ BDSeq [leftDoc, BDLit nameDoc, rightDoc]
TuplePat args boxity _ -> do
argDocs <- layoutPat `mapM` args
return $ case boxity of
Boxed -> BDAlt
[ BDSeq
$ [ BDLit $ Text.pack "(" ]
++ List.intersperse (appSep $ BDLit $ Text.pack ",") argDocs
++ [ BDLit $ Text.pack ")"]
-- TODO
]
Unboxed -> BDAlt
[ BDSeq
$ [ BDLit $ Text.pack "(#" ]
++ List.intersperse (appSep $ BDLit $ Text.pack ",") argDocs
++ [ BDLit $ Text.pack "#)"]
-- TODO
]
AsPat asName asPat -> do
patDoc <- layoutPat asPat
return $ BDSeq
[ BDLit $ lrdrNameToText asName <> Text.pack "@"
, patDoc
]
-- #if MIN_VERSION_ghc(8,0,0)
-- VarPat n -> return $ stringLayouter lpat $ lrdrNameToText n
-- #else
-- VarPat n -> return $ stringLayouter lpat $ rdrNameToText n
-- #endif
_ -> briDocByExact lpat

View File

@ -0,0 +1,77 @@
{-# LANGUAGE DataKinds #-}
module Language.Haskell.Brittany.Layouters.Stmt
( layoutStmt
)
where
#include "prelude.inc"
import Language.Haskell.Brittany.Types
import Language.Haskell.Brittany.LayoutBasics
import RdrName ( RdrName(..) )
import GHC ( runGhc, GenLocated(L), moduleNameString )
import SrcLoc ( SrcSpan )
import HsSyn
import Name
import qualified FastString
import BasicTypes
import Language.Haskell.Brittany.Layouters.Pattern
import Language.Haskell.Brittany.Layouters.Decl
import {-# SOURCE #-} Language.Haskell.Brittany.Layouters.Expr
layoutStmt :: ToBriDoc' (StmtLR RdrName RdrName (LHsExpr RdrName))
layoutStmt lstmt@(L _ stmt) = case stmt of
LastStmt body False _ -> do
layoutExpr body
BindStmt lPat expr _ _ _ -> do
patDoc <- layoutPat lPat
expDoc <- layoutExpr expr
return $ docWrapNode lstmt
$ BDCols ColDoBind
[patDoc, BDSeq [BDLit $ Text.pack " <- ", expDoc]]
LetStmt binds -> layoutLocalBinds binds >>= \case
Nothing ->
return $ docWrapNode lstmt $ BDLit $ Text.pack "let" -- i just tested
-- it, and it is
-- indeed allowed.
-- heh.
Just [] ->
return $ docWrapNode lstmt $ BDLit $ Text.pack "let" -- this probably never happens
Just [bindDoc] -> return $ docWrapNode lstmt $ BDAlt
[ BDCols ColDoLet
[ appSep $ BDLit $ Text.pack "let"
, BDAddBaseY (BrIndentSpecial 4) bindDoc
]
, BDAddBaseY BrIndentRegular $ docPar
(BDLit $ Text.pack "let")
bindDoc
]
Just bindDocs@(bindDoc1:bindDocr) -> do
return $ docWrapNode lstmt
$ BDAlt
[ BDLines
$ (BDCols ColDoLet
[ appSep $ BDLit $ Text.pack "let"
, BDAddBaseY (BrIndentSpecial 4) bindDoc1
])
: (bindDocr <&> \bindDoc ->
BDCols ColDoLet
[ appSep $ BDEmpty
, BDAddBaseY (BrIndentSpecial 4) bindDoc
])
, BDAddBaseY BrIndentRegular
$ docPar
(BDLit $ Text.pack "let")
(BDLines bindDocs)
]
BodyStmt expr _ _ _ -> do
expDoc <- layoutExpr expr
return $ docWrapNode lstmt $ BDAddBaseY BrIndentRegular $ expDoc
_ -> briDocByExact lstmt

View File

@ -0,0 +1,648 @@
{-# LANGUAGE DataKinds #-}
module Language.Haskell.Brittany.Layouters.Type
( layoutType
)
where
#include "prelude.inc"
import Language.Haskell.Brittany.Config.Types
import Language.Haskell.Brittany.Types
import Language.Haskell.Brittany.LayoutBasics
import RdrName ( RdrName(..) )
import GHC ( runGhc, GenLocated(L), moduleNameString )
import Language.Haskell.GHC.ExactPrint.Types ( mkAnnKey )
import SrcLoc ( SrcSpan )
import HsSyn
import Name
import Outputable ( ftext, showSDocUnsafe )
import DataTreePrint
layoutType :: ToBriDoc HsType
layoutType ltype@(L _ typ) = case typ of
-- _ | traceShow (ExactPrint.Types.mkAnnKey ltype) False -> error "impossible"
HsTyVar name -> do
let t = lrdrNameToText name
return $ docWrapNode ltype $ docLit t
HsForAllTy bndrs (L _ (HsQualTy (L _ cntxts@(_:_)) typ2)) -> do
typeDoc <- layoutType typ2
tyVarDocs <- bndrs `forM` \case
(L _ (UserTyVar name)) -> return $ (lrdrNameToText name, Nothing)
(L _ (KindedTyVar lrdrName kind)) -> do
d <- layoutType kind
return $ (lrdrNameToText lrdrName, Just d)
cntxtDocs <- cntxts `forM` layoutType
let
tyVarDocLineList = tyVarDocs >>= \case
(tname, Nothing) -> [BDLit $ Text.pack " " <> tname]
(tname, Just doc) -> [ BDLit $ Text.pack " ("
<> tname
<> Text.pack " :: "
, BDForceSingleline doc
, BDLit $ Text.pack ")"
]
forallDoc = BDAlt
[ let
open = BDLit $ Text.pack "forall"
in BDSeq ([open]++tyVarDocLineList)
, docPar
(BDLit (Text.pack "forall"))
(BDLines
$ tyVarDocs <&> \case
(tname, Nothing) -> BDEnsureIndent BrIndentRegular $ BDLit tname
(tname, Just doc) -> BDEnsureIndent BrIndentRegular
$ BDLines
[ BDCols ColTyOpPrefix
[ docParenLSep
, BDLit tname
]
, BDCols ColTyOpPrefix
[ BDLit $ Text.pack ":: "
, doc
]
, BDLit $ Text.pack ")"
])
]
contextDoc = case cntxtDocs of
[x] -> x
_ -> BDAlt
[ let
open = BDLit $ Text.pack "("
close = BDLit $ Text.pack ")"
list = List.intersperse docCommaSep
$ BDForceSingleline <$> cntxtDocs
in BDSeq ([open]++list++[close])
, let
open = BDCols ColTyOpPrefix
[ docParenLSep
, BDAddBaseY (BrIndentSpecial 2) $ head cntxtDocs
]
close = BDLit $ Text.pack ")"
list = List.tail cntxtDocs <&> \cntxtDoc ->
BDCols ColTyOpPrefix
[ docCommaSep
, BDAddBaseY (BrIndentSpecial 2) cntxtDoc
]
in docPar open $ BDLines $ list ++ [close]
]
return $ docWrapNode ltype $ BDAlt
-- :: forall a b c . (Foo a b c) => a b -> c
[ BDSeq
[ if null bndrs
then BDEmpty
else let
open = BDLit $ Text.pack "forall"
close = BDLit $ Text.pack " . "
in BDSeq ([open]++tyVarDocLineList++[close])
, BDForceSingleline contextDoc
, BDLit $ Text.pack " => "
, typeDoc
]
-- :: forall a b c
-- . (Foo a b c)
-- => a b
-- -> c
, docPar
forallDoc
( BDLines
[ BDCols ColTyOpPrefix
[ docPostComment ltype $ BDLit $ Text.pack " . "
, BDAddBaseY (BrIndentSpecial 3)
$ BDForceSingleline contextDoc
]
, BDCols ColTyOpPrefix
[ BDLit $ Text.pack "=> "
, BDAddBaseY (BrIndentSpecial 3) $ BDForceMultiline typeDoc
]
]
)
]
HsForAllTy bndrs typ2 -> do
typeDoc <- layoutType typ2
tyVarDocs <- bndrs `forM` \case
(L _ (UserTyVar name)) -> return $ (lrdrNameToText name, Nothing)
(L _ (KindedTyVar lrdrName kind)) -> do
d <- layoutType kind
return $ (lrdrNameToText lrdrName, Just d)
let
tyVarDocLineList = tyVarDocs >>= \case
(tname, Nothing) -> [BDLit $ Text.pack " " <> tname]
(tname, Just doc) -> [ BDLit $ Text.pack " ("
<> tname
<> Text.pack " :: "
, BDForceSingleline doc
, BDLit $ Text.pack ")"
]
return $ docWrapNode ltype $ BDAlt
[ BDSeq
[ if null bndrs
then BDEmpty
else let
open = BDLit $ Text.pack "forall"
close = BDLit $ Text.pack " . "
in BDSeq ([open]++tyVarDocLineList++[close])
, typeDoc
]
, docPar
(BDSeq $ BDLit (Text.pack "forall") : tyVarDocLineList)
( BDCols ColTyOpPrefix
[ docPostComment ltype $ BDLit $ Text.pack ". "
, typeDoc
]
)
, docPar
(BDLit (Text.pack "forall"))
(BDLines
$ (tyVarDocs <&> \case
(tname, Nothing) -> BDEnsureIndent BrIndentRegular $ BDLit tname
(tname, Just doc) -> BDEnsureIndent BrIndentRegular
$ BDLines
[ BDCols ColTyOpPrefix
[ docParenLSep
, BDLit tname
]
, BDCols ColTyOpPrefix
[ BDLit $ Text.pack ":: "
, doc
]
, BDLit $ Text.pack ")"
]
)
++[ BDCols ColTyOpPrefix
[ docPostComment ltype $ BDLit $ Text.pack ". "
, typeDoc
]
]
)
]
x@(HsQualTy (L _ []) _) ->
unknownNodeError "HsQualTy [] _" x
HsQualTy (L _ cntxts@(_:_)) typ1 -> do
typeDoc <- layoutType typ1
cntxtDocs <- cntxts `forM` layoutType
let
contextDoc = case cntxtDocs of
[x] -> x
_ -> BDAlt
[ let
open = BDLit $ Text.pack "("
close = BDLit $ Text.pack ")"
list = List.intersperse docCommaSep
$ BDForceSingleline <$> cntxtDocs
in BDSeq ([open]++list++[close])
, let
open = BDCols ColTyOpPrefix
[ docParenLSep
, BDAddBaseY (BrIndentSpecial 2)
$ head cntxtDocs
]
close = BDLit $ Text.pack ")"
list = List.tail cntxtDocs <&> \cntxtDoc ->
BDCols ColTyOpPrefix
[ docCommaSep
, BDAddBaseY (BrIndentSpecial 2)
$ cntxtDoc
]
in docPar open $ BDLines $ list ++ [close]
]
return $ docWrapNode ltype $ BDAlt
-- (Foo a b c) => a b -> c
[ BDSeq
[ BDForceSingleline contextDoc
, BDLit $ Text.pack " => "
, typeDoc
]
-- (Foo a b c)
-- => a b
-- -> c
, docPar
(BDForceSingleline contextDoc)
( BDCols ColTyOpPrefix
[ BDLit $ Text.pack "=> "
, BDAddBaseY (BrIndentSpecial 3) $ BDForceMultiline typeDoc
]
)
]
-- HsQualTy (L _ cntxts) typ2 -> do
-- layouter@(Layouter desc _ _) <- layoutType typ2
-- cntxtLayouters <- cntxts `forM` layoutType
-- let mLine =
-- [ LayoutColumns ColumnKeyUnique [len] len
-- | -- (A a, B b) =>
-- -- 1 2 6
-- constraintLen <- if null cntxts
-- then return 0
-- else ( sequence
-- $ cntxtLayouters <&> _layouter_desc .> _ldesc_line)
-- <&> \cols -> 5
-- + 2 * length cols
-- + sum (_lColumns_min <$> cols)
-- , tyLen <- _lColumns_min <$> _ldesc_line desc
-- , let len = constraintLen + tyLen
-- ]
-- let mBlock =
-- [ BlockDesc
-- { _bdesc_blockStart = AllSameIndent -- this might not be accurate,
-- -- but it should simply not matter.
-- -- *lazy*
-- , _bdesc_min = minR
-- , _bdesc_max = maxR
-- , _bdesc_opIndentFloatUp = Nothing
-- }
-- | (tyMin, tyMax) <- descToMinMax 0 desc
-- , constrMinMaxs <- sequence $ cntxtLayouters <&> _layouter_desc .> descToMinMax 0
-- , let constrMin = constrMinMaxs <&> fst & maximum
-- , let constrMax = constrMinMaxs <&> snd & maximum
-- , let minR = 3 + maximum [constrMin, tyMin]
-- , let maxR = 3 + maximum [constrMax, tyMax]
-- ]
-- return $ Layouter
-- { _layouter_desc = LayoutDesc
-- { _ldesc_line = mLine
-- , _ldesc_block = mBlock
-- }
-- , _layouter_func = \params -> do
-- layoutWritePriorCommentsRestore ltype
-- remaining <- getCurRemaining
-- case mLine of
-- Just (LayoutColumns _ _ m) | m <= remaining -> do
-- when (not $ null cntxts) $ do
-- layoutWriteAppend $ Text.pack "("
-- sequence_ $ intersperse (layoutWriteAppend $ Text.pack ", ")
-- $ cntxtLayouters <&> \lay -> applyLayouterRestore lay defaultParams
-- layoutWriteAppend $ Text.pack ") => "
-- applyLayouterRestore layouter defaultParams
-- _ -> do
-- if null cntxts
-- then do
-- layoutWriteAppend $ Text.pack "()"
-- else do
-- layoutWithNonParamIndent params $ do
-- layoutWriteAppend $ Text.pack "( "
-- let iAct = do
-- layoutWriteNewline
-- layoutWriteAppend $ Text.pack ", "
-- sequence_ $ intersperse iAct
-- $ cntxtLayouters <&> \lay -> applyLayouter lay defaultParams
-- layoutWriteNewline
-- layoutWriteAppend $ Text.pack ")"
-- layoutWriteNewline
-- layoutWriteAppend $ Text.pack "=> "
-- applyLayouterRestore layouter defaultParams
-- { _params_opIndent = _params_opIndent params
-- }
-- , _layouter_ast = ltype
-- }
HsFunTy typ1 typ2 -> do
typeDoc1 <- layoutType typ1
typeDoc2 <- layoutType typ2
let shouldForceML = case typ2 of
(L _ HsFunTy{}) -> True
_ -> False
return $ docWrapNode ltype $ BDAlt
[ BDSeq
[ BDForceSingleline typeDoc1
, docPostComment ltype $ appSep $ BDLit $ Text.pack " ->"
, BDForceSingleline typeDoc2
]
, docPar
typeDoc1
( BDCols ColTyOpPrefix
[ docPostComment ltype $ appSep $ BDLit $ Text.pack "->"
, BDAddBaseY (BrIndentSpecial 3)
$ if shouldForceML then BDForceMultiline typeDoc2
else typeDoc2
]
)
]
HsParTy typ1 -> do
typeDoc1 <- layoutType typ1
return $ docWrapNode ltype $ BDAlt
[ BDSeq
[ docPostComment ltype $ BDLit $ Text.pack "("
, BDForceSingleline typeDoc1
, BDLit $ Text.pack ")"
]
, docPar
( BDCols ColTyOpPrefix
[ docPostComment ltype $ docParenLSep
, BDAddBaseY (BrIndentSpecial 2) $ typeDoc1
])
(BDLit $ Text.pack ")")
]
HsAppTy typ1 typ2 -> do
typeDoc1 <- layoutType typ1
typeDoc2 <- layoutType typ2
return $ docWrapNode ltype $ BDAlt
[ BDSeq
[ BDForceSingleline typeDoc1
, BDLit $ Text.pack " "
, BDForceSingleline typeDoc2
]
, docPar
typeDoc1
(BDEnsureIndent BrIndentRegular typeDoc2)
]
HsAppsTy [] -> error "HsAppsTy []"
HsAppsTy [L _ (HsAppPrefix typ1)] -> do
typeDoc1 <- layoutType typ1
return $ docWrapNode ltype $ typeDoc1
HsAppsTy [L l (HsAppInfix name)] -> do
-- this redirection is somewhat hacky, but whatever.
-- TODO: a general problem when doing deep inspections on
-- the type (and this is not the only instance)
-- is that we potentially omit annotations on some of
-- the middle constructors. i have no idea under which
-- circumstances exactly important annotations (comments)
-- would be assigned to such constructors.
typeDoc1 <- layoutType $ (L l $ HsTyVar name)
return $ docWrapNode ltype $ typeDoc1
HsAppsTy (L _ (HsAppPrefix typHead):typRestA)
| Just typRest <- mapM (\case L _ (HsAppPrefix t) -> Just t
_ -> Nothing) typRestA -> do
docHead <- layoutType typHead
docRest <- mapM layoutType typRest
return $ docWrapNode ltype $ BDAlt
[ BDSeq
$ BDForceSingleline docHead : (docRest >>= \d ->
[ BDLit $ Text.pack " ", BDForceSingleline d ])
, docPar docHead (BDLines $ BDEnsureIndent BrIndentRegular <$> docRest)
]
HsAppsTy (typHead:typRest) -> do
docHead <- layoutAppType typHead
docRest <- mapM layoutAppType typRest
return $ docWrapNode ltype $ BDAlt
[ BDSeq
$ BDForceSingleline docHead : (docRest >>= \d ->
[ BDLit $ Text.pack " ", BDForceSingleline d ])
, docPar docHead (BDLines $ BDEnsureIndent BrIndentRegular <$> docRest)
]
where
layoutAppType (L _ (HsAppPrefix t)) = layoutType t
layoutAppType (L _ (HsAppInfix t)) = BDLit <$> lrdrNameToTextAnn t
HsListTy typ1 -> do
typeDoc1 <- layoutType typ1
return $ docWrapNode ltype $ BDAlt
[ BDSeq
[ docPostComment ltype $ BDLit $ Text.pack "["
, BDForceSingleline typeDoc1
, BDLit $ Text.pack "]"
]
, docPar
( BDCols ColTyOpPrefix
[ docPostComment ltype $ BDLit $ Text.pack "[ "
, BDAddBaseY (BrIndentSpecial 2) $ typeDoc1
])
(BDLit $ Text.pack "]")
]
HsPArrTy typ1 -> do
typeDoc1 <- layoutType typ1
return $ docWrapNode ltype $ BDAlt
[ BDSeq
[ docPostComment ltype $ BDLit $ Text.pack "[:"
, BDForceSingleline typeDoc1
, BDLit $ Text.pack ":]"
]
, docPar
( BDCols ColTyOpPrefix
[ docPostComment ltype $ BDLit $ Text.pack "[:"
, BDAddBaseY (BrIndentSpecial 2) $ typeDoc1
])
(BDLit $ Text.pack ":]")
]
HsTupleTy tupleSort typs -> docWrapNode ltype <$> case tupleSort of
HsUnboxedTuple -> unboxed
HsBoxedTuple -> simple
HsConstraintTuple -> simple
HsBoxedOrConstraintTuple -> simple
where
unboxed = if null typs then error "unboxed unit?" else unboxedL
simple = if null typs then unitL else simpleL
unitL = return $ BDLit $ Text.pack "()"
simpleL = do
docs <- mapM layoutType typs
return $ BDAlt
[ BDSeq $ [BDLit $ Text.pack "("]
++ List.intersperse docCommaSep docs
++ [BDLit $ Text.pack ")"]
, let
start = BDCols ColTyOpPrefix [docParenLSep, head docs]
lines = List.tail docs <&> \d ->
BDCols ColTyOpPrefix [docCommaSep, d]
end = BDLit $ Text.pack ")"
in docPar
(BDAddBaseY (BrIndentSpecial 2) $ start)
(BDLines $ (BDAddBaseY (BrIndentSpecial 2) <$> lines) ++ [end])
]
unboxedL = do
docs <- mapM layoutType typs
return $ BDAlt
[ BDSeq $ [BDLit $ Text.pack "(#"]
++ List.intersperse docCommaSep docs
++ [BDLit $ Text.pack "#)"]
, let
start = BDCols ColTyOpPrefix [BDLit $ Text.pack "(#", head docs]
lines = List.tail docs <&> \d ->
BDCols ColTyOpPrefix [docCommaSep, d]
end = BDLit $ Text.pack "#)"
in docPar
(BDAddBaseY (BrIndentSpecial 2) start)
(BDLines $ (BDAddBaseY (BrIndentSpecial 2) <$> lines) ++ [end])
]
HsOpTy{} -> -- TODO
briDocByExact ltype
-- HsOpTy typ1 opName typ2 -> do
-- -- TODO: these need some proper fixing. precedences don't add up.
-- -- maybe the parser just returns some trivial right recursion
-- -- parse result for any type level operators.
-- -- need to check how things are handled on the expression level.
-- let opStr = lrdrNameToText opName
-- let opLen = Text.length opStr
-- layouter1@(Layouter desc1 _ _) <- layoutType typ1
-- layouter2@(Layouter desc2 _ _) <- layoutType typ2
-- let line = do -- Maybe
-- l1 <- _ldesc_line desc1
-- l2 <- _ldesc_line desc2
-- let len1 = _lColumns_min l1
-- let len2 = _lColumns_min l2
-- let len = 2 + opLen + len1 + len2
-- return $ LayoutColumns
-- { _lColumns_key = ColumnKeyUnique
-- , _lColumns_lengths = [len]
-- , _lColumns_min = len
-- }
-- let block = do -- Maybe
-- rol1 <- descToBlockStart desc1
-- (min2, max2) <- descToMinMax (1+opLen) desc2
-- let (minR, maxR) = case descToBlockMinMax desc1 of
-- Nothing -> (min2, max2)
-- Just (min1, max1) -> (max min1 min2, max max1 max2)
-- return $ BlockDesc
-- { _bdesc_blockStart = rol1
-- , _bdesc_min = minR
-- , _bdesc_max = maxR
-- , _bdesc_opIndentFloatUp = Just (1+opLen)
-- }
-- return $ Layouter
-- { _layouter_desc = LayoutDesc
-- { _ldesc_line = line
-- , _ldesc_block = block
-- }
-- , _layouter_func = \params -> do
-- remaining <- getCurRemaining
-- let allowSameLine = _params_sepLines params /= SepLineTypeOp
-- case line of
-- Just (LayoutColumns _ _ m) | m <= remaining && allowSameLine -> do
-- applyLayouterRestore layouter1 defaultParams
-- layoutWriteAppend $ Text.pack " " <> opStr <> Text.pack " "
-- applyLayouterRestore layouter2 defaultParams
-- _ -> do
-- let upIndent = maybe (1+opLen) (max (1+opLen)) $ _params_opIndent params
-- let downIndent = maybe upIndent (max upIndent) $ _bdesc_opIndentFloatUp =<< _ldesc_block desc2
-- layoutWithAddIndentN downIndent $ applyLayouterRestore layouter1 defaultParams
-- layoutWriteNewline
-- layoutWriteAppend $ opStr <> Text.pack " "
-- layoutWriteEnsureBlockPlusN downIndent
-- applyLayouterRestore layouter2 defaultParams
-- { _params_sepLines = SepLineTypeOp
-- , _params_opIndent = Just downIndent
-- }
-- , _layouter_ast = ltype
-- }
HsIParamTy (HsIPName ipName) typ1 -> do
typeDoc1 <- layoutType typ1
return $ docWrapNode ltype $ BDAlt
[ BDSeq
[ docPostComment ltype
$ BDLit
$ Text.pack ("?" ++ showSDocUnsafe (ftext ipName) ++ "::")
, BDForceSingleline typeDoc1
]
, docPar
( BDLit
$ Text.pack ("?" ++ showSDocUnsafe (ftext ipName))
)
(BDCols ColTyOpPrefix
[ docPostComment ltype
$ BDLit $ Text.pack "::"
, BDAddBaseY (BrIndentSpecial 2) typeDoc1
])
]
HsEqTy typ1 typ2 -> do
typeDoc1 <- layoutType typ1
typeDoc2 <- layoutType typ2
return $ docWrapNode ltype $ BDAlt
[ BDSeq
[ BDForceSingleline typeDoc1
, docPostComment ltype
$ BDLit $ Text.pack " ~ "
, BDForceSingleline typeDoc2
]
, docPar
typeDoc1
( BDCols ColTyOpPrefix
[ docPostComment ltype
$ BDLit $ Text.pack "~ "
, BDAddBaseY (BrIndentSpecial 2) typeDoc2
])
]
-- TODO: test KindSig
HsKindSig typ1 kind1 -> do
typeDoc1 <- layoutType typ1
kindDoc1 <- layoutType kind1
return $ docWrapNode ltype $ BDAlt
[ BDSeq
[ BDForceSingleline typeDoc1
, BDLit $ Text.pack " :: "
, BDForceSingleline kindDoc1
]
, docPar
typeDoc1
( BDCols ColTyOpPrefix
[ docPostComment ltype
$ BDLit $ Text.pack ":: "
, BDAddBaseY (BrIndentSpecial 3) kindDoc1
])
]
HsBangTy{} -> -- TODO
briDocByExact ltype
-- HsBangTy bang typ1 -> do
-- let bangStr = case bang of
-- HsSrcBang _ unpackness strictness ->
-- (++)
-- (case unpackness of
-- SrcUnpack -> "{-# UNPACK -#} "
-- SrcNoUnpack -> "{-# NOUNPACK -#} "
-- NoSrcUnpack -> ""
-- )
-- (case strictness of
-- SrcLazy -> "~"
-- SrcStrict -> "!"
-- NoSrcStrict -> ""
-- )
-- let bangLen = length bangStr
-- layouter@(Layouter desc _ _) <- layoutType typ1
-- let line = do -- Maybe
-- l <- _ldesc_line desc
-- let len = bangLen + _lColumns_min l
-- return $ LayoutColumns
-- { _lColumns_key = ColumnKeyUnique
-- , _lColumns_lengths = [len]
-- , _lColumns_min = len
-- }
-- let block = do -- Maybe
-- rol <- descToBlockStart desc
-- (minR,maxR) <- descToBlockMinMax desc
-- return $ BlockDesc
-- { _bdesc_blockStart = rol
-- , _bdesc_min = minR
-- , _bdesc_max = maxR
-- , _bdesc_opIndentFloatUp = Nothing
-- }
-- return $ Layouter
-- { _layouter_desc = LayoutDesc
-- { _ldesc_line = line
-- , _ldesc_block = block
-- }
-- , _layouter_func = \_params -> do
-- remaining <- getCurRemaining
-- case line of
-- Just (LayoutColumns _ _ m) | m <= remaining -> do
-- layoutWriteAppend $ Text.pack $ bangStr
-- applyLayouterRestore layouter defaultParams
-- _ -> do
-- layoutWriteAppend $ Text.pack $ bangStr
-- layoutWritePostCommentsRestore ltype
-- applyLayouterRestore layouter defaultParams
-- , _layouter_ast = ltype
-- }
HsSpliceTy{} -> -- TODO
briDocByExact ltype
HsDocTy{} -> -- TODO
briDocByExact ltype
HsRecTy{} -> -- TODO
briDocByExact ltype
HsExplicitListTy _ typs -> do
typDocs <- typs `forM` layoutType
return $ BDAlt
[ BDSeq
$ [BDLit $ Text.pack "'["]
++ List.intersperse docCommaSep typDocs
++ [BDLit $ Text.pack "]"]
-- TODO
]
HsExplicitTupleTy{} -> -- TODO
briDocByExact ltype
HsTyLit{} -> -- TODO
briDocByExact ltype
HsCoreTy{} -> -- TODO
briDocByExact ltype
HsWildCardTy{} -> -- TODO
briDocByExact ltype

View File

@ -0,0 +1,28 @@
module Language.Haskell.Brittany.Prelude
where
import Prelude
import qualified Data.Strict.Maybe as Strict
import Debug.Trace
instance Applicative Strict.Maybe where
pure = Strict.Just
Strict.Just f <*> Strict.Just x = Strict.Just (f x)
_ <*> _ = Strict.Nothing
instance Monad Strict.Maybe where
return = Strict.Just
Strict.Nothing >>= _ = Strict.Nothing
Strict.Just x >>= f = f x
traceFunctionWith
:: String -> (a -> String) -> (b -> String) -> (a -> b) -> (a -> b)
traceFunctionWith name s1 s2 f x =
trace traceStr y
where
y = f x
traceStr = name ++ "\nBEFORE:\n" ++ s1 x ++ "\nAFTER:\n" ++ s2 y

View File

@ -0,0 +1,207 @@
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE PatternSynonyms #-}
module Language.Haskell.Brittany.Types
where
#include "prelude.inc"
import qualified Language.Haskell.GHC.ExactPrint as ExactPrint
import qualified Data.Text.Lazy.Builder as Text.Builder
import RdrName ( RdrName(..) )
import GHC ( runGhc, GenLocated(L), moduleNameString )
import SrcLoc ( SrcSpan )
import Language.Haskell.GHC.ExactPrint ( AnnKey, Comment )
import Language.Haskell.GHC.ExactPrint.Types ( Anns, DeltaPos, mkAnnKey )
import Language.Haskell.Brittany.Config.Types
type PPM a = MultiRWSS.MultiRWS '[Config, ExactPrint.Anns] '[Text.Builder.Builder, [LayoutError], Seq String] '[] a
type PriorMap = Map AnnKey [(Comment, DeltaPos)]
type PostMap = Map AnnKey [(Comment, DeltaPos)]
data LayoutState = LayoutState
{ _lstate_baseY :: Int -- ^ number of current indentation columns
-- (not number of indentations).
, _lstate_curY :: Int -- ^ number of chars in the current line.
, _lstate_indLevel :: Int -- ^ current indentation level. set for
-- any layout-affected elements such as
-- let/do/case/where elements.
-- The main purpose of this member is to
-- properly align comments, as their
-- annotation positions are relative to the
-- current layout indentation level.
, _lstate_indLevelLinger :: Int -- like a "last" of indLevel. Used for
-- properly treating cases where comments
-- on the first indented element have an
-- annotation offset relative to the last
-- non-indented element, which is confusing.
, _lstate_commentsPrior :: PriorMap -- map of "true" pre-node comments that
-- really _should_ be included in the
-- output.
, _lstate_commentsPost :: PostMap -- similarly, for post-node comments.
, _lstate_commentCol :: Maybe Int
, _lstate_addSepSpace :: Maybe Int -- number of spaces to insert if anyone
-- writes (any non-spaces) in the
-- current line.
, _lstate_inhibitMTEL :: Bool
-- ^ inhibit move-to-exact-location.
-- normally, processing a node's annotation involves moving to the exact
-- (vertical) location of the node. this ensures that newlines in the
-- input are retained in the output.
-- While this flag is on, this behaviour will be disabled.
-- The flag is automatically turned off when inserting any kind of
-- newline.
, _lstate_isNewline :: NewLineState
-- captures if the layouter currently is in a new line, i.e. if the
-- current line only contains (indentation) spaces.
}
data NewLineState = NewLineStateInit -- initial state. we do not know if in a
-- newline, really. by special-casing
-- this we can appropriately handle it
-- differently at use-site.
| NewLineStateYes
| NewLineStateNo
deriving Eq
-- data LayoutSettings = LayoutSettings
-- { _lsettings_cols :: Int -- the thing that has default 80.
-- , _lsettings_indentPolicy :: IndentPolicy
-- , _lsettings_indentAmount :: Int
-- , _lsettings_indentWhereSpecial :: Bool -- indent where only 1 sometimes (TODO).
-- , _lsettings_indentListSpecial :: Bool -- use some special indentation for ","
-- -- when creating zero-indentation
-- -- multi-line list literals.
-- , _lsettings_importColumn :: Int
-- , _lsettings_initialAnns :: ExactPrint.Anns
-- }
data LayoutError = LayoutErrorUnusedComment String
| LayoutWarning String
| forall ast . Data.Data.Data ast => LayoutErrorUnknownNode String ast
data BriSpacing = BriSpacing
{ _bs_spacePastLineIndent :: Int -- space in the current,
-- potentially somewhat filled
-- line.
, _bs_spacePastIndent :: Int -- space required in properly
-- indented blocks below the
-- current line.
}
data ColSig
= ColTyOpPrefix
-- any prefixed operator/paren/"::"/..
-- expected to have exactly two colums.
-- e.g. ":: foo"
-- 111222
-- "-> bar asd asd"
-- 11122222222222
| ColFuncPatternsPrefix
-- pattern-part of the lhs, e.g. "func (foo a b) c _".
-- Has variable number of columns depending on the number of patterns.
| ColFuncPatternsInfix
-- pattern-part of the lhs, e.g. "Foo a <> Foo b".
-- Has variable number of columns depending on the number of patterns.
| ColCasePattern
| ColEquation
-- e.g. "func pat pat = expr"
-- 1111111111111222222
-- expected to have exactly two columns.
| ColGuardedEquation
-- e.g. "func pat pat | cond = expr"
-- 11111111111112222222222222
-- or "func pat pat | cond"
-- 1111111111111222222
-- expected to have exactly two or three columns.
| ColDoBind
| ColDoLet -- the non-indented variant
| ColRecUpdate
| ColListComp
| ColList
| ColOpPrefix -- merge with ColList ? other stuff?
-- TODO
deriving (Eq, Data.Data.Data, Show)
data BrIndent = BrIndentNone
| BrIndentRegular
| BrIndentSpecial Int
deriving (Eq, Typeable, Data.Data.Data, Show)
type ToBriDocM = MultiRWSS.MultiRWS '[Config, Anns] '[[LayoutError], Seq String] '[]
type ToBriDoc (sym :: * -> *) = GenLocated SrcSpan (sym RdrName) -> ToBriDocM BriDoc
type ToBriDoc' sym = GenLocated SrcSpan sym -> ToBriDocM BriDoc
type ToBriDocC sym c = GenLocated SrcSpan sym -> ToBriDocM c
data DocMultiLine
= MultiLineNo
| MultiLinePossible
deriving (Eq, Typeable)
data BriDoc
= -- BDWrapAnnKey AnnKey BriDoc
BDEmpty
| BDLit Text
| BDSeq [BriDoc] -- elements other than the last should
-- not contains BDPars.
| BDCols ColSig [BriDoc] -- elements other than the last
-- should not contains BDPars
| BDSeparator -- semantically, space-unless-at-end-of-line.
| BDAddBaseY BrIndent BriDoc
| BDSetBaseY BriDoc
| BDSetIndentLevel BriDoc
| BDPar
{ _bdpar_indent :: BrIndent
, _bdpar_restOfLine :: BriDoc -- should not contain other BDPars
, _bdpar_indented :: BriDoc
}
-- | BDAddIndent BrIndent BriDoc
-- | BDNewline
| BDAlt [BriDoc]
| BDForceMultiline BriDoc
| BDForceSingleline BriDoc
| BDForwardLineMode BriDoc
| BDExternal AnnKey
(Set AnnKey) -- set of annkeys contained within the node
-- to be printed via exactprint
Bool -- should print extra comment ?
Text
| BDAnnotationPrior AnnKey BriDoc
| BDAnnotationPost AnnKey BriDoc
| BDLines [BriDoc]
| BDEnsureIndent BrIndent BriDoc
| BDProhibitMTEL BriDoc -- move to exact location
-- TODO: this constructor is deprecated. should
-- still work, but i should probably completely
-- remove it, as i have no proper usecase for
-- it anymore.
deriving Data.Data.Data
data VerticalSpacing
= VerticalSpacing
{ _vs_sameLine :: !Int
, _vs_paragraph :: !(Strict.Maybe Int)
}
deriving Show
newtype LineModeValidity a = LineModeValidity (Strict.Maybe a)
deriving (Functor, Applicative, Monad, Show)
pattern LineModeValid :: forall t. t -> LineModeValidity t
pattern LineModeValid x = LineModeValidity (Strict.Just x) :: LineModeValidity t
pattern LineModeInvalid :: forall t. LineModeValidity t
pattern LineModeInvalid = LineModeValidity Strict.Nothing :: LineModeValidity t

View File

@ -0,0 +1,229 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Language.Haskell.Brittany.Utils
( (.=+)
, (%=+)
, parDoc
, traceIfDumpConf
, mModify
, customLayouterF
, astToDoc
, briDocToDoc
-- , displayBriDocSimpleTree
, annsDoc
, Max (..)
, tellDebugMess
, tellDebugMessShow
)
where
#include "prelude.inc"
import qualified Language.Haskell.GHC.ExactPrint as ExactPrint
import qualified Language.Haskell.GHC.ExactPrint.Annotate as ExactPrint.Annotate
import qualified Language.Haskell.GHC.ExactPrint.Types as ExactPrint.Types
import qualified Language.Haskell.GHC.ExactPrint.Utils as ExactPrint.Utils
import Data.Data
import Data.Generics.Schemes
import Data.Generics.Aliases
import qualified Text.PrettyPrint as PP
import Text.PrettyPrint ( ($+$), (<+>) )
import qualified Outputable as GHC
import qualified DynFlags as GHC
import qualified FastString as GHC
import qualified SrcLoc as GHC
import OccName ( occNameString )
import qualified Data.ByteString as B
import DataTreePrint
import Language.Haskell.Brittany.Config.Types
import Language.Haskell.Brittany.Types
import qualified Control.Lens as Lens
import qualified Data.Generics.Uniplate.Data as Uniplate
(.=+) :: MonadMultiState s m
=> Lens.ASetter s s a b -> b -> m ()
l .=+ b = mModify $ l Lens..~ b
(%=+) :: MonadMultiState s m
=> Lens.ASetter s s a b -> (a -> b) -> m ()
l %=+ f = mModify (l Lens.%~ f)
parDoc :: String -> PP.Doc
parDoc = PP.fsep . fmap PP.text . List.words
showSDoc_ :: GHC.SDoc -> String
showSDoc_ = GHC.showSDoc GHC.unsafeGlobalDynFlags
showGhc :: (GHC.Outputable a) => a -> String
showGhc = GHC.showPpr GHC.unsafeGlobalDynFlags
-- maximum monoid over N+0
-- or more than N, because Num is allowed.
newtype Max a = Max { getMax :: a }
deriving (Eq, Ord, Show, Bounded, Num)
instance (Num a, Ord a) => Monoid (Max a) where
mempty = Max 0
mappend = Data.Coerce.coerce (max :: a -> a -> a)
newtype ShowIsId = ShowIsId String deriving Data
instance Show ShowIsId where show (ShowIsId x) = x
data A x = A ShowIsId x deriving Data
customLayouterF :: ExactPrint.Types.Anns -> LayouterF
customLayouterF anns layoutF =
DataToLayouter $ f `extQ` showIsId
`extQ` fastString
`extQ` bytestring
`extQ` occName
`extQ` srcSpan
`ext2Q` located
where
DataToLayouter f = defaultLayouterF layoutF
simpleLayouter :: String -> NodeLayouter
simpleLayouter s = NodeLayouter (length s) False (const $ PP.text s)
showIsId :: ShowIsId -> NodeLayouter
showIsId (ShowIsId s) = NodeLayouter (length s + 2) True $ \case
Left True -> PP.parens $ PP.text s
Left False -> PP.text s
Right _ -> PP.text s
fastString = simpleLayouter . ("{FastString: "++) . (++"}") . show :: GHC.FastString -> NodeLayouter
bytestring = simpleLayouter . show :: B.ByteString -> NodeLayouter
occName = simpleLayouter . ("{OccName: "++) . (++"}") . OccName.occNameString
srcSpan :: GHC.SrcSpan -> NodeLayouter
srcSpan ss = simpleLayouter
-- $ "{"++ showSDoc_ (GHC.ppr ss)++"}"
$ "{" ++ showGhc ss ++ "}"
located :: (Data b,Data loc) => GHC.GenLocated loc b -> NodeLayouter
located (GHC.L ss a) = runDataToLayouter layoutF $ A annStr a
where
annStr = case cast ss of
Just (s :: GHC.SrcSpan) -> ShowIsId
$ show (ExactPrint.Utils.getAnnotationEP (GHC.L s a) anns)
Nothing -> ShowIsId "nnnnnnnn"
customLayouterNoAnnsF :: LayouterF
customLayouterNoAnnsF layoutF =
DataToLayouter $ f `extQ` showIsId
`extQ` fastString
`extQ` bytestring
`extQ` occName
`extQ` srcSpan
`ext2Q` located
where
DataToLayouter f = defaultLayouterF layoutF
simpleLayouter :: String -> NodeLayouter
simpleLayouter s = NodeLayouter (length s) False (const $ PP.text s)
showIsId :: ShowIsId -> NodeLayouter
showIsId (ShowIsId s) = NodeLayouter (length s + 2) True $ \case
Left True -> PP.parens $ PP.text s
Left False -> PP.text s
Right _ -> PP.text s
fastString = simpleLayouter . ("{FastString: "++) . (++"}") . show :: GHC.FastString -> NodeLayouter
bytestring = simpleLayouter . show :: B.ByteString -> NodeLayouter
occName = simpleLayouter . ("{OccName: "++) . (++"}") . OccName.occNameString
srcSpan :: GHC.SrcSpan -> NodeLayouter
srcSpan ss = simpleLayouter
$ "{"++ showSDoc_ (GHC.ppr ss)++"}"
located :: (Data b) => GHC.GenLocated loc b -> NodeLayouter
located (GHC.L _ss a) = runDataToLayouter layoutF a
-- displayBriDocTree :: BriDoc -> PP.Doc
-- displayBriDocTree = \case
-- BDWrapAnnKey annKey doc -> def "BDWrapAnnKey"
-- $ PP.text (show annKey)
-- $+$ displayBriDocTree doc
-- BDEmpty -> PP.text "BDEmpty"
-- BDLit t -> def "BDLit" $ PP.text (show t)
-- BDSeq list -> def "BDSeq" $ displayList list
-- BDCols sig list -> def "BDCols" $ PP.text (show sig)
-- $+$ displayList list
-- BDSeparator -> PP.text "BDSeparator"
-- BDPar rol indent lines -> def "BDPar" $ displayBriDocTree rol
-- $+$ PP.text (show indent)
-- $+$ displayList lines
-- BDAlt alts -> def "BDAlt" $ displayList alts
-- BDExternal ast _t -> def "BDExternal" (astToDoc ast)
-- BDSpecialPostCommentLoc _ -> PP.text "BDSpecialPostCommentLoc"
-- where
-- def x r = PP.text x $+$ PP.nest 2 r
-- displayList :: [BriDoc] -> PP.Doc
-- displayList [] = PP.text "[]"
-- displayList (x:xr) = PP.cat $ PP.text "[" <+> displayBriDocTree x
-- : [PP.text "," <+> displayBriDocTree t | t<-xr]
-- ++ [PP.text "]"]
-- displayBriDocSimpleTree :: BriDocSimple -> PP.Doc
-- displayBriDocSimpleTree = \case
-- BDSWrapAnnKey annKey doc -> def "BDSWrapAnnKey"
-- $ PP.text (show annKey)
-- $+$ displayBriDocSimpleTree doc
-- BDSLit t -> def "BDSLit" $ PP.text (show t)
-- BDSSeq list -> def "BDSSeq" $ displayList list
-- BDSCols sig list -> def "BDSCols" $ PP.text (show sig)
-- $+$ displayList list
-- BDSSeparator -> PP.text "BDSSeparator"
-- BDSPar rol indent lines -> def "BDSPar" $ displayBriDocSimpleTree rol
-- $+$ PP.text (show indent)
-- $+$ displayList lines
-- BDSExternal annKey _subKeys _t -> def "BDSExternal" (PP.text $ show annKey)
-- BDSSpecialPostCommentLoc _ -> PP.text "BDSSpecialPostCommentLoc"
-- where
-- def x r = PP.text x $+$ PP.nest 2 r
-- displayList :: [BriDocSimple] -> PP.Doc
-- displayList [] = PP.text "[]"
-- displayList (x:xr) = PP.cat $ PP.text "[" <+> displayBriDocSimpleTree x
-- : [PP.text "," <+> displayBriDocSimpleTree t | t<-xr]
-- ++ [PP.text "]"]
traceIfDumpConf :: (MonadMultiReader
Config m,
Show a)
=> String
-> (DebugConfig -> Identity Bool)
-> a
-> m ()
traceIfDumpConf s accessor val = do
whenM (mAsk <&> _conf_debug .> accessor .> runIdentity) $ do
trace ("---- " ++ s ++ " ----\n" ++ show val) $ return ()
tellDebugMess :: MonadMultiWriter
(Seq String) m => String -> m ()
tellDebugMess s = mTell $ Seq.singleton s
tellDebugMessShow :: (MonadMultiWriter
(Seq String) m, Show a) => a -> m ()
tellDebugMessShow = tellDebugMess . show
-- i should really put that into multistate..
mModify :: MonadMultiState s m => (s -> s) -> m ()
mModify f = mGet >>= mSet . f
astToDoc :: Data ast => ast -> PP.Doc
astToDoc ast = printTreeWithCustom 160 customLayouterNoAnnsF ast
briDocToDoc :: BriDoc -> PP.Doc
briDocToDoc = astToDoc . removeAnnotations
where
removeAnnotations = Uniplate.transform $ \case
BDAnnotationPrior _ x -> x
BDAnnotationPost _ x -> x
x -> x
annsDoc :: ExactPrint.Types.Anns -> PP.Doc
annsDoc = printTreeWithCustom 100 customLayouterNoAnnsF . fmap (ShowIsId . show)

788
srcinc/prelude.inc Normal file
View File

@ -0,0 +1,788 @@
import qualified Data.ByteString
import qualified Data.ByteString.Builder
import qualified Data.ByteString.Builder.Extra
import qualified Data.ByteString.Builder.Prim
import qualified Data.ByteString.Char8
import qualified Data.ByteString.Lazy.Builder
import qualified Data.ByteString.Lazy.Builder.ASCII
import qualified Data.ByteString.Lazy.Builder.Extras
import qualified Data.ByteString.Lazy.Char8
import qualified Data.ByteString.Lazy
import qualified Data.ByteString.Short
import qualified Data.ByteString.Unsafe
import qualified Data.Graph
import qualified Data.IntMap
import qualified Data.IntMap.Lazy
import qualified Data.IntMap.Strict
import qualified Data.IntSet
import qualified Data.Map
import qualified Data.Map.Lazy
import qualified Data.Map.Strict
import qualified Data.Sequence
import qualified Data.Set
import qualified Data.Tree
import qualified System.Directory
import qualified Control.Concurrent.Extra
import qualified Control.Exception.Extra
import qualified Control.Monad.Extra
import qualified Data.Either.Extra
import qualified Data.IORef.Extra
import qualified Data.List.Extra
import qualified Data.Tuple.Extra
import qualified Data.Version.Extra
import qualified Numeric.Extra
import qualified System.Directory.Extra
import qualified System.Environment.Extra
import qualified System.IO.Extra
import qualified System.Info.Extra
import qualified System.Process.Extra
import qualified System.Time.Extra
import qualified Test.Hspec
import qualified Test.Hspec.Formatters
import qualified Test.Hspec.QuickCheck
import qualified Test.Hspec.Runner
-- import qualified Control.Exception.Lens
import qualified Control.Lens
-- import qualified Control.Lens.At
-- import qualified Control.Lens.Combinators
-- import qualified Control.Lens.Cons
-- import qualified Control.Lens.Each
-- import qualified Control.Lens.Empty
-- import qualified Control.Lens.Equality
-- import qualified Control.Lens.Extras
-- import qualified Control.Lens.Fold
-- import qualified Control.Lens.Getter
-- import qualified Control.Lens.Indexed
-- import qualified Control.Lens.Internal
-- import qualified Control.Lens.Internal.Bazaar
-- import qualified Control.Lens.Internal.ByteString
-- import qualified Control.Lens.Internal.Coerce
-- import qualified Control.Lens.Internal.Context
-- import qualified Control.Lens.Internal.Deque
-- import qualified Control.Lens.Internal.Exception
-- import qualified Control.Lens.Internal.FieldTH
-- import qualified Control.Lens.Internal.Fold
-- import qualified Control.Lens.Internal.Getter
-- import qualified Control.Lens.Internal.Indexed
-- import qualified Control.Lens.Internal.Instances
-- import qualified Control.Lens.Internal.Iso
-- import qualified Control.Lens.Internal.Level
-- import qualified Control.Lens.Internal.List
-- import qualified Control.Lens.Internal.Magma
-- import qualified Control.Lens.Internal.Prism
-- import qualified Control.Lens.Internal.PrismTH
-- import qualified Control.Lens.Internal.Review
-- import qualified Control.Lens.Internal.Setter
-- import qualified Control.Lens.Internal.TH
-- import qualified Control.Lens.Internal.Zoom
-- import qualified Control.Lens.Iso
-- import qualified Control.Lens.Lens
-- import qualified Control.Lens.Level
-- import qualified Control.Lens.Operators
-- import qualified Control.Lens.Plated
-- import qualified Control.Lens.Prism
-- import qualified Control.Lens.Reified
-- import qualified Control.Lens.Review
-- import qualified Control.Lens.Setter
-- import qualified Control.Lens.TH
-- import qualified Control.Lens.Traversal
-- import qualified Control.Lens.Tuple
-- import qualified Control.Lens.Type
-- import qualified Control.Lens.Wrapped
-- import qualified Control.Lens.Zoom
-- import qualified Control.Monad.Error.Lens
-- import qualified Control.Parallel.Strategies.Lens
-- import qualified Control.Seq.Lens
-- import qualified Data.Array.Lens
-- import qualified Data.Bits.Lens
-- import qualified Data.ByteString.Lazy.Lens
-- import qualified Data.ByteString.Lens
-- import qualified Data.ByteString.Strict.Lens
-- import qualified Data.Complex.Lens
-- import qualified Data.Data.Lens
-- import qualified Data.Dynamic.Lens
-- import qualified Data.HashSet.Lens
-- import qualified Data.IntSet.Lens
-- import qualified Data.List.Lens
-- import qualified Data.Map.Lens
-- import qualified Data.Sequence.Lens
-- import qualified Data.Set.Lens
-- import qualified Data.Text.Lazy.Lens
-- import qualified Data.Text.Lens
-- import qualified Data.Text.Strict.Lens
-- import qualified Data.Tree.Lens
-- import qualified Data.Typeable.Lens
-- import qualified Data.Vector.Generic.Lens
-- import qualified Data.Vector.Lens
-- import qualified GHC.Generics.Lens
-- import qualified Generics.Deriving.Lens
-- import qualified Language.Haskell.TH.Lens
-- import qualified Numeric.Lens
-- import qualified System.Exit.Lens
-- import qualified System.FilePath.Lens
-- import qualified System.IO.Error.Lens
-- import qualified Control.Monad.Cont
-- import qualified Control.Monad.Cont.Class
-- import qualified Control.Monad.Error.Class
-- import qualified Control.Monad.Except
-- import qualified Control.Monad.Identity
-- import qualified Control.Monad.List
-- import qualified Control.Monad.RWS
-- import qualified Control.Monad.RWS.Class
-- import qualified Control.Monad.RWS.Lazy
-- import qualified Control.Monad.RWS.Strict
-- import qualified Control.Monad.Reader
-- import qualified Control.Monad.Reader.Class
-- import qualified Control.Monad.State
-- import qualified Control.Monad.State.Class
-- import qualified Control.Monad.State.Lazy
-- import qualified Control.Monad.State.Strict
-- import qualified Control.Monad.Trans
-- import qualified Control.Monad.Writer
-- import qualified Control.Monad.Writer.Class
-- import qualified Control.Monad.Writer.Lazy
-- import qualified Control.Monad.Writer.Strict
-- import qualified Control.Monad.Trans.MultiRWS
import qualified Control.Monad.Trans.MultiRWS.Lazy
import qualified Control.Monad.Trans.MultiRWS.Strict
import qualified Control.Monad.Trans.MultiReader
import qualified Control.Monad.Trans.MultiReader.Class
import qualified Control.Monad.Trans.MultiReader.Lazy
import qualified Control.Monad.Trans.MultiReader.Strict
import qualified Control.Monad.Trans.MultiState
import qualified Control.Monad.Trans.MultiState.Class
import qualified Control.Monad.Trans.MultiState.Lazy
import qualified Control.Monad.Trans.MultiState.Strict
import qualified Control.Monad.Trans.MultiWriter
import qualified Control.Monad.Trans.MultiWriter.Class
import qualified Control.Monad.Trans.MultiWriter.Lazy
import qualified Control.Monad.Trans.MultiWriter.Strict
import qualified Control.Monad.Trans.MultiRWS.Strict as MultiRWSS
import qualified Control.Monad.Trans.MultiRWS.Lazy as MultiRWSL
import qualified Text.PrettyPrint
import qualified Text.PrettyPrint.Annotated
import qualified Text.PrettyPrint.Annotated.HughesPJ
import qualified Text.PrettyPrint.Annotated.HughesPJClass
import qualified Text.PrettyPrint.HughesPJ
import qualified Text.PrettyPrint.HughesPJClass
import qualified Data.Generics
import qualified Data.Generics.Aliases
import qualified Data.Generics.Basics
import qualified Data.Generics.Builders
import qualified Data.Generics.Instances
import qualified Data.Generics.Schemes
import qualified Data.Generics.Text
import qualified Data.Generics.Twins
import qualified Generics.SYB
-- import qualified Generics.SYB.Aliases
-- import qualified Generics.SYB.Basics
-- import qualified Generics.SYB.Builders
-- import qualified Generics.SYB.Instances
-- import qualified Generics.SYB.Schemes
-- import qualified Generics.SYB.Text
-- import qualified Generics.SYB.Twins
import qualified Data.Text
import qualified Data.Text.Array
import qualified Data.Text.Encoding
import qualified Data.Text.Encoding.Error
import qualified Data.Text.Foreign
import qualified Data.Text.IO
-- import qualified Data.Text.Internal
-- import qualified Data.Text.Internal.Builder
-- import qualified Data.Text.Internal.Builder.Functions
-- import qualified Data.Text.Internal.Builder.Int.Digits
-- import qualified Data.Text.Internal.Builder.RealFloat.Functions
-- import qualified Data.Text.Internal.Encoding.Fusion
-- import qualified Data.Text.Internal.Encoding.Fusion.Common
-- import qualified Data.Text.Internal.Encoding.Utf16
-- import qualified Data.Text.Internal.Encoding.Utf32
-- import qualified Data.Text.Internal.Encoding.Utf8
-- import qualified Data.Text.Internal.Functions
-- import qualified Data.Text.Internal.Fusion
-- import qualified Data.Text.Internal.Fusion.CaseMapping
-- import qualified Data.Text.Internal.Fusion.Common
-- import qualified Data.Text.Internal.Fusion.Size
-- import qualified Data.Text.Internal.Fusion.Types
-- import qualified Data.Text.Internal.IO
-- import qualified Data.Text.Internal.Lazy
-- import qualified Data.Text.Internal.Lazy.Encoding.Fusion
-- import qualified Data.Text.Internal.Lazy.Fusion
-- import qualified Data.Text.Internal.Lazy.Search
-- import qualified Data.Text.Internal.Private
-- import qualified Data.Text.Internal.Read
-- import qualified Data.Text.Internal.Search
-- import qualified Data.Text.Internal.Unsafe
-- import qualified Data.Text.Internal.Unsafe.Char
-- import qualified Data.Text.Internal.Unsafe.Shift
import qualified Data.Text.Lazy
import qualified Data.Text.Lazy.Builder
-- import qualified Data.Text.Lazy.Builder.Int
-- import qualified Data.Text.Lazy.Builder.RealFloat
-- import qualified Data.Text.Lazy.Encoding
-- import qualified Data.Text.Lazy.IO
-- import qualified Data.Text.Lazy.Read
-- import qualified Data.Text.Read
-- import qualified Data.Text.Unsafe
-- import qualified Control.Applicative.Backwards
-- import qualified Control.Applicative.Lift
-- import qualified Control.Monad.IO.Class
-- import qualified Control.Monad.Signatures
-- import qualified Control.Monad.Trans.Class
-- import qualified Control.Monad.Trans.Cont
-- import qualified Control.Monad.Trans.Except
-- import qualified Control.Monad.Trans.Identity
-- import qualified Control.Monad.Trans.List
-- import qualified Control.Monad.Trans.Maybe
-- import qualified Control.Monad.Trans.RWS
-- import qualified Control.Monad.Trans.RWS.Lazy
-- import qualified Control.Monad.Trans.RWS.Strict
-- import qualified Control.Monad.Trans.Reader
-- import qualified Control.Monad.Trans.State
-- import qualified Control.Monad.Trans.State.Lazy
-- import qualified Control.Monad.Trans.State.Strict
-- import qualified Control.Monad.Trans.Writer
-- import qualified Control.Monad.Trans.Writer.Lazy
-- import qualified Control.Monad.Trans.Writer.Strict
-- import qualified Data.Functor.Classes
-- import qualified Data.Functor.Compose
-- import qualified Data.Functor.Constant
-- import qualified Data.Functor.Product
-- import qualified Data.Functor.Reverse
-- import qualified Data.Functor.Sum
-- import qualified Prelude
-- import qualified Control.Applicative
-- import qualified Control.Arrow
-- import qualified Control.Category
-- import qualified Control.Concurrent
-- import qualified Control.Concurrent.Chan
-- import qualified Control.Concurrent.MVar
-- import qualified Control.Concurrent.QSem
-- import qualified Control.Concurrent.QSemN
-- import qualified Control.Exception
-- import qualified Control.Exception.Base
-- import qualified Control.Monad
-- import qualified Control.Monad.Fix
-- import qualified Control.Monad.ST
-- import qualified Control.Monad.ST.Lazy
-- import qualified Control.Monad.ST.Lazy.Unsafe
-- import qualified Control.Monad.ST.Strict
-- import qualified Control.Monad.ST.Unsafe
-- import qualified Control.Monad.Zip
import qualified Data.Bifunctor
import qualified Data.Bits
import qualified Data.Bool
import qualified Data.Char
import qualified Data.Coerce
import qualified Data.Complex
import qualified Data.Data
import qualified Data.Dynamic
import qualified Data.Either
import qualified Data.Eq
import qualified Data.Fixed
import qualified Data.Foldable
import qualified Data.Function
import qualified Data.Functor
import qualified Data.Functor.Identity
import qualified Data.IORef
import qualified Data.Int
import qualified Data.Ix
import qualified Data.List
import qualified Data.Maybe
import qualified Data.Monoid
import qualified Data.Ord
import qualified Data.Proxy
-- import qualified Data.Ratio
-- import qualified Data.STRef
-- import qualified Data.STRef.Lazy
-- import qualified Data.STRef.Strict
-- import qualified Data.String
-- import qualified Data.Traversable
-- import qualified Data.Tuple
-- import qualified Data.Type.Bool
-- import qualified Data.Type.Coercion
-- import qualified Data.Type.Equality
-- import qualified Data.Typeable
-- import qualified Data.Typeable.Internal
-- import qualified Data.Unique
-- import qualified Data.Version
-- import qualified Data.Void
-- import qualified Data.Word
import qualified Debug.Trace
-- import qualified Foreign.C
-- import qualified Foreign.C.Error
-- import qualified Foreign.C.String
-- import qualified Foreign.C.Types
-- import qualified Foreign.Concurrent
-- import qualified Foreign.ForeignPtr
-- import qualified Foreign.ForeignPtr.Unsafe
-- import qualified Foreign.Marshal
-- import qualified Foreign.Marshal.Alloc
-- import qualified Foreign.Marshal.Array
-- import qualified Foreign.Marshal.Error
-- import qualified Foreign.Marshal.Pool
-- import qualified Foreign.Marshal.Unsafe
-- import qualified Foreign.Marshal.Utils
-- import qualified Foreign.Ptr
-- import qualified Foreign.StablePtr
-- import qualified Foreign.Storable
import qualified Numeric
import qualified Numeric.Natural
-- import qualified System.CPUTime
-- import qualified System.Console.GetOpt
-- import qualified System.Environment
-- import qualified System.Exit
import qualified System.IO
-- import qualified System.IO.Error
-- import qualified System.IO.Unsafe
-- import qualified System.Info
-- import qualified System.Mem
-- import qualified System.Mem.StableName
-- import qualified System.Mem.Weak
-- import qualified System.Posix.Types
-- import qualified System.Timeout
-- import qualified Text.ParserCombinators.ReadP
-- import qualified Text.ParserCombinators.ReadPrec
-- import qualified Text.Printf
-- import qualified Text.Read
-- import qualified Text.Read.Lex
-- import qualified Text.Show
-- import qualified Text.Show.Functions
import qualified Unsafe.Coerce
-- import qualified Control.Arrow as Arrow
-- import qualified Control.Category as Category
-- import qualified Control.Concurrent as Concurrent
-- import qualified Control.Concurrent.Chan as Chan
-- import qualified Control.Concurrent.MVar as MVar
-- import qualified Control.Exception as Exception
-- import qualified Control.Exception.Base as Exception.Base
-- import qualified Control.Monad as Monad
-- import qualified Data.Bits as Bits
import qualified Data.Bool as Bool
-- import qualified Data.Char as Char
-- import qualified Data.Complex as Complex
-- import qualified Data.Either as Either
-- import qualified Data.Eq as Eq
-- import qualified Data.Foldable as Foldable
-- import qualified Data.Fixed as Fixed
-- import qualified Data.Functor.Identity as Identity
-- import qualified Data.IORef as IORef
-- import qualified Data.Int as Int
-- import qualified Data.Ix as Ix
-- import qualified Data.Maybe as Maybe
-- import qualified Data.Monoid as Monoid
-- import qualified Data.Ord as Ord
-- import qualified Data.Proxy as Proxy
-- import qualified Data.Traversable as Traversable
-- import qualified Data.Void as Void
import qualified GHC.OldList as List
-- import qualified Text.Printf as Printf
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Lazy as ByteStringL
import qualified Data.IntMap as IntMap
-- import qualified Data.IntMap.Lazy as IntMapL
import qualified Data.IntMap.Strict as IntMapS
-- import qualified Data.IntSet as IntSet
import qualified Data.Map as Map
-- import qualified Data.Map.Lazy as MapL
-- import qualified Data.Map.Strict as MapS
import qualified Data.Sequence as Seq
import qualified Data.Set as Set
import qualified Control.Monad.RWS.Class as RWS.Class
import qualified Control.Monad.Reader.Class as Reader.Class
import qualified Control.Monad.State.Class as State.Class
import qualified Control.Monad.Writer.Class as Writer.Class
import qualified Data.Text as Text
import qualified Data.Text.Encoding as Text.Encoding
import qualified Data.Text.IO as Text.IO
import qualified Data.Text.Lazy as TextL
import qualified Data.Text.Lazy.Encoding as TextL.Encoding
import qualified Data.Text.Lazy.IO as TextL.IO
-- import qualified Control.Monad.Trans.Class as Trans.Class
-- import qualified Control.Monad.Trans.Maybe as Trans.Maybe
-- import qualified Control.Monad.Trans.RWS as RWS
-- import qualified Control.Monad.Trans.RWS.Lazy as RWSL
-- import qualified Control.Monad.Trans.RWS.Strict as RWSS
-- import qualified Control.Monad.Trans.Reader as Reader
import qualified Control.Monad.Trans.State as State
import qualified Control.Monad.Trans.State.Lazy as StateL
import qualified Control.Monad.Trans.State.Strict as StateS
-- import qualified Control.Monad.Trans.Writer as Writer
-- import qualified Control.Monad.Trans.Writer.Lazy as WriterL
-- import qualified Control.Monad.Trans.Writer.Strict as Writer
import qualified Data.Strict.Maybe as Strict
import Data.Functor.Identity ( Identity(..) )
import Control.Concurrent.Chan ( Chan )
import Control.Concurrent.MVar ( MVar )
import Data.Int ( Int )
import Data.Word ( Word )
import Prelude ( Integer, Float, Double )
import Control.Monad.ST ( ST )
import Data.Bool ( Bool(..) )
import Data.Char ( Char )
import Data.Either ( Either(..) )
import Data.IORef ( IORef )
import Data.Maybe ( Maybe(..) )
import Data.Monoid ( Endo(..), All(..), Any(..), Sum(..), Product(..), First(..), Last(..), Alt(..), )
import Data.Ord ( Ordering(..), Down(..) )
import Data.Ratio ( Ratio, Rational )
import Data.String ( String )
import Data.Void ( Void )
import System.IO ( IO )
import Data.Proxy ( Proxy(..) )
import Data.Sequence ( Seq )
import Data.Map ( Map )
import Data.Set ( Set )
import Data.Text ( Text )
import QPrelude.Basics
import QPrelude.ErrorIf
import Prelude ( Char
, String
, Int
, Integer
, Float
, Double
, Bool (..)
, undefined
, Eq (..)
, Ord (..)
, Enum (..)
, Bounded (..)
, Maybe (..)
, Either (..)
, IO
, (<$>)
, (.)
, ($)
, ($!)
, Num (..)
, Integral (..)
, Fractional (..)
, Floating (..)
, RealFrac (..)
, RealFloat (..)
, fromIntegral
, error
, foldr
, foldl
, foldr1
, id
, map
, subtract
, putStrLn
, putStr
, Show (..)
, print
, fst
, snd
, (++)
, not
, (&&)
, (||)
, curry
, uncurry
, Ordering (..)
, flip
, const
, seq
, reverse
, otherwise
, traverse
, realToFrac
, or
, and
, head
, any
, (^)
, Foldable
, Traversable
)
import Data.Foldable ( foldl'
, foldr'
, fold
, asum
)
import Data.List ( partition
, null
, elem
, notElem
, minimum
, maximum
, length
, all
, take
, drop
, find
, sum
, zip
, zip3
, zipWith
, repeat
, replicate
, iterate
, nub
, filter
, intersperse
, intercalate
, isSuffixOf
, isPrefixOf
, dropWhile
, takeWhile
, unzip
, break
, transpose
, sortBy
, mapAccumL
, mapAccumR
, uncons
)
import Data.Tuple ( swap
)
import Data.Char ( ord
, chr
)
import Data.Maybe ( fromMaybe
, maybe
, listToMaybe
, maybeToList
, catMaybes
)
import Data.Word ( Word32
)
import Data.Ord ( comparing
, Down (..)
)
import Data.Either ( either
)
import Data.Ratio ( Ratio
, (%)
, numerator
, denominator
)
import Text.Read ( readMaybe
)
import Control.Monad ( Functor (..)
, Monad (..)
, MonadPlus (..)
, mapM
, mapM_
, forM
, forM_
, sequence
, sequence_
, (=<<)
, (>=>)
, (<=<)
, forever
, void
, join
, replicateM
, replicateM_
, guard
, when
, unless
, liftM
, liftM2
, liftM3
, liftM4
, liftM5
, filterM
, (<$!>)
)
import Control.Applicative ( Applicative (..)
, Alternative (..)
)
import Foreign.Storable ( Storable )
import GHC.Exts ( Constraint )
import Control.Concurrent ( threadDelay
, forkIO
, forkOS
)
import Control.Concurrent.MVar ( MVar
, newEmptyMVar
, newMVar
, putMVar
, readMVar
, takeMVar
, swapMVar
)
import Control.Exception ( evaluate
, bracket
, assert
)
import Debug.Trace ( trace
, traceId
, traceShowId
, traceShow
, traceStack
, traceShowId
, traceIO
, traceM
, traceShowM
)
import Foreign.ForeignPtr ( ForeignPtr
)
import Data.Monoid ( (<>)
, mconcat
, Monoid (..)
)
import Data.Bifunctor ( bimap )
import Data.Functor ( (<$), ($>) )
import Data.Function ( (&) )
import System.IO ( hFlush
, stdout
)
import Data.Typeable ( Typeable
)
import Control.Arrow ( first
, second
, (***)
, (&&&)
, (>>>)
, (<<<)
)
import Data.Functor.Identity ( Identity (..)
)
import Data.Proxy ( Proxy (..)
)
import Data.Version ( showVersion
)
import Data.List.Extra ( nubOrd
, stripSuffix
)
import Control.Monad.Extra ( whenM
, unlessM
, ifM
, notM
, orM
, andM
, anyM
, allM
)
import Data.Tree ( Tree(..)
)
import Control.Monad.Trans.MultiRWS ( -- MultiRWST (..)
-- , MultiRWSTNull
-- , MultiRWS
-- ,
MonadMultiReader(..)
, MonadMultiWriter(..)
, MonadMultiState(..)
-- , runMultiRWST
-- , runMultiRWSTASW
-- , runMultiRWSTW
-- , runMultiRWSTAW
-- , runMultiRWSTSW
-- , runMultiRWSTNil
-- , runMultiRWSTNil_
-- , withMultiReader
-- , withMultiReader_
-- , withMultiReaders
-- , withMultiReaders_
-- , withMultiWriter
-- , withMultiWriterAW
-- , withMultiWriterWA
-- , withMultiWriterW
-- , withMultiWriters
-- , withMultiWritersAW
-- , withMultiWritersWA
-- , withMultiWritersW
-- , withMultiState
-- , withMultiStateAS
-- , withMultiStateSA
-- , withMultiStateA
-- , withMultiStateS
-- , withMultiState_
-- , withMultiStates
-- , withMultiStatesAS
-- , withMultiStatesSA
-- , withMultiStatesA
-- , withMultiStatesS
-- , withMultiStates_
-- , inflateReader
-- , inflateMultiReader
-- , inflateWriter
-- , inflateMultiWriter
-- , inflateState
-- , inflateMultiState
-- , mapMultiRWST
-- , mGetRawR
-- , mGetRawW
-- , mGetRawS
-- , mPutRawR
-- , mPutRawW
-- , mPutRawS
)
import Control.Monad.Trans.MultiReader ( runMultiReaderTNil
, runMultiReaderTNil_
, MultiReaderT (..)
, MultiReader
, MultiReaderTNull
)
import Data.Text ( Text )
import Control.Monad.IO.Class ( MonadIO (..)
)
import Control.Monad.Trans.Class ( lift
)
import Control.Monad.Trans.Maybe ( MaybeT (..)
)
import Language.Haskell.Brittany.Prelude