772 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			772 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| -- tolua: container abstract class
 | |
| -- Written by Waldemar Celes
 | |
| -- TeCGraf/PUC-Rio
 | |
| -- Jul 1998
 | |
| -- $Id: container.lua 1141 2006-05-18 23:58:45Z lindquist $
 | |
| 
 | |
| -- This code is free software; you can redistribute it and/or modify it.
 | |
| -- The software provided hereunder is on an "as is" basis, and
 | |
| -- the author has no obligation to provide maintenance, support, updates,
 | |
| -- enhancements, or modifications.
 | |
| 
 | |
| -- table to store namespaced typedefs/enums in global scope
 | |
| global_typedefs = {}
 | |
| global_enums = {}
 | |
| 
 | |
| -- Container class
 | |
| -- Represents a container of features to be bound
 | |
| -- to lua.
 | |
| classContainer =
 | |
| {
 | |
|  curr = nil,
 | |
| }
 | |
| classContainer.__index = classContainer
 | |
| setmetatable(classContainer,classFeature)
 | |
| 
 | |
| -- output tags
 | |
| function classContainer:decltype ()
 | |
|  push(self)
 | |
|  local i=1
 | |
|  while self[i] do
 | |
|   self[i]:decltype()
 | |
|   i = i+1
 | |
|  end
 | |
|  pop()
 | |
| end
 | |
| 
 | |
| 
 | |
| -- write support code
 | |
| function classContainer:supcode ()
 | |
| 
 | |
| 	if not self:check_public_access() then
 | |
| 		return
 | |
| 	end
 | |
| 
 | |
|  push(self)
 | |
|  local i=1
 | |
|  while self[i] do
 | |
|   if self[i]:check_public_access() then
 | |
|   	self[i]:supcode()
 | |
|   end
 | |
|   i = i+1
 | |
|  end
 | |
|  pop()
 | |
| end
 | |
| 
 | |
| function classContainer:hasvar ()
 | |
|  local i=1
 | |
|  while self[i] do
 | |
|   if self[i]:isvariable() then
 | |
| 		 return 1
 | |
| 		end
 | |
|   i = i+1
 | |
|  end
 | |
| 	return 0
 | |
| end
 | |
| 
 | |
| -- Internal container constructor
 | |
| function _Container (self)
 | |
|  setmetatable(self,classContainer)
 | |
|  self.n = 0
 | |
|  self.typedefs = {tolua_n=0}
 | |
|  self.usertypes = {}
 | |
|  self.enums = {tolua_n=0}
 | |
|  self.lnames = {}
 | |
|  return self
 | |
| end
 | |
| 
 | |
| -- push container
 | |
| function push (t)
 | |
| 	t.prox = classContainer.curr
 | |
|  classContainer.curr = t
 | |
| end
 | |
| 
 | |
| -- pop container
 | |
| function pop ()
 | |
| --print("name",classContainer.curr.name)
 | |
| --foreach(classContainer.curr.usertypes,print)
 | |
| --print("______________")
 | |
|  classContainer.curr = classContainer.curr.prox
 | |
| end
 | |
| 
 | |
| -- get current namespace
 | |
| function getcurrnamespace ()
 | |
| 	return getnamespace(classContainer.curr)
 | |
| end
 | |
| 
 | |
| -- append to current container
 | |
| function append (t)
 | |
|  return classContainer.curr:append(t)
 | |
| end
 | |
| 
 | |
| -- append typedef to current container
 | |
| function appendtypedef (t)
 | |
|  return classContainer.curr:appendtypedef(t)
 | |
| end
 | |
| 
 | |
| -- append usertype to current container
 | |
| function appendusertype (t)
 | |
|  return classContainer.curr:appendusertype(t)
 | |
| end
 | |
| 
 | |
| -- append enum to current container
 | |
| function appendenum (t)
 | |
|  return classContainer.curr:appendenum(t)
 | |
| end
 | |
| 
 | |
| -- substitute typedef
 | |
