You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by jo...@apache.org on 2009/11/23 01:19:13 UTC

svn commit: r883197 - in /poi/trunk/src/java/org/apache/poi: hssf/record/formula/eval/ hssf/record/formula/functions/ ss/formula/

Author: josh
Date: Mon Nov 23 00:19:11 2009
New Revision: 883197

URL: http://svn.apache.org/viewvc?rev=883197&view=rev
Log:
updated remaining evaluator functions to implement fixed args interfaces

Added:
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Var1or2ArgFunction.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Var3or4ArgFunction.java
Removed:
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/And.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/False.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/IsError.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/IsNa.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Isblank.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Isref.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Not.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Or.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Pi.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Rand.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/True.java
Modified:
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/AggregateFunction.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/BooleanFunction.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Hyperlink.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Index.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/LogicalFunction.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Npv.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Substitute.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/TextFunction.java
    poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Vlookup.java
    poi/trunk/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java?rev=883197&r1=883196&r2=883197&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/eval/FunctionEval.java Mon Nov 23 00:19:11 2009
@@ -52,8 +52,8 @@
 
 		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 @@
 		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 @@
 		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 @@
 		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 @@
 
 		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 @@
 		retval[101] = new Hlookup();
 		retval[102] = new Vlookup();
 
-		retval[105] = new Isref();
+		retval[105] = LogicalFunction.ISREF;
 
 		retval[109] = NumericFunction.LOG;
 
@@ -134,9 +135,9 @@
 
 		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 @@
 		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;

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/AggregateFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/AggregateFunction.java?rev=883197&r1=883196&r2=883197&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/AggregateFunction.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/AggregateFunction.java Mon Nov 23 00:19:11 2009
@@ -19,13 +19,67 @@
 
 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 < amolweb at ya hoo dot com >
- *
  */
 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 @@
 			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 @@
 			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) {

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/BooleanFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/BooleanFunction.java?rev=883197&r1=883196&r2=883197&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/BooleanFunction.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/BooleanFunction.java Mon Nov 23 00:19:11 2009
@@ -101,4 +101,46 @@
 
 	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);
+		}
+	};
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java?rev=883197&r1=883196&r2=883197&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/FinanceFunction.java Mon Nov 23 00:19:11 2009
@@ -17,17 +17,58 @@
 
 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 {

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java?rev=883197&r1=883196&r2=883197&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Hlookup.java Mon Nov 23 00:19:11 2009
@@ -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 @@
  *
  * @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 @@
 		}
 	}
 
-
 	/**
 	 * Returns one column from an <tt>AreaEval</tt>
 	 *

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Hyperlink.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Hyperlink.java?rev=883197&r1=883196&r2=883197&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Hyperlink.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Hyperlink.java Mon Nov 23 00:19:11 2009
@@ -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 @@
  * <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;
 	}
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Index.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Index.java?rev=883197&r1=883196&r2=883197&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Index.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Index.java Mon Nov 23 00:19:11 2009
@@ -44,56 +44,71 @@
  *
  * @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

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/LogicalFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/LogicalFunction.java?rev=883197&r1=883196&r2=883197&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/LogicalFunction.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/LogicalFunction.java Mon Nov 23 00:19:11 2009
@@ -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 @@
 
 /**
  * @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 @@
 			// 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;
+		}
+	};
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java?rev=883197&r1=883196&r2=883197&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/LookupUtils.java Mon Nov 23 00:19:11 2009
@@ -379,17 +379,10 @@
 
 	/**
 	 * 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:

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Npv.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Npv.java?rev=883197&r1=883196&r2=883197&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Npv.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Npv.java Mon Nov 23 00:19:11 2009
@@ -17,7 +17,10 @@
 
 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 @@
  * 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;
 	}
-
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java?rev=883197&r1=883196&r2=883197&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/NumericFunction.java Mon Nov 23 00:19:11 2009
@@ -25,6 +25,7 @@
 
 /**
  * @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 @@
 	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 @@
 	/* -------------------------------------------------------------------------- */
 	// 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 @@
 		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 @@
 			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 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;
-			}
-			double base = ds[1];
-			if (base == Math.E) {
-				return logE;
+	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();
+			}
+			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());
 		}
 	};
 }

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Substitute.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Substitute.java?rev=883197&r1=883196&r2=883197&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Substitute.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Substitute.java Mon Nov 23 00:19:11 2009
@@ -27,31 +27,38 @@
  * 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);
 	}

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/TextFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/TextFunction.java?rev=883197&r1=883196&r2=883197&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/TextFunction.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/TextFunction.java Mon Nov 23 00:19:11 2009
@@ -27,7 +27,7 @@
 
 /**
  * @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 @@
 
 	/* ---------------------------------------------------------------------- */
 
-	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 @@
 	 *
 	 * 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 @@
 		}
 	};
 
-	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 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));
 		}
 	};

Added: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Var1or2ArgFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Var1or2ArgFunction.java?rev=883197&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Var1or2ArgFunction.java (added)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Var1or2ArgFunction.java Mon Nov 23 00:19:11 2009
@@ -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;
+	}
+}

Added: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Var3or4ArgFunction.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Var3or4ArgFunction.java?rev=883197&view=auto
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Var3or4ArgFunction.java (added)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Var3or4ArgFunction.java Mon Nov 23 00:19:11 2009
@@ -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;
+	}
+}

Modified: poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Vlookup.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Vlookup.java?rev=883197&r1=883196&r2=883197&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Vlookup.java (original)
+++ poi/trunk/src/java/org/apache/poi/hssf/record/formula/functions/Vlookup.java Mon Nov 23 00:19:11 2009
@@ -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 @@
  *
  * @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) {

Modified: poi/trunk/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java?rev=883197&r1=883196&r2=883197&view=diff
==============================================================================
--- poi/trunk/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java (original)
+++ poi/trunk/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java Mon Nov 23 00:19:11 2009
@@ -37,7 +37,7 @@
  * @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;



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org