Пример #1
0
        /**
         * returns the OperationEval concrete impl instance corresponding
         * to the supplied operationPtg
         */
        public static ValueEval Evaluate(OperationPtg ptg, ValueEval[] args,
                                         OperationEvaluationContext ec)
        {
            if (ptg == null)
            {
                throw new ArgumentException("ptg must not be null");
            }
            NPOI.SS.Formula.Functions.Function result = _instancesByPtgClass[ptg] as NPOI.SS.Formula.Functions.Function;

            if (result != null)
            {
                return(result.Evaluate(args, ec.RowIndex, (short)ec.ColumnIndex));
            }

            if (ptg is AbstractFunctionPtg)
            {
                AbstractFunctionPtg fptg = (AbstractFunctionPtg)ptg;
                int functionIndex        = fptg.FunctionIndex;
                switch (functionIndex)
                {
                case NPOI.SS.Formula.Function.FunctionMetadataRegistry.FUNCTION_INDEX_INDIRECT:
                    return(Indirect.instance.Evaluate(args, ec));

                case NPOI.SS.Formula.Function.FunctionMetadataRegistry.FUNCTION_INDEX_EXTERNAL:
                    return(UserDefinedFunction.instance.Evaluate(args, ec));
                }

                return(FunctionEval.GetBasicFunction(functionIndex).Evaluate(args, ec.RowIndex, ec.ColumnIndex));
            }
            throw new Exception("Unexpected operation ptg class (" + ptg.GetType().Name + ")");
        }
        /**
         * returns the OperationEval concrete impl instance corresponding
         * to the supplied operationPtg
         */
        public static OperationEval Create(OperationPtg ptg)
        {
            if (ptg == null)
            {
                throw new ArgumentException("ptg must not be null");
            }

            Type ptgClass = ptg.GetType();

            ConstructorInfo constructor = (ConstructorInfo)_constructorsByPtgClass[ptgClass];

            if (constructor == null)
            {
                if (ptgClass == typeof(ExpPtg))
                {
                    // ExpPtg Is used for array formulas and shared formulas.
                    // it Is currently Unsupported, and may not even Get implemented here
                    throw new Exception("ExpPtg currently not supported");
                }
                throw new Exception("Unexpected operation ptg class (" + ptgClass.Name + ")");
            }

            Object result;

            Object[] initargs = { ptg };
            try
            {
                result = constructor.Invoke(initargs);
            }
            catch (Exception)
            {
                throw;
            }
            return((OperationEval)result);
        }
Пример #3
0
 private static void Add(Hashtable m, OperationPtg ptgKey, Functions.Function instance)
 {
     // make sure ptg has single private constructor because map lookups assume singleton keys
     ConstructorInfo[] cc = ptgKey.GetType().GetConstructors();
     if (cc.Length > 1 || (cc.Length > 0 && !cc[0].IsPrivate))
     {
         throw new Exception("Failed to verify instance ("
                             + ptgKey.GetType().Name + ") is a singleton.");
     }
     m[ptgKey] = instance;
 }
Пример #4
0
        /**
         * returns the OperationEval concrete impl instance corresponding
         * to the supplied operationPtg
         */
        public static ValueEval Evaluate(OperationPtg ptg, ValueEval[] args,
                                         OperationEvaluationContext ec)
        {
            if (ptg == null)
            {
                throw new ArgumentException("ptg must not be null");
            }
            NPOI.SS.Formula.Functions.Function result = _instancesByPtgClass[ptg] as NPOI.SS.Formula.Functions.Function;

            FreeRefFunction udfFunc = null;

            if (result == null)
            {
                if (ptg is AbstractFunctionPtg)
                {
                    AbstractFunctionPtg fptg = (AbstractFunctionPtg)ptg;
                    int functionIndex        = fptg.FunctionIndex;
                    switch (functionIndex)
                    {
                    case NPOI.SS.Formula.Function.FunctionMetadataRegistry.FUNCTION_INDEX_INDIRECT:
                        udfFunc = Indirect.instance;
                        break;

                    case NPOI.SS.Formula.Function.FunctionMetadataRegistry.FUNCTION_INDEX_EXTERNAL:
                        udfFunc = UserDefinedFunction.instance;
                        break;

                    default:
                        result = FunctionEval.GetBasicFunction(functionIndex);
                        break;
                    }
                }
            }

            if (result != null)
            {
                if (result is ArrayFunction)
                {
                    ArrayFunction func = (ArrayFunction)result;
                    ValueEval     eval = EvaluateArrayFunction(func, args, ec);
                    if (eval != null)
                    {
                        return(eval);
                    }
                }
                return(result.Evaluate(args, ec.RowIndex, (short)ec.ColumnIndex));
            }
            else if (udfFunc != null)
            {
                return(udfFunc.Evaluate(args, ec));
            }
            throw new Exception("Unexpected operation ptg class (" + ptg.GetType().Name + ")");
        }
