> {-# LANGUAGE ExplicitForAll,TupleSections,
>              NoMonomorphismRestriction,OverloadedStrings,
>              FlexibleContexts, RankNTypes #-}
> module Database.Dawdle.Parser
>        (parseCsv)
> where
> import Database.Dawdle.Types
> import Data.Text.Lazy (Text)
> import Text.Parsec
> parseCsv :: Char -> String -> Text -> Either ParseError [[String]]
> parseCsv sepChar = parse (csvFile sepChar)
> newLines :: String
> newLines = "\n\r"
> quoteChars :: String
> quoteChars = "'\""
> csvFile :: Char -> SParser [[String]]
> csvFile sepChar = endBy (line sepChar) eol
> line :: Char -> SParser [String]
> line sepChar = sepBy (cell sepChar) (char sepChar)
> cell :: Char -> SParser String
> cell sepChar = quotedCell <|> many (noneOf (sepChar:newLines))
> quotedCell :: SParser String
> quotedCell = do
>        sChar <- (oneOf quoteChars)
>        content <- many (fmap return nonEscape <|> escape) --(quotedChar sChar)
>        _ <- char sChar <?> "quote at end of cell"
>        return $ concat content
quotedChar :: Char -> SParser Char quotedChar csep = noneOf [csep] <|> try (string (replicate 2 csep) >> return csep)
> nonEscape :: SParser Char
> nonEscape = noneOf "\\\"\0\n\r\v\t\b\f"
> escape :: SParser String
> escape = do
>   d <- char '\\'
>   c <- oneOf "\\\"0nrvtbf"
>   return [d,c]
> eol :: SParser String
> eol =   try (string newLines)
>     <|> try (string (reverse newLines))
>     <|> string "\n"
>     <|> string "\r"
>     <?> "end of line"