protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            var call_object = (node.Object) as MemberExpression;

            if (call_object == null)
            {
                goto method_call_cleanup;
            }
            var    member_string = _get_member_string(call_object);
            string index_access_method;

            if (m_index_access_table.TryGetValue(member_string, out index_access_method) &&
                index_access_method == node.Method.Name)
            {
                if (node.Arguments.Count != 1)
                {
                    goto method_call_cleanup;
                }
                var    arg          = node.Arguments[0];
                string query_string = null;
                if (arg.NodeType == ExpressionType.Constant)
                {
                    query_string = (string)(arg as ConstantExpression).Value;
                }
                else
                {
                    query_string = _evaluate_expression <string>(arg);
                    /* We have to update the expression to avoid re-entering the expression */
                    node = node.Update(
                        node.Object,
                        new List <Expression> {
                        Expression.Constant(query_string, s_string_type)
                    });
                }
                if (query_string == null)
                {
                    goto method_call_cleanup;
                }

                /*
                 * @note    Gotcha. It's an index query method call!
                 */
                m_current_node             = new IndexQueryTreeNode(IndexQueryTreeNode.NodeType.QUERY);
                m_current_node.queryTarget = member_string;
                m_current_node.queryString = query_string;
            }

            /*
             * @note    We don't have to go deeper into the rabbit hole,
             *          as we cannot evaluate the method call.
             */
