changed interface from OperationEval to Function for basic operators

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@805971 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Josh Micich 2009-08-19 20:55:44 +00:00
parent 3316b64495
commit f226104c29
26 changed files with 236 additions and 505 deletions

View File

@ -1,45 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula.eval;
/**
* @author Amol S. Deshmukh < amolweb at ya hoo dot com >
* This is a documentation of the observed behaviour of
* the '+' operator in Excel:
* <ol>
* <li> 1+TRUE = 2
* <li> 1+FALSE = 1
* <li> 1+"true" = #VALUE!
* <li> 1+"1" = 2
* <li> 1+A1 = #VALUE if A1 contains "1"
* <li> 1+A1 = 2 if A1 contains ="1"
* <li> 1+A1 = 2 if A1 contains TRUE or =TRUE
* <li> 1+A1 = #VALUE! if A1 contains "TRUE" or ="TRUE"
*/
public final class AddEval extends TwoOperandNumericOperation {
public static final OperationEval instance = new AddEval();
private AddEval() {
}
protected double evaluate(double d0, double d1) {
return d0 + d1;
}
}

View File

@ -17,12 +17,14 @@
package org.apache.poi.hssf.record.formula.eval; package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.functions.Function;
/** /**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt; * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*/ */
public final class ConcatEval implements OperationEval { public final class ConcatEval implements Function {
public static final OperationEval instance = new ConcatEval(); public static final Function instance = new ConcatEval();
private ConcatEval() { private ConcatEval() {
// enforce singleton // enforce singleton
@ -53,8 +55,4 @@ public final class ConcatEval implements OperationEval {
return new StringEval(sb.toString()); return new StringEval(sb.toString());
} }
public int getNumberOfOperands() {
return 2;
}
} }

View File

@ -1,36 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula.eval;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*/
public final class DivideEval extends TwoOperandNumericOperation {
public static final OperationEval instance = new DivideEval();
private DivideEval() {
}
protected double evaluate(double d0, double d1) throws EvaluationException {
if (d1 == 0.0) {
throw new EvaluationException(ErrorEval.DIV_ZERO);
}
return d0 / d1;
}
}

View File

@ -1,34 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula.eval;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*/
public final class EqualEval extends RelationalOperationEval {
public static final OperationEval instance = new EqualEval();
private EqualEval() {
}
protected boolean convertComparisonResult(int cmpResult) {
return cmpResult == 0;
}
}

View File

@ -1,34 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula.eval;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*/
public final class GreaterEqualEval extends RelationalOperationEval {
public static final OperationEval instance = new GreaterEqualEval();
private GreaterEqualEval() {
}
protected boolean convertComparisonResult(int cmpResult) {
return cmpResult >= 0;
}
}

View File

@ -1,34 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula.eval;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*/
public final class GreaterThanEval extends RelationalOperationEval {
public static final OperationEval instance = new GreaterThanEval();
private GreaterThanEval() {
}
protected boolean convertComparisonResult(int cmpResult) {
return cmpResult > 0;
}
}

View File

@ -1,34 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula.eval;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*/
public final class LessEqualEval extends RelationalOperationEval {
public static final OperationEval instance = new LessEqualEval();
private LessEqualEval() {
}
protected boolean convertComparisonResult(int cmpResult) {
return cmpResult <= 0;
}
}

View File

@ -1,34 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula.eval;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*/
public final class LessThanEval extends RelationalOperationEval {
public static final OperationEval instance = new LessThanEval();
private LessThanEval() {
}
protected boolean convertComparisonResult(int cmpResult) {
return cmpResult < 0;
}
}

View File

@ -1,33 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula.eval;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*/
public final class MultiplyEval extends TwoOperandNumericOperation {
public static final OperationEval instance = new MultiplyEval();
private MultiplyEval() {
}
protected double evaluate(double d0, double d1) {
return d0 * d1;
}
}

View File

@ -1,34 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula.eval;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*
*/
public final class NotEqualEval extends RelationalOperationEval {
public static final OperationEval instance = new NotEqualEval();
private NotEqualEval() {
}
protected boolean convertComparisonResult(int cmpResult) {
return cmpResult != 0;
}
}

View File

@ -40,7 +40,7 @@ public final class OperandResolver {
* an AreaEval. If the actual value retrieved is an ErrorEval, a corresponding * an AreaEval. If the actual value retrieved is an ErrorEval, a corresponding
* EvaluationException is thrown. * EvaluationException is thrown.
*/ */
public static ValueEval getSingleValue(ValueEval arg, int srcCellRow, short srcCellCol) public static ValueEval getSingleValue(ValueEval arg, int srcCellRow, int srcCellCol)
throws EvaluationException { throws EvaluationException {
ValueEval result; ValueEval result;
if (arg instanceof RefEval) { if (arg instanceof RefEval) {
@ -101,8 +101,8 @@ public final class OperandResolver {
* evaluated cell has an error. * evaluated cell has an error.
*/ */
public static ValueEval chooseSingleElementFromArea(AreaEval ae, public static ValueEval chooseSingleElementFromArea(AreaEval ae,
int srcCellRow, short srcCellCol) throws EvaluationException { int srcCellRow, int srcCellCol) throws EvaluationException {
ValueEval result = chooseSingleElementFromAreaInternal(ae, srcCellRow, srcCellCol); ValueEval result = chooseSingleElementFromAreaInternal(ae, srcCellRow, (short) srcCellCol);
if(result == null) { if(result == null) {
// This seems to be required because AreaEval.values() array may contain nulls. // This seems to be required because AreaEval.values() array may contain nulls.
// perhaps that should not be allowed. // perhaps that should not be allowed.

View File

@ -17,14 +17,16 @@
package org.apache.poi.hssf.record.formula.eval; package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.functions.Function;
/** /**
* Implementation of Excel formula token '%'. <p/> * Implementation of Excel formula token '%'. <p/>
* @author Josh Micich * @author Josh Micich
*/ */
public final class PercentEval implements OperationEval { public final class PercentEval implements Function {
public static final OperationEval instance = new PercentEval(); public static final Function instance = new PercentEval();
private PercentEval() { private PercentEval() {
// enforce singleton // enforce singleton
@ -46,8 +48,4 @@ public final class PercentEval implements OperationEval {
} }
return new NumberEval(d / 100); return new NumberEval(d / 100);
} }
public int getNumberOfOperands() {
return 1;
}
} }

View File

@ -1,33 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula.eval;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*/
public final class PowerEval extends TwoOperandNumericOperation {
public static final OperationEval instance = new PowerEval();
private PowerEval() {
}
protected double evaluate(double d0, double d1) {
return Math.pow(d0, d1);
}
}

View File

@ -17,20 +17,22 @@
package org.apache.poi.hssf.record.formula.eval; package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.functions.Function;
/** /**
* *
* @author Josh Micich * @author Josh Micich
*/ */
public final class RangeEval implements OperationEval { public final class RangeEval implements Function {
public static final OperationEval instance = new RangeEval(); public static final Function instance = new RangeEval();
private RangeEval() { private RangeEval() {
// enforces singleton // enforces singleton
} }
public ValueEval evaluate(ValueEval[] args, int srcCellRow, short srcCellCol) { public ValueEval evaluate(ValueEval[] args, int srcRow, short srcCol) {
if(args.length != 2) { if(args.length != 2) {
return ErrorEval.VALUE_INVALID; return ErrorEval.VALUE_INVALID;
} }
@ -72,8 +74,4 @@ public final class RangeEval implements OperationEval {
} }
throw new IllegalArgumentException("Unexpected ref arg class (" + arg.getClass().getName() + ")"); throw new IllegalArgumentException("Unexpected ref arg class (" + arg.getClass().getName() + ")");
} }
public int getNumberOfOperands() {
return 2;
}
} }

View File

@ -17,6 +17,7 @@
package org.apache.poi.hssf.record.formula.eval; package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.functions.Function;
import org.apache.poi.ss.util.NumberComparer; import org.apache.poi.ss.util.NumberComparer;
/** /**
@ -24,7 +25,7 @@ import org.apache.poi.ss.util.NumberComparer;
* *
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt; * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*/ */
public abstract class RelationalOperationEval implements OperationEval { public abstract class RelationalOperationEval implements Function {
/** /**
* Converts a standard compare result (-1, 0, 1) to <code>true</code> or <code>false</code> * Converts a standard compare result (-1, 0, 1) to <code>true</code> or <code>false</code>
@ -136,7 +137,34 @@ public abstract class RelationalOperationEval implements OperationEval {
throw new IllegalArgumentException("bad value class (" + v.getClass().getName() + ")"); throw new IllegalArgumentException("bad value class (" + v.getClass().getName() + ")");
} }
public final int getNumberOfOperands() { public static final Function EqualEval = new RelationalOperationEval() {
return 2; protected boolean convertComparisonResult(int cmpResult) {
return cmpResult == 0;
} }
};
public static final Function GreaterEqualEval = new RelationalOperationEval() {
protected boolean convertComparisonResult(int cmpResult) {
return cmpResult >= 0;
}
};
public static final Function GreaterThanEval = new RelationalOperationEval() {
protected boolean convertComparisonResult(int cmpResult) {
return cmpResult > 0;
}
};
public static final Function LessEqualEval = new RelationalOperationEval() {
protected boolean convertComparisonResult(int cmpResult) {
return cmpResult <= 0;
}
};
public static final Function LessThanEval = new RelationalOperationEval() {
protected boolean convertComparisonResult(int cmpResult) {
return cmpResult < 0;
}
};
public static final Function NotEqualEval = new RelationalOperationEval() {
protected boolean convertComparisonResult(int cmpResult) {
return cmpResult != 0;
}
};
} }

View File

@ -1,33 +0,0 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula.eval;
/**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
*/
public final class SubtractEval extends TwoOperandNumericOperation {
public static final OperationEval instance = new SubtractEval();
private SubtractEval() {
}
protected double evaluate(double d0, double d1) {
return d0 - d1;
}
}

View File

@ -17,12 +17,14 @@
package org.apache.poi.hssf.record.formula.eval; package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.functions.Function;
/** /**
* @author Josh Micich * @author Josh Micich
*/ */
abstract class TwoOperandNumericOperation implements OperationEval { public abstract class TwoOperandNumericOperation implements Function {
protected final double singleOperandEvaluate(ValueEval arg, int srcCellRow, short srcCellCol) throws EvaluationException { protected final double singleOperandEvaluate(ValueEval arg, int srcCellRow, int srcCellCol) throws EvaluationException {
ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol); ValueEval ve = OperandResolver.getSingleValue(arg, srcCellRow, srcCellCol);
return OperandResolver.coerceValueToDouble(ve); return OperandResolver.coerceValueToDouble(ve);
} }
@ -35,7 +37,7 @@ abstract class TwoOperandNumericOperation implements OperationEval {
result = evaluate(d0, d1); result = evaluate(d0, d1);
if (result == 0.0) { // this '==' matches +0.0 and -0.0 if (result == 0.0) { // this '==' matches +0.0 and -0.0
// Excel converts -0.0 to +0.0 for '*', '/', '%', '+' and '^' // Excel converts -0.0 to +0.0 for '*', '/', '%', '+' and '^'
if (!(this instanceof SubtractEval)) { if (!(this instanceof SubtractEvalClass)) {
return NumberEval.ZERO; return NumberEval.ZERO;
} }
} }
@ -48,7 +50,37 @@ abstract class TwoOperandNumericOperation implements OperationEval {
return new NumberEval(result); return new NumberEval(result);
} }
protected abstract double evaluate(double d0, double d1) throws EvaluationException; protected abstract double evaluate(double d0, double d1) throws EvaluationException;
public final int getNumberOfOperands() {
return 2; public static final Function AddEval = new TwoOperandNumericOperation() {
protected double evaluate(double d0, double d1) {
return d0+d1;
}
};
public static final Function DivideEval = new TwoOperandNumericOperation() {
protected double evaluate(double d0, double d1) throws EvaluationException {
if (d1 == 0.0) {
throw new EvaluationException(ErrorEval.DIV_ZERO);
}
return d0/d1;
}
};
public static final Function MultiplyEval = new TwoOperandNumericOperation() {
protected double evaluate(double d0, double d1) {
return d0*d1;
}
};
public static final Function PowerEval = new TwoOperandNumericOperation() {
protected double evaluate(double d0, double d1) {
return Math.pow(d0, d1);
}
};
private static final class SubtractEvalClass extends TwoOperandNumericOperation {
public SubtractEvalClass() {
//
}
protected double evaluate(double d0, double d1) {
return d0-d1;
} }
} }
public static final Function SubtractEval = new SubtractEvalClass();
}

View File

@ -17,14 +17,16 @@
package org.apache.poi.hssf.record.formula.eval; package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.functions.Function;
/** /**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt; * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
* *
*/ */
public final class UnaryMinusEval implements OperationEval { public final class UnaryMinusEval implements Function {
public static final OperationEval instance = new UnaryMinusEval(); public static final Function instance = new UnaryMinusEval();
private UnaryMinusEval() { private UnaryMinusEval() {
// enforce singleton // enforce singleton
@ -46,8 +48,4 @@ public final class UnaryMinusEval implements OperationEval {
} }
return new NumberEval(-d); return new NumberEval(-d);
} }
public int getNumberOfOperands() {
return 1;
}
} }

View File

@ -17,14 +17,16 @@
package org.apache.poi.hssf.record.formula.eval; package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.functions.Function;
/** /**
* @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt; * @author Amol S. Deshmukh &lt; amolweb at ya hoo dot com &gt;
* *
*/ */
public final class UnaryPlusEval implements OperationEval { public final class UnaryPlusEval implements Function {
public static final OperationEval instance = new UnaryPlusEval(); public static final Function instance = new UnaryPlusEval();
private UnaryPlusEval() { private UnaryPlusEval() {
// enforce singleton // enforce singleton
@ -49,8 +51,4 @@ public final class UnaryPlusEval implements OperationEval {
} }
return new NumberEval(+d); return new NumberEval(+d);
} }
public int getNumberOfOperands() {
return 1;
}
} }

View File

@ -39,24 +39,17 @@ import org.apache.poi.hssf.record.formula.RangePtg;
import org.apache.poi.hssf.record.formula.SubtractPtg; import org.apache.poi.hssf.record.formula.SubtractPtg;
import org.apache.poi.hssf.record.formula.UnaryMinusPtg; import org.apache.poi.hssf.record.formula.UnaryMinusPtg;
import org.apache.poi.hssf.record.formula.UnaryPlusPtg; import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
import org.apache.poi.hssf.record.formula.eval.AddEval;
import org.apache.poi.hssf.record.formula.eval.ConcatEval; import org.apache.poi.hssf.record.formula.eval.ConcatEval;
import org.apache.poi.hssf.record.formula.eval.DivideEval;
import org.apache.poi.hssf.record.formula.eval.EqualEval;
import org.apache.poi.hssf.record.formula.eval.FunctionEval; import org.apache.poi.hssf.record.formula.eval.FunctionEval;
import org.apache.poi.hssf.record.formula.eval.GreaterEqualEval;
import org.apache.poi.hssf.record.formula.eval.GreaterThanEval;
import org.apache.poi.hssf.record.formula.eval.LessEqualEval;
import org.apache.poi.hssf.record.formula.eval.LessThanEval;
import org.apache.poi.hssf.record.formula.eval.MultiplyEval;
import org.apache.poi.hssf.record.formula.eval.NotEqualEval;
import org.apache.poi.hssf.record.formula.eval.OperationEval; import org.apache.poi.hssf.record.formula.eval.OperationEval;
import org.apache.poi.hssf.record.formula.eval.PercentEval; import org.apache.poi.hssf.record.formula.eval.PercentEval;
import org.apache.poi.hssf.record.formula.eval.PowerEval;
import org.apache.poi.hssf.record.formula.eval.RangeEval; import org.apache.poi.hssf.record.formula.eval.RangeEval;
import org.apache.poi.hssf.record.formula.eval.SubtractEval; import org.apache.poi.hssf.record.formula.eval.RelationalOperationEval;
import org.apache.poi.hssf.record.formula.eval.TwoOperandNumericOperation;
import org.apache.poi.hssf.record.formula.eval.UnaryMinusEval; import org.apache.poi.hssf.record.formula.eval.UnaryMinusEval;
import org.apache.poi.hssf.record.formula.eval.UnaryPlusEval; import org.apache.poi.hssf.record.formula.eval.UnaryPlusEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
import org.apache.poi.hssf.record.formula.functions.Function;
/** /**
* This class creates <tt>OperationEval</tt> instances to help evaluate <tt>OperationPtg</tt> * This class creates <tt>OperationEval</tt> instances to help evaluate <tt>OperationPtg</tt>
@ -74,28 +67,54 @@ final class OperationEvaluatorFactory {
private static Map<Class<? extends Ptg>, OperationEval> initialiseInstancesMap() { private static Map<Class<? extends Ptg>, OperationEval> initialiseInstancesMap() {
Map<Class<? extends Ptg>, OperationEval> m = new HashMap<Class<? extends Ptg>, OperationEval>(32); Map<Class<? extends Ptg>, OperationEval> m = new HashMap<Class<? extends Ptg>, OperationEval>(32);
m.put(EqualPtg.class, EqualEval.instance);
m.put(EqualPtg.class, EqualEval.instance); put(m, 2, EqualPtg.class, RelationalOperationEval.EqualEval);
m.put(GreaterEqualPtg.class, GreaterEqualEval.instance); put(m, 2, GreaterEqualPtg.class, RelationalOperationEval.GreaterEqualEval);
m.put(GreaterThanPtg.class, GreaterThanEval.instance); put(m, 2, GreaterThanPtg.class, RelationalOperationEval.GreaterThanEval);
m.put(LessEqualPtg.class, LessEqualEval.instance); put(m, 2, LessEqualPtg.class, RelationalOperationEval.LessEqualEval);
m.put(LessThanPtg.class, LessThanEval.instance); put(m, 2, LessThanPtg.class, RelationalOperationEval.LessThanEval);
m.put(NotEqualPtg.class, NotEqualEval.instance); put(m, 2, NotEqualPtg.class, RelationalOperationEval.NotEqualEval);
m.put(ConcatPtg.class, ConcatEval.instance); put(m, 2, ConcatPtg.class, ConcatEval.instance);
m.put(AddPtg.class, AddEval.instance); put(m, 2, AddPtg.class, TwoOperandNumericOperation.AddEval);
m.put(DividePtg.class, DivideEval.instance); put(m, 2, DividePtg.class, TwoOperandNumericOperation.DivideEval);
m.put(MultiplyPtg.class, MultiplyEval.instance); put(m, 2, MultiplyPtg.class, TwoOperandNumericOperation.MultiplyEval);
m.put(PercentPtg.class, PercentEval.instance); put(m, 1, PercentPtg.class, PercentEval.instance);
m.put(PowerPtg.class, PowerEval.instance); put(m, 2, PowerPtg.class, TwoOperandNumericOperation.PowerEval);
m.put(SubtractPtg.class, SubtractEval.instance); put(m, 2, SubtractPtg.class, TwoOperandNumericOperation.SubtractEval);
m.put(UnaryMinusPtg.class, UnaryMinusEval.instance); put(m, 1, UnaryMinusPtg.class, UnaryMinusEval.instance);
m.put(UnaryPlusPtg.class, UnaryPlusEval.instance); put(m, 1, UnaryPlusPtg.class, UnaryPlusEval.instance);
m.put(RangePtg.class, RangeEval.instance); put(m, 2, RangePtg.class, RangeEval.instance);
return m; return m;
} }
private static void put(Map<Class<? extends Ptg>, OperationEval> m, int argCount,
Class<? extends Ptg> ptgClass, Function instance) {
m.put(ptgClass, new OperationFunctionEval(instance, argCount));
}
/**
* Simple adapter from {@link OperationEval} to {@link Function}
*/
private static final class OperationFunctionEval implements OperationEval {
private final Function _function;
private final int _numberOfOperands;
public OperationFunctionEval(Function function, int argCount) {
_function = function;
_numberOfOperands = argCount;
}
public ValueEval evaluate(ValueEval[] args, int rowIndex, short columnIndex) {
return _function.evaluate(args, rowIndex, columnIndex);
}
public int getNumberOfOperands() {
return _numberOfOperands;
}
}
/** /**
* returns the OperationEval concrete impl instance corresponding * returns the OperationEval concrete impl instance corresponding
* to the supplied operationPtg * to the supplied operationPtg

View File

@ -0,0 +1,53 @@
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.functions.Function;
/**
* Collects eval instances for easy access by tests in this package
*
* @author Josh Micich
*/
final class EvalInstances {
private EvalInstances() {
// no instances of this class
}
public static final Function Add = TwoOperandNumericOperation.AddEval;
public static final Function Subtract = TwoOperandNumericOperation.SubtractEval;
public static final Function Multiply = TwoOperandNumericOperation.MultiplyEval;
public static final Function Divide = TwoOperandNumericOperation.DivideEval;
public static final Function Power = TwoOperandNumericOperation.PowerEval;
public static final Function Percent = PercentEval.instance;
public static final Function UnaryMinus = UnaryMinusEval.instance;
public static final Function UnaryPlus = UnaryPlusEval.instance;
public static final Function Equal = RelationalOperationEval.EqualEval;
public static final Function LessThan = RelationalOperationEval.LessThanEval;
public static final Function LessEqual = RelationalOperationEval.LessEqualEval;
public static final Function GreaterThan = RelationalOperationEval.GreaterThanEval;
public static final Function GreaterEqual = RelationalOperationEval.GreaterEqualEval;
public static final Function NotEqual = RelationalOperationEval.NotEqualEval;
public static final Function Range = RangeEval.instance;
public static final Function Concat = ConcatEval.instance;
}

View File

@ -34,7 +34,7 @@ public final class TestDivideEval extends TestCase {
arg0, arg1, arg0, arg1,
}; };
double result = NumericFunctionInvoker.invoke(DivideEval.instance, args, 0, 0); double result = NumericFunctionInvoker.invoke(EvalInstances.Divide, args, 0, 0);
assertEquals(expectedResult, result, 0); assertEquals(expectedResult, result, 0);
} }
@ -56,7 +56,7 @@ public final class TestDivideEval extends TestCase {
ValueEval[] args = { ValueEval[] args = {
new NumberEval(5), NumberEval.ZERO, new NumberEval(5), NumberEval.ZERO,
}; };
ValueEval result = DivideEval.instance.evaluate(args, 0, (short) 0); ValueEval result = EvalInstances.Divide.evaluate(args, 0, (short) 0);
assertEquals(ErrorEval.DIV_ZERO, result); assertEquals(ErrorEval.DIV_ZERO, result);
} }
} }

View File

@ -21,6 +21,7 @@ import junit.framework.AssertionFailedError;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.hssf.record.formula.functions.EvalFactory; import org.apache.poi.hssf.record.formula.functions.EvalFactory;
import org.apache.poi.hssf.record.formula.functions.Function;
/** /**
* Test for {@link EqualEval} * Test for {@link EqualEval}
@ -28,6 +29,8 @@ import org.apache.poi.hssf.record.formula.functions.EvalFactory;
* @author Josh Micich * @author Josh Micich
*/ */
public final class TestEqualEval extends TestCase { public final class TestEqualEval extends TestCase {
// convenient access to namepace
private static final EvalInstances EI = null;
/** /**
* Test for bug observable at svn revision 692218 (Sep 2008)<br/> * Test for bug observable at svn revision 692218 (Sep 2008)<br/>
@ -40,7 +43,7 @@ public final class TestEqualEval extends TestCase {
EvalFactory.createAreaEval("B1:B1", values), EvalFactory.createAreaEval("B1:B1", values),
BoolEval.FALSE, BoolEval.FALSE,
}; };
ValueEval result = EqualEval.instance.evaluate(args, 10, (short)20); ValueEval result = evaluate(EI.Equal, args, 10, 10);
if (result instanceof ErrorEval) { if (result instanceof ErrorEval) {
if (result == ErrorEval.VALUE_INVALID) { if (result == ErrorEval.VALUE_INVALID) {
throw new AssertionFailedError("Identified bug in evaluation of 1x1 area"); throw new AssertionFailedError("Identified bug in evaluation of 1x1 area");
@ -58,7 +61,7 @@ public final class TestEqualEval extends TestCase {
new StringEval(""), new StringEval(""),
BlankEval.INSTANCE, BlankEval.INSTANCE,
}; };
ValueEval result = EqualEval.instance.evaluate(args, 10, (short)20); ValueEval result = evaluate(EI.Equal, args, 10, 10);
assertEquals(BoolEval.class, result.getClass()); assertEquals(BoolEval.class, result.getClass());
BoolEval be = (BoolEval) result; BoolEval be = (BoolEval) result;
if (!be.getBooleanValue()) { if (!be.getBooleanValue()) {
@ -71,17 +74,17 @@ public final class TestEqualEval extends TestCase {
* Test for bug 46613 (observable at svn r737248) * Test for bug 46613 (observable at svn r737248)
*/ */
public void testStringInsensitive_bug46613() { public void testStringInsensitive_bug46613() {
if (!evalStringCmp("abc", "aBc", EqualEval.instance)) { if (!evalStringCmp("abc", "aBc", EI.Equal)) {
throw new AssertionFailedError("Identified bug 46613"); throw new AssertionFailedError("Identified bug 46613");
} }
assertTrue(evalStringCmp("abc", "aBc", EqualEval.instance)); assertTrue(evalStringCmp("abc", "aBc", EI.Equal));
assertTrue(evalStringCmp("ABC", "azz", LessThanEval.instance)); assertTrue(evalStringCmp("ABC", "azz", EI.LessThan));
assertTrue(evalStringCmp("abc", "AZZ", LessThanEval.instance)); assertTrue(evalStringCmp("abc", "AZZ", EI.LessThan));
assertTrue(evalStringCmp("ABC", "aaa", GreaterThanEval.instance)); assertTrue(evalStringCmp("ABC", "aaa", EI.GreaterThan));
assertTrue(evalStringCmp("abc", "AAA", GreaterThanEval.instance)); assertTrue(evalStringCmp("abc", "AAA", EI.GreaterThan));
} }
private static boolean evalStringCmp(String a, String b, OperationEval cmpOp) { private static boolean evalStringCmp(String a, String b, Function cmpOp) {
ValueEval[] args = { ValueEval[] args = {
new StringEval(a), new StringEval(a),
new StringEval(b), new StringEval(b),
@ -103,13 +106,12 @@ public final class TestEqualEval extends TestCase {
*/ */
public void testZeroEquality_bug47198() { public void testZeroEquality_bug47198() {
NumberEval zero = new NumberEval(0.0); NumberEval zero = new NumberEval(0.0);
NumberEval mZero = (NumberEval) UnaryMinusEval.instance.evaluate(new ValueEval[] { zero, }, 0, NumberEval mZero = (NumberEval) evaluate(UnaryMinusEval.instance, new ValueEval[] { zero, }, 0, 0);
(short) 0);
if (Double.doubleToLongBits(mZero.getNumberValue()) == 0x8000000000000000L) { if (Double.doubleToLongBits(mZero.getNumberValue()) == 0x8000000000000000L) {
throw new AssertionFailedError("Identified bug 47198: unary minus should convert -0.0 to 0.0"); throw new AssertionFailedError("Identified bug 47198: unary minus should convert -0.0 to 0.0");
} }
ValueEval[] args = { zero, mZero, }; ValueEval[] args = { zero, mZero, };
BoolEval result = (BoolEval) EqualEval.instance.evaluate(args, 0, (short) 0); BoolEval result = (BoolEval) evaluate(EI.Equal, args, 0, 0);
if (!result.getBooleanValue()) { if (!result.getBooleanValue()) {
throw new AssertionFailedError("Identified bug 47198: -0.0 != 0.0"); throw new AssertionFailedError("Identified bug 47198: -0.0 != 0.0");
} }
@ -124,9 +126,13 @@ public final class TestEqualEval extends TestCase {
assertEquals("1.0055", b.getStringValue()); assertEquals("1.0055", b.getStringValue());
ValueEval[] args = { a, b, }; ValueEval[] args = { a, b, };
BoolEval result = (BoolEval) EqualEval.instance.evaluate(args, 0, (short) 0); BoolEval result = (BoolEval) evaluate(EI.Equal, args, 0, 0);
if (!result.getBooleanValue()) { if (!result.getBooleanValue()) {
throw new AssertionFailedError("Identified bug 47598: 1+1.0028-0.9973 != 1.0055"); throw new AssertionFailedError("Identified bug 47598: 1+1.0028-0.9973 != 1.0055");
} }
} }
private static ValueEval evaluate(Function oper, ValueEval[] args, int srcRowIx, int srcColIx) {
return oper.evaluate(args, srcRowIx, (short) srcColIx);
}
} }

View File

@ -20,6 +20,7 @@ package org.apache.poi.hssf.record.formula.eval;
import junit.framework.ComparisonFailure; import junit.framework.ComparisonFailure;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.apache.poi.hssf.record.formula.functions.Function;
import org.apache.poi.util.HexDump; import org.apache.poi.util.HexDump;
/** /**
@ -39,6 +40,8 @@ import org.apache.poi.util.HexDump;
public final class TestMinusZeroResult extends TestCase { public final class TestMinusZeroResult extends TestCase {
private static final double MINUS_ZERO = -0.0; private static final double MINUS_ZERO = -0.0;
// convenient access to namepace
private static final EvalInstances EI = null;
public void testSimpleOperators() { public void testSimpleOperators() {
@ -46,15 +49,15 @@ public final class TestMinusZeroResult extends TestCase {
checkEval(MINUS_ZERO, UnaryPlusEval.instance, MINUS_ZERO); checkEval(MINUS_ZERO, UnaryPlusEval.instance, MINUS_ZERO);
// most simple operators convert -0.0 to +0.0 // most simple operators convert -0.0 to +0.0
checkEval(0.0, UnaryMinusEval.instance, 0.0); checkEval(0.0, EI.UnaryMinus, 0.0);
checkEval(0.0, PercentEval.instance, MINUS_ZERO); checkEval(0.0, EI.Percent, MINUS_ZERO);
checkEval(0.0, MultiplyEval.instance, MINUS_ZERO, 1.0); checkEval(0.0, EI.Multiply, MINUS_ZERO, 1.0);
checkEval(0.0, DivideEval.instance, MINUS_ZERO, 1.0); checkEval(0.0, EI.Divide, MINUS_ZERO, 1.0);
checkEval(0.0, PowerEval.instance, MINUS_ZERO, 1.0); checkEval(0.0, EI.Power, MINUS_ZERO, 1.0);
// but SubtractEval does not convert -0.0, so '-' and '+' work like java // but SubtractEval does not convert -0.0, so '-' and '+' work like java
checkEval(MINUS_ZERO, SubtractEval.instance, MINUS_ZERO, 0.0); // this is the main point of bug 47198 checkEval(MINUS_ZERO, EI.Subtract, MINUS_ZERO, 0.0); // this is the main point of bug 47198
checkEval(0.0, AddEval.instance, MINUS_ZERO, 0.0); checkEval(0.0, EI.Add, MINUS_ZERO, 0.0);
} }
/** /**
@ -62,9 +65,9 @@ public final class TestMinusZeroResult extends TestCase {
* gets to the comparison operator) * gets to the comparison operator)
*/ */
public void testComparisonOperators() { public void testComparisonOperators() {
checkEval(false, EqualEval.instance, 0.0, MINUS_ZERO); checkEval(false, EI.Equal, 0.0, MINUS_ZERO);
checkEval(true, GreaterThanEval.instance, 0.0, MINUS_ZERO); checkEval(true, EI.GreaterThan, 0.0, MINUS_ZERO);
checkEval(true, LessThanEval.instance, MINUS_ZERO, 0.0); checkEval(true, EI.LessThan, MINUS_ZERO, 0.0);
} }
public void testTextRendering() { public void testTextRendering() {
@ -78,20 +81,20 @@ public final class TestMinusZeroResult extends TestCase {
*/ */
private static void confirmTextRendering(String expRendering, double d) { private static void confirmTextRendering(String expRendering, double d) {
ValueEval[] args = { StringEval.EMPTY_INSTANCE, new NumberEval(d), }; ValueEval[] args = { StringEval.EMPTY_INSTANCE, new NumberEval(d), };
StringEval se = (StringEval) ConcatEval.instance.evaluate(args, -1, (short)-1); StringEval se = (StringEval) EI.Concat.evaluate(args, -1, (short)-1);
String result = se.getStringValue(); String result = se.getStringValue();
assertEquals(expRendering, result); assertEquals(expRendering, result);
} }
private static void checkEval(double expectedResult, OperationEval instance, double... dArgs) { private static void checkEval(double expectedResult, Function instance, double... dArgs) {
NumberEval result = (NumberEval) evaluate(instance, dArgs); NumberEval result = (NumberEval) evaluate(instance, dArgs);
assertDouble(expectedResult, result.getNumberValue()); assertDouble(expectedResult, result.getNumberValue());
} }
private static void checkEval(boolean expectedResult, OperationEval instance, double... dArgs) { private static void checkEval(boolean expectedResult, Function instance, double... dArgs) {
BoolEval result = (BoolEval) evaluate(instance, dArgs); BoolEval result = (BoolEval) evaluate(instance, dArgs);
assertEquals(expectedResult, result.getBooleanValue()); assertEquals(expectedResult, result.getBooleanValue());
} }
private static ValueEval evaluate(OperationEval instance, double... dArgs) { private static ValueEval evaluate(Function instance, double... dArgs) {
ValueEval[] evalArgs; ValueEval[] evalArgs;
evalArgs = new ValueEval[dArgs.length]; evalArgs = new ValueEval[dArgs.length];
for (int i = 0; i < evalArgs.length; i++) { for (int i = 0; i < evalArgs.length; i++) {

View File

@ -41,8 +41,7 @@ public final class TestPercentEval extends TestCase {
arg, arg,
}; };
OperationEval opEval = PercentEval.instance; double result = NumericFunctionInvoker.invoke(PercentEval.instance, args, 0, 0);
double result = NumericFunctionInvoker.invoke(opEval, args, 0, 0);
assertEquals(expectedResult, result, 0); assertEquals(expectedResult, result, 0);
} }

View File

@ -21,7 +21,6 @@ import junit.framework.AssertionFailedError;
import org.apache.poi.hssf.record.formula.eval.ErrorEval; import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.NumericValueEval; import org.apache.poi.hssf.record.formula.eval.NumericValueEval;
import org.apache.poi.hssf.record.formula.eval.OperationEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval; import org.apache.poi.hssf.record.formula.eval.ValueEval;
import org.apache.poi.ss.formula.eval.NotImplementedException; import org.apache.poi.ss.formula.eval.NotImplementedException;
@ -53,13 +52,7 @@ public final class NumericFunctionInvoker {
* result causes the current junit test to fail. * result causes the current junit test to fail.
*/ */
public static double invoke(Function f, ValueEval[] args) { public static double invoke(Function f, ValueEval[] args) {
try { return invoke(f, args, -1, -1);
return invokeInternal(f, args, -1, -1);
} catch (NumericEvalEx e) {
throw new AssertionFailedError("Evaluation of function (" + f.getClass().getName()
+ ") failed: " + e.getMessage());
}
} }
/** /**
* Invokes the specified operator with the arguments. * Invokes the specified operator with the arguments.
@ -67,30 +60,22 @@ public final class NumericFunctionInvoker {
* This method cannot be used for confirming error return codes. Any non-numeric evaluation * This method cannot be used for confirming error return codes. Any non-numeric evaluation
* result causes the current junit test to fail. * result causes the current junit test to fail.
*/ */
public static double invoke(OperationEval f, ValueEval[] args, int srcCellRow, int srcCellCol) { public static double invoke(Function f, ValueEval[] args, int srcCellRow, int srcCellCol) {
try { try {
return invokeInternal(f, args, srcCellRow, srcCellCol); return invokeInternal(f, args, srcCellRow, srcCellCol);
} catch (NumericEvalEx e) { } catch (NumericEvalEx e) {
throw new AssertionFailedError("Evaluation of function (" + f.getClass().getName() throw new AssertionFailedError("Evaluation of function (" + f.getClass().getName()
+ ") failed: " + e.getMessage()); + ") failed: " + e.getMessage());
} }
} }
/** /**
* Formats nicer error messages for the junit output * Formats nicer error messages for the junit output
*/ */
private static double invokeInternal(Object target, ValueEval[] args, int srcCellRow, int srcCellCol) private static double invokeInternal(Function target, ValueEval[] args, int srcCellRow, int srcCellCol)
throws NumericEvalEx { throws NumericEvalEx {
ValueEval evalResult; ValueEval evalResult;
// TODO - make OperationEval extend Function
try { try {
if (target instanceof Function) { evalResult = target.evaluate(args, srcCellRow, (short)srcCellCol);
Function ff = (Function) target;
evalResult = ff.evaluate(args, srcCellRow, (short)srcCellCol);
} else {
OperationEval ff = (OperationEval) target;
evalResult = ff.evaluate(args, srcCellRow, (short)srcCellCol);
}
} catch (NotImplementedException e) { } catch (NotImplementedException e) {
throw new NumericEvalEx("Not implemented:" + e.getMessage()); throw new NumericEvalEx("Not implemented:" + e.getMessage());
} }