Class: Puppet::Pops::Parser::Locator::SubLocator

Inherits:
AbstractLocator show all
Defined in:
lib/puppet/pops/parser/locator.rb

Overview

A Sublocator locates a concrete locator (subspace) in a virtual space. The ‘leading_line_count` is the (virtual) number of lines preceding the first line in the concrete locator. The `leading_offset` is the (virtual) byte offset of the first byte in the concrete locator. The `leading_line_offset` is the (virtual) offset / margin in characters for each line.

This illustrates characters in the sublocator (‘.`) inside the subspace (`X`):

1:XXXXXXXX
2:XXXX.... .. ... ..
3:XXXX. . .... ..
4:XXXX............

This sublocator would be configured with leading_line_count = 1, leading_offset=8, and leading_line_offset=4

Note that leading_offset must be the same for all lines and measured in characters.

A SubLocator is only used during parsing as the parser will translate the local offsets/lengths to the parent locator when a sublocated expression is reduced. Do not call the methods ‘char_offset` or `char_length` as those methods will raise an error.

Instance Attribute Summary collapse

Attributes inherited from AbstractLocator

#line_index, #string

Instance Method Summary collapse

Methods inherited from AbstractLocator

#ary_bsearch_i, #eql?, #hash, #line_for_offset, #pos_on_line, #to_location_hash

Methods inherited from Puppet::Pops::Parser::Locator

compute_line_index, #extract_text, #extract_tree_text, #line_for_offset, #line_index, locator, #offset_on_line, #pos_on_line, #string, #to_s, #to_uri

Constructor Details

#initialize(locator, str, leading_line_count, leading_offset, has_margin, margin_per_line) ⇒ SubLocator

Returns a new instance of SubLocator.



227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/puppet/pops/parser/locator.rb', line 227

def initialize(locator, str, leading_line_count, leading_offset, has_margin, margin_per_line)
  super(str, locator.file)
  @locator = locator
  @leading_line_count = leading_line_count
  @leading_offset = leading_offset
  @has_margin = has_margin
  @margin_per_line = margin_per_line

  # Since lines can have different margin - accumulated margin per line must be computed
  # and since this accumulated margin adjustment is needed more than once; both for start offset,
  # and for end offset (to compute global length) it is computed up front here.
  # The accumulated_offset holds the sum of all removed margins before a position on line n (line index is 1-n,
  # and (unused) position 0 is always 0).
  # The last entry is duplicated since there will be  the line "after last line" that would otherwise require
  # conditional logic.
  #
  @accumulated_margin = margin_per_line.each_with_object([0]) { |val, memo| memo << memo[-1] + val; }
  @accumulated_margin << @accumulated_margin[-1]
end

Instance Attribute Details

#has_marginObject (readonly)



224
225
226
# File 'lib/puppet/pops/parser/locator.rb', line 224

def has_margin
  @has_margin
end

#leading_line_countObject (readonly)



222
223
224
# File 'lib/puppet/pops/parser/locator.rb', line 222

def leading_line_count
  @leading_line_count
end

#leading_offsetObject (readonly)



223
224
225
# File 'lib/puppet/pops/parser/locator.rb', line 223

def leading_offset
  @leading_offset
end

#locatorObject (readonly)



221
222
223
# File 'lib/puppet/pops/parser/locator.rb', line 221

def locator
  @locator
end

#margin_per_lineObject (readonly)



225
226
227
# File 'lib/puppet/pops/parser/locator.rb', line 225

def margin_per_line
  @margin_per_line
end

Instance Method Details

#char_length(offset, end_offset) ⇒ Object

Do not call this method



287
288
289
# File 'lib/puppet/pops/parser/locator.rb', line 287

def char_length(offset, end_offset)
  raise "Should not be called"
end

#char_offset(offset) ⇒ Object

Do not call this method



282
283
284
# File 'lib/puppet/pops/parser/locator.rb', line 282

def char_offset(offset)
  raise "Should not be called"
end

#fileObject



247
248
249
# File 'lib/puppet/pops/parser/locator.rb', line 247

def file
  @locator.file
end

#to_global(offset, length) ⇒ Object

Returns array with transposed (local) offset and (local) length. The transposed values take the margin into account such that it is added to the content to the right

Using X to denote margin and where end of line is explicitly shown as n: “‘ XXXXabcn XXXXdefn “` A local offset of 0 is translated to the start of the first heredoc line, and a length of 1 is adjusted to 5 - i.e to cover “XXXXa”. A local offset of 1, with length 1 would cover “b”. A local offset of 4 and length 1 would cover “XXXXd”

It is possible that lines have different margin and that is taken into account.



265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
# File 'lib/puppet/pops/parser/locator.rb', line 265

def to_global(offset, length)
  # simple case, no margin
  return [offset + @leading_offset, length] unless @has_margin

  # compute local start and end line
  start_line = line_for_offset(offset)
  end_line = line_for_offset(offset + length)

  # complex case when there is a margin
  transposed_offset = offset == 0 ? @leading_offset : offset + @leading_offset + @accumulated_margin[start_line]
  transposed_length = length +
                      @accumulated_margin[end_line] - @accumulated_margin[start_line] +    # the margins between start and end (0 is line 1)
                      (offset_on_line(offset) == 0 ? margin_per_line[start_line - 1] : 0)  # include start's margin in position 0
  [transposed_offset, transposed_length]
end