I am building a Sprache parser to parse expressions similar to SQL search conditions. e.g Property = 123
or Property > AnotherProperty
So far both of those examples work, however I am struggling to figure out what I need to do to allow ANDing/ORing conditions and parenthesis.
Basically I have this so far:
private static readonly Parser<string> Operators =
Parse.String("+").Or(Parse.String("-")).Or(Parse.String("="))
.Or(Parse.String("<")).Or(Parse.String(">"))
.Or(Parse.String("<=")).Or(Parse.String(">=")).Or(Parse.String("<>"))
.Text();
private static readonly Parser<IdentifierExpression> Identifier =
from first in Parse.Letter.Once()
from rest in Parse.LetterOrDigit.Many()
select new IdentifierExpression(first.Concat(rest).ToArray());
public static readonly Parser<Expression> Integer =
Parse.Number.Select(n => new IntegerExpression {Value = int.Parse(n)});
public static readonly Parser<SearchCondition> SearchCondition =
from left in Identifier.Or(Number)
from op in Operators.Token()
from right in Identifier.Or(Number)
select new SearchCondition { Left = left, Right = right, Operator = op};
This works for the simple cases above, but now I need a pointer on how to implement conditions like:
PropertyX = PropertyY OR PropertyX = PropertyZ
PropertyA > PropertyB AND (OtherAnotherProperty = 72 OR OtherAnotherProperty = 150)
Can anyone give me an idea on how to structure the parsers for this sort of thing?
What you have so far is a basic comparison expression parser. It looks like you want to wrap that in a parser that handles logical expressions (
and
,or
, etc.) with sub-expression support.The code I posted at first was ripped from poorly-tested code I was still working on, which didn't handle statements with multiple terms. My understanding of the
ChainOperator
method was clearly incomplete.Parse.ChainOperator
is the method that lets you specify your operators and have them appear 0-to-many times in the expression. I was making assumptions about how it worked that turned out to be just wrong.I've rewritten the code and added a few bits to make it easier to use:
And some examples:
You will still need to add your own parsers for handling comparison expressions and so on. Plug those into the
BooleanValue
parser after the existing terms:I'm doing something similar with a more C#-style filter specification with type checking during the parse phase and separate parsers for strings vs numbers.