Adds support for shadow piercing combinators
Fixes #23
diff --git a/lib/parser.dart b/lib/parser.dart
index 6b05c85..9b1b9ce 100644
--- a/lib/parser.dart
+++ b/lib/parser.dart
@@ -1244,13 +1244,30 @@
combinatorType = TokenKind.COMBINATOR_PLUS;
break;
case TokenKind.GREATER:
+ // Parse > or >>>
_eat(TokenKind.GREATER);
- combinatorType = TokenKind.COMBINATOR_GREATER;
+ if (_maybeEat(TokenKind.GREATER)) {
+ _eat(TokenKind.GREATER);
+ combinatorType = TokenKind.COMBINATOR_DEEP;
+ } else {
+ combinatorType = TokenKind.COMBINATOR_GREATER;
+ }
break;
case TokenKind.TILDE:
_eat(TokenKind.TILDE);
combinatorType = TokenKind.COMBINATOR_TILDE;
break;
+ case TokenKind.SLASH:
+ // Parse /deep/
+ _eat(TokenKind.SLASH);
+ var ate = _maybeEat(TokenKind.IDENTIFIER);
+ var tok = ate ? _previousToken : _peekToken;
+ if (!(ate && tok.text == 'deep')) {
+ _error('expected deep, but found ${tok.text}', tok.span);
+ }
+ _eat(TokenKind.SLASH);
+ combinatorType = TokenKind.COMBINATOR_DEEP;
+ break;
case TokenKind.AMPERSAND:
_eat(TokenKind.AMPERSAND);
thisOperator = true;
diff --git a/lib/src/tokenkind.dart b/lib/src/tokenkind.dart
index 27ccb4b..2ad648a 100644
--- a/lib/src/tokenkind.dart
+++ b/lib/src/tokenkind.dart
@@ -100,8 +100,9 @@
static const int COMBINATOR_PLUS = 515; // + combinator
static const int COMBINATOR_GREATER = 516; // > combinator
static const int COMBINATOR_TILDE = 517; // ~ combinator
+ static const int COMBINATOR_DEEP = 518; // /deep/ or >>> combinator
- static const int UNARY_OP_NONE = 518; // No unary operator present.
+ static const int UNARY_OP_NONE = 519; // No unary operator present.
// Attribute match types:
static const int INCLUDES = 530; // '~='
diff --git a/lib/src/tree.dart b/lib/src/tree.dart
index 63c7301..a103679 100644
--- a/lib/src/tree.dart
+++ b/lib/src/tree.dart
@@ -120,12 +120,24 @@
bool get isCombinatorTilde => combinator == TokenKind.COMBINATOR_TILDE;
bool get isCombinatorDescendant =>
combinator == TokenKind.COMBINATOR_DESCENDANT;
+ bool get isCombinatorDeep => combinator == TokenKind.COMBINATOR_DEEP;
- String get _combinatorToString => isCombinatorDescendant
- ? ' '
- : isCombinatorPlus
- ? ' + '
- : isCombinatorGreater ? ' > ' : isCombinatorTilde ? ' ~ ' : '';
+ String get _combinatorToString {
+ switch (combinator) {
+ case TokenKind.COMBINATOR_DEEP:
+ return ' /deep/ ';
+ case TokenKind.COMBINATOR_DESCENDANT:
+ return ' ';
+ case TokenKind.COMBINATOR_GREATER:
+ return ' > ';
+ case TokenKind.COMBINATOR_PLUS:
+ return ' + ';
+ case TokenKind.COMBINATOR_TILDE:
+ return ' ~ ';
+ default:
+ return '';
+ }
+ }
SimpleSelectorSequence clone() =>
new SimpleSelectorSequence(simpleSelector, span, combinator);
diff --git a/lib/src/tree_printer.dart b/lib/src/tree_printer.dart
index 97c6acc..94ca193 100644
--- a/lib/src/tree_printer.dart
+++ b/lib/src/tree_printer.dart
@@ -271,6 +271,8 @@
output.writeValue('combinator', ">");
} else if (node.isCombinatorTilde) {
output.writeValue('combinator', "~");
+ } else if (node.isCombinatorDeep) {
+ output.writeValue('combinator', '/deep/');
} else {
output.writeValue('combinator', "ERROR UNKNOWN");
}
diff --git a/test/selector_test.dart b/test/selector_test.dart
index 87fb60a..eb2bef8 100644
--- a/test/selector_test.dart
+++ b/test/selector_test.dart
@@ -58,6 +58,14 @@
selectorAst = selector(':host-context(.foo)', errors: errors..clear());
expect(errors.isEmpty, true, reason: errors.toString());
expect(compactOuptut(selectorAst), ':host-context(.foo)');
+
+ selectorAst = selector('.a /deep/ .b', errors: errors..clear());
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(compactOuptut(selectorAst), '.a /deep/ .b');
+
+ selectorAst = selector('.x >>> .y', errors: errors..clear());
+ expect(errors.isEmpty, true, reason: errors.toString());
+ expect(compactOuptut(selectorAst), '.x /deep/ .y');
}
// TODO(terry): Move this failure case to a failure_test.dart when the analyzer