1 {-# LANGUAGE DeriveDataTypeable #-}
2 {-# LANGUAGE DeriveGeneric #-}
3 {-# LANGUAGE RankNTypes #-}
5 module Distribution
.Types
.ModuleRenaming
12 import Distribution
.CabalSpecVersion
13 import Distribution
.Compat
.Prelude
hiding (empty)
16 import Distribution
.ModuleName
17 import Distribution
.Parsec
18 import Distribution
.Pretty
20 import qualified Data
.Map
as Map
21 import qualified Data
.Set
as Set
22 import qualified Distribution
.Compat
.CharParsing
as P
23 import Text
.PrettyPrint
(comma
, hsep
, parens
, punctuate
, text
)
25 -- | Renaming applied to the modules provided by a package.
26 -- The boolean indicates whether or not to also include all of the
27 -- original names of modules. Thus, @ModuleRenaming False []@ is
28 -- "don't expose any modules, and @ModuleRenaming True [("Data.Bool", "Bool")]@
29 -- is, "expose all modules, but also expose @Data.Bool@ as @Bool@".
30 -- If a renaming is omitted you get the 'DefaultRenaming'.
32 -- (NB: This is a list not a map so that we can preserve order.)
34 = -- | A module renaming/thinning; e.g., @(A as B, C as C)@
35 -- brings @B@ and @C@ into scope.
36 ModuleRenaming
[(ModuleName
, ModuleName
)]
37 |
-- | The default renaming, bringing all exported modules
40 |
-- | Hiding renaming, e.g., @hiding (A, B)@, bringing all
41 -- exported modules into scope except the hidden ones.
42 HidingRenaming
[ModuleName
]
43 deriving (Show, Read, Eq
, Ord
, Typeable
, Data
, Generic
)
45 -- | Interpret a 'ModuleRenaming' as a partial map from 'ModuleName'
46 -- to 'ModuleName'. For efficiency, you should partially apply it
47 -- with 'ModuleRenaming' and then reuse it.
48 interpModuleRenaming
:: ModuleRenaming
-> ModuleName
-> Maybe ModuleName
49 interpModuleRenaming DefaultRenaming
= Just
50 interpModuleRenaming
(ModuleRenaming rns
) =
51 let m
= Map
.fromList rns
52 in \k
-> Map
.lookup k m
53 interpModuleRenaming
(HidingRenaming hs
) =
54 let s
= Set
.fromList hs
55 in \k
-> if k `Set
.member` s
then Nothing
else Just k
57 -- | The default renaming, if something is specified in @build-depends@
59 defaultRenaming
:: ModuleRenaming
60 defaultRenaming
= DefaultRenaming
62 -- | Tests if its the default renaming; we can use a more compact syntax
63 -- in 'Distribution.Types.IncludeRenaming.IncludeRenaming' in this case.
64 isDefaultRenaming
:: ModuleRenaming
-> Bool
65 isDefaultRenaming DefaultRenaming
= True
66 isDefaultRenaming _
= False
68 instance Binary ModuleRenaming
69 instance Structured ModuleRenaming
71 instance NFData ModuleRenaming
where rnf
= genericRnf
73 -- NB: parentheses are mandatory, because later we may extend this syntax
74 -- to allow "hiding (A, B)" or other modifier words.
75 instance Pretty ModuleRenaming
where
76 pretty DefaultRenaming
= mempty
77 pretty
(HidingRenaming hides
) =
78 text
"hiding" <+> parens
(hsep
(punctuate comma
(map pretty hides
)))
79 pretty
(ModuleRenaming rns
) =
80 parens
. hsep
$ punctuate comma
(map dispEntry rns
)
83 | orig
== new
= pretty orig
84 |
otherwise = pretty orig
<+> text
"as" <+> pretty new
86 instance Parsec ModuleRenaming
where
88 csv
<- askCabalSpecVersion
89 if csv
>= CabalSpecV3_0
90 then moduleRenamingParsec parensLax lexemeParsec
91 else moduleRenamingParsec parensStrict parsec
93 -- For cabal spec versions < 3.0 white spaces were not skipped
94 -- after the '(' and ')' tokens in the mixin field. This
95 -- parser checks the cabal file version and does the correct
96 -- skipping of spaces.
97 parensLax p
= P
.between
(P
.char
'(' >> P
.spaces
) (P
.char
')' >> P
.spaces
) p
98 parensStrict p
= P
.between
(P
.char
'(' >> warnSpaces
) (P
.char
')') p
102 P
.space
*> fail "space after parenthesis, use cabal-version: 3.0 or higher"
106 => (forall a
. m a
-> m a
)
109 -- ^ module name parser
111 moduleRenamingParsec bp mn
=
112 -- NB: try not necessary as the first token is obvious
113 P
.choice
[parseRename
, parseHiding
, return DefaultRenaming
]
115 cma
= P
.char
',' >> P
.spaces
119 return (ModuleRenaming rns
)
121 _
<- P
.string "hiding"
122 P
.spaces
-- space isn't strictly required as next is an open paren
123 hides
<- bp
(P
.sepBy mn cma
)
124 return (HidingRenaming hides
)
126 P
.sepBy parseEntry cma
130 P
.option
(orig
, orig
) $ do
132 P
.skipSpaces1
-- require space after "as"