Commit 4668b000 authored by Guido van Rossum's avatar Guido van Rossum

Implement PEP 238 in its (almost) full glory.

This introduces:

- A new operator // that means floor division (the kind of division
  where 1/2 is 0).

- The "future division" statement ("from __future__ import division)
  which changes the meaning of the / operator to implement "true
  division" (where 1/2 is 0.5).

- New overloadable operators __truediv__ and __floordiv__.

- New slots in the PyNumberMethods struct for true and floor division,
  new abstract APIs for them, new opcodes, and so on.

I emphasize that without the future division statement, the semantics
of / will remain unchanged until Python 3.0.

Not yet implemented are warnings (default off) when / is used with int
or long arguments.

This has been on display since 7/31 as SF patch #443474.

Flames to /dev/null.
parent 074c9d2b
...@@ -38,7 +38,7 @@ stmt: simple_stmt | compound_stmt ...@@ -38,7 +38,7 @@ 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 | exec_stmt | assert_stmt small_stmt: expr_stmt | print_stmt | del_stmt | pass_stmt | flow_stmt | import_stmt | global_stmt | exec_stmt | assert_stmt
expr_stmt: testlist (augassign testlist | ('=' testlist)*) expr_stmt: testlist (augassign testlist | ('=' testlist)*)
augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//='
# For normal assignments, additional restrictions enforced by the interpreter # For normal assignments, additional restrictions enforced by the interpreter
print_stmt: 'print' ( [ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ] ) print_stmt: 'print' ( [ test (',' test)* [','] ] | '>>' test [ (',' test)+ [','] ] )
del_stmt: 'del' exprlist del_stmt: 'del' exprlist
...@@ -77,7 +77,7 @@ xor_expr: and_expr ('^' and_expr)* ...@@ -77,7 +77,7 @@ xor_expr: and_expr ('^' and_expr)*
and_expr: shift_expr ('&' shift_expr)* and_expr: shift_expr ('&' shift_expr)*
shift_expr: arith_expr (('<<'|'>>') arith_expr)* shift_expr: arith_expr (('<<'|'>>') arith_expr)*
arith_expr: term (('+'|'-') term)* arith_expr: term (('+'|'-') term)*
term: factor (('*'|'/'|'%') factor)* term: factor (('*'|'/'|'%'|'//') factor)*
factor: ('+'|'-'|'~') factor | power factor: ('+'|'-'|'~') factor | power
power: atom trailer* ('**' factor)* power: atom trailer* ('**' factor)*
atom: '(' [testlist] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+ atom: '(' [testlist] ')' | '[' [listmaker] ']' | '{' [dictmaker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+
......
...@@ -547,6 +547,26 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/ ...@@ -547,6 +547,26 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
*/ */
DL_IMPORT(PyObject *) PyNumber_FloorDivide(PyObject *o1, PyObject *o2);
/*
Returns the result of dividing o1 by o2 giving an integral result,
or null on failure.
This is the equivalent of the Python expression: o1//o2.
*/
DL_IMPORT(PyObject *) PyNumber_TrueDivide(PyObject *o1, PyObject *o2);
/*
Returns the result of dividing o1 by o2 giving a float result,
or null on failure.
This is the equivalent of the Python expression: o1/o2.
*/
DL_IMPORT(PyObject *) PyNumber_Remainder(PyObject *o1, PyObject *o2); DL_IMPORT(PyObject *) PyNumber_Remainder(PyObject *o1, PyObject *o2);
/* /*
...@@ -742,6 +762,28 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/ ...@@ -742,6 +762,28 @@ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx*/
*/ */
DL_IMPORT(PyObject *) PyNumber_InPlaceFloorDivide(PyObject *o1,
PyObject *o2);
/*
Returns the result of dividing o1 by o2 giving an integral result,
possibly in-place, or null on failure.
This is the equivalent of the Python expression:
o1 /= o2.
*/
DL_IMPORT(PyObject *) PyNumber_InPlaceTrueDivide(PyObject *o1,
PyObject *o2);
/*
Returns the result of dividing o1 by o2 giving a float result,
possibly in-place, or null on failure.
This is the equivalent of the Python expression:
o1 /= o2.
*/
DL_IMPORT(PyObject *) PyNumber_InPlaceRemainder(PyObject *o1, PyObject *o2); DL_IMPORT(PyObject *) PyNumber_InPlaceRemainder(PyObject *o1, PyObject *o2);
/* /*
......
...@@ -41,6 +41,8 @@ typedef struct { ...@@ -41,6 +41,8 @@ typedef struct {
effect, this passes on the "from __future__ import generators" state effect, this passes on the "from __future__ import generators" state
in effect when the code block was compiled. */ in effect when the code block was compiled. */
#define CO_GENERATOR_ALLOWED 0x1000 #define CO_GENERATOR_ALLOWED 0x1000
/* XXX Ditto for future division */
#define CO_FUTURE_DIVISION 0x2000
extern DL_IMPORT(PyTypeObject) PyCode_Type; extern DL_IMPORT(PyTypeObject) PyCode_Type;
...@@ -64,6 +66,7 @@ typedef struct { ...@@ -64,6 +66,7 @@ typedef struct {
int ff_last_lineno; int ff_last_lineno;
int ff_nested_scopes; int ff_nested_scopes;
int ff_generators; int ff_generators;
int ff_division;
} PyFutureFeatures; } PyFutureFeatures;
DL_IMPORT(PyFutureFeatures *) PyNode_Future(struct _node *, char *); DL_IMPORT(PyFutureFeatures *) PyNode_Future(struct _node *, char *);
...@@ -76,6 +79,9 @@ DL_IMPORT(PyCodeObject *) PyNode_CompileFlags(struct _node *, char *, ...@@ -76,6 +79,9 @@ DL_IMPORT(PyCodeObject *) PyNode_CompileFlags(struct _node *, char *,
#define GENERATORS_DEFAULT 0 #define GENERATORS_DEFAULT 0
#define FUTURE_GENERATORS "generators" #define FUTURE_GENERATORS "generators"
#define DIVISION_DEFAULT 0
#define FUTURE_DIVISION "division"
/* for internal use only */ /* for internal use only */
#define _PyCode_GETCODEPTR(co, pp) \ #define _PyCode_GETCODEPTR(co, pp) \
((*(co)->co_code->ob_type->tp_as_buffer->bf_getreadbuffer) \ ((*(co)->co_code->ob_type->tp_as_buffer->bf_getreadbuffer) \
......
...@@ -161,6 +161,12 @@ typedef struct { ...@@ -161,6 +161,12 @@ typedef struct {
binaryfunc nb_inplace_and; binaryfunc nb_inplace_and;
binaryfunc nb_inplace_xor; binaryfunc nb_inplace_xor;
binaryfunc nb_inplace_or; binaryfunc nb_inplace_or;
/* The following require the Py_TPFLAGS_HAVE_CLASS flag */
binaryfunc nb_floor_divide;
binaryfunc nb_true_divide;
binaryfunc nb_inplace_floor_divide;
binaryfunc nb_inplace_true_divide;
} PyNumberMethods; } PyNumberMethods;
typedef struct { typedef struct {
...@@ -396,7 +402,7 @@ given type object has a specified feature. ...@@ -396,7 +402,7 @@ given type object has a specified feature.
/* tp_iter is defined */ /* tp_iter is defined */
#define Py_TPFLAGS_HAVE_ITER (1L<<7) #define Py_TPFLAGS_HAVE_ITER (1L<<7)
/* Experimental stuff for healing the type/class split */ /* New members introduced by Python 2.2 exist */
#define Py_TPFLAGS_HAVE_CLASS (1L<<8) #define Py_TPFLAGS_HAVE_CLASS (1L<<8)
/* Set if the type object is dynamically allocated */ /* Set if the type object is dynamically allocated */
......
...@@ -29,6 +29,10 @@ extern "C" { ...@@ -29,6 +29,10 @@ extern "C" {
#define BINARY_ADD 23 #define BINARY_ADD 23
#define BINARY_SUBTRACT 24 #define BINARY_SUBTRACT 24
#define BINARY_SUBSCR 25 #define BINARY_SUBSCR 25
#define BINARY_FLOOR_DIVIDE 26
#define BINARY_TRUE_DIVIDE 27
#define INPLACE_FLOOR_DIVIDE 28
#define INPLACE_TRUE_DIVIDE 29
#define SLICE 30 #define SLICE 30
/* Also uses 31-33 */ /* Also uses 31-33 */
......
...@@ -12,6 +12,7 @@ extern "C" { ...@@ -12,6 +12,7 @@ extern "C" {
accordingly then. */ accordingly then. */
#define PyCF_NESTED_SCOPES (0x00000001UL) #define PyCF_NESTED_SCOPES (0x00000001UL)
#define PyCF_GENERATORS (0x00000002UL) #define PyCF_GENERATORS (0x00000002UL)
#define PyCF_DIVISION (0x00000004UL)
typedef struct { typedef struct {
unsigned long cf_flags; /* bitmask of PyCF_xxx flags */ unsigned long cf_flags; /* bitmask of PyCF_xxx flags */
} PyCompilerFlags; } PyCompilerFlags;
......
...@@ -55,10 +55,12 @@ extern "C" { ...@@ -55,10 +55,12 @@ extern "C" {
#define LEFTSHIFTEQUAL 45 #define LEFTSHIFTEQUAL 45
#define RIGHTSHIFTEQUAL 46 #define RIGHTSHIFTEQUAL 46
#define DOUBLESTAREQUAL 47 #define DOUBLESTAREQUAL 47
#define DOUBLESLASH 48
#define DOUBLESLASHEQUAL 49
/* Don't forget to update the table _PyParser_TokenNames in tokenizer.c! */ /* Don't forget to update the table _PyParser_TokenNames in tokenizer.c! */
#define OP 48 #define OP 50
#define ERRORTOKEN 49 #define ERRORTOKEN 51
#define N_TOKENS 50 #define N_TOKENS 52
/* Special definitions for cooperation with parser */ /* Special definitions for cooperation with parser */
......
...@@ -68,3 +68,4 @@ class _Feature: ...@@ -68,3 +68,4 @@ class _Feature:
nested_scopes = _Feature((2, 1, 0, "beta", 1), (2, 2, 0, "alpha", 0)) nested_scopes = _Feature((2, 1, 0, "beta", 1), (2, 2, 0, "alpha", 0))
generators = _Feature((2, 2, 0, "alpha", 1), (2, 3, 0, "final", 0)) generators = _Feature((2, 2, 0, "alpha", 1), (2, 3, 0, "final", 0))
division = _Feature((2, 2, 0, "alpha", 2), (3, 0, 0, "alpha", 0))
...@@ -564,6 +564,20 @@ PyNumber_Add(PyObject *v, PyObject *w) ...@@ -564,6 +564,20 @@ PyNumber_Add(PyObject *v, PyObject *w)
return result; return result;
} }
PyObject *
PyNumber_FloorDivide(PyObject *v, PyObject *w)
{
/* XXX tp_flags test */
return binary_op(v, w, NB_SLOT(nb_floor_divide), "//");
}
PyObject *
PyNumber_TrueDivide(PyObject *v, PyObject *w)
{
/* XXX tp_flags test */
return binary_op(v, w, NB_SLOT(nb_true_divide), "/");
}
PyObject * PyObject *
PyNumber_Remainder(PyObject *v, PyObject *w) PyNumber_Remainder(PyObject *v, PyObject *w)
{ {
...@@ -630,6 +644,22 @@ INPLACE_BINOP(PyNumber_InPlaceRshift, nb_inplace_rshift, nb_rshift, ">>=") ...@@ -630,6 +644,22 @@ INPLACE_BINOP(PyNumber_InPlaceRshift, nb_inplace_rshift, nb_rshift, ">>=")
INPLACE_BINOP(PyNumber_InPlaceSubtract, nb_inplace_subtract, nb_subtract, "-=") INPLACE_BINOP(PyNumber_InPlaceSubtract, nb_inplace_subtract, nb_subtract, "-=")
INPLACE_BINOP(PyNumber_InPlaceDivide, nb_inplace_divide, nb_divide, "/=") INPLACE_BINOP(PyNumber_InPlaceDivide, nb_inplace_divide, nb_divide, "/=")
PyObject *
PyNumber_InPlaceFloorDivide(PyObject *v, PyObject *w)
{
/* XXX tp_flags test */
return binary_iop(v, w, NB_SLOT(nb_inplace_floor_divide),
NB_SLOT(nb_floor_divide), "//=");
}
PyObject *
PyNumber_InPlaceTrueDivide(PyObject *v, PyObject *w)
{
/* XXX tp_flags test */
return binary_iop(v, w, NB_SLOT(nb_inplace_true_divide),
NB_SLOT(nb_true_divide), "/=");
}
PyObject * PyObject *
PyNumber_InPlaceAdd(PyObject *v, PyObject *w) PyNumber_InPlaceAdd(PyObject *v, PyObject *w)
{ {
......
...@@ -1435,6 +1435,8 @@ BINARY(instance_mul, "mul", PyNumber_Multiply) ...@@ -1435,6 +1435,8 @@ BINARY(instance_mul, "mul", PyNumber_Multiply)
BINARY(instance_div, "div", PyNumber_Divide) BINARY(instance_div, "div", PyNumber_Divide)
BINARY(instance_mod, "mod", PyNumber_Remainder) BINARY(instance_mod, "mod", PyNumber_Remainder)
BINARY(instance_divmod, "divmod", PyNumber_Divmod) BINARY(instance_divmod, "divmod", PyNumber_Divmod)
BINARY(instance_floordiv, "floordiv", PyNumber_FloorDivide)
BINARY(instance_truediv, "truediv", PyNumber_TrueDivide)
BINARY_INPLACE(instance_ior, "or", PyNumber_InPlaceOr) BINARY_INPLACE(instance_ior, "or", PyNumber_InPlaceOr)
BINARY_INPLACE(instance_ixor, "xor", PyNumber_InPlaceXor) BINARY_INPLACE(instance_ixor, "xor", PyNumber_InPlaceXor)
...@@ -1446,6 +1448,8 @@ BINARY_INPLACE(instance_isub, "sub", PyNumber_InPlaceSubtract) ...@@ -1446,6 +1448,8 @@ BINARY_INPLACE(instance_isub, "sub", PyNumber_InPlaceSubtract)
BINARY_INPLACE(instance_imul, "mul", PyNumber_InPlaceMultiply) BINARY_INPLACE(instance_imul, "mul", PyNumber_InPlaceMultiply)
BINARY_INPLACE(instance_idiv, "div", PyNumber_InPlaceDivide) BINARY_INPLACE(instance_idiv, "div", PyNumber_InPlaceDivide)
BINARY_INPLACE(instance_imod, "mod", PyNumber_InPlaceRemainder) BINARY_INPLACE(instance_imod, "mod", PyNumber_InPlaceRemainder)
BINARY_INPLACE(instance_ifloordiv, "floordiv", PyNumber_InPlaceFloorDivide)
BINARY_INPLACE(instance_itruediv, "truediv", PyNumber_InPlaceTrueDivide)
/* Try a 3-way comparison, returning an int; v is an instance. Return: /* Try a 3-way comparison, returning an int; v is an instance. Return:
-2 for an exception; -2 for an exception;
...@@ -1900,6 +1904,10 @@ static PyNumberMethods instance_as_number = { ...@@ -1900,6 +1904,10 @@ static PyNumberMethods instance_as_number = {
(binaryfunc)instance_iand, /* nb_inplace_and */ (binaryfunc)instance_iand, /* nb_inplace_and */
(binaryfunc)instance_ixor, /* nb_inplace_xor */ (binaryfunc)instance_ixor, /* nb_inplace_xor */
(binaryfunc)instance_ior, /* nb_inplace_or */ (binaryfunc)instance_ior, /* nb_inplace_or */
(binaryfunc)instance_floordiv, /* nb_floor_divide */
(binaryfunc)instance_truediv, /* nb_true_divide */
(binaryfunc)instance_ifloordiv, /* nb_inplace_floor_divide */
(binaryfunc)instance_itruediv, /* nb_inplace_true_divide */
}; };
PyTypeObject PyInstance_Type = { PyTypeObject PyInstance_Type = {
......
...@@ -441,6 +441,21 @@ complex_pow(PyComplexObject *v, PyObject *w, PyComplexObject *z) ...@@ -441,6 +441,21 @@ complex_pow(PyComplexObject *v, PyObject *w, PyComplexObject *z)
return PyComplex_FromCComplex(p); return PyComplex_FromCComplex(p);
} }
static PyObject *
complex_int_div(PyComplexObject *v, PyComplexObject *w)
{
PyObject *t, *r;
t = complex_divmod(v, w);
if (t != NULL) {
r = PyTuple_GET_ITEM(t, 0);
Py_INCREF(r);
Py_DECREF(t);
return r;
}
return NULL;
}
static PyObject * static PyObject *
complex_neg(PyComplexObject *v) complex_neg(PyComplexObject *v)
{ {
...@@ -859,6 +874,21 @@ static PyNumberMethods complex_as_number = { ...@@ -859,6 +874,21 @@ static PyNumberMethods complex_as_number = {
(unaryfunc)complex_float, /* nb_float */ (unaryfunc)complex_float, /* nb_float */
0, /* nb_oct */ 0, /* nb_oct */
0, /* nb_hex */ 0, /* nb_hex */
0, /* nb_inplace_add */
0, /* nb_inplace_subtract */
0, /* nb_inplace_multiply*/
0, /* nb_inplace_divide */
0, /* nb_inplace_remainder */
0, /* nb_inplace_power */
0, /* nb_inplace_lshift */
0, /* nb_inplace_rshift */
0, /* nb_inplace_and */
0, /* nb_inplace_xor */
0, /* nb_inplace_or */
(binaryfunc)complex_int_div, /* nb_floor_divide */
(binaryfunc)complex_div, /* nb_true_divide */
0, /* nb_inplace_floor_divide */
0, /* nb_inplace_true_divide */
}; };
PyTypeObject PyComplex_Type = { PyTypeObject PyComplex_Type = {
......
...@@ -557,6 +557,21 @@ float_pow(PyObject *v, PyObject *w, PyObject *z) ...@@ -557,6 +557,21 @@ float_pow(PyObject *v, PyObject *w, PyObject *z)
return PyFloat_FromDouble(ix); return PyFloat_FromDouble(ix);
} }
static PyObject *
float_int_div(PyObject *v, PyObject *w)
{
PyObject *t, *r;
t = float_divmod(v, w);
if (t != NULL) {
r = PyTuple_GET_ITEM(t, 0);
Py_INCREF(r);
Py_DECREF(t);
return r;
}
return NULL;
}
static PyObject * static PyObject *
float_neg(PyFloatObject *v) float_neg(PyFloatObject *v)
{ {
...@@ -678,19 +693,23 @@ static PyNumberMethods float_as_number = { ...@@ -678,19 +693,23 @@ static PyNumberMethods float_as_number = {
(unaryfunc)float_int, /*nb_int*/ (unaryfunc)float_int, /*nb_int*/
(unaryfunc)float_long, /*nb_long*/ (unaryfunc)float_long, /*nb_long*/
(unaryfunc)float_float, /*nb_float*/ (unaryfunc)float_float, /*nb_float*/
0, /*nb_oct*/ 0, /* nb_oct */
0, /*nb_hex*/ 0, /* nb_hex */
0, /*nb_inplace_add*/ 0, /* nb_inplace_add */
0, /*nb_inplace_subtract*/ 0, /* nb_inplace_subtract */
0, /*nb_inplace_multiply*/ 0, /* nb_inplace_multiply */
0, /*nb_inplace_divide*/ 0, /* nb_inplace_divide */
0, /*nb_inplace_remainder*/ 0, /* nb_inplace_remainder */
0, /*nb_inplace_power*/ 0, /* nb_inplace_power */
0, /*nb_inplace_lshift*/ 0, /* nb_inplace_lshift */
0, /*nb_inplace_rshift*/ 0, /* nb_inplace_rshift */
0, /*nb_inplace_and*/ 0, /* nb_inplace_and */
0, /*nb_inplace_xor*/ 0, /* nb_inplace_xor */
0, /*nb_inplace_or*/ 0, /* nb_inplace_or */
float_int_div, /* nb_floor_divide */
float_div, /* nb_true_divide */
0, /* nb_inplace_floor_divide */
0, /* nb_inplace_true_divide */
}; };
PyTypeObject PyFloat_Type = { PyTypeObject PyFloat_Type = {
......
...@@ -702,6 +702,12 @@ int_or(PyIntObject *v, PyIntObject *w) ...@@ -702,6 +702,12 @@ int_or(PyIntObject *v, PyIntObject *w)
return PyInt_FromLong(a | b); return PyInt_FromLong(a | b);
} }
static PyObject *
int_true_divide(PyObject *v, PyObject *w)
{
return PyFloat_Type.tp_as_number->nb_divide(v, w);
}
static PyObject * static PyObject *
int_int(PyIntObject *v) int_int(PyIntObject *v)
{ {
...@@ -812,6 +818,10 @@ static PyNumberMethods int_as_number = { ...@@ -812,6 +818,10 @@ static PyNumberMethods int_as_number = {
0, /*nb_inplace_and*/ 0, /*nb_inplace_and*/
0, /*nb_inplace_xor*/ 0, /*nb_inplace_xor*/
0, /*nb_inplace_or*/ 0, /*nb_inplace_or*/
(binaryfunc)int_div, /* nb_floor_divide */
int_true_divide, /* nb_true_divide */
0, /* nb_inplace_floor_divide */
0, /* nb_inplace_true_divide */
}; };
PyTypeObject PyInt_Type = { PyTypeObject PyInt_Type = {
......
...@@ -1981,6 +1981,12 @@ long_or(PyObject *v, PyObject *w) ...@@ -1981,6 +1981,12 @@ long_or(PyObject *v, PyObject *w)
return c; return c;
} }
static PyObject *
long_true_divide(PyObject *v, PyObject *w)
{
return PyFloat_Type.tp_as_number->nb_divide(v, w);
}
static int static int
long_coerce(PyObject **pv, PyObject **pw) long_coerce(PyObject **pv, PyObject **pw)
{ {
...@@ -2092,17 +2098,21 @@ static PyNumberMethods long_as_number = { ...@@ -2092,17 +2098,21 @@ static PyNumberMethods long_as_number = {
(unaryfunc) long_float, /*nb_float*/ (unaryfunc) long_float, /*nb_float*/
(unaryfunc) long_oct, /*nb_oct*/ (unaryfunc) long_oct, /*nb_oct*/
(unaryfunc) long_hex, /*nb_hex*/ (unaryfunc) long_hex, /*nb_hex*/
0, /*nb_inplace_add*/ 0, /* nb_inplace_add */
0, /*nb_inplace_subtract*/ 0, /* nb_inplace_subtract */
0, /*nb_inplace_multiply*/ 0, /* nb_inplace_multiply */
0, /*nb_inplace_divide*/ 0, /* nb_inplace_divide */
0, /*nb_inplace_remainder*/ 0, /* nb_inplace_remainder */
0, /*nb_inplace_power*/ 0, /* nb_inplace_power */
0, /*nb_inplace_lshift*/ 0, /* nb_inplace_lshift */
0, /*nb_inplace_rshift*/ 0, /* nb_inplace_rshift */
0, /*nb_inplace_and*/ 0, /* nb_inplace_and */
0, /*nb_inplace_xor*/ 0, /* nb_inplace_xor */
0, /*nb_inplace_or*/ 0, /* nb_inplace_or */
(binaryfunc)long_div, /* nb_floor_divide */
long_true_divide, /* nb_true_divide */
0, /* nb_inplace_floor_divide */
0, /* nb_inplace_true_divide */
}; };
PyTypeObject PyLong_Type = { PyTypeObject PyLong_Type = {
......
...@@ -80,6 +80,8 @@ char *_PyParser_TokenNames[] = { ...@@ -80,6 +80,8 @@ char *_PyParser_TokenNames[] = {
"LEFTSHIFTEQUAL", "LEFTSHIFTEQUAL",
"RIGHTSHIFTEQUAL", "RIGHTSHIFTEQUAL",
"DOUBLESTAREQUAL", "DOUBLESTAREQUAL",
"DOUBLESLASH",
"DOUBLESLASHEQUAL",
/* This table must match the #defines in token.h! */ /* This table must match the #defines in token.h! */
"OP", "OP",
"<ERRORTOKEN>", "<ERRORTOKEN>",
...@@ -408,6 +410,7 @@ PyToken_TwoChars(int c1, int c2) ...@@ -408,6 +410,7 @@ PyToken_TwoChars(int c1, int c2)
break; break;
case '/': case '/':
switch (c2) { switch (c2) {
case '/': return DOUBLESLASH;
case '=': return SLASHEQUAL; case '=': return SLASHEQUAL;
} }
break; break;
...@@ -469,6 +472,16 @@ PyToken_ThreeChars(int c1, int c2, int c3) ...@@ -469,6 +472,16 @@ PyToken_ThreeChars(int c1, int c2, int c3)
break; break;
} }
break; break;
case '/':
switch (c2) {
case '/':
switch (c3) {
case '=':
return DOUBLESLASHEQUAL;
}
break;
}
break;
} }
return OP; return OP;
} }
......
...@@ -884,6 +884,26 @@ eval_frame(PyFrameObject *f) ...@@ -884,6 +884,26 @@ eval_frame(PyFrameObject *f)
if (x != NULL) continue; if (x != NULL) continue;
break; break;
case BINARY_FLOOR_DIVIDE:
w = POP();
v = POP();
x = PyNumber_FloorDivide(v, w);
Py_DECREF(v);
Py_DECREF(w);
PUSH(x);
if (x != NULL) continue;
break;
case BINARY_TRUE_DIVIDE:
w = POP();
v = POP();
x = PyNumber_TrueDivide(v, w);
Py_DECREF(v);
Py_DECREF(w);
PUSH(x);
if (x != NULL) continue;
break;
case BINARY_MODULO: case BINARY_MODULO:
w = POP(); w = POP();
v = POP(); v = POP();
...@@ -1051,6 +1071,26 @@ eval_frame(PyFrameObject *f) ...@@ -1051,6 +1071,26 @@ eval_frame(PyFrameObject *f)
if (x != NULL) continue; if (x != NULL) continue;
break; break;
case INPLACE_FLOOR_DIVIDE:
w = POP();
v = POP();
x = PyNumber_InPlaceFloorDivide(v, w);
Py_DECREF(v);
Py_DECREF(w);
PUSH(x);
if (x != NULL) continue;
break;
case INPLACE_TRUE_DIVIDE:
w = POP();
v = POP();
x = PyNumber_InPlaceTrueDivide(v, w);
Py_DECREF(v);
Py_DECREF(w);
PUSH(x);
if (x != NULL) continue;
break;
case INPLACE_MODULO: case INPLACE_MODULO:
w = POP(); w = POP();
v = POP(); v = POP();
......
...@@ -1874,14 +1874,20 @@ com_term(struct compiling *c, node *n) ...@@ -1874,14 +1874,20 @@ com_term(struct compiling *c, node *n)
op = BINARY_MULTIPLY; op = BINARY_MULTIPLY;
break; break;
case SLASH: case SLASH:
if (c->c_flags & CO_FUTURE_DIVISION)
op = BINARY_TRUE_DIVIDE;
else
op = BINARY_DIVIDE; op = BINARY_DIVIDE;
break; break;
case PERCENT: case PERCENT:
op = BINARY_MODULO; op = BINARY_MODULO;
break; break;
case DOUBLESLASH:
op = BINARY_FLOOR_DIVIDE;
break;
default: default:
com_error(c, PyExc_SystemError, com_error(c, PyExc_SystemError,
"com_term: operator not *, / or %"); "com_term: operator not *, /, // or %");
op = 255; op = 255;
} }
com_addbyte(c, op); com_addbyte(c, op);
...@@ -2475,7 +2481,14 @@ com_augassign(struct compiling *c, node *n) ...@@ -2475,7 +2481,14 @@ com_augassign(struct compiling *c, node *n)
switch (STR(CHILD(CHILD(n, 1), 0))[0]) { switch (STR(CHILD(CHILD(n, 1), 0))[0]) {
case '+': opcode = INPLACE_ADD; break; case '+': opcode = INPLACE_ADD; break;
case '-': opcode = INPLACE_SUBTRACT; break; case '-': opcode = INPLACE_SUBTRACT; break;
case '/': opcode = INPLACE_DIVIDE; break; case '/':
if (STR(CHILD(CHILD(n, 1), 0))[1] == '/')
opcode = INPLACE_FLOOR_DIVIDE;
else if (c->c_flags & CO_FUTURE_DIVISION)
opcode = INPLACE_TRUE_DIVIDE;
else
opcode = INPLACE_DIVIDE;
break;
case '%': opcode = INPLACE_MODULO; break; case '%': opcode = INPLACE_MODULO; break;
case '<': opcode = INPLACE_LSHIFT; break; case '<': opcode = INPLACE_LSHIFT; break;
case '>': opcode = INPLACE_RSHIFT; break; case '>': opcode = INPLACE_RSHIFT; break;
...@@ -3945,7 +3958,8 @@ jcompile(node *n, char *filename, struct compiling *base, ...@@ -3945,7 +3958,8 @@ jcompile(node *n, char *filename, struct compiling *base,
if (base->c_nested if (base->c_nested
|| (sc.c_symtable->st_cur->ste_type == TYPE_FUNCTION)) || (sc.c_symtable->st_cur->ste_type == TYPE_FUNCTION))
sc.c_nested = 1; sc.c_nested = 1;
sc.c_flags |= base->c_flags & CO_GENERATOR_ALLOWED; sc.c_flags |= base->c_flags & (CO_GENERATOR_ALLOWED |
CO_FUTURE_DIVISION);
} else { } else {
sc.c_private = NULL; sc.c_private = NULL;
sc.c_future = PyNode_Future(n, filename); sc.c_future = PyNode_Future(n, filename);
...@@ -3963,6 +3977,11 @@ jcompile(node *n, char *filename, struct compiling *base, ...@@ -3963,6 +3977,11 @@ jcompile(node *n, char *filename, struct compiling *base,
sc.c_future->ff_generators = 1; sc.c_future->ff_generators = 1;
else if (sc.c_future->ff_generators) else if (sc.c_future->ff_generators)
flags->cf_flags |= PyCF_GENERATORS; flags->cf_flags |= PyCF_GENERATORS;
if (flags->cf_flags & PyCF_DIVISION)
sc.c_future->ff_division = 1;
else if (sc.c_future->ff_division)
flags->cf_flags |= PyCF_DIVISION;
} }
if (symtable_build(&sc, n) < 0) { if (symtable_build(&sc, n) < 0) {
com_free(&sc); com_free(&sc);
...@@ -4437,6 +4456,8 @@ symtable_update_flags(struct compiling *c, PySymtableEntryObject *ste, ...@@ -4437,6 +4456,8 @@ symtable_update_flags(struct compiling *c, PySymtableEntryObject *ste,
c->c_flags |= CO_NESTED; c->c_flags |= CO_NESTED;
if (c->c_future->ff_generators) if (c->c_future->ff_generators)
c->c_flags |= CO_GENERATOR_ALLOWED; c->c_flags |= CO_GENERATOR_ALLOWED;
if (c->c_future->ff_division)
c->c_flags |= CO_FUTURE_DIVISION;
} }
if (ste->ste_generator) if (ste->ste_generator)
c->c_flags |= CO_GENERATOR; c->c_flags |= CO_GENERATOR;
......
...@@ -33,6 +33,8 @@ future_check_features(PyFutureFeatures *ff, node *n, char *filename) ...@@ -33,6 +33,8 @@ future_check_features(PyFutureFeatures *ff, node *n, char *filename)
ff->ff_nested_scopes = 1; ff->ff_nested_scopes = 1;
} else if (strcmp(feature, FUTURE_GENERATORS) == 0) { } else if (strcmp(feature, FUTURE_GENERATORS) == 0) {
ff->ff_generators = 1; ff->ff_generators = 1;
} else if (strcmp(feature, FUTURE_DIVISION) == 0) {
ff->ff_division = 1;
} else if (strcmp(feature, "braces") == 0) { } else if (strcmp(feature, "braces") == 0) {
PyErr_SetString(PyExc_SyntaxError, PyErr_SetString(PyExc_SyntaxError,
"not a chance"); "not a chance");
...@@ -234,6 +236,7 @@ PyNode_Future(node *n, char *filename) ...@@ -234,6 +236,7 @@ PyNode_Future(node *n, char *filename)
ff->ff_last_lineno = -1; ff->ff_last_lineno = -1;
ff->ff_nested_scopes = 0; ff->ff_nested_scopes = 0;
ff->ff_generators = 0; ff->ff_generators = 0;
ff->ff_division = 0;
if (future_parse(ff, n, filename) < 0) { if (future_parse(ff, n, filename) < 0) {
PyMem_Free((void *)ff); PyMem_Free((void *)ff);
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment