Skip to content

Commit 14259a5

Browse files
committed
Move parser comment handling to shared visitor
1 parent 60e7988 commit 14259a5

1 file changed

Lines changed: 77 additions & 73 deletions

File tree

lib/rbi/parser.rb

Lines changed: 77 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -112,12 +112,13 @@ def parse(source, file:)
112112
end
113113

114114
class Visitor < Prism::Visitor
115-
#: (String source, file: String) -> void
116-
def initialize(source, file:)
115+
#: (String source, file: String, ?comments_by_line: Hash[Integer, Prism::Comment]?) -> void
116+
def initialize(source, file:, comments_by_line: nil)
117117
super()
118118

119119
@source = source
120120
@file = file
121+
@comments_by_line = comments_by_line || {} #: Hash[Integer, Prism::Comment]
121122
end
122123

123124
private
@@ -159,6 +160,75 @@ def self?(node)
159160
def t_sig_without_runtime?(node)
160161
!!(node.is_a?(Prism::ConstantPathNode) && node_string(node) =~ /(::)?T::Sig::WithoutRuntime/)
161162
end
163+
164+
#: (Prism::Node node) -> Array[Comment]
165+
def node_comments(node)
166+
comments = []
167+
168+
start_line = node.location.start_line
169+
start_line -= 1 unless @comments_by_line.key?(start_line)
170+
171+
rbs_continuation = [] #: Array[Prism::Comment]
172+
173+
start_line.downto(1) do |line|
174+
comment = @comments_by_line[line]
175+
break unless comment
176+
177+
text = comment.location.slice
178+
179+
# If we find a RBS comment continuation `#|`, we store it until we find the start with `#:`
180+
if text.start_with?("#|")
181+
rbs_continuation << comment
182+
@comments_by_line.delete(line)
183+
next
184+
end
185+
186+
loc = Loc.from_prism(@file, comment.location)
187+
188+
# If we find the start of a RBS comment, we create a new RBSComment
189+
# Note that we ignore RDoc directives such as `:nodoc:`
190+
# See https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Directives
191+
if text.start_with?("#:") && !(text =~ /^#:[a-z_]+:/)
192+
text = text.sub(/^#: ?/, "").rstrip
193+
194+
# If we found continuation comments, we merge them in reverse order (since we go from bottom to top)
195+
rbs_continuation.reverse_each do |rbs_comment|
196+
continuation_text = rbs_comment.location.slice.sub(/^#\| ?/, "").strip
197+
continuation_loc = Loc.from_prism(@file, rbs_comment.location)
198+
loc = loc.join(continuation_loc)
199+
text = "#{text}#{continuation_text}"
200+
end
201+
202+
rbs_continuation.clear
203+
comments.unshift(RBSComment.new(text, loc: loc))
204+
else
205+
# If we have unused continuation comments, we should inject them back to not lose them
206+
rbs_continuation.each do |rbs_comment|
207+
comments.unshift(parse_comment(rbs_comment))
208+
end
209+
210+
rbs_continuation.clear
211+
comments.unshift(parse_comment(comment))
212+
end
213+
214+
@comments_by_line.delete(line)
215+
end
216+
217+
# If we have unused continuation comments, we should inject them back to not lose them
218+
rbs_continuation.each do |rbs_comment|
219+
comments.unshift(parse_comment(rbs_comment))
220+
end
221+
rbs_continuation.clear
222+
223+
comments
224+
end
225+
226+
#: (Prism::Comment node) -> Comment
227+
def parse_comment(node)
228+
text = node.location.slice.sub(/^# ?/, "").rstrip
229+
loc = Loc.from_prism(@file, node.location)
230+
Comment.new(text, loc: loc)
231+
end
162232
end
163233

164234
class TreeBuilder < Visitor
@@ -170,9 +240,12 @@ class TreeBuilder < Visitor
170240

171241
#: (String source, comments: Array[Prism::Comment], file: String) -> void
172242
def initialize(source, comments:, file:)
173-
super(source, file: file)
243+
super(
244+
source,
245+
comments_by_line: comments.to_h { |c| [c.location.start_line, c] },
246+
file: file,
247+
)
174248

175-
@comments_by_line = comments.to_h { |c| [c.location.start_line, c] } #: Hash[Integer, Prism::Comment]
176249
@tree = Tree.new #: Tree
177250

178251
@scopes_stack = [@tree] #: Array[Tree]
@@ -600,75 +673,6 @@ def detach_comments_from_sigs(sigs)
600673
comments
601674
end
602675

603-
#: (Prism::Node node) -> Array[Comment]
604-
def node_comments(node)
605-
comments = []
606-
607-
start_line = node.location.start_line
608-
start_line -= 1 unless @comments_by_line.key?(start_line)
609-
610-
rbs_continuation = [] #: Array[Prism::Comment]
611-
612-
start_line.downto(1) do |line|
613-
comment = @comments_by_line[line]
614-
break unless comment
615-
616-
text = comment.location.slice
617-
618-
# If we find a RBS comment continuation `#|`, we store it until we find the start with `#:`
619-
if text.start_with?("#|")
620-
rbs_continuation << comment
621-
@comments_by_line.delete(line)
622-
next
623-
end
624-
625-
loc = Loc.from_prism(@file, comment.location)
626-
627-
# If we find the start of a RBS comment, we create a new RBSComment
628-
# Note that we ignore RDoc directives such as `:nodoc:`
629-
# See https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Directives
630-
if text.start_with?("#:") && !(text =~ /^#:[a-z_]+:/)
631-
text = text.sub(/^#: ?/, "").rstrip
632-
633-
# If we found continuation comments, we merge them in reverse order (since we go from bottom to top)
634-
rbs_continuation.reverse_each do |rbs_comment|
635-
continuation_text = rbs_comment.location.slice.sub(/^#\| ?/, "").strip
636-
continuation_loc = Loc.from_prism(@file, rbs_comment.location)
637-
loc = loc.join(continuation_loc)
638-
text = "#{text}#{continuation_text}"
639-
end
640-
641-
rbs_continuation.clear
642-
comments.unshift(RBSComment.new(text, loc: loc))
643-
else
644-
# If we have unused continuation comments, we should inject them back to not lose them
645-
rbs_continuation.each do |rbs_comment|
646-
comments.unshift(parse_comment(rbs_comment))
647-
end
648-
649-
rbs_continuation.clear
650-
comments.unshift(parse_comment(comment))
651-
end
652-
653-
@comments_by_line.delete(line)
654-
end
655-
656-
# If we have unused continuation comments, we should inject them back to not lose them
657-
rbs_continuation.each do |rbs_comment|
658-
comments.unshift(parse_comment(rbs_comment))
659-
end
660-
rbs_continuation.clear
661-
662-
comments
663-
end
664-
665-
#: (Prism::Comment node) -> Comment
666-
def parse_comment(node)
667-
text = node.location.slice.sub(/^# ?/, "").rstrip
668-
loc = Loc.from_prism(@file, node.location)
669-
Comment.new(text, loc: loc)
670-
end
671-
672676
#: (Prism::Node? node) -> Array[Arg]
673677
def parse_send_args(node)
674678
args = [] #: Array[Arg]

0 commit comments

Comments
 (0)