summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/test.yml18
m---------3rd/bee.lua0
m---------3rd/json.lua0
m---------3rd/luamake0
-rw-r--r--changelog.md3
-rw-r--r--meta/template/table.lua2
-rw-r--r--script/cli/doc.lua19
-rw-r--r--script/cli/init.lua5
-rw-r--r--script/cli/visualize.lua103
-rw-r--r--script/core/rename.lua6
-rw-r--r--script/core/semantic-tokens.lua8
-rw-r--r--script/encoder/ansi.lua12
-rw-r--r--script/global.d.lua4
-rw-r--r--script/parser/guide.lua8
-rw-r--r--script/parser/luadoc.lua86
-rw-r--r--script/plugin.lua57
-rw-r--r--script/plugins/astHelper.lua25
-rw-r--r--script/plugins/nodeHelper.lua75
-rw-r--r--script/proto/proto.lua11
-rw-r--r--script/vm/compiler.lua80
-rw-r--r--script/vm/infer.lua20
-rw-r--r--script/workspace/scope.lua2
-rw-r--r--test.lua1
-rw-r--r--test/cli/test.lua1
-rw-r--r--test/cli/visualize/test.lua23
-rw-r--r--test/cli/visualize/testdata/all-types-expected.txt587
-rw-r--r--test/cli/visualize/testdata/all-types.txt30
-rw-r--r--test/cli/visualize/testdata/shorten-names-expected.txt327
-rw-r--r--test/cli/visualize/testdata/shorten-names.txt18
-rw-r--r--test/diagnostics/assign-type-mismatch.lua7
-rw-r--r--test/diagnostics/await-in-sync.lua2
-rw-r--r--test/diagnostics/redundant-parameter.lua2
-rw-r--r--test/hover/init.lua15
-rw-r--r--test/plugins/ast/test.lua60
-rw-r--r--test/plugins/node/test.lua56
-rw-r--r--test/plugins/test.lua1
-rw-r--r--test/signature/init.lua14
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
diff --git a/test.lua b/test.lua
index 43ec3aae..1036b816 100644
--- a/test.lua
+++ b/test.lua
@@ -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