Building and Evaluating Expressions Using Delphi RTTI

I faced the challenge of allowing the user to define expressions using compiled classes with RTTI enabled. Let me put it in a simple way.

TAnimal = class(TPersistent)
private
  fWeight : Double;
  fHeight : Double;
  fName : string;
published
  property Weight : Double read fWeight write fWeight;
  property Height : Double read fHeight write fHeight;
  property Name : string read fName write fName;
end;

      

And I have a procedure that will evaluate an animal with the provided expression

function EvaluateAnimal(const animal : TAnimal; expression : string) : Double;
begin
  //Result :=  Turn expression to evaluation and give the result
end;

      

Custom expression (TAnimal.Weight * TAnimal.Height)/(TAnimal.Weight + TAnimal.Height)

Now I can get TAnimal using RTTI Context and get the animal's Height and Weight. However, how can I evaluate the expression the user provided?

Is there any mechanism I can use to prepare a custom expression when my app starts and at runtime, just send an animal instance to get the value. The user is free to change the expression at any time, and the application must evaluate the expression.

I am using Delphi XE3.

0


source to share


1 answer


You can use direct bindings to evaluate expressions. Here's a trivial example:

program BindingsDemo;
{$APPTYPE CONSOLE}

uses
  System.Rtti,
  System.Bindings.Expression,
  System.Bindings.EvalProtocol,
  System.Bindings.Helper;

type
  TFoo = class
    Val1: Integer;
    Val2: Integer;
    Result: TValue;
  end;

procedure Main;
var
  Foo: TFoo;
  scope: IScope;
  expr: TBindingExpression;
begin
  Foo := TFoo.Create;
  Foo.Val1 := 42;
  Foo.Val2 := 666;
  scope := TBindings.CreateAssociationScope([Associate(Foo, 'Foo')]);
  expr := TBindings.CreateUnmanagedBinding(
    [Scope],
    'Foo.Val1 + Foo.Val2',
    [Scope],
    'Foo.Result',
    nil
  );
  expr.Evaluate;
  Assert(Foo.Result.AsInteger=708);
  Writeln(Foo.Result.ToString);
end;

begin
  Main;
  Readln;
end.

      



Note that I intentionally left out the code for free objects, and therefore this code is leaking. I decided to do this so that we can focus on the evaluation aspect of the expression.

+2


source







All Articles