Created
October 19, 2020 15:06
-
-
Save CraftyFella/9b08368389d9682905a2cd289ea268fd to your computer and use it in GitHub Desktop.
Issue with FParsec
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
open FParsec | |
[<RequireQualifiedAccess>] | |
type QueryComparison = | |
| Equal | |
| NotEqual | |
[<RequireQualifiedAccess>] | |
type TableOperators = | |
| And | |
| Or | |
[<RequireQualifiedAccess>] | |
type Filter = | |
| Property of name: string * QueryComparison * value: string | |
| Combined of Filter * TableOperators * Filter | |
let letterOrNumber = asciiLetter <|> digit | |
let manyLettersOrNumbers = many1Chars letterOrNumber | |
let manyCharsNotSingleQuote = (many1Chars (noneOf [ '\'' ])) | |
let stringParser = | |
let quote = pchar '\'' | |
between quote quote manyCharsNotSingleQuote |>> (string) | |
let fieldValueParser = stringParser | |
let queryComparisonParser = | |
[ ("eq", QueryComparison.Equal); ("ne", QueryComparison.NotEqual) ] | |
|> List.map (fun (toMatch, qc) -> stringReturn toMatch qc <?> (sprintf "%O" qc)) | |
|> choice | |
let tableOperatorParser = | |
[ ("or", TableOperators.Or) | |
("and", TableOperators.And) ] | |
|> List.map (fun (toMatch, tableOp) -> stringReturn toMatch tableOp <?> (sprintf "%O" tableOp)) | |
|> choice | |
let propertyParser = | |
let name = manyLettersOrNumbers .>> spaces <?> "Name" | |
let queryComparison = queryComparisonParser .>> spaces <?> "QueryComparison" | |
let filterValue = fieldValueParser <?> "FilterValue" | |
name .>>. queryComparison .>>. filterValue |>> (fun ((n, qc), fv) -> Filter.Property(n, qc, fv)) | |
let parser, parserRef = createParserForwardedToRef() | |
let combinedParserWithBrackets = | |
let open' = pchar '(' | |
let close = pchar ')' | |
let left = (between open' close parser) .>> spaces | |
let right = spaces >>. (between open' close parser) | |
(left .>>. tableOperatorParser .>>. right) |>> (fun ((a, tableOp), b) -> Filter.Combined(a, tableOp, b)) | |
let combinedParserNoBrackets = | |
let left = parser .>> spaces | |
let right = spaces >>. parser | |
(left .>>. tableOperatorParser .>>. right) |>> (fun ((a, tableOp), b) -> Filter.Combined(a, tableOp, b)) | |
let combinedParser = combinedParserWithBrackets <|> combinedParserNoBrackets | |
do parserRef := choice [ propertyParser; combinedParser ] | |
let filter = spaces >>. parser .>> spaces .>> eof | |
let parse query = run filter query | |
[<EntryPoint>] | |
let main argv = | |
parse "(Name eq 'Dave') and (Colour ne 'red')" |> printfn "%A" | |
parse "Name eq 'Dave' and Colour ne 'red'" |> printfn "%A" | |
(* | |
Success: Combined | |
(Property ("Name", Equal, "Dave"), And, Property ("Colour", Equal, "red")) | |
Failure: | |
Error in Ln: 1 Col: 16 | |
Name eq 'Dave' and Colour eq 'red' | |
^ | |
Expecting: end of input | |
*) | |
0 // return an integer exit code |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment