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
*/
/** 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;
}
}
return retval;
}
-
- private AbstractFunctionPtg _delegate;
-
- public FunctionEval(AbstractFunctionPtg funcPtg) {
- _delegate = funcPtg;
- }
-
- public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
- int fidx = _delegate.getFunctionIndex();
+ /**
+ * @return <code>null</code> 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;
}
}
+++ /dev/null
-/* ====================================================================
- 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 <code>null</code>.
- * @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 <code>null</code>.
- */
- ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec);
- int getNumberOfOperands();
-}
+++ /dev/null
-/* ====================================================================
- 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.hssf.record.formula.functions.FreeRefFunction;
-import org.apache.poi.ss.formula.OperationEvaluationContext;
-import org.apache.poi.ss.formula.eval.NotImplementedException;
-/**
- *
- * Common entry point for all user-defined (non-built-in) functions (where
- * <tt>AbstractFunctionPtg.field_2_fnc_index</tt> == 255)
- *
- * @author Josh Micich
- * @author Petr Udalau - Improved resolving of UDFs through the ToolPacks.
- */
-final class UserDefinedFunction implements FreeRefFunction {
-
- public static final FreeRefFunction instance = new UserDefinedFunction();
-
- private UserDefinedFunction() {
- // enforce singleton
- }
-
- public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
- int nIncomingArgs = args.length;
- if(nIncomingArgs < 1) {
- throw new RuntimeException("function name argument missing");
- }
-
- ValueEval nameArg = args[0];
- String functionName;
- if (nameArg instanceof NameEval) {
- functionName = ((NameEval) nameArg).getFunctionName();
- } else if (nameArg instanceof NameXEval) {
- functionName = ec.getWorkbook().resolveNameXText(((NameXEval) nameArg).getPtg());
- } else {
- throw new RuntimeException("First argument should be a NameEval, but got ("
- + nameArg.getClass().getName() + ")");
- }
- FreeRefFunction targetFunc = ec.findUserDefinedFunction(functionName);
- if (targetFunc == null) {
- throw new NotImplementedException(functionName);
- }
- int nOutGoingArgs = nIncomingArgs -1;
- ValueEval[] outGoingArgs = new ValueEval[nOutGoingArgs];
- System.arraycopy(args, 1, outGoingArgs, 0, nOutGoingArgs);
- return targetFunc.evaluate(outGoingArgs, ec);
- }
-}
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;
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;
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 <tt>OperationEval</tt> instances to help evaluate <tt>OperationPtg</tt>
*/
final class OperationEvaluatorFactory {
- private static final Map<OperationPtg, OperationEval> _instancesByPtgClass = initialiseInstancesMap2();
+ private static final Map<OperationPtg, Function> _instancesByPtgClass = initialiseInstancesMap();
private OperationEvaluatorFactory() {
// no instances of this class
}
- private static Map<OperationPtg, OperationEval> initialiseInstancesMap2() {
- Map<OperationPtg, OperationEval> m = new HashMap<OperationPtg, OperationEval>(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, 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);
+ private static Map<OperationPtg, Function> initialiseInstancesMap() {
+ Map<OperationPtg, Function> m = new HashMap<OperationPtg, Function>(32);
+
+ 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, 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<OperationPtg, OperationEval> m, int argCount,
- OperationPtg ptgKey, Function instance) {
+ private static void put(Map<OperationPtg, Function> 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() + ")");
}
--- /dev/null
+/* ====================================================================
+ 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;
+
+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;
+/**
+ *
+ * Common entry point for all user-defined (non-built-in) functions (where
+ * <tt>AbstractFunctionPtg.field_2_fnc_index</tt> == 255)
+ *
+ * @author Josh Micich
+ * @author Petr Udalau - Improved resolving of UDFs through the ToolPacks.
+ */
+final class UserDefinedFunction implements FreeRefFunction {
+
+ public static final FreeRefFunction instance = new UserDefinedFunction();
+
+ private UserDefinedFunction() {
+ // enforce singleton
+ }
+
+ public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
+ int nIncomingArgs = args.length;
+ if(nIncomingArgs < 1) {
+ throw new RuntimeException("function name argument missing");
+ }
+
+ ValueEval nameArg = args[0];
+ String functionName;
+ if (nameArg instanceof NameEval) {
+ functionName = ((NameEval) nameArg).getFunctionName();
+ } else if (nameArg instanceof NameXEval) {
+ functionName = ec.getWorkbook().resolveNameXText(((NameXEval) nameArg).getPtg());
+ } else {
+ throw new RuntimeException("First argument should be a NameEval, but got ("
+ + nameArg.getClass().getName() + ")");
+ }
+ FreeRefFunction targetFunc = ec.findUserDefinedFunction(functionName);
+ if (targetFunc == null) {
+ throw new NotImplementedException(functionName);
+ }
+ int nOutGoingArgs = nIncomingArgs -1;
+ ValueEval[] outGoingArgs = new ValueEval[nOutGoingArgs];
+ System.arraycopy(args, 1, outGoingArgs, 0, nOutGoingArgs);
+ return targetFunc.evaluate(outGoingArgs, ec);
+ }
+}
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;
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
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;
}