[project @ 2006-01-06 16:30:17 by simonmar]
[ghc-hetmet.git] / ghc / compiler / utils / Pretty.lhs
index d3fe50a..ec8f1e7 100644 (file)
@@ -177,34 +177,18 @@ module Pretty (
 
 #include "HsVersions.h"
 
+import BufWrite
 import FastString
-import GlaExts
+
+import GLAEXTS
+
 import Numeric (fromRat)
-import PrimPacked      ( strLength )
 import IO
 
-#if __GLASGOW_HASKELL__ < 503
-import IOExts          ( hPutBufFull )
-#else
 import System.IO       ( hPutBuf )
-#endif
 
-#if __GLASGOW_HASKELL__ < 503
-import PrelBase                ( unpackCString# )
-#else
 import GHC.Base                ( unpackCString# )
-#endif
-
-#if __GLASGOW_HASKELL__ < 411
-import PrelAddr                ( Addr(..) )
-#else
-import Addr            ( Addr(..) )
-#if __GLASGOW_HASKELL__ < 503
-import Ptr             ( Ptr(..) )
-#else
 import GHC.Ptr         ( Ptr(..) )
-#endif
-#endif
 
 -- Don't import Util( assertPanic ) because it makes a loop in the module structure
 
@@ -499,7 +483,7 @@ no occurrences of @Union@ or @NoDoc@ represents just one layout.
 data Doc
  = Empty                                -- empty
  | NilAbove Doc                         -- text "" $$ x
- | TextBeside TextDetails INT Doc       -- text s <> x  
+ | TextBeside !TextDetails INT Doc       -- text s <> x  
  | Nest INT Doc                         -- nest k x
  | Union Doc Doc                        -- ul `union` ur
  | NoDoc                                -- The empty set of documents
@@ -515,7 +499,7 @@ reduceDoc (Above  p g q) = above  p g (reduceDoc q)
 reduceDoc p              = p
 
 
-data TextDetails = Chr  Char
+data TextDetails = Chr  {-#UNPACK#-}!Char
                  | Str  String
                  | PStr FastString     -- a hashed string
                 | LStr Addr# Int#      -- a '\0'-terminated array of bytes
@@ -608,12 +592,12 @@ isEmpty _     = False
 char  c = textBeside_ (Chr c) 1# Empty
 text  s = case length   s of {IBOX(sl) -> textBeside_ (Str s)  sl Empty}
 ftext s = case lengthFS s of {IBOX(sl) -> textBeside_ (PStr s) sl Empty}
-ptext (A# s) = case strLength (A# s) of {IBOX(sl) -> textBeside_ (LStr s sl) sl Empty}
+ptext (Ptr s) = case strLength (Ptr s) of {IBOX(sl) -> textBeside_ (LStr s sl) sl Empty}
 
 -- RULE that turns (text "abc") into (ptext (A# "abc"#)) to avoid the
 -- intermediate packing/unpacking of the string.
 {-# RULES 
-  "text/str" forall a. text (unpackCString# a) = ptext (A# a)
+  "text/str" forall a. text (unpackCString# a) = ptext (Ptr a)
  #-}
 
 nest IBOX(k)  p = mkNest k (reduceDoc p)        -- Externally callable version
@@ -697,15 +681,15 @@ beside :: Doc -> Bool -> RDoc -> RDoc
 beside NoDoc               g q   = NoDoc
 beside (p1 `Union` p2)     g q   = (beside p1 g q) `union_` (beside p2 g q)
 beside Empty               g q   = q
-beside (Nest k p)          g q   = nest_ k (beside p g q)       -- p non-empty
+beside (Nest k p)          g q   = nest_ k $! beside p g q       -- p non-empty
 beside p@(Beside p1 g1 q1) g2 q2 
            {- (A `op1` B) `op2` C == A `op1` (B `op2` C)  iff op1 == op2 
                                                  [ && (op1 == <> || op1 == <+>) ] -}
-         | g1 == g2              = beside p1 g1 (beside q1 g2 q2)
+         | g1 == g2              = beside p1 g1 $! beside q1 g2 q2
          | otherwise             = beside (reduceDoc p) g2 q2
-beside p@(Above _ _ _)     g q   = beside (reduceDoc p) g q
-beside (NilAbove p)        g q   = nilAbove_ (beside p g q)
-beside (TextBeside s sl p) g q   = textBeside_ s sl rest
+beside p@(Above _ _ _)     g q   = let d = reduceDoc p in d `seq` 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
@@ -1020,11 +1004,14 @@ spaces n       = ' ' : spaces (n MINUS ILIT(1))
 \end{code}
 
 \begin{code}
-pprCols = (100 :: Int) -- could make configurable
+pprCols = (120 :: Int) -- could make configurable
 
 printDoc :: Mode -> Handle -> Doc -> IO ()
+printDoc LeftMode hdl doc
+  = do { printLeftRender hdl doc; hFlush hdl }
 printDoc mode hdl doc
-  = fullRender mode pprCols 1.5 put done doc
+  = do { fullRender mode pprCols 1.5 put done doc ;
+        hFlush hdl }
   where
     put (Chr c)  next = hPutChar hdl c >> next 
     put (Str s)  next = hPutStr  hdl s >> next 
@@ -1033,14 +1020,56 @@ printDoc mode hdl doc
 
     done = hPutChar hdl '\n'
 
-#if __GLASGOW_HASKELL__ < 503
-hPutBuf = hPutBufFull
-#endif
-
+  -- some versions of hPutBuf will barf if the length is zero
+hPutLitString handle a# 0# = return ()
 hPutLitString handle a# l#
 #if __GLASGOW_HASKELL__ < 411
   = hPutBuf handle (A# a#) (I# l#)
 #else
   = hPutBuf handle (Ptr a#) (I# l#)
 #endif
+
+-- Printing output in LeftMode is performance critical: it's used when
+-- dumping C and assembly output, so we allow ourselves a few dirty
+-- hacks:
+--
+--     (1) we specialise fullRender for LeftMode with IO output.
+--
+--     (2) we add a layer of buffering on top of Handles.  Handles
+--         don't perform well with lots of hPutChars, which is mostly
+--         what we're doing here, because Handles have to be thread-safe
+--         and async exception-safe.  We only have a single thread and don't
+--         care about exceptions, so we add a layer of fast buffering
+--         over the Handle interface.
+--
+--     (3) a few hacks in layLeft below to convince GHC to generate the right
+--         code.
+
+printLeftRender :: Handle -> Doc -> IO ()
+printLeftRender hdl doc = do
+  b <- newBufHandle hdl
+  layLeft b (reduceDoc doc)
+  bFlush b
+
+-- HACK ALERT!  the "return () >>" below convinces GHC to eta-expand
+-- this function with the IO state lambda.  Otherwise we end up with
+-- closures in all the case branches.
+layLeft b _ | b `seq` False = undefined        -- make it strict in b
+layLeft b NoDoc                = cant_fail
+layLeft b (Union p q)          = return () >> layLeft b (first p q)
+layLeft b (Nest k p)           = return () >> layLeft b p
+layLeft b Empty                = bPutChar b '\n'
+layLeft b (NilAbove p)         = bPutChar b '\n' >> layLeft b p
+layLeft b (TextBeside s sl p)  = put b s >> layLeft b p
+ where
+    put b _ | b `seq` False = undefined
+    put b (Chr c)    = bPutChar b c
+    put b (Str s)    = bPutStr  b s
+    put b (PStr s)   = bPutFS   b s
+    put b (LStr s l) = bPutLitString b s l
+
+#if __GLASGOW_HASKELL__ < 503
+hPutBuf = hPutBufFull
+#endif
+
 \end{code}