/// <summary> /// Filter expression can be a literal string, "Hello World" or it can contain logical /// conjunctions "or" and "and", like this "Hello and Hi" or "Hello & Hi" or "Hello or Hi" /// and it can have parentheses "Hello and (foo or bar)" and so on. It can also have /// a "not" or "!" for negation. /// </summary> public Filter <T> Parse(string quickFilter) { if (string.IsNullOrWhiteSpace(quickFilter)) { return(null); } foreach (Tuple <QuickFilterToken, string> token in GetFilterTokens(quickFilter)) { string literal = token.Item2; switch (token.Item1) { case QuickFilterToken.Literal: // shift stack.Push(new FilterKeyword <T>(new FilterLiteral(literal))); break; case QuickFilterToken.And: // reduce stack.Push(new FilterAnd <T>() { Left = Reduce(QuickFilterToken.And) }); break; case QuickFilterToken.Or: // reduce stack.Push(new FilterOr <T>() { Left = Reduce(QuickFilterToken.Or) }); break; case QuickFilterToken.Not: // reduce stack.Push(new FilterNot <T>() { }); break; case QuickFilterToken.LeftParen: // shift stack.Push(new FilterParens <T>()); break; case QuickFilterToken.RightParen: // reduce Filter <T> op = Reduce(QuickFilterToken.RightParen); FilterParens <T> parens = op as FilterParens <T>; if (parens != null) { // eliminate parens stack.Push(parens.Expression); } else { // missing open parens, now what? stack.Push(op); } break; } } return(Reduce(QuickFilterToken.None)); }
private Filter <T> Reduce(QuickFilterToken token) { while (stack.Count > 0) { Filter <T> top = stack.Pop(); if (stack.Count == 0) { return(top); } Filter <T> op = stack.Peek(); if (token > op.Precidence) { return(top); } op = stack.Pop(); // now combine "top" and "op" if (op is FilterKeyword <T> ) { FilterKeyword <T> keyword = (FilterKeyword <T>)op; op = Combine(keyword, top); } else if (op is FilterAnd <T> ) { FilterAnd <T> and = (FilterAnd <T>)op; and.Right = Combine(and.Right, top); } else if (op is FilterOr <T> ) { FilterOr <T> or = (FilterOr <T>)op; or.Right = Combine(or.Right, top); } else if (op is FilterNot <T> ) { FilterNot <T> not = (FilterNot <T>)op; not.Right = Combine(not.Right, top); } else if (op is FilterParens <T> ) { FilterParens <T> parens = (FilterParens <T>)op; parens.Expression = Combine(parens.Expression, top); } stack.Push(op); } return(null); }