summaryrefslogtreecommitdiff
path: root/server/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/core')
-rw-r--r--server/src/core/completion.lua6
-rw-r--r--server/src/core/diagnostics.lua4
-rw-r--r--server/src/core/hover.lua12
-rw-r--r--server/src/core/value.lua83
-rw-r--r--server/src/core/vm.lua113
5 files changed, 131 insertions, 87 deletions
diff --git a/server/src/core/completion.lua b/server/src/core/completion.lua
index 2cdd2a64..db9189f0 100644
--- a/server/src/core/completion.lua
+++ b/server/src/core/completion.lua
@@ -113,10 +113,10 @@ local function searchLocals(vm, pos, name, callback)
end
local function searchFields(name, source, parent, object, callback)
- if not parent or not parent.value or not parent.value.child then
+ if not parent or not parent.value then
return
end
- for key, field in pairs(parent.value.child) do
+ parent.value:eachField(function (key, field)
if type(key) ~= 'string' then
goto CONTINUE
end
@@ -132,7 +132,7 @@ local function searchFields(name, source, parent, object, callback)
callback(field)
end
::CONTINUE::
- end
+ end)
end
local KEYS = {'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while', 'toclose'}
diff --git a/server/src/core/diagnostics.lua b/server/src/core/diagnostics.lua
index 64852f03..a00e0d52 100644
--- a/server/src/core/diagnostics.lua
+++ b/server/src/core/diagnostics.lua
@@ -41,7 +41,7 @@ end
function mt:searchUndefinedGlobal(callback)
local results = self.results
local env = results.locals[1]
- for index, field in pairs(env.value.child) do
+ env.value:eachField(function (index, field)
if field.value.lib then
goto NEXT_VAR
end
@@ -66,7 +66,7 @@ function mt:searchUndefinedGlobal(callback)
end
end
::NEXT_VAR::
- end
+ end)
end
function mt:searchUnusedLabel(callback)
diff --git a/server/src/core/hover.lua b/server/src/core/hover.lua
index b40c6fa4..7c3623fd 100644
--- a/server/src/core/hover.lua
+++ b/server/src/core/hover.lua
@@ -212,19 +212,19 @@ end
local function findClass(result)
-- 根据部分字段尝试找出自定义类型
local metatable = result.value.metatable
- if not metatable or not metatable.child then
+ if not metatable then
return nil
end
-- 查找meta表的 __name 字段
- local name = metatable.child['__name']
+ local name = metatable:rawGetField('__name')
-- 值必须是字符串
if name and name.value and type(name.value.value) == 'string' then
return name.value.value
end
-- 查找meta表 __index 里的字段
- local index = metatable.child['__index']
- if index and index.value and index.value.child then
- for key, field in pairs(index.value.child) do
+ local index = metatable:rawGetField('__index')
+ if index and index.value then
+ index.value:eachField(function (key, field)
-- 键值类型必须均为字符串
if type(key) ~= 'string' then
goto CONTINUE
@@ -247,7 +247,7 @@ local function findClass(result)
return field.value.value
end
::CONTINUE::
- end
+ end)
end
return nil
end
diff --git a/server/src/core/value.lua b/server/src/core/value.lua
index 2285738b..9943d282 100644
--- a/server/src/core/value.lua
+++ b/server/src/core/value.lua
@@ -4,7 +4,82 @@ local mt = {}
mt.__index = mt
mt.type = 'value'
-return function (tp, uri, source, value)
+function mt:setValue(source, value)
+ self.value = value
+end
+
+function mt:inference(tp)
+ if tp == '...' then
+ error('Value type cant be ...')
+ end
+ if self.type == 'any' and tp ~= 'nil' then
+ self.type = tp
+ end
+end
+
+function mt:createField(name, source)
+ local field = {
+ type = 'field',
+ key = name,
+ source = source or DefaultSource,
+ }
+
+ if not self._child then
+ self._child = {}
+ end
+ local uri = source and source.uri or ''
+ if not self._child[uri] then
+ self._child[uri] = {}
+ end
+ self._child[uri][name] = field
+
+ self:inference('table')
+
+ return field
+end
+
+function mt:rawGetField(name, source)
+ local uri = source and source.uri or ''
+ local field
+ if self._child then
+ if self._child[uri] then
+ field = self._child[uri][name]
+ end
+ if not field then
+ for _, childs in pairs(self._child) do
+ field = childs[name]
+ if field then
+ break
+ end
+ end
+ end
+ end
+end
+
+function mt:getField(name, source)
+ local field = self:rawGetField(name, source)
+ if not field then
+ field = self:createField(name, source)
+ end
+ return field
+end
+
+function mt:eachField(callback)
+ if not self._child then
+ return
+ end
+ local mark = {}
+ for _, childs in pairs(self._child) do
+ for name, field in pairs(childs) do
+ if not mark[name] then
+ mark[name] = true
+ callback(name, field)
+ end
+ end
+ end
+end
+
+return function (tp, source, value)
if tp == '...' then
error('Value type cant be ...')
end
@@ -13,10 +88,10 @@ return function (tp, uri, source, value)
tp = tp[1]
end
local self = setmetatable({
- type = tp,
source = source or DefaultSource,
- value = value,
- uri = uri,
}, mt)
+ if value ~= nil then
+ self:setValue(source, value)
+ end
return self
end
diff --git a/server/src/core/vm.lua b/server/src/core/vm.lua
index 965a0bec..a4535786 100644
--- a/server/src/core/vm.lua
+++ b/server/src/core/vm.lua
@@ -199,7 +199,7 @@ function mt:buildTable(source)
local key = obj[1]
if key.index then
local index = self:getIndex(key)
- local field = self:createField(tbl, index, key)
+ local field = tbl:createField(index, key)
if value.type == 'list' then
self:setValue(field, value[1], key)
else
@@ -207,7 +207,7 @@ function mt:buildTable(source)
end
else
if key.type == 'name' then
- local field = self:createField(tbl, key[1], key)
+ local field = tbl:createField(key[1], key)
self.results.indexs[#self.results.indexs+1] = field
key.isIndex = true
if value.type == 'list' then
@@ -222,17 +222,17 @@ function mt:buildTable(source)
if value.type == 'list' then
if index == #source then
for i, v in ipairs(value) do
- local field = self:createField(tbl, n + i)
+ local field = tbl:createField(n + i)
self:setValue(field, v)
end
else
n = n + 1
- local field = self:createField(tbl, n)
+ local field = tbl:createField(n)
self:setValue(field, value[1])
end
else
n = n + 1
- local field = self:createField(tbl, n)
+ local field = tbl:createField(n)
self:setValue(field, value)
end
-- 处理写了一半的 key = value,把name类的数组元素视为哈希键
@@ -357,42 +357,11 @@ function mt:getValue(var)
return var.value
end
-function mt:createField(pValue, name, source)
- if pValue.type == 'local' or pValue.type == 'field' then
- error('Only value can create field')
- end
- local field = {
- type = 'field',
- key = name,
- source = source or DefaultSource,
- }
-
- if not pValue.child then
- pValue.child = orderTable()
- end
- pValue.child[name] = field
- self:inference(pValue, 'table')
- return field
-end
-
-function mt:getField(pValue, name, source)
- local field = (pValue.child and pValue.child[name])
- if not field and pValue.ENV then
- if self.lsp then
- field = self.lsp:getGlobal(name)
- end
- end
- if not field then
- field = self:createField(pValue, name, source)
- end
- return field
-end
-
function mt:isGlobal(field)
if field.type ~= 'field' then
return false
end
- if field.parent.value.ENV then
+ if field.parent.value and field.parent.value.ENV then
return true
else
return false
@@ -511,8 +480,8 @@ function mt:setFunctionArg(func, values)
if not func.argValues[i] then
func.argValues[i] = values[i]
end
- self:inference(values[i], func.argValues[i].type)
- self:inference(func.argValues[i], values[i].type)
+ values[i]:inference(func.argValues[i].type)
+ func.argValues[i]:inference(values[i].type)
end
self:updateFunctionArgs(func)
@@ -531,7 +500,7 @@ function mt:getFunctionArg(func, i)
end
function mt:checkMetaIndex(value, meta)
- local index = self:getField(meta, '__index')
+ local index = meta:getField('__index')
if not index then
return
end
@@ -674,24 +643,24 @@ function mt:callDoFile(func, values)
end
function mt:call(func, values)
- self:inference(func, 'function')
+ func:inference('function')
local lib = func.lib
if lib then
if lib.args then
for i, arg in ipairs(lib.args) do
if arg.type == '...' then
- self:inference(self:getFunctionArg(func, i), 'any')
+ self:getFunctionArg(func, i):inference('any')
else
- self:inference(self:getFunctionArg(func, i), arg.type or 'any')
+ self:getFunctionArg(func, i):inference(arg.type or 'any')
end
end
end
if lib.returns then
for i, rtn in ipairs(lib.returns) do
if rtn.type == '...' then
- self:inference(self:getFunctionReturns(func, i), 'any')
+ self:getFunctionReturns(func, i):inference('any')
else
- self:inference(self:getFunctionReturns(func, i), rtn.type or 'any')
+ self:getFunctionReturns(func, i):inference(rtn.type or 'any')
end
end
end
@@ -772,17 +741,8 @@ function mt:getFunctionReturns(func, i)
end
end
-function mt:inference(value, type)
- if type == '...' then
- error('Value type cant be ...')
- end
- if value.type == 'any' and type ~= 'nil' then
- value.type = type
- end
-end
-
function mt:createValue(tp, source, v)
- local value = createValue(tp, self.uri, source, v)
+ local value = createValue(tp, source, v)
local lib = library.object[tp]
if lib then
self:getLibChild(value, lib, 'object')
@@ -798,7 +758,7 @@ function mt:getLibChild(value, lib, parentType)
end
self.libraryChild[lib] = {}
for fName, fLib in pairs(lib.child) do
- local fField = self:createField(value, fName)
+ local fField = value:createField(fName)
local fValue = self:getLibValue(fLib, parentType)
self:setValue(fField, fValue)
end
@@ -872,7 +832,7 @@ function mt:getName(name, source)
return loc
end
local ENV = self.scope.locals._ENV
- local global = self:getField(self:getValue(ENV), name, source)
+ local global = self:getValue(ENV):getField(name, source)
global.parent = ENV
return global
end
@@ -1001,7 +961,7 @@ function mt:getSimple(simple, mode)
elseif tp == 'index' then
local child = obj[1]
local index = self:getIndex(child)
- field = self:getField(value, index, child)
+ field = value:getField(index, child)
field.parentValue = value
value = self:getValue(field)
if mode == 'value' or i < #simple then
@@ -1019,7 +979,7 @@ function mt:getSimple(simple, mode)
parentName = ('%s[?]'):format(parentName)
end
elseif tp == 'name' then
- field = self:getField(value, obj[1], obj)
+ field = value:getField(obj[1], obj)
field.parentValue = value
value = self:getValue(field)
if mode == 'value' or i < #simple then
@@ -1055,9 +1015,18 @@ function mt:isTrue(v)
return true
end
+function mt:selectList(list, n)
+ if list.type ~= 'list' then
+ return list
+ end
+ return list[n] or self:createValue('nil')
+end
+
function mt:getBinary(exp)
local v1 = self:getExp(exp[1])
local v2 = self:getExp(exp[2])
+ v1 = self:selectList(v1, 1)
+ v2 = self:selectList(v2, 1)
local op = exp.op
-- TODO 搜索元方法
if op == 'or' then
@@ -1077,8 +1046,8 @@ function mt:getBinary(exp)
or op == '<'
or op == '>'
then
- self:inference(v1, 'number')
- self:inference(v2, 'number')
+ v1:inference('number')
+ v2:inference('number')
return self:createValue('boolean')
elseif op == '~='
or op == '=='
@@ -1090,8 +1059,8 @@ function mt:getBinary(exp)
or op == '<<'
or op == '>>'
then
- self:inference(v1, 'integer')
- self:inference(v2, 'integer')
+ v1:inference('integer')
+ v2:inference('integer')
if math.type(v1.value) == 'integer' and math.type(v2.value) == 'integer' then
if op == '|' then
return self:createValue('integer', v1.value | v2.value)
@@ -1107,8 +1076,8 @@ function mt:getBinary(exp)
end
return self:createValue('integer')
elseif op == '..' then
- self:inference(v1, 'string')
- self:inference(v2, 'string')
+ v1:inference('string')
+ v2:inference('string')
if type(v1.value) == 'string' and type(v2.value) == 'string' then
return self:createValue('string', nil, v1.value .. v2.value)
end
@@ -1121,8 +1090,8 @@ function mt:getBinary(exp)
or op == '%'
or op == '//'
then
- self:inference(v1, 'number')
- self:inference(v2, 'number')
+ v1:inference('number')
+ v2:inference('number')
if type(v1.value) == 'number' and type(v2.value) == 'number' then
if op == '+' then
return self:createValue('number', nil, v1.value + v2.value)
@@ -1158,19 +1127,19 @@ function mt:getUnary(exp)
if op == 'not' then
return self:createValue('boolean')
elseif op == '#' then
- self:inference(v1, 'table')
+ v1:inference('table')
if type(v1.value) == 'string' then
return self:createValue('integer', nil, #v1.value)
end
return self:createValue('integer')
elseif op == '-' then
- self:inference(v1, 'number')
+ v1:inference('number')
if type(v1.value) == 'number' then
return self:createValue('number', nil, -v1.value)
end
return self:createValue('number')
elseif op == '~' then
- self:inference(v1, 'integer')
+ v1:inference('integer')
if math.type(v1.value) == 'integer' then
return self:createValue('integer', nil, ~v1.value)
end
@@ -1481,7 +1450,7 @@ function mt:createEnvironment()
-- 设置全局变量
if not GlobalChild then
for name, lib in pairs(library.global) do
- local field = self:createField(envValue, name)
+ local field = envValue:createField(name)
local value = self:getLibValue(lib, 'global')
value = self:setValue(field, value)
end
@@ -1490,7 +1459,7 @@ function mt:createEnvironment()
envValue.child = readOnly(GlobalChild)
-- 设置 _G 使用 _ENV 的child
- local g = self:getField(envValue, '_G')
+ local g = envValue:getField('_G')
local gValue = self:getValue(g)
gValue.child = envValue.child
self.env = envValue