diff options
author | Guido van Rossum <guido@python.org> | 2018-01-26 16:20:18 (GMT) |
---|---|---|
committer | Ćukasz Langa <lukasz@langa.pl> | 2018-01-26 16:20:18 (GMT) |
commit | 95e4d589137260530e18ef98a2ed84ee3ec57e12 (patch) | |
tree | 9d0c3bc48158e9f0c83f1b9cb509c1fbebd9cfde /Python/ast_unparse.c | |
parent | d7773d92bd11640a8c950d6c36a9cef1cee36f96 (diff) | |
download | cpython-95e4d589137260530e18ef98a2ed84ee3ec57e12.zip cpython-95e4d589137260530e18ef98a2ed84ee3ec57e12.tar.gz cpython-95e4d589137260530e18ef98a2ed84ee3ec57e12.tar.bz2 |
String annotations [PEP 563] (#4390)
* Document `from __future__ import annotations`
* Provide plumbing and tests for `from __future__ import annotations`
* Implement unparsing the AST back to string form
This is required for PEP 563 and as such only implements a part of the
unparsing process that covers expressions.
Diffstat (limited to 'Python/ast_unparse.c')
-rw-r--r-- | Python/ast_unparse.c | 1163 |
1 files changed, 1163 insertions, 0 deletions
diff --git a/Python/ast_unparse.c b/Python/ast_unparse.c new file mode 100644 index 0000000..ef9e948 --- /dev/null +++ b/Python/ast_unparse.c @@ -0,0 +1,1163 @@ +#include <stdbool.h> +#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, bool omit_parens); +static int +append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens); +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_charp(_PyUnicodeWriter *writer, const char *charp) +{ + return _PyUnicodeWriter_WriteASCIIString(writer, charp, -1); +} + +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; +} + +static int +append_ast_boolop(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens) +{ + Py_ssize_t i, value_count; + asdl_seq *values; + + if (!omit_parens && -1 == append_charp(writer, "(")) { + return -1; + } + + values = e->v.BoolOp.values; + value_count = asdl_seq_LEN(values) - 1; + assert(value_count >= 0); + + if (-1 == append_ast_expr(writer, + (expr_ty)asdl_seq_GET(values, 0), + false)) { + return -1; + } + + const char *op = (e->v.BoolOp.op == And) ? " and " : " or "; + for (i = 1; i <= value_count; ++i) { + if (-1 == append_charp(writer, op)) { + return -1; + } + + if (-1 == append_ast_expr(writer, + (expr_ty)asdl_seq_GET(values, i), + false)) { + return -1; + } + } + + return omit_parens ? 0 : append_charp(writer, ")"); +} + +static int +append_ast_binop(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens) +{ + const char *op; + + if (!omit_parens && -1 == append_charp(writer, "(")) { + return -1; + } + + if (-1 == append_ast_expr(writer, e->v.BinOp.left, false)) { + return -1; + } + + switch(e->v.BinOp.op) { + case Add: op = " + "; break; + case Sub: op = " - "; break; + case Mult: op = " * "; break; + case MatMult: op = " @ "; break; + case Div: op = " / "; break; + case Mod: op = " % "; break; + case LShift: op = " << "; break; + case RShift: op = " >> "; break; + case BitOr: op = " | "; break; + case BitXor: op = " ^ "; break; + case BitAnd: op = " & "; break; + case FloorDiv: op = " // "; break; + case Pow: op = " ** "; break; + } + + if (-1 == append_charp(writer, op)) { + return -1; + } + + if (-1 == append_ast_expr(writer, e->v.BinOp.right, false)) { + return -1; + } + + return omit_parens ? 0 : append_charp(writer, ")"); +} + +static int +append_ast_unaryop(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens) +{ + const char *op; + + if (!omit_parens && -1 == append_charp(writer, "(")) { + return -1; + } + + switch(e->v.UnaryOp.op) { + case Invert: op = "~"; break; + case Not: op = "not "; break; + case UAdd: op = "+"; break; + case USub: op = "-"; break; + } + + if (-1 == append_charp(writer, op)) { + return -1; + } + + if (-1 == append_ast_expr(writer, e->v.UnaryOp.operand, false)) { + return -1; + } + + return omit_parens ? 0 : append_charp(writer, ")"); +} + +static int +append_ast_arg(_PyUnicodeWriter *writer, arg_ty arg) +{ + if (-1 == _PyUnicodeWriter_WriteStr(writer, arg->arg)) { + return -1; + } + if (arg->annotation) { + if (-1 == append_charp(writer, ": ")) { + return -1; + } + if (-1 == append_ast_expr(writer, arg->annotation, true)) { + return -1; + } + } + return 0; +} + +static int +append_ast_args(_PyUnicodeWriter *writer, arguments_ty args) +{ + bool first; + Py_ssize_t i, di, arg_count, default_count; + arg_ty arg; + expr_ty default_; + + first = true; + + /* positional arguments with defaults */ + arg_count = asdl_seq_LEN(args->args); + default_count = asdl_seq_LEN(args->defaults); + for (i = 0; i < arg_count; i++) { + if (first) { + first = false; + } + else if (-1 == append_charp(writer, ", ")) { + return -1; + } + + arg = (arg_ty)asdl_seq_GET(args->args, i); + if (-1 == append_ast_arg(writer, arg)) { + return -1; + } + + di = i - arg_count + default_count; + if (di >= 0) { + if (-1 == append_charp(writer, "=")) { + return -1; + } + default_ = (expr_ty)asdl_seq_GET(args->defaults, di); + if (-1 == append_ast_expr(writer, default_, false)) { + return -1; + } + } + } + + /* vararg, or bare '*' if no varargs but keyword-only arguments present */ + if (args->vararg || args->kwonlyargs) { + if (first) { + first = false; + } + else if (-1 == append_charp(writer, ", ")) { + return -1; + } + + if (-1 == append_charp(writer, "*")) { + return -1; + } + + if (args->vararg) { + if (-1 == append_ast_arg(writer, args->vararg)) { + return -1; + } + } + } + + /* keyword-only arguments */ + arg_count = asdl_seq_LEN(args->kwonlyargs); + default_count = asdl_seq_LEN(args->kw_defaults); + for (i = 0; i < arg_count; i++) { + if (first) { + first = false; + } + else if (-1 == append_charp(writer, ", ")) { + return -1; + } + + arg = (arg_ty)asdl_seq_GET(args->kwonlyargs, i); + if (-1 == append_ast_arg(writer, arg)) { + return -1; + } + + di = i - arg_count + default_count; + if (di >= 0) { + if (-1 == append_charp(writer, "=")) { + return -1; + } + default_ = (expr_ty)asdl_seq_GET(args->kw_defaults, di); + if (-1 == append_ast_expr(writer, default_, false)) { + return -1; + } + } + } + + /* **kwargs */ + if (args->kwarg) { + if (first) { + first = false; + } + else if (-1 == append_charp(writer, ", ")) { + return -1; + } + + if (-1 == append_charp(writer, "**")) { + return -1; + } + + if (-1 == append_ast_arg(writer, args->kwarg)) { + return -1; + } + } + + return 0; +} + +static int +append_ast_lambda(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens) +{ + if (!omit_parens && -1 == append_charp(writer, "(")) { + return -1; + } + + if (-1 == append_charp(writer, "lambda ")) { + return -1; + } + + if (-1 == append_ast_args(writer, e->v.Lambda.args)) { + return -1; + } + + if (-1 == append_charp(writer, ": ")) { + return -1; + } + + if (-1 == append_ast_expr(writer, e->v.Lambda.body, true)) { + return -1; + } + + return omit_parens ? 0 : append_charp(writer, ")"); +} + +static int +append_ast_ifexp(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens) +{ + if (!omit_parens && -1 == append_charp(writer, "(")) { + return -1; + } + + if (-1 == append_ast_expr(writer, e->v.IfExp.body, false)) { + return -1; + } + + if (-1 == append_charp(writer, " if ")) { + return -1; + } + + if (-1 == append_ast_expr(writer, e->v.IfExp.test, false)) { + return -1; + } + + if (-1 == append_charp(writer, " else ")) { + return -1; + } + + if (-1 == append_ast_expr(writer, e->v.IfExp.orelse, false)) { + return -1; + } + + return omit_parens ? 0 : append_charp(writer, ")"); +} + +static int +append_ast_dict(_PyUnicodeWriter *writer, expr_ty e) +{ + Py_ssize_t i, value_count; + expr_ty key_node, value_node; + + if (-1 == append_charp(writer, "{")) { + return -1; + } + + value_count = asdl_seq_LEN(e->v.Dict.values); + + for (i = 0; i < value_count; i++) { + if (i > 0 && -1 == append_charp(writer, ", ")) { + return -1; + } + key_node = (expr_ty)asdl_seq_GET(e->v.Dict.keys, i); + if (key_node != NULL) { + if (-1 == append_ast_expr(writer, key_node, false)) { + return -1; + } + + if (-1 == append_charp(writer, ": ")) { + return -1; + } + } + else if (-1 == append_charp(writer, "**")) { + return -1; + } + + value_node = (expr_ty)asdl_seq_GET(e->v.Dict.values, i); + if (-1 == append_ast_expr(writer, value_node, false)) { + return -1; + } + } + + return append_charp(writer, "}"); +} + +static int +append_ast_set(_PyUnicodeWriter *writer, expr_ty e) +{ + Py_ssize_t i, elem_count; + expr_ty elem_node; + + if (-1 == append_charp(writer, "{")) { + return -1; + } + + elem_count = asdl_seq_LEN(e->v.Set.elts); + for (i = 0; i < elem_count; i++) { + if (i > 0 && -1 == append_charp(writer, ", ")) { + return -1; + } + + elem_node = (expr_ty)asdl_seq_GET(e->v.Set.elts, i); + if (-1 == append_ast_expr(writer, elem_node, false)) { + return -1; + } + } + + return append_charp(writer, "}"); +} + +static int +append_ast_list(_PyUnicodeWriter *writer, expr_ty e) +{ + Py_ssize_t i, elem_count; + expr_ty elem_node; + + if (-1 == append_charp(writer, "[")) { + return -1; + } + + elem_count = asdl_seq_LEN(e->v.List.elts); + for (i = 0; i < elem_count; i++) { + if (i > 0 && -1 == append_charp(writer, ", ")) { + return -1; + } + elem_node = (expr_ty)asdl_seq_GET(e->v.List.elts, i); + if (-1 == append_ast_expr(writer, elem_node, false)) { + return -1; + } + } + + return append_charp(writer, "]"); +} + +static int +append_ast_tuple(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens) +{ + Py_ssize_t i, elem_count; + expr_ty elem_node; + + elem_count = asdl_seq_LEN(e->v.Tuple.elts); + + if (!omit_parens || elem_count < 2) { + if (-1 == append_charp(writer, "(")) { + return -1; + } + } + + for (i = 0; i < elem_count; i++) { + if ((i > 0 || elem_count == 1) && -1 == append_charp(writer, ", ")) { + return -1; + } + elem_node = (expr_ty)asdl_seq_GET(e->v.Tuple.elts, i); + if (-1 == append_ast_expr(writer, elem_node, false)) { + return -1; + } + } + + if (!omit_parens || elem_count < 2) { + return append_charp(writer, ")"); + } + + return 0; +} + +static int +append_ast_comprehension(_PyUnicodeWriter *writer, comprehension_ty gen) +{ + Py_ssize_t i, if_count; + + if (-1 == append_charp(writer, gen->is_async ? " async for " : " for ")) { + return -1; + } + + if (-1 == append_ast_expr(writer, gen->target, true)) { + return -1; + } + + if (-1 == append_charp(writer, " in ")) { + return -1; + } + + if (-1 == append_ast_expr(writer, gen->iter, false)) { + return -1; + } + + if_count = asdl_seq_LEN(gen->ifs); + for (i = 0; i < if_count; i++) { + if (-1 == append_charp(writer, " if ")) { + return -1; + } + + if (-1 == append_ast_expr(writer, + (expr_ty)asdl_seq_GET(gen->ifs, i), + false)) { + return -1; + } + } + return 0; +} + +static int +append_ast_comprehensions(_PyUnicodeWriter *writer, asdl_seq *comprehensions) +{ + Py_ssize_t i, gen_count; + comprehension_ty comp_node; + gen_count = asdl_seq_LEN(comprehensions); + + for (i = 0; i < gen_count; i++) { + comp_node = (comprehension_ty)asdl_seq_GET(comprehensions, i); + if (-1 == append_ast_comprehension(writer, comp_node)) { + return -1; + } + } + + return 0; +} + +static int +append_ast_genexp(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens) +{ + if (!omit_parens && -1 == append_charp(writer, "(")) { + return -1; + } + + if (-1 == append_ast_expr(writer, e->v.GeneratorExp.elt, false)) { + return -1; + } + + if (-1 == append_ast_comprehensions(writer, e->v.GeneratorExp.generators)) { + return -1; + } + + return omit_parens ? 0 : append_charp(writer, ")"); +} + +static int +append_ast_listcomp(_PyUnicodeWriter *writer, expr_ty e) +{ + if (-1 == append_charp(writer, "[")) { + return -1; + } + + if (-1 == append_ast_expr(writer, e->v.ListComp.elt, false)) { + return -1; + } + + if (-1 == append_ast_comprehensions(writer, e->v.ListComp.generators)) { + return -1; + } + + return append_charp(writer, "]"); +} + +static int +append_ast_setcomp(_PyUnicodeWriter *writer, expr_ty e) +{ + if (-1 == append_charp(writer, "{")) { + return -1; + } + + if (-1 == append_ast_expr(writer, e->v.SetComp.elt, false)) { + return -1; + } + + if (-1 == append_ast_comprehensions(writer, e->v.SetComp.generators)) { + return -1; + } + + return append_charp(writer, "}"); +} + +static int +append_ast_dictcomp(_PyUnicodeWriter *writer, expr_ty e) +{ + if (-1 == append_charp(writer, "{")) { + return -1; + } + + if (-1 == append_ast_expr(writer, e->v.DictComp.key, false)) { + return -1; + } + + if (-1 == append_charp(writer, ": ")) { + return -1; + } + + if (-1 == append_ast_expr(writer, e->v.DictComp.value, false)) { + return -1; + } + + if (-1 == append_ast_comprehensions(writer, e->v.DictComp.generators)) { + return -1; + } + + return append_charp(writer, "}"); +} + +static int +append_ast_compare(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens) +{ + const char *op; + Py_ssize_t i, comparator_count; + asdl_seq *comparators; + asdl_int_seq *ops; + + if (!omit_parens && -1 == append_charp(writer, "(")) { + return -1; + } + + comparators = e->v.Compare.comparators; + ops = e->v.Compare.ops; + comparator_count = asdl_seq_LEN(comparators); + assert(comparator_count > 0); + assert(comparator_count == asdl_seq_LEN(ops)); + + if (-1 == append_ast_expr(writer, e->v.Compare.left, false)) { + return -1; + } + + for (i = 0; i < comparator_count; i++) { + switch ((cmpop_ty)asdl_seq_GET(ops, i)) { + case Eq: + op = " == "; + break; + case NotEq: + op = " != "; + break; + case Lt: + op = " < "; + break; + case LtE: + op = " <= "; + break; + case Gt: + op = " > "; + break; + case GtE: + op = " >= "; + break; + case Is: + op = " is "; + break; + case IsNot: + op = " is not "; + break; + case In: + op = " in "; + break; + case NotIn: + op = " not in "; + break; + default: + PyErr_SetString(PyExc_SystemError, + "unexpected comparison kind"); + return -1; + } + + if (-1 == append_charp(writer, op)) { + return -1; + } + + if (-1 == append_ast_expr(writer, + (expr_ty)asdl_seq_GET(comparators, i), + false)) { + return -1; + } + } + + return omit_parens ? 0 : append_charp(writer, ")"); +} + +static int +append_ast_keyword(_PyUnicodeWriter *writer, keyword_ty kw) +{ + if (kw->arg == NULL) { + if (-1 == append_charp(writer, "**")) { + return -1; + } + } + else { + if (-1 == _PyUnicodeWriter_WriteStr(writer, kw->arg)) { + return -1; + } + + if (-1 == append_charp(writer, "=")) { + return -1; + } + } + + return append_ast_expr(writer, kw->value, false); +} + +static int +append_ast_call(_PyUnicodeWriter *writer, expr_ty e) +{ + bool first; + Py_ssize_t i, arg_count, kw_count; + expr_ty expr; + keyword_ty kw; + + if (-1 == append_ast_expr(writer, e->v.Call.func, false)) { + return -1; + } + + if (-1 == append_charp(writer, "(")) { + return -1; + } + + first = true; + arg_count = asdl_seq_LEN(e->v.Call.args); + for (i = 0; i < arg_count; i++) { + if (first) { + first = false; + } + else if (-1 == append_charp(writer, ", ")) { + return -1; + } + + expr = (expr_ty)asdl_seq_GET(e->v.Call.args, i); + if (-1 == append_ast_expr(writer, expr, false)) { + return -1; + } + } + + kw_count = asdl_seq_LEN(e->v.Call.keywords); + for (i = 0; i < kw_count; i++) { + if (first) { + first = false; + } + else if (-1 == append_charp(writer, ", ")) { + return -1; + } + + kw = (keyword_ty)asdl_seq_GET(e->v.Call.keywords, i); + if (-1 == append_ast_keyword(writer, kw)) { + return -1; + } + } + + return append_charp(writer, ")"); +} + +static PyObject * +escape_braces(PyObject *orig) +{ + PyObject *temp; + PyObject *result; + temp = PyUnicode_Replace(orig, _str_open_br, _str_dbl_open_br, -1); + if (!temp) { + return NULL; + } + result = PyUnicode_Replace(temp, _str_close_br, _str_dbl_close_br, -1); + Py_DECREF(temp); + return result; +} + +static int +append_fstring_unicode(_PyUnicodeWriter *writer, PyObject *unicode) +{ + PyObject *escaped; + int result = -1; + escaped = escape_braces(unicode); + if (escaped) { + result = _PyUnicodeWriter_WriteStr(writer, escaped); + Py_DECREF(escaped); + } + return result; +} + +static int +append_fstring_element(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) +{ + switch (e->kind) { + case Constant_kind: + return append_fstring_unicode(writer, e->v.Constant.value); + case Str_kind: + return append_fstring_unicode(writer, e->v.Str.s); + case JoinedStr_kind: + return append_joinedstr(writer, e, is_format_spec); + case FormattedValue_kind: + return append_formattedvalue(writer, e, is_format_spec); + default: + PyErr_SetString(PyExc_SystemError, + "unknown expression kind inside f-string"); + return -1; + } +} + +/* Build body separately to enable wrapping the entire stream of Strs, + Constants and FormattedValues in one opening and one closing quote. */ +static PyObject * +build_fstring_body(asdl_seq *values, bool is_format_spec) +{ + Py_ssize_t i, value_count; + _PyUnicodeWriter body_writer; + _PyUnicodeWriter_Init(&body_writer); + body_writer.min_length = 256; + body_writer.overallocate = 1; + + value_count = asdl_seq_LEN(values) - 1; + assert(value_count >= 0); + for (i = 0; i <= value_count; ++i) { + if (-1 == append_fstring_element(&body_writer, + (expr_ty)asdl_seq_GET(values, i), + is_format_spec + )) { + _PyUnicodeWriter_Dealloc(&body_writer); + return NULL; + } + } + + return _PyUnicodeWriter_Finish(&body_writer); +} + +static int +append_joinedstr(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) +{ + int result = -1; + PyObject *body = build_fstring_body(e->v.JoinedStr.values, is_format_spec); + if (!body) { + return -1; + } + + if (!is_format_spec) { + if (-1 != append_charp(writer, "f") && + -1 != append_repr(writer, body)) + { + result = 0; + } + } + else { + result = _PyUnicodeWriter_WriteStr(writer, body); + } + Py_DECREF(body); + return result; +} + +static int +append_formattedvalue(_PyUnicodeWriter *writer, expr_ty e, bool is_format_spec) +{ + char *conversion; + char *outer_brace = "{"; + PyObject *temp_fv_str = expr_as_unicode(e->v.FormattedValue.value, true); + if (!temp_fv_str) { + return -1; + } + if (PyUnicode_Find(temp_fv_str, _str_open_br, 0, 1, 1) == 0) { + /* Expression starts with a brace, split it with a space from the outer + one. */ + outer_brace = "{ "; + } + if (-1 == append_charp(writer, outer_brace)) { + Py_DECREF(temp_fv_str); + return -1; + } + if (-1 == _PyUnicodeWriter_WriteStr(writer, temp_fv_str)) { + Py_DECREF(temp_fv_str); + return -1; + } + Py_DECREF(temp_fv_str); + + if (e->v.FormattedValue.conversion > 0) { + switch (e->v.FormattedValue.conversion) { + case 97: + conversion = "!a"; + break; + case 114: + conversion = "!r"; + break; + case 115: + conversion = "!s"; + break; + default: + PyErr_SetString(PyExc_SystemError, + "unknown f-value conversion kind"); + return -1; + } + if (-1 == append_charp(writer, conversion)) { + return -1; + } + } + if (e->v.FormattedValue.format_spec > 0) { + if (-1 == _PyUnicodeWriter_WriteASCIIString(writer, ":", 1) || + -1 == append_fstring_element(writer, + e->v.FormattedValue.format_spec, + true + )) + { + return -1; + } + } + return append_charp(writer, "}"); +} + +static int +append_ast_attribute(_PyUnicodeWriter *writer, expr_ty e) +{ + const char *period; + if (-1 == append_ast_expr(writer, e->v.Attribute.value, false)) { + return -1; + } + + /* Special case: integers require a space for attribute access to be + unambiguous. Floats and complex numbers don't but work with it, too. */ + if (e->v.Attribute.value->kind == Num_kind || + e->v.Attribute.value->kind == Constant_kind) + { + period = " ."; + } + else { + period = "."; + } + if (-1 == append_charp(writer, period)) { + return -1; + } + + return _PyUnicodeWriter_WriteStr(writer, e->v.Attribute.attr); +} + +static int +append_ast_simple_slice(_PyUnicodeWriter *writer, slice_ty slice) +{ + if (slice->v.Slice.lower) { + if (-1 == append_ast_expr(writer, slice->v.Slice.lower, false)) { + return -1; + } + } + + if (-1 == append_charp(writer, ":")) { + return -1; + } + + if (slice->v.Slice.upper) { + if (-1 == append_ast_expr(writer, slice->v.Slice.upper, false)) { + return -1; + } + } + + if (slice->v.Slice.step) { + if (-1 == append_charp(writer, ":")) { + return -1; + } + if (-1 == append_ast_expr(writer, slice->v.Slice.step, false)) { + return -1; + } + } + 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++) { + if (i > 0 && -1 == append_charp(writer, ", ")) { + return -1; + } + if (-1 == append_ast_expr(writer, + (expr_ty)asdl_seq_GET(slice->v.ExtSlice.dims, i), + false)) { + return -1; + } + } + return 0; +} + +static int +append_ast_slice(_PyUnicodeWriter *writer, slice_ty slice, bool omit_parens) +{ + 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: + return append_ast_expr(writer, slice->v.Index.value, omit_parens); + default: + PyErr_SetString(PyExc_SystemError, + "unexpected slice kind"); + return -1; + } +} + +static int +append_ast_subscript(_PyUnicodeWriter *writer, expr_ty e) +{ + if (-1 == append_ast_expr(writer, e->v.Subscript.value, false)) { + return -1; + } + + if (-1 == append_charp(writer, "[")) { + return -1; + } + + if (-1 == append_ast_slice(writer, e->v.Subscript.slice, true)) { + return -1; + } + + return append_charp(writer, "]"); +} + +static int +append_ast_starred(_PyUnicodeWriter *writer, expr_ty e) +{ + if (-1 == append_charp(writer, "*")) { + return -1; + } + + return append_ast_expr(writer, e->v.Starred.value, false); +} + +static int +append_ast_yield(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens) +{ + if (!omit_parens && -1 == append_charp(writer, "(")) { + return -1; + } + + if (-1 == append_charp(writer, e->v.Yield.value ? "yield " : "yield")) { + return -1; + } + + if (e->v.Yield.value) { + if (-1 == append_ast_expr(writer, e->v.Yield.value, false)) { + return -1; + } + } + return omit_parens ? 0 : append_charp(writer, ")"); +} + +static int +append_ast_yield_from(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens) +{ + if (!omit_parens && -1 == append_charp(writer, "(")) { + return -1; + } + + if (-1 == append_charp(writer, + e->v.YieldFrom.value ? "yield from " : "yield from")) { + return -1; + } + + if (e->v.YieldFrom.value) { + if (-1 == append_ast_expr(writer, e->v.YieldFrom.value, false)) { + return -1; + } + } + return omit_parens ? 0 : append_charp(writer, ")"); +} + +static int +append_ast_await(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens) +{ + if (!omit_parens && -1 == append_charp(writer, "(")) { + return -1; + } + + if (-1 == append_charp(writer, e->v.Await.value ? "await " : "await")) { + return -1; + } + + if (e->v.Await.value) { + if (-1 == append_ast_expr(writer, e->v.Await.value, false)) { + return -1; + } + } + return omit_parens ? 0 : append_charp(writer, ")"); +} + +static int +append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens) +{ + switch (e->kind) { + case BoolOp_kind: + return append_ast_boolop(writer, e, omit_parens); + case BinOp_kind: + return append_ast_binop(writer, e, omit_parens); + case UnaryOp_kind: + return append_ast_unaryop(writer, e, omit_parens); + case Lambda_kind: + return append_ast_lambda(writer, e, omit_parens); + case IfExp_kind: + return append_ast_ifexp(writer, e, omit_parens); + 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, omit_parens); + 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, omit_parens); + case YieldFrom_kind: + return append_ast_yield_from(writer, e, omit_parens); + case Await_kind: + return append_ast_await(writer, e, omit_parens); + case Compare_kind: + return append_ast_compare(writer, e, omit_parens); + 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: + return append_charp(writer, "..."); + 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); + /* child nodes of List and Tuple will have expr_context set */ + case List_kind: + return append_ast_list(writer, e); + case Tuple_kind: + return append_ast_tuple(writer, e, omit_parens); + default: + PyErr_SetString(PyExc_SystemError, + "unknown expression kind"); + return -1; + } +} + +static int +maybe_init_static_strings() +{ + 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, bool omit_parens) +{ + _PyUnicodeWriter writer; + _PyUnicodeWriter_Init(&writer); + writer.min_length = 256; + writer.overallocate = 1; + if (-1 == maybe_init_static_strings() || + -1 == append_ast_expr(&writer, e, omit_parens)) + { + _PyUnicodeWriter_Dealloc(&writer); + return NULL; + } + return _PyUnicodeWriter_Finish(&writer); +} + +PyObject * +_PyAST_ExprAsUnicode(expr_ty e, bool omit_parens) +{ + return expr_as_unicode(e, omit_parens); +} |