diff --git a/modules/java/generator/gen_java.py b/modules/java/generator/gen_java.py index 5de9b5df13..c2f6e8514c 100755 --- a/modules/java/generator/gen_java.py +++ b/modules/java/generator/gen_java.py @@ -140,17 +140,18 @@ class GeneralInfo(): def fullName(self, isCPP=False): 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): 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): - def __init__(self, decl, addedManually=False, namespaces=[]): + def __init__(self, decl, addedManually=False, namespaces=[], enumType=None): GeneralInfo.__init__(self, "const", decl, namespaces) - self.cname = self.name.replace(".", "::") + self.cname = get_cname(self.name) self.value = decl[1] + self.enumType = enumType self.addedManually = addedManually if self.namespace in namespaces_dict: self.name = '%s_%s' % (namespaces_dict[self.namespace], self.name) @@ -166,6 +167,25 @@ class ConstInfo(GeneralInfo): return True 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(): def __init__(self, decl): # [f_ctype, f_name, '', '/RW'] self.ctype = decl[0] @@ -178,7 +198,7 @@ class ClassPropInfo(): class ClassInfo(GeneralInfo): def __init__(self, decl, namespaces=[]): # [ 'class/struct cname', ': base', [modlist] ] GeneralInfo.__init__(self, "class", decl, namespaces) - self.cname = self.name.replace(".", "::") + self.cname = get_cname(self.name) self.methods = [] self.methods_suffixes = {} self.consts = [] # using a list to save the occurrence order @@ -303,7 +323,7 @@ class ArgInfo(): class FuncInfo(GeneralInfo): def __init__(self, decl, namespaces=[]): # [ funcname, return_ctype, [modifiers], [args] ] GeneralInfo.__init__(self, "func", decl, namespaces) - self.cname = decl[0].replace(".", "::") + self.cname = get_cname(decl[0]) self.jname = self.name self.isconstructor = self.name == self.classname if "[" in self.name: @@ -341,7 +361,6 @@ class JavaWrapperGenerator(object): self.classes = { "Mat" : ClassInfo([ 'class Mat', '', [], [] ], self.namespaces) } self.module = "" self.Module = "" - self.enum_types = [] self.ported_func_list = [] self.skipped_func_list = [] 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) - def add_const(self, decl): # [ "const cname", val, [], [] ] - constinfo = ConstInfo(decl, namespaces=self.namespaces) + def add_const(self, decl, enumType=None): # [ "const cname", val, [], [] ] + constinfo = ConstInfo(decl, namespaces=self.namespaces, enumType=enumType) if constinfo.isIgnored(): logging.info('ignored: %s', constinfo) elif not self.isWrapped(constinfo.classname): @@ -423,8 +442,16 @@ class JavaWrapperGenerator(object): logging.info('ok: %s', constinfo) def add_enum(self, decl): # [ "enum cname", "", [], [] ] - enumname = decl[0].replace("enum ", "").strip() - self.enum_types.append(enumname) + enumType = decl[0].rsplit(" ", 1)[1] + if enumType.endswith(""): + 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): fi = FuncInfo(decl, namespaces=self.namespaces) @@ -526,7 +553,7 @@ class JavaWrapperGenerator(object): if self.isWrapped(t): return self.getClass(t).fullName(isCPP=True) else: - return t + return cast_from(t) def gen_func(self, ci, fi, prop_name=''): 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 self.skipped_func_list.append(c_decl + "\n" + 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 for a in fi.args: 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") self.skipped_func_list.append(c_decl + "\n" + 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 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 for f in fields: 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[] jn_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(\ type = type_dict[fi.ctype].get("jn_type", "double[]"), \ 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: @@ -856,7 +883,7 @@ class JavaWrapperGenerator(object): 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) # 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 jni_name = a.defval 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]) ) if ci.consts: - logging.info("%s", ci.consts) - ci.j_code.write(""" + enumTypes = set(map(lambda c: c.enumType, ci.consts)) + 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 - %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 + public static final int + {0};\n\n""".format((",\n"+" "*12).join(["%s = %s" % (c.name, c.value) for c in consts])) + ) # methods for fi in ci.getAllMethods(): self.gen_func(ci, fi) diff --git a/modules/python/src2/gen2.py b/modules/python/src2/gen2.py index 497fe8e11b..8dcce91ed7 100755 --- a/modules/python/src2/gen2.py +++ b/modules/python/src2/gen2.py @@ -680,7 +680,7 @@ class FuncInfo(object): defval0 = "0" tp1 = tp.replace("*", "_ptr") 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) amapping = simple_argtype_mapping.get(tp, (tp, "O", defval0)) @@ -855,7 +855,7 @@ class PythonWrapperGenerator(object): self.classes = {} self.namespaces = {} self.consts = {} - self.enum_types = [] + self.enumTypes = [] self.code_include = StringIO() self.code_types = StringIO() self.code_funcs = StringIO() @@ -914,8 +914,16 @@ class PythonWrapperGenerator(object): #print(cname + ' => ' + str(py_name) + ' (value=' + value + ')') def add_enum(self, name, decl): - enumname = normalize_class_name(name) - self.enum_types.append(enumname) + enumType = normalize_class_name(name) + if enumType.endswith(""): + 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): 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) 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(%s)},\n'%(name, cname)) compat_name = re.sub(r"([a-z])([A-Z])", r"\1_\2", name).upper() if name != compat_name: - self.code_ns_reg.write(' {"%s", %s},\n'%(compat_name, cname)) + self.code_ns_reg.write(' {"%s", static_cast(%s)},\n'%(compat_name, cname)) self.code_ns_reg.write(' {NULL, 0}\n};\n\n') def gen_namespaces_reg(self): @@ -1035,7 +1043,7 @@ class PythonWrapperGenerator(object): self.add_const(name.replace("const ", "").strip(), decl) elif name.startswith("enum"): # enum - self.add_enum(name.replace("enum ", "").strip(), decl) + self.add_enum(name.rsplit(" ", 1)[1], decl) else: # function self.add_func(decl) diff --git a/modules/python/src2/hdr_parser.py b/modules/python/src2/hdr_parser.py index 9fdde15ba1..f5364fc46a 100755 --- a/modules/python/src2/hdr_parser.py +++ b/modules/python/src2/hdr_parser.py @@ -634,8 +634,8 @@ class CppHeaderParser(object): block_type, block_name = b[self.BLOCK_TYPE], b[self.BLOCK_NAME] if block_type in ["file", "enum"]: continue - if block_type not in ["struct", "class", "namespace"]: - print("Error at %d: there are non-valid entries in the current block stack " % (self.lineno, self.block_stack)) + 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 %s" % (self.lineno, self.block_stack)) sys.exit(-1) if block_name and (block_type == "namespace" or not qualified_name): n += block_name + "." @@ -712,7 +712,7 @@ class CppHeaderParser(object): return stmt_type, classname, True, decl if stmt.startswith("enum") or stmt.startswith("namespace"): - stmt_list = stmt.split() + stmt_list = stmt.rsplit(" ", 1) if len(stmt_list) < 2: stmt_list.append("") return stmt_list[0], stmt_list[1], True, None @@ -720,10 +720,10 @@ class CppHeaderParser(object): if stmt.startswith("extern") and "\"C\"" in stmt: return "namespace", "", True, None - if end_token == "}" and context == "enum": + if end_token == "}" and context.startswith("enum"): decl = self.parse_enum(stmt) name = stack_top[self.BLOCK_NAME] - return "enum", name, False, decl + return context, name, False, decl if end_token == ";" and stmt.startswith("typedef"): # TODO: handle typedef's more intelligently @@ -900,10 +900,8 @@ class CppHeaderParser(object): docstring = docstring.strip() stmt_type, name, parse_flag, decl = self.parse_stmt(stmt, token, docstring=docstring) if decl: - if stmt_type == "enum": - if name != "": - decls.append(["enum " + self.get_dotted_name(name), "", [], [], None, ""]) - decls.extend(decl) + if stmt_type.startswith("enum"): + decls.append([stmt_type + " " + self.get_dotted_name(name), "", [], decl, None, ""]) else: decls.append(decl)