From eb84a830df62813f5af7f0144fc77444bf18f3a8 Mon Sep 17 00:00:00 2001 From: Paul Sokolovsky Date: Sun, 10 Sep 2017 17:05:20 +0300 Subject: [PATCH] py/runtime: Implement dispatch for "reverse op" special methods. If, for class X, X.__add__(Y) doesn't exist (or returns NotImplemented), try Y.__radd__(X) instead. This patch could be simpler, but requires undoing operand swap and operation switch to get non-confusing error message in case __radd__ doesn't exist. --- ports/unix/mpconfigport_coverage.h | 1 + py/mpconfig.h | 10 +++++++++- py/objtype.c | 7 +++++++ py/runtime.c | 15 ++++++++++++++- py/runtime0.h | 17 +++++++++++++++++ 5 files changed, 48 insertions(+), 2 deletions(-) diff --git a/ports/unix/mpconfigport_coverage.h b/ports/unix/mpconfigport_coverage.h index a9e0a38fa..367b4853a 100644 --- a/ports/unix/mpconfigport_coverage.h +++ b/ports/unix/mpconfigport_coverage.h @@ -35,6 +35,7 @@ #define MICROPY_FLOAT_HIGH_QUALITY_HASH (1) #define MICROPY_ENABLE_SCHEDULER (1) #define MICROPY_PY_DELATTR_SETATTR (1) +#define MICROPY_PY_REVERSE_SPECIAL_METHODS (1) #define MICROPY_PY_BUILTINS_HELP (1) #define MICROPY_PY_BUILTINS_HELP_MODULES (1) #define MICROPY_PY_SYS_GETSIZEOF (1) diff --git a/py/mpconfig.h b/py/mpconfig.h index 38cf4b560..63438a846 100644 --- a/py/mpconfig.h +++ b/py/mpconfig.h @@ -759,11 +759,19 @@ typedef double mp_float_t; #endif // Whether to support complete set of special methods -// for user classes, otherwise only the most used +// for user classes, or only the most used ones. "Reverse" +// methods are controlled by MICROPY_PY_REVERSE_SPECIAL_METHODS +// below. #ifndef MICROPY_PY_ALL_SPECIAL_METHODS #define MICROPY_PY_ALL_SPECIAL_METHODS (0) #endif +// Whether to support reverse arithmetic operarions methods +// (__radd__, etc.) +#ifndef MICROPY_PY_REVERSE_SPECIAL_METHODS +#define MICROPY_PY_REVERSE_SPECIAL_METHODS (0) +#endif + // Whether to support compile function #ifndef MICROPY_PY_BUILTINS_COMPILE #define MICROPY_PY_BUILTINS_COMPILE (0) diff --git a/py/objtype.c b/py/objtype.c index 8ce593dba..cf9311d5c 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -441,6 +441,13 @@ const qstr mp_binary_op_method_name[] = { MP_BINARY_OP_INPLACE_TRUE_DIVIDE, MP_BINARY_OP_INPLACE_MODULO, MP_BINARY_OP_INPLACE_POWER,*/ + + #if MICROPY_PY_REVERSE_SPECIAL_METHODS + [MP_BINARY_OP_REVERSE_ADD] = MP_QSTR___radd__, + [MP_BINARY_OP_REVERSE_SUBTRACT] = MP_QSTR___rsub__, + [MP_BINARY_OP_REVERSE_MULTIPLY] = MP_QSTR___rmul__, + #endif + [MP_BINARY_OP_LESS] = MP_QSTR___lt__, [MP_BINARY_OP_MORE] = MP_QSTR___gt__, [MP_BINARY_OP_EQUAL] = MP_QSTR___eq__, diff --git a/py/runtime.c b/py/runtime.c index 21ef42577..c533558da 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -555,7 +555,20 @@ generic_binary_op: } } - // TODO implement dispatch for reverse binary ops +#if MICROPY_PY_REVERSE_SPECIAL_METHODS + if (op >= MP_BINARY_OP_OR && op <= MP_BINARY_OP_REVERSE_POWER) { + mp_obj_t t = rhs; + rhs = lhs; + lhs = t; + if (op <= MP_BINARY_OP_POWER) { + op += MP_BINARY_OP_REVERSE_OR - MP_BINARY_OP_OR; + goto generic_binary_op; + } + + // Convert __rop__ back to __op__ for error message + op -= MP_BINARY_OP_REVERSE_OR - MP_BINARY_OP_OR; + } +#endif unsupported_op: if (MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_TERSE) { diff --git a/py/runtime0.h b/py/runtime0.h index 3cf5e530d..a3e9d46b9 100644 --- a/py/runtime0.h +++ b/py/runtime0.h @@ -101,6 +101,23 @@ typedef enum { // Operations below this line don't appear in bytecode, they // just identify special methods. + // MP_BINARY_OP_REVERSE_* must follow immediately after MP_BINARY_OP_* +#if MICROPY_PY_REVERSE_SPECIAL_METHODS + MP_BINARY_OP_REVERSE_OR, + MP_BINARY_OP_REVERSE_XOR, + MP_BINARY_OP_REVERSE_AND, + MP_BINARY_OP_REVERSE_LSHIFT, + MP_BINARY_OP_REVERSE_RSHIFT, + MP_BINARY_OP_REVERSE_ADD, + + MP_BINARY_OP_REVERSE_SUBTRACT, + MP_BINARY_OP_REVERSE_MULTIPLY, + MP_BINARY_OP_REVERSE_FLOOR_DIVIDE, + MP_BINARY_OP_REVERSE_TRUE_DIVIDE, + MP_BINARY_OP_REVERSE_MODULO, + MP_BINARY_OP_REVERSE_POWER, +#endif + MP_BINARY_OP_DIVMOD, // not emitted by the compiler but supported by the runtime MP_BINARY_OP_LAST,