Index: Python/ceval.c =================================================================== --- Python/ceval.c (revision 54401) +++ Python/ceval.c (working copy) @@ -1532,6 +1532,13 @@ } break; + case STORE_LOCALS: + x = POP(); + v = f->f_locals; + Py_XDECREF(v); + f->f_locals = x; + continue; + case LOAD_LOCALS: if ((x = f->f_locals) != NULL) { Py_INCREF(x); Index: Python/graminit.c =================================================================== --- Python/graminit.c (revision 54401) +++ Python/graminit.c (working copy) @@ -1635,7 +1635,7 @@ {23, 4}, }; static arc arcs_76_3[2] = { - {9, 5}, + {14, 5}, {15, 6}, }; static arc arcs_76_4[1] = { Index: Python/ast.c =================================================================== --- Python/ast.c (revision 54401) +++ Python/ast.c (working copy) @@ -2092,28 +2092,6 @@ return ast_for_testlist(c, n); } -/* like ast_for_testlist() but returns a sequence */ -static asdl_seq* -ast_for_class_bases(struct compiling *c, const node* n) -{ - /* testlist: test (',' test)* [','] */ - assert(NCH(n) > 0); - REQ(n, testlist); - if (NCH(n) == 1) { - expr_ty base; - asdl_seq *bases = asdl_seq_new(1, c->c_arena); - if (!bases) - return NULL; - base = ast_for_expr(c, CHILD(n, 0)); - if (!base) - return NULL; - asdl_seq_SET(bases, 0, base); - return bases; - } - - return seq_for_testlist(c, n); -} - static stmt_ty ast_for_expr_stmt(struct compiling *c, const node *n) { @@ -3032,9 +3010,10 @@ static stmt_ty ast_for_classdef(struct compiling *c, const node *n) { - /* classdef: 'class' NAME ['(' testlist ')'] ':' suite */ - asdl_seq *bases, *s; - + /* classdef: 'class' NAME ['(' arglist ')'] ':' suite */ + asdl_seq *s; + expr_ty call, dummy; + REQ(n, classdef); if (!strcmp(STR(CHILD(n, 1)), "None")) { @@ -3042,32 +3021,36 @@ return NULL; } - if (NCH(n) == 4) { + if (NCH(n) == 4) { /* class NAME ':' suite */ s = ast_for_suite(c, CHILD(n, 3)); if (!s) return NULL; - return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, s, LINENO(n), - n->n_col_offset, c->c_arena); + return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, NULL, NULL, NULL, s, + LINENO(n), n->n_col_offset, c->c_arena); } - /* check for empty base list */ - if (TYPE(CHILD(n,3)) == RPAR) { + + if (TYPE(CHILD(n, 3)) == RPAR) { /* class NAME '(' ')' ':' suite */ s = ast_for_suite(c, CHILD(n,5)); if (!s) return NULL; - return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, s, LINENO(n), - n->n_col_offset, c->c_arena); + return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), NULL, NULL, NULL, NULL, s, + LINENO(n), n->n_col_offset, c->c_arena); } - /* else handle the base class list */ - bases = ast_for_class_bases(c, CHILD(n, 3)); - if (!bases) + /* class NAME '(' arglist ')' ':' suite */ + /* build up a fake Call node so we can extract its pieces */ + dummy = Name(NEW_IDENTIFIER(CHILD(n, 1)), Load, LINENO(n), n->n_col_offset, c->c_arena); + call = ast_for_call(c, CHILD(n, 3), dummy); + if (!call) return NULL; - s = ast_for_suite(c, CHILD(n, 6)); if (!s) return NULL; - return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), bases, s, LINENO(n), - n->n_col_offset, c->c_arena); + + return ClassDef(NEW_IDENTIFIER(CHILD(n, 1)), + call->v.Call.args, call->v.Call.keywords, + call->v.Call.starargs, call->v.Call.kwargs, s, + LINENO(n), n->n_col_offset, c->c_arena); } static stmt_ty Index: Python/import.c =================================================================== --- Python/import.c (revision 54401) +++ Python/import.c (working copy) @@ -72,9 +72,10 @@ 3030 (added keyword-only parameters) 3040 (added signature annotations) 3050 (print becomes a function) + 3060 (PEP 3115 metaclass syntax) . */ -#define MAGIC (3050 | ((long)'\r'<<16) | ((long)'\n'<<24)) +#define MAGIC (3060 | ((long)'\r'<<16) | ((long)'\n'<<24)) /* Magic word as global; note that _PyImport_Init() can change the value of this global to accommodate for alterations of how the Index: Python/symtable.c =================================================================== --- Python/symtable.c (revision 54401) +++ Python/symtable.c (working copy) @@ -983,6 +983,11 @@ if (!symtable_add_def(st, s->v.ClassDef.name, DEF_LOCAL)) return 0; VISIT_SEQ(st, expr, s->v.ClassDef.bases); + VISIT_SEQ(st, expr, s->v.ClassDef.keywords); + if (s->v.ClassDef.starargs) + VISIT(st, expr, s->v.ClassDef.starargs); + if (s->v.ClassDef.kwargs) + VISIT(st, expr, s->v.ClassDef.kwargs); if (!symtable_enter_block(st, s->v.ClassDef.name, ClassBlock, (void *)s, s->lineno)) return 0; Index: Python/compile.c =================================================================== --- Python/compile.c (revision 54401) +++ Python/compile.c (working copy) @@ -176,6 +176,11 @@ static int expr_constant(expr_ty e); static int compiler_with(struct compiler *, stmt_ty); +static int compiler_call_helper(struct compiler *c, int n, + asdl_seq *args, + asdl_seq *keywords, + expr_ty starargs, + expr_ty kwargs); static PyCodeObject *assemble(struct compiler *, int addNone); static PyObject *__doc__; @@ -744,6 +749,8 @@ return 0; case WITH_CLEANUP: return -1; /* XXX Sometimes more */ + case STORE_LOCALS: + return -1; case LOAD_LOCALS: return 1; case RETURN_VALUE: @@ -1509,54 +1516,107 @@ static int compiler_class(struct compiler *c, stmt_ty s) { - int n; + static PyObject *build_class = NULL; + static PyObject *locals = NULL; PyCodeObject *co; PyObject *str; - /* push class name on stack, needed by BUILD_CLASS */ - ADDOP_O(c, LOAD_CONST, s->v.ClassDef.name, consts); - /* push the tuple of base classes on the stack */ - n = asdl_seq_LEN(s->v.ClassDef.bases); - if (n > 0) - VISIT_SEQ(c, expr, s->v.ClassDef.bases); - ADDOP_I(c, BUILD_TUPLE, n); - if (!compiler_enter_scope(c, s->v.ClassDef.name, (void *)s, - s->lineno)) - return 0; - c->u->u_private = s->v.ClassDef.name; - Py_INCREF(c->u->u_private); - str = PyString_InternFromString("__name__"); - if (!str || !compiler_nameop(c, str, Load)) { - Py_XDECREF(str); - compiler_exit_scope(c); - return 0; + PySTEntryObject *ste; + + /* initialize statics */ + if (build_class == NULL) { + build_class = PyString_FromString("__build_class__"); + if (build_class == NULL) + return 0; } - - Py_DECREF(str); - str = PyString_InternFromString("__module__"); - if (!str || !compiler_nameop(c, str, Store)) { - Py_XDECREF(str); - compiler_exit_scope(c); - return 0; + if (locals == NULL) { + locals = PyString_FromString("__locals__"); + if (locals == NULL) + return 0; } - Py_DECREF(str); - if (!compiler_body(c, s->v.ClassDef.body)) { - compiler_exit_scope(c); + /* ultimately generate code for: + = __build_class__(, , *, **) + where: + is a function/closure created from the class body + is the class name + is the positional arguments and *varargs argument + is the keyword arguments and **kwds argument + This borrows from compiler_call. + */ + + /* 0. Create a fake variable named __locals__ */ + ste = PySymtable_Lookup(c->c_st, s); + if (ste == NULL) return 0; + assert(PyList_Check(ste->ste_varnames)); + if (PyList_Append(ste->ste_varnames, locals) < 0) + return 0; + + /* 1. compile the class body into a code object */ + if (!compiler_enter_scope(c, s->v.ClassDef.name, (void *)s, s->lineno)) + return 0; + /* this block represents what we do in the new scope */ + { + /* use the class name for name mangling */ + Py_INCREF(s->v.ClassDef.name); + c->u->u_private = s->v.ClassDef.name; + /* force it to have one mandatory argument */ + c->u->u_argcount = 1; + /* load the first argument ... */ + ADDOP_I(c, LOAD_FAST, 0); + /* ... and store it into f_locals */ + ADDOP_IN_SCOPE(c, STORE_LOCALS); + /* load __name__ ... */ + str = PyString_InternFromString("__name__"); + if (!str || !compiler_nameop(c, str, Load)) { + Py_XDECREF(str); + compiler_exit_scope(c); + return 0; + } + Py_DECREF(str); + /* ... and store it as __module__ */ + str = PyString_InternFromString("__module__"); + if (!str || !compiler_nameop(c, str, Store)) { + Py_XDECREF(str); + compiler_exit_scope(c); + return 0; + } + Py_DECREF(str); + /* compile the body proper */ + if (!compiler_body(c, s->v.ClassDef.body)) { + compiler_exit_scope(c); + return 0; + } + /* return the locals (really for b/w compatibility only) */ + ADDOP_IN_SCOPE(c, LOAD_LOCALS); + ADDOP_IN_SCOPE(c, RETURN_VALUE); + /* create the code object */ + co = assemble(c, 1); } - - ADDOP_IN_SCOPE(c, LOAD_LOCALS); - ADDOP_IN_SCOPE(c, RETURN_VALUE); - co = assemble(c, 1); + /* leave the new scope */ compiler_exit_scope(c); if (co == NULL) return 0; + /* 2. load __build_class__ */ + ADDOP_O(c, LOAD_GLOBAL, build_class, names); + + /* 3. load a function (or closure) made from the code object */ compiler_make_closure(c, co, 0); Py_DECREF(co); - ADDOP_I(c, CALL_FUNCTION, 0); - ADDOP(c, BUILD_CLASS); + /* 4. load class name */ + ADDOP_O(c, LOAD_CONST, s->v.ClassDef.name, consts); + + /* 5. generate the rest of the code for the call */ + if (!compiler_call_helper(c, 2, + s->v.ClassDef.bases, + s->v.ClassDef.keywords, + s->v.ClassDef.starargs, + s->v.ClassDef.kwargs)) + return 0; + + /* 6. store into */ if (!compiler_nameop(c, s->v.ClassDef.name, Store)) return 0; return 1; @@ -2613,21 +2673,37 @@ static int compiler_call(struct compiler *c, expr_ty e) { - int n, code = 0; + VISIT(c, expr, e->v.Call.func); + return compiler_call_helper(c, 0, + e->v.Call.args, + e->v.Call.keywords, + e->v.Call.starargs, + e->v.Call.kwargs); +} - VISIT(c, expr, e->v.Call.func); - n = asdl_seq_LEN(e->v.Call.args); - VISIT_SEQ(c, expr, e->v.Call.args); - if (e->v.Call.keywords) { - VISIT_SEQ(c, keyword, e->v.Call.keywords); - n |= asdl_seq_LEN(e->v.Call.keywords) << 8; +/* shared code between compiler_call and compiler_class */ +static int +compiler_call_helper(struct compiler *c, + int n, /* Args already pushed */ + asdl_seq *args, + asdl_seq *keywords, + expr_ty starargs, + expr_ty kwargs) +{ + int code = 0; + + n += asdl_seq_LEN(args); + VISIT_SEQ(c, expr, args); + if (keywords) { + VISIT_SEQ(c, keyword, keywords); + n |= asdl_seq_LEN(keywords) << 8; } - if (e->v.Call.starargs) { - VISIT(c, expr, e->v.Call.starargs); + if (starargs) { + VISIT(c, expr, starargs); code |= 1; } - if (e->v.Call.kwargs) { - VISIT(c, expr, e->v.Call.kwargs); + if (kwargs) { + VISIT(c, expr, kwargs); code |= 2; } switch (code) { Index: Python/Python-ast.c =================================================================== --- Python/Python-ast.c (revision 54401) +++ Python/Python-ast.c (working copy) @@ -49,6 +49,9 @@ static char *ClassDef_fields[]={ "name", "bases", + "keywords", + "starargs", + "kwargs", "body", }; static PyTypeObject *Return_type; @@ -477,7 +480,7 @@ FunctionDef_type = make_type("FunctionDef", stmt_type, FunctionDef_fields, 5); if (!FunctionDef_type) return 0; - ClassDef_type = make_type("ClassDef", stmt_type, ClassDef_fields, 3); + ClassDef_type = make_type("ClassDef", stmt_type, ClassDef_fields, 6); if (!ClassDef_type) return 0; Return_type = make_type("Return", stmt_type, Return_fields, 1); if (!Return_type) return 0; @@ -835,8 +838,9 @@ } stmt_ty -ClassDef(identifier name, asdl_seq * bases, asdl_seq * body, int lineno, int - col_offset, PyArena *arena) +ClassDef(identifier name, asdl_seq * bases, asdl_seq * keywords, expr_ty + starargs, expr_ty kwargs, asdl_seq * body, int lineno, int col_offset, + PyArena *arena) { stmt_ty p; if (!name) { @@ -850,6 +854,9 @@ p->kind = ClassDef_kind; p->v.ClassDef.name = name; p->v.ClassDef.bases = bases; + p->v.ClassDef.keywords = keywords; + p->v.ClassDef.starargs = starargs; + p->v.ClassDef.kwargs = kwargs; p->v.ClassDef.body = body; p->lineno = lineno; p->col_offset = col_offset; @@ -1974,6 +1981,21 @@ if (PyObject_SetAttrString(result, "bases", value) == -1) goto failed; Py_DECREF(value); + value = ast2obj_list(o->v.ClassDef.keywords, ast2obj_keyword); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "keywords", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.ClassDef.starargs); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "starargs", value) == -1) + goto failed; + Py_DECREF(value); + value = ast2obj_expr(o->v.ClassDef.kwargs); + if (!value) goto failed; + if (PyObject_SetAttrString(result, "kwargs", value) == -1) + goto failed; + Py_DECREF(value); value = ast2obj_list(o->v.ClassDef.body, ast2obj_stmt); if (!value) goto failed; if (PyObject_SetAttrString(result, "body", value) == -1) Index: Python/bltinmodule.c =================================================================== --- Python/bltinmodule.c (revision 54401) +++ Python/bltinmodule.c (working copy) @@ -31,6 +31,118 @@ static PyObject *filtertuple (PyObject *, PyObject *); static PyObject * +builtin___build_class__(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *func, *name, *bases, *metaclass, *prep, *namespace, *res; + Py_ssize_t nargs, nbases; + + assert(args != NULL); + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_TypeError, + "__build_class__: args is not a tuple"); + return NULL; + } + nargs = PyTuple_GET_SIZE(args); + if (nargs < 2) { + PyErr_SetString(PyExc_TypeError, + "__build_class__: not enough arguments"); + return NULL; + } + func = PyTuple_GET_ITEM(args, 0); /* Better be callable */ + name = PyTuple_GET_ITEM(args, 1); + if (!PyString_Check(name)) { + PyErr_SetString(PyExc_TypeError, + "__build_class__: name is not a string"); + return NULL; + } + bases = PyTuple_GetSlice(args, 2, nargs); + if (bases == NULL) + return NULL; + nbases = nargs - 2; + + if (kwds == NULL) + metaclass = NULL; + else { + metaclass = PyDict_GetItemString(kwds, "metaclass"); + if (metaclass != NULL) { + Py_INCREF(metaclass); + if (PyDict_DelItemString(kwds, "metaclass") < 0) { + Py_DECREF(metaclass); + Py_DECREF(bases); + return NULL; + } + } + } + if (metaclass == NULL) { + if (PyTuple_GET_SIZE(bases) == 0) + metaclass = (PyObject *) (&PyType_Type); + else { + PyObject *base0 = PyTuple_GET_ITEM(bases, 0); + metaclass = (PyObject *) (base0->ob_type); + } + Py_INCREF(metaclass); + } + prep = PyObject_GetAttrString(metaclass, "__prepare__"); + if (prep == NULL) { + PyErr_Clear(); + namespace = PyDict_New(); + } + else { + PyObject *pargs; + int i; + pargs = PyTuple_New(nargs-1); + if (pargs == NULL) { + Py_DECREF(prep); + Py_DECREF(metaclass); + Py_DECREF(bases); + return NULL; + } + Py_INCREF(name); + PyTuple_SET_ITEM(pargs, 0, name); + for (i = 0; i < nbases; i++) { + PyObject *base = PyTuple_GET_ITEM(bases, i); + Py_INCREF(base); + PyTuple_SET_ITEM(pargs, i+1, base); + } + namespace = PyEval_CallObjectWithKeywords(prep, pargs, kwds); + Py_DECREF(pargs); + Py_DECREF(prep); + if (namespace == NULL) { + Py_DECREF(metaclass); + Py_DECREF(bases); + return NULL; + } + } + res = PyObject_CallFunctionObjArgs(func, namespace, NULL); + if (res != NULL) { + PyObject *margs; + Py_DECREF(res); + res = NULL; + margs = PyTuple_New(3); + if (margs != NULL) { + Py_INCREF(name); + PyTuple_SET_ITEM(margs, 0, name); + Py_INCREF(bases); + PyTuple_SET_ITEM(margs, 1, bases); + Py_INCREF(namespace); + PyTuple_SET_ITEM(margs, 2, namespace); + res = PyEval_CallObjectWithKeywords(metaclass, + margs, kwds); + Py_DECREF(margs); + } + } + Py_DECREF(namespace); + Py_DECREF(metaclass); + Py_DECREF(bases); + return res; +} + +PyDoc_STRVAR(build_class_doc, +"__build_class__(func, name, *bases, metaclass=None, **kwds) -> class\n\ +\n\ +Internal helper function used by the class statement."); + +static PyObject * builtin___import__(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"name", "globals", "locals", "fromlist", @@ -2103,6 +2215,8 @@ static PyMethodDef builtin_methods[] = { + {"__build_class__", (PyCFunction)builtin___build_class__, + METH_VARARGS | METH_KEYWORDS, build_class_doc}, {"__import__", (PyCFunction)builtin___import__, METH_VARARGS | METH_KEYWORDS, import_doc}, {"abs", builtin_abs, METH_O, abs_doc}, {"all", builtin_all, METH_O, all_doc}, Index: Include/opcode.h =================================================================== --- Include/opcode.h (revision 54401) +++ Include/opcode.h (working copy) @@ -59,6 +59,7 @@ #define BINARY_OR 66 #define INPLACE_POWER 67 #define GET_ITER 68 +#define STORE_LOCALS 69 #define PRINT_EXPR 70 @@ -120,10 +121,10 @@ #define RAISE_VARARGS 130 /* Number of raise arguments (1, 2 or 3) */ /* CALL_FUNCTION_XXX opcodes defined below depend on this definition */ #define CALL_FUNCTION 131 /* #args + (#kwargs<<8) */ -#define MAKE_FUNCTION 132 /* #defaults */ +#define MAKE_FUNCTION 132 /* #defaults + #kwdefaults<<8 + #annotations<<16 */ #define BUILD_SLICE 133 /* Number of items */ -#define MAKE_CLOSURE 134 /* #free vars */ +#define MAKE_CLOSURE 134 /* same as MAKE_FUNCTION */ #define LOAD_CLOSURE 135 /* Load free variable from closure */ #define LOAD_DEREF 136 /* Load and dereference from closure cell */ #define STORE_DEREF 137 /* Store into cell */ Index: Include/Python-ast.h =================================================================== --- Include/Python-ast.h (revision 54401) +++ Include/Python-ast.h (working copy) @@ -82,6 +82,9 @@ struct { identifier name; asdl_seq *bases; + asdl_seq *keywords; + expr_ty starargs; + expr_ty kwargs; asdl_seq *body; } ClassDef; @@ -380,8 +383,9 @@ stmt_ty _Py_FunctionDef(identifier name, arguments_ty args, asdl_seq * body, asdl_seq * decorators, expr_ty returns, int lineno, int col_offset, PyArena *arena); -#define ClassDef(a0, a1, a2, a3, a4, a5) _Py_ClassDef(a0, a1, a2, a3, a4, a5) -stmt_ty _Py_ClassDef(identifier name, asdl_seq * bases, asdl_seq * body, int +#define ClassDef(a0, a1, a2, a3, a4, a5, a6, a7, a8) _Py_ClassDef(a0, a1, a2, a3, a4, a5, a6, a7, a8) +stmt_ty _Py_ClassDef(identifier name, asdl_seq * bases, asdl_seq * keywords, + expr_ty starargs, expr_ty kwargs, asdl_seq * body, int lineno, int col_offset, PyArena *arena); #define Return(a0, a1, a2, a3) _Py_Return(a0, a1, a2, a3) stmt_ty _Py_Return(expr_ty value, int lineno, int col_offset, PyArena *arena); Index: Grammar/Grammar =================================================================== --- Grammar/Grammar (revision 54401) +++ Grammar/Grammar (working copy) @@ -119,7 +119,7 @@ testlist: test (',' test)* [','] dictsetmaker: (test ':' test (',' test ':' test)* [',']) | (test (',' test)* [',']) -classdef: 'class' NAME ['(' [testlist] ')'] ':' suite +classdef: 'class' NAME ['(' [arglist] ')'] ':' suite arglist: (argument ',')* (argument [',']| '*' test [',' '**' test] | '**' test) argument: test [gen_for] | test '=' test # Really [keyword '='] test Index: Parser/Python.asdl =================================================================== --- Parser/Python.asdl (revision 54401) +++ Parser/Python.asdl (working copy) @@ -11,7 +11,12 @@ stmt = FunctionDef(identifier name, arguments args, stmt* body, expr* decorators, expr? returns) - | ClassDef(identifier name, expr* bases, stmt* body) + | ClassDef(identifier name, + expr* bases, + keyword* keywords, + expr? starargs, + expr? kwargs, + stmt* body) | Return(expr? value) | Delete(expr* targets) Index: Lib/opcode.py =================================================================== --- Lib/opcode.py (revision 54401) +++ Lib/opcode.py (working copy) @@ -98,6 +98,7 @@ def_op('BINARY_OR', 66) def_op('INPLACE_POWER', 67) def_op('GET_ITER', 68) +def_op('STORE_LOCALS', 69) def_op('PRINT_EXPR', 70) Index: Modules/_bsddb.c =================================================================== --- Modules/_bsddb.c (revision 54401) +++ Modules/_bsddb.c (working copy) @@ -5991,6 +5991,10 @@ * from both DBError and KeyError, since the API only supports * using one base class. */ PyDict_SetItemString(d, "KeyError", PyExc_KeyError); + { + PyObject *builtin_mod = PyImport_ImportModule("__builtin__"); + PyDict_SetItemString(d, "__builtins__", builtin_mod); + } PyRun_String("class DBNotFoundError(DBError, KeyError): pass\n" "class DBKeyEmptyError(DBError, KeyError): pass", Py_file_input, d, d);