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