private static boolean isSingleArgSum(Ptg token) {
   if (token instanceof AttrPtg) {
     AttrPtg attrPtg = (AttrPtg) token;
     return attrPtg.isSum();
   }
   return false;
 }
Пример #2
0
  /**
   * Generates the variable function ptg for the formula.
   *
   * <p>For IF Formulas, additional PTGs are added to the tokens
   *
   * @param name a {@link NamePtg} or {@link NameXPtg} or <code>null</code>
   * @return Ptg a null is returned if we're in an IF formula, it needs extreme manipulation and is
   *     handled in this function
   */
  private ParseNode getFunction(String name, Ptg namePtg, ParseNode[] args) {

    FunctionMetadata fm = FunctionMetadataRegistry.getFunctionByName(name.toUpperCase());
    int numArgs = args.length;
    if (fm == null) {
      if (namePtg == null) {
        throw new IllegalStateException("NamePtg must be supplied for external functions");
      }
      // must be external function
      ParseNode[] allArgs = new ParseNode[numArgs + 1];
      allArgs[0] = new ParseNode(namePtg);
      System.arraycopy(args, 0, allArgs, 1, numArgs);
      return new ParseNode(new FuncVarPtg(name, (byte) (numArgs + 1)), allArgs);
    }

    if (namePtg != null) {
      throw new IllegalStateException("NamePtg no applicable to internal functions");
    }
    boolean isVarArgs = !fm.hasFixedArgsLength();
    int funcIx = fm.getIndex();
    if (funcIx == FunctionMetadataRegistry.FUNCTION_INDEX_SUM && args.length == 1) {
      // Excel encodes the sum of a single argument as tAttrSum
      // POI does the same for consistency, but this is not critical
      return new ParseNode(AttrPtg.getSumSingle(), args);
      // The code below would encode tFuncVar(SUM) which seems to do no harm
    }
    validateNumArgs(args.length, fm);

    AbstractFunctionPtg retval;
    if (isVarArgs) {
      retval = new FuncVarPtg(name, (byte) numArgs);
    } else {
      retval = new FuncPtg(funcIx);
    }
    return new ParseNode(retval, args);
  }
Пример #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;
  }