-----------------------------------------------------------------------------
-- |
-- Module      :  Distribution.Version
-- Copyright   :  Isaac Jones, Simon Marlow 2003-2004
--                Duncan Coutts 2008
--
-- Maintainer  :  cabal-devel@haskell.org
-- Portability :  portable
--
-- Exports the 'Version' type along with a parser and pretty printer. A version
-- is something like @\"1.3.3\"@. It also defines the 'VersionRange' data
-- types. Version ranges are like @\">= 1.2 && < 2\"@.

{- Copyright (c) 2003-2004, Isaac Jones
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.

    * Neither the name of Isaac Jones nor the names of other
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -}

module Distribution.Version (
  -- * Package versions
  Version(..),

  -- * Version ranges
  VersionRange(..),

  -- ** Constructing
  anyVersion, noVersion,
  thisVersion, notThisVersion,
  laterVersion, earlierVersion,
  orLaterVersion, orEarlierVersion,
  unionVersionRanges, intersectVersionRanges,
  withinVersion,
  betweenVersionsInclusive,

  -- ** Inspection
  withinRange,
  isAnyVersion,
  isNoVersion,
  isSpecificVersion,
  simplifyVersionRange,
  foldVersionRange,
  foldVersionRange',

  -- * Version intervals view
  asVersionIntervals,
  VersionInterval,
  LowerBound(..),
  UpperBound(..),
  Bound(..),

  -- ** 'VersionIntervals' abstract type
  -- | The 'VersionIntervals' type and the accompanying functions are exposed
  -- primarily for completeness and testing purposes. In practice
  -- 'asVersionIntervals' is the main function to use to
  -- view a 'VersionRange' as a bunch of 'VersionInterval's.
  --
  VersionIntervals,
  toVersionIntervals,
  fromVersionIntervals,
  withinIntervals,
  versionIntervals,
  mkVersionIntervals,
  unionVersionIntervals,
  intersectVersionIntervals,

 ) where

import Data.Version     ( Version(..) )

import Distribution.Text ( Text(..) )
import qualified Distribution.Compat.ReadP as Parse
import Distribution.Compat.ReadP ((+++))
import qualified Text.PrettyPrint as Disp
import Text.PrettyPrint ((<>), (<+>))
import qualified Data.Char as Char (isDigit)
import Control.Exception (assert)

-- -----------------------------------------------------------------------------
-- Version ranges

-- Todo: maybe move this to Distribution.Package.Version?
-- (package-specific versioning scheme).

