Skip to content

Commit

Permalink
Add support for comments.
Browse files Browse the repository at this point in the history
- Add support for multiline and end of line comments
- Spaces do not need to be optional (it parses zero or more spaces)
- Add spacesOrComment for parsing comments around the expressions
  • Loading branch information
dbrattli committed May 2, 2021
1 parent 6d4efb8 commit 1a04b69
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 13 deletions.
35 changes: 23 additions & 12 deletions src/NpgsqlFSharpParser/Parser.fs
Original file line number Diff line number Diff line change
Expand Up @@ -86,20 +86,22 @@ let manyCharsBetween popen pclose pchar = popen >>? manyCharsTill pchar pclose
// Parses any string between popen and pclose
let anyStringBetween popen pclose = manyCharsBetween popen pclose anyChar

let skipBetween popen pclose = popen >>? skipManyTill skipAnyChar pclose

// Cannot be a reserved keyword.
let unquotedIdentifier : Parser<string, unit> =
let isIdentifierFirstChar token = isLetter token
let isIdentifierChar token = isLetter token || isDigit token || token = '_'

many1Satisfy2L isIdentifierFirstChar isIdentifierChar "identifier" .>> spaces
many1Satisfy2L isIdentifierFirstChar isIdentifierChar "identifier" .>> spacesOrComment
>>= fun identifier ->
if List.contains (identifier.ToUpper()) reserved
then fail (sprintf "Identifier %s is a reserved keyword" identifier)
else preturn identifier

// Can be a reserved keyword.
let quotedIdentifier : Parser<string, unit> =
(skipChar '\"' |> anyStringBetween <| skipChar '\"') .>> spaces
(skipChar '\"' |> anyStringBetween <| skipChar '\"') .>> spacesOrComment

let stringIdentifier =
quotedIdentifier
Expand Down Expand Up @@ -129,7 +131,7 @@ let parameter : Parser<Expr, unit> =
|>> Expr.Parameter

let text value : Parser<string, unit> =
(optional spaces) >>. pstringCI value .>> (optional spaces)
spaces >>. pstringCI value .>> spacesOrComment

let star : Parser<Expr, unit> =
text "*" |>> fun _ -> Expr.Star
Expand All @@ -143,11 +145,11 @@ let parens parser = between (text "(") (text ")") parser
let comma = text ","

let integer : Parser<Expr, unit> =
(optional spaces) >>. pint32 .>> (optional spaces)
spaces >>. pint32 .>> spacesOrComment
|>> Expr.Integer

let number : Parser<Expr, unit> =
(optional spaces) >>. pfloat .>> (optional spaces)
spaces >>. pfloat .>> spacesOrComment
|>> Expr.Float

let boolean : Parser<Expr, unit> =
Expand Down Expand Up @@ -365,11 +367,20 @@ let updateQuery =

preturn (Expr.UpdateQuery query)

opp.AddOperator(InfixOperator("AND", spaces, 7, Associativity.Left, fun left right -> Expr.And(left, right)))
opp.AddOperator(InfixOperator("AS", spaces, 6, Associativity.Left, fun left right -> Expr.As(left, right)))
opp.AddOperator(InfixOperator("as", spaces, 6, Associativity.Left, fun left right -> Expr.As(left, right)))
let spacesOrComment =
let comment = skipString "/*" >>. (charsTillString "*/" true 8096)
let commentEol = skipString "--" >>. skipRestOfLine true

spaces .>>
optional comment .>>
optional commentEol .>>
spaces

