mirror of
https://github.com/python/cpython.git
synced 2025-10-21 22:22:48 +00:00
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
21 changed files with 1223 additions and 823 deletions
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:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue