Skip to content

Commit 7759acd

Browse files
committed
Rename line_to_byte_offset -> byte_offset
Also, include the column in here. Hopefully we can do some additional optimizations later.
1 parent 93fdf21 commit 7759acd

File tree

5 files changed

+47
-42
lines changed

5 files changed

+47
-42
lines changed

lib/prism/lex_compat.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -816,7 +816,7 @@ def result
816816
# Manually implemented instead of `sort_by!(&:location)` for performance.
817817
tokens.sort_by! do |token|
818818
line, column = token.location
819-
source.line_to_byte_offset(line) + column
819+
source.byte_offset(line, column)
820820
end
821821

822822
# Add :on_sp tokens
@@ -833,8 +833,10 @@ def add_on_sp_tokens(tokens, source, data_loc, bom, eof_token)
833833

834834
tokens.each do |token|
835835
line, column = token.location
836-
start_offset = source.line_to_byte_offset(line) + column
837-
# Ripper reports columns on line 1 without counting the BOM, so we adjust to get the real offset
836+
start_offset = source.byte_offset(line, column)
837+
838+
# Ripper reports columns on line 1 without counting the BOM, so we
839+
# adjust to get the real offset
838840
start_offset += 3 if line == 1 && bom
839841

840842
if start_offset > prev_token_end

lib/prism/parse_result.rb

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,13 @@ def slice(byte_offset, length)
7676
source.byteslice(byte_offset, length) or raise
7777
end
7878

79-
# Converts the line number to a byte offset corresponding to the start of that line
80-
def line_to_byte_offset(line)
81-
l = line - @start_line
82-
if l < 0 || l >= offsets.size
83-
raise ArgumentError, "line #{line} is out of range"
84-
end
85-
offsets[l]
79+
# Converts the line number and column in bytes to a byte offset.
80+
def byte_offset(line, column)
81+
normal = line - @start_line
82+
raise IndexError if normal < 0
83+
offsets.fetch(normal) + column
84+
rescue IndexError
85+
raise ArgumentError, "line #{line} is out of range"
8686
end
8787

8888
# Binary search through the offsets to find the line number for the given

sig/prism/parse_result.rbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ module Prism
1414
def encoding: () -> Encoding
1515
def lines: () -> Array[String]
1616
def slice: (Integer byte_offset, Integer length) -> String
17-
def line_to_byte_offset: (Integer line) -> Integer
17+
def byte_offset: (Integer line, Integer column) -> Integer
1818
def line: (Integer byte_offset) -> Integer
1919
def line_start: (Integer byte_offset) -> Integer
2020
def line_end: (Integer byte_offset) -> Integer

templates/lib/prism/node.rb.erb

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,14 +183,13 @@ module Prism
183183
def tunnel(line, column)
184184
queue = [self] #: Array[Prism::node]
185185
result = [] #: Array[Prism::node]
186-
187-
search_offset = source.line_to_byte_offset(line) + column
186+
offset = source.byte_offset(line, column)
188187

189188
while (node = queue.shift)
190189
result << node
191190

192191
node.each_child_node do |child_node|
193-
if child_node.start_offset <= search_offset && search_offset < child_node.end_offset
192+
if child_node.start_offset <= offset && offset < child_node.end_offset
194193
queue << child_node
195194
break
196195
end

test/prism/ruby/source_test.rb

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,48 @@
44

55
module Prism
66
class SourceTest < TestCase
7-
def test_line_to_byte_offset
8-
parse_result = Prism.parse(<<~SRC)
7+
def test_byte_offset
8+
source = Prism.parse(<<~SRC).source
99
abcd
1010
efgh
1111
ijkl
1212
SRC
13-
source = parse_result.source
14-
15-
assert_equal 0, source.line_to_byte_offset(1)
16-
assert_equal 5, source.line_to_byte_offset(2)
17-
assert_equal 10, source.line_to_byte_offset(3)
18-
assert_equal 15, source.line_to_byte_offset(4)
19-
e = assert_raise(ArgumentError) { source.line_to_byte_offset(5) }
20-
assert_equal "line 5 is out of range", e.message
21-
e = assert_raise(ArgumentError) { source.line_to_byte_offset(0) }
22-
assert_equal "line 0 is out of range", e.message
23-
e = assert_raise(ArgumentError) { source.line_to_byte_offset(-1) }
24-
assert_equal "line -1 is out of range", e.message
13+
14+
assert_equal 0, source.byte_offset(1, 0)
15+
assert_equal 5, source.byte_offset(2, 0)
16+
assert_equal 10, source.byte_offset(3, 0)
17+
assert_equal 15, source.byte_offset(4, 0)
18+
19+
error = assert_raise(ArgumentError) { source.byte_offset(5, 0) }
20+
assert_equal "line 5 is out of range", error.message
21+
22+
error = assert_raise(ArgumentError) { source.byte_offset(0, 0) }
23+
assert_equal "line 0 is out of range", error.message
24+
25+
error = assert_raise(ArgumentError) { source.byte_offset(-1, 0) }
26+
assert_equal "line -1 is out of range", error.message
2527
end
2628

27-
def test_line_to_byte_offset_with_start_line
28-
parse_result = Prism.parse(<<~SRC, line: 11)
29+
def test_byte_offset_with_start_line
30+
source = Prism.parse(<<~SRC, line: 11).source
2931
abcd
3032
efgh
3133
ijkl
3234
SRC
33-
source = parse_result.source
34-
35-
assert_equal 0, source.line_to_byte_offset(11)
36-
assert_equal 5, source.line_to_byte_offset(12)
37-
assert_equal 10, source.line_to_byte_offset(13)
38-
assert_equal 15, source.line_to_byte_offset(14)
39-
e = assert_raise(ArgumentError) { source.line_to_byte_offset(15) }
40-
assert_equal "line 15 is out of range", e.message
41-
e = assert_raise(ArgumentError) { source.line_to_byte_offset(10) }
42-
assert_equal "line 10 is out of range", e.message
43-
e = assert_raise(ArgumentError) { source.line_to_byte_offset(9) }
44-
assert_equal "line 9 is out of range", e.message
35+
36+
assert_equal 0, source.byte_offset(11, 0)
37+
assert_equal 5, source.byte_offset(12, 0)
38+
assert_equal 10, source.byte_offset(13, 0)
39+
assert_equal 15, source.byte_offset(14, 0)
40+
41+
error = assert_raise(ArgumentError) { source.byte_offset(15, 0) }
42+
assert_equal "line 15 is out of range", error.message
43+
44+
error = assert_raise(ArgumentError) { source.byte_offset(10, 0) }
45+
assert_equal "line 10 is out of range", error.message
46+
47+
error = assert_raise(ArgumentError) { source.byte_offset(9, 0) }
48+
assert_equal "line 9 is out of range", error.message
4549
end
4650
end
4751
end

0 commit comments

Comments
 (0)