os-string 2.0.8 → 2.0.9
raw patch · 9 files changed
+279/−54 lines, 9 filesdep +template-haskell-liftdep +template-haskell-quasiquoter
Dependencies added: template-haskell-lift, template-haskell-quasiquoter
Files
- System/OsString.hs +1/−0
- System/OsString/Common.hs +24/−5
- System/OsString/Data/ByteString/Short/Internal.hs +167/−1
- System/OsString/Data/ByteString/Short/Word16.hs +5/−2
- System/OsString/Encoding/Internal.hs +12/−3
- System/OsString/Internal.hs +18/−2
- System/OsString/Internal/Types.hs +36/−38
- changelog.md +5/−0
- os-string.cabal +11/−3
System/OsString.hs view
@@ -14,6 +14,7 @@ -- -- It captures the notion of syscall specific encoding (or the lack thereof) to avoid roundtrip issues -- and memory fragmentation by using unpinned byte arrays. Bytes are not touched or interpreted.+{-# LANGUAGE CPP #-} module System.OsString ( -- * String types
System/OsString/Common.hs view
@@ -166,26 +166,41 @@ ( SomeException, try, displayException ) import Control.DeepSeq ( force ) import Data.Bifunctor ( first )-import GHC.IO- ( evaluate, unsafePerformIO )+import Control.Exception ( evaluate )+import System.IO.Unsafe ( unsafePerformIO ) import qualified GHC.Foreign as GHC-import Language.Haskell.TH.Quote+#if __GLASGOW_HASKELL__ >= 914+import Language.Haskell.TH.Lift+ (Lift(..))+import Language.Haskell.TH.QuasiQuoter ( QuasiQuoter (..) )+#else import Language.Haskell.TH.Syntax- ( Lift (..), lift )+ (Lift(..))+import Language.Haskell.TH.Quote+ ( QuasiQuoter (..) )+#endif import GHC.IO.Encoding.Failure ( CodingFailureMode(..) ) #ifdef WINDOWS import System.OsString.Encoding+#if defined(__MHS__)+import GHC.IO.Encoding( TextEncoding, utf16le )+#else import System.IO ( TextEncoding, utf16le )+#endif import GHC.IO.Encoding.UTF16 ( mkUTF16le ) import qualified System.OsString.Data.ByteString.Short.Word16 as BSP #else import System.OsString.Encoding+#if defined(__MHS__)+import GHC.IO.Encoding( TextEncoding, utf8 )+#else import System.IO ( TextEncoding, utf8 )+#endif import GHC.IO.Encoding.UTF8 ( mkUTF8 ) import qualified System.OsString.Data.ByteString.Short as BSP #endif@@ -479,6 +494,7 @@ -- | QuasiQuote a 'PosixString'. This accepts Unicode characters -- and encodes as UTF-8 on unix. #endif+#if defined(MIN_VERSION_template_haskell) || defined(MIN_VERSION_template_haskell_quasi_quoter) pstr :: QuasiQuoter pstr = QuasiQuoter@@ -507,7 +523,10 @@ fail "illegal QuasiQuote (allowed as expression or pattern only, used as a declaration)" } #endif-+#else+pstr :: a+pstr = error "Systen.OsString.Common.pstr: no Template Haskell"+#endif /* !defined(__MHS__) */ -- | Unpack a platform string to a list of platform words. unpack :: PLATFORM_STRING -> [PLATFORM_WORD]
System/OsString/Data/ByteString/Short/Internal.hs view
@@ -6,8 +6,10 @@ {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE UnliftedFFITypes #-} +#if !defined(__MHS__) -- Required for WORDS_BIGENDIAN #include <ghcautoconf.h>+#endif -- | -- Module : System.OsString.Data.ByteString.Short.Internal@@ -44,9 +46,14 @@ #endif import Foreign.Marshal.Array (withArray0, peekArray0, newArray0, withArrayLen, peekArray) import GHC.Exts+#if defined(__MHS__)+import Data.Word+import Control.Monad.ST ( ST )+#else import GHC.Word import GHC.ST ( ST (ST) )+#endif import GHC.Stack ( HasCallStack ) import Prelude hiding ( length )@@ -66,6 +73,62 @@ word16ToChar :: Word16 -> Char word16ToChar = C.chr . fromIntegral +#if defined(__MHS__)+import Control.Monad(forM_)+import qualified Data.Array.Byte as B+import Foreign.Ptr(Ptr, plusPtr)+import Foreign.Storable (peekByteOff)+import System.IO.Unsafe(unsafePerformIO)++w8 :: Word16 -> Word8+w8 = fromIntegral++iw8 :: Int -> Word8+iw8 = fromIntegral++w16 :: Word8 -> Word16+w16 = fromIntegral++-- Use already existsing MHS types for the byte arrays+type BA = B.ByteArray+type MBA s = B.MutableByteArray s++create :: Int -> (forall s. MBA s -> ST s ()) -> BS.ShortByteString+create len fill =+ runST $ do+ mba <- B.newMutableByteArray len+ fill mba+ ba <- B.unsafeFreezeMutableByteArray mba+ return $ fromBA ba++asBA :: BS.ShortByteString -> BA+asBA = B.byteStringToByteArray . BS.fromShort++fromBA :: BA -> BS.ShortByteString+fromBA = BS.toShort . B.byteArrayToByteString++newPinnedByteArray :: Int -> ST s (MBA s)+newPinnedByteArray len = B.newMutableByteArray len++newByteArray :: Int -> ST s (MBA s)+newByteArray len = B.newMutableByteArray len++copyByteArray :: BA -> Int -> MBA s -> Int -> Int -> ST s ()+copyByteArray src src_off dst dst_off len =+ forM_ [0..len-1] $ \ i ->+ B.writeWord8 dst (dst_off + i) (B.indexWord8 src (src_off + i))++unsafeFreezeByteArray :: MBA s -> ST s BA+unsafeFreezeByteArray = B.unsafeFreezeMutableByteArray++copyAddrToByteArray :: Ptr a -> MBA RealWorld -> Int -> Int -> ST RealWorld ()+copyAddrToByteArray src dst dst_off len =+ forM_ [0..len-1] $ \ i -> do+ b <- unsafeIOToST $ peekByteOff src i+ B.writeWord8 dst (dst_off + i) b++#else /* defined(__MHS__) */+ create :: Int -> (forall s. MBA s -> ST s ()) -> ShortByteString create len fill = runST $ do@@ -109,9 +172,10 @@ copyAddrToByteArray (Ptr src#) (MBA# dst#) (I# dst_off#) (I# len#) = ST $ \s -> case copyAddrToByteArray# src# dst# dst_off# len# s of s' -> (# s', () #)+#endif /* defined(__MHS__) */ --- this is a copy-paste from bytestring+ -- this is a copy-paste from bytestring #if !MIN_VERSION_bytestring(0,10,9) ------------------------------------------------------------------------ -- Primop replacements@@ -284,11 +348,98 @@ go mba (i - 2) ws +#if defined(__MHS__) -- | Encode Word16 as little-endian. writeWord16Array :: MBA s -> Int -- ^ Word8 index (not Word16) -> Word16 -> ST s ()+writeWord16Array mba i w = do+ let (hi, lo) = w `quotRem` 256+ B.writeWord8 mba i (w8 lo)+ B.writeWord8 mba (i+1) (w8 hi)++indexWord8Array :: BA+ -> Int -- ^ Word8 index+ -> Word8+indexWord8Array = B.indexWord8++-- | Decode Word16 from little-endian.+indexWord16Array :: BA+ -> Int -- ^ Word8 index (not Word16)+ -> Word16+indexWord16Array ba i = w16 (B.indexWord8 ba (i+1)) * 256 + w16 (B.indexWord8 ba i)++setByteArray :: MBA s -> Int -> Int -> Int -> ST s ()+setByteArray dst off len c =+ forM_ [0..len-1] $ \ i -> B.writeWord8 dst (off + i) (iw8 c)++copyMutableByteArray :: MBA s -> Int -> MBA s -> Int -> Int -> ST s ()+copyMutableByteArray src src_off dst dst_off len =+ forM_ [0..len-1] $ \ i -> do+ b <- B.readWord8 src (src_off + i)+ B.writeWord8 dst (dst_off + i) b++createAndTrim :: Int -> (forall s. MBA s -> ST s (Int, a)) -> (ShortByteString, a)+createAndTrim l fill =+ runST $ do+ mba <- newByteArray l+ (l', res) <- fill mba+ if assert (l' <= l) $ l' >= l+ then do+ ba <- unsafeFreezeByteArray mba+ return (fromBA ba, res)+ else do+ mba2 <- newByteArray l'+ copyMutableByteArray mba 0 mba2 0 l'+ ba <- unsafeFreezeByteArray mba2+ return (fromBA ba, res)++createAndTrim' :: Int -> (forall s. MBA s -> ST s Int) -> ShortByteString+createAndTrim' l fill =+ runST $ do+ mba <- newByteArray l+ l' <- fill mba+ if assert (l' <= l) $ l' >= l+ then do+ ba <- unsafeFreezeByteArray mba+ return (fromBA ba)+ else do+ mba2 <- newByteArray l'+ copyMutableByteArray mba 0 mba2 0 l'+ ba <- unsafeFreezeByteArray mba2+ return (fromBA ba)+{-# INLINE createAndTrim' #-}++createAndTrim'' :: Int -> (forall s. MBA s -> MBA s -> ST s (Int, Int)) -> (ShortByteString, ShortByteString)+createAndTrim'' l fill =+ runST $ do+ mba1 <- newByteArray l+ mba2 <- newByteArray l+ (l1, l2) <- fill mba1 mba2+ sbs1 <- freeze' l1 mba1+ sbs2 <- freeze' l2 mba2+ pure (sbs1, sbs2)+ where+ freeze' :: Int -> MBA s -> ST s ShortByteString+ freeze' l' mba =+ if assert (l' <= l) $ l' >= l+ then do+ ba <- unsafeFreezeByteArray mba+ return (fromBA ba)+ else do+ mba2 <- newByteArray l'+ copyMutableByteArray mba 0 mba2 0 l'+ ba <- unsafeFreezeByteArray mba2+ return (fromBA ba)++#else /* defined(__MHS__) */++-- | Encode Word16 as little-endian.+writeWord16Array :: MBA s+ -> Int -- ^ Word8 index (not Word16)+ -> Word16+ -> ST s () writeWord16Array (MBA# mba#) (I# i#) (W16# w#) = ST $ \s -> case writeWord8ArrayAsWord16# mba# i# (word16ToLE# w#) s of s' -> (# s', () #)@@ -390,6 +541,7 @@ BA# ba# <- unsafeFreezeByteArray mba2 return (SBS ba#) {-# INLINE createAndTrim'' #-}+#endif /* defined(__MHS__) */ -- Returns the index of the first match or the length of the whole -- bytestring if nothing matched.@@ -419,8 +571,13 @@ assertEven :: ShortByteString -> ShortByteString+#if defined(__MHS__)+assertEven sbs+ | even (BS.length sbs) = sbs+#else assertEven sbs@(SBS barr#) | even (I# (sizeofByteArray# barr#)) = sbs+#endif | otherwise = error ("Uneven number of bytes: " <> show (BS.length sbs) <> ". This is not a Word16 bytestream.") @@ -440,6 +597,14 @@ -> Int -- ^ offset for array 2 -> Int -- ^ length to compare -> Int -- ^ like memcmp+#if defined(__MHS__)+compareByteArraysOff ba1 ba1off ba2 ba2off len = unsafePerformIO $+ B.withByteArrayPtr ba1 $ \ ptr1 ->+ B.withByteArrayPtr ba2 $ \ ptr2 ->+ c_memcmp (plusPtr ptr1 ba1off) (plusPtr ptr2 ba2off) len+foreign import ccall "string.h memcmp" c_memcmp :: Ptr Word8 -> Ptr Word8 -> Int -> IO Int++#else /* defined(__MHS__) */ #if MIN_VERSION_base(4,11,0) compareByteArraysOff (BA# ba1#) (I# ba1off#) (BA# ba2#) (I# ba2off#) (I# len#) = I# (compareByteArrays# ba1# ba1off# ba2# ba2off# len#)@@ -458,4 +623,5 @@ foreign import ccall unsafe "static sbs_memcmp_off" c_memcmp_ByteArray :: ByteArray# -> Int -> ByteArray# -> Int -> CSize -> IO CInt #endif+#endif /* defined(__MHS__) */
System/OsString/Data/ByteString/Short/Word16.hs view
@@ -164,7 +164,9 @@ , head , init , last+ , length , map+ , null , replicate , span , splitAt@@ -173,7 +175,7 @@ , takeWhile ) import qualified Data.Foldable as Foldable-import GHC.ST ( ST )+import Control.Monad.ST ( ST ) import GHC.Stack ( HasCallStack ) import GHC.Exts ( inline ) @@ -379,6 +381,7 @@ -- can't use setByteArray here, because we write UTF-16LE | otherwise = create (w * 2) (`go` 0) where+ go :: forall s . MBA s -> Int -> ST s () go mba ix | ix < 0 || ix >= w * 2 = pure () | otherwise = writeWord16Array mba ix c >> go mba (ix + 2)@@ -589,7 +592,7 @@ -- > let (x, y) = span (not . isSpace) (reverse ps) in (reverse y, reverse x) -- spanEnd :: (Word16 -> Bool) -> ShortByteString -> (ShortByteString, ShortByteString)-spanEnd p = \(assertEven -> ps) -> splitAt (findFromEndUntil (not.p) ps) ps+spanEnd p = \(assertEven -> ps) -> splitAt (findFromEndUntil (not . p) ps) ps -- | /O(n)/ 'splitAt' @n xs@ is equivalent to @('take' n xs, 'drop' n xs)@. --
System/OsString/Encoding/Internal.hs view
@@ -2,6 +2,7 @@ , BangPatterns , TypeApplications , MultiWayIf+ , CPP #-} {-# OPTIONS_GHC -funbox-strict-fields #-} @@ -12,9 +13,12 @@ import qualified System.OsString.Data.ByteString.Short.Word16 as BS16 import System.OsString.Internal.Exception +#if !defined(__MHS__) import GHC.Base import GHC.Real import GHC.Num+import GHC.Show (Show (show))+#endif -- import GHC.IO import GHC.IO.Buffer import GHC.IO.Encoding.Failure@@ -23,17 +27,22 @@ import Control.Exception (SomeException, try, Exception (displayException), evaluate) import qualified GHC.Foreign as GHC import Data.Either (Either)-import GHC.IO (unsafePerformIO)+import System.IO.Unsafe (unsafePerformIO) import Control.DeepSeq (force, NFData (rnf)) import Data.Bifunctor (first) import Data.Data (Typeable)-import GHC.Show (Show (show)) import Numeric (showHex) import Foreign.C (CStringLen) import Data.Char (chr) import Foreign import GHC.IO.Encoding (getFileSystemEncoding, getLocaleEncoding) +#if defined(__MHS__)+import Data.Char(ord)+unsafeChr :: Int -> Char+unsafeChr = chr+#endif+ -- ----------------------------------------------------------------------------- -- UCS-2 LE --@@ -171,7 +180,7 @@ c3 <- readWord8Buf iraw (ir+3) let x2 = fromIntegral c3 `shiftL` 8 + fromIntegral c2 if | 0xd800 <= x1 && x1 <= 0xdbff- , 0xdc00 <= x2 && x2 <= 0xdfff -> do+ ,0xdc00 <= x2 && x2 <= 0xdfff -> do ow' <- writeCharBuf oraw ow (unsafeChr ((x1 - 0xd800)*0x400 + (x2 - 0xdc00) + 0x10000)) loop (ir+4) ow' | otherwise -> do
System/OsString/Internal.hs view
@@ -17,12 +17,23 @@ import Data.ByteString.Short ( ShortByteString ) import Data.Char-import Language.Haskell.TH.Quote+#if __GLASGOW_HASKELL__ >= 914+import Language.Haskell.TH.Lift+ (Lift(..), lift)+import Language.Haskell.TH.QuasiQuoter ( QuasiQuoter (..) )+#else import Language.Haskell.TH.Syntax- ( Lift (..), lift )+ (Lift(..), lift)+import Language.Haskell.TH.Quote+ ( QuasiQuoter (..) )+#endif+#if defined(__MHS__)+import GHC.IO.Encoding ( TextEncoding )+#else import System.IO ( TextEncoding )+#endif import System.OsString.Encoding ( EncodingException(..) ) import GHC.IO.Encoding.Failure ( CodingFailureMode(..) )@@ -186,6 +197,7 @@ -- | QuasiQuote an 'OsString'. This accepts Unicode characters -- and encodes as UTF-8 on unix and UTF-16 on windows. -- If used as pattern, requires turning on the @ViewPatterns@ extension.+#if defined(MIN_VERSION_template_haskell) || defined(MIN_VERSION_template_haskell_quasi_quoter) osstr :: QuasiQuoter osstr = QuasiQuoter@@ -214,6 +226,10 @@ fail "illegal QuasiQuote (allowed as expression or pattern only, used as a declaration)" } #endif+#else+osstr :: a+osstr = error "Systen.OsString.Internal.osstr: no Template Haskell"+#endif /* defined(MIN_VERSION_template_haskell) || defined(MIN_VERSION_template_haskell_quasi_quoter) */ -- | Unpack an 'OsString' to a list of 'OsChar'.
System/OsString/Internal/Types.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-}+{-# LANGUAGE DeriveLift #-} {-# LANGUAGE PackageImports #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TemplateHaskellQuotes #-}@@ -36,8 +37,11 @@ import Data.Data import Data.Type.Coercion (Coercion(..), coerceWith) import Data.Word-import Language.Haskell.TH.Syntax- ( Lift (..), lift )+#if __GLASGOW_HASKELL__ >= 914+import Language.Haskell.TH.Lift (Lift)+#else+import Language.Haskell.TH.Syntax (Lift)+#endif #if !MIN_VERSION_base(4,11,0) import Data.Semigroup #endif@@ -46,7 +50,6 @@ import System.OsString.Encoding.Internal import qualified System.OsString.Data.ByteString.Short as BS import qualified System.OsString.Data.ByteString.Short.Word16 as BS16-import qualified Language.Haskell.TH.Syntax as TH -- Using unpinned bytearrays to avoid Heap fragmentation and -- which are reasonably cheap to pass to FFI calls@@ -58,13 +61,20 @@ -- | Commonly used windows string as wide character bytes. newtype WindowsString = WindowsString { getWindowsString :: BS.ShortByteString }- deriving (Eq, Ord, Semigroup, Monoid, Typeable, Generic, NFData)+ deriving (Eq, Ord, Semigroup, Monoid, Typeable, Generic, NFData, Lift) -- | Decodes as UCS-2. instance Show WindowsString where -- cWcharsToChars_UCS2 is total show = show . cWcharsToChars_UCS2 . BS16.unpack . getWindowsString +#if defined(__MHS__)+-- No record pattern synonyms in MicroHs+pattern WS :: BS.ShortByteString -> WindowsString+pattern WS s = WindowsString s+unWS :: WindowsString -> BS.ShortByteString+unWS (WS s) = s+#else -- | Just a short bidirectional synonym for 'WindowsString' constructor. pattern WS :: BS.ShortByteString -> WindowsString pattern WS { unWS } <- WindowsString unWS where@@ -72,25 +82,23 @@ #if __GLASGOW_HASKELL__ >= 802 {-# COMPLETE WS #-} #endif---instance Lift WindowsString where- lift (WindowsString bs) = TH.AppE (TH.ConE 'WindowsString) <$> (lift bs)-#if MIN_VERSION_template_haskell(2,17,0)- liftTyped = TH.unsafeCodeCoerce . TH.lift-#elif MIN_VERSION_template_haskell(2,16,0)- liftTyped = TH.unsafeTExpCoerce . TH.lift-#endif+#endif /* defined(__MHS__) */ -- | Commonly used Posix string as uninterpreted @char[]@ -- array. newtype PosixString = PosixString { getPosixString :: BS.ShortByteString }- deriving (Eq, Ord, Semigroup, Monoid, Typeable, Generic, NFData)+ deriving (Eq, Ord, Semigroup, Monoid, Typeable, Generic, NFData, Lift) -- | Prints the raw bytes without decoding. instance Show PosixString where show (PosixString ps) = show ps +#if defined(__MHS__)+pattern PS :: BS.ShortByteString -> PosixString+pattern PS a = PosixString a+unPS :: PosixString -> BS.ShortByteString+unPS (PS a) = a+#else -- | Just a short bidirectional synonym for 'PosixString' constructor. pattern PS :: BS.ShortByteString -> PosixString pattern PS { unPS } <- PosixString unPS where@@ -98,15 +106,7 @@ #if __GLASGOW_HASKELL__ >= 802 {-# COMPLETE PS #-} #endif--instance Lift PosixString where- lift (PosixString bs) = TH.AppE (TH.ConE 'PosixString) <$> (lift bs)-#if MIN_VERSION_template_haskell(2,17,0)- liftTyped = TH.unsafeCodeCoerce . TH.lift-#elif MIN_VERSION_template_haskell(2,16,0)- liftTyped = TH.unsafeTExpCoerce . TH.lift-#endif-+#endif /* defined(__MHS__) */ #if defined(mingw32_HOST_OS) || defined(__MINGW32__) type PlatformString = WindowsString@@ -126,6 +126,17 @@ instance Show PosixChar where show (PosixChar pc) = show pc +#if defined(__MHS__)+pattern WW :: Word16 -> WindowsChar+pattern WW a = WindowsChar a+unWW :: WindowsChar -> Word16+unWW (WW a) = a++pattern PW :: Word8 -> PosixChar+pattern PW a = PosixChar a+unPW :: PosixChar -> Word8+unPW (PW a) = a+#else -- | Just a short bidirectional synonym for 'WindowsChar' constructor. pattern WW :: Word16 -> WindowsChar pattern WW { unWW } <- WindowsChar unWW where@@ -141,6 +152,7 @@ #if __GLASGOW_HASKELL__ >= 802 {-# COMPLETE PW #-} #endif+#endif /* defined(__MHS__) */ #if defined(mingw32_HOST_OS) || defined(__MINGW32__) type PlatformChar = WindowsChar@@ -159,7 +171,7 @@ -- dealing with the internals isn't generally recommended, but supported -- in case you need to write platform specific code. newtype OsString = OsString { getOsString :: PlatformString }- deriving (Typeable, Generic, NFData)+ deriving (Typeable, Generic, NFData, Lift) -- | On windows, decodes as UCS-2. On unix prints the raw bytes without decoding. instance Show OsString where@@ -188,20 +200,6 @@ instance Semigroup OsString where (<>) = coerce (mappend :: BS.ShortByteString -> BS.ShortByteString -> BS.ShortByteString) #endif---instance Lift OsString where- lift xs = case coercionToPlatformTypes of- Left (_, co) ->- TH.AppE (TH.ConE 'OsString) <$> (lift $ coerceWith co xs)- Right (_, co) -> do- TH.AppE (TH.ConE 'OsString) <$> (lift $ coerceWith co xs)-#if MIN_VERSION_template_haskell(2,17,0)- liftTyped = TH.unsafeCodeCoerce . TH.lift-#elif MIN_VERSION_template_haskell(2,16,0)- liftTyped = TH.unsafeTExpCoerce . TH.lift-#endif- -- | Newtype representing a code unit. --
changelog.md view
@@ -1,5 +1,10 @@ # Changelog for [`os-string` package](http://hackage.haskell.org/package/os-string) +## 2.0.9 *Jan 2026*++* support MicroHS wrt [#35](https://github.com/haskell/os-string/pull/35)+* Switch from template-haskell to template-haskell-quasiquoter and -lift wrt [#36](https://github.com/haskell/os-string/pull/36)+ ## 2.0.8 *Aug 2025* * Add safe conversions from ShortByteString [#34](https://github.com/haskell/os-string/pull/34)
os-string.cabal view
@@ -1,13 +1,13 @@ cabal-version: 2.2 name: os-string-version: 2.0.8+version: 2.0.9 -- NOTE: Don't forget to update ./changelog.md license: BSD-3-Clause license-file: LICENSE author: Julian Ospald <hasufell@posteo.de> maintainer: Julian Ospald <hasufell@posteo.de>-copyright: Julain Ospald 2021-2023+copyright: Julian Ospald 2021-2023 bug-reports: https://github.com/haskell/os-string/issues homepage: https://github.com/haskell/os-string/blob/master/README.md@@ -68,7 +68,15 @@ , bytestring >=0.11.3.0 , deepseq , exceptions- , template-haskell+ -- template-haskell-lift was added as a boot library in GHC-9.14+ -- once we no longer wish to backport releases to older major releases of GHC,+ -- this conditional can be dropped+ if impl(ghc < 9.14)+ build-depends: template-haskell+ elif impl(ghc)+ build-depends:+ , template-haskell-lift >=0.1 && <0.2+ , template-haskell-quasiquoter >=0.1 && <0.2 ghc-options: -Wall