Commit b7c56ce3 authored by Stefan Behnel's avatar Stefan Behnel

support 'and' operator and boolean attribute values in TreePath predicates

parent 8b5d1ff0
...@@ -68,6 +68,13 @@ class TestTreePath(TransformTest): ...@@ -68,6 +68,13 @@ class TestTreePath(TransformTest):
self.assertEquals(0, len(find_all(t, "//NameNode[not(@name)]"))) self.assertEquals(0, len(find_all(t, "//NameNode[not(@name)]")))
self.assertEquals(2, len(find_all(t, "//NameNode[not(@honking)]"))) 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): def test_node_path_attribute_string_predicate(self):
t = self._build_tree() t = self._build_tree()
self.assertEquals(1, len(find_all(t, "//NameNode[@name = 'decorator']"))) self.assertEquals(1, len(find_all(t, "//NameNode[@name = 'decorator']")))
......
...@@ -167,14 +167,20 @@ def handle_attribute(next, token): ...@@ -167,14 +167,20 @@ def handle_attribute(next, token):
def parse_path_value(next): def parse_path_value(next):
token = next() token = next()
value = token[0] value = token[0]
if value[:1] == "'" or value[:1] == '"': if value:
value = value[1:-1] if value[:1] == "'" or value[:1] == '"':
else: return value[1:-1]
try: try:
value = int(value) return int(value)
except ValueError: except ValueError:
raise ValueError("Invalid attribute predicate: '%s'" % value) pass
return value 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): def handle_predicate(next, token):
token = next() token = next()
...@@ -189,6 +195,9 @@ def handle_predicate(next, token): ...@@ -189,6 +195,9 @@ def handle_predicate(next, token):
if token[0] == "/": if token[0] == "/":
token = next() token = next()
if not token[0] and token[1] == 'and':
return logical_and(selector, handle_predicate(next, token))
def select(result): def select(result):
for node in result: for node in result:
subresult = iter((node,)) subresult = iter((node,))
...@@ -199,6 +208,20 @@ def handle_predicate(next, token): ...@@ -199,6 +208,20 @@ def handle_predicate(next, token):
yield node yield node
return select 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 = { operations = {
"@": handle_attribute, "@": handle_attribute,
"": handle_name, "": handle_name,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment