Skip to content

Instantly share code, notes, and snippets.

@CraftyFella
Created October 19, 2020 15:06
Show Gist options
  • Save CraftyFella/9b08368389d9682905a2cd289ea268fd to your computer and use it in GitHub Desktop.
Save CraftyFella/9b08368389d9682905a2cd289ea268fd to your computer and use it in GitHub Desktop.
Issue with FParsec
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