/// <summary> /// Consumes a sequence of tokens representing a UVSS selector part. /// </summary> /// <param name="state">The parser state.</param> /// <param name="allowEOF">A value indicating whether hitting the end of file is valid.</param> /// <param name="allowPseudoClass">A value indicating whether parts with pseduo classes are valid.</param> /// <param name="allowChild">A value indicating whether this selector part can be an immediate child.</param> /// <returns>A new <see cref="UvssSelectorPart"/> object representing the selector part that was consumed.</returns> private static UvssSelectorPart ConsumeSelectorPart(UvssParserState state, Boolean allowEOF, Boolean allowPseudoClass, Boolean allowChild) { var element = default(String); var id = default(String); var pseudoClass = default(String); var classes = new List<String>(); var valid = false; var qualifier = UvssSelectorPartQualifier.None; var universal = false; var elementIsExact = false; while (true) { if (state.IsPastEndOfStream) { if (allowEOF && (qualifier == UvssSelectorPartQualifier.None || valid)) { break; } ThrowUnexpectedEOF(state); } var token = state.CurrentToken; if (token.TokenType == UvssLexerTokenType.WhiteSpace || token.TokenType == UvssLexerTokenType.Comma || token.TokenType == UvssLexerTokenType.OpenCurlyBrace || token.TokenType == UvssLexerTokenType.Pipe) { if (qualifier != UvssSelectorPartQualifier.None && !valid) { ThrowUnexpectedToken(state, token); } break; } if (token.TokenType == UvssLexerTokenType.ChildSelector || token.TokenType == UvssLexerTokenType.LogicalChildSelector || token.TokenType == UvssLexerTokenType.TemplatedChildSelector) { if (!allowChild) ThrowUnexpectedToken(state, token); switch (token.TokenType) { case UvssLexerTokenType.ChildSelector: qualifier = UvssSelectorPartQualifier.VisualChild; break; case UvssLexerTokenType.LogicalChildSelector: qualifier = UvssSelectorPartQualifier.LogicalChild; break; case UvssLexerTokenType.TemplatedChildSelector: qualifier = UvssSelectorPartQualifier.TemplatedChild; break; } state.Advance(); state.AdvanceBeyondWhiteSpace(); continue; } if (token.TokenType == UvssLexerTokenType.Identifier || token.TokenType == UvssLexerTokenType.UniversalSelector) { if (!String.IsNullOrEmpty(pseudoClass)) ThrowUnexpectedToken(state, token); state.Advance(); if (token.TokenType == UvssLexerTokenType.UniversalSelector) { valid = true; universal = true; continue; } else { var typename = default(String); var specific = false; if (IsSelectorForElement(token.Value, out typename, out specific)) { if (element != null || universal) ThrowUnexpectedValue(state, token); valid = true; element = typename; elementIsExact = specific; continue; } } if (IsSelectorForID(token.Value)) { if (id != null) ThrowUnexpectedValue(state, token); valid = true; id = token.Value; continue; } valid = true; classes.Add(token.Value); continue; } if (token.TokenType == UvssLexerTokenType.Colon) { if (!valid) ThrowUnexpectedToken(state, token); state.Advance(); var identifier = state.TryConsume(); if (identifier == null) ThrowUnexpectedEOF(state); if (identifier.Value.TokenType != UvssLexerTokenType.Identifier) ThrowExpectedToken(state, identifier.Value, UvssLexerTokenType.Identifier); pseudoClass = identifier.Value.Value; break; } if (valid) break; ThrowUnexpectedToken(state, token); } return valid ? new UvssSelectorPart(qualifier, element, elementIsExact, id, pseudoClass, classes) : null; }