summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2018-12-21 13:55:13 +0800
committer最萌小汐 <sumneko@hotmail.com>2018-12-21 13:55:13 +0800
commite50a8947ab1c6016e3763e76e0c3bedfa1b9c002 (patch)
treece7c6b45bec0118ff9b5ea918d8995695d8868bc
parentdba3476884f6ff53e0b0843fb77b42e5205161e1 (diff)
downloadlua-language-server-e50a8947ab1c6016e3763e76e0c3bedfa1b9c002.zip
支持dofile和loadfile
-rw-r--r--server/libs/lua53/basic.lni2
-rw-r--r--server/src/matcher/vm.lua115
-rw-r--r--server/src/workspace.lua47
3 files changed, 137 insertions, 27 deletions
diff --git a/server/libs/lua53/basic.lni b/server/libs/lua53/basic.lni
index 92303c4a..7c18cb6f 100644
--- a/server/libs/lua53/basic.lni
+++ b/server/libs/lua53/basic.lni
@@ -45,6 +45,7 @@ name = 'opt'
enum = 'isrunning'
[dofile]
+special = 'dofile'
[[.args]]
name = 'filename'
type = 'string'
@@ -126,6 +127,7 @@ enum = 'bt'
default = true
[loadfile]
+special = 'loadfile'
[[.args]]
name = 'filename'
type = 'string'
diff --git a/server/src/matcher/vm.lua b/server/src/matcher/vm.lua
index a1c84c3c..adc9df1d 100644
--- a/server/src/matcher/vm.lua
+++ b/server/src/matcher/vm.lua
@@ -466,17 +466,54 @@ function mt:callRequire(func, values)
values[1] = self:createValue('any')
end
local str = values[1].value
- if type(str) == 'string' then
- local lib = library.library[str]
- if lib then
- local value = self:getLibValue(lib, 'library')
- self:setFunctionReturn(func, 1, value)
- return
- end
+ if type(str) ~= 'string' then
+ return
+ end
+ local lib = library.library[str]
+ if lib then
+ local value = self:getLibValue(lib, 'library')
+ self:setFunctionReturn(func, 1, value)
+ return
+ else
+ local requireValue = self:createValue('boolean', nil, true)
+ self:setFunctionReturn(func, 1, requireValue)
+ self.requires[requireValue] = {
+ mode = 'require',
+ str = values[1],
+ }
+ end
+end
+
+function mt:callLoadFile(func, values)
+ if not values[1] then
+ values[1] = self:createValue('any')
+ end
+ local str = values[1].value
+ if type(str) ~= 'string' then
+ return
+ end
+ local requireValue = self:buildFunction()
+ self:setFunctionReturn(func, 1, requireValue)
+ self.requires[requireValue] = {
+ mode = 'loadfile',
+ str = values[1],
+ }
+end
+
+function mt:callDoFile(func, values)
+ if not values[1] then
+ values[1] = self:createValue('any')
+ end
+ local str = values[1].value
+ if type(str) ~= 'string' then
+ return
end
- local requireValue = self:createValue('boolean', nil, true)
+ local requireValue = self:createValue('any')
self:setFunctionReturn(func, 1, requireValue)
- self.requires[requireValue] = values[1]
+ self.requires[requireValue] = {
+ mode = 'dofile',
+ str = values[1],
+ }
end
function mt:call(func, values)
@@ -498,6 +535,10 @@ function mt:call(func, values)
self:callSetMetaTable(func, values)
elseif lib.special == 'require' then
self:callRequire(func, values)
+ elseif lib.special == 'loadfile' then
+ self:callLoadFile(func, values)
+ elseif lib.special == 'dofile' then
+ self:callDoFile(func, values)
end
end
end
@@ -1218,6 +1259,19 @@ function mt:mergeRequire(value, strValue, destVM)
strValue.uri = destVM.uri
end
+function mt:mergeLoadFile(value, strValue, destVM)
+ -- 取出对方的主函数
+ local main = destVM.results.main
+ -- loadfile 的返回值就是对方的主函数
+ local mainValue = deepCopy(main)
+ self:mergeValue(value, mainValue)
+
+ -- 支持 loadfile 'xxx.lua' 的转到定义
+ local strSource = strValue.source
+ self.results.sources[strSource] = strValue
+ strValue.uri = destVM.uri
+end
+
function mt:loadRequires()
if not self.lsp or not self.lsp.workspace then
return
@@ -1227,15 +1281,31 @@ function mt:loadRequires()
self.requires[k] = nil
copy[k] = v
end
- for value, strValue in pairs(copy) do
+ for value, data in pairs(copy) do
+ local strValue = data.str
+ local mode = data.mode
local str = strValue.value
if type(str) == 'string' then
- local uri = self.lsp.workspace:searchPath(self.uri, str)
+ local uri
+ if mode == 'require' then
+ uri = self.lsp.workspace:searchPath(self.uri, str)
+ elseif mode == 'loadfile' then
+ uri = self.lsp.workspace:loadPath(self.uri, str)
+ elseif mode == 'dofile' then
+ uri = self.lsp.workspace:loadPath(self.uri, str)
+ elseif mode == '' then
+ end
-- 如果循环require,这里会返回nil
-- 会当场编译VM
local destVM = self.lsp:loadVM(uri)
if destVM then
- self:mergeRequire(value, strValue, destVM)
+ if mode == 'require' then
+ self:mergeRequire(value, strValue, destVM)
+ elseif mode == 'loadfile' then
+ self:mergeLoadFile(value, strValue, destVM)
+ elseif mode == 'dofile' then
+ self:mergeRequire(value, strValue, destVM)
+ end
end
end
end
@@ -1245,14 +1315,29 @@ function mt:tryLoadRequires()
if not self.lsp or not self.lsp.workspace then
return
end
- for value, strValue in pairs(self.requires) do
+ for value, data in pairs(self.requires) do
+ local strValue = data.str
+ local mode = data.mode
local str = strValue.value
if type(str) == 'string' then
- local uri = self.lsp.workspace:searchPath(self.uri, str)
+ local uri
+ if mode == 'require' then
+ uri = self.lsp.workspace:searchPath(self.uri, str)
+ elseif mode == 'loadfile' then
+ uri = self.lsp.workspace:loadPath(self.uri, str)
+ elseif mode == 'dofile' then
+ uri = self.lsp.workspace:loadPath(self.uri, str)
+ end
-- 如果取不到VM(不编译),则做个标记,之后再取一次
local destVM = self.lsp:getVM(uri)
if destVM then
- self:mergeRequire(value, strValue, destVM)
+ if mode == 'require' then
+ self:mergeRequire(value, strValue, destVM)
+ elseif mode == 'loadfile' then
+ self:mergeLoadFile(value, strValue, destVM)
+ elseif mode == 'dofile' then
+ self:mergeRequire(value, strValue, destVM)
+ end
self.requires[value] = nil
else
self.lsp:needRequires(self.uri)
diff --git a/server/src/workspace.lua b/server/src/workspace.lua
index 76b5af51..c2478e40 100644
--- a/server/src/workspace.lua
+++ b/server/src/workspace.lua
@@ -112,16 +112,7 @@ function mt:removeFile(uri)
self.files[name] = nil
end
-function mt:searchPath(baseUri, str)
- if self.loaded[str] then
- return self.loaded[str]
- end
- str = str:gsub('%.', '/')
- local searchers = {}
- for i, luapath in ipairs(self.luapath) do
- searchers[i] = luapath:gsub('%?', str):lower()
- end
-
+function mt:findPath(baseUri, searchers)
local results = {}
for filename, uri in pairs(self.files) do
for _, searcher in ipairs(searchers) do
@@ -143,13 +134,44 @@ function mt:searchPath(baseUri, str)
end)
uri = results[1]
end
- self.loaded[str] = uri
self.lsp:readText(uri, uriDecode(uri))
return uri
end
+function mt:searchPath(baseUri, str)
+ if self.searched[str] then
+ return self.searched[str]
+ end
+ str = str:gsub('%.', '/')
+ local searchers = {}
+ for i, luapath in ipairs(self.luapath) do
+ searchers[i] = luapath:gsub('%?', str):lower()
+ end
+
+ local uri = self:findPath(baseUri, searchers)
+ if uri then
+ self.searched[str] = uri
+ end
+ return uri
+end
+
+function mt:loadPath(baseUri, str)
+ if self.loaded[str] then
+ return self.loaded[str]
+ end
+
+ local searchers = { str }
+
+ local uri = self:findPath(baseUri, searchers)
+ if uri then
+ self.loaded[str] = uri
+ end
+ return uri
+end
+
function mt:reset()
- self.laoded = {}
+ self.searched = {}
+ self.loaded = {}
self.lsp:reCompile()
end
@@ -158,6 +180,7 @@ return function (lsp, name, uri)
lsp = lsp,
name = name,
files = {},
+ searched = {},
loaded = {},
luapath = {
'?.lua',