Merging 'master' into 'wrap'
commit
117b401510
|
@ -10,7 +10,7 @@ Parser classes and rules for parsing C++ classes.
|
|||
Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar, Varun Agrawal, and Frank Dellaert
|
||||
"""
|
||||
|
||||
from typing import Iterable, List, Union
|
||||
from typing import Any, Iterable, List, Union
|
||||
|
||||
from pyparsing import Literal, Optional, ZeroOrMore # type: ignore
|
||||
|
||||
|
@ -48,12 +48,12 @@ class Method:
|
|||
args_list, t.is_const))
|
||||
|
||||
def __init__(self,
|
||||
template: str,
|
||||
template: Union[Template, Any],
|
||||
name: str,
|
||||
return_type: ReturnType,
|
||||
args: ArgumentList,
|
||||
is_const: str,
|
||||
parent: Union[str, "Class"] = ''):
|
||||
parent: Union["Class", Any] = ''):
|
||||
self.template = template
|
||||
self.name = name
|
||||
self.return_type = return_type
|
||||
|
@ -98,7 +98,7 @@ class StaticMethod:
|
|||
name: str,
|
||||
return_type: ReturnType,
|
||||
args: ArgumentList,
|
||||
parent: Union[str, "Class"] = ''):
|
||||
parent: Union["Class", Any] = ''):
|
||||
self.name = name
|
||||
self.return_type = return_type
|
||||
self.args = args
|
||||
|
@ -129,7 +129,7 @@ class Constructor:
|
|||
def __init__(self,
|
||||
name: str,
|
||||
args: ArgumentList,
|
||||
parent: Union["Class", str] = ''):
|
||||
parent: Union["Class", Any] = ''):
|
||||
self.name = name
|
||||
self.args = args
|
||||
|
||||
|
@ -167,7 +167,7 @@ class Operator:
|
|||
return_type: ReturnType,
|
||||
args: ArgumentList,
|
||||
is_const: str,
|
||||
parent: Union[str, "Class"] = ''):
|
||||
parent: Union["Class", Any] = ''):
|
||||
self.name = name
|
||||
self.operator = operator
|
||||
self.return_type = return_type
|
||||
|
@ -284,7 +284,7 @@ class Class:
|
|||
properties: List[Variable],
|
||||
operators: List[Operator],
|
||||
enums: List[Enum],
|
||||
parent: str = '',
|
||||
parent: Any = '',
|
||||
):
|
||||
self.template = template
|
||||
self.is_virtual = is_virtual
|
||||
|
|
|
@ -169,7 +169,7 @@ class GlobalFunction:
|
|||
return_type: ReturnType,
|
||||
args_list: ArgumentList,
|
||||
template: Template,
|
||||
parent: str = ''):
|
||||
parent: Any = ''):
|
||||
self.name = name
|
||||
self.return_type = return_type
|
||||
self.args = args_list
|
||||
|
|
|
@ -12,7 +12,7 @@ Author: Duy Nguyen Ta, Fan Jiang, Matthew Sklar, Varun Agrawal, and Frank Dellae
|
|||
|
||||
# pylint: disable=unnecessary-lambda, expression-not-assigned
|
||||
|
||||
from typing import Iterable, List, Union
|
||||
from typing import List, Sequence, Union
|
||||
|
||||
from pyparsing import (Forward, Optional, Or, ParseResults, # type: ignore
|
||||
delimitedList)
|
||||
|
@ -49,12 +49,12 @@ class Typename:
|
|||
|
||||
def __init__(self,
|
||||
t: ParseResults,
|
||||
instantiations: Iterable[ParseResults] = ()):
|
||||
instantiations: Sequence[ParseResults] = ()):
|
||||
self.name = t[-1] # the name is the last element in this list
|
||||
self.namespaces = t[:-1]
|
||||
|
||||
if instantiations:
|
||||
if isinstance(instantiations, Iterable):
|
||||
if isinstance(instantiations, Sequence):
|
||||
self.instantiations = instantiations # type: ignore
|
||||
else:
|
||||
self.instantiations = instantiations.asList()
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
"""Mixins for reducing the amount of boilerplate in the main wrapper class."""
|
||||
|
||||
from typing import Any, Tuple, Union
|
||||
|
||||
import gtwrap.interface_parser as parser
|
||||
import gtwrap.template_instantiator as instantiator
|
||||
|
||||
|
@ -7,13 +9,14 @@ import gtwrap.template_instantiator as instantiator
|
|||
class CheckMixin:
|
||||
"""Mixin to provide various checks."""
|
||||
# Data types that are primitive types
|
||||
not_ptr_type = ['int', 'double', 'bool', 'char', 'unsigned char', 'size_t']
|
||||
not_ptr_type: Tuple = ('int', 'double', 'bool', 'char', 'unsigned char',
|
||||
'size_t')
|
||||
# Ignore the namespace for these datatypes
|
||||
ignore_namespace = ['Matrix', 'Vector', 'Point2', 'Point3']
|
||||
ignore_namespace: Tuple = ('Matrix', 'Vector', 'Point2', 'Point3')
|
||||
# Methods that should be ignored
|
||||
ignore_methods = ['pickle']
|
||||
ignore_methods: Tuple = ('pickle', )
|
||||
# Methods that should not be wrapped directly
|
||||
whitelist = ['serializable', 'serialize']
|
||||
whitelist: Tuple = ('serializable', 'serialize')
|
||||
# Datatypes that do not need to be checked in methods
|
||||
not_check_type: list = []
|
||||
|
||||
|
@ -23,7 +26,7 @@ class CheckMixin:
|
|||
return True
|
||||
return False
|
||||
|
||||
def is_shared_ptr(self, arg_type):
|
||||
def is_shared_ptr(self, arg_type: parser.Type):
|
||||
"""
|
||||
Determine if the `interface_parser.Type` should be treated as a
|
||||
shared pointer in the wrapper.
|
||||
|
@ -33,7 +36,7 @@ class CheckMixin:
|
|||
and arg_type.typename.name not in self.ignore_namespace
|
||||
and arg_type.typename.name != 'string')
|
||||
|
||||
def is_ptr(self, arg_type):
|
||||
def is_ptr(self, arg_type: parser.Type):
|
||||
"""
|
||||
Determine if the `interface_parser.Type` should be treated as a
|
||||
raw pointer in the wrapper.
|
||||
|
@ -43,7 +46,7 @@ class CheckMixin:
|
|||
and arg_type.typename.name not in self.ignore_namespace
|
||||
and arg_type.typename.name != 'string')
|
||||
|
||||
def is_ref(self, arg_type):
|
||||
def is_ref(self, arg_type: parser.Type):
|
||||
"""
|
||||
Determine if the `interface_parser.Type` should be treated as a
|
||||
reference in the wrapper.
|
||||
|
@ -55,7 +58,14 @@ class CheckMixin:
|
|||
|
||||
class FormatMixin:
|
||||
"""Mixin to provide formatting utilities."""
|
||||
def _clean_class_name(self, instantiated_class):
|
||||
|
||||
ignore_namespace: tuple
|
||||
data_type: Any
|
||||
data_type_param: Any
|
||||
_return_count: Any
|
||||
|
||||
def _clean_class_name(self,
|
||||
instantiated_class: instantiator.InstantiatedClass):
|
||||
"""Reformatted the C++ class name to fit Matlab defined naming
|
||||
standards
|
||||
"""
|
||||
|
@ -65,23 +75,23 @@ class FormatMixin:
|
|||
return instantiated_class.name
|
||||
|
||||
def _format_type_name(self,
|
||||
type_name,
|
||||
separator='::',
|
||||
include_namespace=True,
|
||||
constructor=False,
|
||||
method=False):
|
||||
type_name: parser.Typename,
|
||||
separator: str = '::',
|
||||
include_namespace: bool = True,
|
||||
is_constructor: bool = False,
|
||||
is_method: bool = False):
|
||||
"""
|
||||
Args:
|
||||
type_name: an interface_parser.Typename to reformat
|
||||
separator: the statement to add between namespaces and typename
|
||||
include_namespace: whether to include namespaces when reformatting
|
||||
constructor: if the typename will be in a constructor
|
||||
method: if the typename will be in a method
|
||||
is_constructor: if the typename will be in a constructor
|
||||
is_method: if the typename will be in a method
|
||||
|
||||
Raises:
|
||||
constructor and method cannot both be true
|
||||
"""
|
||||
if constructor and method:
|
||||
if is_constructor and is_method:
|
||||
raise ValueError(
|
||||
'Constructor and method parameters cannot both be True')
|
||||
|
||||
|
@ -93,9 +103,9 @@ class FormatMixin:
|
|||
if name not in self.ignore_namespace and namespace != '':
|
||||
formatted_type_name += namespace + separator
|
||||
|
||||
if constructor:
|
||||
if is_constructor:
|
||||
formatted_type_name += self.data_type.get(name) or name
|
||||
elif method:
|
||||
elif is_method:
|
||||
formatted_type_name += self.data_type_param.get(name) or name
|
||||
else:
|
||||
formatted_type_name += name
|
||||
|
@ -106,8 +116,8 @@ class FormatMixin:
|
|||
template = '{}'.format(
|
||||
self._format_type_name(type_name.instantiations[idx],
|
||||
include_namespace=include_namespace,
|
||||
constructor=constructor,
|
||||
method=method))
|
||||
is_constructor=is_constructor,
|
||||
is_method=is_method))
|
||||
templates.append(template)
|
||||
|
||||
if len(templates) > 0: # If there are no templates
|
||||
|
@ -119,15 +129,15 @@ class FormatMixin:
|
|||
self._format_type_name(type_name.instantiations[idx],
|
||||
separator=separator,
|
||||
include_namespace=False,
|
||||
constructor=constructor,
|
||||
method=method))
|
||||
is_constructor=is_constructor,
|
||||
is_method=is_method))
|
||||
|
||||
return formatted_type_name
|
||||
|
||||
def _format_return_type(self,
|
||||
return_type,
|
||||
include_namespace=False,
|
||||
separator="::"):
|
||||
return_type: parser.function.ReturnType,
|
||||
include_namespace: bool = False,
|
||||
separator: str = "::"):
|
||||
"""Format return_type.
|
||||
|
||||
Args:
|
||||
|
@ -154,18 +164,15 @@ class FormatMixin:
|
|||
|
||||
return return_wrap
|
||||
|
||||
def _format_class_name(self, instantiated_class, separator=''):
|
||||
def _format_class_name(self,
|
||||
instantiated_class: instantiator.InstantiatedClass,
|
||||
separator: str = ''):
|
||||
"""Format a template_instantiator.InstantiatedClass name."""
|
||||
if instantiated_class.parent == '':
|
||||
parent_full_ns = ['']
|
||||
else:
|
||||
parent_full_ns = instantiated_class.parent.full_namespaces()
|
||||
# class_name = instantiated_class.parent.name
|
||||
#
|
||||
# if class_name != '':
|
||||
# class_name += separator
|
||||
#
|
||||
# class_name += instantiated_class.name
|
||||
|
||||
parentname = "".join([separator + x
|
||||
for x in parent_full_ns]) + separator
|
||||
|
||||
|
@ -175,10 +182,12 @@ class FormatMixin:
|
|||
|
||||
return class_name
|
||||
|
||||
def _format_static_method(self, static_method, separator=''):
|
||||
"""Example:
|
||||
|
||||
gtsamPoint3.staticFunction
|
||||
def _format_static_method(self,
|
||||
static_method: parser.StaticMethod,
|
||||
separator: str = ''):
|
||||
"""
|
||||
Example:
|
||||
gtsam.Point3.staticFunction()
|
||||
"""
|
||||
method = ''
|
||||
|
||||
|
@ -188,35 +197,17 @@ class FormatMixin:
|
|||
|
||||
return method[2 * len(separator):]
|
||||
|
||||
def _format_instance_method(self, instance_method, separator=''):
|
||||
def _format_global_function(self,
|
||||
function: Union[parser.GlobalFunction, Any],
|
||||
separator: str = ''):
|
||||
"""Example:
|
||||
|
||||
gtsamPoint3.staticFunction
|
||||
"""
|
||||
method = ''
|
||||
|
||||
if isinstance(instance_method, instantiator.InstantiatedMethod):
|
||||
method_list = [
|
||||
separator + x
|
||||
for x in instance_method.parent.parent.full_namespaces()
|
||||
]
|
||||
method += "".join(method_list) + separator
|
||||
|
||||
method += instance_method.parent.name + separator
|
||||
method += instance_method.original.name
|
||||
method += "<" + instance_method.instantiations.to_cpp() + ">"
|
||||
|
||||
return method[2 * len(separator):]
|
||||
|
||||
def _format_global_method(self, static_method, separator=''):
|
||||
"""Example:
|
||||
|
||||
gtsamPoint3.staticFunction
|
||||
"""
|
||||
method = ''
|
||||
|
||||
if isinstance(static_method, parser.GlobalFunction):
|
||||
method += "".join([separator + x for x in static_method.parent.full_namespaces()]) + \
|
||||
if isinstance(function, parser.GlobalFunction):
|
||||
method += "".join([separator + x for x in function.parent.full_namespaces()]) + \
|
||||
separator
|
||||
|
||||
return method[2 * len(separator):]
|
||||
|
|
|
@ -11,8 +11,6 @@ import textwrap
|
|||
from functools import partial, reduce
|
||||
from typing import Dict, Iterable, List, Union
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import gtwrap.interface_parser as parser
|
||||
import gtwrap.template_instantiator as instantiator
|
||||
from gtwrap.matlab_wrapper.mixins import CheckMixin, FormatMixin
|
||||
|
@ -200,7 +198,7 @@ class MatlabWrapper(CheckMixin, FormatMixin):
|
|||
check_type = self._format_type_name(
|
||||
arg.ctype.typename,
|
||||
separator='.',
|
||||
constructor=not wrap_datatypes)
|
||||
is_constructor=not wrap_datatypes)
|
||||
|
||||
var_arg_wrap += " && isa(varargin{{{num}}},'{data_type}')".format(
|
||||
num=i, data_type=check_type)
|
||||
|
@ -1090,11 +1088,10 @@ class MatlabWrapper(CheckMixin, FormatMixin):
|
|||
if method.instantiations:
|
||||
# method_name += '<{}>'.format(
|
||||
# self._format_type_name(method.instantiations))
|
||||
# method_name = self._format_instance_method(method, '::')
|
||||
method = method.to_cpp()
|
||||
|
||||
elif isinstance(method, parser.GlobalFunction):
|
||||
method_name = self._format_global_method(method, '::')
|
||||
method_name = self._format_global_function(method, '::')
|
||||
method_name += method.name
|
||||
|
||||
else:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
import itertools
|
||||
from copy import deepcopy
|
||||
from typing import Iterable, List
|
||||
from typing import Any, Iterable, List, Sequence
|
||||
|
||||
import gtwrap.interface_parser as parser
|
||||
|
||||
|
@ -214,17 +214,17 @@ class InstantiatedMethod(parser.Method):
|
|||
}
|
||||
"""
|
||||
def __init__(self,
|
||||
original,
|
||||
original: parser.Method,
|
||||
instantiations: Iterable[parser.Typename] = ()):
|
||||
self.original = original
|
||||
self.instantiations = instantiations
|
||||
self.template = ''
|
||||
self.template: Any = ''
|
||||
self.is_const = original.is_const
|
||||
self.parent = original.parent
|
||||
|
||||
# Check for typenames if templated.
|
||||
# This way, we can gracefully handle both templated and non-templated methods.
|
||||
typenames = self.original.template.typenames if self.original.template else []
|
||||
typenames: Sequence = self.original.template.typenames if self.original.template else []
|
||||
self.name = instantiate_name(original.name, self.instantiations)
|
||||
self.return_type = instantiate_return_type(
|
||||
original.return_type,
|
||||
|
@ -348,13 +348,12 @@ class InstantiatedClass(parser.Class):
|
|||
return "{virtual}Class {cpp_class} : {parent_class}\n"\
|
||||
"{ctors}\n{static_methods}\n{methods}\n{operators}".format(
|
||||
virtual="virtual " if self.is_virtual else '',
|
||||
name=self.name,
|
||||
cpp_class=self.to_cpp(),
|
||||
parent_class=self.parent,
|
||||
ctors="\n".join([repr(ctor) for ctor in self.ctors]),
|
||||
methods="\n".join([repr(m) for m in self.methods]),
|
||||
static_methods="\n".join([repr(m)
|
||||
for m in self.static_methods]),
|
||||
methods="\n".join([repr(m) for m in self.methods]),
|
||||
operators="\n".join([repr(op) for op in self.operators])
|
||||
)
|
||||
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
pyparsing
|
||||
pytest
|
||||
loguru
|
|
@ -11,8 +11,6 @@ import os.path as osp
|
|||
import sys
|
||||
import unittest
|
||||
|
||||
from loguru import logger
|
||||
|
||||
sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__))))
|
||||
|
||||
from gtwrap.matlab_wrapper import MatlabWrapper
|
||||
|
@ -44,10 +42,6 @@ class TestWrap(unittest.TestCase):
|
|||
# Create the `actual/matlab` directory
|
||||
os.makedirs(self.MATLAB_ACTUAL_DIR, exist_ok=True)
|
||||
|
||||
# set the log level to INFO by default
|
||||
logger.remove() # remove the default sink
|
||||
logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
|
||||
|
||||
def compare_and_diff(self, file):
|
||||
"""
|
||||
Compute the comparison between the expected and actual file,
|
||||
|
|
Loading…
Reference in New Issue