* 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!)
This commit is contained in:
Guido van Rossum 1993-05-21 19:56:10 +00:00
parent 81daa32c15
commit b3f7258f14
7 changed files with 112 additions and 49 deletions

View File

@ -100,7 +100,7 @@ return_stmt: 'return' [testlist]
raise_stmt: 'raise' test [',' test] raise_stmt: 'raise' test [',' test]
import_stmt: 'import' NAME (',' NAME)* | 'from' NAME 'import' ('*' | NAME (',' NAME)*) import_stmt: 'import' NAME (',' NAME)* | 'from' NAME 'import' ('*' | NAME (',' NAME)*)
global_stmt: 'global' NAME (',' NAME)* global_stmt: 'global' NAME (',' NAME)*
access_stmt: 'access' NAME (',' NAME)* ':' accesstype (',' accesstype)* access_stmt: 'access' ('*' | NAME (',' NAME)*) ':' accesstype (',' accesstype)*
accesstype: NAME+ accesstype: NAME+
# accesstype should be ('public' | 'protected' | 'private') ['read'] ['write'] # accesstype should be ('public' | 'protected' | 'private') ['read'] ['write']
# but can't be because that would create undesirable reserved words! # but can't be because that would create undesirable reserved words!

View File

@ -50,5 +50,6 @@ int setaccessvalue PROTO((object *, object *, object *));
void setaccessowner PROTO((object *, object *)); void setaccessowner PROTO((object *, object *));
object *cloneaccessobject PROTO((object *)); object *cloneaccessobject PROTO((object *));
int hasaccessvalue PROTO((object *));
extern typeobject Anynumbertype, Anysequencetype, Anymappingtype; extern typeobject Anynumbertype, Anysequencetype, Anymappingtype;

View File

@ -24,11 +24,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* Class object interface */ /* Class object interface */
/* /* Revealing some structures (not for general use) */
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...
*/
typedef struct { typedef struct {
OB_HEAD OB_HEAD
@ -37,6 +33,12 @@ typedef struct {
object *cl_name; /* A string */ object *cl_name; /* A string */
} classobject; } classobject;
typedef struct {
OB_HEAD
classobject *in_class; /* The class object */
object *in_dict; /* A dictionary */
} instanceobject;
extern typeobject Classtype, Instancetype, Instancemethodtype; extern typeobject Classtype, Instancetype, Instancemethodtype;
#define is_classobject(op) ((op)->ob_type == &Classtype) #define is_classobject(op) ((op)->ob_type == &Classtype)

View File

@ -99,6 +99,15 @@ setaccessowner(op, class)
ap->ac_class = class; ap->ac_class = class;
} }
int
hasaccessvalue(op)
object *op;
{
if (!is_accessobject(op))
return 0;
return ((accessobject *)op)->ac_value != NULL;
}
object * object *
getaccessvalue(op, class) getaccessvalue(op, class)
object *op; object *op;
@ -268,7 +277,9 @@ access_repr(ap)
char buf[300]; char buf[300];
classobject *class = (classobject *)ap->ac_class; classobject *class = (classobject *)ap->ac_class;
typeobject *type = ap->ac_type; typeobject *type = ap->ac_type;
sprintf(buf, "<access object, class %.100s, type %.100s, mode 0%o>", sprintf(buf,
"<access object, value 0x%lx, class %.100s, type %.100s, mode %04o>",
(long)(ap->ac_value),
class ? getstringvalue(class->cl_name) : "-", class ? getstringvalue(class->cl_name) : "-",
type ? type->tp_name : "-", type ? type->tp_name : "-",
ap->ac_mode); ap->ac_mode);

View File

