Several changes in one:

(1) dictionaries/mappings now have attributes values() and items() as
well as keys(); at the C level, use the new function mappinggetnext()
to iterate over a dictionary.

(2) "class C(): ..." is now illegal; you must write "class C: ...".

(3) Class objects now know their own name (finally!); and minor
improvements to the way how classes, functions and methods are
represented as strings.

(4) Added an "access" statement and semantics.  (This is still
experimental -- as long as you don't use the keyword 'access' nothing
should be changed.)
This commit is contained in:
Guido van Rossum 1993-05-19 14:50:45 +00:00
parent 687dd13bfe
commit 25831652fd
21 changed files with 1223 additions and 823 deletions

View File

@ -2,6 +2,12 @@
# Change log:
# 19-May-93:
# Add access statement
# 18-May-93:
# Abolish old class header syntax
# 06-Apr-92:
# Use only '*' for varargs list
@ -81,7 +87,7 @@ fplist: fpdef (',' fpdef)* [',']
stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt
small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | access_stmt
expr_stmt: (exprlist '=')* exprlist
# For assignments, additional restrictions enforced by the interpreter
print_stmt: 'print' (test ',')* [test]
@ -94,6 +100,11 @@ return_stmt: 'return' [testlist]
raise_stmt: 'raise' test [',' test]
import_stmt: 'import' NAME (',' NAME)* | 'from' NAME 'import' ('*' | NAME (',' NAME)*)
global_stmt: 'global' NAME (',' NAME)*
access_stmt: 'access' NAME (',' NAME)* ':' accesstype (',' accesstype)*
accesstype: NAME+
# accesstype should be ('public' | 'protected' | 'private') ['read'] ['write']
# but can't be because that would create undesirable reserved words!
compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
while_stmt: 'while' test ':' suite ['else' ':' suite]
@ -122,9 +133,4 @@ exprlist: expr (',' expr)* [',']
testlist: test (',' test)* [',']
dictmaker: test ':' test (',' test ':' test)* [',']
# New class syntax should be:
# classdef: class NAME ['(' testlist ')'] ':' suite
# but merged with old syntax for compatibility it becomes:
classdef: 'class' NAME ['(' testlist ')' |'(' ')' ['=' baselist]] ':' suite
baselist: atom arguments (',' atom arguments)*
arguments: '(' ')'
classdef: class NAME ['(' testlist ')'] ':' suite

View File

@ -36,6 +36,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "object.h"
#include "objimpl.h"
#include "accessobject.h"
#include "intobject.h"
#include "longobject.h"
#include "floatobject.h"

View File

@ -37,7 +37,7 @@ extern typeobject Classtype, Instancetype, Instancemethodtype;
#define is_instancemethodobject(op) ((op)->ob_type == &Instancemethodtype)
extern object *newclassobject PROTO((object *, object *, object *));
extern object *newinstanceobject PROTO((object *));
extern object *newinstanceobject PROTO((object *, object *));
extern object *newinstancemethodobject PROTO((object *, object *));
extern object *instancemethodgetfunc PROTO((object *));

View File

@ -33,12 +33,9 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
extern object *dictlookup PROTO((object *dp, char *key));
extern int dictinsert PROTO((object *dp, char *key, object *item));
extern int dictremove PROTO((object *dp, char *key));
extern char *getdictkey PROTO((object *dp, int i));
#define getdictsize getmappingsize
#define getdictkeys getmappingkeys
#define getdict2key getmappingkey
#define dict2lookup mappinglookup
#define dict2insert mappinginsert
#define dict2remove mappingremove

View File

@ -33,7 +33,9 @@ void err_clear PROTO((void));
/* Predefined exceptions */
extern object *AccessError;
extern object *AttributeError;
extern object *ConflictError;
extern object *EOFError;
extern object *IOError;
extern object *ImportError;
@ -59,3 +61,5 @@ extern object *err_errno PROTO((object *));
extern void err_input PROTO((int));
extern void err_badcall PROTO((void));
extern object *err_getexc PROTO((void));

View File

@ -24,6 +24,13 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/* Function object interface */
typedef struct {
OB_HEAD
object *func_code;
object *func_globals;
object *func_name;
} funcobject;
extern typeobject Functype;
#define is_funcobject(op) ((op)->ob_type == &Functype)

View File

@ -21,31 +21,31 @@
#define raise_stmt 276
#define import_stmt 277
#define global_stmt 278
#define compound_stmt 279
#define if_stmt 280
#define while_stmt 281
#define for_stmt 282
#define try_stmt 283
#define except_clause 284
#define suite 285
#define test 286
#define and_test 287
#define not_test 288
#define comparison 289
#define comp_op 290
#define expr 291
#define xor_expr 292
#define and_expr 293
#define shift_expr 294
#define arith_expr 295
#define term 296
#define factor 297
#define atom 298
#define trailer 299
#define subscript 300
#define exprlist 301
#define testlist 302
#define dictmaker 303
#define classdef 304
#define baselist 305
#define arguments 306
#define access_stmt 279
#define accesstype 280
#define compound_stmt 281
#define if_stmt 282
#define while_stmt 283
#define for_stmt 284
#define try_stmt 285
#define except_clause 286
#define suite 287
#define test 288
#define and_test 289
#define not_test 290
#define comparison 291
#define comp_op 292
#define expr 293
#define xor_expr 294
#define and_expr 295
#define shift_expr 296
#define arith_expr 297
#define term 298
#define factor 299
#define atom 300
#define trailer 301
#define subscript 302
#define exprlist 303
#define testlist 304
#define dictmaker 305
#define classdef 306