Пример #5
0
        /**
         * Static method To convert an array of {@link Ptg}s in RPN order
         * To a human readable string format in infix mode.
         * @param book  used for defined names and 3D references
         * @param ptgs  must not be <c>null</c>
         * @return a human readable String
         */
        public static String ToFormulaString(IFormulaRenderingWorkbook book, Ptg[] ptgs)
        {
            if (ptgs == null || ptgs.Length == 0)
            {
                throw new ArgumentException("ptgs must not be null");
            }
            Stack stack = new Stack();

            for (int i = 0; i < ptgs.Length; i++)
            {
                Ptg ptg = ptgs[i];
                // TODO - what about MemNoMemPtg?
                if (ptg is MemAreaPtg || ptg is MemFuncPtg || ptg is MemErrPtg)
                {
                    // marks the start of a list of area expressions which will be naturally combined
                    // by their trailing operators (e.g. UnionPtg)
                    // TODO - Put comment and throw exception in ToFormulaString() of these classes
                    continue;
                }
                if (ptg is ParenthesisPtg)
                {
                    String contents = (String)stack.Pop();
                    stack.Push("(" + contents + ")");
                    continue;
                }
                if (ptg is AttrPtg)
                {
                    AttrPtg attrPtg = ((AttrPtg)ptg);
                    if (attrPtg.IsOptimizedIf || attrPtg.IsOptimizedChoose || attrPtg.IsSkip)
                    {
                        continue;
                    }
                    if (attrPtg.IsSpace)
                    {
                        // POI currently doesn't render spaces in formulas
                        continue;
                        // but if it ever did, care must be taken:
                        // tAttrSpace comes *before* the operand it applies To, which may be consistent
                        // with how the formula text appears but is against the RPN ordering assumed here
                    }
                    if (attrPtg.IsSemiVolatile)
                    {
                        // similar To tAttrSpace - RPN is violated
                        continue;
                    }
                    if (attrPtg.IsSum)
                    {
                        String[] operands = GetOperands(stack, attrPtg.NumberOfOperands);
                        stack.Push(attrPtg.ToFormulaString(operands));
                        continue;
                    }
                    throw new Exception("Unexpected tAttr: " + attrPtg.ToString());
                }

                if (ptg is WorkbookDependentFormula)
                {
                    WorkbookDependentFormula optg = (WorkbookDependentFormula)ptg;
                    stack.Push(optg.ToFormulaString(book));
                    continue;
                }
                if (!(ptg is OperationPtg))
                {
                    stack.Push(ptg.ToFormulaString());
                    continue;
                }

                OperationPtg o         = (OperationPtg)ptg;
                String[]     operands1 = GetOperands(stack, o.NumberOfOperands);
                stack.Push(o.ToFormulaString(operands1));
            }
            if (stack.Count == 0)
            {
                // inspection of the code above reveals that every stack.pop() is followed by a
                // stack.push(). So this is either an internal error or impossible.
                throw new InvalidOperationException("Stack underflow");
            }
            String result = (String)stack.Pop();

            if (stack.Count != 0)
            {
                // Might be caused by some Tokens like AttrPtg and Mem*Ptg, which really shouldn't
                // Put anything on the stack
                throw new InvalidOperationException("too much stuff left on the stack");
            }
            return(result);
        }
