local lpeg = require "lpeg" local PKGBASE = "pkgbase" local PKGNAME = "pkgname" local modes = { [PKGBASE] = PKGBASE, [PKGNAME] = PKGNAME, } local package_mt = {} function package_mt:__index (key) return self.base[key] end local function shallow (list) local new = {} for i, value in ipairs(list) do new[i] = value end return new end local function apply (state, method, ...) if state[method] then return state[method](state, ...) end return nil end local identifier = lpeg.R"az" + lpeg.R"09" + lpeg.S"@+_" identifier = identifier * (identifier + lpeg.S".-")^0 local whitespace = lpeg.S" \t"^0 local newline = lpeg.P"\r\n" + "\n" local rest = (1 - newline)^0 local definition = lpeg.Cc"definition" * whitespace * lpeg.C(identifier) * whitespace * "=" * whitespace * lpeg.C(rest) local comment = lpeg.Cc"comment" * whitespace * lpeg.P"#" * lpeg.C(rest) local empty = lpeg.Cc"empty" * whitespace local invalid = lpeg.Cc"invalid" * lpeg.C(rest) local line = lpeg.Carg(1) * (definition + comment + empty + invalid) / apply * newline local capture = lpeg.Ct(line^0) * -lpeg.P(1) local function srcinfo (text, options) options = options or {} return capture:match( text, nil, { mode = modes[options.mode] or PKGNAME, base = nil, current = nil, definition = function (self, name, value) if name == PKGBASE then self.base = {name=value} self.current = self.base if self.mode == PKGBASE then self.base.packages = {} return self.current end elseif name == PKGNAME then self.current = {name=value} if self.mode == PKGNAME then self.current.base = self.base return setmetatable(self.current, package_mt) else table.insert(self.base.packages, self.current) end else local current_value = self.current[name] if type(current_value) == "table" then current_value = shallow(current_value) -- Wasteful, but won't spill table.insert(current_value, value) self.current[name] = current_value elseif current_value ~= nil then self.current[name] = {current_value, value} else self.current[name] = value end end end, comment = function (self, text) end, empty = function (self) end, invalid = function (self, text) return text end, } ) end return srcinfo