View File

@ -22,22 +22,19 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
******************************************************************/
/*
Mapping object type -- mapping from object to object.
These functions set errno for errors. Functions mappingremove() and
mappinginsert() return nonzero for errors, getmappingsize() returns -1,
the others NULL. A successful call to mappinginsert() calls INCREF()
for the inserted item.
*/
/* Mapping object type -- mapping from hashable object to object */
extern typeobject Mappingtype;
#define is_mappingobject(op) ((op)->ob_type == &Mappingtype)
extern object *newmappingobject PROTO((void));
extern object *mappinglookup PROTO((object *dp, object *key));
extern int mappinginsert PROTO((object *dp, object *key, object *item));
extern int mappingremove PROTO((object *dp, object *key));
extern int getmappingsize PROTO((object *dp));
extern object *getmappingkey PROTO((object *dp, int i));
extern object *getmappingkeys PROTO((object *dp));
extern object *mappinglookup PROTO((object *mp, object *key));
extern int mappinginsert PROTO((object *mp, object *key, object *item));
extern int mappingremove PROTO((object *mp, object *key));
extern void mappingclear PROTO((object *mp));
extern int mappinggetnext
PROTO((object *mp, int *pos, object **key, object **value));
extern object *getmappingkeys PROTO((object *mp));
extern object *getmappingvalues PROTO((object *mp));
extern object *getmappingitems PROTO((object *mp));

View File

@ -100,6 +100,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#define COMPARE_OP 106 /* Comparison operator */
#define IMPORT_NAME 107 /* Index in name list */
#define IMPORT_FROM 108 /* Index in name list */
#define ACCESS_MODE 109 /* Name (mode is int on top of stack) */
#define JUMP_FORWARD 110 /* Number of bytes to skip */
#define JUMP_IF_FALSE 111 /* "" */

View File

@ -33,7 +33,9 @@ void err_clear PROTO((void));
/* Predefined exceptions */
extern object *AccessError;
extern object *AttributeError;
extern object *ConflictError;
extern object *EOFError;
extern object *IOError;
extern object *ImportError;
@ -59,3 +61,5 @@ extern object *err_errno PROTO((object *));
extern void err_input PROTO((int));
extern void err_badcall PROTO((void));
extern object *err_getexc PROTO((void));

View File

