diff options
Diffstat (limited to 'script')
-rw-r--r-- | script/files.lua | 17 | ||||
-rw-r--r-- | script/parser/guide.lua | 34 | ||||
-rw-r--r-- | script/parser/init.lua | 2 | ||||
-rw-r--r-- | script/parser/luadoc.lua | 200 | ||||
-rw-r--r-- | script/plugins/astHelper.lua | 66 |
5 files changed, 234 insertions, 85 deletions
diff --git a/script/files.lua b/script/files.lua index 62f01136..7998ceed 100644 --- a/script/files.lua +++ b/script/files.lua @@ -655,6 +655,17 @@ function m.compileStateAsync(uri, callback) end) end +local function pluginOnTransformAst(uri, state) + local plugin = require 'plugin' + ---TODO: maybe deepcopy astNode + local suc, result = plugin.dispatch('OnTransformAst', uri, state.ast) + if not suc then + return state + end + state.ast = result + return state +end + ---@param uri uri ---@return parser.state? function m.compileState(uri) @@ -700,6 +711,12 @@ function m.compileState(uri) return nil end + state = pluginOnTransformAst(uri, state) + if not state then + log.error('pluginOnTransformAst failed! discard the file state') + return nil + end + m.compileStateThen(state, file) return state diff --git a/script/parser/guide.lua b/script/parser/guide.lua index e7eb3751..103a8cd5 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -419,6 +419,22 @@ function m.getParentType(obj, want) error('guide.getParentType overstack') end +--- 寻找所在父类型 +---@param obj parser.object +---@return parser.object? +function m.getParentTypes(obj, wants) + for _ = 1, 10000 do + obj = obj.parent + if not obj then + return nil + end + if wants[obj.type] then + return obj + end + end + error('guide.getParentTypes overstack') +end + --- 寻找根区块 ---@param obj parser.object ---@return parser.object @@ -1289,4 +1305,22 @@ function m.isParam(source) return true end +---@param source parser.object +---@param index integer +---@return parser.object? +function m.getParam(source, index) + if source.type == 'call' then + local args = source.args + assert(args.type == 'callargs', 'call.args type is\'t callargs') + return args[index] + elseif source.type == 'callargs' then + return source[index] + elseif source.type == 'function' then + local args = source.args + assert(args.type == 'funcargs', 'function.args type is\'t callargs') + return args[index] + end + return nil +end + return m diff --git a/script/parser/init.lua b/script/parser/init.lua index bc004f77..9848ce00 100644 --- a/script/parser/init.lua +++ b/script/parser/init.lua @@ -2,7 +2,7 @@ local api = { compile = require 'parser.compile', lines = require 'parser.lines', guide = require 'parser.guide', - luadoc = require 'parser.luadoc', + luadoc = require 'parser.luadoc'.luadoc, } return api diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index c022adcb..332211e1 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -291,7 +291,7 @@ local function parseTable(parent) needCloseParen = true end field.name = parseName('doc.field.name', field) - or parseIndexField(field) + or parseIndexField(field) if not field.name then pushWarning { type = 'LUADOC_MISS_FIELD_NAME', @@ -401,7 +401,7 @@ local function parseTypeUnitFunction(parent) parent = typeUnit, } arg.name = parseName('doc.type.arg.name', arg) - or parseDots('doc.type.arg.name', arg) + or parseDots('doc.type.arg.name', arg) if not arg.name then pushWarning { type = 'LUADOC_MISS_ARG_NAME', @@ -442,7 +442,7 @@ local function parseTypeUnitFunction(parent) local name try(function () local returnName = parseName('doc.return.name', typeUnit) - or parseDots('doc.return.name', typeUnit) + or parseDots('doc.return.name', typeUnit) if not returnName then return false end @@ -646,15 +646,15 @@ end function parseTypeUnit(parent) local result = parseFunction(parent) - or parseTable(parent) - or parseString(parent) - or parseCode(parent) - or parseInteger(parent) - or parseBoolean(parent) - or parseParen(parent) + or parseTable(parent) + or parseString(parent) + or parseCode(parent) + or parseInteger(parent) + or parseBoolean(parent) + or parseParen(parent) if not result then result = parseName('doc.type.name', parent) - or parseDots('doc.type.name', parent) + or parseDots('doc.type.name', parent) if not result then return nil end @@ -827,7 +827,7 @@ local docSwitch = util.switch() while true do local extend = parseName('doc.extends.name', result) - or parseTable(result) + or parseTable(result) if not extend then pushWarning { type = 'LUADOC_MISS_CLASS_EXTENDS_NAME', @@ -896,7 +896,7 @@ local docSwitch = util.switch() type = 'doc.param', } result.param = parseName('doc.param.name', result) - or parseDots('doc.param.name', result) + or parseDots('doc.param.name', result) if not result.param then pushWarning { type = 'LUADOC_MISS_PARAM_NAME', @@ -951,7 +951,7 @@ local docSwitch = util.switch() dots.parent = docType else docType.name = parseName('doc.return.name', docType) - or parseDots('doc.return.name', docType) + or parseDots('doc.return.name', docType) end result.returns[#result.returns+1] = docType if not checkToken('symbol', ',', 1) then @@ -990,7 +990,7 @@ local docSwitch = util.switch() return false end) result.field = parseName('doc.field.name', result) - or parseIndexField(result) + or parseIndexField(result) if not result.field then pushWarning { type = 'LUADOC_MISS_FIELD_NAME', @@ -1514,7 +1514,7 @@ end local function buildLuaDoc(comment) local text = comment.text local startPos = (comment.type == 'comment.short' and text:match '^%-%s*@()') - or (comment.type == 'comment.long' and text:match '^@()') + or (comment.type == 'comment.long' and text:match '^@()') if not startPos then return { type = 'doc.comment', @@ -1921,6 +1921,14 @@ local function bindDocWithSources(sources, binded) bindGeneric(binded) bindCommentsAndFields(binded) bindReturnIndex(binded) + + -- doc is special node + if lastDoc.special then + if bindDoc(lastDoc.special, binded) then + return + end + end + local row = guide.rowColOf(lastDoc.finish) local suc = bindDocsBetween(sources, binded, guide.positionOf(row, 0), lastDoc.start) if not suc then @@ -1950,13 +1958,14 @@ local function bindDocs(state) binded = {} state.ast.docs.groups[#state.ast.docs.groups+1] = binded end - binded[#binded+1] = doc + binded[#binded+1] = doc if isTailComment(text, doc) then bindDocWithSources(sources, binded) binded = nil else local nextDoc = state.ast.docs[i+1] - if not isNextLine(doc, nextDoc) then + if nextDoc and nextDoc.special + or not isNextLine(doc, nextDoc) then bindDocWithSources(sources, binded) binded = nil end @@ -1974,8 +1983,8 @@ local function findTouch(state, doc) local pos = guide.positionToOffset(state, doc.originalComment.start) for i = pos - 2, 1, -1 do local c = text:sub(i, i) - if c == '\r' - or c == '\n' then + if c == '\r' + or c == '\n' then break elseif c ~= ' ' and c ~= '\t' then @@ -1985,82 +1994,105 @@ local function findTouch(state, doc) end end -return function (state) - local ast = state.ast - local comments = state.comms - table.sort(comments, function (a, b) - return a.start < b.start - end) - ast.docs = { - type = 'doc', - parent = ast, - groups = {}, - } - - pushWarning = function (err) - local errs = state.errs - if err.finish < err.start then - err.finish = err.start +return { + buildAndBindDoc = function (ast, src, comment) + local doc = buildLuaDoc(comment) + if doc then + local pluginDocs = ast.state.pluginDocs or {} + pluginDocs[#pluginDocs+1] = doc + doc.special = src + doc.originalComment = comment + ast.state.pluginDocs = pluginDocs + return true end - local last = errs[#errs] - if last then - if last.start <= err.start and last.finish >= err.finish then - return + return false + end, + luadoc = function (state) + local ast = state.ast + local comments = state.comms + table.sort(comments, function (a, b) + return a.start < b.start + end) + ast.docs = ast.docs or { + type = 'doc', + parent = ast, + groups = {}, + } + + pushWarning = function (err) + local errs = state.errs + if err.finish < err.start then + err.finish = err.start + end + local last = errs[#errs] + if last then + if last.start <= err.start and last.finish >= err.finish then + return + end end + err.level = err.level or 'Warning' + errs[#errs+1] = err + return err end - err.level = err.level or 'Warning' - errs[#errs+1] = err - return err - end - Lines = state.lines + Lines = state.lines - local ci = 1 - NextComment = function (offset, peek) - local comment = comments[ci + (offset or 0)] - if not peek then - ci = ci + 1 + (offset or 0) + local ci = 1 + NextComment = function (offset, peek) + local comment = comments[ci + (offset or 0)] + if not peek then + ci = ci + 1 + (offset or 0) + end + return comment end - 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) + 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 - end - while true do - local comment = NextComment() - if not comment then - break - end - lockResume = false - local doc, rests = buildLuaDoc(comment) - if doc then - insertDoc(doc, comment) - if rests then - for _, rest in ipairs(rests) do - insertDoc(rest, comment) + while true do + local comment = NextComment() + if not comment then + break + end + lockResume = false + local doc, rests = buildLuaDoc(comment) + if doc then + insertDoc(doc, comment) + if rests then + for _, rest in ipairs(rests) do + insertDoc(rest, comment) + end end end end - end + + if ast.state.pluginDocs then + for i, doc in ipairs(ast.state.pluginDocs) do + insertDoc(doc, doc.originalComment) + end + table.sort(ast.docs, function (a, b) + return a.start < b.start + end) + end - ast.docs.start = ast.start - ast.docs.finish = ast.finish + ast.docs.start = ast.start + ast.docs.finish = ast.finish - if #ast.docs == 0 then - return - end + if #ast.docs == 0 then + return + end - bindDocs(state) -end + bindDocs(state) + end +}
\ No newline at end of file diff --git a/script/plugins/astHelper.lua b/script/plugins/astHelper.lua new file mode 100644 index 00000000..6f303c79 --- /dev/null +++ b/script/plugins/astHelper.lua @@ -0,0 +1,66 @@ +local luadoc = require 'parser.luadoc' +local ssub = require 'core.substring' +local guide = require 'parser.guide' +local _M = {} + +function _M.buildComment(t, value) + return { + type = 'comment.short', + start = 1, + finish = 1, + text = "-@" .. t .. " " .. value, + } +end + +function _M.InsertDoc(ast, comm) + local comms = ast.state.comms or {} + comms[#comms+1] = comm + ast.state.comms = comms +end + +--- give the local/global variable add doc.class +---@param ast parser.object +---@param source parser.object local/global variable +---@param classname string +function _M.addClassDoc(ast, source, classname) + if source.type ~= 'local' and not guide.isGlobal(source) then + return false + end + --TODO fileds + --TODO callers + local comment = _M.buildComment("class", classname) + comment.start = source.start - 1 + comment.finish = comment.start + + return luadoc.buildAndBindDoc(ast, source, comment) +end + +---remove `ast` function node `index` arg, the variable will be the function local variable +---@param source parser.object function node +---@param index integer +---@return parser.object? +function _M.removeArg(source, index) + if source.type == 'function' then + local arg = table.remove(source.args, index) + if not arg then + return nil + end + arg.parent = arg.parent.parent + return arg + end + return nil +end + +--- 把特定函数当成构造函数,`index` 参数是self +---@param classname string +---@param source parser.object function node +---@param index integer +function _M.addClassDocAtParam(ast, classname, source, index) + local arg = _M.removeArg(source, index) + if arg then + return _M.addClassDoc(ast, arg, classname) + end + return false +end + +return _M |