private void OnPseudoClass(CssSelectorToken token)
        {
            _state = State.Data;
            _ready = true;

            if (token.Type == CssTokenType.Colon)
            {
                _state = State.PseudoElement;
                return;
            }
            else if (token.Type == CssTokenType.Function)
            {
                if (pseudoClassFunctions.TryGetValue(token.Data, out var creator))
                {
                    _state    = State.Function;
                    _function = creator.Invoke(this);
                    _ready    = false;
                    return;
                }
            }
            else if (token.Type == CssTokenType.Ident)
            {
                var sel = _pseudoClassSelector.Create(token.Data);

                if (sel != null)
                {
                    Insert(sel);
                    return;
                }
            }

            _valid = false;
        }
            private Boolean OnAfterInitialSign(CssSelectorToken token)
            {
                if (token.Type == CssTokenType.Number)
                {
                    return(OnOffset(token));
                }

                if (token.Type == CssTokenType.Dimension)
                {
                    var integral = token.Data.Remove(token.Data.Length - 1);
                    _valid = _valid && token.Data.EndsWith("n", StringComparison.OrdinalIgnoreCase) && Int32.TryParse(integral, NumberStyles.Integer, CultureInfo.InvariantCulture, out _step);
                    _step *= _sign;
                    _sign  = 1;
                    _state = ParseState.Offset;
                    return(false);
                }
                else if (token.Type == CssTokenType.Ident && token.Data.Isi("n"))
                {
                    _step  = _sign;
                    _sign  = 1;
                    _state = ParseState.Offset;
                    return(false);
                }
                else if (_state == ParseState.Initial && token.Type == CssTokenType.Ident && token.Data.Isi("-n"))
                {
                    _step  = -1;
                    _state = ParseState.Offset;
                    return(false);
                }

                _valid = false;
                return(token.Type == CssTokenType.RoundBracketClose);
            }
        private void OnAttributeOperator(CssSelectorToken token)
        {
            if (token.Type != CssTokenType.Whitespace)
            {
                if (token.Type == CssTokenType.SquareBracketClose)
                {
                    _state = State.AttributeValue;
                    OnAttributeEnd(token);
                }
                else if (token.Type == CssTokenType.Match || token.Type == CssTokenType.Delim)
                {
                    _state  = State.AttributeValue;
                    _attrOp = token.Data;

                    if (_attrOp == CombinatorSymbols.Pipe)
                    {
                        _attrNs   = _attrName;
                        _attrName = null;
                        _attrOp   = String.Empty;
                        _state    = State.Attribute;
                    }
                }
                else
                {
                    _state = State.AttributeEnd;
                    _valid = false;
                }
            }
        }
 private void OnAttribute(CssSelectorToken token)
 {
     if (token.Type != CssTokenType.Whitespace)
     {
         if (token.Type == CssTokenType.Ident || token.Type == CssTokenType.String)
         {
             _state    = State.AttributeOperator;
             _attrName = token.Data;
         }
         else if (token.Type == CssTokenType.Delim && token.Data.Is(CombinatorSymbols.Pipe))
         {
             _state  = State.Attribute;
             _attrNs = String.Empty;
         }
         else if (token.Type == CssTokenType.Delim && token.Data.Is("*"))
         {
             _state    = State.AttributeOperator;
             _attrName = "*";
         }
         else
         {
             _state = State.Data;
             _valid = false;
         }
     }
 }
            private Boolean OnInitial(CssSelectorToken token)
            {
                if (token.Type == CssTokenType.Whitespace)
                {
                    return(false);
                }

                if (token.Data.Isi(Keywords.Odd))
                {
                    _state  = ParseState.BeforeOf;
                    _step   = 2;
                    _offset = 1;
                    return(false);
                }
                else if (token.Data.Isi(Keywords.Even))
                {
                    _state  = ParseState.BeforeOf;
                    _step   = 2;
                    _offset = 0;
                    return(false);
                }
                else if (token.Type == CssTokenType.Delim && token.Data.IsOneOf("+", "-"))
                {
                    _sign  = token.Data == "-" ? -1 : +1;
                    _state = ParseState.AfterInitialSign;
                    return(false);
                }

                return(OnAfterInitialSign(token));
            }
            protected override Boolean OnToken(CssSelectorToken token)
            {
                if (token.Type != CssTokenType.RoundBracketClose || _selector._state != State.Data)
                {
                    _selector.Apply(token);
                    return(false);
                }

                return(true);
            }
            private Boolean OnAfter(CssSelectorToken token)
            {
                if (token.Type != CssTokenType.RoundBracketClose || _nested._state != State.Data)
                {
                    _nested.Apply(token);
                    return(false);
                }

                return(true);
            }
 private void OnAttributeValue(CssSelectorToken token)
 {
     if (token.Type != CssTokenType.Whitespace)
     {
         if (token.Type == CssTokenType.Ident || token.Type == CssTokenType.String || token.Type == CssTokenType.Number)
         {
             _state     = State.AttributeEnd;
             _attrValue = token.Data;
         }
         else
         {
             _state = State.Data;
             _valid = false;
         }
     }
 }
            private Boolean OnOffset(CssSelectorToken token)
            {
                if (token.Type == CssTokenType.Whitespace)
                {
                    return(false);
                }

                if (token.Type == CssTokenType.Number)
                {
                    _valid   = _valid && Int32.TryParse(token.Data, NumberStyles.Integer, CultureInfo.InvariantCulture, out _offset);
                    _offset *= _sign;
                    _state   = ParseState.BeforeOf;
                    return(false);
                }

                return(OnBeforeOf(token));
            }
            protected override Boolean OnToken(CssSelectorToken token)
            {
                if (token.Type == CssTokenType.Ident || token.Type == CssTokenType.String)
                {
                    _value = token.Data;
                }
                else if (token.Type == CssTokenType.RoundBracketClose)
                {
                    return(true);
                }
                else if (token.Type != CssTokenType.Whitespace)
                {
                    _valid = false;
                }

                return(false);
            }
        private void OnDelim(CssSelectorToken token)
        {
            switch (token.Data[0])
            {
            case Symbols.Comma:
                InsertOr();
                _ready = false;
                break;

            case Symbols.GreaterThan:
                Insert(CssCombinator.Child);
                _ready = false;
                break;

            case Symbols.Plus:
                Insert(CssCombinator.AdjacentSibling);
                _ready = false;
                break;

            case Symbols.Tilde:
                Insert(CssCombinator.Sibling);
                _ready = false;
                break;

            case Symbols.Asterisk:
                Insert(AllSelector.Instance);
                _ready = true;
                break;

            case Symbols.Pipe:
                if (_combinators.Count > 0 && _combinators.Peek() == CssCombinator.Descendent)
                {
                    Insert(new TypeSelector(String.Empty));
                }

                Insert(CssCombinator.Namespace);
                _ready = false;
                break;

            default:
                _valid = false;
                break;
            }
        }
        private void OnPseudoElement(CssSelectorToken token)
        {
            _state = State.Data;
            _ready = true;

            if (token.Type == CssTokenType.Ident)
            {
                var sel = _pseudoElementSelector.Create(token.Data);

                if (sel != null)
                {
                    _valid = _valid && !_nested;
                    Insert(sel);
                    return;
                }
            }

            _valid = false;
        }
        private void Apply(CssSelectorToken token)
        {
            _invoked = true;

            switch (_state)
            {
            case State.Data:
                OnData(token);
                break;

            case State.Attribute:
                OnAttribute(token);
                break;

            case State.AttributeOperator:
                OnAttributeOperator(token);
                break;

            case State.AttributeValue:
                OnAttributeValue(token);
                break;

            case State.AttributeEnd:
                OnAttributeEnd(token);
                break;

            case State.PseudoClass:
                OnPseudoClass(token);
                break;

            case State.PseudoElement:
                OnPseudoElement(token);
                break;

            case State.Function:
                OnFunctionState(token);
                break;

            default:
                _valid = false;
                break;
            }
        }
            protected override Boolean OnToken(CssSelectorToken token)
            {
                if (token.Type != CssTokenType.RoundBracketClose || _nested._state != State.Data)
                {
                    if (_firstToken && token.Type == CssTokenType.Delim)
                    {
                        // Roughly equivalent to inserting an implicit :scope
                        _nested.Insert(ScopePseudoClassSelector.Instance);
                        _nested.Apply(CssSelectorToken.Whitespace);
                        _matchSiblings = true;
                    }

                    _firstToken = false;
                    _nested.Apply(token);
                    return(false);
                }

                return(true);
            }
            protected override Boolean OnToken(CssSelectorToken token)
            {
                switch (_state)
                {
                case ParseState.Initial:
                    return(OnInitial(token));

                case ParseState.AfterInitialSign:
                    return(OnAfterInitialSign(token));

                case ParseState.Offset:
                    return(OnOffset(token));

                case ParseState.BeforeOf:
                    return(OnBeforeOf(token));

                default:
                    return(OnAfter(token));
                }
            }
            private Boolean OnBeforeOf(CssSelectorToken token)
            {
                if (token.Type == CssTokenType.Whitespace)
                {
                    return(false);
                }

                if (token.Data.Isi(Keywords.Of))
                {
                    _valid  = _allowOf;
                    _state  = ParseState.AfterOf;
                    _nested = _parent.CreateChild();
                    return(false);
                }
                else if (token.Type == CssTokenType.RoundBracketClose)
                {
                    return(true);
                }

                _valid = false;
                return(false);
            }
        private void OnAttributeEnd(CssSelectorToken token)
        {
            if (!_attrInsensitive && token.Type == CssTokenType.Ident && token.Data == "i")
            {
                _attrInsensitive = true;
            }
            else if (token.Type != CssTokenType.Whitespace)
            {
                _state = State.Data;
                _ready = true;

                if (token.Type == CssTokenType.SquareBracketClose)
                {
                    var selector = _attributeSelector.Create(_attrOp, _attrName, _attrValue, _attrNs, _attrInsensitive);
                    _attrInsensitive = false;
                    Insert(selector);
                }
                else
                {
                    _valid = false;
                }
            }
        }
        private void OnFunctionState(CssSelectorToken token)
        {
            if (_function.Finished(token))
            {
                var sel = _function.Produce();

                if (_nested && _function is NotFunctionState)
                {
                    sel = null;
                }

                _function = null;
                _state    = State.Data;
                _ready    = true;

                if (sel != null)
                {
                    Insert(sel);
                    return;
                }

                _valid = false;
            }
        }
 protected abstract Boolean OnToken(CssSelectorToken token);
 public Boolean Finished(CssSelectorToken token)
 {
     return(OnToken(token));
 }
        private void OnData(CssSelectorToken token)
        {
            switch (token.Type)
            {
            //Begin of attribute [A]
            case CssTokenType.SquareBracketOpen:
                _attrName  = null;
                _attrValue = null;
                _attrOp    = String.Empty;
                _attrNs    = null;
                _state     = State.Attribute;
                _ready     = false;
                break;

            //Begin of Pseudo :P
            case CssTokenType.Colon:
                _state = State.PseudoClass;
                _ready = false;
                break;

            //Begin of ID #I
            case CssTokenType.Hash:
                Insert(new IdSelector(token.Data));
                _ready = true;
                break;

            //Begin of Class .c
            case CssTokenType.Class:
                Insert(new ClassSelector(token.Data));
                _ready = true;
                break;

            //Begin of Type E
            case CssTokenType.Ident:
                Insert(new TypeSelector(token.Data));
                _ready = true;
                break;

            //Whitespace could be significant
            case CssTokenType.Whitespace:
                Insert(CssCombinator.Descendent);
                break;

            //Various
            case CssTokenType.Delim:
                OnDelim(token);
                break;

            case CssTokenType.Comma:
                InsertOr();
                _ready = false;
                break;

            case CssTokenType.Column:
                Insert(CssCombinator.Column);
                _ready = false;
                break;

            case CssTokenType.Descendent:
                Insert(CssCombinator.Descendent);
                _ready = false;
                break;

            case CssTokenType.Deep:
                Insert(CssCombinator.Deep);
                _ready = false;
                break;

            default:
                _valid = false;
                break;
            }
        }