diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/build-3rd-meta.lua | 4 | ||||
-rw-r--r-- | tools/love-api.lua | 3 | ||||
-rw-r--r-- | tools/lovr-api.lua | 234 |
3 files changed, 239 insertions, 2 deletions
diff --git a/tools/build-3rd-meta.lua b/tools/build-3rd-meta.lua new file mode 100644 index 00000000..ab6b683e --- /dev/null +++ b/tools/build-3rd-meta.lua @@ -0,0 +1,4 @@ +package.path = package.path .. ';script/?.lua;tools/?.lua' + +dofile 'tools/love-api.lua' +dofile 'tools/lovr-api.lua' diff --git a/tools/love-api.lua b/tools/love-api.lua index 32ded033..90f43876 100644 --- a/tools/love-api.lua +++ b/tools/love-api.lua @@ -1,5 +1,4 @@ - -package.path = package.path .. ';script/?.lua;tools/?.lua;3rd/love-api/?.lua' +package.path = package.path .. ';3rd/love-api/?.lua' local lua51 = require 'Lua51' local api = lua51.require 'love_api' diff --git a/tools/lovr-api.lua b/tools/lovr-api.lua new file mode 100644 index 00000000..6bbc52b4 --- /dev/null +++ b/tools/lovr-api.lua @@ -0,0 +1,234 @@ +local fs = require 'bee.filesystem' +local fsu = require 'fs-utility' + +local api = dofile('3rd/lovr-api/api/init.lua') + +local metaPath = fs.path 'meta/3rd/lovr' +local libraryPath = metaPath / 'library' +fs.create_directories(libraryPath) + +local knownTypes = { + ['nil'] = 'nil', + ['any'] = 'any', + ['boolean'] = 'boolean', + ['number'] = 'number', + ['integer'] = 'integer', + ['string'] = 'string', + ['table'] = 'table', + ['function'] = 'function', + ['userdata'] = 'userdata', + ['lightuserdata'] = 'lightuserdata', + ['thread'] = 'thread', + ['cdata'] = 'ffi.cdata*', + ['light userdata'] = 'lightuserdata', + ['Variant'] = 'any', +} + +local function trim(name) + name = name:gsub('^%s+', '') + name = name:gsub('%s+$', '') + return name +end + +---@param names string +local function getTypeName(names) + if names == '*' then + return 'any' + end + local types = {} + names = names:gsub('%sor%s', '|') + for name in names:gmatch '[^|]+' do + name = trim(name) + types[#types+1] = knownTypes[name] or ('lovr.' .. name) + end + return table.concat(types, '|') +end + +local function formatIndex(key) + if key:match '^[%a_][%w_]*$' then + return key + end + return ('[%q]'):format(key) +end + +local buildType + +local function buildDocTable(tbl) + local fields = {} + for _, field in ipairs(tbl) do + if field.name ~= '...' then + fields[#fields+1] = ('%s: %s'):format(formatIndex(field.name), buildType(field)) + end + end + return ('{%s}'):format(table.concat(fields, ', ')) +end + +function buildType(param) + if param.table then + return buildDocTable(param.table) + end + if param.type then + return getTypeName(param.type) + end + return 'any' +end + +local function buildSuper(tp) + if not tp.supertypes then + return '' + end + local parents = {} + for _, parent in ipairs(tp.supertypes) do + parents[#parents+1] = getTypeName(parent) + end + return (': %s'):format(table.concat(parents, ', ')) +end + +local function buildDescription(desc) + if desc then + return ('---\n---%s\n---'):format(desc:gsub('([\r\n])', '%1---')) + else + return nil + end +end + +local function buildDocFunc(variant) + local params = {} + local returns = {} + for _, param in ipairs(variant.arguments or {}) do + if param.name == '...' then + params[#params+1] = '...' + else + if param.name:find '^[\'"]' then + params[#params+1] = ('%s: %s|%q'):format(param.name:sub(2, -2), getTypeName(param.type), param.name) + else + params[#params+1] = ('%s: %s'):format(param.name, getTypeName(param.type)) + end + end + end + for _, rtn in ipairs(variant.returns or {}) do + returns[#returns+1] = ('%s'):format(getTypeName(rtn.type)) + end + return ('fun(%s)%s'):format( + table.concat(params, ', '), + #returns > 0 and (':' .. table.concat(returns, ', ')) or '' + ) +end + +local function buildMultiDocFunc(tp) + local cbs = {} + for _, variant in ipairs(tp.variants) do + cbs[#cbs+1] = buildDocFunc(variant) + end + return table.concat(cbs, '|') +end + +local function buildFunction(func) + local text = {} + text[#text+1] = buildDescription(func.description) + for i = 2, #func.variants do + local variant = func.variants[i] + text[#text+1] = ('---@overload %s'):format(buildDocFunc(variant)) + end + local params = {} + for _, param in ipairs(func.variants[1].arguments or {}) do + for paramName in param.name:gmatch '[%a_][%w_]*' do + params[#params+1] = paramName + text[#text+1] = ('---@param %s%s %s # %s'):format( + paramName, + param.default == nil and '' or '?', + buildType(param), + param.description + ) + end + end + for _, rtn in ipairs(func.variants[1].returns or {}) do + for returnName in rtn.name:gmatch '[%a_][%w_]*' do + text[#text+1] = ('---@return %s %s # %s'):format( + buildType(rtn), + returnName, + rtn.description + ) + end + end + text[#text+1] = ('function %s(%s) end'):format( + func.key, + table.concat(params, ', ') + ) + return table.concat(text, '\n') +end + +local function buildFile(defs) + local class = defs.key + local filePath = libraryPath / (class .. '.lua') + local text = {} + + text[#text+1] = '---@meta' + text[#text+1] = '' + text[#text+1] = buildDescription(defs.description) + text[#text+1] = ('---@class %s'):format(class) + text[#text+1] = ('%s = {}'):format(class) + + for _, func in ipairs(defs.functions or {}) do + text[#text+1] = '' + text[#text+1] = buildFunction(func) + end + + for _, obj in ipairs(defs.objects or {}) do + local mark = {} + text[#text+1] = '' + text[#text+1] = buildDescription(obj.description) + text[#text+1] = ('---@class %s%s'):format(getTypeName(obj.name), buildSuper(obj)) + text[#text+1] = ('local %s = {}'):format(obj.name) + for _, func in ipairs(obj.methods or {}) do + if not mark[func.name] then + mark[func.name] = true + text[#text+1] = '' + text[#text+1] = buildFunction(func) + end + end + end + + for _, enum in ipairs(defs.enums or {}) do + text[#text+1] = '' + text[#text+1] = buildDescription(enum.description) + text[#text+1] = ('---@class %s'):format(getTypeName(enum.name)) + for _, constant in ipairs(enum.values) do + text[#text+1] = buildDescription(constant.description) + text[#text+1] = ('---@field %s integer'):format(formatIndex(constant.name)) + end + end + + if defs.version then + text[#text+1] = '' + text[#text+1] = ('return %s'):format(class) + end + + text[#text+1] = '' + + fsu.saveFile(filePath, table.concat(text, '\n')) +end + +local function buildCallback(defs) + local filePath = libraryPath / ('callback.lua') + local text = {} + + text[#text+1] = '---@meta' + + for _, cb in ipairs(defs.callbacks or {}) do + text[#text+1] = '' + text[#text+1] = buildDescription(cb.description) + text[#text+1] = ('---@type %s'):format(buildMultiDocFunc(cb)) + text[#text+1] = ('%s = nil'):format(cb.key) + end + + text[#text+1] = '' + + fsu.saveFile(filePath, table.concat(text, '\n')) +end + +buildCallback(api) + +for _, module in ipairs(api.modules) do + buildFile(module) +end |