added fixed arg function interfaces, converted some functions

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@883045 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2009-11-22 07:29:40 +00:00
parent a1d0ece524
commit b095f1d02a
37 changed files with 521 additions and 267 deletions

View File

@ -17,12 +17,13 @@
package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.functions.Fixed2ArgFunction;
import org.apache.poi.hssf.record.formula.functions.Function;
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
*/
public final class ConcatEval implements Function {
public final class ConcatEval extends Fixed2ArgFunction {
public static final Function instance = new ConcatEval();
@ -30,29 +31,30 @@ public final class ConcatEval implements Function {
// enforce singleton
}
public ValueEval evaluate(ValueEval[] args, int srcRow, int srcCol) {
if(args.length != 2) {
return ErrorEval.VALUE_INVALID;
}
StringBuffer sb = new StringBuffer();
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
ValueEval ve0;
ValueEval ve1;
try {
for (int i = 0; i < 2; i++) {
ValueEval ve = OperandResolver.getSingleValue(args[i], srcRow, srcCol);
if (ve instanceof StringValueEval) {
StringValueEval sve = (StringValueEval) ve;
sb.append(sve.getStringValue());
} else if (ve == BlankEval.INSTANCE) {
// do nothing
} else {
throw new RuntimeException("Unexpected value type ("
+ ve.getClass().getName() + ")");
}
}
ve0 = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
ve1 = OperandResolver.getSingleValue(arg1, srcRowIndex, srcColumnIndex);
} catch (EvaluationException e) {
return e.getErrorEval();
}
StringBuilder sb = new StringBuilder();
sb.append(getText(ve0));
sb.append(getText(ve1));
return new StringEval(sb.toString());
}
private Object getText(ValueEval ve) {
if (ve instanceof StringValueEval) {
StringValueEval sve = (StringValueEval) ve;
return sve.getStringValue();
}
if (ve == BlankEval.INSTANCE) {
return "";
}
throw new IllegalAccessError("Unexpected value type ("
+ ve.getClass().getName() + ")");
}
}

View File

@ -17,12 +17,13 @@
package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.functions.Fixed2ArgFunction;
import org.apache.poi.hssf.record.formula.functions.Function;
/**
* @author Josh Micich
*/
public final class IntersectionEval implements Function {
public final class IntersectionEval extends Fixed2ArgFunction {
public static final Function instance = new IntersectionEval();
@ -30,14 +31,11 @@ public final class IntersectionEval implements Function {
// enforces singleton
}
public ValueEval evaluate(ValueEval[] args, int srcRow, int srcCol) {
if(args.length != 2) {
return ErrorEval.VALUE_INVALID;
}
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
try {
AreaEval reA = evaluateRef(args[0]);
AreaEval reB = evaluateRef(args[1]);
AreaEval reA = evaluateRef(arg0);
AreaEval reB = evaluateRef(arg1);
AreaEval result = resolveRange(reA, reB);
if (result == null) {
return ErrorEval.NULL_INTERSECTION;

View File

@ -17,6 +17,7 @@
package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.functions.Fixed1ArgFunction;
import org.apache.poi.hssf.record.formula.functions.Function;
@ -24,7 +25,7 @@ import org.apache.poi.hssf.record.formula.functions.Function;
* Implementation of Excel formula token '%'. <p/>
* @author Josh Micich
*/
public final class PercentEval implements Function {
public final class PercentEval extends Fixed1ArgFunction {
public static final Function instance = new PercentEval();
@ -32,13 +33,10 @@ public final class PercentEval implements Function {
// enforce singleton
}
public ValueEval evaluate(ValueEval[] args, int srcRow, int srcCol) {
if (args.length != 1) {
return ErrorEval.VALUE_INVALID;
}
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
double d;
try {
ValueEval ve = OperandResolver.getSingleValue(args[0], srcRow, srcCol);
ValueEval ve = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
d = OperandResolver.coerceValueToDouble(ve);
} catch (EvaluationException e) {
return e.getErrorEval();

View File

@ -17,6 +17,7 @@
package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.functions.Fixed2ArgFunction;
import org.apache.poi.hssf.record.formula.functions.Function;
@ -24,7 +25,7 @@ import org.apache.poi.hssf.record.formula.functions.Function;
*
* @author Josh Micich
*/
public final class RangeEval implements Function {
public final class RangeEval extends Fixed2ArgFunction {
public static final Function instance = new RangeEval();
@ -32,14 +33,11 @@ public final class RangeEval implements Function {
// enforces singleton
}
public ValueEval evaluate(ValueEval[] args, int srcRow, int srcCol) {
if(args.length != 2) {
return ErrorEval.VALUE_INVALID;
}
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
try {
AreaEval reA = evaluateRef(args[0]);
AreaEval reB = evaluateRef(args[1]);
AreaEval reA = evaluateRef(arg0);
AreaEval reB = evaluateRef(arg1);
return resolveRange(reA, reB);
} catch (EvaluationException e) {
return e.getErrorEval();

View File

@ -17,6 +17,7 @@
package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.functions.Fixed2ArgFunction;
import org.apache.poi.hssf.record.formula.functions.Function;
import org.apache.poi.ss.util.NumberComparer;
@ -25,7 +26,7 @@ import org.apache.poi.ss.util.NumberComparer;
*
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*/
public abstract class RelationalOperationEval implements Function {
public abstract class RelationalOperationEval extends Fixed2ArgFunction {
/**
* Converts a standard compare result (-1, 0, 1) to <code>true</code> or <code>false</code>
@ -55,16 +56,13 @@ public abstract class RelationalOperationEval implements Function {
* Blank < Positive numbers
* </pre>
*/
public final ValueEval evaluate(ValueEval[] operands, int srcRow, int srcCol) {
if (operands.length != 2) {
return ErrorEval.VALUE_INVALID;
}
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
ValueEval vA;
ValueEval vB;
try {
vA = OperandResolver.getSingleValue(operands[0], srcRow, srcCol);
vB = OperandResolver.getSingleValue(operands[1], srcRow, srcCol);
vA = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
vB = OperandResolver.getSingleValue(arg1, srcRowIndex, srcColumnIndex);
} catch (EvaluationException e) {
return e.getErrorEval();
}

View File

@ -17,23 +17,23 @@
package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.functions.Fixed2ArgFunction;
import org.apache.poi.hssf.record.formula.functions.Function;
/**
* @author Josh Micich
*/
public abstract class TwoOperandNumericOperation implements Function {
public abstract class TwoOperandNumericOperation extends Fixed2ArgFunction {
protected final double singleOperandEvaluate(ValueEval arg, int srcCellRow, int srcCellCol) throws EvaluationException {
ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
return OperandResolver.coerceValueToDouble(ve);
}
public final ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
double result;
try {
double d0 = singleOperandEvaluate(args[0], srcCellRow, srcCellCol);
double d1 = singleOperandEvaluate(args[1], srcCellRow, srcCellCol);
double d0 = singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
double d1 = singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
result = evaluate(d0, d1);
if (result == 0.0) { // this '==' matches +0.0 and -0.0
// Excel converts -0.0 to +0.0 for '*', '/', '%', '+' and '^'
@ -49,6 +49,7 @@ public abstract class TwoOperandNumericOperation implements Function {
}
return new NumberEval(result);
}
protected abstract double evaluate(double d0, double d1) throws EvaluationException;
public static final Function AddEval = new TwoOperandNumericOperation() {

View File

@ -17,14 +17,13 @@
package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.functions.Fixed1ArgFunction;
import org.apache.poi.hssf.record.formula.functions.Function;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*/
public final class UnaryMinusEval implements Function {
public final class UnaryMinusEval extends Fixed1ArgFunction {
public static final Function instance = new UnaryMinusEval();
@ -32,13 +31,10 @@ public final class UnaryMinusEval implements Function {
// enforce singleton
}
public ValueEval evaluate(ValueEval[] args, int srcRow, int srcCol) {
if (args.length != 1) {
return ErrorEval.VALUE_INVALID;
}
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
double d;
try {
ValueEval ve = OperandResolver.getSingleValue(args[0], srcRow, srcCol);
ValueEval ve = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
d = OperandResolver.coerceValueToDouble(ve);
} catch (EvaluationException e) {
return e.getErrorEval();

View File

@ -17,14 +17,14 @@
package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.functions.Fixed1ArgFunction;
import org.apache.poi.hssf.record.formula.functions.Function;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*/
public final class UnaryPlusEval implements Function {
public final class UnaryPlusEval extends Fixed1ArgFunction {
public static final Function instance = new UnaryPlusEval();
@ -32,13 +32,10 @@ public final class UnaryPlusEval implements Function {
// enforce singleton
}
public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
if(args.length != 1) {
return ErrorEval.VALUE_INVALID;
}
public ValueEval evaluate(int srcCellRow, int srcCellCol, ValueEval arg0) {
double d;
try {
ValueEval ve = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
ValueEval ve = OperandResolver.getSingleValue(arg0, srcCellRow, srcCellCol);
if(ve instanceof StringEval) {
// Note - asymmetric with UnaryMinus
// -"hello" evaluates to #VALUE!

View File

@ -34,7 +34,7 @@ import org.apache.poi.hssf.usermodel.HSSFDateUtil;
*
* @author Guenter Kickinger g.kickinger@gmx.net
*/
public final class CalendarFieldFunction implements Function {
public final class CalendarFieldFunction extends Fixed1ArgFunction {
public static final Function YEAR = new CalendarFieldFunction(Calendar.YEAR, false);
public static final Function MONTH = new CalendarFieldFunction(Calendar.MONTH, true);
@ -48,14 +48,10 @@ public final class CalendarFieldFunction implements Function {
_needsOneBaseAdjustment = needsOneBaseAdjustment;
}
public ValueEval evaluate(ValueEval[] operands, int srcCellRow, int srcCellCol) {
if (operands.length != 1) {
return ErrorEval.VALUE_INVALID;
}
public final ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
int val;
try {
ValueEval ve = OperandResolver.getSingleValue(operands[0], srcCellRow, srcCellCol);
ValueEval ve = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
val = OperandResolver.coerceValueToInt(ve);
} catch (EvaluationException e) {
return e.getErrorEval();

View File

@ -23,39 +23,32 @@ import org.apache.poi.hssf.record.formula.eval.NumberEval;
import org.apache.poi.hssf.record.formula.eval.RefEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
public final class Column implements Function {
public ValueEval evaluate(ValueEval[] evals, int srcCellRow, int srcCellCol) {
ValueEval retval = null;
int cnum = -1;
public final class Column implements Function0Arg, Function1Arg {
switch (evals.length) {
default:
retval = ErrorEval.VALUE_INVALID;
case 1:
if (evals[0] instanceof AreaEval) {
AreaEval ae = (AreaEval) evals[0];
cnum = ae.getFirstColumn();
}
else if (evals[0] instanceof RefEval) {
RefEval re = (RefEval) evals[0];
cnum = re.getColumn();
}
else { // anything else is not valid argument
retval = ErrorEval.VALUE_INVALID;
}
break;
case 0:
cnum = srcCellCol;
}
if (retval == null) {
retval = (cnum >= 0)
? new NumberEval(cnum + 1) // +1 since excel colnums are 1 based
: (ValueEval) ErrorEval.VALUE_INVALID;
}
return retval;
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
return new NumberEval(srcColumnIndex+1);
}
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
int rnum;
if (arg0 instanceof AreaEval) {
rnum = ((AreaEval) arg0).getFirstColumn();
} else if (arg0 instanceof RefEval) {
rnum = ((RefEval) arg0).getColumn();
} else {
// anything else is not valid argument
return ErrorEval.VALUE_INVALID;
}
return new NumberEval(rnum + 1);
}
public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
switch (args.length) {
case 1:
return evaluate(srcRowIndex, srcColumnIndex, args[0]);
case 0:
return new NumberEval(srcColumnIndex+1);
}
return ErrorEval.VALUE_INVALID;
}
}

View File

@ -28,27 +28,14 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
*
* @author Josh Micich
*/
public final class Columns implements Function {
public final class Columns extends Fixed1ArgFunction {
public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
switch(args.length) {
case 1:
// expected
break;
case 0:
// too few arguments
return ErrorEval.VALUE_INVALID;
default:
// too many arguments
return ErrorEval.VALUE_INVALID;
}
ValueEval firstArg = args[0];
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
int result;
if (firstArg instanceof AreaEval) {
AreaEval ae = (AreaEval) firstArg;
result = ae.getLastColumn() - ae.getFirstColumn() + 1;
} else if (firstArg instanceof RefEval) {
if (arg0 instanceof AreaEval) {
result = ((AreaEval) arg0).getWidth();
} else if (arg0 instanceof RefEval) {
result = 1;
} else { // anything else is not valid argument
return ErrorEval.VALUE_INVALID;

View File

@ -19,7 +19,6 @@ 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.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.NumberEval;
import org.apache.poi.hssf.record.formula.eval.RefEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
@ -36,17 +35,11 @@ import org.apache.poi.hssf.record.formula.functions.CountUtils.I_MatchPredicate;
*
* @author Mads Mohr Christensen
*/
public final class Countblank implements Function {
public final class Countblank extends Fixed1ArgFunction {
public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
if (args.length != 1) {
// TODO - it doesn't seem to be possible to enter COUNTBLANK() into Excel with the wrong arg count
// perhaps this should be an exception
return ErrorEval.VALUE_INVALID;
}
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
double result;
ValueEval arg0 = args[0];
if (arg0 instanceof RefEval) {
result = CountUtils.countMatchingCell((RefEval) arg0, predicate);
} else if (arg0 instanceof AreaEval) {

View File

@ -44,7 +44,7 @@ import org.apache.poi.ss.usermodel.ErrorConstants;
*
* @author Josh Micich
*/
public final class Countif implements Function {
public final class Countif extends Fixed2ArgFunction {
private static final class CmpOp {
public static final int NONE = 0;
@ -400,23 +400,14 @@ public final class Countif implements Function {
}
}
public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
switch(args.length) {
case 2:
// expected
break;
default:
// TODO - it doesn't seem to be possible to enter COUNTIF() into Excel with the wrong arg count
// perhaps this should be an exception
return ErrorEval.VALUE_INVALID;
}
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
I_MatchPredicate mp = createCriteriaPredicate(args[1], srcRowIndex, srcColumnIndex);
I_MatchPredicate mp = createCriteriaPredicate(arg1, srcRowIndex, srcColumnIndex);
if(mp == null) {
// If the criteria arg is a reference to a blank cell, countif always returns zero.
return NumberEval.ZERO;
}
double result = countMatchingCellsInArea(args[0], mp);
double result = countMatchingCellsInArea(arg0, mp);
return new NumberEval(result);
}
/**

View File

@ -22,23 +22,37 @@ import java.util.GregorianCalendar;
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;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
/**
* @author Pavel Krupets (pkrupets at palmtreebusiness dot com)
*/
public final class DateFunc extends NumericFunction.MultiArg {
public final class DateFunc extends Fixed3ArgFunction {
public static final Function instance = new DateFunc();
private DateFunc() {
super(3,3);
// no fields to initialise
}
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
ValueEval arg2) {
double result;
try {
double d0 = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
double d1 = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
double d2 = NumericFunction.singleOperandEvaluate(arg2, srcRowIndex, srcColumnIndex);
result = evaluate(getYear(d0), (int) (d1 - 1), (int) d2);
NumericFunction.checkValue(result);
} catch (EvaluationException e) {
return e.getErrorEval();
}
return new NumberEval(result);
}
protected double evaluate(double[] ds) throws EvaluationException {
int year = getYear(ds[0]);
int month = (int) ds[1] - 1;
int day = (int) ds[2];
private static double evaluate(int year, int month, int day) throws EvaluationException {
if (year < 0 || month < 0 || day < 0) {
throw new EvaluationException(ErrorEval.VALUE_INVALID);

View File

@ -50,12 +50,12 @@ import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
*
* @author Josh Micich
*/
public final class Errortype implements Function {
public final class Errortype extends Fixed1ArgFunction {
public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
try {
OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
return ErrorEval.NA;
} catch (EvaluationException e) {
int result = translateErrorCodeToErrorTypeValue(e.getErrorEval().getErrorCode());

View File

@ -0,0 +1,35 @@
/* ====================================================================
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 functions that only take zero arguments.
*
* @author Josh Micich
*/
public abstract class Fixed0ArgFunction implements Function0Arg {
public final ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
if (args.length != 0) {
return ErrorEval.VALUE_INVALID;
}
return evaluate(srcRowIndex, srcColumnIndex);
}
}

View File

@ -0,0 +1,35 @@
/* ====================================================================
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 functions that must take exactly one argument.
*
* @author Josh Micich
*/
public abstract class Fixed1ArgFunction implements Function1Arg {
public final ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
if (args.length != 1) {
return ErrorEval.VALUE_INVALID;
}
return evaluate(srcRowIndex, srcColumnIndex, args[0]);
}
}

View File

@ -0,0 +1,35 @@
/* ====================================================================
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 functions that must take exactly two arguments.
*
* @author Josh Micich
*/
public abstract class Fixed2ArgFunction implements Function2Arg {
public final ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
if (args.length != 2) {
return ErrorEval.VALUE_INVALID;
}
return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1]);
}
}

View File

@ -0,0 +1,35 @@
/* ====================================================================
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 functions that must take exactly three arguments.
*
* @author Josh Micich
*/
public abstract class Fixed3ArgFunction implements Function3Arg {
public final ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
if (args.length != 3) {
return ErrorEval.VALUE_INVALID;
}
return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2]);
}
}

View File

@ -0,0 +1,35 @@
/* ====================================================================
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 functions that must take exactly four arguments.
*
* @author Josh Micich
*/
public abstract class Fixed4ArgFunction implements Function4Arg {
public final ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
if (args.length != 4) {
return ErrorEval.VALUE_INVALID;
}
return evaluate(srcRowIndex, srcColumnIndex, args[0], args[1], args[2], args[3]);
}
}

View File

@ -0,0 +1,32 @@
/* ====================================================================
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.ValueEval;
/**
* Implemented by all functions that can be called with zero arguments
*
* @author Josh Micich
*/
public interface Function0Arg extends Function {
/**
* see {@link Function#evaluate(ValueEval[], int, int)}
*/
ValueEval evaluate(int srcRowIndex, int srcColumnIndex);
}

View File

@ -0,0 +1,32 @@
/* ====================================================================
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.ValueEval;
/**
* Implemented by all functions that can be called with one argument
*
* @author Josh Micich
*/
public interface Function1Arg extends Function {
/**
* see {@link Function#evaluate(ValueEval[], int, int)}
*/
ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0);
}

View File

@ -0,0 +1,32 @@
/* ====================================================================
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.ValueEval;
/**
* Implemented by all functions that can be called with two arguments
*
* @author Josh Micich
*/
public interface Function2Arg extends Function {
/**
* see {@link Function#evaluate(ValueEval[], int, int)}
*/
ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1);
}

View File

@ -0,0 +1,32 @@
/* ====================================================================
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.ValueEval;
/**
* Implemented by all functions that can be called with three arguments
*
* @author Josh Micich
*/
public interface Function3Arg extends Function {
/**
* see {@link Function#evaluate(ValueEval[], int, int)}
*/
ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1, ValueEval arg2);
}

View File

@ -0,0 +1,32 @@
/* ====================================================================
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.ValueEval;
/**
* Implemented by all functions that can be called with four arguments
*
* @author Josh Micich
*/
public interface Function4Arg extends Function {
/**
* see {@link Function#evaluate(ValueEval[], int, int)}
*/
ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1, ValueEval arg2, ValueEval arg3);
}

View File

@ -25,10 +25,9 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
*
* @author Josh Micich
*/
public final class Na implements Function {
public final class Na extends Fixed0ArgFunction {
public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
public ValueEval evaluate(int srcCellRow, int srcCellCol) {
return ErrorEval.NA;
}
}

View File

@ -19,7 +19,6 @@ package org.apache.poi.hssf.record.formula.functions;
import java.util.Date;
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;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
@ -29,13 +28,9 @@ import org.apache.poi.hssf.usermodel.HSSFDateUtil;
*
* @author Frank Taffelt
*/
public final class Now implements Function {
public ValueEval evaluate(ValueEval[] evals, int srcCellRow, int srcCellCol) {
if (evals.length > 0) {
return ErrorEval.VALUE_INVALID;
}
public final class Now extends Fixed0ArgFunction {
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
Date now = new Date(System.currentTimeMillis());
return new NumberEval(HSSFDateUtil.getExcelDate(now));
}

View File

@ -39,7 +39,10 @@ public abstract class NumericFunction implements Function {
return result;
}
private static final void checkValue(double result) throws EvaluationException {
/**
* @throws EvaluationException (#NUM!) if <tt>result</tt> is <tt>NaN</> or <tt>Infinity</tt>
*/
static final void checkValue(double result) throws EvaluationException {
if (Double.isNaN(result) || Double.isInfinite(result)) {
throw new EvaluationException(ErrorEval.NUM_ERROR);
}

View File

@ -37,19 +37,24 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
*
* @author Manda Wilson &lt; wilson at c bio dot msk cc dot org &gt;
*/
public final class Replace extends TextFunction {
public final class Replace extends Fixed4ArgFunction {
protected ValueEval evaluateFunc(ValueEval[] args, int srcCellRow, int srcCellCol)
throws EvaluationException {
if (args.length != 4) {
return ErrorEval.VALUE_INVALID;
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
ValueEval arg2, ValueEval arg3) {
String oldStr;
int startNum;
int numChars;
String newStr;
try {
oldStr = TextFunction.evaluateStringArg(arg0, srcRowIndex, srcColumnIndex);
startNum = TextFunction.evaluateIntArg(arg1, srcRowIndex, srcColumnIndex);
numChars = TextFunction.evaluateIntArg(arg2, srcRowIndex, srcColumnIndex);
newStr = TextFunction.evaluateStringArg(arg3, srcRowIndex, srcColumnIndex);
} catch (EvaluationException e) {
return e.getErrorEval();
}
String oldStr = evaluateStringArg(args[0], srcCellRow, srcCellCol);
int startNum = evaluateIntArg(args[1], srcCellRow, srcCellCol);
int numChars = evaluateIntArg(args[2], srcCellRow, srcCellCol);
String newStr = evaluateStringArg(args[3], srcCellRow, srcCellCol);
if (startNum < 1 || numChars < 0) {
return ErrorEval.VALUE_INVALID;
}

View File

@ -23,39 +23,33 @@ import org.apache.poi.hssf.record.formula.eval.NumberEval;
import org.apache.poi.hssf.record.formula.eval.RefEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
public final class Row implements Function {
public final class Row implements Function0Arg, Function1Arg {
public ValueEval evaluate(ValueEval[] evals, int srcCellRow, int srcCellCol) {
ValueEval retval = null;
int rnum = -1;
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
return new NumberEval(srcRowIndex+1);
}
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
int rnum;
switch (evals.length) {
default:
retval = ErrorEval.VALUE_INVALID;
case 1:
if (evals[0] instanceof AreaEval) {
AreaEval ae = (AreaEval) evals[0];
rnum = ae.getFirstRow();
}
else if (evals[0] instanceof RefEval) {
RefEval re = (RefEval) evals[0];
rnum = re.getRow();
}
else { // anything else is not valid argument
retval = ErrorEval.VALUE_INVALID;
}
break;
case 0:
rnum = srcCellRow;
if (arg0 instanceof AreaEval) {
rnum = ((AreaEval) arg0).getFirstRow();
} else if (arg0 instanceof RefEval) {
rnum = ((RefEval) arg0).getRow();
} else {
// anything else is not valid argument
return ErrorEval.VALUE_INVALID;
}
if (retval == null) {
retval = (rnum >= 0)
? new NumberEval(rnum + 1) // +1 since excel rownums are 1 based
: (ValueEval) ErrorEval.VALUE_INVALID;
return new NumberEval(rnum + 1);
}
public ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
switch (args.length) {
case 1:
return evaluate(srcRowIndex, srcColumnIndex, args[0]);
case 0:
return new NumberEval(srcRowIndex+1);
}
return retval;
return ErrorEval.VALUE_INVALID;
}
}

View File

@ -28,27 +28,14 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
*
* @author Josh Micich
*/
public final class Rows implements Function {
public final class Rows extends Fixed1ArgFunction {
public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
switch(args.length) {
case 1:
// expected
break;
case 0:
// too few arguments
return ErrorEval.VALUE_INVALID;
default:
// too many arguments
return ErrorEval.VALUE_INVALID;
}
ValueEval firstArg = args[0];
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
int result;
if (firstArg instanceof AreaEval) {
AreaEval ae = (AreaEval) firstArg;
result = ae.getLastRow() - ae.getFirstRow() + 1;
} else if (firstArg instanceof RefEval) {
if (arg0 instanceof AreaEval) {
result = ((AreaEval) arg0).getHeight();
} else if (arg0 instanceof RefEval) {
result = 1;
} else { // anything else is not valid argument
return ErrorEval.VALUE_INVALID;

View File

@ -30,16 +30,10 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
* cause an empty string result. If the argument is an area, the first (top-left) cell is used
* (regardless of the coordinates of the evaluating formula cell).
*/
public final class T implements Function {
public final class T extends Fixed1ArgFunction {
public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
switch (args.length) {
default:
return ErrorEval.VALUE_INVALID;
case 1:
break;
}
ValueEval arg = args[0];
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
ValueEval arg = arg0;
if (arg instanceof RefEval) {
arg = ((RefEval) arg).getInnerValueEval();
} else if (arg instanceof AreaEval) {

View File

@ -29,7 +29,7 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
*
* Based on POI org.apache.hssf.record.formula.DateFunc.java
*/
public final class Time implements Function {
public final class Time extends Fixed3ArgFunction {
private static final int SECONDS_PER_MINUTE = 60;
private static final int SECONDS_PER_HOUR = 3600;
@ -37,25 +37,23 @@ public final class Time implements Function {
private static final int SECONDS_PER_DAY = HOURS_PER_DAY * SECONDS_PER_HOUR;
public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
if (args.length != 3) {
return ErrorEval.VALUE_INVALID;
}
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
ValueEval arg2) {
double result;
try {
result = evaluate(evalArg(args[0]), evalArg(args[1]), evalArg(args[2]));
result = evaluate(evalArg(arg0, srcRowIndex, srcColumnIndex), evalArg(arg1, srcRowIndex, srcColumnIndex), evalArg(arg2, srcRowIndex, srcColumnIndex));
} catch (EvaluationException e) {
return e.getErrorEval();
}
return new NumberEval(result);
}
private static int evalArg(ValueEval arg) throws EvaluationException {
private static int evalArg(ValueEval arg, int srcRowIndex, int srcColumnIndex) throws EvaluationException {
if (arg == MissingArgEval.instance) {
return 0;
}
ValueEval ev = OperandResolver.getSingleValue(arg, srcRowIndex, srcColumnIndex);
// Excel silently truncates double values to integers
return OperandResolver.coerceValueToInt(arg);
return OperandResolver.coerceValueToInt(ev);
}
/**
* Converts the supplied hours, minutes and seconds to an Excel time value.

View File

@ -20,7 +20,6 @@ package org.apache.poi.hssf.record.formula.functions;
import java.util.Calendar;
import java.util.GregorianCalendar;
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;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
@ -30,12 +29,9 @@ import org.apache.poi.hssf.usermodel.HSSFDateUtil;
*
* @author Frank Taffelt
*/
public final class Today implements Function {
public final class Today extends Fixed0ArgFunction {
public ValueEval evaluate(ValueEval[] evals, int srcCellRow, int srcCellCol) {
if (evals.length > 0) {
return ErrorEval.VALUE_INVALID;
}
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex) {
Calendar now = new GregorianCalendar();
now.set(now.get(Calendar.YEAR), now.get(Calendar.MONTH), now.get(Calendar.DATE),0,0,0);
@ -43,4 +39,3 @@ public final class Today implements Function {
return new NumberEval(HSSFDateUtil.getExcelDate(now.getTime()));
}
}

View File

@ -35,19 +35,16 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
*
* @author Josh Micich
*/
public final class Value implements Function {
public final class Value extends Fixed1ArgFunction {
/** "1,0000" is valid, "1,00" is not */
private static final int MIN_DISTANCE_BETWEEN_THOUSANDS_SEPARATOR = 4;
private static final Double ZERO = new Double(0.0);
public ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
if (args.length != 1) {
return ErrorEval.VALUE_INVALID;
}
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0) {
ValueEval veText;
try {
veText = OperandResolver.getSingleValue(args[0], srcCellRow, srcCellCol);
veText = OperandResolver.getSingleValue(arg0, srcRowIndex, srcColumnIndex);
} catch (EvaluationException e) {
return e.getErrorEval();
}

View File

@ -26,7 +26,7 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
*
* @author Josh Micich
*/
abstract class Var2or3ArgFunction implements Function {
abstract class Var2or3ArgFunction implements Function2Arg, Function3Arg {
public final ValueEval evaluate(ValueEval[] args, int srcRowIndex, int srcColumnIndex) {
switch (args.length) {
@ -37,10 +37,4 @@ abstract class Var2or3ArgFunction implements Function {
}
return ErrorEval.VALUE_INVALID;
}
public abstract ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0,
ValueEval arg1, ValueEval arg2);
public abstract ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0,
ValueEval arg1);
}

View File

@ -27,9 +27,8 @@ import org.apache.poi.hssf.record.formula.functions.LookupUtils.ValueVector;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*/
public abstract class XYNumericFunction implements Function {
public abstract class XYNumericFunction extends Fixed2ArgFunction {
private static abstract class ValueArray implements ValueVector {
private final int _size;
@ -96,15 +95,12 @@ public abstract class XYNumericFunction implements Function {
*/
protected abstract Accumulator createAccumulator();
public final ValueEval evaluate(ValueEval[] args, int srcCellRow, int srcCellCol) {
if (args.length != 2) {
return ErrorEval.VALUE_INVALID;
}
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1) {
double result;
try {
ValueVector vvX = createValueVector(args[0]);
ValueVector vvY = createValueVector(args[1]);
ValueVector vvX = createValueVector(arg0);
ValueVector vvY = createValueVector(arg1);
int size = vvX.getSize();
if (size == 0 || vvY.getSize() != size) {
return ErrorEval.NA;