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 as is_, _is_not as is_not 26 27 def binary_op(a, b, left_accessor, right_accessor): 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 AttributeError: 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 AttributeError: 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. 61 62 raise TypeError 63 64 def unary_op(a, accessor): 65 66 """ 67 A single parameterised function providing the unary operator mechanism for 68 the argument 'a' using the given 'accessor' to provide the method for the 69 operand. 70 """ 71 72 # First, try and get a method for the argument, and then call it. 73 74 try: 75 fn = accessor(a) 76 except AttributeError: 77 pass 78 else: 79 result = fn() 80 if is_not(result, NotImplemented): 81 return result 82 83 # Where no method was available, or if the method could not support the 84 # operation, raise an exception. 85 86 raise TypeError 87 88 def augassign(a, b, augmented_accessor, left_accessor, right_accessor): 89 90 """ 91 A single parameterised function providing the augmented assignment mechanism 92 for arguments 'a' and 'b' either using 'augmented_accessor' (directly 93 affecting 'a') or using 'left_accessor' and 'right_accessor' (conventional 94 operator method accessors). 95 96 The result of the assignment is returned. 97 """ 98 99 # First, try and get a method that directly affects the assignment target. 100 101 try: 102 fn = augmented_accessor(a) 103 except AttributeError: 104 pass 105 else: 106 result = fn(b) 107 if is_not(result, NotImplemented): 108 return result 109 110 # Otherwise, attempt a conventional binary operation. 111 112 return binary_op(a, b, left_accessor, right_accessor) 113 114 # vim: tabstop=4 expandtab shiftwidth=4