class KPeg::GrammarRenderer

Public Class Methods

escape(str, embed=false) click to toggle source
# File lib/kpeg/grammar_renderer.rb, line 66
def self.escape(str, embed=false)
  parc = StringEscape.new(str)

  rule = (embed ? "embed" : nil)

  unless parc.parse(rule)
    parc.raise_error
  end

  return parc.text
end
new(gram) click to toggle source
# File lib/kpeg/grammar_renderer.rb, line 5
def initialize(gram)
  @grammar = gram
end

Public Instance Methods

parens?(op) click to toggle source
# File lib/kpeg/grammar_renderer.rb, line 57
def parens?(op)
  case op
  when Sequence, AndPredicate, NotPredicate
    return true
  end

  false
end
render(io) click to toggle source
# File lib/kpeg/grammar_renderer.rb, line 9
def render(io)
  widest = @grammar.rules.keys.sort { |a,b| a.size <=> b.size }.last
  indent = widest.size

  @grammar.variables.sort.each do |name, value|
    io.print "%% #{name} = #{value}\n"
  end

  unless @grammar.variables.empty?
    io.print "\n"
  end

  @grammar.directives.sort_by { |name,| name }.each do |name, act|
    io.print "%% #{name} {"
    io.print act.action
    io.print "}\n\n"
  end

  @grammar.setup_actions.each do |act|
    io.print "%% {"
    io.print act.action
    io.print "}\n\n"
  end

  @grammar.rule_order.each do |name|
    rule = @grammar.find(name)

    io.print(' ' * (indent - name.size))
    io.print "#{name} = "

    op = rule.op

    if op.kind_of? Choice
      op.ops.each_with_index do |r,idx|
        unless idx == 0
          io.print "\n#{' ' * (indent+1)}| "
        end

        render_op io, r
      end
    else
      render_op io, op
    end

    io.puts
  end
end
render_op(io, op) click to toggle source
# File lib/kpeg/grammar_renderer.rb, line 78
def render_op(io, op)
  case op
  when Dot
    io.print "."
  when LiteralString
    esc = GrammarRenderer.escape op.string
    io.print '"'
    io.print esc
    io.print '"'
  when LiteralRegexp
    io.print op.regexp.inspect
  when CharRange
    io.print "[#{op.start}-#{op.fin}]"
  when Sequence
    op.ops.each_with_index do |r,idx|
      unless idx == 0
        io.print " "
      end
      render_op io, r
    end
  when Choice
    io.print "("
    op.ops.each_with_index do |r,idx|
      unless idx == 0
        io.print " | "
      end

      render_op io, r
    end
    io.print ")"
  when Multiple
    if parens?(op.op)
      io.print "("
      render_op io, op.op
      io.print ")"
    else
      render_op io, op.op
    end

    if op.max
      if op.min == 0 and op.max == 1
        io.print "?"
      else
        io.print "[#{op.min}, #{op.max}]"
      end
    elsif op.min == 0
      io.print "*"
    elsif op.min == 1
      io.print "+"
    else
      io.print "[#{op.min},*]"
    end
  when AndPredicate
    io.print "&"
    if parens?(op.op)
      io.print "("
      render_op io, op.op
      io.print ")"
    else
      render_op io, op.op
    end
  when NotPredicate
    io.print "!"
    if parens?(op.op)
      io.print "("
      render_op io, op.op
      io.print ")"
    else
      render_op io, op.op
    end
  when RuleReference
    if op.arguments
      io.print "#{op.rule_name}#{op.arguments}"
    else
      io.print "#{op.rule_name}"
    end
  when InvokeRule
    if op.arguments
      io.print "@#{op.rule_name}#{op.arguments}"
    else
      io.print "@#{op.rule_name}"
    end
  when ForeignInvokeRule
    if op.arguments
      io.print "%#{op.grammar_name}.#{op.rule_name}#{op.arguments}"
    else
      io.print "%#{op.grammar_name}.#{op.rule_name}"
    end
  when Tag
    if parens?(op.op)
      io.print "("
      render_op io, op.op
      io.print ")"
    else
      render_op io, op.op
    end

    if op.tag_name
      io.print ":#{op.tag_name}"
    end
  when Action
    io.print "{#{op.action}}"
  when Collect
    io.print "< "
    render_op io, op.op
    io.print " >"
  when Bounds
    io.print "@< "
    render_op io, op.op
    io.print " >"
  else
    raise "Unknown op type - #{op.class}"
  end
end