Use Optional

This commit is contained in:
thomashii@dukefirehawk.com 2021-05-11 17:03:52 +08:00
parent 15926ff45d
commit 25af334f4d
27 changed files with 78 additions and 69 deletions

View file

@ -18,7 +18,7 @@ final Parser<Map<String, String>> credentials = chain<String>([
match<String>(':'),
string.opt(),
]).map<Map<String, String>>(
(r) => {'username': r.value![0]!, 'password': r.value![2]!});
(r) => {'username': r.value![0], 'password': r.value![2]});
/// We can actually embed a parser within another parser.
///

View file

@ -24,7 +24,7 @@ Parser<num> calculatorGrammar() {
expr.space(),
match<Null>(op).space() as Parser<num>,
expr.space(),
]).map((r) => f(r.value![0]!, r.value![2]!)),
]).map((r) => f(r.value![0], r.value![2])),
);
}

View file

@ -7,7 +7,7 @@ class _Advance<T> extends Parser<T> {
_Advance(this.parser, this.amount);
@override
ParseResult<T?> __parse(ParseArgs args) {
ParseResult<T> __parse(ParseArgs args) {
var result = parser._parse(args.increaseDepth()).change(parser: this);
if (result.successful) args.scanner.position += amount;
return result;

View file

@ -21,7 +21,7 @@ class _Any<T> extends Parser<T> {
_Any(this.parsers, this.backtrack, this.errorMessage, this.severity);
@override
ParseResult<T?> _parse(ParseArgs args) {
ParseResult<T> _parse(ParseArgs args) {
var inactive = parsers
.where((p) => !args.trampoline.isActive(p, args.scanner.position));

View file

@ -1,13 +1,13 @@
part of lex.src.combinator;
class _Cache<T> extends Parser<T> {
final Map<int, ParseResult<T?>> _cache = {};
final Map<int, ParseResult<T>> _cache = {};
final Parser<T> parser;
_Cache(this.parser);
@override
ParseResult<T?> __parse(ParseArgs args) {
ParseResult<T> __parse(ParseArgs args) {
return _cache.putIfAbsent(args.scanner.position, () {
return parser._parse(args.increaseDepth());
}).change(parser: this);

View file

@ -3,9 +3,9 @@ part of lex.src.combinator;
/// Expects to parse a sequence of [parsers].
///
/// If [failFast] is `true` (default), then the first failure to parse will abort the parse.
ListParser<T?> chain<T>(Iterable<Parser<T>> parsers,
ListParser<T> chain<T>(Iterable<Parser<T>> parsers,
{bool failFast: true, SyntaxErrorSeverity? severity}) {
return _Chain<T?>(
return _Chain<T>(
parsers, failFast != false, severity ?? SyntaxErrorSeverity.error);
}
@ -17,7 +17,7 @@ class _Alt<T> extends Parser<T> {
_Alt(this.parser, this.errorMessage, this.severity);
@override
ParseResult<T?> __parse(ParseArgs args) {
ParseResult<T> __parse(ParseArgs args) {
var result = parser._parse(args.increaseDepth());
return result.successful
? result
@ -33,7 +33,7 @@ class _Alt<T> extends Parser<T> {
}
}
class _Chain<T> extends ListParser<T?> {
class _Chain<T> extends ListParser<T> {
final Iterable<Parser<T>> parsers;
final bool failFast;
final SyntaxErrorSeverity severity;
@ -41,7 +41,7 @@ class _Chain<T> extends ListParser<T?> {
_Chain(this.parsers, this.failFast, this.severity);
@override
ParseResult<List<T?>?> __parse(ParseArgs args) {
ParseResult<List<T>> __parse(ParseArgs args) {
var errors = <SyntaxError>[];
var results = <T?>[];
var spans = <FileSpan>[];
@ -61,7 +61,10 @@ class _Chain<T> extends ListParser<T?> {
successful = false;
}
//TODO: To be looked at
//if (result.value != null) {
results.add(result.value);
//}
if (result.span != null) {
spans.add(result.span!);
@ -74,14 +77,14 @@ class _Chain<T> extends ListParser<T?> {
span = spans.reduce((a, b) => a.expand(b));
}
return ParseResult<List<T?>?>(
return ParseResult<List<T>>(
args.trampoline,
args.scanner,
this,
successful,
errors,
span: span,
value: List<T?>.unmodifiable(results),
value: List<T>.unmodifiable(results),
);
}

View file

@ -9,7 +9,7 @@ class _Check<T> extends Parser<T> {
_Check(this.parser, this.matcher, this.errorMessage, this.severity);
@override
ParseResult<T?> __parse(ParseArgs args) {
ParseResult<T> __parse(ParseArgs args) {
var matchState = {};
var result = parser._parse(args.increaseDepth()).change(parser: this);
if (!result.successful)

View file

@ -7,6 +7,7 @@ import 'package:matcher/matcher.dart';
import 'package:source_span/source_span.dart';
import 'package:string_scanner/string_scanner.dart';
import 'package:tuple/tuple.dart';
import 'package:optional/optional.dart';
import '../error.dart';
part 'any.dart';
@ -67,9 +68,9 @@ class ParseArgs {
/// A parser combinator, which can parse very complicated grammars in a manageable manner.
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;
if (args.trampoline.hasMemoized(this, pos))
@ -86,7 +87,7 @@ abstract class Parser<T> {
}
/// 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);
return _parse(args);
}
@ -105,7 +106,7 @@ abstract class Parser<T> {
// 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) {
Parser<U> change<U>(ParseResult<U> Function(ParseResult<T>) f) {
return _Change<T, U>(this, f);
}
@ -128,7 +129,7 @@ abstract class Parser<T> {
}
/// Transforms the parse result using a unary function.
Parser<U> map<U>(U Function(ParseResult<T?>) f) {
Parser<U> map<U>(U Function(ParseResult<T>) f) {
return _Map<T, U>(this, f);
}
@ -171,7 +172,7 @@ abstract class Parser<T> {
Parser<T> or<U>(Parser<T> other) => any<T>([this, other]);
/// Parses this sequence one or more times.
ListParser<T?> plus() => times(1, exact: false);
ListParser<T> plus() => times(1, exact: false);
/// Safely escapes this parser when an error occurs.
///
@ -207,11 +208,11 @@ abstract class Parser<T> {
});
}
Parser<T?> surroundedByCurlyBraces({T? defaultValue}) => opt()
Parser<T> surroundedByCurlyBraces({required T defaultValue}) => opt()
.surroundedBy(match('{').space(), match('}').space())
.map((r) => r.value ?? defaultValue);
Parser<T?> surroundedBySquareBrackets({T? defaultValue}) => opt()
Parser<T> surroundedBySquareBrackets({required T defaultValue}) => opt()
.surroundedBy(match('[').space(), match(']').space())
.map((r) => r.value ?? defaultValue);
@ -336,7 +337,9 @@ class Trampoline {
}
bool isActive(Parser parser, int position) {
if (!_active.containsKey(parser)) return false;
if (!_active.containsKey(parser)) {
return false;
}
var q = _active[parser]!;
if (q.isEmpty) return false;
//return q.contains(position);

View file

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

View file

@ -7,7 +7,7 @@ class _FoldErrors<T> extends Parser<T> {
_FoldErrors(this.parser, this.equal);
@override
ParseResult<T?> __parse(ParseArgs args) {
ParseResult<T> __parse(ParseArgs args) {
var result = parser._parse(args.increaseDepth()).change(parser: this);
var errors = result.errors.fold<List<SyntaxError>>([], (out, e) {
if (!out.any((b) => equal(e, b))) out.add(e);

View file

@ -16,7 +16,7 @@ class _Longest<T> extends Parser<T> {
_Longest(this.parsers, this.errorMessage, this.severity);
@override
ParseResult<T?> _parse(ParseArgs args) {
ParseResult<T> _parse(ParseArgs args) {
var inactive = parsers
.toList()
.where((p) => !args.trampoline.isActive(p, args.scanner.position));
@ -27,7 +27,7 @@ class _Longest<T> extends Parser<T> {
int replay = args.scanner.position;
var errors = <SyntaxError>[];
var results = <ParseResult<T?>>[];
var results = <ParseResult<T>>[];
for (var parser in inactive) {
var result = parser._parse(args.increaseDepth());
@ -59,10 +59,10 @@ class _Longest<T> extends Parser<T> {
}
@override
ParseResult<T?> __parse(ParseArgs args) {
ParseResult<T> __parse(ParseArgs args) {
int replay = args.scanner.position;
var errors = <SyntaxError>[];
var results = <ParseResult<T?>>[];
var results = <ParseResult<T>>[];
for (var parser in parsers) {
var result = parser._parse(args.increaseDepth());

View file

@ -2,14 +2,14 @@ part of lex.src.combinator;
class _Map<T, U> extends Parser<U> {
final Parser<T> parser;
final U Function(ParseResult<T?>) f;
final U Function(ParseResult<T>) f;
_Map(this.parser, this.f);
@override
ParseResult<U?> __parse(ParseArgs args) {
ParseResult<U> __parse(ParseArgs args) {
var result = parser._parse(args.increaseDepth());
return ParseResult<U?>(
return ParseResult<U>(
args.trampoline,
args.scanner,
this,
@ -34,12 +34,12 @@ class _Map<T, U> extends Parser<U> {
class _Change<T, U> extends Parser<U> {
final Parser<T> parser;
final ParseResult<U?> Function(ParseResult<T?>) f;
final ParseResult<U> Function(ParseResult<T>) f;
_Change(this.parser, this.f);
@override
ParseResult<U?> __parse(ParseArgs args) {
ParseResult<U> __parse(ParseArgs args) {
return f(parser._parse(args.increaseDepth())).change(parser: this);
}

View file

@ -7,7 +7,7 @@ class _MaxDepth<T> extends Parser<T> {
_MaxDepth(this.parser, this.cap);
@override
ParseResult<T?> __parse(ParseArgs args) {
ParseResult<T> __parse(ParseArgs args) {
if (args.depth > cap) {
return ParseResult<T>(args.trampoline, args.scanner, this, false, []);
}

View file

@ -8,7 +8,7 @@ class _Negate<T> extends Parser<T> {
_Negate(this.parser, this.errorMessage, this.severity);
@override
ParseResult<T?> __parse(ParseArgs args) {
ParseResult<T> __parse(ParseArgs args) {
var result = parser._parse(args.increaseDepth()).change(parser: this);
if (!result.successful) {

View file

@ -7,7 +7,7 @@ class _Opt<T> extends Parser<T> {
_Opt(this.parser, this.backtrack);
@override
ParseResult<T?> __parse(ParseArgs args) {
ParseResult<T> __parse(ParseArgs args) {
var replay = args.scanner.position;
var result = parser._parse(args.increaseDepth());
@ -35,9 +35,9 @@ class _ListOpt<T> extends ListParser<T> {
_ListOpt(this.parser, this.backtrack);
@override
ParseResult<List<T>?> __parse(ParseArgs args) {
ParseResult<List<T>> __parse(ParseArgs args) {
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;

View file

@ -7,8 +7,8 @@ class _Reduce<T> extends Parser<T> {
_Reduce(this.parser, this.combine);
@override
ParseResult<T?> __parse(ParseArgs args) {
ParseResult<List<T>?> result = parser._parse(args.increaseDepth());
ParseResult<T> __parse(ParseArgs args) {
ParseResult<List<T>> result = parser._parse(args.increaseDepth());
if (!result.successful)
return ParseResult<T>(

View file

@ -15,14 +15,14 @@ class Reference<T> extends Parser<T> {
}
@override
ParseResult<T?> __parse(ParseArgs args) {
ParseResult<T> __parse(ParseArgs args) {
if (_parser == null)
throw StateError('There is no parser assigned to this reference.');
return _parser!._parse(args);
}
@override
ParseResult<T?> _parse(ParseArgs args) {
ParseResult<T> _parse(ParseArgs args) {
if (_parser == null)
throw StateError('There is no parser assigned to this reference.');
return _parser!._parse(args);

View file

@ -12,12 +12,12 @@ class _Repeat<T> extends ListParser<T> {
this.backtrack, this.severity);
@override
ParseResult<List<T>?> __parse(ParseArgs args) {
ParseResult<List<T>> __parse(ParseArgs args) {
var errors = <SyntaxError>[];
var results = <T>[];
var spans = <FileSpan>[];
int success = 0, replay = args.scanner.position;
ParseResult<T?> result;
ParseResult<T> result;
do {
result = parser._parse(args.increaseDepth());
@ -51,7 +51,7 @@ class _Repeat<T> extends ListParser<T> {
} else if (success > count && exact) {
if (backtrack) args.scanner.position = replay;
return ParseResult<List<T>?>(args.trampoline, args.scanner, this, false, [
return ParseResult<List<T>>(args.trampoline, args.scanner, this, false, [
SyntaxError(
severity,
tooMany,

View file

@ -10,7 +10,7 @@ class _Safe<T> extends Parser<T> {
_Safe(this.parser, this.backtrack, this.errorMessage, this.severity);
@override
ParseResult<T?> __parse(ParseArgs args) {
ParseResult<T> __parse(ParseArgs args) {
var replay = args.scanner.position;
try {

View file

@ -2,12 +2,12 @@ part of lex.src.combinator;
class _Value<T> extends Parser<T> {
final Parser<T> parser;
final T Function(ParseResult<T?>) f;
final T Function(ParseResult<T>) f;
_Value(this.parser, this.f);
@override
ParseResult<T?> __parse(ParseArgs args) {
ParseResult<T> __parse(ParseArgs args) {
var result = parser._parse(args.increaseDepth()).change(parser: this);
return result.successful ? result.change(value: f(result)) : result;
}

View file

@ -15,5 +15,6 @@ dependencies:
source_span: ^1.8.1
string_scanner: ^1.1.0
tuple: ^2.0.0
optional: ^6.0.0-nullsafety.2
dev_dependencies:
test: ^1.17.3

View file

@ -11,11 +11,11 @@ main() {
var numbers = number.plus();
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]);
});
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('not numbers')).value, isNull);
});

View file

@ -139,7 +139,8 @@ abstract class Driver<
pipeline.handlers,
resolved.fold<Map<String, dynamic>>(
<String, dynamic>{}, (out, r) => out..addAll(r.allParams)),
(resolved.isEmpty ? null : resolved.first.parseResult)!,
//(resolved.isEmpty ? null : resolved.first.parseResult),
resolved.first.parseResult,
pipeline,
);
}

View file

@ -22,10 +22,11 @@ dependencies:
ref: sdk-2.12.x_nnbd
path: packages/model
angel_route:
git:
url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x_nnbd
path: packages/route
path: ../route
# git:
# url: https://github.com/dukefirehawk/angel.git
# ref: sdk-2.12.x_nnbd
# path: packages/route
charcode: ^1.2.0
combinator:
git:

View file

@ -311,7 +311,7 @@ class Router<T> {
if (parseResult != null) {
if (parseResult.successful && scanner.isDone) {
var tailResult = parseResult.value?.tail ?? '';
print(tailResult);
//print(tailResult);
var result = RoutingResult<T>(
parseResult: parseResult,
params: parseResult.value!.params,
@ -334,13 +334,13 @@ class Router<T> {
/// Returns the result of [resolve] with [path] passed as
/// both `absolute` and `relative`.
Iterable<RoutingResult<T?>> resolveAbsolute(String path,
Iterable<RoutingResult<T>> resolveAbsolute(String path,
{String method = 'GET', bool strip = true}) =>
resolveAll(path, path, method: method, strip: strip);
/// Finds every possible [Route] that matches the given path,
/// with the given method.
Iterable<RoutingResult<T?>> resolveAll(String absolute, String relative,
Iterable<RoutingResult<T>> resolveAll(String absolute, String relative,
{String method = 'GET', bool strip = true}) {
if (_useCache == true) {
return _cache.putIfAbsent('$method$absolute',

View file

@ -3,7 +3,7 @@ part of angel_route.src.router;
/// Represents a complex result of navigating to a path.
class RoutingResult<T> {
/// The parse result that matched the given sub-path.
final ParseResult<RouteResult?> parseResult;
final ParseResult<RouteResult> parseResult;
/// A nested instance, if a sub-path was matched.
final Iterable<RoutingResult<T>> nested;
@ -47,10 +47,10 @@ class RoutingResult<T> {
}
/// All handlers on this sub-path and its children.
List<T?> get allHandlers {
final handlers = <T?>[];
List<T> get allHandlers {
final handlers = <T>[];
void crawl(RoutingResult<T?> result) {
void crawl(RoutingResult<T> result) {
handlers.addAll(result.handlers);
if (result.nested.isNotEmpty == true) {

View file

@ -7,11 +7,11 @@ environment:
sdk: '>=2.12.0 <3.0.0'
dependencies:
combinator:
# path: ../combinator
git:
url: https://github.com/dukefirehawk/angel.git
ref: sdk-2.12.x_nnbd
path: packages/combinator
path: ../combinator
# git:
# url: https://github.com/dukefirehawk/angel.git
# ref: sdk-2.12.x_nnbd
# path: packages/combinator
string_scanner: ^1.0.0
dev_dependencies:
build_runner: ^1.11.5