[project @ 1996-01-08 20:28:12 by partain]
[ghc-hetmet.git] / ghc / lib / prelude / Text.hs
diff --git a/ghc/lib/prelude/Text.hs b/ghc/lib/prelude/Text.hs
new file mode 100644 (file)
index 0000000..239c655
--- /dev/null
@@ -0,0 +1,461 @@
+module PreludeText (
+       ReadS(..), ShowS(..),
+
+       lex,
+       showString,
+       readParen,
+       showParen,
+       read,
+       readDec,
+       readFloat,
+       readLitChar,
+       readSigned,
+       _readRational,
+       reads,
+       show,
+       showChar,
+       showFloat,
+       showInt,
+       showLitChar,
+       showSigned,
+       shows,
+
+       _showHex, _showRadix, _showDigit, -- non-std
+       
+       showSpace__, -- non-std
+--     lexToss__,   -- non-std
+       readOct, readHex
+    ) where
+
+import Cls
+import Core
+import IChar           -- instances
+import IDouble
+import IFloat
+import IInt
+import IInteger
+import IList
+import IRatio
+import ITup2
+import List
+import Prel
+import PS              ( _PackedString, _unpackPS )
+import TyComplex       -- for pragmas
+-- import Prelude hiding ( readParen )
+
+type  ReadS a = String -> [(a,String)]
+type  ShowS   = String -> String
+
+-- *** instances omitted ***
+
+
+{-# SPECIALIZE reads :: ReadS Int,
+                       ReadS Integer,
+                       ReadS Float,
+                       ReadS Double #-}
+{-# SPECIALIZE shows :: Int     -> String -> String = shows_Int,
+                       Integer -> String -> String = shows_Integer,
+                       Float   -> String -> String,
+                       Double  -> String -> String #-}
+{-# SPECIALIZE show  :: Char    -> String,
+                       Int     -> String = itos,
+                       Integer -> String = jtos,
+                       Float   -> String,
+                       Double  -> String,
+                       _PackedString  -> String,
+                       String  -> String,
+                       (Int,Int) -> String,
+                       (Integer,Integer) -> String #-}
+{-# SPECIALIZE read  :: String  -> Int,
+                       String  -> Integer,
+                       String  -> Float,
+                       String  -> Double #-}
+
+--{-# GENERATE_SPECS reads a #-}
+reads          :: (Text a) => ReadS a
+reads          =  readsPrec 0
+
+--{-# GENERATE_SPECS read a #-}
+read           :: (Text a) => String -> a
+read s                 =  case [x | (x,t) <- reads s, ("","") <- lex t] of
+                       [x] -> x
+                       []  -> error ("read{PreludeText}: no parse:"++s++"\n")
+                       _   -> error ("read{PreludeText}: ambiguous parse:"++s++"\n")
+
+--{-# GENERATE_SPECS shows a{+,Int} #-}
+shows          :: (Text a) => a -> ShowS
+shows          =  showsPrec 0
+
+shows_Int      :: Int -> ShowS
+shows_Int n r  = itos n ++ r   --  showsPrec 0 n r
+
+shows_Integer  :: Integer -> ShowS
+shows_Integer n r = jtos n ++ r        --  showsPrec 0 n r
+
+--{-# GENERATE_SPECS show a{+,Int} #-}
+show           :: (Text a) => a -> String
+show x                 =  shows x ""
+
+showChar       :: Char -> ShowS
+showChar       =  (:)
+
+showSpace__    :: ShowS        -- partain: this one is non-std
+showSpace__    = {-showChar ' '-} \ xs -> ' ' : xs
+
+showString     :: String -> ShowS
+showString     =  (++)
+
+showParen      :: Bool -> ShowS -> ShowS
+showParen b p  =  if b then showChar '(' . p . showChar ')' else p
+
+readParen      :: Bool -> ReadS a -> ReadS a
+readParen b g  =  if b then mandatory else optional
+                  where optional r  = g r ++ mandatory r
+                        mandatory r = [(x,u) | ("(",s) <- lex r,
+                                               (x,t)   <- optional s,
+                                               (")",u) <- lex t    ]
+
+--------------------------------------------
+lex                    :: ReadS String
+lex ""                 = [("","")]
+lex (c:s) | isSpace c  = lex (dropWhile isSpace s)
+lex ('-':'-':s)                = case dropWhile (/= '\n') s of
+                                '\n':t -> lex t
+                                _      -> [] -- unterminated end-of-line
+                                             -- comment
+
+lex ('{':'-':s)                = lexNest lex s
+                         where
+                         lexNest f ('-':'}':s) = f s
+                         lexNest f ('{':'-':s) = lexNest (lexNest f) s
+                         lexNest f (c:s)             = lexNest f s
+                         lexNest _ ""          = [] -- unterminated
+                                                    -- nested comment
+
+lex ('<':'-':s)                = [("<-",s)]
+lex ('\'':s)           = [('\'':ch++"'", t) | (ch,'\'':t)  <- lexLitChar s,
+                                              ch /= "'"                ]
+lex ('"':s)            = [('"':str, t)      | (str,t) <- lexString s]
+                         where
+                         lexString ('"':s) = [("\"",s)]
+                         lexString s = [(ch++str, u)
+                                               | (ch,t)  <- lexStrItem s,
+                                                 (str,u) <- lexString t  ]
+
+                         lexStrItem ('\\':'&':s) = [("\\&",s)]
+                         lexStrItem ('\\':c:s) | isSpace c
+                             = [("\\&",t) | '\\':t <- [dropWhile isSpace s]]
+                         lexStrItem s            = lexLitChar s
+
+lex (c:s) | isSingle c = [([c],s)]
+         | isSym1 c    = [(c:sym,t)         | (sym,t) <- [span isSym s]]
+         | isAlpha c   = [(c:nam,t)         | (nam,t) <- [span isIdChar s]]
+         | isDigit c   = [(c:ds++fe,t)      | (ds,s)  <- [span isDigit s],
+                                              (fe,t)  <- lexFracExp s     ]
+         | otherwise   = []    -- bad character
+               where
+               isSingle c  =  c `elem` ",;()[]{}_`"
+               isSym1 c    =  c `elem` "-~" || isSym c
+               isSym c     =  c `elem` "!@#$%&*+./<=>?\\^|:"
+               isIdChar c  =  isAlphanum c || c `elem` "_'"
+
+               lexFracExp ('.':d:s) | isDigit d
+                       = [('.':d:ds++e,u) | (ds,t) <- [span isDigit s],
+                                            (e,u)  <- lexExp t       ]
+               lexFracExp s       = [("",s)]
+
+               lexExp (e:s) | e `elem` "eE"
+                        = [(e:c:ds,u) | (c:t)  <- [s], c `elem` "+-",
+                                                  (ds,u) <- lexDigits t] ++
+                          [(e:ds,t)   | (ds,t) <- lexDigits s]
+               lexExp s = [("",s)]
+
+lexDigits              :: ReadS String 
+lexDigits              =  nonnull isDigit
+
+nonnull                        :: (Char -> Bool) -> ReadS String
+nonnull p s            =  [(cs,t) | (cs@(_:_),t) <- [span p s]]
+
+lexLitChar             :: ReadS String
+
+lexLitChar ('\\':s)    =  [('\\':esc, t) | (esc,t) <- lexEsc s]
+       where
+       lexEsc (c:s)     | c `elem` "abfnrtv\\\"'" = [([c],s)]
+       lexEsc ('^':c:s) | c >= '@' && c <= '_'  = [(['^',c],s)]
+       lexEsc s@(d:_)   | isDigit d             = lexDigits s
+       lexEsc ('o':s)  =  [('o':os, t) | (os,t) <- nonnull isOctDigit s]
+       lexEsc ('x':s)  =  [('x':xs, t) | (xs,t) <- nonnull isHexDigit s]
+       lexEsc s@(c:_)   | isUpper c
+                       =  case [(mne,s') | mne <- "DEL" : asciiTab,
+                                           ([],s') <- [match mne s]      ]
+                          of (pr:_) -> [pr]
+                             []     -> []
+       lexEsc _        =  []
+lexLitChar (c:s)       =  [([c],s)]
+lexLitChar ""          =  []
+
+isOctDigit c  =  c >= '0' && c <= '7'
+isHexDigit c  =  isDigit c || c >= 'A' && c <= 'F'
+                          || c >= 'a' && c <= 'f'
+
+match                  :: (Eq a) => [a] -> [a] -> ([a],[a])
+match (x:xs) (y:ys) | x == y  =  match xs ys
+match xs     ys                      =  (xs,ys)
+
+asciiTab = -- Using an array drags in the array module.  listArray ('\NUL', ' ')
+          ["NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
+           "BS",  "HT",  "LF",  "VT",  "FF",  "CR",  "SO",  "SI", 
+           "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
+           "CAN", "EM",  "SUB", "ESC", "FS",  "GS",  "RS",  "US", 
+           "SP"] 
+
+readLitChar            :: ReadS Char
+
+readLitChar ('\\':s)   =  readEsc s
+       where
+       readEsc ('a':s)  = [('\a',s)]
+       readEsc ('b':s)  = [('\b',s)]
+       readEsc ('f':s)  = [('\f',s)]
+       readEsc ('n':s)  = [('\n',s)]
+       readEsc ('r':s)  = [('\r',s)]
+       readEsc ('t':s)  = [('\t',s)]
+       readEsc ('v':s)  = [('\v',s)]
+       readEsc ('\\':s) = [('\\',s)]
+       readEsc ('"':s)  = [('"',s)]
+       readEsc ('\'':s) = [('\'',s)]
+       readEsc ('^':c:s) | c >= '@' && c <= '_'
+                        = [(chr (ord c - ord '@'), s)]
+       readEsc s@(d:_) | isDigit d
+                        = [(chr n, t) | (n,t) <- readDec s]
+       readEsc ('o':s)  = [(chr n, t) | (n,t) <- readOct s]
+       readEsc ('x':s)  = [(chr n, t) | (n,t) <- readHex s]
+       readEsc s@(c:_) | isUpper c
+                        = let table = ('\DEL', "DEL") : zip ['\NUL'..] asciiTab
+                          in case [(c,s') | (c, mne) <- table,
+                                            ([],s') <- [match mne s]]
+                             of (pr:_) -> [pr]
+                                []     -> []
+       readEsc _        = []
+readLitChar (c:s)      =  [(c,s)]
+
+showLitChar               :: Char -> ShowS
+showLitChar c | c > '\DEL' =  showChar '\\' . protectEsc isDigit (shows (ord c))
+showLitChar '\DEL'        =  showString "\\DEL"
+showLitChar '\\'          =  showString "\\\\"
+showLitChar c | c >= ' '   =  showChar c
+showLitChar '\a'          =  showString "\\a"
+showLitChar '\b'          =  showString "\\b"
+showLitChar '\f'          =  showString "\\f"
+showLitChar '\n'          =  showString "\\n"
+showLitChar '\r'          =  showString "\\r"
+showLitChar '\t'          =  showString "\\t"
+showLitChar '\v'          =  showString "\\v"
+showLitChar '\SO'         =  protectEsc (== 'H') (showString "\\SO")
+showLitChar c             =  showString ('\\' : asciiTab!!ord c)
+
+protectEsc p f            = f . cont
+                            where cont s@(c:_) | p c = "\\&" ++ s
+                                  cont s             = s
+
+{-# SPECIALIZE readDec :: ReadS Int, ReadS Integer #-}
+-- specialisations of readInt should happen automagically
+{-# SPECIALIZE showInt :: Int -> ShowS, Integer -> ShowS #-}
+
+readDec, readOct, readHex :: (Integral a) => ReadS a
+readDec = readInt 10 isDigit (\d -> ord d - i_ord_0)
+readOct = readInt  8 isOctDigit (\d -> ord d - i_ord_0)
+readHex = readInt 16 isHexDigit hex
+           where hex d = ord d - (if isDigit d then i_ord_0
+                                  else ord (if isUpper d then 'A' else 'a')
+                                       - 10)
+
+readInt :: (Integral a) => a -> (Char -> Bool) -> (Char -> Int) -> ReadS a
+readInt radix isDig digToInt s =
+    [(foldl1 (\n d -> n * radix + d) (map (fromIntegral . digToInt) ds), r)
+       | (ds,r) <- nonnull isDig s ]
+
+showInt        :: (Integral a) => a -> ShowS
+{- USE_REPORT_PRELUDE
+showInt n r = let (n',d) = quotRem n 10
+                 r' = chr (i_ord_0 + fromIntegral d) : r
+             in if n' == 0 then r' else showInt n' r'
+-}
+
+showInt n r
+  = case quotRem n 10 of                    { (n', d) ->
+    case (chr (i_ord_0 + fromIntegral d)) of { C# c# -> -- stricter than necessary
+    let
+       r' = C# c# : r
+    in
+    if n' == 0 then r' else showInt n' r'
+    }}
+
+-- #endif /* ! USE_REPORT_PRELUDE */
+
+{-# SPECIALIZE readSigned :: ReadS Int     -> ReadS Int,
+                            ReadS Integer -> ReadS Integer,
+                            ReadS Double  -> ReadS Double #-}
+{-# SPECIALIZE showSigned :: (Int     -> ShowS) -> Int -> Int     -> ShowS = showSigned_Int,
+                            (Integer -> ShowS) -> Int -> Integer -> ShowS = showSigned_Integer,
+                            (Double  -> ShowS) -> Int -> Double  -> ShowS #-}
+{-# SPECIALIZE readFloat  :: ReadS Float,
+                            ReadS Double #-}
+{-# SPECIALIZE showFloat  :: Float -> ShowS, Double -> ShowS #-}
+
+readSigned:: (Real a) => ReadS a -> ReadS a
+readSigned readPos = readParen False read'
+                    where read' r  = read'' r ++
+                                     [(-x,t) | ("-",s) <- lex r,
+                                               (x,t)   <- read'' s]
+                          read'' r = [(n,s)  | (str,s) <- lex r,
+                                               (n,"")  <- readPos str]
+
+-- ******************************************************************
+
+showSigned:: (Real a) => (a -> ShowS) -> Int -> a -> ShowS
+showSigned showPos p x = if x < 0 then showParen (p > 6)
+                                                (showChar '-' . showPos (-x))
+                                 else showPos x
+
+showSigned_Int :: (Int -> ShowS) -> Int -> Int -> ShowS
+showSigned_Int _ p n r
+  = -- from HBC version; support code follows
+    if n < 0 && p > 6 then '(':itos n++(')':r) else itos n ++ r
+
+showSigned_Integer :: (Integer -> ShowS) -> Int -> Integer -> ShowS
+showSigned_Integer _ p n r
+  = -- from HBC version; support code follows
+    if n < 0 && p > 6 then '(':jtos n++(')':r) else jtos n ++ r
+
+itos :: Int -> String
+itos n = 
+    if n < 0 then
+       if -n < 0 then
+           -- n is minInt, a difficult number
+           itos (n `quot` 10) ++ itos' (-(n `rem` 10)) []
+       else
+           '-':itos' (-n) []
+    else 
+       itos' n []
+  where
+    itos' :: Int -> String -> String
+    itos' n cs = 
+       if n < 10 then
+           chr (n + i_ord_0) : cs
+       else 
+           itos' (n `quot` 10) (chr (n `rem` 10+i_ord_0) : cs)
+
+i_ord_0 :: Int
+j_ord_0 :: Integer
+i_ord_0 = ord '0'
+j_ord_0 = toInteger (ord '0')
+
+jtos :: Integer -> String
+jtos n = 
+    if n < 0 then
+       if -n < 0 then
+           -- n is minInt, a difficult number
+           jtos (n `quot` 10) ++ jtos' (-(n `rem` 10)) []
+       else
+           '-':jtos' (-n) []
+    else 
+       jtos' n []
+  where
+    jtos' :: Integer -> String -> String
+    jtos' n cs = 
+       if n < 10 then
+           chr (fromInteger (n + j_ord_0)) : cs
+       else 
+           jtos' (n `quot` 10) (chr (fromInteger (n `rem` 10+j_ord_0)) : cs)
+
+-- ******************************************************************
+
+-- The functions readFloat and showFloat below use rational arithmetic
+-- to insure correct conversion between the floating-point radix and
+-- decimal.  It is often possible to use a higher-precision floating-
+-- point type to obtain the same results.
+
+readFloat :: (RealFloat a) => ReadS a
+readFloat r = [(fromRational x, t) | (x, t) <- readRational r]
+
+readRational :: ReadS Rational -- NB: doesn't handle leading "-"
+
+readRational r
+  = [ ( (n%1)*10^^(k-d), t ) | (n,d,s) <- readFix r,
+                              (k,t)   <- readExp s]
+              where readFix r = [(read (ds++ds'), length ds', t)
+                                       | (ds,'.':s) <- lexDigits r,
+                                         (ds',t)    <- lexDigits s ]
+
+                   readExp (e:s) | e `elem` "eE" = readExp' s
+                    readExp s                    = [(0,s)]
+
+                    readExp' ('-':s) = [(-k,t) | (k,t) <- readDec s]
+                    readExp' ('+':s) = readDec s
+                    readExp' s      = readDec s
+
+_readRational :: String -> Rational -- we export this one (non-std)
+                                   -- NB: *does* handle a leading "-"
+_readRational top_s
+  = case top_s of
+      '-' : xs -> - (read_me xs)
+      xs       -> read_me xs
+  where
+    read_me s
+      = case [x | (x,t) <- readRational s, ("","") <- lex t] of
+         [x] -> x
+         []  -> error ("_readRational: no parse:" ++ top_s)
+         _   -> error ("_readRational: ambiguous parse:" ++ top_s)
+
+-- The number of decimal digits m below is chosen to guarantee 
+-- read (show x) == x.  See
+--     Matula, D. W.  A formalization of floating-point numeric base
+--     conversion.  IEEE Transactions on Computers C-19, 8 (1970 August),
+--     681-692.
+zeros = repeat '0'
+
+showFloat:: (RealFloat a) => a -> ShowS
+showFloat x =
+    if x == 0 then showString ("0." ++ take (m-1) zeros)
+             else if e >= m-1 || e < 0 then showSci else showFix
+    where
+    showFix    = showString whole . showChar '.' . showString frac
+                 where (whole,frac) = splitAt (e+1) (show sig)
+    showSci    = showChar d . showChar '.' . showString frac
+                     . showChar 'e' . shows e
+                 where (d:frac) = show sig
+    (m, sig, e) = if b == 10 then (w,          s,   n+w-1)
+                            else (m', sig', e'   )
+    m'         = _ceiling
+                     ((fromIntegral w * log (fromInteger b)) / log 10 :: Double)
+                 + 1
+    (sig', e') = if      sig1 >= 10^m'     then (_round (t/10), e1+1)
+                 else if sig1 <  10^(m'-1) then (_round (t*10), e1-1)
+                                           else (sig1,          e1  )
+    sig1       = _round t
+    t          = s%1 * (b%1)^^n * 10^^(m'-e1-1)
+    e1         = _floor (logBase 10 x)
+    (s, n)     = decodeFloat x
+    b          = floatRadix x
+    w          = floatDigits x
+
+
+-- With all the guff the Prelude defines, you'd have thought they'd 
+-- include a few of the basics! ADR
+-- (I guess this could be put in a utilities module instead...)
+
+_showHex :: Int -> ShowS
+_showHex = _showRadix 16
+
+_showRadix :: Int -> Int -> ShowS
+_showRadix radix n r = 
+  let (n',d) = quotRem n radix
+      r' = _showDigit d : r
+  in 
+  if n' == 0 then r' else _showRadix radix n' r'
+
+_showDigit :: Int -> Char
+_showDigit d | d < 10    = chr (i_ord_0 + d) 
+             | otherwise = chr (ord 'a' + (d - 10))