Replaced ErrorEval.FUNCTION_NOT_IMPLEMENTED with new exception NotImplementedException. Removed test case involving ISREF which was working for the wrong reasons.

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@736505 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2009-01-22 00:26:28 +00:00
parent c013d9b7c9
commit 59e334e8a5
12 changed files with 233 additions and 168 deletions

View File

@ -20,34 +20,39 @@ package org.apache.poi.hssf.record.formula.atp;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.Eval;
import org.apache.poi.hssf.record.formula.eval.ValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
import org.apache.poi.ss.formula.EvaluationWorkbook; import org.apache.poi.ss.formula.EvaluationWorkbook;
import org.apache.poi.ss.formula.eval.NotImplementedException;
public final class AnalysisToolPak { public final class AnalysisToolPak {
private static final FreeRefFunction NotImplemented = new FreeRefFunction() { private static final class NotImplemented implements FreeRefFunction {
private final String _functionName;
public NotImplemented(String functionName) {
_functionName = functionName;
}
public ValueEval evaluate(Eval[] args, EvaluationWorkbook workbook, int srcCellSheet, public ValueEval evaluate(Eval[] args, EvaluationWorkbook workbook, int srcCellSheet,
int srcCellRow, int srcCellCol) { int srcCellRow, int srcCellCol) {
return ErrorEval.FUNCTION_NOT_IMPLEMENTED; throw new NotImplementedException(_functionName);
} }
}; };
private static Map _functionsByName = createFunctionsMap(); private static Map<String, FreeRefFunction> _functionsByName = createFunctionsMap();
private AnalysisToolPak() { private AnalysisToolPak() {
// no instances of this class // no instances of this class
} }
public static FreeRefFunction findFunction(String name) { public static FreeRefFunction findFunction(String name) {
return (FreeRefFunction)_functionsByName.get(name); return _functionsByName.get(name);
} }
private static Map createFunctionsMap() { private static Map<String, FreeRefFunction> createFunctionsMap() {
Map m = new HashMap(100); Map<String, FreeRefFunction> m = new HashMap<String, FreeRefFunction>(100);
r(m, "ACCRINT", null); r(m, "ACCRINT", null);
r(m, "ACCRINTM", null); r(m, "ACCRINTM", null);
@ -146,8 +151,8 @@ public final class AnalysisToolPak {
return m; return m;
} }
private static void r(Map m, String functionName, FreeRefFunction pFunc) { private static void r(Map<String, FreeRefFunction> m, String functionName, FreeRefFunction pFunc) {
FreeRefFunction func = pFunc == null ? NotImplemented : pFunc; FreeRefFunction func = pFunc == null ? new NotImplemented(functionName) : pFunc;
m.put(functionName, func); m.put(functionName, func);
} }
} }

View File

@ -48,7 +48,6 @@ public final class ErrorEval implements ValueEval {
private static final int CIRCULAR_REF_ERROR_CODE = 0xFFFFFFC4; private static final int CIRCULAR_REF_ERROR_CODE = 0xFFFFFFC4;
private static final int FUNCTION_NOT_IMPLEMENTED_CODE = 0xFFFFFFE2; private static final int FUNCTION_NOT_IMPLEMENTED_CODE = 0xFFFFFFE2;
public static final ErrorEval FUNCTION_NOT_IMPLEMENTED = new ErrorEval(FUNCTION_NOT_IMPLEMENTED_CODE);
// Note - Excel does not seem to represent this condition with an error code // Note - Excel does not seem to represent this condition with an error code
public static final ErrorEval CIRCULAR_REF_ERROR = new ErrorEval(CIRCULAR_REF_ERROR_CODE); public static final ErrorEval CIRCULAR_REF_ERROR = new ErrorEval(CIRCULAR_REF_ERROR_CODE);
@ -68,7 +67,6 @@ public final class ErrorEval implements ValueEval {
case HSSFErrorConstants.ERROR_NA: return NA; case HSSFErrorConstants.ERROR_NA: return NA;
// non-std errors (conditions modeled as errors by POI) // non-std errors (conditions modeled as errors by POI)
case CIRCULAR_REF_ERROR_CODE: return CIRCULAR_REF_ERROR; case CIRCULAR_REF_ERROR_CODE: return CIRCULAR_REF_ERROR;
case FUNCTION_NOT_IMPLEMENTED_CODE: return FUNCTION_NOT_IMPLEMENTED;
} }
throw new RuntimeException("Unexpected error code (" + errorCode + ")"); throw new RuntimeException("Unexpected error code (" + errorCode + ")");
} }

View File

