]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Access checks now work, at least for instance data (not for methods
authorGuido van Rossum <guido@python.org>
Thu, 20 May 1993 14:24:46 +0000 (14:24 +0000)
committerGuido van Rossum <guido@python.org>
Thu, 20 May 1993 14:24:46 +0000 (14:24 +0000)
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.

14 files changed:
Include/accessobject.h [new file with mode: 0644]
Include/ceval.h
Include/classobject.h
Include/eval.h
Include/frameobject.h
Objects/accessobject.c [new file with mode: 0644]
Objects/classobject.c
Objects/frameobject.c
Objects/moduleobject.c
Python/bltinmodule.c
Python/ceval.c
Python/compile.c
Python/import.c
Python/pythonrun.c

diff --git a/Include/accessobject.h b/Include/accessobject.h
new file mode 100644 (file)
index 0000000..1c67849
--- /dev/null
@@ -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;
index a9f79b52b4d9096bda53d90cba5ec5867e67076c..ab7659eaf58dfb4094b71efab27c58f9d49cf61f 100644 (file)
@@ -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 *));
index b9bbc9b6a7a7c6022c0b5f8691b83c06a216aeef..ec07b59b16c7946c9f10c5601ba629d60a6a1fe6 100644 (file)
@@ -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 *));
index 8ac672f3a0508ac0336b7ee9078382ee70d67bb0..a7a0ec8946352c4bf9bbfc46d767810f24f61f44 100644 (file)
@@ -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 *));
index d46b4541912ad526c6860f1421c098db43f86c35..2056e0628cd54d3dee02c4df068ae1490f56a164 100644 (file)
@@ -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 (file)
index 0000000..41790cd
--- /dev/null
@@ -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*/
+};
index bc61b649c142ae9237feb2206c691124185de0ed..e2a5e638173c1f4bd19d11f85f3b1def304a3577 100644 (file)
@@ -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);
index aa2979577e718f2299c77f53eec0e984de162556..7c2aeaeaba7d30b08c16dcfbce71b3c765d0361f 100644 (file)
@@ -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) {
index 8949c7d44b87c49ff5bfacdd2d60ac6f4695d0c3..5c0db153cc00264df51e0c4991c01ad0f74c5323 100644 (file)
@@ -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)
index 3d9504bedcd192ffdd47bdecfcbd71d2dfadce48..c2c29662b6bbf06c9e5ad2e8c47167af324df850 100644 (file)
@@ -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");
index 57abda606a0ee5f65211e1621487a580f860e5e4..39a20d7150da52ef984859fc3eb44b0f0b1a7802 100644 (file)
@@ -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);
index d9d661cbac69d4a5415ab9667f98a5e140b407a7..a8cd4e9418c5a8fabbda2a28ad144cbdaacc47b8 100644 (file)
@@ -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;
index ec21b4c85e83bc739df8fab27e26ac182ac64ecc..395114be854c7034aa9a43f8e3ba48651d6bcdfb 100644 (file)
@@ -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;
        }
index 3898d13af2a414525d632ee6ce0315671431e175..b85be921c08c3db32f1e724eb0caaa694d8ef6aa 100644 (file)
@@ -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;
 }