Class: Parser::Source::Comment::Associator
- Inherits:
-
Object
- Object
- Parser::Source::Comment::Associator
- Defined in:
- lib/parser/source/comment/associator.rb
Overview
A processor which associates AST nodes with comments based on their location in source code. It may be used, for example, to implement rdoc-style processing.
Instance Attribute Summary (collapse)
-
- (Boolean) skip_directives
Skip file processing directives disguised as comments.
Instance Method Summary (collapse)
-
- (Hash(Parser::AST::Node, Array(Parser::Source::Comment))) associate
deprecated
Deprecated.
Use associate_locations.
-
- (Hash(Parser::Source::Map, Array(Parser::Source::Comment))) associate_locations
Same as associate, but uses
node.loc
instead ofnode
as the hash key, thus producing an unambiguous result even in presence of equal nodes. -
- (Associator) initialize(ast, comments)
constructor
A new instance of Associator.
Constructor Details
- (Associator) initialize(ast, comments)
Returns a new instance of Associator
49 50 51 52 53 54 |
# File 'lib/parser/source/comment/associator.rb', line 49 def initialize(ast, comments) @ast = ast @comments = comments @skip_directives = true end |
Instance Attribute Details
- (Boolean) skip_directives
Skip file processing directives disguised as comments. Namely:
- Shebang line,
- Magic encoding comment.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/parser/source/comment/associator.rb', line 43 class Comment::Associator attr_accessor :skip_directives ## # @param [Parser::AST::Node] ast # @param [Array(Parser::Source::Comment)] comments def initialize(ast, comments) @ast = ast @comments = comments @skip_directives = true end ## # Compute a mapping between AST nodes and comments. # # A comment belongs to a certain node if it begins after end # of the previous node (if one exists) and ends before beginning of # the current node. # # This rule is unambiguous and produces the result # one could reasonably expect; for example, this code # # # foo # hoge # bar # + fuga # # will result in the following association: # # { # (send (lvar :hoge) :+ (lvar :fuga)) => # [#<Parser::Source::Comment (string):2:1 "# foo">], # (lvar :fuga) => # [#<Parser::Source::Comment (string):3:8 "# bar">] # } # # Note that {associate} produces unexpected result for nodes which are # equal but have distinct locations; comments for these nodes are merged. # # @return [Hash(Parser::AST::Node, Array(Parser::Source::Comment))] # @deprecated Use {associate_locations}. # def associate @map_using_locations = false do_associate end ## # Same as {associate}, but uses `node.loc` instead of `node` as # the hash key, thus producing an unambiguous result even in presence # of equal nodes. # # @return [Hash(Parser::Source::Map, Array(Parser::Source::Comment))] # def associate_locations @map_using_locations = true do_associate end private def do_associate @mapping = Hash.new { |h, k| h[k] = [] } @comment_num = -1 advance_comment advance_through_directives if @skip_directives @prev_node = nil visit(@ast) @mapping end def visit(node) process_node(node) if node.children.length > 0 node.children.each do |child| next unless child.is_a?(AST::Node) && child.loc && child.loc.expression visit(child) end process_trailing_comments(node) @prev_node = node end end def process_node(node) return unless node.type != :begin while current_comment_between?(@prev_node, node) associate_and_advance_comment(@prev_node, node) end @prev_node = node end def process_trailing_comments(parent) while current_comment_decorates?(@prev_node) associate_and_advance_comment(@prev_node, nil) end while current_comment_before_end?(parent) associate_and_advance_comment(@prev_node, nil) end end def advance_comment @comment_num += 1 @current_comment = @comments[@comment_num] end def current_comment_between?(prev_node, next_node) return false if !@current_comment comment_loc = @current_comment.location.expression if next_node next_loc = next_node.location.expression return false if comment_loc.end_pos > next_loc.begin_pos end if prev_node prev_loc = prev_node.location.expression return false if comment_loc.begin_pos < prev_loc.begin_pos end true end def current_comment_decorates?(prev_node) return false if !@current_comment @current_comment.location.line == prev_node.location.line end def current_comment_before_end?(parent) return false if !@current_comment comment_loc = @current_comment.location.expression parent_loc = parent.location.expression comment_loc.end_pos <= parent_loc.end_pos end def associate_and_advance_comment(prev_node, node) if prev_node && node owner_node = (@current_comment.location.line == prev_node.location.line) ? prev_node : node else owner_node = prev_node ? prev_node : node end key = @map_using_locations ? owner_node.location : owner_node @mapping[key] << @current_comment advance_comment end def advance_through_directives # Skip shebang. if @current_comment && @current_comment.text =~ /^#!/ advance_comment end # Skip encoding line. if @current_comment && @current_comment.text =~ Buffer::ENCODING_RE advance_comment end end end |
Instance Method Details
- (Hash(Parser::AST::Node, Array(Parser::Source::Comment))) associate
Compute a mapping between AST nodes and comments.
A comment belongs to a certain node if it begins after end of the previous node (if one exists) and ends before beginning of the current node.
This rule is unambiguous and produces the result one could reasonably expect; for example, this code
# foo
hoge # bar
+ fuga
will result in the following association:
{
(send (lvar :hoge) :+ (lvar :fuga)) =>
[#<Parser::Source::Comment (string):2:1 "# foo">],
(lvar :fuga) =>
[#<Parser::Source::Comment (string):3:8 "# bar">]
}
Note that Parser::Source::Comment.associate produces unexpected result for nodes which are equal but have distinct locations; comments for these nodes are merged.
85 86 87 88 |
# File 'lib/parser/source/comment/associator.rb', line 85 def associate @map_using_locations = false do_associate end |
- (Hash(Parser::Source::Map, Array(Parser::Source::Comment))) associate_locations
Same as Parser::Source::Comment.associate, but uses node.loc
instead of node
as
the hash key, thus producing an unambiguous result even in presence
of equal nodes.
97 98 99 100 |
# File 'lib/parser/source/comment/associator.rb', line 97 def associate_locations @map_using_locations = true do_associate end |