-- |A module for parsing, comparing, and (eventually) modifying debian version
-- numbers. <http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version>
{-# LANGUAGE FlexibleInstances #-}
{-# OPTIONS -fno-warn-orphans -fno-warn-unused-do-bind #-}
module Debian.Version.Common
    ( DebianVersion -- |Exported abstract because the internal representation is likely to change
    , prettyDebianVersion
    , ParseDebianVersion(..)
    , parseDebianVersion'
    , evr               -- DebianVersion -> (Maybe Int, String, Maybe String)
    , epoch
    , version
    , revision
    , buildDebianVersion
    , parseDV
    ) where

import Data.Char (ord, isDigit, isAlpha)
import Debian.Pretty (PP(..))
import Debian.Version.Internal
import Text.ParserCombinators.Parsec
import Text.Regex
import Text.PrettyPrint (Doc, render, text)
import Distribution.Pretty (Pretty(pretty))

prettyDebianVersion :: DebianVersion -> Doc
prettyDebianVersion :: DebianVersion -> Doc
prettyDebianVersion (DebianVersion s :: String
s _) = String -> Doc
text String
s

instance Pretty (PP DebianVersion) where
    pretty :: PP DebianVersion -> Doc
pretty = DebianVersion -> Doc
prettyDebianVersion (DebianVersion -> Doc)
-> (PP DebianVersion -> DebianVersion) -> PP DebianVersion -> Doc
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PP DebianVersion -> DebianVersion
forall a. PP a -> a
unPP

instance Eq DebianVersion where
    (DebianVersion _ v1 :: (Found Int, NonNumeric, Found NonNumeric)
v1) == :: DebianVersion -> DebianVersion -> Bool
== (DebianVersion _ v2 :: (Found Int, NonNumeric, Found NonNumeric)
v2) = (Found Int, NonNumeric, Found NonNumeric)
v1 (Found Int, NonNumeric, Found NonNumeric)
-> (Found Int, NonNumeric, Found NonNumeric) -> Bool
forall a. Eq a => a -> a -> Bool
== (Found Int, NonNumeric, Found NonNumeric)
v2

instance Ord DebianVersion where
    compare :: DebianVersion -> DebianVersion -> Ordering
compare (DebianVersion _ v1 :: (Found Int, NonNumeric, Found NonNumeric)
v1) (DebianVersion _ v2 :: (Found Int, NonNumeric, Found NonNumeric)
v2) = (Found Int, NonNumeric, Found NonNumeric)
-> (Found Int, NonNumeric, Found NonNumeric) -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Found Int, NonNumeric, Found NonNumeric)
v1 (Found Int, NonNumeric, Found NonNumeric)
v2

instance Show DebianVersion where
    show :: DebianVersion -> String
show v :: DebianVersion
v = "(Debian.Version.parseDebianVersion (" String -> ShowS
forall a. [a] -> [a] -> [a]
++ ShowS
forall a. Show a => a -> String
show (Doc -> String
render (DebianVersion -> Doc
prettyDebianVersion DebianVersion
v)) String -> ShowS
forall a. [a] -> [a] -> [a]
++ " :: String))"

-- make ~ less than everything, and everything else higher that letters
order :: Char -> Int
order :: Char -> Int
order c :: Char
c
    | Char -> Bool
isDigit Char
c = 0
    | Char -> Bool
isAlpha Char
c = Char -> Int
ord Char
c
    | Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== '~' = -1
    | Bool
otherwise = (Char -> Int
ord Char
c) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ 256

-- |We have to do this wackiness because ~ is less than the empty string
compareNonNumeric :: [Char] -> [Char] -> Ordering
compareNonNumeric :: String -> String -> Ordering
compareNonNumeric "" "" = Ordering
EQ
compareNonNumeric "" ('~':_cs :: String
_cs) = Ordering
GT
compareNonNumeric ('~':_cs :: String
_cs) "" = Ordering
LT
compareNonNumeric "" _ = Ordering
LT
compareNonNumeric _ "" = Ordering
GT
compareNonNumeric (c1 :: Char
c1:cs1 :: String
cs1) (c2 :: Char
c2:cs2 :: String
cs2) =
    if (Char -> Int
order Char
c1) Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== (Char -> Int
order Char
c2)
       then String -> String -> Ordering
compareNonNumeric String
cs1 String
cs2
       else Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare (Char -> Int
order Char
c1) (Char -> Int
order Char
c2)

instance Eq NonNumeric where
    (NonNumeric s1 :: String
s1 n1 :: Found Numeric
n1) == :: NonNumeric -> NonNumeric -> Bool
== (NonNumeric s2 :: String
s2 n2 :: Found Numeric
n2) =
        case String -> String -> Ordering
compareNonNumeric String
s1 String
s2 of
          EQ -> Found Numeric
n1 Found Numeric -> Found Numeric -> Bool
forall a. Eq a => a -> a -> Bool
== Found Numeric
n2
          _o :: Ordering
_o -> Bool
False

instance Ord NonNumeric where
    compare :: NonNumeric -> NonNumeric -> Ordering
compare (NonNumeric s1 :: String
s1 n1 :: Found Numeric
n1) (NonNumeric s2 :: String
s2 n2 :: Found Numeric
n2) =
        case String -> String -> Ordering
compareNonNumeric String
s1 String
s2 of
          EQ -> Found Numeric -> Found Numeric -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Found Numeric
n1 Found Numeric
n2
          o :: Ordering
o -> Ordering
o

instance Eq Numeric where
    (Numeric n1 :: Int
n1 mnn1 :: Maybe NonNumeric
mnn1) == :: Numeric -> Numeric -> Bool
== (Numeric n2 :: Int
n2 mnn2 :: Maybe NonNumeric
mnn2) =
        case Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Int
n1 Int
n2 of
          EQ -> case Maybe NonNumeric -> Maybe NonNumeric -> Ordering
compareMaybeNonNumeric Maybe NonNumeric
mnn1 Maybe NonNumeric
mnn2 of
                  EQ -> Bool
True
                  _ -> Bool
False
          _ -> Bool
False

compareMaybeNonNumeric :: Maybe NonNumeric -> Maybe NonNumeric -> Ordering
compareMaybeNonNumeric :: Maybe NonNumeric -> Maybe NonNumeric -> Ordering
compareMaybeNonNumeric mnn1 :: Maybe NonNumeric
mnn1 mnn2 :: Maybe NonNumeric
mnn2 =
    case (Maybe NonNumeric
mnn1, Maybe NonNumeric
mnn2) of
      (Nothing, Nothing) -> Ordering
EQ
      (Just (NonNumeric nn :: String
nn _), Nothing) -> String -> String -> Ordering
compareNonNumeric String
nn ""
      (Nothing, Just (NonNumeric nn :: String
nn _)) -> String -> String -> Ordering
compareNonNumeric "" String
nn
      (Just nn1 :: NonNumeric
nn1, Just nn2 :: NonNumeric
nn2) -> NonNumeric -> NonNumeric -> Ordering
forall a. Ord a => a -> a -> Ordering
compare NonNumeric
nn1 NonNumeric
nn2

instance Ord Numeric where
    compare :: Numeric -> Numeric -> Ordering
compare (Numeric n1 :: Int
n1 mnn1 :: Maybe NonNumeric
mnn1) (Numeric n2 :: Int
n2 mnn2 :: Maybe NonNumeric
mnn2) =
        case Int -> Int -> Ordering
forall a. Ord a => a -> a -> Ordering
compare Int
n1 Int
n2 of
          EQ -> Maybe NonNumeric -> Maybe NonNumeric -> Ordering
compareMaybeNonNumeric Maybe NonNumeric
mnn1 Maybe NonNumeric
mnn2
          o :: Ordering
o -> Ordering
o

-- * Parser

class ParseDebianVersion a where
    parseDebianVersion :: a-> Either ParseError DebianVersion
-- |Convert a string to a debian version number. May throw an
-- exception if the string is unparsable -- but I am not sure if that
-- can currently happen. Are there any invalid version strings?
-- Perhaps ones with underscore, or something?

parseDebianVersion' :: ParseDebianVersion string => string -> DebianVersion
parseDebianVersion' :: string -> DebianVersion
parseDebianVersion' str :: string
str = (ParseError -> DebianVersion)
-> (DebianVersion -> DebianVersion)
-> Either ParseError DebianVersion
-> DebianVersion
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (\e :: ParseError
e -> String -> DebianVersion
forall a. HasCallStack => String -> a
error (ParseError -> String
forall a. Show a => a -> String
show ParseError
e)) DebianVersion -> DebianVersion
forall a. a -> a
id (string -> Either ParseError DebianVersion
forall a.
ParseDebianVersion a =>
a -> Either ParseError DebianVersion
parseDebianVersion string
str)

{-
showNN :: NonNumeric -> String
showNN (NonNumeric s n) = s ++ showN n

showN :: Found Numeric -> String
showN (Found (Numeric n nn)) = show n ++ maybe "" showNN nn
showN (Simulated _) = ""
-}

parseDV :: CharParser () (Found Int, NonNumeric, Found NonNumeric)
parseDV :: CharParser () (Found Int, NonNumeric, Found NonNumeric)
parseDV =
    do ParsecT String () Identity Char -> ParsecT String () Identity ()
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m ()
skipMany (ParsecT String () Identity Char -> ParsecT String () Identity ())
-> ParsecT String () Identity Char -> ParsecT String () Identity ()
forall a b. (a -> b) -> a -> b
$ String -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
oneOf " \t"
       Found Int
e <- CharParser () (Found Int)
parseEpoch
       NonNumeric
upstreamVersion <- Bool -> Bool -> CharParser () NonNumeric
parseNonNumeric Bool
True Bool
True
       Found NonNumeric
debianRevision <- Found NonNumeric
-> ParsecT String () Identity (Found NonNumeric)
-> ParsecT String () Identity (Found NonNumeric)
forall s (m :: * -> *) t a u.
Stream s m t =>
a -> ParsecT s u m a -> ParsecT s u m a
option (NonNumeric -> Found NonNumeric
forall a. a -> Found a
Simulated (String -> Found Numeric -> NonNumeric
NonNumeric "" (Numeric -> Found Numeric
forall a. a -> Found a
Simulated (Int -> Maybe NonNumeric -> Numeric
Numeric 0 Maybe NonNumeric
forall a. Maybe a
Nothing)))) (Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char '-' ParsecT String () Identity Char
-> CharParser () NonNumeric -> CharParser () NonNumeric
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Bool -> Bool -> CharParser () NonNumeric
parseNonNumeric Bool
True Bool
False CharParser () NonNumeric
-> (NonNumeric -> ParsecT String () Identity (Found NonNumeric))
-> ParsecT String () Identity (Found NonNumeric)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Found NonNumeric -> ParsecT String () Identity (Found NonNumeric)
forall (m :: * -> *) a. Monad m => a -> m a
return (Found NonNumeric -> ParsecT String () Identity (Found NonNumeric))
-> (NonNumeric -> Found NonNumeric)
-> NonNumeric
-> ParsecT String () Identity (Found NonNumeric)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonNumeric -> Found NonNumeric
forall a. a -> Found a
Found)
       (Found Int, NonNumeric, Found NonNumeric)
-> CharParser () (Found Int, NonNumeric, Found NonNumeric)
forall (m :: * -> *) a. Monad m => a -> m a
return (Found Int
e, NonNumeric
upstreamVersion, Found NonNumeric
debianRevision)

parseEpoch :: CharParser () (Found Int)
parseEpoch :: CharParser () (Found Int)
parseEpoch =
    Found Int -> CharParser () (Found Int) -> CharParser () (Found Int)
forall s (m :: * -> *) t a u.
Stream s m t =>
a -> ParsecT s u m a -> ParsecT s u m a
option (Int -> Found Int
forall a. a -> Found a
Simulated 0) (CharParser () (Found Int) -> CharParser () (Found Int)
forall tok st a. GenParser tok st a -> GenParser tok st a
try (ParsecT String () Identity Char
-> ParsecT String () Identity String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 ParsecT String () Identity Char
forall s (m :: * -> *) u. Stream s m Char => ParsecT s u m Char
digit ParsecT String () Identity String
-> (String -> CharParser () (Found Int))
-> CharParser () (Found Int)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \d :: String
d -> Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char ':' ParsecT String () Identity Char
-> CharParser () (Found Int) -> CharParser () (Found Int)
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Found Int -> CharParser () (Found Int)
forall (m :: * -> *) a. Monad m => a -> m a
return (Int -> Found Int
forall a. a -> Found a
Found (String -> Int
forall a. Read a => String -> a
read String
d))))


parseNonNumeric :: Bool -> Bool -> CharParser () NonNumeric
parseNonNumeric :: Bool -> Bool -> CharParser () NonNumeric
parseNonNumeric zeroOk :: Bool
zeroOk upstream :: Bool
upstream =
    do String
nn <- (if Bool
zeroOk then ParsecT String () Identity Char
-> ParsecT String () Identity String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many else ParsecT String () Identity Char
-> ParsecT String () Identity String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1) ((String -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf "-0123456789") ParsecT String () Identity Char
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|> (if Bool
upstream then ParsecT String () Identity Char
upstreamDash else ParsecT String () Identity Char
forall tok st a. GenParser tok st a
pzero))
       Found Numeric
n <- Bool -> CharParser () (Found Numeric)
parseNumeric Bool
upstream
       NonNumeric -> CharParser () NonNumeric
forall (m :: * -> *) a. Monad m => a -> m a
return (NonNumeric -> CharParser () NonNumeric)
-> NonNumeric -> CharParser () NonNumeric
forall a b. (a -> b) -> a -> b
$ String -> Found Numeric -> NonNumeric
NonNumeric String
nn Found Numeric
n
    where
      upstreamDash :: CharParser () Char
      upstreamDash :: ParsecT String () Identity Char
upstreamDash = ParsecT String () Identity Char -> ParsecT String () Identity Char
forall tok st a. GenParser tok st a -> GenParser tok st a
try (ParsecT String () Identity Char
 -> ParsecT String () Identity Char)
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall a b. (a -> b) -> a -> b
$ do Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char '-'
                              ParsecT String () Identity Char -> ParsecT String () Identity Char
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m a
lookAhead (ParsecT String () Identity Char
 -> ParsecT String () Identity Char)
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall a b. (a -> b) -> a -> b
$ (ParsecT String () Identity Char
-> ParsecT String () Identity String
forall s u (m :: * -> *) a. ParsecT s u m a -> ParsecT s u m [a]
many (String -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
String -> ParsecT s u m Char
noneOf "- \n\t") ParsecT String () Identity String
-> ParsecT String () Identity Char
-> ParsecT String () Identity Char
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Char -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
Char -> ParsecT s u m Char
char '-')
                              Char -> ParsecT String () Identity Char
forall (m :: * -> *) a. Monad m => a -> m a
return '-'

parseNumeric :: Bool -> CharParser () (Found Numeric)
parseNumeric :: Bool -> CharParser () (Found Numeric)
parseNumeric upstream :: Bool
upstream =
    do String
n <- ParsecT String () Identity Char
-> ParsecT String () Identity String
forall s (m :: * -> *) t u a.
Stream s m t =>
ParsecT s u m a -> ParsecT s u m [a]
many1 ((Char -> Bool) -> ParsecT String () Identity Char
forall s (m :: * -> *) u.
Stream s m Char =>
(Char -> Bool) -> ParsecT s u m Char
satisfy Char -> Bool
isDigit)
       Maybe NonNumeric
nn <- Maybe NonNumeric
-> ParsecT String () Identity (Maybe NonNumeric)
-> ParsecT String () Identity (Maybe NonNumeric)
forall s (m :: * -> *) t a u.
Stream s m t =>
a -> ParsecT s u m a -> ParsecT s u m a
option Maybe NonNumeric
forall a. Maybe a
Nothing  (Bool -> Bool -> CharParser () NonNumeric
parseNonNumeric Bool
False Bool
upstream CharParser () NonNumeric
-> (NonNumeric -> ParsecT String () Identity (Maybe NonNumeric))
-> ParsecT String () Identity (Maybe NonNumeric)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe NonNumeric -> ParsecT String () Identity (Maybe NonNumeric)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe NonNumeric -> ParsecT String () Identity (Maybe NonNumeric))
-> (NonNumeric -> Maybe NonNumeric)
-> NonNumeric
-> ParsecT String () Identity (Maybe NonNumeric)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonNumeric -> Maybe NonNumeric
forall a. a -> Maybe a
Just)
       Found Numeric -> CharParser () (Found Numeric)
forall (m :: * -> *) a. Monad m => a -> m a
return (Found Numeric -> CharParser () (Found Numeric))
-> Found Numeric -> CharParser () (Found Numeric)
forall a b. (a -> b) -> a -> b
$ Numeric -> Found Numeric
forall a. a -> Found a
Found (Int -> Maybe NonNumeric -> Numeric
Numeric (String -> Int
forall a. Read a => String -> a
read String
n) Maybe NonNumeric
nn)
    CharParser () (Found Numeric)
-> CharParser () (Found Numeric) -> CharParser () (Found Numeric)
forall s u (m :: * -> *) a.
ParsecT s u m a -> ParsecT s u m a -> ParsecT s u m a
<|>
    Found Numeric -> CharParser () (Found Numeric)
forall (m :: * -> *) a. Monad m => a -> m a
return (Numeric -> Found Numeric
forall a. a -> Found a
Simulated (Int -> Maybe NonNumeric -> Numeric
Numeric 0 Maybe NonNumeric
forall a. Maybe a
Nothing))

{-
compareTest :: String -> String -> Ordering
compareTest str1 str2 =
    let v1 = either (error . show) id $ parse parseDV str1 str1
        v2 = either (error . show) id $ parse parseDV str2 str2
        in
          compare v1 v2
-}

