local parser = require 'parser' local core = require 'core' local buildVM = require 'vm' rawset(_G, 'TEST', true) function TEST(script) return function (expect) local start = script:find('', 1, true) local pos = (start + finish) // 2 + 1 local new_script = script:gsub('<[!?]', ' '):gsub('[!?]>', ' ') local ast = parser:ast(new_script, 'lua', 'Lua 5.3') local vm = buildVM(ast) assert(vm) local source = core.findSource(vm, pos) local hover = core.hover(source) if expect then assert(hover) expect = expect:gsub('^[\r\n]*(.-)[\r\n]*$', '%1'):gsub('\r\n', '\n') local label = hover.label:gsub('^[\r\n]*(.-)[\r\n]*$', '%1'):gsub('\r\n', '\n') assert(expect == label) else assert(hover == nil) end end end TEST [[ local function (a, b) end ]] "function x(a: any, b: any)" TEST [[ local function x(a, b) end () ]] "function x(a: any, b: any)" TEST [[ local mt = {} mt.__index = mt function mt:init(a, b, c) return {} end local obj = setmetatable({}, mt) obj:(1, '测试') ]] [[ function mt:init(a: number, b: string, c: any) -> table ]] TEST [[ local mt = {} mt.__index = mt function mt:init(a, b, c) return {} end local obj = setmetatable({}, mt) obj:init(1, '测试') obj.(obj, 1, '测试') ]] [[ function mt.init(self: table, a: number, b: string, c: any) -> table ]] TEST [[ function obj.xxx() end obj.() ]] "function obj.xxx()" TEST [[ obj.() ]] [[function obj.xxx() -> any ]] TEST [[ local = 1 ]] "local x: number = 1" TEST [[ = 1 ]] "global x: number = 1" TEST [[ local t = {} t. = 1 ]] "field t.x: number = 1" TEST [[ t = {} t. = 1 ]] "global t.x: number = 1" TEST [[ local mt = {} mt.__name = 'class' local = setmetatable({}, mt) ]] "local obj: *class {}" TEST [[ local mt = {} mt.name = 'class' mt.__index = mt local = setmetatable({}, mt) ]] [[ local obj: *class { __index: table, name: string = "class", } ]] TEST [[ local mt = {} mt.TYPE = 'class' mt.__index = mt local = setmetatable({}, mt) ]] [[ local obj: *class { TYPE: string = "class", __index: table, } ]] TEST [[ local mt = {} mt.Class = 'class' mt.__index = mt local = setmetatable({}, mt) ]] [[ local obj: *class { Class: string = "class", __index: table, } ]] TEST[[ local fs = require 'bee.filesystem' local = fs.current_path() ]] "local root: *bee::filesystem" TEST[[ ('xx'):() ]] [[function *string:yy() -> any]] TEST [[ local = collectgarbage() ]] "local v: any" TEST [[ local type w2l:get_default()[] ]] "local type: any" TEST [[ () ]] [=[ function load(chunk: string/function [, chunkname: string [, mode: string [, env: table]]]) -> function, error_message: string ]=] TEST [[ string.() ]] [[ function string.lower(string) -> string ]] TEST [[ local function x(a, ...) end (1, 2, 3, 4, 5, 6, 7) ]] [[ function x(a: number, ...) ]] TEST [[ local function x() return y() end () ]] [[ function x() -> any ]] TEST [[ local mt = {} mt.__index = mt function mt:add(a, b) end local function init() return setmetatable({}, mt) end local t = init() t:() ]] [[ function mt:add(a: any, b: any) ]] TEST [[ local = - 1000 ]] [[local t: number = -1000]] TEST [[ for in io.lines() do end ]] [[local c: string]] TEST [[ local function f() return ... end local = f() ]] [[local n: any]] TEST [[ local = table.unpack(t) ]] [[local n: any]] TEST [[ local table.pack(n) ]] [[ local n: any ]] TEST [[ ():sub() ]] (nil) TEST [[ local = { a = 1, b = 2, c = 3, } ]] [[ local t: { a: number = 1, b: number = 2, c: number = 3, } ]] TEST [[ local = { a = 1, [1] = 2, [true] = 3, [5.5] = 4, [{}] = 5, [function () end] = 6, ["b"] = 7, ["012"] = 8, } ]] [[ local t: { ["012"]: number = 8, [*function]: number = 6, [*table]: number = 5, [001]: number = 2, [5.5]: number = 4, [true]: number = 3, a: number = 1, b: number = 7, } ]] TEST [[ local = {} t[#t+1] = 1 t[#t+1] = 1 local any = collectgarbage() t[any] = any ]] [[ local t: { [*number]: number = 1, } ]] TEST[[ local x = 1 local y = x print() ]] [[ local y: number = 1 ]] TEST[[ local mt = {} mt.a = 1 mt.b = 2 mt.c = 3 local = setmetatable({}, {__index = mt}) ]] [[ local obj: { a: number = 1, b: number = 2, c: number = 3, } ]] TEST[[ local mt = {} mt.__index = {} function mt:test(a, b) self:() end ]] [[ function mt:test(a: any, b: any) ]] TEST[[ local mt = {} mt.__index = mt mt.__name = 'obj' function mt:remove() end local = setmetatable({ id = 1, }, mt) ]] [[ local self: *obj { __index: table, __name: string = "obj", id: number = 1, remove: function, } ]] TEST[[ local = require 'utf8' ]] [[ local sssss: { char: function, charpattern: string, codepoint: function, codes: function, len: function, offset: function, } ]] TEST[[ function a(v) print() end a(1) ]] [[ local v: number = 1 ]] TEST[[ function a(v) print() end pcall(a, 1) ]] [[ local v: number = 1 ]] TEST[[ function a(v) print() end xpcall(a, log.error, 1) ]] [[ local v: number = 1 ]] TEST[[ function a(v) return 'a' end local _, = pcall(a, 1) ]] [[ local r: string = "a" ]] TEST[[ local = rawlen() ]] [[ local n: integer ]] TEST[[ () ]] [[ function next(table: table [, index: any]) -> key: any, value: any ]] TEST[[ local = pairs() ]] [[ function n(table: table [, index: any]) -> key: any, value: any ]] TEST[[ ---@class Class local = class() ]] [[ local x: *Class {} ]] TEST[[ ---@class Class = class() ]] [[ global x: *Class {} ]] TEST[[ local t = { ---@class Class = class() } ]] [[ field x: *Class {} ]] TEST[[ ---@type Class local = class() ]] [[ local x: *Class {} ]] TEST[[ ---@type Class = class() ]] [[ global x: *Class {} ]] TEST[[ local t = { ---@type Class = class() } ]] [[ field x: *Class {} ]] TEST[[ ---@type A|B|C local = class() ]] [[ local x: *A|B|C {} ]] TEST[[ ---@class Class local = { b = 1 } ]] [[ local x: *Class { b: number = 1, } ]] TEST [[ ---@class Class local mt = {} ---@param t Class function f() end ]] [[ local t: *Class {} ]] TEST [[ ---@class Class local mt = {} ---@param t Class function f(t) print() end ]] [[ local t: *Class {} ]] TEST [[ ---@class Class local mt = {} ---@param t Class function f(t) end f() ]] [[ global s: *Class {} ]] TEST [[ ---@class Class ---@param k Class for in pairs(t) do end ]] [[ local k: *Class {} ]] TEST [[ ---@class Class ---@param v Class for k, in pairs(t) do end ]] [[ local v: *Class {} ]] TEST [[ ---@return A|B ---@return C local function () end ]] [[ function f() -> A|B, C ]] TEST [[ ---@generic T ---@param x T ---@return T local function f(x) end local = f(1) ]] [[ local r: number ]] TEST [[ ---@param x number ---@param y boolean local function (x, y) end ]] [[ function f(x: number, y: boolean) ]] TEST [[ ---@vararg Class local function f(...) local _, = ... end f(1, 2, 3) ]] [[ local x: *Class = 2 ]] TEST [[ ---@vararg Class local function f(...) local _, = ... end ]] [[ local x: *Class {} ]] TEST [[ ---@type string[] local ]] [[ local x: { [*integer]: string, } ]] TEST [[ ---@type string[] local t local = t[1] ]] [[ local x: string ]] TEST [[ ---@type string[] local t for _, in ipairs(t) do end ]] [[ local x: string ]] TEST [[ ---@type string[] local t for _, in pairs(t) do end ]] [[ local x: string ]] TEST [[ ---@type string[] local t for , v in pairs(t) do end ]] [[ local k: integer ]] TEST [[ ---@type table local ]] [[ local x: { [*ClassA]: ClassB, } ]] TEST [[ ---@type table local t for _, in pairs(t) do end ]] [[ local x: *ClassB ]] TEST [[ ---@type table local t for , v in pairs(t) do end ]] [[ local k: *ClassA ]] TEST [[ ---@type fun(x: number, y: number):boolean local ]] [[ function f(x: number, y: number) -> boolean ]] TEST [[ ---@type fun(x: number, y: number):boolean local f f() ]] [[ global a: number ]] TEST [[ ---@type fun(x: number, y: number):boolean local f local = f() ]] [[ local r: boolean ]] TEST [[ ---@param f fun():void function t() end ]] [[ function () -> any ]] TEST [[ ---@param names string[] local function f() end ]] [[ local names: { [*integer]: string, } ]] TEST [[ ---@return any function () ---@type integer local a return a end ]] [[ function f() -> any ]] TEST [[ ---@return any function f() ---@type integer local a return a end local = f() ]] [[ local x: any ]] TEST [[ local = 1 ]] [[ local x: number = 1 ]]