module Distribution.Version (
Version,
mkVersion,
mkVersion',
versionNumbers,
nullVersion,
alterVersion,
showVersion,
VersionRange(..),
anyVersion, noVersion,
thisVersion, notThisVersion,
laterVersion, earlierVersion,
orLaterVersion, orEarlierVersion,
unionVersionRanges, intersectVersionRanges,
differenceVersionRanges,
invertVersionRange,
withinVersion,
majorBoundVersion,
betweenVersionsInclusive,
withinRange,
isAnyVersion,
isNoVersion,
isSpecificVersion,
simplifyVersionRange,
foldVersionRange,
foldVersionRange',
hasUpperBound,
hasLowerBound,
removeUpperBound,
removeLowerBound,
asVersionIntervals,
VersionInterval,
LowerBound(..),
UpperBound(..),
Bound(..),
VersionIntervals,
toVersionIntervals,
fromVersionIntervals,
withinIntervals,
versionIntervals,
mkVersionIntervals,
unionVersionIntervals,
intersectVersionIntervals,
invertVersionIntervals
) where
import Prelude ()
import Distribution.Compat.Prelude
import qualified Data.Version as Base
import Data.Bits (shiftL, shiftR, (.|.), (.&.))
import Distribution.Text
import qualified Distribution.Compat.ReadP as Parse
import Distribution.Compat.ReadP hiding (get)
import qualified Text.PrettyPrint as Disp
import Text.PrettyPrint ((<+>))
import Control.Exception (assert)
import qualified Text.Read as Read
data Version = PV0 !Word64
| PV1 !Int [Int]
deriving (Data,Eq,Generic,Typeable)
instance Ord Version where
compare (PV0 x) (PV0 y) = compare x y
compare (PV1 x xs) (PV1 y ys) = case compare x y of
EQ -> compare xs ys
c -> c
compare (PV0 w) (PV1 y ys) = case compare x y of
EQ -> compare [x2,x3,x4] ys
c -> c
where
x = fromIntegral ((w `shiftR` 48) .&. 0xffff) 1
x2 = fromIntegral ((w `shiftR` 32) .&. 0xffff) 1
x3 = fromIntegral ((w `shiftR` 16) .&. 0xffff) 1
x4 = fromIntegral (w .&. 0xffff) 1
compare (PV1 x xs) (PV0 w) = case compare x y of
EQ -> compare xs [y2,y3,y4]
c -> c
where
y = fromIntegral ((w `shiftR` 48) .&. 0xffff) 1
y2 = fromIntegral ((w `shiftR` 32) .&. 0xffff) 1
y3 = fromIntegral ((w `shiftR` 16) .&. 0xffff) 1
y4 = fromIntegral (w .&. 0xffff) 1
instance Show Version where
showsPrec d v = showParen (d > 10)
$ showString "mkVersion "
. showsPrec 11 (versionNumbers v)
instance Read Version where
readPrec = Read.parens $ do
Read.Ident "mkVersion" <- Read.lexP
v <- Read.step Read.readPrec
return (mkVersion v)
instance Binary Version
instance NFData Version where
rnf (PV0 _) = ()
rnf (PV1 _ ns) = rnf ns
instance Text Version where
disp ver
= Disp.hcat (Disp.punctuate (Disp.char '.')
(map Disp.int $ versionNumbers ver))
parse = do
branch <- Parse.sepBy1 parseNat (Parse.char '.')
_tags <- Parse.many (Parse.char '-' >> Parse.munch1 isAlphaNum)
return (mkVersion branch)
where
parseNat = read `fmap` Parse.munch1 isDigit
mkVersion :: [Int] -> Version
mkVersion [] = nullVersion
mkVersion (v1:[])
| inWord16VerRep1 v1 = PV0 (mkWord64VerRep1 v1)
| otherwise = PV1 v1 []
where
inWord16VerRep1 x1 = inWord16 (x1 .|. (x1+1))
mkWord64VerRep1 y1 = mkWord64VerRep (y1+1) 0 0 0
mkVersion (v1:vs@(v2:[]))
| inWord16VerRep2 v1 v2 = PV0 (mkWord64VerRep2 v1 v2)
| otherwise = PV1 v1 vs
where
inWord16VerRep2 x1 x2 = inWord16 (x1 .|. (x1+1)
.|. x2 .|. (x2+1))
mkWord64VerRep2 y1 y2 = mkWord64VerRep (y1+1) (y2+1) 0 0
mkVersion (v1:vs@(v2:v3:[]))
| inWord16VerRep3 v1 v2 v3 = PV0 (mkWord64VerRep3 v1 v2 v3)
| otherwise = PV1 v1 vs
where
inWord16VerRep3 x1 x2 x3 = inWord16 (x1 .|. (x1+1)
.|. x2 .|. (x2+1)
.|. x3 .|. (x3+1))
mkWord64VerRep3 y1 y2 y3 = mkWord64VerRep (y1+1) (y2+1) (y3+1) 0
mkVersion (v1:vs@(v2:v3:v4:[]))
| inWord16VerRep4 v1 v2 v3 v4 = PV0 (mkWord64VerRep4 v1 v2 v3 v4)
| otherwise = PV1 v1 vs
where
inWord16VerRep4 x1 x2 x3 x4 = inWord16 (x1 .|. (x1+1)
.|. x2 .|. (x2+1)
.|. x3 .|. (x3+1)
.|. x4 .|. (x4+1))
mkWord64VerRep4 y1 y2 y3 y4 = mkWord64VerRep (y1+1) (y2+1) (y3+1) (y4+1)
mkVersion (v1:vs) = PV1 v1 vs
mkWord64VerRep :: Int -> Int -> Int -> Int -> Word64
mkWord64VerRep v1 v2 v3 v4 =
(fromIntegral v1 `shiftL` 48)
.|. (fromIntegral v2 `shiftL` 32)
.|. (fromIntegral v3 `shiftL` 16)
.|. fromIntegral v4
inWord16 :: Int -> Bool
inWord16 x = (fromIntegral x :: Word) <= 0xffff
mkVersion' :: Base.Version -> Version
mkVersion' = mkVersion . Base.versionBranch
versionNumbers :: Version -> [Int]
versionNumbers (PV1 n ns) = n:ns
versionNumbers (PV0 w)
| v1 < 0 = []
| v2 < 0 = [v1]
| v3 < 0 = [v1,v2]
| v4 < 0 = [v1,v2,v3]
| otherwise = [v1,v2,v3,v4]
where
v1 = fromIntegral ((w `shiftR` 48) .&. 0xffff) 1
v2 = fromIntegral ((w `shiftR` 32) .&. 0xffff) 1
v3 = fromIntegral ((w `shiftR` 16) .&. 0xffff) 1
v4 = fromIntegral (w .&. 0xffff) 1
nullVersion :: Version
nullVersion = PV0 0
alterVersion :: ([Int] -> [Int]) -> Version -> Version
alterVersion f = mkVersion . f . versionNumbers
validVersion :: Version -> Bool
validVersion v = v /= nullVersion && all (>=0) (versionNumbers v)
showVersion :: Version -> String
showVersion = display
data VersionRange
= AnyVersion
| ThisVersion Version
| LaterVersion Version
| EarlierVersion Version
| WildcardVersion Version
| MajorBoundVersion Version
| UnionVersionRanges VersionRange VersionRange
| IntersectVersionRanges VersionRange VersionRange
| VersionRangeParens VersionRange
deriving (Data, Eq, Generic, Read, Show, Typeable)
instance Binary VersionRange
instance NFData VersionRange where rnf = genericRnf
anyVersion :: VersionRange
anyVersion = AnyVersion
noVersion :: VersionRange
noVersion = IntersectVersionRanges (LaterVersion v) (EarlierVersion v)
where v = mkVersion [1]
thisVersion :: Version -> VersionRange
thisVersion = ThisVersion
notThisVersion :: Version -> VersionRange
notThisVersion v = UnionVersionRanges (EarlierVersion v) (LaterVersion v)
laterVersion :: Version -> VersionRange
laterVersion = LaterVersion
orLaterVersion :: Version -> VersionRange
orLaterVersion v = UnionVersionRanges (ThisVersion v) (LaterVersion v)
earlierVersion :: Version -> VersionRange
earlierVersion = EarlierVersion
orEarlierVersion :: Version -> VersionRange
orEarlierVersion v = UnionVersionRanges (ThisVersion v) (EarlierVersion v)
unionVersionRanges :: VersionRange -> VersionRange -> VersionRange
unionVersionRanges = UnionVersionRanges
intersectVersionRanges :: VersionRange -> VersionRange -> VersionRange
intersectVersionRanges = IntersectVersionRanges
differenceVersionRanges :: VersionRange -> VersionRange -> VersionRange
differenceVersionRanges vr1 vr2 =
intersectVersionRanges vr1 (invertVersionRange vr2)
invertVersionRange :: VersionRange -> VersionRange
invertVersionRange =
fromVersionIntervals . invertVersionIntervals
. VersionIntervals . asVersionIntervals
withinVersion :: Version -> VersionRange
withinVersion = WildcardVersion
majorBoundVersion :: Version -> VersionRange
majorBoundVersion = MajorBoundVersion
betweenVersionsInclusive :: Version -> Version -> VersionRange
betweenVersionsInclusive v1 v2 =
IntersectVersionRanges (orLaterVersion v1) (orEarlierVersion v2)
removeUpperBound :: VersionRange -> VersionRange
removeUpperBound = fromVersionIntervals . relaxLastInterval . toVersionIntervals
where
relaxLastInterval (VersionIntervals intervals) =
VersionIntervals (relaxLastInterval' intervals)
relaxLastInterval' [] = []
relaxLastInterval' [(l,_)] = [(l, NoUpperBound)]
relaxLastInterval' (i:is) = i : relaxLastInterval' is
removeLowerBound :: VersionRange -> VersionRange
removeLowerBound = fromVersionIntervals . relaxHeadInterval . toVersionIntervals
where
relaxHeadInterval (VersionIntervals intervals) =
VersionIntervals (relaxHeadInterval' intervals)
relaxHeadInterval' [] = []
relaxHeadInterval' ((_,u):is) = (minLowerBound,u) : is
foldVersionRange :: a
-> (Version -> a)
-> (Version -> a)
-> (Version -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> VersionRange -> a
foldVersionRange anyv this later earlier union intersect = fold
where
fold AnyVersion = anyv
fold (ThisVersion v) = this v
fold (LaterVersion v) = later v
fold (EarlierVersion v) = earlier v
fold (WildcardVersion v) = fold (wildcard v)
fold (MajorBoundVersion v) = fold (majorBound v)
fold (UnionVersionRanges v1 v2) = union (fold v1) (fold v2)
fold (IntersectVersionRanges v1 v2) = intersect (fold v1) (fold v2)
fold (VersionRangeParens v) = fold v
wildcard v = intersectVersionRanges
(orLaterVersion v)
(earlierVersion (wildcardUpperBound v))
majorBound v = intersectVersionRanges
(orLaterVersion v)
(earlierVersion (majorUpperBound v))
foldVersionRange' :: a
-> (Version -> a)
-> (Version -> a)
-> (Version -> a)
-> (Version -> a)
-> (Version -> a)
-> (Version -> Version -> a)
-> (Version -> Version -> a)
-> (a -> a -> a)
-> (a -> a -> a)
-> (a -> a)
-> VersionRange -> a
foldVersionRange' anyv this later earlier orLater orEarlier
wildcard major union intersect parens = fold
where
fold AnyVersion = anyv
fold (ThisVersion v) = this v
fold (LaterVersion v) = later v
fold (EarlierVersion v) = earlier v
fold (UnionVersionRanges (ThisVersion v)
(LaterVersion v')) | v==v' = orLater v
fold (UnionVersionRanges (LaterVersion v)
(ThisVersion v')) | v==v' = orLater v
fold (UnionVersionRanges (ThisVersion v)
(EarlierVersion v')) | v==v' = orEarlier v
fold (UnionVersionRanges (EarlierVersion v)
(ThisVersion v')) | v==v' = orEarlier v
fold (WildcardVersion v) = wildcard v (wildcardUpperBound v)
fold (MajorBoundVersion v) = major v (majorUpperBound v)
fold (UnionVersionRanges v1 v2) = union (fold v1) (fold v2)
fold (IntersectVersionRanges v1 v2) = intersect (fold v1) (fold v2)
fold (VersionRangeParens v) = parens (fold v)
withinRange :: Version -> VersionRange -> Bool
withinRange v = foldVersionRange
True
(\v' -> v == v')
(\v' -> v > v')
(\v' -> v < v')
(||)
(&&)
asVersionIntervals :: VersionRange -> [VersionInterval]
asVersionIntervals = versionIntervals . toVersionIntervals
isAnyVersion :: VersionRange -> Bool
isAnyVersion vr = case asVersionIntervals vr of
[(LowerBound v InclusiveBound, NoUpperBound)] | isVersion0 v -> True
_ -> False
isNoVersion :: VersionRange -> Bool
isNoVersion vr = case asVersionIntervals vr of
[] -> True
_ -> False
isSpecificVersion :: VersionRange -> Maybe Version
isSpecificVersion vr = case asVersionIntervals vr of
[(LowerBound v InclusiveBound
,UpperBound v' InclusiveBound)]
| v == v' -> Just v
_ -> Nothing
simplifyVersionRange :: VersionRange -> VersionRange
simplifyVersionRange vr
| null (versionIntervals vi) = vr
| otherwise = fromVersionIntervals vi
where
vi = toVersionIntervals vr
wildcardUpperBound :: Version -> Version
wildcardUpperBound = alterVersion $
\lowerBound -> init lowerBound ++ [last lowerBound + 1]
isWildcardRange :: Version -> Version -> Bool
isWildcardRange ver1 ver2 = check (versionNumbers ver1) (versionNumbers ver2)
where check (n:[]) (m:[]) | n+1 == m = True
check (n:ns) (m:ms) | n == m = check ns ms
check _ _ = False
majorUpperBound :: Version -> Version
majorUpperBound = alterVersion $ \numbers -> case numbers of
[] -> [0,1]
[m1] -> [m1,1]
(m1:m2:_) -> [m1,m2+1]
newtype VersionIntervals = VersionIntervals [VersionInterval]
deriving (Eq, Show)
versionIntervals :: VersionIntervals -> [VersionInterval]
versionIntervals (VersionIntervals is) = is
type VersionInterval = (LowerBound, UpperBound)
data LowerBound = LowerBound Version !Bound deriving (Eq, Show)
data UpperBound = NoUpperBound | UpperBound Version !Bound deriving (Eq, Show)
data Bound = ExclusiveBound | InclusiveBound deriving (Eq, Show)
minLowerBound :: LowerBound
minLowerBound = LowerBound (mkVersion [0]) InclusiveBound
isVersion0 :: Version -> Bool
isVersion0 = (== mkVersion [0])
instance Ord LowerBound where
LowerBound ver bound <= LowerBound ver' bound' = case compare ver ver' of
LT -> True
EQ -> not (bound == ExclusiveBound && bound' == InclusiveBound)
GT -> False
instance Ord UpperBound where
_ <= NoUpperBound = True
NoUpperBound <= UpperBound _ _ = False
UpperBound ver bound <= UpperBound ver' bound' = case compare ver ver' of
LT -> True
EQ -> not (bound == InclusiveBound && bound' == ExclusiveBound)
GT -> False
invariant :: VersionIntervals -> Bool
invariant (VersionIntervals intervals) = all validInterval intervals
&& all doesNotTouch' adjacentIntervals
where
doesNotTouch' :: (VersionInterval, VersionInterval) -> Bool
doesNotTouch' ((_,u), (l',_)) = doesNotTouch u l'
adjacentIntervals :: [(VersionInterval, VersionInterval)]
adjacentIntervals
| null intervals = []
| otherwise = zip intervals (tail intervals)
checkInvariant :: VersionIntervals -> VersionIntervals
checkInvariant is = assert (invariant is) is
mkVersionIntervals :: [VersionInterval] -> Maybe VersionIntervals
mkVersionIntervals intervals
| invariant (VersionIntervals intervals) = Just (VersionIntervals intervals)
| otherwise = Nothing
validInterval :: (LowerBound, UpperBound) -> Bool
validInterval i@(l, u) = validLower l && validUpper u && nonEmpty i
where
validLower (LowerBound v _) = validVersion v
validUpper NoUpperBound = True
validUpper (UpperBound v _) = validVersion v
nonEmpty :: VersionInterval -> Bool
nonEmpty (_, NoUpperBound ) = True
nonEmpty (LowerBound l lb, UpperBound u ub) =
(l < u) || (l == u && lb == InclusiveBound && ub == InclusiveBound)
doesNotTouch :: UpperBound -> LowerBound -> Bool
doesNotTouch NoUpperBound _ = False
doesNotTouch (UpperBound u ub) (LowerBound l lb) =
u < l
|| (u == l && ub == ExclusiveBound && lb == ExclusiveBound)
doesNotIntersect :: UpperBound -> LowerBound -> Bool
doesNotIntersect NoUpperBound _ = False
doesNotIntersect (UpperBound u ub) (LowerBound l lb) =
u < l
|| (u == l && not (ub == InclusiveBound && lb == InclusiveBound))
withinIntervals :: Version -> VersionIntervals -> Bool
withinIntervals v (VersionIntervals intervals) = any withinInterval intervals
where
withinInterval (lowerBound, upperBound) = withinLower lowerBound
&& withinUpper upperBound
withinLower (LowerBound v' ExclusiveBound) = v' < v
withinLower (LowerBound v' InclusiveBound) = v' <= v
withinUpper NoUpperBound = True
withinUpper (UpperBound v' ExclusiveBound) = v' > v
withinUpper (UpperBound v' InclusiveBound) = v' >= v
toVersionIntervals :: VersionRange -> VersionIntervals
toVersionIntervals = foldVersionRange
( chkIvl (minLowerBound, NoUpperBound))
(\v -> chkIvl (LowerBound v InclusiveBound, UpperBound v InclusiveBound))
(\v -> chkIvl (LowerBound v ExclusiveBound, NoUpperBound))
(\v -> if isVersion0 v then VersionIntervals [] else
chkIvl (minLowerBound, UpperBound v ExclusiveBound))
unionVersionIntervals
intersectVersionIntervals
where
chkIvl interval = checkInvariant (VersionIntervals [interval])
fromVersionIntervals :: VersionIntervals -> VersionRange
fromVersionIntervals (VersionIntervals []) = noVersion
fromVersionIntervals (VersionIntervals intervals) =
foldr1 UnionVersionRanges [ interval l u | (l, u) <- intervals ]
where
interval (LowerBound v InclusiveBound)
(UpperBound v' InclusiveBound) | v == v'
= ThisVersion v
interval (LowerBound v InclusiveBound)
(UpperBound v' ExclusiveBound) | isWildcardRange v v'
= WildcardVersion v
interval l u = lowerBound l `intersectVersionRanges'` upperBound u
lowerBound (LowerBound v InclusiveBound)
| isVersion0 v = AnyVersion
| otherwise = orLaterVersion v
lowerBound (LowerBound v ExclusiveBound) = LaterVersion v
upperBound NoUpperBound = AnyVersion
upperBound (UpperBound v InclusiveBound) = orEarlierVersion v
upperBound (UpperBound v ExclusiveBound) = EarlierVersion v
intersectVersionRanges' vr AnyVersion = vr
intersectVersionRanges' AnyVersion vr = vr
intersectVersionRanges' vr vr' = IntersectVersionRanges vr vr'
unionVersionIntervals :: VersionIntervals -> VersionIntervals
-> VersionIntervals
unionVersionIntervals (VersionIntervals is0) (VersionIntervals is'0) =
checkInvariant (VersionIntervals (union is0 is'0))
where
union is [] = is
union [] is' = is'
union (i:is) (i':is') = case unionInterval i i' of
Left Nothing -> i : union is (i' :is')
Left (Just i'') -> union is (i'':is')
Right Nothing -> i' : union (i :is) is'
Right (Just i'') -> union (i'':is) is'
unionInterval :: VersionInterval -> VersionInterval
-> Either (Maybe VersionInterval) (Maybe VersionInterval)
unionInterval (lower , upper ) (lower', upper')
| upper `doesNotTouch` lower' = Left Nothing
| upper' `doesNotTouch` lower = Right Nothing
| upper <= upper' = lowerBound `seq`
Left (Just (lowerBound, upper'))
| otherwise = lowerBound `seq`
Right (Just (lowerBound, upper))
where
lowerBound = min lower lower'
intersectVersionIntervals :: VersionIntervals -> VersionIntervals
-> VersionIntervals
intersectVersionIntervals (VersionIntervals is0) (VersionIntervals is'0) =
checkInvariant (VersionIntervals (intersect is0 is'0))
where
intersect _ [] = []
intersect [] _ = []
intersect (i:is) (i':is') = case intersectInterval i i' of
Left Nothing -> intersect is (i':is')
Left (Just i'') -> i'' : intersect is (i':is')
Right Nothing -> intersect (i:is) is'
Right (Just i'') -> i'' : intersect (i:is) is'
intersectInterval :: VersionInterval -> VersionInterval
-> Either (Maybe VersionInterval) (Maybe VersionInterval)
intersectInterval (lower , upper ) (lower', upper')
| upper `doesNotIntersect` lower' = Left Nothing
| upper' `doesNotIntersect` lower = Right Nothing
| upper <= upper' = lowerBound `seq`
Left (Just (lowerBound, upper))
| otherwise = lowerBound `seq`
Right (Just (lowerBound, upper'))
where
lowerBound = max lower lower'
invertVersionIntervals :: VersionIntervals
-> VersionIntervals
invertVersionIntervals (VersionIntervals xs) =
case xs of
[] -> VersionIntervals [(noLowerBound, NoUpperBound)]
((lb, ub) : more) | lb == noLowerBound ->
VersionIntervals $ invertVersionIntervals' ub more
((lb, ub) : more) ->
VersionIntervals $ (noLowerBound, invertLowerBound lb)
: invertVersionIntervals' ub more
where
invertVersionIntervals' :: UpperBound
-> [(LowerBound, UpperBound)]
-> [(LowerBound, UpperBound)]
invertVersionIntervals' NoUpperBound [] = []
invertVersionIntervals' ub0 [] = [(invertUpperBound ub0, NoUpperBound)]
invertVersionIntervals' ub0 [(lb, NoUpperBound)] =
[(invertUpperBound ub0, invertLowerBound lb)]
invertVersionIntervals' ub0 ((lb, ub1) : more) =
(invertUpperBound ub0, invertLowerBound lb)
: invertVersionIntervals' ub1 more
invertLowerBound :: LowerBound -> UpperBound
invertLowerBound (LowerBound v b) = UpperBound v (invertBound b)
invertUpperBound :: UpperBound -> LowerBound
invertUpperBound (UpperBound v b) = LowerBound v (invertBound b)
invertUpperBound NoUpperBound = error "NoUpperBound: unexpected"
invertBound :: Bound -> Bound
invertBound ExclusiveBound = InclusiveBound
invertBound InclusiveBound = ExclusiveBound
noLowerBound :: LowerBound
noLowerBound = LowerBound (mkVersion [0]) InclusiveBound
instance Text VersionRange where
disp = fst
. foldVersionRange'
( Disp.text "-any" , 0 :: Int)
(\v -> (Disp.text "==" <<>> disp v , 0))
(\v -> (Disp.char '>' <<>> disp v , 0))
(\v -> (Disp.char '<' <<>> disp v , 0))
(\v -> (Disp.text ">=" <<>> disp v , 0))
(\v -> (Disp.text "<=" <<>> disp v , 0))
(\v _ -> (Disp.text "==" <<>> dispWild v , 0))
(\v _ -> (Disp.text "^>=" <<>> disp v , 0))
(\(r1, p1) (r2, p2) ->
(punct 2 p1 r1 <+> Disp.text "||" <+> punct 2 p2 r2 , 2))
(\(r1, p1) (r2, p2) ->
(punct 1 p1 r1 <+> Disp.text "&&" <+> punct 1 p2 r2 , 1))
(\(r, _) -> (Disp.parens r, 0))
where dispWild ver =
Disp.hcat (Disp.punctuate (Disp.char '.')
(map Disp.int $ versionNumbers ver))
<<>> Disp.text ".*"
punct p p' | p < p' = Disp.parens
| otherwise = id
parse = expr
where
expr = do Parse.skipSpaces
t <- term
Parse.skipSpaces
(do _ <- Parse.string "||"
Parse.skipSpaces
e <- expr
return (UnionVersionRanges t e)
+++
return t)
term = do f <- factor
Parse.skipSpaces
(do _ <- Parse.string "&&"
Parse.skipSpaces
t <- term
return (IntersectVersionRanges f t)
+++
return f)
factor = Parse.choice $ parens expr
: parseAnyVersion
: parseNoVersion
: parseWildcardRange
: map parseRangeOp rangeOps
parseAnyVersion = Parse.string "-any" >> return AnyVersion
parseNoVersion = Parse.string "-none" >> return noVersion
parseWildcardRange = do
_ <- Parse.string "=="
Parse.skipSpaces
branch <- Parse.sepBy1 digits (Parse.char '.')
_ <- Parse.char '.'
_ <- Parse.char '*'
return (WildcardVersion (mkVersion branch))
parens p = Parse.between (Parse.char '(' >> Parse.skipSpaces)
(Parse.char ')' >> Parse.skipSpaces)
(do a <- p
Parse.skipSpaces
return (VersionRangeParens a))
digits = do
firstDigit <- Parse.satisfy isDigit
if firstDigit == '0'
then return 0
else do rest <- Parse.munch isDigit
return (read (firstDigit : rest))
parseRangeOp (s,f) = Parse.string s >> Parse.skipSpaces >> fmap f parse
rangeOps = [ ("<", EarlierVersion),
("<=", orEarlierVersion),
(">", LaterVersion),
(">=", orLaterVersion),
("^>=", MajorBoundVersion),
("==", ThisVersion) ]
hasUpperBound :: VersionRange -> Bool
hasUpperBound = foldVersionRange
False
(const True)
(const False)
(const True)
(&&) (||)
hasLowerBound :: VersionRange -> Bool
hasLowerBound = foldVersionRange
False
(const True)
(const True)
(const False)
(&&) (||)