Removed OperationEval and rearranged function/operator evaluation.
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@880593 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
5630df07a4
commit
518ae59f07
@ -17,17 +17,15 @@
|
|||||||
|
|
||||||
package org.apache.poi.hssf.record.formula.eval;
|
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.FunctionMetadata;
|
||||||
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
|
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
|
||||||
import org.apache.poi.hssf.record.formula.functions.*;
|
import org.apache.poi.hssf.record.formula.functions.*;
|
||||||
import org.apache.poi.ss.formula.OperationEvaluationContext;
|
|
||||||
import org.apache.poi.ss.formula.eval.NotImplementedException;
|
import org.apache.poi.ss.formula.eval.NotImplementedException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
|
* @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
|
* Some function IDs that require special treatment
|
||||||
*/
|
*/
|
||||||
@ -37,7 +35,7 @@ public final class FunctionEval implements OperationEval {
|
|||||||
/** 78 */
|
/** 78 */
|
||||||
public static final int OFFSET = 78;
|
public static final int OFFSET = 78;
|
||||||
/** 148 */
|
/** 148 */
|
||||||
public static final int INDIRECT = 148;
|
public static final int INDIRECT = FunctionMetadataRegistry.FUNCTION_INDEX_INDIRECT;
|
||||||
/** 255 */
|
/** 255 */
|
||||||
public static final int EXTERNAL_FUNC = FunctionMetadataRegistry.FUNCTION_INDEX_EXTERNAL;
|
public static final int EXTERNAL_FUNC = FunctionMetadataRegistry.FUNCTION_INDEX_EXTERNAL;
|
||||||
}
|
}
|
||||||
@ -222,33 +220,21 @@ public final class FunctionEval implements OperationEval {
|
|||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
private AbstractFunctionPtg _delegate;
|
* @return <code>null</code> if the specified functionIndex is for INDIRECT() or any external (add-in) function.
|
||||||
|
*/
|
||||||
public FunctionEval(AbstractFunctionPtg funcPtg) {
|
public static Function getBasicFunction(int functionIndex) {
|
||||||
_delegate = funcPtg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
|
|
||||||
int fidx = _delegate.getFunctionIndex();
|
|
||||||
// check for 'free ref' functions first
|
// check for 'free ref' functions first
|
||||||
switch (fidx) {
|
switch (functionIndex) {
|
||||||
case FunctionID.INDIRECT:
|
case FunctionID.INDIRECT:
|
||||||
return Indirect.instance.evaluate(args, ec);
|
|
||||||
case FunctionID.EXTERNAL_FUNC:
|
case FunctionID.EXTERNAL_FUNC:
|
||||||
return UserDefinedFunction.instance.evaluate(args, ec);
|
return null;
|
||||||
}
|
}
|
||||||
// else - must be plain function
|
// else - must be plain function
|
||||||
Function f = functions[fidx];
|
Function result = functions[functionIndex];
|
||||||
if (f == null) {
|
if (result == null) {
|
||||||
throw new NotImplementedException("FuncIx=" + fidx);
|
throw new NotImplementedException("FuncIx=" + functionIndex);
|
||||||
}
|
}
|
||||||
int srcCellRow = ec.getRowIndex();
|
return result;
|
||||||
int srcCellCol = ec.getColumnIndex();
|
|
||||||
return f.evaluate(args, srcCellRow, (short) srcCellCol);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumberOfOperands() {
|
|
||||||
return _delegate.getNumberOfOperands();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 <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();
|
|
||||||
}
|
|
@ -31,6 +31,7 @@ public final class FunctionMetadataRegistry {
|
|||||||
public static final String FUNCTION_NAME_IF = "IF";
|
public static final String FUNCTION_NAME_IF = "IF";
|
||||||
|
|
||||||
public static final short FUNCTION_INDEX_SUM = 4;
|
public static final short FUNCTION_INDEX_SUM = 4;
|
||||||
|
public static final short FUNCTION_INDEX_INDIRECT = 148;
|
||||||
public static final short FUNCTION_INDEX_EXTERNAL = 255;
|
public static final short FUNCTION_INDEX_EXTERNAL = 255;
|
||||||
private static FunctionMetadataRegistry _instance;
|
private static FunctionMetadataRegistry _instance;
|
||||||
|
|
||||||
|
@ -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.ConcatEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.FunctionEval;
|
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.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.PercentEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.RangeEval;
|
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.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.UnaryMinusEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.UnaryPlusEval;
|
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.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.Function;
|
||||||
|
import org.apache.poi.hssf.record.formula.functions.Indirect;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class creates <tt>OperationEval</tt> instances to help evaluate <tt>OperationPtg</tt>
|
* This class creates <tt>OperationEval</tt> instances to help evaluate <tt>OperationPtg</tt>
|
||||||
@ -62,85 +63,73 @@ import org.apache.poi.hssf.record.formula.functions.Function;
|
|||||||
*/
|
*/
|
||||||
final class OperationEvaluatorFactory {
|
final class OperationEvaluatorFactory {
|
||||||
|
|
||||||
private static final Map<OperationPtg, OperationEval> _instancesByPtgClass = initialiseInstancesMap2();
|
private static final Map<OperationPtg, Function> _instancesByPtgClass = initialiseInstancesMap();
|
||||||
|
|
||||||
private OperationEvaluatorFactory() {
|
private OperationEvaluatorFactory() {
|
||||||
// no instances of this class
|
// no instances of this class
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Map<OperationPtg, OperationEval> initialiseInstancesMap2() {
|
private static Map<OperationPtg, Function> initialiseInstancesMap() {
|
||||||
Map<OperationPtg, OperationEval> m = new HashMap<OperationPtg, OperationEval>(32);
|
Map<OperationPtg, Function> m = new HashMap<OperationPtg, Function>(32);
|
||||||
|
|
||||||
put(m, 2, EqualPtg.instance, RelationalOperationEval.EqualEval);
|
put(m, EqualPtg.instance, RelationalOperationEval.EqualEval);
|
||||||
put(m, 2, GreaterEqualPtg.instance, RelationalOperationEval.GreaterEqualEval);
|
put(m, GreaterEqualPtg.instance, RelationalOperationEval.GreaterEqualEval);
|
||||||
put(m, 2, GreaterThanPtg.instance, RelationalOperationEval.GreaterThanEval);
|
put(m, GreaterThanPtg.instance, RelationalOperationEval.GreaterThanEval);
|
||||||
put(m, 2, LessEqualPtg.instance, RelationalOperationEval.LessEqualEval);
|
put(m, LessEqualPtg.instance, RelationalOperationEval.LessEqualEval);
|
||||||
put(m, 2, LessThanPtg.instance, RelationalOperationEval.LessThanEval);
|
put(m, LessThanPtg.instance, RelationalOperationEval.LessThanEval);
|
||||||
put(m, 2, NotEqualPtg.instance, RelationalOperationEval.NotEqualEval);
|
put(m, NotEqualPtg.instance, RelationalOperationEval.NotEqualEval);
|
||||||
|
|
||||||
put(m, 2, ConcatPtg.instance, ConcatEval.instance);
|
put(m, ConcatPtg.instance, ConcatEval.instance);
|
||||||
put(m, 2, AddPtg.instance, TwoOperandNumericOperation.AddEval);
|
put(m, AddPtg.instance, TwoOperandNumericOperation.AddEval);
|
||||||
put(m, 2, DividePtg.instance, TwoOperandNumericOperation.DivideEval);
|
put(m, DividePtg.instance, TwoOperandNumericOperation.DivideEval);
|
||||||
put(m, 2, MultiplyPtg.instance, TwoOperandNumericOperation.MultiplyEval);
|
put(m, MultiplyPtg.instance, TwoOperandNumericOperation.MultiplyEval);
|
||||||
put(m, 1, PercentPtg.instance, PercentEval.instance);
|
put(m, PercentPtg.instance, PercentEval.instance);
|
||||||
put(m, 2, PowerPtg.instance, TwoOperandNumericOperation.PowerEval);
|
put(m, PowerPtg.instance, TwoOperandNumericOperation.PowerEval);
|
||||||
put(m, 2, SubtractPtg.instance, TwoOperandNumericOperation.SubtractEval);
|
put(m, SubtractPtg.instance, TwoOperandNumericOperation.SubtractEval);
|
||||||
put(m, 1, UnaryMinusPtg.instance, UnaryMinusEval.instance);
|
put(m, UnaryMinusPtg.instance, UnaryMinusEval.instance);
|
||||||
put(m, 1, UnaryPlusPtg.instance, UnaryPlusEval.instance);
|
put(m, UnaryPlusPtg.instance, UnaryPlusEval.instance);
|
||||||
put(m, 2, RangePtg.instance, RangeEval.instance);
|
put(m, RangePtg.instance, RangeEval.instance);
|
||||||
put(m, 2, IntersectionPtg.instance, IntersectionEval.instance);
|
put(m, IntersectionPtg.instance, IntersectionEval.instance);
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void put(Map<OperationPtg, OperationEval> m, int argCount,
|
private static void put(Map<OperationPtg, Function> m, OperationPtg ptgKey,
|
||||||
OperationPtg ptgKey, Function instance) {
|
Function instance) {
|
||||||
// make sure ptg has single private constructor because map lookups assume singleton keys
|
// make sure ptg has single private constructor because map lookups assume singleton keys
|
||||||
Constructor[] cc = ptgKey.getClass().getDeclaredConstructors();
|
Constructor[] cc = ptgKey.getClass().getDeclaredConstructors();
|
||||||
if (cc.length > 1 || !Modifier.isPrivate(cc[0].getModifiers())) {
|
if (cc.length > 1 || !Modifier.isPrivate(cc[0].getModifiers())) {
|
||||||
throw new RuntimeException("Failed to verify instance ("
|
throw new RuntimeException("Failed to verify instance ("
|
||||||
+ ptgKey.getClass().getName() + ") is a singleton.");
|
+ ptgKey.getClass().getName() + ") is a singleton.");
|
||||||
}
|
}
|
||||||
m.put(ptgKey, new OperationFunctionEval(instance, argCount));
|
m.put(ptgKey, instance);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns the OperationEval concrete impl instance corresponding
|
* returns the OperationEval concrete impl instance corresponding
|
||||||
* to the supplied operationPtg
|
* to the supplied operationPtg
|
||||||
*/
|
*/
|
||||||
public static OperationEval create(OperationPtg ptg) {
|
public static ValueEval evaluate(OperationPtg ptg, ValueEval[] args,
|
||||||
|
OperationEvaluationContext ec) {
|
||||||
if(ptg == null) {
|
if(ptg == null) {
|
||||||
throw new IllegalArgumentException("ptg must not be null");
|
throw new IllegalArgumentException("ptg must not be null");
|
||||||
}
|
}
|
||||||
OperationEval result = _instancesByPtgClass.get(ptg);
|
Function result = _instancesByPtgClass.get(ptg);
|
||||||
|
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
return result;
|
return result.evaluate(args, ec.getRowIndex(), (short) ec.getColumnIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptg instanceof AbstractFunctionPtg) {
|
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() + ")");
|
throw new RuntimeException("Unexpected operation ptg class (" + ptg.getClass().getName() + ")");
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,11 @@
|
|||||||
limitations under the License.
|
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.hssf.record.formula.functions.FreeRefFunction;
|
||||||
import org.apache.poi.ss.formula.OperationEvaluationContext;
|
import org.apache.poi.ss.formula.OperationEvaluationContext;
|
||||||
import org.apache.poi.ss.formula.eval.NotImplementedException;
|
import org.apache.poi.ss.formula.eval.NotImplementedException;
|
@ -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.NameEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.NameXEval;
|
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.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.RefEval;
|
||||||
import org.apache.poi.hssf.record.formula.eval.StringEval;
|
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;
|
||||||
@ -425,9 +424,8 @@ public final class WorkbookEvaluator {
|
|||||||
|
|
||||||
if (optg instanceof UnionPtg) { continue; }
|
if (optg instanceof UnionPtg) { continue; }
|
||||||
|
|
||||||
OperationEval operation = OperationEvaluatorFactory.create(optg);
|
|
||||||
|
|
||||||
int numops = operation.getNumberOfOperands();
|
int numops = optg.getNumberOfOperands();
|
||||||
ValueEval[] ops = new ValueEval[numops];
|
ValueEval[] ops = new ValueEval[numops];
|
||||||
|
|
||||||
// storing the ops in reverse order since they are popping
|
// storing the ops in reverse order since they are popping
|
||||||
@ -436,7 +434,7 @@ public final class WorkbookEvaluator {
|
|||||||
ops[j] = p;
|
ops[j] = p;
|
||||||
}
|
}
|
||||||
// logDebug("invoke " + operation + " (nAgs=" + numops + ")");
|
// logDebug("invoke " + operation + " (nAgs=" + numops + ")");
|
||||||
opResult = operation.evaluate(ops, ec);
|
opResult = OperationEvaluatorFactory.evaluate(optg, ops, ec);
|
||||||
if (opResult == MissingArgEval.instance) {
|
if (opResult == MissingArgEval.instance) {
|
||||||
opResult = BlankEval.INSTANCE;
|
opResult = BlankEval.INSTANCE;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user