When a call carries an inline return type, the parser accepts any function name. The error only surfaces at evaluation time.
Reproduction
$expr = ExpressionParser::parse('xs:list<int>.sum:int()'); // parses fine
$expr->evaluate(new Scope(['xs' => [1, 2, 3]]));
// EvaluationError: Unknown function "sum"
Same for .reduce:int(...), .length:int(), .first:int() — every plausible-but-nonexistent name.
Why it matters
Expressions are typically parsed and validated once (e.g. when a user saves one) and evaluated much later, in a different context. A name typo therefore escapes validation and only explodes at evaluation time, where it is far more expensive to handle.
Suggestion
When a Declarations instance is available, the parser already knows the built-ins plus any custom declared functions. An undeclared function name could be rejected at parse time instead of being deferred to Scope.
When a call carries an inline return type, the parser accepts any function name. The error only surfaces at evaluation time.
Reproduction
Same for
.reduce:int(...),.length:int(),.first:int()— every plausible-but-nonexistent name.Why it matters
Expressions are typically parsed and validated once (e.g. when a user saves one) and evaluated much later, in a different context. A name typo therefore escapes validation and only explodes at evaluation time, where it is far more expensive to handle.
Suggestion
When a
Declarationsinstance is available, the parser already knows the built-ins plus any custom declared functions. An undeclared function name could be rejected at parse time instead of being deferred toScope.