gen3_cpp.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. #!/usr/bin/env python
  2. # This file is part of OpenCV project.
  3. # It is subject to the license terms in the LICENSE file found in the top-level directory
  4. # of this distribution and at http://opencv.org/license.html
  5. # Copyright (C) 2020 by Archit Rungta
  6. from __future__ import unicode_literals # Needed for python2
  7. import hdr_parser, sys, re, os
  8. from string import Template
  9. from pprint import pprint
  10. from collections import namedtuple
  11. import os, shutil
  12. if sys.version_info[0] >= 3:
  13. from io import StringIO
  14. else:
  15. from cStringIO import StringIO
  16. from parse_tree import *
  17. mod_template = ""
  18. with open("binding_templates_cpp/cv_core.cpp", "r") as f:
  19. mod_template = Template(f.read())
  20. def normalize_name(name):
  21. return name.replace('.', '::')
  22. def normalize_class_name(name):
  23. _, classes, name = split_decl_name(normalize_name(name))
  24. return "_".join(classes+[name])
  25. def normalize_full_name(name):
  26. ns, classes, name = split_decl_name(normalize_name(name))
  27. return "::".join(ns)+'::'+'_'.join(classes+[name])
  28. def split_decl_name(name):
  29. chunks = name.split('::')
  30. namespace = chunks[:-1]
  31. classes = []
  32. while namespace and '::'.join(namespace) not in namespaces:
  33. classes.insert(0, namespace.pop())
  34. ns = '::'.join(namespace)
  35. if ns not in namespaces and ns:
  36. assert(0)
  37. return namespace, classes, chunks[-1]
  38. def registered_tp_search(tp):
  39. found = False
  40. if not tp:
  41. return True
  42. for tpx in registered_types:
  43. if re.findall(tpx, tp):
  44. found = True
  45. break
  46. return found
  47. namespaces = {}
  48. enums = []
  49. classes = {}
  50. functions = {}
  51. registered_types = ["int", "Size.*", "Rect.*", "Scalar", "RotatedRect", "Point.*", "explicit", "string", "bool", "uchar",
  52. "Vec.*", "float", "double", "char", "Mat", "size_t", "RNG", "TermCriteria"]
  53. class ClassInfo(ClassInfo):
  54. def get_cpp_code_header(self):
  55. if self.ismap:
  56. return 'mod.map_type<%s>("%s");\n'%(self.name, self.mapped_name)
  57. if not self.base:
  58. return 'mod.add_type<%s>("%s");\n' % (self.name, self.mapped_name)
  59. else:
  60. return 'mod.add_type<%s>("%s", jlcxx::julia_base_type<%s>());\n' % (self.name, self.mapped_name, self.base)
  61. def get_cpp_code_body(self):
  62. if self.ismap:
  63. return ''
  64. cpp_code = StringIO()
  65. for cons in self.constructors:
  66. cons.__class__ = FuncVariant
  67. cpp_code.write(cons.get_cons_code(self.name, self.mapped_name))
  68. #add get/set
  69. cpp_code.write('\n')
  70. cpp_code.write(self.get_setters())
  71. cpp_code.write('\n')
  72. cpp_code.write(self.get_getters())
  73. cpp_code.write(';')
  74. return cpp_code.getvalue()
  75. # return code for functions and setters and getters if simple class or functions and map type
  76. def get_prop_func_cpp(self, mode, propname):
  77. return "jlopencv_" + self.mapped_name + "_"+mode+"_"+propname
  78. def get_getters(self):
  79. stra = ""
  80. for prop in self.props:
  81. if not self.isalgorithm:
  82. stra = stra + '\nmod.method("%s", [](const %s &cobj) {return %scobj.%s;});' % (self.get_prop_func_cpp("get", prop.name), self.name, '(int)' if prop.tp in enums else '', prop.name)
  83. else:
  84. stra = stra + '\nmod.method("%s", [](const cv::Ptr<%s> &cobj) {return %scobj->%s;});' % (self.get_prop_func_cpp("get", prop.name), self.name,'(int)' if prop.tp in enums else '', prop.name)
  85. return stra
  86. def get_setters(self):
  87. stra = ""
  88. for prop in self.props:
  89. if prop.readonly:
  90. continue
  91. if not self.isalgorithm:
  92. stra = stra + '\nmod.method("%s", [](%s &cobj,const force_enum_int<%s>::Type &v) {cobj.%s=(%s)v;});' % (self.get_prop_func_cpp("set", prop.name), self.name, prop.tp, prop.name, prop.tp)
  93. else:
  94. stra = stra + '\nmod.method("%s", [](cv::Ptr<%s> cobj, const force_enum_int<%s>::Type &v) {cobj->%s=(%s)v;});' % (self.get_prop_func_cpp("set", prop.name), self.name, prop.tp, prop.name, prop.tp)
  95. return stra
  96. class FuncVariant(FuncVariant):
  97. def get_return(self):
  98. outstr = ""
  99. for arg in self.inlist+self.optlist:
  100. if arg.tp not in pass_by_val_types and arg.tp not in enums and self.promote_type(arg.tp)!=arg.tp:
  101. outstr = outstr + "%s=%s_down;\n"%(arg.name, arg.name)
  102. if len(self.outlist)==0:
  103. return outstr+";"
  104. elif len(self.outlist)==1:
  105. return outstr+"return %s;" % ( ('(int64_t)' if self.outlist[0].tp in enums else ('' if self.promote_type(self.outlist[0].tp)==self.outlist[0].tp else '(%s)'%self.promote_type(self.outlist[0].tp))) + self.outlist[0].name)
  106. return outstr+"return make_tuple(%s);" % ",".join(["move(%s)" % (('(int64_t)' if x.tp in enums else ('' if self.promote_type(x.tp)==x.tp else '(%s)'%self.promote_type(x.tp))) +x.name) for x in self.outlist])
  107. def promote_type(self, tp):
  108. if tp=='int':
  109. return 'long long'
  110. elif tp =='float':
  111. return 'double'
  112. return tp
  113. def get_argument(self, isalgo):
  114. args = self.inlist + self.optlist
  115. if self.classname!="" and not self.isconstructor and not self.isstatic:
  116. if isalgo:
  117. args = [ArgInfo("cobj", ("cv::Ptr<%s>" % self.classname))] + args
  118. else:
  119. args = [ArgInfo("cobj", self.classname)] + args
  120. argnamelist = []
  121. for arg in args:
  122. if arg.tp in pass_by_val_types:
  123. print("PATHWAY NOT TESTED")
  124. argnamelist.append(arg.tp[:-1] +"& "+arg.name)
  125. elif arg.tp in enums:
  126. argnamelist.append("int64_t& " + arg.name)
  127. else:
  128. if arg.tp=='bool':
  129. # Bool pass-by-reference is broken
  130. argnamelist.append(arg.tp+" " +arg.name)
  131. else:
  132. argnamelist.append(self.promote_type(arg.tp) + "& "+arg.name)
  133. # argnamelist = [(arg.tp if arg.tp not in pass_by_val_types else arg.tp[:-1]) +"& "+arg.name for arg in args]
  134. argstr = ", ".join(argnamelist)
  135. return argstr
  136. def get_def_outtypes(self):
  137. outstr = ""
  138. for arg in self.deflist:
  139. outstr = outstr + "%s %s;"%(arg.tp if arg.tp not in pass_by_val_types else arg.tp[:-1], arg.name)
  140. for arg in self.inlist+self.optlist:
  141. if arg.tp not in pass_by_val_types and arg.tp not in enums and self.promote_type(arg.tp)!=arg.tp:
  142. outstr = outstr + "%s %s_down=(%s)%s;"%(arg.tp if arg.tp not in pass_by_val_types else arg.tp[:-1], arg.name, arg.tp, arg.name)
  143. return outstr
  144. def get_retval(self, isalgo):
  145. if self.rettype:
  146. stra = "auto retval = "
  147. else:
  148. stra = ""
  149. arlist = []
  150. for x in self.args:
  151. if x.tp in pass_by_val_types:
  152. arlist.append("&"+x.name)
  153. elif x.tp in enums:
  154. arlist.append("(%s)%s" %(x.tp, x.name))
  155. else:
  156. if self.promote_type(x.tp) == x.tp:
  157. arlist.append(x.name)
  158. else:
  159. if len([y for y in self.inlist+self.optlist if y.name==x.name])>0:
  160. # print("ss")
  161. arlist.append("%s_down" %(x.name))
  162. else:
  163. arlist.append(x.name)
  164. argstr = ", ".join(arlist)
  165. if self.classname and not self.isstatic:
  166. stra = stra + "cobj%s%s(%s); " %("->" if isalgo else ".",self.name.split('::')[-1], argstr)
  167. else:
  168. stra = stra + "%s(%s);" % (self.name, argstr)
  169. return stra
  170. def get_cons_code(self, name, mapped_name):
  171. # if self.get_argument(False) == '':
  172. # return ''
  173. arglist = []
  174. for x in self.args:
  175. if x.tp in pass_by_val_types:
  176. arglist.append("&"+x.name)
  177. elif x.tp in enums:
  178. arglist.append("(%s)%s" %(x.tp, x.name))
  179. else:
  180. if self.promote_type(x.tp) == x.tp:
  181. arglist.append(x.name)
  182. else:
  183. # print("ss")
  184. arglist.append("%s_down" %(x.name))
  185. return 'mod.method("%s", [](%s) { %s return jlcxx::create<%s>(%s);});' % (self.get_wrapper_name(), self.get_argument(False), self.get_def_outtypes(), name, " ,".join(arglist))
  186. def get_complete_code(self, classname, isalgo=False):
  187. outstr = '.method("%s", [](%s) {%s %s %s})' % (self.get_wrapper_name(), self.get_argument(isalgo),self.get_def_outtypes(), self.get_retval(isalgo), self.get_return())
  188. return outstr
  189. def gen(srcfiles):
  190. namespaces, default_values = gen_tree(srcfiles)
  191. cpp_code = StringIO()
  192. include_code = StringIO()
  193. nsi = sorted(namespaces.items(), key =lambda x: x[0])
  194. for name, ns in nsi:
  195. cpp_code.write("using namespace %s;\n" % name.replace(".", "::"))
  196. if name.split('.')[-1] == '':
  197. continue
  198. nsname = name
  199. nsprefix = '_'.join(nsname.split('::')[1:])
  200. def sort_classes(classes):
  201. class_inherits = []
  202. class_inherits_names = set()
  203. class_noinherits = []
  204. parent = {}
  205. for name, cl in classes:
  206. if cl.base:
  207. class_inherits.append((name, cl))
  208. parent[name] = cl.base
  209. class_inherits_names.add(name)
  210. else:
  211. class_noinherits.append((name,cl))
  212. final_order = class_noinherits
  213. while len(class_inherits)>0:
  214. for cli in class_inherits:
  215. if parent[cli[0]] not in class_inherits_names:
  216. final_order.append(cli)
  217. class_inherits.remove(cli)
  218. class_inherits_names.remove(cli[0])
  219. return final_order
  220. sorted_cls = sort_classes(ns.classes.items())
  221. for name, cl in sorted_cls:
  222. cl.__class__ = ClassInfo
  223. cpp_code.write(cl.get_cpp_code_header())
  224. if cl.base:
  225. include_code.write("""
  226. template <>
  227. struct SuperType<%s>
  228. {
  229. typedef %s type;
  230. };
  231. """ % (cl.name.replace('.', '::'), cl.base.replace('.', '::')))
  232. for e1,e2 in ns.enums.items():
  233. # cpp_code.write('\n mod.add_bits<{0}>("{1}", jlcxx::julia_type("CppEnum"));'.format(e2[0], e2[1]))
  234. enums.append(e2[0])
  235. enums.append(e2[1])
  236. enums.append(e2[0].replace("cv::", "").replace("::", '_'))
  237. for tp in ns.register_types:
  238. cpp_code.write(' mod.add_type<%s>("%s");\n' %(tp, normalize_class_name(tp)))
  239. # print(enums)
  240. for name, ns in namespaces.items():
  241. nsname = name.replace("::", "_")
  242. for name, cl in ns.classes.items():
  243. cl.__class__ = ClassInfo
  244. cpp_code.write(cl.get_cpp_code_body())
  245. for mname, fs in cl.methods.items():
  246. for f in fs:
  247. f.__class__ = FuncVariant
  248. cpp_code.write('\n mod%s;' % f.get_complete_code(cl.name, cl.isalgorithm))
  249. # for f in cl.constructors:
  250. # cpp_code.write('\n %s; \n' % f.get_cons_code(cl.name, cl.mapped_name))
  251. for mname, fs in ns.funcs.items():
  252. for f in fs:
  253. f.__class__ = FuncVariant
  254. cpp_code.write('\n mod%s;' % f.get_complete_code("", False))
  255. for mapname, name in sorted(ns.consts.items()):
  256. cpp_code.write(' mod.set_const("%s_%s", (force_enum_int<decltype(%s)>::Type)%s);\n'%(nsname, name, mapname, mapname))
  257. compat_name = re.sub(r"([a-z])([A-Z])", r"\1_\2", name).upper()
  258. if name != compat_name:
  259. cpp_code.write(' mod.set_const("%s_%s", (force_enum_int<decltype(%s)>::Type)%s);\n'%(nsname, compat_name, mapname, mapname))
  260. default_values = list(set(default_values))
  261. for val in default_values:
  262. # val = handle_cpp_arg(val)
  263. cpp_code.write(' mod.method("%s", [](){return (force_enum_int<decltype(%s)>::Type)%s;});\n'%(get_var(val), val, val))
  264. with open ('autogen_cpp/cv_core.cpp', 'w') as fd:
  265. fd.write(mod_template.substitute(include_code = include_code.getvalue(), cpp_code=cpp_code.getvalue()))
  266. srcfiles = hdr_parser.opencv_hdr_list
  267. if len(sys.argv) > 1:
  268. srcfiles = [l.strip() for l in sys.argv[1].split(';')]
  269. gen(srcfiles)