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.

API:

  • public

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.

API:

  • public



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)

API:

  • public



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

def has_margin
  @has_margin
end

#leading_line_countObject (readonly)

API:

  • public



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

def leading_line_count
  @leading_line_count
end

#leading_offsetObject (readonly)

API:

  • public



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

def leading_offset
  @leading_offset
end

#locatorObject (readonly)

API:

  • public



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

def locator
  @locator
end

#margin_per_lineObject (readonly)

API:

  • public



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

API:

  • public



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

API:

  • public



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

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

#fileObject

API:

  • public



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.

API:

  • public



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