Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(670)

Unified Diff: pkg/glob/lib/src/ast.dart

Issue 549633002: Add support for listing to the glob package. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Don't run glob tests on the browser. Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: pkg/glob/lib/src/ast.dart
diff --git a/pkg/glob/lib/src/ast.dart b/pkg/glob/lib/src/ast.dart
index 5e1da1a72c2fddff8fac2c64c6f3d132d8c0c0f9..d49b7af6a0d4e7f474fb5cc763be89aefa21985d 100644
--- a/pkg/glob/lib/src/ast.dart
+++ b/pkg/glob/lib/src/ast.dart
@@ -25,6 +25,14 @@ abstract class AstNode {
/// Either this or [canMatchRelative] or both will be true.
final bool canMatchRelative = true;
+ /// Returns a new glob with all the options bubbled to the top level.
+ ///
+ /// In particular, this returns a glob AST with two guarantees:
+ ///
+ /// 1. There are no [OptionsNode]s other than the one at the top level.
+ /// 2. It matches the same set of paths as [this].
+ OptionsNode expand() => new OptionsNode([new SequenceNode([this])]);
Bob Nystrom 2014/09/18 22:17:39 How about "flattenOptions"? Using the same name as
nweiz 2014/09/22 23:48:39 Done.
+
/// Returns whether this glob matches [string].
bool matches(String string) {
if (_regExp == null) _regExp = new RegExp('^${_toRegExp()}\$');
@@ -46,6 +54,87 @@ class SequenceNode extends AstNode {
SequenceNode(Iterable<AstNode> nodes)
: nodes = nodes.toList();
+ OptionsNode expand() {
+ if (nodes.isEmpty) return new OptionsNode([this]);
+
+ var sequences = nodes.first.expand().options;
+ for (var node in nodes.skip(1)) {
+ var nextSequences = node.expand().options;
+ sequences = sequences.expand((sequence) {
+ return nextSequences.map((nextSequence) {
Bob Nystrom 2014/09/18 22:17:39 A loop containing an expand call that's mapping ea
nweiz 2014/09/22 23:48:39 Done.
+ var next = nextSequence.nodes.toList();
+ var combined = sequence.nodes.toList();
+
+ // Combine adjacent LiteralNodes.
+ if (!combined.isEmpty && !next.isEmpty &&
+ combined.last is LiteralNode && next.first is LiteralNode) {
+ combined[combined.length - 1] =
+ new LiteralNode(combined.last.text + next.removeAt(0).text);
+ }
+
+ return new SequenceNode(combined..addAll(next));
+ });
+ });
+ }
+ return new OptionsNode(sequences.toList());
+ }
+
+ /// Splits this glob into components along its path separators.
Bob Nystrom 2014/09/18 22:17:39 A before/after example would help a lot here.
nweiz 2014/09/22 23:48:39 Done.
+ ///
+ /// This should only be called once the glob has been [expand]ed. [context] is
Bob Nystrom 2014/09/18 22:17:39 If this is only valid on certain states, maybe it
nweiz 2014/09/22 23:48:39 Rather than doing that (which I think would add a
+ /// used to determine what absolute roots look like for this glob.
+ List<SequenceNode> split(p.Context context) {
+ // The inner list represents a [SequenceNode] for a single path component;
+ // the outer list is the list of components.
+ var sequences = [[]];
Bob Nystrom 2014/09/18 22:17:39 I think this code will be easier to read if you ad
nweiz 2014/09/22 23:48:39 Done.
+
+ for (var node in nodes) {
+ // This should only be called after [expand].
+ assert(node is! OptionsNode);
+
+ if (node is! LiteralNode || !node.text.contains('/')) {
+ sequences.last.add(node);
+ continue;
+ }
+
+ var text = node.text;
+ if (context.style == p.Style.windows) text.replaceAll("/", "\\");
+ var components = context.split(text);
Bob Nystrom 2014/09/18 22:17:39 "nodeComponents"?
nweiz 2014/09/22 23:48:39 This is referenced a lot more often than the previ
+
+ // If the first component is absolute, that means it's a separator (on
+ // Windows some non-separator things are also absolute, but it's invalid
+ // to have "C:" show up in the middle of a path anyway).
+ if (context.isAbsolute(components.first)) {
+ // If this is the first component, it's the root.
+ if (sequences.length == 1 && sequences.first.isEmpty) {
+ var root = components.first;
+ if (context.style == p.Style.windows) {
+ root = root.replaceAll("\\", "/");
Bob Nystrom 2014/09/18 22:17:39 Why switch to forward slashes on Windows?
nweiz 2014/09/22 23:48:39 Above, we switched to backslashes to make [context
+ }
+ sequences.last.add(new LiteralNode(root));
+ }
+ sequences.add([]);
+ components = components.skip(1);
+ if (components.isEmpty) continue;
+ }
+
+ // For each component except the last one, add a separate sequence to
+ // [sequences] containing only that component.
+ for (var component in components.take(components.length - 1)) {
+ sequences.last.add(new LiteralNode(component));
+ sequences.add([]);
+ }
+
+ // For the final component, only end its sequence (by adding a new empty
+ // sequence) if it ends with a separator.
+ sequences.last.add(new LiteralNode(components.last));
+ if (node.text.endsWith('/')) sequences.add([]);
+ }
+
+ if (sequences.last.isEmpty) sequences.removeLast();
+ return sequences.map((sequence) => new SequenceNode(sequence)).toList();
+ }
+
String _toRegExp() => nodes.map((node) => node._toRegExp()).join();
String toString() => nodes.join();
@@ -119,6 +208,20 @@ class RangeNode extends AstNode {
RangeNode(Iterable<Range> ranges, {this.negated})
: ranges = ranges.toSet();
+ OptionsNode expand() {
+ if (negated || ranges.any((range) => !range.isSingleton)) {
+ return super.expand();
+ }
+
+ // If a range explicitly lists a set of characters, return each character as
+ // a separate expansion.
+ return new OptionsNode(ranges.map((range) {
+ return new SequenceNode([
+ new LiteralNode(new String.fromCharCodes([range.min]))
+ ]);
+ }));
+ }
+
String _toRegExp() {
var buffer = new StringBuffer();
@@ -172,6 +275,9 @@ class OptionsNode extends AstNode {
OptionsNode(Iterable<SequenceNode> options)
: options = options.toList();
+ OptionsNode expand() =>
+ new OptionsNode(options.expand((option) => option.expand().options));
+
String _toRegExp() =>
'(?:${options.map((option) => option._toRegExp()).join("|")})';
@@ -196,7 +302,7 @@ class LiteralNode extends AstNode {
bool get canMatchRelative => !canMatchAbsolute;
- LiteralNode(this.text, this._context);
+ LiteralNode(this.text, [this._context]);
String _toRegExp() => regExpQuote(text);

Powered by Google App Engine
This is Rietveld 408576698