cpython: 27e5437f442c (original) (raw)
Mercurial > cpython
changeset 100065:27e5437f442c
Add ast.Constant Issue #26146: Add a new kind of AST node: ast.Constant. It can be used by external AST optimizers, but the compiler does not emit directly such node. An optimizer can replace the following AST nodes with ast.Constant: * ast.NameConstant: None, False, True * ast.Num: int, float, complex * ast.Str: str * ast.Bytes: bytes * ast.Tuple if items are constants too: tuple * frozenset Update code to accept ast.Constant instead of ast.Num and/or ast.Str: * compiler * docstrings * ast.literal_eval() * Tools/parser/unparse.py [#26146]
Victor Stinner victor.stinner@gmail.com | |
---|---|
date | Tue, 26 Jan 2016 00:40:57 +0100 |
parents | 4cb3c2d0aff2 |
children | cbd4a6a2657e |
files | Include/Python-ast.h Include/asdl.h Lib/ast.py Lib/test/test_ast.py Misc/NEWS Parser/Python.asdl Parser/asdl.py Parser/asdl_c.py Python/Python-ast.c Python/ast.c Python/compile.c Python/future.c Python/symtable.c Tools/parser/unparse.py |
diffstat | 14 files changed, 401 insertions(+), 44 deletions(-)[+] [-] Include/Python-ast.h 13 Include/asdl.h 1 Lib/ast.py 52 Lib/test/test_ast.py 120 Misc/NEWS 4 Parser/Python.asdl 7 Parser/asdl.py 3 Parser/asdl_c.py 21 Python/Python-ast.c 79 Python/ast.c 50 Python/compile.c 60 Python/future.c 5 Python/symtable.c 1 Tools/parser/unparse.py 29 |
line wrap: on
line diff
--- a/Include/Python-ast.h +++ b/Include/Python-ast.h @@ -202,9 +202,9 @@ enum _expr_kind {BoolOp_kind=1, BinOp_ki Await_kind=12, Yield_kind=13, YieldFrom_kind=14, Compare_kind=15, Call_kind=16, Num_kind=17, Str_kind=18, FormattedValue_kind=19, JoinedStr_kind=20, Bytes_kind=21,
NameConstant_kind=22, Ellipsis_kind=23, Attribute_kind=24,[](#l1.7)
Subscript_kind=25, Starred_kind=26, Name_kind=27,[](#l1.8)
List_kind=28, Tuple_kind=29};[](#l1.9)
NameConstant_kind=22, Ellipsis_kind=23, Constant_kind=24,[](#l1.10)
Attribute_kind=25, Subscript_kind=26, Starred_kind=27,[](#l1.11)
Name_kind=28, List_kind=29, Tuple_kind=30};[](#l1.12)
struct _expr { enum _expr_kind kind; union { @@ -316,6 +316,10 @@ struct _expr { } NameConstant; struct {
constant value;[](#l1.20)
} Constant;[](#l1.21)
[](#l1.22)
struct {[](#l1.23) expr_ty value;[](#l1.24) identifier attr;[](#l1.25) expr_context_ty ctx;[](#l1.26)
@@ -567,6 +571,9 @@ expr_ty _Py_NameConstant(singleton value *arena); #define Ellipsis(a0, a1, a2) _Py_Ellipsis(a0, a1, a2) expr_ty _Py_Ellipsis(int lineno, int col_offset, PyArena *arena); +#define Constant(a0, a1, a2, a3) _Py_Constant(a0, a1, a2, a3) +expr_ty _Py_Constant(constant value, int lineno, int col_offset, PyArena
*arena);[](#l1.33)
#define Attribute(a0, a1, a2, a3, a4, a5) _Py_Attribute(a0, a1, a2, a3, a4, a5) expr_ty _Py_Attribute(expr_ty value, identifier attr, expr_context_ty ctx, int lineno, int col_offset, PyArena *arena);
--- a/Include/asdl.h +++ b/Include/asdl.h @@ -6,6 +6,7 @@ typedef PyObject * string; typedef PyObject * bytes; typedef PyObject * object; typedef PyObject * singleton; +typedef PyObject * constant; /* It would be nice if the code generated by asdl_c.py was completely independent of Python, but it is a goal the requires too much work
--- a/Lib/ast.py +++ b/Lib/ast.py @@ -35,6 +35,8 @@ def parse(source, filename='', return compile(source, filename, mode, PyCF_ONLY_AST) +_NUM_TYPES = (int, float, complex) + def literal_eval(node_or_string): """ Safely evaluate an expression node or a string containing a Python @@ -47,7 +49,9 @@ def literal_eval(node_or_string): if isinstance(node_or_string, Expression): node_or_string = node_or_string.body def _convert(node):
if isinstance(node, (Str, Bytes)):[](#l3.16)
if isinstance(node, Constant):[](#l3.17)
return node.value[](#l3.18)
elif isinstance(node, (Str, Bytes)):[](#l3.19) return node.s[](#l3.20) elif isinstance(node, Num):[](#l3.21) return node.n[](#l3.22)
@@ -62,24 +66,21 @@ def literal_eval(node_or_string): in zip(node.keys, node.values)) elif isinstance(node, NameConstant): return node.value
elif isinstance(node, UnaryOp) and \[](#l3.27)
isinstance(node.op, (UAdd, USub)) and \[](#l3.28)
isinstance(node.operand, (Num, UnaryOp, BinOp)):[](#l3.29)
elif isinstance(node, UnaryOp) and isinstance(node.op, (UAdd, USub)):[](#l3.30) operand = _convert(node.operand)[](#l3.31)
if isinstance(node.op, UAdd):[](#l3.32)
return + operand[](#l3.33)
else:[](#l3.34)
return - operand[](#l3.35)
elif isinstance(node, BinOp) and \[](#l3.36)
isinstance(node.op, (Add, Sub)) and \[](#l3.37)
isinstance(node.right, (Num, UnaryOp, BinOp)) and \[](#l3.38)
isinstance(node.left, (Num, UnaryOp, BinOp)):[](#l3.39)
if isinstance(operand, _NUM_TYPES):[](#l3.40)
if isinstance(node.op, UAdd):[](#l3.41)
return + operand[](#l3.42)
else:[](#l3.43)
return - operand[](#l3.44)
elif isinstance(node, BinOp) and isinstance(node.op, (Add, Sub)):[](#l3.45) left = _convert(node.left)[](#l3.46) right = _convert(node.right)[](#l3.47)
if isinstance(node.op, Add):[](#l3.48)
return left + right[](#l3.49)
else:[](#l3.50)
return left - right[](#l3.51)
if isinstance(left, _NUM_TYPES) and isinstance(right, _NUM_TYPES):[](#l3.52)
if isinstance(node.op, Add):[](#l3.53)
return left + right[](#l3.54)
else:[](#l3.55)
return _convert(node_or_string) @@ -196,12 +197,19 @@ def get_docstring(node, clean=True): """ if not isinstance(node, (AsyncFunctionDef, FunctionDef, ClassDef, Module)): raise TypeError("%r can't have docstrings" % node.class.name)return left - right[](#l3.56) raise ValueError('malformed node or string: ' + repr(node))[](#l3.57)
- if node.body and isinstance(node.body[0], Expr) and [](#l3.64)
isinstance(node.body[0].value, Str):[](#l3.65)
if clean:[](#l3.66)
import inspect[](#l3.67)
return inspect.cleandoc(node.body[0].value.s)[](#l3.68)
return node.body[0].value.s[](#l3.69)
- if not(node.body and isinstance(node.body[0], Expr)):
return[](#l3.71)
- node = node.body[0].value
- if isinstance(node, Str):
text = node.s[](#l3.74)
- elif isinstance(node, Constant) and isinstance(node.value, str):
text = node.value[](#l3.76)
- else:
return[](#l3.78)
- if clean:
import inspect[](#l3.80)
text = inspect.cleandoc(text)[](#l3.81)
- return text
--- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -1,7 +1,8 @@ +import ast +import dis import os import sys import unittest -import ast import weakref from test import support @@ -933,6 +934,123 @@ class ASTValidatorTests(unittest.TestCas compile(mod, fn, "exec") +class ConstantTests(unittest.TestCase):
node = tree.body[0].value[](#l4.23)
new_node = ast.Constant(value=value)[](#l4.24)
ast.copy_location(new_node, node)[](#l4.25)
tree.body[0].value = new_node[](#l4.26)
code = compile(tree, "<string>", "exec")[](#l4.28)
ns = {}[](#l4.30)
exec(code, ns)[](#l4.31)
return ns['x'][](#l4.32)
- def test_singletons(self):
for const in (None, False, True, Ellipsis, b'', frozenset()):[](#l4.35)
with self.subTest(const=const):[](#l4.36)
value = self.compile_constant(const)[](#l4.37)
self.assertIs(value, const)[](#l4.38)
- def test_values(self):
nested_tuple = (1,)[](#l4.41)
nested_frozenset = frozenset({1})[](#l4.42)
for level in range(3):[](#l4.43)
nested_tuple = (nested_tuple, 2)[](#l4.44)
nested_frozenset = frozenset({nested_frozenset, 2})[](#l4.45)
values = (123, 123.0, 123j,[](#l4.46)
"unicode", b'bytes',[](#l4.47)
tuple("tuple"), frozenset("frozenset"),[](#l4.48)
nested_tuple, nested_frozenset)[](#l4.49)
for value in values:[](#l4.50)
with self.subTest(value=value):[](#l4.51)
result = self.compile_constant(value)[](#l4.52)
self.assertEqual(result, value)[](#l4.53)
target = tree.body[0].targets[0][](#l4.58)
new_target = ast.Constant(value=1)[](#l4.59)
ast.copy_location(new_target, target)[](#l4.60)
tree.body[0].targets[0] = new_target[](#l4.61)
with self.assertRaises(ValueError) as cm:[](#l4.63)
compile(tree, "string", "exec")[](#l4.64)
self.assertEqual(str(cm.exception),[](#l4.65)
"expression which can't be assigned "[](#l4.66)
"to in Store context")[](#l4.67)
- def test_get_docstring(self):
tree = ast.parse("'docstring'\nx = 1")[](#l4.70)
self.assertEqual(ast.get_docstring(tree), 'docstring')[](#l4.71)
tree.body[0].value = ast.Constant(value='constant docstring')[](#l4.73)
self.assertEqual(ast.get_docstring(tree), 'constant docstring')[](#l4.74)
- def get_load_const(self, tree):
# Compile to bytecode, disassemble and get parameter of LOAD_CONST[](#l4.77)
# instructions[](#l4.78)
co = compile(tree, '<string>', 'exec')[](#l4.79)
consts = [][](#l4.80)
for instr in dis.get_instructions(co):[](#l4.81)
if instr.opname == 'LOAD_CONST':[](#l4.82)
consts.append(instr.argval)[](#l4.83)
return consts[](#l4.84)
- @support.cpython_only
- def test_load_const(self):
consts = [None,[](#l4.88)
True, False,[](#l4.89)
124,[](#l4.90)
2.0,[](#l4.91)
3j,[](#l4.92)
"unicode",[](#l4.93)
b'bytes',[](#l4.94)
(1, 2, 3)][](#l4.95)
code = '\n'.join(map(repr, consts))[](#l4.97)
code += '\n...'[](#l4.98)
code_consts = [const for const in consts[](#l4.100)
if (not isinstance(const, (str, int, float, complex))[](#l4.101)
or isinstance(const, bool))][](#l4.102)
code_consts.append(Ellipsis)[](#l4.103)
# the compiler adds a final "LOAD_CONST None"[](#l4.104)
code_consts.append(None)[](#l4.105)
tree = ast.parse(code)[](#l4.107)
self.assertEqual(self.get_load_const(tree), code_consts)[](#l4.108)
# Replace expression nodes with constants[](#l4.110)
for expr_node, const in zip(tree.body, consts):[](#l4.111)
assert isinstance(expr_node, ast.Expr)[](#l4.112)
new_node = ast.Constant(value=const)[](#l4.113)
ast.copy_location(new_node, expr_node.value)[](#l4.114)
expr_node.value = new_node[](#l4.115)
self.assertEqual(self.get_load_const(tree), code_consts)[](#l4.117)
- def test_literal_eval(self):
tree = ast.parse("1 + 2")[](#l4.120)
binop = tree.body[0].value[](#l4.121)
new_left = ast.Constant(value=10)[](#l4.123)
ast.copy_location(new_left, binop.left)[](#l4.124)
binop.left = new_left[](#l4.125)
new_right = ast.Constant(value=20)[](#l4.127)
ast.copy_location(new_right, binop.right)[](#l4.128)
binop.right = new_right[](#l4.129)
self.assertEqual(ast.literal_eval(binop), 30)[](#l4.131)
+ + def main(): if name != 'main': return
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -10,6 +10,10 @@ Release date: tba
Core and Builtins
-----------------
+- Issue #26146: Add a new kind of AST node: ast.Constant
. It can be used
- Issue #18018: Import raises ImportError instead of SystemError if a relative import is attempted without a known parent package.
--- a/Parser/Python.asdl +++ b/Parser/Python.asdl @@ -1,4 +1,8 @@ --- ASDL's six builtin types are identifier, int, string, bytes, object, singleton +-- ASDL's 7 builtin types are: +-- identifier, int, string, bytes, object, singleton, constant +-- +-- singleton: None, True or False +-- constant can be None, whereas None means "no value" for object. module Python { @@ -76,6 +80,7 @@ module Python | Bytes(bytes s) | NameConstant(singleton value) | Ellipsis
| Constant(constant value)[](#l6.17)
-- the following expression can appear in assignment context | Attribute(expr value, identifier attr, expr_context ctx)
--- a/Parser/asdl.py +++ b/Parser/asdl.py @@ -33,7 +33,8 @@ import re
See the EBNF at the top of the file to understand the logical connection
between the various node types.
-builtin_types = {'identifier', 'string', 'bytes', 'int', 'object', 'singleton'} +builtin_types = {'identifier', 'string', 'bytes', 'int', 'object', 'singleton',
'constant'}[](#l7.9)
--- a/Parser/asdl_c.py +++ b/Parser/asdl_c.py @@ -834,6 +834,7 @@ static PyObject* ast2obj_object(void o) return (PyObject)o; } #define ast2obj_singleton ast2obj_object +#define ast2obj_constant ast2obj_object #define ast2obj_identifier ast2obj_object #define ast2obj_string ast2obj_object #define ast2obj_bytes ast2obj_object @@ -871,6 +872,26 @@ static int obj2ast_object(PyObject* obj, return 0; } +static int obj2ast_constant(PyObject* obj, PyObject** out, PyArena* arena) +{
- if (obj == Py_None || obj == Py_True || obj == Py_False) {
/* don't increment the reference counter, Constant uses a borrowed[](#l8.18)
* reference, not a strong reference */[](#l8.19)
*out = obj;[](#l8.20)
return 0;[](#l8.21)
- }
- if (obj) {
if (PyArena_AddPyObject(arena, obj) < 0) {[](#l8.25)
*out = NULL;[](#l8.26)
return -1;[](#l8.27)
}[](#l8.28)
Py_INCREF(obj);[](#l8.29)
- }
- *out = obj;
- return 0;
+} + static int obj2ast_identifier(PyObject* obj, PyObject** out, PyArena* arena) { if (!PyUnicode_CheckExact(obj) && obj != Py_None) {
--- a/Python/Python-ast.c +++ b/Python/Python-ast.c @@ -306,6 +306,10 @@ static char *NameConstant_fields[]={ "value", }; static PyTypeObject *Ellipsis_type; +static PyTypeObject *Constant_type; +static char *Constant_fields[]={
+}; static PyTypeObject Attribute_type; _Py_IDENTIFIER(attr); _Py_IDENTIFIER(ctx); @@ -709,6 +713,7 @@ static PyObject ast2obj_object(void o) return (PyObject)o; } #define ast2obj_singleton ast2obj_object +#define ast2obj_constant ast2obj_object #define ast2obj_identifier ast2obj_object #define ast2obj_string ast2obj_object #define ast2obj_bytes ast2obj_object @@ -746,6 +751,26 @@ static int obj2ast_object(PyObject* obj, return 0; } +static int obj2ast_constant(PyObject* obj, PyObject** out, PyArena* arena) +{
- if (obj == Py_None || obj == Py_True || obj == Py_False) {
/* don't increment the reference counter, Constant uses a borrowed[](#l9.29)
* reference, not a strong reference */[](#l9.30)
*out = obj;[](#l9.31)
return 0;[](#l9.32)
- }
- if (obj) {
if (PyArena_AddPyObject(arena, obj) < 0) {[](#l9.36)
*out = NULL;[](#l9.37)
return -1;[](#l9.38)
}[](#l9.39)
Py_INCREF(obj);[](#l9.40)
- }
- *out = obj;
- return 0;
+} + static int obj2ast_identifier(PyObject* obj, PyObject** out, PyArena* arena) { if (!PyUnicode_CheckExact(obj) && obj != Py_None) { @@ -941,6 +966,8 @@ static int init_types(void) if (!NameConstant_type) return 0; Ellipsis_type = make_type("Ellipsis", expr_type, NULL, 0); if (!Ellipsis_type) return 0;
- Constant_type = make_type("Constant", expr_type, Constant_fields, 1);
- if (!Constant_type) return 0; Attribute_type = make_type("Attribute", expr_type, Attribute_fields, 3); if (!Attribute_type) return 0; Subscript_type = make_type("Subscript", expr_type, Subscript_fields, 3); @@ -2167,6 +2194,25 @@ Ellipsis(int lineno, int col_offset, PyA }
expr_ty +Constant(constant value, int lineno, int col_offset, PyArena *arena) +{
- expr_ty p;
- if (!value) {
PyErr_SetString(PyExc_ValueError,[](#l9.66)
"field value is required for Constant");[](#l9.67)
return NULL;[](#l9.68)
- }
- p = (expr_ty)PyArena_Malloc(arena, sizeof(*p));
- if (!p)
return NULL;[](#l9.72)
- p->kind = Constant_kind;
- p->v.Constant.value = value;
- p->lineno = lineno;
- p->col_offset = col_offset;
- return p;
+} + +expr_ty Attribute(expr_ty value, identifier attr, expr_context_ty ctx, int lineno, int col_offset, PyArena arena) { @@ -3267,6 +3313,15 @@ ast2obj_expr(void _o) result = PyType_GenericNew(Ellipsis_type, NULL, NULL); if (!result) goto failed; break;
- case Constant_kind:
result = PyType_GenericNew(Constant_type, NULL, NULL);[](#l9.89)
if (!result) goto failed;[](#l9.90)
value = ast2obj_constant(o->v.Constant.value);[](#l9.91)
if (!value) goto failed;[](#l9.92)
if (_PyObject_SetAttrId(result, &PyId_value, value) == -1)[](#l9.93)
goto failed;[](#l9.94)
Py_DECREF(value);[](#l9.95)
case Attribute_kind: result = PyType_GenericNew(Attribute_type, NULL, NULL); if (!result) goto failed;break;[](#l9.96)
@@ -6240,6 +6295,28 @@ obj2ast_expr(PyObject* obj, expr_ty* out if (*out == NULL) goto failed; return 0; }
- isinstance = PyObject_IsInstance(obj, (PyObject*)Constant_type);
- if (isinstance == -1) {
return 1;[](#l9.106)
- }
- if (isinstance) {
constant value;[](#l9.109)
if (_PyObject_HasAttrId(obj, &PyId_value)) {[](#l9.111)
int res;[](#l9.112)
tmp = _PyObject_GetAttrId(obj, &PyId_value);[](#l9.113)
if (tmp == NULL) goto failed;[](#l9.114)
res = obj2ast_constant(tmp, &value, arena);[](#l9.115)
if (res != 0) goto failed;[](#l9.116)
Py_CLEAR(tmp);[](#l9.117)
} else {[](#l9.118)
PyErr_SetString(PyExc_TypeError, "required field \"value\" missing from Constant");[](#l9.119)
return 1;[](#l9.120)
}[](#l9.121)
*out = Constant(value, lineno, col_offset, arena);[](#l9.122)
if (*out == NULL) goto failed;[](#l9.123)
return 0;[](#l9.124)
- } isinstance = PyObject_IsInstance(obj, (PyObject*)Attribute_type); if (isinstance == -1) { return 1;
@@ -7517,6 +7594,8 @@ PyInit__ast(void) 0) return NULL; if (PyDict_SetItemString(d, "Ellipsis", (PyObject*)Ellipsis_type) < 0) return NULL;
- if (PyDict_SetItemString(d, "Constant", (PyObject*)Constant_type) < 0)
if (PyDict_SetItemString(d, "Attribute", (PyObject*)Attribute_type) < 0) return NULL; if (PyDict_SetItemString(d, "Subscript", (PyObject*)Subscript_type) < 0)return NULL;[](#l9.134)
--- a/Python/ast.c +++ b/Python/ast.c @@ -132,6 +132,50 @@ validate_arguments(arguments_ty args) } static int +validate_constant(PyObject *value) +{
- if (PyLong_CheckExact(value)
|| PyFloat_CheckExact(value)[](#l10.13)
|| PyComplex_CheckExact(value)[](#l10.14)
|| PyBool_Check(value)[](#l10.15)
|| PyUnicode_CheckExact(value)[](#l10.16)
|| PyBytes_CheckExact(value))[](#l10.17)
return 1;[](#l10.18)
it = PyObject_GetIter(value);[](#l10.23)
if (it == NULL)[](#l10.24)
return 0;[](#l10.25)
while (1) {[](#l10.27)
PyObject *item = PyIter_Next(it);[](#l10.28)
if (item == NULL) {[](#l10.29)
if (PyErr_Occurred()) {[](#l10.30)
Py_DECREF(it);[](#l10.31)
return 0;[](#l10.32)
}[](#l10.33)
break;[](#l10.34)
}[](#l10.35)
if (!validate_constant(item)) {[](#l10.37)
Py_DECREF(it);[](#l10.38)
return 0;[](#l10.39)
}[](#l10.40)
}[](#l10.41)
+} + +static int validate_expr(expr_ty exp, expr_context_ty ctx) { int check_ctx = 1; @@ -240,6 +284,12 @@ validate_expr(expr_ty exp, expr_context_ return validate_expr(exp->v.Call.func, Load) && validate_exprs(exp->v.Call.args, Load, 0) && validate_keywords(exp->v.Call.keywords);
- case Constant_kind:
if (!validate_constant(exp->v.Constant.value)) {[](#l10.59)
PyErr_SetString(PyExc_TypeError, "invalid type in Constant");[](#l10.60)
return 0;[](#l10.61)
}[](#l10.62)
case Num_kind: { PyObject *n = exp->v.Num.n; if (!PyLong_CheckExact(n) && !PyFloat_CheckExact(n) &&return 1;[](#l10.63)
--- a/Python/compile.c +++ b/Python/compile.c @@ -1314,7 +1314,11 @@ compiler_isdocstring(stmt_ty s) { if (s->kind != Expr_kind) return 0;
- if (s->v.Expr.value->kind == Str_kind)
return 1;[](#l11.9)
- if (s->v.Expr.value->kind == Constant_kind)
return PyUnicode_CheckExact(s->v.Expr.value->v.Constant.value);[](#l11.11)
- return 0;
} /* Compile a sequence of statements, checking for a docstring. */ @@ -1688,8 +1692,12 @@ compiler_function(struct compiler *c, st st = (stmt_ty)asdl_seq_GET(body, 0); docstring = compiler_isdocstring(st);
- if (docstring && c->c_optimize < 2) {
if (st->v.Expr.value->kind == Constant_kind)[](#l11.23)
first_const = st->v.Expr.value->v.Constant.value;[](#l11.24)
else[](#l11.25)
first_const = st->v.Expr.value->v.Str.s;[](#l11.26)
- } if (compiler_add_o(c, c->u->u_consts, first_const) < 0) { compiler_exit_scope(c); return 0;
@@ -2600,6 +2608,36 @@ compiler_assert(struct compiler *c, stmt } static int +compiler_visit_stmt_expr(struct compiler *c, expr_ty value) +{
- if (c->c_interactive && c->c_nestlevel <= 1) {
VISIT(c, expr, value);[](#l11.38)
ADDOP(c, PRINT_EXPR);[](#l11.39)
return 1;[](#l11.40)
- }
- if (value->kind == Str_kind || value->kind == Num_kind) {
/* ignore strings and numbers */[](#l11.44)
return 1;[](#l11.45)
- }
- if (value->kind == Constant_kind) {
PyObject *cst = value->v.Constant.value;[](#l11.49)
if (PyUnicode_CheckExact(cst)[](#l11.50)
|| PyLong_CheckExact(cst)[](#l11.51)
|| PyFloat_CheckExact(cst)[](#l11.52)
|| PyComplex_CheckExact(cst)) {[](#l11.53)
/* ignore strings and numbers */[](#l11.54)
return 1;[](#l11.55)
}[](#l11.56)
- }
+} + +static int compiler_visit_stmt(struct compiler *c, stmt_ty s) { Py_ssize_t i, n; @@ -2669,16 +2707,7 @@ compiler_visit_stmt(struct compiler *c, case Nonlocal_kind: break; case Expr_kind:
if (c->c_interactive && c->c_nestlevel <= 1) {[](#l11.72)
VISIT(c, expr, s->v.Expr.value);[](#l11.73)
ADDOP(c, PRINT_EXPR);[](#l11.74)
}[](#l11.75)
else if (s->v.Expr.value->kind != Str_kind &&[](#l11.76)
s->v.Expr.value->kind != Num_kind) {[](#l11.77)
VISIT(c, expr, s->v.Expr.value);[](#l11.78)
ADDOP(c, POP_TOP);[](#l11.79)
}[](#l11.80)
break;[](#l11.81)
case Pass_kind: break; case Break_kind: @@ -3625,6 +3654,8 @@ expr_constant(struct compiler *c, expr_t switch (e->kind) { case Ellipsis_kind: return 1;return compiler_visit_stmt_expr(c, s->v.Expr.value);[](#l11.82)
- case Constant_kind:
case Num_kind: return PyObject_IsTrue(e->v.Num.n); case Str_kind: @@ -3912,6 +3943,9 @@ compiler_visit_expr(struct compiler *c, return compiler_compare(c, e); case Call_kind: return compiler_call(c, e);return PyObject_IsTrue(e->v.Constant.value);[](#l11.91)
- case Constant_kind:
ADDOP_O(c, LOAD_CONST, e->v.Constant.value, consts);[](#l11.100)
case Num_kind: ADDOP_O(c, LOAD_CONST, e->v.Num.n, consts); break;break;[](#l11.101)
--- a/Python/future.c +++ b/Python/future.c @@ -79,7 +79,10 @@ future_parse(PyFutureFeatures *ff, mod_t i = 0; first = (stmt_ty)asdl_seq_GET(mod->v.Module.body, i);
- if (first->kind == Expr_kind
&& (first->v.Expr.value->kind == Str_kind[](#l12.9)
|| (first->v.Expr.value->kind == Constant_kind[](#l12.10)
&& PyUnicode_CheckExact(first->v.Expr.value->v.Constant.value))))[](#l12.11) i++;[](#l12.12)
--- a/Python/symtable.c +++ b/Python/symtable.c @@ -1455,6 +1455,7 @@ symtable_visit_expr(struct symtable *st, case JoinedStr_kind: VISIT_SEQ(st, expr, e->v.JoinedStr.values); break;
--- a/Tools/parser/unparse.py +++ b/Tools/parser/unparse.py @@ -343,6 +343,11 @@ class Unparser: value = t.s.replace("{", "{{").replace("}", "}}") write(value)
- def _fstring_Constant(self, t, write):
assert isinstance(t.value, str)[](#l14.8)
value = t.value.replace("{", "{{").replace("}", "}}")[](#l14.9)
write(value)[](#l14.10)
+ def _fstring_FormattedValue(self, t, write): write("{") expr = io.StringIO() @@ -364,6 +369,25 @@ class Unparser: def _Name(self, t): self.write(t.id)
- def _write_constant(self, value):
if isinstance(value, (float, complex)):[](#l14.20)
self.write(repr(value).replace("inf", INFSTR))[](#l14.21)
else:[](#l14.22)
self.write(repr(value))[](#l14.23)
- def _Constant(self, t):
value = t.value[](#l14.26)
if isinstance(value, tuple):[](#l14.27)
self.write("(")[](#l14.28)
if len(value) == 1:[](#l14.29)
self._write_constant(value[0])[](#l14.30)
self.write(",")[](#l14.31)
else:[](#l14.32)
interleave(lambda: self.write(", "), self._write_constant, value)[](#l14.33)
self.write(")")[](#l14.34)
else:[](#l14.35)
self._write_constant(t.value)[](#l14.36)
+ def _NameConstant(self, t): self.write(repr(t.value)) @@ -443,7 +467,7 @@ class Unparser: def _Tuple(self, t): self.write("(") if len(t.elts) == 1:
(elt,) = t.elts[](#l14.45)
elt = t.elts[0][](#l14.46) self.dispatch(elt)[](#l14.47) self.write(",")[](#l14.48) else:[](#l14.49)
@@ -490,7 +514,8 @@ class Unparser: # Special case: 3.abs() is a syntax error, so if t.value # is an integer literal then we need to either parenthesize # it or add an extra space to get 3 .abs().
if isinstance(t.value, ast.Num) and isinstance(t.value.n, int):[](#l14.54)
if ((isinstance(t.value, ast.Num) and isinstance(t.value.n, int))[](#l14.55)
or (isinstance(t.value, ast.Constant) and isinstance(t.value.value, int))):[](#l14.56) self.write(" ")[](#l14.57) self.write(".")[](#l14.58) self.write(t.attr)[](#l14.59)