From e8ef5b1281b9dce518902b3451096164c30bca5c Mon Sep 17 00:00:00 2001 From: Kevin Newton Date: Fri, 1 Sep 2023 14:51:50 -0400 Subject: [PATCH] [ruby/yarp] Provide a better inspect https://github.com/ruby/yarp/commit/ef14ae66e4 --- lib/yarp.rb | 78 ++++++++++++++++++++++++++++- yarp/templates/lib/yarp/node.rb.erb | 33 ++++++++++++ 2 files changed, 110 insertions(+), 1 deletion(-) diff --git a/lib/yarp.rb b/lib/yarp.rb index 316918b2db..a77292d26d 100644 --- a/lib/yarp.rb +++ b/lib/yarp.rb @@ -141,6 +141,10 @@ module YARP def deconstruct_keys(keys) { type: type, location: location } end + + def inspect + "#" + end end # This represents an error that was encountered during parsing. @@ -155,6 +159,10 @@ module YARP def deconstruct_keys(keys) { message: message, location: location } end + + def inspect + "#" + end end # This represents a warning that was encountered during parsing. @@ -169,6 +177,10 @@ module YARP def deconstruct_keys(keys) { message: message, location: location } end + + def inspect + "#" + end end # A class that knows how to walk down the tree. None of the individual visit @@ -323,7 +335,6 @@ module YARP q.nest(2) do deconstructed = deconstruct_keys([]) deconstructed.delete(:location) - q.breakable("") q.seplist(deconstructed, lambda { q.comma_breakable }, :each_value) { |value| q.pp(value) } end @@ -333,6 +344,71 @@ module YARP end end + # This object is responsible for generating the output for the inspect method + # implementations of child nodes. + class NodeInspector + attr_reader :prefix, :output + + def initialize(prefix = "") + @prefix = prefix + @output = +"" + end + + # Appends a line to the output with the current prefix. + def <<(line) + output << "#{prefix}#{line}" + end + + # This generates a string that is used as the header of the inspect output + # for any given node. + def header(node) + output = +"@ #{node.class.name.split("::").last} (" + output << "location: (#{node.location.start_offset}...#{node.location.end_offset})" + output << ", newline: true" if node.newline? + output << ")\n" + output + end + + # Generates a string that represents a list of nodes. It handles properly + # using the box drawing characters to make the output look nice. + def list(prefix, nodes) + output = +"(length: #{nodes.length})\n" + last_index = nodes.length - 1 + + nodes.each_with_index do |node, index| + pointer, preadd = (index == last_index) ? ["└── ", " "] : ["├── ", "│ "] + node_prefix = "#{prefix}#{preadd}" + output << node.inspect(NodeInspector.new(node_prefix)).sub(node_prefix, "#{prefix}#{pointer}") + end + + output + end + + # Generates a string that represents a location field on a node. + def location(value) + if value + "(#{value.start_offset}...#{value.end_offset}) = #{value.slice.inspect}" + else + "∅" + end + end + + # Generates a string that represents a child node. + def child_node(node, append) + node.inspect(child_inspector(append)).delete_prefix(prefix) + end + + # Returns a new inspector that can be used to inspect a child node. + def child_inspector(append) + NodeInspector.new("#{prefix}#{append}") + end + + # Returns the output as a string. + def to_str + output + end + end + class FloatNode < Node def value Float(slice) diff --git a/yarp/templates/lib/yarp/node.rb.erb b/yarp/templates/lib/yarp/node.rb.erb index 6241eabd12..8919cb7ad0 100644 --- a/yarp/templates/lib/yarp/node.rb.erb +++ b/yarp/templates/lib/yarp/node.rb.erb @@ -92,6 +92,39 @@ module YARP <%- end -%> <%- end -%> <%- end -%> + + def inspect(inspector = NodeInspector.new) + inspector << inspector.header(self) + <%- node.fields.each_with_index do |field, index| -%> + <%- pointer, preadd = index == node.fields.length - 1 ? ["└── ", " "] : ["├── ", "│ "] -%> + <%- case field -%> + <%- when YARP::NodeListField -%> + inspector << "<%= pointer %><%= field.name %>: #{inspector.list("#{inspector.prefix}<%= preadd %>", <%= field.name %>)}" + <%- when YARP::LocationListField, YARP::ConstantListField -%> + inspector << "<%= pointer %><%= field.name %>: #{<%= field.name %>.inspect}\n" + <%- when YARP::NodeField -%> + inspector << "<%= pointer %><%= field.name %>:\n" + inspector << inspector.child_node(<%= field.name %>, "<%= preadd %>") + <%- when YARP::OptionalNodeField -%> + if (<%= field.name %> = self.<%= field.name %>).nil? + inspector << "<%= pointer %><%= field.name %>: ∅\n" + else + inspector << "<%= pointer %><%= field.name %>:\n" + inspector << <%= field.name %>.inspect(inspector.child_inspector("<%= preadd %>")).delete_prefix(inspector.prefix) + end + <%- when YARP::ConstantField, YARP::StringField, YARP::UInt32Field -%> + inspector << "<%= pointer %><%= field.name %>: #{<%= field.name %>.inspect}\n" + <%- when YARP::FlagsField -%> + <%- flag = flags.find { |flag| flag.name == field.kind }.tap { |flag| raise unless flag } -%> + inspector << "<%= pointer %><%= field.name %>: #{[<%= flag.values.map { |value| "(\"#{value.name.downcase}\" if #{value.name.downcase}?)" }.join(", ") %>].compact.join(", ")}\n" + <%- when YARP::LocationField, YARP::OptionalLocationField -%> + inspector << "<%= pointer %><%= field.name %>: #{inspector.location(<%= field.name %>)}\n" + <%- else -%> + <%- raise -%> + <%- end -%> + <%- end -%> + inspector.to_str + end end <%- end -%>