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:
parent
687dd13bfe
commit
25831652fd
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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 *));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 /* "" */
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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*/
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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");
|
||||
|
|
215
Python/ceval.c
215
Python/ceval.c
|
@ -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;
|
||||
|
@ -1124,6 +1181,13 @@ eval_code(co, globals, locals, arg)
|
|||
err = import_from(f->f_locals, v, w);
|
||||
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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
137
Python/compile.c
137
Python/compile.c
|
@ -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:
|
||||
|
|
1026
Python/graminit.c
1026
Python/graminit.c
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue