Example #1
0
        // Handle parsing of function in final pass
        override internal void FinalPass()
        {
            base.FinalPass();
            _Value.FinalPass();

            //The Changes below were added from Forum, User: solidstate http://www.fyireporting.com/forum/viewtopic.php?t=905
            if (this.DataElementName == null && this.Name == null)
            {
                // no name or dataelementname; try using expression
                FunctionField ff = _Value.Expr as FunctionField;
                if (ff != null && ff.Fld != null)
                {
                    this.DataElementName = ff.Fld.DataField;
                    this.Name            = ff.Fld.Name; // Added
                }

                FunctionAggr fa = _Value.Expr as FunctionAggr;
                if (fa != null)
                {
                    FunctionField ff2 = fa.Expr as FunctionField;
                    if (ff2 != null && ff2.Fld != null)
                    {
                        this.DataElementName = ff2.Fld.DataField;
                        this.Name            = ff2.Fld.Name;
                    }
                }
            }

            if (_ToggleImage != null)
            {
                _ToggleImage.FinalPass();
            }

            if (_HideDuplicates != null)
            {
                object o = OwnerReport.LUAggrScope[_HideDuplicates];
                if (o == null)
                {
                    OwnerReport.rl.LogError(4, "HideDuplicate '" + _HideDuplicates + "' is not a Group or DataSet name.   It will be ignored.");
                    _HideDuplicates = null;
                }
                else if (o is Grouping)
                {
                    Grouping g = o as Grouping;
                    g.AddHideDuplicates(this);
                }
                else if (o is DataSetDefn)
                {
                    DataSetDefn ds = o as DataSetDefn;
                    ds.AddHideDuplicates(this);
                }
            }
            return;
        }
Example #2
0
        // Handle parsing of function in final pass
        override internal void FinalPass()
        {
            base.FinalPass();
            _Value.FinalPass();

            if (this.DataElementName == null && this.Name == null)
            {
                // no name or dataelementname; try using expression
                FunctionField ff = _Value.Expr as FunctionField;
                if (ff != null && ff.Fld != null)
                {
                    this.DataElementName = ff.Fld.DataField;
                }
            }

            if (_ToggleImage != null)
            {
                _ToggleImage.FinalPass();
            }

            if (_HideDuplicates != null)
            {
                object o = OwnerReport.LUAggrScope[_HideDuplicates];
                if (o == null)
                {
                    OwnerReport.rl.LogError(4, "HideDuplicate '" + _HideDuplicates + "' is not a Group or DataSet name.   It will be ignored.");
                    _HideDuplicates = null;
                }
                else if (o is Grouping)
                {
                    Grouping g = o as Grouping;
                    g.AddHideDuplicates(this);
                }
                else if (o is DataSetDefn)
                {
                    DataSetDefn ds = o as DataSetDefn;
                    ds.AddHideDuplicates(this);
                }
            }
            return;
        }
Example #3
0
        List <GroupEntry> _NestedGroup;         // group one hierarchy below

        internal GroupEntry(Grouping g, Sorting s, int start)
        {
            _Group       = g;
            _Sort        = s;
            _StartRow    = start;
            _EndRow      = -1;
            _NestedGroup = new List <GroupEntry>();

            // Check to see if grouping and sorting are the same
            if (g == null || s == null)
            {
                return;                                 // nothing to check if either is null
            }
            if (s.Items.Count != g.GroupExpressions.Items.Count)
            {
                return;
            }

            for (int i = 0; i < s.Items.Count; i++)
            {
                SortBy sb = s.Items[i] as SortBy;

                if (sb.Direction == SortDirectionEnum.Descending)
                {
                    return;                                     // TODO we could optimize this
                }
                FunctionField ff = sb.SortExpression.Expr as FunctionField;
                if (ff == null || ff.GetTypeCode() != TypeCode.String)
                {
                    return;
                }

                GroupExpression ge  = g.GroupExpressions.Items[i] as GroupExpression;
                FunctionField   ff2 = ge.Expression.Expr as FunctionField;
                if (ff2 == null || ff.Fld != ff2.Fld)
                {
                    return;
                }
            }
            _Sort = null;                       // we won't need to sort since the groupby will handle it correctly
        }
