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
-
#skip_directives ⇒ Boolean
Skip file processing directives disguised as comments.
Instance Method Summary collapse
-
#associate ⇒ Hash(Parser::AST::Node, Array(Parser::Source::Comment))
Compute a mapping between AST nodes and comments.
-
#initialize(ast, comments) ⇒ Associator
constructor
A new instance of Associator.
Constructor Details
#initialize(ast, comments) ⇒ Associator
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
#skip_directives ⇒ Boolean
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 |
# 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">] # } # # @return [Hash(Parser::AST::Node, Array(Parser::Source::Comment))] # def associate @mapping = Hash.new { |h, k| h[k] = [] } @comment_num = 0 advance_through_directives if @skip_directives process(nil, @ast) @mapping end private def process(upper_node, node) if node.type == :begin prev_node, next_node = nil, upper_node else while current_comment_between?(prev_node, node) associate_and_advance_comment(node) end prev_node, next_node = nil, upper_node end node.children.each do |child| if child.is_a?(AST::Node) && child.loc && child.loc.expression prev_node, next_node = next_node, child process(prev_node, child) end end end def current_comment @comments[@comment_num] end def advance_comment @comment_num += 1 end def current_comment_between?(prev_node, next_node) return false if current_comment.nil? comment_loc = current_comment.location.expression next_loc = next_node.location.expression if prev_node.nil? comment_loc.end_pos <= next_loc.begin_pos else prev_loc = prev_node.location.expression comment_loc.begin_pos >= prev_loc.end_pos && comment_loc.end_pos <= next_loc.begin_pos end end def associate_and_advance_comment(node) @mapping[node] << 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
#associate ⇒ Hash(Parser::AST::Node, Array(Parser::Source::Comment))
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">]
}
81 82 83 84 85 86 87 88 89 90 |
# File 'lib/parser/source/comment/associator.rb', line 81 def associate @mapping = Hash.new { |h, k| h[k] = [] } @comment_num = 0 advance_through_directives if @skip_directives process(nil, @ast) @mapping end |