summaryrefslogtreecommitdiff
path: root/server/src
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2019-03-04 16:48:58 +0800
committer最萌小汐 <sumneko@hotmail.com>2019-03-04 16:48:58 +0800
commit4843133cf08b1a05c506665b5b84bdf6ccbea884 (patch)
tree60c58b8e82b780600ae3801c954bd04794fd00f9 /server/src
parentd165bf61b7f9d004cc670f6d5316096406054d2d (diff)
downloadlua-language-server-4843133cf08b1a05c506665b5b84bdf6ccbea884.zip
类型推断
Diffstat (limited to 'server/src')
-rw-r--r--server/src/vm/dots.lua28
-rw-r--r--server/src/vm/function.lua35
-rw-r--r--server/src/vm/multi.lua6
-rw-r--r--server/src/vm/vm.lua111
4 files changed, 72 insertions, 108 deletions
diff --git a/server/src/vm/dots.lua b/server/src/vm/dots.lua
deleted file mode 100644
index e9a1ac15..00000000
--- a/server/src/vm/dots.lua
+++ /dev/null
@@ -1,28 +0,0 @@
-local createValue = require 'vm.value'
-
-local mt = {}
-mt.__index = mt
-mt.type = 'dots'
-
-function mt:set(n, value)
- self[n] = value
-end
-
-function mt:get(expect)
- local result = {}
- if expect then
- for i = 1, expect do
- result[i] = self[i] or createValue('any')
- end
- else
- for i = 1, #self do
- result[i] = self[i]
- end
- end
- return result
-end
-
-return function ()
- local self = setmetatable({}, mt)
- return self
-end
diff --git a/server/src/vm/function.lua b/server/src/vm/function.lua
index 145e5eda..f3d4720c 100644
--- a/server/src/vm/function.lua
+++ b/server/src/vm/function.lua
@@ -1,4 +1,3 @@
-local createDots = require 'vm.dots'
local createMulti = require 'vm.multi'
local createValue = require 'vm.value'
local createLocal = require 'vm.local'
@@ -100,7 +99,7 @@ function mt:getReturn(index)
self.returns = createMulti()
end
if index then
- return self.returns:get(index)
+ return self.returns:get(index) or createValue('nil')
else
return self.returns
end
@@ -108,16 +107,16 @@ end
function mt:returnDots(index)
if not self.returns then
- self.returns = {}
+ self.returns = createMulti()
end
- self.returns[index] = createDots()
+ self.returns[index] = createMulti()
end
-function mt:loadDots(expect)
+function mt:loadDots()
if not self._dots then
- self._dots = createDots()
+ self._dots = createMulti()
end
- return self._dots:get(expect)
+ return self._dots
end
function mt:setObject(value, source)
@@ -159,27 +158,29 @@ function mt:run()
end
function mt:setArgs(values)
- if not self.argValues then
- self.argValues = {}
- end
+ self.argValues = {}
for i = 1, #values do
self.argValues[i] = values[i]
end
end
-function mt:createArg(arg)
+function mt:createArg(arg, values)
if arg.type == 'name' then
- local loc = createLocal(arg[1], arg, createValue('any', arg))
+ local value = table.remove(values, 1) or createValue('nil', arg)
+ local loc = createLocal(arg[1], arg, value)
self:saveLocal(arg[1], loc)
self.args[#self.args+1] = loc
elseif arg.type == '...' then
- self._dots = createDots()
+ self._dots = createMulti(values)
+ for i = 1, #values do
+ self._dots:set(i, values[i])
+ end
end
end
function mt:createLibArg(arg)
if arg.type == '...' then
- self._dots = createDots()
+ self._dots = createMulti()
else
local name = arg.name or '_'
local loc = createLocal(name, nil, createValue('any'))
@@ -200,12 +201,14 @@ function mt:createArgs()
if not args then
return
end
+ local values = self.argValues or {}
+ self.argValues = nil
if args.type == 'list' then
for _, arg in ipairs(args) do
- self:createArg(arg)
+ self:createArg(arg, values)
end
else
- self:createArg(args)
+ self:createArg(args, values)
end
end
diff --git a/server/src/vm/multi.lua b/server/src/vm/multi.lua
index 93900a36..f4f21b86 100644
--- a/server/src/vm/multi.lua
+++ b/server/src/vm/multi.lua
@@ -64,6 +64,12 @@ function mt:eachValue(callback)
end
end
+function mt:merge(other)
+ other:eachValue(function (_, value)
+ self:push(value)
+ end)
+end
+
return function ()
local self = setmetatable({}, mt)
return self
diff --git a/server/src/vm/vm.lua b/server/src/vm/vm.lua
index 8c8be4f7..d2057ca7 100644
--- a/server/src/vm/vm.lua
+++ b/server/src/vm/vm.lua
@@ -40,17 +40,6 @@ function mt:eachInfo(var, callback)
return nil
end
-function mt:createDots(index, source)
- local dots = {
- type = 'dots',
- source = source or self:getDefaultSource(),
- func = self:getCurrentFunction(),
- index = index,
- }
- self.chunk.dots = dots
- return dots
-end
-
function mt:buildTable(source)
local tbl = self:createValue('table', source)
if not source then
@@ -283,53 +272,57 @@ function mt:callDoFile(func, values)
func:setReturn(1, requireValue)
end
+function mt:callLibrary(func, values, source, lib)
+ if lib.args then
+ for i, arg in ipairs(lib.args) do
+ local value = values[i]
+ if value and arg.type ~= '...' then
+ value:setType(arg.type, 1.0)
+ end
+ end
+ end
+ if lib.returns then
+ for i, rtn in ipairs(lib.returns) do
+ if rtn.type == '...' then
+ --func:getReturn(i):setType('any', 0.0)
+ else
+ func:getReturn(i):setType(rtn.type or 'any', 1.0)
+ end
+ end
+ end
+ if lib.special then
+ if lib.special == 'setmetatable' then
+ self:callSetMetaTable(func, values, source)
+ 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
+
function mt:call(value, values, source)
- local lib = value.lib
+ local lib = value:getLib()
local func = value:getFunction()
if not func then
return
end
if lib then
- if lib.args then
- for i, arg in ipairs(lib.args) do
- local value = values[i]
- if value and arg.type ~= '...' then
- value:setType(arg.type, 1.0)
- end
- end
- end
- if lib.returns then
- for i, rtn in ipairs(lib.returns) do
- if rtn.type == '...' then
- func:getReturn(i):setType('any', 0.0)
- else
- func:getReturn(i):setType(rtn.type or 'any', 1.0)
- end
- end
- end
- if lib.special then
- if lib.special == 'setmetatable' then
- self:callSetMetaTable(func, values, source)
- 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
+ self:callLibrary(func, values, source, lib)
else
- if not func.source then
+ if func.source then
+ if not source:getFlag 'called' then
+ source:setFlag('called', true)
+ func:setArgs(values)
+ self:runFunction(func)
+ end
+ else
func:setReturn(1, self:createValue('any', source))
end
end
- if not source.hasRuned and func.source then
- source.hasRuned = true
- func:setArgs(values)
- self:runFunction(func)
- end
-
return func:getReturn()
end
@@ -393,15 +386,7 @@ function mt:getIndex(source)
end
end
--- expect表示遇到 ... 时,期待的返回数量
-function mt:unpackDots(res, expect)
- local dots = self:loadDots(expect)
- for _, v in ipairs(dots) do
- res:push(v)
- end
-end
-
-function mt:unpackList(list, expect)
+function mt:unpackList(list)
local res = createMulti()
if not list then
return res
@@ -409,7 +394,7 @@ function mt:unpackList(list, expect)
if list.type == 'list' or list.type == 'call' or list.type == 'return' then
for i, exp in ipairs(list) do
if exp.type == '...' then
- self:unpackDots(res, expect)
+ res:merge(self:loadDots())
break
end
local value = self:getExp(exp)
@@ -426,7 +411,7 @@ function mt:unpackList(list, expect)
end
end
elseif list.type == '...' then
- self:unpackDots(res, expect)
+ res:merge(self:loadDots())
else
local value = self:getExp(list)
if value.type == 'multi' then
@@ -463,7 +448,7 @@ function mt:getSimple(simple, max)
for i = 2, max do
local source = simple[i]
self:instantSource(source)
- value = self:getFirstInMulti(value)
+ value = self:getFirstInMulti(value) or createValue('nil')
if source.type == 'call' then
local args = self:unpackList(source)
@@ -660,9 +645,7 @@ function mt:getExp(exp)
elseif tp == 'table' then
return self:buildTable(exp)
elseif tp == '...' then
- local value = { type = 'list' }
- self:unpackDots(value)
- return value
+ return self:loadDots()
elseif tp == 'list' then
return self:getMultiByList(exp)
end
@@ -1026,8 +1009,8 @@ function mt:loadLabel(name)
return self.currentFunction:loadLabel(name)
end
-function mt:loadDots(expect)
- return self.currentFunction:loadDots(expect)
+function mt:loadDots()
+ return self.currentFunction:loadDots()
end
function mt:getUri()