* 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]
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!

View File

@ -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;

View File

@ -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)

View File

@ -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, "<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) : "-",
type ? type->tp_name : "-",
ap->ac_mode);

View File

@ -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;
}
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)
goto error;
if (is_funcobject(v))
return newinstancemethodobject(v, (object *)inst,
(object *)class);
error:
if (v == 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 *)inst,
(object *)class);
DECREF(v);
v = w;
}
return v;
}
static int

View File

@ -105,10 +105,10 @@ meth_repr(m)
{
char buf[200];
if (m->m_self == NULL)
sprintf(buf, "<built-in function '%.80s'>", m->m_name);
sprintf(buf, "<built-in function %.80s>", m->m_name);
else
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,
(long)m->m_self);
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 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)