static void SetCurrentSelector(ref Selector root, ref Selector workingRoot, ref Operator workingRootParent, Operator op, Selector sel) { var updateRoot = root == workingRoot; op.Left = workingRoot; op.Right = sel; workingRoot = op; if (workingRootParent != null) { workingRootParent.Right = workingRoot; } if (updateRoot) { root = workingRoot; } if (workingRoot is Or) { workingRootParent = (Operator)workingRoot; workingRoot = sel; } }
public static Selector Parse(CssReader reader, char stopChar = '\0') { Selector root = All, workingRoot = All; Operator workingRootParent = null; Action <Operator, Selector> setCurrentSelector = (op, sel) => SetCurrentSelector(ref root, ref workingRoot, ref workingRootParent, op, sel); int p; reader.SkipWhiteSpaces(); while ((p = reader.Peek()) > 0) { switch (unchecked ((char)p)) { case '*': setCurrentSelector(new And(), All); reader.Read(); break; case '.': reader.Read(); var className = reader.ReadIdent(); if (className == null) { return(Invalid); } setCurrentSelector(new And(), new Class(className)); break; case '#': reader.Read(); var id = reader.ReadName(); if (id == null) { return(Invalid); } setCurrentSelector(new And(), new Id(id)); break; case '[': throw new NotImplementedException("Attributes not implemented"); case ',': reader.Read(); setCurrentSelector(new Or(), All); reader.SkipWhiteSpaces(); break; case '+': reader.Read(); setCurrentSelector(new Adjacent(), All); reader.SkipWhiteSpaces(); break; case '~': reader.Read(); setCurrentSelector(new Sibling(), All); reader.SkipWhiteSpaces(); break; case '>': reader.Read(); setCurrentSelector(new Child(), All); reader.SkipWhiteSpaces(); break; case '^': //not in CSS spec reader.Read(); var element = reader.ReadIdent(); if (element == null) { return(Invalid); } setCurrentSelector(new And(), new Base(element)); break; case ' ': case '\t': case '\n': case '\r': case '\f': reader.Read(); bool processWs = false; while ((p = reader.Peek()) > 0) { var c = unchecked ((char)p); if (char.IsWhiteSpace(c)) { reader.Read(); continue; } processWs = (c != '+' && c != '>' && c != ',' && c != '~' && c != stopChar); break; } if (!processWs) { break; } setCurrentSelector(new Descendent(), All); reader.SkipWhiteSpaces(); break; default: if (unchecked ((char)p) == stopChar) { return(root); } var elementName = reader.ReadIdent(); if (elementName == null) { return(Invalid); } setCurrentSelector(new And(), new Element(elementName)); break; } } return(root); }