diff options
-rw-r--r-- | server/src/emmy/generic.lua | 27 | ||||
-rw-r--r-- | server/src/emmy/manager.lua | 36 | ||||
-rw-r--r-- | server/src/emmy/param.lua | 8 | ||||
-rw-r--r-- | server/src/emmy/return.lua | 8 | ||||
-rw-r--r-- | server/src/utility.lua | 50 | ||||
-rw-r--r-- | server/src/vm/emmy.lua | 53 | ||||
-rw-r--r-- | server/src/vm/function.lua | 24 | ||||
-rw-r--r-- | server/test/hover/init.lua | 13 |
8 files changed, 197 insertions, 22 deletions
diff --git a/server/src/emmy/generic.lua b/server/src/emmy/generic.lua new file mode 100644 index 00000000..d47ee585 --- /dev/null +++ b/server/src/emmy/generic.lua @@ -0,0 +1,27 @@ +local listMgr = require 'vm.list' + +---@class EmmyGeneric +local mt = {} +mt.__index = mt +mt.type = 'emmy.generic' + +function mt:getName() + return self.name +end + +function mt:setValue(value) + self._value = value +end + +function mt:getValue() + return self._value +end + +return function (manager, defs) + for _, def in ipairs(defs) do + setmetatable(def, mt) + def._manager = manager + def._binds = {} + end + return defs +end diff --git a/server/src/emmy/manager.lua b/server/src/emmy/manager.lua index 7875e322..5213e2f6 100644 --- a/server/src/emmy/manager.lua +++ b/server/src/emmy/manager.lua @@ -1,11 +1,12 @@ -local listMgr = require 'vm.list' -local newClass = require 'emmy.class' -local newType = require 'emmy.type' +local listMgr = require 'vm.list' +local newClass = require 'emmy.class' +local newType = require 'emmy.type' local newTypeUnit = require 'emmy.typeUnit' -local newAlias = require 'emmy.alias' -local newParam = require 'emmy.param' -local newReturn = require 'emmy.return' -local newField = require 'emmy.field' +local newAlias = require 'emmy.alias' +local newParam = require 'emmy.param' +local newReturn = require 'emmy.return' +local newField = require 'emmy.field' +local newGeneric = require 'emmy.generic' local mt = {} mt.__index = mt @@ -107,15 +108,23 @@ function mt:addAlias(source, typeObj) return aliasObj end -function mt:addParam(source, typeObj) +function mt:addParam(source, bind) local paramObj = newParam(self, source) - paramObj:bindType(typeObj) + if bind.type == 'emmy.type' then + paramObj:bindType(bind) + elseif bind.type == 'emmy.generic' then + paramObj:bindGeneric(bind) + end return paramObj end -function mt:addReturn(source, typeObj) +function mt:addReturn(source, bind) local returnObj = newReturn(self, source) - returnObj:bindType(typeObj) + if bind.type == 'emmy.type' then + returnObj:bindType(bind) + elseif bind.type == 'emmy.generic' then + returnObj:bindGeneric(bind) + end return returnObj end @@ -126,6 +135,11 @@ function mt:addField(source, typeObj, value) return fieldObj end +function mt:addGeneric(defs) + local genericObj = newGeneric(self, defs) + return genericObj +end + function mt:remove() end diff --git a/server/src/emmy/param.lua b/server/src/emmy/param.lua index 9c18bfec..84474db6 100644 --- a/server/src/emmy/param.lua +++ b/server/src/emmy/param.lua @@ -21,6 +21,14 @@ function mt:bindType(type) end end +function mt:bindGeneric(generic) + if generic then + self._bindGeneric = generic + else + return self._bindGeneric + end +end + return function (manager, source) local self = setmetatable({ name = source[1][1], diff --git a/server/src/emmy/return.lua b/server/src/emmy/return.lua index 49f6e260..a347267c 100644 --- a/server/src/emmy/return.lua +++ b/server/src/emmy/return.lua @@ -17,6 +17,14 @@ function mt:bindType(type) end end +function mt:bindGeneric(generic) + if generic then + self._bindGeneric = generic + else + return self._bindGeneric + end +end + return function (manager, source) local self = setmetatable({ source = source.id, diff --git a/server/src/utility.lua b/server/src/utility.lua index 4e390597..a56a78ad 100644 --- a/server/src/utility.lua +++ b/server/src/utility.lua @@ -19,29 +19,64 @@ local TAB = setmetatable({}, { __index = function (self, n) end}) local KEY = {} +local RESERVED = { + ['and'] = true, + ['break'] = true, + ['do'] = true, + ['else'] = true, + ['elseif'] = true, + ['end'] = true, + ['false'] = true, + ['for'] = true, + ['function'] = true, + ['goto'] = true, + ['if'] = true, + ['in'] = true, + ['local'] = true, + ['nil'] = true, + ['not'] = true, + ['or'] = true, + ['repeat'] = true, + ['return'] = true, + ['then'] = true, + ['true'] = true, + ['until'] = true, + ['while'] = true, +} function table.dump(tbl) if type(tbl) ~= 'table' then return ('%q'):format(tbl) end local lines = {} + local mark = {} lines[#lines+1] = '{' local function unpack(tbl, tab) - if tab > 10 then - return '<Deep Table>' + if tab > 10 and mark[tbl] then + lines[#lines+1] = TAB[tab+1] .. '"<Loop>"' + return end + mark[tbl] = true local keys = {} + local integerFormat = '[%d]' + if #tbl >= 10 then + local width = math.log(#tbl, 10) + integerFormat = ('[%%0%dd]'):format(math.ceil(width)) + end for key in pairs(tbl) do if type(key) == 'string' then - if key == '' or key:find('[^%w_]') then + if not key:match('^[%a_][%w_]*$') + or #key >= 32 + or RESERVED[key] + then KEY[key] = ('[%q]'):format(key) else KEY[key] = key end elseif mathType(key) == 'integer' then - KEY[key] = ('[%03d]'):format(key) + KEY[key] = integerFormat:format(key) else - KEY[key] = ('<%s>'):format(key) + KEY[key] = ('["<%s>"]'):format(key) end keys[#keys+1] = key end @@ -60,14 +95,15 @@ function table.dump(tbl) lines[#lines+1] = ('%s},'):format(TAB[tab+1]) elseif tp == 'string' or tp == 'number' or tp == 'boolean' then lines[#lines+1] = ('%s%s = %q,'):format(TAB[tab+1], KEY[key], value) + elseif tp == 'nil' then else - lines[#lines+1] = ('%s%s = <%s>,'):format(TAB[tab+1], KEY[key], value) + lines[#lines+1] = ('%s%s = %s,'):format(TAB[tab+1], KEY[key], tostring(value)) end end end unpack(tbl, 0) lines[#lines+1] = '}' - return table.concat(lines, '\n') + return table.concat(lines, '\r\n') end local function sort_table(tbl) diff --git a/server/src/vm/emmy.lua b/server/src/vm/emmy.lua index 6c93a116..500c4711 100644 --- a/server/src/vm/emmy.lua +++ b/server/src/vm/emmy.lua @@ -4,6 +4,7 @@ function mt:clearEmmy() self._emmy = nil self._emmyParams = nil self._emmyReturns = nil + self._emmyGeneric = nil end function mt:doEmmy(action) @@ -21,6 +22,7 @@ function mt:doEmmy(action) elseif tp == 'emmyField' then self:doEmmyField(action) elseif tp == 'emmyGeneric' then + self:doEmmyGeneric(action) elseif tp == 'emmyVararg' then elseif tp == 'emmyLanguage' then elseif tp == 'emmyArrayType' then @@ -64,6 +66,12 @@ function mt:getEmmyReturns() return returns end +function mt:getEmmyGeneric() + local generic = self._emmyGeneric + self._emmyGeneric = nil + return generic +end + function mt:doEmmyClass(action) ---@type emmyMgr local emmyMgr = self.emmyMgr @@ -120,25 +128,48 @@ function mt:doEmmyAlias(action) end end +function mt:getGenericByType(type) + local generics = self._emmyGeneric + if not generics then + return + end + if #type > 1 then + return + end + local name = type[1][1] + for _, generic in ipairs(generics) do + if generic:getName() == name then + return generic + end + end + return nil +end + function mt:doEmmyParam(action) ---@type emmyMgr local emmyMgr = self.emmyMgr self:instantSource(action) self:instantSource(action[1]) - local type = self:buildEmmyType(action[2]) + local type = self:getGenericByType(action[2]) or self:buildEmmyType(action[2]) local param = emmyMgr:addParam(action, type) action:set('emmy.param', param) self:addEmmyParam(param) + if self.lsp then + self.lsp.global:markGet(self:getUri()) + end end function mt:doEmmyReturn(action) ---@type emmyMgr local emmyMgr = self.emmyMgr self:instantSource(action) - local type = self:buildEmmyType(action[1]) + local type = self:getGenericByType(action[1]) or self:buildEmmyType(action[1]) local rtn = emmyMgr:addReturn(action, type) action:set('emmy.return', rtn) self:addEmmyReturn(rtn) + if self.lsp then + self.lsp.global:markGet(self:getUri()) + end end function mt:doEmmyField(action) @@ -160,6 +191,24 @@ function mt:doEmmyField(action) action:set('target class', class) end +function mt:doEmmyGeneric(action) + ---@type emmyMgr + local emmyMgr = self.emmyMgr + self:instantSource(action) + + local defs = {} + for i, obj in ipairs(action) do + defs[i] = {} + defs[i].name = self:instantSource(obj[1]) + if obj[2] then + defs[i].type = self:buildEmmyType(obj[2]) + end + end + + local generic = emmyMgr:addGeneric(defs) + self._emmyGeneric = generic +end + function mt:doEmmyIncomplete(action) self:instantSource(action) end diff --git a/server/src/vm/function.lua b/server/src/vm/function.lua index 4c2f0be5..5c9019aa 100644 --- a/server/src/vm/function.lua +++ b/server/src/vm/function.lua @@ -259,6 +259,13 @@ function mt:run(vm) -- 向局部变量中填充参数 for i, loc in ipairs(self.args) do loc:setValue(self.argValues[i]) + local emmyParam = self:findEmmyParamByName(loc:getName()) + if emmyParam then + local genericObj = emmyParam:bindGeneric() + if genericObj then + genericObj:setValue(loc:getValue()) + end + end end if self._dots then self._dots = createMulti() @@ -271,7 +278,17 @@ function mt:run(vm) if self._emmyReturns then for i, rtn in ipairs(self._emmyReturns) do local value = vm:createValue('nil', rtn:getSource()) - value:setEmmy(rtn:bindType()) + local typeObj = rtn:bindType() + if typeObj then + value:setEmmy(typeObj) + end + local genericObj = rtn:bindGeneric() + if genericObj then + local destValue = genericObj:getValue() + if destValue then + value:mergeType(destValue) + end + end self:setReturn(i, value) end end @@ -307,7 +324,10 @@ function mt:createArg(vm, arg) local emmyParam = self:findEmmyParamByName(arg[1]) local value = valueMgr.create('nil', arg) if emmyParam then - value:setEmmy(emmyParam:bindType()) + local typeObj = emmyParam:bindType() + if typeObj then + value:setEmmy(typeObj) + end end local loc = localMgr.create(arg[1], arg, value) self:saveUpvalue(arg[1], loc) diff --git a/server/test/hover/init.lua b/server/test/hover/init.lua index 4b4d0c25..24cf8789 100644 --- a/server/test/hover/init.lua +++ b/server/test/hover/init.lua @@ -608,3 +608,16 @@ end function f() -> A|B, C ]] + +--TEST [[ +-----@generic T +-----@param x T +-----@return T +--local function f(x) +--end +-- +--local <?r?> = f(1) +--]] +--[[ +--local r: number = 1 +--]] |