зеркало из https://github.com/github/ruby.git
[ruby/prism] Prism::Node#tunnel
https://github.com/ruby/prism/commit/0bf5d651da
This commit is contained in:
Родитель
c631679b94
Коммит
7a49edcf1f
|
@ -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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче