Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update bindings-generator #139

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 67 additions & 1 deletion generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,23 @@ def get_whole_name(self, generator):
def __str__(self):
return self.canonical_type.whole_name if None != self.canonical_type else self.whole_name

def object_can_convert(self, generator, is_to_native = True):
if self.is_object:
keys = []
if self.canonical_type != None:
keys.append(self.canonical_type.name)
keys.append(self.name)
if is_to_native:
to_native_dict = generator.config['conversions']['to_native']
if NativeType.dict_has_key_re(to_native_dict, keys):
return True
else:
from_native_dict = generator.config['conversions']['from_native']
if NativeType.dict_has_key_re(from_native_dict, keys):
return True

return False

class NativeField(object):
def __init__(self, cursor):
cursor = cursor.canonical
Expand All @@ -426,11 +443,34 @@ def __init__(self, cursor):
self.location = cursor.location
member_field_re = re.compile('m_(\w+)')
match = member_field_re.match(self.name)
self.signature_name = self.name
self.ntype = NativeType.from_type(cursor.type)
if match:
self.pretty_name = match.group(1)
else:
self.pretty_name = self.name

@staticmethod
def can_parse(ntype):
if ntype.kind == cindex.TypeKind.POINTER:
return False
native_type = NativeType.from_type(ntype)
if ntype.kind == cindex.TypeKind.UNEXPOSED and native_type.name != "std::string":
return False
return True

def generate_code(self, current_class = None, generator = None):
gen = current_class.generator if current_class else generator
config = gen.config

if config['definitions'].has_key('public_field'):
tpl = Template(config['definitions']['public_field'],
searchList=[current_class, self])
self.signature_name = str(tpl)
tpl = Template(file=os.path.join(gen.target, "templates", "public_field.c"),
searchList=[current_class, self])
gen.impl_file.write(str(tpl))

# return True if found default argument.
def iterate_param_node(param_node, depth=1):
for node in param_node.get_children():
Expand Down Expand Up @@ -658,6 +698,7 @@ def __init__(self, cursor, generator):
self.namespaced_class_name = self.class_name
self.parents = []
self.fields = []
self.public_fields = []
self.methods = {}
self.static_methods = {}
self.generator = generator
Expand All @@ -675,6 +716,7 @@ def __init__(self, cursor, generator):
self.target_class_name = registration_name
self.namespaced_class_name = get_namespaced_name(cursor)
self.namespace_name = get_namespace_name(cursor)
self.record_deprecated_func = False
self.parse()

@property
Expand All @@ -685,7 +727,9 @@ def parse(self):
'''
parse the current cursor, getting all the necesary information
'''
#print "parse %s class begin" % (self.class_name)
self._deep_iterate(self.cursor)
#print "parse %s class end" % (self.class_name)