Пример #6
0
        // visibility raised for testing
        /* package */
        public ValueEval EvaluateFormula(OperationEvaluationContext ec, Ptg[] ptgs)
        {
            Stack <ValueEval> stack = new Stack <ValueEval>();

            for (int i = 0, iSize = ptgs.Length; i < iSize; i++)
            {
                // since we don't know how To handle these yet :(
                Ptg ptg = ptgs[i];
                if (ptg is AttrPtg)
                {
                    AttrPtg attrPtg = (AttrPtg)ptg;
                    if (attrPtg.IsSum)
                    {
                        // Excel prefers To encode 'SUM()' as a tAttr Token, but this evaluator
                        // expects the equivalent function Token
                        //byte nArgs = 1;  // tAttrSum always Has 1 parameter
                        ptg = FuncVarPtg.SUM;//.Create("SUM", nArgs);
                    }
                    if (attrPtg.IsOptimizedChoose)
                    {
                        ValueEval arg0      = stack.Pop();
                        int[]     jumpTable = attrPtg.JumpTable;
                        int       dist;
                        int       nChoices = jumpTable.Length;
                        try
                        {
                            int switchIndex = Choose.EvaluateFirstArg(arg0, ec.RowIndex, ec.ColumnIndex);
                            if (switchIndex < 1 || switchIndex > nChoices)
                            {
                                stack.Push(ErrorEval.VALUE_INVALID);
                                dist = attrPtg.ChooseFuncOffset + 4; // +4 for tFuncFar(CHOOSE)
                            }
                            else
                            {
                                dist = jumpTable[switchIndex - 1];
                            }
                        }
                        catch (EvaluationException e)
                        {
                            stack.Push(e.GetErrorEval());
                            dist = attrPtg.ChooseFuncOffset + 4; // +4 for tFuncFar(CHOOSE)
                        }
                        // Encoded dist for tAttrChoose includes size of jump table, but
                        // countTokensToBeSkipped() does not (it counts whole tokens).
                        dist -= nChoices * 2 + 2; // subtract jump table size
                        i    += CountTokensToBeSkipped(ptgs, i, dist);
                        continue;
                    }
                    if (attrPtg.IsOptimizedIf)
                    {
                        ValueEval arg0 = stack.Pop();
                        bool      evaluatedPredicate;
                        try
                        {
                            evaluatedPredicate = If.EvaluateFirstArg(arg0, ec.RowIndex, ec.ColumnIndex);
                        }
                        catch (EvaluationException e)
                        {
                            stack.Push(e.GetErrorEval());
                            int dist = attrPtg.Data;
                            i      += CountTokensToBeSkipped(ptgs, i, dist);
                            attrPtg = (AttrPtg)ptgs[i];
                            dist    = attrPtg.Data + 1;
                            i      += CountTokensToBeSkipped(ptgs, i, dist);
                            continue;
                        }
                        if (evaluatedPredicate)
                        {
                            // nothing to skip - true param folows
                        }
                        else
                        {
                            int dist = attrPtg.Data;
                            i += CountTokensToBeSkipped(ptgs, i, dist);
                            Ptg nextPtg = ptgs[i + 1];
                            if (ptgs[i] is AttrPtg && nextPtg is FuncVarPtg)
                            {
                                // this is an if statement without a false param (as opposed to MissingArgPtg as the false param)
                                i++;
                                stack.Push(BoolEval.FALSE);
                            }
                        }
                        continue;
                    }
                    if (attrPtg.IsSkip)
                    {
                        int dist = attrPtg.Data + 1;
                        i += CountTokensToBeSkipped(ptgs, i, dist);
                        if (stack.Peek() == MissingArgEval.instance)
                        {
                            stack.Pop();
                            stack.Push(BlankEval.instance);
                        }
                        continue;
                    }
                }
                if (ptg is ControlPtg)
                {
                    // skip Parentheses, Attr, etc
                    continue;
                }
                if (ptg is MemFuncPtg)
                {
                    // can ignore, rest of Tokens for this expression are in OK RPN order
                    continue;
                }
                if (ptg is MemErrPtg)
                {
                    continue;
                }

                ValueEval opResult;
                if (ptg is OperationPtg)
                {
                    OperationPtg optg = (OperationPtg)ptg;

                    if (optg is UnionPtg)
                    {
                        continue;
                    }

                    int         numops = optg.NumberOfOperands;
                    ValueEval[] ops    = new ValueEval[numops];

                    // storing the ops in reverse order since they are popping
                    for (int j = numops - 1; j >= 0; j--)
                    {
                        ValueEval p = (ValueEval)stack.Pop();
                        ops[j] = p;
                    }
                    //				logDebug("Invoke " + operation + " (nAgs=" + numops + ")");
                    opResult = OperationEvaluatorFactory.Evaluate(optg, ops, ec);
                }
                else
                {
                    opResult = GetEvalForPtg(ptg, ec);
                }
                if (opResult == null)
                {
                    throw new Exception("Evaluation result must not be null");
                }
                //			logDebug("push " + opResult);
                stack.Push(opResult);
            }

            ValueEval value = ((ValueEval)stack.Pop());

            if (stack.Count != 0)
            {
                throw new InvalidOperationException("evaluation stack not empty");
            }
            return(DereferenceResult(value, ec.RowIndex, ec.ColumnIndex));
        }