method_call_cleanup:
            return(node);
        }
        void UnaryBuildTree(IndexQueryTreeNode.NodeType type, UnaryExpression node)
        {
            IndexQueryTreeNode query_node = new IndexQueryTreeNode {
                type = type, children = new List <IndexQueryTreeNode>()
            };

            VisitChildren(query_node.children, node.Operand);
            if (query_node.children.Count != 0)
            {
                m_current_node = query_node;
            }
        }
        IndexQueryTreeNode VisitChild(Expression child)
        {
            IndexQueryTreeNode original_node = m_current_node;

            Visit(child);
            if (m_current_node != original_node)
            {
                var ret = m_current_node;
                m_current_node = original_node;
                return(ret);
            }
            else
            {
                return(null);
            }
        }
        internal HashSet <long> Execute(IndexQueryTreeNode node)
        {
            if (node == null)
            {
                return(null);
            }
            HashSet <long> ret;

            switch (node.type)
            {
            case IndexQueryTreeNode.NodeType.AND:
                ret = Execute(node.children[0]);
                foreach (var child in node.children.Skip(1))
                {
                    ret.IntersectWith(Execute(child));
                }
                break;

            case IndexQueryTreeNode.NodeType.OR:
                ret = Execute(node.children[0]);
                foreach (var child in node.children.Skip(1))
                {
                    foreach (var id in Execute(child))
                    {
                        ret.Add(id);
                    }
                }
                break;

            case IndexQueryTreeNode.NodeType.QUERY:
                if (node.queryString != null)
                {
                    ret = new HashSet <long>(m_substring_query[node.queryTarget](node.queryString));
                }
                else
                {
                    ret = new HashSet <long>(m_substring_query_wildcard[node.queryTarget](node.wildcard_query));
                }
                break;

            default:
                throw new NotImplementedException("Internal error T5012.");
            }
            return(ret);
        }
        private void _equality_build_tree(BinaryExpression node, bool is_equal)
        {
            if (node.Left.Type != s_bool_type || node.Right.Type != s_bool_type)
            {
                return;
            }
            bool?constant = null;
            List <Expression>       exp           = new List <Expression>();
            Func <bool, bool, bool> _equal_helper = (lhs, rhs) => is_equal? lhs == rhs : lhs != rhs;
            bool?lconstant = _constant_boolean_exp_eval(node.Left);
            bool?rconstant = _constant_boolean_exp_eval(node.Right);

            if (lconstant.HasValue)
            {
                constant = lconstant;
            }
            else
            {
                exp.Add(node.Left);
            }
            if (rconstant.HasValue)
            {
                constant = rconstant;
            }
            else
            {
                exp.Add(node.Right);
            }
            if (lconstant.HasValue && rconstant.HasValue)
            {
                m_current_node = new IndexQueryTreeNode(
                    _equal_helper(lconstant.Value, rconstant.Value)?
                    IndexQueryTreeNode.NodeType.UNIVERSE:IndexQueryTreeNode.NodeType.EMPTY);
                return;
            }
            IndexQueryTreeNode query_node;
            IndexQueryTreeNode child_node;

            if (constant.HasValue)
            {
                child_node = VisitChild(exp[0]);
                if (child_node == null)
                {
                    m_current_node = new IndexQueryTreeNode(
                        _equal_helper(constant.Value, true)?
                        IndexQueryTreeNode.NodeType.UNIVERSE: IndexQueryTreeNode.NodeType.EMPTY);
                }
                else
                {
                    if (_equal_helper(constant.Value, true))
                    { /* keep m_current_node as is */
                    }
                    else
                    {
                        query_node = new IndexQueryTreeNode(IndexQueryTreeNode.NodeType.NOT)
                        {
                            children = new List <IndexQueryTreeNode> {
                                child_node
                            }
                        };
                        m_current_node = query_node;
                    }
                }
            }
            else
            {
                query_node = new IndexQueryTreeNode(
                    _equal_helper(true, true)? IndexQueryTreeNode.NodeType.XNOR:IndexQueryTreeNode.NodeType.XOR)
                {
                    children = new List <IndexQueryTreeNode>()
                };
                VisitChildren(query_node.children, node.Left, node.Right);
                switch (query_node.children.Count)
                {
                case 0:
                case 1:
                    /* no index query actions, as we cannot analyse the semantics */
                    break;

                case 2:
                    /* we have query actions on both sides */
                    m_current_node = query_node;
                    break;

                default:
                    throw new Exception("Internal error T5010");
                }
            }
        }
        internal IndexQueryTreeNode Optimize()
        {
            if (children != null)
            {
                List <IndexQueryTreeNode> new_child_list = new List <IndexQueryTreeNode>();
                foreach (var child in children)
                {
                    var new_child = child.Optimize();
                    if (new_child != null)
                    {
                        new_child_list.Add(new_child);
                    }
                }
                this.children = new_child_list;
            }
            if (type == NodeType.QUERY || type == NodeType.UNIVERSE || type == NodeType.EMPTY)
            {
                return(this);
            }
            if (children.Count == 0)
            {
                return(null);
            }
            IndexQueryTreeNode universe = null;
            IndexQueryTreeNode empty    = null;
            IndexQueryTreeNode normal   = null;

            foreach (var child in children)
            {
                if (child.type == NodeType.EMPTY)
                {
                    empty = child;
                }
                else if (child.type == NodeType.UNIVERSE)
                {
                    universe = child;
                }
                else
                {
                    normal = child;
                }
            }
            switch (type)
            {
            case NodeType.NOT:
                /* Drop NOT queries */
                if (children[0].type == NodeType.NOT)
                {
                    return(children[0].children[0]);
                }
                else
                {
                    return(null);
                }

            case NodeType.XNOR:
            case NodeType.XOR:
                /* Not implemented. */
                return(null);

            case NodeType.AND:
            {
                if (empty != null)
                {
                    return(empty);
                }
                if (universe != null)
                {
                    return(normal);
                }
                if (children.Count == 1)
                {
                    return(children[0]);
                }
                else
                {
                    return(this);
                }
            }

            case NodeType.OR:
            {
                if (empty != null)
                {
                    return(normal);
                }
                if (universe != null)
                {
                    return(universe);
                }
                if (children.Count == 1)
                {
                    return(children[0]);
                }
                else
                {
                    return(this);
                }
            }

            default:
                throw new Exception("Internal error T5011.");
            }
        }