module HESQL.Parser (hesqlModule) where import HESQL.Syntax import Text.Parsec.String import Text.Parsec import Text.Parsec.Language (haskellDef) import Text.Parsec.Expr import qualified Text.Parsec.Token as P import Data.List (intercalate) import Database.HDBC import Control.Monad (forM_) import Database.HsSqlPpp.Parsing.Parser hesqlModule :: Parser HesqlModule hesqlModule = do whiteSpace modName <- moduleHeader decls <- decls whiteSpace eof return $ HesqlModule modName decls decls = many decl decl = do fn <- funName p <- many parameter whiteSpace char '=' whiteSpace queryOpt <- queryOpt stmtStr <- sqlStatement whiteSpace stmt <- case parseSql stmtStr of Right [stmt] -> return stmt Left e -> error $ show e -- TODO proper error message, handle other Right cases return $ HesqlDecls fn p queryOpt stmt queryOpt = (reserved "maybe" >> return MaybeQuery) <|> (reserved "lazy" >> return LazyQuery) <|> return StrictQuery sqlStatement :: Parser String sqlStatement = do s <- many (noneOf "\"';") r <- sqlStatement' return $ s ++ r sqlStatement' = do r <- sqlQuoted "\"" <|> sqlQuoted "'" <|> sqlTerminator if (r == ";") then return r else do s <- sqlStatement return $ r++s sqlQuoted s = do l <- between (string s) (string s) $ many qchars return $ s ++ concat l ++ s where qchars = many1 (noneOf ('\\':s)) <|> do c <- char '\\' q <- anyChar return ['\\', q] sqlTerminator = string ";" funName = identifier parameter = identifier modName = sepBy1 identifier (char '.') moduleHeader = do reserved "module" m <- modName reserved "where" return $ intercalate "." m lexer = P.makeTokenParser haskellDef parens = P.parens lexer braces = P.braces lexer identifier = P.identifier lexer reserved = P.reserved lexer reservedOp = P.reservedOp lexer whiteSpace = P.whiteSpace lexer symbol = P.symbol lexer naturalOrFloat = P.naturalOrFloat lexer