expressionBuilderParser method
Expression builder setup.
Implementation
Parser<ExpressionNode> expressionBuilderParser() {
final builder = ExpressionBuilder<ExpressionNode>();
// Primitives
builder.primitive(ref0(primary));
// Group 1: Postfix selectors & operators
builder.group()
..postfix(
ref1(token, '++'),
(val, _) =>
UnaryExpressionNode(operator: '++', operand: val, isPrefix: false),
)
..postfix(
ref1(token, '--'),
(val, _) =>
UnaryExpressionNode(operator: '--', operand: val, isPrefix: false),
)
..postfix(
ref1(token, '!'),
(val, _) =>
UnaryExpressionNode(operator: '!', operand: val, isPrefix: false),
)
// Property access: .prop or ?.prop (including constructor tear-off .new)
..postfix(
seq2(
[ref1(token, '?.'), ref1(token, '.')].toChoiceParser(),
[
ref0(identifier),
ref0(newToken).map((t) => t.value),
].toChoiceParser(),
),
(target, access) => PropertyAccessNode(
target: target,
propertyName: access.$2,
isNullAware: access.$1.value == '?.',
),
)
// Method / function invocation: (args) or <typeArgs>(args)
..postfix(
seq2(
ref0(typeArguments)
.optional()
.map((list) => list ?? const <TypeNode>[]),
ref0(argumentList),
),
(target, inv) => InvocationExpressionNode(
target: target,
typeArguments: inv.$1,
arguments: inv.$2,
),
)
// Indexing: [index] or ?[index]
..postfix(
seq3(
[ref1(token, '?['), ref1(token, '[')].toChoiceParser(),
builder.loopback,
ref1(token, ']'),
),
(target, index) => IndexExpressionNode(
target: target,
index: index.$2,
isNullAware: index.$1.value == '?[',
),
);
// Group 2: Prefix operators
builder.group()
..prefix(
ref1(token, '-'),
(op, val) => UnaryExpressionNode(operator: '-', operand: val),
)
..prefix(
ref1(token, '!'),
(op, val) => UnaryExpressionNode(operator: '!', operand: val),
)
..prefix(
ref1(token, '~'),
(op, val) => UnaryExpressionNode(operator: '~', operand: val),
)
..prefix(
ref1(token, '++'),
(op, val) => UnaryExpressionNode(operator: '++', operand: val),
)
..prefix(
ref1(token, '--'),
(op, val) => UnaryExpressionNode(operator: '--', operand: val),
)
..prefix(ref0(awaitToken), (op, val) => AwaitExpressionNode(val))
..prefix(ref0(throwToken), (op, val) => ThrowExpressionNode(val));
// Group 3: Multiplicative (*, /, ~/, %)
builder.group()
..left(
ref1(token, '*'),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '*', right: right),
)
..left(
ref1(token, '/'),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '/', right: right),
)
..left(
ref1(token, '~/'),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '~/', right: right),
)
..left(
ref1(token, '%'),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '%', right: right),
);
// Group 4: Additive (+, -)
builder.group()
..left(
ref1(token, '+'),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '+', right: right),
)
..left(
ref1(token, '-'),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '-', right: right),
);
// Group 5: Shift (<<, >>>, >>)
builder.group()
..left(
ref1(token, '<<'),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '<<', right: right),
)
..left(
ref1(token, '>>>'),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '>>>', right: right),
)
..left(
ref1(token, '>>'),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '>>', right: right),
);
// Group 6: Relational (<, <=, >, >=, is, is!, as)
builder.group()
..left(
ref1(token, '<='),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '<=', right: right),
)
..left(
ref1(token, '>='),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '>=', right: right),
)
..left(
ref1(token, '<'),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '<', right: right),
)
..left(
ref1(token, '>'),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '>', right: right),
)
..postfix(
seq2(
[ref0(isToken) & ref1(token, '!'), ref0(isToken)].toChoiceParser(),
ref0(typeTestType),
),
(expr, isTest) {
final isNegated = isTest.$1 is List;
return TypeTestExpressionNode(
expression: expr,
type: isTest.$2,
isNegated: isNegated,
);
},
)
..postfix(
seq2(ref0(asToken), ref0(typeTestType)),
(expr, asCast) =>
TypeCastExpressionNode(expression: expr, type: asCast.$2),
);
// Group 7: Equality (==, !=)
builder.group()
..left(
ref1(token, '=='),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '==', right: right),
)
..left(
ref1(token, '!='),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '!=', right: right),
);
// Group 8: Bitwise AND (&)
builder.group().left(
ref1(token, '&'),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '&', right: right),
);
// Group 9: Bitwise XOR (^)
builder.group().left(
ref1(token, '^'),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '^', right: right),
);
// Group 10: Bitwise OR (|)
builder.group().left(
ref1(token, '|'),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '|', right: right),
);
// Group 11: Logical AND (&&)
builder.group().left(
ref1(token, '&&'),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '&&', right: right),
);
// Group 12: Logical OR (||)
builder.group().left(
ref1(token, '||'),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: '||', right: right),
);
// Group 13: If-null (??)
builder.group().right(
ref1(token, '??'),
(left, op, right) => IfNullExpressionNode(left: left, right: right),
);
// Group 14: Ternary conditional (c ? t : e)
builder.group().postfix(
seq4(
ref1(token, '?'),
builder.loopback,
ref1(token, ':'),
builder.loopback,
),
(cond, ternary) => ConditionalExpressionNode(
condition: cond,
thenExpression: ternary.$2,
elseExpression: ternary.$4,
),
);
// Group 15: Cascade (.. or ?..)
builder.group().postfix(
seq2(
[ref1(token, '?..'), ref1(token, '..')].toChoiceParser(),
ref0(cascadeSection).plus(),
),
(target, cascade) => CascadeExpressionNode(
target: target,
cascadeSections: cascade.$2,
isNullAware: cascade.$1.value == '?..',
),
);
// Group 16: Assignment & Compound Assignment (=, +=, -=, *=, /=, ~/=, %=, <<=, >>=, >>>=, &=, ^=, |=, ??=)
builder.group().right(
[
ref1(token, '='),
ref1(token, '+='),
ref1(token, '-='),
ref1(token, '*='),
ref1(token, '/='),
ref1(token, '~/='),
ref1(token, '%='),
ref1(token, '<<='),
ref1(token, '>>>='),
ref1(token, '>>='),
ref1(token, '&='),
ref1(token, '^='),
ref1(token, '|='),
ref1(token, '??='),
].toChoiceParser().map((t) => t.value),
(left, op, right) =>
BinaryExpressionNode(left: left, operator: op, right: right),
);
return builder.build();
}