Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor walkers from visit pattern into iterator pattern #101

Open
2 of 3 tasks
Pennycook opened this issue Aug 26, 2024 · 1 comment · May be fixed by #126
Open
2 of 3 tasks

Refactor walkers from visit pattern into iterator pattern #101

Pennycook opened this issue Aug 26, 2024 · 1 comment · May be fixed by #126
Labels
enhancement New feature or request
Milestone

Comments

@Pennycook
Copy link
Contributor

Feature/behavior summary

Inspired by the Python bindings for libclang, we can provide an iterator-based API to walk through specialization trees.

As a simple example, this would allow us to replace the entire TreePrinter class with a loop like:

for node in tree.walk():
  print(node)

Request attributes

  • Would this be a refactor of existing code?
  • Does this proposal require new package dependencies?
  • Would this change break backwards compatibility?

Related issues

No response

Solution description

  • Add iterator methods to SourceTree.
  • Refactor all usage of "walker" classes to use the new iterator-based API.
  • Remove all the "walker" classes.

Additional notes

If it becomes apparent during the refactoring process that some of our existing "walkers" need a visitor pattern, we should also expose a dedicated visit(Visitor) interface that does not require users of the tree to implement their own recursive tree traversal.

@Pennycook Pennycook added the enhancement New feature or request label Aug 26, 2024
@Pennycook Pennycook added this to the 2.0.0 milestone Aug 26, 2024
@intel intel deleted a comment Aug 26, 2024
@intel intel deleted a comment Aug 26, 2024
This was referenced Sep 4, 2024
@Pennycook
Copy link
Contributor Author

Pennycook commented Sep 12, 2024

It turns out that we do need a visitor approach to complement the simple walk() function.

@laserkelvin, I've been working on this recently and I have what I think is quite an elegant solution. But there's an open design question that I'd like your feedback on before I finalize the implementation and open a pull request.

The basic idea is to have a visit function that accepts any callable, and then invoke that callable on every node in the tree. For very simple cases the callable can be a lambda or a function, and for more complicated cases (that require state) you can use an object.

For example, the following could be used to count all the nodes in the tree:

class NodeCounter:

  def __init__(self):
    self.count = 0

  def __call__(self, node):
    self.count += 1
    return True # see below

visitor = NodeCounter()
tree.visit(visitor)
print(visitor.count)

The return True is the bit I'm unsure about. What it currently means is "visit the children of this node", but it doesn't feel obvious and I can imagine people wanting slightly different use-cases (e.g., "don't visit any more nodes at all", "skip the children of this node", "return to the parent of this node", etc).

My proposal is to change the return handling such that:

  • None (or no return statement at all) => Visit the next node.
  • Visit.NEXT => Same as above.
  • Visit.NEXT_SIBLING => Don't process this node's children, and skip to its next sibling.

None or Visit.NEXT would be equivalent to returning True in the current implementation, while Visit.NEXT_SIBLING would be equivalent to returning False in the current implementation. I think that explicit values would be more readable, and we can extend things later if we decide we need to support more patterns.

What do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant