Updated to Null Safety
This commit is contained in:
parent
cb56b31d10
commit
01171d8954
24 changed files with 101 additions and 94 deletions
|
@ -8,7 +8,7 @@ class _Advance<T> extends Parser<T> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<T> __parse(ParseArgs args) {
|
ParseResult<T> __parse(ParseArgs args) {
|
||||||
var result = parser._parse(args.increaseDepth())!.change(parser: this);
|
var result = parser._parse(args.increaseDepth()).change(parser: this);
|
||||||
if (result.successful) args.scanner.position += amount;
|
if (result.successful) args.scanner.position += amount;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ part of lex.src.combinator;
|
||||||
/// generate any error at all.
|
/// generate any error at all.
|
||||||
Parser<T> any<T>(Iterable<Parser<T>> parsers,
|
Parser<T> any<T>(Iterable<Parser<T>> parsers,
|
||||||
{bool backtrack: true, errorMessage, SyntaxErrorSeverity? severity}) {
|
{bool backtrack: true, errorMessage, SyntaxErrorSeverity? severity}) {
|
||||||
return new _Any(parsers, backtrack != false, errorMessage,
|
return _Any(parsers, backtrack != false, errorMessage,
|
||||||
severity ?? SyntaxErrorSeverity.error);
|
severity ?? SyntaxErrorSeverity.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,14 +26,14 @@ class _Any<T> extends Parser<T> {
|
||||||
.where((p) => !args.trampoline.isActive(p, args.scanner.position));
|
.where((p) => !args.trampoline.isActive(p, args.scanner.position));
|
||||||
|
|
||||||
if (inactive.isEmpty) {
|
if (inactive.isEmpty) {
|
||||||
return new ParseResult(args.trampoline, args.scanner, this, false, []);
|
return ParseResult(args.trampoline, args.scanner, this, false, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
var errors = <SyntaxError>[];
|
var errors = <SyntaxError>[];
|
||||||
int replay = args.scanner.position;
|
int replay = args.scanner.position;
|
||||||
|
|
||||||
for (var parser in inactive) {
|
for (var parser in inactive) {
|
||||||
var result = parser._parse(args.increaseDepth())!;
|
var result = parser._parse(args.increaseDepth());
|
||||||
|
|
||||||
if (result.successful)
|
if (result.successful)
|
||||||
return result;
|
return result;
|
||||||
|
@ -45,7 +45,7 @@ class _Any<T> extends Parser<T> {
|
||||||
|
|
||||||
if (errorMessage != false) {
|
if (errorMessage != false) {
|
||||||
errors.add(
|
errors.add(
|
||||||
new SyntaxError(
|
SyntaxError(
|
||||||
severity,
|
severity,
|
||||||
errorMessage?.toString() ??
|
errorMessage?.toString() ??
|
||||||
'No match found for ${parsers.length} alternative(s)',
|
'No match found for ${parsers.length} alternative(s)',
|
||||||
|
@ -54,13 +54,13 @@ class _Any<T> extends Parser<T> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ParseResult(args.trampoline, args.scanner, this, false, errors);
|
return ParseResult(args.trampoline, args.scanner, this, false, errors);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<T>? __parse(ParseArgs args) {
|
ParseResult<T> __parse(ParseArgs args) {
|
||||||
// Never called
|
// Never called
|
||||||
return null;
|
throw ArgumentError("[Combinator] Invalid method call");
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
|
@ -7,7 +7,7 @@ class _Cast<T, U extends T> extends Parser<U> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<U> __parse(ParseArgs args) {
|
ParseResult<U> __parse(ParseArgs args) {
|
||||||
var result = parser._parse(args.increaseDepth())!;
|
var result = parser._parse(args.increaseDepth());
|
||||||
return new ParseResult<U>(
|
return new ParseResult<U>(
|
||||||
args.trampoline,
|
args.trampoline,
|
||||||
args.scanner,
|
args.scanner,
|
||||||
|
@ -38,7 +38,7 @@ class _CastDynamic<T> extends Parser<dynamic> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<dynamic> __parse(ParseArgs args) {
|
ParseResult<dynamic> __parse(ParseArgs args) {
|
||||||
var result = parser._parse(args.increaseDepth())!;
|
var result = parser._parse(args.increaseDepth());
|
||||||
return new ParseResult<dynamic>(
|
return new ParseResult<dynamic>(
|
||||||
args.trampoline,
|
args.trampoline,
|
||||||
args.scanner,
|
args.scanner,
|
||||||
|
|
|
@ -18,7 +18,7 @@ class _Alt<T> extends Parser<T> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<T> __parse(ParseArgs args) {
|
ParseResult<T> __parse(ParseArgs args) {
|
||||||
var result = parser._parse(args.increaseDepth())!;
|
var result = parser._parse(args.increaseDepth());
|
||||||
return result.successful
|
return result.successful
|
||||||
? result
|
? result
|
||||||
: result.addErrors([
|
: result.addErrors([
|
||||||
|
@ -48,7 +48,7 @@ class _Chain<T> extends ListParser<T> {
|
||||||
bool successful = true;
|
bool successful = true;
|
||||||
|
|
||||||
for (var parser in parsers) {
|
for (var parser in parsers) {
|
||||||
var result = parser._parse(args.increaseDepth())!;
|
var result = parser._parse(args.increaseDepth());
|
||||||
|
|
||||||
if (!result.successful) {
|
if (!result.successful) {
|
||||||
if (parser is _Alt) errors.addAll(result.errors);
|
if (parser is _Alt) errors.addAll(result.errors);
|
||||||
|
|
|
@ -11,7 +11,7 @@ class _Check<T> extends Parser<T> {
|
||||||
@override
|
@override
|
||||||
ParseResult<T> __parse(ParseArgs args) {
|
ParseResult<T> __parse(ParseArgs args) {
|
||||||
var matchState = {};
|
var matchState = {};
|
||||||
var result = parser._parse(args.increaseDepth())!.change(parser: this);
|
var result = parser._parse(args.increaseDepth()).change(parser: this);
|
||||||
if (!result.successful)
|
if (!result.successful)
|
||||||
return result;
|
return result;
|
||||||
else if (!matcher.matches(result.value, matchState)) {
|
else if (!matcher.matches(result.value, matchState)) {
|
||||||
|
|
|
@ -67,9 +67,9 @@ class ParseArgs {
|
||||||
|
|
||||||
/// A parser combinator, which can parse very complicated grammars in a manageable manner.
|
/// A parser combinator, which can parse very complicated grammars in a manageable manner.
|
||||||
abstract class Parser<T> {
|
abstract class Parser<T> {
|
||||||
ParseResult<T>? __parse(ParseArgs args);
|
ParseResult<T> __parse(ParseArgs args);
|
||||||
|
|
||||||
ParseResult<T>? _parse(ParseArgs args) {
|
ParseResult<T> _parse(ParseArgs args) {
|
||||||
var pos = args.scanner.position;
|
var pos = args.scanner.position;
|
||||||
|
|
||||||
if (args.trampoline.hasMemoized(this, pos))
|
if (args.trampoline.hasMemoized(this, pos))
|
||||||
|
@ -86,7 +86,7 @@ abstract class Parser<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses text from a [SpanScanner].
|
/// Parses text from a [SpanScanner].
|
||||||
ParseResult<T>? parse(SpanScanner scanner, [int depth = 1]) {
|
ParseResult<T> parse(SpanScanner scanner, [int depth = 1]) {
|
||||||
var args = ParseArgs(Trampoline(), scanner, depth);
|
var args = ParseArgs(Trampoline(), scanner, depth);
|
||||||
return _parse(args);
|
return _parse(args);
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ abstract class Parser<T> {
|
||||||
|
|
||||||
// TODO: Type issue
|
// TODO: Type issue
|
||||||
/// Runs the given function, which changes the returned [ParseResult] into one relating to a [U] object.
|
/// Runs the given function, which changes the returned [ParseResult] into one relating to a [U] object.
|
||||||
Parser<U> change<U>(ParseResult<U> Function(ParseResult<T>?) f) {
|
Parser<U> change<U>(ParseResult<U> Function(ParseResult<T>) f) {
|
||||||
return _Change<T, U>(this, f);
|
return _Change<T, U>(this, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,8 +140,10 @@ abstract class Parser<T> {
|
||||||
/// Ensures this pattern is not matched.
|
/// Ensures this pattern is not matched.
|
||||||
///
|
///
|
||||||
/// You can provide an [errorMessage].
|
/// You can provide an [errorMessage].
|
||||||
Parser<T> negate({String? errorMessage, SyntaxErrorSeverity? severity}) =>
|
Parser<T> negate(
|
||||||
_Negate<T>(this, errorMessage, severity ?? SyntaxErrorSeverity.error);
|
{String errorMessage = 'Negate error',
|
||||||
|
SyntaxErrorSeverity severity = SyntaxErrorSeverity.error}) =>
|
||||||
|
_Negate<T>(this, errorMessage, severity);
|
||||||
|
|
||||||
/// Caches the results of parse attempts at various locations within the source text.
|
/// Caches the results of parse attempts at various locations within the source text.
|
||||||
///
|
///
|
||||||
|
@ -153,7 +155,7 @@ abstract class Parser<T> {
|
||||||
/// Consumes `this` and another parser, but only considers the result of `this` parser.
|
/// Consumes `this` and another parser, but only considers the result of `this` parser.
|
||||||
Parser<T> and(Parser other) => then(other).change<T>((r) {
|
Parser<T> and(Parser other) => then(other).change<T>((r) {
|
||||||
return ParseResult<T>(
|
return ParseResult<T>(
|
||||||
r!.trampoline,
|
r.trampoline,
|
||||||
r.scanner,
|
r.scanner,
|
||||||
this,
|
this,
|
||||||
r.successful,
|
r.successful,
|
||||||
|
@ -176,7 +178,7 @@ abstract class Parser<T> {
|
||||||
/// The generated parser only runs once; repeated uses always exit eagerly.
|
/// The generated parser only runs once; repeated uses always exit eagerly.
|
||||||
Parser<T> safe(
|
Parser<T> safe(
|
||||||
{bool backtrack: true,
|
{bool backtrack: true,
|
||||||
String? errorMessage,
|
String errorMessage = "error",
|
||||||
SyntaxErrorSeverity? severity}) =>
|
SyntaxErrorSeverity? severity}) =>
|
||||||
_Safe<T>(
|
_Safe<T>(
|
||||||
this, backtrack, errorMessage, severity ?? SyntaxErrorSeverity.error);
|
this, backtrack, errorMessage, severity ?? SyntaxErrorSeverity.error);
|
||||||
|
@ -240,7 +242,7 @@ abstract class Parser<T> {
|
||||||
Parser<T> space() => trail(RegExp(r'[ \n\r\t]+'));
|
Parser<T> space() => trail(RegExp(r'[ \n\r\t]+'));
|
||||||
|
|
||||||
/// Consumes 0 or more instance(s) of this parser.
|
/// Consumes 0 or more instance(s) of this parser.
|
||||||
ListParser<T?> star({bool backtrack: true}) =>
|
ListParser<T> star({bool backtrack: true}) =>
|
||||||
times(1, exact: false, backtrack: backtrack).opt();
|
times(1, exact: false, backtrack: backtrack).opt();
|
||||||
|
|
||||||
/// Shortcut for [chain]-ing two parsers together.
|
/// Shortcut for [chain]-ing two parsers together.
|
||||||
|
@ -259,10 +261,10 @@ abstract class Parser<T> {
|
||||||
/// an infinite amount of occurrences after the specified [count].
|
/// an infinite amount of occurrences after the specified [count].
|
||||||
///
|
///
|
||||||
/// You can provide custom error messages for when there are [tooFew] or [tooMany] occurrences.
|
/// You can provide custom error messages for when there are [tooFew] or [tooMany] occurrences.
|
||||||
ListParser<T?> times(int count,
|
ListParser<T> times(int count,
|
||||||
{bool exact: true,
|
{bool exact: true,
|
||||||
String? tooFew,
|
String tooFew = 'Too few',
|
||||||
String? tooMany,
|
String tooMany = 'Too many',
|
||||||
bool backtrack: true,
|
bool backtrack: true,
|
||||||
SyntaxErrorSeverity? severity}) {
|
SyntaxErrorSeverity? severity}) {
|
||||||
return _Repeat<T>(this, count, exact, tooFew, tooMany, backtrack,
|
return _Repeat<T>(this, count, exact, tooFew, tooMany, backtrack,
|
||||||
|
|
|
@ -8,7 +8,7 @@ class _Compare<T> extends ListParser<T> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<List<T>> __parse(ParseArgs args) {
|
ParseResult<List<T>> __parse(ParseArgs args) {
|
||||||
ParseResult<List<T>> result = parser._parse(args.increaseDepth())!;
|
ParseResult<List<T>> result = parser._parse(args.increaseDepth());
|
||||||
if (!result.successful) return result;
|
if (!result.successful) return result;
|
||||||
|
|
||||||
result = result.change(
|
result = result.change(
|
||||||
|
|
|
@ -8,7 +8,7 @@ class _FoldErrors<T> extends Parser<T> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<T> __parse(ParseArgs args) {
|
ParseResult<T> __parse(ParseArgs args) {
|
||||||
var result = parser._parse(args.increaseDepth())!.change(parser: this);
|
var result = parser._parse(args.increaseDepth()).change(parser: this);
|
||||||
var errors = result.errors.fold<List<SyntaxError>>([], (out, e) {
|
var errors = result.errors.fold<List<SyntaxError>>([], (out, e) {
|
||||||
if (!out.any((b) => equal(e, b))) out.add(e);
|
if (!out.any((b) => equal(e, b))) out.add(e);
|
||||||
return out;
|
return out;
|
||||||
|
|
|
@ -8,7 +8,7 @@ class _Index<T> extends Parser<T> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<T> __parse(ParseArgs args) {
|
ParseResult<T> __parse(ParseArgs args) {
|
||||||
ParseResult<List<T>> result = parser._parse(args.increaseDepth())!;
|
ParseResult<List<T>> result = parser._parse(args.increaseDepth());
|
||||||
Object? value;
|
Object? value;
|
||||||
|
|
||||||
if (result.successful)
|
if (result.successful)
|
||||||
|
|
|
@ -31,7 +31,7 @@ class _Longest<T> extends Parser<T> {
|
||||||
var results = <ParseResult<T>>[];
|
var results = <ParseResult<T>>[];
|
||||||
|
|
||||||
for (var parser in inactive) {
|
for (var parser in inactive) {
|
||||||
var result = parser._parse(args.increaseDepth())!;
|
var result = parser._parse(args.increaseDepth());
|
||||||
|
|
||||||
if (result.successful && result.span != null)
|
if (result.successful && result.span != null)
|
||||||
results.add(result);
|
results.add(result);
|
||||||
|
@ -66,7 +66,7 @@ class _Longest<T> extends Parser<T> {
|
||||||
var results = <ParseResult<T>>[];
|
var results = <ParseResult<T>>[];
|
||||||
|
|
||||||
for (var parser in parsers) {
|
for (var parser in parsers) {
|
||||||
var result = parser._parse(args.increaseDepth())!;
|
var result = parser._parse(args.increaseDepth());
|
||||||
|
|
||||||
if (result.successful)
|
if (result.successful)
|
||||||
results.add(result);
|
results.add(result);
|
||||||
|
|
|
@ -8,8 +8,8 @@ class _Map<T, U> extends Parser<U> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<U> __parse(ParseArgs args) {
|
ParseResult<U> __parse(ParseArgs args) {
|
||||||
var result = parser._parse(args.increaseDepth())!;
|
var result = parser._parse(args.increaseDepth());
|
||||||
return new ParseResult<U>(
|
return ParseResult<U>(
|
||||||
args.trampoline,
|
args.trampoline,
|
||||||
args.scanner,
|
args.scanner,
|
||||||
this,
|
this,
|
||||||
|
@ -34,7 +34,7 @@ class _Map<T, U> extends Parser<U> {
|
||||||
|
|
||||||
class _Change<T, U> extends Parser<U> {
|
class _Change<T, U> extends Parser<U> {
|
||||||
final Parser<T> parser;
|
final Parser<T> parser;
|
||||||
final ParseResult<U> Function(ParseResult<T>?) f;
|
final ParseResult<U> Function(ParseResult<T>) f;
|
||||||
|
|
||||||
_Change(this.parser, this.f);
|
_Change(this.parser, this.f);
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ class _MaxDepth<T> extends Parser<T> {
|
||||||
_MaxDepth(this.parser, this.cap);
|
_MaxDepth(this.parser, this.cap);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<T>? __parse(ParseArgs args) {
|
ParseResult<T> __parse(ParseArgs args) {
|
||||||
if (args.depth > cap) {
|
if (args.depth > cap) {
|
||||||
return new ParseResult<T>(args.trampoline, args.scanner, this, false, []);
|
return new ParseResult<T>(args.trampoline, args.scanner, this, false, []);
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ class _Negate<T> extends Parser<T> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<T> __parse(ParseArgs args) {
|
ParseResult<T> __parse(ParseArgs args) {
|
||||||
var result = parser._parse(args.increaseDepth())!.change(parser: this);
|
var result = parser._parse(args.increaseDepth()).change(parser: this);
|
||||||
|
|
||||||
if (!result.successful) {
|
if (!result.successful) {
|
||||||
return new ParseResult<T>(
|
return new ParseResult<T>(
|
||||||
|
|
|
@ -9,7 +9,7 @@ class _Opt<T> extends Parser<T> {
|
||||||
@override
|
@override
|
||||||
ParseResult<T> __parse(ParseArgs args) {
|
ParseResult<T> __parse(ParseArgs args) {
|
||||||
var replay = args.scanner.position;
|
var replay = args.scanner.position;
|
||||||
var result = parser._parse(args.increaseDepth())!;
|
var result = parser._parse(args.increaseDepth());
|
||||||
|
|
||||||
if (!result.successful) args.scanner.position = replay;
|
if (!result.successful) args.scanner.position = replay;
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ class _ListOpt<T> extends ListParser<T> {
|
||||||
@override
|
@override
|
||||||
ParseResult<List<T>> __parse(ParseArgs args) {
|
ParseResult<List<T>> __parse(ParseArgs args) {
|
||||||
var replay = args.scanner.position;
|
var replay = args.scanner.position;
|
||||||
ParseResult<List<T>> result = parser._parse(args.increaseDepth())!;
|
ParseResult<List<T>> result = parser._parse(args.increaseDepth());
|
||||||
|
|
||||||
if (!result.successful) args.scanner.position = replay;
|
if (!result.successful) args.scanner.position = replay;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ class _Reduce<T> extends Parser<T> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<T> __parse(ParseArgs args) {
|
ParseResult<T> __parse(ParseArgs args) {
|
||||||
ParseResult<List<T>> result = parser._parse(args.increaseDepth())!;
|
ParseResult<List<T>> result = parser._parse(args.increaseDepth());
|
||||||
|
|
||||||
if (!result.successful)
|
if (!result.successful)
|
||||||
return new ParseResult<T>(
|
return new ParseResult<T>(
|
||||||
|
|
|
@ -16,22 +16,26 @@ class Reference<T> extends Parser<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<T>? __parse(ParseArgs args) {
|
ParseResult<T> __parse(ParseArgs args) {
|
||||||
if (_parser == null)
|
if (_parser == null)
|
||||||
throw new StateError('There is no parser assigned to this reference.');
|
throw new StateError('There is no parser assigned to this reference.');
|
||||||
return _parser!._parse(args);
|
return _parser!._parse(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<T>? _parse(ParseArgs args) {
|
ParseResult<T> _parse(ParseArgs args) {
|
||||||
|
if (_parser == null)
|
||||||
|
throw new StateError('There is no parser assigned to this reference.');
|
||||||
return _parser!._parse(args);
|
return _parser!._parse(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void stringify(CodeBuffer buffer) {
|
void stringify(CodeBuffer buffer) {
|
||||||
if (_parser == null)
|
if (_parser == null) {
|
||||||
buffer.writeln('(undefined reference <$T>)');
|
buffer.writeln('(undefined reference <$T>)');
|
||||||
else if (!printed) _parser!.stringify(buffer);
|
} else if (!printed) {
|
||||||
|
_parser!.stringify(buffer);
|
||||||
|
}
|
||||||
printed = true;
|
printed = true;
|
||||||
buffer.writeln('(previously printed reference)');
|
buffer.writeln('(previously printed reference)');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,63 +1,67 @@
|
||||||
part of lex.src.combinator;
|
part of lex.src.combinator;
|
||||||
|
|
||||||
class _Repeat<T> extends ListParser<T?> {
|
class _Repeat<T> extends ListParser<T> {
|
||||||
final Parser<T> parser;
|
final Parser<T> parser;
|
||||||
final int count;
|
final int count;
|
||||||
final bool exact, backtrack;
|
final bool exact, backtrack;
|
||||||
final String? tooFew, tooMany;
|
final String tooFew;
|
||||||
|
final String tooMany;
|
||||||
final SyntaxErrorSeverity severity;
|
final SyntaxErrorSeverity severity;
|
||||||
|
|
||||||
_Repeat(this.parser, this.count, this.exact, this.tooFew, this.tooMany,
|
_Repeat(this.parser, this.count, this.exact, this.tooFew, this.tooMany,
|
||||||
this.backtrack, this.severity);
|
this.backtrack, this.severity);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<List<T?>> __parse(ParseArgs args) {
|
ParseResult<List<T>> __parse(ParseArgs args) {
|
||||||
var errors = <SyntaxError>[];
|
var errors = <SyntaxError>[];
|
||||||
var results = <T?>[];
|
var results = <T>[];
|
||||||
var spans = <FileSpan?>[];
|
var spans = <FileSpan>[];
|
||||||
int success = 0, replay = args.scanner.position;
|
int success = 0, replay = args.scanner.position;
|
||||||
ParseResult<T>? result;
|
ParseResult<T>? result;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
result = parser._parse(args.increaseDepth());
|
result = parser._parse(args.increaseDepth());
|
||||||
if (result!.successful) {
|
if (result.successful) {
|
||||||
success++;
|
success++;
|
||||||
results.add(result.value);
|
if (result.value != null) {
|
||||||
|
results.add(result.value!);
|
||||||
|
}
|
||||||
replay = args.scanner.position;
|
replay = args.scanner.position;
|
||||||
} else if (backtrack) args.scanner.position = replay;
|
} else if (backtrack) args.scanner.position = replay;
|
||||||
|
|
||||||
if (result.span != null) spans.add(result.span);
|
if (result.span != null) {
|
||||||
|
spans.add(result.span!);
|
||||||
|
}
|
||||||
} while (result.successful);
|
} while (result.successful);
|
||||||
|
|
||||||
if (success < count) {
|
if (success < count) {
|
||||||
errors.addAll(result.errors);
|
errors.addAll(result.errors);
|
||||||
errors.add(
|
errors.add(
|
||||||
new SyntaxError(
|
SyntaxError(
|
||||||
severity,
|
severity,
|
||||||
tooFew ?? 'Expected at least $count occurence(s).',
|
tooFew,
|
||||||
result.span ?? args.scanner.emptySpan,
|
result.span ?? args.scanner.emptySpan,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (backtrack) args.scanner.position = replay;
|
if (backtrack) args.scanner.position = replay;
|
||||||
|
|
||||||
return new ParseResult<List<T?>>(
|
return ParseResult<List<T>>(
|
||||||
args.trampoline, args.scanner, this, false, errors);
|
args.trampoline, args.scanner, this, false, errors);
|
||||||
} else if (success > count && exact) {
|
} else if (success > count && exact) {
|
||||||
if (backtrack) args.scanner.position = replay;
|
if (backtrack) args.scanner.position = replay;
|
||||||
|
|
||||||
return new ParseResult<List<T?>>(
|
return ParseResult<List<T>>(args.trampoline, args.scanner, this, false, [
|
||||||
args.trampoline, args.scanner, this, false, [
|
SyntaxError(
|
||||||
new SyntaxError(
|
|
||||||
severity,
|
severity,
|
||||||
tooMany ?? 'Expected no more than $count occurence(s).',
|
tooMany,
|
||||||
result.span ?? args.scanner.emptySpan,
|
result.span ?? args.scanner.emptySpan,
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var span = spans.reduce((a, b) => a!.expand(b!));
|
var span = spans.reduce((a, b) => a.expand(b));
|
||||||
return new ParseResult<List<T?>>(
|
return ParseResult<List<T>>(
|
||||||
args.trampoline,
|
args.trampoline,
|
||||||
args.scanner,
|
args.scanner,
|
||||||
this,
|
this,
|
||||||
|
@ -70,7 +74,7 @@ class _Repeat<T> extends ListParser<T?> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void stringify(CodeBuffer buffer) {
|
void stringify(CodeBuffer buffer) {
|
||||||
var r = new StringBuffer('{$count');
|
var r = StringBuffer('{$count');
|
||||||
if (!exact) r.write(',');
|
if (!exact) r.write(',');
|
||||||
r.write('}');
|
r.write('}');
|
||||||
buffer
|
buffer
|
||||||
|
|
|
@ -3,14 +3,14 @@ part of lex.src.combinator;
|
||||||
class _Safe<T> extends Parser<T> {
|
class _Safe<T> extends Parser<T> {
|
||||||
final Parser<T> parser;
|
final Parser<T> parser;
|
||||||
final bool backtrack;
|
final bool backtrack;
|
||||||
final String? errorMessage;
|
final String errorMessage;
|
||||||
final SyntaxErrorSeverity severity;
|
final SyntaxErrorSeverity severity;
|
||||||
bool _triggered = false;
|
bool _triggered = false;
|
||||||
|
|
||||||
_Safe(this.parser, this.backtrack, this.errorMessage, this.severity);
|
_Safe(this.parser, this.backtrack, this.errorMessage, this.severity);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<T>? __parse(ParseArgs args) {
|
ParseResult<T> __parse(ParseArgs args) {
|
||||||
var replay = args.scanner.position;
|
var replay = args.scanner.position;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -21,16 +21,13 @@ class _Safe<T> extends Parser<T> {
|
||||||
if (backtrack) args.scanner.position = replay;
|
if (backtrack) args.scanner.position = replay;
|
||||||
var errors = <SyntaxError>[];
|
var errors = <SyntaxError>[];
|
||||||
|
|
||||||
if (errorMessage != null) {
|
errors.add(
|
||||||
// TODO: Custom severity for all errors?
|
new SyntaxError(
|
||||||
errors.add(
|
severity,
|
||||||
new SyntaxError(
|
errorMessage,
|
||||||
severity,
|
args.scanner.lastSpan ?? args.scanner.emptySpan,
|
||||||
errorMessage,
|
),
|
||||||
args.scanner.lastSpan ?? args.scanner.emptySpan,
|
);
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ParseResult<T>(
|
return new ParseResult<T>(
|
||||||
args.trampoline, args.scanner, this, false, errors);
|
args.trampoline, args.scanner, this, false, errors);
|
||||||
|
|
|
@ -7,7 +7,7 @@ class _ToList<T> extends ListParser<T?> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<List<T?>> __parse(ParseArgs args) {
|
ParseResult<List<T?>> __parse(ParseArgs args) {
|
||||||
var result = parser._parse(args.increaseDepth())!;
|
var result = parser._parse(args.increaseDepth());
|
||||||
|
|
||||||
if (result.value is List) {
|
if (result.value is List) {
|
||||||
return (result as ParseResult<List<T?>>).change(parser: this);
|
return (result as ParseResult<List<T?>>).change(parser: this);
|
||||||
|
|
|
@ -8,7 +8,7 @@ class _Value<T> extends Parser<T> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
ParseResult<T> __parse(ParseArgs args) {
|
ParseResult<T> __parse(ParseArgs args) {
|
||||||
var result = parser._parse(args.increaseDepth())!.change(parser: this);
|
var result = parser._parse(args.increaseDepth()).change(parser: this);
|
||||||
return result.successful ? result.change(value: f(result)) : result;
|
return result.successful ? result.change(value: f(result)) : result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,11 +12,11 @@ main() {
|
||||||
|
|
||||||
test('sort', () {
|
test('sort', () {
|
||||||
var parser = numbers.sort((a, b) => a!.compareTo(b!));
|
var parser = numbers.sort((a, b) => a!.compareTo(b!));
|
||||||
expect(parser.parse(scan('21,2,3,34,20'))!.value, [2, 3, 20, 21, 34]);
|
expect(parser.parse(scan('21,2,3,34,20')).value, [2, 3, 20, 21, 34]);
|
||||||
});
|
});
|
||||||
test('reduce', () {
|
test('reduce', () {
|
||||||
var parser = numbers.reduce((a, b) => a! + b!);
|
var parser = numbers.reduce((a, b) => a! + b!);
|
||||||
expect(parser.parse(scan('21,2,3,34,20'))!.value, 80);
|
expect(parser.parse(scan('21,2,3,34,20')).value, 80);
|
||||||
expect(parser.parse(scan('not numbers'))!.value, isNull);
|
expect(parser.parse(scan('not numbers')).value, isNull);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,13 +4,13 @@ import 'common.dart';
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
test('match string', () {
|
test('match string', () {
|
||||||
expect(match('hello').parse(scan('hello world'))!.successful, isTrue);
|
expect(match('hello').parse(scan('hello world')).successful, isTrue);
|
||||||
});
|
});
|
||||||
test('match start only', () {
|
test('match start only', () {
|
||||||
expect(match('hello').parse(scan('goodbye hello'))!.successful, isFalse);
|
expect(match('hello').parse(scan('goodbye hello')).successful, isFalse);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('fail if no match', () {
|
test('fail if no match', () {
|
||||||
expect(match('hello').parse(scan('world'))!.successful, isFalse);
|
expect(match('hello').parse(scan('world')).successful, isFalse);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,29 +14,29 @@ main() {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('change', () {
|
test('change', () {
|
||||||
var parser = match('hello').change((r) => r!.change(value: 23));
|
var parser = match('hello').change((r) => r.change(value: 23));
|
||||||
expect(parser.parse(scan('helloworld'))!.value, 23);
|
expect(parser.parse(scan('helloworld')).value, 23);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('check', () {
|
test('check', () {
|
||||||
var parser = match<int>(new RegExp(r'[A-Za-z]+'))
|
var parser = match<int>(new RegExp(r'[A-Za-z]+'))
|
||||||
.value((r) => r.span!.length)
|
.value((r) => r.span!.length)
|
||||||
.check(greaterThan(3));
|
.check(greaterThan(3));
|
||||||
expect(parser.parse(scan('helloworld'))!.successful, isTrue);
|
expect(parser.parse(scan('helloworld')).successful, isTrue);
|
||||||
expect(parser.parse(scan('yo'))!.successful, isFalse);
|
expect(parser.parse(scan('yo')).successful, isFalse);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('map', () {
|
test('map', () {
|
||||||
var parser =
|
var parser =
|
||||||
match(new RegExp(r'[A-Za-z]+')).map<int>((r) => r.span!.length);
|
match(new RegExp(r'[A-Za-z]+')).map<int>((r) => r.span!.length);
|
||||||
expect(parser.parse(scan('hello'))!.value, 5);
|
expect(parser.parse(scan('hello')).value, 5);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('negate', () {
|
test('negate', () {
|
||||||
var parser = match('hello').negate(errorMessage: 'world');
|
var parser = match('hello').negate(errorMessage: 'world');
|
||||||
expect(parser.parse(scan('goodbye world'))!.successful, isTrue);
|
expect(parser.parse(scan('goodbye world')).successful, isTrue);
|
||||||
expect(parser.parse(scan('hello world'))!.successful, isFalse);
|
expect(parser.parse(scan('hello world')).successful, isFalse);
|
||||||
expect(parser.parse(scan('hello world'))!.errors.first.message, 'world');
|
expect(parser.parse(scan('hello world')).errors.first.message, 'world');
|
||||||
});
|
});
|
||||||
|
|
||||||
group('opt', () {
|
group('opt', () {
|
||||||
|
@ -44,13 +44,13 @@ main() {
|
||||||
var list = match('hel').then(match('lo')).opt();
|
var list = match('hel').then(match('lo')).opt();
|
||||||
|
|
||||||
test('succeeds if present', () {
|
test('succeeds if present', () {
|
||||||
expect(single.parse(scan('hello'))!.successful, isTrue);
|
expect(single.parse(scan('hello')).successful, isTrue);
|
||||||
expect(list.parse(scan('hello'))!.successful, isTrue);
|
expect(list.parse(scan('hello')).successful, isTrue);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('succeeds if not present', () {
|
test('succeeds if not present', () {
|
||||||
expect(single.parse(scan('goodbye'))!.successful, isTrue);
|
expect(single.parse(scan('goodbye')).successful, isTrue);
|
||||||
expect(list.parse(scan('goodbye'))!.successful, isTrue);
|
expect(list.parse(scan('goodbye')).successful, isTrue);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('backtracks if not present', () {
|
test('backtracks if not present', () {
|
||||||
|
|
|
@ -6,10 +6,10 @@ main() {
|
||||||
var parser = match('hello').value((r) => 'world');
|
var parser = match('hello').value((r) => 'world');
|
||||||
|
|
||||||
test('sets value', () {
|
test('sets value', () {
|
||||||
expect(parser.parse(scan('hello world'))!.value, 'world');
|
expect(parser.parse(scan('hello world')).value, 'world');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('no value if no match', () {
|
test('no value if no match', () {
|
||||||
expect(parser.parse(scan('goodbye world'))!.value, isNull);
|
expect(parser.parse(scan('goodbye world')).value, isNull);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue