micropython

lib/operator.py

443:583b1de09eec
2011-07-05 Paul Boddie Simplified ObjectSet merging which seemed to be attempting to combine individual values.
     1 #!/usr/bin/env python     2      3 """     4 Operator support.     5      6 Copyright (C) 2010 Paul Boddie <paul@boddie.org.uk>     7      8 This program is free software; you can redistribute it and/or modify it under     9 the terms of the GNU General Public License as published by the Free Software    10 Foundation; either version 3 of the License, or (at your option) any later    11 version.    12     13 This program is distributed in the hope that it will be useful, but WITHOUT    14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS    15 FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more    16 details.    17     18 You should have received a copy of the GNU General Public License along with    19 this program.  If not, see <http://www.gnu.org/licenses/>.    20 """    21     22 def binary_op(a, b, left_accessor, right_accessor):    23     24     """    25     A single parameterised function providing the binary operator mechanism for    26     arguments 'a' and 'b' using accessors given as 'left_accessor' and    27     'right_accessor' which provide the methods for the operands.    28     """    29     30     # First, try and get a method for the left argument, and then call it with    31     # the right argument.    32     33     try:    34         fn = left_accessor(a)    35     except AttributeError:    36         pass    37     else:    38         result = fn(b)    39         if result is not NotImplemented:    40             return result    41     42     # Otherwise, try and get a method for the right argument, and then call it    43     # with the left argument.    44     45     try:    46         fn = right_accessor(b)    47     except AttributeError:    48         pass    49     else:    50         result = fn(a)    51         if result is not NotImplemented:    52             return result    53     54     # Where no methods were available, or if neither method could support the    55     # operation, raise an exception.    56     57     raise TypeError    58     59 def unary_op(a, accessor):    60     61     """    62     A single parameterised function providing the unary operator mechanism for    63     the argument 'a' using the given 'accessor' to provide the method for the    64     operand.    65     """    66     67     # First, try and get a method for the argument, and then call it.    68     69     try:    70         fn = accessor(a)    71     except AttributeError:    72         pass    73     else:    74         result = fn()    75         if result is not NotImplemented:    76             return result    77     78     # Where no method was available, or if the method could not support the    79     # operation, raise an exception.    80     81     raise TypeError    82     83 def augassign(a, b, augmented_accessor, left_accessor, right_accessor):    84     85     """    86     A single parameterised function providing the augmented assignment mechanism    87     for arguments 'a' and 'b' either using 'augmented_accessor' (directly    88     affecting 'a') or using 'left_accessor' and 'right_accessor' (conventional    89     operator method accessors).    90     91     The result of the assignment is returned.    92     """    93     94     # First, try and get a method that directly affects the assignment target.    95     96     try:    97         fn = augmented_accessor(a)    98     except AttributeError:    99         pass   100     else:   101         result = fn(b)   102         if result is not NotImplemented:   103             return result   104    105     # Otherwise, attempt a conventional binary operation.   106    107     return binary_op(a, b, left_accessor, right_accessor)   108    109 # These functions defer method lookup by wrapping the attribute access in   110 # lambda functions. Thus, the appropriate methods are defined locally, but no   111 # attempt to obtain them is made until the generic function is called.   112    113 # NOTE: The compiler should make it possible for the following functions to call   114 # NOTE: the generic operator implementations with no additional call overhead.   115    116 # Binary operator functions.   117    118 def add(a, b):   119     return binary_op(a, b, lambda a: a.__add__, lambda b: b.__radd__)   120    121 def and_(a, b):   122     return binary_op(a, b, lambda a: a.__and__, lambda b: b.__rand__)   123    124 def div(a, b):   125     return binary_op(a, b, lambda a: a.__div__, lambda b: b.__rdiv__)   126    127 def floordiv(a, b):   128     return binary_op(a, b, lambda a: a.__floordiv__, lambda b: b.__rfloordiv__)   129    130 def lshift(a, b):   131     return binary_op(a, b, lambda a: a.__lshift__, lambda b: b.__rlshift__)   132    133 def mod(a, b):   134     return binary_op(a, b, lambda a: a.__mod__, lambda b: b.__rmod__)   135    136 def mul(a, b):   137     return binary_op(a, b, lambda a: a.__mul__, lambda b: b.__rmul__)   138    139 def or_(a, b):   140     return binary_op(a, b, lambda a: a.__or__, lambda b: b.__ror__)   141    142 def pow(a, b):   143     return binary_op(a, b, lambda a: a.__pow__, lambda b: b.__rpow__)   144    145 def rshift(a, b):   146     return binary_op(a, b, lambda a: a.__rshift__, lambda b: b.__rrshift__)   147    148 def sub(a, b):   149     return binary_op(a, b, lambda a: a.__sub__, lambda b: b.__rsub__)   150    151 def xor(a, b):   152     return binary_op(a, b, lambda a: a.__xor__, lambda b: b.__rxor__)   153    154 # Unary operator functions.   155    156 def invert(a):   157     return unary_op(a, lambda a: a.__invert__)   158    159 def neg(a):   160     return unary_op(a, lambda a: a.__neg__)   161    162 def pos(a):   163     return unary_op(a, lambda a: a.__pos__)   164    165 # Augmented assignment functions.   166    167 def iadd(a, b):   168     return augassign(a, b, lambda a: a.__iadd__, lambda a: a.__add__, lambda b: b.__radd__)   169    170 def iand_(a, b):   171     return augassign(a, b, lambda a: a.__iand__, lambda a: a.__and__, lambda b: b.__rand__)   172    173 def idiv(a, b):   174     return augassign(a, b, lambda a: a.__idiv__, lambda a: a.__div__, lambda b: b.__rdiv__)   175    176 def ifloordiv(a, b):   177     return augassign(a, b, lambda a: a.__ifloordiv__, lambda a: a.__floordiv__, lambda b: b.__rfloordiv__)   178    179 def ilshift(a, b):   180     return augassign(a, b, lambda a: a.__ilshift__, lambda a: a.__lshift__, lambda b: b.__rlshift__)   181    182 def imod(a, b):   183     return augassign(a, b, lambda a: a.__imod__, lambda a: a.__mod__, lambda b: b.__rmod__)   184    185 def imul(a, b):   186     return augassign(a, b, lambda a: a.__imul__, lambda a: a.__mul__, lambda b: b.__rmul__)   187    188 def ior_(a, b):   189     return augassign(a, b, lambda a: a.__ior__, lambda a: a.__or__, lambda b: b.__ror__)   190    191 def ipow(a, b):   192     return augassign(a, b, lambda a: a.__ipow__, lambda a: a.__pow__, lambda b: b.__rpow__)   193    194 def irshift(a, b):   195     return augassign(a, b, lambda a: a.__irshift__, lambda a: a.__rshift__, lambda b: b.__rrshift__)   196    197 def isub(a, b):   198     return augassign(a, b, lambda a: a.__isub__, lambda a: a.__sub__, lambda b: b.__rsub__)   199    200 def ixor(a, b):   201     return augassign(a, b, lambda a: a.__ixor__, lambda a: a.__xor__, lambda b: b.__rxor__)   202    203 # Comparison functions.   204    205 def eq(a, b):   206     return binary_op(a, b, lambda a: a.__eq__, lambda b: b.__eq__)   207    208 def ge(a, b):   209     return binary_op(a, b, lambda a: a.__ge__, lambda b: b.__le__)   210    211 def gt(a, b):   212     return binary_op(a, b, lambda a: a.__gt__, lambda b: b.__lt__)   213    214 def le(a, b):   215     return binary_op(a, b, lambda a: a.__le__, lambda b: b.__ge__)   216    217 def lt(a, b):   218     return binary_op(a, b, lambda a: a.__lt__, lambda b: b.__gt__)   219    220 def ne(a, b):   221     return binary_op(a, b, lambda a: a.__ne__, lambda b: b.__ne__)   222    223 # Access and slicing functions.   224    225 def getitem(a, b):   226     return a.__getitem__(b)   227    228 def setitem(a, b, c):   229     a.__setitem__(b, c)   230    231 # NOTE: Should be able to optimise temporary instance allocations for slices.   232    233 def getslice(a, b, c):   234     return a.__getitem__(slice(b, c))   235    236 def setslice(a, b, c, d):   237     a.__setitem__(slice(b, c), d)   238    239 # vim: tabstop=4 expandtab shiftwidth=4