summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/src/core/hover/emmy_function.lua123
-rw-r--r--server/src/core/hover/hover.lua11
-rw-r--r--server/src/emmy/funcType.lua49
-rw-r--r--server/src/emmy/manager.lua6
-rw-r--r--server/src/vm/emmy.lua46
-rw-r--r--server/src/vm/local.lua17
-rw-r--r--server/src/vm/value.lua5
-rw-r--r--server/test/hover/init.lua9
8 files changed, 254 insertions, 12 deletions
diff --git a/server/src/core/hover/emmy_function.lua b/server/src/core/hover/emmy_function.lua
new file mode 100644
index 00000000..6306957f
--- /dev/null
+++ b/server/src/core/hover/emmy_function.lua
@@ -0,0 +1,123 @@
+---@param emmy EmmyFunctionType
+local function buildEmmyArgs(emmy, object, select)
+ local start
+ if object then
+ start = 2
+ else
+ start = 1
+ end
+ local strs = {}
+ local i = 0
+ emmy:eachParam(function (name, typeObj)
+ i = i + 1
+ if i > start then
+ strs[#strs+1] = ', '
+ end
+ if i == select then
+ strs[#strs+1] = '@ARG'
+ end
+ strs[#strs+1] = name .. ': ' .. typeObj:getType()
+ if i == select then
+ strs[#strs+1] = '@ARG'
+ end
+ end)
+ local text = table.concat(strs)
+ local argLabel = {}
+ for i = 1, 2 do
+ local pos = text:find('@ARG', 1, true)
+ if pos then
+ if i == 1 then
+ argLabel[i] = pos
+ else
+ argLabel[i] = pos - 1
+ end
+ text = text:sub(1, pos-1) .. text:sub(pos+4)
+ end
+ end
+ if #argLabel == 0 then
+ argLabel = nil
+ end
+ return text, argLabel
+end
+
+local function buildEmmyReturns(emmy)
+ return '\n -> ' .. emmy:getReturn():getType()
+end
+
+local function buildEnum(lib)
+ if not lib.enums then
+ return ''
+ end
+ local container = table.container()
+ for _, enum in ipairs(lib.enums) do
+ if not enum.name or (not enum.enum and not enum.code) then
+ goto NEXT_ENUM
+ end
+ if not container[enum.name] then
+ container[enum.name] = {}
+ if lib.args then
+ for _, arg in ipairs(lib.args) do
+ if arg.name == enum.name then
+ container[enum.name].type = arg.type
+ break
+ end
+ end
+ end
+ if lib.returns then
+ for _, rtn in ipairs(lib.returns) do
+ if rtn.name == enum.name then
+ container[enum.name].type = rtn.type
+ break
+ end
+ end
+ end
+ end
+ table.insert(container[enum.name], enum)
+ ::NEXT_ENUM::
+ end
+ local strs = {}
+ for name, enums in pairs(container) do
+ local tp
+ if type(enums.type) == 'table' then
+ tp = table.concat(enums.type, '/')
+ else
+ tp = enums.type
+ end
+ strs[#strs+1] = ('\n%s: %s'):format(name, tp or 'any')
+ for _, enum in ipairs(enums) do
+ if enum.default then
+ strs[#strs+1] = '\n -> '
+ else
+ strs[#strs+1] = '\n | '
+ end
+ if enum.code then
+ strs[#strs+1] = tostring(enum.code)
+ else
+ strs[#strs+1] = ('%q'):format(enum.enum)
+ end
+ if enum.description then
+ strs[#strs+1] = ' -- ' .. enum.description
+ end
+ end
+ end
+ return table.concat(strs)
+end
+
+return function (name, emmy, object, select)
+ local args, argLabel = buildEmmyArgs(emmy, object, select)
+ local returns = buildEmmyReturns(emmy)
+ local enum = buildEnum(emmy)
+ local tip = emmy.description
+ local headLen = #('function %s('):format(name)
+ local title = ('function %s(%s)%s'):format(name, args, returns)
+ if argLabel then
+ argLabel[1] = argLabel[1] + headLen
+ argLabel[2] = argLabel[2] + headLen
+ end
+ return {
+ label = title,
+ description = tip,
+ enum = enum,
+ argLabel = argLabel,
+ }
+end
diff --git a/server/src/core/hover/hover.lua b/server/src/core/hover/hover.lua
index c0f62f24..31699d07 100644
--- a/server/src/core/hover/hover.lua
+++ b/server/src/core/hover/hover.lua
@@ -1,6 +1,7 @@
local findLib = require 'core.find_lib'
local getFunctionHover = require 'core.hover.function'
local getFunctionHoverAsLib = require 'core.hover.lib_function'
+local getFunctionHoverAsEmmy = require 'core.hover.emmy_function'
local buildValueName = require 'core.hover.name'
local OriginTypes = {
@@ -198,6 +199,7 @@ end
local function hoverAsValue(source, lsp, select)
local lib, fullkey = findLib(source)
+ ---@type value
local value = source:findValue()
local name = fullkey or buildValueName(source)
@@ -207,8 +209,13 @@ local function hoverAsValue(source, lsp, select)
if lib then
hover = getFunctionHoverAsLib(name, lib, object, select)
else
- local func = value:getFunction()
- hover = getFunctionHover(name, func, object, select)
+ local emmy = value:getEmmy()
+ if emmy and emmy.type == 'emmy.functionType' then
+ hover = getFunctionHoverAsEmmy(name, emmy, object, select)
+ else
+ local func = value:getFunction()
+ hover = getFunctionHover(name, func, object, select)
+ end
end
else
hover = getValueHover(source, name, value, lib)
diff --git a/server/src/emmy/funcType.lua b/server/src/emmy/funcType.lua
new file mode 100644
index 00000000..405de594
--- /dev/null
+++ b/server/src/emmy/funcType.lua
@@ -0,0 +1,49 @@
+local listMgr = require 'vm.list'
+
+---@class EmmyFunctionType
+local mt = {}
+mt.__index = mt
+mt.type = 'emmy.functionType'
+
+function mt:getType()
+ return 'function'
+end
+
+function mt:getSource()
+ return listMgr.get(self.source)
+end
+
+function mt:setValue(value)
+ self.value = value
+end
+
+function mt:getValue()
+ return self.value
+end
+
+function mt:addParam(name, type)
+ self._params[#self._params+1] = { name, type }
+end
+
+function mt:addReturn(type)
+ self._return = type
+end
+
+function mt:eachParam(callback)
+ for _, data in ipairs(self._params) do
+ callback(data[1], data[2])
+ end
+end
+
+function mt:getReturn()
+ return self._return
+end
+
+return function (manager, source)
+ local self = setmetatable({
+ source = source.id,
+ _params = {},
+ _manager = manager,
+ }, mt)
+ return self
+end
diff --git a/server/src/emmy/manager.lua b/server/src/emmy/manager.lua
index dad456a8..128ed029 100644
--- a/server/src/emmy/manager.lua
+++ b/server/src/emmy/manager.lua
@@ -9,6 +9,7 @@ local newField = require 'emmy.field'
local newGeneric = require 'emmy.generic'
local newArrayType = require 'emmy.arrayType'
local newTableType = require 'emmy.tableType'
+local newFuncType = require 'emmy.funcType'
local mt = {}
mt.__index = mt
@@ -116,6 +117,11 @@ function mt:addTableType(source, keyType, valueType)
return typeObj
end
+function mt:addFunctionType(source)
+ local typeObj = newFuncType(self, source)
+ return typeObj
+end
+
function mt:addAlias(source, typeObj)
local aliasName = source[1][1]
local aliasObj = newAlias(self, source)
diff --git a/server/src/vm/emmy.lua b/server/src/vm/emmy.lua
index a66738e5..cdbbd3b7 100644
--- a/server/src/vm/emmy.lua
+++ b/server/src/vm/emmy.lua
@@ -31,6 +31,7 @@ function mt:doEmmy(action)
elseif tp == 'emmyTableType' then
self:doEmmyTableType(action)
elseif tp == 'emmyFunctionType' then
+ self:doEmmyFunctionType(action)
elseif tp == 'emmySee' then
elseif tp == 'emmyIncomplete' then
self:doEmmyIncomplete(action)
@@ -225,12 +226,17 @@ function mt:doEmmyVararg(action)
end
end
-function mt:doEmmyArrayType(action)
+function mt:buildEmmyArrayType(action)
---@type emmyMgr
local emmyMgr = self.emmyMgr
self:instantSource(action)
action:set('emmy class', action[1])
local type = emmyMgr:addArrayType(action)
+ return type
+end
+
+function mt:doEmmyArrayType(action)
+ local type = self:buildEmmyArrayType(action)
self._emmy = type
if self.lsp then
self.lsp.global:markGet(self:getUri())
@@ -238,13 +244,18 @@ function mt:doEmmyArrayType(action)
return type
end
-function mt:doEmmyTableType(action)
+function mt:buildEmmyTableType(action)
---@type emmyMgr
local emmyMgr = self.emmyMgr
self:instantSource(action)
local keyType = self:buildEmmyType(action[1])
local valueType = self:buildEmmyType(action[2])
local type = emmyMgr:addTableType(action, keyType, valueType)
+ return type
+end
+
+function mt:doEmmyTableType(action)
+ local type = self:buildEmmyTableType(action)
self._emmy = type
if self.lsp then
self.lsp.global:markGet(self:getUri())
@@ -252,6 +263,37 @@ function mt:doEmmyTableType(action)
return type
end
+function mt:doEmmyFunctionType(action)
+ ---@type emmyMgr
+ local emmyMgr = self.emmyMgr
+ self:instantSource(action)
+ local func = emmyMgr:addFunctionType(action)
+ for i = 1, #action // 2 do
+ local nameSource = action[i*2-1]
+ local typeSource = action[i*2]
+ local paramType = self:buildEmmyAnyType(typeSource)
+ func:addParam(nameSource[1], paramType)
+ end
+ local returnType = self:buildEmmyAnyType(action[#action])
+ func:addReturn(returnType)
+ self._emmy = func
+ return func
+end
+
+function mt:buildEmmyAnyType(source)
+ if source.type == 'emmyType' then
+ return self:buildEmmyType(source)
+ elseif source.type == 'emmyArrayType' then
+ return self:buildEmmyArrayType(source)
+ elseif source.type == 'emmyTableType' then
+ return self:buildEmmyTableType(source)
+ elseif source.type == 'emmyFunctionType' then
+ return self:buildEmmyFunctionType(source)
+ else
+ error('Unknown emmy type: ' .. table.dump(source))
+ end
+end
+
function mt:doEmmyIncomplete(action)
self:instantSource(action)
end
diff --git a/server/src/vm/local.lua b/server/src/vm/local.lua
index ce47414a..5b936625 100644
--- a/server/src/vm/local.lua
+++ b/server/src/vm/local.lua
@@ -136,18 +136,19 @@ function mt:getSource()
return listMgr.get(self.source)
end
+local EMMY_TYPE = {
+ ['emmy.class'] = true,
+ ['emmy.type'] = true,
+ ['emmy.arrayType'] = true,
+ ['emmy.tableType'] = true,
+ ['emmy.functionType'] = true,
+}
+
function mt:setEmmy(emmy)
if not emmy then
return
end
- if emmy.type ~= 'emmy.class'
- and emmy.type ~= 'emmy.type'
- and emmy.type ~= 'emmy.arrayType'
- and emmy.type ~= 'emmy.tableType'
- then
- return
- end
- if self.value then
+ if self.value and EMMY_TYPE[emmy.type] then
self.value:setEmmy(emmy)
end
end
diff --git a/server/src/vm/value.lua b/server/src/vm/value.lua
index 6cfaec4b..b43530d0 100644
--- a/server/src/vm/value.lua
+++ b/server/src/vm/value.lua
@@ -13,6 +13,7 @@ local TypeLevel = {
['number'] = 0.6,
}
+---@class value
local mt = {}
mt.__index = mt
mt.type = 'value'
@@ -595,6 +596,10 @@ function mt:setEmmy(emmy)
---@type EmmyTableType
local emmyTableType = emmy
emmyTableType:setValue(self)
+ elseif emmy.type == 'emmy.functionType' then
+ ---@type EmmyFunctionType
+ local emmyFuncType = emmy
+ emmyFuncType:setValue(self)
else
return
end
diff --git a/server/test/hover/init.lua b/server/test/hover/init.lua
index 1c4809a6..baed3912 100644
--- a/server/test/hover/init.lua
+++ b/server/test/hover/init.lua
@@ -721,3 +721,12 @@ end
[[
local k: *ClassA
]]
+
+TEST [[
+---@type fun(x: number, y: number):boolean
+local <?f?>
+]]
+[[
+function f(x: number, y: number)
+ -> boolean
+]]