summaryrefslogtreecommitdiff
path: root/server-beta/src/core/engineer.lua
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2019-09-26 14:27:04 +0800
committer最萌小汐 <sumneko@hotmail.com>2019-09-26 14:27:04 +0800
commit4958dc910cbe4fd00d263cb320f06ae1ea3bee2f (patch)
tree881cf949bca5f44f033044b74ac1177365a6d9ce /server-beta/src/core/engineer.lua
parent3036d9d81a5771665e27b1bfe06662d163155b22 (diff)
downloadlua-language-server-4958dc910cbe4fd00d263cb320f06ae1ea3bee2f.zip
重构搜索器
Diffstat (limited to 'server-beta/src/core/engineer.lua')
-rw-r--r--server-beta/src/core/engineer.lua261
1 files changed, 51 insertions, 210 deletions
diff --git a/server-beta/src/core/engineer.lua b/server-beta/src/core/engineer.lua
index a093a90a..45cff84e 100644
--- a/server-beta/src/core/engineer.lua
+++ b/server-beta/src/core/engineer.lua
@@ -3,6 +3,7 @@ local config = require 'config'
local type = type
local setmetatable = setmetatable
+local ipairs = ipairs
_ENV = nil
@@ -11,238 +12,78 @@ local mt = {}
mt.__index = mt
mt.type = 'engineer'
-function mt:call(method, obj, ...)
- self.step = self.step + 1
- if self.step > 100 then
- return nil
- end
- if not obj then
- return nil
- end
- if ... == nil and obj['_'..method] ~= nil then
- return obj['_'..method]
- end
- local res = self[method](self, obj, ...)
- self.step = self.step - 1
- if ... == nil then
- obj['_'..method] = res
- end
- return res
-end
-
---- 根据变量名,遍历全局变量
-function mt:eachGloablOfName(name, callback)
- if type(name) ~= 'string' then
- return
- end
- guide.eachSourceOf(self.ast.root, {
- ['setglobal'] = function (source)
- if source[1] == name then
- callback(source, 'set')
- end
- end,
- ['getglobal'] = function (source)
- if source[1] == name then
- callback(source, 'get')
- end
- end,
- ['setfield'] = function (source)
- if source.field[1] ~= name then
- return
- end
- if self:call('isGlobalField', source) then
- callback(source, 'set')
- end
- end,
- ['getfield'] = function (source)
- if source.field[1] ~= name then
- return
- end
- if self:call('isGlobalField', source) then
- callback(source, 'get')
- end
- end,
- ['call'] = function (source)
- local d = self:call('asRawSet', source)
- if d then
- if self:call('getLiteral', d.k) == name then
- callback(source, 'set')
- end
- end
- local d = self:call('asRawGet', source)
- if d then
- if self:call('getLiteral', d.k) == name then
- callback(source, 'get')
- end
- end
- end,
- })
-end
-
---- 是否是全局变量
-function mt:isGlobal(obj)
- if obj.type == 'getglobal' then
- return true
- end
- if obj.type == 'getfield' then
- return self:call('isGlobalField', obj)
- end
- if obj.type == 'call' then
- local d = self:call('asRawGet', obj)
- return not not d
- end
- return false
-end
-
---- 是否是指定名称的全局变量
-function mt:isGlobalOfName(obj, name)
- if not self:call('isGlobal', obj) then
- return false
- end
- return self:call('getName', obj) == name
-end
-
---- 获取名称
-function mt:getName(obj)
- if obj.type == 'setglobal' or obj.type == 'getglobal' then
- return obj[1]
- elseif obj.type == 'setfield' or obj.type == 'getfield' then
- return obj.field[1]
- elseif obj.type == 'local' or obj.type == 'setlocal' or obj.type == 'getlocal' then
- return obj[1]
- end
- return false
-end
-
---- 获取字面量值
-function mt:getLiteral(obj)
- if obj.type == 'number' then
- return obj[1]
- elseif obj.type == 'boolean' then
- return obj[1]
- elseif obj.type == 'string' then
+--- 获取对象作为域时的名字
+function mt:getFieldName(obj)
+ if obj.type == 'getglobal' or obj.type == 'setglobal' then
return obj[1]
end
return nil
end
---- 是否是全局field
----|_G.xxx
----|_ENV.xxx
----|_ENV._G.xxx
-function mt:isGlobalField(obj)
- local node = self.ast.root[obj.node]
- if self:call('isG', node) then
- return true
- end
- if self:call('isENV', node) then
- return true
+--- 查找所有局部变量引用
+function mt:eachRefAsLocal(obj, callback)
+ callback(obj, 'local')
+ if obj.ref then
+ for _, ref in ipairs(obj.ref) do
+ local refObj = self.root[ref]
+ if refObj.type == 'setlocal' then
+ callback(self.root[ref], 'set')
+ elseif refObj.type == 'getlocal' then
+ callback(self.root[ref], 'get')
+ elseif refObj.type == 'setglobal' then
+ callback(self.root[ref], 'settable', refObj)
+ elseif refObj.type == 'getglobal' then
+ callback(self.root[ref], 'gettable', refObj)
+ end
+ end
end
- return false
end
---- 是否是_ENV
-function mt:isENV(obj)
+--- 查找所有全局变量引用
+function mt:eachRefAsGlobal(obj, callback)
local version = config.config.runtime.version
- if version == 'Lua 5.1' or version == 'LuaJIT' then
- return false
- end
- if self:isGlobalOfName(obj, '_ENV') then
- return true
- end
- return false
-end
-
---- 是否是_G
-function mt:isG(obj)
- if self:isGlobalOfName(obj, '_G') then
- return true
- end
- return false
-end
-
---- 获取call的参数
-function mt:getCallArg(obj, i)
- local args = self.ast.root[obj.args]
- if not args then
- return nil
- end
- return self.ast.root[args[i]]
-end
-
---- 获取rawset信息
-function mt:asRawSet(obj)
- local node = self.ast.root[obj.node]
- if not self:isGlobalOfName(node, 'rawset') then
- return false
+ if version ~= 'Lua 5.1' and version ~= 'LuaJIT' then
+ local env = guide.getLocal(self.root, obj, '_ENV', obj.start)
+ local field = self:getFieldName(obj)
+ self:eachRefAsField(env, field, callback)
+ return
end
- return {
- t = self:getCallArg(obj, 1),
- k = self:getCallArg(obj, 2),
- v = self:getCallArg(obj, 3),
- }
end
---- 获取rawget信息
-function mt:asRawGet(obj)
- local node = self.ast.root[obj.node]
- if not self:isGlobalOfName(node, 'rawget') then
- return false
- end
- return {
- t = self:getCallArg(obj, 1),
- k = self:getCallArg(obj, 2),
- }
+--- 查找所有域引用
+function mt:eachRefAsField(parent, field, callback)
+ self:eachRef(parent, function (src, mode)
+ if self:getFieldName(src) ~= field then
+ return
+ end
+ if mode == 'settable' then
+ callback(src, 'set')
+ elseif mode == 'gettable' then
+ callback(src, 'get')
+ end
+ end)
end
---- 根据指定的局部变量,遍历局部变量引用
-function mt:eachLocalRef(obj, callback)
- if not obj then
- return
- end
- local src
+--- 查找所有引用
+function mt:eachRef(obj, callback)
if obj.type == 'local' then
- src = obj
+ self:eachRefAsLocal(obj, callback)
elseif obj.type == 'getlocal' or obj.type == 'setlocal' then
- src = self.ast.root[obj.loc]
- else
- return
- end
- callback(src, 'local')
- if src.ref then
- for i = 1, #src.ref do
- local ref = src.ref[i]
- local refObj = self.ast.root[ref]
- if refObj.type == 'setlocal' then
- callback(refObj, 'set')
- elseif refObj.type == 'getlocal' then
- callback(refObj, 'get')
- end
- end
- end
-end
-
---- 遍历class
-function mt:eachClass(obj, callback)
- local root = self.ast.root
- if obj.type == 'setlocal' or obj.type == 'getlocal' then
- local loc = root[obj.loc]
- local setmethod = root[loc.method]
- if setmethod then
- local node = root[setmethod.node]
- self:call('eachLocalRef', node, function (src, mode)
- if mode == 'local' or mode == 'set' then
- callback(src)
- end
- end)
- end
+ local loc = self.root[obj.loc]
+ self:eachRefAsLocal(loc, callback)
+ elseif obj.type == 'setglobal' or obj.type == 'getglobal' then
+ self:eachRefAsGlobal(obj, callback)
end
end
return function (ast)
+ if not ast.vm then
+ ast.vm = {}
+ end
local self = setmetatable({
step = 0,
- ast = ast,
+ root = ast.root,
+ vm = ast.vm,
}, mt)
return self
end