Exemplo n.º 1
0
 public CompileResult(eErrorType errorType)
 {
     Result   = ExcelErrorValue.Create(errorType);
     DataType = DataType.ExcelError;
 }
Exemplo n.º 2
0
 protected CompileResult CreateResult(eErrorType errorType)
 {
     return(CreateResult(ExcelErrorValue.Create(errorType), DataType.ExcelError));
 }
Exemplo n.º 3
0
        public override CompileResult Execute(IEnumerable <FunctionArgument> arguments, ParsingContext context)
        {
            ValidateArguments(arguments, 2);
            var  number = ArgToDecimal(arguments, 0);
            var  refer  = arguments.ElementAt(1);
            bool asc    = false;

            if (arguments.Count() > 2)
            {
                asc = base.ArgToBool(arguments, 2);
            }
            var l = new List <double>();

            foreach (var c in refer.ValueAsRangeInfo)
            {
                var v = Utils.ConvertUtil.GetValueDouble(c.Value, false, true);
                if (!double.IsNaN(v))
                {
                    l.Add(v);
                }
            }
            l.Sort();
            double ix;

            if (asc)
            {
                ix = l.IndexOf(number) + 1;
                if (_isAvg)
                {
                    int st = Convert.ToInt32(ix);
                    while (l.Count > st && l[st] == number)
                    {
                        st++;
                    }
                    if (st > ix)
                    {
                        ix = ix + ((st - ix) / 2D);
                    }
                }
            }
            else
            {
                ix = l.LastIndexOf(number);
                if (_isAvg)
                {
                    int st = Convert.ToInt32(ix) - 1;
                    while (0 <= st && l[st] == number)
                    {
                        st--;
                    }
                    if (st + 1 < ix)
                    {
                        ix = ix - ((ix - st - 1) / 2D);
                    }
                }
                ix = l.Count - ix;
            }
            if (ix <= 0 || ix > l.Count)
            {
                return(new CompileResult(ExcelErrorValue.Create(eErrorType.NA), DataType.ExcelError));
            }
            else
            {
                return(CreateResult(ix, DataType.Decimal));
            }
        }
Exemplo n.º 4
0
        protected CompileResult Lookup(LookupNavigator navigator, LookupArguments lookupArgs)
        {
            object lastValue       = null;
            object lastLookupValue = null;
            int?   lastMatchResult = null;

            if (lookupArgs.SearchedValue == null)
            {
                throw new ExcelErrorValueException("Lookupfunction failed to lookup value", ExcelErrorValue.Create(eErrorType.NA));
            }
            do
            {
                var matchResult = IsMatch(navigator.CurrentValue, lookupArgs.SearchedValue);
                if (matchResult != 0)
                {
                    if (lastValue != null && navigator.CurrentValue == null)
                    {
                        break;
                    }

                    if (lookupArgs.RangeLookup)
                    {
                        if (lastValue == null && matchResult > 0)
                        {
                            ThrowExcelErrorValueException(eErrorType.NA);
                        }
                        if (lastValue != null && matchResult > 0 && lastMatchResult < 0)
                        {
                            return(_compileResultFactory.Create(lastLookupValue));
                        }
                        lastMatchResult = matchResult;
                        lastValue       = navigator.CurrentValue;
                        lastLookupValue = navigator.GetLookupValue();
                    }
                }
                else
                {
                    return(_compileResultFactory.Create(navigator.GetLookupValue()));
                }
            }while (navigator.MoveNext());

            if (lookupArgs.RangeLookup)
            {
                return(_compileResultFactory.Create(lastLookupValue));
            }

            throw new ExcelErrorValueException("Lookupfunction failed to lookup value", ExcelErrorValue.Create(eErrorType.NA));
        }
 public ExcelErrorValueException(eErrorType errorType)
     : this(ExcelErrorValue.Create(errorType))
 {
 }
Exemplo n.º 6
0
        public void OperatorMinusShouldThrowExceptionIfNonNumericOperand()
        {
            var result = Operator.Minus.Apply(new CompileResult(1, DataType.Integer), new CompileResult("a", DataType.String));

            Assert.AreEqual(ExcelErrorValue.Create(eErrorType.Value), result.Result);
        }
Exemplo n.º 7
0
        public void OperatorDivideShouldReturnValueErrorIfNonNumericOperand()
        {
            var result = Operator.Divide.Apply(new CompileResult(1, DataType.Integer), new CompileResult("a", DataType.String));

            Assert.AreEqual(ExcelErrorValue.Create(eErrorType.Value), result.Result);
        }
