Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ee0746a

Browse files
gh-122943: Move code generation for var-positional parameter to converters (GH-126575)
1 parent 403410f commit ee0746a

File tree

2 files changed

+91
-73
lines changed

2 files changed

+91
-73
lines changed

Tools/clinic/libclinic/converters.py

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1232,22 +1232,95 @@ def set_template_dict(self, template_dict: TemplateDict) -> None:
12321232

12331233
# Converters for var-positional parameter.
12341234

1235-
class varpos_tuple_converter(CConverter):
1235+
class VarPosCConverter(CConverter):
1236+
format_unit = ''
1237+
1238+
def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None:
1239+
raise AssertionError('should never be called')
1240+
1241+
def parse_vararg(self, *, pos_only: int, min_pos: int, max_pos: int,
1242+
fastcall: bool, limited_capi: bool) -> str:
1243+
raise NotImplementedError
1244+
1245+
1246+
class varpos_tuple_converter(VarPosCConverter):
12361247
type = 'PyObject *'
12371248
format_unit = ''
12381249
c_default = 'NULL'
12391250

12401251
def cleanup(self) -> str:
12411252
return f"""Py_XDECREF({self.parser_name});\n"""
12421253

1243-
def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None:
1244-
raise AssertionError('should never be called')
1254+
def parse_vararg(self, *, pos_only: int, min_pos: int, max_pos: int,
1255+
fastcall: bool, limited_capi: bool) -> str:
1256+
paramname = self.parser_name
1257+
if fastcall:
1258+
if limited_capi:
1259+
if min(pos_only, min_pos) < max_pos:
1260+
size = f'Py_MAX(nargs - {max_pos}, 0)'
1261+
else:
1262+
size = f'nargs - {max_pos}' if max_pos else 'nargs'
1263+
return f"""
1264+
{paramname} = PyTuple_New({size});
1265+
if (!{paramname}) {{{{
1266+
goto exit;
1267+
}}}}
1268+
for (Py_ssize_t i = {max_pos}; i < nargs; ++i) {{{{
1269+
PyTuple_SET_ITEM({paramname}, i - {max_pos}, Py_NewRef(args[i]));
1270+
}}}}
1271+
"""
1272+
else:
1273+
self.add_include('pycore_tuple.h', '_PyTuple_FromArray()')
1274+
start = f'args + {max_pos}' if max_pos else 'args'
1275+
size = f'nargs - {max_pos}' if max_pos else 'nargs'
1276+
if min(pos_only, min_pos) < max_pos:
1277+
return f"""
1278+
{paramname} = nargs > {max_pos}
1279+
? _PyTuple_FromArray({start}, {size})
1280+
: PyTuple_New(0);
1281+
if ({paramname} == NULL) {{{{
1282+
goto exit;
1283+
}}}}
1284+
"""
1285+
else:
1286+
return f"""
1287+
{paramname} = _PyTuple_FromArray({start}, {size});
1288+
if ({paramname} == NULL) {{{{
1289+
goto exit;
1290+
}}}}
1291+
"""
1292+
else:
1293+
if max_pos:
1294+
return f"""
1295+
{paramname} = PyTuple_GetSlice(args, {max_pos}, PY_SSIZE_T_MAX);
1296+
if (!{paramname}) {{{{
1297+
goto exit;
1298+
}}}}
1299+
"""
1300+
else:
1301+
return f"{paramname} = Py_NewRef(args);\n"
12451302

1246-
class varpos_array_converter(CConverter):
1303+
1304+
class varpos_array_converter(VarPosCConverter):
12471305
type = 'PyObject * const *'
1248-
format_unit = ''
12491306
length = True
12501307
c_ignored_default = ''
12511308

1252-
def parse_arg(self, argname: str, displayname: str, *, limited_capi: bool) -> str | None:
1253-
raise AssertionError('should never be called')
1309+
def parse_vararg(self, *, pos_only: int, min_pos: int, max_pos: int,
1310+
fastcall: bool, limited_capi: bool) -> str:
1311+
paramname = self.parser_name
1312+
if not fastcall:
1313+
self.add_include('pycore_tuple.h', '_PyTuple_ITEMS()')
1314+
start = 'args' if fastcall else '_PyTuple_ITEMS(args)'
1315+
size = 'nargs' if fastcall else 'PyTuple_GET_SIZE(args)'
1316+
if max_pos:
1317+
if min(pos_only, min_pos) < max_pos:
1318+
start = f'{size} > {max_pos} ? {start} + {max_pos} : {start}'
1319+
size = f'Py_MAX(0, {size} - {max_pos})'
1320+
else:
1321+
start = f'{start} + {max_pos}'
1322+
size = f'{size} - {max_pos}'
1323+
return f"""
1324+
{paramname} = {start};
1325+
{self.length_name} = {size};
1326+
"""

