класс Prism::ParseResult::Comments
После разбора исходного кода у нас есть и синтаксическое дерево, и список найденных в исходном коде комментариев. Этот класс отвечает за обход дерева и поиск ближайшего места для прикрепления каждого комментария.
Для этого он сначала находит ближайшие места для каждого комментария. Места могут быть получены либо непосредственно из узлов, либо из полей расположения узлов. Например, у узла класса «ClassNode» есть общее расположение, охватывающее весь класс, но также есть расположение для ключевого слова «class».
После того, как ближайшие места будут найдены, он определяет, к какому из них прикрепить комментарий. Если это заключительный комментарий (комментарий на той же строке, что и другой исходный код), он будет отдавать предпочтение прикреплению к ближайшему расположению, которое находится перед комментарием. В противном случае он будет отдавать предпочтение прикреплению к ближайшему расположению, которое находится после комментария.
Атрибуты
Результат разбора, к которому мы прикрепляем комментарии.
Публичные методы класса
# File lib/prism/parse_result/comments.rb, line 78 def initialize(parse_result) @parse_result = parse_result end
Создать новый объект Comments, который будет прикреплять комментарии к заданному результату разбора.
Публичные методы экземпляра
# File lib/prism/parse_result/comments.rb, line 84
def attach!
parse_result.comments.each do |comment|
preceding, enclosing, following = nearest_targets(parse_result.value, comment)
target =
if comment.trailing?
preceding || following || enclosing || NodeTarget.new(parse_result.value)
else
# If a comment exists on its own line, prefer a leading comment.
following || preceding || enclosing || NodeTarget.new(parse_result.value)
end
target << comment
end
end Прикрепить комментарии к соответствующим местам в дереве, изменяя результат разбора.
Приватные методы экземпляра
# File lib/prism/parse_result/comments.rb, line 103
def nearest_targets(node, comment)
comment_start = comment.location.start_offset
comment_end = comment.location.end_offset
targets = []
node.comment_targets.map do |value|
case value
when StatementsNode
targets.concat(value.body.map { |node| NodeTarget.new(node) })
when Node
targets << NodeTarget.new(value)
when Location
targets << LocationTarget.new(value)
end
end
targets.sort_by!(&:start_offset)
preceding = nil
following = nil
left = 0
right = targets.length
# This is a custom binary search that finds the nearest nodes to the
# given comment. When it finds a node that completely encapsulates the
# comment, it recurses downward into the tree.
while left < right
middle = (left + right) / 2
target = targets[middle]
target_start = target.start_offset
target_end = target.end_offset
if target.encloses?(comment)
# The comment is completely contained by this target. Abandon the
# binary search at this level.
return nearest_targets(target.node, comment)
end
if target_end <= comment_start
# This target falls completely before the comment. Because we will
# never consider this target or any targets before it again, this
# target must be the closest preceding target we have encountered so
# far.
preceding = target
left = middle + 1
next
end
if comment_end <= target_start
# This target falls completely after the comment. Because we will
# never consider this target or any targets after it again, this
# target must be the closest following target we have encountered so
# far.
following = target
right = middle
next
end
# This should only happen if there is a bug in this parser.
raise "Comment location overlaps with a target location"
end
[preceding, NodeTarget.new(node), following]
end Отвечает за поиск ближайших целей для данного комментария в контексте данного узла-оболочки.
Ruby Core © 1993–2022 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.