class Prism::ParseResult::Comments
当我们解析完源代码后,我们会同时得到语法树和在源代码中找到的注释列表。此类负责遍历语法树并找到每个注释应该附加到的最近位置。
它是通过首先为每个注释找到最近的位置来完成的。位置可以来自节点本身,也可以来自节点上的位置字段。例如,一个 ClassNode 有一个包含整个类的整体位置,但也有一个表示 class 关键字的位置。
一旦找到最近的位置,它就会决定附加到哪个位置。如果它是行尾注释(与源代码在同一行的注释),它将倾向于附加到位于注释之前的最近位置。否则,它将倾向于附加到位于注释之后的最近位置。
属性
我们要为其附加注释的解析结果。
Public Class Methods
Source
# File lib/prism/parse_result/comments.rb, line 87 def initialize(parse_result) @parse_result = parse_result end
创建一个新的 Comments 对象,它将把注释附加到给定的解析结果中。
Public Instance Methods
Source
# File lib/prism/parse_result/comments.rb, line 93 def attach! parse_result.comments.each do |comment| preceding, enclosing, following = nearest_targets(parse_result.value, comment) if comment.trailing? if preceding preceding.trailing_comment(comment) else (following || enclosing || NodeTarget.new(parse_result.value)).leading_comment(comment) end else # If a comment exists on its own line, prefer a leading comment. if following following.leading_comment(comment) elsif preceding preceding.trailing_comment(comment) else (enclosing || NodeTarget.new(parse_result.value)).leading_comment(comment) end end end end
通过修改解析结果,将注释附加到树中的相应位置。
私有实例方法
Source
# File lib/prism/parse_result/comments.rb, line 120 def nearest_targets(node, comment) comment_start = comment.location.start_offset comment_end = comment.location.end_offset targets = [] #: Array[_Target] 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 #: _Target? following = nil #: _Target? 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) # @type var target: NodeTarget # 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
负责在给定封装节点的情况下,为给定注释查找最近的目标。