@ -29,9 +29,6 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "structmember.h"
#include "ceval.h"
extern typeobject MappingInstancetype;
extern typeobject SequenceInstancetype;
typedef struct {
OB_HEAD
object *cl_bases; /* A tuple */
@ -102,7 +99,10 @@ class_getattr(op, name)
}
v = dictlookup(op->cl_methods, name);
if (v != NULL) {
INCREF(v);
if (is_accessobject(v))
v = getaccessvalue(v, (object *)NULL);
else
INCREF(v);
return v;
}
{
@ -126,6 +126,7 @@ class_setattr(op, name, v)
char *name;
object *v;
{
object *ac;
if (name[0] == '_' && name[1] == '_') {
int n = strlen(name);
if (name[n-1] == '_' && name[n-2] == '_') {
@ -133,6 +134,9 @@ class_setattr(op, name, v)
return -1;
}
}
ac = dictlookup(op->cl_methods, name);
if (ac != NULL && is_accessobject(ac))
return setaccessvalue(ac, (object *)NULL, v);
if (v == NULL) {
int rv = dictremove(op->cl_methods, name);
if (rv < 0)
@ -144,6 +148,20 @@ class_setattr(op, name, v)
return dictinsert(op->cl_methods, name, v);
}
static object *
class_repr(op)
classobject *op;
{
char buf[140];
char *name;
if (op->cl_name == NULL || !is_stringobject(op->cl_name))
name = "?";
else
name = getstringvalue(op->cl_name);
sprintf(buf, "<class %.100s at %lx>", name, (long)op);
return newstringobject(buf);
}
typeobject Classtype = {
OB_HEAD_INIT(&Typetype)
0,
@ -155,7 +173,7 @@ typeobject Classtype = {
class_getattr, /*tp_getattr*/
class_setattr, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
class_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
@ -170,12 +188,18 @@ typedef struct {
object *in_attr; /* A dictionary */
} instanceobject;
static object *instance_getattr PROTO((instanceobject *, char *));
object *
newinstanceobject(class)
register object *class;
newinstanceobject(class, arg)
object *class;
object *arg;
{
register instanceobject *inst;
object *v;
object *init;
int pos;
object *key, *value;
if (!is_classobject(class)) {
err_badcall();
return NULL;
@ -187,9 +211,52 @@ newinstanceobject(class)
inst->in_class = (classobject *)class;
inst->in_attr = newdictobject();
if (inst->in_attr == NULL) {
error:
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();
if (arg != NULL && !(is_tupleobject(arg) &&
gettuplesize(arg) == 0)) {
err_setstr(TypeError,
"this classobject() takes no arguments");
DECREF(inst);
inst = NULL;
}
}
else {
object *res = call_object(init, arg);
DECREF(init);
if (res == NULL) {
DECREF(inst);
inst = NULL;
}
else {
if (res != None) {
err_setstr(TypeError,
"__init__() should return None");
DECREF(inst);
inst = NULL;
}
DECREF(res);
}
}
return (object *)inst;
}
@ -199,9 +266,29 @@ static void
instance_dealloc(inst)
register instanceobject *inst;
{
object *error_type, *error_value;
object *del;
/* Call the __del__ method if it exists. First temporarily
revive the object and save the current exception, if any. */
INCREF(inst);
err_get(&error_type, &error_value);
if ((del = instance_getattr(inst, "__del__")) != NULL) {
object *args = newtupleobject(0);
object *res = args;
if (res != NULL)
res = call_object(del, args);
XDECREF(args);
DECREF(del);
XDECREF(res);
/* XXX If __del__ raised an exception, it is ignored! */
}
/* Restore the saved exception and undo the temporary revival */
err_setval(error_type, error_value);
/* Can't use DECREF here, it would cause a recursive call */
if (--inst->ob_refcnt > 0)
return; /* __del__ added a reference; don't delete now */
DECREF(inst->in_class);
if (inst->in_attr != NULL)
DECREF(inst->in_attr);
XDECREF(inst->in_attr);
free((ANY *)inst);
}
@ -221,7 +308,10 @@ instance_getattr(inst, name)
}
v = dictlookup(inst->in_attr, name);
if (v != NULL) {
INCREF(v);
if (is_accessobject(v))
v = getaccessvalue(v, (object *)NULL);
else
INCREF(v);
return v;
}
v = class_getattr(inst->in_class, name);
@ -243,6 +333,7 @@ instance_setattr(inst, name, v)
char *name;
object *v;
{
object *ac;
if (name[0] == '_' && name[1] == '_') {
int n = strlen(name);
if (name[n-1] == '_' && name[n-2] == '_') {
@ -250,6 +341,9 @@ instance_setattr(inst, name, v)
return -1;
}
}
ac = dictlookup(inst->in_attr, name);
if (ac != NULL && is_accessobject(ac))
return setaccessvalue(ac, (object *)NULL, v);
if (v == NULL) {
int rv = dictremove(inst->in_attr, name);
if (rv < 0)
@ -270,9 +364,15 @@ instance_repr(inst)
func = instance_getattr(inst, "__repr__");
if (func == NULL) {
char buf[80];
char buf[140];
object *classname = inst->in_class->cl_name;
char *cname;
if (classname != NULL && is_stringobject(classname))
cname = getstringvalue(classname);
else
cname = "?";
err_clear();
sprintf(buf, "<instance object at %lx>", (long)inst);
sprintf(buf, "<%.100s instance at %lx>", cname, (long)inst);
return newstringobject(buf);
}
res = call_object(func, (object *)NULL);
@ -773,6 +873,7 @@ typeobject Instancetype = {
0,
instance_dealloc, /*tp_dealloc*/
0, /*tp_print*/
(object * (*) FPROTO((object *, char *)))
instance_getattr, /*tp_getattr*/
instance_setattr, /*tp_setattr*/
instance_compare, /*tp_compare*/
@ -879,6 +980,28 @@ instancemethod_compare(a, b)
return cmp;
}
static object *
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);
else
cname = "?";
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);
return newstringobject(buf);
}
static long
instancemethod_hash(a)
instancemethodobject *a;
@ -904,7 +1027,7 @@ typeobject Instancemethodtype = {
instancemethod_getattr, /*tp_getattr*/
0, /*tp_setattr*/
instancemethod_compare, /*tp_compare*/
0, /*tp_repr*/
instancemethod_repr, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/

View File

@ -307,39 +307,49 @@ mappingremove(op, key)
return 0;
}
int
getmappingsize(op)
register object *op;
void
mappingclear(op)
object *op;
{
if (!is_mappingobject(op)) {
err_badcall();
return -1;
int i;
register mappingobject *mp;
if (!is_mappingobject(op))
return;
mp = (mappingobject *)op;
for (i = 0; i < mp->ma_size; i++) {
XDECREF(mp->ma_table[i].me_key);
XDECREF(mp->ma_table[i].me_value);
mp->ma_table[i].me_key = NULL;
mp->ma_table[i].me_value = NULL;
}
return ((mappingobject *)op) -> ma_size;
mp->ma_used = 0;
}
object *
getmappingkey(op, i)
int
mappinggetnext(op, ppos, pkey, pvalue)
object *op;
register int i;
int *ppos;
object **pkey;
object **pvalue;
{
/* XXX This can't return errors since its callers assume
that NULL means there was no key at that point */
int i;
register mappingobject *mp;
if (!is_mappingobject(op)) {
/* err_badcall(); */
return NULL;
}
if (!is_dictobject(op))
return 0;
mp = (mappingobject *)op;
if (i < 0 || i >= mp->ma_size) {
/* err_badarg(); */
return NULL;
}
if (mp->ma_table[i].me_value == NULL) {
/* Not an error! */
return NULL;
}
return (object *) mp->ma_table[i].me_key;
i = *ppos;
if (i < 0)
return 0;
while (i < mp->ma_size && mp->ma_table[i].me_value == NULL)
i++;
*ppos = i+1;
if (i >= mp->ma_size)
return 0;
if (pkey)
*pkey = mp->ma_table[i].me_key;
if (pvalue)
*pvalue = mp->ma_table[i].me_value;
return 1;
}
/* Methods */
@ -488,6 +498,61 @@ mapping_keys(mp, args)
return v;
}
static object *
mapping_values(mp, args)
register mappingobject *mp;
object *args;
{
register object *v;
register int i, j;
if (!getnoarg(args))
return NULL;
v = newlistobject(mp->ma_used);
if (v == NULL)
return NULL;
for (i = 0, j = 0; i < mp->ma_size; i++) {
if (mp->ma_table[i].me_value != NULL) {
object *value = mp->ma_table[i].me_value;
INCREF(value);
setlistitem(v, j, value);
j++;
}
}
return v;
}
static object *
mapping_items(mp, args)
register mappingobject *mp;
object *args;
{
register object *v;
register int i, j;
if (!getnoarg(args))
return NULL;
v = newlistobject(mp->ma_used);
if (v == NULL)
return NULL;
for (i = 0, j = 0; i < mp->ma_size; i++) {
if (mp->ma_table[i].me_value != NULL) {
object *key = mp->ma_table[i].me_key;
object *value = mp->ma_table[i].me_value;
object *item = newtupleobject(2);
if (item == NULL) {
DECREF(v);
return NULL;
}
INCREF(key);
settupleitem(item, 0, key);
INCREF(value);
settupleitem(item, 1, value);
setlistitem(v, j, item);
j++;
}
}
return v;
}
object *
getmappingkeys(mp)
object *mp;
@ -499,6 +564,28 @@ getmappingkeys(mp)
return mapping_keys((mappingobject *)mp, (object *)NULL);
}
object *
getmappingvalues(mp)
object *mp;
{
if (mp == NULL || !is_mappingobject(mp)) {
err_badcall();
return NULL;
}
return mapping_values((mappingobject *)mp, (object *)NULL);
}
object *
getmappingitems(mp)
object *mp;
{
if (mp == NULL || !is_mappingobject(mp)) {
err_badcall();
return NULL;
}
return mapping_values((mappingobject *)mp, (object *)NULL);
}
static int
mapping_compare(a, b)
mappingobject *a, *b;
@ -582,8 +669,10 @@ mapping_has_key(mp, args)
}
static struct methodlist mapp_methods[] = {
{"keys", mapping_keys},
{"has_key", mapping_has_key},
{"items", mapping_items},
{"keys", mapping_keys},
{"values", mapping_values},
{NULL, NULL} /* sentinel */
};
@ -697,14 +786,3 @@ dictremove(v, key)
}
return mappingremove(v, last_name_object);
}
char *
getdictkey(v, i)
object *v;
int i;
{
object *key = getmappingkey(v, i);
if (key == NULL)
return NULL;
return getstringvalue(key);
}

View File

@ -28,12 +28,6 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "compile.h"
#include "structmember.h"
typedef struct {
OB_HEAD
object *func_code;
object *func_globals;
} funcobject;
object *
newfuncobject(code, globals)
object *code;
@ -45,6 +39,8 @@ newfuncobject(code, globals)
op->func_code = code;
INCREF(globals);
op->func_globals = globals;
op->func_name = ((codeobject*)(op->func_code))->co_name;
INCREF(op->func_name);
}
return (object *)op;
}
@ -78,6 +74,7 @@ getfuncglobals(op)
static struct memberlist func_memberlist[] = {
{"func_code", T_OBJECT, OFF(func_code), READONLY},
{"func_globals",T_OBJECT, OFF(func_globals), READONLY},
{"func_name", T_OBJECT, OFF(func_name), READONLY},
{NULL} /* Sentinel */
};
@ -104,7 +101,7 @@ func_repr(op)
{
char buf[140];
sprintf(buf, "<function %.100s at %lx>",
getstringvalue(((codeobject*)(op->func_code))->co_name),
getstringvalue(op->func_name),
(long)op);
return newstringobject(buf);
}

View File

@ -307,39 +307,49 @@ mappingremove(op, key)
return 0;
}
int
getmappingsize(op)
register object *op;
void
mappingclear(op)
object *op;
{
if (!is_mappingobject(op)) {
err_badcall();
return -1;
int i;
register mappingobject *mp;
if (!is_mappingobject(op))
return;
mp = (mappingobject *)op;
for (i = 0; i < mp->ma_size; i++) {
XDECREF(mp->ma_table[i].me_key);
XDECREF(mp->ma_table[i].me_value);
mp->ma_table[i].me_key = NULL;
mp->ma_table[i].me_value = NULL;
}
return ((mappingobject *)op) -> ma_size;
mp->ma_used = 0;
}
object *
getmappingkey(op, i)
int
mappinggetnext(op, ppos, pkey, pvalue)
object *op;
register int i;
int *ppos;
object **pkey;
object **pvalue;
{
/* XXX This can't return errors since its callers assume
that NULL means there was no key at that point */
int i;
register mappingobject *mp;
if (!is_mappingobject(op)) {
/* err_badcall(); */
return NULL;
}
if (!is_dictobject(op))
return 0;
mp = (mappingobject *)op;
if (i < 0 || i >= mp->ma_size) {
/* err_badarg(); */
return NULL;
}
if (mp->ma_table[i].me_value == NULL) {
/* Not an error! */
return NULL;
}
return (object *) mp->ma_table[i].me_key;
i = *ppos;
if (i < 0)
return 0;
while (i < mp->ma_size && mp->ma_table[i].me_value == NULL)
i++;
*ppos = i+1;
if (i >= mp->ma_size)
return 0;
if (pkey)
*pkey = mp->ma_table[i].me_key;
if (pvalue)
*pvalue = mp->ma_table[i].me_value;
return 1;
}
/* Methods */
@ -488,6 +498,61 @@ mapping_keys(mp, args)
return v;
}
static object *
mapping_values(mp, args)
register mappingobject *mp;
object *args;
{
register object *v;
register int i, j;
if (!getnoarg(args))
return NULL;
v = newlistobject(mp->ma_used);
if (v == NULL)
return NULL;
for (i = 0, j = 0; i < mp->ma_size; i++) {
if (mp->ma_table[i].me_value != NULL) {
object *value = mp->ma_table[i].me_value;
INCREF(value);
setlistitem(v, j, value);
j++;
}
}
return v;
}
static object *
mapping_items(mp, args)
register mappingobject *mp;
object *args;
{
register object *v;
register int i, j;
if (!getnoarg(args))
return NULL;
v = newlistobject(mp->ma_used);
if (v == NULL)
return NULL;
for (i = 0, j = 0; i < mp->ma_size; i++) {
if (mp->ma_table[i].me_value != NULL) {
object *key = mp->ma_table[i].me_key;
object *value = mp->ma_table[i].me_value;
object *item = newtupleobject(2);
if (item == NULL) {
DECREF(v);
return NULL;
}
INCREF(key);
settupleitem(item, 0, key);
INCREF(value);
settupleitem(item, 1, value);
setlistitem(v, j, item);
j++;
}
}
return v;
}
object *
getmappingkeys(mp)
object *mp;
@ -499,6 +564,28 @@ getmappingkeys(mp)
return mapping_keys((mappingobject *)mp, (object *)NULL);
}
object *
getmappingvalues(mp)
object *mp;
{
if (mp == NULL || !is_mappingobject(mp)) {
err_badcall();
return NULL;
}
return mapping_values((mappingobject *)mp, (object *)NULL);
}
object *
getmappingitems(mp)
object *mp;
{
if (mp == NULL || !is_mappingobject(mp)) {
err_badcall();
return NULL;
}
return mapping_values((mappingobject *)mp, (object *)NULL);
}
static int
mapping_compare(a, b)
mappingobject *a, *b;
@ -582,8 +669,10 @@ mapping_has_key(mp, args)
}
static struct methodlist mapp_methods[] = {
{"keys", mapping_keys},
{"has_key", mapping_has_key},
{"items", mapping_items},
{"keys", mapping_keys},
{"values", mapping_values},
{NULL, NULL} /* sentinel */
};
@ -697,14 +786,3 @@ dictremove(v, key)
}
return mappingremove(v, last_name_object);
}
char *
getdictkey(v, i)
object *v;
int i;
{
object *key = getmappingkey(v, i);
if (key == NULL)
return NULL;
return getstringvalue(key);
}

