[3.7] bpo-33475: Fix and improve converting annotations to strings. (GH-6774). (GH-6927)

(cherry picked from commit 64fddc423fcbe90b8088446c63385ec0aaf3077c)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
diff --git a/Python/ast_unparse.c b/Python/ast_unparse.c
index 1345271..725ce31 100644
--- a/Python/ast_unparse.c
+++ b/Python/ast_unparse.c
@@ -9,13 +9,15 @@
 
 /* Forward declarations for recursion via helper functions. */
 static PyObject *
-expr_as_unicode(expr_ty e, bool omit_parens);
+expr_as_unicode(expr_ty e, int level);
 static int
-append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens);
+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)
@@ -23,6 +25,39 @@
     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)
 {
@@ -37,111 +72,108 @@
     return ret;
 }
 
+/* Priority levels */
+
+enum {
+    PR_TUPLE,
+    PR_TEST,            /* 'if'-'else', 'lambda' */
+    PR_OR,              /* 'or' */
+    PR_AND,             /* 'and' */
+    PR_NOT,             /* 'not' */
+    PR_CMP,             /* '<', '>', '==', '>=', '<=', '!=',
+                           'in', 'not in', 'is', 'is not' */
+    PR_EXPR,
+    PR_BOR = PR_EXPR,   /* '|' */
+    PR_BXOR,            /* '^' */
+    PR_BAND,            /* '&' */
+    PR_SHIFT,           /* '<<', '>>' */
+    PR_ARITH,           /* '+', '-' */
+    PR_TERM,            /* '*', '@', '/', '%', '//' */
+    PR_FACTOR,          /* unary '+', '-', '~' */
+    PR_POWER,           /* '**' */
+    PR_AWAIT,           /* 'await' */
+    PR_ATOM,
+};
+
 static int