Exemplo n.º 8
0
        /// <summary>
        /// Converts the given <see cref="CompileResult"/> into an <see cref="Expression"/>.
        /// </summary>
        /// <param name="compileResult">The <see cref="CompileResult"/> to convert.</param>
        /// <returns>Returns the <see cref="Expression"/> representation of the given <see cref="CompileResult"/>.</returns>
        public Expression FromCompileResult(CompileResult compileResult)
        {
            switch (compileResult.DataType)
            {
            case DataType.Integer:
                return(compileResult.Result is string
                       ?new IntegerExpression(compileResult.Result.ToString())
                           : new IntegerExpression(Convert.ToDouble(compileResult.Result)));

            case DataType.Time:
            case DataType.Decimal:
                return(compileResult.Result is string
                       ?new DecimalExpression(compileResult.Result.ToString())
                           : new DecimalExpression(Convert.ToDouble(compileResult.Result)));

            case DataType.String:
                return(new StringExpression(compileResult.Result.ToString()));

            case DataType.Boolean:
                return(compileResult.Result is string
                       ?new BooleanExpression(compileResult.Result.ToString())
                           : new BooleanExpression((bool)compileResult.Result));

            case DataType.Date:
                if (compileResult.Result is DateTime dateTimeResult || DateTime.TryParse(compileResult.Result.ToString(), out dateTimeResult))
                {
                    return(new DateExpression(dateTimeResult.ToOADate().ToString()));
                }
                if (double.TryParse(compileResult.Result.ToString(), out double oaDate))
                {
                    return(new DateExpression(oaDate.ToString()));
                }
                return(new ExcelErrorExpression(ExcelErrorValue.Create(eErrorType.Value)));

            case DataType.ExcelError:
                if (compileResult.Result is ExcelErrorValue errorValueResult)
                {
                    return(new ExcelErrorExpression(errorValueResult));
                }
                else if (compileResult.Result is eErrorType eErrorTypeResult)
                {
                    return(new ExcelErrorExpression(ExcelErrorValue.Create(eErrorTypeResult)));
                }
                else
                {
                    return(new ExcelErrorExpression(compileResult.Result?.ToString(), ExcelErrorValue.Parse(compileResult.Result?.ToString())));
                }

            case DataType.Empty:
                return(new IntegerExpression(0));

            case DataType.ExcelAddress:
                return(new StringExpression(compileResult.Result.ToString()));

            case DataType.Enumerable:
            case DataType.Unknown:
            default:
                // Enumerable results only end up with the first item in the collection.
                // The result factory will itself return an enumerable CompileResult for List<object> so
                // in order to prevent infinite recursion there is an explicit check for that specific type.
                // The other form of enumerable result is IRangeInfo which is safely reduced in the result factory.
                var resultToProcess = compileResult.Result;
                if (resultToProcess is List <object> listResult)
                {
                    resultToProcess = listResult.FirstOrDefault();
                }
                var result = this.ResultFactory.Create(resultToProcess);
                return(this.FromCompileResult(result));
            }
        }
Exemplo n.º 9
0
 public void MaxIfsShouldReturnNaErrorIfNoMatch()
 {
     _worksheet.Cells["F1"].Formula = "MAXIFS(D3:D7,C3:C7,\"P\")";
     _worksheet.Calculate();
     Assert.AreEqual(ExcelErrorValue.Create(eErrorType.NA).ToString(), _worksheet.Cells["F1"].Value.ToString());
 }
Exemplo n.º 10
0
 public void CreateWithInvalidDefaultErrorTypeThrowsException()
 {
     ExcelErrorValue.Create(default(eErrorType));
 }
Exemplo n.º 11
0
        /// <summary>
        /// Takes the user arguments multiplies the corresponding components in the given arguments and returns the sum of
        /// those products.
        /// </summary>
        /// <param name="arguments">The user specified arguments, usually arrays for this function.</param>
        /// <param name="context">The current context of the function.</param>
        /// <returns>The sum of the products fo the corresponding components in the given array.</returns>
        public override CompileResult Execute(IEnumerable <FunctionArgument> arguments, ParsingContext context)
        {
            if (this.ArgumentsAreValid(arguments, 1, out eErrorType argumentError) == false)
            {
                return(new CompileResult(argumentError));
            }
            double result = 0d;
            List <List <double> > results = new List <List <double> >();

            foreach (var arg in arguments)
            {
                results.Add(new List <double>());
                var currentResult = results.Last();
                if (arg.Value is IEnumerable <FunctionArgument> )
                {
                    foreach (var val in (IEnumerable <FunctionArgument>)arg.Value)
                    {
                        this.AddValue(val.Value, currentResult);
                    }
                }
                else if (arg.Value is FunctionArgument)
                {
                    this.AddValue(arg.Value, currentResult);
                }
                else if (arg.IsExcelRange)
                {
                    var r = arg.ValueAsRangeInfo;
                    for (int col = r.Address._fromCol; col <= r.Address._toCol; col++)
                    {
                        for (int row = r.Address._fromRow; row <= r.Address._toRow; row++)
                        {
                            if (r.GetValue(row, col) is bool)
                            {
                                this.AddValue(0, currentResult);
                            }
                            else if (r.GetValue(row, col) is ExcelErrorValue)
                            {
                                return(new CompileResult((ExcelErrorValue)r.GetValue(row, col)));
                            }
                            else
                            {
                                this.AddValue(r.GetValue(row, col), currentResult);
                            }
                        }
                    }
                }
                else if (arg.Value is int || arg.Value is double || arg.Value is System.DateTime)
                {
                    this.AddValue(arg.Value, currentResult);
                }
                else
                {
                    return(new CompileResult(eErrorType.Value));
                }
            }

            var arrayLength = results.First().Count;

            foreach (var list in results)
            {
                if (list.Count != arrayLength)
                {
                    throw new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Value));
                }
            }
            for (var rowIndex = 0; rowIndex < arrayLength; rowIndex++)
            {
                double rowResult = 1;
                for (var colIndex = 0; colIndex < results.Count; colIndex++)
                {
                    rowResult *= results[colIndex][rowIndex];
                }
                result += rowResult;
            }
            return(this.CreateResult(result, DataType.Decimal));
        }
Exemplo n.º 12
0
 public void CreateWithInvalidErrorTypeThrowsException()
 {
     ExcelErrorValue.Create(0);
 }
Exemplo n.º 13
0
        public void IfErrorWithNameErrorAndNAErrorReturnsCorrectResult()
        {
            var function  = new IfError();
            var arguments = FunctionsHelper.CreateArgs(ExcelErrorValue.Create(eErrorType.Name), ExcelErrorValue.Create(eErrorType.NA));
            var result    = function.Execute(arguments, this.ParsingContext);

            Assert.AreEqual(eErrorType.NA, ((ExcelErrorValue)result.Result).Type);
        }
Exemplo n.º 14
0
        /// <summary>
        /// Calculates a body value in a pivot table cell.
        /// </summary>
        /// <param name="dataRow">The row in the backing body data.</param>
        /// <param name="dataColumn">The column in the backing body data.</param>
        /// <param name="backingDatas">The backing data for the pivot table body.</param>
        /// <param name="grandGrandTotalValues">The backing data for the pivot table grand grand totals.</param>
        /// <param name="rowGrandTotalsValuesLists">The backing data for the pivot table row grand totals.</param>
        /// <param name="columnGrandTotalsValuesLists">The backing data for the pivot table column grand totals.</param>
        /// <returns>An object value for the cell.</returns>
        public override object CalculateBodyValue(
            int dataRow, int dataColumn,
            PivotCellBackingData[,] backingDatas,
            PivotCellBackingData[] grandGrandTotalValues,
            List <PivotCellBackingData> rowGrandTotalsValuesLists,
            List <PivotCellBackingData> columnGrandTotalsValuesLists)
        {
            var rowHeader       = base.PivotTable.RowHeaders[dataRow];
            var columnHeader    = base.PivotTable.ColumnHeaders[dataColumn];
            var cellBackingData = backingDatas[dataRow, dataColumn];
            var dataField       = base.PivotTable.DataFields[base.DataFieldCollectionIndex];

            // TODO: Deal with "(next)" and "(previous)" options for this setting. See task #11840
            // "(next)" is stored as "1048829" and "(previous)" is "1048828".
            if (dataField.BaseItem == 1048829)
            {
                throw new InvalidOperationException(@"'(next)' is not supported for the 'Show Data as Percent of' setting.");
            }
            else if (dataField.BaseItem == 1048828)
            {
                throw new InvalidOperationException(@"'(previous)' is not supported for the 'Show Data as Percent of' setting.");
            }

            var baseFieldItemTuple = new Tuple <int, int>(dataField.BaseField, dataField.BaseItem);

            if (cellBackingData == null)
            {
                return(cellBackingData?.Result);
            }
            else if (rowHeader.CacheRecordIndices.Any(t => t.Equals(baseFieldItemTuple)) || columnHeader.CacheRecordIndices.Any(t => t.Equals(baseFieldItemTuple)))
            {
                if (cellBackingData?.Result != null)
                {
                    if (Convert.ToDouble(cellBackingData.Result) == 0)
                    {
                        return(ExcelErrorValue.Create(eErrorType.Div0));
                    }
                    return(1);                     // At a row/column that contains the comparison field item which makes this 100%.
                }
                else
                {
                    return(cellBackingData?.Result);
                }
            }
            else
            {
                // Try to find a value that matches either the current row or column header structure.
                // If a value is found, the percentage can be calculated. Otherwise, the appropriate error is written out.
                if (this.TryFindMatchingHeaderIndex(rowHeader, baseFieldItemTuple, base.PivotTable.RowHeaders, out int headerIndex))
                {
                    var baseValue = backingDatas[headerIndex, dataColumn]?.Result;
                    return(this.GetShowDataAsPercentOfValue(baseValue, cellBackingData?.Result));
                }
                else if (this.TryFindMatchingHeaderIndex(columnHeader, baseFieldItemTuple, base.PivotTable.ColumnHeaders, out headerIndex))
                {
                    var baseValue = backingDatas[dataRow, headerIndex]?.Result;
                    return(this.GetShowDataAsPercentOfValue(baseValue, cellBackingData?.Result));
                }
                else
                {
                    if (!base.PivotTable.RowFields.Any(f => f.Index == dataField.BaseField) &&
                        !base.PivotTable.ColumnFields.Any(f => f.Index == dataField.BaseField))
                    {
                        // If the dataField.BaseField is not a row or column field, all values #N/A!
                        return(ExcelErrorValue.Create(eErrorType.NA));
                    }
                    else if (!rowHeader.CacheRecordIndices.Any(i => i.Item1 == dataField.BaseField) &&
                             !columnHeader.CacheRecordIndices.Any(i => i.Item1 == dataField.BaseField))
                    {
                        // Subtotals only get a value if they are at the same depth or below the show data as field.
                        return(null);
                    }
                    else
                    {
                        return(ExcelErrorValue.Create(eErrorType.NA));
                    }
                }
            }
        }
Exemplo n.º 15
0
 public override CompileResult Execute(IEnumerable <FunctionArgument> arguments, ParsingContext context)
 {
     return(CreateResult(ExcelErrorValue.Create(eErrorType.NA), DataType.ExcelError));
 }
Exemplo n.º 16
0
 public void MaxIfsShouldReturnValueErrorIfWrongSizeOnCriteriaRange()
 {
     _worksheet.Cells["F1"].Formula = "MAXIFS(D3:D7,C3:C7,\"F\", B3:B5, \"Mi**nda\")";
     _worksheet.Calculate();
     Assert.AreEqual(ExcelErrorValue.Create(eErrorType.Value).ToString(), _worksheet.Cells["F1"].Value.ToString());
 }
Exemplo n.º 17
0
 /// <summary>
 /// Throws an <see cref="ArgumentException"/> if <paramref name="condition"/> evaluates to true.
 /// </summary>
 /// <param name="condition"></param>
 /// <param name="errorType"></param>
 /// <exception cref="ExcelErrorValueException"></exception>
 protected void ThrowExcelErrorValueExceptionIf(Func <bool> condition, eErrorType errorType)
 {
     if (condition())
     {
         throw new ExcelErrorValueException("An excel function error occurred", ExcelErrorValue.Create(errorType));
     }
 }
