diff options
Diffstat (limited to 'script/parser')
-rw-r--r-- | script/parser/guide.lua | 201 | ||||
-rw-r--r-- | script/parser/luadoc.lua | 323 | ||||
-rw-r--r-- | script/parser/newparser.lua | 10 |
3 files changed, 305 insertions, 229 deletions
diff --git a/script/parser/guide.lua b/script/parser/guide.lua index eda85c97..f490b306 100644 --- a/script/parser/guide.lua +++ b/script/parser/guide.lua @@ -1,66 +1,59 @@ local error = error local type = type ----@class parser.guide.object ----@field bindDocs parser.guide.object[] ----@field bindGroup parser.guide.object[] ----@field bindSources parser.guide.object[] ----@field value parser.guide.object ----@field parent parser.guide.object +---@class parser.object +---@field bindDocs parser.object[] +---@field bindGroup parser.object[] +---@field bindSources parser.object[] +---@field value parser.object +---@field parent parser.object ---@field type string ---@field special string ---@field tag string ----@field args parser.guide.object[] ----@field locals parser.guide.object[] ----@field returns parser.guide.object[] +---@field args parser.object[] +---@field locals parser.object[] +---@field returns parser.object[] ---@field uri uri ---@field start integer ---@field finish integer ---@field effect integer ---@field attrs string[] ----@field specials parser.guide.object[] ----@field labels parser.guide.object[] ----@field node parser.guide.object +---@field specials parser.object[] +---@field labels parser.object[] +---@field node parser.object ---@field dummy boolean ----@field field parser.guide.object ----@field method parser.guide.object ----@field index parser.guide.object ----@field extends parser.guide.object[] ----@field types parser.guide.object[] ----@field fields parser.guide.object[] ----@field typeGeneric table<integer, parser.guide.object[]> ----@field tkey parser.guide.object ----@field tvalue parser.guide.object +---@field field parser.object +---@field method parser.object +---@field index parser.object +---@field extends parser.object[]|parser.object +---@field types parser.object[] +---@field fields parser.object[] +---@field tkey parser.object +---@field tvalue parser.object ---@field tindex integer ----@field op parser.guide.object ----@field next parser.guide.object ----@field docParam parser.guide.object +---@field op parser.object +---@field next parser.object +---@field docParam parser.object ---@field sindex integer ----@field name parser.guide.object ----@field call parser.guide.object ----@field closure parser.guide.object ----@field proto parser.guide.object ----@field exp parser.guide.object ----@field isGeneric boolean ----@field alias parser.guide.object ----@field class parser.guide.object ----@field vararg parser.guide.object ----@field param parser.guide.object ----@field overload parser.guide.object +---@field name parser.object +---@field call parser.object +---@field closure parser.object +---@field proto parser.object +---@field exp parser.object +---@field alias parser.object +---@field class parser.object +---@field vararg parser.object +---@field param parser.object +---@field overload parser.object ---@field docParamMap table<string, integer> ---@field upvalues table<string, string[]> ----@field ref parser.guide.object[] +---@field ref parser.object[] ---@field returnIndex integer ----@field docs parser.guide.object[] +---@field docs parser.object[] ---@field state table ---@field comment table ---@field optional boolean ----@field _root parser.guide.object ----@field _noders noders ----@field _mnode parser.guide.object ----@field _noded boolean ----@field _initedNoders boolean ----@field _compiledGlobals boolean +---@field _root parser.object ---@class guide ---@field debugMode boolean @@ -125,8 +118,9 @@ local childMap = { ['unary'] = {1}, ['doc'] = {'#'}, - ['doc.class'] = {'class', '#extends', 'comment'}, + ['doc.class'] = {'class', '#extends', '#signs', 'comment'}, ['doc.type'] = {'#types', 'name', 'comment'}, + ['doc.type.name'] = {'#signs'}, ['doc.alias'] = {'alias', 'extends', 'comment'}, ['doc.param'] = {'param', 'extends', 'comment'}, ['doc.return'] = {'#returns', 'comment'}, @@ -135,19 +129,18 @@ local childMap = { ['doc.generic.object'] = {'generic', 'extends', 'comment'}, ['doc.vararg'] = {'vararg', 'comment'}, ['doc.type.array'] = {'node'}, - ['doc.type.table'] = {'tkey', 'tvalue', 'comment'}, ['doc.type.function'] = {'#args', '#returns', 'comment'}, - ['doc.type.ltable'] = {'#fields', 'comment'}, + ['doc.type.table'] = {'#fields', 'comment'}, ['doc.type.literal'] = {'node'}, ['doc.type.arg'] = {'name', 'extends'}, - ['doc.type.field'] = {'extends'}, + ['doc.type.field'] = {'name', 'extends'}, ['doc.overload'] = {'overload', 'comment'}, ['doc.see'] = {'name', 'field'}, ['doc.version'] = {'#versions'}, ['doc.diagnostic'] = {'#names'}, } ----@type table<string, fun(obj: parser.guide.object, list: parser.guide.object[])> +---@type table<string, fun(obj: parser.object, list: parser.object[])> local compiledChildMap = setmetatable({}, {__index = function (self, name) local defs = childMap[name] if not defs then @@ -227,7 +220,7 @@ local function formatNumber(n) end --- 是否是字面量 ----@param obj parser.guide.object +---@param obj parser.object ---@return boolean function m.isLiteral(obj) local tp = obj.type @@ -241,7 +234,7 @@ function m.isLiteral(obj) end --- 获取字面量 ----@param obj parser.guide.object +---@param obj parser.object ---@return any function m.getLiteral(obj) local tp = obj.type @@ -258,8 +251,8 @@ function m.getLiteral(obj) end --- 寻找父函数 ----@param obj parser.guide.object ----@return parser.guide.object +---@param obj parser.object +---@return parser.object function m.getParentFunction(obj) for _ = 1, 10000 do obj = obj.parent @@ -275,8 +268,8 @@ function m.getParentFunction(obj) end --- 寻找所在区块 ----@param obj parser.guide.object ----@return parser.guide.object +---@param obj parser.object +---@return parser.object function m.getBlock(obj) for _ = 1, 10000 do if not obj then @@ -304,8 +297,8 @@ function m.getBlock(obj) end --- 寻找所在父区块 ----@param obj parser.guide.object ----@return parser.guide.object +---@param obj parser.object +---@return parser.object function m.getParentBlock(obj) for _ = 1, 10000 do obj = obj.parent @@ -321,8 +314,8 @@ function m.getParentBlock(obj) end --- 寻找所在可break的父区块 ----@param obj parser.guide.object ----@return parser.guide.object +---@param obj parser.object +---@return parser.object function m.getBreakBlock(obj) for _ = 1, 10000 do obj = obj.parent @@ -341,8 +334,8 @@ function m.getBreakBlock(obj) end --- 寻找doc的主体 ----@param obj parser.guide.object ----@return parser.guide.object +---@param obj parser.object +---@return parser.object function m.getDocState(obj) for _ = 1, 10000 do local parent = obj.parent @@ -358,8 +351,8 @@ function m.getDocState(obj) end --- 寻找所在父类型 ----@param obj parser.guide.object ----@return parser.guide.object +---@param obj parser.object +---@return parser.object function m.getParentType(obj, want) for _ = 1, 10000 do obj = obj.parent @@ -374,8 +367,8 @@ function m.getParentType(obj, want) end --- 寻找根区块 ----@param obj parser.guide.object ----@return parser.guide.object +---@param obj parser.object +---@return parser.object function m.getRoot(obj) local source = obj if source._root then @@ -399,7 +392,7 @@ function m.getRoot(obj) error('guide.getRoot overstack') end ----@param obj parser.guide.object +---@param obj parser.object ---@return uri function m.getUri(obj) if obj.uri then @@ -653,10 +646,10 @@ function m.eachSourceBetween(ast, start, finish, callback) end local function getSourceTypeCache(ast) - local cache = ast.typeCache + local cache = ast._typeCache if not cache then cache = {} - ast.typeCache = cache + ast._typeCache = cache m.eachSource(ast, function (source) local tp = source.type if not tp then @@ -699,10 +692,10 @@ end --- 遍历所有的source function m.eachSource(ast, callback) - local cache = ast.eachCache + local cache = ast._eachCache if not cache then cache = { ast } - ast.eachCache = cache + ast._eachCache = cache local mark = {} local index = 1 while true do @@ -814,20 +807,25 @@ function m.getLineRange(state, row) end local isSetMap = { - ['setglobal'] = true, - ['local'] = true, - ['setlocal'] = true, - ['setfield'] = true, - ['setmethod'] = true, - ['setindex'] = true, - ['tablefield'] = true, - ['tableindex'] = true, - ['tableexp'] = true, - ['doc.class.name'] = true, - ['doc.alias.name'] = true, - ['doc.field.name'] = true, - ['doc.field'] = true, - ['doc.type.field'] = true, + ['setglobal'] = true, + ['local'] = true, + ['setlocal'] = true, + ['setfield'] = true, + ['setmethod'] = true, + ['setindex'] = true, + ['tablefield'] = true, + ['tableindex'] = true, + ['tableexp'] = true, + ['label'] = true, + ['doc.class'] = true, + ['doc.alias'] = true, + ['doc.field'] = true, + ['doc.type.function'] = true, + ['doc.type.table'] = true, + ['doc.class.name'] = true, + ['doc.alias.name'] = true, + ['doc.field.name'] = true, + ['doc.type.field'] = true, } function m.isSet(source) local tp = source.type @@ -887,17 +885,17 @@ function m.getKeyNameOfLiteral(obj) elseif tp == 'number' then local n = obj[1] if n then - return formatNumber(obj[1]) + return obj[1] end elseif tp == 'integer' then local n = obj[1] if n then - return formatNumber(obj[1]) + return obj[1] end elseif tp == 'boolean' then local b = obj[1] if b then - return tostring(b) + return b end end end @@ -930,7 +928,7 @@ function m.getKeyName(obj) or tp == 'tableindex' then return m.getKeyNameOfLiteral(obj.index) elseif tp == 'tableexp' then - return tostring(obj.tindex) + return obj.tindex elseif tp == 'field' or tp == 'method' or tp == 'doc.see.field' then @@ -940,11 +938,11 @@ function m.getKeyName(obj) elseif tp == 'doc.alias' then return obj.alias[1] elseif tp == 'doc.field' then - return tostring(obj.field[1]) + return obj.field[1] elseif tp == 'doc.field.name' then - return tostring(obj[1]) + return obj[1] elseif tp == 'doc.type.field' then - return tostring(obj.name[1]) + return obj.name[1] elseif tp == 'dummy' then return obj[1] end @@ -1106,7 +1104,7 @@ function m.getPath(a, b, sameFunction) end ---是否是全局变量(包括 _G.XXX 形式) ----@param source parser.guide.object +---@param source parser.object ---@return boolean function m.isGlobal(source) if source._isGlobal ~= nil then @@ -1184,4 +1182,25 @@ function m.isOOP(source) return false end +local baseTypeMap = { + ['unknown'] = true, + ['any'] = true, + ['true'] = true, + ['false'] = true, + ['nil'] = true, + ['boolean'] = true, + ['number'] = true, + ['string'] = true, + ['table'] = true, + ['function'] = true, + ['thread'] = true, + ['userdata'] = true, +} + +---@param str string +---@return boolean +function m.isBaseType(str) + return baseTypeMap[str] == true +end + return m diff --git a/script/parser/luadoc.lua b/script/parser/luadoc.lua index d15fd95a..cf734a53 100644 --- a/script/parser/luadoc.lua +++ b/script/parser/luadoc.lua @@ -120,6 +120,10 @@ Symbol <- ({} { end, }) +---@class parser.object +---@field literal boolean +---@field signs parser.object[] + local function trim(str) return str:match '^%s*(%S+)%s*$' end @@ -220,25 +224,138 @@ local function parseIndexField(tp, parent) return nil end nextToken() - local class = { - type = tp, - start = getStart(), - finish = getFinish(), - parent = parent, + local start = getFinish() - 1 + local indexTP, index = peekToken() + if indexTP == 'name' then + local field = parseType(parent) + nextSymbolOrError ']' + return field + else + nextToken() + local class = { + type = tp, + start = start, + finish = getFinish(), + parent = parent, + } + class[1] = index + nextSymbolOrError ']' + class.finish = getFinish() + return class + end +end + +local function parseTable(parent) + if not checkToken('symbol', '{', 1) then + return nil + end + nextToken() + local typeUnit = { + type = 'doc.type.table', + start = getStart(), + parent = parent, + fields = {}, } - local indexTP, index = nextToken() - if indexTP ~= 'integer' - and indexTP ~= 'string' then + + while true do + if checkToken('symbol', '}', 1) then + nextToken() + break + end + local field = { + type = 'doc.type.field', + parent = typeUnit, + } + + do + field.name = parseName('doc.field.name', field) + or parseIndexField('doc.field.name', field) + if not field.name then + pushWarning { + type = 'LUADOC_MISS_FIELD_NAME', + start = getFinish(), + finish = getFinish(), + } + break + end + if not field.start then + field.start = field.name.start + end + if checkToken('symbol', '?', 1) then + nextToken() + field.optional = true + end + field.finish = getFinish() + if not nextSymbolOrError(':') then + break + end + field.extends = parseType(field) + if not field.extends then + break + end + field.finish = getFinish() + end + + typeUnit.fields[#typeUnit.fields+1] = field + if checkToken('symbol', ',', 1) then + nextToken() + else + nextSymbolOrError('}') + break + end + end + typeUnit.finish = getFinish() + return typeUnit +end + +local function parseSigns(parent, mode) + if not checkToken('symbol', '<', 1) then + return nil + end + nextToken() + local signs = {} + while true do + local sign + if mode == 'name' then + sign = parseName('doc.generic.name', parent) + if not sign then + pushWarning { + type = 'LUADOC_MISS_SIGN_NAME', + start = getFinish(), + finish = getFinish(), + } + break + end + elseif mode == 'type' then + sign = parseType(parent) + if not sign then + pushWarning { + type = 'LUADOC_MISS_TYPE_NAME', + start = getFinish(), + finish = getFinish(), + } + break + end + end + signs[#signs+1] = sign + if checkToken('symbol', ',', 1) then + nextToken() + else + break + end + end + if not checkToken('symbol', '>', 1) then pushWarning { - type = 'LUADOC_INDEX_MUST_INT', - start = getStart(), + type = 'LUADOC_MISS_SYMBOL', + start = getFinish(), finish = getFinish(), + symbol = { + symbol = '>', + } } end - class[1] = index - nextSymbolOrError ']' - class.finish = getFinish() - return class + nextToken() + return signs end local function parseClass(parent) @@ -258,6 +375,7 @@ local function parseClass(parent) end result.start = getStart() result.finish = getFinish() + result.signs = parseSigns(result, 'name') if not checkToken('symbol', ':', 1) then return result end @@ -267,6 +385,7 @@ local function parseClass(parent) while true do local extend = parseName('doc.extends.name', result) + or parseTable(result) if not extend then pushWarning { type = 'LUADOC_MISS_CLASS_EXTENDS_NAME', @@ -301,39 +420,6 @@ local function parseTypeUnitArray(parent, node) return result end -local function parseTypeUnitTable(parent, node) - if not checkToken('symbol', '<', 1) then - return nil - end - if not nextSymbolOrError('<') then - return nil - end - - local result = { - type = 'doc.type.table', - start = node.start, - node = node, - parent = parent, - } - - local key = parseType(result) - if not key or not nextSymbolOrError(',') then - return nil - end - local value = parseType(result) - if not value then - return nil - end - nextSymbolOrError('>') - - node.parent = result - result.finish = getFinish() - result.tkey = key - result.tvalue = value - - return result -end - local function parseDots(tp, parent) if not checkToken('symbol', '...', 1) then return @@ -349,9 +435,14 @@ local function parseDots(tp, parent) return dots end -local function parseTypeUnitFunction() +local function parseTypeUnitFunction(parent) + if not checkToken('name', 'fun', 1) then + return nil + end + nextToken() local typeUnit = { type = 'doc.type.function', + parent = parent, start = getStart(), args = {}, returns = {}, @@ -422,74 +513,17 @@ local function parseTypeUnitFunction() return typeUnit end -local function parseTypeUnitLiteralTable() - local typeUnit = { - type = 'doc.type.ltable', - start = getStart(), - fields = {}, - } - - while true do - if checkToken('symbol', '}', 1) then - nextToken() - break - end - local field = { - type = 'doc.type.field', - parent = typeUnit, - } - - do - field.name = parseName('doc.field.name', field) - or parseIndexField('doc.field.name', field) - if not field.name then - pushWarning { - type = 'LUADOC_MISS_FIELD_NAME', - start = getFinish(), - finish = getFinish(), - } - break - end - if not field.start then - field.start = field.name.start - end - if checkToken('symbol', '?', 1) then - nextToken() - field.optional = true - end - field.finish = getFinish() - if not nextSymbolOrError(':') then - break - end - field.extends = parseType(field) - if not field.extends then - break - end - field.finish = getFinish() - end - - typeUnit.fields[#typeUnit.fields+1] = field - if checkToken('symbol', ',', 1) then - nextToken() - else - nextSymbolOrError('}') - break - end - end - typeUnit.finish = getFinish() - return typeUnit -end - local parseTypeUnit -local function parseDocFunction(parent, content) +local function parseFunction(parent) + local _, content = peekToken() if content == 'async' then + nextToken() local pos = getStart() local tp, cont = peekToken() if tp == 'name' then if cont == 'fun' then - nextToken() - local func = parseTypeUnit(parent, cont) + local func = parseTypeUnit(parent) if func then func.async = true func.asyncPos = pos @@ -499,32 +533,29 @@ local function parseDocFunction(parent, content) end end if content == 'fun' then - return parseTypeUnitFunction() + return parseTypeUnitFunction(parent) end end -function parseTypeUnit(parent, content) - local result = parseDocFunction(parent, content) - if not result then - if content == '{' then - result = parseTypeUnitLiteralTable() - end - end +function parseTypeUnit(parent) + local result = parseFunction(parent) + or parseTable(parent) if not result then + local _, token = nextToken() result = { type = 'doc.type.name', start = getStart(), finish = getFinish(), - [1] = content, + parent = parent, + [1] = token, } + result.signs = parseSigns(result, 'type') end if not result then return nil end - result.parent = parent while true do local newResult = parseTypeUnitArray(parent, result) - or parseTypeUnitTable(parent, result) if not newResult then break end @@ -593,8 +624,7 @@ function parseType(parent) end if tp == 'name' then - nextToken() - local typeUnit = parseTypeUnit(result, content) + local typeUnit = parseTypeUnit(result) if not typeUnit then break end @@ -608,6 +638,13 @@ function parseType(parent) end elseif tp == 'string' then nextToken() + -- compatibility + if content:sub(1, 1) == '"' + or content:sub(1, 1) == "'" then + if content:sub(1, 1) == content:sub(-1, -1) then + content = content:sub(2, -2) + end + end local typeEnum = { type = 'doc.type.enum', start = getStart(), @@ -620,8 +657,7 @@ function parseType(parent) result.start = typeEnum.start end elseif tp == 'symbol' and content == '{' then - nextToken() - local typeUnit = parseTypeUnit(result, content) + local typeUnit = parseTypeUnit(result) if not typeUnit then break end @@ -642,6 +678,16 @@ function parseType(parent) if not result.start then result.start = vararg.start end + elseif tp == 'integer' then + nextToken() + local integer = { + type = 'doc.type.integer', + start = getStart(), + finish = getFinish(), + parent = result, + [1] = content, + } + result.types[#result.types+1] = integer end if not checkToken('symbol', '|', 1) then break @@ -741,6 +787,7 @@ local function parseAlias() return nil end result.start = getStart() + result.signs = parseSigns(result, 'name') result.extends = parseType(result) if not result.extends then pushWarning { @@ -933,11 +980,10 @@ local function parseOverload() } return nil end - nextToken() local result = { type = 'doc.overload', } - result.overload = parseDocFunction(result, name) + result.overload = parseFunction(result) if not result.overload then return nil end @@ -1261,19 +1307,30 @@ end local function bindGeneric(binded) local generics = {} for _, doc in ipairs(binded) do - if doc.type == 'doc.generic' then + if doc.type == 'doc.generic' then for _, obj in ipairs(doc.generics) do local name = obj.generic[1] - generics[name] = {} + generics[name] = true + end + end + if doc.type == 'doc.class' + or doc.type == 'doc.alias' then + if doc.signs then + for _, sign in ipairs(doc.signs) do + local name = sign[1] + generics[name] = true + end end - elseif doc.type == 'doc.param' - or doc.type == 'doc.return' - or doc.type == 'doc.type' then + end + if doc.type == 'doc.param' + or doc.type == 'doc.return' + or doc.type == 'doc.type' + or doc.type == 'doc.class' + or doc.type == 'doc.alias' then guide.eachSourceType(doc, 'doc.type.name', function (src) local name = src[1] if generics[name] then - generics[name][#generics[name]+1] = src - src.typeGeneric = generics + src.type = 'doc.generic.name' end end) end diff --git a/script/parser/newparser.lua b/script/parser/newparser.lua index e4884212..66df7046 100644 --- a/script/parser/newparser.lua +++ b/script/parser/newparser.lua @@ -2588,9 +2588,9 @@ local function skipSeps() end end ----@return parser.guide.object first ----@return parser.guide.object second ----@return parser.guide.object[] rest +---@return parser.object first +---@return parser.object second +---@return parser.object[] rest local function parseSetValues() skipSpace() local first = parseExp() @@ -2645,8 +2645,8 @@ local function pushActionIntoCurrentChunk(action) end end ----@return parser.guide.object second ----@return parser.guide.object[] rest +---@return parser.object second +---@return parser.object[] rest local function parseVarTails(parser, isLocal) if Tokens[Index + 1] ~= ',' then return |