# Copyright 2014 Insight Software Consortium.
# Copyright 2004-2008 Roman Yakovenko.
# Distributed under the Boost Software License, Version 1.0.
# See http://www.boost.org/LICENSE_1_0.txt
"""
defines classes, that describe C++ types
"""
from . import compilers
from . import algorithms_cache
class type_t(object):
"""base class for all types"""
def __init__(self):
object.__init__(self)
self.cache = algorithms_cache.type_algs_cache_t()
self._byte_size = 0
self._byte_align = 0
self.compiler = None
def __str__(self):
res = self.decl_string
if res[:2] == "::":
res = res[2:]
return res
def __eq__(self, other):
if not isinstance(other, type_t):
return False
return self.decl_string == other.decl_string
def __hash__(self):
return hash(self.decl_string)
def __ne__(self, other):
return not self.__eq__(other)
def __lt__(self, other):
if not isinstance(other, self.__class__):
return self.__class__.__name__ < other.__class__.__name__
return self.decl_string < other.decl_string
def build_decl_string(self, with_defaults=True):
raise NotImplementedError()
@property
def decl_string(self):
return self.build_decl_string()
@property
def partial_decl_string(self):
return self.build_decl_string(False)
def _clone_impl(self):
raise NotImplementedError()
def clone(self):
"returns new instance of the type"
answer = self._clone_impl()
return answer
@property
def byte_size(self):
"Size of this type in bytes @type: int"
return self._byte_size
@byte_size.setter
def byte_size(self, new_byte_size):
self._byte_size = new_byte_size
@property
def byte_align(self):
"Alignment of this type in bytes @type: int"
return self._byte_align
@byte_align.setter
def byte_align(self, new_byte_align):
self._byte_align = new_byte_align
# There are cases when GCC-XML reports something like this
#
# In this case I will use this as type
class dummy_type_t(type_t):
"""provides :class:`type_t` interface for a string, that defines C++ type.
This class could be very useful in the code generator.
"""
def __init__(self, decl_string):
type_t.__init__(self)
self._decl_string = decl_string
def build_decl_string(self, with_defaults=True):
return self._decl_string
def _clone_impl(self):
return dummy_type_t(self._decl_string)
class unknown_t(type_t):
"type, that represents all C++ types, that could not be parsed by GCC-XML"
def __init__(self):
type_t.__init__(self)
def build_decl_string(self, with_defaults=True):
return '?unknown?'
def _clone_impl(self):
return self
class ellipsis_t(type_t):
"""type, that represents "..." in function definition"""
def __init__(self):
type_t.__init__(self)
def build_decl_string(self, with_defaults=True):
return '...'
def _clone_impl(self):
return self
##########################################################################
# Fundamental types:
class fundamental_t(type_t):
"""base class for all fundamental, build-in types"""
def __init__(self, name):
type_t.__init__(self)
self._name = name
def build_decl_string(self, with_defaults=True):
return self._name
def _clone_impl(self):
return self
class java_fundamental_t(fundamental_t):
"""base class for all JNI defined fundamental types"""
def __init__(self, name):
fundamental_t.__init__(self, name)
class void_t(fundamental_t):
"""represents void type"""
CPPNAME = 'void'
def __init__(self):
fundamental_t.__init__(self, void_t.CPPNAME)
class char_t(fundamental_t):
"""represents char type"""
CPPNAME = 'char'
def __init__(self):
fundamental_t.__init__(self, char_t.CPPNAME)
class signed_char_t(fundamental_t):
"""represents signed char type"""
CPPNAME = 'signed char'
def __init__(self):
fundamental_t.__init__(self, signed_char_t.CPPNAME)
class unsigned_char_t(fundamental_t):
"""represents unsigned char type"""
CPPNAME = 'unsigned char'
def __init__(self):
fundamental_t.__init__(self, unsigned_char_t.CPPNAME)
class wchar_t(fundamental_t):
"""represents wchar_t type"""
CPPNAME = 'wchar_t'
def __init__(self):
fundamental_t.__init__(self, wchar_t.CPPNAME)
class short_int_t(fundamental_t):
"""represents short int type"""
CPPNAME = 'short int'
def __init__(self):
fundamental_t.__init__(self, short_int_t.CPPNAME)
class short_unsigned_int_t(fundamental_t):
"""represents short unsigned int type"""
CPPNAME = 'short unsigned int'
def __init__(self):
fundamental_t.__init__(self, short_unsigned_int_t.CPPNAME)
class bool_t(fundamental_t):
"""represents bool type"""
CPPNAME = 'bool'
def __init__(self):
fundamental_t.__init__(self, bool_t.CPPNAME)
class int_t(fundamental_t):
"""represents int type"""
CPPNAME = 'int'
def __init__(self):
fundamental_t.__init__(self, int_t.CPPNAME)
class unsigned_int_t(fundamental_t):
"""represents unsigned int type"""
CPPNAME = 'unsigned int'
def __init__(self):
fundamental_t.__init__(self, unsigned_int_t.CPPNAME)
class long_int_t(fundamental_t):
"""represents long int type"""
CPPNAME = 'long int'
def __init__(self):
fundamental_t.__init__(self, long_int_t.CPPNAME)
class long_unsigned_int_t(fundamental_t):
"""represents long unsigned int type"""
CPPNAME = 'long unsigned int'
def __init__(self):
fundamental_t.__init__(self, long_unsigned_int_t.CPPNAME)
class long_long_int_t(fundamental_t):
"""represents long long int type"""
CPPNAME = 'long long int'
def __init__(self):
fundamental_t.__init__(self, long_long_int_t.CPPNAME)
class long_long_unsigned_int_t(fundamental_t):
"""represents long long unsigned int type"""
CPPNAME = 'long long unsigned int'
def __init__(self):
fundamental_t.__init__(self, long_long_unsigned_int_t.CPPNAME)
class float_t(fundamental_t):
"""represents float type"""
CPPNAME = 'float'
def __init__(self):
fundamental_t.__init__(self, float_t.CPPNAME)
class double_t(fundamental_t):
"""represents double type"""
CPPNAME = 'double'
def __init__(self):
fundamental_t.__init__(self, double_t.CPPNAME)
class long_double_t(fundamental_t):
"""represents long double type"""
CPPNAME = 'long double'
def __init__(self):
fundamental_t.__init__(self, long_double_t.CPPNAME)
class complex_double_t(fundamental_t):
"""represents complex double type"""
CPPNAME = 'complex double'
def __init__(self):
fundamental_t.__init__(self, complex_double_t.CPPNAME)
class complex_long_double_t(fundamental_t):
"""represents complex long double type"""
CPPNAME = 'complex long double'
def __init__(self):
fundamental_t.__init__(self, complex_long_double_t.CPPNAME)
class complex_float_t(fundamental_t):
"""represents complex float type"""
CPPNAME = 'complex float'
def __init__(self):
fundamental_t.__init__(self, complex_float_t.CPPNAME)
class jbyte_t(java_fundamental_t):
"""represents jbyte type"""
JNAME = 'jbyte'
def __init__(self):
java_fundamental_t.__init__(self, jbyte_t.JNAME)
class jshort_t(java_fundamental_t):
"""represents jshort type"""
JNAME = 'jshort'
def __init__(self):
java_fundamental_t.__init__(self, jshort_t.JNAME)
class jint_t(java_fundamental_t):
"""represents jint type"""
JNAME = 'jint'
def __init__(self):
java_fundamental_t.__init__(self, jint_t.JNAME)
class jlong_t(java_fundamental_t):
"""represents jlong type"""
JNAME = 'jlong'
def __init__(self):
java_fundamental_t.__init__(self, jlong_t.JNAME)
class jfloat_t(java_fundamental_t):
"""represents jfloat type"""
JNAME = 'jfloat'
def __init__(self):
java_fundamental_t.__init__(self, jfloat_t.JNAME)
class jdouble_t(java_fundamental_t):
"""represents jdouble type"""
JNAME = 'jdouble'
def __init__(self):
java_fundamental_t.__init__(self, jdouble_t.JNAME)
class jchar_t(java_fundamental_t):
"""represents jchar type"""
JNAME = 'jchar'
def __init__(self):
java_fundamental_t.__init__(self, jchar_t.JNAME)
class jboolean_t(java_fundamental_t):
"""represents jboolean type"""
JNAME = 'jboolean'
def __init__(self):
java_fundamental_t.__init__(self, jboolean_t.JNAME)
class int128_t(fundamental_t):
"""represents __int128_t type"""
CPPNAME = '__int128_t'
def __init__(self):
fundamental_t.__init__(self, int128_t.CPPNAME)
class uint128_t(fundamental_t):
"""represents __uint128_t type"""
CPPNAME = '__uint128_t'
def __init__(self):
fundamental_t.__init__(self, uint128_t.CPPNAME)
FUNDAMENTAL_TYPES = {
# adding java types
void_t.CPPNAME: void_t(),
char_t.CPPNAME: char_t(),
signed_char_t.CPPNAME: signed_char_t(),
unsigned_char_t.CPPNAME: unsigned_char_t(),
wchar_t.CPPNAME: wchar_t(),
short_int_t.CPPNAME: short_int_t(),
'signed ' + short_int_t.CPPNAME: short_int_t(),
short_unsigned_int_t.CPPNAME: short_unsigned_int_t(),
bool_t.CPPNAME: bool_t(),
int_t.CPPNAME: int_t(),
'signed ' + int_t.CPPNAME: int_t(),
unsigned_int_t.CPPNAME: unsigned_int_t(),
long_int_t.CPPNAME: long_int_t(),
long_unsigned_int_t.CPPNAME: long_unsigned_int_t(),
long_long_int_t.CPPNAME: long_long_int_t(),
long_long_unsigned_int_t.CPPNAME: long_long_unsigned_int_t(),
int128_t.CPPNAME: int128_t(),
uint128_t.CPPNAME: uint128_t(),
float_t.CPPNAME: float_t(),
double_t.CPPNAME: double_t(),
long_double_t.CPPNAME: long_double_t(),
complex_long_double_t.CPPNAME: complex_long_double_t(),
complex_double_t.CPPNAME: complex_double_t(),
complex_float_t.CPPNAME: complex_float_t(),
jbyte_t.JNAME: jbyte_t(),
jshort_t.JNAME: jshort_t(),
jint_t.JNAME: jint_t(),
jlong_t.JNAME: jlong_t(),
jfloat_t.JNAME: jfloat_t(),
jdouble_t.JNAME: jdouble_t(),
jchar_t.JNAME: jchar_t(),
jboolean_t.JNAME: jboolean_t(),
'__java_byte': jbyte_t(),
'__java_short': jshort_t(),
'__java_int': jint_t(),
'__java_long': jlong_t(),
'__java_float': jfloat_t(),
'__java_double': jdouble_t(),
'__java_char': jchar_t(),
'__java_boolean': jboolean_t()
}
"""
defines a mapping between fundamental type name and its synonym to the instance
of class that describes the type
"""
##########################################################################
# Compaund types:
class compound_t(type_t):
"""class that allows to represent compound types like `const int*`"""
def __init__(self, base):
type_t.__init__(self)
self._base = base
@property
def base(self):
"reference to internal/base class"
return self._base
@base.setter
def base(self, new_base):
self._base = new_base
class volatile_t(compound_t):
"""represents `volatile whatever` type"""
def __init__(self, base):
compound_t.__init__(self, base)
def build_decl_string(self, with_defaults=True):
return self.base.build_decl_string(with_defaults) + ' volatile'
def _clone_impl(self):
return volatile_t(self.base.clone())
class restrict_t(compound_t):
"""represents `restrict whatever` type"""
# The restrict keyword can be considered an extension to the strict
# aliasing rule. It allows the programmer to declare that pointers which
# share the same type (or were otherwise validly created) do not alias
# eachother. By using restrict the programmer can declare that any loads
# and stores through the qualified pointer (or through another pointer
# copied either directly or indirectly from the restricted pointer) are
# the only loads and stores to the same address during the lifetime of
# the pointer. In other words, the pointer is not aliased by any pointers
# other than its own copies.
def __init__(self, base):
compound_t.__init__(self, base)
def build_decl_string(self, with_defaults=True):
return '__restrict__ ' + self.base.build_decl_string(with_defaults)
def _clone_impl(self):
return restrict_t(self.base.clone())
class const_t(compound_t):
"""represents `whatever const` type"""
def __init__(self, base):
compound_t.__init__(self, base)
def build_decl_string(self, with_defaults=True):
return self.base.build_decl_string(with_defaults) + ' const'
def _clone_impl(self):
return const_t(self.base.clone())
class pointer_t(compound_t):
"""represents `whatever*` type"""
def __init__(self, base):
compound_t.__init__(self, base)
def build_decl_string(self, with_defaults=True):
return self.base.build_decl_string(with_defaults) + ' *'
def _clone_impl(self):
return pointer_t(self.base.clone())
class reference_t(compound_t):
"""represents `whatever&` type"""
def __init__(self, base):
compound_t.__init__(self, base)
def build_decl_string(self, with_defaults=True):
return self.base.build_decl_string(with_defaults) + ' &'
def _clone_impl(self):
return reference_t(self.base.clone())
class array_t(compound_t):
"""represents C++ array type"""
SIZE_UNKNOWN = -1
def __init__(self, base, size):
compound_t.__init__(self, base)
self._size = size
@property
def size(self):
"returns array size"
return self._size
@size.setter
def size(self, size):
"""sometimes there is a need to update the size of the array"""
self.cache.reset()
self._size = size
def build_decl_string(self, with_defaults=True):
# return self.base.build_decl_string(with_defaults) + '[%d]' %
# self.size
return self.__bds_for_multi_dim_arrays(None, with_defaults)
def __bds_for_multi_dim_arrays(self, parent_dims=None, with_defaults=True):
if parent_dims:
parent_dims.append(self.size)
else:
parent_dims = [self.size]
if isinstance(self.base, array_t):
return self.base.__bds_for_multi_dim_arrays(
parent_dims,
with_defaults)
else:
tmp = []
for s in parent_dims:
tmp.append('[%d]' % s)
return self.base.build_decl_string(with_defaults) + ''.join(tmp)
def _clone_impl(self):
return array_t(self.base.clone(), self.size)
class calldef_type_t(object):
"""base class for all types that describes "callable" declaration"""
def __init__(self, return_type=None, arguments_types=None):
object.__init__(self)
self._return_type = return_type
if arguments_types is None:
arguments_types = []
self._arguments_types = arguments_types
@property
def return_type(self):
"""reference to :class:`return type `"""
return self._return_type
@return_type.setter
def return_type(self, new_return_type):
self._return_type = new_return_type
@property
def arguments_types(self):
"""list of argument :class:`types `"""
return self._arguments_types
@arguments_types.setter
def arguments_types(self, new_arguments_types):
self._arguments_types = new_arguments_types
@property
def has_ellipsis(self):
return self.arguments_types and isinstance(
self.arguments_types[-1], ellipsis_t)
class free_function_type_t(type_t, calldef_type_t):
"""describes free function type"""
NAME_TEMPLATE = '%(return_type)s (*)( %(arguments)s )'
TYPEDEF_NAME_TEMPLATE = (
'%(return_type)s ( *%(typedef_name)s )( %(arguments)s )')
def __init__(self, return_type=None, arguments_types=None):
type_t.__init__(self)
calldef_type_t.__init__(self, return_type, arguments_types)
@staticmethod
def create_decl_string(return_type, arguments_types, with_defaults=True):
"""
returns free function type
:param return_type: function return type
:type return_type: :class:`type_t`
:param arguments_types: list of argument :class:`type `
:rtype: :class:`free_function_type_t`
"""
f = lambda x: x.build_decl_string(with_defaults)
return free_function_type_t.NAME_TEMPLATE % {
'return_type': return_type.build_decl_string(with_defaults),
'arguments': ','.join(
map(
f,
arguments_types))}
def build_decl_string(self, with_defaults=True):
return self.create_decl_string(
self.return_type,
self.arguments_types,
with_defaults)
def _clone_impl(self):
rt_clone = None
if self.return_type:
rt_clone = self.return_type.clone()
return free_function_type_t(
rt_clone, [
arg.clone() for arg in self.arguments_types])
# TODO: create real typedef
def create_typedef(self, typedef_name, unused=None, with_defaults=True):
"""returns string, that contains valid C++ code, that defines typedef
to function type
:param name: the desired name of typedef
"""
# unused argument simplifies user code
f = lambda x: x.build_decl_string(with_defaults)
return free_function_type_t.TYPEDEF_NAME_TEMPLATE % {
'typedef_name': typedef_name,
'return_type': self.return_type.build_decl_string(with_defaults),
'arguments': ','.join(map(f, self.arguments_types))}
class member_function_type_t(type_t, calldef_type_t):
"""describes member function type"""
NAME_TEMPLATE = (
'%(return_type)s ( %(class)s::* )( %(arguments)s )%(has_const)s')
TYPEDEF_NAME_TEMPLATE = (
'%(return_type)s ( %(class)s::*%(typedef_name)s' +
')( %(arguments)s ) %(has_const)s')
def __init__(
self,
class_inst=None,
return_type=None,
arguments_types=None,
has_const=False):
type_t.__init__(self)
calldef_type_t.__init__(self, return_type, arguments_types)
self._has_const = has_const
self._class_inst = class_inst
@property
def has_const(self):
"""describes, whether function has const modifier"""
return self._has_const
@has_const.setter
def has_const(self, has_const):
self._has_const = has_const
@property
def class_inst(self):
"""reference to parent :class:`class `"""
return self._class_inst
@class_inst.setter
def class_inst(self, class_inst):
self._class_inst = class_inst
# TODO: create real typedef
def create_typedef(
self,
typedef_name,
class_alias=None,
with_defaults=True):
"""creates typedef to the function type
:param typedef_name: desired type name
:rtype: string
"""
has_const_str = ''
if self.has_const:
has_const_str = 'const'
if None is class_alias:
if with_defaults:
class_alias = self.class_inst.decl_string
else:
class_alias = self.class_inst.partial_decl_string
f = lambda x: x.build_decl_string(with_defaults)
return member_function_type_t.TYPEDEF_NAME_TEMPLATE % {
'typedef_name': typedef_name,
'return_type': self.return_type.build_decl_string(with_defaults),
'class': class_alias,
'arguments': ','.join(
map(
f,
self.arguments_types)),
'has_const': has_const_str}
def create(self):
return self.build_decl_string(
self.return_type,
self.class_inst.decl_string,
self.arguments_types,
self.has_const)
@staticmethod
def create_decl_string(
return_type,
class_decl_string,
arguments_types,
has_const,
with_defaults=True):
has_const_str = ''
if has_const:
has_const_str = 'const'
return_type_decl_string = ''
if return_type:
return_type_decl_string = return_type.build_decl_string(
with_defaults)
f = lambda x: x.build_decl_string(with_defaults)
return member_function_type_t.NAME_TEMPLATE % {
'return_type': return_type_decl_string,
'class': class_decl_string,
'arguments': ','.join(
map(
f,
arguments_types)),
'has_const': has_const_str}
def build_decl_string(self, with_defaults=True):
return self.create_decl_string(
self.return_type,
self.class_inst.decl_string,
self.arguments_types,
self.has_const,
with_defaults)
def _clone_impl(self):
rt_clone = None
if self.return_type:
rt_clone = self.return_type.clone()
return member_function_type_t(
self.class_inst, rt_clone, [
arg.clone() for arg in self.arguments_types], self.has_const)
class member_variable_type_t(compound_t):
"""describes member variable type"""
NAME_TEMPLATE = '%(type)s ( %(class)s::* )'
def __init__(self, class_inst=None, variable_type=None):
compound_t.__init__(self, class_inst)
self._mv_type = variable_type
@property
def variable_type(self):
"""describes member variable :class:`type `"""
return self._mv_type
@variable_type.setter
def variable_type(self, new_type):
self._mv_type = new_type
def build_decl_string(self, with_defaults=True):
return self.NAME_TEMPLATE % {
'type': self.variable_type.build_decl_string(with_defaults),
'class': self.base.build_decl_string(with_defaults)}
def _clone_impl(self):
return member_variable_type_t(
class_inst=self.base,
variable_type=self.variable_type.clone())
##########################################################################
# declarated types:
class declarated_t(type_t):
"""class that binds between to hierarchies: :class:`type_t`
and :class:`declaration_t`"""
def __init__(self, declaration):
type_t.__init__(self)
self._declaration = declaration
@property
def declaration(self):
"reference to :class:`declaration_t`"
return self._declaration
@declaration.setter
def declaration(self, new_declaration):
self._declaration = new_declaration
def build_decl_string(self, with_defaults=True):
if with_defaults:
return self._declaration.decl_string
else:
return self._declaration.partial_decl_string
def _clone_impl(self):
return declarated_t(self._declaration)
@property
def byte_size(self):
"Size of this type in bytes @type: int"
return self._declaration.byte_size
@property
def byte_align(self):
"alignment of this type in bytes @type: int"
return self._declaration.byte_align
class type_qualifiers_t(object):
"""contains additional information about type: mutable, static, extern"""
def __init__(self, has_static=False, has_mutable=False):
self._has_static = has_static
self._has_mutable = has_mutable
def __eq__(self, other):
if not isinstance(other, type_qualifiers_t):
return False
return self.has_static == other.has_static \
and self.has_mutable == other.has_mutable
def __hash__(self):
return super.__hash__(self)
def __ne__(self, other):
return not self.__eq__(other)
def __lt__(self, other):
if not isinstance(other, type_qualifiers_t):
return object.__lt__(self, other)
return self.has_static < other.has_static \
and self.has_mutable < other.has_mutable
@property
def has_static(self):
return self._has_static
@has_static.setter
def has_static(self, has_static):
self._has_static = has_static
@property
def has_extern(self):
"""synonym to static"""
return self.has_static
@has_extern.setter
def has_extern(self, has_extern):
self.has_static = has_extern
@property
def has_mutable(self):
return self._has_mutable
@has_mutable.setter
def has_mutable(self, has_mutable):
self._has_mutable = has_mutable