private static String Start(StringSource source, Char current, StringBuilder buffer)
        {
            if (current == Symbols.Minus)
            {
                current = source.Next();

                if (current.IsNameStart() || source.IsValidEscape())
                {
                    buffer.Append(Symbols.Minus);
                    return(Rest(source, current, buffer));
                }

                source.Back();
            }
            else if (current.IsNameStart())
            {
                buffer.Append(current);
                return(Rest(source, source.Next(), buffer));
            }
            else if (current == Symbols.ReverseSolidus && source.IsValidEscape())
            {
                buffer.Append(source.ConsumeEscape());
                return(Rest(source, source.Next(), buffer));
            }

            buffer.ToPool();
            return(null);
        }
Beispiel #2
0
        private static Unit NumberExponential(StringSource source, StringBuilder buffer)
        {
            var letter  = source.Current;
            var current = source.Next();

            if (current.IsDigit())
            {
                buffer.Append(letter).Append(current);
                return(SciNotation(source, buffer));
            }
            else if (current == Symbols.Plus || current == Symbols.Minus)
            {
                var op = current;
                current = source.Next();

                if (current.IsDigit())
                {
                    buffer.Append(letter).Append(op).Append(current);
                    return(SciNotation(source, buffer));
                }

                source.Back();
            }

            var number = buffer.ToString();

            return(Dimension(source, number, buffer.Clear().Append(letter)));
        }
Beispiel #3
0
        internal static IEnumerable <IfHeaderCondition> Parse([NotNull] StringSource source, [NotNull] EntityTagComparer entityTagComparer)
        {
            while (!source.SkipWhiteSpace())
            {
                var       isNot = false;
                EntityTag?etag  = null;
                if (source.AdvanceIf("Not", StringComparison.OrdinalIgnoreCase))
                {
                    isNot = true;
                    source.SkipWhiteSpace();
                }

                Uri stateToken;
                if (CodedUrlParser.TryParse(source, out stateToken))
                {
                    // Coded-URL found
                }
                else if (source.Get() == '[')
                {
                    // Entity-tag found
                    etag = EntityTag.Parse(source).Single();
                    if (!source.AdvanceIf("]"))
                    {
                        throw new ArgumentException($"{source.Remaining} is not a valid condition (ETag not ending with ']')", nameof(source));
                    }
                }
                else
                {
                    source.Back();
                    break;
                }

                yield return(new IfHeaderCondition(isNot, stateToken, etag, entityTagComparer));
            }
        }
        private static UrlReference DoubleQuoted(StringSource source)
        {
            var buffer = StringBuilderPool.Obtain();

            while (true)
            {
                var current = source.Next();

                if (current.IsLineBreak())
                {
                    return(Bad(source, buffer));
                }
                else if (Symbols.EndOfFile == current)
                {
                    return(new UrlReference(buffer.ToPool()));
                }
                else if (current == Symbols.DoubleQuote)
                {
                    return(End(source, buffer));
                }
                else if (current != Symbols.ReverseSolidus)
                {
                    buffer.Append(current);
                }
                else
                {
                    current = source.Next();

                    if (current == Symbols.EndOfFile)
                    {
                        source.Back();
                        return(new UrlReference(buffer.ToPool()));
                    }
                    else if (current.IsLineBreak())
                    {
                        buffer.AppendLine();
                    }
                    else
                    {
                        source.Back();
                        buffer.Append(source.ConsumeEscape());
                    }
                }
            }
        }
Beispiel #5
0
        public static Char BackTo(this StringSource source, Int32 index)
        {
            var diff    = source.Index - index;
            var current = Symbols.Null;

            while (diff > 0)
            {
                current = source.Back();
                diff--;
            }

            return(current);
        }
