GridSheetExpressionEvaluator class

Custom expression evaluator with null-safe evaluation for GridSheet.

This class extends ExpressionEvaluator from the expressions package to provide null-safe evaluation of conditional formatting rules, filter expressions, and conditional editability expressions.

Null Handling Philosophy

Standard expression evaluation often throws exceptions when encountering null values. This evaluator implements graceful null handling suitable for spreadsheet-like grids where empty cells (nulls) are common:

Equality Operators

  • null == nulltrue
  • null == valuefalse
  • null != nullfalse
  • null != valuetrue

Comparison Operators

  • Any comparison with null → false
  • Examples: null < 5, 10 > null, null <= null all return false

Logical Operators

  • null && anythingfalse
  • null || truetrue
  • null || falsefalse
  • null || nullfalse

Unary Operators

  • !null (NOT null) → true (absence is treated as falsy)
  • -null, +nullnull

Arithmetic Operators

  • Any operation with null → null
  • Examples: null + 5, 10 * null return null

Usage Examples

final evaluator = GridSheetExpressionEvaluator();
final parser = ExpressionParser();

// Conditional formatting with nulls
final expr = parser.parse('age > 18');
final context = {'age': null};
final result = evaluator.eval(expr, context);
debugPrint(result);  // false (null comparison returns false)

// Null equality check
final expr = parser.parse('status == null');
final context = {'status': null};
final result = evaluator.eval(expr, context);
debugPrint(result);  // true

// Logical operations with nulls
final expr = parser.parse('active || premium');
final context = {'active': null, 'premium': true};
final result = evaluator.eval(expr, context);
debugPrint(result);  // true (null || true = true)

// Complex expression
final expr = parser.parse('(age >= 18 && age <= 65) || retired');
final context = {'age': null, 'retired': true};
final result = evaluator.eval(expr, context);
debugPrint(result);  // true (first part false, but retired is true)

Custom Evaluator Pattern

You can extend this class to add custom functions or operators:

class CustomEvaluator extends GridSheetExpressionEvaluator {
  @override
  dynamic evalMemberExpression(
    MemberExpression expression,
    Map<String, dynamic> context,
  ) {
    // Add custom functions like ISBLANK(), LEN(), etc.
    if (expression.property is Identifier) {
      final funcName = (expression.property as Identifier).name;

      if (funcName == 'ISBLANK') {
        final value = eval(expression.object, context);
        return value == null || value == '';
      }

      if (funcName == 'LEN') {
        final value = eval(expression.object, context);
        return value?.toString().length ?? 0;
      }
    }

    return super.evalMemberExpression(expression, context);
  }
}

Performance Considerations

  • Expression parsing is expensive; cache parsed expressions when possible
  • Evaluation is relatively fast but avoid in hot loops
  • Context map lookup is O(1) but creates temporary objects

Thread Safety

This evaluator is stateless and thread-safe. Multiple threads can share the same instance safely.

See also:

  • GridSheetConditionalFormatRule, which uses this for formatting rules
  • GridSheetColumn.conditionalExpression, for cell editability
  • ExpressionEvaluator, the base class from the expressions package

Constructors

GridSheetExpressionEvaluator()
Creates a null-safe expression evaluator.
const

Properties

hashCode int
The hash code for this object.
no setterinherited
memberAccessors List<MemberAccessor>
finalinherited
runtimeType Type
A representation of the runtime type of the object.
no setterinherited

Methods

eval(Expression expression, Map<String, dynamic> context) → dynamic
Evaluates an expression with null-safe error handling.
evalBinaryExpression(BinaryExpression expression, Map<String, dynamic> context) → dynamic
Evaluates binary operations with null-safe logic.
evalCallExpression(CallExpression expression, Map<String, dynamic> context) → dynamic
inherited
evalConditionalExpression(ConditionalExpression expression, Map<String, dynamic> context) → dynamic
inherited
evalIndexExpression(IndexExpression expression, Map<String, dynamic> context) → dynamic
inherited
evalLiteral(Literal literal, Map<String, dynamic> context) → dynamic
Evaluates literal values, including null literals.
evalMemberExpression(MemberExpression expression, Map<String, dynamic> context) → dynamic
inherited
evalThis(ThisExpression expression, Map<String, dynamic> context) → dynamic
inherited
evalUnaryExpression(UnaryExpression expression, Map<String, dynamic> context) → dynamic
Evaluates unary operations with null-safe logic.
evalVariable(Variable variable, Map<String, dynamic> context) → dynamic
inherited
getMember(dynamic obj, String member) → dynamic
inherited
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
toString() String
A string representation of this object.
inherited

Operators

operator ==(Object other) bool
The equality operator.
inherited