@ -121,18 +121,24 @@ class_getattr(op, name)
return v; return v;
} }
v = class_lookup(op, name, &class); v = class_lookup(op, name, &class);
if (v != NULL) { if (v == NULL) {
if (is_accessobject(v)) err_setstr(AttributeError, name);
v = getaccessvalue(v, getclass()); return NULL;
else if (is_funcobject(v))
v = newinstancemethodobject(v, (object *)NULL,
(object *)class);
else
INCREF(v);
return v;
} }
err_setstr(AttributeError, name); if (is_accessobject(v)) {
return NULL; 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 static int
@ -217,12 +223,6 @@ issubclass(class, base)
/* Instance objects */ /* 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 object *instance_getattr PROTO((instanceobject *, char *));
static int static int
@ -241,8 +241,11 @@ addaccess(class, inst)
pos = 0; pos = 0;
while (mappinggetnext(class->cl_dict, &pos, &key, &value)) { while (mappinggetnext(class->cl_dict, &pos, &key, &value)) {
object *v;
if (!is_accessobject(value)) if (!is_accessobject(value))
continue; continue;
if (hasaccessvalue(value))
continue;
ac = dict2lookup(inst->in_dict, key); ac = dict2lookup(inst->in_dict, key);
if (ac != NULL && is_accessobject(ac)) { if (ac != NULL && is_accessobject(ac)) {
err_setval(ConflictError, key); err_setval(ConflictError, key);
@ -361,22 +364,27 @@ instance_getattr(inst, name)
return (object *)inst->in_class; return (object *)inst->in_class;
} }
v = dictlookup(inst->in_dict, name); v = dictlookup(inst->in_dict, name);
if (v != NULL) { if (v == NULL) {
if (is_accessobject(v)) v = class_lookup(inst->in_class, name, &class);
v = getaccessvalue(v, getclass()); if (v == NULL) {
else err_setstr(AttributeError, name);
INCREF(v); return NULL;
return v; }
} }
v = class_lookup(inst->in_class, name, &class); if (is_accessobject(v)) {
if (v == NULL) v = getaccessvalue(v, getclass());
goto error; if (v == NULL)
if (is_funcobject(v)) return NULL;
return newinstancemethodobject(v, (object *)inst, }
(object *)class); else
error: INCREF(v);
err_setstr(AttributeError, name); if (is_funcobject(v)) {
return NULL; object *w = newinstancemethodobject(v, (object *)inst,
(object *)class);
DECREF(v);
v = w;
}
return v;
} }
static int static int

View File

@ -105,10 +105,10 @@ meth_repr(m)
{ {
char buf[200]; char buf[200];
if (m->m_self == NULL) if (m->m_self == NULL)
sprintf(buf, "<built-in function '%.80s'>", m->m_name); sprintf(buf, "<built-in function %.80s>", m->m_name);
else else
sprintf(buf, sprintf(buf,
"<built-in method '%.80s' of %.80s object at %lx>", "<built-in method %.80s of %.80s object at %lx>",
m->m_name, m->m_self->ob_type->tp_name, m->m_name, m->m_self->ob_type->tp_name,
(long)m->m_self); (long)m->m_self);
return newstringobject(buf); return newstringobject(buf);

View File

@ -87,7 +87,7 @@ static int import_from PROTO((object *, object *, object *));
static object *build_class PROTO((object *, object *, object *)); static object *build_class PROTO((object *, object *, object *));
static void locals_2_fast PROTO((frameobject *, int)); static void locals_2_fast PROTO((frameobject *, int));
static void fast_2_locals PROTO((frameobject *)); 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 */ /* 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 *trace = NULL; /* Trace function or NULL */
object *retval; /* Return value iff why == WHY_RETURN */ object *retval; /* Return value iff why == WHY_RETURN */
char *name; /* Name used by some instructions */ 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 #ifdef LLTRACE
int lltrace; int lltrace;
#endif #endif
@ -760,7 +761,22 @@ eval_code(co, globals, locals, class, arg)
w = GETNAMEV(oparg); w = GETNAMEV(oparg);
v = POP(); v = POP();
u = dict2lookup(f->f_locals, w); 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); err = setaccessvalue(u, class, v);
DECREF(v); DECREF(v);
break; break;
@ -1190,7 +1206,10 @@ eval_code(co, globals, locals, class, arg)
case ACCESS_MODE: case ACCESS_MODE:
v = POP(); v = POP();
w = GETNAMEV(oparg); 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); DECREF(v);
break; break;
@ -1995,7 +2014,28 @@ call_function(func, arg)
object *self = instancemethodgetself(func); object *self = instancemethodgetself(func);
class = instancemethodgetclass(func); class = instancemethodgetclass(func);
func = instancemethodgetfunc(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; int argcount;
if (arg == NULL) if (arg == NULL)
argcount = 0; argcount = 0;
@ -2380,11 +2420,12 @@ build_class(methods, bases, name)
} }
static int static int
access_statement(name, mode, f) access_statement(name, vmode, f)
object *name; object *name;
int mode; object *vmode;
frameobject *f; frameobject *f;
{ {
int mode = getintvalue(vmode);
object *value, *ac; object *value, *ac;
typeobject *type; typeobject *type;
int fastind, ret; int fastind, ret;
@ -2415,7 +2456,7 @@ access_statement(name, mode, f)
type = value->ob_type; type = value->ob_type;
else else
type = NULL; type = NULL;
ac = newaccessobject(value, (object*)NULL, type, mode); ac = newaccessobject(value, f->f_class, type, mode);
if (ac == NULL) if (ac == NULL)
return -1; return -1;
if (fastind >= 0) if (fastind >= 0)