diff --git a/src/java/org/apache/poi/hssf/dev/FormulaViewer.java b/src/java/org/apache/poi/hssf/dev/FormulaViewer.java
index 167eaba53..d42cda71a 100644
--- a/src/java/org/apache/poi/hssf/dev/FormulaViewer.java
+++ b/src/java/org/apache/poi/hssf/dev/FormulaViewer.java
@@ -20,7 +20,7 @@ package org.apache.poi.hssf.dev;
import java.io.FileInputStream;
import java.util.List;
-import org.apache.poi.hssf.model.FormulaParser;
+import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.FormulaRecord;
import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.RecordFactory;
@@ -181,7 +181,7 @@ public class FormulaViewer
private static String composeFormula(FormulaRecord record)
{
- return FormulaParser.toFormulaString((HSSFWorkbook)null, record.getParsedExpression());
+ return HSSFFormulaParser.toFormulaString((HSSFWorkbook)null, record.getParsedExpression());
}
/**
diff --git a/src/java/org/apache/poi/hssf/eventusermodel/EventWorkbookBuilder.java b/src/java/org/apache/poi/hssf/eventusermodel/EventWorkbookBuilder.java
index 3c767dc25..c7a1471a7 100644
--- a/src/java/org/apache/poi/hssf/eventusermodel/EventWorkbookBuilder.java
+++ b/src/java/org/apache/poi/hssf/eventusermodel/EventWorkbookBuilder.java
@@ -19,7 +19,7 @@ package org.apache.poi.hssf.eventusermodel;
import java.util.ArrayList;
import java.util.List;
-import org.apache.poi.hssf.model.FormulaParser;
+import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.BoundSheetRecord;
import org.apache.poi.hssf.record.EOFRecord;
@@ -33,7 +33,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
* When working with the EventUserModel, if you want to
* process formulas, you need an instance of
* {@link Workbook} to pass to a {@link HSSFWorkbook},
- * to finally give to {@link FormulaParser},
+ * to finally give to {@link HSSFFormulaParser},
* and this will build you stub ones.
* Since you're working with the EventUserModel, you
* wouldn't want to get a full {@link Workbook} and
@@ -41,7 +41,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
* Instead, you should collect a few key records as they
* go past, then call this once you have them to build a
* stub {@link Workbook}, and from that a stub
- * {@link HSSFWorkbook}, to use with the {@link FormulaParser}.
+ * {@link HSSFWorkbook}, to use with the {@link HSSFFormulaParser}.
*
* The records you should collect are:
* * {@link ExternSheetRecord}
@@ -56,7 +56,7 @@ public class EventWorkbookBuilder {
/**
* Wraps up your stub {@link Workbook} as a stub
* {@link HSSFWorkbook}, ready for passing to
- * {@link FormulaParser}
+ * {@link HSSFFormulaParser}
* @param workbook A stub {@link Workbook}
*/
public static HSSFWorkbook createStubHSSFWorkbook(Workbook workbook) {
@@ -65,11 +65,11 @@ public class EventWorkbookBuilder {
/**
* Creates a stub Workbook from the supplied records,
- * suitable for use with the {@link FormulaParser}
+ * suitable for use with the {@link HSSFFormulaParser}
* @param externs The ExternSheetRecords in your file
* @param bounds The BoundSheetRecords in your file
* @param sst The SSTRecord in your file.
- * @return A stub Workbook suitable for use with {@link FormulaParser}
+ * @return A stub Workbook suitable for use with {@link HSSFFormulaParser}
*/
public static Workbook createStubWorkbook(ExternSheetRecord[] externs,
BoundSheetRecord[] bounds, SSTRecord sst) {
@@ -103,10 +103,10 @@ public class EventWorkbookBuilder {
/**
* Creates a stub workbook from the supplied records,
- * suitable for use with the {@link FormulaParser}
+ * suitable for use with the {@link HSSFFormulaParser}
* @param externs The ExternSheetRecords in your file
* @param bounds The BoundSheetRecords in your file
- * @return A stub Workbook suitable for use with {@link FormulaParser}
+ * @return A stub Workbook suitable for use with {@link HSSFFormulaParser}
*/
public static Workbook createStubWorkbook(ExternSheetRecord[] externs,
BoundSheetRecord[] bounds) {
diff --git a/src/java/org/apache/poi/hssf/extractor/EventBasedExcelExtractor.java b/src/java/org/apache/poi/hssf/extractor/EventBasedExcelExtractor.java
index 2ea35c773..430dcd475 100644
--- a/src/java/org/apache/poi/hssf/extractor/EventBasedExcelExtractor.java
+++ b/src/java/org/apache/poi/hssf/extractor/EventBasedExcelExtractor.java
@@ -32,7 +32,7 @@ import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;
import org.apache.poi.hssf.eventusermodel.HSSFListener;
import org.apache.poi.hssf.eventusermodel.HSSFRequest;
-import org.apache.poi.hssf.model.FormulaParser;
+import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.BOFRecord;
import org.apache.poi.hssf.record.BoundSheetRecord;
import org.apache.poi.hssf.record.CellValueRecordInterface;
@@ -45,6 +45,7 @@ import org.apache.poi.hssf.record.Record;
import org.apache.poi.hssf.record.SSTRecord;
import org.apache.poi.hssf.record.StringRecord;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
/**
@@ -177,7 +178,7 @@ public class EventBasedExcelExtractor extends POIOLE2TextExtractor {
thisRow = frec.getRow();
if(formulasNotResults) {
- thisText = FormulaParser.toFormulaString(null, frec.getParsedExpression());
+ thisText = HSSFFormulaParser.toFormulaString((HSSFWorkbook)null, frec.getParsedExpression());
} else {
if(frec.hasCachedResultString()) {
// Formula result is a string
diff --git a/src/java/org/apache/poi/hssf/model/HSSFFormulaParser.java b/src/java/org/apache/poi/hssf/model/HSSFFormulaParser.java
new file mode 100644
index 000000000..c492c5e86
--- /dev/null
+++ b/src/java/org/apache/poi/hssf/model/HSSFFormulaParser.java
@@ -0,0 +1,72 @@
+/* ====================================================================
+ 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.model;
+
+import java.util.List;
+
+import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.FormulaParser;
+import org.apache.poi.ss.formula.FormulaParsingWorkbook;
+import org.apache.poi.ss.formula.FormulaRenderer;
+import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
+
+/**
+ * HSSF wrapper for the {@link FormulaParser}
+ *
+ * @author Josh Micich
+ */
+public final class HSSFFormulaParser {
+
+ private static FormulaParsingWorkbook createParsingWorkbook(HSSFWorkbook book) {
+ return HSSFEvaluationWorkbook.create(book);
+ }
+
+ private HSSFFormulaParser() {
+ // no instances of this class
+ }
+
+ public static Ptg[] parse(String formula, HSSFWorkbook workbook) {
+ return FormulaParser.parse(formula, createParsingWorkbook(workbook));
+ }
+
+ public static Ptg[] parse(String formula, HSSFWorkbook workbook, int formulaType) {
+ return FormulaParser.parse(formula, createParsingWorkbook(workbook), formulaType);
+ }
+
+ public static String toFormulaString(HSSFWorkbook book, List lptgs) {
+ return toFormulaString(HSSFEvaluationWorkbook.create(book), lptgs);
+ }
+ /**
+ * Convenience method which takes in a list then passes it to the
+ * other toFormulaString signature.
+ * @param book workbook for 3D and named references
+ * @param lptgs list of Ptg, can be null or empty
+ * @return a human readable String
+ */
+ public static String toFormulaString(FormulaRenderingWorkbook book, List lptgs) {
+ Ptg[] ptgs = new Ptg[lptgs.size()];
+ lptgs.toArray(ptgs);
+ return FormulaRenderer.toFormulaString(book, ptgs);
+ }
+
+ public static String toFormulaString(HSSFWorkbook book, Ptg[] ptgs) {
+ return FormulaRenderer.toFormulaString(HSSFEvaluationWorkbook.create(book), ptgs);
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/record/CFRuleRecord.java b/src/java/org/apache/poi/hssf/record/CFRuleRecord.java
index 06256c5cc..cca4e6c65 100644
--- a/src/java/org/apache/poi/hssf/record/CFRuleRecord.java
+++ b/src/java/org/apache/poi/hssf/record/CFRuleRecord.java
@@ -17,7 +17,7 @@
package org.apache.poi.hssf.record;
-import org.apache.poi.hssf.model.FormulaParser;
+import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.cf.BorderFormatting;
import org.apache.poi.hssf.record.cf.FontFormatting;
import org.apache.poi.hssf.record.cf.PatternFormatting;
@@ -595,6 +595,6 @@ public final class CFRuleRecord extends Record {
if(formula == null) {
return null;
}
- return FormulaParser.parse(formula, workbook);
+ return HSSFFormulaParser.parse(formula, workbook);
}
}
diff --git a/src/java/org/apache/poi/hssf/record/NameRecord.java b/src/java/org/apache/poi/hssf/record/NameRecord.java
index d36124e7b..dc301bca9 100644
--- a/src/java/org/apache/poi/hssf/record/NameRecord.java
+++ b/src/java/org/apache/poi/hssf/record/NameRecord.java
@@ -20,7 +20,7 @@ package org.apache.poi.hssf.record;
import java.util.ArrayList;
import java.util.List;
-import org.apache.poi.hssf.model.FormulaParser;
+import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.formula.Area3DPtg;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.Ref3DPtg;
@@ -495,7 +495,7 @@ public final class NameRecord extends Record {
* @return area reference
*/
public String getAreaReference(HSSFWorkbook book){
- return FormulaParser.toFormulaString(book, field_13_name_definition);
+ return HSSFFormulaParser.toFormulaString(book, field_13_name_definition);
}
/** sets the reference , the area only (range)
diff --git a/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java b/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java
index f528fb67b..ca9dd7d3e 100644
--- a/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java
+++ b/src/java/org/apache/poi/hssf/record/formula/atp/AnalysisToolPak.java
@@ -24,13 +24,13 @@ import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.EvaluationWorkbook;
public final class AnalysisToolPak {
private static final FreeRefFunction NotImplemented = new FreeRefFunction() {
- public ValueEval evaluate(Eval[] args, HSSFWorkbook workbook, int srcCellSheet,
+ public ValueEval evaluate(Eval[] args, EvaluationWorkbook workbook, int srcCellSheet,
int srcCellRow, int srcCellCol) {
return ErrorEval.FUNCTION_NOT_IMPLEMENTED;
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/atp/ParityFunction.java b/src/java/org/apache/poi/hssf/record/formula/atp/ParityFunction.java
index a6dd10a84..b907d89ea 100644
--- a/src/java/org/apache/poi/hssf/record/formula/atp/ParityFunction.java
+++ b/src/java/org/apache/poi/hssf/record/formula/atp/ParityFunction.java
@@ -17,7 +17,6 @@
package org.apache.poi.hssf.record.formula.atp;
-import org.apache.poi.hssf.record.formula.eval.BlankEval;
import org.apache.poi.hssf.record.formula.eval.BoolEval;
import org.apache.poi.hssf.record.formula.eval.ErrorEval;
import org.apache.poi.hssf.record.formula.eval.Eval;
@@ -25,8 +24,7 @@ import org.apache.poi.hssf.record.formula.eval.EvaluationException;
import org.apache.poi.hssf.record.formula.eval.OperandResolver;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.EvaluationWorkbook;
/**
* Implementation of Excel 'Analysis ToolPak' function ISEVEN() ISODD()
*
@@ -42,7 +40,7 @@ final class ParityFunction implements FreeRefFunction {
_desiredParity = desiredParity;
}
- public ValueEval evaluate(Eval[] args, HSSFWorkbook workbook, int srcCellSheet, int srcCellRow,
+ public ValueEval evaluate(Eval[] args, EvaluationWorkbook workbook, int srcCellSheet, int srcCellRow,
int srcCellCol) {
if (args.length != 1) {
return ErrorEval.VALUE_INVALID;
diff --git a/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java b/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java
index f48eba8d5..05c14f368 100644
--- a/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java
+++ b/src/java/org/apache/poi/hssf/record/formula/atp/YearFrac.java
@@ -21,7 +21,6 @@ import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.regex.Pattern;
-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.Eval;
import org.apache.poi.hssf.record.formula.eval.EvaluationException;
@@ -31,8 +30,7 @@ import org.apache.poi.hssf.record.formula.eval.StringEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
import org.apache.poi.hssf.usermodel.HSSFDateUtil;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.EvaluationWorkbook;
/**
* Implementation of Excel 'Analysis ToolPak' function YEARFRAC()
*
@@ -61,7 +59,7 @@ final class YearFrac implements FreeRefFunction {
// enforce singleton
}
- public ValueEval evaluate(Eval[] args, HSSFWorkbook workbook, int srcCellSheet, int srcCellRow,
+ public ValueEval evaluate(Eval[] args, EvaluationWorkbook workbook, int srcCellSheet, int srcCellRow,
int srcCellCol) {
double result;
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java b/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java
index 96cc64310..8e8a9799e 100755
--- a/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/ExternalFunction.java
@@ -19,7 +19,7 @@ package org.apache.poi.hssf.record.formula.eval;
import org.apache.poi.hssf.record.formula.atp.AnalysisToolPak;
import org.apache.poi.hssf.record.formula.functions.FreeRefFunction;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.EvaluationWorkbook;
/**
*
* Common entry point for all user-defined (non-built-in) functions (where
@@ -30,7 +30,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
*/
final class ExternalFunction implements FreeRefFunction {
- public ValueEval evaluate(Eval[] args, HSSFWorkbook workbook,
+ public ValueEval evaluate(Eval[] args, EvaluationWorkbook workbook,
int srcCellSheet, int srcCellRow,int srcCellCol) {
int nIncomingArgs = args.length;
@@ -58,9 +58,9 @@ final class ExternalFunction implements FreeRefFunction {
return targetFunc.evaluate(outGoingArgs, workbook, srcCellSheet, srcCellRow, srcCellCol);
}
- private FreeRefFunction findExternalUserDefinedFunction(HSSFWorkbook workbook,
+ private FreeRefFunction findExternalUserDefinedFunction(EvaluationWorkbook workbook,
NameXEval n) throws EvaluationException {
- String functionName = workbook.resolveNameXText(n.getSheetRefIndex(), n.getNameNumber());
+ String functionName = workbook.resolveNameXText(n.getPtg());
if(false) {
System.out.println("received call to external user defined function (" + functionName + ")");
diff --git a/src/java/org/apache/poi/hssf/record/formula/eval/NameXEval.java b/src/java/org/apache/poi/hssf/record/formula/eval/NameXEval.java
index 12b6be380..b67f4eb3d 100644
--- a/src/java/org/apache/poi/hssf/record/formula/eval/NameXEval.java
+++ b/src/java/org/apache/poi/hssf/record/formula/eval/NameXEval.java
@@ -17,32 +17,27 @@
package org.apache.poi.hssf.record.formula.eval;
+import org.apache.poi.hssf.record.formula.NameXPtg;
+
/**
* @author Josh Micich
*/
public final class NameXEval implements Eval {
- /** index to REF entry in externsheet record */
- private final int _sheetRefIndex;
- /** index to defined name or externname table(1 based) */
- private final int _nameNumber;
+ private final NameXPtg _ptg;
- public NameXEval(int sheetRefIndex, int nameNumber) {
- _sheetRefIndex = sheetRefIndex;
- _nameNumber = nameNumber;
+ public NameXEval(NameXPtg ptg) {
+ _ptg = ptg;
}
- public int getSheetRefIndex() {
- return _sheetRefIndex;
- }
- public int getNameNumber() {
- return _nameNumber;
+ public NameXPtg getPtg() {
+ return _ptg;
}
public String toString() {
StringBuffer sb = new StringBuffer(64);
sb.append(getClass().getName()).append(" [");
- sb.append(_sheetRefIndex).append(", ").append(_nameNumber);
+ sb.append(_ptg.getSheetRefIndex()).append(", ").append(_ptg.getNameIndex());
sb.append("]");
return sb.toString();
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/FreeRefFunction.java b/src/java/org/apache/poi/hssf/record/formula/functions/FreeRefFunction.java
index 977c1b363..cdec045b4 100755
--- a/src/java/org/apache/poi/hssf/record/formula/functions/FreeRefFunction.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/FreeRefFunction.java
@@ -19,8 +19,7 @@ package org.apache.poi.hssf.record.formula.functions;
import org.apache.poi.hssf.record.formula.eval.Eval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.EvaluationWorkbook;
/**
@@ -53,5 +52,5 @@ public interface FreeRefFunction {
* a specified Excel error (Exceptions are never thrown to represent Excel errors).
*
*/
- ValueEval evaluate(Eval[] args, HSSFWorkbook workbook, int srcCellSheet, int srcCellRow, int srcCellCol);
+ ValueEval evaluate(Eval[] args, EvaluationWorkbook workbook, int srcCellSheet, int srcCellRow, int srcCellCol);
}
diff --git a/src/java/org/apache/poi/hssf/record/formula/functions/Indirect.java b/src/java/org/apache/poi/hssf/record/formula/functions/Indirect.java
index f4036c107..567f29b2b 100644
--- a/src/java/org/apache/poi/hssf/record/formula/functions/Indirect.java
+++ b/src/java/org/apache/poi/hssf/record/formula/functions/Indirect.java
@@ -1,27 +1,26 @@
-/*
-* 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.
-*/
+/* ====================================================================
+ 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.Eval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ss.formula.EvaluationWorkbook;
/**
* Implementation for Excel function INDIRECT
@@ -41,7 +40,7 @@ import org.apache.poi.hssf.usermodel.HSSFWorkbook;
*/
public final class Indirect implements FreeRefFunction {
- public ValueEval evaluate(Eval[] args, HSSFWorkbook workbook, int srcCellSheet, int srcCellRow, int srcCellCol) {
+ public ValueEval evaluate(Eval[] args, EvaluationWorkbook workbook, int srcCellSheet, int srcCellRow, int srcCellCol) {
// TODO - implement INDIRECT()
return ErrorEval.FUNCTION_NOT_IMPLEMENTED;
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/DVConstraint.java b/src/java/org/apache/poi/hssf/usermodel/DVConstraint.java
index a1027ccfa..5bc478f42 100644
--- a/src/java/org/apache/poi/hssf/usermodel/DVConstraint.java
+++ b/src/java/org/apache/poi/hssf/usermodel/DVConstraint.java
@@ -20,10 +20,12 @@ import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
-import org.apache.poi.hssf.model.FormulaParser;
+import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.formula.NumberPtg;
import org.apache.poi.hssf.record.formula.Ptg;
import org.apache.poi.hssf.record.formula.StringPtg;
+import org.apache.poi.ss.formula.FormulaParser;
+import org.apache.poi.ss.formula.FormulaType;
/**
*
@@ -339,7 +341,7 @@ public class DVConstraint {
if (_explicitListValues == null) {
// formula is parsed with slightly different RVA rules: (root node type must be 'reference')
- return FormulaParser.parse(_formula1, workbook, FormulaParser.FORMULA_TYPE_DATAVALIDATION_LIST);
+ return HSSFFormulaParser.parse(_formula1, workbook, FormulaType.DATAVALIDATION_LIST);
// To do: Excel places restrictions on the available operations within a list formula.
// Some things like union and intersection are not allowed.
}
@@ -369,7 +371,7 @@ public class DVConstraint {
if (value != null) {
throw new IllegalStateException("Both formula and value cannot be present");
}
- return FormulaParser.parse(formula, workbook);
+ return HSSFFormulaParser.parse(formula, workbook);
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
index 9f12f4305..3d2f99f41 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFCell.java
@@ -25,7 +25,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
-import org.apache.poi.hssf.model.FormulaParser;
+import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.BlankRecord;
@@ -124,7 +124,7 @@ public final class HSSFCell {
short xfindex = sheet.getSheet().getXFIndexForColAt(col);
setCellType(CELL_TYPE_BLANK, false, row, col,xfindex);
}
- /* package */ HSSFSheet getSheet() {
+ public HSSFSheet getSheet() {
return sheet;
}
@@ -589,12 +589,12 @@ public final class HSSFCell {
if (rec.getXFIndex() == (short)0) {
rec.setXFIndex((short) 0x0f);
}
- Ptg[] ptgs = FormulaParser.parse(formula, book);
+ Ptg[] ptgs = HSSFFormulaParser.parse(formula, book);
frec.setParsedExpression(ptgs);
}
public String getCellFormula() {
- return FormulaParser.toFormulaString(book, ((FormulaRecordAggregate)record).getFormulaRecord().getParsedExpression());
+ return HSSFFormulaParser.toFormulaString(book, ((FormulaRecordAggregate)record).getFormulaRecord().getParsedExpression());
}
/**
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java b/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java
index fc34b9da9..29430b094 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFConditionalFormattingRule.java
@@ -17,7 +17,7 @@
package org.apache.poi.hssf.usermodel;
-import org.apache.poi.hssf.model.FormulaParser;
+import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.record.CFRuleRecord;
import org.apache.poi.hssf.record.CFRuleRecord.ComparisonOperator;
import org.apache.poi.hssf.record.cf.BorderFormatting;
@@ -205,6 +205,6 @@ public final class HSSFConditionalFormattingRule
if(parsedExpression ==null) {
return null;
}
- return FormulaParser.toFormulaString(workbook, parsedExpression);
+ return HSSFFormulaParser.toFormulaString(workbook, parsedExpression);
}
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
index f9399ee8c..16ef3b2a9 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
@@ -1,8 +1,14 @@
package org.apache.poi.hssf.usermodel;
+import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.model.Workbook;
+import org.apache.poi.hssf.record.NameRecord;
import org.apache.poi.hssf.record.formula.NamePtg;
import org.apache.poi.hssf.record.formula.NameXPtg;
+import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.ss.formula.EvaluationName;
+import org.apache.poi.ss.formula.EvaluationWorkbook;
+import org.apache.poi.ss.formula.FormulaParsingWorkbook;
import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
/**
@@ -10,8 +16,9 @@ import org.apache.poi.ss.formula.FormulaRenderingWorkbook;
*
* @author Josh Micich
*/
-public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook {
+public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook, EvaluationWorkbook, FormulaParsingWorkbook {
+ private final HSSFWorkbook _uBook;
private final Workbook _iBook;
public static HSSFEvaluationWorkbook create(HSSFWorkbook book) {
@@ -22,9 +29,58 @@ public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook {
}
private HSSFEvaluationWorkbook(HSSFWorkbook book) {
+ _uBook = book;
_iBook = book.getWorkbook();
}
+ public int getExternalSheetIndex(String sheetName) {
+ int sheetIndex = _uBook.getSheetIndex(sheetName);
+ return _iBook.checkExternSheet(sheetIndex);
+ }
+
+ public EvaluationName getName(int index) {
+ return new Name(_iBook.getNameRecord(index), index);
+ }
+
+ public EvaluationName getName(String name) {
+ for(int i=0; i < _iBook.getNumNames(); i++) {
+ NameRecord nr = _iBook.getNameRecord(i);
+ if (name.equalsIgnoreCase(nr.getNameText())) {
+ return new Name(nr, i);
+ }
+ }
+ return null;
+ }
+
+ public int getSheetIndex(HSSFSheet sheet) {
+ return _uBook.getSheetIndex(sheet);
+ }
+
+ public String getSheetName(int sheetIndex) {
+ return _uBook.getSheetName(sheetIndex);
+ }
+
+ public int getNameIndex(String name) {
+ return _uBook.getNameIndex(name);
+ }
+
+ public NameXPtg getNameXPtg(String name) {
+ return _iBook.getNameXPtg(name);
+ }
+
+ public HSSFSheet getSheet(int sheetIndex) {
+ return _uBook.getSheetAt(sheetIndex);
+ }
+
+ public HSSFSheet getSheetByExternSheetIndex(int externSheetIndex) {
+ int sheetIndex = _iBook.getSheetIndexFromExternSheetIndex(externSheetIndex);
+ return _uBook.getSheetAt(sheetIndex);
+ }
+
+ public HSSFWorkbook getWorkbook() {
+ return _uBook;
+ }
+
public String resolveNameXText(NameXPtg n) {
return _iBook.resolveNameXText(n.getSheetRefIndex(), n.getNameIndex());
}
@@ -35,4 +91,45 @@ public final class HSSFEvaluationWorkbook implements FormulaRenderingWorkbook {
public String getNameText(NamePtg namePtg) {
return _iBook.getNameRecord(namePtg.getIndex()).getNameText();
}
+ public EvaluationName getName(NamePtg namePtg) {
+ int ix = namePtg.getIndex();
+ return new Name(_iBook.getNameRecord(ix), ix);
+ }
+ public Ptg[] getFormulaTokens(HSSFCell cell) {
+ return HSSFFormulaParser.parse(cell.getCellFormula(), _uBook);
+ }
+
+ private static final class Name implements EvaluationName {
+
+ private final NameRecord _nameRecord;
+ private final int _index;
+
+ public Name(NameRecord nameRecord, int index) {
+ _nameRecord = nameRecord;
+ _index = index;
+ }
+
+ public Ptg[] getNameDefinition() {
+ return _nameRecord.getNameDefinition();
+ }
+
+ public String getNameText() {
+ return _nameRecord.getNameText();
+ }
+
+ public boolean hasFormula() {
+ return _nameRecord.hasFormula();
+ }
+
+ public boolean isFunctionName() {
+ return _nameRecord.isFunctionName();
+ }
+
+ public boolean isRange() {
+ return _nameRecord.hasFormula(); // TODO - is this right?
+ }
+ public NamePtg createPtg() {
+ return new NamePtg(_index);
+ }
+ }
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java b/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
index 0e6e49338..1e6aa163c 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFFormulaEvaluator.java
@@ -1,703 +1,368 @@
-/* ====================================================================
- 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.usermodel;
-
-import java.util.Iterator;
-import java.util.Stack;
-
-import org.apache.poi.hssf.model.FormulaParser;
-import org.apache.poi.hssf.model.Workbook;
-import org.apache.poi.hssf.record.NameRecord;
-import org.apache.poi.hssf.record.formula.Area3DPtg;
-import org.apache.poi.hssf.record.formula.AreaPtg;
-import org.apache.poi.hssf.record.formula.BoolPtg;
-import org.apache.poi.hssf.record.formula.ControlPtg;
-import org.apache.poi.hssf.record.formula.ErrPtg;
-import org.apache.poi.hssf.record.formula.IntPtg;
-import org.apache.poi.hssf.record.formula.MemErrPtg;
-import org.apache.poi.hssf.record.formula.MissingArgPtg;
-import org.apache.poi.hssf.record.formula.NamePtg;
-import org.apache.poi.hssf.record.formula.NameXPtg;
-import org.apache.poi.hssf.record.formula.NumberPtg;
-import org.apache.poi.hssf.record.formula.OperationPtg;
-import org.apache.poi.hssf.record.formula.Ptg;
-import org.apache.poi.hssf.record.formula.Ref3DPtg;
-import org.apache.poi.hssf.record.formula.RefPtg;
-import org.apache.poi.hssf.record.formula.StringPtg;
-import org.apache.poi.hssf.record.formula.UnionPtg;
-import org.apache.poi.hssf.record.formula.UnknownPtg;
-import org.apache.poi.hssf.record.formula.eval.AreaEval;
-import org.apache.poi.hssf.record.formula.eval.BlankEval;
-import org.apache.poi.hssf.record.formula.eval.BoolEval;
-import org.apache.poi.hssf.record.formula.eval.ErrorEval;
-import org.apache.poi.hssf.record.formula.eval.Eval;
-import org.apache.poi.hssf.record.formula.eval.FunctionEval;
-import org.apache.poi.hssf.record.formula.eval.NameEval;
-import org.apache.poi.hssf.record.formula.eval.NameXEval;
-import org.apache.poi.hssf.record.formula.eval.NumberEval;
-import org.apache.poi.hssf.record.formula.eval.OperationEval;
-import org.apache.poi.hssf.record.formula.eval.RefEval;
-import org.apache.poi.hssf.record.formula.eval.StringEval;
-import org.apache.poi.hssf.record.formula.eval.ValueEval;
-import org.apache.poi.hssf.util.CellReference;
-
-/**
- * Evaluates formula cells.
- *
- * For performance reasons, this class keeps a cache of all previously calculated intermediate
- * cell values. Be sure to call {@link #clearCache()} if any workbook cells are changed between
- * calls to evaluate~ methods on this class.
- *
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- * @author Josh Micich
- */
-public class HSSFFormulaEvaluator {
-
- /**
- * used to track the number of evaluations
- */
- private static final class Counter {
- public int value;
- public int depth;
- public Counter() {
- value = 0;
- }
- }
-
- private final HSSFWorkbook _workbook;
- private final EvaluationCache _cache;
-
- private Counter _evaluationCounter;
-
- /**
- * @deprecated (Sep 2008) HSSFSheet parameter is ignored
- */
- public HSSFFormulaEvaluator(HSSFSheet sheet, HSSFWorkbook workbook) {
- this(workbook);
- if (false) {
- sheet.toString(); // suppress unused parameter compiler warning
- }
- }
- public HSSFFormulaEvaluator(HSSFWorkbook workbook) {
- this(workbook, new EvaluationCache(), new Counter());
- }
-
- private HSSFFormulaEvaluator(HSSFWorkbook workbook, EvaluationCache cache, Counter evaluationCounter) {
- _workbook = workbook;
- _cache = cache;
- _evaluationCounter = evaluationCounter;
- }
-
- /**
- * for debug use. Used in toString methods
- */
- /* package */ String getSheetName(HSSFSheet sheet) {
- return _workbook.getSheetName(_workbook.getSheetIndex(sheet));
- }
- /**
- * for debug/test use
- */
- /* package */ int getEvaluationCount() {
- return _evaluationCounter.value;
- }
-
- private static boolean isDebugLogEnabled() {
- return false;
- }
- private static void logDebug(String s) {
- if (isDebugLogEnabled()) {
- System.out.println(s);
- }
- }
-
- /**
- * Does nothing
- * @deprecated (Aug 2008) - not needed, since the current row can be derived from the cell
- */
- public void setCurrentRow(HSSFRow row) {
- // do nothing
- if (false) {
- row.getClass(); // suppress unused parameter compiler warning
- }
- }
-
- /**
- * Should be called whenever there are changes to input cells in the evaluated workbook.
- * Failure to call this method after changing cell values will cause incorrect behaviour
- * of the evaluate~ methods of this class
- */
- public void clearCache() {
- _cache.clear();
- }
-
- /**
- * Returns an underlying FormulaParser, for the specified
- * Formula String and HSSFWorkbook.
- * This will allow you to generate the Ptgs yourself, if
- * your needs are more complex than just having the
- * formula evaluated.
- */
- public static FormulaParser getUnderlyingParser(HSSFWorkbook workbook, String formula) {
- return new FormulaParser(formula, workbook);
- }
-
- /**
- * If cell contains a formula, the formula is evaluated and returned,
- * else the CellValue simply copies the appropriate cell value from
- * the cell and also its cell type. This method should be preferred over
- * evaluateInCell() when the call should not modify the contents of the
- * original cell.
- * @param cell
- */
- public CellValue evaluate(HSSFCell cell) {
- if (cell == null) {
- return null;
- }
-
- switch (cell.getCellType()) {
- case HSSFCell.CELL_TYPE_BOOLEAN:
- return CellValue.valueOf(cell.getBooleanCellValue());
- case HSSFCell.CELL_TYPE_ERROR:
- return CellValue.getError(cell.getErrorCellValue());
- case HSSFCell.CELL_TYPE_FORMULA:
- return evaluateFormulaCellValue(cell);
- case HSSFCell.CELL_TYPE_NUMERIC:
- return new CellValue(cell.getNumericCellValue());
- case HSSFCell.CELL_TYPE_STRING:
- return new CellValue(cell.getRichStringCellValue().getString());
- }
- throw new IllegalStateException("Bad cell type (" + cell.getCellType() + ")");
- }
-
-
- /**
- * If cell contains formula, it evaluates the formula,
- * and saves the result of the formula. The cell
- * remains as a formula cell.
- * Else if cell does not contain formula, this method leaves
- * the cell unchanged.
- * Note that the type of the formula result is returned,
- * so you know what kind of value is also stored with
- * the formula.
- *
- * int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
- *
- * Be aware that your cell will hold both the formula,
- * and the result. If you want the cell replaced with
- * the result of the formula, use {@link #evaluateInCell(HSSFCell)}
- * @param cell The cell to evaluate
- * @return The type of the formula result (the cell's type remains as HSSFCell.CELL_TYPE_FORMULA however)
- */
- public int evaluateFormulaCell(HSSFCell cell) {
- if (cell == null || cell.getCellType() != HSSFCell.CELL_TYPE_FORMULA) {
- return -1;
- }
- CellValue cv = evaluateFormulaCellValue(cell);
- // cell remains a formula cell, but the cached value is changed
- setCellValue(cell, cv);
- return cv.getCellType();
- }
-
- /**
- * If cell contains formula, it evaluates the formula, and
- * puts the formula result back into the cell, in place
- * of the old formula.
- * Else if cell does not contain formula, this method leaves
- * the cell unchanged.
- * Note that the same instance of HSSFCell is returned to
- * allow chained calls like:
- *
- * int evaluatedCellType = evaluator.evaluateInCell(cell).getCellType();
- *
- * Be aware that your cell value will be changed to hold the
- * result of the formula. If you simply want the formula
- * value computed for you, use {@link #evaluateFormulaCell(HSSFCell)}
- * @param cell
- */
- public HSSFCell evaluateInCell(HSSFCell cell) {
- if (cell == null) {
- return null;
- }
- if (cell.getCellType() == HSSFCell.CELL_TYPE_FORMULA) {
- CellValue cv = evaluateFormulaCellValue(cell);
- setCellType(cell, cv); // cell will no longer be a formula cell
- setCellValue(cell, cv);
- }
- return cell;
- }
- private static void setCellType(HSSFCell cell, CellValue cv) {
- int cellType = cv.getCellType();
- switch (cellType) {
- case HSSFCell.CELL_TYPE_BOOLEAN:
- case HSSFCell.CELL_TYPE_ERROR:
- case HSSFCell.CELL_TYPE_NUMERIC:
- case HSSFCell.CELL_TYPE_STRING:
- cell.setCellType(cellType);
- return;
- case HSSFCell.CELL_TYPE_BLANK:
- // never happens - blanks eventually get translated to zero
- case HSSFCell.CELL_TYPE_FORMULA:
- // this will never happen, we have already evaluated the formula
- }
- throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
- }
-
- private static void setCellValue(HSSFCell cell, CellValue cv) {
- int cellType = cv.getCellType();
- switch (cellType) {
- case HSSFCell.CELL_TYPE_BOOLEAN:
- cell.setCellValue(cv.getBooleanValue());
- break;
- case HSSFCell.CELL_TYPE_ERROR:
- cell.setCellErrorValue(cv.getErrorValue());
- break;
- case HSSFCell.CELL_TYPE_NUMERIC:
- cell.setCellValue(cv.getNumberValue());
- break;
- case HSSFCell.CELL_TYPE_STRING:
- cell.setCellValue(cv.getRichTextStringValue());
- break;
- case HSSFCell.CELL_TYPE_BLANK:
- // never happens - blanks eventually get translated to zero
- case HSSFCell.CELL_TYPE_FORMULA:
- // this will never happen, we have already evaluated the formula
- default:
- throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
- }
- }
-
- /**
- * Loops over all cells in all sheets of the supplied
- * workbook.
- * For cells that contain formulas, their formulas are
- * evaluated, and the results are saved. These cells
- * remain as formula cells.
- * For cells that do not contain formulas, no changes
- * are made.
- * This is a helpful wrapper around looping over all
- * cells, and calling evaluateFormulaCell on each one.
- */
- public static void evaluateAllFormulaCells(HSSFWorkbook wb) {
- HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(wb);
- for(int i=0; inull, never {@link BlankEval}
- */
- private ValueEval internalEvaluate(HSSFCell srcCell) {
- int srcRowNum = srcCell.getRowIndex();
- int srcColNum = srcCell.getCellNum();
-
- ValueEval result;
-
- int sheetIndex = _workbook.getSheetIndex(srcCell.getSheet());
- result = _cache.getValue(sheetIndex, srcRowNum, srcColNum);
- if (result != null) {
- return result;
- }
- _evaluationCounter.value++;
- _evaluationCounter.depth++;
-
- EvaluationCycleDetector tracker = EvaluationCycleDetectorManager.getTracker();
-
- if(!tracker.startEvaluate(_workbook, sheetIndex, srcRowNum, srcColNum)) {
- return ErrorEval.CIRCULAR_REF_ERROR;
- }
- try {
- result = evaluateCell(sheetIndex, srcRowNum, (short)srcColNum, srcCell.getCellFormula());
- } finally {
- tracker.endEvaluate(_workbook, sheetIndex, srcRowNum, srcColNum);
- _cache.setValue(sheetIndex, srcRowNum, srcColNum, result);
- _evaluationCounter.depth--;
- }
- if (isDebugLogEnabled()) {
- String sheetName = _workbook.getSheetName(sheetIndex);
- CellReference cr = new CellReference(srcRowNum, srcColNum);
- logDebug("Evaluated " + sheetName + "!" + cr.formatAsString() + " to " + result.toString());
- }
- return result;
- }
- private ValueEval evaluateCell(int sheetIndex, int srcRowNum, short srcColNum, String cellFormulaText) {
-
- Ptg[] ptgs = FormulaParser.parse(cellFormulaText, _workbook);
-
- Stack stack = new Stack();
- for (int i = 0, iSize = ptgs.length; i < iSize; i++) {
-
- // since we don't know how to handle these yet :(
- Ptg ptg = ptgs[i];
- if (ptg instanceof ControlPtg) {
- // skip Parentheses, Attr, etc
- continue;
- }
- if (ptg instanceof MemErrPtg) { continue; }
- if (ptg instanceof MissingArgPtg) {
- // TODO - might need to push BlankEval or MissingArgEval
- continue;
- }
- Eval opResult;
- if (ptg instanceof OperationPtg) {
- OperationPtg optg = (OperationPtg) ptg;
-
- if (optg instanceof UnionPtg) { continue; }
-
- OperationEval operation = OperationEvaluatorFactory.create(optg);
-
- int numops = operation.getNumberOfOperands();
- Eval[] ops = new Eval[numops];
-
- // storing the ops in reverse order since they are popping
- for (int j = numops - 1; j >= 0; j--) {
- Eval p = (Eval) stack.pop();
- ops[j] = p;
- }
-// logDebug("invoke " + operation + " (nAgs=" + numops + ")");
- opResult = invokeOperation(operation, ops, _workbook, sheetIndex, srcRowNum, srcColNum);
- } else {
- opResult = getEvalForPtg(ptg, sheetIndex);
- }
- if (opResult == null) {
- throw new RuntimeException("Evaluation result must not be null");
- }
-// logDebug("push " + opResult);
- stack.push(opResult);
- }
-
- ValueEval value = ((ValueEval) stack.pop());
- if (!stack.isEmpty()) {
- throw new IllegalStateException("evaluation stack not empty");
- }
- value = dereferenceValue(value, srcRowNum, srcColNum);
- if (value == BlankEval.INSTANCE) {
- // Note Excel behaviour here. A blank final final value is converted to zero.
- return NumberEval.ZERO;
- // Formulas _never_ evaluate to blank. If a formula appears to have evaluated to
- // blank, the actual value is empty string. This can be verified with ISBLANK().
- }
- return value;
- }
-
- /**
- * Dereferences a single value from any AreaEval or RefEval evaluation result.
- * If the supplied evaluationResult is just a plain value, it is returned as-is.
- * @return a NumberEval, StringEval, BoolEval,
- * BlankEval or ErrorEval. Never null
.
- */
- private static ValueEval dereferenceValue(ValueEval evaluationResult, int srcRowNum, short srcColNum) {
- if (evaluationResult instanceof RefEval) {
- RefEval rv = (RefEval) evaluationResult;
- return rv.getInnerValueEval();
- }
- if (evaluationResult instanceof AreaEval) {
- AreaEval ae = (AreaEval) evaluationResult;
- if (ae.isRow()) {
- if(ae.isColumn()) {
- return ae.getRelativeValue(0, 0);
- }
- return ae.getValueAt(ae.getFirstRow(), srcColNum);
- }
- if (ae.isColumn()) {
- return ae.getValueAt(srcRowNum, ae.getFirstColumn());
- }
- return ErrorEval.VALUE_INVALID;
- }
- return evaluationResult;
- }
-
- private static Eval invokeOperation(OperationEval operation, Eval[] ops,
- HSSFWorkbook workbook, int sheetIndex, int srcRowNum, int srcColNum) {
-
- if(operation instanceof FunctionEval) {
- FunctionEval fe = (FunctionEval) operation;
- if(fe.isFreeRefFunction()) {
- return fe.getFreeRefFunction().evaluate(ops, workbook, sheetIndex, srcRowNum, srcColNum);
- }
- }
- return operation.evaluate(ops, srcRowNum, (short)srcColNum);
- }
-
- private HSSFSheet getOtherSheet(int externSheetIndex) {
- Workbook wb = _workbook.getWorkbook();
- return _workbook.getSheetAt(wb.getSheetIndexFromExternSheetIndex(externSheetIndex));
- }
-
- /**
- * returns an appropriate Eval impl instance for the Ptg. The Ptg must be
- * one of: Area3DPtg, AreaPtg, ReferencePtg, Ref3DPtg, IntPtg, NumberPtg,
- * StringPtg, BoolPtg
special Note: OperationPtg subtypes cannot be
- * passed here!
- */
- private Eval getEvalForPtg(Ptg ptg, int sheetIndex) {
- if (ptg instanceof NamePtg) {
- // named ranges, macro functions
- NamePtg namePtg = (NamePtg) ptg;
- int numberOfNames = _workbook.getNumberOfNames();
- int nameIndex = namePtg.getIndex();
- if(nameIndex < 0 || nameIndex >= numberOfNames) {
- throw new RuntimeException("Bad name index (" + nameIndex
- + "). Allowed range is (0.." + (numberOfNames-1) + ")");
- }
- NameRecord nameRecord = _workbook.getWorkbook().getNameRecord(nameIndex);
- if (nameRecord.isFunctionName()) {
- return new NameEval(nameRecord.getNameText());
- }
- if (nameRecord.hasFormula()) {
- return evaluateNameFormula(nameRecord.getNameDefinition(), sheetIndex);
- }
-
- throw new RuntimeException("Don't now how to evalate name '" + nameRecord.getNameText() + "'");
- }
- if (ptg instanceof NameXPtg) {
- NameXPtg nameXPtg = (NameXPtg) ptg;
- return new NameXEval(nameXPtg.getSheetRefIndex(), nameXPtg.getNameIndex());
- }
-
- if (ptg instanceof IntPtg) {
- return new NumberEval(((IntPtg)ptg).getValue());
- }
- if (ptg instanceof NumberPtg) {
- return new NumberEval(((NumberPtg)ptg).getValue());
- }
- if (ptg instanceof StringPtg) {
- return new StringEval(((StringPtg) ptg).getValue());
- }
- if (ptg instanceof BoolPtg) {
- return BoolEval.valueOf(((BoolPtg) ptg).getValue());
- }
- if (ptg instanceof ErrPtg) {
- return ErrorEval.valueOf(((ErrPtg) ptg).getErrorCode());
- }
- HSSFSheet sheet = _workbook.getSheetAt(sheetIndex);
- if (ptg instanceof RefPtg) {
- return new LazyRefEval(((RefPtg) ptg), sheet, this);
- }
- if (ptg instanceof AreaPtg) {
- return new LazyAreaEval(((AreaPtg) ptg), sheet, this);
- }
- if (ptg instanceof Ref3DPtg) {
- Ref3DPtg refPtg = (Ref3DPtg) ptg;
- HSSFSheet xsheet = getOtherSheet(refPtg.getExternSheetIndex());
- return new LazyRefEval(refPtg, xsheet, this);
- }
- if (ptg instanceof Area3DPtg) {
- Area3DPtg a3dp = (Area3DPtg) ptg;
- HSSFSheet xsheet = getOtherSheet(a3dp.getExternSheetIndex());
- return new LazyAreaEval(a3dp, xsheet, this);
- }
-
- if (ptg instanceof UnknownPtg) {
- // POI uses UnknownPtg when the encoded Ptg array seems to be corrupted.
- // This seems to occur in very rare cases (e.g. unused name formulas in bug 44774, attachment 21790)
- // In any case, formulas are re-parsed before execution, so UnknownPtg should not get here
- throw new RuntimeException("UnknownPtg not allowed");
- }
-
- throw new RuntimeException("Unexpected ptg class (" + ptg.getClass().getName() + ")");
- }
- private Eval evaluateNameFormula(Ptg[] ptgs, int sheetIndex) {
- if (ptgs.length > 1) {
- throw new RuntimeException("Complex name formulas not supported yet");
- }
- return getEvalForPtg(ptgs[0], sheetIndex);
- }
-
- /**
- * Given a cell, find its type and from that create an appropriate ValueEval
- * impl instance and return that. Since the cell could be an external
- * reference, we need the sheet that this belongs to.
- * Non existent cells are treated as empty.
- */
- /* package */ ValueEval getEvalForCell(HSSFCell cell) {
-
- if (cell == null) {
- return BlankEval.INSTANCE;
- }
- switch (cell.getCellType()) {
- case HSSFCell.CELL_TYPE_NUMERIC:
- return new NumberEval(cell.getNumericCellValue());
- case HSSFCell.CELL_TYPE_STRING:
- return new StringEval(cell.getRichStringCellValue().getString());
- case HSSFCell.CELL_TYPE_FORMULA:
- return internalEvaluate(cell);
- case HSSFCell.CELL_TYPE_BOOLEAN:
- return BoolEval.valueOf(cell.getBooleanCellValue());
- case HSSFCell.CELL_TYPE_BLANK:
- return BlankEval.INSTANCE;
- case HSSFCell.CELL_TYPE_ERROR:
- return ErrorEval.valueOf(cell.getErrorCellValue());
- }
- throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")");
- }
-
- /**
- * Mimics the 'data view' of a cell. This allows formula evaluator
- * to return a CellValue instead of precasting the value to String
- * or Number or boolean type.
- * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
- */
- public static final class CellValue {
- public static final CellValue TRUE = new CellValue(HSSFCell.CELL_TYPE_BOOLEAN, 0.0, true, null, 0);
- public static final CellValue FALSE= new CellValue(HSSFCell.CELL_TYPE_BOOLEAN, 0.0, false, null, 0);
-
- private final int _cellType;
- private final double _numberValue;
- private final boolean _booleanValue;
- private final String _textValue;
- private final int _errorCode;
-
- private CellValue(int cellType, double numberValue, boolean booleanValue,
- String textValue, int errorCode) {
- _cellType = cellType;
- _numberValue = numberValue;
- _booleanValue = booleanValue;
- _textValue = textValue;
- _errorCode = errorCode;
- }
-
-
- /* package*/ CellValue(double numberValue) {
- this(HSSFCell.CELL_TYPE_NUMERIC, numberValue, false, null, 0);
- }
- /* package*/ static CellValue valueOf(boolean booleanValue) {
- return booleanValue ? TRUE : FALSE;
- }
- /* package*/ CellValue(String stringValue) {
- this(HSSFCell.CELL_TYPE_STRING, 0.0, false, stringValue, 0);
- }
- /* package*/ static CellValue getError(int errorCode) {
- return new CellValue(HSSFCell.CELL_TYPE_ERROR, 0.0, false, null, errorCode);
- }
-
-
- /**
- * @return Returns the booleanValue.
- */
- public boolean getBooleanValue() {
- return _booleanValue;
- }
- /**
- * @return Returns the numberValue.
- */
- public double getNumberValue() {
- return _numberValue;
- }
- /**
- * @return Returns the stringValue.
- */
- public String getStringValue() {
- return _textValue;
- }
- /**
- * @return Returns the cellType.
- */
- public int getCellType() {
- return _cellType;
- }
- /**
- * @return Returns the errorValue.
- */
- public byte getErrorValue() {
- return (byte) _errorCode;
- }
- /**
- * @return Returns the richTextStringValue.
- * @deprecated (Sep 2008) Text formatting is lost during formula evaluation. Use {@link #getStringValue()}
- */
- public HSSFRichTextString getRichTextStringValue() {
- return new HSSFRichTextString(_textValue);
- }
- public String toString() {
- StringBuffer sb = new StringBuffer(64);
- sb.append(getClass().getName()).append(" [");
- sb.append(formatAsString());
- sb.append("]");
- return sb.toString();
- }
-
- public String formatAsString() {
- switch (_cellType) {
- case HSSFCell.CELL_TYPE_NUMERIC:
- return String.valueOf(_numberValue);
- case HSSFCell.CELL_TYPE_STRING:
- return '"' + _textValue + '"';
- case HSSFCell.CELL_TYPE_BOOLEAN:
- return _booleanValue ? "TRUE" : "FALSE";
- case HSSFCell.CELL_TYPE_ERROR:
- return ErrorEval.getText(_errorCode);
- }
- return "";
- }
- }
-
- /**
- * debug method
- */
- void inspectPtgs(String formula) {
- Ptg[] ptgs = FormulaParser.parse(formula, _workbook);
- System.out.println("");
- for (int i = 0, iSize = ptgs.length; i < iSize; i++) {
- System.out.println("");
- System.out.println(ptgs[i]);
- if (ptgs[i] instanceof OperationPtg) {
- System.out.println("numoperands: " + ((OperationPtg) ptgs[i]).getNumberOfOperands());
- }
- System.out.println("");
- }
- System.out.println("");
- }
-}
+/* ====================================================================
+ 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.usermodel;
+
+import java.util.Iterator;
+
+import org.apache.poi.hssf.record.formula.eval.BoolEval;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.ss.formula.WorkbookEvaluator;
+
+/**
+ * Evaluates formula cells.
+ *
+ * For performance reasons, this class keeps a cache of all previously calculated intermediate
+ * cell values. Be sure to call {@link #clearCache()} if any workbook cells are changed between
+ * calls to evaluate~ methods on this class.
+ *
+ * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
+ * @author Josh Micich
+ */
+public class HSSFFormulaEvaluator {
+
+ private WorkbookEvaluator _bookEvaluator;
+
+ /**
+ * @deprecated (Sep 2008) HSSFSheet parameter is ignored
+ */
+ public HSSFFormulaEvaluator(HSSFSheet sheet, HSSFWorkbook workbook) {
+ this(workbook);
+ if (false) {
+ sheet.toString(); // suppress unused parameter compiler warning
+ }
+ }
+ public HSSFFormulaEvaluator(HSSFWorkbook workbook) {
+ _bookEvaluator = new WorkbookEvaluator(HSSFEvaluationWorkbook.create(workbook));
+ }
+
+ /**
+ * TODO for debug/test use
+ */
+ /* package */ int getEvaluationCount() {
+ return _bookEvaluator.getEvaluationCount();
+ }
+
+ /**
+ * Does nothing
+ * @deprecated (Aug 2008) - not needed, since the current row can be derived from the cell
+ */
+ public void setCurrentRow(HSSFRow row) {
+ // do nothing
+ if (false) {
+ row.getClass(); // suppress unused parameter compiler warning
+ }
+ }
+
+ /**
+ * Should be called whenever there are major changes (e.g. moving sheets) to input cells
+ * in the evaluated workbook.
+ * Failure to call this method after changing cell values will cause incorrect behaviour
+ * of the evaluate~ methods of this class
+ */
+ public void clearAllCachedResultValues() {
+ _bookEvaluator.clearAllCachedResultValues();
+ }
+ /**
+ * Should be called whenever there are changes to individual input cells in the evaluated workbook.
+ * Failure to call this method after changing cell values will cause incorrect behaviour
+ * of the evaluate~ methods of this class
+ */
+ public void clearCachedResultValue(HSSFSheet sheet, int rowIndex, int columnIndex) {
+ _bookEvaluator.clearCachedResultValue(sheet, rowIndex, columnIndex);
+ }
+
+ /**
+ * If cell contains a formula, the formula is evaluated and returned,
+ * else the CellValue simply copies the appropriate cell value from
+ * the cell and also its cell type. This method should be preferred over
+ * evaluateInCell() when the call should not modify the contents of the
+ * original cell.
+ * @param cell
+ */
+ public CellValue evaluate(HSSFCell cell) {
+ if (cell == null) {
+ return null;
+ }
+
+ switch (cell.getCellType()) {
+ case HSSFCell.CELL_TYPE_BOOLEAN:
+ return CellValue.valueOf(cell.getBooleanCellValue());
+ case HSSFCell.CELL_TYPE_ERROR:
+ return CellValue.getError(cell.getErrorCellValue());
+ case HSSFCell.CELL_TYPE_FORMULA:
+ return evaluateFormulaCellValue(cell);
+ case HSSFCell.CELL_TYPE_NUMERIC:
+ return new CellValue(cell.getNumericCellValue());
+ case HSSFCell.CELL_TYPE_STRING:
+ return new CellValue(cell.getRichStringCellValue().getString());
+ }
+ throw new IllegalStateException("Bad cell type (" + cell.getCellType() + ")");
+ }
+
+
+ /**
+ * If cell contains formula, it evaluates the formula,
+ * and saves the result of the formula. The cell
+ * remains as a formula cell.
+ * Else if cell does not contain formula, this method leaves
+ * the cell unchanged.
+ * Note that the type of the formula result is returned,
+ * so you know what kind of value is also stored with
+ * the formula.
+ *
+ * int evaluatedCellType = evaluator.evaluateFormulaCell(cell);
+ *
+ * Be aware that your cell will hold both the formula,
+ * and the result. If you want the cell replaced with
+ * the result of the formula, use {@link #evaluateInCell(HSSFCell)}
+ * @param cell The cell to evaluate
+ * @return The type of the formula result (the cell's type remains as HSSFCell.CELL_TYPE_FORMULA however)
+ */
+ public int evaluateFormulaCell(HSSFCell cell) {
+ if (cell == null || cell.getCellType() != HSSFCell.CELL_TYPE_FORMULA) {
+ return -1;
+ }
+ CellValue cv = evaluateFormulaCellValue(cell);
+ // cell remains a formula cell, but the cached value is changed
+ setCellValue(cell, cv);
+ return cv.getCellType();
+ }
+
+ /**
+ * If cell contains formula, it evaluates the formula, and
+ * puts the formula result back into the cell, in place
+ * of the old formula.
+ * Else if cell does not contain formula, this method leaves
+ * the cell unchanged.
+ * Note that the same instance of HSSFCell is returned to
+ * allow chained calls like:
+ *
+ * int evaluatedCellType = evaluator.evaluateInCell(cell).getCellType();
+ *
+ * Be aware that your cell value will be changed to hold the
+ * result of the formula. If you simply want the formula
+ * value computed for you, use {@link #evaluateFormulaCell(HSSFCell)}
+ * @param cell
+ */
+ public HSSFCell evaluateInCell(HSSFCell cell) {
+ if (cell == null) {
+ return null;
+ }
+ if (cell.getCellType() == HSSFCell.CELL_TYPE_FORMULA) {
+ CellValue cv = evaluateFormulaCellValue(cell);
+ setCellType(cell, cv); // cell will no longer be a formula cell
+ setCellValue(cell, cv);
+ }
+ return cell;
+ }
+ private static void setCellType(HSSFCell cell, CellValue cv) {
+ int cellType = cv.getCellType();
+ switch (cellType) {
+ case HSSFCell.CELL_TYPE_BOOLEAN:
+ case HSSFCell.CELL_TYPE_ERROR:
+ case HSSFCell.CELL_TYPE_NUMERIC:
+ case HSSFCell.CELL_TYPE_STRING:
+ cell.setCellType(cellType);
+ return;
+ case HSSFCell.CELL_TYPE_BLANK:
+ // never happens - blanks eventually get translated to zero
+ case HSSFCell.CELL_TYPE_FORMULA:
+ // this will never happen, we have already evaluated the formula
+ }
+ throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
+ }
+
+ private static void setCellValue(HSSFCell cell, CellValue cv) {
+ int cellType = cv.getCellType();
+ switch (cellType) {
+ case HSSFCell.CELL_TYPE_BOOLEAN:
+ cell.setCellValue(cv.getBooleanValue());
+ break;
+ case HSSFCell.CELL_TYPE_ERROR:
+ cell.setCellErrorValue(cv.getErrorValue());
+ break;
+ case HSSFCell.CELL_TYPE_NUMERIC:
+ cell.setCellValue(cv.getNumberValue());
+ break;
+ case HSSFCell.CELL_TYPE_STRING:
+ cell.setCellValue(cv.getRichTextStringValue());
+ break;
+ case HSSFCell.CELL_TYPE_BLANK:
+ // never happens - blanks eventually get translated to zero
+ case HSSFCell.CELL_TYPE_FORMULA:
+ // this will never happen, we have already evaluated the formula
+ default:
+ throw new IllegalStateException("Unexpected cell value type (" + cellType + ")");
+ }
+ }
+
+ /**
+ * Loops over all cells in all sheets of the supplied
+ * workbook.
+ * For cells that contain formulas, their formulas are
+ * evaluated, and the results are saved. These cells
+ * remain as formula cells.
+ * For cells that do not contain formulas, no changes
+ * are made.
+ * This is a helpful wrapper around looping over all
+ * cells, and calling evaluateFormulaCell on each one.
+ */
+ public static void evaluateAllFormulaCells(HSSFWorkbook wb) {
+ HSSFFormulaEvaluator evaluator = new HSSFFormulaEvaluator(wb);
+ for(int i=0; i";
+ }
+ }
+}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFName.java b/src/java/org/apache/poi/hssf/usermodel/HSSFName.java
index 8c264e4a5..c24fa0508 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFName.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFName.java
@@ -95,7 +95,7 @@ public final class HSSFName {
*/
private void setSheetName(String sheetName){
int sheetNumber = _book.getSheetIndex(sheetName);
- short externSheetNumber = _book.getExternalSheetIndex(sheetNumber);
+ short externSheetNumber = _book.getWorkbook().checkExternSheet(sheetNumber);
_definedNameRec.setExternSheetNumber(externSheetNumber);
}
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
index a12aff5e1..25e24426a 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
@@ -661,52 +661,6 @@ public class HSSFWorkbook extends POIDocument
return -1;
}
- /* package */ int findSheetIndex(Sheet sheet) {
- for(int i=0; i<_sheets.size(); i++) {
- HSSFSheet hSheet = (HSSFSheet) _sheets.get(i);
- if(hSheet.getSheet() == sheet) {
- return i;
- }
- }
- throw new IllegalArgumentException("Specified sheet not found in this workbook");
- }
-
- /**
- * Returns the external sheet index of the sheet
- * with the given internal index, creating one
- * if needed.
- * Used by some of the more obscure formula and
- * named range things.
- * @deprecated for POI internal use only (formula parsing). This method is likely to
- * be removed in future versions of POI.
- */
- public short getExternalSheetIndex(int internalSheetIndex) {
- return workbook.checkExternSheet(internalSheetIndex);
- }
- /**
- * @deprecated for POI internal use only (formula rendering). This method is likely to
- * be removed in future versions of POI.
- */
- public String findSheetNameFromExternSheet(int externSheetIndex){
- // TODO - don't expose internal ugliness like externSheet indexes to the user model API
- return workbook.findSheetNameFromExternSheet(externSheetIndex);
- }
- /**
- * @deprecated for POI internal use only (formula rendering). This method is likely to
- * be removed in future versions of POI.
- *
- * @param refIndex Index to REF entry in EXTERNSHEET record in the Link Table
- * @param definedNameIndex zero-based to DEFINEDNAME or EXTERNALNAME record
- * @return the string representation of the defined or external name
- */
- public String resolveNameXText(int refIndex, int definedNameIndex) {
- // TODO - make this less cryptic / move elsewhere
- return workbook.resolveNameXText(refIndex, definedNameIndex);
- }
-
-
-
-
/**
* create an HSSFSheet for this HSSFWorkbook, adds it to the sheets and returns
* the high level representation. Use this to create new sheets.
@@ -750,7 +704,7 @@ public class HSSFWorkbook extends POIDocument
if (filterDbNameIndex >=0) {
NameRecord origNameRecord = workbook.getNameRecord(filterDbNameIndex);
// copy original formula but adjust 3D refs to the new external sheet index
- int newExtSheetIx = getExternalSheetIndex(newSheetIndex);
+ int newExtSheetIx = workbook.checkExternSheet(newSheetIndex);
Ptg[] ptgs = origNameRecord.getNameDefinition();
for (int i=0; i< ptgs.length; i++) {
Ptg ptg = ptgs[i];
diff --git a/src/java/org/apache/poi/ss/formula/CellEvaluationFrame.java b/src/java/org/apache/poi/ss/formula/CellEvaluationFrame.java
new file mode 100644
index 000000000..b6f542a08
--- /dev/null
+++ b/src/java/org/apache/poi/ss/formula/CellEvaluationFrame.java
@@ -0,0 +1,71 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ss.formula;
+
+/**
+ * Stores the parameters that identify the evaluation of one cell.
+ */
+final class CellEvaluationFrame {
+
+ private final int _sheetIndex;
+ private final int _srcRowNum;
+ private final int _srcColNum;
+ private final int _hashCode;
+
+ public CellEvaluationFrame(int sheetIndex, int srcRowNum, int srcColNum) {
+ if (sheetIndex < 0) {
+ throw new IllegalArgumentException("sheetIndex must not be negative");
+ }
+ _sheetIndex = sheetIndex;
+ _srcRowNum = srcRowNum;
+ _srcColNum = srcColNum;
+ _hashCode = sheetIndex + 17 * (srcRowNum + 17 * srcColNum);
+ }
+
+ public boolean equals(Object obj) {
+ CellEvaluationFrame other = (CellEvaluationFrame) obj;
+ if (_sheetIndex != other._sheetIndex) {
+ return false;
+ }
+ if (_srcRowNum != other._srcRowNum) {
+ return false;
+ }
+ if (_srcColNum != other._srcColNum) {
+ return false;
+ }
+ return true;
+ }
+ public int hashCode() {
+ return _hashCode;
+ }
+
+ /**
+ * @return human readable string for debug purposes
+ */
+ public String formatAsString() {
+ return "R=" + _srcRowNum + " C=" + _srcColNum + " ShIx=" + _sheetIndex;
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer(64);
+ sb.append(getClass().getName()).append(" [");
+ sb.append(formatAsString());
+ sb.append("]");
+ return sb.toString();
+ }
+}
\ No newline at end of file
diff --git a/src/java/org/apache/poi/ss/formula/CellEvaluator.java b/src/java/org/apache/poi/ss/formula/CellEvaluator.java
new file mode 100644
index 000000000..22846c2d4
--- /dev/null
+++ b/src/java/org/apache/poi/ss/formula/CellEvaluator.java
@@ -0,0 +1,54 @@
+package org.apache.poi.ss.formula;
+
+import org.apache.poi.hssf.record.formula.eval.BlankEval;
+import org.apache.poi.hssf.record.formula.eval.BoolEval;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+
+final class CellEvaluator {
+
+ private final WorkbookEvaluator _bookEvaluator;
+ private final EvaluationTracker _tracker;
+
+ public CellEvaluator(WorkbookEvaluator bookEvaluator, EvaluationTracker tracker) {
+ _bookEvaluator = bookEvaluator;
+ _tracker = tracker;
+ }
+
+ /**
+ * Given a cell, find its type and from that create an appropriate ValueEval
+ * impl instance and return that. Since the cell could be an external
+ * reference, we need the sheet that this belongs to.
+ * Non existent cells are treated as empty.
+ */
+ public ValueEval getEvalForCell(HSSFCell cell) {
+
+ if (cell == null) {
+ return BlankEval.INSTANCE;
+ }
+ switch (cell.getCellType()) {
+ case HSSFCell.CELL_TYPE_NUMERIC:
+ return new NumberEval(cell.getNumericCellValue());
+ case HSSFCell.CELL_TYPE_STRING:
+ return new StringEval(cell.getRichStringCellValue().getString());
+ case HSSFCell.CELL_TYPE_FORMULA:
+ return _bookEvaluator.internalEvaluate(cell, _tracker);
+ case HSSFCell.CELL_TYPE_BOOLEAN:
+ return BoolEval.valueOf(cell.getBooleanCellValue());
+ case HSSFCell.CELL_TYPE_BLANK:
+ return BlankEval.INSTANCE;
+ case HSSFCell.CELL_TYPE_ERROR:
+ return ErrorEval.valueOf(cell.getErrorCellValue());
+ }
+ throw new RuntimeException("Unexpected cell type (" + cell.getCellType() + ")");
+ }
+
+ public String getSheetName(HSSFSheet sheet) {
+ return _bookEvaluator.getSheetName(sheet);
+ }
+
+}
diff --git a/src/java/org/apache/poi/hssf/usermodel/EvaluationCache.java b/src/java/org/apache/poi/ss/formula/EvaluationCache.java
similarity index 58%
rename from src/java/org/apache/poi/hssf/usermodel/EvaluationCache.java
rename to src/java/org/apache/poi/ss/formula/EvaluationCache.java
index 97c4d6eed..d78f4a728 100644
--- a/src/java/org/apache/poi/hssf/usermodel/EvaluationCache.java
+++ b/src/java/org/apache/poi/ss/formula/EvaluationCache.java
@@ -15,12 +15,14 @@
limitations under the License.
==================================================================== */
-package org.apache.poi.hssf.usermodel;
+package org.apache.poi.ss.formula;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
/**
* Performance optimisation for {@link HSSFFormulaEvaluator}. This class stores previously
@@ -31,55 +33,29 @@ import org.apache.poi.hssf.record.formula.eval.ValueEval;
* @author Josh Micich
*/
final class EvaluationCache {
- private static final class Key {
-
- private final int _sheetIndex;
- private final int _srcRowNum;
- private final int _srcColNum;
- private final int _hashCode;
-
- public Key(int sheetIndex, int srcRowNum, int srcColNum) {
- _sheetIndex = sheetIndex;
- _srcRowNum = srcRowNum;
- _srcColNum = srcColNum;
- _hashCode = sheetIndex + srcRowNum + srcColNum;
- }
-
- public int hashCode() {
- return _hashCode;
- }
-
- public boolean equals(Object obj) {
- Key other = (Key) obj;
- if (_hashCode != other._hashCode) {
- return false;
- }
- if (_sheetIndex != other._sheetIndex) {
- return false;
- }
- if (_srcRowNum != other._srcRowNum) {
- return false;
- }
- if (_srcColNum != other._srcColNum) {
- return false;
- }
- return true;
- }
- }
+ private static final CellEvaluationFrame[] EMPTY_CEF_ARRAY = { };
private final Map _valuesByKey;
+ private final Map _consumingCellsByDest;
/* package */EvaluationCache() {
_valuesByKey = new HashMap();
+ _consumingCellsByDest = new HashMap();
}
public ValueEval getValue(int sheetIndex, int srcRowNum, int srcColNum) {
- Key key = new Key(sheetIndex, srcRowNum, srcColNum);
+ return getValue(new CellEvaluationFrame(sheetIndex, srcRowNum, srcColNum));
+ }
+
+ /* package */ ValueEval getValue(CellEvaluationFrame key) {
return (ValueEval) _valuesByKey.get(key);
}
public void setValue(int sheetIndex, int srcRowNum, int srcColNum, ValueEval value) {
- Key key = new Key(sheetIndex, srcRowNum, srcColNum);
+ setValue(new CellEvaluationFrame(sheetIndex, srcRowNum, srcColNum), value);
+ }
+
+ /* package */ void setValue(CellEvaluationFrame key, ValueEval value) {
if (_valuesByKey.containsKey(key)) {
throw new RuntimeException("Already have cached value for this cell");
}
@@ -92,4 +68,32 @@ final class EvaluationCache {
public void clear() {
_valuesByKey.clear();
}
+
+ public void clearValue(int sheetIndex, int rowIndex, int columnIndex) {
+ clearValuesRecursive(new CellEvaluationFrame(sheetIndex, rowIndex, columnIndex));
+
+ }
+
+ private void clearValuesRecursive(CellEvaluationFrame cef) {
+ CellEvaluationFrame[] consumingCells = getConsumingCells(cef);
+ for (int i = 0; i < consumingCells.length; i++) {
+ clearValuesRecursive(consumingCells[i]);
+ }
+ _valuesByKey.remove(cef);
+ _consumingCellsByDest.remove(cef);
+ }
+
+ private CellEvaluationFrame[] getConsumingCells(CellEvaluationFrame cef) {
+ List temp = (List) _consumingCellsByDest.get(cef);
+ if (temp == null) {
+ return EMPTY_CEF_ARRAY;
+ }
+ int nItems = temp.size();
+ if (temp.size() < 1) {
+ return EMPTY_CEF_ARRAY;
+ }
+ CellEvaluationFrame[] result = new CellEvaluationFrame[nItems];
+ temp.toArray(result);
+ return result;
+ }
}
diff --git a/src/java/org/apache/poi/ss/formula/EvaluationName.java b/src/java/org/apache/poi/ss/formula/EvaluationName.java
new file mode 100644
index 000000000..ae8624c7b
--- /dev/null
+++ b/src/java/org/apache/poi/ss/formula/EvaluationName.java
@@ -0,0 +1,41 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ss.formula;
+
+import org.apache.poi.hssf.record.formula.NamePtg;
+import org.apache.poi.hssf.record.formula.Ptg;
+/**
+ * Abstracts a name record for formula evaluation.
+ *
+ * For POI internal use only
+ *
+ * @author Josh Micich
+ */
+public interface EvaluationName {
+
+ String getNameText();
+
+ boolean isFunctionName();
+
+ boolean hasFormula();
+
+ Ptg[] getNameDefinition();
+
+ boolean isRange();
+ NamePtg createPtg();
+}
diff --git a/src/java/org/apache/poi/hssf/usermodel/EvaluationCycleDetector.java b/src/java/org/apache/poi/ss/formula/EvaluationTracker.java
similarity index 61%
rename from src/java/org/apache/poi/hssf/usermodel/EvaluationCycleDetector.java
rename to src/java/org/apache/poi/ss/formula/EvaluationTracker.java
index 0c168af6b..20ab3299a 100755
--- a/src/java/org/apache/poi/hssf/usermodel/EvaluationCycleDetector.java
+++ b/src/java/org/apache/poi/ss/formula/EvaluationTracker.java
@@ -15,81 +15,31 @@
limitations under the License.
==================================================================== */
-package org.apache.poi.hssf.usermodel;
+package org.apache.poi.ss.formula;
import java.util.ArrayList;
import java.util.List;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+
/**
* Instances of this class keep track of multiple dependent cell evaluations due
- * to recursive calls to HSSFFormulaEvaluator.internalEvaluate().
+ * to recursive calls to {@link WorkbookEvaluator#evaluate(HSSFCell)}
* The main purpose of this class is to detect an attempt to evaluate a cell
* that is already being evaluated. In other words, it detects circular
* references in spreadsheet formulas.
*
* @author Josh Micich
*/
-final class EvaluationCycleDetector {
-
- /**
- * Stores the parameters that identify the evaluation of one cell.
- */
- private static final class CellEvaluationFrame {
-
- private final HSSFWorkbook _workbook;
- private final int _sheetIndex;
- private final int _srcRowNum;
- private final int _srcColNum;
-
- public CellEvaluationFrame(HSSFWorkbook workbook, int sheetIndex, int srcRowNum, int srcColNum) {
- if (workbook == null) {
- throw new IllegalArgumentException("workbook must not be null");
- }
- if (sheetIndex < 0) {
- throw new IllegalArgumentException("sheetIndex must not be negative");
- }
- _workbook = workbook;
- _sheetIndex = sheetIndex;
- _srcRowNum = srcRowNum;
- _srcColNum = srcColNum;
- }
-
- public boolean equals(Object obj) {
- CellEvaluationFrame other = (CellEvaluationFrame) obj;
- if (_workbook != other._workbook) {
- return false;
- }
- if (_sheetIndex != other._sheetIndex) {
- return false;
- }
- if (_srcRowNum != other._srcRowNum) {
- return false;
- }
- if (_srcColNum != other._srcColNum) {
- return false;
- }
- return true;
- }
-
- /**
- * @return human readable string for debug purposes
- */
- public String formatAsString() {
- return "R=" + _srcRowNum + " C=" + _srcColNum + " ShIx=" + _sheetIndex;
- }
-
- public String toString() {
- StringBuffer sb = new StringBuffer(64);
- sb.append(getClass().getName()).append(" [");
- sb.append(formatAsString());
- sb.append("]");
- return sb.toString();
- }
- }
+final class EvaluationTracker {
private final List _evaluationFrames;
+ private final EvaluationCache _cache;
- public EvaluationCycleDetector() {
+ public EvaluationTracker(EvaluationCache cache) {
+ _cache = cache;
_evaluationFrames = new ArrayList();
}
@@ -108,13 +58,16 @@ final class EvaluationCycleDetector {
* @return true
if the specified cell has not been visited yet in the current
* evaluation. false
if the specified cell is already being evaluated.
*/
- public boolean startEvaluate(HSSFWorkbook workbook, int sheetIndex, int srcRowNum, int srcColNum) {
- CellEvaluationFrame cef = new CellEvaluationFrame(workbook, sheetIndex, srcRowNum, srcColNum);
+ public ValueEval startEvaluate(int sheetIndex, int srcRowNum, int srcColNum) {
+ CellEvaluationFrame cef = new CellEvaluationFrame(sheetIndex, srcRowNum, srcColNum);
if (_evaluationFrames.contains(cef)) {
- return false;
+ return ErrorEval.CIRCULAR_REF_ERROR;
}
- _evaluationFrames.add(cef);
- return true;
+ ValueEval result = _cache.getValue(cef);
+ if (result == null) {
+ _evaluationFrames.add(cef);
+ }
+ return result;
}
/**
@@ -128,8 +81,9 @@ final class EvaluationCycleDetector {
* Assuming a well behaved client, parameters to this method would not be
* required. However, they have been included to assert correct behaviour,
* and form more meaningful error messages.
+ * @param result
*/
- public void endEvaluate(HSSFWorkbook workbook, int sheetIndex, int srcRowNum, int srcColNum) {
+ public void endEvaluate(int sheetIndex, int srcRowNum, int srcColNum, ValueEval result) {
int nFrames = _evaluationFrames.size();
if (nFrames < 1) {
throw new IllegalStateException("Call to endEvaluate without matching call to startEvaluate");
@@ -137,7 +91,7 @@ final class EvaluationCycleDetector {
nFrames--;
CellEvaluationFrame cefExpected = (CellEvaluationFrame) _evaluationFrames.get(nFrames);
- CellEvaluationFrame cefActual = new CellEvaluationFrame(workbook, sheetIndex, srcRowNum, srcColNum);
+ CellEvaluationFrame cefActual = new CellEvaluationFrame(sheetIndex, srcRowNum, srcColNum);
if (!cefActual.equals(cefExpected)) {
throw new RuntimeException("Wrong cell specified. "
+ "Corresponding startEvaluate() call was for cell {"
@@ -146,5 +100,7 @@ final class EvaluationCycleDetector {
}
// else - no problems so pop current frame
_evaluationFrames.remove(nFrames);
+
+ _cache.setValue(cefActual, result);
}
}
diff --git a/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java b/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java
new file mode 100644
index 000000000..29083f7a5
--- /dev/null
+++ b/src/java/org/apache/poi/ss/formula/EvaluationWorkbook.java
@@ -0,0 +1,42 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ss.formula;
+
+import org.apache.poi.hssf.record.formula.NamePtg;
+import org.apache.poi.hssf.record.formula.NameXPtg;
+import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+/**
+ * Abstracts a workbook for the purpose of formula evaluation.
+ *
+ * For POI internal use only
+ *
+ * @author Josh Micich
+ */
+public interface EvaluationWorkbook {
+ String getSheetName(int sheetIndex);
+ int getSheetIndex(HSSFSheet sheet);
+
+ HSSFSheet getSheet(int sheetIndex);
+
+ HSSFSheet getSheetByExternSheetIndex(int externSheetIndex);
+ EvaluationName getName(NamePtg namePtg);
+ String resolveNameXText(NameXPtg ptg);
+ Ptg[] getFormulaTokens(HSSFCell cell);
+}
diff --git a/src/java/org/apache/poi/hssf/model/FormulaParser.java b/src/java/org/apache/poi/ss/formula/FormulaParser.java
similarity index 89%
rename from src/java/org/apache/poi/hssf/model/FormulaParser.java
rename to src/java/org/apache/poi/ss/formula/FormulaParser.java
index a24c7be60..df2f8c282 100644
--- a/src/java/org/apache/poi/hssf/model/FormulaParser.java
+++ b/src/java/org/apache/poi/ss/formula/FormulaParser.java
@@ -15,7 +15,7 @@
limitations under the License.
==================================================================== */
-package org.apache.poi.hssf.model;
+package org.apache.poi.ss.formula;
import java.util.ArrayList;
import java.util.List;
@@ -58,14 +58,9 @@ import org.apache.poi.hssf.record.formula.UnaryPlusPtg;
import org.apache.poi.hssf.record.formula.function.FunctionMetadata;
import org.apache.poi.hssf.record.formula.function.FunctionMetadataRegistry;
import org.apache.poi.hssf.usermodel.HSSFErrorConstants;
-import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
-import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator;
-import org.apache.poi.hssf.usermodel.HSSFName;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.AreaReference;
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.hssf.util.CellReference.NameType;
-import org.apache.poi.ss.formula.FormulaRenderer;
/**
* This class parses a formula string into a List of tokens in RPN order.
@@ -83,6 +78,7 @@ import org.apache.poi.ss.formula.FormulaRenderer;
* @author Cameron Riley (criley at ekmail.com)
* @author Peter M. Murray (pete at quantrix dot com)
* @author Pavel Krupets (pkrupets at palmtreebusiness dot com)
+ * @author Josh Micich
*/
public final class FormulaParser {
@@ -99,14 +95,6 @@ public final class FormulaParser {
}
}
- public static final int FORMULA_TYPE_CELL = 0;
- public static final int FORMULA_TYPE_SHARED = 1;
- public static final int FORMULA_TYPE_ARRAY =2;
- public static final int FORMULA_TYPE_CONDFORMAT = 3;
- public static final int FORMULA_TYPE_NAMEDRANGE = 4;
- // this constant is currently very specific. The exact differences from general data
- // validation formulas or conditional format formulas is not known yet
- public static final int FORMULA_TYPE_DATAVALIDATION_LIST = 5;
private final String formulaString;
private final int formulaLength;
@@ -122,7 +110,8 @@ public final class FormulaParser {
*/
private char look;
- private HSSFWorkbook book;
+ private FormulaParsingWorkbook book;
+
/**
@@ -137,19 +126,19 @@ public final class FormulaParser {
* model.Workbook, then use the convenience method on
* usermodel.HSSFFormulaEvaluator
*/
- public FormulaParser(String formula, HSSFWorkbook book){
+ private FormulaParser(String formula, FormulaParsingWorkbook book){
formulaString = formula;
pointer=0;
this.book = book;
formulaLength = formulaString.length();
}
- public static Ptg[] parse(String formula, HSSFWorkbook book) {
- return parse(formula, book, FORMULA_TYPE_CELL);
+ public static Ptg[] parse(String formula, FormulaParsingWorkbook book) {
+ return parse(formula, book, FormulaType.CELL);
}
- public static Ptg[] parse(String formula, HSSFWorkbook workbook, int formulaType) {
- FormulaParser fp = HSSFFormulaEvaluator.getUnderlyingParser(workbook, formula);
+ public static Ptg[] parse(String formula, FormulaParsingWorkbook workbook, int formulaType) {
+ FormulaParser fp = new FormulaParser(formula, workbook);
fp.parse();
return fp.getRPNPtg(formulaType);
}
@@ -308,7 +297,7 @@ public final class FormulaParser {
Match('!');
String sheetName = name;
String first = parseIdentifier();
- short externIdx = book.getExternalSheetIndex(book.getSheetIndex(sheetName));
+ int externIdx = book.getExternalSheetIndex(sheetName);
areaRef = parseArea(name);
if (areaRef != null) {
// will happen if dots are used instead of colon
@@ -330,7 +319,7 @@ public final class FormulaParser {
}
return new Area3DPtg(first+":"+second,externIdx);
}
- return new Ref3DPtg(first,externIdx);
+ return new Ref3DPtg(first, externIdx);
}
if (name.equalsIgnoreCase("TRUE") || name.equalsIgnoreCase("FALSE")) {
return new BoolPtg(name.toUpperCase());
@@ -346,15 +335,16 @@ public final class FormulaParser {
new FormulaParseException("Name '" + name
+ "' does not look like a cell reference or named range");
}
-
- for(int i = 0; i < book.getNumberOfNames(); i++) {
- // named range name matching is case insensitive
- if(book.getNameAt(i).getNameName().equalsIgnoreCase(name)) {
- return new NamePtg(i);
- }
- }
- throw new FormulaParseException("Specified named range '"
+ EvaluationName evalName = book.getName(name);
+ if (evalName == null) {
+ throw new FormulaParseException("Specified named range '"
+ name + "' does not exist in the current workbook.");
+ }
+ if (evalName.isRange()) {
+ return evalName.createPtg();
+ }
+ throw new FormulaParseException("Specified name '"
+ + name + "' is not a range as expected");
}
/**
@@ -410,10 +400,15 @@ public final class FormulaParser {
// user defined function
// in the token tree, the name is more or less the first argument
+ EvaluationName hName = book.getName(name);
+ if (hName == null) {
- int nameIndex = book.getNameIndex(name);
- if (nameIndex >= 0) {
- HSSFName hName = book.getNameAt(nameIndex);
+ nameToken = book.getNameXPtg(name);
+ if (nameToken == null) {
+ throw new FormulaParseException("Name '" + name
+ + "' is completely unknown in the current workbook");
+ }
+ } else {
if (!hName.isFunctionName()) {
throw new FormulaParseException("Attempt to use name '" + name
+ "' as a function, but defined name in workbook does not refer to a function");
@@ -421,14 +416,7 @@ public final class FormulaParser {
// calls to user-defined functions within the workbook
// get a Name token which points to a defined name record
- nameToken = new NamePtg(nameIndex);
- } else {
-
- nameToken = book.getNameXPtg(name);
- if (nameToken == null) {
- throw new FormulaParseException("Name '" + name
- + "' is completely unknown in the current workbook");
- }
+ nameToken = hName.createPtg();
}
}
@@ -965,9 +953,9 @@ end;
/**
* API call to execute the parsing of the formula
- * @deprecated use {@link #parse(String, HSSFWorkbook)} directly
+ *
*/
- public void parse() {
+ private void parse() {
pointer=0;
GetChar();
_rootNode = comparisonExpression();
@@ -979,60 +967,10 @@ end;
}
}
-
- /*********************************
- * PARSER IMPLEMENTATION ENDS HERE
- * EXCEL SPECIFIC METHODS BELOW
- *******************************/
-
- /** API call to retrive the array of Ptgs created as
- * a result of the parsing
- */
- public Ptg[] getRPNPtg() {
- return getRPNPtg(FORMULA_TYPE_CELL);
- }
-
- public Ptg[] getRPNPtg(int formulaType) {
+ private Ptg[] getRPNPtg(int formulaType) {
OperandClassTransformer oct = new OperandClassTransformer(formulaType);
// RVA is for 'operand class': 'reference', 'value', 'array'
oct.transformFormula(_rootNode);
return ParseNode.toTokenArray(_rootNode);
}
-
- /**
- * Convenience method which takes in a list then passes it to the
- * other toFormulaString signature.
- * @param book workbook for 3D and named references
- * @param lptgs list of Ptg, can be null or empty
- * @return a human readable String
- */
- public static String toFormulaString(HSSFWorkbook book, List lptgs) {
- String retval = null;
- if (lptgs == null || lptgs.size() == 0) return "#NAME";
- Ptg[] ptgs = new Ptg[lptgs.size()];
- ptgs = (Ptg[])lptgs.toArray(ptgs);
- retval = toFormulaString(book, ptgs);
- return retval;
- }
- /**
- * Convenience method which takes in a list then passes it to the
- * other toFormulaString signature. Works on the current
- * workbook for 3D and named references
- * @param lptgs list of Ptg, can be null or empty
- * @return a human readable String
- */
- public String toFormulaString(List lptgs) {
- return toFormulaString(book, lptgs);
- }
-
- /**
- * Static method to convert an array of Ptgs in RPN order
- * to a human readable string format in infix mode.
- * @param book workbook for named and 3D references
- * @param ptgs array of Ptg, can be null or empty
- * @return a human readable String
- */
- public static String toFormulaString(HSSFWorkbook book, Ptg[] ptgs) {
- return FormulaRenderer.toFormulaString(HSSFEvaluationWorkbook.create(book), ptgs);
- }
}
diff --git a/src/java/org/apache/poi/ss/formula/FormulaParsingWorkbook.java b/src/java/org/apache/poi/ss/formula/FormulaParsingWorkbook.java
new file mode 100644
index 000000000..69431c2c2
--- /dev/null
+++ b/src/java/org/apache/poi/ss/formula/FormulaParsingWorkbook.java
@@ -0,0 +1,37 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ss.formula;
+
+import org.apache.poi.hssf.record.formula.NameXPtg;
+
+/**
+ * Abstracts a workbook for the purpose of formula parsing.
+ *
+ * For POI internal use only
+ *
+ * @author Josh Micich
+ */
+public interface FormulaParsingWorkbook {
+ /**
+ * named range name matching is case insensitive
+ */
+ EvaluationName getName(String name);
+
+ int getExternalSheetIndex(String sheetName);
+ NameXPtg getNameXPtg(String name);
+}
diff --git a/src/java/org/apache/poi/ss/formula/FormulaRenderer.java b/src/java/org/apache/poi/ss/formula/FormulaRenderer.java
index 21386cd0d..980c345d3 100644
--- a/src/java/org/apache/poi/ss/formula/FormulaRenderer.java
+++ b/src/java/org/apache/poi/ss/formula/FormulaRenderer.java
@@ -1,3 +1,20 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
package org.apache.poi.ss.formula;
import java.util.List;
@@ -11,6 +28,13 @@ import org.apache.poi.hssf.record.formula.OperationPtg;
import org.apache.poi.hssf.record.formula.ParenthesisPtg;
import org.apache.poi.hssf.record.formula.Ptg;
+/**
+ * Common logic for rendering formulas.
+ *
+ * For POI internal use only
+ *
+ * @author Josh Micich
+ */
public class FormulaRenderer {
/**
* Convenience method which takes in a list then passes it to the
diff --git a/src/java/org/apache/poi/ss/formula/FormulaRenderingWorkbook.java b/src/java/org/apache/poi/ss/formula/FormulaRenderingWorkbook.java
index 3a92aa8cb..ac95f4da0 100644
--- a/src/java/org/apache/poi/ss/formula/FormulaRenderingWorkbook.java
+++ b/src/java/org/apache/poi/ss/formula/FormulaRenderingWorkbook.java
@@ -1,8 +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.ss.formula;
import org.apache.poi.hssf.record.formula.NamePtg;
import org.apache.poi.hssf.record.formula.NameXPtg;
+/**
+ * Abstracts a workbook for the purpose of converting formula to text.
+ *
+ * For POI internal use only
+ *
+ * @author Josh Micich
+ */
public interface FormulaRenderingWorkbook {
String getSheetNameByExternSheet(int externSheetIndex);
diff --git a/src/java/org/apache/poi/hssf/usermodel/EvaluationCycleDetectorManager.java b/src/java/org/apache/poi/ss/formula/FormulaType.java
old mode 100755
new mode 100644
similarity index 59%
rename from src/java/org/apache/poi/hssf/usermodel/EvaluationCycleDetectorManager.java
rename to src/java/org/apache/poi/ss/formula/FormulaType.java
index a06cd201e..3b47030d4
--- a/src/java/org/apache/poi/hssf/usermodel/EvaluationCycleDetectorManager.java
+++ b/src/java/org/apache/poi/ss/formula/FormulaType.java
@@ -1,46 +1,40 @@
-/* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-==================================================================== */
-
-package org.apache.poi.hssf.usermodel;
-
-/**
- * This class makes an EvaluationCycleDetector instance available to
- * each thread via a ThreadLocal in order to avoid adding a parameter
- * to a few protected methods within HSSFFormulaEvaluator.
- *
- * @author Josh Micich
- */
-final class EvaluationCycleDetectorManager {
-
- ThreadLocal tl = null;
- private static ThreadLocal _tlEvaluationTracker = new ThreadLocal() {
- protected synchronized Object initialValue() {
- return new EvaluationCycleDetector();
- }
- };
-
- /**
- * @return
- */
- public static EvaluationCycleDetector getTracker() {
- return (EvaluationCycleDetector) _tlEvaluationTracker.get();
- }
-
- private EvaluationCycleDetectorManager() {
- // no instances of this class
- }
-}
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ss.formula;
+
+/**
+ * Enumeration of various formula types.
+ *
+ * For POI internal use only
+ *
+ * @author Josh Micich
+ */
+public final class FormulaType {
+ private FormulaType() {
+ // no instances of this class
+ }
+ public static final int CELL = 0;
+ public static final int SHARED = 1;
+ public static final int ARRAY =2;
+ public static final int CONDFORMAT = 3;
+ public static final int NAMEDRANGE = 4;
+ // this constant is currently very specific. The exact differences from general data
+ // validation formulas or conditional format formulas is not known yet
+ public static final int DATAVALIDATION_LIST = 5;
+
+}
diff --git a/src/java/org/apache/poi/hssf/usermodel/LazyAreaEval.java b/src/java/org/apache/poi/ss/formula/LazyAreaEval.java
similarity index 90%
rename from src/java/org/apache/poi/hssf/usermodel/LazyAreaEval.java
rename to src/java/org/apache/poi/ss/formula/LazyAreaEval.java
index 0e1d1fd00..07c368ed0 100644
--- a/src/java/org/apache/poi/hssf/usermodel/LazyAreaEval.java
+++ b/src/java/org/apache/poi/ss/formula/LazyAreaEval.java
@@ -15,7 +15,7 @@
limitations under the License.
==================================================================== */
-package org.apache.poi.hssf.usermodel;
+package org.apache.poi.ss.formula;
import org.apache.poi.hssf.record.formula.AreaI;
import org.apache.poi.hssf.record.formula.AreaI.OffsetArea;
@@ -23,6 +23,9 @@ import org.apache.poi.hssf.record.formula.eval.AreaEval;
import org.apache.poi.hssf.record.formula.eval.AreaEvalBase;
import org.apache.poi.hssf.record.formula.eval.BlankEval;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.util.CellReference;
/**
@@ -32,9 +35,9 @@ import org.apache.poi.hssf.util.CellReference;
final class LazyAreaEval extends AreaEvalBase {
private final HSSFSheet _sheet;
- private HSSFFormulaEvaluator _evaluator;
+ private final CellEvaluator _evaluator;
- public LazyAreaEval(AreaI ptg, HSSFSheet sheet, HSSFFormulaEvaluator evaluator) {
+ public LazyAreaEval(AreaI ptg, HSSFSheet sheet, CellEvaluator evaluator) {
super(ptg);
_sheet = sheet;
_evaluator = evaluator;
diff --git a/src/java/org/apache/poi/hssf/usermodel/LazyRefEval.java b/src/java/org/apache/poi/ss/formula/LazyRefEval.java
similarity index 85%
rename from src/java/org/apache/poi/hssf/usermodel/LazyRefEval.java
rename to src/java/org/apache/poi/ss/formula/LazyRefEval.java
index d26ac59ff..fa1f3a383 100644
--- a/src/java/org/apache/poi/hssf/usermodel/LazyRefEval.java
+++ b/src/java/org/apache/poi/ss/formula/LazyRefEval.java
@@ -15,7 +15,7 @@
limitations under the License.
==================================================================== */
-package org.apache.poi.hssf.usermodel;
+package org.apache.poi.ss.formula;
import org.apache.poi.hssf.record.formula.AreaI;
import org.apache.poi.hssf.record.formula.Ref3DPtg;
@@ -25,6 +25,9 @@ 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.RefEvalBase;
import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.util.CellReference;
/**
@@ -34,15 +37,15 @@ import org.apache.poi.hssf.util.CellReference;
final class LazyRefEval extends RefEvalBase {
private final HSSFSheet _sheet;
- private final HSSFFormulaEvaluator _evaluator;
+ private final CellEvaluator _evaluator;
- public LazyRefEval(RefPtg ptg, HSSFSheet sheet, HSSFFormulaEvaluator evaluator) {
+ public LazyRefEval(RefPtg ptg, HSSFSheet sheet, CellEvaluator evaluator) {
super(ptg.getRow(), ptg.getColumn());
_sheet = sheet;
_evaluator = evaluator;
}
- public LazyRefEval(Ref3DPtg ptg, HSSFSheet sheet, HSSFFormulaEvaluator evaluator) {
+ public LazyRefEval(Ref3DPtg ptg, HSSFSheet sheet, CellEvaluator evaluator) {
super(ptg.getRow(), ptg.getColumn());
_sheet = sheet;
_evaluator = evaluator;
diff --git a/src/java/org/apache/poi/hssf/model/OperandClassTransformer.java b/src/java/org/apache/poi/ss/formula/OperandClassTransformer.java
similarity index 98%
rename from src/java/org/apache/poi/hssf/model/OperandClassTransformer.java
rename to src/java/org/apache/poi/ss/formula/OperandClassTransformer.java
index 8b7b56638..79087e4d6 100644
--- a/src/java/org/apache/poi/hssf/model/OperandClassTransformer.java
+++ b/src/java/org/apache/poi/ss/formula/OperandClassTransformer.java
@@ -15,7 +15,7 @@
limitations under the License.
==================================================================== */
-package org.apache.poi.hssf.model;
+package org.apache.poi.ss.formula;
import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
import org.apache.poi.hssf.record.formula.ControlPtg;
@@ -63,10 +63,10 @@ final class OperandClassTransformer {
public void transformFormula(ParseNode rootNode) {
byte rootNodeOperandClass;
switch (_formulaType) {
- case FormulaParser.FORMULA_TYPE_CELL:
+ case FormulaType.CELL:
rootNodeOperandClass = Ptg.CLASS_VALUE;
break;
- case FormulaParser.FORMULA_TYPE_DATAVALIDATION_LIST:
+ case FormulaType.DATAVALIDATION_LIST:
rootNodeOperandClass = Ptg.CLASS_REF;
break;
default:
diff --git a/src/java/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java b/src/java/org/apache/poi/ss/formula/OperationEvaluatorFactory.java
similarity index 99%
rename from src/java/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java
rename to src/java/org/apache/poi/ss/formula/OperationEvaluatorFactory.java
index 21dc06759..eaa57c114 100755
--- a/src/java/org/apache/poi/hssf/usermodel/OperationEvaluatorFactory.java
+++ b/src/java/org/apache/poi/ss/formula/OperationEvaluatorFactory.java
@@ -15,7 +15,7 @@
limitations under the License.
==================================================================== */
-package org.apache.poi.hssf.usermodel;
+package org.apache.poi.ss.formula;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
diff --git a/src/java/org/apache/poi/hssf/model/ParseNode.java b/src/java/org/apache/poi/ss/formula/ParseNode.java
similarity index 99%
rename from src/java/org/apache/poi/hssf/model/ParseNode.java
rename to src/java/org/apache/poi/ss/formula/ParseNode.java
index acd8cb12b..75685dee6 100644
--- a/src/java/org/apache/poi/hssf/model/ParseNode.java
+++ b/src/java/org/apache/poi/ss/formula/ParseNode.java
@@ -15,7 +15,7 @@
limitations under the License.
==================================================================== */
-package org.apache.poi.hssf.model;
+package org.apache.poi.ss.formula;
import org.apache.poi.hssf.record.formula.AttrPtg;
import org.apache.poi.hssf.record.formula.FuncVarPtg;
diff --git a/src/java/org/apache/poi/ss/formula/WorkbookDependentFormula.java b/src/java/org/apache/poi/ss/formula/WorkbookDependentFormula.java
index 420527dd8..b7ccfaf0e 100644
--- a/src/java/org/apache/poi/ss/formula/WorkbookDependentFormula.java
+++ b/src/java/org/apache/poi/ss/formula/WorkbookDependentFormula.java
@@ -1,5 +1,30 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
package org.apache.poi.ss.formula;
+/**
+ * Should be implemented by any {@link Ptg} subclass that needs a workbook to render its formula.
+ *
+ *
+ * For POI internal use only
+ *
+ * @author Josh Micich
+ */
public interface WorkbookDependentFormula {
String toFormulaString(FormulaRenderingWorkbook book);
}
diff --git a/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java b/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
new file mode 100644
index 000000000..199d35b66
--- /dev/null
+++ b/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
@@ -0,0 +1,348 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ss.formula;
+
+import java.util.Stack;
+
+import org.apache.poi.hssf.record.formula.Area3DPtg;
+import org.apache.poi.hssf.record.formula.AreaPtg;
+import org.apache.poi.hssf.record.formula.BoolPtg;
+import org.apache.poi.hssf.record.formula.ControlPtg;
+import org.apache.poi.hssf.record.formula.ErrPtg;
+import org.apache.poi.hssf.record.formula.IntPtg;
+import org.apache.poi.hssf.record.formula.MemErrPtg;
+import org.apache.poi.hssf.record.formula.MissingArgPtg;
+import org.apache.poi.hssf.record.formula.NamePtg;
+import org.apache.poi.hssf.record.formula.NameXPtg;
+import org.apache.poi.hssf.record.formula.NumberPtg;
+import org.apache.poi.hssf.record.formula.OperationPtg;
+import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.record.formula.Ref3DPtg;
+import org.apache.poi.hssf.record.formula.RefPtg;
+import org.apache.poi.hssf.record.formula.StringPtg;
+import org.apache.poi.hssf.record.formula.UnionPtg;
+import org.apache.poi.hssf.record.formula.UnknownPtg;
+import org.apache.poi.hssf.record.formula.eval.AreaEval;
+import org.apache.poi.hssf.record.formula.eval.BlankEval;
+import org.apache.poi.hssf.record.formula.eval.BoolEval;
+import org.apache.poi.hssf.record.formula.eval.ErrorEval;
+import org.apache.poi.hssf.record.formula.eval.Eval;
+import org.apache.poi.hssf.record.formula.eval.FunctionEval;
+import org.apache.poi.hssf.record.formula.eval.NameEval;
+import org.apache.poi.hssf.record.formula.eval.NameXEval;
+import org.apache.poi.hssf.record.formula.eval.NumberEval;
+import org.apache.poi.hssf.record.formula.eval.OperationEval;
+import org.apache.poi.hssf.record.formula.eval.RefEval;
+import org.apache.poi.hssf.record.formula.eval.StringEval;
+import org.apache.poi.hssf.record.formula.eval.ValueEval;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.util.CellReference;
+
+/**
+ * Evaluates formula cells.
+ *
+ * For performance reasons, this class keeps a cache of all previously calculated intermediate
+ * cell values. Be sure to call {@link #clearCache()} if any workbook cells are changed between
+ * calls to evaluate~ methods on this class.
+ *
+ * For POI internal use only
+ *
+ * @author Josh Micich
+ */
+public class WorkbookEvaluator {
+
+ /**
+ * used to track the number of evaluations
+ */
+ private static final class Counter {
+ public int value;
+ public int depth;
+ public Counter() {
+ value = 0;
+ }
+ }
+
+ private final EvaluationWorkbook _workbook;
+ private final EvaluationCache _cache;
+
+ private Counter _evaluationCounter;
+
+ public WorkbookEvaluator(EvaluationWorkbook workbook) {
+ _workbook = workbook;
+ _cache = new EvaluationCache();
+ _evaluationCounter = new Counter();
+ }
+
+ /**
+ * for debug use. Used in toString methods
+ */
+ /* package */ String getSheetName(HSSFSheet sheet) {
+ return getSheetName(getSheetIndex(sheet));
+ }
+ private String getSheetName(int sheetIndex) {
+ return _workbook.getSheetName(sheetIndex);
+ }
+ /**
+ * for debug/test use
+ */
+ public int getEvaluationCount() {
+ return _evaluationCounter.value;
+ }
+
+ private static boolean isDebugLogEnabled() {
+ return false;
+ }
+ private static void logDebug(String s) {
+ if (isDebugLogEnabled()) {
+ System.out.println(s);
+ }
+ }
+
+ /**
+ * Should be called whenever there are changes to input cells in the evaluated workbook.
+ * Failure to call this method after changing cell values will cause incorrect behaviour
+ * of the evaluate~ methods of this class
+ */
+ public void clearAllCachedResultValues() {
+ _cache.clear();
+ }
+
+ public void clearCachedResultValue(HSSFSheet sheet, int rowIndex, int columnIndex) {
+ int sheetIndex = getSheetIndex(sheet);
+ _cache.clearValue(sheetIndex, rowIndex, columnIndex);
+
+ }
+ private int getSheetIndex(HSSFSheet sheet) {
+ // TODO cache sheet indexes too
+ return _workbook.getSheetIndex(sheet);
+ }
+
+ public ValueEval evaluate(HSSFCell srcCell) {
+ return internalEvaluate(srcCell, new EvaluationTracker(_cache));
+ }
+
+ /**
+ * Dev. Note: Internal evaluate must be passed only a formula cell
+ * else a runtime exception will be thrown somewhere inside the method.
+ * (Hence this is a private method.)
+ * @return never null
, never {@link BlankEval}
+ */
+ /* package */ ValueEval internalEvaluate(HSSFCell srcCell, EvaluationTracker tracker) {
+ int srcRowNum = srcCell.getRowIndex();
+ int srcColNum = srcCell.getCellNum();
+
+ ValueEval result;
+
+ int sheetIndex = getSheetIndex(srcCell.getSheet());
+ result = tracker.startEvaluate(sheetIndex, srcRowNum, srcColNum);
+ if (result != null) {
+ return result;
+ }
+ _evaluationCounter.value++;
+ _evaluationCounter.depth++;
+
+ try {
+ Ptg[] ptgs = _workbook.getFormulaTokens(srcCell);
+ result = evaluateCell(sheetIndex, srcRowNum, (short)srcColNum, ptgs, tracker);
+ } finally {
+ tracker.endEvaluate(sheetIndex, srcRowNum, srcColNum, result);
+ _evaluationCounter.depth--;
+ }
+ if (isDebugLogEnabled()) {
+ String sheetName = getSheetName(sheetIndex);
+ CellReference cr = new CellReference(srcRowNum, srcColNum);
+ logDebug("Evaluated " + sheetName + "!" + cr.formatAsString() + " to " + result.toString());
+ }
+ return result;
+ }
+ private ValueEval evaluateCell(int sheetIndex, int srcRowNum, short srcColNum, Ptg[] ptgs, EvaluationTracker tracker) {
+
+ Stack stack = new Stack();
+ for (int i = 0, iSize = ptgs.length; i < iSize; i++) {
+
+ // since we don't know how to handle these yet :(
+ Ptg ptg = ptgs[i];
+ if (ptg instanceof ControlPtg) {
+ // skip Parentheses, Attr, etc
+ continue;
+ }
+ if (ptg instanceof MemErrPtg) { continue; }
+ if (ptg instanceof MissingArgPtg) {
+ // TODO - might need to push BlankEval or MissingArgEval
+ continue;
+ }
+ Eval opResult;
+ if (ptg instanceof OperationPtg) {
+ OperationPtg optg = (OperationPtg) ptg;
+
+ if (optg instanceof UnionPtg) { continue; }
+
+ OperationEval operation = OperationEvaluatorFactory.create(optg);
+
+ int numops = operation.getNumberOfOperands();
+ Eval[] ops = new Eval[numops];
+
+ // storing the ops in reverse order since they are popping
+ for (int j = numops - 1; j >= 0; j--) {
+ Eval p = (Eval) stack.pop();
+ ops[j] = p;
+ }
+// logDebug("invoke " + operation + " (nAgs=" + numops + ")");
+ opResult = invokeOperation(operation, ops, _workbook, sheetIndex, srcRowNum, srcColNum);
+ } else {
+ opResult = getEvalForPtg(ptg, sheetIndex, tracker);
+ }
+ if (opResult == null) {
+ throw new RuntimeException("Evaluation result must not be null");
+ }
+// logDebug("push " + opResult);
+ stack.push(opResult);
+ }
+
+ ValueEval value = ((ValueEval) stack.pop());
+ if (!stack.isEmpty()) {
+ throw new IllegalStateException("evaluation stack not empty");
+ }
+ value = dereferenceValue(value, srcRowNum, srcColNum);
+ if (value == BlankEval.INSTANCE) {
+ // Note Excel behaviour here. A blank final final value is converted to zero.
+ return NumberEval.ZERO;
+ // Formulas _never_ evaluate to blank. If a formula appears to have evaluated to
+ // blank, the actual value is empty string. This can be verified with ISBLANK().
+ }
+ return value;
+ }
+
+ /**
+ * Dereferences a single value from any AreaEval or RefEval evaluation result.
+ * If the supplied evaluationResult is just a plain value, it is returned as-is.
+ * @return a NumberEval, StringEval, BoolEval,
+ * BlankEval or ErrorEval. Never null
.
+ */
+ private static ValueEval dereferenceValue(ValueEval evaluationResult, int srcRowNum, short srcColNum) {
+ if (evaluationResult instanceof RefEval) {
+ RefEval rv = (RefEval) evaluationResult;
+ return rv.getInnerValueEval();
+ }
+ if (evaluationResult instanceof AreaEval) {
+ AreaEval ae = (AreaEval) evaluationResult;
+ if (ae.isRow()) {
+ if(ae.isColumn()) {
+ return ae.getRelativeValue(0, 0);
+ }
+ return ae.getValueAt(ae.getFirstRow(), srcColNum);
+ }
+ if (ae.isColumn()) {
+ return ae.getValueAt(srcRowNum, ae.getFirstColumn());
+ }
+ return ErrorEval.VALUE_INVALID;
+ }
+ return evaluationResult;
+ }
+
+ private static Eval invokeOperation(OperationEval operation, Eval[] ops,
+ EvaluationWorkbook workbook, int sheetIndex, int srcRowNum, int srcColNum) {
+
+ if(operation instanceof FunctionEval) {
+ FunctionEval fe = (FunctionEval) operation;
+ if(fe.isFreeRefFunction()) {
+ return fe.getFreeRefFunction().evaluate(ops, workbook, sheetIndex, srcRowNum, srcColNum);
+ }
+ }
+ return operation.evaluate(ops, srcRowNum, (short)srcColNum);
+ }
+
+ private HSSFSheet getOtherSheet(int externSheetIndex) {
+ return _workbook.getSheetByExternSheetIndex(externSheetIndex);
+ }
+
+ /**
+ * returns an appropriate Eval impl instance for the Ptg. The Ptg must be
+ * one of: Area3DPtg, AreaPtg, ReferencePtg, Ref3DPtg, IntPtg, NumberPtg,
+ * StringPtg, BoolPtg
special Note: OperationPtg subtypes cannot be
+ * passed here!
+ */
+ private Eval getEvalForPtg(Ptg ptg, int sheetIndex, EvaluationTracker tracker) {
+ if (ptg instanceof NamePtg) {
+ // named ranges, macro functions
+ NamePtg namePtg = (NamePtg) ptg;
+ EvaluationName nameRecord = _workbook.getName(namePtg);
+ if (nameRecord.isFunctionName()) {
+ return new NameEval(nameRecord.getNameText());
+ }
+ if (nameRecord.hasFormula()) {
+ return evaluateNameFormula(nameRecord.getNameDefinition(), sheetIndex, tracker);
+ }
+
+ throw new RuntimeException("Don't now how to evalate name '" + nameRecord.getNameText() + "'");
+ }
+ if (ptg instanceof NameXPtg) {
+ return new NameXEval(((NameXPtg) ptg));
+ }
+
+ if (ptg instanceof IntPtg) {
+ return new NumberEval(((IntPtg)ptg).getValue());
+ }
+ if (ptg instanceof NumberPtg) {
+ return new NumberEval(((NumberPtg)ptg).getValue());
+ }
+ if (ptg instanceof StringPtg) {
+ return new StringEval(((StringPtg) ptg).getValue());
+ }
+ if (ptg instanceof BoolPtg) {
+ return BoolEval.valueOf(((BoolPtg) ptg).getValue());
+ }
+ if (ptg instanceof ErrPtg) {
+ return ErrorEval.valueOf(((ErrPtg) ptg).getErrorCode());
+ }
+ CellEvaluator ce = new CellEvaluator(this, tracker);
+ HSSFSheet sheet = _workbook.getSheet(sheetIndex);
+ if (ptg instanceof RefPtg) {
+ return new LazyRefEval(((RefPtg) ptg), sheet, ce);
+ }
+ if (ptg instanceof AreaPtg) {
+ return new LazyAreaEval(((AreaPtg) ptg), sheet, ce);
+ }
+ if (ptg instanceof Ref3DPtg) {
+ Ref3DPtg refPtg = (Ref3DPtg) ptg;
+ HSSFSheet xsheet = getOtherSheet(refPtg.getExternSheetIndex());
+ return new LazyRefEval(refPtg, xsheet, ce);
+ }
+ if (ptg instanceof Area3DPtg) {
+ Area3DPtg a3dp = (Area3DPtg) ptg;
+ HSSFSheet xsheet = getOtherSheet(a3dp.getExternSheetIndex());
+ return new LazyAreaEval(a3dp, xsheet, ce);
+ }
+
+ if (ptg instanceof UnknownPtg) {
+ // POI uses UnknownPtg when the encoded Ptg array seems to be corrupted.
+ // This seems to occur in very rare cases (e.g. unused name formulas in bug 44774, attachment 21790)
+ // In any case, formulas are re-parsed before execution, so UnknownPtg should not get here
+ throw new RuntimeException("UnknownPtg not allowed");
+ }
+
+ throw new RuntimeException("Unexpected ptg class (" + ptg.getClass().getName() + ")");
+ }
+ private Eval evaluateNameFormula(Ptg[] ptgs, int sheetIndex, EvaluationTracker tracker) {
+ if (ptgs.length > 1) {
+ throw new RuntimeException("Complex name formulas not supported yet");
+ }
+ return getEvalForPtg(ptgs[0], sheetIndex, tracker);
+ }
+}
diff --git a/src/testcases/org/apache/poi/hssf/eventusermodel/TestEventWorkbookBuilder.java b/src/testcases/org/apache/poi/hssf/eventusermodel/TestEventWorkbookBuilder.java
index a17414af7..2c56ea57a 100644
--- a/src/testcases/org/apache/poi/hssf/eventusermodel/TestEventWorkbookBuilder.java
+++ b/src/testcases/org/apache/poi/hssf/eventusermodel/TestEventWorkbookBuilder.java
@@ -26,7 +26,7 @@ import junit.framework.TestCase;
import org.apache.poi.hssf.HSSFTestDataSamples;
import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener;
-import org.apache.poi.hssf.model.FormulaParser;
+import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.FormulaRecord;
import org.apache.poi.hssf.record.Record;
@@ -101,7 +101,7 @@ public final class TestEventWorkbookBuilder extends TestCase {
// Check we can get the formula without breaking
for(int i=0; inull
*/
/* package */ static Ptg[] parseFormula(String formula) {
- Ptg[] result = FormulaParser.parse(formula, null);
+ Ptg[] result = HSSFFormulaParser.parse(formula, (HSSFWorkbook)null);
assertNotNull("Ptg array should not be null", result);
return result;
}
+ private static String toFormulaString(Ptg[] ptgs) {
+ return HSSFFormulaParser.toFormulaString((HSSFWorkbook)null, ptgs);
+ }
public void testSimpleFormula() {
Ptg[] ptgs = parseFormula("2+2");
@@ -133,7 +136,7 @@ public final class TestFormulaParser extends TestCase {
HSSFWorkbook w = HSSFTestDataSamples.openSampleWorkbook("testNames.xls");
HSSFEvaluationWorkbook book = HSSFEvaluationWorkbook.create(w);
- Ptg[] ptg = FormulaParser.parse("myFunc()", w);
+ Ptg[] ptg = HSSFFormulaParser.parse("myFunc()", w);
// myFunc() actually takes 1 parameter. Don't know if POI will ever be able to detect this problem
// the name gets encoded as the first arg
@@ -405,7 +408,7 @@ public final class TestFormulaParser extends TestCase {
Ptg[] ptgs = {
new FuncPtg(10),
};
- assertEquals("NA()", FormulaParser.toFormulaString(book, ptgs));
+ assertEquals("NA()", HSSFFormulaParser.toFormulaString(book, ptgs));
}
public void testPercent() {
@@ -639,11 +642,11 @@ public final class TestFormulaParser extends TestCase {
String formulaString;
Ptg[] ptgs;
ptgs = parseFormula("sum(5, 2, if(3>2, sum(A1:A2), 6))");
- formulaString = FormulaParser.toFormulaString(null, ptgs);
+ formulaString = toFormulaString(ptgs);
assertEquals("SUM(5,2,IF(3>2,SUM(A1:A2),6))", formulaString);
ptgs = parseFormula("if(1<2,sum(5, 2, if(3>2, sum(A1:A2), 6)),4)");
- formulaString = FormulaParser.toFormulaString(null, ptgs);
+ formulaString = toFormulaString(ptgs);
assertEquals("IF(1<2,SUM(5,2,IF(3>2,SUM(A1:A2),6)),4)", formulaString);
}
public void testParserErrors() {
@@ -665,12 +668,9 @@ public final class TestFormulaParser extends TestCase {
try {
parseFormula(formula);
throw new AssertionFailedError("expected parse exception");
- } catch (FormulaParseException e) {
- // expected during successful test
- assertNotNull(e.getMessage());
} catch (RuntimeException e) {
- e.printStackTrace();
- fail("Wrong exception:" + e.getMessage());
+ // expected during successful test
+ FormulaParserTestHelper.confirmParseException(e);
}
}
@@ -697,7 +697,7 @@ public final class TestFormulaParser extends TestCase {
Ptg[] ptgs = { spacePtg, new IntPtg(4), };
String formulaString;
try {
- formulaString = FormulaParser.toFormulaString(null, ptgs);
+ formulaString = toFormulaString(ptgs);
} catch (IllegalStateException e) {
if(e.getMessage().equalsIgnoreCase("too much stuff left on the stack")) {
throw new AssertionFailedError("Identified bug 44609");
@@ -709,7 +709,7 @@ public final class TestFormulaParser extends TestCase {
assertEquals("4", formulaString);
ptgs = new Ptg[] { new IntPtg(3), spacePtg, new IntPtg(4), spacePtg, AddPtg.instance, };
- formulaString = FormulaParser.toFormulaString(null, ptgs);
+ formulaString = toFormulaString(ptgs);
assertEquals("3+4", formulaString);
}
@@ -725,7 +725,7 @@ public final class TestFormulaParser extends TestCase {
DividePtg.instance,
};
try {
- FormulaParser.toFormulaString(null, ptgs);
+ toFormulaString(ptgs);
fail("Expected exception was not thrown");
} catch (IllegalStateException e) {
// expected during successful test
@@ -764,10 +764,10 @@ public final class TestFormulaParser extends TestCase {
private static void confirmArgCountMsg(String formula, String expectedMessage) {
HSSFWorkbook book = new HSSFWorkbook();
try {
- FormulaParser.parse(formula, book);
+ HSSFFormulaParser.parse(formula, book);
throw new AssertionFailedError("Didn't get parse exception as expected");
- } catch (FormulaParseException e) {
- assertEquals(expectedMessage, e.getMessage());
+ } catch (RuntimeException e) {
+ FormulaParserTestHelper.confirmParseException(e, expectedMessage);
}
}
@@ -776,15 +776,17 @@ public final class TestFormulaParser extends TestCase {
try {
parseFormula("round(3.14;2)");
throw new AssertionFailedError("Didn't get parse exception as expected");
- } catch (FormulaParseException e) {
- assertEquals("Parse error near char 10 ';' in specified formula 'round(3.14;2)'. Expected ',' or ')'", e.getMessage());
+ } catch (RuntimeException e) {
+ FormulaParserTestHelper.confirmParseException(e,
+ "Parse error near char 10 ';' in specified formula 'round(3.14;2)'. Expected ',' or ')'");
}
try {
parseFormula(" =2+2");
throw new AssertionFailedError("Didn't get parse exception as expected");
- } catch (FormulaParseException e) {
- assertEquals("The specified formula ' =2+2' starts with an equals sign which is not allowed.", e.getMessage());
+ } catch (RuntimeException e) {
+ FormulaParserTestHelper.confirmParseException(e,
+ "The specified formula ' =2+2' starts with an equals sign which is not allowed.");
}
}
@@ -819,7 +821,7 @@ public final class TestFormulaParser extends TestCase {
Ptg[] ptgs;
try {
- ptgs = FormulaParser.parse("count(pfy1)", wb);
+ ptgs = HSSFFormulaParser.parse("count(pfy1)", wb);
} catch (IllegalArgumentException e) {
if (e.getMessage().equals("Specified colIx (1012) is out of range")) {
throw new AssertionFailedError("Identified bug 45354");
@@ -835,10 +837,9 @@ public final class TestFormulaParser extends TestCase {
try {
cell.setCellFormula("count(pf1)");
throw new AssertionFailedError("Expected formula parse execption");
- } catch (FormulaParseException e) {
- if (!e.getMessage().equals("Specified named range 'pf1' does not exist in the current workbook.")) {
- throw e;
- }
+ } catch (RuntimeException e) {
+ FormulaParserTestHelper.confirmParseException(e,
+ "Specified named range 'pf1' does not exist in the current workbook.");
}
cell.setCellFormula("count(fp1)"); // plain cell ref, col is in range
}
@@ -850,14 +851,14 @@ public final class TestFormulaParser extends TestCase {
HSSFWorkbook book = new HSSFWorkbook();
book.createSheet("Sheet1");
- ptgs = FormulaParser.parse("Sheet1!A10:A40000", book);
+ ptgs = HSSFFormulaParser.parse("Sheet1!A10:A40000", book);
aptg = (AreaI) ptgs[0];
if (aptg.getLastRow() == -25537) {
throw new AssertionFailedError("Identified bug 45358");
}
assertEquals(39999, aptg.getLastRow());
- ptgs = FormulaParser.parse("Sheet1!A10:A65536", book);
+ ptgs = HSSFFormulaParser.parse("Sheet1!A10:A65536", book);
aptg = (AreaI) ptgs[0];
assertEquals(65535, aptg.getLastRow());
diff --git a/src/testcases/org/apache/poi/hssf/model/TestFormulaParserEval.java b/src/testcases/org/apache/poi/hssf/model/TestFormulaParserEval.java
index 2bede8e5f..fbbdbd54d 100644
--- a/src/testcases/org/apache/poi/hssf/model/TestFormulaParserEval.java
+++ b/src/testcases/org/apache/poi/hssf/model/TestFormulaParserEval.java
@@ -17,9 +17,9 @@
package org.apache.poi.hssf.model;
+import junit.framework.AssertionFailedError;
import junit.framework.TestCase;
-import org.apache.poi.hssf.model.FormulaParser.FormulaParseException;
import org.apache.poi.hssf.record.formula.FuncVarPtg;
import org.apache.poi.hssf.record.formula.NamePtg;
import org.apache.poi.hssf.record.formula.Ptg;
@@ -30,6 +30,7 @@ import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator.CellValue;
+import org.apache.poi.ss.formula.FormulaParserTestHelper;
/**
* Test the low level formula parser functionality,
@@ -51,21 +52,21 @@ public final class TestFormulaParserEval extends TestCase {
name.setNameName("testName");
name.setReference("A1:A2");
- ptgs = FormulaParser.parse("SUM(testName)", workbook);
+ ptgs = HSSFFormulaParser.parse("SUM(testName)", workbook);
assertTrue("two tokens expected, got "+ptgs.length,ptgs.length == 2);
assertEquals(NamePtg.class, ptgs[0].getClass());
assertEquals(FuncVarPtg.class, ptgs[1].getClass());
// Now make it a single cell
name.setReference("C3");
- ptgs = FormulaParser.parse("SUM(testName)", workbook);
+ ptgs = HSSFFormulaParser.parse("SUM(testName)", workbook);
assertTrue("two tokens expected, got "+ptgs.length,ptgs.length == 2);
assertEquals(NamePtg.class, ptgs[0].getClass());
assertEquals(FuncVarPtg.class, ptgs[1].getClass());
// And make it non-contiguous
name.setReference("A1:A2,C3");
- ptgs = FormulaParser.parse("SUM(testName)", workbook);
+ ptgs = HSSFFormulaParser.parse("SUM(testName)", workbook);
assertTrue("two tokens expected, got "+ptgs.length,ptgs.length == 2);
assertEquals(NamePtg.class, ptgs[0].getClass());
assertEquals(FuncVarPtg.class, ptgs[1].getClass());
@@ -89,11 +90,12 @@ public final class TestFormulaParserEval extends TestCase {
CellValue result;
try {
result = fe.evaluate(cell);
- } catch (FormulaParseException e) {
- if(e.getMessage().equals("Found reference to named range \"A\", but that named range wasn't defined!")) {
- fail("Identifed bug 44539");
+ } catch (RuntimeException e) {
+ FormulaParserTestHelper.confirmParseException(e);
+ if (!e.getMessage().equals("Found reference to named range \"A\", but that named range wasn't defined!")) {
+ throw new AssertionFailedError("Identifed bug 44539");
}
- throw new RuntimeException(e);
+ throw e;
}
assertEquals(HSSFCell.CELL_TYPE_NUMERIC, result.getCellType());
assertEquals(42.0, result.getNumberValue(), 0.0);
diff --git a/src/testcases/org/apache/poi/hssf/model/TestOperandClassTransformer.java b/src/testcases/org/apache/poi/hssf/model/TestOperandClassTransformer.java
index 47cfb574c..530c2b09c 100644
--- a/src/testcases/org/apache/poi/hssf/model/TestOperandClassTransformer.java
+++ b/src/testcases/org/apache/poi/hssf/model/TestOperandClassTransformer.java
@@ -23,6 +23,7 @@ import junit.framework.TestCase;
import org.apache.poi.hssf.record.formula.AbstractFunctionPtg;
import org.apache.poi.hssf.record.formula.FuncVarPtg;
import org.apache.poi.hssf.record.formula.Ptg;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/**
* Tests specific formula examples in OperandClassTransformer.
@@ -31,9 +32,15 @@ import org.apache.poi.hssf.record.formula.Ptg;
*/
public final class TestOperandClassTransformer extends TestCase {
+ private static Ptg[] parseFormula(String formula) {
+ Ptg[] result = HSSFFormulaParser.parse(formula, (HSSFWorkbook)null);
+ assertNotNull("Ptg array should not be null", result);
+ return result;
+ }
+
public void testMdeterm() {
String formula = "MDETERM(ABS(A1))";
- Ptg[] ptgs = FormulaParser.parse(formula, null);
+ Ptg[] ptgs = parseFormula(formula);
confirmTokenClass(ptgs, 0, Ptg.CLASS_ARRAY);
confirmFuncClass(ptgs, 1, "ABS", Ptg.CLASS_ARRAY);
@@ -51,7 +58,7 @@ public final class TestOperandClassTransformer extends TestCase {
*/
public void DISABLED_testIndexPi1() {
String formula = "INDEX(PI(),1)";
- Ptg[] ptgs = FormulaParser.parse(formula, null);
+ Ptg[] ptgs = parseFormula(formula);
confirmFuncClass(ptgs, 1, "PI", Ptg.CLASS_ARRAY); // fails as of POI 3.1
confirmFuncClass(ptgs, 2, "INDEX", Ptg.CLASS_VALUE);
@@ -63,7 +70,7 @@ public final class TestOperandClassTransformer extends TestCase {
*/
public void testDirectOperandOfValueOperator() {
String formula = "COUNT(A1*1)";
- Ptg[] ptgs = FormulaParser.parse(formula, null);
+ Ptg[] ptgs = parseFormula(formula);
if (ptgs[0].getPtgClass() == Ptg.CLASS_REF) {
throw new AssertionFailedError("Identified bug 45348");
}
@@ -78,13 +85,13 @@ public final class TestOperandClassTransformer extends TestCase {
public void testRtoV() {
String formula = "lookup(A1, A3:A52, B3:B52)";
- Ptg[] ptgs = FormulaParser.parse(formula, null);
+ Ptg[] ptgs = parseFormula(formula);
confirmTokenClass(ptgs, 0, Ptg.CLASS_VALUE);
}
public void testComplexIRR_bug45041() {
String formula = "(1+IRR(SUMIF(A:A,ROW(INDIRECT(MIN(A:A)&\":\"&MAX(A:A))),B:B),0))^365-1";
- Ptg[] ptgs = FormulaParser.parse(formula, null);
+ Ptg[] ptgs = parseFormula(formula);
FuncVarPtg rowFunc = (FuncVarPtg) ptgs[10];
FuncVarPtg sumifFunc = (FuncVarPtg) ptgs[12];
diff --git a/src/testcases/org/apache/poi/hssf/model/TestRVA.java b/src/testcases/org/apache/poi/hssf/model/TestRVA.java
index 1ec7c92ae..eb69a5cd0 100644
--- a/src/testcases/org/apache/poi/hssf/model/TestRVA.java
+++ b/src/testcases/org/apache/poi/hssf/model/TestRVA.java
@@ -82,7 +82,7 @@ public final class TestRVA extends TestCase {
private void confirmCell(HSSFCell formulaCell, String formula, HSSFWorkbook wb) {
Ptg[] excelPtgs = FormulaExtractor.getPtgs(formulaCell);
- Ptg[] poiPtgs = FormulaParser.parse(formula, wb);
+ Ptg[] poiPtgs = HSSFFormulaParser.parse(formula, wb);
int nExcelTokens = excelPtgs.length;
int nPoiTokens = poiPtgs.length;
if (nExcelTokens != nPoiTokens) {
diff --git a/src/testcases/org/apache/poi/hssf/record/formula/TestAreaPtg.java b/src/testcases/org/apache/poi/hssf/record/formula/TestAreaPtg.java
index f5b80f6da..84f689774 100644
--- a/src/testcases/org/apache/poi/hssf/record/formula/TestAreaPtg.java
+++ b/src/testcases/org/apache/poi/hssf/record/formula/TestAreaPtg.java
@@ -20,7 +20,7 @@ package org.apache.poi.hssf.record.formula;
import junit.framework.TestCase;
-import org.apache.poi.hssf.model.FormulaParser;
+import org.apache.poi.hssf.model.HSSFFormulaParser;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
/**
@@ -87,7 +87,7 @@ public final class TestAreaPtg extends TestCase {
private static String shiftAllColumnsBy1(String formula) {
int letUsShiftColumn1By1Column=1;
HSSFWorkbook wb = null;
- Ptg[] ptgs = FormulaParser.parse(formula, wb);
+ Ptg[] ptgs = HSSFFormulaParser.parse(formula, wb);
for(int i=0; i