public override bool Parse(ItemFactory itemFactory, ITextProvider text, TokenStream tokens) { // Parse namespace: foo|bar, *|, *, |A, ..., applies to both elements and attributes // note that there should not be spaces between namespace, | and name i.e. // foo | bar are actually three selectors and middle one is missing namespace and name. // // Note that we are not going to parse 3|3 as a valid name. Technically we could do it and // leave validation to verify and squiggle with it, but parsing such construct as a legal // name would cause colorizer to colorize sequence as an item name which would be confusing // to the user. I'd rather have it not colorized as legal name and have it apper black instead // telling customer that it is wrong as she types, well before validation pass hits. if (tokens.CurrentToken.TokenType == CssTokenType.Identifier || tokens.CurrentToken.TokenType == CssTokenType.Asterisk) { // There should be no spaces between namespace, | and the element name if (tokens.IsWhiteSpaceAfterCurrentToken() || tokens.Peek(1).IsSelectorTerminator()) { Name = Children.AddCurrentAndAdvance(tokens, CssClassifierContextType.ItemName); } else if (tokens.Peek(1).TokenType == CssTokenType.Or) { // validator will deal with invalid namespaces Namespace = Children.AddCurrentAndAdvance(tokens, CssClassifierContextType.ItemNamespace); Separator = Children.AddCurrentAndAdvance(tokens, CssClassifierContextType.Default); } } else if (tokens.CurrentToken.TokenType == CssTokenType.Or) { Separator = Children.AddCurrentAndAdvance(tokens, CssClassifierContextType.Default); } if (Name == null && (tokens.CurrentToken.TokenType == CssTokenType.Identifier || tokens.CurrentToken.TokenType == CssTokenType.Asterisk)) { if (Separator == null || !tokens.IsWhiteSpaceBeforeCurrentToken()) { Name = Children.AddCurrentAndAdvance(tokens, CssClassifierContextType.ItemName); } } else { // It is OK for the name to be missing. Lonely | is the same as *|* // so we are not going to add missing item here } return(Children.Count > 0); }
public static ParseItem ParseUnknown( ComplexItem parent, ItemFactory itemFactory, ITextProvider text, TokenStream tokens, ParseErrorType?errorType = null) { ParseItem pi = null; bool alreadyParsed = false; // For a single unknown token, let this switch fall through where a // ParseErrorItem will get created. For multiple unknown tokens, deal with // them in this switch and let them automatically get wrapped in an unknown block. CssClassifierContextType contextType = CssClassifierContextType.Default; switch (tokens.CurrentToken.TokenType) { case CssTokenType.Url: pi = itemFactory.Create <UrlItem>(parent); break; case CssTokenType.Function: pi = Function.ParseFunction(parent, itemFactory, text, tokens); alreadyParsed = true; break; case CssTokenType.OpenFunctionBrace: case CssTokenType.OpenSquareBracket: case CssTokenType.OpenCurlyBrace: pi = itemFactory.Create <UnknownBlock>(parent); break; case CssTokenType.String: case CssTokenType.MultilineString: case CssTokenType.InvalidString: contextType = CssClassifierContextType.String; break; } if (pi == null) { pi = new TokenItem(tokens.CurrentToken, contextType); } if (!alreadyParsed && !pi.Parse(itemFactory, text, tokens)) { Debug.Fail("Parse of an unknown item failed."); // I've done all I can do to deal with this unknown token, but now // it must be totally ignored so that parsing doesn't get into an infinite loop. tokens.AdvanceToken(); pi = null; } if (pi != null && errorType.HasValue) { pi.AddParseError(errorType.Value, ParseErrorLocation.WholeItem); } return(pi); }