Skip to content

Commit

Permalink
Rework version range parser
Browse files Browse the repository at this point in the history
- No more `try`
- It recognises wild-card version after all operators,
  but fails with more descriptive warning after non-==
  Fixes haskell#989
  • Loading branch information
phadej committed Dec 25, 2017
1 parent 70fd4d2 commit 4f11f21
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 24 deletions.
2 changes: 2 additions & 0 deletions Cabal/Cabal.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ extra-source-files:
tests/ParserTests/errors/common3.errors
tests/ParserTests/errors/leading-comma.cabal
tests/ParserTests/errors/leading-comma.errors
tests/ParserTests/errors/range-ge-wild.cabal
tests/ParserTests/errors/range-ge-wild.errors
tests/ParserTests/regressions/Octree-0.5.cabal
tests/ParserTests/regressions/Octree-0.5.format
tests/ParserTests/regressions/common.cabal
Expand Down
72 changes: 48 additions & 24 deletions Cabal/Distribution/Types/VersionRange.hs
Original file line number Diff line number Diff line change
Expand Up @@ -411,37 +411,61 @@ instance Parsec VersionRange where
return (intersectVersionRanges f t)
<|>
return f)
factor = P.choice
$ parens expr
: parseAnyVersion
: parseNoVersion
: parseWildcardRange
: map parseRangeOp rangeOps
parseAnyVersion = P.string "-any" >> return anyVersion
parseNoVersion = P.string "-none" >> return noVersion

parseWildcardRange = P.try $ do
_ <- P.string "=="
P.spaces
branch <- some (P.integral <* P.char '.')
_ <- P.char '*'
return (withinVersion (mkVersion branch))
factor = parens expr <|> prim

prim = do
op <- P.munch1 (`elem` "<>=^-") P.<?> "operator"
case op of
"-" -> anyVersion <$ P.string "any" <|> noVersion <$ P.string "none"

"==" -> do
P.spaces
(wild, v) <- verOrWild
pure $ (if wild then withinVersion else thisVersion) v

_ -> do
P.spaces
(wild, v) <- verOrWild
when wild $ P.unexpected $
"wild-card version after non-== operator: " ++ show op
case op of
">=" -> pure $ orLaterVersion v
"<" -> pure $ earlierVersion v
"^>=" -> pure $ majorBoundVersion v
"<=" -> pure $ orEarlierVersion v
">" -> pure $ laterVersion v
_ -> fail $ "Unknown version operator " ++ show op

-- either wildcard or normal version
verOrWild :: CabalParsing m => m (Bool, Version)
verOrWild = do
x <- P.integral
verLoop (x :)

-- trailing: wildcard (.y.*) or normal version (optional tags) (.y.z-tag)
verLoop :: CabalParsing m => ([Int] -> [Int]) -> m (Bool, Version)
verLoop acc = verLoop' acc <|> (tags >> pure (False, mkVersion (acc [])))

verLoop' :: CabalParsing m => ([Int] -> [Int]) -> m (Bool, Version)
verLoop' acc = do
_ <- P.char '.'
((\x -> verLoop (acc . (x :))) =<< P.integral)
<|> (\_ -> (True, mkVersion (acc []))) <$> P.char '*'

parens p = P.between
(P.char '(' >> P.spaces)
((P.char '(' P.<?> "opening paren") >> P.spaces)
(P.char ')' >> P.spaces)
(do a <- p
P.spaces
return (VersionRangeParens a))

-- TODO: make those non back-tracking
parseRangeOp (s,f) = P.try (P.string s *> P.spaces *> fmap f parsec)
rangeOps = [ ("<", earlierVersion),
("<=", orEarlierVersion),
(">", laterVersion),
(">=", orLaterVersion),
("^>=", majorBoundVersion),
("==", thisVersion) ]
tags :: CabalParsing m => m ()
tags = do
ts <- many $ P.char '-' *> some (P.satisfy isAlphaNum)
case ts of
[] -> pure ()
(_ : _) -> parsecWarning PWTVersionTag "version with tags"


instance Text VersionRange where
parse = expr
Expand Down
1 change: 1 addition & 0 deletions Cabal/tests/ParserTests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ errorTests = testGroup "errors"
, errorTest "common2.cabal"
, errorTest "common3.cabal"
, errorTest "leading-comma.cabal"
, errorTest "range-ge-wild.cabal"
]

errorTest :: FilePath -> TestTree
Expand Down
8 changes: 8 additions & 0 deletions Cabal/tests/ParserTests/errors/range-ge-wild.cabal
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
name: range-ge-wild
version: 0
synopsis: Wild range after non-== op
build-type: Simple
cabal-version: >=1.10

library
build-depends: base >= 4.*
1 change: 1 addition & 0 deletions Cabal/tests/ParserTests/errors/range-ge-wild.errors
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PError (Position 8 29) "\nunexpected wild-card version after non-== operator: \">=\": \"base >= 4.*\""

0 comments on commit 4f11f21

Please sign in to comment.