| function applytypedef (mod,type)
 | |
|  return classContainer.curr:applytypedef(mod,type)
 | |
| end
 | |
| 
 | |
| -- check if is type
 | |
| function findtype (type)
 | |
|  local t = classContainer.curr:findtype(type)
 | |
| 	return t
 | |
| end
 | |
| 
 | |
| -- check if is typedef
 | |
| function istypedef (type)
 | |
|  return classContainer.curr:istypedef(type)
 | |
| end
 | |
| 
 | |
| -- get fulltype (with namespace)
 | |
| function fulltype (t)
 | |
|  local curr =  classContainer.curr
 | |
| 	while curr do
 | |
| 	 if curr then
 | |
| 		 if curr.typedefs and curr.typedefs[t] then
 | |
| 		  return curr.typedefs[t]
 | |
| 		 elseif curr.usertypes and curr.usertypes[t] then
 | |
| 		  return curr.usertypes[t]
 | |
| 			end
 | |
| 		end
 | |
| 	 curr = curr.prox
 | |
| 	end
 | |
| 	return t
 | |
| end
 | |
| 
 | |
| -- checks if it requires collection
 | |
| function classContainer:requirecollection (t)
 | |
|  push(self)
 | |
|  local i=1
 | |
| 	local r = false
 | |
|  while self[i] do
 | |
|   r = self[i]:requirecollection(t) or r
 | |
|   i = i+1
 | |
|  end
 | |
| 	pop()
 | |
| 	return r
 | |
| end
 | |
| 
 | |
| 
 | |
| -- get namesapce
 | |
| function getnamespace (curr)
 | |
| 	local namespace = ''
 | |
| 	while curr do
 | |
| 	 if curr and
 | |
| 		   ( curr.classtype == 'class' or curr.classtype == 'namespace')
 | |
| 		then
 | |
| 		 namespace = (curr.original_name or curr.name) .. '::' .. namespace
 | |
| 		 --namespace = curr.name .. '::' .. namespace
 | |
| 		end
 | |
| 	 curr = curr.prox
 | |
| 	end
 | |
| 	return namespace
 | |
| end
 | |
| 
 | |
| -- get namespace (only namespace)
 | |
| function getonlynamespace ()
 | |
|  local curr = classContainer.curr
 | |
| 	local namespace = ''
 | |
| 	while curr do
 | |
| 		if curr.classtype == 'class' then
 | |
| 		 return namespace
 | |
| 		elseif curr.classtype == 'namespace' then
 | |
| 		 namespace = curr.name .. '::' .. namespace
 | |
| 		end
 | |
| 	 curr = curr.prox
 | |
| 	end
 | |
| 	return namespace
 | |
| end
 | |
| 
 | |
| -- check if is enum
 | |
| function isenum (type)
 | |
|  return classContainer.curr:isenum(type)
 | |
| end
 | |
| 
 | |
| -- append feature to container
 | |
| function classContainer:append (t)
 | |
|  self.n = self.n + 1
 | |
|  self[self.n] = t
 | |
|  t.parent = self
 | |
| end
 | |
| 
 | |
| -- append typedef
 | |
| function classContainer:appendtypedef (t)
 | |
|  local namespace = getnamespace(classContainer.curr)
 | |
|  self.typedefs.tolua_n = self.typedefs.tolua_n + 1
 | |
|  self.typedefs[self.typedefs.tolua_n] = t
 | |
| 	self.typedefs[t.utype] = namespace .. t.utype
 | |
| 	global_typedefs[namespace..t.utype] = t
 | |
| 	t.ftype = findtype(t.type) or t.type
 | |
| 	--print("appending typedef "..t.utype.." as "..namespace..t.utype.." with ftype "..t.ftype)
 | |
| 	append_global_type(namespace..t.utype)
 | |
| 	if t.ftype and isenum(t.ftype) then
 | |
| 
 | |
| 		global_enums[namespace..t.utype] = true
 | |
| 	end
 | |
| end
 | |
| 
 | |