-- |Split a DebianVersion into its three components: epoch, version,
-- revision.  It is not safe to use the parsed version number for
-- this because you will lose information, such as leading zeros.
evr :: DebianVersion -> (Maybe Int, String, Maybe String)
evr :: DebianVersion -> (Maybe Int, String, Maybe String)
evr (DebianVersion s :: String
s _) =
    let re :: Regex
re = String -> Regex
mkRegex "^(([0-9]+):)?(([^-]*)|((.*)-([^-]*)))$" in
    --                 (         ) (        (            ))
    --                  (   e  )    (  v  )  (v2) (  r  )
    case Regex -> String -> Maybe [String]
matchRegex Regex
re String
s of
      Just ["", _, _, v :: String
v, "", _, _] -> (Maybe Int
forall a. Maybe a
Nothing, String
v, Maybe String
forall a. Maybe a
Nothing)
      Just ["", _, _, _, _,  v :: String
v, r :: String
r] -> (Maybe Int
forall a. Maybe a
Nothing, String
v, String -> Maybe String
forall a. a -> Maybe a
Just String
r)
      Just [_,  e :: String
e, _, v :: String
v, "", _, _] -> (Int -> Maybe Int
forall a. a -> Maybe a
Just (String -> Int
forall a. Read a => String -> a
read String
e), String
v, Maybe String
forall a. Maybe a
Nothing)
      Just [_,  e :: String
e, _, _, _,  v :: String
v, r :: String
r] -> (Int -> Maybe Int
forall a. a -> Maybe a
Just (String -> Int
forall a. Read a => String -> a
read String
e), String
v, String -> Maybe String
forall a. a -> Maybe a
Just String
r)
      -- I really don't think this can happen.
      _ -> String -> (Maybe Int, String, Maybe String)