def methods_clean(self):
'''
Expand Down Expand Up @@ -762,6 +806,8 @@ def generate_code(self):
if self.generator.script_type == "lua":
for m in self.override_methods_clean():
m['impl'].generate_code(self, is_override = True)
for m in self.public_fields:
m.generate_code(self)
# generate register section
register = Template(file=os.path.join(self.generator.target, "templates", "register.c"),
searchList=[{"current_class": self}])
Expand All @@ -778,6 +824,8 @@ def generate_code(self):
searchList=[{"current_class": self}])
self.doc_func_file.write(str(apidoc_fun_foot_script))
self.doc_func_file.close()
if self.record_deprecated_func:
self.record_deprecated_file.close()
def _deep_iterate(self, cursor=None, depth=0):
for node in cursor.get_children():
# print("%s%s - %s" % ("> " * depth, node.displayname, node.kind))
Expand Down Expand Up @@ -833,8 +881,19 @@ def _process_node(self, cursor):

elif cursor.kind == cindex.CursorKind.FIELD_DECL:
self.fields.append(NativeField(cursor))
if self._current_visibility == cindex.AccessSpecifierKind.PUBLIC and NativeField.can_parse(cursor.type):
self.public_fields.append(NativeField(cursor))
elif cursor.kind == cindex.CursorKind.CXX_ACCESS_SPEC_DECL:
self._current_visibility = cursor.get_access_specifier()
elif cursor.kind == cindex.CursorKind.CXX_METHOD and cursor.get_availability() == cindex.AvailabilityKind.DEPRECATED and self._current_visibility == cindex.AccessSpecifierKind.PUBLIC:
if self.generator.script_type == "lua" and self.generator.record_deprecated_func:
if not self.record_deprecated_func:
docdeprecatedfilepath = os.path.join(self.generator.outdir + "/deprecated", self.class_name + ".txt")
self.record_deprecated_file = open(docdeprecatedfilepath, "w+")
self.record_deprecated_file.write("Deprecated functions of " + self.class_name + "as follows:\n")
self.record_deprecated_func = True
m = NativeFunction(cursor)
self.record_deprecated_file.write(m.func_name + "\n")
elif cursor.kind == cindex.CursorKind.CXX_METHOD and cursor.get_availability() != cindex.AvailabilityKind.DEPRECATED:
# skip if variadic
if self._current_visibility == cindex.AccessSpecifierKind.PUBLIC and not cursor.type.is_function_variadic():
Expand Down Expand Up @@ -926,6 +985,7 @@ def __init__(self, opts):
self.script_control_cpp = opts['script_control_cpp'] == "yes"
self.script_type = opts['script_type']
self.macro_judgement = opts['macro_judgement']
self.record_deprecated_func = opts['record_deprecated_func'] == "yes"

if opts['skip']:
list_of_skips = re.split(",\n?", opts['skip'])
Expand Down Expand Up @@ -1052,6 +1112,11 @@ def generate_code(self):
if not os.path.exists(docfiledir):
os.makedirs(docfiledir)

if self.script_type == "lua" and self.record_deprecated_func:
record_files_dir = self.outdir + "/deprecated"
if not os.path.exists(record_files_dir):
os.makedirs(record_files_dir)

if self.script_type == "lua":
docfilepath = os.path.join(docfiledir, self.out_file + "_api.lua")
else:
Expand Down Expand Up @@ -1395,7 +1460,8 @@ def main():
'out_file': opts.out_file or config.get(s, 'prefix'),
'script_control_cpp': config.get(s, 'script_control_cpp') if config.has_option(s, 'script_control_cpp') else 'no',
'script_type': t,
'macro_judgement': config.get(s, 'macro_judgement') if config.has_option(s, 'macro_judgement') else None
'macro_judgement': config.get(s, 'macro_judgement') if config.has_option(s, 'macro_judgement') else None,
'record_deprecated_func' : config.get(s, 'record_deprecated_func') if config.has_option(s, 'record_deprecated_func') else 'no'
}
generator = Generator(gen_opts)
generator.generate_code()
Expand Down
1 change: 1 addition & 0 deletions targets/lua/conversions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ definitions:
ifunction: "lua_${generator.prefix}_${class_name}_${func_name}"
sfunction: "lua_${generator.prefix}_${class_name}_${func_name}"
constructor: "lua_${generator.prefix}_${class_name}_constructor"
public_field: "lua_${generator.prefix}_${class_name}"
conversions:
# some times you want to use a special native type when converting from spidermonkey to native
# the most common case would be from JS-boolean to bool. Using "bool" will fail here since we
Expand Down
100 changes: 100 additions & 0 deletions targets/lua/templates/public_field.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
## ===== member implementation template
int ${signature_name}_get${name}(lua_State* tolua_S)
{
${namespaced_class_name}* cobj = nullptr;
\#if COCOS2D_DEBUG >= 1
tolua_Error tolua_err;
if (!tolua_isusertype(tolua_S,1,"${generator.scriptname_from_native($namespaced_class_name, $namespace_name)}",0,&tolua_err)) goto tolua_lerror;
\#endif

cobj = (${namespaced_class_name}*)tolua_tousertype(tolua_S,1,0);

\#if COCOS2D_DEBUG >= 1
if (!cobj)
{
tolua_error(tolua_S,"invalid 'cobj' in function '${signature_name}_get${name}'", nullptr);
return 0;
}
\#endif

#if $ntype.is_object and not $ntype.object_can_convert($generator, False)
${ntype.from_native({"generator": $generator,
"type_name": $ntype.namespaced_name.replace("*", ""),
"ntype": $ntype.get_whole_name($generator)+"*",
"level": 2,
"scriptname": $generator.scriptname_from_native($ntype.namespaced_name, $ntype.namespace_name),
"in_value":"&cobj->" + $pretty_name,
})};
#else
${ntype.from_native({"generator": $generator,
"type_name": $ntype.namespaced_name.replace("*", ""),
"ntype": $ntype.get_whole_name($generator),
"level": 2,
"scriptname": $generator.scriptname_from_native($ntype.namespaced_name, $ntype.namespace_name),
"in_value":"cobj->" + $pretty_name,
})};
#end if

return 1;
\#if COCOS2D_DEBUG >= 1
tolua_lerror:
tolua_error(tolua_S,"#ferror in function '${signature_name}_get${name}'.",&tolua_err);
return 0;
\#endif
}

int ${signature_name}_set${name}(lua_State* tolua_S)
{
int argc = 0;
${namespaced_class_name}* cobj = nullptr;
bool ok = true;

\#if COCOS2D_DEBUG >= 1
tolua_Error tolua_err;
if (!tolua_isusertype(tolua_S,1,"${generator.scriptname_from_native($namespaced_class_name, $namespace_name)}",0,&tolua_err)) goto tolua_lerror;
\#endif

cobj = (${namespaced_class_name}*)tolua_tousertype(tolua_S,1,0);

\#if COCOS2D_DEBUG >= 1
if (!cobj)
{
tolua_error(tolua_S,"invalid 'cobj' in function '${signature_name}_set${name}'", nullptr);
return 0;
}
\#endif
argc = lua_gettop(tolua_S) - 1;

if (1 == argc)
{
#if $ntype.is_object and not $ntype.object_can_convert($generator)
${ntype.to_string($generator)}* arg0 = nullptr;
#else
${ntype.to_string($generator)} arg0;
#end if
${ntype.to_native({"generator": $generator,
"arg_idx": 2,
"out_value": "arg0",
"lua_namespaced_class_name": $generator.scriptname_from_native($namespaced_class_name, $namespace_name),
"func_name": $name,
"scriptname": $generator.scriptname_from_native($ntype.namespaced_name, $ntype.namespace_name),
"level": 2,
"arg":$ntype,
})};
#if $ntype.is_object and not $ntype.object_can_convert($generator)
cobj->$pretty_name = *arg0;
#else
cobj->$pretty_name = arg0;
#end if
return 0;
}

CCLOG("%s has wrong number of arguments: %d, was expecting %d \n", "${generator.scriptname_from_native($namespaced_class_name, $namespace_name)}:${name}",argc, 1);
return 0;

\#if COCOS2D_DEBUG >= 1
tolua_lerror:
tolua_error(tolua_S,"#ferror in function '${signature_name}_get${name}'.",&tolua_err);
return 0;
\#endif
}
16 changes: 9 additions & 7 deletions targets/lua/templates/register.c
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
#set has_constructor = False
#if $current_class.methods.has_key('constructor')
#set has_constructor = True
${current_class.methods.constructor.generate_code($current_class)}
#end if
#
#set generator = $current_class.generator
#set methods = $current_class.methods_clean()
#set st_methods = $current_class.static_methods_clean()
#set public_fields = $current_class.public_fields
#
static int lua_${generator.prefix}_${current_class.class_name}_finalize(lua_State* tolua_S)
{
printf("luabindings: finalizing LUA object (${current_class.class_name})");
#if $generator.script_control_cpp
#if not $current_class.is_ref_class and $current_class.has_constructor
\#if COCOS2D_DEBUG >= 1
tolua_Error tolua_err;
if (
Expand All @@ -26,7 +25,7 @@ static int lua_${generator.prefix}_${current_class.class_name}_finalize(lua_Stat
\#if COCOS2D_DEBUG >= 1
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'delete'", nullptr);
\#endif
delete self;
CC_SAFE_DELETE(self);
}
return 0;
\#if COCOS2D_DEBUG >= 1
Expand All @@ -42,21 +41,21 @@ int lua_register_${generator.prefix}_${current_class.class_name}(lua_State* tolu
{
tolua_usertype(tolua_S,"${generator.scriptname_from_native($current_class.namespaced_class_name, $current_class.namespace_name)}");
#if len($current_class.parents) > 0
#if $generator.script_control_cpp and $current_class.has_constructor
#if not $current_class.is_ref_class and $current_class.has_constructor
tolua_cclass(tolua_S,"${current_class.class_name}","${generator.scriptname_from_native($current_class.namespaced_class_name, $current_class.namespace_name)}","${generator.scriptname_from_native($current_class.parents[0].namespaced_class_name,$current_class.parents[0].namespace_name)}",lua_${generator.prefix}_${current_class.class_name}_finalize);
#else
tolua_cclass(tolua_S,"${current_class.class_name}","${generator.scriptname_from_native($current_class.namespaced_class_name, $current_class.namespace_name)}","${generator.scriptname_from_native($current_class.parents[0].namespaced_class_name,$current_class.parents[0].namespace_name)}",nullptr);
#end if
#else
#if $generator.script_control_cpp and $current_class.has_constructor
#if not $current_class.is_ref_class and $current_class.has_constructor
tolua_cclass(tolua_S,"${current_class.class_name}","${generator.scriptname_from_native($current_class.namespaced_class_name, $current_class.namespace_name)}","",lua_${generator.prefix}_${current_class.class_name}_finalize);
#else
tolua_cclass(tolua_S,"${current_class.class_name}","${generator.scriptname_from_native($current_class.namespaced_class_name, $current_class.namespace_name)}","",nullptr);
#end if
#end if

tolua_beginmodule(tolua_S,"${current_class.class_name}");
#if has_constructor
#if $current_class.has_constructor
tolua_function(tolua_S,"new",lua_${generator.prefix}_${current_class.class_name}_constructor);
#end if
#for m in methods
Expand All @@ -67,6 +66,9 @@ int lua_register_${generator.prefix}_${current_class.class_name}(lua_State* tolu
#set fn = m['impl']
tolua_function(tolua_S,"${m['name']}", ${fn.signature_name});
#end for
#for m in public_fields
tolua_variable(tolua_S,"${m.name}", ${m.signature_name}_get${m.name}, ${m.signature_name}_set${m.name});
#end for
tolua_endmodule(tolua_S);
std::string typeName = typeid(${current_class.namespaced_class_name}).name();
g_luaType[typeName] = "${generator.scriptname_from_native($current_class.namespaced_class_name, $current_class.namespace_name)}";
Expand Down