@ -20,6 +20,7 @@ package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.atp.AnalysisToolPak; import org.apache.poi.hssf.record.formula.atp.AnalysisToolPak;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction; import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
import org.apache.poi.ss.formula.EvaluationWorkbook; import org.apache.poi.ss.formula.EvaluationWorkbook;
import org.apache.poi.ss.formula.eval.NotImplementedException;
/** /**
* *
* Common entry point for all user-defined (non-built-in) functions (where * Common entry point for all user-defined (non-built-in) functions (where
@ -40,7 +41,6 @@ final class ExternalFunction implements FreeRefFunction {
Eval nameArg = args[0]; Eval nameArg = args[0];
FreeRefFunction targetFunc; FreeRefFunction targetFunc;
try {
if (nameArg instanceof NameEval) { if (nameArg instanceof NameEval) {
targetFunc = findInternalUserDefinedFunction((NameEval) nameArg); targetFunc = findInternalUserDefinedFunction((NameEval) nameArg);
} else if (nameArg instanceof NameXEval) { } else if (nameArg instanceof NameXEval) {
@ -49,17 +49,14 @@ final class ExternalFunction implements FreeRefFunction {
throw new RuntimeException("First argument should be a NameEval, but got (" throw new RuntimeException("First argument should be a NameEval, but got ("
+ nameArg.getClass().getName() + ")"); + nameArg.getClass().getName() + ")");
} }
} catch (EvaluationException e) {
return e.getErrorEval();
}
int nOutGoingArgs = nIncomingArgs -1; int nOutGoingArgs = nIncomingArgs -1;
Eval[] outGoingArgs = new Eval[nOutGoingArgs]; Eval[] outGoingArgs = new Eval[nOutGoingArgs];
System.arraycopy(args, 1, outGoingArgs, 0, nOutGoingArgs); System.arraycopy(args, 1, outGoingArgs, 0, nOutGoingArgs);
return targetFunc.evaluate(outGoingArgs, workbook, srcCellSheet, srcCellRow, srcCellCol); return targetFunc.evaluate(outGoingArgs, workbook, srcCellSheet, srcCellRow, srcCellCol);
} }
private FreeRefFunction findExternalUserDefinedFunction(EvaluationWorkbook workbook, private static FreeRefFunction findExternalUserDefinedFunction(EvaluationWorkbook workbook,
NameXEval n) throws EvaluationException { NameXEval n) {
String functionName = workbook.resolveNameXText(n.getPtg()); String functionName = workbook.resolveNameXText(n.getPtg());
if(false) { if(false) {
@ -71,10 +68,10 @@ final class ExternalFunction implements FreeRefFunction {
if (result != null) { if (result != null) {
return result; return result;
} }
throw new EvaluationException(ErrorEval.FUNCTION_NOT_IMPLEMENTED); throw new NotImplementedException(functionName);
} }
private FreeRefFunction findInternalUserDefinedFunction(NameEval functionNameEval) throws EvaluationException { private static FreeRefFunction findInternalUserDefinedFunction(NameEval functionNameEval) {
String functionName = functionNameEval.getFunctionName(); String functionName = functionNameEval.getFunctionName();
if(false) { if(false) {
@ -82,7 +79,6 @@ final class ExternalFunction implements FreeRefFunction {
} }
// TODO find the implementation for the user defined function // TODO find the implementation for the user defined function
throw new EvaluationException(ErrorEval.FUNCTION_NOT_IMPLEMENTED); throw new NotImplementedException(functionName);
} }
} }

View File

@ -19,6 +19,7 @@ package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.AbstractFunctionPtg; import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
import org.apache.poi.hssf.record.formula.functions.Function; import org.apache.poi.hssf.record.formula.functions.Function;
import org.apache.poi.ss.formula.eval.NotImplementedException;
/** /**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt; * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
@ -35,7 +36,7 @@ public final class FuncVarEval extends FunctionEval {
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
Function f = getFunction(); Function f = getFunction();
if (f == null) { if (f == null) {
return ErrorEval.FUNCTION_NOT_IMPLEMENTED; throw new NotImplementedException("FuncIx=" + getFunctionIndex());
} }
return f.evaluate(operands, srcRow, srcCol); return f.evaluate(operands, srcRow, srcCol);
} }

View File

@ -43,17 +43,14 @@ public abstract class FunctionEval implements OperationEval {
protected static Function[] functions = produceFunctions(); protected static Function[] functions = produceFunctions();
private static Map freeRefFunctionsByIdMap; private static Map<Integer, FreeRefFunction> freeRefFunctionsByIdMap;
static { static {
Map m = new HashMap(); Map<Integer, FreeRefFunction> m = new HashMap<Integer, FreeRefFunction>();
addMapping(m, ID.INDIRECT, new Indirect()); m.put(createFRFKey(ID.INDIRECT), new Indirect());
addMapping(m, ID.EXTERNAL_FUNC, new ExternalFunction()); m.put(createFRFKey(ID.EXTERNAL_FUNC), new ExternalFunction());
freeRefFunctionsByIdMap = m; freeRefFunctionsByIdMap = m;
} }
private static void addMapping(Map m, int offset, FreeRefFunction frf) {
m.put(createFRFKey(offset), frf);
}
private static Integer createFRFKey(int functionIndex) { private static Integer createFRFKey(int functionIndex) {
return new Integer(functionIndex); return new Integer(functionIndex);
} }
@ -67,7 +64,7 @@ public abstract class FunctionEval implements OperationEval {
return freeRefFunctionsByIdMap.containsKey(createFRFKey(getFunctionIndex())); return freeRefFunctionsByIdMap.containsKey(createFRFKey(getFunctionIndex()));
} }
public FreeRefFunction getFreeRefFunction() { public FreeRefFunction getFreeRefFunction() {
return (FreeRefFunction) freeRefFunctionsByIdMap.get(createFRFKey(getFunctionIndex())); return freeRefFunctionsByIdMap.get(createFRFKey(getFunctionIndex()));
} }
public abstract short getFunctionIndex(); public abstract short getFunctionIndex();
@ -164,11 +161,11 @@ public abstract class FunctionEval implements OperationEval {
retval[88] = new Setname(); // SETNAME retval[88] = new Setname(); // SETNAME
retval[89] = new Caller(); // CALLER retval[89] = new Caller(); // CALLER
retval[90] = new Deref(); // DEREF retval[90] = new Deref(); // DEREF
retval[91] = new NotImplementedFunction(); // WINDOWS retval[91] = new NotImplementedFunction("WINDOWS");
retval[92] = new Series(); // SERIES retval[92] = new Series(); // SERIES
retval[93] = new NotImplementedFunction(); // DOCUMENTS retval[93] = new NotImplementedFunction("DOCUMENTS");
retval[94] = new Activecell(); // ACTIVECELL retval[94] = new Activecell(); // ACTIVECELL
retval[95] = new NotImplementedFunction(); // SELECTION retval[95] = new NotImplementedFunction("SELECTION");
retval[96] = new Result(); // RESULT retval[96] = new Result(); // RESULT
retval[97] = NumericFunction.ATAN2; retval[97] = NumericFunction.ATAN2;
retval[98] = NumericFunction.ASIN; retval[98] = NumericFunction.ASIN;
@ -179,8 +176,8 @@ public abstract class FunctionEval implements OperationEval {
retval[103] = new Links(); // LINKS retval[103] = new Links(); // LINKS
retval[104] = new Input(); // INPUT retval[104] = new Input(); // INPUT
retval[105] = new Isref(); // ISREF retval[105] = new Isref(); // ISREF
retval[106] = new NotImplementedFunction(); // GETFORMULA retval[106] = new NotImplementedFunction("GETFORMULA");
retval[107] = new NotImplementedFunction(); // GETNAME retval[107] = new NotImplementedFunction("GETNAME");
retval[108] = new Setvalue(); // SETVALUE retval[108] = new Setvalue(); // SETVALUE
retval[109] = NumericFunction.LOG; retval[109] = NumericFunction.LOG;
retval[110] = new Exec(); // EXEC retval[110] = new Exec(); // EXEC
@ -196,7 +193,7 @@ public abstract class FunctionEval implements OperationEval {
retval[120] = new Substitute(); // SUBSTITUTE retval[120] = new Substitute(); // SUBSTITUTE
retval[121] = new Code(); // CODE retval[121] = new Code(); // CODE
retval[122] = new Names(); // NAMES retval[122] = new Names(); // NAMES
retval[123] = new NotImplementedFunction(); // DIRECTORY retval[123] = new NotImplementedFunction("DIRECTORY");
retval[124] = new Find(); // FIND retval[124] = new Find(); // FIND
retval[125] = new Cell(); // CELL retval[125] = new Cell(); // CELL
retval[126] = new Iserr(); // ISERR retval[126] = new Iserr(); // ISERR
@ -205,36 +202,36 @@ public abstract class FunctionEval implements OperationEval {
retval[129] = new Isblank(); // ISBLANK retval[129] = new Isblank(); // ISBLANK
retval[130] = new T(); // T retval[130] = new T(); // T
retval[131] = new N(); // N retval[131] = new N(); // N
retval[132] = new NotImplementedFunction(); // FOPEN retval[132] = new NotImplementedFunction("FOPEN");
retval[133] = new NotImplementedFunction(); // FCLOSE retval[133] = new NotImplementedFunction("FCLOSE");
retval[134] = new NotImplementedFunction(); // FSIZE retval[134] = new NotImplementedFunction("FSIZE");
retval[135] = new NotImplementedFunction(); // FREADLN retval[135] = new NotImplementedFunction("FREADLN");
retval[136] = new NotImplementedFunction(); // FREAD retval[136] = new NotImplementedFunction("FREAD");
retval[137] = new NotImplementedFunction(); // FWRITELN retval[137] = new NotImplementedFunction("FWRITELN");
retval[138] = new NotImplementedFunction(); // FWRITE retval[138] = new NotImplementedFunction("FWRITE");
retval[139] = new Fpos(); // FPOS retval[139] = new Fpos(); // FPOS
retval[140] = new Datevalue(); // DATEVALUE retval[140] = new Datevalue(); // DATEVALUE
retval[141] = new Timevalue(); // TIMEVALUE retval[141] = new Timevalue(); // TIMEVALUE
retval[142] = new Sln(); // SLN retval[142] = new Sln(); // SLN
retval[143] = new Syd(); // SYD retval[143] = new Syd(); // SYD
retval[144] = new Ddb(); // DDB retval[144] = new Ddb(); // DDB
retval[145] = new NotImplementedFunction(); // GETDEF retval[145] = new NotImplementedFunction("GETDEF");
retval[146] = new Reftext(); // REFTEXT retval[146] = new Reftext(); // REFTEXT
retval[147] = new Textref(); // TEXTREF retval[147] = new Textref(); // TEXTREF
retval[ID.INDIRECT] = null; // Indirect.evaluate has different signature retval[ID.INDIRECT] = null; // Indirect.evaluate has different signature
retval[149] = new NotImplementedFunction(); // REGISTER retval[149] = new NotImplementedFunction("REGISTER");
retval[150] = new Call(); // CALL retval[150] = new Call(); // CALL
retval[151] = new NotImplementedFunction(); // ADDBAR retval[151] = new NotImplementedFunction("ADDBAR");
retval[152] = new NotImplementedFunction(); // ADDMENU retval[152] = new NotImplementedFunction("ADDMENU");
retval[153] = new NotImplementedFunction(); // ADDCOMMAND retval[153] = new NotImplementedFunction("ADDCOMMAND");
retval[154] = new NotImplementedFunction(); // ENABLECOMMAND retval[154] = new NotImplementedFunction("ENABLECOMMAND");
retval[155] = new NotImplementedFunction(); // CHECKCOMMAND retval[155] = new NotImplementedFunction("CHECKCOMMAND");
retval[156] = new NotImplementedFunction(); // RENAMECOMMAND retval[156] = new NotImplementedFunction("RENAMECOMMAND");
retval[157] = new NotImplementedFunction(); // SHOWBAR retval[157] = new NotImplementedFunction("SHOWBAR");
retval[158] = new NotImplementedFunction(); // DELETEMENU retval[158] = new NotImplementedFunction("DELETEMENU");
retval[159] = new NotImplementedFunction(); // DELETECOMMAND retval[159] = new NotImplementedFunction("DELETECOMMAND");
retval[160] = new NotImplementedFunction(); // GETCHARTITEM retval[160] = new NotImplementedFunction("GETCHARTITEM");
retval[161] = new NotImplementedFunction(); // DIALOGBOX retval[161] = new NotImplementedFunction("DIALOGBOX");
retval[162] = new Clean(); // CLEAN retval[162] = new Clean(); // CLEAN
retval[163] = new Mdeterm(); // MDETERM retval[163] = new Mdeterm(); // MDETERM
retval[164] = new Minverse(); // MINVERSE retval[164] = new Minverse(); // MINVERSE
@ -243,24 +240,24 @@ public abstract class FunctionEval implements OperationEval {
retval[167] = new Ipmt(); // IPMT retval[167] = new Ipmt(); // IPMT
retval[168] = new Ppmt(); // PPMT retval[168] = new Ppmt(); // PPMT
retval[169] = new Counta(); // COUNTA retval[169] = new Counta(); // COUNTA
retval[170] = new NotImplementedFunction(); // CANCELKEY retval[170] = new NotImplementedFunction("CANCELKEY");
retval[175] = new Initiate(); // INITIATE retval[175] = new Initiate(); // INITIATE
retval[176] = new Request(); // REQUEST retval[176] = new Request(); // REQUEST
retval[177] = new NotImplementedFunction(); // POKE retval[177] = new NotImplementedFunction("POKE");
retval[178] = new NotImplementedFunction(); // EXECUTE retval[178] = new NotImplementedFunction("EXECUTE");
retval[179] = new NotImplementedFunction(); // TERMINATE retval[179] = new NotImplementedFunction("TERMINATE");
retval[180] = new NotImplementedFunction(); // RESTART retval[180] = new NotImplementedFunction("RESTART");
retval[181] = new Help(); // HELP retval[181] = new Help(); // HELP
retval[182] = new NotImplementedFunction(); // GETBAR retval[182] = new NotImplementedFunction("GETBAR");
retval[183] = AggregateFunction.PRODUCT; retval[183] = AggregateFunction.PRODUCT;
retval[184] = NumericFunction.FACT; retval[184] = NumericFunction.FACT;
retval[185] = new NotImplementedFunction(); // GETCELL retval[185] = new NotImplementedFunction("GETCELL");
retval[186] = new NotImplementedFunction(); // GETWORKSPACE retval[186] = new NotImplementedFunction("GETWORKSPACE");
retval[187] = new NotImplementedFunction(); // GETWINDOW retval[187] = new NotImplementedFunction("GETWINDOW");
retval[188] = new NotImplementedFunction(); // GETDOCUMENT retval[188] = new NotImplementedFunction("GETDOCUMENT");
retval[189] = new Dproduct(); // DPRODUCT retval[189] = new Dproduct(); // DPRODUCT
retval[190] = new Isnontext(); // ISNONTEXT retval[190] = new Isnontext(); // ISNONTEXT
retval[191] = new NotImplementedFunction(); // GETNOTE retval[191] = new NotImplementedFunction("GETNOTE");
retval[192] = new Note(); // NOTE retval[192] = new Note(); // NOTE
retval[193] = new Stdevp(); // STDEVP retval[193] = new Stdevp(); // STDEVP
retval[194] = new Varp(); // VARP retval[194] = new Varp(); // VARP
@ -269,8 +266,8 @@ public abstract class FunctionEval implements OperationEval {
retval[197] = new Trunc(); // TRUNC retval[197] = new Trunc(); // TRUNC
retval[198] = new Islogical(); // ISLOGICAL retval[198] = new Islogical(); // ISLOGICAL
retval[199] = new Dcounta(); // DCOUNTA retval[199] = new Dcounta(); // DCOUNTA
retval[200] = new NotImplementedFunction(); // DELETEBAR retval[200] = new NotImplementedFunction("DELETEBAR");
retval[201] = new NotImplementedFunction(); // UNREGISTER retval[201] = new NotImplementedFunction("UNREGISTER");
retval[204] = new Usdollar(); // USDOLLAR retval[204] = new Usdollar(); // USDOLLAR
retval[205] = new Findb(); // FINDB retval[205] = new Findb(); // FINDB
retval[206] = new Searchb(); // SEARCHB retval[206] = new Searchb(); // SEARCHB
@ -297,37 +294,37 @@ public abstract class FunctionEval implements OperationEval {
retval[233] = NumericFunction.ACOSH; retval[233] = NumericFunction.ACOSH;
retval[234] = NumericFunction.ATANH; retval[234] = NumericFunction.ATANH;
retval[235] = new Dget(); // DGET retval[235] = new Dget(); // DGET
retval[236] = new NotImplementedFunction(); // CREATEOBJECT retval[236] = new NotImplementedFunction("CREATEOBJECT");
retval[237] = new Volatile(); // VOLATILE retval[237] = new Volatile(); // VOLATILE
retval[238] = new Lasterror(); // LASTERROR retval[238] = new Lasterror(); // LASTERROR
retval[239] = new NotImplementedFunction(); // CUSTOMUNDO retval[239] = new NotImplementedFunction("CUSTOMUNDO");
retval[240] = new Customrepeat(); // CUSTOMREPEAT retval[240] = new Customrepeat(); // CUSTOMREPEAT
retval[241] = new Formulaconvert(); // FORMULACONVERT retval[241] = new Formulaconvert(); // FORMULACONVERT
retval[242] = new NotImplementedFunction(); // GETLINKINFO retval[242] = new NotImplementedFunction("GETLINKINFO");
retval[243] = new NotImplementedFunction(); // TEXTBOX retval[243] = new NotImplementedFunction("TEXTBOX");
retval[244] = new Info(); // INFO retval[244] = new Info(); // INFO
retval[245] = new Group(); // GROUP retval[245] = new Group(); // GROUP
retval[246] = new NotImplementedFunction(); // GETOBJECT retval[246] = new NotImplementedFunction("GETOBJECT");
retval[247] = new Db(); // DB retval[247] = new Db(); // DB
retval[248] = new NotImplementedFunction(); // PAUSE retval[248] = new NotImplementedFunction("PAUSE");
retval[250] = new NotImplementedFunction(); // RESUME retval[250] = new NotImplementedFunction("RESUME");
retval[252] = new Frequency(); // FREQUENCY retval[252] = new Frequency(); // FREQUENCY
retval[253] = new NotImplementedFunction(); // ADDTOOLBAR retval[253] = new NotImplementedFunction("ADDTOOLBAR");
retval[254] = new NotImplementedFunction(); // DELETETOOLBAR retval[254] = new NotImplementedFunction("DELETETOOLBAR");
retval[ID.EXTERNAL_FUNC] = null; // ExternalFunction is a FreeREfFunction retval[ID.EXTERNAL_FUNC] = null; // ExternalFunction is a FreeREfFunction
retval[256] = new NotImplementedFunction(); // RESETTOOLBAR retval[256] = new NotImplementedFunction("RESETTOOLBAR");
retval[257] = new Evaluate(); // EVALUATE retval[257] = new Evaluate(); // EVALUATE
retval[258] = new NotImplementedFunction(); // GETTOOLBAR retval[258] = new NotImplementedFunction("GETTOOLBAR");
retval[259] = new NotImplementedFunction(); // GETTOOL retval[259] = new NotImplementedFunction("GETTOOL");
retval[260] = new NotImplementedFunction(); // SPELLINGCHECK retval[260] = new NotImplementedFunction("SPELLINGCHECK");
retval[261] = new Errortype(); // ERRORTYPE retval[261] = new Errortype(); // ERRORTYPE
retval[262] = new NotImplementedFunction(); // APPTITLE retval[262] = new NotImplementedFunction("APPTITLE");
retval[263] = new NotImplementedFunction(); // WINDOWTITLE retval[263] = new NotImplementedFunction("WINDOWTITLE");
retval[264] = new NotImplementedFunction(); // SAVETOOLBAR retval[264] = new NotImplementedFunction("SAVETOOLBAR");
retval[265] = new NotImplementedFunction(); // ENABLETOOL retval[265] = new NotImplementedFunction("ENABLETOOL");
retval[266] = new NotImplementedFunction(); // PRESSTOOL retval[266] = new NotImplementedFunction("PRESSTOOL");
retval[267] = new NotImplementedFunction(); // REGISTERID retval[267] = new NotImplementedFunction("REGISTERID");
retval[268] = new NotImplementedFunction(); // GETWORKBOOK retval[268] = new NotImplementedFunction("GETWORKBOOK");
retval[269] = AggregateFunction.AVEDEV; retval[269] = AggregateFunction.AVEDEV;
retval[270] = new Betadist(); // BETADIST retval[270] = new Betadist(); // BETADIST
retval[271] = new Gammaln(); // GAMMALN retval[271] = new Gammaln(); // GAMMALN
@ -392,33 +389,33 @@ public abstract class FunctionEval implements OperationEval {
retval[330] = new Mode(); // MODE retval[330] = new Mode(); // MODE
retval[331] = new Trimmean(); // TRIMMEAN retval[331] = new Trimmean(); // TRIMMEAN
retval[332] = new Tinv(); // TINV retval[332] = new Tinv(); // TINV
retval[334] = new NotImplementedFunction(); // MOVIECOMMAND retval[334] = new NotImplementedFunction("MOVIECOMMAND");
retval[335] = new NotImplementedFunction(); // GETMOVIE retval[335] = new NotImplementedFunction("GETMOVIE");
retval[336] = TextFunction.CONCATENATE; retval[336] = TextFunction.CONCATENATE;
retval[337] = NumericFunction.POWER; retval[337] = NumericFunction.POWER;
retval[338] = new NotImplementedFunction(); // PIVOTADDDATA retval[338] = new NotImplementedFunction("PIVOTADDDATA");
retval[339] = new NotImplementedFunction(); // GETPIVOTTABLE retval[339] = new NotImplementedFunction("GETPIVOTTABLE");
retval[340] = new NotImplementedFunction(); // GETPIVOTFIELD retval[340] = new NotImplementedFunction("GETPIVOTFIELD");
retval[341] = new NotImplementedFunction(); // GETPIVOTITEM retval[341] = new NotImplementedFunction("GETPIVOTITEM");
retval[342] = NumericFunction.RADIANS; retval[342] = NumericFunction.RADIANS;
retval[343] = NumericFunction.DEGREES; retval[343] = NumericFunction.DEGREES;
retval[344] = new Subtotal(); // SUBTOTAL retval[344] = new Subtotal(); // SUBTOTAL
retval[345] = new Sumif(); // SUMIF retval[345] = new Sumif(); // SUMIF
retval[346] = new Countif(); // COUNTIF retval[346] = new Countif(); // COUNTIF
retval[347] = new Countblank(); // COUNTBLANK retval[347] = new Countblank(); // COUNTBLANK
retval[348] = new NotImplementedFunction(); // SCENARIOGET retval[348] = new NotImplementedFunction("SCENARIOGET");
retval[349] = new NotImplementedFunction(); // OPTIONSLISTSGET retval[349] = new NotImplementedFunction("OPTIONSLISTSGET");
retval[350] = new Ispmt(); // ISPMT retval[350] = new Ispmt(); // ISPMT
retval[351] = new Datedif(); // DATEDIF retval[351] = new Datedif(); // DATEDIF
retval[352] = new Datestring(); // DATESTRING retval[352] = new Datestring(); // DATESTRING
retval[353] = new Numberstring(); // NUMBERSTRING retval[353] = new Numberstring(); // NUMBERSTRING
retval[354] = new Roman(); // ROMAN retval[354] = new Roman(); // ROMAN
retval[355] = new NotImplementedFunction(); // OPENDIALOG retval[355] = new NotImplementedFunction("OPENDIALOG");
retval[356] = new NotImplementedFunction(); // SAVEDIALOG retval[356] = new NotImplementedFunction("SAVEDIALOG");
retval[357] = new NotImplementedFunction(); // VIEWGET retval[357] = new NotImplementedFunction("VIEWGET");
retval[358] = new NotImplementedFunction(); // GETPIVOTDATA retval[358] = new NotImplementedFunction("GETPIVOTDATA");
retval[359] = new Hyperlink(); // HYPERLINK retval[359] = new Hyperlink(); // HYPERLINK
retval[360] = new NotImplementedFunction(); // PHONETIC retval[360] = new NotImplementedFunction("PHONETIC");
retval[361] = new Averagea(); // AVERAGEA retval[361] = new Averagea(); // AVERAGEA
retval[362] = MinaMaxa.MAXA; retval[362] = MinaMaxa.MAXA;
retval[363] = MinaMaxa.MINA; retval[363] = MinaMaxa.MINA;

View File

@ -17,10 +17,10 @@
package org.apache.poi.hssf.record.formula.functions; package org.apache.poi.hssf.record.formula.functions;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.Eval;
import org.apache.poi.hssf.record.formula.eval.ValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval;
import org.apache.poi.ss.formula.EvaluationWorkbook; import org.apache.poi.ss.formula.EvaluationWorkbook;
import org.apache.poi.ss.formula.eval.NotImplementedException;
/** /**
* Implementation for Excel function INDIRECT<p/> * Implementation for Excel function INDIRECT<p/>
@ -42,7 +42,6 @@ public final class Indirect implements FreeRefFunction {
public ValueEval evaluate(Eval[] args, EvaluationWorkbook workbook, int srcCellSheet, int srcCellRow, int srcCellCol) { public ValueEval evaluate(Eval[] args, EvaluationWorkbook workbook, int srcCellSheet, int srcCellRow, int srcCellCol) {
// TODO - implement INDIRECT() // TODO - implement INDIRECT()
return ErrorEval.FUNCTION_NOT_IMPLEMENTED; throw new NotImplementedException("INDIRECT");
} }
} }

View File

@ -1,41 +1,44 @@
/* /* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one or more Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0 The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0 http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and See the License for the specific language governing permissions and
* limitations under the License. limitations under the License.
*/ ==================================================================== */
/*
* Created on May 6, 2005
*
*/
package org.apache.poi.hssf.record.formula.functions; package org.apache.poi.hssf.record.formula.functions;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.Eval;
import org.apache.poi.ss.formula.eval.NotImplementedException;
/** /**
* *
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt; * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
* This is the default implementation of a Function class. * This is the default implementation of a Function class.
* The default behaviour is to return a non-standard ErrorEval * The default behaviour is to raise a POI internal error
* "ErrorEval.FUNCTION_NOT_IMPLEMENTED". This error should alert * ({@link NotImplementedException}). This error should alert
* the user that the formula contained a function that is not * the user that the formula contained a function that is not
* yet implemented. * yet implemented.
*/ */
public class NotImplementedFunction implements Function { public class NotImplementedFunction implements Function {
private final String _functionName;
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) { protected NotImplementedFunction() {
return ErrorEval.FUNCTION_NOT_IMPLEMENTED; _functionName = getClass().getName();
}
public NotImplementedFunction(String name) {
_functionName = name;
} }
public Eval evaluate(Eval[] operands, int srcRow, short srcCol) {
throw new NotImplementedException(_functionName);
}
} }

