public void ParseCssStyleSheet(char[] textBuffer) { this.textBuffer = textBuffer; Reset(); this.parseState = CssParseState.Init; lexer.Lex(textBuffer); //----------------------------- //expand some compound property foreach (CssDocMember mb in cssDocument.GetCssDocMemberIter()) { switch (mb.MemberKind) { case WebDom.CssDocMemberKind.RuleSet: EvaluateRuleSet((WebDom.CssRuleSet)mb); break; case WebDom.CssDocMemberKind.Media: EvaluateMedia((WebDom.CssAtMedia)mb); break; default: case WebDom.CssDocMemberKind.Page: throw new NotSupportedException(); } } //----------------------------- }
public CssRuleSet ParseCssPropertyDeclarationList(char[] textBuffer) { this.textBuffer = textBuffer; Reset(); //------------- _currentRuleSet = new CssRuleSet(); //------------- this.parseState = CssParseState.BlockBody; lexer.Lex(textBuffer); EvaluateRuleSet(this._currentRuleSet); return this._currentRuleSet; }
void LexerEmitHandler(CssTokenName tkname, int start, int len) { switch (parseState) { default: { throw new NotSupportedException(); } break; case CssParseState.Init: { switch (tkname) { case CssTokenName.Comment: { //comment token } break; case CssTokenName.RBrace: { //exit from current ruleset block if (this._mediaStack.Count > 0) { this._currentAtMedia = this._mediaStack.Pop(); } } break; case CssTokenName.Star: { //start new code block CssRuleSet newblock; this._currentAtMedia.AddRuleSet(this._currentRuleSet = newblock = new CssRuleSet()); newblock.AddSelector(this._currentSelectorExpr = new CssSimpleElementSelector(SimpleElementSelectorKind.All)); parseState = CssParseState.MoreBlockName; } break; case CssTokenName.At: { //at rule parseState = CssParseState.ExpectAtRuleName; } break; //-------------------------------------------------- //1. case CssTokenName.Colon: { CssRuleSet newblock; _currentAtMedia.AddRuleSet(this._currentRuleSet = newblock = new CssRuleSet()); newblock.AddSelector(this._currentSelectorExpr = new CssSimpleElementSelector(SimpleElementSelectorKind.PseudoClass)); parseState = CssParseState.ExpectIdenAfterSpecialBlockNameSymbol; } break; //2. case CssTokenName.Dot: { CssRuleSet newblock; _currentAtMedia.AddRuleSet(this._currentRuleSet = newblock = new CssRuleSet()); newblock.AddSelector(this._currentSelectorExpr = new CssSimpleElementSelector(SimpleElementSelectorKind.ClassName)); parseState = CssParseState.ExpectIdenAfterSpecialBlockNameSymbol; } break; //3. case CssTokenName.DoubleColon: { CssRuleSet newblock; _currentAtMedia.AddRuleSet(this._currentRuleSet = newblock = new CssRuleSet()); newblock.AddSelector(this._currentSelectorExpr = new CssSimpleElementSelector(SimpleElementSelectorKind.Extend)); parseState = CssParseState.ExpectIdenAfterSpecialBlockNameSymbol; } break; //4. case CssTokenName.Iden: { //block name CssRuleSet newblock; _currentAtMedia.AddRuleSet(this._currentRuleSet = newblock = new CssRuleSet()); newblock.AddSelector(this._currentSelectorExpr = new CssSimpleElementSelector()); this._currentSelectorExpr.Name = new string(this.textBuffer, start, len); parseState = CssParseState.MoreBlockName; } break; //5. case CssTokenName.Sharp: { CssRuleSet newblock; _currentAtMedia.AddRuleSet(this._currentRuleSet = newblock = new CssRuleSet()); newblock.AddSelector(this._currentSelectorExpr = new CssSimpleElementSelector(SimpleElementSelectorKind.Id)); parseState = CssParseState.ExpectIdenAfterSpecialBlockNameSymbol; } break; } } break; case CssParseState.MoreBlockName: { //more switch (tkname) { case CssTokenName.LBrace: { //block body parseState = CssParseState.BlockBody; } break; case CssTokenName.LBracket: { //element attr parseState = CssParseState.ExpectBlockAttrIden; } break; //1. case CssTokenName.Colon: { //wait iden after colon var cssSelector = new CssSimpleElementSelector(); cssSelector.selectorType = SimpleElementSelectorKind.PseudoClass; _currentRuleSet.AddSelector(cssSelector); this._currentSelectorExpr = cssSelector; parseState = CssParseState.ExpectIdenAfterSpecialBlockNameSymbol; } break; //2. case CssTokenName.Dot: { var cssSelector = new CssSimpleElementSelector(); cssSelector.selectorType = SimpleElementSelectorKind.ClassName; _currentRuleSet.AddSelector(cssSelector); this._currentSelectorExpr = cssSelector; parseState = CssParseState.ExpectIdenAfterSpecialBlockNameSymbol; } break; //3. case CssTokenName.DoubleColon: { var cssSelector = new CssSimpleElementSelector(); cssSelector.selectorType = SimpleElementSelectorKind.Extend; _currentRuleSet.AddSelector(cssSelector); this._currentSelectorExpr = cssSelector; parseState = CssParseState.ExpectIdenAfterSpecialBlockNameSymbol; } break; //4. case CssTokenName.Iden: { //add more block name var cssSelector = new CssSimpleElementSelector(); cssSelector.selectorType = SimpleElementSelectorKind.TagName; cssSelector.Name = new string(this.textBuffer, start, len); _currentRuleSet.AddSelector(cssSelector); this._currentSelectorExpr = cssSelector; } break; //5. case CssTokenName.Sharp: { //id var cssSelector = new CssSimpleElementSelector(); cssSelector.selectorType = SimpleElementSelectorKind.Id; _currentRuleSet.AddSelector(cssSelector); this._currentSelectorExpr = cssSelector; parseState = CssParseState.ExpectIdenAfterSpecialBlockNameSymbol; } break; //---------------------------------------------------- //element combinator operators case CssTokenName.Comma: { this._currentRuleSet.PrepareExpression(CssCombinatorOperator.List); } break; case CssTokenName.Star: { }break; case CssTokenName.RAngle: { } break; case CssTokenName.Plus: { } break; case CssTokenName.Tile: { } break; //---------------------------------------------------- default: { throw new NotSupportedException(); } break; } } break; case CssParseState.ExpectIdenAfterSpecialBlockNameSymbol: { switch (tkname) { case CssTokenName.Iden: { this._currentSelectorExpr.Name = new string(this.textBuffer, start, len); parseState = CssParseState.MoreBlockName; } break; default: { throw new NotSupportedException(); } } } break; case CssParseState.ExpectBlockAttrIden: { switch (tkname) { case CssTokenName.Iden: { //attribute parseState = CssParseState.AfterAttrName; this._currentSelectorExpr.AddAttribute(this._currentSelectorAttr = new CssAttributeSelectorExpression()); this._currentSelectorAttr.AttributeName = new string(this.textBuffer, start, len); } break; default: { throw new NotSupportedException(); } break; } } break; case CssParseState.AfterAttrName: { switch (tkname) { case CssTokenName.OpEq: { parseState = CssParseState.ExpectedBlockAttrValue; //expected attr value } break; case CssTokenName.RBracket: { //no attr value parseState = CssParseState.MoreBlockName; } break; default: { throw new NotSupportedException(); } break; } } break; case CssParseState.ExpectedBlockAttrValue: { switch (tkname) { case CssTokenName.LiteralString: { this._currentSelectorAttr.valueExpression = this._latestPropertyValue = new CssCodePrimitiveExpression(new string(this.textBuffer, start, len), CssValueHint.LiteralString); this._currentSelectorAttr = null; } break; default: { } break; } parseState = CssParseState.AfterBlockNameAttr; } break; case CssParseState.AfterBlockNameAttr: { switch (tkname) { default: { } break; case CssTokenName.RBracket: { parseState = CssParseState.MoreBlockName; this._currentSelectorAttr = null; } break; } } break; case CssParseState.BlockBody: { switch (tkname) { case CssTokenName.Iden: { //block name //create css property string cssPropName = new string(this.textBuffer, start, len); var wellknownName = UserMapUtil.GetWellKnownPropName(cssPropName); if (wellknownName == WellknownCssPropertyName.Unknown) { _currentRuleSet.AddCssCodeProperty(this._currentProperty = new CssPropertyDeclaration(cssPropName)); } else { _currentRuleSet.AddCssCodeProperty(this._currentProperty = new CssPropertyDeclaration(wellknownName)); } this._latestPropertyValue = null; parseState = CssParseState.AfterPropertyName; } break; case CssTokenName.RBrace: { //close current block this._currentProperty = null; this._currentSelectorAttr = null; this._currentSelectorExpr = null; parseState = CssParseState.Init; } break; case CssTokenName.SemiColon: { //another semi colon just skip } break; default: { throw new NotSupportedException(); } break; } } break; case CssParseState.AfterPropertyName: { if (tkname == CssTokenName.Colon) { parseState = CssParseState.ExpectPropertyValue; } else { throw new NotSupportedException(); } } break; case CssParseState.ExpectPropertyValue: { switch (tkname) { default: { throw new NotSupportedException(); } case CssTokenName.Sharp: { //follow by hex color value parseState = CssParseState.ExpectValueOfHexColor; } break; case CssTokenName.LiteralString: { this._currentProperty.AddValue(this._latestPropertyValue = new CssCodePrimitiveExpression(new string(this.textBuffer, start, len), CssValueHint.LiteralString)); parseState = CssParseState.AfterPropertyValue; } break; case CssTokenName.Number: { float number = float.Parse(new string(this.textBuffer, start, len)); this._currentProperty.AddValue(this._latestPropertyValue = new CssCodePrimitiveExpression(number)); parseState = CssParseState.AfterPropertyValue; } break; case CssTokenName.NumberUnit: { } break; case CssTokenName.Iden: { //property value this._currentProperty.AddValue(this._latestPropertyValue = new CssCodePrimitiveExpression(new string(this.textBuffer, start, len), CssValueHint.Iden)); parseState = CssParseState.AfterPropertyValue; } break; } } break; case CssParseState.ExpectValueOfHexColor: { switch (tkname) { case CssTokenName.Iden: { this._currentProperty.AddValue(this._latestPropertyValue = new CssCodePrimitiveExpression("#" + new string(this.textBuffer, start, len), CssValueHint.HexColor)); } break; case CssTokenName.Number: { this._currentProperty.AddValue(this._latestPropertyValue = new CssCodePrimitiveExpression("#" + new string(this.textBuffer, start, len), CssValueHint.HexColor)); } break; default: { throw new NotSupportedException(); } } parseState = CssParseState.AfterPropertyValue; } break; case CssParseState.AfterPropertyValue: { switch (tkname) { default: { throw new NotSupportedException(); } case CssTokenName.Comma: { //skip comma } break; case CssTokenName.Percent: { if (_latestPropertyValue is CssCodePrimitiveExpression) { ((CssCodePrimitiveExpression)_latestPropertyValue).Unit = "%"; } } break; case CssTokenName.Divide: { //eg. font: style variant weight size/line-height family; CssCodeBinaryExpression codeBinaryOpExpr = new CssCodeBinaryExpression(); codeBinaryOpExpr.OpName = CssValueOpName.Divide; codeBinaryOpExpr.Left = this._latestPropertyValue; //replace previous add value *** int valueCount = this._currentProperty.ValueCount; //replace this._currentProperty.ReplaceValue(valueCount - 1, codeBinaryOpExpr); this._latestPropertyValue = codeBinaryOpExpr; } break; case CssTokenName.LiteralString: { var literalValue = new string(this.textBuffer, start, len); throw new NotSupportedException(); } break; case CssTokenName.LParen: { //function parseState = CssParseState.ExpectedFuncParameter; //make current prop value as func CssCodeFunctionCallExpression funcCallExpr = new CssCodeFunctionCallExpression( this._latestPropertyValue.ToString()); int valueCount = this._currentProperty.ValueCount; this._currentProperty.ReplaceValue(valueCount - 1, funcCallExpr); this._latestPropertyValue = funcCallExpr; } break; case CssTokenName.RBrace: { //close block parseState = CssParseState.Init; } break; case CssTokenName.SemiColon: { //start new proeprty parseState = CssParseState.BlockBody; this._currentProperty = null; } break; case CssTokenName.Iden: { //another property value this._currentProperty.AddValue(this._latestPropertyValue = new CssCodePrimitiveExpression(new string(this.textBuffer, start, len), CssValueHint.Iden)); } break; case CssTokenName.Number: { //another property value float number = float.Parse(new string(this.textBuffer, start, len)); this._currentProperty.AddValue(this._latestPropertyValue = new CssCodePrimitiveExpression(number)); } break; case CssTokenName.NumberUnit: { //number unit if (_latestPropertyValue is CssCodePrimitiveExpression) { ((CssCodePrimitiveExpression)_latestPropertyValue).Unit = new string(this.textBuffer, start, len); } } break; case CssTokenName.Sharp: { parseState = CssParseState.ExpectValueOfHexColor; } break; } } break; case CssParseState.ExpectAtRuleName: { //iden switch (tkname) { default: { throw new NotSupportedException(); } case CssTokenName.Iden: { string iden = new string(this.textBuffer, start, len); //create new rule _currentRuleSet = null; _currentProperty = null; _currentSelectorAttr = null; _currentSelectorExpr = null; switch (iden) { case "media": { parseState = CssParseState.MediaList; //store previous media if (this._currentAtMedia != null) { this._mediaStack.Push(this._currentAtMedia); } this.cssDocument.Add(this._currentAtMedia = new CssAtMedia()); } break; case "import": { parseState = CssParseState.ExpectImportURL; } break; case "page": { throw new NotSupportedException(); } break; default: { throw new NotSupportedException(); } break; } } break; } } break; case CssParseState.MediaList: { //medialist sep by comma switch (tkname) { default: { throw new NotSupportedException(); } case CssTokenName.Iden: { //media name this._currentAtMedia.AddMedia(new string(this.textBuffer, start, len)); } break; case CssTokenName.Comma: { //wait for another media } break; case CssTokenName.LBrace: { //begin rule set part parseState = CssParseState.Init; } break; } } break; case CssParseState.ExpectedFuncParameter: { string funcArg = new string(this.textBuffer, start, len); switch (tkname) { default: { throw new NotSupportedException(); } case CssTokenName.RParen: { this.parseState = CssParseState.AfterPropertyValue; } break; case CssTokenName.LiteralString: { ((CssCodeFunctionCallExpression)this._latestPropertyValue).AddFuncArg( new CssCodePrimitiveExpression(funcArg, CssValueHint.LiteralString)); this.parseState = CssParseState.AfterFuncParameter; } break; case CssTokenName.Number: { float number = float.Parse(funcArg); ((CssCodeFunctionCallExpression)this._latestPropertyValue).AddFuncArg( new CssCodePrimitiveExpression(number)); this.parseState = CssParseState.AfterFuncParameter; } break; case CssTokenName.Iden: { ((CssCodeFunctionCallExpression)this._latestPropertyValue).AddFuncArg( new CssCodePrimitiveExpression(funcArg, CssValueHint.Iden)); this.parseState = CssParseState.AfterFuncParameter; } break; } } break; case CssParseState.AfterFuncParameter: { switch (tkname) { default: { throw new NotSupportedException(); } case CssTokenName.RParen: { this.parseState = CssParseState.AfterPropertyValue; } break; case CssTokenName.Comma: { this.parseState = CssParseState.ExpectedFuncParameter; } break; } } break; } }