diff options
Diffstat (limited to 'server/src/matcher/find_lib.lua')
-rw-r--r-- | server/src/matcher/find_lib.lua | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/server/src/matcher/find_lib.lua b/server/src/matcher/find_lib.lua new file mode 100644 index 00000000..f24dabd4 --- /dev/null +++ b/server/src/matcher/find_lib.lua @@ -0,0 +1,233 @@ +local lni = require 'lni' +local fs = require 'bee.filesystem' + +local function mergeEnum(lib, locale) + if not lib or not locale then + return + end + local pack = {} + for _, enum in ipairs(lib) do + if enum.enum then + pack[enum.enum] = enum + end + end + for _, enum in ipairs(locale) do + if pack[enum.enum] then + pack[enum.enum].description = enum.description + end + end +end + +local function mergeField(lib, locale) + if not lib or not locale then + return + end + local pack = {} + for _, field in ipairs(lib) do + if field.field then + pack[field.field] = field + end + end + for _, field in ipairs(locale) do + if pack[field.field] then + pack[field.field].description = field.description + end + end +end + +local function mergeLocale(libs, locale) + if not libs or not locale then + return + end + for name in pairs(locale) do + if libs[name] then + libs[name].description = locale[name].description + mergeEnum(libs[name].enums, locale[name].enums) + mergeField(libs[name].fields, locale[name].fields) + end + end +end + +local function mergeLibs(target, libs) + if not libs then + return + end + for name, lib in pairs(libs) do + target.names[#target.names+1] = name + target.libs[#target.libs+1] = lib + end +end + +local function loadLocale(language, relative) + local localePath = ROOT / 'locale' / language / relative + local localeBuf = io.load(localePath) + if localeBuf then + local locale = table.container() + xpcall(lni.classics, log.error, localeBuf, localePath:string(), {locale}) + return locale + end + return nil +end + +local Libs +local function getLibs() + if Libs then + return Libs + end + local language = require 'language' + Libs = setmetatable({ + names = {}, + libs = {}, + }, { + __pairs = function (self) + local i = 0 + return function () + i = i + 1 + return self.names[i], self.libs[i] + end + end, + }) + for path in io.scan(ROOT / 'libs') do + local libs + local buf = io.load(path) + if buf then + libs = table.container() + xpcall(lni.classics, log.error, buf, path:string(), {libs}) + end + local relative = fs.relative(path, ROOT) + + local locale = loadLocale('en-US', relative) + mergeLocale(libs, locale) + if language ~= 'en-US' then + locale = loadLocale(language, relative) + mergeLocale(libs, locale) + end + mergeLibs(Libs, libs) + end + + return Libs +end + +local function isGlobal(var) + if var.type ~= 'field' then + return false + end + if not var.parent then + return false + end + return var.parent.key == '_ENV' or var.parent.key == '_G' +end + +local function checkSourceAsGlobal(value, name, showname) + if value.key == name and isGlobal(value) then + return showname or name + end + return nil +end + +local function checkSourceAsLibrary(value, name, showname) + if value.type ~= 'lib' then + return nil + end + if value.name == name then + return showname or name + end + return nil +end + +local function checkSource(value, libname, lib) + if not lib.source then + return checkSourceAsGlobal(value, libname) + end + for _, source in ipairs(lib.source) do + if source.type == 'global' then + local fullKey = checkSourceAsGlobal(value, source.name or libname, source.nick or libname) + if fullKey then + return fullKey + end + elseif source.type == 'library' then + local fullKey = checkSourceAsLibrary(value, source.name or libname, source.nick or libname) + if fullKey then + return fullKey + end + end + end + return nil +end + +local function checkParentAsGlobal(parentValue, name, parent) + local parentName = checkSourceAsGlobal(parentValue, parent.name, parent.nick) + if not parentName then + return nil + end + return ('%s.%s'):format(parentName, name) +end + +local function checkParentAsLibrary(parentValue, name, parent) + local parentName = checkSourceAsLibrary(parentValue, parent.name, parent.nick) + if not parentName then + return nil + end + return ('%s.%s'):format(parentName, name) +end + +local function checkParentAsObject(parentValue, name, parent) + if parentValue.type ~= parent.name then + return nil + end + return ('*%s:%s'):format(parent.name, name) +end + +local function checkParent(value, name, lib) + if name ~= value.key then + return nil + end + local parentValue = value.parent + if not parentValue then + return nil + end + parentValue = parentValue.value or parentValue + for _, parent in ipairs(lib.parent) do + if parent.type == 'global' then + local fullKey = checkParentAsGlobal(parentValue, name, parent) + if fullKey then + return fullKey, false + end + elseif parent.type == 'library' then + local fullKey = checkParentAsLibrary(parentValue, name, parent) + if fullKey then + return fullKey, false + end + elseif parent.type == 'object' then + local fullKey = checkParentAsObject(parentValue, name, parent) + if fullKey then + return fullKey, true + end + end + end + return nil +end + +local function findLib(var, libs) + local value = var.value or var + for libname, lib in pairs(libs) do + if lib.parent then + local fullKey, oo = checkParent(value, libname, lib) + if fullKey then + return lib, fullKey, oo + end + else + local fullKey = checkSource(value, libname, lib) + if fullKey then + return lib, fullKey, false + end + end + end + return nil, nil, nil +end + +return function (var) + local libs = getLibs() + local lib, fullKey, oo = findLib(var, libs) + return lib, fullKey, oo +end |