diff options
author | Guido van Rossum <guido@python.org> | 1993-05-20 14:24:46 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1993-05-20 14:24:46 (GMT) |
commit | 81daa32c15cfa9f05eda037916cdbfd5b4323431 (patch) | |
tree | 82d67f6db4ff6f1ae1a682f2ec4b01d075f3e405 /Objects/classobject.c | |
parent | 25831652fd4c03323066d4cafdc0551c396a993e (diff) | |
download | cpython-81daa32c15cfa9f05eda037916cdbfd5b4323431.zip cpython-81daa32c15cfa9f05eda037916cdbfd5b4323431.tar.gz cpython-81daa32c15cfa9f05eda037916cdbfd5b4323431.tar.bz2 |
Access checks now work, at least for instance data (not for methods
yet). The class is now passed to eval_code and stored in the current
frame. It is also stored in instance method objects. An "unbound"
instance method is now returned when a function is retrieved through
"classname.funcname", which when called passes the class to eval_code.
Diffstat (limited to 'Objects/classobject.c')
-rw-r--r-- | Objects/classobject.c | 258 |
1 files changed, 173 insertions, 85 deletions
diff --git a/Objects/classobject.c b/Objects/classobject.c index bc61b64..e2a5e63 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -29,19 +29,14 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "structmember.h" #include "ceval.h" -typedef struct { - OB_HEAD - object *cl_bases; /* A tuple */ - object *cl_methods; /* A dictionary */ - object *cl_name; /* A string */ -} classobject; - object * -newclassobject(bases, methods, name) +newclassobject(bases, dict, name) object *bases; /* NULL or tuple of classobjects! */ - object *methods; + object *dict; object *name; /* String; NULL if unknown */ { + int pos; + object *key, *value; classobject *op; if (bases == NULL) { bases = newtupleobject(0); @@ -56,10 +51,15 @@ newclassobject(bases, methods, name) return NULL; } op->cl_bases = bases; - INCREF(methods); - op->cl_methods = methods; + INCREF(dict); + op->cl_dict = dict; XINCREF(name); op->cl_name = name; + pos = 0; + while (mappinggetnext(dict, &pos, &key, &value)) { + if (is_accessobject(value)) + setaccessowner(value, (object *)op); + } return (object *) op; } @@ -70,20 +70,43 @@ class_dealloc(op) classobject *op; { DECREF(op->cl_bases); - DECREF(op->cl_methods); + DECREF(op->cl_dict); XDECREF(op->cl_name); free((ANY *)op); } static object * +class_lookup(cp, name, pclass) + classobject *cp; + char *name; + classobject **pclass; +{ + int i, n; + object *value = dictlookup(cp->cl_dict, name); + if (value != NULL) { + *pclass = cp; + return value; + } + n = gettuplesize(cp->cl_bases); + for (i = 0; i < n; i++) { + object *v = class_lookup((classobject *) + gettupleitem(cp->cl_bases, i), name, pclass); + if (v != NULL) + return v; + } + return NULL; +} + +static object * class_getattr(op, name) register classobject *op; register char *name; { register object *v; + object *class; if (strcmp(name, "__dict__") == 0) { - INCREF(op->cl_methods); - return op->cl_methods; + INCREF(op->cl_dict); + return op->cl_dict; } if (strcmp(name, "__bases__") == 0) { INCREF(op->cl_bases); @@ -97,25 +120,17 @@ class_getattr(op, name) INCREF(v); return v; } - v = dictlookup(op->cl_methods, name); + v = class_lookup(op, name, &class); if (v != NULL) { if (is_accessobject(v)) - v = getaccessvalue(v, (object *)NULL); + v = getaccessvalue(v, getclass()); + else if (is_funcobject(v)) + v = newinstancemethodobject(v, (object *)NULL, + (object *)class); else INCREF(v); return v; } - { - int n = gettuplesize(op->cl_bases); - int i; - for (i = 0; i < n; i++) { - v = class_getattr((classobject *) - gettupleitem(op->cl_bases, i), name); - if (v != NULL) - return v; - err_clear(); - } - } err_setstr(AttributeError, name); return NULL; } @@ -134,18 +149,18 @@ class_setattr(op, name, v) return -1; } } - ac = dictlookup(op->cl_methods, name); + ac = dictlookup(op->cl_dict, name); if (ac != NULL && is_accessobject(ac)) - return setaccessvalue(ac, (object *)NULL, v); + return setaccessvalue(ac, getclass(), v); if (v == NULL) { - int rv = dictremove(op->cl_methods, name); + int rv = dictremove(op->cl_dict, name); if (rv < 0) err_setstr(AttributeError, "delete non-existing class attribute"); return rv; } else - return dictinsert(op->cl_methods, name, v); + return dictinsert(op->cl_dict, name, v); } static object * @@ -179,17 +194,71 @@ typeobject Classtype = { 0, /*tp_as_mapping*/ }; +int +issubclass(class, base) + object *class; + object *base; +{ + int i, n; + classobject *cp; + if (class == NULL || !is_classobject(class)) + return 0; + if (class == base) + return 1; + cp = (classobject *)class; + n = gettuplesize(cp->cl_bases); + for (i = 0; i < n; i++) { + if (issubclass(gettupleitem(cp->cl_bases, i), base)) + return 1; + } + return 0; +} + -/* We're not done yet: next, we define instance objects... */ +/* Instance objects */ typedef struct { OB_HEAD classobject *in_class; /* The class object */ - object *in_attr; /* A dictionary */ + object *in_dict; /* A dictionary */ } instanceobject; static object *instance_getattr PROTO((instanceobject *, char *)); +static int +addaccess(class, inst) + classobject *class; + instanceobject *inst; +{ + int i, n, pos, ret; + object *key, *value, *ac; + + n = gettuplesize(class->cl_bases); + for (i = 0; i < n; i++) { + if (addaccess(gettupleitem(class->cl_bases, i), inst) < 0) + return -1; + } + + pos = 0; + while (mappinggetnext(class->cl_dict, &pos, &key, &value)) { + if (!is_accessobject(value)) + continue; + ac = dict2lookup(inst->in_dict, key); + if (ac != NULL && is_accessobject(ac)) { + err_setval(ConflictError, key); + return -1; + } + ac = cloneaccessobject(value); + if (ac == NULL) + return -1; + ret = dict2insert(inst->in_dict, key, ac); + DECREF(ac); + if (ret != 0) + return -1; + } + return 0; +} + object * newinstanceobject(class, arg) object *class; @@ -198,8 +267,6 @@ newinstanceobject(class, arg) register instanceobject *inst; object *v; object *init; - int pos; - object *key, *value; if (!is_classobject(class)) { err_badcall(); return NULL; @@ -209,26 +276,12 @@ newinstanceobject(class, arg) return NULL; INCREF(class); inst->in_class = (classobject *)class; - inst->in_attr = newdictobject(); - if (inst->in_attr == NULL) { - error: + inst->in_dict = newdictobject(); + if (inst->in_dict == NULL || + addaccess((classobject *)class, inst) != 0) { DECREF(inst); return NULL; } - pos = 0; - while (mappinggetnext(((classobject *)class)->cl_methods, - &pos, &key, &value)) { - if (is_accessobject(value)) { - object *ac = cloneaccessobject(value); - int err; - if (ac == NULL) - goto error; - err = dict2insert(inst->in_attr, key, ac); - DECREF(ac); - if (err) - goto error; - } - } init = instance_getattr(inst, "__init__"); if (init == NULL) { err_clear(); @@ -288,7 +341,7 @@ instance_dealloc(inst) if (--inst->ob_refcnt > 0) return; /* __del__ added a reference; don't delete now */ DECREF(inst->in_class); - XDECREF(inst->in_attr); + XDECREF(inst->in_dict); free((ANY *)inst); } @@ -298,31 +351,30 @@ instance_getattr(inst, name) register char *name; { register object *v; + classobject *class; if (strcmp(name, "__dict__") == 0) { - INCREF(inst->in_attr); - return inst->in_attr; + INCREF(inst->in_dict); + return inst->in_dict; } if (strcmp(name, "__class__") == 0) { INCREF(inst->in_class); return (object *)inst->in_class; } - v = dictlookup(inst->in_attr, name); + v = dictlookup(inst->in_dict, name); if (v != NULL) { if (is_accessobject(v)) - v = getaccessvalue(v, (object *)NULL); + v = getaccessvalue(v, getclass()); else INCREF(v); return v; } - v = class_getattr(inst->in_class, name); + v = class_lookup(inst->in_class, name, &class); if (v == NULL) - return v; /* class_getattr() has set the error */ - if (is_funcobject(v)) { - object *w = newinstancemethodobject(v, (object *)inst); - DECREF(v); - return w; - } - DECREF(v); + goto error; + if (is_funcobject(v)) + return newinstancemethodobject(v, (object *)inst, + (object *)class); + error: err_setstr(AttributeError, name); return NULL; } @@ -341,18 +393,18 @@ instance_setattr(inst, name, v) return -1; } } - ac = dictlookup(inst->in_attr, name); + ac = dictlookup(inst->in_dict, name); if (ac != NULL && is_accessobject(ac)) - return setaccessvalue(ac, (object *)NULL, v); + return setaccessvalue(ac, getclass(), v); if (v == NULL) { - int rv = dictremove(inst->in_attr, name); + int rv = dictremove(inst->in_dict, name); if (rv < 0) err_setstr(AttributeError, "delete non-existing instance attribute"); return rv; } else - return dictinsert(inst->in_attr, name, v); + return dictinsert(inst->in_dict, name, v); } static object * @@ -893,18 +945,24 @@ instance_convert(inst, methodname) } -/* And finally, here are instance method objects */ +/* Instance method objects are used for two purposes: + (a) as bound instance methods (returned by instancename.methodname) + (b) as unbound methods (returned by ClassName.methodname) + In case (b), im_self is NULL +*/ typedef struct { OB_HEAD - object *im_func; /* The method function */ - object *im_self; /* The object to which this applies */ + object *im_func; /* The function implementing the method */ + object *im_self; /* The instance it is bound to, or NULL */ + object *im_class; /* The class that defined the method */ } instancemethodobject; object * -newinstancemethodobject(func, self) +newinstancemethodobject(func, self, class) object *func; object *self; + object *class; { register instancemethodobject *im; if (!is_funcobject(func)) { @@ -916,8 +974,10 @@ newinstancemethodobject(func, self) return NULL; INCREF(func); im->im_func = func; - INCREF(self); + XINCREF(self); im->im_self = self; + INCREF(class); + im->im_class = class; return (object *)im; } @@ -943,6 +1003,17 @@ instancemethodgetself(im) return ((instancemethodobject *)im)->im_self; } +object * +instancemethodgetclass(im) + register object *im; +{ + if (!is_instancemethodobject(im)) { + err_badcall(); + return NULL; + } + return ((instancemethodobject *)im)->im_class; +} + /* Class method methods */ #define OFF(x) offsetof(instancemethodobject, x) @@ -950,6 +1021,7 @@ instancemethodgetself(im) static struct memberlist instancemethod_memberlist[] = { {"im_func", T_OBJECT, OFF(im_func)}, {"im_self", T_OBJECT, OFF(im_self)}, + {"im_class", T_OBJECT, OFF(im_class)}, {NULL} /* Sentinel */ }; @@ -966,7 +1038,8 @@ instancemethod_dealloc(im) register instancemethodobject *im; { DECREF(im->im_func); - DECREF(im->im_self); + XDECREF(im->im_self); + DECREF(im->im_class); free((ANY *)im); } @@ -985,20 +1058,32 @@ instancemethod_repr(a) instancemethodobject *a; { char buf[240]; - object *classname = - ((instanceobject *)(a->im_self))->in_class->cl_name; - object *funcname = ((funcobject *)(a->im_func))->func_name; - char *cname, *fname; - if (classname != NULL && is_stringobject(classname)) - cname = getstringvalue(classname); + instanceobject *self = (instanceobject *)(a->im_self); + funcobject *func = (funcobject *)(a->im_func); + classobject *class = (classobject *)(a->im_class); + object *fclassname, *iclassname, *funcname; + char *fcname, *icname, *fname; + fclassname = class->cl_name; + funcname = func->func_name; + if (fclassname != NULL && is_stringobject(fclassname)) + fcname = getstringvalue(fclassname); else - cname = "?"; + fcname = "?"; if (funcname != NULL && is_stringobject(funcname)) fname = getstringvalue(funcname); else fname = "?"; - sprintf(buf, "<method %.100s of %.100s instance at %lx>", - fname, cname, (long)a->im_func); + if (self == NULL) + sprintf(buf, "<unbound method %.100s.%.100s>", fcname, fname); + else { + iclassname = self->in_class->cl_name; + if (iclassname != NULL && is_stringobject(iclassname)) + icname = getstringvalue(iclassname); + else + icname = "?"; + sprintf(buf, "<method %.60s.%.60s of %.60s instance at %lx>", + fcname, fname, icname, (long)self); + } return newstringobject(buf); } @@ -1007,7 +1092,10 @@ instancemethod_hash(a) instancemethodobject *a; { long x, y; - x = hashobject(a->im_self); + if (a->im_self == NULL) + x = hashobject(None); + else + x = hashobject(a->im_self); if (x == -1) return -1; y = hashobject(a->im_func); |