platform/lib/src/grammar.dart

174 lines
4.5 KiB
Dart
Raw Normal View History

2017-11-27 02:21:19 +00:00
part of angel_route.src.router;
2017-11-28 21:07:14 +00:00
class RouteGrammar {
2017-11-27 02:21:19 +00:00
static final Parser<String> notSlash =
match(new RegExp(r'[^/]+')).value((r) => r.span.text);
static final Parser<RegExp> regExp = new _RegExpParser();
static final Parser<String> parameterName =
match(new RegExp(r':([A-Za-z0-9_]+)'))
.value((r) => r.span.text.substring(1));
2017-11-28 21:07:14 +00:00
static final Parser<ParameterSegment> parameterSegment = chain([
2017-11-27 02:21:19 +00:00
parameterName,
match('?').value((r) => true).opt(),
regExp.opt(),
]).map((r) {
2017-11-28 21:07:14 +00:00
var s = new ParameterSegment(r.value[0], r.value[2]);
return r.value[1] == true ? new OptionalSegment(s) : s;
2017-11-27 02:21:19 +00:00
});
2017-11-28 21:07:14 +00:00
static final Parser<WildcardSegment> wildcardSegment =
match('*').value((r) => new WildcardSegment());
2017-11-27 02:21:19 +00:00
2017-11-28 21:07:14 +00:00
static final Parser<ConstantSegment> constantSegment =
notSlash.map((r) => new ConstantSegment(r.value));
2017-11-27 02:21:19 +00:00
2017-11-28 21:07:14 +00:00
static final Parser<RouteSegment> routeSegment =
2017-11-27 02:21:19 +00:00
any([parameterSegment, wildcardSegment, constantSegment]);
2017-11-28 21:07:14 +00:00
static final Parser<RouteDefinition> routeDefinition = routeSegment
2017-11-27 02:21:19 +00:00
.separatedBy(match('/'))
2017-11-28 21:07:14 +00:00
.map((r) => new RouteDefinition(r.value ?? []))
2017-11-27 02:21:19 +00:00
.surroundedBy(match('/').star().opt());
}
class _RegExpParser extends Parser<RegExp> {
static final RegExp rgx = new RegExp(r'\((.+)\)');
@override
ParseResult<RegExp> parse(SpanScanner scanner, [int depth = 1]) {
if (!scanner.matches(rgx)) return new ParseResult(this, false, []);
return new ParseResult(this, true, [],
span: scanner.lastSpan, value: new RegExp(scanner.lastMatch[1]));
}
}
2017-11-28 21:07:14 +00:00
class RouteDefinition {
final List<RouteSegment> segments;
2017-11-27 02:21:19 +00:00
2017-11-28 21:07:14 +00:00
RouteDefinition(this.segments);
2017-11-27 02:21:19 +00:00
2017-11-28 21:07:14 +00:00
Parser<Map<String, dynamic>> compile() {
Parser<Map<String, dynamic>> out;
2017-11-27 02:21:19 +00:00
2017-11-28 21:07:14 +00:00
for (int i = 0; i < segments.length; i++) {
var s = segments[i];
bool isLast = i == segments.length - 1;
2017-11-27 02:21:19 +00:00
if (out == null)
2017-11-28 21:07:14 +00:00
out = s.compile(isLast);
2017-11-27 02:21:19 +00:00
else
2017-11-28 21:07:14 +00:00
out = s.compileNext(out.then(match('/')).index(0), isLast);
2017-11-27 02:21:19 +00:00
}
return out;
}
}
2017-11-28 21:07:14 +00:00
abstract class RouteSegment {
Parser<Map<String, dynamic>> compile(bool isLast);
Parser<Map<String, dynamic>> compileNext(
Parser<Map<String, dynamic>> p, bool isLast);
2017-11-27 02:21:19 +00:00
}
2017-11-28 21:07:14 +00:00
class ConstantSegment extends RouteSegment {
2017-11-27 02:21:19 +00:00
final String text;
2017-11-28 21:07:14 +00:00
ConstantSegment(this.text);
2017-11-27 02:21:19 +00:00
@override
String toString() {
return 'Constant: $text';
}
@override
2017-11-28 21:07:14 +00:00
Parser<Map<String, dynamic>> compile(bool isLast) {
2017-11-27 02:21:19 +00:00
return match(text).value((r) => {});
}
@override
2017-11-28 21:07:14 +00:00
Parser<Map<String, dynamic>> compileNext(
Parser<Map<String, dynamic>> p, bool isLast) {
return p.then(compile(isLast)).index(0);
2017-11-27 02:21:19 +00:00
}
}
2017-11-28 21:07:14 +00:00
class WildcardSegment extends RouteSegment {
2017-11-27 02:21:19 +00:00
@override
String toString() {
return 'Wildcard segment';
}
2017-11-28 21:07:14 +00:00
Parser<Map<String, dynamic>> _compile(bool isLast) {
if (isLast) return match(new RegExp(r'.*'));
2017-11-27 02:21:19 +00:00
return match(new RegExp(r'[^/]*'));
}
@override
2017-11-28 21:07:14 +00:00
Parser<Map<String, dynamic>> compile(bool isLast) {
return _compile(isLast).map((r) => {});
2017-11-27 02:21:19 +00:00
}
@override
2017-11-28 21:07:14 +00:00
Parser<Map<String, dynamic>> compileNext(
Parser<Map<String, dynamic>> p, bool isLast) {
return p.then(_compile(isLast)).index(0);
2017-11-27 02:21:19 +00:00
}
}
2017-11-28 21:07:14 +00:00
class OptionalSegment extends ParameterSegment {
final ParameterSegment parameter;
2017-11-27 02:21:19 +00:00
2017-11-28 21:07:14 +00:00
OptionalSegment(this.parameter) : super(parameter.name, parameter.regExp);
2017-11-27 02:21:19 +00:00
@override
String toString() {
return 'Optional: $parameter';
}
@override
2017-11-28 21:07:14 +00:00
Parser<Map<String, dynamic>> compile(bool isLast) {
return super.compile(isLast).opt();
2017-11-27 02:21:19 +00:00
}
@override
2017-11-28 21:07:14 +00:00
Parser<Map<String, dynamic>> compileNext(
Parser<Map<String, dynamic>> p, bool isLast) {
2017-11-27 02:21:19 +00:00
return p.then(_compile().opt()).map((r) {
if (r.value[1] == null) return r.value[0];
return r.value[0]..addAll({name: Uri.decodeComponent(r.value[1])});
});
}
}
2017-11-28 21:07:14 +00:00
class ParameterSegment extends RouteSegment {
2017-11-27 02:21:19 +00:00
final String name;
final RegExp regExp;
2017-11-28 21:07:14 +00:00
ParameterSegment(this.name, this.regExp);
2017-11-27 02:21:19 +00:00
@override
String toString() {
if (regExp != null) return 'Param: $name (${regExp.pattern})';
return 'Param: $name';
}
2017-11-28 21:07:14 +00:00
Parser<Map<String, dynamic>> _compile() {
2017-11-27 02:21:19 +00:00
return regExp != null
? match(regExp).value((r) => r.span.text)
2017-11-28 21:07:14 +00:00
: RouteGrammar.notSlash;
2017-11-27 02:21:19 +00:00
}
@override
2017-11-28 21:07:14 +00:00
Parser<Map<String, dynamic>> compile(bool isLast) {
2017-11-27 02:21:19 +00:00
return _compile().map((r) => {name: Uri.decodeComponent(r.span.text)});
}
@override
2017-11-28 21:07:14 +00:00
Parser<Map<String, dynamic>> compileNext(
Parser<Map<String, dynamic>> p, bool isLast) {
2017-11-27 02:21:19 +00:00
return p.then(_compile()).map((r) {
return r.value[0]..addAll({name: Uri.decodeComponent(r.value[1])});
});
}
}