Skip to content

Commit ec6966e

Browse files
authored
Merge pull request #5566 from phadej/if-import
PoC: If import
2 parents 1c86abe + a05db9b commit ec6966e

File tree

6 files changed

+771
-30
lines changed

6 files changed

+771
-30
lines changed

Cabal/Cabal.cabal

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ extra-source-files:
8888
tests/ParserTests/regressions/bad-glob-syntax.check
8989
tests/ParserTests/regressions/cc-options-with-optimization.cabal
9090
tests/ParserTests/regressions/cc-options-with-optimization.check
91+
tests/ParserTests/regressions/common-conditional.cabal
92+
tests/ParserTests/regressions/common-conditional.expr
93+
tests/ParserTests/regressions/common-conditional.format
9194
tests/ParserTests/regressions/common.cabal
9295
tests/ParserTests/regressions/common.expr
9396
tests/ParserTests/regressions/common.format

Cabal/Distribution/PackageDescription/Parsec.hs

Lines changed: 49 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -418,30 +418,36 @@ parseFields v fields grammar = do
418418

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

423423
parseCondTree
424-
:: forall a c.
425-
CabalSpecVersion
426-
-> HasElif -- ^ accept @elif@
427-
-> ParsecFieldGrammar' a -- ^ grammar
428-
-> (a -> c) -- ^ condition extractor
424+
:: forall a. L.HasBuildInfo a
425+
=> CabalSpecVersion
426+
-> HasElif -- ^ accept @elif@
427+
-> ParsecFieldGrammar' a -- ^ grammar
428+
-> Map String CondTreeBuildInfo -- ^ common stanzas
429+
-> (BuildInfo -> a) -- ^ constructor from buildInfo
430+
-> (a -> [Dependency]) -- ^ condition extractor
429431
-> [Field Position]
430-
-> ParseResult (CondTree ConfVar c a)
431-
parseCondTree v hasElif grammar cond = go
432+
-> ParseResult (CondTree ConfVar [Dependency] a)
433+
parseCondTree v hasElif grammar commonStanzas fromBuildInfo cond = go
432434
where
433-
go fields = do
435+
go fields0 = do
436+
(fields, endo) <-
437+
if v >= CabalSpecV3_0
438+
then processImports v fromBuildInfo commonStanzas fields0
439+
else traverse (warnImport v) fields0 >>= \fields1 -> return (catMaybes fields1, id)
440+
434441
let (fs, ss) = partitionFields fields
435442
x <- parseFieldGrammar v fs grammar
436443
branches <- concat <$> traverse parseIfs ss
437-
return (CondNode x (cond x) branches) -- TODO: branches
444+
return $ endo $ CondNode x (cond x) branches
438445

