/** * @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; }
/** * 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); } }