// 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));
        }
示例#2
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);
        }