Clean up whitespace during the quasi-quote parsing

This commit is contained in:
Nikita Volkov 2014-12-27 07:18:04 +03:00
parent 89875c763a
commit 9572af05ad
3 changed files with 56 additions and 25 deletions

View File

@ -22,5 +22,23 @@ main =
context "Quasi quoter" $ do context "Quasi quoter" $ do
it "generates a proper statement" $ do it "generates a proper statement" $ do
(flip shouldBe) (flip shouldBe)
(HB.Stmt " SELECT (? + ?) " (V.fromList [HB.encodeValue 'a', HB.encodeValue 'b']) True) (HB.Stmt "SELECT (? + ?)" (V.fromList [HB.encodeValue 'a', HB.encodeValue 'b']) True)
([H.stmt| SELECT (? + ?) |] 'a' 'b' :: HB.Stmt X) ([H.stmt| SELECT (? + ?) |] 'a' 'b' :: HB.Stmt X)
it "does not drop quotes" $ do
let
HB.Stmt t _ _ =
[H.stmt| SELECT "a", 'b' |]
(flip shouldBe)
"SELECT \"a\", 'b'"
t
it "cleans whitespace" $ do
let
HB.Stmt t _ _ =
[H.stmt| CREATE TABLE data (
field1 DECIMAL NOT NULL,
field2 BIGINT NOT NULL,
PRIMARY KEY (field1)
) |]
(flip shouldBe)
"CREATE TABLE data ( field1 DECIMAL NOT NULL, field2 BIGINT NOT NULL, PRIMARY KEY (field1) )"
t

View File

@ -60,6 +60,7 @@ import qualified Hasql.RowParser as RowParser
import qualified Hasql.QParser as QParser import qualified Hasql.QParser as QParser
import qualified ListT import qualified ListT
import qualified Data.Pool as Pool import qualified Data.Pool as Pool
import qualified Data.Text as Text
import qualified Data.Vector as Vector import qualified Data.Vector as Vector
import qualified Data.Vector.Mutable as MVector import qualified Data.Vector.Mutable as MVector
import qualified Language.Haskell.TH as TH import qualified Language.Haskell.TH as TH
@ -337,8 +338,8 @@ stmt =
where where
parseExp s = parseExp s =
do do
n <- either (fail . showString "Parsing failure: ") return (QParser.parse (fromString s)) (t, n) <- either (fail . showString "Parsing failure: ") return (QParser.parse (fromString s))
return $ statementF s (fromIntegral n) return $ statementF (Text.unpack t) (fromIntegral n)
statementF s n = statementF s n =
TH.LamE TH.LamE
(map TH.VarP argNames) (map TH.VarP argNames)

View File

@ -2,37 +2,49 @@ module Hasql.QParser where
import Hasql.Prelude hiding (takeWhile) import Hasql.Prelude hiding (takeWhile)
import Data.Attoparsec.Text hiding (Result) import Data.Attoparsec.Text hiding (Result)
import qualified Data.Text as Text import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Lazy.Builder as TLB
-- | -- |
-- The amount of placeholders. -- Produces a whitespace-cleaned text and a count of placeholders in it.
type Result = parse :: Text -> Either String (Text, Int)
(Word)
parse :: Text -> Either String Result
parse = parse =
parseOnly $ flip execStateT 0 $ parseOnly $ singleTemplate
statement *>
(lift endOfInput <|> singleTemplate :: Parser (Text, Int)
(void (lift (char ';')) <* fail "A semicolon detected. Only single statements are allowed")) singleTemplate =
where template <*
statement = ((endOfInput) <|>
skipMany1 $ (() <$ skipSpace <* char ';' <* fail "A semicolon detected. Only single statements are allowed"))
void (lift stringLit) <|>
void (lift (char '?') <* modify succ) <|> template :: Parser (Text, Int)
void (lift (notChar ';')) template =
flip runStateT 0 $ do
lift $ skipSpace
fmap (TL.toStrict . TLB.toLazyText . mconcat) $
many $
(mempty <$ lift trailingWhitespace) <|>
(TLB.singleton ' ' <$ lift (takeWhile1 isSpace)) <|>
(TLB.fromText <$> lift stringLit) <|>
(TLB.singleton <$> lift (char '?') <* modify succ) <|>
(TLB.singleton <$> lift (notChar ';'))
trailingWhitespace :: Parser ()
trailingWhitespace =
() <$ takeWhile1 isSpace <* endOfInput
stringLit :: Parser Text stringLit :: Parser Text
stringLit = stringLit =
do do
quote <- quote <-
char '"' <|> char '\'' char '"' <|> char '\''
text <- content <-
fmap mconcat $ many $ fmap mconcat $ many $
string "\\\\" <|> TLB.fromText <$> string "\\\\" <|>
string (fromString ['\\', quote]) <|> TLB.fromText <$> string (fromString ['\\', quote]) <|>
(Text.singleton <$> notChar quote) TLB.singleton <$> notChar quote
char quote char quote
return text return $ TL.toStrict . TLB.toLazyText $
TLB.singleton quote <> content <> TLB.singleton quote