2 Code to use the parsed results and convert it to a format 3 that Matlab's MEX compiler can use. 12 from functools
import partial, reduce
13 from typing
import Dict, Iterable, List, Union
24 """ Wrap the given C++ code into Matlab. 27 module: the C++ module being wrapped 28 module_name: name of the C++ module being wrapped 29 top_module_namespace: C++ namespace for the top module (default '') 30 ignore_classes: A list of classes to ignore (default []) 35 top_module_namespace='',
37 use_boost_serialization=
False):
51 'unsigned char':
'unsigned char',
63 'unsigned char':
'unsigned char',
76 self.wrapper_map: Dict = {}
78 self.includes: List[parser.Include] = []
80 self.classes: List[Union[parser.Class,
81 instantiator.InstantiatedClass]] = []
82 self.classes_elems: Dict[Union[parser.Class,
83 instantiator.InstantiatedClass],
88 self.content: List[str] = []
91 dir_path = osp.dirname(osp.realpath(__file__))
92 with open(osp.join(dir_path,
"matlab_wrapper.tpl"))
as f:
96 """Add `instantiated_class` to the list of classes.""" 97 if self.classes_elems.
get(instantiated_class)
is None:
98 self.classes_elems[instantiated_class] = 0
99 self.classes.append(instantiated_class)
102 collector_function=None,
104 function_name: str =
None):
106 Get and define wrapper ids. 107 Generates the map of id -> collector function. 110 collector_function: tuple storing info about the wrapper function 111 (namespace, class instance, function name, function object) 112 id_diff: constant to add to the id in the map 113 function_name: Optional custom function_name. 116 the current wrapper id 118 if collector_function
is not None:
119 is_instantiated_class =
isinstance(collector_function[1],
120 instantiator.InstantiatedClass)
122 if function_name
is None:
123 if is_instantiated_class:
124 function_name = collector_function[0] + \
125 collector_function[1].name +
'_' + collector_function[2]
127 function_name = collector_function[1].name
130 collector_function[0], collector_function[1],
131 collector_function[2], function_name +
'_' +
139 return 'handle' if names ==
'' else names
142 """Insert spaces at the beginning of each line 145 x: the statement currently generated 146 y: the addition to add to the statement 148 return x +
'\n' + (
'' if y ==
'' else ' ') + y
152 """Recursively expand all possibilities for optional default arguments. 153 We create "overload" functions with fewer arguments, but since we have to "remember" what 154 the default arguments are for later, we make a backup. 158 return ArgumentList([copy.copy(arg)
for arg
in args.list()])
160 def method_copy(method):
161 method2 = copy.copy(method)
162 method2.args = args_copy(method.args)
163 method2.args.backup = method.args.backup
167 method.args.backup = args_copy(method.args)
168 method = method_copy(method)
169 for arg
in reversed(method.args.list()):
170 if arg.default
is not None:
172 methodWithArg = method_copy(method)
173 method.args.list().remove(arg)
176 *MatlabWrapper._expand_default_arguments(method,
180 assert all(arg.default
is None for arg
in method.args.list()), \
181 'In parsing method {:}: Arguments with default values cannot appear before ones ' \
182 'without default values.'.
format(method.name)
186 """Group overloaded methods together""" 190 for method
in methods:
191 method_index = method_map.get(method.name)
193 if method_index
is None:
194 method_map[method.name] =
len(method_out)
196 MatlabWrapper._expand_default_arguments(method))
199 method_index] += MatlabWrapper._expand_default_arguments(
205 """Wrap an interface_parser.ArgumentList into a list of arguments. 208 A string representation of the arguments. For example: 213 for i, arg
in enumerate(args.list(), 1):
215 include_namespace=
False)
217 arg_wrap +=
'{c_type} {arg_name}{comma}'.
format(
220 comma=
'' if i ==
len(args.list())
else ', ')
225 """ Wrap an interface_parser.ArgumentList into a statement of argument 229 A string representation of a variable arguments for an if 230 statement. For example: 231 ' && isa(varargin{1},'double') && isa(varargin{2},'numeric')' 235 for i, arg
in enumerate(args.list(), 1):
236 name = arg.ctype.typename.name
237 if name
in self.not_check_type:
245 if check_type
is None:
249 is_constructor=
not wrap_datatypes)
251 var_arg_wrap +=
" && isa(varargin{{{num}}},'{data_type}')".
format(
252 num=i, data_type=check_type)
254 var_arg_wrap +=
' && size(varargin{{{num}}},2)==1'.
format(
257 var_arg_wrap +=
' && size(varargin{{{num}}},1)==2'.
format(
259 var_arg_wrap +=
' && size(varargin{{{num}}},2)==1'.
format(
262 var_arg_wrap +=
' && size(varargin{{{num}}},1)==3'.
format(
264 var_arg_wrap +=
' && size(varargin{{{num}}},2)==1'.
format(
270 """ Wrap an interface_parser.ArgumentList into a list of argument 274 A string representation of a list of variable arguments. 276 'varargin{1}, varargin{2}, varargin{3}' 281 for i
in range(1,
len(args.list()) + 1):
283 var_list_wrap +=
'varargin{{{}}}'.
format(i)
286 var_list_wrap +=
', varargin{{{}}}'.
format(i)
292 Wrap the given arguments into either just a varargout call or a 293 call in an if statement that checks if the parameters are accurate. 295 TODO Update this method so that default arguments are supported. 299 param_count =
len(args)
300 check_statement =
'if length(varargin) == {param_count}'.
format(
301 param_count=param_count)
303 for _, arg
in enumerate(args.list()):
304 name = arg.ctype.typename.name
306 if name
in self.not_check_type:
315 if check_type
is None:
319 check_statement +=
" && isa(varargin{{{id}}},'{ctype}')".
format(
320 id=arg_id, ctype=check_type)
323 check_statement +=
' && size(varargin{{{num}}},2)==1'.
format(
326 check_statement +=
' && size(varargin{{{num}}},1)==2'.
format(
328 check_statement +=
' && size(varargin{{{num}}},2)==1'.
format(
331 check_statement +=
' && size(varargin{{{num}}},1)==3'.
format(
333 check_statement +=
' && size(varargin{{{num}}},2)==1'.
format(
338 check_statement = check_statement \
339 if check_statement ==
'' \
340 else check_statement +
'\n' 342 return check_statement
348 if instantiated_class
and \
349 self.
is_enum(arg.ctype, instantiated_class):
350 enum_type = f
"{arg.ctype.typename}" 351 arg_type = f
"{enum_type}" 352 unwrap = f
'unwrap_enum<{enum_type}>(in[{arg_id}]);' 354 elif self.
is_ref(arg.ctype):
355 arg_type =
"{ctype}&".
format(ctype=ctype_sep)
356 unwrap =
'*unwrap_shared_ptr< {ctype} >(in[{id}], "ptr_{ctype_camel}");'.
format(
357 ctype=ctype_sep, ctype_camel=ctype_camel, id=arg_id)
359 elif self.
is_ptr(arg.ctype)
and \
360 arg.ctype.typename.name
not in self.ignore_namespace:
362 arg_type =
"{ctype_sep}*".
format(ctype_sep=ctype_sep)
363 unwrap =
'unwrap_ptr< {ctype_sep} >(in[{id}], "ptr_{ctype}");'.
format(
364 ctype_sep=ctype_sep, ctype=ctype_camel, id=arg_id)
367 arg.ctype.typename.name
not in self.ignore_namespace:
369 arg_type =
"std::shared_ptr<{ctype_sep}>".
format(
371 unwrap =
'unwrap_shared_ptr< {ctype_sep} >(in[{id}], "ptr_{ctype}");'.
format(
372 ctype_sep=ctype_sep, ctype=ctype_camel, id=arg_id)
375 arg_type =
"{ctype}".
format(ctype=arg.ctype.typename.name)
376 unwrap =
'unwrap< {ctype} >(in[{id}]);'.
format(
377 ctype=arg.ctype.typename.name, id=arg_id)
379 return arg_type, unwrap
384 instantiated_class=None):
385 """Format the interface_parser.Arguments. 388 ((a), unsigned char a = unwrap< unsigned char >(in[1]);), 389 ((a), Test& t = *unwrap_shared_ptr< Test >(in[1], "ptr_Test");), 390 ((a), std::shared_ptr<Test> p1 = unwrap_shared_ptr< Test >(in[1], "ptr_Test");) 394 for arg
in args.list():
396 arg, arg_id, instantiated_class=instantiated_class)
398 body_args += textwrap.indent(textwrap.dedent(
'''\ 399 {arg_type} {name} = {unwrap} 400 '''.
format(arg_type=arg_type, name=arg.name,
406 explicit_arg_names = [arg.name
for arg
in args.list()]
408 for arg
in args.backup.list():
412 if (arg.default
is not None)
and (arg.name
413 not in explicit_arg_names):
414 params += arg.default
419 not self.
is_enum(arg.ctype, instantiated_class)
and \
420 arg.ctype.typename.name
not in self.ignore_namespace:
421 if arg.ctype.is_shared_ptr:
422 call_type = arg.ctype.is_shared_ptr
424 call_type = arg.ctype.is_ptr
429 return params, body_args
433 """The amount of objects returned by the given 434 interface_parser.ReturnType. 436 return 1
if return_type.type2 ==
'' else 2
439 """Determine the name of wrapper function.""" 443 """Generate comments for serialize methods.""" 445 static_methods = sorted(static_methods, key=
lambda name: name.name)
447 for static_method
in static_methods:
448 if comment_wrap ==
'':
449 comment_wrap =
'%-------Static Methods-------\n' 451 comment_wrap +=
'%{name}({args}) : returns {return_type}\n'.
format(
452 name=static_method.name,
455 include_namespace=
True))
457 comment_wrap += textwrap.dedent(
'''\ 459 %-------Serialization Interface------- 460 %string_serialize() : returns string 461 %string_deserialize(string serialized) : returns {class_name} 463 ''').
format(class_name=class_name)
468 """Generate comments for the given class in Matlab. 471 instantiated_class: the class being wrapped 472 ctors: a list of the constructors in the class 473 methods: a list of the methods in the class 475 class_name = instantiated_class.name
476 ctors = instantiated_class.ctors
477 properties = instantiated_class.properties
478 methods = instantiated_class.methods
479 static_methods = instantiated_class.static_methods
481 comment = textwrap.dedent(
'''\ 482 %class {class_name}, see Doxygen page for details 483 %at https://gtsam.org/doxygen/ 484 ''').
format(class_name=class_name)
487 comment +=
'%\n%-------Constructors-------\n' 491 comment +=
'%{ctor_name}({args})\n'.
format(ctor_name=ctor.name,
495 if len(properties) != 0:
497 '%-------Properties-------\n' 498 for propty
in properties:
499 comment +=
'%{}\n'.
format(propty.name)
501 if len(methods) != 0:
503 '%-------Methods-------\n' 505 methods = sorted(methods, key=
lambda name: name.name)
508 for method
in methods:
509 if method.name
in self.whitelist:
511 if method.name
in self.ignore_methods:
514 comment +=
'%{name}({args})'.
format(name=method.name,
518 if method.return_type.type2 ==
'':
520 method.return_type.type1.typename)
522 return_type =
'pair< {type1}, {type2} >'.
format(
524 method.return_type.type1.typename),
526 method.return_type.type2.typename))
528 comment +=
' : returns {return_type}\n'.
format(
529 return_type=return_type)
533 if len(static_methods) != 0:
540 Wrap methods in the body of a class. 549 Wrap a sequence of methods/functions. Groups methods with the same names 551 If global_funcs is True then output every method into its own file. 556 for method
in methods:
557 if method
in self.ignore_methods:
562 self.content.append((
"".join([
563 '+' + x +
'/' for x
in global_ns.full_namespaces()[1:]
564 ])[:-1], [(method[0].name +
'.m', method_text)]))
572 """Wrap the given global function.""" 574 function = [function]
576 function_name = function[0].name
581 for i, overload
in enumerate(function):
582 param_wrap +=
' if' if i == 0
else ' elseif' 583 param_wrap +=
' length(varargin) == ' 585 if len(overload.args.list()) == 0:
588 param_wrap +=
str(
len(overload.args.list())) \
593 overload.return_type, include_namespace=
True, separator=
".")
595 return_type_formatted)
597 param_wrap += textwrap.indent(textwrap.dedent(
'''\ 598 {varargout}{module_name}_wrapper({num}, varargin{{:}}); 599 ''').
format(varargout=varargout,
602 collector_function=(function[0].parent.name,
603 function[i],
'global_function',
607 param_wrap += textwrap.indent(textwrap.dedent(
'''\ 609 error('Arguments do not match any overload of function {func_name}'); 610 end''').
format(func_name=function_name),
613 global_function = textwrap.indent(textwrap.dedent(
'''\ 614 function varargout = {m_method}(varargin) 617 ''').
format(m_method=function_name, statements=param_wrap),
620 return global_function
624 """Wrap class constructor. 627 namespace_name: the name of the namespace ('' if it does not exist) 628 inst_class: instance of the class 629 parent_name: the name of the parent class if it exists 630 ctors: the interface_parser.Constructor in the class 631 is_virtual: whether the class is part of a virtual inheritance 634 has_parent = parent_name !=
'' 635 class_name = inst_class.name
641 ctors = sum((MatlabWrapper._expand_default_arguments(ctor)
642 for ctor
in ctors), [])
644 methods_wrap = textwrap.indent(textwrap.dedent(
"""\ 646 function obj = {class_name}(varargin) 647 """).
format(class_name=class_name),
651 methods_wrap +=
" if (nargin == 2 || (nargin == 3 && strcmp(varargin{3}, 'void')))" 653 methods_wrap +=
' if nargin == 2' 655 methods_wrap +=
" && isa(varargin{1}, 'uint64')" 656 methods_wrap +=
" && varargin{1} == uint64(5139824614673773682)\n" 659 methods_wrap += textwrap.indent(textwrap.dedent(
'''\ 661 my_ptr = varargin{{2}}; 663 my_ptr = {wrapper_name}({id}, varargin{{2}}); 669 methods_wrap +=
' my_ptr = varargin{2};\n' 672 (namespace_name, inst_class,
'collectorInsertAndMakeBase',
None),
673 id_diff=-1
if is_virtual
else 0)
675 methods_wrap +=
' {ptr}{wrapper_name}({id}, my_ptr);\n' \
677 ptr=
'base_ptr = ' if has_parent
else '',
679 id=collector_base_id - (1
if is_virtual
else 0))
682 wrapper_return =
'[ my_ptr, base_ptr ] = ' \
686 methods_wrap += textwrap.indent(textwrap.dedent(
'''\ 687 elseif nargin == {len}{varargin} 688 {ptr}{wrapper}({num}{comma}{var_arg}); 695 (namespace_name, inst_class,
'constructor', ctor)),
696 comma=
'' if len(ctor.args.list()) == 0
else ', ',
703 base_obj =
' obj = obj@{parent_name}(uint64(5139824614673773682), base_ptr);'.
format(
704 parent_name=parent_name)
707 base_obj =
'\n' + base_obj
709 methods_wrap += textwrap.indent(textwrap.dedent(
'''\ 711 error('Arguments do not match any overload of {class_name_doc} constructor'); 713 obj.ptr_{class_name} = my_ptr; 715 ''').
format(namespace=namespace_name,
716 d=
'' if namespace_name ==
'' else '.',
727 """Generate Matlab properties block of the class. 732 ptr_gtsamISAM2Params = 0 738 class_name: Class name with namespace to assign unique pointer. 739 inst_class: The instantiated class whose properties we want to wrap. 742 str: The `properties` block in a Matlab `classdef`. 745 class_pointer =
" ptr_{class_name} = 0".
format(class_name=class_name)
747 if len(inst_class.properties) > 0:
748 properties =
'\n' +
"\n".join(
749 [
" {}".
format(p.name)
for p
in inst_class.properties])
753 properties = class_pointer + properties
754 properties_block = textwrap.dedent(
'''\ 758 ''').
format(properties=properties)
759 return properties_block
762 inst_class: InstantiatedClass):
763 """Generate wrappers for the setters & getters of class properties. 766 inst_class: The instantiated class whose properties we wish to wrap. 769 for propty
in inst_class.properties:
771 function_name = namespace_name + inst_class.name +
'_get_' + propty.name
773 function varargout = get.{name}(this) 774 {varargout} = {wrapper}({num}, this); 775 this.{name} = {varargout}; 777 """.
format(name=propty.name,
778 varargout=
'varargout{1}',
781 (namespace_name, inst_class, propty.name, propty),
782 function_name=function_name))
783 properties.append(getter)
786 function_name = namespace_name + inst_class.name +
'_set_' + propty.name
788 function set.{name}(this, value) 790 {wrapper}({num}, this, value); 792 """.
format(name=propty.name,
795 (namespace_name, inst_class, propty.name, propty),
796 function_name=function_name))
797 properties.append(setter)
802 """Generate the delete function for the Matlab class.""" 803 class_name = inst_class.name
805 methods_text = textwrap.indent(textwrap.dedent(
"""\ 807 {wrapper}({num}, obj.ptr_{class_name}); 810 (namespace_name, inst_class,
'deconstructor',
None)),
812 class_name=
"".join(inst_class.parent.full_namespaces()) +
819 """Generate the display function for the Matlab class.""" 820 return textwrap.indent(textwrap.dedent(
"""\ 821 function display(obj), obj.print(''); end 822 %DISPLAY Calls print on the object 823 function disp(obj), obj.display; end 824 %DISP Calls print on the object 829 """Group overloaded methods together""" 834 """Determine format of return and varargout statements""" 837 if return_type_formatted ==
'void' \
838 else 'varargout{1} = ' 840 varargout =
'[ varargout{1} varargout{2} ] = ' 848 serialize=(
False, )):
849 """Wrap the methods in the class. 852 namespace_name: the name of the class's namespace 853 inst_class: the instantiated class whose methods to wrap 854 methods: the methods to wrap in the order to wrap them 855 serialize: mutable param storing if one of the methods is serialize 863 serialize =
list(serialize)
865 for method
in methods:
866 method_name = method[0].name
867 if method_name
in self.whitelist
and method_name !=
'serialize':
869 if method_name
in self.ignore_methods:
872 if method_name ==
'serialize':
876 namespace_name, inst_class)
880 method_text += textwrap.indent(textwrap.dedent(
"""\ 881 function varargout = {method_name}(this, varargin) 882 """).
format(caps_name=method_name.upper(),
883 method_name=method_name),
886 for overload
in method:
887 method_text += textwrap.indent(textwrap.dedent(
"""\ 888 % {caps_name} usage: {method_name}(""").
format(
889 caps_name=method_name.upper(),
890 method_name=method_name),
895 overload.return_type,
896 include_namespace=
True,
899 return_type_formatted)
903 class_name = namespace_name + (
'' if namespace_name ==
'' 904 else '.') + inst_class.name
907 if check_statement ==
'' \
908 else textwrap.indent(textwrap.dedent(
"""\ 912 class_name=class_name,
913 method_name=overload.original.name), prefix=
' ')
915 method_text += textwrap.dedent(
"""\ 916 {method_args}) : returns {return_type} 917 % Doxygen can be found at https://gtsam.org/doxygen/ 918 {check_statement}{spacing}{varargout}{wrapper}({num}, this, varargin{{:}}); 919 {end_statement}""").
format(
921 return_type=return_type_formatted,
923 (namespace_name, inst_class,
924 overload.original.name, overload)),
925 check_statement=check_statement,
926 spacing=
'' if check_statement ==
'' else ' ',
929 end_statement=end_statement)
931 final_statement = textwrap.indent(textwrap.dedent(
"""\ 932 error('Arguments do not match any overload of function {class_name}.{method_name}'); 933 """.
format(class_name=class_name, method_name=method_name)),
935 method_text += final_statement +
'end\n\n' 942 Wrap the static methods in the class. 944 class_name = instantiated_class.name
946 method_text =
'methods(Static = true)\n' 947 static_methods = sorted(instantiated_class.static_methods,
948 key=
lambda name: name.name)
952 for static_method
in static_methods:
953 format_name =
list(static_method[0].name)
954 format_name[0] = format_name[0]
956 if static_method[0].name
in self.ignore_methods:
959 method_text += textwrap.indent(textwrap.dedent(
'''\ 960 function varargout = {name}(varargin) 961 '''.
format(name=
''.join(format_name))),
964 for static_overload
in static_method:
966 static_overload.args)
969 if check_statement ==
'' \
970 else textwrap.indent(textwrap.dedent(
""" 974 method_text += textwrap.indent(textwrap.dedent(
'''\ 975 % {name_caps} usage: {name_upper_case}({args}) : returns {return_type} 976 % Doxygen can be found at https://gtsam.org/doxygen/ 977 {check_statement}{spacing}varargout{{1}} = {wrapper}({id}, varargin{{:}});{end_statement} 979 name=
''.join(format_name),
980 name_caps=static_overload.name.upper(),
981 name_upper_case=static_overload.name,
984 static_overload.return_type,
985 include_namespace=
True,
987 length=
len(static_overload.args.list()),
989 static_overload.args),
990 check_statement=check_statement,
991 spacing=
'' if check_statement ==
'' else ' ',
994 (namespace_name, instantiated_class,
995 static_overload.name, static_overload)),
996 class_name=instantiated_class.name,
997 end_statement=end_statement),
1002 method_text += textwrap.indent(textwrap.dedent(
"""\ 1003 error('Arguments do not match any overload of function {class_name}.{method_name}'); 1004 """.
format(class_name=class_name,
1005 method_name=static_overload.name)),
1008 method_text += textwrap.indent(textwrap.dedent(
"""\ 1014 method_text += WrapperTemplate.matlab_deserialize.format(
1015 class_name=namespace_name +
'.' + instantiated_class.name,
1018 (namespace_name, instantiated_class,
'string_deserialize',
1025 namespace_name: str =
''):
1026 """Generate comments and code for given class. 1029 instantiated_class: template_instantiator.InstantiatedClass 1030 instance storing the class to wrap 1031 namespace_name: the name of the namespace if there is one 1034 namespace_file_name = namespace_name + file_name
1036 uninstantiated_name =
"::".join(instantiated_class.namespaces()
1037 [1:]) +
"::" + instantiated_class.name
1043 content_text += self.
wrap_methods(instantiated_class.methods)
1051 content_text +=
'classdef {class_name} < {parent}\n'.
format(
1052 class_name=file_name,
1054 instantiated_class.parent_class)).replace(
"::",
"."))
1057 content_text +=
' ' + reduce(
1060 instantiated_class).splitlines()) +
'\n' 1063 content_text +=
' ' + reduce(
1068 instantiated_class.parent_class,
1069 instantiated_class.ctors,
1070 instantiated_class.is_virtual,
1071 ).splitlines()) +
'\n' 1074 content_text +=
' ' + reduce(
1077 namespace_name, instantiated_class).splitlines()) +
'\n' 1080 content_text +=
' ' + reduce(
1087 if len(instantiated_class.methods) != 0:
1088 methods = sorted(instantiated_class.methods,
1089 key=
lambda name: name.name)
1094 serialize=serialize).splitlines()
1095 if len(class_methods_wrapped) > 0:
1096 content_text +=
' ' + reduce(
1097 lambda x, y: x +
'\n' + (
'' if y ==
'' else ' ') + y,
1098 class_methods_wrapped) +
'\n' 1101 if len(instantiated_class.properties) != 0:
1103 namespace_name, instantiated_class)
1104 content_text += textwrap.indent(textwrap.dedent(
1105 "".join(property_accessors)),
1108 content_text +=
' end' 1111 content_text +=
'\n\n ' + reduce(
1114 serialize[0]).splitlines()) +
'\n' + \
1118 content_text += textwrap.dedent(
'''\ 1125 for enum
in instantiated_class.enums:
1127 if namespace_name !=
'':
1128 submodule = f
"+{namespace_name}/" 1131 submodule += f
"+{instantiated_class.name}" 1132 self.content.append((submodule, [enum_text]))
1134 return file_name +
'.m', content_text
1138 Wrap an enum definition as a Matlab class. 1141 enum: The interface_parser.Enum instance 1143 file_name = enum.name +
'.m' 1144 enum_template = textwrap.dedent(
"""\ 1145 classdef {0} < uint32 1151 enumerators =
"\n ".join([
1152 f
"{enumerator.name}({idx})" 1153 for idx, enumerator
in enumerate(enum.enumerators)
1156 content = enum_template.format(enum.name, enumerators)
1157 return file_name, content
1160 """Wrap a namespace by wrapping all of its components. 1163 namespace: the interface_parser.namespace instance of the namespace 1164 add_cpp_file: Flag indicating whether the mex file should be added 1166 namespaces = namespace.full_namespaces()
1167 inner_namespace = namespace.name !=
'' 1170 top_level_scope = []
1171 inner_namespace_scope = []
1173 for element
in namespace.content:
1175 self.includes.append(element)
1184 '+' + x +
'/' for x
in namespace.full_namespaces()[1:]
1186 inner_namespace_scope.append((module, [(file, content)]))
1188 top_level_scope.append((file, content))
1190 elif isinstance(element, instantiator.InstantiatedClass):
1195 element,
"".join(namespace.full_namespaces()))
1197 if not class_text
is None:
1198 inner_namespace_scope.append((
"".join([
1200 for x
in namespace.full_namespaces()[1:]
1201 ])[:-1], [(class_text[0], class_text[1])]))
1204 top_level_scope.append((class_text[0], class_text[1]))
1206 self.content.extend(top_level_scope)
1209 self.content.append(inner_namespace_scope)
1217 func
for func
in namespace.content
1221 self.
wrap_methods(all_funcs,
True, global_ns=namespace)
1230 """Wrap the collector function which returns a shared pointer.""" 1231 new_line =
'\n' if new_line
else '' 1233 return WrapperTemplate.collector_function_shared_return.format(
1235 include_namespace=
False),
1236 shared_obj=shared_obj,
1242 Wrap the return type of the collector function when a std::pair is returned. 1244 return_type_text =
' out[' +
str(func_id) +
'] = ' 1245 pair_value =
'first' if func_id == 0
else 'second' 1246 new_line =
'\n' if func_id == 0
else '' 1250 shared_obj =
'pairResult.' + pair_value
1252 if not (return_type.is_shared_ptr
or return_type.is_ptr):
1253 shared_obj =
'std::make_shared<{name}>({shared_obj})' \
1255 shared_obj=
'pairResult.' + pair_value)
1257 if return_type.typename.name
in self.ignore_namespace:
1259 return_type.typename, shared_obj, func_id, func_id == 0)
1261 return_type_text +=
'wrap_shared_ptr({0},"{1}", false);{new_line}' \
1267 return_type_text +=
'wrap< {0} >(pairResult.{1});{2}'.
format(
1269 pair_value, new_line)
1271 return return_type_text
1276 instantiated_class: InstantiatedClass =
None):
1277 """Helper method to get the final statement before the return in the collector function.""" 1280 if instantiated_class
and \
1281 self.
is_enum(ctype, instantiated_class):
1283 class_name =
".".join(instantiated_class.namespaces()[1:] +
1284 [instantiated_class.name])
1287 class_name =
".".join(instantiated_class.parent.full_namespaces()[1:])
1289 if class_name !=
"":
1292 enum_type = f
"{class_name}{ctype.typename.name}" 1293 expanded = textwrap.indent(
1294 f
'out[0] = wrap_enum({obj},\"{enum_type}\");', prefix=
' ')
1300 include_namespace=
True)
1302 if ctype.typename.name
in self.ignore_namespace:
1304 ctype.typename, obj, 0, new_line=
False)
1306 if ctype.is_shared_ptr
or ctype.is_ptr:
1307 shared_obj =
'{obj},"{method_name_sep}"'.
format(
1308 obj=obj, method_name_sep=sep_method_name(
'.'))
1310 method_name_sep_dot = sep_method_name(
'.')
1314 if isinstance(ctype, parser.TemplatedType)
and \
1315 "std::optional" ==
str(ctype.typename)[:13]:
1317 type_name = ctype.template_params[0].typename
1318 method_name_sep_dot =
".".join(
1319 type_name.namespaces) + f
".{type_name.name}" 1322 shared_obj_template =
'std::make_shared<{method_name_sep_col}>({obj}),' \
1323 '"{method_name_sep_dot}"' 1324 shared_obj = shared_obj_template \
1325 .
format(method_name_sep_col=sep_method_name(),
1326 method_name_sep_dot=method_name_sep_dot,
1329 if ctype.typename.name
not in self.ignore_namespace:
1330 expanded += textwrap.indent(
1331 'out[0] = wrap_shared_ptr({0}, false);'.
format(shared_obj),
1334 expanded +=
' out[0] = wrap< {0} >({1});'.
format(
1335 ctype.typename.name, obj)
1341 Wrap the complete return type of the function. 1346 method.args, arg_id=1, instantiated_class=instantiated_class)[0]
1348 return_1 = method.return_type.type1
1350 return_1_name = method.return_type.type1.typename.name
1353 if isinstance(method, instantiator.InstantiatedMethod):
1354 method_name = method.to_cpp()
1357 if method.instantiations:
1360 method = method.to_cpp()
1362 elif isinstance(method, instantiator.InstantiatedStaticMethod):
1364 method_name += method.original.name
1366 elif isinstance(method, parser.GlobalFunction):
1368 method_name += method.name
1371 if isinstance(method.parent, instantiator.InstantiatedClass):
1372 method_name = method.parent.to_cpp() +
"::" 1375 method_name += method.name
1377 obj =
' ' if return_1_name ==
'void' else '' 1378 obj +=
'{}{}({})'.
format(obj_start, method_name, params)
1380 if return_1_name !=
'void':
1381 if return_count == 1:
1383 obj, return_1, instantiated_class=instantiated_class)
1385 elif return_count == 2:
1386 return_2 = method.return_type.type2
1388 expanded +=
' auto pairResult = {};\n'.
format(obj)
1394 expanded += obj +
';' 1400 class_property: parser.Variable,
1401 instantiated_class: InstantiatedClass =
None):
1402 """Get the last collector function statement before return for a property.""" 1403 property_name = class_property.name
1404 obj =
'obj->{}'.
format(property_name)
1407 class_property.ctype,
1408 instantiated_class=instantiated_class)
1413 Add function to upcast type from void type. 1415 return WrapperTemplate.collector_function_upcast_from_void.format(
1416 class_name=class_name, cpp_name=cpp_name, id=func_id)
1420 Generate the complete collector function that goes into the wrapper.cpp file. 1422 A collector function is the Mex function used to interact between 1423 the C++ object and the Matlab .m files. 1425 collector_func = self.wrapper_map.
get(func_id)
1427 if collector_func
is None:
1430 method_name = collector_func[3]
1432 collector_function =
"void {}" \
1433 "(int nargout, mxArray *out[], int nargin, const mxArray *in[])\n".
format(method_name)
1435 if isinstance(collector_func[1], instantiator.InstantiatedClass):
1438 extra = collector_func[4]
1440 class_name = collector_func[0] + collector_func[1].name
1441 class_name_separated = collector_func[1].to_cpp()
1443 is_static_method =
isinstance(extra, parser.StaticMethod)
1444 is_property =
isinstance(extra, parser.Variable)
1446 if collector_func[2] ==
'collectorInsertAndMakeBase':
1447 body += textwrap.indent(textwrap.dedent(
'''\ 1448 mexAtExit(&_deleteAllObjects); 1449 typedef std::shared_ptr<{class_name_sep}> Shared;\n 1450 Shared *self = *reinterpret_cast<Shared**> (mxGetData(in[0])); 1451 collector_{class_name}.insert(self); 1452 ''').
format(class_name_sep=class_name_separated,
1453 class_name=class_name),
1456 if collector_func[1].parent_class:
1457 body += textwrap.indent(textwrap.dedent(
''' 1458 typedef std::shared_ptr<{}> SharedBase; 1459 out[0] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL); 1460 *reinterpret_cast<SharedBase**>(mxGetData(out[0])) = new SharedBase(*self); 1461 ''').
format(collector_func[1].parent_class),
1464 elif collector_func[2] ==
'constructor':
1467 extra.args, instantiated_class=collector_func[1])
1469 if collector_func[1].parent_class:
1470 base += textwrap.indent(textwrap.dedent(
''' 1471 typedef std::shared_ptr<{}> SharedBase; 1472 out[1] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL); 1473 *reinterpret_cast<SharedBase**>(mxGetData(out[1])) = new SharedBase(*self); 1474 ''').
format(collector_func[1].parent_class),
1477 body += textwrap.dedent(
'''\ 1478 mexAtExit(&_deleteAllObjects); 1479 typedef std::shared_ptr<{class_name_sep}> Shared;\n 1480 {body_args} Shared *self = new Shared(new {class_name_sep}({params})); 1481 collector_{class_name}.insert(self); 1482 out[0] = mxCreateNumericMatrix(1, 1, mxUINT32OR64_CLASS, mxREAL); 1483 *reinterpret_cast<Shared**> (mxGetData(out[0])) = self; 1484 {base}''').
format(class_name_sep=class_name_separated,
1485 body_args=body_args,
1487 class_name=class_name,
1490 elif collector_func[2] ==
'deconstructor':
1491 body += textwrap.indent(textwrap.dedent(
'''\ 1492 typedef std::shared_ptr<{class_name_sep}> Shared; 1493 checkArguments("delete_{class_name}",nargout,nargin,1); 1494 Shared *self = *reinterpret_cast<Shared**>(mxGetData(in[0])); 1495 Collector_{class_name}::iterator item; 1496 item = collector_{class_name}.find(self); 1497 if(item != collector_{class_name}.end()) {{ 1498 collector_{class_name}.erase(item); 1501 ''').
format(class_name_sep=class_name_separated,
1502 class_name=class_name),
1505 elif extra ==
'serialize':
1508 collector_func[1].name,
1509 full_name=collector_func[1].to_cpp(),
1510 namespace=collector_func[0])
1512 elif extra ==
'deserialize':
1515 collector_func[1].name,
1516 full_name=collector_func[1].to_cpp(),
1517 namespace=collector_func[0])
1519 elif is_method
or is_static_method:
1522 if is_static_method:
1525 method_name += extra.name
1529 arg_id=1
if is_method
else 0,
1530 instantiated_class=collector_func[1])
1533 extra, collector_func[1])
1538 shared_obj =
' auto obj = unwrap_shared_ptr<{class_name_sep}>' \
1539 '(in[0], "ptr_{class_name}");\n'.
format(
1540 class_name_sep=class_name_separated,
1541 class_name=class_name)
1543 body +=
' checkArguments("{method_name}",nargout,nargin{min1},' \
1547 '{return_body}\n'.
format(
1548 min1=
'-1' if is_method
else '',
1549 shared_obj=shared_obj,
1550 method_name=method_name,
1551 num_args=
len(extra.args.list()),
1552 body_args=body_args,
1553 return_body=return_body)
1556 shared_obj =
' auto obj = unwrap_shared_ptr<{class_name_sep}>' \
1557 '(in[0], "ptr_{class_name}");\n'.
format(
1558 class_name_sep=class_name_separated,
1559 class_name=class_name)
1563 extra, arg_id=1, instantiated_class=collector_func[1])
1564 unpack_property = textwrap.indent(textwrap.dedent(
'''\ 1565 {arg_type} {name} = {unwrap} 1566 '''.
format(arg_type=property_type,
1572 if "_get_" in method_name:
1574 extra, instantiated_class=collector_func[1])
1576 getter =
' checkArguments("{property_name}",nargout,nargin{min1},' \
1579 '{return_body}\n'.
format(
1580 property_name=extra.name,
1583 shared_obj=shared_obj,
1584 return_body=return_body)
1589 if "_set_" in method_name:
1591 not self.
is_enum(extra.ctype, collector_func[1])
1592 return_body =
' obj->{0} = {1}{0};'.
format(
1593 extra.name,
'*' if is_ptr_type
else '')
1595 setter =
' checkArguments("{property_name}",nargout,nargin{min1},' \
1598 '{unpack_property}' \
1599 '{return_body}\n'.
format(
1600 property_name=extra.name,
1603 shared_obj=shared_obj,
1604 unpack_property=unpack_property,
1605 return_body=return_body)
1611 if extra
not in [
'serialize',
'deserialize']:
1614 collector_function += body
1617 body = textwrap.dedent(
'''\ 1619 checkArguments("{function_name}",nargout,nargin,{len}); 1620 ''').
format(function_name=collector_func[1].name,
1622 len=
len(collector_func[1].args.list()))
1626 collector_func[1]) +
'\n}\n' 1628 collector_function += body
1632 return collector_function
1636 Generate the wrapped MEX function. 1642 id_val = self.wrapper_map.
get(wrapper_id)
1643 set_next_case =
False 1646 id_val = self.wrapper_map.
get(wrapper_id + 1)
1651 set_next_case =
True 1653 cases += textwrap.indent(textwrap.dedent(
'''\ 1655 {}(nargout, out, nargin-1, in+1); 1657 ''').
format(wrapper_id, next_case
if next_case
else id_val[3]),
1661 next_case =
'{}_upcastFromVoid_{}'.
format(
1662 id_val[1].name, wrapper_id + 1)
1666 mex_function = WrapperTemplate.mex_function.format(
1672 """Get the name of the class `cls` taking template instantiations into account.""" 1673 if cls.instantiations:
1674 class_name_sep = cls.name
1676 class_name_sep = cls.to_cpp()
1680 return class_name, class_name_sep
1684 Generate the preamble of the wrapper file, which includes 1685 the Boost exports, typedefs for collectors, and 1686 the _deleteAllObjects and _RTTIRegister functions. 1689 typedef_instances = []
1690 boost_class_export_guid =
'' 1691 typedef_collectors =
'' 1694 for cls
in self.classes:
1697 uninstantiated_name =
"::".join(cls.namespaces()[1:] + [cls.name])
1704 if cls.instantiations:
1706 for i, inst
in enumerate(cls.instantiations):
1712 typedef_instances.append(
'typedef {original_class_name} {class_name_sep};' \
1713 .
format(original_class_name=cls.to_cpp(),
1714 class_name_sep=cls.name))
1719 boost_class_export_guid +=
'BOOST_CLASS_EXPORT_GUID({}, "{}");\n'.
format(
1720 class_name_sep, class_name)
1723 typedef_collectors += WrapperTemplate.typdef_collectors.format(
1724 class_name_sep=class_name_sep, class_name=class_name)
1727 delete_objs += WrapperTemplate.delete_obj.format(
1728 class_name=class_name)
1732 rtti_classes +=
' types.insert(std::make_pair(typeid({}).name(), "{}"));\n' \
1733 .
format(class_name_sep, class_name)
1736 typedef_instances =
"\n".join(typedef_instances)
1739 delete_all_objs = WrapperTemplate.delete_all_objects.format(
1740 delete_objs=delete_objs)
1743 rtti_register = WrapperTemplate.rtti_register.format(
1744 module_name=self.
module_name, rtti_classes=rtti_classes)
1746 return typedef_instances, boost_class_export_guid, \
1747 typedef_collectors, delete_all_objs, rtti_register
1750 """Generate the c++ wrapper.""" 1751 assert namespace,
"Namespace if empty" 1754 includes_list = sorted(self.includes,
1755 key=
lambda include: include.header)
1759 boost_headers = WrapperTemplate.boost_headers
1763 includes = textwrap.dedent(
"""\ 1764 {wrapper_file_headers} 1768 boost_headers=boost_headers,
1769 includes_list=
'\n'.join(map(str, includes_list)))
1772 typedef_instances, boost_class_export_guid, \
1773 typedef_collectors, delete_all_objs, \
1774 rtti_register = preamble
1777 set_next_case =
False 1780 id_val = self.wrapper_map.
get(idx)
1781 queue_set_next_case = set_next_case
1783 set_next_case =
False 1786 id_val = self.wrapper_map.
get(idx + 1)
1791 set_next_case =
True 1795 if queue_set_next_case:
1797 id_val[1].name, idx, id_val[1].to_cpp())
1799 wrapper_file = textwrap.dedent(
'''\ 1802 {boost_class_export_guid} 1803 {typedefs_collectors} 1806 {pointer_constructor_fragment}{mex_function}''') \
1807 .
format(includes=includes,
1808 typedef_instances=typedef_instances,
1809 boost_class_export_guid=boost_class_export_guid,
1810 typedefs_collectors=typedef_collectors,
1811 delete_all_objs=delete_all_objs,
1812 rtti_register=rtti_register,
1813 pointer_constructor_fragment=ptr_ctor_frag,
1816 self.content.append((self.
_wrapper_name() +
'.cpp', wrapper_file))
1820 Wrap the serizalize method of the class. 1822 class_name = inst_class.name
1824 (namespace_name, inst_class,
'string_serialize',
'serialize'))
1826 return WrapperTemplate.class_serialize_method.format(
1828 wrapper_id=wrapper_id,
1829 class_name=namespace_name +
'.' + class_name)
1836 Wrap the serizalize collector function. 1838 return WrapperTemplate.collector_function_serialize.format(
1839 class_name=class_name, full_name=full_name, namespace=namespace)
1846 Wrap the deserizalize collector function. 1848 return WrapperTemplate.collector_function_deserialize.format(
1849 class_name=class_name, full_name=full_name, namespace=namespace)
1853 Generate files and folders from matlab wrapper content. 1856 cc_content: The content to generate formatted as 1857 (file_name, file_content) or 1858 (folder_name, [(file_name, file_content)]) 1859 path: The path to the files parent folder within the main folder 1861 for c
in cc_content:
1866 path_to_folder = osp.join(path, c[0][0])
1868 if not osp.isdir(path_to_folder):
1870 os.makedirs(path_to_folder, exist_ok=
True)
1874 for sub_content
in c:
1878 path_to_folder = osp.join(path, c[0])
1880 if not osp.isdir(path_to_folder):
1882 os.makedirs(path_to_folder, exist_ok=
True)
1885 for sub_content
in c[1]:
1886 path_to_file = osp.join(path_to_folder, sub_content[0])
1887 with open(path_to_file,
'w')
as f:
1888 f.write(sub_content[1])
1890 path_to_file = osp.join(path, c[0])
1892 if not osp.isdir(path_to_file):
1898 with open(path_to_file,
'w')
as f:
1902 """High level function to wrap the project.""" 1906 with open(file,
'r') as f: 1910 parsed_result = parser.Module.parseString(content)
1913 module = instantiator.instantiate_namespace(parsed_result)
1915 if module.name
in modules:
1917 module.name].content[0].content += module.content[0].content
1919 modules[module.name] = module
1921 for module
in modules.values():
def _group_methods(self, methods)
def _wrap_args(self, args)
def generate_wrapper(self, namespace)
def wrap_class_deconstructor(self, namespace_name, inst_class)
def _has_serialization(self, cls)
static const Eigen::internal::all_t all
def wrap_methods(self, methods, global_funcs=False, global_ns=None)
def wrap_class_methods(self, namespace_name, inst_class, methods, serialize=(False,))
def wrap_properties_block(self, class_name, inst_class)
def get_class_name(self, cls)
def wrap_collector_function_serialize(self, class_name, full_name='', namespace='')
def wrap_class_properties
def wrap_collector_function_return_types(self, return_type, func_id)
def __init__(self, module_name, top_module_namespace='', ignore_classes=(), use_boost_serialization=False)
bool isinstance(handle obj)
def wrap_method(self, methods)
def wrap_collector_function_deserialize(self, class_name, full_name='', namespace='')
def add_class(self, instantiated_class)
def generate_collector_function(self, func_id)
def wrap_collector_property_return
def _wrapper_unwrap_arguments(self, args, arg_id=0, instantiated_class=None)
def generate_content(self, cc_content, path)
def generate_preamble(self)
def wrap_class_serialize_method(self, namespace_name, inst_class)
def wrap_enum(self, enum)
def _group_class_methods(self, methods)
def class_comment(self, instantiated_class)
def class_serialize_comment(self, class_name, static_methods)
def _wrap_variable_arguments(self, args, wrap_datatypes=True)
def _unwrap_argument(self, arg, arg_id=0, instantiated_class=None)
def _wrap_list_variable_arguments(self, args)
def wrap_collector_function_return(self, method, instantiated_class=None)
def wrap_collector_function_shared_return(self, return_type_name, shared_obj, func_id, new_line=True)
def wrap_instantiated_class
def wrap_class_constructors(self, namespace_name, inst_class, parent_name, ctors, is_virtual)
def wrap_static_methods(self, namespace_name, instantiated_class, serialize)
def _qualified_name(self, names)
def wrap_namespace(self, namespace, add_mex_file=True)
def _insert_spaces(self, x, y)
def _wrap_method_check_statement
def _expand_default_arguments(method, save_backup=True)
Double_ range(const Point2_ &p, const Point2_ &q)
def _return_count(return_type)
std::string format(const std::string &str, const std::vector< std::string > &find, const std::vector< std::string > &replace)
def wrap_global_function(self, function)
def wrap_collector_function_upcast_from_void(self, class_name, func_id, cpp_name)
def wrap(self, files, path)
Container::iterator get(Container &c, Position position)
size_t len(handle h)
Get the length of a Python object.
def _format_varargout(cls, return_type, return_type_formatted)
def wrap_class_display(self)