View File

@ -109,8 +109,12 @@ module_getattr(m, name)
res = dictlookup(m->md_dict, name);
if (res == NULL)
err_setstr(AttributeError, name);
else
INCREF(res);
else {
if (is_accessobject(res))
res = getaccessvalue(res, (object *)NULL);
else
INCREF(res);
}
return res;
}
@ -120,10 +124,17 @@ module_setattr(m, name, v)
char *name;
object *v;
{
if (strcmp(name, "__dict__") == 0 || strcmp(name, "__name__") == 0) {
err_setstr(TypeError, "read-only special attribute");
return -1;
object *ac;
if (name[0] == '_' && name[1] == '_') {
int n = strlen(name);
if (name[n-1] == '_' && name[n-2] == '_') {
err_setstr(TypeError, "read-only special attribute");
return -1;
}
}
ac = dictlookup(m->md_dict, name);
if (ac != NULL && is_accessobject(ac))
return setaccessvalue(ac, (object *)NULL, v);
if (v == NULL) {
int rv = dictremove(m->md_dict, name);
if (rv < 0)

View File

@ -796,7 +796,9 @@ getbuiltin(name)
/* Predefined exceptions */
object *AccessError;
object *AttributeError;
object *ConflictError;
object *EOFError;
object *IOError;
object *ImportError;
@ -827,7 +829,9 @@ newstdexception(name)
static void
initerrors()
{
AccessError = newstdexception("AccessError");
AttributeError = newstdexception("AttributeError");
ConflictError = newstdexception("ConflictError");
EOFError = newstdexception("EOFError");
IOError = newstdexception("IOError");
ImportError = newstdexception("ImportError");

View File

@ -84,9 +84,10 @@ static int cmp_exception PROTO((object *, object *));
static int cmp_member PROTO((object *, object *));
static object *cmp_outcome PROTO((int, object *, object *));
static int import_from PROTO((object *, object *, object *));
static object *build_class PROTO((object *, object *));
static object *build_class PROTO((object *, object *, object *));
static void locals_2_fast PROTO((frameobject *, int));
static void fast_2_locals PROTO((frameobject *));
static int access_statement PROTO((object *, int, frameobject *));
/* Pointer to current frame, used to link new frames to */
@ -743,10 +744,12 @@ eval_code(co, globals, locals, arg)
break;
case BUILD_CLASS:
w = POP();
u = POP();
v = POP();
x = build_class(v, w);
w = POP();
x = build_class(u, v, w);
PUSH(x);
DECREF(u);
DECREF(v);
DECREF(w);
break;
@ -754,12 +757,24 @@ eval_code(co, globals, locals, arg)
case STORE_NAME:
w = GETNAMEV(oparg);
v = POP();
u = dict2lookup(f->f_locals, w);
if (u != NULL && is_accessobject(u)) {
err = setaccessvalue(u, (object *)NULL, v);
DECREF(v);
break;
}
err = dict2insert(f->f_locals, w, v);
DECREF(v);
break;
case DELETE_NAME:
w = GETNAMEV(oparg);
u = dict2lookup(f->f_locals, w);
if (u != NULL && is_accessobject(u)) {
err = setaccessvalue(u, (object *)NULL,
(object *)NULL);
break;
}
if ((err = dict2remove(f->f_locals, w)) != 0)
err_setstr(NameError, getstringvalue(w));
break;
@ -952,12 +967,24 @@ eval_code(co, globals, locals, arg)
case STORE_GLOBAL:
w = GETNAMEV(oparg);
v = POP();
u = dict2lookup(f->f_locals, w);
if (u != NULL && is_accessobject(u)) {
err = setaccessvalue(u, (object *)NULL, v);
DECREF(v);
break;
}
err = dict2insert(f->f_globals, w, v);
DECREF(v);
break;
case DELETE_GLOBAL:
w = GETNAMEV(oparg);
u = dict2lookup(f->f_locals, w);
if (u != NULL && is_accessobject(u)) {
err = setaccessvalue(u, (object *)NULL,
(object *)NULL);
break;
}
if ((err = dict2remove(f->f_globals, w)) != 0)
err_setstr(NameError, getstringvalue(w));
break;
@ -984,6 +1011,11 @@ eval_code(co, globals, locals, arg)
}
}
}
if (is_accessobject(x)) {
x = getaccessvalue(x, (object *)NULL);
if (x == NULL)
break;
}
INCREF(x);
PUSH(x);
break;
@ -1000,6 +1032,11 @@ eval_code(co, globals, locals, arg)
break;
}
}
if (is_accessobject(x)) {
x = getaccessvalue(x, (object *)NULL);
if (x == NULL)
break;
}
INCREF(x);
PUSH(x);
break;
@ -1011,6 +1048,11 @@ eval_code(co, globals, locals, arg)
err_setstr(NameError, getstringvalue(w));
break;
}
if (is_accessobject(x)) {
x = getaccessvalue(x, (object *)NULL);
if (x == NULL)
break;
}
INCREF(x);
PUSH(x);
break;
@ -1041,15 +1083,25 @@ eval_code(co, globals, locals, arg)
"undefined local variable");
break;
}
if (is_accessobject(x)) {
x = getaccessvalue(x, (object *)NULL);
if (x == NULL)
break;
}
INCREF(x);
PUSH(x);
break;
case STORE_FAST:
v = POP();
w = GETLISTITEM(fastlocals, oparg);
if (w != NULL && is_accessobject(w)) {
err = setaccessvalue(w, (object *)NULL, v);
DECREF(v);
break;
}
XDECREF(w);
w = POP();
GETLISTITEM(fastlocals, oparg) = w;
GETLISTITEM(fastlocals, oparg) = v;
break;
case DELETE_FAST:
@ -1059,6 +1111,11 @@ eval_code(co, globals, locals, arg)
"undefined local variable");
break;
}
if (w != NULL && is_accessobject(w)) {
err = setaccessvalue(w, (object *)NULL,
(object *)NULL);
break;
}
DECREF(x);
GETLISTITEM(fastlocals, oparg) = NULL;
break;
@ -1125,6 +1182,13 @@ eval_code(co, globals, locals, arg)
locals_2_fast(f, 0);
break;
case ACCESS_MODE:
v = POP();
w = GETNAMEV(oparg);
err = access_statement(w, (int)getintvalue(v), f);
DECREF(v);
break;
case JUMP_FORWARD:
JUMPBY(oparg);
break;
@ -1483,7 +1547,8 @@ fast_2_locals(f)
/* Merge f->f_fastlocals into f->f_locals */
object *locals, *fast, *map;
object *error_type, *error_value;
int i;
int pos;
object *key, *value;
if (f == NULL)
return;
locals = f->f_locals;
@ -1495,16 +1560,10 @@ fast_2_locals(f)
!is_dictobject(map))
return;
err_get(&error_type, &error_value);
i = getdictsize(map);
while (--i >= 0) {
object *key;
object *value;
pos = 0;
while (mappinggetnext(map, &pos, &key, &value)) {
int j;
key = getdict2key(map, i);
if (key == NULL)
continue;
value = dict2lookup(map, key);
if (value == NULL || !is_intobject(value))
if (!is_intobject(value))
continue;
j = getintvalue(value);
value = getlistitem(fast, j);
@ -1529,7 +1588,8 @@ locals_2_fast(f, clear)
/* Merge f->f_locals into f->f_fastlocals */
object *locals, *fast, *map;
object *error_type, *error_value;
int i;
int pos;
object *key, *value;
if (f == NULL)
return;
locals = f->f_locals;
@ -1541,16 +1601,10 @@ locals_2_fast(f, clear)
!is_dictobject(map))
return;
err_get(&error_type, &error_value);
i = getdictsize(map);
while (--i >= 0) {
object *key;
object *value;
pos = 0;
while (mappinggetnext(map, &pos, &key, &value)) {
int j;
key = getdict2key(map, i);
if (key == NULL)
continue;
value = dict2lookup(map, key);
if (value == NULL || !is_intobject(value))
if (!is_intobject(value))
continue;
j = getintvalue(value);
value = dict2lookup(locals, key);
@ -1907,14 +1961,7 @@ call_builtin(func, arg)
return (*meth)(self, arg);
}
if (is_classobject(func)) {
if (arg != NULL &&
!(is_tupleobject(arg) &&
gettuplesize(arg) == 0)) {
err_setstr(TypeError,
"classobject() allows no arguments");
return NULL;
}
return newinstanceobject(func);
return newinstanceobject(func, arg);
}
err_setstr(TypeError, "call of non-function");
return NULL;
@ -2258,19 +2305,14 @@ import_from(locals, v, name)
object *w, *x;
w = getmoduledict(v);
if (getstringvalue(name)[0] == '*') {
int i;
int n = getdictsize(w);
for (i = 0; i < n; i++) {
name = getdict2key(w, i);
if (name == NULL || getstringvalue(name)[0] == '_')
int pos;
object *name, *value;
pos = 0;
while (mappinggetnext(w, &pos, &name, &value)) {
if (!is_stringobject(name) ||
getstringvalue(name)[0] == '_')
continue;
x = dict2lookup(w, name);
if (x == NULL) {
/* XXX can't happen? */
err_setstr(SystemError, getstringvalue(name));
return -1;
}
if (dict2insert(locals, name, x) != 0)
if (dict2insert(locals, name, value) != 0)
return -1;
}
return 0;
@ -2290,27 +2332,74 @@ import_from(locals, v, name)
}
static object *
build_class(v, w)
object *v; /* None or tuple containing base classes */
object *w; /* dictionary */
build_class(methods, bases, name)
object *methods; /* dictionary */
object *bases; /* tuple containing classes */
object *name; /* string */
{
if (is_tupleobject(v)) {
int i;
for (i = gettuplesize(v); --i >= 0; ) {
object *x = gettupleitem(v, i);
if (!is_classobject(x)) {
err_setstr(TypeError,
"base is not a class object");
return NULL;
}
}
int i;
if (!is_tupleobject(bases)) {
err_setstr(SystemError, "build_class with non-tuple bases");
return NULL;
}
else {
v = NULL;
}
if (!is_dictobject(w)) {
if (!is_dictobject(methods)) {
err_setstr(SystemError, "build_class with non-dictionary");
return NULL;
}
return newclassobject(v, w, (object *) NULL);
if (!is_stringobject(name)) {
err_setstr(SystemError, "build_class witn non-string name");
return NULL;
}
for (i = gettuplesize(bases); --i >= 0; ) {
object *base = gettupleitem(bases, i);
if (!is_classobject(base)) {
err_setstr(TypeError,
"base is not a class object");
return NULL;
}
}
return newclassobject(bases, methods, name);
}
static int
access_statement(name, mode, f)
object *name;
int mode;
frameobject *f;
{
object *value;
int i = -1;
object *ac;
int ret;
if (f->f_localmap == NULL)
value = dict2lookup(f->f_locals, name);
else {
value = dict2lookup(f->f_localmap, name);
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);
else {
value = NULL;
i = -1;
}
}
}
if (value && is_accessobject(value)) {
err_setstr(AccessError, "can't override access");
return -1;
}
err_clear();
ac = newaccessobject(value, (object*)NULL, (typeobject*)NULL, mode);
if (ac == NULL)
return -1;
if (i >= 0)
ret = setlistitem(f->f_fastlocals, i, ac);
else {
ret = dict2insert(f->f_locals, name, ac);
DECREF(ac);
}
return ret;
}

View File

@ -1408,6 +1408,65 @@ com_global_stmt(c, n)
}
}
#define strequ(a, b) (strcmp((a), (b)) == 0)
static void
com_access_stmt(c, n)
struct compiling *c;
node *n;
{
int i, j, k, mode, imode;
object *vmode;
REQ(n, access_stmt);
/* 'access' NAME (',' NAME)* ':' accesstype (',' accesstype)*
accesstype: NAME+ */
/* Find where the colon is */
i = 1;
while (TYPE(CHILD(n,i-1)) != COLON)
i += 1;
/* 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++) {
if (strequ(STR(CHILD(CHILD(n,j),k)), "public"))
p = 0;
else if (strequ(STR(CHILD(CHILD(n,j),k)), "protected"))
p = 1;
else if (strequ(STR(CHILD(CHILD(n,j),k)), "private"))
p = 2;
else if (strequ(STR(CHILD(CHILD(n,j),k)), "read"))
r = 1;
else if (strequ(STR(CHILD(CHILD(n,j),k)), "write"))
w = 1;
else /* XXX should make this an exception */
fprintf(stderr, "bad access type %s\n",
STR(CHILD(CHILD(n,j),k)));
}
if (r == 0 && w == 0)
r =w = 1;
if (p == 0) {
if (r == 1) mode |= AC_R_PUBLIC;
if (w == 1) mode |= AC_W_PUBLIC;
} else if (p == 1) {
if (r == 1) mode |= AC_R_PROTECTED;
if (w == 1) mode |= AC_W_PROTECTED;
} else {
if (r == 1) mode |= AC_R_PRIVATE;
if (w == 1) mode |= AC_W_PRIVATE;
}
}
vmode = newintobject((long)mode);
imode = com_addconst(c, vmode);
XDECREF(vmode);
for (i = 1; TYPE(CHILD(n,i-1)) != COLON; i+=2) {
com_addoparg(c, LOAD_CONST, imode);
com_addopname(c, ACCESS_MODE, CHILD(n, i));
}
}
static void
com_if_stmt(c, n)
struct compiling *c;
@ -1726,23 +1785,7 @@ com_funcdef(c, n)
}
static void
com_oldbases(c, n)
struct compiling *c;
node *n;
{
int i;
REQ(n, baselist);
/*
baselist: atom arguments (',' atom arguments)*
arguments: '(' ')'
*/
for (i = 0; i < NCH(n); i += 3)
com_node(c, CHILD(n, i));
com_addoparg(c, BUILD_TUPLE, (NCH(n)+1) / 3);
}
static void
com_newbases(c, n)
com_bases(c, n)
struct compiling *c;
node *n;
{
@ -1759,46 +1802,28 @@ com_classdef(c, n)
struct compiling *c;
node *n;
{
int i;
object *v;
REQ(n, classdef);
/*
classdef: 'class' NAME
['(' testlist ')' |'(' ')' ['=' baselist]] ':' suite
baselist: atom arguments (',' atom arguments)*
arguments: '(' ')'
*/
/* This piece of code must push a tuple on the stack (the bases) */
if (TYPE(CHILD(n, 2)) != LPAR) {
/* New syntax without base classes:
class NAME ':' suite
___________^
*/
/* classdef: class NAME ['(' testlist ')'] ':' suite */
if ((v = newstringobject(STR(CHILD(n, 1)))) == NULL) {
c->c_errors++;
return;
}
/* Push the class name on the stack */
i = com_addconst(c, v);
com_addoparg(c, LOAD_CONST, i);
DECREF(v);
/* Push the tuple of base classes on the stack */
if (TYPE(CHILD(n, 2)) != LPAR)
com_addoparg(c, BUILD_TUPLE, 0);
}
else {
if (TYPE(CHILD(n, 3)) == RPAR) {
/* Old syntax with or without base classes:
class NAME '(' ')' ['=' baselist] ':' suite
_______________^....^...^
*/
if (TYPE(CHILD(n, 4)) == EQUAL)
com_oldbases(c, CHILD(n, 5));
else
com_addoparg(c, BUILD_TUPLE, 0);
}
else {
/* New syntax with base classes:
class NAME '(' testlist ')' ':' suite
_______________^
*/
com_newbases(c, CHILD(n, 3));
}
}
else
com_bases(c, CHILD(n, 3));
v = (object *)compile(n, c->c_filename);
if (v == NULL)
c->c_errors++;
else {
int i = com_addconst(c, v);
i = com_addconst(c, v);
com_addoparg(c, LOAD_CONST, i);
com_addbyte(c, BUILD_FUNCTION);
com_addbyte(c, UNARY_CALL);
@ -1882,6 +1907,9 @@ com_node(c, n)
case global_stmt:
com_global_stmt(c, n);
break;
case access_stmt:
com_access_stmt(c, n);
break;
case if_stmt:
com_if_stmt(c, n);
break;
@ -2084,9 +2112,8 @@ compile_node(c, n)
break;
case classdef: /* A class definition */
/* classdef: 'class' NAME
['(' testlist ')' |'(' ')' ['=' baselist]]
':' suite */
/* classdef: 'class' NAME ['(' testlist ')'] ':' suite */
c->c_name = STR(CHILD(n, 1));
com_node(c, CHILD(n, NCH(n)-1)); /* The suite */
com_addbyte(c, LOAD_LOCALS);
com_addbyte(c, RETURN_VALUE);
@ -2114,8 +2141,8 @@ compile_node(c, n)
There is one problem: 'from foo import *' introduces local variables
that we can't know while compiling. If this is the case, wo don't
optimize at all (this rarely happens, since import is mostly used
at the module level).
optimize at all (this rarely happens, since this form of import
statement is mostly used at the module level).
Note that, because of this optimization, code like the following
won't work:

File diff suppressed because it is too large Load Diff

View File

@ -54,7 +54,7 @@ extern char *argv0;
/* Magic word to reject .pyc files generated by other Python versions */
#define MAGIC 0x99BE3AL
#define MAGIC 0x999901L /* Increment by one for each incompatible change */
static object *modules;
@ -353,46 +353,27 @@ reload_module(m)
return get_module(m, getmodulename(m), (object **)NULL);
}
static void
cleardict(d)
object *d;
{
int i;
for (i = getdictsize(d); --i >= 0; ) {
char *k;
k = getdictkey(d, i);
if (k != NULL)
(void) dictremove(d, k);
}
}
void
doneimport()
{
if (modules != NULL) {
int i;
int pos;
object *modname, *module;
/* Explicitly erase all modules; this is the safest way
to get rid of at least *some* circular dependencies */
for (i = getdictsize(modules); --i >= 0; ) {
object *k;
k = getdict2key(modules, i);
if (k != NULL) {
object *m;
m = dict2lookup(modules, k);
if (m == NULL)
err_clear();
else if (is_moduleobject(m)) {
object *d;
d = getmoduledict(m);
if (d != NULL && is_dictobject(d)) {
cleardict(d);
}
}
pos = 0;
while (mappinggetnext(modules, &pos, &modname, &module)) {
if (is_moduleobject(module)) {
object *dict;
dict = getmoduledict(module);
if (dict != NULL && is_dictobject(dict))
mappingclear(dict);
}
}
cleardict(modules);
mappingclear(modules);
}
DECREF(modules);
modules = NULL;
}

View File

@ -174,17 +174,14 @@ w_object(v, p)
}
}
else if (is_dictobject(v)) {
int pos;
object *key, *value;
w_byte(TYPE_DICT, p);
/* This one is NULL object terminated! */
n = getdictsize(v);
for (i = 0; i < n; i++) {
object *key, *val;
key = getdict2key(v, (int)i);
if (key != NULL) {
val = dict2lookup(v, key); /* Can't be NULL */
w_object(key, p);
w_object(val, p);
}
pos = 0;
while (mappinggetnext(v, &pos, &key, &value)) {
w_object(key, p);
w_object(value, p);
}
w_object((object *)NULL, p);
}