memberAccess function
Member access parser - handles dot notation like product.name.first.
Optimized with a two-tier approach:
- Fast path: Pattern-based parsing for simple identifier chains (no array access) Uses a single pattern match + string split instead of parsing each identifier
- Slow path: Original recursive parsing for complex cases with array access
The fast path provides ~50% reduction in parser activations for simple cases.
Implementation
Parser memberAccess() {
// Fast path: Simple identifier chain without array access
// Pattern matches: identifier(.identifier)+ where no segment is followed by '['
final identChar = pattern('a-zA-Z0-9_-');
final dot = char('.');
// First segment: identifier pattern
final firstIdent = pattern('a-zA-Z') & identChar.star();
// Additional segments: .identifier (NOT followed by '[')
final additionalSegment = dot & pattern('a-zA-Z') & identChar.star();
// Fast path parser - matches simple chains and ensures not followed by '['
// The negative lookahead char('[').not() ensures we don't match when array access follows
final simpleMemberAccess =
((firstIdent & additionalSegment.plus()).flatten() & char('[').not())
.pick(0) // Get just the flattened string, not the lookahead result
.cast<String>()
.where((value) {
// Exclude reserved words in any segment
final parts = value.split('.');
return !parts.any(
(p) => ['and', 'or', 'not', 'contains'].contains(p),
);
})
.map((value) {
final parts = value.split('.');
final object = Identifier(parts.first);
final members = parts
.skip(1)
.map((name) => Identifier(name))
.toList();
return MemberAccess(object, members.cast<ASTNode>());
});
// Slow path: Original recursive parsing for complex cases (with array access)
final complexMemberAccess =
(ref0(identifier) &
(char('.') & (ref0(arrayAccess) | ref0(identifier))).plus())
.map((values) {
var object = values[0] as Identifier;
var members = (values[1] as List)
.map((m) => m[1] as ASTNode)
.toList();
return MemberAccess(object, members);
});
// Try fast path first, fall back to slow path
return (simpleMemberAccess | complexMemberAccess).labeled('memberAccess');
}