-append_ast_boolop(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens)
+append_ast_boolop(_PyUnicodeWriter *writer, expr_ty e, int level)
 {
     Py_ssize_t i, value_count;
     asdl_seq *values;
+    const char *op = (e->v.BoolOp.op == And) ? " and " : " or ";
+    int pr = (e->v.BoolOp.op == And) ? PR_AND : PR_OR;
 
-    if (!omit_parens && -1 == append_charp(writer, "(")) {
-        return -1;
-    }
+    APPEND_STR_IF(level > pr, "(");
 
     values = e->v.BoolOp.values;
-    value_count = asdl_seq_LEN(values) - 1;
-    assert(value_count >= 0);
+    value_count = asdl_seq_LEN(values);
 
-    if (-1 == append_ast_expr(writer,
-                              (expr_ty)asdl_seq_GET(values, 0),
-                              false)) {
-        return -1;
+    for (i = 0; i < value_count; ++i) {
+        APPEND_STR_IF(i > 0, op);
+        APPEND_EXPR((expr_ty)asdl_seq_GET(values, i), pr + 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, ")");
+    APPEND_STR_IF(level > pr, ")");
+    return 0;
 }
 
 static int
-append_ast_binop(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens)
+append_ast_binop(_PyUnicodeWriter *writer, expr_ty e, int level)
 {
     const char *op;
+    int pr;
+    bool rassoc = false;  /* is right-associative? */
 
-    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;
+    switch (e->v.BinOp.op) {
+    case Add: op = " + "; pr = PR_ARITH; break;
+    case Sub: op = " - "; pr = PR_ARITH; break;
+    case Mult: op = " * "; pr = PR_TERM; break;
+    case MatMult: op = " @ "; pr = PR_TERM; break;
+    case Div: op = " / "; pr = PR_TERM; break;
+    case Mod: op = " % "; pr = PR_TERM; break;
+    case LShift: op = " << "; pr = PR_SHIFT; break;
+    case RShift: op = " >> "; pr = PR_SHIFT; break;
+    case BitOr: op = " | "; pr = PR_BOR; break;
+    case BitXor: op = " ^ "; pr = PR_BXOR; break;
+    case BitAnd: op = " & "; pr = PR_BAND; break;
+    case FloorDiv: op = " // "; pr = PR_TERM; break;
+    case Pow: op = " ** "; pr = PR_POWER; rassoc = true; break;
     default:
-        Py_UNREACHABLE();
-    }
-
-    if (-1 == append_charp(writer, op)) {
+        PyErr_SetString(PyExc_SystemError,
+                        "unknown binary operator");
         return -1;
     }
 
-    if (-1 == append_ast_expr(writer, e->v.BinOp.right, false)) {
-        return -1;
-    }
-
-    return omit_parens ? 0 : append_charp(writer, ")");
+    APPEND_STR_IF(level > pr, "(");
+    APPEND_EXPR(e->v.BinOp.left, pr + rassoc);
+    APPEND_STR(op);
+    APPEND_EXPR(e->v.BinOp.right, pr + !rassoc);
+    APPEND_STR_IF(level > pr, ")");
+    return 0;
 }
 
 static int
-append_ast_unaryop(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens)
+append_ast_unaryop(_PyUnicodeWriter *writer, expr_ty e, int level)
 {
     const char *op;
+    int pr;
 
-    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;
+    switch (e->v.UnaryOp.op) {
+    case Invert: op = "~"; pr = PR_FACTOR; break;
+    case Not: op = "not "; pr = PR_NOT; break;
+    case UAdd: op = "+"; pr = PR_FACTOR; break;
+    case USub: op = "-"; pr = PR_FACTOR; break;
     default:
-        Py_UNREACHABLE();
-    }
-
-    if (-1 == append_charp(writer, op)) {
+        PyErr_SetString(PyExc_SystemError,
+                        "unknown unary operator");
         return -1;
     }
 
-    if (-1 == append_ast_expr(writer, e->v.UnaryOp.operand, false)) {
-        return -1;
-    }
-
-    return omit_parens ? 0 : append_charp(writer, ")");
+    APPEND_STR_IF(level > pr, "(");
+    APPEND_STR(op);
+    APPEND_EXPR(e->v.UnaryOp.operand, pr);
+    APPEND_STR_IF(level > pr, ")");
+    return 0;
 }
 
 static int
@@ -151,12 +183,8 @@
         return -1;
     }
     if (arg->annotation) {
-        if (-1 == append_charp(writer, ": ")) {
-            return -1;
-        }
-        if (-1 == append_ast_expr(writer, arg->annotation, true)) {
-            return -1;
-        }
+        APPEND_STR(": ");
+        APPEND_EXPR(arg->annotation, PR_TEST);
     }
     return 0;
 }
@@ -166,8 +194,6 @@
 {
     bool first;
     Py_ssize_t i, di, arg_count, default_count;
-    arg_ty arg;
-    expr_ty default_;
 
     first = true;
 
@@ -175,47 +201,22 @@
     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;
-        }
+        APPEND_STR_IF_NOT_FIRST(", ");
+        APPEND(arg, (arg_ty)asdl_seq_GET(args->args, i));
 
         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;
