Class: Ast::Merge::Comment::CStyleTrackerBase

Inherits:
Object
  • Object
show all
Defined in:
lib/ast/merge/comment/c_style_tracker_base.rb

Overview

Shared base class for C-style comment trackers across the merge family.

This base owns reusable // + /* */ scanning, span-aware lookup for multi-line block comments, shared line-comment region/attachment building, and augmenter integration. It intentionally keeps the current shared tracked-hash adapter boundary: block comments are tracked and queryable, but shared nodes/regions/attachments still expose only line-style comments until a broader block-comment normalization layer exists.

Subclasses may override:

  • #owner_line_num for format-specific owner resolution
  • #inline_comment_candidate? for syntax-specific inline-comment heuristics

The tracked-comment hash shape extends the tracked-hash adapter input with C-style facts such as :block and optional :end_line for multi-line block spans.

Constant Summary collapse

SINGLE_LINE_COMMENT_REGEX =

Matches a full-line single-line C-style comment.

Returns:

  • (Regexp)
%r{\A(?<indent>\s*)//\s?(?<text>.*)\z}
BLOCK_COMMENT_SINGLE_REGEX =

Matches a full-line block comment contained on one line.

Returns:

  • (Regexp)
%r{\A(?<indent>\s*)/\*\s?(?<text>.*?)\s?\*/\s*\z}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(lines) ⇒ CStyleTrackerBase

Returns a new instance of CStyleTrackerBase.

Parameters:

  • lines (Array<String>)

    Source lines (already chomped/split)



35
36
37
38
39
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 35

def initialize(lines)
  @lines = Array(lines)
  @comments = extract_comments
  @comments_by_line = (@comments)
end

Instance Attribute Details

#commentsObject (readonly)

Returns the value of attribute comments.



32
33
34
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 32

def comments
  @comments
end

#linesObject (readonly)

Returns the value of attribute lines.



32
33
34
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 32

def lines
  @lines
end

Instance Method Details

#augment(owners: [], **options) ⇒ Object


Augmenter integration



277
278
279
280
281
282
283
284
285
286
287
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 277

def augment(owners: [], **options)
  Augmenter.new(
    lines: @lines,
    comments: shared_region_comments,
    owners: owners,
    style: :c_style_line,
    total_comment_count: @comments.size,
    block_comment_count: @comments.count { |comment| comment[:block] },
    **options
  )
end

#blank_line?(line_num) ⇒ Boolean

Returns:

  • (Boolean)


257
258
259
260
261
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 257

def blank_line?(line_num)
  return false if line_num < 1 || line_num > @lines.length

  @lines[line_num - 1].to_s.strip.empty?
end

#comment_at(line_num) ⇒ Object


Single-comment lookup



45
46
47
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 45

def comment_at(line_num)
  @comments_by_line[line_num]&.first
end

#comment_attachment_for(owner, line_num: nil, leading_comments: nil, inline_comment: nil, trailing_comments: nil, **metadata) ⇒ Object


Attachment building



222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 222

def comment_attachment_for(owner, line_num: nil, leading_comments: nil, inline_comment: nil,
                           trailing_comments: nil, **)
  resolved_line_num = line_num || owner_line_num(owner)
  resolved_end_line = owner_end_line(owner) || resolved_line_num
  leading_region = if resolved_line_num
                     leading_comment_region_before(resolved_line_num, comments: leading_comments)
                   end
  inline_region = (inline_comment_region_at(resolved_line_num, comment: inline_comment) if resolved_line_num)
  trailing_region = if resolved_end_line
                      trailing_comment_region_after(resolved_end_line, comments: trailing_comments,
                                                                       owner: owner)
                    end

  Attachment.new(
    owner: owner,
    leading_region: leading_region,
    inline_region: inline_region,
    trailing_region: trailing_region,
    metadata: .merge(
      line_num: resolved_line_num,
      end_line: resolved_end_line,
      source: :comment_tracker
    )
  )
end

#comment_node_at(line_num) ⇒ Comment::Line?

Return the normalized shared comment node at a line.

Parameters:

  • line_num (Integer)

    1-based line number

Returns:



60
61
62
63
64
65
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 60

def comment_node_at(line_num)
  comment = comment_at(line_num)
  return unless comment && shared_region_comment?(comment)

  build_comment_node(comment)
end

#comment_nodesArray<Comment::Line>

Return all normalized shared comment nodes eligible for region building.

Returns:



52
53
54
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 52

def comment_nodes
  @comment_nodes ||= shared_region_comments.map { |comment| build_comment_node(comment) }
end

#comment_region_for_range(range, kind:, full_line_only: false) ⇒ Region

Build a normalized region from comments intersecting a line range.

Parameters:

  • range (Range)

    1-based line range

  • kind (Symbol)

    region ownership kind

  • full_line_only (Boolean) (defaults to: false)

    whether to keep only full-line comments

Returns:



83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 83

def comment_region_for_range(range, kind:, full_line_only: false)
  selected = comments_in_range(range).select { |comment| shared_region_comment?(comment) }
  selected = selected.select { |comment| comment[:full_line] } if full_line_only

  build_region(
    kind: kind,
    comments: selected,
    metadata: {
      range: range,
      full_line_only: full_line_only,
      source: :comment_tracker
    }
  )
end

#comments_in_range(range) ⇒ Object


Range queries



71
72
73
74
75
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 71

def comments_in_range(range)
  @comments.select do |comment|
    range.begin <= comment_end_line(comment) && range.end >= comment_start_line(comment)
  end
end

#full_line_comment?(line_num) ⇒ Boolean


Line utilities

Returns:

  • (Boolean)


252
253
254
255
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 252

def full_line_comment?(line_num)
  comment = comment_at(line_num)
  comment&.dig(:full_line) || false
end

#inline_comment_at(line_num) ⇒ Hash?

Return the inline comment tracked on a line.

Parameters:

  • line_num (Integer)

    1-based line number

Returns:

  • (Hash, nil)


143
144
145
146
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 143

def inline_comment_at(line_num)
  comment = comment_at(line_num)
  comment if comment && !comment[:full_line]
end

#inline_comment_region_at(line_num, comment: nil) ⇒ Region?

Return the normalized inline region for a single line.

Parameters:

  • line_num (Integer)

    1-based line number

  • comment (Hash, nil) (defaults to: nil)

    optional preselected inline comment

Returns:



153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 153

def inline_comment_region_at(line_num, comment: nil)
  selected = [comment || inline_comment_at(line_num)].compact.select { |item| shared_region_comment?(item) }
  return if selected.empty?

  build_region(
    kind: :inline,
    comments: selected,
    metadata: {
      line_num: line_num,
      source: :comment_tracker
    }
  )
end

#leading_comment_region_before(line_num, comments: nil) ⇒ Region?

Return the normalized leading comment region before a line.

Parameters:

  • line_num (Integer)

    owner line number

  • comments (Array<Hash>, nil) (defaults to: nil)

    optional preselected comments

Returns:



124
125
126
127
128
129
130
131
132
133
134
135
136
137
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 124

def leading_comment_region_before(line_num, comments: nil)
  selected = comments || leading_comments_before(line_num)
  selected = selected.select { |comment| comment[:full_line] && shared_region_comment?(comment) }
  return if selected.empty?

  build_region(
    kind: :leading,
    comments: selected,
    metadata: {
      line_num: line_num,
      source: :comment_tracker
    }
  )
end

#leading_comments_before(line_num) ⇒ Object


Leading / inline comment helpers



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 102

def leading_comments_before(line_num)
  leading = []
  current = line_num - 1
  current -= 1 while current >= 1 && blank_line?(current)

  while current >= 1
    comment = comment_at(current)
    break unless comment && comment[:full_line]

    leading.unshift(comment)
    current = comment_start_line(comment) - 1
    current -= 1 while current >= 1 && blank_line?(current)
  end

  leading
end

#line_at(line_num) ⇒ String?

Return the raw source line at a 1-based line number.

Parameters:

  • line_num (Integer)

    1-based line number

Returns:

  • (String, nil)


267
268
269
270
271
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 267

def line_at(line_num)
  return if line_num < 1 || line_num > @lines.length

  @lines[line_num - 1]
end

#trailing_comment_region_after(line_num, upper_bound: nil, comments: nil, owner: nil) ⇒ Region?

Return the normalized trailing region after an owner span.

Parameters:

  • line_num (Integer)

    1-based end line of the owner

  • upper_bound (Integer, nil) (defaults to: nil)

    exclusive upper bound before the next owner

  • comments (Array<Hash>, nil) (defaults to: nil)

    optional preselected trailing comments

Returns:



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 202

def trailing_comment_region_after(line_num, upper_bound: nil, comments: nil, owner: nil)
  selected = comments || trailing_comments_after(line_num, upper_bound: upper_bound, owner: owner)
  selected = selected.select { |comment| comment[:full_line] && shared_region_comment?(comment) }
  return if selected.empty?

  build_region(
    kind: :trailing,
    comments: selected,
    metadata: {
      line_num: line_num,
      upper_bound: upper_bound,
      source: :comment_tracker
    }
  )
end

#trailing_comments_after(line_num, upper_bound: nil, owner: nil) ⇒ Array<Hash>

Return adjacent full-line trailing line comments after an owner span.

The first trailing comment must begin immediately after the owner. Blank lines are only preserved between later trailing comments, not between the owner and the first trailing comment.

Parameters:

  • line_num (Integer)

    1-based end line of the owner

  • upper_bound (Integer, nil) (defaults to: nil)

    exclusive upper bound before the next owner

Returns:

  • (Array<Hash>)


176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/ast/merge/comment/c_style_tracker_base.rb', line 176

def trailing_comments_after(line_num, upper_bound: nil, owner: nil)
  trailing = []
  current = line_num + 1
  max_line = upper_bound ? upper_bound - 1 : @lines.length
  return trailing if current > max_line || blank_line?(current)

  while current <= max_line
    comment = comment_at(current)
    break unless comment && comment[:full_line] && shared_region_comment?(comment) && trailing_comment_owned_by?(
      comment, owner
    )

    trailing << comment
    current = comment_end_line(comment) + 1
    current += 1 while current <= max_line && blank_line?(current)
  end

  trailing
end