From b3f7258f14cb2f3e52236a4087ed82541a173e7b Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Fri, 21 May 1993 19:56:10 +0000 Subject: [PATCH] * Lots of small changes related to access. * Added "access *: ...", made access work for class methods. * Introduced subclass check: make sure that when calling ClassName.methodname(instance, ...), the instance is an instance of ClassName or of a subclass thereof (this might break some old code!) --- Grammar/Grammar | 2 +- Include/accessobject.h | 1 + Include/classobject.h | 12 ++++--- Objects/accessobject.c | 13 +++++++- Objects/classobject.c | 72 +++++++++++++++++++++++------------------- Objects/methodobject.c | 4 +-- Python/ceval.c | 57 ++++++++++++++++++++++++++++----- 7 files changed, 112 insertions(+), 49 deletions(-) diff --git a/Grammar/Grammar b/Grammar/Grammar index cb4bc2718e8..430b7913691 100644 --- a/Grammar/Grammar +++ b/Grammar/Grammar @@ -100,7 +100,7 @@ return_stmt: 'return' [testlist] raise_stmt: 'raise' test [',' test] import_stmt: 'import' NAME (',' NAME)* | 'from' NAME 'import' ('*' | NAME (',' NAME)*) global_stmt: 'global' NAME (',' NAME)* -access_stmt: 'access' NAME (',' NAME)* ':' accesstype (',' accesstype)* +access_stmt: 'access' ('*' | NAME (',' NAME)*) ':' accesstype (',' accesstype)* accesstype: NAME+ # accesstype should be ('public' | 'protected' | 'private') ['read'] ['write'] # but can't be because that would create undesirable reserved words! diff --git a/Include/accessobject.h b/Include/accessobject.h index 1c67849d7eb..d50d02885f3 100644 --- a/Include/accessobject.h +++ b/Include/accessobject.h @@ -50,5 +50,6 @@ int setaccessvalue PROTO((object *, object *, object *)); void setaccessowner PROTO((object *, object *)); object *cloneaccessobject PROTO((object *)); +int hasaccessvalue PROTO((object *)); extern typeobject Anynumbertype, Anysequencetype, Anymappingtype; diff --git a/Include/classobject.h b/Include/classobject.h index ec07b59b16c..ccab6a37b82 100644 --- a/Include/classobject.h +++ b/Include/classobject.h @@ -24,11 +24,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* Class object interface */ -/* -Classes are really hacked in at the last moment. -It should be possible to use other object types as base classes, -but currently it isn't. We'll see if we can fix that later, sigh... -*/ +/* Revealing some structures (not for general use) */ typedef struct { OB_HEAD @@ -37,6 +33,12 @@ typedef struct { object *cl_name; /* A string */ } classobject; +typedef struct { + OB_HEAD + classobject *in_class; /* The class object */ + object *in_dict; /* A dictionary */ +} instanceobject; + extern typeobject Classtype, Instancetype, Instancemethodtype; #define is_classobject(op) ((op)->ob_type == &Classtype) diff --git a/Objects/accessobject.c b/Objects/accessobject.c index 41790cd3063..6fd9bd56084 100644 --- a/Objects/accessobject.c +++ b/Objects/accessobject.c @@ -99,6 +99,15 @@ setaccessowner(op, class) ap->ac_class = class; } +int +hasaccessvalue(op) + object *op; +{ + if (!is_accessobject(op)) + return 0; + return ((accessobject *)op)->ac_value != NULL; +} + object * getaccessvalue(op, class) object *op; @@ -268,7 +277,9 @@ access_repr(ap) char buf[300]; classobject *class = (classobject *)ap->ac_class; typeobject *type = ap->ac_type; - sprintf(buf, "", + sprintf(buf, + "", + (long)(ap->ac_value), class ? getstringvalue(class->cl_name) : "-", type ? type->tp_name : "-", ap->ac_mode); diff --git a/Objects/classobject.c b/Objects/classobject.c index e2a5e638173..0a6fc7e77d8 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -121,18 +121,24 @@ class_getattr(op, name) return v; } v = class_lookup(op, name, &class); - if (v != NULL) { - if (is_accessobject(v)) - v = getaccessvalue(v, getclass()); - else if (is_funcobject(v)) - v = newinstancemethodobject(v, (object *)NULL, - (object *)class); - else - INCREF(v); - return v; + if (v == NULL) { + err_setstr(AttributeError, name); + return NULL; } - err_setstr(AttributeError, name); - return NULL; + if (is_accessobject(v)) { + v = getaccessvalue(v, getclass()); + if (v == NULL) + return NULL; + } + else + INCREF(v); + if (is_funcobject(v)) { + object *w = newinstancemethodobject(v, (object *)NULL, + (object *)class); + DECREF(v); + v = w; + } + return v; } static int @@ -217,12 +223,6 @@ issubclass(class, base) /* Instance objects */ -typedef struct { - OB_HEAD - classobject *in_class; /* The class object */ - object *in_dict; /* A dictionary */ -} instanceobject; - static object *instance_getattr PROTO((instanceobject *, char *)); static int @@ -241,8 +241,11 @@ addaccess(class, inst) pos = 0; while (mappinggetnext(class->cl_dict, &pos, &key, &value)) { + object *v; if (!is_accessobject(value)) continue; + if (hasaccessvalue(value)) + continue; ac = dict2lookup(inst->in_dict, key); if (ac != NULL && is_accessobject(ac)) { err_setval(ConflictError, key); @@ -361,22 +364,27 @@ instance_getattr(inst, name) return (object *)inst->in_class; } v = dictlookup(inst->in_dict, name); - if (v != NULL) { - if (is_accessobject(v)) - v = getaccessvalue(v, getclass()); - else - INCREF(v); - return v; + if (v == NULL) { + v = class_lookup(inst->in_class, name, &class); + if (v == NULL) { + err_setstr(AttributeError, name); + return NULL; + } } - v = class_lookup(inst->in_class, name, &class); - if (v == NULL) - goto error; - if (is_funcobject(v)) - return newinstancemethodobject(v, (object *)inst, - (object *)class); - error: - err_setstr(AttributeError, name); - return NULL; + if (is_accessobject(v)) { + v = getaccessvalue(v, getclass()); + if (v == NULL) + return NULL; + } + else + INCREF(v); + if (is_funcobject(v)) { + object *w = newinstancemethodobject(v, (object *)inst, + (object *)class); + DECREF(v); + v = w; + } + return v; } static int diff --git a/Objects/methodobject.c b/Objects/methodobject.c index d7ba02e7a1d..102e5772ac7 100644 --- a/Objects/methodobject.c +++ b/Objects/methodobject.c @@ -105,10 +105,10 @@ meth_repr(m) { char buf[200]; if (m->m_self == NULL) - sprintf(buf, "", m->m_name); + sprintf(buf, "", m->m_name); else sprintf(buf, - "", + "", m->m_name, m->m_self->ob_type->tp_name, (long)m->m_self); return newstringobject(buf); diff --git a/Python/ceval.c b/Python/ceval.c index 39a20d7150d..0e2acfc5f23 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -87,7 +87,7 @@ static int import_from PROTO((object *, object *, object *)); static object *build_class PROTO((object *, object *, object *)); static void locals_2_fast PROTO((frameobject *, int)); static void fast_2_locals PROTO((frameobject *)); -static int access_statement PROTO((object *, int, frameobject *)); +static int access_statement PROTO((object *, object *, frameobject *)); /* Pointer to current frame, used to link new frames to */ @@ -184,7 +184,8 @@ eval_code(co, globals, locals, class, arg) object *trace = NULL; /* Trace function or NULL */ object *retval; /* Return value iff why == WHY_RETURN */ char *name; /* Name used by some instructions */ - int needmerge = 0; + int needmerge = 0; /* Set if need to merge locals back at end */ + int defmode = 0; /* Default access mode for new variables */ #ifdef LLTRACE int lltrace; #endif @@ -760,7 +761,22 @@ eval_code(co, globals, locals, class, arg) w = GETNAMEV(oparg); v = POP(); u = dict2lookup(f->f_locals, w); - if (u != NULL && is_accessobject(u)) { + if (u == NULL) { + if (defmode != 0) { + if (v != None) + u = (object *)v->ob_type; + else + u = NULL; + x = newaccessobject(v, class, + (typeobject *)u, + defmode); + DECREF(v); + if (x == NULL) + break; + v = x; + } + } + else if (is_accessobject(u)) { err = setaccessvalue(u, class, v); DECREF(v); break; @@ -1190,7 +1206,10 @@ eval_code(co, globals, locals, class, arg) case ACCESS_MODE: v = POP(); w = GETNAMEV(oparg); - err = access_statement(w, (int)getintvalue(v), f); + if (getstringvalue(w)[0] == '*') + defmode = getintvalue(v); + else + err = access_statement(w, v, f); DECREF(v); break; @@ -1995,7 +2014,28 @@ call_function(func, arg) object *self = instancemethodgetself(func); class = instancemethodgetclass(func); func = instancemethodgetfunc(func); - if (self != NULL) { + if (self == NULL) { + /* Unbound methods must be called with an instance of + the class (or a derived class) as first argument */ + if (arg != NULL && is_tupleobject(arg) && + gettuplesize(arg) >= 1) { + self = gettupleitem(arg, 0); + if (self != NULL && + is_instanceobject(self) && + issubclass((object *) + (((instanceobject *)self)->in_class), + class)) + /* self = self */ ; + else + self = NULL; + } + if (self == NULL) { + err_setstr(TypeError, + "unbound method must be called with class instance argument"); + return NULL; + } + } + else { int argcount; if (arg == NULL) argcount = 0; @@ -2380,11 +2420,12 @@ build_class(methods, bases, name) } static int -access_statement(name, mode, f) +access_statement(name, vmode, f) object *name; - int mode; + object *vmode; frameobject *f; { + int mode = getintvalue(vmode); object *value, *ac; typeobject *type; int fastind, ret; @@ -2415,7 +2456,7 @@ access_statement(name, mode, f) type = value->ob_type; else type = NULL; - ac = newaccessobject(value, (object*)NULL, type, mode); + ac = newaccessobject(value, f->f_class, type, mode); if (ac == NULL) return -1; if (fastind >= 0)