module Raabro::ModuleMethods

def self.included(target)

def self.included(target)
  target.instance_eval do
    extend ::Raabro::ModuleMethods
    extend self
  end
end

def _match(name, input, parter, regex_or_string)

def _match(name, input, parter, regex_or_string)
  r = Raabro::Tree.new(name, parter, input)
  if l = input.match(regex_or_string)
    r.result = 1
    r.length = l
    input.offset += l
  end
  r
end

def _narrow(parser)

def _narrow(parser)
  fail ArgumentError.new("lone quantifier #{parser}") if _quantify(parser)
  method(parser.to_sym)
end

def _parse(parser, input)

def _parse(parser, input)
  #p [ caller.length, parser, input.tring ]
  #r = _narrow(parser).call(input)
  #p [ caller.length, parser, input.tring, r.to_a(children: false) ]
  #r
  _narrow(parser).call(input)
end

def _quantify(parser)

def _quantify(parser)
  return nil if parser.is_a?(Symbol) && respond_to?(parser)
    # so that :plus and co can be overriden
  case parser
  when '?', :q, :qmark then [ 0, 1 ]
  when '*', :s, :star then [ 0, 0 ]
  when '+', :p, :plus then [ 1, 0 ]
  when '!' then :bang
  else nil
  end
end

def all(name, input, parser)

def all(name, input, parser)
  start = input.offset
  length = input.string.length - input.offset
  r = ::Raabro::Tree.new(name, :all, input)
  c = _parse(parser, input)
  r.children << c
  if c.length < length
    input.offset = start
  else
    r.result = 1
    r.length = c.length
  end
  r
end

def alt(name, input, *parsers)

def alt(name, input, *parsers)
  greedy =
    if parsers.last == true || parsers.last == false
      parsers.pop
    else
      false
    end
  r = ::Raabro::Tree.new(name, greedy ? :altg : :alt, input)
  start = input.offset
  c = nil
  parsers.each do |pa|
    cc = _parse(pa, input)
    r.children << cc
    input.offset = start
    if greedy
      if cc.result == 1 && cc.length >= (c ? c.length : -1)
        c.result = 0 if c
        c = cc
      else
        cc.result = 0
      end
    else
      c = cc
      break if c.result == 1
    end
  end
  if c && c.result == 1
    r.result = 1
    r.length = c.length
    input.offset = start + r.length
  end
  r.prune! if input.options[:prune]
  r
end

def altg(name, input, *parsers)

def altg(name, input, *parsers)
  alt(name, input, *parsers, true)
end

def eseq(name, input, startpa, eltpa, seppa=nil, endpa=nil)

def eseq(name, input, startpa, eltpa, seppa=nil, endpa=nil)
  jseq = false
  if seppa.nil? && endpa.nil?
    jseq = true
    seppa = eltpa; eltpa = startpa; startpa = nil
  end
  start = input.offset
  r = ::Raabro::Tree.new(name, jseq ? :jseq : :eseq, input)
  r.result = 1
  c = nil
  if startpa
    c = _parse(startpa, input)
    r.children << c
    r.result = 0 if c.result != 1
  end
  if r.result == 1
    on_elt = false
    count = 0
    empty_stack = 0
    loop do
      on_elt = ! on_elt
      cr = _parse(on_elt ? eltpa : seppa, input)
      empty_stack = cr.empty? ? empty_stack + 1 : 0
      cr.result = 0 if empty_stack > 1
        #
        # prevent "no progress"
      r.children.push(cr)
      if cr.result != 1
        if on_elt && count > 0
          lsep = r.children[-2]
          lsep.result = 0
          input.offset = lsep.offset
        end
        break
      end
      count += 1
    end
    r.result = 0 if jseq && count < 1
  end
  if r.result == 1 && endpa
    c = _parse(endpa, input)
    r.children << c
    r.result = 0 if c.result != 1
  end
  if r.result == 1
    r.length = input.offset - start
  else
    input.offset = start
  end
  r.prune! if input.options[:prune]
  r