View File

@ -63,6 +63,7 @@ import org.apache.poi.hssf.record.formula.eval.StringEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval;
import org.apache.poi.hssf.util.CellReference; import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet; import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet;
import org.apache.poi.ss.formula.eval.NotImplementedException;
import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Cell;
/** /**
@ -220,6 +221,8 @@ public final class WorkbookEvaluator {
} }
tracker.updateCacheResult(result); tracker.updateCacheResult(result);
} catch (NotImplementedException e) {
throw addExceptionInfo(e, sheetIndex, rowIndex, columnIndex);
} finally { } finally {
tracker.endEvaluate(cce); tracker.endEvaluate(cce);
} }
@ -236,6 +239,25 @@ public final class WorkbookEvaluator {
} }
return cce.getValue(); return cce.getValue();
} }
/**
* Adds the current cell reference to the exception for easier debugging.
* Would be nice to get the formula text as well, but that seems to require
* too much digging around and casting to get the FormulaRenderingWorkbook.
*/
private NotImplementedException addExceptionInfo(NotImplementedException inner, int sheetIndex, int rowIndex, int columnIndex) {
try {
String sheetName = _workbook.getSheetName(sheetIndex);
CellReference cr = new CellReference(sheetName, rowIndex, columnIndex, false, false);
String msg = "Error evaluating cell " + cr.formatAsString();
return new NotImplementedException(msg, inner);
} catch (Exception e) {
// avoid bombing out during exception handling
e.printStackTrace();
return inner; // preserve original exception
}
}
/** /**
* Gets the value from a non-formula cell. * Gets the value from a non-formula cell.
* @param cell may be <code>null</code> * @param cell may be <code>null</code>

View File

@ -0,0 +1,36 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.ss.formula.eval;
import org.apache.poi.ss.usermodel.FormulaEvaluator;
/**
* An exception thrown by implementors of {@link FormulaEvaluator} when attempting to evaluate
* a formula which requires features that POI does not (yet) support.
*
* @author Josh Micich
*/
public final class NotImplementedException extends RuntimeException {
public NotImplementedException(String message) {
super(message);
}
public NotImplementedException(String message, NotImplementedException cause) {
super(message, cause);
}
}

View File

@ -28,6 +28,7 @@ import org.apache.poi.hssf.usermodel.HSSFName;
import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.formula.eval.NotImplementedException;
import org.apache.poi.ss.usermodel.CellValue; import org.apache.poi.ss.usermodel.CellValue;
/** /**
* *
@ -66,11 +67,16 @@ public final class TestExternalFunction extends TestCase {
assertEquals("myFunc()", actualFormula); assertEquals("myFunc()", actualFormula);
HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb); HSSFFormulaEvaluator fe = new HSSFFormulaEvaluator(wb);
CellValue evalResult = fe.evaluate(cell); // Check out what ExternalFunction.evaluate() does:
CellValue evalResult;
// Check the return value from ExternalFunction.evaluate() try {
evalResult = fe.evaluate(cell);
} catch (NotImplementedException e) {
assertEquals("Error evaluating cell Sheet1!B1", e.getMessage());
assertEquals("myFunc", e.getCause().getMessage());
return;
}
// TODO - make this test assert something more interesting as soon as ExternalFunction works a bit better // TODO - make this test assert something more interesting as soon as ExternalFunction works a bit better
assertEquals(HSSFCell.CELL_TYPE_ERROR, evalResult.getCellType()); assertNotNull(evalResult);
assertEquals(ErrorEval.FUNCTION_NOT_IMPLEMENTED.getErrorCode(), evalResult.getErrorValue());
} }
} }

View File

@ -24,6 +24,7 @@ import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval; import org.apache.poi.hssf.record.formula.eval.Eval;
import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
import org.apache.poi.hssf.record.formula.eval.OperationEval; import org.apache.poi.hssf.record.formula.eval.OperationEval;
import org.apache.poi.ss.formula.eval.NotImplementedException;
/** /**
* Test helper class for invoking functions with numeric results. * Test helper class for invoking functions with numeric results.
@ -83,6 +84,7 @@ public final class NumericFunctionInvoker {
throws NumericEvalEx { throws NumericEvalEx {
Eval evalResult; Eval evalResult;
// TODO - make OperationEval extend Function // TODO - make OperationEval extend Function
try {
if (target instanceof Function) { if (target instanceof Function) {
Function ff = (Function) target; Function ff = (Function) target;
evalResult = ff.evaluate(args, srcCellRow, (short)srcCellCol); evalResult = ff.evaluate(args, srcCellRow, (short)srcCellCol);
@ -90,6 +92,9 @@ public final class NumericFunctionInvoker {
OperationEval ff = (OperationEval) target; OperationEval ff = (OperationEval) target;
evalResult = ff.evaluate(args, srcCellRow, (short)srcCellCol); evalResult = ff.evaluate(args, srcCellRow, (short)srcCellCol);
} }
} catch (NotImplementedException e) {
throw new NumericEvalEx("Not implemented:" + e.getMessage());
}
if(evalResult == null) { if(evalResult == null) {
throw new NumericEvalEx("Result object was null"); throw new NumericEvalEx("Result object was null");
@ -108,9 +113,6 @@ public final class NumericFunctionInvoker {
return result.getNumberValue(); return result.getNumberValue();
} }
private static String formatErrorMessage(ErrorEval ee) { private static String formatErrorMessage(ErrorEval ee) {
if(errorCodesAreEqual(ee, ErrorEval.FUNCTION_NOT_IMPLEMENTED)) {
return "Function not implemented";
}
if(errorCodesAreEqual(ee, ErrorEval.VALUE_INVALID)) { if(errorCodesAreEqual(ee, ErrorEval.VALUE_INVALID)) {
return "Error code: #VALUE! (invalid value)"; return "Error code: #VALUE! (invalid value)";
} }