summaryrefslogtreecommitdiffstats
path: root/Tools/clinic/libclinic
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2024-11-08 12:12:15 (GMT)
committerGitHub <noreply@github.com>2024-11-08 12:12:15 (GMT)
commitee0746af7d7cfc6cc25441726034e4fea4bcf7e5 (patch)
treed78b24545814d940f1f42cbb0f79975f47bf9565 /Tools/clinic/libclinic
parent403410fa1be036214efa7955127911e5592910db (diff)
downloadcpython-ee0746af7d7cfc6cc25441726034e4fea4bcf7e5.zip
cpython-ee0746af7d7cfc6cc25441726034e4fea4bcf7e5.tar.gz
cpython-ee0746af7d7cfc6cc25441726034e4fea4bcf7e5.tar.bz2
gh-122943: Move code generation for var-positional parameter to converters (GH-126575)
Diffstat (limited to 'Tools/clinic/libclinic')
-rw-r--r--Tools/clinic/libclinic/converters.py87
-rw-r--r--Tools/clinic/libclinic/parse_args.py77
2 files changed, 91 insertions, 73 deletions
diff --git a/Tools/clinic/libclinic/converters.py b/Tools/clinic/libclinic/converters.py
index 860ff81..a65f73b 100644
--- a/Tools/clinic/libclinic/converters.py
+++ b/Tools/clinic/libclinic/converters.py
@@ -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};
+ """
diff --git a/Tools/clinic/libclinic/parse_args.py b/Tools/clinic/libclinic/parse_args.py
index 2ce4e75..08cf697 100644
--- a/Tools/clinic/libclinic/parse_args.py
+++ b/Tools/clinic/libclinic/parse_args.py
@@ -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,