Class: KPeg::Parser

Inherits:
StringScanner
  • Object
show all
Defined in:
lib/vendor/kpeg/lib/kpeg.rb

Defined Under Namespace

Classes: LeftRecursive, MemoEntry

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(str, grammar) ⇒ Parser

Returns a new instance of Parser



7
8
9
10
11
12
13
14
15
16
# File 'lib/vendor/kpeg/lib/kpeg.rb', line 7

def initialize(str, grammar)
  super str

  @grammar = grammar
  # A 2 level hash.
  @memoizations = Hash.new { |h,k| h[k] = {} }

  @failing_pos = nil
  @failing_rule = nil
end

Instance Attribute Details

#failing_ruleObject

Returns the value of attribute failing_rule



19
20
21
# File 'lib/vendor/kpeg/lib/kpeg.rb', line 19

def failing_rule
  @failing_rule
end

#grammarObject (readonly)

Returns the value of attribute grammar



18
19
20
# File 'lib/vendor/kpeg/lib/kpeg.rb', line 18

def grammar
  @grammar
end

#memoizationsObject (readonly)

Returns the value of attribute memoizations



18
19
20
# File 'lib/vendor/kpeg/lib/kpeg.rb', line 18

def memoizations
  @memoizations
end

Instance Method Details

#apply(rule) ⇒ Object



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/vendor/kpeg/lib/kpeg.rb', line 120

def apply(rule)
  if m = @memoizations[rule][pos]
    m.inc!

    self.pos = m.pos
    if m.ans.kind_of? LeftRecursive
      m.ans.detected = true
      return nil
    end

    return m.ans
  else
    lr = LeftRecursive.new(false)
    m = MemoEntry.new(lr, pos)
    @memoizations[rule][pos] = m
    start_pos = pos

    ans = rule.match(self)

    m.move! ans, pos

    # Don't bother trying to grow the left recursion
    # if it's failing straight away (thus there is no seed)
    if ans and lr.detected
      return grow_lr(rule, start_pos, m)
    else
      return ans
    end

    return ans
  end
end

#current_column(target = pos) ⇒ Object



37
38
39
40
41
42
43
44
45
46
# File 'lib/vendor/kpeg/lib/kpeg.rb', line 37

def current_column(target=pos)
  offset = 0
  string.each_line do |line|
    len = line.size
    return (target - offset) if offset + len >= target
    offset += len
  end

  -1
end

#current_line(target = pos) ⇒ Object



48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/vendor/kpeg/lib/kpeg.rb', line 48

def current_line(target=pos)
  cur_offset = 0
  cur_line = 0

  string.each_line do |line|
    cur_line += 1
    cur_offset += line.size
    return cur_line if cur_offset >= target
  end

  -1
end

#error_expectationObject



67
68
69
70
71
72
73
74
75
# File 'lib/vendor/kpeg/lib/kpeg.rb', line 67

def error_expectation
  return "" unless @failing_rule

  error_pos = @failing_pos
  line_no = current_line(error_pos)
  col_no = current_column(error_pos)

  return "Expected #{@failing_rule.string.inspect} at line #{line_no}, column #{col_no} (offset #{error_pos})"
end

#fail(rule) ⇒ Object



31
32
33
34
35
# File 'lib/vendor/kpeg/lib/kpeg.rb', line 31

def fail(rule)
  @failing_pos = pos
  @failing_rule = rule
  return nil
end

#failed?Boolean

Returns:

  • (Boolean)


168
169
170
# File 'lib/vendor/kpeg/lib/kpeg.rb', line 168

def failed?
  !!@failing_rule
end

#grow_lr(rule, start_pos, m) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
164
165
166
# File 'lib/vendor/kpeg/lib/kpeg.rb', line 153

def grow_lr(rule, start_pos, m)
  while true
    self.pos = start_pos
    ans = rule.match(self)
    return nil unless ans

    break if pos <= m.pos

    m.move! ans, pos
  end

  self.pos = m.pos
  return m.ans
end

#linesObject



61
62
63
64
65
# File 'lib/vendor/kpeg/lib/kpeg.rb', line 61

def lines
  lines = []
  string.each_line { |l| lines << l }
  lines
end

#parse(name = nil) ⇒ Object



172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/vendor/kpeg/lib/kpeg.rb', line 172

def parse(name=nil)
  if name
    rule = @grammar.find(name)
    unless rule
      raise "Unknown rule - #{name}"
    end

    match = apply rule
  else
    match = apply @grammar.root
  end

  if pos == string.size
    @failing_rule = nil
  end

  return match
end

#show_error(io = STDOUT) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/vendor/kpeg/lib/kpeg.rb', line 77

def show_error(io=STDOUT)
  return unless @failing_rule

  error_pos = @failing_pos
  line_no = current_line(error_pos)
  col_no = current_column(error_pos)

  io.puts "Expected #{@failing_rule.string.inspect} at line #{line_no}, column #{col_no} (offset #{error_pos})"
  io.puts "Got: #{string[error_pos,1].inspect}"
  io.puts "Rule: #{@failing_rule.inspect}"
  line = lines[line_no-1]
  io.puts "=> #{line}"
  io.print(" " * (col_no + 3))
  io.puts "^"
end

#switch_grammar(gram) ⇒ Object



21
22
23
24
25
26
27
28
29
# File 'lib/vendor/kpeg/lib/kpeg.rb', line 21

def switch_grammar(gram)
  begin
    old = @grammar
    @grammar = gram
    yield
  ensure
    @grammar = old
  end
end