]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-122943: Move code generation for var-positional parameter to converters (GH-126575)
authorSerhiy Storchaka <storchaka@gmail.com>
Fri, 8 Nov 2024 12:12:15 +0000 (14:12 +0200)
committerGitHub <noreply@github.com>
Fri, 8 Nov 2024 12:12:15 +0000 (14:12 +0200)
Tools/clinic/libclinic/converters.py
Tools/clinic/libclinic/parse_args.py

index 860ff8135fb258dcadad6749e13dd1cf5ccd1c83..a65f73ba02fb5d3fd3b1efea55ad6acfd87cb586 100644 (file)
@@ -1232,7 +1232,18 @@ class self_converter(CConverter):
 
 # Converters for var-positional parameter.
 
-class varpos_tuple_converter(CConverter):
+class VarPosCConverter(CConverter):
+    format_unit = ''
+
+    def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None:
+        raise AssertionError('should never be called')
+
+    def parse_vararg(self, *, pos_only: int, min_pos: int, max_pos: int,
+                     fastcall: bool, limited_capi: bool) -> str:
+        raise NotImplementedError
+
+
+class varpos_tuple_converter(VarPosCConverter):
     type = 'PyObject *'
     format_unit = ''
     c_default = 'NULL'
@@ -1240,14 +1251,76 @@ class varpos_tuple_converter(CConverter):
     def cleanup(self) -> str:
         return f"""Py_XDECREF({self.parser_name});\n"""
 
-    def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None:
-        raise AssertionError('should never be called')
+    def parse_vararg(self, *, pos_only: int, min_pos: int, max_pos: int,
+                     fastcall: bool, limited_capi: bool) -> str:
+        paramname = self.parser_name
+        if fastcall:
+            if limited_capi:
+                if min(pos_only, min_pos) < max_pos:
+                    size = f'Py_MAX(nargs - {max_pos}, 0)'
+                else:
+                    size = f'nargs - {max_pos}' if max_pos else 'nargs'
+                return f"""
+                    {paramname} = PyTuple_New({size});
+                    if (!{paramname}) {{{{
+                        goto exit;
+                    }}}}
+                    for (Py_ssize_t i = {max_pos}; i < nargs; ++i) {{{{
+                        PyTuple_SET_ITEM({paramname}, i - {max_pos}, Py_NewRef(args[i]));
+                    }}}}
+                    """
+            else:
+                self.add_include('pycore_tuple.h', '_PyTuple_FromArray()')
+                start = f'args + {max_pos}' if max_pos else 'args'
+                size = f'nargs - {max_pos}' if max_pos else 'nargs'
+                if min(pos_only, min_pos) < max_pos:
+                    return f"""
+                        {paramname} = nargs > {max_pos}
+                            ? _PyTuple_FromArray({start}, {size})
+                            : PyTuple_New(0);
+                        if ({paramname} == NULL) {{{{
+                            goto exit;
+                        }}}}
+                        """
+                else:
+                    return f"""
+                        {paramname} = _PyTuple_FromArray({start}, {size});
+                        if ({paramname} == NULL) {{{{
+                            goto exit;
+                        }}}}
+                        """
+        else:
+            if max_pos:
+                return f"""
+                    {paramname} = PyTuple_GetSlice(args, {max_pos}, PY_SSIZE_T_MAX);
+                    if (!{paramname}) {{{{
+                        goto exit;
+                    }}}}
+                    """
+            else:
+                return f"{paramname} = Py_NewRef(args);\n"
 
-class varpos_array_converter(CConverter):
+
+class varpos_array_converter(VarPosCConverter):
     type = 'PyObject * const *'
-    format_unit = ''
     length = True
     c_ignored_default = ''
 
-    def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None:
-        raise AssertionError('should never be called')
+    def parse_vararg(self, *, pos_only: int, min_pos: int, max_pos: int,
+                     fastcall: bool, limited_capi: bool) -> str:
+        paramname = self.parser_name
+        if not fastcall:
+            self.add_include('pycore_tuple.h', '_PyTuple_ITEMS()')
+        start = 'args' if fastcall else '_PyTuple_ITEMS(args)'
+        size = 'nargs' if fastcall else 'PyTuple_GET_SIZE(args)'
+        if max_pos:
+            if min(pos_only, min_pos) < max_pos:
+                start = f'{size} > {max_pos} ? {start} + {max_pos} : {start}'
+                size = f'Py_MAX(0, {size} - {max_pos})'
+            else:
+                start = f'{start} + {max_pos}'
+                size = f'{size} - {max_pos}'
+        return f"""
+            {paramname} = {start};
+            {self.length_name} = {size};
+            """
index 2ce4e7512148d26eaf03530c2f0e79f7847d18d7..08cf697b67e5ae27f798bf6524912a068f26885b 100644 (file)
@@ -452,71 +452,13 @@ class ParseArgsCodeGen:
 
     def _parse_vararg(self) -> str:
         assert self.varpos is not None
