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); }
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))); }
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()); } } } }
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); }
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()); }
/// <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)); } }