merge stable
authorNicolas Chauvat <nicolas.chauvat@logilab.fr>
Sat, 25 Sep 2010 22:32:13 +0200
branchstable
changeset 591 cae803a9d648
parent 587 df94554d6ebd (current diff)
parent 590 b93df9e76dfe (diff)
child 592 8d097456fa5b
merge
--- a/base.py	Mon Sep 13 14:46:46 2010 +0200
+++ b/base.py	Sat Sep 25 22:32:13 2010 +0200
@@ -140,9 +140,14 @@
         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
+        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."""
--- a/nodes.py	Mon Sep 13 14:46:46 2010 +0200
+++ b/nodes.py	Sat Sep 25 22:32:13 2010 +0200
@@ -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,14 +142,17 @@
         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']:
-                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
-            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):
--- a/stcheck.py	Mon Sep 13 14:46:46 2010 +0200
+++ b/stcheck.py	Sat Sep 25 22:32:13 2010 +0200
@@ -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):
--- a/stmts.py	Mon Sep 13 14:46:46 2010 +0200
+++ b/stmts.py	Sat Sep 25 22:32:13 2010 +0200
@@ -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"""
--- a/undo.py	Mon Sep 13 14:46:46 2010 +0200
+++ b/undo.py	Sat Sep 25 22:32:13 2010 +0200
@@ -15,9 +15,8 @@
 #
 # 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."""
 
-"""
 __docformat__ = "restructuredtext en"
 
 from rql.nodes import VariableRef, Variable, BinaryNode
@@ -61,9 +60,11 @@
 
 class NodeOperation(object):
     """Abstract class for node manipulation operations."""
-    def __init__(self, node):
+    def __init__(self, node, stmt=None):
         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,45 +136,36 @@
 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
-        # 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"""
+        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 !
-            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
+        self.node.parent = parent
         for varref in self.node.iget_nodes(VariableRef):
             varref.register_reference()