Пример #1
0
        /// <summary>
        /// 4.4.3. Single quoted string state
        /// </summary>
        CssToken StringSQ(Char current)
        {
            while (true)
            {
                switch (current)
                {
                    case Specification.SingleQuote:
                    case Specification.EndOfFile:
                        return CssStringToken.Plain(FlushBuffer());

                    case Specification.FormFeed:
                    case Specification.LineFeed:
                        RaiseErrorOccurred(ErrorCode.LineBreakUnexpected);
                        Back();
                        return (CssStringToken.Plain(FlushBuffer(), true));

                    case Specification.ReverseSolidus:
                        current = Next;

                        if (current.IsLineBreak())
                            _stringBuffer.AppendLine();
                        else if (current != Specification.EndOfFile)
                            _stringBuffer.Append(ConsumeEscape(current));
                        else
                        {
                            RaiseErrorOccurred(ErrorCode.EOF);
                            Back();
                            return(CssStringToken.Plain(FlushBuffer(), true));
                        }

                        break;

                    default:
                        _stringBuffer.Append(current);
                        break;
                }

                current = Next;
            }
        }
Пример #2
0
        /// <summary>
        /// 4.4.1. Data state
        /// </summary>
        CssToken Data(Char current)
        {
            switch (current)
            {
                case Specification.LineFeed:
                case Specification.CarriageReturn:
                case Specification.Tab:
                case Specification.Space:
                    do { current = Next; }
                    while (current.IsSpaceCharacter());

                    if (_ignoreWs)
                        return Data(current);

                    Back();
                    return CssSpecialCharacter.Whitespace;

                case Specification.DoubleQuote:
                    return StringDQ(Next);

                case Specification.Num:
                    return HashStart(Next);

                case Specification.Dollar:
                    current = Next;

                    if (current == Specification.Equality)
                        return CssMatchToken.Suffix;

                    return CssToken.Delim(Previous);

                case Specification.SingleQuote:
                    return StringSQ(Next);

                case Specification.RoundBracketOpen:
                    return CssBracketToken.OpenRound;

                case Specification.RoundBracketClose:
                    return CssBracketToken.CloseRound;

                case Specification.Asterisk:
                    current = Next;

                    if (current == Specification.Equality)
                        return CssMatchToken.Substring;

                    return CssToken.Delim(Previous);

                case Specification.Plus:
                {
                    var c1 = Next;

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

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

                    return CssToken.Delim(current);
                }

                case Specification.Comma:
                    return CssSpecialCharacter.Comma;

                case Specification.Dot:
                {
                    var c = Next;

                    if (c.IsDigit())
                        return NumberStart(Previous);

                    return CssToken.Delim(Previous);
                }

                case Specification.Minus:
                {
                    var c1 = Next;

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

                        if (c1.IsDigit() || (c1 == Specification.Dot && c2.IsDigit()))
                            return NumberStart(current);
                        else if (c1.IsNameStart())
                            return IdentStart(current);
                        else if (c1 == Specification.ReverseSolidus && !c2.IsLineBreak() && c2 != Specification.EndOfFile)
                            return IdentStart(current);
                        else if (c1 == Specification.Minus && c2 == Specification.GreaterThan)
                        {
                            Advance(2);

                            if (_ignoreCs)
                                return Data(Next);

                            return CssCommentToken.Close;
                        }
                    }

                    return CssToken.Delim(current);
                }

                case Specification.Solidus:
                    current = Next;

                    if (current == Specification.Asterisk)
                        return Comment(Next);

                    return CssToken.Delim(Previous);

                case Specification.ReverseSolidus:
                    current = Next;

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

                    return IdentStart(Previous);

                case Specification.Colon:
                    return CssSpecialCharacter.Colon;

                case Specification.Semicolon:
                    return CssSpecialCharacter.Semicolon;

                case Specification.LessThan:
                    current = Next;

                    if (current == Specification.ExclamationMark)
                    {
                        current = Next;

                        if (current == Specification.Minus)
                        {
                            current = Next;

                            if (current == Specification.Minus)
                            {
                                if (_ignoreCs)
                                    return Data(Next);

                                return CssCommentToken.Open;
                            }

                            current = Previous;
                        }

                        current = Previous;
                    }

                    return CssToken.Delim(Previous);

                case Specification.At:
                    return AtKeywordStart(Next);

                case Specification.SquareBracketOpen:
                    return CssBracketToken.OpenSquare;

                case Specification.SquareBracketClose:
                    return CssBracketToken.CloseSquare;

                case Specification.Accent:
                    current = Next;

                    if (current == Specification.Equality)
                        return CssMatchToken.Prefix;

                    return CssToken.Delim(Previous);

                case Specification.CurlyBracketOpen:
                    return CssBracketToken.OpenCurly;

                case Specification.CurlyBracketClose:
                    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 = Next;

                    if (current == Specification.Plus)
                    {
                        current = Next;

                        if (current.IsHex() || current == Specification.QuestionMark)
                            return UnicodeRange(current);

                        current = Previous;
                    }

                    return IdentStart(Previous);

                case Specification.Pipe:
                    current = Next;

                    if (current == Specification.Equality)
                        return CssMatchToken.Dash;
                    else if (current == Specification.Pipe)
                        return CssToken.Column;

                    return CssToken.Delim(Previous);

                case Specification.Tilde:
                    current = Next;

                    if (current == Specification.Equality)
                        return CssMatchToken.Include;

                    return CssToken.Delim(Previous);

                case Specification.EndOfFile:
                    return null;

                case Specification.ExclamationMark:
                    current = Next;

                    if (current == Specification.Equality)
                        return CssMatchToken.Not;

                    return CssToken.Delim(Previous);

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

                    return CssToken.Delim(current);
            }
        }
