PEP 308 implementation, including minor refdocs and some testcases. It
breaks the parser module, because it adds the if/else construct as well as
two new grammar rules for backward compatibility. If no one else fixes
parsermodule, I guess I'll go ahead and fix it later this week.

The TeX code was checked with texcheck.py, but not rendered. There is
actually a slight incompatibility:

>>> (x for x in lambda:0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: iteration over non-sequence

changes into

>>> (x for x in lambda: 0)
  File "<stdin>", line 1
    (x for x in lambda: 0)
                     ^
SyntaxError: invalid syntax

Since there's no way the former version can be useful, it's probably a
bugfix ;)
diff --git a/Python/Python-ast.c b/Python/Python-ast.c
index 6935851..8d148e3 100644
--- a/Python/Python-ast.c
+++ b/Python/Python-ast.c
@@ -151,6 +151,12 @@
         "args",
         "body",
 };
+PyTypeObject *IfExp_type;
+char *IfExp_fields[]={
+        "test",
+        "body",
+        "orelse",
+};
 PyTypeObject *Dict_type;
 char *Dict_fields[]={
         "keys",
@@ -431,6 +437,7 @@
         BinOp_type = make_type("BinOp", expr_type, BinOp_fields, 3);
         UnaryOp_type = make_type("UnaryOp", expr_type, UnaryOp_fields, 2);
         Lambda_type = make_type("Lambda", expr_type, Lambda_fields, 2);
+        IfExp_type = make_type("IfExp", expr_type, IfExp_fields, 3);
         Dict_type = make_type("Dict", expr_type, Dict_fields, 2);
         ListComp_type = make_type("ListComp", expr_type, ListComp_fields, 2);
         GeneratorExp_type = make_type("GeneratorExp", expr_type,
@@ -1138,6 +1145,38 @@
 }
 
 expr_ty
+IfExp(expr_ty test, expr_ty body, expr_ty orelse, int lineno, PyArena *arena)
+{
+        expr_ty p;
+        if (!test) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field test is required for IfExp");
+                return NULL;
+        }
+        if (!body) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field body is required for IfExp");
+                return NULL;
+        }
+        if (!orelse) {
+                PyErr_SetString(PyExc_ValueError,
+                                "field orelse is required for IfExp");
+                return NULL;
+        }
+        p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
+        if (!p) {
+                PyErr_NoMemory();
+                return NULL;
+        }
+        p->kind = IfExp_kind;
+        p->v.IfExp.test = test;
+        p->v.IfExp.body = body;
+        p->v.IfExp.orelse = orelse;
+        p->lineno = lineno;
+        return p;
+}
+
+expr_ty
 Dict(asdl_seq * keys, asdl_seq * values, int lineno, PyArena *arena)
 {
         expr_ty p;
@@ -2077,6 +2116,25 @@
                         goto failed;
                 Py_DECREF(value);
                 break;
+        case IfExp_kind:
+                result = PyType_GenericNew(IfExp_type, NULL, NULL);
+                if (!result) goto failed;
+                value = ast2obj_expr(o->v.IfExp.test);
+                if (!value) goto failed;
+                if (PyObject_SetAttrString(result, "test", value) == -1)
+                        goto failed;
+                Py_DECREF(value);
+                value = ast2obj_expr(o->v.IfExp.body);
+                if (!value) goto failed;
+                if (PyObject_SetAttrString(result, "body", value) == -1)
+                        goto failed;
+                Py_DECREF(value);
+                value = ast2obj_expr(o->v.IfExp.orelse);
+                if (!value) goto failed;
+                if (PyObject_SetAttrString(result, "orelse", value) == -1)
+                        goto failed;
+                Py_DECREF(value);
+                break;
         case Dict_kind:
                 result = PyType_GenericNew(Dict_type, NULL, NULL);
                 if (!result) goto failed;