summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2023-08-25 09:57:39 -0400
committergit <svn-admin@ruby-lang.org>2023-08-25 19:31:28 +0000
commit649aba28f43534c729087238d01362a1f01bcc4a (patch)
tree75c938e2939036b9fd35fd0e304392c2ffa7507d
parent3b9085ad24d774231d24716ef1f6ceb292174cc6 (diff)
[ruby/yarp] Add Node#copy and MutationVisitor
https://github.com/ruby/yarp/commit/3693091661
-rw-r--r--lib/yarp.rb1
-rw-r--r--lib/yarp/yarp.gemspec1
-rw-r--r--yarp/templates/lib/yarp/mutation_visitor.rb.erb19
-rw-r--r--yarp/templates/lib/yarp/node.rb.erb9
-rwxr-xr-xyarp/templates/template.rb1
5 files changed, 31 insertions, 0 deletions
diff --git a/lib/yarp.rb b/lib/yarp.rb
index 15217e80f4..a3b0c3b074 100644
--- a/lib/yarp.rb
+++ b/lib/yarp.rb
@@ -507,6 +507,7 @@ module YARP
end
require_relative "yarp/lex_compat"
+require_relative "yarp/mutation_visitor"
require_relative "yarp/node"
require_relative "yarp/ripper_compat"
require_relative "yarp/serialize"
diff --git a/lib/yarp/yarp.gemspec b/lib/yarp/yarp.gemspec
index db69bcb451..70b6c7ebaa 100644
--- a/lib/yarp/yarp.gemspec
+++ b/lib/yarp/yarp.gemspec
@@ -61,6 +61,7 @@ Gem::Specification.new do |spec|
"lib/yarp.rb",
"lib/yarp/ffi.rb",
"lib/yarp/lex_compat.rb",
+ "lib/yarp/mutation_visitor.rb",
"lib/yarp/node.rb",
"lib/yarp/pack.rb",
"lib/yarp/ripper_compat.rb",
diff --git a/yarp/templates/lib/yarp/mutation_visitor.rb.erb b/yarp/templates/lib/yarp/mutation_visitor.rb.erb
new file mode 100644
index 0000000000..c88cabbdbb
--- /dev/null
+++ b/yarp/templates/lib/yarp/mutation_visitor.rb.erb
@@ -0,0 +1,19 @@
+module YARP
+ # This visitor walks through the tree and copies each node as it is being
+ # visited. This is useful for consumers that want to mutate the tree, as you
+ # can change subtrees in place without effecting the rest of the tree.
+ class MutationVisitor < BasicVisitor
+ <%- nodes.each_with_index do |node, index| -%>
+<%= "\n" if index != 0 -%>
+ # Copy a <%= node.name %> node
+ def visit_<%= node.human %>(node)
+ <%- params = node.params.select { |param| [NodeParam, OptionalNodeParam, NodeListParam].include?(param.class) } -%>
+ <%- if params.any? -%>
+ node.copy(<%= params.map { |param| "#{param.name}: visit(node.#{param.name})" }.join(", ") %>)
+ <%- else -%>
+ node.copy
+ <%- end -%>
+ end
+ <%- end -%>
+ end
+end
diff --git a/yarp/templates/lib/yarp/node.rb.erb b/yarp/templates/lib/yarp/node.rb.erb
index c1f14f537a..9bd9eb54e1 100644
--- a/yarp/templates/lib/yarp/node.rb.erb
+++ b/yarp/templates/lib/yarp/node.rb.erb
@@ -48,6 +48,15 @@ module YARP
}.compact.join(", ") %>]
end
+ # def copy: (**params) -> <%= node.name %>
+ def copy(**params)
+ <%= node.name %>.new(
+ <%- (node.params.map(&:name) + ["location"]).map do |name| -%>
+ <%= name %>: params.fetch(:<%= name %>) { self.<%= name %> },
+ <%- end -%>
+ )
+ end
+
# def deconstruct: () -> Array[nil | Node]
alias deconstruct child_nodes
diff --git a/yarp/templates/template.rb b/yarp/templates/template.rb
index 8b8a175172..e34d5b1a7b 100755
--- a/yarp/templates/template.rb
+++ b/yarp/templates/template.rb
@@ -315,6 +315,7 @@ TEMPLATES = [
"java/org/yarp/Loader.java",
"java/org/yarp/Nodes.java",
"java/org/yarp/AbstractNodeVisitor.java",
+ "lib/yarp/mutation_visitor.rb",
"lib/yarp/node.rb",
"lib/yarp/serialize.rb",
"src/node.c",