| -- append usertype: return full type
 | |
| function classContainer:appendusertype (t)
 | |
| 	local container
 | |
| 	if t == (self.original_name or self.name) then
 | |
| 		container = self.prox
 | |
| 	else
 | |
| 		container = self
 | |
| 	end
 | |
| 	local ft = getnamespace(container) .. t
 | |
| 	container.usertypes[t] = ft
 | |
| 	_usertype[ft] = ft
 | |
| 	return ft
 | |
| end
 | |
| 
 | |
| -- append enum
 | |
| function classContainer:appendenum (t)
 | |
|  local namespace = getnamespace(classContainer.curr)
 | |
|  self.enums.tolua_n = self.enums.tolua_n + 1
 | |
|  self.enums[self.enums.tolua_n] = t
 | |
| 	global_enums[namespace..t.name] = t
 | |
| end
 | |
| 
 | |
| -- determine lua function name overload
 | |
| function classContainer:overload (lname)
 | |
|  if not self.lnames[lname] then
 | |
|   self.lnames[lname] = 0
 | |
|  else
 | |
|   self.lnames[lname] = self.lnames[lname] + 1
 | |
|  end
 | |
|  return format("%02d",self.lnames[lname])
 | |
| end
 | |
| 
 | |
| -- applies typedef: returns the 'the facto' modifier and type
 | |
| function classContainer:applytypedef (mod,type)
 | |
| 	if global_typedefs[type] then
 | |
| 		--print("found typedef "..global_typedefs[type].type)
 | |
| 		local mod1, type1 = global_typedefs[type].mod, global_typedefs[type].ftype
 | |
| 		local mod2, type2 = applytypedef(mod.." "..mod1, type1)
 | |
| 		--return mod2 .. ' ' .. mod1, type2
 | |
| 		return mod2, type2
 | |
| 	end
 | |
| 	do return mod,type end
 | |
| end
 | |
| 
 | |
| -- check if it is a typedef
 | |
| function classContainer:istypedef (type)
 | |
|  local env = self
 | |
|  while env do
 | |
|   if env.typedefs then
 | |
|    local i=1
 | |
|    while env.typedefs[i] do
 | |
|     if env.typedefs[i].utype == type then
 | |
|          return type
 | |
|         end
 | |
|         i = i+1
 | |
|    end
 | |
|   end
 | |
|   env = env.parent
 | |
|  end
 | |
|  return nil
 | |
| end
 | |
| 
 | |
| function find_enum_var(var)
 | |
| 
 | |
| 	if tonumber(var) then return var end
 | |
| 
 | |
| 	local c = classContainer.curr
 | |
| 	while c do
 | |
| 		local ns = getnamespace(c)
 | |
| 		for k,v in pairs(_global_enums) do
 | |
| 			if match_type(var, v, ns) then
 | |
| 				return v
 | |
| 			end
 | |
| 		end
 | |
| 		if c.base and c.base ~= '' then
 | |
| 			c = _global_classes[c:findtype(c.base)]
 | |
| 		else
 | |
| 			c = nil
 | |
| 		end
 | |
| 	end
 | |
| 
 | |
| 	return var
 | |
| end
 | |
| 
 | |
| -- check if is a registered type: return full type or nil
 | |
| function classContainer:findtype (t)
 | |
| 
 | |
| 	t = string.gsub(t, "=.*", "")
 | |
| 	if _basic[t] then
 | |
| 	 return t
 | |
| 	end
 | |
| 
 | |
| 	local _,_,em = string.find(t, "([&%*])%s*$")
 | |
| 	t = string.gsub(t, "%s*([&%*])%s*$", "")
 | |
| 	p = self
 | |
| 	while p and type(p)=='table' do
 | |
| 		local st = getnamespace(p)
 | |
| 
 | |
| 		for i=_global_types.n,1,-1 do -- in reverse order
 | |
| 
 | |
| 			if match_type(t, _global_types[i], st) then
 | |
| 				return _global_types[i]..(em or "")
 | |
| 			end
 | |
| 		end
 | |
| 		if p.base and p.base ~= '' and p.base ~= t then
 | |
| 			--print("type is "..t..", p is "..p.base.." self.type is "..self.type.." self.name is "..self.name)
 | |
| 			p = _global_classes[p:findtype(p.base)]
 | |
| 		else
 | |
| 			p = nil
 | |
| 		end
 | |
| 	end
 | |
| 
 | |
| 	return nil
 | |
| end
 | |
| 
 | |
| function append_global_type(t, class)
 | |
| 	_global_types.n = _global_types.n +1
 | |
| 	_global_types[_global_types.n] = t
 | |
| 	_global_types_hash[t] = 1
 | |
| 	if class then append_class_type(t, class) end
 | |
| end
 | |
| 
 | |
| function append_class_type(t,class)
 | |
| 	if _global_classes[t] then
 | |
| 		class.flags = _global_classes[t].flags
 | |
| 		class.lnames = _global_classes[t].lnames
 | |
| 		if _global_classes[t].base and (_global_classes[t].base ~= '') then
 | |
| 			class.base = _global_classes[t].base or class.base
 | |
| 		end
 | |
| 	end
 | |
| 	_global_classes[t] = class
 | |
| 	class.flags = class.flags or {}
 | |
| end
 | |
| 
 | |
| function match_type(childtype, regtype, st)
 | |
| --print("findtype "..childtype..", "..regtype..", "..st)
 | |
| 	local b,e = string.find(regtype, childtype, -string.len(childtype), true)
 | |
| 	if b then
 | |
| 
 | |
| 		if e == string.len(regtype) and
 | |
| 				(b == 1 or (string.sub(regtype, b-1, b-1) == ':' and
 | |
| 				string.sub(regtype, 1, b-1) == string.sub(st, 1, b-1))) then
 | |
| 			return true
 | |
| 		end
 | |
| 	end
 | |
| 
 | |
| 	return false
 | |
| end
 | |
| 
 | |
| function findtype_on_childs(self, t)
 | |
| 
 | |
| 	local tchild
 | |
| 	if self.classtype == 'class' or self.classtype == 'namespace' then
 | |
| 		for k,v in ipairs(self) do
 | |
| 			if v.classtype == 'class' or v.classtype == 'namespace' then
 | |
| 				if v.typedefs and v.typedefs[t] then
 | |
| 				 return v.typedefs[t]
 | |
| 				elseif v.usertypes and v.usertypes[t] then
 | |
| 				 return v.usertypes[t]
 | |
| 				end
 | |
| 				tchild = findtype_on_childs(v, t)
 | |
| 				if tchild then return tchild end
 | |
| 			end
 | |
| 		end
 | |
| 	end
 | |
| 	return nil
 | |
| 
 | |
| end
 | |
| 
 | |
| function classContainer:isenum (type)
 | |
|  if global_enums[type] then
 | |
| 	return type
 | |
|  else
 | |
|  	return false
 | |
|  end
 | |
| 
 | |
|  local basetype = gsub(type,"^.*::","")
 | |
|  local env = self
 | |
|  while env do
 | |
|   if env.enums then
 | |
|    local i=1
 | |
|    while env.enums[i] do
 | |
|     if env.enums[i].name == basetype then
 | |
|          return true
 | |
|         end
 | |
|         i = i+1
 | |
|    end
 | |
|   end
 | |
|   env = env.parent
 | |
|  end
 | |
|  return false
 | |
| end
 | |
| 
 | |
| methodisvirtual = false -- a global
 | |
| 
 | |
| -- parse chunk
 | |
| function classContainer:doparse (s)
 | |
| --print ("parse "..s)
 | |
| 
 | |
|  -- try the parser hook
 | |
|  do
 | |
|  	local sub = parser_hook(s)
 | |
|  	if sub then
 | |
|  		return sub
 | |
|  	end
 | |
|  end
 | |
| 
 | |
