bpo-36540: PEP 570 -- Implementation (GH-12701)

This commit contains the implementation of PEP570: Python positional-only parameters.

* Update Grammar/Grammar with new typedarglist and varargslist

* Regenerate grammar files

* Update and regenerate AST related files

* Update code object

* Update marshal.c

* Update compiler and symtable

* Regenerate importlib files

* Update callable objects

* Implement positional-only args logic in ceval.c

* Regenerate frozen data

* Update standard library to account for positional-only args

* Add test file for positional-only args

* Update other test files to account for positional-only args

* Add News entry

* Update inspect module and related tests
diff --git a/Objects/call.c b/Objects/call.c
index d52e7e2..68f9e87 100644
--- a/Objects/call.c
+++ b/Objects/call.c
@@ -320,11 +320,11 @@
         (co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
     {
         /* Fast paths */
-        if (argdefs == NULL && co->co_argcount == nargs) {
+        if (argdefs == NULL && co->co_argcount + co->co_posonlyargcount == nargs) {
             return function_code_fastcall(co, args, nargs, globals);
         }
         else if (nargs == 0 && argdefs != NULL
-                 && co->co_argcount == PyTuple_GET_SIZE(argdefs)) {
+                 && co->co_argcount + co->co_posonlyargcount == PyTuple_GET_SIZE(argdefs)) {
             /* function called with no arguments, but all parameters have
                a default value: use default values as arguments .*/
             args = _PyTuple_ITEMS(argdefs);
@@ -406,11 +406,11 @@
     if (co->co_kwonlyargcount == 0 && nkwargs == 0 &&
         (co->co_flags & ~PyCF_MASK) == (CO_OPTIMIZED | CO_NEWLOCALS | CO_NOFREE))
     {
-        if (argdefs == NULL && co->co_argcount == nargs) {
+        if (argdefs == NULL && co->co_argcount + co->co_posonlyargcount== nargs) {
             return function_code_fastcall(co, stack, nargs, globals);
         }
         else if (nargs == 0 && argdefs != NULL
-                 && co->co_argcount == PyTuple_GET_SIZE(argdefs)) {
+                 && co->co_argcount + co->co_posonlyargcount == PyTuple_GET_SIZE(argdefs)) {
             /* function called with no arguments, but all parameters have
                a default value: use default values as arguments .*/
             stack = _PyTuple_ITEMS(argdefs);
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 09182d6..62d7c5d 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -96,7 +96,7 @@
 
 
 PyCodeObject *
-PyCode_New(int argcount, int kwonlyargcount,
+PyCode_New(int argcount, int posonlyargcount, int kwonlyargcount,
            int nlocals, int stacksize, int flags,
            PyObject *code, PyObject *consts, PyObject *names,
            PyObject *varnames, PyObject *freevars, PyObject *cellvars,
@@ -108,8 +108,8 @@
     Py_ssize_t i, n_cellvars, n_varnames, total_args;
 
     /* Check argument types */
-    if (argcount < 0 || kwonlyargcount < 0 || nlocals < 0 ||
-        code == NULL || !PyBytes_Check(code) ||
+    if (argcount < 0 || posonlyargcount < 0 || kwonlyargcount < 0 ||
+        nlocals < 0 || code == NULL || !PyBytes_Check(code) ||
         consts == NULL || !PyTuple_Check(consts) ||
         names == NULL || !PyTuple_Check(names) ||
         varnames == NULL || !PyTuple_Check(varnames) ||
@@ -141,10 +141,12 @@
     }
 
     n_varnames = PyTuple_GET_SIZE(varnames);
-    if (argcount <= n_varnames && kwonlyargcount <= n_varnames) {
+    if (posonlyargcount + argcount <= n_varnames
+        && kwonlyargcount <= n_varnames) {
         /* Never overflows. */
-        total_args = (Py_ssize_t)argcount + (Py_ssize_t)kwonlyargcount +
-                ((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0);
+        total_args = (Py_ssize_t)posonlyargcount + (Py_ssize_t)argcount
+                      + (Py_ssize_t)kwonlyargcount +
+                      ((flags & CO_VARARGS) != 0) + ((flags & CO_VARKEYWORDS) != 0);
     }
     else {
         total_args = n_varnames + 1;
@@ -193,6 +195,7 @@
         return NULL;
     }
     co->co_argcount = argcount;
+    co->co_posonlyargcount = posonlyargcount;
     co->co_kwonlyargcount = kwonlyargcount;
     co->co_nlocals = nlocals;
     co->co_stacksize = stacksize;
@@ -249,6 +252,7 @@
         goto failed;
 
     result = PyCode_New(0,                      /* argcount */
+                0,                              /* posonlyargcount */
                 0,                              /* kwonlyargcount */
                 0,                              /* nlocals */
                 0,                              /* stacksize */
@@ -274,21 +278,22 @@
 #define OFF(x) offsetof(PyCodeObject, x)
 
 static PyMemberDef code_memberlist[] = {
-    {"co_argcount",     T_INT,          OFF(co_argcount),       READONLY},
-    {"co_kwonlyargcount",       T_INT,  OFF(co_kwonlyargcount), READONLY},
-    {"co_nlocals",      T_INT,          OFF(co_nlocals),        READONLY},
-    {"co_stacksize",T_INT,              OFF(co_stacksize),      READONLY},
-    {"co_flags",        T_INT,          OFF(co_flags),          READONLY},
-    {"co_code",         T_OBJECT,       OFF(co_code),           READONLY},
-    {"co_consts",       T_OBJECT,       OFF(co_consts),         READONLY},
-    {"co_names",        T_OBJECT,       OFF(co_names),          READONLY},
-    {"co_varnames",     T_OBJECT,       OFF(co_varnames),       READONLY},
-    {"co_freevars",     T_OBJECT,       OFF(co_freevars),       READONLY},
-    {"co_cellvars",     T_OBJECT,       OFF(co_cellvars),       READONLY},
-    {"co_filename",     T_OBJECT,       OFF(co_filename),       READONLY},
-    {"co_name",         T_OBJECT,       OFF(co_name),           READONLY},
-    {"co_firstlineno", T_INT,           OFF(co_firstlineno),    READONLY},
-    {"co_lnotab",       T_OBJECT,       OFF(co_lnotab),         READONLY},
+    {"co_argcount",     T_INT,          OFF(co_argcount),        READONLY},
+    {"co_posonlyargcount",      T_INT,  OFF(co_posonlyargcount), READONLY},
+    {"co_kwonlyargcount",       T_INT,  OFF(co_kwonlyargcount),  READONLY},
+    {"co_nlocals",      T_INT,          OFF(co_nlocals),         READONLY},
+    {"co_stacksize",T_INT,              OFF(co_stacksize),       READONLY},
+    {"co_flags",        T_INT,          OFF(co_flags),           READONLY},
+    {"co_code",         T_OBJECT,       OFF(co_code),            READONLY},
+    {"co_consts",       T_OBJECT,       OFF(co_consts),          READONLY},
+    {"co_names",        T_OBJECT,       OFF(co_names),           READONLY},
+    {"co_varnames",     T_OBJECT,       OFF(co_varnames),        READONLY},
+    {"co_freevars",     T_OBJECT,       OFF(co_freevars),        READONLY},
+    {"co_cellvars",     T_OBJECT,       OFF(co_cellvars),        READONLY},
+    {"co_filename",     T_OBJECT,       OFF(co_filename),        READONLY},
+    {"co_name",         T_OBJECT,       OFF(co_name),            READONLY},
+    {"co_firstlineno", T_INT,           OFF(co_firstlineno),     READONLY},
+    {"co_lnotab",       T_OBJECT,       OFF(co_lnotab),          READONLY},
     {NULL}      /* Sentinel */
 };
 
@@ -335,9 +340,9 @@
 }
 
 PyDoc_STRVAR(code_doc,
-"code(argcount, kwonlyargcount, nlocals, stacksize, flags, codestring,\n\
-      constants, names, varnames, filename, name, firstlineno,\n\
-      lnotab[, freevars[, cellvars]])\n\
+"code(argcount, posonlyargcount, kwonlyargcount, nlocals, stacksize,\n\
+      flags, codestring, constants, names, varnames, filename, name,\n\
+      firstlineno, lnotab[, freevars[, cellvars]])\n\
 \n\
 Create a code object.  Not for the faint of heart.");
 
@@ -345,6 +350,7 @@
 code_new(PyTypeObject *type, PyObject *args, PyObject *kw)
 {
     int argcount;
+    int posonlyargcount;
     int kwonlyargcount;
     int nlocals;
     int stacksize;
@@ -361,8 +367,8 @@
     int firstlineno;
     PyObject *lnotab;
 
-    if (!PyArg_ParseTuple(args, "iiiiiSO!O!O!UUiS|O!O!:code",
-                          &argcount, &kwonlyargcount,
+    if (!PyArg_ParseTuple(args, "iiiiiiSO!O!O!UUiS|O!O!:code",
+                          &argcount, &posonlyargcount, &kwonlyargcount,
                               &nlocals, &stacksize, &flags,
                           &code,
                           &PyTuple_Type, &consts,
@@ -381,6 +387,13 @@
         goto cleanup;
     }
 
+    if (posonlyargcount < 0) {
+        PyErr_SetString(
+            PyExc_ValueError,
+            "code: posonlyargcount must not be negative");
+        goto cleanup;
+    }
+
     if (kwonlyargcount < 0) {
         PyErr_SetString(
             PyExc_ValueError,
@@ -413,7 +426,7 @@
     if (ourcellvars == NULL)
         goto cleanup;
 
-    co = (PyObject *)PyCode_New(argcount, kwonlyargcount,
+    co = (PyObject *)PyCode_New(argcount, posonlyargcount, kwonlyargcount,
                                 nlocals, stacksize, flags,
                                 code, consts, ournames, ourvarnames,
                                 ourfreevars, ourcellvars, filename,
@@ -645,9 +658,11 @@
     cp = (PyCodeObject *)other;
 
     eq = PyObject_RichCompareBool(co->co_name, cp->co_name, Py_EQ);
-    if (eq <= 0) goto unequal;
+    if (!eq) goto unequal;
     eq = co->co_argcount == cp->co_argcount;
     if (!eq) goto unequal;
+    eq = co->co_posonlyargcount == cp->co_posonlyargcount;
+    if (!eq) goto unequal;
     eq = co->co_kwonlyargcount == cp->co_kwonlyargcount;
     if (!eq) goto unequal;
     eq = co->co_nlocals == cp->co_nlocals;
@@ -720,7 +735,7 @@
     h6 = PyObject_Hash(co->co_cellvars);
     if (h6 == -1) return -1;
     h = h0 ^ h1 ^ h2 ^ h3 ^ h4 ^ h5 ^ h6 ^
-        co->co_argcount ^ co->co_kwonlyargcount ^
+        co->co_argcount ^ co->co_posonlyargcount ^ co->co_kwonlyargcount ^
         co->co_nlocals ^ co->co_flags;
     if (h == -1) h = -2;
     return h;