def _resolve_refs(self, rule_map, expr, done): """Return an expression with all its lazy references recursively resolved. Resolve any lazy references in the expression ``expr``, recursing into all subexpressions. :arg done: The set of Expressions that have already been or are currently being resolved, to ward off redundant work and prevent infinite recursion for circular refs """ if isinstance(expr, LazyReference): label = text_type(expr) try: reffed_expr = rule_map[label] except KeyError: raise UndefinedLabel(expr) return self._resolve_refs(rule_map, reffed_expr, done) else: if getattr(expr, 'members', ()) and expr not in done: # Prevents infinite recursion for circular refs. At worst, one # of `expr.members` can refer back to `expr`, but it can't go # any farther. done.add(expr) expr.members = tuple( self._resolve_refs(rule_map, member, done) for member in expr.members) return expr
def _resolve_refs(self, rule_map, expr): """Return an expression with all its lazy references recursively resolved. Resolve any lazy references in the expression ``expr``, recursing into all subexpressions. """ if isinstance(expr, LazyReference): label = unicode(expr) try: reffed_expr = rule_map[label] except KeyError: raise UndefinedLabel(expr) return self._resolve_refs(rule_map, reffed_expr) else: original_members = getattr(expr, 'members', ()) if original_members: # Prevents infinite recursion for circular refs. At worst, one # of `expr.members` can refer back to `expr`, but it can't go # any farther. expr.members = () resolved_members = [ self._resolve_refs(rule_map, member) for member in original_members ] expr.members = resolved_members return expr
def _resolve_refs(self, rule_map, expr, unwalked_names, walking_names): """Return an expression with all its lazy references recursively resolved. Resolve any lazy references in the expression ``expr``, recursing into all subexpressions. Populate ``rule_map`` with any other rules (named expressions) resolved along the way. Remove from ``unwalked_names`` any which were resolved. :arg walking_names: The stack of labels we are currently recursing through. This prevents infinite recursion for circular refs. """ # If it's a top-level (named) expression and we've already walked it, # don't walk it again: if expr.name and expr.name not in unwalked_names: # unwalked_names started out with all the rule names in it, so, if # this is a named expr and it isn't in there, it must have been # resolved. return rule_map[expr.name] # If not, resolve it: elif isinstance(expr, LazyReference): label = str(expr) if label not in walking_names: # We aren't already working on traversing this label: try: reffed_expr = rule_map[label] except KeyError: raise UndefinedLabel(expr) rule_map[label] = self._resolve_refs(rule_map, reffed_expr, unwalked_names, walking_names + (label, )) # If we recurse into a compound expression, the remove() # happens in there. But if this label points to a non-compound # expression like a literal or a regex or another lazy # reference, we need to do this here: unwalked_names.discard(label) return rule_map[label] else: members = getattr(expr, 'members', []) if members: expr.members = [ self._resolve_refs(rule_map, m, unwalked_names, walking_names) for m in members ] if expr.name: unwalked_names.remove(expr.name) return expr
def resolve_refs(expr): """Turn references into the things they actually reference. Walk the expression tree, looking for _LazyReferences. When we find one, replace it with rules[the reference]. """ if isinstance(expr, LazyReference): try: return rule_map[expr] except KeyError: raise UndefinedLabel(expr) else: members = getattr(expr, 'members', None) if members: expr.members = [resolve_refs(m) for m in members] return expr
def _resolve_ref(expr): """ Update in place rule_map and resolved, returns expr resolved: if it is a reference, its transitivly reffed exp is returned if it is a compound exp, its members are resolved and it is returned """ # nonlocal rule_map, resolved if isinstance(expr, LazyReference): label = str(expr) try: reffed_expr = rule_map[label] except KeyError: raise UndefinedLabel(expr) try: reffed_expr = _resolve_ref(reffed_expr) except RuntimeError: raise RecursiveLabel(label) # Deal with rules aliasing expressions like A=B B='b' the LazyReference # resolution will associate 'A' with the expression 'b' with name 'B' if reffed_expr.name != label: reffed_expr = copy(reffed_expr) reffed_expr.name = label rule_map[label] = reffed_expr return reffed_expr elif not expr in resolved: #deal with _Compound expressions original_members = getattr(expr, 'members', None) if original_members != None: # Prevents infinite recursion for circular refs. expr.members = None resolved_members = [ _resolve_ref(member) for member in original_members ] expr.members = resolved_members resolved.add(expr) return expr else: return expr