/// <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);
        }
Exemple #3
0
        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);
        }