diff options
37 files changed, 1610 insertions, 78 deletions
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..7414d190 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,18 @@ +name: test +on: [ push, pull_request ] +jobs: + test: + strategy: + fail-fast: false + matrix: + include: + - { os: ubuntu-20.04, platform: linux-x64 } + - { os: macos-latest, platform: darwin-x64 } + - { os: windows-latest, platform: win32-x64 } + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - uses: actboy168/setup-luamake@master + - run: luamake -platform ${{ matrix.platform }} diff --git a/3rd/bee.lua b/3rd/bee.lua -Subproject b5bf3647e8ba493f2f4d83bed61a29ba8969f12 +Subproject dfed9f99d272fedb70c8161d9250918c17d285b diff --git a/3rd/json.lua b/3rd/json.lua -Subproject 93dd093c872fb9e0415641eb9e7db3ce7f915d7 +Subproject 21c9584d30fa36c542c98b6b141039331858371 diff --git a/3rd/luamake b/3rd/luamake -Subproject 9aee7c80b3386fcb9739473be2f8931fad3e9a1 +Subproject 13bf00fb858a24c709ddbdc372ec01cc645609b diff --git a/changelog.md b/changelog.md index bd0fe839..20110331 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,8 @@ # changelog +## 3.7.5 +* `FIX` rename in library files + ## 3.7.4 `2024-1-5` * `FIX` rename to unicode with `Lua.runtime.unicodeName = true` diff --git a/meta/template/table.lua b/meta/template/table.lua index a2e9580b..84eb3659 100644 --- a/meta/template/table.lua +++ b/meta/template/table.lua @@ -27,7 +27,7 @@ function table.insert(list, pos, value) end ---@nodiscard function table.maxn(table) end ----@version >5.3 +---@version >5.3, JIT ---#DES 'table.move' ---@param a1 table ---@param f integer diff --git a/script/cli/doc.lua b/script/cli/doc.lua index 9140a258..fb9b0a8e 100644 --- a/script/cli/doc.lua +++ b/script/cli/doc.lua @@ -169,6 +169,7 @@ local function collectTypes(global, results) field.desc = getDesc(source) field.rawdesc = getDesc(source, true) field.extends = packObject(source.extends) + field.visible = vm.getVisibleType(source) return end if source.type == 'setfield' @@ -187,6 +188,7 @@ local function collectTypes(global, results) field.desc = getDesc(source) field.rawdesc = getDesc(source, true) field.extends = packObject(source.value) + field.visible = vm.getVisibleType(source) return end if source.type == 'tableindex' then @@ -207,6 +209,7 @@ local function collectTypes(global, results) field.desc = getDesc(source) field.rawdesc = getDesc(source, true) field.extends = packObject(source.value) + field.visible = vm.getVisibleType(source) return end end) @@ -245,6 +248,8 @@ local function collectVars(global, results) } result.desc = result.desc or getDesc(set) result.rawdesc = result.rawdesc or getDesc(set, true) + result.defines[#result.defines].extends['desc'] = getDesc(set) + result.defines[#result.defines].extends['rawdesc'] = getDesc(set, true) end end if #result.defines == 0 then @@ -292,6 +297,18 @@ function export.export(outputPath, callback) return docPath, mdPath end +function export.getDocOutputPath() + local doc_output_path = '' + if type(DOC_OUT_PATH) == 'string' then + doc_output_path = fs.absolute(fs.path(DOC_OUT_PATH)):string() + elseif DOC_OUT_PATH == true then + doc_output_path = fs.current_path():string() + else + doc_output_path = LOGPATH + end + return doc_output_path +end + ---@async ---@param outputPath string function export.makeDoc(outputPath) @@ -350,7 +367,7 @@ function export.runCLI() ws.awaitReady(rootUri) await.sleep(0.1) - local docPath, mdPath = export.export(LOGPATH, function (i, max) + local docPath, mdPath = export.export(export.getDocOutputPath(), function (i, max) if os.clock() - lastClock > 0.2 then lastClock = os.clock() local output = '\x0D' diff --git a/script/cli/init.lua b/script/cli/init.lua index b5a9f86d..6d7fc0ff 100644 --- a/script/cli/init.lua +++ b/script/cli/init.lua @@ -12,3 +12,8 @@ if _G['DOC'] then require 'cli.doc' .runCLI() os.exit(0, true) end + +if _G['VISUALIZE'] then + local ret = require 'cli.visualize' .runCLI() + os.exit(ret or 0, true) +end diff --git a/script/cli/visualize.lua b/script/cli/visualize.lua new file mode 100644 index 00000000..29269b82 --- /dev/null +++ b/script/cli/visualize.lua @@ -0,0 +1,103 @@ +local lang = require 'language' +local parser = require 'parser' +local guide = require 'parser.guide' + +local function nodeId(node) + return node.type .. ':' .. node.start .. ':' .. node.finish +end + +local function shorten(str) + if type(str) ~= 'string' then + return str + end + str = str:gsub('\n', '\\\\n') + if #str <= 20 then + return str + else + return str:sub(1, 17) .. '...' + end +end + +local function getTooltipLine(k, v) + if type(v) == 'table' then + if v.type then + v = '<node ' .. v.type .. '>' + else + v = '<table>' + end + end + v = tostring(v) + v = v:gsub('"', '\\"') + return k .. ': ' .. shorten(v) .. '\\n' +end + +local function getTooltip(node) + local str = '' + local skipNodes = {parent = true, start = true, finish = true, type = true} + str = str .. getTooltipLine('start', node.start) + str = str .. getTooltipLine('finish', node.finish) + for k, v in pairs(node) do + if type(k) ~= 'number' and not skipNodes[k] then + str = str .. getTooltipLine(k, v) + end + end + for i = 1, math.min(#node, 15) do + str = str .. getTooltipLine(i, node[i]) + end + if #node > 15 then + str = str .. getTooltipLine('15..' .. #node, '(...)') + end + return str +end + +local nodeEntry = '\t"%s" [\n\t\tlabel="%s\\l%s\\l"\n\t\ttooltip="%s"\n\t]' +local function getNodeLabel(node) + local keyName = guide.getKeyName(node) + if node.type == 'binary' or node.type == 'unary' then + keyName = node.op.type + elseif node.type == 'label' or node.type == 'goto' then + keyName = node[1] + end + return nodeEntry:format(nodeId(node), node.type, shorten(keyName) or '', getTooltip(node)) +end + +local function getVisualizeVisitor(writer) + local function visitNode(node, parent) + if node == nil then return end + writer:write(getNodeLabel(node)) + writer:write('\n') + if parent then + writer:write(('\t"%s" -> "%s"'):format(nodeId(parent), nodeId(node))) + writer:write('\n') + end + guide.eachChild(node, function(child) + visitNode(child, node) + end) + end + return visitNode +end + + +local export = {} + +function export.visualizeAst(code, writer) + local state = parser.compile(code, 'Lua', _G['LUA_VER'] or 'Lua 5.4') + writer:write('digraph AST {\n') + writer:write('\tnode [shape = rect]\n') + getVisualizeVisitor(writer)(state.ast) + writer:write('}\n') +end + +function export.runCLI() + lang(LOCALE) + local file = _G['VISUALIZE'] + local code, err = io.open(file) + if not code then + io.stderr:write('failed to open ' .. file .. ': ' .. err) + return 1 + end + code = code:read('a') + return export.visualizeAst(code, io.stdout) +end + +return export diff --git a/script/core/rename.lua b/script/core/rename.lua index cc5d37f3..534a972a 100644 --- a/script/core/rename.lua +++ b/script/core/rename.lua @@ -414,7 +414,11 @@ function m.rename(uri, pos, newname) return end mark[uid] = true - if files.isLibrary(turi, true) then + if vm.isMetaFile(turi) then + return + end + if files.isLibrary(turi, true) + and not files.isLibrary(uri, true) then return end results[#results+1] = { diff --git a/script/core/semantic-tokens.lua b/script/core/semantic-tokens.lua index 4e1d8e00..e908ef7b 100644 --- a/script/core/semantic-tokens.lua +++ b/script/core/semantic-tokens.lua @@ -882,6 +882,10 @@ return function (uri, start, finish) local n = 0 guide.eachSourceBetween(state.ast, start, finish, function (source) ---@async + -- skip virtual source + if source.virtual then + return + end Care(source.type, source, options, results) n = n + 1 if n % 100 == 0 then @@ -890,6 +894,10 @@ return function (uri, start, finish) end) for _, comm in ipairs(state.comms) do + -- skip virtual comment + if comm.virtual then + return + end if start <= comm.start and comm.finish <= finish then local headPos = (comm.type == 'comment.short' and comm.text:match '^%-%s*[@|]()') or (comm.type == 'comment.long' and comm.text:match '^@()') diff --git a/script/encoder/ansi.lua b/script/encoder/ansi.lua index f5273c51..7cb64ec3 100644 --- a/script/encoder/ansi.lua +++ b/script/encoder/ansi.lua @@ -1,24 +1,24 @@ local platform = require 'bee.platform' -local unicode +local windows if platform.OS == 'Windows' then - unicode = require 'bee.unicode' + windows = require 'bee.windows' end local m = {} function m.toutf8(text) - if not unicode then + if not windows then return text end - return unicode.a2u(text) + return windows.a2u(text) end function m.fromutf8(text) - if not unicode then + if not windows then return text end - return unicode.u2a(text) + return windows.u2a(text) end return m diff --git a/script/global.d.lua b/script/global.d.lua index b44d6371..cee9e01b 100644 --- a/script/global.d.lua +++ b/script/global.d.lua @@ -52,6 +52,10 @@ CHECK = '' ---@type string DOC = '' +--output directory path for documentation (doc.json, ...) +---@type string +DOC_OUT_PATH = '' + ---@type string | '"Error"' | '"Warning"' | '"Information"' | '"Hint"' CHECKLEVEL = 'Warning' diff --git a/script/parser/guide.lua b/script/parser/guide.lua index 4e71c832..fd779da0 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -10,7 +10,7 @@ local type = type ---@field type string ---@field special string ---@field tag string ----@field args { [integer]: parser.object, start: integer, finish: integer } +---@field args { [integer]: parser.object, start: integer, finish: integer, type: string } ---@field locals parser.object[] ---@field returns? parser.object[] ---@field breaks? parser.object[] @@ -1313,12 +1313,18 @@ end function m.getParams(source) if source.type == 'call' then local args = source.args + if not args then + return + end assert(args.type == 'callargs', 'call.args type is\'t callargs') return args elseif source.type == 'callargs' then return source elseif source.type == 'function' then local args = source.args + if not args then + return + end assert(args.type == 'funcargs', 'function.args type is\'t callargs') return args end diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index 47396df6..edbfd34e 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -369,6 +369,78 @@ local function parseTable(parent) return typeUnit end +local function parseTuple(parent) + if not checkToken('symbol', '[', 1) then + return nil + end + nextToken() + local typeUnit = { + type = 'doc.type.table', + start = getStart(), + parent = parent, + fields = {}, + isTuple = true, + } + + local index = 1 + while true do + if checkToken('symbol', ']', 1) then + nextToken() + break + end + local field = { + type = 'doc.type.field', + parent = typeUnit, + } + + do + local needCloseParen + if checkToken('symbol', '(', 1) then + nextToken() + needCloseParen = true + end + field.name = { + type = 'doc.type', + start = getFinish(), + firstFinish = getFinish(), + finish = getFinish(), + parent = field, + } + field.name.types = { + [1] = { + type = 'doc.type.integer', + start = getFinish(), + finish = getFinish(), + parent = field.name, + [1] = index, + } + } + index = index + 1 + field.extends = parseType(field) + if not field.extends then + break + end + field.optional = field.extends.optional + field.start = field.extends.start + field.finish = field.extends.finish + if needCloseParen then + nextSymbolOrError ')' + end + end + + typeUnit.fields[#typeUnit.fields+1] = field + if checkToken('symbol', ',', 1) + or checkToken('symbol', ';', 1) then + nextToken() + else + nextSymbolOrError(']') + break + end + end + typeUnit.finish = getFinish() + return typeUnit +end + local function parseSigns(parent) if not checkToken('symbol', '<', 1) then return nil @@ -729,6 +801,7 @@ end function parseTypeUnit(parent) local result = parseFunction(parent) or parseTable(parent) + or parseTuple(parent) or parseString(parent) or parseCode(parent) or parseInteger(parent) @@ -912,6 +985,7 @@ local docSwitch = util.switch() while true do local extend = parseName('doc.extends.name', result) or parseTable(result) + or parseTuple(result) if not extend then pushWarning { type = 'LUADOC_MISS_CLASS_EXTENDS_NAME', @@ -2050,7 +2124,10 @@ local function bindDocs(state) state.ast.docs.groups[#state.ast.docs.groups+1] = binded end binded[#binded+1] = doc - if isTailComment(text, doc) then + if doc.specialBindGroup then + bindDocWithSources(sources, doc.specialBindGroup) + binded = nil + elseif isTailComment(text, doc) and doc.type ~= "doc.class" and doc.type ~= "doc.field" then bindDocWithSources(sources, binded) binded = nil else @@ -2154,11 +2231,13 @@ local function luadoc(state) end end end - + if ast.state.pluginDocs then for i, doc in ipairs(ast.state.pluginDocs) do insertDoc(doc, doc.originalComment) end + ---@param a unknown + ---@param b unknown table.sort(ast.docs, function (a, b) return a.start < b.start end) @@ -2176,7 +2255,7 @@ local function luadoc(state) end return { - buildAndBindDoc = function (ast, src, comment) + buildAndBindDoc = function (ast, src, comment, group) local doc = buildLuaDoc(comment) if doc then local pluginDocs = ast.state.pluginDocs or {} @@ -2184,6 +2263,7 @@ return { doc.special = src doc.originalComment = comment doc.virtual = true + doc.specialBindGroup = group ast.state.pluginDocs = pluginDocs return doc end diff --git a/script/plugin.lua b/script/plugin.lua index 7a661e0d..b297cd9b 100644 --- a/script/plugin.lua +++ b/script/plugin.lua @@ -7,6 +7,15 @@ local scope = require 'workspace.scope' local ws = require 'workspace' local fs = require 'bee.filesystem' +---@class pluginInterfaces +local pluginConfigs = { + -- create plugin for vm module + VM = { + OnCompileFunctionParam = function (next, func, source) + end + } +} + ---@class plugin local m = {} @@ -51,6 +60,15 @@ function m.dispatch(event, uri, ...) return failed == 0, res1, res2 end +function m.getVmPlugin(uri) + local scp = scope.getScope(uri) + local interfaces = scp:get('pluginInterfaces') + if not interfaces then + return + end + return interfaces.VM +end + ---@async ---@param scp scope local function checkTrustLoad(scp) @@ -78,6 +96,40 @@ local function checkTrustLoad(scp) return true end +local function createMethodGroup(interfaces, key, methods) + local methodGroup = {} + + for method in pairs(methods) do + local funcs = setmetatable({}, { + __call = function (t, next, ...) + if #t == 0 then + return next(...) + else + local result + for _, fn in ipairs(t) do + result = fn(next, ...) + end + return result + end + end + }) + for _, interface in ipairs(interfaces) do + local func = interface[method] + if not func then + local namespace = interface[key] + if namespace then + func = namespace[method] + end + end + if func then + funcs[#funcs+1] = func + end + end + methodGroup[method] = funcs + end + return #methodGroup>0 and methodGroup or nil +end + ---@param uri uri local function initPlugin(uri) await.call(function () ---@async @@ -148,6 +200,11 @@ local function initPlugin(uri) end interfaces[#interfaces+1] = interface end + + for key, config in pairs(pluginConfigs) do + interfaces[key] = createMethodGroup(interfaces, key, config) + end + ws.resetFiles(scp) end) end diff --git a/script/plugins/astHelper.lua b/script/plugins/astHelper.lua index aba09478..bfe2dd27 100644 --- a/script/plugins/astHelper.lua +++ b/script/plugins/astHelper.lua @@ -23,14 +23,27 @@ end ---@param ast parser.object ---@param source parser.object local/global variable ---@param classname string -function _M.addClassDoc(ast, source, classname) +---@param group table? +function _M.addClassDoc(ast, source, classname, group) + return _M.addDoc(ast, source, "class", classname, group) +end + +--- give the local/global variable a luadoc comment +---@param ast parser.object +---@param source parser.object local/global variable +---@param key string +---@param value string +---@param group table? +function _M.addDoc(ast, source, key, value, group) if source.type ~= 'local' and not guide.isGlobal(source) then return false end - --TODO fileds - --TODO callers - local comment = _M.buildComment("class", classname, source.start - 1) - return luadoc.buildAndBindDoc(ast, source, comment) + local comment = _M.buildComment(key, value, source.start - 1) + local doc = luadoc.buildAndBindDoc(ast, source, comment, group) + if group then + group[#group+1] = doc + end + return doc end ---remove `ast` function node `index` arg, the variable will be the function local variable @@ -57,7 +70,7 @@ end function _M.addClassDocAtParam(ast, classname, source, index) local arg = _M.removeArg(source, index) if arg then - return _M.addClassDoc(ast, arg, classname), arg + return not not _M.addClassDoc(ast, arg, classname), arg end return false end diff --git a/script/plugins/nodeHelper.lua b/script/plugins/nodeHelper.lua new file mode 100644 index 00000000..3f90b152 --- /dev/null +++ b/script/plugins/nodeHelper.lua @@ -0,0 +1,75 @@ +local vm = require 'vm' +local guide = require 'parser.guide' + +local _M = {} + +---@class node.match.pattern +---@field next node.match.pattern? + +local function deepCompare(source, pattern) + local type1, type2 = type(source), type(pattern) + if type1 ~= type2 then + return false + end + + if type1 ~= "table" then + return source == pattern + end + + for key2, value2 in pairs(pattern) do + local value1 = source[key2] + if value1 == nil or not deepCompare(value1, value2) then + return false + end + end + + return true +end + +---@param source parser.object +---@param pattern node.match.pattern +---@return boolean +function _M.matchPattern(source, pattern) + if source.type == 'local' then + if source.parent.type == 'funcargs' and source.parent.parent.type == 'function' then + for i, ref in ipairs(source.ref) do + if deepCompare(ref, pattern) then + return true + end + end + end + end + return false +end + +local vaildVarRegex = "()([a-zA-Z][a-zA-Z0-9_]*)()" +---创建类型 *.field.field形式的 pattern +---@param pattern string +---@return node.match.pattern?, string? +function _M.createFieldPattern(pattern) + local ret = { next = nil } + local next = ret + local init = 1 + while true do + local startpos, matched, endpos + if pattern:sub(1, 1) == "*" then + startpos, matched, endpos = init, "*", init + 1 + else + startpos, matched, endpos = vaildVarRegex:match(pattern, init) + end + if not startpos then + break + end + if startpos ~= init then + return nil, "invalid pattern" + end + local field = matched == "*" and { next = nil } + or { field = { type = 'field', matched }, type = 'getfield', next = nil } + next.next = field + next = field + pattern = pattern:sub(endpos) + end + return ret +end + +return _M diff --git a/script/proto/proto.lua b/script/proto/proto.lua index d01c8f36..2460b4ec 100644 --- a/script/proto/proto.lua +++ b/script/proto/proto.lua @@ -1,5 +1,3 @@ -local subprocess = require 'bee.subprocess' -local socket = require 'bee.socket' local util = require 'utility' local await = require 'await' local pub = require 'pub' @@ -7,7 +5,7 @@ local jsonrpc = require 'jsonrpc' local define = require 'proto.define' local json = require 'json' local inspect = require 'inspect' -local thread = require 'bee.thread' +local platform = require 'bee.platform' local fs = require 'bee.filesystem' local net = require 'service.net' local timer = require 'timer' @@ -234,8 +232,11 @@ end function m.listen(mode, socketPort) m.mode = mode if mode == 'stdio' then - subprocess.filemode(io.stdin, 'b') - subprocess.filemode(io.stdout, 'b') + if platform.OS == 'Windows' then + local windows = require 'bee.windows' + windows.filemode(io.stdin, 'b') + windows.filemode(io.stdout, 'b') + end io.stdin:setvbuf 'no' io.stdout:setvbuf 'no' pub.task('loadProtoByStdio') diff --git a/script/vm/compiler.lua b/script/vm/compiler.lua index 2222fa9b..2253c83a 100644 --- a/script/vm/compiler.lua +++ b/script/vm/compiler.lua @@ -5,6 +5,7 @@ local rpath = require 'workspace.require-path' local files = require 'files' ---@class vm local vm = require 'vm.vm' +local plugin = require 'plugin' ---@class parser.object ---@field _compiledNodes boolean @@ -1031,6 +1032,55 @@ local function compileForVars(source, target) end ---@param source parser.object +local function compileFunctionParam(func, source) + -- local call ---@type fun(f: fun(x: number));call(function (x) end) --> x -> number + local funcNode = vm.compileNode(func) + for n in funcNode:eachObject() do + if n.type == 'doc.type.function' then + for index, arg in ipairs(n.args) do + if func.args[index] == source then + local argNode = vm.compileNode(arg) + for an in argNode:eachObject() do + if an.type ~= 'doc.generic.name' then + vm.setNode(source, an) + end + end + return true + end + end + end + end + if func.parent.type == 'local' then + local refs = func.parent.ref + local findCall + if refs then + for i, ref in ipairs(refs) do + if ref.parent.type == 'call' then + findCall = ref.parent + break + end + end + end + if findCall and findCall.args then + local index + for i, arg in ipairs(source.parent) do + if arg == source then + index = i + break + end + end + if index then + local callerArg = findCall.args[index] + if callerArg then + vm.setNode(source, vm.compileNode(callerArg)) + return true + end + end + end + end +end + +---@param source parser.object local function compileLocal(source) local myNode = vm.setNode(source, source) @@ -1069,7 +1119,6 @@ local function compileLocal(source) vm.setNode(source, vm.compileNode(setfield.node)) end end - if source.parent.type == 'funcargs' and not hasMarkDoc and not hasMarkParam then local func = source.parent.parent -- local call ---@type fun(f: fun(x: number));call(function (x) end) --> x -> number @@ -1090,35 +1139,6 @@ local function compileLocal(source) end end end - if not hasDocArg - and func.parent.type == 'local' then - local refs = func.parent.ref - local findCall - if refs then - for i, ref in ipairs(refs) do - if ref.parent.type == 'call' then - findCall = ref.parent - break - end - end - end - if findCall and findCall.args then - local index - for i, arg in ipairs(source.parent) do - if arg == source then - index = i - break - end - end - if index then - local callerArg = findCall.args[index] - if callerArg then - hasDocArg = true - vm.setNode(source, vm.compileNode(callerArg)) - end - end - end - end if not hasDocArg then vm.setNode(source, vm.declareGlobal('type', 'any')) end diff --git a/script/vm/infer.lua b/script/vm/infer.lua index f2673ed3..3f3d0e3a 100644 --- a/script/vm/infer.lua +++ b/script/vm/infer.lua @@ -157,22 +157,24 @@ local viewNodeSwitch;viewNodeSwitch = util.switch() end infer._hasClass = true local buf = {} - buf[#buf+1] = '{ ' + buf[#buf+1] = source.isTuple and '[' or '{ ' for i, field in ipairs(source.fields) do if i > 1 then buf[#buf+1] = ', ' end - local key = field.name - if key.type == 'doc.type' then - buf[#buf+1] = ('[%s]: '):format(vm.getInfer(key):view(uri)) - elseif type(key[1]) == 'string' then - buf[#buf+1] = key[1] .. ': ' - else - buf[#buf+1] = ('[%q]: '):format(key[1]) + if not source.isTuple then + local key = field.name + if key.type == 'doc.type' then + buf[#buf+1] = ('[%s]: '):format(vm.getInfer(key):view(uri)) + elseif type(key[1]) == 'string' then + buf[#buf+1] = key[1] .. ': ' + else + buf[#buf+1] = ('[%q]: '):format(key[1]) + end end buf[#buf+1] = vm.getInfer(field.extends):view(uri) end - buf[#buf+1] = ' }' + buf[#buf+1] = source.isTuple and ']' or ' }' return table.concat(buf) end) : case 'doc.type.string' diff --git a/script/workspace/scope.lua b/script/workspace/scope.lua index da72a1eb..789b5f81 100644 --- a/script/workspace/scope.lua +++ b/script/workspace/scope.lua @@ -125,8 +125,6 @@ function mt:set(k, v) return v end ----@param k string ----@return any function mt:get(k) return self._data[k] end @@ -108,6 +108,7 @@ local function main() test 'tclient' test 'full' test 'plugins.test' + test 'cli.test' end loadAllLibs() diff --git a/test/cli/test.lua b/test/cli/test.lua new file mode 100644 index 00000000..7b988f68 --- /dev/null +++ b/test/cli/test.lua @@ -0,0 +1 @@ +require 'cli.visualize.test' diff --git a/test/cli/visualize/test.lua b/test/cli/visualize/test.lua new file mode 100644 index 00000000..c9722c32 --- /dev/null +++ b/test/cli/visualize/test.lua @@ -0,0 +1,23 @@ +local visualize = require 'cli.visualize' + +local testDataDir = 'test/cli/visualize/testdata/' + +local function TestVisualize(fileName) + local inputFile = testDataDir .. fileName .. '.txt' + local outputFile = testDataDir .. fileName .. '-expected.txt' + local output = '' + local writer = {} + function writer:write(text) + output = output .. text + end + visualize.visualizeAst(io.open(inputFile):read('a'), writer) + local expectedOutput = io.open(outputFile):read('a') + if expectedOutput ~= output then + -- uncomment this to update reference output + --io.open(outputFile, "w+"):write(output):close() + error('output mismatch for test file ' .. inputFile) + end +end + +TestVisualize('all-types') +TestVisualize('shorten-names') diff --git a/test/cli/visualize/testdata/all-types-expected.txt b/test/cli/visualize/testdata/all-types-expected.txt new file mode 100644 index 00000000..5391658c --- /dev/null +++ b/test/cli/visualize/testdata/all-types-expected.txt @@ -0,0 +1,587 @@ +digraph AST { + node [shape = rect] + "main:0:300000" [ + label="main\l\l" + tooltip="start: 0\nfinish: 300000\nlocals: <table>\nstate: <table>\nreturns: <table>\n1: <node setglobal>\n2: <node setfield>\n3: <node setindex>\n4: <node setmethod>\n5: <node local>\n6: <node while>\n7: <node call>\n8: <node loop>\n9: <node setglobal>\n10: <node if>\n" + ] + "setglobal:0:3" [ + label="setglobal\lfoo\l" + tooltip="start: 0\nfinish: 3\nrange: 35\nvalue: <node table>\nnode: <node local>\n1: foo\n" + ] + "main:0:300000" -> "setglobal:0:3" + "table:6:35" [ + label="table\l\l" + tooltip="start: 6\nfinish: 35\n1: <node tablefield>\n2: <node tablefield>\n3: <node tableindex>\n" + ] + "setglobal:0:3" -> "table:6:35" + "tablefield:7:8" [ + label="tablefield\lx\l" + tooltip="start: 7\nfinish: 8\nnode: <node table>\nrange: 12\nfield: <node field>\nvalue: <node integer>\n" + ] + "table:6:35" -> "tablefield:7:8" + "field:7:8" [ + label="field\lx\l" + tooltip="start: 7\nfinish: 8\n1: x\n" + ] + "tablefield:7:8" -> "field:7:8" + "integer:11:12" [ + label="integer\l5\l" + tooltip="start: 11\nfinish: 12\n1: 5\n" + ] + "tablefield:7:8" -> "integer:11:12" + "tablefield:14:17" [ + label="tablefield\lbar\l" + tooltip="start: 14\nfinish: 17\nnode: <node table>\nrange: 21\nfield: <node field>\nvalue: <node integer>\n" + ] + "table:6:35" -> "tablefield:14:17" + "field:14:17" [ + label="field\lbar\l" + tooltip="start: 14\nfinish: 17\n1: bar\n" + ] + "tablefield:14:17" -> "field:14:17" + "integer:20:21" [ + label="integer\l6\l" + tooltip="start: 20\nfinish: 21\n1: 6\n" + ] + "tablefield:14:17" -> "integer:20:21" + "tableindex:23:30" [ + label="tableindex\lbaz\l" + tooltip="start: 23\nfinish: 30\nrange: 34\nnode: <node table>\nvalue: <node integer>\nindex: <node string>\n" + ] + "table:6:35" -> "tableindex:23:30" + "string:24:29" [ + label="string\lbaz\l" + tooltip="start: 24\nfinish: 29\n1: baz\n2: \"\n" + ] + "tableindex:23:30" -> "string:24:29" + "integer:33:34" [ + label="integer\l7\l" + tooltip="start: 33\nfinish: 34\n1: 7\n" + ] + "tableindex:23:30" -> "integer:33:34" + "setfield:10000:10005" [ + label="setfield\ly\l" + tooltip="start: 10000\nfinish: 10005\nrange: 10017\nfield: <node field>\nnode: <node getglobal>\ndot: <node .>\nvalue: <node binary>\n" + ] + "main:0:300000" -> "setfield:10000:10005" + "getglobal:10000:10003" [ + label="getglobal\lfoo\l" + tooltip="start: 10000\nfinish: 10003\nnext: <node setfield>\nnode: <node local>\n1: foo\n" + ] + "setfield:10000:10005" -> "getglobal:10000:10003" + "field:10004:10005" [ + label="field\ly\l" + tooltip="start: 10004\nfinish: 10005\n1: y\n" + ] + "setfield:10000:10005" -> "field:10004:10005" + "binary:10008:10017" [ + label="binary\l+\l" + tooltip="start: 10008\nfinish: 10017\nop: <node +>\n1: <node getfield>\n2: <node integer>\n" + ] + "setfield:10000:10005" -> "binary:10008:10017" + "getfield:10008:10013" [ + label="getfield\lx\l" + tooltip="start: 10008\nfinish: 10013\nfield: <node field>\ndot: <node .>\nnode: <node getglobal>\n" + ] + "binary:10008:10017" -> "getfield:10008:10013" + "getglobal:10008:10011" [ + label="getglobal\lfoo\l" + tooltip="start: 10008\nfinish: 10011\nnext: <node getfield>\nnode: <node local>\n1: foo\n" + ] + "getfield:10008:10013" -> "getglobal:10008:10011" + "field:10012:10013" [ + label="field\lx\l" + tooltip="start: 10012\nfinish: 10013\n1: x\n" + ] + "getfield:10008:10013" -> "field:10012:10013" + "integer:10016:10017" [ + label="integer\l1\l" + tooltip="start: 10016\nfinish: 10017\n1: 1\n" + ] + "binary:10008:10017" -> "integer:10016:10017" + "setindex:20000:20006" [ + label="setindex\l1\l" + tooltip="start: 20000\nfinish: 20006\nrange: 20015\nnode: <node getglobal>\nvalue: <node getindex>\nindex: <node integer>\n" + ] + "main:0:300000" -> "setindex:20000:20006" + "getglobal:20000:20003" [ + label="getglobal\lfoo\l" + tooltip="start: 20000\nfinish: 20003\nnext: <node setindex>\nnode: <node local>\n1: foo\n" + ] + "setindex:20000:20006" -> "getglobal:20000:20003" + "integer:20004:20005" [ + label="integer\l1\l" + tooltip="start: 20004\nfinish: 20005\n1: 1\n" + ] + "setindex:20000:20006" -> "integer:20004:20005" + "getindex:20009:20015" [ + label="getindex\l0\l" + tooltip="start: 20009\nfinish: 20015\nnode: <node getglobal>\nindex: <node integer>\n" + ] + "setindex:20000:20006" -> "getindex:20009:20015" + "getglobal:20009:20012" [ + label="getglobal\lfoo\l" + tooltip="start: 20009\nfinish: 20012\nnext: <node getindex>\nnode: <node local>\n1: foo\n" + ] + "getindex:20009:20015" -> "getglobal:20009:20012" + "integer:20013:20014" [ + label="integer\l0\l" + tooltip="start: 20013\nfinish: 20014\n1: 0\n" + ] + "getindex:20009:20015" -> "integer:20013:20014" + "setmethod:30009:30023" [ + label="setmethod\lsomeMethod\l" + tooltip="start: 30009\nfinish: 30023\nrange: 30042\nmethod: <node method>\nvalue: <node function>\ncolon: <node :>\nvstart: 30000\nnode: <node getglobal>\n" + ] + "main:0:300000" -> "setmethod:30009:30023" + "getglobal:30009:30012" [ + label="getglobal\lfoo\l" + tooltip="start: 30009\nfinish: 30012\nnode: <node local>\nnext: <node setmethod>\n1: foo\n" + ] + "setmethod:30009:30023" -> "getglobal:30009:30012" + "method:30013:30023" [ + label="method\lsomeMethod\l" + tooltip="start: 30013\nfinish: 30023\n1: someMethod\n" + ] + "setmethod:30009:30023" -> "method:30013:30023" + "function:30000:30042" [ + label="function\l\l" + tooltip="start: 30000\nfinish: 30042\nhasReturn: true\nargs: <node funcargs>\nlocals: <table>\nkeyword: <table>\nbstart: 30025\nreturns: <table>\n1: <node return>\n" + ] + "setmethod:30009:30023" -> "function:30000:30042" + "funcargs:30023:30025" [ + label="funcargs\l\l" + tooltip="start: 30023\nfinish: 30025\n1: <node self>\n" + ] + "function:30000:30042" -> "funcargs:30023:30025" + "self:30008:30008" [ + label="self\lself\l" + tooltip="start: 30008\nfinish: 30008\neffect: 30008\n1: self\n" + ] + "funcargs:30023:30025" -> "self:30008:30008" + "return:30026:30038" [ + label="return\l\l" + tooltip="start: 30026\nfinish: 30038\n1: <node boolean>\n" + ] + "function:30000:30042" -> "return:30026:30038" + "boolean:30033:30038" [ + label="boolean\l\l" + tooltip="start: 30033\nfinish: 30038\n1: false\n" + ] + "return:30026:30038" -> "boolean:30033:30038" + "local:40006:40007" [ + label="local\ls\l" + tooltip="start: 40006\nfinish: 40007\nrange: 40011\nlocPos: 40000\nvalue: <node integer>\nref: <table>\neffect: 40011\n1: s\n" + ] + "main:0:300000" -> "local:40006:40007" + "integer:40010:40011" [ + label="integer\l0\l" + tooltip="start: 40010\nfinish: 40011\n1: 0\n" + ] + "local:40006:40007" -> "integer:40010:40011" + "while:50000:70003" [ + label="while\l\l" + tooltip="start: 50000\nfinish: 70003\nfilter: <node binary>\nkeyword: <table>\nbstart: 50013\n1: <node setlocal>\n" + ] + "main:0:300000" -> "while:50000:70003" + "binary:50006:50012" [ + label="binary\l<\l" + tooltip="start: 50006\nfinish: 50012\nop: <node <>\n1: <node getlocal>\n2: <node integer>\n" + ] + "while:50000:70003" -> "binary:50006:50012" + "getlocal:50006:50007" [ + label="getlocal\ls\l" + tooltip="start: 50006\nfinish: 50007\nnode: <node local>\n1: s\n" + ] + "binary:50006:50012" -> "getlocal:50006:50007" + "integer:50010:50012" [ + label="integer\l10\l" + tooltip="start: 50010\nfinish: 50012\n1: 10\n" + ] + "binary:50006:50012" -> "integer:50010:50012" + "setlocal:60001:60002" [ + label="setlocal\ls\l" + tooltip="start: 60001\nfinish: 60002\nrange: 60038\nvalue: <node binary>\nnode: <node local>\n1: s\n" + ] + "while:50000:70003" -> "setlocal:60001:60002" + "binary:60005:60038" [ + label="binary\l+\l" + tooltip="start: 60005\nfinish: 60038\nop: <node +>\n1: <node getlocal>\n2: <node paren>\n" + ] + "setlocal:60001:60002" -> "binary:60005:60038" + "getlocal:60005:60006" [ + label="getlocal\ls\l" + tooltip="start: 60005\nfinish: 60006\nnode: <node local>\n1: s\n" + ] + "binary:60005:60038" -> "getlocal:60005:60006" + "paren:60009:60038" [ + label="paren\l\l" + tooltip="start: 60009\nfinish: 60038\nexp: <node binary>\n" + ] + "binary:60005:60038" -> "paren:60009:60038" + "binary:60010:60037" [ + label="binary\lor\l" + tooltip="start: 60010\nfinish: 60037\nop: <node or>\n1: <node call>\n2: <node integer>\n" + ] + "paren:60009:60038" -> "binary:60010:60037" + "call:60010:60031" [ + label="call\l\l" + tooltip="start: 60010\nfinish: 60031\nargs: <node callargs>\nnode: <node getmethod>\n" + ] + "binary:60010:60037" -> "call:60010:60031" + "getmethod:60010:60024" [ + label="getmethod\lsomeMethod\l" + tooltip="start: 60010\nfinish: 60024\nmethod: <node method>\nnode: <node getglobal>\ncolon: <node :>\n" + ] + "call:60010:60031" -> "getmethod:60010:60024" + "getglobal:60010:60013" [ + label="getglobal\lfoo\l" + tooltip="start: 60010\nfinish: 60013\nnext: <node getmethod>\nnode: <node local>\n1: foo\n" + ] + "getmethod:60010:60024" -> "getglobal:60010:60013" + "method:60014:60024" [ + label="method\lsomeMethod\l" + tooltip="start: 60014\nfinish: 60024\n1: someMethod\n" + ] + "getmethod:60010:60024" -> "method:60014:60024" + "callargs:60024:60031" [ + label="callargs\l\l" + tooltip="start: 60024\nfinish: 60031\n1: <node self>\n2: <node getglobal>\n3: <node integer>\n" + ] + "call:60010:60031" -> "callargs:60024:60031" + "self:60013:60014" [ + label="self\lself\l" + tooltip="start: 60013\nfinish: 60014\n1: self\n" + ] + "callargs:60024:60031" -> "self:60013:60014" + "getglobal:60025:60026" [ + label="getglobal\li\l" + tooltip="start: 60025\nfinish: 60026\nnode: <node local>\n1: i\n" + ] + "callargs:60024:60031" -> "getglobal:60025:60026" + "integer:60028:60030" [ + label="integer\l10\l" + tooltip="start: 60028\nfinish: 60030\n1: 10\n" + ] + "callargs:60024:60031" -> "integer:60028:60030" + "integer:60035:60037" [ + label="integer\l10\l" + tooltip="start: 60035\nfinish: 60037\n1: 10\n" + ] + "binary:60010:60037" -> "integer:60035:60037" + "call:80000:80008" [ + label="call\l\l" + tooltip="start: 80000\nfinish: 80008\nargs: <node callargs>\nnode: <node getglobal>\n" + ] + "main:0:300000" -> "call:80000:80008" + "getglobal:80000:80005" [ + label="getglobal\lprint\l" + tooltip="start: 80000\nfinish: 80005\nnode: <node local>\n1: print\n" + ] + "call:80000:80008" -> "getglobal:80000:80005" + "callargs:80005:80008" [ + label="callargs\l\l" + tooltip="start: 80005\nfinish: 80008\n1: <node getlocal>\n" + ] + "call:80000:80008" -> "callargs:80005:80008" + "getlocal:80006:80007" [ + label="getlocal\ls\l" + tooltip="start: 80006\nfinish: 80007\nnode: <node local>\n1: s\n" + ] + "callargs:80005:80008" -> "getlocal:80006:80007" + "loop:90000:140003" [ + label="loop\l\l" + tooltip="start: 90000\nfinish: 140003\ninit: <node integer>\nstep: <node integer>\nmax: <node integer>\nlocals: <table>\nkeyword: <table>\nbstart: 90018\nloc: <node local>\n1: <node in>\n" + ] + "main:0:300000" -> "loop:90000:140003" + "local:90004:90005" [ + label="local\lj\l" + tooltip="start: 90004\nfinish: 90005\neffect: 90017\n1: j\n" + ] + "loop:90000:140003" -> "local:90004:90005" + "integer:90008:90010" [ + label="integer\l10\l" + tooltip="start: 90008\nfinish: 90010\n1: 10\n" + ] + "loop:90000:140003" -> "integer:90008:90010" + "integer:90012:90013" [ + label="integer\l1\l" + tooltip="start: 90012\nfinish: 90013\n1: 1\n" + ] + "loop:90000:140003" -> "integer:90012:90013" + "integer:90015:90017" [ + label="integer\l-1\l" + tooltip="start: 90015\nfinish: 90017\n1: -1\n" + ] + "loop:90000:140003" -> "integer:90015:90017" + "in:100001:130004" [ + label="in\l\l" + tooltip="start: 100001\nfinish: 130004\nexps: <node list>\nlabels: <table>\nlocals: <table>\nkeyword: <table>\nbstart: 100020\nkeys: <node list>\n1: <node goto>\n2: <node label>\n" + ] + "loop:90000:140003" -> "in:100001:130004" + "list:100005:100006" [ + label="list\l\l" + tooltip="start: 100005\nfinish: 100006\nrange: 100009\n1: <node local>\n" + ] + "in:100001:130004" -> "list:100005:100006" + "local:100005:100006" [ + label="local\li\l" + tooltip="start: 100005\nfinish: 100006\neffect: 100019\n1: i\n" + ] + "list:100005:100006" -> "local:100005:100006" + "list:100010:100019" [ + label="list\l\l" + tooltip="start: 100010\nfinish: 100019\n1: <node call>\n" + ] + "in:100001:130004" -> "list:100010:100019" + "call:100010:100019" [ + label="call\l\l" + tooltip="start: 100010\nfinish: 100019\nargs: <node callargs>\nnode: <node getglobal>\n" + ] + "list:100010:100019" -> "call:100010:100019" + "getglobal:100010:100016" [ + label="getglobal\lipairs\l" + tooltip="start: 100010\nfinish: 100016\nspecial: ipairs\nnode: <node local>\n1: ipairs\n" + ] + "call:100010:100019" -> "getglobal:100010:100016" + "callargs:100016:100019" [ + label="callargs\l\l" + tooltip="start: 100016\nfinish: 100019\n1: <node getlocal>\n" + ] + "call:100010:100019" -> "callargs:100016:100019" + "getlocal:100017:100018" [ + label="getlocal\ls\l" + tooltip="start: 100017\nfinish: 100018\nnode: <node local>\n1: s\n" + ] + "callargs:100016:100019" -> "getlocal:100017:100018" + "goto:110007:110015" [ + label="goto\lfoolabel\l" + tooltip="start: 110007\nfinish: 110015\nkeyStart: 110002\nnode: <node label>\n1: foolabel\n" + ] + "in:100001:130004" -> "goto:110007:110015" + "label:120004:120012" [ + label="label\lfoolabel\l" + tooltip="start: 120004\nfinish: 120012\nref: <table>\n1: foolabel\n" + ] + "in:100001:130004" -> "label:120004:120012" + "setglobal:160009:160012" [ + label="setglobal\lfoo\l" + tooltip="start: 160009\nfinish: 160012\nrange: 210003\nvstart: 160000\nvalue: <node function>\nnode: <node local>\n1: foo\n" + ] + "main:0:300000" -> "setglobal:160009:160012" + "function:160000:210003" [ + label="function\l\l" + tooltip="start: 160000\nfinish: 210003\nkeyword: <table>\nhasReturn: true\nargs: <node funcargs>\nbstart: 160014\nreturns: <table>\n1: <node return>\n" + ] + "setglobal:160009:160012" -> "function:160000:210003" + "funcargs:160012:160014" [ + label="funcargs\l\l" + tooltip="start: 160012\nfinish: 160014\n" + ] + "function:160000:210003" -> "funcargs:160012:160014" + "return:170001:200004" [ + label="return\l\l" + tooltip="start: 170001\nfinish: 200004\n1: <node function>\n" + ] + "function:160000:210003" -> "return:170001:200004" + "function:170008:200004" [ + label="function\l\l" + tooltip="start: 170008\nfinish: 200004\nargs: <node funcargs>\nlocals: <table>\nbstart: 170024\nkeyword: <table>\nvararg: <node ...>\n1: <node repeat>\n" + ] + "return:170001:200004" -> "function:170008:200004" + "funcargs:170016:170024" [ + label="funcargs\l\l" + tooltip="start: 170016\nfinish: 170024\n1: <node local>\n2: <node ...>\n" + ] + "function:170008:200004" -> "funcargs:170016:170024" + "local:170017:170018" [ + label="local\lx\l" + tooltip="start: 170017\nfinish: 170018\neffect: 170018\n1: x\n" + ] + "funcargs:170016:170024" -> "local:170017:170018" + "...:170020:170023" [ + label="...\l\l" + tooltip="start: 170020\nfinish: 170023\nref: <table>\n1: ...\n" + ] + "funcargs:170016:170024" -> "...:170020:170023" + "repeat:180002:190028" [ + label="repeat\l\l" + tooltip="start: 180002\nfinish: 190028\nfilter: <node binary>\nkeyword: <table>\nbstart: 180008\n" + ] + "function:170008:200004" -> "repeat:180002:190028" + "binary:190008:190028" [ + label="binary\l>\l" + tooltip="start: 190008\nfinish: 190028\nop: <node >>\n1: <node call>\n2: <node integer>\n" + ] + "repeat:180002:190028" -> "binary:190008:190028" + "call:190008:190024" [ + label="call\l\l" + tooltip="start: 190008\nfinish: 190024\nargs: <node callargs>\nnode: <node getglobal>\n" + ] + "binary:190008:190028" -> "call:190008:190024" + "getglobal:190008:190014" [ + label="getglobal\lselect\l" + tooltip="start: 190008\nfinish: 190014\nnode: <node local>\n1: select\n" + ] + "call:190008:190024" -> "getglobal:190008:190014" + "callargs:190014:190024" [ + label="callargs\l\l" + tooltip="start: 190014\nfinish: 190024\n1: <node string>\n2: <node varargs>\n" + ] + "call:190008:190024" -> "callargs:190014:190024" + "string:190015:190018" [ + label="string\l#\l" + tooltip="start: 190015\nfinish: 190018\n1: #\n2: '\n" + ] + "callargs:190014:190024" -> "string:190015:190018" + "varargs:190020:190023" [ + label="varargs\l\l" + tooltip="start: 190020\nfinish: 190023\nnode: <node ...>\n" + ] + "callargs:190014:190024" -> "varargs:190020:190023" + "integer:190027:190028" [ + label="integer\l0\l" + tooltip="start: 190027\nfinish: 190028\n1: 0\n" + ] + "binary:190008:190028" -> "integer:190027:190028" + "if:230000:290003" [ + label="if\l\l" + tooltip="start: 230000\nfinish: 290003\n1: <node ifblock>\n2: <node elseifblock>\n3: <node elseblock>\n" + ] + "main:0:300000" -> "if:230000:290003" + "ifblock:230000:250000" [ + label="ifblock\l\l" + tooltip="start: 230000\nfinish: 250000\nbstart: 230009\nfilter: <node getglobal>\nhasReturn: true\nkeyword: <table>\n1: <node return>\n" + ] + "if:230000:290003" -> "ifblock:230000:250000" + "getglobal:230003:230004" [ + label="getglobal\lx\l" + tooltip="start: 230003\nfinish: 230004\nnode: <node local>\n1: x\n" + ] + "ifblock:230000:250000" -> "getglobal:230003:230004" + "return:240001:240048" [ + label="return\l\l" + tooltip="start: 240001\nfinish: 240048\n1: <node binary>\n" + ] + "ifblock:230000:250000" -> "return:240001:240048" + "binary:240008:240048" [ + label="binary\lor\l" + tooltip="start: 240008\nfinish: 240048\nop: <node or>\n1: <node binary>\n2: <node binary>\n" + ] + "return:240001:240048" -> "binary:240008:240048" + "binary:240008:240023" [ + label="binary\lor\l" + tooltip="start: 240008\nfinish: 240023\nop: <node or>\n1: <node binary>\n2: <node binary>\n" + ] + "binary:240008:240048" -> "binary:240008:240023" + "binary:240008:240013" [ + label="binary\l<\l" + tooltip="start: 240008\nfinish: 240013\nop: <node <>\n1: <node getglobal>\n2: <node integer>\n" + ] + "binary:240008:240023" -> "binary:240008:240013" + "getglobal:240008:240009" [ + label="getglobal\lx\l" + tooltip="start: 240008\nfinish: 240009\nnode: <node local>\n1: x\n" + ] + "binary:240008:240013" -> "getglobal:240008:240009" + "integer:240012:240013" [ + label="integer\l0\l" + tooltip="start: 240012\nfinish: 240013\n1: 0\n" + ] + "binary:240008:240013" -> "integer:240012:240013" + "binary:240017:240023" [ + label="binary\l>=\l" + tooltip="start: 240017\nfinish: 240023\nop: <node >=>\n1: <node getglobal>\n2: <node integer>\n" + ] + "binary:240008:240023" -> "binary:240017:240023" + "getglobal:240017:240018" [ + label="getglobal\lx\l" + tooltip="start: 240017\nfinish: 240018\nnode: <node local>\n1: x\n" + ] + "binary:240017:240023" -> "getglobal:240017:240018" + "integer:240022:240023" [ + label="integer\l0\l" + tooltip="start: 240022\nfinish: 240023\n1: 0\n" + ] + "binary:240017:240023" -> "integer:240022:240023" + "binary:240027:240048" [ + label="binary\land\l" + tooltip="start: 240027\nfinish: 240048\nop: <node and>\n1: <node binary>\n2: <node binary>\n" + ] + "binary:240008:240048" -> "binary:240027:240048" + "binary:240027:240037" [ + label="binary\l<=\l" + tooltip="start: 240027\nfinish: 240037\nop: <node <=>\n1: <node unary>\n2: <node integer>\n" + ] + "binary:240027:240048" -> "binary:240027:240037" + "unary:240027:240032" [ + label="unary\lnot\l" + tooltip="start: 240027\nfinish: 240032\nop: <node not>\n1: <node getglobal>\n" + ] + "binary:240027:240037" -> "unary:240027:240032" + "getglobal:240031:240032" [ + label="getglobal\lx\l" + tooltip="start: 240031\nfinish: 240032\nnode: <node local>\n1: x\n" + ] + "unary:240027:240032" -> "getglobal:240031:240032" + "integer:240036:240037" [ + label="integer\l0\l" + tooltip="start: 240036\nfinish: 240037\n1: 0\n" + ] + "binary:240027:240037" -> "integer:240036:240037" + "binary:240042:240048" [ + label="binary\l>\l" + tooltip="start: 240042\nfinish: 240048\nop: <node >>\n1: <node unary>\n2: <node integer>\n" + ] + "binary:240027:240048" -> "binary:240042:240048" + "unary:240042:240044" [ + label="unary\l-\l" + tooltip="start: 240042\nfinish: 240044\nop: <node ->\n1: <node getglobal>\n" + ] + "binary:240042:240048" -> "unary:240042:240044" + "getglobal:240043:240044" [ + label="getglobal\lx\l" + tooltip="start: 240043\nfinish: 240044\nnode: <node local>\n1: x\n" + ] + "unary:240042:240044" -> "getglobal:240043:240044" + "integer:240047:240048" [ + label="integer\l7\l" + tooltip="start: 240047\nfinish: 240048\n1: 7\n" + ] + "binary:240042:240048" -> "integer:240047:240048" + "elseifblock:250000:270000" [ + label="elseifblock\l\l" + tooltip="start: 250000\nfinish: 270000\nbstart: 250013\nfilter: <node getglobal>\nhasReturn: true\nkeyword: <table>\n1: <node return>\n" + ] + "if:230000:290003" -> "elseifblock:250000:270000" + "getglobal:250007:250008" [ + label="getglobal\ly\l" + tooltip="start: 250007\nfinish: 250008\nnode: <node local>\n1: y\n" + ] + "elseifblock:250000:270000" -> "getglobal:250007:250008" + "return:260001:260011" [ + label="return\l\l" + tooltip="start: 260001\nfinish: 260011\n1: <node number>\n" + ] + "elseifblock:250000:270000" -> "return:260001:260011" + "number:260008:260011" [ + label="number\l5.7\l" + tooltip="start: 260008\nfinish: 260011\n1: 5.7\n" + ] + "return:260001:260011" -> "number:260008:260011" + "elseblock:270000:290000" [ + label="elseblock\l\l" + tooltip="start: 270000\nfinish: 290000\nkeyword: <table>\nbstart: 270004\nhasReturn: true\n1: <node return>\n" + ] + "if:230000:290003" -> "elseblock:270000:290000" + "return:280001:280091" [ + label="return\l\l" + tooltip="start: 280001\nfinish: 280091\n1: <node string>\n" + ] + "elseblock:270000:290000" -> "return:280001:280091" + "string:280008:280091" [ + label="string\la very long strin...\l" + tooltip="start: 280008\nfinish: 280091\n1: a very long strin...\n2: \"\n" + ] + "return:280001:280091" -> "string:280008:280091" +} diff --git a/test/cli/visualize/testdata/all-types.txt b/test/cli/visualize/testdata/all-types.txt new file mode 100644 index 00000000..167bd54b --- /dev/null +++ b/test/cli/visualize/testdata/all-types.txt @@ -0,0 +1,30 @@ +foo = {x = 5, bar = 6, ["baz"] = 7} +foo.y = foo.x + 1 +foo[1] = foo[0] +function foo:someMethod() return false end +local s = 0 +while s < 10 do + s = s + (foo:someMethod(i, 10) or 10) +end +print(s) +for j = 10, 1, -1 do + for i in ipairs(s) do + goto foolabel + ::foolabel:: + end +end + +function foo() + return function(x, ...) + repeat + until select('#', ...) > 0 + end +end + +if x then + return x < 0 or x >= 0 or not x <= 0 and -x > 7 +elseif y then + return 5.7 +else + return "a very long string that should get shortened to not destroy the layout completely" +end diff --git a/test/cli/visualize/testdata/shorten-names-expected.txt b/test/cli/visualize/testdata/shorten-names-expected.txt new file mode 100644 index 00000000..c03a697a --- /dev/null +++ b/test/cli/visualize/testdata/shorten-names-expected.txt @@ -0,0 +1,327 @@ +digraph AST { + node [shape = rect] + "main:0:170009" [ + label="main\l\l" + tooltip="start: 0\nfinish: 170009\nlocals: <table>\nstate: <table>\n1: <node setglobal>\n2: <node setglobal>\n3: <node setglobal>\n4: <node setglobal>\n5: <node setglobal>\n6: <node setglobal>\n7: <node setglobal>\n8: <node setglobal>\n9: <node setglobal>\n10: <node setglobal>\n11: <node setglobal>\n12: <node setglobal>\n13: <node setglobal>\n14: <node setglobal>\n15: <node setglobal>\n15..17: (...)\n" + ] + "setglobal:0:1" [ + label="setglobal\ls\l" + tooltip="start: 0\nfinish: 1\nrange: 101\nvalue: <node string>\nnode: <node local>\n1: s\n" + ] + "main:0:170009" -> "setglobal:0:1" + "string:4:101" [ + label="string\lvery long string ...\l" + tooltip="start: 4\nfinish: 101\n1: very long string ...\n2: \"\n" + ] + "setglobal:0:1" -> "string:4:101" + "setglobal:10000:10001" [ + label="setglobal\ls\l" + tooltip="start: 10000\nfinish: 10001\nrange: 10031\nvalue: <node string>\nnode: <node local>\n1: s\n" + ] + "main:0:170009" -> "setglobal:10000:10001" + "string:10004:10031" [ + label="string\lstring\\nwith\\n\...\l" + tooltip="start: 10004\nfinish: 10031\nescs: <table>\n1: string\\nwith\\n\...\n2: \"\n" + ] + "setglobal:10000:10001" -> "string:10004:10031" + "setglobal:20000:20001" [ + label="setglobal\lx\l" + tooltip="start: 20000\nfinish: 20001\nrange: 20009\nvalue: <node binary>\nnode: <node local>\n1: x\n" + ] + "main:0:170009" -> "setglobal:20000:20001" + "binary:20004:20009" [ + label="binary\l+\l" + tooltip="start: 20004\nfinish: 20009\nop: <node +>\n1: <node getglobal>\n2: <node integer>\n" + ] + "setglobal:20000:20001" -> "binary:20004:20009" + "getglobal:20004:20005" [ + label="getglobal\lx\l" + tooltip="start: 20004\nfinish: 20005\nnode: <node local>\n1: x\n" + ] + "binary:20004:20009" -> "getglobal:20004:20005" + "integer:20008:20009" [ + label="integer\l1\l" + tooltip="start: 20008\nfinish: 20009\n1: 1\n" + ] + "binary:20004:20009" -> "integer:20008:20009" + "setglobal:30000:30001" [ + label="setglobal\lx\l" + tooltip="start: 30000\nfinish: 30001\nrange: 30009\nvalue: <node binary>\nnode: <node local>\n1: x\n" + ] + "main:0:170009" -> "setglobal:30000:30001" + "binary:30004:30009" [ + label="binary\l+\l" + tooltip="start: 30004\nfinish: 30009\nop: <node +>\n1: <node getglobal>\n2: <node integer>\n" + ] + "setglobal:30000:30001" -> "binary:30004:30009" + "getglobal:30004:30005" [ + label="getglobal\lx\l" + tooltip="start: 30004\nfinish: 30005\nnode: <node local>\n1: x\n" + ] + "binary:30004:30009" -> "getglobal:30004:30005" + "integer:30008:30009" [ + label="integer\l1\l" + tooltip="start: 30008\nfinish: 30009\n1: 1\n" + ] + "binary:30004:30009" -> "integer:30008:30009" + "setglobal:40000:40001" [ + label="setglobal\lx\l" + tooltip="start: 40000\nfinish: 40001\nrange: 40009\nvalue: <node binary>\nnode: <node local>\n1: x\n" + ] + "main:0:170009" -> "setglobal:40000:40001" + "binary:40004:40009" [ + label="binary\l+\l" + tooltip="start: 40004\nfinish: 40009\nop: <node +>\n1: <node getglobal>\n2: <node integer>\n" + ] + "setglobal:40000:40001" -> "binary:40004:40009" + "getglobal:40004:40005" [ + label="getglobal\lx\l" + tooltip="start: 40004\nfinish: 40005\nnode: <node local>\n1: x\n" + ] + "binary:40004:40009" -> "getglobal:40004:40005" + "integer:40008:40009" [ + label="integer\l1\l" + tooltip="start: 40008\nfinish: 40009\n1: 1\n" + ] + "binary:40004:40009" -> "integer:40008:40009" + "setglobal:50000:50001" [ + label="setglobal\lx\l" + tooltip="start: 50000\nfinish: 50001\nrange: 50009\nvalue: <node binary>\nnode: <node local>\n1: x\n" + ] + "main:0:170009" -> "setglobal:50000:50001" + "binary:50004:50009" [ + label="binary\l+\l" + tooltip="start: 50004\nfinish: 50009\nop: <node +>\n1: <node getglobal>\n2: <node integer>\n" + ] + "setglobal:50000:50001" -> "binary:50004:50009" + "getglobal:50004:50005" [ + label="getglobal\lx\l" + tooltip="start: 50004\nfinish: 50005\nnode: <node local>\n1: x\n" + ] + "binary:50004:50009" -> "getglobal:50004:50005" + "integer:50008:50009" [ + label="integer\l1\l" + tooltip="start: 50008\nfinish: 50009\n1: 1\n" + ] + "binary:50004:50009" -> "integer:50008:50009" + "setglobal:60000:60001" [ + label="setglobal\lx\l" + tooltip="start: 60000\nfinish: 60001\nrange: 60009\nvalue: <node binary>\nnode: <node local>\n1: x\n" + ] + "main:0:170009" -> "setglobal:60000:60001" + "binary:60004:60009" [ + label="binary\l+\l" + tooltip="start: 60004\nfinish: 60009\nop: <node +>\n1: <node getglobal>\n2: <node integer>\n" + ] + "setglobal:60000:60001" -> "binary:60004:60009" + "getglobal:60004:60005" [ + label="getglobal\lx\l" + tooltip="start: 60004\nfinish: 60005\nnode: <node local>\n1: x\n" + ] + "binary:60004:60009" -> "getglobal:60004:60005" + "integer:60008:60009" [ + label="integer\l1\l" + tooltip="start: 60008\nfinish: 60009\n1: 1\n" + ] + "binary:60004:60009" -> "integer:60008:60009" + "setglobal:70000:70001" [ + label="setglobal\lx\l" + tooltip="start: 70000\nfinish: 70001\nrange: 70009\nvalue: <node binary>\nnode: <node local>\n1: x\n" + ] + "main:0:170009" -> "setglobal:70000:70001" + "binary:70004:70009" [ + label="binary\l+\l" + tooltip="start: 70004\nfinish: 70009\nop: <node +>\n1: <node getglobal>\n2: <node integer>\n" + ] + "setglobal:70000:70001" -> "binary:70004:70009" + "getglobal:70004:70005" [ + label="getglobal\lx\l" + tooltip="start: 70004\nfinish: 70005\nnode: <node local>\n1: x\n" + ] + "binary:70004:70009" -> "getglobal:70004:70005" + "integer:70008:70009" [ + label="integer\l1\l" + tooltip="start: 70008\nfinish: 70009\n1: 1\n" + ] + "binary:70004:70009" -> "integer:70008:70009" + "setglobal:80000:80001" [ + label="setglobal\lx\l" + tooltip="start: 80000\nfinish: 80001\nrange: 80009\nvalue: <node binary>\nnode: <node local>\n1: x\n" + ] + "main:0:170009" -> "setglobal:80000:80001" + "binary:80004:80009" [ + label="binary\l+\l" + tooltip="start: 80004\nfinish: 80009\nop: <node +>\n1: <node getglobal>\n2: <node integer>\n" + ] + "setglobal:80000:80001" -> "binary:80004:80009" + "getglobal:80004:80005" [ + label="getglobal\lx\l" + tooltip="start: 80004\nfinish: 80005\nnode: <node local>\n1: x\n" + ] + "binary:80004:80009" -> "getglobal:80004:80005" + "integer:80008:80009" [ + label="integer\l1\l" + tooltip="start: 80008\nfinish: 80009\n1: 1\n" + ] + "binary:80004:80009" -> "integer:80008:80009" + "setglobal:90000:90001" [ + label="setglobal\lx\l" + tooltip="start: 90000\nfinish: 90001\nrange: 90009\nvalue: <node binary>\nnode: <node local>\n1: x\n" + ] + "main:0:170009" -> "setglobal:90000:90001" + "binary:90004:90009" [ + label="binary\l+\l" + tooltip="start: 90004\nfinish: 90009\nop: <node +>\n1: <node getglobal>\n2: <node integer>\n" + ] + "setglobal:90000:90001" -> "binary:90004:90009" + "getglobal:90004:90005" [ + label="getglobal\lx\l" + tooltip="start: 90004\nfinish: 90005\nnode: <node local>\n1: x\n" + ] + "binary:90004:90009" -> "getglobal:90004:90005" + "integer:90008:90009" [ + label="integer\l1\l" + tooltip="start: 90008\nfinish: 90009\n1: 1\n" + ] + "binary:90004:90009" -> "integer:90008:90009" + "setglobal:100000:100001" [ + label="setglobal\lx\l" + tooltip="start: 100000\nfinish: 100001\nrange: 100009\nvalue: <node binary>\nnode: <node local>\n1: x\n" + ] + "main:0:170009" -> "setglobal:100000:100001" + "binary:100004:100009" [ + label="binary\l+\l" + tooltip="start: 100004\nfinish: 100009\nop: <node +>\n1: <node getglobal>\n2: <node integer>\n" + ] + "setglobal:100000:100001" -> "binary:100004:100009" + "getglobal:100004:100005" [ + label="getglobal\lx\l" + tooltip="start: 100004\nfinish: 100005\nnode: <node local>\n1: x\n" + ] + "binary:100004:100009" -> "getglobal:100004:100005" + "integer:100008:100009" [ + label="integer\l1\l" + tooltip="start: 100008\nfinish: 100009\n1: 1\n" + ] + "binary:100004:100009" -> "integer:100008:100009" + "setglobal:110000:110001" [ + label="setglobal\lx\l" + tooltip="start: 110000\nfinish: 110001\nrange: 110009\nvalue: <node binary>\nnode: <node local>\n1: x\n" + ] + "main:0:170009" -> "setglobal:110000:110001" + "binary:110004:110009" [ + label="binary\l+\l" + tooltip="start: 110004\nfinish: 110009\nop: <node +>\n1: <node getglobal>\n2: <node integer>\n" + ] + "setglobal:110000:110001" -> "binary:110004:110009" + "getglobal:110004:110005" [ + label="getglobal\lx\l" + tooltip="start: 110004\nfinish: 110005\nnode: <node local>\n1: x\n" + ] + "binary:110004:110009" -> "getglobal:110004:110005" + "integer:110008:110009" [ + label="integer\l1\l" + tooltip="start: 110008\nfinish: 110009\n1: 1\n" + ] + "binary:110004:110009" -> "integer:110008:110009" + "setglobal:120000:120001" [ + label="setglobal\lx\l" + tooltip="start: 120000\nfinish: 120001\nrange: 120009\nvalue: <node binary>\nnode: <node local>\n1: x\n" + ] + "main:0:170009" -> "setglobal:120000:120001" + "binary:120004:120009" [ + label="binary\l+\l" + tooltip="start: 120004\nfinish: 120009\nop: <node +>\n1: <node getglobal>\n2: <node integer>\n" + ] + "setglobal:120000:120001" -> "binary:120004:120009" + "getglobal:120004:120005" [ + label="getglobal\lx\l" + tooltip="start: 120004\nfinish: 120005\nnode: <node local>\n1: x\n" + ] + "binary:120004:120009" -> "getglobal:120004:120005" + "integer:120008:120009" [ + label="integer\l1\l" + tooltip="start: 120008\nfinish: 120009\n1: 1\n" + ] + "binary:120004:120009" -> "integer:120008:120009" + "setglobal:130000:130001" [ + label="setglobal\lx\l" + tooltip="start: 130000\nfinish: 130001\nrange: 130009\nvalue: <node binary>\nnode: <node local>\n1: x\n" + ] + "main:0:170009" -> "setglobal:130000:130001" + "binary:130004:130009" [ + label="binary\l+\l" + tooltip="start: 130004\nfinish: 130009\nop: <node +>\n1: <node getglobal>\n2: <node integer>\n" + ] + "setglobal:130000:130001" -> "binary:130004:130009" + "getglobal:130004:130005" [ + label="getglobal\lx\l" + tooltip="start: 130004\nfinish: 130005\nnode: <node local>\n1: x\n" + ] + "binary:130004:130009" -> "getglobal:130004:130005" + "integer:130008:130009" [ + label="integer\l1\l" + tooltip="start: 130008\nfinish: 130009\n1: 1\n" + ] + "binary:130004:130009" -> "integer:130008:130009" + "setglobal:140000:140001" [ + label="setglobal\lx\l" + tooltip="start: 140000\nfinish: 140001\nrange: 140009\nvalue: <node binary>\nnode: <node local>\n1: x\n" + ] + "main:0:170009" -> "setglobal:140000:140001" + "binary:140004:140009" [ + label="binary\l+\l" + tooltip="start: 140004\nfinish: 140009\nop: <node +>\n1: <node getglobal>\n2: <node integer>\n" + ] + "setglobal:140000:140001" -> "binary:140004:140009" + "getglobal:140004:140005" [ + label="getglobal\lx\l" + tooltip="start: 140004\nfinish: 140005\nnode: <node local>\n1: x\n" + ] + "binary:140004:140009" -> "getglobal:140004:140005" + "integer:140008:140009" [ + label="integer\l1\l" + tooltip="start: 140008\nfinish: 140009\n1: 1\n" + ] + "binary:140004:140009" -> "integer:140008:140009" + "setglobal:160000:160001" [ + label="setglobal\lx\l" + tooltip="start: 160000\nfinish: 160001\nrange: 160009\nvalue: <node binary>\nnode: <node local>\n1: x\n" + ] + "main:0:170009" -> "setglobal:160000:160001" + "binary:160004:160009" [ + label="binary\l+\l" + tooltip="start: 160004\nfinish: 160009\nop: <node +>\n1: <node getglobal>\n2: <node integer>\n" + ] + "setglobal:160000:160001" -> "binary:160004:160009" + "getglobal:160004:160005" [ + label="getglobal\lx\l" + tooltip="start: 160004\nfinish: 160005\nnode: <node local>\n1: x\n" + ] + "binary:160004:160009" -> "getglobal:160004:160005" + "integer:160008:160009" [ + label="integer\l1\l" + tooltip="start: 160008\nfinish: 160009\n1: 1\n" + ] + "binary:160004:160009" -> "integer:160008:160009" + "setglobal:170000:170001" [ + label="setglobal\lx\l" + tooltip="start: 170000\nfinish: 170001\nrange: 170009\nvalue: <node binary>\nnode: <node local>\n1: x\n" + ] + "main:0:170009" -> "setglobal:170000:170001" + "binary:170004:170009" [ + label="binary\l+\l" + tooltip="start: 170004\nfinish: 170009\nop: <node +>\n1: <node getglobal>\n2: <node integer>\n" + ] + "setglobal:170000:170001" -> "binary:170004:170009" + "getglobal:170004:170005" [ + label="getglobal\lx\l" + tooltip="start: 170004\nfinish: 170005\nnode: <node local>\n1: x\n" + ] + "binary:170004:170009" -> "getglobal:170004:170005" + "integer:170008:170009" [ + label="integer\l1\l" + tooltip="start: 170008\nfinish: 170009\n1: 1\n" + ] + "binary:170004:170009" -> "integer:170008:170009" +} diff --git a/test/cli/visualize/testdata/shorten-names.txt b/test/cli/visualize/testdata/shorten-names.txt new file mode 100644 index 00000000..90aa7f0e --- /dev/null +++ b/test/cli/visualize/testdata/shorten-names.txt @@ -0,0 +1,18 @@ +s = "very long string that is very long and would be annoying if it was fully included in the output" +s = "string\nwith\n\new\nlines" +x = x + 1 +x = x + 1 +x = x + 1 +x = x + 1 +x = x + 1 +x = x + 1 +x = x + 1 +x = x + 1 +x = x + 1 +x = x + 1 +x = x + 1 +x = x + 1 +x = x + 1 +-- more than 15 lines should be shortened for tooltip in main +x = x + 1 +x = x + 1
\ No newline at end of file diff --git a/test/diagnostics/assign-type-mismatch.lua b/test/diagnostics/assign-type-mismatch.lua index d4632563..dc55a7da 100644 --- a/test/diagnostics/assign-type-mismatch.lua +++ b/test/diagnostics/assign-type-mismatch.lua @@ -99,6 +99,13 @@ t['x'] = nil ]] TEST [[ +---@type [boolean] +local t = { <![1]!> = nil } + +t = nil +]] + +TEST [[ local t = { true } t[1] = nil diff --git a/test/diagnostics/await-in-sync.lua b/test/diagnostics/await-in-sync.lua index 7647f2eb..323c1113 100644 --- a/test/diagnostics/await-in-sync.lua +++ b/test/diagnostics/await-in-sync.lua @@ -119,7 +119,7 @@ end TEST [[ local function f(cb) - <!cb!>() + cb() end local function af() diff --git a/test/diagnostics/redundant-parameter.lua b/test/diagnostics/redundant-parameter.lua index 520a6381..fabe3340 100644 --- a/test/diagnostics/redundant-parameter.lua +++ b/test/diagnostics/redundant-parameter.lua @@ -94,7 +94,7 @@ print(1, 2, 3, 4, 5) TEST [[ local function f(callback) - callback(<!1!>, <!2!>, <!3!>) + callback(1, 2, 3) end f(function () end) ]] diff --git a/test/hover/init.lua b/test/hover/init.lua index 851443ec..0cfce3a4 100644 --- a/test/hover/init.lua +++ b/test/hover/init.lua @@ -276,7 +276,7 @@ function string.lower(s: string|number) -> string ]] --- 根据传入值推测参数类型 +-- 不根据传入值推测参数类型 TEST [[ local function x(a, ...) end @@ -284,7 +284,7 @@ end <?x?>(1, 2, 3, 4, 5, 6, 7) ]] [[ -function x(a: integer, ...any) +function x(a: any, ...any) ]] TEST [[ @@ -1228,6 +1228,17 @@ local <?x?> local x: table<ClassA, ClassB> ]] +TEST [[ +---@type [ClassA, ClassB] +local <?x?> +]] +[[ +local x: [ClassA, ClassB] { + [1]: ClassA, + [2]: ClassB, +} +]] + --TEST [[ -----@class ClassA -----@class ClassB diff --git a/test/plugins/ast/test.lua b/test/plugins/ast/test.lua index 95e87694..a01b9e2e 100644 --- a/test/plugins/ast/test.lua +++ b/test/plugins/ast/test.lua @@ -3,11 +3,14 @@ local guide = require 'parser.guide' local helper = require 'plugins.astHelper' ---@diagnostic disable: await-in-sync -local function TestPlugin(script, plugin, checker) +---@param ... function checkers +local function TestPlugin(script, plugin, ...) local state = parser.compile(script, "Lua", "Lua 5.4") state.ast = plugin(TESTURI, state.ast) or state.ast parser.luadoc(state) - checker(state) + for i = 1, select('#', ...) do + select(i, ...)(state) + end end local function isDocClass(ast) @@ -62,6 +65,47 @@ local function TestSelfIsClass(state, next) end) end +local function TestAHasField(state, next) + local foundFields = false + local cb = function (source) + if not source.bindDocs or not source.bindDocs[1].class or source.bindDocs[1].class[1] ~= "A" then + return + end + assert(#source.bindDocs == 1) + assert(#source.bindDocs[1].fields >= 2) + assert(source.bindDocs[1].fields[1].field[1] == "x") + assert(source.bindDocs[1].fields[2].field[1] == "y") + foundFields = true + end + guide.eachSourceType(state.ast, "local", cb) + guide.eachSourceType(state.ast, "setglobal", cb) + assert(foundFields) +end + +local function plugin_AddMultipleDocs(uri, ast) + guide.eachSourceType(ast, "call", function(source) + local node = source.node + if guide.getKeyName(node) ~= 'Class' then + return + end + local wants = { + ['local'] = true, + ['setglobal'] = true + } + local classnameNode = guide.getParentTypes(source, wants) + if not classnameNode then + return + end + local classname = guide.getKeyName(classnameNode) + if classname then + local group = {} + helper.addClassDoc(ast, classnameNode, classname, group) + helper.addDoc(ast, classnameNode, "field", "x number", group) + helper.addDoc(ast, classnameNode, "field", "y string", group) + end + end) +end + local function TestPlugin1(script) TestPlugin(script, plugin_AddClass, TestAIsClass) end @@ -70,6 +114,10 @@ local function TestPlugin2(script) TestPlugin(script, plugin_AddClassAtParam, TestSelfIsClass) end +local function TestPlugin3(script) + TestPlugin(script, plugin_AddMultipleDocs, TestAIsClass, TestAHasField) +end + TestPlugin1 [[ local A = Class(function() end) ]] @@ -86,4 +134,12 @@ TestPlugin2 [[ function ctor(self) end ]] +TestPlugin3 [[ + local A = Class() +]] + +TestPlugin3 [[ + A = Class() +]] + require 'plugins.ast.helper' diff --git a/test/plugins/node/test.lua b/test/plugins/node/test.lua new file mode 100644 index 00000000..15e4d16c --- /dev/null +++ b/test/plugins/node/test.lua @@ -0,0 +1,56 @@ +local files = require 'files' +local scope = require 'workspace.scope' +local nodeHelper = require 'plugins.nodeHelper' +local vm = require 'vm' +local guide = require 'parser.guide' + + +local pattern, msg = nodeHelper.createFieldPattern("*.components") +assert(pattern, msg) + +---@param source parser.object +function OnCompileFunctionParam(next, func, source) + if next(func, source) then + return true + end + --从该参数的使用模式来推导该类型 + if nodeHelper.matchPattern(source, pattern) then + local type = vm.declareGlobal('type', 'TestClass', TESTURI) + vm.setNode(source, vm.createNode(type, source)) + return true + end +end + +local myplugin = { OnCompileFunctionParam = OnCompileFunctionParam } + +---@diagnostic disable: await-in-sync +local function TestPlugin(script) + local prefix = [[ + ---@class TestClass + ---@field b string + ]] + ---@param checker fun(state:parser.state) + return function (plugin, checker) + files.open(TESTURI) + files.setText(TESTURI, prefix .. script, true) + scope.getScope(TESTURI):set('pluginInterfaces', plugin) + local state = files.getState(TESTURI) + assert(state) + checker(state) + files.remove(TESTURI) + end +end + +TestPlugin [[ + local function t(a) + a.components:test() + end +]](myplugin, function (state) + guide.eachSourceType(state.ast, 'local', function (src) + if guide.getKeyName(src) == 'a' then + local node = vm.compileNode(src) + assert(node) + assert(not vm.isUnknown(node)) + end + end) +end) diff --git a/test/plugins/test.lua b/test/plugins/test.lua index 655d30b8..b6533de9 100644 --- a/test/plugins/test.lua +++ b/test/plugins/test.lua @@ -1,2 +1,3 @@ require 'plugins.ast.test' require 'plugins.ffi.test' +require 'plugins.node.test' diff --git a/test/signature/init.lua b/test/signature/init.lua index 2bf4b824..f46ce017 100644 --- a/test/signature/init.lua +++ b/test/signature/init.lua @@ -88,7 +88,7 @@ end x(1, 2, 3, <??> ]] -{'function x(a: integer, <!...any!>)'} +{'function x(a: any, <!...any!>)'} TEST [[ (''):sub(<??> @@ -106,7 +106,7 @@ end f(1, 'string<??>') ]] -{'function f(a: integer, <!b: string!>, c: any)'} +{'function f(a: any, <!b: any!>, c: any)'} TEST [[ pcall(function () <??> end) @@ -156,7 +156,7 @@ end f({},<??>) ]] -{'function f(a: table, <!b: any!>, c: any)'} +{'function f(a: any, <!b: any!>, c: any)'} TEST [[ for _ in pairs(<??>) do @@ -188,7 +188,7 @@ end x( aaaa <??>, 2) ]] -{"function x(<!a: any!>, b: integer)"} +{"function x(<!a: any!>, b: any)"} TEST [[ local function x(a, b) @@ -196,7 +196,7 @@ end x(<??> aaaa , 2) ]] -{'function x(<!a: any!>, b: integer)'} +{'function x(<!a: any!>, b: any)'} TEST [[ local function x(a, b) @@ -204,7 +204,7 @@ end x(aaaa ,<??> 2) ]] -{'function x(a: any, <!b: integer!>)'} +{'function x(a: any, <!b: any!>)'} TEST [[ local function x(a, b) @@ -212,7 +212,7 @@ end x(aaaa , 2 <??>) ]] -{'function x(a: any, <!b: integer!>)'} +{'function x(a: any, <!b: any!>)'} TEST [[ local fooC |