Beispiel #6
0
        private static Unit NumberDash(StringSource source, StringBuilder buffer)
        {
            var current = source.Next();

            if (current.IsNameStart() || source.IsValidEscape())
            {
                var number = buffer.ToString();
                return(Dimension(source, number, buffer.Clear().Append(Symbols.Minus)));
            }
            else
            {
                source.Back();
                return(new Unit(buffer.ToPool(), String.Empty));
            }
        }
        private static String SingleQuoted(StringSource source)
        {
            var buffer = StringBuilderPool.Obtain();

            while (true)
            {
                var current = source.Next();

                switch (current)
                {
                case Symbols.SingleQuote:
                case Symbols.EndOfFile:
                    source.Next();
                    return(buffer.ToPool());

                case Symbols.FormFeed:
                case Symbols.LineFeed:
                    buffer.ToPool();
                    return(null);

                case Symbols.ReverseSolidus:
                    current = source.Next();

                    if (current.IsLineBreak())
                    {
                        buffer.AppendLine();
                    }
                    else if (current != Symbols.EndOfFile)
                    {
                        source.Back();
                        buffer.Append(source.ConsumeEscape());
                    }
                    else
                    {
                        return(buffer.ToPool());
                    }

                    break;

                default:
                    buffer.Append(current);
                    break;
                }
            }
        }
        /// <summary>
        /// Consumes the escape sequence if any. Assumes, the source currently being at a
        /// solidus (valid escape).
        /// </summary>
        public static String ConsumeEscape(this StringSource source)
        {
            var current = source.Next();

            if (current.IsHex())
            {
                var isHex  = true;
                var escape = new Char[6];
                var length = 0;

                while (isHex && length < escape.Length)
                {
                    escape[length++] = current;
                    current          = source.Next();
                    isHex            = current.IsHex();
                }

                if (!current.IsSpaceCharacter())
                {
                    source.Back();
                }

                var code = 0;
                var pwr  = 1;

                for (var i = length - 1; i >= 0; i--)
                {
                    code += escape[i].FromHex() * pwr;
                    pwr  *= 16;
                }

                if (!code.IsInvalid())
                {
                    return(Char.ConvertFromUtf32(code));
                }

                current = Symbols.Replacement;
            }

            return(current.ToString());
        }
