[project @ 1996-01-08 20:28:12 by partain]
[ghc-hetmet.git] / ghc / lib / ghc / CharSeq.lhs
diff --git a/ghc/lib/ghc/CharSeq.lhs b/ghc/lib/ghc/CharSeq.lhs
new file mode 100644 (file)
index 0000000..d552027
--- /dev/null
@@ -0,0 +1,282 @@
+%
+% (c) The GRASP/AQUA Project, Glasgow University, 1992-1995
+%
+\section[CharSeq]{Characters sequences: the @CSeq@ type}
+
+\begin{code}
+#if defined(COMPILING_GHC)
+# include "HsVersions.h"
+#else
+# define FAST_STRING String
+# define FAST_INT    Int
+# define ILIT(x)     (x)
+# define IBOX(x)     (x)
+# define _GE_       >=
+# define _ADD_      +
+# define _SUB_      -
+# define FAST_BOOL   Bool
+# define _TRUE_             True
+# define _FALSE_     False
+#endif
+
+module CharSeq (
+       CSeq,
+       cNil, cAppend, cIndent, cNL, cStr, cPStr, cCh, cInt,
+#if ! defined(COMPILING_GHC)
+       cLength,
+       cShows,
+#endif
+       cShow
+
+#if defined(COMPILING_GHC) && __GLASGOW_HASKELL__ >= 22
+       , cAppendFile
+   ) where
+
+#if __GLASGOW_HASKELL__ < 26
+import PreludePrimIO
+#endif
+import PreludeGlaST
+
+#else
+   ) where
+#endif
+\end{code}
+
+%************************************************
+%*                                             *
+       \subsection{The interface}
+%*                                             *
+%************************************************
+
+\begin{code}
+cShow  :: CSeq -> [Char]
+
+#if ! defined(COMPILING_GHC)
+-- not used in GHC
+cShows :: CSeq -> ShowS
+cLength        :: CSeq -> Int
+#endif
+
+cNil    :: CSeq
+cAppend :: CSeq -> CSeq -> CSeq
+cIndent :: Int -> CSeq -> CSeq
+cNL    :: CSeq
+cStr   :: [Char] -> CSeq
+cPStr  :: FAST_STRING -> CSeq
+cCh    :: Char -> CSeq
+cInt   :: Int -> CSeq
+
+#if defined(COMPILING_GHC) && __GLASGOW_HASKELL__ >= 22
+
+# if __GLASGOW_HASKELL__ < 23
+#  define _FILE _Addr
+# endif
+
+cAppendFile :: _FILE -> CSeq -> PrimIO ()
+#endif
+\end{code}
+
+%************************************************
+%*                                             *
+       \subsection{The representation}
+%*                                             *
+%************************************************
+
+\begin{code}
+data CSeq
+  = CNil
+  | CAppend    CSeq CSeq
+  | CIndent    Int  CSeq
+  | CNewline                   -- Move to start of next line, unless we're
+                               -- already at the start of a line.
+  | CStr       [Char]
+  | CCh                Char
+  | CInt       Int     -- equiv to "CStr (show the_int)"
+#if defined(COMPILING_GHC) && __GLASGOW_HASKELL__ >= 23
+  | CPStr      _PackedString
+#endif
+\end{code}
+
+The construction functions do pattern matching, to ensure that
+redundant CNils are eliminated.  This is bound to have some effect on
+evaluation order, but quite what I don't know.
+
+\begin{code}
+cNil = CNil
+\end{code}
+
+The following special cases were eating our lunch! They make the whole
+thing too strict.  A classic strictness bug!
+\begin{code}
+-- cAppend CNil cs2  = cs2
+-- cAppend cs1  CNil = cs1
+
+cAppend cs1 cs2 = CAppend cs1 cs2
+
+cIndent n cs = CIndent n cs
+
+cNL    = CNewline
+cStr   = CStr
+cCh    = CCh
+cInt   = CInt
+
+#if defined(COMPILING_GHC) && __GLASGOW_HASKELL__ >= 23
+cPStr  = CPStr
+#else
+cPStr  = CStr
+#endif
+
+cShow  seq     = flatten ILIT(0) _TRUE_ seq []
+
+#if ! defined(COMPILING_GHC)
+cShows seq rest = cShow seq ++ rest
+cLength seq = length (cShow seq) -- *not* the best way to do this!
+#endif
+
+#if defined(COMPILING_GHC) && __GLASGOW_HASKELL__ >= 22
+cAppendFile file_star seq
+  = flattenIO file_star seq
+#endif
+\end{code}
+
+This code is {\em hammered}.  We are not above doing sleazy
+non-standard things.  (WDP 94/10)
+
+\begin{code}
+data WorkItem = WI FAST_INT CSeq -- indentation, and sequence
+
+flatten :: FAST_INT    -- Indentation
+       -> FAST_BOOL    -- True => just had a newline
+       -> CSeq         -- Current seq to flatten
+       -> [WorkItem]   -- Work list with indentation
+       -> String
+
+flatten n nlp CNil seqs = flattenS nlp seqs
+
+flatten n nlp (CAppend seq1 seq2) seqs = flatten n nlp seq1 ((WI n seq2) : seqs)
+flatten n nlp (CIndent IBOX(n2) seq) seqs = flatten (n2 _ADD_ n) nlp seq seqs
+
+flatten n _FALSE_ CNewline seqs = '\n' : flattenS _TRUE_ seqs
+flatten n _TRUE_  CNewline seqs = flattenS _TRUE_ seqs -- Already at start of line
+
+flatten n _FALSE_ (CStr s) seqs = s ++ flattenS _FALSE_ seqs
+flatten n _FALSE_ (CCh  c) seqs = c :  flattenS _FALSE_ seqs
+flatten n _FALSE_ (CInt i) seqs = show i ++ flattenS _FALSE_ seqs
+#if defined(COMPILING_GHC) && __GLASGOW_HASKELL__ >= 23
+flatten n _FALSE_ (CPStr s) seqs = _unpackPS s ++ flattenS _FALSE_ seqs
+#endif
+
+flatten n _TRUE_  (CStr s) seqs = mkIndent n (s ++ flattenS _FALSE_ seqs)
+flatten n _TRUE_  (CCh  c) seqs = mkIndent n (c :  flattenS _FALSE_ seqs)
+flatten n _TRUE_  (CInt i) seqs = mkIndent n (show i ++ flattenS _FALSE_ seqs)
+#if defined(COMPILING_GHC) && __GLASGOW_HASKELL__ >= 23
+flatten n _TRUE_ (CPStr s) seqs = mkIndent n (_unpackPS s ++ flattenS _FALSE_ seqs)
+#endif
+\end{code}
+
+\begin{code}
+flattenS :: FAST_BOOL -> [WorkItem] -> String
+flattenS nlp [] = ""
+flattenS nlp ((WI col seq):seqs) = flatten col nlp seq seqs
+\end{code}
+
+\begin{code}
+mkIndent :: FAST_INT -> String -> String
+mkIndent ILIT(0) s = s
+mkIndent n       s
+  = if (n _GE_ ILIT(8))
+    then '\t' : mkIndent (n _SUB_ ILIT(8)) s
+    else ' '  : mkIndent (n _SUB_ ILIT(1)) s
+    -- Hmm.. a little Unix-y.
+\end{code}
+
+Now the I/O version.
+This code is massively {\em hammered}.
+It {\em ignores} indentation.
+
+\begin{code}
+#if defined(COMPILING_GHC) && __GLASGOW_HASKELL__ >= 22
+
+flattenIO :: _FILE     -- file we are writing to
+         -> CSeq       -- Seq to print
+         -> PrimIO ()
+
+flattenIO file sq
+# if __GLASGOW_HASKELL__ >= 23
+  | file == ``NULL'' = error "panic:flattenIO" -- really just to force eval :-)
+  | otherwise
+# endif
+  = flat sq
+  where
+    flat CNil = BSCC("flatCNil") returnPrimIO () ESCC
+
+    flat (CIndent n2 seq) = BSCC("flatCIndent") flat seq ESCC
+
+    flat (CAppend seq1 seq2)
+      = BSCC("flatCAppend")
+       flat seq1 `seqPrimIO` flat seq2
+       ESCC
+
+    flat CNewline = BSCC("flatCNL") _ccall_ stg_putc '\n' file ESCC
+
+    flat (CCh c) = BSCC("flatCCh") _ccall_ stg_putc c file ESCC
+
+    flat (CInt i) = BSCC("flatCInt") _ccall_ fprintf file percent_d i ESCC
+
+    flat (CStr s) = BSCC("flatCStr") put_str s ESCC
+
+# if defined(COMPILING_GHC) && __GLASGOW_HASKELL__ >= 23
+    flat (CPStr s) = BSCC("flatCPStr") put_pstr s ESCC
+# endif
+
+    -----
+    put_str, put_str2 :: String -> PrimIO ()
+
+    put_str str
+      = --put_str2 ``stderr'' (str ++ "\n") `seqPrimIO`
+       put_str2                str
+
+    put_str2 [] = BSCC("putNil") returnPrimIO () ESCC
+
+    put_str2 (c1@(C# _) : c2@(C# _) : c3@(C# _) : c4@(C# _) : cs)
+      = BSCC("put4")
+       _ccall_ stg_putc  c1 file       `seqPrimIO`
+       _ccall_ stg_putc  c2 file       `seqPrimIO`
+       _ccall_ stg_putc  c3 file       `seqPrimIO`
+       _ccall_ stg_putc  c4 file       `seqPrimIO`
+       put_str2 cs     -- efficiency hack?  who knows... (WDP 94/10)
+       ESCC
+
+    put_str2 (c1@(C# _) : c2@(C# _) : c3@(C# _) : cs)
+      = BSCC("put3")
+       _ccall_ stg_putc  c1 file       `seqPrimIO`
+       _ccall_ stg_putc  c2 file       `seqPrimIO`
+       _ccall_ stg_putc  c3 file       `seqPrimIO`
+       put_str2 cs     -- efficiency hack?  who knows... (WDP 94/10)
+       ESCC
+
+    put_str2 (c1@(C# _) : c2@(C# _) : cs)
+      = BSCC("put2")
+       _ccall_ stg_putc  c1 file       `seqPrimIO`
+       _ccall_ stg_putc  c2 file       `seqPrimIO`
+       put_str2 cs     -- efficiency hack?  who knows... (WDP 94/10)
+       ESCC
+
+    put_str2 (c1@(C# _) : cs)
+      = BSCC("put1")
+       _ccall_ stg_putc  c1 file       `seqPrimIO`
+       put_str2 cs     -- efficiency hack?  who knows... (WDP 94/10)
+       ESCC
+
+# if __GLASGOW_HASKELL__ >= 23
+    put_pstr ps = _putPS file ps
+# endif
+
+# if __GLASGOW_HASKELL__ >= 23
+percent_d = _psToByteArray SLIT("%d")
+# else
+percent_d = "%d"
+# endif
+
+#endif {- __GLASGOW_HASKELL__ >= 22 -}
+\end{code}