primaryTerm function
Primary term parser - parses the basic building blocks of expressions.
This includes:
- Grouped expressions: (a + b)
- Ranges: (1..5)
- Unary operations: not x, !x
- Member access: user.name
- Array access: items
0 - Literals: 1, "hello", true
- Identifiers: user
Optimized with first-character routing to skip impossible alternatives:
- Letter-starting inputs skip paren checks, route to identifier-like parsers
- Quote-starting inputs skip to string literal directly
- Digit/minus inputs skip to numeric literal directly
- Paren/bang inputs route to their specific parsers
This provides ~15% reduction in parser activations for typical inputs.
Implementation
Parser primaryTerm() {
// Letter-starting inputs: identifiers, keywords, 'not' operator
// Skip paren checks since letters can't start grouped expressions
final letterCases =
pattern('a-zA-Z').and() &
(ref0(unaryOperation) | // 'not x'
ref0(memberAccess) | // x, x.y (has fast path for simple identifiers)
ref0(arrayAccess) | // x[0]
ref0(literal) | // true, false, nil, empty
ref0(identifier)); // fallback
// '!' -> unary not operation
final bangCase = char('!').and() & ref0(unaryOperation);
// Quote-starting -> string literal (skip 5 alternatives)
final stringCase = (char('"') | char("'")).and() & ref0(stringLiteral);
// Digit or minus -> numeric literal (skip 5 alternatives)
final numericCase = (digit() | char('-')).and() & ref0(numericLiteral);
// Paren -> grouped expression or range
final parenCase = char('(').and() & (ref0(groupedExpression) | ref0(range));
return (letterCases.pick(1) | // Most common: identifiers
bangCase.pick(1) | // Unary bang
stringCase.pick(1) | // String literals
numericCase.pick(1) | // Numeric literals
parenCase.pick(1)) // Grouped/range (less common)
.labeled('primaryTerm');
}