|  -- try the null statement
 | |
|  do
 | |
|  	local b,e,code = string.find(s, "^%s*;")
 | |
|  	if b then
 | |
|  		return strsub(s,e+1)
 | |
|  	end
 | |
|  end
 | |
| 
 | |
|  -- try empty verbatim line
 | |
|  do
 | |
|  	local b,e,code = string.find(s, "^%s*$\n")
 | |
|  	if b then
 | |
|  		return strsub(s,e+1)
 | |
|  	end
 | |
|  end
 | |
| 
 | |
|  -- try Lua code
 | |
|  do
 | |
|   local b,e,code = strfind(s,"^%s*(%b\1\2)")
 | |
|   if b then
 | |
|    Code(strsub(code,2,-2))
 | |
|    return strsub(s,e+1)
 | |
|   end
 | |
|  end
 | |
| 
 | |
|  -- try C code
 | |
|  do
 | |
|   local b,e,code = strfind(s,"^%s*(%b\3\4)")
 | |
|   if b then
 | |
| 	code = '{'..strsub(code,2,-2)..'\n}\n'
 | |
| 	Verbatim(code,'r')        -- verbatim code for 'r'egister fragment
 | |
| 	return strsub(s,e+1)
 | |
|   end
 | |
|  end
 | |
| 
 | |
|  -- try C code for preamble section
 | |
|  do
 | |
|  	local b,e,code = string.find(s, "^%s*(%b\5\6)")
 | |
|  	if b then
 | |
|  		code = string.sub(code, 2, -2).."\n"
 | |
| 		Verbatim(code, '')
 | |
| 		return string.sub(s, e+1)
 | |
|  	end
 | |
|  end
 | |
| 
 | |
|  -- try default_property directive
 | |
|  do
 | |
|  	local b,e,ptype = strfind(s, "^%s*TOLUA_PROPERTY_TYPE%s*%(+%s*([^%)%s]*)%s*%)+%s*;?")
 | |
|  	if b then
 | |
|  		if not ptype or ptype == "" then
 | |
|  			ptype = "default"
 | |
|  		end
 | |
|  		self:set_property_type(ptype)
 | |
| 	 	return strsub(s, e+1)
 | |
|  	end
 | |
|  end
 | |
| 
 | |
|  -- try protected_destructor directive
 | |
|  do
 | |
|  	local b,e = string.find(s, "^%s*TOLUA_PROTECTED_DESTRUCTOR%s*;?")
 | |
| 	if b then
 | |
| 		if self.set_protected_destructor then
 | |
| 	 		self:set_protected_destructor(true)
 | |
| 	 	end
 | |
|  		return strsub(s, e+1)
 | |
|  	end
 | |
|  end
 | |
| 
 | |
|  -- try 'extern' keyword
 | |
|  do
 | |
|  	local b,e = string.find(s, "^%s*extern%s+")
 | |
|  	if b then
 | |
| 		-- do nothing
 | |
|  		return strsub(s, e+1)
 | |
|  	end
 | |
|  end
 | |
| 	
 | |
|  -- try 'virtual' keyworkd
 | |
|  do
 | |
|  	local b,e = string.find(s, "^%s*virtual%s+")
 | |
|  	if b then
 | |
|  		methodisvirtual = true
 | |
|  		return strsub(s, e+1)
 | |
|  	end
 | |
|  end
 | |
| 
 | |
|  -- try labels (public, private, etc)
 | |
|  do
 | |
|  	local b,e = string.find(s, "^%s*%w*%s*:[^:]")
 | |
|  	if b then
 | |
|  		return strsub(s, e) -- preserve the [^:]
 | |
|  	end
 | |
|  end
 | |
| 
 | |
|  -- try module
 | |
|  do
 | |
|   local b,e,name,body = strfind(s,"^%s*module%s%s*([_%w][_%w]*)%s*(%b{})%s*")
 | |
|   if b then
 | |
|    _curr_code = strsub(s,b,e)
 | |
|    Module(name,body)
 | |
