diff options
author | Tomas R <tomas.roun8@gmail.com> | 2024-09-18 17:28:22 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-18 17:28:22 (GMT) |
commit | 21d2a9ab2f4dcbf1be462d3b7f7a231a46bc1cb7 (patch) | |
tree | 5bb4398ecb1cd8325d109d00878b60da8e29adfd /Parser | |
parent | f9fa6ba4f8d90ae12bc1f6a792d66903bb169ba8 (diff) | |
download | cpython-21d2a9ab2f4dcbf1be462d3b7f7a231a46bc1cb7.zip cpython-21d2a9ab2f4dcbf1be462d3b7f7a231a46bc1cb7.tar.gz cpython-21d2a9ab2f4dcbf1be462d3b7f7a231a46bc1cb7.tar.bz2 |
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>
Diffstat (limited to 'Parser')
-rwxr-xr-x | Parser/asdl_c.py | 222 |
1 files changed, 222 insertions, 0 deletions
diff --git a/Parser/asdl_c.py b/Parser/asdl_c.py index 9fed69b..fac9a77 100755 --- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -1435,8 +1435,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}, |