blob: 12a322af19eca193a0b198819b1030d98c74ebff [file] [log] [blame] [edit]
import 'package:meta/meta.dart';
import '../../core/parser.dart';
import '../../shared/types.dart';
/// A continuous path through the parser graph.
class ParserPath {
/// Constructs a path from a list of parsers and indexes.
ParserPath(this.parsers, this.indexes)
: assert(parsers.isNotEmpty, 'parsers cannot be empty'),
assert(indexes.length == parsers.length - 1, 'indexes wrong size'),
assert((() {
for (var i = 0; i < indexes.length; i++) {
if (parsers[i].children[indexes[i]] != parsers[i + 1]) {
return false;
}
}
return true;
})(), 'indexes invalid');
/// The non-empty list of parsers in this path.
final List<Parser> parsers;
/// The parser where this path starts.
Parser get source => parsers.first;
/// The parser where this path ends.
Parser get target => parsers.last;
/// The number of parsers in this path.
int get length => parsers.length;
/// The child-indexes that navigate from one parser to the next one. This
/// collection contains one element less than the number of parsers in the
/// path.
final List<int> indexes;
void _push(Parser parser, int index) {
parsers.add(parser);
indexes.add(index);
}
void _pop() {
parsers.removeLast();
indexes.removeLast();
}
}
@internal
Iterable<ParserPath> depthFirstSearch(
ParserPath path, Predicate<ParserPath> predicate) sync* {
if (predicate(path)) {
yield ParserPath(List.from(path.parsers), List.from(path.indexes));
} else {
final children = path.target.children;
for (var i = 0; i < children.length; i++) {
final child = children[i];
if (!path.parsers.contains(child)) {
path._push(child, i);
yield* depthFirstSearch(path, predicate);
path._pop();
}
}
}
}