Example #4
0
		// FuncIDent: IDENTIFIER ( [Expr] [, Expr]*) | IDENTIFIER
		private bool MatchFuncIDent(out IExpr result)
		{
			IExpr e;
			string fullname;			// will hold the full name
			string method;				// will hold method name or second part of name
			string firstPart;			// will hold the collection name
			string thirdPart;			// will hold third part of name
			bool bOnePart;				// simple name: no ! or . in name

			result = null;

			if (curToken.Type != TokenTypes.IDENTIFIER)
				return false;

			// Disentangle method calls from collection references
			method = fullname = curToken.Value;
			curToken = tokens.Extract();

			// Break the name into parts
			char[] breakChars = new char[] {'!', '.'};

			int posBreak = method.IndexOfAny(breakChars);
			if (posBreak > 0)
			{
				bOnePart = false;
				firstPart = method.Substring(0, posBreak);
				method = method.Substring(posBreak+1);		// rest of expression
			}
			else
			{
				bOnePart = true;
				firstPart = method;
			}

			posBreak = method.IndexOf('.');
            if (posBreak > 0)
            {
                thirdPart = method.Substring(posBreak + 1);	// rest of expression
                method = method.Substring(0, posBreak);
            }
            else
            {
                thirdPart = null;
            }

			if (curToken.Type != TokenTypes.LPAREN) switch (firstPart)
			{
				case "Fields":
					Field f = idLookup.LookupField(method);
                    if (f == null && !this._InAggregate)
                    {
                        throw new ParserException("Field '" + method + "'  not found.");
                    }
					if (thirdPart == null || thirdPart == "Value")
					{
						if (f == null)
						{
                            FunctionField ff;
                            result = ff = new FunctionField(method);
							this._FieldResolve.Add(ff);
						}
						else
							result = new FunctionField(f);	
					}
					else if (thirdPart == "IsMissing")
					{
						if (f == null)
						{
                            FunctionField ff;
							result = ff = new FunctionFieldIsMissing(method);
							this._FieldResolve.Add(ff);
						}
						else
							result = new FunctionFieldIsMissing(f);
					}
					else
						throw new ParserException("Field '" + method + "'  only supports 'Value' and 'IsMissing' properties.");
					return true;
                case "Parameters":  // see ResolveParametersMethod for resolution of MultiValue parameter function reference
					ReportParameter p = idLookup.LookupParameter(method);
					if (p == null)
						throw new ParserException("Report parameter '" + method + "'  not found.");
                    int ci = thirdPart == null? -1: thirdPart.IndexOf(".Count");
                    if (ci > 0)
                        thirdPart = thirdPart.Substring(0, ci);
                    FunctionReportParameter r;                    
					if (thirdPart == null || thirdPart == "Value")
						r = new FunctionReportParameter(p);
					else if (thirdPart == "Label")
						r = new FunctionReportParameterLabel(p);
					else
						throw new ParserException("Parameter '" + method + "'  only supports 'Value' and 'Label' properties.");
                    if (ci > 0)
                        r.SetParameterMethod("Count", null);
                    
                    result = r;
                    return true;
				case "ReportItems":
					Textbox t = idLookup.LookupReportItem(method);
					if (t == null)
						throw new ParserException("ReportItem '" + method + "'  not found.");
					if (thirdPart != null && thirdPart != "Value")
						throw new ParserException("ReportItem '" + method + "'  only supports 'Value' property.");
					result = new FunctionTextbox(t, idLookup.ExpressionName);	
					return true;
				case "Globals":
					e = idLookup.LookupGlobal(method);
					if (e == null)
						throw new ParserException("Globals '" + method + "'  not found.");
					result = e;
					return true;
				case "User":
					e = idLookup.LookupUser(method);
					if (e == null)
						throw new ParserException("User variable '" + method + "'  not found.");
					result = e;
					return true;
				case "Recursive":	// Only valid for some aggregate functions
					result = new IdentifierKey(IdentifierKeyEnum.Recursive);
					return true;
				case "Simple":		// Only valid for some aggregate functions
					result = new IdentifierKey(IdentifierKeyEnum.Simple);
					return true;
				default:
					if (!bOnePart)
						throw new ParserException(string.Format("'{0}' is an unknown identifer.", fullname));

					switch (method.ToLower())		// lexer should probably mark these
					{
						case "true":
						case "false":
							result = new ConstantBoolean(method.ToLower());
							break;
						default:
							// usually this is enum that will be used in an aggregate 
							result = new Identifier(method);
							break;
					}
					return true;
			}

			// We've got an function reference
			curToken = tokens.Extract();		// get rid of '('

			// Got a function now obtain the arguments
			int argCount=0;
			
			bool isAggregate = IsAggregate(method, bOnePart);
			if (_NoAggregate && isAggregate)
				throw new ParserException("Aggregate function '" + method + "' cannot be used within a Grouping expression.");
			if (_InAggregate && isAggregate)
				throw new ParserException("Aggregate function '" + method + "' cannot be nested in another aggregate function.");
			_InAggregate = isAggregate;
			if (_InAggregate)
				_FieldResolve = new List<FunctionField>();

            List<IExpr> largs = new List<IExpr>();
			while(true)
			{
				if (curToken.Type == TokenTypes.RPAREN)
				{	// We've got our function
					curToken = tokens.Extract();
					break;
				}
				if (argCount == 0)
				{
					// don't need to do anything
				}
				else if (curToken.Type == TokenTypes.COMMA)
				{
					curToken = tokens.Extract();
				}
				else
					throw new ParserException("Invalid function arguments.  Found '" + curToken.Value + "'  At column " + Convert.ToString(curToken.StartCol));
				
				MatchExprAndOr(out e);
				if (e == null)
					throw new ParserException("Expecting ',' or ')'.  Found '" + curToken.Value + "'  At column " + Convert.ToString(curToken.StartCol));

				largs.Add(e);
				argCount++;
			}
			if (_InAggregate)
			{
				ResolveFields(method, this._FieldResolve, largs);
				_FieldResolve = null;
				_InAggregate = false;
			}

            IExpr[] args = largs.ToArray();

			object scope;
			bool bSimple;
			if (!bOnePart)				
            {
                result = (firstPart == "Parameters")?
                    ResolveParametersMethod(method, thirdPart, args):
                    ResolveMethodCall(fullname, args);	// throw exception when fails
            }
			else switch(method.ToLower())
			{
				case "iif":
					if (args.Length != 3)
						throw new ParserException("iff function requires 3 arguments." + "  At column " + Convert.ToString(curToken.StartCol));
//  We allow any type for the first argument; it will get converted to boolean at runtime
//					if (args[0].GetTypeCode() != TypeCode.Boolean)
//						throw new ParserException("First argument to iif function must be boolean." + "  At column " + Convert.ToString(curToken.StartCol));
					result = new FunctionIif(args[0], args[1], args[2]);
					break;
				case "choose":
					if (args.Length <= 2)
						throw new ParserException("Choose function requires at least 2 arguments." + "  At column " + Convert.ToString(curToken.StartCol));
					switch (args[0].GetTypeCode())
					{
						case TypeCode.Double:
						case TypeCode.Single:
						case TypeCode.Int32:
						case TypeCode.Decimal:
						case TypeCode.Int16:
						case TypeCode.Int64:
							break;
						default:
							throw new ParserException("First argument to Choose function must be numeric." + "  At column " + Convert.ToString(curToken.StartCol));
					}
					result = new FunctionChoose(args);
					break;
				case "switch":
					if (args.Length <= 2)
						throw new ParserException("Switch function requires at least 2 arguments." + "  At column " + Convert.ToString(curToken.StartCol));
				    if (args.Length % 2 != 0)
						throw new ParserException("Switch function must have an even number of arguments." + "  At column " + Convert.ToString(curToken.StartCol));
					for (int i=0; i < args.Length; i = i+2)
					{
						if (args[i].GetTypeCode() != TypeCode.Boolean)
							throw new ParserException("Switch function must have a boolean expression every other argument." + "  At column " + Convert.ToString(curToken.StartCol));
					}
					result = new FunctionSwitch(args);
					break;
				case "format":
					if (args.Length > 2 || args.Length < 1)
						throw new ParserException("Format function requires 2 arguments." + "  At column " + Convert.ToString(curToken.StartCol));
					if (args.Length == 1)
					{
						result = new FunctionFormat(args[0], new ConstantString(""));
					}
					else
					{
						if (args[1].GetTypeCode() != TypeCode.String)
							throw new ParserException("Second argument to Format function must be a string." + "  At column " + Convert.ToString(curToken.StartCol));
						result = new FunctionFormat(args[0], args[1]);
					}
					break;

				case "fields":
					if (args.Length != 1)
						throw new ParserException("Fields collection requires exactly 1 argument." + "  At column " + Convert.ToString(curToken.StartCol));
					result = new FunctionFieldCollection(idLookup.Fields, args[0]);
                    if (curToken.Type == TokenTypes.DOT)
                    {	// user placed "."                  TODO: generalize this code
                        curToken = tokens.Extract();                // skip past dot operator
                        if (curToken.Type == TokenTypes.IDENTIFIER && curToken.Value.ToLowerInvariant() == "value")
                            curToken = tokens.Extract();            // only support "value" property for now
                        else
                            throw new ParserException(curToken.Value + " is not a known property for Fields." + "  At column " + Convert.ToString(curToken.StartCol));
                    }
                    break;
				case "parameters":
					if (args.Length != 1)
						throw new ParserException("Parameters collection requires exactly 1 argument." + "  At column " + Convert.ToString(curToken.StartCol));
					result = new FunctionParameterCollection(idLookup.Parameters, args[0]);
                    if (curToken.Type == TokenTypes.DOT)
                    {	// user placed "." 
                        curToken = tokens.Extract();                // skip past dot operator
                        if (curToken.Type == TokenTypes.IDENTIFIER && curToken.Value.ToLowerInvariant() == "value")
                            curToken = tokens.Extract();            // only support "value" property for now
                        else
                            throw new ParserException(curToken.Value + " is not a known property for Fields." + "  At column " + Convert.ToString(curToken.StartCol));
                    }
                    break;
				case "reportitems":
					if (args.Length != 1)
						throw new ParserException("ReportItems collection requires exactly 1 argument." + "  At column " + Convert.ToString(curToken.StartCol));
					result = new FunctionReportItemCollection(idLookup.ReportItems, args[0]);
                    if (curToken.Type == TokenTypes.DOT)
                    {	// user placed "." 
                        curToken = tokens.Extract();                // skip past dot operator
                        if (curToken.Type == TokenTypes.IDENTIFIER && curToken.Value.ToLowerInvariant() == "value")
                            curToken = tokens.Extract();            // only support "value" property for now
                        else
                            throw new ParserException(curToken.Value + " is not a known property for Fields." + "  At column " + Convert.ToString(curToken.StartCol));
                    }
                    break;
				case "globals":
					if (args.Length != 1)
						throw new ParserException("Globals collection requires exactly 1 argument." + "  At column " + Convert.ToString(curToken.StartCol));
					result = new FunctionGlobalCollection(idLookup.Globals, args[0]);
					break;
				case "user":
					if (args.Length != 1)
						throw new ParserException("User collection requires exactly 1 argument." + "  At column " + Convert.ToString(curToken.StartCol));
					result = new FunctionUserCollection(idLookup.User, args[0]);
					break;
				case "sum":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrSum aggrFS = new FunctionAggrSum(_DataCache, args[0], scope);
					aggrFS.LevelCheck = bSimple;
					result = aggrFS;
					break;
				case "avg":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrAvg aggrFA = new FunctionAggrAvg(_DataCache, args[0], scope);
					aggrFA.LevelCheck = bSimple;
					result = aggrFA;
					break;
				case "min":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrMin aggrFMin = new FunctionAggrMin(_DataCache, args[0], scope);
					aggrFMin.LevelCheck = bSimple;
					result = aggrFMin;
					break;
				case "max":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrMax aggrFMax = new FunctionAggrMax(_DataCache, args[0], scope);
					aggrFMax.LevelCheck = bSimple;
					result = aggrFMax;
					break;
				case "first":
					scope = ResolveAggrScope(args, 2, out bSimple);
					result = new FunctionAggrFirst(_DataCache, args[0], scope);
					break;
				case "last":
					scope = ResolveAggrScope(args, 2, out bSimple);
					result = new FunctionAggrLast(_DataCache, args[0], scope);
					break;
				case "next":
					scope = ResolveAggrScope(args, 2, out bSimple);
					result = new FunctionAggrNext(_DataCache, args[0], scope);
					break;
				case "previous":
				    scope = ResolveAggrScope(args, 2, out bSimple);
					result = new FunctionAggrPrevious(_DataCache, args[0], scope);
					break;
				case "level":
					scope = ResolveAggrScope(args, 1, out bSimple);
					result = new FunctionAggrLevel(scope);
					break;
                case "aggregate":
                    scope = ResolveAggrScope(args, 2, out bSimple);
                    FunctionAggrArray aggr = new FunctionAggrArray(_DataCache, args[0], scope);
                    aggr.LevelCheck = bSimple;
                    result = aggr;
                    break;
                case "count":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrCount aggrFC = new FunctionAggrCount(_DataCache, args[0], scope);
					aggrFC.LevelCheck = bSimple;
					result = aggrFC;
					break;
				case "countrows":
					scope = ResolveAggrScope(args, 1, out bSimple);
					FunctionAggrCountRows aggrFCR = new FunctionAggrCountRows(scope);
					aggrFCR.LevelCheck = bSimple;
					result = aggrFCR;
					break;
                case "countdistinct":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrCountDistinct aggrFCD = new FunctionAggrCountDistinct(_DataCache, args[0], scope);
					aggrFCD.LevelCheck = bSimple;
					result = aggrFCD;
					break;
				case "rownumber":
					scope = ResolveAggrScope(args, 1, out bSimple);
					IExpr texpr = new ConstantDouble("0");
					result = new FunctionAggrRvCount(_DataCache, texpr, scope);
					break;
				case "runningvalue":
					if (args.Length < 2 || args.Length > 3)
						throw new ParserException("RunningValue takes 2 or 3 arguments." + "  At column " + Convert.ToString(curToken.StartCol));
					string aggrFunc = args[1].EvaluateString(null, null);
					if (aggrFunc == null)
						throw new ParserException("RunningValue 'Function' argument is invalid." + "  At column " + Convert.ToString(curToken.StartCol));
					scope = ResolveAggrScope(args, 3, out bSimple);
					switch(aggrFunc.ToLower())
					{
						case "sum":
							result = new FunctionAggrRvSum(_DataCache, args[0], scope);
							break;
						case "avg":
							result = new FunctionAggrRvAvg(_DataCache, args[0], scope);
							break;
						case "count":
							result = new FunctionAggrRvCount(_DataCache, args[0], scope);
							break;
						case "max":
							result = new FunctionAggrRvMax(_DataCache, args[0], scope);
							break;
						case "min":
							result = new FunctionAggrRvMin(_DataCache, args[0], scope);
							break;
						case "stdev":
							result = new FunctionAggrRvStdev(_DataCache, args[0], scope);
							break;
						case "stdevp":
							result = new FunctionAggrRvStdevp(_DataCache, args[0], scope);
							break;
						case "var":
							result = new FunctionAggrRvVar(_DataCache, args[0], scope);
							break;
						case "varp":
							result = new FunctionAggrRvVarp(_DataCache, args[0], scope);
							break;
						default:
							throw new ParserException("RunningValue function '" + aggrFunc + "' is not supported.  At column " + Convert.ToString(curToken.StartCol));
					}
					break;
				case "stdev":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrStdev aggrSDev = new FunctionAggrStdev(_DataCache, args[0], scope);
					aggrSDev.LevelCheck = bSimple;
					result = aggrSDev;
					break;
				case "stdevp":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrStdevp aggrSDevP = new FunctionAggrStdevp(_DataCache, args[0], scope);
					aggrSDevP.LevelCheck = bSimple;
					result = aggrSDevP;
					break;
				case "var":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrVar aggrVar = new FunctionAggrVar(_DataCache, args[0], scope);
					aggrVar.LevelCheck = bSimple;
					result = aggrVar;
					break;
				case "varp":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrVarp aggrVarP = new FunctionAggrVarp(_DataCache, args[0], scope);
					aggrVarP.LevelCheck = bSimple;
					result = aggrVarP;
					break;
				default:
					result = ResolveMethodCall(fullname, args);		// through exception when fails
					break;
			}

			return true;
		}
