|
|
|
@ -1,20 +1,26 @@
|
|
|
|
|
#!/usr/bin/lua
|
|
|
|
|
|
|
|
|
|
if not (#arg >= 1 and #arg <= 4) then
|
|
|
|
|
print('usage: ' .. arg[0] .. ' <cpp class header> [class name] [cpp class instance] [lua class instance]')
|
|
|
|
|
return false
|
|
|
|
|
-- parse options
|
|
|
|
|
if #arg == 0 then
|
|
|
|
|
print('usage: ' .. arg[0] .. ' <headers> [--doc]')
|
|
|
|
|
os.exit(1)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
cppclassheader = arg[1]
|
|
|
|
|
cppclassname = arg[2]
|
|
|
|
|
cppclassinstance = arg[3]
|
|
|
|
|
luaclassname = arg[3] or luaclassname
|
|
|
|
|
gendoc = false
|
|
|
|
|
for i=1,#arg do
|
|
|
|
|
if arg[i] == '--doc' then
|
|
|
|
|
table.remove(arg, i)
|
|
|
|
|
gendoc = true
|
|
|
|
|
break
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if not io.open(cppclassheader, 'r') then
|
|
|
|
|
print('could not open ' .. cppclassheader)
|
|
|
|
|
return false
|
|
|
|
|
if #arg == 0 then
|
|
|
|
|
print('Specify a file.')
|
|
|
|
|
os.exit(1)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- string utilities
|
|
|
|
|
function string:matchcount(pattern)
|
|
|
|
|
local count = 0
|
|
|
|
|
for w in self:gmatch(pattern) do count = count + 1 end
|
|
|
|
@ -28,68 +34,234 @@ function string:splitlines()
|
|
|
|
|
return t
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
classfound = false
|
|
|
|
|
publicmethods = false
|
|
|
|
|
for line in io.lines(cppclassheader) do
|
|
|
|
|
foundclassname = line:match('^class ([%w_]+)')
|
|
|
|
|
if foundclassname then
|
|
|
|
|
if not cppclassname then
|
|
|
|
|
guessedclassname = cppclassheader:match('([%w_]+)\.h$'):lower()
|
|
|
|
|
if foundclassname:lower() == guessedclassname then
|
|
|
|
|
cppclassname = foundclassname
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function table.removevalue(t, value)
|
|
|
|
|
for k,v in pairs(t) do
|
|
|
|
|
if v == value then
|
|
|
|
|
table.remove(t, k)
|
|
|
|
|
break
|
|
|
|
|
end
|
|
|
|
|
if foundclassname == cppclassname then
|
|
|
|
|
classfound = true
|
|
|
|
|
publicmethods = false
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if cppclassinstance then
|
|
|
|
|
print(' g_lua.registerStaticClass("' .. luaclassname .. '");')
|
|
|
|
|
else
|
|
|
|
|
baseclassname = line:match(': public ([%w_]+)')
|
|
|
|
|
bindline = ' g_lua.registerClass<' .. cppclassname
|
|
|
|
|
function string.split(s, delim)
|
|
|
|
|
local start = 1
|
|
|
|
|
local results = {}
|
|
|
|
|
while true do
|
|
|
|
|
local pos = string.find(s, delim, start, true)
|
|
|
|
|
if not pos then
|
|
|
|
|
break
|
|
|
|
|
end
|
|
|
|
|
table.insert(results, string.sub(s, start, pos-1))
|
|
|
|
|
start = pos + string.len(delim)
|
|
|
|
|
end
|
|
|
|
|
table.insert(results, string.sub(s, start))
|
|
|
|
|
table.removevalue(results, '')
|
|
|
|
|
return results
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if baseclassname and baseclassname ~= 'LuaObject' then
|
|
|
|
|
bindline = bindline .. ', ' .. baseclassname
|
|
|
|
|
end
|
|
|
|
|
function string.trim(s)
|
|
|
|
|
return string.match(s, '^%s*(.*%S)') or ''
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
bindline = bindline .. '>();'
|
|
|
|
|
print(bindline)
|
|
|
|
|
function countbrackets(str)
|
|
|
|
|
local ret = 0
|
|
|
|
|
for _i in str:gmatch('{') do ret = ret+1 end
|
|
|
|
|
for _i in str:gmatch('}') do ret = ret-1 end
|
|
|
|
|
return ret
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
bindline = ' g_lua.bindClassStaticFunction<' .. cppclassname .. '>("create", []{ return ' .. cppclassname .. 'Ptr(new ' .. cppclassname .. '); });'
|
|
|
|
|
print(bindline)
|
|
|
|
|
end
|
|
|
|
|
elseif classfound then
|
|
|
|
|
return true
|
|
|
|
|
function filterType(arg)
|
|
|
|
|
arg = arg:gsub('^const[%s]+', '')
|
|
|
|
|
arg = arg:gsub('Ptr', '')
|
|
|
|
|
arg = arg:gsub('&', '')
|
|
|
|
|
arg = arg:gsub('.*List$', 'table')
|
|
|
|
|
arg = arg:gsub('^std::string$', 'string')
|
|
|
|
|
arg = arg:gsub('^OTMLNode$', 'table')
|
|
|
|
|
arg = arg:gsub('^std::vector<.*>$', 'table')
|
|
|
|
|
arg = arg:gsub('^std::map<.*>$', 'table')
|
|
|
|
|
arg = arg:gsub('^[u]?int[0-9_t]*$', 'integer')
|
|
|
|
|
arg = arg:gsub('^float$', 'number')
|
|
|
|
|
arg = arg:gsub('^double$', 'number')
|
|
|
|
|
arg = arg:gsub('^bool$', 'boolean')
|
|
|
|
|
arg = arg:gsub('^ticks_t$', 'integer')
|
|
|
|
|
arg = arg:gsub('.*\*.*', 'buffer')
|
|
|
|
|
arg = arg:gsub('.*::.*', 'enum')
|
|
|
|
|
return arg
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function filterArgs(str)
|
|
|
|
|
local args = str:split(',') or { str }
|
|
|
|
|
|
|
|
|
|
newstr = ''
|
|
|
|
|
for i,argstr in pairs(args) do
|
|
|
|
|
argstr = argstr:gsub('[%s]*=.*','')
|
|
|
|
|
local argtype, argvar = argstr:match('^(.*[%s]+[&*]?)([%w_]*)')
|
|
|
|
|
newstr = newstr .. filterType(argtype:trim()) .. ' ' .. argvar:trim()
|
|
|
|
|
|
|
|
|
|
if i ~= #args then
|
|
|
|
|
newstr = newstr .. ', '
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if classfound then
|
|
|
|
|
if line:match('public:') then
|
|
|
|
|
publicmethods = true
|
|
|
|
|
elseif line:match('private:') or line:match('protected:') then
|
|
|
|
|
publicmethods = false
|
|
|
|
|
elseif publicmethods then
|
|
|
|
|
funcname, args = line:match('^ *[%w <>&\*:_]* ([%w_]+)%(([^%)]*%))[%w ]*[;{=].*$')
|
|
|
|
|
if funcname then
|
|
|
|
|
if funcname ~= cppclassname and funcname ~= 'create' then
|
|
|
|
|
numargs = args:matchcount('[^,)]+[,)]')
|
|
|
|
|
|
|
|
|
|
if cppclassinstance then
|
|
|
|
|
bindline = ' g_lua.bindClassStaticFunction("' .. luaclassname .. '", "' .. funcname .. '", ' ..
|
|
|
|
|
'std::bind(&' .. cppclassname .. "::" .. funcname .. ', &' .. cppclassinstance
|
|
|
|
|
for i=1,numargs do
|
|
|
|
|
bindline = bindline .. ', std::placeholders::_' .. i
|
|
|
|
|
|
|
|
|
|
return newstr
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function filterReturn(str)
|
|
|
|
|
str = str:gsub('virtual ', '')
|
|
|
|
|
str = str:gsub('static ', '')
|
|
|
|
|
return filterType(str:trim())
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function emitSingletonDecl(cppclass, luaclass)
|
|
|
|
|
if gendoc then
|
|
|
|
|
outline = 'class ' .. luaclass .. ' {\n' ..
|
|
|
|
|
'public:'
|
|
|
|
|
else
|
|
|
|
|
outline = ' // ' .. luaclass .. '\n' ..
|
|
|
|
|
' g_lua.registerStaticClass("' .. luaclass .. '");'
|
|
|
|
|
end
|
|
|
|
|
print(outline)
|
|
|
|
|
return outline
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function emitClassDecl(cppclass, luaclass, baseclass)
|
|
|
|
|
local outline
|
|
|
|
|
if gendoc then
|
|
|
|
|
outline = 'class ' .. luaclass
|
|
|
|
|
if cppclass ~= 'LuaObject' and baseclass then
|
|
|
|
|
outline = outline .. ' : public ' .. baseclass
|
|
|
|
|
end
|
|
|
|
|
outline = outline .. ' {\npublic:'
|
|
|
|
|
else
|
|
|
|
|
print(' // ' .. luaclass)
|
|
|
|
|
outline = ' g_lua.registerClass<' .. cppclass
|
|
|
|
|
if cppclass ~= 'LuaObject' and baseclass and baseclass ~= 'LuaObject' then
|
|
|
|
|
outline = outline .. ', ' .. baseclass
|
|
|
|
|
end
|
|
|
|
|
outline = outline .. '>();'
|
|
|
|
|
end
|
|
|
|
|
print(outline)
|
|
|
|
|
return outline
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function emitClassEnd()
|
|
|
|
|
local outline = '\n'
|
|
|
|
|
if gendoc then
|
|
|
|
|
outline = '};\n'
|
|
|
|
|
end
|
|
|
|
|
print(outline)
|
|
|
|
|
return outline
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function emitSingletonFunctionDecl(cppclass, luaclass, funcname, funcargs, funcret)
|
|
|
|
|
local outline
|
|
|
|
|
if gendoc then
|
|
|
|
|
outline = ' ' .. filterReturn(funcret) .. ' ' .. funcname .. '(' .. filterArgs(funcargs) .. ');'
|
|
|
|
|
else
|
|
|
|
|
outline = ' g_lua.bindSingletonFunction("' .. luaclass .. '", "' .. funcname .. '", &' .. cppclass .. '::' .. funcname .. ', &' .. luaclass .. ');'
|
|
|
|
|
end
|
|
|
|
|
print(outline)
|
|
|
|
|
return outline
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function emitMemberFunctionDecl(cppclass, luaclass, funcname, funcargs, funcret)
|
|
|
|
|
local outline
|
|
|
|
|
if gendoc then
|
|
|
|
|
outline = ' ' .. filterReturn(funcret) .. ' ' .. funcname .. '(' .. filterArgs(funcargs) .. ');'
|
|
|
|
|
else
|
|
|
|
|
outline = ' g_lua.bindClassMemberFunction("' .. funcname .. '", &' .. cppclass .. '::' .. funcname .. ');'
|
|
|
|
|
end
|
|
|
|
|
print(outline)
|
|
|
|
|
return outline
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function parseClassHeader(line, param)
|
|
|
|
|
cppclass = line:match('^[%s]*class[%s]+([%w_]+)')
|
|
|
|
|
if not cppclass then
|
|
|
|
|
print('Invalid directive at ' .. header .. ':' .. linenumber)
|
|
|
|
|
os.exit(1)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
luaclass = param or cppclass
|
|
|
|
|
insideclass = true
|
|
|
|
|
publicmethods = true
|
|
|
|
|
brackets = 0
|
|
|
|
|
bindnext = true
|
|
|
|
|
|
|
|
|
|
if singleton then
|
|
|
|
|
emitSingletonDecl(cppclass, luaclass)
|
|
|
|
|
else
|
|
|
|
|
baseclass = line:match(':[%s]+public[%s]+([%w_]+)')
|
|
|
|
|
emitClassDecl(cppclass, luaclass, baseclass)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function parseHeader(file)
|
|
|
|
|
header = file
|
|
|
|
|
linenumber = 0
|
|
|
|
|
brackets = 0
|
|
|
|
|
publicmethods = false
|
|
|
|
|
insideclass = false
|
|
|
|
|
singleton = false
|
|
|
|
|
|
|
|
|
|
if not io.open(header, 'r') then
|
|
|
|
|
print('Unable to open ' .. header)
|
|
|
|
|
exit(1)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
lines = {}
|
|
|
|
|
for line in io.lines(header) do table.insert(lines, line) end
|
|
|
|
|
|
|
|
|
|
for linenumber=1,#lines do
|
|
|
|
|
local line = lines[linenumber]
|
|
|
|
|
local param = line:match('^[%s]*//[%s]*@[%w]+[%s]+(.*)[%s]*')
|
|
|
|
|
|
|
|
|
|
if not insideclass then
|
|
|
|
|
if line:match('[%s]*//[%s]*@bindsingleton') then
|
|
|
|
|
singleton = true
|
|
|
|
|
linenumber = linenumber+1
|
|
|
|
|
parseClassHeader(lines[linenumber], param)
|
|
|
|
|
elseif line:match('[%s]*//[%s]*@bindclass') then
|
|
|
|
|
singleton = false
|
|
|
|
|
linenumber = linenumber+1
|
|
|
|
|
parseClassHeader(lines[linenumber], param)
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
if brackets > 1 then
|
|
|
|
|
-- ignore
|
|
|
|
|
elseif line:match('[%s]*//[%s]*@dontbind') then
|
|
|
|
|
bindnext = false
|
|
|
|
|
elseif line:match('[%s]*template') then
|
|
|
|
|
bindnext = false
|
|
|
|
|
elseif line:match('[%s]*public:') then
|
|
|
|
|
publicmethods = true
|
|
|
|
|
elseif line:match('[%s]*private:') or line:match('[%s]*protected:') then
|
|
|
|
|
publicmethods = false
|
|
|
|
|
elseif line:match('^};') then
|
|
|
|
|
insideclass = false
|
|
|
|
|
emitClassEnd()
|
|
|
|
|
elseif bindnext then
|
|
|
|
|
funcreturn, funcname, funcargs = line:match('^[%s]*([%w <>&\*:_]*) ([%w_]+)%(([^%)]*%))[%w ]*[;{=].*$')
|
|
|
|
|
if funcname then
|
|
|
|
|
funcargs = funcargs:match('(.*)\%)')
|
|
|
|
|
if funcname ~= cppclass then
|
|
|
|
|
if singleton then
|
|
|
|
|
emitSingletonFunctionDecl(cppclass, luaclass, funcname, funcargs, funcreturn)
|
|
|
|
|
else
|
|
|
|
|
emitMemberFunctionDecl(cppclass, luaclass, funcname, funcargs, funcreturn)
|
|
|
|
|
end
|
|
|
|
|
bindline = bindline .. '));'
|
|
|
|
|
else
|
|
|
|
|
bindline = ' g_lua.bindClassMemberFunction<' .. cppclassname .. '>("' .. funcname .. '", &' ..
|
|
|
|
|
cppclassname .. '::' .. funcname .. ');'
|
|
|
|
|
end
|
|
|
|
|
print(bindline)
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
bindnext = true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
brackets = brackets + countbrackets(line)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return true
|
|
|
|
|
for i=1,#arg do
|
|
|
|
|
parseHeader(arg[i])
|
|
|
|
|
end
|