GitHub Viewer
#include
#include "Python.h"
#include "Python-ast.h"
static PyObject *_str_open_br;
static PyObject *_str_dbl_open_br;
static PyObject *_str_close_br;
static PyObject *_str_dbl_close_br;
/* Forward declarations for recursion via helper functions. */
static PyObject *
expr_as_unicode(expr_ty e, int level);
static int
append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, int level);
static int
append_joinedstr(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec);
static int
append_formattedvalue(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec);
static int
append_ast_slice(_PyUnicodeWriter *writer, slice_ty slice);
static int
append_charp(_PyUnicodeWriter *writer, const char *charp)
{
return _PyUnicodeWriter_WriteASCIIString(writer, charp, -1);
}
#define APPEND_STR_FINISH(str) do { \
return append_charp(writer, (str)); \
} while (0)
#define APPEND_STR(str) do { \
if (-1 == append_charp(writer, (str))) { \
return -1; \
} \
} while (0)
#define APPEND_STR_IF(cond, str) do { \
if ((cond) && -1 == append_charp(writer, (str))) { \
return -1; \
} \
} while (0)
#define APPEND_STR_IF_NOT_FIRST(str) do { \
APPEND_STR_IF(!first, (str)); \
first = false; \
} while (0)
#define APPEND_EXPR(expr, pr) do { \
if (-1 == append_ast_expr(writer, (expr), (pr))) { \
return -1; \
} \
} while (0)
#define APPEND(type, value) do { \
if (-1 == append_ast_ ## type(writer, (value))) { \
return -1; \
} \
} while (0)
static int
append_repr(_PyUnicodeWriter *writer, PyObject *obj)
{
int ret;
PyObject *repr;
repr = PyObject_Repr(obj);
if (!repr) {
return -1;
}
ret = _PyUnicodeWriter_WriteStr(writer, repr);
Py_DECREF(repr);
return ret;
}
/* Priority levels */
enum {
PR_TUPLE,
PR_TEST, /* 'if'-'else', 'lambda' */
PR_OR, /* 'or' */
PR_AND, /* 'and' */
PR_NOT, /* 'not' */
PR_CMP, /* '', '==', '>=', 'v.Attribute.value->kind == Num_kind ||
e->v.Attribute.value->kind == Constant_kind)
{
period = " .";
}
else {
period = ".";
}
APPEND_STR(period);
return _PyUnicodeWriter_WriteStr(writer, e->v.Attribute.attr);
}
static int
append_ast_simple_slice(_PyUnicodeWriter *writer, slice_ty slice)
{
if (slice->v.Slice.lower) {
APPEND_EXPR(slice->v.Slice.lower, PR_TEST);
}
APPEND_STR(":");
if (slice->v.Slice.upper) {
APPEND_EXPR(slice->v.Slice.upper, PR_TEST);
}
if (slice->v.Slice.step) {
APPEND_STR(":");
APPEND_EXPR(slice->v.Slice.step, PR_TEST);
}
return 0;
}
static int
append_ast_ext_slice(_PyUnicodeWriter *writer, slice_ty slice)
{
Py_ssize_t i, dims_count;
dims_count = asdl_seq_LEN(slice->v.ExtSlice.dims);
for (i = 0; i < dims_count; i++) {
APPEND_STR_IF(i > 0, ", ");
APPEND(slice, (slice_ty)asdl_seq_GET(slice->v.ExtSlice.dims, i));
}
return 0;
}
static int
append_ast_slice(_PyUnicodeWriter *writer, slice_ty slice)
{
switch (slice->kind) {
case Slice_kind:
return append_ast_simple_slice(writer, slice);
case ExtSlice_kind:
return append_ast_ext_slice(writer, slice);
case Index_kind:
APPEND_EXPR(slice->v.Index.value, PR_TUPLE);
return 0;
default:
PyErr_SetString(PyExc_SystemError,
"unexpected slice kind");
return -1;
}
}
static int
append_ast_subscript(_PyUnicodeWriter *writer, expr_ty e)
{
APPEND_EXPR(e->v.Subscript.value, PR_ATOM);
APPEND_STR("[");
APPEND(slice, e->v.Subscript.slice);
APPEND_STR_FINISH("]");
}
static int
append_ast_starred(_PyUnicodeWriter *writer, expr_ty e)
{
APPEND_STR("*");
APPEND_EXPR(e->v.Starred.value, PR_EXPR);
return 0;
}
static int
append_ast_yield(_PyUnicodeWriter *writer, expr_ty e)
{
if (!e->v.Yield.value) {
APPEND_STR_FINISH("(yield)");
}
APPEND_STR("(yield ");
APPEND_EXPR(e->v.Yield.value, PR_TEST);
APPEND_STR_FINISH(")");
}
static int
append_ast_yield_from(_PyUnicodeWriter *writer, expr_ty e)
{
APPEND_STR("(yield from ");
APPEND_EXPR(e->v.YieldFrom.value, PR_TEST);
APPEND_STR_FINISH(")");
}
static int
append_ast_await(_PyUnicodeWriter *writer, expr_ty e, int level)
{
APPEND_STR_IF(level > PR_AWAIT, "(");
APPEND_STR("await ");
APPEND_EXPR(e->v.Await.value, PR_ATOM);
APPEND_STR_IF(level > PR_AWAIT, ")");
return 0;
}
static int
append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, int level)
{
switch (e->kind) {
case BoolOp_kind:
return append_ast_boolop(writer, e, level);
case BinOp_kind:
return append_ast_binop(writer, e, level);
case UnaryOp_kind:
return append_ast_unaryop(writer, e, level);
case Lambda_kind:
return append_ast_lambda(writer, e, level);
case IfExp_kind:
return append_ast_ifexp(writer, e, level);
case Dict_kind:
return append_ast_dict(writer, e);
case Set_kind:
return append_ast_set(writer, e);
case GeneratorExp_kind:
return append_ast_genexp(writer, e);
case ListComp_kind:
return append_ast_listcomp(writer, e);
case SetComp_kind:
return append_ast_setcomp(writer, e);
case DictComp_kind:
return append_ast_dictcomp(writer, e);
case Yield_kind:
return append_ast_yield(writer, e);
case YieldFrom_kind:
return append_ast_yield_from(writer, e);
case Await_kind:
return append_ast_await(writer, e, level);
case Compare_kind:
return append_ast_compare(writer, e, level);
case Call_kind:
return append_ast_call(writer, e);
case Constant_kind:
return append_repr(writer, e->v.Constant.value);
case Num_kind:
return append_repr(writer, e->v.Num.n);
case Str_kind:
return append_repr(writer, e->v.Str.s);
case JoinedStr_kind:
return append_joinedstr(writer, e, false);
case FormattedValue_kind:
return append_formattedvalue(writer, e, false);
case Bytes_kind:
return append_repr(writer, e->v.Bytes.s);
case Ellipsis_kind:
APPEND_STR_FINISH("...");
case NameConstant_kind:
return append_repr(writer, e->v.NameConstant.value);
/* The following exprs can be assignment targets. */
case Attribute_kind:
return append_ast_attribute(writer, e);
case Subscript_kind:
return append_ast_subscript(writer, e);
case Starred_kind:
return append_ast_starred(writer, e);
case Name_kind:
return _PyUnicodeWriter_WriteStr(writer, e->v.Name.id);
case List_kind:
return append_ast_list(writer, e);
case Tuple_kind:
return append_ast_tuple(writer, e, level);
default:
PyErr_SetString(PyExc_SystemError,
"unknown expression kind");
return -1;
}
}
static int
maybe_init_static_strings(void)
{
if (!_str_open_br &&
!(_str_open_br = PyUnicode_InternFromString("{"))) {
return -1;
}
if (!_str_dbl_open_br &&
!(_str_dbl_open_br = PyUnicode_InternFromString("{{"))) {
return -1;
}
if (!_str_close_br &&
!(_str_close_br = PyUnicode_InternFromString("}"))) {
return -1;
}
if (!_str_dbl_close_br &&
!(_str_dbl_close_br = PyUnicode_InternFromString("}}"))) {
return -1;
}
return 0;
}
static PyObject *
expr_as_unicode(expr_ty e, int level)
{
_PyUnicodeWriter writer;
_PyUnicodeWriter_Init(&writer);
writer.min_length = 256;
writer.overallocate = 1;
if (-1 == maybe_init_static_strings() ||
-1 == append_ast_expr(&writer, e, level))
{
_PyUnicodeWriter_Dealloc(&writer);
return NULL;
}
return _PyUnicodeWriter_Finish(&writer);
}
PyObject *
_PyAST_ExprAsUnicode(expr_ty e)
{
return expr_as_unicode(e, PR_TEST);
}