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."); } }