Skip to content

Commit e34bc19

Browse files
committed
refactor: do not bound error types
1 parent de884e0 commit e34bc19

File tree

3 files changed

+77
-36
lines changed

3 files changed

+77
-36
lines changed

src/Text/Megaparsec/Time.hs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,21 @@ import Data.Time (Day, DayOfWeek (..),
2121
NominalDiffTime, TimeOfDay (..),
2222
defaultTimeLocale, parseTimeM,
2323
secondsToNominalDiffTime)
24-
import Data.Void (Void)
2524
import Text.Megaparsec (Parsec, takeRest, try)
2625
import Text.Megaparsec.Char (char, digitChar, space, space1,
2726
string')
2827
import Text.Megaparsec.Utils (posNumParser)
2928

3029
type DayResult = Either Int DayOfWeek
3130

32-
dateParser :: Parsec Void String (Maybe DayResult, TimeOfDay)
31+
dateParser
32+
:: Ord e
33+
=> Parsec e String (Maybe DayResult, TimeOfDay)
3334
dateParser = (,) <$> optional (try (dayParser <* space1)) <*> timeParser
3435

35-
dayParser :: Parsec Void String DayResult
36+
dayParser
37+
:: Ord e
38+
=> Parsec e String DayResult
3639
dayParser = choice
3740
[ Right <$> longDay
3841
, Right <$> shortDay
@@ -48,7 +51,9 @@ dayParser = choice
4851
absoluteDay = toEnum . read <$> some digitChar
4952
relativeDay = ($) <$> sign <*> (read <$> some digitChar)
5053

51-
durationParser :: Parsec Void String NominalDiffTime
54+
durationParser
55+
:: Ord e
56+
=> Parsec e String NominalDiffTime
5257
durationParser = try hours <|> try minutes <|> secondsParser
5358
where hours = do
5459
h <- hoursParser <* space
@@ -63,22 +68,32 @@ durationParser = try hours <|> try minutes <|> secondsParser
6368

6469
return $ m + s
6570

66-
gregorianDayParser :: Parsec Void String Day
71+
gregorianDayParser
72+
:: Ord e
73+
=> Parsec e String Day
6774
gregorianDayParser = do
6875
s <- takeRest
6976
parseTimeM False defaultTimeLocale "%F" s <|>
7077
parseTimeM False defaultTimeLocale "%d/%m/%Y" s
7178

72-
hoursParser :: Parsec Void String NominalDiffTime
79+
hoursParser
80+
:: Ord e
81+
=> Parsec e String NominalDiffTime
7382
hoursParser = secondsToNominalDiffTime . (* 3600) <$> posNumParser <* char 'h'
7483

75-
minutesParser :: Parsec Void String NominalDiffTime
84+
minutesParser
85+
:: Ord e
86+
=> Parsec e String NominalDiffTime
7687
minutesParser = secondsToNominalDiffTime . (* 60) <$> posNumParser <* char 'm'
7788

78-
secondsParser :: Parsec Void String NominalDiffTime
89+
secondsParser
90+
:: Ord e
91+
=> Parsec e String NominalDiffTime
7992
secondsParser = secondsToNominalDiffTime <$> posNumParser <* optional (char 's')
8093

81-
timeParser :: Parsec Void String TimeOfDay
94+
timeParser
95+
:: Ord e
96+
=> Parsec e String TimeOfDay
8297
timeParser = do
8398
h <- read <$> replicateM 2 digitChar
8499
void $ char ':'

src/Text/Megaparsec/Utils.hs

Lines changed: 40 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -26,66 +26,85 @@ import Data.Maybe (fromJust)
2626
import qualified Data.Text as T (unpack)
2727
import Data.UUID (UUID)
2828
import qualified Data.UUID as U (fromString)
29-
import Data.Void (Void)
30-
import Text.Megaparsec (Parsec, anySingle,
31-
errorBundlePretty, runParser,
32-
try)
29+
import Text.Megaparsec (Parsec, ShowErrorComponent,
30+
anySingle, errorBundlePretty,
31+
runParser, try)
3332
import Text.Megaparsec.Char (char, digitChar, hexDigitChar,
3433
string')
3534

3635
-- | Parse a case-insensitive human-readable boolean, including C-style numbers
3736
-- and English yes-no.
38-
boolParser :: Parsec Void String Bool
37+
boolParser
38+
:: Ord e
39+
=> Parsec e String Bool
3940
boolParser = true <|> false
4041
where true = True <$ choice (map string' ["true", "y", "yes", "1"])
4142
false = False <$ choice (map string' ["false", "n", "no", "0"])
4243

4344
-- | Parse a 'Bounded' 'Enum' type that has a 'Show' instance, trying all
4445
-- possibilities, case-insensitive, in the 'Enum' order.
4546
boundedEnumShowParser
46-
:: Bounded a
47+
:: Ord e
48+
=> Bounded a
4749
=> Enum a
4850
=> Show a
49-
=> Parsec Void String a
51+
=> Parsec e String a
5052
boundedEnumShowParser =
5153
choice . map parseShow $ sortOn (negate . length . show) [minBound ..]
5254
where parseShow a = string' (show a) $> a
5355

5456
-- | Parse a comma-separated list of items.
55-
commaSeparated :: Parsec Void String a -> Parsec Void String (NonEmpty a)
57+
commaSeparated
58+
:: Ord e
59+
=> Parsec e String a
60+
-> Parsec e String (NonEmpty a)
5661
commaSeparated p = (:|) <$> p <*> many (char ',' >> p)
5762

5863
-- | Parse any occurrence of a given parser. Consumes any input before occurence.
59-
occurrence :: Parsec Void String a -> Parsec Void String a
64+
occurrence
65+
:: Ord e
66+
=> Parsec e String a
67+
-> Parsec e String a
6068
occurrence p = go
6169
where go = p <|> (anySingle >> go)
6270

6371
-- | Parse all occurrences of a given parser.
64-
occurrences :: Parsec Void String a -> Parsec Void String [a]
72+
occurrences
73+
:: Ord e
74+
=> Parsec e String a
75+
-> Parsec e String [a]
6576
occurrences = some . try . occurrence . try
6677

6778
-- | Parse a positive number with decimals.
68-
posDecNumParser :: Parsec Void String Double
79+
posDecNumParser
80+
:: Ord e
81+
=> Parsec e String Double
6982
posDecNumParser = do
7083
num <- some digitChar
7184
den <- maybe "" ("." <>) <$> optional (char '.' >> some digitChar)
7285

7386
return . read $ num <> den
7487

7588
-- | Parse a positive integer.
76-
posNumParser :: Read a => Parsec Void String a
89+
posNumParser
90+
:: Ord e
91+
=> Read a
92+
=> Parsec e String a
7793
posNumParser = read <$> some digitChar
7894

7995
-- | Parse an integer, without any spaces between minus sign and digits.
80-
numParser :: Parsec Void String Int
96+
numParser
97+
:: Ord e
98+
=> Parsec e String Int
8199
numParser = (char '-' >> negate <$> posNumParser) <|> posNumParser
82100

83101
-- | Convert a 'Parsec' parser into a 'Parser' suited for 'FromJSON' instances.
84102
parsecToJSONParser
103+
:: ShowErrorComponent e
85104
-- ^ Parser name.
86-
:: String
105+
=> String
87106
-- ^ Parser.
88-
-> Parsec Void String a
107+
-> Parsec e String a
89108
-- ^ Input value.
90109
-> Value
91110
-> Parser a
@@ -94,11 +113,15 @@ parsecToJSONParser n p =
94113

95114
-- | Convert a 'Parsec' parser into a 'ReadS' parser. Useful for defining 'Read'
96115
-- instances with 'Megaparsec'.
97-
parsecToReadsPrec :: Parsec Void String a -> ReadS a
116+
parsecToReadsPrec
117+
:: Parsec e String a
118+
-> ReadS a
98119
parsecToReadsPrec p = either (const []) (\x -> [(x, "")]) . runParser p "string"
99120

100121
-- | Parse a RFC4122-compliant UUID.
101-
uuidParser :: Parsec Void String UUID
122+
uuidParser
123+
:: Ord e
124+
=> Parsec e String UUID
102125
uuidParser = do
103126
part1 <- replicateM 8 hexDigitChar
104127
void $ char '-'

test/Text/Megaparsec/UtilsSpec.hs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
{-# LANGUAGE TypeApplications #-}
12
{-# OPTIONS_GHC -Wno-orphans #-}
23

34
module Text.Megaparsec.UtilsSpec
@@ -111,44 +112,46 @@ parseOrPrettyError p = first errorBundlePretty . runParser p "test"
111112

112113
spec :: Spec
113114
spec = do
115+
let parseMaybe' = parseMaybe @Void
116+
114117
describe "parsers" $ do
115118
it "SomeData" . property $ \v ->
116-
parseMaybe someDataParser (show (v :: SomeData)) `shouldBe` Just v
119+
parseMaybe' someDataParser (show (v :: SomeData)) `shouldBe` Just v
117120

118121
it "SomeEnum" . property $ \v ->
119-
parseMaybe someEnumParser (show (v :: SomeEnum)) `shouldBe` Just v
122+
parseMaybe' someEnumParser (show (v :: SomeEnum)) `shouldBe` Just v
120123

121124
it "SomeADT" . property $ \v ->
122-
parseMaybe someADTParser (show (v :: SomeADT)) `shouldBe` Just v
125+
parseMaybe' someADTParser (show (v :: SomeADT)) `shouldBe` Just v
123126

124127
context "posDecNumParser" $ do
125128
it "no decimals" . property $ \v ->
126-
parseMaybe posDecNumParser (show (abs (v :: Int))) `shouldBe`
129+
parseMaybe' posDecNumParser (show (abs (v :: Int))) `shouldBe`
127130
Just (fromIntegral (abs v))
128131

129132
it "decimals" . property $ \v ->
130-
parseMaybe posDecNumParser (printf "%f" (abs (v :: Double))) `shouldBe`
133+
parseMaybe' posDecNumParser (printf "%f" (abs (v :: Double))) `shouldBe`
131134
Just (abs v)
132135

133136
it "posNumParser" . property $ \v ->
134-
parseMaybe posNumParser (show (abs (v :: Int))) `shouldBe` Just (abs v)
137+
parseMaybe' posNumParser (show (abs (v :: Int))) `shouldBe` Just (abs v)
135138

136139
it "numParser" . property $ \v ->
137-
parseMaybe numParser (show (v :: Int)) `shouldBe` Just v
140+
parseMaybe' numParser (show (v :: Int)) `shouldBe` Just v
138141

139142
describe "boundedEnumShowParser" $ do
140143
context "lowercase" . exhaustive $ \v ->
141-
parseMaybe (boundedEnumShowParser <* eof) (show v) `shouldBe` Just (v :: SomeEnum)
144+
parseMaybe' (boundedEnumShowParser <* eof) (show v) `shouldBe` Just (v :: SomeEnum)
142145

143146
context "uppercase" . exhaustive $ \v ->
144-
parseMaybe (boundedEnumShowParser <* eof) (map toUpper (show v))
147+
parseMaybe' (boundedEnumShowParser <* eof) (map toUpper (show v))
145148
`shouldBe` Just (v :: SomeEnum)
146149

147150
context "mixed" . exhaustive $ \v -> do
148151
let capitalize i x | even i = toUpper x
149152
| otherwise = x
150153
mixCase = zipWith capitalize [(0 :: Int) ..]
151-
parseMaybe (boundedEnumShowParser <* eof) (mixCase (show v))
154+
parseMaybe' (boundedEnumShowParser <* eof) (mixCase (show v))
152155
`shouldBe` Just (v :: SomeEnum)
153156

154157
describe "occurrence" $ do

0 commit comments

Comments
 (0)