aboutsummaryrefslogtreecommitdiff
path: root/Haskell-book/24/ParserExercises/src/SemVer.hs
blob: 47b49ab92dec5f10b2c687fb6c85f7bc8166a6fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
module SemVer where

import Control.Applicative
import Text.Trifecta

-- 1. Write a parser for semantic versions as defined by http://semver.org/.
-- After making a working parser, write an Ord instance for the SemVer type
-- that obeys the specification outlined on the SemVer website.

-- Relevant to precedence/ordering,
-- cannot sort numbers like strings.
data NumberOrString = NOSS String
                    | NOSI Integer
                    deriving (Eq, Show)

type Major = Integer
type Minor = Integer
type Patch = Integer
type Release = [NumberOrString]
type Metadata = [NumberOrString]

data SemVer = SemVer Major Minor Patch Release Metadata
    deriving (Eq, Show)

parseNos :: Parser NumberOrString
parseNos = do
    nos <- (NOSI <$> integer)
       <|> (NOSS <$> some letter)
    return nos

parseRelease :: Parser [NumberOrString]
parseRelease = do
    _ <- char '-'
    sepBy parseNos (char '.')

parseMetadata :: Parser [NumberOrString]
parseMetadata = do
    _ <- char '+'
    sepBy parseNos (char '.')

parseSemVer :: Parser SemVer
parseSemVer = do
    major <- decimal
    _ <- char '.'
    minor <- decimal
    _ <- char '.'
    patch <- decimal
    release <- option [] parseRelease
    metadata <- option [] parseMetadata

    return $ SemVer major minor patch release metadata