Skip to main content
TExpression is the base class for TeeBI’s expression parser and evaluator. It enables dynamic calculations, filtering, and data transformations using a familiar syntax.

Overview

TExpression provides:
  • Arithmetic: +, -, *, /, mod, ^
  • Comparison: =, <>, >, <, >=, <=
  • Logical: and, or, not, in
  • Text: Upper, Lower, Contains, Starts, Ends, SubString
  • Math: Sin, Cos, Sqrt, Abs, Round, Power
  • Date/Time: Year, Month, Day, Hour, Date, Time
  • Functions: If-Then-Else, IsEmpty, Length

Class Hierarchy

TExpression (abstract base)
├── TIntegerExpression      // Integer constants
├── TFloatExpression        // Float constants
├── TBooleanExpression      // Boolean constants
├── TDateTimeExpression     // DateTime constants
├── TTextExpression         // String constants
├── TArrayExpression        // Arrays
├── TArithmeticExpression   // +, -, *, /, mod, ^
├── TLogicalExpression      // =, <>, >, <, >=, <=, and, or
├── TUnaryExpression        // Single operand expressions
│   ├── TUnaryNotExpression // not operator
│   └── TParameterExpression // Function calls
│       ├── TMathExpression
│       ├── TDateExpression
│       ├── TTimeExpression
│       ├── TUnaryTextExpression
│       └── TTextOperandExpression
└── TIfExpression           // condition ? then : else

Base Class

TExpression = class abstract
public
  // Parse from string
  class function FromString(const S: String): TExpression; static;
  
  // Evaluate and return result
  function Value: TData; virtual; abstract;
  
  // Convert to string representation
  function ToString: String; override;
  
  // Quick evaluation
  class function Evaluate(const S: String): TData; static;
  
  // Clone expression
  class function Clone(const AExpression: TExpression): TExpression; static;
end;

Creating Expressions

From String

var
  Expr: TExpression;
begin
  Expr := TExpression.FromString('2 + 3 * 4');
  ShowMessage(Expr.Value);  // 14
end;

Quick Evaluation

var
  Result: TData;
begin
  Result := TExpression.Evaluate('(10 + 5) * 2');  // 30
end;

Constants

// Integer
var IntExpr := TIntegerExpression.Create(42);

// Float
var FloatExpr := TFloatExpression.Create(3.14159);

// Boolean
var BoolExpr := TBooleanExpression.Create(True);

// Text
var TextExpr := TTextExpression.Create('Hello');

// DateTime
var DateExpr := TDateTimeExpression.Create(Now);

Arithmetic Operators

Basic Operations

TExpression.Evaluate('10 + 5');      // 15
TExpression.Evaluate('10 - 5');      // 5
TExpression.Evaluate('10 * 5');      // 50
TExpression.Evaluate('10 / 5');      // 2
TExpression.Evaluate('10 mod 3');    // 1
TExpression.Evaluate('2 ^ 3');       // 8 (power)

Precedence

TExpression.Evaluate('2 + 3 * 4');       // 14 (multiplication first)
TExpression.Evaluate('(2 + 3) * 4');     // 20 (parentheses first)
TExpression.Evaluate('2 ^ 3 ^ 2');       // 512 (right-associative)

Comparison Operators

TExpression.Evaluate('5 = 5');       // True
TExpression.Evaluate('5 <> 3');      // True
TExpression.Evaluate('5 > 3');       // True
TExpression.Evaluate('5 < 3');       // False
TExpression.Evaluate('5 >= 5');      // True
TExpression.Evaluate('5 <= 4');      // False

Logical Operators

AND / OR

TExpression.Evaluate('true and true');    // True
TExpression.Evaluate('true and false');   // False
TExpression.Evaluate('true or false');    // True
TExpression.Evaluate('false or false');   // False

NOT

TExpression.Evaluate('not true');         // False
TExpression.Evaluate('not false');        // True
TExpression.Evaluate('not (5 > 3)');      // False

IN Operator

TExpression.Evaluate('5 in [1,2,3,4,5]');              // True
TExpression.Evaluate('"red" in ["red","blue"]');      // True
TExpression.Evaluate('10 in [1,2,3]');                 // False

Math Functions

TExpression.Evaluate('Abs(-5)');         // 5
TExpression.Evaluate('Sqrt(16)');        // 4
TExpression.Evaluate('Sqr(5)');          // 25
TExpression.Evaluate('Round(3.7)');      // 4
TExpression.Evaluate('Trunc(3.7)');      // 3
TExpression.Evaluate('Sign(-5)');        // -1
TExpression.Evaluate('Power(2, 8)');     // 256

TExpression.Evaluate('Sin(0)');          // 0
TExpression.Evaluate('Cos(0)');          // 1
TExpression.Evaluate('Tan(0)');          // 0

TExpression.Evaluate('Log(100)');        // 2 (log base 10)
TExpression.Evaluate('Ln(2.718)');       // 1 (natural log)
TExpression.Evaluate('Exp(1)');          // 2.718... (e)

Constants

TExpression.Evaluate('PI');              // 3.14159...
TExpression.Evaluate('E');               // 2.71828...

Text Functions

Case Conversion

TExpression.Evaluate('Upper("hello")');       // "HELLO"
TExpression.Evaluate('Lower("HELLO")');       // "hello"

String Operations

TExpression.Evaluate('Length("Hello")');                  // 5
TExpression.Evaluate('Trim("  Hello  ")');                // "Hello"
TExpression.Evaluate('IsEmpty("")');                      // True
TExpression.Evaluate('SubString("Hello", 1, 3)');         // "ell"
TExpression.Evaluate('IndexOf("Hello World", "World")');  // 6

String Comparison

