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: # Change log:
# 19-May-93:
# Add access statement
# 18-May-93:
# Abolish old class header syntax
# 06-Apr-92: # 06-Apr-92:
# Use only '*' for varargs list # Use only '*' for varargs list
@ -81,7 +87,7 @@ fplist: fpdef (',' fpdef)* [',']
stmt: simple_stmt | compound_stmt stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE 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 expr_stmt: (exprlist '=')* exprlist
# For assignments, additional restrictions enforced by the interpreter # For assignments, additional restrictions enforced by the interpreter
print_stmt: 'print' (test ',')* [test] print_stmt: 'print' (test ',')* [test]
@ -94,6 +100,11 @@ return_stmt: 'return' [testlist]
raise_stmt: 'raise' test [',' test] raise_stmt: 'raise' test [',' test]
import_stmt: 'import' NAME (',' NAME)* | 'from' NAME 'import' ('*' | NAME (',' NAME)*) import_stmt: 'import' NAME (',' NAME)* | 'from' NAME 'import' ('*' | NAME (',' NAME)*)
global_stmt: 'global' 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 compound_stmt: if_stmt | while_stmt | for_stmt | try_stmt | funcdef | classdef
if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite] if_stmt: 'if' test ':' suite ('elif' test ':' suite)* ['else' ':' suite]
while_stmt: 'while' test ':' suite ['else' ':' suite] while_stmt: 'while' test ':' suite ['else' ':' suite]
@ -122,9 +133,4 @@ exprlist: expr (',' expr)* [',']
testlist: test (',' test)* [','] testlist: test (',' test)* [',']
dictmaker: test ':' test (',' test ':' test)* [','] dictmaker: test ':' test (',' test ':' test)* [',']
# New class syntax should be: classdef: class NAME ['(' testlist ')'] ':' suite
# 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: '(' ')'

View File

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

View File

@ -37,7 +37,7 @@ extern typeobject Classtype, Instancetype, Instancemethodtype;
#define is_instancemethodobject(op) ((op)->ob_type == &Instancemethodtype) #define is_instancemethodobject(op) ((op)->ob_type == &Instancemethodtype)
extern object *newclassobject PROTO((object *, object *, object *)); 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 *newinstancemethodobject PROTO((object *, object *));
extern object *instancemethodgetfunc PROTO((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 object *dictlookup PROTO((object *dp, char *key));
extern int dictinsert PROTO((object *dp, char *key, object *item)); extern int dictinsert PROTO((object *dp, char *key, object *item));
extern int dictremove PROTO((object *dp, char *key)); extern int dictremove PROTO((object *dp, char *key));
extern char *getdictkey PROTO((object *dp, int i));
#define getdictsize getmappingsize
#define getdictkeys getmappingkeys #define getdictkeys getmappingkeys
#define getdict2key getmappingkey
#define dict2lookup mappinglookup #define dict2lookup mappinglookup
#define dict2insert mappinginsert #define dict2insert mappinginsert
#define dict2remove mappingremove #define dict2remove mappingremove

View File

@ -33,7 +33,9 @@ void err_clear PROTO((void));
/* Predefined exceptions */ /* Predefined exceptions */
extern object *AccessError;
extern object *AttributeError; extern object *AttributeError;
extern object *ConflictError;
extern object *EOFError; extern object *EOFError;
extern object *IOError; extern object *IOError;
extern object *ImportError; extern object *ImportError;
@ -59,3 +61,5 @@ extern object *err_errno PROTO((object *));
extern void err_input PROTO((int)); extern void err_input PROTO((int));
extern void err_badcall PROTO((void)); 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 */ /* Function object interface */
typedef struct {
OB_HEAD
object *func_code;
object *func_globals;
object *func_name;
} funcobject;
extern typeobject Functype; extern typeobject Functype;
#define is_funcobject(op) ((op)->ob_type == &Functype) #define is_funcobject(op) ((op)->ob_type == &Functype)

View File

@ -21,31 +21,31 @@
#define raise_stmt 276 #define raise_stmt 276
#define import_stmt 277 #define import_stmt 277
#define global_stmt 278 #define global_stmt 278
#define compound_stmt 279 #define access_stmt 279
#define if_stmt 280 #define accesstype 280
#define while_stmt 281 #define compound_stmt 281
#define for_stmt 282 #define if_stmt 282
#define try_stmt 283 #define while_stmt 283
#define except_clause 284 #define for_stmt 284
#define suite 285 #define try_stmt 285
#define test 286 #define except_clause 286
#define and_test 287 #define suite 287
#define not_test 288 #define test 288
#define comparison 289 #define and_test 289
#define comp_op 290 #define not_test 290
#define expr 291 #define comparison 291
#define xor_expr 292 #define comp_op 292
#define and_expr 293 #define expr 293
#define shift_expr 294 #define xor_expr 294
#define arith_expr 295 #define and_expr 295
#define term 296 #define shift_expr 296
#define factor 297 #define arith_expr 297
#define atom 298 #define term 298
#define trailer 299 #define factor 299
#define subscript 300 #define atom 300
#define exprlist 301 #define trailer 301
#define testlist 302 #define subscript 302
#define dictmaker 303 #define exprlist 303
#define classdef 304 #define testlist 304
#define baselist 305 #define dictmaker 305
#define arguments 306 #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 hashable object to object */
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.
*/
extern typeobject Mappingtype; extern typeobject Mappingtype;
#define is_mappingobject(op) ((op)->ob_type == &Mappingtype) #define is_mappingobject(op) ((op)->ob_type == &Mappingtype)
extern object *newmappingobject PROTO((void)); extern object *newmappingobject PROTO((void));
extern object *mappinglookup PROTO((object *dp, object *key)); extern object *mappinglookup PROTO((object *mp, object *key));
extern int mappinginsert PROTO((object *dp, object *key, object *item)); extern int mappinginsert PROTO((object *mp, object *key, object *item));
extern int mappingremove PROTO((object *dp, object *key)); extern int mappingremove PROTO((object *mp, object *key));
extern int getmappingsize PROTO((object *dp)); extern void mappingclear PROTO((object *mp));
extern object *getmappingkey PROTO((object *dp, int i)); extern int mappinggetnext
extern object *getmappingkeys PROTO((object *dp)); 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 COMPARE_OP 106 /* Comparison operator */
#define IMPORT_NAME 107 /* Index in name list */ #define IMPORT_NAME 107 /* Index in name list */
#define IMPORT_FROM 108 /* 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_FORWARD 110 /* Number of bytes to skip */
#define JUMP_IF_FALSE 111 /* "" */ #define JUMP_IF_FALSE 111 /* "" */

View File

@ -33,7 +33,9 @@ void err_clear PROTO((void));
/* Predefined exceptions */ /* Predefined exceptions */
extern object *AccessError;
extern object *AttributeError; extern object *AttributeError;
extern object *ConflictError;
extern object *EOFError; extern object *EOFError;
extern object *IOError; extern object *IOError;
extern object *ImportError; extern object *ImportError;
@ -59,3 +61,5 @@ extern object *err_errno PROTO((object *));
extern void err_input PROTO((int)); extern void err_input PROTO((int));
extern void err_badcall PROTO((void)); 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 "structmember.h"
#include "ceval.h" #include "ceval.h"
extern typeobject MappingInstancetype;
extern typeobject SequenceInstancetype;
typedef struct { typedef struct {
OB_HEAD OB_HEAD
object *cl_bases; /* A tuple */ object *cl_bases; /* A tuple */
@ -102,7 +99,10 @@ class_getattr(op, name)
} }
v = dictlookup(op->cl_methods, name); v = dictlookup(op->cl_methods, name);
if (v != NULL) { if (v != NULL) {
INCREF(v); if (is_accessobject(v))
v = getaccessvalue(v, (object *)NULL);
else
INCREF(v);
return v; return v;
} }
{ {
@ -126,6 +126,7 @@ class_setattr(op, name, v)
char *name; char *name;
object *v; object *v;
{ {
object *ac;
if (name[0] == '_' && name[1] == '_') { if (name[0] == '_' && name[1] == '_') {
int n = strlen(name); int n = strlen(name);
if (name[n-1] == '_' && name[n-2] == '_') { if (name[n-1] == '_' && name[n-2] == '_') {
@ -133,6 +134,9 @@ class_setattr(op, name, v)
return -1; return -1;
} }
} }
ac = dictlookup(op->cl_methods, name);
if (ac != NULL && is_accessobject(ac))
return setaccessvalue(ac, (object *)NULL, v);
if (v == NULL) { if (v == NULL) {
int rv = dictremove(op->cl_methods, name); int rv = dictremove(op->cl_methods, name);
if (rv < 0) if (rv < 0)
@ -144,6 +148,20 @@ class_setattr(op, name, v)
return dictinsert(op->cl_methods, 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 = { typeobject Classtype = {
OB_HEAD_INIT(&Typetype) OB_HEAD_INIT(&Typetype)
0, 0,
@ -155,7 +173,7 @@ typeobject Classtype = {
class_getattr, /*tp_getattr*/ class_getattr, /*tp_getattr*/
class_setattr, /*tp_setattr*/ class_setattr, /*tp_setattr*/
0, /*tp_compare*/ 0, /*tp_compare*/
0, /*tp_repr*/ class_repr, /*tp_repr*/
0, /*tp_as_number*/ 0, /*tp_as_number*/
0, /*tp_as_sequence*/ 0, /*tp_as_sequence*/
0, /*tp_as_mapping*/ 0, /*tp_as_mapping*/
@ -170,12 +188,18 @@ typedef struct {
object *in_attr; /* A dictionary */ object *in_attr; /* A dictionary */
} instanceobject; } instanceobject;
static object *instance_getattr PROTO((instanceobject *, char *));
object * object *
newinstanceobject(class) newinstanceobject(class, arg)
register object *class; object *class;
object *arg;
{ {
register instanceobject *inst; register instanceobject *inst;
object *v; object *v;
object *init;
int pos;
object *key, *value;
if (!is_classobject(class)) { if (!is_classobject(class)) {
err_badcall(); err_badcall();
return NULL; return NULL;
@ -187,9 +211,52 @@ newinstanceobject(class)
inst->in_class = (classobject *)class; inst->in_class = (classobject *)class;
inst->in_attr = newdictobject(); inst->in_attr = newdictobject();
if (inst->in_attr == NULL) { if (inst->in_attr == NULL) {
error:
DECREF(inst); DECREF(inst);
return NULL; 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; return (object *)inst;
} }
@ -199,9 +266,29 @@ static void
instance_dealloc(inst) instance_dealloc(inst)
register instanceobject *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); DECREF(inst->in_class);
if (inst->in_attr != NULL) XDECREF(inst->in_attr);
DECREF(inst->in_attr);
free((ANY *)inst); free((ANY *)inst);
} }
@ -221,7 +308,10 @@ instance_getattr(inst, name)
} }
v = dictlookup(inst->in_attr, name); v = dictlookup(inst->in_attr, name);
if (v != NULL) { if (v != NULL) {
INCREF(v); if (is_accessobject(v))
v = getaccessvalue(v, (object *)NULL);
else
INCREF(v);
return v; return v;
} }
v = class_getattr(inst->in_class, name); v = class_getattr(inst->in_class, name);
@ -243,6 +333,7 @@ instance_setattr(inst, name, v)
char *name; char *name;
object *v; object *v;
{ {
object *ac;
if (name[0] == '_' && name[1] == '_') { if (name[0] == '_' && name[1] == '_') {
int n = strlen(name); int n = strlen(name);
if (name[n-1] == '_' && name[n-2] == '_') { if (name[n-1] == '_' && name[n-2] == '_') {
@ -250,6 +341,9 @@ instance_setattr(inst, name, v)
return -1; return -1;
} }
} }
ac = dictlookup(inst->in_attr, name);
if (ac != NULL && is_accessobject(ac))
return setaccessvalue(ac, (object *)NULL, v);
if (v == NULL) { if (v == NULL) {
int rv = dictremove(inst->in_attr, name); int rv = dictremove(inst->in_attr, name);
if (rv < 0) if (rv < 0)
@ -270,9 +364,15 @@ instance_repr(inst)
func = instance_getattr(inst, "__repr__"); func = instance_getattr(inst, "__repr__");
if (func == NULL) { 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(); err_clear();
sprintf(buf, "<instance object at %lx>", (long)inst); sprintf(buf, "<%.100s instance at %lx>", cname, (long)inst);
return newstringobject(buf); return newstringobject(buf);
} }
res = call_object(func, (object *)NULL); res = call_object(func, (object *)NULL);
@ -773,6 +873,7 @@ typeobject Instancetype = {
0, 0,
instance_dealloc, /*tp_dealloc*/ instance_dealloc, /*tp_dealloc*/
0, /*tp_print*/ 0, /*tp_print*/
(object * (*) FPROTO((object *, char *)))
instance_getattr, /*tp_getattr*/ instance_getattr, /*tp_getattr*/
instance_setattr, /*tp_setattr*/ instance_setattr, /*tp_setattr*/
instance_compare, /*tp_compare*/ instance_compare, /*tp_compare*/
@ -879,6 +980,28 @@ instancemethod_compare(a, b)
return cmp; 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 static long
instancemethod_hash(a) instancemethod_hash(a)
instancemethodobject *a; instancemethodobject *a;
@ -904,7 +1027,7 @@ typeobject Instancemethodtype = {
instancemethod_getattr, /*tp_getattr*/ instancemethod_getattr, /*tp_getattr*/
0, /*tp_setattr*/ 0, /*tp_setattr*/
instancemethod_compare, /*tp_compare*/ instancemethod_compare, /*tp_compare*/
0, /*tp_repr*/ instancemethod_repr, /*tp_repr*/
0, /*tp_as_number*/ 0, /*tp_as_number*/
0, /*tp_as_sequence*/ 0, /*tp_as_sequence*/
0, /*tp_as_mapping*/ 0, /*tp_as_mapping*/

View File

@ -307,39 +307,49 @@ mappingremove(op, key)
return 0; return 0;
} }
int void
getmappingsize(op) mappingclear(op)
register object *op; object *op;
{ {
if (!is_mappingobject(op)) { int i;
err_badcall(); register mappingobject *mp;
return -1; 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 * int
getmappingkey(op, i) mappinggetnext(op, ppos, pkey, pvalue)
object *op; object *op;
register int i; int *ppos;
object **pkey;
object **pvalue;
{ {
/* XXX This can't return errors since its callers assume int i;
that NULL means there was no key at that point */
register mappingobject *mp; register mappingobject *mp;
if (!is_mappingobject(op)) { if (!is_dictobject(op))
/* err_badcall(); */ return 0;
return NULL;
}
mp = (mappingobject *)op; mp = (mappingobject *)op;
if (i < 0 || i >= mp->ma_size) { i = *ppos;
/* err_badarg(); */ if (i < 0)
return NULL; return 0;
} while (i < mp->ma_size && mp->ma_table[i].me_value == NULL)
if (mp->ma_table[i].me_value == NULL) { i++;
/* Not an error! */ *ppos = i+1;
return NULL; if (i >= mp->ma_size)
} return 0;
return (object *) mp->ma_table[i].me_key; if (pkey)
*pkey = mp->ma_table[i].me_key;
if (pvalue)
*pvalue = mp->ma_table[i].me_value;
return 1;
} }
/* Methods */ /* Methods */
@ -488,6 +498,61 @@ mapping_keys(mp, args)
return v; 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 * object *
getmappingkeys(mp) getmappingkeys(mp)
object *mp; object *mp;
@ -499,6 +564,28 @@ getmappingkeys(mp)
return mapping_keys((mappingobject *)mp, (object *)NULL); 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 static int
mapping_compare(a, b) mapping_compare(a, b)
mappingobject *a, *b; mappingobject *a, *b;
@ -582,8 +669,10 @@ mapping_has_key(mp, args)
} }
static struct methodlist mapp_methods[] = { static struct methodlist mapp_methods[] = {
{"keys", mapping_keys},
{"has_key", mapping_has_key}, {"has_key", mapping_has_key},
{"items", mapping_items},
{"keys", mapping_keys},
{"values", mapping_values},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
@ -697,14 +786,3 @@ dictremove(v, key)
} }
return mappingremove(v, last_name_object); 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 "compile.h"
#include "structmember.h" #include "structmember.h"
typedef struct {
OB_HEAD
object *func_code;
object *func_globals;
} funcobject;
object * object *
newfuncobject(code, globals) newfuncobject(code, globals)
object *code; object *code;
@ -45,6 +39,8 @@ newfuncobject(code, globals)
op->func_code = code; op->func_code = code;
INCREF(globals); INCREF(globals);
op->func_globals = globals; op->func_globals = globals;
op->func_name = ((codeobject*)(op->func_code))->co_name;
INCREF(op->func_name);
} }
return (object *)op; return (object *)op;
} }
@ -78,6 +74,7 @@ getfuncglobals(op)
static struct memberlist func_memberlist[] = { static struct memberlist func_memberlist[] = {
{"func_code", T_OBJECT, OFF(func_code), READONLY}, {"func_code", T_OBJECT, OFF(func_code), READONLY},
{"func_globals",T_OBJECT, OFF(func_globals), READONLY}, {"func_globals",T_OBJECT, OFF(func_globals), READONLY},
{"func_name", T_OBJECT, OFF(func_name), READONLY},
{NULL} /* Sentinel */ {NULL} /* Sentinel */
}; };
@ -104,7 +101,7 @@ func_repr(op)
{ {
char buf[140]; char buf[140];
sprintf(buf, "<function %.100s at %lx>", sprintf(buf, "<function %.100s at %lx>",
getstringvalue(((codeobject*)(op->func_code))->co_name), getstringvalue(op->func_name),
(long)op); (long)op);
return newstringobject(buf); return newstringobject(buf);
} }

View File

@ -307,39 +307,49 @@ mappingremove(op, key)
return 0; return 0;
} }
int void
getmappingsize(op) mappingclear(op)
register object *op; object *op;
{ {
if (!is_mappingobject(op)) { int i;
err_badcall(); register mappingobject *mp;
return -1; 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 * int
getmappingkey(op, i) mappinggetnext(op, ppos, pkey, pvalue)
object *op; object *op;
register int i; int *ppos;
object **pkey;
object **pvalue;
{ {
/* XXX This can't return errors since its callers assume int i;
that NULL means there was no key at that point */
register mappingobject *mp; register mappingobject *mp;
if (!is_mappingobject(op)) { if (!is_dictobject(op))
/* err_badcall(); */ return 0;
return NULL;
}
mp = (mappingobject *)op; mp = (mappingobject *)op;
if (i < 0 || i >= mp->ma_size) { i = *ppos;
/* err_badarg(); */ if (i < 0)
return NULL; return 0;
} while (i < mp->ma_size && mp->ma_table[i].me_value == NULL)
if (mp->ma_table[i].me_value == NULL) { i++;
/* Not an error! */ *ppos = i+1;
return NULL; if (i >= mp->ma_size)
} return 0;
return (object *) mp->ma_table[i].me_key; if (pkey)
*pkey = mp->ma_table[i].me_key;
if (pvalue)
*pvalue = mp->ma_table[i].me_value;
return 1;
} }
/* Methods */ /* Methods */
@ -488,6 +498,61 @@ mapping_keys(mp, args)
return v; 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 * object *
getmappingkeys(mp) getmappingkeys(mp)
object *mp; object *mp;
@ -499,6 +564,28 @@ getmappingkeys(mp)
return mapping_keys((mappingobject *)mp, (object *)NULL); 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 static int
mapping_compare(a, b) mapping_compare(a, b)
mappingobject *a, *b; mappingobject *a, *b;
@ -582,8 +669,10 @@ mapping_has_key(mp, args)
} }
static struct methodlist mapp_methods[] = { static struct methodlist mapp_methods[] = {
{"keys", mapping_keys},
{"has_key", mapping_has_key}, {"has_key", mapping_has_key},
{"items", mapping_items},
{"keys", mapping_keys},
{"values", mapping_values},
{NULL, NULL} /* sentinel */ {NULL, NULL} /* sentinel */
}; };
@ -697,14 +786,3 @@ dictremove(v, key)
} }
return mappingremove(v, last_name_object); 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); res = dictlookup(m->md_dict, name);
if (res == NULL) if (res == NULL)
err_setstr(AttributeError, name); err_setstr(AttributeError, name);
else else {
INCREF(res); if (is_accessobject(res))
res = getaccessvalue(res, (object *)NULL);
else
INCREF(res);
}
return res; return res;
} }
@ -120,10 +124,17 @@ module_setattr(m, name, v)
char *name; char *name;
object *v; object *v;
{ {
if (strcmp(name, "__dict__") == 0 || strcmp(name, "__name__") == 0) { object *ac;
err_setstr(TypeError, "read-only special attribute"); if (name[0] == '_' && name[1] == '_') {
return -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) { if (v == NULL) {
int rv = dictremove(m->md_dict, name); int rv = dictremove(m->md_dict, name);
if (rv < 0) if (rv < 0)

View File

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

View File

@ -84,9 +84,10 @@ static int cmp_exception PROTO((object *, object *));
static int cmp_member PROTO((object *, object *)); static int cmp_member PROTO((object *, object *));
static object *cmp_outcome PROTO((int, object *, object *)); static object *cmp_outcome PROTO((int, object *, object *));
static int import_from PROTO((object *, 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 locals_2_fast PROTO((frameobject *, int));
static void fast_2_locals PROTO((frameobject *)); 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 */ /* Pointer to current frame, used to link new frames to */
@ -743,10 +744,12 @@ eval_code(co, globals, locals, arg)
break; break;
case BUILD_CLASS: case BUILD_CLASS:
w = POP(); u = POP();
v = POP(); v = POP();
x = build_class(v, w); w = POP();
x = build_class(u, v, w);
PUSH(x); PUSH(x);
DECREF(u);
DECREF(v); DECREF(v);
DECREF(w); DECREF(w);
break; break;
@ -754,12 +757,24 @@ eval_code(co, globals, locals, arg)
case STORE_NAME: case STORE_NAME:
w = GETNAMEV(oparg); w = GETNAMEV(oparg);
v = POP(); 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); err = dict2insert(f->f_locals, w, v);
DECREF(v); DECREF(v);
break; break;
case DELETE_NAME: case DELETE_NAME:
w = GETNAMEV(oparg); 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) if ((err = dict2remove(f->f_locals, w)) != 0)
err_setstr(NameError, getstringvalue(w)); err_setstr(NameError, getstringvalue(w));
break; break;
@ -952,12 +967,24 @@ eval_code(co, globals, locals, arg)
case STORE_GLOBAL: case STORE_GLOBAL:
w = GETNAMEV(oparg); w = GETNAMEV(oparg);
v = POP(); 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); err = dict2insert(f->f_globals, w, v);
DECREF(v); DECREF(v);
break; break;
case DELETE_GLOBAL: case DELETE_GLOBAL:
w = GETNAMEV(oparg); 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) if ((err = dict2remove(f->f_globals, w)) != 0)
err_setstr(NameError, getstringvalue(w)); err_setstr(NameError, getstringvalue(w));
break; 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); INCREF(x);
PUSH(x); PUSH(x);
break; break;
@ -1000,6 +1032,11 @@ eval_code(co, globals, locals, arg)
break; break;
} }
} }
if (is_accessobject(x)) {
x = getaccessvalue(x, (object *)NULL);
if (x == NULL)
break;
}
INCREF(x); INCREF(x);
PUSH(x); PUSH(x);
break; break;
@ -1011,6 +1048,11 @@ eval_code(co, globals, locals, arg)
err_setstr(NameError, getstringvalue(w)); err_setstr(NameError, getstringvalue(w));
break; break;
} }
if (is_accessobject(x)) {
x = getaccessvalue(x, (object *)NULL);
if (x == NULL)
break;
}
INCREF(x); INCREF(x);
PUSH(x); PUSH(x);
break; break;
@ -1041,15 +1083,25 @@ eval_code(co, globals, locals, arg)
"undefined local variable"); "undefined local variable");
break; break;
} }
if (is_accessobject(x)) {
x = getaccessvalue(x, (object *)NULL);
if (x == NULL)
break;
}
INCREF(x); INCREF(x);
PUSH(x); PUSH(x);
break; break;
case STORE_FAST: case STORE_FAST:
v = POP();
w = GETLISTITEM(fastlocals, oparg); w = GETLISTITEM(fastlocals, oparg);
if (w != NULL && is_accessobject(w)) {
err = setaccessvalue(w, (object *)NULL, v);
DECREF(v);
break;
}
XDECREF(w); XDECREF(w);
w = POP(); GETLISTITEM(fastlocals, oparg) = v;
GETLISTITEM(fastlocals, oparg) = w;
break; break;
case DELETE_FAST: case DELETE_FAST:
@ -1059,6 +1111,11 @@ eval_code(co, globals, locals, arg)
"undefined local variable"); "undefined local variable");
break; break;
} }
if (w != NULL && is_accessobject(w)) {
err = setaccessvalue(w, (object *)NULL,
(object *)NULL);
break;
}
DECREF(x); DECREF(x);
GETLISTITEM(fastlocals, oparg) = NULL; GETLISTITEM(fastlocals, oparg) = NULL;
break; break;
@ -1124,6 +1181,13 @@ eval_code(co, globals, locals, arg)
err = import_from(f->f_locals, v, w); err = import_from(f->f_locals, v, w);
locals_2_fast(f, 0); locals_2_fast(f, 0);
break; break;
case ACCESS_MODE:
v = POP();
w = GETNAMEV(oparg);
err = access_statement(w, (int)getintvalue(v), f);
DECREF(v);
break;
case JUMP_FORWARD: case JUMP_FORWARD:
JUMPBY(oparg); JUMPBY(oparg);
@ -1483,7 +1547,8 @@ fast_2_locals(f)
/* Merge f->f_fastlocals into f->f_locals */ /* Merge f->f_fastlocals into f->f_locals */
object *locals, *fast, *map; object *locals, *fast, *map;
object *error_type, *error_value; object *error_type, *error_value;
int i; int pos;
object *key, *value;
if (f == NULL) if (f == NULL)
return; return;
locals = f->f_locals; locals = f->f_locals;
@ -1495,16 +1560,10 @@ fast_2_locals(f)
!is_dictobject(map)) !is_dictobject(map))
return; return;
err_get(&error_type, &error_value); err_get(&error_type, &error_value);
i = getdictsize(map); pos = 0;
while (--i >= 0) { while (mappinggetnext(map, &pos, &key, &value)) {
object *key;
object *value;
int j; int j;
key = getdict2key(map, i); if (!is_intobject(value))
if (key == NULL)
continue;
value = dict2lookup(map, key);
if (value == NULL || !is_intobject(value))
continue; continue;
j = getintvalue(value); j = getintvalue(value);
value = getlistitem(fast, j); value = getlistitem(fast, j);
@ -1529,7 +1588,8 @@ locals_2_fast(f, clear)
/* Merge f->f_locals into f->f_fastlocals */ /* Merge f->f_locals into f->f_fastlocals */
object *locals, *fast, *map; object *locals, *fast, *map;
object *error_type, *error_value; object *error_type, *error_value;
int i; int pos;
object *key, *value;
if (f == NULL) if (f == NULL)
return; return;
locals = f->f_locals; locals = f->f_locals;
@ -1541,16 +1601,10 @@ locals_2_fast(f, clear)
!is_dictobject(map)) !is_dictobject(map))
return; return;
err_get(&error_type, &error_value); err_get(&error_type, &error_value);
i = getdictsize(map); pos = 0;
while (--i >= 0) { while (mappinggetnext(map, &pos, &key, &value)) {
object *key;
object *value;
int j; int j;
key = getdict2key(map, i); if (!is_intobject(value))
if (key == NULL)
continue;
value = dict2lookup(map, key);
if (value == NULL || !is_intobject(value))
continue; continue;
j = getintvalue(value); j = getintvalue(value);
value = dict2lookup(locals, key); value = dict2lookup(locals, key);
@ -1907,14 +1961,7 @@ call_builtin(func, arg)
return (*meth)(self, arg); return (*meth)(self, arg);
} }
if (is_classobject(func)) { if (is_classobject(func)) {
if (arg != NULL && return newinstanceobject(func, arg);
!(is_tupleobject(arg) &&
gettuplesize(arg) == 0)) {
err_setstr(TypeError,
"classobject() allows no arguments");
return NULL;
}
return newinstanceobject(func);
} }
err_setstr(TypeError, "call of non-function"); err_setstr(TypeError, "call of non-function");
return NULL; return NULL;
@ -2258,19 +2305,14 @@ import_from(locals, v, name)
object *w, *x; object *w, *x;
w = getmoduledict(v); w = getmoduledict(v);
if (getstringvalue(name)[0] == '*') { if (getstringvalue(name)[0] == '*') {
int i; int pos;
int n = getdictsize(w); object *name, *value;
for (i = 0; i < n; i++) { pos = 0;
name = getdict2key(w, i); while (mappinggetnext(w, &pos, &name, &value)) {
if (name == NULL || getstringvalue(name)[0] == '_') if (!is_stringobject(name) ||
getstringvalue(name)[0] == '_')
continue; continue;
x = dict2lookup(w, name); if (dict2insert(locals, name, value) != 0)
if (x == NULL) {
/* XXX can't happen? */
err_setstr(SystemError, getstringvalue(name));
return -1;
}
if (dict2insert(locals, name, x) != 0)
return -1; return -1;
} }
return 0; return 0;
@ -2290,27 +2332,74 @@ import_from(locals, v, name)
} }
static object * static object *
build_class(v, w) build_class(methods, bases, name)
object *v; /* None or tuple containing base classes */ object *methods; /* dictionary */
object *w; /* dictionary */ object *bases; /* tuple containing classes */
object *name; /* string */
{ {
if (is_tupleobject(v)) { int i;
int i; if (!is_tupleobject(bases)) {
for (i = gettuplesize(v); --i >= 0; ) { err_setstr(SystemError, "build_class with non-tuple bases");
object *x = gettupleitem(v, i); return NULL;
if (!is_classobject(x)) {
err_setstr(TypeError,
"base is not a class object");
return NULL;
}
}
} }
else { if (!is_dictobject(methods)) {
v = NULL;
}
if (!is_dictobject(w)) {
err_setstr(SystemError, "build_class with non-dictionary"); err_setstr(SystemError, "build_class with non-dictionary");
return NULL; 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 static void
com_if_stmt(c, n) com_if_stmt(c, n)
struct compiling *c; struct compiling *c;
@ -1726,23 +1785,7 @@ com_funcdef(c, n)
} }
static void static void
com_oldbases(c, n) com_bases(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)
struct compiling *c; struct compiling *c;
node *n; node *n;
{ {
@ -1759,46 +1802,28 @@ com_classdef(c, n)
struct compiling *c; struct compiling *c;
node *n; node *n;
{ {
int i;
object *v; object *v;
REQ(n, classdef); REQ(n, classdef);
/* /* classdef: class NAME ['(' testlist ')'] ':' suite */
classdef: 'class' NAME if ((v = newstringobject(STR(CHILD(n, 1)))) == NULL) {
['(' testlist ')' |'(' ')' ['=' baselist]] ':' suite c->c_errors++;
baselist: atom arguments (',' atom arguments)* return;
arguments: '(' ')' }
*/ /* Push the class name on the stack */
/* This piece of code must push a tuple on the stack (the bases) */ i = com_addconst(c, v);
if (TYPE(CHILD(n, 2)) != LPAR) { com_addoparg(c, LOAD_CONST, i);
/* New syntax without base classes: DECREF(v);
class NAME ':' suite /* Push the tuple of base classes on the stack */
___________^ if (TYPE(CHILD(n, 2)) != LPAR)
*/
com_addoparg(c, BUILD_TUPLE, 0); com_addoparg(c, BUILD_TUPLE, 0);
} else
else { com_bases(c, CHILD(n, 3));
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));
}
}
v = (object *)compile(n, c->c_filename); v = (object *)compile(n, c->c_filename);
if (v == NULL) if (v == NULL)
c->c_errors++; c->c_errors++;
else { else {
int i = com_addconst(c, v); i = com_addconst(c, v);
com_addoparg(c, LOAD_CONST, i); com_addoparg(c, LOAD_CONST, i);
com_addbyte(c, BUILD_FUNCTION); com_addbyte(c, BUILD_FUNCTION);
com_addbyte(c, UNARY_CALL); com_addbyte(c, UNARY_CALL);
@ -1882,6 +1907,9 @@ com_node(c, n)
case global_stmt: case global_stmt:
com_global_stmt(c, n); com_global_stmt(c, n);
break; break;
case access_stmt:
com_access_stmt(c, n);
break;
case if_stmt: case if_stmt:
com_if_stmt(c, n); com_if_stmt(c, n);
break; break;
@ -2084,9 +2112,8 @@ compile_node(c, n)
break; break;
case classdef: /* A class definition */ case classdef: /* A class definition */
/* classdef: 'class' NAME /* classdef: 'class' NAME ['(' testlist ')'] ':' suite */
['(' testlist ')' |'(' ')' ['=' baselist]] c->c_name = STR(CHILD(n, 1));
':' suite */
com_node(c, CHILD(n, NCH(n)-1)); /* The suite */ com_node(c, CHILD(n, NCH(n)-1)); /* The suite */
com_addbyte(c, LOAD_LOCALS); com_addbyte(c, LOAD_LOCALS);
com_addbyte(c, RETURN_VALUE); com_addbyte(c, RETURN_VALUE);
@ -2114,8 +2141,8 @@ compile_node(c, n)
There is one problem: 'from foo import *' introduces local variables 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 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 optimize at all (this rarely happens, since this form of import
at the module level). statement is mostly used at the module level).
Note that, because of this optimization, code like the following Note that, because of this optimization, code like the following
won't work: 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 */ /* 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; static object *modules;
@ -353,46 +353,27 @@ reload_module(m)
return get_module(m, getmodulename(m), (object **)NULL); 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 void
doneimport() doneimport()
{ {
if (modules != NULL) { if (modules != NULL) {
int i; int pos;
object *modname, *module;
/* Explicitly erase all modules; this is the safest way /* Explicitly erase all modules; this is the safest way
to get rid of at least *some* circular dependencies */ to get rid of at least *some* circular dependencies */
for (i = getdictsize(modules); --i >= 0; ) { pos = 0;
object *k; while (mappinggetnext(modules, &pos, &modname, &module)) {
k = getdict2key(modules, i); if (is_moduleobject(module)) {
if (k != NULL) { object *dict;
object *m; dict = getmoduledict(module);
m = dict2lookup(modules, k); if (dict != NULL && is_dictobject(dict))
if (m == NULL) mappingclear(dict);
err_clear();
else if (is_moduleobject(m)) {
object *d;
d = getmoduledict(m);
if (d != NULL && is_dictobject(d)) {
cleardict(d);
}
}
} }
} }
cleardict(modules); mappingclear(modules);
} }
DECREF(modules); DECREF(modules);
modules = NULL;
} }

View File

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