mirror of
https://github.com/python/cpython.git
synced 2025-07-08 03:45:36 +00:00
gh-116022: Improve repr()
of AST nodes (#117046)
Co-authored-by: AN Long <aisk@users.noreply.github.com> Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com> Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com>
This commit is contained in:
parent
f9fa6ba4f8
commit
21d2a9ab2f
7 changed files with 682 additions and 2 deletions
222
Python/Python-ast.c
generated
222
Python/Python-ast.c
generated
|
@ -5636,8 +5636,230 @@ static PyGetSetDef ast_type_getsets[] = {
|
|||
{NULL}
|
||||
};
|
||||
|
||||
static PyObject *
|
||||
ast_repr_max_depth(AST_object *self, int depth);
|
||||
|
||||
/* Format list and tuple properties of AST nodes.
|
||||
Note that, only the first and last elements are shown.
|
||||
Anything in between is represented with an ellipsis ('...').
|
||||
For example, the list [1, 2, 3] is formatted as
|
||||
'List(elts=[Constant(1), ..., Constant(3)])'. */
|
||||
static PyObject *
|
||||
ast_repr_list(PyObject *list, int depth)
|
||||
{
|
||||
assert(PyList_Check(list) || PyTuple_Check(list));
|
||||
|
||||
struct ast_state *state = get_ast_state();
|
||||
if (state == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_ssize_t length = PySequence_Size(list);
|
||||
if (length < 0) {
|
||||
return NULL;
|
||||
}
|
||||
else if (length == 0) {
|
||||
return PyObject_Repr(list);
|
||||
}
|
||||
|
||||
_PyUnicodeWriter writer;
|
||||
_PyUnicodeWriter_Init(&writer);
|
||||
writer.overallocate = 1;
|
||||
PyObject *items[2] = {NULL, NULL};
|
||||
|
||||
items[0] = PySequence_GetItem(list, 0);
|
||||
if (!items[0]) {
|
||||
goto error;
|
||||
}
|
||||
if (length > 1) {
|
||||
items[1] = PySequence_GetItem(list, length - 1);
|
||||
if (!items[1]) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
bool is_list = PyList_Check(list);
|
||||
if (_PyUnicodeWriter_WriteChar(&writer, is_list ? '[' : '(') < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (Py_ssize_t i = 0; i < Py_MIN(length, 2); i++) {
|
||||
PyObject *item = items[i];
|
||||
PyObject *item_repr;
|
||||
|
||||
if (PyType_IsSubtype(Py_TYPE(item), (PyTypeObject *)state->AST_type)) {
|
||||
item_repr = ast_repr_max_depth((AST_object*)item, depth - 1);
|
||||
} else {
|
||||
item_repr = PyObject_Repr(item);
|
||||
}
|
||||
if (!item_repr) {
|
||||
goto error;
|
||||
}
|
||||
if (i > 0) {
|
||||
if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (_PyUnicodeWriter_WriteStr(&writer, item_repr) < 0) {
|
||||
Py_DECREF(item_repr);
|
||||
goto error;
|
||||
}
|
||||
if (i == 0 && length > 2) {
|
||||
if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ...", 5) < 0) {
|
||||
Py_DECREF(item_repr);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
Py_DECREF(item_repr);
|
||||
}
|
||||
|
||||
if (_PyUnicodeWriter_WriteChar(&writer, is_list ? ']' : ')') < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
Py_XDECREF(items[0]);
|
||||
Py_XDECREF(items[1]);
|
||||
return _PyUnicodeWriter_Finish(&writer);
|
||||
|
||||
error:
|
||||
Py_XDECREF(items[0]);
|
||||
Py_XDECREF(items[1]);
|
||||
_PyUnicodeWriter_Dealloc(&writer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
ast_repr_max_depth(AST_object *self, int depth)
|
||||
{
|
||||
struct ast_state *state = get_ast_state();
|
||||
if (state == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (depth <= 0) {
|
||||
return PyUnicode_FromFormat("%s(...)", Py_TYPE(self)->tp_name);
|
||||
}
|
||||
|
||||
int status = Py_ReprEnter((PyObject *)self);
|
||||
if (status != 0) {
|
||||
if (status < 0) {
|
||||
return NULL;
|
||||
}
|
||||
return PyUnicode_FromFormat("%s(...)", Py_TYPE(self)->tp_name);
|
||||
}
|
||||
|
||||
PyObject *fields;
|
||||
if (PyObject_GetOptionalAttr((PyObject *)Py_TYPE(self), state->_fields, &fields) < 0) {
|
||||
Py_ReprLeave((PyObject *)self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Py_ssize_t numfields = PySequence_Size(fields);
|
||||
if (numfields < 0) {
|
||||
Py_ReprLeave((PyObject *)self);
|
||||
Py_DECREF(fields);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (numfields == 0) {
|
||||
Py_ReprLeave((PyObject *)self);
|
||||
Py_DECREF(fields);
|
||||
return PyUnicode_FromFormat("%s()", Py_TYPE(self)->tp_name);
|
||||
}
|
||||
|
||||
const char* tp_name = Py_TYPE(self)->tp_name;
|
||||
_PyUnicodeWriter writer;
|
||||
_PyUnicodeWriter_Init(&writer);
|
||||
writer.overallocate = 1;
|
||||
|
||||
if (_PyUnicodeWriter_WriteASCIIString(&writer, tp_name, strlen(tp_name)) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (_PyUnicodeWriter_WriteChar(&writer, '(') < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
for (Py_ssize_t i = 0; i < numfields; i++) {
|
||||
PyObject *name = PySequence_GetItem(fields, i);
|
||||
if (!name) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
PyObject *value = PyObject_GetAttr((PyObject *)self, name);
|
||||
if (!value) {
|
||||
Py_DECREF(name);
|
||||
goto error;
|
||||
}
|
||||
|
||||
PyObject *value_repr;
|
||||
if (PyList_Check(value) || PyTuple_Check(value)) {
|
||||
value_repr = ast_repr_list(value, depth);
|
||||
}
|
||||
else if (PyType_IsSubtype(Py_TYPE(value), (PyTypeObject *)state->AST_type)) {
|
||||
value_repr = ast_repr_max_depth((AST_object*)value, depth - 1);
|
||||
}
|
||||
else {
|
||||
value_repr = PyObject_Repr(value);
|
||||
}
|
||||
|
||||
Py_DECREF(value);
|
||||
|
||||
if (!value_repr) {
|
||||
Py_DECREF(name);
|
||||
Py_DECREF(value);
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0) {
|
||||
Py_DECREF(name);
|
||||
Py_DECREF(value_repr);
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
if (_PyUnicodeWriter_WriteStr(&writer, name) < 0) {
|
||||
Py_DECREF(name);
|
||||
Py_DECREF(value_repr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
Py_DECREF(name);
|
||||
|
||||
if (_PyUnicodeWriter_WriteChar(&writer, '=') < 0) {
|
||||
Py_DECREF(value_repr);
|
||||
goto error;
|
||||
}
|
||||
if (_PyUnicodeWriter_WriteStr(&writer, value_repr) < 0) {
|
||||
Py_DECREF(value_repr);
|
||||
goto error;
|
||||
}
|
||||
|
||||
Py_DECREF(value_repr);
|
||||
}
|
||||
|
||||
if (_PyUnicodeWriter_WriteChar(&writer, ')') < 0) {
|
||||
goto error;
|
||||
}
|
||||
Py_ReprLeave((PyObject *)self);
|
||||
Py_DECREF(fields);
|
||||
return _PyUnicodeWriter_Finish(&writer);
|
||||
|
||||
error:
|
||||
Py_ReprLeave((PyObject *)self);
|
||||
Py_DECREF(fields);
|
||||
_PyUnicodeWriter_Dealloc(&writer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
ast_repr(AST_object *self)
|
||||
{
|
||||
return ast_repr_max_depth(self, 3);
|
||||
}
|
||||
|
||||
static PyType_Slot AST_type_slots[] = {
|
||||
{Py_tp_dealloc, ast_dealloc},
|
||||
{Py_tp_repr, ast_repr},
|
||||
{Py_tp_getattro, PyObject_GenericGetAttr},
|
||||
{Py_tp_setattro, PyObject_GenericSetAttr},
|
||||
{Py_tp_traverse, ast_traverse},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue