micropython

lib/operator.py

506:d5f5db3d3636
2012-05-18 Paul Boddie Added support for the inspection and generation of list comprehensions. Moved various common code generation routines into separate methods and adjusted the list and sequence population methods for wider re-use.
     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