diff options
-rw-r--r-- | changelog.md | 15 | ||||
-rw-r--r-- | script/core/generic.lua | 45 | ||||
-rw-r--r-- | script/core/hover/table.lua | 6 | ||||
-rw-r--r-- | script/core/noder.lua | 227 | ||||
-rw-r--r-- | script/parser/luadoc.lua | 4 | ||||
-rw-r--r-- | test/type_inference/init.lua | 11 |
6 files changed, 182 insertions, 126 deletions
diff --git a/changelog.md b/changelog.md index 2f4125f7..f4aa68a6 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,21 @@ # changelog ## 2.2.0 +* `NEW` `LuaDoc`: supports literal table: + ```lua + ---@generic T + ---@param x T + ---@return { x: number, y: T, z?: boolean} + local function f(x) end + + local t = f('str') + -- hovering "t" shows: + local t: { + x: number, + y: string, + z?: boolean, + } + ``` * `FIX` supports for file with LF ## 2.1.0 diff --git a/script/core/generic.lua b/script/core/generic.lua index 5f9ad5a4..47cad7df 100644 --- a/script/core/generic.lua +++ b/script/core/generic.lua @@ -34,9 +34,7 @@ end ---@param proto parser.guide.object ---@return generic.value local function createValue(closure, proto, callback, road) - if callback then - road = road or {} - end + road = road or {} if proto.type == 'doc.type' then local types = {} local hasGeneric @@ -54,6 +52,8 @@ local function createValue(closure, proto, callback, road) end local value = instantValue(closure, proto) value.types = types + value.enums = proto.enums + value.resumes = proto.resumes noder.compileNode(noder.getNoders(proto), value) return value end @@ -98,18 +98,15 @@ local function createValue(closure, proto, callback, road) return value end if proto.type == 'doc.type.array' then - if road then - road[#road+1] = noder.WEAK_ANY_FIELD - end + road[#road+1] = noder.WEAK_ANY_FIELD local node = createValue(closure, proto.node, callback, road) - if road then - road[#road] = nil - end + road[#road] = nil if not node then return nil end local value = instantValue(closure, proto) value.node = node + noder.compileNode(noder.getNoders(proto), value) return value end if proto.type == 'doc.type.table' then @@ -127,6 +124,36 @@ local function createValue(closure, proto, callback, road) local value = instantValue(closure, proto) value.tkey = tkey or proto.tkey value.tvalue = tvalue or proto.tvalue + noder.compileNode(noder.getNoders(proto), value) + return value + end + if proto.type == 'doc.type.ltable' then + local fields = {} + for i, field in ipairs(proto.fields) do + fields[i] = createValue(closure, field, callback, road) or field + end + if #fields == 0 then + return nil + end + local value = instantValue(closure, proto) + value.fields = fields + noder.compileNode(noder.getNoders(proto), value) + return value + end + if proto.type == 'doc.type.field' then + road[#road+1] = ('%s%q'):format( + noder.SPLIT_CHAR, + proto.name[1] + ) + local typeUnit = createValue(closure, proto.extends, callback, road) + road[#road] = nil + if not typeUnit then + return nil + end + local value = instantValue(closure, proto) + value.name = proto.name + value.extends = typeUnit + noder.compileNode(noder.getNoders(proto), value) return value end end diff --git a/script/core/hover/table.lua b/script/core/hover/table.lua index c3a8fe95..bd0274cf 100644 --- a/script/core/hover/table.lua +++ b/script/core/hover/table.lua @@ -116,6 +116,12 @@ local function getOptionalMap(fields) optionals[key] = true end end + if field.type == 'doc.type.field' then + if field.optional then + local key = vm.getKeyName(field) + optionals[key] = true + end + end end return optionals end diff --git a/script/core/noder.lua b/script/core/noder.lua index eac1b9f5..2558a22e 100644 --- a/script/core/noder.lua +++ b/script/core/noder.lua @@ -646,6 +646,87 @@ local function compileCallReturn(noders, call, sourceID, returnIndex) pushBackward(noders, funcXID, sourceID, 'deep') end +function m.compileDocValue(noders, tp, id, source) + if tp == 'doc.type' then + if source.bindSources then + for _, src in ipairs(source.bindSources) do + pushForward(noders, getID(src), id) + pushForward(noders, id, getID(src)) + end + end + for _, enumUnit in ipairs(source.enums) do + pushForward(noders, id, getID(enumUnit)) + end + for _, resumeUnit in ipairs(source.resumes) do + pushForward(noders, id, getID(resumeUnit)) + end + for _, typeUnit in ipairs(source.types) do + local unitID = getID(typeUnit) + pushForward(noders, id, unitID) + if source.bindSources then + for _, src in ipairs(source.bindSources) do + pushBackward(noders, unitID, getID(src)) + end + end + end + end + if tp == 'doc.type.table' then + if source.tkey then + local keyID = ('%s%s'):format( + id, + TABLE_KEY + ) + pushForward(noders, keyID, getID(source.tkey)) + end + if source.tvalue then + local valueID = ('%s%s'):format( + id, + ANY_FIELD + ) + pushForward(noders, valueID, getID(source.tvalue)) + end + end + if tp == 'doc.type.ltable' then + local firstField = source.fields[1] + if not firstField then + return + end + local keyID = ('%s%s'):format( + id, + WEAK_TABLE_KEY + ) + local valueID = ('%s%s'):format( + id, + WEAK_ANY_FIELD + ) + pushForward(noders, keyID, 'dn:string') + pushForward(noders, valueID, getID(firstField.extends)) + for _, field in ipairs(source.fields) do + local extendsID = ('%s%s%q'):format( + id, + SPLIT_CHAR, + field.name[1] + ) + pushForward(noders, extendsID, getID(field)) + pushForward(noders, extendsID, getID(field.extends)) + end + end + if tp == 'doc.type.array' then + if source.node then + local nodeID = ('%s%s'):format( + id, + ANY_FIELD + ) + pushForward(noders, nodeID, getID(source.node)) + end + local keyID = ('%s%s'):format( + id, + TABLE_KEY + ) + pushForward(noders, keyID, 'dn:integer') + end +end + ---@param noders noders ---@param source parser.guide.object ---@return parser.guide.object[] @@ -695,29 +776,29 @@ function m.compileNode(noders, source) end end -- 分解 @type - if source.type == 'doc.type' then - if source.bindSources then - for _, src in ipairs(source.bindSources) do - pushForward(noders, getID(src), id) - pushForward(noders, id, getID(src)) - end - end - for _, enumUnit in ipairs(source.enums) do - pushForward(noders, id, getID(enumUnit)) - end - for _, resumeUnit in ipairs(source.resumes) do - pushForward(noders, id, getID(resumeUnit)) - end - for _, typeUnit in ipairs(source.types) do - local unitID = getID(typeUnit) - pushForward(noders, id, unitID) - if source.bindSources then - for _, src in ipairs(source.bindSources) do - pushBackward(noders, unitID, getID(src)) - end - end - end - end + --if source.type == 'doc.type' then + -- if source.bindSources then + -- for _, src in ipairs(source.bindSources) do + -- pushForward(noders, getID(src), id) + -- pushForward(noders, id, getID(src)) + -- end + -- end + -- for _, enumUnit in ipairs(source.enums) do + -- pushForward(noders, id, getID(enumUnit)) + -- end + -- for _, resumeUnit in ipairs(source.resumes) do + -- pushForward(noders, id, getID(resumeUnit)) + -- end + -- for _, typeUnit in ipairs(source.types) do + -- local unitID = getID(typeUnit) + -- pushForward(noders, id, unitID) + -- if source.bindSources then + -- for _, src in ipairs(source.bindSources) do + -- pushBackward(noders, unitID, getID(src)) + -- end + -- end + -- end + --end -- 分解 @alias if source.type == 'doc.alias' then pushForward(noders, getID(source.alias), getID(source.extends)) @@ -773,6 +854,7 @@ function m.compileNode(noders, source) pushForward(noders, fieldID, fieldClassID) end end + m.compileDocValue(noders, source.type, id, source) if source.type == 'call' then if source.parent.type ~= 'select' then compileCallReturn(noders, source, id, 1) @@ -818,61 +900,6 @@ function m.compileNode(noders, source) end) end end - if source.type == 'doc.type.table' then - if source.tkey then - local keyID = ('%s%s'):format( - id, - TABLE_KEY - ) - pushForward(noders, keyID, getID(source.tkey)) - end - if source.tvalue then - local valueID = ('%s%s'):format( - id, - ANY_FIELD - ) - pushForward(noders, valueID, getID(source.tvalue)) - end - end - if source.type == 'doc.type.ltable' then - local firstField = source.fields[1] - if not firstField then - return - end - local keyID = ('%s%s'):format( - id, - WEAK_TABLE_KEY - ) - local valueID = ('%s%s'):format( - id, - WEAK_ANY_FIELD - ) - pushForward(noders, keyID, 'dn:string') - pushForward(noders, valueID, getID(firstField.extends)) - for _, field in ipairs(source.fields) do - local extendsID = ('%s%s%q'):format( - id, - SPLIT_CHAR, - field.name[1] - ) - pushForward(noders, extendsID, getID(field)) - pushForward(noders, extendsID, getID(field.extends)) - end - end - if source.type == 'doc.type.array' then - if source.node then - local nodeID = ('%s%s'):format( - id, - ANY_FIELD - ) - pushForward(noders, nodeID, getID(source.node)) - end - local keyID = ('%s%s'):format( - id, - TABLE_KEY - ) - pushForward(noders, keyID, 'dn:integer') - end if source.type == 'doc.type.name' then local uri = guide.getUri(source) collector.subscribe(uri, id, getNode(noders, id)) @@ -1056,43 +1083,13 @@ function m.compileNode(noders, source) end end end - if proto.type == 'doc.type' then - for _, tp in ipairs(source.types) do - pushForward(noders, id, getID(tp)) - pushBackward(noders, getID(tp), id) - end - end - if proto.type == 'doc.type.array' then - local nodeID = ('%s%s'):format( - id, - ANY_FIELD - ) - pushForward(noders, nodeID, getID(source.node)) - local keyID = ('%s%s'):format( - id, - TABLE_KEY - ) - pushForward(noders, keyID, 'dn:integer') - end - if proto.type == 'doc.type.table' then - if source.tkey then - local keyID = ('%s%s'):format( - id, - TABLE_KEY - ) - pushForward(noders, keyID, getID(source.tkey)) - end - if source.tvalue then - local valueID = ('%s%s'):format( - id, - ANY_FIELD - ) - pushForward(noders, valueID, getID(source.tvalue)) - end - end - if proto.type == 'doc.type.ltable' then - -- TODO - end + --if proto.type == 'doc.type' then + -- for _, tp in ipairs(source.types) do + -- pushForward(noders, id, getID(tp)) + -- pushBackward(noders, getID(tp), id) + -- end + --end + m.compileDocValue(noders, proto.type, id, source) end end diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index 45e59fe9..f47a43c3 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -407,7 +407,7 @@ local function parseTypeUnitLiteralTable(parent) } do - field.name = parseName('doc.ltfield.name', field) + field.name = parseName('doc.field.name', field) if not field.name then pushError { type = 'LUADOC_MISS_FIELD_NAME', @@ -438,7 +438,7 @@ local function parseTypeUnitLiteralTable(parent) if checkToken('symbol', ',', 1) then nextToken() else - nextSymbolOrError(')') + nextSymbolOrError('}') break end end diff --git a/test/type_inference/init.lua b/test/type_inference/init.lua index 3df73863..83e73487 100644 --- a/test/type_inference/init.lua +++ b/test/type_inference/init.lua @@ -867,3 +867,14 @@ end xpcall(work, debug.traceback, function (<?value?>) end) ]] + +TEST 'string' [[ +---@generic T +---@param x T +---@return { x: T } +local function f(x) end + +local t = f('') + +print(t.<?x?>) +]] |