]> source.dussan.org Git - poi.git/commitdiff
Removed OperationEval and rearranged function/operator evaluation.
authorJosh Micich <josh@apache.org>
Mon, 16 Nov 2009 05:41:57 +0000 (05:41 +0000)
committerJosh Micich <josh@apache.org>
Mon, 16 Nov 2009 05:41:57 +0000 (05:41 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@880593 13f79535-47bb-0310-9956-ffa450edef68

src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
src/java/org/apache/poi/hssf/record/formula/eval/OperationEval.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/eval/UserDefinedFunction.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/function/FunctionMetadataRegistry.java
src/java/org/apache/poi/ss/formula/OperationEvaluatorFactory.java
src/java/org/apache/poi/ss/formula/UserDefinedFunction.java [new file with mode: 0644]
src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java

index dc5d6c5fe5a9fc90501aa899467547c05d504f51..f5a941d677cd6588a7fa5bef4d818b5a2c0ed54b 100644 (file)
 
 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 &lt; amolweb at ya hoo dot com &gt;
  */
-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 <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;
        }
 }
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 (file)
index 481caa0..0000000
+++ /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 &lt; amolweb at ya hoo dot com &gt;
- *
- */
-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();
-}
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 (file)
index 223f133..0000000
+++ /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
- * <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);
-       }
-}
index 6fb0aabd3e3d1677d82a34790dd5317fc4bf6da7..e14366f7812a76718a1d8273d708080ac7fa7e66 100644 (file)
@@ -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;
 
index e416a7ee8748447ed8bdfc26aca73459cdadfd69..87cef4f9cd827022efdfefd9b046b694d8168c82 100644 (file)
@@ -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 <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 {
 
-       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() + ")");
        }
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 (file)
index 0000000..7bf612a
--- /dev/null
@@ -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
+ * <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);
+       }
+}
index 18d8c11d42618c9c1fa57de0913bbb6074284c97..8fc1f3eb998e6c7e3bf6e7add8e71a8db5d42484 100644 (file)
@@ -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;
                                }