diff --git a/py3k/Doc/library/dis.rst b/py3k/Doc/library/dis.rst index 8d4d956..b095b85 100644 --- a/py3k/Doc/library/dis.rst +++ b/py3k/Doc/library/dis.rst @@ -228,6 +228,11 @@ result back on the stack. Implements ``TOS = TOS1 % TOS``. +.. opcode:: BINARY_AT () + + Implements ``TOS = TOS1 @ TOS``. + + .. opcode:: BINARY_ADD () Implements ``TOS = TOS1 + TOS``. @@ -299,6 +304,11 @@ the original TOS1. Implements in-place ``TOS = TOS1 % TOS``. +.. opcode:: INPLACE_AT () + + Implements in-place ``TOS = TOS1 @ TOS``. + + .. opcode:: INPLACE_ADD () Implements in-place ``TOS = TOS1 + TOS``. diff --git a/py3k/Grammar/Grammar b/py3k/Grammar/Grammar index 1f226b8..cd3f3d4 100644 --- a/py3k/Grammar/Grammar +++ b/py3k/Grammar/Grammar @@ -40,7 +40,7 @@ small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt | expr_stmt: testlist (augassign (yield_expr|testlist) | ('=' (yield_expr|testlist))*) augassign: ('+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | - '<<=' | '>>=' | '**=' | '//=') + '<<=' | '>>=' | '**=' | '//=' | '@=') # For normal assignments, additional restrictions enforced by the interpreter del_stmt: 'del' exprlist pass_stmt: 'pass' @@ -94,7 +94,7 @@ xor_expr: and_expr ('^' and_expr)* and_expr: shift_expr ('&' shift_expr)* shift_expr: arith_expr (('<<'|'>>') arith_expr)* arith_expr: term (('+'|'-') term)* -term: factor (('*'|'/'|'%'|'//') factor)* +term: factor (('*'|'/'|'%'|'@'|'//') factor)* factor: ('+'|'-'|'~') factor | power power: atom trailer* ['**' factor] atom: ('(' [yield_expr|testlist_comp] ')' | diff --git a/py3k/Include/Python-ast.h b/py3k/Include/Python-ast.h index 0ad788b..f75705f 100644 --- a/py3k/Include/Python-ast.h +++ b/py3k/Include/Python-ast.h @@ -16,8 +16,8 @@ typedef struct _slice *slice_ty; typedef enum _boolop { And=1, Or=2 } boolop_ty; typedef enum _operator { Add=1, Sub=2, Mult=3, Div=4, Mod=5, Pow=6, LShift=7, - RShift=8, BitOr=9, BitXor=10, BitAnd=11, FloorDiv=12 } - operator_ty; + RShift=8, BitOr=9, BitXor=10, BitAnd=11, FloorDiv=12, + At=13 } operator_ty; typedef enum _unaryop { Invert=1, Not=2, UAdd=3, USub=4 } unaryop_ty; diff --git a/py3k/Include/opcode.h b/py3k/Include/opcode.h index 2b1c59d..190f71d 100644 --- a/py3k/Include/opcode.h +++ b/py3k/Include/opcode.h @@ -33,6 +33,8 @@ extern "C" { #define BINARY_TRUE_DIVIDE 27 #define INPLACE_FLOOR_DIVIDE 28 #define INPLACE_TRUE_DIVIDE 29 +#define BINARY_AT 30 +#define INPLACE_AT 31 #define STORE_MAP 54 #define INPLACE_ADD 55 diff --git a/py3k/Include/token.h b/py3k/Include/token.h index 772a85e..f79747b 100644 --- a/py3k/Include/token.h +++ b/py3k/Include/token.h @@ -64,6 +64,7 @@ extern "C" { #define OP 53 #define ERRORTOKEN 54 #define N_TOKENS 55 +#define ATEQUAL 56 /* Special definitions for cooperation with parser */ diff --git a/py3k/Include/unicodeobject.h b/py3k/Include/unicodeobject.h index 08b518a..62b404c 100644 --- a/py3k/Include/unicodeobject.h +++ b/py3k/Include/unicodeobject.h @@ -189,6 +189,7 @@ typedef PY_UNICODE_TYPE Py_UNICODE; # define PyUnicode_EncodeUnicodeEscape PyUnicodeUCS2_EncodeUnicodeEscape # define PyUnicode_Find PyUnicodeUCS2_Find # define PyUnicode_Format PyUnicodeUCS2_Format +# define PyUnicode_FormatPrime PyUnicodeUCS2_FormatPrime # define PyUnicode_FromEncodedObject PyUnicodeUCS2_FromEncodedObject # define PyUnicode_FromFormat PyUnicodeUCS2_FromFormat # define PyUnicode_FromFormatV PyUnicodeUCS2_FromFormatV @@ -288,6 +289,7 @@ typedef PY_UNICODE_TYPE Py_UNICODE; # define PyUnicode_EncodeUnicodeEscape PyUnicodeUCS4_EncodeUnicodeEscape # define PyUnicode_Find PyUnicodeUCS4_Find # define PyUnicode_Format PyUnicodeUCS4_Format +# define PyUnicode_FormatPrime PyUnicodeUCS4_FormatPrime # define PyUnicode_FromEncodedObject PyUnicodeUCS4_FromEncodedObject # define PyUnicode_FromFormat PyUnicodeUCS4_FromFormat # define PyUnicode_FromFormatV PyUnicodeUCS4_FromFormatV @@ -1464,6 +1466,11 @@ PyAPI_FUNC(PyObject *) PyUnicode_Format( PyObject *args /* Argument tuple or dictionary */ ); +PyAPI_FUNC(PyObject *) PyUnicode_FormatPrime( + PyObject *format, /* Format string */ + PyObject *args /* Argument tuple or dictionary */ + ); + /* Checks whether element is contained in container and return 1/0 accordingly. diff --git a/py3k/Lib/opcode.py b/py3k/Lib/opcode.py index 86ebc5c..8314714 100644 --- a/py3k/Lib/opcode.py +++ b/py3k/Lib/opcode.py @@ -68,6 +68,8 @@ def jabs_op(name, op): def_op('BINARY_TRUE_DIVIDE', 27) def_op('INPLACE_FLOOR_DIVIDE', 28) def_op('INPLACE_TRUE_DIVIDE', 29) +def_op('BINARY_AT', 30) +def_op('INPLACE_AT', 31) def_op('STORE_MAP', 54) def_op('INPLACE_ADD', 55) diff --git a/py3k/Modules/parsermodule.c b/py3k/Modules/parsermodule.c index a16e69c..1025498 100644 --- a/py3k/Modules/parsermodule.c +++ b/py3k/Modules/parsermodule.c @@ -1547,6 +1547,7 @@ validate_expr_stmt(node *tree) || strcmp(s, "/=") == 0 || strcmp(s, "//=") == 0 || strcmp(s, "%=") == 0 + || strcmp(s, "@=") == 0 || strcmp(s, "&=") == 0 || strcmp(s, "|=") == 0 || strcmp(s, "^=") == 0 @@ -2251,7 +2252,8 @@ validate_term(node *tree) res = (((TYPE(CHILD(tree, pos)) == STAR) || (TYPE(CHILD(tree, pos)) == SLASH) || (TYPE(CHILD(tree, pos)) == DOUBLESLASH) - || (TYPE(CHILD(tree, pos)) == PERCENT)) + || (TYPE(CHILD(tree, pos)) == PERCENT) + || (TYPE(CHILD(tree, pos)) == AT)) && validate_factor(CHILD(tree, pos + 1))); return (res); diff --git a/py3k/Objects/unicodeobject.c b/py3k/Objects/unicodeobject.c index 0d4a3dd..6f3bea6 100644 --- a/py3k/Objects/unicodeobject.c +++ b/py3k/Objects/unicodeobject.c @@ -9067,6 +9067,71 @@ formatchar(Py_UNICODE *buf, return -1; } +PyObject * +PyUnicode_FormatPrime(PyObject *format, PyObject *args) +{ + Py_ssize_t arglen; + PyObject *dict, *last_item, *retval, *tuple; + int args_ref = 0, tuple_ref = 0; + + if (format == NULL || args == NULL) { + PyErr_BadInternalCall(); + return NULL; + } else if (!PyUnicode_Check(format)) { + PyErr_Format(PyExc_TypeError, + "unsupported operand type(s) for %.100s: " + "'%.100s' and '%.100s'", + "@", + format->ob_type->tp_name, + args->ob_type->tp_name); + return NULL; + } + + /* default values */ + tuple = args; + dict = NULL; + + if (PyTuple_Check(args)) { + arglen = PyTuple_Size(args); + + if (arglen > 1) { + /* check for existence of dict at end */ + last_item = PyTuple_GetItem(args, arglen - 1); + + if (PyDict_CheckExact(last_item)) { + dict = last_item; + + /* clone n - 1 elements of an n-sized tuple... + * does this introduce a memory leak? + */ + tuple = PyTuple_GetSlice(args, 0, arglen - 1); + args_ref = 1; + } + } + } + else if (PyDict_Check(args)) { + tuple = PyTuple_New(0); + if (!tuple) + return NULL; + dict = args; + } + else { + /* pass as one-length tuple */ + tuple = PyTuple_New(1); + tuple_ref = 1; + PyTuple_SetItem(tuple, 0, args); + Py_INCREF(args); + } + + retval = do_string_format(format, tuple, dict); + if (tuple_ref) + Py_DECREF(tuple); + if (args_ref) + Py_DECREF(args); + return retval; +} + + /* fmt%(v1,v2,...) is roughly equivalent to sprintf(fmt, v1, v2, ...) FORMATBUFLEN is the length of the buffer in which chars are formatted. */ diff --git a/py3k/Parser/Python.asdl b/py3k/Parser/Python.asdl index 7a10def..da7cb33 100644 --- a/py3k/Parser/Python.asdl +++ b/py3k/Parser/Python.asdl @@ -93,6 +93,7 @@ module Python version "$Revision: 67616 $" operator = Add | Sub | Mult | Div | Mod | Pow | LShift | RShift | BitOr | BitXor | BitAnd | FloorDiv + | At unaryop = Invert | Not | UAdd | USub diff --git a/py3k/Parser/tokenizer.c b/py3k/Parser/tokenizer.c index 15e8185..d163f08 100644 --- a/py3k/Parser/tokenizer.c +++ b/py3k/Parser/tokenizer.c @@ -103,7 +103,8 @@ char *_PyParser_TokenNames[] = { /* This table must match the #defines in token.h! */ "OP", "", - "" + "", + "ATEQUAL" }; @@ -1084,6 +1085,11 @@ PyToken_TwoChars(int c1, int c2) case '=': return PERCENTEQUAL; } break; + case '@': + switch (c2) { + case '=': return ATEQUAL; + } + break; case '&': switch (c2) { case '=': return AMPEREQUAL; diff --git a/py3k/Python/ast.c b/py3k/Python/ast.c index 83572ee..757913a 100644 --- a/py3k/Python/ast.c +++ b/py3k/Python/ast.c @@ -348,6 +348,8 @@ get_operator(const node *n) return FloorDiv; case PERCENT: return Mod; + case AT: + return At; default: return (operator_ty)0; } @@ -517,6 +519,8 @@ ast_for_augassign(struct compiling *c, const node *n) return Div; case '%': return Mod; + case '@': + return At; case '<': return LShift; case '>': diff --git a/py3k/Python/ceval.c b/py3k/Python/ceval.c index b5b5c27..bcafd65 100644 --- a/py3k/Python/ceval.c +++ b/py3k/Python/ceval.c @@ -1456,6 +1456,16 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) if (x != NULL) DISPATCH(); break; + TARGET(BINARY_AT) + w = POP(); + v = TOP(); + x = PyUnicode_FormatPrime(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) DISPATCH(); + break; + TARGET(BINARY_ADD) w = POP(); v = TOP(); @@ -1617,6 +1627,16 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) if (x != NULL) DISPATCH(); break; + TARGET(INPLACE_AT) + w = POP(); + v = TOP(); + x = PyUnicode_FormatPrime(v, w); + Py_DECREF(v); + Py_DECREF(w); + SET_TOP(x); + if (x != NULL) DISPATCH(); + break; + TARGET(INPLACE_ADD) w = POP(); v = TOP(); diff --git a/py3k/Python/compile.c b/py3k/Python/compile.c index c78949d..f0ef6e3 100644 --- a/py3k/Python/compile.c +++ b/py3k/Python/compile.c @@ -716,6 +716,7 @@ opcode_stack_effect(int opcode, int oparg) case BINARY_POWER: case BINARY_MULTIPLY: case BINARY_MODULO: + case BINARY_AT: case BINARY_ADD: case BINARY_SUBTRACT: case BINARY_SUBSCR: @@ -730,6 +731,7 @@ opcode_stack_effect(int opcode, int oparg) case INPLACE_SUBTRACT: case INPLACE_MULTIPLY: case INPLACE_MODULO: + case INPLACE_AT: return -1; case STORE_SUBSCR: return -3; @@ -2388,6 +2390,8 @@ binop(struct compiler *c, operator_ty op) return BINARY_TRUE_DIVIDE; case Mod: return BINARY_MODULO; + case At: + return BINARY_AT; case Pow: return BINARY_POWER; case LShift: @@ -2452,6 +2456,8 @@ inplace_binop(struct compiler *c, operator_ty op) return INPLACE_TRUE_DIVIDE; case Mod: return INPLACE_MODULO; + case At: + return INPLACE_AT; case Pow: return INPLACE_POWER; case LShift: diff --git a/py3k/Python/opcode_targets.h b/py3k/Python/opcode_targets.h index 043e42a..20a00a1 100644 --- a/py3k/Python/opcode_targets.h +++ b/py3k/Python/opcode_targets.h @@ -29,8 +29,8 @@ static void *opcode_targets[256] = { &&TARGET_BINARY_TRUE_DIVIDE, &&TARGET_INPLACE_FLOOR_DIVIDE, &&TARGET_INPLACE_TRUE_DIVIDE, - &&_unknown_opcode, - &&_unknown_opcode, + &&TARGET_BINARY_AT, + &&TARGET_INPLACE_AT, &&_unknown_opcode, &&_unknown_opcode, &&_unknown_opcode,