Skip to content

Commit b9545a4

Browse files
committed
py: type - fix initialisation and repr
1 parent eb7e8f3 commit b9545a4

File tree

3 files changed

+101
-7
lines changed

3 files changed

+101
-7
lines changed

py/internal.go

+13
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,19 @@ func Repr(self Object) (Object, error) {
349349
return String(fmt.Sprintf("<%s instance at %p>", self.Type().Name, self)), nil
350350
}
351351

352+
// DebugRepr - see Repr but returns the repr or error as a string
353+
func DebugRepr(self Object) string {
354+
res, err := Repr(self)
355+
if err != nil {
356+
return fmt.Sprintf("Repr(%s) returned %v", self.Type().Name, err)
357+
}
358+
str, ok := res.(String)
359+
if !ok {
360+
return fmt.Sprintf("Repr(%s) didn't return a string", self.Type().Name)
361+
}
362+
return string(str)
363+
}
364+
352365
// Calls __str__ on the object and if not found calls __repr__
353366
func Str(self Object) (Object, error) {
354367
if I, ok := self.(I__str__); ok {

py/type.go

+62-7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
// and using the cache clearing machinery to clear the caches when the
55
// heirachy changes
66

7+
// FIXME should make Mro and Bases be []*Type
8+
79
package py
810

911
import (
@@ -187,7 +189,7 @@ var ObjectType = &Type{
187189
}
188190

189191
func init() {
190-
// Initialises like this to avoid initialisation loops
192+
// Initialised like this to avoid initialisation loops
191193
TypeType.New = TypeNew
192194
TypeType.Init = TypeInit
193195
TypeType.ObjectType = TypeType
@@ -219,6 +221,35 @@ func (t *Type) GetDict() StringDict {
219221
return t.Dict
220222
}
221223

224+
// delayedReady holds types waiting to be intialised
225+
var delayedReady = []*Type{}
226+
227+
// TypeDelayReady stores the list of types to initialise
228+
//
229+
// Call MakeReady when all initialised
230+
func TypeDelayReady(t *Type) {
231+
delayedReady = append(delayedReady, t)
232+
}
233+
234+
// TypeMakeReady readies all the types
235+
func TypeMakeReady() (err error) {
236+
for _, t := range delayedReady {
237+
err = t.Ready()
238+
if err != nil {
239+
return fmt.Errorf("Error initialising go type %s: %v", t.Name, err)
240+
}
241+
}
242+
delayedReady = nil
243+
return nil
244+
}
245+
246+
func init() {
247+
err := TypeMakeReady()
248+
if err != nil {
249+
log.Fatal(err)
250+
}
251+
}
252+
222253
// Make a new type from a name
223254
//
224255
// For making Go types
@@ -229,7 +260,7 @@ func NewType(Name string, Doc string) *Type {
229260
Doc: Doc,
230261
Dict: StringDict{},
231262
}
232-
//t.Ready()
263+
TypeDelayReady(t)
233264
return t
234265
}
235266

@@ -245,7 +276,7 @@ func NewTypeX(Name string, Doc string, New NewFunc, Init InitFunc) *Type {
245276
Init: Init,
246277
Dict: StringDict{},
247278
}
248-
//t.Ready()
279+
TypeDelayReady(t)
249280
return t
250281
}
251282

@@ -269,8 +300,9 @@ func (t *Type) NewTypeFlags(Name string, Doc string, New NewFunc, Init InitFunc,
269300
Init: Init,
270301
Flags: Flags,
271302
Dict: StringDict{},
303+
Bases: Tuple{t},
272304
}
273-
//tt.Ready()
305+
TypeDelayReady(t)
274306
return tt
275307
}
276308

@@ -307,12 +339,14 @@ func (metatype *Type) CalculateMetaclass(bases Tuple) (*Type, error) {
307339
}
308340

309341
// type test with subclassing support
342+
// reads a IsSubtype of b
310343
func (a *Type) IsSubtype(b *Type) bool {
311344
mro := a.Mro
312-
if mro != nil {
345+
if len(mro) != 0 {
313346
// Deal with multiple inheritance without recursion
314347
// by walking the MRO tuple
315-
for _, base := range mro {
348+
for _, baseObj := range mro {
349+
base := baseObj.(*Type)
316350
if base == b {
317351
return true
318352
}
@@ -939,7 +973,7 @@ func remove_subclass(base, t *Type) {
939973

940974
// Ready the type for use
941975
//
942-
// Raises an exception on problems
976+
// Returns an error on problems
943977
func (t *Type) Ready() error {
944978
// PyObject *dict, *bases;
945979
// PyTypeObject *base;
@@ -1699,7 +1733,28 @@ func (ty *Type) M__ne__(other Object) (Object, error) {
16991733
return True, nil
17001734
}
17011735

1736+
func (ty *Type) M__str__() (Object, error) {
1737+
if res, ok, err := ty.CallMethod("__str__", Tuple{ty}, nil); ok {
1738+
return res, err
1739+
}
1740+
return ty.M__repr__()
1741+
}
1742+
1743+
func (ty *Type) M__repr__() (Object, error) {
1744+
if res, ok, err := ty.CallMethod("__repr__", Tuple{ty}, nil); ok {
1745+
return res, err
1746+
}
1747+
if ty.Name == "" {
1748+
// FIXME not a good way to tell objects from classes!
1749+
return String(fmt.Sprintf("<%s object at %p>", ty.Type().Name, ty)), nil
1750+
}
1751+
return String(fmt.Sprintf("<class '%s'>", ty.Name)), nil
1752+
1753+
}
1754+
17021755
// Make sure it satisfies the interface
17031756
var _ Object = (*Type)(nil)
17041757
var _ I__call__ = (*Type)(nil)
17051758
var _ IGetDict = (*Type)(nil)
1759+
var _ I__repr__ = (*Type)(nil)
1760+
var _ I__str__ = (*Type)(nil)

py/type_test.go

+26
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,29 @@ func TestIsSubType(t *testing.T) {
1818
}
1919
}
2020
}
21+
22+
func TestMro(t *testing.T) {
23+
for _, test := range []struct {
24+
t *Type
25+
want []*Type
26+
}{
27+
{ObjectType, []*Type{ObjectType}},
28+
{BaseException, []*Type{BaseException, ObjectType}},
29+
{ExceptionType, []*Type{ExceptionType, BaseException, ObjectType}},
30+
{ValueError, []*Type{ValueError, ExceptionType, BaseException, ObjectType}},
31+
} {
32+
got := test.t.Mro
33+
if len(test.want) != len(got) {
34+
t.Errorf("differing lengths: want %v, got %v", test.want, got)
35+
} else {
36+
for i := range got {
37+
baseGot := got[i].(*Type)
38+
baseWant := test.want[i]
39+
if baseGot != baseWant {
40+
t.Errorf("mro[%d] want %s got %s", i, baseWant.Name, baseGot.Name)
41+
}
42+
43+
}
44+
}
45+
}
46+
}

0 commit comments

Comments
 (0)