opp.AddOperator(InfixOperator("AND", spacesOrComment, 7, Associativity.Left, fun left right -> Expr.And(left, right)))
opp.AddOperator(InfixOperator("AS", spacesOrComment, 6, Associativity.Left, fun left right -> Expr.As(left, right)))
opp.AddOperator(InfixOperator("as", spacesOrComment, 6, Associativity.Left, fun left right -> Expr.As(left, right)))
opp.AddOperator(InfixOperator("OR", notFollowedBy (text "DER BY"), 6, Associativity.Left, fun left right -> Expr.Or(left, right)))
opp.AddOperator(InfixOperator("IN", spaces, 8, Associativity.Left, fun left right -> Expr.In(left, right)))
opp.AddOperator(InfixOperator("IN", spacesOrComment, 8, Associativity.Left, fun left right -> Expr.In(left, right)))
opp.AddOperator(InfixOperator(">", spaces, 9, Associativity.Left, fun left right -> Expr.GreaterThan(left, right)))
opp.AddOperator(InfixOperator("<", spaces, 9, Associativity.Left, fun left right -> Expr.LessThan(left, right)))
opp.AddOperator(InfixOperator("<=", spaces, 9, Associativity.Left, fun left right -> Expr.LessThanOrEqual(left, right)))
Expand All @@ -380,8 +391,8 @@ opp.AddOperator(InfixOperator("||", spaces, 9, Associativity.Left, fun left righ
opp.AddOperator(InfixOperator("::", spaces, 9, Associativity.Left, fun left right -> Expr.TypeCast(left, right)))
opp.AddOperator(InfixOperator("->>", spaces, 9, Associativity.Left, fun left right -> Expr.JsonIndex(left, right)))

opp.AddOperator(PostfixOperator("IS NULL", spaces, 8, false, fun value -> Expr.Equals(Expr.Null, value)))
opp.AddOperator(PostfixOperator("IS NOT NULL", spaces, 8, false, fun value -> Expr.Not(Expr.Equals(Expr.Null, value))))
opp.AddOperator(PostfixOperator("IS NULL", spacesOrComment, 8, false, fun value -> Expr.Equals(Expr.Null, value)))
opp.AddOperator(PostfixOperator("IS NOT NULL", spacesOrComment, 8, false, fun value -> Expr.Not(Expr.Equals(Expr.Null, value))))

opp.TermParser <- choice [
(attempt updateQuery)
Expand All @@ -399,7 +410,7 @@ opp.TermParser <- choice [
parameter
]

let fullParser = (optional spaces) >>. expr .>> (optional spaces <|> (text ";" |>> fun _ -> ()))
let fullParser = spacesOrComment >>. expr .>> (spacesOrComment <|> (text ";" |>> ignore))

let parse (input: string) : Result<Expr, string> =
match run fullParser input with
Expand Down
46 changes: 45 additions & 1 deletion tests/NpgsqlFSharpAnalyzer.Tests/ParseSelectTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -513,4 +513,48 @@ let selectQueryTests = testList "Parse SELECT tests" [
From = Expr.As(Expr.Ident "$Table", Expr.Ident "tbl") |> Some
Limit = Some (Expr.Integer 100)
}
]

testSelect "SELECT 1 -- This is a comment" {
SelectExpr.Default with Columns = [Expr.Integer 1]
}

testSelect """
-- This is a comment
SELECT 1""" {
SelectExpr.Default with Columns = [Expr.Integer 1]
}

testSelect """
/* Comment inserted first */
SELECT 1""" {
SelectExpr.Default with Columns = [Expr.Integer 1]
}

testSelect """
SELECT 1
/* Comment inserted last */
""" {
SelectExpr.Default with Columns = [Expr.Integer 1]
}

testSelect """
SELECT 1;
/* Comment inserted after semicolon */
""" {
SelectExpr.Default with Columns = [Expr.Integer 1]
}

testSelect """
SELECT * /* Comment inserted here */
FROM -- Ignore
(SELECT NOW()) time /* Comment inserted here */
LIMIT 1 -- Ignore
""" {
SelectExpr.Default with
Columns = [Expr.Star]
From = Some (Expr.As (Expr.SelectQuery {
SelectExpr.Default with
Columns = [Expr.Function ("NOW", [])]
}, Expr.Ident "time"))
Limit = Some (Expr.Integer 1)
}]

0 comments on commit 1a04b69

Please sign in to comment.