Пример #3
0
        /// <summary>
        /// Checks if the current position is the beginning of a valid escape sequence.
        /// </summary>
        /// <returns>The result of the check.</returns>
        Boolean IsValidEscape(Char current)
        {
            if (current != Specification.ReverseSolidus)
                return false;

            current = Next;
            Back();

            if (current == Specification.EndOfFile)
                return false;
            else if (current.IsLineBreak())
                return false;

            return true;
        }
Пример #4
0
        /// <summary>
        /// Just goes back one character without checking
        /// if the beginning is already reached.
        /// </summary>
        void BackUnsafe()
        {
            _source.Index -= 1;

            if (_source.Index == 0)
            {
                _column = 0;
                _current = Symbols.Null;
                return;
            }

            _current = _source[_source.Index - 1];

            if (_current == Symbols.CarriageReturn)
            {
                BackUnsafe();
                return;
            }

            if (_current.IsLineBreak())
            {
                _column = _columns.Count != 0 ? _columns.Pop() : (UInt16)1;
                _row--;
            }
            else
            {
                _column--;
            }
        }
Пример #5
0
        /// <summary>
        /// 4.4.19. URL-single-quoted state
        /// </summary>
        CssToken UrlSQ(Char current, CssTokenType type)
        {
            while (true)
            {
                if (current.IsLineBreak())
                {
                    RaiseErrorOccurred(ErrorCode.LineBreakUnexpected);
                    return UrlBad(Next, type);
                }
                else if (Specification.EndOfFile == current)
                {
                    return CssStringToken.Url(type, FlushBuffer());
                }
                else if (current == Specification.SingleQuote)
                {
                    return UrlEnd(Next, type);
                }
                else if (current == Specification.ReverseSolidus)
                {
                    current = Next;

                    if (current == Specification.EndOfFile)
                    {
                        Back(2);
                        RaiseErrorOccurred(ErrorCode.EOF);
                        return CssStringToken.Url(type, FlushBuffer(), true);
                    }
                    else if (current.IsLineBreak())
                        _stringBuffer.AppendLine();
                    else
                        _stringBuffer.Append(ConsumeEscape(current));
                }
                else
                    _stringBuffer.Append(current);

                current = Next;
            }
        }
Пример #6
0
        /// <summary>
        /// Checks if the current position is the beginning of a valid escape sequence.
        /// </summary>
        /// <returns>The result of the check.</returns>
        Boolean IsValidEscape(Char current)
        {
            if (current != Symbols.ReverseSolidus)
                return false;

            current = GetNext();
            Back();

            if (current == Symbols.EndOfFile)
                return false;
            else if (current.IsLineBreak())
                return false;

            return true;
        }