Пример #7
0
        // visibility raised for testing
        /* package */

        public ValueEval EvaluateFormula(OperationEvaluationContext ec, Ptg[] ptgs)
        {
            string dbgIndentStr = "";           // always init. to non-null just for defensive avoiding NPE

            if (dbgEvaluationOutputForNextEval)
            {
                // first evaluation call when ouput is desired, so iit. this evaluator instance
                dbgEvaluationOutputIndent      = 1;
                dbgEvaluationOutputForNextEval = false;
            }
            if (dbgEvaluationOutputIndent > 0)
            {
                // init. indent string to needed spaces (create as substring vom very long space-only string;
                // limit indendation for deep recursions)
                dbgIndentStr = "                                                                                                    ";
                dbgIndentStr = dbgIndentStr.Substring(0, Math.Min(dbgIndentStr.Length, dbgEvaluationOutputIndent * 2));
                EVAL_LOG.Log(POILogger.WARN, dbgIndentStr
                             + "- evaluateFormula('" + ec.GetRefEvaluatorForCurrentSheet().SheetNameRange
                             + "'/" + new CellReference(ec.RowIndex, ec.ColumnIndex).FormatAsString()
                             + "): " + Arrays.ToString(ptgs).Replace("\\Qorg.apache.poi.ss.formula.ptg.\\E", ""));
                dbgEvaluationOutputIndent++;
            }

            Stack <ValueEval> stack = new Stack <ValueEval>();

            for (int i = 0, iSize = ptgs.Length; i < iSize; i++)
            {
                // since we don't know how To handle these yet :(
                Ptg ptg = ptgs[i];
                if (dbgEvaluationOutputIndent > 0)
                {
                    EVAL_LOG.Log(POILogger.INFO, dbgIndentStr + "  * ptg " + i + ": " + ptg.ToString());
                }
                if (ptg is AttrPtg)
                {
                    AttrPtg attrPtg = (AttrPtg)ptg;
                    if (attrPtg.IsSum)
                    {
                        // Excel prefers To encode 'SUM()' as a tAttr Token, but this evaluator
                        // expects the equivalent function Token
                        //byte nArgs = 1;  // tAttrSum always Has 1 parameter
                        ptg = FuncVarPtg.SUM;//.Create("SUM", nArgs);
                    }
                    if (attrPtg.IsOptimizedChoose)
                    {
                        ValueEval arg0      = stack.Pop();
                        int[]     jumpTable = attrPtg.JumpTable;
                        int       dist;
                        int       nChoices = jumpTable.Length;
                        try
                        {
                            int switchIndex = Choose.EvaluateFirstArg(arg0, ec.RowIndex, ec.ColumnIndex);
                            if (switchIndex < 1 || switchIndex > nChoices)
                            {
                                stack.Push(ErrorEval.VALUE_INVALID);
                                dist = attrPtg.ChooseFuncOffset + 4; // +4 for tFuncFar(CHOOSE)
                            }
                            else
                            {
                                dist = jumpTable[switchIndex - 1];
                            }
                        }
                        catch (EvaluationException e)
                        {
                            stack.Push(e.GetErrorEval());
                            dist = attrPtg.ChooseFuncOffset + 4; // +4 for tFuncFar(CHOOSE)
                        }
                        // Encoded dist for tAttrChoose includes size of jump table, but
                        // countTokensToBeSkipped() does not (it counts whole tokens).
                        dist -= nChoices * 2 + 2; // subtract jump table size
                        i    += CountTokensToBeSkipped(ptgs, i, dist);
                        continue;
                    }
                    if (attrPtg.IsOptimizedIf)
                    {
                        ValueEval arg0 = stack.Pop();
                        bool      evaluatedPredicate;
                        try
                        {
                            evaluatedPredicate = If.EvaluateFirstArg(arg0, ec.RowIndex, ec.ColumnIndex);
                        }
                        catch (EvaluationException e)
                        {
                            stack.Push(e.GetErrorEval());
                            int dist = attrPtg.Data;
                            i      += CountTokensToBeSkipped(ptgs, i, dist);
                            attrPtg = (AttrPtg)ptgs[i];
                            dist    = attrPtg.Data + 1;
                            i      += CountTokensToBeSkipped(ptgs, i, dist);
                            continue;
                        }
                        if (evaluatedPredicate)
                        {
                            // nothing to skip - true param folows
                        }
                        else
                        {
                            int dist = attrPtg.Data;
                            i += CountTokensToBeSkipped(ptgs, i, dist);
                            Ptg nextPtg = ptgs[i + 1];
                            if (ptgs[i] is AttrPtg && nextPtg is FuncVarPtg &&
                                // in order to verify that there is no third param, we need to check
                                // if we really have the IF next or some other FuncVarPtg as third param, e.g. ROW()/COLUMN()!
                                ((FuncVarPtg)nextPtg).FunctionIndex == FunctionMetadataRegistry.FUNCTION_INDEX_IF)
                            {
                                // this is an if statement without a false param (as opposed to MissingArgPtg as the false param)
                                i++;
                                stack.Push(BoolEval.FALSE);
                            }
                        }
                        continue;
                    }
                    if (attrPtg.IsSkip)
                    {
                        int dist = attrPtg.Data + 1;
                        i += CountTokensToBeSkipped(ptgs, i, dist);
                        if (stack.Peek() == MissingArgEval.instance)
                        {
                            stack.Pop();
                            stack.Push(BlankEval.instance);
                        }
                        continue;
                    }
                }
                if (ptg is ControlPtg)
                {
                    // skip Parentheses, Attr, etc
                    continue;
                }
                if (ptg is MemFuncPtg || ptg is MemAreaPtg)
                {
                    // can ignore, rest of Tokens for this expression are in OK RPN order
                    continue;
                }
                if (ptg is MemErrPtg)
                {
                    continue;
                }

                ValueEval opResult;
                if (ptg is OperationPtg)
                {
                    OperationPtg optg = (OperationPtg)ptg;

                    if (optg is UnionPtg)
                    {
                        continue;
                    }

                    int         numops = optg.NumberOfOperands;
                    ValueEval[] ops    = new ValueEval[numops];

                    // storing the ops in reverse order since they are popping
                    for (int j = numops - 1; j >= 0; j--)
                    {
                        ValueEval p = (ValueEval)stack.Pop();
                        ops[j] = p;
                    }
                    //				logDebug("Invoke " + operation + " (nAgs=" + numops + ")");
                    opResult = OperationEvaluatorFactory.Evaluate(optg, ops, ec);
                }
                else
                {
                    opResult = GetEvalForPtg(ptg, ec);
                }
                if (opResult == null)
                {
                    throw new Exception("Evaluation result must not be null");
                }
                //			logDebug("push " + opResult);
                stack.Push(opResult);
                if (dbgEvaluationOutputIndent > 0)
                {
                    EVAL_LOG.Log(POILogger.INFO, dbgIndentStr + "    = " + opResult.ToString());
                }
            }

            ValueEval value = ((ValueEval)stack.Pop());

            if (stack.Count != 0)
            {
                throw new InvalidOperationException("evaluation stack not empty");
            }
            ValueEval result = DereferenceResult(value, ec.RowIndex, ec.ColumnIndex);

            if (dbgEvaluationOutputIndent > 0)
            {
                EVAL_LOG.Log(POILogger.INFO, dbgIndentStr + "finshed eval of "
                             + new CellReference(ec.RowIndex, ec.ColumnIndex).FormatAsString()
                             + ": " + result.ToString());
                dbgEvaluationOutputIndent--;
                if (dbgEvaluationOutputIndent == 1)
                {
                    // this evaluation is done, reset indent to stop logging
                    dbgEvaluationOutputIndent = -1;
                }
            } // if
            return(result);
        }