ICondition ExtractCondition(ref CssToken token)
        {
            var condition = default(ICondition);

            if (token.Type == CssTokenType.RoundBracketOpen)
            {
                token = _tokenizer.Get();
                condition = CreateCondition(ref token);

                if (condition != null)
                    condition = new GroupCondition(condition);
                else if (token.Type == CssTokenType.Ident)
                    condition = DeclarationCondition(ref token);

                if (token.Type == CssTokenType.RoundBracketClose)
                    token = _tokenizer.Get();
            }
            else if (token.Data.Equals(Keywords.Not, StringComparison.OrdinalIgnoreCase))
            {
                token = _tokenizer.Get();
                condition = ExtractCondition(ref token);

                if (condition != null)
                    condition = new NotCondition(condition);
            }

            return condition;
        }
 static CssMatchToken()
 {
     include = new CssMatchToken { _type = CssTokenType.IncludeMatch };
     dash = new CssMatchToken { _type = CssTokenType.DashMatch };
     prefix = new CssMatchToken { _type = CssTokenType.PrefixMatch };
     substring = new CssMatchToken { _type = CssTokenType.SubstringMatch };
     suffix = new CssMatchToken { _type = CssTokenType.SuffixMatch };
     not = new CssMatchToken { _type = CssTokenType.NotMatch };
 }
        public override CssRule Create(CssToken current)
        {
            var token = _tokenizer.Get();
            var rule = new CssFontFaceRule(_parser);

            if (token.Type != CssTokenType.CurlyBracketOpen)
                return SkipDeclarations(token);

            FillFontFaceDeclarations(rule);
            return rule;
        }
        public override CssRule Create(CssToken current)
        {
            var token = _tokenizer.Get();
            var rule = new CssSupportsRule(_parser);
            rule.Condition = CreateCondition(ref token);

            if (token.Type != CssTokenType.CurlyBracketOpen)
                return SkipDeclarations(token);

            FillRules(rule);
            return rule;
        }
        public override CssRule Create(CssToken current)
        {
            var token = _tokenizer.Get();
            var rule = new CssDocumentRule(_parser);
            var functions = CreateFunctions(ref token);
            rule.Conditions.AddRange(functions);

            if (token.Type != CssTokenType.CurlyBracketOpen)
                return SkipDeclarations(token);

            FillRules(rule);
            return rule;
        }
        /// <summary>
        /// Called when the document functions have to been found.
        /// </summary>
        public List<IDocumentFunction> CreateFunctions(ref CssToken token)
        {
            var list = new List<IDocumentFunction>();

            do
            {
                var function = token.ToDocumentFunction();

                if (function == null)
                    break;

                list.Add(function);
                token = _tokenizer.Get();
            }
            while (token.Type == CssTokenType.Comma);

            return list;
        }
        ICondition DeclarationCondition(ref CssToken token)
        {
            var name = token.Data;
            var property = Factory.Properties.Create(name);

            if (property == null)
                property = new CssUnknownProperty(name);

            token = _tokenizer.Get();

            if (token.Type == CssTokenType.Colon)
            {
                var important = false;
                var result = CreateValue(ref token, out important);
                property.IsImportant = important;

                if (result != null)
                    return new DeclarationCondition(property, result);
            }

            return null;
        }
        /// <summary>
        /// Called before any token in the value regime had been seen.
        /// </summary>
        public ICondition CreateCondition(ref CssToken token)
        {
            var condition = ExtractCondition(ref token);

            if (condition != null)
            {
                if (token.Data.Equals(Keywords.And, StringComparison.OrdinalIgnoreCase))
                {
                    token = _tokenizer.Get();
                    var conditions = MultipleConditions(condition, Keywords.And, ref token);
                    return new AndCondition(conditions);
                }
                else if (token.Data.Equals(Keywords.Or, StringComparison.OrdinalIgnoreCase))
                {
                    token = _tokenizer.Get();
                    var conditions = MultipleConditions(condition, Keywords.Or, ref token);
                    return new OrCondition(conditions);
                }
            }

            return condition;
        }
        List<ICondition> MultipleConditions(ICondition condition, String connector, ref CssToken token)
        {
            var list = new List<ICondition>();
            list.Add(condition);

            while (token.Type != CssTokenType.Eof)
            {
                condition = ExtractCondition(ref token);

                if (condition == null)
                    break;

                list.Add(condition);

                if (!token.Data.Equals(connector, StringComparison.OrdinalIgnoreCase))
                    break;

                token = _tokenizer.Get();
            }

            return list;
        }
        /// <summary>
        /// 4.4.1. Data state
        /// </summary>
        CssToken Data(Char current)
        {
            switch (current)
            {
            case Specification.LF:
            case Specification.CR:
            case Specification.TAB:
            case Specification.SPACE:
                do
                {
                    current = src.Next;
                }while (Specification.IsSpaceCharacter(current));
                src.Back();
                return(CssSpecialCharacter.Whitespace);

            case Specification.DQ:
                return(StringDQ(src.Next));

            case Specification.NUM:
                return(HashStart(src.Next));

            case Specification.DOLLAR:
                current = src.Next;

                if (current == Specification.EQ)
                {
                    return(CssMatchToken.Suffix);
                }

                return(CssToken.Delim(src.Previous));

            case Specification.SQ:
                return(StringSQ(src.Next));

            case '(':
                return(CssBracketToken.OpenRound);

            case ')':
                return(CssBracketToken.CloseRound);

            case Specification.ASTERISK:
                current = src.Next;

                if (current == Specification.EQ)
                {
                    return(CssMatchToken.Substring);
                }

                return(CssToken.Delim(src.Previous));

            case Specification.PLUS:
            {
                var c1 = src.Next;

                if (c1 == Specification.EOF)
                {
                    src.Back();
                }
                else
                {
                    var c2 = src.Next;
                    src.Back(2);

                    if (Specification.IsDigit(c1) || (c1 == Specification.FS && Specification.IsDigit(c2)))
                    {
                        return(NumberStart(current));
                    }
                }

                return(CssToken.Delim(current));
            }

            case Specification.COMMA:
                return(CssSpecialCharacter.Comma);

            case Specification.FS:
            {
                var c = src.Next;

                if (Specification.IsDigit(c))
                {
                    return(NumberStart(src.Previous));
                }

                return(CssToken.Delim(src.Previous));
            }

            case Specification.DASH:
            {
                var c1 = src.Next;

                if (c1 == Specification.EOF)
                {
                    src.Back();
                }
                else
                {
                    var c2 = src.Next;
                    src.Back(2);

                    if (Specification.IsDigit(c1) || (c1 == Specification.FS && Specification.IsDigit(c2)))
                    {
                        return(NumberStart(current));
                    }
                    else if (Specification.IsNameStart(c1))
                    {
                        return(IdentStart(current));
                    }
                    else if (c1 == Specification.RSOLIDUS && !Specification.IsLineBreak(c2) && c2 != Specification.EOF)
                    {
                        return(IdentStart(current));
                    }
                    else if (c1 == Specification.DASH && c2 == Specification.GT)
                    {
                        src.Advance(2);
                        return(CssCommentToken.Close);
                    }
                }

                return(CssToken.Delim(current));
            }

            case Specification.SOLIDUS:
                current = src.Next;

                if (current == Specification.ASTERISK)
                {
                    return(Comment(src.Next));
                }

                return(CssToken.Delim(src.Previous));

            case Specification.RSOLIDUS:
                current = src.Next;

                if (Specification.IsLineBreak(current) || current == Specification.EOF)
                {
                    RaiseErrorOccurred(current == Specification.EOF ? ErrorCode.EOF : ErrorCode.LineBreakUnexpected);
                    return(CssToken.Delim(src.Previous));
                }

                return(IdentStart(src.Previous));

            case Specification.COL:
                return(CssSpecialCharacter.Colon);

            case Specification.SC:
                return(CssSpecialCharacter.Semicolon);

            case Specification.LT:
                current = src.Next;

                if (current == Specification.EM)
                {
                    current = src.Next;

                    if (current == Specification.DASH)
                    {
                        current = src.Next;

                        if (current == Specification.DASH)
                        {
                            return(CssCommentToken.Open);
                        }

                        current = src.Previous;
                    }

                    current = src.Previous;
                }

                return(CssToken.Delim(src.Previous));

            case Specification.AT:
                return(AtKeywordStart(src.Next));

            case '[':
                return(CssBracketToken.OpenSquare);

            case ']':
                return(CssBracketToken.CloseSquare);

            case Specification.CA:
                current = src.Next;

                if (current == Specification.EQ)
                {
                    return(CssMatchToken.Prefix);
                }

                return(CssToken.Delim(src.Previous));

            case '{':
                return(CssBracketToken.OpenCurly);

            case '}':
                return(CssBracketToken.CloseCurly);

            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                return(NumberStart(current));

            case 'U':
            case 'u':
                current = src.Next;

                if (current == Specification.PLUS)
                {
                    current = src.Next;

                    if (Specification.IsHex(current) || current == Specification.QM)
                    {
                        return(UnicodeRange(current));
                    }

                    current = src.Previous;
                }

                return(IdentStart(src.Previous));

            case Specification.PIPE:
                current = src.Next;

                if (current == Specification.EQ)
                {
                    return(CssMatchToken.Dash);
                }
                else if (current == Specification.PIPE)
                {
                    return(CssToken.Column);
                }

                return(CssToken.Delim(src.Previous));

            case Specification.TILDE:
                current = src.Next;

                if (current == Specification.EQ)
                {
                    return(CssMatchToken.Include);
                }

                return(CssToken.Delim(src.Previous));

            case Specification.EOF:
                return(null);

            case Specification.EM:
                current = src.Next;

                if (current == Specification.EQ)
                {
                    return(CssMatchToken.Not);
                }

                return(CssToken.Delim(src.Previous));

            default:
                if (Specification.IsNameStart(current))
                {
                    return(IdentStart(current));
                }

                return(CssToken.Delim(current));
            }
        }
        /// <summary>
        /// 4.4.23. Unicode-range State
        /// </summary>
        CssToken UnicodeRange(Char current)
        {
            for (int i = 0; i < 6; i++)
            {
                if (!Specification.IsHex(current))
                {
                    break;
                }

                stringBuffer.Append(current);
                current = src.Next;
            }

            if (stringBuffer.Length != 6)
            {
                for (int i = 0; i < 6 - stringBuffer.Length; i++)
                {
                    if (current != Specification.QM)
                    {
                        current = src.Previous;
                        break;
                    }

                    stringBuffer.Append(current);
                    current = src.Next;
                }

                var range = FlushBuffer();
                var start = range.Replace(Specification.QM, '0');
                var end   = range.Replace(Specification.QM, 'F');
                return(CssToken.Range(start, end));
            }
            else if (current == Specification.DASH)
            {
                current = src.Next;

                if (Specification.IsHex(current))
                {
                    var start = stringBuffer.ToString();
                    stringBuffer.Clear();

                    for (int i = 0; i < 6; i++)
                    {
                        if (!Specification.IsHex(current))
                        {
                            current = src.Previous;
                            break;
                        }

                        stringBuffer.Append(current);
                        current = src.Next;
                    }

                    var end = FlushBuffer();
                    return(CssToken.Range(start, end));
                }
                else
                {
                    src.Back(2);
                    return(CssToken.Range(FlushBuffer(), null));
                }
            }
            else
            {
                src.Back();
                return(CssToken.Range(FlushBuffer(), null));
            }
        }