[Python-checkins] cpython: PEP 465: a dedicated infix operator for matrix multiplication (closes #21176)

benjamin.peterson python-checkins at python.org
Thu Apr 10 05:56:07 CEST 2014


http://hg.python.org/cpython/rev/c553d8f72d65
changeset: 90206:c553d8f72d65
user: Benjamin Peterson <benjamin at python.org>
date: Wed Apr 09 23:55:56 2014 -0400
summary:
 PEP 465: a dedicated infix operator for matrix multiplication (closes #21176)
files:
 Doc/c-api/number.rst | 17 +
 Doc/c-api/typeobj.rst | 3 +
 Doc/library/dis.rst | 10 +
 Doc/library/operator.rst | 18 +
 Doc/library/token.rst | 1 +
 Doc/reference/datamodel.rst | 60 +-
 Doc/reference/expressions.rst | 17 +-
 Doc/reference/simple_stmts.rst | 2 +-
 Grammar/Grammar | 4 +-
 Include/Python-ast.h | 6 +-
 Include/abstract.h | 12 +
 Include/object.h | 3 +
 Include/opcode.h | 3 +
 Include/token.h | 13 +-
 Include/typeslots.h | 2 +
 Lib/importlib/_bootstrap.py | 3 +-
 Lib/opcode.py | 3 +
 Lib/operator.py | 11 +
 Lib/test/test_augassign.py | 15 +
 Lib/test/test_capi.py | 17 +
 Lib/test/test_descr.py | 1 +
 Lib/test/test_grammar.py | 14 +
 Lib/test/test_operator.py | 11 +
 Lib/test/test_sys.py | 2 +-
 Lib/test/test_tokenize.py | 5 +-
 Lib/token.py | 11 +-
 Lib/tokenize.py | 5 +-
 Misc/NEWS | 2 +
 Modules/_operator.c | 4 +
 Modules/_testcapimodule.c | 107 +++++
 Objects/abstract.c | 14 +
 Objects/typeobject.c | 10 +
 Objects/typeslots.inc | 2 +
 Parser/Python.asdl | 2 +-
 Parser/tokenizer.c | 8 +-
 Python/Python-ast.c | 24 +-
 Python/ast.c | 8 +-
 Python/ceval.c | 24 +
 Python/compile.c | 6 +
 Python/graminit.c | 435 ++++++++++----------
 Python/importlib.h | 320 +++++++-------
 Python/opcode_targets.h | 4 +-
 42 files changed, 800 insertions(+), 439 deletions(-)
diff --git a/Doc/c-api/number.rst b/Doc/c-api/number.rst
--- a/Doc/c-api/number.rst
+++ b/Doc/c-api/number.rst
@@ -30,6 +30,14 @@
 the equivalent of the Python expression ``o1 * o2``.
 
 
+.. c:function:: PyObject* PyNumber_MatrixMultiply(PyObject *o1, PyObject *o2)
+
+ Returns the result of matrix multiplication on *o1* and *o2*, or *NULL* on
+ failure. This is the equivalent of the Python expression ``o1 @ o2``.
+
+ .. versionadded:: 3.5
+
+
 .. c:function:: PyObject* PyNumber_FloorDivide(PyObject *o1, PyObject *o2)
 
 Return the floor of *o1* divided by *o2*, or *NULL* on failure. This is
@@ -146,6 +154,15 @@
 the Python statement ``o1 *= o2``.
 
 
+.. c:function:: PyObject* PyNumber_InPlaceMatrixMultiply(PyObject *o1, PyObject *o2)
+
+ Returns the result of matrix multiplication on *o1* and *o2*, or *NULL* on
+ failure. The operation is done *in-place* when *o1* supports it. This is
+ the equivalent of the Python statement ``o1 @= o2``.
+
+ .. versionadded:: 3.5
+
+
 .. c:function:: PyObject* PyNumber_InPlaceFloorDivide(PyObject *o1, PyObject *o2)
 
 Returns the mathematical floor of dividing *o1* by *o2*, or *NULL* on failure.
diff --git a/Doc/c-api/typeobj.rst b/Doc/c-api/typeobj.rst
--- a/Doc/c-api/typeobj.rst
+++ b/Doc/c-api/typeobj.rst
@@ -1121,6 +1121,9 @@
 binaryfunc nb_inplace_true_divide;
 
 unaryfunc nb_index;
+
+ binaryfunc nb_matrix_multiply;
+ binaryfunc nb_inplace_matrix_multiply;
 } PyNumberMethods;
 
 .. note::
diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst
--- a/Doc/library/dis.rst
+++ b/Doc/library/dis.rst
@@ -364,6 +364,11 @@
 Implements ``TOS = TOS1 * TOS``.
 
 
+.. opcode:: BINARY_MATRIX_MULTIPLY
+
+ Implements ``TOS = TOS1 @ TOS``.
+
+
 .. opcode:: BINARY_FLOOR_DIVIDE
 
 Implements ``TOS = TOS1 // TOS``.
@@ -436,6 +441,11 @@
 Implements in-place ``TOS = TOS1 * TOS``.
 
 
+.. opcode:: INPLACE_MATRIX_MULTIPLY
+
+ Implements in-place ``TOS = TOS1 @ TOS``.
+
+
 .. opcode:: INPLACE_FLOOR_DIVIDE
 
 Implements in-place ``TOS = TOS1 // TOS``.
diff --git a/Doc/library/operator.rst b/Doc/library/operator.rst
--- a/Doc/library/operator.rst
+++ b/Doc/library/operator.rst
@@ -138,6 +138,14 @@
 Return ``a * b``, for *a* and *b* numbers.
 
 
+.. function:: matmul(a, b)
+ __matmul__(a, b)
+
+ Return ``a @ b``.
+
+ .. versionadded:: 3.5
+
+
 .. function:: neg(obj)
 __neg__(obj)
 
@@ -400,6 +408,8 @@
 +-----------------------+-------------------------+---------------------------------------+
 | Multiplication | ``a * b`` | ``mul(a, b)`` |
 +-----------------------+-------------------------+---------------------------------------+
+| Matrix Multiplication | ``a @ b`` | ``matmul(a, b)`` |
++-----------------------+-------------------------+---------------------------------------+
 | Negation (Arithmetic) | ``- a`` | ``neg(a)`` |
 +-----------------------+-------------------------+---------------------------------------+
 | Negation (Logical) | ``not a`` | ``not_(a)`` |
@@ -508,6 +518,14 @@
 ``a = imul(a, b)`` is equivalent to ``a *= b``.
 
 
+.. function:: imatmul(a, b)
+ __imatmul__(a, b)
+
+ ``a = imatmul(a, b)`` is equivalent to ``a @= b``.
+
+ .. versionadded:: 3.5
+
+
 .. function:: ior(a, b)
 __ior__(a, b)
 
diff --git a/Doc/library/token.rst b/Doc/library/token.rst
--- a/Doc/library/token.rst
+++ b/Doc/library/token.rst
@@ -93,6 +93,7 @@
 DOUBLESLASH
 DOUBLESLASHEQUAL
 AT
+ ATEQUAL
 RARROW
 ELLIPSIS
 OP
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
--- a/Doc/reference/datamodel.rst
+++ b/Doc/reference/datamodel.rst
@@ -1970,6 +1970,7 @@
 .. method:: object.__add__(self, other)
 object.__sub__(self, other)
 object.__mul__(self, other)
+ object.__matmul__(self, other)
 object.__truediv__(self, other)
 object.__floordiv__(self, other)
 object.__mod__(self, other)
@@ -1986,15 +1987,16 @@
 builtin: pow
 builtin: pow
 
- These methods are called to implement the binary arithmetic operations (``+``,
- ``-``, ``*``, ``/``, ``//``, ``%``, :func:`divmod`, :func:`pow`, ``**``, ``<<``,
- ``>>``, ``&``, ``^``, ``|``). For instance, to evaluate the expression
- ``x + y``, where *x* is an instance of a class that has an :meth:`__add__`
- method, ``x.__add__(y)`` is called. The :meth:`__divmod__` method should be the
- equivalent to using :meth:`__floordiv__` and :meth:`__mod__`; it should not be
- related to :meth:`__truediv__`. Note that :meth:`__pow__` should be defined
- to accept an optional third argument if the ternary version of the built-in
- :func:`pow` function is to be supported.
+ These methods are called to implement the binary arithmetic operations
+ (``+``, ``-``, ``*``, ``@``, ``/``, ``//``, ``%``, :func:`divmod`,
+ :func:`pow`, ``**``, ``<<``, ``>>``, ``&``, ``^``, ``|``). For instance, to
+ evaluate the expression ``x + y``, where *x* is an instance of a class that
+ has an :meth:`__add__` method, ``x.__add__(y)`` is called. The
+ :meth:`__divmod__` method should be the equivalent to using
+ :meth:`__floordiv__` and :meth:`__mod__`; it should not be related to
+ :meth:`__truediv__`. Note that :meth:`__pow__` should be defined to accept
+ an optional third argument if the ternary version of the built-in :func:`pow`
+ function is to be supported.
 
 If one of those methods does not support the operation with the supplied
 arguments, it should return ``NotImplemented``.
@@ -2003,6 +2005,7 @@
 .. method:: object.__radd__(self, other)
 object.__rsub__(self, other)
 object.__rmul__(self, other)
+ object.__rmatmul__(self, other)
 object.__rtruediv__(self, other)
 object.__rfloordiv__(self, other)
 object.__rmod__(self, other)
@@ -2018,14 +2021,14 @@
 builtin: divmod
 builtin: pow
 
- These methods are called to implement the binary arithmetic operations (``+``,
- ``-``, ``*``, ``/``, ``//``, ``%``, :func:`divmod`, :func:`pow`, ``**``,
- ``<<``, ``>>``, ``&``, ``^``, ``|``) with reflected (swapped) operands.
- These functions are only called if the left operand does not support the
- corresponding operation and the operands are of different types. [#]_ For
- instance, to evaluate the expression ``x - y``, where *y* is an instance of
- a class that has an :meth:`__rsub__` method, ``y.__rsub__(x)`` is called if
- ``x.__sub__(y)`` returns *NotImplemented*.
+ These methods are called to implement the binary arithmetic operations
+ (``+``, ``-``, ``*``, ``@``, ``/``, ``//``, ``%``, :func:`divmod`,
+ :func:`pow`, ``**``, ``<<``, ``>>``, ``&``, ``^``, ``|``) with reflected
+ (swapped) operands. These functions are only called if the left operand does
+ not support the corresponding operation and the operands are of different
+ types. [#]_ For instance, to evaluate the expression ``x - y``, where *y* is
+ an instance of a class that has an :meth:`__rsub__` method, ``y.__rsub__(x)``
+ is called if ``x.__sub__(y)`` returns *NotImplemented*.
 
 .. index:: builtin: pow
 
@@ -2043,6 +2046,7 @@
 .. method:: object.__iadd__(self, other)
 object.__isub__(self, other)
 object.__imul__(self, other)
+ object.__imatmul__(self, other)
 object.__itruediv__(self, other)
 object.__ifloordiv__(self, other)
 object.__imod__(self, other)
@@ -2054,17 +2058,17 @@
 object.__ior__(self, other)
 
 These methods are called to implement the augmented arithmetic assignments
- (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``, ``**=``, ``<<=``, ``>>=``,
- ``&=``, ``^=``, ``|=``). These methods should attempt to do the operation
- in-place (modifying *self*) and return the result (which could be, but does
- not have to be, *self*). If a specific method is not defined, the augmented
- assignment falls back to the normal methods. For instance, if *x* is an
- instance of a class with an :meth:`__iadd__` method, ``x += y`` is equivalent
- to ``x = x.__iadd__(y)`` . Otherwise, ``x.__add__(y)`` and ``y.__radd__(x)``
- are considered, as with the evaluation of ``x + y``. In certain situations,
- augmented assignment can result in unexpected errors (see
- :ref:`faq-augmented-assignment-tuple-error`), but this behavior is in
- fact part of the data model.
+ (``+=``, ``-=``, ``*=``, ``@=``, ``/=``, ``//=``, ``%=``, ``**=``, ``<<=``,
+ ``>>=``, ``&=``, ``^=``, ``|=``). These methods should attempt to do the
+ operation in-place (modifying *self*) and return the result (which could be,
+ but does not have to be, *self*). If a specific method is not defined, the
+ augmented assignment falls back to the normal methods. For instance, if *x*
+ is an instance of a class with an :meth:`__iadd__` method, ``x += y`` is
+ equivalent to ``x = x.__iadd__(y)`` . Otherwise, ``x.__add__(y)`` and
+ ``y.__radd__(x)`` are considered, as with the evaluation of ``x + y``. In
+ certain situations, augmented assignment can result in unexpected errors (see
+ :ref:`faq-augmented-assignment-tuple-error`), but this behavior is in fact
+ part of the data model.
 
 
 .. method:: object.__neg__(self)
diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst
--- a/Doc/reference/expressions.rst
+++ b/Doc/reference/expressions.rst
@@ -892,8 +892,9 @@
 operators and one for additive operators:
 
 .. productionlist::
- m_expr: `u_expr` | `m_expr` "*" `u_expr` | `m_expr` "//" `u_expr` | `m_expr` "/" `u_expr`
- : | `m_expr` "%" `u_expr`
+ m_expr: `u_expr` | `m_expr` "*" `u_expr` | `m_expr` "@" `m_expr` |
+ : `m_expr` "//" `u_expr`| `m_expr` "/" `u_expr` |
+ : `m_expr` "%" `u_expr`
 a_expr: `m_expr` | `a_expr` "+" `m_expr` | `a_expr` "-" `m_expr`
 
 .. index:: single: multiplication
@@ -904,6 +905,13 @@
 common type and then multiplied together. In the latter case, sequence
 repetition is performed; a negative repetition factor yields an empty sequence.
 
+.. index:: single: matrix multiplication
+
+The ``@`` (at) operator is intended to be used for matrix multiplication. No
+builtin Python types implement this operator.
+
+.. versionadded:: 3.5
+
 .. index::
 exception: ZeroDivisionError
 single: division
@@ -1346,8 +1354,9 @@
 +-----------------------------------------------+-------------------------------------+
 | ``+``, ``-`` | Addition and subtraction |
 +-----------------------------------------------+-------------------------------------+
-| ``*``, ``/``, ``//``, ``%`` | Multiplication, division, remainder |
-| | [#]_ |
+| ``*``, ``@``, ``/``, ``//``, ``%`` | Multiplication, matrix |
+| | multiplication division, |
+| | remainder [#]_ |
 +-----------------------------------------------+-------------------------------------+
 | ``+x``, ``-x``, ``~x`` | Positive, negative, bitwise NOT |
 +-----------------------------------------------+-------------------------------------+
diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst
--- a/Doc/reference/simple_stmts.rst
+++ b/Doc/reference/simple_stmts.rst
@@ -267,7 +267,7 @@
 .. productionlist::
 augmented_assignment_stmt: `augtarget` `augop` (`expression_list` | `yield_expression`)
 augtarget: `identifier` | `attributeref` | `subscription` | `slicing`
- augop: "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="
+ augop: "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**="
 : | ">>=" | "<<=" | "&=" | "^=" | "|="
 
 (See section :ref:`primaries` for the syntax definitions for the last three
diff --git a/Grammar/Grammar b/Grammar/Grammar
--- a/Grammar/Grammar
+++ b/Grammar/Grammar
@@ -40,7 +40,7 @@
 expr_stmt: testlist_star_expr (augassign (yield_expr|testlist) |
 ('=' (yield_expr|testlist_star_expr))*)
 testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [',']
-augassign: ('+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' |
+augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' |
 '<<=' | '>>=' | '**=' | '//=')
 # For normal assignments, additional restrictions enforced by the interpreter
 del_stmt: 'del' exprlist
@@ -97,7 +97,7 @@
 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/Include/Python-ast.h b/Include/Python-ast.h
--- a/Include/Python-ast.h
+++ b/Include/Python-ast.h
@@ -15,9 +15,9 @@
 
 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;
+typedef enum _operator { Add=1, Sub=2, Mult=3, MatMult=4, Div=5, Mod=6, Pow=7,
+ LShift=8, RShift=9, BitOr=10, BitXor=11, BitAnd=12,
+ FloorDiv=13 } operator_ty;
 
 typedef enum _unaryop { Invert=1, Not=2, UAdd=3, USub=4 } unaryop_ty;
 
diff --git a/Include/abstract.h b/Include/abstract.h
--- a/Include/abstract.h
+++ b/Include/abstract.h
@@ -658,6 +658,12 @@
 o1*o2.
 */
 
+ PyAPI_FUNC(PyObject *) PyNumber_MatrixMultiply(PyObject *o1, PyObject *o2);
+
+ /*
+ This is the equivalent of the Python expression: o1 @ o2.
+ */
+
 PyAPI_FUNC(PyObject *) PyNumber_FloorDivide(PyObject *o1, PyObject *o2);
 
 /*
@@ -832,6 +838,12 @@
 o1 *= o2.
 */
 
+ PyAPI_FUNC(PyObject *) PyNumber_InPlaceMatrixMultiply(PyObject *o1, PyObject *o2);
+
+ /*
+ This is the equivalent of the Python expression: o1 @= o2.
+ */
+
 PyAPI_FUNC(PyObject *) PyNumber_InPlaceFloorDivide(PyObject *o1,
 PyObject *o2);
 
diff --git a/Include/object.h b/Include/object.h
--- a/Include/object.h
+++ b/Include/object.h
@@ -275,6 +275,9 @@
 binaryfunc nb_inplace_true_divide;
 
 unaryfunc nb_index;
+
+ binaryfunc nb_matrix_multiply;
+ binaryfunc nb_inplace_matrix_multiply;
 } PyNumberMethods;
 
 typedef struct {
diff --git a/Include/opcode.h b/Include/opcode.h
--- a/Include/opcode.h
+++ b/Include/opcode.h
@@ -20,6 +20,9 @@
 
 #define UNARY_INVERT 15
 
+#define BINARY_MATRIX_MULTIPLY 16
+#define INPLACE_MATRIX_MULTIPLY 17
+
 #define BINARY_POWER 19
 
 #define BINARY_MULTIPLY 20
diff --git a/Include/token.h b/Include/token.h
--- a/Include/token.h
+++ b/Include/token.h
@@ -58,13 +58,14 @@
 #define DOUBLESTAREQUAL	46
 #define DOUBLESLASH	47
 #define DOUBLESLASHEQUAL 48
-#define AT 49	
-#define RARROW 50
-#define ELLIPSIS 51
+#define AT 49
+#define ATEQUAL		50
+#define RARROW 51
+#define ELLIPSIS 52
 /* Don't forget to update the table _PyParser_TokenNames in tokenizer.c! */
-#define OP		52
-#define ERRORTOKEN	53
-#define N_TOKENS	54
+#define OP		53
+#define ERRORTOKEN	54
+#define N_TOKENS	55
 
 /* Special definitions for cooperation with parser */
 
diff --git a/Include/typeslots.h b/Include/typeslots.h
--- a/Include/typeslots.h
+++ b/Include/typeslots.h
@@ -74,3 +74,5 @@
 #define Py_tp_members 72
 #define Py_tp_getset 73
 #define Py_tp_free 74
+#define Py_nb_matrix_multiply 75
+#define Py_nb_inplace_matrix_multiply 76
diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -419,12 +419,13 @@
 # Python 3.4a4 3290 (changes to __qualname__ computation)
 # Python 3.4a4 3300 (more changes to __qualname__ computation)
 # Python 3.4rc2 3310 (alter __qualname__ computation)
+# Python 3.5a0 3320 (matrix multiplication operator)
 #
 # MAGIC must change whenever the bytecode emitted by the compiler may no
 # longer be understood by older implementations of the eval loop (usually
 # due to the addition of new opcodes).
 
-MAGIC_NUMBER = (3310).to_bytes(2, 'little') + b'\r\n'
+MAGIC_NUMBER = (3320).to_bytes(2, 'little') + b'\r\n'
 _RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
 
 _PYCACHE = '__pycache__'
diff --git a/Lib/opcode.py b/Lib/opcode.py
--- a/Lib/opcode.py
+++ b/Lib/opcode.py
@@ -70,6 +70,9 @@
 
 def_op('UNARY_INVERT', 15)
 
+def_op('BINARY_MATRIX_MULTIPLY', 16)
+def_op('INPLACE_MATRIX_MULTIPLY', 17)
+
 def_op('BINARY_POWER', 19)
 def_op('BINARY_MULTIPLY', 20)
 
diff --git a/Lib/operator.py b/Lib/operator.py
--- a/Lib/operator.py
+++ b/Lib/operator.py
@@ -105,6 +105,10 @@
 "Same as a * b."
 return a * b
 
+def matmul(a, b):
+ "Same as a @ b."
+ return a @ b
+
 def neg(a):
 "Same as -a."
 return -a
@@ -326,6 +330,11 @@
 a *= b
 return a
 
+def imatmul(a, b):
+ "Same as a @= b."
+ a @= b
+ return a
+
 def ior(a, b):
 "Same as a |= b."
 a |= b
@@ -383,6 +392,7 @@
 __lshift__ = lshift
 __mod__ = mod
 __mul__ = mul
+__matmul__ = matmul
 __neg__ = neg
 __or__ = or_
 __pos__ = pos
@@ -403,6 +413,7 @@
 __ilshift__ = ilshift
 __imod__ = imod
 __imul__ = imul
+__imatmul__ = imatmul
 __ior__ = ior
 __ipow__ = ipow
 __irshift__ = irshift
diff --git a/Lib/test/test_augassign.py b/Lib/test/test_augassign.py
--- a/Lib/test/test_augassign.py
+++ b/Lib/test/test_augassign.py
@@ -136,6 +136,14 @@
 output.append("__imul__ called")
 return self
 
+ def __matmul__(self, val):
+ output.append("__matmul__ called")
+ def __rmatmul__(self, val):
+ output.append("__rmatmul__ called")
+ def __imatmul__(self, val):
+ output.append("__imatmul__ called")
+ return self
+
 def __div__(self, val):
 output.append("__div__ called")
 def __rdiv__(self, val):
@@ -233,6 +241,10 @@
 1 * x
 x *= 1
 
+ x @ 1
+ 1 @ x
+ x @= 1
+
 x / 1
 1 / x
 x /= 1
@@ -279,6 +291,9 @@
 __mul__ called
 __rmul__ called
 __imul__ called
+__matmul__ called
+__rmatmul__ called
+__imatmul__ called
 __truediv__ called
 __rtruediv__ called
 __itruediv__ called
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -150,6 +150,23 @@
 self.assertEqual(_testcapi.docstring_with_signature_and_extra_newlines.__text_signature__,
 "($module, /, parameter)")
 
+ def test_c_type_with_matrix_multiplication(self):
+ M = _testcapi.matmulType
+ m1 = M()
+ m2 = M()
+ self.assertEqual(m1 @ m2, ("matmul", m1, m2))
+ self.assertEqual(m1 @ 42, ("matmul", m1, 42))
+ self.assertEqual(42 @ m1, ("matmul", 42, m1))
+ o = m1
+ o @= m2
+ self.assertEqual(o, ("imatmul", m1, m2))
+ o = m1
+ o @= 42
+ self.assertEqual(o, ("imatmul", m1, 42))
+ o = 42
+ o @= m1
+ self.assertEqual(o, ("matmul", 42, m1))
+
 
 @unittest.skipUnless(threading, 'Threading required for this test.')
 class TestPendingCalls(unittest.TestCase):
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -4160,6 +4160,7 @@
 ('__add__', 'x + y', 'x += y'),
 ('__sub__', 'x - y', 'x -= y'),
 ('__mul__', 'x * y', 'x *= y'),
+ ('__matmul__', 'x @ y', 'x @= y'),
 ('__truediv__', 'operator.truediv(x, y)', None),
 ('__floordiv__', 'operator.floordiv(x, y)', None),
 ('__div__', 'x / y', 'x /= y'),
diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py
--- a/Lib/test/test_grammar.py
+++ b/Lib/test/test_grammar.py
@@ -985,6 +985,20 @@
 self.assertFalse((False is 2) is 3)
 self.assertFalse(False is 2 is 3)
 
+ def test_matrix_mul(self):
+ # This is not intended to be a comprehensive test, rather just to be few
+ # samples of the @ operator in test_grammar.py.
+ class M:
+ def __matmul__(self, o):
+ return 4
+ def __imatmul__(self, o):
+ self.other = o
+ return self
+ m = M()
+ self.assertEqual(m @ m, 4)
+ m @= 42
+ self.assertEqual(m.other, 42)
+
 
 def test_main():
 run_unittest(TokenTests, GrammarTests)
diff --git a/Lib/test/test_operator.py b/Lib/test/test_operator.py
--- a/Lib/test/test_operator.py
+++ b/Lib/test/test_operator.py
@@ -203,6 +203,15 @@
 self.assertRaises(TypeError, operator.mul, None, None)
 self.assertTrue(operator.mul(5, 2) == 10)
 
+ def test_matmul(self):
+ operator = self.module
+ self.assertRaises(TypeError, operator.matmul)
+ self.assertRaises(TypeError, operator.matmul, 42, 42)
+ class M:
+ def __matmul__(self, other):
+ return other - 1
+ self.assertEqual(M() @ 42, 41)
+
 def test_neg(self):
 operator = self.module
 self.assertRaises(TypeError, operator.neg)
@@ -416,6 +425,7 @@
 def __ilshift__ (self, other): return "ilshift"
 def __imod__ (self, other): return "imod"
 def __imul__ (self, other): return "imul"
+ def __imatmul__ (self, other): return "imatmul"
 def __ior__ (self, other): return "ior"
 def __ipow__ (self, other): return "ipow"
 def __irshift__ (self, other): return "irshift"
@@ -430,6 +440,7 @@
 self.assertEqual(operator.ilshift (c, 5), "ilshift")
 self.assertEqual(operator.imod (c, 5), "imod")
 self.assertEqual(operator.imul (c, 5), "imul")
+ self.assertEqual(operator.imatmul (c, 5), "imatmul")
 self.assertEqual(operator.ior (c, 5), "ior")
 self.assertEqual(operator.ipow (c, 5), "ipow")
 self.assertEqual(operator.irshift (c, 5), "irshift")
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -952,7 +952,7 @@
 check(int, s)
 # (PyTypeObject + PyNumberMethods + PyMappingMethods +
 # PySequenceMethods + PyBufferProcs + 4P)
- s = vsize('P2n15Pl4Pn9Pn11PIP') + struct.calcsize('34P 3P 10P 2P 4P')
+ s = vsize('P2n17Pl4Pn9Pn11PIP') + struct.calcsize('34P 3P 10P 2P 4P')
 # Separate block for PyDictKeysObject with 4 entries
 s += struct.calcsize("2nPn") + 4*struct.calcsize("n2P")
 # class
diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py
--- a/Lib/test/test_tokenize.py
+++ b/Lib/test/test_tokenize.py
@@ -464,7 +464,7 @@
 
 Multiplicative
 
- >>> dump_tokens("x = 1//1*1/5*12%0x12")
+ >>> dump_tokens("x = 1//1*1/5*12%0x12 at 42")
 ENCODING 'utf-8' (0, 0) (0, 0)
 NAME 'x' (1, 0) (1, 1)
 OP '=' (1, 2) (1, 3)
@@ -479,6 +479,8 @@
 NUMBER '12' (1, 13) (1, 15)
 OP '%' (1, 15) (1, 16)
 NUMBER '0x12' (1, 16) (1, 20)
+ OP '@' (1, 20) (1, 21)
+ NUMBER '42' (1, 21) (1, 23)
 
 Unary
 
@@ -1154,6 +1156,7 @@
 self.assertExactTypeEqual('//', token.DOUBLESLASH)
 self.assertExactTypeEqual('//=', token.DOUBLESLASHEQUAL)
 self.assertExactTypeEqual('@', token.AT)
+ self.assertExactTypeEqual('@=', token.ATEQUAL)
 
 self.assertExactTypeEqual('a**2+b**2==c**2',
 NAME, token.DOUBLESTAR, NUMBER,
diff --git a/Lib/token.py b/Lib/token.py
--- a/Lib/token.py
+++ b/Lib/token.py
@@ -60,11 +60,12 @@
 DOUBLESLASH = 47
 DOUBLESLASHEQUAL = 48
 AT = 49
-RARROW = 50
-ELLIPSIS = 51
-OP = 52
-ERRORTOKEN = 53
-N_TOKENS = 54
+ATEQUAL = 50
+RARROW = 51
+ELLIPSIS = 52
+OP = 53
+ERRORTOKEN = 54
+N_TOKENS = 55
 NT_OFFSET = 256
 #--end constants--
 
diff --git a/Lib/tokenize.py b/Lib/tokenize.py
--- a/Lib/tokenize.py
+++ b/Lib/tokenize.py
@@ -91,7 +91,8 @@
 '**=': DOUBLESTAREQUAL,
 '//': DOUBLESLASH,
 '//=': DOUBLESLASHEQUAL,
- '@': AT
+ '@': AT,
+ '@=': ATEQUAL,
 }
 
 class TokenInfo(collections.namedtuple('TokenInfo', 'type string start end line')):
@@ -150,7 +151,7 @@
 # recognized as two instances of =).
 Operator = group(r"\*\*=?", r">>=?", r"<<=?", r"!=",
 r"//=?", r"->",
- r"[+\-*/%&|^=<>]=?",
+ r"[+\-*/%&@|^=<>]=?",
 r"~")
 
 Bracket = '[][(){}]'
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,8 @@
 Core and Builtins
 -----------------
 
+- PEP 465 and Issue #21176: Add the '@' operator for matrix multiplication.
+
 - Issue #21134: Fix segfault when str is called on an uninitialized
 UnicodeEncodeError, UnicodeDecodeError, or UnicodeTranslateError object.
 
diff --git a/Modules/_operator.c b/Modules/_operator.c
--- a/Modules/_operator.c
+++ b/Modules/_operator.c
@@ -69,6 +69,7 @@
 spam2(op_add , PyNumber_Add)
 spam2(op_sub , PyNumber_Subtract)
 spam2(op_mul , PyNumber_Multiply)
+spam2(op_matmul , PyNumber_MatrixMultiply)
 spam2(op_floordiv , PyNumber_FloorDivide)
 spam2(op_truediv , PyNumber_TrueDivide)
 spam2(op_mod , PyNumber_Remainder)
@@ -86,6 +87,7 @@
 spam2(op_iadd , PyNumber_InPlaceAdd)
 spam2(op_isub , PyNumber_InPlaceSubtract)
 spam2(op_imul , PyNumber_InPlaceMultiply)
+spam2(op_imatmul , PyNumber_InPlaceMatrixMultiply)
 spam2(op_ifloordiv , PyNumber_InPlaceFloorDivide)
 spam2(op_itruediv , PyNumber_InPlaceTrueDivide)
 spam2(op_imod , PyNumber_InPlaceRemainder)
@@ -343,6 +345,7 @@
 spam2(add, "add(a, b) -- Same as a + b.")
 spam2(sub, "sub(a, b) -- Same as a - b.")
 spam2(mul, "mul(a, b) -- Same as a * b.")
+spam2(matmul, "matmul(a, b) -- Same as a @ b.")
 spam2(floordiv, "floordiv(a, b) -- Same as a // b.")
 spam2(truediv, "truediv(a, b) -- Same as a / b.")
 spam2(mod, "mod(a, b) -- Same as a % b.")
@@ -360,6 +363,7 @@
 spam2(iadd, "a = iadd(a, b) -- Same as a += b.")
 spam2(isub, "a = isub(a, b) -- Same as a -= b.")
 spam2(imul, "a = imul(a, b) -- Same as a *= b.")
+spam2(imatmul, "a = imatmul(a, b) -- Same as a @= b.")
 spam2(ifloordiv, "a = ifloordiv(a, b) -- Same as a //= b.")
 spam2(itruediv, "a = itruediv(a, b) -- Same as a /= b")
 spam2(imod, "a = imod(a, b) -- Same as a %= b.")
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -3298,6 +3298,109 @@
 };
 
 
+typedef struct {
+ PyObject_HEAD
+} matmulObject;
+
+static PyObject *
+matmulType_matmul(PyObject *self, PyObject *other)
+{
+ return Py_BuildValue("(sOO)", "matmul", self, other);
+}
+
+static PyObject *
+matmulType_imatmul(PyObject *self, PyObject *other)
+{
+ return Py_BuildValue("(sOO)", "imatmul", self, other);
+}
+
+static void
+matmulType_dealloc(PyObject *self)
+{
+ return Py_TYPE(self)->tp_free(self);
+}
+
+static PyNumberMethods matmulType_as_number = {
+ 0, /* nb_add */
+ 0, /* nb_subtract */
+ 0, /* nb_multiply */
+ 0, /* nb_remainde r*/
+ 0, /* nb_divmod */
+ 0, /* nb_power */
+ 0, /* nb_negative */
+ 0, /* tp_positive */
+ 0, /* tp_absolute */
+ 0, /* tp_bool */
+ 0, /* nb_invert */
+ 0, /* nb_lshift */
+ 0, /* nb_rshift */
+ 0, /* nb_and */
+ 0, /* nb_xor */
+ 0, /* nb_or */
+ 0, /* nb_int */
+ 0, /* nb_reserved */
+ 0, /* nb_float */
+ 0, /* nb_inplace_add */
+ 0, /* nb_inplace_subtract */
+ 0, /* nb_inplace_multiply */
+ 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 */
+ 0, /* nb_floor_divide */
+ 0, /* nb_true_divide */
+ 0, /* nb_inplace_floor_divide */
+ 0, /* nb_inplace_true_divide */
+ 0, /* nb_index */
+ matmulType_matmul, /* nb_matrix_multiply */
+ matmulType_imatmul /* nb_matrix_inplace_multiply */
+};
+
+static PyTypeObject matmulType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "matmulType",
+ sizeof(matmulObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ matmulType_dealloc, /* destructor tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_reserved */
+ 0, /* tp_repr */
+ &matmulType_as_number, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ PyObject_GenericGetAttr, /* tp_getattro */
+ PyObject_GenericSetAttr, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ 0, /* tp_flags */
+ "C level type with matrix operations defined",
+ 0, /* traverseproc tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ PyType_GenericNew, /* tp_new */
+ PyObject_Del, /* tp_free */
+};
+
 
 static struct PyModuleDef _testcapimodule = {
 PyModuleDef_HEAD_INIT,
@@ -3327,6 +3430,10 @@
 /* don't use a name starting with "test", since we don't want
 test_capi to automatically call this */
 PyModule_AddObject(m, "_test_structmembersType", (PyObject *)&test_structmembersType);
+ if (PyType_Ready(&matmulType) < 0)
+ return NULL;
+ Py_INCREF(&matmulType);
+ PyModule_AddObject(m, "matmulType", (PyObject *)&matmulType);
 
 PyModule_AddObject(m, "CHAR_MAX", PyLong_FromLong(CHAR_MAX));
 PyModule_AddObject(m, "CHAR_MIN", PyLong_FromLong(CHAR_MIN));
diff --git a/Objects/abstract.c b/Objects/abstract.c
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -932,6 +932,12 @@
 }
 
 PyObject *
+PyNumber_MatrixMultiply(PyObject *v, PyObject *w)
+{
+ return binary_op(v, w, NB_SLOT(nb_matrix_multiply), "@");
+}
+
+PyObject *
 PyNumber_FloorDivide(PyObject *v, PyObject *w)
 {
 return binary_op(v, w, NB_SLOT(nb_floor_divide), "//");
@@ -1012,6 +1018,7 @@
 INPLACE_BINOP(PyNumber_InPlaceLshift, nb_inplace_lshift, nb_lshift, "<<=")
 INPLACE_BINOP(PyNumber_InPlaceRshift, nb_inplace_rshift, nb_rshift, ">>=")
 INPLACE_BINOP(PyNumber_InPlaceSubtract, nb_inplace_subtract, nb_subtract, "-=")
+INPLACE_BINOP(PyNumber_InMatrixMultiply, nb_inplace_matrix_multiply, nb_matrix_multiply, "@=")
 
 PyObject *
 PyNumber_InPlaceFloorDivide(PyObject *v, PyObject *w)
@@ -1078,6 +1085,13 @@
 }
 
 PyObject *
+PyNumber_InPlaceMatrixMultiply(PyObject *v, PyObject *w)
+{
+ return binary_iop(v, w, NB_SLOT(nb_inplace_matrix_multiply),
+ NB_SLOT(nb_matrix_multiply), "@=");
+}
+
+PyObject *
 PyNumber_InPlaceRemainder(PyObject *v, PyObject *w)
 {
 return binary_iop(v, w, NB_SLOT(nb_inplace_remainder),
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -4469,6 +4469,8 @@
 COPYNUM(nb_inplace_true_divide);
 COPYNUM(nb_inplace_floor_divide);
 COPYNUM(nb_index);
+ COPYNUM(nb_matrix_multiply);
+ COPYNUM(nb_inplace_matrix_multiply);
 }
 
 if (type->tp_as_sequence != NULL && base->tp_as_sequence != NULL) {
@@ -5605,6 +5607,7 @@
 SLOT1BIN(slot_nb_add, nb_add, "__add__", "__radd__")
 SLOT1BIN(slot_nb_subtract, nb_subtract, "__sub__", "__rsub__")
 SLOT1BIN(slot_nb_multiply, nb_multiply, "__mul__", "__rmul__")
+SLOT1BIN(slot_nb_matrix_multiply, nb_matrix_multiply, "__matmul__", "__rmatmul__")
 SLOT1BIN(slot_nb_remainder, nb_remainder, "__mod__", "__rmod__")
 SLOT1BIN(slot_nb_divmod, nb_divmod, "__divmod__", "__rdivmod__")
 
@@ -5698,6 +5701,7 @@
 SLOT1(slot_nb_inplace_add, "__iadd__", PyObject *, "O")
 SLOT1(slot_nb_inplace_subtract, "__isub__", PyObject *, "O")
 SLOT1(slot_nb_inplace_multiply, "__imul__", PyObject *, "O")
+SLOT1(slot_nb_inplace_matrix_multiply, "__imatmul__", PyObject *, "O")
 SLOT1(slot_nb_inplace_remainder, "__imod__", PyObject *, "O")
 /* Can't use SLOT1 here, because nb_inplace_power is ternary */
 static PyObject *
@@ -6278,6 +6282,12 @@
 "__index__($self, /)\n--\n\n"
 "Return self converted to an integer, if self is suitable"
 "for use as an index into a list."),
+ BINSLOT("__matmul__", nb_matrix_multiply, slot_nb_matrix_multiply,
+ "@"),
+ RBINSLOT("__rmatmul__", nb_matrix_multiply, slot_nb_matrix_multiply,
+ "@"),
+ IBSLOT("__imatmul__", nb_inplace_matrix_multiply, slot_nb_inplace_matrix_multiply,
+ wrap_binaryfunc, "@="),
 MPSLOT("__len__", mp_length, slot_mp_length, wrap_lenfunc,
 "__len__($self, /)\n--\n\nReturn len(self)."),
 MPSLOT("__getitem__", mp_subscript, slot_mp_subscript,
diff --git a/Objects/typeslots.inc b/Objects/typeslots.inc
--- a/Objects/typeslots.inc
+++ b/Objects/typeslots.inc
@@ -73,3 +73,5 @@
 offsetof(PyHeapTypeObject, ht_type.tp_members),
 offsetof(PyHeapTypeObject, ht_type.tp_getset),
 offsetof(PyHeapTypeObject, ht_type.tp_free),
+offsetof(PyHeapTypeObject, as_number.nb_matrix_multiply),
+offsetof(PyHeapTypeObject, as_number.nb_inplace_matrix_multiply),
diff --git a/Parser/Python.asdl b/Parser/Python.asdl
--- a/Parser/Python.asdl
+++ b/Parser/Python.asdl
@@ -91,7 +91,7 @@
 
 boolop = And | Or 
 
- operator = Add | Sub | Mult | Div | Mod | Pow | LShift 
+ operator = Add | Sub | Mult | MatMult | Div | Mod | Pow | LShift 
 | RShift | BitOr | BitXor | BitAnd | FloorDiv
 
 unaryop = Invert | Not | UAdd | USub
diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c
--- a/Parser/tokenizer.c
+++ b/Parser/tokenizer.c
@@ -98,6 +98,7 @@
 "DOUBLESLASH",
 "DOUBLESLASHEQUAL",
 "AT",
+ "ATEQUAL",
 "RARROW",
 "ELLIPSIS",
 /* This table must match the #defines in token.h! */
@@ -1131,7 +1132,7 @@
 case '}': return RBRACE;
 case '^': return CIRCUMFLEX;
 case '~': return TILDE;
- case '@': return AT;
+ case '@': return AT;
 default: return OP;
 }
 }
@@ -1207,6 +1208,11 @@
 case '=': return CIRCUMFLEXEQUAL;
 }
 break;
+ case '@':
+ switch (c2) {
+ case '=': return ATEQUAL;
+ }
+ break;
 }
 return OP;
 }
diff --git a/Python/Python-ast.c b/Python/Python-ast.c
--- a/Python/Python-ast.c
+++ b/Python/Python-ast.c
@@ -349,13 +349,14 @@
 static PyTypeObject *Or_type;
 static PyTypeObject *operator_type;
 static PyObject *Add_singleton, *Sub_singleton, *Mult_singleton,
-*Div_singleton, *Mod_singleton, *Pow_singleton, *LShift_singleton,
-*RShift_singleton, *BitOr_singleton, *BitXor_singleton, *BitAnd_singleton,
-*FloorDiv_singleton;
+*MatMult_singleton, *Div_singleton, *Mod_singleton, *Pow_singleton,
+*LShift_singleton, *RShift_singleton, *BitOr_singleton, *BitXor_singleton,
+*BitAnd_singleton, *FloorDiv_singleton;
 static PyObject* ast2obj_operator(operator_ty);
 static PyTypeObject *Add_type;
 static PyTypeObject *Sub_type;
 static PyTypeObject *Mult_type;
+static PyTypeObject *MatMult_type;
 static PyTypeObject *Div_type;
 static PyTypeObject *Mod_type;
 static PyTypeObject *Pow_type;
@@ -970,6 +971,10 @@
 if (!Mult_type) return 0;
 Mult_singleton = PyType_GenericNew(Mult_type, NULL, NULL);
 if (!Mult_singleton) return 0;
+ MatMult_type = make_type("MatMult", operator_type, NULL, 0);
+ if (!MatMult_type) return 0;
+ MatMult_singleton = PyType_GenericNew(MatMult_type, NULL, NULL);
+ if (!MatMult_singleton) return 0;
 Div_type = make_type("Div", operator_type, NULL, 0);
 if (!Div_type) return 0;
 Div_singleton = PyType_GenericNew(Div_type, NULL, NULL);
@@ -3232,6 +3237,9 @@
 case Mult:
 Py_INCREF(Mult_singleton);
 return Mult_singleton;
+ case MatMult:
+ Py_INCREF(MatMult_singleton);
+ return MatMult_singleton;
 case Div:
 Py_INCREF(Div_singleton);
 return Div_singleton;
@@ -6175,6 +6183,14 @@
 *out = Mult;
 return 0;
 }
+ isinstance = PyObject_IsInstance(obj, (PyObject *)MatMult_type);
+ if (isinstance == -1) {
+ return 1;
+ }
+ if (isinstance) {
+ *out = MatMult;
+ return 0;
+ }
 isinstance = PyObject_IsInstance(obj, (PyObject *)Div_type);
 if (isinstance == -1) {
 return 1;
@@ -6956,6 +6972,8 @@
 if (PyDict_SetItemString(d, "Add", (PyObject*)Add_type) < 0) return NULL;
 if (PyDict_SetItemString(d, "Sub", (PyObject*)Sub_type) < 0) return NULL;
 if (PyDict_SetItemString(d, "Mult", (PyObject*)Mult_type) < 0) return NULL;
+ if (PyDict_SetItemString(d, "MatMult", (PyObject*)MatMult_type) < 0) return
+ NULL;
 if (PyDict_SetItemString(d, "Div", (PyObject*)Div_type) < 0) return NULL;
 if (PyDict_SetItemString(d, "Mod", (PyObject*)Mod_type) < 0) return NULL;
 if (PyDict_SetItemString(d, "Pow", (PyObject*)Pow_type) < 0) return NULL;
diff --git a/Python/ast.c b/Python/ast.c
--- a/Python/ast.c
+++ b/Python/ast.c
@@ -825,6 +825,8 @@
 return Sub;
 case STAR:
 return Mult;
+ case AT:
+ return MatMult;
 case SLASH:
 return Div;
 case DOUBLESLASH:
@@ -1030,6 +1032,8 @@
 return Pow;
 else
 return Mult;
+ case '@':
+ return MatMult;
 default:
 PyErr_Format(PyExc_SystemError, "invalid augassign: %s", STR(n));
 return (operator_ty)0;
@@ -2266,7 +2270,7 @@
 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)*
 */
@@ -2577,7 +2581,7 @@
 /* expr_stmt: testlist_star_expr (augassign (yield_expr|testlist)
 | ('=' (yield_expr|testlist))*)
 testlist_star_expr: (test|star_expr) (',' test|star_expr)* [',']
- augassign: '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^='
+ augassign: '+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^='
 | '<<=' | '>>=' | '**=' | '//='
 test: ... here starts the operator precendence dance
 */
diff --git a/Python/ceval.c b/Python/ceval.c
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -1495,6 +1495,18 @@
 DISPATCH();
 }
 
+ TARGET(BINARY_MATRIX_MULTIPLY) {
+ PyObject *right = POP();
+ PyObject *left = TOP();
+ PyObject *res = PyNumber_MatrixMultiply(left, right);
+ Py_DECREF(left);
+ Py_DECREF(right);
+ SET_TOP(res);
+ if (res == NULL)
+ goto error;
+ DISPATCH();
+ }
+
 TARGET(BINARY_TRUE_DIVIDE) {
 PyObject *divisor = POP();
 PyObject *dividend = TOP();
@@ -1685,6 +1697,18 @@
 DISPATCH();
 }
 
+ TARGET(INPLACE_MATRIX_MULTIPLY) {
+ PyObject *right = POP();
+ PyObject *left = TOP();
+ PyObject *res = PyNumber_InPlaceMatrixMultiply(left, right);
+ Py_DECREF(left);
+ Py_DECREF(right);
+ SET_TOP(res);
+ if (res == NULL)
+ goto error;
+ DISPATCH();
+ }
+
 TARGET(INPLACE_TRUE_DIVIDE) {
 PyObject *divisor = POP();
 PyObject *dividend = TOP();
diff --git a/Python/compile.c b/Python/compile.c
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -881,6 +881,7 @@
 
 case BINARY_POWER:
 case BINARY_MULTIPLY:
+ case BINARY_MATRIX_MULTIPLY:
 case BINARY_MODULO:
 case BINARY_ADD:
 case BINARY_SUBTRACT:
@@ -895,6 +896,7 @@
 case INPLACE_ADD:
 case INPLACE_SUBTRACT:
 case INPLACE_MULTIPLY:
+ case INPLACE_MATRIX_MULTIPLY:
 case INPLACE_MODULO:
 return -1;
 case STORE_SUBSCR:
@@ -2625,6 +2627,8 @@
 return BINARY_SUBTRACT;
 case Mult:
 return BINARY_MULTIPLY;
+ case MatMult:
+ return BINARY_MATRIX_MULTIPLY;
 case Div:
 return BINARY_TRUE_DIVIDE;
 case Mod:
@@ -2689,6 +2693,8 @@
 return INPLACE_SUBTRACT;
 case Mult:
 return INPLACE_MULTIPLY;
+ case MatMult:
+ return INPLACE_MATRIX_MULTIPLY;
 case Div:
 return INPLACE_TRUE_DIVIDE;
 case Mod:
diff --git a/Python/graminit.c b/Python/graminit.c
--- a/Python/graminit.c
+++ b/Python/graminit.c
@@ -476,7 +476,7 @@
 {2, arcs_16_1},
 {3, arcs_16_2},
 };
