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
Exemple #2
0
    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
Exemple #3
0
    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
Exemple #4
0
        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
Exemple #5
0
 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