1
Fork 0

new syntax for names and string literals

This commit is contained in:
Jake Wheat 2016-02-12 13:09:58 +02:00
parent 1b4eefc431
commit 52f035b718
8 changed files with 150 additions and 165 deletions

View file

@ -50,26 +50,20 @@ parsec
> -- > --
> | Identifier String > | Identifier String
> >
> -- | This is an identifier quoted with " > -- | This is a quoted identifier, the quotes can be " or u&,
> | QIdentifier String > -- etc. or something dialect specific like []
> -- | This is an identifier quoted with u&" > -- the first two fields are the start and end quotes
> | UQIdentifier String > | QuotedIdentifier String -- start quote
> String -- end quote
> -- | This is a dialect specific quoted identifier with the quote > String -- content
> -- characters explicit. The first and second fields are the
> -- starting and ending quote characters.
> | DQIdentifier String String String
>
> -- | This is a host param symbol, e.g. :param > -- | This is a host param symbol, e.g. :param
> | HostParam String > | HostParam String
> >
> -- | This is a string literal. > -- | This is a string literal. The first two fields are the --
> | SqlString String > -- start and end quotes, which are usually both ', but can be
> > -- the character set (one of nNbBxX, or u&, U&), or a dialect
> -- | This is a character set string literal. The first field is > -- specific string quoting (such as $$ in postgres)
> -- the character set (one of nNbBxX, or u&, U&). > | SqlString String String String
> | CSSqlString String String
>
> -- | A number literal (integral or otherwise), stored in original format > -- | A number literal (integral or otherwise), stored in original format
> -- unchanged > -- unchanged
> | SqlNumber String > | SqlNumber String
@ -95,15 +89,19 @@ parsec
> prettyToken :: Dialect -> Token -> String > prettyToken :: Dialect -> Token -> String
> prettyToken _ (Symbol s) = s > prettyToken _ (Symbol s) = s
> prettyToken _ (Identifier t) = t > prettyToken _ (Identifier t) = t
> prettyToken _ (QIdentifier t) = > prettyToken _ (QuotedIdentifier q1 q2 t) =
> "\"" ++ doubleChars '"' t ++ "\"" > q1 ++
> prettyToken _ (UQIdentifier t) = > -- todo: a bit hacky, do a better design
> "u&\"" ++ doubleChars '"' t ++ "\"" > (if '"' `elem` q1 then doubleChars '"' t else t)
> prettyToken _ (DQIdentifier s e t) = > ++ q2
> s ++ t ++ e > --prettyToken _ (UQIdentifier t) =
> -- "u&\"" ++ doubleChars '"' t ++ "\""
> --prettyToken _ (DQIdentifier s e t) =
> -- s ++ t ++ e
> prettyToken _ (HostParam p) = ':':p > prettyToken _ (HostParam p) = ':':p
> prettyToken _ (SqlString t) = "'" ++ doubleChars '\'' t ++ "'" > prettyToken _ (SqlString s e t) =
> prettyToken _ (CSSqlString cs t) = cs ++ "'" ++ t ++ "'" > s ++ (if '\'' `elem` s then doubleChars '\'' t else t) ++ e
> --prettyToken _ (CSSqlString cs t) = cs ++ "'" ++ t ++ "'"
> prettyToken _ (SqlNumber r) = r > prettyToken _ (SqlNumber r) = r
> prettyToken _ (Whitespace t) = t > prettyToken _ (Whitespace t) = t
> prettyToken _ (LineComment l) = l > prettyToken _ (LineComment l) = l
@ -181,12 +179,14 @@ u&"unicode quoted identifier"
> identifier :: Dialect -> Parser Token > identifier :: Dialect -> Parser Token
> identifier d = > identifier d =
> choice > choice
> [QIdentifier <$> qiden > [QuotedIdentifier "\"" "\"" <$> qiden
> -- try is used here to avoid a conflict with identifiers > -- try is used here to avoid a conflict with identifiers
> -- and quoted strings which also start with a 'u' > -- and quoted strings which also start with a 'u'
> ,UQIdentifier <$> ((try (string "u&" <|> string "U&")) *> qiden) > ,QuotedIdentifier "u&\"" "\"" <$> (try (string "u&") *> qiden)
> ,QuotedIdentifier "U&\"" "\"" <$> (try (string "U&") *> qiden)
> ,Identifier <$> identifierString > ,Identifier <$> identifierString
> ,DQIdentifier "`" "`" <$> mySqlQIden > -- todo: dialect protection
> ,QuotedIdentifier "`" "`" <$> mySqlQIden
> ] > ]
> where > where
> qiden = char '"' *> qidenSuffix "" > qiden = char '"' *> qidenSuffix ""
@ -226,7 +226,7 @@ x'hexidecimal string'
> ,normalString > ,normalString
> ] > ]
> where > where
> normalString = SqlString {-"'"-} <$> (char '\'' *> normalStringSuffix "") > normalString = SqlString "'" "'" <$> (char '\'' *> normalStringSuffix "")
> normalStringSuffix t = do > normalStringSuffix t = do
> s <- takeTill (=='\'') > s <- takeTill (=='\'')
> void $ char '\'' > void $ char '\''
@ -239,10 +239,10 @@ x'hexidecimal string'
> -- identifiers which can start with n,b,x,u > -- identifiers which can start with n,b,x,u
> -- once we read the quote type and the starting ' > -- once we read the quote type and the starting '
> -- then we commit to a string > -- then we commit to a string
> csString = CSSqlString <$> try (cs <* char '\'') <*> normalStringSuffix "" > csString = SqlString <$> try cs <*> return "'" <*> normalStringSuffix ""
> cs = choice [(:[]) <$> oneOf "nNbBxX" > cs = choice $ (map (\x -> string ([x] ++ "'")) "nNbBxX")
> ,string "u&" > ++ [string "u&'"
> ,string "U&"] > ,string "U&'"]
> hostParam :: Dialect -> Parser Token > hostParam :: Dialect -> Parser Token
> hostParam _ = HostParam <$> (char ':' *> identifierString) > hostParam _ = HostParam <$> (char ':' *> identifierString)
@ -283,13 +283,15 @@ A symbol is one of the two character symbols, or one of the single
character symbols in the two lists below. character symbols in the two lists below.
> symbol :: Dialect -> Parser Token > symbol :: Dialect -> Parser Token
> symbol _ = Symbol <$> choice (many1 (char '.') : > symbol _ = Symbol <$>
> choice (
> many1 (char '.') :
> -- try is used because most of the first > -- try is used because most of the first
> -- characters of the two character symbols > -- characters of the two character symbols
> -- can also be part of a single character symbol > -- can also be part of a single character symbol
> -- maybe this would be better with left factoring? > -- maybe this would be better with left factoring?
> map (try . string) [">=","<=","!=","<>","||"] > map (try . string) [">=","<=","!=","<>","||"]
> ++ map (string . (:[])) "+-^*/%~&|?<>[]=,;()") > ++ map (string . (:[])) "+-^*/%~&|?<>[]=,;()")
> sqlWhitespace :: Dialect -> Parser Token > sqlWhitespace :: Dialect -> Parser Token
> sqlWhitespace _ = Whitespace <$> many1 (satisfy isSpace) > sqlWhitespace _ = Whitespace <$> many1 (satisfy isSpace)