data VersionRange
  = AnyVersion
  | ThisVersion            Version -- = version
  | LaterVersion           Version -- > version  (NB. not >=)
  | EarlierVersion         Version -- < version
  | WildcardVersion        Version -- == ver.*   (same as >= ver && < ver+1)
  | UnionVersionRanges     VersionRange VersionRange
  | IntersectVersionRanges VersionRange VersionRange
  | VersionRangeParens     VersionRange -- just '(exp)' parentheses syntax
  deriving (D:Show ::
  (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> T:Show aShow,D:Read ::
  (Int -> ReadS a)
  -> ReadS [a]
  -> ReadPrec a
  -> ReadPrec [a]
  -> T:Read aRead,D:Eq :: (a -> a -> Bool) -> (a -> a -> Bool) -> T:Eq aEq)

{-# DEPRECATED AnyVersion "Use 'anyVersion', 'foldVersionRange' or 'asVersionIntervals'" #-}
{-# DEPRECATED ThisVersion "use 'thisVersion', 'foldVersionRange' or 'asVersionIntervals'" #-}
{-# DEPRECATED LaterVersion "use 'laterVersion', 'foldVersionRange' or 'asVersionIntervals'" #-}
{-# DEPRECATED EarlierVersion "use 'earlierVersion', 'foldVersionRange' or 'asVersionIntervals'" #-}
{-# DEPRECATED WildcardVersion "use 'anyVersion', 'foldVersionRange' or 'asVersionIntervals'" #-}
{-# DEPRECATED UnionVersionRanges "use 'unionVersionRanges', 'foldVersionRange' or 'asVersionIntervals'" #-}
{-# DEPRECATED IntersectVersionRanges "use 'intersectVersionRanges', 'foldVersionRange' or 'asVersionIntervals'" #-}

-- | The version range @-any@. That is, a version range containing all
-- versions.
--
-- > withinRange v anyVersion = True
--
anyVersion :: VersionRange
anyVersion = AnyVersion :: VersionRangeAnyVersion

-- | The empty version range, that is a version range containing no versions.
--
-- This can be constructed using any unsatisfiable version range expression,
-- for example @> 1 && < 1@.
--
-- > withinRange v anyVersion = False
--
noVersion :: VersionRange
noVersion = IntersectVersionRanges ::
  VersionRange -> VersionRange -> VersionRangeIntersectVersionRanges (LaterVersion :: Version -> VersionRangeLaterVersion v :: Versionv) (EarlierVersion :: Version -> VersionRangeEarlierVersion v :: Versionv)
  where v = Version :: [Int] -> [String] -> VersionVersion [1] [] :: [a][]

-- | The version range @== v@
--
-- > withinRange v' (thisVersion v) = v' == v
--
thisVersion :: Version -> VersionRange
thisVersion = ThisVersion :: Version -> VersionRangeThisVersion

-- | The version range @< v || > v@
--
-- > withinRange v' (notThisVersion v) = v' /= v
--
notThisVersion :: Version -> VersionRange
notThisVersion v = UnionVersionRanges :: VersionRange -> VersionRange -> VersionRangeUnionVersionRanges (EarlierVersion :: Version -> VersionRangeEarlierVersion v :: Versionv) (LaterVersion :: Version -> VersionRangeLaterVersion v :: Versionv)

-- | The version range @> v@
--
-- > withinRange v' (laterVersion v) = v' > v
--
laterVersion :: Version -> VersionRange
laterVersion = LaterVersion :: Version -> VersionRangeLaterVersion

-- | The version range @>= v@
--
-- > withinRange v' (orLaterVersion v) = v' >= v
--
orLaterVersion :: Version -> VersionRange
orLaterVersion   v = UnionVersionRanges :: VersionRange -> VersionRange -> VersionRangeUnionVersionRanges (ThisVersion :: Version -> VersionRangeThisVersion v :: Versionv) (LaterVersion :: Version -> VersionRangeLaterVersion v :: Versionv)

-- | The version range @< v@
--
-- > withinRange v' (earlierVersion v) = v' < v
--
earlierVersion :: Version -> VersionRange
earlierVersion = EarlierVersion :: Version -> VersionRangeEarlierVersion

-- | The version range @<= v@
--
-- > withinRange v' (orEarlierVersion v) = v' <= v
--
orEarlierVersion :: Version -> VersionRange
orEarlierVersion v = UnionVersionRanges :: VersionRange -> VersionRange -> VersionRangeUnionVersionRanges (ThisVersion :: Version -> VersionRangeThisVersion v :: Versionv) (EarlierVersion :: Version -> VersionRangeEarlierVersion v :: Versionv)

-- | The version range @vr1 || vr2@
--
-- >   withinRange v' (unionVersionRanges vr1 vr2)
-- > = withinRange v' vr1 || withinRange v' vr2
--
unionVersionRanges :: VersionRange -> VersionRange -> VersionRange
unionVersionRanges = UnionVersionRanges :: VersionRange -> VersionRange -> VersionRangeUnionVersionRanges

-- | The version range @vr1 && vr2@
--
-- >   withinRange v' (intersectVersionRanges vr1 vr2)
-- > = withinRange v' vr1 && withinRange v' vr2
--
intersectVersionRanges :: VersionRange -> VersionRange -> VersionRange
intersectVersionRanges = IntersectVersionRanges ::
  VersionRange -> VersionRange -> VersionRangeIntersectVersionRanges

-- | The version range @== v.*@.
--
-- For example, for version @1.2@, the version range @== 1.2.*@ is the same as
-- @>= 1.2 && < 1.3@
--
-- > withinRange v' (laterVersion v) = v' >= v && v' < upper v
-- >   where
-- >     upper (Version lower t) = Version (init lower ++ [last lower + 1]) t
--
withinVersion :: Version -> VersionRange
withinVersion = WildcardVersion :: Version -> VersionRangeWildcardVersion

-- | The version range @>= v1 && <= v2@.
--
-- In practice this is not very useful because we normally use inclusive lower
-- bounds and exclusive upper bounds.
--
-- > withinRange v' (laterVersion v) = v' > v
--
betweenVersionsInclusive :: Version -> Version -> VersionRange
betweenVersionsInclusive v1 v2 =
  IntersectVersionRanges ::
  VersionRange -> VersionRange -> VersionRangeIntersectVersionRanges (orLaterVersion :: Version -> VersionRangeorLaterVersion v1 :: VersionRangev1) (orEarlierVersion :: Version -> VersionRangeorEarlierVersion v2 :: VersionRangev2)

{-# DEPRECATED betweenVersionsInclusive
    "In practice this is not very useful because we normally use inclusive lower bounds and exclusive upper bounds"
  #-}

-- | Fold over the basic syntactic structure of a 'VersionRange'.
--
-- This provides a syntacic view of the expression defining the version range.
-- The syntactic sugar @\">= v\"@, @\"<= v\"@ and @\"== v.*\"@ is presented
-- in terms of the other basic syntax.
--
-- For a semantic view use 'asVersionIntervals'.
--
foldVersionRange :: a                         -- ^ @\"-any\"@ version
                 -> (Version -> a)            -- ^ @\"== v\"@
                 -> (Version -> a)            -- ^ @\"> v\"@
                 -> (Version -> a)            -- ^ @\"< v\"@
                 -> (a -> a -> a)             -- ^ @\"_ || _\"@ union
                 -> (a -> a -> a)             -- ^ @\"_ && _\"@ intersection
                 -> VersionRange -> a
foldVersionRange anyv this later earlier union intersect = fold :: VersionRange -> afold
  where
    fold AnyVersion                     = anyv :: aanyv
    fold (ThisVersion v)                = this :: Version -> athis v :: Versionv
    fold (LaterVersion v)               = later :: Version -> alater v :: Versionv
    fold (EarlierVersion v)             = earlier :: Version -> aearlier v :: Versionv
    fold (WildcardVersion v)            = fold :: VersionRange -> afold (wildcard :: Version -> VersionRangewildcard v :: Versionv)
    fold (UnionVersionRanges v1 v2)     = union :: a -> a -> aunion (fold :: VersionRange -> afold v1 :: VersionRangev1) (fold :: VersionRange -> afold v2 :: VersionRangev2)
    fold (IntersectVersionRanges v1 v2) = intersect :: a -> a -> aintersect (fold :: VersionRange -> afold v1 :: VersionRangev1) (fold :: VersionRange -> afold v2 :: VersionRangev2)
    fold (VersionRangeParens v)         = fold :: VersionRange -> afold v :: Versionv

    wildcard v = intersectVersionRanges ::
  VersionRange -> VersionRange -> VersionRangeintersectVersionRanges
                   (orLaterVersion :: Version -> VersionRangeorLaterVersion v :: Versionv)
                   (earlierVersion :: Version -> VersionRangeearlierVersion (wildcardUpperBound :: Version -> VersionwildcardUpperBound v :: Versionv))

-- | An extended variant of 'foldVersionRange' that also provides a view of
-- in which the syntactic sugar @\">= v\"@, @\"<= v\"@ and @\"== v.*\"@ is presented
-- explicitly rather than in terms of the other basic syntax.
--
foldVersionRange' :: a                         -- ^ @\"-any\"@ version
                  -> (Version -> a)            -- ^ @\"== v\"@
                  -> (Version -> a)            -- ^ @\"> v\"@
                  -> (Version -> a)            -- ^ @\"< v\"@
                  -> (Version -> a)            -- ^ @\">= v\"@
                  -> (Version -> a)            -- ^ @\"<= v\"@
                  -> (Version -> Version -> a) -- ^ @\"== v.*\"@ wildcard. The
                                               -- function is passed the
                                               -- inclusive lower bound and the
                                               -- exclusive upper bounds of the
                                               -- range defined by the wildcard.
                  -> (a -> a -> a)             -- ^ @\"_ || _\"@ union
                  -> (a -> a -> a)             -- ^ @\"_ && _\"@ intersection
                  -> (a -> a)                  -- ^ @\"(_)\"@ parentheses
                  -> VersionRange -> a
foldVersionRange' anyv this later earlier orLater orEarlier
                  wildcard union intersect parens = fold :: VersionRange -> afold
  where
    fold AnyVersion                     = anyv :: aanyv
    fold (ThisVersion v)                = this :: Version -> athis v :: Versionv
    fold (LaterVersion v)               = later :: Version -> alater v :: Versionv
    fold (EarlierVersion v)             = earlier :: Version -> aearlier v :: Versionv

    fold (UnionVersionRanges (ThisVersion    v)
                             (LaterVersion   v')) | v :: Versionv(==) :: Eq a => a -> a -> Bool==v' :: Versionv' = orLater :: Version -> aorLater v :: Versionv
    fold (UnionVersionRanges (LaterVersion   v)
                             (ThisVersion    v')) | v :: Versionv(==) :: Eq a => a -> a -> Bool==v' :: Versionv' = orLater :: Version -> aorLater v :: Versionv
    fold (UnionVersionRanges (ThisVersion    v)
                             (EarlierVersion v')) | v :: Versionv(==) :: Eq a => a -> a -> Bool==v' :: Versionv' = orEarlier :: Version -> aorEarlier v :: Versionv
    fold (UnionVersionRanges (EarlierVersion v)
                             (ThisVersion    v')) | v :: Versionv(==) :: Eq a => a -> a -> Bool==v' :: Versionv' = orEarlier :: Version -> aorEarlier v :: Versionv

    fold (WildcardVersion v)            = wildcard :: Version -> VersionRangewildcard v :: Versionv (wildcardUpperBound :: Version -> VersionwildcardUpperBound v :: Versionv)
    fold (UnionVersionRanges v1 v2)     = union :: a -> a -> aunion (fold :: VersionRange -> afold v1 :: VersionRangev1) (fold :: VersionRange -> afold v2 :: VersionRangev2)
    fold (IntersectVersionRanges v1 v2) = intersect :: a -> a -> aintersect (fold :: VersionRange -> afold v1 :: VersionRangev1) (fold :: VersionRange -> afold v2 :: VersionRangev2)
    fold (VersionRangeParens v)         = parens :: Parser r Char VersionRange -> ReadP r VersionRangeparens (fold :: VersionRange -> afold v :: Versionv)


-- | Does this version fall within the given range?
--
-- This is the evaluation function for the 'VersionRange' type.
--
withinRange :: Version -> VersionRange -> Bool
withinRange v = foldVersionRange ::
  a
  -> (Version -> a)
  -> (Version -> a)
  -> (Version -> a)
  -> (a -> a -> a)
  -> (a -> a -> a)
  -> VersionRange
  -> afoldVersionRange
                   True :: BoolTrue
                   (\v'  -> versionBranch :: Version -> [Int]versionBranch v :: Versionv (==) :: Eq a => a -> a -> Bool== versionBranch :: Version -> [Int]versionBranch v' :: Versionv')
                   (\v'  -> versionBranch :: Version -> [Int]versionBranch v :: Versionv (>) :: Ord a => a -> a -> Bool>  versionBranch :: Version -> [Int]versionBranch v' :: Versionv')
                   (\v'  -> versionBranch :: Version -> [Int]versionBranch v :: Versionv (<) :: Ord a => a -> a -> Bool<  versionBranch :: Version -> [Int]versionBranch v' :: Versionv')
                   (||) :: Bool -> Bool -> Bool(||)
                   (&&) :: Bool -> Bool -> Bool(&&)

-- | View a 'VersionRange' as a union of intervals.
--
-- This provides a canonical view of the semantics of a 'VersionRange' as
-- opposed to the syntax of the expression used to define it. For the syntactic
-- view use 'foldVersionRange'.
--
-- Each interval is non-empty. The sequence is in increasing order and no
-- intervals overlap or touch. Therefore only the first and last can be
-- unbounded. The sequence can be empty if the range is empty
-- (e.g. a range expression like @< 1 && > 2@).
--
-- Other checks are trivial to implement using this view. For example:
--
-- > isNoVersion vr | [] <- asVersionIntervals vr = True
-- >                | otherwise                   = False
--
-- > isSpecificVersion vr
-- >    | [(LowerBound v  InclusiveBound
-- >       ,UpperBound v' InclusiveBound)] <- asVersionIntervals vr
-- >    , v == v'   = Just v
-- >    | otherwise = Nothing
--
asVersionIntervals :: VersionRange -> [VersionInterval]
asVersionIntervals = versionIntervals :: VersionIntervals -> [VersionInterval]versionIntervals (.) :: (b -> c) -> (a -> b) -> a -> c. toVersionIntervals :: VersionRange -> VersionIntervalstoVersionIntervals

-- | Does this 'VersionRange' place any restriction on the 'Version' or is it
-- in fact equivalent to 'AnyVersion'.
--
-- Note this is a semantic check, not simply a syntactic check. So for example
-- the following is @True@ (for all @v@).
--
-- > isAnyVersion (EarlierVersion v `UnionVersionRanges` orLaterVersion v)
--
isAnyVersion :: VersionRange -> Bool
isAnyVersion vr = case asVersionIntervals :: VersionRange -> [VersionInterval]asVersionIntervals vr :: VersionRangevr of
  [(LowerBound v InclusiveBound, NoUpperBound)] | isVersion0 :: Version -> BoolisVersion0 v :: Versionv -> True :: BoolTrue
  _                                                            -> False :: BoolFalse

-- | This is the converse of 'isAnyVersion'. It check if the version range is
-- empty, if there is no possible version that satisfies the version range.
--
-- For example this is @True@ (for all @v@):
--
-- > isNoVersion (EarlierVersion v `IntersectVersionRanges` LaterVersion v)
--
isNoVersion :: VersionRange -> Bool
isNoVersion vr = case asVersionIntervals :: VersionRange -> [VersionInterval]asVersionIntervals vr :: VersionRangevr of
  [] -> True :: BoolTrue
  _  -> False :: BoolFalse

-- | Is this version range in fact just a specific version?
--
-- For example the version range @\">= 3 && <= 3\"@ contains only the version
-- @3@.
--
isSpecificVersion :: VersionRange -> Maybe Version
isSpecificVersion vr = case asVersionIntervals :: VersionRange -> [VersionInterval]asVersionIntervals vr :: VersionRangevr of
  [(LowerBound v  InclusiveBound
   ,UpperBound v' InclusiveBound)]
    | v :: Versionv (==) :: Eq a => a -> a -> Bool== v' :: Versionv' -> Just :: a -> Maybe aJust v :: Versionv
  _           -> Nothing :: Maybe aNothing

-- | Simplify a 'VersionRange' expression. For non-empty version ranges
-- this produces a canonical form. Empty or inconsistent version ranges
-- are left as-is because that provides more information.
--
-- If you need a canonical form use
-- @fromVersionIntervals . toVersionIntervals@
--
-- It satisfies the following properties:
--
-- > withinRange v (simplifyVersionRange r) = withinRange v r
--
-- >     withinRange v r = withinRange v r'
-- > ==> simplifyVersionRange r = simplifyVersionRange r'
-- >  || isNoVersion r
-- >  || isNoVersion r'
--
simplifyVersionRange :: VersionRange -> VersionRange
simplifyVersionRange vr
    -- If the version range is inconsistent then we just return the
    -- original since that has more information than ">1 && < 1", which
    -- is the canonical inconsistent version range.
    | null :: [a] -> Boolnull (versionIntervals :: VersionIntervals -> [VersionInterval]versionIntervals vi :: VersionIntervalsvi) = vr :: VersionRangevr
    | otherwise :: Boolotherwise                  = fromVersionIntervals :: VersionIntervals -> VersionRangefromVersionIntervals vi :: VersionIntervalsvi
  where
    vi = toVersionIntervals :: VersionRange -> VersionIntervalstoVersionIntervals vr :: VersionRangevr

----------------------------
-- Wildcard range utilities
--

wildcardUpperBound :: Version -> Version
wildcardUpperBound (Version lowerBound ts) = (Version :: [Int] -> [String] -> VersionVersion upperBound :: UpperBound -> VersionRangeupperBound ts :: [String]ts)
  where
    upperBound = init :: [a] -> [a]init lowerBound :: LowerBound -> VersionRangelowerBound (++) :: [a] -> [a] -> [a]++ [last :: [a] -> alast lowerBound :: LowerBound -> VersionRangelowerBound (+) :: Num a => a -> a -> a+ 1]

isWildcardRange :: Version -> Version -> Bool
isWildcardRange (Version branch1 _) (Version branch2 _) = check :: [a] -> [a] -> Boolcheck branch1 :: [Int]branch1 branch2 :: [Int]branch2
  where check (n:[]) (m:[]) | n :: an(+) :: Num a => a -> a -> a+1 (==) :: Eq a => a -> a -> Bool== m :: am = True :: BoolTrue
        check (n:ns) (m:ms) | n :: an   (==) :: Eq a => a -> a -> Bool== m :: am = check :: [a] -> [a] -> Boolcheck ns :: [a]ns ms :: [a]ms
        check _      _                 = False :: BoolFalse

------------------
-- Intervals view
--

-- | A complementary representation of a 'VersionRange'. Instead of a boolean
-- version predicate it uses an increasing sequence of non-overlapping,
-- non-empty intervals.
--
-- The key point is that this representation gives a canonical representation
-- for the semantics of 'VersionRange's. This makes it easier to check things
-- like whether a version range is empty, covers all versions, or requires a
-- certain minimum or maximum version. It also makes it easy to check equality
-- or containment. It also makes it easier to identify \'simple\' version
-- predicates for translation into foreign packaging systems that do not
-- support complex version range expressions.
--
newtype VersionIntervals = VersionIntervals [VersionInterval]
  deriving (D:Eq :: (a -> a -> Bool) -> (a -> a -> Bool) -> T:Eq aEq, D:Show ::
  (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> T:Show aShow)

-- | Inspect the list of version intervals.
--
versionIntervals :: VersionIntervals -> [VersionInterval]
versionIntervals (VersionIntervals is) = is :: [VersionInterval]is

type VersionInterval = (LowerBound, UpperBound)
data LowerBound =                LowerBound Version !Bound deriving (D:Eq :: (a -> a -> Bool) -> (a -> a -> Bool) -> T:Eq aEq, D:Show ::
  (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> T:Show aShow)
data UpperBound = NoUpperBound | UpperBound Version !Bound deriving (D:Eq :: (a -> a -> Bool) -> (a -> a -> Bool) -> T:Eq aEq, D:Show ::
  (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> T:Show aShow)
data Bound      = ExclusiveBound | InclusiveBound          deriving (D:Eq :: (a -> a -> Bool) -> (a -> a -> Bool) -> T:Eq aEq, D:Show ::
  (Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> T:Show aShow)

minLowerBound :: LowerBound
minLowerBound = ($WLowerBound) :: Version -> Bound -> LowerBoundLowerBound (Version :: [Int] -> [String] -> VersionVersion [0] [] :: [a][]) InclusiveBound :: BoundInclusiveBound

isVersion0 :: Version -> Bool
isVersion0 (Version [0] _) = True :: BoolTrue
isVersion0 _               = False :: BoolFalse

instance D:Ord ::
  Eq a =>
  (a -> a -> Ordering)
  -> (a -> a -> Bool)
  -> (a -> a -> Bool)
  -> (a -> a -> Bool)
  -> (a -> a -> Bool)
  -> (a -> a -> a)
  -> (a -> a -> a)
  -> T:Ord aOrd LowerBound where
  LowerBound ver bound <= LowerBound ver' bound' = case compare :: Ord a => a -> a -> Orderingcompare ver :: Versionver ver' :: Versionver' of
    LT -> True :: BoolTrue
    EQ -> not :: Bool -> Boolnot (bound :: Boundbound (==) :: Eq a => a -> a -> Bool== ExclusiveBound :: BoundExclusiveBound (&&) :: Bool -> Bool -> Bool&& bound' :: Boundbound' (==) :: Eq a => a -> a -> Bool== InclusiveBound :: BoundInclusiveBound)
    GT -> False :: BoolFalse

instance D:Ord ::
  Eq a =>
  (a -> a -> Ordering)
  -> (a -> a -> Bool)
  -> (a -> a -> Bool)
  -> (a -> a -> Bool)
  -> (a -> a -> Bool)
  -> (a -> a -> a)
  -> (a -> a -> a)
  -> T:Ord aOrd UpperBound where
  _            <= NoUpperBound   = True :: BoolTrue
  NoUpperBound <= UpperBound _ _ = False :: BoolFalse
  UpperBound ver bound <= UpperBound ver' bound' = case compare :: Ord a => a -> a -> Orderingcompare ver :: Versionver ver' :: Versionver' of
    LT -> True :: BoolTrue
    EQ -> not :: Bool -> Boolnot (bound :: Boundbound (==) :: Eq a => a -> a -> Bool== InclusiveBound :: BoundInclusiveBound (&&) :: Bool -> Bool -> Bool&& bound' :: Boundbound' (==) :: Eq a => a -> a -> Bool== ExclusiveBound :: BoundExclusiveBound)
    GT -> False :: BoolFalse

invariant :: VersionIntervals -> Bool
invariant (VersionIntervals intervals) = all :: (a -> Bool) -> [a] -> Boolall validInterval :: (LowerBound, UpperBound) -> BoolvalidInterval intervals :: [VersionInterval]intervals
                                      (&&) :: Bool -> Bool -> Bool&& all :: (a -> Bool) -> [a] -> Boolall doesNotTouch' :: (VersionInterval, VersionInterval) -> BooldoesNotTouch' adjacentIntervals :: [(VersionInterval, VersionInterval)]adjacentIntervals
  where
    doesNotTouch' :: (VersionInterval, VersionInterval) -> Bool
    doesNotTouch' ((_,u), (l',_)) = doesNotTouch :: UpperBound -> LowerBound -> BooldoesNotTouch u :: UpperBoundu l' :: LowerBoundl'

    adjacentIntervals :: [(VersionInterval, VersionInterval)]
    adjacentIntervals
      | null :: [a] -> Boolnull intervals :: [VersionInterval]intervals = [] :: [a][]
      | otherwise :: Boolotherwise      = zip :: [a] -> [b] -> [(a, b)]zip intervals :: [VersionInterval]intervals (tail :: [a] -> [a]tail intervals :: [VersionInterval]intervals)

checkInvariant :: VersionIntervals -> VersionIntervals
checkInvariant is = assertError :: Addr# -> Bool -> a -> aassert (invariant :: VersionIntervals -> Boolinvariant is :: [VersionInterval]is) is :: [VersionInterval]is

-- | Directly construct a 'VersionIntervals' from a list of intervals.
--
-- Each interval must be non-empty. The sequence must be in increasing order
-- and no invervals may overlap or touch. If any of these conditions are not
-- satisfied the function returns @Nothing@.
--
mkVersionIntervals :: [VersionInterval] -> Maybe VersionIntervals
mkVersionIntervals intervals
  | invariant :: VersionIntervals -> Boolinvariant (VersionIntervals :: [VersionInterval] -> VersionIntervalsVersionIntervals intervals :: [VersionInterval]intervals) = Just :: a -> Maybe aJust (VersionIntervals :: [VersionInterval] -> VersionIntervalsVersionIntervals intervals :: [VersionInterval]intervals)
  | otherwise :: Boolotherwise                              = Nothing :: Maybe aNothing

validVersion :: Version -> Bool
validVersion (Version [] _) = False :: BoolFalse
validVersion (Version vs _) = all :: (a -> Bool) -> [a] -> Boolall ((>=) :: Ord a => a -> a -> Bool>=0) vs :: [Int]vs

validInterval :: (LowerBound, UpperBound) -> Bool
validInterval i@(l, u) = validLower :: LowerBound -> BoolvalidLower l :: LowerBoundl (&&) :: Bool -> Bool -> Bool&& validUpper :: UpperBound -> BoolvalidUpper u :: UpperBoundu (&&) :: Bool -> Bool -> Bool&& nonEmpty :: VersionInterval -> BoolnonEmpty i :: VersionIntervali
  where
    validLower (LowerBound v _) = validVersion :: Version -> BoolvalidVersion v :: Versionv
    validUpper NoUpperBound     = True :: BoolTrue
    validUpper (UpperBound v _) = validVersion :: Version -> BoolvalidVersion v :: Versionv

-- Check an interval is non-empty
--
nonEmpty :: VersionInterval -> Bool
nonEmpty (_,               NoUpperBound   ) = True :: BoolTrue
nonEmpty (LowerBound l lb, UpperBound u ub) =
  (l :: LowerBoundl (<) :: Ord a => a -> a -> Bool< u :: UpperBoundu) (||) :: Bool -> Bool -> Bool|| (l :: LowerBoundl (==) :: Eq a => a -> a -> Bool== u :: UpperBoundu (&&) :: Bool -> Bool -> Bool&& lb :: Boundlb (==) :: Eq a => a -> a -> Bool== InclusiveBound :: BoundInclusiveBound (&&) :: Bool -> Bool -> Bool&& ub :: Boundub (==) :: Eq a => a -> a -> Bool== InclusiveBound :: BoundInclusiveBound)

-- Check an upper bound does not intersect, or even touch a lower bound:
--
--   ---|      or  ---)     but not  ---]     or  ---)     or  ---]
--       |---         (---              (---         [---         [---
--
doesNotTouch :: UpperBound -> LowerBound -> Bool
doesNotTouch NoUpperBound _ = False :: BoolFalse
doesNotTouch (UpperBound u ub) (LowerBound l lb) =
      u :: UpperBoundu (<) :: Ord a => a -> a -> Bool<  l :: LowerBoundl
  (||) :: Bool -> Bool -> Bool|| (u :: UpperBoundu (==) :: Eq a => a -> a -> Bool== l :: LowerBoundl (&&) :: Bool -> Bool -> Bool&& ub :: Boundub (==) :: Eq a => a -> a -> Bool== ExclusiveBound :: BoundExclusiveBound (&&) :: Bool -> Bool -> Bool&& lb :: Boundlb (==) :: Eq a => a -> a -> Bool== ExclusiveBound :: BoundExclusiveBound)

-- | Check an upper bound does not intersect a lower bound:
--
--   ---|      or  ---)     or  ---]     or  ---)     but not  ---]
--       |---         (---         (---         [---              [---
--
doesNotIntersect :: UpperBound -> LowerBound -> Bool
doesNotIntersect NoUpperBound _ = False :: BoolFalse
doesNotIntersect (UpperBound u ub) (LowerBound l lb) =
      u :: UpperBoundu (<) :: Ord a => a -> a -> Bool<  l :: LowerBoundl
  (||) :: Bool -> Bool -> Bool|| (u :: UpperBoundu (==) :: Eq a => a -> a -> Bool== l :: LowerBoundl (&&) :: Bool -> Bool -> Bool&& not :: Bool -> Boolnot (ub :: Boundub (==) :: Eq a => a -> a -> Bool== InclusiveBound :: BoundInclusiveBound (&&) :: Bool -> Bool -> Bool&& lb :: Boundlb (==) :: Eq a => a -> a -> Bool== InclusiveBound :: BoundInclusiveBound))

-- | Test if a version falls within the version intervals.
--
-- It exists mostly for completeness and testing. It satisfies the following
-- properties:
--
-- > withinIntervals v (toVersionIntervals vr) = withinRange v vr
-- > withinIntervals v ivs = withinRange v (fromVersionIntervals ivs)
--
withinIntervals :: Version -> VersionIntervals -> Bool
withinIntervals v (VersionIntervals intervals) = any :: (a -> Bool) -> [a] -> Boolany withinInterval :: (LowerBound, UpperBound) -> BoolwithinInterval intervals :: [VersionInterval]intervals
  where
    withinInterval (lowerBound, upperBound)    = withinLower :: LowerBound -> BoolwithinLower lowerBound :: LowerBound -> VersionRangelowerBound
                                              (&&) :: Bool -> Bool -> Bool&& withinUpper :: UpperBound -> BoolwithinUpper upperBound :: UpperBound -> VersionRangeupperBound
    withinLower (LowerBound v' ExclusiveBound) = v' :: Versionv' (<) :: Ord a => a -> a -> Bool<  v :: Versionv
    withinLower (LowerBound v' InclusiveBound) = v' :: Versionv' (<=) :: Ord a => a -> a -> Bool<= v :: Versionv

    withinUpper NoUpperBound                   = True :: BoolTrue
    withinUpper (UpperBound v' ExclusiveBound) = v' :: Versionv' (>) :: Ord a => a -> a -> Bool>  v :: Versionv
    withinUpper (UpperBound v' InclusiveBound) = v' :: Versionv' (>=) :: Ord a => a -> a -> Bool>= v :: Versionv

-- | Convert a 'VersionRange' to a sequence of version intervals.
--
toVersionIntervals :: VersionRange -> VersionIntervals
toVersionIntervals = foldVersionRange ::
  a
  -> (Version -> a)
  -> (Version -> a)
  -> (Version -> a)
  -> (a -> a -> a)
  -> (a -> a -> a)
  -> VersionRange
  -> afoldVersionRange
  (         chkIvl :: VersionInterval -> VersionIntervalschkIvl (minLowerBound :: LowerBoundminLowerBound,               NoUpperBound :: UpperBoundNoUpperBound))
  (\v    -> chkIvl :: VersionInterval -> VersionIntervalschkIvl (($WLowerBound) :: Version -> Bound -> LowerBoundLowerBound v :: Versionv InclusiveBound :: BoundInclusiveBound, ($WUpperBound) :: Version -> Bound -> UpperBoundUpperBound v :: Versionv InclusiveBound :: BoundInclusiveBound))
  (\v    -> chkIvl :: VersionInterval -> VersionIntervalschkIvl (($WLowerBound) :: Version -> Bound -> LowerBoundLowerBound v :: Versionv ExclusiveBound :: BoundExclusiveBound, NoUpperBound :: UpperBoundNoUpperBound))
  (\v    -> if isVersion0 :: Version -> BoolisVersion0 v :: Versionv then VersionIntervals :: [VersionInterval] -> VersionIntervalsVersionIntervals [] :: [a][] else
            chkIvl :: VersionInterval -> VersionIntervalschkIvl (minLowerBound :: LowerBoundminLowerBound,               ($WUpperBound) :: Version -> Bound -> UpperBoundUpperBound v :: Versionv ExclusiveBound :: BoundExclusiveBound))
  unionVersionIntervals ::
  VersionIntervals -> VersionIntervals -> VersionIntervalsunionVersionIntervals
  intersectVersionIntervals ::
  VersionIntervals -> VersionIntervals -> VersionIntervalsintersectVersionIntervals
  where
    chkIvl interval = checkInvariant :: VersionIntervals -> VersionIntervalscheckInvariant (VersionIntervals :: [VersionInterval] -> VersionIntervalsVersionIntervals [interval :: LowerBound -> UpperBound -> VersionRangeinterval])

-- | Convert a 'VersionIntervals' value back into a 'VersionRange' expression
-- representing the version intervals.
--
fromVersionIntervals :: VersionIntervals -> VersionRange
fromVersionIntervals (VersionIntervals []) = noVersion :: VersionRangenoVersion
fromVersionIntervals (VersionIntervals intervals) =
    foldr1 :: (a -> a -> a) -> [a] -> afoldr1 UnionVersionRanges :: VersionRange -> VersionRange -> VersionRangeUnionVersionRanges [ interval :: LowerBound -> UpperBound -> VersionRangeinterval l :: LowerBoundl u :: UpperBoundu | (l, u) <- intervals :: [VersionInterval]intervals ]

  where
    interval (LowerBound v  InclusiveBound)
             (UpperBound v' InclusiveBound) | v :: Versionv (==) :: Eq a => a -> a -> Bool== v' :: Versionv'
                 = ThisVersion :: Version -> VersionRangeThisVersion v :: Versionv
    interval (LowerBound v  InclusiveBound)
             (UpperBound v' ExclusiveBound) | isWildcardRange :: Version -> Version -> BoolisWildcardRange v :: Versionv v' :: Versionv'
                 = WildcardVersion :: Version -> VersionRangeWildcardVersion v :: Versionv
    interval l u = lowerBound :: LowerBound -> VersionRangelowerBound l :: LowerBoundl intersectVersionRanges' ::
  VersionRange -> VersionRange -> VersionRange`intersectVersionRanges'` upperBound :: UpperBound -> VersionRangeupperBound u :: UpperBoundu

    lowerBound (LowerBound v InclusiveBound)
                              | isVersion0 :: Version -> BoolisVersion0 v :: Versionv = AnyVersion :: VersionRangeAnyVersion
                              | otherwise :: Boolotherwise    = orLaterVersion :: Version -> VersionRangeorLaterVersion v :: Versionv
    lowerBound (LowerBound v ExclusiveBound) = LaterVersion :: Version -> VersionRangeLaterVersion v :: Versionv

    upperBound NoUpperBound                  = AnyVersion :: VersionRangeAnyVersion
    upperBound (UpperBound v InclusiveBound) = orEarlierVersion :: Version -> VersionRangeorEarlierVersion v :: Versionv
    upperBound (UpperBound v ExclusiveBound) = EarlierVersion :: Version -> VersionRangeEarlierVersion v :: Versionv

    intersectVersionRanges' vr AnyVersion = vr :: VersionRangevr
    intersectVersionRanges' AnyVersion vr = vr :: VersionRangevr
    intersectVersionRanges' vr vr'        = IntersectVersionRanges ::
  VersionRange -> VersionRange -> VersionRangeIntersectVersionRanges vr :: VersionRangevr vr' :: VersionRangevr'

unionVersionIntervals :: VersionIntervals -> VersionIntervals
                      -> VersionIntervals
unionVersionIntervals (VersionIntervals is0) (VersionIntervals is'0) =
  checkInvariant :: VersionIntervals -> VersionIntervalscheckInvariant (VersionIntervals :: [VersionInterval] -> VersionIntervalsVersionIntervals (union :: a -> a -> aunion is0 :: [VersionInterval]is0 is'0 :: [VersionInterval]is'0))
  where
    union is []  = is :: [VersionInterval]is
    union [] is' = is' :: [VersionInterval]is'
    union (i:is) (i':is') = case unionInterval ::
  VersionInterval
  -> VersionInterval
  -> Either (Maybe VersionInterval) (Maybe VersionInterval)unionInterval i :: VersionIntervali i' :: VersionIntervali' of
      Left  Nothing    -> i :: VersionIntervali  (:) :: a -> [a] -> [a]: union :: a -> a -> aunion      is :: [VersionInterval]is  (i' :: VersionIntervali' (:) :: a -> [a] -> [a]:is' :: [VersionInterval]is')
      Left  (Just i'') ->      union :: a -> a -> aunion      is :: [VersionInterval]is  (i'' :: VersionIntervali''(:) :: a -> [a] -> [a]:is' :: [VersionInterval]is')
      Right Nothing    -> i' :: VersionIntervali' (:) :: a -> [a] -> [a]: union :: a -> a -> aunion (i :: VersionIntervali  (:) :: a -> [a] -> [a]:is :: [VersionInterval]is)      is' :: [VersionInterval]is'
      Right (Just i'') ->      union :: a -> a -> aunion (i'' :: VersionIntervali''(:) :: a -> [a] -> [a]:is :: [VersionInterval]is)      is' :: [VersionInterval]is'

unionInterval :: VersionInterval -> VersionInterval
              -> Either (Maybe VersionInterval) (Maybe VersionInterval)
unionInterval (lower , upper ) (lower', upper')

  -- Non-intersecting intervals with the left interval ending first
  | upper :: UpperBoundupper doesNotTouch :: UpperBound -> LowerBound -> Bool`doesNotTouch` lower' :: LowerBoundlower' = Left :: a -> Either a bLeft Nothing :: Maybe aNothing

  -- Non-intersecting intervals with the right interval first
  | upper' :: UpperBoundupper' doesNotTouch :: UpperBound -> LowerBound -> Bool`doesNotTouch` lower :: LowerBoundlower = Right :: b -> Either a bRight Nothing :: Maybe aNothing

  -- Complete or partial overlap, with the left interval ending first
  | upper :: UpperBoundupper (<=) :: Ord a => a -> a -> Bool<= upper' :: UpperBoundupper' = lowerBound :: LowerBound -> VersionRangelowerBound seq :: a -> b -> b`seq`
                      Left :: a -> Either a bLeft (Just :: a -> Maybe aJust (lowerBound :: LowerBound -> VersionRangelowerBound, upper' :: UpperBoundupper'))

  -- Complete or partial overlap, with the left interval ending first
  | otherwise :: Boolotherwise = lowerBound :: LowerBound -> VersionRangelowerBound seq :: a -> b -> b`seq`
                Right :: b -> Either a bRight (Just :: a -> Maybe aJust (lowerBound :: LowerBound -> VersionRangelowerBound, upper :: UpperBoundupper))
  where
    lowerBound = min :: Ord a => a -> a -> amin lower :: LowerBoundlower lower' :: LowerBoundlower'

intersectVersionIntervals :: VersionIntervals -> VersionIntervals
                          -> VersionIntervals
intersectVersionIntervals (VersionIntervals is0) (VersionIntervals is'0) =
  checkInvariant :: VersionIntervals -> VersionIntervalscheckInvariant (VersionIntervals :: [VersionInterval] -> VersionIntervalsVersionIntervals (intersect :: a -> a -> aintersect is0 :: [VersionInterval]is0 is'0 :: [VersionInterval]is'0))
  where
    intersect _  [] = [] :: [a][]
    intersect [] _  = [] :: [a][]
    intersect (i:is) (i':is') = case intersectInterval ::
  VersionInterval
  -> VersionInterval
  -> Either (Maybe VersionInterval) (Maybe VersionInterval)intersectInterval i :: VersionIntervali i' :: VersionIntervali' of
      Left  Nothing    ->       intersect :: a -> a -> aintersect is :: [VersionInterval]is (i' :: VersionIntervali'(:) :: a -> [a] -> [a]:is' :: [VersionInterval]is')
      Left  (Just i'') -> i'' :: VersionIntervali'' (:) :: a -> [a] -> [a]: intersect :: a -> a -> aintersect is :: [VersionInterval]is (i' :: VersionIntervali'(:) :: a -> [a] -> [a]:is' :: [VersionInterval]is')
      Right Nothing    ->       intersect :: a -> a -> aintersect (i :: VersionIntervali(:) :: a -> [a] -> [a]:is :: [VersionInterval]is) is' :: [VersionInterval]is'
      Right (Just i'') -> i'' :: VersionIntervali'' (:) :: a -> [a] -> [a]: intersect :: a -> a -> aintersect (i :: VersionIntervali(:) :: a -> [a] -> [a]:is :: [VersionInterval]is) is' :: [VersionInterval]is'

intersectInterval :: VersionInterval -> VersionInterval
                  -> Either (Maybe VersionInterval) (Maybe VersionInterval)
intersectInterval (lower , upper ) (lower', upper')

  -- Non-intersecting intervals with the left interval ending first
  | upper :: UpperBoundupper doesNotIntersect :: UpperBound -> LowerBound -> Bool`doesNotIntersect` lower' :: LowerBoundlower' = Left :: a -> Either a bLeft Nothing :: Maybe aNothing

  -- Non-intersecting intervals with the right interval first
  | upper' :: UpperBoundupper' doesNotIntersect :: UpperBound -> LowerBound -> Bool`doesNotIntersect` lower :: LowerBoundlower = Right :: b -> Either a bRight Nothing :: Maybe aNothing

  -- Complete or partial overlap, with the left interval ending first
  | upper :: UpperBoundupper (<=) :: Ord a => a -> a -> Bool<= upper' :: UpperBoundupper' = lowerBound :: LowerBound -> VersionRangelowerBound seq :: a -> b -> b`seq`
                      Left :: a -> Either a bLeft (Just :: a -> Maybe aJust (lowerBound :: LowerBound -> VersionRangelowerBound, upper :: UpperBoundupper))

  -- Complete or partial overlap, with the right interval ending first
  | otherwise :: Boolotherwise = lowerBound :: LowerBound -> VersionRangelowerBound seq :: a -> b -> b`seq`
                Right :: b -> Either a bRight (Just :: a -> Maybe aJust (lowerBound :: LowerBound -> VersionRangelowerBound, upper' :: UpperBoundupper'))
  where
    lowerBound = max :: Ord a => a -> a -> amax lower :: LowerBoundlower lower' :: LowerBoundlower'

-------------------------------
-- Parsing and pretty printing
--

instance D:Text :: (a -> Doc) -> (forall r. ReadP r a) -> T:Text aText VersionRange where
  disp = fst :: (a, b) -> afst
       (.) :: (b -> c) -> (a -> b) -> a -> c. foldVersionRange' ::
  a
  -> (Version -> a)
  -> (Version -> a)
  -> (Version -> a)
  -> (Version -> a)
  -> (Version -> a)
  -> (Version -> Version -> a)
  -> (a -> a -> a)
  -> (a -> a -> a)
  -> (a -> a)
  -> VersionRange
  -> afoldVersionRange'                         -- precedence:
           (         text :: String -> DocDisp.text "-any"                           , 0 :: Int)
           (\v   -> (text :: String -> DocDisp.text "==" (<>) :: Doc -> Doc -> Doc<> disp :: Text a => a -> Docdisp v :: Versionv                   , 0))
           (\v   -> (char :: Char -> DocDisp.char '>'  (<>) :: Doc -> Doc -> Doc<> disp :: Text a => a -> Docdisp v :: Versionv                   , 0))
           (\v   -> (char :: Char -> DocDisp.char '<'  (<>) :: Doc -> Doc -> Doc<> disp :: Text a => a -> Docdisp v :: Versionv                   , 0))
           (\v   -> (text :: String -> DocDisp.text ">=" (<>) :: Doc -> Doc -> Doc<> disp :: Text a => a -> Docdisp v :: Versionv                   , 0))
           (\v   -> (text :: String -> DocDisp.text "<=" (<>) :: Doc -> Doc -> Doc<> disp :: Text a => a -> Docdisp v :: Versionv                   , 0))
           (\v _ -> (text :: String -> DocDisp.text "==" (<>) :: Doc -> Doc -> Doc<> dispWild :: Version -> DocdispWild v :: Versionv               , 0))
           (\(r1, p1) (r2, p2) -> (punct :: a -> a -> Doc -> Docpunct 2 p1 :: Intp1 r1 :: Docr1 (<+>) :: Doc -> Doc -> Doc<+> text :: String -> DocDisp.text "||" (<+>) :: Doc -> Doc -> Doc<+> punct :: a -> a -> Doc -> Docpunct 2 p2 :: Intp2 r2 :: Docr2 , 2))
           (\(r1, p1) (r2, p2) -> (punct :: a -> a -> Doc -> Docpunct 1 p1 :: Intp1 r1 :: Docr1 (<+>) :: Doc -> Doc -> Doc<+> text :: String -> DocDisp.text "&&" (<+>) :: Doc -> Doc -> Doc<+> punct :: a -> a -> Doc -> Docpunct 1 p2 :: Intp2 r2 :: Docr2 , 1))
           (\(r, p)   -> (parens :: Doc -> DocDisp.parens r :: Docr, p :: Parser r Char VersionRangep))

    where dispWild (Version b _) =
               hcat :: [Doc] -> DocDisp.hcat (punctuate :: Doc -> [Doc] -> [Doc]Disp.punctuate (char :: Char -> DocDisp.char '.') (map :: (a -> b) -> [a] -> [b]map int :: Int -> DocDisp.int b :: [Int]b))
            (<>) :: Doc -> Doc -> Doc<> text :: String -> DocDisp.text ".*"
          punct p p' | p :: Parser r Char VersionRangep (<) :: Ord a => a -> a -> Bool< p' :: ap'    = parens :: Doc -> DocDisp.parens
                     | otherwise :: Boolotherwise = id :: a -> aid

  parse = expr :: Parser r Char VersionRangeexpr
   where
        expr   = do skipSpaces :: ReadP r ()Parse.skipSpaces
                    t <- term :: Parser r Char VersionRangeterm
                    skipSpaces :: ReadP r ()Parse.skipSpaces
                    (do _  <- string :: String -> ReadP r StringParse.string "||"
                        skipSpaces :: ReadP r ()Parse.skipSpaces
                        e <- expr :: Parser r Char VersionRangeexpr
                        return :: Monad m => forall a. a -> m areturn (UnionVersionRanges :: VersionRange -> VersionRange -> VersionRangeUnionVersionRanges t :: VersionRanget e :: VersionRangee)
                     (+++) :: ReadP r a -> ReadP r a -> ReadP r a+++
                     return :: Monad m => forall a. a -> m areturn t :: VersionRanget)
        term   = do f <- factor :: Parser r Char VersionRangefactor
                    skipSpaces :: ReadP r ()Parse.skipSpaces
                    (do _  <- string :: String -> ReadP r StringParse.string "&&"
                        skipSpaces :: ReadP r ()Parse.skipSpaces
                        t <- term :: Parser r Char VersionRangeterm
                        return :: Monad m => forall a. a -> m areturn (IntersectVersionRanges ::
  VersionRange -> VersionRange -> VersionRangeIntersectVersionRanges f :: VersionRangef t :: VersionRanget)
                     (+++) :: ReadP r a -> ReadP r a -> ReadP r a+++
                     return :: Monad m => forall a. a -> m areturn f :: VersionRangef)
        factor = choice :: [ReadP r a] -> ReadP r aParse.choice ($) :: (a -> b) -> a -> b$ parens :: Parser r Char VersionRange -> ReadP r VersionRangeparens expr :: Parser r Char VersionRangeexpr
                              (:) :: a -> [a] -> [a]: parseAnyVersion :: Parser r Char VersionRangeparseAnyVersion
                              (:) :: a -> [a] -> [a]: parseWildcardRange :: Parser r Char VersionRangeparseWildcardRange
                              (:) :: a -> [a] -> [a]: map :: (a -> b) -> [a] -> [b]map parseRangeOp :: Text a => (String, a -> b) -> Parser r Char bparseRangeOp rangeOps :: [([Char], Version -> VersionRange)]rangeOps
        parseAnyVersion    = string :: String -> ReadP r StringParse.string "-any" (>>) :: Monad m => forall a b. m a -> m b -> m b>> return :: Monad m => forall a. a -> m areturn AnyVersion :: VersionRangeAnyVersion

        parseWildcardRange = do
          _ <- string :: String -> ReadP r StringParse.string "=="
          skipSpaces :: ReadP r ()Parse.skipSpaces
          branch <- sepBy1 :: ReadP r a -> ReadP r sep -> ReadP r [a]Parse.sepBy1 digits :: Parser r Char Intdigits (char :: Char -> ReadP r CharParse.char '.')
          _ <- char :: Char -> ReadP r CharParse.char '.'
          _ <- char :: Char -> ReadP r CharParse.char '*'
          return :: Monad m => forall a. a -> m areturn (WildcardVersion :: Version -> VersionRangeWildcardVersion (Version :: [Int] -> [String] -> VersionVersion branch :: [Int]branch [] :: [a][]))

        parens p = between :: ReadP r open -> ReadP r close -> ReadP r a -> ReadP r aParse.between (char :: Char -> ReadP r CharParse.char '(' (>>) :: Monad m => forall a b. m a -> m b -> m b>> skipSpaces :: ReadP r ()Parse.skipSpaces)
                                 (char :: Char -> ReadP r CharParse.char ')' (>>) :: Monad m => forall a b. m a -> m b -> m b>> skipSpaces :: ReadP r ()Parse.skipSpaces)
                                 (do a <- p :: Parser r Char VersionRangep
                                     skipSpaces :: ReadP r ()Parse.skipSpaces
                                     return :: Monad m => forall a. a -> m areturn (VersionRangeParens :: VersionRange -> VersionRangeVersionRangeParens a :: VersionRangea))

        digits = do
          first <- satisfy :: (Char -> Bool) -> ReadP r CharParse.satisfy isDigit :: Char -> BoolChar.isDigit
          if first :: Charfirst (==) :: Eq a => a -> a -> Bool== '0'
            then return :: Monad m => forall a. a -> m areturn 0
            else do rest <- munch :: (Char -> Bool) -> ReadP r StringParse.munch isDigit :: Char -> BoolChar.isDigit
                    return :: Monad m => forall a. a -> m areturn (read :: Read a => String -> aread (first :: Charfirst (:) :: a -> [a] -> [a]: rest :: Stringrest))

        parseRangeOp (s,f) = string :: String -> ReadP r StringParse.string s :: Strings (>>) :: Monad m => forall a b. m a -> m b -> m b>> skipSpaces :: ReadP r ()Parse.skipSpaces (>>) :: Monad m => forall a b. m a -> m b -> m b>> fmap :: Functor f => forall a b. (a -> b) -> f a -> f bfmap f :: VersionRangef parse :: Text a => forall r. ReadP r aparse
        rangeOps = [ ("<",  EarlierVersion :: Version -> VersionRangeEarlierVersion),
                     ("<=", orEarlierVersion :: Version -> VersionRangeorEarlierVersion),
                     (">",  LaterVersion :: Version -> VersionRangeLaterVersion),
                     (">=", orLaterVersion :: Version -> VersionRangeorLaterVersion),
                     ("==", ThisVersion :: Version -> VersionRangeThisVersion) ]