Пример #7
0
        /// <summary>
        /// 4.4.1. Data state
        /// </summary>
        CssToken Data(Char current)
        {
            _position = GetCurrentPosition();

            switch (current)
            {
                case Symbols.FormFeed:
                case Symbols.LineFeed:
                case Symbols.CarriageReturn:
                case Symbols.Tab:
                case Symbols.Space:
                    return NewWhitespace(current);

                case Symbols.DoubleQuote:
                    return StringDQ();

                case Symbols.Num:
                    return _valueMode ? ColorLiteral() : HashStart();

                case Symbols.Dollar:
                    current = GetNext();

                    if (current == Symbols.Equality)
                        return NewSuffix();

                    return NewDelimiter(GetPrevious());

                case Symbols.SingleQuote:
                    return StringSQ();

                case Symbols.RoundBracketOpen:
                    return NewOpenRound();

                case Symbols.RoundBracketClose:
                    return NewCloseRound();

                case Symbols.Asterisk:
                    current = GetNext();

                    if (current == Symbols.Equality)
                        return NewSubstring();

                    return NewDelimiter(GetPrevious());

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

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

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

                case Symbols.Comma:
                    return NewComma();

                case Symbols.Dot:
                {
                    var c = GetNext();

                    if (c.IsDigit())
                        return NumberStart(GetPrevious());
                        
                    return NewDelimiter(GetPrevious());
                }

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

                    if (c1 != Symbols.EndOfFile)
                    {
                        var c2 = GetNext();
                        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)
                        {
                            Advance(2);
                            return NewCloseComment();
                        }
                    }
                    else
                        Back();
                        
                    return NewDelimiter(current);
                }

                case Symbols.Solidus:
                    current = GetNext();

                    if (current == Symbols.Asterisk)
                        return Comment();
                        
                    return NewDelimiter(GetPrevious());

                case Symbols.ReverseSolidus:
                    current = GetNext();

                    if (current.IsLineBreak())
                    {
                        RaiseErrorOccurred(CssParseError.LineBreakUnexpected);
                        return NewDelimiter(GetPrevious());
                    }
                    else if (current == Symbols.EndOfFile)
                    {
                        RaiseErrorOccurred(CssParseError.EOF);
                        return NewDelimiter(GetPrevious());
                    }

                    return IdentStart(GetPrevious());

                case Symbols.Colon:
                    return NewColon();

                case Symbols.Semicolon:
                    return NewSemicolon();

                case Symbols.LessThan:
                    current = GetNext();

                    if (current == Symbols.ExclamationMark)
                    {
                        current = GetNext();

                        if (current == Symbols.Minus)
                        {
                            current = GetNext();

                            if (current == Symbols.Minus)
                                return NewOpenComment();

                            current = GetPrevious();
                        }

                        current = GetPrevious();
                    }

                    return NewDelimiter(GetPrevious());

                case Symbols.At:
                    return AtKeywordStart();

                case Symbols.SquareBracketOpen:
                    return NewOpenSquare();

                case Symbols.SquareBracketClose:
                    return NewCloseSquare();

                case Symbols.Accent:
                    current = GetNext();

                    if (current == Symbols.Equality)
                        return NewPrefix();

                    return NewDelimiter(GetPrevious());

                case Symbols.CurlyBracketOpen:
                    return NewOpenCurly();

                case Symbols.CurlyBracketClose:
                    return NewCloseCurly();

                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 = GetNext();

                    if (current == Symbols.Plus)
                    {
                        current = GetNext();

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

                        current = GetPrevious();
                    }

                    return IdentStart(GetPrevious());

                case Symbols.Pipe:
                    current = GetNext();

                    if (current == Symbols.Equality)
                        return NewDash();
                    else if (current == Symbols.Pipe)
                        return NewColumn();

                    return NewDelimiter(GetPrevious());

                case Symbols.Tilde:
                    current = GetNext();

                    if (current == Symbols.Equality)
                        return NewInclude();

                    return NewDelimiter(GetPrevious());

                case Symbols.EndOfFile:
                    return NewEof();

                case Symbols.ExclamationMark:

                    current = GetNext();

                    if (current == Symbols.Equality)
                        return NewNot();

                    return NewDelimiter(GetPrevious());

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

                    return NewDelimiter(current);
            }
        }
Пример #8
0
        /// <summary>
        /// 4.4.3. Single quoted string state
        /// </summary>
        CssToken StringSQ(Char current)
        {
            while (true)
            {
                switch (current)
                {
                    case Specification.SQ:
                    case Specification.EOF:
                        return CssStringToken.Plain(FlushBuffer());

                    case Specification.FF:
                    case Specification.LF:
                        RaiseErrorOccurred(ErrorCode.LineBreakUnexpected);
                        _src.Back();
                        return (CssStringToken.Plain(FlushBuffer(), true));

                    case Specification.RSOLIDUS:
                        current = _src.Next;

                        if (current.IsLineBreak())
                            _stringBuffer.AppendLine();
                        else if (current != Specification.EOF)
                            _stringBuffer.Append(ConsumeEscape(current));
                        else
                        {
                            RaiseErrorOccurred(ErrorCode.EOF);
                            _src.Back();
                            return(CssStringToken.Plain(FlushBuffer(), true));
                        }

                        break;

                    default:
                        _stringBuffer.Append(current);
                        break;
                }

                current = _src.Next;
            }
        }
Пример #9
0
        /// <summary>
        /// Just goes back one character without checking
        /// if the beginning is already reached.
        /// </summary>
        void BackUnsafe()
        {
            _reader.Index -= 1;

            if (_reader.Index == 0)
            {
                _column = 0;
                _current = Specification.Null;
                return;
            }

            _current = _reader[_reader.Index - 1];

            if (_current.IsLineBreak())
            {
                _column = _collengths.Count != 0 ? _collengths.Pop() : 1;
                _row--;
            }
            else
                _column--;
        }
