Merging 'master' into 'wrap'

release/4.3a0
Varun Agrawal 2021-07-22 11:51:22 -04:00
commit 117b401510
8 changed files with 68 additions and 88 deletions

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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):]

View File

@ -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:

View File

@ -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])
)

View File

@ -1,3 +1,2 @@
pyparsing
pytest
loguru

View File

@ -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,