private void validateNumArgs(int numArgs, FunctionMetadata fm) { if (numArgs < fm.getMinParams()) { String msg = "Too few arguments to function '" + fm.getName() + "'. "; if (fm.hasFixedArgsLength()) { msg += "Expected " + fm.getMinParams(); } else { msg += "At least " + fm.getMinParams() + " were expected"; } msg += " but got " + numArgs + "."; throw new FormulaParseException(msg); } // the maximum number of arguments depends on the Excel version int maxArgs; if (fm.hasUnlimitedVarags()) { if (_book != null) { maxArgs = _book.getSpreadsheetVersion().getMaxFunctionArgs(); } else { // _book can be omitted by test cases maxArgs = fm.getMaxParams(); // just use BIFF8 } } else { maxArgs = fm.getMaxParams(); } if (numArgs > maxArgs) { String msg = "Too many arguments to function '" + fm.getName() + "'. "; if (fm.hasFixedArgsLength()) { msg += "Expected " + maxArgs; } else { msg += "At most " + maxArgs + " were expected"; } msg += " but got " + numArgs + "."; throw new FormulaParseException(msg); } }
/** * 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(FuncVarPtg.create(name, 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 = FuncVarPtg.create(name, numArgs); } else { retval = FuncPtg.create(funcIx); } return new ParseNode(retval, args); }