Merge branch 'master' into support-ident-ie-filter
diff --git a/example/call_parser.dart b/example/call_parser.dart
index c77cf03..9a993ea 100644
--- a/example/call_parser.dart
+++ b/example/call_parser.dart
@@ -2,7 +2,6 @@
 // for details. All rights reserved. Use of this source code is governed by a
 
 import 'package:csslib/parser.dart' as css;
-import 'package:csslib/src/messages.dart';
 import 'package:csslib/visitor.dart';
 
 const _default = const css.PreprocessorOptions(
@@ -17,7 +16,7 @@
  * tests (by default) will ensure that the CSS is really valid.
  */
 StyleSheet parseCss(String cssInput,
-    {List<Message> errors, css.PreprocessorOptions opts}) {
+    {List<css.Message> errors, css.PreprocessorOptions opts}) {
   return css.parse(cssInput,
       errors: errors, options: opts == null ? _default : opts);
 }
@@ -28,7 +27,7 @@
     (emitCss..visitTree(ss, pretty: true)).toString();
 
 main() {
-  var errors = <Message>[];
+  var errors = <css.Message>[];
 
   // Parse a simple stylesheet.
   print('1. Good CSS, parsed CSS emitted:');
diff --git a/lib/css.dart b/lib/css.dart
index a6539cf..c417354 100644
--- a/lib/css.dart
+++ b/lib/css.dart
@@ -10,9 +10,8 @@
 import 'package:source_span/source_span.dart';
 
 import 'parser.dart';
+import 'src/messages.dart' show Messages;
 import 'visitor.dart';
-import 'src/messages.dart';
-import 'src/options.dart';
 
 void main(List<String> arguments) {
   // TODO(jmesserly): fix this to return a proper exit code
diff --git a/lib/parser.dart b/lib/parser.dart
index 7dfe184..6b05c85 100644
--- a/lib/parser.dart
+++ b/lib/parser.dart
@@ -8,10 +8,11 @@
 
 import 'package:source_span/source_span.dart';
 
-import "visitor.dart";
+import 'visitor.dart';
 import 'src/messages.dart';
 import 'src/options.dart';
 
+export 'src/messages.dart' show Message;
 export 'src/options.dart';
 
 part 'src/analyzer.dart';
@@ -1218,6 +1219,20 @@
     return new Selector(simpleSequences, _makeSpan(start));
   }
 
+  /// Same as [processSelector] but reports an error for each combinator.
+  ///
+  /// This is a quick fix for parsing <compound-selectors> until the parser
+  /// supports Selector Level 4 grammar:
+  /// https://drafts.csswg.org/selectors-4/#typedef-compound-selector
+  Selector processCompoundSelector() {
+    return processSelector()
+      ..simpleSelectorSequences.forEach((sequence) {
+        if (!sequence.isCombinatorNone) {
+          _error('compound selector can not contain combinator', sequence.span);
+        }
+      });
+  }
+
   simpleSelectorSequence(bool forceCombinatorNone) {
     var start = _peekToken.span;
     var combinatorType = TokenKind.COMBINATOR_NONE;
@@ -1428,7 +1443,8 @@
     // Functional pseudo?
 
     if (_peekToken.kind == TokenKind.LPAREN) {
-      if (!pseudoElement && pseudoName.name.toLowerCase() == 'not') {
+      var name = pseudoName.name.toLowerCase();
+      if (!pseudoElement && name == 'not') {
         _eat(TokenKind.LPAREN);
 
         // Negation :   ':NOT(' S* negation_arg S* ')'
@@ -1436,6 +1452,12 @@
 
         _eat(TokenKind.RPAREN);
         return new NegationSelector(negArg, _makeSpan(start));
+      } else if (!pseudoElement && (name == 'host' || name == 'host-context')) {
+        _eat(TokenKind.LPAREN);
+        var selector = processCompoundSelector();
+        _eat(TokenKind.RPAREN);
+        var span = _makeSpan(start);
+        return new PseudoClassFunctionSelector(pseudoName, selector, span);
       } else {
         // Special parsing for expressions in pseudo functions.  Minus is used
         // as operator not identifier.
diff --git a/lib/src/css_printer.dart b/lib/src/css_printer.dart
index a62ca47..d3b62d0 100644
--- a/lib/src/css_printer.dart
+++ b/lib/src/css_printer.dart
@@ -107,16 +107,14 @@
       emit(node._ident);
       emit(node.hasPseudoPage ? ':${node._pseudoPage}' : '');
     }
-    emit(' ');
 
     var declsMargin = node._declsMargin;
     var declsMarginLength = declsMargin.length;
+    emit(' {$_newLine');
     for (var i = 0; i < declsMarginLength; i++) {
-      if (i > 0) emit(_newLine);
-      emit('{$_newLine');
       declsMargin[i].visit(this);
-      emit('}');
     }
+    emit('}');
   }
 
   /** @charset "charset encoding" */
@@ -326,7 +324,7 @@
 
   void visitPseudoClassFunctionSelector(PseudoClassFunctionSelector node) {
     emit(":${node.name}(");
-    node.expression.visit(this);
+    node.argument.visit(this);
     emit(')');
   }
 
diff --git a/lib/src/tree.dart b/lib/src/tree.dart
index a6a64fc..63c7301 100644
--- a/lib/src/tree.dart
+++ b/lib/src/tree.dart
@@ -291,15 +291,19 @@
   String toString() => "::$name";
 }
 
-// :pseudoClassFunction(expression)
+// :pseudoClassFunction(argument)
 class PseudoClassFunctionSelector extends PseudoClassSelector {
-  final SelectorExpression expression;
+  final TreeNode _argument; // Selector, SelectorExpression
 
-  PseudoClassFunctionSelector(Identifier name, this.expression, SourceSpan span)
+  PseudoClassFunctionSelector(Identifier name, this._argument, SourceSpan span)
       : super(name, span);
 
   PseudoClassFunctionSelector clone() =>
-      new PseudoClassFunctionSelector(_name, expression, span);
+      new PseudoClassFunctionSelector(_name, _argument, span);
+
+  TreeNode get argument => _argument;
+  Selector get selector => _argument as Selector;
+  SelectorExpression get expression => _argument as SelectorExpression;
 
   visit(VisitorBase visitor) => visitor.visitPseudoClassFunctionSelector(this);
 }
diff --git a/lib/src/tree_printer.dart b/lib/src/tree_printer.dart
index 9b0a6c2..97c6acc 100644
--- a/lib/src/tree_printer.dart
+++ b/lib/src/tree_printer.dart
@@ -338,7 +338,7 @@
   void visitPseudoClassFunctionSelector(PseudoClassFunctionSelector node) {
     heading('Pseudo Class Function Selector', node);
     output.depth++;
-    visitSelectorExpression(node.expression);
+    node.argument.visit(this);
     super.visitPseudoClassFunctionSelector(node);
     output.depth--;
   }
diff --git a/pubspec.yaml b/pubspec.yaml
index f1cac20..8ed29b6 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: csslib
-version: 0.13.3
+version: 0.13.6
 author: Dart Team <misc@dartlang.org>
 description: A library for parsing CSS.
 homepage: https://github.com/dart-lang/csslib
diff --git a/test/declaration_test.dart b/test/declaration_test.dart
index c92d68a..007916d 100644
--- a/test/declaration_test.dart
+++ b/test/declaration_test.dart
@@ -287,6 +287,7 @@
   width: 10px;
 }
 @page bar : left { @top-left { margin: 8px; } }
+@page { @top-left { margin: 8px; } width: 10px; }
 @charset "ISO-8859-1";
 @charset 'ASCII';''';
 
@@ -308,6 +309,12 @@
   margin: 8px;
 }
 }
+@page {
+@top-left {
+  margin: 8px;
+}
+  width: 10px;
+}
 @charset "ISO-8859-1";
 @charset "ASCII";''';
 
diff --git a/test/selector_test.dart b/test/selector_test.dart
index dff4415..87fb60a 100644
--- a/test/selector_test.dart
+++ b/test/selector_test.dart
@@ -46,6 +46,18 @@
   selectorAst = selector('#_privateId', errors: errors..clear());
   expect(errors.isEmpty, true, reason: errors.toString());
   expect('#_privateId', compactOuptut(selectorAst));
+
+  selectorAst = selector(':host', errors: errors..clear());
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(compactOuptut(selectorAst), ':host');
+
+  selectorAst = selector(':host(.foo)', errors: errors..clear());
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(compactOuptut(selectorAst), ':host(.foo)');
+
+  selectorAst = selector(':host-context(.foo)', errors: errors..clear());
+  expect(errors.isEmpty, true, reason: errors.toString());
+  expect(compactOuptut(selectorAst), ':host-context(.foo)');
 }
 
 // TODO(terry): Move this failure case to a failure_test.dart when the analyzer