support 'and' operator and boolean attribute values in TreePath predicates
authorStefan Behnel <scoder@users.berlios.de>
Sun, 4 Oct 2009 19:11:22 +0000 (21:11 +0200)
committerStefan Behnel <scoder@users.berlios.de>
Sun, 4 Oct 2009 19:11:22 +0000 (21:11 +0200)
Cython/Compiler/Tests/TestTreePath.py
Cython/Compiler/TreePath.py

index 1ae0d374a89e2e9461f677fe8e18ab063344a79f..fb70bdc32eab8ea78cc12262f62e686fd9f20ca2 100644 (file)
@@ -68,6 +68,13 @@ class TestTreePath(TransformTest):
         self.assertEquals(0, len(find_all(t, "//NameNode[not(@name)]")))
         self.assertEquals(2, len(find_all(t, "//NameNode[not(@honking)]")))
 
+    def test_node_path_and(self):
+        t = self._build_tree()
+        self.assertEquals(1, len(find_all(t, "//DefNode[.//ReturnStatNode and .//NameNode]")))
+        self.assertEquals(0, len(find_all(t, "//NameNode[@honking and @name]")))
+        self.assertEquals(0, len(find_all(t, "//NameNode[@name and @honking]")))
+        self.assertEquals(2, len(find_all(t, "//DefNode[.//NameNode[@name] and @name]")))
+
     def test_node_path_attribute_string_predicate(self):
         t = self._build_tree()
         self.assertEquals(1, len(find_all(t, "//NameNode[@name = 'decorator']")))
index 432c8652ea1b3da357852075e2093dee35a5b4ad..527fa6f0baba259c18d40c18d977e22b8f6b612a 100644 (file)
@@ -167,14 +167,20 @@ def handle_attribute(next, token):
 def parse_path_value(next):
     token = next()
     value = token[0]
-    if value[:1] == "'" or value[:1] == '"':
-        value = value[1:-1]
-    else:
+    if value:
+        if value[:1] == "'" or value[:1] == '"':
+            return value[1:-1]
         try:
-            value = int(value)
+            return int(value)
         except ValueError:
-            raise ValueError("Invalid attribute predicate: '%s'" % value)
-    return value
+            pass
+    else:
+        name = token[1].lower()
+        if name == 'true':
+            return True
+        elif name == 'false':
+            return False
+    raise ValueError("Invalid attribute predicate: '%s'" % value)
 
 def handle_predicate(next, token):
     token = next()
@@ -189,6 +195,9 @@ def handle_predicate(next, token):
             if token[0] == "/":
                 token = next()
 
+        if not token[0] and token[1] == 'and':
+            return logical_and(selector, handle_predicate(next, token))
+
     def select(result):
         for node in result:
             subresult = iter((node,))
@@ -199,6 +208,20 @@ def handle_predicate(next, token):
                 yield node
     return select
 
+def logical_and(lhs_selects, rhs_select):
+    def select(result):
+        for node in result:
+            subresult = iter((node,))
+            for select in lhs_selects:
+                subresult = select(subresult)
+            predicate_result = _get_first_or_none(subresult)
+            subresult = iter((node,))
+            if predicate_result is not None:
+                for result_node in rhs_select(subresult):
+                    yield node
+    return select
+    
+
 operations = {
     "@":  handle_attribute,
     "":   handle_name,