<commit_before>## -*- python -*-
## pylint: disable-msg=W0142,R0921

"""
Base classes for all parameter/return type handlers,
and base interfaces for wrapper generators.
"""

import codesink


try:
    all
except NameError: # for compatibility with Python < 2.5
    def all(iterable):
        "Returns True if all elements are true"
        for element in iterable:
            if not element:
                return False
        return True

class CodeGenerationError(Exception):
    """Exception that is raised when wrapper generation fails for some reason."""


def join_ctype_and_name(ctype, name):
    """
    Utility method that joins a C type and a variable name into
    a single string

    >>> join_ctype_and_name('void*', 'foo')
    'void *foo'
    >>> join_ctype_and_name('void *', 'foo')
    'void *foo'
    >>> join_ctype_and_name("void**", "foo")
    'void **foo'
    >>> join_ctype_and_name("void **", "foo")
    'void **foo'
    """
    if ctype[-1] == '*':
        for i in range(-1, -len(ctype), -1):
            if ctype[i] != '*':
                if ctype[i] == ' ':
                    return "".join([ctype[:i+1], ctype[i+1:], name])
                else:
                    return "".join([ctype[:i+1], ' ', ctype[i+1:], name])
        raise ValueError
    else:
        return " ".join([ctype, name])


class CodeBlock(object):
    '''An intelligent code block that keeps track of cleanup actions.
    This object is to be used by TypeHandlers when generating code.'''

    class CleanupHandle(object):
        """Handle for some cleanup code"""
        __slots__ = ['code_block', 'position']
        def __init__(self, code_block, position):
            """Create a handle given code_block and position"""
            self.code_block = code_block
            self.position = position

        def __cmp__(self, other):
            comp = cmp(self.code_block, other.code_block)
            if comp:
                return comp
            return cmp(self.position, other.position)

        def cancel(self):
            """Cancel the cleanup code"""
            self.code_block.remove_cleanup_code(self)

        def get_position(self):
            "returns the cleanup code relative position"
            return self.position

    
    def __init__(self, error_return, predecessor=None):
        '''
           error_return -- code that is generated on error conditions
                           (detected by write_error_check()); normally
                           it returns from the wrapper function,
                           e.g. return NULL;
           predecessor -- optional predecessor code block; a
                          predecessor is used to search for additional
                          cleanup actions.

        >>> block = CodeBlock('return NULL;')
        >>> block.write_code("foo();")
        >>> cleanup1 = block.add_cleanup_code("clean1();")
        >>> cleanup2 = block.add_cleanup_code("clean2();")
        >>> cleanup3 = block.add_cleanup_code("clean3();")
        >>> cleanup2.cancel()
        >>> block.write_error_check("error()", "error_clean()")
        >>> block.write_code("bar();")
        >>> block.write_cleanup()
        >>> print block.sink.flush().rstrip()
        foo();
        if (error()) {
            error_clean()
            clean3();
            clean1();
            return NULL;
        }
        bar();
        clean3();
        clean1();
        '''
        self.sink = codesink.MemoryCodeSink()
        self.predecessor = predecessor
        self._cleanup_actions = {}
        self._last_cleanup_position = 0
        self.error_return = error_return
        
    def write_code(self, code):
        '''Write out some simple code'''
        self.sink.writeln(code)

    def add_cleanup_code(self, cleanup_code):
        '''Add a chunk of code used to cleanup previously allocated resources

        Returns a handle used to cancel the cleanup code
        '''
        self._last_cleanup_position += 1
        handle = self.CleanupHandle(self, self._last_cleanup_position)
        self._cleanup_actions[handle.get_position()] = cleanup_code
        return handle

    def remove_cleanup_code(self, handle):
        '''Remove cleanup code previously added with add_cleanup_code()
        '''
        assert isinstance(handle, self.CleanupHandle)
        del self._cleanup_actions[handle.get_position()]

    def get_cleanup_code(self):
        '''return a new list with all cleanup actions, including the
        ones from predecessor code blocks; Note: cleanup actions are
        executed in reverse order than when they were added.'''
        if self.predecessor is None:
            cleanup = []
        else:
            cleanup = self.predecessor.get_cleanup_code()
        items = self._cleanup_actions.items()
        items.sort()
        for dummy, code in items:<commit_msg>Add CodeBlock.indent/unindent methods (simple proxies to the code sink methods).<commit_after>## -*- python -*-
## pylint: disable-msg=W0142,R0921

"""
Base classes for all parameter/return type handlers,
and base interfaces for wrapper generators.
"""

import codesink


try:
    all
except NameError: # for compatibility with Python < 2.5
    def all(iterable):
        "Returns True if all elements are true"
        for element in iterable:
            if not element:
                return False
        return True

class CodeGenerationError(Exception):
    """Exception that is raised when wrapper generation fails for some reason."""


def join_ctype_and_name(ctype, name):
    """
    Utility method that joins a C type and a variable name into
    a single string

    >>> join_ctype_and_name('void*', 'foo')
    'void *foo'
    >>> join_ctype_and_name('void *', 'foo')
    'void *foo'
    >>> join_ctype_and_name("void**", "foo")
    'void **foo'
    >>> join_ctype_and_name("void **", "foo")
    'void **foo'
    """
    if ctype[-1] == '*':
        for i in range(-1, -len(ctype), -1):
            if ctype[i] != '*':
                if ctype[i] == ' ':
                    return "".join([ctype[:i+1], ctype[i+1:], name])
                else:
                    return "".join([ctype[:i+1], ' ', ctype[i+1:], name])
        raise ValueError
    else:
        return " ".join([ctype, name])


class CodeBlock(object):
    '''An intelligent code block that keeps track of cleanup actions.
    This object is to be used by TypeHandlers when generating code.'''

    class CleanupHandle(object):
        """Handle for some cleanup code"""
        __slots__ = ['code_block', 'position']
        def __init__(self, code_block, position):
            """Create a handle given code_block and position"""
            self.code_block = code_block
            self.position = position

        def __cmp__(self, other):
            comp = cmp(self.code_block, other.code_block)
            if comp:
                return comp
            return cmp(self.position, other.position)

        def cancel(self):
            """Cancel the cleanup code"""
            self.code_block.remove_cleanup_code(self)

        def get_position(self):
            "returns the cleanup code relative position"
            return self.position

    
    def __init__(self, error_return, predecessor=None):
        '''
           error_return -- code that is generated on error conditions
                           (detected by write_error_check()); normally
                           it returns from the wrapper function,
                           e.g. return NULL;
           predecessor -- optional predecessor code block; a
                          predecessor is used to search for additional
                          cleanup actions.

        >>> block = CodeBlock('return NULL;')
        >>> block.write_code("foo();")
        >>> cleanup1 = block.add_cleanup_code("clean1();")
        >>> cleanup2 = block.add_cleanup_code("clean2();")
        >>> cleanup3 = block.add_cleanup_code("clean3();")
        >>> cleanup2.cancel()
        >>> block.write_error_check("error()", "error_clean()")
        >>> block.write_code("bar();")
        >>> block.write_cleanup()
        >>> print block.sink.flush().rstrip()
        foo();
        if (error()) {
            error_clean()
            clean3();
            clean1();
            return NULL;
        }
        bar();
        clean3();
        clean1();
        '''
        self.sink = codesink.MemoryCodeSink()
        self.predecessor = predecessor
        self._cleanup_actions = {}
        self._last_cleanup_position = 0
        self.error_return = error_return
        
    def write_code(self, code):
        '''Write out some simple code'''
        self.sink.writeln(code)

    def indent(self, level=4):
        '''Add a certain ammount of indentation to all lines written
        from now on and until unindent() is called'''
        self.sink.indent(level)

    def unindent(self):
        '''Revert indentation level to the value before last indent() call'''
        self.sink.unindent()

    def add_cleanup_code(self, cleanup_code):
        '''Add a chunk of code used to cleanup previously allocated resources

        Returns a handle used to cancel the cleanup code
        '''
        self._last_cleanup_position += 1
        handle = self.CleanupHandle(self, self._last_cleanup_position)
        self._cleanup_actions[handle.get_position()] = cleanup_code
        return handle

    def remove_cleanup_code(self, handle):
        '''Remove cleanup code previously added with add_cleanup_code()
        '''
        assert isinstance(handle, self.CleanupHandle)
        del self._cleanup_actions[handle.get_position()]

    def get_cleanup_code(self):
        '''return a new list with all cleanup actions, including the
        ones from predecessor code blocks; Note: cleanup actions are
        executed in reverse order than when they were added.'''
        if self.predecessor is None:
            cleanup = []
        else:
            cleanup = self.predecessor.get_cleanup_code()
        items = self._cleanup_actions.items()
        items.sort()
        for dummy, code in items:
{'fraction_non_alphanumeric': 0.11153922149772773, 'fraction_numerical': 0.006026476980833828, 'mean_word_length': 2.1282447466007417, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 87, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '338016', 'n_tokens_mistral': 2750, 'n_tokens_neox': 2662, 'n_words': 801}