|    return strsub(s,e+1)
 | |
|   end
 | |
|  end
 | |
| 
 | |
|  -- try namesapce
 | |
|  do
 | |
|   local b,e,name,body = strfind(s,"^%s*namespace%s%s*([_%w][_%w]*)%s*(%b{})%s*;?")
 | |
|   if b then
 | |
|    _curr_code = strsub(s,b,e)
 | |
|    Namespace(name,body)
 | |
|    return strsub(s,e+1)
 | |
|   end
 | |
|  end
 | |
| 
 | |
|  -- try define
 | |
|  do
 | |
|   local b,e,name = strfind(s,"^%s*#define%s%s*([^%s]*)[^\n]*\n%s*")
 | |
|   if b then
 | |
|    _curr_code = strsub(s,b,e)
 | |
|    Define(name)
 | |
|    return strsub(s,e+1)
 | |
|   end
 | |
|  end
 | |
| 
 | |
|  -- try enumerates
 | |
| 
 | |
|  do
 | |
|   local b,e,name,body,varname = strfind(s,"^%s*enum%s+(%S*)%s*(%b{})%s*([^%s;]*)%s*;?%s*")
 | |
|   if b then
 | |
|    --error("#Sorry, declaration of enums and variables on the same statement is not supported.\nDeclare your variable separately (example: '"..name.." "..varname..";')")
 | |
|    _curr_code = strsub(s,b,e)
 | |
|    Enumerate(name,body,varname)
 | |
|    return strsub(s,e+1)
 | |
|   end
 | |
|  end
 | |
| 
 | |
| -- do
 | |
| --  local b,e,name,body = strfind(s,"^%s*enum%s+(%S*)%s*(%b{})%s*;?%s*")
 | |
| --  if b then
 | |
| --   _curr_code = strsub(s,b,e)
 | |
| --   Enumerate(name,body)
 | |
| --  return strsub(s,e+1)
 | |
| --  end
 | |
| -- end
 | |
| 
 | |
|  do
 | |
|   local b,e,body,name = strfind(s,"^%s*typedef%s+enum[^{]*(%b{})%s*([%w_][^%s]*)%s*;%s*")
 | |
|   if b then
 | |
|    _curr_code = strsub(s,b,e)
 | |
|    Enumerate(name,body)
 | |
|    return strsub(s,e+1)
 | |
|   end
 | |
|  end
 | |
| 
 | |
|  -- try operator
 | |
|  do
 | |
|   local b,e,decl,kind,arg,const = strfind(s,"^%s*([_%w][_%w%s%*&:<>,]-%s+operator)%s*([^%s][^%s]*)%s*(%b())%s*(c?o?n?s?t?)%s*;%s*")
 | |
|   if not b then
 | |
| 		 -- try inline
 | |
|    b,e,decl,kind,arg,const = strfind(s,"^%s*([_%w][_%w%s%*&:<>,]-%s+operator)%s*([^%s][^%s]*)%s*(%b())%s*(c?o?n?s?t?)[%s\n]*%b{}%s*;?%s*")
 | |
|   end
 | |
|   if not b then
 | |
|   	-- try cast operator
 | |
|   	b,e,decl,kind,arg,const = strfind(s, "^%s*(operator)%s+([%w_:%d<>%*%&%s]+)%s*(%b())%s*(c?o?n?s?t?)");
 | |
|   	if b then
 | |
|   		local _,ie = string.find(s, "^%s*%b{}", e+1)
 | |
|   		if ie then
 | |
|   			e = ie
 | |
|   		end
 | |
|   	end
 | |
|   end
 | |
|   if b then
 | |
|    _curr_code = strsub(s,b,e)
 | |
|    Operator(decl,kind,arg,const)
 | |
|    return strsub(s,e+1)
 | |
|   end
 | |
|  end
 | |
| 
 | |
|  -- try function
 | |
|  do
 | |
