Skip to content

Commit f4ba42a

Browse files
committed
Allow imports in conditional sections
- Warn about missplaced import (on top level) - Warn in trees
1 parent 064d9e9 commit f4ba42a

File tree

6 files changed

+719
-30
lines changed

6 files changed

+719
-30
lines changed

Cabal/Cabal.cabal

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ extra-source-files:
8484
tests/ParserTests/regressions/bad-glob-syntax.check
8585
tests/ParserTests/regressions/cc-options-with-optimization.cabal
8686
tests/ParserTests/regressions/cc-options-with-optimization.check
87+
tests/ParserTests/regressions/common-conditional.cabal
88+
tests/ParserTests/regressions/common-conditional.expr
89+
tests/ParserTests/regressions/common-conditional.format
8790
tests/ParserTests/regressions/common.cabal
8891
tests/ParserTests/regressions/common.expr
8992
tests/ParserTests/regressions/common.format

Cabal/Distribution/PackageDescription/Parsec.hs

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -419,30 +419,35 @@ parseFields v fields grammar = do
419419

420420
warnInvalidSubsection :: Section Position -> ParseResult ()
421421
warnInvalidSubsection (MkSection (Name pos name) _ _) =
422-
void (parseFailure pos $ "invalid subsection " ++ show name)
422+
void $ parseFailure pos $ "invalid subsection " ++ show name
423423

424424
parseCondTree
425-
:: forall a c.
426-
CabalSpecVersion
427-
-> HasElif -- ^ accept @elif@
428-
-> ParsecFieldGrammar' a -- ^ grammar
429-
-> (a -> c) -- ^ condition extractor
425+
:: forall a. FromBuildInfo a
426+
=> CabalSpecVersion
427+
-> HasElif -- ^ accept @elif@
428+
-> ParsecFieldGrammar' a -- ^ grammar
429+
-> Map String CondTreeBuildInfo -- ^ common stanzas
430+
-> (a -> [Dependency]) -- ^ condition extractor
430431
-> [Field Position]
431-
-> ParseResult (CondTree ConfVar c a)
432-
parseCondTree v hasElif grammar cond = go
432+
-> ParseResult (CondTree ConfVar [Dependency] a)
433+
parseCondTree v hasElif grammar commonStanzas cond = go
433434
where
434-
go fields = do
435+
go fields0 = do
436+
(fields, endo) <-
437+
if v >= CabalSpecV3_0
438+
then processImports v commonStanzas fields0
439+
else traverse_ (warnImport v) fields0 >> return (fields0, id)
440+
435441
let (fs, ss) = partitionFields fields
436442
x <- parseFieldGrammar v fs grammar
437443
branches <- concat <$> traverse parseIfs ss
438-
return (CondNode x (cond x) branches) -- TODO: branches
444+
return $ endo $ CondNode x (cond x) branches
439445