439-
parseIfs :: [Section Position] -> ParseResult [CondBranch ConfVar c a]
446+
parseIfs :: [Section Position] -> ParseResult [CondBranch ConfVar [Dependency] a]
440447
parseIfs [] = return []
441448
parseIfs (MkSection (Name _ name) test fields : sections) | name == "if" = do
442449
test' <- parseConditionConfVar test
443450
fields' <- go fields
444-
-- TODO: else
445451
(elseFields, sections') <- parseElseIfs sections
446452
return (CondBranch test' fields' elseFields : sections')
447453
parseIfs (MkSection (Name pos name) _ _ : sections) = do
@@ -450,7 +456,7 @@ parseCondTree v hasElif grammar cond = go
450456

451457
parseElseIfs
452458
:: [Section Position]
453-
-> ParseResult (Maybe (CondTree ConfVar c a), [CondBranch ConfVar c a])
459+
-> ParseResult (Maybe (CondTree ConfVar [Dependency] a), [CondBranch ConfVar [Dependency] a])
454460
parseElseIfs [] = return (Nothing, [])
455461
parseElseIfs (MkSection (Name pos name) args fields : sections) | name == "else" = do
456462
unless (null args) $
@@ -459,10 +465,7 @@ parseCondTree v hasElif grammar cond = go
459465
sections' <- parseIfs sections
460466
return (Just elseFields, sections')
461467

462-
463-
464468
parseElseIfs (MkSection (Name _ name) test fields : sections) | hasElif == HasElif, name == "elif" = do
465-
-- TODO: check cabal-version
466469
test' <- parseConditionConfVar test
467470
fields' <- go fields
468471
(elseFields, sections') <- parseElseIfs sections
@@ -566,21 +569,32 @@ parseCondTreeWithCommonStanzas
566569
-> Map String CondTreeBuildInfo -- ^ common stanzas
567570
-> [Field Position]
568571
-> ParseResult (CondTree ConfVar [Dependency] a)
569-
parseCondTreeWithCommonStanzas v grammar fromBuildInfo commonStanzas = goImports []
572+
parseCondTreeWithCommonStanzas v grammar fromBuildInfo commonStanzas fields = do
573+
(fields', endo) <- processImports v fromBuildInfo commonStanzas fields
574+
x <- parseCondTree v hasElif grammar commonStanzas fromBuildInfo (view L.targetBuildDepends) fields'
575+
return (endo x)
570576
where
571577
hasElif = specHasElif v
578+
579+
processImports
580+
:: forall a. L.HasBuildInfo a
581+
=> CabalSpecVersion
582+
-> (BuildInfo -> a) -- ^ construct fromBuildInfo
583+
-> Map String CondTreeBuildInfo -- ^ common stanzas
584+
-> [Field Position]
585+
-> ParseResult ([Field Position], CondTree ConfVar [Dependency] a -> CondTree ConfVar [Dependency] a)
586+
processImports v fromBuildInfo commonStanzas = go []
587+
where
572588
hasCommonStanzas = specHasCommonStanzas v
573589

574590
getList' :: List CommaFSep Token String -> [String]
575591
getList' = Newtype.unpack
576592

577-
-- parse leading imports
578-
-- not supported:
579-
goImports acc (Field (Name pos name) _ : fields) | name == "import", hasCommonStanzas == NoCommonStanzas = do
593+
go acc (Field (Name pos name) _ : fields) | name == "import", hasCommonStanzas == NoCommonStanzas = do
580594
parseWarning pos PWTUnknownField "Unknown field: import. You should set cabal-version: 2.2 or larger to use common stanzas"
581-
goImports acc fields
595+
go acc fields
582596
-- supported:
583-
goImports acc (Field (Name pos name) fls : fields) | name == "import" = do
597+
go acc (Field (Name pos name) fls : fields) | name == "import" = do
584598
names <- getList' <$> runFieldParser pos parsec v fls
585599
names' <- for names $ \commonName ->
586600
case Map.lookup commonName commonStanzas of
@@ -590,16 +604,21 @@ parseCondTreeWithCommonStanzas v grammar fromBuildInfo commonStanzas = goImports
590604
Just commonTree ->
591605
pure (Just commonTree)
592606

593-
goImports (acc ++ catMaybes names') fields
594-
595-
-- Go to parsing condTree after first non-import 'Field'.
596-
goImports acc fields = go acc fields
607+
go (acc ++ catMaybes names') fields
597608

598609
-- parse actual CondTree
599-
go :: [CondTreeBuildInfo] -> [Field Position] -> ParseResult (CondTree ConfVar [Dependency] a)
600-
go bis fields = do
601-
x <- parseCondTree v hasElif grammar (view L.targetBuildDepends) fields
602-
pure $ foldr (mergeCommonStanza fromBuildInfo) x bis
610+
go acc fields = do
611+
fields' <- catMaybes <$> traverse (warnImport v) fields
612+
pure $ (fields', \x -> foldr (mergeCommonStanza fromBuildInfo) x acc)
613+
614+
-- | Warn on "import" fields, also map to Maybe, so errorneous fields can be filtered
615+
warnImport :: CabalSpecVersion -> Field Position -> ParseResult (Maybe (Field Position))
616+
warnImport v (Field (Name pos name) _) | name == "import" = do
617+
if specHasCommonStanzas v == NoCommonStanzas
618+
then parseWarning pos PWTUnknownField "Unknown field: import. You should set cabal-version: 2.2 or larger to use common stanzas"
619+
else parseWarning pos PWTUnknownField "Unknown field: import. Common stanza imports should be at the top of the enclosing section"
620+
return Nothing
621+
warnImport _ f = pure (Just f)
603622

604623
mergeCommonStanza
605624
:: L.HasBuildInfo a

Cabal/tests/ParserTests.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ regressionTests = testGroup "regressions"
142142
, regressionTest "shake.cabal"
143143
, regressionTest "common.cabal"
144144
, regressionTest "common2.cabal"
145+
, regressionTest "common-conditional.cabal"
145146
, regressionTest "leading-comma.cabal"
146147
, regressionTest "wl-pprint-indef.cabal"
147148
, 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)