I felt like playing with this idea for Delphi - as like writing parsers. 😉 Years ago I did something similar for a document management system in a different language. I've written a small demo illustrating 2 ways of parsing https://github.com/sempare/sempare-delphi-fts-expression
I did this for fun and in a few hours, so it is still very raw. It contains a hand rolled lexer and parser, but hopefully can give you some ideas how to do this too.
In the first (Sempare.FullTextSearch.SimpleExpression.Test.pas) you can see some scenarios:
procedure TSimpleExprTest.TestSimpleExpr;
begin
assert.AreEqual('name = ''conrad''', tparser.ParseStr('name', '"conrad"'));
end;
procedure TSimpleExprTest.TestWildCard2Expr;
begin
assert.AreEqual('(name like ''conrad%'') or (name like ''%pete'')', tparser.ParseStr('name', '"conrad%" "%pete"'));
end;
procedure TSimpleExprTest.TestWildCardExpr;
begin
assert.AreEqual('name like ''conrad%''', tparser.ParseStr('name', '"conrad%"'));
end;
procedure TSimpleExprTest.TestNotExpr;
begin
assert.AreEqual('not (name = ''conrad'')', tparser.ParseStr('name', 'not "conrad"'));
end;
procedure TSimpleExprTest.TestOrExpr;
begin
assert.AreEqual('(name = ''abc'') or (name = ''def'')', tparser.ParseStr('name', '"abc" or "def"'));
end;
procedure TSimpleExprTest.TestPrecidentExpr;
begin
assert.AreEqual('(name = ''abc'') and (not ((name = ''321'') or (name = ''def'')))', tparser.ParseStr('name', '''abc'' and not ''321'' or ''def'''));
end;
The second (Sempare.FullTextSearch.Expression.Test.pas) is a bit more general. It illustrates parsing, but implementation at present is fairly basic as just a pretty printer:
procedure TExprTest.TestNotExpr;
begin
assert.Areequal('not (name != ''conrad'')', tparser.ParseStr('not (name!="conrad")'));
end;
procedure TExprTest.TestOrExpr;
begin
assert.Areequal('(name = ''abc'') or (text = ''def'')', tparser.ParseStr('name = ''abc'' or text = ''def'''));
end;
procedure TExprTest.TestPrecidentExpr;
begin
assert.Areequal('((name = ''abc'') and (value = ''321'')) or (text = ''def'')', //
tparser.ParseStr('name = ''abc'' and value = ''321'' or text = ''def'''));
end;
procedure TExprTest.TestStartsWithExpr;
begin
assert.Areequal('name like ''abc%''', tparser.ParseStr('name starts with "abc"'));
end;
above you can see that the parsing identifies the precedence and places brackets appropriately. Also it changed 'starts with' to 'like'...
NOTE: there are 2 different parsers implemented for the above scenarios (but both named TParser - just depends which unit is being referenced)
Hope you find this useful.