/// <summary>
        /// Visit LINQtoSPARQL expression
        /// </summary>
        /// <param name="m">method call expression</param>
        /// <param name="level">expression group level</param>
        private void VisitSPARQL(MethodCallExpression m, int level = 0)
        {
            if (m.Arguments == null || m.Arguments.Count == 0)
            {
                return;
            }



            IWhereItem ret  = null;
            string     name = m.Method.Name;

            int nextItemLevel  = level;
            var nextMethodCall = m.Arguments[0] as MethodCallExpression;

            if (name == "End")
            {
                nextItemLevel++;
            }
            else if (level > 0 && GroupingMethods.Any(n => n == name))
            {
                nextItemLevel--;
            }

            if (!ClauseMethods.Any(n => n == name))
            {
                NextMethodCall = nextMethodCall;
                if (NextMethodCall != null)
                {
                    VisitSPARQL(NextMethodCall,
                                (name == "Or" && nextMethodCall.Method.Name != "End")
                         ? nextItemLevel + 1 : nextItemLevel);
                }
            }



            var list = Groups.Last.Value;

            switch (name)
            {
            case "End":         Groups.RemoveLast(); break;

            case "Group":       ret = VisitGroup(m); break;

            case "Match":       ret = VisitMatch(m); break;

            case "And_1":       ret = VisitAnd1(m, list); break;

            case "And_2":       ret = VisitAnd2(m, list); break;

            case "Optional":    ret = VisitOptional(m); break;

            case "FilterBy":    ret = VisitFilterBy(m); break;

            case "Either":      ret = VisitEither(m); break;

            case "Minus":       ret = VisitMinus(m); break;

            case "Exists":      ret = VisitExists(m); break;

            case "NotExists":   ret = VisitNotExists(m); break;

            case "Or":
                if (nextMethodCall.Method.Name != "End")
                {
                    Groups.RemoveLast();
                }
                list = Groups.Last.Value;
                Groups.RemoveLast();
                ret = VisitOr(m, list);
                break;

            case "Select":      SelectClause = VisitSelect(m); break;

            case "OrderBy":     OrderByClause = VisitOrderBy(m); break;

            case "GroupBy":     GroupByClause = VisitOrderBy(m); break;

            case "Having":      HavingClause = VisitOrderBy(m); break;

            case "Limit":       LimitClause = VisitLimit(m); break;

            case "Offset":      OffsetClause = VisitOffset(m); break;

            case "Prefix":      VisitPrefix(m); break;

            //case "Bind":
            case "As":          ret = VisitBindAs(nextMethodCall, m); break;

            case "Distinct":    VisitDistinct(m); break;

            case "From":        FromClause = VisitFrom(m); break;

            case "FromNamed":   VisitFromNamed(m); break;

            case "Using":       UsingClause = VisitUsing(m); break;

            case "UsingNamed":  VisitUsingNamed(m); break;

            case "With":        WithClause = VisitWith(m); break;

            case "Graph":       ret = VisitGraph(m); break;
            }

            if (ret == null)
            {
                return;
            }

            list.Add(ret);

            if (level <= nextItemLevel)
            {
                return;
            }

            Group group;

            while ((group = ret as Group) != null)
            {
                Groups.AddLast(group);
                ret = group.Count > 0 ? group[0] : null;
            }
        }