diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
index dc5d6c5fe..f5a941d67 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
@@ -17,17 +17,15 @@
package org.apache.poi.hssf.record.formula.eval;
-import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
import org.apache.poi.hssf.record.formula.function.FunctionMetadata;
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
import org.apache.poi.hssf.record.formula.functions.*;
-import org.apache.poi.ss.formula.OperationEvaluationContext;
import org.apache.poi.ss.formula.eval.NotImplementedException;
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
*/
-public final class FunctionEval implements OperationEval {
+public final class FunctionEval {
/**
* Some function IDs that require special treatment
*/
@@ -37,7 +35,7 @@ public final class FunctionEval implements OperationEval {
/** 78 */
public static final int OFFSET = 78;
/** 148 */
- public static final int INDIRECT = 148;
+ public static final int INDIRECT = FunctionMetadataRegistry.FUNCTION_INDEX_INDIRECT;
/** 255 */
public static final int EXTERNAL_FUNC = FunctionMetadataRegistry.FUNCTION_INDEX_EXTERNAL;
}
@@ -222,33 +220,21 @@ public final class FunctionEval implements OperationEval {
}
return retval;
}
-
- private AbstractFunctionPtg _delegate;
-
- public FunctionEval(AbstractFunctionPtg funcPtg) {
- _delegate = funcPtg;
- }
-
- public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
- int fidx = _delegate.getFunctionIndex();
+ /**
+ * @return null
if the specified functionIndex is for INDIRECT() or any external (add-in) function.
+ */
+ public static Function getBasicFunction(int functionIndex) {
// check for 'free ref' functions first
- switch (fidx) {
+ switch (functionIndex) {
case FunctionID.INDIRECT:
- return Indirect.instance.evaluate(args, ec);
case FunctionID.EXTERNAL_FUNC:
- return UserDefinedFunction.instance.evaluate(args, ec);
+ return null;
}
// else - must be plain function
- Function f = functions[fidx];
- if (f == null) {
- throw new NotImplementedException("FuncIx=" + fidx);
+ Function result = functions[functionIndex];
+ if (result == null) {
+ throw new NotImplementedException("FuncIx=" + functionIndex);
}
- int srcCellRow = ec.getRowIndex();
- int srcCellCol = ec.getColumnIndex();
- return f.evaluate(args, srcCellRow, (short) srcCellCol);
- }
-
- public int getNumberOfOperands() {
- return _delegate.getNumberOfOperands();
+ return result;
}
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/OperationEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/OperationEval.java
deleted file mode 100644
index 481caa0b6..000000000
--- a/src/java/org/apache/poi/hssf/record/formula/eval/OperationEval.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/* ====================================================================
- 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.hssf.record.formula.eval;
-
-import org.apache.poi.ss.formula.OperationEvaluationContext;
-
-/**
- * Common interface for implementations of Excel formula operations.
- *
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- *
- */
-public interface OperationEval {
-
- /**
- * @param args the evaluated operation arguments. Elements of this array typically implement
- * {@link ValueEval}. Empty values are represented with {@link BlankEval} or {@link
- * MissingArgEval}, never null
.
- * @param ec used to identify the current cell under evaluation, and potentially to
- * dynamically create references
- * @return The evaluated result, possibly an {@link ErrorEval}, never null
.
- */
- ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec);
- int getNumberOfOperands();
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/function/FunctionMetadataRegistry.java b/src/java/org/apache/poi/hssf/record/formula/function/FunctionMetadataRegistry.java
index 6fb0aabd3..e14366f78 100644
--- a/src/java/org/apache/poi/hssf/record/formula/function/FunctionMetadataRegistry.java
+++ b/src/java/org/apache/poi/hssf/record/formula/function/FunctionMetadataRegistry.java
@@ -31,6 +31,7 @@ public final class FunctionMetadataRegistry {
public static final String FUNCTION_NAME_IF = "IF";
public static final short FUNCTION_INDEX_SUM = 4;
+ public static final short FUNCTION_INDEX_INDIRECT = 148;
public static final short FUNCTION_INDEX_EXTERNAL = 255;
private static FunctionMetadataRegistry _instance;
diff --git a/src/java/org/apache/poi/ss/formula/OperationEvaluatorFactory.java b/src/java/org/apache/poi/ss/formula/OperationEvaluatorFactory.java
index e416a7ee8..87cef4f9c 100644
--- a/src/java/org/apache/poi/ss/formula/OperationEvaluatorFactory.java
+++ b/src/java/org/apache/poi/ss/formula/OperationEvaluatorFactory.java
@@ -44,7 +44,6 @@ import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
import org.apache.poi.hssf.record.formula.eval.ConcatEval;
import org.apache.poi.hssf.record.formula.eval.FunctionEval;
import org.apache.poi.hssf.record.formula.eval.IntersectionEval;
-import org.apache.poi.hssf.record.formula.eval.OperationEval;
import org.apache.poi.hssf.record.formula.eval.PercentEval;
import org.apache.poi.hssf.record.formula.eval.RangeEval;
import org.apache.poi.hssf.record.formula.eval.RelationalOperationEval;
@@ -52,7 +51,9 @@ import org.apache.poi.hssf.record.formula.eval.TwoOperandNumericOperation;
import org.apache.poi.hssf.record.formula.eval.UnaryMinusEval;
import org.apache.poi.hssf.record.formula.eval.UnaryPlusEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
import org.apache.poi.hssf.record.formula.functions.Function;
+import org.apache.poi.hssf.record.formula.functions.Indirect;
/**
* This class creates OperationEval instances to help evaluate OperationPtg
@@ -62,85 +63,73 @@ import org.apache.poi.hssf.record.formula.functions.Function;
*/
final class OperationEvaluatorFactory {
- private static final Map _instancesByPtgClass = initialiseInstancesMap2();
+ private static final Map _instancesByPtgClass = initialiseInstancesMap();
private OperationEvaluatorFactory() {
// no instances of this class
}
- private static Map initialiseInstancesMap2() {
- Map m = new HashMap(32);
+ private static Map initialiseInstancesMap() {
+ Map m = new HashMap(32);
- put(m, 2, EqualPtg.instance, RelationalOperationEval.EqualEval);
- put(m, 2, GreaterEqualPtg.instance, RelationalOperationEval.GreaterEqualEval);
- put(m, 2, GreaterThanPtg.instance, RelationalOperationEval.GreaterThanEval);
- put(m, 2, LessEqualPtg.instance, RelationalOperationEval.LessEqualEval);
- put(m, 2, LessThanPtg.instance, RelationalOperationEval.LessThanEval);
- put(m, 2, NotEqualPtg.instance, RelationalOperationEval.NotEqualEval);
+ put(m, EqualPtg.instance, RelationalOperationEval.EqualEval);
+ put(m, GreaterEqualPtg.instance, RelationalOperationEval.GreaterEqualEval);
+ put(m, GreaterThanPtg.instance, RelationalOperationEval.GreaterThanEval);
+ put(m, LessEqualPtg.instance, RelationalOperationEval.LessEqualEval);
+ put(m, LessThanPtg.instance, RelationalOperationEval.LessThanEval);
+ put(m, NotEqualPtg.instance, RelationalOperationEval.NotEqualEval);
- put(m, 2, ConcatPtg.instance, ConcatEval.instance);
- put(m, 2, AddPtg.instance, TwoOperandNumericOperation.AddEval);
- put(m, 2, DividePtg.instance, TwoOperandNumericOperation.DivideEval);
- put(m, 2, MultiplyPtg.instance, TwoOperandNumericOperation.MultiplyEval);
- put(m, 1, PercentPtg.instance, PercentEval.instance);
- put(m, 2, PowerPtg.instance, TwoOperandNumericOperation.PowerEval);
- put(m, 2, SubtractPtg.instance, TwoOperandNumericOperation.SubtractEval);
- put(m, 1, UnaryMinusPtg.instance, UnaryMinusEval.instance);
- put(m, 1, UnaryPlusPtg.instance, UnaryPlusEval.instance);
- put(m, 2, RangePtg.instance, RangeEval.instance);
- put(m, 2, IntersectionPtg.instance, IntersectionEval.instance);
+ put(m, ConcatPtg.instance, ConcatEval.instance);
+ put(m, AddPtg.instance, TwoOperandNumericOperation.AddEval);
+ put(m, DividePtg.instance, TwoOperandNumericOperation.DivideEval);
+ put(m, MultiplyPtg.instance, TwoOperandNumericOperation.MultiplyEval);
+ put(m, PercentPtg.instance, PercentEval.instance);
+ put(m, PowerPtg.instance, TwoOperandNumericOperation.PowerEval);
+ put(m, SubtractPtg.instance, TwoOperandNumericOperation.SubtractEval);
+ put(m, UnaryMinusPtg.instance, UnaryMinusEval.instance);
+ put(m, UnaryPlusPtg.instance, UnaryPlusEval.instance);
+ put(m, RangePtg.instance, RangeEval.instance);
+ put(m, IntersectionPtg.instance, IntersectionEval.instance);
return m;
}
- private static void put(Map m, int argCount,
- OperationPtg ptgKey, Function instance) {
+ private static void put(Map m, OperationPtg ptgKey,
+ Function instance) {
// make sure ptg has single private constructor because map lookups assume singleton keys
Constructor[] cc = ptgKey.getClass().getDeclaredConstructors();
if (cc.length > 1 || !Modifier.isPrivate(cc[0].getModifiers())) {
throw new RuntimeException("Failed to verify instance ("
+ ptgKey.getClass().getName() + ") is a singleton.");
}
- m.put(ptgKey, new OperationFunctionEval(instance, argCount));
- }
-
- /**
- * Simple adapter from {@link OperationEval} to {@link Function}
- */
- private static final class OperationFunctionEval implements OperationEval {
-
- private final Function _function;
- private final int _numberOfOperands;
-
- public OperationFunctionEval(Function function, int argCount) {
- _function = function;
- _numberOfOperands = argCount;
- }
-
- public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
- return _function.evaluate(args, ec.getRowIndex(), (short) ec.getColumnIndex());
- }
-
- public int getNumberOfOperands() {
- return _numberOfOperands;
- }
+ m.put(ptgKey, instance);
}
/**
* returns the OperationEval concrete impl instance corresponding
* to the supplied operationPtg
*/
- public static OperationEval create(OperationPtg ptg) {
+ public static ValueEval evaluate(OperationPtg ptg, ValueEval[] args,
+ OperationEvaluationContext ec) {
if(ptg == null) {
throw new IllegalArgumentException("ptg must not be null");
}
- OperationEval result = _instancesByPtgClass.get(ptg);
+ Function result = _instancesByPtgClass.get(ptg);
if (result != null) {
- return result;
+ return result.evaluate(args, ec.getRowIndex(), (short) ec.getColumnIndex());
}
if (ptg instanceof AbstractFunctionPtg) {
- return new FunctionEval((AbstractFunctionPtg)ptg);
+ 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() + ")");
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/UserDefinedFunction.java b/src/java/org/apache/poi/ss/formula/UserDefinedFunction.java
similarity index 92%
rename from src/java/org/apache/poi/hssf/record/formula/eval/UserDefinedFunction.java
rename to src/java/org/apache/poi/ss/formula/UserDefinedFunction.java
index 223f13378..7bf612a47 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/UserDefinedFunction.java
+++ b/src/java/org/apache/poi/ss/formula/UserDefinedFunction.java
@@ -15,8 +15,11 @@
limitations under the License.
==================================================================== */
-package org.apache.poi.hssf.record.formula.eval;
+package org.apache.poi.ss.formula;
+import org.apache.poi.hssf.record.formula.eval.NameEval;
+import org.apache.poi.hssf.record.formula.eval.NameXEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
import org.apache.poi.ss.formula.OperationEvaluationContext;
import org.apache.poi.ss.formula.eval.NotImplementedException;
diff --git a/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java b/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
index 18d8c11d4..8fc1f3eb9 100644
--- a/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
+++ b/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
@@ -57,7 +57,6 @@ import org.apache.poi.hssf.record.formula.eval.MissingArgEval;
import org.apache.poi.hssf.record.formula.eval.NameEval;
import org.apache.poi.hssf.record.formula.eval.NameXEval;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.OperationEval;
import org.apache.poi.hssf.record.formula.eval.RefEval;
import org.apache.poi.hssf.record.formula.eval.StringEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
@@ -425,9 +424,8 @@ public final class WorkbookEvaluator {
if (optg instanceof UnionPtg) { continue; }
- OperationEval operation = OperationEvaluatorFactory.create(optg);
- int numops = operation.getNumberOfOperands();
+ int numops = optg.getNumberOfOperands();
ValueEval[] ops = new ValueEval[numops];
// storing the ops in reverse order since they are popping
@@ -436,7 +434,7 @@ public final class WorkbookEvaluator {
ops[j] = p;
}
// logDebug("invoke " + operation + " (nAgs=" + numops + ")");
- opResult = operation.evaluate(ops, ec);
+ opResult = OperationEvaluatorFactory.evaluate(optg, ops, ec);
if (opResult == MissingArgEval.instance) {
opResult = BlankEval.INSTANCE;
}