summaryrefslogtreecommitdiff
path: root/compiler/utils
diff options
context:
space:
mode:
authorSylvain Henry <sylvain@haskus.fr>2020-04-20 16:54:38 +0200
committerMarge Bot <ben+marge-bot@smart-cactus.org>2020-04-26 13:55:14 -0400
commitaf332442123878c1b61d236dce46418efcbe8750 (patch)
treeec4b332843cdd4fedb4aa60b11b7b8dba82a0764 /compiler/utils
parentb0fbfc7582fb81314dc28a056536737fb5eeaa6e (diff)
downloadhaskell-af332442123878c1b61d236dce46418efcbe8750.tar.gz
Modules: Utils and Data (#13009)
Update Haddock submodule Metric Increase: haddock.compiler
Diffstat (limited to 'compiler/utils')
-rw-r--r--compiler/utils/AsmUtils.hs21
-rw-r--r--compiler/utils/Bag.hs335
-rw-r--r--compiler/utils/Binary.hs1457
-rw-r--r--compiler/utils/BooleanFormula.hs262
-rw-r--r--compiler/utils/BufWrite.hs145
-rw-r--r--compiler/utils/Digraph.hs524
-rw-r--r--compiler/utils/Encoding.hs450
-rw-r--r--compiler/utils/EnumSet.hs35
-rw-r--r--compiler/utils/Exception.hs83
-rw-r--r--compiler/utils/FV.hs200
-rw-r--r--compiler/utils/FastFunctions.hs21
-rw-r--r--compiler/utils/FastMutInt.hs61
-rw-r--r--compiler/utils/FastString.hs693
-rw-r--r--compiler/utils/FastStringEnv.hs100
-rw-r--r--compiler/utils/Fingerprint.hs47
-rw-r--r--compiler/utils/FiniteMap.hs31
-rw-r--r--compiler/utils/GhcPrelude.hs33
-rw-r--r--compiler/utils/GraphBase.hs107
-rw-r--r--compiler/utils/GraphColor.hs375
-rw-r--r--compiler/utils/GraphOps.hs682
-rw-r--r--compiler/utils/GraphPpr.hs173
-rw-r--r--compiler/utils/IOEnv.hs219
-rw-r--r--compiler/utils/Json.hs56
-rw-r--r--compiler/utils/ListSetOps.hs180
-rw-r--r--compiler/utils/Maybes.hs114
-rw-r--r--compiler/utils/MonadUtils.hs215
-rw-r--r--compiler/utils/OrdList.hs194
-rw-r--r--compiler/utils/Outputable.hs1304
-rw-r--r--compiler/utils/Outputable.hs-boot14
-rw-r--r--compiler/utils/Pair.hs60
-rw-r--r--compiler/utils/Panic.hs259
-rw-r--r--compiler/utils/PlainPanic.hs138
-rw-r--r--compiler/utils/PprColour.hs101
-rw-r--r--compiler/utils/Pretty.hs1105
-rw-r--r--compiler/utils/State.hs46
-rw-r--r--compiler/utils/Stream.hs135
-rw-r--r--compiler/utils/StringBuffer.hs334
-rw-r--r--compiler/utils/TrieMap.hs406
-rw-r--r--compiler/utils/UnVarGraph.hs145
-rw-r--r--compiler/utils/Util.hs1465
40 files changed, 0 insertions, 12325 deletions
diff --git a/compiler/utils/AsmUtils.hs b/compiler/utils/AsmUtils.hs
deleted file mode 100644
index d3393d71e2..0000000000
--- a/compiler/utils/AsmUtils.hs
+++ /dev/null
@@ -1,21 +0,0 @@
--- | Various utilities used in generating assembler.
---
--- These are used not only by the native code generator, but also by the
--- GHC.Driver.Pipeline
-module AsmUtils
- ( sectionType
- ) where
-
-import GhcPrelude
-
-import GHC.Platform
-import Outputable
-
--- | Generate a section type (e.g. @\@progbits@). See #13937.
-sectionType :: Platform -- ^ Target platform
- -> String -- ^ section type
- -> SDoc -- ^ pretty assembler fragment
-sectionType platform ty =
- case platformArch platform of
- ArchARM{} -> char '%' <> text ty
- _ -> char '@' <> text ty
diff --git a/compiler/utils/Bag.hs b/compiler/utils/Bag.hs
deleted file mode 100644
index e1eea48000..0000000000
--- a/compiler/utils/Bag.hs
+++ /dev/null
@@ -1,335 +0,0 @@
-{-
-(c) The University of Glasgow 2006
-(c) The GRASP/AQUA Project, Glasgow University, 1992-1998
-
-
-Bag: an unordered collection with duplicates
--}
-
-{-# LANGUAGE ScopedTypeVariables, CPP, DeriveFunctor #-}
-
-module Bag (
- Bag, -- abstract type
-
- emptyBag, unitBag, unionBags, unionManyBags,
- mapBag,
- elemBag, lengthBag,
- filterBag, partitionBag, partitionBagWith,
- concatBag, catBagMaybes, foldBag,
- isEmptyBag, isSingletonBag, consBag, snocBag, anyBag, allBag,
- listToBag, bagToList, mapAccumBagL,
- concatMapBag, concatMapBagPair, mapMaybeBag,
- mapBagM, mapBagM_,
- flatMapBagM, flatMapBagPairM,
- mapAndUnzipBagM, mapAccumBagLM,
- anyBagM, filterBagM
- ) where
-
-import GhcPrelude
-
-import Outputable
-import Util
-
-import MonadUtils
-import Control.Monad
-import Data.Data
-import Data.Maybe( mapMaybe )
-import Data.List ( partition, mapAccumL )
-import qualified Data.Foldable as Foldable
-
-infixr 3 `consBag`
-infixl 3 `snocBag`
-
-data Bag a
- = EmptyBag
- | UnitBag a
- | TwoBags (Bag a) (Bag a) -- INVARIANT: neither branch is empty
- | ListBag [a] -- INVARIANT: the list is non-empty
- deriving (Functor)
-
-emptyBag :: Bag a
-emptyBag = EmptyBag
-
-unitBag :: a -> Bag a
-unitBag = UnitBag
-
-lengthBag :: Bag a -> Int
-lengthBag EmptyBag = 0
-lengthBag (UnitBag {}) = 1
-lengthBag (TwoBags b1 b2) = lengthBag b1 + lengthBag b2
-lengthBag (ListBag xs) = length xs
-
-elemBag :: Eq a => a -> Bag a -> Bool
-elemBag _ EmptyBag = False
-elemBag x (UnitBag y) = x == y
-elemBag x (TwoBags b1 b2) = x `elemBag` b1 || x `elemBag` b2
-elemBag x (ListBag ys) = any (x ==) ys
-
-unionManyBags :: [Bag a] -> Bag a
-unionManyBags xs = foldr unionBags EmptyBag xs
-
--- This one is a bit stricter! The bag will get completely evaluated.
-
-unionBags :: Bag a -> Bag a -> Bag a
-unionBags EmptyBag b = b
-unionBags b EmptyBag = b
-unionBags b1 b2 = TwoBags b1 b2
-
-consBag :: a -> Bag a -> Bag a
-snocBag :: Bag a -> a -> Bag a
-
-consBag elt bag = (unitBag elt) `unionBags` bag
-snocBag bag elt = bag `unionBags` (unitBag elt)
-
-isEmptyBag :: Bag a -> Bool
-isEmptyBag EmptyBag = True
-isEmptyBag _ = False -- NB invariants
-
-isSingletonBag :: Bag a -> Bool
-isSingletonBag EmptyBag = False
-isSingletonBag (UnitBag _) = True
-isSingletonBag (TwoBags _ _) = False -- Neither is empty
-isSingletonBag (ListBag xs) = isSingleton xs
-
-filterBag :: (a -> Bool) -> Bag a -> Bag a
-filterBag _ EmptyBag = EmptyBag
-filterBag pred b@(UnitBag val) = if pred val then b else EmptyBag
-filterBag pred (TwoBags b1 b2) = sat1 `unionBags` sat2
- where sat1 = filterBag pred b1
- sat2 = filterBag pred b2
-filterBag pred (ListBag vs) = listToBag (filter pred vs)
-
-filterBagM :: Monad m => (a -> m Bool) -> Bag a -> m (Bag a)
-filterBagM _ EmptyBag = return EmptyBag
-filterBagM pred b@(UnitBag val) = do
- flag <- pred val
- if flag then return b
- else return EmptyBag
-filterBagM pred (TwoBags b1 b2) = do
- sat1 <- filterBagM pred b1
- sat2 <- filterBagM pred b2
- return (sat1 `unionBags` sat2)
-filterBagM pred (ListBag vs) = do
- sat <- filterM pred vs
- return (listToBag sat)
-
-allBag :: (a -> Bool) -> Bag a -> Bool
-allBag _ EmptyBag = True
-allBag p (UnitBag v) = p v
-allBag p (TwoBags b1 b2) = allBag p b1 && allBag p b2
-allBag p (ListBag xs) = all p xs
-
-anyBag :: (a -> Bool) -> Bag a -> Bool
-anyBag _ EmptyBag = False
-anyBag p (UnitBag v) = p v
-anyBag p (TwoBags b1 b2) = anyBag p b1 || anyBag p b2
-anyBag p (ListBag xs) = any p xs
-
-anyBagM :: Monad m => (a -> m Bool) -> Bag a -> m Bool
-anyBagM _ EmptyBag = return False
-anyBagM p (UnitBag v) = p v
-anyBagM p (TwoBags b1 b2) = do flag <- anyBagM p b1
- if flag then return True
- else anyBagM p b2
-anyBagM p (ListBag xs) = anyM p xs
-
-concatBag :: Bag (Bag a) -> Bag a
-concatBag bss = foldr add emptyBag bss
- where
- add bs rs = bs `unionBags` rs
-
-catBagMaybes :: Bag (Maybe a) -> Bag a
-catBagMaybes bs = foldr add emptyBag bs
- where
- add Nothing rs = rs
- add (Just x) rs = x `consBag` rs
-
-partitionBag :: (a -> Bool) -> Bag a -> (Bag a {- Satisfy predictate -},
- Bag a {- Don't -})
-partitionBag _ EmptyBag = (EmptyBag, EmptyBag)
-partitionBag pred b@(UnitBag val)
- = if pred val then (b, EmptyBag) else (EmptyBag, b)
-partitionBag pred (TwoBags b1 b2)
- = (sat1 `unionBags` sat2, fail1 `unionBags` fail2)
- where (sat1, fail1) = partitionBag pred b1
- (sat2, fail2) = partitionBag pred b2
-partitionBag pred (ListBag vs) = (listToBag sats, listToBag fails)
- where (sats, fails) = partition pred vs
-
-
-partitionBagWith :: (a -> Either b c) -> Bag a
- -> (Bag b {- Left -},
- Bag c {- Right -})
-partitionBagWith _ EmptyBag = (EmptyBag, EmptyBag)
-partitionBagWith pred (UnitBag val)
- = case pred val of
- Left a -> (UnitBag a, EmptyBag)
- Right b -> (EmptyBag, UnitBag b)
-partitionBagWith pred (TwoBags b1 b2)
- = (sat1 `unionBags` sat2, fail1 `unionBags` fail2)
- where (sat1, fail1) = partitionBagWith pred b1
- (sat2, fail2) = partitionBagWith pred b2
-partitionBagWith pred (ListBag vs) = (listToBag sats, listToBag fails)
- where (sats, fails) = partitionWith pred vs
-
-foldBag :: (r -> r -> r) -- Replace TwoBags with this; should be associative
- -> (a -> r) -- Replace UnitBag with this
- -> r -- Replace EmptyBag with this
- -> Bag a
- -> r
-
-{- Standard definition
-foldBag t u e EmptyBag = e
-foldBag t u e (UnitBag x) = u x
-foldBag t u e (TwoBags b1 b2) = (foldBag t u e b1) `t` (foldBag t u e b2)
-foldBag t u e (ListBag xs) = foldr (t.u) e xs
--}
-
--- More tail-recursive definition, exploiting associativity of "t"
-foldBag _ _ e EmptyBag = e
-foldBag t u e (UnitBag x) = u x `t` e
-foldBag t u e (TwoBags b1 b2) = foldBag t u (foldBag t u e b2) b1
-foldBag t u e (ListBag xs) = foldr (t.u) e xs
-
-mapBag :: (a -> b) -> Bag a -> Bag b
-mapBag = fmap
-
-concatMapBag :: (a -> Bag b) -> Bag a -> Bag b
-concatMapBag _ EmptyBag = EmptyBag
-concatMapBag f (UnitBag x) = f x
-concatMapBag f (TwoBags b1 b2) = unionBags (concatMapBag f b1) (concatMapBag f b2)
-concatMapBag f (ListBag xs) = foldr (unionBags . f) emptyBag xs
-
-concatMapBagPair :: (a -> (Bag b, Bag c)) -> Bag a -> (Bag b, Bag c)
-concatMapBagPair _ EmptyBag = (EmptyBag, EmptyBag)
-concatMapBagPair f (UnitBag x) = f x
-concatMapBagPair f (TwoBags b1 b2) = (unionBags r1 r2, unionBags s1 s2)
- where
- (r1, s1) = concatMapBagPair f b1
- (r2, s2) = concatMapBagPair f b2
-concatMapBagPair f (ListBag xs) = foldr go (emptyBag, emptyBag) xs
- where
- go a (s1, s2) = (unionBags r1 s1, unionBags r2 s2)
- where
- (r1, r2) = f a
-
-mapMaybeBag :: (a -> Maybe b) -> Bag a -> Bag b
-mapMaybeBag _ EmptyBag = EmptyBag
-mapMaybeBag f (UnitBag x) = case f x of
- Nothing -> EmptyBag
- Just y -> UnitBag y
-mapMaybeBag f (TwoBags b1 b2) = unionBags (mapMaybeBag f b1) (mapMaybeBag f b2)
-mapMaybeBag f (ListBag xs) = ListBag (mapMaybe f xs)
-
-mapBagM :: Monad m => (a -> m b) -> Bag a -> m (Bag b)
-mapBagM _ EmptyBag = return EmptyBag
-mapBagM f (UnitBag x) = do r <- f x
- return (UnitBag r)
-mapBagM f (TwoBags b1 b2) = do r1 <- mapBagM f b1
- r2 <- mapBagM f b2
- return (TwoBags r1 r2)
-mapBagM f (ListBag xs) = do rs <- mapM f xs
- return (ListBag rs)
-
-mapBagM_ :: Monad m => (a -> m b) -> Bag a -> m ()
-mapBagM_ _ EmptyBag = return ()
-mapBagM_ f (UnitBag x) = f x >> return ()
-mapBagM_ f (TwoBags b1 b2) = mapBagM_ f b1 >> mapBagM_ f b2
-mapBagM_ f (ListBag xs) = mapM_ f xs
-
-flatMapBagM :: Monad m => (a -> m (Bag b)) -> Bag a -> m (Bag b)
-flatMapBagM _ EmptyBag = return EmptyBag
-flatMapBagM f (UnitBag x) = f x
-flatMapBagM f (TwoBags b1 b2) = do r1 <- flatMapBagM f b1
- r2 <- flatMapBagM f b2
- return (r1 `unionBags` r2)
-flatMapBagM f (ListBag xs) = foldrM k EmptyBag xs
- where
- k x b2 = do { b1 <- f x; return (b1 `unionBags` b2) }
-
-flatMapBagPairM :: Monad m => (a -> m (Bag b, Bag c)) -> Bag a -> m (Bag b, Bag c)
-flatMapBagPairM _ EmptyBag = return (EmptyBag, EmptyBag)
-flatMapBagPairM f (UnitBag x) = f x
-flatMapBagPairM f (TwoBags b1 b2) = do (r1,s1) <- flatMapBagPairM f b1
- (r2,s2) <- flatMapBagPairM f b2
- return (r1 `unionBags` r2, s1 `unionBags` s2)
-flatMapBagPairM f (ListBag xs) = foldrM k (EmptyBag, EmptyBag) xs
- where
- k x (r2,s2) = do { (r1,s1) <- f x
- ; return (r1 `unionBags` r2, s1 `unionBags` s2) }
-
-mapAndUnzipBagM :: Monad m => (a -> m (b,c)) -> Bag a -> m (Bag b, Bag c)
-mapAndUnzipBagM _ EmptyBag = return (EmptyBag, EmptyBag)
-mapAndUnzipBagM f (UnitBag x) = do (r,s) <- f x
- return (UnitBag r, UnitBag s)
-mapAndUnzipBagM f (TwoBags b1 b2) = do (r1,s1) <- mapAndUnzipBagM f b1
- (r2,s2) <- mapAndUnzipBagM f b2
- return (TwoBags r1 r2, TwoBags s1 s2)
-mapAndUnzipBagM f (ListBag xs) = do ts <- mapM f xs
- let (rs,ss) = unzip ts
- return (ListBag rs, ListBag ss)
-
-mapAccumBagL ::(acc -> x -> (acc, y)) -- ^ combining function
- -> acc -- ^ initial state
- -> Bag x -- ^ inputs
- -> (acc, Bag y) -- ^ final state, outputs
-mapAccumBagL _ s EmptyBag = (s, EmptyBag)
-mapAccumBagL f s (UnitBag x) = let (s1, x1) = f s x in (s1, UnitBag x1)
-mapAccumBagL f s (TwoBags b1 b2) = let (s1, b1') = mapAccumBagL f s b1
- (s2, b2') = mapAccumBagL f s1 b2
- in (s2, TwoBags b1' b2')
-mapAccumBagL f s (ListBag xs) = let (s', xs') = mapAccumL f s xs
- in (s', ListBag xs')
-
-mapAccumBagLM :: Monad m
- => (acc -> x -> m (acc, y)) -- ^ combining function
- -> acc -- ^ initial state
- -> Bag x -- ^ inputs
- -> m (acc, Bag y) -- ^ final state, outputs
-mapAccumBagLM _ s EmptyBag = return (s, EmptyBag)
-mapAccumBagLM f s (UnitBag x) = do { (s1, x1) <- f s x; return (s1, UnitBag x1) }
-mapAccumBagLM f s (TwoBags b1 b2) = do { (s1, b1') <- mapAccumBagLM f s b1
- ; (s2, b2') <- mapAccumBagLM f s1 b2
- ; return (s2, TwoBags b1' b2') }
-mapAccumBagLM f s (ListBag xs) = do { (s', xs') <- mapAccumLM f s xs
- ; return (s', ListBag xs') }
-
-listToBag :: [a] -> Bag a
-listToBag [] = EmptyBag
-listToBag [x] = UnitBag x
-listToBag vs = ListBag vs
-
-bagToList :: Bag a -> [a]
-bagToList b = foldr (:) [] b
-
-instance (Outputable a) => Outputable (Bag a) where
- ppr bag = braces (pprWithCommas ppr (bagToList bag))
-
-instance Data a => Data (Bag a) where
- gfoldl k z b = z listToBag `k` bagToList b -- traverse abstract type abstractly
- toConstr _ = abstractConstr $ "Bag("++show (typeOf (undefined::a))++")"
- gunfold _ _ = error "gunfold"
- dataTypeOf _ = mkNoRepType "Bag"
- dataCast1 x = gcast1 x
-
-instance Foldable.Foldable Bag where
- foldr _ z EmptyBag = z
- foldr k z (UnitBag x) = k x z
- foldr k z (TwoBags b1 b2) = foldr k (foldr k z b2) b1
- foldr k z (ListBag xs) = foldr k z xs
-
- foldl _ z EmptyBag = z
- foldl k z (UnitBag x) = k z x
- foldl k z (TwoBags b1 b2) = foldl k (foldl k z b1) b2
- foldl k z (ListBag xs) = foldl k z xs
-
- foldl' _ z EmptyBag = z
- foldl' k z (UnitBag x) = k z x
- foldl' k z (TwoBags b1 b2) = let r1 = foldl' k z b1 in seq r1 $ foldl' k r1 b2
- foldl' k z (ListBag xs) = foldl' k z xs
-
-instance Traversable Bag where
- traverse _ EmptyBag = pure EmptyBag
- traverse f (UnitBag x) = UnitBag <$> f x
- traverse f (TwoBags b1 b2) = TwoBags <$> traverse f b1 <*> traverse f b2
- traverse f (ListBag xs) = ListBag <$> traverse f xs
diff --git a/compiler/utils/Binary.hs b/compiler/utils/Binary.hs
deleted file mode 100644
index 529519df1d..0000000000
--- a/compiler/utils/Binary.hs
+++ /dev/null
@@ -1,1457 +0,0 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE PolyKinds #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE GADTs #-}
-{-# LANGUAGE MultiWayIf #-}
-{-# LANGUAGE BangPatterns #-}
-
-{-# OPTIONS_GHC -O2 -funbox-strict-fields #-}
--- We always optimise this, otherwise performance of a non-optimised
--- compiler is severely affected
-
---
--- (c) The University of Glasgow 2002-2006
---
--- Binary I/O library, with special tweaks for GHC
---
--- Based on the nhc98 Binary library, which is copyright
--- (c) Malcolm Wallace and Colin Runciman, University of York, 1998.
--- Under the terms of the license for that software, we must tell you
--- where you can obtain the original version of the Binary library, namely
--- http://www.cs.york.ac.uk/fp/nhc98/
-
-module Binary
- ( {-type-} Bin,
- {-class-} Binary(..),
- {-type-} BinHandle,
- SymbolTable, Dictionary,
-
- BinData(..), dataHandle, handleData,
-
- openBinMem,
--- closeBin,
-
- seekBin,
- tellBin,
- castBin,
- withBinBuffer,
-
- writeBinMem,
- readBinMem,
-
- putAt, getAt,
-
- -- * For writing instances
- putByte,
- getByte,
-
- -- * Variable length encodings
- putULEB128,
- getULEB128,
- putSLEB128,
- getSLEB128,
-
- -- * Lazy Binary I/O
- lazyGet,
- lazyPut,
-
- -- * User data
- UserData(..), getUserData, setUserData,
- newReadState, newWriteState,
- putDictionary, getDictionary, putFS,
- ) where
-
-#include "HsVersions.h"
-
-import GhcPrelude
-
-import {-# SOURCE #-} GHC.Types.Name (Name)
-import FastString
-import PlainPanic
-import GHC.Types.Unique.FM
-import FastMutInt
-import Fingerprint
-import GHC.Types.Basic
-import GHC.Types.SrcLoc
-
-import Control.DeepSeq
-import Foreign
-import Data.Array
-import Data.ByteString (ByteString)
-import qualified Data.ByteString.Internal as BS
-import qualified Data.ByteString.Unsafe as BS
-import Data.IORef
-import Data.Char ( ord, chr )
-import Data.Time
-import Data.List (unfoldr)
-import Type.Reflection
-import Type.Reflection.Unsafe
-import Data.Kind (Type)
-import GHC.Exts (TYPE, RuntimeRep(..), VecCount(..), VecElem(..))
-import Control.Monad ( when, (<$!>), unless )
-import System.IO as IO
-import System.IO.Unsafe ( unsafeInterleaveIO )
-import System.IO.Error ( mkIOError, eofErrorType )
-import GHC.Real ( Ratio(..) )
-import GHC.Serialized
-
-type BinArray = ForeignPtr Word8
-
-
-
----------------------------------------------------------------
--- BinData
----------------------------------------------------------------
-
-data BinData = BinData Int BinArray
-
-instance NFData BinData where
- rnf (BinData sz _) = rnf sz
-
-instance Binary BinData where
- put_ bh (BinData sz dat) = do
- put_ bh sz
- putPrim bh sz $ \dest ->
- withForeignPtr dat $ \orig ->
- copyBytes dest orig sz
- --
- get bh = do
- sz <- get bh
- dat <- mallocForeignPtrBytes sz
- getPrim bh sz $ \orig ->
- withForeignPtr dat $ \dest ->
- copyBytes dest orig sz
- return (BinData sz dat)
-
-dataHandle :: BinData -> IO BinHandle
-dataHandle (BinData size bin) = do
- ixr <- newFastMutInt
- szr <- newFastMutInt
- writeFastMutInt ixr 0
- writeFastMutInt szr size
- binr <- newIORef bin
- return (BinMem noUserData ixr szr binr)
-
-handleData :: BinHandle -> IO BinData
-handleData (BinMem _ ixr _ binr) = BinData <$> readFastMutInt ixr <*> readIORef binr
-
----------------------------------------------------------------
--- BinHandle
----------------------------------------------------------------
-
-data BinHandle
- = BinMem { -- binary data stored in an unboxed array
- bh_usr :: UserData, -- sigh, need parameterized modules :-)
- _off_r :: !FastMutInt, -- the current offset
- _sz_r :: !FastMutInt, -- size of the array (cached)
- _arr_r :: !(IORef BinArray) -- the array (bounds: (0,size-1))
- }
- -- XXX: should really store a "high water mark" for dumping out
- -- the binary data to a file.
-
-getUserData :: BinHandle -> UserData
-getUserData bh = bh_usr bh
-
-setUserData :: BinHandle -> UserData -> BinHandle
-setUserData bh us = bh { bh_usr = us }
-
--- | Get access to the underlying buffer.
---
--- It is quite important that no references to the 'ByteString' leak out of the
--- continuation lest terrible things happen.
-withBinBuffer :: BinHandle -> (ByteString -> IO a) -> IO a
-withBinBuffer (BinMem _ ix_r _ arr_r) action = do
- arr <- readIORef arr_r
- ix <- readFastMutInt ix_r
- withForeignPtr arr $ \ptr ->
- BS.unsafePackCStringLen (castPtr ptr, ix) >>= action
-
-
----------------------------------------------------------------
--- Bin
----------------------------------------------------------------
-
-newtype Bin a = BinPtr Int
- deriving (Eq, Ord, Show, Bounded)
-
-castBin :: Bin a -> Bin b
-castBin (BinPtr i) = BinPtr i
-
----------------------------------------------------------------
--- class Binary
----------------------------------------------------------------
-
--- | Do not rely on instance sizes for general types,
--- we use variable length encoding for many of them.
-class Binary a where
- put_ :: BinHandle -> a -> IO ()
- put :: BinHandle -> a -> IO (Bin a)
- get :: BinHandle -> IO a
-
- -- define one of put_, put. Use of put_ is recommended because it
- -- is more likely that tail-calls can kick in, and we rarely need the
- -- position return value.
- put_ bh a = do _ <- put bh a; return ()
- put bh a = do p <- tellBin bh; put_ bh a; return p
-
-putAt :: Binary a => BinHandle -> Bin a -> a -> IO ()
-putAt bh p x = do seekBin bh p; put_ bh x; return ()
-
-getAt :: Binary a => BinHandle -> Bin a -> IO a
-getAt bh p = do seekBin bh p; get bh
-
-openBinMem :: Int -> IO BinHandle
-openBinMem size
- | size <= 0 = error "Data.Binary.openBinMem: size must be >= 0"
- | otherwise = do
- arr <- mallocForeignPtrBytes size
- arr_r <- newIORef arr
- ix_r <- newFastMutInt
- writeFastMutInt ix_r 0
- sz_r <- newFastMutInt
- writeFastMutInt sz_r size
- return (BinMem noUserData ix_r sz_r arr_r)
-
-tellBin :: BinHandle -> IO (Bin a)
-tellBin (BinMem _ r _ _) = do ix <- readFastMutInt r; return (BinPtr ix)
-
-seekBin :: BinHandle -> Bin a -> IO ()
-seekBin h@(BinMem _ ix_r sz_r _) (BinPtr !p) = do
- sz <- readFastMutInt sz_r
- if (p >= sz)
- then do expandBin h p; writeFastMutInt ix_r p
- else writeFastMutInt ix_r p
-
-writeBinMem :: BinHandle -> FilePath -> IO ()
-writeBinMem (BinMem _ ix_r _ arr_r) fn = do
- h <- openBinaryFile fn WriteMode
- arr <- readIORef arr_r
- ix <- readFastMutInt ix_r
- withForeignPtr arr $ \p -> hPutBuf h p ix
- hClose h
-
-readBinMem :: FilePath -> IO BinHandle
--- Return a BinHandle with a totally undefined State
-readBinMem filename = do
- h <- openBinaryFile filename ReadMode
- filesize' <- hFileSize h
- let filesize = fromIntegral filesize'
- arr <- mallocForeignPtrBytes filesize
- count <- withForeignPtr arr $ \p -> hGetBuf h p filesize
- when (count /= filesize) $
- error ("Binary.readBinMem: only read " ++ show count ++ " bytes")
- hClose h
- arr_r <- newIORef arr
- ix_r <- newFastMutInt
- writeFastMutInt ix_r 0
- sz_r <- newFastMutInt
- writeFastMutInt sz_r filesize
- return (BinMem noUserData ix_r sz_r arr_r)
-
--- expand the size of the array to include a specified offset
-expandBin :: BinHandle -> Int -> IO ()
-expandBin (BinMem _ _ sz_r arr_r) !off = do
- !sz <- readFastMutInt sz_r
- let !sz' = getSize sz
- arr <- readIORef arr_r
- arr' <- mallocForeignPtrBytes sz'
- withForeignPtr arr $ \old ->
- withForeignPtr arr' $ \new ->
- copyBytes new old sz
- writeFastMutInt sz_r sz'
- writeIORef arr_r arr'
- where
- getSize :: Int -> Int
- getSize !sz
- | sz > off
- = sz
- | otherwise
- = getSize (sz * 2)
-
--- -----------------------------------------------------------------------------
--- Low-level reading/writing of bytes
-
--- | Takes a size and action writing up to @size@ bytes.
--- After the action has run advance the index to the buffer
--- by size bytes.
-putPrim :: BinHandle -> Int -> (Ptr Word8 -> IO ()) -> IO ()
-putPrim h@(BinMem _ ix_r sz_r arr_r) size f = do
- ix <- readFastMutInt ix_r
- sz <- readFastMutInt sz_r
- when (ix + size > sz) $
- expandBin h (ix + size)
- arr <- readIORef arr_r
- withForeignPtr arr $ \op -> f (op `plusPtr` ix)
- writeFastMutInt ix_r (ix + size)
-
--- -- | Similar to putPrim but advances the index by the actual number of
--- -- bytes written.
--- putPrimMax :: BinHandle -> Int -> (Ptr Word8 -> IO Int) -> IO ()
--- putPrimMax h@(BinMem _ ix_r sz_r arr_r) size f = do
--- ix <- readFastMutInt ix_r
--- sz <- readFastMutInt sz_r
--- when (ix + size > sz) $
--- expandBin h (ix + size)
--- arr <- readIORef arr_r
--- written <- withForeignPtr arr $ \op -> f (op `plusPtr` ix)
--- writeFastMutInt ix_r (ix + written)
-
-getPrim :: BinHandle -> Int -> (Ptr Word8 -> IO a) -> IO a
-getPrim (BinMem _ ix_r sz_r arr_r) size f = do
- ix <- readFastMutInt ix_r
- sz <- readFastMutInt sz_r
- when (ix + size > sz) $
- ioError (mkIOError eofErrorType "Data.Binary.getPrim" Nothing Nothing)
- arr <- readIORef arr_r
- w <- withForeignPtr arr $ \op -> f (op `plusPtr` ix)
- writeFastMutInt ix_r (ix + size)
- return w
-
-putWord8 :: BinHandle -> Word8 -> IO ()
-putWord8 h !w = putPrim h 1 (\op -> poke op w)
-
-getWord8 :: BinHandle -> IO Word8
-getWord8 h = getPrim h 1 peek
-
--- putWord16 :: BinHandle -> Word16 -> IO ()
--- putWord16 h w = putPrim h 2 (\op -> do
--- pokeElemOff op 0 (fromIntegral (w `shiftR` 8))
--- pokeElemOff op 1 (fromIntegral (w .&. 0xFF))
--- )
-
--- getWord16 :: BinHandle -> IO Word16
--- getWord16 h = getPrim h 2 (\op -> do
--- w0 <- fromIntegral <$> peekElemOff op 0
--- w1 <- fromIntegral <$> peekElemOff op 1
--- return $! w0 `shiftL` 8 .|. w1
--- )
-
-putWord32 :: BinHandle -> Word32 -> IO ()
-putWord32 h w = putPrim h 4 (\op -> do
- pokeElemOff op 0 (fromIntegral (w `shiftR` 24))
- pokeElemOff op 1 (fromIntegral ((w `shiftR` 16) .&. 0xFF))
- pokeElemOff op 2 (fromIntegral ((w `shiftR` 8) .&. 0xFF))
- pokeElemOff op 3 (fromIntegral (w .&. 0xFF))
- )
-
-getWord32 :: BinHandle -> IO Word32
-getWord32 h = getPrim h 4 (\op -> do
- w0 <- fromIntegral <$> peekElemOff op 0
- w1 <- fromIntegral <$> peekElemOff op 1
- w2 <- fromIntegral <$> peekElemOff op 2
- w3 <- fromIntegral <$> peekElemOff op 3
-
- return $! (w0 `shiftL` 24) .|.
- (w1 `shiftL` 16) .|.
- (w2 `shiftL` 8) .|.
- w3
- )
-
--- putWord64 :: BinHandle -> Word64 -> IO ()
--- putWord64 h w = putPrim h 8 (\op -> do
--- pokeElemOff op 0 (fromIntegral (w `shiftR` 56))
--- pokeElemOff op 1 (fromIntegral ((w `shiftR` 48) .&. 0xFF))
--- pokeElemOff op 2 (fromIntegral ((w `shiftR` 40) .&. 0xFF))
--- pokeElemOff op 3 (fromIntegral ((w `shiftR` 32) .&. 0xFF))
--- pokeElemOff op 4 (fromIntegral ((w `shiftR` 24) .&. 0xFF))
--- pokeElemOff op 5 (fromIntegral ((w `shiftR` 16) .&. 0xFF))
--- pokeElemOff op 6 (fromIntegral ((w `shiftR` 8) .&. 0xFF))
--- pokeElemOff op 7 (fromIntegral (w .&. 0xFF))
--- )
-
--- getWord64 :: BinHandle -> IO Word64
--- getWord64 h = getPrim h 8 (\op -> do
--- w0 <- fromIntegral <$> peekElemOff op 0
--- w1 <- fromIntegral <$> peekElemOff op 1
--- w2 <- fromIntegral <$> peekElemOff op 2
--- w3 <- fromIntegral <$> peekElemOff op 3
--- w4 <- fromIntegral <$> peekElemOff op 4
--- w5 <- fromIntegral <$> peekElemOff op 5
--- w6 <- fromIntegral <$> peekElemOff op 6
--- w7 <- fromIntegral <$> peekElemOff op 7
-
--- return $! (w0 `shiftL` 56) .|.
--- (w1 `shiftL` 48) .|.
--- (w2 `shiftL` 40) .|.
--- (w3 `shiftL` 32) .|.
--- (w4 `shiftL` 24) .|.
--- (w5 `shiftL` 16) .|.
--- (w6 `shiftL` 8) .|.
--- w7
--- )
-
-putByte :: BinHandle -> Word8 -> IO ()
-putByte bh !w = putWord8 bh w
-
-getByte :: BinHandle -> IO Word8
-getByte h = getWord8 h
-
--- -----------------------------------------------------------------------------
--- Encode numbers in LEB128 encoding.
--- Requires one byte of space per 7 bits of data.
---
--- There are signed and unsigned variants.
--- Do NOT use the unsigned one for signed values, at worst it will
--- result in wrong results, at best it will lead to bad performance
--- when coercing negative values to an unsigned type.
---
--- We mark them as SPECIALIZE as it's extremely critical that they get specialized
--- to their specific types.
---
--- TODO: Each use of putByte performs a bounds check,
--- we should use putPrimMax here. However it's quite hard to return
--- the number of bytes written into putPrimMax without allocating an
--- Int for it, while the code below does not allocate at all.
--- So we eat the cost of the bounds check instead of increasing allocations
--- for now.
-
--- Unsigned numbers
-{-# SPECIALISE putULEB128 :: BinHandle -> Word -> IO () #-}
-{-# SPECIALISE putULEB128 :: BinHandle -> Word64 -> IO () #-}
-{-# SPECIALISE putULEB128 :: BinHandle -> Word32 -> IO () #-}
-{-# SPECIALISE putULEB128 :: BinHandle -> Word16 -> IO () #-}
-{-# SPECIALISE putULEB128 :: BinHandle -> Int -> IO () #-}
-{-# SPECIALISE putULEB128 :: BinHandle -> Int64 -> IO () #-}
-{-# SPECIALISE putULEB128 :: BinHandle -> Int32 -> IO () #-}
-{-# SPECIALISE putULEB128 :: BinHandle -> Int16 -> IO () #-}
-putULEB128 :: forall a. (Integral a, FiniteBits a) => BinHandle -> a -> IO ()
-putULEB128 bh w =
-#if defined(DEBUG)
- (if w < 0 then panic "putULEB128: Signed number" else id) $
-#endif
- go w
- where
- go :: a -> IO ()
- go w
- | w <= (127 :: a)
- = putByte bh (fromIntegral w :: Word8)
- | otherwise = do
- -- bit 7 (8th bit) indicates more to come.
- let !byte = setBit (fromIntegral w) 7 :: Word8
- putByte bh byte
- go (w `unsafeShiftR` 7)
-
-{-# SPECIALISE getULEB128 :: BinHandle -> IO Word #-}
-{-# SPECIALISE getULEB128 :: BinHandle -> IO Word64 #-}
-{-# SPECIALISE getULEB128 :: BinHandle -> IO Word32 #-}
-{-# SPECIALISE getULEB128 :: BinHandle -> IO Word16 #-}
-{-# SPECIALISE getULEB128 :: BinHandle -> IO Int #-}
-{-# SPECIALISE getULEB128 :: BinHandle -> IO Int64 #-}
-{-# SPECIALISE getULEB128 :: BinHandle -> IO Int32 #-}
-{-# SPECIALISE getULEB128 :: BinHandle -> IO Int16 #-}
-getULEB128 :: forall a. (Integral a, FiniteBits a) => BinHandle -> IO a
-getULEB128 bh =
- go 0 0
- where
- go :: Int -> a -> IO a
- go shift w = do
- b <- getByte bh
- let !hasMore = testBit b 7
- let !val = w .|. ((clearBit (fromIntegral b) 7) `unsafeShiftL` shift) :: a
- if hasMore
- then do
- go (shift+7) val
- else
- return $! val
-
--- Signed numbers
-{-# SPECIALISE putSLEB128 :: BinHandle -> Word -> IO () #-}
-{-# SPECIALISE putSLEB128 :: BinHandle -> Word64 -> IO () #-}
-{-# SPECIALISE putSLEB128 :: BinHandle -> Word32 -> IO () #-}
-{-# SPECIALISE putSLEB128 :: BinHandle -> Word16 -> IO () #-}
-{-# SPECIALISE putSLEB128 :: BinHandle -> Int -> IO () #-}
-{-# SPECIALISE putSLEB128 :: BinHandle -> Int64 -> IO () #-}
-{-# SPECIALISE putSLEB128 :: BinHandle -> Int32 -> IO () #-}
-{-# SPECIALISE putSLEB128 :: BinHandle -> Int16 -> IO () #-}
-putSLEB128 :: forall a. (Integral a, Bits a) => BinHandle -> a -> IO ()
-putSLEB128 bh initial = go initial
- where
- go :: a -> IO ()
- go val = do
- let !byte = fromIntegral (clearBit val 7) :: Word8
- let !val' = val `unsafeShiftR` 7
- let !signBit = testBit byte 6
- let !done =
- -- Unsigned value, val' == 0 and last value can
- -- be discriminated from a negative number.
- ((val' == 0 && not signBit) ||
- -- Signed value,
- (val' == -1 && signBit))
-
- let !byte' = if done then byte else setBit byte 7
- putByte bh byte'
-
- unless done $ go val'
-
-{-# SPECIALISE getSLEB128 :: BinHandle -> IO Word #-}
-{-# SPECIALISE getSLEB128 :: BinHandle -> IO Word64 #-}
-{-# SPECIALISE getSLEB128 :: BinHandle -> IO Word32 #-}
-{-# SPECIALISE getSLEB128 :: BinHandle -> IO Word16 #-}
-{-# SPECIALISE getSLEB128 :: BinHandle -> IO Int #-}
-{-# SPECIALISE getSLEB128 :: BinHandle -> IO Int64 #-}
-{-# SPECIALISE getSLEB128 :: BinHandle -> IO Int32 #-}
-{-# SPECIALISE getSLEB128 :: BinHandle -> IO Int16 #-}
-getSLEB128 :: forall a. (Show a, Integral a, FiniteBits a) => BinHandle -> IO a
-getSLEB128 bh = do
- (val,shift,signed) <- go 0 0
- if signed && (shift < finiteBitSize val )
- then return $! ((complement 0 `unsafeShiftL` shift) .|. val)
- else return val
- where
- go :: Int -> a -> IO (a,Int,Bool)
- go shift val = do
- byte <- getByte bh
- let !byteVal = fromIntegral (clearBit byte 7) :: a
- let !val' = val .|. (byteVal `unsafeShiftL` shift)
- let !more = testBit byte 7
- let !shift' = shift+7
- if more
- then go (shift') val'
- else do
- let !signed = testBit byte 6
- return (val',shift',signed)
-
--- -----------------------------------------------------------------------------
--- Primitive Word writes
-
-instance Binary Word8 where
- put_ bh !w = putWord8 bh w
- get = getWord8
-
-instance Binary Word16 where
- put_ = putULEB128
- get = getULEB128
-
-instance Binary Word32 where
- put_ = putULEB128
- get = getULEB128
-
-instance Binary Word64 where
- put_ = putULEB128
- get = getULEB128
-
--- -----------------------------------------------------------------------------
--- Primitive Int writes
-
-instance Binary Int8 where
- put_ h w = put_ h (fromIntegral w :: Word8)
- get h = do w <- get h; return $! (fromIntegral (w::Word8))
-
-instance Binary Int16 where
- put_ = putSLEB128
- get = getSLEB128
-
-instance Binary Int32 where
- put_ = putSLEB128
- get = getSLEB128
-
-instance Binary Int64 where
- put_ h w = putSLEB128 h w
- get h = getSLEB128 h
-
--- -----------------------------------------------------------------------------
--- Instances for standard types
-
-instance Binary () where
- put_ _ () = return ()
- get _ = return ()
-
-instance Binary Bool where
- put_ bh b = putByte bh (fromIntegral (fromEnum b))
- get bh = do x <- getWord8 bh; return $! (toEnum (fromIntegral x))
-
-instance Binary Char where
- put_ bh c = put_ bh (fromIntegral (ord c) :: Word32)
- get bh = do x <- get bh; return $! (chr (fromIntegral (x :: Word32)))
-
-instance Binary Int where
- put_ bh i = put_ bh (fromIntegral i :: Int64)
- get bh = do
- x <- get bh
- return $! (fromIntegral (x :: Int64))
-
-instance Binary a => Binary [a] where
- put_ bh l = do
- let len = length l
- put_ bh len
- mapM_ (put_ bh) l
- get bh = do
- len <- get bh :: IO Int -- Int is variable length encoded so only
- -- one byte for small lists.
- let loop 0 = return []
- loop n = do a <- get bh; as <- loop (n-1); return (a:as)
- loop len
-
-instance (Ix a, Binary a, Binary b) => Binary (Array a b) where
- put_ bh arr = do
- put_ bh $ bounds arr
- put_ bh $ elems arr
- get bh = do
- bounds <- get bh
- xs <- get bh
- return $ listArray bounds xs
-
-instance (Binary a, Binary b) => Binary (a,b) where
- put_ bh (a,b) = do put_ bh a; put_ bh b
- get bh = do a <- get bh
- b <- get bh
- return (a,b)
-
-instance (Binary a, Binary b, Binary c) => Binary (a,b,c) where
- put_ bh (a,b,c) = do put_ bh a; put_ bh b; put_ bh c
- get bh = do a <- get bh
- b <- get bh
- c <- get bh
- return (a,b,c)
-
-instance (Binary a, Binary b, Binary c, Binary d) => Binary (a,b,c,d) where
- put_ bh (a,b,c,d) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d
- get bh = do a <- get bh
- b <- get bh
- c <- get bh
- d <- get bh
- return (a,b,c,d)
-
-instance (Binary a, Binary b, Binary c, Binary d, Binary e) => Binary (a,b,c,d, e) where
- put_ bh (a,b,c,d, e) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d; put_ bh e;
- get bh = do a <- get bh
- b <- get bh
- c <- get bh
- d <- get bh
- e <- get bh
- return (a,b,c,d,e)
-
-instance (Binary a, Binary b, Binary c, Binary d, Binary e, Binary f) => Binary (a,b,c,d, e, f) where
- put_ bh (a,b,c,d, e, f) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d; put_ bh e; put_ bh f;
- get bh = do a <- get bh
- b <- get bh
- c <- get bh
- d <- get bh
- e <- get bh
- f <- get bh
- return (a,b,c,d,e,f)
-
-instance (Binary a, Binary b, Binary c, Binary d, Binary e, Binary f, Binary g) => Binary (a,b,c,d,e,f,g) where
- put_ bh (a,b,c,d,e,f,g) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d; put_ bh e; put_ bh f; put_ bh g
- get bh = do a <- get bh
- b <- get bh
- c <- get bh
- d <- get bh
- e <- get bh
- f <- get bh
- g <- get bh
- return (a,b,c,d,e,f,g)
-
-instance Binary a => Binary (Maybe a) where
- put_ bh Nothing = putByte bh 0
- put_ bh (Just a) = do putByte bh 1; put_ bh a
- get bh = do h <- getWord8 bh
- case h of
- 0 -> return Nothing
- _ -> do x <- get bh; return (Just x)
-
-instance (Binary a, Binary b) => Binary (Either a b) where
- put_ bh (Left a) = do putByte bh 0; put_ bh a
- put_ bh (Right b) = do putByte bh 1; put_ bh b
- get bh = do h <- getWord8 bh
- case h of
- 0 -> do a <- get bh ; return (Left a)
- _ -> do b <- get bh ; return (Right b)
-
-instance Binary UTCTime where
- put_ bh u = do put_ bh (utctDay u)
- put_ bh (utctDayTime u)
- get bh = do day <- get bh
- dayTime <- get bh
- return $ UTCTime { utctDay = day, utctDayTime = dayTime }
-
-instance Binary Day where
- put_ bh d = put_ bh (toModifiedJulianDay d)
- get bh = do i <- get bh
- return $ ModifiedJulianDay { toModifiedJulianDay = i }
-
-instance Binary DiffTime where
- put_ bh dt = put_ bh (toRational dt)
- get bh = do r <- get bh
- return $ fromRational r
-
-{-
-Finally - a reasonable portable Integer instance.
-
-We used to encode values in the Int32 range as such,
-falling back to a string of all things. In either case
-we stored a tag byte to discriminate between the two cases.
-
-This made some sense as it's highly portable but also not very
-efficient.
-
-However GHC stores a surprisingly large number off large Integer
-values. In the examples looked at between 25% and 50% of Integers
-serialized were outside of the Int32 range.
-
-Consider a valie like `2724268014499746065`, some sort of hash
-actually generated by GHC.
-In the old scheme this was encoded as a list of 19 chars. This
-gave a size of 77 Bytes, one for the length of the list and 76
-since we encode chars as Word32 as well.
-
-We can easily do better. The new plan is:
-
-* Start with a tag byte
- * 0 => Int64 (LEB128 encoded)
- * 1 => Negative large interger
- * 2 => Positive large integer
-* Followed by the value:
- * Int64 is encoded as usual
- * Large integers are encoded as a list of bytes (Word8).
- We use Data.Bits which defines a bit order independent of the representation.
- Values are stored LSB first.
-
-This means our example value `2724268014499746065` is now only 10 bytes large.
-* One byte tag
-* One byte for the length of the [Word8] list.
-* 8 bytes for the actual date.
-
-The new scheme also does not depend in any way on
-architecture specific details.
-
-We still use this scheme even with LEB128 available,
-as it has less overhead for truly large numbers. (> maxBound :: Int64)
-
-The instance is used for in Binary Integer and Binary Rational in basicTypes/Literal.hs
--}
-
-instance Binary Integer where
- put_ bh i
- | i >= lo64 && i <= hi64 = do
- putWord8 bh 0
- put_ bh (fromIntegral i :: Int64)
- | otherwise = do
- if i < 0
- then putWord8 bh 1
- else putWord8 bh 2
- put_ bh (unroll $ abs i)
- where
- lo64 = fromIntegral (minBound :: Int64)
- hi64 = fromIntegral (maxBound :: Int64)
- get bh = do
- int_kind <- getWord8 bh
- case int_kind of
- 0 -> fromIntegral <$!> (get bh :: IO Int64)
- -- Large integer
- 1 -> negate <$!> getInt
- 2 -> getInt
- _ -> panic "Binary Integer - Invalid byte"
- where
- getInt :: IO Integer
- getInt = roll <$!> (get bh :: IO [Word8])
-
-unroll :: Integer -> [Word8]
-unroll = unfoldr step
- where
- step 0 = Nothing
- step i = Just (fromIntegral i, i `shiftR` 8)
-
-roll :: [Word8] -> Integer
-roll = foldl' unstep 0 . reverse
- where
- unstep a b = a `shiftL` 8 .|. fromIntegral b
-
-
- {-
- -- This code is currently commented out.
- -- See https://gitlab.haskell.org/ghc/ghc/issues/3379#note_104346 for
- -- discussion.
-
- put_ bh (S# i#) = do putByte bh 0; put_ bh (I# i#)
- put_ bh (J# s# a#) = do
- putByte bh 1
- put_ bh (I# s#)
- let sz# = sizeofByteArray# a# -- in *bytes*
- put_ bh (I# sz#) -- in *bytes*
- putByteArray bh a# sz#
-
- get bh = do
- b <- getByte bh
- case b of
- 0 -> do (I# i#) <- get bh
- return (S# i#)
- _ -> do (I# s#) <- get bh
- sz <- get bh
- (BA a#) <- getByteArray bh sz
- return (J# s# a#)
-
-putByteArray :: BinHandle -> ByteArray# -> Int# -> IO ()
-putByteArray bh a s# = loop 0#
- where loop n#
- | n# ==# s# = return ()
- | otherwise = do
- putByte bh (indexByteArray a n#)
- loop (n# +# 1#)
-
-getByteArray :: BinHandle -> Int -> IO ByteArray
-getByteArray bh (I# sz) = do
- (MBA arr) <- newByteArray sz
- let loop n
- | n ==# sz = return ()
- | otherwise = do
- w <- getByte bh
- writeByteArray arr n w
- loop (n +# 1#)
- loop 0#
- freezeByteArray arr
- -}
-
-{-
-data ByteArray = BA ByteArray#
-data MBA = MBA (MutableByteArray# RealWorld)
-
-newByteArray :: Int# -> IO MBA
-newByteArray sz = IO $ \s ->
- case newByteArray# sz s of { (# s, arr #) ->
- (# s, MBA arr #) }
-
-freezeByteArray :: MutableByteArray# RealWorld -> IO ByteArray
-freezeByteArray arr = IO $ \s ->
- case unsafeFreezeByteArray# arr s of { (# s, arr #) ->
- (# s, BA arr #) }
-
-writeByteArray :: MutableByteArray# RealWorld -> Int# -> Word8 -> IO ()
-writeByteArray arr i (W8# w) = IO $ \s ->
- case writeWord8Array# arr i w s of { s ->
- (# s, () #) }
-
-indexByteArray :: ByteArray# -> Int# -> Word8
-indexByteArray a# n# = W8# (indexWord8Array# a# n#)
-
--}
-instance (Binary a) => Binary (Ratio a) where
- put_ bh (a :% b) = do put_ bh a; put_ bh b
- get bh = do a <- get bh; b <- get bh; return (a :% b)
-
--- Instance uses fixed-width encoding to allow inserting
--- Bin placeholders in the stream.
-instance Binary (Bin a) where
- put_ bh (BinPtr i) = putWord32 bh (fromIntegral i :: Word32)
- get bh = do i <- getWord32 bh; return (BinPtr (fromIntegral (i :: Word32)))
-
--- -----------------------------------------------------------------------------
--- Instances for Data.Typeable stuff
-
-instance Binary TyCon where
- put_ bh tc = do
- put_ bh (tyConPackage tc)
- put_ bh (tyConModule tc)
- put_ bh (tyConName tc)
- put_ bh (tyConKindArgs tc)
- put_ bh (tyConKindRep tc)
- get bh =
- mkTyCon <$> get bh <*> get bh <*> get bh <*> get bh <*> get bh
-
-instance Binary VecCount where
- put_ bh = putByte bh . fromIntegral . fromEnum
- get bh = toEnum . fromIntegral <$> getByte bh
-
-instance Binary VecElem where
- put_ bh = putByte bh . fromIntegral . fromEnum
- get bh = toEnum . fromIntegral <$> getByte bh
-
-instance Binary RuntimeRep where
- put_ bh (VecRep a b) = putByte bh 0 >> put_ bh a >> put_ bh b
- put_ bh (TupleRep reps) = putByte bh 1 >> put_ bh reps
- put_ bh (SumRep reps) = putByte bh 2 >> put_ bh reps
- put_ bh LiftedRep = putByte bh 3
- put_ bh UnliftedRep = putByte bh 4
- put_ bh IntRep = putByte bh 5
- put_ bh WordRep = putByte bh 6
- put_ bh Int64Rep = putByte bh 7
- put_ bh Word64Rep = putByte bh 8
- put_ bh AddrRep = putByte bh 9
- put_ bh FloatRep = putByte bh 10
- put_ bh DoubleRep = putByte bh 11
- put_ bh Int8Rep = putByte bh 12
- put_ bh Word8Rep = putByte bh 13
- put_ bh Int16Rep = putByte bh 14
- put_ bh Word16Rep = putByte bh 15
-#if __GLASGOW_HASKELL__ >= 809
- put_ bh Int32Rep = putByte bh 16
- put_ bh Word32Rep = putByte bh 17
-#endif
-
- get bh = do
- tag <- getByte bh
- case tag of
- 0 -> VecRep <$> get bh <*> get bh
- 1 -> TupleRep <$> get bh
- 2 -> SumRep <$> get bh
- 3 -> pure LiftedRep
- 4 -> pure UnliftedRep
- 5 -> pure IntRep
- 6 -> pure WordRep
- 7 -> pure Int64Rep
- 8 -> pure Word64Rep
- 9 -> pure AddrRep
- 10 -> pure FloatRep
- 11 -> pure DoubleRep
- 12 -> pure Int8Rep
- 13 -> pure Word8Rep
- 14 -> pure Int16Rep
- 15 -> pure Word16Rep
-#if __GLASGOW_HASKELL__ >= 809
- 16 -> pure Int32Rep
- 17 -> pure Word32Rep
-#endif
- _ -> fail "Binary.putRuntimeRep: invalid tag"
-
-instance Binary KindRep where
- put_ bh (KindRepTyConApp tc k) = putByte bh 0 >> put_ bh tc >> put_ bh k
- put_ bh (KindRepVar bndr) = putByte bh 1 >> put_ bh bndr
- put_ bh (KindRepApp a b) = putByte bh 2 >> put_ bh a >> put_ bh b
- put_ bh (KindRepFun a b) = putByte bh 3 >> put_ bh a >> put_ bh b
- put_ bh (KindRepTYPE r) = putByte bh 4 >> put_ bh r
- put_ bh (KindRepTypeLit sort r) = putByte bh 5 >> put_ bh sort >> put_ bh r
-
- get bh = do
- tag <- getByte bh
- case tag of
- 0 -> KindRepTyConApp <$> get bh <*> get bh
- 1 -> KindRepVar <$> get bh
- 2 -> KindRepApp <$> get bh <*> get bh
- 3 -> KindRepFun <$> get bh <*> get bh
- 4 -> KindRepTYPE <$> get bh
- 5 -> KindRepTypeLit <$> get bh <*> get bh
- _ -> fail "Binary.putKindRep: invalid tag"
-
-instance Binary TypeLitSort where
- put_ bh TypeLitSymbol = putByte bh 0
- put_ bh TypeLitNat = putByte bh 1
- get bh = do
- tag <- getByte bh
- case tag of
- 0 -> pure TypeLitSymbol
- 1 -> pure TypeLitNat
- _ -> fail "Binary.putTypeLitSort: invalid tag"
-
-putTypeRep :: BinHandle -> TypeRep a -> IO ()
--- Special handling for TYPE, (->), and RuntimeRep due to recursive kind
--- relations.
--- See Note [Mutually recursive representations of primitive types]
-putTypeRep bh rep
- | Just HRefl <- rep `eqTypeRep` (typeRep :: TypeRep Type)
- = put_ bh (0 :: Word8)
-putTypeRep bh (Con' con ks) = do
- put_ bh (1 :: Word8)
- put_ bh con
- put_ bh ks
-putTypeRep bh (App f x) = do
- put_ bh (2 :: Word8)
- putTypeRep bh f
- putTypeRep bh x
-putTypeRep bh (Fun arg res) = do
- put_ bh (3 :: Word8)
- putTypeRep bh arg
- putTypeRep bh res
-
-getSomeTypeRep :: BinHandle -> IO SomeTypeRep
-getSomeTypeRep bh = do
- tag <- get bh :: IO Word8
- case tag of
- 0 -> return $ SomeTypeRep (typeRep :: TypeRep Type)
- 1 -> do con <- get bh :: IO TyCon
- ks <- get bh :: IO [SomeTypeRep]
- return $ SomeTypeRep $ mkTrCon con ks
-
- 2 -> do SomeTypeRep f <- getSomeTypeRep bh
- SomeTypeRep x <- getSomeTypeRep bh
- case typeRepKind f of
- Fun arg res ->
- case arg `eqTypeRep` typeRepKind x of
- Just HRefl ->
- case typeRepKind res `eqTypeRep` (typeRep :: TypeRep Type) of
- Just HRefl -> return $ SomeTypeRep $ mkTrApp f x
- _ -> failure "Kind mismatch in type application" []
- _ -> failure "Kind mismatch in type application"
- [ " Found argument of kind: " ++ show (typeRepKind x)
- , " Where the constructor: " ++ show f
- , " Expects kind: " ++ show arg
- ]
- _ -> failure "Applied non-arrow"
- [ " Applied type: " ++ show f
- , " To argument: " ++ show x
- ]
- 3 -> do SomeTypeRep arg <- getSomeTypeRep bh
- SomeTypeRep res <- getSomeTypeRep bh
- if
- | App argkcon _ <- typeRepKind arg
- , App reskcon _ <- typeRepKind res
- , Just HRefl <- argkcon `eqTypeRep` tYPErep
- , Just HRefl <- reskcon `eqTypeRep` tYPErep
- -> return $ SomeTypeRep $ Fun arg res
- | otherwise -> failure "Kind mismatch" []
- _ -> failure "Invalid SomeTypeRep" []
- where
- tYPErep :: TypeRep TYPE
- tYPErep = typeRep
-
- failure description info =
- fail $ unlines $ [ "Binary.getSomeTypeRep: "++description ]
- ++ map (" "++) info
-
-instance Typeable a => Binary (TypeRep (a :: k)) where
- put_ = putTypeRep
- get bh = do
- SomeTypeRep rep <- getSomeTypeRep bh
- case rep `eqTypeRep` expected of
- Just HRefl -> pure rep
- Nothing -> fail $ unlines
- [ "Binary: Type mismatch"
- , " Deserialized type: " ++ show rep
- , " Expected type: " ++ show expected
- ]
- where expected = typeRep :: TypeRep a
-
-instance Binary SomeTypeRep where
- put_ bh (SomeTypeRep rep) = putTypeRep bh rep
- get = getSomeTypeRep
-
--- -----------------------------------------------------------------------------
--- Lazy reading/writing
-
-lazyPut :: Binary a => BinHandle -> a -> IO ()
-lazyPut bh a = do
- -- output the obj with a ptr to skip over it:
- pre_a <- tellBin bh
- put_ bh pre_a -- save a slot for the ptr
- put_ bh a -- dump the object
- q <- tellBin bh -- q = ptr to after object
- putAt bh pre_a q -- fill in slot before a with ptr to q
- seekBin bh q -- finally carry on writing at q
-
-lazyGet :: Binary a => BinHandle -> IO a
-lazyGet bh = do
- p <- get bh -- a BinPtr
- p_a <- tellBin bh
- a <- unsafeInterleaveIO $ do
- -- NB: Use a fresh off_r variable in the child thread, for thread
- -- safety.
- off_r <- newFastMutInt
- getAt bh { _off_r = off_r } p_a
- seekBin bh p -- skip over the object for now
- return a
-
--- -----------------------------------------------------------------------------
--- UserData
--- -----------------------------------------------------------------------------
-
--- | Information we keep around during interface file
--- serialization/deserialization. Namely we keep the functions for serializing
--- and deserializing 'Name's and 'FastString's. We do this because we actually
--- use serialization in two distinct settings,
---
--- * When serializing interface files themselves
---
--- * When computing the fingerprint of an IfaceDecl (which we computing by
--- hashing its Binary serialization)
---
--- These two settings have different needs while serializing Names:
---
--- * Names in interface files are serialized via a symbol table (see Note
--- [Symbol table representation of names] in GHC.Iface.Binary).
---
--- * During fingerprinting a binding Name is serialized as the OccName and a
--- non-binding Name is serialized as the fingerprint of the thing they
--- represent. See Note [Fingerprinting IfaceDecls] for further discussion.
---
-data UserData =
- UserData {
- -- for *deserialising* only:
- ud_get_name :: BinHandle -> IO Name,
- ud_get_fs :: BinHandle -> IO FastString,
-
- -- for *serialising* only:
- ud_put_nonbinding_name :: BinHandle -> Name -> IO (),
- -- ^ serialize a non-binding 'Name' (e.g. a reference to another
- -- binding).
- ud_put_binding_name :: BinHandle -> Name -> IO (),
- -- ^ serialize a binding 'Name' (e.g. the name of an IfaceDecl)
- ud_put_fs :: BinHandle -> FastString -> IO ()
- }
-
-newReadState :: (BinHandle -> IO Name) -- ^ how to deserialize 'Name's
- -> (BinHandle -> IO FastString)
- -> UserData
-newReadState get_name get_fs
- = UserData { ud_get_name = get_name,
- ud_get_fs = get_fs,
- ud_put_nonbinding_name = undef "put_nonbinding_name",
- ud_put_binding_name = undef "put_binding_name",
- ud_put_fs = undef "put_fs"
- }
-
-newWriteState :: (BinHandle -> Name -> IO ())
- -- ^ how to serialize non-binding 'Name's
- -> (BinHandle -> Name -> IO ())
- -- ^ how to serialize binding 'Name's
- -> (BinHandle -> FastString -> IO ())
- -> UserData
-newWriteState put_nonbinding_name put_binding_name put_fs
- = UserData { ud_get_name = undef "get_name",
- ud_get_fs = undef "get_fs",
- ud_put_nonbinding_name = put_nonbinding_name,
- ud_put_binding_name = put_binding_name,
- ud_put_fs = put_fs
- }
-
-noUserData :: a
-noUserData = undef "UserData"
-
-undef :: String -> a
-undef s = panic ("Binary.UserData: no " ++ s)
-
----------------------------------------------------------
--- The Dictionary
----------------------------------------------------------
-
-type Dictionary = Array Int FastString -- The dictionary
- -- Should be 0-indexed
-
-putDictionary :: BinHandle -> Int -> UniqFM (Int,FastString) -> IO ()
-putDictionary bh sz dict = do
- put_ bh sz
- mapM_ (putFS bh) (elems (array (0,sz-1) (nonDetEltsUFM dict)))
- -- It's OK to use nonDetEltsUFM here because the elements have indices
- -- that array uses to create order
-
-getDictionary :: BinHandle -> IO Dictionary
-getDictionary bh = do
- sz <- get bh
- elems <- sequence (take sz (repeat (getFS bh)))
- return (listArray (0,sz-1) elems)
-
----------------------------------------------------------
--- The Symbol Table
----------------------------------------------------------
-
--- On disk, the symbol table is an array of IfExtName, when
--- reading it in we turn it into a SymbolTable.
-
-type SymbolTable = Array Int Name
-
----------------------------------------------------------
--- Reading and writing FastStrings
----------------------------------------------------------
-
-putFS :: BinHandle -> FastString -> IO ()
-putFS bh fs = putBS bh $ bytesFS fs
-
-getFS :: BinHandle -> IO FastString
-getFS bh = do
- l <- get bh :: IO Int
- getPrim bh l (\src -> pure $! mkFastStringBytes src l )
-
-putBS :: BinHandle -> ByteString -> IO ()
-putBS bh bs =
- BS.unsafeUseAsCStringLen bs $ \(ptr, l) -> do
- put_ bh l
- putPrim bh l (\op -> BS.memcpy op (castPtr ptr) l)
-
-getBS :: BinHandle -> IO ByteString
-getBS bh = do
- l <- get bh :: IO Int
- BS.create l $ \dest -> do
- getPrim bh l (\src -> BS.memcpy dest src l)
-
-instance Binary ByteString where
- put_ bh f = putBS bh f
- get bh = getBS bh
-
-instance Binary FastString where
- put_ bh f =
- case getUserData bh of
- UserData { ud_put_fs = put_fs } -> put_fs bh f
-
- get bh =
- case getUserData bh of
- UserData { ud_get_fs = get_fs } -> get_fs bh
-
--- Here to avoid loop
-instance Binary LeftOrRight where
- put_ bh CLeft = putByte bh 0
- put_ bh CRight = putByte bh 1
-
- get bh = do { h <- getByte bh
- ; case h of
- 0 -> return CLeft
- _ -> return CRight }
-
-instance Binary PromotionFlag where
- put_ bh NotPromoted = putByte bh 0
- put_ bh IsPromoted = putByte bh 1
-
- get bh = do
- n <- getByte bh
- case n of
- 0 -> return NotPromoted
- 1 -> return IsPromoted
- _ -> fail "Binary(IsPromoted): fail)"
-
-instance Binary Fingerprint where
- put_ h (Fingerprint w1 w2) = do put_ h w1; put_ h w2
- get h = do w1 <- get h; w2 <- get h; return (Fingerprint w1 w2)
-
-instance Binary FunctionOrData where
- put_ bh IsFunction = putByte bh 0
- put_ bh IsData = putByte bh 1
- get bh = do
- h <- getByte bh
- case h of
- 0 -> return IsFunction
- 1 -> return IsData
- _ -> panic "Binary FunctionOrData"
-
-instance Binary TupleSort where
- put_ bh BoxedTuple = putByte bh 0
- put_ bh UnboxedTuple = putByte bh 1
- put_ bh ConstraintTuple = putByte bh 2
- get bh = do
- h <- getByte bh
- case h of
- 0 -> do return BoxedTuple
- 1 -> do return UnboxedTuple
- _ -> do return ConstraintTuple
-
-instance Binary Activation where
- put_ bh NeverActive = do
- putByte bh 0
- put_ bh AlwaysActive = do
- putByte bh 1
- put_ bh (ActiveBefore src aa) = do
- putByte bh 2
- put_ bh src
- put_ bh aa
- put_ bh (ActiveAfter src ab) = do
- putByte bh 3
- put_ bh src
- put_ bh ab
- get bh = do
- h <- getByte bh
- case h of
- 0 -> do return NeverActive
- 1 -> do return AlwaysActive
- 2 -> do src <- get bh
- aa <- get bh
- return (ActiveBefore src aa)
- _ -> do src <- get bh
- ab <- get bh
- return (ActiveAfter src ab)
-
-instance Binary InlinePragma where
- put_ bh (InlinePragma s a b c d) = do
- put_ bh s
- put_ bh a
- put_ bh b
- put_ bh c
- put_ bh d
-
- get bh = do
- s <- get bh
- a <- get bh
- b <- get bh
- c <- get bh
- d <- get bh
- return (InlinePragma s a b c d)
-
-instance Binary RuleMatchInfo where
- put_ bh FunLike = putByte bh 0
- put_ bh ConLike = putByte bh 1
- get bh = do
- h <- getByte bh
- if h == 1 then return ConLike
- else return FunLike
-
-instance Binary InlineSpec where
- put_ bh NoUserInline = putByte bh 0
- put_ bh Inline = putByte bh 1
- put_ bh Inlinable = putByte bh 2
- put_ bh NoInline = putByte bh 3
-
- get bh = do h <- getByte bh
- case h of
- 0 -> return NoUserInline
- 1 -> return Inline
- 2 -> return Inlinable
- _ -> return NoInline
-
-instance Binary RecFlag where
- put_ bh Recursive = do
- putByte bh 0
- put_ bh NonRecursive = do
- putByte bh 1
- get bh = do
- h <- getByte bh
- case h of
- 0 -> do return Recursive
- _ -> do return NonRecursive
-
-instance Binary OverlapMode where
- put_ bh (NoOverlap s) = putByte bh 0 >> put_ bh s
- put_ bh (Overlaps s) = putByte bh 1 >> put_ bh s
- put_ bh (Incoherent s) = putByte bh 2 >> put_ bh s
- put_ bh (Overlapping s) = putByte bh 3 >> put_ bh s
- put_ bh (Overlappable s) = putByte bh 4 >> put_ bh s
- get bh = do
- h <- getByte bh
- case h of
- 0 -> (get bh) >>= \s -> return $ NoOverlap s
- 1 -> (get bh) >>= \s -> return $ Overlaps s
- 2 -> (get bh) >>= \s -> return $ Incoherent s
- 3 -> (get bh) >>= \s -> return $ Overlapping s
- 4 -> (get bh) >>= \s -> return $ Overlappable s
- _ -> panic ("get OverlapMode" ++ show h)
-
-
-instance Binary OverlapFlag where
- put_ bh flag = do put_ bh (overlapMode flag)
- put_ bh (isSafeOverlap flag)
- get bh = do
- h <- get bh
- b <- get bh
- return OverlapFlag { overlapMode = h, isSafeOverlap = b }
-
-instance Binary FixityDirection where
- put_ bh InfixL = do
- putByte bh 0
- put_ bh InfixR = do
- putByte bh 1
- put_ bh InfixN = do
- putByte bh 2
- get bh = do
- h <- getByte bh
- case h of
- 0 -> do return InfixL
- 1 -> do return InfixR
- _ -> do return InfixN
-
-instance Binary Fixity where
- put_ bh (Fixity src aa ab) = do
- put_ bh src
- put_ bh aa
- put_ bh ab
- get bh = do
- src <- get bh
- aa <- get bh
- ab <- get bh
- return (Fixity src aa ab)
-
-instance Binary WarningTxt where
- put_ bh (WarningTxt s w) = do
- putByte bh 0
- put_ bh s
- put_ bh w
- put_ bh (DeprecatedTxt s d) = do
- putByte bh 1
- put_ bh s
- put_ bh d
-
- get bh = do
- h <- getByte bh
- case h of
- 0 -> do s <- get bh
- w <- get bh
- return (WarningTxt s w)
- _ -> do s <- get bh
- d <- get bh
- return (DeprecatedTxt s d)
-
-instance Binary StringLiteral where
- put_ bh (StringLiteral st fs) = do
- put_ bh st
- put_ bh fs
- get bh = do
- st <- get bh
- fs <- get bh
- return (StringLiteral st fs)
-
-instance Binary a => Binary (Located a) where
- put_ bh (L l x) = do
- put_ bh l
- put_ bh x
-
- get bh = do
- l <- get bh
- x <- get bh
- return (L l x)
-
-instance Binary RealSrcSpan where
- put_ bh ss = do
- put_ bh (srcSpanFile ss)
- put_ bh (srcSpanStartLine ss)
- put_ bh (srcSpanStartCol ss)
- put_ bh (srcSpanEndLine ss)
- put_ bh (srcSpanEndCol ss)
-
- get bh = do
- f <- get bh
- sl <- get bh
- sc <- get bh
- el <- get bh
- ec <- get bh
- return (mkRealSrcSpan (mkRealSrcLoc f sl sc)
- (mkRealSrcLoc f el ec))
-
-instance Binary BufPos where
- put_ bh (BufPos i) = put_ bh i
- get bh = BufPos <$> get bh
-
-instance Binary BufSpan where
- put_ bh (BufSpan start end) = do
- put_ bh start
- put_ bh end
- get bh = do
- start <- get bh
- end <- get bh
- return (BufSpan start end)
-
-instance Binary SrcSpan where
- put_ bh (RealSrcSpan ss sb) = do
- putByte bh 0
- put_ bh ss
- put_ bh sb
-
- put_ bh (UnhelpfulSpan s) = do
- putByte bh 1
- put_ bh s
-
- get bh = do
- h <- getByte bh
- case h of
- 0 -> do ss <- get bh
- sb <- get bh
- return (RealSrcSpan ss sb)
- _ -> do s <- get bh
- return (UnhelpfulSpan s)
-
-instance Binary Serialized where
- put_ bh (Serialized the_type bytes) = do
- put_ bh the_type
- put_ bh bytes
- get bh = do
- the_type <- get bh
- bytes <- get bh
- return (Serialized the_type bytes)
-
-instance Binary SourceText where
- put_ bh NoSourceText = putByte bh 0
- put_ bh (SourceText s) = do
- putByte bh 1
- put_ bh s
-
- get bh = do
- h <- getByte bh
- case h of
- 0 -> return NoSourceText
- 1 -> do
- s <- get bh
- return (SourceText s)
- _ -> panic $ "Binary SourceText:" ++ show h
diff --git a/compiler/utils/BooleanFormula.hs b/compiler/utils/BooleanFormula.hs
deleted file mode 100644
index 76d80eb305..0000000000
--- a/compiler/utils/BooleanFormula.hs
+++ /dev/null
@@ -1,262 +0,0 @@
-{-# LANGUAGE DeriveDataTypeable, DeriveFunctor, DeriveFoldable,
- DeriveTraversable #-}
-
---------------------------------------------------------------------------------
--- | Boolean formulas without quantifiers and without negation.
--- Such a formula consists of variables, conjunctions (and), and disjunctions (or).
---
--- This module is used to represent minimal complete definitions for classes.
---
-module BooleanFormula (
- BooleanFormula(..), LBooleanFormula,
- mkFalse, mkTrue, mkAnd, mkOr, mkVar,
- isFalse, isTrue,
- eval, simplify, isUnsatisfied,
- implies, impliesAtom,
- pprBooleanFormula, pprBooleanFormulaNice
- ) where
-
-import GhcPrelude
-
-import Data.List ( nub, intersperse )
-import Data.Data
-
-import MonadUtils
-import Outputable
-import Binary
-import GHC.Types.SrcLoc
-import GHC.Types.Unique
-import GHC.Types.Unique.Set
-
-----------------------------------------------------------------------
--- Boolean formula type and smart constructors
-----------------------------------------------------------------------
-
-type LBooleanFormula a = Located (BooleanFormula a)
-
-data BooleanFormula a = Var a | And [LBooleanFormula a] | Or [LBooleanFormula a]
- | Parens (LBooleanFormula a)
- deriving (Eq, Data, Functor, Foldable, Traversable)
-
-mkVar :: a -> BooleanFormula a
-mkVar = Var
-
-mkFalse, mkTrue :: BooleanFormula a
-mkFalse = Or []
-mkTrue = And []
-
--- Convert a Bool to a BooleanFormula
-mkBool :: Bool -> BooleanFormula a
-mkBool False = mkFalse
-mkBool True = mkTrue
-
--- Make a conjunction, and try to simplify
-mkAnd :: Eq a => [LBooleanFormula a] -> BooleanFormula a
-mkAnd = maybe mkFalse (mkAnd' . nub) . concatMapM fromAnd
- where
- -- See Note [Simplification of BooleanFormulas]
- fromAnd :: LBooleanFormula a -> Maybe [LBooleanFormula a]
- fromAnd (L _ (And xs)) = Just xs
- -- assume that xs are already simplified
- -- otherwise we would need: fromAnd (And xs) = concat <$> traverse fromAnd xs
- fromAnd (L _ (Or [])) = Nothing
- -- in case of False we bail out, And [..,mkFalse,..] == mkFalse
- fromAnd x = Just [x]
- mkAnd' [x] = unLoc x
- mkAnd' xs = And xs
-
-mkOr :: Eq a => [LBooleanFormula a] -> BooleanFormula a
-mkOr = maybe mkTrue (mkOr' . nub) . concatMapM fromOr
- where
- -- See Note [Simplification of BooleanFormulas]
- fromOr (L _ (Or xs)) = Just xs
- fromOr (L _ (And [])) = Nothing
- fromOr x = Just [x]
- mkOr' [x] = unLoc x
- mkOr' xs = Or xs
-
-
-{-
-Note [Simplification of BooleanFormulas]
-~~~~~~~~~~~~~~~~~~~~~~
-The smart constructors (`mkAnd` and `mkOr`) do some attempt to simplify expressions. In particular,
- 1. Collapsing nested ands and ors, so
- `(mkAnd [x, And [y,z]]`
- is represented as
- `And [x,y,z]`
- Implemented by `fromAnd`/`fromOr`
- 2. Collapsing trivial ands and ors, so
- `mkAnd [x]` becomes just `x`.
- Implemented by mkAnd' / mkOr'
- 3. Conjunction with false, disjunction with true is simplified, i.e.
- `mkAnd [mkFalse,x]` becomes `mkFalse`.
- 4. Common subexpression elimination:
- `mkAnd [x,x,y]` is reduced to just `mkAnd [x,y]`.
-
-This simplification is not exhaustive, in the sense that it will not produce
-the smallest possible equivalent expression. For example,
-`Or [And [x,y], And [x]]` could be simplified to `And [x]`, but it currently
-is not. A general simplifier would need to use something like BDDs.
-
-The reason behind the (crude) simplifier is to make for more user friendly
-error messages. E.g. for the code
- > class Foo a where
- > {-# MINIMAL bar, (foo, baq | foo, quux) #-}
- > instance Foo Int where
- > bar = ...
- > baz = ...
- > quux = ...
-We don't show a ridiculous error message like
- Implement () and (either (`foo' and ()) or (`foo' and ()))
--}
-
-----------------------------------------------------------------------
--- Evaluation and simplification
-----------------------------------------------------------------------
-
-isFalse :: BooleanFormula a -> Bool
-isFalse (Or []) = True
-isFalse _ = False
-
-isTrue :: BooleanFormula a -> Bool
-isTrue (And []) = True
-isTrue _ = False
-
-eval :: (a -> Bool) -> BooleanFormula a -> Bool
-eval f (Var x) = f x
-eval f (And xs) = all (eval f . unLoc) xs
-eval f (Or xs) = any (eval f . unLoc) xs
-eval f (Parens x) = eval f (unLoc x)
-
--- Simplify a boolean formula.
--- The argument function should give the truth of the atoms, or Nothing if undecided.
-simplify :: Eq a => (a -> Maybe Bool) -> BooleanFormula a -> BooleanFormula a
-simplify f (Var a) = case f a of
- Nothing -> Var a
- Just b -> mkBool b
-simplify f (And xs) = mkAnd (map (\(L l x) -> L l (simplify f x)) xs)
-simplify f (Or xs) = mkOr (map (\(L l x) -> L l (simplify f x)) xs)
-simplify f (Parens x) = simplify f (unLoc x)
-
--- Test if a boolean formula is satisfied when the given values are assigned to the atoms
--- if it is, returns Nothing
--- if it is not, return (Just remainder)
-isUnsatisfied :: Eq a => (a -> Bool) -> BooleanFormula a -> Maybe (BooleanFormula a)
-isUnsatisfied f bf
- | isTrue bf' = Nothing
- | otherwise = Just bf'
- where
- f' x = if f x then Just True else Nothing
- bf' = simplify f' bf
-
--- prop_simplify:
--- eval f x == True <==> isTrue (simplify (Just . f) x)
--- eval f x == False <==> isFalse (simplify (Just . f) x)
-
--- If the boolean formula holds, does that mean that the given atom is always true?
-impliesAtom :: Eq a => BooleanFormula a -> a -> Bool
-Var x `impliesAtom` y = x == y
-And xs `impliesAtom` y = any (\x -> (unLoc x) `impliesAtom` y) xs
- -- we have all of xs, so one of them implying y is enough
-Or xs `impliesAtom` y = all (\x -> (unLoc x) `impliesAtom` y) xs
-Parens x `impliesAtom` y = (unLoc x) `impliesAtom` y
-
-implies :: Uniquable a => BooleanFormula a -> BooleanFormula a -> Bool
-implies e1 e2 = go (Clause emptyUniqSet [e1]) (Clause emptyUniqSet [e2])
- where
- go :: Uniquable a => Clause a -> Clause a -> Bool
- go l@Clause{ clauseExprs = hyp:hyps } r =
- case hyp of
- Var x | memberClauseAtoms x r -> True
- | otherwise -> go (extendClauseAtoms l x) { clauseExprs = hyps } r
- Parens hyp' -> go l { clauseExprs = unLoc hyp':hyps } r
- And hyps' -> go l { clauseExprs = map unLoc hyps' ++ hyps } r
- Or hyps' -> all (\hyp' -> go l { clauseExprs = unLoc hyp':hyps } r) hyps'
- go l r@Clause{ clauseExprs = con:cons } =
- case con of
- Var x | memberClauseAtoms x l -> True
- | otherwise -> go l (extendClauseAtoms r x) { clauseExprs = cons }
- Parens con' -> go l r { clauseExprs = unLoc con':cons }
- And cons' -> all (\con' -> go l r { clauseExprs = unLoc con':cons }) cons'
- Or cons' -> go l r { clauseExprs = map unLoc cons' ++ cons }
- go _ _ = False
-
--- A small sequent calculus proof engine.
-data Clause a = Clause {
- clauseAtoms :: UniqSet a,
- clauseExprs :: [BooleanFormula a]
- }
-extendClauseAtoms :: Uniquable a => Clause a -> a -> Clause a
-extendClauseAtoms c x = c { clauseAtoms = addOneToUniqSet (clauseAtoms c) x }
-
-memberClauseAtoms :: Uniquable a => a -> Clause a -> Bool
-memberClauseAtoms x c = x `elementOfUniqSet` clauseAtoms c
-
-----------------------------------------------------------------------
--- Pretty printing
-----------------------------------------------------------------------
-
--- Pretty print a BooleanFormula,
--- using the arguments as pretty printers for Var, And and Or respectively
-pprBooleanFormula' :: (Rational -> a -> SDoc)
- -> (Rational -> [SDoc] -> SDoc)
- -> (Rational -> [SDoc] -> SDoc)
- -> Rational -> BooleanFormula a -> SDoc
-pprBooleanFormula' pprVar pprAnd pprOr = go
- where
- go p (Var x) = pprVar p x
- go p (And []) = cparen (p > 0) $ empty
- go p (And xs) = pprAnd p (map (go 3 . unLoc) xs)
- go _ (Or []) = keyword $ text "FALSE"
- go p (Or xs) = pprOr p (map (go 2 . unLoc) xs)
- go p (Parens x) = go p (unLoc x)
-
--- Pretty print in source syntax, "a | b | c,d,e"
-pprBooleanFormula :: (Rational -> a -> SDoc) -> Rational -> BooleanFormula a -> SDoc
-pprBooleanFormula pprVar = pprBooleanFormula' pprVar pprAnd pprOr
- where
- pprAnd p = cparen (p > 3) . fsep . punctuate comma
- pprOr p = cparen (p > 2) . fsep . intersperse vbar
-
--- Pretty print human in readable format, "either `a' or `b' or (`c', `d' and `e')"?
-pprBooleanFormulaNice :: Outputable a => BooleanFormula a -> SDoc
-pprBooleanFormulaNice = pprBooleanFormula' pprVar pprAnd pprOr 0
- where
- pprVar _ = quotes . ppr
- pprAnd p = cparen (p > 1) . pprAnd'
- pprAnd' [] = empty
- pprAnd' [x,y] = x <+> text "and" <+> y
- pprAnd' xs@(_:_) = fsep (punctuate comma (init xs)) <> text ", and" <+> last xs
- pprOr p xs = cparen (p > 1) $ text "either" <+> sep (intersperse (text "or") xs)
-
-instance (OutputableBndr a) => Outputable (BooleanFormula a) where
- ppr = pprBooleanFormulaNormal
-
-pprBooleanFormulaNormal :: (OutputableBndr a)
- => BooleanFormula a -> SDoc
-pprBooleanFormulaNormal = go
- where
- go (Var x) = pprPrefixOcc x
- go (And xs) = fsep $ punctuate comma (map (go . unLoc) xs)
- go (Or []) = keyword $ text "FALSE"
- go (Or xs) = fsep $ intersperse vbar (map (go . unLoc) xs)
- go (Parens x) = parens (go $ unLoc x)
-
-
-----------------------------------------------------------------------
--- Binary
-----------------------------------------------------------------------
-
-instance Binary a => Binary (BooleanFormula a) where
- put_ bh (Var x) = putByte bh 0 >> put_ bh x
- put_ bh (And xs) = putByte bh 1 >> put_ bh xs
- put_ bh (Or xs) = putByte bh 2 >> put_ bh xs
- put_ bh (Parens x) = putByte bh 3 >> put_ bh x
-
- get bh = do
- h <- getByte bh
- case h of
- 0 -> Var <$> get bh
- 1 -> And <$> get bh
- 2 -> Or <$> get bh
- _ -> Parens <$> get bh
diff --git a/compiler/utils/BufWrite.hs b/compiler/utils/BufWrite.hs
deleted file mode 100644
index 8a28f470f4..0000000000
--- a/compiler/utils/BufWrite.hs
+++ /dev/null
@@ -1,145 +0,0 @@
-{-# LANGUAGE BangPatterns #-}
-
------------------------------------------------------------------------------
---
--- Fast write-buffered Handles
---
--- (c) The University of Glasgow 2005-2006
---
--- This is a simple abstraction over Handles that offers very fast write
--- buffering, but without the thread safety that Handles provide. It's used
--- to save time in Pretty.printDoc.
---
------------------------------------------------------------------------------
-
-module BufWrite (
- BufHandle(..),
- newBufHandle,
- bPutChar,
- bPutStr,
- bPutFS,
- bPutFZS,
- bPutPtrString,
- bPutReplicate,
- bFlush,
- ) where
-
-import GhcPrelude
-
-import FastString
-import FastMutInt
-
-import Control.Monad ( when )
-import Data.ByteString (ByteString)
-import qualified Data.ByteString.Unsafe as BS
-import Data.Char ( ord )
-import Foreign
-import Foreign.C.String
-import System.IO
-
--- -----------------------------------------------------------------------------
-
-data BufHandle = BufHandle {-#UNPACK#-}!(Ptr Word8)
- {-#UNPACK#-}!FastMutInt
- Handle
-
-newBufHandle :: Handle -> IO BufHandle
-newBufHandle hdl = do
- ptr <- mallocBytes buf_size
- r <- newFastMutInt
- writeFastMutInt r 0
- return (BufHandle ptr r hdl)
-
-buf_size :: Int
-buf_size = 8192
-
-bPutChar :: BufHandle -> Char -> IO ()
-bPutChar b@(BufHandle buf r hdl) !c = do
- i <- readFastMutInt r
- if (i >= buf_size)
- then do hPutBuf hdl buf buf_size
- writeFastMutInt r 0
- bPutChar b c
- else do pokeElemOff buf i (fromIntegral (ord c) :: Word8)
- writeFastMutInt r (i+1)
-
-bPutStr :: BufHandle -> String -> IO ()
-bPutStr (BufHandle buf r hdl) !str = do
- i <- readFastMutInt r
- loop str i
- where loop "" !i = do writeFastMutInt r i; return ()
- loop (c:cs) !i
- | i >= buf_size = do
- hPutBuf hdl buf buf_size
- loop (c:cs) 0
- | otherwise = do
- pokeElemOff buf i (fromIntegral (ord c))
- loop cs (i+1)
-
-bPutFS :: BufHandle -> FastString -> IO ()
-bPutFS b fs = bPutBS b $ bytesFS fs
-
-bPutFZS :: BufHandle -> FastZString -> IO ()
-bPutFZS b fs = bPutBS b $ fastZStringToByteString fs
-
-bPutBS :: BufHandle -> ByteString -> IO ()
-bPutBS b bs = BS.unsafeUseAsCStringLen bs $ bPutCStringLen b
-
-bPutCStringLen :: BufHandle -> CStringLen -> IO ()
-bPutCStringLen b@(BufHandle buf r hdl) cstr@(ptr, len) = do
- i <- readFastMutInt r
- if (i + len) >= buf_size
- then do hPutBuf hdl buf i
- writeFastMutInt r 0
- if (len >= buf_size)
- then hPutBuf hdl ptr len
- else bPutCStringLen b cstr
- else do
- copyBytes (buf `plusPtr` i) ptr len
- writeFastMutInt r (i + len)
-
-bPutPtrString :: BufHandle -> PtrString -> IO ()
-bPutPtrString b@(BufHandle buf r hdl) l@(PtrString a len) = l `seq` do
- i <- readFastMutInt r
- if (i+len) >= buf_size
- then do hPutBuf hdl buf i
- writeFastMutInt r 0
- if (len >= buf_size)
- then hPutBuf hdl a len
- else bPutPtrString b l
- else do
- copyBytes (buf `plusPtr` i) a len
- writeFastMutInt r (i+len)
-
--- | Replicate an 8-bit character
-bPutReplicate :: BufHandle -> Int -> Char -> IO ()
-bPutReplicate (BufHandle buf r hdl) len c = do
- i <- readFastMutInt r
- let oc = fromIntegral (ord c)
- if (i+len) < buf_size
- then do
- fillBytes (buf `plusPtr` i) oc len
- writeFastMutInt r (i+len)
- else do
- -- flush the current buffer
- when (i /= 0) $ hPutBuf hdl buf i
- if (len < buf_size)
- then do
- fillBytes buf oc len
- writeFastMutInt r len
- else do
- -- fill a full buffer
- fillBytes buf oc buf_size
- -- flush it as many times as necessary
- let go n | n >= buf_size = do
- hPutBuf hdl buf buf_size
- go (n-buf_size)
- | otherwise = writeFastMutInt r n
- go len
-
-bFlush :: BufHandle -> IO ()
-bFlush (BufHandle buf r hdl) = do
- i <- readFastMutInt r
- when (i > 0) $ hPutBuf hdl buf i
- free buf
- return ()
diff --git a/compiler/utils/Digraph.hs b/compiler/utils/Digraph.hs
deleted file mode 100644
index ad5fbf53c3..0000000000
--- a/compiler/utils/Digraph.hs
+++ /dev/null
@@ -1,524 +0,0 @@
--- (c) The University of Glasgow 2006
-
-{-# LANGUAGE CPP, ScopedTypeVariables, ViewPatterns #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-
-module Digraph(
- Graph, graphFromEdgedVerticesOrd, graphFromEdgedVerticesUniq,
-
- SCC(..), Node(..), flattenSCC, flattenSCCs,
- stronglyConnCompG,
- topologicalSortG,
- verticesG, edgesG, hasVertexG,
- reachableG, reachablesG, transposeG,
- emptyG,
-
- findCycle,
-
- -- For backwards compatibility with the simpler version of Digraph
- stronglyConnCompFromEdgedVerticesOrd,
- stronglyConnCompFromEdgedVerticesOrdR,
- stronglyConnCompFromEdgedVerticesUniq,
- stronglyConnCompFromEdgedVerticesUniqR,
-
- -- Simple way to classify edges
- EdgeType(..), classifyEdges
- ) where
-
-#include "HsVersions.h"
-
-------------------------------------------------------------------------------
--- A version of the graph algorithms described in:
---
--- ``Lazy Depth-First Search and Linear IntGraph Algorithms in Haskell''
--- by David King and John Launchbury
---
--- Also included is some additional code for printing tree structures ...
---
--- If you ever find yourself in need of algorithms for classifying edges,
--- or finding connected/biconnected components, consult the history; Sigbjorn
--- Finne contributed some implementations in 1997, although we've since
--- removed them since they were not used anywhere in GHC.
-------------------------------------------------------------------------------
-
-
-import GhcPrelude
-
-import Util ( minWith, count )
-import Outputable
-import Maybes ( expectJust )
-
--- std interfaces
-import Data.Maybe
-import Data.Array
-import Data.List hiding (transpose)
-import qualified Data.Map as Map
-import qualified Data.Set as Set
-
-import qualified Data.Graph as G
-import Data.Graph hiding (Graph, Edge, transposeG, reachable)
-import Data.Tree
-import GHC.Types.Unique
-import GHC.Types.Unique.FM
-
-{-
-************************************************************************
-* *
-* Graphs and Graph Construction
-* *
-************************************************************************
-
-Note [Nodes, keys, vertices]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- * A 'node' is a big blob of client-stuff
-
- * Each 'node' has a unique (client) 'key', but the latter
- is in Ord and has fast comparison
-
- * Digraph then maps each 'key' to a Vertex (Int) which is
- arranged densely in 0.n
--}
-
-data Graph node = Graph {
- gr_int_graph :: IntGraph,
- gr_vertex_to_node :: Vertex -> node,
- gr_node_to_vertex :: node -> Maybe Vertex
- }
-
-data Edge node = Edge node node
-
-{-| Representation for nodes of the Graph.
-
- * The @payload@ is user data, just carried around in this module
-
- * The @key@ is the node identifier.
- Key has an Ord instance for performance reasons.
-
- * The @[key]@ are the dependencies of the node;
- it's ok to have extra keys in the dependencies that
- are not the key of any Node in the graph
--}
-data Node key payload = DigraphNode {
- node_payload :: payload, -- ^ User data
- node_key :: key, -- ^ User defined node id
- node_dependencies :: [key] -- ^ Dependencies/successors of the node
- }
-
-
-instance (Outputable a, Outputable b) => Outputable (Node a b) where
- ppr (DigraphNode a b c) = ppr (a, b, c)
-
-emptyGraph :: Graph a
-emptyGraph = Graph (array (1, 0) []) (error "emptyGraph") (const Nothing)
-
--- See Note [Deterministic SCC]
-graphFromEdgedVertices
- :: ReduceFn key payload
- -> [Node key payload] -- The graph; its ok for the
- -- out-list to contain keys which aren't
- -- a vertex key, they are ignored
- -> Graph (Node key payload)
-graphFromEdgedVertices _reduceFn [] = emptyGraph
-graphFromEdgedVertices reduceFn edged_vertices =
- Graph graph vertex_fn (key_vertex . key_extractor)
- where key_extractor = node_key
- (bounds, vertex_fn, key_vertex, numbered_nodes) =
- reduceFn edged_vertices key_extractor
- graph = array bounds [ (v, sort $ mapMaybe key_vertex ks)
- | (v, (node_dependencies -> ks)) <- numbered_nodes]
- -- We normalize outgoing edges by sorting on node order, so
- -- that the result doesn't depend on the order of the edges
-
--- See Note [Deterministic SCC]
--- See Note [reduceNodesIntoVertices implementations]
-graphFromEdgedVerticesOrd
- :: Ord key
- => [Node key payload] -- The graph; its ok for the
- -- out-list to contain keys which aren't
- -- a vertex key, they are ignored
- -> Graph (Node key payload)
-graphFromEdgedVerticesOrd = graphFromEdgedVertices reduceNodesIntoVerticesOrd
-
--- See Note [Deterministic SCC]
--- See Note [reduceNodesIntoVertices implementations]
-graphFromEdgedVerticesUniq
- :: Uniquable key
- => [Node key payload] -- The graph; its ok for the
- -- out-list to contain keys which aren't
- -- a vertex key, they are ignored
- -> Graph (Node key payload)
-graphFromEdgedVerticesUniq = graphFromEdgedVertices reduceNodesIntoVerticesUniq
-
-type ReduceFn key payload =
- [Node key payload] -> (Node key payload -> key) ->
- (Bounds, Vertex -> Node key payload
- , key -> Maybe Vertex, [(Vertex, Node key payload)])
-
-{-
-Note [reduceNodesIntoVertices implementations]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-reduceNodesIntoVertices is parameterized by the container type.
-This is to accommodate key types that don't have an Ord instance
-and hence preclude the use of Data.Map. An example of such type
-would be Unique, there's no way to implement Ord Unique
-deterministically.
-
-For such types, there's a version with a Uniquable constraint.
-This leaves us with two versions of every function that depends on
-reduceNodesIntoVertices, one with Ord constraint and the other with
-Uniquable constraint.
-For example: graphFromEdgedVerticesOrd and graphFromEdgedVerticesUniq.
-
-The Uniq version should be a tiny bit more efficient since it uses
-Data.IntMap internally.
--}
-reduceNodesIntoVertices
- :: ([(key, Vertex)] -> m)
- -> (key -> m -> Maybe Vertex)
- -> ReduceFn key payload
-reduceNodesIntoVertices fromList lookup nodes key_extractor =
- (bounds, (!) vertex_map, key_vertex, numbered_nodes)
- where
- max_v = length nodes - 1
- bounds = (0, max_v) :: (Vertex, Vertex)
-
- -- Keep the order intact to make the result depend on input order
- -- instead of key order
- numbered_nodes = zip [0..] nodes
- vertex_map = array bounds numbered_nodes
-
- key_map = fromList
- [ (key_extractor node, v) | (v, node) <- numbered_nodes ]
- key_vertex k = lookup k key_map
-
--- See Note [reduceNodesIntoVertices implementations]
-reduceNodesIntoVerticesOrd :: Ord key => ReduceFn key payload
-reduceNodesIntoVerticesOrd = reduceNodesIntoVertices Map.fromList Map.lookup
-
--- See Note [reduceNodesIntoVertices implementations]
-reduceNodesIntoVerticesUniq :: Uniquable key => ReduceFn key payload
-reduceNodesIntoVerticesUniq = reduceNodesIntoVertices listToUFM (flip lookupUFM)
-
-{-
-************************************************************************
-* *
-* SCC
-* *
-************************************************************************
--}
-
-type WorkItem key payload
- = (Node key payload, -- Tip of the path
- [payload]) -- Rest of the path;
- -- [a,b,c] means c depends on b, b depends on a
-
--- | Find a reasonably short cycle a->b->c->a, in a strongly
--- connected component. The input nodes are presumed to be
--- a SCC, so you can start anywhere.
-findCycle :: forall payload key. Ord key
- => [Node key payload] -- The nodes. The dependencies can
- -- contain extra keys, which are ignored
- -> Maybe [payload] -- A cycle, starting with node
- -- so each depends on the next
-findCycle graph
- = go Set.empty (new_work root_deps []) []
- where
- env :: Map.Map key (Node key payload)
- env = Map.fromList [ (node_key node, node) | node <- graph ]
-
- -- Find the node with fewest dependencies among the SCC modules
- -- This is just a heuristic to find some plausible root module
- root :: Node key payload
- root = fst (minWith snd [ (node, count (`Map.member` env)
- (node_dependencies node))
- | node <- graph ])
- DigraphNode root_payload root_key root_deps = root
-
-
- -- 'go' implements Dijkstra's algorithm, more or less
- go :: Set.Set key -- Visited
- -> [WorkItem key payload] -- Work list, items length n
- -> [WorkItem key payload] -- Work list, items length n+1
- -> Maybe [payload] -- Returned cycle
- -- Invariant: in a call (go visited ps qs),
- -- visited = union (map tail (ps ++ qs))
-
- go _ [] [] = Nothing -- No cycles
- go visited [] qs = go visited qs []
- go visited (((DigraphNode payload key deps), path) : ps) qs
- | key == root_key = Just (root_payload : reverse path)
- | key `Set.member` visited = go visited ps qs
- | key `Map.notMember` env = go visited ps qs
- | otherwise = go (Set.insert key visited)
- ps (new_qs ++ qs)
- where
- new_qs = new_work deps (payload : path)
-
- new_work :: [key] -> [payload] -> [WorkItem key payload]
- new_work deps path = [ (n, path) | Just n <- map (`Map.lookup` env) deps ]
-
-{-
-************************************************************************
-* *
-* Strongly Connected Component wrappers for Graph
-* *
-************************************************************************
-
-Note: the components are returned topologically sorted: later components
-depend on earlier ones, but not vice versa i.e. later components only have
-edges going from them to earlier ones.
--}
-
-{-
-Note [Deterministic SCC]
-~~~~~~~~~~~~~~~~~~~~~~~~
-stronglyConnCompFromEdgedVerticesUniq,
-stronglyConnCompFromEdgedVerticesUniqR,
-stronglyConnCompFromEdgedVerticesOrd and
-stronglyConnCompFromEdgedVerticesOrdR
-provide a following guarantee:
-Given a deterministically ordered list of nodes it returns a deterministically
-ordered list of strongly connected components, where the list of vertices
-in an SCC is also deterministically ordered.
-Note that the order of edges doesn't need to be deterministic for this to work.
-We use the order of nodes to normalize the order of edges.
--}
-
-stronglyConnCompG :: Graph node -> [SCC node]
-stronglyConnCompG graph = decodeSccs graph forest
- where forest = {-# SCC "Digraph.scc" #-} scc (gr_int_graph graph)
-
-decodeSccs :: Graph node -> Forest Vertex -> [SCC node]
-decodeSccs Graph { gr_int_graph = graph, gr_vertex_to_node = vertex_fn } forest
- = map decode forest
- where
- decode (Node v []) | mentions_itself v = CyclicSCC [vertex_fn v]
- | otherwise = AcyclicSCC (vertex_fn v)
- decode other = CyclicSCC (dec other [])
- where dec (Node v ts) vs = vertex_fn v : foldr dec vs ts
- mentions_itself v = v `elem` (graph ! v)
-
-
--- The following two versions are provided for backwards compatibility:
--- See Note [Deterministic SCC]
--- See Note [reduceNodesIntoVertices implementations]
-stronglyConnCompFromEdgedVerticesOrd
- :: Ord key
- => [Node key payload]
- -> [SCC payload]
-stronglyConnCompFromEdgedVerticesOrd
- = map (fmap node_payload) . stronglyConnCompFromEdgedVerticesOrdR
-
--- The following two versions are provided for backwards compatibility:
--- See Note [Deterministic SCC]
--- See Note [reduceNodesIntoVertices implementations]
-stronglyConnCompFromEdgedVerticesUniq
- :: Uniquable key
- => [Node key payload]
- -> [SCC payload]
-stronglyConnCompFromEdgedVerticesUniq
- = map (fmap node_payload) . stronglyConnCompFromEdgedVerticesUniqR
-
--- The "R" interface is used when you expect to apply SCC to
--- (some of) the result of SCC, so you don't want to lose the dependency info
--- See Note [Deterministic SCC]
--- See Note [reduceNodesIntoVertices implementations]
-stronglyConnCompFromEdgedVerticesOrdR
- :: Ord key
- => [Node key payload]
- -> [SCC (Node key payload)]
-stronglyConnCompFromEdgedVerticesOrdR =
- stronglyConnCompG . graphFromEdgedVertices reduceNodesIntoVerticesOrd
-
--- The "R" interface is used when you expect to apply SCC to
--- (some of) the result of SCC, so you don't want to lose the dependency info
--- See Note [Deterministic SCC]
--- See Note [reduceNodesIntoVertices implementations]
-stronglyConnCompFromEdgedVerticesUniqR
- :: Uniquable key
- => [Node key payload]
- -> [SCC (Node key payload)]
-stronglyConnCompFromEdgedVerticesUniqR =
- stronglyConnCompG . graphFromEdgedVertices reduceNodesIntoVerticesUniq
-
-{-
-************************************************************************
-* *
-* Misc wrappers for Graph
-* *
-************************************************************************
--}
-
-topologicalSortG :: Graph node -> [node]
-topologicalSortG graph = map (gr_vertex_to_node graph) result
- where result = {-# SCC "Digraph.topSort" #-} topSort (gr_int_graph graph)
-
-reachableG :: Graph node -> node -> [node]
-reachableG graph from = map (gr_vertex_to_node graph) result
- where from_vertex = expectJust "reachableG" (gr_node_to_vertex graph from)
- result = {-# SCC "Digraph.reachable" #-} reachable (gr_int_graph graph) [from_vertex]
-
--- | Given a list of roots return all reachable nodes.
-reachablesG :: Graph node -> [node] -> [node]
-reachablesG graph froms = map (gr_vertex_to_node graph) result
- where result = {-# SCC "Digraph.reachable" #-}
- reachable (gr_int_graph graph) vs
- vs = [ v | Just v <- map (gr_node_to_vertex graph) froms ]
-
-hasVertexG :: Graph node -> node -> Bool
-hasVertexG graph node = isJust $ gr_node_to_vertex graph node
-
-verticesG :: Graph node -> [node]
-verticesG graph = map (gr_vertex_to_node graph) $ vertices (gr_int_graph graph)
-
-edgesG :: Graph node -> [Edge node]
-edgesG graph = map (\(v1, v2) -> Edge (v2n v1) (v2n v2)) $ edges (gr_int_graph graph)
- where v2n = gr_vertex_to_node graph
-
-transposeG :: Graph node -> Graph node
-transposeG graph = Graph (G.transposeG (gr_int_graph graph))
- (gr_vertex_to_node graph)
- (gr_node_to_vertex graph)
-
-emptyG :: Graph node -> Bool
-emptyG g = graphEmpty (gr_int_graph g)
-
-{-
-************************************************************************
-* *
-* Showing Graphs
-* *
-************************************************************************
--}
-
-instance Outputable node => Outputable (Graph node) where
- ppr graph = vcat [
- hang (text "Vertices:") 2 (vcat (map ppr $ verticesG graph)),
- hang (text "Edges:") 2 (vcat (map ppr $ edgesG graph))
- ]
-
-instance Outputable node => Outputable (Edge node) where
- ppr (Edge from to) = ppr from <+> text "->" <+> ppr to
-
-graphEmpty :: G.Graph -> Bool
-graphEmpty g = lo > hi
- where (lo, hi) = bounds g
-
-{-
-************************************************************************
-* *
-* IntGraphs
-* *
-************************************************************************
--}
-
-type IntGraph = G.Graph
-
-{-
-------------------------------------------------------------
--- Depth first search numbering
-------------------------------------------------------------
--}
-
--- Data.Tree has flatten for Tree, but nothing for Forest
-preorderF :: Forest a -> [a]
-preorderF ts = concatMap flatten ts
-
-{-
-------------------------------------------------------------
--- Finding reachable vertices
-------------------------------------------------------------
--}
-
--- This generalizes reachable which was found in Data.Graph
-reachable :: IntGraph -> [Vertex] -> [Vertex]
-reachable g vs = preorderF (dfs g vs)
-
-{-
-************************************************************************
-* *
-* Classify Edge Types
-* *
-************************************************************************
--}
-
--- Remark: While we could generalize this algorithm this comes at a runtime
--- cost and with no advantages. If you find yourself using this with graphs
--- not easily represented using Int nodes please consider rewriting this
--- using the more general Graph type.
-
--- | Edge direction based on DFS Classification
-data EdgeType
- = Forward
- | Cross
- | Backward -- ^ Loop back towards the root node.
- -- Eg backjumps in loops
- | SelfLoop -- ^ v -> v
- deriving (Eq,Ord)
-
-instance Outputable EdgeType where
- ppr Forward = text "Forward"
- ppr Cross = text "Cross"
- ppr Backward = text "Backward"
- ppr SelfLoop = text "SelfLoop"
-
-newtype Time = Time Int deriving (Eq,Ord,Num,Outputable)
-
---Allow for specialization
-{-# INLINEABLE classifyEdges #-}
-
--- | Given a start vertex, a way to get successors from a node
--- and a list of (directed) edges classify the types of edges.
-classifyEdges :: forall key. Uniquable key => key -> (key -> [key])
- -> [(key,key)] -> [((key, key), EdgeType)]
-classifyEdges root getSucc edges =
- --let uqe (from,to) = (getUnique from, getUnique to)
- --in pprTrace "Edges:" (ppr $ map uqe edges) $
- zip edges $ map classify edges
- where
- (_time, starts, ends) = addTimes (0,emptyUFM,emptyUFM) root
- classify :: (key,key) -> EdgeType
- classify (from,to)
- | startFrom < startTo
- , endFrom > endTo
- = Forward
- | startFrom > startTo
- , endFrom < endTo
- = Backward
- | startFrom > startTo
- , endFrom > endTo
- = Cross
- | getUnique from == getUnique to
- = SelfLoop
- | otherwise
- = pprPanic "Failed to classify edge of Graph"
- (ppr (getUnique from, getUnique to))
-
- where
- getTime event node
- | Just time <- lookupUFM event node
- = time
- | otherwise
- = pprPanic "Failed to classify edge of CFG - not not timed"
- (text "edges" <> ppr (getUnique from, getUnique to)
- <+> ppr starts <+> ppr ends )
- startFrom = getTime starts from
- startTo = getTime starts to
- endFrom = getTime ends from
- endTo = getTime ends to
-
- addTimes :: (Time, UniqFM Time, UniqFM Time) -> key
- -> (Time, UniqFM Time, UniqFM Time)
- addTimes (time,starts,ends) n
- --Dont reenter nodes
- | elemUFM n starts
- = (time,starts,ends)
- | otherwise =
- let
- starts' = addToUFM starts n time
- time' = time + 1
- succs = getSucc n :: [key]
- (time'',starts'',ends') = foldl' addTimes (time',starts',ends) succs
- ends'' = addToUFM ends' n time''
- in
- (time'' + 1, starts'', ends'')
diff --git a/compiler/utils/Encoding.hs b/compiler/utils/Encoding.hs
deleted file mode 100644
index b4af68621d..0000000000
--- a/compiler/utils/Encoding.hs
+++ /dev/null
@@ -1,450 +0,0 @@
-{-# LANGUAGE BangPatterns, MagicHash, UnboxedTuples #-}
-{-# OPTIONS_GHC -O2 #-}
--- We always optimise this, otherwise performance of a non-optimised
--- compiler is severely affected
-
--- -----------------------------------------------------------------------------
---
--- (c) The University of Glasgow, 1997-2006
---
--- Character encodings
---
--- -----------------------------------------------------------------------------
-
-module Encoding (
- -- * UTF-8
- utf8DecodeChar#,
- utf8PrevChar,
- utf8CharStart,
- utf8DecodeChar,
- utf8DecodeByteString,
- utf8DecodeStringLazy,
- utf8EncodeChar,
- utf8EncodeString,
- utf8EncodedLength,
- countUTF8Chars,
-
- -- * Z-encoding
- zEncodeString,
- zDecodeString,
-
- -- * Base62-encoding
- toBase62,
- toBase62Padded
- ) where
-
-import GhcPrelude
-
-import Foreign
-import Foreign.ForeignPtr.Unsafe
-import Data.Char
-import qualified Data.Char as Char
-import Numeric
-import GHC.IO
-
-import Data.ByteString (ByteString)
-import qualified Data.ByteString.Internal as BS
-
-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 StringBuffer.hs).
-
-{-# INLINE utf8DecodeChar# #-}
-utf8DecodeChar# :: Addr# -> (# Char#, Int# #)
-utf8DecodeChar# a# =
- let !ch0 = word2Int# (indexWord8OffAddr# a# 0#) in
- case () of
- _ | isTrue# (ch0 <=# 0x7F#) -> (# chr# ch0, 1# #)
-
- | isTrue# ((ch0 >=# 0xC0#) `andI#` (ch0 <=# 0xDF#)) ->
- let !ch1 = word2Int# (indexWord8OffAddr# a# 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# (indexWord8OffAddr# a# 1#) in
- if isTrue# ((ch1 <# 0x80#) `orI#` (ch1 >=# 0xC0#)) then fail 1# else
- let !ch2 = word2Int# (indexWord8OffAddr# a# 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# (indexWord8OffAddr# a# 1#) in
- if isTrue# ((ch1 <# 0x80#) `orI#` (ch1 >=# 0xC0#)) then fail 1# else
- let !ch2 = word2Int# (indexWord8OffAddr# a# 2#) in
- if isTrue# ((ch2 <# 0x80#) `orI#` (ch2 >=# 0xC0#)) then fail 2# else
- let !ch3 = word2Int# (indexWord8OffAddr# a# 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.
-
-utf8DecodeChar :: Ptr Word8 -> (Char, Int)
-utf8DecodeChar (Ptr a#) =
- case utf8DecodeChar# a# 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
-
-utf8DecodeByteString :: ByteString -> [Char]
-utf8DecodeByteString (BS.PS ptr offset len)
- = utf8DecodeStringLazy ptr offset len
-
-utf8DecodeStringLazy :: ForeignPtr Word8 -> Int -> Int -> [Char]
-utf8DecodeStringLazy fptr offset len
- = unsafeDupablePerformIO $ unpack start
- where
- !start = unsafeForeignPtrToPtr fptr `plusPtr` offset
- !end = start `plusPtr` len
-
- unpack p
- | p >= end = touchForeignPtr fptr >> return []
- | otherwise =
- case utf8DecodeChar# (unPtr p) of
- (# c#, nBytes# #) -> do
- rest <- unsafeDupableInterleaveIO $ unpack (p `plusPtr#` nBytes#)
- return (C# c# : rest)
-
-countUTF8Chars :: Ptr Word8 -> Int -> IO Int
-countUTF8Chars ptr len = go ptr 0
- where
- !end = ptr `plusPtr` len
-
- go p !n
- | p >= end = return n
- | otherwise = do
- case utf8DecodeChar# (unPtr p) of
- (# _, nBytes# #) -> go (p `plusPtr#` nBytes#) (n+1)
-
-unPtr :: Ptr a -> Addr#
-unPtr (Ptr a) = a
-
-plusPtr# :: Ptr a -> Int# -> Ptr a
-plusPtr# ptr nBytes# = ptr `plusPtr` (I# nBytes#)
-
-utf8EncodeChar :: Char -> Ptr Word8 -> IO (Ptr Word8)
-utf8EncodeChar c ptr =
- let x = ord c in
- case () of
- _ | x > 0 && x <= 0x007f -> do
- poke ptr (fromIntegral x)
- return (ptr `plusPtr` 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
- poke ptr (fromIntegral (0xC0 .|. ((x `shiftR` 6) .&. 0x1F)))
- pokeElemOff ptr 1 (fromIntegral (0x80 .|. (x .&. 0x3F)))
- return (ptr `plusPtr` 2)
- | x <= 0xffff -> do
- poke ptr (fromIntegral (0xE0 .|. (x `shiftR` 12) .&. 0x0F))
- pokeElemOff ptr 1 (fromIntegral (0x80 .|. (x `shiftR` 6) .&. 0x3F))
- pokeElemOff ptr 2 (fromIntegral (0x80 .|. (x .&. 0x3F)))
- return (ptr `plusPtr` 3)
- | otherwise -> do
- poke ptr (fromIntegral (0xF0 .|. (x `shiftR` 18)))
- pokeElemOff ptr 1 (fromIntegral (0x80 .|. ((x `shiftR` 12) .&. 0x3F)))
- pokeElemOff ptr 2 (fromIntegral (0x80 .|. ((x `shiftR` 6) .&. 0x3F)))
- pokeElemOff ptr 3 (fromIntegral (0x80 .|. (x .&. 0x3F)))
- return (ptr `plusPtr` 4)
-
-utf8EncodeString :: Ptr Word8 -> String -> IO ()
-utf8EncodeString ptr str = go ptr str
- where go !_ [] = return ()
- go ptr (c:cs) = do
- ptr' <- utf8EncodeChar c ptr
- go ptr' 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
-
--- -----------------------------------------------------------------------------
--- The Z-encoding
-
-{-
-This is the main name-encoding and decoding function. It encodes any
-string into a string that is acceptable as a C name. This is done
-right before we emit a symbol name into the compiled C or asm code.
-Z-encoding of strings is cached in the FastString interface, so we
-never encode the same string more than once.
-
-The basic encoding scheme is this.
-
-* Tuples (,,,) are coded as Z3T
-
-* Alphabetic characters (upper and lower) and digits
- all translate to themselves;
- except 'Z', which translates to 'ZZ'
- and 'z', which translates to 'zz'
- We need both so that we can preserve the variable/tycon distinction
-
-* Most other printable characters translate to 'zx' or 'Zx' for some
- alphabetic character x
-
-* The others translate as 'znnnU' where 'nnn' is the decimal number
- of the character
-
- Before After
- --------------------------
- Trak Trak
- foo_wib foozuwib
- > zg
- >1 zg1
- foo# foozh
- foo## foozhzh
- foo##1 foozhzh1
- fooZ fooZZ
- :+ ZCzp
- () Z0T 0-tuple
- (,,,,) Z5T 5-tuple
- (# #) Z1H unboxed 1-tuple (note the space)
- (#,,,,#) Z5H unboxed 5-tuple
- (NB: There is no Z1T nor Z0H.)
--}
-
-type UserString = String -- As the user typed it
-type EncodedString = String -- Encoded form
-
-
-zEncodeString :: UserString -> EncodedString
-zEncodeString cs = case maybe_tuple cs of
- Just n -> n -- Tuples go to Z2T etc
- Nothing -> go cs
- where
- go [] = []
- go (c:cs) = encode_digit_ch c ++ go' cs
- go' [] = []
- go' (c:cs) = encode_ch c ++ go' cs
-
-unencodedChar :: Char -> Bool -- True for chars that don't need encoding
-unencodedChar 'Z' = False
-unencodedChar 'z' = False
-unencodedChar c = c >= 'a' && c <= 'z'
- || c >= 'A' && c <= 'Z'
- || c >= '0' && c <= '9'
-
--- If a digit is at the start of a symbol then we need to encode it.
--- Otherwise package names like 9pH-0.1 give linker errors.
-encode_digit_ch :: Char -> EncodedString
-encode_digit_ch c | c >= '0' && c <= '9' = encode_as_unicode_char c
-encode_digit_ch c | otherwise = encode_ch c
-
-encode_ch :: Char -> EncodedString
-encode_ch c | unencodedChar c = [c] -- Common case first
-
--- Constructors
-encode_ch '(' = "ZL" -- Needed for things like (,), and (->)
-encode_ch ')' = "ZR" -- For symmetry with (
-encode_ch '[' = "ZM"
-encode_ch ']' = "ZN"
-encode_ch ':' = "ZC"
-encode_ch 'Z' = "ZZ"
-
--- Variables
-encode_ch 'z' = "zz"
-encode_ch '&' = "za"
-encode_ch '|' = "zb"
-encode_ch '^' = "zc"
-encode_ch '$' = "zd"
-encode_ch '=' = "ze"
-encode_ch '>' = "zg"
-encode_ch '#' = "zh"
-encode_ch '.' = "zi"
-encode_ch '<' = "zl"
-encode_ch '-' = "zm"
-encode_ch '!' = "zn"
-encode_ch '+' = "zp"
-encode_ch '\'' = "zq"
-encode_ch '\\' = "zr"
-encode_ch '/' = "zs"
-encode_ch '*' = "zt"
-encode_ch '_' = "zu"
-encode_ch '%' = "zv"
-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
- 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
- -- could remove the 'U' in the middle (the 'z' works as a separator).
-
-zDecodeString :: EncodedString -> UserString
-zDecodeString [] = []
-zDecodeString ('Z' : d : rest)
- | isDigit d = decode_tuple d rest
- | otherwise = decode_upper d : zDecodeString rest
-zDecodeString ('z' : d : rest)
- | isDigit d = decode_num_esc d rest
- | otherwise = decode_lower d : zDecodeString rest
-zDecodeString (c : rest) = c : zDecodeString rest
-
-decode_upper, decode_lower :: Char -> Char
-
-decode_upper 'L' = '('
-decode_upper 'R' = ')'
-decode_upper 'M' = '['
-decode_upper 'N' = ']'
-decode_upper 'C' = ':'
-decode_upper 'Z' = 'Z'
-decode_upper ch = {-pprTrace "decode_upper" (char ch)-} ch
-
-decode_lower 'z' = 'z'
-decode_lower 'a' = '&'
-decode_lower 'b' = '|'
-decode_lower 'c' = '^'
-decode_lower 'd' = '$'
-decode_lower 'e' = '='
-decode_lower 'g' = '>'
-decode_lower 'h' = '#'
-decode_lower 'i' = '.'
-decode_lower 'l' = '<'
-decode_lower 'm' = '-'
-decode_lower 'n' = '!'
-decode_lower 'p' = '+'
-decode_lower 'q' = '\''
-decode_lower 'r' = '\\'
-decode_lower 's' = '/'
-decode_lower 't' = '*'
-decode_lower 'u' = '_'
-decode_lower 'v' = '%'
-decode_lower ch = {-pprTrace "decode_lower" (char ch)-} ch
-
--- Characters not having a specific code are coded as z224U (in hex)
-decode_num_esc :: Char -> EncodedString -> UserString
-decode_num_esc d rest
- = go (digitToInt d) rest
- where
- go n (c : rest) | isHexDigit c = go (16*n + digitToInt c) rest
- go n ('U' : rest) = chr n : zDecodeString rest
- go n other = error ("decode_num_esc: " ++ show n ++ ' ':other)
-
-decode_tuple :: Char -> EncodedString -> UserString
-decode_tuple d rest
- = go (digitToInt d) rest
- where
- -- NB. recurse back to zDecodeString after decoding the tuple, because
- -- the tuple might be embedded in a longer name.
- go n (c : rest) | isDigit c = go (10*n + digitToInt c) rest
- go 0 ('T':rest) = "()" ++ zDecodeString rest
- go n ('T':rest) = '(' : replicate (n-1) ',' ++ ")" ++ zDecodeString rest
- go 1 ('H':rest) = "(# #)" ++ zDecodeString rest
- go n ('H':rest) = '(' : '#' : replicate (n-1) ',' ++ "#)" ++ zDecodeString rest
- go n other = error ("decode_tuple: " ++ show n ++ ' ':other)
-
-{-
-Tuples are encoded as
- Z3T or Z3H
-for 3-tuples or unboxed 3-tuples respectively. No other encoding starts
- Z<digit>
-
-* "(# #)" is the tycon for an unboxed 1-tuple (not 0-tuple)
- There are no unboxed 0-tuples.
-
-* "()" is the tycon for a boxed 0-tuple.
- There are no boxed 1-tuples.
--}
-
-maybe_tuple :: UserString -> Maybe EncodedString
-
-maybe_tuple "(# #)" = Just("Z1H")
-maybe_tuple ('(' : '#' : cs) = case count_commas (0::Int) cs of
- (n, '#' : ')' : _) -> Just ('Z' : shows (n+1) "H")
- _ -> Nothing
-maybe_tuple "()" = Just("Z0T")
-maybe_tuple ('(' : cs) = case count_commas (0::Int) cs of
- (n, ')' : _) -> Just ('Z' : shows (n+1) "T")
- _ -> Nothing
-maybe_tuple _ = Nothing
-
-count_commas :: Int -> String -> (Int, String)
-count_commas n (',' : cs) = count_commas (n+1) cs
-count_commas n cs = (n,cs)
-
-
-{-
-************************************************************************
-* *
- Base 62
-* *
-************************************************************************
-
-Note [Base 62 encoding 128-bit integers]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Instead of base-62 encoding a single 128-bit integer
-(ceil(21.49) characters), we'll base-62 a pair of 64-bit integers
-(2 * ceil(10.75) characters). Luckily for us, it's the same number of
-characters!
--}
-
---------------------------------------------------------------------------
--- Base 62
-
--- The base-62 code is based off of 'locators'
--- ((c) Operational Dynamics Consulting, BSD3 licensed)
-
--- | Size of a 64-bit word when written as a base-62 string
-word64Base62Len :: Int
-word64Base62Len = 11
-
--- | Converts a 64-bit word into a base-62 string
-toBase62Padded :: Word64 -> String
-toBase62Padded w = pad ++ str
- where
- pad = replicate len '0'
- len = word64Base62Len - length str -- 11 == ceil(64 / lg 62)
- str = toBase62 w
-
-toBase62 :: Word64 -> String
-toBase62 w = showIntAtBase 62 represent w ""
- where
- represent :: Int -> Char
- represent x
- | x < 10 = Char.chr (48 + x)
- | x < 36 = Char.chr (65 + x - 10)
- | x < 62 = Char.chr (97 + x - 36)
- | otherwise = error "represent (base 62): impossible!"
diff --git a/compiler/utils/EnumSet.hs b/compiler/utils/EnumSet.hs
deleted file mode 100644
index 670a5c64c8..0000000000
--- a/compiler/utils/EnumSet.hs
+++ /dev/null
@@ -1,35 +0,0 @@
--- | A tiny wrapper around 'IntSet.IntSet' for representing sets of 'Enum'
--- things.
-module EnumSet
- ( EnumSet
- , member
- , insert
- , delete
- , toList
- , fromList
- , empty
- ) where
-
-import GhcPrelude
-
-import qualified Data.IntSet as IntSet
-
-newtype EnumSet a = EnumSet IntSet.IntSet
-
-member :: Enum a => a -> EnumSet a -> Bool
-member x (EnumSet s) = IntSet.member (fromEnum x) s
-
-insert :: Enum a => a -> EnumSet a -> EnumSet a
-insert x (EnumSet s) = EnumSet $ IntSet.insert (fromEnum x) s
-
-delete :: Enum a => a -> EnumSet a -> EnumSet a
-delete x (EnumSet s) = EnumSet $ IntSet.delete (fromEnum x) s
-
-toList :: Enum a => EnumSet a -> [a]
-toList (EnumSet s) = map toEnum $ IntSet.toList s
-
-fromList :: Enum a => [a] -> EnumSet a
-fromList = EnumSet . IntSet.fromList . map fromEnum
-
-empty :: EnumSet a
-empty = EnumSet IntSet.empty
diff --git a/compiler/utils/Exception.hs b/compiler/utils/Exception.hs
deleted file mode 100644
index 9d9b3ae25c..0000000000
--- a/compiler/utils/Exception.hs
+++ /dev/null
@@ -1,83 +0,0 @@
-{-# OPTIONS_GHC -fno-warn-deprecations #-}
-module Exception
- (
- module Control.Exception,
- module Exception
- )
- where
-
-import GhcPrelude
-
-import Control.Exception
-import Control.Monad.IO.Class
-
-catchIO :: IO a -> (IOException -> IO a) -> IO a
-catchIO = Control.Exception.catch
-
-handleIO :: (IOException -> IO a) -> IO a -> IO a
-handleIO = flip catchIO
-
-tryIO :: IO a -> IO (Either IOException a)
-tryIO = try
-
--- | A monad that can catch exceptions. A minimal definition
--- requires a definition of 'gcatch'.
---
--- Implementations on top of 'IO' should implement 'gmask' to
--- eventually call the primitive 'Control.Exception.mask'.
--- These are used for
--- implementations that support asynchronous exceptions. The default
--- implementations of 'gbracket' and 'gfinally' use 'gmask'
--- thus rarely require overriding.
---
-class MonadIO m => ExceptionMonad m where
-
- -- | Generalised version of 'Control.Exception.catch', allowing an arbitrary
- -- exception handling monad instead of just 'IO'.
- gcatch :: Exception e => m a -> (e -> m a) -> m a
-
- -- | Generalised version of 'Control.Exception.mask_', allowing an arbitrary
- -- exception handling monad instead of just 'IO'.
- gmask :: ((m a -> m a) -> m b) -> m b
-
- -- | Generalised version of 'Control.Exception.bracket', allowing an arbitrary
- -- exception handling monad instead of just 'IO'.
- gbracket :: m a -> (a -> m b) -> (a -> m c) -> m c
-
- -- | Generalised version of 'Control.Exception.finally', allowing an arbitrary
- -- exception handling monad instead of just 'IO'.
- gfinally :: m a -> m b -> m a
-
- gbracket before after thing =
- gmask $ \restore -> do
- a <- before
- r <- restore (thing a) `gonException` after a
- _ <- after a
- return r
-
- a `gfinally` sequel =
- gmask $ \restore -> do
- r <- restore a `gonException` sequel
- _ <- sequel
- return r
-
-instance ExceptionMonad IO where
- gcatch = Control.Exception.catch
- gmask f = mask (\x -> f x)
-
-gtry :: (ExceptionMonad m, Exception e) => m a -> m (Either e a)
-gtry act = gcatch (act >>= \a -> return (Right a))
- (\e -> return (Left e))
-
--- | Generalised version of 'Control.Exception.handle', allowing an arbitrary
--- exception handling monad instead of just 'IO'.
-ghandle :: (ExceptionMonad m, Exception e) => (e -> m a) -> m a -> m a
-ghandle = flip gcatch
-
--- | Always executes the first argument. If this throws an exception the
--- second argument is executed and the exception is raised again.
-gonException :: (ExceptionMonad m) => m a -> m b -> m a
-gonException ioA cleanup = ioA `gcatch` \e ->
- do _ <- cleanup
- liftIO $ throwIO (e :: SomeException)
-
diff --git a/compiler/utils/FV.hs b/compiler/utils/FV.hs
deleted file mode 100644
index f0a35d4100..0000000000
--- a/compiler/utils/FV.hs
+++ /dev/null
@@ -1,200 +0,0 @@
-{-
-(c) Bartosz Nitka, Facebook 2015
-
-Utilities for efficiently and deterministically computing free variables.
-
--}
-
-{-# LANGUAGE BangPatterns #-}
-
-module FV (
- -- * Deterministic free vars computations
- FV, InterestingVarFun,
-
- -- * Running the computations
- fvVarList, fvVarSet, fvDVarSet,
-
- -- ** Manipulating those computations
- unitFV,
- emptyFV,
- mkFVs,
- unionFV,
- unionsFV,
- delFV,
- delFVs,
- filterFV,
- mapUnionFV,
- ) where
-
-import GhcPrelude
-
-import GHC.Types.Var
-import GHC.Types.Var.Set
-
--- | Predicate on possible free variables: returns @True@ iff the variable is
--- interesting
-type InterestingVarFun = Var -> Bool
-
--- Note [Deterministic FV]
--- ~~~~~~~~~~~~~~~~~~~~~~~
--- When computing free variables, the order in which you get them affects
--- the results of floating and specialization. If you use UniqFM to collect
--- them and then turn that into a list, you get them in nondeterministic
--- order as described in Note [Deterministic UniqFM] in GHC.Types.Unique.DFM.
-
--- A naive algorithm for free variables relies on merging sets of variables.
--- Merging costs O(n+m) for UniqFM and for UniqDFM there's an additional log
--- factor. It's cheaper to incrementally add to a list and use a set to check
--- for duplicates.
-type FV = InterestingVarFun -- Used for filtering sets as we build them
- -> VarSet -- Locally bound variables
- -> VarAcc -- Accumulator
- -> VarAcc
-
-type VarAcc = ([Var], VarSet) -- List to preserve ordering and set to check for membership,
- -- so that the list doesn't have duplicates
- -- For explanation of why using `VarSet` is not deterministic see
- -- Note [Deterministic UniqFM] in GHC.Types.Unique.DFM.
-
--- Note [FV naming conventions]
--- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
--- To get the performance and determinism that FV provides, FV computations
--- need to built up from smaller FV computations and then evaluated with
--- one of `fvVarList`, `fvDVarSet` That means the functions
--- returning FV need to be exported.
---
--- The conventions are:
---
--- a) non-deterministic functions:
--- * a function that returns VarSet
--- e.g. `tyVarsOfType`
--- b) deterministic functions:
--- * a worker that returns FV
--- e.g. `tyFVsOfType`
--- * a function that returns [Var]
--- e.g. `tyVarsOfTypeList`
--- * a function that returns DVarSet
--- e.g. `tyVarsOfTypeDSet`
---
--- Where tyVarsOfType, tyVarsOfTypeList, tyVarsOfTypeDSet are implemented
--- in terms of the worker evaluated with fvVarSet, fvVarList, fvDVarSet
--- respectively.
-
--- | Run a free variable computation, returning a list of distinct free
--- variables in deterministic order and a non-deterministic set containing
--- those variables.
-fvVarAcc :: FV -> ([Var], VarSet)
-fvVarAcc fv = fv (const True) emptyVarSet ([], emptyVarSet)
-
--- | Run a free variable computation, returning a list of distinct free
--- variables in deterministic order.
-fvVarList :: FV -> [Var]
-fvVarList = fst . fvVarAcc
-
--- | Run a free variable computation, returning a deterministic set of free
--- variables. Note that this is just a wrapper around the version that
--- returns a deterministic list. If you need a list you should use
--- `fvVarList`.
-fvDVarSet :: FV -> DVarSet
-fvDVarSet = mkDVarSet . fvVarList
-
--- | Run a free variable computation, returning a non-deterministic set of
--- free variables. Don't use if the set will be later converted to a list
--- and the order of that list will impact the generated code.
-fvVarSet :: FV -> VarSet
-fvVarSet = snd . fvVarAcc
-
--- Note [FV eta expansion]
--- ~~~~~~~~~~~~~~~~~~~~~~~
--- Let's consider an eta-reduced implementation of freeVarsOf using FV:
---
--- freeVarsOf (App a b) = freeVarsOf a `unionFV` freeVarsOf b
---
--- If GHC doesn't eta-expand it, after inlining unionFV we end up with
---
--- freeVarsOf = \x ->
--- case x of
--- App a b -> \fv_cand in_scope acc ->
--- freeVarsOf a fv_cand in_scope $! freeVarsOf b fv_cand in_scope $! acc
---
--- which has to create a thunk, resulting in more allocations.
---
--- On the other hand if it is eta-expanded:
---
--- freeVarsOf (App a b) fv_cand in_scope acc =
--- (freeVarsOf a `unionFV` freeVarsOf b) fv_cand in_scope acc
---
--- after inlining unionFV we have:
---
--- freeVarsOf = \x fv_cand in_scope acc ->
--- case x of
--- App a b ->
--- freeVarsOf a fv_cand in_scope $! freeVarsOf b fv_cand in_scope $! acc
---
--- which saves allocations.
---
--- GHC when presented with knowledge about all the call sites, correctly
--- eta-expands in this case. Unfortunately due to the fact that freeVarsOf gets
--- exported to be composed with other functions, GHC doesn't have that
--- information and has to be more conservative here.
---
--- Hence functions that get exported and return FV need to be manually
--- eta-expanded. See also #11146.
-
--- | Add a variable - when free, to the returned free variables.
--- Ignores duplicates and respects the filtering function.
-unitFV :: Id -> FV
-unitFV var fv_cand in_scope acc@(have, haveSet)
- | var `elemVarSet` in_scope = acc
- | var `elemVarSet` haveSet = acc
- | fv_cand var = (var:have, extendVarSet haveSet var)
- | otherwise = acc
-{-# INLINE unitFV #-}
-
--- | Return no free variables.
-emptyFV :: FV
-emptyFV _ _ acc = acc
-{-# INLINE emptyFV #-}
-
--- | Union two free variable computations.
-unionFV :: FV -> FV -> FV
-unionFV fv1 fv2 fv_cand in_scope acc =
- fv1 fv_cand in_scope $! fv2 fv_cand in_scope $! acc
-{-# INLINE unionFV #-}
-
--- | Mark the variable as not free by putting it in scope.
-delFV :: Var -> FV -> FV
-delFV var fv fv_cand !in_scope acc =
- fv fv_cand (extendVarSet in_scope var) acc
-{-# INLINE delFV #-}
-
--- | Mark many free variables as not free.
-delFVs :: VarSet -> FV -> FV
-delFVs vars fv fv_cand !in_scope acc =
- fv fv_cand (in_scope `unionVarSet` vars) acc
-{-# INLINE delFVs #-}
-
--- | Filter a free variable computation.
-filterFV :: InterestingVarFun -> FV -> FV
-filterFV fv_cand2 fv fv_cand1 in_scope acc =
- fv (\v -> fv_cand1 v && fv_cand2 v) in_scope acc
-{-# INLINE filterFV #-}
-
--- | Map a free variable computation over a list and union the results.
-mapUnionFV :: (a -> FV) -> [a] -> FV
-mapUnionFV _f [] _fv_cand _in_scope acc = acc
-mapUnionFV f (a:as) fv_cand in_scope acc =
- mapUnionFV f as fv_cand in_scope $! f a fv_cand in_scope $! acc
-{-# INLINABLE mapUnionFV #-}
-
--- | Union many free variable computations.
-unionsFV :: [FV] -> FV
-unionsFV fvs fv_cand in_scope acc = mapUnionFV id fvs fv_cand in_scope acc
-{-# INLINE unionsFV #-}
-
--- | Add multiple variables - when free, to the returned free variables.
--- Ignores duplicates and respects the filtering function.
-mkFVs :: [Var] -> FV
-mkFVs vars fv_cand in_scope acc =
- mapUnionFV unitFV vars fv_cand in_scope acc
-{-# INLINE mkFVs #-}
diff --git a/compiler/utils/FastFunctions.hs b/compiler/utils/FastFunctions.hs
deleted file mode 100644
index 9a09bb7b76..0000000000
--- a/compiler/utils/FastFunctions.hs
+++ /dev/null
@@ -1,21 +0,0 @@
-{-
-(c) The University of Glasgow, 2000-2006
--}
-
-{-# LANGUAGE CPP, MagicHash, UnboxedTuples #-}
-
-module FastFunctions (
- inlinePerformIO,
- ) where
-
-#include "HsVersions.h"
-
-import GhcPrelude ()
-
-import GHC.Exts
-import GHC.IO (IO(..))
-
--- Just like unsafeDupablePerformIO, but we inline it.
-{-# INLINE inlinePerformIO #-}
-inlinePerformIO :: IO a -> a
-inlinePerformIO (IO m) = case m realWorld# of (# _, r #) -> r
diff --git a/compiler/utils/FastMutInt.hs b/compiler/utils/FastMutInt.hs
deleted file mode 100644
index 20206f8b1e..0000000000
--- a/compiler/utils/FastMutInt.hs
+++ /dev/null
@@ -1,61 +0,0 @@
-{-# LANGUAGE BangPatterns, MagicHash, UnboxedTuples #-}
-{-# OPTIONS_GHC -O2 #-}
--- We always optimise this, otherwise performance of a non-optimised
--- compiler is severely affected
---
--- (c) The University of Glasgow 2002-2006
---
--- Unboxed mutable Ints
-
-module FastMutInt(
- FastMutInt, newFastMutInt,
- readFastMutInt, writeFastMutInt,
-
- FastMutPtr, newFastMutPtr,
- readFastMutPtr, writeFastMutPtr
- ) where
-
-import GhcPrelude
-
-import Data.Bits
-import GHC.Base
-import GHC.Ptr
-
-newFastMutInt :: IO FastMutInt
-readFastMutInt :: FastMutInt -> IO Int
-writeFastMutInt :: FastMutInt -> Int -> IO ()
-
-newFastMutPtr :: IO FastMutPtr
-readFastMutPtr :: FastMutPtr -> IO (Ptr a)
-writeFastMutPtr :: FastMutPtr -> Ptr a -> IO ()
-
-data FastMutInt = FastMutInt (MutableByteArray# RealWorld)
-
-newFastMutInt = IO $ \s ->
- case newByteArray# size s of { (# s, arr #) ->
- (# s, FastMutInt arr #) }
- where !(I# size) = finiteBitSize (0 :: Int)
-
-readFastMutInt (FastMutInt arr) = IO $ \s ->
- case readIntArray# arr 0# s of { (# s, i #) ->
- (# s, I# i #) }
-
-writeFastMutInt (FastMutInt arr) (I# i) = IO $ \s ->
- case writeIntArray# arr 0# i s of { s ->
- (# s, () #) }
-
-data FastMutPtr = FastMutPtr (MutableByteArray# RealWorld)
-
-newFastMutPtr = IO $ \s ->
- case newByteArray# size s of { (# s, arr #) ->
- (# s, FastMutPtr arr #) }
- -- GHC assumes 'sizeof (Int) == sizeof (Ptr a)'
- where !(I# size) = finiteBitSize (0 :: Int)
-
-readFastMutPtr (FastMutPtr arr) = IO $ \s ->
- case readAddrArray# arr 0# s of { (# s, i #) ->
- (# s, Ptr i #) }
-
-writeFastMutPtr (FastMutPtr arr) (Ptr i) = IO $ \s ->
- case writeAddrArray# arr 0# i s of { s ->
- (# s, () #) }
diff --git a/compiler/utils/FastString.hs b/compiler/utils/FastString.hs
deleted file mode 100644
index 9a74eff16d..0000000000
--- a/compiler/utils/FastString.hs
+++ /dev/null
@@ -1,693 +0,0 @@
--- (c) The University of Glasgow, 1997-2006
-
-{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples,
- GeneralizedNewtypeDeriving #-}
-{-# OPTIONS_GHC -O2 -funbox-strict-fields #-}
--- We always optimise this, otherwise performance of a non-optimised
--- compiler is severely affected
-
--- |
--- There are two principal string types used internally by GHC:
---
--- ['FastString']
---
--- * A compact, hash-consed, representation of character strings.
--- * Comparison is O(1), and you can get a 'Unique.Unique' from them.
--- * Generated by 'fsLit'.
--- * Turn into 'Outputable.SDoc' with 'Outputable.ftext'.
---
--- ['PtrString']
---
--- * Pointer and size of a Latin-1 encoded string.
--- * Practically no operations.
--- * Outputting them is fast.
--- * Generated by 'sLit'.
--- * Turn into 'Outputable.SDoc' with 'Outputable.ptext'
--- * Requires manual memory management.
--- Improper use may lead to memory leaks or dangling pointers.
--- * It assumes Latin-1 as the encoding, therefore it cannot represent
--- arbitrary Unicode strings.
---
--- Use 'PtrString' unless you want the facilities of 'FastString'.
-module FastString
- (
- -- * ByteString
- bytesFS, -- :: FastString -> ByteString
- fastStringToByteString, -- = bytesFS (kept for haddock)
- mkFastStringByteString,
- fastZStringToByteString,
- unsafeMkByteString,
-
- -- * FastZString
- FastZString,
- hPutFZS,
- zString,
- lengthFZS,
-
- -- * FastStrings
- FastString(..), -- not abstract, for now.
-
- -- ** Construction
- fsLit,
- mkFastString,
- mkFastStringBytes,
- mkFastStringByteList,
- mkFastStringForeignPtr,
- mkFastString#,
-
- -- ** Deconstruction
- unpackFS, -- :: FastString -> String
-
- -- ** Encoding
- zEncodeFS,
-
- -- ** Operations
- uniqueOfFS,
- lengthFS,
- nullFS,
- appendFS,
- headFS,
- tailFS,
- concatFS,
- consFS,
- nilFS,
- isUnderscoreFS,
-
- -- ** Outputting
- hPutFS,
-
- -- ** Internal
- getFastStringTable,
- getFastStringZEncCounter,
-
- -- * PtrStrings
- PtrString (..),
-
- -- ** Construction
- sLit,
- mkPtrString#,
- mkPtrString,
-
- -- ** Deconstruction
- unpackPtrString,
-
- -- ** Operations
- lengthPS
- ) where
-
-#include "HsVersions.h"
-
-import GhcPrelude as Prelude
-
-import Encoding
-import FastFunctions
-import PlainPanic
-import Util
-
-import Control.Concurrent.MVar
-import Control.DeepSeq
-import Control.Monad
-import Data.ByteString (ByteString)
-import qualified Data.ByteString as BS
-import qualified Data.ByteString.Char8 as BSC
-import qualified Data.ByteString.Internal as BS
-import qualified Data.ByteString.Unsafe as BS
-import Foreign.C
-import GHC.Exts
-import System.IO
-import Data.Data
-import Data.IORef
-import Data.Char
-import Data.Semigroup as Semi
-
-import GHC.IO
-
-import Foreign
-
-#if GHC_STAGE >= 2
-import GHC.Conc.Sync (sharedCAF)
-#endif
-
-import GHC.Base ( unpackCString#, unpackNBytes# )
-
-
--- | Gives the UTF-8 encoded bytes corresponding to a 'FastString'
-bytesFS :: FastString -> ByteString
-bytesFS f = fs_bs f
-
-{-# DEPRECATED fastStringToByteString "Use `bytesFS` instead" #-}
-fastStringToByteString :: FastString -> ByteString
-fastStringToByteString = bytesFS
-
-fastZStringToByteString :: FastZString -> ByteString
-fastZStringToByteString (FastZString bs) = bs
-
--- This will drop information if any character > '\xFF'
-unsafeMkByteString :: String -> ByteString
-unsafeMkByteString = BSC.pack
-
-hashFastString :: FastString -> Int
-hashFastString (FastString _ _ bs _)
- = inlinePerformIO $ BS.unsafeUseAsCStringLen bs $ \(ptr, len) ->
- return $ hashStr (castPtr ptr) len
-
--- -----------------------------------------------------------------------------
-
-newtype FastZString = FastZString ByteString
- deriving NFData
-
-hPutFZS :: Handle -> FastZString -> IO ()
-hPutFZS handle (FastZString bs) = BS.hPut handle bs
-
-zString :: FastZString -> String
-zString (FastZString bs) =
- inlinePerformIO $ BS.unsafeUseAsCStringLen bs peekCAStringLen
-
-lengthFZS :: FastZString -> Int
-lengthFZS (FastZString bs) = BS.length bs
-
-mkFastZStringString :: String -> FastZString
-mkFastZStringString str = FastZString (BSC.pack str)
-
--- -----------------------------------------------------------------------------
-
-{-| A 'FastString' is a UTF-8 encoded string together with a unique ID. All
-'FastString's are stored in a global hashtable to support fast O(1)
-comparison.
-
-It is also associated with a lazy reference to the Z-encoding
-of this string which is used by the compiler internally.
--}
-data FastString = FastString {
- uniq :: {-# UNPACK #-} !Int, -- unique id
- n_chars :: {-# UNPACK #-} !Int, -- number of chars
- fs_bs :: {-# UNPACK #-} !ByteString,
- fs_zenc :: FastZString
- -- ^ Lazily computed z-encoding of this string.
- --
- -- Since 'FastString's are globally memoized this is computed at most
- -- once for any given string.
- }
-
-instance Eq FastString where
- f1 == f2 = uniq f1 == uniq f2
-
-instance Ord FastString where
- -- Compares lexicographically, not by unique
- a <= b = case cmpFS a b of { LT -> True; EQ -> True; GT -> False }
- a < b = case cmpFS a b of { LT -> True; EQ -> False; GT -> False }
- a >= b = case cmpFS a b of { LT -> False; EQ -> True; GT -> True }
- a > b = case cmpFS a b of { LT -> False; EQ -> False; GT -> True }
- max x y | x >= y = x
- | otherwise = y
- min x y | x <= y = x
- | otherwise = y
- compare a b = cmpFS a b
-
-instance IsString FastString where
- fromString = fsLit
-
-instance Semi.Semigroup FastString where
- (<>) = appendFS
-
-instance Monoid FastString where
- mempty = nilFS
- mappend = (Semi.<>)
- mconcat = concatFS
-
-instance Show FastString where
- show fs = show (unpackFS fs)
-
-instance Data FastString where
- -- don't traverse?
- toConstr _ = abstractConstr "FastString"
- gunfold _ _ = error "gunfold"
- dataTypeOf _ = mkNoRepType "FastString"
-
-instance NFData FastString where
- rnf fs = seq fs ()
-
-cmpFS :: FastString -> FastString -> Ordering
-cmpFS f1@(FastString u1 _ _ _) f2@(FastString u2 _ _ _) =
- if u1 == u2 then EQ else
- compare (bytesFS f1) (bytesFS f2)
-
-foreign import ccall unsafe "memcmp"
- memcmp :: Ptr a -> Ptr b -> Int -> IO Int
-
--- -----------------------------------------------------------------------------
--- Construction
-
-{-
-Internally, the compiler will maintain a fast string symbol table, providing
-sharing and fast comparison. Creation of new @FastString@s then covertly does a
-lookup, re-using the @FastString@ if there was a hit.
-
-The design of the FastString hash table allows for lockless concurrent reads
-and updates to multiple buckets with low synchronization overhead.
-
-See Note [Updating the FastString table] on how it's updated.
--}
-data FastStringTable = FastStringTable
- {-# UNPACK #-} !(IORef Int) -- the unique ID counter shared with all buckets
- {-# UNPACK #-} !(IORef Int) -- number of computed z-encodings for all buckets
- (Array# (IORef FastStringTableSegment)) -- concurrent segments
-
-data FastStringTableSegment = FastStringTableSegment
- {-# UNPACK #-} !(MVar ()) -- the lock for write in each segment
- {-# UNPACK #-} !(IORef Int) -- the number of elements
- (MutableArray# RealWorld [FastString]) -- buckets in this segment
-
-{-
-Following parameters are determined based on:
-
-* Benchmark based on testsuite/tests/utils/should_run/T14854.hs
-* Stats of @echo :browse | ghc --interactive -dfaststring-stats >/dev/null@:
- on 2018-10-24, we have 13920 entries.
--}
-segmentBits, numSegments, segmentMask, initialNumBuckets :: Int
-segmentBits = 8
-numSegments = 256 -- bit segmentBits
-segmentMask = 0xff -- bit segmentBits - 1
-initialNumBuckets = 64
-
-hashToSegment# :: Int# -> Int#
-hashToSegment# hash# = hash# `andI#` segmentMask#
- where
- !(I# segmentMask#) = segmentMask
-
-hashToIndex# :: MutableArray# RealWorld [FastString] -> Int# -> Int#
-hashToIndex# buckets# hash# =
- (hash# `uncheckedIShiftRL#` segmentBits#) `remInt#` size#
- where
- !(I# segmentBits#) = segmentBits
- size# = sizeofMutableArray# buckets#
-
-maybeResizeSegment :: IORef FastStringTableSegment -> IO FastStringTableSegment
-maybeResizeSegment segmentRef = do
- segment@(FastStringTableSegment lock counter old#) <- readIORef segmentRef
- let oldSize# = sizeofMutableArray# old#
- newSize# = oldSize# *# 2#
- (I# n#) <- readIORef counter
- if isTrue# (n# <# newSize#) -- maximum load of 1
- then return segment
- else do
- resizedSegment@(FastStringTableSegment _ _ new#) <- IO $ \s1# ->
- case newArray# newSize# [] s1# of
- (# s2#, arr# #) -> (# s2#, FastStringTableSegment lock counter arr# #)
- forM_ [0 .. (I# oldSize#) - 1] $ \(I# i#) -> do
- fsList <- IO $ readArray# old# i#
- forM_ fsList $ \fs -> do
- let -- Shall we store in hash value in FastString instead?
- !(I# hash#) = hashFastString fs
- idx# = hashToIndex# new# hash#
- IO $ \s1# ->
- case readArray# new# idx# s1# of
- (# s2#, bucket #) -> case writeArray# new# idx# (fs: bucket) s2# of
- s3# -> (# s3#, () #)
- writeIORef segmentRef resizedSegment
- return resizedSegment
-
-{-# NOINLINE stringTable #-}
-stringTable :: FastStringTable
-stringTable = unsafePerformIO $ do
- let !(I# numSegments#) = numSegments
- !(I# initialNumBuckets#) = initialNumBuckets
- loop a# i# s1#
- | isTrue# (i# ==# numSegments#) = s1#
- | otherwise = case newMVar () `unIO` s1# of
- (# s2#, lock #) -> case newIORef 0 `unIO` s2# of
- (# s3#, counter #) -> case newArray# initialNumBuckets# [] s3# of
- (# s4#, buckets# #) -> case newIORef
- (FastStringTableSegment lock counter buckets#) `unIO` s4# of
- (# s5#, segment #) -> case writeArray# a# i# segment s5# of
- s6# -> loop a# (i# +# 1#) s6#
- uid <- newIORef 603979776 -- ord '$' * 0x01000000
- n_zencs <- newIORef 0
- tab <- IO $ \s1# ->
- case newArray# numSegments# (panic "string_table") s1# of
- (# s2#, arr# #) -> case loop arr# 0# s2# of
- s3# -> case unsafeFreezeArray# arr# s3# of
- (# s4#, segments# #) ->
- (# s4#, FastStringTable uid n_zencs segments# #)
-
- -- use the support wired into the RTS to share this CAF among all images of
- -- libHSghc
-#if GHC_STAGE < 2
- return tab
-#else
- sharedCAF tab getOrSetLibHSghcFastStringTable
-
--- from the RTS; thus we cannot use this mechanism when GHC_STAGE<2; the previous
--- RTS might not have this symbol
-foreign import ccall unsafe "getOrSetLibHSghcFastStringTable"
- getOrSetLibHSghcFastStringTable :: Ptr a -> IO (Ptr a)
-#endif
-
-{-
-
-We include the FastString table in the `sharedCAF` mechanism because we'd like
-FastStrings created by a Core plugin to have the same uniques as corresponding
-strings created by the host compiler itself. For example, this allows plugins
-to lookup known names (eg `mkTcOcc "MySpecialType"`) in the GlobalRdrEnv or
-even re-invoke the parser.
-
-In particular, the following little sanity test was failing in a plugin
-prototyping safe newtype-coercions: GHC.NT.Type.NT was imported, but could not
-be looked up /by the plugin/.
-
- let rdrName = mkModuleName "GHC.NT.Type" `mkRdrQual` mkTcOcc "NT"
- putMsgS $ showSDoc dflags $ ppr $ lookupGRE_RdrName rdrName $ mg_rdr_env guts
-
-`mkTcOcc` involves the lookup (or creation) of a FastString. Since the
-plugin's FastString.string_table is empty, constructing the RdrName also
-allocates new uniques for the FastStrings "GHC.NT.Type" and "NT". These
-uniques are almost certainly unequal to the ones that the host compiler
-originally assigned to those FastStrings. Thus the lookup fails since the
-domain of the GlobalRdrEnv is affected by the RdrName's OccName's FastString's
-unique.
-
-Maintaining synchronization of the two instances of this global is rather
-difficult because of the uses of `unsafePerformIO` in this module. Not
-synchronizing them risks breaking the rather major invariant that two
-FastStrings with the same unique have the same string. Thus we use the
-lower-level `sharedCAF` mechanism that relies on Globals.c.
-
--}
-
-mkFastString# :: Addr# -> FastString
-mkFastString# a# = mkFastStringBytes ptr (ptrStrLength ptr)
- where ptr = Ptr a#
-
-{- Note [Updating the FastString table]
-
-We use a concurrent hashtable which contains multiple segments, each hash value
-always maps to the same segment. Read is lock-free, write to the a segment
-should acquire a lock for that segment to avoid race condition, writes to
-different segments are independent.
-
-The procedure goes like this:
-
-1. Find out which segment to operate on based on the hash value
-2. Read the relevant bucket and perform a look up of the string.
-3. If it exists, return it.
-4. Otherwise grab a unique ID, create a new FastString and atomically attempt
- to update the relevant segment with this FastString:
-
- * Resize the segment by doubling the number of buckets when the number of
- FastStrings in this segment grows beyond the threshold.
- * Double check that the string is not in the bucket. Another thread may have
- inserted it while we were creating our string.
- * Return the existing FastString if it exists. The one we preemptively
- created will get GCed.
- * Otherwise, insert and return the string we created.
--}
-
-mkFastStringWith
- :: (Int -> IORef Int-> IO FastString) -> Ptr Word8 -> Int -> IO FastString
-mkFastStringWith mk_fs !ptr !len = do
- FastStringTableSegment lock _ buckets# <- readIORef segmentRef
- let idx# = hashToIndex# buckets# hash#
- bucket <- IO $ readArray# buckets# idx#
- res <- bucket_match bucket len ptr
- case res of
- Just found -> return found
- Nothing -> do
- -- The withMVar below is not dupable. It can lead to deadlock if it is
- -- only run partially and putMVar is not called after takeMVar.
- noDuplicate
- n <- get_uid
- new_fs <- mk_fs n n_zencs
- withMVar lock $ \_ -> insert new_fs
- where
- !(FastStringTable uid n_zencs segments#) = stringTable
- get_uid = atomicModifyIORef' uid $ \n -> (n+1,n)
-
- !(I# hash#) = hashStr ptr len
- (# segmentRef #) = indexArray# segments# (hashToSegment# hash#)
- insert fs = do
- FastStringTableSegment _ counter buckets# <- maybeResizeSegment segmentRef
- let idx# = hashToIndex# buckets# hash#
- bucket <- IO $ readArray# buckets# idx#
- res <- bucket_match bucket len ptr
- case res of
- -- The FastString was added by another thread after previous read and
- -- before we acquired the write lock.
- Just found -> return found
- Nothing -> do
- IO $ \s1# ->
- case writeArray# buckets# idx# (fs: bucket) s1# of
- s2# -> (# s2#, () #)
- modifyIORef' counter succ
- return fs
-
-bucket_match :: [FastString] -> Int -> Ptr Word8 -> IO (Maybe FastString)
-bucket_match [] _ _ = return Nothing
-bucket_match (v@(FastString _ _ bs _):ls) len ptr
- | len == BS.length bs = do
- b <- BS.unsafeUseAsCString bs $ \buf ->
- cmpStringPrefix ptr (castPtr buf) len
- if b then return (Just v)
- else bucket_match ls len ptr
- | otherwise =
- bucket_match ls len ptr
-
-mkFastStringBytes :: Ptr Word8 -> Int -> FastString
-mkFastStringBytes !ptr !len =
- -- NB: Might as well use unsafeDupablePerformIO, since mkFastStringWith is
- -- idempotent.
- unsafeDupablePerformIO $
- mkFastStringWith (copyNewFastString ptr len) ptr len
-
--- | Create a 'FastString' from an existing 'ForeignPtr'; the difference
--- between this and 'mkFastStringBytes' is that we don't have to copy
--- the bytes if the string is new to the table.
-mkFastStringForeignPtr :: Ptr Word8 -> ForeignPtr Word8 -> Int -> IO FastString
-mkFastStringForeignPtr ptr !fp len
- = mkFastStringWith (mkNewFastString fp ptr len) ptr len
-
--- | Create a 'FastString' from an existing 'ForeignPtr'; the difference
--- between this and 'mkFastStringBytes' is that we don't have to copy
--- the bytes if the string is new to the table.
-mkFastStringByteString :: ByteString -> FastString
-mkFastStringByteString bs =
- inlinePerformIO $
- BS.unsafeUseAsCStringLen bs $ \(ptr, len) -> do
- let ptr' = castPtr ptr
- mkFastStringWith (mkNewFastStringByteString bs ptr' len) ptr' len
-
--- | Creates a UTF-8 encoded 'FastString' from a 'String'
-mkFastString :: String -> FastString
-mkFastString str =
- inlinePerformIO $ do
- let l = utf8EncodedLength str
- buf <- mallocForeignPtrBytes l
- withForeignPtr buf $ \ptr -> do
- utf8EncodeString ptr str
- mkFastStringForeignPtr ptr buf l
-
--- | Creates a 'FastString' from a UTF-8 encoded @[Word8]@
-mkFastStringByteList :: [Word8] -> FastString
-mkFastStringByteList str = mkFastStringByteString (BS.pack str)
-
--- | Creates a (lazy) Z-encoded 'FastString' from a 'String' and account
--- the number of forced z-strings into the passed 'IORef'.
-mkZFastString :: IORef Int -> ByteString -> FastZString
-mkZFastString n_zencs bs = unsafePerformIO $ do
- atomicModifyIORef' n_zencs $ \n -> (n+1, ())
- return $ mkFastZStringString (zEncodeString (utf8DecodeByteString bs))
-
-mkNewFastString :: ForeignPtr Word8 -> Ptr Word8 -> Int -> Int
- -> IORef Int -> IO FastString
-mkNewFastString fp ptr len uid n_zencs = do
- let bs = BS.fromForeignPtr fp 0 len
- zstr = mkZFastString n_zencs bs
- n_chars <- countUTF8Chars ptr len
- return (FastString uid n_chars bs zstr)
-
-mkNewFastStringByteString :: ByteString -> Ptr Word8 -> Int -> Int
- -> IORef Int -> IO FastString
-mkNewFastStringByteString bs ptr len uid n_zencs = do
- let zstr = mkZFastString n_zencs bs
- n_chars <- countUTF8Chars ptr len
- return (FastString uid n_chars bs zstr)
-
-copyNewFastString :: Ptr Word8 -> Int -> Int -> IORef Int -> IO FastString
-copyNewFastString ptr len uid n_zencs = do
- fp <- copyBytesToForeignPtr ptr len
- let bs = BS.fromForeignPtr fp 0 len
- zstr = mkZFastString n_zencs bs
- n_chars <- countUTF8Chars ptr len
- return (FastString uid n_chars bs zstr)
-
-copyBytesToForeignPtr :: Ptr Word8 -> Int -> IO (ForeignPtr Word8)
-copyBytesToForeignPtr ptr len = do
- fp <- mallocForeignPtrBytes len
- withForeignPtr fp $ \ptr' -> copyBytes ptr' ptr len
- return fp
-
-cmpStringPrefix :: Ptr Word8 -> Ptr Word8 -> Int -> IO Bool
-cmpStringPrefix ptr1 ptr2 len =
- do r <- memcmp ptr1 ptr2 len
- return (r == 0)
-
-hashStr :: Ptr Word8 -> Int -> Int
- -- use the Addr to produce a hash value between 0 & m (inclusive)
-hashStr (Ptr a#) (I# len#) = loop 0# 0#
- where
- loop h n =
- if isTrue# (n ==# len#) then
- I# h
- else
- let
- -- DO NOT move this let binding! indexCharOffAddr# reads from the
- -- pointer so we need to evaluate this based on the length check
- -- above. Not doing this right caused #17909.
- !c = ord# (indexCharOffAddr# a# n)
- !h2 = (h *# 16777619#) `xorI#` c
- in
- loop h2 (n +# 1#)
-
--- -----------------------------------------------------------------------------
--- Operations
-
--- | Returns the length of the 'FastString' in characters
-lengthFS :: FastString -> Int
-lengthFS f = n_chars f
-
--- | Returns @True@ if the 'FastString' is empty
-nullFS :: FastString -> Bool
-nullFS f = BS.null (fs_bs f)
-
--- | Unpacks and decodes the FastString
-unpackFS :: FastString -> String
-unpackFS (FastString _ _ bs _) = utf8DecodeByteString bs
-
--- | Returns a Z-encoded version of a 'FastString'. This might be the
--- original, if it was already Z-encoded. The first time this
--- function is applied to a particular 'FastString', the results are
--- memoized.
---
-zEncodeFS :: FastString -> FastZString
-zEncodeFS (FastString _ _ _ ref) = ref
-
-appendFS :: FastString -> FastString -> FastString
-appendFS fs1 fs2 = mkFastStringByteString
- $ BS.append (bytesFS fs1) (bytesFS fs2)
-
-concatFS :: [FastString] -> FastString
-concatFS = mkFastStringByteString . BS.concat . map fs_bs
-
-headFS :: FastString -> Char
-headFS (FastString _ 0 _ _) = panic "headFS: Empty FastString"
-headFS (FastString _ _ bs _) =
- inlinePerformIO $ BS.unsafeUseAsCString bs $ \ptr ->
- return (fst (utf8DecodeChar (castPtr ptr)))
-
-tailFS :: FastString -> FastString
-tailFS (FastString _ 0 _ _) = panic "tailFS: Empty FastString"
-tailFS (FastString _ _ bs _) =
- inlinePerformIO $ BS.unsafeUseAsCString bs $ \ptr ->
- do let (_, n) = utf8DecodeChar (castPtr ptr)
- return $! mkFastStringByteString (BS.drop n bs)
-
-consFS :: Char -> FastString -> FastString
-consFS c fs = mkFastString (c : unpackFS fs)
-
-uniqueOfFS :: FastString -> Int
-uniqueOfFS (FastString u _ _ _) = u
-
-nilFS :: FastString
-nilFS = mkFastString ""
-
-isUnderscoreFS :: FastString -> Bool
-isUnderscoreFS fs = fs == fsLit "_"
-
--- -----------------------------------------------------------------------------
--- Stats
-
-getFastStringTable :: IO [[[FastString]]]
-getFastStringTable =
- forM [0 .. numSegments - 1] $ \(I# i#) -> do
- let (# segmentRef #) = indexArray# segments# i#
- FastStringTableSegment _ _ buckets# <- readIORef segmentRef
- let bucketSize = I# (sizeofMutableArray# buckets#)
- forM [0 .. bucketSize - 1] $ \(I# j#) ->
- IO $ readArray# buckets# j#
- where
- !(FastStringTable _ _ segments#) = stringTable
-
-getFastStringZEncCounter :: IO Int
-getFastStringZEncCounter = readIORef n_zencs
- where
- !(FastStringTable _ n_zencs _) = stringTable
-
--- -----------------------------------------------------------------------------
--- Outputting 'FastString's
-
--- |Outputs a 'FastString' with /no decoding at all/, that is, you
--- get the actual bytes in the 'FastString' written to the 'Handle'.
-hPutFS :: Handle -> FastString -> IO ()
-hPutFS handle fs = BS.hPut handle $ bytesFS fs
-
--- ToDo: we'll probably want an hPutFSLocal, or something, to output
--- in the current locale's encoding (for error messages and suchlike).
-
--- -----------------------------------------------------------------------------
--- PtrStrings, here for convenience only.
-
--- | A 'PtrString' is a pointer to some array of Latin-1 encoded chars.
-data PtrString = PtrString !(Ptr Word8) !Int
-
--- | Wrap an unboxed address into a 'PtrString'.
-mkPtrString# :: Addr# -> PtrString
-mkPtrString# a# = PtrString (Ptr a#) (ptrStrLength (Ptr a#))
-
--- | Encode a 'String' into a newly allocated 'PtrString' using Latin-1
--- encoding. The original string must not contain non-Latin-1 characters
--- (above codepoint @0xff@).
-{-# INLINE mkPtrString #-}
-mkPtrString :: String -> PtrString
-mkPtrString s =
- -- we don't use `unsafeDupablePerformIO` here to avoid potential memory leaks
- -- and because someone might be using `eqAddr#` to check for string equality.
- unsafePerformIO (do
- let len = length s
- p <- mallocBytes len
- let
- loop :: Int -> String -> IO ()
- loop !_ [] = return ()
- loop n (c:cs) = do
- pokeByteOff p n (fromIntegral (ord c) :: Word8)
- loop (1+n) cs
- loop 0 s
- return (PtrString p len)
- )
-
--- | Decode a 'PtrString' back into a 'String' using Latin-1 encoding.
--- This does not free the memory associated with 'PtrString'.
-unpackPtrString :: PtrString -> String
-unpackPtrString (PtrString (Ptr p#) (I# n#)) = unpackNBytes# p# n#
-
--- | Return the length of a 'PtrString'
-lengthPS :: PtrString -> Int
-lengthPS (PtrString _ n) = n
-
--- -----------------------------------------------------------------------------
--- under the carpet
-
-foreign import ccall unsafe "strlen"
- ptrStrLength :: Ptr Word8 -> Int
-
-{-# NOINLINE sLit #-}
-sLit :: String -> PtrString
-sLit x = mkPtrString x
-
-{-# NOINLINE fsLit #-}
-fsLit :: String -> FastString
-fsLit x = mkFastString x
-
-{-# RULES "slit"
- forall x . sLit (unpackCString# x) = mkPtrString# x #-}
-{-# RULES "fslit"
- forall x . fsLit (unpackCString# x) = mkFastString# x #-}
diff --git a/compiler/utils/FastStringEnv.hs b/compiler/utils/FastStringEnv.hs
deleted file mode 100644
index bc151f736b..0000000000
--- a/compiler/utils/FastStringEnv.hs
+++ /dev/null
@@ -1,100 +0,0 @@
-{-
-%
-% (c) The University of Glasgow 2006
-% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
-%
-\section[FastStringEnv]{@FastStringEnv@: FastString environments}
--}
-
-module FastStringEnv (
- -- * FastString environments (maps)
- FastStringEnv,
-
- -- ** Manipulating these environments
- mkFsEnv,
- emptyFsEnv, unitFsEnv,
- extendFsEnv_C, extendFsEnv_Acc, extendFsEnv,
- extendFsEnvList, extendFsEnvList_C,
- filterFsEnv,
- plusFsEnv, plusFsEnv_C, alterFsEnv,
- lookupFsEnv, lookupFsEnv_NF, delFromFsEnv, delListFromFsEnv,
- elemFsEnv, mapFsEnv,
-
- -- * Deterministic FastString environments (maps)
- DFastStringEnv,
-
- -- ** Manipulating these environments
- mkDFsEnv, emptyDFsEnv, dFsEnvElts, lookupDFsEnv
- ) where
-
-import GhcPrelude
-
-import GHC.Types.Unique.FM
-import GHC.Types.Unique.DFM
-import Maybes
-import FastString
-
-
--- | A non-deterministic set of FastStrings.
--- See Note [Deterministic UniqFM] in GHC.Types.Unique.DFM for explanation why it's not
--- deterministic and why it matters. Use DFastStringEnv if the set eventually
--- gets converted into a list or folded over in a way where the order
--- changes the generated code.
-type FastStringEnv a = UniqFM a -- Domain is FastString
-
-emptyFsEnv :: FastStringEnv a
-mkFsEnv :: [(FastString,a)] -> FastStringEnv a
-alterFsEnv :: (Maybe a-> Maybe a) -> FastStringEnv a -> FastString -> FastStringEnv a
-extendFsEnv_C :: (a->a->a) -> FastStringEnv a -> FastString -> a -> FastStringEnv a
-extendFsEnv_Acc :: (a->b->b) -> (a->b) -> FastStringEnv b -> FastString -> a -> FastStringEnv b
-extendFsEnv :: FastStringEnv a -> FastString -> a -> FastStringEnv a
-plusFsEnv :: FastStringEnv a -> FastStringEnv a -> FastStringEnv a
-plusFsEnv_C :: (a->a->a) -> FastStringEnv a -> FastStringEnv a -> FastStringEnv a
-extendFsEnvList :: FastStringEnv a -> [(FastString,a)] -> FastStringEnv a
-extendFsEnvList_C :: (a->a->a) -> FastStringEnv a -> [(FastString,a)] -> FastStringEnv a
-delFromFsEnv :: FastStringEnv a -> FastString -> FastStringEnv a
-delListFromFsEnv :: FastStringEnv a -> [FastString] -> FastStringEnv a
-elemFsEnv :: FastString -> FastStringEnv a -> Bool
-unitFsEnv :: FastString -> a -> FastStringEnv a
-lookupFsEnv :: FastStringEnv a -> FastString -> Maybe a
-lookupFsEnv_NF :: FastStringEnv a -> FastString -> a
-filterFsEnv :: (elt -> Bool) -> FastStringEnv elt -> FastStringEnv elt
-mapFsEnv :: (elt1 -> elt2) -> FastStringEnv elt1 -> FastStringEnv elt2
-
-emptyFsEnv = emptyUFM
-unitFsEnv x y = unitUFM x y
-extendFsEnv x y z = addToUFM x y z
-extendFsEnvList x l = addListToUFM x l
-lookupFsEnv x y = lookupUFM x y
-alterFsEnv = alterUFM
-mkFsEnv l = listToUFM l
-elemFsEnv x y = elemUFM x y
-plusFsEnv x y = plusUFM x y
-plusFsEnv_C f x y = plusUFM_C f x y
-extendFsEnv_C f x y z = addToUFM_C f x y z
-mapFsEnv f x = mapUFM f x
-extendFsEnv_Acc x y z a b = addToUFM_Acc x y z a b
-extendFsEnvList_C x y z = addListToUFM_C x y z
-delFromFsEnv x y = delFromUFM x y
-delListFromFsEnv x y = delListFromUFM x y
-filterFsEnv x y = filterUFM x y
-
-lookupFsEnv_NF env n = expectJust "lookupFsEnv_NF" (lookupFsEnv env n)
-
--- Deterministic FastStringEnv
--- See Note [Deterministic UniqFM] in GHC.Types.Unique.DFM for explanation why we need
--- DFastStringEnv.
-
-type DFastStringEnv a = UniqDFM a -- Domain is FastString
-
-emptyDFsEnv :: DFastStringEnv a
-emptyDFsEnv = emptyUDFM
-
-dFsEnvElts :: DFastStringEnv a -> [a]
-dFsEnvElts = eltsUDFM
-
-mkDFsEnv :: [(FastString,a)] -> DFastStringEnv a
-mkDFsEnv l = listToUDFM l
-
-lookupDFsEnv :: DFastStringEnv a -> FastString -> Maybe a
-lookupDFsEnv = lookupUDFM
diff --git a/compiler/utils/Fingerprint.hs b/compiler/utils/Fingerprint.hs
deleted file mode 100644
index 21f6a93c77..0000000000
--- a/compiler/utils/Fingerprint.hs
+++ /dev/null
@@ -1,47 +0,0 @@
-{-# LANGUAGE CPP #-}
-{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
-
--- ----------------------------------------------------------------------------
---
--- (c) The University of Glasgow 2006
---
--- Fingerprints for recompilation checking and ABI versioning.
---
--- https://gitlab.haskell.org/ghc/ghc/wikis/commentary/compiler/recompilation-avoidance
---
--- ----------------------------------------------------------------------------
-
-module Fingerprint (
- readHexFingerprint,
- fingerprintByteString,
- -- * Re-exported from GHC.Fingerprint
- Fingerprint(..), fingerprint0,
- fingerprintFingerprints,
- fingerprintData,
- fingerprintString,
- getFileHash
- ) where
-
-#include "HsVersions.h"
-
-import GhcPrelude
-
-import Foreign
-import GHC.IO
-import Numeric ( readHex )
-
-import qualified Data.ByteString as BS
-import qualified Data.ByteString.Unsafe as BS
-
-import GHC.Fingerprint
-
--- useful for parsing the output of 'md5sum', should we want to do that.
-readHexFingerprint :: String -> Fingerprint
-readHexFingerprint s = Fingerprint w1 w2
- where (s1,s2) = splitAt 16 s
- [(w1,"")] = readHex s1
- [(w2,"")] = readHex (take 16 s2)
-
-fingerprintByteString :: BS.ByteString -> Fingerprint
-fingerprintByteString bs = unsafeDupablePerformIO $
- BS.unsafeUseAsCStringLen bs $ \(ptr, len) -> fingerprintData (castPtr ptr) len
diff --git a/compiler/utils/FiniteMap.hs b/compiler/utils/FiniteMap.hs
deleted file mode 100644
index 0692830932..0000000000
--- a/compiler/utils/FiniteMap.hs
+++ /dev/null
@@ -1,31 +0,0 @@
--- Some extra functions to extend Data.Map
-
-module FiniteMap (
- insertList,
- insertListWith,
- deleteList,
- foldRight, foldRightWithKey
- ) where
-
-import GhcPrelude
-
-import Data.Map (Map)
-import qualified Data.Map as Map
-
-insertList :: Ord key => [(key,elt)] -> Map key elt -> Map key elt
-insertList xs m = foldl' (\m (k, v) -> Map.insert k v m) m xs
-
-insertListWith :: Ord key
- => (elt -> elt -> elt)
- -> [(key,elt)]
- -> Map key elt
- -> Map key elt
-insertListWith f xs m0 = foldl' (\m (k, v) -> Map.insertWith f k v m) m0 xs
-
-deleteList :: Ord key => [key] -> Map key elt -> Map key elt
-deleteList ks m = foldl' (flip Map.delete) m ks
-
-foldRight :: (elt -> a -> a) -> a -> Map key elt -> a
-foldRight = Map.foldr
-foldRightWithKey :: (key -> elt -> a -> a) -> a -> Map key elt -> a
-foldRightWithKey = Map.foldrWithKey
diff --git a/compiler/utils/GhcPrelude.hs b/compiler/utils/GhcPrelude.hs
deleted file mode 100644
index dd78f15573..0000000000
--- a/compiler/utils/GhcPrelude.hs
+++ /dev/null
@@ -1,33 +0,0 @@
-{-# LANGUAGE CPP #-}
-
--- | Custom GHC "Prelude"
---
--- This module serves as a replacement for the "Prelude" module
--- and abstracts over differences between the bootstrapping
--- GHC version, and may also provide a common default vocabulary.
-
--- Every module in GHC
--- * Is compiled with -XNoImplicitPrelude
--- * Explicitly imports GhcPrelude
-
-module GhcPrelude (module X) where
-
--- We export the 'Semigroup' class but w/o the (<>) operator to avoid
--- clashing with the (Outputable.<>) operator which is heavily used
--- through GHC's code-base.
-
-import Prelude as X hiding ((<>))
-import Data.Foldable as X (foldl')
-
-{-
-Note [Why do we import Prelude here?]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-The files ghc-boot-th.cabal, ghc-boot.cabal, ghci.cabal and
-ghc-heap.cabal contain the directive default-extensions:
-NoImplicitPrelude. There are two motivations for this:
- - Consistency with the compiler directory, which enables
- NoImplicitPrelude;
- - Allows loading the above dependent packages with ghc-in-ghci,
- giving a smoother development experience when adding new
- extensions.
--}
diff --git a/compiler/utils/GraphBase.hs b/compiler/utils/GraphBase.hs
deleted file mode 100644
index 67c362ff00..0000000000
--- a/compiler/utils/GraphBase.hs
+++ /dev/null
@@ -1,107 +0,0 @@
-
--- | Types for the general graph colorer.
-module GraphBase (
- Triv,
- Graph (..),
- initGraph,
- graphMapModify,
-
- Node (..), newNode,
-)
-
-
-where
-
-import GhcPrelude
-
-import GHC.Types.Unique.Set
-import GHC.Types.Unique.FM
-
-
--- | A fn to check if a node is trivially colorable
--- For graphs who's color classes are disjoint then a node is 'trivially colorable'
--- when it has less neighbors and exclusions than available colors for that node.
---
--- For graph's who's color classes overlap, ie some colors alias other colors, then
--- this can be a bit more tricky. There is a general way to calculate this, but
--- it's likely be too slow for use in the code. The coloring algorithm takes
--- a canned function which can be optimised by the user to be specific to the
--- specific graph being colored.
---
--- for details, see "A Generalised Algorithm for Graph-Coloring Register Allocation"
--- Smith, Ramsey, Holloway - PLDI 2004.
---
-type Triv k cls color
- = cls -- the class of the node we're trying to color.
- -> UniqSet k -- the node's neighbors.
- -> UniqSet color -- the node's exclusions.
- -> Bool
-
-
--- | The Interference graph.
--- There used to be more fields, but they were turfed out in a previous revision.
--- maybe we'll want more later..
---
-data Graph k cls color
- = Graph {
- -- | All active nodes in the graph.
- graphMap :: UniqFM (Node k cls color) }
-
-
--- | An empty graph.
-initGraph :: Graph k cls color
-initGraph
- = Graph
- { graphMap = emptyUFM }
-
-
--- | Modify the finite map holding the nodes in the graph.
-graphMapModify
- :: (UniqFM (Node k cls color) -> UniqFM (Node k cls color))
- -> Graph k cls color -> Graph k cls color
-
-graphMapModify f graph
- = graph { graphMap = f (graphMap graph) }
-
-
-
--- | Graph nodes.
--- Represents a thing that can conflict with another thing.
--- For the register allocater the nodes represent registers.
---
-data Node k cls color
- = Node {
- -- | A unique identifier for this node.
- nodeId :: k
-
- -- | The class of this node,
- -- determines the set of colors that can be used.
- , nodeClass :: cls
-
- -- | The color of this node, if any.
- , nodeColor :: Maybe color
-
- -- | Neighbors which must be colored differently to this node.
- , nodeConflicts :: UniqSet k
-
- -- | Colors that cannot be used by this node.
- , nodeExclusions :: UniqSet color
-
- -- | Colors that this node would prefer to be, in descending order.
- , nodePreference :: [color]
-
- -- | Neighbors that this node would like to be colored the same as.
- , nodeCoalesce :: UniqSet k }
-
-
--- | An empty node.
-newNode :: k -> cls -> Node k cls color
-newNode k cls
- = Node
- { nodeId = k
- , nodeClass = cls
- , nodeColor = Nothing
- , nodeConflicts = emptyUniqSet
- , nodeExclusions = emptyUniqSet
- , nodePreference = []
- , nodeCoalesce = emptyUniqSet }
diff --git a/compiler/utils/GraphColor.hs b/compiler/utils/GraphColor.hs
deleted file mode 100644
index d10b28175c..0000000000
--- a/compiler/utils/GraphColor.hs
+++ /dev/null
@@ -1,375 +0,0 @@
--- | Graph Coloring.
--- This is a generic graph coloring library, abstracted over the type of
--- the node keys, nodes and colors.
---
-
-{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
-
-module GraphColor (
- module GraphBase,
- module GraphOps,
- module GraphPpr,
- colorGraph
-)
-
-where
-
-import GhcPrelude
-
-import GraphBase
-import GraphOps
-import GraphPpr
-
-import GHC.Types.Unique
-import GHC.Types.Unique.FM
-import GHC.Types.Unique.Set
-import Outputable
-
-import Data.Maybe
-import Data.List
-
-
--- | Try to color a graph with this set of colors.
--- Uses Chaitin's algorithm to color the graph.
--- The graph is scanned for nodes which are deamed 'trivially colorable'. These nodes
--- are pushed onto a stack and removed from the graph.
--- Once this process is complete the graph can be colored by removing nodes from
--- the stack (ie in reverse order) and assigning them colors different to their neighbors.
---
-colorGraph
- :: ( Uniquable k, Uniquable cls, Uniquable color
- , Eq cls, Ord k
- , Outputable k, Outputable cls, Outputable color)
- => Bool -- ^ whether to do iterative coalescing
- -> Int -- ^ how many times we've tried to color this graph so far.
- -> UniqFM (UniqSet color) -- ^ map of (node class -> set of colors available for this class).
- -> Triv k cls color -- ^ fn to decide whether a node is trivially colorable.
- -> (Graph k cls color -> k) -- ^ fn to choose a node to potentially leave uncolored if nothing is trivially colorable.
- -> Graph k cls color -- ^ the graph to color.
-
- -> ( Graph k cls color -- the colored graph.
- , UniqSet k -- the set of nodes that we couldn't find a color for.
- , UniqFM k ) -- map of regs (r1 -> r2) that were coalesced
- -- r1 should be replaced by r2 in the source
-
-colorGraph iterative spinCount colors triv spill graph0
- = let
- -- If we're not doing iterative coalescing then do an aggressive coalescing first time
- -- around and then conservative coalescing for subsequent passes.
- --
- -- Aggressive coalescing is a quick way to get rid of many reg-reg moves. However, if
- -- there is a lot of register pressure and we do it on every round then it can make the
- -- graph less colorable and prevent the algorithm from converging in a sensible number
- -- of cycles.
- --
- (graph_coalesced, kksCoalesce1)
- = if iterative
- then (graph0, [])
- else if spinCount == 0
- then coalesceGraph True triv graph0
- else coalesceGraph False triv graph0
-
- -- run the scanner to slurp out all the trivially colorable nodes
- -- (and do coalescing if iterative coalescing is enabled)
- (ksTriv, ksProblems, kksCoalesce2)
- = colorScan iterative triv spill graph_coalesced
-
- -- If iterative coalescing is enabled, the scanner will coalesce the graph as does its business.
- -- We need to apply all the coalescences found by the scanner to the original
- -- graph before doing assignColors.
- --
- -- Because we've got the whole, non-pruned graph here we turn on aggressive coalescing
- -- to force all the (conservative) coalescences found during scanning.
- --
- (graph_scan_coalesced, _)
- = mapAccumL (coalesceNodes True triv) graph_coalesced kksCoalesce2
-
- -- color the trivially colorable nodes
- -- during scanning, keys of triv nodes were added to the front of the list as they were found
- -- this colors them in the reverse order, as required by the algorithm.
- (graph_triv, ksNoTriv)
- = assignColors colors graph_scan_coalesced ksTriv
-
- -- try and color the problem nodes
- -- problem nodes are the ones that were left uncolored because they weren't triv.
- -- theres a change we can color them here anyway.
- (graph_prob, ksNoColor)
- = assignColors colors graph_triv ksProblems
-
- -- if the trivially colorable nodes didn't color then something is probably wrong
- -- with the provided triv function.
- --
- in if not $ null ksNoTriv
- then pprPanic "colorGraph: trivially colorable nodes didn't color!" -- empty
- ( empty
- $$ text "ksTriv = " <> ppr ksTriv
- $$ text "ksNoTriv = " <> ppr ksNoTriv
- $$ text "colors = " <> ppr colors
- $$ empty
- $$ dotGraph (\_ -> text "white") triv graph_triv)
-
- else ( graph_prob
- , mkUniqSet ksNoColor -- the nodes that didn't color (spills)
- , if iterative
- then (listToUFM kksCoalesce2)
- else (listToUFM kksCoalesce1))
-
-
--- | Scan through the conflict graph separating out trivially colorable and
--- potentially uncolorable (problem) nodes.
---
--- Checking whether a node is trivially colorable or not is a reasonably expensive operation,
--- so after a triv node is found and removed from the graph it's no good to return to the 'start'
--- of the graph and recheck a bunch of nodes that will probably still be non-trivially colorable.
---
--- To ward against this, during each pass through the graph we collect up a list of triv nodes
--- that were found, and only remove them once we've finished the pass. The more nodes we can delete
--- at once the more likely it is that nodes we've already checked will become trivially colorable
--- for the next pass.
---
--- TODO: add work lists to finding triv nodes is easier.
--- If we've just scanned the graph, and removed triv nodes, then the only
--- nodes that we need to rescan are the ones we've removed edges from.
-
-colorScan
- :: ( Uniquable k, Uniquable cls, Uniquable color
- , Ord k, Eq cls
- , Outputable k, Outputable cls)
- => Bool -- ^ whether to do iterative coalescing
- -> Triv k cls color -- ^ fn to decide whether a node is trivially colorable
- -> (Graph k cls color -> k) -- ^ fn to choose a node to potentially leave uncolored if nothing is trivially colorable.
- -> Graph k cls color -- ^ the graph to scan
-
- -> ([k], [k], [(k, k)]) -- triv colorable nodes, problem nodes, pairs of nodes to coalesce
-
-colorScan iterative triv spill graph
- = colorScan_spin iterative triv spill graph [] [] []
-
-colorScan_spin
- :: ( Uniquable k, Uniquable cls, Uniquable color
- , Ord k, Eq cls
- , Outputable k, Outputable cls)
- => Bool
- -> Triv k cls color
- -> (Graph k cls color -> k)
- -> Graph k cls color
- -> [k]
- -> [k]
- -> [(k, k)]
- -> ([k], [k], [(k, k)])
-
-colorScan_spin iterative triv spill graph
- ksTriv ksSpill kksCoalesce
-
- -- if the graph is empty then we're done
- | isNullUFM $ graphMap graph
- = (ksTriv, ksSpill, reverse kksCoalesce)
-
- -- Simplify:
- -- Look for trivially colorable nodes.
- -- If we can find some then remove them from the graph and go back for more.
- --
- | nsTrivFound@(_:_)
- <- scanGraph (\node -> triv (nodeClass node) (nodeConflicts node) (nodeExclusions node)
-
- -- for iterative coalescing we only want non-move related
- -- nodes here
- && (not iterative || isEmptyUniqSet (nodeCoalesce node)))
- $ graph
-
- , ksTrivFound <- map nodeId nsTrivFound
- , graph2 <- foldr (\k g -> let Just g' = delNode k g
- in g')
- graph ksTrivFound
-
- = colorScan_spin iterative triv spill graph2
- (ksTrivFound ++ ksTriv)
- ksSpill
- kksCoalesce
-
- -- Coalesce:
- -- If we're doing iterative coalescing and no triv nodes are available
- -- then it's time for a coalescing pass.
- | iterative
- = case coalesceGraph False triv graph of
-
- -- we were able to coalesce something
- -- go back to Simplify and see if this frees up more nodes to be trivially colorable.
- (graph2, kksCoalesceFound@(_:_))
- -> colorScan_spin iterative triv spill graph2
- ksTriv ksSpill (reverse kksCoalesceFound ++ kksCoalesce)
-
- -- Freeze:
- -- nothing could be coalesced (or was triv),
- -- time to choose a node to freeze and give up on ever coalescing it.
- (graph2, [])
- -> case freezeOneInGraph graph2 of
-
- -- we were able to freeze something
- -- hopefully this will free up something for Simplify
- (graph3, True)
- -> colorScan_spin iterative triv spill graph3
- ksTriv ksSpill kksCoalesce
-
- -- we couldn't find something to freeze either
- -- time for a spill
- (graph3, False)
- -> colorScan_spill iterative triv spill graph3
- ksTriv ksSpill kksCoalesce
-
- -- spill time
- | otherwise
- = colorScan_spill iterative triv spill graph
- ksTriv ksSpill kksCoalesce
-
-
--- Select:
--- we couldn't find any triv nodes or things to freeze or coalesce,
--- and the graph isn't empty yet.. We'll have to choose a spill
--- candidate and leave it uncolored.
---
-colorScan_spill
- :: ( Uniquable k, Uniquable cls, Uniquable color
- , Ord k, Eq cls
- , Outputable k, Outputable cls)
- => Bool
- -> Triv k cls color
- -> (Graph k cls color -> k)
- -> Graph k cls color
- -> [k]
- -> [k]
- -> [(k, k)]
- -> ([k], [k], [(k, k)])
-
-colorScan_spill iterative triv spill graph
- ksTriv ksSpill kksCoalesce
-
- = let kSpill = spill graph
- Just graph' = delNode kSpill graph
- in colorScan_spin iterative triv spill graph'
- ksTriv (kSpill : ksSpill) kksCoalesce
-
-
--- | Try to assign a color to all these nodes.
-
-assignColors
- :: ( Uniquable k, Uniquable cls, Uniquable color
- , Outputable cls)
- => UniqFM (UniqSet color) -- ^ map of (node class -> set of colors available for this class).
- -> Graph k cls color -- ^ the graph
- -> [k] -- ^ nodes to assign a color to.
- -> ( Graph k cls color -- the colored graph
- , [k]) -- the nodes that didn't color.
-
-assignColors colors graph ks
- = assignColors' colors graph [] ks
-
- where assignColors' _ graph prob []
- = (graph, prob)
-
- assignColors' colors graph prob (k:ks)
- = case assignColor colors k graph of
-
- -- couldn't color this node
- Nothing -> assignColors' colors graph (k : prob) ks
-
- -- this node colored ok, so do the rest
- Just graph' -> assignColors' colors graph' prob ks
-
-
- assignColor colors u graph
- | Just c <- selectColor colors graph u
- = Just (setColor u c graph)
-
- | otherwise
- = Nothing
-
-
-
--- | Select a color for a certain node
--- taking into account preferences, neighbors and exclusions.
--- returns Nothing if no color can be assigned to this node.
---
-selectColor
- :: ( Uniquable k, Uniquable cls, Uniquable color
- , Outputable cls)
- => UniqFM (UniqSet color) -- ^ map of (node class -> set of colors available for this class).
- -> Graph k cls color -- ^ the graph
- -> k -- ^ key of the node to select a color for.
- -> Maybe color
-
-selectColor colors graph u
- = let -- lookup the node
- Just node = lookupNode graph u
-
- -- lookup the available colors for the class of this node.
- colors_avail
- = case lookupUFM colors (nodeClass node) of
- Nothing -> pprPanic "selectColor: no colors available for class " (ppr (nodeClass node))
- Just cs -> cs
-
- -- find colors we can't use because they're already being used
- -- by a node that conflicts with this one.
- Just nsConflicts
- = sequence
- $ map (lookupNode graph)
- $ nonDetEltsUniqSet
- $ nodeConflicts node
- -- See Note [Unique Determinism and code generation]
-
- colors_conflict = mkUniqSet
- $ catMaybes
- $ map nodeColor nsConflicts
-
- -- the prefs of our neighbors
- colors_neighbor_prefs
- = mkUniqSet
- $ concatMap nodePreference nsConflicts
-
- -- colors that are still valid for us
- colors_ok_ex = minusUniqSet colors_avail (nodeExclusions node)
- colors_ok = minusUniqSet colors_ok_ex colors_conflict
-
- -- the colors that we prefer, and are still ok
- colors_ok_pref = intersectUniqSets
- (mkUniqSet $ nodePreference node) colors_ok
-
- -- the colors that we could choose while being nice to our neighbors
- colors_ok_nice = minusUniqSet
- colors_ok colors_neighbor_prefs
-
- -- the best of all possible worlds..
- colors_ok_pref_nice
- = intersectUniqSets
- colors_ok_nice colors_ok_pref
-
- -- make the decision
- chooseColor
-
- -- everyone is happy, yay!
- | not $ isEmptyUniqSet colors_ok_pref_nice
- , c : _ <- filter (\x -> elementOfUniqSet x colors_ok_pref_nice)
- (nodePreference node)
- = Just c
-
- -- we've got one of our preferences
- | not $ isEmptyUniqSet colors_ok_pref
- , c : _ <- filter (\x -> elementOfUniqSet x colors_ok_pref)
- (nodePreference node)
- = Just c
-
- -- it wasn't a preference, but it was still ok
- | not $ isEmptyUniqSet colors_ok
- , c : _ <- nonDetEltsUniqSet colors_ok
- -- See Note [Unique Determinism and code generation]
- = Just c
-
- -- no colors were available for us this time.
- -- looks like we're going around the loop again..
- | otherwise
- = Nothing
-
- in chooseColor
-
-
-
diff --git a/compiler/utils/GraphOps.hs b/compiler/utils/GraphOps.hs
deleted file mode 100644
index a1693c6a5a..0000000000
--- a/compiler/utils/GraphOps.hs
+++ /dev/null
@@ -1,682 +0,0 @@
--- | Basic operations on graphs.
---
-
-{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
-
-module GraphOps (
- addNode, delNode, getNode, lookupNode, modNode,
- size,
- union,
- addConflict, delConflict, addConflicts,
- addCoalesce, delCoalesce,
- addExclusion, addExclusions,
- addPreference,
- coalesceNodes, coalesceGraph,
- freezeNode, freezeOneInGraph, freezeAllInGraph,
- scanGraph,
- setColor,
- validateGraph,
- slurpNodeConflictCount
-)
-where
-
-import GhcPrelude
-
-import GraphBase
-
-import Outputable
-import GHC.Types.Unique
-import GHC.Types.Unique.Set
-import GHC.Types.Unique.FM
-
-import Data.List hiding (union)
-import Data.Maybe
-
--- | Lookup a node from the graph.
-lookupNode
- :: Uniquable k
- => Graph k cls color
- -> k -> Maybe (Node k cls color)
-
-lookupNode graph k
- = lookupUFM (graphMap graph) k
-
-
--- | Get a node from the graph, throwing an error if it's not there
-getNode
- :: Uniquable k
- => Graph k cls color
- -> k -> Node k cls color
-
-getNode graph k
- = case lookupUFM (graphMap graph) k of
- Just node -> node
- Nothing -> panic "ColorOps.getNode: not found"
-
-
--- | Add a node to the graph, linking up its edges
-addNode :: Uniquable k
- => k -> Node k cls color
- -> Graph k cls color -> Graph k cls color
-
-addNode k node graph
- = let
- -- add back conflict edges from other nodes to this one
- map_conflict =
- nonDetFoldUniqSet
- -- It's OK to use nonDetFoldUFM here because the
- -- operation is commutative
- (adjustUFM_C (\n -> n { nodeConflicts =
- addOneToUniqSet (nodeConflicts n) k}))
- (graphMap graph)
- (nodeConflicts node)
-
- -- add back coalesce edges from other nodes to this one
- map_coalesce =
- nonDetFoldUniqSet
- -- It's OK to use nonDetFoldUFM here because the
- -- operation is commutative
- (adjustUFM_C (\n -> n { nodeCoalesce =
- addOneToUniqSet (nodeCoalesce n) k}))
- map_conflict
- (nodeCoalesce node)
-
- in graph
- { graphMap = addToUFM map_coalesce k node}
-
-
--- | Delete a node and all its edges from the graph.
-delNode :: (Uniquable k)
- => k -> Graph k cls color -> Maybe (Graph k cls color)
-
-delNode k graph
- | Just node <- lookupNode graph k
- = let -- delete conflict edges from other nodes to this one.
- graph1 = foldl' (\g k1 -> let Just g' = delConflict k1 k g in g') graph
- $ nonDetEltsUniqSet (nodeConflicts node)
-
- -- delete coalesce edge from other nodes to this one.
- graph2 = foldl' (\g k1 -> let Just g' = delCoalesce k1 k g in g') graph1
- $ nonDetEltsUniqSet (nodeCoalesce node)
- -- See Note [Unique Determinism and code generation]
-
- -- delete the node
- graph3 = graphMapModify (\fm -> delFromUFM fm k) graph2
-
- in Just graph3
-
- | otherwise
- = Nothing
-
-
--- | Modify a node in the graph.
--- returns Nothing if the node isn't present.
---
-modNode :: Uniquable k
- => (Node k cls color -> Node k cls color)
- -> k -> Graph k cls color -> Maybe (Graph k cls color)
-
-modNode f k graph
- = case lookupNode graph k of
- Just Node{}
- -> Just
- $ graphMapModify
- (\fm -> let Just node = lookupUFM fm k
- node' = f node
- in addToUFM fm k node')
- graph
-
- Nothing -> Nothing
-
-
--- | Get the size of the graph, O(n)
-size :: Graph k cls color -> Int
-
-size graph
- = sizeUFM $ graphMap graph
-
-
--- | Union two graphs together.
-union :: Graph k cls color -> Graph k cls color -> Graph k cls color
-
-union graph1 graph2
- = Graph
- { graphMap = plusUFM (graphMap graph1) (graphMap graph2) }
-
-
--- | Add a conflict between nodes to the graph, creating the nodes required.
--- Conflicts are virtual regs which need to be colored differently.
-addConflict
- :: Uniquable k
- => (k, cls) -> (k, cls)
- -> Graph k cls color -> Graph k cls color
-
-addConflict (u1, c1) (u2, c2)
- = let addNeighbor u c u'
- = adjustWithDefaultUFM
- (\node -> node { nodeConflicts = addOneToUniqSet (nodeConflicts node) u' })
- (newNode u c) { nodeConflicts = unitUniqSet u' }
- u
-
- in graphMapModify
- ( addNeighbor u1 c1 u2
- . addNeighbor u2 c2 u1)
-
-
--- | Delete a conflict edge. k1 -> k2
--- returns Nothing if the node isn't in the graph
-delConflict
- :: Uniquable k
- => k -> k
- -> Graph k cls color -> Maybe (Graph k cls color)
-
-delConflict k1 k2
- = modNode
- (\node -> node { nodeConflicts = delOneFromUniqSet (nodeConflicts node) k2 })
- k1
-
-
--- | Add some conflicts to the graph, creating nodes if required.
--- All the nodes in the set are taken to conflict with each other.
-addConflicts
- :: Uniquable k
- => UniqSet k -> (k -> cls)
- -> Graph k cls color -> Graph k cls color
-
-addConflicts conflicts getClass
-
- -- just a single node, but no conflicts, create the node anyway.
- | (u : []) <- nonDetEltsUniqSet conflicts
- = graphMapModify
- $ adjustWithDefaultUFM
- id
- (newNode u (getClass u))
- u
-
- | otherwise
- = graphMapModify
- $ \fm -> foldl' (\g u -> addConflictSet1 u getClass conflicts g) fm
- $ nonDetEltsUniqSet conflicts
- -- See Note [Unique Determinism and code generation]
-
-
-addConflictSet1 :: Uniquable k
- => k -> (k -> cls) -> UniqSet k
- -> UniqFM (Node k cls color)
- -> UniqFM (Node k cls color)
-addConflictSet1 u getClass set
- = case delOneFromUniqSet set u of
- set' -> adjustWithDefaultUFM
- (\node -> node { nodeConflicts = unionUniqSets set' (nodeConflicts node) } )
- (newNode u (getClass u)) { nodeConflicts = set' }
- u
-
-
--- | Add an exclusion to the graph, creating nodes if required.
--- These are extra colors that the node cannot use.
-addExclusion
- :: (Uniquable k, Uniquable color)
- => k -> (k -> cls) -> color
- -> Graph k cls color -> Graph k cls color
-
-addExclusion u getClass color
- = graphMapModify
- $ adjustWithDefaultUFM
- (\node -> node { nodeExclusions = addOneToUniqSet (nodeExclusions node) color })
- (newNode u (getClass u)) { nodeExclusions = unitUniqSet color }
- u
-
-addExclusions
- :: (Uniquable k, Uniquable color)
- => k -> (k -> cls) -> [color]
- -> Graph k cls color -> Graph k cls color
-
-addExclusions u getClass colors graph
- = foldr (addExclusion u getClass) graph colors
-
-
--- | Add a coalescence edge to the graph, creating nodes if required.
--- It is considered adventageous to assign the same color to nodes in a coalesence.
-addCoalesce
- :: Uniquable k
- => (k, cls) -> (k, cls)
- -> Graph k cls color -> Graph k cls color
-
-addCoalesce (u1, c1) (u2, c2)
- = let addCoalesce u c u'
- = adjustWithDefaultUFM
- (\node -> node { nodeCoalesce = addOneToUniqSet (nodeCoalesce node) u' })
- (newNode u c) { nodeCoalesce = unitUniqSet u' }
- u
-
- in graphMapModify
- ( addCoalesce u1 c1 u2
- . addCoalesce u2 c2 u1)
-
-
--- | Delete a coalescence edge (k1 -> k2) from the graph.
-delCoalesce
- :: Uniquable k
- => k -> k
- -> Graph k cls color -> Maybe (Graph k cls color)
-
-delCoalesce k1 k2
- = modNode (\node -> node { nodeCoalesce = delOneFromUniqSet (nodeCoalesce node) k2 })
- k1
-
-
--- | Add a color preference to the graph, creating nodes if required.
--- The most recently added preference is the most preferred.
--- The algorithm tries to assign a node it's preferred color if possible.
---
-addPreference
- :: Uniquable k
- => (k, cls) -> color
- -> Graph k cls color -> Graph k cls color
-
-addPreference (u, c) color
- = graphMapModify
- $ adjustWithDefaultUFM
- (\node -> node { nodePreference = color : (nodePreference node) })
- (newNode u c) { nodePreference = [color] }
- u
-
-
--- | Do aggressive coalescing on this graph.
--- returns the new graph and the list of pairs of nodes that got coalesced together.
--- for each pair, the resulting node will have the least key and be second in the pair.
---
-coalesceGraph
- :: (Uniquable k, Ord k, Eq cls, Outputable k)
- => Bool -- ^ If True, coalesce nodes even if this might make the graph
- -- less colorable (aggressive coalescing)
- -> Triv k cls color
- -> Graph k cls color
- -> ( Graph k cls color
- , [(k, k)]) -- pairs of nodes that were coalesced, in the order that the
- -- coalescing was applied.
-
-coalesceGraph aggressive triv graph
- = coalesceGraph' aggressive triv graph []
-
-coalesceGraph'
- :: (Uniquable k, Ord k, Eq cls, Outputable k)
- => Bool
- -> Triv k cls color
- -> Graph k cls color
- -> [(k, k)]
- -> ( Graph k cls color
- , [(k, k)])
-coalesceGraph' aggressive triv graph kkPairsAcc
- = let
- -- find all the nodes that have coalescence edges
- cNodes = filter (\node -> not $ isEmptyUniqSet (nodeCoalesce node))
- $ nonDetEltsUFM $ graphMap graph
- -- See Note [Unique Determinism and code generation]
-
- -- build a list of pairs of keys for node's we'll try and coalesce
- -- every pair of nodes will appear twice in this list
- -- ie [(k1, k2), (k2, k1) ... ]
- -- This is ok, GrapOps.coalesceNodes handles this and it's convenient for
- -- build a list of what nodes get coalesced together for later on.
- --
- cList = [ (nodeId node1, k2)
- | node1 <- cNodes
- , k2 <- nonDetEltsUniqSet $ nodeCoalesce node1 ]
- -- See Note [Unique Determinism and code generation]
-
- -- do the coalescing, returning the new graph and a list of pairs of keys
- -- that got coalesced together.
- (graph', mPairs)
- = mapAccumL (coalesceNodes aggressive triv) graph cList
-
- -- keep running until there are no more coalesces can be found
- in case catMaybes mPairs of
- [] -> (graph', reverse kkPairsAcc)
- pairs -> coalesceGraph' aggressive triv graph' (reverse pairs ++ kkPairsAcc)
-
-
--- | Coalesce this pair of nodes unconditionally \/ aggressively.
--- The resulting node is the one with the least key.
---
--- returns: Just the pair of keys if the nodes were coalesced
--- the second element of the pair being the least one
---
--- Nothing if either of the nodes weren't in the graph
-
-coalesceNodes
- :: (Uniquable k, Ord k, Eq cls)
- => Bool -- ^ If True, coalesce nodes even if this might make the graph
- -- less colorable (aggressive coalescing)
- -> Triv k cls color
- -> Graph k cls color
- -> (k, k) -- ^ keys of the nodes to be coalesced
- -> (Graph k cls color, Maybe (k, k))
-
-coalesceNodes aggressive triv graph (k1, k2)
- | (kMin, kMax) <- if k1 < k2
- then (k1, k2)
- else (k2, k1)
-
- -- the nodes being coalesced must be in the graph
- , Just nMin <- lookupNode graph kMin
- , Just nMax <- lookupNode graph kMax
-
- -- can't coalesce conflicting modes
- , not $ elementOfUniqSet kMin (nodeConflicts nMax)
- , not $ elementOfUniqSet kMax (nodeConflicts nMin)
-
- -- can't coalesce the same node
- , nodeId nMin /= nodeId nMax
-
- = coalesceNodes_merge aggressive triv graph kMin kMax nMin nMax
-
- -- don't do the coalescing after all
- | otherwise
- = (graph, Nothing)
-
-coalesceNodes_merge
- :: (Uniquable k, Eq cls)
- => Bool
- -> Triv k cls color
- -> Graph k cls color
- -> k -> k
- -> Node k cls color
- -> Node k cls color
- -> (Graph k cls color, Maybe (k, k))
-
-coalesceNodes_merge aggressive triv graph kMin kMax nMin nMax
-
- -- sanity checks
- | nodeClass nMin /= nodeClass nMax
- = error "GraphOps.coalesceNodes: can't coalesce nodes of different classes."
-
- | not (isNothing (nodeColor nMin) && isNothing (nodeColor nMax))
- = error "GraphOps.coalesceNodes: can't coalesce colored nodes."
-
- ---
- | otherwise
- = let
- -- the new node gets all the edges from its two components
- node =
- Node { nodeId = kMin
- , nodeClass = nodeClass nMin
- , nodeColor = Nothing
-
- -- nodes don't conflict with themselves..
- , nodeConflicts
- = (unionUniqSets (nodeConflicts nMin) (nodeConflicts nMax))
- `delOneFromUniqSet` kMin
- `delOneFromUniqSet` kMax
-
- , nodeExclusions = unionUniqSets (nodeExclusions nMin) (nodeExclusions nMax)
- , nodePreference = nodePreference nMin ++ nodePreference nMax
-
- -- nodes don't coalesce with themselves..
- , nodeCoalesce
- = (unionUniqSets (nodeCoalesce nMin) (nodeCoalesce nMax))
- `delOneFromUniqSet` kMin
- `delOneFromUniqSet` kMax
- }
-
- in coalesceNodes_check aggressive triv graph kMin kMax node
-
-coalesceNodes_check
- :: Uniquable k
- => Bool
- -> Triv k cls color
- -> Graph k cls color
- -> k -> k
- -> Node k cls color
- -> (Graph k cls color, Maybe (k, k))
-
-coalesceNodes_check aggressive triv graph kMin kMax node
-
- -- Unless we're coalescing aggressively, if the result node is not trivially
- -- colorable then don't do the coalescing.
- | not aggressive
- , not $ triv (nodeClass node) (nodeConflicts node) (nodeExclusions node)
- = (graph, Nothing)
-
- | otherwise
- = let -- delete the old nodes from the graph and add the new one
- Just graph1 = delNode kMax graph
- Just graph2 = delNode kMin graph1
- graph3 = addNode kMin node graph2
-
- in (graph3, Just (kMax, kMin))
-
-
--- | Freeze a node
--- This is for the iterative coalescer.
--- By freezing a node we give up on ever coalescing it.
--- Move all its coalesce edges into the frozen set - and update
--- back edges from other nodes.
---
-freezeNode
- :: Uniquable k
- => k -- ^ key of the node to freeze
- -> Graph k cls color -- ^ the graph
- -> Graph k cls color -- ^ graph with that node frozen
-
-freezeNode k
- = graphMapModify
- $ \fm ->
- let -- freeze all the edges in the node to be frozen
- Just node = lookupUFM fm k
- node' = node
- { nodeCoalesce = emptyUniqSet }
-
- fm1 = addToUFM fm k node'
-
- -- update back edges pointing to this node
- freezeEdge k node
- = if elementOfUniqSet k (nodeCoalesce node)
- then node { nodeCoalesce = delOneFromUniqSet (nodeCoalesce node) k }
- else node -- panic "GraphOps.freezeNode: edge to freeze wasn't in the coalesce set"
- -- If the edge isn't actually in the coelesce set then just ignore it.
-
- fm2 = nonDetFoldUniqSet (adjustUFM_C (freezeEdge k)) fm1
- -- It's OK to use nonDetFoldUFM here because the operation
- -- is commutative
- $ nodeCoalesce node
-
- in fm2
-
-
--- | Freeze one node in the graph
--- This if for the iterative coalescer.
--- Look for a move related node of low degree and freeze it.
---
--- We probably don't need to scan the whole graph looking for the node of absolute
--- lowest degree. Just sample the first few and choose the one with the lowest
--- degree out of those. Also, we don't make any distinction between conflicts of different
--- classes.. this is just a heuristic, after all.
---
--- IDEA: freezing a node might free it up for Simplify.. would be good to check for triv
--- right here, and add it to a worklist if known triv\/non-move nodes.
---
-freezeOneInGraph
- :: (Uniquable k)
- => Graph k cls color
- -> ( Graph k cls color -- the new graph
- , Bool ) -- whether we found a node to freeze
-
-freezeOneInGraph graph
- = let compareNodeDegree n1 n2
- = compare (sizeUniqSet $ nodeConflicts n1) (sizeUniqSet $ nodeConflicts n2)
-
- candidates
- = sortBy compareNodeDegree
- $ take 5 -- 5 isn't special, it's just a small number.
- $ scanGraph (\node -> not $ isEmptyUniqSet (nodeCoalesce node)) graph
-
- in case candidates of
-
- -- there wasn't anything available to freeze
- [] -> (graph, False)
-
- -- we found something to freeze
- (n : _)
- -> ( freezeNode (nodeId n) graph
- , True)
-
-
--- | Freeze all the nodes in the graph
--- for debugging the iterative allocator.
---
-freezeAllInGraph
- :: (Uniquable k)
- => Graph k cls color
- -> Graph k cls color
-
-freezeAllInGraph graph
- = foldr freezeNode graph
- $ map nodeId
- $ nonDetEltsUFM $ graphMap graph
- -- See Note [Unique Determinism and code generation]
-
-
--- | Find all the nodes in the graph that meet some criteria
---
-scanGraph
- :: (Node k cls color -> Bool)
- -> Graph k cls color
- -> [Node k cls color]
-
-scanGraph match graph
- = filter match $ nonDetEltsUFM $ graphMap graph
- -- See Note [Unique Determinism and code generation]
-
-
--- | validate the internal structure of a graph
--- all its edges should point to valid nodes
--- If they don't then throw an error
---
-validateGraph
- :: (Uniquable k, Outputable k, Eq color)
- => SDoc -- ^ extra debugging info to display on error
- -> Bool -- ^ whether this graph is supposed to be colored.
- -> Graph k cls color -- ^ graph to validate
- -> Graph k cls color -- ^ validated graph
-
-validateGraph doc isColored graph
-
- -- Check that all edges point to valid nodes.
- | edges <- unionManyUniqSets
- ( (map nodeConflicts $ nonDetEltsUFM $ graphMap graph)
- ++ (map nodeCoalesce $ nonDetEltsUFM $ graphMap graph))
-
- , nodes <- mkUniqSet $ map nodeId $ nonDetEltsUFM $ graphMap graph
- , badEdges <- minusUniqSet edges nodes
- , not $ isEmptyUniqSet badEdges
- = pprPanic "GraphOps.validateGraph"
- ( text "Graph has edges that point to non-existent nodes"
- $$ text " bad edges: " <> pprUFM (getUniqSet badEdges) (vcat . map ppr)
- $$ doc )
-
- -- Check that no conflicting nodes have the same color
- | badNodes <- filter (not . (checkNode graph))
- $ nonDetEltsUFM $ graphMap graph
- -- See Note [Unique Determinism and code generation]
- , not $ null badNodes
- = pprPanic "GraphOps.validateGraph"
- ( text "Node has same color as one of it's conflicts"
- $$ text " bad nodes: " <> hcat (map (ppr . nodeId) badNodes)
- $$ doc)
-
- -- If this is supposed to be a colored graph,
- -- check that all nodes have a color.
- | isColored
- , badNodes <- filter (\n -> isNothing $ nodeColor n)
- $ nonDetEltsUFM $ graphMap graph
- , not $ null badNodes
- = pprPanic "GraphOps.validateGraph"
- ( text "Supposably colored graph has uncolored nodes."
- $$ text " uncolored nodes: " <> hcat (map (ppr . nodeId) badNodes)
- $$ doc )
-
-
- -- graph looks ok
- | otherwise
- = graph
-
-
--- | If this node is colored, check that all the nodes which
--- conflict with it have different colors.
-checkNode
- :: (Uniquable k, Eq color)
- => Graph k cls color
- -> Node k cls color
- -> Bool -- ^ True if this node is ok
-
-checkNode graph node
- | Just color <- nodeColor node
- , Just neighbors <- sequence $ map (lookupNode graph)
- $ nonDetEltsUniqSet $ nodeConflicts node
- -- See Note [Unique Determinism and code generation]
-
- , neighbourColors <- catMaybes $ map nodeColor neighbors
- , elem color neighbourColors
- = False
-
- | otherwise
- = True
-
-
-
--- | Slurp out a map of how many nodes had a certain number of conflict neighbours
-
-slurpNodeConflictCount
- :: Graph k cls color
- -> UniqFM (Int, Int) -- ^ (conflict neighbours, num nodes with that many conflicts)
-
-slurpNodeConflictCount graph
- = addListToUFM_C
- (\(c1, n1) (_, n2) -> (c1, n1 + n2))
- emptyUFM
- $ map (\node
- -> let count = sizeUniqSet $ nodeConflicts node
- in (count, (count, 1)))
- $ nonDetEltsUFM
- -- See Note [Unique Determinism and code generation]
- $ graphMap graph
-
-
--- | Set the color of a certain node
-setColor
- :: Uniquable k
- => k -> color
- -> Graph k cls color -> Graph k cls color
-
-setColor u color
- = graphMapModify
- $ adjustUFM_C
- (\n -> n { nodeColor = Just color })
- u
-
-
-{-# INLINE adjustWithDefaultUFM #-}
-adjustWithDefaultUFM
- :: Uniquable k
- => (a -> a) -> a -> k
- -> UniqFM a -> UniqFM a
-
-adjustWithDefaultUFM f def k map
- = addToUFM_C
- (\old _ -> f old)
- map
- k def
-
--- Argument order different from UniqFM's adjustUFM
-{-# INLINE adjustUFM_C #-}
-adjustUFM_C
- :: Uniquable k
- => (a -> a)
- -> k -> UniqFM a -> UniqFM a
-
-adjustUFM_C f k map
- = case lookupUFM map k of
- Nothing -> map
- Just a -> addToUFM map k (f a)
-
diff --git a/compiler/utils/GraphPpr.hs b/compiler/utils/GraphPpr.hs
deleted file mode 100644
index 4327ec881c..0000000000
--- a/compiler/utils/GraphPpr.hs
+++ /dev/null
@@ -1,173 +0,0 @@
-
--- | Pretty printing of graphs.
-
-module GraphPpr (
- dumpGraph,
- dotGraph
-)
-where
-
-import GhcPrelude
-
-import GraphBase
-
-import Outputable
-import GHC.Types.Unique
-import GHC.Types.Unique.Set
-import GHC.Types.Unique.FM
-
-import Data.List (mapAccumL)
-import Data.Maybe
-
-
--- | Pretty print a graph in a somewhat human readable format.
-dumpGraph
- :: (Outputable k, Outputable color)
- => Graph k cls color -> SDoc
-
-dumpGraph graph
- = text "Graph"
- $$ pprUFM (graphMap graph) (vcat . map dumpNode)
-
-dumpNode
- :: (Outputable k, Outputable color)
- => Node k cls color -> SDoc
-
-dumpNode node
- = text "Node " <> ppr (nodeId node)
- $$ text "conflicts "
- <> parens (int (sizeUniqSet $ nodeConflicts node))
- <> text " = "
- <> ppr (nodeConflicts node)
-
- $$ text "exclusions "
- <> parens (int (sizeUniqSet $ nodeExclusions node))
- <> text " = "
- <> ppr (nodeExclusions node)
-
- $$ text "coalesce "
- <> parens (int (sizeUniqSet $ nodeCoalesce node))
- <> text " = "
- <> ppr (nodeCoalesce node)
-
- $$ space
-
-
-
--- | Pretty print a graph in graphviz .dot format.
--- Conflicts get solid edges.
--- Coalescences get dashed edges.
-dotGraph
- :: ( Uniquable k
- , Outputable k, Outputable cls, Outputable color)
- => (color -> SDoc) -- ^ What graphviz color to use for each node color
- -- It's usually safe to return X11 style colors here,
- -- ie "red", "green" etc or a hex triplet #aaff55 etc
- -> Triv k cls color
- -> Graph k cls color -> SDoc
-
-dotGraph colorMap triv graph
- = let nodes = nonDetEltsUFM $ graphMap graph
- -- See Note [Unique Determinism and code generation]
- in vcat
- ( [ text "graph G {" ]
- ++ map (dotNode colorMap triv) nodes
- ++ (catMaybes $ snd $ mapAccumL dotNodeEdges emptyUniqSet nodes)
- ++ [ text "}"
- , space ])
-
-
-dotNode :: ( Outputable k, Outputable cls, Outputable color)
- => (color -> SDoc)
- -> Triv k cls color
- -> Node k cls color -> SDoc
-
-dotNode colorMap triv node
- = let name = ppr $ nodeId node
- cls = ppr $ nodeClass node
-
- excludes
- = hcat $ punctuate space
- $ map (\n -> text "-" <> ppr n)
- $ nonDetEltsUniqSet $ nodeExclusions node
- -- See Note [Unique Determinism and code generation]
-
- preferences
- = hcat $ punctuate space
- $ map (\n -> text "+" <> ppr n)
- $ nodePreference node
-
- expref = if and [isEmptyUniqSet (nodeExclusions node), null (nodePreference node)]
- then empty
- else text "\\n" <> (excludes <+> preferences)
-
- -- if the node has been colored then show that,
- -- otherwise indicate whether it looks trivially colorable.
- color
- | Just c <- nodeColor node
- = text "\\n(" <> ppr c <> text ")"
-
- | triv (nodeClass node) (nodeConflicts node) (nodeExclusions node)
- = text "\\n(" <> text "triv" <> text ")"
-
- | otherwise
- = text "\\n(" <> text "spill?" <> text ")"
-
- label = name <> text " :: " <> cls
- <> expref
- <> color
-
- pcolorC = case nodeColor node of
- Nothing -> text "style=filled fillcolor=white"
- Just c -> text "style=filled fillcolor=" <> doubleQuotes (colorMap c)
-
-
- pout = text "node [label=" <> doubleQuotes label <> space <> pcolorC <> text "]"
- <> space <> doubleQuotes name
- <> text ";"
-
- in pout
-
-
--- | Nodes in the graph are doubly linked, but we only want one edge for each
--- conflict if the graphviz graph. Traverse over the graph, but make sure
--- to only print the edges for each node once.
-
-dotNodeEdges
- :: ( Uniquable k
- , Outputable k)
- => UniqSet k
- -> Node k cls color
- -> (UniqSet k, Maybe SDoc)
-
-dotNodeEdges visited node
- | elementOfUniqSet (nodeId node) visited
- = ( visited
- , Nothing)
-
- | otherwise
- = let dconflicts
- = map (dotEdgeConflict (nodeId node))
- $ nonDetEltsUniqSet
- -- See Note [Unique Determinism and code generation]
- $ minusUniqSet (nodeConflicts node) visited
-
- dcoalesces
- = map (dotEdgeCoalesce (nodeId node))
- $ nonDetEltsUniqSet
- -- See Note [Unique Determinism and code generation]
- $ minusUniqSet (nodeCoalesce node) visited
-
- out = vcat dconflicts
- $$ vcat dcoalesces
-
- in ( addOneToUniqSet visited (nodeId node)
- , Just out)
-
- where dotEdgeConflict u1 u2
- = doubleQuotes (ppr u1) <> text " -- " <> doubleQuotes (ppr u2)
- <> text ";"
-
- dotEdgeCoalesce u1 u2
- = doubleQuotes (ppr u1) <> text " -- " <> doubleQuotes (ppr u2)
- <> space <> text "[ style = dashed ];"
diff --git a/compiler/utils/IOEnv.hs b/compiler/utils/IOEnv.hs
deleted file mode 100644
index f9da146da5..0000000000
--- a/compiler/utils/IOEnv.hs
+++ /dev/null
@@ -1,219 +0,0 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE DeriveFunctor #-}
---
--- (c) The University of Glasgow 2002-2006
---
--- The IO Monad with an environment
---
--- The environment is passed around as a Reader monad but
--- as its in the IO monad, mutable references can be used
--- for updating state.
---
-
-module IOEnv (
- IOEnv, -- Instance of Monad
-
- -- Monad utilities
- module MonadUtils,
-
- -- Errors
- failM, failWithM,
- IOEnvFailure(..),
-
- -- Getting at the environment
- getEnv, setEnv, updEnv,
-
- runIOEnv, unsafeInterleaveM, uninterruptibleMaskM_,
- tryM, tryAllM, tryMostM, fixM,
-
- -- I/O operations
- IORef, newMutVar, readMutVar, writeMutVar, updMutVar,
- atomicUpdMutVar, atomicUpdMutVar'
- ) where
-
-import GhcPrelude
-
-import GHC.Driver.Session
-import Exception
-import GHC.Types.Module
-import Panic
-
-import Data.IORef ( IORef, newIORef, readIORef, writeIORef, modifyIORef,
- atomicModifyIORef, atomicModifyIORef' )
-import System.IO.Unsafe ( unsafeInterleaveIO )
-import System.IO ( fixIO )
-import Control.Monad
-import MonadUtils
-import Control.Applicative (Alternative(..))
-
-----------------------------------------------------------------------
--- Defining the monad type
-----------------------------------------------------------------------
-
-
-newtype IOEnv env a = IOEnv (env -> IO a) deriving (Functor)
-
-unIOEnv :: IOEnv env a -> (env -> IO a)
-unIOEnv (IOEnv m) = m
-
-instance Monad (IOEnv m) where
- (>>=) = thenM
- (>>) = (*>)
-
-instance MonadFail (IOEnv m) where
- fail _ = failM -- Ignore the string
-
-instance Applicative (IOEnv m) where
- pure = returnM
- IOEnv f <*> IOEnv x = IOEnv (\ env -> f env <*> x env )
- (*>) = thenM_
-
-returnM :: a -> IOEnv env a
-returnM a = IOEnv (\ _ -> return a)
-
-thenM :: IOEnv env a -> (a -> IOEnv env b) -> IOEnv env b
-thenM (IOEnv m) f = IOEnv (\ env -> do { r <- m env ;
- unIOEnv (f r) env })
-
-thenM_ :: IOEnv env a -> IOEnv env b -> IOEnv env b
-thenM_ (IOEnv m) f = IOEnv (\ env -> do { _ <- m env ; unIOEnv f env })
-
-failM :: IOEnv env a
-failM = IOEnv (\ _ -> throwIO IOEnvFailure)
-
-failWithM :: String -> IOEnv env a
-failWithM s = IOEnv (\ _ -> ioError (userError s))
-
-data IOEnvFailure = IOEnvFailure
-
-instance Show IOEnvFailure where
- show IOEnvFailure = "IOEnv failure"
-
-instance Exception IOEnvFailure
-
-instance ExceptionMonad (IOEnv a) where
- gcatch act handle =
- IOEnv $ \s -> unIOEnv act s `gcatch` \e -> unIOEnv (handle e) s
- gmask f =
- IOEnv $ \s -> gmask $ \io_restore ->
- let
- g_restore (IOEnv m) = IOEnv $ \s -> io_restore (m s)
- in
- unIOEnv (f g_restore) s
-
-instance ContainsDynFlags env => HasDynFlags (IOEnv env) where
- getDynFlags = do env <- getEnv
- return $! extractDynFlags env
-
-instance ContainsModule env => HasModule (IOEnv env) where
- getModule = do env <- getEnv
- return $ extractModule env
-
-----------------------------------------------------------------------
--- Fundamental combinators specific to the monad
-----------------------------------------------------------------------
-
-
----------------------------
-runIOEnv :: env -> IOEnv env a -> IO a
-runIOEnv env (IOEnv m) = m env
-
-
----------------------------
-{-# NOINLINE fixM #-}
- -- Aargh! Not inlining fixM alleviates a space leak problem.
- -- Normally fixM is used with a lazy tuple match: if the optimiser is
- -- shown the definition of fixM, it occasionally transforms the code
- -- in such a way that the code generator doesn't spot the selector
- -- thunks. Sigh.
-
-fixM :: (a -> IOEnv env a) -> IOEnv env a
-fixM f = IOEnv (\ env -> fixIO (\ r -> unIOEnv (f r) env))
-
-
----------------------------
-tryM :: IOEnv env r -> IOEnv env (Either IOEnvFailure r)
--- Reflect UserError exceptions (only) into IOEnv monad
--- Other exceptions are not caught; they are simply propagated as exns
---
--- The idea is that errors in the program being compiled will give rise
--- to UserErrors. But, say, pattern-match failures in GHC itself should
--- not be caught here, else they'll be reported as errors in the program
--- begin compiled!
-tryM (IOEnv thing) = IOEnv (\ env -> tryIOEnvFailure (thing env))
-
-tryIOEnvFailure :: IO a -> IO (Either IOEnvFailure a)
-tryIOEnvFailure = try
-
--- XXX We shouldn't be catching everything, e.g. timeouts
-tryAllM :: IOEnv env r -> IOEnv env (Either SomeException r)
--- Catch *all* exceptions
--- This is used when running a Template-Haskell splice, when
--- even a pattern-match failure is a programmer error
-tryAllM (IOEnv thing) = IOEnv (\ env -> try (thing env))
-
-tryMostM :: IOEnv env r -> IOEnv env (Either SomeException r)
-tryMostM (IOEnv thing) = IOEnv (\ env -> tryMost (thing env))
-
----------------------------
-unsafeInterleaveM :: IOEnv env a -> IOEnv env a
-unsafeInterleaveM (IOEnv m) = IOEnv (\ env -> unsafeInterleaveIO (m env))
-
-uninterruptibleMaskM_ :: IOEnv env a -> IOEnv env a
-uninterruptibleMaskM_ (IOEnv m) = IOEnv (\ env -> uninterruptibleMask_ (m env))
-
-----------------------------------------------------------------------
--- Alternative/MonadPlus
-----------------------------------------------------------------------
-
-instance Alternative (IOEnv env) where
- empty = IOEnv (const empty)
- m <|> n = IOEnv (\env -> unIOEnv m env <|> unIOEnv n env)
-
-instance MonadPlus (IOEnv env)
-
-----------------------------------------------------------------------
--- Accessing input/output
-----------------------------------------------------------------------
-
-instance MonadIO (IOEnv env) where
- liftIO io = IOEnv (\ _ -> io)
-
-newMutVar :: a -> IOEnv env (IORef a)
-newMutVar val = liftIO (newIORef val)
-
-writeMutVar :: IORef a -> a -> IOEnv env ()
-writeMutVar var val = liftIO (writeIORef var val)
-
-readMutVar :: IORef a -> IOEnv env a
-readMutVar var = liftIO (readIORef var)
-
-updMutVar :: IORef a -> (a -> a) -> IOEnv env ()
-updMutVar var upd = liftIO (modifyIORef var upd)
-
--- | Atomically update the reference. Does not force the evaluation of the
--- new variable contents. For strict update, use 'atomicUpdMutVar''.
-atomicUpdMutVar :: IORef a -> (a -> (a, b)) -> IOEnv env b
-atomicUpdMutVar var upd = liftIO (atomicModifyIORef var upd)
-
--- | Strict variant of 'atomicUpdMutVar'.
-atomicUpdMutVar' :: IORef a -> (a -> (a, b)) -> IOEnv env b
-atomicUpdMutVar' var upd = liftIO (atomicModifyIORef' var upd)
-
-----------------------------------------------------------------------
--- Accessing the environment
-----------------------------------------------------------------------
-
-getEnv :: IOEnv env env
-{-# INLINE getEnv #-}
-getEnv = IOEnv (\ env -> return env)
-
--- | Perform a computation with a different environment
-setEnv :: env' -> IOEnv env' a -> IOEnv env a
-{-# INLINE setEnv #-}
-setEnv new_env (IOEnv m) = IOEnv (\ _ -> m new_env)
-
--- | Perform a computation with an altered environment
-updEnv :: (env -> env') -> IOEnv env' a -> IOEnv env a
-{-# INLINE updEnv #-}
-updEnv upd (IOEnv m) = IOEnv (\ env -> m (upd env))
diff --git a/compiler/utils/Json.hs b/compiler/utils/Json.hs
deleted file mode 100644
index 2bf00d3851..0000000000
--- a/compiler/utils/Json.hs
+++ /dev/null
@@ -1,56 +0,0 @@
-{-# LANGUAGE GADTs #-}
-module Json where
-
-import GhcPrelude
-
-import Outputable
-import Data.Char
-import Numeric
-
--- | Simple data type to represent JSON documents.
-data JsonDoc where
- JSNull :: JsonDoc
- JSBool :: Bool -> JsonDoc
- JSInt :: Int -> JsonDoc
- JSString :: String -> JsonDoc
- JSArray :: [JsonDoc] -> JsonDoc
- JSObject :: [(String, JsonDoc)] -> JsonDoc
-
-
--- This is simple and slow as it is only used for error reporting
-renderJSON :: JsonDoc -> SDoc
-renderJSON d =
- case d of
- JSNull -> text "null"
- JSBool b -> text $ if b then "true" else "false"
- JSInt n -> ppr n
- JSString s -> doubleQuotes $ text $ escapeJsonString s
- JSArray as -> brackets $ pprList renderJSON as
- JSObject fs -> braces $ pprList renderField fs
- where
- renderField :: (String, JsonDoc) -> SDoc
- renderField (s, j) = doubleQuotes (text s) <> colon <+> renderJSON j
-
- pprList pp xs = hcat (punctuate comma (map pp xs))
-
-escapeJsonString :: String -> String
-escapeJsonString = concatMap escapeChar
- where
- escapeChar '\b' = "\\b"
- escapeChar '\f' = "\\f"
- escapeChar '\n' = "\\n"
- escapeChar '\r' = "\\r"
- escapeChar '\t' = "\\t"
- escapeChar '"' = "\\\""
- escapeChar '\\' = "\\\\"
- escapeChar c | isControl c || fromEnum c >= 0x7f = uni_esc c
- escapeChar c = [c]
-
- uni_esc c = "\\u" ++ (pad 4 (showHex (fromEnum c) ""))
-
- pad n cs | len < n = replicate (n-len) '0' ++ cs
- | otherwise = cs
- where len = length cs
-
-class ToJson a where
- json :: a -> JsonDoc
diff --git a/compiler/utils/ListSetOps.hs b/compiler/utils/ListSetOps.hs
deleted file mode 100644
index 85233c9533..0000000000
--- a/compiler/utils/ListSetOps.hs
+++ /dev/null
@@ -1,180 +0,0 @@
-{-
-(c) The University of Glasgow 2006
-(c) The GRASP/AQUA Project, Glasgow University, 1992-1998
-
-\section[ListSetOps]{Set-like operations on lists}
--}
-
-{-# LANGUAGE CPP #-}
-
-module ListSetOps (
- unionLists, minusList, deleteBys,
-
- -- Association lists
- Assoc, assoc, assocMaybe, assocUsing, assocDefault, assocDefaultUsing,
-
- -- Duplicate handling
- hasNoDups, removeDups, findDupsEq,
- equivClasses,
-
- -- Indexing
- getNth
- ) where
-
-#include "HsVersions.h"
-
-import GhcPrelude
-
-import Outputable
-import Util
-
-import qualified Data.List as L
-import qualified Data.List.NonEmpty as NE
-import Data.List.NonEmpty (NonEmpty(..))
-import qualified Data.Set as S
-
-getNth :: Outputable a => [a] -> Int -> a
-getNth xs n = ASSERT2( xs `lengthExceeds` n, ppr n $$ ppr xs )
- xs !! n
-
-deleteBys :: (a -> a -> Bool) -> [a] -> [a] -> [a]
--- (deleteBys eq xs ys) returns xs-ys, using the given equality function
--- Just like 'Data.List.delete' but with an equality function
-deleteBys eq xs ys = foldl' (flip (L.deleteBy eq)) xs ys
-
-{-
-************************************************************************
-* *
- Treating lists as sets
- Assumes the lists contain no duplicates, but are unordered
-* *
-************************************************************************
--}
-
-
--- | Assumes that the arguments contain no duplicates
-unionLists :: (HasDebugCallStack, Outputable a, Eq a) => [a] -> [a] -> [a]
--- We special case some reasonable common patterns.
-unionLists xs [] = xs
-unionLists [] ys = ys
-unionLists [x] ys
- | isIn "unionLists" x ys = ys
- | otherwise = x:ys
-unionLists xs [y]
- | isIn "unionLists" y xs = xs
- | otherwise = y:xs
-unionLists xs ys
- = WARN(lengthExceeds xs 100 || lengthExceeds ys 100, ppr xs $$ ppr ys)
- [x | x <- xs, isn'tIn "unionLists" x ys] ++ ys
-
--- | Calculate the set difference of two lists. This is
--- /O((m + n) log n)/, where we subtract a list of /n/ elements
--- from a list of /m/ elements.
---
--- Extremely short cases are handled specially:
--- When /m/ or /n/ is 0, this takes /O(1)/ time. When /m/ is 1,
--- it takes /O(n)/ time.
-minusList :: Ord a => [a] -> [a] -> [a]
--- There's no point building a set to perform just one lookup, so we handle
--- extremely short lists specially. It might actually be better to use
--- an O(m*n) algorithm when m is a little longer (perhaps up to 4 or even 5).
--- The tipping point will be somewhere in the area of where /m/ and /log n/
--- become comparable, but we probably don't want to work too hard on this.
-minusList [] _ = []
-minusList xs@[x] ys
- | x `elem` ys = []
- | otherwise = xs
--- Using an empty set or a singleton would also be silly, so let's not.
-minusList xs [] = xs
-minusList xs [y] = filter (/= y) xs
--- When each list has at least two elements, we build a set from the
--- second argument, allowing us to filter the first argument fairly
--- efficiently.
-minusList xs ys = filter (`S.notMember` yss) xs
- where
- yss = S.fromList ys
-
-{-
-************************************************************************
-* *
-\subsection[Utils-assoc]{Association lists}
-* *
-************************************************************************
-
-Inefficient finite maps based on association lists and equality.
--}
-
--- A finite mapping based on equality and association lists
-type Assoc a b = [(a,b)]
-
-assoc :: (Eq a) => String -> Assoc a b -> a -> b
-assocDefault :: (Eq a) => b -> Assoc a b -> a -> b
-assocUsing :: (a -> a -> Bool) -> String -> Assoc a b -> a -> b
-assocMaybe :: (Eq a) => Assoc a b -> a -> Maybe b
-assocDefaultUsing :: (a -> a -> Bool) -> b -> Assoc a b -> a -> b
-
-assocDefaultUsing _ deflt [] _ = deflt
-assocDefaultUsing eq deflt ((k,v) : rest) key
- | k `eq` key = v
- | otherwise = assocDefaultUsing eq deflt rest key
-
-assoc crash_msg list key = assocDefaultUsing (==) (panic ("Failed in assoc: " ++ crash_msg)) list key
-assocDefault deflt list key = assocDefaultUsing (==) deflt list key
-assocUsing eq crash_msg list key = assocDefaultUsing eq (panic ("Failed in assoc: " ++ crash_msg)) list key
-
-assocMaybe alist key
- = lookup alist
- where
- lookup [] = Nothing
- lookup ((tv,ty):rest) = if key == tv then Just ty else lookup rest
-
-{-
-************************************************************************
-* *
-\subsection[Utils-dups]{Duplicate-handling}
-* *
-************************************************************************
--}
-
-hasNoDups :: (Eq a) => [a] -> Bool
-
-hasNoDups xs = f [] xs
- where
- f _ [] = True
- f seen_so_far (x:xs) = if x `is_elem` seen_so_far
- then False
- else f (x:seen_so_far) xs
-
- is_elem = isIn "hasNoDups"
-
-equivClasses :: (a -> a -> Ordering) -- Comparison
- -> [a]
- -> [NonEmpty a]
-
-equivClasses _ [] = []
-equivClasses _ [stuff] = [stuff :| []]
-equivClasses cmp items = NE.groupBy eq (L.sortBy cmp items)
- where
- eq a b = case cmp a b of { EQ -> True; _ -> False }
-
-removeDups :: (a -> a -> Ordering) -- Comparison function
- -> [a]
- -> ([a], -- List with no duplicates
- [NonEmpty a]) -- List of duplicate groups. One representative
- -- from each group appears in the first result
-
-removeDups _ [] = ([], [])
-removeDups _ [x] = ([x],[])
-removeDups cmp xs
- = case L.mapAccumR collect_dups [] (equivClasses cmp xs) of { (dups, xs') ->
- (xs', dups) }
- where
- collect_dups :: [NonEmpty a] -> NonEmpty a -> ([NonEmpty a], a)
- collect_dups dups_so_far (x :| []) = (dups_so_far, x)
- collect_dups dups_so_far dups@(x :| _) = (dups:dups_so_far, x)
-
-findDupsEq :: (a->a->Bool) -> [a] -> [NonEmpty a]
-findDupsEq _ [] = []
-findDupsEq eq (x:xs) | L.null eq_xs = findDupsEq eq xs
- | otherwise = (x :| eq_xs) : findDupsEq eq neq_xs
- where (eq_xs, neq_xs) = L.partition (eq x) xs
diff --git a/compiler/utils/Maybes.hs b/compiler/utils/Maybes.hs
deleted file mode 100644
index 37acb25a1a..0000000000
--- a/compiler/utils/Maybes.hs
+++ /dev/null
@@ -1,114 +0,0 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE DeriveFunctor #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE FlexibleContexts #-}
-
-{-
-(c) The University of Glasgow 2006
-(c) The GRASP/AQUA Project, Glasgow University, 1992-1998
--}
-
-module Maybes (
- module Data.Maybe,
-
- MaybeErr(..), -- Instance of Monad
- failME, isSuccess,
-
- orElse,
- firstJust, firstJusts,
- whenIsJust,
- expectJust,
- rightToMaybe,
-
- -- * MaybeT
- MaybeT(..), liftMaybeT, tryMaybeT
- ) where
-
-import GhcPrelude
-
-import Control.Monad
-import Control.Monad.Trans.Maybe
-import Control.Exception (catch, SomeException(..))
-import Data.Maybe
-import Util (HasCallStack)
-
-infixr 4 `orElse`
-
-{-
-************************************************************************
-* *
-\subsection[Maybe type]{The @Maybe@ type}
-* *
-************************************************************************
--}
-
-firstJust :: Maybe a -> Maybe a -> Maybe a
-firstJust a b = firstJusts [a, b]
-
--- | Takes a list of @Maybes@ and returns the first @Just@ if there is one, or
--- @Nothing@ otherwise.
-firstJusts :: [Maybe a] -> Maybe a
-firstJusts = msum
-
-expectJust :: HasCallStack => String -> Maybe a -> a
-{-# INLINE expectJust #-}
-expectJust _ (Just x) = x
-expectJust err Nothing = error ("expectJust " ++ err)
-
-whenIsJust :: Monad m => Maybe a -> (a -> m ()) -> m ()
-whenIsJust (Just x) f = f x
-whenIsJust Nothing _ = return ()
-
--- | Flipped version of @fromMaybe@, useful for chaining.
-orElse :: Maybe a -> a -> a
-orElse = flip fromMaybe
-
-rightToMaybe :: Either a b -> Maybe b
-rightToMaybe (Left _) = Nothing
-rightToMaybe (Right x) = Just x
-
-{-
-************************************************************************
-* *
-\subsection[MaybeT type]{The @MaybeT@ monad transformer}
-* *
-************************************************************************
--}
-
--- We had our own MaybeT in the past. Now we reuse transformer's MaybeT
-
-liftMaybeT :: Monad m => m a -> MaybeT m a
-liftMaybeT act = MaybeT $ Just `liftM` act
-
--- | Try performing an 'IO' action, failing on error.
-tryMaybeT :: IO a -> MaybeT IO a
-tryMaybeT action = MaybeT $ catch (Just `fmap` action) handler
- where
- handler (SomeException _) = return Nothing
-
-{-
-************************************************************************
-* *
-\subsection[MaybeErr type]{The @MaybeErr@ type}
-* *
-************************************************************************
--}
-
-data MaybeErr err val = Succeeded val | Failed err
- deriving (Functor)
-
-instance Applicative (MaybeErr err) where
- pure = Succeeded
- (<*>) = ap
-
-instance Monad (MaybeErr err) where
- Succeeded v >>= k = k v
- Failed e >>= _ = Failed e
-
-isSuccess :: MaybeErr err val -> Bool
-isSuccess (Succeeded {}) = True
-isSuccess (Failed {}) = False
-
-failME :: err -> MaybeErr err val
-failME e = Failed e
diff --git a/compiler/utils/MonadUtils.hs b/compiler/utils/MonadUtils.hs
deleted file mode 100644
index 50e53b98c8..0000000000
--- a/compiler/utils/MonadUtils.hs
+++ /dev/null
@@ -1,215 +0,0 @@
--- | Utilities related to Monad and Applicative classes
--- Mostly for backwards compatibility.
-
-module MonadUtils
- ( Applicative(..)
- , (<$>)
-
- , MonadFix(..)
- , MonadIO(..)
-
- , zipWith3M, zipWith3M_, zipWith4M, zipWithAndUnzipM
- , mapAndUnzipM, mapAndUnzip3M, mapAndUnzip4M, mapAndUnzip5M
- , mapAccumLM
- , mapSndM
- , concatMapM
- , mapMaybeM
- , fmapMaybeM, fmapEitherM
- , anyM, allM, orM
- , foldlM, foldlM_, foldrM
- , maybeMapM
- , whenM, unlessM
- , filterOutM
- ) where
-
--------------------------------------------------------------------------------
--- Imports
--------------------------------------------------------------------------------
-
-import GhcPrelude
-
-import Control.Applicative
-import Control.Monad
-import Control.Monad.Fix
-import Control.Monad.IO.Class
-import Data.Foldable (sequenceA_, foldlM, foldrM)
-import Data.List (unzip4, unzip5, zipWith4)
-
--------------------------------------------------------------------------------
--- Common functions
--- These are used throughout the compiler
--------------------------------------------------------------------------------
-
-{-
-
-Note [Inline @zipWithNM@ functions]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The inline principle for 'zipWith3M', 'zipWith4M' and 'zipWith3M_' is the same
-as for 'zipWithM' and 'zipWithM_' in "Control.Monad", see
-Note [Fusion for zipN/zipWithN] in GHC/List.hs for more details.
-
-The 'zipWithM'/'zipWithM_' functions are inlined so that the `zipWith` and
-`sequenceA` functions with which they are defined have an opportunity to fuse.
-
-Furthermore, 'zipWith3M'/'zipWith4M' and 'zipWith3M_' have been explicitly
-rewritten in a non-recursive way similarly to 'zipWithM'/'zipWithM_', and for
-more than just uniformity: after [D5241](https://phabricator.haskell.org/D5241)
-for issue #14037, all @zipN@/@zipWithN@ functions fuse, meaning
-'zipWith3M'/'zipWIth4M' and 'zipWith3M_'@ now behave like 'zipWithM' and
-'zipWithM_', respectively, with regards to fusion.
-
-As such, since there are not any differences between 2-ary 'zipWithM'/
-'zipWithM_' and their n-ary counterparts below aside from the number of
-arguments, the `INLINE` pragma should be replicated in the @zipWithNM@
-functions below as well.
-
--}
-
-zipWith3M :: Monad m => (a -> b -> c -> m d) -> [a] -> [b] -> [c] -> m [d]
-{-# INLINE zipWith3M #-}
--- Inline so that fusion with 'zipWith3' and 'sequenceA' has a chance to fire.
--- See Note [Inline @zipWithNM@ functions] above.
-zipWith3M f xs ys zs = sequenceA (zipWith3 f xs ys zs)
-
-zipWith3M_ :: Monad m => (a -> b -> c -> m d) -> [a] -> [b] -> [c] -> m ()
-{-# INLINE zipWith3M_ #-}
--- Inline so that fusion with 'zipWith4' and 'sequenceA' has a chance to fire.
--- See Note [Inline @zipWithNM@ functions] above.
-zipWith3M_ f xs ys zs = sequenceA_ (zipWith3 f xs ys zs)
-
-zipWith4M :: Monad m => (a -> b -> c -> d -> m e)
- -> [a] -> [b] -> [c] -> [d] -> m [e]
-{-# INLINE zipWith4M #-}
--- Inline so that fusion with 'zipWith5' and 'sequenceA' has a chance to fire.
--- See Note [Inline @zipWithNM@ functions] above.
-zipWith4M f xs ys ws zs = sequenceA (zipWith4 f xs ys ws zs)
-
-zipWithAndUnzipM :: Monad m
- => (a -> b -> m (c, d)) -> [a] -> [b] -> m ([c], [d])
-{-# INLINABLE zipWithAndUnzipM #-}
--- See Note [flatten_args performance] in GHC.Tc.Solver.Flatten for why this
--- pragma is essential.
-zipWithAndUnzipM f (x:xs) (y:ys)
- = do { (c, d) <- f x y
- ; (cs, ds) <- zipWithAndUnzipM f xs ys
- ; return (c:cs, d:ds) }
-zipWithAndUnzipM _ _ _ = return ([], [])
-
-{-
-
-Note [Inline @mapAndUnzipNM@ functions]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The inline principle is the same as 'mapAndUnzipM' in "Control.Monad".
-The 'mapAndUnzipM' function is inlined so that the `unzip` and `traverse`
-functions with which it is defined have an opportunity to fuse, see
-Note [Inline @unzipN@ functions] in Data/OldList.hs for more details.
-
-Furthermore, the @mapAndUnzipNM@ functions have been explicitly rewritten in a
-non-recursive way similarly to 'mapAndUnzipM', and for more than just
-uniformity: after [D5249](https://phabricator.haskell.org/D5249) for Trac
-ticket #14037, all @unzipN@ functions fuse, meaning 'mapAndUnzip3M',
-'mapAndUnzip4M' and 'mapAndUnzip5M' now behave like 'mapAndUnzipM' with regards
-to fusion.
-
-As such, since there are not any differences between 2-ary 'mapAndUnzipM' and
-its n-ary counterparts below aside from the number of arguments, the `INLINE`
-pragma should be replicated in the @mapAndUnzipNM@ functions below as well.
-
--}
-
--- | mapAndUnzipM for triples
-mapAndUnzip3M :: Monad m => (a -> m (b,c,d)) -> [a] -> m ([b],[c],[d])
-{-# INLINE mapAndUnzip3M #-}
--- Inline so that fusion with 'unzip3' and 'traverse' has a chance to fire.
--- See Note [Inline @mapAndUnzipNM@ functions] above.
-mapAndUnzip3M f xs = unzip3 <$> traverse f xs
-
-mapAndUnzip4M :: Monad m => (a -> m (b,c,d,e)) -> [a] -> m ([b],[c],[d],[e])
-{-# INLINE mapAndUnzip4M #-}
--- Inline so that fusion with 'unzip4' and 'traverse' has a chance to fire.
--- See Note [Inline @mapAndUnzipNM@ functions] above.
-mapAndUnzip4M f xs = unzip4 <$> traverse f xs
-
-mapAndUnzip5M :: Monad m => (a -> m (b,c,d,e,f)) -> [a] -> m ([b],[c],[d],[e],[f])
-{-# INLINE mapAndUnzip5M #-}
--- Inline so that fusion with 'unzip5' and 'traverse' has a chance to fire.
--- See Note [Inline @mapAndUnzipNM@ functions] above.
-mapAndUnzip5M f xs = unzip5 <$> traverse f xs
-
--- | Monadic version of mapAccumL
-mapAccumLM :: Monad m
- => (acc -> x -> m (acc, y)) -- ^ combining function
- -> acc -- ^ initial state
- -> [x] -- ^ inputs
- -> m (acc, [y]) -- ^ final state, outputs
-mapAccumLM _ s [] = return (s, [])
-mapAccumLM f s (x:xs) = do
- (s1, x') <- f s x
- (s2, xs') <- mapAccumLM f s1 xs
- return (s2, x' : xs')
-
--- | Monadic version of mapSnd
-mapSndM :: Monad m => (b -> m c) -> [(a,b)] -> m [(a,c)]
-mapSndM _ [] = return []
-mapSndM f ((a,b):xs) = do { c <- f b; rs <- mapSndM f xs; return ((a,c):rs) }
-
--- | Monadic version of concatMap
-concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b]
-concatMapM f xs = liftM concat (mapM f xs)
-
--- | Applicative version of mapMaybe
-mapMaybeM :: Applicative m => (a -> m (Maybe b)) -> [a] -> m [b]
-mapMaybeM f = foldr g (pure [])
- where g a = liftA2 (maybe id (:)) (f a)
-
--- | Monadic version of fmap
-fmapMaybeM :: (Monad m) => (a -> m b) -> Maybe a -> m (Maybe b)
-fmapMaybeM _ Nothing = return Nothing
-fmapMaybeM f (Just x) = f x >>= (return . Just)
-
--- | Monadic version of fmap
-fmapEitherM :: Monad m => (a -> m b) -> (c -> m d) -> Either a c -> m (Either b d)
-fmapEitherM fl _ (Left a) = fl a >>= (return . Left)
-fmapEitherM _ fr (Right b) = fr b >>= (return . Right)
-
--- | Monadic version of 'any', aborts the computation at the first @True@ value
-anyM :: Monad m => (a -> m Bool) -> [a] -> m Bool
-anyM _ [] = return False
-anyM f (x:xs) = do b <- f x
- if b then return True
- else anyM f xs
-
--- | Monad version of 'all', aborts the computation at the first @False@ value
-allM :: Monad m => (a -> m Bool) -> [a] -> m Bool
-allM _ [] = return True
-allM f (b:bs) = (f b) >>= (\bv -> if bv then allM f bs else return False)
-
--- | Monadic version of or
-orM :: Monad m => m Bool -> m Bool -> m Bool
-orM m1 m2 = m1 >>= \x -> if x then return True else m2
-
--- | Monadic version of foldl that discards its result
-foldlM_ :: (Monad m, Foldable t) => (a -> b -> m a) -> a -> t b -> m ()
-foldlM_ = foldM_
-
--- | Monadic version of fmap specialised for Maybe
-maybeMapM :: Monad m => (a -> m b) -> (Maybe a -> m (Maybe b))
-maybeMapM _ Nothing = return Nothing
-maybeMapM m (Just x) = liftM Just $ m x
-
--- | Monadic version of @when@, taking the condition in the monad
-whenM :: Monad m => m Bool -> m () -> m ()
-whenM mb thing = do { b <- mb
- ; when b thing }
-
--- | Monadic version of @unless@, taking the condition in the monad
-unlessM :: Monad m => m Bool -> m () -> m ()
-unlessM condM acc = do { cond <- condM
- ; unless cond acc }
-
--- | Like 'filterM', only it reverses the sense of the test.
-filterOutM :: (Applicative m) => (a -> m Bool) -> [a] -> m [a]
-filterOutM p =
- foldr (\ x -> liftA2 (\ flg -> if flg then id else (x:)) (p x)) (pure [])
diff --git a/compiler/utils/OrdList.hs b/compiler/utils/OrdList.hs
deleted file mode 100644
index 8da5038b2c..0000000000
--- a/compiler/utils/OrdList.hs
+++ /dev/null
@@ -1,194 +0,0 @@
-{-
-(c) The University of Glasgow 2006
-(c) The AQUA Project, Glasgow University, 1993-1998
-
-
-This is useful, general stuff for the Native Code Generator.
-
-Provide trees (of instructions), so that lists of instructions
-can be appended in linear time.
--}
-{-# LANGUAGE DeriveFunctor #-}
-
-{-# LANGUAGE BangPatterns #-}
-
-module OrdList (
- OrdList,
- nilOL, isNilOL, unitOL, appOL, consOL, snocOL, concatOL, lastOL,
- headOL,
- mapOL, fromOL, toOL, foldrOL, foldlOL, reverseOL, fromOLReverse,
- strictlyEqOL, strictlyOrdOL
-) where
-
-import GhcPrelude
-import Data.Foldable
-
-import Outputable
-
-import qualified Data.Semigroup as Semigroup
-
-infixl 5 `appOL`
-infixl 5 `snocOL`
-infixr 5 `consOL`
-
-data OrdList a
- = None
- | One a
- | Many [a] -- Invariant: non-empty
- | Cons a (OrdList a)
- | Snoc (OrdList a) a
- | Two (OrdList a) -- Invariant: non-empty
- (OrdList a) -- Invariant: non-empty
- deriving (Functor)
-
-instance Outputable a => Outputable (OrdList a) where
- ppr ol = ppr (fromOL ol) -- Convert to list and print that
-
-instance Semigroup (OrdList a) where
- (<>) = appOL
-
-instance Monoid (OrdList a) where
- mempty = nilOL
- mappend = (Semigroup.<>)
- mconcat = concatOL
-
-instance Foldable OrdList where
- foldr = foldrOL
- foldl' = foldlOL
- toList = fromOL
- null = isNilOL
- length = lengthOL
-
-instance Traversable OrdList where
- traverse f xs = toOL <$> traverse f (fromOL xs)
-
-nilOL :: OrdList a
-isNilOL :: OrdList a -> Bool
-
-unitOL :: a -> OrdList a
-snocOL :: OrdList a -> a -> OrdList a
-consOL :: a -> OrdList a -> OrdList a
-appOL :: OrdList a -> OrdList a -> OrdList a
-concatOL :: [OrdList a] -> OrdList a
-headOL :: OrdList a -> a
-lastOL :: OrdList a -> a
-lengthOL :: OrdList a -> Int
-
-nilOL = None
-unitOL as = One as
-snocOL as b = Snoc as b
-consOL a bs = Cons a bs
-concatOL aas = foldr appOL None aas
-
-headOL None = panic "headOL"
-headOL (One a) = a
-headOL (Many as) = head as
-headOL (Cons a _) = a
-headOL (Snoc as _) = headOL as
-headOL (Two as _) = headOL as
-
-lastOL None = panic "lastOL"
-lastOL (One a) = a
-lastOL (Many as) = last as
-lastOL (Cons _ as) = lastOL as
-lastOL (Snoc _ a) = a
-lastOL (Two _ as) = lastOL as
-
-lengthOL None = 0
-lengthOL (One _) = 1
-lengthOL (Many as) = length as
-lengthOL (Cons _ as) = 1 + length as
-lengthOL (Snoc as _) = 1 + length as
-lengthOL (Two as bs) = length as + length bs
-
-isNilOL None = True
-isNilOL _ = False
-
-None `appOL` b = b
-a `appOL` None = a
-One a `appOL` b = Cons a b
-a `appOL` One b = Snoc a b
-a `appOL` b = Two a b
-
-fromOL :: OrdList a -> [a]
-fromOL a = go a []
- where go None acc = acc
- go (One a) acc = a : acc
- go (Cons a b) acc = a : go b acc
- go (Snoc a b) acc = go a (b:acc)
- go (Two a b) acc = go a (go b acc)
- go (Many xs) acc = xs ++ acc
-
-fromOLReverse :: OrdList a -> [a]
-fromOLReverse a = go a []
- -- acc is already in reverse order
- where go :: OrdList a -> [a] -> [a]
- go None acc = acc
- go (One a) acc = a : acc
- go (Cons a b) acc = go b (a : acc)
- go (Snoc a b) acc = b : go a acc
- go (Two a b) acc = go b (go a acc)
- go (Many xs) acc = reverse xs ++ acc
-
-mapOL :: (a -> b) -> OrdList a -> OrdList b
-mapOL = fmap
-
-foldrOL :: (a->b->b) -> b -> OrdList a -> b
-foldrOL _ z None = z
-foldrOL k z (One x) = k x z
-foldrOL k z (Cons x xs) = k x (foldrOL k z xs)
-foldrOL k z (Snoc xs x) = foldrOL k (k x z) xs
-foldrOL k z (Two b1 b2) = foldrOL k (foldrOL k z b2) b1
-foldrOL k z (Many xs) = foldr k z xs
-
--- | Strict left fold.
-foldlOL :: (b->a->b) -> b -> OrdList a -> b
-foldlOL _ z None = z
-foldlOL k z (One x) = k z x
-foldlOL k z (Cons x xs) = let !z' = (k z x) in foldlOL k z' xs
-foldlOL k z (Snoc xs x) = let !z' = (foldlOL k z xs) in k z' x
-foldlOL k z (Two b1 b2) = let !z' = (foldlOL k z b1) in foldlOL k z' b2
-foldlOL k z (Many xs) = foldl' k z xs
-
-toOL :: [a] -> OrdList a
-toOL [] = None
-toOL [x] = One x
-toOL xs = Many xs
-
-reverseOL :: OrdList a -> OrdList a
-reverseOL None = None
-reverseOL (One x) = One x
-reverseOL (Cons a b) = Snoc (reverseOL b) a
-reverseOL (Snoc a b) = Cons b (reverseOL a)
-reverseOL (Two a b) = Two (reverseOL b) (reverseOL a)
-reverseOL (Many xs) = Many (reverse xs)
-
--- | Compare not only the values but also the structure of two lists
-strictlyEqOL :: Eq a => OrdList a -> OrdList a -> Bool
-strictlyEqOL None None = True
-strictlyEqOL (One x) (One y) = x == y
-strictlyEqOL (Cons a as) (Cons b bs) = a == b && as `strictlyEqOL` bs
-strictlyEqOL (Snoc as a) (Snoc bs b) = a == b && as `strictlyEqOL` bs
-strictlyEqOL (Two a1 a2) (Two b1 b2) = a1 `strictlyEqOL` b1 && a2 `strictlyEqOL` b2
-strictlyEqOL (Many as) (Many bs) = as == bs
-strictlyEqOL _ _ = False
-
--- | Compare not only the values but also the structure of two lists
-strictlyOrdOL :: Ord a => OrdList a -> OrdList a -> Ordering
-strictlyOrdOL None None = EQ
-strictlyOrdOL None _ = LT
-strictlyOrdOL (One x) (One y) = compare x y
-strictlyOrdOL (One _) _ = LT
-strictlyOrdOL (Cons a as) (Cons b bs) =
- compare a b `mappend` strictlyOrdOL as bs
-strictlyOrdOL (Cons _ _) _ = LT
-strictlyOrdOL (Snoc as a) (Snoc bs b) =
- compare a b `mappend` strictlyOrdOL as bs
-strictlyOrdOL (Snoc _ _) _ = LT
-strictlyOrdOL (Two a1 a2) (Two b1 b2) =
- (strictlyOrdOL a1 b1) `mappend` (strictlyOrdOL a2 b2)
-strictlyOrdOL (Two _ _) _ = LT
-strictlyOrdOL (Many as) (Many bs) = compare as bs
-strictlyOrdOL (Many _ ) _ = GT
-
-
diff --git a/compiler/utils/Outputable.hs b/compiler/utils/Outputable.hs
deleted file mode 100644
index d36faa4724..0000000000
--- a/compiler/utils/Outputable.hs
+++ /dev/null
@@ -1,1304 +0,0 @@
-{-# LANGUAGE LambdaCase #-}
-
-{-
-(c) The University of Glasgow 2006-2012
-(c) The GRASP Project, Glasgow University, 1992-1998
--}
-
--- | This module defines classes and functions for pretty-printing. It also
--- exports a number of helpful debugging and other utilities such as 'trace' and 'panic'.
---
--- The interface to this module is very similar to the standard Hughes-PJ pretty printing
--- module, except that it exports a number of additional functions that are rarely used,
--- and works over the 'SDoc' type.
-module Outputable (
- -- * Type classes
- Outputable(..), OutputableBndr(..),
-
- -- * Pretty printing combinators
- SDoc, runSDoc, initSDocContext,
- docToSDoc,
- interppSP, interpp'SP,
- pprQuotedList, pprWithCommas, quotedListWithOr, quotedListWithNor,
- pprWithBars,
- empty, isEmpty, nest,
- char,
- text, ftext, ptext, ztext,
- int, intWithCommas, integer, word, float, double, rational, doublePrec,
- parens, cparen, brackets, braces, quotes, quote,
- doubleQuotes, angleBrackets,
- semi, comma, colon, dcolon, space, equals, dot, vbar,
- arrow, larrow, darrow, arrowt, larrowt, arrowtt, larrowtt,
- lparen, rparen, lbrack, rbrack, lbrace, rbrace, underscore,
- blankLine, forAllLit, bullet,
- (<>), (<+>), hcat, hsep,
- ($$), ($+$), vcat,
- sep, cat,
- fsep, fcat,
- hang, hangNotEmpty, punctuate, ppWhen, ppUnless,
- ppWhenOption, ppUnlessOption,
- speakNth, speakN, speakNOf, plural, isOrAre, doOrDoes, itsOrTheir,
- unicodeSyntax,
-
- coloured, keyword,
-
- -- * Converting 'SDoc' into strings and outputting it
- printSDoc, printSDocLn, printForUser, printForUserPartWay,
- printForC, bufLeftRenderSDoc,
- pprCode, mkCodeStyle,
- showSDoc, showSDocUnsafe, showSDocOneLine,
- showSDocForUser, showSDocDebug, showSDocDump, showSDocDumpOneLine,
- showSDocUnqual, showPpr,
- renderWithStyle,
-
- pprInfixVar, pprPrefixVar,
- pprHsChar, pprHsString, pprHsBytes,
-
- primFloatSuffix, primCharSuffix, primWordSuffix, primDoubleSuffix,
- primInt64Suffix, primWord64Suffix, primIntSuffix,
-
- pprPrimChar, pprPrimInt, pprPrimWord, pprPrimInt64, pprPrimWord64,
-
- pprFastFilePath, pprFilePathString,
-
- -- * Controlling the style in which output is printed
- BindingSite(..),
-
- PprStyle, CodeStyle(..), PrintUnqualified(..),
- QueryQualifyName, QueryQualifyModule, QueryQualifyPackage,
- reallyAlwaysQualify, reallyAlwaysQualifyNames,
- alwaysQualify, alwaysQualifyNames, alwaysQualifyModules,
- neverQualify, neverQualifyNames, neverQualifyModules,
- alwaysQualifyPackages, neverQualifyPackages,
- QualifyName(..), queryQual,
- sdocWithDynFlags, sdocOption,
- updSDocContext,
- SDocContext (..), sdocWithContext,
- getPprStyle, withPprStyle, setStyleColoured,
- pprDeeper, pprDeeperList, pprSetDepth,
- codeStyle, userStyle, debugStyle, dumpStyle, asmStyle,
- qualName, qualModule, qualPackage,
- mkErrStyle, defaultErrStyle, defaultDumpStyle, mkDumpStyle, defaultUserStyle,
- mkUserStyle, cmdlineParserStyle, Depth(..),
- withUserStyle, withErrStyle,
-
- ifPprDebug, whenPprDebug, getPprDebug,
-
- -- * Error handling and debugging utilities
- pprPanic, pprSorry, assertPprPanic, pprPgmError,
- pprTrace, pprTraceDebug, pprTraceWith, pprTraceIt, warnPprTrace,
- pprSTrace, pprTraceException, pprTraceM, pprTraceWithFlags,
- trace, pgmError, panic, sorry, assertPanic,
- pprDebugAndThen, callStackDoc,
- ) where
-
-import GhcPrelude
-
-import {-# SOURCE #-} GHC.Driver.Session
- ( DynFlags, hasPprDebug, hasNoDebugOutput
- , pprUserLength
- , unsafeGlobalDynFlags, initSDocContext
- )
-import {-# SOURCE #-} GHC.Types.Module( UnitId, Module, ModuleName, moduleName )
-import {-# SOURCE #-} GHC.Types.Name.Occurrence( OccName )
-
-import BufWrite (BufHandle)
-import FastString
-import qualified Pretty
-import Util
-import qualified PprColour as Col
-import Pretty ( Doc, Mode(..) )
-import Panic
-import GHC.Serialized
-import GHC.LanguageExtensions (Extension)
-
-import Data.ByteString (ByteString)
-import qualified Data.ByteString as BS
-import Data.Char
-import qualified Data.Map as M
-import Data.Int
-import qualified Data.IntMap as IM
-import Data.Set (Set)
-import qualified Data.Set as Set
-import Data.String
-import Data.Word
-import System.IO ( Handle )
-import System.FilePath
-import Text.Printf
-import Numeric (showFFloat)
-import Data.Graph (SCC(..))
-import Data.List (intersperse)
-import Data.List.NonEmpty (NonEmpty (..))
-import qualified Data.List.NonEmpty as NEL
-
-import GHC.Fingerprint
-import GHC.Show ( showMultiLineString )
-import GHC.Stack ( callStack, prettyCallStack )
-import Control.Monad.IO.Class
-import Exception
-
-{-
-************************************************************************
-* *
-\subsection{The @PprStyle@ data type}
-* *
-************************************************************************
--}
-
-data PprStyle
- = PprUser PrintUnqualified Depth Coloured
- -- Pretty-print in a way that will make sense to the
- -- ordinary user; must be very close to Haskell
- -- syntax, etc.
- -- Assumes printing tidied code: non-system names are
- -- printed without uniques.
-
- | PprDump PrintUnqualified
- -- For -ddump-foo; less verbose than PprDebug, but more than PprUser
- -- Does not assume tidied code: non-external names
- -- are printed with uniques.
-
- | PprDebug -- Full debugging output
-
- | PprCode CodeStyle
- -- Print code; either C or assembler
-
-data CodeStyle = CStyle -- The format of labels differs for C and assembler
- | AsmStyle
-
-data Depth = AllTheWay
- | PartWay Int -- 0 => stop
-
-data Coloured
- = Uncoloured
- | Coloured
-
--- -----------------------------------------------------------------------------
--- Printing original names
-
--- | When printing code that contains original names, we need to map the
--- original names back to something the user understands. This is the
--- purpose of the triple of functions that gets passed around
--- when rendering 'SDoc'.
-data PrintUnqualified = QueryQualify {
- queryQualifyName :: QueryQualifyName,
- queryQualifyModule :: QueryQualifyModule,
- queryQualifyPackage :: QueryQualifyPackage
-}
-
--- | Given a `Name`'s `Module` and `OccName`, decide whether and how to qualify
--- it.
-type QueryQualifyName = Module -> OccName -> QualifyName
-
--- | For a given module, we need to know whether to print it with
--- a package name to disambiguate it.
-type QueryQualifyModule = Module -> Bool
-
--- | For a given package, we need to know whether to print it with
--- the component id to disambiguate it.
-type QueryQualifyPackage = UnitId -> Bool
-
--- See Note [Printing original names] in GHC.Driver.Types
-data QualifyName -- Given P:M.T
- = NameUnqual -- It's in scope unqualified as "T"
- -- OR nothing called "T" is in scope
-
- | NameQual ModuleName -- It's in scope qualified as "X.T"
-
- | NameNotInScope1 -- It's not in scope at all, but M.T is not bound
- -- in the current scope, so we can refer to it as "M.T"
-
- | NameNotInScope2 -- It's not in scope at all, and M.T is already bound in
- -- the current scope, so we must refer to it as "P:M.T"
-
-instance Outputable QualifyName where
- ppr NameUnqual = text "NameUnqual"
- ppr (NameQual _mod) = text "NameQual" -- can't print the mod without module loops :(
- ppr NameNotInScope1 = text "NameNotInScope1"
- ppr NameNotInScope2 = text "NameNotInScope2"
-
-reallyAlwaysQualifyNames :: QueryQualifyName
-reallyAlwaysQualifyNames _ _ = NameNotInScope2
-
--- | NB: This won't ever show package IDs
-alwaysQualifyNames :: QueryQualifyName
-alwaysQualifyNames m _ = NameQual (moduleName m)
-
-neverQualifyNames :: QueryQualifyName
-neverQualifyNames _ _ = NameUnqual
-
-alwaysQualifyModules :: QueryQualifyModule
-alwaysQualifyModules _ = True
-
-neverQualifyModules :: QueryQualifyModule
-neverQualifyModules _ = False
-
-alwaysQualifyPackages :: QueryQualifyPackage
-alwaysQualifyPackages _ = True
-
-neverQualifyPackages :: QueryQualifyPackage
-neverQualifyPackages _ = False
-
-reallyAlwaysQualify, alwaysQualify, neverQualify :: PrintUnqualified
-reallyAlwaysQualify
- = QueryQualify reallyAlwaysQualifyNames
- alwaysQualifyModules
- alwaysQualifyPackages
-alwaysQualify = QueryQualify alwaysQualifyNames
- alwaysQualifyModules
- alwaysQualifyPackages
-neverQualify = QueryQualify neverQualifyNames
- neverQualifyModules
- neverQualifyPackages
-
-defaultUserStyle :: DynFlags -> PprStyle
-defaultUserStyle dflags = mkUserStyle dflags neverQualify AllTheWay
-
-defaultDumpStyle :: DynFlags -> PprStyle
- -- Print without qualifiers to reduce verbosity, unless -dppr-debug
-defaultDumpStyle dflags
- | hasPprDebug dflags = PprDebug
- | otherwise = PprDump neverQualify
-
-mkDumpStyle :: DynFlags -> PrintUnqualified -> PprStyle
-mkDumpStyle dflags print_unqual
- | hasPprDebug dflags = PprDebug
- | otherwise = PprDump print_unqual
-
-defaultErrStyle :: DynFlags -> PprStyle
--- Default style for error messages, when we don't know PrintUnqualified
--- It's a bit of a hack because it doesn't take into account what's in scope
--- Only used for desugarer warnings, and typechecker errors in interface sigs
--- NB that -dppr-debug will still get into PprDebug style
-defaultErrStyle dflags = mkErrStyle dflags neverQualify
-
--- | Style for printing error messages
-mkErrStyle :: DynFlags -> PrintUnqualified -> PprStyle
-mkErrStyle dflags qual =
- mkUserStyle dflags qual (PartWay (pprUserLength dflags))
-
-cmdlineParserStyle :: DynFlags -> PprStyle
-cmdlineParserStyle dflags = mkUserStyle dflags alwaysQualify AllTheWay
-
-mkUserStyle :: DynFlags -> PrintUnqualified -> Depth -> PprStyle
-mkUserStyle dflags unqual depth
- | hasPprDebug dflags = PprDebug
- | otherwise = PprUser unqual depth Uncoloured
-
-withUserStyle :: PrintUnqualified -> Depth -> SDoc -> SDoc
-withUserStyle unqual depth doc = sdocOption sdocPprDebug $ \case
- True -> withPprStyle PprDebug doc
- False -> withPprStyle (PprUser unqual depth Uncoloured) doc
-
-withErrStyle :: PrintUnqualified -> SDoc -> SDoc
-withErrStyle unqual doc =
- sdocWithDynFlags $ \dflags ->
- withPprStyle (mkErrStyle dflags unqual) doc
-
-setStyleColoured :: Bool -> PprStyle -> PprStyle
-setStyleColoured col style =
- case style of
- PprUser q d _ -> PprUser q d c
- _ -> style
- where
- c | col = Coloured
- | otherwise = Uncoloured
-
-instance Outputable PprStyle where
- ppr (PprUser {}) = text "user-style"
- ppr (PprCode {}) = text "code-style"
- ppr (PprDump {}) = text "dump-style"
- ppr (PprDebug {}) = text "debug-style"
-
-{-
-Orthogonal to the above printing styles are (possibly) some
-command-line flags that affect printing (often carried with the
-style). The most likely ones are variations on how much type info is
-shown.
-
-The following test decides whether or not we are actually generating
-code (either C or assembly), or generating interface files.
-
-************************************************************************
-* *
-\subsection{The @SDoc@ data type}
-* *
-************************************************************************
--}
-
--- | Represents a pretty-printable document.
---
--- To display an 'SDoc', use 'printSDoc', 'printSDocLn', 'bufLeftRenderSDoc',
--- or 'renderWithStyle'. Avoid calling 'runSDoc' directly as it breaks the
--- abstraction layer.
-newtype SDoc = SDoc { runSDoc :: SDocContext -> Doc }
-
-data SDocContext = SDC
- { sdocStyle :: !PprStyle
- , sdocColScheme :: !Col.Scheme
- , sdocLastColour :: !Col.PprColour
- -- ^ The most recently used colour.
- -- This allows nesting colours.
- , sdocShouldUseColor :: !Bool
- , sdocLineLength :: !Int
- , sdocCanUseUnicode :: !Bool
- -- ^ True if Unicode encoding is supported
- -- and not disable by GHC_NO_UNICODE environment variable
- , sdocHexWordLiterals :: !Bool
- , sdocPprDebug :: !Bool
- , sdocPrintUnicodeSyntax :: !Bool
- , sdocPrintCaseAsLet :: !Bool
- , sdocPrintTypecheckerElaboration :: !Bool
- , sdocPrintAxiomIncomps :: !Bool
- , sdocPrintExplicitKinds :: !Bool
- , sdocPrintExplicitCoercions :: !Bool
- , sdocPrintExplicitRuntimeReps :: !Bool
- , sdocPrintExplicitForalls :: !Bool
- , sdocPrintPotentialInstances :: !Bool
- , sdocPrintEqualityRelations :: !Bool
- , sdocSuppressTicks :: !Bool
- , sdocSuppressTypeSignatures :: !Bool
- , sdocSuppressTypeApplications :: !Bool
- , sdocSuppressIdInfo :: !Bool
- , sdocSuppressCoercions :: !Bool
- , sdocSuppressUnfoldings :: !Bool
- , sdocSuppressVarKinds :: !Bool
- , sdocSuppressUniques :: !Bool
- , sdocSuppressModulePrefixes :: !Bool
- , sdocSuppressStgExts :: !Bool
- , sdocErrorSpans :: !Bool
- , sdocStarIsType :: !Bool
- , sdocImpredicativeTypes :: !Bool
- , sdocDynFlags :: DynFlags -- TODO: remove
- }
-
-instance IsString SDoc where
- fromString = text
-
--- The lazy programmer's friend.
-instance Outputable SDoc where
- ppr = id
-
-
-withPprStyle :: PprStyle -> SDoc -> SDoc
-withPprStyle sty d = SDoc $ \ctxt -> runSDoc d ctxt{sdocStyle=sty}
-
-pprDeeper :: SDoc -> SDoc
-pprDeeper d = SDoc $ \ctx -> case ctx of
- SDC{sdocStyle=PprUser _ (PartWay 0) _} -> Pretty.text "..."
- SDC{sdocStyle=PprUser q (PartWay n) c} ->
- runSDoc d ctx{sdocStyle = PprUser q (PartWay (n-1)) c}
- _ -> runSDoc d ctx
-
--- | Truncate a list that is longer than the current depth.
-pprDeeperList :: ([SDoc] -> SDoc) -> [SDoc] -> SDoc
-pprDeeperList f ds
- | null ds = f []
- | otherwise = SDoc work
- where
- work ctx@SDC{sdocStyle=PprUser q (PartWay n) c}
- | n==0 = Pretty.text "..."
- | otherwise =
- runSDoc (f (go 0 ds)) ctx{sdocStyle = PprUser q (PartWay (n-1)) c}
- where
- go _ [] = []
- go i (d:ds) | i >= n = [text "...."]
- | otherwise = d : go (i+1) ds
- work other_ctx = runSDoc (f ds) other_ctx
-
-pprSetDepth :: Depth -> SDoc -> SDoc
-pprSetDepth depth doc = SDoc $ \ctx ->
- case ctx of
- SDC{sdocStyle=PprUser q _ c} ->
- runSDoc doc ctx{sdocStyle = PprUser q depth c}
- _ ->
- runSDoc doc ctx
-
-getPprStyle :: (PprStyle -> SDoc) -> SDoc
-getPprStyle df = SDoc $ \ctx -> runSDoc (df (sdocStyle ctx)) ctx
-
-sdocWithDynFlags :: (DynFlags -> SDoc) -> SDoc
-sdocWithDynFlags f = SDoc $ \ctx -> runSDoc (f (sdocDynFlags ctx)) ctx
-
-sdocWithContext :: (SDocContext -> SDoc) -> SDoc
-sdocWithContext f = SDoc $ \ctx -> runSDoc (f ctx) ctx
-
-sdocOption :: (SDocContext -> a) -> (a -> SDoc) -> SDoc
-sdocOption f g = sdocWithContext (g . f)
-
-updSDocContext :: (SDocContext -> SDocContext) -> SDoc -> SDoc
-updSDocContext upd doc
- = SDoc $ \ctx -> runSDoc doc (upd ctx)
-
-qualName :: PprStyle -> QueryQualifyName
-qualName (PprUser q _ _) mod occ = queryQualifyName q mod occ
-qualName (PprDump q) mod occ = queryQualifyName q mod occ
-qualName _other mod _ = NameQual (moduleName mod)
-
-qualModule :: PprStyle -> QueryQualifyModule
-qualModule (PprUser q _ _) m = queryQualifyModule q m
-qualModule (PprDump q) m = queryQualifyModule q m
-qualModule _other _m = True
-
-qualPackage :: PprStyle -> QueryQualifyPackage
-qualPackage (PprUser q _ _) m = queryQualifyPackage q m
-qualPackage (PprDump q) m = queryQualifyPackage q m
-qualPackage _other _m = True
-
-queryQual :: PprStyle -> PrintUnqualified
-queryQual s = QueryQualify (qualName s)
- (qualModule s)
- (qualPackage s)
-
-codeStyle :: PprStyle -> Bool
-codeStyle (PprCode _) = True
-codeStyle _ = False
-
-asmStyle :: PprStyle -> Bool
-asmStyle (PprCode AsmStyle) = True
-asmStyle _other = False
-
-dumpStyle :: PprStyle -> Bool
-dumpStyle (PprDump {}) = True
-dumpStyle _other = False
-
-debugStyle :: PprStyle -> Bool
-debugStyle PprDebug = True
-debugStyle _other = False
-
-userStyle :: PprStyle -> Bool
-userStyle (PprUser {}) = True
-userStyle _other = False
-
-getPprDebug :: (Bool -> SDoc) -> SDoc
-getPprDebug d = getPprStyle $ \ sty -> d (debugStyle sty)
-
-ifPprDebug :: SDoc -> SDoc -> SDoc
--- ^ Says what to do with and without -dppr-debug
-ifPprDebug yes no = getPprDebug $ \ dbg -> if dbg then yes else no
-
-whenPprDebug :: SDoc -> SDoc -- Empty for non-debug style
--- ^ Says what to do with -dppr-debug; without, return empty
-whenPprDebug d = ifPprDebug d empty
-
--- | The analog of 'Pretty.printDoc_' for 'SDoc', which tries to make sure the
--- terminal doesn't get screwed up by the ANSI color codes if an exception
--- is thrown during pretty-printing.
-printSDoc :: SDocContext -> Mode -> Handle -> SDoc -> IO ()
-printSDoc ctx mode handle doc =
- Pretty.printDoc_ mode cols handle (runSDoc doc ctx)
- `finally`
- Pretty.printDoc_ mode cols handle
- (runSDoc (coloured Col.colReset empty) ctx)
- where
- cols = sdocLineLength ctx
-
--- | Like 'printSDoc' but appends an extra newline.
-printSDocLn :: SDocContext -> Mode -> Handle -> SDoc -> IO ()
-printSDocLn ctx mode handle doc =
- printSDoc ctx mode handle (doc $$ text "")
-
-printForUser :: DynFlags -> Handle -> PrintUnqualified -> SDoc -> IO ()
-printForUser dflags handle unqual doc
- = printSDocLn ctx PageMode handle doc
- where ctx = initSDocContext dflags (mkUserStyle dflags unqual AllTheWay)
-
-printForUserPartWay :: DynFlags -> Handle -> Int -> PrintUnqualified -> SDoc
- -> IO ()
-printForUserPartWay dflags handle d unqual doc
- = printSDocLn ctx PageMode handle doc
- where ctx = initSDocContext dflags (mkUserStyle dflags unqual (PartWay d))
-
--- | Like 'printSDocLn' but specialized with 'LeftMode' and
--- @'PprCode' 'CStyle'@. This is typically used to output C-- code.
-printForC :: DynFlags -> Handle -> SDoc -> IO ()
-printForC dflags handle doc =
- printSDocLn ctx LeftMode handle doc
- where ctx = initSDocContext dflags (PprCode CStyle)
-
--- | An efficient variant of 'printSDoc' specialized for 'LeftMode' that
--- outputs to a 'BufHandle'.
-bufLeftRenderSDoc :: SDocContext -> BufHandle -> SDoc -> IO ()
-bufLeftRenderSDoc ctx bufHandle doc =
- Pretty.bufLeftRender bufHandle (runSDoc doc ctx)
-
-pprCode :: CodeStyle -> SDoc -> SDoc
-pprCode cs d = withPprStyle (PprCode cs) d
-
-mkCodeStyle :: CodeStyle -> PprStyle
-mkCodeStyle = PprCode
-
--- Can't make SDoc an instance of Show because SDoc is just a function type
--- However, Doc *is* an instance of Show
--- showSDoc just blasts it out as a string
-showSDoc :: DynFlags -> SDoc -> String
-showSDoc dflags sdoc = renderWithStyle (initSDocContext dflags (defaultUserStyle dflags)) sdoc
-
--- showSDocUnsafe is unsafe, because `unsafeGlobalDynFlags` might not be
--- initialised yet.
-showSDocUnsafe :: SDoc -> String
-showSDocUnsafe sdoc = showSDoc unsafeGlobalDynFlags sdoc
-
-showPpr :: Outputable a => DynFlags -> a -> String
-showPpr dflags thing = showSDoc dflags (ppr thing)
-
-showSDocUnqual :: DynFlags -> SDoc -> String
--- Only used by Haddock
-showSDocUnqual dflags sdoc = showSDoc dflags sdoc
-
-showSDocForUser :: DynFlags -> PrintUnqualified -> SDoc -> String
--- Allows caller to specify the PrintUnqualified to use
-showSDocForUser dflags unqual doc
- = renderWithStyle (initSDocContext dflags (mkUserStyle dflags unqual AllTheWay)) doc
-
-showSDocDump :: DynFlags -> SDoc -> String
-showSDocDump dflags d = renderWithStyle (initSDocContext dflags (defaultDumpStyle dflags)) d
-
-showSDocDebug :: DynFlags -> SDoc -> String
-showSDocDebug dflags d = renderWithStyle (initSDocContext dflags PprDebug) d
-
-renderWithStyle :: SDocContext -> SDoc -> String
-renderWithStyle ctx sdoc
- = let s = Pretty.style{ Pretty.mode = PageMode,
- Pretty.lineLength = sdocLineLength ctx }
- in Pretty.renderStyle s $ runSDoc sdoc ctx
-
--- This shows an SDoc, but on one line only. It's cheaper than a full
--- showSDoc, designed for when we're getting results like "Foo.bar"
--- and "foo{uniq strictness}" so we don't want fancy layout anyway.
-showSDocOneLine :: SDocContext -> SDoc -> String
-showSDocOneLine ctx d
- = let s = Pretty.style{ Pretty.mode = OneLineMode,
- Pretty.lineLength = sdocLineLength ctx } in
- Pretty.renderStyle s $
- runSDoc d ctx
-
-showSDocDumpOneLine :: DynFlags -> SDoc -> String
-showSDocDumpOneLine dflags d
- = let s = Pretty.style{ Pretty.mode = OneLineMode,
- Pretty.lineLength = irrelevantNCols } in
- Pretty.renderStyle s $
- runSDoc d (initSDocContext dflags (defaultDumpStyle dflags))
-
-irrelevantNCols :: Int
--- Used for OneLineMode and LeftMode when number of cols isn't used
-irrelevantNCols = 1
-
-isEmpty :: SDocContext -> SDoc -> Bool
-isEmpty ctx sdoc = Pretty.isEmpty $ runSDoc sdoc (ctx {sdocStyle = PprDebug})
-
-docToSDoc :: Doc -> SDoc
-docToSDoc d = SDoc (\_ -> d)
-
-empty :: SDoc
-char :: Char -> SDoc
-text :: String -> SDoc
-ftext :: FastString -> SDoc
-ptext :: PtrString -> SDoc
-ztext :: FastZString -> SDoc
-int :: Int -> SDoc
-integer :: Integer -> SDoc
-word :: Integer -> SDoc
-float :: Float -> SDoc
-double :: Double -> SDoc
-rational :: Rational -> SDoc
-
-empty = docToSDoc $ Pretty.empty
-char c = docToSDoc $ Pretty.char c
-
-text s = docToSDoc $ Pretty.text s
-{-# INLINE text #-} -- Inline so that the RULE Pretty.text will fire
-
-ftext s = docToSDoc $ Pretty.ftext s
-ptext s = docToSDoc $ Pretty.ptext s
-ztext s = docToSDoc $ Pretty.ztext s
-int n = docToSDoc $ Pretty.int n
-integer n = docToSDoc $ Pretty.integer n
-float n = docToSDoc $ Pretty.float n
-double n = docToSDoc $ Pretty.double n
-rational n = docToSDoc $ Pretty.rational n
- -- See Note [Print Hexadecimal Literals] in Pretty.hs
-word n = sdocOption sdocHexWordLiterals $ \case
- True -> docToSDoc $ Pretty.hex n
- False -> docToSDoc $ Pretty.integer n
-
--- | @doublePrec p n@ shows a floating point number @n@ with @p@
--- digits of precision after the decimal point.
-doublePrec :: Int -> Double -> SDoc
-doublePrec p n = text (showFFloat (Just p) n "")
-
-parens, braces, brackets, quotes, quote,
- doubleQuotes, angleBrackets :: SDoc -> SDoc
-
-parens d = SDoc $ Pretty.parens . runSDoc d
-braces d = SDoc $ Pretty.braces . runSDoc d
-brackets d = SDoc $ Pretty.brackets . runSDoc d
-quote d = SDoc $ Pretty.quote . runSDoc d
-doubleQuotes d = SDoc $ Pretty.doubleQuotes . runSDoc d
-angleBrackets d = char '<' <> d <> char '>'
-
-cparen :: Bool -> SDoc -> SDoc
-cparen b d = SDoc $ Pretty.maybeParens b . runSDoc d
-
--- 'quotes' encloses something in single quotes...
--- but it omits them if the thing begins or ends in a single quote
--- so that we don't get `foo''. Instead we just have foo'.
-quotes d = sdocOption sdocCanUseUnicode $ \case
- True -> char '‘' <> d <> char '’'
- False -> SDoc $ \sty ->
- let pp_d = runSDoc d sty
- str = show pp_d
- in case (str, lastMaybe str) of
- (_, Just '\'') -> pp_d
- ('\'' : _, _) -> pp_d
- _other -> Pretty.quotes pp_d
-
-semi, comma, colon, equals, space, dcolon, underscore, dot, vbar :: SDoc
-arrow, larrow, darrow, arrowt, larrowt, arrowtt, larrowtt :: SDoc
-lparen, rparen, lbrack, rbrack, lbrace, rbrace, blankLine :: SDoc
-
-blankLine = docToSDoc $ Pretty.text ""
-dcolon = unicodeSyntax (char '∷') (docToSDoc $ Pretty.text "::")
-arrow = unicodeSyntax (char '→') (docToSDoc $ Pretty.text "->")
-larrow = unicodeSyntax (char '←') (docToSDoc $ Pretty.text "<-")
-darrow = unicodeSyntax (char '⇒') (docToSDoc $ Pretty.text "=>")
-arrowt = unicodeSyntax (char '⤚') (docToSDoc $ Pretty.text ">-")
-larrowt = unicodeSyntax (char '⤙') (docToSDoc $ Pretty.text "-<")
-arrowtt = unicodeSyntax (char '⤜') (docToSDoc $ Pretty.text ">>-")
-larrowtt = unicodeSyntax (char '⤛') (docToSDoc $ Pretty.text "-<<")
-semi = docToSDoc $ Pretty.semi
-comma = docToSDoc $ Pretty.comma
-colon = docToSDoc $ Pretty.colon
-equals = docToSDoc $ Pretty.equals
-space = docToSDoc $ Pretty.space
-underscore = char '_'
-dot = char '.'
-vbar = char '|'
-lparen = docToSDoc $ Pretty.lparen
-rparen = docToSDoc $ Pretty.rparen
-lbrack = docToSDoc $ Pretty.lbrack
-rbrack = docToSDoc $ Pretty.rbrack
-lbrace = docToSDoc $ Pretty.lbrace
-rbrace = docToSDoc $ Pretty.rbrace
-
-forAllLit :: SDoc
-forAllLit = unicodeSyntax (char '∀') (text "forall")
-
-bullet :: SDoc
-bullet = unicode (char '•') (char '*')
-
-unicodeSyntax :: SDoc -> SDoc -> SDoc
-unicodeSyntax unicode plain =
- sdocOption sdocCanUseUnicode $ \can_use_unicode ->
- sdocOption sdocPrintUnicodeSyntax $ \print_unicode_syntax ->
- if can_use_unicode && print_unicode_syntax
- then unicode
- else plain
-
-unicode :: SDoc -> SDoc -> SDoc
-unicode unicode plain = sdocOption sdocCanUseUnicode $ \case
- True -> unicode
- False -> plain
-
-nest :: Int -> SDoc -> SDoc
--- ^ Indent 'SDoc' some specified amount
-(<>) :: SDoc -> SDoc -> SDoc
--- ^ Join two 'SDoc' together horizontally without a gap
-(<+>) :: SDoc -> SDoc -> SDoc
--- ^ Join two 'SDoc' together horizontally with a gap between them
-($$) :: SDoc -> SDoc -> SDoc
--- ^ Join two 'SDoc' together vertically; if there is
--- no vertical overlap it "dovetails" the two onto one line
-($+$) :: SDoc -> SDoc -> SDoc
--- ^ Join two 'SDoc' together vertically
-
-nest n d = SDoc $ Pretty.nest n . runSDoc d
-(<>) d1 d2 = SDoc $ \sty -> (Pretty.<>) (runSDoc d1 sty) (runSDoc d2 sty)
-(<+>) d1 d2 = SDoc $ \sty -> (Pretty.<+>) (runSDoc d1 sty) (runSDoc d2 sty)
-($$) d1 d2 = SDoc $ \sty -> (Pretty.$$) (runSDoc d1 sty) (runSDoc d2 sty)
-($+$) d1 d2 = SDoc $ \sty -> (Pretty.$+$) (runSDoc d1 sty) (runSDoc d2 sty)
-
-hcat :: [SDoc] -> SDoc
--- ^ Concatenate 'SDoc' horizontally
-hsep :: [SDoc] -> SDoc
--- ^ Concatenate 'SDoc' horizontally with a space between each one
-vcat :: [SDoc] -> SDoc
--- ^ Concatenate 'SDoc' vertically with dovetailing
-sep :: [SDoc] -> SDoc
--- ^ Separate: is either like 'hsep' or like 'vcat', depending on what fits
-cat :: [SDoc] -> SDoc
--- ^ Catenate: is either like 'hcat' or like 'vcat', depending on what fits
-fsep :: [SDoc] -> SDoc
--- ^ A paragraph-fill combinator. It's much like sep, only it
--- keeps fitting things on one line until it can't fit any more.
-fcat :: [SDoc] -> SDoc
--- ^ This behaves like 'fsep', but it uses '<>' for horizontal conposition rather than '<+>'
-
-
-hcat ds = SDoc $ \sty -> Pretty.hcat [runSDoc d sty | d <- ds]
-hsep ds = SDoc $ \sty -> Pretty.hsep [runSDoc d sty | d <- ds]
-vcat ds = SDoc $ \sty -> Pretty.vcat [runSDoc d sty | d <- ds]
-sep ds = SDoc $ \sty -> Pretty.sep [runSDoc d sty | d <- ds]
-cat ds = SDoc $ \sty -> Pretty.cat [runSDoc d sty | d <- ds]
-fsep ds = SDoc $ \sty -> Pretty.fsep [runSDoc d sty | d <- ds]
-fcat ds = SDoc $ \sty -> Pretty.fcat [runSDoc d sty | d <- ds]
-
-hang :: SDoc -- ^ The header
- -> Int -- ^ Amount to indent the hung body
- -> SDoc -- ^ The hung body, indented and placed below the header
- -> SDoc
-hang d1 n d2 = SDoc $ \sty -> Pretty.hang (runSDoc d1 sty) n (runSDoc d2 sty)
-
--- | This behaves like 'hang', but does not indent the second document
--- when the header is empty.
-hangNotEmpty :: SDoc -> Int -> SDoc -> SDoc
-hangNotEmpty d1 n d2 =
- SDoc $ \sty -> Pretty.hangNotEmpty (runSDoc d1 sty) n (runSDoc d2 sty)
-
-punctuate :: SDoc -- ^ The punctuation
- -> [SDoc] -- ^ The list that will have punctuation added between every adjacent pair of elements
- -> [SDoc] -- ^ Punctuated list
-punctuate _ [] = []
-punctuate p (d:ds) = go d ds
- where
- go d [] = [d]
- go d (e:es) = (d <> p) : go e es
-
-ppWhen, ppUnless :: Bool -> SDoc -> SDoc
-ppWhen True doc = doc
-ppWhen False _ = empty
-
-ppUnless True _ = empty
-ppUnless False doc = doc
-
-ppWhenOption :: (SDocContext -> Bool) -> SDoc -> SDoc
-ppWhenOption f doc = sdocOption f $ \case
- True -> doc
- False -> empty
-
-ppUnlessOption :: (SDocContext -> Bool) -> SDoc -> SDoc
-ppUnlessOption f doc = sdocOption f $ \case
- True -> empty
- False -> doc
-
--- | Apply the given colour\/style for the argument.
---
--- Only takes effect if colours are enabled.
-coloured :: Col.PprColour -> SDoc -> SDoc
-coloured col sdoc = sdocOption sdocShouldUseColor $ \case
- True -> SDoc $ \case
- ctx@SDC{ sdocLastColour = lastCol, sdocStyle = PprUser _ _ Coloured } ->
- let ctx' = ctx{ sdocLastColour = lastCol `mappend` col } in
- Pretty.zeroWidthText (Col.renderColour col)
- Pretty.<> runSDoc sdoc ctx'
- Pretty.<> Pretty.zeroWidthText (Col.renderColourAfresh lastCol)
- ctx -> runSDoc sdoc ctx
- False -> sdoc
-
-keyword :: SDoc -> SDoc
-keyword = coloured Col.colBold
-
-{-
-************************************************************************
-* *
-\subsection[Outputable-class]{The @Outputable@ class}
-* *
-************************************************************************
--}
-
--- | Class designating that some type has an 'SDoc' representation
-class Outputable a where
- ppr :: a -> SDoc
- pprPrec :: Rational -> a -> SDoc
- -- 0 binds least tightly
- -- We use Rational because there is always a
- -- Rational between any other two Rationals
-
- ppr = pprPrec 0
- pprPrec _ = ppr
-
-instance Outputable Char where
- ppr c = text [c]
-
-instance Outputable Bool where
- ppr True = text "True"
- ppr False = text "False"
-
-instance Outputable Ordering where
- ppr LT = text "LT"
- ppr EQ = text "EQ"
- ppr GT = text "GT"
-
-instance Outputable Int32 where
- ppr n = integer $ fromIntegral n
-
-instance Outputable Int64 where
- ppr n = integer $ fromIntegral n
-
-instance Outputable Int where
- ppr n = int n
-
-instance Outputable Integer where
- ppr n = integer n
-
-instance Outputable Word16 where
- ppr n = integer $ fromIntegral n
-
-instance Outputable Word32 where
- ppr n = integer $ fromIntegral n
-
-instance Outputable Word where
- ppr n = integer $ fromIntegral n
-
-instance Outputable Float where
- ppr f = float f
-
-instance Outputable Double where
- ppr f = double f
-
-instance Outputable () where
- ppr _ = text "()"
-
-instance (Outputable a) => Outputable [a] where
- ppr xs = brackets (fsep (punctuate comma (map ppr xs)))
-
-instance (Outputable a) => Outputable (NonEmpty a) where
- ppr = ppr . NEL.toList
-
-instance (Outputable a) => Outputable (Set a) where
- ppr s = braces (fsep (punctuate comma (map ppr (Set.toList s))))
-
-instance (Outputable a, Outputable b) => Outputable (a, b) where
- ppr (x,y) = parens (sep [ppr x <> comma, ppr y])
-
-instance Outputable a => Outputable (Maybe a) where
- ppr Nothing = text "Nothing"
- ppr (Just x) = text "Just" <+> ppr x
-
-instance (Outputable a, Outputable b) => Outputable (Either a b) where
- ppr (Left x) = text "Left" <+> ppr x
- ppr (Right y) = text "Right" <+> ppr y
-
--- ToDo: may not be used
-instance (Outputable a, Outputable b, Outputable c) => Outputable (a, b, c) where
- ppr (x,y,z) =
- parens (sep [ppr x <> comma,
- ppr y <> comma,
- ppr z ])
-
-instance (Outputable a, Outputable b, Outputable c, Outputable d) =>
- Outputable (a, b, c, d) where
- ppr (a,b,c,d) =
- parens (sep [ppr a <> comma,
- ppr b <> comma,
- ppr c <> comma,
- ppr d])
-
-instance (Outputable a, Outputable b, Outputable c, Outputable d, Outputable e) =>
- Outputable (a, b, c, d, e) where
- ppr (a,b,c,d,e) =
- parens (sep [ppr a <> comma,
- ppr b <> comma,
- ppr c <> comma,
- ppr d <> comma,
- ppr e])
-
-instance (Outputable a, Outputable b, Outputable c, Outputable d, Outputable e, Outputable f) =>
- Outputable (a, b, c, d, e, f) where
- ppr (a,b,c,d,e,f) =
- parens (sep [ppr a <> comma,
- ppr b <> comma,
- ppr c <> comma,
- ppr d <> comma,
- ppr e <> comma,
- ppr f])
-
-instance (Outputable a, Outputable b, Outputable c, Outputable d, Outputable e, Outputable f, Outputable g) =>
- Outputable (a, b, c, d, e, f, g) where
- ppr (a,b,c,d,e,f,g) =
- parens (sep [ppr a <> comma,
- ppr b <> comma,
- ppr c <> comma,
- ppr d <> comma,
- ppr e <> comma,
- ppr f <> comma,
- ppr g])
-
-instance Outputable FastString where
- ppr fs = ftext fs -- Prints an unadorned string,
- -- no double quotes or anything
-
-instance (Outputable key, Outputable elt) => Outputable (M.Map key elt) where
- ppr m = ppr (M.toList m)
-instance (Outputable elt) => Outputable (IM.IntMap elt) where
- ppr m = ppr (IM.toList m)
-
-instance Outputable Fingerprint where
- ppr (Fingerprint w1 w2) = text (printf "%016x%016x" w1 w2)
-
-instance Outputable a => Outputable (SCC a) where
- ppr (AcyclicSCC v) = text "NONREC" $$ (nest 3 (ppr v))
- ppr (CyclicSCC vs) = text "REC" $$ (nest 3 (vcat (map ppr vs)))
-
-instance Outputable Serialized where
- ppr (Serialized the_type bytes) = int (length bytes) <+> text "of type" <+> text (show the_type)
-
-instance Outputable Extension where
- ppr = text . show
-
-{-
-************************************************************************
-* *
-\subsection{The @OutputableBndr@ class}
-* *
-************************************************************************
--}
-
--- | 'BindingSite' is used to tell the thing that prints binder what
--- language construct is binding the identifier. This can be used
--- to decide how much info to print.
--- Also see Note [Binding-site specific printing] in GHC.Core.Ppr
-data BindingSite
- = LambdaBind -- ^ The x in (\x. e)
- | CaseBind -- ^ The x in case scrut of x { (y,z) -> ... }
- | CasePatBind -- ^ The y,z in case scrut of x { (y,z) -> ... }
- | LetBind -- ^ The x in (let x = rhs in e)
-
--- | When we print a binder, we often want to print its type too.
--- The @OutputableBndr@ class encapsulates this idea.
-class Outputable a => OutputableBndr a where
- pprBndr :: BindingSite -> a -> SDoc
- pprBndr _b x = ppr x
-
- pprPrefixOcc, pprInfixOcc :: a -> SDoc
- -- Print an occurrence of the name, suitable either in the
- -- prefix position of an application, thus (f a b) or ((+) x)
- -- or infix position, thus (a `f` b) or (x + y)
-
- bndrIsJoin_maybe :: a -> Maybe Int
- bndrIsJoin_maybe _ = Nothing
- -- When pretty-printing we sometimes want to find
- -- whether the binder is a join point. You might think
- -- we could have a function of type (a->Var), but Var
- -- isn't available yet, alas
-
-{-
-************************************************************************
-* *
-\subsection{Random printing helpers}
-* *
-************************************************************************
--}
-
--- We have 31-bit Chars and will simply use Show instances of Char and String.
-
--- | Special combinator for showing character literals.
-pprHsChar :: Char -> SDoc
-pprHsChar c | c > '\x10ffff' = char '\\' <> text (show (fromIntegral (ord c) :: Word32))
- | otherwise = text (show c)
-
--- | Special combinator for showing string literals.
-pprHsString :: FastString -> SDoc
-pprHsString fs = vcat (map text (showMultiLineString (unpackFS fs)))
-
--- | Special combinator for showing bytestring literals.
-pprHsBytes :: ByteString -> SDoc
-pprHsBytes bs = let escaped = concatMap escape $ BS.unpack bs
- in vcat (map text (showMultiLineString escaped)) <> char '#'
- where escape :: Word8 -> String
- escape w = let c = chr (fromIntegral w)
- in if isAscii c
- then [c]
- else '\\' : show w
-
--- Postfix modifiers for unboxed literals.
--- See Note [Printing of literals in Core] in `basicTypes/Literal.hs`.
-primCharSuffix, primFloatSuffix, primIntSuffix :: SDoc
-primDoubleSuffix, primWordSuffix, primInt64Suffix, primWord64Suffix :: SDoc
-primCharSuffix = char '#'
-primFloatSuffix = char '#'
-primIntSuffix = char '#'
-primDoubleSuffix = text "##"
-primWordSuffix = text "##"
-primInt64Suffix = text "L#"
-primWord64Suffix = text "L##"
-
--- | Special combinator for showing unboxed literals.
-pprPrimChar :: Char -> SDoc
-pprPrimInt, pprPrimWord, pprPrimInt64, pprPrimWord64 :: Integer -> SDoc
-pprPrimChar c = pprHsChar c <> primCharSuffix
-pprPrimInt i = integer i <> primIntSuffix
-pprPrimWord w = word w <> primWordSuffix
-pprPrimInt64 i = integer i <> primInt64Suffix
-pprPrimWord64 w = word w <> primWord64Suffix
-
----------------------
--- Put a name in parens if it's an operator
-pprPrefixVar :: Bool -> SDoc -> SDoc
-pprPrefixVar is_operator pp_v
- | is_operator = parens pp_v
- | otherwise = pp_v
-
--- Put a name in backquotes if it's not an operator
-pprInfixVar :: Bool -> SDoc -> SDoc
-pprInfixVar is_operator pp_v
- | is_operator = pp_v
- | otherwise = char '`' <> pp_v <> char '`'
-
----------------------
-pprFastFilePath :: FastString -> SDoc
-pprFastFilePath path = text $ normalise $ unpackFS path
-
--- | Normalise, escape and render a string representing a path
---
--- e.g. "c:\\whatever"
-pprFilePathString :: FilePath -> SDoc
-pprFilePathString path = doubleQuotes $ text (escape (normalise path))
- where
- escape [] = []
- escape ('\\':xs) = '\\':'\\':escape xs
- escape (x:xs) = x:escape xs
-
-{-
-************************************************************************
-* *
-\subsection{Other helper functions}
-* *
-************************************************************************
--}
-
-pprWithCommas :: (a -> SDoc) -- ^ The pretty printing function to use
- -> [a] -- ^ The things to be pretty printed
- -> SDoc -- ^ 'SDoc' where the things have been pretty printed,
- -- comma-separated and finally packed into a paragraph.
-pprWithCommas pp xs = fsep (punctuate comma (map pp xs))
-
-pprWithBars :: (a -> SDoc) -- ^ The pretty printing function to use
- -> [a] -- ^ The things to be pretty printed
- -> SDoc -- ^ 'SDoc' where the things have been pretty printed,
- -- bar-separated and finally packed into a paragraph.
-pprWithBars pp xs = fsep (intersperse vbar (map pp xs))
-
--- | Returns the separated concatenation of the pretty printed things.
-interppSP :: Outputable a => [a] -> SDoc
-interppSP xs = sep (map ppr xs)
-
--- | Returns the comma-separated concatenation of the pretty printed things.
-interpp'SP :: Outputable a => [a] -> SDoc
-interpp'SP xs = sep (punctuate comma (map ppr xs))
-
--- | Returns the comma-separated concatenation of the quoted pretty printed things.
---
--- > [x,y,z] ==> `x', `y', `z'
-pprQuotedList :: Outputable a => [a] -> SDoc
-pprQuotedList = quotedList . map ppr
-
-quotedList :: [SDoc] -> SDoc
-quotedList xs = fsep (punctuate comma (map quotes xs))
-
-quotedListWithOr :: [SDoc] -> SDoc
--- [x,y,z] ==> `x', `y' or `z'
-quotedListWithOr xs@(_:_:_) = quotedList (init xs) <+> text "or" <+> quotes (last xs)
-quotedListWithOr xs = quotedList xs
-
-quotedListWithNor :: [SDoc] -> SDoc
--- [x,y,z] ==> `x', `y' nor `z'
-quotedListWithNor xs@(_:_:_) = quotedList (init xs) <+> text "nor" <+> quotes (last xs)
-quotedListWithNor xs = quotedList xs
-
-{-
-************************************************************************
-* *
-\subsection{Printing numbers verbally}
-* *
-************************************************************************
--}
-
-intWithCommas :: Integral a => a -> SDoc
--- Prints a big integer with commas, eg 345,821
-intWithCommas n
- | n < 0 = char '-' <> intWithCommas (-n)
- | q == 0 = int (fromIntegral r)
- | otherwise = intWithCommas q <> comma <> zeroes <> int (fromIntegral r)
- where
- (q,r) = n `quotRem` 1000
- zeroes | r >= 100 = empty
- | r >= 10 = char '0'
- | otherwise = text "00"
-
--- | Converts an integer to a verbal index:
---
--- > speakNth 1 = text "first"
--- > speakNth 5 = text "fifth"
--- > speakNth 21 = text "21st"
-speakNth :: Int -> SDoc
-speakNth 1 = text "first"
-speakNth 2 = text "second"
-speakNth 3 = text "third"
-speakNth 4 = text "fourth"
-speakNth 5 = text "fifth"
-speakNth 6 = text "sixth"
-speakNth n = hcat [ int n, text suffix ]
- where
- suffix | n <= 20 = "th" -- 11,12,13 are non-std
- | last_dig == 1 = "st"
- | last_dig == 2 = "nd"
- | last_dig == 3 = "rd"
- | otherwise = "th"
-
- last_dig = n `rem` 10
-
--- | Converts an integer to a verbal multiplicity:
---
--- > speakN 0 = text "none"
--- > speakN 5 = text "five"
--- > speakN 10 = text "10"
-speakN :: Int -> SDoc
-speakN 0 = text "none" -- E.g. "he has none"
-speakN 1 = text "one" -- E.g. "he has one"
-speakN 2 = text "two"
-speakN 3 = text "three"
-speakN 4 = text "four"
-speakN 5 = text "five"
-speakN 6 = text "six"
-speakN n = int n
-
--- | Converts an integer and object description to a statement about the
--- multiplicity of those objects:
---
--- > speakNOf 0 (text "melon") = text "no melons"
--- > speakNOf 1 (text "melon") = text "one melon"
--- > speakNOf 3 (text "melon") = text "three melons"
-speakNOf :: Int -> SDoc -> SDoc
-speakNOf 0 d = text "no" <+> d <> char 's'
-speakNOf 1 d = text "one" <+> d -- E.g. "one argument"
-speakNOf n d = speakN n <+> d <> char 's' -- E.g. "three arguments"
-
--- | Determines the pluralisation suffix appropriate for the length of a list:
---
--- > plural [] = char 's'
--- > plural ["Hello"] = empty
--- > plural ["Hello", "World"] = char 's'
-plural :: [a] -> SDoc
-plural [_] = empty -- a bit frightening, but there you are
-plural _ = char 's'
-
--- | Determines the form of to be appropriate for the length of a list:
---
--- > isOrAre [] = text "are"
--- > isOrAre ["Hello"] = text "is"
--- > isOrAre ["Hello", "World"] = text "are"
-isOrAre :: [a] -> SDoc
-isOrAre [_] = text "is"
-isOrAre _ = text "are"
-
--- | Determines the form of to do appropriate for the length of a list:
---
--- > doOrDoes [] = text "do"
--- > doOrDoes ["Hello"] = text "does"
--- > doOrDoes ["Hello", "World"] = text "do"
-doOrDoes :: [a] -> SDoc
-doOrDoes [_] = text "does"
-doOrDoes _ = text "do"
-
--- | Determines the form of possessive appropriate for the length of a list:
---
--- > itsOrTheir [x] = text "its"
--- > itsOrTheir [x,y] = text "their"
--- > itsOrTheir [] = text "their" -- probably avoid this
-itsOrTheir :: [a] -> SDoc
-itsOrTheir [_] = text "its"
-itsOrTheir _ = text "their"
-
-{-
-************************************************************************
-* *
-\subsection{Error handling}
-* *
-************************************************************************
--}
-
-callStackDoc :: HasCallStack => SDoc
-callStackDoc =
- hang (text "Call stack:")
- 4 (vcat $ map text $ lines (prettyCallStack callStack))
-
-pprPanic :: HasCallStack => String -> SDoc -> a
--- ^ Throw an exception saying "bug in GHC"
-pprPanic s doc = panicDoc s (doc $$ callStackDoc)
-
-pprSorry :: String -> SDoc -> a
--- ^ Throw an exception saying "this isn't finished yet"
-pprSorry = sorryDoc
-
-
-pprPgmError :: String -> SDoc -> a
--- ^ Throw an exception saying "bug in pgm being compiled" (used for unusual program errors)
-pprPgmError = pgmErrorDoc
-
-pprTraceDebug :: String -> SDoc -> a -> a
-pprTraceDebug str doc x
- | debugIsOn && hasPprDebug unsafeGlobalDynFlags = pprTrace str doc x
- | otherwise = x
-
--- | If debug output is on, show some 'SDoc' on the screen
-pprTrace :: String -> SDoc -> a -> a
-pprTrace str doc x = pprTraceWithFlags unsafeGlobalDynFlags str doc x
-
--- | If debug output is on, show some 'SDoc' on the screen
-pprTraceWithFlags :: DynFlags -> String -> SDoc -> a -> a
-pprTraceWithFlags dflags str doc x
- | hasNoDebugOutput dflags = x
- | otherwise = pprDebugAndThen dflags trace (text str) doc x
-
-pprTraceM :: Applicative f => String -> SDoc -> f ()
-pprTraceM str doc = pprTrace str doc (pure ())
-
--- | @pprTraceWith desc f x@ is equivalent to @pprTrace desc (f x) x@.
--- This allows you to print details from the returned value as well as from
--- ambient variables.
-pprTraceWith :: String -> (a -> SDoc) -> a -> a
-pprTraceWith desc f x = pprTrace desc (f x) x
-
--- | @pprTraceIt desc x@ is equivalent to @pprTrace desc (ppr x) x@
-pprTraceIt :: Outputable a => String -> a -> a
-pprTraceIt desc x = pprTraceWith desc ppr x
-
--- | @pprTraceException desc x action@ runs action, printing a message
--- if it throws an exception.
-pprTraceException :: ExceptionMonad m => String -> SDoc -> m a -> m a
-pprTraceException heading doc =
- handleGhcException $ \exc -> liftIO $ do
- putStrLn $ showSDocDump unsafeGlobalDynFlags (sep [text heading, nest 2 doc])
- throwGhcExceptionIO exc
-
--- | If debug output is on, show some 'SDoc' on the screen along
--- with a call stack when available.
-pprSTrace :: HasCallStack => SDoc -> a -> a
-pprSTrace doc = pprTrace "" (doc $$ callStackDoc)
-
-warnPprTrace :: HasCallStack => Bool -> String -> Int -> SDoc -> a -> a
--- ^ Just warn about an assertion failure, recording the given file and line number.
--- Should typically be accessed with the WARN macros
-warnPprTrace _ _ _ _ x | not debugIsOn = x
-warnPprTrace _ _file _line _msg x
- | hasNoDebugOutput unsafeGlobalDynFlags = x
-warnPprTrace False _file _line _msg x = x
-warnPprTrace True file line msg x
- = pprDebugAndThen unsafeGlobalDynFlags trace heading
- (msg $$ callStackDoc )
- x
- where
- heading = hsep [text "WARNING: file", text file <> comma, text "line", int line]
-
--- | Panic with an assertion failure, recording the given file and
--- line number. Should typically be accessed with the ASSERT family of macros
-assertPprPanic :: HasCallStack => String -> Int -> SDoc -> a
-assertPprPanic _file _line msg
- = pprPanic "ASSERT failed!" msg
-
-pprDebugAndThen :: DynFlags -> (String -> a) -> SDoc -> SDoc -> a
-pprDebugAndThen dflags cont heading pretty_msg
- = cont (showSDocDump dflags doc)
- where
- doc = sep [heading, nest 2 pretty_msg]
diff --git a/compiler/utils/Outputable.hs-boot b/compiler/utils/Outputable.hs-boot
deleted file mode 100644
index 77e0982826..0000000000
--- a/compiler/utils/Outputable.hs-boot
+++ /dev/null
@@ -1,14 +0,0 @@
-module Outputable where
-
-import GhcPrelude
-import GHC.Stack( HasCallStack )
-
-data SDoc
-data PprStyle
-data SDocContext
-
-showSDocUnsafe :: SDoc -> String
-
-warnPprTrace :: HasCallStack => Bool -> String -> Int -> SDoc -> a -> a
-
-text :: String -> SDoc
diff --git a/compiler/utils/Pair.hs b/compiler/utils/Pair.hs
deleted file mode 100644
index e9313f89b2..0000000000
--- a/compiler/utils/Pair.hs
+++ /dev/null
@@ -1,60 +0,0 @@
-{-
-A simple homogeneous pair type with useful Functor, Applicative, and
-Traversable instances.
--}
-
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE DeriveFunctor #-}
-
-module Pair ( Pair(..), unPair, toPair, swap, pLiftFst, pLiftSnd ) where
-
-#include "HsVersions.h"
-
-import GhcPrelude
-
-import Outputable
-import qualified Data.Semigroup as Semi
-
-data Pair a = Pair { pFst :: a, pSnd :: a }
- deriving (Functor)
--- Note that Pair is a *unary* type constructor
--- whereas (,) is binary
-
--- The important thing about Pair is that it has a *homogeneous*
--- Functor instance, so you can easily apply the same function
--- to both components
-
-instance Applicative Pair where
- pure x = Pair x x
- (Pair f g) <*> (Pair x y) = Pair (f x) (g y)
-
-instance Foldable Pair where
- foldMap f (Pair x y) = f x `mappend` f y
-
-instance Traversable Pair where
- traverse f (Pair x y) = Pair <$> f x <*> f y
-
-instance Semi.Semigroup a => Semi.Semigroup (Pair a) where
- Pair a1 b1 <> Pair a2 b2 = Pair (a1 Semi.<> a2) (b1 Semi.<> b2)
-
-instance (Semi.Semigroup a, Monoid a) => Monoid (Pair a) where
- mempty = Pair mempty mempty
- mappend = (Semi.<>)
-
-instance Outputable a => Outputable (Pair a) where
- ppr (Pair a b) = ppr a <+> char '~' <+> ppr b
-
-unPair :: Pair a -> (a,a)
-unPair (Pair x y) = (x,y)
-
-toPair :: (a,a) -> Pair a
-toPair (x,y) = Pair x y
-
-swap :: Pair a -> Pair a
-swap (Pair x y) = Pair y x
-
-pLiftFst :: (a -> a) -> Pair a -> Pair a
-pLiftFst f (Pair a b) = Pair (f a) b
-
-pLiftSnd :: (a -> a) -> Pair a -> Pair a
-pLiftSnd f (Pair a b) = Pair a (f b)
diff --git a/compiler/utils/Panic.hs b/compiler/utils/Panic.hs
deleted file mode 100644
index 16f493826c..0000000000
--- a/compiler/utils/Panic.hs
+++ /dev/null
@@ -1,259 +0,0 @@
-{-
-(c) The University of Glasgow 2006
-(c) The GRASP Project, Glasgow University, 1992-2000
-
-Defines basic functions for printing error messages.
-
-It's hard to put these functions anywhere else without causing
-some unnecessary loops in the module dependency graph.
--}
-
-{-# LANGUAGE CPP, ScopedTypeVariables, LambdaCase #-}
-
-module Panic (
- GhcException(..), showGhcException,
- throwGhcException, throwGhcExceptionIO,
- handleGhcException,
- PlainPanic.progName,
- pgmError,
-
- panic, sorry, assertPanic, trace,
- panicDoc, sorryDoc, pgmErrorDoc,
-
- cmdLineError, cmdLineErrorIO,
-
- Exception.Exception(..), showException, safeShowException,
- try, tryMost, throwTo,
-
- withSignalHandlers,
-) where
-
-import GhcPrelude
-
-import {-# SOURCE #-} Outputable (SDoc, showSDocUnsafe)
-import PlainPanic
-
-import Exception
-
-import Control.Monad.IO.Class
-import Control.Concurrent
-import Data.Typeable ( cast )
-import Debug.Trace ( trace )
-import System.IO.Unsafe
-
-#if !defined(mingw32_HOST_OS)
-import System.Posix.Signals as S
-#endif
-
-#if defined(mingw32_HOST_OS)
-import GHC.ConsoleHandler as S
-#endif
-
-import System.Mem.Weak ( deRefWeak )
-
--- | GHC's own exception type
--- error messages all take the form:
---
--- @
--- <location>: <error>
--- @
---
--- If the location is on the command line, or in GHC itself, then
--- <location>="ghc". All of the error types below correspond to
--- a <location> of "ghc", except for ProgramError (where the string is
--- assumed to contain a location already, so we don't print one).
-
-data GhcException
- -- | Some other fatal signal (SIGHUP,SIGTERM)
- = Signal Int
-
- -- | Prints the short usage msg after the error
- | UsageError String
-
- -- | A problem with the command line arguments, but don't print usage.
- | CmdLineError String
-
- -- | The 'impossible' happened.
- | Panic String
- | PprPanic String SDoc
-
- -- | The user tickled something that's known not to work yet,
- -- but we're not counting it as a bug.
- | Sorry String
- | PprSorry String SDoc
-
- -- | An installation problem.
- | InstallationError String
-
- -- | An error in the user's code, probably.
- | ProgramError String
- | PprProgramError String SDoc
-
-instance Exception GhcException where
- fromException (SomeException e)
- | Just ge <- cast e = Just ge
- | Just pge <- cast e = Just $
- case pge of
- PlainSignal n -> Signal n
- PlainUsageError str -> UsageError str
- PlainCmdLineError str -> CmdLineError str
- PlainPanic str -> Panic str
- PlainSorry str -> Sorry str
- PlainInstallationError str -> InstallationError str
- PlainProgramError str -> ProgramError str
- | otherwise = Nothing
-
-instance Show GhcException where
- showsPrec _ e@(ProgramError _) = showGhcException e
- showsPrec _ e@(CmdLineError _) = showString "<command line>: " . showGhcException e
- showsPrec _ e = showString progName . showString ": " . showGhcException e
-
--- | Show an exception as a string.
-showException :: Exception e => e -> String
-showException = show
-
--- | Show an exception which can possibly throw other exceptions.
--- Used when displaying exception thrown within TH code.
-safeShowException :: Exception e => e -> IO String
-safeShowException e = do
- -- ensure the whole error message is evaluated inside try
- r <- try (return $! forceList (showException e))
- case r of
- Right msg -> return msg
- Left e' -> safeShowException (e' :: SomeException)
- where
- forceList [] = []
- forceList xs@(x : xt) = x `seq` forceList xt `seq` xs
-
--- | Append a description of the given exception to this string.
---
--- Note that this uses 'DynFlags.unsafeGlobalDynFlags', which may have some
--- uninitialized fields if invoked before 'GHC.initGhcMonad' has been called.
--- If the error message to be printed includes a pretty-printer document
--- which forces one of these fields this call may bottom.
-showGhcException :: GhcException -> ShowS
-showGhcException = showPlainGhcException . \case
- Signal n -> PlainSignal n
- UsageError str -> PlainUsageError str
- CmdLineError str -> PlainCmdLineError str
- Panic str -> PlainPanic str
- Sorry str -> PlainSorry str
- InstallationError str -> PlainInstallationError str
- ProgramError str -> PlainProgramError str
-
- PprPanic str sdoc -> PlainPanic $
- concat [str, "\n\n", showSDocUnsafe sdoc]
- PprSorry str sdoc -> PlainProgramError $
- concat [str, "\n\n", showSDocUnsafe sdoc]
- PprProgramError str sdoc -> PlainProgramError $
- concat [str, "\n\n", showSDocUnsafe sdoc]
-
-throwGhcException :: GhcException -> a
-throwGhcException = Exception.throw
-
-throwGhcExceptionIO :: GhcException -> IO a
-throwGhcExceptionIO = Exception.throwIO
-
-handleGhcException :: ExceptionMonad m => (GhcException -> m a) -> m a -> m a
-handleGhcException = ghandle
-
-panicDoc, sorryDoc, pgmErrorDoc :: String -> SDoc -> a
-panicDoc x doc = throwGhcException (PprPanic x doc)
-sorryDoc x doc = throwGhcException (PprSorry x doc)
-pgmErrorDoc x doc = throwGhcException (PprProgramError x doc)
-
--- | Like try, but pass through UserInterrupt and Panic exceptions.
--- Used when we want soft failures when reading interface files, for example.
--- TODO: I'm not entirely sure if this is catching what we really want to catch
-tryMost :: IO a -> IO (Either SomeException a)
-tryMost action = do r <- try action
- case r of
- Left se ->
- case fromException se of
- -- Some GhcException's we rethrow,
- Just (Signal _) -> throwIO se
- Just (Panic _) -> throwIO se
- -- others we return
- Just _ -> return (Left se)
- Nothing ->
- case fromException se of
- -- All IOExceptions are returned
- Just (_ :: IOException) ->
- return (Left se)
- -- Anything else is rethrown
- Nothing -> throwIO se
- Right v -> return (Right v)
-
--- | We use reference counting for signal handlers
-{-# NOINLINE signalHandlersRefCount #-}
-#if !defined(mingw32_HOST_OS)
-signalHandlersRefCount :: MVar (Word, Maybe (S.Handler,S.Handler
- ,S.Handler,S.Handler))
-#else
-signalHandlersRefCount :: MVar (Word, Maybe S.Handler)
-#endif
-signalHandlersRefCount = unsafePerformIO $ newMVar (0,Nothing)
-
-
--- | Temporarily install standard signal handlers for catching ^C, which just
--- throw an exception in the current thread.
-withSignalHandlers :: (ExceptionMonad m, MonadIO m) => m a -> m a
-withSignalHandlers act = do
- main_thread <- liftIO myThreadId
- wtid <- liftIO (mkWeakThreadId main_thread)
-
- let
- interrupt = do
- r <- deRefWeak wtid
- case r of
- Nothing -> return ()
- Just t -> throwTo t UserInterrupt
-
-#if !defined(mingw32_HOST_OS)
- let installHandlers = do
- let installHandler' a b = installHandler a b Nothing
- hdlQUIT <- installHandler' sigQUIT (Catch interrupt)
- hdlINT <- installHandler' sigINT (Catch interrupt)
- -- see #3656; in the future we should install these automatically for
- -- all Haskell programs in the same way that we install a ^C handler.
- let fatal_signal n = throwTo main_thread (Signal (fromIntegral n))
- hdlHUP <- installHandler' sigHUP (Catch (fatal_signal sigHUP))
- hdlTERM <- installHandler' sigTERM (Catch (fatal_signal sigTERM))
- return (hdlQUIT,hdlINT,hdlHUP,hdlTERM)
-
- let uninstallHandlers (hdlQUIT,hdlINT,hdlHUP,hdlTERM) = do
- _ <- installHandler sigQUIT hdlQUIT Nothing
- _ <- installHandler sigINT hdlINT Nothing
- _ <- installHandler sigHUP hdlHUP Nothing
- _ <- installHandler sigTERM hdlTERM Nothing
- return ()
-#else
- -- GHC 6.3+ has support for console events on Windows
- -- NOTE: running GHCi under a bash shell for some reason requires
- -- you to press Ctrl-Break rather than Ctrl-C to provoke
- -- an interrupt. Ctrl-C is getting blocked somewhere, I don't know
- -- why --SDM 17/12/2004
- let sig_handler ControlC = interrupt
- sig_handler Break = interrupt
- sig_handler _ = return ()
-
- let installHandlers = installHandler (Catch sig_handler)
- let uninstallHandlers = installHandler -- directly install the old handler
-#endif
-
- -- install signal handlers if necessary
- let mayInstallHandlers = liftIO $ modifyMVar_ signalHandlersRefCount $ \case
- (0,Nothing) -> do
- hdls <- installHandlers
- return (1,Just hdls)
- (c,oldHandlers) -> return (c+1,oldHandlers)
-
- -- uninstall handlers if necessary
- let mayUninstallHandlers = liftIO $ modifyMVar_ signalHandlersRefCount $ \case
- (1,Just hdls) -> do
- _ <- uninstallHandlers hdls
- return (0,Nothing)
- (c,oldHandlers) -> return (c-1,oldHandlers)
-
- mayInstallHandlers
- act `gfinally` mayUninstallHandlers
diff --git a/compiler/utils/PlainPanic.hs b/compiler/utils/PlainPanic.hs
deleted file mode 100644
index 0892ebff7d..0000000000
--- a/compiler/utils/PlainPanic.hs
+++ /dev/null
@@ -1,138 +0,0 @@
-{-# LANGUAGE CPP, ScopedTypeVariables, LambdaCase #-}
-
--- | Defines a simple exception type and utilities to throw it. The
--- 'PlainGhcException' type is a subset of the 'Panic.GhcException'
--- type. It omits the exception constructors that involve
--- pretty-printing via 'Outputable.SDoc'.
---
--- There are two reasons for this:
---
--- 1. To avoid import cycles / use of boot files. "Outputable" has
--- many transitive dependencies. To throw exceptions from these
--- modules, the functions here can be used without introducing import
--- cycles.
---
--- 2. To reduce the number of modules that need to be compiled to
--- object code when loading GHC into GHCi. See #13101
-module PlainPanic
- ( PlainGhcException(..)
- , showPlainGhcException
-
- , panic, sorry, pgmError
- , cmdLineError, cmdLineErrorIO
- , assertPanic
-
- , progName
- ) where
-
-#include "HsVersions.h"
-
-import Config
-import Exception
-import GHC.Stack
-import GhcPrelude
-import System.Environment
-import System.IO.Unsafe
-
--- | This type is very similar to 'Panic.GhcException', but it omits
--- the constructors that involve pretty-printing via
--- 'Outputable.SDoc'. Due to the implementation of 'fromException'
--- for 'Panic.GhcException', this type can be caught as a
--- 'Panic.GhcException'.
---
--- Note that this should only be used for throwing exceptions, not for
--- catching, as 'Panic.GhcException' will not be converted to this
--- type when catching.
-data PlainGhcException
- -- | Some other fatal signal (SIGHUP,SIGTERM)
- = PlainSignal Int
-
- -- | Prints the short usage msg after the error
- | PlainUsageError String
-
- -- | A problem with the command line arguments, but don't print usage.
- | PlainCmdLineError String
-
- -- | The 'impossible' happened.
- | PlainPanic String
-
- -- | The user tickled something that's known not to work yet,
- -- but we're not counting it as a bug.
- | PlainSorry String
-
- -- | An installation problem.
- | PlainInstallationError String
-
- -- | An error in the user's code, probably.
- | PlainProgramError String
-
-instance Exception PlainGhcException
-
-instance Show PlainGhcException where
- showsPrec _ e@(PlainProgramError _) = showPlainGhcException e
- showsPrec _ e@(PlainCmdLineError _) = showString "<command line>: " . showPlainGhcException e
- showsPrec _ e = showString progName . showString ": " . showPlainGhcException e
-
--- | The name of this GHC.
-progName :: String
-progName = unsafePerformIO (getProgName)
-{-# NOINLINE progName #-}
-
--- | Short usage information to display when we are given the wrong cmd line arguments.
-short_usage :: String
-short_usage = "Usage: For basic information, try the `--help' option."
-
--- | Append a description of the given exception to this string.
-showPlainGhcException :: PlainGhcException -> ShowS
-showPlainGhcException =
- \case
- PlainSignal n -> showString "signal: " . shows n
- PlainUsageError str -> showString str . showChar '\n' . showString short_usage
- PlainCmdLineError str -> showString str
- PlainPanic s -> panicMsg (showString s)
- PlainSorry s -> sorryMsg (showString s)
- PlainInstallationError str -> showString str
- PlainProgramError str -> showString str
- where
- sorryMsg :: ShowS -> ShowS
- sorryMsg s =
- showString "sorry! (unimplemented feature or known bug)\n"
- . showString (" (GHC version " ++ cProjectVersion ++ ":\n\t")
- . s . showString "\n"
-
- panicMsg :: ShowS -> ShowS
- panicMsg s =
- showString "panic! (the 'impossible' happened)\n"
- . showString (" (GHC version " ++ cProjectVersion ++ ":\n\t")
- . s . showString "\n\n"
- . showString "Please report this as a GHC bug: https://www.haskell.org/ghc/reportabug\n"
-
-throwPlainGhcException :: PlainGhcException -> a
-throwPlainGhcException = Exception.throw
-
--- | Panics and asserts.
-panic, sorry, pgmError :: String -> a
-panic x = unsafeDupablePerformIO $ do
- stack <- ccsToStrings =<< getCurrentCCS x
- if null stack
- then throwPlainGhcException (PlainPanic x)
- else throwPlainGhcException (PlainPanic (x ++ '\n' : renderStack stack))
-
-sorry x = throwPlainGhcException (PlainSorry x)
-pgmError x = throwPlainGhcException (PlainProgramError x)
-
-cmdLineError :: String -> a
-cmdLineError = unsafeDupablePerformIO . cmdLineErrorIO
-
-cmdLineErrorIO :: String -> IO a
-cmdLineErrorIO x = do
- stack <- ccsToStrings =<< getCurrentCCS x
- if null stack
- then throwPlainGhcException (PlainCmdLineError x)
- else throwPlainGhcException (PlainCmdLineError (x ++ '\n' : renderStack stack))
-
--- | Throw a failed assertion exception for a given filename and line number.
-assertPanic :: String -> Int -> a
-assertPanic file line =
- Exception.throw (Exception.AssertionFailed
- ("ASSERT failed! file " ++ file ++ ", line " ++ show line))
diff --git a/compiler/utils/PprColour.hs b/compiler/utils/PprColour.hs
deleted file mode 100644
index f32b8b0084..0000000000
--- a/compiler/utils/PprColour.hs
+++ /dev/null
@@ -1,101 +0,0 @@
-module PprColour where
-import GhcPrelude
-
-import Data.Maybe (fromMaybe)
-import Util (OverridingBool(..), split)
-import Data.Semigroup as Semi
-
--- | A colour\/style for use with 'coloured'.
-newtype PprColour = PprColour { renderColour :: String }
-
-instance Semi.Semigroup PprColour where
- PprColour s1 <> PprColour s2 = PprColour (s1 <> s2)
-
--- | Allow colours to be combined (e.g. bold + red);
--- In case of conflict, right side takes precedence.
-instance Monoid PprColour where
- mempty = PprColour mempty
- mappend = (<>)
-
-renderColourAfresh :: PprColour -> String
-renderColourAfresh c = renderColour (colReset `mappend` c)
-
-colCustom :: String -> PprColour
-colCustom "" = mempty
-colCustom s = PprColour ("\27[" ++ s ++ "m")
-
-colReset :: PprColour
-colReset = colCustom "0"
-
-colBold :: PprColour
-colBold = colCustom ";1"
-
-colBlackFg :: PprColour
-colBlackFg = colCustom "30"
-
-colRedFg :: PprColour
-colRedFg = colCustom "31"
-
-colGreenFg :: PprColour
-colGreenFg = colCustom "32"
-
-colYellowFg :: PprColour
-colYellowFg = colCustom "33"
-
-colBlueFg :: PprColour
-colBlueFg = colCustom "34"
-
-colMagentaFg :: PprColour
-colMagentaFg = colCustom "35"
-
-colCyanFg :: PprColour
-colCyanFg = colCustom "36"
-
-colWhiteFg :: PprColour
-colWhiteFg = colCustom "37"
-
-data Scheme =
- Scheme
- { sHeader :: PprColour
- , sMessage :: PprColour
- , sWarning :: PprColour
- , sError :: PprColour
- , sFatal :: PprColour
- , sMargin :: PprColour
- }
-
-defaultScheme :: Scheme
-defaultScheme =
- Scheme
- { sHeader = mempty
- , sMessage = colBold
- , sWarning = colBold `mappend` colMagentaFg
- , sError = colBold `mappend` colRedFg
- , sFatal = colBold `mappend` colRedFg
- , sMargin = colBold `mappend` colBlueFg
- }
-
--- | Parse the colour scheme from a string (presumably from the @GHC_COLORS@
--- environment variable).
-parseScheme :: String -> (OverridingBool, Scheme) -> (OverridingBool, Scheme)
-parseScheme "always" (_, cs) = (Always, cs)
-parseScheme "auto" (_, cs) = (Auto, cs)
-parseScheme "never" (_, cs) = (Never, cs)
-parseScheme input (b, cs) =
- ( b
- , Scheme
- { sHeader = fromMaybe (sHeader cs) (lookup "header" table)
- , sMessage = fromMaybe (sMessage cs) (lookup "message" table)
- , sWarning = fromMaybe (sWarning cs) (lookup "warning" table)
- , sError = fromMaybe (sError cs) (lookup "error" table)
- , sFatal = fromMaybe (sFatal cs) (lookup "fatal" table)
- , sMargin = fromMaybe (sMargin cs) (lookup "margin" table)
- }
- )
- where
- table = do
- w <- split ':' input
- let (k, v') = break (== '=') w
- case v' of
- '=' : v -> return (k, colCustom v)
- _ -> []
diff --git a/compiler/utils/Pretty.hs b/compiler/utils/Pretty.hs
deleted file mode 100644
index 5adfdd7699..0000000000
--- a/compiler/utils/Pretty.hs
+++ /dev/null
@@ -1,1105 +0,0 @@
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE MagicHash #-}
-
------------------------------------------------------------------------------
--- |
--- Module : Pretty
--- Copyright : (c) The University of Glasgow 2001
--- License : BSD-style (see the file LICENSE)
---
--- Maintainer : David Terei <code@davidterei.com>
--- Stability : stable
--- Portability : portable
---
--- John Hughes's and Simon Peyton Jones's Pretty Printer Combinators
---
--- Based on /The Design of a Pretty-printing Library/
--- in Advanced Functional Programming,
--- Johan Jeuring and Erik Meijer (eds), LNCS 925
--- <http://www.cs.chalmers.se/~rjmh/Papers/pretty.ps>
---
------------------------------------------------------------------------------
-
-{-
-Note [Differences between libraries/pretty and compiler/utils/Pretty.hs]
-
-For historical reasons, there are two different copies of `Pretty` in the GHC
-source tree:
- * `libraries/pretty` is a submodule containing
- https://github.com/haskell/pretty. This is the `pretty` library as released
- on hackage. It is used by several other libraries in the GHC source tree
- (e.g. template-haskell and Cabal).
- * `compiler/utils/Pretty.hs` (this module). It is used by GHC only.
-
-There is an ongoing effort in https://github.com/haskell/pretty/issues/1 and
-https://gitlab.haskell.org/ghc/ghc/issues/10735 to try to get rid of GHC's copy
-of Pretty.
-
-Currently, GHC's copy of Pretty resembles pretty-1.1.2.0, with the following
-major differences:
- * GHC's copy uses `Faststring` for performance reasons.
- * GHC's copy has received a backported bugfix for #12227, which was
- released as pretty-1.1.3.4 ("Remove harmful $! forcing in beside",
- https://github.com/haskell/pretty/pull/35).
-
-Other differences are minor. Both copies define some extra functions and
-instances not defined in the other copy. To see all differences, do this in a
-ghc git tree:
-
- $ cd libraries/pretty
- $ git checkout v1.1.2.0
- $ cd -
- $ vimdiff compiler/utils/Pretty.hs \
- libraries/pretty/src/Text/PrettyPrint/HughesPJ.hs
-
-For parity with `pretty-1.1.2.1`, the following two `pretty` commits would
-have to be backported:
- * "Resolve foldr-strictness stack overflow bug"
- (307b8173f41cd776eae8f547267df6d72bff2d68)
- * "Special-case reduce for horiz/vert"
- (c57c7a9dfc49617ba8d6e4fcdb019a3f29f1044c)
-This has not been done sofar, because these commits seem to cause more
-allocation in the compiler (see thomie's comments in
-https://github.com/haskell/pretty/pull/9).
--}
-
-module Pretty (
-
- -- * The document type
- Doc, TextDetails(..),
-
- -- * Constructing documents
-
- -- ** Converting values into documents
- char, text, ftext, ptext, ztext, sizedText, zeroWidthText,
- int, integer, float, double, rational, hex,
-
- -- ** Simple derived documents
- semi, comma, colon, space, equals,
- lparen, rparen, lbrack, rbrack, lbrace, rbrace,
-
- -- ** Wrapping documents in delimiters
- parens, brackets, braces, quotes, quote, doubleQuotes,
- maybeParens,
-
- -- ** Combining documents
- empty,
- (<>), (<+>), hcat, hsep,
- ($$), ($+$), vcat,
- sep, cat,
- fsep, fcat,
- nest,
- hang, hangNotEmpty, punctuate,
-
- -- * Predicates on documents
- isEmpty,
-
- -- * Rendering documents
-
- -- ** Rendering with a particular style
- Style(..),
- style,
- renderStyle,
- Mode(..),
-
- -- ** General rendering
- fullRender, txtPrinter,
-
- -- ** GHC-specific rendering
- printDoc, printDoc_,
- bufLeftRender -- performance hack
-
- ) where
-
-import GhcPrelude hiding (error)
-
-import BufWrite
-import FastString
-import PlainPanic
-import System.IO
-import Numeric (showHex)
-
---for a RULES
-import GHC.Base ( unpackCString#, unpackNBytes#, Int(..) )
-import GHC.Ptr ( Ptr(..) )
-
--- ---------------------------------------------------------------------------
--- The Doc calculus
-
-{-
-Laws for $$
-~~~~~~~~~~~
-<a1> (x $$ y) $$ z = x $$ (y $$ z)
-<a2> empty $$ x = x
-<a3> x $$ empty = x
-
- ...ditto $+$...
-
-Laws for <>
-~~~~~~~~~~~
-<b1> (x <> y) <> z = x <> (y <> z)
-<b2> empty <> x = empty
-<b3> x <> empty = x
-
- ...ditto <+>...
-
-Laws for text
-~~~~~~~~~~~~~
-<t1> text s <> text t = text (s++t)
-<t2> text "" <> x = x, if x non-empty
-
-** because of law n6, t2 only holds if x doesn't
-** start with `nest'.
-
-
-Laws for nest
-~~~~~~~~~~~~~
-<n1> nest 0 x = x
-<n2> nest k (nest k' x) = nest (k+k') x
-<n3> nest k (x <> y) = nest k x <> nest k y
-<n4> nest k (x $$ y) = nest k x $$ nest k y
-<n5> nest k empty = empty
-<n6> x <> nest k y = x <> y, if x non-empty
-
-** Note the side condition on <n6>! It is this that
-** makes it OK for empty to be a left unit for <>.
-
-Miscellaneous
-~~~~~~~~~~~~~
-<m1> (text s <> x) $$ y = text s <> ((text "" <> x) $$
- nest (-length s) y)
-
-<m2> (x $$ y) <> z = x $$ (y <> z)
- if y non-empty
-
-
-Laws for list versions
-~~~~~~~~~~~~~~~~~~~~~~
-<l1> sep (ps++[empty]++qs) = sep (ps ++ qs)
- ...ditto hsep, hcat, vcat, fill...
-
-<l2> nest k (sep ps) = sep (map (nest k) ps)
- ...ditto hsep, hcat, vcat, fill...
-
-Laws for oneLiner
-~~~~~~~~~~~~~~~~~
-<o1> oneLiner (nest k p) = nest k (oneLiner p)
-<o2> oneLiner (x <> y) = oneLiner x <> oneLiner y
-
-You might think that the following version of <m1> would
-be neater:
-
-<3 NO> (text s <> x) $$ y = text s <> ((empty <> x)) $$
- nest (-length s) y)
-
-But it doesn't work, for if x=empty, we would have
-
- text s $$ y = text s <> (empty $$ nest (-length s) y)
- = text s <> nest (-length s) y
--}
-
--- ---------------------------------------------------------------------------
--- Operator fixity
-
-infixl 6 <>
-infixl 6 <+>
-infixl 5 $$, $+$
-
-
--- ---------------------------------------------------------------------------
--- The Doc data type
-
--- | The abstract type of documents.
--- A Doc represents a *set* of layouts. A Doc with
--- no occurrences of Union or NoDoc represents just one layout.
-data Doc
- = Empty -- empty
- | NilAbove Doc -- text "" $$ x
- | TextBeside !TextDetails {-# UNPACK #-} !Int Doc -- text s <> x
- | Nest {-# UNPACK #-} !Int Doc -- nest k x
- | Union Doc Doc -- ul `union` ur
- | NoDoc -- The empty set of documents
- | Beside Doc Bool Doc -- True <=> space between
- | Above Doc Bool Doc -- True <=> never overlap
-
-{-
-Here are the invariants:
-
-1) The argument of NilAbove is never Empty. Therefore
- a NilAbove occupies at least two lines.
-
-2) The argument of @TextBeside@ is never @Nest@.
-
-3) The layouts of the two arguments of @Union@ both flatten to the same
- string.
-
-4) The arguments of @Union@ are either @TextBeside@, or @NilAbove@.
-
-5) A @NoDoc@ may only appear on the first line of the left argument of an
- union. Therefore, the right argument of an union can never be equivalent
- to the empty set (@NoDoc@).
-
-6) An empty document is always represented by @Empty@. It can't be
- hidden inside a @Nest@, or a @Union@ of two @Empty@s.
-
-7) The first line of every layout in the left argument of @Union@ is
- longer than the first line of any layout in the right argument.
- (1) ensures that the left argument has a first line. In view of
- (3), this invariant means that the right argument must have at
- least two lines.
-
-Notice the difference between
- * NoDoc (no documents)
- * Empty (one empty document; no height and no width)
- * text "" (a document containing the empty string;
- one line high, but has no width)
--}
-
-
--- | RDoc is a "reduced GDoc", guaranteed not to have a top-level Above or Beside.
-type RDoc = Doc
-
--- | The TextDetails data type
---
--- A TextDetails represents a fragment of text that will be
--- output at some point.
-data TextDetails = Chr {-# UNPACK #-} !Char -- ^ A single Char fragment
- | Str String -- ^ A whole String fragment
- | PStr FastString -- a hashed string
- | ZStr FastZString -- a z-encoded string
- | LStr {-# UNPACK #-} !PtrString
- -- a '\0'-terminated array of bytes
- | RStr {-# UNPACK #-} !Int {-# UNPACK #-} !Char
- -- a repeated character (e.g., ' ')
-
-instance Show Doc where
- showsPrec _ doc cont = fullRender (mode style) (lineLength style)
- (ribbonsPerLine style)
- txtPrinter cont doc
-
-
--- ---------------------------------------------------------------------------
--- Values and Predicates on GDocs and TextDetails
-
--- | A document of height and width 1, containing a literal character.
-char :: Char -> Doc
-char c = textBeside_ (Chr c) 1 Empty
-
--- | A document of height 1 containing a literal string.
--- 'text' satisfies the following laws:
---
--- * @'text' s '<>' 'text' t = 'text' (s'++'t)@
---
--- * @'text' \"\" '<>' x = x@, if @x@ non-empty
---
--- The side condition on the last law is necessary because @'text' \"\"@
--- has height 1, while 'empty' has no height.
-text :: String -> Doc
-text s = textBeside_ (Str s) (length s) Empty
-{-# NOINLINE [0] text #-} -- Give the RULE a chance to fire
- -- It must wait till after phase 1 when
- -- the unpackCString first is manifested
-
--- 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 (mkPtrString# a)
- #-}
-{-# RULES "text/unpackNBytes#"
- forall p n. text (unpackNBytes# p n) = ptext (PtrString (Ptr p) (I# n))
- #-}
-
-ftext :: FastString -> Doc
-ftext s = textBeside_ (PStr s) (lengthFS s) Empty
-
-ptext :: PtrString -> Doc
-ptext s = textBeside_ (LStr s) (lengthPS s) Empty
-
-ztext :: FastZString -> Doc
-ztext s = textBeside_ (ZStr s) (lengthFZS s) Empty
-
--- | Some text with any width. (@text s = sizedText (length s) s@)
-sizedText :: Int -> String -> Doc
-sizedText l s = textBeside_ (Str s) l Empty
-
--- | Some text, but without any width. Use for non-printing text
--- such as a HTML or Latex tags
-zeroWidthText :: String -> Doc
-zeroWidthText = sizedText 0
-
--- | The empty document, with no height and no width.
--- 'empty' is the identity for '<>', '<+>', '$$' and '$+$', and anywhere
--- in the argument list for 'sep', 'hcat', 'hsep', 'vcat', 'fcat' etc.
-empty :: Doc
-empty = Empty
-
--- | Returns 'True' if the document is empty
-isEmpty :: Doc -> Bool
-isEmpty Empty = True
-isEmpty _ = False
-
-{-
-Q: What is the reason for negative indentation (i.e. argument to indent
- is < 0) ?
-
-A:
-This indicates an error in the library client's code.
-If we compose a <> b, and the first line of b is more indented than some
-other lines of b, the law <n6> (<> eats nests) may cause the pretty
-printer to produce an invalid layout:
-
-doc |0123345
-------------------
-d1 |a...|
-d2 |...b|
- |c...|
-
-d1<>d2 |ab..|
- c|....|
-
-Consider a <> b, let `s' be the length of the last line of `a', `k' the
-indentation of the first line of b, and `k0' the indentation of the
-left-most line b_i of b.
-
-The produced layout will have negative indentation if `k - k0 > s', as
-the first line of b will be put on the (s+1)th column, effectively
-translating b horizontally by (k-s). Now if the i^th line of b has an
-indentation k0 < (k-s), it is translated out-of-page, causing
-`negative indentation'.
--}
-
-
-semi :: Doc -- ^ A ';' character
-comma :: Doc -- ^ A ',' character
-colon :: Doc -- ^ A ':' character
-space :: Doc -- ^ A space character
-equals :: Doc -- ^ A '=' character
-lparen :: Doc -- ^ A '(' character
-rparen :: Doc -- ^ A ')' character
-lbrack :: Doc -- ^ A '[' character
-rbrack :: Doc -- ^ A ']' character
-lbrace :: Doc -- ^ A '{' character
-rbrace :: Doc -- ^ A '}' character
-semi = char ';'
-comma = char ','
-colon = char ':'
-space = char ' '
-equals = char '='
-lparen = char '('
-rparen = char ')'
-lbrack = char '['
-rbrack = char ']'
-lbrace = char '{'
-rbrace = char '}'
-
-spaceText, nlText :: TextDetails
-spaceText = Chr ' '
-nlText = Chr '\n'
-
-int :: Int -> Doc -- ^ @int n = text (show n)@
-integer :: Integer -> Doc -- ^ @integer n = text (show n)@
-float :: Float -> Doc -- ^ @float n = text (show n)@
-double :: Double -> Doc -- ^ @double n = text (show n)@
-rational :: Rational -> Doc -- ^ @rational n = text (show n)@
-hex :: Integer -> Doc -- ^ See Note [Print Hexadecimal Literals]
-int n = text (show n)
-integer n = text (show n)
-float n = text (show n)
-double n = text (show n)
-rational n = text (show n)
-hex n = text ('0' : 'x' : padded)
- where
- str = showHex n ""
- strLen = max 1 (length str)
- len = 2 ^ (ceiling (logBase 2 (fromIntegral strLen :: Double)) :: Int)
- padded = replicate (len - strLen) '0' ++ str
-
-parens :: Doc -> Doc -- ^ Wrap document in @(...)@
-brackets :: Doc -> Doc -- ^ Wrap document in @[...]@
-braces :: Doc -> Doc -- ^ Wrap document in @{...}@
-quotes :: Doc -> Doc -- ^ Wrap document in @\'...\'@
-quote :: Doc -> Doc
-doubleQuotes :: Doc -> Doc -- ^ Wrap document in @\"...\"@
-quotes p = char '`' <> p <> char '\''
-quote p = char '\'' <> p
-doubleQuotes p = char '"' <> p <> char '"'
-parens p = char '(' <> p <> char ')'
-brackets p = char '[' <> p <> char ']'
-braces p = char '{' <> p <> char '}'
-
-{-
-Note [Print Hexadecimal Literals]
-
-Relevant discussions:
- * Phabricator: https://phabricator.haskell.org/D4465
- * GHC Trac: https://gitlab.haskell.org/ghc/ghc/issues/14872
-
-There is a flag `-dword-hex-literals` that causes literals of
-type `Word#` or `Word64#` to be displayed in hexadecimal instead
-of decimal when dumping GHC core. It also affects the presentation
-of these in GHC's error messages. Additionally, the hexadecimal
-encoding of these numbers is zero-padded so that its length is
-a power of two. As an example of what this does,
-consider the following haskell file `Literals.hs`:
-
- module Literals where
-
- alpha :: Int
- alpha = 100 + 200
-
- beta :: Word -> Word
- beta x = x + div maxBound 255 + div 0xFFFFFFFF 255 + 0x0202
-
-We get the following dumped core when we compile on a 64-bit
-machine with ghc -O2 -fforce-recomp -ddump-simpl -dsuppress-all
--dhex-word-literals literals.hs:
-
- ==================== Tidy Core ====================
-
- ... omitted for brevity ...
-
- -- RHS size: {terms: 2, types: 0, coercions: 0, joins: 0/0}
- alpha
- alpha = I# 300#
-
- -- RHS size: {terms: 12, types: 3, coercions: 0, joins: 0/0}
- beta
- beta
- = \ x_aYE ->
- case x_aYE of { W# x#_a1v0 ->
- W#
- (plusWord#
- (plusWord# (plusWord# x#_a1v0 0x0101010101010101##) 0x01010101##)
- 0x0202##)
- }
-
-Notice that the word literals are in hexadecimals and that they have
-been padded with zeroes so that their lengths are 16, 8, and 4, respectively.
-
--}
-
--- | Apply 'parens' to 'Doc' if boolean is true.
-maybeParens :: Bool -> Doc -> Doc
-maybeParens False = id
-maybeParens True = parens
-
--- ---------------------------------------------------------------------------
--- Structural operations on GDocs
-
--- | Perform some simplification of a built up @GDoc@.
-reduceDoc :: Doc -> RDoc
-reduceDoc (Beside p g q) = p `seq` g `seq` (beside p g $! reduceDoc q)
-reduceDoc (Above p g q) = p `seq` g `seq` (above p g $! reduceDoc q)
-reduceDoc p = p
-
--- | List version of '<>'.
-hcat :: [Doc] -> Doc
-hcat = reduceAB . foldr (beside_' False) empty
-
--- | List version of '<+>'.
-hsep :: [Doc] -> Doc
-hsep = reduceAB . foldr (beside_' True) empty
-
--- | List version of '$$'.
-vcat :: [Doc] -> Doc
-vcat = reduceAB . foldr (above_' False) empty
-
--- | Nest (or indent) a document by a given number of positions
--- (which may also be negative). 'nest' satisfies the laws:
---
--- * @'nest' 0 x = x@
---
--- * @'nest' k ('nest' k' x) = 'nest' (k+k') x@
---
--- * @'nest' k (x '<>' y) = 'nest' k z '<>' 'nest' k y@
---
--- * @'nest' k (x '$$' y) = 'nest' k x '$$' 'nest' k y@
---
--- * @'nest' k 'empty' = 'empty'@
---
--- * @x '<>' 'nest' k y = x '<>' y@, if @x@ non-empty
---
--- The side condition on the last law is needed because
--- 'empty' is a left identity for '<>'.
-nest :: Int -> Doc -> Doc
-nest k p = mkNest k (reduceDoc p)
-
--- | @hang d1 n d2 = sep [d1, nest n d2]@
-hang :: Doc -> Int -> Doc -> Doc
-hang d1 n d2 = sep [d1, nest n d2]
-
--- | Apply 'hang' to the arguments if the first 'Doc' is not empty.
-hangNotEmpty :: Doc -> Int -> Doc -> Doc
-hangNotEmpty d1 n d2 = if isEmpty d1
- then d2
- else hang d1 n d2
-
--- | @punctuate p [d1, ... dn] = [d1 \<> p, d2 \<> p, ... dn-1 \<> p, dn]@
-punctuate :: Doc -> [Doc] -> [Doc]
-punctuate _ [] = []
-punctuate p (x:xs) = go x xs
- where go y [] = [y]
- go y (z:zs) = (y <> p) : go z zs
-
--- mkNest checks for Nest's invariant that it doesn't have an Empty inside it
-mkNest :: Int -> Doc -> Doc
-mkNest k _ | k `seq` False = undefined
-mkNest k (Nest k1 p) = mkNest (k + k1) p
-mkNest _ NoDoc = NoDoc
-mkNest _ Empty = Empty
-mkNest 0 p = p
-mkNest k p = nest_ k p
-
--- mkUnion checks for an empty document
-mkUnion :: Doc -> Doc -> Doc
-mkUnion Empty _ = Empty
-mkUnion p q = p `union_` q
-
-beside_' :: Bool -> Doc -> Doc -> Doc
-beside_' _ p Empty = p
-beside_' g p q = Beside p g q
-
-above_' :: Bool -> Doc -> Doc -> Doc
-above_' _ p Empty = p
-above_' g p q = Above p g q
-
-reduceAB :: Doc -> Doc
-reduceAB (Above Empty _ q) = q
-reduceAB (Beside Empty _ q) = q
-reduceAB doc = doc
-
-nilAbove_ :: RDoc -> RDoc
-nilAbove_ = NilAbove
-
--- Arg of a TextBeside is always an RDoc
-textBeside_ :: TextDetails -> Int -> RDoc -> RDoc
-textBeside_ = TextBeside
-
-nest_ :: Int -> RDoc -> RDoc
-nest_ = Nest
-
-union_ :: RDoc -> RDoc -> RDoc
-union_ = Union
-
-
--- ---------------------------------------------------------------------------
--- Vertical composition @$$@
-
--- | Above, except that if the last line of the first argument stops
--- at least one position before the first line of the second begins,
--- these two lines are overlapped. For example:
---
--- > text "hi" $$ nest 5 (text "there")
---
--- lays out as
---
--- > hi there
---
--- rather than
---
--- > hi
--- > there
---
--- '$$' is associative, with identity 'empty', and also satisfies
---
--- * @(x '$$' y) '<>' z = x '$$' (y '<>' z)@, if @y@ non-empty.
---
-($$) :: Doc -> Doc -> Doc
-p $$ q = above_ p False q
-
--- | Above, with no overlapping.
--- '$+$' is associative, with identity 'empty'.
-($+$) :: Doc -> Doc -> Doc
-p $+$ q = above_ p True q
-
-above_ :: Doc -> Bool -> Doc -> Doc
-above_ p _ Empty = p
-above_ Empty _ q = q
-above_ p g q = Above p g q
-
-above :: Doc -> Bool -> RDoc -> RDoc
-above (Above p g1 q1) g2 q2 = above p g1 (above q1 g2 q2)
-above p@(Beside{}) g q = aboveNest (reduceDoc p) g 0 (reduceDoc q)
-above p g q = aboveNest p g 0 (reduceDoc q)
-
--- Specification: aboveNest p g k q = p $g$ (nest k q)
-aboveNest :: RDoc -> Bool -> Int -> RDoc -> RDoc
-aboveNest _ _ k _ | k `seq` False = undefined
-aboveNest NoDoc _ _ _ = NoDoc
-aboveNest (p1 `Union` p2) g k q = aboveNest p1 g k q `union_`
- aboveNest p2 g k q
-
-aboveNest Empty _ k q = mkNest k q
-aboveNest (Nest k1 p) g k q = nest_ k1 (aboveNest p g (k - k1) q)
- -- p can't be Empty, so no need for mkNest
-
-aboveNest (NilAbove p) g k q = nilAbove_ (aboveNest p g k q)
-aboveNest (TextBeside s sl p) g k q = textBeside_ s sl rest
- where
- !k1 = k - sl
- rest = case p of
- Empty -> nilAboveNest g k1 q
- _ -> aboveNest p g k1 q
-aboveNest (Above {}) _ _ _ = error "aboveNest Above"
-aboveNest (Beside {}) _ _ _ = error "aboveNest Beside"
-
--- Specification: text s <> nilaboveNest g k q
--- = text s <> (text "" $g$ nest k q)
-nilAboveNest :: Bool -> Int -> RDoc -> RDoc
-nilAboveNest _ k _ | k `seq` False = undefined
-nilAboveNest _ _ Empty = Empty
- -- Here's why the "text s <>" is in the spec!
-nilAboveNest g k (Nest k1 q) = nilAboveNest g (k + k1) q
-nilAboveNest g k q | not g && k > 0 -- No newline if no overlap
- = textBeside_ (RStr k ' ') k q
- | otherwise -- Put them really above
- = nilAbove_ (mkNest k q)
-
-
--- ---------------------------------------------------------------------------
--- Horizontal composition @<>@
-
--- We intentionally avoid Data.Monoid.(<>) here due to interactions of
--- Data.Monoid.(<>) and (<+>). See
--- http://www.haskell.org/pipermail/libraries/2011-November/017066.html
-
--- | Beside.
--- '<>' is associative, with identity 'empty'.
-(<>) :: Doc -> Doc -> Doc
-p <> q = beside_ p False q
-
--- | Beside, separated by space, unless one of the arguments is 'empty'.
--- '<+>' is associative, with identity 'empty'.
-(<+>) :: Doc -> Doc -> Doc
-p <+> q = beside_ p True q
-
-beside_ :: Doc -> Bool -> Doc -> Doc
-beside_ p _ Empty = p
-beside_ Empty _ q = q
-beside_ p g q = Beside p g q
-
--- Specification: beside g p q = p <g> q
-beside :: Doc -> Bool -> RDoc -> RDoc
-beside NoDoc _ _ = NoDoc
-beside (p1 `Union` p2) g q = beside p1 g q `union_` beside p2 g q
-beside Empty _ q = q
-beside (Nest k p) g q = nest_ k $! beside p g q
-beside p@(Beside p1 g1 q1) g2 q2
- | g1 == g2 = beside p1 g1 $! beside q1 g2 q2
- | otherwise = beside (reduceDoc p) g2 q2
-beside p@(Above{}) g q = let !d = reduceDoc p in 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
- _ -> beside p g q
-
--- Specification: text "" <> nilBeside g p
--- = text "" <g> p
-nilBeside :: Bool -> RDoc -> RDoc
-nilBeside _ Empty = Empty -- Hence the text "" in the spec
-nilBeside g (Nest _ p) = nilBeside g p
-nilBeside g p | g = textBeside_ spaceText 1 p
- | otherwise = p
-
-
--- ---------------------------------------------------------------------------
--- Separate, @sep@
-
--- Specification: sep ps = oneLiner (hsep ps)
--- `union`
--- vcat ps
-
--- | Either 'hsep' or 'vcat'.
-sep :: [Doc] -> Doc
-sep = sepX True -- Separate with spaces
-
--- | Either 'hcat' or 'vcat'.
-cat :: [Doc] -> Doc
-cat = sepX False -- Don't
-
-sepX :: Bool -> [Doc] -> Doc
-sepX _ [] = empty
-sepX x (p:ps) = sep1 x (reduceDoc p) 0 ps
-
-
--- Specification: sep1 g k ys = sep (x : map (nest k) ys)
--- = oneLiner (x <g> nest k (hsep ys))
--- `union` x $$ nest k (vcat ys)
-sep1 :: Bool -> RDoc -> Int -> [Doc] -> RDoc
-sep1 _ _ k _ | k `seq` False = undefined
-sep1 _ NoDoc _ _ = NoDoc
-sep1 g (p `Union` q) k ys = sep1 g p k ys `union_`
- aboveNest q False k (reduceDoc (vcat ys))
-
-sep1 g Empty k ys = mkNest k (sepX g ys)
-sep1 g (Nest n p) k ys = nest_ n (sep1 g p (k - n) ys)
-
-sep1 _ (NilAbove p) k ys = nilAbove_
- (aboveNest p False k (reduceDoc (vcat ys)))
-sep1 g (TextBeside s sl p) k ys = textBeside_ s sl (sepNB g p (k - sl) ys)
-sep1 _ (Above {}) _ _ = error "sep1 Above"
-sep1 _ (Beside {}) _ _ = error "sep1 Beside"
-
--- Specification: sepNB p k ys = sep1 (text "" <> p) k ys
--- Called when we have already found some text in the first item
--- We have to eat up nests
-sepNB :: Bool -> Doc -> Int -> [Doc] -> Doc
-sepNB g (Nest _ p) k ys
- = sepNB g p k ys -- Never triggered, because of invariant (2)
-sepNB g Empty k ys
- = oneLiner (nilBeside g (reduceDoc rest)) `mkUnion`
- -- XXX: TODO: PRETTY: Used to use True here (but GHC used False...)
- nilAboveNest False k (reduceDoc (vcat ys))
- where
- rest | g = hsep ys
- | otherwise = hcat ys
-sepNB g p k ys
- = sep1 g p k ys
-
-
--- ---------------------------------------------------------------------------
--- @fill@
-
--- | \"Paragraph fill\" version of 'cat'.
-fcat :: [Doc] -> Doc
-fcat = fill False
-
--- | \"Paragraph fill\" version of 'sep'.
-fsep :: [Doc] -> Doc
-fsep = fill True
-
--- Specification:
---
--- fill g docs = fillIndent 0 docs
---
--- fillIndent k [] = []
--- fillIndent k [p] = p
--- fillIndent k (p1:p2:ps) =
--- oneLiner p1 <g> fillIndent (k + length p1 + g ? 1 : 0)
--- (remove_nests (oneLiner p2) : ps)
--- `Union`
--- (p1 $*$ nest (-k) (fillIndent 0 ps))
---
--- $*$ is defined for layouts (not Docs) as
--- layout1 $*$ layout2 | hasMoreThanOneLine layout1 = layout1 $$ layout2
--- | otherwise = layout1 $+$ layout2
-
-fill :: Bool -> [Doc] -> RDoc
-fill _ [] = empty
-fill g (p:ps) = fill1 g (reduceDoc p) 0 ps
-
-fill1 :: Bool -> RDoc -> Int -> [Doc] -> Doc
-fill1 _ _ k _ | k `seq` False = undefined
-fill1 _ NoDoc _ _ = NoDoc
-fill1 g (p `Union` q) k ys = fill1 g p k ys `union_`
- aboveNest q False k (fill g ys)
-fill1 g Empty k ys = mkNest k (fill g ys)
-fill1 g (Nest n p) k ys = nest_ n (fill1 g p (k - n) ys)
-fill1 g (NilAbove p) k ys = nilAbove_ (aboveNest p False k (fill g ys))
-fill1 g (TextBeside s sl p) k ys = textBeside_ s sl (fillNB g p (k - sl) ys)
-fill1 _ (Above {}) _ _ = error "fill1 Above"
-fill1 _ (Beside {}) _ _ = error "fill1 Beside"
-
-fillNB :: Bool -> Doc -> Int -> [Doc] -> Doc
-fillNB _ _ k _ | k `seq` False = undefined
-fillNB g (Nest _ p) k ys = fillNB g p k ys
- -- Never triggered, because of invariant (2)
-fillNB _ Empty _ [] = Empty
-fillNB g Empty k (Empty:ys) = fillNB g Empty k ys
-fillNB g Empty k (y:ys) = fillNBE g k y ys
-fillNB g p k ys = fill1 g p k ys
-
-
-fillNBE :: Bool -> Int -> Doc -> [Doc] -> Doc
-fillNBE g k y ys
- = nilBeside g (fill1 g ((elideNest . oneLiner . reduceDoc) y) k' ys)
- -- XXX: TODO: PRETTY: Used to use True here (but GHC used False...)
- `mkUnion` nilAboveNest False k (fill g (y:ys))
- where k' = if g then k - 1 else k
-
-elideNest :: Doc -> Doc
-elideNest (Nest _ d) = d
-elideNest d = d
-
--- ---------------------------------------------------------------------------
--- Selecting the best layout
-
-best :: Int -- Line length
- -> Int -- Ribbon length
- -> RDoc
- -> RDoc -- No unions in here!
-best w0 r = get w0
- where
- get :: Int -- (Remaining) width of line
- -> Doc -> Doc
- get w _ | w == 0 && False = undefined
- get _ Empty = Empty
- get _ NoDoc = NoDoc
- get w (NilAbove p) = nilAbove_ (get w p)
- get w (TextBeside s sl p) = textBeside_ s sl (get1 w sl p)
- get w (Nest k p) = nest_ k (get (w - k) p)
- get w (p `Union` q) = nicest w r (get w p) (get w q)
- get _ (Above {}) = error "best get Above"
- get _ (Beside {}) = error "best get Beside"
-
- get1 :: Int -- (Remaining) width of line
- -> Int -- Amount of first line already eaten up
- -> Doc -- This is an argument to TextBeside => eat Nests
- -> Doc -- No unions in here!
-
- get1 w _ _ | w == 0 && False = undefined
- get1 _ _ Empty = Empty
- get1 _ _ NoDoc = NoDoc
- get1 w sl (NilAbove p) = nilAbove_ (get (w - sl) p)
- get1 w sl (TextBeside t tl p) = textBeside_ t tl (get1 w (sl + tl) p)
- get1 w sl (Nest _ p) = get1 w sl p
- get1 w sl (p `Union` q) = nicest1 w r sl (get1 w sl p)
- (get1 w sl q)
- get1 _ _ (Above {}) = error "best get1 Above"
- get1 _ _ (Beside {}) = error "best get1 Beside"
-
-nicest :: Int -> Int -> Doc -> Doc -> Doc
-nicest !w !r = nicest1 w r 0
-
-nicest1 :: Int -> Int -> Int -> Doc -> Doc -> Doc
-nicest1 !w !r !sl p q | fits ((w `min` r) - sl) p = p
- | otherwise = q
-
-fits :: Int -- Space available
- -> Doc
- -> Bool -- True if *first line* of Doc fits in space available
-fits n _ | n < 0 = False
-fits _ NoDoc = False
-fits _ Empty = True
-fits _ (NilAbove _) = True
-fits n (TextBeside _ sl p) = fits (n - sl) p
-fits _ (Above {}) = error "fits Above"
-fits _ (Beside {}) = error "fits Beside"
-fits _ (Union {}) = error "fits Union"
-fits _ (Nest {}) = error "fits Nest"
-
--- | @first@ returns its first argument if it is non-empty, otherwise its second.
-first :: Doc -> Doc -> Doc
-first p q | nonEmptySet p = p -- unused, because (get OneLineMode) is unused
- | otherwise = q
-
-nonEmptySet :: Doc -> Bool
-nonEmptySet NoDoc = False
-nonEmptySet (_ `Union` _) = True
-nonEmptySet Empty = True
-nonEmptySet (NilAbove _) = True
-nonEmptySet (TextBeside _ _ p) = nonEmptySet p
-nonEmptySet (Nest _ p) = nonEmptySet p
-nonEmptySet (Above {}) = error "nonEmptySet Above"
-nonEmptySet (Beside {}) = error "nonEmptySet Beside"
-
--- @oneLiner@ returns the one-line members of the given set of @GDoc@s.
-oneLiner :: Doc -> Doc
-oneLiner NoDoc = NoDoc
-oneLiner Empty = Empty
-oneLiner (NilAbove _) = NoDoc
-oneLiner (TextBeside s sl p) = textBeside_ s sl (oneLiner p)
-oneLiner (Nest k p) = nest_ k (oneLiner p)
-oneLiner (p `Union` _) = oneLiner p
-oneLiner (Above {}) = error "oneLiner Above"
-oneLiner (Beside {}) = error "oneLiner Beside"
-
-
--- ---------------------------------------------------------------------------
--- Rendering
-
--- | A rendering style.
-data Style
- = Style { mode :: Mode -- ^ The rendering mode
- , lineLength :: Int -- ^ Length of line, in chars
- , ribbonsPerLine :: Float -- ^ Ratio of line length to ribbon length
- }
-
--- | The default style (@mode=PageMode, lineLength=100, ribbonsPerLine=1.5@).
-style :: Style
-style = Style { lineLength = 100, ribbonsPerLine = 1.5, mode = PageMode }
-
--- | Rendering mode.
-data Mode = PageMode -- ^ Normal
- | ZigZagMode -- ^ With zig-zag cuts
- | LeftMode -- ^ No indentation, infinitely long lines
- | OneLineMode -- ^ All on one line
-
--- | Render the @Doc@ to a String using the given @Style@.
-renderStyle :: Style -> Doc -> String
-renderStyle s = fullRender (mode s) (lineLength s) (ribbonsPerLine s)
- txtPrinter ""
-
--- | Default TextDetails printer
-txtPrinter :: TextDetails -> String -> String
-txtPrinter (Chr c) s = c:s
-txtPrinter (Str s1) s2 = s1 ++ s2
-txtPrinter (PStr s1) s2 = unpackFS s1 ++ s2
-txtPrinter (ZStr s1) s2 = zString s1 ++ s2
-txtPrinter (LStr s1) s2 = unpackPtrString s1 ++ s2
-txtPrinter (RStr n c) s2 = replicate n c ++ s2
-
--- | The general rendering interface.
-fullRender :: Mode -- ^ Rendering mode
- -> Int -- ^ Line length
- -> Float -- ^ Ribbons per line
- -> (TextDetails -> a -> a) -- ^ What to do with text
- -> a -- ^ What to do at the end
- -> Doc -- ^ The document
- -> a -- ^ Result
-fullRender OneLineMode _ _ txt end doc
- = easyDisplay spaceText (\_ y -> y) txt end (reduceDoc doc)
-fullRender LeftMode _ _ txt end doc
- = easyDisplay nlText first txt end (reduceDoc doc)
-
-fullRender m lineLen ribbons txt rest doc
- = display m lineLen ribbonLen txt rest doc'
- where
- doc' = best bestLineLen ribbonLen (reduceDoc doc)
-
- bestLineLen, ribbonLen :: Int
- ribbonLen = round (fromIntegral lineLen / ribbons)
- bestLineLen = case m of
- ZigZagMode -> maxBound
- _ -> lineLen
-
-easyDisplay :: TextDetails
- -> (Doc -> Doc -> Doc)
- -> (TextDetails -> a -> a)
- -> a
- -> Doc
- -> a
-easyDisplay nlSpaceText choose txt end
- = lay
- where
- lay NoDoc = error "easyDisplay: NoDoc"
- lay (Union p q) = lay (choose p q)
- lay (Nest _ p) = lay p
- lay Empty = end
- lay (NilAbove p) = nlSpaceText `txt` lay p
- lay (TextBeside s _ p) = s `txt` lay p
- lay (Above {}) = error "easyDisplay Above"
- lay (Beside {}) = error "easyDisplay Beside"
-
-display :: Mode -> Int -> Int -> (TextDetails -> a -> a) -> a -> Doc -> a
-display m !page_width !ribbon_width txt end doc
- = case page_width - ribbon_width of { gap_width ->
- case gap_width `quot` 2 of { shift ->
- let
- lay k _ | k `seq` False = undefined
- lay k (Nest k1 p) = lay (k + k1) p
- lay _ Empty = end
- lay k (NilAbove p) = nlText `txt` lay k p
- lay k (TextBeside s sl p)
- = case m of
- ZigZagMode | k >= gap_width
- -> nlText `txt` (
- Str (replicate shift '/') `txt` (
- nlText `txt`
- lay1 (k - shift) s sl p ))
-
- | k < 0
- -> nlText `txt` (
- Str (replicate shift '\\') `txt` (
- nlText `txt`
- lay1 (k + shift) s sl p ))
-
- _ -> lay1 k s sl p
- lay _ (Above {}) = error "display lay Above"
- lay _ (Beside {}) = error "display lay Beside"
- lay _ NoDoc = error "display lay NoDoc"
- lay _ (Union {}) = error "display lay Union"
-
- lay1 !k s !sl p = let !r = k + sl
- in indent k (s `txt` lay2 r p)
-
- lay2 k _ | k `seq` False = undefined
- lay2 k (NilAbove p) = nlText `txt` lay k p
- lay2 k (TextBeside s sl p) = s `txt` lay2 (k + sl) p
- lay2 k (Nest _ p) = lay2 k p
- lay2 _ Empty = end
- lay2 _ (Above {}) = error "display lay2 Above"
- lay2 _ (Beside {}) = error "display lay2 Beside"
- lay2 _ NoDoc = error "display lay2 NoDoc"
- lay2 _ (Union {}) = error "display lay2 Union"
-
- indent !n r = RStr n ' ' `txt` r
- in
- lay 0 doc
- }}
-
-printDoc :: Mode -> Int -> Handle -> Doc -> IO ()
--- printDoc adds a newline to the end
-printDoc mode cols hdl doc = printDoc_ mode cols hdl (doc $$ text "")
-
-printDoc_ :: Mode -> Int -> Handle -> Doc -> IO ()
--- printDoc_ does not add a newline at the end, so that
--- successive calls can output stuff on the same line
--- Rather like putStr vs putStrLn
-printDoc_ LeftMode _ hdl doc
- = do { printLeftRender hdl doc; hFlush hdl }
-printDoc_ mode pprCols hdl 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
- put (PStr s) next = hPutStr hdl (unpackFS s) >> next
- -- NB. not hPutFS, we want this to go through
- -- the I/O library's encoding layer. (#3398)
- put (ZStr s) next = hPutFZS hdl s >> next
- put (LStr s) next = hPutPtrString hdl s >> next
- put (RStr n c) next = hPutStr hdl (replicate n c) >> next
-
- done = return () -- hPutChar hdl '\n'
-
- -- some versions of hPutBuf will barf if the length is zero
-hPutPtrString :: Handle -> PtrString -> IO ()
-hPutPtrString _handle (PtrString _ 0) = return ()
-hPutPtrString handle (PtrString a l) = hPutBuf handle a l
-
--- 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.
-
-printLeftRender :: Handle -> Doc -> IO ()
-printLeftRender hdl doc = do
- b <- newBufHandle hdl
- bufLeftRender b doc
- bFlush b
-
-bufLeftRender :: BufHandle -> Doc -> IO ()
-bufLeftRender b doc = layLeft b (reduceDoc doc)
-
-layLeft :: BufHandle -> Doc -> IO ()
-layLeft b _ | b `seq` False = undefined -- make it strict in b
-layLeft _ NoDoc = error "layLeft: NoDoc"
-layLeft b (Union p q) = layLeft b $! first p q
-layLeft b (Nest _ p) = layLeft b $! p
-layLeft b Empty = bPutChar b '\n'
-layLeft b (NilAbove p) = p `seq` (bPutChar b '\n' >> layLeft b p)
-layLeft b (TextBeside s _ p) = s `seq` (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 (ZStr s) = bPutFZS b s
- put b (LStr s) = bPutPtrString b s
- put b (RStr n c) = bPutReplicate b n c
-layLeft _ _ = panic "layLeft: Unhandled case"
-
--- Define error=panic, for easier comparison with libraries/pretty.
-error :: String -> a
-error = panic
diff --git a/compiler/utils/State.hs b/compiler/utils/State.hs
deleted file mode 100644
index 92269e91e7..0000000000
--- a/compiler/utils/State.hs
+++ /dev/null
@@ -1,46 +0,0 @@
-{-# LANGUAGE DeriveFunctor #-}
-{-# LANGUAGE UnboxedTuples #-}
-
-module State where
-
-import GhcPrelude
-
-newtype State s a = State { runState' :: s -> (# a, s #) }
- deriving (Functor)
-
-instance Applicative (State s) where
- pure x = State $ \s -> (# x, s #)
- m <*> n = State $ \s -> case runState' m s of
- (# f, s' #) -> case runState' n s' of
- (# x, s'' #) -> (# f x, s'' #)
-
-instance Monad (State s) where
- m >>= n = State $ \s -> case runState' m s of
- (# r, s' #) -> runState' (n r) s'
-
-get :: State s s
-get = State $ \s -> (# s, s #)
-
-gets :: (s -> a) -> State s a
-gets f = State $ \s -> (# f s, s #)
-
-put :: s -> State s ()
-put s' = State $ \_ -> (# (), s' #)
-
-modify :: (s -> s) -> State s ()
-modify f = State $ \s -> (# (), f s #)
-
-
-evalState :: State s a -> s -> a
-evalState s i = case runState' s i of
- (# a, _ #) -> a
-
-
-execState :: State s a -> s -> s
-execState s i = case runState' s i of
- (# _, s' #) -> s'
-
-
-runState :: State s a -> s -> (a, s)
-runState s i = case runState' s i of
- (# a, s' #) -> (a, s')
diff --git a/compiler/utils/Stream.hs b/compiler/utils/Stream.hs
deleted file mode 100644
index 7eabbe1958..0000000000
--- a/compiler/utils/Stream.hs
+++ /dev/null
@@ -1,135 +0,0 @@
--- -----------------------------------------------------------------------------
---
--- (c) The University of Glasgow 2012
---
--- Monadic streams
---
--- -----------------------------------------------------------------------------
-module Stream (
- Stream(..), yield, liftIO,
- collect, collect_, consume, fromList,
- Stream.map, Stream.mapM, Stream.mapAccumL, Stream.mapAccumL_
- ) where
-
-import GhcPrelude
-
-import Control.Monad
-
--- |
--- @Stream m a b@ is a computation in some Monad @m@ that delivers a sequence
--- of elements of type @a@ followed by a result of type @b@.
---
--- More concretely, a value of type @Stream m a b@ can be run using @runStream@
--- in the Monad @m@, and it delivers either
---
--- * the final result: @Left b@, or
--- * @Right (a,str)@, where @a@ is the next element in the stream, and @str@
--- is a computation to get the rest of the stream.
---
--- Stream is itself a Monad, and provides an operation 'yield' that
--- produces a new element of the stream. This makes it convenient to turn
--- existing monadic computations into streams.
---
--- The idea is that Stream is useful for making a monadic computation
--- that produces values from time to time. This can be used for
--- knitting together two complex monadic operations, so that the
--- producer does not have to produce all its values before the
--- consumer starts consuming them. We make the producer into a
--- Stream, and the consumer pulls on the stream each time it wants a
--- new value.
---
-newtype Stream m a b = Stream { runStream :: m (Either b (a, Stream m a b)) }
-
-instance Monad f => Functor (Stream f a) where
- fmap = liftM
-
-instance Monad m => Applicative (Stream m a) where
- pure a = Stream (return (Left a))
- (<*>) = ap
-
-instance Monad m => Monad (Stream m a) where
-
- Stream m >>= k = Stream $ do
- r <- m
- case r of
- Left b -> runStream (k b)
- Right (a,str) -> return (Right (a, str >>= k))
-
-yield :: Monad m => a -> Stream m a ()
-yield a = Stream (return (Right (a, return ())))
-
-liftIO :: IO a -> Stream IO b a
-liftIO io = Stream $ io >>= return . Left
-
--- | Turn a Stream into an ordinary list, by demanding all the elements.
-collect :: Monad m => Stream m a () -> m [a]
-collect str = go str []
- where
- go str acc = do
- r <- runStream str
- case r of
- Left () -> return (reverse acc)
- Right (a, str') -> go str' (a:acc)
-
--- | Turn a Stream into an ordinary list, by demanding all the elements.
-collect_ :: Monad m => Stream m a r -> m ([a], r)
-collect_ str = go str []
- where
- go str acc = do
- r <- runStream str
- case r of
- Left r -> return (reverse acc, r)
- Right (a, str') -> go str' (a:acc)
-
-consume :: Monad m => Stream m a b -> (a -> m ()) -> m b
-consume str f = do
- r <- runStream str
- case r of
- Left ret -> return ret
- Right (a, str') -> do
- f a
- consume str' f
-
--- | Turn a list into a 'Stream', by yielding each element in turn.
-fromList :: Monad m => [a] -> Stream m a ()
-fromList = mapM_ yield
-
--- | Apply a function to each element of a 'Stream', lazily
-map :: Monad m => (a -> b) -> Stream m a x -> Stream m b x
-map f str = Stream $ do
- r <- runStream str
- case r of
- Left x -> return (Left x)
- Right (a, str') -> return (Right (f a, Stream.map f str'))
-
--- | Apply a monadic operation to each element of a 'Stream', lazily
-mapM :: Monad m => (a -> m b) -> Stream m a x -> Stream m b x
-mapM f str = Stream $ do
- r <- runStream str
- case r of
- Left x -> return (Left x)
- Right (a, str') -> do
- b <- f a
- return (Right (b, Stream.mapM f str'))
-
--- | analog of the list-based 'mapAccumL' on Streams. This is a simple
--- way to map over a Stream while carrying some state around.
-mapAccumL :: Monad m => (c -> a -> m (c,b)) -> c -> Stream m a ()
- -> Stream m b c
-mapAccumL f c str = Stream $ do
- r <- runStream str
- case r of
- Left () -> return (Left c)
- Right (a, str') -> do
- (c',b) <- f c a
- return (Right (b, mapAccumL f c' str'))
-
-mapAccumL_ :: Monad m => (c -> a -> m (c,b)) -> c -> Stream m a r
- -> Stream m b (c, r)
-mapAccumL_ f c str = Stream $ do
- r <- runStream str
- case r of
- Left r -> return (Left (c, r))
- Right (a, str') -> do
- (c',b) <- f c a
- return (Right (b, mapAccumL_ f c' str'))
diff --git a/compiler/utils/StringBuffer.hs b/compiler/utils/StringBuffer.hs
deleted file mode 100644
index 91377cad17..0000000000
--- a/compiler/utils/StringBuffer.hs
+++ /dev/null
@@ -1,334 +0,0 @@
-{-
-(c) The University of Glasgow 2006
-(c) The University of Glasgow, 1997-2006
-
-
-Buffers for scanning string input stored in external arrays.
--}
-
-{-# LANGUAGE BangPatterns, CPP, MagicHash, UnboxedTuples #-}
-{-# OPTIONS_GHC -O2 #-}
--- We always optimise this, otherwise performance of a non-optimised
--- compiler is severely affected
-
-module StringBuffer
- (
- StringBuffer(..),
- -- non-abstract for vs\/HaskellService
-
- -- * Creation\/destruction
- hGetStringBuffer,
- hGetStringBufferBlock,
- hPutStringBuffer,
- appendStringBuffers,
- stringToStringBuffer,
-
- -- * Inspection
- nextChar,
- currentChar,
- prevChar,
- atEnd,
-
- -- * Moving and comparison
- stepOn,
- offsetBytes,
- byteDiff,
- atLine,
-
- -- * Conversion
- lexemeToString,
- lexemeToFastString,
- decodePrevNChars,
-
- -- * Parsing integers
- parseUnsignedInteger,
- ) where
-
-#include "HsVersions.h"
-
-import GhcPrelude
-
-import Encoding
-import FastString
-import FastFunctions
-import PlainPanic
-import Util
-
-import Data.Maybe
-import Control.Exception
-import System.IO
-import System.IO.Unsafe ( unsafePerformIO )
-import GHC.IO.Encoding.UTF8 ( mkUTF8 )
-import GHC.IO.Encoding.Failure ( CodingFailureMode(IgnoreCodingFailure) )
-
-import GHC.Exts
-
-import Foreign
-
--- -----------------------------------------------------------------------------
--- The StringBuffer type
-
--- |A StringBuffer is an internal pointer to a sized chunk of bytes.
--- The bytes are intended to be *immutable*. There are pure
--- operations to read the contents of a StringBuffer.
---
--- A StringBuffer may have a finalizer, depending on how it was
--- obtained.
---
-data StringBuffer
- = StringBuffer {
- buf :: {-# UNPACK #-} !(ForeignPtr Word8),
- len :: {-# UNPACK #-} !Int, -- length
- cur :: {-# UNPACK #-} !Int -- current pos
- }
- -- The buffer is assumed to be UTF-8 encoded, and furthermore
- -- we add three @\'\\0\'@ bytes to the end as sentinels so that the
- -- decoder doesn't have to check for overflow at every single byte
- -- of a multibyte sequence.
-
-instance Show StringBuffer where
- showsPrec _ s = showString "<stringbuffer("
- . shows (len s) . showString "," . shows (cur s)
- . showString ")>"
-
--- -----------------------------------------------------------------------------
--- Creation / Destruction
-
--- | Read a file into a 'StringBuffer'. The resulting buffer is automatically
--- managed by the garbage collector.
-hGetStringBuffer :: FilePath -> IO StringBuffer
-hGetStringBuffer fname = do
- h <- openBinaryFile fname ReadMode
- size_i <- hFileSize h
- offset_i <- skipBOM h size_i 0 -- offset is 0 initially
- let size = fromIntegral $ size_i - offset_i
- buf <- mallocForeignPtrArray (size+3)
- withForeignPtr buf $ \ptr -> do
- r <- if size == 0 then return 0 else hGetBuf h ptr size
- hClose h
- if (r /= size)
- then ioError (userError "short read of file")
- else newUTF8StringBuffer buf ptr size
-
-hGetStringBufferBlock :: Handle -> Int -> IO StringBuffer
-hGetStringBufferBlock handle wanted
- = do size_i <- hFileSize handle
- offset_i <- hTell handle >>= skipBOM handle size_i
- let size = min wanted (fromIntegral $ size_i-offset_i)
- buf <- mallocForeignPtrArray (size+3)
- withForeignPtr buf $ \ptr ->
- do r <- if size == 0 then return 0 else hGetBuf handle ptr size
- if r /= size
- then ioError (userError $ "short read of file: "++show(r,size,size_i,handle))
- else newUTF8StringBuffer buf ptr size
-
-hPutStringBuffer :: Handle -> StringBuffer -> IO ()
-hPutStringBuffer hdl (StringBuffer buf len cur)
- = do withForeignPtr (plusForeignPtr buf cur) $ \ptr ->
- hPutBuf hdl ptr len
-
--- | Skip the byte-order mark if there is one (see #1744 and #6016),
--- and return the new position of the handle in bytes.
---
--- This is better than treating #FEFF as whitespace,
--- because that would mess up layout. We don't have a concept
--- of zero-width whitespace in Haskell: all whitespace codepoints
--- have a width of one column.
-skipBOM :: Handle -> Integer -> Integer -> IO Integer
-skipBOM h size offset =
- -- Only skip BOM at the beginning of a file.
- if size > 0 && offset == 0
- then do
- -- Validate assumption that handle is in binary mode.
- ASSERTM( hGetEncoding h >>= return . isNothing )
- -- Temporarily select utf8 encoding with error ignoring,
- -- to make `hLookAhead` and `hGetChar` return full Unicode characters.
- bracket_ (hSetEncoding h safeEncoding) (hSetBinaryMode h True) $ do
- c <- hLookAhead h
- if c == '\xfeff'
- then hGetChar h >> hTell h
- else return offset
- else return offset
- where
- safeEncoding = mkUTF8 IgnoreCodingFailure
-
-newUTF8StringBuffer :: ForeignPtr Word8 -> Ptr Word8 -> Int -> IO StringBuffer
-newUTF8StringBuffer buf ptr size = do
- pokeArray (ptr `plusPtr` size :: Ptr Word8) [0,0,0]
- -- sentinels for UTF-8 decoding
- return $ StringBuffer buf size 0
-
-appendStringBuffers :: StringBuffer -> StringBuffer -> IO StringBuffer
-appendStringBuffers sb1 sb2
- = do newBuf <- mallocForeignPtrArray (size+3)
- withForeignPtr newBuf $ \ptr ->
- withForeignPtr (buf sb1) $ \sb1Ptr ->
- withForeignPtr (buf sb2) $ \sb2Ptr ->
- do copyArray ptr (sb1Ptr `advancePtr` cur sb1) sb1_len
- copyArray (ptr `advancePtr` sb1_len) (sb2Ptr `advancePtr` cur sb2) sb2_len
- pokeArray (ptr `advancePtr` size) [0,0,0]
- return (StringBuffer newBuf size 0)
- where sb1_len = calcLen sb1
- sb2_len = calcLen sb2
- calcLen sb = len sb - cur sb
- size = sb1_len + sb2_len
-
--- | Encode a 'String' into a 'StringBuffer' as UTF-8. The resulting buffer
--- is automatically managed by the garbage collector.
-stringToStringBuffer :: String -> StringBuffer
-stringToStringBuffer str =
- unsafePerformIO $ do
- let size = utf8EncodedLength str
- buf <- mallocForeignPtrArray (size+3)
- withForeignPtr buf $ \ptr -> do
- utf8EncodeString ptr str
- pokeArray (ptr `plusPtr` size :: Ptr Word8) [0,0,0]
- -- sentinels for UTF-8 decoding
- return (StringBuffer buf size 0)
-
--- -----------------------------------------------------------------------------
--- Grab a character
-
--- | Return the first UTF-8 character of a nonempty 'StringBuffer' and as well
--- the remaining portion (analogous to 'Data.List.uncons'). __Warning:__ The
--- behavior is undefined if the 'StringBuffer' is empty. The result shares
--- the same buffer as the original. Similar to 'utf8DecodeChar', if the
--- character cannot be decoded as UTF-8, @\'\\0\'@ is returned.
-{-# INLINE nextChar #-}
-nextChar :: StringBuffer -> (Char,StringBuffer)
-nextChar (StringBuffer buf len (I# cur#)) =
- -- Getting our fingers dirty a little here, but this is performance-critical
- inlinePerformIO $ do
- withForeignPtr buf $ \(Ptr a#) -> do
- case utf8DecodeChar# (a# `plusAddr#` cur#) of
- (# c#, nBytes# #) ->
- let cur' = I# (cur# +# nBytes#) in
- return (C# c#, StringBuffer buf len cur')
-
--- | Return the first UTF-8 character of a nonempty 'StringBuffer' (analogous
--- to 'Data.List.head'). __Warning:__ The behavior is undefined if the
--- 'StringBuffer' is empty. Similar to 'utf8DecodeChar', if the character
--- cannot be decoded as UTF-8, @\'\\0\'@ is returned.
-currentChar :: StringBuffer -> Char
-currentChar = fst . nextChar
-
-prevChar :: StringBuffer -> Char -> Char
-prevChar (StringBuffer _ _ 0) deflt = deflt
-prevChar (StringBuffer buf _ cur) _ =
- inlinePerformIO $ do
- withForeignPtr buf $ \p -> do
- p' <- utf8PrevChar (p `plusPtr` cur)
- return (fst (utf8DecodeChar p'))
-
--- -----------------------------------------------------------------------------
--- Moving
-
--- | Return a 'StringBuffer' with the first UTF-8 character removed (analogous
--- to 'Data.List.tail'). __Warning:__ The behavior is undefined if the
--- 'StringBuffer' is empty. The result shares the same buffer as the
--- original.
-stepOn :: StringBuffer -> StringBuffer
-stepOn s = snd (nextChar s)
-
--- | Return a 'StringBuffer' with the first @n@ bytes removed. __Warning:__
--- If there aren't enough characters, the returned 'StringBuffer' will be
--- invalid and any use of it may lead to undefined behavior. The result
--- shares the same buffer as the original.
-offsetBytes :: Int -- ^ @n@, the number of bytes
- -> StringBuffer
- -> StringBuffer
-offsetBytes i s = s { cur = cur s + i }
-
--- | Compute the difference in offset between two 'StringBuffer's that share
--- the same buffer. __Warning:__ The behavior is undefined if the
--- 'StringBuffer's use separate buffers.
-byteDiff :: StringBuffer -> StringBuffer -> Int
-byteDiff s1 s2 = cur s2 - cur s1
-
--- | Check whether a 'StringBuffer' is empty (analogous to 'Data.List.null').
-atEnd :: StringBuffer -> Bool
-atEnd (StringBuffer _ l c) = l == c
-
--- | Computes a 'StringBuffer' which points to the first character of the
--- wanted line. Lines begin at 1.
-atLine :: Int -> StringBuffer -> Maybe StringBuffer
-atLine line sb@(StringBuffer buf len _) =
- inlinePerformIO $
- withForeignPtr buf $ \p -> do
- p' <- skipToLine line len p
- if p' == nullPtr
- then return Nothing
- else
- let
- delta = p' `minusPtr` p
- in return $ Just (sb { cur = delta
- , len = len - delta
- })
-
-skipToLine :: Int -> Int -> Ptr Word8 -> IO (Ptr Word8)
-skipToLine !line !len !op0 = go 1 op0
- where
- !opend = op0 `plusPtr` len
-
- go !i_line !op
- | op >= opend = pure nullPtr
- | i_line == line = pure op
- | otherwise = do
- w <- peek op :: IO Word8
- case w of
- 10 -> go (i_line + 1) (plusPtr op 1)
- 13 -> do
- -- this is safe because a 'StringBuffer' is
- -- guaranteed to have 3 bytes sentinel values.
- w' <- peek (plusPtr op 1) :: IO Word8
- case w' of
- 10 -> go (i_line + 1) (plusPtr op 2)
- _ -> go (i_line + 1) (plusPtr op 1)
- _ -> go i_line (plusPtr op 1)
-
--- -----------------------------------------------------------------------------
--- Conversion
-
--- | Decode the first @n@ bytes of a 'StringBuffer' as UTF-8 into a 'String'.
--- Similar to 'utf8DecodeChar', if the character cannot be decoded as UTF-8,
--- they will be replaced with @\'\\0\'@.
-lexemeToString :: StringBuffer
- -> Int -- ^ @n@, the number of bytes
- -> String
-lexemeToString _ 0 = ""
-lexemeToString (StringBuffer buf _ cur) bytes =
- utf8DecodeStringLazy buf cur bytes
-
-lexemeToFastString :: StringBuffer
- -> Int -- ^ @n@, the number of bytes
- -> FastString
-lexemeToFastString _ 0 = nilFS
-lexemeToFastString (StringBuffer buf _ cur) len =
- inlinePerformIO $
- withForeignPtr buf $ \ptr ->
- return $! mkFastStringBytes (ptr `plusPtr` cur) len
-
--- | Return the previous @n@ characters (or fewer if we are less than @n@
--- characters into the buffer.
-decodePrevNChars :: Int -> StringBuffer -> String
-decodePrevNChars n (StringBuffer buf _ cur) =
- inlinePerformIO $ withForeignPtr buf $ \p0 ->
- go p0 n "" (p0 `plusPtr` (cur - 1))
- where
- go :: Ptr Word8 -> Int -> String -> Ptr Word8 -> IO String
- go buf0 n acc p | n == 0 || buf0 >= p = return acc
- go buf0 n acc p = do
- p' <- utf8PrevChar p
- let (c,_) = utf8DecodeChar p'
- go buf0 (n - 1) (c:acc) p'
-
--- -----------------------------------------------------------------------------
--- Parsing integer strings in various bases
-parseUnsignedInteger :: StringBuffer -> Int -> Integer -> (Char->Int) -> Integer
-parseUnsignedInteger (StringBuffer buf _ cur) len radix char_to_int
- = inlinePerformIO $ withForeignPtr buf $ \ptr -> return $! let
- go i x | i == len = x
- | otherwise = case fst (utf8DecodeChar (ptr `plusPtr` (cur + i))) of
- '_' -> go (i + 1) x -- skip "_" (#14473)
- char -> go (i + 1) (x * radix + toInteger (char_to_int char))
- in go 0 0
diff --git a/compiler/utils/TrieMap.hs b/compiler/utils/TrieMap.hs
deleted file mode 100644
index 815a060a0c..0000000000
--- a/compiler/utils/TrieMap.hs
+++ /dev/null
@@ -1,406 +0,0 @@
-{-
-(c) The University of Glasgow 2006
-(c) The GRASP/AQUA Project, Glasgow University, 1992-1998
--}
-
-{-# LANGUAGE RankNTypes #-}
-{-# LANGUAGE TypeFamilies #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE TypeSynonymInstances #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE UndecidableInstances #-}
-module TrieMap(
- -- * Maps over 'Maybe' values
- MaybeMap,
- -- * Maps over 'List' values
- ListMap,
- -- * Maps over 'Literal's
- LiteralMap,
- -- * 'TrieMap' class
- TrieMap(..), insertTM, deleteTM,
-
- -- * Things helpful for adding additional Instances.
- (>.>), (|>), (|>>), XT,
- foldMaybe,
- -- * Map for leaf compression
- GenMap,
- lkG, xtG, mapG, fdG,
- xtList, lkList
-
- ) where
-
-import GhcPrelude
-
-import GHC.Types.Literal
-import GHC.Types.Unique.DFM
-import GHC.Types.Unique( Unique )
-
-import qualified Data.Map as Map
-import qualified Data.IntMap as IntMap
-import Outputable
-import Control.Monad( (>=>) )
-import Data.Kind( Type )
-
-{-
-This module implements TrieMaps, which are finite mappings
-whose key is a structured value like a CoreExpr or Type.
-
-This file implements tries over general data structures.
-Implementation for tries over Core Expressions/Types are
-available in GHC.Core.Map.
-
-The regular pattern for handling TrieMaps on data structures was first
-described (to my knowledge) in Connelly and Morris's 1995 paper "A
-generalization of the Trie Data Structure"; there is also an accessible
-description of the idea in Okasaki's book "Purely Functional Data
-Structures", Section 10.3.2
-
-************************************************************************
-* *
- The TrieMap class
-* *
-************************************************************************
--}
-
-type XT a = Maybe a -> Maybe a -- How to alter a non-existent elt (Nothing)
- -- or an existing elt (Just)
-
-class TrieMap m where
- type Key m :: Type
- emptyTM :: m a
- lookupTM :: forall b. Key m -> m b -> Maybe b
- alterTM :: forall b. Key m -> XT b -> m b -> m b
- mapTM :: (a->b) -> m a -> m b
-
- foldTM :: (a -> b -> b) -> m a -> b -> b
- -- The unusual argument order here makes
- -- it easy to compose calls to foldTM;
- -- see for example fdE below
-
-insertTM :: TrieMap m => Key m -> a -> m a -> m a
-insertTM k v m = alterTM k (\_ -> Just v) m
-
-deleteTM :: TrieMap m => Key m -> m a -> m a
-deleteTM k m = alterTM k (\_ -> Nothing) m
-
-----------------------
--- Recall that
--- Control.Monad.(>=>) :: (a -> Maybe b) -> (b -> Maybe c) -> a -> Maybe c
-
-(>.>) :: (a -> b) -> (b -> c) -> a -> c
--- Reverse function composition (do f first, then g)
-infixr 1 >.>
-(f >.> g) x = g (f x)
-infixr 1 |>, |>>
-
-(|>) :: a -> (a->b) -> b -- Reverse application
-x |> f = f x
-
-----------------------
-(|>>) :: TrieMap m2
- => (XT (m2 a) -> m1 (m2 a) -> m1 (m2 a))
- -> (m2 a -> m2 a)
- -> m1 (m2 a) -> m1 (m2 a)
-(|>>) f g = f (Just . g . deMaybe)
-
-deMaybe :: TrieMap m => Maybe (m a) -> m a
-deMaybe Nothing = emptyTM
-deMaybe (Just m) = m
-
-{-
-************************************************************************
-* *
- IntMaps
-* *
-************************************************************************
--}
-
-instance TrieMap IntMap.IntMap where
- type Key IntMap.IntMap = Int
- emptyTM = IntMap.empty
- lookupTM k m = IntMap.lookup k m
- alterTM = xtInt
- foldTM k m z = IntMap.foldr k z m
- mapTM f m = IntMap.map f m
-
-xtInt :: Int -> XT a -> IntMap.IntMap a -> IntMap.IntMap a
-xtInt k f m = IntMap.alter f k m
-
-instance Ord k => TrieMap (Map.Map k) where
- type Key (Map.Map k) = k
- emptyTM = Map.empty
- lookupTM = Map.lookup
- alterTM k f m = Map.alter f k m
- foldTM k m z = Map.foldr k z m
- mapTM f m = Map.map f m
-
-
-{-
-Note [foldTM determinism]
-~~~~~~~~~~~~~~~~~~~~~~~~~
-We want foldTM to be deterministic, which is why we have an instance of
-TrieMap for UniqDFM, but not for UniqFM. Here's an example of some things that
-go wrong if foldTM is nondeterministic. Consider:
-
- f a b = return (a <> b)
-
-Depending on the order that the typechecker generates constraints you
-get either:
-
- f :: (Monad m, Monoid a) => a -> a -> m a
-
-or:
-
- f :: (Monoid a, Monad m) => a -> a -> m a
-
-The generated code will be different after desugaring as the dictionaries
-will be bound in different orders, leading to potential ABI incompatibility.
-
-One way to solve this would be to notice that the typeclasses could be
-sorted alphabetically.
-
-Unfortunately that doesn't quite work with this example:
-
- f a b = let x = a <> a; y = b <> b in x
-
-where you infer:
-
- f :: (Monoid m, Monoid m1) => m1 -> m -> m1
-
-or:
-
- f :: (Monoid m1, Monoid m) => m1 -> m -> m1
-
-Here you could decide to take the order of the type variables in the type
-according to depth first traversal and use it to order the constraints.
-
-The real trouble starts when the user enables incoherent instances and
-the compiler has to make an arbitrary choice. Consider:
-
- class T a b where
- go :: a -> b -> String
-
- instance (Show b) => T Int b where
- go a b = show a ++ show b
-
- instance (Show a) => T a Bool where
- go a b = show a ++ show b
-
- f = go 10 True
-
-GHC is free to choose either dictionary to implement f, but for the sake of
-determinism we'd like it to be consistent when compiling the same sources
-with the same flags.
-
-inert_dicts :: DictMap is implemented with a TrieMap. In getUnsolvedInerts it
-gets converted to a bag of (Wanted) Cts using a fold. Then in
-solve_simple_wanteds it's merged with other WantedConstraints. We want the
-conversion to a bag to be deterministic. For that purpose we use UniqDFM
-instead of UniqFM to implement the TrieMap.
-
-See Note [Deterministic UniqFM] in GHC.Types.Unique.DFM for more details on how it's made
-deterministic.
--}
-
-instance TrieMap UniqDFM where
- type Key UniqDFM = Unique
- emptyTM = emptyUDFM
- lookupTM k m = lookupUDFM m k
- alterTM k f m = alterUDFM f m k
- foldTM k m z = foldUDFM k z m
- mapTM f m = mapUDFM f m
-
-{-
-************************************************************************
-* *
- Maybes
-* *
-************************************************************************
-
-If m is a map from k -> val
-then (MaybeMap m) is a map from (Maybe k) -> val
--}
-
-data MaybeMap m a = MM { mm_nothing :: Maybe a, mm_just :: m a }
-
-instance TrieMap m => TrieMap (MaybeMap m) where
- type Key (MaybeMap m) = Maybe (Key m)
- emptyTM = MM { mm_nothing = Nothing, mm_just = emptyTM }
- lookupTM = lkMaybe lookupTM
- alterTM = xtMaybe alterTM
- foldTM = fdMaybe
- mapTM = mapMb
-
-mapMb :: TrieMap m => (a->b) -> MaybeMap m a -> MaybeMap m b
-mapMb f (MM { mm_nothing = mn, mm_just = mj })
- = MM { mm_nothing = fmap f mn, mm_just = mapTM f mj }
-
-lkMaybe :: (forall b. k -> m b -> Maybe b)
- -> Maybe k -> MaybeMap m a -> Maybe a
-lkMaybe _ Nothing = mm_nothing
-lkMaybe lk (Just x) = mm_just >.> lk x
-
-xtMaybe :: (forall b. k -> XT b -> m b -> m b)
- -> Maybe k -> XT a -> MaybeMap m a -> MaybeMap m a
-xtMaybe _ Nothing f m = m { mm_nothing = f (mm_nothing m) }
-xtMaybe tr (Just x) f m = m { mm_just = mm_just m |> tr x f }
-
-fdMaybe :: TrieMap m => (a -> b -> b) -> MaybeMap m a -> b -> b
-fdMaybe k m = foldMaybe k (mm_nothing m)
- . foldTM k (mm_just m)
-
-{-
-************************************************************************
-* *
- Lists
-* *
-************************************************************************
--}
-
-data ListMap m a
- = LM { lm_nil :: Maybe a
- , lm_cons :: m (ListMap m a) }
-
-instance TrieMap m => TrieMap (ListMap m) where
- type Key (ListMap m) = [Key m]
- emptyTM = LM { lm_nil = Nothing, lm_cons = emptyTM }
- lookupTM = lkList lookupTM
- alterTM = xtList alterTM
- foldTM = fdList
- mapTM = mapList
-
-instance (TrieMap m, Outputable a) => Outputable (ListMap m a) where
- ppr m = text "List elts" <+> ppr (foldTM (:) m [])
-
-mapList :: TrieMap m => (a->b) -> ListMap m a -> ListMap m b
-mapList f (LM { lm_nil = mnil, lm_cons = mcons })
- = LM { lm_nil = fmap f mnil, lm_cons = mapTM (mapTM f) mcons }
-
-lkList :: TrieMap m => (forall b. k -> m b -> Maybe b)
- -> [k] -> ListMap m a -> Maybe a
-lkList _ [] = lm_nil
-lkList lk (x:xs) = lm_cons >.> lk x >=> lkList lk xs
-
-xtList :: TrieMap m => (forall b. k -> XT b -> m b -> m b)
- -> [k] -> XT a -> ListMap m a -> ListMap m a
-xtList _ [] f m = m { lm_nil = f (lm_nil m) }
-xtList tr (x:xs) f m = m { lm_cons = lm_cons m |> tr x |>> xtList tr xs f }
-
-fdList :: forall m a b. TrieMap m
- => (a -> b -> b) -> ListMap m a -> b -> b
-fdList k m = foldMaybe k (lm_nil m)
- . foldTM (fdList k) (lm_cons m)
-
-foldMaybe :: (a -> b -> b) -> Maybe a -> b -> b
-foldMaybe _ Nothing b = b
-foldMaybe k (Just a) b = k a b
-
-{-
-************************************************************************
-* *
- Basic maps
-* *
-************************************************************************
--}
-
-type LiteralMap a = Map.Map Literal a
-
-{-
-************************************************************************
-* *
- GenMap
-* *
-************************************************************************
-
-Note [Compressed TrieMap]
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The GenMap constructor augments TrieMaps with leaf compression. This helps
-solve the performance problem detailed in #9960: suppose we have a handful
-H of entries in a TrieMap, each with a very large key, size K. If you fold over
-such a TrieMap you'd expect time O(H). That would certainly be true of an
-association list! But with TrieMap we actually have to navigate down a long
-singleton structure to get to the elements, so it takes time O(K*H). This
-can really hurt on many type-level computation benchmarks:
-see for example T9872d.
-
-The point of a TrieMap is that you need to navigate to the point where only one
-key remains, and then things should be fast. So the point of a SingletonMap
-is that, once we are down to a single (key,value) pair, we stop and
-just use SingletonMap.
-
-'EmptyMap' provides an even more basic (but essential) optimization: if there is
-nothing in the map, don't bother building out the (possibly infinite) recursive
-TrieMap structure!
-
-Compressed triemaps are heavily used by GHC.Core.Map. So we have to mark some things
-as INLINEABLE to permit specialization.
--}
-
-data GenMap m a
- = EmptyMap
- | SingletonMap (Key m) a
- | MultiMap (m a)
-
-instance (Outputable a, Outputable (m a)) => Outputable (GenMap m a) where
- ppr EmptyMap = text "Empty map"
- ppr (SingletonMap _ v) = text "Singleton map" <+> ppr v
- ppr (MultiMap m) = ppr m
-
--- TODO undecidable instance
-instance (Eq (Key m), TrieMap m) => TrieMap (GenMap m) where
- type Key (GenMap m) = Key m
- emptyTM = EmptyMap
- lookupTM = lkG
- alterTM = xtG
- foldTM = fdG
- mapTM = mapG
-
---We want to be able to specialize these functions when defining eg
---tries over (GenMap CoreExpr) which requires INLINEABLE
-
-{-# INLINEABLE lkG #-}
-lkG :: (Eq (Key m), TrieMap m) => Key m -> GenMap m a -> Maybe a
-lkG _ EmptyMap = Nothing
-lkG k (SingletonMap k' v') | k == k' = Just v'
- | otherwise = Nothing
-lkG k (MultiMap m) = lookupTM k m
-
-{-# INLINEABLE xtG #-}
-xtG :: (Eq (Key m), TrieMap m) => Key m -> XT a -> GenMap m a -> GenMap m a
-xtG k f EmptyMap
- = case f Nothing of
- Just v -> SingletonMap k v
- Nothing -> EmptyMap
-xtG k f m@(SingletonMap k' v')
- | k' == k
- -- The new key matches the (single) key already in the tree. Hence,
- -- apply @f@ to @Just v'@ and build a singleton or empty map depending
- -- on the 'Just'/'Nothing' response respectively.
- = case f (Just v') of
- Just v'' -> SingletonMap k' v''
- Nothing -> EmptyMap
- | otherwise
- -- We've hit a singleton tree for a different key than the one we are
- -- searching for. Hence apply @f@ to @Nothing@. If result is @Nothing@ then
- -- we can just return the old map. If not, we need a map with *two*
- -- entries. The easiest way to do that is to insert two items into an empty
- -- map of type @m a@.
- = case f Nothing of
- Nothing -> m
- Just v -> emptyTM |> alterTM k' (const (Just v'))
- >.> alterTM k (const (Just v))
- >.> MultiMap
-xtG k f (MultiMap m) = MultiMap (alterTM k f m)
-
-{-# INLINEABLE mapG #-}
-mapG :: TrieMap m => (a -> b) -> GenMap m a -> GenMap m b
-mapG _ EmptyMap = EmptyMap
-mapG f (SingletonMap k v) = SingletonMap k (f v)
-mapG f (MultiMap m) = MultiMap (mapTM f m)
-
-{-# INLINEABLE fdG #-}
-fdG :: TrieMap m => (a -> b -> b) -> GenMap m a -> b -> b
-fdG _ EmptyMap = \z -> z
-fdG k (SingletonMap _ v) = \z -> k v z
-fdG k (MultiMap m) = foldTM k m
diff --git a/compiler/utils/UnVarGraph.hs b/compiler/utils/UnVarGraph.hs
deleted file mode 100644
index 20eff96c2c..0000000000
--- a/compiler/utils/UnVarGraph.hs
+++ /dev/null
@@ -1,145 +0,0 @@
-{-
-
-Copyright (c) 2014 Joachim Breitner
-
-A data structure for undirected graphs of variables
-(or in plain terms: Sets of unordered pairs of numbers)
-
-
-This is very specifically tailored for the use in CallArity. In particular it
-stores the graph as a union of complete and complete bipartite graph, which
-would be very expensive to store as sets of edges or as adjanceny lists.
-
-It does not normalize the graphs. This means that g `unionUnVarGraph` g is
-equal to g, but twice as expensive and large.
-
--}
-module UnVarGraph
- ( UnVarSet
- , emptyUnVarSet, mkUnVarSet, varEnvDom, unionUnVarSet, unionUnVarSets
- , delUnVarSet
- , elemUnVarSet, isEmptyUnVarSet
- , UnVarGraph
- , emptyUnVarGraph
- , unionUnVarGraph, unionUnVarGraphs
- , completeGraph, completeBipartiteGraph
- , neighbors
- , hasLoopAt
- , delNode
- ) where
-
-import GhcPrelude
-
-import GHC.Types.Id
-import GHC.Types.Var.Env
-import GHC.Types.Unique.FM
-import Outputable
-import Bag
-import GHC.Types.Unique
-
-import qualified Data.IntSet as S
-
--- We need a type for sets of variables (UnVarSet).
--- We do not use VarSet, because for that we need to have the actual variable
--- at hand, and we do not have that when we turn the domain of a VarEnv into a UnVarSet.
--- Therefore, use a IntSet directly (which is likely also a bit more efficient).
-
--- Set of uniques, i.e. for adjancet nodes
-newtype UnVarSet = UnVarSet (S.IntSet)
- deriving Eq
-
-k :: Var -> Int
-k v = getKey (getUnique v)
-
-emptyUnVarSet :: UnVarSet
-emptyUnVarSet = UnVarSet S.empty
-
-elemUnVarSet :: Var -> UnVarSet -> Bool
-elemUnVarSet v (UnVarSet s) = k v `S.member` s
-
-
-isEmptyUnVarSet :: UnVarSet -> Bool
-isEmptyUnVarSet (UnVarSet s) = S.null s
-
-delUnVarSet :: UnVarSet -> Var -> UnVarSet
-delUnVarSet (UnVarSet s) v = UnVarSet $ k v `S.delete` s
-
-mkUnVarSet :: [Var] -> UnVarSet
-mkUnVarSet vs = UnVarSet $ S.fromList $ map k vs
-
-varEnvDom :: VarEnv a -> UnVarSet
-varEnvDom ae = UnVarSet $ ufmToSet_Directly ae
-
-unionUnVarSet :: UnVarSet -> UnVarSet -> UnVarSet
-unionUnVarSet (UnVarSet set1) (UnVarSet set2) = UnVarSet (set1 `S.union` set2)
-
-unionUnVarSets :: [UnVarSet] -> UnVarSet
-unionUnVarSets = foldr unionUnVarSet emptyUnVarSet
-
-instance Outputable UnVarSet where
- ppr (UnVarSet s) = braces $
- hcat $ punctuate comma [ ppr (getUnique i) | i <- S.toList s]
-
-
--- The graph type. A list of complete bipartite graphs
-data Gen = CBPG UnVarSet UnVarSet -- complete bipartite
- | CG UnVarSet -- complete
-newtype UnVarGraph = UnVarGraph (Bag Gen)
-
-emptyUnVarGraph :: UnVarGraph
-emptyUnVarGraph = UnVarGraph emptyBag
-
-unionUnVarGraph :: UnVarGraph -> UnVarGraph -> UnVarGraph
-{-
-Premature optimisation, it seems.
-unionUnVarGraph (UnVarGraph [CBPG s1 s2]) (UnVarGraph [CG s3, CG s4])
- | s1 == s3 && s2 == s4
- = pprTrace "unionUnVarGraph fired" empty $
- completeGraph (s1 `unionUnVarSet` s2)
-unionUnVarGraph (UnVarGraph [CBPG s1 s2]) (UnVarGraph [CG s3, CG s4])
- | s2 == s3 && s1 == s4
- = pprTrace "unionUnVarGraph fired2" empty $
- completeGraph (s1 `unionUnVarSet` s2)
--}
-unionUnVarGraph (UnVarGraph g1) (UnVarGraph g2)
- = -- pprTrace "unionUnVarGraph" (ppr (length g1, length g2)) $
- UnVarGraph (g1 `unionBags` g2)
-
-unionUnVarGraphs :: [UnVarGraph] -> UnVarGraph
-unionUnVarGraphs = foldl' unionUnVarGraph emptyUnVarGraph
-
--- completeBipartiteGraph A B = { {a,b} | a ∈ A, b ∈ B }
-completeBipartiteGraph :: UnVarSet -> UnVarSet -> UnVarGraph
-completeBipartiteGraph s1 s2 = prune $ UnVarGraph $ unitBag $ CBPG s1 s2
-
-completeGraph :: UnVarSet -> UnVarGraph
-completeGraph s = prune $ UnVarGraph $ unitBag $ CG s
-
-neighbors :: UnVarGraph -> Var -> UnVarSet
-neighbors (UnVarGraph g) v = unionUnVarSets $ concatMap go $ bagToList g
- where go (CG s) = (if v `elemUnVarSet` s then [s] else [])
- go (CBPG s1 s2) = (if v `elemUnVarSet` s1 then [s2] else []) ++
- (if v `elemUnVarSet` s2 then [s1] else [])
-
--- hasLoopAt G v <=> v--v ∈ G
-hasLoopAt :: UnVarGraph -> Var -> Bool
-hasLoopAt (UnVarGraph g) v = any go $ bagToList g
- where go (CG s) = v `elemUnVarSet` s
- go (CBPG s1 s2) = v `elemUnVarSet` s1 && v `elemUnVarSet` s2
-
-
-delNode :: UnVarGraph -> Var -> UnVarGraph
-delNode (UnVarGraph g) v = prune $ UnVarGraph $ mapBag go g
- where go (CG s) = CG (s `delUnVarSet` v)
- go (CBPG s1 s2) = CBPG (s1 `delUnVarSet` v) (s2 `delUnVarSet` v)
-
-prune :: UnVarGraph -> UnVarGraph
-prune (UnVarGraph g) = UnVarGraph $ filterBag go g
- where go (CG s) = not (isEmptyUnVarSet s)
- go (CBPG s1 s2) = not (isEmptyUnVarSet s1) && not (isEmptyUnVarSet s2)
-
-instance Outputable Gen where
- ppr (CG s) = ppr s <> char '²'
- ppr (CBPG s1 s2) = ppr s1 <+> char 'x' <+> ppr s2
-instance Outputable UnVarGraph where
- ppr (UnVarGraph g) = ppr g
diff --git a/compiler/utils/Util.hs b/compiler/utils/Util.hs
deleted file mode 100644
index b343d9cf8b..0000000000
--- a/compiler/utils/Util.hs
+++ /dev/null
@@ -1,1465 +0,0 @@
--- (c) The University of Glasgow 2006
-
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE KindSignatures #-}
-{-# LANGUAGE ConstraintKinds #-}
-{-# LANGUAGE BangPatterns #-}
-{-# LANGUAGE TupleSections #-}
-
-{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
-
--- | Highly random utility functions
---
-module Util (
- -- * Flags dependent on the compiler build
- ghciSupported, debugIsOn,
- isWindowsHost, isDarwinHost,
-
- -- * Miscellaneous higher-order functions
- applyWhen, nTimes,
-
- -- * General list processing
- zipEqual, zipWithEqual, zipWith3Equal, zipWith4Equal,
- zipLazy, stretchZipWith, zipWithAndUnzip, zipAndUnzip,
-
- zipWithLazy, zipWith3Lazy,
-
- filterByList, filterByLists, partitionByList,
-
- unzipWith,
-
- mapFst, mapSnd, chkAppend,
- mapAndUnzip, mapAndUnzip3, mapAccumL2,
- filterOut, partitionWith,
-
- dropWhileEndLE, spanEnd, last2, lastMaybe,
-
- foldl1', foldl2, count, countWhile, all2,
-
- lengthExceeds, lengthIs, lengthIsNot,
- lengthAtLeast, lengthAtMost, lengthLessThan,
- listLengthCmp, atLength,
- equalLength, compareLength, leLength, ltLength,
-
- isSingleton, only, singleton,
- notNull, snocView,
-
- isIn, isn'tIn,
-
- chunkList,
-
- changeLast,
-
- whenNonEmpty,
-
- -- * Tuples
- fstOf3, sndOf3, thdOf3,
- firstM, first3M, secondM,
- fst3, snd3, third3,
- uncurry3,
- liftFst, liftSnd,
-
- -- * List operations controlled by another list
- takeList, dropList, splitAtList, split,
- dropTail, capitalise,
-
- -- * Sorting
- sortWith, minWith, nubSort, ordNub,
-
- -- * Comparisons
- isEqual, eqListBy, eqMaybeBy,
- thenCmp, cmpList,
- removeSpaces,
- (<&&>), (<||>),
-
- -- * Edit distance
- fuzzyMatch, fuzzyLookup,
-
- -- * Transitive closures
- transitiveClosure,
-
- -- * Strictness
- seqList, strictMap,
-
- -- * Module names
- looksLikeModuleName,
- looksLikePackageName,
-
- -- * Argument processing
- getCmd, toCmdArgs, toArgs,
-
- -- * Integers
- exactLog2,
-
- -- * Floating point
- readRational,
- readHexRational,
-
- -- * IO-ish utilities
- doesDirNameExist,
- getModificationUTCTime,
- modificationTimeIfExists,
- withAtomicRename,
-
- global, consIORef, globalM,
- sharedGlobal, sharedGlobalM,
-
- -- * Filenames and paths
- Suffix,
- splitLongestPrefix,
- escapeSpaces,
- Direction(..), reslash,
- makeRelativeTo,
-
- -- * Utils for defining Data instances
- abstractConstr, abstractDataType, mkNoRepType,
-
- -- * Utils for printing C code
- charToC,
-
- -- * Hashing
- hashString,
-
- -- * Call stacks
- HasCallStack,
- HasDebugCallStack,
-
- -- * Utils for flags
- OverridingBool(..),
- overrideWith,
- ) where
-
-#include "HsVersions.h"
-
-import GhcPrelude
-
-import Exception
-import PlainPanic
-
-import Data.Data
-import Data.IORef ( IORef, newIORef, atomicModifyIORef' )
-import System.IO.Unsafe ( unsafePerformIO )
-import Data.List hiding (group)
-import Data.List.NonEmpty ( NonEmpty(..) )
-
-import GHC.Exts
-import GHC.Stack (HasCallStack)
-
-import Control.Applicative ( liftA2 )
-import Control.Monad ( liftM, guard )
-import Control.Monad.IO.Class ( MonadIO, liftIO )
-import GHC.Conc.Sync ( sharedCAF )
-import System.IO.Error as IO ( isDoesNotExistError )
-import System.Directory ( doesDirectoryExist, getModificationTime, renameFile )
-import System.FilePath
-
-import Data.Char ( isUpper, isAlphaNum, isSpace, chr, ord, isDigit, toUpper
- , isHexDigit, digitToInt )
-import Data.Int
-import Data.Ratio ( (%) )
-import Data.Ord ( comparing )
-import Data.Bits
-import Data.Word
-import qualified Data.IntMap as IM
-import qualified Data.Set as Set
-
-import Data.Time
-
-#if defined(DEBUG)
-import {-# SOURCE #-} Outputable ( warnPprTrace, text )
-#endif
-
-infixr 9 `thenCmp`
-
-{-
-************************************************************************
-* *
-\subsection{Is DEBUG on, are we on Windows, etc?}
-* *
-************************************************************************
-
-These booleans are global constants, set by CPP flags. They allow us to
-recompile a single module (this one) to change whether or not debug output
-appears. They sometimes let us avoid even running CPP elsewhere.
-
-It's important that the flags are literal constants (True/False). Then,
-with -0, tests of the flags in other modules will simplify to the correct
-branch of the conditional, thereby dropping debug code altogether when
-the flags are off.
--}
-
-ghciSupported :: Bool
-#if defined(HAVE_INTERNAL_INTERPRETER)
-ghciSupported = True
-#else
-ghciSupported = False
-#endif
-
-debugIsOn :: Bool
-#if defined(DEBUG)
-debugIsOn = True
-#else
-debugIsOn = False
-#endif
-
-isWindowsHost :: Bool
-#if defined(mingw32_HOST_OS)
-isWindowsHost = True
-#else
-isWindowsHost = False
-#endif
-
-isDarwinHost :: Bool
-#if defined(darwin_HOST_OS)
-isDarwinHost = True
-#else
-isDarwinHost = False
-#endif
-
-{-
-************************************************************************
-* *
-\subsection{Miscellaneous higher-order functions}
-* *
-************************************************************************
--}
-
--- | Apply a function iff some condition is met.
-applyWhen :: Bool -> (a -> a) -> a -> a
-applyWhen True f x = f x
-applyWhen _ _ x = x
-
--- | A for loop: Compose a function with itself n times. (nth rather than twice)
-nTimes :: Int -> (a -> a) -> (a -> a)
-nTimes 0 _ = id
-nTimes 1 f = f
-nTimes n f = f . nTimes (n-1) f
-
-fstOf3 :: (a,b,c) -> a
-sndOf3 :: (a,b,c) -> b
-thdOf3 :: (a,b,c) -> c
-fstOf3 (a,_,_) = a
-sndOf3 (_,b,_) = b
-thdOf3 (_,_,c) = c
-
-fst3 :: (a -> d) -> (a, b, c) -> (d, b, c)
-fst3 f (a, b, c) = (f a, b, c)
-
-snd3 :: (b -> d) -> (a, b, c) -> (a, d, c)
-snd3 f (a, b, c) = (a, f b, c)
-
-third3 :: (c -> d) -> (a, b, c) -> (a, b, d)
-third3 f (a, b, c) = (a, b, f c)
-
-uncurry3 :: (a -> b -> c -> d) -> (a, b, c) -> d
-uncurry3 f (a, b, c) = f a b c
-
-liftFst :: (a -> b) -> (a, c) -> (b, c)
-liftFst f (a,c) = (f a, c)
-
-liftSnd :: (a -> b) -> (c, a) -> (c, b)
-liftSnd f (c,a) = (c, f a)
-
-firstM :: Monad m => (a -> m c) -> (a, b) -> m (c, b)
-firstM f (x, y) = liftM (\x' -> (x', y)) (f x)
-
-first3M :: Monad m => (a -> m d) -> (a, b, c) -> m (d, b, c)
-first3M f (x, y, z) = liftM (\x' -> (x', y, z)) (f x)
-
-secondM :: Monad m => (b -> m c) -> (a, b) -> m (a, c)
-secondM f (x, y) = (x,) <$> f y
-
-{-
-************************************************************************
-* *
-\subsection[Utils-lists]{General list processing}
-* *
-************************************************************************
--}
-
-filterOut :: (a->Bool) -> [a] -> [a]
--- ^ Like filter, only it reverses the sense of the test
-filterOut _ [] = []
-filterOut p (x:xs) | p x = filterOut p xs
- | otherwise = x : filterOut p xs
-
-partitionWith :: (a -> Either b c) -> [a] -> ([b], [c])
--- ^ Uses a function to determine which of two output lists an input element should join
-partitionWith _ [] = ([],[])
-partitionWith f (x:xs) = case f x of
- Left b -> (b:bs, cs)
- Right c -> (bs, c:cs)
- where (bs,cs) = partitionWith f xs
-
-chkAppend :: [a] -> [a] -> [a]
--- Checks for the second argument being empty
--- Used in situations where that situation is common
-chkAppend xs ys
- | null ys = xs
- | otherwise = xs ++ ys
-
-{-
-A paranoid @zip@ (and some @zipWith@ friends) that checks the lists
-are of equal length. Alastair Reid thinks this should only happen if
-DEBUGging on; hey, why not?
--}
-
-zipEqual :: String -> [a] -> [b] -> [(a,b)]
-zipWithEqual :: String -> (a->b->c) -> [a]->[b]->[c]
-zipWith3Equal :: String -> (a->b->c->d) -> [a]->[b]->[c]->[d]
-zipWith4Equal :: String -> (a->b->c->d->e) -> [a]->[b]->[c]->[d]->[e]
-
-#if !defined(DEBUG)
-zipEqual _ = zip
-zipWithEqual _ = zipWith
-zipWith3Equal _ = zipWith3
-zipWith4Equal _ = zipWith4
-#else
-zipEqual _ [] [] = []
-zipEqual msg (a:as) (b:bs) = (a,b) : zipEqual msg as bs
-zipEqual msg _ _ = panic ("zipEqual: unequal lists: "++msg)
-
-zipWithEqual msg z (a:as) (b:bs)= z a b : zipWithEqual msg z as bs
-zipWithEqual _ _ [] [] = []
-zipWithEqual msg _ _ _ = panic ("zipWithEqual: unequal lists: "++msg)
-
-zipWith3Equal msg z (a:as) (b:bs) (c:cs)
- = z a b c : zipWith3Equal msg z as bs cs
-zipWith3Equal _ _ [] [] [] = []
-zipWith3Equal msg _ _ _ _ = panic ("zipWith3Equal: unequal lists: "++msg)
-
-zipWith4Equal msg z (a:as) (b:bs) (c:cs) (d:ds)
- = z a b c d : zipWith4Equal msg z as bs cs ds
-zipWith4Equal _ _ [] [] [] [] = []
-zipWith4Equal msg _ _ _ _ _ = panic ("zipWith4Equal: unequal lists: "++msg)
-#endif
-
--- | 'zipLazy' is a kind of 'zip' that is lazy in the second list (observe the ~)
-zipLazy :: [a] -> [b] -> [(a,b)]
-zipLazy [] _ = []
-zipLazy (x:xs) ~(y:ys) = (x,y) : zipLazy xs ys
-
--- | 'zipWithLazy' is like 'zipWith' but is lazy in the second list.
--- The length of the output is always the same as the length of the first
--- list.
-zipWithLazy :: (a -> b -> c) -> [a] -> [b] -> [c]
-zipWithLazy _ [] _ = []
-zipWithLazy f (a:as) ~(b:bs) = f a b : zipWithLazy f as bs
-
--- | 'zipWith3Lazy' is like 'zipWith3' but is lazy in the second and third lists.
--- The length of the output is always the same as the length of the first
--- list.
-zipWith3Lazy :: (a -> b -> c -> d) -> [a] -> [b] -> [c] -> [d]
-zipWith3Lazy _ [] _ _ = []
-zipWith3Lazy f (a:as) ~(b:bs) ~(c:cs) = f a b c : zipWith3Lazy f as bs cs
-
--- | 'filterByList' takes a list of Bools and a list of some elements and
--- filters out these elements for which the corresponding value in the list of
--- Bools is False. This function does not check whether the lists have equal
--- length.
-filterByList :: [Bool] -> [a] -> [a]
-filterByList (True:bs) (x:xs) = x : filterByList bs xs
-filterByList (False:bs) (_:xs) = filterByList bs xs
-filterByList _ _ = []
-
--- | 'filterByLists' takes a list of Bools and two lists as input, and
--- outputs a new list consisting of elements from the last two input lists. For
--- each Bool in the list, if it is 'True', then it takes an element from the
--- former list. If it is 'False', it takes an element from the latter list.
--- The elements taken correspond to the index of the Bool in its list.
--- For example:
---
--- @
--- filterByLists [True, False, True, False] \"abcd\" \"wxyz\" = \"axcz\"
--- @
---
--- This function does not check whether the lists have equal length.
-filterByLists :: [Bool] -> [a] -> [a] -> [a]
-filterByLists (True:bs) (x:xs) (_:ys) = x : filterByLists bs xs ys
-filterByLists (False:bs) (_:xs) (y:ys) = y : filterByLists bs xs ys
-filterByLists _ _ _ = []
-
--- | 'partitionByList' takes a list of Bools and a list of some elements and
--- partitions the list according to the list of Bools. Elements corresponding
--- to 'True' go to the left; elements corresponding to 'False' go to the right.
--- For example, @partitionByList [True, False, True] [1,2,3] == ([1,3], [2])@
--- This function does not check whether the lists have equal
--- length; when one list runs out, the function stops.
-partitionByList :: [Bool] -> [a] -> ([a], [a])
-partitionByList = go [] []
- where
- go trues falses (True : bs) (x : xs) = go (x:trues) falses bs xs
- go trues falses (False : bs) (x : xs) = go trues (x:falses) bs xs
- go trues falses _ _ = (reverse trues, reverse falses)
-
-stretchZipWith :: (a -> Bool) -> b -> (a->b->c) -> [a] -> [b] -> [c]
--- ^ @stretchZipWith p z f xs ys@ stretches @ys@ by inserting @z@ in
--- the places where @p@ returns @True@
-
-stretchZipWith _ _ _ [] _ = []
-stretchZipWith p z f (x:xs) ys
- | p x = f x z : stretchZipWith p z f xs ys
- | otherwise = case ys of
- [] -> []
- (y:ys) -> f x y : stretchZipWith p z f xs ys
-
-mapFst :: (a->c) -> [(a,b)] -> [(c,b)]
-mapSnd :: (b->c) -> [(a,b)] -> [(a,c)]
-
-mapFst f xys = [(f x, y) | (x,y) <- xys]
-mapSnd f xys = [(x, f y) | (x,y) <- xys]
-
-mapAndUnzip :: (a -> (b, c)) -> [a] -> ([b], [c])
-
-mapAndUnzip _ [] = ([], [])
-mapAndUnzip f (x:xs)
- = let (r1, r2) = f x
- (rs1, rs2) = mapAndUnzip f xs
- in
- (r1:rs1, r2:rs2)
-
-mapAndUnzip3 :: (a -> (b, c, d)) -> [a] -> ([b], [c], [d])
-
-mapAndUnzip3 _ [] = ([], [], [])
-mapAndUnzip3 f (x:xs)
- = let (r1, r2, r3) = f x
- (rs1, rs2, rs3) = mapAndUnzip3 f xs
- in
- (r1:rs1, r2:rs2, r3:rs3)
-
-zipWithAndUnzip :: (a -> b -> (c,d)) -> [a] -> [b] -> ([c],[d])
-zipWithAndUnzip f (a:as) (b:bs)
- = let (r1, r2) = f a b
- (rs1, rs2) = zipWithAndUnzip f as bs
- in
- (r1:rs1, r2:rs2)
-zipWithAndUnzip _ _ _ = ([],[])
-
--- | This has the effect of making the two lists have equal length by dropping
--- the tail of the longer one.
-zipAndUnzip :: [a] -> [b] -> ([a],[b])
-zipAndUnzip (a:as) (b:bs)
- = let (rs1, rs2) = zipAndUnzip as bs
- in
- (a:rs1, b:rs2)
-zipAndUnzip _ _ = ([],[])
-
-mapAccumL2 :: (s1 -> s2 -> a -> (s1, s2, b)) -> s1 -> s2 -> [a] -> (s1, s2, [b])
-mapAccumL2 f s1 s2 xs = (s1', s2', ys)
- where ((s1', s2'), ys) = mapAccumL (\(s1, s2) x -> case f s1 s2 x of
- (s1', s2', y) -> ((s1', s2'), y))
- (s1, s2) xs
-
--- | @atLength atLen atEnd ls n@ unravels list @ls@ to position @n@. Precisely:
---
--- @
--- atLength atLenPred atEndPred ls n
--- | n < 0 = atLenPred ls
--- | length ls < n = atEndPred (n - length ls)
--- | otherwise = atLenPred (drop n ls)
--- @
-atLength :: ([a] -> b) -- Called when length ls >= n, passed (drop n ls)
- -- NB: arg passed to this function may be []
- -> b -- Called when length ls < n
- -> [a]
- -> Int
- -> b
-atLength atLenPred atEnd ls0 n0
- | n0 < 0 = atLenPred ls0
- | otherwise = go n0 ls0
- where
- -- go's first arg n >= 0
- go 0 ls = atLenPred ls
- go _ [] = atEnd -- n > 0 here
- go n (_:xs) = go (n-1) xs
-
--- Some special cases of atLength:
-
--- | @(lengthExceeds xs n) = (length xs > n)@
-lengthExceeds :: [a] -> Int -> Bool
-lengthExceeds lst n
- | n < 0
- = True
- | otherwise
- = atLength notNull False lst n
-
--- | @(lengthAtLeast xs n) = (length xs >= n)@
-lengthAtLeast :: [a] -> Int -> Bool
-lengthAtLeast = atLength (const True) False
-
--- | @(lengthIs xs n) = (length xs == n)@
-lengthIs :: [a] -> Int -> Bool
-lengthIs lst n
- | n < 0
- = False
- | otherwise
- = atLength null False lst n
-
--- | @(lengthIsNot xs n) = (length xs /= n)@
-lengthIsNot :: [a] -> Int -> Bool
-lengthIsNot lst n
- | n < 0 = True
- | otherwise = atLength notNull True lst n
-
--- | @(lengthAtMost xs n) = (length xs <= n)@
-lengthAtMost :: [a] -> Int -> Bool
-lengthAtMost lst n
- | n < 0
- = False
- | otherwise
- = atLength null True lst n
-
--- | @(lengthLessThan xs n) == (length xs < n)@
-lengthLessThan :: [a] -> Int -> Bool
-lengthLessThan = atLength (const False) True
-
-listLengthCmp :: [a] -> Int -> Ordering
-listLengthCmp = atLength atLen atEnd
- where
- atEnd = LT -- Not yet seen 'n' elts, so list length is < n.
-
- atLen [] = EQ
- atLen _ = GT
-
-equalLength :: [a] -> [b] -> Bool
--- ^ True if length xs == length ys
-equalLength [] [] = True
-equalLength (_:xs) (_:ys) = equalLength xs ys
-equalLength _ _ = False
-
-compareLength :: [a] -> [b] -> Ordering
-compareLength [] [] = EQ
-compareLength (_:xs) (_:ys) = compareLength xs ys
-compareLength [] _ = LT
-compareLength _ [] = GT
-
-leLength :: [a] -> [b] -> Bool
--- ^ True if length xs <= length ys
-leLength xs ys = case compareLength xs ys of
- LT -> True
- EQ -> True
- GT -> False
-
-ltLength :: [a] -> [b] -> Bool
--- ^ True if length xs < length ys
-ltLength xs ys = case compareLength xs ys of
- LT -> True
- EQ -> False
- GT -> False
-
-----------------------------
-singleton :: a -> [a]
-singleton x = [x]
-
-isSingleton :: [a] -> Bool
-isSingleton [_] = True
-isSingleton _ = False
-
-notNull :: [a] -> Bool
-notNull [] = False
-notNull _ = True
-
-only :: [a] -> a
-#if defined(DEBUG)
-only [a] = a
-#else
-only (a:_) = a
-#endif
-only _ = panic "Util: only"
-
--- Debugging/specialising versions of \tr{elem} and \tr{notElem}
-
-# if !defined(DEBUG)
-isIn, isn'tIn :: Eq a => String -> a -> [a] -> Bool
-isIn _msg x ys = x `elem` ys
-isn'tIn _msg x ys = x `notElem` ys
-
-# else /* DEBUG */
-isIn, isn'tIn :: (HasDebugCallStack, Eq a) => String -> a -> [a] -> Bool
-isIn msg x ys
- = elem100 0 x ys
- where
- elem100 :: Eq a => Int -> a -> [a] -> Bool
- elem100 _ _ [] = False
- elem100 i x (y:ys)
- | i > 100 = WARN(True, text ("Over-long elem in " ++ msg)) (x `elem` (y:ys))
- | otherwise = x == y || elem100 (i + 1) x ys
-
-isn'tIn msg x ys
- = notElem100 0 x ys
- where
- notElem100 :: Eq a => Int -> a -> [a] -> Bool
- notElem100 _ _ [] = True
- notElem100 i x (y:ys)
- | i > 100 = WARN(True, text ("Over-long notElem in " ++ msg)) (x `notElem` (y:ys))
- | otherwise = x /= y && notElem100 (i + 1) x ys
-# endif /* DEBUG */
-
-
--- | Split a list into chunks of /n/ elements
-chunkList :: Int -> [a] -> [[a]]
-chunkList _ [] = []
-chunkList n xs = as : chunkList n bs where (as,bs) = splitAt n xs
-
--- | Replace the last element of a list with another element.
-changeLast :: [a] -> a -> [a]
-changeLast [] _ = panic "changeLast"
-changeLast [_] x = [x]
-changeLast (x:xs) x' = x : changeLast xs x'
-
-whenNonEmpty :: Applicative m => [a] -> (NonEmpty a -> m ()) -> m ()
-whenNonEmpty [] _ = pure ()
-whenNonEmpty (x:xs) f = f (x :| xs)
-
-{-
-************************************************************************
-* *
-\subsubsection{Sort utils}
-* *
-************************************************************************
--}
-
-minWith :: Ord b => (a -> b) -> [a] -> a
-minWith get_key xs = ASSERT( not (null xs) )
- head (sortWith get_key xs)
-
-nubSort :: Ord a => [a] -> [a]
-nubSort = Set.toAscList . Set.fromList
-
--- | Remove duplicates but keep elements in order.
--- O(n * log n)
-ordNub :: Ord a => [a] -> [a]
-ordNub xs
- = go Set.empty xs
- where
- go _ [] = []
- go s (x:xs)
- | Set.member x s = go s xs
- | otherwise = x : go (Set.insert x s) xs
-
-
-{-
-************************************************************************
-* *
-\subsection[Utils-transitive-closure]{Transitive closure}
-* *
-************************************************************************
-
-This algorithm for transitive closure is straightforward, albeit quadratic.
--}
-
-transitiveClosure :: (a -> [a]) -- Successor function
- -> (a -> a -> Bool) -- Equality predicate
- -> [a]
- -> [a] -- The transitive closure
-
-transitiveClosure succ eq xs
- = go [] xs
- where
- go done [] = done
- go done (x:xs) | x `is_in` done = go done xs
- | otherwise = go (x:done) (succ x ++ xs)
-
- _ `is_in` [] = False
- x `is_in` (y:ys) | eq x y = True
- | otherwise = x `is_in` ys
-
-{-
-************************************************************************
-* *
-\subsection[Utils-accum]{Accumulating}
-* *
-************************************************************************
-
-A combination of foldl with zip. It works with equal length lists.
--}
-
-foldl2 :: (acc -> a -> b -> acc) -> acc -> [a] -> [b] -> acc
-foldl2 _ z [] [] = z
-foldl2 k z (a:as) (b:bs) = foldl2 k (k z a b) as bs
-foldl2 _ _ _ _ = panic "Util: foldl2"
-
-all2 :: (a -> b -> Bool) -> [a] -> [b] -> Bool
--- True if the lists are the same length, and
--- all corresponding elements satisfy the predicate
-all2 _ [] [] = True
-all2 p (x:xs) (y:ys) = p x y && all2 p xs ys
-all2 _ _ _ = False
-
--- Count the number of times a predicate is true
-
-count :: (a -> Bool) -> [a] -> Int
-count p = go 0
- where go !n [] = n
- go !n (x:xs) | p x = go (n+1) xs
- | otherwise = go n xs
-
-countWhile :: (a -> Bool) -> [a] -> Int
--- Length of an /initial prefix/ of the list satisfying p
-countWhile p = go 0
- where go !n (x:xs) | p x = go (n+1) xs
- go !n _ = n
-
-{-
-@splitAt@, @take@, and @drop@ but with length of another
-list giving the break-off point:
--}
-
-takeList :: [b] -> [a] -> [a]
--- (takeList as bs) trims bs to the be same length
--- as as, unless as is longer in which case it's a no-op
-takeList [] _ = []
-takeList (_:xs) ls =
- case ls of
- [] -> []
- (y:ys) -> y : takeList xs ys
-
-dropList :: [b] -> [a] -> [a]
-dropList [] xs = xs
-dropList _ xs@[] = xs
-dropList (_:xs) (_:ys) = dropList xs ys
-
-
-splitAtList :: [b] -> [a] -> ([a], [a])
-splitAtList [] xs = ([], xs)
-splitAtList _ xs@[] = (xs, xs)
-splitAtList (_:xs) (y:ys) = (y:ys', ys'')
- where
- (ys', ys'') = splitAtList xs ys
-
--- drop from the end of a list
-dropTail :: Int -> [a] -> [a]
--- Specification: dropTail n = reverse . drop n . reverse
--- Better implemention due to Joachim Breitner
--- http://www.joachim-breitner.de/blog/archives/600-On-taking-the-last-n-elements-of-a-list.html
-dropTail n xs
- = go (drop n xs) xs
- where
- go (_:ys) (x:xs) = x : go ys xs
- go _ _ = [] -- Stop when ys runs out
- -- It'll always run out before xs does
-
--- dropWhile from the end of a list. This is similar to Data.List.dropWhileEnd,
--- but is lazy in the elements and strict in the spine. For reasonably short lists,
--- such as path names and typical lines of text, dropWhileEndLE is generally
--- faster than dropWhileEnd. Its advantage is magnified when the predicate is
--- expensive--using dropWhileEndLE isSpace to strip the space off a line of text
--- is generally much faster than using dropWhileEnd isSpace for that purpose.
--- Specification: dropWhileEndLE p = reverse . dropWhile p . reverse
--- Pay attention to the short-circuit (&&)! The order of its arguments is the only
--- difference between dropWhileEnd and dropWhileEndLE.
-dropWhileEndLE :: (a -> Bool) -> [a] -> [a]
-dropWhileEndLE p = foldr (\x r -> if null r && p x then [] else x:r) []
-
--- | @spanEnd p l == reverse (span p (reverse l))@. The first list
--- returns actually comes after the second list (when you look at the
--- input list).
-spanEnd :: (a -> Bool) -> [a] -> ([a], [a])
-spanEnd p l = go l [] [] l
- where go yes _rev_yes rev_no [] = (yes, reverse rev_no)
- go yes rev_yes rev_no (x:xs)
- | p x = go yes (x : rev_yes) rev_no xs
- | otherwise = go xs [] (x : rev_yes ++ rev_no) xs
-
--- | Get the last two elements in a list. Partial!
-{-# INLINE last2 #-}
-last2 :: [a] -> (a,a)
-last2 = foldl' (\(_,x2) x -> (x2,x)) (partialError,partialError)
- where
- partialError = panic "last2 - list length less than two"
-
-lastMaybe :: [a] -> Maybe a
-lastMaybe [] = Nothing
-lastMaybe xs = Just $ last xs
-
--- | Split a list into its last element and the initial part of the list.
--- @snocView xs = Just (init xs, last xs)@ for non-empty lists.
--- @snocView xs = Nothing@ otherwise.
--- Unless both parts of the result are guaranteed to be used
--- prefer separate calls to @last@ + @init@.
--- If you are guaranteed to use both, this will
--- be more efficient.
-snocView :: [a] -> Maybe ([a],a)
-snocView [] = Nothing
-snocView xs
- | (xs,x) <- go xs
- = Just (xs,x)
- where
- go :: [a] -> ([a],a)
- go [x] = ([],x)
- go (x:xs)
- | !(xs',x') <- go xs
- = (x:xs', x')
- go [] = error "impossible"
-
-split :: Char -> String -> [String]
-split c s = case rest of
- [] -> [chunk]
- _:rest -> chunk : split c rest
- where (chunk, rest) = break (==c) s
-
--- | Convert a word to title case by capitalising the first letter
-capitalise :: String -> String
-capitalise [] = []
-capitalise (c:cs) = toUpper c : cs
-
-
-{-
-************************************************************************
-* *
-\subsection[Utils-comparison]{Comparisons}
-* *
-************************************************************************
--}
-
-isEqual :: Ordering -> Bool
--- Often used in (isEqual (a `compare` b))
-isEqual GT = False
-isEqual EQ = True
-isEqual LT = False
-
-thenCmp :: Ordering -> Ordering -> Ordering
-{-# INLINE thenCmp #-}
-thenCmp EQ ordering = ordering
-thenCmp ordering _ = ordering
-
-eqListBy :: (a->a->Bool) -> [a] -> [a] -> Bool
-eqListBy _ [] [] = True
-eqListBy eq (x:xs) (y:ys) = eq x y && eqListBy eq xs ys
-eqListBy _ _ _ = False
-
-eqMaybeBy :: (a ->a->Bool) -> Maybe a -> Maybe a -> Bool
-eqMaybeBy _ Nothing Nothing = True
-eqMaybeBy eq (Just x) (Just y) = eq x y
-eqMaybeBy _ _ _ = False
-
-cmpList :: (a -> a -> Ordering) -> [a] -> [a] -> Ordering
- -- `cmpList' uses a user-specified comparer
-
-cmpList _ [] [] = EQ
-cmpList _ [] _ = LT
-cmpList _ _ [] = GT
-cmpList cmp (a:as) (b:bs)
- = case cmp a b of { EQ -> cmpList cmp as bs; xxx -> xxx }
-
-removeSpaces :: String -> String
-removeSpaces = dropWhileEndLE isSpace . dropWhile isSpace
-
--- Boolean operators lifted to Applicative
-(<&&>) :: Applicative f => f Bool -> f Bool -> f Bool
-(<&&>) = liftA2 (&&)
-infixr 3 <&&> -- same as (&&)
-
-(<||>) :: Applicative f => f Bool -> f Bool -> f Bool
-(<||>) = liftA2 (||)
-infixr 2 <||> -- same as (||)
-
-{-
-************************************************************************
-* *
-\subsection{Edit distance}
-* *
-************************************************************************
--}
-
--- | Find the "restricted" Damerau-Levenshtein edit distance between two strings.
--- See: <http://en.wikipedia.org/wiki/Damerau-Levenshtein_distance>.
--- Based on the algorithm presented in "A Bit-Vector Algorithm for Computing
--- Levenshtein and Damerau Edit Distances" in PSC'02 (Heikki Hyyro).
--- See http://www.cs.uta.fi/~helmu/pubs/psc02.pdf and
--- http://www.cs.uta.fi/~helmu/pubs/PSCerr.html for an explanation
-restrictedDamerauLevenshteinDistance :: String -> String -> Int
-restrictedDamerauLevenshteinDistance str1 str2
- = restrictedDamerauLevenshteinDistanceWithLengths m n str1 str2
- where
- m = length str1
- n = length str2
-
-restrictedDamerauLevenshteinDistanceWithLengths
- :: Int -> Int -> String -> String -> Int
-restrictedDamerauLevenshteinDistanceWithLengths m n str1 str2
- | m <= n
- = if n <= 32 -- n must be larger so this check is sufficient
- then restrictedDamerauLevenshteinDistance' (undefined :: Word32) m n str1 str2
- else restrictedDamerauLevenshteinDistance' (undefined :: Integer) m n str1 str2
-
- | otherwise
- = if m <= 32 -- m must be larger so this check is sufficient
- then restrictedDamerauLevenshteinDistance' (undefined :: Word32) n m str2 str1
- else restrictedDamerauLevenshteinDistance' (undefined :: Integer) n m str2 str1
-
-restrictedDamerauLevenshteinDistance'
- :: (Bits bv, Num bv) => bv -> Int -> Int -> String -> String -> Int
-restrictedDamerauLevenshteinDistance' _bv_dummy m n str1 str2
- | [] <- str1 = n
- | otherwise = extractAnswer $
- foldl' (restrictedDamerauLevenshteinDistanceWorker
- (matchVectors str1) top_bit_mask vector_mask)
- (0, 0, m_ones, 0, m) str2
- where
- m_ones@vector_mask = (2 ^ m) - 1
- top_bit_mask = (1 `shiftL` (m - 1)) `asTypeOf` _bv_dummy
- extractAnswer (_, _, _, _, distance) = distance
-
-restrictedDamerauLevenshteinDistanceWorker
- :: (Bits bv, Num bv) => IM.IntMap bv -> bv -> bv
- -> (bv, bv, bv, bv, Int) -> Char -> (bv, bv, bv, bv, Int)
-restrictedDamerauLevenshteinDistanceWorker str1_mvs top_bit_mask vector_mask
- (pm, d0, vp, vn, distance) char2
- = seq str1_mvs $ seq top_bit_mask $ seq vector_mask $
- seq pm' $ seq d0' $ seq vp' $ seq vn' $
- seq distance'' $ seq char2 $
- (pm', d0', vp', vn', distance'')
- where
- pm' = IM.findWithDefault 0 (ord char2) str1_mvs
-
- d0' = ((((sizedComplement vector_mask d0) .&. pm') `shiftL` 1) .&. pm)
- .|. ((((pm' .&. vp) + vp) .&. vector_mask) `xor` vp) .|. pm' .|. vn
- -- No need to mask the shiftL because of the restricted range of pm
-
- hp' = vn .|. sizedComplement vector_mask (d0' .|. vp)
- hn' = d0' .&. vp
-
- hp'_shift = ((hp' `shiftL` 1) .|. 1) .&. vector_mask
- hn'_shift = (hn' `shiftL` 1) .&. vector_mask
- vp' = hn'_shift .|. sizedComplement vector_mask (d0' .|. hp'_shift)
- vn' = d0' .&. hp'_shift
-
- distance' = if hp' .&. top_bit_mask /= 0 then distance + 1 else distance
- distance'' = if hn' .&. top_bit_mask /= 0 then distance' - 1 else distance'
-
-sizedComplement :: Bits bv => bv -> bv -> bv
-sizedComplement vector_mask vect = vector_mask `xor` vect
-
-matchVectors :: (Bits bv, Num bv) => String -> IM.IntMap bv
-matchVectors = snd . foldl' go (0 :: Int, IM.empty)
- where
- go (ix, im) char = let ix' = ix + 1
- im' = IM.insertWith (.|.) (ord char) (2 ^ ix) im
- in seq ix' $ seq im' $ (ix', im')
-
-{-# SPECIALIZE INLINE restrictedDamerauLevenshteinDistance'
- :: Word32 -> Int -> Int -> String -> String -> Int #-}
-{-# SPECIALIZE INLINE restrictedDamerauLevenshteinDistance'
- :: Integer -> Int -> Int -> String -> String -> Int #-}
-
-{-# SPECIALIZE restrictedDamerauLevenshteinDistanceWorker
- :: IM.IntMap Word32 -> Word32 -> Word32
- -> (Word32, Word32, Word32, Word32, Int)
- -> Char -> (Word32, Word32, Word32, Word32, Int) #-}
-{-# SPECIALIZE restrictedDamerauLevenshteinDistanceWorker
- :: IM.IntMap Integer -> Integer -> Integer
- -> (Integer, Integer, Integer, Integer, Int)
- -> Char -> (Integer, Integer, Integer, Integer, Int) #-}
-
-{-# SPECIALIZE INLINE sizedComplement :: Word32 -> Word32 -> Word32 #-}
-{-# SPECIALIZE INLINE sizedComplement :: Integer -> Integer -> Integer #-}
-
-{-# SPECIALIZE matchVectors :: String -> IM.IntMap Word32 #-}
-{-# SPECIALIZE matchVectors :: String -> IM.IntMap Integer #-}
-
-fuzzyMatch :: String -> [String] -> [String]
-fuzzyMatch key vals = fuzzyLookup key [(v,v) | v <- vals]
-
--- | Search for possible matches to the users input in the given list,
--- returning a small number of ranked results
-fuzzyLookup :: String -> [(String,a)] -> [a]
-fuzzyLookup user_entered possibilites
- = map fst $ take mAX_RESULTS $ sortBy (comparing snd)
- [ (poss_val, distance) | (poss_str, poss_val) <- possibilites
- , let distance = restrictedDamerauLevenshteinDistance
- poss_str user_entered
- , distance <= fuzzy_threshold ]
- where
- -- Work out an appropriate match threshold:
- -- We report a candidate if its edit distance is <= the threshold,
- -- The threshold is set to about a quarter of the # of characters the user entered
- -- Length Threshold
- -- 1 0 -- Don't suggest *any* candidates
- -- 2 1 -- for single-char identifiers
- -- 3 1
- -- 4 1
- -- 5 1
- -- 6 2
- --
- fuzzy_threshold = truncate $ fromIntegral (length user_entered + 2) / (4 :: Rational)
- mAX_RESULTS = 3
-
-{-
-************************************************************************
-* *
-\subsection[Utils-pairs]{Pairs}
-* *
-************************************************************************
--}
-
-unzipWith :: (a -> b -> c) -> [(a, b)] -> [c]
-unzipWith f pairs = map ( \ (a, b) -> f a b ) pairs
-
-seqList :: [a] -> b -> b
-seqList [] b = b
-seqList (x:xs) b = x `seq` seqList xs b
-
-strictMap :: (a -> b) -> [a] -> [b]
-strictMap _ [] = []
-strictMap f (x : xs) =
- let
- !x' = f x
- !xs' = strictMap f xs
- in
- x' : xs'
-
-{-
-************************************************************************
-* *
- Globals and the RTS
-* *
-************************************************************************
-
-When a plugin is loaded, it currently gets linked against a *newly
-loaded* copy of the GHC package. This would not be a problem, except
-that the new copy has its own mutable state that is not shared with
-that state that has already been initialized by the original GHC
-package.
-
-(Note that if the GHC executable was dynamically linked this
-wouldn't be a problem, because we could share the GHC library it
-links to; this is only a problem if DYNAMIC_GHC_PROGRAMS=NO.)
-
-The solution is to make use of @sharedCAF@ through @sharedGlobal@
-for globals that are shared between multiple copies of ghc packages.
--}
-
--- Global variables:
-
-global :: a -> IORef a
-global a = unsafePerformIO (newIORef a)
-
-consIORef :: IORef [a] -> a -> IO ()
-consIORef var x = do
- atomicModifyIORef' var (\xs -> (x:xs,()))
-
-globalM :: IO a -> IORef a
-globalM ma = unsafePerformIO (ma >>= newIORef)
-
--- Shared global variables:
-
-sharedGlobal :: a -> (Ptr (IORef a) -> IO (Ptr (IORef a))) -> IORef a
-sharedGlobal a get_or_set = unsafePerformIO $
- newIORef a >>= flip sharedCAF get_or_set
-
-sharedGlobalM :: IO a -> (Ptr (IORef a) -> IO (Ptr (IORef a))) -> IORef a
-sharedGlobalM ma get_or_set = unsafePerformIO $
- ma >>= newIORef >>= flip sharedCAF get_or_set
-
--- Module names:
-
-looksLikeModuleName :: String -> Bool
-looksLikeModuleName [] = False
-looksLikeModuleName (c:cs) = isUpper c && go cs
- where go [] = True
- go ('.':cs) = looksLikeModuleName cs
- go (c:cs) = (isAlphaNum c || c == '_' || c == '\'') && go cs
-
--- Similar to 'parse' for Distribution.Package.PackageName,
--- but we don't want to depend on Cabal.
-looksLikePackageName :: String -> Bool
-looksLikePackageName = all (all isAlphaNum <&&> not . (all isDigit)) . split '-'
-
-{-
-Akin to @Prelude.words@, but acts like the Bourne shell, treating
-quoted strings as Haskell Strings, and also parses Haskell [String]
-syntax.
--}
-
-getCmd :: String -> Either String -- Error
- (String, String) -- (Cmd, Rest)
-getCmd s = case break isSpace $ dropWhile isSpace s of
- ([], _) -> Left ("Couldn't find command in " ++ show s)
- res -> Right res
-
-toCmdArgs :: String -> Either String -- Error
- (String, [String]) -- (Cmd, Args)
-toCmdArgs s = case getCmd s of
- Left err -> Left err
- Right (cmd, s') -> case toArgs s' of
- Left err -> Left err
- Right args -> Right (cmd, args)
-
-toArgs :: String -> Either String -- Error
- [String] -- Args
-toArgs str
- = case dropWhile isSpace str of
- s@('[':_) -> case reads s of
- [(args, spaces)]
- | all isSpace spaces ->
- Right args
- _ ->
- Left ("Couldn't read " ++ show str ++ " as [String]")
- s -> toArgs' s
- where
- toArgs' :: String -> Either String [String]
- -- Remove outer quotes:
- -- > toArgs' "\"foo\" \"bar baz\""
- -- Right ["foo", "bar baz"]
- --
- -- Keep inner quotes:
- -- > toArgs' "-DFOO=\"bar baz\""
- -- Right ["-DFOO=\"bar baz\""]
- toArgs' s = case dropWhile isSpace s of
- [] -> Right []
- ('"' : _) -> do
- -- readAsString removes outer quotes
- (arg, rest) <- readAsString s
- (arg:) `fmap` toArgs' rest
- s' -> case break (isSpace <||> (== '"')) s' of
- (argPart1, s''@('"':_)) -> do
- (argPart2, rest) <- readAsString s''
- -- show argPart2 to keep inner quotes
- ((argPart1 ++ show argPart2):) `fmap` toArgs' rest
- (arg, s'') -> (arg:) `fmap` toArgs' s''
-
- readAsString :: String -> Either String (String, String)
- readAsString s = case reads s of
- [(arg, rest)]
- -- rest must either be [] or start with a space
- | all isSpace (take 1 rest) ->
- Right (arg, rest)
- _ ->
- Left ("Couldn't read " ++ show s ++ " as String")
------------------------------------------------------------------------------
--- Integers
-
--- | Determine the $\log_2$ of exact powers of 2
-exactLog2 :: Integer -> Maybe Integer
-exactLog2 x
- | x <= 0 = Nothing
- | x > fromIntegral (maxBound :: Int32) = Nothing
- | x' .&. (-x') /= x' = Nothing
- | otherwise = Just (fromIntegral c)
- where
- x' = fromIntegral x :: Int32
- c = countTrailingZeros x'
-
-{-
--- -----------------------------------------------------------------------------
--- Floats
--}
-
-readRational__ :: ReadS Rational -- NB: doesn't handle leading "-"
-readRational__ r = do
- (n,d,s) <- readFix r
- (k,t) <- readExp s
- return ((n%1)*10^^(k-d), t)
- where
- readFix r = do
- (ds,s) <- lexDecDigits r
- (ds',t) <- lexDotDigits s
- return (read (ds++ds'), length ds', t)
-
- readExp (e:s) | e `elem` "eE" = readExp' s
- readExp s = return (0,s)
-
- readExp' ('+':s) = readDec s
- readExp' ('-':s) = do (k,t) <- readDec s
- return (-k,t)
- readExp' s = readDec s
-
- readDec s = do
- (ds,r) <- nonnull isDigit s
- return (foldl1 (\n d -> n * 10 + d) [ ord d - ord '0' | d <- ds ],
- r)
-
- lexDecDigits = nonnull isDigit
-
- lexDotDigits ('.':s) = return (span' isDigit s)
- lexDotDigits s = return ("",s)
-
- nonnull p s = do (cs@(_:_),t) <- return (span' p s)
- return (cs,t)
-
- span' _ xs@[] = (xs, xs)
- span' p xs@(x:xs')
- | x == '_' = span' p xs' -- skip "_" (#14473)
- | p x = let (ys,zs) = span' p xs' in (x:ys,zs)
- | otherwise = ([],xs)
-
-readRational :: String -> Rational -- 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 (do { (x,"") <- readRational__ s ; return x }) of
- [x] -> x
- [] -> error ("readRational: no parse:" ++ top_s)
- _ -> error ("readRational: ambiguous parse:" ++ top_s)
-
-
-readHexRational :: String -> Rational
-readHexRational str =
- case str of
- '-' : xs -> - (readMe xs)
- xs -> readMe xs
- where
- readMe as =
- case readHexRational__ as of
- Just n -> n
- _ -> error ("readHexRational: no parse:" ++ str)
-
-
-readHexRational__ :: String -> Maybe Rational
-readHexRational__ ('0' : x : rest)
- | x == 'X' || x == 'x' =
- do let (front,rest2) = span' isHexDigit rest
- guard (not (null front))
- let frontNum = steps 16 0 front
- case rest2 of
- '.' : rest3 ->
- do let (back,rest4) = span' isHexDigit rest3
- guard (not (null back))
- let backNum = steps 16 frontNum back
- exp1 = -4 * length back
- case rest4 of
- p : ps | isExp p -> fmap (mk backNum . (+ exp1)) (getExp ps)
- _ -> return (mk backNum exp1)
- p : ps | isExp p -> fmap (mk frontNum) (getExp ps)
- _ -> Nothing
-
- where
- isExp p = p == 'p' || p == 'P'
-
- getExp ('+' : ds) = dec ds
- getExp ('-' : ds) = fmap negate (dec ds)
- getExp ds = dec ds
-
- mk :: Integer -> Int -> Rational
- mk n e = fromInteger n * 2^^e
-
- dec cs = case span' isDigit cs of
- (ds,"") | not (null ds) -> Just (steps 10 0 ds)
- _ -> Nothing
-
- steps base n ds = foldl' (step base) n ds
- step base n d = base * n + fromIntegral (digitToInt d)
-
- span' _ xs@[] = (xs, xs)
- span' p xs@(x:xs')
- | x == '_' = span' p xs' -- skip "_" (#14473)
- | p x = let (ys,zs) = span' p xs' in (x:ys,zs)
- | otherwise = ([],xs)
-
-readHexRational__ _ = Nothing
-
------------------------------------------------------------------------------
--- Verify that the 'dirname' portion of a FilePath exists.
---
-doesDirNameExist :: FilePath -> IO Bool
-doesDirNameExist fpath = doesDirectoryExist (takeDirectory fpath)
-
------------------------------------------------------------------------------
--- Backwards compatibility definition of getModificationTime
-
-getModificationUTCTime :: FilePath -> IO UTCTime
-getModificationUTCTime = getModificationTime
-
--- --------------------------------------------------------------
--- check existence & modification time at the same time
-
-modificationTimeIfExists :: FilePath -> IO (Maybe UTCTime)
-modificationTimeIfExists f = do
- (do t <- getModificationUTCTime f; return (Just t))
- `catchIO` \e -> if isDoesNotExistError e
- then return Nothing
- else ioError e
-
--- --------------------------------------------------------------
--- atomic file writing by writing to a temporary file first (see #14533)
---
--- This should be used in all cases where GHC writes files to disk
--- and uses their modification time to skip work later,
--- as otherwise a partially written file (e.g. due to crash or Ctrl+C)
--- also results in a skip.
-
-withAtomicRename :: (MonadIO m) => FilePath -> (FilePath -> m a) -> m a
-withAtomicRename targetFile f = do
- -- The temp file must be on the same file system (mount) as the target file
- -- to result in an atomic move on most platforms.
- -- The standard way to ensure that is to place it into the same directory.
- -- This can still be fooled when somebody mounts a different file system
- -- at just the right time, but that is not a case we aim to cover here.
- let temp = targetFile <.> "tmp"
- res <- f temp
- liftIO $ renameFile temp targetFile
- return res
-
--- --------------------------------------------------------------
--- split a string at the last character where 'pred' is True,
--- returning a pair of strings. The first component holds the string
--- up (but not including) the last character for which 'pred' returned
--- True, the second whatever comes after (but also not including the
--- last character).
---
--- If 'pred' returns False for all characters in the string, the original
--- string is returned in the first component (and the second one is just
--- empty).
-splitLongestPrefix :: String -> (Char -> Bool) -> (String,String)
-splitLongestPrefix str pred
- | null r_pre = (str, [])
- | otherwise = (reverse (tail r_pre), reverse r_suf)
- -- 'tail' drops the char satisfying 'pred'
- where (r_suf, r_pre) = break pred (reverse str)
-
-escapeSpaces :: String -> String
-escapeSpaces = foldr (\c s -> if isSpace c then '\\':c:s else c:s) ""
-
-type Suffix = String
-
---------------------------------------------------------------
--- * Search path
---------------------------------------------------------------
-
-data Direction = Forwards | Backwards
-
-reslash :: Direction -> FilePath -> FilePath
-reslash d = f
- where f ('/' : xs) = slash : f xs
- f ('\\' : xs) = slash : f xs
- f (x : xs) = x : f xs
- f "" = ""
- slash = case d of
- Forwards -> '/'
- Backwards -> '\\'
-
-makeRelativeTo :: FilePath -> FilePath -> FilePath
-this `makeRelativeTo` that = directory </> thisFilename
- where (thisDirectory, thisFilename) = splitFileName this
- thatDirectory = dropFileName that
- directory = joinPath $ f (splitPath thisDirectory)
- (splitPath thatDirectory)
-
- f (x : xs) (y : ys)
- | x == y = f xs ys
- f xs ys = replicate (length ys) ".." ++ xs
-
-{-
-************************************************************************
-* *
-\subsection[Utils-Data]{Utils for defining Data instances}
-* *
-************************************************************************
-
-These functions helps us to define Data instances for abstract types.
--}
-
-abstractConstr :: String -> Constr
-abstractConstr n = mkConstr (abstractDataType n) ("{abstract:"++n++"}") [] Prefix
-
-abstractDataType :: String -> DataType
-abstractDataType n = mkDataType n [abstractConstr n]
-
-{-
-************************************************************************
-* *
-\subsection[Utils-C]{Utils for printing C code}
-* *
-************************************************************************
--}
-
-charToC :: Word8 -> String
-charToC w =
- case chr (fromIntegral w) of
- '\"' -> "\\\""
- '\'' -> "\\\'"
- '\\' -> "\\\\"
- c | c >= ' ' && c <= '~' -> [c]
- | otherwise -> ['\\',
- chr (ord '0' + ord c `div` 64),
- chr (ord '0' + ord c `div` 8 `mod` 8),
- chr (ord '0' + ord c `mod` 8)]
-
-{-
-************************************************************************
-* *
-\subsection[Utils-Hashing]{Utils for hashing}
-* *
-************************************************************************
--}
-
--- | A sample hash function for Strings. We keep multiplying by the
--- golden ratio and adding. The implementation is:
---
--- > hashString = foldl' f golden
--- > where f m c = fromIntegral (ord c) * magic + hashInt32 m
--- > magic = 0xdeadbeef
---
--- Where hashInt32 works just as hashInt shown above.
---
--- Knuth argues that repeated multiplication by the golden ratio
--- will minimize gaps in the hash space, and thus it's a good choice
--- for combining together multiple keys to form one.
---
--- Here we know that individual characters c are often small, and this
--- produces frequent collisions if we use ord c alone. A
--- particular problem are the shorter low ASCII and ISO-8859-1
--- character strings. We pre-multiply by a magic twiddle factor to
--- obtain a good distribution. In fact, given the following test:
---
--- > testp :: Int32 -> Int
--- > testp k = (n - ) . length . group . sort . map hs . take n $ ls
--- > where ls = [] : [c : l | l <- ls, c <- ['\0'..'\xff']]
--- > hs = foldl' f golden
--- > f m c = fromIntegral (ord c) * k + hashInt32 m
--- > n = 100000
---
--- We discover that testp magic = 0.
-hashString :: String -> Int32
-hashString = foldl' f golden
- where f m c = fromIntegral (ord c) * magic + hashInt32 m
- magic = fromIntegral (0xdeadbeef :: Word32)
-
-golden :: Int32
-golden = 1013904242 -- = round ((sqrt 5 - 1) * 2^32) :: Int32
--- was -1640531527 = round ((sqrt 5 - 1) * 2^31) :: Int32
--- but that has bad mulHi properties (even adding 2^32 to get its inverse)
--- Whereas the above works well and contains no hash duplications for
--- [-32767..65536]
-
--- | A sample (and useful) hash function for Int32,
--- implemented by extracting the uppermost 32 bits of the 64-bit
--- result of multiplying by a 33-bit constant. The constant is from
--- Knuth, derived from the golden ratio:
---
--- > golden = round ((sqrt 5 - 1) * 2^32)
---
--- We get good key uniqueness on small inputs
--- (a problem with previous versions):
--- (length $ group $ sort $ map hashInt32 [-32767..65536]) == 65536 + 32768
---
-hashInt32 :: Int32 -> Int32
-hashInt32 x = mulHi x golden + x
-
--- hi 32 bits of a x-bit * 32 bit -> 64-bit multiply
-mulHi :: Int32 -> Int32 -> Int32
-mulHi a b = fromIntegral (r `shiftR` 32)
- where r :: Int64
- r = fromIntegral a * fromIntegral b
-
--- | A call stack constraint, but only when 'isDebugOn'.
-#if defined(DEBUG)
-type HasDebugCallStack = HasCallStack
-#else
-type HasDebugCallStack = (() :: Constraint)
-#endif
-
-data OverridingBool
- = Auto
- | Always
- | Never
- deriving Show
-
-overrideWith :: Bool -> OverridingBool -> Bool
-overrideWith b Auto = b
-overrideWith _ Always = True
-overrideWith _ Never = False