forall a. HasCallStack => String -> a
error ("Invalid Debian Version String: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
s)

epoch :: DebianVersion -> Maybe Int
epoch :: DebianVersion -> Maybe Int
epoch v :: DebianVersion
v = case DebianVersion -> (Maybe Int, String, Maybe String)
evr DebianVersion
v of (x :: Maybe Int
x, _, _) -> Maybe Int
x
version :: DebianVersion -> String
version :: DebianVersion -> String
version v :: DebianVersion
v = case DebianVersion -> (Maybe Int, String, Maybe String)
evr DebianVersion
v of (_, x :: String
x, _) -> String
x
revision :: DebianVersion -> Maybe String
revision :: DebianVersion -> Maybe String
revision v :: DebianVersion
v = case DebianVersion -> (Maybe Int, String, Maybe String)
evr DebianVersion
v of (_, _, x :: Maybe String
x) -> Maybe String
x

-- Build a Debian version number from epoch, version, revision
buildDebianVersion :: Maybe Int -> String -> Maybe String -> DebianVersion
buildDebianVersion :: Maybe Int -> String -> Maybe String -> DebianVersion
buildDebianVersion e :: Maybe Int
e v :: String
v r :: Maybe String
r =
    (ParseError -> DebianVersion)
-> ((Found Int, NonNumeric, Found NonNumeric) -> DebianVersion)
-> Either ParseError (Found Int, NonNumeric, Found NonNumeric)
-> DebianVersion
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (String -> DebianVersion
forall a. HasCallStack => String -> a
error (String -> DebianVersion)
-> (ParseError -> String) -> ParseError -> DebianVersion
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ParseError -> String
forall a. Show a => a -> String
show) (String
-> (Found Int, NonNumeric, Found NonNumeric) -> DebianVersion
DebianVersion String
str) (Either ParseError (Found Int, NonNumeric, Found NonNumeric)
 -> DebianVersion)
-> Either ParseError (Found Int, NonNumeric, Found NonNumeric)
-> DebianVersion
forall a b. (a -> b) -> a -> b
$ CharParser () (Found Int, NonNumeric, Found NonNumeric)
-> String
-> String
-> Either ParseError (Found Int, NonNumeric, Found NonNumeric)
forall s t a.
Stream s Identity t =>
Parsec s () a -> String -> s -> Either ParseError a
parse CharParser () (Found Int, NonNumeric, Found NonNumeric)
parseDV String
str String
str
    where
      str :: String
str = (String -> (Int -> String) -> Maybe Int -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe "" (\ n :: Int
n -> Int -> String
forall a. Show a => a -> String
show Int
n String -> ShowS
forall a. [a] -> [a] -> [a]
++ ":") Maybe Int
e String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
v String -> ShowS
forall a. [a] -> [a] -> [a]
++ String -> ShowS -> Maybe String -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe "" (\ s :: String
s -> "-" String -> ShowS
forall a. [a] -> [a] -> [a]
++ String
s) Maybe String
r)