/// <summary> /// (BNF) at-rule : ATKEYWORD S* any* [ block | ';' S* ]; /// </summary> /// <returns></returns> /// <remarks> /// NOTE: each at-rule might parse differently according to CSS3 /// The @media block for example contains a block of statements /// while other at-rules with a block contain a block of declarations /// </remarks> private CssAtRule ParseAtRule() { CssAtRule atRule = new CssAtRule(); int start = this.Position + 1;// start with first char of ident char ch; while (this.Read(out ch) && !Char.IsWhiteSpace(ch)) { // continue consuming } atRule.Ident = this.Copy(start); while (this.Read(out ch) && Char.IsWhiteSpace(ch)) { // consuming whitespace } start = this.Position;// start with current char do { switch (ch) { case '{': //Block Begin { atRule.Value = this.Copy(start); bool containsRuleSets = String.Equals(atRule.Ident, CssAtRule.MediaIdent, StringComparison.Ordinal); while (true) { while (this.Read(out ch) && Char.IsWhiteSpace(ch)) { // consume whitespace } if (ch == '}') { break; } try { if (containsRuleSets) { // includes @media CssStatement statement = this.ParseStatement(); atRule.Block.Values.Add(statement); } else { // includes @font-face, @page this.PutBack(); CssDeclaration declaration = this.ParseDeclaration(); atRule.Block.Values.Add(declaration); } } catch (ParseException ex) { this.errors.Add(ex); while (this.Read(out ch) && ch != '}') { // restabilize on block end } break; } } return(atRule); } case ';': //At-Rule End { atRule.Value = this.Copy(start); return(atRule); } } } while (this.Read(out ch)); throw new UnexpectedEndOfFile("Unclosed At-Rule", this.reader.FilePath, this.reader.Line, this.reader.Column); }
/// <summary> /// (BNF) at-rule : ATKEYWORD S* any* [ block | ';' S* ]; /// </summary> /// <returns></returns> /// <remarks> /// NOTE: each at-rule might parse differently according to CSS3 /// The @media block for example contains a block of statements /// while other at-rules with a block contain a block of declarations /// </remarks> private CssAtRule ParseAtRule() { CssAtRule atRule = new CssAtRule(); int start = this.Position + 1;// start with first char of ident char ch; while (this.Read(out ch) && !Char.IsWhiteSpace(ch)) { // continue consuming } atRule.Ident = this.Copy(start); while (this.Read(out ch) && Char.IsWhiteSpace(ch)) { // consuming whitespace } start = this.Position;// start with current char do { switch (ch) { case '{': //Block Begin { atRule.Value = this.Copy(start); bool containsRuleSets = String.Equals(atRule.Ident, CssAtRule.MediaIdent, StringComparison.Ordinal); while (true) { while (this.Read(out ch) && Char.IsWhiteSpace(ch)) { // consume whitespace } if (ch == '}') { break; } try { if (containsRuleSets) { // includes @media CssStatement statement = this.ParseStatement(); atRule.Block.Values.Add(statement); } else { // includes @font-face, @page this.PutBack(); CssDeclaration declaration = this.ParseDeclaration(); atRule.Block.Values.Add(declaration); } } catch (ParseException ex) { this.errors.Add(ex); while (this.Read(out ch) && ch != '}') { // restabilize on block end } break; } } return atRule; } case ';': //At-Rule End { atRule.Value = this.Copy(start); return atRule; } } } while (this.Read(out ch)); throw new UnexpectedEndOfFile("Unclosed At-Rule", this.reader.FilePath, this.reader.Line, this.reader.Column); }