CssParser
The CSS parser.
See http://dev.w3.org/csswg/css-syntax/#parsing for more details.
using AngleSharp.Css;
using AngleSharp.Dom;
using AngleSharp.Dom.Css;
using AngleSharp.Events;
using AngleSharp.Extensions;
using AngleSharp.Parser.Css.States;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace AngleSharp.Parser.Css
{
[DebuggerStepThrough]
public sealed class CssParser
{
private readonly CssTokenizer _tokenizer;
private readonly object _syncGuard;
private readonly CssStyleSheet _sheet;
private bool _started;
private Task<ICssStyleSheet> _task;
public bool IsAsync => _task != null;
public ICssStyleSheet Result {
get {
Parse();
return _sheet;
}
}
public CssParser(string source, IConfiguration configuration = null)
: this(new CssStyleSheet(configuration, new TextSource(source)))
{
}
public CssParser(Stream stream, IConfiguration configuration = null)
: this(new CssStyleSheet(configuration, new TextSource(stream, configuration.DefaultEncoding())))
{
}
internal CssParser(CssStyleSheet stylesheet)
{
IElement ownerNode = stylesheet.OwnerNode;
_syncGuard = new object();
_tokenizer = new CssTokenizer(stylesheet.Source, stylesheet.Options.Events);
_started = false;
_sheet = stylesheet;
}
public Task<ICssStyleSheet> ParseAsync()
{
return ParseAsync(default(CssParserOptions));
}
public Task<ICssStyleSheet> ParseAsync(CssParserOptions options)
{
return ParseAsync(options, CancellationToken.None);
}
public Task<ICssStyleSheet> ParseAsync(CssParserOptions options, CancellationToken cancelToken)
{
lock (_syncGuard) {
if (!_started) {
_started = true;
_task = KernelAsync(options, cancelToken);
}
}
return _task;
}
public ICssStyleSheet Parse()
{
return Parse(default(CssParserOptions));
}
public ICssStyleSheet Parse(CssParserOptions options)
{
if (!_started) {
_started = true;
Kernel(options);
}
return _sheet;
}
private static CssTokenizer CreateTokenizer(string sourceCode, IConfiguration configuration)
{
IEventAggregator events = configuration?.Events;
TextSource source = new TextSource(sourceCode);
return new CssTokenizer(source, events);
}
private void Kernel(CssParserOptions options)
{
CssToken cssToken = _tokenizer.Get();
do {
CssRule rule = _tokenizer.CreateRule(cssToken, options);
_sheet.AddRule(rule);
cssToken = _tokenizer.Get();
} while (cssToken.Type != CssTokenType.Eof);
}
private async Task<ICssStyleSheet> KernelAsync(CssParserOptions options, CancellationToken cancelToken)
{
await _sheet.Source.PrefetchAll(cancelToken).ConfigureAwait(false);
Kernel(options);
return _sheet;
}
public static ISelector ParseSelector(string selectorText)
{
CssTokenizer cssTokenizer = CreateTokenizer(selectorText, null);
cssTokenizer.State = CssParseMode.Selector;
CssSelectorConstructor cssSelectorConstructor = Pool.NewSelectorConstructor();
CssToken cssToken = cssTokenizer.Get();
while (cssToken.Type != CssTokenType.Eof) {
cssSelectorConstructor.Apply(cssToken);
cssToken = cssTokenizer.Get();
}
return cssSelectorConstructor.ToPool();
}
public static IKeyframeSelector ParseKeyframeSelector(string keyText)
{
CssTokenizer cssTokenizer = CreateTokenizer(keyText, null);
CssToken token = cssTokenizer.Get();
CssKeyframesState cssKeyframesState = new CssKeyframesState(cssTokenizer, default(CssParserOptions));
KeyframeSelector result = cssKeyframesState.CreateKeyframeSelector(ref token);
if (token.Type != CssTokenType.Eof)
return null;
return result;
}
internal static CssValue ParseValue(string valueText)
{
CssTokenizer tokenizer = CreateTokenizer(valueText, null);
CssToken token = null;
CssUnknownState cssUnknownState = new CssUnknownState(tokenizer, default(CssParserOptions));
CssValue result = cssUnknownState.CreateValue(ref token);
if (token.Type != CssTokenType.Eof)
return null;
return result;
}
internal static CssRule ParseRule(string ruleText)
{
CssTokenizer cssTokenizer = CreateTokenizer(ruleText, null);
CssToken token = cssTokenizer.Get();
CssRule result = cssTokenizer.CreateRule(token, default(CssParserOptions));
if (cssTokenizer.Get().Type != CssTokenType.Eof)
return null;
return result;
}
internal static CssStyleDeclaration ParseDeclarations(string declarations)
{
CssStyleDeclaration cssStyleDeclaration = new CssStyleDeclaration((string)null);
AppendDeclarations(cssStyleDeclaration, declarations);
return cssStyleDeclaration;
}
internal static CssProperty ParseDeclaration(string declarationText)
{
return ParseDeclaration(declarationText, default(CssParserOptions));
}
internal static CssProperty ParseDeclaration(string declarationText, CssParserOptions options)
{
CssTokenizer cssTokenizer = CreateTokenizer(declarationText, null);
CssToken token = cssTokenizer.Get();
CssUnknownState cssUnknownState = new CssUnknownState(cssTokenizer, options);
CssProperty result = cssUnknownState.CreateDeclaration(ref token);
if (token.Type != CssTokenType.Eof)
return null;
return result;
}
internal static List<CssMedium> ParseMediaList(string mediaText)
{
CssTokenizer cssTokenizer = CreateTokenizer(mediaText, null);
CssToken token = cssTokenizer.Get();
CssUnknownState cssUnknownState = new CssUnknownState(cssTokenizer, default(CssParserOptions));
List<CssMedium> result = cssUnknownState.CreateMedia(ref token);
if (token.Type != CssTokenType.Eof)
return null;
return result;
}
internal static ICondition ParseCondition(string conditionText)
{
CssTokenizer cssTokenizer = CreateTokenizer(conditionText, null);
CssToken token = cssTokenizer.Get();
CssSupportsState cssSupportsState = new CssSupportsState(cssTokenizer, default(CssParserOptions));
ICondition result = cssSupportsState.CreateCondition(ref token);
if (token.Type != CssTokenType.Eof)
return null;
return result;
}
internal static List<IDocumentFunction> ParseDocumentRules(string source)
{
CssTokenizer cssTokenizer = CreateTokenizer(source, null);
CssToken token = cssTokenizer.Get();
CssDocumentState cssDocumentState = new CssDocumentState(cssTokenizer, default(CssParserOptions));
List<IDocumentFunction> result = cssDocumentState.CreateFunctions(ref token);
if (token.Type != CssTokenType.Eof)
return null;
return result;
}
internal static CssMedium ParseMedium(string source)
{
CssTokenizer cssTokenizer = CreateTokenizer(source, null);
CssToken token = cssTokenizer.Get();
CssUnknownState cssUnknownState = new CssUnknownState(cssTokenizer, default(CssParserOptions));
CssMedium result = cssUnknownState.CreateMedium(ref token);
if (token.Type != CssTokenType.Eof)
return null;
return result;
}
internal static CssKeyframeRule ParseKeyframeRule(string ruleText)
{
CssTokenizer cssTokenizer = CreateTokenizer(ruleText, null);
CssToken token = cssTokenizer.Get();
CssKeyframesState cssKeyframesState = new CssKeyframesState(cssTokenizer, default(CssParserOptions));
CssKeyframeRule result = cssKeyframesState.CreateKeyframeRule(token);
if (cssTokenizer.Get().Type != CssTokenType.Eof)
return null;
return result;
}
internal static void AppendDeclarations(CssStyleDeclaration style, string declarations)
{
CssTokenizer tokenizer = CreateTokenizer(declarations, null);
CssUnknownState cssUnknownState = new CssUnknownState(tokenizer, default(CssParserOptions));
cssUnknownState.FillDeclarations(style);
}
}
}