internal static InstructAST Build(InstructAST left, InstructAST right) { // a -- a == <fail> if (left.Equals(right)) return AnyCharAST.Negate; // When b contains a, a -- b matches no codepoints if (right.Contains(left)) return AnyCharAST.Negate; // When a and b are disjoint, a -- b == a if (left.DisjointWith(right)) return left; // \p{Any} -- a == !a if (AnyCharAST.Instance.Equals(left)) return NotTestAST.Make(right); // !a -- !b == b -- a; !a -- b == !(a || b); a -- !b == a && b NotTestAST negLeft = left as NotTestAST; NotTestAST negRight = right as NotTestAST; if (negLeft != null) { if (negRight != null) return DiffTestAST.Make(negRight.Argument, negLeft.Argument); else return NotTestAST.Make(OrTestAST.Make(negLeft.Argument, right)); } else if (negRight != null) return AndTestAST.Make(left, negRight.Argument); // (a -- b) -- c == a -- (b || c) DiffTestAST diffLeft = left as DiffTestAST; if (diffLeft != null) return DiffTestAST.Make(diffLeft.Left, OrTestAST.Make(diffLeft.Right, right)); // (a || b) -- c == (a -- c) || (b -- c) OrTestAST orLeft = left as OrTestAST; if (orLeft != null) return OrTestAST.Make(DiffTestAST.Make(orLeft.Left, right), DiffTestAST.Make(orLeft.Right, right)); // When a and b are overlapping ranges, a -- b == a with a gap CharRangeAST leftRange = left as CharRangeAST; if (leftRange != null) { int excludeMin = -1; int excludeMax = -1; OneCharAST rightChar = right as OneCharAST; if (rightChar != null && (leftRange.FoldsCase == rightChar.FoldsCase)) { excludeMin = excludeMax = rightChar.Character; } CharRangeAST rightRange = right as CharRangeAST; if (rightRange != null && (leftRange.FoldsCase == rightRange.FoldsCase)) { excludeMin = rightRange.Min; excludeMax = rightRange.Max; } if (leftRange.Min <= excludeMax && excludeMin <= leftRange.Max) return OrTestAST.Make(CharRangeAST.Make(leftRange.Min, excludeMin - 1, leftRange.FoldsCase), CharRangeAST.Make(excludeMax + 1, leftRange.Max, leftRange.FoldsCase)); } return new DiffTestAST(left, right); }
internal static InstructAST Build(InstructAST left, InstructAST right) { // a && a == a if (left.Equals(right)) return left; // <empty> && a == a && <empty> == a if zero-width, <fail> otherwise if (left == EmptyAST.Instance) return right.IsZeroWidth ? right : AnyCharAST.Negate; if (right == EmptyAST.Instance) return left.IsZeroWidth ? left : AnyCharAST.Negate; // When a contains b, a && b == b if (left.Contains(right)) return right; // When b contains a, a && b == a if (right.Contains(left)) return left; // When a and b are disjoint, a && b matches nowhere if (left.DisjointWith(right)) return AnyCharAST.Negate; // !a && !b == !(a || b), !a && b == b -- a, a && !b == a -- b NotTestAST negLeft = left as NotTestAST; NotTestAST negRight = right as NotTestAST; if (negLeft != null) { if (negRight != null) return NotTestAST.Make(OrTestAST.Make(negLeft.Argument, negRight.Argument)); else return DiffTestAST.Make(right, negLeft.Argument); } else if (negRight != null) return DiffTestAST.Make(left, negRight.Argument); // (a && b) && c == a && (b && c) AndTestAST andRight = right as AndTestAST; if (andRight != null) return AndTestAST.Make(AndTestAST.Make(left, andRight.Left), andRight.Right); // (a || b) && c == (a && c) || (b && c) OrTestAST orLeft = left as OrTestAST; if (orLeft != null) return OrTestAST.Make(AndTestAST.Make(orLeft.Left, right), AndTestAST.Make(orLeft.Right, right)); // a && (b || c) == (a && b) || (a && c) if (!left.IsZeroWidth) { OrTestAST orRight = right as OrTestAST; if (orRight != null) return OrTestAST.Make(AndTestAST.Make(left, orRight.Left), AndTestAST.Make(left, orRight.Right)); } // Intersection of overlapping ranges is the overlap CharRangeAST leftRange = left as CharRangeAST; CharRangeAST rightRange = right as CharRangeAST; if (leftRange != null && rightRange != null && (leftRange.FoldsCase == rightRange.FoldsCase)) { int low = Math.Max(leftRange.Min, rightRange.Min); int high = Math.Min(leftRange.Max, rightRange.Max); return CharRangeAST.Make(low, high, leftRange.FoldsCase); } return new AndTestAST(left, right); }
internal static InstructAST Build(InstructAST left, InstructAST right) { // a || <empty> == <empty> || a == a if (EmptyAST.Instance == left) return right; if (EmptyAST.Instance == right) return left; // a || a == a if (left.Equals(right)) return left; // When a contains b, a || b == a if (left.Contains(right)) return left; // When b contains a, a || b == b if (right.Contains(left)) return right; // !a || !b == !(a && b), !a || b == !(a -- b), a || !b == !(b -- a) NotTestAST negLeft = left as NotTestAST; NotTestAST negRight = right as NotTestAST; if (negLeft != null) { if (negRight != null) return NotTestAST.Make(AndTestAST.Make(negLeft.Argument, negRight.Argument)); else return NotTestAST.Make(DiffTestAST.Make(negLeft.Argument, right)); } else if (negRight != null) return NotTestAST.Make(DiffTestAST.Make(negRight.Argument, left)); // (a || b) || c == a || (b || c) OrTestAST orRight = right as OrTestAST; if (orRight != null) return OrTestAST.Make(OrTestAST.Make(left, orRight.Left), orRight.Right); // Merge overlapping and adjacent ranges OneCharAST oChar = null; CharRangeAST range = null; CharRangeAST leftRange = left as CharRangeAST; CharRangeAST rightRange = right as CharRangeAST; if (leftRange != null) { if (rightRange != null && (leftRange.FoldsCase == rightRange.FoldsCase) && rightRange.Max + 1 >= leftRange.Min && leftRange.Max + 1 >= rightRange.Min) { int low = Math.Min(leftRange.Min, rightRange.Min); int high = Math.Max(leftRange.Max, rightRange.Max); return CharRangeAST.Make(low, high, leftRange.FoldsCase); } oChar = right as OneCharAST; range = leftRange; } else if (rightRange != null) { oChar = left as OneCharAST; range = rightRange; } // Merge a character adjacent to a range with the range if (oChar != null) { if (range.FoldsCase && oChar.FoldsCase) { if (oChar.Character.ToCaseFold() == range.Min.ToCaseFold() - 1) return CharRangeAST.Make(range.Min - 1, range.Max, true); else if (oChar.Character.ToCaseFold() == range.Max.ToCaseFold() + 1) return CharRangeAST.Make(range.Min, range.Max + 1, true); } if (!range.FoldsCase && !oChar.FoldsCase) { if (oChar.Character == range.Min - 1) return CharRangeAST.Make(range.Min - 1, range.Max, false); else if (oChar.Character == range.Max + 1) return CharRangeAST.Make(range.Min, range.Max + 1, false); } } return new OrTestAST(left, right); }