-            }
+            APPEND_STR("=");
+            APPEND_EXPR((expr_ty)asdl_seq_GET(args->defaults, di), PR_TEST);
         }
     }
 
     /* 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;
-        }
-
+        APPEND_STR_IF_NOT_FIRST(", ");
+        APPEND_STR("*");
         if (args->vararg) {
-            if (-1 == append_ast_arg(writer, args->vararg)) {
-                return -1;
-            }
+            APPEND(arg, args->vararg);
         }
     }
 
@@ -223,223 +224,127 @@
     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;
-        }
+        APPEND_STR_IF_NOT_FIRST(", ");
+        APPEND(arg, (arg_ty)asdl_seq_GET(args->kwonlyargs, i));
 
         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;
-            }
+            APPEND_STR("=");
+            APPEND_EXPR((expr_ty)asdl_seq_GET(args->kw_defaults, di), PR_TEST);
         }
     }
 
     /* **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;
-        }
+        APPEND_STR_IF_NOT_FIRST(", ");
+        APPEND_STR("**");
+        APPEND(arg, args->kwarg);
     }
 
     return 0;
 }
 
 static int
-append_ast_lambda(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens)
+append_ast_lambda(_PyUnicodeWriter *writer, expr_ty e, int level)
 {
-    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, ")");
+    APPEND_STR_IF(level > PR_TEST, "(");
+    APPEND_STR("lambda ");
+    APPEND(args, e->v.Lambda.args);
+    APPEND_STR(": ");
+    APPEND_EXPR(e->v.Lambda.body, PR_TEST);
+    APPEND_STR_IF(level > PR_TEST, ")");
+    return 0;
 }
 
 static int
-append_ast_ifexp(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens)
+append_ast_ifexp(_PyUnicodeWriter *writer, expr_ty e, int level)
 {
-    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, ")");
+    APPEND_STR_IF(level > PR_TEST, "(");
+    APPEND_EXPR(e->v.IfExp.body, PR_TEST + 1);
+    APPEND_STR(" if ");
+    APPEND_EXPR(e->v.IfExp.test, PR_TEST + 1);
+    APPEND_STR(" else ");
+    APPEND_EXPR(e->v.IfExp.orelse, PR_TEST);
+    APPEND_STR_IF(level > PR_TEST, ")");
+    return 0;
 }
 
 static int
 append_ast_dict(_PyUnicodeWriter *writer, expr_ty e)
 {
     Py_ssize_t i, value_count;
-    expr_ty key_node, value_node;
+    expr_ty key_node;
 
-    if (-1 == append_charp(writer, "{")) {
-        return -1;
-    }
-
+    APPEND_STR("{");
     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;
-        }
+        APPEND_STR_IF(i > 0, ", ");
         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;
-            }
+            APPEND_EXPR(key_node, PR_TEST);
+            APPEND_STR(": ");
+            APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.Dict.values, i), PR_TEST);
         }
-        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;
+        else {
+            APPEND_STR("**");
+            APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.Dict.values, i), PR_EXPR);
         }
     }
 
-    return append_charp(writer, "}");
+    APPEND_STR_FINISH("}");
 }
 
 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;
-    }
-
+    APPEND_STR("{");
     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;
-        }
+        APPEND_STR_IF(i > 0, ", ");
+        APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.Set.elts, i), PR_TEST);
     }
 
-    return append_charp(writer, "}");
+    APPEND_STR_FINISH("}");
 }
 
 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;
-    }
-
+    APPEND_STR("[");
     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;
-        }
+        APPEND_STR_IF(i > 0, ", ");
+        APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.List.elts, i), PR_TEST);
     }
 
-    return append_charp(writer, "]");
+    APPEND_STR_FINISH("]");
 }
 
 static int
-append_ast_tuple(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens)
+append_ast_tuple(_PyUnicodeWriter *writer, expr_ty e, int level)
 {
     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;
-        }
+    if (elem_count == 0) {
+        APPEND_STR_FINISH("()");
     }
 
+    APPEND_STR_IF(level > PR_TUPLE, "(");
+
     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;
-        }
+        APPEND_STR_IF(i > 0, ", ");
+        APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.Tuple.elts, i), PR_TEST);
     }
 
-    if (!omit_parens || elem_count < 2) {
-        return append_charp(writer, ")");
-    }
-
+    APPEND_STR_IF(elem_count == 1, ",");
+    APPEND_STR_IF(level > PR_TUPLE, ")");
     return 0;
 }
 
@@ -448,33 +353,15 @@
 {
     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;
-    }
+    APPEND_STR(gen->is_async ? " async for " : " for ");
+    APPEND_EXPR(gen->target, PR_TUPLE);
+    APPEND_STR(" in ");
+    APPEND_EXPR(gen->iter, PR_TEST + 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;
-        }
+        APPEND_STR(" if ");
+        APPEND_EXPR((expr_ty)asdl_seq_GET(gen->ifs, i), PR_TEST + 1);
     }
     return 0;
 }
@@ -483,110 +370,62 @@
 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;
-        }
+        APPEND(comprehension, (comprehension_ty)asdl_seq_GET(comprehensions, i));
     }
 
     return 0;
 }
 
 static int
-append_ast_genexp(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens)
+append_ast_genexp(_PyUnicodeWriter *writer, expr_ty e)
 {
-    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, ")");
+    APPEND_STR("(");
+    APPEND_EXPR(e->v.GeneratorExp.elt, PR_TEST);
+    APPEND(comprehensions, e->v.GeneratorExp.generators);
+    APPEND_STR_FINISH(")");
 }
 
 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, "]");
+    APPEND_STR("[");
+    APPEND_EXPR(e->v.ListComp.elt, PR_TEST);
+    APPEND(comprehensions, e->v.ListComp.generators);
+    APPEND_STR_FINISH("]");
 }
 
 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, "}");
+    APPEND_STR("{");
+    APPEND_EXPR(e->v.SetComp.elt, PR_TEST);
+    APPEND(comprehensions, e->v.SetComp.generators);
+    APPEND_STR_FINISH("}");
 }
 
 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, "}");
+    APPEND_STR("{");
+    APPEND_EXPR(e->v.DictComp.key, PR_TEST);
+    APPEND_STR(": ");
+    APPEND_EXPR(e->v.DictComp.value, PR_TEST);
+    APPEND(comprehensions, e->v.DictComp.generators);
+    APPEND_STR_FINISH("}");
 }
 
 static int
-append_ast_compare(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens)
+append_ast_compare(_PyUnicodeWriter *writer, expr_ty e, int level)
 {
     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;
-    }
+    APPEND_STR_IF(level > PR_CMP, "(");
 
     comparators = e->v.Compare.comparators;
     ops = e->v.Compare.ops;
@@ -594,9 +433,7 @@
     assert(comparator_count > 0);
     assert(comparator_count == asdl_seq_LEN(ops));
 
-    if (-1 == append_ast_expr(writer, e->v.Compare.left, false)) {
-        return -1;
-    }
+    APPEND_EXPR(e->v.Compare.left, PR_CMP + 1);
 
     for (i = 0; i < comparator_count; i++) {
         switch ((cmpop_ty)asdl_seq_GET(ops, i)) {
@@ -636,39 +473,30 @@
             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;
-        }
+        APPEND_STR(op);
+        APPEND_EXPR((expr_ty)asdl_seq_GET(comparators, i), PR_CMP + 1);
     }
 
-    return omit_parens ? 0 : append_charp(writer, ")");
+    APPEND_STR_IF(level > PR_CMP, ")");
+    return 0;
 }
 
 static int
 append_ast_keyword(_PyUnicodeWriter *writer, keyword_ty kw)
 {
     if (kw->arg == NULL) {
-        if (-1 == append_charp(writer, "**")) {
-            return -1;
-        }
+        APPEND_STR("**");
     }
     else {
         if (-1 == _PyUnicodeWriter_WriteStr(writer, kw->arg)) {
             return -1;
         }
 
-        if (-1 == append_charp(writer, "=")) {
-            return -1;
-        }
+        APPEND_STR("=");
     }
 
-    return append_ast_expr(writer, kw->value, false);
+    APPEND_EXPR(kw->value, PR_TEST);
+    return 0;
 }
 
 static int
@@ -677,48 +505,33 @@
     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;
+    APPEND_EXPR(e->v.Call.func, PR_ATOM);
+
+    arg_count = asdl_seq_LEN(e->v.Call.args);
+    kw_count = asdl_seq_LEN(e->v.Call.keywords);
+    if (arg_count == 1 && kw_count == 0) {
+        expr = (expr_ty)asdl_seq_GET(e->v.Call.args, 0);
+        if (expr->kind == GeneratorExp_kind) {
+            /* Special case: a single generator expression. */
+            return append_ast_genexp(writer, expr);
+        }
     }
 
-    if (-1 == append_charp(writer, "(")) {
-        return -1;
-    }
+    APPEND_STR("(");
 
     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;
-        }
+        APPEND_STR_IF_NOT_FIRST(", ");
+        APPEND_EXPR((expr_ty)asdl_seq_GET(e->v.Call.args, i), PR_TEST);
     }
 
-    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;
-        }
+        APPEND_STR_IF_NOT_FIRST(", ");
+        APPEND(keyword, (keyword_ty)asdl_seq_GET(e->v.Call.keywords, i));
     }
 
-    return append_charp(writer, ")");
+    APPEND_STR_FINISH(")");
 }
 
 static PyObject *
@@ -778,9 +591,8 @@
     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) {
+    value_count = asdl_seq_LEN(values);
+    for (i = 0; i < value_count; ++i) {
         if (-1 == append_fstring_element(&body_writer,
                                          (expr_ty)asdl_seq_GET(values, i),
                                          is_format_spec
@@ -819,9 +631,11 @@
 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);
+    const char *conversion;
+    const char *outer_brace = "{";
+    /* Grammar allows PR_TUPLE, but use >PR_TEST for adding parenthesis
+       around a lambda with ':' */
+    PyObject *temp_fv_str = expr_as_unicode(e->v.FormattedValue.value, PR_TEST + 1);
     if (!temp_fv_str) {
         return -1;
     }
@@ -842,13 +656,13 @@
 
     if (e->v.FormattedValue.conversion > 0) {
         switch (e->v.FormattedValue.conversion) {
-        case 97:
+        case 'a':
             conversion = "!a";
             break;
-        case 114:
+        case 'r':
             conversion = "!r";
             break;
-        case 115:
+        case 's':
             conversion = "!s";
             break;
         default:
@@ -856,9 +670,7 @@
                             "unknown f-value conversion kind");
             return -1;
         }
-        if (-1 == append_charp(writer, conversion)) {
-            return -1;
-        }
+        APPEND_STR(conversion);
     }
     if (e->v.FormattedValue.format_spec) {
         if (-1 == _PyUnicodeWriter_WriteASCIIString(writer, ":", 1) ||
@@ -870,16 +682,15 @@
             return -1;
         }
     }
-    return append_charp(writer, "}");
+
+    APPEND_STR_FINISH("}");
 }
 
 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;
-    }
+    APPEND_EXPR(e->v.Attribute.value, PR_ATOM);
 
     /* Special case: integers require a space for attribute access to be
        unambiguous.  Floats and complex numbers don't but work with it, too. */
