From: Josh Micich Date: Mon, 16 Nov 2009 05:41:57 +0000 (+0000) Subject: Removed OperationEval and rearranged function/operator evaluation. X-Git-Tag: REL_3_6~52 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=cb74e3a99c1884ac0afbfd92904d050c5e697199;p=poi.git Removed OperationEval and rearranged function/operator evaluation. git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@880593 13f79535-47bb-0310-9956-ffa450edef68 --- 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 dc5d6c5fe5..f5a941d677 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 481caa0b6b..0000000000 --- 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/eval/UserDefinedFunction.java b/src/java/org/apache/poi/hssf/record/formula/eval/UserDefinedFunction.java deleted file mode 100644 index 223f13378e..0000000000 --- a/src/java/org/apache/poi/hssf/record/formula/eval/UserDefinedFunction.java +++ /dev/null @@ -1,64 +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.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 - * AbstractFunctionPtg.field_2_fnc_index == 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); - } -} 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 6fb0aabd3e..e14366f781 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 e416a7ee87..87cef4f9cd 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); - - 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 initialiseInstancesMap() { + Map m = new HashMap(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 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/ss/formula/UserDefinedFunction.java b/src/java/org/apache/poi/ss/formula/UserDefinedFunction.java new file mode 100644 index 0000000000..7bf612a47c --- /dev/null +++ b/src/java/org/apache/poi/ss/formula/UserDefinedFunction.java @@ -0,0 +1,67 @@ +/* ==================================================================== + 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 + * AbstractFunctionPtg.field_2_fnc_index == 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); + } +} diff --git a/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java b/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java index 18d8c11d42..8fc1f3eb99 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; }