primaryTerm function

Parser primaryTerm()

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: items0
  • 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');
}