diff options
Diffstat (limited to 'script/parser')
-rw-r--r-- | script/parser/guide.lua | 4 | ||||
-rw-r--r-- | script/parser/luadoc.lua | 215 |
2 files changed, 169 insertions, 50 deletions
diff --git a/script/parser/guide.lua b/script/parser/guide.lua index 0768cbb4..76f0fbca 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -4,7 +4,7 @@ local type = type ---@class parser.object ---@field bindDocs parser.object[] ---@field bindGroup parser.object[] ----@field bindSources parser.object[] +---@field bindSource parser.object[] ---@field value parser.object ---@field parent parser.object ---@field type string @@ -51,6 +51,8 @@ local type = type ---@field upvalues table<string, string[]> ---@field ref parser.object[] ---@field returnIndex integer +---@field assignIndex integer +---@field docIndex integer ---@field docs parser.object[] ---@field state table ---@field comment table diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index ca23b331..1b538e84 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -860,7 +860,22 @@ local docSwitch = util.switch() end) : case 'type' : call(function () - return parseType() + local first = parseType() + if not first then + return nil + end + first.docIndex = 1 + local rests + while checkToken('symbol', ',', 1) do + nextToken() + local rest = parseType() + if not rests then + rests = {} + end + rests[#rests+1] = rest + rest.docIndex = #rests + 1 + end + return first, rests end) : case 'alias' : call(function () @@ -1444,10 +1459,17 @@ local function buildLuaDoc(comment) local doc = text:sub(startPos) parseTokens(doc, comment.start + startPos) - local result = convertTokens() + local result, rests = convertTokens() if result then result.range = comment.finish - local cstart = text:find('%S', (result.firstFinish or result.finish) - comment.start) + local finish = result.firstFinish or result.finish + if rests then + for _, rest in ipairs(rests) do + rest.range = comment.finish + finish = rest.firstFinish or result.finish + end + end + local cstart = text:find('%S', finish - comment.start) if cstart and cstart < comment.finish then result.comment = { type = 'doc.tailcomment', @@ -1456,11 +1478,16 @@ local function buildLuaDoc(comment) parent = result, text = trimTailComment(text:sub(cstart)), } + if rests then + for _, rest in ipairs(rests) do + rest.comment = result.comment + end + end end end if result then - return result + return result, rests end return { @@ -1560,7 +1587,82 @@ local function bindGeneric(binded) end end -local function bindDocsBetween(sources, binded, bindSources, start, finish) +local function bindDoc(source, binded) + local ok = false + for _, doc in ipairs(binded) do + if doc.bindSource then + goto CONTINUE + end + if doc.type == 'doc.class' + or doc.type == 'doc.type' + or doc.type == 'doc.deprecated' + or doc.type == 'doc.version' + or doc.type == 'doc.module' then + if source.type == 'function' + or source.type == 'self' then + goto CONTINUE + end + elseif doc.type == 'doc.overload' then + if not source.bindDocs then + source.bindDocs = {} + end + source.bindDocs[#source.bindDocs+1] = doc + if source.type ~= 'function' then + doc.bindSource = source + end + elseif doc.type == 'doc.param' then + local suc + if source.type == 'local' + and doc.param[1] == source[1] + and ( source.parent.type == 'funcargs' + or ( source.parent.type == 'in' + and source.finish <= source.parent.keys.finish + ) + ) then + suc = true + elseif source.type == '...' + and doc.param[1] == '...' then + suc = true + elseif source.type == 'self' + and doc.param[1] == 'self' then + suc = true + end + if source.type == 'function' then + if not source.bindDocs then + source.bindDocs = {} + end + source.bindDocs[#source.bindDocs+1] = doc + end + + if not suc then + goto CONTINUE + end + elseif doc.type == 'doc.vararg' then + if source.type ~= '...' then + goto CONTINUE + end + elseif doc.type == 'doc.return' + or doc.type == 'doc.generic' + or doc.type == 'doc.async' + or doc.type == 'doc.nodiscard' then + if source.type ~= 'function' then + goto CONTINUE + end + elseif doc.type ~= 'doc.comment' then + goto CONTINUE + end + if not source.bindDocs then + source.bindDocs = {} + end + source.bindDocs[#source.bindDocs+1] = doc + doc.bindSource = source + ok = true + ::CONTINUE:: + end + return ok +end + +local function bindDocsBetween(sources, binded, start, finish) -- 用二分法找到第一个 local max = #sources local index @@ -1583,28 +1685,14 @@ local function bindDocsBetween(sources, binded, bindSources, start, finish) end end + local ok = false -- 从前往后进行绑定 - local skipUntil for i = index, max do local src = sources[i] if src and src.start >= start then if src.start >= finish then break end - if skipUntil then - if skipUntil > src.start then - goto CONTINUE - else - skipUntil = nil - end - end - -- 遇到table后中断,处理以下情况: - -- ---@type AAA - -- local t = {x = 1, y = 2} - if src.type == 'table' then - skipUntil = skipUntil or src.finish - goto CONTINUE - end if src.start >= start then if src.type == 'local' or src.type == 'self' @@ -1615,14 +1703,17 @@ local function bindDocsBetween(sources, binded, bindSources, start, finish) or src.type == 'setfield' or src.type == 'setindex' or src.type == 'setmethod' - or src.type == 'function' then - src.bindDocs = binded - bindSources[#bindSources+1] = src + or src.type == 'function' + or src.type == '...' then + if bindDoc(src, binded) then + ok = true + end end end - ::CONTINUE:: end end + + return ok end local function bindReturnIndex(binded) @@ -1637,30 +1728,49 @@ local function bindReturnIndex(binded) end end -local function bindClassAndFields(binded) +local function bindCommentsToDoc(doc, comments) + doc.bindComments = comments + for _, comment in ipairs(comments) do + comment.bindSource = doc + end +end + +local function bindCommentsAndFields(binded) local class + local comments = {} for _, doc in ipairs(binded) do if doc.type == 'doc.class' then -- 多个class连续写在一起,只有最后一个class可以绑定source if class then - class.bindSources = nil + class.bindSource = nil end class = doc + bindCommentsToDoc(doc, comments) + comments = {} elseif doc.type == 'doc.field' then if class then class.fields[#class.fields+1] = doc doc.class = class end + bindCommentsToDoc(doc, comments) + comments = {} elseif doc.type == 'doc.operator' then if class then class.operators[#class.operators+1] = doc doc.class = class end + bindCommentsToDoc(doc, comments) + comments = {} + elseif doc.type == 'doc.alias' then + bindCommentsToDoc(doc, comments) + comments = {} + elseif doc.type == 'doc.comment' then + comments[#comments+1] = doc end end end -local function bindDoc(sources, binded) +local function bindDocWithSources(sources, binded) if not binded then return end @@ -1668,19 +1778,17 @@ local function bindDoc(sources, binded) if not lastDoc then return end - local bindSources = {} for _, doc in ipairs(binded) do doc.bindGroup = binded - doc.bindSources = bindSources end bindGeneric(binded) + bindCommentsAndFields(binded) + bindReturnIndex(binded) local row = guide.rowColOf(lastDoc.finish) - bindDocsBetween(sources, binded, bindSources, guide.positionOf(row, 0), lastDoc.start) - if #bindSources == 0 then - bindDocsBetween(sources, binded, bindSources, guide.positionOf(row + 1, 0), guide.positionOf(row + 2, 0)) + local suc = bindDocsBetween(sources, binded, guide.positionOf(row, 0), lastDoc.start) + if not suc then + bindDocsBetween(sources, binded, guide.positionOf(row + 1, 0), guide.positionOf(row + 2, 0)) end - bindReturnIndex(binded) - bindClassAndFields(binded) end local bindDocAccept = { @@ -1707,17 +1815,17 @@ local function bindDocs(state) end binded[#binded+1] = doc if isTailComment(text, doc) then - bindDoc(sources, binded) + bindDocWithSources(sources, binded) binded = nil else local nextDoc = state.ast.docs[i+1] if not isNextLine(doc, nextDoc) then - bindDoc(sources, binded) + bindDocWithSources(sources, binded) binded = nil end if not isContinuedDoc(doc, nextDoc) and not isTailComment(text, nextDoc) then - bindDoc(sources, binded) + bindDocWithSources(sources, binded) binded = nil end end @@ -1767,24 +1875,33 @@ return function (state) return comment end + local function insertDoc(doc, comment) + ast.docs[#ast.docs+1] = doc + doc.parent = ast.docs + if ast.start > doc.start then + ast.start = doc.start + end + if ast.finish < doc.finish then + ast.finish = doc.finish + end + doc.originalComment = comment + if comment.type == 'comment.long' then + findTouch(state, doc) + end + end + while true do local comment = NextComment() if not comment then break end - local doc = buildLuaDoc(comment) + local doc, rests = buildLuaDoc(comment) if doc then - ast.docs[#ast.docs+1] = doc - doc.parent = ast.docs - if ast.start > doc.start then - ast.start = doc.start - end - if ast.finish < doc.finish then - ast.finish = doc.finish - end - doc.originalComment = comment - if comment.type == 'comment.long' then - findTouch(state, doc) + insertDoc(doc, comment) + if rests then + for _, rest in ipairs(rests) do + insertDoc(rest, comment) + end end end end |