@@ -891,9 +702,7 @@
     else {
         period = ".";
     }
-    if (-1 == append_charp(writer, period)) {
-        return -1;
-    }
+    APPEND_STR(period);
 
     return _PyUnicodeWriter_WriteStr(writer, e->v.Attribute.attr);
 }
@@ -902,28 +711,18 @@
 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;
-        }
+        APPEND_EXPR(slice->v.Slice.lower, PR_TEST);
     }
 
-    if (-1 == append_charp(writer, ":")) {
-        return -1;
-    }
+    APPEND_STR(":");
 
     if (slice->v.Slice.upper) {
-        if (-1 == append_ast_expr(writer, slice->v.Slice.upper, false)) {
-            return -1;
-        }
+        APPEND_EXPR(slice->v.Slice.upper, PR_TEST);
     }
 
     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;
-        }
+        APPEND_STR(":");
+        APPEND_EXPR(slice->v.Slice.step, PR_TEST);
     }
     return 0;
 }
@@ -934,28 +733,23 @@
     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;
-        }
+        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, bool omit_parens)
+append_ast_slice(_PyUnicodeWriter *writer, slice_ty slice)
 {
-    switch(slice->kind) {
+    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);
+        APPEND_EXPR(slice->v.Index.value, PR_TUPLE);
+        return 0;
     default:
         PyErr_SetString(PyExc_SystemError,
                         "unexpected slice kind");
@@ -966,109 +760,70 @@
 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, "]");
