bpo-34822: Simplify AST for subscription. (GH-9605)
* Remove the slice type.
* Make Slice a kind of the expr type instead of the slice type.
* Replace ExtSlice(slices) with Tuple(slices, Load()).
* Replace Index(value) with a value itself.
All non-terminal nodes in AST for expressions are now of the expr type.
diff --git a/Lib/ast.py b/Lib/ast.py
index 0bce4a4..8b88d0f 100644
--- a/Lib/ast.py
+++ b/Lib/ast.py
@@ -445,7 +445,7 @@
def visit_Name(self, node):
return copy_location(Subscript(
value=Name(id='data', ctx=Load()),
- slice=Index(value=Str(s=node.id)),
+ slice=Constant(value=node.id),
ctx=node.ctx
), node)
@@ -552,6 +552,7 @@
_const_types_not = {
Num: (bool,),
}
+
_const_node_type_names = {
bool: 'NameConstant', # should be before int
type(None): 'NameConstant',
@@ -563,6 +564,23 @@
type(...): 'Ellipsis',
}
+class Index(AST):
+ def __new__(cls, value, **kwargs):
+ return value
+
+class ExtSlice(AST):
+ def __new__(cls, dims=(), **kwargs):
+ return Tuple(list(dims), Load(), **kwargs)
+
+def _dims_getter(self):
+ return self.elts
+
+def _dims_setter(self, value):
+ self.elts = value
+
+Tuple.dims = property(_dims_getter, _dims_setter)
+
+
# Large float and imaginary literals get turned into infinities in the AST.
# We unparse those infinities to INFSTR.
_INFSTR = "1e" + repr(sys.float_info.max_10_exp + 1)
@@ -1268,10 +1286,8 @@
self.set_precedence(_Precedence.ATOM, node.value)
self.traverse(node.value)
with self.delimit("[", "]"):
- if (isinstance(node.slice, Index)
- and isinstance(node.slice.value, Tuple)
- and node.slice.value.elts):
- self.items_view(self.traverse, node.slice.value.elts)
+ if isinstance(node.slice, Tuple) and node.slice.elts:
+ self.items_view(self.traverse, node.slice.elts)
else:
self.traverse(node.slice)
@@ -1283,10 +1299,6 @@
def visit_Ellipsis(self, node):
self.write("...")
- def visit_Index(self, node):
- self.set_precedence(_Precedence.TUPLE, node.value)
- self.traverse(node.value)
-
def visit_Slice(self, node):
if node.lower:
self.traverse(node.lower)
@@ -1297,9 +1309,6 @@
self.write(":")
self.traverse(node.step)
- def visit_ExtSlice(self, node):
- self.items_view(self.traverse, node.dims)
-
def visit_arg(self, node):
self.write(node.arg)
if node.annotation:
diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
index c1e9f00..0058e93 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -343,6 +343,10 @@
def test_field_attr_existence(self):
for name, item in ast.__dict__.items():
if self._is_ast_node(name, item):
+ if name == 'Index':
+ # Index(value) just returns value now.
+ # The argument is required.
+ continue
x = item()
if isinstance(x, ast.AST):
self.assertEqual(type(x._fields), tuple)
@@ -1308,11 +1312,11 @@
self.expr(attr, "must have Load context")
def test_subscript(self):
- sub = ast.Subscript(ast.Name("x", ast.Store()), ast.Index(ast.Num(3)),
+ sub = ast.Subscript(ast.Name("x", ast.Store()), ast.Num(3),
ast.Load())
self.expr(sub, "must have Load context")
x = ast.Name("x", ast.Load())
- sub = ast.Subscript(x, ast.Index(ast.Name("y", ast.Store())),
+ sub = ast.Subscript(x, ast.Name("y", ast.Store()),
ast.Load())
self.expr(sub, "must have Load context")
s = ast.Name("x", ast.Store())
@@ -1320,9 +1324,9 @@
sl = ast.Slice(*args)
self.expr(ast.Subscript(x, sl, ast.Load()),
"must have Load context")
- sl = ast.ExtSlice([])
- self.expr(ast.Subscript(x, sl, ast.Load()), "empty dims on ExtSlice")
- sl = ast.ExtSlice([ast.Index(s)])
+ sl = ast.Tuple([], ast.Load())
+ self.expr(ast.Subscript(x, sl, ast.Load()))
+ sl = ast.Tuple([s], ast.Load())
self.expr(ast.Subscript(x, sl, ast.Load()), "must have Load context")
def test_starred(self):
@@ -1664,11 +1668,11 @@
''').strip()
i1, i2, im = map(self._parse_value, (s1, s2, sm))
self._check_content(s1, i1.value, 'f()[1, 2]')
- self._check_content(s1, i1.value.slice.value, '1, 2')
+ self._check_content(s1, i1.value.slice, '1, 2')
self._check_content(s2, i2.slice.lower, 'a.b')
self._check_content(s2, i2.slice.upper, 'c.d')
- self._check_content(sm, im.slice.dims[0].upper, 'f ()')
- self._check_content(sm, im.slice.dims[1].lower, 'g ()')
+ self._check_content(sm, im.slice.elts[0].upper, 'f ()')
+ self._check_content(sm, im.slice.elts[1].lower, 'g ()')
self._check_end_pos(im, 3, 3)
def test_binop(self):
@@ -1989,13 +1993,13 @@
('Expression', ('Constant', (1, 0, 1, 2), 10, None)),
('Expression', ('Constant', (1, 0, 1, 8), 'string', None)),
('Expression', ('Attribute', (1, 0, 1, 3), ('Name', (1, 0, 1, 1), 'a', ('Load',)), 'b', ('Load',))),
-('Expression', ('Subscript', (1, 0, 1, 6), ('Name', (1, 0, 1, 1), 'a', ('Load',)), ('Slice', ('Name', (1, 2, 1, 3), 'b', ('Load',)), ('Name', (1, 4, 1, 5), 'c', ('Load',)), None), ('Load',))),
+('Expression', ('Subscript', (1, 0, 1, 6), ('Name', (1, 0, 1, 1), 'a', ('Load',)), ('Slice', (1, 2, 1, 5), ('Name', (1, 2, 1, 3), 'b', ('Load',)), ('Name', (1, 4, 1, 5), 'c', ('Load',)), None), ('Load',))),
('Expression', ('Name', (1, 0, 1, 1), 'v', ('Load',))),
('Expression', ('List', (1, 0, 1, 7), [('Constant', (1, 1, 1, 2), 1, None), ('Constant', (1, 3, 1, 4), 2, None), ('Constant', (1, 5, 1, 6), 3, None)], ('Load',))),
('Expression', ('List', (1, 0, 1, 2), [], ('Load',))),
('Expression', ('Tuple', (1, 0, 1, 5), [('Constant', (1, 0, 1, 1), 1, None), ('Constant', (1, 2, 1, 3), 2, None), ('Constant', (1, 4, 1, 5), 3, None)], ('Load',))),
('Expression', ('Tuple', (1, 0, 1, 7), [('Constant', (1, 1, 1, 2), 1, None), ('Constant', (1, 3, 1, 4), 2, None), ('Constant', (1, 5, 1, 6), 3, None)], ('Load',))),
('Expression', ('Tuple', (1, 0, 1, 2), [], ('Load',))),
-('Expression', ('Call', (1, 0, 1, 17), ('Attribute', (1, 0, 1, 7), ('Attribute', (1, 0, 1, 5), ('Attribute', (1, 0, 1, 3), ('Name', (1, 0, 1, 1), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',)), 'd', ('Load',)), [('Subscript', (1, 8, 1, 16), ('Attribute', (1, 8, 1, 11), ('Name', (1, 8, 1, 9), 'a', ('Load',)), 'b', ('Load',)), ('Slice', ('Constant', (1, 12, 1, 13), 1, None), ('Constant', (1, 14, 1, 15), 2, None), None), ('Load',))], [])),
+('Expression', ('Call', (1, 0, 1, 17), ('Attribute', (1, 0, 1, 7), ('Attribute', (1, 0, 1, 5), ('Attribute', (1, 0, 1, 3), ('Name', (1, 0, 1, 1), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',)), 'd', ('Load',)), [('Subscript', (1, 8, 1, 16), ('Attribute', (1, 8, 1, 11), ('Name', (1, 8, 1, 9), 'a', ('Load',)), 'b', ('Load',)), ('Slice', (1, 12, 1, 15), ('Constant', (1, 12, 1, 13), 1, None), ('Constant', (1, 14, 1, 15), 2, None), None), ('Load',))], [])),
]
main()
diff --git a/Lib/test/test_type_comments.py b/Lib/test/test_type_comments.py
index 43be54e..017073a 100644
--- a/Lib/test/test_type_comments.py
+++ b/Lib/test/test_type_comments.py
@@ -390,7 +390,7 @@
arg = tree.argtypes[0]
self.assertEqual(arg.id, "int")
self.assertEqual(tree.returns.value.id, "List")
- self.assertEqual(tree.returns.slice.value.id, "str")
+ self.assertEqual(tree.returns.slice.id, "str")
tree = parse_func_type_input("(int, *str, **Any) -> float")
self.assertEqual(tree.argtypes[0].id, "int")