/// <summary>Indicates whether all characters in another character class are also in this class.</summary>
        /// <param name="other">The other character class.</param>
        /// <returns><c>true</c> if <paramref name="other"/> is a subset of this class, otherwise <c>false.</c></returns>
        public override bool Contains(InstructAST other)
        {
            CategoryAST oCat = other as CategoryAST;
            if (oCat != null)
                return this.Category == oCat.Category;

            return base.Contains(other);
        }
        /// <summary>Indicates whether all characters in another character class are also in this class.</summary>
        /// <param name="other">The other character class.</param>
        /// <returns><c>true</c> if <paramref name="other"/> is a subset of this class, otherwise <c>false.</c></returns>
        public override bool Contains(InstructAST other)
        {
            ScriptAST oScr = other as ScriptAST;
            if (oScr != null)
                return (this.IsExtended || !oScr.IsExtended) && this.Script == oScr.Script;

            return base.Contains(other);
        }
        /// <summary>Indicates whether all characters in another character class are also in this class.</summary>
        /// <param name="other">The other character class.</param>
        /// <returns><c>true</c> if <paramref name="other"/> is a subset of this class, otherwise <c>false.</c></returns>
        public override bool Contains(InstructAST other)
        {
            PropertyAST oProp = other as PropertyAST;
            if (oProp != null)
                return this.Property.Contains(oProp.Property);

            CategoryAST oCat = other as CategoryAST;
            if (oCat != null)
                return this.Property.Contains(oCat.Category);

            return base.Contains(other);
        }
        /// <summary>Indicates whether all positions matched by another instruction
        /// are also matched by this instruction.</summary>
        /// <param name="other">The other instruction.</param>
        /// <returns><c>true</c> if <paramref name="other"/> is a subset of this instruction,
        /// otherwise <c>false.</c></returns>
        public virtual bool Contains(InstructAST other)
        {
            OneCharAST oChar = other as OneCharAST;
            if (oChar != null && !oChar.FoldsCase)
                return Contains(oChar.Character);

            AndTestAST oAnd = other as AndTestAST;
            if (oAnd != null)
                return Contains(oAnd.Left) || Contains(oAnd.Right);

            DiffTestAST oDiff = other as DiffTestAST;
            if (oDiff != null)
                return Contains(oDiff.Left);

            return this.Equals(other);
        }
 /// <summary>Indicates whether this and another character class have no codepoints in common.</summary>
 /// <param name="other">The other character class.</param>
 /// <returns><c>true</c> if this character class and <paramref name="other"/> are disjoint,
 /// otherwise <c>false</c>.</returns>
 public override bool DisjointWith(InstructAST other)
 {
     return false;
 }
        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);
        }
 /// <summary>Indicates whether all positions matched by another instruction
 /// are also matched by this instruction.</summary>
 /// <param name="other">The other instruction.</param>
 /// <returns><c>true</c> if <paramref name="other"/> is a subset of this instruction,
 /// otherwise <c>false.</c></returns>
 public override bool Contains(InstructAST other)
 {
     return Left.Contains(other) && Right.Contains(other);
 }
        /// <summary>Indicates whether this and another character class have no codepoints in common.</summary>
        /// <param name="other">The other character class.</param>
        /// <returns><c>true</c> if this character class and <paramref name="other"/> are disjoint,
        /// otherwise <c>false</c>.</returns>
        public override bool DisjointWith(InstructAST other)
        {
            PropertyAST oProp = other as PropertyAST;
            if (oProp != null)
                return oProp.Property.DisjointWith(this.Category);

            CategoryAST oCat = other as CategoryAST;
            if (oCat != null)
                return this.Category != oCat.Category;

            return base.DisjointWith(other);
        }
        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);
        }
 /// <summary>Adds an instruction to the NFA's table.</summary>
 /// <param name="ast">An AST to translate to an instruction.</param>
 /// <returns>The translation of <paramref name="ast"/>.</returns>
 internal int AddInstructions(InstructAST ast)
 {
     return instructIndex(ast);
 }
        /// <summary>Indicates whether this and another character class have no codepoints in common.</summary>
        /// <param name="other">The other character class.</param>
        /// <returns><c>true</c> if this character class and <paramref name="other"/> are disjoint,
        /// otherwise <c>false</c>.</returns>
        public override bool DisjointWith(InstructAST other)
        {
            if (!FoldsCase)
            {
                CharRangeAST oRange = other as CharRangeAST;
                if (oRange != null && !oRange.FoldsCase)
                    return this.Max < oRange.Min || this.Min > oRange.Max;

                for (int i = Min; i <= Max; i++)
                    if (other.Contains(i)) return false;
                return true;
            }

            return base.DisjointWith(other);
        }
        /// <summary>Indicates whether all characters in another character class are also in this class.</summary>
        /// <param name="other">The other character class.</param>
        /// <returns><c>true</c> if <paramref name="other"/> is a subset of this class, otherwise <c>false.</c></returns>
        public override bool Contains(InstructAST other)
        {
            OneCharAST oChar = other as OneCharAST;
            if (oChar != null)
                return (this.FoldsCase || !oChar.FoldsCase) && Contains(oChar.Character);

            CharRangeAST oRange = other as CharRangeAST;
            if (oRange != null) return (this.FoldsCase || !oRange.FoldsCase) &&
                this.Min <= oRange.Min && oRange.Max <= this.Max;

            return base.Contains(other);
        }
        /// <summary>Indicates whether all characters in another character class are also in this class.</summary>
        /// <param name="other">The other character class.</param>
        /// <returns><c>true</c> if <paramref name="other"/> is a subset of this class, otherwise <c>false.</c></returns>
        public override bool Contains(InstructAST other)
        {
            OneCharAST oChar = other as OneCharAST;
            if (oChar != null)
                return (FoldsCase || !oChar.FoldsCase) && Contains(oChar.Character);

            return base.Contains(other);
        }
        /// <summary>Indicates whether this and another character class have no codepoints in common.</summary>
        /// <param name="other">The other character class.</param>
        /// <returns><c>true</c> if this character class and <paramref name="other"/> are disjoint,
        /// otherwise <c>false</c>.</returns>
        public override bool DisjointWith(InstructAST other)
        {
            if (!FoldsCase && !other.IsZeroWidth)
                return !other.Contains(Character);

            OneCharAST oChar = other as OneCharAST;
            if (oChar != null)
                return !(Contains(oChar.Character) || oChar.Contains(Character));

            return base.DisjointWith(other);
        }
        /// <summary>Indicates whether this and another character class have no codepoints in common.</summary>
        /// <param name="other">The other character class.</param>
        /// <returns><c>true</c> if this character class and <paramref name="other"/> are disjoint,
        /// otherwise <c>false</c>.</returns>
        public override bool DisjointWith(InstructAST other)
        {
            ScriptAST oScr = other as ScriptAST;
            if (oScr != null)
                return !this.IsExtended && !oScr.IsExtended && this.Script != oScr.Script;

            return base.DisjointWith(other);
        }
        /// <summary>Indicates whether this and another instruction ever match at the same positions.</summary>
        /// <param name="other">The other instruction.</param>
        /// <returns><c>true</c> if this instruction and <paramref name="other"/> are disjoint,
        /// otherwise <c>false</c>.</returns>
        public virtual bool DisjointWith(InstructAST other)
        {
            OneCharAST oChar = other as OneCharAST;
            if (oChar != null && !oChar.FoldsCase)
                return !Contains(oChar.Character);

            NotTestAST oNot = other as NotTestAST;
            if (oNot != null)
                return oNot.Argument.Contains(this);

            AndTestAST oAnd = other as AndTestAST;
            if (oAnd != null)
                return DisjointWith(oAnd.Left) || DisjointWith(oAnd.Right);

            DiffTestAST oDiff = other as DiffTestAST;
            if (oDiff != null)
                return DisjointWith(oDiff.Left);

            return false;
        }
 private NotTestAST(InstructAST argument)
     : base()
 {
     Argument = argument;
 }
        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);
        }
 /// <summary>Indicates whether this and another character class have no codepoints in common.</summary>
 /// <param name="other">The other character class.</param>
 /// <returns><c>true</c> if this character class and <paramref name="other"/> are disjoint,
 /// otherwise <c>false</c>.</returns>
 public override bool DisjointWith(InstructAST other)
 {
     return Argument.Contains(other);
 }
 /// <summary>Indicates whether this and another instruction ever match at the same positions.</summary>
 /// <param name="other">The other instruction.</param>
 /// <returns><c>true</c> if this instruction and <paramref name="other"/> are disjoint,
 /// otherwise <c>false</c>.</returns>
 public override bool DisjointWith(InstructAST other)
 {
     return Left.DisjointWith(other) || Right.DisjointWith(other);
 }
        internal static InstructAST Build(InstructAST argument)
        {
            // !!a == a
            NotTestAST negArg = argument as NotTestAST;
            if (negArg != null) return negArg.Argument;

            // !<empty> == <fail>
            //if (argument == EmptyAST.Instance) return AnyCharAST.Negate;

            return new NotTestAST(argument);
        }
 internal AndTestAST(InstructAST left, InstructAST right)
     : base()
 {
     Left = left; Right = right;
 }
 /// <summary>Indicates whether all characters in another character class are also in this class.</summary>
 /// <param name="other">The other character class.</param>
 /// <returns><c>true</c> if <paramref name="other"/> is a subset of this class, otherwise <c>false.</c></returns>
 public override bool Contains(InstructAST other)
 {
     return true;
 }