mirror of https://github.com/python/cpython
gh-122943: Move code generation for var-positional parameter to converters (GH-126575)
This commit is contained in:
parent
403410fa1b
commit
ee0746af7d
|
@ -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};
|
||||
"""
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue