CssBuilder
See http://dev.w3.org/csswg/css-syntax/#parsing for details.
using AngleSharp.Css;
using AngleSharp.Css.Values;
using AngleSharp.Dom;
using AngleSharp.Dom.Collections;
using AngleSharp.Dom.Css;
using AngleSharp.Extensions;
using AngleSharp.Services.Default;
using System;
using System.Collections.Generic;
using System.Text;
namespace AngleSharp.Parser.Css
{
internal sealed class CssBuilder
{
private readonly CssTokenizer _tokenizer;
private readonly CssParser _parser;
private readonly Stack<CssNode> _nodes;
public CssBuilder(CssTokenizer tokenizer, CssParser parser)
{
_tokenizer = tokenizer;
_parser = parser;
_nodes = new Stack<CssNode>();
}
public CssRule CreateAtRule(CssToken token)
{
if (token.Data.Is(RuleNames.Media))
return CreateMedia(token);
if (token.Data.Is(RuleNames.FontFace))
return CreateFontFace(token);
if (token.Data.Is(RuleNames.Keyframes))
return CreateKeyframes(token);
if (token.Data.Is(RuleNames.Import))
return CreateImport(token);
if (token.Data.Is(RuleNames.Charset))
return CreateCharset(token);
if (token.Data.Is(RuleNames.Namespace))
return CreateNamespace(token);
if (token.Data.Is(RuleNames.Page))
return CreatePage(token);
if (token.Data.Is(RuleNames.Supports))
return CreateSupports(token);
if (token.Data.Is(RuleNames.ViewPort))
return CreateViewport(token);
if (token.Data.Is(RuleNames.Document))
return CreateDocument(token);
return CreateUnknown(token);
}
public CssRule CreateRule(CssToken token)
{
switch (token.Type) {
case CssTokenType.AtKeyword:
return CreateAtRule(token);
case CssTokenType.CurlyBracketOpen:
RaiseErrorOccurred(CssParseError.InvalidBlockStart, token.Position);
JumpToRuleEnd(ref token);
return null;
case CssTokenType.String:
case CssTokenType.Url:
case CssTokenType.RoundBracketClose:
case CssTokenType.CurlyBracketClose:
case CssTokenType.SquareBracketClose:
RaiseErrorOccurred(CssParseError.InvalidToken, token.Position);
JumpToRuleEnd(ref token);
return null;
default:
return CreateStyle(token);
}
}
public CssRule CreateCharset(CssToken current)
{
CssCharsetRule cssCharsetRule = new CssCharsetRule(_parser);
TextPosition position = current.Position;
CssToken token = NextToken();
_nodes.Push(cssCharsetRule);
CollectTrivia(ref token);
if (token.Type == CssTokenType.String)
cssCharsetRule.CharacterSet = token.Data;
JumpToEnd(ref token);
cssCharsetRule.SourceCode = CreateView(position, token.Position);
_nodes.Pop();
return cssCharsetRule;
}
public CssRule CreateDocument(CssToken current)
{
CssDocumentRule rule = new CssDocumentRule(_parser);
TextPosition position = current.Position;
CssToken token = NextToken();
_nodes.Push(rule);
CollectTrivia(ref token);
FillFunctions(delegate(DocumentFunction function) {
rule.AppendChild(function);
}, ref token);
CollectTrivia(ref token);
if (token.Type == CssTokenType.CurlyBracketOpen) {
TextPosition end = FillRules(rule);
rule.SourceCode = CreateView(position, end);
_nodes.Pop();
return rule;
}
_nodes.Pop();
return SkipDeclarations(token);
}
public CssRule CreateViewport(CssToken current)
{
CssViewportRule cssViewportRule = new CssViewportRule(_parser);
TextPosition position = current.Position;
CssToken token = NextToken();
_nodes.Push(cssViewportRule);
CollectTrivia(ref token);
if (token.Type == CssTokenType.CurlyBracketOpen) {
CssViewportRule rule = cssViewportRule;
CssPropertyFactory properties = Factory.Properties;
TextPosition end = FillDeclarations(rule, properties.CreateViewport);
cssViewportRule.SourceCode = CreateView(position, end);
_nodes.Pop();
return cssViewportRule;
}
_nodes.Pop();
return SkipDeclarations(token);
}
public CssRule CreateFontFace(CssToken current)
{
CssFontFaceRule cssFontFaceRule = new CssFontFaceRule(_parser);
TextPosition position = current.Position;
CssToken token = NextToken();
_nodes.Push(cssFontFaceRule);
CollectTrivia(ref token);
if (token.Type == CssTokenType.CurlyBracketOpen) {
CssFontFaceRule rule = cssFontFaceRule;
CssPropertyFactory properties = Factory.Properties;
TextPosition end = FillDeclarations(rule, properties.CreateFont);
cssFontFaceRule.SourceCode = CreateView(position, end);
_nodes.Pop();
return cssFontFaceRule;
}
_nodes.Pop();
return SkipDeclarations(token);
}
public CssRule CreateImport(CssToken current)
{
CssImportRule cssImportRule = new CssImportRule(_parser);
TextPosition position = current.Position;
CssToken token = NextToken();
_nodes.Push(cssImportRule);
CollectTrivia(ref token);
if (token.Is(CssTokenType.String, CssTokenType.Url)) {
cssImportRule.Href = token.Data;
token = NextToken();
CollectTrivia(ref token);
FillMediaList(cssImportRule.Media, CssTokenType.Semicolon, ref token);
}
CollectTrivia(ref token);
JumpToEnd(ref token);
cssImportRule.SourceCode = CreateView(position, token.Position);
_nodes.Pop();
return cssImportRule;
}
public CssRule CreateKeyframes(CssToken current)
{
CssKeyframesRule cssKeyframesRule = new CssKeyframesRule(_parser);
TextPosition position = current.Position;
CssToken token = NextToken();
_nodes.Push(cssKeyframesRule);
CollectTrivia(ref token);
cssKeyframesRule.Name = GetRuleName(ref token);
CollectTrivia(ref token);
if (token.Type == CssTokenType.CurlyBracketOpen) {
TextPosition end = FillKeyframeRules(cssKeyframesRule);
cssKeyframesRule.SourceCode = CreateView(position, end);
_nodes.Pop();
return cssKeyframesRule;
}
_nodes.Pop();
return SkipDeclarations(token);
}
public CssRule CreateMedia(CssToken current)
{
CssMediaRule cssMediaRule = new CssMediaRule(_parser);
TextPosition position = current.Position;
CssToken token = NextToken();
_nodes.Push(cssMediaRule);
CollectTrivia(ref token);
FillMediaList(cssMediaRule.Media, CssTokenType.CurlyBracketOpen, ref token);
CollectTrivia(ref token);
if (token.Type != CssTokenType.CurlyBracketOpen) {
while (token.Type != CssTokenType.EndOfFile) {
if (token.Type == CssTokenType.Semicolon) {
_nodes.Pop();
return null;
}
if (token.Type == CssTokenType.CurlyBracketOpen)
break;
token = NextToken();
}
}
TextPosition end = FillRules(cssMediaRule);
cssMediaRule.SourceCode = CreateView(position, end);
_nodes.Pop();
return cssMediaRule;
}
public CssRule CreateNamespace(CssToken current)
{
CssNamespaceRule cssNamespaceRule = new CssNamespaceRule(_parser);
TextPosition position = current.Position;
CssToken token = NextToken();
_nodes.Push(cssNamespaceRule);
CollectTrivia(ref token);
cssNamespaceRule.Prefix = GetRuleName(ref token);
CollectTrivia(ref token);
if (token.Type == CssTokenType.Url)
cssNamespaceRule.NamespaceUri = token.Data;
JumpToEnd(ref token);
cssNamespaceRule.SourceCode = CreateView(position, token.Position);
_nodes.Pop();
return cssNamespaceRule;
}
public CssRule CreatePage(CssToken current)
{
CssPageRule cssPageRule = new CssPageRule(_parser);
TextPosition position = current.Position;
CssToken token = NextToken();
_nodes.Push(cssPageRule);
CollectTrivia(ref token);
cssPageRule.Selector = CreateSelector(ref token);
CollectTrivia(ref token);
if (token.Type == CssTokenType.CurlyBracketOpen) {
TextPosition end = FillDeclarations(cssPageRule.Style);
cssPageRule.SourceCode = CreateView(position, end);
_nodes.Pop();
return cssPageRule;
}
_nodes.Pop();
return SkipDeclarations(token);
}
public CssRule CreateSupports(CssToken current)
{
CssSupportsRule cssSupportsRule = new CssSupportsRule(_parser);
TextPosition position = current.Position;
CssToken token = NextToken();
_nodes.Push(cssSupportsRule);
CollectTrivia(ref token);
cssSupportsRule.Condition = AggregateCondition(ref token);
CollectTrivia(ref token);
if (token.Type == CssTokenType.CurlyBracketOpen) {
TextPosition end = FillRules(cssSupportsRule);
cssSupportsRule.SourceCode = CreateView(position, end);
_nodes.Pop();
return cssSupportsRule;
}
_nodes.Pop();
return SkipDeclarations(token);
}
public CssRule CreateStyle(CssToken current)
{
CssStyleRule cssStyleRule = new CssStyleRule(_parser);
TextPosition position = current.Position;
_nodes.Push(cssStyleRule);
CollectTrivia(ref current);
cssStyleRule.Selector = CreateSelector(ref current);
TextPosition end = FillDeclarations(cssStyleRule.Style);
cssStyleRule.SourceCode = CreateView(position, end);
_nodes.Pop();
if (cssStyleRule.Selector == null)
return null;
return cssStyleRule;
}
public CssKeyframeRule CreateKeyframeRule(CssToken current)
{
CssKeyframeRule cssKeyframeRule = new CssKeyframeRule(_parser);
TextPosition position = current.Position;
_nodes.Push(cssKeyframeRule);
CollectTrivia(ref current);
cssKeyframeRule.Key = CreateKeyframeSelector(ref current);
TextPosition end = FillDeclarations(cssKeyframeRule.Style);
cssKeyframeRule.SourceCode = CreateView(position, end);
_nodes.Pop();
if (cssKeyframeRule.Key == null)
return null;
return cssKeyframeRule;
}
public CssRule CreateUnknown(CssToken current)
{
TextPosition position = current.Position;
if (_parser.Options.IsIncludingUnknownRules) {
CssToken cssToken = NextToken();
CssUnknownRule cssUnknownRule = new CssUnknownRule(current.Data, _parser);
_nodes.Push(cssUnknownRule);
while (cssToken.IsNot(CssTokenType.CurlyBracketOpen, CssTokenType.Semicolon, CssTokenType.EndOfFile)) {
cssToken = NextToken();
}
if (cssToken.Type == CssTokenType.CurlyBracketOpen) {
int num = 1;
do {
cssToken = NextToken();
switch (cssToken.Type) {
case CssTokenType.CurlyBracketOpen:
num++;
break;
case CssTokenType.CurlyBracketClose:
num--;
break;
case CssTokenType.EndOfFile:
num = 0;
break;
}
} while (num != 0);
}
cssUnknownRule.SourceCode = CreateView(position, cssToken.Position);
_nodes.Pop();
return cssUnknownRule;
}
RaiseErrorOccurred(CssParseError.UnknownAtRule, position);
JumpToRuleEnd(ref current);
return null;
}
public CssValue CreateValue(ref CssToken token)
{
bool important = false;
return CreateValue(CssTokenType.CurlyBracketClose, ref token, out important);
}
public List<CssMedium> CreateMedia(ref CssToken token)
{
List<CssMedium> list = new List<CssMedium>();
CollectTrivia(ref token);
while (token.Type != CssTokenType.EndOfFile) {
CssMedium cssMedium = CreateMedium(ref token);
if (cssMedium == null || token.IsNot(CssTokenType.Comma, CssTokenType.EndOfFile))
throw new DomException(DomError.Syntax);
token = NextToken();
CollectTrivia(ref token);
list.Add(cssMedium);
}
return list;
}
public TextPosition CreateRules(CssStyleSheet sheet)
{
CssToken token = NextToken();
_nodes.Push(sheet);
CollectTrivia(ref token);
while (token.Type != CssTokenType.EndOfFile) {
CssRule rule = CreateRule(token);
token = NextToken();
CollectTrivia(ref token);
sheet.Rules.Add(rule);
}
_nodes.Pop();
return token.Position;
}
public IConditionFunction CreateCondition(ref CssToken token)
{
CollectTrivia(ref token);
return AggregateCondition(ref token);
}
public KeyframeSelector CreateKeyframeSelector(ref CssToken token)
{
List<Percent> list = new List<Percent>();
bool flag = true;
TextPosition position = token.Position;
CollectTrivia(ref token);
while (token.Type != CssTokenType.EndOfFile) {
if (list.Count > 0) {
if (token.Type == CssTokenType.CurlyBracketOpen)
break;
if (token.Type != CssTokenType.Comma)
flag = false;
else
token = NextToken();
CollectTrivia(ref token);
}
if (token.Type == CssTokenType.Percentage)
list.Add(new Percent(((CssUnitToken)token).Value));
else if (token.Type == CssTokenType.Ident && token.Data.Is(Keywords.From)) {
list.Add(Percent.Zero);
} else if (token.Type == CssTokenType.Ident && token.Data.Is(Keywords.To)) {
list.Add(Percent.Hundred);
} else {
flag = false;
}
token = NextToken();
CollectTrivia(ref token);
}
if (!flag)
RaiseErrorOccurred(CssParseError.InvalidSelector, position);
return new KeyframeSelector(list);
}
public List<DocumentFunction> CreateFunctions(ref CssToken token)
{
List<DocumentFunction> functions = new List<DocumentFunction>();
CollectTrivia(ref token);
FillFunctions(delegate(DocumentFunction function) {
functions.Add(function);
}, ref token);
return functions;
}
public TextPosition FillDeclarations(CssStyleDeclaration style)
{
CssToken token = NextToken();
_nodes.Push(style);
CollectTrivia(ref token);
while (token.IsNot(CssTokenType.EndOfFile, CssTokenType.CurlyBracketClose)) {
CssPropertyFactory properties = Factory.Properties;
CssProperty cssProperty = CreateDeclarationWith(properties.Create, ref token);
if (cssProperty != null && cssProperty.HasValue)
style.SetProperty(cssProperty);
CollectTrivia(ref token);
}
_nodes.Pop();
return token.Position;
}
public CssProperty CreateDeclarationWith(Func<string, CssProperty> createProperty, ref CssToken token)
{
CssProperty cssProperty = null;
StringBuilder stringBuilder = Pool.NewStringBuilder();
TextPosition position = token.Position;
while (token.IsDeclarationName()) {
stringBuilder.Append(token.ToValue());
token = NextToken();
}
string text = stringBuilder.ToPool();
object obj;
if (text.Length > 0) {
CssParserOptions options = _parser.Options;
if (!options.IsIncludingUnknownDeclarations) {
options = _parser.Options;
if (!options.IsToleratingInvalidValues) {
obj = createProperty(text);
goto IL_007f;
}
}
obj = new CssUnknownProperty(text);
goto IL_007f;
}
if (token.Type != CssTokenType.EndOfFile) {
RaiseErrorOccurred(CssParseError.IdentExpected, position);
JumpToDeclEnd(ref token);
}
goto IL_0131;
IL_007f:
cssProperty = (CssProperty)obj;
if (cssProperty == null)
RaiseErrorOccurred(CssParseError.UnknownDeclarationName, position);
else
_nodes.Push(cssProperty);
CollectTrivia(ref token);
if (token.Type == CssTokenType.Colon) {
bool important = false;
CssValue cssValue = CreateValue(CssTokenType.CurlyBracketClose, ref token, out important);
if (cssValue == null)
RaiseErrorOccurred(CssParseError.ValueMissing, token.Position);
else if (cssProperty != null && cssProperty.TrySetValue(cssValue)) {
cssProperty.IsImportant = important;
}
CollectTrivia(ref token);
} else
RaiseErrorOccurred(CssParseError.ColonMissing, token.Position);
JumpToDeclEnd(ref token);
if (cssProperty != null)
_nodes.Pop();
goto IL_0131;
IL_0131:
if (token.Type == CssTokenType.Semicolon)
token = NextToken();
return cssProperty;
}
public CssProperty CreateDeclaration(ref CssToken token)
{
CollectTrivia(ref token);
CssPropertyFactory properties = Factory.Properties;
return CreateDeclarationWith(properties.Create, ref token);
}
public CssMedium CreateMedium(ref CssToken token)
{
CssMedium cssMedium = new CssMedium();
CollectTrivia(ref token);
if (token.Type == CssTokenType.Ident) {
string data = token.Data;
if (data.Isi(Keywords.Not)) {
cssMedium.IsInverse = true;
token = NextToken();
CollectTrivia(ref token);
} else if (data.Isi(Keywords.Only)) {
cssMedium.IsExclusive = true;
token = NextToken();
CollectTrivia(ref token);
}
}
if (token.Type == CssTokenType.Ident) {
cssMedium.Type = token.Data;
token = NextToken();
CollectTrivia(ref token);
if (token.Type != CssTokenType.Ident || !token.Data.Isi(Keywords.And))
return cssMedium;
token = NextToken();
CollectTrivia(ref token);
}
do {
if (token.Type != CssTokenType.RoundBracketOpen)
return null;
token = NextToken();
CollectTrivia(ref token);
MediaFeature mediaFeature = CreateFeature(ref token);
if (mediaFeature != null)
cssMedium.AppendChild(mediaFeature);
if (token.Type != CssTokenType.RoundBracketClose)
return null;
token = NextToken();
CollectTrivia(ref token);
if (mediaFeature == 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 cssMedium;
}
private void JumpToEnd(ref CssToken current)
{
while (current.IsNot(CssTokenType.EndOfFile, CssTokenType.Semicolon)) {
current = NextToken();
}
}
private void JumpToRuleEnd(ref CssToken current)
{
int num = 0;
while (current.Type != CssTokenType.EndOfFile) {
if (current.Type == CssTokenType.CurlyBracketOpen)
num++;
else if (current.Type == CssTokenType.CurlyBracketClose) {
num--;
}
if (num <= 0 && current.Is(CssTokenType.CurlyBracketClose, CssTokenType.Semicolon))
break;
current = NextToken();
}
}
private void JumpToArgEnd(ref CssToken current)
{
int num = 0;
while (current.Type != CssTokenType.EndOfFile) {
if (current.Type == CssTokenType.RoundBracketOpen)
num++;
else {
if (num <= 0 && current.Type == CssTokenType.RoundBracketClose)
break;
if (current.Type == CssTokenType.RoundBracketClose)
num--;
}
current = NextToken();
}
}
private void JumpToDeclEnd(ref CssToken current)
{
int num = 0;
while (current.Type != CssTokenType.EndOfFile) {
if (current.Type == CssTokenType.CurlyBracketOpen)
num++;
else {
if (num <= 0 && current.Is(CssTokenType.CurlyBracketClose, CssTokenType.Semicolon))
break;
if (current.Type == CssTokenType.CurlyBracketClose)
num--;
}
current = NextToken();
}
}
private CssToken NextToken()
{
return _tokenizer.Get();
}
private TextView CreateView(TextPosition start, TextPosition end)
{
return new TextView(new TextRange(start, end), _tokenizer.Source);
}
private void CollectTrivia(ref CssToken token)
{
bool isStoringTrivia = _parser.Options.IsStoringTrivia;
while (token.Type == CssTokenType.Whitespace || token.Type == CssTokenType.Comment || token.Type == CssTokenType.Cdc || token.Type == CssTokenType.Cdo) {
if (isStoringTrivia && token.Type == CssTokenType.Comment) {
CssNode cssNode = _nodes.Peek();
CssComment cssComment = new CssComment(token.Data);
TextPosition position = token.Position;
cssComment.SourceCode = CreateView(end: position.After(token.ToValue()), start: position);
cssNode.AppendChild(cssComment);
}
token = _tokenizer.Get();
}
}
private CssRule SkipDeclarations(CssToken token)
{
RaiseErrorOccurred(CssParseError.InvalidToken, token.Position);
JumpToRuleEnd(ref token);
return null;
}
private void RaiseErrorOccurred(CssParseError code, TextPosition position)
{
_tokenizer.RaiseErrorOccurred(code, position);
}
private IConditionFunction AggregateCondition(ref CssToken token)
{
IConditionFunction conditionFunction = ExtractCondition(ref token);
if (conditionFunction != null) {
CollectTrivia(ref token);
string data = token.Data;
Func<IEnumerable<IConditionFunction>, IConditionFunction> creator = data.GetCreator();
if (creator != null) {
token = NextToken();
CollectTrivia(ref token);
List<IConditionFunction> arg = MultipleConditions(conditionFunction, data, ref token);
conditionFunction = creator(arg);
}
}
return conditionFunction;
}
private IConditionFunction ExtractCondition(ref CssToken token)
{
if (token.Type == CssTokenType.RoundBracketOpen) {
token = NextToken();
CollectTrivia(ref token);
IConditionFunction conditionFunction = AggregateCondition(ref token);
if (conditionFunction != null)
conditionFunction = new GroupCondition {
Content = conditionFunction
};
else if (token.Type == CssTokenType.Ident) {
conditionFunction = DeclarationCondition(ref token);
}
if (token.Type == CssTokenType.RoundBracketClose) {
token = NextToken();
CollectTrivia(ref token);
}
return conditionFunction;
}
if (token.Data.Isi(Keywords.Not)) {
NotCondition notCondition = new NotCondition();
token = NextToken();
CollectTrivia(ref token);
notCondition.Content = ExtractCondition(ref token);
return notCondition;
}
return null;
}
private IConditionFunction DeclarationCondition(ref CssToken token)
{
CssProperty cssProperty = Factory.Properties.Create(token.Data) ?? new CssUnknownProperty(token.Data);
DeclarationCondition result = null;
token = NextToken();
CollectTrivia(ref token);
if (token.Type == CssTokenType.Colon) {
bool important = false;
CssValue cssValue = CreateValue(CssTokenType.RoundBracketClose, ref token, out important);
cssProperty.IsImportant = important;
if (cssValue != null)
result = new DeclarationCondition(cssProperty, cssValue);
}
return result;
}
private List<IConditionFunction> MultipleConditions(IConditionFunction condition, string connector, ref CssToken token)
{
List<IConditionFunction> 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;
}
private void FillFunctions(Action<DocumentFunction> add, ref CssToken token)
{
do {
DocumentFunction documentFunction = token.ToDocumentFunction();
if (documentFunction == null)
break;
token = NextToken();
CollectTrivia(ref token);
add(documentFunction);
if (token.Type != CssTokenType.Comma)
break;
token = NextToken();
CollectTrivia(ref token);
} while (token.Type != CssTokenType.EndOfFile);
}
private TextPosition FillKeyframeRules(CssKeyframesRule parentRule)
{
CssToken token = NextToken();
CollectTrivia(ref token);
while (token.IsNot(CssTokenType.EndOfFile, CssTokenType.CurlyBracketClose)) {
CssKeyframeRule rule = CreateKeyframeRule(token);
token = NextToken();
CollectTrivia(ref token);
parentRule.Rules.Add(rule);
}
return token.Position;
}
private TextPosition FillDeclarations(CssDeclarationRule rule, Func<string, CssProperty> createProperty)
{
CssToken token = NextToken();
CollectTrivia(ref token);
while (token.IsNot(CssTokenType.EndOfFile, CssTokenType.CurlyBracketClose)) {
CssProperty cssProperty = CreateDeclarationWith(createProperty, ref token);
if (cssProperty != null && cssProperty.HasValue)
rule.SetProperty(cssProperty);
CollectTrivia(ref token);
}
return token.Position;
}
private TextPosition FillRules(CssGroupingRule group)
{
CssToken token = NextToken();
CollectTrivia(ref token);
while (token.IsNot(CssTokenType.EndOfFile, CssTokenType.CurlyBracketClose)) {
CssRule rule = CreateRule(token);
token = NextToken();
CollectTrivia(ref token);
group.Rules.Add(rule);
}
return token.Position;
}
private void FillMediaList(MediaList list, CssTokenType end, ref CssToken token)
{
_nodes.Push(list);
if (token.Type != end) {
while (token.Type != CssTokenType.EndOfFile) {
CssMedium cssMedium = CreateMedium(ref token);
if (cssMedium != null)
list.AppendChild(cssMedium);
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();
}
private ISelector CreateSelector(ref CssToken token)
{
CssSelectorConstructor selectorCreator = _parser.GetSelectorCreator();
TextPosition position = token.Position;
while (token.IsNot(CssTokenType.EndOfFile, CssTokenType.CurlyBracketOpen, CssTokenType.CurlyBracketClose)) {
selectorCreator.Apply(token);
token = NextToken();
}
bool isValid = selectorCreator.IsValid;
ISelector selector = selectorCreator.ToPool();
CssNode cssNode = selector as CssNode;
if (cssNode != null) {
TextPosition end = token.Position.Shift(-1);
cssNode.SourceCode = CreateView(position, end);
}
if (!isValid && !_parser.Options.IsToleratingInvalidValues) {
RaiseErrorOccurred(CssParseError.InvalidSelector, position);
selector = null;
}
return selector;
}
private CssValue CreateValue(CssTokenType closing, ref CssToken token, out bool important)
{
CssValueBuilder cssValueBuilder = Pool.NewValueBuilder();
_tokenizer.IsInValue = true;
token = NextToken();
TextPosition position = token.Position;
while (token.IsNot(CssTokenType.EndOfFile, CssTokenType.Semicolon, closing)) {
cssValueBuilder.Apply(token);
token = NextToken();
}
important = cssValueBuilder.IsImportant;
_tokenizer.IsInValue = false;
bool isValid = cssValueBuilder.IsValid;
CssValue cssValue = cssValueBuilder.ToPool();
CssNode cssNode = cssValue;
if (cssNode != null) {
TextPosition end = token.Position.Shift(-1);
cssNode.SourceCode = CreateView(position, end);
}
if (!isValid && !_parser.Options.IsToleratingInvalidValues) {
RaiseErrorOccurred(CssParseError.InvalidValue, position);
cssValue = null;
}
return cssValue;
}
private string GetRuleName(ref CssToken token)
{
string result = string.Empty;
if (token.Type == CssTokenType.Ident) {
result = token.Data;
token = NextToken();
}
return result;
}
private MediaFeature CreateFeature(ref CssToken token)
{
if (token.Type == CssTokenType.Ident) {
TextPosition position = token.Position;
CssValue value = CssValue.Empty;
MediaFeature mediaFeature = _parser.Options.IsToleratingInvalidConstraints ? new UnknownMediaFeature(token.Data) : Factory.MediaFeatures.Create(token.Data);
token = NextToken();
if (token.Type == CssTokenType.Colon) {
CssValueBuilder cssValueBuilder = Pool.NewValueBuilder();
token = NextToken();
while (token.IsNot(CssTokenType.RoundBracketClose, CssTokenType.EndOfFile) || !cssValueBuilder.IsReady) {
cssValueBuilder.Apply(token);
token = NextToken();
}
value = cssValueBuilder.ToPool();
} else if (token.Type == CssTokenType.EndOfFile) {
return null;
}
if (mediaFeature != null && mediaFeature.TrySetValue(value)) {
CssNode cssNode = mediaFeature;
if (cssNode != null) {
TextPosition end = token.Position.Shift(-1);
cssNode.SourceCode = CreateView(position, end);
}
return mediaFeature;
}
} else
JumpToArgEnd(ref token);
return null;
}
}
}