Example #5
0
		// FuncIDent: IDENTIFIER ( [Expr] [, Expr]*) | IDENTIFIER
		private bool MatchFuncIDent(out IExpr result)
		{
			IExpr e;
			string fullname;			// will hold the full name
			string method;				// will hold method name or second part of name
			string firstPart;			// will hold the collection name
			string thirdPart;			// will hold third part of name
			bool bOnePart;				// simple name: no ! or . in name

			result = null;

			if (curToken.Type != TokenTypes.IDENTIFIER)
				return false;

			// Disentangle method calls from collection references
			method = fullname = curToken.Value;
			curToken = tokens.Extract();

			// Break the name into parts
			char[] breakChars = new char[] {'!', '.'};

			int posBreak = method.IndexOfAny(breakChars);
			if (posBreak > 0)
			{
				bOnePart = false;
				firstPart = method.Substring(0, posBreak);
				method = method.Substring(posBreak+1);		// rest of expression
			}
			else
			{
				bOnePart = true;
				firstPart = method;
			}

			posBreak = method.IndexOf('.');
            if (posBreak > 0)
            {
                thirdPart = method.Substring(posBreak + 1);	// rest of expression
                method = method.Substring(0, posBreak);
            }
            else
            {
                thirdPart = null;
            }

			if (curToken.Type != TokenTypes.LPAREN) switch (firstPart)
			{
				case "Fields":
					Field f = null;

					if (inAggregateDataSet != null)
					{
						f = inAggregateDataSet.Fields == null ? null : inAggregateDataSet.Fields[method];
						if (f == null)
							throw new ParserException(string.Format(Strings.Parser_ErrorP_FieldNotInDataSet, method, inAggregateDataSet.Name.Nm));
					}
					else
					{
						f = idLookup.LookupField(method);
						if (f == null)
						{
							throw new ParserException(string.Format(Strings.Parser_ErrorP_FieldNotFound, method));
						}
					}

					if (thirdPart == null || thirdPart == "Value")
					{
						result = new FunctionField(f);	
					}
					else if (thirdPart == "IsMissing")
					{
						result = new FunctionFieldIsMissing(f);
					}
					else
						throw new ParserException(string.Format(Strings.Parser_ErrorP_FieldSupportsValueAndIsMissing, method));
					return true;
                case "Parameters":  // see ResolveParametersMethod for resolution of MultiValue parameter function reference
					ReportParameter p = idLookup.LookupParameter(method);
					if (p == null)
						throw new ParserException(string.Format(Strings.Parser_ErrorP_ParameterNotFound, method));
                    int ci = thirdPart == null? -1: thirdPart.IndexOf(".Count");
                    if (ci > 0)
                        thirdPart = thirdPart.Substring(0, ci);
                    FunctionReportParameter r;                    
					if (thirdPart == null || thirdPart == "Value")
						r = new FunctionReportParameter(p);
					else if (thirdPart == "Label")
						r = new FunctionReportParameterLabel(p);
					else
						throw new ParserException(string.Format(Strings.Parser_ErrorP_ParameterSupportsValueAndLabel, method));
                    if (ci > 0)
                        r.SetParameterMethod("Count", null);
                    
                    result = r;
                    return true;
				case "ReportItems":
					Textbox t = idLookup.LookupReportItem(method);
					if (t == null)
						throw new ParserException(string.Format(Strings.Parser_ErrorP_ItemNotFound, method));
					if (thirdPart != null && thirdPart != "Value")
						throw new ParserException(string.Format(Strings.Parser_ErrorP_ItemSupportsValue, method));
					result = new FunctionTextbox(t, idLookup.ExpressionName);	
					return true;
				case "Globals":
					e = idLookup.LookupGlobal(method);
					if (e == null)
						throw new ParserException(string.Format(Strings.Parser_ErrorP_GlobalsNotFound, method));
					result = e;
					return true;
				case "User":
					e = idLookup.LookupUser(method);
					if (e == null)
						throw new ParserException(string.Format(Strings.Parser_ErrorP_UserVarNotFound, method));
					result = e;
					return true;
				case "Recursive":	// Only valid for some aggregate functions
					result = new IdentifierKey(IdentifierKeyEnum.Recursive);
					return true;
				case "Simple":		// Only valid for some aggregate functions
					result = new IdentifierKey(IdentifierKeyEnum.Simple);
					return true;
				default:
					if (!bOnePart)
						throw new ParserException(string.Format(Strings.Parser_ErrorP_UnknownIdentifer, fullname));

					switch (method.ToLower())		// lexer should probably mark these
					{
						case "true":
						case "false":
							result = new ConstantBoolean(method.ToLower());
							break;
						default:
							// usually this is enum that will be used in an aggregate 
							result = new Identifier(method);
							break;
					}
					return true;
			}

			// We've got an function reference
			curToken = tokens.Extract();		// get rid of '('

			// Got a function now obtain the arguments
			int argCount=0;
			
			bool isAggregate = IsAggregate(method, bOnePart);
			if (_NoAggregate && isAggregate)
				throw new ParserException(string.Format(Strings.Parser_ErrorP_AggregateCannotUsedWithinGrouping, method));
			if (_InAggregate && isAggregate)
				throw new ParserException(string.Format(Strings.Parser_ErrorP_AggregateCannotNestedInAnotherAggregate, method));
			_InAggregate = isAggregate;
			if (_InAggregate)
			{
				int level = 0;
				bool nextScope = false;
				Token scopeToken = null;
				foreach(Token tok in tokens)
				{
					if(nextScope)
					{
						scopeToken = tok;
						break;
					}
					
					if(level == 0 && tok.Type == TokenTypes.COMMA)
					{
						nextScope = true;
						continue;
					}
					if (tok.Type == TokenTypes.RPAREN)
						level--;
					if (tok.Type == TokenTypes.LPAREN)
						level++;
				}

				if (scopeToken != null)
				{
					if (scopeToken.Type != TokenTypes.QUOTE)
						throw new ParserException(string.Format(Strings.Parser_ErrorP_ScopeMustConstant, scopeToken.Value));
					inAggregateDataSet = this.idLookup.ScopeDataSet(scopeToken.Value);
					if (inAggregateDataSet == null)
						throw new ParserException(string.Format(Strings.Parser_ErrorP_ScopeNotKnownDataSet, scopeToken.Value));
				}
			}

            List<IExpr> largs = new List<IExpr>();
			while(true)
			{
				if (curToken.Type == TokenTypes.RPAREN)
				{	// We've got our function
					curToken = tokens.Extract();
					break;
				}
				if (argCount == 0)
				{
					// don't need to do anything
				}
				else if (curToken.Type == TokenTypes.COMMA)
				{
					curToken = tokens.Extract();
				}
				else
					throw new ParserException(Strings.Parser_ErrorP_Invalid_function_arguments + GetLocationInfoWithValue(curToken));
				
				MatchExprAndOr(out e);
				if (e == null)
					throw new ParserException(Strings.Parser_ErrorP_ExpectingComma + GetLocationInfoWithValue(curToken));

				largs.Add(e);
				argCount++;
			}
			if (_InAggregate)
			{
				inAggregateDataSet = null;
				_InAggregate = false;
			}

            IExpr[] args = largs.ToArray();

			object scope;
			bool bSimple;
			if (!bOnePart)				
            {
                result = (firstPart == "Parameters")?
                    ResolveParametersMethod(method, thirdPart, args):
                    ResolveMethodCall(fullname, args);	// throw exception when fails
            }
			else switch(method.ToLower())
			{
				case "iif":
					if (args.Length != 3)
						throw new ParserException(Strings.Parser_ErrorP_iff_function_requires_3_arguments + GetLocationInfo(curToken));
//  We allow any type for the first argument; it will get converted to boolean at runtime
//					if (args[0].GetTypeCode() != TypeCode.Boolean)
//						throw new ParserException("First argument to iif function must be boolean." + GetLocationInfo(curToken));
					result = new FunctionIif(args[0], args[1], args[2]);
					break;
				case "choose":
					if (args.Length <= 2)
						throw new ParserException(Strings.Parser_ErrorP_ChooseRequires2Arguments + GetLocationInfo(curToken));
					switch (args[0].GetTypeCode())
					{
						case TypeCode.Double:
						case TypeCode.Single:
						case TypeCode.Int32:
						case TypeCode.Decimal:
						case TypeCode.Int16:
						case TypeCode.Int64:
                        case TypeCode.UInt16:
                        case TypeCode.UInt32:
                        case TypeCode.UInt64:
							break;
						default:
							throw new ParserException(Strings.Parser_ErrorP_ChooseFirstArgumentMustNumeric + GetLocationInfo(curToken));
					}
					result = new FunctionChoose(args);
					break;
				case "switch":
					if (args.Length <= 2)
						throw new ParserException(Strings.Parser_ErrorP_SwitchRequires2Arguments + GetLocationInfo(curToken));
				    if (args.Length % 2 != 0)
						throw new ParserException(Strings.Parser_ErrorP_SwitchMustEvenArguments + GetLocationInfo(curToken));
					for (int i=0; i < args.Length; i = i+2)
					{
						if (args[i].GetTypeCode() != TypeCode.Boolean)
							throw new ParserException(Strings.Parser_ErrorP_SwitchMustBoolean + GetLocationInfo(curToken));
					}
					result = new FunctionSwitch(args);
					break;
				case "format":
					if (args.Length > 2 || args.Length < 1)
						throw new ParserException(Strings.Parser_ErrorP_FormatRequires2Arguments + GetLocationInfo(curToken));
					if (args.Length == 1)
					{
						result = new FunctionFormat(args[0], new ConstantString(""));
					}
					else
					{
						if (args[1].GetTypeCode() != TypeCode.String)
							throw new ParserException(Strings.Parser_ErrorP_SecondMustString + GetLocationInfo(curToken));
						result = new FunctionFormat(args[0], args[1]);
					}
					break;

				case "fields":
					if (args.Length != 1)
						throw new ParserException(Strings.Parser_ErrorP_FieldsRequires1Argument + GetLocationInfo(curToken));
					result = new FunctionFieldCollection(idLookup.Fields, args[0]);
                    if (curToken.Type == TokenTypes.DOT)
                    {	// user placed "."                  TODO: generalize this code
                        curToken = tokens.Extract();                // skip past dot operator
                        if (curToken.Type == TokenTypes.IDENTIFIER && curToken.Value.ToLowerInvariant() == "value")
                            curToken = tokens.Extract();            // only support "value" property for now
                        else
							throw new ParserException(string.Format(Strings.Parser_ErrorP_UnknownProperty, curToken.Value, "Fields") + GetLocationInfo(curToken));
                    }
                    break;
				case "parameters":
					if (args.Length != 1)
						throw new ParserException(Strings.Parser_ErrorP_ParametersRequires1Argument + GetLocationInfo(curToken));
					result = new FunctionParameterCollection(idLookup.Parameters, args[0]);
                    if (curToken.Type == TokenTypes.DOT)
                    {	// user placed "." 
                        curToken = tokens.Extract();                // skip past dot operator
                        if (curToken.Type == TokenTypes.IDENTIFIER && curToken.Value.ToLowerInvariant() == "value")
                            curToken = tokens.Extract();            // only support "value" property for now
                        else
                            throw new ParserException((string.Format(Strings.Parser_ErrorP_UnknownProperty, curToken.Value, "Parameters") + GetLocationInfo(curToken)));
                    }
                    break;
				case "reportitems":
					if (args.Length != 1)
						throw new ParserException(Strings.Parser_ErrorP_ReportItemsRequires1Argument + GetLocationInfo(curToken));
					result = new FunctionReportItemCollection(idLookup.ReportItems, args[0]);
                    if (curToken.Type == TokenTypes.DOT)
                    {	// user placed "." 
                        curToken = tokens.Extract();                // skip past dot operator
                        if (curToken.Type == TokenTypes.IDENTIFIER && curToken.Value.ToLowerInvariant() == "value")
                            curToken = tokens.Extract();            // only support "value" property for now
                        else
                            throw new ParserException((string.Format(Strings.Parser_ErrorP_UnknownProperty, curToken.Value, "ReportItems") + GetLocationInfo(curToken)));
                    }
                    break;
				case "globals":
					if (args.Length != 1)
						throw new ParserException(Strings.Parser_ErrorP_GlobalsRequires1Argument + GetLocationInfo(curToken));
					result = new FunctionGlobalCollection(idLookup.Globals, args[0]);
					break;
				case "user":
					if (args.Length != 1)
						throw new ParserException(Strings.Parser_ErrorP_UserRequires1Argument + GetLocationInfo(curToken));
					result = new FunctionUserCollection(idLookup.User, args[0]);
					break;
				case "sum":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrSum aggrFS = new FunctionAggrSum(_DataCache, args[0], scope);
					aggrFS.LevelCheck = bSimple;
					result = aggrFS;
					break;
				case "avg":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrAvg aggrFA = new FunctionAggrAvg(_DataCache, args[0], scope);
					aggrFA.LevelCheck = bSimple;
					result = aggrFA;
					break;
				case "min":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrMin aggrFMin = new FunctionAggrMin(_DataCache, args[0], scope);
					aggrFMin.LevelCheck = bSimple;
					result = aggrFMin;
					break;
				case "max":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrMax aggrFMax = new FunctionAggrMax(_DataCache, args[0], scope);
					aggrFMax.LevelCheck = bSimple;
					result = aggrFMax;
					break;
				case "first":
					scope = ResolveAggrScope(args, 2, out bSimple);
					result = new FunctionAggrFirst(_DataCache, args[0], scope);
					break;
				case "last":
					scope = ResolveAggrScope(args, 2, out bSimple);
					result = new FunctionAggrLast(_DataCache, args[0], scope);
					break;
				case "next":
					scope = ResolveAggrScope(args, 2, out bSimple);
					result = new FunctionAggrNext(_DataCache, args[0], scope);
					break;
				case "previous":
				    scope = ResolveAggrScope(args, 2, out bSimple);
					result = new FunctionAggrPrevious(_DataCache, args[0], scope);
					break;
				case "level":
					scope = ResolveAggrScope(args, 1, out bSimple);
					result = new FunctionAggrLevel(scope);
					break;
                case "aggregate":
                    scope = ResolveAggrScope(args, 2, out bSimple);
                    FunctionAggrArray aggr = new FunctionAggrArray(_DataCache, args[0], scope);
                    aggr.LevelCheck = bSimple;
                    result = aggr;
                    break;
                case "count":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrCount aggrFC = new FunctionAggrCount(_DataCache, args[0], scope);
					aggrFC.LevelCheck = bSimple;
					result = aggrFC;
					break;
				case "countrows":
					scope = ResolveAggrScope(args, 1, out bSimple);
					FunctionAggrCountRows aggrFCR = new FunctionAggrCountRows(scope);
					aggrFCR.LevelCheck = bSimple;
					result = aggrFCR;
					break;
                case "countdistinct":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrCountDistinct aggrFCD = new FunctionAggrCountDistinct(_DataCache, args[0], scope);
					aggrFCD.LevelCheck = bSimple;
					result = aggrFCD;
					break;
				case "rownumber":
					scope = ResolveAggrScope(args, 1, out bSimple);
					IExpr texpr = new ConstantDouble("0");
					result = new FunctionAggrRvCount(_DataCache, texpr, scope);
					break;
				case "runningvalue":
					if (args.Length < 2 || args.Length > 3)
						throw new ParserException(Strings.Parser_ErrorP_RunningValue_takes_2_or_3_arguments + GetLocationInfo(curToken));
					string aggrFunc = args[1].EvaluateString(null, null);
					if (aggrFunc == null)
						throw new ParserException(Strings.Parser_ErrorP_RunningValueArgumentInvalid + GetLocationInfo(curToken));
					scope = ResolveAggrScope(args, 3, out bSimple);
					switch(aggrFunc.ToLower())
					{
						case "sum":
							result = new FunctionAggrRvSum(_DataCache, args[0], scope);
							break;
						case "avg":
							result = new FunctionAggrRvAvg(_DataCache, args[0], scope);
							break;
						case "count":
							result = new FunctionAggrRvCount(_DataCache, args[0], scope);
							break;
						case "max":
							result = new FunctionAggrRvMax(_DataCache, args[0], scope);
							break;
						case "min":
							result = new FunctionAggrRvMin(_DataCache, args[0], scope);
							break;
						case "stdev":
							result = new FunctionAggrRvStdev(_DataCache, args[0], scope);
							break;
						case "stdevp":
							result = new FunctionAggrRvStdevp(_DataCache, args[0], scope);
							break;
						case "var":
							result = new FunctionAggrRvVar(_DataCache, args[0], scope);
							break;
						case "varp":
							result = new FunctionAggrRvVarp(_DataCache, args[0], scope);
							break;
						default:
							throw new ParserException(string.Format(Strings.Parser_ErrorP_RunningValueNotSupported, aggrFunc) + GetLocationInfo(curToken));
					}
					break;
				case "stdev":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrStdev aggrSDev = new FunctionAggrStdev(_DataCache, args[0], scope);
					aggrSDev.LevelCheck = bSimple;
					result = aggrSDev;
					break;
				case "stdevp":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrStdevp aggrSDevP = new FunctionAggrStdevp(_DataCache, args[0], scope);
					aggrSDevP.LevelCheck = bSimple;
					result = aggrSDevP;
					break;
				case "var":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrVar aggrVar = new FunctionAggrVar(_DataCache, args[0], scope);
					aggrVar.LevelCheck = bSimple;
					result = aggrVar;
					break;
				case "varp":
					scope = ResolveAggrScope(args, 2, out bSimple);
					FunctionAggrVarp aggrVarP = new FunctionAggrVarp(_DataCache, args[0], scope);
					aggrVarP.LevelCheck = bSimple;
					result = aggrVarP;
					break;
				default:
					result = ResolveMethodCall(fullname, args);		// through exception when fails
					break;
			}

			return true;
		}
