Updated combinator

This commit is contained in:
thomashii 2021-05-18 21:15:28 +08:00
parent 082b7876b4
commit 26d9936a3f
26 changed files with 85 additions and 69 deletions

View file

@ -1,3 +1,6 @@
# 2.0.2
* Resolve static analysis warnings
# 2.0.1
* Updated README

View file

@ -1,5 +1,5 @@
# angel3_combinator
[![version](https://img.shields.io/badge/pub-v2.0.1-brightgreen)](https://pub.dartlang.org/packages/angel3_combinator)
[![version](https://img.shields.io/badge/pub-v2.0.2-brightgreen)](https://pub.dartlang.org/packages/angel3_combinator)
[![Null Safety](https://img.shields.io/badge/null-safety-brightgreen)](https://dart.dev/null-safety)
[![Gitter](https://img.shields.io/gitter/room/angel_dart/discussion)](https://gitter.im/angel_dart/discussion)

View file

@ -1,3 +1,4 @@
include: package:pedantic/analysis_options.yaml
analyzer:
strong-mode:
implicit-casts: false

View file

@ -49,7 +49,8 @@ void main() {
print(error.toolString);
print(error.span!.highlight(color: true));
}
} else
} else {
print(result.value);
}
}
}

View file

@ -64,7 +64,8 @@ void main() {
stderr.writeln(error.toolString);
stderr.writeln(error.span!.highlight(color: true));
}
} else
} else {
print(result.value);
}
}
}

View file

@ -10,7 +10,7 @@ final Parser<String> id =
// pattern.
//
// This is useful for parsing arrays or map literals.
main() {
void main() {
while (true) {
stdout.write('Enter a string (ex "a,b,c"): ');
var line = stdin.readLineSync()!;
@ -22,7 +22,8 @@ main() {
print(error.toolString);
print(error.span!.highlight(color: true));
}
} else
} else {
print(result.value);
}
}
}

View file

@ -50,7 +50,7 @@ Parser jsonGrammar() {
return expr.foldErrors();
}
main() {
void main() {
var JSON = jsonGrammar();
while (true) {
@ -64,7 +64,8 @@ main() {
print(error.toolString);
print(error.span!.highlight(color: true));
}
} else
} else {
print(result.value);
}
}
}

View file

@ -19,7 +19,7 @@ final Parser number = //
(minus.opt() & decimal) // minus?, decimal
.map<num>((r) => num.parse(r.span!.text));
main() {
void main() {
while (true) {
stdout.write('Enter a number: ');
var line = stdin.readLineSync()!;
@ -31,7 +31,8 @@ main() {
stderr.writeln(error.toolString);
stderr.writeln(error.span!.highlight(color: true));
}
} else
} else {
print(result.value);
}
}
}

View file

@ -26,7 +26,7 @@ final Parser pairs = pair
final Parser queryString = pairs.opt();
main() {
void main() {
while (true) {
stdout.write('Enter a query string: ');
var line = stdin.readLineSync()!;
@ -38,7 +38,8 @@ main() {
print(error.toolString);
print(error.span!.highlight(color: true));
}
} else
} else {
print(result.value);
}
}
}

View file

