blob: 9dd2b9deba6533d13018ec74011055f981c245e3 [file] [log] [blame]
import 'package:meta/meta.dart';
import '../../context/context.dart';
import '../../context/failure.dart';
import '../../context/result.dart';
import '../../core/parser.dart';
import '../predicate/any.dart';
import 'delegate.dart';
import 'sequence.dart';
extension NotParserExtension<R> on Parser<R> {
/// Returns a parser (logical not-predicate) that succeeds with the [Failure]
/// whenever the receiver fails, but never consumes input.
///
/// For example, the parser `char('_').not().seq(identifier)` accepts
/// identifiers that do not start with an underscore character. If the parser
/// `char('_')` accepts the input, the negation and subsequently the
/// complete parser fails. Otherwise the parser `identifier` is given the
/// ability to process the complete identifier.
@useResult
Parser<Failure<R>> not([String message = 'success not expected']) =>
NotParser(this, message);
/// Returns a parser that consumes any input token (character), but the
/// receiver.
///
/// For example, the parser `letter().neg()` accepts any input but a letter.
/// The parser fails for inputs like `'a'` or `'Z'`, but succeeds for
/// input like `'1'`, `'_'` or `'$'`.
@useResult
Parser<String> neg([String message = 'input not expected']) =>
seq2(not(message), any()).map2((_, value) => value);
}
/// The not-predicate, a parser that succeeds whenever its delegate does not,
/// but consumes no input [Parr 1994, 1995].
class NotParser<R> extends DelegateParser<R, Failure<R>> {
NotParser(super.delegate, this.message);
/// Error message to annotate parse failures with.
final String message;
@override
Result<Failure<R>> parseOn(Context context) {
final result = delegate.parseOn(context);
if (result.isFailure) {
return context.success(result as Failure<R>);
} else {
return context.failure(message);
}
}
@override
int fastParseOn(String buffer, int position) {
final result = delegate.fastParseOn(buffer, position);
return result < 0 ? position : -1;
}
@override
String toString() => '${super.toString()}[$message]';
@override
NotParser<R> copy() => NotParser<R>(delegate, message);
@override
bool hasEqualProperties(NotParser<R> other) =>
super.hasEqualProperties(other) && message == other.message;
}