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.
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 *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 @@
 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 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 @@
 
 /* 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 @@
 	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 @@
 #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 @@
 #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 @@
 		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 @@
 	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 @@
 		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 @@
 			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 @@
 	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 @@
 	register instanceobject *inst;
 	object *v;
 	object *init;
-	int pos;
-	object *key, *value;
 	if (!is_classobject(class)) {
 		err_badcall();
 		return NULL;
@@ -209,26 +276,12 @@
 		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 @@
 	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 @@
 	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 @@
 			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 @@
 }
 
 
-/* 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 @@
 		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 @@
 	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 @@
 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 @@
 	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 @@
 	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 @@
 	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 @@
 	{"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 @@
 	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 @@
 };
 
 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 @@
 		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 @@
 		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 @@
 /* Module object implementation */
 
 #include "allobjects.h"
+#include "ceval.h"
 
 typedef struct {
 	OB_HEAD
@@ -111,7 +112,7 @@
 		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 @@
 	}
 	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 @@
 	}
 	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 @@
 /* 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 @@
 			co,			/*code*/
 			globals,		/*globals*/
 			locals,			/*locals*/
+			class,			/*class*/
 			50,			/*nvalues*/
 			20);			/*nblocks*/
 	if (f == NULL)
@@ -759,7 +761,7 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 				}
 			}
 			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 @@
 				}
 			}
 			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 @@
 				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 @@
 				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 @@
 			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 @@
 				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 @@
 		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 @@
 {
 	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 @@
 	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 @@
 	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 @@
 		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 @@
 		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 @@
 	/* 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 @@
 					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 @@
 			}
 		}
 	}
-	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 @@
 		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 @@
 	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;
 }