Skip to content

Commit 110fc8a

Browse files
committed
Implement divmod and pow and check and fix interfaces for int, float, complex
1 parent c1b8923 commit 110fc8a

File tree

7 files changed

+339
-79
lines changed

7 files changed

+339
-79
lines changed

py/arithmetic.go

+81-11
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111

1212
// Add two python objects together returning an Object
1313
//
14-
// Will raise TypeError if can't be added
14+
// Will raise TypeError if can't be add can't be run on these objects
1515
func Add(a, b Object) Object {
1616
// Try using a to add
1717
A, ok := a.(I__add__)
@@ -51,7 +51,7 @@ func IAdd(a, b Object) Object {
5151

5252
// Sub two python objects together returning an Object
5353
//
54-
// Will raise TypeError if can't be subed
54+
// Will raise TypeError if can't be sub can't be run on these objects
5555
func Sub(a, b Object) Object {
5656
// Try using a to sub
5757
A, ok := a.(I__sub__)
@@ -91,7 +91,7 @@ func ISub(a, b Object) Object {
9191

9292
// Mul two python objects together returning an Object
9393
//
94-
// Will raise TypeError if can't be muled
94+
// Will raise TypeError if can't be mul can't be run on these objects
9595
func Mul(a, b Object) Object {
9696
// Try using a to mul
9797
A, ok := a.(I__mul__)
@@ -131,7 +131,7 @@ func IMul(a, b Object) Object {
131131

132132
// TrueDiv two python objects together returning an Object
133133
//
134-
// Will raise TypeError if can't be truedived
134+
// Will raise TypeError if can't be truediv can't be run on these objects
135135
func TrueDiv(a, b Object) Object {
136136
// Try using a to truediv
137137
A, ok := a.(I__truediv__)
@@ -171,7 +171,7 @@ func ITrueDiv(a, b Object) Object {
171171

172172
// FloorDiv two python objects together returning an Object
173173
//
174-
// Will raise TypeError if can't be floordived
174+
// Will raise TypeError if can't be floordiv can't be run on these objects
175175
func FloorDiv(a, b Object) Object {
176176
// Try using a to floordiv
177177
A, ok := a.(I__floordiv__)
@@ -211,7 +211,7 @@ func IFloorDiv(a, b Object) Object {
211211

212212
// Mod two python objects together returning an Object
213213
//
214-
// Will raise TypeError if can't be moded
214+
// Will raise TypeError if can't be mod can't be run on these objects
215215
func Mod(a, b Object) Object {
216216
// Try using a to mod
217217
A, ok := a.(I__mod__)
@@ -249,9 +249,37 @@ func IMod(a, b Object) Object {
249249
return Mod(a, b)
250250
}
251251

252+
// DivMod two python objects together returning an Object
253+
//
254+
// Will raise TypeError if can't be divmod can't be run on these objects
255+
func DivMod(a, b Object) (Object, Object) {
256+
// Try using a to divmod
257+
A, ok := a.(I__divmod__)
258+
if ok {
259+
res, res2 := A.M__divmod__(b)
260+
if res != NotImplemented {
261+
return res, res2
262+
}
263+
}
264+
265+
// Now using b to rdivmod if different in type to a
266+
if a.Type() != b.Type() {
267+
B, ok := b.(I__rdivmod__)
268+
if ok {
269+
res, res2 := B.M__rdivmod__(a)
270+
if res != NotImplemented {
271+
return res, res2
272+
}
273+
}
274+
}
275+
276+
// FIXME should be TypeError
277+
panic(fmt.Sprintf("TypeError: unsupported operand type(s) for divmod: '%s' and '%s'", a.Type().Name, b.Type().Name))
278+
}
279+
252280
// Lshift two python objects together returning an Object
253281
//
254-
// Will raise TypeError if can't be lshifted
282+
// Will raise TypeError if can't be lshift can't be run on these objects
255283
func Lshift(a, b Object) Object {
256284
// Try using a to lshift
257285
A, ok := a.(I__lshift__)
@@ -291,7 +319,7 @@ func ILshift(a, b Object) Object {
291319

292320
// Rshift two python objects together returning an Object
293321
//
294-
// Will raise TypeError if can't be rshifted
322+
// Will raise TypeError if can't be rshift can't be run on these objects
295323
func Rshift(a, b Object) Object {
296324
// Try using a to rshift
297325
A, ok := a.(I__rshift__)
@@ -331,7 +359,7 @@ func IRshift(a, b Object) Object {
331359

332360
// And two python objects together returning an Object
333361
//
334-
// Will raise TypeError if can't be anded
362+
// Will raise TypeError if can't be and can't be run on these objects
335363
func And(a, b Object) Object {
336364
// Try using a to and
337365
A, ok := a.(I__and__)
@@ -371,7 +399,7 @@ func IAnd(a, b Object) Object {
371399

372400
// Xor two python objects together returning an Object
373401
//
374-
// Will raise TypeError if can't be xored
402+
// Will raise TypeError if can't be xor can't be run on these objects
375403
func Xor(a, b Object) Object {
376404
// Try using a to xor
377405
A, ok := a.(I__xor__)
@@ -411,7 +439,7 @@ func IXor(a, b Object) Object {
411439

412440
// Or two python objects together returning an Object
413441
//
414-
// Will raise TypeError if can't be ored
442+
// Will raise TypeError if can't be or can't be run on these objects
415443
func Or(a, b Object) Object {
416444
// Try using a to or
417445
A, ok := a.(I__or__)
@@ -448,3 +476,45 @@ func IOr(a, b Object) Object {
448476
}
449477
return Or(a, b)
450478
}
479+
480+
// Pow three python objects together returning an Object
481+
//
482+
// If c != None then it won't attempt to call __rpow__
483+
//
484+
// Will raise TypeError if can't be pow can't be run on these objects
485+
func Pow(a, b, c Object) Object {
486+
// Try using a to pow
487+
A, ok := a.(I__pow__)
488+
if ok {
489+
res := A.M__pow__(b, c)
490+
if res != NotImplemented {
491+
return res
492+
}
493+
}
494+
495+
// Now using b to rpow if different in type to a
496+
if c == None && a.Type() != b.Type() {
497+
B, ok := b.(I__rpow__)
498+
if ok {
499+
res := B.M__rpow__(a)
500+
if res != NotImplemented {
501+
return res
502+
}
503+
}
504+
}
505+
506+
// FIXME should be TypeError
507+
panic(fmt.Sprintf("TypeError: unsupported operand type(s) for ** or pow(): '%s' and '%s'", a.Type().Name, b.Type().Name))
508+
}
509+
510+
// Inplace pow
511+
func IPow(a, b, c Object) Object {
512+
A, ok := a.(I__ipow__)
513+
if ok {
514+
res := A.M__ipow__(b, c)
515+
if res != NotImplemented {
516+
return res
517+
}
518+
}
519+
return Pow(a, b, c)
520+
}

py/complex.go

+49-8
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package py
44

55
import (
66
"math"
7+
"math/cmplx"
78
)
89

910
var ComplexType = NewType("complex64")
@@ -65,7 +66,7 @@ func (a Complex) M__rsub__(other Object) Object {
6566
return NotImplemented
6667
}
6768

68-
func (a Complex) M__isub(other Object) Object {
69+
func (a Complex) M__isub__(other Object) Object {
6970
return a.M__sub__(other)
7071
}
7172

@@ -98,7 +99,7 @@ func (a Complex) M__rtruediv__(other Object) Object {
9899
return NotImplemented
99100
}
100101

101-
func (a Complex) M__itruediv(other Object) Object {
102+
func (a Complex) M__itruediv__(other Object) Object {
102103
return Complex(a).M__truediv__(other)
103104
}
104105

@@ -128,31 +129,71 @@ func (a Complex) M__rfloordiv__(other Object) Object {
128129
return NotImplemented
129130
}
130131

131-
func (a Complex) M__ifloordiv(other Object) Object {
132+
func (a Complex) M__ifloordiv__(other Object) Object {
132133
return a.M__floordiv__(other)
133134
}
134135

135136
// Does Mod of two floating point numbers
136-
func complexMod(a, b Complex) Complex {
137+
func complexDivMod(a, b Complex) (Complex, Complex) {
137138
q := complexFloor(a / b)
138139
r := a - Complex(q)*b
139-
return Complex(r)
140+
return q, Complex(r)
140141
}
141142

142143
func (a Complex) M__mod__(other Object) Object {
143144
if b, ok := convertToComplex(other); ok {
144-
return complexMod(a, b)
145+
_, r := complexDivMod(a, b)
146+
return r
145147
}
146148
return NotImplemented
147149
}
148150

149151
func (a Complex) M__rmod__(other Object) Object {
150152
if b, ok := convertToComplex(other); ok {
151-
return complexMod(b, a)
153+
_, r := complexDivMod(b, a)
154+
return r
152155
}
153156
return NotImplemented
154157
}
155158

156-
func (a Complex) M__imod(other Object) Object {
159+
func (a Complex) M__imod__(other Object) Object {
157160
return a.M__mod__(other)
158161
}
162+
163+
func (a Complex) M__divmod__(other Object) (Object, Object) {
164+
if b, ok := convertToComplex(other); ok {
165+
return complexDivMod(a, b)
166+
}
167+
return NotImplemented, None
168+
}
169+
170+
func (a Complex) M__rdivmod__(other Object) (Object, Object) {
171+
if b, ok := convertToComplex(other); ok {
172+
return complexDivMod(b, a)
173+
}
174+
return NotImplemented, None
175+
}
176+
177+
func (a Complex) M__pow__(other, modulus Object) Object {
178+
if modulus != None {
179+
return NotImplemented
180+
}
181+
if b, ok := convertToComplex(other); ok {
182+
return Complex(cmplx.Pow(complex128(a), complex128(b)))
183+
}
184+
return NotImplemented
185+
}
186+
187+
func (a Complex) M__rpow__(other Object) Object {
188+
if b, ok := convertToComplex(other); ok {
189+
return Complex(cmplx.Pow(complex128(b), complex128(a)))
190+
}
191+
return NotImplemented
192+
}
193+
194+
func (a Complex) M__ipow__(other, modulus Object) Object {
195+
return a.M__pow__(other, modulus)
196+
}
197+
198+
// Check interface is satisfied
199+
var _ floatArithmetic = Complex(complex(0, 0))

py/float.go

+49-9
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func (a Float) M__rsub__(other Object) Object {
6565
return NotImplemented
6666
}
6767

68-
func (a Float) M__isub(other Object) Object {
68+
func (a Float) M__isub__(other Object) Object {
6969
return a.M__sub__(other)
7070
}
7171

@@ -98,7 +98,7 @@ func (a Float) M__rtruediv__(other Object) Object {
9898
return NotImplemented
9999
}
100100

101-
func (a Float) M__itruediv(other Object) Object {
101+
func (a Float) M__itruediv__(other Object) Object {
102102
return Float(a).M__truediv__(other)
103103
}
104104

@@ -116,31 +116,71 @@ func (a Float) M__rfloordiv__(other Object) Object {
116116
return NotImplemented
117117
}
118118

119-
func (a Float) M__ifloordiv(other Object) Object {
119+
func (a Float) M__ifloordiv__(other Object) Object {
120120
return a.M__floordiv__(other)
121121
}
122122

123-
// Does Mod of two floating point numbers
124-
func floatMod(a, b Float) Float {
123+
// Does DivMod of two floating point numbers
124+
func floatDivMod(a, b Float) (Float, Float) {
125125
q := Float(math.Floor(float64(a / b)))
126126
r := a - q*b
127-
return Float(r)
127+
return q, Float(r)
128128
}
129129

130130
func (a Float) M__mod__(other Object) Object {
131131
if b, ok := convertToFloat(other); ok {
132-
return floatMod(a, b)
132+
_, r := floatDivMod(a, b)
133+
return r
133134
}
134135
return NotImplemented
135136
}
136137

137138
func (a Float) M__rmod__(other Object) Object {
138139
if b, ok := convertToFloat(other); ok {
139-
return floatMod(b, a)
140+
_, r := floatDivMod(b, a)
141+
return r
140142
}
141143
return NotImplemented
142144
}
143145

144-
func (a Float) M__imod(other Object) Object {
146+
func (a Float) M__imod__(other Object) Object {
145147
return a.M__mod__(other)
146148
}
149+
150+
func (a Float) M__divmod__(other Object) (Object, Object) {
151+
if b, ok := convertToFloat(other); ok {
152+
return floatDivMod(a, b)
153+
}
154+
return NotImplemented, None
155+
}
156+
157+
func (a Float) M__rdivmod__(other Object) (Object, Object) {
158+
if b, ok := convertToFloat(other); ok {
159+
return floatDivMod(b, a)
160+
}
161+
return NotImplemented, None
162+
}
163+
164+
func (a Float) M__pow__(other, modulus Object) Object {
165+
if modulus != None {
166+
return NotImplemented
167+
}
168+
if b, ok := convertToFloat(other); ok {
169+
return Float(math.Pow(float64(a), float64(b)))
170+
}
171+
return NotImplemented
172+
}
173+
174+
func (a Float) M__rpow__(other Object) Object {
175+
if b, ok := convertToFloat(other); ok {
176+
return Float(math.Pow(float64(b), float64(a)))
177+
}
178+
return NotImplemented
179+
}
180+
181+
func (a Float) M__ipow__(other, modulus Object) Object {
182+
return a.M__pow__(other, modulus)
183+
}
184+
185+
// Check interface is satisfied
186+
var _ floatArithmetic = Float(0)

0 commit comments

Comments
 (0)