private static BaseSelector GetPseudoSelector(Block token)
    {
      switch (((SymbolBlock)token).Value)
      {
        case PseudoSelectorPrefix.PseudoRoot:
          return new PseudoSelector(PseudoTypes.Root);

        case PseudoSelectorPrefix.PseudoFirstOfType:
          return new PseudoSelector(PseudoTypes.FirstOfType);

        case PseudoSelectorPrefix.PseudoLastoftype:
          return new PseudoSelector(PseudoTypes.Lastoftype);

        case PseudoSelectorPrefix.PseudoOnlychild:
          return new PseudoSelector(PseudoTypes.Onlychild);

        case PseudoSelectorPrefix.PseudoOnlyOfType:
          return new PseudoSelector(PseudoTypes.OnlyOfType);

        case PseudoSelectorPrefix.PseudoFirstchild:
          return new PseudoSelector(PseudoTypes.Firstchild);

        case PseudoSelectorPrefix.PseudoLastchild:
          return new PseudoSelector(PseudoTypes.Lastchild);

        case PseudoSelectorPrefix.PseudoEmpty:
          return new PseudoSelector(PseudoTypes.Empty);

        case PseudoSelectorPrefix.PseudoLink:
          return new PseudoSelector(PseudoTypes.Link);

        case PseudoSelectorPrefix.PseudoVisited:
          return new PseudoSelector(PseudoTypes.Visited);

        case PseudoSelectorPrefix.PseudoActive:
          return new PseudoSelector(PseudoTypes.Active);

        case PseudoSelectorPrefix.PseudoHover:
          return new PseudoSelector(PseudoTypes.Hover);

        case PseudoSelectorPrefix.PseudoFocus:
          return new PseudoSelector(PseudoTypes.Focus);

        case PseudoSelectorPrefix.PseudoTarget:
          return new PseudoSelector(PseudoTypes.Target);

        case PseudoSelectorPrefix.PseudoEnabled:
          return new PseudoSelector(PseudoTypes.Enabled);

        case PseudoSelectorPrefix.PseudoDisabled:
          return new PseudoSelector(PseudoTypes.Disabled);

        case PseudoSelectorPrefix.PseudoDefault:
          return new PseudoSelector(PseudoTypes.Default);

        case PseudoSelectorPrefix.PseudoChecked:
          return new PseudoSelector(PseudoTypes.Checked);

        case PseudoSelectorPrefix.PseudoIndeterminate:
          return new PseudoSelector(PseudoTypes.Indeterminate);

        case PseudoSelectorPrefix.PseudoUnchecked:
          return new PseudoSelector(PseudoTypes.Unchecked);

        case PseudoSelectorPrefix.PseudoValid:
          return new PseudoSelector(PseudoTypes.Valid);

        case PseudoSelectorPrefix.PseudoInvalid:
          return new PseudoSelector(PseudoTypes.Invalid);

        case PseudoSelectorPrefix.PseudoRequired:
          return new PseudoSelector(PseudoTypes.Required);

        case PseudoSelectorPrefix.PseudoReadonly:
          return new PseudoSelector(PseudoTypes.Readonly);

        case PseudoSelectorPrefix.PseudoReadwrite:
          return new PseudoSelector(PseudoTypes.Readwrite);

        case PseudoSelectorPrefix.PseudoInrange:
          return new PseudoSelector(PseudoTypes.Inrange);

        case PseudoSelectorPrefix.PseudoOutofrange:
          return new PseudoSelector(PseudoTypes.Outofrange);

        case PseudoSelectorPrefix.PseudoOptional:
          return new PseudoSelector(PseudoTypes.Optional);

        case PseudoSelectorPrefix.PseudoElementBefore:
          return new PseudoElementSelector(PseudoElements.Before);

        case PseudoSelectorPrefix.PseudoElementAfter:
          return new PseudoElementSelector(PseudoElements.After);

        case PseudoSelectorPrefix.PseudoElementFirstline:
          return new PseudoElementSelector(PseudoElements.Firstline);

        case PseudoSelectorPrefix.PseudoElementFirstletter:
          return new PseudoElementSelector(PseudoElements.Firstletter);

        case PseudoSelectorPrefix.PseudoElementSelection:
          return new PseudoElementSelector(PseudoElements.Selection);

        default:
          return new UnknownSelector(":" + token.ToString());
      }
    }
    private void ParseAttributeOperator(Block token)
    {
      if (token.GrammarSegment == GrammarSegment.Whitespace)
      {
        return;
      }

      _selectorOperation = SelectorOperation.AttributeValue;

      if (token.GrammarSegment == GrammarSegment.SquareBracketClose)
      {
        ParseAttributeEnd(token);
      }
      else if (token is MatchBlock || token.GrammarSegment == GrammarSegment.Delimiter)
      {
        _attributeOperator = token.ToString();
      }
      else
      {
        _selectorOperation = SelectorOperation.AttributeEnd;
      }
    }
    private void ParsePseudoClassFunction(Block token)
    {
      if (token.GrammarSegment == GrammarSegment.Whitespace)
      {
        return;
      }

      switch (_attributeName)
      {
        case PseudoSelectorPrefix.PseudoFunctionNthchild:
        case PseudoSelectorPrefix.PseudoFunctionNthlastchild:
        case PseudoSelectorPrefix.PseudoFunctionNthOfType:
        case PseudoSelectorPrefix.PseudoFunctionNthLastOfType:
          {
            switch (token.GrammarSegment)
            {
              case GrammarSegment.Ident:
              case GrammarSegment.Number:
              case GrammarSegment.Dimension:
                _attributeValue += token.ToString();
                return;

              case GrammarSegment.Delimiter:
                var chr = ((DelimiterBlock)token).Value;

                if (chr == Specification.PlusSign || chr == Specification.MinusSign)
                {
                  _attributeValue += chr;
                  return;
                }

                break;
            }

            break;
          }
        case PseudoSelectorPrefix.PseudoFunctionNot:
          {
            if (_nestedSelectorFactory == null)
            {
              _nestedSelectorFactory = new SelectorFactory();
            }

            if (token.GrammarSegment != GrammarSegment.ParenClose || _nestedSelectorFactory._selectorOperation != SelectorOperation.Data)
            {
              _nestedSelectorFactory.Apply(token);
              return;
            }

            break;
          }
        case PseudoSelectorPrefix.PseudoFunctionDir:
          {
            if (token.GrammarSegment == GrammarSegment.Ident)
            {
              _attributeValue = ((SymbolBlock)token).Value;
            }

            _selectorOperation = SelectorOperation.PseudoClassFunctionEnd;
            return;
          }
        case PseudoSelectorPrefix.PseudoFunctionLang:
          {
            if (token.GrammarSegment == GrammarSegment.Ident)
            {
              _attributeValue = ((SymbolBlock)token).Value;
            }

            _selectorOperation = SelectorOperation.PseudoClassFunctionEnd;
            return;
          }
        case PseudoSelectorPrefix.PseudoFunctionContains:
          {
            switch (token.GrammarSegment)
            {
              case GrammarSegment.String:
                _attributeValue = ((StringBlock)token).Value;
                break;

              case GrammarSegment.Ident:
                _attributeValue = ((SymbolBlock)token).Value;
                break;
            }

            _selectorOperation = SelectorOperation.PseudoClassFunctionEnd;
            return;
          }
      }

      PrasePseudoClassFunctionEnd(token);
    }
    private bool ParseMediaValue(Block token)
    {
      switch (token.GrammarSegment)
      {
        case GrammarSegment.CurlyBraceOpen:
        case GrammarSegment.Semicolon:
          {
            var container = CurrentRule as ISupportsMedia;

            if (container != null)
            {
              container.Media.AppendMedium(_mediaDefn);
            }

            if (CurrentRule is ImportRule)
            {
              return ParsePostInstruction(token);
            }

            SetParsingContext(ParsingContext.DataBlock);
            _mediaDefn = null;
            return token.GrammarSegment == GrammarSegment.CurlyBraceOpen;
          }
        case GrammarSegment.Comma:
          {
            var container = CurrentRule as ISupportsMedia;

            if (container != null)
            {
              container.Media.AppendMedium(_mediaDefn);
            }
            _mediaDefn = null;
            return true;
          }
        case GrammarSegment.Whitespace:
          {
            // Do Nothing
            return true;
          }
        default:
          {
            if (_mediaDefn == null) _mediaDefn = new MediaDefinition();
            switch (token.ToString())
            {
              case "only":
                _mediaDefn.Modifier = MediaTypeModifier.Only;
                break;
              case "not":
                _mediaDefn.Modifier = MediaTypeModifier.Not;
                break;
              case "screen":
                _mediaDefn.Type = MediaType.Screen;
                break;
              case "speech":
                _mediaDefn.Type = MediaType.Speech;
                break;
              case "print":
                _mediaDefn.Type = MediaType.Print;
                break;
              case "all":
                _mediaDefn.Type = MediaType.All;
                break;
              case "braille":
                _mediaDefn.Type = MediaType.Braille;
                break;
              case "embossed":
                _mediaDefn.Type = MediaType.Embossed;
                break;
              case "handheld":
                _mediaDefn.Type = MediaType.Handheld;
                break;
              case "projection":
                _mediaDefn.Type = MediaType.Projection;
                break;
              case "tty":
                _mediaDefn.Type = MediaType.Tty;
                break;
              case "tv":
                _mediaDefn.Type = MediaType.Tv;
                break;
              case "and":
                // do nothing
                break;
              case "(":
                _mediaProp = new MediaProperty();
                break;
              case ")":
                if (_mediaProp != null)
                {
                  var plain = _mediaProp as MediaPropertyPlain;
                  if (plain != null && _terms.Length == 1)
                  {
                    plain.Value = _terms[0];
                  }
                  else if (!string.IsNullOrEmpty(_compare1) && _terms.Length > 0)
                  {
                    var range = new MediaPropertyRange { Name = _mediaProp.Name };
                    if (_nameFirst)
                    {
                      if (_compare1.StartsWith("<"))
                      {
                        range.UpperBound = _terms[0];
                        range.UpperCompare = _compare1;
                      }
                      else
                      {
                        range.LowerBound = _terms[0];
                        range.LowerCompare = _compare1.Replace('>', '<');
                      }
                    }
                    else
                    {
                      if (_terms.Length == 1)
                      {
                        if (_compare1.StartsWith(">"))
                        {
                          range.UpperBound = _terms[0];
                          range.UpperCompare = _compare1.Replace('>', '<');
                        }
                        else
                        {
                          range.LowerBound = _terms[0];
                          range.LowerCompare = _compare1;
                        }
                      }
                      else
                      {
                        if (_compare1.StartsWith("<"))
                        {
                          range.LowerBound = _terms[0];
                          range.LowerCompare = _compare1;
                          range.UpperBound = _terms[1];
                          range.UpperCompare = _compare2;
                        }
                        else
                        {
                          range.UpperBound = _terms[0];
                          range.UpperCompare = _compare1.Replace('>', '<');
                          range.LowerBound = _terms[1];
                          range.LowerCompare = _compare2.Replace('>', '<');
                        } 
                      }
                    }
                    _mediaProp = range;
                  }
                  _mediaDefn.Properties.Add(_mediaProp);
                }
                _compare1 = null;
                _compare2 = null;
                _mediaProp = null;
                _terms = new TermList();
                break;
              case ":":
                if (_mediaProp != null) _mediaProp = new MediaPropertyPlain { Name = _mediaProp.Name };
                break;
              case "<":
              case ">":
                if (string.IsNullOrEmpty(_compare1))
                  _compare1 = token.ToString();
                else
                  _compare2 = token.ToString();
                break;
              case "=":
                if (string.IsNullOrEmpty(_compare1) || (string.IsNullOrEmpty(_compare2) && _compare1 != "="))
                  _compare1 = (_compare1 ?? "") + token.ToString();
                else
                  _compare2 = (_compare2 ?? "") + token.ToString();
                break;
              default:
                if (token.GrammarSegment == GrammarSegment.Ident && string.IsNullOrEmpty(_mediaProp.Name))
                {
                  _mediaProp.Name = token.ToString();
                  _nameFirst = string.IsNullOrEmpty(_compare1);
                }
                else
                {
                  ParseSingleValue(token);
                }
                break;
            }
            return true;
          }
      }
    }
    private bool ParsePageSelector(Block token)
    {
      if (token.GrammarSegment == GrammarSegment.Colon || token.GrammarSegment == GrammarSegment.Whitespace)
      {
        return true;
      }

      if (token.GrammarSegment == GrammarSegment.Ident)
      {
        CastRuleSet<PageRule>().Selector = ElementRestriction.LocalName(token.ToString());
        return true;
      }

      if (token.GrammarSegment == GrammarSegment.CurlyBraceOpen)
      {
        SetParsingContext(ParsingContext.InDeclaration);
        return true;
      }

      return false;
    }
    private bool ParseKeyframeText(Block token)
    {
      if (token.GrammarSegment == GrammarSegment.CurlyBraceOpen)
      {
        _frame = null;
        SetParsingContext(ParsingContext.InDeclaration);
        return true;
      }

      if (token.GrammarSegment == GrammarSegment.CurlyBracketClose)
      {
        ParseKeyframesData(token);
        return false;
      }

      if (token.GrammarSegment == GrammarSegment.Comma)
      {
        return true;
      }

      if (_frame == null)
      {
        _frame = new KeyframeRule();
        _frame.AddValue(token.ToString());

        CastRuleSet<KeyframesRule>().Declarations.Add(_frame);
        _activeRuleSets.Push(_frame);
      }
      else
      {
        _frame.AddValue(token.ToString());
      }

      return true;
    }
    private bool ParseHexValue(Block token)
    {
      switch (token.GrammarSegment)
      {
        case GrammarSegment.Number:
        case GrammarSegment.Dimension:
        case GrammarSegment.Ident:
          var rest = token.ToString();

          if (_buffer.Length + rest.Length <= 6)
          {
            _buffer.Append(rest);
            return true;
          }

          break;
      }

      ParseSingleValueHexColor(_buffer.ToString());
      SetParsingContext(ParsingContext.InSingleValue);
      return ParseSingleValue(token);
    }
    private bool ParseSingleValue(Block token)
    {
      switch (token.GrammarSegment)
      {
        case GrammarSegment.Dimension: // "3px"
          return AddTerm(new PrimitiveTerm(((UnitBlock)token).Unit, ((UnitBlock)token).Value));

        case GrammarSegment.Hash:// "#ffffff"
          return ParseSingleValueHexColor(((SymbolBlock)token).Value);

        case GrammarSegment.Delimiter: // "#"
          if (token.ToString() == ".")
          {
            _terms.AddSeparator(GrammarSegment.Delimiter);
            return true;
          }
          return ParseValueDelimiter((DelimiterBlock)token);

        case GrammarSegment.Ident: // "auto"
          return ParseSingleValueIdent((SymbolBlock)token);

        case GrammarSegment.String:// "'some value'"
          return AddTerm(new PrimitiveTerm(UnitType.String, ((StringBlock)token).Value));

        case GrammarSegment.Url:// "url('http://....')"
          return AddTerm(new PrimitiveTerm(UnitType.Uri, ((StringBlock)token).Value));

        case GrammarSegment.Percentage: // "10%"
          return AddTerm(new PrimitiveTerm(UnitType.Percentage, ((UnitBlock)token).Value));

        case GrammarSegment.Number: // "123"
          return AddTerm(new PrimitiveTerm(UnitType.Number, ((NumericBlock)token).Value));

        case GrammarSegment.Whitespace: // " "
          _terms.AddSeparator(GrammarSegment.Whitespace);
          SetParsingContext(ParsingContext.InValueList);
          return true;

        case GrammarSegment.Function: // rgba(...)
          _functionBuffers.Push(new FunctionBuffer(((SymbolBlock)token).Value));
          SetParsingContext(ParsingContext.InFunction);
          return true;

        case GrammarSegment.Comma: // ","
          _terms.AddSeparator(GrammarSegment.Comma);
          SetParsingContext(ParsingContext.InValuePool);
          return true;

        case GrammarSegment.Colon: // ":"
          _terms.AddSeparator(GrammarSegment.Colon);
          return true;

        case GrammarSegment.Semicolon: // ";"
        case GrammarSegment.CurlyBracketClose: // "}"
          return ParsePostValue(token);

        case GrammarSegment.ParenClose: // ")"
          SetParsingContext(ParsingContext.AfterValue);
          return true;

        default:
          return false;
      }
    }