summaryrefslogtreecommitdiff
path: root/script/parser
diff options
context:
space:
mode:
Diffstat (limited to 'script/parser')
-rw-r--r--script/parser/guide.lua201
-rw-r--r--script/parser/luadoc.lua323
-rw-r--r--script/parser/newparser.lua10
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