-        paramname = self.varpos.converter.parser_name
-        if self.varpos.converter.length:
-            if not self.fastcall:
-                self.codegen.add_include('pycore_tuple.h',
-                                        '_PyTuple_ITEMS()')
-            start = 'args' if self.fastcall else '_PyTuple_ITEMS(args)'
-            size = 'nargs' if self.fastcall else 'PyTuple_GET_SIZE(args)'
-            if self.max_pos:
-                if min(self.pos_only, self.min_pos) < self.max_pos:
-                    start = f'{size} > {self.max_pos} ? {start} + {self.max_pos} : {start}'
-                    size = f'Py_MAX(0, {size} - {self.max_pos})'
-                else:
-                    start = f'{start} + {self.max_pos}'
-                    size = f'{size} - {self.max_pos}'
-            return f"""
-                {paramname} = {start};
-                {self.varpos.converter.length_name} = {size};
-                """
-
-        if self.fastcall:
-            if self.limited_capi:
-                if min(self.pos_only, self.min_pos) < self.max_pos:
-                    size = f'Py_MAX(nargs - {self.max_pos}, 0)'
-                else:
-                    size = f'nargs - {self.max_pos}' if self.max_pos else 'nargs'
-                return f"""
-                    {paramname} = PyTuple_New({size});
-                    if (!{paramname}) {{{{
-                        goto exit;
-                    }}}}
-                    for (Py_ssize_t i = {self.max_pos}; i < nargs; ++i) {{{{
-                        PyTuple_SET_ITEM({paramname}, i - {self.max_pos}, Py_NewRef(args[i]));
-                    }}}}
-                    """
-            else:
-                self.codegen.add_include('pycore_tuple.h',
-                                         '_PyTuple_FromArray()')
-                if min(self.pos_only, self.min_pos) < self.max_pos:
-                    return f"""
-                        {paramname} = nargs > {self.max_pos}
-                            ? _PyTuple_FromArray(args + {self.max_pos}, nargs - {self.max_pos})
-                            : PyTuple_New(0);
-                        if ({paramname} == NULL) {{{{
-                            goto exit;
-                        }}}}
-                        """
-                else:
-                    start = f'args + {self.max_pos}' if self.max_pos else 'args'
-                    size = f'nargs - {self.max_pos}' if self.max_pos else 'nargs'
-                    return f"""
-                        {paramname} = _PyTuple_FromArray({start}, {size});
-                        if ({paramname} == NULL) {{{{
-                            goto exit;
-                        }}}}
-                        """
-        else:
-            if self.max_pos:
-                return f"""
-                    {paramname} = PyTuple_GetSlice(args, {self.max_pos}, PY_SSIZE_T_MAX);
-                    if (!{paramname}) {{{{
-                        goto exit;
-                    }}}}
-                    """
-            else:
-                return f"{paramname} = Py_NewRef(args);\n"
+        c = self.varpos.converter
+        assert isinstance(c, libclinic.converters.VarPosCConverter)
+        return c.parse_vararg(pos_only=self.pos_only,
+                              min_pos=self.min_pos,
+                              max_pos=self.max_pos,
+                              fastcall=self.fastcall,
+                              limited_capi=self.limited_capi)
 
     def parse_pos_only(self) -> None:
         if self.fastcall:
@@ -839,7 +781,10 @@ class ParseArgsCodeGen:
     def copy_includes(self) -> None:
         # Copy includes from parameters to Clinic after parse_arg()
         # has been called above.
-        for converter in self.converters:
+        converters = self.converters
+        if self.varpos:
+            converters = converters + [self.varpos.converter]
+        for converter in converters:
             for include in converter.get_includes():
                 self.codegen.add_include(
                     include.filename,