]> source.dussan.org Git - poi.git/commitdiff
updated remaining evaluator functions to implement fixed args interfaces
authorJosh Micich <josh@apache.org>
Mon, 23 Nov 2009 00:19:11 +0000 (00:19 +0000)
committerJosh Micich <josh@apache.org>
Mon, 23 Nov 2009 00:19:11 +0000 (00:19 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@883197 13f79535-47bb-0310-9956-ffa450edef68

28 files changed:
src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
src/java/org/apache/poi/hssf/record/formula/functions/AggregateFunction.java
src/java/org/apache/poi/hssf/record/formula/functions/And.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/BooleanFunction.java
src/java/org/apache/poi/hssf/record/formula/functions/False.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java
src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java
src/java/org/apache/poi/hssf/record/formula/functions/Hyperlink.java
src/java/org/apache/poi/hssf/record/formula/functions/Index.java
src/java/org/apache/poi/hssf/record/formula/functions/IsError.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/IsNa.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/Isblank.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/Isref.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/LogicalFunction.java
src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java
src/java/org/apache/poi/hssf/record/formula/functions/Not.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/Npv.java
src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java
src/java/org/apache/poi/hssf/record/formula/functions/Or.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/Pi.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/Rand.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/Substitute.java
src/java/org/apache/poi/hssf/record/formula/functions/TextFunction.java
src/java/org/apache/poi/hssf/record/formula/functions/True.java [deleted file]
src/java/org/apache/poi/hssf/record/formula/functions/Var1or2ArgFunction.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/record/formula/functions/Var3or4ArgFunction.java [new file with mode: 0644]
src/java/org/apache/poi/hssf/record/formula/functions/Vlookup.java
src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java

index cfe88369e4c5a7656526f74c2a242d0641dbbb49..1fa5a386143e44561a9aa0c59b82936b18ca168a 100644 (file)
@@ -52,8 +52,8 @@ public final class FunctionEval {
 
                retval[0] = new Count();
                retval[1] = new If();
-               retval[2] = new IsNa();
-               retval[3] = new IsError();
+               retval[2] = LogicalFunction.ISNA;
+               retval[3] = LogicalFunction.ISERROR;
                retval[ID.SUM] = AggregateFunction.SUM;
                retval[5] = AggregateFunction.AVERAGE;
                retval[6] = AggregateFunction.MIN;
@@ -69,7 +69,7 @@ public final class FunctionEval {
                retval[16] = NumericFunction.COS;
                retval[17] = NumericFunction.TAN;
                retval[18] = NumericFunction.ATAN;
-               retval[19] = new Pi();
+               retval[19] = NumericFunction.PI;
                retval[20] = NumericFunction.SQRT;
                retval[21] = NumericFunction.EXP;
                retval[22] = NumericFunction.LN;
@@ -84,11 +84,11 @@ public final class FunctionEval {
                retval[31] = TextFunction.MID;
                retval[32] = TextFunction.LEN;
                retval[33] = new Value();
-               retval[34] = new True();
-               retval[35] = new False();
-               retval[36] = new And();
-               retval[37] = new Or();
-               retval[38] = new Not();
+               retval[34] = BooleanFunction.TRUE;
+               retval[35] = BooleanFunction.FALSE;
+               retval[36] = BooleanFunction.AND;
+               retval[37] = BooleanFunction.OR;
+               retval[38] = BooleanFunction.NOT;
                retval[39] = NumericFunction.MOD;
 
                retval[56] = FinanceFunction.PV;
@@ -96,7 +96,7 @@ public final class FunctionEval {
                retval[58] = FinanceFunction.NPER;
                retval[59] = FinanceFunction.PMT;
 
-               retval[63] = new Rand();
+               retval[63] = NumericFunction.RAND;
                retval[64] = new Match();
                retval[65] = DateFunc.instance;
                retval[66] = new Time();
@@ -108,6 +108,7 @@ public final class FunctionEval {
 
                retval[76] = new Rows();
                retval[77] = new Columns();
+               retval[82] = TextFunction.SEARCH;
                retval[ID.OFFSET] = new Offset();
                retval[82] = TextFunction.SEARCH;
 
@@ -118,7 +119,7 @@ public final class FunctionEval {
                retval[101] = new Hlookup();
                retval[102] = new Vlookup();
 
-               retval[105] = new Isref();
+               retval[105] = LogicalFunction.ISREF;
 
                retval[109] = NumericFunction.LOG;
 
@@ -134,9 +135,9 @@ public final class FunctionEval {
 
                retval[124] = TextFunction.FIND;
 
-               retval[127] = LogicalFunction.IsText;
-               retval[128] = LogicalFunction.IsNumber;
-               retval[129] = new Isblank();
+               retval[127] = LogicalFunction.ISTEXT;
+               retval[128] = LogicalFunction.ISNUMBER;
+               retval[129] = LogicalFunction.ISBLANK;
                retval[130] = new T();
 
                retval[ID.INDIRECT] = null; // Indirect.evaluate has different signature
@@ -146,9 +147,9 @@ public final class FunctionEval {
                retval[183] = AggregateFunction.PRODUCT;
                retval[184] = NumericFunction.FACT;
 
-               retval[190] = LogicalFunction.IsNonText;
+               retval[190] = LogicalFunction.ISNONTEXT;
 
-               retval[198] = LogicalFunction.IsLogical;
+               retval[198] = LogicalFunction.ISLOGICAL;
 
                retval[212] = NumericFunction.ROUNDUP;
                retval[213] = NumericFunction.ROUNDDOWN;
index 6397ea39f5375fc49de980f68bf3e867e4daa545..2df9dd3e575476045f6e24994ebd019a02195319 100644 (file)
@@ -19,13 +19,67 @@ package org.apache.poi.hssf.record.formula.functions;
 
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.EvaluationException;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.OperandResolver;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
 /**
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
  */
 public abstract class AggregateFunction extends MultiOperandNumericFunction {
 
+       private static final class LargeSmall extends Fixed2ArgFunction {
+               private final boolean _isLarge;
+               protected LargeSmall(boolean isLarge) {
+                       _isLarge = isLarge;
+               }
+
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0,
+                               ValueEval arg1) {
+                       double dn;
+                       try {
+                               ValueEval ve1 = OperandResolver.getSingleValue(arg1, srcRowIndex, srcColumnIndex);
+                               dn = OperandResolver.coerceValueToDouble(ve1);
+                       } catch (EvaluationException e1) {
+                               // all errors in the second arg translate to #VALUE!
+                               return ErrorEval.VALUE_INVALID;
+                       }
+                       // weird Excel behaviour on second arg
+                       if (dn < 1.0) {
+                               // values between 0.0 and 1.0 result in #NUM!
+                               return ErrorEval.NUM_ERROR;
+                       }
+                       // all other values are rounded up to the next integer
+                       int k = (int) Math.ceil(dn);
+
+                       double result;
+                       try {
+                               double[] ds = ValueCollector.collectValues(arg0);
+                               if (k > ds.length) {
+                                       return ErrorEval.NUM_ERROR;
+                               }
+                               result = _isLarge ? StatsLib.kthLargest(ds, k) : StatsLib.kthSmallest(ds, k);
+                               NumericFunction.checkValue(result);
+                       } catch (EvaluationException e) {
+                               return e.getErrorEval();
+                       }
+
+                       return new NumberEval(result);
+               }
+       }
+       private static final class ValueCollector extends MultiOperandNumericFunction {
+               private static final ValueCollector instance = new ValueCollector();
+               public ValueCollector() {
+                       super(false, false);
+               }
+               public static double[] collectValues(ValueEval...operands) throws EvaluationException {
+                       return instance.getNumberArray(operands);
+               }
+               protected double evaluate(double[] values) {
+                       throw new IllegalStateException("should not be called");
+               }
+       }
+
        protected AggregateFunction() {
                super(false, false);
        }
@@ -48,17 +102,7 @@ public abstract class AggregateFunction extends MultiOperandNumericFunction {
                        return StatsLib.devsq(values);
                }
        };
-       public static final Function LARGE = new AggregateFunction() {
-               protected double evaluate(double[] ops) throws EvaluationException {
-                       if (ops.length < 2) {
-                               throw new EvaluationException(ErrorEval.NUM_ERROR);
-                       }
-                       double[] values = new double[ops.length-1];
-                       int k = (int) ops[ops.length-1];
-                       System.arraycopy(ops, 0, values, 0, values.length);
-                       return StatsLib.kthLargest(values, k);
-               }
-       };
+       public static final Function LARGE = new LargeSmall(true);
        public static final Function MAX = new AggregateFunction() {
                protected double evaluate(double[] values) {
                        return values.length > 0 ? MathX.max(values) : 0;
@@ -79,17 +123,7 @@ public abstract class AggregateFunction extends MultiOperandNumericFunction {
                        return MathX.product(values);
                }
        };
-       public static final Function SMALL = new AggregateFunction() {
-               protected double evaluate(double[] ops) throws EvaluationException {
-                       if (ops.length < 2) {
-                               throw new EvaluationException(ErrorEval.NUM_ERROR);
-                       }
-                       double[] values = new double[ops.length-1];
-                       int k = (int) ops[ops.length-1];
-                       System.arraycopy(ops, 0, values, 0, values.length);
-                       return StatsLib.kthSmallest(values, k);
-               }
-       };
+       public static final Function SMALL = new LargeSmall(false);
        public static final Function STDEV = new AggregateFunction() {
                protected double evaluate(double[] values) throws EvaluationException {
                        if (values.length < 1) {
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/And.java b/src/java/org/apache/poi/hssf/record/formula/functions/And.java
deleted file mode 100644 (file)
index e024562..0000000
+++ /dev/null
@@ -1,32 +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.functions;
-
-/**
- *
- */
-public final class And extends BooleanFunction {
-
-       protected boolean getInitialResultValue() {
-               return true;
-       }
-
-       protected boolean partialEvaluate(boolean cumulativeResult, boolean currentValue) {
-               return cumulativeResult && currentValue;
-       }
-}
index 4e959a61e53a241ee2018c24070c94832a5bb24a..0165e501a5674ab878be1cf64aae11d4259b17c9 100644 (file)
@@ -101,4 +101,46 @@ public abstract class BooleanFunction implements Function {
 
        protected abstract boolean getInitialResultValue();
        protected abstract boolean partialEvaluate(boolean cumulativeResult, boolean currentValue);
+
+
+       public static final Function AND = new BooleanFunction() {
+               protected boolean getInitialResultValue() {
+                       return true;
+               }
+               protected boolean partialEvaluate(boolean cumulativeResult, boolean currentValue) {
+                       return cumulativeResult && currentValue;
+               }
+       };
+       public static final Function OR = new BooleanFunction() {
+               protected boolean getInitialResultValue() {
+                       return false;
+               }
+               protected boolean partialEvaluate(boolean cumulativeResult, boolean currentValue) {
+                       return cumulativeResult || currentValue;
+               }
+       };
+       public static final Function FALSE = new Fixed0ArgFunction() {
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
+                       return BoolEval.FALSE;
+               }
+       };
+       public static final Function TRUE = new Fixed0ArgFunction() {
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
+                       return BoolEval.TRUE;
+               }
+       };
+       public static final Function NOT = new Fixed1ArgFunction() {
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
+                       boolean boolArgVal;
+                       try {
+                               ValueEval ve = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
+                               Boolean b = OperandResolver.coerceValueToBoolean(ve, false);
+                               boolArgVal = b == null ? false : b.booleanValue();
+                       } catch (EvaluationException e) {
+                               return e.getErrorEval();
+                       }
+
+                       return BoolEval.valueOf(!boolArgVal);
+               }
+       };
 }
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/False.java b/src/java/org/apache/poi/hssf/record/formula/functions/False.java
deleted file mode 100644 (file)
index 74ade2d..0000000
+++ /dev/null
@@ -1,42 +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.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BoolEval;
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public final class False implements Function {
-
-    public ValueEval evaluate(ValueEval[] operands, int srcRow, int srcCol) {
-        ValueEval retval;
-        switch (operands.length) {
-        default:
-            retval = ErrorEval.VALUE_INVALID;
-            break;
-        case 0:
-            retval = BoolEval.FALSE;
-        }
-        return retval;
-    }
-
-}
index 2de9ab13501e4043ec0dbef78b4766feab7a0f61..c101f2dc9e6f547b2af432decb7f0e9a47102f95 100644 (file)
 
 package org.apache.poi.hssf.record.formula.functions;
 
+import org.apache.poi.hssf.record.formula.eval.BoolEval;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.EvaluationException;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
 /**
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- * Super class for all Evals for financial function evaluation.
- *
  */
-public abstract class FinanceFunction extends NumericFunction.MultiArg {
+public abstract class FinanceFunction implements Function3Arg, Function4Arg {
+       private static final ValueEval DEFAULT_ARG3 = NumberEval.ZERO;
+       private static final ValueEval DEFAULT_ARG4 = BoolEval.FALSE;
+
 
        protected FinanceFunction() {
-               super (3, 5);
+               // no instance fields
+       }
+
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+                       ValueEval arg2) {
+               return evaluate(srcRowIndex, srcColumnIndex, arg0, arg1, arg2, DEFAULT_ARG3);
+       }
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+                       ValueEval arg2, ValueEval arg3) {
+               return evaluate(srcRowIndex, srcColumnIndex, arg0, arg1, arg2, arg3, DEFAULT_ARG4);
+       }
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+                       ValueEval arg2, ValueEval arg3, ValueEval arg4) {
+               double result;
+               try {
+                       double d0 = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+                       double d1 = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
+                       double d2 = NumericFunction.singleOperandEvaluate(arg2, srcRowIndex, srcColumnIndex);
+                       double d3 = NumericFunction.singleOperandEvaluate(arg3, srcRowIndex, srcColumnIndex);
+                       double d4 = NumericFunction.singleOperandEvaluate(arg4, srcRowIndex, srcColumnIndex);
+                       result = evaluate(d0, d1, d2, d3, d4 != 0.0);
+                       NumericFunction.checkValue(result);
+               } catch (EvaluationException e) {
+                       return e.getErrorEval();
+               }
+               return new NumberEval(result);
+       }
+       public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+               switch (args.length) {
+                       case 3:
+                               return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2], DEFAULT_ARG3, DEFAULT_ARG4);
+                       case 4:
+                               return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2], args[3], DEFAULT_ARG4);
+                       case 5:
+                               return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2], args[3], args[4]);
+               }
+               return ErrorEval.VALUE_INVALID;
        }
 
        protected double evaluate(double[] ds) throws EvaluationException {
index 0a25044f33364bd8f78d02b26e7e5674b02b5bf6..03faa25b550ac4b75d371bbd0be190bb95ade753 100644 (file)
@@ -18,7 +18,7 @@
 package org.apache.poi.hssf.record.formula.functions;
 
 import org.apache.poi.hssf.record.formula.eval.AreaEval;
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.BoolEval;
 import org.apache.poi.hssf.record.formula.eval.EvaluationException;
 import org.apache.poi.hssf.record.formula.eval.OperandResolver;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
@@ -39,27 +39,24 @@ import org.apache.poi.hssf.record.formula.functions.LookupUtils.ValueVector;
  *
  * @author Josh Micich
  */
-public final class Hlookup implements Function {
+public final class Hlookup extends Var3or4ArgFunction  {
+       private static final ValueEval DEFAULT_ARG3 = BoolEval.TRUE;
 
-       public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
-               ValueEval arg3 = null;
-               switch(args.length) {
-                       case 4:
-                               arg3 = args[3]; // important: assumed array element is never null
-                       case 3:
-                               break;
-                       default:
-                               // wrong number of arguments
-                               return ErrorEval.VALUE_INVALID;
-               }
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+                       ValueEval arg2) {
+               return evaluate(srcRowIndex, srcColumnIndex, arg0, arg1, arg2, DEFAULT_ARG3);
+       }
+
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+                       ValueEval arg2, ValueEval arg3) {
                try {
                        // Evaluation order:
                        // arg0 lookup_value, arg1 table_array, arg3 range_lookup, find lookup value, arg2 row_index, fetch result
-                       ValueEval lookupValue = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
-                       AreaEval tableArray = LookupUtils.resolveTableArrayArg(args[1]);
-                       boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcCellRow, srcCellCol);
+                       ValueEval lookupValue = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
+                       AreaEval tableArray = LookupUtils.resolveTableArrayArg(arg1);
+                       boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcRowIndex, srcColumnIndex);
                        int colIndex = LookupUtils.lookupIndexOfValue(lookupValue, LookupUtils.createRowVector(tableArray, 0), isRangeLookup);
-                       int rowIndex = LookupUtils.resolveRowOrColIndexArg(args[2], srcCellRow, srcCellCol);
+                       int rowIndex = LookupUtils.resolveRowOrColIndexArg(arg2, srcRowIndex, srcColumnIndex);
                        ValueVector resultCol = createResultColumnVector(tableArray, rowIndex);
                        return resultCol.getItem(colIndex);
                } catch (EvaluationException e) {
@@ -67,7 +64,6 @@ public final class Hlookup implements Function {
                }
        }
 
-
        /**
         * Returns one column from an <tt>AreaEval</tt>
         *
index 703af9716c143dc1747bdc2f86ab6b952b37ecab..761c5f3a63b303dbd1b6046be2b1f02e2871f2c2 100644 (file)
@@ -17,9 +17,6 @@
 
 package org.apache.poi.hssf.record.formula.functions;
 
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.EvaluationException;
-import org.apache.poi.hssf.record.formula.eval.OperandResolver;
 import org.apache.poi.hssf.record.formula.eval.StringEval;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
@@ -36,21 +33,17 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
  * <b>friendly_name</b> (optional) the value to display<p/>
  *
  *  Returns last argument.  Leaves type unchanged (does not convert to {@link StringEval}).
-
+ *
  * @author Wayne Clingingsmith
  */
-public final class Hyperlink implements Function {
+public final class Hyperlink extends Var1or2ArgFunction {
 
-       public ValueEval evaluate(ValueEval[] operands, int srcRow, int srcCol) {
-               int lastArgIx = operands.length - 1;
-               if (lastArgIx < 0 || lastArgIx > 1) {
-                       return ErrorEval.VALUE_INVALID;
-               }
-
-               try {
-                       return OperandResolver.getSingleValue(operands[lastArgIx], srcRow, srcCol);
-               } catch (EvaluationException e) {
-                       return e.getErrorEval();
-               }
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
+               return arg0;
+       }
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
+               // note - if last arg is MissingArgEval, result will be NumberEval.ZERO,
+               // but WorkbookEvaluator does that translation
+               return arg1;
        }
 }
index 49e7484fa7bb79ee67cdc70af36a67b6a12189ec..ad1dc9dd2b7e2e9a9f1631d1dc8a5b7b0b54a3a7 100644 (file)
@@ -44,56 +44,71 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
  *
  * @author Josh Micich
  */
-public final class Index implements Function {
+public final class Index implements Function2Arg, Function3Arg, Function4Arg {
 
-       public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
-               int nArgs = args.length;
-               if(nArgs < 2) {
-                       // too few arguments
-                       return ErrorEval.VALUE_INVALID;
-               }
-               ValueEval firstArg = args[0];
-               if (firstArg instanceof RefEval) {
-                       // convert to area ref for simpler code in getValueFromArea()
-                       firstArg = ((RefEval)firstArg).offset(0, 0, 0, 0);
-               }
-               if(!(firstArg instanceof AreaEval)) {
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
+               AreaEval reference = convertFirstArg(arg0);
 
-                       // else the other variation of this function takes an array as the first argument
-                       // it seems like interface 'ArrayEval' does not even exist yet
-                       throw new RuntimeException("Incomplete code - cannot handle first arg of type ("
-                                       + firstArg.getClass().getName() + ")");
+               boolean colArgWasPassed = false;
+               int columnIx = 0;
+               try {
+                       int rowIx = resolveIndexArg(arg1, srcRowIndex, srcColumnIndex);
+                       return getValueFromArea(reference, rowIx, columnIx, colArgWasPassed, srcRowIndex, srcColumnIndex);
+               } catch (EvaluationException e) {
+                       return e.getErrorEval();
                }
-               AreaEval reference = (AreaEval) firstArg;
+       }
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+                       ValueEval arg2) {
+               AreaEval reference = convertFirstArg(arg0);
 
-               int rowIx = 0;
-               int columnIx = 0;
-               boolean colArgWasPassed = false;
+               boolean colArgWasPassed = true;
                try {
-                       switch(nArgs) {
-                               case 4:
-                                       throw new RuntimeException("Incomplete code" +
-                                                       " - don't know how to support the 'area_num' parameter yet)");
-                                       // Excel expression might look like this "INDEX( (A1:B4, C3:D6, D2:E5 ), 1, 2, 3)
-                                       // In this example, the 3rd area would be used i.e. D2:E5, and the overall result would be E2
-                                       // Token array might be encoded like this: MemAreaPtg, AreaPtg, AreaPtg, UnionPtg, UnionPtg, ParenthesesPtg
-                                       // The formula parser doesn't seem to support this yet. Not sure if the evaluator does either
-
-                               case 3:
-                                       columnIx = resolveIndexArg(args[2], srcCellRow, srcCellCol);
-                                       colArgWasPassed = true;
-                               case 2:
-                                       rowIx = resolveIndexArg(args[1], srcCellRow, srcCellCol);
-                                       break;
-                               default:
-                                       // too many arguments
-                                       return ErrorEval.VALUE_INVALID;
-                       }
-                       return getValueFromArea(reference, rowIx, columnIx, colArgWasPassed, srcCellRow, srcCellCol);
+                       int columnIx = resolveIndexArg(arg2, srcRowIndex, srcColumnIndex);
+                       int rowIx = resolveIndexArg(arg1, srcRowIndex, srcColumnIndex);
+                       return getValueFromArea(reference, rowIx, columnIx, colArgWasPassed, srcRowIndex, srcColumnIndex);
                } catch (EvaluationException e) {
                        return e.getErrorEval();
                }
        }
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+                       ValueEval arg2, ValueEval arg3) {
+               throw new RuntimeException("Incomplete code"
+                               + " - don't know how to support the 'area_num' parameter yet)");
+               // Excel expression might look like this "INDEX( (A1:B4, C3:D6, D2:E5 ), 1, 2, 3)
+               // In this example, the 3rd area would be used i.e. D2:E5, and the overall result would be E2
+               // Token array might be encoded like this: MemAreaPtg, AreaPtg, AreaPtg, UnionPtg, UnionPtg, ParenthesesPtg
+               // The formula parser doesn't seem to support this yet. Not sure if the evaluator does either
+       }
+
+       private static AreaEval convertFirstArg(ValueEval arg0) {
+               ValueEval firstArg = arg0;
+               if (firstArg instanceof RefEval) {
+                       // convert to area ref for simpler code in getValueFromArea()
+                       return ((RefEval)firstArg).offset(0, 0, 0, 0);
+               }
+               if((firstArg instanceof AreaEval)) {
+                       return (AreaEval) firstArg;
+               }
+               // else the other variation of this function takes an array as the first argument
+               // it seems like interface 'ArrayEval' does not even exist yet
+               throw new RuntimeException("Incomplete code - cannot handle first arg of type ("
+                               + firstArg.getClass().getName() + ")");
+
+       }
+
+       public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+               switch (args.length) {
+                       case 2:
+                               return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1]);
+                       case 3:
+                               return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2]);
+                       case 4:
+                               return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2], args[3]);
+               }
+               return ErrorEval.VALUE_INVALID;
+       }
+
 
        /**
         * @param colArgWasPassed <code>false</code> if the INDEX argument list had just 2 items
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/IsError.java b/src/java/org/apache/poi/hssf/record/formula/functions/IsError.java
deleted file mode 100644 (file)
index 654f4d7..0000000
+++ /dev/null
@@ -1,42 +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.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BoolEval;
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.EvaluationException;
-import org.apache.poi.hssf.record.formula.eval.OperandResolver;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Josh Micich
- */
-public final class IsError implements Function {
-
-       public ValueEval evaluate(ValueEval[] operands, int srcCellRow, int srcCellCol) {
-               if (operands.length != 1) {
-                       return ErrorEval.VALUE_INVALID;
-               }
-               try {
-                       OperandResolver.getSingleValue(operands[0], srcCellRow, srcCellCol);
-               } catch (EvaluationException e) {
-                       return BoolEval.TRUE;
-               }
-               return BoolEval.FALSE;
-       }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/IsNa.java b/src/java/org/apache/poi/hssf/record/formula/functions/IsNa.java
deleted file mode 100644 (file)
index 316a29e..0000000
+++ /dev/null
@@ -1,56 +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.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BoolEval;
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.EvaluationException;
-import org.apache.poi.hssf.record.formula.eval.OperandResolver;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import org.apache.poi.ss.usermodel.ErrorConstants;
-
-/**
- * Implementation for Excel ISNA() function.<p/>
- *
- * <b>Syntax</b>:<br/>
- * <b>ISNA</b>(<b>value</b>)<p/>
- *
- * <b>value</b>  The value to be tested<br/>
- * <br/>
- * Returns <tt>TRUE</tt> if the specified value is '#N/A', <tt>FALSE</tt> otherwise.
- *
- * @author Josh Micich
- */
-public final class IsNa implements Function {
-
-       public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
-               if(args.length != 1) {
-                       return ErrorEval.VALUE_INVALID;
-               }
-               ValueEval arg = args[0];
-
-               try {
-                       OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
-               } catch (EvaluationException e) {
-                       if (e.getErrorEval().getErrorCode() == ErrorConstants.ERROR_NA) {
-                               return BoolEval.TRUE;
-                       }
-               }
-               return BoolEval.FALSE;
-       }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Isblank.java b/src/java/org/apache/poi/hssf/record/formula/functions/Isblank.java
deleted file mode 100644 (file)
index 60132c3..0000000
+++ /dev/null
@@ -1,47 +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.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BlankEval;
-import org.apache.poi.hssf.record.formula.eval.BoolEval;
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.EvaluationException;
-import org.apache.poi.hssf.record.formula.eval.OperandResolver;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public final class Isblank implements Function {
-
-       public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
-               if(args.length != 1) {
-                       return ErrorEval.VALUE_INVALID;
-               }
-               ValueEval arg = args[0];
-
-               ValueEval singleCellValue;
-               try {
-                       singleCellValue = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
-               } catch (EvaluationException e) {
-                       return BoolEval.FALSE;
-               }
-               return BoolEval.valueOf(singleCellValue instanceof BlankEval);
-       }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Isref.java b/src/java/org/apache/poi/hssf/record/formula/functions/Isref.java
deleted file mode 100644 (file)
index 84eb80b..0000000
+++ /dev/null
@@ -1,42 +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.functions;
-
-import org.apache.poi.hssf.record.formula.eval.AreaEval;
-import org.apache.poi.hssf.record.formula.eval.BoolEval;
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.RefEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- */
-public final class Isref implements Function {
-       public ValueEval evaluate(ValueEval[] operands, int srcCellRow, int srcCellCol) {
-               if (operands.length != 1) {
-                       return ErrorEval.VALUE_INVALID;
-               }
-
-               ValueEval eval = operands[0];
-               if (eval instanceof RefEval || eval instanceof AreaEval) {
-                       return BoolEval.TRUE;
-               }
-
-               return BoolEval.FALSE;
-       }
-}
index 34221ec9f6a77b33f88768485b79980c942ef087..206dd41b689045233bb99ec08dfcf19de7b7d159 100644 (file)
@@ -17,6 +17,8 @@
 
 package org.apache.poi.hssf.record.formula.functions;
 
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.BlankEval;
 import org.apache.poi.hssf.record.formula.eval.BoolEval;
 import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.EvaluationException;
@@ -28,30 +30,14 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
 /**
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
+ * @author Josh Micich
  */
-public abstract class LogicalFunction implements Function {
+public abstract class LogicalFunction extends Fixed1ArgFunction {
 
-       /**
-        * recursively evaluate any RefEvals TODO - use {@link OperandResolver}
-        */
-       private static ValueEval xlateRefEval(RefEval reval) {
-               ValueEval retval = reval.getInnerValueEval();
-
-               if (retval instanceof RefEval) {
-                       RefEval re = (RefEval) retval;
-                       retval = xlateRefEval(re);
-               }
-
-               return retval;
-       }
-
-       public final ValueEval evaluate(ValueEval[] operands, int srcCellRow, int srcCellCol) {
-               if (operands.length != 1) {
-                       return ErrorEval.VALUE_INVALID;
-               }
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
                ValueEval ve;
                try {
-                       ve = OperandResolver.getSingleValue(operands[0], srcCellRow, srcCellCol);
+                       ve = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
                } catch (EvaluationException e) {
                        if (false) {
                                // Note - it is more usual to propagate error codes straight to the result like this:
@@ -61,32 +47,73 @@ public abstract class LogicalFunction implements Function {
                        // this will usually cause a 'FALSE' result except for ISNONTEXT()
                        ve = e.getErrorEval();
                }
-               if (ve instanceof RefEval) {
-                       ve = xlateRefEval((RefEval) ve);
-               }
                return BoolEval.valueOf(evaluate(ve));
 
        }
+       /**
+        * @param arg any {@link ValueEval}, potentially {@link BlankEval} or {@link ErrorEval}.
+        */
        protected abstract boolean evaluate(ValueEval arg);
 
-       public static final Function IsLogical = new LogicalFunction() {
+       public static final Function ISLOGICAL = new LogicalFunction() {
                protected boolean evaluate(ValueEval arg) {
                        return arg instanceof BoolEval;
                }
        };
-       public static final Function IsNonText = new LogicalFunction() {
+       public static final Function ISNONTEXT = new LogicalFunction() {
                protected boolean evaluate(ValueEval arg) {
                        return !(arg instanceof StringEval);
                }
        };
-       public static final Function IsNumber = new LogicalFunction() {
+       public static final Function ISNUMBER = new LogicalFunction() {
                protected boolean evaluate(ValueEval arg) {
                        return arg instanceof NumberEval;
                }
        };
-       public static final Function IsText = new LogicalFunction() {
+       public static final Function ISTEXT = new LogicalFunction() {
                protected boolean evaluate(ValueEval arg) {
                        return arg instanceof StringEval;
                }
        };
+
+       public static final Function ISBLANK = new LogicalFunction() {
+
+               protected boolean evaluate(ValueEval arg) {
+                       return arg instanceof BlankEval;
+               }
+       };
+
+       public static final Function ISERROR = new LogicalFunction() {
+
+               protected boolean evaluate(ValueEval arg) {
+                       return arg instanceof ErrorEval;
+               }
+       };
+
+       /**
+        * Implementation for Excel ISNA() function.<p/>
+        *
+        * <b>Syntax</b>:<br/>
+        * <b>ISNA</b>(<b>value</b>)<p/>
+        *
+        * <b>value</b>  The value to be tested<br/>
+        * <br/>
+        * Returns <tt>TRUE</tt> if the specified value is '#N/A', <tt>FALSE</tt> otherwise.
+        */
+       public static final Function ISNA = new LogicalFunction() {
+
+               protected boolean evaluate(ValueEval arg) {
+                       return arg == ErrorEval.NA;
+               }
+       };
+
+       public static final Function ISREF = new Fixed1ArgFunction() {
+
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
+                       if (arg0 instanceof RefEval || arg0 instanceof AreaEval) {
+                               return BoolEval.TRUE;
+                       }
+                       return BoolEval.FALSE;
+               }
+       };
 }
index 58e3684dfc0aba3f96fcc75ebad9d22c27104123..ae2bc9114cf449a828615e4f2cfa8cf3c9bed387 100644 (file)
@@ -379,17 +379,10 @@ final class LookupUtils {
 
        /**
         * Resolves the last (optional) parameter (<b>range_lookup</b>) to the VLOOKUP and HLOOKUP functions.
-        * @param rangeLookupArg
-        * @param srcCellRow
-        * @param srcCellCol
-        * @return
-        * @throws EvaluationException
+        * @param rangeLookupArg must not be <code>null</code>
         */
        public static boolean resolveRangeLookupArg(ValueEval rangeLookupArg, int srcCellRow, int srcCellCol) throws EvaluationException {
-               if(rangeLookupArg == null) {
-                       // range_lookup arg not provided
-                       return true; // default is TRUE
-               }
+
                ValueEval valEval = OperandResolver.getSingleValue(rangeLookupArg, srcCellRow, srcCellCol);
                if(valEval instanceof BlankEval) {
                        // Tricky:
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Not.java b/src/java/org/apache/poi/hssf/record/formula/functions/Not.java
deleted file mode 100644 (file)
index 792ee3a..0000000
+++ /dev/null
@@ -1,50 +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.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BoolEval;
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.EvaluationException;
-import org.apache.poi.hssf.record.formula.eval.OperandResolver;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-
-/**
- * @author Amol S. Deshmukh &lt; amol at apache dot org &gt;
- * The NOT boolean function. Returns negation of specified value
- * (treated as a boolean). If the specified arg is a number,
- * then it is true <=> 'number is non-zero'
- */
-public final class Not implements Function {
-
-       public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
-               if (args.length != 1) {
-                       return ErrorEval.VALUE_INVALID;
-               }
-               boolean boolArgVal;
-               try {
-                       ValueEval ve = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
-                       Boolean b = OperandResolver.coerceValueToBoolean(ve, false);
-                       boolArgVal = b == null ? false : b.booleanValue();
-               } catch (EvaluationException e) {
-                       return e.getErrorEval();
-               }
-
-               return BoolEval.valueOf(!boolArgVal);
-       }
-}
index 114aa4d02e1d701a561cabec3294d56eb19836c6..99955301e7286c92c78d05775cdd0fd70354e40f 100644 (file)
 
 package org.apache.poi.hssf.record.formula.functions;
 
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
 import org.apache.poi.hssf.record.formula.eval.EvaluationException;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
 /**
  * Calculates the net present value of an investment by using a discount rate
@@ -25,23 +28,80 @@ import org.apache.poi.hssf.record.formula.eval.EvaluationException;
  * values). Minimum 2 arguments, first arg is the rate of discount over the
  * length of one period others up to 254 arguments representing the payments and
  * income.
- * 
+ *
  * @author SPetrakovsky
  */
-public class Npv extends NumericFunction.MultiArg {
+public final class Npv implements Function2Arg, Function3Arg, Function4Arg {
 
-       public Npv() {
-               super(2, 255);
+
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
+               double result;
+               try {
+                       double rate = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+                       double d1 = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
+                       result = evaluate(rate, d1);
+                       NumericFunction.checkValue(result);
+               } catch (EvaluationException e) {
+                       return e.getErrorEval();
+               }
+               return new NumberEval(result);
+       }
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+                       ValueEval arg2) {
+               double result;
+               try {
+                       double rate = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+                       double d1 = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
+                       double d2 = NumericFunction.singleOperandEvaluate(arg2, srcRowIndex, srcColumnIndex);
+                       result = evaluate(rate, d1, d2);
+                       NumericFunction.checkValue(result);
+               } catch (EvaluationException e) {
+                       return e.getErrorEval();
+               }
+               return new NumberEval(result);
+       }
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+                       ValueEval arg2, ValueEval arg3) {
+               double result;
+               try {
+                       double rate = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+                       double d1 = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
+                       double d2 = NumericFunction.singleOperandEvaluate(arg2, srcRowIndex, srcColumnIndex);
+                       double d3 = NumericFunction.singleOperandEvaluate(arg3, srcRowIndex, srcColumnIndex);
+                       result = evaluate(rate, d1, d2, d3);
+                       NumericFunction.checkValue(result);
+               } catch (EvaluationException e) {
+                       return e.getErrorEval();
+               }
+               return new NumberEval(result);
        }
 
-       @Override
-       protected double evaluate(double[] ds) throws EvaluationException {
-               double rate = ds[0];
+       public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+               int nArgs = args.length;
+               if (nArgs<2) {
+                       return ErrorEval.VALUE_INVALID;
+               }
+               int np = nArgs-1;
+               double[] ds = new double[np];
+               double result;
+               try {
+                       double rate = NumericFunction.singleOperandEvaluate(args[0], srcRowIndex, srcColumnIndex);
+                       for (int i = 0; i < ds.length; i++) {
+                               ds[i] =  NumericFunction.singleOperandEvaluate(args[i+1], srcRowIndex, srcColumnIndex);
+                       }
+                       result = evaluate(rate, ds);
+                       NumericFunction.checkValue(result);
+               } catch (EvaluationException e) {
+                       return e.getErrorEval();
+               }
+               return new NumberEval(result);
+       }
+
+       private static double evaluate(double rate, double...ds) {
                double sum = 0;
-               for (int i = 1; i < ds.length; i++) {
+               for (int i = 0; i < ds.length; i++) {
                        sum += ds[i] / Math.pow(rate + 1, i);
                }
                return sum;
        }
-
 }
index 24b0ae26920b3f67fc89f824fd4bcf410e7a1628..3d32925ae3964bd881aa77e930443d629a7c81e9 100644 (file)
@@ -25,6 +25,7 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
 /**
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
+ * @author Josh Micich
  */
 public abstract class NumericFunction implements Function {
 
@@ -32,8 +33,8 @@ public abstract class NumericFunction implements Function {
        static final double TEN = 10.0;
        static final double LOG_10_TO_BASE_e = Math.log(TEN);
 
-       protected static final double singleOperandEvaluate(ValueEval arg, int srcCellRow, int srcCellCol) throws EvaluationException {
-               ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
+       protected static final double singleOperandEvaluate(ValueEval arg, int srcRowIndex, int srcColumnIndex) throws EvaluationException {
+               ValueEval ve = OperandResolver.getSingleValue(arg, srcRowIndex, srcColumnIndex);
                double result = OperandResolver.coerceValueToDouble(ve);
                checkValue(result);
                return result;
@@ -64,10 +65,21 @@ public abstract class NumericFunction implements Function {
        /* -------------------------------------------------------------------------- */
        // intermediate sub-classes (one-arg, two-arg and multi-arg)
 
-       public static abstract class OneArg extends NumericFunction {
+       public static abstract class OneArg extends Fixed1ArgFunction {
                protected OneArg() {
                        // no fields to initialise
                }
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
+                       double result;
+                       try {
+                               double d = singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+                               result = evaluate(d);
+                               checkValue(result);
+                       } catch (EvaluationException e) {
+                               return e.getErrorEval();
+                       }
+                       return new NumberEval(result);
+               }
                protected final double eval(ValueEval[] args, int srcCellRow, int srcCellCol) throws EvaluationException {
                        if (args.length != 1) {
                                throw new EvaluationException(ErrorEval.VALUE_INVALID);
@@ -78,40 +90,26 @@ public abstract class NumericFunction implements Function {
                protected abstract double evaluate(double d) throws EvaluationException;
        }
 
-       public static abstract class TwoArg extends NumericFunction {
+       public static abstract class TwoArg extends Fixed2ArgFunction {
                protected TwoArg() {
                        // no fields to initialise
                }
-               protected final double eval(ValueEval[] args, int srcCellRow, int srcCellCol) throws EvaluationException {
-                       if (args.length != 2) {
-                               throw new EvaluationException(ErrorEval.VALUE_INVALID);
-                       }
-                       double d0 = singleOperandEvaluate(args[0], srcCellRow, srcCellCol);
-                       double d1 = singleOperandEvaluate(args[1], srcCellRow, srcCellCol);
-                       return evaluate(d0, d1);
-               }
-               protected abstract double evaluate(double d0, double d1) throws EvaluationException;
-       }
 
-       public static abstract class MultiArg extends NumericFunction {
-               private final int _minArgs;
-               private final int _maxArgs;
-               protected MultiArg(int minArgs, int maxArgs) {
-                       _minArgs = minArgs;
-                       _maxArgs = maxArgs;
-               }
-               protected final double eval(ValueEval[] args, int srcCellRow, int srcCellCol) throws EvaluationException {
-                       int nArgs = args.length;
-                       if (nArgs < _minArgs || nArgs > _maxArgs) {
-                               throw new EvaluationException(ErrorEval.VALUE_INVALID);
-                       }
-                       double[] ds = new double[nArgs];
-                       for(int i=0; i<nArgs; i++) {
-                               ds[i] = singleOperandEvaluate(args[i], srcCellRow, srcCellCol);
+
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
+                       double result;
+                       try {
+                               double d0 = singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+                               double d1 = singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
+                               result =  evaluate(d0, d1);
+                               checkValue(result);
+                       } catch (EvaluationException e) {
+                               return e.getErrorEval();
                        }
-                       return evaluate(ds);
+                       return new NumberEval(result);
                }
-               protected abstract double evaluate(double[] ds) throws EvaluationException;
+
+               protected abstract double evaluate(double d0, double d1) throws EvaluationException;
        }
 
        /* -------------------------------------------------------------------------- */
@@ -166,9 +164,34 @@ public abstract class NumericFunction implements Function {
                        return Math.toDegrees(d);
                }
        };
-       public static final Function DOLLAR = new OneArg() {
-               protected double evaluate(double d) {
-                       return d;
+       static final NumberEval DOLLAR_ARG2_DEFAULT = new NumberEval(2.0);
+       public static final Function DOLLAR = new Var1or2ArgFunction() {
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
+                       return evaluate(srcRowIndex, srcColumnIndex, arg0, DOLLAR_ARG2_DEFAULT);
+               }
+
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0,
+                               ValueEval arg1) {
+                       double val;
+                       double d1;
+                       try {
+                               val = singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+                               d1 = singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
+                       } catch (EvaluationException e) {
+                               return e.getErrorEval();
+                       }
+                       // second arg converts to int by truncating toward zero
+                       int nPlaces = (int)d1;
+
+                       if (nPlaces > 127) {
+                               return ErrorEval.VALUE_INVALID;
+                       }
+
+
+                       // TODO - DOLLAR() function impl is NQR
+                       // result should be StringEval, with leading '$' and thousands separators
+                       // current junits are asserting incorrect behaviour
+                       return new NumberEval(val);
                }
        };
        public static final Function EXP = new OneArg() {
@@ -298,18 +321,53 @@ public abstract class NumericFunction implements Function {
 
        /* -------------------------------------------------------------------------- */
 
-       public static final Function LOG = new MultiArg(1,2) {
-               protected double evaluate(double[] ds) {
-
-                       double logE = Math.log(ds[0]);
-                       if (ds.length == 1) {
-                               return logE / LOG_10_TO_BASE_e;
+       private static final class Log extends Var1or2ArgFunction {
+               public Log() {
+                       // no instance fields
+               }
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
+                       double result;
+                       try {
+                               double d0 = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+                               result = Math.log(d0) / LOG_10_TO_BASE_e;
+                               NumericFunction.checkValue(result);
+                       } catch (EvaluationException e) {
+                               return e.getErrorEval();
                        }
-                       double base = ds[1];
-                       if (base == Math.E) {
-                               return logE;
+                       return new NumberEval(result);
+               }
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0,
+                               ValueEval arg1) {
+                       double result;
+                       try {
+                               double d0 = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
+                               double d1 = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
+                               double logE = Math.log(d0);
+                               double base = d1;
+                               if (base == Math.E) {
+                                       result = logE;
+                               } else {
+                                       result = logE / Math.log(base);
+                               }
+                               NumericFunction.checkValue(result);
+                       } catch (EvaluationException e) {
+                               return e.getErrorEval();
                        }
-                       return logE / Math.log(base);
+                       return new NumberEval(result);
+               }
+       }
+
+       public static final Function LOG = new Log();
+
+       static final NumberEval PI_EVAL = new NumberEval(Math.PI);
+       public static final Function PI = new Fixed0ArgFunction() {
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
+                       return PI_EVAL;
+               }
+       };
+       public static final Function RAND = new Fixed0ArgFunction() {
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
+                       return new NumberEval(Math.random());
                }
        };
 }
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Or.java b/src/java/org/apache/poi/hssf/record/formula/functions/Or.java
deleted file mode 100644 (file)
index bab7747..0000000
+++ /dev/null
@@ -1,32 +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.functions;
-
-/**
- *
- */
-public final class Or extends BooleanFunction {
-
-       protected boolean getInitialResultValue() {
-               return false;
-       }
-
-       protected boolean partialEvaluate(boolean cumulativeResult, boolean currentValue) {
-               return cumulativeResult || currentValue;
-       }
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Pi.java b/src/java/org/apache/poi/hssf/record/formula/functions/Pi.java
deleted file mode 100644 (file)
index e31d656..0000000
+++ /dev/null
@@ -1,44 +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.functions;
-
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public final class Pi implements Function {
-
-    private static final NumberEval PI_EVAL = new NumberEval(Math.PI);
-
-    public ValueEval evaluate(ValueEval[] operands, int srcRow, int srcCol) {
-        ValueEval retval;
-        switch (operands.length) {
-        default:
-            retval = ErrorEval.VALUE_INVALID;
-            break;
-        case 0:
-            retval = PI_EVAL;
-        }
-        return retval;
-    }
-
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Rand.java b/src/java/org/apache/poi/hssf/record/formula/functions/Rand.java
deleted file mode 100644 (file)
index e1467a6..0000000
+++ /dev/null
@@ -1,42 +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.functions;
-
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public final class Rand implements Function {
-
-    public ValueEval evaluate(ValueEval[] operands, int srcRow, int srcCol) {
-        ValueEval retval;
-        switch (operands.length) {
-        default:
-            retval = ErrorEval.VALUE_INVALID;
-            break;
-        case 0:
-            retval = new NumberEval(Math.random());
-        }
-        return retval;
-    }
-
-}
index 0055bc6fe4297cc642ebd0e9ac640ec20aa1459a..558de6ba8f36adbf93143a603c418de70799d083 100644 (file)
@@ -27,31 +27,38 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
  * Substitutes text in a text string with new text, some number of times.
  * @author Manda Wilson &lt; wilson at c bio dot msk cc dot org &gt;
  */
-public final class Substitute extends TextFunction {
+public final class Substitute extends Var3or4ArgFunction {
 
-       protected ValueEval evaluateFunc(ValueEval[] args, int srcCellRow, int srcCellCol)
-                       throws EvaluationException {
-               if (args.length < 3 || args.length > 4) {
-                       return ErrorEval.VALUE_INVALID;
-               }
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+                       ValueEval arg2) {
+               String result;
+               try {
+                       String oldStr = TextFunction.evaluateStringArg(arg0, srcRowIndex, srcColumnIndex);
+                       String searchStr = TextFunction.evaluateStringArg(arg1, srcRowIndex, srcColumnIndex);
+                       String newStr = TextFunction.evaluateStringArg(arg2, srcRowIndex, srcColumnIndex);
 
-               String oldStr = evaluateStringArg(args[0], srcCellRow, srcCellCol);
-               String searchStr = evaluateStringArg(args[1], srcCellRow, srcCellCol);
-               String newStr = evaluateStringArg(args[2], srcCellRow, srcCellCol);
+                       result = replaceAllOccurrences(oldStr, searchStr, newStr);
+               } catch (EvaluationException e) {
+                       return e.getErrorEval();
+               }
+               return new StringEval(result);
+       }
 
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+                       ValueEval arg2, ValueEval arg3) {
                String result;
-               switch (args.length) {
-                       default:
-                               throw new IllegalStateException("Cannot happen");
-                       case 4:
-                               int instanceNumber = evaluateIntArg(args[3], srcCellRow, srcCellCol);
-                               if (instanceNumber < 1) {
-                                       return ErrorEval.VALUE_INVALID;
-                               }
-                               result = replaceOneOccurrence(oldStr, searchStr, newStr, instanceNumber);
-                               break;
-                       case 3:
-                               result = replaceAllOccurrences(oldStr, searchStr, newStr);
+               try {
+                       String oldStr = TextFunction.evaluateStringArg(arg0, srcRowIndex, srcColumnIndex);
+                       String searchStr = TextFunction.evaluateStringArg(arg1, srcRowIndex, srcColumnIndex);
+                       String newStr = TextFunction.evaluateStringArg(arg2, srcRowIndex, srcColumnIndex);
+
+                       int instanceNumber = TextFunction.evaluateIntArg(arg3, srcRowIndex, srcColumnIndex);
+                       if (instanceNumber < 1) {
+                               return ErrorEval.VALUE_INVALID;
+                       }
+                       result = replaceOneOccurrence(oldStr, searchStr, newStr, instanceNumber);
+               } catch (EvaluationException e) {
+                       return e.getErrorEval();
                }
                return new StringEval(result);
        }
index e62425986698d7a963df16b10c76e39d01044662..6b108f2f65b6469b755687e0ddc9d03cbc6a586b 100644 (file)
@@ -27,7 +27,7 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
 
 /**
  * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
+ * @author Josh Micich
  */
 public abstract class TextFunction implements Function {
 
@@ -54,17 +54,18 @@ public abstract class TextFunction implements Function {
 
        /* ---------------------------------------------------------------------- */
 
-       private static abstract class SingleArgTextFunc extends TextFunction {
+       private static abstract class SingleArgTextFunc extends Fixed1ArgFunction {
 
                protected SingleArgTextFunc() {
                        // no fields to initialise
                }
-               protected ValueEval evaluateFunc(ValueEval[] args, int srcCellRow, int srcCellCol)
-                               throws EvaluationException {
-                       if (args.length != 1) {
-                               return ErrorEval.VALUE_INVALID;
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
+                       String arg;
+                       try {
+                               arg = evaluateStringArg(arg0, srcRowIndex, srcColumnIndex);
+                       } catch (EvaluationException e) {
+                               return e.getErrorEval();
                        }
-                       String arg = evaluateStringArg(args[0], srcCellRow, srcCellCol);
                        return evaluate(arg);
                }
                protected abstract ValueEval evaluate(String arg);
@@ -107,17 +108,20 @@ public abstract class TextFunction implements Function {
         *
         * Author: Manda Wilson &lt; wilson at c bio dot msk cc dot org &gt;
         */
-       public static final Function MID = new TextFunction() {
+       public static final Function MID = new Fixed3ArgFunction() {
 
-               protected ValueEval evaluateFunc(ValueEval[] args, int srcCellRow, int srcCellCol)
-                               throws EvaluationException {
-                       if (args.length != 3) {
-                               return ErrorEval.VALUE_INVALID;
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0,
+                               ValueEval arg1, ValueEval arg2) {
+                       String text;
+                       int startCharNum;
+                       int numChars;
+                       try {
+                               text = evaluateStringArg(arg0, srcRowIndex, srcColumnIndex);
+                               startCharNum = evaluateIntArg(arg1, srcRowIndex, srcColumnIndex);
+                               numChars = evaluateIntArg(arg2, srcRowIndex, srcColumnIndex);
+                       } catch (EvaluationException e) {
+                               return e.getErrorEval();
                        }
-
-                       String text = evaluateStringArg(args[0], srcCellRow, srcCellCol);
-                       int startCharNum = evaluateIntArg(args[1], srcCellRow, srcCellCol);
-                       int numChars = evaluateIntArg(args[2], srcCellRow, srcCellCol);
                        int startIx = startCharNum - 1; // convert to zero-based
 
                        // Note - for start_num arg, blank/zero causes error(#VALUE!),
@@ -138,19 +142,25 @@ public abstract class TextFunction implements Function {
                }
        };
 
-       private static final class LeftRight extends TextFunction {
-
+       private static final class LeftRight extends Var1or2ArgFunction {
+               private static final ValueEval DEFAULT_ARG1 = new NumberEval(1.0);
                private final boolean _isLeft;
                protected LeftRight(boolean isLeft) {
                        _isLeft = isLeft;
                }
-               protected ValueEval evaluateFunc(ValueEval[] args, int srcCellRow, int srcCellCol)
-                               throws EvaluationException {
-                       if (args.length != 2) {
-                               return ErrorEval.VALUE_INVALID;
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
+                       return evaluate(srcRowIndex, srcColumnIndex, arg0, DEFAULT_ARG1);
+               }
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0,
+                               ValueEval arg1) {
+                       String arg;
+                       int index;
+                       try {
+                               arg = evaluateStringArg(arg0, srcRowIndex, srcColumnIndex);
+                               index = evaluateIntArg(arg1, srcRowIndex, srcColumnIndex);
+                       } catch (EvaluationException e) {
+                               return e.getErrorEval();
                        }
-                       String arg = evaluateStringArg(args[0], srcCellRow, srcCellCol);
-                       int index = evaluateIntArg(args[1], srcCellRow, srcCellCol);
 
                        String result;
                        if (_isLeft) {
@@ -165,28 +175,33 @@ public abstract class TextFunction implements Function {
        public static final Function LEFT = new LeftRight(true);
        public static final Function RIGHT = new LeftRight(false);
 
-       public static final Function CONCATENATE = new TextFunction() {
+       public static final Function CONCATENATE = new Function() {
 
-               protected ValueEval evaluateFunc(ValueEval[] args, int srcCellRow, int srcCellCol)
-                               throws EvaluationException {
-                       StringBuffer sb = new StringBuffer();
+               public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+                       StringBuilder sb = new StringBuilder();
                        for (int i=0, iSize=args.length; i<iSize; i++) {
-                               sb.append(evaluateStringArg(args[i], srcCellRow, srcCellCol));
+                               try {
+                                       sb.append(evaluateStringArg(args[i], srcRowIndex, srcColumnIndex));
+                               } catch (EvaluationException e) {
+                                       return e.getErrorEval();
+                               }
                        }
                        return new StringEval(sb.toString());
                }
        };
 
-       public static final Function EXACT = new TextFunction() {
+       public static final Function EXACT = new Fixed2ArgFunction() {
 
-               protected ValueEval evaluateFunc(ValueEval[] args, int srcCellRow, int srcCellCol)
-                               throws EvaluationException {
-                       if (args.length != 2) {
-                               return ErrorEval.VALUE_INVALID;
+               public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0,
+                               ValueEval arg1) {
+                       String s0;
+                       String s1;
+                       try {
+                               s0 = evaluateStringArg(arg0, srcRowIndex, srcColumnIndex);
+                               s1 = evaluateStringArg(arg1, srcRowIndex, srcColumnIndex);
+                       } catch (EvaluationException e) {
+                               return e.getErrorEval();
                        }
-
-                       String s0 = evaluateStringArg(args[0], srcCellRow, srcCellCol);
-                       String s1 = evaluateStringArg(args[1], srcCellRow, srcCellCol);
                        return BoolEval.valueOf(s0.equals(s1));
                }
        };
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/True.java b/src/java/org/apache/poi/hssf/record/formula/functions/True.java
deleted file mode 100644 (file)
index 968999b..0000000
+++ /dev/null
@@ -1,42 +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.functions;
-
-import org.apache.poi.hssf.record.formula.eval.BoolEval;
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-
-/**
- * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
- *
- */
-public final class True implements Function {
-
-    public ValueEval evaluate(ValueEval[] operands, int srcRow, int srcCol) {
-        ValueEval retval;
-        switch (operands.length) {
-        default:
-            retval = ErrorEval.VALUE_INVALID;
-            break;
-        case 0:
-            retval = BoolEval.TRUE;
-        }
-        return retval;
-    }
-
-}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Var1or2ArgFunction.java b/src/java/org/apache/poi/hssf/record/formula/functions/Var1or2ArgFunction.java
new file mode 100644 (file)
index 0000000..d7310c4
--- /dev/null
@@ -0,0 +1,40 @@
+/* ====================================================================
+   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.functions;
+
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
+/**
+ * Convenience base class for any function which must take two or three
+ * arguments
+ *
+ * @author Josh Micich
+ */
+abstract class Var1or2ArgFunction implements Function1Arg, Function2Arg {
+
+       public final ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+               switch (args.length) {
+                       case 1:
+                               return evaluate(srcRowIndex, srcColumnIndex, args[0]);
+                       case 2:
+                               return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1]);
+               }
+               return ErrorEval.VALUE_INVALID;
+       }
+}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Var3or4ArgFunction.java b/src/java/org/apache/poi/hssf/record/formula/functions/Var3or4ArgFunction.java
new file mode 100644 (file)
index 0000000..c3cf941
--- /dev/null
@@ -0,0 +1,40 @@
+/* ====================================================================
+   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.functions;
+
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+
+/**
+ * Convenience base class for any function which must take three or four
+ * arguments
+ *
+ * @author Josh Micich
+ */
+abstract class Var3or4ArgFunction implements Function3Arg, Function4Arg {
+
+       public final ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
+               switch (args.length) {
+                       case 3:
+                               return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2]);
+                       case 4:
+                               return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2], args[3]);
+               }
+               return ErrorEval.VALUE_INVALID;
+       }
+}
index 6c3ad929a62e16633312e667a144de2c70aa6282..ebd35caaf55a375d21826d6e18e8f8b40a5d8d7a 100644 (file)
@@ -18,7 +18,7 @@
 package org.apache.poi.hssf.record.formula.functions;
 
 import org.apache.poi.hssf.record.formula.eval.AreaEval;
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.BoolEval;
 import org.apache.poi.hssf.record.formula.eval.EvaluationException;
 import org.apache.poi.hssf.record.formula.eval.OperandResolver;
 import org.apache.poi.hssf.record.formula.eval.ValueEval;
@@ -39,27 +39,24 @@ import org.apache.poi.hssf.record.formula.functions.LookupUtils.ValueVector;
  *
  * @author Josh Micich
  */
-public final class Vlookup implements Function {
+public final class Vlookup extends Var3or4ArgFunction {
+       private static final ValueEval DEFAULT_ARG3 = BoolEval.TRUE;
 
-       public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
-               ValueEval arg3 = null;
-               switch(args.length) {
-                       case 4:
-                               arg3 = args[3]; // important: assumed array element is never null
-                       case 3:
-                               break;
-                       default:
-                               // wrong number of arguments
-                               return ErrorEval.VALUE_INVALID;
-               }
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+                       ValueEval arg2) {
+               return evaluate(srcRowIndex, srcColumnIndex, arg0, arg1, arg2, DEFAULT_ARG3);
+       }
+
+       public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
+                       ValueEval arg2, ValueEval arg3) {
                try {
                        // Evaluation order:
                        // arg0 lookup_value, arg1 table_array, arg3 range_lookup, find lookup value, arg2 col_index, fetch result
-                       ValueEval lookupValue = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
-                       AreaEval tableArray = LookupUtils.resolveTableArrayArg(args[1]);
-                       boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcCellRow, srcCellCol);
+                       ValueEval lookupValue = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
+                       AreaEval tableArray = LookupUtils.resolveTableArrayArg(arg1);
+                       boolean isRangeLookup = LookupUtils.resolveRangeLookupArg(arg3, srcRowIndex, srcColumnIndex);
                        int rowIndex = LookupUtils.lookupIndexOfValue(lookupValue, LookupUtils.createColumnVector(tableArray, 0), isRangeLookup);
-                       int colIndex = LookupUtils.resolveRowOrColIndexArg(args[2], srcCellRow, srcCellCol);
+                       int colIndex = LookupUtils.resolveRowOrColIndexArg(arg2, srcRowIndex, srcColumnIndex);
                        ValueVector resultCol = createResultColumnVector(tableArray, colIndex);
                        return resultCol.getItem(rowIndex);
                } catch (EvaluationException e) {
index 15d59c3a8831b318a40d89ec59bc363365ddb635..32bc460d0eac32fa7855bc9f08db437a7594e584 100644 (file)
@@ -37,7 +37,7 @@ import org.apache.poi.ss.util.CellReference.NameType;
  * @author Josh Micich
  */
 public final class OperationEvaluationContext {
-
+       public static final FreeRefFunction UDF = UserDefinedFunction.instance;
        private final EvaluationWorkbook _workbook;
        private final int _sheetIndex;
        private final int _rowIndex;