packages feed

ghc-boot 9.4.1 → 9.6.0.20230302

raw patch · 6 files changed

+398/−315 lines, 6 filesdep ~basedep ~ghc-boot-thdep ~unixPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: base, ghc-boot-th, unix

API changes (from Hackage documentation)

- GHC.Utils.Encoding: countUTF8Chars :: ShortByteString -> IO Int
- GHC.Utils.Encoding: utf8CharStart :: Ptr Word8 -> IO (Ptr Word8)
- GHC.Utils.Encoding: utf8CompareShortByteString :: ShortByteString -> ShortByteString -> Ordering
- GHC.Utils.Encoding: utf8DecodeByteString :: ByteString -> [Char]
- GHC.Utils.Encoding: utf8DecodeChar :: Ptr Word8 -> (Char, Int)
- GHC.Utils.Encoding: utf8DecodeCharAddr# :: Addr# -> Int# -> (# Char#, Int# #)
- GHC.Utils.Encoding: utf8DecodeShortByteString :: ShortByteString -> [Char]
- GHC.Utils.Encoding: utf8DecodeStringLazy :: ForeignPtr Word8 -> Int -> Int -> [Char]
- GHC.Utils.Encoding: utf8EncodeChar :: (Int# -> Word8# -> State# s -> State# s) -> Char -> ST s Int
- GHC.Utils.Encoding: utf8EncodeShortByteString :: String -> IO ShortByteString
- GHC.Utils.Encoding: utf8EncodeString :: String -> ByteString
- GHC.Utils.Encoding: utf8EncodeStringPtr :: Ptr Word8 -> String -> IO ()
- GHC.Utils.Encoding: utf8EncodedLength :: String -> Int
- GHC.Utils.Encoding: utf8PrevChar :: Ptr Word8 -> IO (Ptr Word8)
- GHC.Utils.Encoding: utf8UnconsByteString :: ByteString -> Maybe (Char, ByteString)
+ GHC.Data.ShortText: singleton :: Char -> ShortText
+ GHC.Platform.ArchOS: ArchLoongArch64 :: Arch
+ GHC.Platform.ArchOS: ArchWasm32 :: Arch
+ GHC.Platform.ArchOS: OSWasi :: OS
+ GHC.Utils.Encoding: type EncodedString = String
+ GHC.Utils.Encoding: type UserString = String
+ GHC.Utils.Encoding.UTF8: utf8CharStart :: Ptr Word8 -> IO (Ptr Word8)
+ GHC.Utils.Encoding.UTF8: utf8CompareByteArray# :: ByteArray# -> ByteArray# -> Ordering
+ GHC.Utils.Encoding.UTF8: utf8CompareShortByteString :: ShortByteString -> ShortByteString -> Ordering
+ GHC.Utils.Encoding.UTF8: utf8CountCharsByteArray# :: ByteArray# -> Int
+ GHC.Utils.Encoding.UTF8: utf8CountCharsShortByteString :: ShortByteString -> Int
+ GHC.Utils.Encoding.UTF8: utf8DecodeByteArray# :: ByteArray# -> [Char]
+ GHC.Utils.Encoding.UTF8: utf8DecodeByteString :: ByteString -> [Char]
+ GHC.Utils.Encoding.UTF8: utf8DecodeCharAddr# :: Addr# -> Int# -> (# Char#, Int# #)
+ GHC.Utils.Encoding.UTF8: utf8DecodeCharByteArray# :: ByteArray# -> Int# -> (# Char#, Int# #)
+ GHC.Utils.Encoding.UTF8: utf8DecodeCharPtr :: Ptr Word8 -> (Char, Int)
+ GHC.Utils.Encoding.UTF8: utf8DecodeForeignPtr :: ForeignPtr Word8 -> Int -> Int -> [Char]
+ GHC.Utils.Encoding.UTF8: utf8DecodeShortByteString :: ShortByteString -> [Char]
+ GHC.Utils.Encoding.UTF8: utf8EncodeByteArray# :: String -> ByteArray#
+ GHC.Utils.Encoding.UTF8: utf8EncodeByteString :: String -> ByteString
+ GHC.Utils.Encoding.UTF8: utf8EncodePtr :: Ptr Word8 -> String -> IO ()
+ GHC.Utils.Encoding.UTF8: utf8EncodeShortByteString :: String -> ShortByteString
+ GHC.Utils.Encoding.UTF8: utf8EncodedLength :: String -> Int
+ GHC.Utils.Encoding.UTF8: utf8PrevChar :: Ptr Word8 -> IO (Ptr Word8)
+ GHC.Utils.Encoding.UTF8: utf8UnconsByteString :: ByteString -> Maybe (Char, ByteString)

Files

GHC/BaseDir.hs view
@@ -17,6 +17,7 @@ import Prelude -- See Note [Why do we import Prelude here?]  import Data.List (stripPrefix)+import Data.Maybe (listToMaybe) import System.FilePath  -- Windows@@ -37,7 +38,7 @@ expandPathVar :: String -> FilePath -> String -> String expandPathVar var value str   | Just str' <- stripPrefix ('$':var) str-  , null str' || isPathSeparator (head str')+  , maybe True isPathSeparator (listToMaybe str')   = value ++ expandPathVar var value str' expandPathVar var value (x:xs) = x : expandPathVar var value xs expandPathVar _ _ [] = []
GHC/Data/ShortText.hs view
@@ -1,6 +1,6 @@ {-# LANGUAGE BangPatterns, MagicHash, UnboxedTuples, GeneralizedNewtypeDeriving, DerivingStrategies, CPP #-} {-# OPTIONS_GHC -O2 -funbox-strict-fields #-}--- gross hack: we manuvered ourselves into a position where we can't boot GHC with a LLVM based GHC anymore.+-- gross hack: we maneuvered ourselves into a position where we can't boot GHC with a LLVM based GHC anymore. -- LLVM based GHC's fail to compile memcmp ffi calls.  These end up as memcmp$def in the llvm ir, however we -- don't have any prototypes and subsequently the llvm toolchain chokes on them.  Since 7fdcce6d, we use -- ShortText for the package database.  This however introduces this very module; which through inlining ends@@ -10,7 +10,7 @@ -- The solution thusly is to force late binding via the linker instead of inlining when comping with the -- bootstrap compiler.  This will produce a slower (slightly less optimised) stage1 compiler only. ----- See issue 18857. hsyl20 deserves credit for coming up with the idea for the soltuion.+-- See issue 18857. hsyl20 deserves credit for coming up with the idea for the solution. -- -- This can be removed when we exit the boot compiler window. Thus once we drop GHC-9.2 as boot compiler, -- we can drop this code as well.@@ -29,6 +29,7 @@         -- * ShortText         ShortText(..),         -- ** Conversion to and from String+        singleton,         pack,         unpack,         -- ** Operations@@ -67,15 +68,20 @@  -- | /O(n)/ Returns the length of the 'ShortText' in characters. codepointLength :: ShortText -> Int-codepointLength st = unsafeDupablePerformIO $ countUTF8Chars (contents st)+codepointLength st = utf8CountCharsShortByteString (contents st)+ -- | /O(1)/ Returns the length of the 'ShortText' in bytes. byteLength :: ShortText -> Int byteLength st = SBS.length $ contents st  -- | /O(n)/ Convert a 'String' into a 'ShortText'. pack :: String -> ShortText-pack s = unsafeDupablePerformIO $ ShortText <$> utf8EncodeShortByteString s+pack s = ShortText $ utf8EncodeShortByteString s +-- | Create a singleton+singleton :: Char -> ShortText+singleton s = pack [s]+ -- | /O(n)/ Convert a 'ShortText' into a 'String'. unpack :: ShortText -> String unpack st = utf8DecodeShortByteString $ contents st@@ -100,8 +106,10 @@ -- non-printable characters. head :: ShortText -> Char head st-  | SBS.null $ contents st = error "head: Empty ShortText"-  | otherwise              = Prelude.head $ unpack st+  | hd:_ <- unpack st+  = hd+  | otherwise+  = error "head: Empty ShortText"  -- | /O(n)/ The 'stripPrefix' function takes two 'ShortText's and returns 'Just' the remainder of -- the second iff the first is its prefix, and otherwise Nothing.
GHC/Platform/ArchOS.hs view
@@ -44,7 +44,9 @@    | ArchMipseb    | ArchMipsel    | ArchRISCV64+   | ArchLoongArch64    | ArchJavaScript+   | ArchWasm32    deriving (Read, Show, Eq, Ord)  -- | ARM Instruction Set Architecture@@ -95,6 +97,7 @@    | OSQNXNTO    | OSAIX    | OSHurd+   | OSWasi    deriving (Read, Show, Eq, Ord)  @@ -132,7 +135,9 @@   ArchMipseb        -> "mipseb"   ArchMipsel        -> "mipsel"   ArchRISCV64       -> "riscv64"-  ArchJavaScript    -> "js"+  ArchLoongArch64   -> "loongarch64"+  ArchJavaScript    -> "javascript"+  ArchWasm32        -> "wasm32"  -- | See Note [Platform Syntax]. stringEncodeOS :: OS -> String@@ -151,3 +156,4 @@   OSQNXNTO    -> "nto-qnx"   OSAIX       -> "aix"   OSHurd      -> "hurd"+  OSWasi      -> "wasi"
GHC/Utils/Encoding.hs view
@@ -17,23 +17,11 @@  module GHC.Utils.Encoding (         -- * UTF-8-        utf8DecodeCharAddr#,-        utf8PrevChar,-        utf8CharStart,-        utf8DecodeChar,-        utf8DecodeByteString,-        utf8UnconsByteString,-        utf8DecodeShortByteString,-        utf8CompareShortByteString,-        utf8DecodeStringLazy,-        utf8EncodeChar,-        utf8EncodeString,-        utf8EncodeStringPtr,-        utf8EncodeShortByteString,-        utf8EncodedLength,-        countUTF8Chars,+        module GHC.Utils.Encoding.UTF8,          -- * Z-encoding+        UserString,+        EncodedString,         zEncodeString,         zDecodeString, @@ -45,295 +33,11 @@ import Prelude  import Foreign-import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr) import Data.Char import qualified Data.Char as Char import Numeric-import GHC.IO-import GHC.ST -import Data.ByteString (ByteString)-import qualified Data.ByteString.Internal as BS-import Data.ByteString.Short.Internal (ShortByteString(..))--import GHC.Exts---- -------------------------------------------------------------------------------- UTF-8---- We can't write the decoder as efficiently as we'd like without--- resorting to unboxed extensions, unfortunately.  I tried to write--- an IO version of this function, but GHC can't eliminate boxed--- results from an IO-returning function.------ We assume we can ignore overflow when parsing a multibyte character here.--- To make this safe, we add extra sentinel bytes to unparsed UTF-8 sequences--- before decoding them (see "GHC.Data.StringBuffer").--{-# INLINE utf8DecodeChar# #-}-utf8DecodeChar# :: (Int# -> Word#) -> (# Char#, Int# #)-utf8DecodeChar# indexWord8# =-  let !ch0 = word2Int# (indexWord8# 0#) in-  case () of-    _ | isTrue# (ch0 <=# 0x7F#) -> (# chr# ch0, 1# #)--      | isTrue# ((ch0 >=# 0xC0#) `andI#` (ch0 <=# 0xDF#)) ->-        let !ch1 = word2Int# (indexWord8# 1#) in-        if isTrue# ((ch1 <# 0x80#) `orI#` (ch1 >=# 0xC0#)) then fail 1# else-        (# chr# (((ch0 -# 0xC0#) `uncheckedIShiftL#` 6#) +#-                  (ch1 -# 0x80#)),-           2# #)--      | isTrue# ((ch0 >=# 0xE0#) `andI#` (ch0 <=# 0xEF#)) ->-        let !ch1 = word2Int# (indexWord8# 1#) in-        if isTrue# ((ch1 <# 0x80#) `orI#` (ch1 >=# 0xC0#)) then fail 1# else-        let !ch2 = word2Int# (indexWord8# 2#) in-        if isTrue# ((ch2 <# 0x80#) `orI#` (ch2 >=# 0xC0#)) then fail 2# else-        (# chr# (((ch0 -# 0xE0#) `uncheckedIShiftL#` 12#) +#-                 ((ch1 -# 0x80#) `uncheckedIShiftL#` 6#)  +#-                  (ch2 -# 0x80#)),-           3# #)--     | isTrue# ((ch0 >=# 0xF0#) `andI#` (ch0 <=# 0xF8#)) ->-        let !ch1 = word2Int# (indexWord8# 1#) in-        if isTrue# ((ch1 <# 0x80#) `orI#` (ch1 >=# 0xC0#)) then fail 1# else-        let !ch2 = word2Int# (indexWord8# 2#) in-        if isTrue# ((ch2 <# 0x80#) `orI#` (ch2 >=# 0xC0#)) then fail 2# else-        let !ch3 = word2Int# (indexWord8# 3#) in-        if isTrue# ((ch3 <# 0x80#) `orI#` (ch3 >=# 0xC0#)) then fail 3# else-        (# chr# (((ch0 -# 0xF0#) `uncheckedIShiftL#` 18#) +#-                 ((ch1 -# 0x80#) `uncheckedIShiftL#` 12#) +#-                 ((ch2 -# 0x80#) `uncheckedIShiftL#` 6#)  +#-                  (ch3 -# 0x80#)),-           4# #)--      | otherwise -> fail 1#-  where-        -- all invalid sequences end up here:-        fail :: Int# -> (# Char#, Int# #)-        fail nBytes# = (# '\0'#, nBytes# #)-        -- '\xFFFD' would be the usual replacement character, but-        -- that's a valid symbol in Haskell, so will result in a-        -- confusing parse error later on.  Instead we use '\0' which-        -- will signal a lexer error immediately.--utf8DecodeCharAddr# :: Addr# -> Int# -> (# Char#, Int# #)-utf8DecodeCharAddr# a# off# =-#if !MIN_VERSION_base(4,16,0)-    utf8DecodeChar# (\i# -> indexWord8OffAddr# a# (i# +# off#))-#else-    utf8DecodeChar# (\i# -> word8ToWord# (indexWord8OffAddr# a# (i# +# off#)))-#endif--utf8DecodeCharByteArray# :: ByteArray# -> Int# -> (# Char#, Int# #)-utf8DecodeCharByteArray# ba# off# =-#if !MIN_VERSION_base(4,16,0)-    utf8DecodeChar# (\i# -> indexWord8Array# ba# (i# +# off#))-#else-    utf8DecodeChar# (\i# -> word8ToWord# (indexWord8Array# ba# (i# +# off#)))-#endif---utf8DecodeChar :: Ptr Word8 -> (Char, Int)-utf8DecodeChar !(Ptr a#) =-  case utf8DecodeCharAddr# a# 0# of-    (# c#, nBytes# #) -> ( C# c#, I# nBytes# )---- UTF-8 is cleverly designed so that we can always figure out where--- the start of the current character is, given any position in a--- stream.  This function finds the start of the previous character,--- assuming there *is* a previous character.-utf8PrevChar :: Ptr Word8 -> IO (Ptr Word8)-utf8PrevChar p = utf8CharStart (p `plusPtr` (-1))--utf8CharStart :: Ptr Word8 -> IO (Ptr Word8)-utf8CharStart p = go p- where go p = do w <- peek p-                 if w >= 0x80 && w < 0xC0-                        then go (p `plusPtr` (-1))-                        else return p--{-# INLINE utf8DecodeLazy# #-}-utf8DecodeLazy# :: (IO ()) -> (Int# -> (# Char#, Int# #)) -> Int# -> IO [Char]-utf8DecodeLazy# retain decodeChar# len#-  = unpack 0#-  where-    unpack i#-        | isTrue# (i# >=# len#) = retain >> return []-        | otherwise =-            case decodeChar# i# of-              (# c#, nBytes# #) -> do-                rest <- unsafeDupableInterleaveIO $ unpack (i# +# nBytes#)-                return (C# c# : rest)--utf8DecodeByteString :: ByteString -> [Char]-utf8DecodeByteString (BS.PS fptr offset len)-  = utf8DecodeStringLazy fptr offset len--utf8UnconsByteString :: ByteString -> Maybe (Char, ByteString)-utf8UnconsByteString (BS.PS _ _ 0) = Nothing-utf8UnconsByteString (BS.PS fptr offset len)-  = unsafeDupablePerformIO $-      withForeignPtr fptr $ \ptr -> do-        let (c,n) = utf8DecodeChar (ptr `plusPtr` offset)-        return $ Just (c, BS.PS fptr (offset + n) (len - n))--utf8DecodeStringLazy :: ForeignPtr Word8 -> Int -> Int -> [Char]-utf8DecodeStringLazy fp offset (I# len#)-  = unsafeDupablePerformIO $ do-      let !(Ptr a#) = unsafeForeignPtrToPtr fp `plusPtr` offset-      utf8DecodeLazy# (touchForeignPtr fp) (utf8DecodeCharAddr# a#) len#--- Note that since utf8DecodeLazy# returns a thunk the lifetime of the--- ForeignPtr actually needs to be longer than the lexical lifetime--- withForeignPtr would provide here. That's why we use touchForeignPtr to--- keep the fp alive until the last character has actually been decoded.--utf8CompareShortByteString :: ShortByteString -> ShortByteString -> Ordering-utf8CompareShortByteString (SBS a1) (SBS a2) = go 0# 0#-   -- UTF-8 has the property that sorting by bytes values also sorts by-   -- code-points.-   -- BUT we use "Modified UTF-8" which encodes \0 as 0xC080 so this property-   -- doesn't hold and we must explicitly check this case here.-   -- Note that decoding every code point would also work but it would be much-   -- more costly.-   where-       !sz1 = sizeofByteArray# a1-       !sz2 = sizeofByteArray# a2-       go off1 off2-         | isTrue# ((off1 >=# sz1) `andI#` (off2 >=# sz2)) = EQ-         | isTrue# (off1 >=# sz1)                          = LT-         | isTrue# (off2 >=# sz2)                          = GT-         | otherwise =-#if !MIN_VERSION_base(4,16,0)-               let !b1_1 = indexWord8Array# a1 off1-                   !b2_1 = indexWord8Array# a2 off2-#else-               let !b1_1 = word8ToWord# (indexWord8Array# a1 off1)-                   !b2_1 = word8ToWord# (indexWord8Array# a2 off2)-#endif-               in case b1_1 of-                  0xC0## -> case b2_1 of-                     0xC0## -> go (off1 +# 1#) (off2 +# 1#)-#if !MIN_VERSION_base(4,16,0)-                     _      -> case indexWord8Array# a1 (off1 +# 1#) of-#else-                     _      -> case word8ToWord# (indexWord8Array# a1 (off1 +# 1#)) of-#endif-                        0x80## -> LT-                        _      -> go (off1 +# 1#) (off2 +# 1#)-                  _      -> case b2_1 of-#if !MIN_VERSION_base(4,16,0)-                     0xC0## -> case indexWord8Array# a2 (off2 +# 1#) of-#else-                     0xC0## -> case word8ToWord# (indexWord8Array# a2 (off2 +# 1#)) of-#endif-                        0x80## -> GT-                        _      -> go (off1 +# 1#) (off2 +# 1#)-                     _   | isTrue# (b1_1 `gtWord#` b2_1) -> GT-                         | isTrue# (b1_1 `ltWord#` b2_1) -> LT-                         | otherwise                     -> go (off1 +# 1#) (off2 +# 1#)--utf8DecodeShortByteString :: ShortByteString -> [Char]-utf8DecodeShortByteString (SBS ba#)-  = unsafeDupablePerformIO $-      let len# = sizeofByteArray# ba# in-      utf8DecodeLazy# (return ()) (utf8DecodeCharByteArray# ba#) len#--countUTF8Chars :: ShortByteString -> IO Int-countUTF8Chars (SBS ba) = go 0# 0#-  where-    len# = sizeofByteArray# ba-    go i# n#-      | isTrue# (i# >=# len#) =-          return (I# n#)-      | otherwise = do-          case utf8DecodeCharByteArray# ba i# of-            (# _, nBytes# #) -> go (i# +# nBytes#) (n# +# 1#)--{-# INLINE utf8EncodeChar #-}-utf8EncodeChar :: (Int# -> Word8# -> State# s -> State# s)-               -> Char -> ST s Int-utf8EncodeChar write# c =-  let x = fromIntegral (ord c) in-  case () of-    _ | x > 0 && x <= 0x007f -> do-          write 0 x-          return 1-        -- NB. '\0' is encoded as '\xC0\x80', not '\0'.  This is so that we-        -- can have 0-terminated UTF-8 strings (see GHC.Base.unpackCStringUtf8).-      | x <= 0x07ff -> do-          write 0 (0xC0 .|. ((x `shiftR` 6) .&. 0x1F))-          write 1 (0x80 .|. (x .&. 0x3F))-          return 2-      | x <= 0xffff -> do-          write 0 (0xE0 .|. (x `shiftR` 12) .&. 0x0F)-          write 1 (0x80 .|. (x `shiftR` 6) .&. 0x3F)-          write 2 (0x80 .|. (x .&. 0x3F))-          return 3-      | otherwise -> do-          write 0 (0xF0 .|. (x `shiftR` 18))-          write 1 (0x80 .|. ((x `shiftR` 12) .&. 0x3F))-          write 2 (0x80 .|. ((x `shiftR` 6) .&. 0x3F))-          write 3 (0x80 .|. (x .&. 0x3F))-          return 4-  where-    {-# INLINE write #-}-    write (I# off#) (W# c#) = ST $ \s ->-#if !MIN_VERSION_base(4,16,0)-      case write# off# (narrowWord8# c#) s of-#else-      case write# off# (wordToWord8# c#) s of-#endif-        s -> (# s, () #)--utf8EncodeString :: String -> ByteString-utf8EncodeString s =-  unsafePerformIO $ do-    let len = utf8EncodedLength s-    buf <- mallocForeignPtrBytes len-    withForeignPtr buf $ \ptr -> do-      utf8EncodeStringPtr ptr s-      pure (BS.fromForeignPtr buf 0 len)--utf8EncodeStringPtr :: Ptr Word8 -> String -> IO ()-utf8EncodeStringPtr (Ptr a#) str = go a# str-  where go !_   []   = return ()-        go a# (c:cs) = do-#if !MIN_VERSION_base(4,16,0)-          -- writeWord8OffAddr# was taking a Word#-          I# off# <- stToIO $ utf8EncodeChar (\i w -> writeWord8OffAddr# a# i (extendWord8# w)) c-#else-          I# off# <- stToIO $ utf8EncodeChar (writeWord8OffAddr# a#) c-#endif-          go (a# `plusAddr#` off#) cs--utf8EncodeShortByteString :: String -> IO ShortByteString-utf8EncodeShortByteString str = IO $ \s ->-  case utf8EncodedLength str         of { I# len# ->-  case newByteArray# len# s          of { (# s, mba# #) ->-  case go mba# 0# str                of { ST f_go ->-  case f_go s                        of { (# s, () #) ->-  case unsafeFreezeByteArray# mba# s of { (# s, ba# #) ->-  (# s, SBS ba# #) }}}}}-  where-    go _ _ [] = return ()-    go mba# i# (c:cs) = do-#if !MIN_VERSION_base(4,16,0)-      -- writeWord8Array# was taking a Word#-      I# off# <- utf8EncodeChar (\j# w -> writeWord8Array# mba# (i# +# j#) (extendWord8# w)) c-#else-      I# off# <- utf8EncodeChar (\j# -> writeWord8Array# mba# (i# +# j#)) c-#endif-      go mba# (i# +# off#) cs--utf8EncodedLength :: String -> Int-utf8EncodedLength str = go 0 str-  where go !n [] = n-        go n (c:cs)-          | ord c > 0 && ord c <= 0x007f = go (n+1) cs-          | ord c <= 0x07ff = go (n+2) cs-          | ord c <= 0xffff = go (n+3) cs-          | otherwise       = go (n+4) cs+import GHC.Utils.Encoding.UTF8  -- ----------------------------------------------------------------------------- -- Note [Z-Encoding]@@ -441,8 +145,10 @@ encode_ch c    = encode_as_unicode_char c  encode_as_unicode_char :: Char -> EncodedString-encode_as_unicode_char c = 'z' : if isDigit (head hex_str) then hex_str-                                                           else '0':hex_str+encode_as_unicode_char c = 'z' : case hex_str of+  hd : _+    | isDigit hd -> hex_str+  _ -> '0' : hex_str   where hex_str = showHex (ord c) "U"   -- ToDo: we could improve the encoding here in various ways.   -- eg. strings of unicode characters come out as 'z1234Uz5678U', we
+ GHC/Utils/Encoding/UTF8.hs view
@@ -0,0 +1,361 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE BangPatterns, MagicHash, UnboxedTuples, MultiWayIf #-}+{-# OPTIONS_GHC -O2 -fno-warn-name-shadowing #-}+-- We always optimise this, otherwise performance of a non-optimised+-- compiler is severely affected. This module used to live in the `ghc`+-- package but has been moved to `ghc-boot` because the definition+-- of the package database (needed in both ghc and in ghc-pkg) lives in+-- `ghc-boot` and uses ShortText, which in turn depends on this module.++-- | Simple, non-streaming UTF-8 codecs.+--+-- This is one of several UTF-8 implementations provided by GHC; see Note+-- [GHC's many UTF-8 implementations] in "GHC.Encoding.UTF8" for an+-- overview.+--+module GHC.Utils.Encoding.UTF8+    ( -- * Decoding single characters+      utf8DecodeCharAddr#+    , utf8DecodeCharPtr+    , utf8DecodeCharByteArray#+    , utf8PrevChar+    , utf8CharStart+    , utf8UnconsByteString+      -- * Decoding strings+    , utf8DecodeByteString+    , utf8DecodeShortByteString+    , utf8DecodeForeignPtr+    , utf8DecodeByteArray#+      -- * Counting characters+    , utf8CountCharsShortByteString+    , utf8CountCharsByteArray#+      -- * Comparison+    , utf8CompareByteArray#+    , utf8CompareShortByteString+      -- * Encoding strings+    , utf8EncodeByteArray#+    , utf8EncodePtr+    , utf8EncodeByteString+    , utf8EncodeShortByteString+    , utf8EncodedLength+    ) where+++import Prelude++import Foreign+import GHC.IO+#if MIN_VERSION_base(4,18,0)+import GHC.Encoding.UTF8+#else+import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)+import Data.Char+import GHC.Exts+import GHC.ST+#endif++import Data.ByteString (ByteString)+import qualified Data.ByteString.Internal as BS+import Data.ByteString.Short.Internal (ShortByteString(..))++-- | Find the start of the codepoint preceding the codepoint at the given+-- 'Ptr'. This is undefined if there is no previous valid codepoint.+utf8PrevChar :: Ptr Word8 -> IO (Ptr Word8)+utf8PrevChar p = utf8CharStart (p `plusPtr` (-1))++-- | Find the start of the codepoint at the given 'Ptr'. This is undefined if+-- there is no previous valid codepoint.+utf8CharStart :: Ptr Word8 -> IO (Ptr Word8)+utf8CharStart p = go p+ where go p = do w <- peek p+                 if w >= 0x80 && w < 0xC0+                        then go (p `plusPtr` (-1))+                        else return p++utf8CountCharsShortByteString :: ShortByteString -> Int+utf8CountCharsShortByteString (SBS ba) = utf8CountCharsByteArray# ba++utf8DecodeShortByteString :: ShortByteString -> [Char]+utf8DecodeShortByteString (SBS ba#) = utf8DecodeByteArray# ba#++-- | Decode a 'ByteString' containing a UTF-8 string.+utf8DecodeByteString :: ByteString -> [Char]+utf8DecodeByteString (BS.PS fptr offset len)+  = utf8DecodeForeignPtr fptr offset len++utf8EncodeShortByteString :: String -> ShortByteString+utf8EncodeShortByteString str = SBS (utf8EncodeByteArray# str)++-- | Encode a 'String' into a 'ByteString'.+utf8EncodeByteString :: String -> ByteString+utf8EncodeByteString s =+  unsafePerformIO $ do+    let len = utf8EncodedLength s+    buf <- mallocForeignPtrBytes len+    withForeignPtr buf $ \ptr -> do+      utf8EncodePtr ptr s+      pure (BS.fromForeignPtr buf 0 len)++utf8UnconsByteString :: ByteString -> Maybe (Char, ByteString)+utf8UnconsByteString (BS.PS _ _ 0) = Nothing+utf8UnconsByteString (BS.PS fptr offset len)+  = unsafeDupablePerformIO $+      withForeignPtr fptr $ \ptr -> do+        let (c,n) = utf8DecodeCharPtr (ptr `plusPtr` offset)+        return $ Just (c, BS.PS fptr (offset + n) (len - n))++utf8CompareShortByteString :: ShortByteString -> ShortByteString -> Ordering+utf8CompareShortByteString (SBS a1) (SBS a2) = utf8CompareByteArray# a1 a2++---------------------------------------------------------+-- Everything below was moved into base in GHC 9.6+--+-- These can be dropped in GHC 9.6 + 2 major releases.+---------------------------------------------------------++#if !MIN_VERSION_base(4,18,0)++-- We can't write the decoder as efficiently as we'd like without+-- resorting to unboxed extensions, unfortunately.  I tried to write+-- an IO version of this function, but GHC can't eliminate boxed+-- results from an IO-returning function.+--+-- We assume we can ignore overflow when parsing a multibyte character here.+-- To make this safe, we add extra sentinel bytes to unparsed UTF-8 sequences+-- before decoding them (see "GHC.Data.StringBuffer").++{-# INLINE utf8DecodeChar# #-}+-- | Decode a single codepoint from a byte buffer indexed by the given indexing+-- function.+utf8DecodeChar# :: (Int# -> Word#) -> (# Char#, Int# #)+utf8DecodeChar# indexWord8# =+  let !ch0 = word2Int# (indexWord8# 0#) in+  case () of+    _ | isTrue# (ch0 <=# 0x7F#) -> (# chr# ch0, 1# #)++      | isTrue# ((ch0 >=# 0xC0#) `andI#` (ch0 <=# 0xDF#)) ->+        let !ch1 = word2Int# (indexWord8# 1#) in+        if isTrue# ((ch1 <# 0x80#) `orI#` (ch1 >=# 0xC0#)) then fail 1# else+        (# chr# (((ch0 -# 0xC0#) `uncheckedIShiftL#` 6#) +#+                  (ch1 -# 0x80#)),+           2# #)++      | isTrue# ((ch0 >=# 0xE0#) `andI#` (ch0 <=# 0xEF#)) ->+        let !ch1 = word2Int# (indexWord8# 1#) in+        if isTrue# ((ch1 <# 0x80#) `orI#` (ch1 >=# 0xC0#)) then fail 1# else+        let !ch2 = word2Int# (indexWord8# 2#) in+        if isTrue# ((ch2 <# 0x80#) `orI#` (ch2 >=# 0xC0#)) then fail 2# else+        (# chr# (((ch0 -# 0xE0#) `uncheckedIShiftL#` 12#) +#+                 ((ch1 -# 0x80#) `uncheckedIShiftL#` 6#)  +#+                  (ch2 -# 0x80#)),+           3# #)++     | isTrue# ((ch0 >=# 0xF0#) `andI#` (ch0 <=# 0xF8#)) ->+        let !ch1 = word2Int# (indexWord8# 1#) in+        if isTrue# ((ch1 <# 0x80#) `orI#` (ch1 >=# 0xC0#)) then fail 1# else+        let !ch2 = word2Int# (indexWord8# 2#) in+        if isTrue# ((ch2 <# 0x80#) `orI#` (ch2 >=# 0xC0#)) then fail 2# else+        let !ch3 = word2Int# (indexWord8# 3#) in+        if isTrue# ((ch3 <# 0x80#) `orI#` (ch3 >=# 0xC0#)) then fail 3# else+        (# chr# (((ch0 -# 0xF0#) `uncheckedIShiftL#` 18#) +#+                 ((ch1 -# 0x80#) `uncheckedIShiftL#` 12#) +#+                 ((ch2 -# 0x80#) `uncheckedIShiftL#` 6#)  +#+                  (ch3 -# 0x80#)),+           4# #)++      | otherwise -> fail 1#+  where+        -- all invalid sequences end up here:+        fail :: Int# -> (# Char#, Int# #)+        fail nBytes# = (# '\0'#, nBytes# #)+        -- '\xFFFD' would be the usual replacement character, but+        -- that's a valid symbol in Haskell, so will result in a+        -- confusing parse error later on.  Instead we use '\0' which+        -- will signal a lexer error immediately.++-- | Decode a single character at the given 'Addr#'.+utf8DecodeCharAddr# :: Addr# -> Int# -> (# Char#, Int# #)+utf8DecodeCharAddr# a# off# =+#if !MIN_VERSION_base(4,16,0)+    utf8DecodeChar# (\i# -> indexWord8OffAddr# a# (i# +# off#))+#else+    utf8DecodeChar# (\i# -> word8ToWord# (indexWord8OffAddr# a# (i# +# off#)))+#endif++-- | Decode a single codepoint starting at the given 'Ptr'.+utf8DecodeCharPtr :: Ptr Word8 -> (Char, Int)+utf8DecodeCharPtr !(Ptr a#) =+  case utf8DecodeCharAddr# a# 0# of+    (# c#, nBytes# #) -> ( C# c#, I# nBytes# )++-- | Decode a single codepoint starting at the given byte offset into a+-- 'ByteArray#'.+utf8DecodeCharByteArray# :: ByteArray# -> Int# -> (# Char#, Int# #)+utf8DecodeCharByteArray# ba# off# =+#if !MIN_VERSION_base(4,16,0)+    utf8DecodeChar# (\i# -> indexWord8Array# ba# (i# +# off#))+#else+    utf8DecodeChar# (\i# -> word8ToWord# (indexWord8Array# ba# (i# +# off#)))+#endif++{-# INLINE utf8Decode# #-}+utf8Decode# :: (IO ()) -> (Int# -> (# Char#, Int# #)) -> Int# -> IO [Char]+utf8Decode# retain decodeChar# len#+  = unpack 0#+  where+    unpack i#+        | isTrue# (i# >=# len#) = retain >> return []+        | otherwise =+            case decodeChar# i# of+              (# c#, nBytes# #) -> do+                rest <- unsafeDupableInterleaveIO $ unpack (i# +# nBytes#)+                return (C# c# : rest)++utf8DecodeForeignPtr :: ForeignPtr Word8 -> Int -> Int -> [Char]+utf8DecodeForeignPtr fp offset (I# len#)+  = unsafeDupablePerformIO $ do+      let !(Ptr a#) = unsafeForeignPtrToPtr fp `plusPtr` offset+      utf8Decode# (touchForeignPtr fp) (utf8DecodeCharAddr# a#) len#+-- Note that since utf8Decode# returns a thunk the lifetime of the+-- ForeignPtr actually needs to be longer than the lexical lifetime+-- withForeignPtr would provide here. That's why we use touchForeignPtr to+-- keep the fp alive until the last character has actually been decoded.++utf8DecodeByteArray# :: ByteArray# -> [Char]+utf8DecodeByteArray# ba#+  = unsafeDupablePerformIO $+      let len# = sizeofByteArray# ba# in+      utf8Decode# (return ()) (utf8DecodeCharByteArray# ba#) len#++utf8CompareByteArray# :: ByteArray# -> ByteArray# -> Ordering+utf8CompareByteArray# a1 a2 = go 0# 0#+   -- UTF-8 has the property that sorting by bytes values also sorts by+   -- code-points.+   -- BUT we use "Modified UTF-8" which encodes \0 as 0xC080 so this property+   -- doesn't hold and we must explicitly check this case here.+   -- Note that decoding every code point would also work but it would be much+   -- more costly.+   where+       !sz1 = sizeofByteArray# a1+       !sz2 = sizeofByteArray# a2+       go off1 off2+         | isTrue# ((off1 >=# sz1) `andI#` (off2 >=# sz2)) = EQ+         | isTrue# (off1 >=# sz1)                          = LT+         | isTrue# (off2 >=# sz2)                          = GT+         | otherwise =+#if !MIN_VERSION_base(4,16,0)+               let !b1_1 = indexWord8Array# a1 off1+                   !b2_1 = indexWord8Array# a2 off2+#else+               let !b1_1 = word8ToWord# (indexWord8Array# a1 off1)+                   !b2_1 = word8ToWord# (indexWord8Array# a2 off2)+#endif+               in case b1_1 of+                  0xC0## -> case b2_1 of+                     0xC0## -> go (off1 +# 1#) (off2 +# 1#)+#if !MIN_VERSION_base(4,16,0)+                     _      -> case indexWord8Array# a1 (off1 +# 1#) of+#else+                     _      -> case word8ToWord# (indexWord8Array# a1 (off1 +# 1#)) of+#endif+                        0x80## -> LT+                        _      -> go (off1 +# 1#) (off2 +# 1#)+                  _      -> case b2_1 of+#if !MIN_VERSION_base(4,16,0)+                     0xC0## -> case indexWord8Array# a2 (off2 +# 1#) of+#else+                     0xC0## -> case word8ToWord# (indexWord8Array# a2 (off2 +# 1#)) of+#endif+                        0x80## -> GT+                        _      -> go (off1 +# 1#) (off2 +# 1#)+                     _   | isTrue# (b1_1 `gtWord#` b2_1) -> GT+                         | isTrue# (b1_1 `ltWord#` b2_1) -> LT+                         | otherwise                     -> go (off1 +# 1#) (off2 +# 1#)++utf8CountCharsByteArray# :: ByteArray# -> Int+utf8CountCharsByteArray# ba = go 0# 0#+  where+    len# = sizeofByteArray# ba+    go i# n#+      | isTrue# (i# >=# len#) = I# n#+      | otherwise =+          case utf8DecodeCharByteArray# ba i# of+            (# _, nBytes# #) -> go (i# +# nBytes#) (n# +# 1#)++{-# INLINE utf8EncodeChar #-}+utf8EncodeChar :: (Int# -> Word8# -> State# s -> State# s)+               -> Char -> ST s Int+utf8EncodeChar write# c =+  let x = fromIntegral (ord c) in+  case () of+    _ | x > 0 && x <= 0x007f -> do+          write 0 x+          return 1+        -- NB. '\0' is encoded as '\xC0\x80', not '\0'.  This is so that we+        -- can have 0-terminated UTF-8 strings (see GHC.Base.unpackCStringUtf8).+      | x <= 0x07ff -> do+          write 0 (0xC0 .|. ((x `shiftR` 6) .&. 0x1F))+          write 1 (0x80 .|. (x .&. 0x3F))+          return 2+      | x <= 0xffff -> do+          write 0 (0xE0 .|. (x `shiftR` 12) .&. 0x0F)+          write 1 (0x80 .|. (x `shiftR` 6) .&. 0x3F)+          write 2 (0x80 .|. (x .&. 0x3F))+          return 3+      | otherwise -> do+          write 0 (0xF0 .|. (x `shiftR` 18))+          write 1 (0x80 .|. ((x `shiftR` 12) .&. 0x3F))+          write 2 (0x80 .|. ((x `shiftR` 6) .&. 0x3F))+          write 3 (0x80 .|. (x .&. 0x3F))+          return 4+  where+    {-# INLINE write #-}+    write (I# off#) (W# c#) = ST $ \s ->+#if !MIN_VERSION_base(4,16,0)+      case write# off# (narrowWord8# c#) s of+#else+      case write# off# (wordToWord8# c#) s of+#endif+        s -> (# s, () #)++utf8EncodePtr :: Ptr Word8 -> String -> IO ()+utf8EncodePtr (Ptr a#) str = go a# str+  where go !_   []   = return ()+        go a# (c:cs) = do+#if !MIN_VERSION_base(4,16,0)+          -- writeWord8OffAddr# was taking a Word#+          I# off# <- stToIO $ utf8EncodeChar (\i w -> writeWord8OffAddr# a# i (extendWord8# w)) c+#else+          I# off# <- stToIO $ utf8EncodeChar (writeWord8OffAddr# a#) c+#endif+          go (a# `plusAddr#` off#) cs++utf8EncodeByteArray# :: String -> ByteArray#+utf8EncodeByteArray# str = runRW# $ \s ->+  case utf8EncodedLength str         of { I# len# ->+  case newByteArray# len# s          of { (# s, mba# #) ->+  case go mba# 0# str                of { ST f_go ->+  case f_go s                        of { (# s, () #) ->+  case unsafeFreezeByteArray# mba# s of { (# _, ba# #) ->+  ba# }}}}}+  where+    go _ _ [] = return ()+    go mba# i# (c:cs) = do+#if !MIN_VERSION_base(4,16,0)+      -- writeWord8Array# was taking a Word#+      I# off# <- utf8EncodeChar (\j# w -> writeWord8Array# mba# (i# +# j#) (extendWord8# w)) c+#else+      I# off# <- utf8EncodeChar (\j# -> writeWord8Array# mba# (i# +# j#)) c+#endif+      go mba# (i# +# off#) cs++utf8EncodedLength :: String -> Int+utf8EncodedLength str = go 0 str+  where go !n [] = n+        go n (c:cs)+          | ord c > 0 && ord c <= 0x007f = go (n+1) cs+          | ord c <= 0x07ff = go (n+2) cs+          | ord c <= 0xffff = go (n+3) cs+          | otherwise       = go (n+4) cs++#endif /* MIN_VERSION_base(4,18,0) */
ghc-boot.cabal view
@@ -5,7 +5,7 @@ -- ghc-boot.cabal.  name:           ghc-boot-version:        9.4.1+version:        9.6.0.20230302 license:        BSD-3-Clause license-file:   LICENSE category:       GHC@@ -28,7 +28,7 @@ extra-source-files: changelog.md  custom-setup-    setup-depends: base >= 3 && < 5, Cabal >= 1.6 && <3.9, directory, filepath+    setup-depends: base >= 3 && < 5, Cabal >= 1.6 && <3.10, directory, filepath  source-repository head     type:     git@@ -45,6 +45,7 @@             GHC.Data.ShortText             GHC.Data.SizedSeq             GHC.Utils.Encoding+            GHC.Utils.Encoding.UTF8             GHC.LanguageExtensions             GHC.Unit.Database             GHC.Serialized@@ -69,14 +70,14 @@             GHC.Version             GHC.Platform.Host -    build-depends: base       >= 4.7 && < 4.18,+    build-depends: base       >= 4.7 && < 4.19,                    binary     == 0.8.*,                    bytestring >= 0.10 && < 0.12,                    containers >= 0.5 && < 0.7,                    directory  >= 1.2 && < 1.4,                    filepath   >= 1.3 && < 1.5,                    deepseq    >= 1.4 && < 1.5,-                   ghc-boot-th == 9.4.1+                   ghc-boot-th == 9.6.0.20230302     if !os(windows)         build-depends:-                   unix       >= 2.7 && < 2.8+                   unix       >= 2.7 && < 2.9