summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Newton <kddnewton@gmail.com>2026-01-27 14:55:09 -0500
committergit <svn-admin@ruby-lang.org>2026-01-27 20:06:22 +0000
commitc983b7aee631db46002ba7438089d792c2b0298b (patch)
tree5cf1863fad7e37daac12a1f7b625f141de61f435
parent39b28e67a6363f9ffe1f478298984414083c96d4 (diff)
[ruby/prism] Rename line_to_byte_offset -> byte_offset
Also, include the column in here. Hopefully we can do some additional optimizations later. https://github.com/ruby/prism/commit/7759acdd26
-rw-r--r--lib/prism/lex_compat.rb8
-rw-r--r--lib/prism/parse_result.rb14
-rw-r--r--prism/templates/lib/prism/node.rb.erb5
-rw-r--r--test/prism/ruby/source_test.rb60
4 files changed, 46 insertions, 41 deletions
diff --git a/lib/prism/lex_compat.rb b/lib/prism/lex_compat.rb
index 523ad39586..4960230bcf 100644
--- a/lib/prism/lex_compat.rb
+++ b/lib/prism/lex_compat.rb
@@ -816,7 +816,7 @@ module Prism
# Manually implemented instead of `sort_by!(&:location)` for performance.
tokens.sort_by! do |token|
line, column = token.location
- source.line_to_byte_offset(line) + column
+ source.byte_offset(line, column)
end
# Add :on_sp tokens
@@ -833,8 +833,10 @@ module Prism
tokens.each do |token|
line, column = token.location
- start_offset = source.line_to_byte_offset(line) + column
- # Ripper reports columns on line 1 without counting the BOM, so we adjust to get the real offset
+ start_offset = source.byte_offset(line, column)
+
+ # Ripper reports columns on line 1 without counting the BOM, so we
+ # adjust to get the real offset
start_offset += 3 if line == 1 && bom
if start_offset > prev_token_end
diff --git a/lib/prism/parse_result.rb b/lib/prism/parse_result.rb
index 12d19da562..be1c13f97c 100644
--- a/lib/prism/parse_result.rb
+++ b/lib/prism/parse_result.rb
@@ -76,13 +76,13 @@ module Prism
source.byteslice(byte_offset, length) or raise
end
- # Converts the line number to a byte offset corresponding to the start of that line
- def line_to_byte_offset(line)
- l = line - @start_line
- if l < 0 || l >= offsets.size
- raise ArgumentError, "line #{line} is out of range"
- end
- offsets[l]
+ # Converts the line number and column in bytes to a byte offset.
+ def byte_offset(line, column)
+ normal = line - @start_line
+ raise IndexError if normal < 0
+ offsets.fetch(normal) + column
+ rescue IndexError
+ raise ArgumentError, "line #{line} is out of range"
end
# Binary search through the offsets to find the line number for the given
diff --git a/prism/templates/lib/prism/node.rb.erb b/prism/templates/lib/prism/node.rb.erb
index 8225bfb328..6f8e8b0acc 100644
--- a/prism/templates/lib/prism/node.rb.erb
+++ b/prism/templates/lib/prism/node.rb.erb
@@ -183,14 +183,13 @@ module Prism
def tunnel(line, column)
queue = [self] #: Array[Prism::node]
result = [] #: Array[Prism::node]
-
- search_offset = source.line_to_byte_offset(line) + column
+ offset = source.byte_offset(line, column)
while (node = queue.shift)
result << node
node.each_child_node do |child_node|
- if child_node.start_offset <= search_offset && search_offset < child_node.end_offset
+ if child_node.start_offset <= offset && offset < child_node.end_offset
queue << child_node
break
end
diff --git a/test/prism/ruby/source_test.rb b/test/prism/ruby/source_test.rb
index afd2825765..f7cf4fe83a 100644
--- a/test/prism/ruby/source_test.rb
+++ b/test/prism/ruby/source_test.rb
@@ -4,44 +4,48 @@ require_relative "../test_helper"
module Prism
class SourceTest < TestCase
- def test_line_to_byte_offset
- parse_result = Prism.parse(<<~SRC)
+ def test_byte_offset
+ source = Prism.parse(<<~SRC).source
abcd
efgh
ijkl
SRC
- source = parse_result.source
-
- assert_equal 0, source.line_to_byte_offset(1)
- assert_equal 5, source.line_to_byte_offset(2)
- assert_equal 10, source.line_to_byte_offset(3)
- assert_equal 15, source.line_to_byte_offset(4)
- e = assert_raise(ArgumentError) { source.line_to_byte_offset(5) }
- assert_equal "line 5 is out of range", e.message
- e = assert_raise(ArgumentError) { source.line_to_byte_offset(0) }
- assert_equal "line 0 is out of range", e.message
- e = assert_raise(ArgumentError) { source.line_to_byte_offset(-1) }
- assert_equal "line -1 is out of range", e.message
+
+ assert_equal 0, source.byte_offset(1, 0)
+ assert_equal 5, source.byte_offset(2, 0)
+ assert_equal 10, source.byte_offset(3, 0)
+ assert_equal 15, source.byte_offset(4, 0)
+
+ error = assert_raise(ArgumentError) { source.byte_offset(5, 0) }
+ assert_equal "line 5 is out of range", error.message
+
+ error = assert_raise(ArgumentError) { source.byte_offset(0, 0) }
+ assert_equal "line 0 is out of range", error.message
+
+ error = assert_raise(ArgumentError) { source.byte_offset(-1, 0) }
+ assert_equal "line -1 is out of range", error.message
end
- def test_line_to_byte_offset_with_start_line
- parse_result = Prism.parse(<<~SRC, line: 11)
+ def test_byte_offset_with_start_line
+ source = Prism.parse(<<~SRC, line: 11).source
abcd
efgh
ijkl
SRC
- source = parse_result.source
-
- assert_equal 0, source.line_to_byte_offset(11)
- assert_equal 5, source.line_to_byte_offset(12)
- assert_equal 10, source.line_to_byte_offset(13)
- assert_equal 15, source.line_to_byte_offset(14)
- e = assert_raise(ArgumentError) { source.line_to_byte_offset(15) }
- assert_equal "line 15 is out of range", e.message
- e = assert_raise(ArgumentError) { source.line_to_byte_offset(10) }
- assert_equal "line 10 is out of range", e.message
- e = assert_raise(ArgumentError) { source.line_to_byte_offset(9) }
- assert_equal "line 9 is out of range", e.message
+
+ assert_equal 0, source.byte_offset(11, 0)
+ assert_equal 5, source.byte_offset(12, 0)
+ assert_equal 10, source.byte_offset(13, 0)
+ assert_equal 15, source.byte_offset(14, 0)
+
+ error = assert_raise(ArgumentError) { source.byte_offset(15, 0) }
+ assert_equal "line 15 is out of range", error.message
+
+ error = assert_raise(ArgumentError) { source.byte_offset(10, 0) }
+ assert_equal "line 10 is out of range", error.message
+
+ error = assert_raise(ArgumentError) { source.byte_offset(9, 0) }
+ assert_equal "line 9 is out of range", error.message
end
end
end