mirror of
				https://github.com/edubart/otclient.git
				synced 2025-11-04 04:36:23 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			267 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Lua
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			267 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Lua
		
	
	
		
			Executable File
		
	
	
	
	
#!/usr/bin/lua
 | 
						|
 | 
						|
-- parse options
 | 
						|
if #arg == 0 then
 | 
						|
  print('usage: ' .. arg[0] .. ' <headers> [--doc]')
 | 
						|
  os.exit(1)
 | 
						|
end
 | 
						|
 | 
						|
gendoc = false
 | 
						|
for i=1,#arg do
 | 
						|
  if arg[i] == '--doc' then
 | 
						|
    table.remove(arg, i)
 | 
						|
    gendoc = true
 | 
						|
    break
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
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
 | 
						|
  return count
 | 
						|
end
 | 
						|
 | 
						|
function string:splitlines()
 | 
						|
  local t = {}
 | 
						|
  local function helper(line) table.insert(t, line) return "" end
 | 
						|
  helper((self:gsub("(.-)\r?\n", helper)))
 | 
						|
  return t
 | 
						|
end
 | 
						|
 | 
						|
 | 
						|
function table.removevalue(t, value)
 | 
						|
  for k,v in pairs(t) do
 | 
						|
    if v == value then
 | 
						|
      table.remove(t, k)
 | 
						|
      break
 | 
						|
    end
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
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
 | 
						|
 | 
						|
function string.trim(s)
 | 
						|
  return string.match(s, '^%s*(.*%S)') or ''
 | 
						|
end
 | 
						|
 | 
						|
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
 | 
						|
 | 
						|
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
 | 
						|
 | 
						|
  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
 | 
						|
          end
 | 
						|
        end
 | 
						|
      else
 | 
						|
        bindnext = true
 | 
						|
      end
 | 
						|
      brackets = brackets + countbrackets(line)
 | 
						|
    end
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
for i=1,#arg do
 | 
						|
  parseHeader(arg[i])
 | 
						|
end |