|   --local b,e,decl,arg,const = strfind(s,"^%s*([~_%w][_@%w%s%*&:<>]*[_%w])%s*(%b())%s*(c?o?n?s?t?)%s*=?%s*0?%s*;%s*")
 | |
|   local b,e,decl,arg,const,virt = strfind(s,"^%s*([^%(\n]+)%s*(%b())%s*(c?o?n?s?t?)%s*(=?%s*0?)%s*;%s*")
 | |
|   if not b then
 | |
|   	-- try function with template
 | |
|   	b,e,decl,arg,const = strfind(s,"^%s*([~_%w][_@%w%s%*&:<>]*[_%w]%b<>)%s*(%b())%s*(c?o?n?s?t?)%s*=?%s*0?%s*;%s*")
 | |
|   end
 | |
|   if not b then
 | |
|    -- try a single letter function name
 | |
|    b,e,decl,arg,const = strfind(s,"^%s*([_%w])%s*(%b())%s*(c?o?n?s?t?)%s*;%s*")
 | |
|   end
 | |
|   if b then
 | |
|   	if virt and string.find(virt, "[=0]") then
 | |
|   		if self.flags then
 | |
|   			self.flags.pure_virtual = true
 | |
|   		end
 | |
|   	end
 | |
|    _curr_code = strsub(s,b,e)
 | |
|    Function(decl,arg,const)
 | |
|    return strsub(s,e+1)
 | |
|   end
 | |
|  end
 | |
| 
 | |
|  -- try inline function
 | |
|  do
 | |
|   local b,e,decl,arg,const = strfind(s,"^%s*([^%(\n]+)%s*(%b())%s*(c?o?n?s?t?)[^;{]*%b{}%s*;?%s*")
 | |
|   --local b,e,decl,arg,const = strfind(s,"^%s*([~_%w][_@%w%s%*&:<>]*[_%w>])%s*(%b())%s*(c?o?n?s?t?)[^;]*%b{}%s*;?%s*")
 | |
|   if not b then
 | |
|    -- try a single letter function name
 | |
|    b,e,decl,arg,const = strfind(s,"^%s*([_%w])%s*(%b())%s*(c?o?n?s?t?).-%b{}%s*;?%s*")
 | |
|   end
 | |
|   if b then
 | |
|    _curr_code = strsub(s,b,e)
 | |
|    Function(decl,arg,const)
 | |
|    return strsub(s,e+1)
 | |
|   end
 | |
|  end
 | |
| 
 | |
|  -- try class
 | |
|  do
 | |
| 	 local b,e,name,base,body
 | |
| 		base = '' body = ''
 | |
| 		b,e,name = strfind(s,"^%s*class%s*([_%w][_%w@]*)%s*;")  -- dummy class
 | |
| 		if not b then
 | |
| 			b,e,name = strfind(s,"^%s*struct%s*([_%w][_%w@]*)%s*;")    -- dummy struct
 | |
| 			if not b then
 | |
| 				b,e,name,base,body = strfind(s,"^%s*class%s*([_%w][_%w@]*)%s*(.-)%s*(%b{})%s*;%s*")
 | |
| 				if not b then
 | |
| 					b,e,name,base,body = strfind(s,"^%s*struct%s*([_%w][_%w@]*)%s*(.-)%s*(%b{})%s*;%s*")
 | |
| 					if not b then
 | |
| 						b,e,name,base,body = strfind(s,"^%s*union%s*([_%w][_%w@]*)%s*(.-)%s*(%b{})%s*;%s*")
 | |
| 						if not b then
 | |
| 							base = ''
 | |
| 							b,e,body,name = strfind(s,"^%s*typedef%s%s*struct%s%s*[_%w]*%s*(%b{})%s*([_%w][_%w@]*)%s*;%s*")
 | |
| 						end
 | |
| 					end
 | |
| 				end
 | |
| 			end
 | |
| 		end
 | |
| 		if b then
 | |
| 			if base ~= '' then
 | |
| 				base = string.gsub(base, "^%s*:%s*", "")
 | |
