hirt-0.0.1.0: Parse.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TupleSections #-}
module Parse where
import Types
import Control.Applicative
import Control.Monad
import Data.Attoparsec.Text
import Data.Char
import Data.List
import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Text.IO as T
skipLine :: Parser ()
skipLine = skipWhile (not . isEndOfLine) >> endOfLine
spaceyEndOfLine :: Parser ()
spaceyEndOfLine = skipWhile (\x -> isSpace x && (not . isEndOfLine) x) >> endOfLine
class Parseable a where
names :: a -> [T.Text]
parser :: Parser a
instance Parseable AB where
names _ = ["a", "b"]
parser = (,) <$> double <* skipSpace <*> double
instance Parseable ABC where
names _ = ["a", "b", "c"]
parser = (,,) <$> double <* skipSpace <*> double <* skipSpace <*> double
headable :: Parser () -> Parser a -> Parser a
headable header list = (header >> list) <|> list
line :: [T.Text] -> Parser ()
line xs = (sequence . map name $ xs) >> skipLine
where name n = skipSpace >> string n
responsesParser :: Parser [(Contestant, Task, Points)]
responsesParser = headable header list <* endOfInput
where
header = line ["contestant", "task", "result"]
list = many $ do
skipSpace
c <- takeTill isSpace <* skipSpace
t <- takeTill isSpace <* skipSpace
r <- double <* endOfLine
return (c, t, r > 0)
thetasParser :: Parser [(Contestant, Theta)]
thetasParser = headable header list <* endOfInput
where
header = line ["theta"]
list = many $ do
skipSpace
c <- takeTill isSpace <* skipSpace
t <- double <* skipLine
return (c, t)
taskParamParser :: Parser (Task, TaskParam)
taskParamParser = do
t <- takeTill isSpace <* skipSpace
p <- parser
return (t,p)
taskParamsParser :: [Task] -> Parser [(Task, TaskParam)]
taskParamsParser tasks = headable header list <* endOfInput
where
header = line $ names (undefined :: TaskParam)
list = matchList paramsParser <|> (matchList $ many $ (taskParamParser <* skipLine))
matchList p = do
xs <- p
when (length xs /= length tasks) $
fail $ "expecting " ++ (show $ length tasks)
++ " tasks while " ++ (show $ length xs) ++ " found."
when ((sort $ map fst xs) /= (sort tasks)) $
fail "task names do not match"
return xs
paramsParser = do
ps <- many $ parser <* endOfLine
return $ zip (tasks ++ repeat "") ps
twologParser :: Parser [TaskParam]
twologParser = do
_ <- manyTill (skipWhile (not . isEndOfLine) >> endOfLine) endOfLine
many $ parser <* spaceyEndOfLine
justParse :: Parser a -> Text -> a
justParse p s = case parseOnly p s of
Left e -> error e
Right r -> r
fromFile :: Parser a -> FilePath -> IO a
fromFile p f = fmap (justParse p) (T.readFile f)