/// <summary>
        /// Binds a <see cref="SyntacticTree"/>.
        /// </summary>
        /// <param name="syntax">The query descriptor token to bind.</param>
        /// <returns>The bound query descriptor.</returns>
        public ODataUri BindTree(SyntacticTree syntax)
        {
            ExceptionUtils.CheckArgumentNotNull(syntax, "syntax");
            ExceptionUtils.CheckArgumentNotNull(syntax.Path, "syntax.Path");

            // Make a copy of query options since we may consume some of them as we bind the query
            bindingState.QueryOptions = new List <CustomQueryOptionToken>(syntax.QueryOptions);

            ParameterAliasValueAccessor parameterAliasValueAccessor = new ParameterAliasValueAccessor(syntax.ParameterAliases);
            ODataPath          path         = null;
            FilterClause       filter       = null;
            OrderByClause      orderBy      = null;
            long?              skip         = null;
            long?              top          = null;
            SelectExpandClause selectExpand = null;
            bool?              count        = null;

            // set parameterAliasValueAccessor for uri path, $filter, $orderby
            this.bindingState.Configuration.ParameterAliasValueAccessor = parameterAliasValueAccessor;

            // First bind the path
            path = ODataPathFactory.BindPath(syntax.Path, this.bindingState.Configuration);

            // If the path leads to a collection, then create a range variable that represents iterating over the collection
            var rangeVariable = NodeFactory.CreateImplicitRangeVariable(path);

            if (rangeVariable != null)
            {
                this.bindingState.RangeVariables.Push(rangeVariable);
            }

            if (syntax.Filter != null || syntax.OrderByTokens.Any())
            {
                this.bindingState.ImplicitRangeVariable = this.bindingState.RangeVariables.Peek();
            }

            // Apply filter first, then order-by, skip, top, select and expand
            filter = BindFilter(syntax, rangeVariable);

            orderBy = BindOrderBy(syntax, rangeVariable, path);

            skip = BindSkip(syntax, rangeVariable, path);

            top = BindTop(syntax, rangeVariable, path);

            selectExpand = BindSelectExpand(syntax, path, this.bindingState.Configuration);

            count = BindQueryCount(syntax, path);

            // Add the remaining query options to the query descriptor.
            List <QueryNode> boundQueryOptions = MetadataBinder.ProcessQueryOptions(this.bindingState, this.bindMethod);

            Debug.Assert(bindingState.QueryOptions == null, "this.queryOptions == null");
            bindingState.RangeVariables.Pop();
            bindingState.ImplicitRangeVariable = null;

            return(new ODataUri(parameterAliasValueAccessor, path, boundQueryOptions, selectExpand, filter, orderBy, skip, top, count));
        }