platform/packages/combinator/lib/src/combinator/repeat.dart
2021-05-18 21:15:28 +08:00

89 lines
2.1 KiB
Dart

part of lex.src.combinator;
class _Repeat<T> extends ListParser<T> {
final Parser<T> parser;
final int count;
final bool exact, backtrack;
final String tooFew;
final String tooMany;
final SyntaxErrorSeverity severity;
_Repeat(this.parser, this.count, this.exact, this.tooFew, this.tooMany,
this.backtrack, this.severity);
@override
ParseResult<List<T>> __parse(ParseArgs args) {
var errors = <SyntaxError>[];
var results = <T>[];
var spans = <FileSpan>[];
var success = 0;
var replay = args.scanner.position;
ParseResult<T> result;
do {
result = parser._parse(args.increaseDepth());
if (result.successful) {
success++;
if (result.value != null) {
results.add(result.value!);
}
replay = args.scanner.position;
} else if (backtrack) args.scanner.position = replay;
if (result.span != null) {
spans.add(result.span!);
}
} while (result.successful);
if (success < count) {
errors.addAll(result.errors);
errors.add(
SyntaxError(
severity,
tooFew,
result.span ?? args.scanner.emptySpan,
),
);
if (backtrack) args.scanner.position = replay;
return ParseResult<List<T>>(
args.trampoline, args.scanner, this, false, errors);
} else if (success > count && exact) {
if (backtrack) args.scanner.position = replay;
return ParseResult<List<T>>(args.trampoline, args.scanner, this, false, [
SyntaxError(
severity,
tooMany,
result.span ?? args.scanner.emptySpan,
),
]);
}
var span = spans.reduce((a, b) => a.expand(b));
return ParseResult<List<T>>(
args.trampoline,
args.scanner,
this,
true,
[],
span: span,
value: results,
);
}
@override
void stringify(CodeBuffer buffer) {
var r = StringBuffer('{$count');
if (!exact) r.write(',');
r.write('}');
buffer
..writeln('repeat($r) (')
..indent();
parser.stringify(buffer);
buffer
..outdent()
..writeln(')');
}
}