TExpression.Evaluate('"Hello" starts "He"');      // True
TExpression.Evaluate('"Hello" ends "lo"');        // True
TExpression.Evaluate('"Hello" contains "ll"');    // True

String Manipulation

TExpression.Evaluate('Insert("Hello", " World", 5)');        // "Hello World"
TExpression.Evaluate('Remove("Hello World", 6, 6)');          // "Hello"
TExpression.Evaluate('Replace("Hello", "ll", "y")');         // "Heyo"

Date/Time Functions

Current Date/Time

var Now := TExpression.Evaluate('NOW');        // Current date and time
var Today := TExpression.Evaluate('DATE()');   // Current date (no time)
var CurrentTime := TExpression.Evaluate('TIME()');  // Current time (no date)

Date Parts

var
  DateExpr: TExpression;
begin
  DateExpr := TDateTimeExpression.Create(EncodeDate(2024, 3, 15));
  
  // Extract parts
  TExpression.Evaluate('Year(' + DateExpr.Value + ')');      // 2024
  TExpression.Evaluate('Month(' + DateExpr.Value + ')');     // 3
  TExpression.Evaluate('Day(' + DateExpr.Value + ')');       // 15
  TExpression.Evaluate('Quarter(' + DateExpr.Value + ')');   // 1
  TExpression.Evaluate('WeekDay(' + DateExpr.Value + ')');   // 5 (Friday)
end;

Date/Time Parts

Available date/time part functions:
  • Year, Month, Day, Hour, Minute, Second, Millisecond
  • Quarter, WeekDay, WeekOfYear, DayOfYear
  • ShortMonthName, LongMonthName
  • ShortWeekDay, LongWeekDay
  • Decade, Century, Millennium

Conditional (If-Then-Else)

TExpression.Evaluate('if 5 > 3 then "Yes" else "No"');  // "Yes"
TExpression.Evaluate('if 5 < 3 then 100 else 200');     // 200

Nested Conditions

var
  Expr: String;
begin
  Expr := 'if Age < 18 then "Minor" else ' +
          'if Age < 65 then "Adult" else "Senior"';
  
  Result := TExpression.Evaluate(Expr);
end;

Arrays

var
  ArrayExpr: TArrayExpression;
begin
  ArrayExpr := TArrayExpression.Create([
    TIntegerExpression.Create(1),
    TIntegerExpression.Create(2),
    TIntegerExpression.Create(3)
  ]);
  
  // Use in expressions
  TExpression.Evaluate('5 in [1,2,3,4,5]');  // True
end;

Data Expressions

When working with TDataItem fields:
var
  DataExpr: TExpression;
begin
  // Create expression referencing data fields
  DataExpr := TDataExpression.FromString(MyData, 'Price * Quantity');
  
  // Use in filters
  Filter := TDataFilter.FromString(Products, 'Price > 100');
  
  // Use in calculations
  CalcExpr := TDataExpression.FromString(Sales, 'Total * 1.2');
end;

Practical Examples

Price Calculation

var
  TotalExpr: TExpression;
begin
  TotalExpr := TDataExpression.FromString(OrderDetails,
    'Price * Quantity * (1 + TaxRate)');
  
  Result := TotalExpr.Value;
end;

Discount Logic

var
  DiscountExpr: TExpression;
begin
  DiscountExpr := TDataExpression.FromString(Orders,
    'if Total > 1000 then Total * 0.1 else ' +
    'if Total > 500 then Total * 0.05 else 0');
  
  Discount := DiscountExpr.Value;
end;

Age Calculation

var
  AgeExpr: TExpression;
begin
  AgeExpr := TDataExpression.FromString(Customers,
    'Year(NOW) - Year(BirthDate)');
  
  Age := AgeExpr.Value;
end;

Full Name

var
  NameExpr: TExpression;
begin
  NameExpr := TDataExpression.FromString(Customers,
    'FirstName + " " + LastName');
  
  FullName := NameExpr.Value;
end;

Complex Filter

var
  FilterExpr: TExpression;
begin
  FilterExpr := TDataFilter.FromString(Products,
    '(Category = "Electronics" or Category = "Computers") and ' +
    'Price between 100 and 500 and ' +
    'InStock = true and ' +
    'not IsEmpty(Description)');
end;

Date Range

var
  RangeExpr: TExpression;
begin
  RangeExpr := TDataFilter.FromString(Orders,
    'OrderDate >= Date("2024-01-01") and ' +
    'OrderDate < Date("2024-02-01")');
end;

Error Handling

Custom Error Handler

function MyErrorHandler(const APos: Integer; const AMessage: String): Boolean;
begin
  ShowMessage(Format('Parse error at position %d: %s', [APos, AMessage]));
  Result := True;  // Suppress exception
end;

var
  Expr: TExpression;
begin
  Expr := TExpression.FromString('invalid + syntax', nil, MyErrorHandler);
end;

Try-Catch

var
  Expr: TExpression;
begin
  try
    Expr := TExpression.FromString(UserInput);
    Result := Expr.Value;
  except
    on E: EExpressionParse do
      ShowMessage('Parse error: ' + E.Message);
  end;
end;

Performance Tips

Reuse Expressions

// Bad: Parse every time
for i := 0 to 1000 do
  Result := TExpression.Evaluate('Price * 1.2');

// Good: Parse once, reuse
var
  Expr: TExpression;
begin
  Expr := TExpression.FromString('Price * 1.2');
  for i := 0 to 1000 do
    Result := Expr.Value;
end;

Simplify Complex Expressions

// Less optimal
Expr := 'if A > 100 and B > 100 and C > 100 then X else Y';

// Better (if possible)
Expr := 'if Min([A,B,C]) > 100 then X else Y';

See Also

Build docs developers (and LLMs) love