local lpeg = require('lpeg')
local re = require('re')
lpeg.setmaxstack(20000)
local P, R, S, C, Cmt, Carg, Cc
P, R, S, C, Cmt, Carg, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cmt, lpeg.Carg, lpeg.Cc
local DEFS
do
  local _with_0 = { }
  _with_0.nl = P("\r") ^ -1 * P("\n")
  _with_0.tab = P("\t")
  _with_0.tonumber = tonumber
  _with_0.tochar = string.char
  _with_0.unpack = unpack or table.unpack
  _with_0["nil"] = Cc(nil)
  _with_0.userdata = Carg(1)
  _with_0.utf8_char = (R("\194\223") * R("\128\191") + R("\224\239") * R("\128\191") * R("\128\191") + R("\240\244") * R("\128\191") * R("\128\191") * R("\128\191"))
  _with_0.Tree = function(t, userdata)
    return userdata.make_tree(t, userdata)
  end
  DEFS = _with_0
end
setmetatable(DEFS, {
  __index = function(self, key)
    do
      local i = key:match("^ascii_(%d+)$")
      if i then
        local c = string.char(tonumber(i))
        self[key] = c
        return c
      else
        do
          i = key:match("^number_(%d+)$")
          if i then
            local p = Cc(tonumber(i))
            self[key] = p
            return p
          end
        end
      end
    end
  end
})
local peg_tidier = re.compile([[file <- %nl* {~ (def/comment) (%nl+ (def/comment))* %nl* ~}
def <- anon_def / captured_def
anon_def <-
    ({ident} (" "*) ":" {[^%nl]* (%nl+ " "+ [^%nl]*)*}) 
    -> "%1 <- %2"
captured_def <-
    ({ident} (" "*) "(" {ident} ")" (" "*) ":" {[^%nl]* (%nl+ " "+ [^%nl]*)*})
    -> "%1 <- ({| {:start:{}:} %3 {:stop:{}:} {:type: (''->'%2') :} |} %%userdata) -> Tree"
ident <- [a-zA-Z_][a-zA-Z0-9_]*
comment <- "--" [^%nl]*
]])
local make_parser
make_parser = function(peg, make_tree)
  if make_tree == nil then
    make_tree = nil
  end
  peg = assert(peg_tidier:match(peg))
  peg = assert(re.compile(peg, DEFS))
  return function(input, filename)
    if filename == nil then
      filename = '???'
    end
    input = tostring(input)
    local tree_mt = {
      __index = {
        source = input,
        filename = filename
      }
    }
    local userdata = {
      make_tree = make_tree or (function(t)
        return setmetatable(t, tree_mt)
      end),
      filename = filename,
      source = input
    }
    local tree = peg:match(input, nil, userdata)
    if not tree then
      error("File " .. tostring(filename) .. " failed to parse:\n" .. tostring(input))
    end
    return tree
  end
end
return make_parser