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 == null→truenull == value→falsenull != null→falsenull != value→true
Comparison Operators
- Any comparison with null →
false - Examples:
null < 5,10 > null,null <= nullall returnfalse
Logical Operators
null && anything→falsenull || true→truenull || false→falsenull || null→false
Unary Operators
!null(NOT null) →true(absence is treated as falsy)-null,+null→null
Arithmetic Operators
- Any operation with null →
null - Examples:
null + 5,10 * nullreturnnull
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 editabilityExpressionEvaluator, 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