Example #6
0
        // FuncIDent: IDENTIFIER ( [Expr] [, Expr]*) | IDENTIFIER
        private bool MatchFuncIDent(out IExpr result)
        {
            IExpr  e;
            string fullname;                                    // will hold the full name
            string method;                                      // will hold method name or second part of name
            string firstPart;                                   // will hold the collection name
            string thirdPart;                                   // will hold third part of name
            bool   bOnePart;                                    // simple name: no ! or . in name

            result = null;

            if (curToken.Type != TokenTypes.IDENTIFIER)
            {
                return(false);
            }

            // Disentangle method calls from collection references
            method   = fullname = curToken.Value;
            curToken = tokens.Extract();

            // Break the name into parts
            char[] breakChars = new char[] { '!', '.' };

            int posBreak = method.IndexOfAny(breakChars);

            if (posBreak > 0)
            {
                bOnePart  = false;
                firstPart = method.Substring(0, posBreak);
                method    = method.Substring(posBreak + 1);                     // rest of expression
            }
            else
            {
                bOnePart  = true;
                firstPart = method;
            }

            posBreak = method.IndexOf('.');
            if (posBreak > 0)
            {
                thirdPart = method.Substring(posBreak + 1);                     // rest of expression
                method    = method.Substring(0, posBreak);
            }
            else
            {
                thirdPart = null;
            }

            if (curToken.Type != TokenTypes.LPAREN)
            {
                switch (firstPart)
                {
                case "Fields":
                    Field f = idLookup.LookupField(method);
                    if (f == null && !this._InAggregate)
                    {
                        throw new ParserException("Field '" + method + "'  not found.");
                    }
                    if (thirdPart == null || thirdPart == "Value")
                    {
                        if (f == null)
                        {
                            FunctionField ff;
                            result = ff = new FunctionField(method);
                            this._FieldResolve.Add(ff);
                        }
                        else
                        {
                            result = new FunctionField(f);
                        }
                    }
                    else if (thirdPart == "IsMissing")
                    {
                        if (f == null)
                        {
                            FunctionField ff;
                            result = ff = new FunctionFieldIsMissing(method);
                            this._FieldResolve.Add(ff);
                        }
                        else
                        {
                            result = new FunctionFieldIsMissing(f);
                        }
                    }
                    else
                    {
                        throw new ParserException("Field '" + method + "'  only supports 'Value' and 'IsMissing' properties.");
                    }
                    return(true);

                case "Parameters":  // see ResolveParametersMethod for resolution of MultiValue parameter function reference
                    ReportParameter p = idLookup.LookupParameter(method);
                    if (p == null)
                    {
                        throw new ParserException("Report parameter '" + method + "'  not found.");
                    }
                    int ci = thirdPart == null? -1: thirdPart.IndexOf(".Count");
                    if (ci > 0)
                    {
                        thirdPart = thirdPart.Substring(0, ci);
                    }
                    FunctionReportParameter r;
                    if (thirdPart == null || thirdPart == "Value")
                    {
                        r = new FunctionReportParameter(p);
                    }
                    else if (thirdPart == "Label")
                    {
                        r = new FunctionReportParameterLabel(p);
                    }
                    else
                    {
                        throw new ParserException("Parameter '" + method + "'  only supports 'Value' and 'Label' properties.");
                    }
                    if (ci > 0)
                    {
                        r.SetParameterMethod("Count", null);
                    }

                    result = r;
                    return(true);

                case "ReportItems":
                    Textbox t = idLookup.LookupReportItem(method);
                    if (t == null)
                    {
                        throw new ParserException("ReportItem '" + method + "'  not found.");
                    }
                    if (thirdPart != null && thirdPart != "Value")
                    {
                        throw new ParserException("ReportItem '" + method + "'  only supports 'Value' property.");
                    }
                    result = new FunctionTextbox(t, idLookup.ExpressionName);
                    return(true);

                case "Globals":
                    e = idLookup.LookupGlobal(method);
                    if (e == null)
                    {
                        throw new ParserException("Globals '" + method + "'  not found.");
                    }
                    result = e;
                    return(true);

                case "User":
                    e = idLookup.LookupUser(method);
                    if (e == null)
                    {
                        throw new ParserException("User variable '" + method + "'  not found.");
                    }
                    result = e;
                    return(true);

                case "Recursive":                       // Only valid for some aggregate functions
                    result = new IdentifierKey(IdentifierKeyEnum.Recursive);
                    return(true);

                case "Simple":                          // Only valid for some aggregate functions
                    result = new IdentifierKey(IdentifierKeyEnum.Simple);
                    return(true);

                default:
                    if (!bOnePart)
                    {
                        throw new ParserException(string.Format("'{0}' is an unknown identifer.", fullname));
                    }

                    switch (method.ToLower())                                   // lexer should probably mark these
                    {
                    case "true":
                    case "false":
                        result = new ConstantBoolean(method.ToLower());
                        break;

                    default:
                        // usually this is enum that will be used in an aggregate
                        result = new Identifier(method);
                        break;
                    }
                    return(true);
                }
            }

            // We've got an function reference
            curToken = tokens.Extract();                        // get rid of '('

            // Got a function now obtain the arguments
            int argCount = 0;

            bool isAggregate = IsAggregate(method, bOnePart);

            if (_NoAggregate && isAggregate)
            {
                throw new ParserException("Aggregate function '" + method + "' cannot be used within a Grouping expression.");
            }
            if (_InAggregate && isAggregate)
            {
                throw new ParserException("Aggregate function '" + method + "' cannot be nested in another aggregate function.");
            }
            _InAggregate = isAggregate;
            if (_InAggregate)
            {
                _FieldResolve = new List <FunctionField>();
            }

            List <IExpr> largs = new List <IExpr>();

            while (true)
            {
                if (curToken.Type == TokenTypes.RPAREN)
                {                       // We've got our function
                    curToken = tokens.Extract();
                    break;
                }
                if (argCount == 0)
                {
                    // don't need to do anything
                }
                else if (curToken.Type == TokenTypes.COMMA)
                {
                    curToken = tokens.Extract();
                }
                else
                {
                    throw new ParserException("Invalid function arguments.  Found '" + curToken.Value + "'  At column " + Convert.ToString(curToken.StartCol));
                }

                MatchExprAndOr(out e);
                if (e == null)
                {
                    throw new ParserException("Expecting ',' or ')'.  Found '" + curToken.Value + "'  At column " + Convert.ToString(curToken.StartCol));
                }

                largs.Add(e);
                argCount++;
            }
            if (_InAggregate)
            {
                ResolveFields(method, this._FieldResolve, largs);
                _FieldResolve = null;
                _InAggregate  = false;
            }

            IExpr[] args = largs.ToArray();

            object scope;
            bool   bSimple;

            if (!bOnePart)
            {
                result = (firstPart == "Parameters")?
                         ResolveParametersMethod(method, thirdPart, args):
                         ResolveMethodCall(fullname, args); // throw exception when fails
            }
            else
            {
                switch (method.ToLower())
                {
                case "iif":
                    if (args.Length != 3)
                    {
                        throw new ParserException("iff function requires 3 arguments." + "  At column " + Convert.ToString(curToken.StartCol));
                    }
//  We allow any type for the first argument; it will get converted to boolean at runtime
//					if (args[0].GetTypeCode() != TypeCode.Boolean)
//						throw new ParserException("First argument to iif function must be boolean." + "  At column " + Convert.ToString(curToken.StartCol));
                    result = new FunctionIif(args[0], args[1], args[2]);
                    break;

                case "choose":
                    if (args.Length <= 2)
                    {
                        throw new ParserException("Choose function requires at least 2 arguments." + "  At column " + Convert.ToString(curToken.StartCol));
                    }
                    switch (args[0].GetTypeCode())
                    {
                    case TypeCode.Double:
                    case TypeCode.Single:
                    case TypeCode.Int32:
                    case TypeCode.Decimal:
                    case TypeCode.Int16:
                    case TypeCode.Int64:
                        break;

                    default:
                        throw new ParserException("First argument to Choose function must be numeric." + "  At column " + Convert.ToString(curToken.StartCol));
                    }
                    result = new FunctionChoose(args);
                    break;

                case "switch":
                    if (args.Length <= 2)
                    {
                        throw new ParserException("Switch function requires at least 2 arguments." + "  At column " + Convert.ToString(curToken.StartCol));
                    }
                    if (args.Length % 2 != 0)
                    {
                        throw new ParserException("Switch function must have an even number of arguments." + "  At column " + Convert.ToString(curToken.StartCol));
                    }
                    for (int i = 0; i < args.Length; i = i + 2)
                    {
                        if (args[i].GetTypeCode() != TypeCode.Boolean)
                        {
                            throw new ParserException("Switch function must have a boolean expression every other argument." + "  At column " + Convert.ToString(curToken.StartCol));
                        }
                    }
                    result = new FunctionSwitch(args);
                    break;

                case "format":
                    if (args.Length > 2 || args.Length < 1)
                    {
                        throw new ParserException("Format function requires 2 arguments." + "  At column " + Convert.ToString(curToken.StartCol));
                    }
                    if (args.Length == 1)
                    {
                        result = new FunctionFormat(args[0], new ConstantString(""));
                    }
                    else
                    {
                        if (args[1].GetTypeCode() != TypeCode.String)
                        {
                            throw new ParserException("Second argument to Format function must be a string." + "  At column " + Convert.ToString(curToken.StartCol));
                        }
                        result = new FunctionFormat(args[0], args[1]);
                    }
                    break;

                case "fields":
                    if (args.Length != 1)
                    {
                        throw new ParserException("Fields collection requires exactly 1 argument." + "  At column " + Convert.ToString(curToken.StartCol));
                    }
                    result = new FunctionFieldCollection(idLookup.Fields, args[0]);
                    break;

                case "parameters":
                    if (args.Length != 1)
                    {
                        throw new ParserException("Parameters collection requires exactly 1 argument." + "  At column " + Convert.ToString(curToken.StartCol));
                    }
                    result = new FunctionParameterCollection(idLookup.Parameters, args[0]);
                    break;

                case "reportitems":
                    if (args.Length != 1)
                    {
                        throw new ParserException("ReportItems collection requires exactly 1 argument." + "  At column " + Convert.ToString(curToken.StartCol));
                    }
                    result = new FunctionReportItemCollection(idLookup.ReportItems, args[0]);
                    break;

                case "globals":
                    if (args.Length != 1)
                    {
                        throw new ParserException("Globals collection requires exactly 1 argument." + "  At column " + Convert.ToString(curToken.StartCol));
                    }
                    result = new FunctionGlobalCollection(idLookup.Globals, args[0]);
                    break;

                case "user":
                    if (args.Length != 1)
                    {
                        throw new ParserException("User collection requires exactly 1 argument." + "  At column " + Convert.ToString(curToken.StartCol));
                    }
                    result = new FunctionUserCollection(idLookup.User, args[0]);
                    break;

                case "sum":
                    scope = ResolveAggrScope(args, 2, out bSimple);
                    FunctionAggrSum aggrFS = new FunctionAggrSum(_DataCache, args[0], scope);
                    aggrFS.LevelCheck = bSimple;
                    result            = aggrFS;
                    break;

                case "avg":
                    scope = ResolveAggrScope(args, 2, out bSimple);
                    FunctionAggrAvg aggrFA = new FunctionAggrAvg(_DataCache, args[0], scope);
                    aggrFA.LevelCheck = bSimple;
                    result            = aggrFA;
                    break;

                case "min":
                    scope = ResolveAggrScope(args, 2, out bSimple);
                    FunctionAggrMin aggrFMin = new FunctionAggrMin(_DataCache, args[0], scope);
                    aggrFMin.LevelCheck = bSimple;
                    result = aggrFMin;
                    break;

                case "max":
                    scope = ResolveAggrScope(args, 2, out bSimple);
                    FunctionAggrMax aggrFMax = new FunctionAggrMax(_DataCache, args[0], scope);
                    aggrFMax.LevelCheck = bSimple;
                    result = aggrFMax;
                    break;

                case "first":
                    scope  = ResolveAggrScope(args, 2, out bSimple);
                    result = new FunctionAggrFirst(_DataCache, args[0], scope);
                    break;

                case "last":
                    scope  = ResolveAggrScope(args, 2, out bSimple);
                    result = new FunctionAggrLast(_DataCache, args[0], scope);
                    break;

                case "next":
                    scope  = ResolveAggrScope(args, 2, out bSimple);
                    result = new FunctionAggrNext(_DataCache, args[0], scope);
                    break;

                case "previous":
                    scope  = ResolveAggrScope(args, 2, out bSimple);
                    result = new FunctionAggrPrevious(_DataCache, args[0], scope);
                    break;

                case "level":
                    scope  = ResolveAggrScope(args, 1, out bSimple);
                    result = new FunctionAggrLevel(scope);
                    break;

                case "count":
                    scope = ResolveAggrScope(args, 2, out bSimple);
                    FunctionAggrCount aggrFC = new FunctionAggrCount(_DataCache, args[0], scope);
                    aggrFC.LevelCheck = bSimple;
                    result            = aggrFC;
                    break;

                case "countrows":
                    scope = ResolveAggrScope(args, 1, out bSimple);
                    FunctionAggrCountRows aggrFCR = new FunctionAggrCountRows(scope);
                    aggrFCR.LevelCheck = bSimple;
                    result             = aggrFCR;
                    break;

                case "countdistinct":
                    scope = ResolveAggrScope(args, 2, out bSimple);
                    FunctionAggrCountDistinct aggrFCD = new FunctionAggrCountDistinct(_DataCache, args[0], scope);
                    aggrFCD.LevelCheck = bSimple;
                    result             = aggrFCD;
                    break;

                case "rownumber":
                    scope = ResolveAggrScope(args, 1, out bSimple);
                    IExpr texpr = new ConstantDouble("0");
                    result = new FunctionAggrRvCount(_DataCache, texpr, scope);
                    break;

                case "runningvalue":
                    if (args.Length < 2 || args.Length > 3)
                    {
                        throw new ParserException("RunningValue takes 2 or 3 arguments." + "  At column " + Convert.ToString(curToken.StartCol));
                    }
                    string aggrFunc = args[1].EvaluateString(null, null);
                    if (aggrFunc == null)
                    {
                        throw new ParserException("RunningValue 'Function' argument is invalid." + "  At column " + Convert.ToString(curToken.StartCol));
                    }
                    scope = ResolveAggrScope(args, 3, out bSimple);
                    switch (aggrFunc.ToLower())
                    {
                    case "sum":
                        result = new FunctionAggrRvSum(_DataCache, args[0], scope);
                        break;

                    case "avg":
                        result = new FunctionAggrRvAvg(_DataCache, args[0], scope);
                        break;

                    case "count":
                        result = new FunctionAggrRvCount(_DataCache, args[0], scope);
                        break;

                    case "max":
                        result = new FunctionAggrRvMax(_DataCache, args[0], scope);
                        break;

                    case "min":
                        result = new FunctionAggrRvMin(_DataCache, args[0], scope);
                        break;

                    case "stdev":
                        result = new FunctionAggrRvStdev(_DataCache, args[0], scope);
                        break;

                    case "stdevp":
                        result = new FunctionAggrRvStdevp(_DataCache, args[0], scope);
                        break;

                    case "var":
                        result = new FunctionAggrRvVar(_DataCache, args[0], scope);
                        break;

                    case "varp":
                        result = new FunctionAggrRvVarp(_DataCache, args[0], scope);
                        break;

                    default:
                        throw new ParserException("RunningValue function '" + aggrFunc + "' is not supported.  At column " + Convert.ToString(curToken.StartCol));
                    }
                    break;

                case "stdev":
                    scope = ResolveAggrScope(args, 2, out bSimple);
                    FunctionAggrStdev aggrSDev = new FunctionAggrStdev(_DataCache, args[0], scope);
                    aggrSDev.LevelCheck = bSimple;
                    result = aggrSDev;
                    break;

                case "stdevp":
                    scope = ResolveAggrScope(args, 2, out bSimple);
                    FunctionAggrStdevp aggrSDevP = new FunctionAggrStdevp(_DataCache, args[0], scope);
                    aggrSDevP.LevelCheck = bSimple;
                    result = aggrSDevP;
                    break;

                case "var":
                    scope = ResolveAggrScope(args, 2, out bSimple);
                    FunctionAggrVar aggrVar = new FunctionAggrVar(_DataCache, args[0], scope);
                    aggrVar.LevelCheck = bSimple;
                    result             = aggrVar;
                    break;

                case "varp":
                    scope = ResolveAggrScope(args, 2, out bSimple);
                    FunctionAggrVarp aggrVarP = new FunctionAggrVarp(_DataCache, args[0], scope);
                    aggrVarP.LevelCheck = bSimple;
                    result = aggrVarP;
                    break;

                default:
                    result = ResolveMethodCall(fullname, args);                                 // through exception when fails
                    break;
                }
            }

            return(true);
        }