Exemplo n.º 18
0
        internal virtual object ParseCell(IEnumerable <Token> tokens, string worksheet, int row, int column, out DataType dataType)
        {
            var rangeAddress = _parsingContext.RangeAddressFactory.Create(worksheet, column, row);

            using (var scope = _parsingContext.Scopes.NewScope(rangeAddress))
            {
                dataType = DataType.Unknown;
                var graph = _graphBuilder.Build(tokens);
                if (graph.Expressions.Count() == 0)
                {
                    return(0d);
                }
                try
                {
                    var compileResult = _compiler.Compile(graph.Expressions);
                    // quick solution for the fact that an excelrange can be returned.
                    var rangeInfo = compileResult.Result as ExcelDataProvider.IRangeInfo;
                    if (rangeInfo == null)
                    {
                        if (compileResult.Result != null)
                        {
                            dataType = compileResult.DataType;
                        }
                        return(compileResult.Result ?? 0d);
                    }
                    else
                    {
                        if (rangeInfo.IsEmpty)
                        {
                            return(0d);
                        }
                        if (!rangeInfo.IsMulti)
                        {
                            dataType = DataType.Enumerable;
                            return(rangeInfo.First().Value ?? 0d);
                        }
                        // ok to return multicell if it is a workbook scoped name.
                        if (string.IsNullOrEmpty(worksheet))
                        {
                            return(rangeInfo);
                        }
                        if (_parsingContext.Debug)
                        {
                            var msg = string.Format("A range with multiple cell was returned at row {0}, column {1}", row, column);
                            _parsingContext.Configuration.Logger.Log(_parsingContext, msg);
                        }

                        if (rangeInfo.Address.Rows > rangeInfo.Address.Columns)
                        {
                            var rangeAddressRow = rangeAddress.ToRow;
                            var startRow        = rangeInfo.Address.Start.Row;
                            var endRow          = rangeInfo.Address.End.Row;

                            var startCol = rangeInfo.Address.Start.Column;
                            var endCol   = rangeInfo.Address.End.Column;

                            if (startCol != endCol)
                            {
                                dataType = DataType.ExcelError;
                                return(ExcelErrorValue.Create(eErrorType.Value));
                            }

                            if (rangeAddressRow == startRow)
                            {
                                return(rangeInfo.Worksheet.Cells[rangeInfo.Address.Start.Row, rangeInfo.Address.End.Column].Value);
                            }
                            else if (rangeAddressRow == endRow)
                            {
                                var test       = rangeInfo.Address.End.Row;
                                var secondTest = rangeInfo.Address.End.Column;
                                return(rangeInfo.Worksheet.Cells[rangeInfo.Address.End.Row, rangeInfo.Address.End.Column].Value);
                            }
                            else if (rangeAddressRow > startRow && rangeAddressRow < endRow)
                            {
                                return(rangeInfo.Worksheet.Cells[rangeAddress.FromRow, rangeInfo.Address.Start.Column].Value);
                            }
                        }
                        else
                        {
                            var rangeAddressCol = rangeAddress.ToCol;
                            var startCol        = rangeInfo.Address.Start.Column;
                            var endCol          = rangeInfo.Address.End.Column;
                            var startRow        = rangeInfo.Address.Start.Row;
                            var endRow          = rangeInfo.Address.End.Row;

                            if (startRow != endRow)
                            {
                                dataType = DataType.ExcelError;
                                return(ExcelErrorValue.Create(eErrorType.Value));
                            }

                            if (rangeAddressCol == startCol)
                            {
                                return(rangeInfo.Worksheet.Cells[rangeInfo.Address.Start.Row, rangeAddress.FromCol].Value);
                            }
                            else if (rangeAddressCol == endCol)
                            {
                                return(rangeInfo.Worksheet.Cells[rangeInfo.Address.Start.Row, rangeAddress.FromCol].Value);
                            }
                            else if (rangeAddressCol > startCol && rangeAddressCol < endCol)
                            {
                                return(rangeInfo.Worksheet.Cells[rangeInfo.Address.Start.Row, rangeAddress.FromCol].Value);
                            }
                        }
                        dataType = DataType.ExcelError;
                        return(ExcelErrorValue.Create(eErrorType.Value));
                    }
                }
                catch (ExcelErrorValueException ex)
                {
                    if (_parsingContext.Debug)
                    {
                        _parsingContext.Configuration.Logger.Log(_parsingContext, ex);
                    }
                    dataType = DataType.ExcelError;
                    return(ex.ErrorValue);
                }
            }
        }
Exemplo n.º 19
0
        public void OperatorDivideShouldReturnDivideByZeroIfRightOperandIsZero()
        {
            var result = Operator.Divide.Apply(new CompileResult(1d, DataType.Decimal), new CompileResult(0d, DataType.Decimal));

            Assert.AreEqual(ExcelErrorValue.Create(eErrorType.Div0), result.Result);
        }
 public virtual ExcelFunction GetFunction(string name)
 {
     if (!_functions.ContainsKey(name.ToLower()))
     {
         //throw new InvalidOperationException("Non supported function: " + name);
         throw new ExcelErrorValueException("Non supported function: " + name, ExcelErrorValue.Create(eErrorType.Name));
     }
     return(_functions[name.ToLower()]);
 }
Exemplo n.º 21
0
 /// <summary>
 /// Throws an <see cref="ExcelErrorValueException"/> with the given <paramref name="errorType"/> set.
 /// </summary>
 /// <param name="errorType"></param>
 protected void ThrowExcelErrorValueException(eErrorType errorType)
 {
     throw new ExcelErrorValueException("An excel function error occurred", ExcelErrorValue.Create(errorType));
 }
Exemplo n.º 22
0
 public void MatchInvalidParameterCount()
 {
     this.Worksheet.Cells["A4"].Formula = "MATCH(3)";
     this.Worksheet.Calculate();
     Assert.AreEqual(ExcelErrorValue.Create(eErrorType.Value), this.Worksheet.Cells["A4"].Value);
 }