diff --git a/nodes.py b/nodes.py index d38764ab62ef2536cbc8d33c5ae6b10f526ce7f6_bm9kZXMucHk=..53e9cd50975e3d705c9fe26e0666f8e90c8fc187_bm9kZXMucHk= 100644 --- a/nodes.py +++ b/nodes.py @@ -26,7 +26,8 @@ from rql import CoercionError from rql.base import BaseNode, Node, BinaryNode, LeafNode -from rql.utils import function_description, quote, uquote, build_visitor_stub +from rql.utils import (function_description, quote, uquote, build_visitor_stub, + common_parent) CONSTANT_TYPES = frozenset((None, 'Date', 'Datetime', 'Boolean', 'Float', 'Int', 'String', 'Substitute', 'etype')) @@ -949,11 +950,8 @@ def set_scope(self, scopenode): if scopenode is self.stmt or self.stinfo['scope'] is None: self.stinfo['scope'] = scopenode - elif self.stinfo['scope'] is not self.stmt and scopenode is not self.stinfo['scope']: - # XXX get common parent scope if this assertion fail - assert scopenode.parent.scope is self.stinfo['scope'].parent.scope, \ - (scopenode.parent.scope, self.stinfo['scope'].parent.scope) - self.stinfo['scope'] = scopenode.parent.scope + elif not (self.stinfo['scope'] is self.stmt or scopenode is self.stinfo['scope']): + self.stinfo['scope'] = common_parent(self.stinfo['scope'], scopenode) def get_scope(self): return self.stinfo['scope'] @@ -985,6 +983,7 @@ return rel return None + build_visitor_stub((SubQuery, And, Or, Not, Exists, Relation, Comparison, MathExpression, Function, Constant, VariableRef, SortTerm, ColumnAlias, Variable)) diff --git a/utils.py b/utils.py index d38764ab62ef2536cbc8d33c5ae6b10f526ce7f6_dXRpbHMucHk=..53e9cd50975e3d705c9fe26e0666f8e90c8fc187_dXRpbHMucHk= 100644 --- a/utils.py +++ b/utils.py @@ -73,6 +73,25 @@ """Return true if the given word is a RQL keyword.""" return word.upper() in KEYWORDS +def common_parent(node1, node2): + """return the first common parent between node1 and node2 + + algorithm : + 1) index node1's parents + 2) climb among node2's parents until we find a common parent + """ + # index node1's parents + node1_parents = set() + while node1: + node1_parents.add(node1) + node1 = node1.parent + # climb among node2's parents until we find a common parent + while node2: + if node2 in node1_parents: + return node2 + node2 = node2.parent + raise Exception('DUH!') + FUNCTIONS = _GenericAdvFuncHelper.FUNCTIONS.copy() def register_function(funcdef):