440-
parseIfs :: [Section Position] -> ParseResult [CondBranch ConfVar c a]
446+
parseIfs :: [Section Position] -> ParseResult [CondBranch ConfVar [Dependency] a]
441447
parseIfs [] = return []
442448
parseIfs (MkSection (Name _ name) test fields : sections) | name == "if" = do
443449
test' <- parseConditionConfVar test
444450
fields' <- go fields
445-
-- TODO: else
446451
(elseFields, sections') <- parseElseIfs sections
447452
return (CondBranch test' fields' elseFields : sections')
448453
parseIfs (MkSection (Name pos name) _ _ : sections) = do
@@ -451,7 +456,7 @@ parseCondTree v hasElif grammar cond = go
451456

452457
parseElseIfs
453458
:: [Section Position]
454-
-> ParseResult (Maybe (CondTree ConfVar c a), [CondBranch ConfVar c a])
459+
-> ParseResult (Maybe (CondTree ConfVar [Dependency] a), [CondBranch ConfVar [Dependency] a])
455460
parseElseIfs [] = return (Nothing, [])
456461
parseElseIfs (MkSection (Name pos name) args fields : sections) | name == "else" = do
457462
unless (null args) $
@@ -460,10 +465,7 @@ parseCondTree v hasElif grammar cond = go
460465
sections' <- parseIfs sections
461466
return (Just elseFields, sections')
462467

463-
464-
465468
parseElseIfs (MkSection (Name _ name) test fields : sections) | hasElif == HasElif, name == "elif" = do
466-
-- TODO: check cabal-version
467469
test' <- parseConditionConfVar test
468470
fields' <- go fields
469471
(elseFields, sections') <- parseElseIfs sections
@@ -560,21 +562,31 @@ parseCondTreeWithCommonStanzas
560562
-> Map String CondTreeBuildInfo -- ^ common stanzas
561563
-> [Field Position]
562564
-> ParseResult (CondTree ConfVar [Dependency] a)
563-
parseCondTreeWithCommonStanzas v grammar commonStanzas = goImports []
565+
parseCondTreeWithCommonStanzas v grammar commonStanzas fields = do
566+
(fields', endo) <- processImports v commonStanzas fields
567+
x <- parseCondTree v hasElif grammar commonStanzas (view L.targetBuildDepends) fields'
568+
return (endo x)
564569
where
565570
hasElif = specHasElif v
571+
572+
processImports
573+
:: forall a. FromBuildInfo a
574+
=> CabalSpecVersion
575+
-> Map String CondTreeBuildInfo -- ^ common stanzas
576+
-> [Field Position]
577+
-> ParseResult ([Field Position], CondTree ConfVar [Dependency] a -> CondTree ConfVar [Dependency] a)
578+
processImports v commonStanzas = go []
579+
where
566580
hasCommonStanzas = specHasCommonStanzas v
567581

568582
getList' :: List CommaFSep Token String -> [String]
569583
getList' = Newtype.unpack
570584

571-
-- parse leading imports
572-
-- not supported:
573-
goImports acc (Field (Name pos name) _ : fields) | name == "import", hasCommonStanzas == NoCommonStanzas = do
585+
go acc (Field (Name pos name) _ : fields) | name == "import", hasCommonStanzas == NoCommonStanzas = do
574586
parseWarning pos PWTUnknownField "Unknown field: import. You should set cabal-version: 2.2 or larger to use common stanzas"
575-
goImports acc fields
587+
go acc fields
576588
-- supported:
577-
goImports acc (Field (Name pos name) fls : fields) | name == "import" = do
589+
go acc (Field (Name pos name) fls : fields) | name == "import" = do
578590
names <- getList' <$> runFieldParser pos parsec v fls
579591
names' <- for names $ \commonName ->
580592
case Map.lookup commonName commonStanzas of
@@ -584,16 +596,19 @@ parseCondTreeWithCommonStanzas v grammar commonStanzas = goImports []
584596
Just commonTree ->
585597
pure (Just commonTree)
586598

587-
goImports (acc ++ catMaybes names') fields
599+
go (acc ++ catMaybes names') fields
588600

589-
-- Go to parsing condTree after first non-import 'Field'.
590-
goImports acc fields = go acc fields
601+
-- TODO: and filter!
602+
go acc fields = do
603+
traverse_ (warnImport v) fields
604+
return (fields, \x -> foldr mergeCommonStanza x acc)
591605

592-
-- parse actual CondTree
593-
go :: [CondTreeBuildInfo] -> [Field Position] -> ParseResult (CondTree ConfVar [Dependency] a)
594-
go bis fields = do
595-
x <- parseCondTree v hasElif grammar (view L.targetBuildDepends) fields
596-
pure $ foldr mergeCommonStanza x bis
606+
warnImport :: CabalSpecVersion -> Field Position -> ParseResult ()
607+
warnImport v (Field (Name pos name) _) | name == "import" =
608+
if specHasCommonStanzas v == NoCommonStanzas
609+
then parseWarning pos PWTUnknownField "Unknown field: import. You should set cabal-version: 2.2 or larger to use common stanzas"
610+
else parseWarning pos PWTUnknownField "Unknown field: import. Common stanza imports should be at the top of the enclosing section"
611+
warnImport _ _ = pure ()
597612

598613
mergeCommonStanza
599614
:: forall a. FromBuildInfo a

Cabal/tests/ParserTests.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ regressionTests = testGroup "regressions"
140140
, regressionTest "shake.cabal"
141141
, regressionTest "common.cabal"
142142
, regressionTest "common2.cabal"
143+
, regressionTest "common-conditional.cabal"
143144
, regressionTest "leading-comma.cabal"
144145
, regressionTest "wl-pprint-indef.cabal"
145146
, regressionTest "th-lift-instances.cabal"
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
cabal-version: 2.6
2+
name: common-conditional
3+
version: 0
4+
synopsis: Common-stanza demo demo
5+
build-type: Simple
6+
7+
source-repository head
8+
Type: git
9+
Location: https://github.com/hvr/-.git
10+
11+
flag foo
12+
manual: True
13+
default: True
14+
15+
common win-dows
16+
if os(windows)
17+
build-depends: Win32
18+
19+
common deps
20+
import: win-dows
21+
buildable: True
22+
build-depends:
23+
base >=4.10 && <4.11,
24+
containers
25+
26+
library
27+
if flag(foo)
28+
import: deps
29+
30+
default-language: Haskell2010
31+
exposed-modules: ElseIf
32+
33+
build-depends:
34+
ghc-prim
35+
36+
test-suite tests
37+
-- buildable fields verify that we don't have duplicate field warnings
38+
buildable: True
39+
if os(windows)
40+
buildable: False
41+
42+
if flag(foo)
43+
import: deps, win-dows
44+
45+
type: exitcode-stdio-1.0
46+
main-is: Tests.hs
47+
48+
build-depends:
49+
HUnit

0 commit comments

Comments
 (0)