{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE MagicHash #-}
module Pretty (
Doc, TextDetails(..),
char, text, ftext, ptext, ztext, sizedText, zeroWidthText,
int, integer, float, double, rational,
semi, comma, colon, space, equals,
lparen, rparen, lbrack, rbrack, lbrace, rbrace,
parens, brackets, braces, quotes, quote, doubleQuotes,
maybeParens,
empty,
(<>), (<+>), hcat, hsep,
($$), ($+$), vcat,
sep, cat,
fsep, fcat,
nest,
hang, hangNotEmpty, punctuate,
isEmpty,
Style(..),
style,
renderStyle,
Mode(..),
fullRender,
printDoc, printDoc_,
bufLeftRender
) where
import BufWrite
import FastString
import Panic
import System.IO
import Prelude hiding (error)
import GHC.Base ( unpackCString# )
import GHC.Ptr ( Ptr(..) )
infixl 6 <>
infixl 6 <+>
infixl 5 $$, $+$
data Doc
= Empty
| NilAbove Doc
| TextBeside !TextDetails {-# UNPACK #-} !Int Doc
| Nest {-# UNPACK #-} !Int Doc
| Union Doc Doc
| NoDoc
| Beside Doc Bool Doc
| Above Doc Bool Doc
type RDoc = Doc
data TextDetails = Chr {-# UNPACK #-} !Char
| Str String
| PStr FastString
| ZStr FastZString
| LStr {-# UNPACK #-} !LitString {-#UNPACK #-} !Int
instance Show Doc where
showsPrec _ doc cont = fullRender (mode style) (lineLength style)
(ribbonsPerLine style)
txtPrinter cont doc
char :: Char -> Doc
char c = textBeside_ (Chr c) 1 Empty
text :: String -> Doc
text s = case length s of {sl -> textBeside_ (Str s) sl Empty}
{-# NOINLINE [0] text #-}
{-# RULES
"text/str" forall a. text (unpackCString# a) = ptext (Ptr a)
#-}
ftext :: FastString -> Doc
ftext s = case lengthFS s of {sl -> textBeside_ (PStr s) sl Empty}
ptext :: LitString -> Doc
ptext s = case lengthLS s of {sl -> textBeside_ (LStr s sl) sl Empty}
ztext :: FastZString -> Doc
ztext s = case lengthFZS s of {sl -> textBeside_ (ZStr s) sl Empty}
sizedText :: Int -> String -> Doc
sizedText l s = textBeside_ (Str s) l Empty
zeroWidthText :: String -> Doc
zeroWidthText = sizedText 0
empty :: Doc
empty = Empty
isEmpty :: Doc -> Bool
isEmpty Empty = True
isEmpty _ = False
spaces :: Int -> String
spaces !n = replicate n ' '
semi :: Doc
comma :: Doc
colon :: Doc
space :: Doc
equals :: Doc
lparen :: Doc
rparen :: Doc
lbrack :: Doc
rbrack :: Doc
lbrace :: Doc
rbrace :: Doc
semi = char ';'
comma = char ','
colon = char ':'
space = char ' '
equals = char '='
lparen = char '('
rparen = char ')'
lbrack = char '['
rbrack = char ']'
lbrace = char '{'
rbrace = char '}'
spaceText, nlText :: TextDetails
spaceText = Chr ' '
nlText = Chr '\n'
int :: Int -> Doc
integer :: Integer -> Doc
float :: Float -> Doc
double :: Double -> Doc
rational :: Rational -> Doc
int n = text (show n)
integer n = text (show n)
float n = text (show n)
double n = text (show n)
rational n = text (show n)
parens :: Doc -> Doc
brackets :: Doc -> Doc
braces :: Doc -> Doc
quotes :: Doc -> Doc
quote :: Doc -> Doc
doubleQuotes :: Doc -> Doc
quotes p = char '`' <> p <> char '\''
quote p = char '\'' <> p
doubleQuotes p = char '"' <> p <> char '"'
parens p = char '(' <> p <> char ')'
brackets p = char '[' <> p <> char ']'
braces p = char '{' <> p <> char '}'
maybeParens :: Bool -> Doc -> Doc
maybeParens False = id
maybeParens True = parens
reduceDoc :: Doc -> RDoc
reduceDoc (Beside p g q) = beside p g (reduceDoc q)
reduceDoc (Above p g q) = above p g (reduceDoc q)
reduceDoc p = p
hcat :: [Doc] -> Doc
hcat = reduceAB . foldr (beside_' False) empty
hsep :: [Doc] -> Doc
hsep = reduceAB . foldr (beside_' True) empty
vcat :: [Doc] -> Doc
vcat = reduceAB . foldr (above_' False) empty
nest :: Int -> Doc -> Doc
nest k p = mkNest k (reduceDoc p)
hang :: Doc -> Int -> Doc -> Doc
hang d1 n d2 = sep [d1, nest n d2]
hangNotEmpty :: Doc -> Int -> Doc -> Doc
hangNotEmpty d1 n d2 = if isEmpty d1
then d2
else hang d1 n d2
punctuate :: Doc -> [Doc] -> [Doc]
punctuate _ [] = []
punctuate p (x:xs) = go x xs
where go y [] = [y]
go y (z:zs) = (y <> p) : go z zs
mkNest :: Int -> Doc -> Doc
mkNest k _ | k `seq` False = undefined
mkNest k (Nest k1 p) = mkNest (k + k1) p
mkNest _ NoDoc = NoDoc
mkNest _ Empty = Empty
mkNest 0 p = p
mkNest k p = nest_ k p
mkUnion :: Doc -> Doc -> Doc
mkUnion Empty _ = Empty
mkUnion p q = p `union_` q
beside_' :: Bool -> Doc -> Doc -> Doc
beside_' _ p Empty = p
beside_' g p q = Beside p g q
above_' :: Bool -> Doc -> Doc -> Doc
above_' _ p Empty = p
above_' g p q = Above p g q
reduceAB :: Doc -> Doc
reduceAB (Above Empty _ q) = q
reduceAB (Beside Empty _ q) = q
reduceAB doc = doc
nilAbove_ :: RDoc -> RDoc
nilAbove_ = NilAbove
textBeside_ :: TextDetails -> Int -> RDoc -> RDoc
textBeside_ = TextBeside
nest_ :: Int -> RDoc -> RDoc
nest_ = Nest
union_ :: RDoc -> RDoc -> RDoc
union_ = Union
($$) :: Doc -> Doc -> Doc
p $$ q = above_ p False q
($+$) :: Doc -> Doc -> Doc
p $+$ q = above_ p True q
above_ :: Doc -> Bool -> Doc -> Doc
above_ p _ Empty = p
above_ Empty _ q = q
above_ p g q = Above p g q
above :: Doc -> Bool -> RDoc -> RDoc
above (Above p g1 q1) g2 q2 = above p g1 (above q1 g2 q2)
above p@(Beside{}) g q = aboveNest (reduceDoc p) g 0 (reduceDoc q)
above p g q = aboveNest p g 0 (reduceDoc q)
aboveNest :: RDoc -> Bool -> Int -> RDoc -> RDoc
aboveNest _ _ k _ | k `seq` False = undefined
aboveNest NoDoc _ _ _ = NoDoc
aboveNest (p1 `Union` p2) g k q = aboveNest p1 g k q `union_`
aboveNest p2 g k q
aboveNest Empty _ k q = mkNest k q
aboveNest (Nest k1 p) g k q = nest_ k1 (aboveNest p g (k - k1) q)
aboveNest (NilAbove p) g k q = nilAbove_ (aboveNest p g k q)
aboveNest (TextBeside s sl p) g k q = textBeside_ s sl rest
where
!k1 = k - sl
rest = case p of
Empty -> nilAboveNest g k1 q
_ -> aboveNest p g k1 q
aboveNest (Above {}) _ _ _ = error "aboveNest Above"
aboveNest (Beside {}) _ _ _ = error "aboveNest Beside"
nilAboveNest :: Bool -> Int -> RDoc -> RDoc
nilAboveNest _ k _ | k `seq` False = undefined
nilAboveNest _ _ Empty = Empty
nilAboveNest g k (Nest k1 q) = nilAboveNest g (k + k1) q
nilAboveNest g k q | not g && k > 0
= textBeside_ (Str (spaces k)) k q
| otherwise
= nilAbove_ (mkNest k q)
(<>) :: Doc -> Doc -> Doc
p <> q = beside_ p False q
(<+>) :: Doc -> Doc -> Doc
p <+> q = beside_ p True q
beside_ :: Doc -> Bool -> Doc -> Doc
beside_ p _ Empty = p
beside_ Empty _ q = q
beside_ p g q = Beside p g q
beside :: Doc -> Bool -> RDoc -> RDoc
beside NoDoc _ _ = NoDoc
beside (p1 `Union` p2) g q = beside p1 g q `union_` beside p2 g q
beside Empty _ q = q
beside (Nest k p) g q = nest_ k $! beside p g q
beside p@(Beside p1 g1 q1) g2 q2
| g1 == g2 = beside p1 g1 $! beside q1 g2 q2
| otherwise = beside (reduceDoc p) g2 q2
beside p@(Above{}) g q = let !d = reduceDoc p in beside d g q
beside (NilAbove p) g q = nilAbove_ $! beside p g q
beside (TextBeside s sl p) g q = textBeside_ s sl rest
where
rest = case p of
Empty -> nilBeside g q
_ -> beside p g q
nilBeside :: Bool -> RDoc -> RDoc
nilBeside _ Empty = Empty
nilBeside g (Nest _ p) = nilBeside g p
nilBeside g p | g = textBeside_ spaceText 1 p
| otherwise = p
sep :: [Doc] -> Doc
sep = sepX True
cat :: [Doc] -> Doc
cat = sepX False
sepX :: Bool -> [Doc] -> Doc
sepX _ [] = empty
sepX x (p:ps) = sep1 x (reduceDoc p) 0 ps
sep1 :: Bool -> RDoc -> Int -> [Doc] -> RDoc
sep1 _ _ k _ | k `seq` False = undefined
sep1 _ NoDoc _ _ = NoDoc
sep1 g (p `Union` q) k ys = sep1 g p k ys `union_`
aboveNest q False k (reduceDoc (vcat ys))
sep1 g Empty k ys = mkNest k (sepX g ys)
sep1 g (Nest n p) k ys = nest_ n (sep1 g p (k - n) ys)
sep1 _ (NilAbove p) k ys = nilAbove_
(aboveNest p False k (reduceDoc (vcat ys)))
sep1 g (TextBeside s sl p) k ys = textBeside_ s sl (sepNB g p (k - sl) ys)
sep1 _ (Above {}) _ _ = error "sep1 Above"
sep1 _ (Beside {}) _ _ = error "sep1 Beside"
sepNB :: Bool -> Doc -> Int -> [Doc] -> Doc
sepNB g (Nest _ p) k ys
= sepNB g p k ys
sepNB g Empty k ys
= oneLiner (nilBeside g (reduceDoc rest)) `mkUnion`
nilAboveNest False k (reduceDoc (vcat ys))
where
rest | g = hsep ys
| otherwise = hcat ys
sepNB g p k ys
= sep1 g p k ys
fcat :: [Doc] -> Doc
fcat = fill False
fsep :: [Doc] -> Doc
fsep = fill True
fill :: Bool -> [Doc] -> RDoc
fill _ [] = empty
fill g (p:ps) = fill1 g (reduceDoc p) 0 ps
fill1 :: Bool -> RDoc -> Int -> [Doc] -> Doc
fill1 _ _ k _ | k `seq` False = undefined
fill1 _ NoDoc _ _ = NoDoc
fill1 g (p `Union` q) k ys = fill1 g p k ys `union_`
aboveNest q False k (fill g ys)
fill1 g Empty k ys = mkNest k (fill g ys)
fill1 g (Nest n p) k ys = nest_ n (fill1 g p (k - n) ys)
fill1 g (NilAbove p) k ys = nilAbove_ (aboveNest p False k (fill g ys))
fill1 g (TextBeside s sl p) k ys = textBeside_ s sl (fillNB g p (k - sl) ys)
fill1 _ (Above {}) _ _ = error "fill1 Above"
fill1 _ (Beside {}) _ _ = error "fill1 Beside"
fillNB :: Bool -> Doc -> Int -> [Doc] -> Doc
fillNB _ _ k _ | k `seq` False = undefined
fillNB g (Nest _ p) k ys = fillNB g p k ys
fillNB _ Empty _ [] = Empty
fillNB g Empty k (Empty:ys) = fillNB g Empty k ys
fillNB g Empty k (y:ys) = fillNBE g k y ys
fillNB g p k ys = fill1 g p k ys
fillNBE :: Bool -> Int -> Doc -> [Doc] -> Doc
fillNBE g k y ys
= nilBeside g (fill1 g ((elideNest . oneLiner . reduceDoc) y) k' ys)
`mkUnion` nilAboveNest False k (fill g (y:ys))
where k' = if g then k - 1 else k
elideNest :: Doc -> Doc
elideNest (Nest _ d) = d
elideNest d = d
best :: Int
-> Int
-> RDoc
-> RDoc
best w0 r = get w0
where
get :: Int
-> Doc -> Doc
get w _ | w == 0 && False = undefined
get _ Empty = Empty
get _ NoDoc = NoDoc
get w (NilAbove p) = nilAbove_ (get w p)
get w (TextBeside s sl p) = textBeside_ s sl (get1 w sl p)
get w (Nest k p) = nest_ k (get (w - k) p)
get w (p `Union` q) = nicest w r (get w p) (get w q)
get _ (Above {}) = error "best get Above"
get _ (Beside {}) = error "best get Beside"
get1 :: Int
-> Int
-> Doc
-> Doc
get1 w _ _ | w == 0 && False = undefined
get1 _ _ Empty = Empty
get1 _ _ NoDoc = NoDoc
get1 w sl (NilAbove p) = nilAbove_ (get (w - sl) p)
get1 w sl (TextBeside t tl p) = textBeside_ t tl (get1 w (sl + tl) p)
get1 w sl (Nest _ p) = get1 w sl p
get1 w sl (p `Union` q) = nicest1 w r sl (get1 w sl p)
(get1 w sl q)
get1 _ _ (Above {}) = error "best get1 Above"
get1 _ _ (Beside {}) = error "best get1 Beside"
nicest :: Int -> Int -> Doc -> Doc -> Doc
nicest !w !r = nicest1 w r 0
nicest1 :: Int -> Int -> Int -> Doc -> Doc -> Doc
nicest1 !w !r !sl p q | fits ((w `min` r) - sl) p = p
| otherwise = q
fits :: Int
-> Doc
-> Bool
fits n _ | n < 0 = False
fits _ NoDoc = False
fits _ Empty = True
fits _ (NilAbove _) = True
fits n (TextBeside _ sl p) = fits (n - sl) p
fits _ (Above {}) = error "fits Above"
fits _ (Beside {}) = error "fits Beside"
fits _ (Union {}) = error "fits Union"
fits _ (Nest {}) = error "fits Nest"
first :: Doc -> Doc -> Doc
first p q | nonEmptySet p = p
| otherwise = q
nonEmptySet :: Doc -> Bool
nonEmptySet NoDoc = False
nonEmptySet (_ `Union` _) = True
nonEmptySet Empty = True
nonEmptySet (NilAbove _) = True
nonEmptySet (TextBeside _ _ nilAbove_nonEmptySet (elideNest _ erro, "fits Nest"
Name -> Int=
( 8span> !8span> get1ass="hs-identifspan class="">elideasidentifier hs-var">elideasidentifier hs-var">elideasidentifier hs-var">elideasidentifier hs-var">elideasidentifier hs-var">elideasidentifier hs-var">elideasididentifier hs-var">x )
gespan class="hs-operator hs-var">&&a"local-6989586621679089490">s-identifier">get1ass="hs-identifspan class="">(qelideasidentifier he-var">elideasidentifier hs-varn>elideasidentifier hs-var">elideasidmdentifier hs-var">x )
gespan class="hs-operator hs-var">&&a"local-6989586621679089490">s-identifier">get1ass=&21679734442">n :: elideasidentifier hs-var">elideasidentifier hs-var">elidan>` Falsepan class="hs-idenss="hs-glyph">->:: _ first/span>Falsepan class="hs-idenss="hs-glyph">-&gu9089476">gespan class="hs-operator hs-varn class="hs-identifier">_elideasidentifier hs-var">elideasidmdentifier hs-var">x )
gespan class="hs-operator hs-var">&&a"local-6989586621679089490">< &&a"local-6989586621679089490">< &varn>&&a"local-6989586621679089490">< &varn>)
gespan class="hs-operator hs-var">&&a"locpan class="hs-identi>elideNest p
| elideasiy.html#union_">union_`span>8span class="hs-identifier">gesvar">union_ ys)
fill1Just ::->span> an class="hs-operator hs-var">&&a"loca name="li89586621679089476">8span class="hs-identifier">gesvar">union_ s-identifier">get1asu="hs-identifspan class=""> : NilAbove _) = True
first>
8spa.ss="hs-identifier hs-var">NilAbove _)<048spa.ss="hs-identifier hs-varspan> &varn>elideasidentifier hs-varn>elideasidentifier hs-var">elideasidmdentifier hs-var">x )
gespan class="hs-operator hs-var">&&a"local-6)
fill1_ fillNB _ Falsepan class="hs-idenss="hs-glyph">-&gu94">first :: _ Falsepan class="hs-idenss="hs-glyph">-&gu94">first :: _)<048spa.ss="hs-identifier hs-varspan> &varn>elideasidentifier hs-varn>elideasidentifier hs-var">elideasidmdentifier hs-var">x )
gespan class="hs-operator hs-}ar">&&a"local-6whs-operat_span class="hs-special">)
{(
fits elideasidentifier hs-href="#local-698958662167908951 :: _ Falsesl w:: _ "fits Above"
fitsfits elideasidentif1i89586621679089476">8span class="hs-"hs-identifier hs-type">Doc -> Doc fits hsep yswhs-operat_span class="hs-special">)
union_<">Doc s-identifier">get1asu="hs-identifspan class=""> <29471">"fits Above&qua>) = noef="Pretty.html#reduceDoc">reduceDoc (elideasidentifier hs-href="#local-698958662167908951 :: :: var">&ef="#local-6989586621679089507">r =
fits_pan> eian>)fill1Doc :: var">&ef="#local-6989586621679089507">rpan>
_)
union_-- unused, because (get OneLineMode) is unused
> p k _)
union_-- unused, becau_local-6989586ref="#locaeetty.html#-823">redentifier">_ =pd95866217À9089476">gespan class="hs-operator hs-var">&&a"local-6989586621679089490">s-identifier">get1 )
s-identan>
pan> <29471">"fits Above&qua>) 33">_)
fill1> p _)<048spa.ss="hs-identifier hs-varspan> _p rpan>
_)
743">s-identan>
redentifier">_ pan> <29471">reduceDoc fits Above&qua>) s-identan>
!redentifier">_ ->
s-identan>
pan> <29471">
gehqan class="hs-operator hs-}ar">&&a"local-6pan> <29471">=s-identan>redentifier"(ing">"fits Above&qua>) 33">_)
p _ redentifiey h4on__ redentifiey h4on__)<048spa.ss="hs-identifier hs-varspan> _p NilAbovepan> <29471"><|san clylocaar">union_<"s-comment">-- unu###############################1111111111111111111111111111111111111111111111111111111111111111111111132 33">_) n 33">_)_ redentifiey h4on__
_ppan> eian>)<048spa.ss="hs-identifier hs-varspan> -- unused, becau_local-6989586ref="#locaeetty.html#-823">redentifsed
> prewte434"> redentifiey h4on_eian>_ )<048spa.ss="hs-identifier hs-varspan> pan> redentifier">_ fits elideasidentif1i89586621679629476">8span class="hs-"hs-identifierp7111111111##189587111111111##189####################################################-varspan> ######- hs-varspapan> nppan> eian>redentifsed
> <18111##189587111111111##189587111111111##15n> <29471">91##189587111111lass="hs-identifier hs-var">redentifsed
> Ns> ppan> _33">_##########################-loc>pan> -> :: _runRuleM (g Doc | idName ___<18111##189587111111111##189587111111111##15n> <29471">91##189587111111lass="hs-identifier">_runRuleM (g Doc | idName __s-identan>
Data.Wordan class="hs-identifier hs-var">idNamed
> p (p .0/src/%{MODULE/./-}.html#%{NAME}/Control.Monad.html#guard">guard runRuleM ("fits Union"
fits guard fits guardecial"89fits_.Word<-6989586621679734287ass="hs-identie#################################- hs-varspapan> >_.Wo"hs-special">)0/src/%{MODULE/./-}.html#%{NAME}/Control.Monad.html#guard">guard 33">_)_ _ 33">_< class="hs-idenn class="hs-id>.Word<-6989586621679734287ass="hs-identie#########;fits Above&ifierpan> 33">_< class="hs-idenn class="hs-id>.Word<-6989586621679734287ass="hs-identie#########;fits Above&ifierpan> 33">_< class="hs-idenn class="hs-id>.Word<-^9> 33"n>_0er">_<1111111132 p (w - kss="hs-identifier hs-var">kss="hs-identifier hs-var">kss="hs-identifier hs-var">kss="hs-ids f.f.<-idenn class=2 get _ _0er">_<1111111132 p _0er">_<1111111132 _Word<-6989586621679734287ass="hs-identie#########;fits Above&ifierpan> 33">_guarbme="line-825">fits_33">_< class="hs-idenn class="hs-id>..Wo"hs-special">)0/src/%{MODULE/./-}.html#%{NAME}/Control.Monad.html#guard">