Skip to content

Instantly share code, notes, and snippets.

@tompng
Created February 1, 2025 17:28
Show Gist options
  • Save tompng/8110149c5344e89bddaafa636eab7547 to your computer and use it in GitHub Desktop.
Save tompng/8110149c5344e89bddaafa636eab7547 to your computer and use it in GitHub Desktop.
require 'prism'
require 'ripper'
def parsey_extract_locations(code)
lines = code.lines
line_indexes = lines.reduce([0]) { _1 << _1.last + _2.bytesize }
code_index = ->(line, col) { line_indexes[line - 1] + col }
locations = []
each_node = -> node do
locs = node.locations.compact
unless locs.empty?
from = locs.flat_map { code_index.call(it.first_lineno, it.first_column) }.min
to = locs.flat_map { code_index.call(it.last_lineno, it.last_column) }.max
locations << [from, to]
end
node.children.each do |child|
each_node.call(child) if child.is_a?(RubyVM::AbstractSyntaxTree::Node)
end
end
each_node.call(RubyVM::AbstractSyntaxTree.parse(code))
locations
end
def prism_extract_locations(code)
locations = []
each_node = ->node do
locations << [node.location.start_offset, node.location.end_offset]
node.compact_child_nodes.each(&each_node)
end
each_node.call(Prism.parse(code).value)
locations
end
def print_depth(code, locations)
depth = 0
last_pos = 0
segments = []
locations.uniq.flat_map { [[_1, +1], [_2, -1]] }.sort.each do |pos, open_close|
segments << [code.byteslice(last_pos...pos), depth] unless last_pos == pos
depth += open_close
last_pos = pos
end
puts(
segments.map do |segment, depth|
c = [255 - 3 * depth, 232].max
"\e[48;5;#{c}m#{segment}\e[0m"
end.join
)
end
def compare(code)
print_depth(code, parsey_extract_locations(code))
print_depth(code, prism_extract_locations(code))
end
compare('def f = not a in b rescue c')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment