class KPeg::CompiledParser

Attributes

failed_rule[R]
failing_rule_offset[R]
pos[RW]
result[RW]
string[R]

Public Class Methods

new(str, debug=false) click to toggle source

This is distinct from setup_parser so that a standalone parser can redefine initialize and still have access to the proper parser setup code.

# File lib/kpeg/compiled_parser.rb, line 19
def initialize(str, debug=false)
  setup_parser(str, debug)
end
rule_info(name, rendered) click to toggle source
# File lib/kpeg/compiled_parser.rb, line 327
def self.rule_info(name, rendered)
  RuleInfo.new(name, rendered)
end

Public Instance Methods

apply(rule) click to toggle source
# File lib/kpeg/compiled_parser.rb, line 263
def apply(rule)
  @result = nil
  if m = @memoizations[rule][@pos]
    @pos = m.pos
    if !m.set
      m.left_rec = true
      return nil
    end

    @result = m.result

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

    ans = __send__ rule

    lr = m.left_rec

    m.move! ans, @pos, @result

    # Don't bother trying to grow the left recursion
    # if it's failing straight away (thus there is no seed)
    if ans and lr
      return grow_lr(rule, nil, start_pos, m)
    else
      return ans
    end
  end
end
apply_with_args(rule, *args) click to toggle source
# File lib/kpeg/compiled_parser.rb, line 229
def apply_with_args(rule, *args)
  @result = nil
  memo_key = [rule, args]
  if m = @memoizations[memo_key][@pos]
    @pos = m.pos
    if !m.set
      m.left_rec = true
      return nil
    end

    @result = m.result

    return m.ans
  else
    m = MemoEntry.new(nil, @pos)
    @memoizations[memo_key][@pos] = m
    start_pos = @pos

    ans = __send__ rule, *args

    lr = m.left_rec

    m.move! ans, @pos, @result

    # Don't bother trying to grow the left recursion
    # if it's failing straight away (thus there is no seed)
    if ans and lr
      return grow_lr(rule, args, start_pos, m)
    else
      return ans
    end
  end
end
external_invoke(other, rule, *args) click to toggle source
# File lib/kpeg/compiled_parser.rb, line 210
def external_invoke(other, rule, *args)
  old_pos = @pos
  old_string = @string

  set_string other.string, other.pos

  begin
    if val = __send__(rule, *args)
      other.pos = @pos
      other.result = @result
    else
      other.set_failed_rule "#{self.class}##{rule}"
    end
    val
  ensure
    set_string old_string, old_pos
  end
end
failure_caret() click to toggle source
# File lib/kpeg/compiled_parser.rb, line 79
def failure_caret
  p = current_pos_info @failing_rule_offset
  "#{p.line.chomp}\n#{' ' * (p.col - 1)}^"
end
failure_character() click to toggle source
# File lib/kpeg/compiled_parser.rb, line 84
def failure_character
  current_character @failing_rule_offset
end
failure_info() click to toggle source
# File lib/kpeg/compiled_parser.rb, line 67
def failure_info
  l = current_line @failing_rule_offset
  c = current_column @failing_rule_offset

  if @failed_rule.kind_of? Symbol
    info = self.class::Rules[@failed_rule]
    "line #{l}, column #{c}: failed rule '#{info.name}' = '#{info.rendered}'"
  else
    "line #{l}, column #{c}: failed rule '#{@failed_rule}'"
  end
end
failure_oneline() click to toggle source
# File lib/kpeg/compiled_parser.rb, line 88
def failure_oneline
  p = current_pos_info @failing_rule_offset

  if @failed_rule.kind_of? Symbol
    info = self.class::Rules[@failed_rule]
    "@#{p.lno}:#{p.col} failed rule '#{info.name}', got '#{p.char}'"
  else
    "@#{p.lno}:#{p.col} failed rule '#{@failed_rule}', got '#{p.char}'"
  end
end
get_byte() click to toggle source
# File lib/kpeg/compiled_parser.rb, line 154
def get_byte
  if @pos >= @string_size
    return nil
  end

  s = @string[@pos].ord
  @pos += 1
  s
end
get_text(start) click to toggle source
# File lib/kpeg/compiled_parser.rb, line 46
def get_text(start)
  @string[start..@pos-1]
end
grow_lr(rule, args, start_pos, m) click to toggle source
# File lib/kpeg/compiled_parser.rb, line 296
def grow_lr(rule, args, start_pos, m)
  while true
    @pos = start_pos
    @result = m.result

    if args
      ans = __send__ rule, *args
    else
      ans = __send__ rule
    end
    return nil unless ans

    break if @pos <= m.pos

    m.move! ans, @pos, @result
  end

  @result = m.result
  @pos = m.pos
  return m.ans
end
match_string(str) click to toggle source
# File lib/kpeg/compiled_parser.rb, line 134
def match_string(str)
  len = str.size
  if @string[pos,len] == str
    @pos += len
    return str
  end

  return nil
end
parse(rule=nil) click to toggle source
# File lib/kpeg/compiled_parser.rb, line 175
def parse(rule=nil)
  # We invoke the rules indirectly via apply
  # instead of by just calling them as methods because
  # if the rules use left recursion, apply needs to
  # manage that.

  if !rule
    apply(:_root)
  else
    method = rule.gsub("-","_hyphen_")
    apply :"_#{method}"
  end
end
raise_error() click to toggle source
# File lib/kpeg/compiled_parser.rb, line 102
def raise_error
  raise ParseError, failure_oneline
end
scan(reg) click to toggle source
# File lib/kpeg/compiled_parser.rb, line 144
def scan(reg)
  if m = reg.match(@string, @pos)
    @pos = m.end(0)
    return true
  end

  return nil
end
set_failed_rule(name) click to toggle source
# File lib/kpeg/compiled_parser.rb, line 125
def set_failed_rule(name)
  if @pos > @failing_rule_offset
    @failed_rule = name
    @failing_rule_offset = @pos
  end
end
set_string(string, pos) click to toggle source

Sets the string and current parsing position for the parser.

# File lib/kpeg/compiled_parser.rb, line 51
def set_string string, pos
  @string = string
  @string_size = string ? string.size : 0
  @pos = pos
  @position_line_offsets = nil
end
setup_foreign_grammar() click to toggle source

Must be outside the STANDALONE block because a standalone parser always injects it’s own version of this method.

# File lib/kpeg/compiled_parser.rb, line 8
def setup_foreign_grammar
end
setup_parser(str, debug=false) click to toggle source

Prepares for parsing str. If you define a custom initialize you must call this method before parse

# File lib/kpeg/compiled_parser.rb, line 29
def setup_parser(str, debug=false)
  set_string str, 0
  @memoizations = Hash.new { |h,k| h[k] = {} }
  @result = nil
  @failed_rule = nil
  @failing_rule_offset = -1
  @line_offsets = nil

  setup_foreign_grammar
end
show_error(io=STDOUT) click to toggle source
# File lib/kpeg/compiled_parser.rb, line 106
def show_error(io=STDOUT)
  error_pos = @failing_rule_offset
  p = current_pos_info(error_pos)

  io.puts "On line #{p.lno}, column #{p.col}:"

  if @failed_rule.kind_of? Symbol
    info = self.class::Rules[@failed_rule]
    io.puts "Failed to match '#{info.rendered}' (rule '#{info.name}')"
  else
    io.puts "Failed to match rule '#{@failed_rule}'"
  end

  io.puts "Got: #{p.char.inspect}"
  io.puts "=> #{p.line}"
  io.print(" " * (p.col + 2))
  io.puts "^"
end
show_pos() click to toggle source
# File lib/kpeg/compiled_parser.rb, line 58
def show_pos
  width = 10
  if @pos < width
    "#{@pos} (\"#{@string[0,@pos]}\" @ \"#{@string[@pos,width]}\")"
  else
    "#{@pos} (\"... #{@string[@pos - width, width]}\" @ \"#{@string[@pos,width]}\")"
  end
end