local core = require 'core.hover' local files = require 'files' rawset(_G, 'TEST', true) function TEST(script) return function (expect) files.removeAll() local start = script:find('', 1, true) local pos = (start + finish) // 2 + 1 local new_script = script:gsub('<[!?]', ' '):gsub('[!?]>', ' ') files.setText('', new_script) local hover = core.byUri('', pos) 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) 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: any, b: any, c: any) ]] TEST [[ local mt = {} mt.__index = mt mt.type = 'Class' function mt:init(a, b, c) return end local obj = setmetatable({}, mt) obj:(1, '测试') ]] [[ function Class:init(a: any, b: any, c: any) ]] TEST [[ local mt = {} mt.__index = mt mt.__name = 'Class' function mt:init(a, b, c) return end local obj = setmetatable({}, mt) obj:(1, '测试') ]] [[ function Class:init(a: any, b: any, c: 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: any, b: any, 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(a: any, b: any, c: any) -> table ]] TEST [[ function obj.xxx() end obj.() ]] "function obj.xxx()" TEST [[ obj.() ]] [[global obj.xxx: any]] TEST [[ local = 1 ]] "local x: integer = 1" TEST [[ = 1 ]] "global x: integer = 1" TEST [[ local t = {} t. = 1 ]] "field t.x: integer = 1" TEST [[ t = {} t. = 1 ]] "global t.x: integer = 1" TEST [[ t = { = 1 } ]] "field x: integer = 1" TEST [[ local = {} ]] "local obj: {}" 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: class, name: string = "class", } ]] TEST [[ local mt = {} mt.TYPE = 'class' mt.__index = mt local = setmetatable({}, mt) ]] [[ local obj: class { TYPE: string = "class", __index: class, } ]] TEST [[ local mt = {} mt.Class = 'class' mt.__index = mt local = setmetatable({}, mt) ]] [[ local obj: class { Class: string = "class", __index: class, } ]] -- TODO 支持自定义的函数库 --TEST[[ --local fs = require 'bee.filesystem' --local = fs.current_path() --]] --"local root: bee::filesystem" TEST [[ () ]] [[ function print(...) ]] TEST [[ string.() ]] [[ function string.sub(string, i: integer [, j: integer]) -> string ]] TEST[[ ('xx'):() ]] [[function string:sub(i: integer [, j: integer]) -> string]] TEST [[ local = collectgarbage() ]] "local v: any" TEST [[ local type w2l:get_default()[] ]] "local type: any" -- TODO 可选参数(或多原型) TEST [[ () ]] [=[ function load(chunk: string|function [, chunkname: string [, mode: string [, env: table]]]) -> function 2. 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: any, ...) ]] TEST [[ local function x() return y() end () ]] [[ function x() -> any ]] TEST [[ local mt = {} function mt:add(a, b) end local function init() return mt end local t = init() t:() ]] [[ function mt:add(a: any, b: 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: integer = -1000]] -- TODO 暂不支持 --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 [[ local s = ]] [[9 个字节,5 个字符]] TEST [[ local n = ]] [[255]] TEST [[ local = { a = 1, b = 2, c = 3, } ]] [[ local t: { a: integer = 1, b: integer = 2, c: integer = 3, } ]] TEST [[ local = {} t.a = 1 t.a = true ]] [[ local t: { a: boolean|integer = 1|true, } ]] TEST [[ local = { a = 1, [1] = 2, [true] = 3, [5.5] = 4, [{}] = 5, [function () end] = 6, ["b"] = 7, ["012"] = 8, } ]] [[ local t: { a: integer = 1, [1]: integer = 2, [true]: integer = 3, [5.5]: integer = 4, [table]: integer = 5, [function]: integer = 6, b: integer = 7, ["012"]: integer = 8, } ]] TEST [[ local = {} t[#t+1] = 1 t[#t+1] = 1 local any = collectgarbage() t[any] = any ]] [[ local t: { [integer]: integer = 1, } ]] TEST[[ local x = 1 local y = x print() ]] [[ local y: integer = 1 ]] TEST[[ local mt = {} mt.a = 1 mt.b = 2 mt.c = 3 local = setmetatable({}, {__index = mt}) ]] [[ local obj: { a: integer = 1, b: integer = 2, c: integer = 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: obj, __name: string = "obj", id: integer = 1, remove: function, } ]] TEST [[ print() ]] [[ global utf8: utf8 { char: function, charpattern: string, codepoint: function, codes: function, len: function, offset: function, } ]] TEST [[ print(io.) ]] [[ global io.stderr: FILE* ]] TEST [[ print() ]] [[ global io: io { close: function, flush: function, input: function, lines: function, open: function, output: function, popen: function, read: function, stderr: FILE*, stdin: FILE*, stdout: FILE*, tmpfile: function, type: function, write: function, } ]] TEST [[ local = require 'utf8' ]] [[ local sssss: utf8 { char: function, charpattern: string, codepoint: function, codes: function, len: function, offset: function, } ]] TEST [[ function F(a) end function F(b) end function F(a) end () ]] [[ (3 个定义,2 个原型) (2) function F(a: any) (1) function F(b: any) ]] -- 不根据参数推断 --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 = a(1) ]] [[ local r: string = "a" ]] 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 2. value: any ]] -- TODO 暂未实现 --TEST[[ --local = pairs() --]] --[[ --function n(table: table [, index: any]) -- -> key: any, value: any --]] TEST[[ local = '\a' ]] [[local x: string = "\007"]] TEST [[ local = { b = 1, c = 2, d = 3, a = 4, s = 5, y = 6, z = 7, q = 8, g = 9, p = 10, l = 11, } ]] [[ local t: { b: integer = 1, c: integer = 2, d: integer = 3, a: integer = 4, s: integer = 5, y: integer = 6, z: integer = 7, q: integer = 8, g: integer = 9, p: integer = 10, l: integer = 11, } ]] TEST [[ local function () return nil, nil end ]] [[ function f() -> nil 2. nil ]] TEST [[ local function f() return nil end local = f() ]] [[ local x: nil ]] TEST [[ local function () return 1 return nil end ]] [[ function f() -> integer|nil ]] TEST [[ local = { b = 1, c = 2, d = 3, } local e = t.b ]] [[ local t: { b: integer = 1, c: integer = 2, d: integer = 3, } ]] TEST [[ local = { b = 1, c = 2, d = 3, } g.e = t.b ]] [[ local t: { b: integer = 1, c: integer = 2, d: integer = 3, } ]] TEST [[ local t = { v = { b = 1, c = 2, d = 3, } } print(t.) ]] [[ field t.v: { b: integer = 1, c: integer = 2, d: integer = 3, } ]] TEST [[ local = { f = io.open(), } ]] [[ local t: { f: FILE*, } ]] TEST [[ io.() ]] [[ function io.popen(prog: string [, mode: string]) -> FILE*|nil 2.[error_message: string] ]] TEST [[ ]] [[ global _G: _G { _G: _G, _VERSION: string, arg: arg, assert: function, collectgarbage: function, coroutine: coroutine, debug: debug, dofile: function, error: function, getmetatable: function, io: io, ipairs: function, load: function, loadfile: function, math: math, next: function, os: os, package: package, pairs: function, pcall: function, print: function, rawequal: function, rawget: function, rawlen: function, rawset: function, require: function, select: function, setmetatable: function, string: string, table: table, tonumber: function, tostring: function, type: function, utf8: utf8, warn: function, xpcall: function, } ]] TEST [[ local x x = 1 x = 1.0 print() ]] [[ local x: number = 1 ]] TEST [[ local = 1 ]] [[ local x : integer = 1 ]] --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|boolean)[] --local --]] --[[ --local x: { -- [*integer]: string|boolean, --} --]] -- --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 () -- -> void --]] -- --TEST [[ -----@type fun(a:any, b:any) --local f --local t = {f = f} --t:() --]] --[[ --function f(b: any) -- -> 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 [[ -----@param x number {optional = 'after'} -----@param y boolean {optional = 'self'} -----@param z string --function (x, y, z) end --]] --[=[ --function f([x: number [, y: boolean], z: string]) --]=] -- --TEST [[ -----@return string {name = 'key'} -----@return string {name = 'value'} --function () end --]] --[=[ --function f() -- -> key: string, value: string --]=] -- --TEST [[ -----@return {name = 'x', optional = 'after'} -----@return string {name = 'y', optional = 'self'} -----@return string {name = 'z'} --function () end --]] --[=[ --function f() -- -> [x: any [, y: string], z: string] --]=] -- --TEST [[ -----@return {name = 'x', optional = 'after'} -----@return string {name = 'y', optional = 'self'} -----@return string {name = 'z'} --function f() -- return function (a, b) -- end --end -- -- = f() --]] --[=[ --function f2(a: any, b: any) --]=]