-static arc arcs_17_0[12] = {
+static arc arcs_17_0[13] = {
 {49, 1},
 {50, 1},
 {51, 1},
@@ -489,19 +489,20 @@
 {58, 1},
 {59, 1},
 {60, 1},
+ {61, 1},
 };
 static arc arcs_17_1[1] = {
 {0, 1},
 };
 static state states_17[2] = {
- {12, arcs_17_0},
+ {13, arcs_17_0},
 {1, arcs_17_1},
 };
 static arc arcs_18_0[1] = {
- {61, 1},
+ {62, 1},
 };
 static arc arcs_18_1[1] = {
- {62, 2},
+ {63, 2},
 };
 static arc arcs_18_2[1] = {
 {0, 2},
@@ -512,7 +513,7 @@
 {1, arcs_18_2},
 };
 static arc arcs_19_0[1] = {
- {63, 1},
+ {64, 1},
 };
 static arc arcs_19_1[1] = {
 {0, 1},
@@ -522,11 +523,11 @@
 {1, arcs_19_1},
 };
 static arc arcs_20_0[5] = {
- {64, 1},
 {65, 1},
 {66, 1},
 {67, 1},
 {68, 1},
+ {69, 1},
 };
 static arc arcs_20_1[1] = {
 {0, 1},
@@ -536,7 +537,7 @@
 {1, arcs_20_1},
 };
 static arc arcs_21_0[1] = {
- {69, 1},
+ {70, 1},
 };
 static arc arcs_21_1[1] = {
 {0, 1},
@@ -546,7 +547,7 @@
 {1, arcs_21_1},
 };
 static arc arcs_22_0[1] = {
- {70, 1},
+ {71, 1},
 };
 static arc arcs_22_1[1] = {
 {0, 1},
@@ -556,7 +557,7 @@
 {1, arcs_22_1},
 };
 static arc arcs_23_0[1] = {
- {71, 1},
+ {72, 1},
 };
 static arc arcs_23_1[2] = {
 {9, 2},
@@ -581,14 +582,14 @@
 {1, arcs_24_1},
 };
 static arc arcs_25_0[1] = {
- {72, 1},
+ {73, 1},
 };
 static arc arcs_25_1[2] = {
 {24, 2},
 {0, 1},
 };
 static arc arcs_25_2[2] = {
- {73, 3},
+ {74, 3},
 {0, 2},
 };
 static arc arcs_25_3[1] = {
@@ -605,8 +606,8 @@
 {1, arcs_25_4},
 };
 static arc arcs_26_0[2] = {
- {74, 1},
 {75, 1},
+ {76, 1},
 };
 static arc arcs_26_1[1] = {
 {0, 1},
@@ -616,10 +617,10 @@
 {1, arcs_26_1},
 };
 static arc arcs_27_0[1] = {
- {76, 1},
+ {77, 1},
 };
 static arc arcs_27_1[1] = {
- {77, 2},
+ {78, 2},
 };
 static arc arcs_27_2[1] = {
 {0, 2},
@@ -630,32 +631,32 @@
 {1, arcs_27_2},
 };
 static arc arcs_28_0[1] = {
- {73, 1},
+ {74, 1},
 };
 static arc arcs_28_1[3] = {
- {78, 2},
 {79, 2},
+ {80, 2},
 {12, 3},
 };
 static arc arcs_28_2[4] = {
- {78, 2},
 {79, 2},
+ {80, 2},
 {12, 3},
- {76, 4},
+ {77, 4},
 };
 static arc arcs_28_3[1] = {
- {76, 4},
+ {77, 4},
 };
 static arc arcs_28_4[3] = {
 {31, 5},
 {13, 6},
- {80, 5},
+ {81, 5},
 };
 static arc arcs_28_5[1] = {
 {0, 5},
 };
 static arc arcs_28_6[1] = {
- {80, 7},
+ {81, 7},
 };
 static arc arcs_28_7[1] = {
 {15, 5},
@@ -674,7 +675,7 @@
 {21, 1},
 };
 static arc arcs_29_1[2] = {
- {82, 2},
+ {83, 2},
 {0, 1},
 };
 static arc arcs_29_2[1] = {
@@ -693,7 +694,7 @@
 {12, 1},
 };
 static arc arcs_30_1[2] = {
- {82, 2},
+ {83, 2},
 {0, 1},
 };
 static arc arcs_30_2[1] = {
@@ -709,14 +710,14 @@
 {1, arcs_30_3},
 };
 static arc arcs_31_0[1] = {
- {81, 1},
+ {82, 1},
 };
 static arc arcs_31_1[2] = {
 {30, 2},
 {0, 1},
 };
 static arc arcs_31_2[2] = {
- {81, 1},
+ {82, 1},
 {0, 2},
 };
 static state states_31[3] = {
@@ -725,7 +726,7 @@
 {2, arcs_31_2},
 };
 static arc arcs_32_0[1] = {
- {83, 1},
+ {84, 1},
 };
 static arc arcs_32_1[2] = {
 {30, 0},
@@ -739,7 +740,7 @@
 {21, 1},
 };
 static arc arcs_33_1[2] = {
- {78, 0},
+ {79, 0},
 {0, 1},
 };
 static state states_33[2] = {
@@ -747,7 +748,7 @@
 {2, arcs_33_1},
 };
 static arc arcs_34_0[1] = {
- {84, 1},
+ {85, 1},
 };
 static arc arcs_34_1[1] = {
 {21, 2},
@@ -762,7 +763,7 @@
 {2, arcs_34_2},
 };
 static arc arcs_35_0[1] = {
- {85, 1},
+ {86, 1},
 };
 static arc arcs_35_1[1] = {
 {21, 2},
@@ -777,7 +778,7 @@
 {2, arcs_35_2},
 };
 static arc arcs_36_0[1] = {
- {86, 1},
+ {87, 1},
 };
 static arc arcs_36_1[1] = {
 {24, 2},
@@ -800,11 +801,11 @@
 {1, arcs_36_4},
 };
 static arc arcs_37_0[8] = {
- {87, 1},
 {88, 1},
 {89, 1},
 {90, 1},
 {91, 1},
+ {92, 1},
 {19, 1},
 {18, 1},
 {17, 1},
@@ -817,7 +818,7 @@
 {1, arcs_37_1},
 };
 static arc arcs_38_0[1] = {
- {92, 1},
+ {93, 1},
 };
 static arc arcs_38_1[1] = {
 {24, 2},
@@ -829,8 +830,8 @@
 {26, 4},
 };
 static arc arcs_38_4[3] = {
- {93, 1},
- {94, 5},
+ {94, 1},
+ {95, 5},
 {0, 4},
 };
 static arc arcs_38_5[1] = {
@@ -853,7 +854,7 @@
 {1, arcs_38_7},
 };
 static arc arcs_39_0[1] = {
- {95, 1},
+ {96, 1},
 };
 static arc arcs_39_1[1] = {
 {24, 2},
@@ -865,7 +866,7 @@
 {26, 4},
 };
 static arc arcs_39_4[2] = {
- {94, 5},
+ {95, 5},
 {0, 4},
 };
 static arc arcs_39_5[1] = {
@@ -888,13 +889,13 @@
 {1, arcs_39_7},
 };
 static arc arcs_40_0[1] = {
- {96, 1},
+ {97, 1},
 };
 static arc arcs_40_1[1] = {
- {62, 2},
+ {63, 2},
 };
 static arc arcs_40_2[1] = {
- {97, 3},
+ {98, 3},
 };
 static arc arcs_40_3[1] = {
 {9, 4},
@@ -906,7 +907,7 @@
 {26, 6},
 };
 static arc arcs_40_6[2] = {
- {94, 7},
+ {95, 7},
 {0, 6},
 };
 static arc arcs_40_7[1] = {
@@ -931,7 +932,7 @@
 {1, arcs_40_9},
 };
 static arc arcs_41_0[1] = {
- {98, 1},
+ {99, 1},
 };
 static arc arcs_41_1[1] = {
 {25, 2},
@@ -940,8 +941,8 @@
 {26, 3},
 };
 static arc arcs_41_3[2] = {
- {99, 4},
- {100, 5},
+ {100, 4},
+ {101, 5},
 };
 static arc arcs_41_4[1] = {
 {25, 6},
@@ -956,9 +957,9 @@
 {26, 9},
 };
 static arc arcs_41_8[4] = {
- {99, 4},
- {94, 10},
- {100, 5},
+ {100, 4},
+ {95, 10},
+ {101, 5},
 {0, 8},
 };
 static arc arcs_41_9[1] = {
@@ -971,7 +972,7 @@
 {26, 12},
 };
 static arc arcs_41_12[2] = {
- {100, 5},
+ {101, 5},
 {0, 12},
 };
 static state states_41[13] = {
@@ -990,10 +991,10 @@
 {2, arcs_41_12},
 };
 static arc arcs_42_0[1] = {
- {101, 1},
+ {102, 1},
 };
 static arc arcs_42_1[1] = {
- {102, 2},
+ {103, 2},
 };
 static arc arcs_42_2[2] = {
 {30, 1},
@@ -1016,11 +1017,11 @@
 {24, 1},
 };
 static arc arcs_43_1[2] = {
- {82, 2},
+ {83, 2},
 {0, 1},
 };
 static arc arcs_43_2[1] = {
- {103, 3},
+ {104, 3},
 };
 static arc arcs_43_3[1] = {
 {0, 3},
@@ -1032,14 +1033,14 @@
 {1, arcs_43_3},
 };
 static arc arcs_44_0[1] = {
- {104, 1},
+ {105, 1},
 };
 static arc arcs_44_1[2] = {
 {24, 2},
 {0, 1},
 };
 static arc arcs_44_2[2] = {
- {82, 3},
+ {83, 3},
 {0, 2},
 };
 static arc arcs_44_3[1] = {
@@ -1063,14 +1064,14 @@
 {0, 1},
 };
 static arc arcs_45_2[1] = {
- {105, 3},
+ {106, 3},
 };
 static arc arcs_45_3[1] = {
 {6, 4},
 };
 static arc arcs_45_4[2] = {
 {6, 4},
- {106, 1},
+ {107, 1},
 };
 static state states_45[5] = {
 {2, arcs_45_0},
@@ -1080,21 +1081,21 @@
 {2, arcs_45_4},
 };
 static arc arcs_46_0[2] = {
- {107, 1},
- {108, 2},
+ {108, 1},
+ {109, 2},
 };
 static arc arcs_46_1[2] = {
- {92, 3},
+ {93, 3},
 {0, 1},
 };
 static arc arcs_46_2[1] = {
 {0, 2},
 };
 static arc arcs_46_3[1] = {
- {107, 4},
+ {108, 4},
 };
 static arc arcs_46_4[1] = {
- {94, 5},
+ {95, 5},
 };
 static arc arcs_46_5[1] = {
 {24, 2},
@@ -1108,8 +1109,8 @@
 {1, arcs_46_5},
 };
 static arc arcs_47_0[2] = {
- {107, 1},
- {110, 1},
+ {108, 1},
+ {111, 1},
 };
 static arc arcs_47_1[1] = {
 {0, 1},
@@ -1119,7 +1120,7 @@
 {1, arcs_47_1},
 };
 static arc arcs_48_0[1] = {
- {111, 1},
+ {112, 1},
 };
 static arc arcs_48_1[2] = {
 {33, 2},
@@ -1142,7 +1143,7 @@
 {1, arcs_48_4},
 };
 static arc arcs_49_0[1] = {
- {111, 1},
+ {112, 1},
 };
 static arc arcs_49_1[2] = {
 {33, 2},
@@ -1152,7 +1153,7 @@
 {25, 3},
 };
 static arc arcs_49_3[1] = {
- {109, 4},
+ {110, 4},
 };
 static arc arcs_49_4[1] = {
 {0, 4},
@@ -1165,10 +1166,10 @@
 {1, arcs_49_4},
 };
 static arc arcs_50_0[1] = {
- {112, 1},
+ {113, 1},
 };
 static arc arcs_50_1[2] = {
- {113, 0},
+ {114, 0},
 {0, 1},
 };
 static state states_50[2] = {
@@ -1176,10 +1177,10 @@
 {2, arcs_50_1},
 };
 static arc arcs_51_0[1] = {
- {114, 1},
+ {115, 1},
 };
 static arc arcs_51_1[2] = {
- {115, 0},
+ {116, 0},
 {0, 1},
 };
 static state states_51[2] = {
@@ -1187,11 +1188,11 @@
 {2, arcs_51_1},
 };
 static arc arcs_52_0[2] = {
- {116, 1},
- {117, 2},
+ {117, 1},
+ {118, 2},
 };
 static arc arcs_52_1[1] = {
- {114, 2},
+ {115, 2},
 };
 static arc arcs_52_2[1] = {
 {0, 2},
@@ -1202,10 +1203,10 @@
 {1, arcs_52_2},
 };
 static arc arcs_53_0[1] = {
- {103, 1},
+ {104, 1},
 };
 static arc arcs_53_1[2] = {
- {118, 0},
+ {119, 0},
 {0, 1},
 };
 static state states_53[2] = {
@@ -1213,25 +1214,25 @@
 {2, arcs_53_1},
 };
 static arc arcs_54_0[10] = {
- {119, 1},
 {120, 1},
 {121, 1},
 {122, 1},
 {123, 1},
 {124, 1},
 {125, 1},
- {97, 1},
- {116, 2},
- {126, 3},
+ {126, 1},
+ {98, 1},
+ {117, 2},
+ {127, 3},
 };
 static arc arcs_54_1[1] = {
 {0, 1},
 };
 static arc arcs_54_2[1] = {
- {97, 1},
+ {98, 1},
 };
 static arc arcs_54_3[2] = {
- {116, 1},
+ {117, 1},
 {0, 3},
 };
 static state states_54[4] = {
@@ -1244,7 +1245,7 @@
 {31, 1},
 };
 static arc arcs_55_1[1] = {
- {103, 2},
+ {104, 2},
 };
 static arc arcs_55_2[1] = {
 {0, 2},
@@ -1255,10 +1256,10 @@
 {1, arcs_55_2},
 };
 static arc arcs_56_0[1] = {
- {127, 1},
+ {128, 1},
 };
 static arc arcs_56_1[2] = {
- {128, 0},
+ {129, 0},
 {0, 1},
 };
 static state states_56[2] = {
@@ -1266,10 +1267,10 @@
 {2, arcs_56_1},
 };
 static arc arcs_57_0[1] = {
- {129, 1},
+ {130, 1},
 };
 static arc arcs_57_1[2] = {
- {130, 0},
+ {131, 0},
 {0, 1},
 };
 static state states_57[2] = {
@@ -1277,10 +1278,10 @@
 {2, arcs_57_1},
 };
 static arc arcs_58_0[1] = {
- {131, 1},
+ {132, 1},
 };
 static arc arcs_58_1[2] = {
- {132, 0},
+ {133, 0},
 {0, 1},
 };
 static state states_58[2] = {
@@ -1288,11 +1289,11 @@
 {2, arcs_58_1},
 };
 static arc arcs_59_0[1] = {
- {133, 1},
+ {134, 1},
 };
 static arc arcs_59_1[3] = {
- {134, 0},
 {135, 0},
+ {136, 0},
 {0, 1},
 };
 static state states_59[2] = {
@@ -1300,11 +1301,11 @@
 {3, arcs_59_1},
 };
 static arc arcs_60_0[1] = {
- {136, 1},
+ {137, 1},
 };
 static arc arcs_60_1[3] = {
- {137, 0},
 {138, 0},
+ {139, 0},
 {0, 1},
 };
 static state states_60[2] = {
@@ -1312,27 +1313,28 @@
 {3, arcs_60_1},
 };
 static arc arcs_61_0[1] = {
- {139, 1},
+ {140, 1},
 };
-static arc arcs_61_1[5] = {
+static arc arcs_61_1[6] = {
 {31, 0},
- {140, 0},
+ {11, 0},
 {141, 0},
 {142, 0},
+ {143, 0},
 {0, 1},
 };
 static state states_61[2] = {
 {1, arcs_61_0},
- {5, arcs_61_1},
+ {6, arcs_61_1},
 };
 static arc arcs_62_0[4] = {
- {137, 1},
 {138, 1},
- {143, 1},
- {144, 2},
+ {139, 1},
+ {144, 1},
+ {145, 2},
 };
 static arc arcs_62_1[1] = {
- {139, 2},
+ {140, 2},
 };
 static arc arcs_62_2[1] = {
 {0, 2},
@@ -1343,15 +1345,15 @@
 {1, arcs_62_2},
 };
 static arc arcs_63_0[1] = {
- {145, 1},
+ {146, 1},
 };
 static arc arcs_63_1[3] = {
- {146, 1},
+ {147, 1},
 {32, 2},
 {0, 1},
 };
 static arc arcs_63_2[1] = {
- {139, 3},
+ {140, 3},
 };
 static arc arcs_63_3[1] = {
 {0, 3},
@@ -1364,44 +1366,44 @@
 };
 static arc arcs_64_0[10] = {
 {13, 1},
- {148, 2},
- {150, 3},
+ {149, 2},
+ {151, 3},
 {21, 4},
- {153, 4},
- {154, 5},
- {79, 4},
- {155, 4},
+ {154, 4},
+ {155, 5},
+ {80, 4},
 {156, 4},
 {157, 4},
+ {158, 4},
 };
 static arc arcs_64_1[3] = {
 {47, 6},
- {147, 6},
+ {148, 6},
 {15, 4},
 };
 static arc arcs_64_2[2] = {
- {147, 7},
- {149, 4},
+ {148, 7},
+ {150, 4},
 };
 static arc arcs_64_3[2] = {
- {151, 8},
- {152, 4},
+ {152, 8},
+ {153, 4},
 };
 static arc arcs_64_4[1] = {
 {0, 4},
 };
 static arc arcs_64_5[2] = {
- {154, 5},
+ {155, 5},
 {0, 5},
 };
 static arc arcs_64_6[1] = {
 {15, 4},
 };
 static arc arcs_64_7[1] = {
- {149, 4},
+ {150, 4},
 };
 static arc arcs_64_8[1] = {
- {152, 4},
+ {153, 4},
 };
 static state states_64[9] = {
 {10, arcs_64_0},
@@ -1419,7 +1421,7 @@
 {48, 1},
 };
 static arc arcs_65_1[3] = {
- {158, 2},
+ {159, 2},
 {30, 3},
 {0, 1},
 };
@@ -1444,15 +1446,15 @@
 };
 static arc arcs_66_0[3] = {
 {13, 1},
- {148, 2},
- {78, 3},
+ {149, 2},
+ {79, 3},
 };
 static arc arcs_66_1[2] = {
 {14, 4},
 {15, 5},
 };
 static arc arcs_66_2[1] = {
- {159, 6},
+ {160, 6},
 };
 static arc arcs_66_3[1] = {
 {21, 5},
@@ -1464,7 +1466,7 @@
 {0, 5},
 };
 static arc arcs_66_6[1] = {
- {149, 5},
+ {150, 5},
 };
 static state states_66[7] = {
 {3, arcs_66_0},
@@ -1476,14 +1478,14 @@
 {1, arcs_66_6},
 };
 static arc arcs_67_0[1] = {
- {160, 1},
+ {161, 1},
 };
 static arc arcs_67_1[2] = {
 {30, 2},
 {0, 1},
 };
 static arc arcs_67_2[2] = {
- {160, 1},
+ {161, 1},
 {0, 2},
 };
 static state states_67[3] = {
@@ -1501,11 +1503,11 @@
 };
 static arc arcs_68_2[3] = {
 {24, 3},
- {161, 4},
+ {162, 4},
 {0, 2},
 };
 static arc arcs_68_3[2] = {
- {161, 4},
+ {162, 4},
 {0, 3},
 };
 static arc arcs_68_4[1] = {
@@ -1534,7 +1536,7 @@
 {1, arcs_69_2},
 };
 static arc arcs_70_0[2] = {
- {103, 1},
+ {104, 1},
 {48, 1},
 };
 static arc arcs_70_1[2] = {
@@ -1542,7 +1544,7 @@
 {0, 1},
 };
 static arc arcs_70_2[3] = {
- {103, 1},
+ {104, 1},
 {48, 1},
 {0, 2},
 };
@@ -1572,7 +1574,7 @@
 };
 static arc arcs_72_1[4] = {
 {25, 2},
- {158, 3},
+ {159, 3},
 {30, 4},
 {0, 1},
 };
