Class: Pegparse::LineCounter

Inherits:
Object
  • Object
show all
Defined in:
lib/pegparse/line_counter.rb

Overview

count line number and indent level

Instance Method Summary collapse

Constructor Details

#initializeLineCounter

Returns a new instance of LineCounter.



4
5
6
7
8
# File 'lib/pegparse/line_counter.rb', line 4

def initialize
  @line_start_pos = [0]
  @line_start_pos_noindent = [0]
  @farthest_pos = 0
end

Instance Method Details

#indent(pos) ⇒ Integer

get indent level for the line including pos

Parameters:

  • pos (Integer)

Returns:

  • (Integer)


57
58
59
60
# File 'lib/pegparse/line_counter.rb', line 57

def indent(pos)
  line_count, * = position(pos)
  @line_start_pos_noindent[line_count] - @line_start_pos[line_count]
end

#memo(pos, str) ⇒ Object

update with partial string

Parameters:

  • pos (Integer)

    position of str relative to whole input

  • str (String)

    partial string

Raises:

  • (ArgumentError)


13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/pegparse/line_counter.rb', line 13

def memo(pos, str)
  return if pos + str.size < @farthest_pos
  raise ArgumentError if pos > @farthest_pos

  row, * = position(pos)
  str.each_byte.with_index do |ch, index|
    if ch == ' '.ord || ch == "\t".ord
      # 既知のインデントより後ろに空白が続いている場合、インデントの深さを増やす
      if (pos + index) == (@line_start_pos_noindent[row])
        @line_start_pos_noindent[row] += 1
      end
    end
    if ch == "\n".ord
      next_line_start_pos = pos + index + 1
      if @line_start_pos.last < next_line_start_pos
        @line_start_pos << next_line_start_pos
        @line_start_pos_noindent << next_line_start_pos
      end
      row += 1
    end
  end
  if @farthest_pos < pos + str.size
    @farthest_pos = pos + str.size
  end
end

#position(pos) ⇒ Array[Integer]

get line number and char offset for pos

Parameters:

  • pos (Integer)

Returns:

  • (Array[Integer])


42
43
44
45
46
47
48
49
50
51
52
# File 'lib/pegparse/line_counter.rb', line 42

def position(pos)
  if pos >= @line_start_pos.last
    line_count = @line_start_pos.size - 1
  else
    after_pos_line_head = @line_start_pos.bsearch_index{|x| x > pos}
    line_count = after_pos_line_head - 1
  end
  char_count = pos - @line_start_pos[line_count]

  [line_count, char_count]
end