module Data.Dates.Internal where
import Data.Char
import Text.Parsec
import Text.Parsec.String
tryRead :: Read a => String -> Parsec String st a
tryRead str =
case reads str of
[(res, "")] -> return res
_ -> fail $ "Cannot read: " ++ str
tryReadInt ∷ Num a ⇒ String → Parsec String st a
tryReadInt str =
if all isDigit str
then return $ fromIntegral $ foldl (\a b → 10*a+b) 0 $ map digitToInt str
else fail $ "Cannot read: " ++ str
times ∷ Int
→ Parsec String st t
→ Parsec String st [t]
times 0 _ = return []
times n p = do
ts ← times (n1) p
t ← optionMaybe p
case t of
Just t' → return (ts ++ [t'])
Nothing → return ts
number ∷ Int
→ Int
→ Parsec String st Int
number n m = do
t ← tryReadInt =<< (n `times` digit)
if t > m
then fail "number too large"
else return t
pYear ∷ Parsec String st Int
pYear = do
y ← number 4 10000
if y < 2000
then return (y+2000)
else return y
pMonth ∷ Parsec String st Int
pMonth = number 2 12
pDay ∷ Parsec String st Int
pDay = number 2 31