Skip to content

Commit 08ec768

Browse files
committed
Split up comments between leading and trailing
Also make them lazy to allocate the array, and also expose ParseResult#encoding.
1 parent f692feb commit 08ec768

File tree

3 files changed

+73
-18
lines changed

3 files changed

+73
-18
lines changed

lib/prism/parse_result.rb

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@ def initialize(source, start_line = 1, offsets = [])
2121
@offsets = offsets # set after parsing is done
2222
end
2323

24+
# Returns the encoding of the source code, which is set by parameters to the
25+
# parser or by the encoding magic comment.
26+
def encoding
27+
source.encoding
28+
end
29+
2430
# Perform a byteslice on the source code using the given byte offset and
2531
# byte length.
2632
def slice(byte_offset, length)
@@ -108,16 +114,46 @@ class Location
108114
# The length of this location in bytes.
109115
attr_reader :length
110116

111-
# The list of comments attached to this location
112-
attr_reader :comments
113-
114117
# Create a new location object with the given source, start byte offset, and
115118
# byte length.
116119
def initialize(source, start_offset, length)
117120
@source = source
118121
@start_offset = start_offset
119122
@length = length
120-
@comments = []
123+
124+
# These are used to store comments that are associated with this location.
125+
# They are initialized to `nil` to save on memory when there are no
126+
# comments to be attached and/or the comment-related APIs are not used.
127+
@leading_comments = nil
128+
@trailing_comments = nil
129+
end
130+
131+
# These are the comments that are associated with this location that exist
132+
# before the start of this location.
133+
def leading_comments
134+
@leading_comments ||= []
135+
end
136+
137+
# Attach a comment to the leading comments of this location.
138+
def leading_comment(comment)
139+
leading_comments << comment
140+
end
141+
142+
# These are the comments that are associated with this location that exist
143+
# after the end of this location.
144+
def trailing_comments
145+
@trailing_comments ||= []
146+
end
147+
148+
# Attach a comment to the trailing comments of this location.
149+
def trailing_comment(comment)
150+
trailing_comments << comment
151+
end
152+
153+
# Returns all comments that are associated with this location (both leading
154+
# and trailing comments).
155+
def comments
156+
(@leading_comments || []).concat(@trailing_comments || [])
121157
end
122158

123159
# Create a new location object with the given options.
@@ -268,6 +304,11 @@ def initialize(location)
268304
def deconstruct_keys(keys)
269305
{ location: location }
270306
end
307+
308+
# Returns the content of the comment by slicing it from the source code.
309+
def slice
310+
location.slice
311+
end
271312
end
272313

273314
# InlineComment objects are the most common. They correspond to comments in
@@ -437,6 +478,11 @@ def deconstruct_keys(keys)
437478
{ value: value, comments: comments, magic_comments: magic_comments, data_loc: data_loc, errors: errors, warnings: warnings }
438479
end
439480

481+
# Returns the encoding of the source code that was parsed.
482+
def encoding
483+
source.encoding
484+
end
485+
440486
# Returns true if there were no errors during parsing and false if there
441487
# were.
442488
def success?

lib/prism/parse_result/comments.rb

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,12 @@ def encloses?(comment)
3939
comment.location.end_offset <= end_offset
4040
end
4141

42-
def <<(comment)
43-
node.location.comments << comment
42+
def leading_comment(comment)
43+
node.location.leading_comment(comment)
44+
end
45+
46+
def trailing_comment(comment)
47+
node.location.trailing_comment(comment)
4448
end
4549
end
4650

@@ -65,8 +69,12 @@ def encloses?(comment)
6569
false
6670
end
6771

68-
def <<(comment)
69-
location.comments << comment
72+
def leading_comment(comment)
73+
location.leading_comment(comment)
74+
end
75+
76+
def trailing_comment(comment)
77+
location.trailing_comment(comment)
7078
end
7179
end
7280

@@ -84,15 +92,16 @@ def initialize(parse_result)
8492
def attach!
8593
parse_result.comments.each do |comment|
8694
preceding, enclosing, following = nearest_targets(parse_result.value, comment)
87-
target =
88-
if comment.trailing?
89-
preceding || following || enclosing || NodeTarget.new(parse_result.value)
90-
else
91-
# If a comment exists on its own line, prefer a leading comment.
92-
following || preceding || enclosing || NodeTarget.new(parse_result.value)
93-
end
94-
95-
target << comment
95+
96+
if comment.trailing?
97+
preceding&.trailing_comment(comment) ||
98+
(following || enclosing || NodeTarget.new(parse_result.value)).leading_comment(comment)
99+
else
100+
# If a comment exists on its own line, prefer a leading comment.
101+
following&.leading_comment(comment) ||
102+
preceding&.trailing_comment(comment) ||
103+
(enclosing || NodeTarget.new(parse_result.value)).leading_comment(comment)
104+
end
96105
end
97106
end
98107

test/prism/magic_comment_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class MagicCommentTest < TestCase
3030

3131
def assert_magic_comment(example)
3232
expected = Ripper.new(example).tap(&:parse).encoding
33-
actual = Prism.parse(example).source.source.encoding
33+
actual = Prism.parse(example).encoding
3434
assert_equal expected, actual
3535
end
3636
end

0 commit comments

Comments
 (0)