View file

@ -330,10 +330,8 @@ u&"example quoted"
> name :: Parser Name > name :: Parser Name
> name = do > name = do
> d <- getState > d <- getState
> choice [QName <$> qidentifierTok > choice [Name <$> identifierTok (blacklist d) Nothing
> ,UQName <$> uqidentifierTok > ,(\(s,e,t) -> QuotedName s e t) <$> qidentifierTok
> ,Name <$> identifierTok (blacklist d) Nothing
> ,(\(s,e,t) -> DQName s e t) <$> dqidentifierTok
> ] > ]
todo: replace (:[]) with a named function all over todo: replace (:[]) with a named function all over
@ -558,16 +556,13 @@ factoring in this function, and it is a little dense.
See the stringToken lexer below for notes on string literal syntax. See the stringToken lexer below for notes on string literal syntax.
> stringLit :: Parser ValueExpr > stringLit :: Parser ValueExpr
> stringLit = StringLit <$> stringTokExtend > stringLit = (\(s,e,t) -> StringLit s e t) <$> stringTokExtend
> numberLit :: Parser ValueExpr > numberLit :: Parser ValueExpr
> numberLit = NumLit <$> sqlNumberTok False > numberLit = NumLit <$> sqlNumberTok False
> characterSetLit :: Parser ValueExpr
> characterSetLit = uncurry CSStringLit <$> csSqlStringLitTok
> simpleLiteral :: Parser ValueExpr > simpleLiteral :: Parser ValueExpr
> simpleLiteral = numberLit <|> stringLit <|> characterSetLit > simpleLiteral = numberLit <|> stringLit
== star, param, host param == star, param, host param
@ -690,7 +685,7 @@ this. also fix the monad -> applicative
> intervalLit = try (keyword_ "interval" >> do > intervalLit = try (keyword_ "interval" >> do
> s <- optionMaybe $ choice [True <$ symbol_ "+" > s <- optionMaybe $ choice [True <$ symbol_ "+"
> ,False <$ symbol_ "-"] > ,False <$ symbol_ "-"]
> lit <- stringTok > lit <- singleQuotesOnlyStringTok
> q <- optionMaybe intervalQualifier > q <- optionMaybe intervalQualifier
> mkIt s lit q) > mkIt s lit q)
> where > where
@ -716,7 +711,7 @@ all the value expressions which start with an identifier
> idenExpr :: Parser ValueExpr > idenExpr :: Parser ValueExpr
> idenExpr = > idenExpr =
> -- todo: work out how to left factor this > -- todo: work out how to left factor this
> try (TypedLit <$> typeName <*> stringTokExtend) > try (TypedLit <$> typeName <*> singleQuotesOnlyStringTok)
> <|> multisetSetFunction > <|> multisetSetFunction
> <|> (names <**> option Iden app) > <|> (names <**> option Iden app)
> where > where
@ -831,7 +826,7 @@ in the source
> keyword "trim" >> > keyword "trim" >>
> parens (mkTrim > parens (mkTrim
> <$> option "both" sides > <$> option "both" sides
> <*> option " " stringTok > <*> option " " singleQuotesOnlyStringTok
> <*> (keyword_ "from" *> valueExpr)) > <*> (keyword_ "from" *> valueExpr))
> where > where
> sides = choice ["leading" <$ keyword_ "leading" > sides = choice ["leading" <$ keyword_ "leading"
@ -839,7 +834,7 @@ in the source
> ,"both" <$ keyword_ "both"] > ,"both" <$ keyword_ "both"]
> mkTrim fa ch fr = > mkTrim fa ch fr =
> SpecialOpK [Name "trim"] Nothing > SpecialOpK [Name "trim"] Nothing
> $ catMaybes [Just (fa,StringLit ch) > $ catMaybes [Just (fa,StringLit "'" "'" ch)
> ,Just ("from", fr)] > ,Just ("from", fr)]
=== app, aggregate, window === app, aggregate, window
@ -1951,28 +1946,34 @@ unsigned integer match
symbol matching symbol matching
keyword matching keyword matching
> csSqlStringLitTok :: Parser (String,String) > stringTok :: Parser (String,String,String)
> csSqlStringLitTok = mytoken (\tok ->
> case tok of
> L.CSSqlString p s -> Just (p,s)
> _ -> Nothing)
> stringTok :: Parser String
> stringTok = mytoken (\tok -> > stringTok = mytoken (\tok ->
> case tok of > case tok of
> L.SqlString s -> Just s > L.SqlString s e t -> Just (s,e,t)
> _ -> Nothing)
> singleQuotesOnlyStringTok :: Parser String
> singleQuotesOnlyStringTok = mytoken (\tok ->
> case tok of
> L.SqlString "'" "'" t -> Just t
> _ -> Nothing) > _ -> Nothing)
This is to support SQL strings where you can write This is to support SQL strings where you can write
'part of a string' ' another part' 'part of a string' ' another part'
and it will parse as a single string and it will parse as a single string
> stringTokExtend :: Parser String It is only allowed when all the strings are quoted with ' atm.
> stringTokExtend :: Parser (String,String,String)
> stringTokExtend = do > stringTokExtend = do
> x <- stringTok > (s,e,x) <- stringTok
> choice [ > choice [
> ((x++) <$> stringTokExtend) > do
> ,return x > guard (s == "'" && e == "'")
> (s',e',y) <- stringTokExtend
> guard (s' == "'" && e' == "'")
> return $ (s,e,x ++ y)
> ,return (s,e,x)
> ] > ]
> hostParamTok :: Parser String > hostParamTok :: Parser String
@ -2002,25 +2003,12 @@ and it will parse as a single string
> (Just k, L.Identifier p) | k == map toLower p -> Just p > (Just k, L.Identifier p) | k == map toLower p -> Just p
> _ -> Nothing) > _ -> Nothing)
> qidentifierTok :: Parser String > qidentifierTok :: Parser (String,String,String)
> qidentifierTok = mytoken (\tok -> > qidentifierTok = mytoken (\tok ->
> case tok of > case tok of
> L.QIdentifier p -> Just p > L.QuotedIdentifier s e t -> Just (s,e,t)
> _ -> Nothing) > _ -> Nothing)
> dqidentifierTok :: Parser (String,String,String)
> dqidentifierTok = mytoken (\tok ->
> case tok of
> L.DQIdentifier s e t -> Just (s,e,t)
> _ -> Nothing)
> uqidentifierTok :: Parser String
> uqidentifierTok = mytoken (\tok ->
> case tok of
> L.UQIdentifier p -> Just p
> _ -> Nothing)
> mytoken :: (L.Token -> Maybe a) -> Parser a > mytoken :: (L.Token -> Maybe a) -> Parser a
> mytoken test = token showToken posToken testToken > mytoken test = token showToken posToken testToken
> where > where

View file

@ -16,7 +16,7 @@ which have been changed to try to improve the layout of the output.
> import Language.SQL.SimpleSQL.Dialect > import Language.SQL.SimpleSQL.Dialect
> import Text.PrettyPrint (render, vcat, text, (<>), (<+>), empty, parens, > import Text.PrettyPrint (render, vcat, text, (<>), (<+>), empty, parens,
> nest, Doc, punctuate, comma, sep, quotes, > nest, Doc, punctuate, comma, sep, quotes,
> doubleQuotes, brackets,hcat) > brackets,hcat)
> import Data.Maybe (maybeToList, catMaybes) > import Data.Maybe (maybeToList, catMaybes)
> import Data.List (intercalate) > import Data.List (intercalate)
@ -40,7 +40,8 @@ which have been changed to try to improve the layout of the output.
= value expressions = value expressions
> valueExpr :: Dialect -> ValueExpr -> Doc > valueExpr :: Dialect -> ValueExpr -> Doc
> valueExpr _ (StringLit s) = quotes $ text $ doubleUpQuotes s > valueExpr _ (StringLit s e t) =
> text (s ++ (if '\'' `elem` s then doubleUpQuotes t else t) ++ e)
> valueExpr _ (NumLit s) = text s > valueExpr _ (NumLit s) = text s
> valueExpr _ (IntervalLit s v f t) = > valueExpr _ (IntervalLit s v f t) =
@ -210,11 +211,6 @@ which have been changed to try to improve the layout of the output.
> Distinct -> text "distinct" > Distinct -> text "distinct"
> ,valueExpr d b] > ,valueExpr d b]
> valueExpr _ (CSStringLit cs st) =
> text cs <> quotes (text $ doubleUpQuotes st)
> valueExpr d (Escape v e) = > valueExpr d (Escape v e) =
> valueExpr d v <+> text "escape" <+> text [e] > valueExpr d v <+> text "escape" <+> text [e]
@ -243,21 +239,18 @@ which have been changed to try to improve the layout of the output.
> unname :: Name -> String > unname :: Name -> String
> unname (QName n) = "\"" ++ doubleUpDoubleQuotes n ++ "\""
> unname (UQName n) = "U&\"" ++ doubleUpDoubleQuotes n ++ "\""
> unname (Name n) = n > unname (Name n) = n
> unname (DQName s e n) = s ++ n ++ e > unname (QuotedName s e n) =
> s ++ (if '"' `elem` s then doubleUpDoubleQuotes n else n) ++ e
> unnames :: [Name] -> String > unnames :: [Name] -> String
> unnames ns = intercalate "." $ map unname ns > unnames ns = intercalate "." $ map unname ns
> name :: Name -> Doc > name :: Name -> Doc
> name (QName n) = doubleQuotes $ text $ doubleUpDoubleQuotes n
> name (UQName n) =
> text "U&" <> doubleQuotes (text $ doubleUpDoubleQuotes n)
> name (Name n) = text n > name (Name n) = text n
> name (DQName s e n) = text s <> text n <> text e > name (QuotedName s e n) =
> text s <> text (if '"' `elem` s then doubleUpDoubleQuotes n else n) <> text e
> names :: [Name] -> Doc > names :: [Name] -> Doc
> names ns = hcat $ punctuate (text ".") $ map name ns > names ns = hcat $ punctuate (text ".") $ map name ns

View file

@ -88,9 +88,9 @@
> -- > --
> -- * 12.34e-6 > -- * 12.34e-6
> NumLit String > NumLit String
> -- | string literal, currently only basic strings between > -- | string literal, with the start and end quote
> -- single quotes with a single quote escaped using '' > -- e.g. 'test' -> StringLit "'" "'" "test"
> | StringLit String > | StringLit String String String
> -- | text of interval literal, units of interval precision, > -- | text of interval literal, units of interval precision,
> -- e.g. interval 3 days (3) > -- e.g. interval 3 days (3)
> | IntervalLit > | IntervalLit
@ -203,8 +203,6 @@
> -- second is the subscripts/ctor args > -- second is the subscripts/ctor args
> | ArrayCtor QueryExpr -- ^ this is used for the query expression version of array constructors, e.g. array(select * from t) > | ArrayCtor QueryExpr -- ^ this is used for the query expression version of array constructors, e.g. array(select * from t)
> | CSStringLit String String
todo: special syntax for like, similar with escape - escape cannot go todo: special syntax for like, similar with escape - escape cannot go
in other places in other places
@ -220,10 +218,8 @@ in other places
> -- | Represents an identifier name, which can be quoted or unquoted. > -- | Represents an identifier name, which can be quoted or unquoted.
> data Name = Name String > data Name = Name String
> | QName String > | QuotedName String String String
> | UQName String > -- ^ quoted name, the fields are start quote, end quote and the string itself, these will usually be ", others are possible e.g. `something` is parsed to QuotedName "`" "`" "something, and $a$ test $a$ is parsed to QuotedName "$a$" "$a$" " test "
> | DQName String String String
> -- ^ dialect quoted name, the fields are start quote, end quote and the string itself, e.g. `something` is parsed to DQName "`" "`" "something, and $a$ test $a$ is parsed to DQName "$a$" "$a$" " test "
> deriving (Eq,Show,Read,Data,Typeable) > deriving (Eq,Show,Read,Data,Typeable)
> -- | Represents a type name, used in casts. > -- | Represents a type name, used in casts.

View file

@ -7,9 +7,10 @@ Test for the lexer
> import Language.SQL.SimpleSQL.TestTypes > import Language.SQL.SimpleSQL.TestTypes
> import Language.SQL.SimpleSQL.Lex (Token(..)) > import Language.SQL.SimpleSQL.Lex (Token(..))
> --import Debug.Trace > --import Debug.Trace
> import Data.Char (isAlpha)
> lexerTable :: [(String,[Token])] > ansiLexerTable :: [(String,[Token])]
> lexerTable = > ansiLexerTable =
> -- single char symbols > -- single char symbols
> map (\s -> ([s],[Symbol [s]])) "+-^*/%~&|?<>[]=,;()" > map (\s -> ([s],[Symbol [s]])) "+-^*/%~&|?<>[]=,;()"
> -- multi char symbols > -- multi char symbols
@ -17,21 +18,21 @@ Test for the lexer
> ++ (let idens = ["a", "_a", "test", "table", "Stuff", "STUFF"] > ++ (let idens = ["a", "_a", "test", "table", "Stuff", "STUFF"]
> -- simple identifiers > -- simple identifiers
> in map (\i -> (i, [Identifier i])) idens > in map (\i -> (i, [Identifier i])) idens
> ++ map (\i -> ("\"" ++ i ++ "\"", [QIdentifier i])) idens > ++ map (\i -> ("\"" ++ i ++ "\"", [QuotedIdentifier "\"" "\"" i])) idens
> -- todo: in order to make lex . pretty id, need to > -- todo: in order to make lex . pretty id, need to
> -- preserve the case of the u > -- preserve the case of the u
> ++ map (\i -> ("u&\"" ++ i ++ "\"", [UQIdentifier i])) idens > ++ map (\i -> ("u&\"" ++ i ++ "\"", [QuotedIdentifier "u&\"" "\"" i])) idens
> -- host param > -- host param
> ++ map (\i -> (':':i, [HostParam i])) idens > ++ map (\i -> (':':i, [HostParam i])) idens
> ) > )
> -- quoted identifiers with embedded double quotes > -- quoted identifiers with embedded double quotes
> ++ [("\"normal \"\" iden\"", [QIdentifier "normal \" iden"])] > ++ [("\"normal \"\" iden\"", [QuotedIdentifier "\"" "\"" "normal \" iden"])]
> -- strings > -- strings
> ++ [("'string'", [SqlString "string"]) > ++ [("'string'", [SqlString "'" "'" "string"])
> ,("'normal '' quote'", [SqlString "normal ' quote"]) > ,("'normal '' quote'", [SqlString "'" "'" "normal ' quote"])
> ,("'normalendquote '''", [SqlString "normalendquote '"])] > ,("'normalendquote '''", [SqlString "'" "'" "normalendquote '"])]
> -- csstrings > -- csstrings
> ++ map (\c -> (c ++ "'test'", [CSSqlString c "test"])) > ++ map (\c -> (c ++ "'test'", [SqlString (c ++ "'") "'" "test"]))
> ["n", "N","b", "B","x", "X", "u&"] > ["n", "N","b", "B","x", "X", "u&"]
> -- numbers > -- numbers
> ++ [("10", [SqlNumber "10"]) > ++ [("10", [SqlNumber "10"])
@ -54,14 +55,18 @@ Test for the lexer
> ,"/* this *is/ a comment */" > ,"/* this *is/ a comment */"
> ] > ]
> lexerTests :: TestItem > lexerTests :: TestItem
> lexerTests = Group "lexerTests" $ > lexerTests = Group "lexerTests" $
> [Group "lexer token tests" $ [LexerTest ansi2011 s t | (s,t) <- lexerTable] > [Group "lexer token tests" [ansiLexerTests]]
> ,Group "generated combination lexer tests" $
> ansiLexerTests :: TestItem
> ansiLexerTests = Group "ansiLexerTests" $
> [Group "ansi lexer token tests" $ [LexerTest ansi2011 s t | (s,t) <- ansiLexerTable]
> ,Group "ansi generated combination lexer tests" $
> [ LexerTest ansi2011 (s ++ s1) (t ++ t1) > [ LexerTest ansi2011 (s ++ s1) (t ++ t1)
> | (s,t) <- lexerTable > | (s,t) <- ansiLexerTable
> , (s1,t1) <- lexerTable > , (s1,t1) <- ansiLexerTable
which combinations won't work: which combinations won't work:
<> <= >= || two single symbols which make a double char symbol <> <= >= || two single symbols which make a double char symbol
@ -101,17 +106,16 @@ number number (todo: double check more carefully)
> ,symbolPair "*" "/" > ,symbolPair "*" "/"
> ,(isIdentifier, isIdentifier) > ,(isIdentifier, isIdentifier)
> ,(isQIdentifier, isQIdentifier) > ,(isDQIdentifier, isDQIdentifier)
> ,(isUQIdentifier, isQIdentifier) > ,(isCQIdentifier, isDQIdentifier)
> ,(isString, isString) > ,(isString, isNonCsString)
> ,(isCsString, isString)
> ,(isEofLineComment, const True) > ,(isEofLineComment, const True)
> ,(isNumber, isNumber) > ,(isNumber, isNumber)
> ,(isHostParam,isIdentifier) > ,(isHostParam,isIdentifier)
> ,(isHostParam,isCsString) > ,(isHostParam,isCsString)
> ,(isHostParam,isUQIdentifier) > ,(isHostParam,isCQIdentifier)
> ,(isIdentifier,isCsString) > ,(isIdentifier,isCsString)
> ,(isIdentifier,isUQIdentifier) > ,(isIdentifier,isCQIdentifier)
> ,(isWhitespace, isWhitespace) > ,(isWhitespace, isWhitespace)
> ,(isIdentifier, isNumber) > ,(isIdentifier, isNumber)
> ,(isHostParam, isNumber) > ,(isHostParam, isNumber)
@ -119,12 +123,17 @@ number number (todo: double check more carefully)
> ] > ]
> isIdentifier (Identifier _) = True > isIdentifier (Identifier _) = True
> isIdentifier _ = False > isIdentifier _ = False
> isQIdentifier (QIdentifier _) = True > isDQIdentifier (QuotedIdentifier "\"" _ _) = True
> isQIdentifier _ = False > isDQIdentifier _ = False
> isUQIdentifier (UQIdentifier _) = True > isCQIdentifier (QuotedIdentifier (x:_) _ _) | isAlpha x = True
> isUQIdentifier _ = False > isCQIdentifier _ = False
> isCsString (CSSqlString {}) = True > isCsString (SqlString (x:_) _ _) | isAlpha x = True
> isCsString _ = False > isCsString _ = False
> isString (SqlString _ _ _) = True
> isString _ = False
> isNonCsString (SqlString [] _ _) = True
> isNonCsString (SqlString (x:_) _ _) | not (isAlpha x) = True
> isNonCsString _ = False
> isEofLineComment (LineComment s) = last s /= '\n' > isEofLineComment (LineComment s) = last s /= '\n'
> isEofLineComment _ = False > isEofLineComment _ = False
> isLineComment (LineComment {}) = True > isLineComment (LineComment {}) = True
@ -137,9 +146,6 @@ number number (todo: double check more carefully)
> isWhitespace _ = False > isWhitespace _ = False
> isMinus (Symbol "-") = True > isMinus (Symbol "-") = True
> isMinus _ = False > isMinus _ = False
> isString (SqlString _) = True
> isString _ = False
> symbolPair a b = ((==Symbol a), (==Symbol b)) > symbolPair a b = ((==Symbol a), (==Symbol b))
> listPred :: ((Token -> Bool),(Token -> Bool)) -> [Token] -> Bool > listPred :: ((Token -> Bool),(Token -> Bool)) -> [Token] -> Bool
> listPred _ [] = False > listPred _ [] = False

View file

@ -19,7 +19,7 @@ limit syntax
> backtickQuotes :: TestItem > backtickQuotes :: TestItem
> backtickQuotes = Group "backtickQuotes" (map (uncurry (TestValueExpr mysql)) > backtickQuotes = Group "backtickQuotes" (map (uncurry (TestValueExpr mysql))
> [("`test`", Iden [DQName "`" "`" "test"]) > [("`test`", Iden [QuotedName "`" "`" "test"])
> ] > ]
> ++ [ParseValueExprFails ansi2011 "`test`"] > ++ [ParseValueExprFails ansi2011 "`test`"]
> ) > )

View file

@ -506,17 +506,17 @@ Specify a non-null value.
> characterStringLiterals = Group "character string literals" > characterStringLiterals = Group "character string literals"
> $ map (uncurry (TestValueExpr ansi2011)) > $ map (uncurry (TestValueExpr ansi2011))
> [("'a regular string literal'" > [("'a regular string literal'"
> ,StringLit "a regular string literal") > ,StringLit "'" "'" "a regular string literal")
> ,("'something' ' some more' 'and more'" > ,("'something' ' some more' 'and more'"
> ,StringLit "something some moreand more") > ,StringLit "'" "'" "something some moreand more")
> ,("'something' \n ' some more' \t 'and more'" > ,("'something' \n ' some more' \t 'and more'"
> ,StringLit "something some moreand more") > ,StringLit "'" "'" "something some moreand more")
> ,("'something' -- a comment\n ' some more' /*another comment*/ 'and more'" > ,("'something' -- a comment\n ' some more' /*another comment*/ 'and more'"
> ,StringLit "something some moreand more") > ,StringLit "'" "'" "something some moreand more")
> ,("'a quote: '', stuff'" > ,("'a quote: '', stuff'"
> ,StringLit "a quote: ', stuff") > ,StringLit "'" "'" "a quote: ', stuff")
> ,("''" > ,("''"
> ,StringLit "") > ,StringLit "'" "'" "")
I'm not sure how this should work. Maybe the parser should reject non I'm not sure how this should work. Maybe the parser should reject non
ascii characters in strings and identifiers unless the current SQL ascii characters in strings and identifiers unless the current SQL
@ -533,8 +533,8 @@ character set allows them.
> nationalCharacterStringLiterals :: TestItem > nationalCharacterStringLiterals :: TestItem
> nationalCharacterStringLiterals = Group "national character string literals" > nationalCharacterStringLiterals = Group "national character string literals"
> $ map (uncurry (TestValueExpr ansi2011)) > $ map (uncurry (TestValueExpr ansi2011))
> [("N'something'", CSStringLit "N" "something") > [("N'something'", StringLit "N'" "'" "something")
> ,("n'something'", CSStringLit "n" "something") > ,("n'something'", StringLit "n'" "'" "something")
> ] > ]
<Unicode character string literal> ::= <Unicode character string literal> ::=
@ -550,11 +550,11 @@ character set allows them.
> unicodeCharacterStringLiterals :: TestItem > unicodeCharacterStringLiterals :: TestItem
> unicodeCharacterStringLiterals = Group "unicode character string literals" > unicodeCharacterStringLiterals = Group "unicode character string literals"
> $ map (uncurry (TestValueExpr ansi2011)) > $ map (uncurry (TestValueExpr ansi2011))
> [("U&'something'", CSStringLit "U&" "something") > [("U&'something'", StringLit "U&'" "'" "something")
> ,("u&'something' escape =" > ,("u&'something' escape ="
> ,Escape (CSStringLit "u&" "something") '=') > ,Escape (StringLit "u&'" "'" "something") '=')
> ,("u&'something' uescape =" > ,("u&'something' uescape ="
> ,UEscape (CSStringLit "u&" "something") '=') > ,UEscape (StringLit "u&'" "'" "something") '=')
> ] > ]
TODO: unicode escape TODO: unicode escape
@ -570,8 +570,8 @@ TODO: unicode escape
> binaryStringLiterals = Group "binary string literals" > binaryStringLiterals = Group "binary string literals"
> $ map (uncurry (TestValueExpr ansi2011)) > $ map (uncurry (TestValueExpr ansi2011))
> [--("B'101010'", CSStringLit "B" "101010") > [--("B'101010'", CSStringLit "B" "101010")
> ("X'7f7f7f'", CSStringLit "X" "7f7f7f") > ("X'7f7f7f'", StringLit "X'" "'" "7f7f7f")
> ,("X'7f7f7f' escape z", Escape (CSStringLit "X" "7f7f7f") 'z') > ,("X'7f7f7f' escape z", Escape (StringLit "X'" "'" "7f7f7f") 'z')
> ] > ]
<signed numeric literal> ::= [ <sign> ] <unsigned numeric literal> <signed numeric literal> ::= [ <sign> ] <unsigned numeric literal>
@ -753,10 +753,10 @@ Specify names.
> ,("t1",Iden [Name "t1"]) > ,("t1",Iden [Name "t1"])
> ,("a.b",Iden [Name "a", Name "b"]) > ,("a.b",Iden [Name "a", Name "b"])
> ,("a.b.c",Iden [Name "a", Name "b", Name "c"]) > ,("a.b.c",Iden [Name "a", Name "b", Name "c"])
> ,("\"quoted iden\"", Iden [QName "quoted iden"]) > ,("\"quoted iden\"", Iden [QuotedName "\"" "\"" "quoted iden"])
> ,("\"quoted \"\" iden\"", Iden [QName "quoted \" iden"]) > ,("\"quoted \"\" iden\"", Iden [QuotedName "\"" "\"" "quoted \" iden"])
> ,("U&\"quoted iden\"", Iden [UQName "quoted iden"]) > ,("U&\"quoted iden\"", Iden [QuotedName "U&\"" "\"" "quoted iden"])
> ,("U&\"quoted \"\" iden\"", Iden [UQName "quoted \" iden"]) > ,("U&\"quoted \"\" iden\"", Iden [QuotedName "U&\"" "\"" "quoted \" iden"])
> ] > ]
TODO: more identifiers, e.g. unicode escapes?, mixed quoted/unquoted TODO: more identifiers, e.g. unicode escapes?, mixed quoted/unquoted
@ -1100,8 +1100,8 @@ create a list of type name variations:
> -- 1 with and without tz > -- 1 with and without tz
> ,("time with time zone" > ,("time with time zone"
> ,TimeTypeName [Name "time"] Nothing True) > ,TimeTypeName [Name "time"] Nothing True)
> ,("timestamp(3) without time zone" > ,("datetime(3) without time zone"
> ,TimeTypeName [Name "timestamp"] (Just 3) False) > ,TimeTypeName [Name "datetime"] (Just 3) False)
> -- chars: (single/multiname) x prec x charset x collate > -- chars: (single/multiname) x prec x charset x collate
> -- 1111 > -- 1111
> ,("char varying(5) character set something collate something_insensitive" > ,("char varying(5) character set something collate something_insensitive"
@ -1199,7 +1199,7 @@ expression
> [(ctn ++ " 'test'", TypedLit stn "test") > [(ctn ++ " 'test'", TypedLit stn "test")
> ] > ]
> makeCastTests (ctn, stn) = > makeCastTests (ctn, stn) =
> [("cast('test' as " ++ ctn ++ ")", Cast (StringLit "test") stn) > [("cast('test' as " ++ ctn ++ ")", Cast (StringLit "'" "'" "test") stn)
> ] > ]
> makeTests a = makeSimpleTests a ++ makeCastTests a > makeTests a = makeSimpleTests a ++ makeCastTests a
@ -1215,7 +1215,7 @@ Define a field of a row type.
> fieldDefinition = Group "field definition" > fieldDefinition = Group "field definition"
> $ map (uncurry (TestValueExpr ansi2011)) > $ map (uncurry (TestValueExpr ansi2011))
> [("cast('(1,2)' as row(a int,b char))" > [("cast('(1,2)' as row(a int,b char))"
> ,Cast (StringLit "(1,2)") > ,Cast (StringLit "'" "'" "(1,2)")
> $ RowTypeName [(Name "a", TypeName [Name "int"]) > $ RowTypeName [(Name "a", TypeName [Name "int"])
> ,(Name "b", TypeName [Name "char"])])] > ,(Name "b", TypeName [Name "char"])])]

View file

@ -34,9 +34,9 @@ Tests for parsing value expressions
> ,("3e3", NumLit "3e3") > ,("3e3", NumLit "3e3")
> ,("3e+3", NumLit "3e+3") > ,("3e+3", NumLit "3e+3")
> ,("3e-3", NumLit "3e-3") > ,("3e-3", NumLit "3e-3")
> ,("'string'", StringLit "string") > ,("'string'", StringLit "'" "'" "string")
> ,("'string with a '' quote'", StringLit "string with a ' quote") > ,("'string with a '' quote'", StringLit "'" "'" "string with a ' quote")
> ,("'1'", StringLit "1") > ,("'1'", StringLit "'" "'" "1")
> ,("interval '3' day" > ,("interval '3' day"
> ,IntervalLit Nothing "3" (Itf "day" Nothing) Nothing) > ,IntervalLit Nothing "3" (Itf "day" Nothing) Nothing)
> ,("interval '3' day (3)" > ,("interval '3' day (3)"
@ -48,7 +48,7 @@ Tests for parsing value expressions
> identifiers = Group "identifiers" $ map (uncurry (TestValueExpr ansi2011)) > identifiers = Group "identifiers" $ map (uncurry (TestValueExpr ansi2011))
> [("iden1", Iden [Name "iden1"]) > [("iden1", Iden [Name "iden1"])
> --,("t.a", Iden2 "t" "a") > --,("t.a", Iden2 "t" "a")
> ,("\"quoted identifier\"", Iden [QName "quoted identifier"]) > ,("\"quoted identifier\"", Iden [QuotedName "\"" "\"" "quoted identifier"])
> ] > ]
> star :: TestItem > star :: TestItem
@ -142,19 +142,19 @@ Tests for parsing value expressions
> casts :: TestItem > casts :: TestItem
> casts = Group "operators" $ map (uncurry (TestValueExpr ansi2011)) > casts = Group "operators" $ map (uncurry (TestValueExpr ansi2011))
> [("cast('1' as int)" > [("cast('1' as int)"
> ,Cast (StringLit "1") $ TypeName [Name "int"]) > ,Cast (StringLit "'" "'" "1") $ TypeName [Name "int"])
> ,("int '3'" > ,("int '3'"
> ,TypedLit (TypeName [Name "int"]) "3") > ,TypedLit (TypeName [Name "int"]) "3")
> ,("cast('1' as double precision)" > ,("cast('1' as double precision)"
> ,Cast (StringLit "1") $ TypeName [Name "double precision"]) > ,Cast (StringLit "'" "'" "1") $ TypeName [Name "double precision"])
> ,("cast('1' as float(8))" > ,("cast('1' as float(8))"
> ,Cast (StringLit "1") $ PrecTypeName [Name "float"] 8) > ,Cast (StringLit "'" "'" "1") $ PrecTypeName [Name "float"] 8)
> ,("cast('1' as decimal(15,2))" > ,("cast('1' as decimal(15,2))"
> ,Cast (StringLit "1") $ PrecScaleTypeName [Name "decimal"] 15 2) > ,Cast (StringLit "'" "'" "1") $ PrecScaleTypeName [Name "decimal"] 15 2)
> ,("double precision '3'" > ,("double precision '3'"
@ -283,43 +283,43 @@ target_string
> ,("trim(from target_string)" > ,("trim(from target_string)"
> ,SpecialOpK [Name "trim"] Nothing > ,SpecialOpK [Name "trim"] Nothing
> [("both", StringLit " ") > [("both", StringLit "'" "'" " ")
> ,("from", Iden [Name "target_string"])]) > ,("from", Iden [Name "target_string"])])
> ,("trim(leading from target_string)" > ,("trim(leading from target_string)"
> ,SpecialOpK [Name "trim"] Nothing > ,SpecialOpK [Name "trim"] Nothing
> [("leading", StringLit " ") > [("leading", StringLit "'" "'" " ")
> ,("from", Iden [Name "target_string"])]) > ,("from", Iden [Name "target_string"])])
> ,("trim(trailing from target_string)" > ,("trim(trailing from target_string)"
> ,SpecialOpK [Name "trim"] Nothing > ,SpecialOpK [Name "trim"] Nothing
> [("trailing", StringLit " ") > [("trailing", StringLit "'" "'" " ")
> ,("from", Iden [Name "target_string"])]) > ,("from", Iden [Name "target_string"])])
> ,("trim(both from target_string)" > ,("trim(both from target_string)"
> ,SpecialOpK [Name "trim"] Nothing > ,SpecialOpK [Name "trim"] Nothing
> [("both", StringLit " ") > [("both", StringLit "'" "'" " ")
> ,("from", Iden [Name "target_string"])]) > ,("from", Iden [Name "target_string"])])
> ,("trim(leading 'x' from target_string)" > ,("trim(leading 'x' from target_string)"
> ,SpecialOpK [Name "trim"] Nothing > ,SpecialOpK [Name "trim"] Nothing
> [("leading", StringLit "x") > [("leading", StringLit "'" "'" "x")
> ,("from", Iden [Name "target_string"])]) > ,("from", Iden [Name "target_string"])])
> ,("trim(trailing 'y' from target_string)" > ,("trim(trailing 'y' from target_string)"
> ,SpecialOpK [Name "trim"] Nothing > ,SpecialOpK [Name "trim"] Nothing
> [("trailing", StringLit "y") > [("trailing", StringLit "'" "'" "y")
> ,("from", Iden [Name "target_string"])]) > ,("from", Iden [Name "target_string"])])
> ,("trim(both 'z' from target_string collate C)" > ,("trim(both 'z' from target_string collate C)"
> ,SpecialOpK [Name "trim"] Nothing > ,SpecialOpK [Name "trim"] Nothing
> [("both", StringLit "z") > [("both", StringLit "'" "'" "z")
> ,("from", Collate (Iden [Name "target_string"]) [Name "C"])]) > ,("from", Collate (Iden [Name "target_string"]) [Name "C"])])
> ,("trim(leading from target_string)" > ,("trim(leading from target_string)"
> ,SpecialOpK [Name "trim"] Nothing > ,SpecialOpK [Name "trim"] Nothing
> [("leading", StringLit " ") > [("leading", StringLit "'" "'" " ")
> ,("from", Iden [Name "target_string"])]) > ,("from", Iden [Name "target_string"])])