private static void AssertNextToken(CssScanner lex, CssTokenType type, Func<CssToken, bool> condition) { var token = new CssToken(); Assert.IsTrue(lex.Next(token, true), "Unexpected EOF"); Assert.AreEqual(type, token.mType); Assert.IsTrue(condition(token), "Condition for token {0} failed".Fmt(token.mType)); }
public CssToken(string value, CssTokenType type, int line, int col) { this.value = value; this.type = type; this.col = col; this.line = line; }
/// <summary> /// 4.4.19. URL-single-quoted state /// </summary> CssToken UrlSQ(CssTokenType type) { while (true) { var current = Next; if (current.IsLineBreak()) { RaiseErrorOccurred(ErrorCode.LineBreakUnexpected); return(UrlBad(type)); } else if (Specification.EndOfFile == current) { return(CssStringToken.Url(type, FlushBuffer())); } else if (current == Specification.SingleQuote) { return(UrlEnd(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); } } }
protected void AddToken(CssTokenType type, int start, int length) { CssToken token = new CssToken(type, start, length); Tokens.Add(token); #if DEBUG token.DebugText = (type != CssTokenType.EndOfFile) ? CS.TextProvider.GetText(start, length) : "EOF"; if (type != CssTokenType.WhiteSpace && token.DebugText.Length > 0) { // Tokens must not have whitespace at either end (that can break incremental tokenizing) Debug.Assert( !TextHelper.IsWhiteSpace(token.DebugText[0]) && !TextHelper.IsWhiteSpace(token.DebugText[token.DebugText.Length - 1])); } #endif }
/// <summary> /// 4.4.22. Bad URL state /// </summary> CssToken UrlBad(CssTokenType type) { while (true) { var current = GetNext(); if (current == Symbols.EndOfFile) { RaiseErrorOccurred(ErrorCode.EOF); return(CssStringToken.Url(type, FlushBuffer(), true)); } else if (current == Symbols.RoundBracketClose) { return(CssStringToken.Url(type, FlushBuffer(), true)); } else if (IsValidEscape(current)) { current = GetNext(); _stringBuffer.Append(ConsumeEscape(current)); } } }
/// <summary> /// 4.4.22. Bad URL state /// </summary> CssToken UrlBad(Char current, CssTokenType type) { while (true) { if (current == Specification.EndOfFile) { RaiseErrorOccurred(ErrorCode.EOF); return(CssStringToken.Url(type, FlushBuffer(), true)); } else if (current == Specification.RoundBracketClose) { return(CssStringToken.Url(type, FlushBuffer(), true)); } else if (IsValidEscape(current)) { current = _src.Next; _stringBuffer.Append(ConsumeEscape(current)); } current = _src.Next; } }
void FillMediaList(MediaList list, CssTokenType end, ref CssToken token) { if (token.Type == end) { return; } while (token.Type != CssTokenType.Eof) { CreateNewNode(); var medium = CloseNode(CreateMedium(ref token)); if (medium != null) { list.Add(medium); } if (token.Type != CssTokenType.Comma) { break; } token = NextToken(); CollectTrivia(ref token); } if (token.Type == end && list.Length > 0) { return; } list.Clear(); list.Add(new CssMedium { IsInverse = true, Type = Keywords.All }); }
/// <summary> /// 4.4.21. URL-unquoted state /// </summary> CssToken UrlUQ(Char current, CssTokenType type) { while (true) { if (current.IsSpaceCharacter()) { return(UrlEnd(type)); } else if (current == Symbols.RoundBracketClose || current == Symbols.EndOfFile) { return(NewUrl(type, FlushBuffer())); } else if (current == Symbols.DoubleQuote || current == Symbols.SingleQuote || current == Symbols.RoundBracketOpen || current.IsNonPrintable()) { RaiseErrorOccurred(CssParseError.InvalidCharacter); return(UrlBad(type)); } else if (current == Symbols.ReverseSolidus) { if (IsValidEscape(current)) { current = GetNext(); _stringBuffer.Append(ConsumeEscape(current)); } else { RaiseErrorOccurred(CssParseError.InvalidCharacter); return(UrlBad(type)); } } else { _stringBuffer.Append(current); } current = GetNext(); } }
/// <summary> /// 4.4.21. URL-unquoted state /// </summary> CssToken UrlUQ(Char current, CssTokenType type) { while (true) { if (current.IsSpaceCharacter()) { return(UrlEnd(type)); } else if (current == Specification.RoundBracketClose || current == Specification.EndOfFile) { return(CssStringToken.Url(type, FlushBuffer())); } else if (current == Specification.DoubleQuote || current == Specification.SingleQuote || current == Specification.RoundBracketOpen || current.IsNonPrintable()) { RaiseErrorOccurred(ErrorCode.InvalidCharacter); return(UrlBad(type)); } else if (current == Specification.ReverseSolidus) { if (IsValidEscape(current)) { current = Next; _stringBuffer.Append(ConsumeEscape(current)); } else { RaiseErrorOccurred(ErrorCode.InvalidCharacter); return(UrlBad(type)); } } else { _stringBuffer.Append(current); } current = Next; } }
/// <summary> /// Appends media labels from the given source to the medialist. /// </summary> /// <param name="source">The token iterator.</param> /// <param name="media">The medialist to append to.</param> /// <param name="endToken">The optional token type to finish appending to the list.</param> void AppendMediaList(IEnumerator <CssToken> source, MediaList media, CssTokenType endToken = CssTokenType.Semicolon) { do { if (source.Current.Type == CssTokenType.Whitespace) { continue; } else if (source.Current.Type == endToken) { break; } do { if (source.Current.Type == CssTokenType.Comma || source.Current.Type == endToken) { break; } else if (source.Current.Type == CssTokenType.Whitespace) { buffer.Append(' '); } else { buffer.Append(source.Current.ToValue()); } }while (source.MoveNext()); media.AppendMedium(buffer.ToString()); buffer.Clear(); if (source.Current.Type == endToken) { break; } }while (source.MoveNext()); }
// two more bools can fit before enum flags should be used internal CssToken(CssTokenType tokenType, int start, int length) { TokenType = tokenType; Start = start; Length = length; switch (TokenType) { case CssTokenType.CloseCComment: case CssTokenType.CommentText: IsComment = true; IsChildToken = true; break; case CssTokenType.CloseHtmlComment: case CssTokenType.OpenCComment: case CssTokenType.OpenHtmlComment: case CssTokenType.SingleLineComment: case CssTokenType.SingleTokenComment: IsComment = true; break; } }
/// <summary> /// 4.4.17. URL state /// </summary> CssToken UrlStart(CssTokenType type) { var current = SkipSpaces(); switch (current) { case Symbols.EndOfFile: RaiseErrorOccurred(CssParseError.EOF); return(NewUrl(type, String.Empty, true)); case Symbols.DoubleQuote: return(UrlDQ(type)); case Symbols.SingleQuote: return(UrlSQ(type)); case Symbols.RoundBracketClose: return(NewUrl(type, String.Empty, false)); default: return(UrlUQ(current, type)); } }
/// <summary> /// 4.4.17. URL state /// </summary> CssToken UrlStart(CssTokenType type) { var current = SkipSpaces(); switch (current) { case Symbols.EndOfFile: RaiseErrorOccurred(ErrorCode.EOF); return(CssStringToken.Url(type, String.Empty, true)); case Symbols.DoubleQuote: return(UrlDQ(type)); case Symbols.SingleQuote: return(UrlSQ(type)); case ')': return(CssStringToken.Url(type, String.Empty, false)); default: return(UrlUQ(current, type)); } }
void FillMediaList(MediaList list, CssTokenType end, ref CssToken token) { _nodes.Push(list); if (token.Type != end) { while (token.Type != CssTokenType.EndOfFile) { var medium = CreateMedium(ref token); if (medium != null) { list.AppendChild(medium); } if (token.Type != CssTokenType.Comma) { break; } token = NextToken(); CollectTrivia(ref token); } if (token.Type != end || list.Length == 0) { list.Clear(); list.AppendChild(new CssMedium { IsInverse = true, Type = Keywords.All }); } } _nodes.Pop(); }
/// <summary> /// Before any medium has been found for the @media or @import rule. /// </summary> void FillMediaList(MediaList list, CssTokenType end, ref CssToken token) { if (token.Type == end) { return; } while (token.Type != CssTokenType.Eof) { var medium = CreateMedium(ref token); if (medium != null) { list.Add(medium); } if (token.Type != CssTokenType.Comma) { break; } token = _tokenizer.Get(); } if (token.Type == end && list.Length > 0) { return; } list.Clear(); list.Add(new CssMedium { IsInverse = true, Type = Keywords.All }); }
/// <summary> /// 4.4.20. URL-end state /// </summary> CssToken UrlEnd(Char current, CssTokenType type) { while (true) { if (current == Specification.RoundBracketClose) return CssStringToken.Url(type, FlushBuffer()); else if (!current.IsSpaceCharacter()) { RaiseErrorOccurred(ErrorCode.InvalidCharacter); return UrlBad(current, type); } current = Next; } }
public CssToken(CssTokenType type, String data, TextPosition position) { _type = type; _data = data; _position = position; }
private void acceptElement(CssTokenType t) { CssToken ct = tokenizer.Current; while (tokenizer.Current.GetTokenType () == CssTokenType.COMMENT) { tokenizer.MoveNext (); Console.WriteLine("ignored comment"); } if (tokenizer.Current.GetTokenType () != t) { Console.WriteLine("Parser: Rejected Terminal: {0} {1} - Expected {2}", ct.GetValue (), ct.GetTokenType ().ToString (), t.ToString ()); throw new Exception("I made a boo!"); } else { currentNode.AddChild(new CssNode(tokenizer.Current)); Console.WriteLine("Parser: Accepted Terminal: {0} {1}", tokenizer.Current.GetValue (), tokenizer.Current.GetTokenType ().ToString ()); } tokenizer.MoveNext (); }
/// <summary> /// Before any medium has been found for the @media or @import rule. /// </summary> void FillMediaList(MediaList list, CssTokenType end, ref CssToken token) { if (token.Type == end) return; while (token.Type != CssTokenType.Eof) { var medium = CreateMedium(ref token); if (medium != null) list.Add(medium); if (token.Type != CssTokenType.Comma) break; token = _tokenizer.Get(); } if (token.Type == end && list.Length > 0) return; list.Clear(); list.Add(new CssMedium { IsInverse = true, Type = Keywords.All }); }
public StartsWithValueConverter(CssTokenType type, String data, IValueConverter converter) { _type = type; _data = data; _converter = converter; }
/// <summary> /// 4.4.21. URL-unquoted state /// </summary> CssToken UrlUQ(Char current, CssTokenType type) { while (true) { if (current.IsSpaceCharacter()) { return UrlEnd(_src.Next, type); } else if (current == Specification.RBC || current == Specification.EOF) { return CssStringToken.Url(type, FlushBuffer()); } else if (current == Specification.DQ || current == Specification.SQ || current == Specification.RBO || current.IsNonPrintable()) { RaiseErrorOccurred(ErrorCode.InvalidCharacter); return UrlBad(_src.Next, type); } else if (current == Specification.RSOLIDUS) { if (IsValidEscape(current)) { current = _src.Next; _stringBuffer.Append(ConsumeEscape(current)); } else { RaiseErrorOccurred(ErrorCode.InvalidCharacter); return UrlBad(_src.Next, type); } } else _stringBuffer.Append(current); current = _src.Next; } }
public CssUnitToken(CssTokenType type, String value, String dimension, TextPosition position) : base(type, value, position) { _unit = dimension; }
/// <summary> /// Checks if the provided token is either of the first or the second /// type of token. /// </summary> /// <param name="token">The token to examine.</param> /// <param name="a">The first type to match.</param> /// <param name="b">The alternative match for the token.</param> /// <returns>Result of the examination.</returns> public static Boolean Is(this CssToken token, CssTokenType a, CssTokenType b) { var type = token.Type; return(type == a || type == b); }
/// <summary> /// Checks if the provided token is neither of the first, nor the /// second nor the third type of token. /// </summary> /// <param name="token">The token to examine.</param> /// <param name="a">The first type to unmatch.</param> /// <param name="b">The alternative unmatch for the token.</param> /// <param name="c">The final unmatch for the token.</param> /// <returns>Result of the examination.</returns> public static Boolean IsNot(this CssToken token, CssTokenType a, CssTokenType b, CssTokenType c) { var type = token.Type; return(type != a && type != b && type != c); }
/// <summary> /// 4.4.20. URL-end state /// </summary> CssToken UrlEnd(CssTokenType type) { while (true) { var current = GetNext(); if (current == Symbols.RoundBracketClose) { return NewUrl(type, FlushBuffer()); } else if (!current.IsSpaceCharacter()) { RaiseErrorOccurred(CssParseError.InvalidCharacter); Back(); return UrlBad(type); } } }
/// <summary> /// Checks if the provided token is neither of the first, nor the /// second nor the third type of token. /// </summary> /// <param name="token">The token to examine.</param> /// <param name="a">The first type to unmatch.</param> /// <param name="b">The alternative unmatch for the token.</param> /// <param name="c">The final unmatch for the token.</param> /// <returns>Result of the examination.</returns> public static Boolean IsNot(this CssToken token, CssTokenType a, CssTokenType b, CssTokenType c) { var type = token.Type; return type != a && type != b && type != c; }
/// <summary> /// Checks if the provided token is either of the first or the second /// type of token. /// </summary> /// <param name="token">The token to examine.</param> /// <param name="a">The first type to match.</param> /// <param name="b">The alternative match for the token.</param> /// <returns>Result of the examination.</returns> public static Boolean Is(this CssToken token, CssTokenType a, CssTokenType b) { var type = token.Type; return type == a || type == b; }
/// <summary> /// 4.4.19. URL-single-quoted state /// </summary> CssToken UrlSQ(CssTokenType type) { while (true) { var current = GetNext(); if (current.IsLineBreak()) { RaiseErrorOccurred(CssParseError.LineBreakUnexpected); return UrlBad(type); } else if (Symbols.EndOfFile == current) { return NewUrl(type, FlushBuffer()); } else if (current == Symbols.SingleQuote) { return UrlEnd(type); } else if (current != Symbols.ReverseSolidus) { _stringBuffer.Append(current); } else { current = GetNext(); if (current == Symbols.EndOfFile) { Back(2); RaiseErrorOccurred(CssParseError.EOF); return NewUrl(type, FlushBuffer(), bad: true); } else if (current.IsLineBreak()) _stringBuffer.AppendLine(); else _stringBuffer.Append(ConsumeEscape(current)); } } }
/// <summary> /// 4.4.17. URL state /// </summary> CssToken UrlStart(CssTokenType type) { var current = SkipSpaces(); switch (current) { case Symbols.EndOfFile: RaiseErrorOccurred(CssParseError.EOF); return NewUrl(type, String.Empty, bad: true); case Symbols.DoubleQuote: return UrlDQ(type); case Symbols.SingleQuote: return UrlSQ(type); case Symbols.RoundBracketClose: return NewUrl(type, String.Empty, bad: false); default: return UrlUQ(current, type); } }
/// <summary> /// 4.4.17. URL state /// </summary> CssToken UrlStart(Char current, CssTokenType type) { while (current.IsSpaceCharacter()) current = Next; switch (current) { case Specification.EndOfFile: RaiseErrorOccurred(ErrorCode.EOF); return CssStringToken.Url(type, String.Empty, true); case Specification.DoubleQuote: return UrlDQ(Next, type); case Specification.SingleQuote: return UrlSQ(Next, type); case ')': return CssStringToken.Url(type, String.Empty, false); default: return UrlUQ(current, type); } }
/// <summary> /// Creates a new CSS keyword token. /// </summary> /// <param name="type">The exact type.</param> /// <param name="data">The data to use.</param> /// <param name="position">The token's position.</param> public CssKeywordToken(CssTokenType type, String data, TextPosition position) : base(type, data, position) { }
private void FillMediaList(MediaList list, CssTokenType end, ref CssToken token) { _nodes.Push(list); if (token.Type != end) { while (token.Type != CssTokenType.EndOfFile) { var medium = CreateMedium(ref token); if (medium != null) { list.AppendChild(medium); } if (token.Type != CssTokenType.Comma) { break; } token = NextToken(); CollectTrivia(ref token); } if (token.Type != end || list.Length == 0) { list.Clear(); list.AppendChild(new CssMedium { IsInverse = true, Type = Keywords.All }); } } _nodes.Pop(); }
protected virtual bool HandleToken() { CssTokenType tokenType = CssTokenType.Unknown; int tokenStart = CS.Position; switch (CS.CurrentChar) { case '*': if (CS.Peek(1) == '=') { tokenType = CssTokenType.ContainsString; CS.Advance(1); } else { tokenType = CssTokenType.Asterisk; } break; case '&': tokenType = CssTokenType.Ampersand; break; case '.': tokenType = CssTokenType.Dot; break; case '!': tokenType = CssTokenType.Bang; break; case ',': tokenType = CssTokenType.Comma; break; case '^': if (CS.Peek(1) == '=') { tokenType = CssTokenType.BeginsWith; CS.Advance(1); } else { tokenType = CssTokenType.Caret; } break; case ':': if (CS.Peek(1) == ':') { tokenType = CssTokenType.DoubleColon; CS.Advance(1); } else { tokenType = CssTokenType.Colon; } break; case '$': if (CS.Peek(1) == '=') { tokenType = CssTokenType.EndsWith; CS.Advance(1); } else { tokenType = CssTokenType.Dollar; } break; case '=': tokenType = CssTokenType.Equals; break; case '>': tokenType = CssTokenType.Greater; break; case '|': if (CS.Peek(1) == '=') { tokenType = CssTokenType.ListBeginsWith; CS.Advance(1); } else if (CS.Peek(1) == '|') { tokenType = CssTokenType.DoublePipe; CS.Advance(1); } else { tokenType = CssTokenType.Or; } break; case '%': tokenType = CssTokenType.Percent; break; case ';': tokenType = CssTokenType.Semicolon; break; case '/': if (HandleComment()) { return(true); } else { tokenType = CssTokenType.Slash; } break; case '\\': if (HandleSlashNineHack()) { return(true); } break; case '<': if (CS.TextProvider.CompareTo(CS.Position, "<!--", ignoreCase: false)) { CS.Advance(4); AddToken(CssTokenType.OpenHtmlComment, tokenStart, CS.Position - tokenStart); return(true); } break; case '~': if (CS.Peek(1) == '=') { tokenType = CssTokenType.OneOf; CS.Advance(1); } else { tokenType = CssTokenType.Tilde; } break; case '(': tokenType = CssTokenType.OpenFunctionBrace; break; case ')': tokenType = CssTokenType.CloseFunctionBrace; break; case '[': tokenType = CssTokenType.OpenSquareBracket; break; case ']': tokenType = CssTokenType.CloseSquareBracket; break; case '{': tokenType = CssTokenType.OpenCurlyBrace; break; case '}': tokenType = CssTokenType.CloseCurlyBrace; break; case '@': tokenType = CssTokenType.At; break; case '\'': case '\"': if (HandleString() != CssTokenType.Unknown) { return(true); } break; case '#': if (HandleHash()) { return(true); } else { tokenType = CssTokenType.Hash; } break; case '+': tokenType = CssTokenType.Plus; break; case '-': if (HandleIdentifier()) { return(true); } else if (CS.TextProvider.CompareTo(CS.Position, "-->", ignoreCase: false)) { CS.Advance(3); AddToken(CssTokenType.CloseHtmlComment, tokenStart, CS.Position - tokenStart); return(true); } else { tokenType = CssTokenType.Minus; } break; case 'u': case 'U': if (HandleUnicodeRange()) { return(true); } break; } if (tokenType == CssTokenType.Unknown && HandleIdentifier()) { return(true); } if (!HandleUnknown()) { // Some kind of junk in the CSS, just deal with it by making an unknown token CS.Advance(1); AddToken(tokenType, tokenStart, CS.Position - tokenStart); } return(true); }
private CssValue CreateValue(CssTokenType closing, ref CssToken token, out Boolean important) { var value = Pool.NewValueBuilder(); _tokenizer.IsInValue = true; token = NextToken(); var start = token.Position; while (token.IsNot(CssTokenType.EndOfFile, CssTokenType.Semicolon, closing)) { value.Apply(token); token = NextToken(); } important = value.IsImportant; _tokenizer.IsInValue = false; var valueIsValid = value.IsValid; var result = value.ToPool(); var node = result as CssNode; if (node != null) { var end = token.Position.Shift(-1); node.SourceCode = CreateView(start, end); } if (!valueIsValid && !_parser.Options.IsToleratingInvalidValues) { RaiseErrorOccurred(CssParseError.InvalidValue, start); result = null; } return result; }
CssToken NewUrl(CssTokenType type, String data, Boolean bad = false) { return new CssStringToken(type, data, bad, _position); }
/// <summary> /// Creates a new comment. /// </summary> CssCommentToken(CssTokenType type, String data) : base(type, data) { }
/// <summary> /// Called before any token in the value regime had been seen. /// </summary> CssValue CreateValue(CssTokenType closing, ref CssToken token, out Boolean important) { var value = Pool.NewValueBuilder(); _tokenizer.State = CssParseMode.Value; token = _tokenizer.Get(); while (token.Type != CssTokenType.Eof) { if (token.Is(CssTokenType.Semicolon, closing)) break; value.Apply(token); token = _tokenizer.Get(); } important = value.IsImportant; _tokenizer.State = CssParseMode.Data; if (value.IsValid || _parser.Options.IsToleratingInvalidValues) return value.ToPool(); value.ToPool(); return null; }
public CssSelectorToken(CssTokenType type, String data) { _type = type; _data = data; }
/// <summary> /// Creates a new CSS string token. /// </summary> /// <param name="type">The exact type.</param> CssStringToken(CssTokenType type) { _type = type; }
/// <summary> /// Creates a new CSS unit token. /// </summary> /// <param name="type">The exact type.</param> CssUnitToken(CssTokenType type) { _type = type; }
/// <summary> /// 4.4.22. Bad URL state /// </summary> CssToken UrlBad(Char current, CssTokenType type) { while (true) { if (current == Specification.EndOfFile) { RaiseErrorOccurred(ErrorCode.EOF); return CssStringToken.Url(type, FlushBuffer(), true); } else if (current == Specification.RoundBracketClose) { return CssStringToken.Url(type, FlushBuffer(), true); } else if (IsValidEscape(current)) { current = Next; _stringBuffer.Append(ConsumeEscape(current)); } current = Next; } }
static CssToken ConsumeNodeName(string src, ref int index, bool validateFirstChar, CssTokenType type) { int start = index; if (!validateFirstChar) { ++index; } while (index < src.Length && ">~+,:.#()[] ".IndexOf(src[index]) == -1) { ++index; } if (index == start) { throw new Exception("how did we end up with a 0-length tag name starting at " + index + " for:" + src); } return(new CssToken(src.Substring(start, index - start), type)); }
/// <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; } }
/// <summary> /// 4.4.21. URL-unquoted state /// </summary> CssToken UrlUQ(Char current, CssTokenType type) { while (true) { if (current.IsSpaceCharacter()) { return UrlEnd(type); } else if (current == Symbols.RoundBracketClose || current == Symbols.EndOfFile) { return NewUrl(type, FlushBuffer()); } else if (current == Symbols.DoubleQuote || current == Symbols.SingleQuote || current == Symbols.RoundBracketOpen || current.IsNonPrintable()) { RaiseErrorOccurred(CssParseError.InvalidCharacter); return UrlBad(type); } else if (current != Symbols.ReverseSolidus) { _stringBuffer.Append(current); } else if (IsValidEscape(current)) { current = GetNext(); _stringBuffer.Append(ConsumeEscape(current)); } else { RaiseErrorOccurred(CssParseError.InvalidCharacter); return UrlBad(type); } current = GetNext(); } }
/// <summary> /// 4.4.21. URL-unquoted state /// </summary> CssToken UrlUQ(Char current, CssTokenType type) { while (true) { if (current.IsSpaceCharacter()) { return UrlEnd(Next, type); } else if (current == Specification.RoundBracketClose || current == Specification.EndOfFile) { return CssStringToken.Url(type, FlushBuffer()); } else if (current == Specification.DoubleQuote || current == Specification.SingleQuote || current == Specification.RoundBracketOpen || current.IsNonPrintable()) { RaiseErrorOccurred(ErrorCode.InvalidCharacter); return UrlBad(Next, type); } else if (current == Specification.ReverseSolidus) { if (IsValidEscape(current)) { current = Next; _stringBuffer.Append(ConsumeEscape(current)); } else { RaiseErrorOccurred(ErrorCode.InvalidCharacter); return UrlBad(Next, type); } } else _stringBuffer.Append(current); current = Next; } }
public CssToken(CssTokenType type, Char data, TextPosition position) : this(type, data.ToString(), position) { }
/// <summary> /// Creates a new CSS string token (URL string). /// </summary> /// <param name="token">The token type (url, urlprefix, domain).</param> /// <param name="data">The URL string data.</param> /// <param name="bad">If the URL was bad (optional).</param> /// <returns>The created URL string token.</returns> public static CssStringToken Url(CssTokenType token, String data, Boolean bad = false) { return new CssStringToken(token) { _data = data, _bad = bad }; }
/// <summary> /// Appends media labels from the given source to the medialist. /// </summary> /// <param name="source">The token iterator.</param> /// <param name="media">The medialist to append to.</param> /// <param name="endToken">The optional token type to finish appending to the list.</param> void AppendMediaList(IEnumerator<CssToken> source, MediaList media, CssTokenType endToken = CssTokenType.Semicolon) { do { if (source.Current.Type == CssTokenType.Whitespace) continue; else if (source.Current.Type == endToken) break; do { if (source.Current.Type == CssTokenType.Comma || source.Current.Type == endToken) break; else if (source.Current.Type == CssTokenType.Whitespace) buffer.Append(' '); else buffer.Append(source.Current.ToValue()); } while (source.MoveNext()); media.AppendMedium(buffer.ToString()); buffer.Clear(); if (source.Current.Type == endToken) break; } while (source.MoveNext()); }
protected CssTokenType SkipString() { // This can detect single and double quoted strings, spanning a single or multiple lines. // Also, unterminated strings are detected. The return value tells you the type: // // CssTokenType.Unknown (not a string at all) // CssTokenType.MultilineString // CssTokenType.String // CssTokenType.InvalidString (unterminated) CssTokenType tokenType = CssTokenType.Unknown; if (TextHelper.IsQuote(CS.CurrentChar)) { // Guilty until proven valid tokenType = CssTokenType.InvalidString; char quote = CS.CurrentChar; bool multiLine = false; CS.Advance(1); while (!CS.IsAtEnd) { if (AtScopeBlocker()) { break; } else if (CS.CurrentChar == quote) { // Found matching end quote tokenType = multiLine ? CssTokenType.MultilineString : CssTokenType.String; CS.Advance(1); break; } else if (TextHelper.IsNewLine(CS.CurrentChar)) { break; } else if (AtEscape()) { SkipEscape(); } else if (CS.CurrentChar == '\\') { // must be an escaped line break CS.Advance(1); Debug.Assert(TextHelper.IsNewLine(CS.CurrentChar)); SkipNewLine(); multiLine = true; } else { CS.Advance(1); } } if (tokenType == CssTokenType.InvalidString) { SkipWhitespaceReverse(); } } return(tokenType); }
/// <summary> /// Creates a new CSS keyword token. /// </summary> /// <param name="type">The exact type.</param> /// <param name="data">The data to use.</param> CssKeywordToken(CssTokenType type, String data) : base(type, data) { }
private bool HandleComment() { const CssTokenType startTokenType = CssTokenType.OpenCComment; const CssTokenType endTokenType = CssTokenType.CloseCComment; const string commentStart = "/*"; const string commentEnd = "*/"; if (AtScopeBlocker()) { AddToken(CssTokenType.ScopeBlocker, CS.Position, ScopeBlockerText.Length); CS.Advance(ScopeBlockerText.Length); return(true); } // Comment: /* foo */ // Makes three tokens for a comment (start, text, and end) if (!CS.TextProvider.CompareTo(CS.Position, commentStart, ignoreCase: false)) { return(false); } // Skip the start of the comment AddToken(startTokenType, CS.Position, commentStart.Length); CS.Advance(commentStart.Length); // Skip the inner text of the comment bool endFound = false; if (!CS.IsAtEnd) { SkipWhitespace(); int start = CS.Position; for (; !CS.IsAtEnd; CS.Advance(1)) { if (CS.TextProvider.CompareTo(CS.Position, commentEnd, ignoreCase: false)) { endFound = true; break; } if (AtScopeBlocker()) { // Catch: /* Foo /* END EXTERNAL SOURCE */ break; } } if (CS.Position >= start) { // Create a token for the comment text, don't include trailing whitespace SkipWhitespaceReverse(); if (CS.Position > start) { AddToken(CssTokenType.CommentText, start, CS.Position - start); } SkipWhitespace(); } } // Skip the end of the comment if (endFound) { AddToken(endTokenType, CS.Position, commentEnd.Length); CS.Advance(commentEnd.Length); } return(true); }
/// <summary> /// Creates a new special character token. /// </summary> /// <param name="c">The character to contain.</param> /// <param name="type">The actual token type.</param> CssSpecialCharacter(Char c, CssTokenType type) : base(c) { _type = type; }
/// <summary> /// 4.4.22. Bad URL state /// </summary> CssToken UrlBad(CssTokenType type) { var current = Current; var curly = 0; var round = 1; while (current != Symbols.EndOfFile) { if (current == Symbols.Semicolon) { Back(); return NewUrl(type, FlushBuffer(), true); } else if (current == Symbols.CurlyBracketClose && --curly == -1) { Back(); return NewUrl(type, FlushBuffer(), true); } else if (current == Symbols.RoundBracketClose && --round == 0) { return NewUrl(type, FlushBuffer(), true); } else if (IsValidEscape(current)) { current = GetNext(); _stringBuffer.Append(ConsumeEscape(current)); } else { if (current == Symbols.RoundBracketOpen) ++round; else if (curly == Symbols.CurlyBracketOpen) ++curly; _stringBuffer.Append(current); } current = GetNext(); } RaiseErrorOccurred(CssParseError.EOF); return NewUrl(type, FlushBuffer(), bad: true); }
public CssKeywordToken(CssTokenType type, String data, TextPosition position) : base(type, data, position) { }
/// <summary> /// Creates a new CSS unit token. /// </summary> /// <param name="type">The exact type.</param> /// <param name="value">The value.</param> /// <param name="dimension">The unit (dimension).</param> /// <param name="position">The token's position.</param> public CssUnitToken(CssTokenType type, String value, String dimension, TextPosition position) : base(type, value, position) { _unit = dimension; }
static void ConsumeOpenCloseGroup(string src, ref int index, List <CssToken> tokens, char closeChar, CssTokenType groupType) { char openChar = src[index++]; int closeIndex = src.IndexOf(closeChar, index); if (closeIndex < index) { throw new FormatException("'" + openChar + "' at " + (index - 1) + " has no matching '" + closeChar + "'"); } // this works since () [] {} are non-nestable (I think) // return everything inside () as a single token. Let consumers parse them out tokens.Add(new CssToken(openChar.ToString(), groupType)); tokens.Add(new CssToken(src.Substring(index, closeIndex - index).Trim(), CssTokenType.Parameter)); tokens.Add(new CssToken(closeChar.ToString(), groupType)); index = closeIndex + 1; }