[pygccxml-commit] SF.net SVN: pygccxml:[1713] pyplusplus_dev
Brought to you by:
mbaas,
roman_yakovenko
From: <rom...@us...> - 2009-05-11 07:44:56
|
Revision: 1713 http://pygccxml.svn.sourceforge.net/pygccxml/?rev=1713&view=rev Author: roman_yakovenko Date: 2009-05-11 07:44:51 +0000 (Mon, 11 May 2009) Log Message: ----------- update docs Modified Paths: -------------- pygccxml_dev/pygccxml/declarations/matchers.py pyplusplus_dev/pyplusplus/function_transformers/function_transformation.py pyplusplus_dev/pyplusplus/module_builder/boost_python_builder.py pyplusplus_dev/pyplusplus/module_builder/ctypes_builder.py pyplusplus_dev/unittests/ctypes_tester.py pyplusplus_dev/unittests/custom_smart_ptr_classes_tester.py pyplusplus_dev/unittests/test_all.py pyplusplus_dev/unittests/virtual_inheritance_tester.py Modified: pygccxml_dev/pygccxml/declarations/matchers.py =================================================================== --- pygccxml_dev/pygccxml/declarations/matchers.py 2009-05-11 07:27:29 UTC (rev 1712) +++ pygccxml_dev/pygccxml/declarations/matchers.py 2009-05-11 07:44:51 UTC (rev 1713) @@ -1,542 +1,545 @@ -# Copyright 2004-2008 Roman Yakovenko. -# Distributed under the Boost Software License, Version 1.0. (See -# accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -""" -defines all "built-in" classes that implement declarations compare functionality -according to some criteria -""" - -import os -import re -import types -import algorithm -import variable -import namespace -import calldef -import cpptypes -import templates -import class_declaration -from pygccxml import utils - -class matcher_base_t(object): - """matcher_base_t class defines interface for classes that will implement - compare functionality according to some criteria. - """ - def __init__( self ): - object.__init__( self ) - - def __call__(self, decl): - raise NotImplementedError( "matcher must always implement the __call__() method." ) - - def __invert__(self): - """not-operator (~)""" - return not_matcher_t(self) - - def __and__(self, other): - """and-operator (&)""" - return and_matcher_t([self, other]) - - def __or__(self, other): - """or-operator (|)""" - return or_matcher_t([self, other]) - - def __str__( self ): - return "base class for all matchers" - -class and_matcher_t(matcher_base_t): - """ - Combine several other matchers with "&" (and) operator. - - For example: find all private functions with name XXX - - .. code-block:: python - - matcher = access_type_matcher_t( 'private' ) & calldef_matcher_t( name='XXX' ) - """ - def __init__(self, matchers): - matcher_base_t.__init__(self) - self.matchers = matchers - - def __call__(self, decl): - for matcher in self.matchers: - if not matcher(decl): - return False - return True - - def __str__(self): - return " & ".join( map( lambda x: "(%s)" % str( x ), self.matchers ) ) - - -class or_matcher_t(matcher_base_t): - """Combine several other matchers with "|" (or) operator. - - For example: find all functions and variables with name 'XXX' - - .. code-block:: python - - matcher = variable_matcher_t( name='XXX' ) | calldef_matcher_t( name='XXX' ) - - """ - def __init__(self, matchers): - matcher_base_t.__init__(self) - self.matchers = matchers - - def __call__(self, decl): - for matcher in self.matchers: - if matcher(decl): - return True - return False - - def __str__(self): - return " | ".join( map( lambda x: "(%s)" % str( x ), self.matchers ) ) - - -class not_matcher_t(matcher_base_t): - """ - return the inverse result of a matcher - - For example: find all public and protected declarations - - .. code-block:: python - - matcher = ~access_type_matcher_t( 'private' ) - """ - def __init__(self, matcher): - matcher_base_t.__init__(self) - self.matcher = matcher - - def __call__(self, decl): - return not self.matcher(decl) - - def __str__(self): - return "~(%s)"%str(self.matcher) - -class declaration_matcher_t( matcher_base_t ): - """ - Instance of this class will match declarations by next criteria: - - declaration name, also could be fully qualified name - Example: `wstring` or `::std::wstring` - - declaration type - Example: :class:`class_t`, :class:`namespace_t`, :class:`enumeration_t` - - location within file system ( file or directory ) - """ - def __init__( self, name=None, decl_type=None, header_dir=None, header_file=None ): - """ - :param decl_type: declaration type to match by. For example :class:`enumeration_t`. - :type decl_type: any class that derives from :class:`declaration_t` class - - :param name: declaration name, could be full name. - :type name: str - - :param header_dir: absolute directory path - :type header_dir: str - - :param header_file: absolute file path - :type header_file: str - - """ - #An other option is that pygccxml will create absolute path using - #os.path.abspath function. But I think this is just wrong, because abspath - #builds path using current working directory. This behavior is fragile - #and very difficult to find a bug. - matcher_base_t.__init__( self ) - self.decl_type = decl_type - self.__name = None - self.__opt_is_tmpl_inst = None - self.__opt_tmpl_name = None - self.__opt_is_full_name = None - self.__decl_name_only = None - - self._set_name( name ) - - self.header_dir = header_dir - self.header_file = header_file - - if self.header_dir: - self.header_dir = utils.normalize_path( self.header_dir ) - if not os.path.isabs( self.header_dir ): - raise RuntimeError( "Path to header directory should be absolute!" ) - - if self.header_file: - self.header_file = utils.normalize_path( self.header_file ) - if not os.path.isabs( self.header_file ): - raise RuntimeError( "Path to header file should be absolute!" ) - - def _get_name(self): - return self.__name - - def _set_name( self, name ): - self.__name = name - if not self.__name: - self.__opt_is_tmpl_inst = None - self.__opt_tmpl_name = None - self.__opt_is_full_name = None - self.__decl_name_only = None - else: - self.__opt_is_tmpl_inst = templates.is_instantiation( self.__name ) - self.__opt_tmpl_name = templates.name( self.__name ) - if self.__opt_is_tmpl_inst: - if '::' in self.__opt_tmpl_name: - self.__opt_is_full_name = True - self.__decl_name_only = self.__opt_tmpl_name.split('::')[-1] - else: - self.__opt_is_full_name = False - self.__decl_name_only = self.__opt_tmpl_name - self.__name = templates.normalize( name ) - else: - if '::' in self.__name: - self.__opt_is_full_name = True - self.__decl_name_only = self.__name.split('::')[-1] - else: - self.__opt_is_full_name = False - self.__decl_name_only = self.__name - - - name = property( _get_name, _set_name ) - - def __str__( self ): - msg = [] - if not None is self.decl_type: - msg.append( '(decl type==%s)' % self.decl_type.__name__ ) - if not None is self.name: - msg.append( '(name==%s)' % self.name ) - if not None is self.header_dir: - msg.append( '(header dir==%s)' % self.header_dir ) - if not None is self.header_file: - msg.append( '(header file==%s)' % self.header_file ) - if not msg: - msg.append( 'any' ) - return ' and '.join( msg ) - - def __call__( self, decl ): - if not None is self.decl_type: - if not isinstance( decl, self.decl_type ): - return False - if not None is self.name: - if not self.check_name( decl ): - return False - if not None is self.header_dir: - if decl.location: - decl_dir = os.path.abspath( os.path.dirname( decl.location.file_name ) ) - decl_dir = utils.normalize_path( decl_dir ) - if decl_dir[:len(self.header_dir)] != self.header_dir: - return False - else: - return False - if not None is self.header_file: - if decl.location: - decl_file = os.path.abspath( decl.location.file_name ) - decl_file = utils.normalize_path( decl_file ) - if decl_file != self.header_file: - return False - else: - return False - return True - - def check_name( self, decl ): - assert not None is self.name - if self.__opt_is_tmpl_inst: - if not self.__opt_is_full_name: - if self.name != templates.normalize( decl.name ) \ - and self.name != templates.normalize( decl.partial_name ): - return False - else: - if self.name != templates.normalize( algorithm.full_name( decl, with_defaults=True ) ) \ - and self.name != templates.normalize( algorithm.full_name( decl, with_defaults=False ) ): - return False - else: - if not self.__opt_is_full_name: - if self.name != decl.name and self.name != decl.partial_name: - return False - else: - if self.name != algorithm.full_name( decl, with_defaults=True ) \ - and self.name != algorithm.full_name( decl, with_defaults=False ): - return False - return True - - def is_full_name(self): - return self.__opt_is_full_name - - def _get_decl_name_only(self): - return self.__decl_name_only - decl_name_only = property( _get_decl_name_only ) - -class variable_matcher_t( declaration_matcher_t ): - """ - Instance of this class will match variables by next criteria: - - :class:`declaration_matcher_t` criteria - - variable type. Example: :class:`int_t` or 'int' - """ - def __init__( self, name=None, type=None, header_dir=None, header_file=None ): - """ - :param type: variable type - :type type: string or instance of :class:`type_t` derived class - """ - declaration_matcher_t.__init__( self - , name=name - , decl_type=variable.variable_t - , header_dir=header_dir - , header_file=header_file ) - self.type = type - - def __call__( self, decl ): - if not super( variable_matcher_t, self ).__call__( decl ): - return False - if not None is self.type: - if isinstance( self.type, cpptypes.type_t ): - if self.type != decl.type: - return False - else: - if self.type != decl.type.decl_string: - return False - return True - - def __str__( self ): - msg = [ super( variable_matcher_t, self ).__str__() ] - if msg == [ 'any' ]: - msg = [] - if not None is self.type: - msg.append( '(value type==%s)' % str(self.type) ) - if not msg: - msg.append( 'any' ) - return ' and '.join( msg ) - - -class namespace_matcher_t( declaration_matcher_t ): - """Instance of this class will match namespaces by name.""" - - def __init__( self, name=None ): - declaration_matcher_t.__init__( self, name=name, decl_type=namespace.namespace_t) - - def __call__( self, decl ): - if self.name and decl.name == '': - #unnamed namespace have same name as thier parent, we should prevent - #this happens. The price is: user should search for unnamed namespace - #directly. - return False - return super( namespace_matcher_t, self ).__call__( decl ) - - -class calldef_matcher_t( declaration_matcher_t ): - """ - Instance of this class will match callable by the following criteria: - * :class:`declaration_matcher_t` criteria - * return type. For example: :class:`int_t` or 'int' - * argument types - """ - - def __init__( self, name=None, return_type=None, arg_types=None, decl_type=None, header_dir=None, header_file=None): - """ - :param return_type: callable return type - :type return_type: string or instance of :class:`type_t` derived class - - :param arg_types: list of function argument types. `arg_types` can contain. - Any item within the list could be string or instance of :class:`type_t` derived - class. If you don't want some argument to participate in match you can - put None. For example: - - .. code-block:: python - - calldef_matcher_t( arg_types=[ 'int &', None ] ) - - will match all functions that takes 2 arguments, where the first one is - reference to integer and second any - - :type arg_types: list - """ - if None is decl_type: - decl_type = calldef.calldef_t - declaration_matcher_t.__init__( self - , name=name - , decl_type=decl_type - , header_dir=header_dir - , header_file=header_file ) - - self.return_type = return_type - self.arg_types = arg_types - - def __call__( self, decl ): - if not super( calldef_matcher_t, self ).__call__( decl ): - return False - if not None is self.return_type \ - and not self.__compare_types( self.return_type, decl.return_type ): - return False - if self.arg_types: - if isinstance( self.arg_types, (types.ListType, types.TupleType)): - if len(self.arg_types) != len( decl.arguments ): - return False - for type_or_str, arg in zip( self.arg_types, decl.arguments ): - if None == type_or_str: - continue - else: - if not self.__compare_types( type_or_str, arg.type ): - return False - return True - - def __compare_types( self, type_or_str, type ): - assert type_or_str - if type is None: - return False - if isinstance( type_or_str, cpptypes.type_t ): - if type_or_str != type: - return False - else: - if type_or_str != type.decl_string: - return False - return True - - def __str__( self ): - msg = [ super( calldef_matcher_t, self ).__str__() ] - if msg == [ 'any' ]: - msg = [] - if not None is self.return_type: - msg.append( '(return type==%s)' % str(self.return_type) ) - if self.arg_types: - for i in range( len( self.arg_types ) ): - if self.arg_types[i] is None: - msg.append( '(arg %d type==any)' % i ) - else: - msg.append( '(arg %d type==%s)' % ( i, str( self.arg_types[i] ) ) ) - if not msg: - msg.append( 'any' ) - return ' and '.join( msg ) - - -class operator_matcher_t( calldef_matcher_t ): - """ - Instance of this class will match operators by next criteria: - * :class:`calldef_matcher_t` criteria - * operator symbol: =, !=, (), [] and etc - """ - def __init__( self, name=None, symbol=None, return_type=None, arg_types=None, decl_type=None, header_dir=None, header_file=None): - """ - :param symbol: operator symbol - :type symbol: str - """ - if None is decl_type: - decl_type = calldef.operator_t - calldef_matcher_t.__init__( self - , name=name - , return_type=return_type - , arg_types=arg_types - , decl_type=decl_type - , header_dir=header_dir - , header_file=header_file) - self.symbol = symbol - - def __call__( self, decl ): - if not super( operator_matcher_t, self ).__call__( decl ): - return False - if not None is self.symbol: - if self.symbol != decl.symbol: - return False - return True - - def __str__( self ): - msg = [ super( operator_matcher_t, self ).__str__() ] - if msg == [ 'any' ]: - msg = [] - if not None is self.symbol: - msg.append( '(symbol==%s)' % str(self.symbol) ) - if not msg: - msg.append( 'any' ) - return ' and '.join( msg ) - -class regex_matcher_t( matcher_base_t ): - """ - Instance of this class will match declaration using regular expression. - User should supply a function that will extract from declaration desired - information as string. Later, this matcher will match that string using - user regular expression. - """ - def __init__( self, regex, function=None ): - """ - :param regex: regular expression - :type regex: string, an instance of this class will compile it for you - - :param function: function that will be called to get an information from - declaration as string. As input this function takes 1 argument: reference - to declaration. Return value should be string. If function is None, then - the matcher will use declaration name. - - """ - matcher_base_t.__init__(self) - self.regex = re.compile( regex ) - self.function = function - if None is self.function: - self.function = lambda decl: decl.name - - def __call__( self, decl ): - text = self.function( decl ) - return bool( self.regex.match( text ) ) - - def __str__( self ): - return '(regex=%s)' % self.regex - -class access_type_matcher_t( matcher_base_t ): - """ - Instance of this class will match declaration by its access type: public, - private or protected. If declarations does not have access type, for example - free function, then `False` will be returned. - """ - - def __init__( self, access_type ): - """ - :param access_type: declaration access type, could be "public", "private", "protected" - :type access_type: :class: `str` - """ - matcher_base_t.__init__( self ) - self.access_type = access_type - - def __call__( self, decl ): - if not isinstance( decl.parent, class_declaration.class_t ): - return False - return self.access_type == decl.parent.find_out_member_access_type( decl ) - - def __str__( self ): - return '(access type=%s)' % self.access_type - -class virtuality_type_matcher_t( matcher_base_t ): - """ - Instance of this class will match declaration by its virtual type: not virtual, - virtual or pure virtual. If declarations does not have "virtual" property, - for example free function, then `False` will be returned. - """ - - def __init__( self, virtuality_type ): - """ - :param access_type: declaration access type - :type access_type: :class:VIRTUALITY_TYPES defines few constants for your convenience. - """ - matcher_base_t.__init__( self ) - self.virtuality_type = virtuality_type - - def __call__( self, decl ): - if not isinstance( decl.parent, class_declaration.class_t ): - return False - return self.virtuality_type == decl.virtuality - - def __str__( self ): - return '(virtuality type=%s)' % self.virtuality_type - - -class custom_matcher_t( matcher_base_t ): - """ - Instance of this class will match declaration by user custom criteria. - """ - - def __init__( self, function ): - """ - :param function: callable, that takes single argument - declaration instance - should return True or False - """ - matcher_base_t.__init__( self ) - self.function = function - - def __call__( self, decl ): - return bool( self.function( decl ) ) - - def __str__( self ): - return '(user criteria)' +# Copyright 2004-2008 Roman Yakovenko. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +""" +defines all "built-in" classes that implement declarations compare functionality +according to some criteria +""" + +import os +import re +import types +import algorithm +import variable +import namespace +import calldef +import cpptypes +import templates +import class_declaration +from pygccxml import utils + +class matcher_base_t(object): + """matcher_base_t class defines interface for classes that will implement + compare functionality according to some criteria. + """ + def __init__( self ): + object.__init__( self ) + + def __call__(self, decl): + raise NotImplementedError( "matcher must always implement the __call__() method." ) + + def __invert__(self): + """not-operator (~)""" + return not_matcher_t(self) + + def __and__(self, other): + """and-operator (&)""" + return and_matcher_t([self, other]) + + def __or__(self, other): + """or-operator (|)""" + return or_matcher_t([self, other]) + + def __str__( self ): + return "base class for all matchers" + +class and_matcher_t(matcher_base_t): + """ + Combine several other matchers with "&" (and) operator. + + For example: find all private functions with name XXX + + .. code-block:: python + + matcher = access_type_matcher_t( 'private' ) & calldef_matcher_t( name='XXX' ) + """ + def __init__(self, matchers): + matcher_base_t.__init__(self) + self.matchers = matchers + + def __call__(self, decl): + for matcher in self.matchers: + if not matcher(decl): + return False + return True + + def __str__(self): + return " & ".join( map( lambda x: "(%s)" % str( x ), self.matchers ) ) + + +class or_matcher_t(matcher_base_t): + """Combine several other matchers with "|" (or) operator. + + For example: find all functions and variables with name 'XXX' + + .. code-block:: python + + matcher = variable_matcher_t( name='XXX' ) | calldef_matcher_t( name='XXX' ) + + """ + def __init__(self, matchers): + matcher_base_t.__init__(self) + self.matchers = matchers + + def __call__(self, decl): + for matcher in self.matchers: + if matcher(decl): + return True + return False + + def __str__(self): + return " | ".join( map( lambda x: "(%s)" % str( x ), self.matchers ) ) + + +class not_matcher_t(matcher_base_t): + """ + return the inverse result of a matcher + + For example: find all public and protected declarations + + .. code-block:: python + + matcher = ~access_type_matcher_t( 'private' ) + """ + def __init__(self, matcher): + matcher_base_t.__init__(self) + self.matcher = matcher + + def __call__(self, decl): + return not self.matcher(decl) + + def __str__(self): + return "~(%s)"%str(self.matcher) + +class declaration_matcher_t( matcher_base_t ): + """ + Instance of this class will match declarations by next criteria: + - declaration name, also could be fully qualified name + Example: `wstring` or `::std::wstring` + - declaration type + Example: :class:`class_t`, :class:`namespace_t`, :class:`enumeration_t` + - location within file system ( file or directory ) + """ + def __init__( self, name=None, decl_type=None, header_dir=None, header_file=None ): + """ + :param decl_type: declaration type to match by. For example :class:`enumeration_t`. + :type decl_type: any class that derives from :class:`declaration_t` class + + :param name: declaration name, could be full name. + :type name: str + + :param header_dir: absolute directory path + :type header_dir: str + + :param header_file: absolute file path + :type header_file: str + + """ + #An other option is that pygccxml will create absolute path using + #os.path.abspath function. But I think this is just wrong, because abspath + #builds path using current working directory. This behavior is fragile + #and very difficult to find a bug. + matcher_base_t.__init__( self ) + self.decl_type = decl_type + self.__name = None + self.__opt_is_tmpl_inst = None + self.__opt_tmpl_name = None + self.__opt_is_full_name = None + self.__decl_name_only = None + + self._set_name( name ) + + self.header_dir = header_dir + self.header_file = header_file + + if self.header_dir: + self.header_dir = utils.normalize_path( self.header_dir ) + if not os.path.isabs( self.header_dir ): + raise RuntimeError( "Path to header directory should be absolute!" ) + + if self.header_file: + self.header_file = utils.normalize_path( self.header_file ) + if not os.path.isabs( self.header_file ): + raise RuntimeError( "Path to header file should be absolute!" ) + + def _get_name(self): + return self.__name + + def _set_name( self, name ): + self.__name = name + if not self.__name: + self.__opt_is_tmpl_inst = None + self.__opt_tmpl_name = None + self.__opt_is_full_name = None + self.__decl_name_only = None + else: + self.__opt_is_tmpl_inst = templates.is_instantiation( self.__name ) + self.__opt_tmpl_name = templates.name( self.__name ) + if self.__opt_is_tmpl_inst: + if '::' in self.__opt_tmpl_name: + self.__opt_is_full_name = True + self.__decl_name_only = self.__opt_tmpl_name.split('::')[-1] + else: + self.__opt_is_full_name = False + self.__decl_name_only = self.__opt_tmpl_name + self.__name = templates.normalize( name ) + else: + if '::' in self.__name: + self.__opt_is_full_name = True + self.__decl_name_only = self.__name.split('::')[-1] + else: + self.__opt_is_full_name = False + self.__decl_name_only = self.__name + + + name = property( _get_name, _set_name ) + + def __str__( self ): + msg = [] + if not None is self.decl_type: + msg.append( '(decl type==%s)' % self.decl_type.__name__ ) + if not None is self.name: + msg.append( '(name==%s)' % self.name ) + if not None is self.header_dir: + msg.append( '(header dir==%s)' % self.header_dir ) + if not None is self.header_file: + msg.append( '(header file==%s)' % self.header_file ) + if not msg: + msg.append( 'any' ) + return ' and '.join( msg ) + + def __call__( self, decl ): + if not None is self.decl_type: + if not isinstance( decl, self.decl_type ): + return False + if not None is self.name: + if not self.check_name( decl ): + return False + if not None is self.header_dir: + if decl.location: + decl_dir = os.path.abspath( os.path.dirname( decl.location.file_name ) ) + decl_dir = utils.normalize_path( decl_dir ) + if decl_dir[:len(self.header_dir)] != self.header_dir: + return False + else: + return False + if not None is self.header_file: + if decl.location: + decl_file = os.path.abspath( decl.location.file_name ) + decl_file = utils.normalize_path( decl_file ) + if decl_file != self.header_file: + return False + else: + return False + return True + + def check_name( self, decl ): + assert not None is self.name + if self.__opt_is_tmpl_inst: + if not self.__opt_is_full_name: + if self.name != templates.normalize( decl.name ) \ + and self.name != templates.normalize( decl.partial_name ): + return False + else: + if self.name != templates.normalize( algorithm.full_name( decl, with_defaults=True ) ) \ + and self.name != templates.normalize( algorithm.full_name( decl, with_defaults=False ) ): + return False + else: + if not self.__opt_is_full_name: + if self.name != decl.name and self.name != decl.partial_name: + return False + else: + if self.name != algorithm.full_name( decl, with_defaults=True ) \ + and self.name != algorithm.full_name( decl, with_defaults=False ): + return False + return True + + def is_full_name(self): + return self.__opt_is_full_name + + def _get_decl_name_only(self): + return self.__decl_name_only + decl_name_only = property( _get_decl_name_only ) + +class variable_matcher_t( declaration_matcher_t ): + """ + Instance of this class will match variables by next criteria: + - :class:`declaration_matcher_t` criteria + - variable type. Example: :class:`int_t` or 'int' + """ + def __init__( self, name=None, type=None, header_dir=None, header_file=None ): + """ + :param type: variable type + :type type: string or instance of :class:`type_t` derived class + """ + declaration_matcher_t.__init__( self + , name=name + , decl_type=variable.variable_t + , header_dir=header_dir + , header_file=header_file ) + self.type = type + + def __call__( self, decl ): + if not super( variable_matcher_t, self ).__call__( decl ): + return False + if not None is self.type: + if isinstance( self.type, cpptypes.type_t ): + if self.type != decl.type: + return False + else: + if self.type != decl.type.decl_string: + return False + return True + + def __str__( self ): + msg = [ super( variable_matcher_t, self ).__str__() ] + if msg == [ 'any' ]: + msg = [] + if not None is self.type: + msg.append( '(value type==%s)' % str(self.type) ) + if not msg: + msg.append( 'any' ) + return ' and '.join( msg ) + + +class namespace_matcher_t( declaration_matcher_t ): + """Instance of this class will match namespaces by name.""" + + def __init__( self, name=None ): + declaration_matcher_t.__init__( self, name=name, decl_type=namespace.namespace_t) + + def __call__( self, decl ): + if self.name and decl.name == '': + #unnamed namespace have same name as thier parent, we should prevent + #this happens. The price is: user should search for unnamed namespace + #directly. + return False + return super( namespace_matcher_t, self ).__call__( decl ) + + +class calldef_matcher_t( declaration_matcher_t ): + """ + Instance of this class will match callable by the following criteria: + * :class:`declaration_matcher_t` criteria + * return type. For example: :class:`int_t` or 'int' + * argument types + + """ + + def __init__( self, name=None, return_type=None, arg_types=None, decl_type=None, header_dir=None, header_file=None): + """ + :param return_type: callable return type + :type return_type: string or instance of :class:`type_t` derived class + + :type arg_types: list + :param arg_types: list of function argument types. `arg_types` can contain. + Any item within the list could be string or instance + of :class:`type_t` derived class. If you don't want + some argument to participate in match you can put None. + + For example: + + .. code-block:: python + + calldef_matcher_t( arg_types=[ 'int &', None ] ) + + will match all functions that takes 2 arguments, where the first one is + reference to integer and second any + """ + if None is decl_type: + decl_type = calldef.calldef_t + declaration_matcher_t.__init__( self + , name=name + , decl_type=decl_type + , header_dir=header_dir + , header_file=header_file ) + + self.return_type = return_type + self.arg_types = arg_types + + def __call__( self, decl ): + if not super( calldef_matcher_t, self ).__call__( decl ): + return False + if not None is self.return_type \ + and not self.__compare_types( self.return_type, decl.return_type ): + return False + if self.arg_types: + if isinstance( self.arg_types, (types.ListType, types.TupleType)): + if len(self.arg_types) != len( decl.arguments ): + return False + for type_or_str, arg in zip( self.arg_types, decl.arguments ): + if None == type_or_str: + continue + else: + if not self.__compare_types( type_or_str, arg.type ): + return False + return True + + def __compare_types( self, type_or_str, type ): + assert type_or_str + if type is None: + return False + if isinstance( type_or_str, cpptypes.type_t ): + if type_or_str != type: + return False + else: + if type_or_str != type.decl_string: + return False + return True + + def __str__( self ): + msg = [ super( calldef_matcher_t, self ).__str__() ] + if msg == [ 'any' ]: + msg = [] + if not None is self.return_type: + msg.append( '(return type==%s)' % str(self.return_type) ) + if self.arg_types: + for i in range( len( self.arg_types ) ): + if self.arg_types[i] is None: + msg.append( '(arg %d type==any)' % i ) + else: + msg.append( '(arg %d type==%s)' % ( i, str( self.arg_types[i] ) ) ) + if not msg: + msg.append( 'any' ) + return ' and '.join( msg ) + + +class operator_matcher_t( calldef_matcher_t ): + """ + Instance of this class will match operators by next criteria: + * :class:`calldef_matcher_t` criteria + * operator symbol: =, !=, (), [] and etc + """ + def __init__( self, name=None, symbol=None, return_type=None, arg_types=None, decl_type=None, header_dir=None, header_file=None): + """ + :param symbol: operator symbol + :type symbol: str + """ + if None is decl_type: + decl_type = calldef.operator_t + calldef_matcher_t.__init__( self + , name=name + , return_type=return_type + , arg_types=arg_types + , decl_type=decl_type + , header_dir=header_dir + , header_file=header_file) + self.symbol = symbol + + def __call__( self, decl ): + if not super( operator_matcher_t, self ).__call__( decl ): + return False + if not None is self.symbol: + if self.symbol != decl.symbol: + return False + return True + + def __str__( self ): + msg = [ super( operator_matcher_t, self ).__str__() ] + if msg == [ 'any' ]: + msg = [] + if not None is self.symbol: + msg.append( '(symbol==%s)' % str(self.symbol) ) + if not msg: + msg.append( 'any' ) + return ' and '.join( msg ) + +class regex_matcher_t( matcher_base_t ): + """ + Instance of this class will match declaration using regular expression. + User should supply a function that will extract from declaration desired + information as string. Later, this matcher will match that string using + user regular expression. + """ + def __init__( self, regex, function=None ): + """ + :param regex: regular expression + :type regex: string, an instance of this class will compile it for you + + :param function: function that will be called to get an information from + declaration as string. As input this function takes single + argument - reference to a declaration. Return value + should be string. If function is None, then the matcher + will use declaration name. + + """ + matcher_base_t.__init__(self) + self.regex = re.compile( regex ) + self.function = function + if None is self.function: + self.function = lambda decl: decl.name + + def __call__( self, decl ): + text = self.function( decl ) + return bool( self.regex.match( text ) ) + + def __str__( self ): + return '(regex=%s)' % self.regex + +class access_type_matcher_t( matcher_base_t ): + """ + Instance of this class will match declaration by its access type: public, + private or protected. If declarations does not have access type, for example + free function, then `False` will be returned. + """ + + def __init__( self, access_type ): + """ + :param access_type: declaration access type, could be "public", "private", "protected" + :type access_type: :class: `str` + """ + matcher_base_t.__init__( self ) + self.access_type = access_type + + def __call__( self, decl ): + if not isinstance( decl.parent, class_declaration.class_t ): + return False + return self.access_type == decl.parent.find_out_member_access_type( decl ) + + def __str__( self ): + return '(access type=%s)' % self.access_type + +class virtuality_type_matcher_t( matcher_base_t ): + """ + Instance of this class will match declaration by its virtual type: not virtual, + virtual or pure virtual. If declarations does not have "virtual" property, + for example free function, then `False` will be returned. + """ + + def __init__( self, virtuality_type ): + """ + :param access_type: declaration access type + :type access_type: :class:VIRTUALITY_TYPES defines few constants for your convenience. + """ + matcher_base_t.__init__( self ) + self.virtuality_type = virtuality_type + + def __call__( self, decl ): + if not isinstance( decl.parent, class_declaration.class_t ): + return False + return self.virtuality_type == decl.virtuality + + def __str__( self ): + return '(virtuality type=%s)' % self.virtuality_type + + +class custom_matcher_t( matcher_base_t ): + """ + Instance of this class will match declaration by user custom criteria. + """ + + def __init__( self, function ): + """ + :param function: callable, that takes single argument - declaration instance + should return True or False + """ + matcher_base_t.__init__( self ) + self.function = function + + def __call__( self, decl ): + return bool( self.function( decl ) ) + + def __str__( self ): + return '(user criteria)' Modified: pyplusplus_dev/pyplusplus/function_transformers/function_transformation.py =================================================================== --- pyplusplus_dev/pyplusplus/function_transformers/function_transformation.py 2009-05-11 07:27:29 UTC (rev 1712) +++ pyplusplus_dev/pyplusplus/function_transformers/function_transformation.py 2009-05-11 07:44:51 UTC (rev 1713) @@ -1,73 +1,73 @@ -# Copyright 2006 Roman Yakovenko. -# Distributed under the Boost Software License, Version 1.0. (See -# accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -"""defines :class:function_transformation_t class""" - -import md5 -import controllers -from pygccxml import declarations -from pyplusplus import code_repository - -class function_transformation_t: - """the class holds function transformation definition - all transformations that should be applied""" - def __init__(self, function, transformer_creator, **keywd): - self.__function = function - self.__controller = None - if isinstance( function.parent, declarations.class_t ): - if declarations.VIRTUALITY_TYPES.NOT_VIRTUAL == function.virtuality: - self.__controller = controllers.mem_fun_controller_t( function ) - elif declarations.VIRTUALITY_TYPES.PURE_VIRTUAL == function.virtuality: - self.__controller = controllers.pure_virtual_mem_fun_controller_t( function ) - else: - self.__controller = controllers.virtual_mem_fun_controller_t( function ) - else: - self.__controller = controllers.free_fun_controller_t( function ) - self.__transformers = map( lambda tr_creator: tr_creator( function ), transformer_creator ) - self.__thread_safe = keywd.get( 'thread_safe', False ) - self.__controller.apply( self.__transformers ) - self.__unique_name = None - self.__alias = keywd.get( 'alias', None ) - - @property - def unique_name( self ): - if None is self.__unique_name: - obj = md5.new() - if self.__function.mangled: # free functions don't have a mangled value - obj.update( self.__function.mangled ) - else: - obj.update( self.__function.decl_string ) - obj.update( self.__function.location.file_name ) - obj.update( str( self.__function.location.line ) ) - self.__unique_name = self.__function.name + '_' + obj.hexdigest () - return self.__unique_name - - @property - def alias( self ): - if None is self.__alias: - if self.__function.overloads: - self.__alias = self.unique_name - else: - self.__alias = self.__function.alias - return self.__alias - - @property - def transformers( self ): - return self.__transformers - - @property - def controller( self ): - return self.__controller - - def required_headers( self ): - headers = [] - map( lambda transformer: headers.extend( transformer.required_headers() ) - , self.transformers ) - if self.__function.call_policies: - headers.append( code_repository.call_policies.file_name ) - return headers - - @property - def thread_safe( self ): - return self.__thread_safe +# Copyright 2006 Roman Yakovenko. +# Distributed under the Boost Software License, Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +"""defines :class:function_transformation_t class""" + +import hashlib +import controllers +from pygccxml import declarations +from pyplusplus import code_repository + +class function_transformation_t: + """the class holds function transformation definition - all transformations that should be applied""" + def __init__(self, function, transformer_creator, **keywd): + self.__function = function + self.__controller = None + if isinstance( function.parent, declarations.class_t ): + if declarations.VIRTUALITY_TYPES.NOT_VIRTUAL == function.virtuality: + self.__controller = controllers.mem_fun_controller_t( function ) + elif declarations.VIRTUALITY_TYPES.PURE_VIRTUAL == function.virtuality: + self.__controller = controllers.pure_virtual_mem_fun_controller_t( function ) + else: + self.__controller = controllers.virtual_mem_fun_controller_t( function ) + else: + self.__controller = controllers.free_fun_controller_t( function ) + self.__transformers = map( lambda tr_creator: tr_creator( function ), transformer_creator ) + self.__thread_safe = keywd.get( 'thread_safe', False ) + self.__controller.apply( self.__transformers ) + self.__unique_name = None + self.__alias = keywd.get( 'alias', None ) + + @property + def unique_name( self ): + if None is self.__unique_name: + obj = hashlib.md5() + if self.__function.mangled: # free functions don't have a mangled value + obj.update( self.__function.mangled ) + else: + obj.update( self.__function.decl_string ) + obj.update( self.__function.location.file_name ) + obj.update( str( self.__function.location.line ) ) + self.__unique_name = self.__function.name + '_' + obj.hexdigest () + return self.__unique_name + + @property + def alias( self ): + if None is self.__alias: + if self.__function.overloads: + self.__alias = self.unique_name + else: + self.__alias = self.__function.alias + return self.__alias + + @property + def transformers( self ): + return self.__transformers + + @property + def controller( self ): + return self.__controller + + def required_headers( self ): + headers = [] + map( lambda transformer: headers.extend( transformer.required_headers() ) + , self.transformers ) + if self.__function.call_policies: + headers.append( code_repository.call_policies.file_name ) + return headers + + @property + def thread_safe( self ): + return self.__thread_safe Modified: pyplusplus_dev/pyplusplus/module_builder/boost_python_builder.py =================================================================== --- pyplusplus_dev/pyplusplus/module_builder/boost_python_builder.py 2009-05-11 07:27:29 UTC (rev 1712) +++ pyplusplus_dev/pyplusplus/module_builder/boost_python_builder.py 2009-05-11 07:44:51 UTC (rev 1713) @@ -1,424 +1,427 @@ -# Copyright 2004-2008 Roman Yakovenko. -# Distributed under the Boost Software License, Version 1.0. (See -# accompanying file LICENSE_1_0.txt or copy at -# http://www.boost.org/LICENSE_1_0.txt) - -import os -import sys -import time -import types -import warnings -import module_builder - -from pygccxml import parser -from pygccxml import utils as pygccxml_utils -from pygccxml import declarations as decls_package - -from pyplusplus import utils -from pyplusplus import _logging_ -from pyplusplus import decl_wrappers -from pyplusplus import file_writers -from pyplusplus import code_creators -from pyplusplus import creators_factory - -class builder_t(module_builder.module_builder_t): - """ - This class provides users with simple and intuitive interface to `Py++` - and/or pygccxml functionality. If this is your first attempt to use `Py++` - consider to read tutorials. You can find them on `web site <http://www.language-binding.net>`_. - """ - - def __init__( self - , files - , gccxml_path='' - , working_directory='.' - , include_paths=None - , define_symbols=None - , undefine_symbols=None - , start_with_declarations=None - , compilation_mode=None - , cache=None - , optimize_queries=True - , ignore_gccxml_output=False - , indexing_suite_version=1 - , cflags="" - , encoding='ascii' - , compiler=None - , gccxml_config=None): - """ - :param files: list of files, declarations from them you want to export - :type files: list of strings or :class:`parser.file_configuration_t` instances - - :param gccxml_path: path to gccxml binary. If you don't pass this argument, - pygccxml parser will try to locate it using you environment PATH variable - :type gccxml_path: str - - :param include_paths: additional header files location. You don't have to - specify system and standard directories. - :type include_paths: list of strings - - :param define_symbols: list of symbols to be defined for preprocessor. - :param define_symbols: list of strings - - :param undefine_symbols: list of symbols to be undefined for preprocessor. - :param undefine_symbols: list of strings - - :param cflags: Raw string to be added to gccxml command line. - - :param gccxml_config: instance of pygccxml.parser.config_t class, holds - gccxml( compiler ) configuration. You can use this argument instead of - passing the compiler configuration separately. - """ - module_builder.module_builder_t.__init__( self, global_ns=None, encoding=encoding ) - - if not gccxml_config: - gccxml_config = parser.config_t( gccxml_path=gccxml_path - , working_directory=working_directory - , include_paths=include_paths - , define_symbols=define_symbols - , undefine_symbols=undefine_symbols - , start_with_declarations=start_with_declarations - , ignore_gccxml_output=ignore_gccxml_output - , cflags=cflags - , compiler=compiler) - - #may be in future I will add those directories to user_defined_directories to self.__code_creator. - self.__parsed_files = map( pygccxml_utils.normalize_path - , parser.project_reader_t.get_os_file_names( files ) ) - tmp = map( lambda file_: os.path.split( file_ )[0], self.__parsed_files ) - self.__parsed_dirs = filter( None, tmp ) - - self.global_ns = self.__parse_declarations( files - , gccxml_config - , compilation_mode - , cache - , indexing_suite_version) - self.global_ns.decls(recursive=True, allow_empty=True)._code_generator = decl_wrappers.CODE_GENERATOR_TYPES.CTYPES - - self.__code_creator = None - if optimize_queries: - self.run_query_optimizer() - - self.__declarations_code_head = [] - self.__declarations_code_tail = [] - - self.__registrations_code_head = [] - self.__registrations_code_tail = [] - - - - def register_module_dependency( self, other_module_generated_code_dir ): - """ - `already_exposed` solution is pretty good when you mix hand-written - modules with `Py++` generated. It doesn't work/scale for "true" - multi-module development. This is exactly the reason why `Py++` - offers "semi automatic" solution. - - For every exposed module, `Py++` generates `exposed_decl.pypp.txt` file. - This file contains the list of all parsed declarations and whether they - were included or excluded. Later, when you work on another module, you - can tell `Py++` that the current module depends on the previously - generated one. `Py++` will load `exposed_decl.pypp.txt` file and update - the declarations. - """ - - db = utils.exposed_decls_db_t() - db.load( other_module_generated_code_dir ) - db.update_decls( self.global_ns ) - - - def __parse_declarations( self, files, gccxml_config, compilation_mode, cache, indexing_suite_version ): - if None is gccxml_config: - gccxml_config = parser.config_t() - if None is compilation_mode: - compilation_mode = parser.COMPILATION_MODE.FILE_BY_FILE - start_time = time.clock() - self.logger.debug( 'parsing files - started' ) - reader = parser.project_reader_t( gccxml_config, cache, decl_wrappers.dwfactory_t() ) - decls = reader.read_files( files, compilation_mode ) - - self.logger.debug( 'parsing files - done( %f seconds )' % ( time.clock() - start_time ) ) - self.logger.debug( 'settings declarations defaults - started' ) - - global_ns = decls_package.matcher.get_single( - decls_package.namespace_matcher_t( name='::' ) - , decls ) - if indexing_suite_version != 1: - for cls in global_ns.classes(): - cls.indexing_suite_version = indexing_suite_version - for cls in global_ns.decls(decl_type=decls_package.class_declaration_t): - cls.indexing_suite_version = indexing_suite_version - - start_time = time.clock() - self.__apply_decls_defaults(decls) - self.logger.debug( 'settings declarations defaults - done( %f seconds )' - % ( time.clock() - start_time ) ) - return global_ns - - def __filter_by_location( self, flatten_decls ): - for decl in flatten_decls: - if not decl.location: - continue - fpath = pygccxml_utils.normalize_path( decl.location.file_name ) - if pygccxml_utils.contains_parent_dir( fpath, self.__parsed_dirs ): - continue - if fpath in self.__parsed_files: - continue - found = False - for pfile in self.__parsed_files: - if fpath.endswith( pfile ): - found = True - break - if not found: - decl.exclude() - - def __apply_decls_defaults(self, decls): - flatten_decls = decls_package.make_flatten( decls ) - self.__filter_by_location( flatten_decls ) - call_policies_resolver = creators_factory.built_in_resolver_t() - calldefs = filter( lambda decl: isinstance( decl, decls_package.calldef_t ) - , flatten_decls ) - map( lambda calldef: calldef.set_call_policies( call_policies_resolver( calldef ) ) - , calldefs ) - mem_vars = filter( lambda decl: isinstance( decl, decls_package.variable_t ) - and isinstance( decl.parent, decls_package.class_t ) - , flatten_decls ) - map( lambda mem_var: mem_var.set_getter_call_policies( call_policies_resolver( mem_var, 'get' ) ) - , mem_vars ) - map( lambda mem_var: mem_var.set_setter_call_policies( call_policies_resolver( mem_var, 'set' ) ) - , mem_vars ) - - @property - def declarations_code_head( self ): - "List of user code, that will be added to the head of the declarations section." - return self.__declarations_code_head - - @property - def declarations_code_tail( self ): - "List of user code, that will be added to the tail of the declarations section." - return self.__declarations_code_tail - - @property - def registrations_code_head( self ): - "List of user code, that will be added to the head of the registrations section." - return self.__registrations_code_head - - @property - def registrations_code_tail( self ): - "List of user code, that will be added to the tail of the registrations section." - return self.__registrations_code_tail - - def build_code_creator( self - , module_name - , boost_python_ns_name='bp' - , call_policies_resolver_=None - , types_db=None - , target_configuration=None - , enable_indexing_suite=True - , doc_extractor=None): - """ - Creates :class:`code_creators.bpmodule_t` code creator. - - :param module_name: module name - :type module_name: str - - :param boost_python_ns_name: boost::python namespace alias, by default it is `bp` - :type boost_python_ns_name: str - - :param call_policies_resolver_: callable, that will be invoked on every calldef object. It should return call policies. - :type call_policies_resolver_: callable - :param doc_extractor: callable, that takes as argument reference to declaration and returns documentation string - :type doc_extractor: callable or None - """ - - creator = creators_factory.bpcreator_t( self.global_ns - , module_name - , boost_python_ns_name - , call_policies_resolver_ - , types_db - , target_configuration - , enable_indexing_suite ) - self.__code_creator = creator.create() - self.__code_creator.replace_included_headers(self.__parsed_files) - self.__code_creator.update_documentation( doc_extractor ) - return self.__code_creator - - @property - def code_creator( self ): - "reference to :class:`code_creators.bpmodule_t` instance" - if not self.__code_creator: - raise RuntimeError( "self.module is equal to None. Did you forget to call build_code_creator function?" ) - return self.__code_creator - - def has_code_creator( self ): - """ - Function, that will return True if build_code_creator function has been - called and False otherwise - """ - return not ( None is self.__code_creator ) - - def add_declaration_code( self, code, tail=True ): - if tail: - self.__declarations_code_tail.append( code ) - else: - self.__declarations_code_head.append( code ) - - def add_registration_code( self, code, tail=True ): - if tail: - self.__registrations_code_tail.append( code ) - else: - self.__registrations_code_head.append( code ) - - def add_constants( self, **keywds ): - """ - adds code that exposes some constants to Python. - - For example: - .. code-block:: python - - mb.add_constants( version='"1.2.3"' ) - # or - constants = dict( version:'"1.2.3"' ) - mb.add_constants( \\*\\*constants ) - - will generate the following code: - - .. code-block:: c++ - - boost::python::scope().attr("version") = "1.2.3"; - - """ - tmpl = 'boost::python::scope().attr("%(name)s") = %(value)s;' - for name, value in keywds.items(): - if not isinstance( value, types.StringTypes ): - value = str( value ) - self.add_regi... [truncated message content] |