mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 17:44:04 +08:00
Merge pull request #12303 from cv3d:improvements/binding_python
This commit is contained in:
commit
f826709452
@ -140,17 +140,18 @@ class GeneralInfo():
|
|||||||
|
|
||||||
def fullName(self, isCPP=False):
|
def fullName(self, isCPP=False):
|
||||||
result = ".".join([self.fullClass(), self.name])
|
result = ".".join([self.fullClass(), self.name])
|
||||||
return result if not isCPP else result.replace(".", "::")
|
return result if not isCPP else get_cname(result)
|
||||||
|
|
||||||
def fullClass(self, isCPP=False):
|
def fullClass(self, isCPP=False):
|
||||||
result = ".".join([f for f in [self.namespace] + self.classpath.split(".") if len(f)>0])
|
result = ".".join([f for f in [self.namespace] + self.classpath.split(".") if len(f)>0])
|
||||||
return result if not isCPP else result.replace(".", "::")
|
return result if not isCPP else get_cname(result)
|
||||||
|
|
||||||
class ConstInfo(GeneralInfo):
|
class ConstInfo(GeneralInfo):
|
||||||
def __init__(self, decl, addedManually=False, namespaces=[]):
|
def __init__(self, decl, addedManually=False, namespaces=[], enumType=None):
|
||||||
GeneralInfo.__init__(self, "const", decl, namespaces)
|
GeneralInfo.__init__(self, "const", decl, namespaces)
|
||||||
self.cname = self.name.replace(".", "::")
|
self.cname = get_cname(self.name)
|
||||||
self.value = decl[1]
|
self.value = decl[1]
|
||||||
|
self.enumType = enumType
|
||||||
self.addedManually = addedManually
|
self.addedManually = addedManually
|
||||||
if self.namespace in namespaces_dict:
|
if self.namespace in namespaces_dict:
|
||||||
self.name = '%s_%s' % (namespaces_dict[self.namespace], self.name)
|
self.name = '%s_%s' % (namespaces_dict[self.namespace], self.name)
|
||||||
@ -166,6 +167,25 @@ class ConstInfo(GeneralInfo):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def normalize_field_name(name):
|
||||||
|
return name.replace(".","_").replace("[","").replace("]","").replace("_getNativeObjAddr()","_nativeObj")
|
||||||
|
|
||||||
|
def normalize_class_name(name):
|
||||||
|
return re.sub(r"^cv\.", "", name).replace(".", "_")
|
||||||
|
|
||||||
|
def get_cname(name):
|
||||||
|
return name.replace(".", "::")
|
||||||
|
|
||||||
|
def cast_from(t):
|
||||||
|
if t in type_dict and "cast_from" in type_dict[t]:
|
||||||
|
return type_dict[t]["cast_from"]
|
||||||
|
return t
|
||||||
|
|
||||||
|
def cast_to(t):
|
||||||
|
if t in type_dict and "cast_to" in type_dict[t]:
|
||||||
|
return type_dict[t]["cast_to"]
|
||||||
|
return t
|
||||||
|
|
||||||
class ClassPropInfo():
|
class ClassPropInfo():
|
||||||
def __init__(self, decl): # [f_ctype, f_name, '', '/RW']
|
def __init__(self, decl): # [f_ctype, f_name, '', '/RW']
|
||||||
self.ctype = decl[0]
|
self.ctype = decl[0]
|
||||||
@ -178,7 +198,7 @@ class ClassPropInfo():
|
|||||||
class ClassInfo(GeneralInfo):
|
class ClassInfo(GeneralInfo):
|
||||||
def __init__(self, decl, namespaces=[]): # [ 'class/struct cname', ': base', [modlist] ]
|
def __init__(self, decl, namespaces=[]): # [ 'class/struct cname', ': base', [modlist] ]
|
||||||
GeneralInfo.__init__(self, "class", decl, namespaces)
|
GeneralInfo.__init__(self, "class", decl, namespaces)
|
||||||
self.cname = self.name.replace(".", "::")
|
self.cname = get_cname(self.name)
|
||||||
self.methods = []
|
self.methods = []
|
||||||
self.methods_suffixes = {}
|
self.methods_suffixes = {}
|
||||||
self.consts = [] # using a list to save the occurrence order
|
self.consts = [] # using a list to save the occurrence order
|
||||||
@ -303,7 +323,7 @@ class ArgInfo():
|
|||||||
class FuncInfo(GeneralInfo):
|
class FuncInfo(GeneralInfo):
|
||||||
def __init__(self, decl, namespaces=[]): # [ funcname, return_ctype, [modifiers], [args] ]
|
def __init__(self, decl, namespaces=[]): # [ funcname, return_ctype, [modifiers], [args] ]
|
||||||
GeneralInfo.__init__(self, "func", decl, namespaces)
|
GeneralInfo.__init__(self, "func", decl, namespaces)
|
||||||
self.cname = decl[0].replace(".", "::")
|
self.cname = get_cname(decl[0])
|
||||||
self.jname = self.name
|
self.jname = self.name
|
||||||
self.isconstructor = self.name == self.classname
|
self.isconstructor = self.name == self.classname
|
||||||
if "[" in self.name:
|
if "[" in self.name:
|
||||||
@ -341,7 +361,6 @@ class JavaWrapperGenerator(object):
|
|||||||
self.classes = { "Mat" : ClassInfo([ 'class Mat', '', [], [] ], self.namespaces) }
|
self.classes = { "Mat" : ClassInfo([ 'class Mat', '', [], [] ], self.namespaces) }
|
||||||
self.module = ""
|
self.module = ""
|
||||||
self.Module = ""
|
self.Module = ""
|
||||||
self.enum_types = []
|
|
||||||
self.ported_func_list = []
|
self.ported_func_list = []
|
||||||
self.skipped_func_list = []
|
self.skipped_func_list = []
|
||||||
self.def_args_hist = {} # { def_args_cnt : funcs_cnt }
|
self.def_args_hist = {} # { def_args_cnt : funcs_cnt }
|
||||||
@ -404,8 +423,8 @@ class JavaWrapperGenerator(object):
|
|||||||
)
|
)
|
||||||
logging.info('ok: class %s, name: %s, base: %s', classinfo, name, classinfo.base)
|
logging.info('ok: class %s, name: %s, base: %s', classinfo, name, classinfo.base)
|
||||||
|
|
||||||
def add_const(self, decl): # [ "const cname", val, [], [] ]
|
def add_const(self, decl, enumType=None): # [ "const cname", val, [], [] ]
|
||||||
constinfo = ConstInfo(decl, namespaces=self.namespaces)
|
constinfo = ConstInfo(decl, namespaces=self.namespaces, enumType=enumType)
|
||||||
if constinfo.isIgnored():
|
if constinfo.isIgnored():
|
||||||
logging.info('ignored: %s', constinfo)
|
logging.info('ignored: %s', constinfo)
|
||||||
elif not self.isWrapped(constinfo.classname):
|
elif not self.isWrapped(constinfo.classname):
|
||||||
@ -423,8 +442,16 @@ class JavaWrapperGenerator(object):
|
|||||||
logging.info('ok: %s', constinfo)
|
logging.info('ok: %s', constinfo)
|
||||||
|
|
||||||
def add_enum(self, decl): # [ "enum cname", "", [], [] ]
|
def add_enum(self, decl): # [ "enum cname", "", [], [] ]
|
||||||
enumname = decl[0].replace("enum ", "").strip()
|
enumType = decl[0].rsplit(" ", 1)[1]
|
||||||
self.enum_types.append(enumname)
|
if enumType.endswith("<unnamed>"):
|
||||||
|
enumType = None
|
||||||
|
else:
|
||||||
|
ctype = normalize_class_name(enumType)
|
||||||
|
type_dict[ctype] = { "cast_from" : "int", "cast_to" : get_cname(enumType), "j_type" : "int", "jn_type" : "int", "jni_type" : "jint", "suffix" : "I" }
|
||||||
|
const_decls = decl[3]
|
||||||
|
|
||||||
|
for decl in const_decls:
|
||||||
|
self.add_const(decl, enumType)
|
||||||
|
|
||||||
def add_func(self, decl):
|
def add_func(self, decl):
|
||||||
fi = FuncInfo(decl, namespaces=self.namespaces)
|
fi = FuncInfo(decl, namespaces=self.namespaces)
|
||||||
@ -526,7 +553,7 @@ class JavaWrapperGenerator(object):
|
|||||||
if self.isWrapped(t):
|
if self.isWrapped(t):
|
||||||
return self.getClass(t).fullName(isCPP=True)
|
return self.getClass(t).fullName(isCPP=True)
|
||||||
else:
|
else:
|
||||||
return t
|
return cast_from(t)
|
||||||
|
|
||||||
def gen_func(self, ci, fi, prop_name=''):
|
def gen_func(self, ci, fi, prop_name=''):
|
||||||
logging.info("%s", fi)
|
logging.info("%s", fi)
|
||||||
@ -559,7 +586,7 @@ class JavaWrapperGenerator(object):
|
|||||||
msg = "// Return type '%s' is not supported, skipping the function\n\n" % fi.ctype
|
msg = "// Return type '%s' is not supported, skipping the function\n\n" % fi.ctype
|
||||||
self.skipped_func_list.append(c_decl + "\n" + msg)
|
self.skipped_func_list.append(c_decl + "\n" + msg)
|
||||||
j_code.write( " "*4 + msg )
|
j_code.write( " "*4 + msg )
|
||||||
logging.warning("SKIP:" + c_decl.strip() + "\t due to RET type" + fi.ctype)
|
logging.warning("SKIP:" + c_decl.strip() + "\t due to RET type " + fi.ctype)
|
||||||
return
|
return
|
||||||
for a in fi.args:
|
for a in fi.args:
|
||||||
if a.ctype not in type_dict:
|
if a.ctype not in type_dict:
|
||||||
@ -571,7 +598,7 @@ class JavaWrapperGenerator(object):
|
|||||||
msg = "// Unknown type '%s' (%s), skipping the function\n\n" % (a.ctype, a.out or "I")
|
msg = "// Unknown type '%s' (%s), skipping the function\n\n" % (a.ctype, a.out or "I")
|
||||||
self.skipped_func_list.append(c_decl + "\n" + msg)
|
self.skipped_func_list.append(c_decl + "\n" + msg)
|
||||||
j_code.write( " "*4 + msg )
|
j_code.write( " "*4 + msg )
|
||||||
logging.warning("SKIP:" + c_decl.strip() + "\t due to ARG type" + a.ctype + "/" + (a.out or "I"))
|
logging.warning("SKIP:" + c_decl.strip() + "\t due to ARG type " + a.ctype + "/" + (a.out or "I"))
|
||||||
return
|
return
|
||||||
|
|
||||||
self.ported_func_list.append(c_decl)
|
self.ported_func_list.append(c_decl)
|
||||||
@ -650,7 +677,7 @@ class JavaWrapperGenerator(object):
|
|||||||
if "I" in a.out or not a.out or self.isWrapped(a.ctype): # input arg, pass by primitive fields
|
if "I" in a.out or not a.out or self.isWrapped(a.ctype): # input arg, pass by primitive fields
|
||||||
for f in fields:
|
for f in fields:
|
||||||
jn_args.append ( ArgInfo([ f[0], a.name + f[1], "", [], "" ]) )
|
jn_args.append ( ArgInfo([ f[0], a.name + f[1], "", [], "" ]) )
|
||||||
jni_args.append( ArgInfo([ f[0], a.name + f[1].replace(".","_").replace("[","").replace("]","").replace("_getNativeObjAddr()","_nativeObj"), "", [], "" ]) )
|
jni_args.append( ArgInfo([ f[0], a.name + normalize_field_name(f[1]), "", [], "" ]) )
|
||||||
if "O" in a.out and not self.isWrapped(a.ctype): # out arg, pass as double[]
|
if "O" in a.out and not self.isWrapped(a.ctype): # out arg, pass as double[]
|
||||||
jn_args.append ( ArgInfo([ "double[]", "%s_out" % a.name, "", [], "" ]) )
|
jn_args.append ( ArgInfo([ "double[]", "%s_out" % a.name, "", [], "" ]) )
|
||||||
jni_args.append ( ArgInfo([ "double[]", "%s_out" % a.name, "", [], "" ]) )
|
jni_args.append ( ArgInfo([ "double[]", "%s_out" % a.name, "", [], "" ]) )
|
||||||
@ -698,7 +725,7 @@ class JavaWrapperGenerator(object):
|
|||||||
" private static native $type $name($args);\n").substitute(\
|
" private static native $type $name($args);\n").substitute(\
|
||||||
type = type_dict[fi.ctype].get("jn_type", "double[]"), \
|
type = type_dict[fi.ctype].get("jn_type", "double[]"), \
|
||||||
name = fi.jname + '_' + str(suffix_counter), \
|
name = fi.jname + '_' + str(suffix_counter), \
|
||||||
args = ", ".join(["%s %s" % (type_dict[a.ctype]["jn_type"], a.name.replace(".","_").replace("[","").replace("]","").replace("_getNativeObjAddr()","_nativeObj")) for a in jn_args])
|
args = ", ".join(["%s %s" % (type_dict[a.ctype]["jn_type"], normalize_field_name(a.name)) for a in jn_args])
|
||||||
) );
|
) );
|
||||||
|
|
||||||
# java part:
|
# java part:
|
||||||
@ -856,7 +883,7 @@ class JavaWrapperGenerator(object):
|
|||||||
if not a.out and not "jni_var" in type_dict[a.ctype]:
|
if not a.out and not "jni_var" in type_dict[a.ctype]:
|
||||||
# explicit cast to C type to avoid ambiguous call error on platforms (mingw)
|
# explicit cast to C type to avoid ambiguous call error on platforms (mingw)
|
||||||
# where jni types are different from native types (e.g. jint is not the same as int)
|
# where jni types are different from native types (e.g. jint is not the same as int)
|
||||||
jni_name = "(%s)%s" % (a.ctype, jni_name)
|
jni_name = "(%s)%s" % (cast_to(a.ctype), jni_name)
|
||||||
if not a.ctype: # hidden
|
if not a.ctype: # hidden
|
||||||
jni_name = a.defval
|
jni_name = a.defval
|
||||||
cvargs.append( type_dict[a.ctype].get("jni_name", jni_name) % {"n" : a.name})
|
cvargs.append( type_dict[a.ctype].get("jni_name", jni_name) % {"n" : a.name})
|
||||||
@ -930,11 +957,35 @@ JNIEXPORT $rtype JNICALL Java_org_opencv_${module}_${clazz}_$fname
|
|||||||
%s;\n\n""" % (",\n"+" "*12).join(["%s = %s" % (c.name, c.value) for c in ci.private_consts])
|
%s;\n\n""" % (",\n"+" "*12).join(["%s = %s" % (c.name, c.value) for c in ci.private_consts])
|
||||||
)
|
)
|
||||||
if ci.consts:
|
if ci.consts:
|
||||||
logging.info("%s", ci.consts)
|
enumTypes = set(map(lambda c: c.enumType, ci.consts))
|
||||||
ci.j_code.write("""
|
grouped_consts = {enumType: [c for c in ci.consts if c.enumType == enumType] for enumType in enumTypes}
|
||||||
|
for typeName, consts in grouped_consts.items():
|
||||||
|
logging.info("%s", consts)
|
||||||
|
if typeName:
|
||||||
|
typeName = typeName.rsplit(".", 1)[-1]
|
||||||
|
###################### Utilize Java enums ######################
|
||||||
|
# ci.j_code.write("""
|
||||||
|
# public enum {1} {{
|
||||||
|
# {0};
|
||||||
|
#
|
||||||
|
# private final int id;
|
||||||
|
# {1}(int id) {{ this.id = id; }}
|
||||||
|
# {1}({1} _this) {{ this.id = _this.id; }}
|
||||||
|
# public int getValue() {{ return id; }}
|
||||||
|
# }}\n\n""".format((",\n"+" "*8).join(["%s(%s)" % (c.name, c.value) for c in consts]), typeName)
|
||||||
|
# )
|
||||||
|
################################################################
|
||||||
|
ci.j_code.write("""
|
||||||
|
// C++: enum {1}
|
||||||
public static final int
|
public static final int
|
||||||
%s;\n\n""" % (",\n"+" "*12).join(["%s = %s" % (c.name, c.value) for c in ci.consts])
|
{0};\n\n""".format((",\n"+" "*12).join(["%s = %s" % (c.name, c.value) for c in consts]), typeName)
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
ci.j_code.write("""
|
||||||
|
// C++: enum <unnamed>
|
||||||
|
public static final int
|
||||||
|
{0};\n\n""".format((",\n"+" "*12).join(["%s = %s" % (c.name, c.value) for c in consts]))
|
||||||
|
)
|
||||||
# methods
|
# methods
|
||||||
for fi in ci.getAllMethods():
|
for fi in ci.getAllMethods():
|
||||||
self.gen_func(ci, fi)
|
self.gen_func(ci, fi)
|
||||||
|
@ -680,7 +680,7 @@ class FuncInfo(object):
|
|||||||
defval0 = "0"
|
defval0 = "0"
|
||||||
tp1 = tp.replace("*", "_ptr")
|
tp1 = tp.replace("*", "_ptr")
|
||||||
tp_candidates = [a.tp, normalize_class_name(self.namespace + "." + a.tp)]
|
tp_candidates = [a.tp, normalize_class_name(self.namespace + "." + a.tp)]
|
||||||
if any(tp in codegen.enum_types for tp in tp_candidates):
|
if any(tp in codegen.enumTypes for tp in tp_candidates):
|
||||||
defval0 = "static_cast<%s>(%d)" % (a.tp, 0)
|
defval0 = "static_cast<%s>(%d)" % (a.tp, 0)
|
||||||
|
|
||||||
amapping = simple_argtype_mapping.get(tp, (tp, "O", defval0))
|
amapping = simple_argtype_mapping.get(tp, (tp, "O", defval0))
|
||||||
@ -855,7 +855,7 @@ class PythonWrapperGenerator(object):
|
|||||||
self.classes = {}
|
self.classes = {}
|
||||||
self.namespaces = {}
|
self.namespaces = {}
|
||||||
self.consts = {}
|
self.consts = {}
|
||||||
self.enum_types = []
|
self.enumTypes = []
|
||||||
self.code_include = StringIO()
|
self.code_include = StringIO()
|
||||||
self.code_types = StringIO()
|
self.code_types = StringIO()
|
||||||
self.code_funcs = StringIO()
|
self.code_funcs = StringIO()
|
||||||
@ -914,8 +914,16 @@ class PythonWrapperGenerator(object):
|
|||||||
#print(cname + ' => ' + str(py_name) + ' (value=' + value + ')')
|
#print(cname + ' => ' + str(py_name) + ' (value=' + value + ')')
|
||||||
|
|
||||||
def add_enum(self, name, decl):
|
def add_enum(self, name, decl):
|
||||||
enumname = normalize_class_name(name)
|
enumType = normalize_class_name(name)
|
||||||
self.enum_types.append(enumname)
|
if enumType.endswith("<unnamed>"):
|
||||||
|
enumType = None
|
||||||
|
else:
|
||||||
|
self.enumTypes.append(enumType)
|
||||||
|
const_decls = decl[3]
|
||||||
|
|
||||||
|
for decl in const_decls:
|
||||||
|
name = decl[0]
|
||||||
|
self.add_const(name.replace("const ", "").strip(), decl)
|
||||||
|
|
||||||
def add_func(self, decl):
|
def add_func(self, decl):
|
||||||
namespace, classes, barename = self.split_decl_name(decl[0])
|
namespace, classes, barename = self.split_decl_name(decl[0])
|
||||||
@ -987,10 +995,10 @@ class PythonWrapperGenerator(object):
|
|||||||
|
|
||||||
self.code_ns_reg.write('static ConstDef consts_%s[] = {\n'%wname)
|
self.code_ns_reg.write('static ConstDef consts_%s[] = {\n'%wname)
|
||||||
for name, cname in sorted(ns.consts.items()):
|
for name, cname in sorted(ns.consts.items()):
|
||||||
self.code_ns_reg.write(' {"%s", %s},\n'%(name, cname))
|
self.code_ns_reg.write(' {"%s", static_cast<long>(%s)},\n'%(name, cname))
|
||||||
compat_name = re.sub(r"([a-z])([A-Z])", r"\1_\2", name).upper()
|
compat_name = re.sub(r"([a-z])([A-Z])", r"\1_\2", name).upper()
|
||||||
if name != compat_name:
|
if name != compat_name:
|
||||||
self.code_ns_reg.write(' {"%s", %s},\n'%(compat_name, cname))
|
self.code_ns_reg.write(' {"%s", static_cast<long>(%s)},\n'%(compat_name, cname))
|
||||||
self.code_ns_reg.write(' {NULL, 0}\n};\n\n')
|
self.code_ns_reg.write(' {NULL, 0}\n};\n\n')
|
||||||
|
|
||||||
def gen_namespaces_reg(self):
|
def gen_namespaces_reg(self):
|
||||||
@ -1035,7 +1043,7 @@ class PythonWrapperGenerator(object):
|
|||||||
self.add_const(name.replace("const ", "").strip(), decl)
|
self.add_const(name.replace("const ", "").strip(), decl)
|
||||||
elif name.startswith("enum"):
|
elif name.startswith("enum"):
|
||||||
# enum
|
# enum
|
||||||
self.add_enum(name.replace("enum ", "").strip(), decl)
|
self.add_enum(name.rsplit(" ", 1)[1], decl)
|
||||||
else:
|
else:
|
||||||
# function
|
# function
|
||||||
self.add_func(decl)
|
self.add_func(decl)
|
||||||
|
@ -634,8 +634,8 @@ class CppHeaderParser(object):
|
|||||||
block_type, block_name = b[self.BLOCK_TYPE], b[self.BLOCK_NAME]
|
block_type, block_name = b[self.BLOCK_TYPE], b[self.BLOCK_NAME]
|
||||||
if block_type in ["file", "enum"]:
|
if block_type in ["file", "enum"]:
|
||||||
continue
|
continue
|
||||||
if block_type not in ["struct", "class", "namespace"]:
|
if block_type not in ["struct", "class", "namespace", "enum struct", "enum class"]:
|
||||||
print("Error at %d: there are non-valid entries in the current block stack " % (self.lineno, self.block_stack))
|
print("Error at %d: there are non-valid entries in the current block stack %s" % (self.lineno, self.block_stack))
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
if block_name and (block_type == "namespace" or not qualified_name):
|
if block_name and (block_type == "namespace" or not qualified_name):
|
||||||
n += block_name + "."
|
n += block_name + "."
|
||||||
@ -712,7 +712,7 @@ class CppHeaderParser(object):
|
|||||||
return stmt_type, classname, True, decl
|
return stmt_type, classname, True, decl
|
||||||
|
|
||||||
if stmt.startswith("enum") or stmt.startswith("namespace"):
|
if stmt.startswith("enum") or stmt.startswith("namespace"):
|
||||||
stmt_list = stmt.split()
|
stmt_list = stmt.rsplit(" ", 1)
|
||||||
if len(stmt_list) < 2:
|
if len(stmt_list) < 2:
|
||||||
stmt_list.append("<unnamed>")
|
stmt_list.append("<unnamed>")
|
||||||
return stmt_list[0], stmt_list[1], True, None
|
return stmt_list[0], stmt_list[1], True, None
|
||||||
@ -720,10 +720,10 @@ class CppHeaderParser(object):
|
|||||||
if stmt.startswith("extern") and "\"C\"" in stmt:
|
if stmt.startswith("extern") and "\"C\"" in stmt:
|
||||||
return "namespace", "", True, None
|
return "namespace", "", True, None
|
||||||
|
|
||||||
if end_token == "}" and context == "enum":
|
if end_token == "}" and context.startswith("enum"):
|
||||||
decl = self.parse_enum(stmt)
|
decl = self.parse_enum(stmt)
|
||||||
name = stack_top[self.BLOCK_NAME]
|
name = stack_top[self.BLOCK_NAME]
|
||||||
return "enum", name, False, decl
|
return context, name, False, decl
|
||||||
|
|
||||||
if end_token == ";" and stmt.startswith("typedef"):
|
if end_token == ";" and stmt.startswith("typedef"):
|
||||||
# TODO: handle typedef's more intelligently
|
# TODO: handle typedef's more intelligently
|
||||||
@ -900,10 +900,8 @@ class CppHeaderParser(object):
|
|||||||
docstring = docstring.strip()
|
docstring = docstring.strip()
|
||||||
stmt_type, name, parse_flag, decl = self.parse_stmt(stmt, token, docstring=docstring)
|
stmt_type, name, parse_flag, decl = self.parse_stmt(stmt, token, docstring=docstring)
|
||||||
if decl:
|
if decl:
|
||||||
if stmt_type == "enum":
|
if stmt_type.startswith("enum"):
|
||||||
if name != "<unnamed>":
|
decls.append([stmt_type + " " + self.get_dotted_name(name), "", [], decl, None, ""])
|
||||||
decls.append(["enum " + self.get_dotted_name(name), "", [], [], None, ""])
|
|
||||||
decls.extend(decl)
|
|
||||||
else:
|
else:
|
||||||
decls.append(decl)
|
decls.append(decl)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user