Tools/clinic/libclinic/parse_args.py

Lines changed: 11 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -452,71 +452,13 @@ def parse_option_groups(self) -> None:
452452

453453
def _parse_vararg(self) -> str:
454454
assert self.varpos is not None
455-
paramname = self.varpos.converter.parser_name
456-
if self.varpos.converter.length:
457-
if not self.fastcall:
458-
self.codegen.add_include('pycore_tuple.h',
459-
'_PyTuple_ITEMS()')
460-
start = 'args' if self.fastcall else '_PyTuple_ITEMS(args)'
461-
size = 'nargs' if self.fastcall else 'PyTuple_GET_SIZE(args)'
462-
if self.max_pos:
463-
if min(self.pos_only, self.min_pos) < self.max_pos:
464-
start = f'{size} > {self.max_pos} ? {start} + {self.max_pos} : {start}'
465-
size = f'Py_MAX(0, {size} - {self.max_pos})'
466-
else:
467-
start = f'{start} + {self.max_pos}'
468-
size = f'{size} - {self.max_pos}'
469-
return f"""
470-
{paramname} = {start};
471-
{self.varpos.converter.length_name} = {size};
472-
"""
473-
474-
if self.fastcall:
475-
if self.limited_capi:
476-
if min(self.pos_only, self.min_pos) < self.max_pos:
477-
size = f'Py_MAX(nargs - {self.max_pos}, 0)'
478-
else:
479-
size = f'nargs - {self.max_pos}' if self.max_pos else 'nargs'
480-
return f"""
481-
{paramname} = PyTuple_New({size});
482-
if (!{paramname}) {{{{
483-
goto exit;
484-
}}}}
485-
for (Py_ssize_t i = {self.max_pos}; i < nargs; ++i) {{{{
486-
PyTuple_SET_ITEM({paramname}, i - {self.max_pos}, Py_NewRef(args[i]));
487-
}}}}
488-
"""
489-
else:
490-
self.codegen.add_include('pycore_tuple.h',
491-
'_PyTuple_FromArray()')
492-
if min(self.pos_only, self.min_pos) < self.max_pos:
493-
return f"""
494-
{paramname} = nargs > {self.max_pos}
495-
? _PyTuple_FromArray(args + {self.max_pos}, nargs - {self.max_pos})
496-
: PyTuple_New(0);
497-
if ({paramname} == NULL) {{{{
498-
goto exit;
499-
}}}}
500-
"""
501-
else:
502-
start = f'args + {self.max_pos}' if self.max_pos else 'args'
503-
size = f'nargs - {self.max_pos}' if self.max_pos else 'nargs'
504-
return f"""
505-
{paramname} = _PyTuple_FromArray({start}, {size});
506-
if ({paramname} == NULL) {{{{
507-
goto exit;
508-
}}}}
509-
"""
510-
else:
511-
if self.max_pos:
512-
return f"""
513-
{paramname} = PyTuple_GetSlice(args, {self.max_pos}, PY_SSIZE_T_MAX);
514-
if (!{paramname}) {{{{
515-
goto exit;
516-
}}}}
517-
"""
518-
else:
519-
return f"{paramname} = Py_NewRef(args);\n"
455+
c = self.varpos.converter
456+
assert isinstance(c, libclinic.converters.VarPosCConverter)
457+
return c.parse_vararg(pos_only=self.pos_only,
458+
min_pos=self.min_pos,
459+
max_pos=self.max_pos,
460+
fastcall=self.fastcall,
461+
limited_capi=self.limited_capi)
520462

521463
def parse_pos_only(self) -> None:
522464
if self.fastcall:
@@ -839,7 +781,10 @@ def parse_general(self, clang: CLanguage) -> None:
839781
def copy_includes(self) -> None:
840782
# Copy includes from parameters to Clinic after parse_arg()
841783
# has been called above.
842-
for converter in self.converters:
784+
converters = self.converters
785+
if self.varpos:
786+
converters = converters + [self.varpos.converter]
787+
for converter in converters:
843788
for include in converter.get_includes():
844789
self.codegen.add_include(
845790
include.filename,

0 commit comments

Comments
 (0)