Skip to content

Commit 64c73d3

Browse files
committed
If statements and rich comparisons
* Fast path for MakeXXX - most likely it is already an XXX * Add rich comparisons * Factor not to py.Not * Implement JUMP_FORWARD, POP_JUMP_IF_*
1 parent e552306 commit 64c73d3

File tree

10 files changed

+525
-126
lines changed

10 files changed

+525
-126
lines changed

py/arithmetic.go

+220-90
Large diffs are not rendered by default.

py/bool.go

+7
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,10 @@ var (
1515
func (s Bool) Type() *Type {
1616
return BoolType
1717
}
18+
19+
func (a Bool) M__bool__() Object {
20+
return a
21+
}
22+
23+
// Check interface is satisfied
24+
var _ I__bool__ = Bool(false)

py/complex.go

+46
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package py
44

55
import (
6+
"fmt"
67
"math"
78
"math/cmplx"
89
)
@@ -207,5 +208,50 @@ func (a Complex) M__ipow__(other, modulus Object) Object {
207208
return a.M__pow__(other, modulus)
208209
}
209210

211+
// Rich comparison
212+
213+
func (a Complex) M__lt__(other Object) Object {
214+
if _, ok := convertToComplex(other); ok {
215+
// FIXME type error
216+
panic(fmt.Sprintf("TypeError: no ordering relation is defined for complex numbers"))
217+
}
218+
return NotImplemented
219+
}
220+
221+
func (a Complex) M__le__(other Object) Object {
222+
return a.M__lt__(other)
223+
}
224+
225+
func (a Complex) M__eq__(other Object) Object {
226+
if b, ok := convertToComplex(other); ok {
227+
if a == b {
228+
return True
229+
} else {
230+
return False
231+
}
232+
}
233+
return NotImplemented
234+
}
235+
236+
func (a Complex) M__ne__(other Object) Object {
237+
if b, ok := convertToComplex(other); ok {
238+
if a != b {
239+
return True
240+
} else {
241+
return False
242+
}
243+
}
244+
return NotImplemented
245+
}
246+
247+
func (a Complex) M__gt__(other Object) Object {
248+
return a.M__lt__(other)
249+
}
250+
251+
func (a Complex) M__ge__(other Object) Object {
252+
return a.M__lt__(other)
253+
}
254+
210255
// Check interface is satisfied
211256
var _ floatArithmetic = Complex(complex(0, 0))
257+
var _ richComparison = Complex(0)

py/float.go

+71-2
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,76 @@ func (a Float) M__round__(digitsObj Object) Object {
225225
return scale * Float(math.Floor(float64(a)/float64(scale)))
226226
}
227227

228+
// Rich comparison
229+
230+
func (a Float) M__lt__(other Object) Object {
231+
if b, ok := convertToFloat(other); ok {
232+
if a < b {
233+
return True
234+
} else {
235+
return False
236+
}
237+
}
238+
return NotImplemented
239+
}
240+
241+
func (a Float) M__le__(other Object) Object {
242+
if b, ok := convertToFloat(other); ok {
243+
if a <= b {
244+
return True
245+
} else {
246+
return False
247+
}
248+
}
249+
return NotImplemented
250+
}
251+
252+
func (a Float) M__eq__(other Object) Object {
253+
if b, ok := convertToFloat(other); ok {
254+
if a == b {
255+
return True
256+
} else {
257+
return False
258+
}
259+
}
260+
return NotImplemented
261+
}
262+
263+
func (a Float) M__ne__(other Object) Object {
264+
if b, ok := convertToFloat(other); ok {
265+
if a != b {
266+
return True
267+
} else {
268+
return False
269+
}
270+
}
271+
return NotImplemented
272+
}
273+
274+
func (a Float) M__gt__(other Object) Object {
275+
if b, ok := convertToFloat(other); ok {
276+
if a > b {
277+
return True
278+
} else {
279+
return False
280+
}
281+
}
282+
return NotImplemented
283+
}
284+
285+
func (a Float) M__ge__(other Object) Object {
286+
if b, ok := convertToFloat(other); ok {
287+
if a >= b {
288+
return True
289+
} else {
290+
return False
291+
}
292+
}
293+
return NotImplemented
294+
}
295+
228296
// Check interface is satisfied
229297
var _ floatArithmetic = Float(0)
230-
var _ conversionBetweenTypes = Int(0)
231-
var _ I__bool__ = Int(0)
298+
var _ conversionBetweenTypes = Float(0)
299+
var _ I__bool__ = Float(0)
300+
var _ richComparison = Float(0)

py/frame.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ type Frame struct {
4141
Gen Object
4242

4343
// FIXME Tstate *PyThreadState
44-
Lasti int // Last instruction if called
44+
Lasti int32 // Last instruction if called
4545
// Call PyFrame_GetLineNumber() instead of reading this field
4646
// directly. As of 2.3 f_lineno is only valid when tracing is
4747
// active (i.e. when f_trace is set). At other times we use

py/gen.go

+53-14
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,14 @@ type Ops []struct {
2121
Binary bool
2222
Ternary bool
2323
NoInplace bool
24+
Opposite string
25+
Conversion string
2426
}
2527

2628
type Data struct {
27-
UnaryOps Ops
28-
BinaryOps Ops
29-
TernaryOps Ops
29+
UnaryOps Ops
30+
BinaryOps Ops
31+
ComparisonOps Ops
3032
}
3133

3234
var data = Data{
@@ -35,9 +37,9 @@ var data = Data{
3537
{Name: "pos", Title: "Pos", Operator: "+", Unary: true},
3638
{Name: "abs", Title: "Abs", Operator: "abs", Unary: true},
3739
{Name: "invert", Title: "Invert", Operator: "~", Unary: true},
38-
{Name: "complex", Title: "MakeComplex", Operator: "complex", Unary: true},
39-
{Name: "int", Title: "MakeInt", Operator: "int", Unary: true},
40-
{Name: "float", Title: "MakeFloat", Operator: "float", Unary: true},
40+
{Name: "complex", Title: "MakeComplex", Operator: "complex", Unary: true, Conversion: "Complex"},
41+
{Name: "int", Title: "MakeInt", Operator: "int", Unary: true, Conversion: "Int"},
42+
{Name: "float", Title: "MakeFloat", Operator: "float", Unary: true, Conversion: "Float"},
4143
},
4244
BinaryOps: Ops{
4345
{Name: "add", Title: "Add", Operator: "+", Binary: true},
@@ -54,6 +56,14 @@ var data = Data{
5456
{Name: "or", Title: "Or", Operator: "|", Binary: true},
5557
{Name: "pow", Title: "Pow", Operator: "** or pow()", Ternary: true},
5658
},
59+
ComparisonOps: Ops{
60+
{Name: "gt", Title: "Gt", Operator: ">", Opposite: "le"},
61+
{Name: "ge", Title: "Ge", Operator: ">=", Opposite: "lt"},
62+
{Name: "lt", Title: "Lt", Operator: "<", Opposite: "ge"},
63+
{Name: "le", Title: "Le", Operator: "<=", Opposite: "gt"},
64+
{Name: "eq", Title: "Eq", Operator: "==", Opposite: "ne"},
65+
{Name: "ne", Title: "Ne", Operator: "!=", Opposite: "eq"},
66+
},
5767
}
5868

5969
func main() {
@@ -80,8 +90,12 @@ import (
8090
//
8191
// Will raise TypeError if {{.Title}} can't be run on this object
8292
func {{.Title}}(a Object) Object {
83-
A, ok := a.(I__{{.Name}}__)
84-
if ok {
93+
{{ if .Conversion }}
94+
if _, ok := a.({{.Conversion}}); ok {
95+
return a
96+
}
97+
{{end}}
98+
if A, ok := a.(I__{{.Name}}__); ok {
8599
res := A.M__{{.Name}}__()
86100
if res != NotImplemented {
87101
return res
@@ -101,8 +115,7 @@ func {{.Title}}(a Object) Object {
101115
// Will raise TypeError if can't be {{.Name}} can't be run on these objects
102116
func {{.Title}}(a, b {{ if .Ternary }}, c{{ end }} Object) (Object {{ if .TwoReturnParameters}}, Object{{ end }}) {
103117
// Try using a to {{.Name}}
104-
A, ok := a.(I__{{.Name}}__)
105-
if ok {
118+
if A, ok := a.(I__{{.Name}}__); ok {
106119
res {{ if .TwoReturnParameters}}, res2{{ end }} := A.M__{{.Name}}__(b {{ if .Ternary }}, c{{ end }})
107120
if res != NotImplemented {
108121
return res {{ if .TwoReturnParameters }}, res2{{ end }}
@@ -111,8 +124,7 @@ func {{.Title}}(a, b {{ if .Ternary }}, c{{ end }} Object) (Object {{ if .TwoRet
111124
112125
// Now using b to r{{.Name}} if different in type to a
113126
if {{ if .Ternary }} c == None && {{ end }} a.Type() != b.Type() {
114-
B, ok := b.(I__r{{.Name}}__)
115-
if ok {
127+
if B, ok := b.(I__r{{.Name}}__); ok {
116128
res {{ if .TwoReturnParameters}}, res2 {{ end }} := B.M__r{{.Name}}__(a)
117129
if res != NotImplemented {
118130
return res{{ if .TwoReturnParameters}}, res2{{ end }}
@@ -127,8 +139,7 @@ func {{.Title}}(a, b {{ if .Ternary }}, c{{ end }} Object) (Object {{ if .TwoRet
127139
{{ if not .NoInplace }}
128140
// Inplace {{.Name}}
129141
func I{{.Title}}(a, b {{ if .Ternary }}, c{{ end }} Object) Object {
130-
A, ok := a.(I__i{{.Name}}__)
131-
if ok {
142+
if A, ok := a.(I__i{{.Name}}__); ok {
132143
res := A.M__i{{.Name}}__(b {{ if .Ternary }}, c{{ end }})
133144
if res != NotImplemented {
134145
return res
@@ -138,4 +149,32 @@ func I{{.Title}}(a, b {{ if .Ternary }}, c{{ end }} Object) Object {
138149
}
139150
{{end}}
140151
{{end}}
152+
153+
{{ range .ComparisonOps }}
154+
// {{.Title}} two python objects returning a boolean result
155+
//
156+
// Will raise TypeError if {{.Title}} can't be run on this object
157+
func {{.Title}}(a Object, b Object) Object {
158+
// Try using a to {{.Name}}
159+
if A, ok := a.(I__{{.Name}}__); ok {
160+
res := A.M__{{.Name}}__(b)
161+
if res != NotImplemented {
162+
return res
163+
}
164+
}
165+
166+
// Try using b to {{.Opposite}} with reversed parameters
167+
if B, ok := a.(I__{{.Opposite}}__); ok {
168+
res := B.M__{{.Opposite}}__(b)
169+
if res == True {
170+
return False
171+
} else if res == False {
172+
return True
173+
}
174+
}
175+
176+
// FIXME should be TypeError
177+
panic(fmt.Sprintf("TypeError: unsupported operand type(s) for {{.Operator}}: '%s' and '%s'", a.Type().Name, b.Type().Name))
178+
}
179+
{{ end }}
141180
`

py/int.go

+69
Original file line numberDiff line numberDiff line change
@@ -333,9 +333,78 @@ func (a Int) M__round__(digits Object) Object {
333333
return Int(Float(a).M__round__(digits).(Float))
334334
}
335335

336+
// Rich comparison
337+
338+
func (a Int) M__lt__(other Object) Object {
339+
if b, ok := convertToInt(other); ok {
340+
if a < b {
341+
return True
342+
} else {
343+
return False
344+
}
345+
}
346+
return NotImplemented
347+
}
348+
349+
func (a Int) M__le__(other Object) Object {
350+
if b, ok := convertToInt(other); ok {
351+
if a <= b {
352+
return True
353+
} else {
354+
return False
355+
}
356+
}
357+
return NotImplemented
358+
}
359+
360+
func (a Int) M__eq__(other Object) Object {
361+
if b, ok := convertToInt(other); ok {
362+
if a == b {
363+
return True
364+
} else {
365+
return False
366+
}
367+
}
368+
return NotImplemented
369+
}
370+
371+
func (a Int) M__ne__(other Object) Object {
372+
if b, ok := convertToInt(other); ok {
373+
if a != b {
374+
return True
375+
} else {
376+
return False
377+
}
378+
}
379+
return NotImplemented
380+
}
381+
382+
func (a Int) M__gt__(other Object) Object {
383+
if b, ok := convertToInt(other); ok {
384+
if a > b {
385+
return True
386+
} else {
387+
return False
388+
}
389+
}
390+
return NotImplemented
391+
}
392+
393+
func (a Int) M__ge__(other Object) Object {
394+
if b, ok := convertToInt(other); ok {
395+
if a >= b {
396+
return True
397+
} else {
398+
return False
399+
}
400+
}
401+
return NotImplemented
402+
}
403+
336404
// Check interface is satisfied
337405
var _ floatArithmetic = Int(0)
338406
var _ booleanArithmetic = Int(0)
339407
var _ conversionBetweenTypes = Int(0)
340408
var _ I__bool__ = Int(0)
341409
var _ I__index__ = Int(0)
410+
var _ richComparison = Int(0)

py/internal.go

+17-4
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,18 @@ import (
1515
// neither __len__() nor __bool__(), all its instances are considered
1616
// true.
1717
func MakeBool(a Object) Object {
18-
A, ok := a.(I__bool__)
19-
if ok {
18+
if _, ok := a.(Bool); ok {
19+
return a
20+
}
21+
22+
if A, ok := a.(I__bool__); ok {
2023
res := A.M__bool__()
2124
if res != NotImplemented {
2225
return res
2326
}
2427
}
2528

26-
B, ok := a.(I__len__)
27-
if ok {
29+
if B, ok := a.(I__len__); ok {
2830
res := B.M__len__()
2931
if res != NotImplemented {
3032
return MakeBool(res)
@@ -46,3 +48,14 @@ func Index(a Object) int {
4648
// FIXME should be TypeError
4749
panic(fmt.Sprintf("TypeError: unsupported operand type(s) for index: '%s'", a.Type().Name))
4850
}
51+
52+
// Return the result of not a
53+
func Not(a Object) Object {
54+
switch MakeBool(a) {
55+
case False:
56+
return True
57+
case True:
58+
return False
59+
}
60+
panic("bool() didn't return True or False")
61+
}

0 commit comments

Comments
 (0)