summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--server-beta/src/core/diagnostics/undefined-global.lua41
-rw-r--r--server-beta/src/library.lua296
-rw-r--r--server-beta/src/searcher/eachField.lua13
-rw-r--r--server-beta/src/searcher/eachGlobal.lua13
-rw-r--r--server-beta/src/searcher/eachRef.lua13
-rw-r--r--server-beta/src/searcher/searcher.lua4
6 files changed, 357 insertions, 23 deletions
diff --git a/server-beta/src/core/diagnostics/undefined-global.lua b/server-beta/src/core/diagnostics/undefined-global.lua
index db7af133..888064dc 100644
--- a/server-beta/src/core/diagnostics/undefined-global.lua
+++ b/server-beta/src/core/diagnostics/undefined-global.lua
@@ -3,6 +3,8 @@ local guide = require 'parser.guide'
local searcher = require 'searcher'
local define = require 'proto.define'
local lang = require 'language'
+local library = require 'library'
+local config = require 'config'
return function (uri, callback)
local ast = files.getAst(uri)
@@ -10,26 +12,53 @@ return function (uri, callback)
return
end
+ -- 先遍历一次所有该文件中的全局变量
+ -- 如果变量有 set 行为,则做标记
+ -- 然后再遍历一次,对所有的行为打上标记
local hasSet = {}
searcher.eachGlobal(ast.ast, function (info)
- local key = info.key
- if hasSet[key] ~= nil then
+ if hasSet[info.source] ~= nil then
return
end
- hasSet[key] = false
+ local mark = false
searcher.eachRef(info.source, function (info)
if info.mode == 'set' then
- hasSet[key] = true
+ mark = true
end
end)
+ searcher.eachRef(info.source, function (info)
+ hasSet[info.source] = mark
+ end)
end)
+ -- 然后再遍历一次,检查所有标记为假的全局变量
searcher.eachGlobal(ast.ast, function (info)
local source = info.source
- if info.mode == 'get' and not hasSet[info.key] then
+ local key = info.key
+ local skey = key:match '^s|(.+)$'
+ if not skey then
+ return
+ end
+ if library.global[skey] then
+ return
+ end
+ if config.config.diagnostics.globals[skey] then
+ return
+ end
+ if info.mode == 'get' and not hasSet[source] then
+ local message
+ local otherVersion = library.other[key]
+ local customVersion = library.custom[key]
+ if otherVersion then
+ message = ('%s(%s)'):format(message, lang.script('DIAG_DEFINED_VERSION', table.concat(otherVersion, '/'), config.config.runtime.version))
+ elseif customVersion then
+ message = ('%s(%s)'):format(message, lang.script('DIAG_DEFINED_CUSTOM', table.concat(customVersion, '/')))
+ else
+ message = lang.script('DIAG_UNDEF_GLOBAL', info.key)
+ end
callback {
start = source.start,
finish = source.finish,
- message = lang.script('DIAG_UNDEF_GLOBAL', info.key),
+ message = message,
}
end
end)
diff --git a/server-beta/src/library.lua b/server-beta/src/library.lua
new file mode 100644
index 00000000..d4dba7c9
--- /dev/null
+++ b/server-beta/src/library.lua
@@ -0,0 +1,296 @@
+local lni = require 'lni'
+local fs = require 'bee.filesystem'
+local config = require 'config'
+local util = require 'utility'
+
+local m = {}
+
+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
+ if enum.code then
+ pack[enum.code] = enum
+ end
+ end
+ for _, enum in ipairs(locale) do
+ if pack[enum.enum] then
+ if enum.description then
+ pack[enum.enum].description = enum.description
+ end
+ end
+ if pack[enum.code] then
+ if enum.description then
+ pack[enum.code].description = enum.description
+ end
+ 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
+ if field.description then
+ pack[field.field].description = field.description
+ end
+ 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
+ if locale[name].description then
+ libs[name].description = locale[name].description
+ end
+ mergeEnum(libs[name].enums, locale[name].enums)
+ mergeField(libs[name].fields, locale[name].fields)
+ end
+ end
+end
+
+local function isMatchVersion(version)
+ if not version then
+ return true
+ end
+ local runtimeVersion = config.config.runtime.version
+ if type(version) == 'table' then
+ for i = 1, #version do
+ if version[i] == runtimeVersion then
+ return true
+ end
+ end
+ else
+ if version == runtimeVersion then
+ return true
+ end
+ end
+ return false
+end
+
+local function insertGlobal(tbl, key, value)
+ if not isMatchVersion(value.version) then
+ return false
+ end
+ if not value.doc then
+ value.doc = key
+ end
+ tbl[key] = value
+ return true
+end
+
+local function insertOther(tbl, key, value)
+ if not value.version then
+ return
+ end
+ if not tbl[key] then
+ tbl[key] = {}
+ end
+ if type(value.version) == 'string' then
+ tbl[key][#tbl[key]+1] = value.version
+ elseif type(value.version) == 'table' then
+ for _, version in ipairs(value.version) do
+ if type(version) == 'string' then
+ tbl[key][#tbl[key]+1] = version
+ end
+ end
+ end
+ table.sort(tbl[key])
+end
+
+local function insertCustom(tbl, key, value, libName)
+ if not tbl[key] then
+ tbl[key] = {}
+ end
+ tbl[key][#tbl[key]+1] = libName
+ table.sort(tbl[key])
+end
+
+local function isEnableGlobal(libName)
+ if config.config.runtime.library[libName] then
+ return true
+ end
+ if libName:sub(1, 1) == '@' then
+ return true
+ end
+ return false
+end
+
+local function mergeSource(alllibs, name, lib, libName)
+ if not lib.source then
+ if isEnableGlobal(libName) then
+ local suc = insertGlobal(alllibs.global, name, lib)
+ if not suc then
+ insertOther(alllibs.other, name, lib)
+ end
+ else
+ insertCustom(alllibs.custom, name, lib, libName)
+ end
+ return
+ end
+ for _, source in ipairs(lib.source) do
+ local sourceName = source.name or name
+ if source.type == 'global' then
+ if isEnableGlobal(libName) then
+ local suc = insertGlobal(alllibs.global, sourceName, lib)
+ if not suc then
+ insertOther(alllibs.other, sourceName, lib)
+ end
+ else
+ insertCustom(alllibs.custom, sourceName, lib, libName)
+ end
+ elseif source.type == 'library' then
+ insertGlobal(alllibs.library, sourceName, lib)
+ elseif source.type == 'object' then
+ insertGlobal(alllibs.object, sourceName, lib)
+ end
+ end
+end
+
+local function copy(t)
+ local new = {}
+ for k, v in pairs(t) do
+ new[k] = v
+ end
+ return new
+end
+
+local function insertChild(tbl, name, key, value)
+ if not name or not key then
+ return
+ end
+ if not isMatchVersion(value.version) then
+ return
+ end
+ if not value.doc then
+ value.doc = ('%s.%s'):format(name, key)
+ end
+ if not tbl[name] then
+ tbl[name] = {
+ type = name,
+ name = name,
+ child = {},
+ }
+ end
+ tbl[name].child[key] = copy(value)
+end
+
+local function mergeParent(alllibs, name, lib, libName)
+ for _, parent in ipairs(lib.parent) do
+ if parent.type == 'global' then
+ if isEnableGlobal(libName) then
+ insertChild(alllibs.global, parent.name, name, lib)
+ end
+ elseif parent.type == 'library' then
+ insertChild(alllibs.library, parent.name, name, lib)
+ elseif parent.type == 'object' then
+ insertChild(alllibs.object, parent.name, name, lib)
+ end
+ end
+end
+
+local function mergeLibs(alllibs, libs, libName)
+ if not libs then
+ return
+ end
+ for _, lib in pairs(libs) do
+ if lib.parent then
+ mergeParent(alllibs, lib.name, lib, libName)
+ else
+ mergeSource(alllibs, lib.name, lib, libName)
+ end
+ end
+end
+
+local function loadLocale(language, relative)
+ local localePath = ROOT / 'locale' / language / relative
+ local localeBuf = util.loadFile(localePath:string())
+ if localeBuf then
+ local locale = util.container()
+ xpcall(lni, log.error, localeBuf, localePath:string(), {locale})
+ return locale
+ end
+ return nil
+end
+
+local function fix(libs)
+ for name, lib in pairs(libs) do
+ lib.name = lib.name or name
+ lib.child = {}
+ end
+end
+
+local function scan(path)
+ local result = {path}
+ local i = 0
+ return function ()
+ i = i + 1
+ local current = result[i]
+ if not current then
+ return nil
+ end
+ if fs.is_directory(current) then
+ for path in current:list_directory() do
+ result[#result+1] = path
+ end
+ end
+ return current
+ end
+end
+
+local function init()
+ local lang = require 'language'
+ local id = lang.id
+ m.global = util.container()
+ m.library = util.container()
+ m.object = util.container()
+ m.other = util.container()
+ m.custom = util.container()
+
+ for libPath in (ROOT / 'libs'):list_directory() do
+ local libName = libPath:filename():string()
+ for path in scan(libPath) do
+ local libs
+ local buf = util.loadFile(path:string())
+ if buf then
+ libs = util.container()
+ xpcall(lni, log.error, buf, path:string(), {libs})
+ fix(libs)
+ end
+ local relative = fs.relative(path, ROOT)
+
+ local locale = loadLocale('en-US', relative)
+ mergeLocale(libs, locale)
+ if id ~= 'en-US' then
+ locale = loadLocale(id, relative)
+ mergeLocale(libs, locale)
+ end
+ mergeLibs(m, libs, libName)
+ end
+ end
+end
+
+function m.reload()
+ init()
+end
+
+init()
+
+return m
diff --git a/server-beta/src/searcher/eachField.lua b/server-beta/src/searcher/eachField.lua
index 11ec2be2..401378b7 100644
--- a/server-beta/src/searcher/eachField.lua
+++ b/server-beta/src/searcher/eachField.lua
@@ -130,10 +130,6 @@ end
--- 获取所有的field
function searcher.eachField(source, callback)
- local lock <close> = searcher.lock('eachField', source)
- if not lock then
- return
- end
local cache = searcher.cache.eachField[source]
if cache then
for i = 1, #cache do
@@ -141,6 +137,10 @@ function searcher.eachField(source, callback)
end
return
end
+ local unlock = searcher.lock('eachField', source)
+ if not unlock then
+ return
+ end
cache = {}
searcher.cache.eachField[source] = cache
local mark = {}
@@ -151,6 +151,9 @@ function searcher.eachField(source, callback)
end
mark[src] = true
cache[#cache+1] = info
- callback(info)
end)
+ unlock()
+ for i = 1, #cache do
+ callback(cache[i])
+ end
end
diff --git a/server-beta/src/searcher/eachGlobal.lua b/server-beta/src/searcher/eachGlobal.lua
index 21ee2c51..49396b00 100644
--- a/server-beta/src/searcher/eachGlobal.lua
+++ b/server-beta/src/searcher/eachGlobal.lua
@@ -8,10 +8,6 @@ local function eachGlobal(source, callback)
end
function searcher.eachGlobal(source, callback)
- local lock <close> = searcher.lock('eachGlobal', source)
- if not lock then
- return
- end
local cache = searcher.cache.eachGlobal[source]
if cache then
for i = 1, #cache do
@@ -19,6 +15,10 @@ function searcher.eachGlobal(source, callback)
end
return
end
+ local unlock = searcher.lock('eachGlobal', source)
+ if not unlock then
+ return
+ end
cache = {}
searcher.cache.eachGlobal[source] = cache
local mark = {}
@@ -29,6 +29,9 @@ function searcher.eachGlobal(source, callback)
end
mark[src] = true
cache[#cache+1] = info
- callback(info)
end)
+ unlock()
+ for i = 1, #cache do
+ callback(cache[i])
+ end
end
diff --git a/server-beta/src/searcher/eachRef.lua b/server-beta/src/searcher/eachRef.lua
index 4cefa405..7b2e3a27 100644
--- a/server-beta/src/searcher/eachRef.lua
+++ b/server-beta/src/searcher/eachRef.lua
@@ -330,10 +330,6 @@ end
--- 获取所有的引用
function searcher.eachRef(source, callback)
- local lock <close> = searcher.lock('eachRef', source)
- if not lock then
- return
- end
local cache = searcher.cache.eachRef[source]
if cache then
for i = 1, #cache do
@@ -341,6 +337,10 @@ function searcher.eachRef(source, callback)
end
return
end
+ local unlock = searcher.lock('eachRef', source)
+ if not unlock then
+ return
+ end
cache = {}
searcher.cache.eachRef[source] = cache
local mark = {}
@@ -351,6 +351,9 @@ function searcher.eachRef(source, callback)
end
mark[src] = true
cache[#cache+1] = info
- callback(info)
end)
+ unlock()
+ for i = 1, #cache do
+ callback(cache[i])
+ end
end
diff --git a/server-beta/src/searcher/searcher.lua b/server-beta/src/searcher/searcher.lua
index d09e3428..361243fc 100644
--- a/server-beta/src/searcher/searcher.lua
+++ b/server-beta/src/searcher/searcher.lua
@@ -24,9 +24,9 @@ function m.lock(tp, source)
return nil
end
m.locked[tp][source] = true
- return util.defer(function ()
+ return function ()
m.locked[tp][source] = nil
- end)
+ end
end
--- 获取特殊对象的名字