public BinaryExpression(BinaryOperator @operator, CssExpression left, CssExpression right) { _operator = @operator; _left = left; _right = right; }
public static CssExpression State(CssExpression expression, string state) => new StateExpression(expression, state);
private static CssExpression Combine(CssExpression left, CssExpression right, CssExpression.BinaryOperator op) => left == null ? right : CssExpression.Binary(op, left, right);
public static CssExpression Binary(BinaryOperator op, CssExpression left, CssExpression right) => new BinaryExpression(op, left, right);
public static CssExpression Parse(TextReader reader) { var ors = new List <CssExpression>(); CssExpression current = null; var currentOp = CssExpression.BinaryOperator.And; int code; while ((code = reader.Read()) >= 0) { var c = (char)code; switch (c) { case '*': current = Combine(current, CssExpression.All, currentOp);; break; case '.': current = Combine(current, CssExpression.Class(ReadText(reader)), currentOp); break; case '#': current = Combine(current, CssExpression.Id(ReadText(reader)), currentOp); break; case ':': current = CssExpression.State(current, ReadText(reader)); break; case '~': while (reader.Peek() == ' ') { reader.Read(); } currentOp = CssExpression.BinaryOperator.Prev; break; case '+': while (reader.Peek() == ' ') { reader.Read(); } currentOp = CssExpression.BinaryOperator.PrevSibling; break; case ',': while (reader.Peek() == ' ') { reader.Read(); } ors.Add(current); current = null; break; case '>': while (reader.Peek() == ' ') { reader.Read(); } currentOp = CssExpression.BinaryOperator.Parent; break; case ' ': currentOp = ReadOperator(reader); break; case '[': { var attrValue = ReadText(reader, true).Split('='); reader.Read(); var attr = attrValue[0]; if (attr.Length == 0) { break; } if (attrValue.Length == 1) { current = Combine(current, CssExpression.Attr(CssExpression.AttributeOperator.Exists, attrValue[0], null), currentOp); break; } var opChar = attr.Last(); var attrOp = CssExpression.AttributeOperator.Equals; switch (opChar) { case '~': attrOp = CssExpression.AttributeOperator.DelimitedContains; break; case '|': attrOp = CssExpression.AttributeOperator.DelimitedStartWith; break; case '^': attrOp = CssExpression.AttributeOperator.StartWith; break; case '$': attrOp = CssExpression.AttributeOperator.EndWith; break; case '*': attrOp = CssExpression.AttributeOperator.Contains; break; } var val = attrValue[1]; if (val.StartsWith("\"")) { val = val.Trim('"'); } else if (val.StartsWith("'")) { val = val.Trim('\''); } current = Combine(current, CssExpression.Attr( attrOp, attrOp == CssExpression.AttributeOperator.Equals ? attr : attr.Substring(0, attr.Length - 1), val), currentOp); break; } case '\r': case '\n': case '\t': break; default: current = Combine(current, CssExpression.Tag(c + ReadText(reader)), currentOp); break; } } if (ors.Count > 0) { ors.Add(current); return(CssExpression.Or(ors)); } return(current ?? CssExpression.None); }