Class: Parslet::Source::LineCache

Inherits:
Object
  • Object
show all
Defined in:
lib/parslet/source/line_cache.rb

Overview

A cache for line start positions.

Instance Method Summary collapse

Constructor Details

#initializeLineCache

Returns a new instance of LineCache.


7
8
9
10
11
12
13
14
# File 'lib/parslet/source/line_cache.rb', line 7

def initialize
  # Stores line endings as a simple position number. The first line always
  # starts at 0; numbers beyond the biggest entry are on any line > size, 
  # but probably make a scan to that position neccessary.
  @line_ends = []
  @line_ends.extend RangeSearch
  @last_line_end = nil
end

Instance Method Details

#line_and_column(pos) ⇒ Object

Returns a <line, column> tuple for the given input position. Input position must be given as byte offset into original string.


19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/parslet/source/line_cache.rb', line 19

def line_and_column(pos)
  pos = pos.bytepos if pos.respond_to? :bytepos
  eol_idx = @line_ends.lbound(pos)

  if eol_idx
    # eol_idx points to the offset that ends the current line.
    # Let's try to find the offset that starts it: 
    offset = eol_idx>0 && @line_ends[eol_idx-1] || 0
    return [eol_idx+1, pos-offset+1]
  else
    # eol_idx is nil, that means that we're beyond the last line end that
    # we know about. Pretend for now that we're just on the last line.
    offset = @line_ends.last || 0
    return [@line_ends.size+1, pos-offset+1]
  end
end

#scan_for_line_endings(start_pos, buf) ⇒ Object


36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/parslet/source/line_cache.rb', line 36

def scan_for_line_endings(start_pos, buf)
  return unless buf

  buf = StringScanner.new(buf)
  return unless buf.exist?(/\n/)

  ## If we have already read part or all of buf, we already know about
  ## line ends in that portion. remove it and correct cur (search index)
  if @last_line_end && start_pos < @last_line_end
    # Let's not search the range from start_pos to last_line_end again.
    buf.pos = @last_line_end - start_pos
  end

  ## Scan the string for line endings; store the positions of all endings
  ## in @line_ends. 
  while buf.skip_until(/\n/)
    @last_line_end = start_pos + buf.pos
    @line_ends << @last_line_end
  end
end