/// <summary> /// Applies the token to the currently build value. /// </summary> /// <param name="token">The current token to apply.</param> public void Apply(CssToken token) { switch (token.Type) { case CssTokenType.RoundBracketOpen: _open++; Add(token); break; case CssTokenType.Function: // e.g. "rgba(...)" Add(token); break; case CssTokenType.Ident: // e.g. "auto" _important = CheckImportant(token); break; case CssTokenType.RoundBracketClose: _open--; Add(token); break; case CssTokenType.Whitespace: // e.g. " " if (_values.Count > 0 && IsSlash(_values[_values.Count - 1]) == false) _buffer = token; break; case CssTokenType.Dimension: // e.g. "3px" case CssTokenType.Percentage: // e.g. "5%" case CssTokenType.Color:// e.g. "#ABCDEF" case CssTokenType.Delim:// e.g. "#" case CssTokenType.String:// e.g. "'i am a string'" case CssTokenType.Url:// e.g. "url('this is a valid URL')" case CssTokenType.Number: // e.g. "173" case CssTokenType.Comma: // e.g. "," Add(token); break; case CssTokenType.Comment: // Should not be considered. break; default: // everything else is unexpected _valid = false; Add(token); break; } }
/// <summary> /// Called before the property name has been detected. /// </summary> public CssProperty CreateDeclarationWith(Func<String, CssProperty> createProperty, ref CssToken token) { var property = default(CssProperty); if (token.Type == CssTokenType.Ident) { var propertyName = token.Data; token = _tokenizer.Get(); if (token.Type != CssTokenType.Colon) { RaiseErrorOccurred(CssParseError.ColonMissing, token); } else { property = _parser.Options.IsIncludingUnknownDeclarations || _parser.Options.IsToleratingInvalidValues ? new CssUnknownProperty(propertyName) : createProperty(propertyName); if (property == null) RaiseErrorOccurred(CssParseError.UnknownDeclarationName, token); var important = false; var val = CreateValue(ref token, out important); if (val == null) RaiseErrorOccurred(CssParseError.ValueMissing, token); else if (property != null && property.TrySetValue(val)) property.IsImportant = important; } _tokenizer.JumpToEndOfDeclaration(); token = _tokenizer.Get(); } else if (token.Type != CssTokenType.Eof) { RaiseErrorOccurred(CssParseError.IdentExpected, token); _tokenizer.JumpToEndOfDeclaration(); token = _tokenizer.Get(); } if (token.Type == CssTokenType.Semicolon) token = _tokenizer.Get(); return property; }
void Add(CssToken token) { if (_buffer != null && !IsCommaOrSlash(token)) { _values.Add(_buffer); } else if (_values.Count != 0 && !IsComma(token) && IsComma(_values[_values.Count - 1])) { _values.Add(CssToken.Whitespace); } _buffer = null; if (_important) { _valid = false; } _values.Add(token); }
/// <summary> /// Resets the builder for reprocessing. /// </summary> public CssValueBuilder Reset() { _open = 0; _valid = true; _buffer = null; _important = false; _values.Clear(); return this; }
static Boolean IsExclamationMark(CssToken token) { return(token.Type == CssTokenType.Delim && token.Data.Has(Symbols.ExclamationMark)); }
static Boolean IsCommaOrSlash(CssToken token) { return(IsComma(token) || IsSlash(token)); }
public Boolean Finished(CssToken token) { return(OnToken(token)); }
/// <summary> /// Checks if the provided token is neither of the first nor the second /// 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> /// <returns>Result of the examination.</returns> public static Boolean IsNot(this CssToken token, CssTokenType a, CssTokenType b) { var type = token.Type; return(type != a && type != b); }
private CssRule SkipDeclarations(CssToken token) { RaiseErrorOccurred(CssParseError.InvalidToken, token.Position); JumpToRuleEnd(ref token); return(default(CssRule)); }
/// <summary> /// Scans the current medium for the @media or @import rule. /// </summary> public CssMedium CreateMedium(ref CssToken token) { var medium = new CssMedium(); CollectTrivia(ref token); if (token.Type == CssTokenType.Ident) { var identifier = token.Data; if (identifier.Isi(Keywords.Not)) { medium.IsInverse = true; token = NextToken(); CollectTrivia(ref token); } else if (identifier.Isi(Keywords.Only)) { medium.IsExclusive = true; token = NextToken(); CollectTrivia(ref token); } } if (token.Type == CssTokenType.Ident) { medium.Type = token.Data; token = NextToken(); CollectTrivia(ref token); if (token.Type != CssTokenType.Ident || !token.Data.Isi(Keywords.And)) { return(medium); } token = NextToken(); CollectTrivia(ref token); } do { if (token.Type != CssTokenType.RoundBracketOpen) { return(null); } token = NextToken(); CollectTrivia(ref token); var feature = CreateFeature(ref token); if (feature != null) { medium.AppendChild(feature); } if (token.Type != CssTokenType.RoundBracketClose) { return(null); } token = NextToken(); CollectTrivia(ref token); if (feature == null) { return(null); } if (token.Type != CssTokenType.Ident || !token.Data.Isi(Keywords.And)) { break; } token = NextToken(); CollectTrivia(ref token); }while (token.Type != CssTokenType.EndOfFile); return(medium); }
/// <summary> /// Called before the property name has been detected. /// </summary> public CssProperty CreateDeclaration(ref CssToken token) { CollectTrivia(ref token); return(CreateDeclarationWith(Factory.Properties.Create, ref token)); }
/// <summary> /// Called before the property name has been detected. /// </summary> public CssProperty CreateDeclarationWith(Func <String, CssProperty> createProperty, ref CssToken token) { var property = default(CssProperty); var sb = Pool.NewStringBuilder(); var start = token.Position; while (token.IsDeclarationName()) { sb.Append(token.ToValue()); token = NextToken(); } var propertyName = sb.ToPool(); if (propertyName.Length > 0) { property = _parser.Options.IsIncludingUnknownDeclarations || _parser.Options.IsToleratingInvalidValues ? new CssUnknownProperty(propertyName) : createProperty(propertyName); if (property == null) { RaiseErrorOccurred(CssParseError.UnknownDeclarationName, start); } else { _nodes.Push(property); } CollectTrivia(ref token); if (token.Type == CssTokenType.Colon) { var important = false; var value = CreateValue(CssTokenType.CurlyBracketClose, ref token, out important); if (value == null) { RaiseErrorOccurred(CssParseError.ValueMissing, token.Position); } else if (property != null && property.TrySetValue(value)) { property.IsImportant = important; } CollectTrivia(ref token); } else { RaiseErrorOccurred(CssParseError.ColonMissing, token.Position); } JumpToDeclEnd(ref token); if (property != null) { _nodes.Pop(); } } else if (token.Type != CssTokenType.EndOfFile) { RaiseErrorOccurred(CssParseError.IdentExpected, start); JumpToDeclEnd(ref token); } if (token.Type == CssTokenType.Semicolon) { token = NextToken(); } return(property); }
/// <summary> /// Called before any token in the value regime had been seen. /// </summary> public IConditionFunction CreateCondition(ref CssToken token) { CollectTrivia(ref token); return(AggregateCondition(ref token)); }
/// <summary> /// Creates a single value. Does not care about the !important flag. /// </summary> public CssValue CreateValue(ref CssToken token) { var important = false; return(CreateValue(CssTokenType.CurlyBracketClose, ref token, out important)); }
/// <summary> /// 4.4.23. Unicode-range State /// </summary> CssToken UnicodeRange(Char current) { for (int i = 0; i < 6; i++) { if (!current.IsHex()) { break; } _stringBuffer.Append(current); current = Next; } if (_stringBuffer.Length != 6) { for (int i = 0; i < 6 - _stringBuffer.Length; i++) { if (current != Specification.QuestionMark) { current = Previous; break; } _stringBuffer.Append(current); current = Next; } var range = FlushBuffer(); var start = range.Replace(Specification.QuestionMark, '0'); var end = range.Replace(Specification.QuestionMark, 'F'); return(CssToken.Range(start, end)); } else if (current == Specification.Minus) { current = Next; if (current.IsHex()) { var start = _stringBuffer.ToString(); _stringBuffer.Clear(); for (int i = 0; i < 6; i++) { if (!current.IsHex()) { current = Previous; break; } _stringBuffer.Append(current); current = Next; } var end = FlushBuffer(); return(CssToken.Range(start, end)); } else { Back(2); return(CssToken.Range(FlushBuffer(), null)); } } else { Back(); return(CssToken.Range(FlushBuffer(), null)); } }
static Boolean IsComma(CssToken token) { return token.Type == CssTokenType.Comma; }
static Boolean IsSlash(CssToken token) { return token.Type == CssTokenType.Delim && token.Data.Has(Symbols.Solidus); }
private List <IConditionFunction> MultipleConditions(IConditionFunction condition, String connector, ref CssToken token) { var list = new List <IConditionFunction>(); CollectTrivia(ref token); list.Add(condition); while (token.Type != CssTokenType.EndOfFile) { condition = ExtractCondition(ref token); if (condition == null) { break; } list.Add(condition); if (!token.Data.Isi(connector)) { break; } token = NextToken(); CollectTrivia(ref token); } return(list); }
/// <summary> /// Tries to read and set media constraints for the provided medium. /// </summary> Boolean TrySetConstraint(CssMedium medium, ref CssToken token) { if (token.Type != CssTokenType.Ident) { _tokenizer.JumpToClosedArguments(); token = _tokenizer.Get(); return false; } var value = Pool.NewValueBuilder(); var featureName = token.Data; token = _tokenizer.Get(); if (token.Type == CssTokenType.Colon) { _tokenizer.State = CssParseMode.Value; token = _tokenizer.Get(); while (token.Type != CssTokenType.RoundBracketClose || value.IsReady == false) { if (token.Type == CssTokenType.Eof) break; value.Apply(token); token = _tokenizer.Get(); } _tokenizer.State = CssParseMode.Data; var val = value.ToPool(); var feature = _parser.Options.IsToleratingInvalidConstraints ? new UnknownMediaFeature(featureName) : Factory.MediaFeatures.Create(featureName); if (feature == null || !feature.TrySetValue(val)) return false; medium.AddConstraint(feature); return true; } return token.Type != CssTokenType.Eof; }
/// <summary> /// Called before the property name has been detected. /// </summary> public CssProperty CreateDeclaration(ref CssToken token) { return CreateDeclarationWith(Factory.Properties.Create, ref token); }
/// <summary> /// 4.4.1. Data state /// </summary> CssToken Data(Char current) { switch (current) { case Symbols.LineFeed: case Symbols.CarriageReturn: case Symbols.Tab: case Symbols.Space: do { current = GetNext(); }while (current.IsSpaceCharacter()); if (_ignoreWs) { return(Data(current)); } Back(); return(CssSpecialCharacter.Whitespace); case Symbols.DoubleQuote: return(StringDQ()); case Symbols.Num: return(HashStart()); case Symbols.Dollar: current = GetNext(); if (current == Symbols.Equality) { return(CssMatchToken.Suffix); } return(CssToken.Delim(GetPrevious())); case Symbols.SingleQuote: return(StringSQ()); case Symbols.RoundBracketOpen: return(CssBracketToken.OpenRound); case Symbols.RoundBracketClose: return(CssBracketToken.CloseRound); case Symbols.Asterisk: current = GetNext(); if (current == Symbols.Equality) { return(CssMatchToken.Substring); } return(CssToken.Delim(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(CssToken.Delim(current)); } case Symbols.Comma: return(CssSpecialCharacter.Comma); case Symbols.Dot: { var c = GetNext(); if (c.IsDigit()) { return(NumberStart(GetPrevious())); } return(CssToken.Delim(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); if (_ignoreCs) { return(Data(GetNext())); } return(CssCommentToken.Close); } } else { Back(); } return(CssToken.Delim(current)); } case Symbols.Solidus: current = GetNext(); if (current == Symbols.Asterisk) { return(Comment()); } return(CssToken.Delim(GetPrevious())); case Symbols.ReverseSolidus: current = GetNext(); if (current.IsLineBreak() || current == Symbols.EndOfFile) { RaiseErrorOccurred(current == Symbols.EndOfFile ? ErrorCode.EOF : ErrorCode.LineBreakUnexpected); return(CssToken.Delim(GetPrevious())); } return(IdentStart(GetPrevious())); case Symbols.Colon: return(CssSpecialCharacter.Colon); case Symbols.Semicolon: return(CssSpecialCharacter.Semicolon); case Symbols.LessThan: current = GetNext(); if (current == Symbols.ExclamationMark) { current = GetNext(); if (current == Symbols.Minus) { current = GetNext(); if (current == Symbols.Minus) { if (_ignoreCs) { return(Data(GetNext())); } return(CssCommentToken.Open); } current = GetPrevious(); } current = GetPrevious(); } return(CssToken.Delim(GetPrevious())); case Symbols.At: return(AtKeywordStart()); case Symbols.SquareBracketOpen: return(CssBracketToken.OpenSquare); case Symbols.SquareBracketClose: return(CssBracketToken.CloseSquare); case Symbols.Accent: current = GetNext(); if (current == Symbols.Equality) { return(CssMatchToken.Prefix); } return(CssToken.Delim(GetPrevious())); case Symbols.CurlyBracketOpen: return(CssBracketToken.OpenCurly); case Symbols.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 = 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(CssMatchToken.Dash); } else if (current == Symbols.Pipe) { return(CssColumnToken.Instance); } return(CssToken.Delim(GetPrevious())); case Symbols.Tilde: current = GetNext(); if (current == Symbols.Equality) { return(CssMatchToken.Include); } return(CssToken.Delim(GetPrevious())); case Symbols.EndOfFile: return(null); case Symbols.ExclamationMark: current = GetNext(); if (current == Symbols.Equality) { return(CssMatchToken.Not); } return(CssToken.Delim(GetPrevious())); default: if (current.IsNameStart()) { return(IdentStart(current)); } return(CssToken.Delim(current)); } }
/// <summary> /// Scans the current medium for the @media or @import rule. /// </summary> public CssMedium CreateMedium(ref CssToken token) { var medium = new CssMedium(); if (token.Type == CssTokenType.Ident) { var identifier = token.Data; if (identifier.Equals(Keywords.Not, StringComparison.OrdinalIgnoreCase)) { medium.IsInverse = true; token = _tokenizer.Get(); } else if (identifier.Equals(Keywords.Only, StringComparison.OrdinalIgnoreCase)) { medium.IsExclusive = true; token = _tokenizer.Get(); } } if (token.Type == CssTokenType.Ident) { medium.Type = token.Data; token = _tokenizer.Get(); if (token.Type != CssTokenType.Ident || String.Compare(token.Data, Keywords.And, StringComparison.OrdinalIgnoreCase) != 0) return medium; token = _tokenizer.Get(); } do { if (token.Type != CssTokenType.RoundBracketOpen) return null; token = _tokenizer.Get(); var couldSetConstraint = TrySetConstraint(medium, ref token); if (token.Type != CssTokenType.RoundBracketClose) return null; token = _tokenizer.Get(); if (couldSetConstraint == false) return null; if (token.Type != CssTokenType.Ident || String.Compare(token.Data, Keywords.And, StringComparison.OrdinalIgnoreCase) != 0) break; token = _tokenizer.Get(); } while (token.Type != CssTokenType.Eof); return medium; }
protected abstract Boolean OnToken(CssToken token);
/// <summary> /// Skips the current declaration. /// </summary> protected CssRule SkipDeclarations(CssToken token) { RaiseErrorOccurred(CssParseError.InvalidToken, token); _tokenizer.SkipUnknownRule(); return null; }
static Boolean IsComma(CssToken token) { return(token.Type == CssTokenType.Comma); }
/// <summary> /// State that is called once we are in a CSS selector. /// </summary> protected ISelector CreateSelector(ref CssToken token) { var selector = Pool.NewSelectorConstructor(); _tokenizer.State = CssParseMode.Selector; var start = token; while (token.IsNot(CssTokenType.Eof, CssTokenType.CurlyBracketOpen, CssTokenType.CurlyBracketClose)) { selector.Apply(token); token = _tokenizer.Get(); } if (selector.IsValid == false) RaiseErrorOccurred(CssParseError.InvalidSelector, start); _tokenizer.State = CssParseMode.Data; return selector.ToPool(); }
static Boolean IsSlash(CssToken token) { return(token.Type == CssTokenType.Delim && token.Data.Has(Symbols.Solidus)); }
/// <summary> /// Called before any token in the value regime had been seen. /// </summary> protected CssValue CreateValue(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, CssTokenType.CurlyBracketClose) || (token.Type == CssTokenType.RoundBracketClose && value.IsReady)) break; value.Apply(token); token = _tokenizer.Get(); } important = value.IsImportant; _tokenizer.State = CssParseMode.Data; return value.ToPool(); }
Boolean CheckImportant(CssToken token) { if (_values.Count != 0 && token.Data == Keywords.Important) { var previous = _values[_values.Count - 1]; if (IsExclamationMark(previous)) { do _values.RemoveAt(_values.Count - 1); while (_values.Count > 0 && _values[_values.Count - 1].Type == CssTokenType.Whitespace); return true; } } Add(token); return _important; }
/// <summary> /// Before the name of a rule has been detected. /// </summary> protected String GetRuleName(ref CssToken token) { var name = String.Empty; if (token.Type == CssTokenType.Ident) { name = token.Data; token = _tokenizer.Get(); } return name; }
static Boolean IsCommaOrSlash(CssToken token) { return IsComma(token) || IsSlash(token); }
/// <summary> /// Before any medium has been found for the @media or @import rule. /// </summary> protected void FillMediaList(MediaList list, ref CssToken token) { if (token.Type != CssTokenType.CurlyBracketOpen) { 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 != CssTokenType.CurlyBracketOpen) { do { if (token.Type == CssTokenType.Eof || token.Type == CssTokenType.Semicolon) break; token = _tokenizer.Get(); } while (token.Type != CssTokenType.CurlyBracketOpen); list.Clear(); } if (list.Length == 0) { list.Add(new CssMedium { IsInverse = true, Type = Keywords.All }); } } }
static Boolean IsExclamationMark(CssToken token) { return token.Type == CssTokenType.Delim && token.Data.Has(Symbols.ExclamationMark); }
/// <summary> /// Fires an error occurred event. /// </summary> /// <param name="code">The associated error code.</param> /// <param name="token">The associated token.</param> protected void RaiseErrorOccurred(CssParseError code, CssToken token) { _tokenizer.RaiseErrorOccurred(code, token.Position); }
public abstract CssRule Create(CssToken current);
/// <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); }