@@ -1587,7 +1589,7 @@
 {0, 4},
 };
 static arc arcs_72_5[3] = {
- {158, 3},
+ {159, 3},
 {30, 7},
 {0, 5},
 };
@@ -1623,7 +1625,7 @@
 {2, arcs_72_10},
 };
 static arc arcs_73_0[1] = {
- {162, 1},
+ {163, 1},
 };
 static arc arcs_73_1[1] = {
 {21, 2},
@@ -1659,7 +1661,7 @@
 {1, arcs_73_7},
 };
 static arc arcs_74_0[3] = {
- {163, 1},
+ {164, 1},
 {31, 2},
 {32, 3},
 };
@@ -1674,7 +1676,7 @@
 {24, 6},
 };
 static arc arcs_74_4[4] = {
- {163, 1},
+ {164, 1},
 {31, 2},
 {32, 3},
 {0, 4},
@@ -1687,7 +1689,7 @@
 {0, 6},
 };
 static arc arcs_74_7[2] = {
- {163, 5},
+ {164, 5},
 {32, 3},
 };
 static state states_74[8] = {
@@ -1704,7 +1706,7 @@
 {24, 1},
 };
 static arc arcs_75_1[3] = {
- {158, 2},
+ {159, 2},
 {29, 3},
 {0, 1},
 };
