You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by on...@apache.org on 2016/06/10 02:51:45 UTC
svn commit: r1747625 [1/2] - in /poi/branches/xssf_structured_references/src:
java/org/apache/poi/hssf/usermodel/ java/org/apache/poi/ss/formula/
java/org/apache/poi/ss/formula/functions/
ooxml/java/org/apache/poi/xssf/usermodel/ testcases/org/apache/p...
Author: onealj
Date: Fri Jun 10 02:51:45 2016
New Revision: 1747625
URL: http://svn.apache.org/viewvc?rev=1747625&view=rev
Log:
whitespace (tabs to spaces)
Modified:
poi/branches/xssf_structured_references/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/FormulaParsingWorkbook.java
poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java
poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/functions/Indirect.java
poi/branches/xssf_structured_references/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFCell.java
poi/branches/xssf_structured_references/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
poi/branches/xssf_structured_references/src/testcases/org/apache/poi/hssf/record/TestSharedFormulaRecord.java
Modified: poi/branches/xssf_structured_references/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java
URL: http://svn.apache.org/viewvc/poi/branches/xssf_structured_references/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java?rev=1747625&r1=1747624&r2=1747625&view=diff
==============================================================================
--- poi/branches/xssf_structured_references/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java (original)
+++ poi/branches/xssf_structured_references/src/java/org/apache/poi/hssf/usermodel/HSSFEvaluationWorkbook.java Fri Jun 10 02:51:45 2016
@@ -6,7 +6,7 @@
(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
+ 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,
Modified: poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/FormulaParsingWorkbook.java
URL: http://svn.apache.org/viewvc/poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/FormulaParsingWorkbook.java?rev=1747625&r1=1747624&r2=1747625&view=diff
==============================================================================
--- poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/FormulaParsingWorkbook.java (original)
+++ poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/FormulaParsingWorkbook.java Fri Jun 10 02:51:45 2016
@@ -32,51 +32,51 @@ import org.apache.poi.ss.util.CellRefere
* @author Josh Micich
*/
public interface FormulaParsingWorkbook {
- /**
- * named range name matching is case insensitive
- */
- EvaluationName getName(String name, int sheetIndex);
-
- /**
- * Return the underlying workbook
- */
- Name createName();
+ /**
+ * named range name matching is case insensitive
+ */
+ EvaluationName getName(String name, int sheetIndex);
+
+ /**
+ * Return the underlying workbook
+ */
+ Name createName();
- /**
- * XSSF Only - gets a table that exists in the worksheet
- */
- Table getTable(String name);
-
- /**
- * Return an external name (named range, function, user-defined function) Ptg
- */
- Ptg getNameXPtg(String name, SheetIdentifier sheet);
-
- /**
- * Produce the appropriate Ptg for a 3d cell reference
- */
- Ptg get3DReferencePtg(CellReference cell, SheetIdentifier sheet);
+ /**
+ * XSSF Only - gets a table that exists in the worksheet
+ */
+ Table getTable(String name);
+
+ /**
+ * Return an external name (named range, function, user-defined function) Ptg
+ */
+ Ptg getNameXPtg(String name, SheetIdentifier sheet);
+
+ /**
+ * Produce the appropriate Ptg for a 3d cell reference
+ */
+ Ptg get3DReferencePtg(CellReference cell, SheetIdentifier sheet);
/**
* Produce the appropriate Ptg for a 3d area reference
*/
Ptg get3DReferencePtg(AreaReference area, SheetIdentifier sheet);
- /**
- * gets the externSheet index for a sheet from this workbook
- */
- int getExternalSheetIndex(String sheetName);
- /**
- * gets the externSheet index for a sheet from an external workbook
- * @param workbookName e.g. "Budget.xls"
- * @param sheetName a name of a sheet in that workbook
- */
- int getExternalSheetIndex(String workbookName, String sheetName);
+ /**
+ * gets the externSheet index for a sheet from this workbook
+ */
+ int getExternalSheetIndex(String sheetName);
+ /**
+ * gets the externSheet index for a sheet from an external workbook
+ * @param workbookName e.g. "Budget.xls"
+ * @param sheetName a name of a sheet in that workbook
+ */
+ int getExternalSheetIndex(String workbookName, String sheetName);
- /**
- * Returns an enum holding spreadhseet properties specific to an Excel version (
- * max column and row numbers, max arguments to a function, etc.)
- */
- SpreadsheetVersion getSpreadsheetVersion();
+ /**
+ * Returns an enum holding spreadhseet properties specific to an Excel version (
+ * max column and row numbers, max arguments to a function, etc.)
+ */
+ SpreadsheetVersion getSpreadsheetVersion();
}
Modified: poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java
URL: http://svn.apache.org/viewvc/poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java?rev=1747625&r1=1747624&r2=1747625&view=diff
==============================================================================
--- poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java (original)
+++ poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/OperationEvaluationContext.java Fri Jun 10 02:51:45 2016
@@ -46,199 +46,199 @@ import org.apache.poi.ss.util.CellRefere
* For POI internal use only
*/
public final class OperationEvaluationContext {
- public static final FreeRefFunction UDF = UserDefinedFunction.instance;
- private final EvaluationWorkbook _workbook;
- private final int _sheetIndex;
- private final int _rowIndex;
- private final int _columnIndex;
- private final EvaluationTracker _tracker;
- private final WorkbookEvaluator _bookEvaluator;
-
- public OperationEvaluationContext(WorkbookEvaluator bookEvaluator, EvaluationWorkbook workbook, int sheetIndex, int srcRowNum,
- int srcColNum, EvaluationTracker tracker) {
- _bookEvaluator = bookEvaluator;
- _workbook = workbook;
- _sheetIndex = sheetIndex;
- _rowIndex = srcRowNum;
- _columnIndex = srcColNum;
- _tracker = tracker;
- }
-
- public EvaluationWorkbook getWorkbook() {
- return _workbook;
- }
-
- public int getRowIndex() {
- return _rowIndex;
- }
-
- public int getColumnIndex() {
- return _columnIndex;
- }
-
- SheetRangeEvaluator createExternSheetRefEvaluator(ExternSheetReferenceToken ptg) {
- return createExternSheetRefEvaluator(ptg.getExternSheetIndex());
- }
- SheetRangeEvaluator createExternSheetRefEvaluator(String firstSheetName, String lastSheetName, int externalWorkbookNumber) {
+ public static final FreeRefFunction UDF = UserDefinedFunction.instance;
+ private final EvaluationWorkbook _workbook;
+ private final int _sheetIndex;
+ private final int _rowIndex;
+ private final int _columnIndex;
+ private final EvaluationTracker _tracker;
+ private final WorkbookEvaluator _bookEvaluator;
+
+ public OperationEvaluationContext(WorkbookEvaluator bookEvaluator, EvaluationWorkbook workbook, int sheetIndex, int srcRowNum,
+ int srcColNum, EvaluationTracker tracker) {
+ _bookEvaluator = bookEvaluator;
+ _workbook = workbook;
+ _sheetIndex = sheetIndex;
+ _rowIndex = srcRowNum;
+ _columnIndex = srcColNum;
+ _tracker = tracker;
+ }
+
+ public EvaluationWorkbook getWorkbook() {
+ return _workbook;
+ }
+
+ public int getRowIndex() {
+ return _rowIndex;
+ }
+
+ public int getColumnIndex() {
+ return _columnIndex;
+ }
+
+ SheetRangeEvaluator createExternSheetRefEvaluator(ExternSheetReferenceToken ptg) {
+ return createExternSheetRefEvaluator(ptg.getExternSheetIndex());
+ }
+ SheetRangeEvaluator createExternSheetRefEvaluator(String firstSheetName, String lastSheetName, int externalWorkbookNumber) {
ExternalSheet externalSheet = _workbook.getExternalSheet(firstSheetName, lastSheetName, externalWorkbookNumber);
return createExternSheetRefEvaluator(externalSheet);
}
- SheetRangeEvaluator createExternSheetRefEvaluator(int externSheetIndex) {
- ExternalSheet externalSheet = _workbook.getExternalSheet(externSheetIndex);
+ SheetRangeEvaluator createExternSheetRefEvaluator(int externSheetIndex) {
+ ExternalSheet externalSheet = _workbook.getExternalSheet(externSheetIndex);
return createExternSheetRefEvaluator(externalSheet);
- }
- SheetRangeEvaluator createExternSheetRefEvaluator(ExternalSheet externalSheet) {
- WorkbookEvaluator targetEvaluator;
- int otherFirstSheetIndex;
- int otherLastSheetIndex = -1;
- if (externalSheet == null || externalSheet.getWorkbookName() == null) {
- // sheet is in same workbook
- targetEvaluator = _bookEvaluator;
- if(externalSheet == null) {
- otherFirstSheetIndex = 0;
- } else {
- otherFirstSheetIndex = _workbook.getSheetIndex(externalSheet.getSheetName());
- }
-
- if (externalSheet instanceof ExternalSheetRange) {
- String lastSheetName = ((ExternalSheetRange)externalSheet).getLastSheetName();
- otherLastSheetIndex = _workbook.getSheetIndex(lastSheetName);
- }
- } else {
- // look up sheet by name from external workbook
- String workbookName = externalSheet.getWorkbookName();
- try {
- targetEvaluator = _bookEvaluator.getOtherWorkbookEvaluator(workbookName);
- } catch (WorkbookNotFoundException e) {
- throw new RuntimeException(e.getMessage(), e);
- }
-
- otherFirstSheetIndex = targetEvaluator.getSheetIndex(externalSheet.getSheetName());
+ }
+ SheetRangeEvaluator createExternSheetRefEvaluator(ExternalSheet externalSheet) {
+ WorkbookEvaluator targetEvaluator;
+ int otherFirstSheetIndex;
+ int otherLastSheetIndex = -1;
+ if (externalSheet == null || externalSheet.getWorkbookName() == null) {
+ // sheet is in same workbook
+ targetEvaluator = _bookEvaluator;
+ if(externalSheet == null) {
+ otherFirstSheetIndex = 0;
+ } else {
+ otherFirstSheetIndex = _workbook.getSheetIndex(externalSheet.getSheetName());
+ }
+
+ if (externalSheet instanceof ExternalSheetRange) {
+ String lastSheetName = ((ExternalSheetRange)externalSheet).getLastSheetName();
+ otherLastSheetIndex = _workbook.getSheetIndex(lastSheetName);
+ }
+ } else {
+ // look up sheet by name from external workbook
+ String workbookName = externalSheet.getWorkbookName();
+ try {
+ targetEvaluator = _bookEvaluator.getOtherWorkbookEvaluator(workbookName);
+ } catch (WorkbookNotFoundException e) {
+ throw new RuntimeException(e.getMessage(), e);
+ }
+
+ otherFirstSheetIndex = targetEvaluator.getSheetIndex(externalSheet.getSheetName());
if (externalSheet instanceof ExternalSheetRange) {
String lastSheetName = ((ExternalSheetRange)externalSheet).getLastSheetName();
otherLastSheetIndex = targetEvaluator.getSheetIndex(lastSheetName);
}
-
- if (otherFirstSheetIndex < 0) {
- throw new RuntimeException("Invalid sheet name '" + externalSheet.getSheetName()
- + "' in bool '" + workbookName + "'.");
- }
- }
-
- if (otherLastSheetIndex == -1) {
- // Reference to just one sheet
- otherLastSheetIndex = otherFirstSheetIndex;
- }
-
- SheetRefEvaluator[] evals = new SheetRefEvaluator[otherLastSheetIndex-otherFirstSheetIndex+1];
- for (int i=0; i<evals.length; i++) {
- int otherSheetIndex = i+otherFirstSheetIndex;
- evals[i] = new SheetRefEvaluator(targetEvaluator, _tracker, otherSheetIndex);
- }
- return new SheetRangeEvaluator(otherFirstSheetIndex, otherLastSheetIndex, evals);
- }
-
- /**
- * @return <code>null</code> if either workbook or sheet is not found
- */
- private SheetRefEvaluator createExternSheetRefEvaluator(String workbookName, String sheetName) {
- WorkbookEvaluator targetEvaluator;
- if (workbookName == null) {
- targetEvaluator = _bookEvaluator;
- } else {
- if (sheetName == null) {
- throw new IllegalArgumentException("sheetName must not be null if workbookName is provided");
- }
- try {
- targetEvaluator = _bookEvaluator.getOtherWorkbookEvaluator(workbookName);
- } catch (WorkbookNotFoundException e) {
- return null;
- }
- }
- int otherSheetIndex = sheetName == null ? _sheetIndex : targetEvaluator.getSheetIndex(sheetName);
- if (otherSheetIndex < 0) {
- return null;
- }
- return new SheetRefEvaluator(targetEvaluator, _tracker, otherSheetIndex);
- }
-
- public SheetRangeEvaluator getRefEvaluatorForCurrentSheet() {
- SheetRefEvaluator sre = new SheetRefEvaluator(_bookEvaluator, _tracker, _sheetIndex);
- return new SheetRangeEvaluator(_sheetIndex, sre);
- }
-
-
-
- /**
- * Resolves a cell or area reference dynamically.
- * @param workbookName the name of the workbook containing the reference. If <code>null</code>
- * the current workbook is assumed. Note - to evaluate formulas which use multiple workbooks,
- * a {@link CollaboratingWorkbooksEnvironment} must be set up.
- * @param sheetName the name of the sheet containing the reference. May be <code>null</code>
- * (when <tt>workbookName</tt> is also null) in which case the current workbook and sheet is
- * assumed.
- * @param refStrPart1 the single cell reference or first part of the area reference. Must not
- * be <code>null</code>.
- * @param refStrPart2 the second part of the area reference. For single cell references this
- * parameter must be <code>null</code>
- * @param isA1Style specifies the format for <tt>refStrPart1</tt> and <tt>refStrPart2</tt>.
- * Pass <code>true</code> for 'A1' style and <code>false</code> for 'R1C1' style.
- * TODO - currently POI only supports 'A1' reference style
- * @return a {@link RefEval} or {@link AreaEval}
- */
- public ValueEval getDynamicReference(String workbookName, String sheetName, String refStrPart1,
- String refStrPart2, boolean isA1Style) {
- if (!isA1Style) {
- throw new RuntimeException("R1C1 style not supported yet");
- }
- SheetRefEvaluator se = createExternSheetRefEvaluator(workbookName, sheetName);
- if (se == null) {
- return ErrorEval.REF_INVALID;
- }
- SheetRangeEvaluator sre = new SheetRangeEvaluator(_sheetIndex, se);
-
- // ugly typecast - TODO - make spreadsheet version more easily accessible
- SpreadsheetVersion ssVersion = ((FormulaParsingWorkbook)_workbook).getSpreadsheetVersion();
-
- NameType part1refType = classifyCellReference(refStrPart1, ssVersion);
- switch (part1refType) {
- case BAD_CELL_OR_NAMED_RANGE:
- return ErrorEval.REF_INVALID;
- case NAMED_RANGE:
+
+ if (otherFirstSheetIndex < 0) {
+ throw new RuntimeException("Invalid sheet name '" + externalSheet.getSheetName()
+ + "' in bool '" + workbookName + "'.");
+ }
+ }
+
+ if (otherLastSheetIndex == -1) {
+ // Reference to just one sheet
+ otherLastSheetIndex = otherFirstSheetIndex;
+ }
+
+ SheetRefEvaluator[] evals = new SheetRefEvaluator[otherLastSheetIndex-otherFirstSheetIndex+1];
+ for (int i=0; i<evals.length; i++) {
+ int otherSheetIndex = i+otherFirstSheetIndex;
+ evals[i] = new SheetRefEvaluator(targetEvaluator, _tracker, otherSheetIndex);
+ }
+ return new SheetRangeEvaluator(otherFirstSheetIndex, otherLastSheetIndex, evals);
+ }
+
+ /**
+ * @return <code>null</code> if either workbook or sheet is not found
+ */
+ private SheetRefEvaluator createExternSheetRefEvaluator(String workbookName, String sheetName) {
+ WorkbookEvaluator targetEvaluator;
+ if (workbookName == null) {
+ targetEvaluator = _bookEvaluator;
+ } else {
+ if (sheetName == null) {
+ throw new IllegalArgumentException("sheetName must not be null if workbookName is provided");
+ }
+ try {
+ targetEvaluator = _bookEvaluator.getOtherWorkbookEvaluator(workbookName);
+ } catch (WorkbookNotFoundException e) {
+ return null;
+ }
+ }
+ int otherSheetIndex = sheetName == null ? _sheetIndex : targetEvaluator.getSheetIndex(sheetName);
+ if (otherSheetIndex < 0) {
+ return null;
+ }
+ return new SheetRefEvaluator(targetEvaluator, _tracker, otherSheetIndex);
+ }
+
+ public SheetRangeEvaluator getRefEvaluatorForCurrentSheet() {
+ SheetRefEvaluator sre = new SheetRefEvaluator(_bookEvaluator, _tracker, _sheetIndex);
+ return new SheetRangeEvaluator(_sheetIndex, sre);
+ }
+
+
+
+ /**
+ * Resolves a cell or area reference dynamically.
+ * @param workbookName the name of the workbook containing the reference. If <code>null</code>
+ * the current workbook is assumed. Note - to evaluate formulas which use multiple workbooks,
+ * a {@link CollaboratingWorkbooksEnvironment} must be set up.
+ * @param sheetName the name of the sheet containing the reference. May be <code>null</code>
+ * (when <tt>workbookName</tt> is also null) in which case the current workbook and sheet is
+ * assumed.
+ * @param refStrPart1 the single cell reference or first part of the area reference. Must not
+ * be <code>null</code>.
+ * @param refStrPart2 the second part of the area reference. For single cell references this
+ * parameter must be <code>null</code>
+ * @param isA1Style specifies the format for <tt>refStrPart1</tt> and <tt>refStrPart2</tt>.
+ * Pass <code>true</code> for 'A1' style and <code>false</code> for 'R1C1' style.
+ * TODO - currently POI only supports 'A1' reference style
+ * @return a {@link RefEval} or {@link AreaEval}
+ */
+ public ValueEval getDynamicReference(String workbookName, String sheetName, String refStrPart1,
+ String refStrPart2, boolean isA1Style) {
+ if (!isA1Style) {
+ throw new RuntimeException("R1C1 style not supported yet");
+ }
+ SheetRefEvaluator se = createExternSheetRefEvaluator(workbookName, sheetName);
+ if (se == null) {
+ return ErrorEval.REF_INVALID;
+ }
+ SheetRangeEvaluator sre = new SheetRangeEvaluator(_sheetIndex, se);
+
+ // ugly typecast - TODO - make spreadsheet version more easily accessible
+ SpreadsheetVersion ssVersion = ((FormulaParsingWorkbook)_workbook).getSpreadsheetVersion();
+
+ NameType part1refType = classifyCellReference(refStrPart1, ssVersion);
+ switch (part1refType) {
+ case BAD_CELL_OR_NAMED_RANGE:
+ return ErrorEval.REF_INVALID;
+ case NAMED_RANGE:
EvaluationName nm = ((FormulaParsingWorkbook)_workbook).getName(refStrPart1, _sheetIndex);
if(!nm.isRange()){
throw new RuntimeException("Specified name '" + refStrPart1 + "' is not a range as expected.");
}
return _bookEvaluator.evaluateNameFormula(nm.getNameDefinition(), this);
- }
- if (refStrPart2 == null) {
- // no ':'
- switch (part1refType) {
- case COLUMN:
- case ROW:
- return ErrorEval.REF_INVALID;
- case CELL:
- CellReference cr = new CellReference(refStrPart1);
- return new LazyRefEval(cr.getRow(), cr.getCol(), sre);
- }
- throw new IllegalStateException("Unexpected reference classification of '" + refStrPart1 + "'.");
- }
- NameType part2refType = classifyCellReference(refStrPart1, ssVersion);
- switch (part2refType) {
- case BAD_CELL_OR_NAMED_RANGE:
- return ErrorEval.REF_INVALID;
- case NAMED_RANGE:
- throw new RuntimeException("Cannot evaluate '" + refStrPart1
- + "'. Indirect evaluation of defined names not supported yet");
- }
-
- if (part2refType != part1refType) {
- // LHS and RHS of ':' must be compatible
- return ErrorEval.REF_INVALID;
- }
- int firstRow, firstCol, lastRow, lastCol;
- switch (part1refType) {
- case COLUMN:
+ }
+ if (refStrPart2 == null) {
+ // no ':'
+ switch (part1refType) {
+ case COLUMN:
+ case ROW:
+ return ErrorEval.REF_INVALID;
+ case CELL:
+ CellReference cr = new CellReference(refStrPart1);
+ return new LazyRefEval(cr.getRow(), cr.getCol(), sre);
+ }
+ throw new IllegalStateException("Unexpected reference classification of '" + refStrPart1 + "'.");
+ }
+ NameType part2refType = classifyCellReference(refStrPart1, ssVersion);
+ switch (part2refType) {
+ case BAD_CELL_OR_NAMED_RANGE:
+ return ErrorEval.REF_INVALID;
+ case NAMED_RANGE:
+ throw new RuntimeException("Cannot evaluate '" + refStrPart1
+ + "'. Indirect evaluation of defined names not supported yet");
+ }
+
+ if (part2refType != part1refType) {
+ // LHS and RHS of ':' must be compatible
+ return ErrorEval.REF_INVALID;
+ }
+ int firstRow, firstCol, lastRow, lastCol;
+ switch (part1refType) {
+ case COLUMN:
firstRow =0;
if (part2refType.equals(NameType.COLUMN))
{
@@ -252,7 +252,7 @@ public final class OperationEvaluationCo
lastCol = parseColRef(refStrPart2);
}
break;
- case ROW:
+ case ROW:
// support of cell range in the form of integer:integer
firstCol = 0;
if (part2refType.equals(NameType.ROW))
@@ -265,61 +265,61 @@ public final class OperationEvaluationCo
firstRow = parseRowRef(refStrPart1);
lastRow = parseRowRef(refStrPart2);
}
- break;
- case CELL:
- CellReference cr;
- cr = new CellReference(refStrPart1);
- firstRow = cr.getRow();
- firstCol = cr.getCol();
- cr = new CellReference(refStrPart2);
- lastRow = cr.getRow();
- lastCol = cr.getCol();
- break;
- default:
- throw new IllegalStateException("Unexpected reference classification of '" + refStrPart1 + "'.");
- }
- return new LazyAreaEval(firstRow, firstCol, lastRow, lastCol, sre);
- }
-
- private static int parseRowRef(String refStrPart) {
- return CellReference.convertColStringToIndex(refStrPart);
- }
-
- private static int parseColRef(String refStrPart) {
- return Integer.parseInt(refStrPart) - 1;
- }
-
- private static NameType classifyCellReference(String str, SpreadsheetVersion ssVersion) {
- int len = str.length();
- if (len < 1) {
- return CellReference.NameType.BAD_CELL_OR_NAMED_RANGE;
- }
- return CellReference.classifyCellReference(str, ssVersion);
- }
-
- public FreeRefFunction findUserDefinedFunction(String functionName) {
- return _bookEvaluator.findUserDefinedFunction(functionName);
- }
-
- public ValueEval getRefEval(int rowIndex, int columnIndex) {
- SheetRangeEvaluator sre = getRefEvaluatorForCurrentSheet();
- return new LazyRefEval(rowIndex, columnIndex, sre);
- }
- public ValueEval getRef3DEval(Ref3DPtg rptg) {
- SheetRangeEvaluator sre = createExternSheetRefEvaluator(rptg.getExternSheetIndex());
- return new LazyRefEval(rptg.getRow(), rptg.getColumn(), sre);
- }
+ break;
+ case CELL:
+ CellReference cr;
+ cr = new CellReference(refStrPart1);
+ firstRow = cr.getRow();
+ firstCol = cr.getCol();
+ cr = new CellReference(refStrPart2);
+ lastRow = cr.getRow();
+ lastCol = cr.getCol();
+ break;
+ default:
+ throw new IllegalStateException("Unexpected reference classification of '" + refStrPart1 + "'.");
+ }
+ return new LazyAreaEval(firstRow, firstCol, lastRow, lastCol, sre);
+ }
+
+ private static int parseRowRef(String refStrPart) {
+ return CellReference.convertColStringToIndex(refStrPart);
+ }
+
+ private static int parseColRef(String refStrPart) {
+ return Integer.parseInt(refStrPart) - 1;
+ }
+
+ private static NameType classifyCellReference(String str, SpreadsheetVersion ssVersion) {
+ int len = str.length();
+ if (len < 1) {
+ return CellReference.NameType.BAD_CELL_OR_NAMED_RANGE;
+ }
+ return CellReference.classifyCellReference(str, ssVersion);
+ }
+
+ public FreeRefFunction findUserDefinedFunction(String functionName) {
+ return _bookEvaluator.findUserDefinedFunction(functionName);
+ }
+
+ public ValueEval getRefEval(int rowIndex, int columnIndex) {
+ SheetRangeEvaluator sre = getRefEvaluatorForCurrentSheet();
+ return new LazyRefEval(rowIndex, columnIndex, sre);
+ }
+ public ValueEval getRef3DEval(Ref3DPtg rptg) {
+ SheetRangeEvaluator sre = createExternSheetRefEvaluator(rptg.getExternSheetIndex());
+ return new LazyRefEval(rptg.getRow(), rptg.getColumn(), sre);
+ }
public ValueEval getRef3DEval(Ref3DPxg rptg) {
SheetRangeEvaluator sre = createExternSheetRefEvaluator(
rptg.getSheetName(), rptg.getLastSheetName(), rptg.getExternalWorkbookNumber());
return new LazyRefEval(rptg.getRow(), rptg.getColumn(), sre);
}
- public ValueEval getAreaEval(int firstRowIndex, int firstColumnIndex,
- int lastRowIndex, int lastColumnIndex) {
- SheetRangeEvaluator sre = getRefEvaluatorForCurrentSheet();
- return new LazyAreaEval(firstRowIndex, firstColumnIndex, lastRowIndex, lastColumnIndex, sre);
- }
+ public ValueEval getAreaEval(int firstRowIndex, int firstColumnIndex,
+ int lastRowIndex, int lastColumnIndex) {
+ SheetRangeEvaluator sre = getRefEvaluatorForCurrentSheet();
+ return new LazyAreaEval(firstRowIndex, firstColumnIndex, lastRowIndex, lastColumnIndex, sre);
+ }
public ValueEval getArea3DEval(Area3DPtg aptg) {
SheetRangeEvaluator sre = createExternSheetRefEvaluator(aptg.getExternSheetIndex());
return new LazyAreaEval(aptg.getFirstRow(), aptg.getFirstColumn(),
@@ -348,8 +348,8 @@ public final class OperationEvaluationCo
);
return getExternalNameXEval(externName, workbookName);
}
- public ValueEval getNameXEval(NameXPxg nameXPxg) {
- ExternalSheet externSheet = _workbook.getExternalSheet(nameXPxg.getSheetName(), null, nameXPxg.getExternalWorkbookNumber());
+ public ValueEval getNameXEval(NameXPxg nameXPxg) {
+ ExternalSheet externSheet = _workbook.getExternalSheet(nameXPxg.getSheetName(), null, nameXPxg.getExternalWorkbookNumber());
if(externSheet == null || externSheet.getWorkbookName() == null) {
// External reference to our own workbook's name
return getLocalNameXEval(nameXPxg);
@@ -363,8 +363,8 @@ public final class OperationEvaluationCo
nameXPxg.getExternalWorkbookNumber()
);
return getExternalNameXEval(externName, workbookName);
- }
-
+ }
+
private ValueEval getLocalNameXEval(NameXPxg nameXPxg) {
// Look up the sheet, if present
int sIdx = -1;
@@ -383,7 +383,7 @@ public final class OperationEvaluationCo
return new FunctionNameEval(name);
}
}
- private ValueEval getLocalNameXEval(NameXPtg nameXPtg) {
+ private ValueEval getLocalNameXEval(NameXPtg nameXPtg) {
String name = _workbook.resolveNameXText(nameXPtg);
// Try to parse it as a name
@@ -406,11 +406,11 @@ public final class OperationEvaluationCo
// Must be an external function
return new FunctionNameEval(name);
}
- }
- public int getSheetIndex() {
- return _sheetIndex;
- }
-
+ }
+ public int getSheetIndex() {
+ return _sheetIndex;
+ }
+
private ValueEval getExternalNameXEval(ExternalName externName, String workbookName) {
try {
// Fetch the workbook this refers to, and the name as defined with that
Modified: poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java
URL: http://svn.apache.org/viewvc/poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java?rev=1747625&r1=1747624&r2=1747625&view=diff
==============================================================================
--- poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java (original)
+++ poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/WorkbookEvaluator.java Fri Jun 10 02:51:45 2016
@@ -93,39 +93,39 @@ import org.apache.poi.util.POILogger;
* @author Thies Wellpott (debug output enhancements)
*/
public final class WorkbookEvaluator {
-
- private static final POILogger LOG = POILogFactory.getLogger(WorkbookEvaluator.class);
+
+ private static final POILogger LOG = POILogFactory.getLogger(WorkbookEvaluator.class);
private final EvaluationWorkbook _workbook;
- private EvaluationCache _cache;
- /** part of cache entry key (useful when evaluating multiple workbooks) */
- private int _workbookIx;
-
- private final IEvaluationListener _evaluationListener;
- private final Map<EvaluationSheet, Integer> _sheetIndexesBySheet;
- private final Map<String, Integer> _sheetIndexesByName;
- private CollaboratingWorkbooksEnvironment _collaboratingWorkbookEnvironment;
- private final IStabilityClassifier _stabilityClassifier;
- private final AggregatingUDFFinder _udfFinder;
+ private EvaluationCache _cache;
+ /** part of cache entry key (useful when evaluating multiple workbooks) */
+ private int _workbookIx;
+
+ private final IEvaluationListener _evaluationListener;
+ private final Map<EvaluationSheet, Integer> _sheetIndexesBySheet;
+ private final Map<String, Integer> _sheetIndexesByName;
+ private CollaboratingWorkbooksEnvironment _collaboratingWorkbookEnvironment;
+ private final IStabilityClassifier _stabilityClassifier;
+ private final AggregatingUDFFinder _udfFinder;
private boolean _ignoreMissingWorkbooks = false;
- /**
- * @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
- */
- public WorkbookEvaluator(EvaluationWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
- this (workbook, null, stabilityClassifier, udfFinder);
- }
- /* package */ WorkbookEvaluator(EvaluationWorkbook workbook, IEvaluationListener evaluationListener,
- IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
- _workbook = workbook;
- _evaluationListener = evaluationListener;
- _cache = new EvaluationCache(evaluationListener);
- _sheetIndexesBySheet = new IdentityHashMap<EvaluationSheet, Integer>();
- _sheetIndexesByName = new IdentityHashMap<String, Integer>();
- _collaboratingWorkbookEnvironment = CollaboratingWorkbooksEnvironment.EMPTY;
- _workbookIx = 0;
- _stabilityClassifier = stabilityClassifier;
+ /**
+ * @param udfFinder pass <code>null</code> for default (AnalysisToolPak only)
+ */
+ public WorkbookEvaluator(EvaluationWorkbook workbook, IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
+ this (workbook, null, stabilityClassifier, udfFinder);
+ }
+ /* package */ WorkbookEvaluator(EvaluationWorkbook workbook, IEvaluationListener evaluationListener,
+ IStabilityClassifier stabilityClassifier, UDFFinder udfFinder) {
+ _workbook = workbook;
+ _evaluationListener = evaluationListener;
+ _cache = new EvaluationCache(evaluationListener);
+ _sheetIndexesBySheet = new IdentityHashMap<EvaluationSheet, Integer>();
+ _sheetIndexesByName = new IdentityHashMap<String, Integer>();
+ _collaboratingWorkbookEnvironment = CollaboratingWorkbooksEnvironment.EMPTY;
+ _workbookIx = 0;
+ _stabilityClassifier = stabilityClassifier;
AggregatingUDFFinder defaultToolkit = // workbook can be null in unit tests
workbook == null ? null : (AggregatingUDFFinder)workbook.getUDFFinder();
@@ -133,501 +133,501 @@ public final class WorkbookEvaluator {
defaultToolkit.add(udfFinder);
}
_udfFinder = defaultToolkit;
- }
+ }
+
+ /**
+ * also for debug use. Used in toString methods
+ */
+ /* package */ String getSheetName(int sheetIndex) {
+ return _workbook.getSheetName(sheetIndex);
+ }
+
+ /* package */ EvaluationSheet getSheet(int sheetIndex) {
+ return _workbook.getSheet(sheetIndex);
+ }
+
+ /* package */ EvaluationWorkbook getWorkbook() {
+ return _workbook;
+ }
+
+ /* package */ EvaluationName getName(String name, int sheetIndex) {
+ EvaluationName evalName = _workbook.getName(name, sheetIndex);
+ return evalName;
+ }
+
+ private static boolean isDebugLogEnabled() {
+ return LOG.check(POILogger.DEBUG);
+ }
+ private static boolean isInfoLogEnabled() {
+ return LOG.check(POILogger.INFO);
+ }
+ private static void logDebug(String s) {
+ if (isDebugLogEnabled()) {
+ LOG.log(POILogger.DEBUG, s);
+ }
+ }
+ private static void logInfo(String s) {
+ if (isInfoLogEnabled()) {
+ LOG.log(POILogger.INFO, s);
+ }
+ }
+ /* package */ void attachToEnvironment(CollaboratingWorkbooksEnvironment collaboratingWorkbooksEnvironment, EvaluationCache cache, int workbookIx) {
+ _collaboratingWorkbookEnvironment = collaboratingWorkbooksEnvironment;
+ _cache = cache;
+ _workbookIx = workbookIx;
+ }
+ /* package */ CollaboratingWorkbooksEnvironment getEnvironment() {
+ return _collaboratingWorkbookEnvironment;
+ }
+
+ /**
+ * Discards the current workbook environment and attaches to the default 'empty' environment.
+ * Also resets evaluation cache.
+ */
+ /* package */ void detachFromEnvironment() {
+ _collaboratingWorkbookEnvironment = CollaboratingWorkbooksEnvironment.EMPTY;
+ _cache = new EvaluationCache(_evaluationListener);
+ _workbookIx = 0;
+ }
+ /**
+ * @return the evaluator for another workbook which is part of the same {@link CollaboratingWorkbooksEnvironment}
+ */
+ /* package */ WorkbookEvaluator getOtherWorkbookEvaluator(String workbookName) throws WorkbookNotFoundException {
+ return _collaboratingWorkbookEnvironment.getWorkbookEvaluator(workbookName);
+ }
+
+ /* package */ IEvaluationListener getEvaluationListener() {
+ return _evaluationListener;
+ }
+
+ /**
+ * 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();
+ _sheetIndexesBySheet.clear();
+ }
+
+ /**
+ * Should be called to tell the cell value cache that the specified (value or formula) cell
+ * has changed.
+ */
+ public void notifyUpdateCell(EvaluationCell cell) {
+ int sheetIndex = getSheetIndex(cell.getSheet());
+ _cache.notifyUpdateCell(_workbookIx, sheetIndex, cell);
+ }
+ /**
+ * Should be called to tell the cell value cache that the specified cell has just been
+ * deleted.
+ */
+ public void notifyDeleteCell(EvaluationCell cell) {
+ int sheetIndex = getSheetIndex(cell.getSheet());
+ _cache.notifyDeleteCell(_workbookIx, sheetIndex, cell);
+ }
+
+ private int getSheetIndex(EvaluationSheet sheet) {
+ Integer result = _sheetIndexesBySheet.get(sheet);
+ if (result == null) {
+ int sheetIndex = _workbook.getSheetIndex(sheet);
+ if (sheetIndex < 0) {
+ throw new RuntimeException("Specified sheet from a different book");
+ }
+ result = Integer.valueOf(sheetIndex);
+ _sheetIndexesBySheet.put(sheet, result);
+ }
+ return result.intValue();
+ }
+
+ public ValueEval evaluate(EvaluationCell srcCell) {
+ int sheetIndex = getSheetIndex(srcCell.getSheet());
+ return evaluateAny(srcCell, sheetIndex, srcCell.getRowIndex(), srcCell.getColumnIndex(), new EvaluationTracker(_cache));
+ }
+
+ /**
+ * Case-insensitive.
+ * @return -1 if sheet with specified name does not exist
+ */
+ /* package */ int getSheetIndex(String sheetName) {
+ Integer result = _sheetIndexesByName.get(sheetName);
+ if (result == null) {
+ int sheetIndex = _workbook.getSheetIndex(sheetName);
+ if (sheetIndex < 0) {
+ return -1;
+ }
+ result = Integer.valueOf(sheetIndex);
+ _sheetIndexesByName.put(sheetName, result);
+ }
+ return result.intValue();
+ }
+
+ /* package */ int getSheetIndexByExternIndex(int externSheetIndex) {
+ return _workbook.convertFromExternSheetIndex(externSheetIndex);
+ }
+
+
+ /**
+ * @return never <code>null</code>, never {@link BlankEval}
+ */
+ private ValueEval evaluateAny(EvaluationCell srcCell, int sheetIndex,
+ int rowIndex, int columnIndex, EvaluationTracker tracker) {
+
+ // avoid tracking dependencies to cells that have constant definition
+ boolean shouldCellDependencyBeRecorded = _stabilityClassifier == null ? true
+ : !_stabilityClassifier.isCellFinal(sheetIndex, rowIndex, columnIndex);
+ if (srcCell == null || srcCell.getCellType() != Cell.CELL_TYPE_FORMULA) {
+ ValueEval result = getValueFromNonFormulaCell(srcCell);
+ if (shouldCellDependencyBeRecorded) {
+ tracker.acceptPlainValueDependency(_workbookIx, sheetIndex, rowIndex, columnIndex, result);
+ }
+ return result;
+ }
+
+ FormulaCellCacheEntry cce = _cache.getOrCreateFormulaCellEntry(srcCell);
+ if (shouldCellDependencyBeRecorded || cce.isInputSensitive()) {
+ tracker.acceptFormulaDependency(cce);
+ }
+ IEvaluationListener evalListener = _evaluationListener;
+ ValueEval result;
+ if (cce.getValue() == null) {
+ if (!tracker.startEvaluate(cce)) {
+ return ErrorEval.CIRCULAR_REF_ERROR;
+ }
+ OperationEvaluationContext ec = new OperationEvaluationContext(this, _workbook, sheetIndex, rowIndex, columnIndex, tracker);
+
+ try {
+
+ Ptg[] ptgs = _workbook.getFormulaTokens(srcCell);
+// System.out.println("=====");
+// XSSFCell c = ((XSSFEvaluationCell)srcCell).getXSSFCell();
+// System.out.println("Formula is "+ c);
+// System.out.println("The cell is " + c.getSheet().getSheetName()+"!"+c.getReference());
+// System.out.println("Evaluation tokens : "); // TODO Dlivshen remove
+// for (Ptg ptg : ptgs) { // TODO Dlivshen remove
+// System.out.println(ptg); // TODO Dlivshen remove
+// } // TODO Dlivshen remove
+// System.out.println("======"); // TODO Dlivshen remove
+ if (evalListener == null) {
+ result = evaluateFormula(ec, ptgs);
+ } else {
+ evalListener.onStartEvaluate(srcCell, cce);
+ result = evaluateFormula(ec, ptgs);
+ evalListener.onEndEvaluate(cce, result);
+ }
+
+ tracker.updateCacheResult(result);
+ }
+ catch (NotImplementedException e) {
+ throw addExceptionInfo(e, sheetIndex, rowIndex, columnIndex);
+ } catch (RuntimeException re) {
+ if (re.getCause() instanceof WorkbookNotFoundException && _ignoreMissingWorkbooks) {
+ logInfo(re.getCause().getMessage() + " - Continuing with cached value!");
+ switch(srcCell.getCachedFormulaResultType()) {
+ case Cell.CELL_TYPE_NUMERIC:
+ result = new NumberEval(srcCell.getNumericCellValue());
+ break;
+ case Cell.CELL_TYPE_STRING:
+ result = new StringEval(srcCell.getStringCellValue());
+ break;
+ case Cell.CELL_TYPE_BLANK:
+ result = BlankEval.instance;
+ break;
+ case Cell.CELL_TYPE_BOOLEAN:
+ result = BoolEval.valueOf(srcCell.getBooleanCellValue());
+ break;
+ case Cell.CELL_TYPE_ERROR:
+ result = ErrorEval.valueOf(srcCell.getErrorCellValue());
+ break;
+ case Cell.CELL_TYPE_FORMULA:
+ default:
+ throw new RuntimeException("Unexpected cell type '" + srcCell.getCellType()+"' found!");
+ }
+ } else {
+ throw re;
+ }
+ } finally {
+ tracker.endEvaluate(cce);
+ }
+ } else {
+ if(evalListener != null) {
+ evalListener.onCacheHit(sheetIndex, rowIndex, columnIndex, cce.getValue());
+ }
+ return cce.getValue();
+ }
+ if (isDebugLogEnabled()) {
+ String sheetName = getSheetName(sheetIndex);
+ CellReference cr = new CellReference(rowIndex, columnIndex);
+ logDebug("Evaluated " + sheetName + "!" + cr.formatAsString() + " to " + result.toString());
+ }
+ // Usually (result === cce.getValue())
+ // But sometimes: (result==ErrorEval.CIRCULAR_REF_ERROR, cce.getValue()==null)
+ // When circular references are detected, the cache entry is only updated for
+ // the top evaluation frame
+ return result;
+ }
- /**
- * also for debug use. Used in toString methods
- */
- /* package */ String getSheetName(int sheetIndex) {
- return _workbook.getSheetName(sheetIndex);
- }
-
- /* package */ EvaluationSheet getSheet(int sheetIndex) {
- return _workbook.getSheet(sheetIndex);
- }
-
- /* package */ EvaluationWorkbook getWorkbook() {
- return _workbook;
- }
-
- /* package */ EvaluationName getName(String name, int sheetIndex) {
- EvaluationName evalName = _workbook.getName(name, sheetIndex);
- return evalName;
- }
-
- private static boolean isDebugLogEnabled() {
- return LOG.check(POILogger.DEBUG);
- }
- private static boolean isInfoLogEnabled() {
- return LOG.check(POILogger.INFO);
- }
- private static void logDebug(String s) {
- if (isDebugLogEnabled()) {
- LOG.log(POILogger.DEBUG, s);
- }
- }
- private static void logInfo(String s) {
- if (isInfoLogEnabled()) {
- LOG.log(POILogger.INFO, s);
- }
- }
- /* package */ void attachToEnvironment(CollaboratingWorkbooksEnvironment collaboratingWorkbooksEnvironment, EvaluationCache cache, int workbookIx) {
- _collaboratingWorkbookEnvironment = collaboratingWorkbooksEnvironment;
- _cache = cache;
- _workbookIx = workbookIx;
- }
- /* package */ CollaboratingWorkbooksEnvironment getEnvironment() {
- return _collaboratingWorkbookEnvironment;
- }
-
- /**
- * Discards the current workbook environment and attaches to the default 'empty' environment.
- * Also resets evaluation cache.
- */
- /* package */ void detachFromEnvironment() {
- _collaboratingWorkbookEnvironment = CollaboratingWorkbooksEnvironment.EMPTY;
- _cache = new EvaluationCache(_evaluationListener);
- _workbookIx = 0;
- }
- /**
- * @return the evaluator for another workbook which is part of the same {@link CollaboratingWorkbooksEnvironment}
- */
- /* package */ WorkbookEvaluator getOtherWorkbookEvaluator(String workbookName) throws WorkbookNotFoundException {
- return _collaboratingWorkbookEnvironment.getWorkbookEvaluator(workbookName);
- }
-
- /* package */ IEvaluationListener getEvaluationListener() {
- return _evaluationListener;
- }
-
- /**
- * 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();
- _sheetIndexesBySheet.clear();
- }
-
- /**
- * Should be called to tell the cell value cache that the specified (value or formula) cell
- * has changed.
- */
- public void notifyUpdateCell(EvaluationCell cell) {
- int sheetIndex = getSheetIndex(cell.getSheet());
- _cache.notifyUpdateCell(_workbookIx, sheetIndex, cell);
- }
- /**
- * Should be called to tell the cell value cache that the specified cell has just been
- * deleted.
- */
- public void notifyDeleteCell(EvaluationCell cell) {
- int sheetIndex = getSheetIndex(cell.getSheet());
- _cache.notifyDeleteCell(_workbookIx, sheetIndex, cell);
- }
-
- private int getSheetIndex(EvaluationSheet sheet) {
- Integer result = _sheetIndexesBySheet.get(sheet);
- if (result == null) {
- int sheetIndex = _workbook.getSheetIndex(sheet);
- if (sheetIndex < 0) {
- throw new RuntimeException("Specified sheet from a different book");
- }
- result = Integer.valueOf(sheetIndex);
- _sheetIndexesBySheet.put(sheet, result);
- }
- return result.intValue();
- }
-
- public ValueEval evaluate(EvaluationCell srcCell) {
- int sheetIndex = getSheetIndex(srcCell.getSheet());
- return evaluateAny(srcCell, sheetIndex, srcCell.getRowIndex(), srcCell.getColumnIndex(), new EvaluationTracker(_cache));
- }
-
- /**
- * Case-insensitive.
- * @return -1 if sheet with specified name does not exist
- */
- /* package */ int getSheetIndex(String sheetName) {
- Integer result = _sheetIndexesByName.get(sheetName);
- if (result == null) {
- int sheetIndex = _workbook.getSheetIndex(sheetName);
- if (sheetIndex < 0) {
- return -1;
- }
- result = Integer.valueOf(sheetIndex);
- _sheetIndexesByName.put(sheetName, result);
- }
- return result.intValue();
- }
-
- /* package */ int getSheetIndexByExternIndex(int externSheetIndex) {
- return _workbook.convertFromExternSheetIndex(externSheetIndex);
- }
-
-
- /**
- * @return never <code>null</code>, never {@link BlankEval}
- */
- private ValueEval evaluateAny(EvaluationCell srcCell, int sheetIndex,
- int rowIndex, int columnIndex, EvaluationTracker tracker) {
-
- // avoid tracking dependencies to cells that have constant definition
- boolean shouldCellDependencyBeRecorded = _stabilityClassifier == null ? true
- : !_stabilityClassifier.isCellFinal(sheetIndex, rowIndex, columnIndex);
- if (srcCell == null || srcCell.getCellType() != Cell.CELL_TYPE_FORMULA) {
- ValueEval result = getValueFromNonFormulaCell(srcCell);
- if (shouldCellDependencyBeRecorded) {
- tracker.acceptPlainValueDependency(_workbookIx, sheetIndex, rowIndex, columnIndex, result);
- }
- return result;
- }
-
- FormulaCellCacheEntry cce = _cache.getOrCreateFormulaCellEntry(srcCell);
- if (shouldCellDependencyBeRecorded || cce.isInputSensitive()) {
- tracker.acceptFormulaDependency(cce);
- }
- IEvaluationListener evalListener = _evaluationListener;
- ValueEval result;
- if (cce.getValue() == null) {
- if (!tracker.startEvaluate(cce)) {
- return ErrorEval.CIRCULAR_REF_ERROR;
- }
- OperationEvaluationContext ec = new OperationEvaluationContext(this, _workbook, sheetIndex, rowIndex, columnIndex, tracker);
-
- try {
-
- Ptg[] ptgs = _workbook.getFormulaTokens(srcCell);
-// System.out.println("=====");
-// XSSFCell c = ((XSSFEvaluationCell)srcCell).getXSSFCell();
-// System.out.println("Formula is "+ c);
-// System.out.println("The cell is " + c.getSheet().getSheetName()+"!"+c.getReference());
-// System.out.println("Evaluation tokens : "); // TODO Dlivshen remove
-// for (Ptg ptg : ptgs) { // TODO Dlivshen remove
-// System.out.println(ptg); // TODO Dlivshen remove
-// } // TODO Dlivshen remove
-// System.out.println("======"); // TODO Dlivshen remove
- if (evalListener == null) {
- result = evaluateFormula(ec, ptgs);
- } else {
- evalListener.onStartEvaluate(srcCell, cce);
- result = evaluateFormula(ec, ptgs);
- evalListener.onEndEvaluate(cce, result);
- }
-
- tracker.updateCacheResult(result);
- }
- catch (NotImplementedException e) {
- throw addExceptionInfo(e, sheetIndex, rowIndex, columnIndex);
- } catch (RuntimeException re) {
- if (re.getCause() instanceof WorkbookNotFoundException && _ignoreMissingWorkbooks) {
- logInfo(re.getCause().getMessage() + " - Continuing with cached value!");
- switch(srcCell.getCachedFormulaResultType()) {
- case Cell.CELL_TYPE_NUMERIC:
- result = new NumberEval(srcCell.getNumericCellValue());
- break;
- case Cell.CELL_TYPE_STRING:
- result = new StringEval(srcCell.getStringCellValue());
- break;
- case Cell.CELL_TYPE_BLANK:
- result = BlankEval.instance;
- break;
- case Cell.CELL_TYPE_BOOLEAN:
- result = BoolEval.valueOf(srcCell.getBooleanCellValue());
- break;
- case Cell.CELL_TYPE_ERROR:
- result = ErrorEval.valueOf(srcCell.getErrorCellValue());
- break;
- case Cell.CELL_TYPE_FORMULA:
- default:
- throw new RuntimeException("Unexpected cell type '" + srcCell.getCellType()+"' found!");
- }
- } else {
- throw re;
- }
- } finally {
- tracker.endEvaluate(cce);
- }
- } else {
- if(evalListener != null) {
- evalListener.onCacheHit(sheetIndex, rowIndex, columnIndex, cce.getValue());
- }
- return cce.getValue();
- }
- if (isDebugLogEnabled()) {
- String sheetName = getSheetName(sheetIndex);
- CellReference cr = new CellReference(rowIndex, columnIndex);
- logDebug("Evaluated " + sheetName + "!" + cr.formatAsString() + " to " + result.toString());
- }
- // Usually (result === cce.getValue())
- // But sometimes: (result==ErrorEval.CIRCULAR_REF_ERROR, cce.getValue()==null)
- // When circular references are detected, the cache entry is only updated for
- // the top evaluation frame
- return result;
- }
-
- /**
- * Adds the current cell reference to the exception for easier debugging.
- * Would be nice to get the formula text as well, but that seems to require
- * too much digging around and casting to get the FormulaRenderingWorkbook.
- */
- private NotImplementedException addExceptionInfo(NotImplementedException inner, int sheetIndex, int rowIndex, int columnIndex) {
-
- try {
- String sheetName = _workbook.getSheetName(sheetIndex);
- CellReference cr = new CellReference(sheetName, rowIndex, columnIndex, false, false);
- String msg = "Error evaluating cell " + cr.formatAsString();
- return new NotImplementedException(msg, inner);
- } catch (Exception e) {
- // avoid bombing out during exception handling
- LOG.log(POILogger.ERROR, "Can't add exception info", e);
- return inner; // preserve original exception
- }
- }
- /**
- * Gets the value from a non-formula cell.
- * @param cell may be <code>null</code>
- * @return {@link BlankEval} if cell is <code>null</code> or blank, never <code>null</code>
- */
- /* package */ static ValueEval getValueFromNonFormulaCell(EvaluationCell cell) {
- if (cell == null) {
- return BlankEval.instance;
- }
- int cellType = cell.getCellType();
- switch (cellType) {
- case Cell.CELL_TYPE_NUMERIC:
- return new NumberEval(cell.getNumericCellValue());
- case Cell.CELL_TYPE_STRING:
- return new StringEval(cell.getStringCellValue());
- case Cell.CELL_TYPE_BOOLEAN:
- return BoolEval.valueOf(cell.getBooleanCellValue());
- case Cell.CELL_TYPE_BLANK:
- return BlankEval.instance;
- case Cell.CELL_TYPE_ERROR:
- return ErrorEval.valueOf(cell.getErrorCellValue());
- }
- throw new RuntimeException("Unexpected cell type (" + cellType + ")");
- }
+ /**
+ * Adds the current cell reference to the exception for easier debugging.
+ * Would be nice to get the formula text as well, but that seems to require
+ * too much digging around and casting to get the FormulaRenderingWorkbook.
+ */
+ private NotImplementedException addExceptionInfo(NotImplementedException inner, int sheetIndex, int rowIndex, int columnIndex) {
+
+ try {
+ String sheetName = _workbook.getSheetName(sheetIndex);
+ CellReference cr = new CellReference(sheetName, rowIndex, columnIndex, false, false);
+ String msg = "Error evaluating cell " + cr.formatAsString();
+ return new NotImplementedException(msg, inner);
+ } catch (Exception e) {
+ // avoid bombing out during exception handling
+ LOG.log(POILogger.ERROR, "Can't add exception info", e);
+ return inner; // preserve original exception
+ }
+ }
+ /**
+ * Gets the value from a non-formula cell.
+ * @param cell may be <code>null</code>
+ * @return {@link BlankEval} if cell is <code>null</code> or blank, never <code>null</code>
+ */
+ /* package */ static ValueEval getValueFromNonFormulaCell(EvaluationCell cell) {
+ if (cell == null) {
+ return BlankEval.instance;
+ }
+ int cellType = cell.getCellType();
+ switch (cellType) {
+ case Cell.CELL_TYPE_NUMERIC:
+ return new NumberEval(cell.getNumericCellValue());
+ case Cell.CELL_TYPE_STRING:
+ return new StringEval(cell.getStringCellValue());
+ case Cell.CELL_TYPE_BOOLEAN:
+ return BoolEval.valueOf(cell.getBooleanCellValue());
+ case Cell.CELL_TYPE_BLANK:
+ return BlankEval.instance;
+ case Cell.CELL_TYPE_ERROR:
+ return ErrorEval.valueOf(cell.getErrorCellValue());
+ }
+ throw new RuntimeException("Unexpected cell type (" + cellType + ")");
+ }
/**
* whether print detailed messages about the next formula evaluation
*/
- private boolean dbgEvaluationOutputForNextEval = false;
+ private boolean dbgEvaluationOutputForNextEval = false;
+
+ // special logger for formula evaluation output (because of possibly very large output)
+ private final POILogger EVAL_LOG = POILogFactory.getLogger("POI.FormulaEval");
+ // current indent level for evalution; negative value for no output
+ private int dbgEvaluationOutputIndent = -1;
+
+ // visibility raised for testing
+ /* package */ ValueEval evaluateFormula(OperationEvaluationContext ec, Ptg[] ptgs) {
+
+ String dbgIndentStr = ""; // always init. to non-null just for defensive avoiding NPE
+ if (dbgEvaluationOutputForNextEval) {
+ // first evaluation call when ouput is desired, so iit. this evaluator instance
+ dbgEvaluationOutputIndent = 1;
+ dbgEvaluationOutputForNextEval = false;
+ }
+ if (dbgEvaluationOutputIndent > 0) {
+ // init. indent string to needed spaces (create as substring vom very long space-only string;
+ // limit indendation for deep recursions)
+ dbgIndentStr = " ";
+ dbgIndentStr = dbgIndentStr.substring(0, Math.min(dbgIndentStr.length(), dbgEvaluationOutputIndent*2));
+ EVAL_LOG.log(POILogger.WARN, dbgIndentStr
+ + "- evaluateFormula('" + ec.getRefEvaluatorForCurrentSheet().getSheetNameRange()
+ + "'/" + new CellReference(ec.getRowIndex(), ec.getColumnIndex()).formatAsString()
+ + "): " + Arrays.toString(ptgs).replaceAll("\\Qorg.apache.poi.ss.formula.ptg.\\E", ""));
+ dbgEvaluationOutputIndent++;
+ }
+
+ Stack<ValueEval> stack = new Stack<ValueEval>();
+ 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 (dbgEvaluationOutputIndent > 0) {
+ EVAL_LOG.log(POILogger.INFO, dbgIndentStr + " * ptg " + i + ": " + ptg);
+ }
+ if (ptg instanceof AttrPtg) {
+ AttrPtg attrPtg = (AttrPtg) ptg;
+ if (attrPtg.isSum()) {
+ // Excel prefers to encode 'SUM()' as a tAttr token, but this evaluator
+ // expects the equivalent function token
+ ptg = FuncVarPtg.SUM;
+ }
+ if (attrPtg.isOptimizedChoose()) {
+ ValueEval arg0 = stack.pop();
+ int[] jumpTable = attrPtg.getJumpTable();
+ int dist;
+ int nChoices = jumpTable.length;
+ try {
+ int switchIndex = Choose.evaluateFirstArg(arg0, ec.getRowIndex(), ec.getColumnIndex());
+ if (switchIndex<1 || switchIndex > nChoices) {
+ stack.push(ErrorEval.VALUE_INVALID);
+ dist = attrPtg.getChooseFuncOffset() + 4; // +4 for tFuncFar(CHOOSE)
+ } else {
+ dist = jumpTable[switchIndex-1];
+ }
+ } catch (EvaluationException e) {
+ stack.push(e.getErrorEval());
+ dist = attrPtg.getChooseFuncOffset() + 4; // +4 for tFuncFar(CHOOSE)
+ }
+ // Encoded dist for tAttrChoose includes size of jump table, but
+ // countTokensToBeSkipped() does not (it counts whole tokens).
+ dist -= nChoices*2+2; // subtract jump table size
+ i+= countTokensToBeSkipped(ptgs, i, dist);
+ continue;
+ }
+ if (attrPtg.isOptimizedIf()) {
+ ValueEval arg0 = stack.pop();
+ boolean evaluatedPredicate;
+ try {
+ evaluatedPredicate = IfFunc.evaluateFirstArg(arg0, ec.getRowIndex(), ec.getColumnIndex());
+ } catch (EvaluationException e) {
+ stack.push(e.getErrorEval());
+ int dist = attrPtg.getData();
+ i+= countTokensToBeSkipped(ptgs, i, dist);
+ attrPtg = (AttrPtg) ptgs[i];
+ dist = attrPtg.getData()+1;
+ i+= countTokensToBeSkipped(ptgs, i, dist);
+ continue;
+ }
+ if (evaluatedPredicate) {
+ // nothing to skip - true param follows
+ } else {
+ int dist = attrPtg.getData();
+ i+= countTokensToBeSkipped(ptgs, i, dist);
+ Ptg nextPtg = ptgs[i+1];
+ if (ptgs[i] instanceof AttrPtg && nextPtg instanceof FuncVarPtg &&
+ // in order to verify that there is no third param, we need to check
+ // if we really have the IF next or some other FuncVarPtg as third param, e.g. ROW()/COLUMN()!
+ ((FuncVarPtg)nextPtg).getFunctionIndex() == FunctionMetadataRegistry.FUNCTION_INDEX_IF) {
+ // this is an if statement without a false param (as opposed to MissingArgPtg as the false param)
+ i++;
+ stack.push(BoolEval.FALSE);
+ }
+ }
+ continue;
+ }
+ if (attrPtg.isSkip()) {
+ int dist = attrPtg.getData()+1;
+ i+= countTokensToBeSkipped(ptgs, i, dist);
+ if (stack.peek() == MissingArgEval.instance) {
+ stack.pop();
+ stack.push(BlankEval.instance);
+ }
+ continue;
+ }
+ }
+ if (ptg instanceof ControlPtg) {
+ // skip Parentheses, Attr, etc
+ continue;
+ }
+ if (ptg instanceof MemFuncPtg || ptg instanceof MemAreaPtg) {
+ // can ignore, rest of tokens for this expression are in OK RPN order
+ continue;
+ }
+ if (ptg instanceof MemErrPtg) {
+ continue;
+ }
+
+ ValueEval opResult;
+ if (ptg instanceof OperationPtg) {
+ OperationPtg optg = (OperationPtg) ptg;
+
+ if (optg instanceof UnionPtg) { continue; }
+
+
+ int numops = optg.getNumberOfOperands();
+ ValueEval[] ops = new ValueEval[numops];
+
+ // storing the ops in reverse order since they are popping
+ for (int j = numops - 1; j >= 0; j--) {
+ ValueEval p = stack.pop();
+ ops[j] = p;
+ }
+// logDebug("invoke " + operation + " (nAgs=" + numops + ")");
+ opResult = OperationEvaluatorFactory.evaluate(optg, ops, ec);
+ } else {
+ opResult = getEvalForPtg(ptg, ec);
+ }
+ if (opResult == null) {
+ throw new RuntimeException("Evaluation result must not be null");
+ }
+// logDebug("push " + opResult);
+ stack.push(opResult);
+ if (dbgEvaluationOutputIndent > 0) {
+ EVAL_LOG.log(POILogger.INFO, dbgIndentStr + " = " + opResult);
+ }
+ }
+
+ ValueEval value = stack.pop();
+ if (!stack.isEmpty()) {
+ throw new IllegalStateException("evaluation stack not empty");
+ }
+ ValueEval result = dereferenceResult(value, ec.getRowIndex(), ec.getColumnIndex());
+ if (dbgEvaluationOutputIndent > 0) {
+ EVAL_LOG.log(POILogger.INFO, dbgIndentStr + "finshed eval of "
+ + new CellReference(ec.getRowIndex(), ec.getColumnIndex()).formatAsString()
+ + ": " + result);
+ dbgEvaluationOutputIndent--;
+ if (dbgEvaluationOutputIndent == 1) {
+ // this evaluation is done, reset indent to stop logging
+ dbgEvaluationOutputIndent = -1;
+ }
+ } // if
+ return result;
+
+ }
+
+ /**
+ * Calculates the number of tokens that the evaluator should skip upon reaching a tAttrSkip.
+ *
+ * @return the number of tokens (starting from <tt>startIndex+1</tt>) that need to be skipped
+ * to achieve the specified <tt>distInBytes</tt> skip distance.
+ */
+ private static int countTokensToBeSkipped(Ptg[] ptgs, int startIndex, int distInBytes) {
+ int remBytes = distInBytes;
+ int index = startIndex;
+ while (remBytes != 0) {
+ index++;
+ remBytes -= ptgs[index].getSize();
+ if (remBytes < 0) {
+ throw new RuntimeException("Bad skip distance (wrong token size calculation).");
+ }
+ if (index >= ptgs.length) {
+ throw new RuntimeException("Skip distance too far (ran out of formula tokens).");
+ }
+ }
+ return index-startIndex;
+ }
- // special logger for formula evaluation output (because of possibly very large output)
- private final POILogger EVAL_LOG = POILogFactory.getLogger("POI.FormulaEval");
- // current indent level for evalution; negative value for no output
- private int dbgEvaluationOutputIndent = -1;
-
- // visibility raised for testing
- /* package */ ValueEval evaluateFormula(OperationEvaluationContext ec, Ptg[] ptgs) {
-
- String dbgIndentStr = ""; // always init. to non-null just for defensive avoiding NPE
- if (dbgEvaluationOutputForNextEval) {
- // first evaluation call when ouput is desired, so iit. this evaluator instance
- dbgEvaluationOutputIndent = 1;
- dbgEvaluationOutputForNextEval = false;
- }
- if (dbgEvaluationOutputIndent > 0) {
- // init. indent string to needed spaces (create as substring vom very long space-only string;
- // limit indendation for deep recursions)
- dbgIndentStr = " ";
- dbgIndentStr = dbgIndentStr.substring(0, Math.min(dbgIndentStr.length(), dbgEvaluationOutputIndent*2));
- EVAL_LOG.log(POILogger.WARN, dbgIndentStr
- + "- evaluateFormula('" + ec.getRefEvaluatorForCurrentSheet().getSheetNameRange()
- + "'/" + new CellReference(ec.getRowIndex(), ec.getColumnIndex()).formatAsString()
- + "): " + Arrays.toString(ptgs).replaceAll("\\Qorg.apache.poi.ss.formula.ptg.\\E", ""));
- dbgEvaluationOutputIndent++;
- }
-
- Stack<ValueEval> stack = new Stack<ValueEval>();
- 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 (dbgEvaluationOutputIndent > 0) {
- EVAL_LOG.log(POILogger.INFO, dbgIndentStr + " * ptg " + i + ": " + ptg);
- }
- if (ptg instanceof AttrPtg) {
- AttrPtg attrPtg = (AttrPtg) ptg;
- if (attrPtg.isSum()) {
- // Excel prefers to encode 'SUM()' as a tAttr token, but this evaluator
- // expects the equivalent function token
- ptg = FuncVarPtg.SUM;
- }
- if (attrPtg.isOptimizedChoose()) {
- ValueEval arg0 = stack.pop();
- int[] jumpTable = attrPtg.getJumpTable();
- int dist;
- int nChoices = jumpTable.length;
- try {
- int switchIndex = Choose.evaluateFirstArg(arg0, ec.getRowIndex(), ec.getColumnIndex());
- if (switchIndex<1 || switchIndex > nChoices) {
- stack.push(ErrorEval.VALUE_INVALID);
- dist = attrPtg.getChooseFuncOffset() + 4; // +4 for tFuncFar(CHOOSE)
- } else {
- dist = jumpTable[switchIndex-1];
- }
- } catch (EvaluationException e) {
- stack.push(e.getErrorEval());
- dist = attrPtg.getChooseFuncOffset() + 4; // +4 for tFuncFar(CHOOSE)
- }
- // Encoded dist for tAttrChoose includes size of jump table, but
- // countTokensToBeSkipped() does not (it counts whole tokens).
- dist -= nChoices*2+2; // subtract jump table size
- i+= countTokensToBeSkipped(ptgs, i, dist);
- continue;
- }
- if (attrPtg.isOptimizedIf()) {
- ValueEval arg0 = stack.pop();
- boolean evaluatedPredicate;
- try {
- evaluatedPredicate = IfFunc.evaluateFirstArg(arg0, ec.getRowIndex(), ec.getColumnIndex());
- } catch (EvaluationException e) {
- stack.push(e.getErrorEval());
- int dist = attrPtg.getData();
- i+= countTokensToBeSkipped(ptgs, i, dist);
- attrPtg = (AttrPtg) ptgs[i];
- dist = attrPtg.getData()+1;
- i+= countTokensToBeSkipped(ptgs, i, dist);
- continue;
- }
- if (evaluatedPredicate) {
- // nothing to skip - true param follows
- } else {
- int dist = attrPtg.getData();
- i+= countTokensToBeSkipped(ptgs, i, dist);
- Ptg nextPtg = ptgs[i+1];
- if (ptgs[i] instanceof AttrPtg && nextPtg instanceof FuncVarPtg &&
- // in order to verify that there is no third param, we need to check
- // if we really have the IF next or some other FuncVarPtg as third param, e.g. ROW()/COLUMN()!
- ((FuncVarPtg)nextPtg).getFunctionIndex() == FunctionMetadataRegistry.FUNCTION_INDEX_IF) {
- // this is an if statement without a false param (as opposed to MissingArgPtg as the false param)
- i++;
- stack.push(BoolEval.FALSE);
- }
- }
- continue;
- }
- if (attrPtg.isSkip()) {
- int dist = attrPtg.getData()+1;
- i+= countTokensToBeSkipped(ptgs, i, dist);
- if (stack.peek() == MissingArgEval.instance) {
- stack.pop();
- stack.push(BlankEval.instance);
- }
- continue;
- }
- }
- if (ptg instanceof ControlPtg) {
- // skip Parentheses, Attr, etc
- continue;
- }
- if (ptg instanceof MemFuncPtg || ptg instanceof MemAreaPtg) {
- // can ignore, rest of tokens for this expression are in OK RPN order
- continue;
- }
- if (ptg instanceof MemErrPtg) {
- continue;
- }
-
- ValueEval opResult;
- if (ptg instanceof OperationPtg) {
- OperationPtg optg = (OperationPtg) ptg;
-
- if (optg instanceof UnionPtg) { continue; }
-
-
- int numops = optg.getNumberOfOperands();
- ValueEval[] ops = new ValueEval[numops];
-
- // storing the ops in reverse order since they are popping
- for (int j = numops - 1; j >= 0; j--) {
- ValueEval p = stack.pop();
- ops[j] = p;
- }
-// logDebug("invoke " + operation + " (nAgs=" + numops + ")");
- opResult = OperationEvaluatorFactory.evaluate(optg, ops, ec);
- } else {
- opResult = getEvalForPtg(ptg, ec);
- }
- if (opResult == null) {
- throw new RuntimeException("Evaluation result must not be null");
- }
-// logDebug("push " + opResult);
- stack.push(opResult);
- if (dbgEvaluationOutputIndent > 0) {
- EVAL_LOG.log(POILogger.INFO, dbgIndentStr + " = " + opResult);
- }
- }
-
- ValueEval value = stack.pop();
- if (!stack.isEmpty()) {
- throw new IllegalStateException("evaluation stack not empty");
- }
- ValueEval result = dereferenceResult(value, ec.getRowIndex(), ec.getColumnIndex());
- if (dbgEvaluationOutputIndent > 0) {
- EVAL_LOG.log(POILogger.INFO, dbgIndentStr + "finshed eval of "
- + new CellReference(ec.getRowIndex(), ec.getColumnIndex()).formatAsString()
- + ": " + result);
- dbgEvaluationOutputIndent--;
- if (dbgEvaluationOutputIndent == 1) {
- // this evaluation is done, reset indent to stop logging
- dbgEvaluationOutputIndent = -1;
- }
- } // if
- return result;
-
- }
-
- /**
- * Calculates the number of tokens that the evaluator should skip upon reaching a tAttrSkip.
- *
- * @return the number of tokens (starting from <tt>startIndex+1</tt>) that need to be skipped
- * to achieve the specified <tt>distInBytes</tt> skip distance.
- */
- private static int countTokensToBeSkipped(Ptg[] ptgs, int startIndex, int distInBytes) {
- int remBytes = distInBytes;
- int index = startIndex;
- while (remBytes != 0) {
- index++;
- remBytes -= ptgs[index].getSize();
- if (remBytes < 0) {
- throw new RuntimeException("Bad skip distance (wrong token size calculation).");
- }
- if (index >= ptgs.length) {
- throw new RuntimeException("Skip distance too far (ran out of formula tokens).");
- }
- }
- return index-startIndex;
- }
-
- /**
- * 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 {@link NumberEval}, {@link StringEval}, {@link BoolEval}, or
- * {@link ErrorEval}. Never <code>null</code>. {@link BlankEval} is
- * converted to {@link NumberEval#ZERO}
- */
- public static ValueEval dereferenceResult(ValueEval evaluationResult, int srcRowNum, int srcColNum) {
- ValueEval value;
- try {
- value = OperandResolver.getSingleValue(evaluationResult, srcRowNum, srcColNum);
- } catch (EvaluationException e) {
- return e.getErrorEval();
- }
- 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 {@link NumberEval}, {@link StringEval}, {@link BoolEval}, or
+ * {@link ErrorEval}. Never <code>null</code>. {@link BlankEval} is
+ * converted to {@link NumberEval#ZERO}
+ */
+ public static ValueEval dereferenceResult(ValueEval evaluationResult, int srcRowNum, int srcColNum) {
+ ValueEval value;
+ try {
+ value = OperandResolver.getSingleValue(evaluationResult, srcRowNum, srcColNum);
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+ 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;
+ }
/**
@@ -719,7 +719,7 @@ public final class WorkbookEvaluator {
}
return eval;
}
-
+
private ValueEval getEvalForNameRecord(EvaluationName nameRecord, OperationEvaluationContext ec) {
if (nameRecord.isFunctionName()) {
return new FunctionNameEval(nameRecord.getNameText());
@@ -734,25 +734,25 @@ public final class WorkbookEvaluator {
/**
* YK: Used by OperationEvaluationContext to resolve indirect names.
*/
- /*package*/ ValueEval evaluateNameFormula(Ptg[] ptgs, OperationEvaluationContext ec) {
+ /*package*/ ValueEval evaluateNameFormula(Ptg[] ptgs, OperationEvaluationContext ec) {
if (ptgs.length == 1) {
return getEvalForPtg(ptgs[0], ec);
}
- return evaluateFormula(ec, ptgs);
- }
+ return evaluateFormula(ec, ptgs);
+ }
+
+ /**
+ * Used by the lazy ref evals whenever they need to get the value of a contained cell.
+ */
+ /* package */ ValueEval evaluateReference(EvaluationSheet sheet, int sheetIndex, int rowIndex,
+ int columnIndex, EvaluationTracker tracker) {
- /**
- * Used by the lazy ref evals whenever they need to get the value of a contained cell.
- */
- /* package */ ValueEval evaluateReference(EvaluationSheet sheet, int sheetIndex, int rowIndex,
- int columnIndex, EvaluationTracker tracker) {
-
- EvaluationCell cell = sheet.getCell(rowIndex, columnIndex);
- return evaluateAny(cell, sheetIndex, rowIndex, columnIndex, tracker);
- }
- public FreeRefFunction findUserDefinedFunction(String functionName) {
- return _udfFinder.findFunction(functionName);
- }
+ EvaluationCell cell = sheet.getCell(rowIndex, columnIndex);
+ return evaluateAny(cell, sheetIndex, rowIndex, columnIndex, tracker);
+ }
+ public FreeRefFunction findUserDefinedFunction(String functionName) {
+ return _udfFinder.findFunction(functionName);
+ }
/**
* Whether to ignore missing references to external workbooks and
Modified: poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/functions/Indirect.java
URL: http://svn.apache.org/viewvc/poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/functions/Indirect.java?rev=1747625&r1=1747624&r2=1747625&view=diff
==============================================================================
--- poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/functions/Indirect.java (original)
+++ poi/branches/xssf_structured_references/src/java/org/apache/poi/ss/formula/functions/Indirect.java Fri Jun 10 02:51:45 2016
@@ -49,78 +49,78 @@ public final class Indirect implements F
public static final FreeRefFunction instance = new Indirect();
- private Indirect() {
- // enforce singleton
- }
-
- public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
- if (args.length < 1) {
- return ErrorEval.VALUE_INVALID;
- }
-
- boolean isA1style;
- String text;
- try {
- ValueEval ve = OperandResolver.getSingleValue(args[0], ec.getRowIndex(), ec
- .getColumnIndex());
- text = OperandResolver.coerceValueToString(ve);
- switch (args.length) {
- case 1:
- isA1style = true;
- break;
- case 2:
- isA1style = evaluateBooleanArg(args[1], ec);
- break;
- default:
- return ErrorEval.VALUE_INVALID;
- }
- } catch (EvaluationException e) {
- return e.getErrorEval();
- }
-
- return evaluateIndirect(ec, text, isA1style);
- }
-
- private static boolean evaluateBooleanArg(ValueEval arg, OperationEvaluationContext ec)
- throws EvaluationException {
- ValueEval ve = OperandResolver.getSingleValue(arg, ec.getRowIndex(), ec.getColumnIndex());
-
- if (ve == BlankEval.instance || ve == MissingArgEval.instance) {
- return false;
- }
- // numeric quantities follow standard boolean conversion rules
- // for strings, only "TRUE" and "FALSE" (case insensitive) are valid
- return OperandResolver.coerceValueToBoolean(ve, false).booleanValue();
- }
-
- private static ValueEval evaluateIndirect(final OperationEvaluationContext ec, String text,
- boolean isA1style) {
-
- ec.getRowIndex();
- ec.getColumnIndex();
-
- // Search backwards for '!' because sheet names can contain '!'
- int plingPos = text.lastIndexOf('!');
-
- String workbookName;
- String sheetName;
- String refText; // whitespace around this gets trimmed OK
- if (plingPos < 0) {
- workbookName = null;
- sheetName = null;
- refText = text;
- } else {
- String[] parts = parseWorkbookAndSheetName(text.subSequence(0, plingPos));
- if (parts == null) {
- return ErrorEval.REF_INVALID;
- }
- workbookName = parts[0];
- sheetName = parts[1];
- refText = text.substring(plingPos + 1);
- }
+ private Indirect() {
+ // enforce singleton
+ }
+
+ public ValueEval evaluate(ValueEval[] args, OperationEvaluationContext ec) {
+ if (args.length < 1) {
+ return ErrorEval.VALUE_INVALID;
+ }
+
+ boolean isA1style;
+ String text;
+ try {
+ ValueEval ve = OperandResolver.getSingleValue(args[0], ec.getRowIndex(), ec
+ .getColumnIndex());
+ text = OperandResolver.coerceValueToString(ve);
+ switch (args.length) {
+ case 1:
+ isA1style = true;
+ break;
+ case 2:
+ isA1style = evaluateBooleanArg(args[1], ec);
+ break;
+ default:
+ return ErrorEval.VALUE_INVALID;
+ }
+ } catch (EvaluationException e) {
+ return e.getErrorEval();
+ }
+
+ return evaluateIndirect(ec, text, isA1style);
+ }
- String refStrPart1;
- String refStrPart2;
+ private static boolean evaluateBooleanArg(ValueEval arg, OperationEvaluationContext ec)
+ throws EvaluationException {
+ ValueEval ve = OperandResolver.getSingleValue(arg, ec.getRowIndex(), ec.getColumnIndex());
+
+ if (ve == BlankEval.instance || ve == MissingArgEval.instance) {
+ return false;
+ }
+ // numeric quantities follow standard boolean conversion rules
+ // for strings, only "TRUE" and "FALSE" (case insensitive) are valid
+ return OperandResolver.coerceValueToBoolean(ve, false).booleanValue();
+ }
+
+ private static ValueEval evaluateIndirect(final OperationEvaluationContext ec, String text,
+ boolean isA1style) {
+
+ ec.getRowIndex();
+ ec.getColumnIndex();
+
+ // Search backwards for '!' because sheet names can contain '!'
+ int plingPos = text.lastIndexOf('!');
+
+ String workbookName;
+ String sheetName;
+ String refText; // whitespace around this gets trimmed OK
+ if (plingPos < 0) {
+ workbookName = null;
+ sheetName = null;
+ refText = text;
+ } else {
+ String[] parts = parseWorkbookAndSheetName(text.subSequence(0, plingPos));
+ if (parts == null) {
+ return ErrorEval.REF_INVALID;
+ }
+ workbookName = parts[0];
+ sheetName = parts[1];
+ refText = text.substring(plingPos + 1);
+ }
+
+ String refStrPart1;
+ String refStrPart2;
if (Table.isStructuredReference.matcher(refText).matches()) { // The argument is structured reference
Area3DPxg areaPtg = null;
try{
@@ -130,128 +130,128 @@ public final class Indirect implements F
}
return ec.getArea3DEval(areaPtg);
} else { // The argumnet is regular reference
- int colonPos = refText.indexOf(':');
- if (colonPos < 0) {
- refStrPart1 = refText.trim();
- refStrPart2 = null;
- } else {
- refStrPart1 = refText.substring(0, colonPos).trim();
- refStrPart2 = refText.substring(colonPos + 1).trim();
- }
- return ec.getDynamicReference(workbookName, sheetName, refStrPart1, refStrPart2, isA1style);
- }
- }
-
- /**
- * @return array of length 2: {workbookName, sheetName,}. Second element will always be
- * present. First element may be null if sheetName is unqualified.
- * Returns <code>null</code> if text cannot be parsed.
- */
- private static String[] parseWorkbookAndSheetName(CharSequence text) {
- int lastIx = text.length() - 1;
- if (lastIx < 0) {
- return null;
- }
- if (canTrim(text)) {
- return null;
- }
- char firstChar = text.charAt(0);
- if (Character.isWhitespace(firstChar)) {
- return null;
- }
- if (firstChar == '\'') {
- // workbookName or sheetName needs quoting
- // quotes go around both
- if (text.charAt(lastIx) != '\'') {
- return null;
- }
- firstChar = text.charAt(1);
- if (Character.isWhitespace(firstChar)) {
- return null;
- }
- String wbName;
- int sheetStartPos;
- if (firstChar == '[') {
- int rbPos = text.toString().lastIndexOf(']');
- if (rbPos < 0) {
- return null;
- }
- wbName = unescapeString(text.subSequence(2, rbPos));
- if (wbName == null || canTrim(wbName)) {
- return null;
- }
- sheetStartPos = rbPos + 1;
- } else {
- wbName = null;
- sheetStartPos = 1;
- }
-
- // else - just sheet name
- String sheetName = unescapeString(text.subSequence(sheetStartPos, lastIx));
- if (sheetName == null) { // note - when quoted, sheetName can
- // start/end with whitespace
- return null;
- }
- return new String[] { wbName, sheetName, };
- }
-
- if (firstChar == '[') {
- int rbPos = text.toString().lastIndexOf(']');
- if (rbPos < 0) {
- return null;
- }
- CharSequence wbName = text.subSequence(1, rbPos);
- if (canTrim(wbName)) {
- return null;
- }
- CharSequence sheetName = text.subSequence(rbPos + 1, text.length());
- if (canTrim(sheetName)) {
- return null;
- }
- return new String[] { wbName.toString(), sheetName.toString(), };
- }
- // else - just sheet name
- return new String[] { null, text.toString(), };
- }
-
- /**
- * @return <code>null</code> if there is a syntax error in any escape sequence
- * (the typical syntax error is a single quote character not followed by another).
- */
- private static String unescapeString(CharSequence text) {
- int len = text.length();
- StringBuilder sb = new StringBuilder(len);
- int i = 0;
- while (i < len) {
- char ch = text.charAt(i);
- if (ch == '\'') {
- // every quote must be followed by another
- i++;
- if (i >= len) {
- return null;
- }
- ch = text.charAt(i);
- if (ch != '\'') {
- return null;
- }
- }
- sb.append(ch);
- i++;
- }
- return sb.toString();
- }
-
- private static boolean canTrim(CharSequence text) {
- int lastIx = text.length() - 1;
- if (lastIx < 0) {
- return false;
- }
- if (Character.isWhitespace(text.charAt(0))) {
- return true;
- }
- if (Character.isWhitespace(text.charAt(lastIx))) {
- return true;
- }
- return false;
- }
+ int colonPos = refText.indexOf(':');
+ if (colonPos < 0) {
+ refStrPart1 = refText.trim();
+ refStrPart2 = null;
+ } else {
+ refStrPart1 = refText.substring(0, colonPos).trim();
+ refStrPart2 = refText.substring(colonPos + 1).trim();
+ }
+ return ec.getDynamicReference(workbookName, sheetName, refStrPart1, refStrPart2, isA1style);
+ }
+ }
+
+ /**
+ * @return array of length 2: {workbookName, sheetName,}. Second element will always be
+ * present. First element may be null if sheetName is unqualified.
+ * Returns <code>null</code> if text cannot be parsed.
+ */
+ private static String[] parseWorkbookAndSheetName(CharSequence text) {
+ int lastIx = text.length() - 1;
+ if (lastIx < 0) {
+ return null;
+ }
+ if (canTrim(text)) {
+ return null;
+ }
+ char firstChar = text.charAt(0);
+ if (Character.isWhitespace(firstChar)) {
+ return null;
+ }
+ if (firstChar == '\'') {
+ // workbookName or sheetName needs quoting
+ // quotes go around both
+ if (text.charAt(lastIx) != '\'') {
+ return null;
+ }
+ firstChar = text.charAt(1);
+ if (Character.isWhitespace(firstChar)) {
+ return null;
+ }
+ String wbName;
+ int sheetStartPos;
+ if (firstChar == '[') {
+ int rbPos = text.toString().lastIndexOf(']');
+ if (rbPos < 0) {
+ return null;
+ }
+ wbName = unescapeString(text.subSequence(2, rbPos));
+ if (wbName == null || canTrim(wbName)) {
+ return null;
+ }
+ sheetStartPos = rbPos + 1;
+ } else {
+ wbName = null;
+ sheetStartPos = 1;
+ }
+
+ // else - just sheet name
+ String sheetName = unescapeString(text.subSequence(sheetStartPos, lastIx));
+ if (sheetName == null) { // note - when quoted, sheetName can
+ // start/end with whitespace
+ return null;
+ }
+ return new String[] { wbName, sheetName, };
+ }
+
+ if (firstChar == '[') {
+ int rbPos = text.toString().lastIndexOf(']');
+ if (rbPos < 0) {
+ return null;
+ }
+ CharSequence wbName = text.subSequence(1, rbPos);
+ if (canTrim(wbName)) {
+ return null;
+ }
+ CharSequence sheetName = text.subSequence(rbPos + 1, text.length());
+ if (canTrim(sheetName)) {
+ return null;
+ }
+ return new String[] { wbName.toString(), sheetName.toString(), };
+ }
+ // else - just sheet name
+ return new String[] { null, text.toString(), };
+ }
+
+ /**
+ * @return <code>null</code> if there is a syntax error in any escape sequence
+ * (the typical syntax error is a single quote character not followed by another).
+ */
+ private static String unescapeString(CharSequence text) {
+ int len = text.length();
+ StringBuilder sb = new StringBuilder(len);
+ int i = 0;
+ while (i < len) {
+ char ch = text.charAt(i);
+ if (ch == '\'') {
+ // every quote must be followed by another
+ i++;
+ if (i >= len) {
+ return null;
+ }
+ ch = text.charAt(i);
+ if (ch != '\'') {
+ return null;
+ }
+ }
+ sb.append(ch);
+ i++;
+ }
+ return sb.toString();
+ }
+
+ private static boolean canTrim(CharSequence text) {
+ int lastIx = text.length() - 1;
+ if (lastIx < 0) {
+ return false;
+ }
+ if (Character.isWhitespace(text.charAt(0))) {
+ return true;
+ }
+ if (Character.isWhitespace(text.charAt(lastIx))) {
+ return true;
+ }
+ return false;
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org