Skip to content

Commit 4533308

Browse files
committed
CabalSpecVersion + Leading (or trailing) comma for build-depends
CabalSpecVersion type-class will allow to gather per-spec conditionals. Currently it's used for selecting parsers / grammatical structure. Leading (or trailing commas) for CommaFSep/CommaVSep fields, i.e. fields with mandatory comma are (atm): - build-depends - build-tool-depends - build-tools - mixins - pkgconfig-depends - reexported-modules - setup-depends
1 parent b8c95ea commit 4533308

File tree

14 files changed

+299
-121
lines changed

14 files changed

+299
-121
lines changed

Cabal/Cabal.cabal

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ extra-source-files:
3838
tests/ParserTests/errors/common2.errors
3939
tests/ParserTests/errors/common3.cabal
4040
tests/ParserTests/errors/common3.errors
41+
tests/ParserTests/errors/leading-comma.cabal
42+
tests/ParserTests/errors/leading-comma.errors
4143
tests/ParserTests/regressions/Octree-0.5.cabal
4244
tests/ParserTests/regressions/Octree-0.5.format
4345
tests/ParserTests/regressions/common.cabal
@@ -55,6 +57,8 @@ extra-source-files:
5557
tests/ParserTests/regressions/haddock-api-2.18.1-check.cabal
5658
tests/ParserTests/regressions/issue-774.cabal
5759
tests/ParserTests/regressions/issue-774.format
60+
tests/ParserTests/regressions/leading-comma.cabal
61+
tests/ParserTests/regressions/leading-comma.format
5862
tests/ParserTests/regressions/nothing-unicode.cabal
5963
tests/ParserTests/regressions/nothing-unicode.format
6064
tests/ParserTests/regressions/shake.cabal
@@ -148,6 +152,7 @@ library
148152
Distribution.Backpack.ModSubst
149153
Distribution.Backpack.ModuleShape
150154
Distribution.Backpack.PreModuleShape
155+
Distribution.CabalSpecVersion
151156
Distribution.Utils.IOData
152157
Distribution.Utils.LogProgress
153158
Distribution.Utils.MapAccum
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{-# LANGUAGE FlexibleContexts, RankNTypes #-}
2+
module Distribution.CabalSpecVersion where
3+
4+
import Distribution.Parsec.Class (Parsec (..), ParsecParser)
5+
6+
-- A class to select how to parse different fields.
7+
class CabalSpecVersion v where
8+
-- | @v@ can act as own proxy
9+
cabalSpecVersion :: v
10+
11+
-- | Parsec parser according to the spec version
12+
specParsec :: Parsec a => v -> ParsecParser a
13+
14+
-- given a version, whether this spec knows about it's fields
15+
specKnows :: v -> [Int] -> Bool
16+
17+
specHasElif :: v -> HasElif
18+
specHasCommonStanzas :: v -> HasCommonStanzas
19+
20+
data CabalSpecOld = CabalSpecOld
21+
data CabalSpecV22 = CabalSpecV22
22+
23+
instance CabalSpecVersion CabalSpecOld where
24+
cabalSpecVersion = CabalSpecOld
25+
specParsec _ = parsec
26+
specKnows _ vs = vs < [2,1]
27+
specHasElif _ = NoElif
28+
specHasCommonStanzas _ = NoCommonStanzas
29+
30+
instance CabalSpecVersion CabalSpecV22 where
31+
cabalSpecVersion = CabalSpecV22
32+
specParsec _ = parsec22
33+
specKnows _ _ = True
34+
specHasElif _ = HasElif
35+
specHasCommonStanzas _ = HasCommonStanzas
36+
37+
type CabalSpecLatest = CabalSpecV22
38+
39+
-------------------------------------------------------------------------------
40+
-- "Booleans"
41+
-------------------------------------------------------------------------------
42+
43+
data HasElif = HasElif | NoElif
44+
deriving (Eq, Show)
45+
46+
data HasCommonStanzas = HasCommonStanzas | NoCommonStanzas
47+
deriving (Eq, Show)

Cabal/Distribution/FieldGrammar.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ import Distribution.FieldGrammar.Pretty
4040
import Distribution.Parsec.Field
4141
import Distribution.Utils.Generic (spanMaybe)
4242

43-
type ParsecFieldGrammar' a = ParsecFieldGrammar a a
44-
type PrettyFieldGrammar' a = PrettyFieldGrammar a a
43+
type ParsecFieldGrammar' v a = ParsecFieldGrammar v a a
44+
type PrettyFieldGrammar' a = PrettyFieldGrammar a a
4545

4646
infixl 5 ^^^
4747

Cabal/Distribution/FieldGrammar/Parsec.hs

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
{-# LANGUAGE DeriveFunctor #-}
2-
{-# LANGUAGE OverloadedStrings #-}
1+
{-# LANGUAGE DeriveFunctor #-}
2+
{-# LANGUAGE OverloadedStrings #-}
3+
{-# LANGUAGE ScopedTypeVariables #-}
34
-- | This module provides a 'FieldGrammarParser', one way to parse
45
-- @.cabal@ -like files.
56
--
@@ -61,16 +62,18 @@ module Distribution.FieldGrammar.Parsec (
6162
runFieldParser',
6263
) where
6364

65+
import Data.List (dropWhileEnd)
66+
import Data.Ord (comparing)
67+
import Data.Set (Set)
68+
import Distribution.CabalSpecVersion
69+
import Distribution.Compat.Newtype
70+
import Distribution.Compat.Prelude
71+
import Distribution.Simple.Utils (fromUTF8BS)
72+
import Prelude ()
73+
6474
import qualified Data.ByteString as BS
65-
import Data.List (dropWhileEnd)
66-
import Data.Ord (comparing)
67-
import Data.Set (Set)
6875
import qualified Data.Set as Set
6976
import qualified Distribution.Compat.Map.Strict as Map
70-
import Distribution.Compat.Prelude
71-
import Distribution.Compat.Newtype
72-
import Distribution.Simple.Utils (fromUTF8BS)
73-
import Prelude ()
7477
import qualified Text.Parsec as P
7578
import qualified Text.Parsec.Error as P
7679

@@ -98,14 +101,14 @@ data Section ann = MkSection !(Name ann) [SectionArg ann] [Field ann]
98101
-- ParsecFieldGrammar
99102
-------------------------------------------------------------------------------
100103

101-
data ParsecFieldGrammar s a = ParsecFG
104+
data ParsecFieldGrammar v s a = ParsecFG
102105
{ fieldGrammarKnownFields :: !(Set FieldName)
103106
, fieldGrammarKnownPrefixes :: !(Set FieldName)
104107
, fieldGrammarParser :: !(Fields Position -> ParseResult a)
105108
}
106109
deriving (Functor)
107110

108-
parseFieldGrammar :: Fields Position -> ParsecFieldGrammar s a -> ParseResult a
111+
parseFieldGrammar :: Fields Position -> ParsecFieldGrammar v s a -> ParseResult a
109112
parseFieldGrammar fields grammar = do
110113
for_ (Map.toList (Map.filterWithKey isUnknownField fields)) $ \(name, nfields) ->
111114
for_ nfields $ \(MkNamelessField pos _) ->
@@ -120,10 +123,10 @@ parseFieldGrammar fields grammar = do
120123
k `Set.member` fieldGrammarKnownFields grammar
121124
|| any (`BS.isPrefixOf` k) (fieldGrammarKnownPrefixes grammar)
122125

123-
fieldGrammarKnownFieldList :: ParsecFieldGrammar s a -> [FieldName]
126+
fieldGrammarKnownFieldList :: ParsecFieldGrammar v s a -> [FieldName]
124127
fieldGrammarKnownFieldList = Set.toList . fieldGrammarKnownFields
125128

126-
instance Applicative (ParsecFieldGrammar s) where
129+
instance Applicative (ParsecFieldGrammar v s) where
127130
pure x = ParsecFG mempty mempty (\_ -> pure x)
128131
{-# INLINE pure #-}
129132

@@ -133,7 +136,7 @@ instance Applicative (ParsecFieldGrammar s) where
133136
(\fields -> f'' fields <*> x'' fields)
134137
{-# INLINE (<*>) #-}
135138

136-
instance FieldGrammar ParsecFieldGrammar where
139+
instance CabalSpecVersion v => FieldGrammar (ParsecFieldGrammar v) where
137140
blurFieldGrammar _ (ParsecFG s s' parser) = ParsecFG s s' parser
138141

139142
uniqueFieldAla fn _pack _extract = ParsecFG (Set.singleton fn) Set.empty parser
@@ -147,7 +150,7 @@ instance FieldGrammar ParsecFieldGrammar where
147150
Just xs-> parseOne (last xs)
148151

149152
parseOne (MkNamelessField pos fls) =
150-
unpack' _pack <$> runFieldParser pos parsec fls
153+
unpack' _pack <$> runFieldParser pos (specParsec (cabalSpecVersion :: v)) fls
151154

152155
booleanFieldDef fn _extract def = ParsecFG (Set.singleton fn) Set.empty parser
153156
where
@@ -160,7 +163,7 @@ instance FieldGrammar ParsecFieldGrammar where
160163
-- TODO: warn about duplicate optional fields?
161164
Just xs -> parseOne (last xs)
162165

163-
parseOne (MkNamelessField pos fls) = runFieldParser pos parsec fls
166+
parseOne (MkNamelessField pos fls) = runFieldParser pos (specParsec (cabalSpecVersion :: v)) fls
164167

165168
optionalFieldAla fn _pack _extract = ParsecFG (Set.singleton fn) Set.empty parser
166169
where
@@ -173,15 +176,15 @@ instance FieldGrammar ParsecFieldGrammar where
173176

174177
parseOne (MkNamelessField pos fls)
175178
| null fls = pure Nothing
176-
| otherwise = Just . (unpack' _pack) <$> runFieldParser pos parsec fls
179+
| otherwise = Just . (unpack' _pack) <$> runFieldParser pos (specParsec (cabalSpecVersion :: v)) fls
177180

178181
monoidalFieldAla fn _pack _extract = ParsecFG (Set.singleton fn) Set.empty parser
179182
where
180183
parser fields = case Map.lookup fn fields of
181184
Nothing -> pure mempty
182185
Just xs -> foldMap (unpack' _pack) <$> traverse parseOne xs
183186

184-
parseOne (MkNamelessField pos fls) = runFieldParser pos parsec fls
187+
parseOne (MkNamelessField pos fls) = runFieldParser pos (specParsec (cabalSpecVersion :: v)) fls
185188

186189
prefixedFields fnPfx _extract = ParsecFG mempty (Set.singleton fnPfx) (pure . parser)
187190
where
@@ -199,6 +202,7 @@ instance FieldGrammar ParsecFieldGrammar where
199202
trim :: String -> String
200203
trim = dropWhile isSpace . dropWhileEnd isSpace
201204

205+
-- TODO: use versionedAvailable to drop parsing if old field.
202206
availableSince _ = id
203207

204208
deprecatedSince (_ : _) _ grammar = grammar -- pass on non-empty version

Cabal/Distribution/PackageDescription/FieldGrammar.hs

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import Distribution.Compat.Lens
4343
import Distribution.Compat.Prelude
4444
import Prelude ()
4545

46+
import Distribution.CabalSpecVersion
4647
import Distribution.Compiler (CompilerFlavor (..))
4748
import Distribution.FieldGrammar
4849
import Distribution.License (License (..))
@@ -127,7 +128,8 @@ libraryFieldGrammar n = Library n
127128
<*> monoidalFieldAla "signatures" (alaList' VCat MQuoted) L.signatures
128129
<*> booleanFieldDef "exposed" L.libExposed True
129130
<*> blurFieldGrammar L.libBuildInfo buildInfoFieldGrammar
130-
{-# SPECIALIZE libraryFieldGrammar :: Maybe UnqualComponentName -> ParsecFieldGrammar' Library #-}
131+
{-# SPECIALIZE libraryFieldGrammar :: Maybe UnqualComponentName -> ParsecFieldGrammar' CabalSpecOld Library #-}
132+
{-# SPECIALIZE libraryFieldGrammar :: Maybe UnqualComponentName -> ParsecFieldGrammar' CabalSpecV22 Library #-}
131133
{-# SPECIALIZE libraryFieldGrammar :: Maybe UnqualComponentName -> PrettyFieldGrammar' Library #-}
132134

133135
-------------------------------------------------------------------------------
@@ -144,7 +146,8 @@ foreignLibFieldGrammar n = ForeignLib n
144146
<*> optionalField "lib-version-info" L.foreignLibVersionInfo
145147
<*> optionalField "lib-version-linux" L.foreignLibVersionLinux
146148
<*> monoidalFieldAla "mod-def-file" (alaList' FSep FilePathNT) L.foreignLibModDefFile
147-
{-# SPECIALIZE foreignLibFieldGrammar :: UnqualComponentName -> ParsecFieldGrammar' ForeignLib #-}
149+
{-# SPECIALIZE foreignLibFieldGrammar :: UnqualComponentName -> ParsecFieldGrammar' CabalSpecOld ForeignLib #-}
150+
{-# SPECIALIZE foreignLibFieldGrammar :: UnqualComponentName -> ParsecFieldGrammar' CabalSpecV22 ForeignLib #-}
148151
{-# SPECIALIZE foreignLibFieldGrammar :: UnqualComponentName -> PrettyFieldGrammar' ForeignLib #-}
149152

150153
-------------------------------------------------------------------------------
@@ -159,7 +162,8 @@ executableFieldGrammar n = Executable n
159162
<$> optionalFieldDefAla "main-is" FilePathNT L.modulePath ""
160163
<*> monoidalField "scope" L.exeScope
161164
<*> blurFieldGrammar L.buildInfo buildInfoFieldGrammar
162-
{-# SPECIALIZE executableFieldGrammar :: UnqualComponentName -> ParsecFieldGrammar' Executable #-}
165+
{-# SPECIALIZE executableFieldGrammar :: UnqualComponentName -> ParsecFieldGrammar' CabalSpecOld Executable #-}
166+
{-# SPECIALIZE executableFieldGrammar :: UnqualComponentName -> ParsecFieldGrammar' CabalSpecV22 Executable #-}
163167
{-# SPECIALIZE executableFieldGrammar :: UnqualComponentName -> PrettyFieldGrammar' Executable #-}
164168

165169
-------------------------------------------------------------------------------
@@ -404,7 +408,8 @@ buildInfoFieldGrammar = BuildInfo
404408
<*> prefixedFields "x-" L.customFieldsBI
405409
<*> monoidalFieldAla "build-depends" (alaList CommaVCat) L.targetBuildDepends
406410
<*> monoidalFieldAla "mixins" (alaList CommaVCat) L.mixins
407-
{-# SPECIALIZE buildInfoFieldGrammar :: ParsecFieldGrammar' BuildInfo #-}
411+
{-# SPECIALIZE buildInfoFieldGrammar :: ParsecFieldGrammar' CabalSpecOld BuildInfo #-}
412+
{-# SPECIALIZE buildInfoFieldGrammar :: ParsecFieldGrammar' CabalSpecV22 BuildInfo #-}
408413
{-# SPECIALIZE buildInfoFieldGrammar :: PrettyFieldGrammar' BuildInfo #-}
409414

410415
hsSourceDirsGrammar
@@ -487,7 +492,8 @@ flagFieldGrammar name = MkFlag name
487492
<$> optionalFieldDefAla "description" FreeText L.flagDescription ""
488493
<*> booleanFieldDef "default" L.flagDefault True
489494
<*> booleanFieldDef "manual" L.flagManual False
490-
{-# SPECIALIZE flagFieldGrammar :: FlagName -> ParsecFieldGrammar' Flag #-}
495+
{-# SPECIALIZE flagFieldGrammar :: FlagName -> ParsecFieldGrammar' CabalSpecOld Flag #-}
496+
{-# SPECIALIZE flagFieldGrammar :: FlagName -> ParsecFieldGrammar' CabalSpecV22 Flag #-}
491497
{-# SPECIALIZE flagFieldGrammar :: FlagName -> PrettyFieldGrammar' Flag #-}
492498

493499
-------------------------------------------------------------------------------
@@ -504,7 +510,8 @@ sourceRepoFieldGrammar kind = SourceRepo kind
504510
<*> optionalFieldAla "branch" Token L.repoBranch
505511
<*> optionalFieldAla "tag" Token L.repoTag
506512
<*> optionalFieldAla "subdir" FilePathNT L.repoSubdir
507-
{-# SPECIALIZE sourceRepoFieldGrammar :: RepoKind -> ParsecFieldGrammar' SourceRepo #-}
513+
{-# SPECIALIZE sourceRepoFieldGrammar :: RepoKind -> ParsecFieldGrammar' CabalSpecOld SourceRepo #-}
514+
{-# SPECIALIZE sourceRepoFieldGrammar :: RepoKind -> ParsecFieldGrammar' CabalSpecV22 SourceRepo #-}
508515
{-# SPECIALIZE sourceRepoFieldGrammar :: RepoKind ->PrettyFieldGrammar' SourceRepo #-}
509516

510517
-------------------------------------------------------------------------------
@@ -516,5 +523,6 @@ setupBInfoFieldGrammar
516523
=> Bool -> g SetupBuildInfo SetupBuildInfo
517524
setupBInfoFieldGrammar def = flip SetupBuildInfo def
518525
<$> monoidalFieldAla "setup-depends" (alaList CommaVCat) L.setupDepends
519-
{-# SPECIALIZE setupBInfoFieldGrammar :: Bool -> ParsecFieldGrammar' SetupBuildInfo #-}
526+
{-# SPECIALIZE setupBInfoFieldGrammar :: Bool -> ParsecFieldGrammar' CabalSpecOld SetupBuildInfo #-}
527+
{-# SPECIALIZE setupBInfoFieldGrammar :: Bool -> ParsecFieldGrammar' CabalSpecV22 SetupBuildInfo #-}
520528
{-# SPECIALIZE setupBInfoFieldGrammar :: Bool ->PrettyFieldGrammar' SetupBuildInfo #-}

0 commit comments

Comments
 (0)