@ -45,12 +45,13 @@ void main() {
while (q.isNotEmpty) {
var current = q.removeFirst();
if (current is! Tuple2)
if (current is! Tuple2) {
out.insert(0, current);
else {
} else {
var args = [];
for (int i = 0; i < (current.item1 as num); i++)
for (var i = 0; i < (current.item1 as num); i++) {
args.add(out.removeLast());
}
out.add(current.item2(args));
}
}

View file

@ -7,7 +7,7 @@ part of lex.src.combinator;
/// You can provide a custom [errorMessage]. You can set it to `false` to not
/// generate any error at all.
Parser<T> any<T>(Iterable<Parser<T>> parsers,
{bool backtrack: true, errorMessage, SyntaxErrorSeverity? severity}) {
{bool backtrack = true, errorMessage, SyntaxErrorSeverity? severity}) {
return _Any(parsers, backtrack != false, errorMessage,
severity ?? SyntaxErrorSeverity.error);
}
@ -30,14 +30,14 @@ class _Any<T> extends Parser<T> {
}
var errors = <SyntaxError>[];
int replay = args.scanner.position;
var replay = args.scanner.position;
for (var parser in inactive) {
var result = parser._parse(args.increaseDepth());
if (result.successful)
if (result.successful) {
return result;
else {
} else {
if (backtrack) args.scanner.position = replay;
if (parser is _Alt) errors.addAll(result.errors);
}
@ -60,7 +60,7 @@ class _Any<T> extends Parser<T> {
@override
ParseResult<T> __parse(ParseArgs args) {
// Never called
throw ArgumentError("[Combinator] Invalid method call");
throw ArgumentError('[Combinator] Invalid method call');
}
@override
@ -68,7 +68,7 @@ class _Any<T> extends Parser<T> {
buffer
..writeln('any(${parsers.length}) (')
..indent();
int i = 1;
var i = 1;
for (var parser in parsers) {
buffer

View file

@ -4,7 +4,7 @@ part of lex.src.combinator;
///
/// If [failFast] is `true` (default), then the first failure to parse will abort the parse.
ListParser<T> chain<T>(Iterable<Parser<T>> parsers,
{bool failFast: true, SyntaxErrorSeverity? severity}) {
{bool failFast = true, SyntaxErrorSeverity? severity}) {
return _Chain<T>(
parsers, failFast != false, severity ?? SyntaxErrorSeverity.error);
}
@ -45,7 +45,7 @@ class _Chain<T> extends ListParser<T> {
var errors = <SyntaxError>[];
var results = <T>[];
var spans = <FileSpan>[];
bool successful = true;
var successful = true;
for (var parser in parsers) {
var result = parser._parse(args.increaseDepth());
@ -64,7 +64,7 @@ class _Chain<T> extends ListParser<T> {
if (result.value != null) {
results.add(result.value!);
} else {
results.add("NULL" as T);
results.add('NULL' as T);
}
if (result.span != null) {
@ -94,7 +94,7 @@ class _Chain<T> extends ListParser<T> {
buffer
..writeln('chain(${parsers.length}) (')
..indent();
int i = 1;
var i = 1;
for (var parser in parsers) {
buffer

View file

@ -12,9 +12,9 @@ class _Check<T> extends Parser<T> {
ParseResult<T> __parse(ParseArgs args) {
var matchState = {};
var result = parser._parse(args.increaseDepth()).change(parser: this);
if (!result.successful)
if (!result.successful) {
return result;
else if (!matcher.matches(result.value, matchState)) {
} else if (!matcher.matches(result.value, matchState)) {
return result.change(successful: false).addErrors([
SyntaxError(
severity,
@ -23,9 +23,10 @@ class _Check<T> extends Parser<T> {
result.span,
),
]);
} else
} else {
return result;
}
}
@override
void stringify(CodeBuffer buffer) {

View file

@ -72,11 +72,13 @@ abstract class Parser<T> {
ParseResult<T> _parse(ParseArgs args) {
var pos = args.scanner.position;
if (args.trampoline.hasMemoized(this, pos))
if (args.trampoline.hasMemoized(this, pos)) {
return args.trampoline.getMemoized<T>(this, pos);
}
if (args.trampoline.isActive(this, pos))
if (args.trampoline.isActive(this, pos)) {
return ParseResult(args.trampoline, args.scanner, this, false, []);
}
args.trampoline.enter(this, pos);
var result = __parse(args);
@ -103,7 +105,6 @@ abstract class Parser<T> {
/// Casts this parser to produce [dynamic] objects.
Parser<dynamic> castDynamic() => _CastDynamic<T>(this);
// TODO: Type issue
/// 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) {
return _Change<T, U>(this, f);
@ -122,7 +123,7 @@ abstract class Parser<T> {
_Alt<T>(this, errorMessage, severity ?? SyntaxErrorSeverity.error);
/// Removes multiple errors that occur in the same spot; this can reduce noise in parser output.
Parser<T> foldErrors({bool equal(SyntaxError a, SyntaxError b)?}) {
Parser<T> foldErrors({bool Function(SyntaxError a, SyntaxError b)? equal}) {
equal ??= (b, e) => b.span?.start.offset == e.span?.start.offset;
return _FoldErrors<T>(this, equal);
}
@ -177,8 +178,8 @@ abstract class Parser<T> {
///
/// The generated parser only runs once; repeated uses always exit eagerly.
Parser<T> safe(
{bool backtrack: true,
String errorMessage = "error",
{bool backtrack = true,
String errorMessage = 'error',
SyntaxErrorSeverity? severity}) =>
_Safe<T>(
this, backtrack, errorMessage, severity ?? SyntaxErrorSeverity.error);
@ -191,14 +192,14 @@ abstract class Parser<T> {
/// Use this as a shortcut to parse arrays, parameter lists, etc.
Parser<List<T>> separatedBy(Parser other) {
var suffix = other.then(this).index(1).cast<T>();
return this.then(suffix.star()).map((r) {
return then(suffix.star()).map((r) {
var v = r.value;
if (v == null || v.length < 2) {
return [];
}
var preceding = v.isEmpty ? [] : (v[0] == null ? [] : [v[0]]);
var out = List<T>.from(preceding);
if (v[1] != null && v[1] != "NULL") {
if (v[1] != null && v[1] != 'NULL') {
v[1].forEach((element) {
out.add(element as T);
});
@ -240,7 +241,7 @@ abstract class Parser<T> {
Parser<T> space() => trail(RegExp(r'[ \n\r\t]+'));
/// 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();
/// Shortcut for [chain]-ing two parsers together.
@ -260,10 +261,10 @@ abstract class Parser<T> {
///
/// You can provide custom error messages for when there are [tooFew] or [tooMany] occurrences.
ListParser<T> times(int count,
{bool exact: true,
{bool exact = true,
String tooFew = 'Too few',
String tooMany = 'Too many',
bool backtrack: true,
bool backtrack = true,
SyntaxErrorSeverity? severity}) {
return _Repeat<T>(this, count, exact, tooFew, tooMany, backtrack,
severity ?? SyntaxErrorSeverity.error);
@ -273,7 +274,7 @@ abstract class Parser<T> {
///
/// If [backtrack] is `true` (default), then a failed parse will not
/// modify the scanner state.
Parser<T> opt({bool backtrack: true}) => _Opt(this, backtrack);
Parser<T> opt({bool backtrack = true}) => _Opt(this, backtrack);
/// Sets the value of the [ParseResult].
Parser<T> value(T Function(ParseResult<T?>) f) {
@ -302,7 +303,7 @@ abstract class ListParser<T> extends Parser<List<T>> {
ListParser<T> sort(Comparator<T> compare) => _Compare(this, compare);
@override
ListParser<T> opt({bool backtrack: true}) => _ListOpt(this, backtrack);
ListParser<T> opt({bool backtrack = true}) => _ListOpt(this, backtrack);
/// Modifies this parser, returning only the values that match a predicate.
Parser<List<T>> where(bool Function(T) f) =>

View file

@ -8,7 +8,7 @@ class _Compare<T> extends ListParser<T> {
@override
ParseResult<List<T>> __parse(ParseArgs args) {
ParseResult<List<T>> result = parser._parse(args.increaseDepth());
var result = parser._parse(args.increaseDepth());
if (!result.successful) return result;
result = result.change(

View file

@ -8,19 +8,18 @@ class _Index<T> extends Parser<T> {
@override
ParseResult<T> __parse(ParseArgs args) {
ParseResult<List<T>> result = parser._parse(args.increaseDepth());
var result = parser._parse(args.increaseDepth());
Object? value;
if (result.successful) {
var vList = result.value;
if (vList == null) {
throw ArgumentError("ParseResult is null");
throw ArgumentError('ParseResult is null');
}
if (index == -1) {
value = vList.last;
} else {
if (index < vList.length) {
//TODO: Look at this
// print(">>>>Index: $index, Size: ${vList.length}");
// value =
// index == -1 ? result.value!.last : result.value!.elementAt(index);

View file

@ -25,16 +25,16 @@ class _Longest<T> extends Parser<T> {
return ParseResult(args.trampoline, args.scanner, this, false, []);
}
int replay = args.scanner.position;
var replay = args.scanner.position;
var errors = <SyntaxError>[];
var results = <ParseResult<T>>[];
for (var parser in inactive) {
var result = parser._parse(args.increaseDepth());
if (result.successful && result.span != null)
if (result.successful && result.span != null) {
results.add(result);
else if (parser is _Alt) errors.addAll(result.errors);
} else if (parser is _Alt) errors.addAll(result.errors);
args.scanner.position = replay;
}
@ -45,7 +45,7 @@ class _Longest<T> extends Parser<T> {
return results.first;
}
if (errorMessage != false)
if (errorMessage != false) {
errors.add(
SyntaxError(
severity,
@ -54,22 +54,23 @@ class _Longest<T> extends Parser<T> {
args.scanner.emptySpan,
),
);
}
return ParseResult(args.trampoline, args.scanner, this, false, errors);
}
@override
ParseResult<T> __parse(ParseArgs args) {
int replay = args.scanner.position;
var replay = args.scanner.position;
var errors = <SyntaxError>[];
var results = <ParseResult<T>>[];
for (var parser in parsers) {
var result = parser._parse(args.increaseDepth());
if (result.successful)
if (result.successful) {
results.add(result);
else if (parser is _Alt) errors.addAll(result.errors);
} else if (parser is _Alt) errors.addAll(result.errors);
args.scanner.position = replay;
}
@ -97,7 +98,7 @@ class _Longest<T> extends Parser<T> {
buffer
..writeln('longest(${parsers.length}) (')
..indent();
int i = 1;
var i = 1;
for (var parser in parsers) {
buffer

View file

@ -15,7 +15,7 @@ class _Match<T> extends Parser<T> {
@override
ParseResult<T> __parse(ParseArgs args) {
var scanner = args.scanner;
if (!scanner.scan(pattern))
if (!scanner.scan(pattern)) {
return ParseResult(args.trampoline, scanner, this, false, [
SyntaxError(
severity,
@ -23,6 +23,7 @@ class _Match<T> extends Parser<T> {
scanner.emptySpan,
),
]);
}
return ParseResult<T>(
args.trampoline,
scanner,

View file

@ -37,7 +37,7 @@ class _ListOpt<T> extends ListParser<T> {
@override
ParseResult<List<T>> __parse(ParseArgs args) {
var replay = args.scanner.position;
ParseResult<List<T>> result = parser._parse(args.increaseDepth());
var result = parser._parse(args.increaseDepth());
if (!result.successful) args.scanner.position = replay;

View file

@ -8,9 +8,9 @@ class _Reduce<T> extends Parser<T> {
@override
ParseResult<T> __parse(ParseArgs args) {
ParseResult<List<T>> result = parser._parse(args.increaseDepth());
var result = parser._parse(args.increaseDepth());
if (!result.successful)
if (!result.successful) {
return ParseResult<T>(
args.trampoline,
args.scanner,
@ -18,6 +18,7 @@ class _Reduce<T> extends Parser<T> {
false,
result.errors,
);
}
result = result.change(
value: result.value?.isNotEmpty == true ? result.value : []);

View file

@ -8,23 +8,26 @@ class Reference<T> extends Parser<T> {
Reference._();
void set parser(Parser<T> value) {
if (_parser != null)
set parser(Parser<T> value) {
if (_parser != null) {
throw StateError('There is already a parser assigned to this reference.');
}
_parser = value;
}
@override
ParseResult<T> __parse(ParseArgs args) {
if (_parser == null)
if (_parser == null) {
throw StateError('There is no parser assigned to this reference.');
}
return _parser!._parse(args);
}
@override
ParseResult<T> _parse(ParseArgs args) {
if (_parser == null)
if (_parser == null) {
throw StateError('There is no parser assigned to this reference.');
}
return _parser!._parse(args);
}

View file

@ -16,7 +16,8 @@ class _Repeat<T> extends ListParser<T> {
var errors = <SyntaxError>[];
var results = <T>[];
var spans = <FileSpan>[];
int success = 0, replay = args.scanner.position;
var success = 0;
var replay = args.scanner.position;
ParseResult<T> result;
do {

View file

@ -13,7 +13,7 @@ class _ToList<T> extends ListParser<T> {
return (result as ParseResult<List<T>>).change(parser: this);
}
List<T> values = [];
var values = <T>[];
if (result.value != null) {
values.add(result.value!);
}

View file

@ -1,5 +1,5 @@
name: angel3_combinator
version: 2.0.1
version: 2.0.2
description: Packrat parser combinators that support static typing, generics, file spans, memoization, and more.
homepage: https://github.com/dukefirehawk/angel/tree/angel3/packages/combinator
environment:
@ -12,3 +12,4 @@ dependencies:
tuple: ^2.0.0
dev_dependencies:
test: ^1.17.4
pedantic: ^1.11.0

View file

@ -2,7 +2,7 @@ import 'package:angel3_combinator/angel3_combinator.dart';
import 'package:test/test.dart';
import 'common.dart';
main() {
void main() {
var number = chain([
match(RegExp(r'[0-9]+')).value((r) => int.parse(r.span!.text)),
match(',').opt(),

View file

@ -1,7 +1,3 @@
import 'package:angel3_combinator/angel3_combinator.dart';
import 'package:string_scanner/string_scanner.dart';
import 'package:test/test.dart';
void main() {}
/*