|
| 1 | +# This script locates a set of nodes determined by a line and column (in bytes). |
| 2 | + |
| 3 | +require "prism" |
| 4 | + |
| 5 | +def locate(node, line:, column:) |
| 6 | + queue = [node] |
| 7 | + result = [] |
| 8 | + |
| 9 | + while (node = queue.shift) |
| 10 | + # Each node that we visit should be added to the result, so that we end up |
| 11 | + # with an array of the nodes that we traversed. |
| 12 | + result << node |
| 13 | + |
| 14 | + # Iterate over each child node. |
| 15 | + node.compact_child_nodes.each do |child_node| |
| 16 | + child_location = child_node.location |
| 17 | + |
| 18 | + start_line = child_location.start_line |
| 19 | + end_line = child_location.end_line |
| 20 | + |
| 21 | + # Here we determine if the given coordinates are contained within the |
| 22 | + # child node's location. |
| 23 | + if start_line == end_line |
| 24 | + if line == start_line && column >= child_location.start_column && column < child_location.end_column |
| 25 | + queue << child_node |
| 26 | + break |
| 27 | + end |
| 28 | + elsif (line == start_line && column >= child_location.start_column) || (line == end_line && column < child_location.end_column) |
| 29 | + queue << child_node |
| 30 | + break |
| 31 | + elsif line > start_line && line < end_line |
| 32 | + queue << child_node |
| 33 | + break |
| 34 | + end |
| 35 | + end |
| 36 | + end |
| 37 | + |
| 38 | + # Finally, we return the result. |
| 39 | + result |
| 40 | +end |
| 41 | + |
| 42 | +result = Prism.parse_stream(DATA) |
| 43 | +locate(result.value, line: 4, column: 14).each_with_index do |node, index| |
| 44 | + location = node.location |
| 45 | + puts "#{" " * index}#{node.type}@#{location.start_line}:#{location.start_column}-#{location.end_line}:#{location.end_column}" |
| 46 | +end |
| 47 | + |
| 48 | +# => |
| 49 | +# program_node@1:0-7:3 |
| 50 | +# statements_node@1:0-7:3 |
| 51 | +# module_node@1:0-7:3 |
| 52 | +# statements_node@2:2-6:5 |
| 53 | +# class_node@2:2-6:5 |
| 54 | +# statements_node@3:4-5:7 |
| 55 | +# def_node@3:4-5:7 |
| 56 | +# statements_node@4:6-4:21 |
| 57 | +# call_node@4:6-4:21 |
| 58 | +# call_node@4:6-4:15 |
| 59 | +# arguments_node@4:12-4:15 |
| 60 | +# integer_node@4:12-4:15 |
| 61 | + |
| 62 | +__END__ |
| 63 | +module Foo |
| 64 | + class Bar |
| 65 | + def baz |
| 66 | + 111 + 222 + 333 |
| 67 | + end |
| 68 | + end |
| 69 | +end |
0 commit comments