[ruby/prism] Prism::Node#tunnel

https://github.com/ruby/prism/commit/0bf5d651da
This commit is contained in:
Kevin Newton 2024-05-02 12:59:49 -04:00 коммит произвёл git
Родитель c631679b94
Коммит 7a49edcf1f
4 изменённых файлов: 62 добавлений и 3 удалений

Просмотреть файл

@ -172,7 +172,7 @@ module Prism
DEPRECATED: ConstantPathNode#child is deprecated and will be removed \
in the next major version. Use \
ConstantPathNode#name/ConstantPathNode#name_loc instead. Called from \
#{caller(1..1).first}.
#{caller(1, 1)&.first}.
MSG
name ? ConstantReadNode.new(source, name, name_loc) : MissingNode.new(source, location)
@ -214,7 +214,7 @@ module Prism
DEPRECATED: ConstantPathTargetNode#child is deprecated and will be \
removed in the next major version. Use \
ConstantPathTargetNode#name/ConstantPathTargetNode#name_loc instead. \
Called from #{caller(1..1).first}.
Called from #{caller(1, 1)&.first}.
MSG
name ? ConstantReadNode.new(source, name, name_loc) : MissingNode.new(source, location)

Просмотреть файл

@ -149,7 +149,10 @@ module Prism
parent = node.parent
if parent.is_a?(ConstantReadNode) && parent.slice == "Prism"
compile_constant_name(node, node.name)
name = node.name
raise CompilationError, node.inspect if name.nil?
compile_constant_name(node, name)
else
compile_error(node)
end

Просмотреть файл

@ -76,6 +76,43 @@ module Prism
DotVisitor.new.tap { |visitor| accept(visitor) }.to_dot
end
# Returns a list of nodes that are descendants of this node that contain the
# given line and column. This is useful for locating a node that is selected
# based on the line and column of the source code.
#
# Important to note is that the column given to this method should be in
# bytes, as opposed to characters or code units.
def tunnel(line, column)
queue = [self]
result = []
while (node = queue.shift)
result << node
node.compact_child_nodes.each do |child_node|
child_location = child_node.location
start_line = child_location.start_line
end_line = child_location.end_line
if start_line == end_line
if line == start_line && column >= child_location.start_column && column < child_location.end_column
queue << child_node
break
end
elsif (line == start_line && column >= child_location.start_column) || (line == end_line && column < child_location.end_column)
queue << child_node
break
elsif line > start_line && line < end_line
queue << child_node
break
end
end
end
result
end
# Returns a list of the fields that exist for this node class. Fields
# describe the structure of the node. This kind of reflection is useful for
# things like recursively visiting each node _and_ field in the tree.

Просмотреть файл

@ -266,6 +266,25 @@ module Prism
refute_operator parse_expression(complex_source_1), :===, parse_expression(complex_source_2)
end
def test_node_tunnel
program = Prism.parse("foo(1) +\n bar(2, 3) +\n baz(3, 4, 5)").value
tunnel = program.tunnel(1, 4).last
assert_kind_of IntegerNode, tunnel
assert_equal 1, tunnel.value
tunnel = program.tunnel(2, 6).last
assert_kind_of IntegerNode, tunnel
assert_equal 2, tunnel.value
tunnel = program.tunnel(3, 9).last
assert_kind_of IntegerNode, tunnel
assert_equal 4, tunnel.value
tunnel = program.tunnel(3, 8)
assert_equal [ProgramNode, StatementsNode, CallNode, ArgumentsNode, CallNode, ArgumentsNode], tunnel.map(&:class)
end
private
def parse_expression(source)