diff options
Diffstat (limited to 'parser.lua')
| -rw-r--r-- | parser.lua | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/parser.lua b/parser.lua new file mode 100644 index 0000000..0694e3e --- /dev/null +++ b/parser.lua @@ -0,0 +1,88 @@ +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 repr +repr = require('utils').repr +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 |
