module HESQL.Parser (hesqlModule) where import HESQL.Syntax import Text.Parsec.String import Text.Parsec import Text.Parsec.Language (haskellDef) import qualified Text.Parsec.Token as P import Data.List (intercalate) import Database.HsSqlPpp.Parsing.Parser hesqlModule :: FilePath -> Parser HesqlModule hesqlModule fileName = do whiteSpace modName <- moduleHeader decls' <- decls fileName whiteSpace eof return $ HesqlModule modName decls' decls :: FilePath -> Parser [HesqlDecls] decls fileName = many (decl fileName) decl :: String -> Parser HesqlDecls decl fileName = do fn <- funName p <- many parameter whiteSpace char '=' whiteSpace queryOpt' <- queryOpt stmtLoc <- getPosition stmtStr <- sqlStatement whiteSpace stmt <- case parseSqlWithPosition fileName (sourceLine stmtLoc) (sourceColumn stmtLoc) stmtStr of Right [stmt] -> return stmt Right _ -> error "unexpected number of statements" Left e -> error $ show e -- TODO proper error message, handle other Right cases return $ HesqlDecls fn p queryOpt' stmt queryOpt :: Parser QueryOpt 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' :: Parser String sqlStatement' = do r <- sqlQuoted "\"" <|> sqlQuoted "'" <|> sqlTerminator if (r == ";") then return r else do s <- sqlStatement return $ r++s sqlQuoted :: String -> Parser String sqlQuoted s = do l <- between (string s) (string s) $ many qchars return $ s ++ concat l ++ s where qchars = many1 (noneOf ('\\':s)) <|> do char '\\' q <- anyChar return ['\\', q] sqlTerminator :: Parser String sqlTerminator = string ";" funName :: Parser String funName = identifier parameter = identifier moduleName = sepBy1 identifier (char '.') moduleHeader = do reserved "module" m <- moduleName 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