module RestyScript.Parser.Action ( readAction ) where import RestyScript.Parser import RestyScript.Parser.View import RestyScript.AST import Text.ParserCombinators.Parsec import Text.ParserCombinators.Parsec.Expr import Monad (liftM, msum) readAction :: String -> String -> Either ParseError RSVal readAction = parse parseAction parseAction :: Parser RSVal parseAction = do spaces stmts <- sepEndBy1 parseStmt $ many1 (char ';' >> spaces) eof return $ Action stmts parseStmt :: Parser RSVal parseStmt = parseDelete <|> parseUpdate <|> parseHttp <|> parseView "action statement" httpCmds = ["GET", "PUT", "DELETE", "POST"] parseHttp :: Parser RSVal parseHttp = do cmd <- msum $ map keyword httpCmds spaces url <- parseLitExpr content <- option Empty parseJSON return $ HttpCmd cmd url content litOpTable = [ [Infix (do { reservedOp "||"; spaces; return Concat} "operator") AssocLeft] ] parseLitExpr :: Parser RSVal parseLitExpr = buildExpressionParser litOpTable parseLitAtom "literal expression" parseLitAtom :: Parser RSVal parseLitAtom = parseNumber <|> parseString <|> parseDString <|> try (parseVerbatimString) <|> parseVariable <|> parens parseLitExpr -- Double quoted strings in the context of HTTP commands parseDString :: Parser RSVal parseDString = do s <- between (char '"' >> spaces) (char '"' >> spaces) $ many $ quotedChar '"' spaces return $ String s parseJSON :: Parser RSVal parseJSON = parseObject <|> parseArray <|> parseLitExpr "JSON content" parseObject :: Parser RSVal parseObject = do obj <- between (char '{' >> spaces) (char '}' >> spaces) $ sepBy1 parsePair (char ',' >> spaces) spaces return $ Object obj parsePair :: Parser RSVal parsePair = do key <- parseKey char ':' spaces value <- parseJSON return $ Pair key value parseKey :: Parser RSVal parseKey = parseLitExpr <|> liftM String symbol "JSON hash key" parseArray :: Parser RSVal parseArray = do lst <- between (char '[' >> spaces) (char ']' >> spaces) $ sepBy parseJSON (char ',' >> spaces) spaces return $ Array lst parseDelete :: Parser RSVal parseDelete = do keyword "delete" >> spaces >> keyword "from" >> spaces model <- parseModel cond <- parseWhere return $ Delete model cond "SQL delete statement" parseUpdate :: Parser RSVal parseUpdate = do keyword "update" >> spaces model <- parseModel assign <- keyword "set" >> spaces >> parseAssign cond <- option Empty parseWhere return $ Update model assign cond "SQL update statement" parseAssign :: Parser RSVal parseAssign = do col <- parseColumn char '=' >> spaces expr <- parseExpr return $ Assign col expr "Column assignment"