I'm trying to parse SQL search conditions and having trouble getting the parser to differentiate logical (AND
, OR
) from other infix operators. I'm parsing them as different nodes (perhaps that's difficult to do), but simplifies the evaluation phase. Here's the relevant code snippet (I can include more if necessary).
let opp = OperatorPrecedenceParser<_,_,_>()
let scalarExpr = opp.ExpressionParser
opp.TermParser <- constant <|> id <|> between lparen rparen scalarExpr <|> scalarExpr
//infix operators added here
let comparison = //(e.g., 1 < 2)
let compareExpr = pipe3 scalarExpr compareOp scalarExpr (fun l op r -> Comparison(op, l, r))
between lparen rparen compareExpr <|> compareExpr
let andTerm = pstringCI "and" .>> ws
let orTerm = pstringCI "or" .>> ws
let searchCondition, searchConditionRef = createParserForwardedToRef()
searchConditionRef :=
[ comparison
pipe3 searchCondition andTerm searchCondition (fun l _ r -> And(l, r))
pipe3 searchCondition orTerm searchCondition (fun l _ r -> Or(l, r))
between lparen rparen searchCondition ]
|> choice
let filter : Parser<_,unit> = ws >>. searchCondition .>> eof
"1 = 1"
correctly parses to Comparison (Eq,Constant (Int32 1),Constant (Int32 1))
but once I try to join two comparisons with a logical operator, e.g., "1 = 1 or 2 = 2"
, it fails to parse with
Error in Ln: 1 Col: 7
1 = 1 or 2 = 2
^
Expecting: end of input or infix operator
: 7
I expected it to parse the 1
before the error as a scalar expression and upon hitting or
backtrack, realizing it's not an infix operator, return 1
as the complete scalar, and recognize it's parsing the left-hand side of a condition joined by logical operator or
.
Instead, it seems to continue assuming 1
begins a more complex scalar expression, possibly involving an infix operator.
Is there a problem with the code, or is the solution to parse AND
/OR
as infix operators (using the same OperatorPrecedenceParser
)? I'd rather not go that route, so I'm hoping I've made a simple mistake somewhere.
The complete code is on gist.