public Either <ParsingError, CellValueCalculator> TryApplyBinaryOperator(
            string operatorChars,
            CellValueCalculator secondArgument,
            FormulaParameters parameters)
        {
            if ((operatorChars == "&&" || operatorChars == "||") &&
                (ResultType != typeof(bool) || secondArgument.ResultType != typeof(bool)))
            {
                return(Left(new ParsingError($"Operator '{operatorChars}' cannot be applied to operands of type '{ResultType.Name}' and '{secondArgument.ResultType}'")));
            }

            var op        = KnownBinaryOperations[operatorChars];
            var localThis = this;

            return
                (from resultType in TryToDeduceResultingType(operatorChars, ResultType, secondArgument.ResultType)
                 from leftOperand in localThis.TryCastTo(resultType)
                 from rightOperand in secondArgument.TryCastTo(resultType)
                 select CombineCalculators(
                     op.ResultIsBoolean?typeof(bool) : resultType,
                     parameters,
                     op.Expression(leftOperand.CalculateExpression, rightOperand.CalculateExpression),
                     $"{leftOperand.CalculateExpression}{operatorChars}{rightOperand.CalculateExpression}",
                     leftOperand,
                     rightOperand));
        }
 internal ColumnFormula(
     CellValueCalculator cellValueCalculator,
     FormulaExpressionsCompiler formulaExpressionsCompiler)
 {
     _cellCalculator             = formulaExpressionsCompiler.CompileCellValueCalculator(cellValueCalculator);
     _aggregatedValueCalculators = formulaExpressionsCompiler.CompileAggregatedValueCalculators(cellValueCalculator.AggregatedValuesCalculators);
     _expressionText             = cellValueCalculator.ToString();
 }
 public Delegate CompileCellValueCalculator(CellValueCalculator valueCalculator)
 {
     return(Expression.Lambda(valueCalculator.CalculateExpression, Parameters.CurrentRow, Parameters.AggregatedValues).Compile());
 }