Skip to content

Commit ef14ae6

Browse files
committed
Provide a better inspect
1 parent fc88558 commit ef14ae6

File tree

3 files changed

+130
-4
lines changed

3 files changed

+130
-4
lines changed

bin/parse

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,23 @@ else
1515
result = YARP.parse_file(ARGV[0] || "test.rb")
1616
end
1717

18-
result.mark_newlines if ENV['MARK_NEWLINES']
19-
result = result.value.accept(YARP::DesugarVisitor.new) if ENV['DESUGAR']
20-
pp result
18+
result.mark_newlines if ENV["MARK_NEWLINES"]
19+
20+
value = result.value
21+
value = value.accept(YARP::DesugarVisitor.new) if ENV["DESUGAR"]
22+
23+
parts = {}
24+
parts["Comments"] = result.comments if result.comments.any?
25+
parts["Warnings"] = result.warnings if result.warnings.any?
26+
parts["Errors"] = result.errors if result.errors.any?
27+
28+
if parts.empty?
29+
puts value.inspect
30+
else
31+
parts["AST"] = value
32+
parts.each_with_index do |(key, value), index|
33+
puts if index > 0
34+
puts "#{key}:"
35+
puts value.inspect
36+
end
37+
end

lib/yarp.rb

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ def initialize(type, location)
141141
def deconstruct_keys(keys)
142142
{ type: type, location: location }
143143
end
144+
145+
def inspect
146+
"#<YARP::Comment @type=#{@type.inspect} @location=#{@location.inspect}>"
147+
end
144148
end
145149

146150
# This represents an error that was encountered during parsing.
@@ -155,6 +159,10 @@ def initialize(message, location)
155159
def deconstruct_keys(keys)
156160
{ message: message, location: location }
157161
end
162+
163+
def inspect
164+
"#<YARP::ParseError @message=#{@message.inspect} @location=#{@location.inspect}>"
165+
end
158166
end
159167

160168
# This represents a warning that was encountered during parsing.
@@ -169,6 +177,10 @@ def initialize(message, location)
169177
def deconstruct_keys(keys)
170178
{ message: message, location: location }
171179
end
180+
181+
def inspect
182+
"#<YARP::ParseWarning @message=#{@message.inspect} @location=#{@location.inspect}>"
183+
end
172184
end
173185

174186
# A class that knows how to walk down the tree. None of the individual visit
@@ -323,7 +335,6 @@ def pretty_print(q)
323335
q.nest(2) do
324336
deconstructed = deconstruct_keys([])
325337
deconstructed.delete(:location)
326-
327338
q.breakable("")
328339
q.seplist(deconstructed, lambda { q.comma_breakable }, :each_value) { |value| q.pp(value) }
329340
end
@@ -333,6 +344,71 @@ def pretty_print(q)
333344
end
334345
end
335346

347+
# This object is responsible for generating the output for the inspect method
348+
# implementations of child nodes.
349+
class NodeInspector
350+
attr_reader :prefix, :output
351+
352+
def initialize(prefix = "")
353+
@prefix = prefix
354+
@output = +""
355+
end
356+
357+
# Appends a line to the output with the current prefix.
358+
def <<(line)
359+
output << "#{prefix}#{line}"
360+
end
361+
362+
# This generates a string that is used as the header of the inspect output
363+
# for any given node.
364+
def header(node)
365+
output = +"@ #{node.class.name.split("::").last} ("
366+
output << "location: (#{node.location.start_offset}...#{node.location.end_offset})"
367+
output << ", newline: true" if node.newline?
368+
output << ")\n"
369+
output
370+
end
371+
372+
# Generates a string that represents a list of nodes. It handles properly
373+
# using the box drawing characters to make the output look nice.
374+
def list(prefix, nodes)
375+
output = +"(length: #{nodes.length})\n"
376+
last_index = nodes.length - 1
377+
378+
nodes.each_with_index do |node, index|
379+
pointer, preadd = (index == last_index) ? ["└── ", " "] : ["├── ", "│ "]
380+
node_prefix = "#{prefix}#{preadd}"
381+
output << node.inspect(NodeInspector.new(node_prefix)).sub(node_prefix, "#{prefix}#{pointer}")
382+
end
383+
384+
output
385+
end
386+
387+
# Generates a string that represents a location field on a node.
388+
def location(value)
389+
if value
390+
"(#{value.start_offset}...#{value.end_offset}) = #{value.slice.inspect}"
391+
else
392+
"∅"
393+
end
394+
end
395+
396+
# Generates a string that represents a child node.
397+
def child_node(node, append)
398+
node.inspect(child_inspector(append)).delete_prefix(prefix)
399+
end
400+
401+
# Returns a new inspector that can be used to inspect a child node.
402+
def child_inspector(append)
403+
NodeInspector.new("#{prefix}#{append}")
404+
end
405+
406+
# Returns the output as a string.
407+
def to_str
408+
output
409+
end
410+
end
411+
336412
class FloatNode < Node
337413
def value
338414
Float(slice)

templates/lib/yarp/node.rb.erb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,39 @@ module YARP
9292
<%- end -%>
9393
<%- end -%>
9494
<%- end -%>
95+
96+
def inspect(inspector = NodeInspector.new)
97+
inspector << inspector.header(self)
98+
<%- node.fields.each_with_index do |field, index| -%>
99+
<%- pointer, preadd = index == node.fields.length - 1 ? ["└── ", " "] : ["├── ", "│ "] -%>
100+
<%- case field -%>
101+
<%- when YARP::NodeListField -%>
102+
inspector << "<%= pointer %><%= field.name %>: #{inspector.list("#{inspector.prefix}<%= preadd %>", <%= field.name %>)}"
103+
<%- when YARP::LocationListField, YARP::ConstantListField -%>
104+
inspector << "<%= pointer %><%= field.name %>: #{<%= field.name %>.inspect}\n"
105+
<%- when YARP::NodeField -%>
106+
inspector << "<%= pointer %><%= field.name %>:\n"
107+
inspector << inspector.child_node(<%= field.name %>, "<%= preadd %>")
108+
<%- when YARP::OptionalNodeField -%>
109+
if (<%= field.name %> = self.<%= field.name %>).nil?
110+
inspector << "<%= pointer %><%= field.name %>: ∅\n"
111+
else
112+
inspector << "<%= pointer %><%= field.name %>:\n"
113+
inspector << <%= field.name %>.inspect(inspector.child_inspector("<%= preadd %>")).delete_prefix(inspector.prefix)
114+
end
115+
<%- when YARP::ConstantField, YARP::StringField, YARP::UInt32Field -%>
116+
inspector << "<%= pointer %><%= field.name %>: #{<%= field.name %>.inspect}\n"
117+
<%- when YARP::FlagsField -%>
118+
<%- flag = flags.find { |flag| flag.name == field.kind }.tap { |flag| raise unless flag } -%>
119+
inspector << "<%= pointer %><%= field.name %>: #{[<%= flag.values.map { |value| "(\"#{value.name.downcase}\" if #{value.name.downcase}?)" }.join(", ") %>].compact.join(", ")}\n"
120+
<%- when YARP::LocationField, YARP::OptionalLocationField -%>
121+
inspector << "<%= pointer %><%= field.name %>: #{inspector.location(<%= field.name %>)}\n"
122+
<%- else -%>
123+
<%- raise -%>
124+
<%- end -%>
125+
<%- end -%>
126+
inspector.to_str
127+
end
95128
end
96129

97130
<%- end -%>

0 commit comments

Comments
 (0)