Пример #10
0
        /// <summary>
        /// Checks if the current position is the beginning of a valid escape sequence.
        /// </summary>
        /// <returns>The result of the check.</returns>
        Boolean IsValidEscape(Char current)
        {
            if (current != Specification.RSOLIDUS)
                return false;

            current = _src.Next;
            _src.Back();

            if (current == Specification.EOF)
                return false;
            else if (current.IsLineBreak())
                return false;

            return true;
        }
Пример #11
0
        /// <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 (current.IsSpaceCharacter());

                    if (_ignoreWs)
                        return Data(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 Specification.RBO:
                    return CssBracketToken.OpenRound;

                case Specification.RBC:
                    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 (c1.IsDigit() || (c1 == Specification.DOT && c2.IsDigit()))
                                return NumberStart(current);
                        }

                        return CssToken.Delim(current);
                    }

                case Specification.COMMA:
                    return CssSpecialCharacter.Comma;

                case Specification.DOT:
                    {
                        var c = _src.Next;

                        if (c.IsDigit())
                            return NumberStart(_src.Previous);

                        return CssToken.Delim(_src.Previous);
                    }

                case Specification.MINUS:
                    {
                        var c1 = _src.Next;

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

                            if (c1.IsDigit() || (c1 == Specification.DOT && c2.IsDigit()))
                                return NumberStart(current);
                            else if (c1.IsNameStart())
                                return IdentStart(current);
                            else if (c1 == Specification.RSOLIDUS && !c2.IsLineBreak() && c2 != Specification.EOF)
                                return IdentStart(current);
                            else if (c1 == Specification.MINUS && c2 == Specification.GT)
                            {
                                _src.Advance(2);

                                if (_ignoreCs)
                                    return Data(_src.Next);

                                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 (current.IsLineBreak() || current == Specification.EOF)
                    {
                        RaiseErrorOccurred(current == Specification.EOF ? ErrorCode.EOF : ErrorCode.LineBreakUnexpected);
                        return CssToken.Delim(_src.Previous);
                    }

                    return IdentStart(_src.Previous);

                case Specification.COLON:
                    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.MINUS)
                        {
                            current = _src.Next;

                            if (current == Specification.MINUS)
                            {
                                if (_ignoreCs)
                                    return Data(_src.Next);

                                return CssCommentToken.Open;
                            }

                            current = _src.Previous;
                        }

                        current = _src.Previous;
                    }

                    return CssToken.Delim(_src.Previous);

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

                case Specification.SBO:
                    return CssBracketToken.OpenSquare;

                case Specification.SBC:
                    return CssBracketToken.CloseSquare;

                case Specification.ACCENT:
                    current = _src.Next;

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

                    return CssToken.Delim(_src.Previous);

                case Specification.CBO:
                    return CssBracketToken.OpenCurly;

                case Specification.CBC:
                    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 (current.IsHex() || 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 (current.IsNameStart())
                        return IdentStart(current);

                    return CssToken.Delim(current);
            }
        }
Пример #12
0
        /// <summary>
        /// 4.4.19. URL-single-quoted state
        /// </summary>
        CssToken UrlSQ(Char current, CssTokenType type)
        {
            while (true)
            {
                if (current.IsLineBreak())
                {
                    RaiseErrorOccurred(ErrorCode.LineBreakUnexpected);
                    return UrlBad(_src.Next, type);
                }
                else if (Specification.EOF == current)
                {
                    return CssStringToken.Url(type, FlushBuffer());
                }
                else if (current == Specification.SQ)
                {
                    return UrlEnd(_src.Next, type);
                }
                else if (current == Specification.RSOLIDUS)
                {
                    current = _src.Next;

                    if (current == Specification.EOF)
                    {
                        _src.Back(2);
                        RaiseErrorOccurred(ErrorCode.EOF);
                        return CssStringToken.Url(type, FlushBuffer(), true);
                    }
                    else if (current.IsLineBreak())
                        _stringBuffer.AppendLine();
                    else
                        _stringBuffer.Append(ConsumeEscape(current));
                }
                else
                    _stringBuffer.Append(current);

                current = _src.Next;
            }
        }
Пример #13
0
        void BackUnsafe()
        {
            _insertion--;

            if (_insertion == 0)
            {
                _column = 0;
                _current = Specification.NULL;
                return;
            }

            _current = _buffer[_insertion - 1];

            if (_current.IsLineBreak())
            {
                _column = _collengths.Count != 0 ? _collengths.Pop() : 1;
                _row--;
            }
            else
                _column--;
        }
Пример #14
0
        Boolean IsValidEscape(Char current)
        {
            if (current == Symbols.ReverseSolidus)
            {
                current = GetNext();
                Back();

                return current != Symbols.EndOfFile && !current.IsLineBreak();
            }
                
            return false;
        }