99 lines
2.6 KiB
Lua
99 lines
2.6 KiB
Lua
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 foldr
|
|
foldr = function(...)
|
|
local inner = select(1, ...)
|
|
for i = 2, select('#', ...) do
|
|
assert(inner.type)
|
|
local outer = select(i, ...)
|
|
table.insert(outer, 1, inner)
|
|
inner.start = outer.start
|
|
inner = outer
|
|
end
|
|
assert(inner.type)
|
|
return inner
|
|
end
|
|
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
|
|
_with_0.foldr = foldr
|
|
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* {~ (captured_def/line) (%nl+ (captured_def/line))* %nl* ~}
|
|
ident <- [a-zA-Z_][a-zA-Z0-9_]*
|
|
line <- [^%nl]*
|
|
captured_def <-
|
|
({ident} (" "*) "(" {ident} ")" (" "*) "<-" {[^%nl]* (%nl+ " "+ [^%nl]*)*}) ->
|
|
"%1 <- ({| {:type:''->'%2':} {:start:{}:}
|
|
%3
|
|
{:stop:{}:} |} %%userdata) -> Tree"
|
|
]])
|
|
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
|