/// <summary> /// Get total count of cells in the specified range without initalizing them all /// (which might cause serious performance issues on column-wide calculations). /// </summary> /// <param name="rangeExpression">Expression referring to the cell range.</param> /// <returns>Total number of cells in the range.</returns> internal static long GetTotalCellsCount(XObjectExpression rangeExpression) { var range = ((rangeExpression)?.Value as CellRangeReference)?.Range; if (range == null) { return(0); } return((long)(range.LastColumn().ColumnNumber() - range.FirstColumn().ColumnNumber() + 1) * (long)(range.LastRow().RowNumber() - range.FirstRow().RowNumber() + 1)); }
private Expression ParseAtom() { string id; Expression x = null; switch (_token.Type) { // literals case TKTYPE.LITERAL: x = new Expression(_token); break; // identifiers case TKTYPE.IDENTIFIER: // get identifier id = (string)_token.Value; // look for functions if (_fnTbl.TryGetValue(id, out FunctionDefinition fnDef)) { var p = GetParameters(); var pCnt = p == null ? 0 : p.Count; if (fnDef.ParmMin != -1 && pCnt < fnDef.ParmMin) { Throw(string.Format("Too few parameters for function '{0}'. Expected a minimum of {1} and a maximum of {2}.", id, fnDef.ParmMin, fnDef.ParmMax)); } if (fnDef.ParmMax != -1 && pCnt > fnDef.ParmMax) { Throw(string.Format("Too many parameters for function '{0}'.Expected a minimum of {1} and a maximum of {2}.", id, fnDef.ParmMin, fnDef.ParmMax)); } x = new FunctionExpression(fnDef, p); break; } // look for simple variables (much faster than binding!) if (_vars.ContainsKey(id)) { x = new VariableExpression(_vars, id); break; } // look for external objects var xObj = GetExternalObject(id); if (xObj != null) { x = new XObjectExpression(xObj); break; } Throw("Unexpected identifier"); break; // sub-expressions case TKTYPE.GROUP: // Normally anything other than opening parenthesis is illegal here // but Excel allows omitted parameters so return empty value expression. if (_token.ID != TKID.OPEN) { return(new EmptyValueExpression()); } // get expression GetToken(); x = ParseCompare(); // check that the parenthesis was closed if (_token.ID != TKID.CLOSE) { Throw("Unbalanced parenthesis."); } break; case TKTYPE.ERROR: x = new ErrorExpression((ErrorExpression.ExpressionErrorType)_token.Value); break; } // make sure we got something... if (x == null) { Throw(); } // done GetToken(); return(x); }
Expression ParseAtom() { string id; Expression x = null; FunctionDefinition fnDef = null; switch (_token.Type) { // literals case TKTYPE.LITERAL: x = new Expression(_token); break; // identifiers case TKTYPE.IDENTIFIER: // get identifier id = (string)_token.Value; // look for functions if (_fnTbl.TryGetValue(id, out fnDef)) { var p = GetParameters(); var pCnt = p == null ? 0 : p.Count; if (fnDef.ParmMin != -1 && pCnt < fnDef.ParmMin) { Throw("Too few parameters."); } if (fnDef.ParmMax != -1 && pCnt > fnDef.ParmMax) { Throw("Too many parameters."); } x = new FunctionExpression(fnDef, p); break; } // look for simple variables (much faster than binding!) if (_vars.ContainsKey(id)) { x = new VariableExpression(_vars, id); break; } // look for external objects var xObj = GetExternalObject(id); if (xObj != null) { x = new XObjectExpression(xObj); break; } // look for bindings if (DataContext != null) { var list = new List <BindingInfo>(); for (var t = _token; t != null; t = GetMember()) { list.Add(new BindingInfo((string)t.Value, GetParameters())); } x = new BindingExpression(this, list, _ci); break; } Throw("Unexpected identifier"); break; // sub-expressions case TKTYPE.GROUP: // anything other than opening parenthesis is illegal here if (_token.ID != TKID.OPEN) { Throw("Expression expected."); } // get expression GetToken(); x = ParseCompare(); // check that the parenthesis was closed if (_token.ID != TKID.CLOSE) { Throw("Unbalanced parenthesis."); } break; } // make sure we got something... if (x == null) { Throw(); } // done GetToken(); return(x); }