Skip to content

Commit 9dc3e65

Browse files
committed
type() much more nearly working
1 parent 9022860 commit 9dc3e65

File tree

1 file changed

+176
-48
lines changed

1 file changed

+176
-48
lines changed

py/type.go

Lines changed: 176 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,11 @@ const (
6565
)
6666

6767
type Type struct {
68-
Name string // For printing, in format "<module>.<name>"
69-
Doc string // Documentation string
70-
Methods StringDict // *PyMethodDef
71-
Members StringDict // *PyMemberDef
68+
ObjectType *Type // Type of this object
69+
Name string // For printing, in format "<module>.<name>"
70+
Doc string // Documentation string
71+
Methods StringDict // *PyMethodDef
72+
Members StringDict // *PyMemberDef
7273
// Getset *PyGetSetDef
7374
Base *Type
7475
Dict StringDict
@@ -163,24 +164,32 @@ type Type struct {
163164
*/
164165
}
165166

166-
var TypeType = NewType("type", "type(object) -> the object's type\ntype(name, bases, dict) -> a new type")
167+
var TypeType *Type = &Type{Name: "type", Doc: "type(object) -> the object's type\ntype(name, bases, dict) -> a new type"}
167168
var BaseObjectType = NewType("object", "The most base type")
168169

169170
func init() {
171+
TypeType.ObjectType = TypeType
170172
// FIXME put this into NewType
171173
TypeType.New = TypeNew
174+
TypeType.Init = TypeInit
175+
BaseObjectType.Flags |= TPFLAGS_BASETYPE
176+
BaseObjectType.New = ObjectNew
177+
BaseObjectType.Init = ObjectInit
172178
}
173179

174180
// Type of this object
175-
func (o *Type) Type() *Type {
176-
return TypeType
181+
func (t *Type) Type() *Type {
182+
return t.ObjectType
177183
}
178184

179185
// Make a new type from a name
186+
//
187+
// For making Go types
180188
func NewType(Name string, Doc string) *Type {
181189
return &Type{
182-
Name: Name,
183-
Doc: Doc,
190+
ObjectType: TypeType,
191+
Name: Name,
192+
Doc: Doc,
184193
}
185194
}
186195

@@ -235,18 +244,16 @@ func (a *Type) IsSubtype(b *Type) bool {
235244
}
236245
}
237246

238-
// Call a type
247+
// Call type()
239248
func (t *Type) M__call__(args Tuple, kwargs StringDict) Object {
240-
var obj Object
241-
242249
if t.New == nil {
243250
// FIXME TypeError
244251
panic(fmt.Sprintf("TypeError: cannot create '%s' instances", t.Name))
245252
}
246253

247-
obj = t.New(t, args, kwargs)
254+
obj := t.New(t, args, kwargs)
248255
// Ugly exception: when the call was type(something),
249-
// don't call Init on the result.
256+
// don't call tp_init on the result.
250257
if t == TypeType && len(args) == 1 && len(kwargs) == 0 {
251258
return obj
252259
}
@@ -255,9 +262,9 @@ func (t *Type) M__call__(args Tuple, kwargs StringDict) Object {
255262
if !obj.Type().IsSubtype(t) {
256263
return obj
257264
}
258-
t = obj.Type()
259-
if t.Init != nil {
260-
t.Init(obj, args, kwargs)
265+
objType := obj.Type()
266+
if objType.Init != nil {
267+
objType.Init(obj, args, kwargs)
261268
}
262269
return obj
263270
}
@@ -569,8 +576,16 @@ func (t *Type) mro_internal() {
569576
result = t.mro_implementation()
570577
} else {
571578
checkit = true
572-
mro := lookup_method(t, "mro")
573-
result = Call(mro, nil, nil)
579+
// FIXME this is what it was originally
580+
// but we haven't put mro in slots or anything
581+
// mro := lookup_method(t, "mro")
582+
mro := lookup_maybe(t, "mro")
583+
if mro == nil {
584+
// Default to internal implementation
585+
result = t.mro_implementation()
586+
} else {
587+
result = Call(mro, nil, nil)
588+
}
574589
}
575590
tuple := SequenceTuple(result)
576591
if checkit {
@@ -924,33 +939,13 @@ func best_base(bases Tuple) *Type {
924939
}
925940

926941
// Generic object allocator
927-
func (t *Type) Alloc(nitems int) Object {
928-
// PyObject *obj;
929-
// const size_t size = _PyObject_VAR_SIZE(type, nitems+1);
930-
// /* note that we need to add one, for the sentinel */
931-
932-
// if (PyType_IS_GC(type))
933-
// obj = _PyObject_GC_Malloc(size);
934-
// else
935-
// obj = (PyObject *)PyObject_MALLOC(size);
936-
937-
// if (obj == nil)
938-
// return PyErr_NoMemory();
942+
func (t *Type) Alloc() *Type {
943+
obj := new(Type)
939944

940-
// memset(obj, '\0', size);
945+
// Set the type of the new object to this type
946+
obj.ObjectType = t
941947

942-
// if (type->tp_flags & Py_TPFLAGS_HEAPTYPE)
943-
// Py_INCREF(type);
944-
945-
// if (type->tp_itemsize == 0)
946-
// PyObject_INIT(obj, type);
947-
// else
948-
// (void) PyObject_INIT_VAR((PyVarObject *)obj, type, nitems);
949-
950-
// if (PyType_IS_GC(type))
951-
// _PyObject_GC_TRACK(obj);
952-
// return obj;
953-
return None
948+
return obj
954949
}
955950

956951
// Create a new type
@@ -973,8 +968,7 @@ func TypeNew(metatype *Type, args Tuple, kwargs StringDict) *Type {
973968
// a msg saying type() needs exactly 3.
974969
if len(args)+len(kwargs) != 3 {
975970
// FIXME TypeError
976-
panic(fmt.Sprintf("PyExc_TypeError: type() takes 1 or 3 arguments"))
977-
return nil
971+
panic(fmt.Sprintf("TypeError: type() takes 1 or 3 arguments"))
978972
}
979973

980974
// Check arguments: (name, bases, dict)
@@ -1144,7 +1138,10 @@ func TypeNew(metatype *Type, args Tuple, kwargs StringDict) *Type {
11441138
}
11451139

11461140
// Allocate the type object
1147-
new_type = metatype.Alloc(nslots).(*Type)
1141+
_ = nslots // FIXME
1142+
new_type = metatype.Alloc()
1143+
new_type.New = ObjectNew // FIXME metatype.New // FIXME?
1144+
new_type.Init = ObjectInit // FIXME metatype.New // FIXME?
11481145

11491146
// Keep name and slots alive in the extended type object
11501147
et := new_type
@@ -1165,7 +1162,7 @@ func TypeNew(metatype *Type, args Tuple, kwargs StringDict) *Type {
11651162

11661163
// Set __module__ in the dict
11671164
if _, ok := dict["__module__"]; !ok {
1168-
fmt.Printf("FIXME neet to get the current vm globals somehow")
1165+
fmt.Printf("FIXME neet to get the current vm globals somehow\n")
11691166
// tmp = PyEval_GetGlobals()
11701167
// if tmp != nil {
11711168
// tmp, ok := tmp["__name__"]
@@ -1294,6 +1291,137 @@ func TypeNew(metatype *Type, args Tuple, kwargs StringDict) *Type {
12941291
return new_type
12951292
}
12961293

1294+
func TypeInit(cls Object, args Tuple, kwargs StringDict) {
1295+
if len(kwargs) != 0 {
1296+
// FIXME TypeError
1297+
panic(fmt.Sprintf("TypeError: type.__init__() takes no keyword arguments"))
1298+
}
1299+
1300+
if len(args) != 1 && len(args) != 3 {
1301+
// FIXME TypeError
1302+
panic(fmt.Sprintf("TypeError: type.__init__() takes 1 or 3 arguments"))
1303+
}
1304+
1305+
// Call object.__init__(self) now.
1306+
// XXX Could call super(type, cls).__init__() but what's the point?
1307+
ObjectInit(cls, nil, nil)
1308+
}
1309+
1310+
// The base type of all types (eventually)... except itself.
1311+
1312+
// You may wonder why object.__new__() only complains about arguments
1313+
// when object.__init__() is not overridden, and vice versa.
1314+
//
1315+
// Consider the use cases:
1316+
//
1317+
// 1. When neither is overridden, we want to hear complaints about
1318+
// excess (i.e., any) arguments, since their presence could
1319+
// indicate there's a bug.
1320+
//
1321+
// 2. When defining an Immutable type, we are likely to override only
1322+
// __new__(), since __init__() is called too late to initialize an
1323+
// Immutable object. Since __new__() defines the signature for the
1324+
// type, it would be a pain to have to override __init__() just to
1325+
// stop it from complaining about excess arguments.
1326+
//
1327+
// 3. When defining a Mutable type, we are likely to override only
1328+
// __init__(). So here the converse reasoning applies: we don't
1329+
// want to have to override __new__() just to stop it from
1330+
// complaining.
1331+
//
1332+
// 4. When __init__() is overridden, and the subclass __init__() calls
1333+
// object.__init__(), the latter should complain about excess
1334+
// arguments; ditto for __new__().
1335+
//
1336+
// Use cases 2 and 3 make it unattractive to unconditionally check for
1337+
// excess arguments. The best solution that addresses all four use
1338+
// cases is as follows: __init__() complains about excess arguments
1339+
// unless __new__() is overridden and __init__() is not overridden
1340+
// (IOW, if __init__() is overridden or __new__() is not overridden);
1341+
// symmetrically, __new__() complains about excess arguments unless
1342+
// __init__() is overridden and __new__() is not overridden
1343+
// (IOW, if __new__() is overridden or __init__() is not overridden).
1344+
//
1345+
// However, for backwards compatibility, this breaks too much code.
1346+
// Therefore, in 2.6, we'll *warn* about excess arguments when both
1347+
// methods are overridden; for all other cases we'll use the above
1348+
// rules.
1349+
1350+
// Return true if any arguments supplied
1351+
func excess_args(args Tuple, kwargs StringDict) bool {
1352+
return len(args) != 0 || len(kwargs) != 0
1353+
}
1354+
1355+
func ObjectInit(self Object, args Tuple, kwargs StringDict) {
1356+
t := self.Type()
1357+
// FIXME bodge to compare function pointers
1358+
if excess_args(args, kwargs) && (fmt.Sprintf("%x", t.New) == fmt.Sprintf("%x", ObjectNew) || fmt.Sprintf("%x", t.Init) != fmt.Sprintf("%x", ObjectInit)) {
1359+
// FIXME type error
1360+
panic(fmt.Sprintf("TypeError: object.__init__() takes no parameters"))
1361+
}
1362+
}
1363+
1364+
func ObjectNew(t *Type, args Tuple, kwargs StringDict) *Type {
1365+
// FIXME bodge to compare function pointers
1366+
if excess_args(args, kwargs) && (fmt.Sprintf("%x", t.Init) == fmt.Sprintf("%x", ObjectInit) || fmt.Sprintf("%x", t.New) != fmt.Sprintf("%x", ObjectNew)) {
1367+
// FIXME type error
1368+
panic(fmt.Sprintf("TypeError: object() takes no parameters"))
1369+
}
1370+
1371+
// FIXME abstrac types
1372+
// if (type->tp_flags & Py_TPFLAGS_IS_ABSTRACT) {
1373+
// PyObject *abstract_methods = NULL;
1374+
// PyObject *builtins;
1375+
// PyObject *sorted;
1376+
// PyObject *sorted_methods = NULL;
1377+
// PyObject *joined = NULL;
1378+
// PyObject *comma;
1379+
// _Py_static_string(comma_id, ", ");
1380+
// _Py_IDENTIFIER(sorted);
1381+
1382+
// // Compute ", ".join(sorted(type.__abstractmethods__))
1383+
// // into joined.
1384+
// abstract_methods = type_abstractmethods(type, NULL);
1385+
// if (abstract_methods == NULL) {
1386+
// goto error;
1387+
// }
1388+
// builtins = PyEval_GetBuiltins();
1389+
// if (builtins == NULL) {
1390+
// goto error;
1391+
// }
1392+
// sorted = _PyDict_GetItemId(builtins, &PyId_sorted);
1393+
// if (sorted == NULL) {
1394+
// goto error;
1395+
// }
1396+
// sorted_methods = PyObject_CallFunctionObjArgs(sorted,
1397+
// abstract_methods,
1398+
// NULL);
1399+
// if (sorted_methods == NULL) {
1400+
// goto error;
1401+
// }
1402+
// comma = _PyUnicode_FromId(&comma_id);
1403+
// if (comma == NULL) {
1404+
// goto error;
1405+
// }
1406+
// joined = PyUnicode_Join(comma, sorted_methods);
1407+
// if (joined == NULL) {
1408+
// goto error;
1409+
// }
1410+
1411+
// PyErr_Format(PyExc_TypeError,
1412+
// "Can't instantiate abstract class %s "
1413+
// "with abstract methods %U",
1414+
// type->tp_name,
1415+
// joined);
1416+
// error:
1417+
// Py_XDECREF(joined);
1418+
// Py_XDECREF(sorted_methods);
1419+
// Py_XDECREF(abstract_methods);
1420+
// return NULL;
1421+
// }
1422+
return t.Alloc()
1423+
}
1424+
12971425
// Make sure it satisfies the interface
12981426
var _ Object = (*Type)(nil)
12991427
var _ I__call__ = (*Type)(nil)

0 commit comments

Comments
 (0)