+    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)
 {
-    if (-1 == append_charp(writer, "*")) {
-        return -1;
-    }
-
-    return append_ast_expr(writer, e->v.Starred.value, false);
+    APPEND_STR("*");
+    APPEND_EXPR(e->v.Starred.value, PR_EXPR);
+    return 0;
 }
 
 static int
-append_ast_yield(_PyUnicodeWriter *writer, expr_ty e, bool omit_parens)
+append_ast_yield(_PyUnicodeWriter *writer, expr_ty e)
 {
-    if (!omit_parens && -1 == append_charp(writer, "(")) {
-        return -1;
+    if (!e->v.Yield.value) {
+        APPEND_STR_FINISH("(yield)");
     }
 
-    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, ")");
+    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, bool omit_parens)
+append_ast_yield_from(_PyUnicodeWriter *writer, expr_ty e)
 {
-    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, ")");
+    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, bool omit_parens)
+append_ast_await(_PyUnicodeWriter *writer, expr_ty e, int level)
 {
-    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, ")");
+    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, bool omit_parens)
+append_ast_expr(_PyUnicodeWriter *writer, expr_ty e, int level)
 {
     switch (e->kind) {
     case BoolOp_kind:
-        return append_ast_boolop(writer, e, omit_parens);
+        return append_ast_boolop(writer, e, level);
     case BinOp_kind:
-        return append_ast_binop(writer, e, omit_parens);
+        return append_ast_binop(writer, e, level);
     case UnaryOp_kind:
-        return append_ast_unaryop(writer, e, omit_parens);
+        return append_ast_unaryop(writer, e, level);
     case Lambda_kind:
-        return append_ast_lambda(writer, e, omit_parens);
+        return append_ast_lambda(writer, e, level);
     case IfExp_kind:
-        return append_ast_ifexp(writer, e, omit_parens);
+        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, omit_parens);
+        return append_ast_genexp(writer, e);
     case ListComp_kind:
         return append_ast_listcomp(writer, e);
     case SetComp_kind:
@@ -1076,13 +831,13 @@
     case DictComp_kind:
         return append_ast_dictcomp(writer, e);
     case Yield_kind:
-        return append_ast_yield(writer, e, omit_parens);
+        return append_ast_yield(writer, e);
     case YieldFrom_kind:
-        return append_ast_yield_from(writer, e, omit_parens);
+        return append_ast_yield_from(writer, e);
     case Await_kind:
-        return append_ast_await(writer, e, omit_parens);
+        return append_ast_await(writer, e, level);
     case Compare_kind:
-        return append_ast_compare(writer, e, omit_parens);
+        return append_ast_compare(writer, e, level);
     case Call_kind:
         return append_ast_call(writer, e);
     case Constant_kind:
@@ -1098,7 +853,7 @@
     case Bytes_kind:
         return append_repr(writer, e->v.Bytes.s);
     case Ellipsis_kind:
-        return append_charp(writer, "...");
+        APPEND_STR_FINISH("...");
     case NameConstant_kind:
         return append_repr(writer, e->v.NameConstant.value);
     /* The following exprs can be assignment targets. */
@@ -1110,11 +865,10 @@
         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);
+        return append_ast_tuple(writer, e, level);
     default:
         PyErr_SetString(PyExc_SystemError,
                         "unknown expression kind");
@@ -1145,14 +899,14 @@
 }
 
 static PyObject *
-expr_as_unicode(expr_ty e, bool omit_parens)
+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, omit_parens))
+        -1 == append_ast_expr(&writer, e, level))
     {
         _PyUnicodeWriter_Dealloc(&writer);
         return NULL;
@@ -1161,7 +915,7 @@
 }
 
 PyObject *
-_PyAST_ExprAsUnicode(expr_ty e, bool omit_parens)
+_PyAST_ExprAsUnicode(expr_ty e)
 {
-    return expr_as_unicode(e, omit_parens);
+    return expr_as_unicode(e, PR_TEST);
 }