/** 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 IllegalArgumentException("ptg must not be null");
    }
    Function result = _instancesByPtgClass.get(ptg);

    if (result != null) {
      return result.evaluate(args, ec.getRowIndex(), (short) ec.getColumnIndex());
    }

    if (ptg instanceof AbstractFunctionPtg) {
      AbstractFunctionPtg fptg = (AbstractFunctionPtg) ptg;
      int functionIndex = fptg.getFunctionIndex();
      switch (functionIndex) {
        case FunctionMetadataRegistry.FUNCTION_INDEX_INDIRECT:
          return Indirect.instance.evaluate(args, ec);
        case FunctionMetadataRegistry.FUNCTION_INDEX_EXTERNAL:
          return UserDefinedFunction.instance.evaluate(args, ec);
      }

      return FunctionEval.getBasicFunction(functionIndex)
          .evaluate(args, ec.getRowIndex(), (short) ec.getColumnIndex());
    }
    throw new RuntimeException("Unexpected operation ptg class (" + ptg.getClass().getName() + ")");
  }
Пример #2
0
  /**
   * returns an appropriate Eval impl instance for the Ptg. The Ptg must be one of: Area3DPtg,
   * AreaPtg, ReferencePtg, Ref3DPtg, IntPtg, NumberPtg, StringPtg, BoolPtg <br>
   * special Note: OperationPtg subtypes cannot be passed here!
   */
  private ValueEval getEvalForPtg(Ptg ptg, OperationEvaluationContext ec) {
    //  consider converting all these (ptg instanceof XxxPtg) expressions to (ptg.getClass() ==
    // XxxPtg.class)

    if (ptg instanceof NamePtg) {
      // named ranges, macro functions
      NamePtg namePtg = (NamePtg) ptg;
      EvaluationName nameRecord = _workbook.getName(namePtg);
      if (nameRecord.isFunctionName()) {
        return new NameEval(nameRecord.getNameText());
      }
      if (nameRecord.hasFormula()) {
        return evaluateNameFormula(nameRecord.getNameDefinition(), ec);
      }

      throw new RuntimeException(
          "Don't now how to evalate name '" + nameRecord.getNameText() + "'");
    }
    if (ptg instanceof NameXPtg) {
      return new NameXEval(((NameXPtg) ptg));
    }

    if (ptg instanceof IntPtg) {
      return new NumberEval(((IntPtg) ptg).getValue());
    }
    if (ptg instanceof NumberPtg) {
      return new NumberEval(((NumberPtg) ptg).getValue());
    }
    if (ptg instanceof StringPtg) {
      return new StringEval(((StringPtg) ptg).getValue());
    }
    if (ptg instanceof BoolPtg) {
      return BoolEval.valueOf(((BoolPtg) ptg).getValue());
    }
    if (ptg instanceof ErrPtg) {
      return ErrorEval.valueOf(((ErrPtg) ptg).getErrorCode());
    }
    if (ptg instanceof MissingArgPtg) {
      return MissingArgEval.instance;
    }
    if (ptg instanceof AreaErrPtg
        || ptg instanceof RefErrorPtg
        || ptg instanceof DeletedArea3DPtg
        || ptg instanceof DeletedRef3DPtg) {
      return ErrorEval.REF_INVALID;
    }
    if (ptg instanceof Ref3DPtg) {
      Ref3DPtg refPtg = (Ref3DPtg) ptg;
      SheetRefEvaluator sre = ec.createExternSheetRefEvaluator(refPtg);
      return new LazyRefEval(refPtg, sre);
    }
    if (ptg instanceof Area3DPtg) {
      Area3DPtg aptg = (Area3DPtg) ptg;
      SheetRefEvaluator sre = ec.createExternSheetRefEvaluator(aptg);
      return new LazyAreaEval(aptg, sre);
    }
    SheetRefEvaluator sre = ec.getRefEvaluatorForCurrentSheet();
    if (ptg instanceof RefPtg) {
      return new LazyRefEval(((RefPtg) ptg), sre);
    }
    if (ptg instanceof AreaPtg) {
      return new LazyAreaEval(((AreaPtg) ptg), sre);
    }

    if (ptg instanceof UnknownPtg) {
      // POI uses UnknownPtg when the encoded Ptg array seems to be corrupted.
      // This seems to occur in very rare cases (e.g. unused name formulas in bug 44774, attachment
      // 21790)
      // In any case, formulas are re-parsed before execution, so UnknownPtg should not get here
      throw new RuntimeException("UnknownPtg not allowed");
    }
    if (ptg instanceof ExpPtg) {
      // ExpPtg is used for array formulas and shared formulas.
      // it is currently unsupported, and may not even get implemented here
      throw new RuntimeException("ExpPtg currently not supported");
    }

    throw new RuntimeException("Unexpected ptg class (" + ptg.getClass().getName() + ")");
  }
Пример #3
0
  // visibility raised for testing
  /* package */ 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 instanceof 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 = new FuncVarPtg("SUM", nArgs);
        }
      }
      if (ptg instanceof ControlPtg) {
        // skip Parentheses, Attr, etc
        continue;
      }
      if (ptg instanceof MemFuncPtg) {
        // can ignore, rest of tokens for this expression are in OK RPN order
        continue;
      }
      if (ptg instanceof MemErrPtg) {
        continue;
      }

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

        if (optg instanceof UnionPtg) {
          continue;
        }

        OperationEval operation = OperationEvaluatorFactory.create(optg);

        int numops = operation.getNumberOfOperands();
        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 = stack.pop();
          ops[j] = p;
        }
        //				logDebug("invoke " + operation + " (nAgs=" + numops + ")");
        opResult = operation.evaluate(ops, ec);
        if (opResult == MissingArgEval.instance) {
          opResult = BlankEval.INSTANCE;
        }
      } else {
        opResult = getEvalForPtg(ptg, ec);
      }
      if (opResult == null) {
        throw new RuntimeException("Evaluation result must not be null");
      }
      //			logDebug("push " + opResult);
      stack.push(opResult);
    }

    ValueEval value = stack.pop();
    if (!stack.isEmpty()) {
      throw new IllegalStateException("evaluation stack not empty");
    }
    value = dereferenceValue(value, ec.getRowIndex(), ec.getColumnIndex());
    if (value == BlankEval.INSTANCE) {
      // Note Excel behaviour here. A blank final final value is converted to zero.
      return NumberEval.ZERO;
      // Formulas _never_ evaluate to blank.  If a formula appears to have evaluated to
      // blank, the actual value is empty string. This can be verified with ISBLANK().
    }
    return value;
  }