summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1993-05-20 14:24:46 (GMT)
committerGuido van Rossum <guido@python.org>1993-05-20 14:24:46 (GMT)
commit81daa32c15cfa9f05eda037916cdbfd5b4323431 (patch)
tree82d67f6db4ff6f1ae1a682f2ec4b01d075f3e405
parent25831652fd4c03323066d4cafdc0551c396a993e (diff)
downloadcpython-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.
-rw-r--r--Include/accessobject.h54
-rw-r--r--Include/ceval.h1
-rw-r--r--Include/classobject.h12
-rw-r--r--Include/eval.h3
-rw-r--r--Include/frameobject.h3
-rw-r--r--Objects/accessobject.c320
-rw-r--r--Objects/classobject.c258
-rw-r--r--Objects/frameobject.c8
-rw-r--r--Objects/moduleobject.c5
-rw-r--r--Python/bltinmodule.c2
-rw-r--r--Python/ceval.c127
-rw-r--r--Python/compile.c6
-rw-r--r--Python/import.c4
-rw-r--r--Python/pythonrun.c2
14 files changed, 655 insertions, 150 deletions
diff --git a/Include/accessobject.h b/Include/accessobject.h
new file mode 100644
index 0000000..1c67849
--- /dev/null
+++ b/Include/accessobject.h
@@ -0,0 +1,54 @@
+/***********************************************************
+Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum,
+Amsterdam, The Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* Access object interface */
+
+/* Access mode bits (note similarity with UNIX permissions) */
+#define AC_R 0444
+#define AC_W 0222
+
+#define AC_PRIVATE 0700
+#define AC_R_PRIVATE 0400
+#define AC_W_PRIVATE 0200
+
+#define AC_PROTECTED 0070
+#define AC_R_PROTECTED 0040
+#define AC_W_PROTECTED 0020
+
+#define AC_PUBLIC 0007
+#define AC_R_PUBLIC 0004
+#define AC_W_PUBLIC 0002
+
+extern typeobject Accesstype;
+
+#define is_accessobject(v) ((v)->ob_type == &Accesstype)
+
+object *newaccessobject PROTO((object *, object *, typeobject *, int));
+object *getaccessvalue PROTO((object *, object *));
+int setaccessvalue PROTO((object *, object *, object *));
+
+void setaccessowner PROTO((object *, object *));
+object *cloneaccessobject PROTO((object *));
+
+extern typeobject Anynumbertype, Anysequencetype, Anymappingtype;
diff --git a/Include/ceval.h b/Include/ceval.h
index a9f79b5..ab7659e 100644
--- a/Include/ceval.h
+++ b/Include/ceval.h
@@ -28,6 +28,7 @@ object *call_object PROTO((object *, object *));
object *getglobals PROTO((void));
object *getlocals PROTO((void));
+object *getclass PROTO((void));
void mergelocals PROTO((void));
void printtraceback PROTO((object *));
diff --git a/Include/classobject.h b/Include/classobject.h
index b9bbc9b..ec07b59 100644
--- a/Include/classobject.h
+++ b/Include/classobject.h
@@ -30,6 +30,13 @@ 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 {
+ OB_HEAD
+ object *cl_bases; /* A tuple of class objects */
+ object *cl_dict; /* A dictionary */
+ object *cl_name; /* A string */
+} classobject;
+
extern typeobject Classtype, Instancetype, Instancemethodtype;
#define is_classobject(op) ((op)->ob_type == &Classtype)
@@ -38,9 +45,12 @@ extern typeobject Classtype, Instancetype, Instancemethodtype;
extern object *newclassobject PROTO((object *, object *, object *));
extern object *newinstanceobject PROTO((object *, object *));
-extern object *newinstancemethodobject PROTO((object *, object *));
+extern object *newinstancemethodobject PROTO((object *, object *, object *));
extern object *instancemethodgetfunc PROTO((object *));
extern object *instancemethodgetself PROTO((object *));
+extern object *instancemethodgetclass PROTO((object *));
extern object *instance_convert PROTO((object *, char *));
+
+extern int issubclass PROTO((object *, object *));
diff --git a/Include/eval.h b/Include/eval.h
index 8ac672f..a7a0ec8 100644
--- a/Include/eval.h
+++ b/Include/eval.h
@@ -24,4 +24,5 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* Interface to execute compiled code */
-object *eval_code PROTO((codeobject *, object *, object *, object *));
+object *eval_code
+ PROTO((codeobject *, object *, object *, object *, object *));
diff --git a/Include/frameobject.h b/Include/frameobject.h
index d46b454..2056e06 100644
--- a/Include/frameobject.h
+++ b/Include/frameobject.h
@@ -36,6 +36,7 @@ typedef struct _frame {
codeobject *f_code; /* code segment */
object *f_globals; /* global symbol table (dictobject) */
object *f_locals; /* local symbol table (dictobject) */
+ object *f_class; /* class context (classobject or NULL) */
object *f_fastlocals; /* fast local variables (listobject) */
object *f_localmap; /* local variable names (dictobject) */
object **f_valuestack; /* malloc'ed array */
@@ -55,7 +56,7 @@ extern typeobject Frametype;
#define is_frameobject(op) ((op)->ob_type == &Frametype)
frameobject * newframeobject PROTO(
- (frameobject *, codeobject *, object *, object *, int, int));
+ (frameobject *, codeobject *, object *, object *, object *, int, int));
/* The rest of the interface is specific for frame objects */
diff --git a/Objects/accessobject.c b/Objects/accessobject.c
new file mode 100644
index 0000000..41790cd
--- /dev/null
+++ b/Objects/accessobject.c
@@ -0,0 +1,320 @@
+/***********************************************************
+Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum,
+Amsterdam, The Netherlands.
+
+ All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* Access object implementation */
+
+#include "allobjects.h"
+
+#include "structmember.h"
+#include "modsupport.h" /* For getargs() etc. */
+
+typedef struct {
+ OB_HEAD
+ object *ac_value;
+ object *ac_class;
+ typeobject *ac_type;
+ int ac_mode;
+} accessobject;
+
+/* Forward */
+static int typecheck PROTO((object *, typeobject *));
+static int classcheck PROTO((object *, object *, int, int));
+
+object *
+newaccessobject(value, class, type, mode)
+ object *value;
+ object *class;
+ typeobject *type;
+ int mode;
+{
+ accessobject *ap;
+ if (class != NULL && !is_classobject(class)) {
+ err_badcall();
+ return NULL;
+ }
+ if (!typecheck(value, type)) {
+ err_setstr(AccessError,
+ "access: initial value has inappropriate type");
+ return NULL;
+ }
+ ap = NEWOBJ(accessobject, &Accesstype);
+ if (ap == NULL)
+ return NULL;
+ XINCREF(value);
+ ap->ac_value = value;
+ XINCREF(class);
+ ap->ac_class = class;
+ XINCREF(type);
+ ap->ac_type = (typeobject *)type;
+ ap->ac_mode = mode;
+ return (object *)ap;
+}
+
+object *
+cloneaccessobject(op)
+ object *op;
+{
+ register accessobject *ap;
+ if (!is_accessobject(op)) {
+ err_badcall();
+ return NULL;
+ }
+ ap = (accessobject *)op;
+ return newaccessobject(ap->ac_value, ap->ac_class,
+ ap->ac_type, ap->ac_mode);
+}
+
+void
+setaccessowner(op, class)
+ object *op;
+ object *class;
+{
+ register accessobject *ap;
+ if (!is_accessobject(op) || class != NULL && !is_classobject(class))
+ return; /* XXX no error */
+ ap = (accessobject *)op;
+ XDECREF(ap->ac_class);
+ XINCREF(class);
+ ap->ac_class = class;
+}
+
+object *
+getaccessvalue(op, class)
+ object *op;
+ object *class;
+{
+ register accessobject *ap;
+ if (!is_accessobject(op)) {
+ err_badcall();
+ return NULL;
+ }
+ ap = (accessobject *)op;
+
+ if (!classcheck(class, ap->ac_class, AC_R, ap->ac_mode)) {
+ err_setstr(AccessError, "read access denied");
+ return NULL;
+ }
+
+ if (ap->ac_value == NULL) {
+ err_setstr(AccessError, "no current value");
+ return NULL;
+ }
+ INCREF(ap->ac_value);
+ return ap->ac_value;
+}
+
+int
+setaccessvalue(op, class, value)
+ object *op;
+ object *class;
+ object *value;
+{
+ register accessobject *ap;
+ if (!is_accessobject(op)) {
+ err_badcall();
+ return -1;
+ }
+ ap = (accessobject *)op;
+
+ if (!classcheck(class, ap->ac_class, AC_W, ap->ac_mode)) {
+ err_setstr(AccessError, "write access denied");
+ return -1;
+ }
+
+ if (!typecheck(value, ap->ac_type)) {
+ err_setstr(AccessError, "assign value of inappropriate type");
+ return -1;
+ }
+
+ if (value == NULL) { /* Delete it */
+ if (ap->ac_value == NULL) {
+ err_setstr(AccessError, "no current value");
+ return -1;
+ }
+ DECREF(ap->ac_value);
+ ap->ac_value = NULL;
+ return 0;
+ }
+ XDECREF(ap->ac_value);
+ INCREF(value);
+ ap->ac_value = value;
+ return 0;
+}
+
+static int
+typecheck(value, type)
+ object *value;
+ typeobject *type;
+{
+ object *x;
+ if (value == NULL || type == NULL)
+ return 1; /* No check */
+ if (value->ob_type == type)
+ return 1; /* Exact match */
+ if (type == &Anynumbertype) {
+ if (value->ob_type->tp_as_number == NULL)
+ return 0;
+ if (!is_instanceobject(value))
+ return 1;
+ /* For instances, make sure it really looks like a number */
+ x = getattr(value, "__sub__");
+ if (x == NULL) {
+ err_clear();
+ return 0;
+ }
+ DECREF(x);
+ return 1;
+ }
+ if (type == &Anysequencetype) {
+ if (value->ob_type->tp_as_sequence == NULL)
+ return 0;
+ if (!is_instanceobject(value))
+ return 1;
+ /* For instances, make sure it really looks like a sequence */
+ x = getattr(value, "__getslice__");
+ if (x == NULL) {
+ err_clear();
+ return 0;
+ }
+ DECREF(x);
+ return 1;
+ }
+ if (type == &Anymappingtype) {
+ if (value->ob_type->tp_as_mapping == NULL)
+ return 0;
+ if (!is_instanceobject(value))
+ return 1;
+ /* For instances, make sure it really looks like a mapping */
+ x = getattr(value, "__getitem__");
+ if (x == NULL) {
+ err_clear();
+ return 0;
+ }
+ DECREF(x);
+ return 1;
+ }
+ return 0;
+}
+
+static int
+classcheck(caller, owner, access, mode)
+ object *caller;
+ object *owner;
+ int access;
+ int mode;
+{
+ if (caller == owner && owner != NULL)
+ return access & mode & (AC_PRIVATE|AC_PROTECTED|AC_PUBLIC);
+ if (caller != NULL && owner != NULL && issubclass(caller, owner))
+ return access & mode & (AC_PROTECTED|AC_PUBLIC);
+ return access & mode & AC_PUBLIC;
+}
+
+/* Access methods */
+
+static void
+access_dealloc(ap)
+ accessobject *ap;
+{
+ XDECREF(ap->ac_value);
+ XDECREF(ap->ac_class);
+ XDECREF(ap->ac_type);
+ DEL(ap);
+}
+
+#define OFF(x) offsetof(accessobject, x)
+
+static struct memberlist access_memberlist[] = {
+ {"ac_value", T_OBJECT, OFF(ac_value)},
+ {"ac_class", T_OBJECT, OFF(ac_class)},
+ {"ac_type", T_OBJECT, OFF(ac_type)},
+ {"ac_mode", T_INT, OFF(ac_mode)},
+ {NULL} /* Sentinel */
+};
+
+static object *
+access_getattr(ap, name)
+ accessobject *ap;
+ char *name;
+{
+ return getmember((char *)ap, access_memberlist, name);
+}
+
+static object *
+access_repr(ap)
+ accessobject *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>",
+ class ? getstringvalue(class->cl_name) : "-",
+ type ? type->tp_name : "-",
+ ap->ac_mode);
+ return newstringobject(buf);
+}
+
+typeobject Accesstype = {
+ OB_HEAD_INIT(&Typetype)
+ 0, /*ob_size*/
+ "access", /*tp_name*/
+ sizeof(accessobject), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ access_dealloc, /*tp_dealloc*/
+ 0, /*tp_print*/
+ access_getattr, /*tp_getattr*/
+ 0, /*tp_setattr*/
+ 0, /*tp_compare*/
+ access_repr, /*tp_repr*/
+ 0, /*tp_as_number*/
+ 0, /*tp_as_sequence*/
+ 0, /*tp_as_mapping*/
+ 0, /*tp_hash*/
+};
+
+/* Dummy type objects to indicate classes of types */
+
+/* XXX This should be replaced by a more general "subclassing"
+ XXX mechanism for type objects... */
+
+typeobject Anynumbertype = {
+ OB_HEAD_INIT(&Typetype)
+ 0, /*ob_size*/
+ "*number*", /*tp_name*/
+};
+
+/* XXX Should really distinguish mutable and immutable sequences as well */
+
+typeobject Anysequencetype = {
+ OB_HEAD_INIT(&Typetype)
+ 0, /*ob_size*/
+ "*sequence*", /*tp_name*/
+};
+
+typeobject Anymappingtype = {
+ OB_HEAD_INIT(&Typetype)
+ 0, /*ob_size*/
+ "*mapping*", /*tp_name*/
+};
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);
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index aa29795..7c2aeae 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -38,6 +38,7 @@ static struct memberlist frame_memberlist[] = {
{"f_code", T_OBJECT, OFF(f_code)},
{"f_globals", T_OBJECT, OFF(f_globals)},
{"f_locals", T_OBJECT, OFF(f_locals)},
+ {"f_class", T_OBJECT, OFF(f_class)},
/* {"f_fastlocals",T_OBJECT, OFF(f_fastlocals)}, /* XXX Unsafe */
{"f_localmap", T_OBJECT, OFF(f_localmap)},
{"f_lasti", T_INT, OFF(f_lasti)},
@@ -84,6 +85,7 @@ frame_dealloc(f)
XDECREF(f->f_code);
XDECREF(f->f_globals);
XDECREF(f->f_locals);
+ XDECREF(f->f_class);
XDECREF(f->f_fastlocals);
XDECREF(f->f_localmap);
f->f_back = free_list;
@@ -108,11 +110,12 @@ typeobject Frametype = {
};
frameobject *
-newframeobject(back, code, globals, locals, nvalues, nblocks)
+newframeobject(back, code, globals, locals, class, nvalues, nblocks)
frameobject *back;
codeobject *code;
object *globals;
object *locals;
+ object *class;
int nvalues;
int nblocks;
{
@@ -121,6 +124,7 @@ newframeobject(back, code, globals, locals, nvalues, nblocks)
code == NULL || !is_codeobject(code) ||
globals == NULL || !is_dictobject(globals) ||
locals == NULL || !is_dictobject(locals) ||
+ (class != NULL && !is_classobject(class)) ||
nvalues < 0 || nblocks < 0) {
err_badcall();
return NULL;
@@ -146,6 +150,8 @@ newframeobject(back, code, globals, locals, nvalues, nblocks)
f->f_globals = globals;
INCREF(locals);
f->f_locals = locals;
+ XINCREF(class);
+ f->f_class = class;
f->f_fastlocals = NULL;
f->f_localmap = NULL;
if (nvalues > f->f_nvalues || f->f_valuestack == NULL) {
diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c
index 8949c7d..5c0db15 100644
--- a/Objects/moduleobject.c
+++ b/Objects/moduleobject.c
@@ -25,6 +25,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* Module object implementation */
#include "allobjects.h"
+#include "ceval.h"
typedef struct {
OB_HEAD
@@ -111,7 +112,7 @@ module_getattr(m, name)
err_setstr(AttributeError, name);
else {
if (is_accessobject(res))
- res = getaccessvalue(res, (object *)NULL);
+ res = getaccessvalue(res, getclass());
else
INCREF(res);
}
@@ -134,7 +135,7 @@ module_setattr(m, name, v)
}
ac = dictlookup(m->md_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(m->md_dict, name);
if (rv < 0)
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 3d9504b..c2c2966 100644
--- a/Python/bltinmodule.c
+++ b/Python/bltinmodule.c
@@ -212,7 +212,7 @@ exec_eval(v, start)
}
if (is_codeobject(str))
return eval_code((codeobject *) str, globals, locals,
- (object *)NULL);
+ (object *)NULL, (object *)NULL);
s = getstringvalue(str);
if (strlen(s) != getstringsize(str)) {
err_setstr(ValueError, "embedded '\\0' in string arg");
diff --git a/Python/ceval.c b/Python/ceval.c
index 57abda6..39a20d7 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -161,10 +161,11 @@ enum why_code {
/* Interpreter main loop */
object *
-eval_code(co, globals, locals, arg)
+eval_code(co, globals, locals, class, arg)
codeobject *co;
object *globals;
object *locals;
+ object *class;
object *arg;
{
register unsigned char *next_instr;
@@ -244,6 +245,7 @@ eval_code(co, globals, locals, arg)
co, /*code*/
globals, /*globals*/
locals, /*locals*/
+ class, /*class*/
50, /*nvalues*/
20); /*nblocks*/
if (f == NULL)
@@ -759,7 +761,7 @@ eval_code(co, globals, locals, arg)
v = POP();
u = dict2lookup(f->f_locals, w);
if (u != NULL && is_accessobject(u)) {
- err = setaccessvalue(u, (object *)NULL, v);
+ err = setaccessvalue(u, class, v);
DECREF(v);
break;
}
@@ -771,7 +773,7 @@ eval_code(co, globals, locals, arg)
w = GETNAMEV(oparg);
u = dict2lookup(f->f_locals, w);
if (u != NULL && is_accessobject(u)) {
- err = setaccessvalue(u, (object *)NULL,
+ err = setaccessvalue(u, class,
(object *)NULL);
break;
}
@@ -969,7 +971,7 @@ eval_code(co, globals, locals, arg)
v = POP();
u = dict2lookup(f->f_locals, w);
if (u != NULL && is_accessobject(u)) {
- err = setaccessvalue(u, (object *)NULL, v);
+ err = setaccessvalue(u, class, v);
DECREF(v);
break;
}
@@ -981,7 +983,7 @@ eval_code(co, globals, locals, arg)
w = GETNAMEV(oparg);
u = dict2lookup(f->f_locals, w);
if (u != NULL && is_accessobject(u)) {
- err = setaccessvalue(u, (object *)NULL,
+ err = setaccessvalue(u, class,
(object *)NULL);
break;
}
@@ -1012,11 +1014,12 @@ eval_code(co, globals, locals, arg)
}
}
if (is_accessobject(x)) {
- x = getaccessvalue(x, (object *)NULL);
+ x = getaccessvalue(x, class);
if (x == NULL)
break;
}
- INCREF(x);
+ else
+ INCREF(x);
PUSH(x);
break;
@@ -1033,11 +1036,12 @@ eval_code(co, globals, locals, arg)
}
}
if (is_accessobject(x)) {
- x = getaccessvalue(x, (object *)NULL);
+ x = getaccessvalue(x, class);
if (x == NULL)
break;
}
- INCREF(x);
+ else
+ INCREF(x);
PUSH(x);
break;
@@ -1049,11 +1053,12 @@ eval_code(co, globals, locals, arg)
break;
}
if (is_accessobject(x)) {
- x = getaccessvalue(x, (object *)NULL);
+ x = getaccessvalue(x, class);
if (x == NULL)
break;
}
- INCREF(x);
+ else
+ INCREF(x);
PUSH(x);
break;
@@ -1084,11 +1089,12 @@ eval_code(co, globals, locals, arg)
break;
}
if (is_accessobject(x)) {
- x = getaccessvalue(x, (object *)NULL);
+ x = getaccessvalue(x, class);
if (x == NULL)
break;
}
- INCREF(x);
+ else
+ INCREF(x);
PUSH(x);
break;
@@ -1096,7 +1102,7 @@ eval_code(co, globals, locals, arg)
v = POP();
w = GETLISTITEM(fastlocals, oparg);
if (w != NULL && is_accessobject(w)) {
- err = setaccessvalue(w, (object *)NULL, v);
+ err = setaccessvalue(w, class, v);
DECREF(v);
break;
}
@@ -1112,8 +1118,7 @@ eval_code(co, globals, locals, arg)
break;
}
if (w != NULL && is_accessobject(w)) {
- err = setaccessvalue(w, (object *)NULL,
- (object *)NULL);
+ err = setaccessvalue(w, class, (object *)NULL);
break;
}
DECREF(x);
@@ -1643,6 +1648,15 @@ getglobals()
return current_frame->f_globals;
}
+object *
+getclass()
+{
+ if (current_frame == NULL)
+ return NULL;
+ else
+ return current_frame->f_class;
+}
+
void
printtraceback(f)
object *f;
@@ -1974,37 +1988,41 @@ call_function(func, arg)
{
object *newarg = NULL;
object *newlocals, *newglobals;
+ object *class = NULL;
object *co, *v;
if (is_instancemethodobject(func)) {
- int argcount;
object *self = instancemethodgetself(func);
+ class = instancemethodgetclass(func);
func = instancemethodgetfunc(func);
- if (arg == NULL)
- argcount = 0;
- else if (is_tupleobject(arg))
- argcount = gettuplesize(arg);
- else
- argcount = 1;
- newarg = newtupleobject(argcount + 1);
- if (newarg == NULL)
- return NULL;
- INCREF(self);
- settupleitem(newarg, 0, self);
- if (arg != NULL && !is_tupleobject(arg)) {
- INCREF(arg);
- settupleitem(newarg, 1, arg);
- }
- else {
- int i;
- object *v;
- for (i = 0; i < argcount; i++) {
- v = gettupleitem(arg, i);
- XINCREF(v);
- settupleitem(newarg, i+1, v);
+ if (self != NULL) {
+ int argcount;
+ if (arg == NULL)
+ argcount = 0;
+ else if (is_tupleobject(arg))
+ argcount = gettuplesize(arg);
+ else
+ argcount = 1;
+ newarg = newtupleobject(argcount + 1);
+ if (newarg == NULL)
+ return NULL;
+ INCREF(self);
+ settupleitem(newarg, 0, self);
+ if (arg != NULL && !is_tupleobject(arg)) {
+ INCREF(arg);
+ settupleitem(newarg, 1, arg);
+ }
+ else {
+ int i;
+ object *v;
+ for (i = 0; i < argcount; i++) {
+ v = gettupleitem(arg, i);
+ XINCREF(v);
+ settupleitem(newarg, i+1, v);
+ }
}
+ arg = newarg;
}
- arg = newarg;
}
else {
if (!is_funcobject(func)) {
@@ -2031,7 +2049,7 @@ call_function(func, arg)
newglobals = getfuncglobals(func);
INCREF(newglobals);
- v = eval_code((codeobject *)co, newglobals, newlocals, arg);
+ v = eval_code((codeobject *)co, newglobals, newlocals, class, arg);
DECREF(newlocals);
DECREF(newglobals);
@@ -2367,10 +2385,10 @@ access_statement(name, mode, f)
int mode;
frameobject *f;
{
- object *value;
- int i = -1;
- object *ac;
- int ret;
+ object *value, *ac;
+ typeobject *type;
+ int fastind, ret;
+ fastind = -1;
if (f->f_localmap == NULL)
value = dict2lookup(f->f_locals, name);
else {
@@ -2378,12 +2396,13 @@ access_statement(name, mode, f)
if (value == NULL || !is_intobject(value))
value = NULL;
else {
- i = getintvalue(value);
- if (0 <= i && i < getlistsize(f->f_fastlocals))
- value = getlistitem(f->f_fastlocals, i);
+ fastind = getintvalue(value);
+ if (0 <= fastind &&
+ fastind < getlistsize(f->f_fastlocals))
+ value = getlistitem(f->f_fastlocals, fastind);
else {
value = NULL;
- i = -1;
+ fastind = -1;
}
}
}
@@ -2392,11 +2411,15 @@ access_statement(name, mode, f)
return -1;
}
err_clear();
- ac = newaccessobject(value, (object*)NULL, (typeobject*)NULL, mode);
+ if (value != NULL && value != None)
+ type = value->ob_type;
+ else
+ type = NULL;
+ ac = newaccessobject(value, (object*)NULL, type, mode);
if (ac == NULL)
return -1;
- if (i >= 0)
- ret = setlistitem(f->f_fastlocals, i, ac);
+ if (fastind >= 0)
+ ret = setlistitem(f->f_fastlocals, fastind, ac);
else {
ret = dict2insert(f->f_locals, name, ac);
DECREF(ac);
diff --git a/Python/compile.c b/Python/compile.c
index d9d661c..a8cd4e9 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -1429,8 +1429,8 @@ com_access_stmt(c, n)
/* Calculate the mode mask */
mode = 0;
for (j = i; j < NCH(n); j += 2) {
- int r=0,w=0,p=0;
- for (k=0; k<NCH(CHILD(n,j)); k++) {
+ int r = 0, w = 0, p = 0;
+ for (k = 0; k < NCH(CHILD(n,j)); k++) {
if (strequ(STR(CHILD(CHILD(n,j),k)), "public"))
p = 0;
else if (strequ(STR(CHILD(CHILD(n,j),k)), "protected"))
@@ -1446,7 +1446,7 @@ com_access_stmt(c, n)
STR(CHILD(CHILD(n,j),k)));
}
if (r == 0 && w == 0)
- r =w = 1;
+ r = w = 1;
if (p == 0) {
if (r == 1) mode |= AC_R_PUBLIC;
if (w == 1) mode |= AC_W_PUBLIC;
diff --git a/Python/import.c b/Python/import.c
index ec21b4c..395114b 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -303,7 +303,7 @@ get_module(m, name, m_ret)
}
}
}
- v = eval_code(co, d, d, (object *)NULL);
+ v = eval_code(co, d, d, (object *)NULL, (object *)NULL);
DECREF(co);
return v;
}
@@ -422,7 +422,7 @@ init_frozen(name)
return -1;
if ((m = add_module(name)) == NULL ||
(d = getmoduledict(m)) == NULL ||
- (v = eval_code(co, d, d, (object *)NULL)) == NULL) {
+ (v = eval_code(co, d, d, (object*)NULL, (object*)NULL)) == NULL) {
DECREF(co);
return -1;
}
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index 3898d13..b85be92 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -320,7 +320,7 @@ eval_node(n, filename, globals, locals)
freetree(n);
if (co == NULL)
return NULL;
- v = eval_code(co, globals, locals, (object *)NULL);
+ v = eval_code(co, globals, locals, (object *)NULL, (object *)NULL);
DECREF(co);
return v;
}