diff options
author | Joris | 2016-04-04 22:48:33 +0200 |
---|---|---|
committer | Joris | 2016-04-04 22:48:33 +0200 |
commit | d8eedc3e2639f0f50f0554f89dc121da4941d4d1 (patch) | |
tree | 81bd4d0a261b0550a0501ad2f70fa52b4ee21000 /src/Model/EventParser.hs | |
parent | e66ea0b49c8f7202114df366668598026f211eba (diff) |
Rename birthday to event
Diffstat (limited to 'src/Model/EventParser.hs')
-rw-r--r-- | src/Model/EventParser.hs | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/src/Model/EventParser.hs b/src/Model/EventParser.hs new file mode 100644 index 0000000..7a9955f --- /dev/null +++ b/src/Model/EventParser.hs @@ -0,0 +1,92 @@ +{-# LANGUAGE OverloadedStrings #-} + +module Model.EventParser + ( parseEvents + ) where + +import Control.Arrow (left) + +import Data.Text (Text) +import qualified Data.Text as T +import Data.Maybe (catMaybes) + +import Text.ParserCombinators.Parsec +import Text.Parsec.Char (endOfLine) + +import Model.Event (Event, Event(Event)) +import qualified Model.Event as Event +import Model.Date (Date(Date)) +import qualified Model.Date as Date + +parseEvents :: Text -> Either Text [Event] +parseEvents input = + left (T.pack . show) (parse eventsParser "" (T.unpack input)) >>= validateEvents + +validateEvents :: [Event] -> Either Text [Event] +validateEvents events = + let invalid = filter (not . Date.isValid . Event.date) events + in if null invalid + then + Right events + else + Left $ + T.concat + [ "Invalid events: " + , T.intercalate ", " (map Event.renderEvent invalid) + ] + +eventsParser :: Parser [Event] +eventsParser = concat <$> many monthSection + +monthSection :: Parser [Event] +monthSection = do + month <- monthSectionTitle + spaces + events <- catMaybes <$> many lineParser + return $ + map (\(day, year, name) -> + Event (Date day month year) name + ) events + +lineParser :: Parser (Maybe (Int, Int, Text)) +lineParser = + (Just <$> eventParser <* endOfLine) + <|> (comment >> return Nothing) + <|> (emptyLine >> return Nothing) + +monthSectionTitle :: Parser Int +monthSectionTitle = char '[' *> monthParser <* char ']' + +monthParser :: Parser Int +monthParser = + (try $ string "January" >> return 1) + <|> (try $ string "February" >> return 2) + <|> (try $ string "March" >> return 3) + <|> (try $ string "April" >> return 4) + <|> (try $ string "May" >> return 5) + <|> (try $ string "June" >> return 6) + <|> (try $ string "July" >> return 7) + <|> (try $ string "August" >> return 8) + <|> (try $ string "September" >> return 9) + <|> (try $ string "October" >> return 10) + <|> (try $ string "November" >> return 11) + <|> (try $ string "December" >> return 12) + +eventParser :: Parser (Int, Int, Text) +eventParser = + (,,) <$> + integerParser <* separator ',' <*> + integerParser <* separator ':' <*> + (T.strip . T.pack <$> many (noneOf "\n")) + +separator :: Char -> Parser () +separator c = many (char ' ') >> char c >> many (char ' ') >> return () + +integerParser :: Parser Int +integerParser = (read :: String -> Int) <$> many1 digit + +emptyLine :: Parser () +emptyLine = skipMany (char ' ') >> endOfLine >> return () + +comment :: Parser () +comment = char '#' >> many (noneOf "\n") >> endOfLine >> return () |