-
-
Notifications
You must be signed in to change notification settings - Fork 56
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
Add MutationVisitor#remove
API to remove nodes from the tree
#305
base: main
Are you sure you want to change the base?
Add MutationVisitor#remove
API to remove nodes from the tree
#305
Conversation
c1fbb73
to
a178845
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great start!
I have one or two issues at the moment. The biggest issue is that I think I didn't design the #copy
interface well. If you pass nil
as the value of one of the fields, it uses the value that's already present.
e.g., if you were to run IfNode#copy
and pass predicate: nil
, then it wouldn't change the tree at all.
In this case I think one of the precursors to this PR could be changing the copy methods to instead use the current values as the default values, as in change:
def copy(predicate: nil, statements: nil, consequent: nil, location: nil)
node =
IfNode.new(
predicate: predicate || self.predicate,
statements: statements || self.statements,
consequent: consequent || self.consequent,
location: location || self.location
)
node.comments.concat(comments.map(&:copy))
node
end
to
def copy(predicate: self.predicate, statements: self.statements, consequent: self.consequent, location: self.location)
node =
IfNode.new(
predicate: predicate,
statements: statements,
consequent: consequent,
location: location
)
node.comments.concat(comments.map(&:copy))
node
end
At the moment most of the places where you're removing nodes is going to result in not actually removing them because of this.
The other thing I have an issue with is that removing nodes from the tree could easily break the tree's expectations.
For example, in your example you have it removing a vcall with do_more_work
as the value. If that were the predicate of an if node, as in: if do_more_work
and the predicate went away, then you now can't format the tree at all.
For these reasons, I think we need a RemovedNode
that you put in place of the existing node when you replace it. That RemovedNode
should have the same API as the other nodes in the tree so that it can be queried as normal.
bf2e468
to
9a49f30
Compare
9a49f30
to
b1db957
Compare
Hey @kddnewton, sorry for a delay, I finally have found some time to make changes on the PR
That's what I end up doing, could you have another look? Thanks!
Correct me if I'm wrong but I don't think this is a concern anymore as long as we go with a "truthy" |
# [Array[ Comment | EmbDoc ]] the comments attached to this node | ||
attr_reader :comments | ||
|
||
def initialize(location:) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't sure about exact API of the RemovedNode
. I think we may want RemovedNode
to point to an instance of the node it substitutes but I at the moment I don't have use-cases for it so I decided not to overcomplicate. Perhaps I should have simplified it even further and dropped the comments
and location
properties but some existing code expected every node to respond to comments
so I decided to avoid breaking this expectation
This PR allows extends
MutationVisitor
to allow removing nodes from the tree.The API we are going with is having
remove
helper method along withmutate
to define patterns for nodes to be removed from the tree.It's not a necessity but provides a nicer API compared to:
allowing for
visitor.remove("<pattern for node to be removed>")
to be used.Under the hood we are mutating the tree by substituting nodes that match the removal pattern with an instance of
RemovedNode
which purpose is to keep the tree valid and be formatted as an empty string during tree dumping.