/// <summary>
        /// Adds alternate expression (Rule1 | Rule2) to the expression tree for the current rule.
        /// </summary>
        /// <param name="match">Current parse tree node</param>
        private void EnterAlternate(ITextParseTreeNode match)
        {
            /* Alternate expressions are parsed like this:
             *
             * Rule1 | Rule2 | Rule3
             *
             * RuleName (Rule1)
             * AlternateExpression
             * -RuleName (Rule2)
             * -AlternateExpression
             * --RuleName (Rule3)
             */

            if (ruleBodyExpression is OneOfExpression)
            {
                // Already alternating, just add to children
                base.Enter(match);
            }
            else
            {
                // Start new alternate with previous expression
                var previousExpression = ruleBodyExpression.RemoveLastChild();

                var alternateExpression = new OneOfExpression();
                alternateExpression.AddChild(previousExpression);

                ruleBodyExpression.AddChild(alternateExpression);
                ruleBodyExpression = alternateExpression;

                base.Enter(match);

                ruleBodyExpression = ruleBodyExpression.Parent;
            }
        }
        public void Given_OneOfExpression_Simplify_should_output_expected_expression(OneOfExpression input, FilterExpression expected)
        {
            // Act
            FilterExpression actual = input.Simplify();

            // Assert
            actual.Should().Be(expected);
        }
        public void Implements_IsEquivalentTo_Properly(OneOfExpression first, FilterExpression other, bool expected, string reason)
        {
            // Act
            bool actual = first.IsEquivalentTo(other);

            // Assert
            actual.Should()
            .Be(expected, reason);
        }
        public void Given_OneOxpression_that_contains_inner_OneOfExpressions_Simplify_should_flatten_them(NonEmptyArray <FilterExpression> first, NonEmptyArray <FilterExpression> second, NonEmptyArray <FilterExpression> third)
        {
            // Arrange
            FilterExpression expected = new OneOfExpression(first.Item.Concat(second.Item)
                                                            .Concat(third.Item)
                                                            .ToArray()).Simplify();

            OneOfExpression initial = new(new OneOfExpression(first.Item),
                                          new OneOfExpression(second.Item),
                                          new OneOfExpression(third.Item));

            // Act
            FilterExpression actual = initial.Simplify();

            // Assert
            actual.Should()
            .Be(expected);
        }
        public void ImplementsEqualsCorrectly(OneOfExpression first, object other, bool expected, string reason)
        {
            _outputHelper.WriteLine($"First instance : {first}");
            _outputHelper.WriteLine($"Second instance : {other}");

            // Act
            bool actual         = first.Equals(other);
            int  actualHashCode = first.GetHashCode();

            // Assert
            actual.Should()
            .Be(expected, reason);
            if (expected)
            {
                actualHashCode.Should()
                .Be(other?.GetHashCode(), reason);
            }
            else
            {
                actualHashCode.Should()
                .NotBe(other?.GetHashCode(), reason);
            }
        }