/** * 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 + ")"); }
/** @return never <code>null</code>, never {@link BlankEval} */ private ValueEval evaluateAny( EvaluationCell srcCell, int sheetIndex, int rowIndex, int columnIndex, EvaluationTracker tracker) { // avoid tracking dependencies for 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); if (evalListener == null) { result = evaluateFormula(ec, ptgs); } else { evalListener.onStartEvaluate(srcCell, cce, ptgs); result = evaluateFormula(ec, ptgs); evalListener.onEndEvaluate(cce, result); } tracker.updateCacheResult(result); } catch (NotImplementedException e) { throw addExceptionInfo(e, sheetIndex, rowIndex, columnIndex); } 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; }