end

def make_includable

def make_includable
  def self.included(target)
    target.instance_eval do
      extend ::Raabro::ModuleMethods
      extend self
    end
  end
end

def method_added(name)

def method_added(name)
  m = method(name)
  return unless m.arity == 1
  return unless m.parameters[0][1] == :i || m.parameters[0][1] == :input
  @last = name.to_sym
end

def nott(name, input, parser)

def nott(name, input, parser)
  start = input.offset
  r = ::Raabro::Tree.new(name, :nott, input)
  c = _parse(parser, input)
  r.children << c
  r.length = 0
  r.result = c.result == 1 ? 0 : 1
  input.offset = start
  r
end

def parse(input, opts={})

def parse(input, opts={})
  d = opts[:debug].to_i
  opts[:rewrite] = false if d > 0
  opts[:all] = false if d > 1
  opts[:prune] = false if d > 2
  opts[:prune] = true unless opts.has_key?(:prune)
  root = self.respond_to?(:root) ? :root : @last
  t =
    if opts[:all] == false
      _parse(root, Raabro::Input.new(input, opts))
    else
      all(nil, Raabro::Input.new(input, opts), root)
    end
  return reparse_for_error(input, opts, t) if opts[:error] && t.result != 1
  return nil if opts[:prune] != false && t.result != 1
  t = t.children.first if t.parter == :all
  return rewrite(t) if opts[:rewrite] != false
  t
end

def ren(name, input, parser)

def ren(name, input, parser)
  r = _parse(parser, input)
  r.name = name
  r
end

def rep(name, input, parser, min, max=0)

def rep(name, input, parser, min, max=0)
  min = 0 if min == nil || min < 0
  max = nil if max.nil? || max < 1
  r = ::Raabro::Tree.new(name, :rep, input)
  start = input.offset
  count = 0
  loop do
    c = _parse(parser, input)
    r.children << c
    break if c.result != 1
    count += 1
    break if c.length < 1
    break if max && count == max
  end
  if count >= min && (max == nil || count <= max)
    r.result = 1
    r.length = input.offset - start
  else
    input.offset = start
  end
  r.prune! if input.options[:prune]
  r
end

def reparse_for_error(input, opts, t)

def reparse_for_error(input, opts, t)
  t =
    opts[:prune] == false ?
    t :
    parse(input, opts.merge(error: false, rewrite: false, prune: false))
bro.pp(t, colours: true)
  t.extract_error
end

def rewrite(tree)

def rewrite(tree)
  return !! methods.find { |m| m.to_s.start_with?('rewrite_') } if tree == 0
    # return true when "rewrite_xxx" methods seem to have been provided
  send("rewrite_#{tree.name}", tree)
end

def rewrite_(tree)

def rewrite_(tree)
  t = tree.lookup(nil)
  t ? rewrite(t) : nil
end

def rex(name, input, regex_or_string)

def rex(name, input, regex_or_string)
  _match(name, input, :rex, Regexp.new(regex_or_string))
end

def seq(name, input, *parsers)

def seq(name, input, *parsers)
  r = ::Raabro::Tree.new(name, :seq, input)
  start = input.offset
  c = nil
  loop do
    pa = parsers.shift
    break unless pa
    if parsers.first == '!'
      parsers.shift
      c = nott(nil, input, pa)
      r.children << c
    elsif q = _quantify(parsers.first)
      parsers.shift
      c = rep(nil, input, pa, *q)
      r.children.concat(c.children)
    else
      c = _parse(pa, input)
      r.children << c
    end
    break if c.result != 1
  end
  if c && c.result == 1
    r.result = 1
    r.length = input.offset - start
  else
    input.offset = start
  end
  r
end

def str(name, input, string)

def str(name, input, string)
  _match(name, input, :str, string)
end