Lichen

Annotated lib/operator/core.py

476:7153e60d49b9
2017-01-19 Paul Boddie Added simple import and __file__ attribute test.
paul@6 1
#!/usr/bin/env python
paul@6 2
paul@6 3
"""
paul@6 4
Operator support.
paul@6 5
paul@6 6
Copyright (C) 2010, 2013, 2015, 2016 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@6 22
# Define "is" and "is not" in terms of native operations. They are imported by
paul@6 23
# the operator.binary module.
paul@6 24
paul@354 25
from native import is_, is_not
paul@6 26
paul@278 27
def binary_op(a, b, left_accessor, right_accessor, default=None):
paul@6 28
paul@6 29
    """
paul@6 30
    A single parameterised function providing the binary operator mechanism for
paul@6 31
    arguments 'a' and 'b' using accessors given as 'left_accessor' and
paul@6 32
    'right_accessor' which provide the methods for the operands.
paul@6 33
    """
paul@6 34
paul@6 35
    # First, try and get a method for the left argument, and then call it with
paul@6 36
    # the right argument.
paul@6 37
paul@6 38
    try:
paul@6 39
        fn = left_accessor(a)
paul@364 40
    except TypeError:
paul@6 41
        pass
paul@6 42
    else:
paul@6 43
        result = fn(b)
paul@6 44
        if is_not(result, NotImplemented):
paul@6 45
            return result
paul@6 46
paul@6 47
    # Otherwise, try and get a method for the right argument, and then call it
paul@6 48
    # with the left argument.
paul@6 49
paul@6 50
    try:
paul@6 51
        fn = right_accessor(b)
paul@364 52
    except TypeError:
paul@6 53
        pass
paul@6 54
    else:
paul@6 55
        result = fn(a)
paul@6 56
        if is_not(result, NotImplemented):
paul@6 57
            return result
paul@6 58
paul@6 59
    # Where no methods were available, or if neither method could support the
paul@278 60
    # operation, raise an exception or provide a default result.
paul@6 61
paul@278 62
    if default is None:
paul@278 63
        raise TypeError
paul@278 64
    else:
paul@278 65
        return default
paul@6 66
paul@278 67
def unary_op(a, accessor, default=None):
paul@6 68
paul@6 69
    """
paul@6 70
    A single parameterised function providing the unary operator mechanism for
paul@6 71
    the argument 'a' using the given 'accessor' to provide the method for the
paul@6 72
    operand.
paul@6 73
    """
paul@6 74
paul@6 75
    # First, try and get a method for the argument, and then call it.
paul@6 76
paul@6 77
    try:
paul@6 78
        fn = accessor(a)
paul@364 79
    except TypeError:
paul@6 80
        pass
paul@6 81
    else:
paul@6 82
        result = fn()
paul@6 83
        if is_not(result, NotImplemented):
paul@6 84
            return result
paul@6 85
paul@6 86
    # Where no method was available, or if the method could not support the
paul@278 87
    # operation, raise an exception or provide a default result.
paul@6 88
paul@278 89
    if default is None:
paul@278 90
        raise TypeError
paul@278 91
    else:
paul@278 92
        return default
paul@6 93
paul@6 94
def augassign(a, b, augmented_accessor, left_accessor, right_accessor):
paul@6 95
paul@6 96
    """
paul@6 97
    A single parameterised function providing the augmented assignment mechanism
paul@6 98
    for arguments 'a' and 'b' either using 'augmented_accessor' (directly
paul@6 99
    affecting 'a') or using 'left_accessor' and 'right_accessor' (conventional
paul@6 100
    operator method accessors).
paul@6 101
paul@6 102
    The result of the assignment is returned.
paul@6 103
    """
paul@6 104
paul@6 105
    # First, try and get a method that directly affects the assignment target.
paul@6 106
paul@6 107
    try:
paul@6 108
        fn = augmented_accessor(a)
paul@364 109
    except TypeError:
paul@6 110
        pass
paul@6 111
    else:
paul@6 112
        result = fn(b)
paul@6 113
        if is_not(result, NotImplemented):
paul@6 114
            return result
paul@6 115
paul@6 116
    # Otherwise, attempt a conventional binary operation.
paul@6 117
paul@6 118
    return binary_op(a, b, left_accessor, right_accessor)
paul@6 119
paul@6 120
# vim: tabstop=4 expandtab shiftwidth=4