Beispiel #9
0
        /// <summary>
        /// 4.4.1. Data state
        /// </summary>
        private CssSelectorToken Data(Char current)
        {
            switch (current)
            {
            case Symbols.FormFeed:
            case Symbols.LineFeed:
            case Symbols.CarriageReturn:
            case Symbols.Tab:
            case Symbols.Space:
                _source.SkipSpaces();
                return(new CssSelectorToken(CssTokenType.Whitespace, " "));

            case Symbols.Num:
                return(HashStart());

            case Symbols.Dot:
                current = _source.Next();

                if (current.IsDigit())
                {
                    return(NumberStart(_source.Back()));
                }
                else
                {
                    var token = Data(current);

                    if (token.Type == CssTokenType.Ident)
                    {
                        return(new CssSelectorToken(CssTokenType.Class, token.Data));
                    }
                }

                return(NewInvalid());

            case Symbols.Asterisk:
                current = _source.Next();

                if (current == Symbols.Equality)
                {
                    _source.Next();
                    return(NewMatch(CombinatorSymbols.InText));
                }

                return(NewDelimiter(Symbols.Asterisk));

            case Symbols.Comma:
                _source.Next();
                return(new CssSelectorToken(CssTokenType.Comma, ","));

            case Symbols.GreaterThan:
                current = _source.Next();

                if (current == Symbols.GreaterThan)
                {
                    current = _source.Next();

                    if (current == Symbols.GreaterThan)
                    {
                        _source.Next();
                        return(new CssSelectorToken(CssTokenType.Deep, ">>>"));
                    }

                    return(new CssSelectorToken(CssTokenType.Descendent, ">>"));
                }

                return(NewDelimiter(Symbols.GreaterThan));

            case Symbols.Minus:
            {
                var c1 = _source.Next();

                if (c1 != Symbols.EndOfFile)
                {
                    var c2 = _source.Next();
                    _source.Back(2);

                    if (c1.IsDigit() || (c1 == Symbols.Dot && c2.IsDigit()))
                    {
                        return(NumberStart(current));
                    }
                    else if (c1.IsNameStart())
                    {
                        return(IdentStart(current));
                    }
                    else if (c1 == Symbols.ReverseSolidus && !c2.IsLineBreak() && c2 != Symbols.EndOfFile)
                    {
                        return(IdentStart(current));
                    }
                    else if (c1 == Symbols.Minus && c2 == Symbols.GreaterThan)
                    {
                        _source.Next(2);
                        return(NewInvalid());
                    }

                    _source.Next();
                }

                return(NewDelimiter(Symbols.Minus));
            }

            case Symbols.Plus:
            {
                var c1 = _source.Next();

                if (c1 != Symbols.EndOfFile)
                {
                    var c2 = _source.Next();
                    _source.Back();

                    if (c1.IsDigit() || (c1 == Symbols.Dot && c2.IsDigit()))
                    {
                        _source.Back();
                        return(NumberStart(current));
                    }
                }

                return(NewDelimiter(Symbols.Plus));
            }

            case Symbols.Colon:
                _source.Next();
                return(new CssSelectorToken(CssTokenType.Colon, ":"));

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

            case Symbols.DoubleQuote:
                return(StringDQ());

            case Symbols.SingleQuote:
                return(StringSQ());

            case 'U':
            case 'u':
                current = _source.Next();

                if (current == Symbols.Plus)
                {
                    current = _source.Next();

                    if (current.IsHex() || current == Symbols.QuestionMark)
                    {
                        return(UnicodeRange(current));
                    }

                    current = _source.Back();
                }

                return(IdentStart(_source.Back()));

            case Symbols.SquareBracketOpen:
                _source.Next();
                return(new CssSelectorToken(CssTokenType.SquareBracketOpen, "["));

            case Symbols.SquareBracketClose:
                _source.Next();
                return(new CssSelectorToken(CssTokenType.SquareBracketClose, "]"));

            case Symbols.RoundBracketClose:
                _source.Next();
                return(new CssSelectorToken(CssTokenType.RoundBracketClose, ")"));

            case Symbols.Solidus:
                current = _source.Next();

                if (current == Symbols.Asterisk)
                {
                    return(Data(_source.SkipCssComment()));
                }

                return(NewDelimiter(Symbols.Solidus));

            case Symbols.ReverseSolidus:
                current = _source.Next();

                if (current.IsLineBreak() || current == Symbols.EndOfFile)
                {
                    return(NewDelimiter(Symbols.ReverseSolidus));
                }

                return(IdentStart(_source.Back()));

            case Symbols.LessThan:
                current = _source.Next();

                if (current == Symbols.ExclamationMark)
                {
                    current = _source.Next();

                    if (current == Symbols.Minus)
                    {
                        current = _source.Next();

                        if (current == Symbols.Minus)
                        {
                            _source.Next();
                            return(NewInvalid());
                        }

                        current = _source.Back();
                    }

                    current = _source.Back();
                }

                return(NewDelimiter(Symbols.LessThan));

            case Symbols.Accent:
                current = _source.Next();

                if (current == Symbols.Equality)
                {
                    _source.Next();
                    return(NewMatch(CombinatorSymbols.Begins));
                }

                return(NewDelimiter(Symbols.Accent));

            case Symbols.EndOfFile:
                return(new CssSelectorToken(CssTokenType.EndOfFile, String.Empty));

            case Symbols.Pipe:
                current = _source.Next();

                if (current == Symbols.Equality)
                {
                    _source.Next();
                    return(NewMatch(CombinatorSymbols.InToken));
                }
                else if (current == Symbols.Pipe)
                {
                    _source.Next();
                    return(new CssSelectorToken(CssTokenType.Column, CombinatorSymbols.Column));
                }

                return(NewDelimiter(Symbols.Pipe));

            case Symbols.Dollar:
                current = _source.Next();

                if (current == Symbols.Equality)
                {
                    _source.Next();
                    return(NewMatch(CombinatorSymbols.Ends));
                }

                return(NewDelimiter(Symbols.Dollar));

            case Symbols.Tilde:
                current = _source.Next();

                if (current == Symbols.Equality)
                {
                    _source.Next();
                    return(NewMatch(CombinatorSymbols.InList));
                }

                return(NewDelimiter(Symbols.Tilde));

            case Symbols.ExclamationMark:
                current = _source.Next();

                if (current == Symbols.Equality)
                {
                    _source.Next();
                    return(NewMatch(CombinatorSymbols.Unlike));
                }

                return(NewDelimiter(Symbols.ExclamationMark));

            case Symbols.At:
                return(AtKeywordStart());

            case Symbols.RoundBracketOpen:
            case Symbols.CurlyBracketOpen:
            case Symbols.CurlyBracketClose:
            case Symbols.Semicolon:
                _source.Next();
                return(NewInvalid());

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

                _source.Next();
                return(NewDelimiter(current));
            }
        }