blob: 3fef6cd3eff7b5afdd52c30561561d0ff9dda24c [file] [log] [blame]
import 'package:meta/meta.dart';
import '../../context/context.dart';
import '../../context/failure.dart';
import '../../context/result.dart';
import '../../context/success.dart';
import '../../core/parser.dart';
import '../../shared/types.dart';
import '../combinator/delegate.dart';
extension WhereParserExtension<R> on Parser<R> {
/// Returns a parser that evaluates the [predicate] with the successful
/// parse result. If the predicate returns `true` the parser proceeds with
/// the parse result, otherwise a parse failure is created using the
/// optionally specified [failureMessage] and [failurePosition] callbacks.
///
/// The function [failureMessage] receives the parse result and is expected
/// to return an error string of the failed predicate. If no function is
/// provided a default error message is created.
///
/// Similarly, the [failurePosition] receives the parse result and is
/// expected to return the position of the error of the failed predicate. If
/// no function is provided the parser fails at the beginning of the
/// delegate.
///
/// The following example parses two characters, but only succeeds if they
/// are equal:
///
/// final inner = any() & any();
/// final parser = inner.where(
/// (value) => value[0] == value[1],
/// failureFactory: (context, success) =>
/// context.failure('characters do not match'));
/// parser.parse('aa'); // ==> Success: ['a', 'a']
/// parser.parse('ab'); // ==> Failure: characters do not match
///
@useResult
Parser<R> where(
Predicate<R> predicate, {
FailureFactory<R>? failureFactory,
@Deprecated('Use `failureFactory` instead')
Callback<R, String>? failureMessage,
@Deprecated('Use `failureFactory` instead')
Callback<R, int>? failurePosition,
}) =>
WhereParser<R>(
this,
predicate,
failureFactory ??
((failureMessage != null || failurePosition != null)
? (context, success) => context.failure(
failureMessage?.call(success.value) ??
'unexpected "${success.value}"',
failurePosition?.call(success.value))
: (context, success) =>
context.failure('unexpected "${success.value}"')));
}
typedef FailureFactory<R> = Failure<R> Function(
Context context, Success<R> success);
class WhereParser<R> extends DelegateParser<R, R> {
WhereParser(super.parser, this.predicate, this.failureFactory);
final Predicate<R> predicate;
final FailureFactory<R> failureFactory;
@override
Result<R> parseOn(Context context) {
final result = delegate.parseOn(context);
if (result is Success<R> && !predicate(result.value)) {
return failureFactory(context, result);
}
return result;
}
@override
Parser<R> copy() => WhereParser<R>(delegate, predicate, failureFactory);
@override
bool hasEqualProperties(WhereParser<R> other) =>
super.hasEqualProperties(other) &&
predicate == other.predicate &&
failureFactory == other.failureFactory;
}