예제 #1
0
  /**
   * @return <code>false</code> if sub-expression represented the specified ParseNode definitely
   *     cannot appear on either side of the range (':') operator
   */
  private static boolean isValidRangeOperand(ParseNode a) {
    Ptg tkn = a.getToken();
    // Note - order is important for these instance-of checks
    if (tkn instanceof OperandPtg) {
      // notably cell refs and area refs
      return true;
    }

    // next 2 are special cases of OperationPtg
    if (tkn instanceof AbstractFunctionPtg) {
      AbstractFunctionPtg afp = (AbstractFunctionPtg) tkn;
      byte returnClass = afp.getDefaultOperandClass();
      return Ptg.CLASS_REF == returnClass;
    }
    if (tkn instanceof ValueOperatorPtg) {
      return false;
    }
    if (tkn instanceof OperationPtg) {
      return true;
    }

    // one special case of ControlPtg
    if (tkn instanceof ParenthesisPtg) {
      // parenthesis Ptg should have only one child
      return isValidRangeOperand(a.getChildren()[0]);
    }

    // one special case of ScalarConstantPtg
    if (tkn == ErrPtg.REF_INVALID) {
      return true;
    }

    // All other ControlPtgs and ScalarConstantPtgs cannot be used with ':'
    return false;
  }
  /** 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() + ")");
  }
  private void setSimpleValueFuncClass(
      AbstractFunctionPtg afp, byte desiredOperandClass, boolean callerForceArrayFlag) {

    if (callerForceArrayFlag || desiredOperandClass == Ptg.CLASS_ARRAY) {
      afp.setClass(Ptg.CLASS_ARRAY);
    } else {
      afp.setClass(Ptg.CLASS_VALUE);
    }
  }
 private static boolean isSimpleValueFunction(Ptg token) {
   if (token instanceof AbstractFunctionPtg) {
     AbstractFunctionPtg aptg = (AbstractFunctionPtg) token;
     if (aptg.getDefaultOperandClass() != Ptg.CLASS_VALUE) {
       return false;
     }
     int numberOfOperands = aptg.getNumberOfOperands();
     for (int i = numberOfOperands - 1; i >= 0; i--) {
       if (aptg.getParameterClass(i) != Ptg.CLASS_VALUE) {
         return false;
       }
     }
     return true;
   }
   return false;
 }
예제 #5
0
  /**
   * Note - Excel function names are 'case aware but not case sensitive'. This method may end up
   * creating a defined name record in the workbook if the specified name is not an internal Excel
   * function, and has not been encountered before.
   *
   * @param name case preserved function name (as it was entered/appeared in the formula).
   */
  private ParseNode function(String name) {
    Ptg nameToken = null;
    if (!AbstractFunctionPtg.isBuiltInFunctionName(name)) {
      // user defined function
      // in the token tree, the name is more or less the first argument

      if (_book == null) {
        // Only test cases omit the book (expecting it not to be needed)
        throw new IllegalStateException("Need book to evaluate name '" + name + "'");
      }
      EvaluationName hName = _book.getName(name, _sheetIndex);
      if (hName == null) {

        nameToken = _book.getNameXPtg(name);
        if (nameToken == null) {
          throw new FormulaParseException(
              "Name '" + name + "' is completely unknown in the current workbook");
        }
      } else {
        if (!hName.isFunctionName()) {
          throw new FormulaParseException(
              "Attempt to use name '"
                  + name
                  + "' as a function, but defined name in workbook does not refer to a function");
        }

        // calls to user-defined functions within the workbook
        // get a Name token which points to a defined name record
        nameToken = hName.createPtg();
      }
    }

    Match('(');
    ParseNode[] args = Arguments();
    Match(')');

    return getFunction(name, nameToken, args);
  }
  private void transformFunctionNode(
      AbstractFunctionPtg afp,
      ParseNode[] children,
      byte desiredOperandClass,
      boolean callerForceArrayFlag) {

    boolean localForceArrayFlag;
    byte defaultReturnOperandClass = afp.getDefaultOperandClass();

    if (callerForceArrayFlag) {
      switch (defaultReturnOperandClass) {
        case Ptg.CLASS_REF:
          if (desiredOperandClass == Ptg.CLASS_REF) {
            afp.setClass(Ptg.CLASS_REF);
          } else {
            afp.setClass(Ptg.CLASS_ARRAY);
          }
          localForceArrayFlag = false;
          break;
        case Ptg.CLASS_ARRAY:
          afp.setClass(Ptg.CLASS_ARRAY);
          localForceArrayFlag = false;
          break;
        case Ptg.CLASS_VALUE:
          afp.setClass(Ptg.CLASS_ARRAY);
          localForceArrayFlag = true;
          break;
        default:
          throw new IllegalStateException(
              "Unexpected operand class (" + defaultReturnOperandClass + ")");
      }
    } else {
      if (defaultReturnOperandClass == desiredOperandClass) {
        localForceArrayFlag = false;
        // an alternative would have been to for non-base Ptgs to set their operand class
        // from their default, but this would require the call in many subclasses because
        // the default OC is not known until the end of the constructor
        afp.setClass(defaultReturnOperandClass);
      } else {
        switch (desiredOperandClass) {
          case Ptg.CLASS_VALUE:
            // always OK to set functions to return 'value'
            afp.setClass(Ptg.CLASS_VALUE);
            localForceArrayFlag = false;
            break;
          case Ptg.CLASS_ARRAY:
            switch (defaultReturnOperandClass) {
              case Ptg.CLASS_REF:
                afp.setClass(Ptg.CLASS_REF);
                //								afp.setClass(Ptg.CLASS_ARRAY);
                break;
              case Ptg.CLASS_VALUE:
                afp.setClass(Ptg.CLASS_ARRAY);
                break;
              default:
                throw new IllegalStateException(
                    "Unexpected operand class (" + defaultReturnOperandClass + ")");
            }
            localForceArrayFlag = (defaultReturnOperandClass == Ptg.CLASS_VALUE);
            break;
          case Ptg.CLASS_REF:
            switch (defaultReturnOperandClass) {
              case Ptg.CLASS_ARRAY:
                afp.setClass(Ptg.CLASS_ARRAY);
                break;
              case Ptg.CLASS_VALUE:
                afp.setClass(Ptg.CLASS_VALUE);
                break;
              default:
                throw new IllegalStateException(
                    "Unexpected operand class (" + defaultReturnOperandClass + ")");
            }
            localForceArrayFlag = false;
            break;
          default:
            throw new IllegalStateException(
                "Unexpected operand class (" + desiredOperandClass + ")");
        }
      }
    }

    for (int i = 0; i < children.length; i++) {
      ParseNode child = children[i];
      byte paramOperandClass = afp.getParameterClass(i);
      transformNode(child, paramOperandClass, localForceArrayFlag);
    }
  }