diff --git a/base.py b/base.py index df94554d6ebd8c7dcd411b519f1952ab7ead0207_YmFzZS5weQ==..cae803a9d648839fabe40474deb0bafafed0f7ef_YmFzZS5weQ== 100644 --- a/base.py +++ b/base.py @@ -140,6 +140,10 @@ child.parent = self def remove(self, child): - """remove a child node""" - self.children.remove(child) + """Remove a child node. Return the removed node, its old parent and + index in the children list. + """ + index = self.children.index(child) + del self.children[index] + parent = child.parent child.parent = None @@ -145,4 +149,5 @@ child.parent = None + return child, parent, index def insert(self, index, child): """insert a child node""" @@ -155,7 +160,7 @@ self.children.pop(i) self.children.insert(i, new_child) new_child.parent = self - + return old_child, self, i class BinaryNode(Node): __slots__ = () @@ -169,8 +174,8 @@ def remove(self, child): """Remove the child and replace this node with the other child.""" - self.children.remove(child) - self.parent.replace(self, self.children[0]) + index = self.children.index(child) + return self.parent.replace(self, self.children[not index]) def get_parts(self): """Return the left hand side and the right hand side of this node.""" diff --git a/nodes.py b/nodes.py index df94554d6ebd8c7dcd411b519f1952ab7ead0207_bm9kZXMucHk=..cae803a9d648839fabe40474deb0bafafed0f7ef_bm9kZXMucHk= 100644 --- a/nodes.py +++ b/nodes.py @@ -105,6 +105,19 @@ relation.append(cmpop) return relation +def make_constant_restriction(var, rtype, value, ctype, operator='='): + if ctype is None: + ctype = etype_from_pyobj(value) + if isinstance(value, (set, frozenset, tuple, list, dict)): + if len(value) > 1: + rel = make_relation(var, rtype, ('IN',), Function, operator) + infunc = rel.children[1].children[0] + for atype in sorted(value): + infunc.append(Constant(atype, ctype)) + return rel + value = iter(value).next() + return make_relation(var, rtype, (value, ctype), Constant, operator) + class EditableMixIn(object): """mixin class to add edition functionalities to some nodes, eg root nodes @@ -129,6 +142,8 @@ handling """ # unregister variable references in the removed subtree + parent = node.parent + stmt = parent.stmt for varref in node.iget_nodes(VariableRef): varref.unregister_reference() if undefine and not varref.variable.stinfo['references']: @@ -132,6 +147,8 @@ for varref in node.iget_nodes(VariableRef): varref.unregister_reference() if undefine and not varref.variable.stinfo['references']: - node.stmt.undefine_variable(varref.variable) + stmt.undefine_variable(varref.variable) + # remove return actually removed node and its parent + node, parent, index = parent.remove(node) if self.should_register_op: from rql.undo import RemoveNodeOperation @@ -136,7 +153,6 @@ if self.should_register_op: from rql.undo import RemoveNodeOperation - self.undo_manager.add_operation(RemoveNodeOperation(node)) - node.parent.remove(node) + self.undo_manager.add_operation(RemoveNodeOperation(node, parent, stmt, index)) def add_restriction(self, relation): """add a restriction relation""" @@ -160,18 +176,8 @@ variable rtype = value """ - if ctype is None: - ctype = etype_from_pyobj(value) - if isinstance(value, (set, frozenset, tuple, list, dict)): - if len(value) > 1: - rel = make_relation(var, rtype, ('IN',), Function, operator=operator) - infunc = rel.children[1].children[0] - for atype in sorted(value): - infunc.append(Constant(atype, ctype)) - return self.add_restriction(rel) - value = iter(value).next() - return self.add_restriction(make_relation(var, rtype, (value, ctype), - Constant, operator)) + restr = make_constant_restriction(var, rtype, value, ctype, operator) + return self.add_restriction(restr) def add_relation(self, lhsvar, rtype, rhsvar): """builds a restriction node to express '<var> eid <eid>'""" @@ -279,6 +285,9 @@ def neged(self, traverse_scope=False, _fromnode=None, strict=False): return self + def remove(self, child): + return self.parent.remove(self) + # def parent_scope_property(attr): # def _get_parent_attr(self, attr=attr): # return getattr(self.parent.scope, attr) @@ -334,6 +343,10 @@ assert oldnode is self.query self.query = newnode newnode.parent = self + return oldnode, self, None + + def remove(self, child): + return self.parent.remove(self) @property def scope(self): diff --git a/stcheck.py b/stcheck.py index df94554d6ebd8c7dcd411b519f1952ab7ead0207_c3RjaGVjay5weQ==..cae803a9d648839fabe40474deb0bafafed0f7ef_c3RjaGVjay5weQ== 100644 --- a/stcheck.py +++ b/stcheck.py @@ -315,8 +315,7 @@ # NOT normalization child = not_.children[0] if self._should_wrap_by_exists(child): - not_.remove(child) - not_.append(Exists(child)) + not_.replace(child, Exists(child)) def _should_wrap_by_exists(self, child): if isinstance(child, Exists): diff --git a/stmts.py b/stmts.py index df94554d6ebd8c7dcd411b519f1952ab7ead0207_c3RtdHMucHk=..cae803a9d648839fabe40474deb0bafafed0f7ef_c3RtdHMucHk= 100644 --- a/stmts.py +++ b/stmts.py @@ -101,10 +101,7 @@ self._varmaker = rqlvar_maker(defined=self.defined_vars, # XXX only on Select node aliases=getattr(self, 'aliases', None)) - name = self._varmaker.next() - while name in self.defined_vars: - name = self._varmaker.next() - return name + return self._varmaker.next() def make_variable(self): """create a new variable with an unique name for this tree""" @@ -146,6 +143,7 @@ raise return True + class Statement(object): """base class for statement nodes""" @@ -702,6 +700,7 @@ # XXX resetting oldnode parent cause pb with cw.test_views (w/ facets) #oldnode.parent = None newnode.parent = self + return oldnode, self, None def remove(self, node): if node is self.where: @@ -716,6 +715,7 @@ else: raise Exception('duh XXX') node.parent = None + return node, self, None def undefine_variable(self, var): """undefine the given variable and remove all relations where it appears""" diff --git a/undo.py b/undo.py index df94554d6ebd8c7dcd411b519f1952ab7ead0207_dW5kby5weQ==..cae803a9d648839fabe40474deb0bafafed0f7ef_dW5kby5weQ== 100644 --- a/undo.py +++ b/undo.py @@ -15,5 +15,5 @@ # # You should have received a copy of the GNU Lesser General Public License along # with rql. If not, see <http://www.gnu.org/licenses/>. -"""Manages undos on RQL syntax trees. +"""Manages undos on RQL syntax trees.""" @@ -19,5 +19,4 @@ -""" __docformat__ = "restructuredtext en" from rql.nodes import VariableRef, Variable, BinaryNode @@ -61,5 +60,5 @@ class NodeOperation(object): """Abstract class for node manipulation operations.""" - def __init__(self, node): + def __init__(self, node, stmt=None): self.node = node @@ -65,5 +64,7 @@ self.node = node - self.stmt = node.stmt + if stmt is None: + stmt = node.stmt + self.stmt = stmt def __str__(self): """undo the operation on the selection""" @@ -135,11 +136,10 @@ class RemoveNodeOperation(NodeOperation): """Defines how to undo remove_node().""" - def __init__(self, node): - NodeOperation.__init__(self, node) - self.node_parent = node.parent - if isinstance(self.node_parent, Select): - assert self.node is self.node_parent.where - else: - self.index = node.parent.children.index(node) + def __init__(self, node, parent, stmt, index): + NodeOperation.__init__(self, node, stmt) + self.node_parent = parent + #if isinstance(parent, Select): + # assert self.node is parent.where + self.index = index # XXX FIXME : find a better way to do that @@ -145,12 +145,5 @@ # XXX FIXME : find a better way to do that - # needed when removing a BinaryNode's child - self.binary_remove = isinstance(self.node_parent, BinaryNode) - if self.binary_remove: - self.gd_parent = self.node_parent.parent - if isinstance(self.gd_parent, Select): - assert self.node_parent is self.gd_parent.where - else: - self.parent_index = self.gd_parent.children.index(self.node_parent) + self.binary_remove = isinstance(node, BinaryNode) def undo(self, selection): """undo the operation on the selection""" @@ -154,9 +147,14 @@ def undo(self, selection): """undo the operation on the selection""" + parent = self.node_parent + if self.index is None: + assert isinstance(parent, Select) + sibling = parent.where = self.node + parent.where = self.node if self.binary_remove: # if 'parent' was a BinaryNode, then first reinsert the removed node # at the same pos in the original 'parent' Binary Node, and then # reinsert this BinaryNode in its parent's children list # WARNING : the removed node sibling's parent is no longer the # 'node_parent'. We must Reparent it manually ! @@ -157,20 +155,13 @@ if self.binary_remove: # if 'parent' was a BinaryNode, then first reinsert the removed node # at the same pos in the original 'parent' Binary Node, and then # reinsert this BinaryNode in its parent's children list # WARNING : the removed node sibling's parent is no longer the # 'node_parent'. We must Reparent it manually ! - node_sibling = self.node_parent.children[0] - node_sibling.parent = self.node_parent - self.node_parent.insert(self.index, self.node) - if isinstance(self.gd_parent, Select): - self.gd_parent.where = self.node_parent - else: - self.gd_parent.children[self.parent_index] = self.node_parent - self.node_parent.parent = self.gd_parent - elif isinstance(self.node_parent, Select): - self.node_parent.where = self.node - self.node.parent = self.node_parent - else: - self.node_parent.insert(self.index, self.node) + if self.index is not None: + sibling = self.node_parent.children[self.index] + parent.children[self.index] = self.node + sibling.parent = self.node + elif self.index is not None: + parent.insert(self.index, self.node) # register reference from the removed node @@ -176,4 +167,5 @@ # register reference from the removed node + self.node.parent = parent for varref in self.node.iget_nodes(VariableRef): varref.register_reference()