gen3_julia_cxx.py 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  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. if sys.version_info[0] >= 3:
  12. from io import StringIO
  13. else:
  14. from cStringIO import StringIO
  15. import os, shutil
  16. from parse_tree import *
  17. jl_cpp_argmap = {}
  18. jl_cpp_defmap = {}
  19. julia_types = ["Int32", "Float32", "Float64", "Bool", "String", "Array", "Any"]
  20. cv_types = ["UMat","Size" ]
  21. submodule_template = Template('')
  22. root_template = Template('')
  23. with open("binding_templates_jl/template_cv2_submodule_cxx.jl", "r") as f:
  24. submodule_template = Template(f.read())
  25. with open("binding_templates_jl/template_cv2_root.jl", "r") as f:
  26. root_template = Template(f.read())
  27. with open("typemap.txt", 'r') as f:
  28. tmp = f.readlines()
  29. for ln in tmp:
  30. ln = ln.strip('\n').split(':')
  31. jl_cpp_argmap[ln[0]] = ln[1]
  32. with open("defval.txt", 'r') as f:
  33. tmp = f.readlines()
  34. for ln in tmp:
  35. ln = ln.strip('\n').split('|')
  36. if ln[0] not in jl_cpp_defmap:
  37. jl_cpp_defmap[ln[0]] = {}
  38. jl_cpp_defmap[ln[0]][ln[1]] = ln[2]
  39. def handle_def_arg(inp, tp = '', ns=''):
  40. tp = tp.strip()
  41. inp = inp.strip()
  42. out = ''
  43. if inp in jl_cpp_defmap[tp]:
  44. out = jl_cpp_defmap[tp][inp]
  45. elif inp != '':
  46. print(inp+" not found")
  47. # print(inp, tp, out)
  48. return out
  49. def handle_jl_arg(inp):
  50. if not inp:
  51. return ''
  52. inp = inp.replace('std::', '')
  53. if inp in jl_cpp_argmap:
  54. return jl_cpp_argmap[inp]
  55. inp = inp.replace('cv::', '')
  56. return inp
  57. # return outs
  58. class ClassInfo(ClassInfo):
  59. def get_jl_code(self):
  60. if self.ismap:
  61. return ''
  62. return self.overload_get()+self.overload_set()
  63. def overload_get(self):
  64. stra = "function Base.getproperty(m::%s, s::Symbol)\n" %(self.mapped_name)
  65. if self.isalgorithm:
  66. stra = "function Base.getproperty(m::cv_Ptr{%s}, s::Symbol)\n" %(self.mapped_name)
  67. for prop in self.props:
  68. stra = stra + " if s==:" + prop.name+"\n"
  69. stra = stra + " return cpp_to_julia(%s(m))\n"%self.get_prop_func_cpp("get", prop.name)
  70. stra = stra + " end\n"
  71. stra = stra + " return Base.getfield(m, s)\nend\n"
  72. return stra
  73. def overload_set(self):
  74. stra = "function Base.setproperty!(m::%s, s::Symbol, v)\n" %(self.mapped_name)
  75. if self.isalgorithm:
  76. stra = "function Base.setproperty!(m::cv_Ptr{%s}, s::Symbol, v)\n" %(self.mapped_name)
  77. for prop in self.props:
  78. if not prop.readonly:
  79. continue
  80. stra = stra + " if s==:" + prop.name+"\n"
  81. stra = stra + " %s(m, julia_to_cpp(v))\n"%(self.get_prop_func_cpp("set", prop.name))
  82. stra = stra + " end\n"
  83. stra = stra + " return Base.setfield!(m, s, v)\nend\n"
  84. return stra
  85. class FuncVariant(FuncVariant):
  86. def promote_type(self, tp):
  87. if tp=='int':
  88. return 'long long'
  89. elif tp =='float':
  90. return 'double'
  91. return tp
  92. def get_argument_full(self, classname='', isalgo = False):
  93. arglist = self.inlist + self.optlist
  94. argnamelist = [arg.name+"::"+(handle_jl_arg(self.promote_type(arg.tp)) if handle_jl_arg(arg.tp) not in pass_by_val_types else handle_jl_arg(self.promote_type(arg.tp[:-1]))) for arg in arglist]
  95. argstr = ", ".join(argnamelist)
  96. return argstr
  97. def get_argument_opt(self, ns=''):
  98. # [print(arg.default_value,":",handle_def_arg(arg.default_value, handle_jl_arg(arg.tp))) for arg in self.optlist]
  99. try:
  100. str2 = ", ".join(["%s::%s = %s(%s)" % (arg.name, handle_jl_arg(self.promote_type(arg.tp)), handle_jl_arg(self.promote_type(arg.tp)) if (arg.tp == 'int' or arg.tp=='float' or arg.tp=='double') else '', handle_def_arg(arg.default_value, handle_jl_arg(self.promote_type(arg.tp)), ns)) for arg in self.optlist])
  101. return str2
  102. except KeyError:
  103. return ''
  104. def get_argument_def(self, classname, isalgo):
  105. arglist = self.inlist
  106. argnamelist = [arg.name+"::"+(handle_jl_arg(self.promote_type(arg.tp)) if handle_jl_arg(self.promote_type(arg.tp)) not in pass_by_val_types else handle_jl_arg(self.promote_type(arg.tp[:-1]))) for arg in arglist]
  107. argstr = ", ".join(argnamelist)
  108. return argstr
  109. def get_return(self, classname=''):
  110. argstr = ''
  111. arglist = self.inlist + self.optlist
  112. return "return cpp_to_julia(%s(%s))" %(self.get_wrapper_name(), ",".join(["julia_to_cpp(%s)" % (x.name) for x in arglist]))
  113. def get_algo_tp(self, classname, isalgo):
  114. if not isalgo or not classname:
  115. return ''
  116. return ' where {T <: %s}' % classname
  117. def get_complete_code(self, classname='', isalgo = False, iscons = False, gen_default = True, ns = ''):
  118. if classname and not iscons:
  119. if isalgo:
  120. self.inlist = [ArgInfo("cobj", "cv_Ptr{T}")] + self.inlist
  121. else:
  122. self.inlist = [ArgInfo("cobj", classname)] + self.inlist
  123. map_name = self.mapped_name
  124. if ns!='cv':
  125. map_name = '%s_%s' %(ns.split('::')[-1], map_name)
  126. outstr = 'function %s(%s)%s\n\t%s\nend\n' % (map_name, self.get_argument_full(classname, isalgo), self.get_algo_tp(classname, isalgo),self.get_return())
  127. str2 = ", ".join([x.name for x in self.inlist + self.optlist])
  128. # outstr = outstr +
  129. if self.get_argument_opt() != '' and gen_default:
  130. outstr = outstr + ('%s(%s; %s)%s = %s(%s)\n' % (map_name, self.get_argument_def(classname, isalgo), self.get_argument_opt(ns), self.get_algo_tp(classname, isalgo), map_name, str2))
  131. if iscons and len(self.inlist+self.optlist)==0 and ns=='cv':
  132. return ''
  133. return outstr
  134. def gen(srcfiles):
  135. namespaces, _ = gen_tree(srcfiles)
  136. jl_code = StringIO()
  137. for name, ns in namespaces.items():
  138. cv_types.extend(ns.registered)
  139. jl_code = StringIO()
  140. nsname = name
  141. for e1,e2 in ns.enums.items():
  142. # jl_code.write('\n const {0} = Int32'.format(e2[0]))
  143. jl_code.write('\n const {0} = Int64 \n'.format(e2[0].replace("cv::", "").replace("::", "_")))
  144. # Do not duplicate functions. This should prevent overwriting of Mat function by UMat functions
  145. function_signatures = []
  146. for cname, cl in ns.classes.items():
  147. cl.__class__ = ClassInfo
  148. jl_code.write(cl.get_jl_code())
  149. for mname, fs in cl.methods.items():
  150. for f in fs:
  151. f.__class__ = FuncVariant
  152. sign = (f.name, f.mapped_name, f.classname, [x.tp for x in f.inlist+f.optlist])
  153. if sign in function_signatures:
  154. print("Skipping entirely: ", f.name)
  155. continue
  156. sign2 = (f.name, f.mapped_name, f.classname, [x.tp for x in f.inlist])
  157. gend = True
  158. if sign2 in function_signatures:
  159. print("Skipping default declaration: ", f.name)
  160. gend = False
  161. jl_code.write('\n%s' % f.get_complete_code(classname = cl.mapped_name, isalgo = cl.isalgorithm, gen_default = gend, ns=nsname))
  162. function_signatures.append(sign)
  163. function_signatures.append(sign2)
  164. for f in cl.constructors:
  165. f.__class__ = FuncVariant
  166. jl_code.write('\n%s' % f.get_complete_code(classname = cl.mapped_name, isalgo = cl.isalgorithm, iscons = True, ns=nsname))
  167. for mname, fs in ns.funcs.items():
  168. for f in fs:
  169. f.__class__ = FuncVariant
  170. sign = (f.name, f.mapped_name, f.classname, [x.tp for x in f.inlist+f.optlist])
  171. if sign in function_signatures:
  172. print("Skipping entirely: ", f.name)
  173. continue
  174. gend = True
  175. sign2 = (f.name, f.mapped_name, f.classname, [x.tp for x in f.inlist])
  176. if sign2 in function_signatures:
  177. print("Skipping default declaration: ", f.name)
  178. gend = False
  179. jl_code.write('\n%s' % f.get_complete_code(gen_default = gend, ns=nsname))
  180. function_signatures.append(sign)
  181. function_signatures.append(sign2)
  182. imports = ''
  183. for namex in namespaces:
  184. if namex.startswith(name) and len(namex.split('::')) == 1 + len(name.split('::')):
  185. imports = imports + '\ninclude("%s_cxx_wrap.jl")'%namex.replace('::', '_')
  186. code = ''
  187. if name == 'cv':
  188. code = root_template.substitute(modname = name, code = jl_code.getvalue(), submodule_imports = imports)
  189. else:
  190. code = submodule_template.substitute(code = jl_code.getvalue(), submodule_imports = imports)
  191. with open ('autogen_jl/%s_cxx_wrap.jl' % ns.name.replace('::', '_'), 'w') as fd:
  192. fd.write(code)
  193. srcfiles = hdr_parser.opencv_hdr_list
  194. if len(sys.argv) > 1:
  195. srcfiles = [l.strip() for l in sys.argv[1].split(';')]
  196. gen(srcfiles)