private IReadOnlyCollection <BooleanExpressionToken> ReduceParenTokens(IReadOnlyCollection <BooleanExpressionToken> tokens)
        {
            var cursor = new BooleanExpressionTokenReaderCursor {
                Tokens = tokens.ToList()
            };

            List <BooleanExpressionToken> allTokens = new List <BooleanExpressionToken>();

            while (cursor.Read(out var token))
            {
                if (token is OpenParenToken)
                {
                    var innerTokens     = ReadUntilClosingParen(cursor);
                    var parenExpression = new BooleanParenExpression {
                        InnerExpression = new BooleanExpressionTokenReader().CreateBooleanExpressionFromTokens(innerTokens)
                    };

                    var reduced = new ReducedToken {
                        ReducedExpression = parenExpression
                    };
                    allTokens.Add(reduced);
                }
                else
                {
                    allTokens.Add(token);
                }
            }
            return(allTokens);
        }
        private IReadOnlyCollection <BooleanExpressionToken> ReadUntilClosingParen(BooleanExpressionTokenReaderCursor cursor)
        {
            List <BooleanExpressionToken> innerTokens = new List <BooleanExpressionToken>();
            var currentDepth = 1;

            while (cursor.Read(out var token))
            {
                if (token is OpenParenToken)
                {
                    currentDepth++;
                }

                if (token is CloseParenToken)
                {
                    currentDepth--;
                    if (currentDepth == 0)
                    {
                        return(innerTokens); //don't add the closing paren to the inner tokens.
                    }
                }

                innerTokens.Add(token);
            }

            return(innerTokens);
        }
        private IReadOnlyCollection <BooleanExpressionToken> ReduceScalarTokens(IReadOnlyCollection <BooleanExpressionToken> tokens)
        {
            var cursor = new BooleanExpressionTokenReaderCursor {
                Tokens = tokens.ToList()
            };

            List <BooleanExpressionToken> allTokens = new List <BooleanExpressionToken>();

            while (cursor.Read(out var token))
            {
                if (token is NegationToken)
                {
                    var reducedScalar = new ReducedScalarToken();

                    cursor.Read(out var negatedToken);
                    if (negatedToken is ReducedParenToken _reduced)
                    {
                        reducedScalar.ReducedExpression = _reduced.ReducedExpression;
                        allTokens.Add(reducedScalar);
                        continue;
                    }

                    if (negatedToken is VariableReference)
                    {
                        reducedScalar.ReducedExpression = new BooleanExpressionTokenReader().ReadScalar(negatedToken);
                        allTokens.Add(reducedScalar);
                        continue;
                    }

                    throw new ArgumentException("Unsupported use of unary not");
                }
                else if (token is VariableReference || token is DecimalLiteral || token is StringLiteral || token is IntegerLiteral || token is GuidLiteral)
                {
                    allTokens.Add(new ReducedScalarToken {
                        ReducedExpression = new BooleanExpressionTokenReader().ReadScalar(token)
                    });
                }
                else
                {
                    allTokens.Add(token);
                }
            }
            return(allTokens);
        }
        private IReadOnlyCollection <BooleanExpressionToken> ReduceComparisonTokens(IReadOnlyCollection <BooleanExpressionToken> tokens)
        {
            var cursor = new BooleanExpressionTokenReaderCursor {
                Tokens = tokens.ToList()
            };

            List <BooleanExpressionToken> allTokens = new List <BooleanExpressionToken>();

            //BooleanExpression comparisonLeftScope = null;
            while (cursor.Read(out var token))
            {
                if (token is ComparisonOperatorToken comparison)
                {
                    if (!allTokens.Any())
                    {
                        throw new ArgumentException("Expect left operand for comparison.");
                    }

                    var success = cursor.Read(out var rightToken);
                    if (!success)
                    {
                        throw new ArgumentException("No right operand for comparison.");
                    }

                    var pop = (ReducedScalarToken)allTokens.Last();
                    allTokens.Remove(pop);
                    allTokens.Add(new ReducedScalarToken
                    {
                        ReducedExpression = new ComparisonExpression
                        {
                            Left           = pop.ReducedExpression,
                            ComparisonType = comparison.ComparisonType,
                            Right          = ((ReducedToken)rightToken).ReducedExpression
                        }
                    });
                }
                else
                {
                    allTokens.Add(token);
                }
            }
            return(allTokens);
        }
        private IReadOnlyCollection <BooleanExpressionToken> ReduceBooleanBinaryTokens(IReadOnlyCollection <BooleanExpressionToken> tokens)
        {
            var cursor = new BooleanExpressionTokenReaderCursor {
                Tokens = tokens.ToList()
            };

            List <BooleanExpressionToken> allTokens = new List <BooleanExpressionToken>();

            while (cursor.Read(out var token))
            {
                if (token is BooleanBinaryToken logicGateToken)
                {
                    if (!allTokens.Any())
                    {
                        throw new ArgumentException("Expect left operand for boolean binary.");
                    }

                    var success = cursor.Read(out var rightToken);
                    if (!success)
                    {
                        throw new ArgumentException("No right operand for logic gate.");
                    }

                    var pop = (ReducedScalarToken)allTokens.Last();
                    allTokens.Remove(pop);
                    allTokens.Add(new ReducedScalarToken
                    {
                        ReducedExpression = new BooleanBinaryExpression
                        {
                            Left     = pop.ReducedExpression,
                            GateType = logicGateToken.GateType,
                            Right    = ((ReducedToken)rightToken).ReducedExpression
                        }
                    });
                }
                else
                {
                    allTokens.Add(token);
                }
            }
            return(allTokens);
        }