| 				base = string.gsub(base, "%s*public%s*", "")
 | |
| 				base = split(base, ",")
 | |
| 				--local b,e
 | |
| 				--b,e,base = strfind(base,".-([_%w][_%w<>,:]*)$")
 | |
| 			else
 | |
| 				base = {}
 | |
| 			end
 | |
| 			_curr_code = strsub(s,b,e)
 | |
| 			Class(name,base,body)
 | |
| 			return strsub(s,e+1)
 | |
| 		end
 | |
| 	end
 | |
| 
 | |
|  -- try typedef
 | |
|  do
 | |
|   local b,e,types = strfind(s,"^%s*typedef%s%s*(.-)%s*;%s*")
 | |
|   if b then
 | |
|    _curr_code = strsub(s,b,e)
 | |
|    Typedef(types)
 | |
|    return strsub(s,e+1)
 | |
|   end
 | |
|  end
 | |
| 
 | |
|  -- try variable
 | |
|  do
 | |
|   local b,e,decl = strfind(s,"^%s*([_%w][_@%s%w%d%*&:<>,]*[_%w%d])%s*;%s*")
 | |
|   if b then
 | |
|    _curr_code = strsub(s,b,e)
 | |
| 
 | |
| 	local list = split_c_tokens(decl, ",")
 | |
| 	Variable(list[1])
 | |
| 	if list.n > 1 then
 | |
| 		local _,_,type = strfind(list[1], "(.-)%s+([^%s]*)$");
 | |
| 
 | |
| 		local i =2;
 | |
| 		while list[i] do
 | |
| 			Variable(type.." "..list[i])
 | |
| 			i=i+1
 | |
| 		end
 | |
| 	end
 | |
|    --Variable(decl)
 | |
|    return strsub(s,e+1)
 | |
|   end
 | |
|  end
 | |
| 
 | |
| 	-- try string
 | |
|  do
 | |
|   local b,e,decl = strfind(s,"^%s*([_%w]?[_%s%w%d]-char%s+[_@%w%d]*%s*%[%s*%S+%s*%])%s*;%s*")
 | |
|   if b then
 | |
|    _curr_code = strsub(s,b,e)
 | |
|    Variable(decl)
 | |
|    return strsub(s,e+1)
 | |
|   end
 | |
|  end
 | |
| 
 | |
|  -- try array
 | |
|  do
 | |
|   local b,e,decl = strfind(s,"^%s*([_%w][][_@%s%w%d%*&:]*[]_%w%d])%s*;%s*")
 | |
|   if b then
 | |
|    _curr_code = strsub(s,b,e)
 | |
|    Array(decl)
 | |
|    return strsub(s,e+1)
 | |
|   end
 | |
|  end
 | |
| 
 | |
|  -- no matching
 | |
|  if gsub(s,"%s%s*","") ~= "" then
 | |
|   _curr_code = s
 | |
|   error("#parse error")
 | |
|  else
 | |
|   return ""
 | |
|  end
 | |
| 
 | |
| end
 | |
| 
 | |
| function classContainer:parse (s)
 | |
| 
 | |
| 	self.curr_member_access = nil
 | |
| 
 | |
|  while s ~= '' do
 | |
|   s = self:doparse(s)
 | |
|   methodisvirtual = false
 | |
|  end
 | |
| end
 | |
| 
 | |
| 
 | |
| -- property types
 | |
| 
 | |
| function get_property_type()
 | |
| 
 | |
| 	return classContainer.curr:get_property_type()
 | |
| end
 | |
| 
 | |
| function classContainer:set_property_type(ptype)
 | |
| 	ptype = string.gsub(ptype, "^%s*", "")
 | |
| 	ptype = string.gsub(ptype, "%s*$", "")
 | |
| 
 | |
| 	self.property_type = ptype
 | |
| end
 | |
| 
 | |
| function classContainer:get_property_type()
 | |
| 	return self.property_type or (self.parent and self.parent:get_property_type()) or "default"
 | |
| end
 |