private static BoundQuery ToDisjunctiveNormalForm(BoundQuery node) { if (node is BoundNegatedQuery negated) { return(ToDisjunctiveNormalForm(Negate(negated.Query))); } if (node is BoundOrQuery or) { var left = ToDisjunctiveNormalForm(or.Left); var right = ToDisjunctiveNormalForm(or.Right); if (ReferenceEquals(left, or.Left) && ReferenceEquals(right, or.Right)) { return(node); } return(new BoundOrQuery(left, right)); } if (node is BoundAndQuery and) { var left = ToDisjunctiveNormalForm(and.Left); var right = ToDisjunctiveNormalForm(and.Right); // (A OR B) AND C -> (A AND C) OR (B AND C) if (left is BoundOrQuery leftOr) { var a = leftOr.Left; var b = leftOr.Right; var c = right; return(new BoundOrQuery( ToDisjunctiveNormalForm(new BoundAndQuery(a, c)), ToDisjunctiveNormalForm(new BoundAndQuery(b, c)) )); } // A AND (B OR C) -> (A AND B) OR (A AND C) if (right is BoundOrQuery rightOr) { var a = left; var b = rightOr.Left; var c = rightOr.Right; return(new BoundOrQuery( ToDisjunctiveNormalForm(new BoundAndQuery(a, b)), ToDisjunctiveNormalForm(new BoundAndQuery(a, c)) )); } return(new BoundAndQuery(left, right)); } return(node); }
static void Walk(IndentedTextWriter writer, BoundQuery node) { switch (node) { case BoundKevValueQuery kevValue: writer.WriteLine($"{(kevValue.IsNegated ? "-" : "")}{kevValue.Key}:{kevValue.Value}"); break; case BoundTextQuery text: writer.WriteLine($"{(text.IsNegated ? "-" : "")}{text.Text}"); break; case BoundNegatedQuery negated: writer.WriteLine("NOT"); writer.Indent++; Walk(writer, negated.Query); writer.Indent--; break; case BoundAndQuery and: writer.WriteLine("AND"); writer.Indent++; Walk(writer, and.Left); Walk(writer, and.Right); writer.Indent--; break; case BoundOrQuery or: writer.WriteLine("OR"); writer.Indent++; Walk(writer, or.Left); Walk(writer, or.Right); writer.Indent--; break; default: throw new Exception($"Unexpected node {node.GetType()}"); } }
private static BoundQuery Negate(BoundQuery node) { switch (node) { case BoundKevValueQuery kevValue: return(NegateKevValueExpression(kevValue)); case BoundTextQuery text: return(NegateTextExpression(text)); case BoundNegatedQuery negated: return(NegateNegatedExpression(negated)); case BoundAndQuery and: return(NegateAndExpression(and)); case BoundOrQuery or: return(NegateOrExpression(or)); default: throw new Exception($"Unexpected node {node.GetType()}"); } }