@@ -1721,8 +1723,8 @@
 {1, arcs_75_3},
 };
 static arc arcs_76_0[2] = {
- {158, 1},
- {165, 1},
+ {159, 1},
+ {166, 1},
 };
 static arc arcs_76_1[1] = {
 {0, 1},
@@ -1732,19 +1734,19 @@
 {1, arcs_76_1},
 };
 static arc arcs_77_0[1] = {
- {96, 1},
+ {97, 1},
 };
 static arc arcs_77_1[1] = {
- {62, 2},
+ {63, 2},
 };
 static arc arcs_77_2[1] = {
- {97, 3},
+ {98, 3},
 };
 static arc arcs_77_3[1] = {
- {107, 4},
+ {108, 4},
 };
 static arc arcs_77_4[2] = {
- {164, 5},
+ {165, 5},
 {0, 4},
 };
 static arc arcs_77_5[1] = {
@@ -1759,13 +1761,13 @@
 {1, arcs_77_5},
 };
 static arc arcs_78_0[1] = {
- {92, 1},
+ {93, 1},
 };
 static arc arcs_78_1[1] = {
- {109, 2},
+ {110, 2},
 };
 static arc arcs_78_2[2] = {
- {164, 3},
+ {165, 3},
 {0, 2},
 };
 static arc arcs_78_3[1] = {
@@ -1788,10 +1790,10 @@
 {1, arcs_79_1},
 };
 static arc arcs_80_0[1] = {
- {167, 1},
+ {168, 1},
 };
 static arc arcs_80_1[2] = {
- {168, 2},
+ {169, 2},
 {0, 1},
 };
 static arc arcs_80_2[1] = {
@@ -1803,7 +1805,7 @@
 {1, arcs_80_2},
 };
 static arc arcs_81_0[2] = {
- {73, 1},
+ {74, 1},
 {9, 2},
 };
 static arc arcs_81_1[1] = {
@@ -1819,11 +1821,11 @@
 };
 static dfa dfas[82] = {
 {256, "single_input", 0, 3, states_0,
- "004円050円060円200円000円000円000円240円340円223円160円220円045円200円020円000円000円206円120円076円204円000円"},
+ "004円050円060円200円000円000円000円100円301円047円341円040円113円000円041円000円000円014円241円174円010円001円"},
 {257, "file_input", 0, 2, states_1,
- "204円050円060円200円000円000円000円240円340円223円160円220円045円200円020円000円000円206円120円076円204円000円"},
+ "204円050円060円200円000円000円000円100円301円047円341円040円113円000円041円000円000円014円241円174円010円001円"},
 {258, "eval_input", 0, 3, states_2,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円200円020円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円041円000円000円014円241円174円000円000円"},
 {259, "decorator", 0, 7, states_3,
 "000円010円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
 {260, "decorators", 0, 2, states_4,
@@ -1843,39 +1845,39 @@
 {267, "vfpdef", 0, 2, states_11,
 "000円000円040円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
 {268, "stmt", 0, 2, states_12,
- "000円050円060円200円000円000円000円240円340円223円160円220円045円200円020円000円000円206円120円076円204円000円"},
+ "000円050円060円200円000円000円000円100円301円047円341円040円113円000円041円000円000円014円241円174円010円001円"},
 {269, "simple_stmt", 0, 4, states_13,
- "000円040円040円200円000円000円000円240円340円223円160円000円000円200円020円000円000円206円120円076円200円000円"},
+ "000円040円040円200円000円000円000円100円301円047円341円000円000円000円041円000円000円014円241円174円000円001円"},
 {270, "small_stmt", 0, 2, states_14,
- "000円040円040円200円000円000円000円240円340円223円160円000円000円200円020円000円000円206円120円076円200円000円"},
+ "000円040円040円200円000円000円000円100円301円047円341円000円000円000円041円000円000円014円241円174円000円001円"},
 {271, "expr_stmt", 0, 6, states_15,
- "000円040円040円200円000円000円000円000円000円200円000円000円000円200円020円000円000円206円120円076円000円000円"},
+ "000円040円040円200円000円000円000円000円000円000円001円000円000円000円041円000円000円014円241円174円000円000円"},
 {272, "testlist_star_expr", 0, 3, states_16,
- "000円040円040円200円000円000円000円000円000円200円000円000円000円200円020円000円000円206円120円076円000円000円"},
+ "000円040円040円200円000円000円000円000円000円000円001円000円000円000円041円000円000円014円241円174円000円000円"},
 {273, "augassign", 0, 2, states_17,
- "000円000円000円000円000円000円376円037円000円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円376円077円000円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
 {274, "del_stmt", 0, 3, states_18,
- "000円000円000円000円000円000円000円040円000円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円100円000円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
 {275, "pass_stmt", 0, 2, states_19,
- "000円000円000円000円000円000円000円200円000円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円001円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
 {276, "flow_stmt", 0, 2, states_20,
- "000円000円000円000円000円000円000円000円340円001円000円000円000円000円000円000円000円000円000円000円200円000円"},
+ "000円000円000円000円000円000円000円000円300円003円000円000円000円000円000円000円000円000円000円000円000円001円"},
 {277, "break_stmt", 0, 2, states_21,
- "000円000円000円000円000円000円000円000円040円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円100円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
 {278, "continue_stmt", 0, 2, states_22,
- "000円000円000円000円000円000円000円000円100円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円200円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
 {279, "return_stmt", 0, 3, states_23,
- "000円000円000円000円000円000円000円000円200円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円001円000円000円000円000円000円000円000円000円000円000円000円000円"},
 {280, "yield_stmt", 0, 2, states_24,
- "000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円200円000円"},
+ "000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円001円"},
 {281, "raise_stmt", 0, 5, states_25,
- "000円000円000円000円000円000円000円000円000円001円000円000円000円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円002円000円000円000円000円000円000円000円000円000円000円000円000円"},
 {282, "import_stmt", 0, 2, states_26,
- "000円000円000円000円000円000円000円000円000円022円000円000円000円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円044円000円000円000円000円000円000円000円000円000円000円000円000円"},
 {283, "import_name", 0, 3, states_27,
- "000円000円000円000円000円000円000円000円000円020円000円000円000円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円040円000円000円000円000円000円000円000円000円000円000円000円000円"},
 {284, "import_from", 0, 8, states_28,
- "000円000円000円000円000円000円000円000円000円002円000円000円000円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円004円000円000円000円000円000円000円000円000円000円000円000円000円"},
 {285, "import_as_name", 0, 4, states_29,
 "000円000円040円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
 {286, "dotted_as_name", 0, 4, states_30,
@@ -1887,103 +1889,103 @@
 {289, "dotted_name", 0, 2, states_33,
 "000円000円040円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
 {290, "global_stmt", 0, 3, states_34,
- "000円000円000円000円000円000円000円000円000円000円020円000円000円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円000円040円000円000円000円000円000円000円000円000円000円000円000円"},
 {291, "nonlocal_stmt", 0, 3, states_35,
- "000円000円000円000円000円000円000円000円000円000円040円000円000円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円000円100円000円000円000円000円000円000円000円000円000円000円000円"},
 {292, "assert_stmt", 0, 5, states_36,
- "000円000円000円000円000円000円000円000円000円000円100円000円000円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円000円200円000円000円000円000円000円000円000円000円000円000円000円"},
 {293, "compound_stmt", 0, 2, states_37,
- "000円010円020円000円000円000円000円000円000円000円000円220円045円000円000円000円000円000円000円000円004円000円"},
+ "000円010円020円000円000円000円000円000円000円000円000円040円113円000円000円000円000円000円000円000円010円000円"},
 {294, "if_stmt", 0, 8, states_38,
- "000円000円000円000円000円000円000円000円000円000円000円020円000円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円000円000円040円000円000円000円000円000円000円000円000円000円000円"},
 {295, "while_stmt", 0, 8, states_39,
- "000円000円000円000円000円000円000円000円000円000円000円200円000円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円000円000円000円001円000円000円000円000円000円000円000円000円000円"},
 {296, "for_stmt", 0, 10, states_40,
- "000円000円000円000円000円000円000円000円000円000円000円000円001円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円000円000円000円002円000円000円000円000円000円000円000円000円000円"},
 {297, "try_stmt", 0, 13, states_41,
- "000円000円000円000円000円000円000円000円000円000円000円000円004円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円000円000円000円010円000円000円000円000円000円000円000円000円000円"},
 {298, "with_stmt", 0, 5, states_42,
- "000円000円000円000円000円000円000円000円000円000円000円000円040円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円000円000円000円100円000円000円000円000円000円000円000円000円000円"},
 {299, "with_item", 0, 4, states_43,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円200円020円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円041円000円000円014円241円174円000円000円"},
 {300, "except_clause", 0, 5, states_44,
- "000円000円000円000円000円000円000円000円000円000円000円000円000円001円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円000円000円000円000円002円000円000円000円000円000円000円000円000円"},
 {301, "suite", 0, 5, states_45,
- "004円040円040円200円000円000円000円240円340円223円160円000円000円200円020円000円000円206円120円076円200円000円"},
+ "004円040円040円200円000円000円000円100円301円047円341円000円000円000円041円000円000円014円241円174円000円001円"},
 {302, "test", 0, 6, states_46,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円200円020円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円041円000円000円014円241円174円000円000円"},
 {303, "test_nocond", 0, 2, states_47,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円200円020円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円041円000円000円014円241円174円000円000円"},
 {304, "lambdef", 0, 5, states_48,
- "000円000円000円000円000円000円000円000円000円000円000円000円000円200円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円000円000円000円000円000円001円000円000円000円000円000円000円000円"},
 {305, "lambdef_nocond", 0, 5, states_49,
- "000円000円000円000円000円000円000円000円000円000円000円000円000円200円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円000円000円000円000円000円001円000円000円000円000円000円000円000円"},
 {306, "or_test", 0, 2, states_50,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円000円020円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円040円000円000円014円241円174円000円000円"},
 {307, "and_test", 0, 2, states_51,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円000円020円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円040円000円000円014円241円174円000円000円"},
 {308, "not_test", 0, 3, states_52,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円000円020円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円040円000円000円014円241円174円000円000円"},
 {309, "comparison", 0, 2, states_53,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円000円000円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円000円000円000円014円241円174円000円000円"},
 {310, "comp_op", 0, 4, states_54,
- "000円000円000円000円000円000円000円000円000円000円000円000円002円000円220円177円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円000円000円000円004円000円040円377円000円000円000円000円000円000円"},
 {311, "star_expr", 0, 3, states_55,
 "000円000円000円200円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
 {312, "expr", 0, 2, states_56,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円000円000円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円000円000円000円014円241円174円000円000円"},
 {313, "xor_expr", 0, 2, states_57,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円000円000円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円000円000円000円014円241円174円000円000円"},
 {314, "and_expr", 0, 2, states_58,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円000円000円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円000円000円000円014円241円174円000円000円"},
 {315, "shift_expr", 0, 2, states_59,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円000円000円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円000円000円000円014円241円174円000円000円"},
 {316, "arith_expr", 0, 2, states_60,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円000円000円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円000円000円000円014円241円174円000円000円"},
 {317, "term", 0, 2, states_61,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円000円000円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円000円000円000円014円241円174円000円000円"},
 {318, "factor", 0, 3, states_62,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円000円000円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円000円000円000円014円241円174円000円000円"},
 {319, "power", 0, 4, states_63,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円000円000円000円000円000円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円000円000円000円000円240円174円000円000円"},
 {320, "atom", 0, 9, states_64,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円000円000円000円000円000円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円000円000円000円000円240円174円000円000円"},
 {321, "testlist_comp", 0, 5, states_65,
- "000円040円040円200円000円000円000円000円000円200円000円000円000円200円020円000円000円206円120円076円000円000円"},
+ "000円040円040円200円000円000円000円000円000円000円001円000円000円000円041円000円000円014円241円174円000円000円"},
 {322, "trailer", 0, 7, states_66,
- "000円040円000円000円000円000円000円000円000円100円000円000円000円000円000円000円000円000円020円000円000円000円"},
+ "000円040円000円000円000円000円000円000円000円200円000円000円000円000円000円000円000円000円040円000円000円000円"},
 {323, "subscriptlist", 0, 3, states_67,
- "000円040円040円002円000円000円000円000円000円200円000円000円000円200円020円000円000円206円120円076円000円000円"},
+ "000円040円040円002円000円000円000円000円000円000円001円000円000円000円041円000円000円014円241円174円000円000円"},
 {324, "subscript", 0, 5, states_68,
- "000円040円040円002円000円000円000円000円000円200円000円000円000円200円020円000円000円206円120円076円000円000円"},
+ "000円040円040円002円000円000円000円000円000円000円001円000円000円000円041円000円000円014円241円174円000円000円"},
 {325, "sliceop", 0, 3, states_69,
 "000円000円000円002円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
 {326, "exprlist", 0, 3, states_70,
- "000円040円040円200円000円000円000円000円000円200円000円000円000円000円000円000円000円206円120円076円000円000円"},
+ "000円040円040円200円000円000円000円000円000円000円001円000円000円000円000円000円000円014円241円174円000円000円"},
 {327, "testlist", 0, 3, states_71,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円200円020円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円041円000円000円014円241円174円000円000円"},
 {328, "dictorsetmaker", 0, 11, states_72,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円200円020円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円041円000円000円014円241円174円000円000円"},
 {329, "classdef", 0, 8, states_73,
- "000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円004円000円"},
+ "000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円010円000円"},
 {330, "arglist", 0, 8, states_74,
- "000円040円040円200円001円000円000円000円000円200円000円000円000円200円020円000円000円206円120円076円000円000円"},
+ "000円040円040円200円001円000円000円000円000円000円001円000円000円000円041円000円000円014円241円174円000円000円"},
 {331, "argument", 0, 4, states_75,
- "000円040円040円000円000円000円000円000円000円200円000円000円000円200円020円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円000円001円000円000円000円041円000円000円014円241円174円000円000円"},
 {332, "comp_iter", 0, 2, states_76,
- "000円000円000円000円000円000円000円000円000円000円000円020円001円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円000円000円040円002円000円000円000円000円000円000円000円000円000円"},
 {333, "comp_for", 0, 6, states_77,
- "000円000円000円000円000円000円000円000円000円000円000円000円001円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円000円000円000円002円000円000円000円000円000円000円000円000円000円"},
 {334, "comp_if", 0, 4, states_78,
- "000円000円000円000円000円000円000円000円000円000円000円020円000円000円000円000円000円000円000円000円000円000円"},
+ "000円000円000円000円000円000円000円000円000円000円000円040円000円000円000円000円000円000円000円000円000円000円"},
 {335, "encoding_decl", 0, 2, states_79,
 "000円000円040円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円"},
 {336, "yield_expr", 0, 3, states_80,
- "000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円200円000円"},
+ "000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円000円001円"},
 {337, "yield_arg", 0, 3, states_81,
- "000円040円040円000円000円000円000円000円000円202円000円000円000円200円020円000円000円206円120円076円000円000円"},
+ "000円040円040円000円000円000円000円000円000円004円001円000円000円000円041円000円000円014円241円174円000円000円"},
 };
-static label labels[169] = {
+static label labels[170] = {
 {0, "EMPTY"},
 {256, 0},
 {4, 0},
@@ -2007,7 +2009,7 @@
 {1, "def"},
 {1, 0},
 {263, 0},
- {50, 0},
+ {51, 0},
 {302, 0},
 {11, 0},
 {301, 0},
@@ -2036,6 +2038,7 @@
 {36, 0},
 {37, 0},
 {38, 0},
+ {50, 0},
 {39, 0},
 {40, 0},
 {41, 0},
@@ -2063,7 +2066,7 @@
 {1, "import"},
 {288, 0},
 {23, 0},
- {51, 0},
+ {52, 0},
 {287, 0},
 {285, 0},
 {1, "as"},
@@ -2157,6 +2160,6 @@
 grammar _PyParser_Grammar = {
 82,
 dfas,
- {169, labels},
+ {170, labels},
 256
 };
diff --git a/Python/importlib.h b/Python/importlib.h
--- a/Python/importlib.h
+++ b/Python/importlib.h
[stripped]
diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h
--- a/Python/opcode_targets.h
+++ b/Python/opcode_targets.h
@@ -15,8 +15,8 @@
 &&_unknown_opcode,
 &&_unknown_opcode,
 &&TARGET_UNARY_INVERT,
- &&_unknown_opcode,
- &&_unknown_opcode,
+ &&TARGET_BINARY_MATRIX_MULTIPLY,
+ &&TARGET_INPLACE_MATRIX_MULTIPLY,
 &&_unknown_opcode,
 &&TARGET_BINARY_POWER,
 &&TARGET_BINARY_MULTIPLY,
-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /