Lichen

Annotated lib/__builtins__/span.py

986:9ee9c9e18fa6
14 months ago Paul Boddie Introduced a dedicated method for statement nodes.
paul@6 1
#!/usr/bin/env python
paul@6 2
paul@6 3
"""
paul@6 4
Span-related objects.
paul@6 5
paul@907 6
Copyright (C) 2015, 2016, 2017, 2018, 2019 Paul Boddie <paul@boddie.org.uk>
paul@6 7
paul@6 8
This program is free software; you can redistribute it and/or modify it under
paul@6 9
the terms of the GNU General Public License as published by the Free Software
paul@6 10
Foundation; either version 3 of the License, or (at your option) any later
paul@6 11
version.
paul@6 12
paul@6 13
This program is distributed in the hope that it will be useful, but WITHOUT
paul@6 14
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
paul@6 15
FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
paul@6 16
details.
paul@6 17
paul@6 18
You should have received a copy of the GNU General Public License along with
paul@6 19
this program.  If not, see <http://www.gnu.org/licenses/>.
paul@6 20
"""
paul@6 21
paul@367 22
class slice:
paul@6 23
paul@367 24
    "Implementation of slice."
paul@6 25
paul@6 26
    NO_END = object()
paul@6 27
paul@367 28
    def __init__(self, start_or_end=None, end=NO_END, step=1):
paul@6 29
paul@367 30
        "Initialise the slice with the given 'start_or_end', 'end' and 'step'."
paul@6 31
paul@412 32
        if end is slice.NO_END:
paul@6 33
            self.start = 0
paul@6 34
            self.end = start_or_end
paul@6 35
        else:
paul@6 36
            self.start = start_or_end
paul@6 37
            self.end = end
paul@6 38
paul@367 39
        if step == 0:
paul@367 40
            raise ValueError(self.step)
paul@367 41
paul@6 42
        self.step = step
paul@294 43
paul@367 44
    def __str__(self):
paul@367 45
paul@367 46
        "Return a string representation."
paul@367 47
paul@808 48
        return "%s.%s(%r, %r, %r)" % (self.__parent__.__name__, self.__name__,
paul@808 49
                                      self.start,  self.end, self.step)
paul@367 50
paul@367 51
    __repr__ = __str__
paul@367 52
paul@367 53
class xrange(slice):
paul@367 54
paul@367 55
    "Implementation of xrange."
paul@367 56
paul@367 57
    def __init__(self, start_or_end, end=slice.NO_END, step=1):
paul@367 58
paul@367 59
        "Initialise the xrange with the given 'start_or_end', 'end' and 'step'."
paul@367 60
paul@367 61
        get_using(slice.__init__, self)(start_or_end, end, step)
paul@367 62
paul@294 63
        # Constrain the end according to the start and step.
paul@294 64
paul@294 65
        if step > 0:
paul@294 66
            self.end = _max(self.start, self.end)
paul@294 67
        elif step < 0:
paul@294 68
            self.end = _min(self.start, self.end)
paul@294 69
        else:
paul@294 70
            raise ValueError(self.step)
paul@294 71
paul@294 72
    def __len__(self):
paul@294 73
paul@294 74
        "Return the length of the range."
paul@294 75
paul@771 76
        n = (self.end - self.start) / self.step
paul@771 77
        last = self.start + (n * self.step)
paul@771 78
        if last == self.end:
paul@771 79
            return n
paul@771 80
        else:
paul@771 81
            return n + 1
paul@6 82
paul@6 83
    def __iter__(self):
paul@6 84
paul@6 85
        "Return an iterator, currently self."
paul@6 86
paul@691 87
        return xrangeiterator(self.start, self.step, self.__len__())
paul@369 88
paul@369 89
class xrangeiterator:
paul@369 90
paul@369 91
    "An iterator over an xrange."
paul@369 92
paul@821 93
    def __init__(self, start, .step, .count):
paul@369 94
paul@821 95
        "Initialise the iterator with the given 'start', 'step' and 'count'."
paul@369 96
paul@691 97
        self.current = start
paul@6 98
paul@6 99
    def next(self):
paul@6 100
paul@6 101
        "Return the next item or raise a StopIteration exception."
paul@6 102
paul@689 103
        if not self.count:
paul@907 104
            raise StopIteration, self
paul@6 105
paul@6 106
        current = self.current
paul@691 107
        self.current = self.current.__add__(self.step)
paul@691 108
        self.count = self.count.__sub__(1)
paul@6 109
        return current
paul@6 110
paul@294 111
def range(start_or_end, end=None, step=1):
paul@294 112
paul@294 113
    "Implementation of range."
paul@294 114
paul@294 115
    return list(xrange(start_or_end, end, step))
paul@294 116
paul@421 117
def _max(x, y):
paul@421 118
paul@421 119
    "Return the maximum of 'x' and 'y'."
paul@421 120
paul@421 121
    if x >= y:
paul@421 122
        return x
paul@421 123
    else:
paul@421 124
        return y
paul@421 125
paul@421 126
def _min(x, y):
paul@421 127
paul@421 128
    "Return the minimum of 'x' and 'y'."
paul@421 129
paul@421 130
    if x <= y:
paul@421 131
        return x
paul@421 132
    else:
paul@421 133
        return y
paul@421 134
paul@6 135
# vim: tabstop=4 expandtab shiftwidth=4