From aa7d54817a0c1854be8548ef14a0cd994b02ae1d Mon Sep 17 00:00:00 2001 From: CPython Developers <> Date: Wed, 17 Aug 2022 03:09:19 +0900 Subject: [PATCH 01/11] Update test_future from CPython 3.10.6 --- Lib/test/test_future.py | 81 ++++++++++++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/Lib/test/test_future.py b/Lib/test/test_future.py index 9be4eca8e..5a3944e69 100644 --- a/Lib/test/test_future.py +++ b/Lib/test/test_future.py @@ -78,13 +78,6 @@ class FutureTest(unittest.TestCase): from test import badsyntax_future10 self.check_syntax_error(cm.exception, "badsyntax_future10", 3) - k, v = None, None # 'dictionary changed size during iteration' - for k, v in locals().items(): - if k.startswith("test_badfuture"): - # XXX RUSTPYTHON TODO: fix SyntaxError - locals()[k] = unittest.expectedFailure(v) - del k, v - def test_ensure_flags_dont_clash(self): # bpo-39562: test that future flags and compiler flags doesn't clash @@ -141,8 +134,12 @@ class AnnotationsFutureTestCase(unittest.TestCase): ... async def g2(arg: {ann}) -> None: ... + class H: + var: {ann} + object.attr: {ann} var: {ann} var2: {ann} = None + object.attr: {ann} """ ) @@ -174,6 +171,14 @@ class AnnotationsFutureTestCase(unittest.TestCase): self.assertEqual(actual, expected) + def _exec_future(self, code): + scope = {} + exec( + "from __future__ import annotations\n" + + code, {}, scope + ) + return scope + def test_annotations(self): eq = self.assertAnnotationEqual eq('...') @@ -313,10 +318,6 @@ class AnnotationsFutureTestCase(unittest.TestCase): eq("f'{x}'") eq("f'{x!r}'") eq("f'{x!a}'") - eq('(yield from outside_of_generator)') - eq('(yield)') - eq('(yield a + b)') - eq('await some.complicated[0].call(with_args=True or 1 is not 1)') eq('[x for x in (a if b else c)]') eq('[x for x in a if (b if c else d)]') eq('f(x for x in a)') @@ -324,13 +325,11 @@ class AnnotationsFutureTestCase(unittest.TestCase): eq('f((x for x in a), 2)') eq('(((a)))', 'a') eq('(((a, b)))', '(a, b)') - eq("(x := 10)") - eq("f'{(x := 10):=10}'") eq("1 + 2 + 3") def test_fstring_debug_annotations(self): # f-strings with '=' don't round trip very well, so set the expected - # result explicitely. + # result explicitly. self.assertAnnotationEqual("f'{x=!r}'", expected="f'x={x!r}'") self.assertAnnotationEqual("f'{x=:}'", expected="f'x={x:}'") self.assertAnnotationEqual("f'{x=:.2f}'", expected="f'x={x:.2f}'") @@ -350,6 +349,60 @@ class AnnotationsFutureTestCase(unittest.TestCase): self.assertAnnotationEqual("('inf', 1e1000, 'infxxx', 1e1000j)", expected=f"('inf', {inf}, 'infxxx', {infj})") self.assertAnnotationEqual("(1e1000, (1e1000j,))", expected=f"({inf}, ({infj},))") + def test_annotation_with_complex_target(self): + with self.assertRaises(SyntaxError): + exec( + "from __future__ import annotations\n" + "object.__debug__: int" + ) + + def test_annotations_symbol_table_pass(self): + namespace = self._exec_future(dedent(""" + from __future__ import annotations + + def foo(): + outer = 1 + def bar(): + inner: outer = 1 + return bar + """)) + + foo = namespace.pop("foo") + self.assertIsNone(foo().__closure__) + self.assertEqual(foo.__code__.co_cellvars, ()) + self.assertEqual(foo().__code__.co_freevars, ()) + + def test_annotations_forbidden(self): + with self.assertRaises(SyntaxError): + self._exec_future("test: (yield)") + + with self.assertRaises(SyntaxError): + self._exec_future("test.test: (yield a + b)") + + with self.assertRaises(SyntaxError): + self._exec_future("test[something]: (yield from x)") + + with self.assertRaises(SyntaxError): + self._exec_future("def func(test: (yield from outside_of_generator)): pass") + + with self.assertRaises(SyntaxError): + self._exec_future("def test() -> (await y): pass") + + with self.assertRaises(SyntaxError): + self._exec_future("async def test() -> something((a := b)): pass") + + with self.assertRaises(SyntaxError): + self._exec_future("test: await some.complicated[0].call(with_args=True or 1 is not 1)") + + with self.assertRaises(SyntaxError): + self._exec_future("test: f'{(x := 10):=10}'") + + with self.assertRaises(SyntaxError): + self._exec_future(dedent("""\ + def foo(): + def bar(arg: (yield)): pass + """)) + if __name__ == "__main__": unittest.main() From c995f37ec2e0d0f882473beace7abe8269faa1a3 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 17 Aug 2022 03:13:48 +0900 Subject: [PATCH 02/11] Add failing markers to test_future --- Lib/test/test_future.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Lib/test/test_future.py b/Lib/test/test_future.py index 5a3944e69..dfd4c0644 100644 --- a/Lib/test/test_future.py +++ b/Lib/test/test_future.py @@ -38,41 +38,57 @@ class FutureTest(unittest.TestCase): with import_helper.CleanImport('test_future3'): from test import test_future3 + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_badfuture3(self): with self.assertRaises(SyntaxError) as cm: from test import badsyntax_future3 self.check_syntax_error(cm.exception, "badsyntax_future3", 3) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_badfuture4(self): with self.assertRaises(SyntaxError) as cm: from test import badsyntax_future4 self.check_syntax_error(cm.exception, "badsyntax_future4", 3) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_badfuture5(self): with self.assertRaises(SyntaxError) as cm: from test import badsyntax_future5 self.check_syntax_error(cm.exception, "badsyntax_future5", 4) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_badfuture6(self): with self.assertRaises(SyntaxError) as cm: from test import badsyntax_future6 self.check_syntax_error(cm.exception, "badsyntax_future6", 3) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_badfuture7(self): with self.assertRaises(SyntaxError) as cm: from test import badsyntax_future7 self.check_syntax_error(cm.exception, "badsyntax_future7", 3, 53) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_badfuture8(self): with self.assertRaises(SyntaxError) as cm: from test import badsyntax_future8 self.check_syntax_error(cm.exception, "badsyntax_future8", 3) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_badfuture9(self): with self.assertRaises(SyntaxError) as cm: from test import badsyntax_future9 self.check_syntax_error(cm.exception, "badsyntax_future9", 3) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_badfuture10(self): with self.assertRaises(SyntaxError) as cm: from test import badsyntax_future10 @@ -349,6 +365,8 @@ class AnnotationsFutureTestCase(unittest.TestCase): self.assertAnnotationEqual("('inf', 1e1000, 'infxxx', 1e1000j)", expected=f"('inf', {inf}, 'infxxx', {infj})") self.assertAnnotationEqual("(1e1000, (1e1000j,))", expected=f"({inf}, ({infj},))") + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_annotation_with_complex_target(self): with self.assertRaises(SyntaxError): exec( @@ -356,6 +374,8 @@ class AnnotationsFutureTestCase(unittest.TestCase): "object.__debug__: int" ) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_annotations_symbol_table_pass(self): namespace = self._exec_future(dedent(""" from __future__ import annotations @@ -372,6 +392,8 @@ class AnnotationsFutureTestCase(unittest.TestCase): self.assertEqual(foo.__code__.co_cellvars, ()) self.assertEqual(foo().__code__.co_freevars, ()) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_annotations_forbidden(self): with self.assertRaises(SyntaxError): self._exec_future("test: (yield)") From f108d97353f7edbee76a2673c98ae42af1c4b2e5 Mon Sep 17 00:00:00 2001 From: CPython Developers <> Date: Thu, 11 Aug 2022 07:29:18 +0900 Subject: [PATCH 03/11] Update {test_}ast.py from CPython 3.10.6 --- Lib/ast.py | 109 ++++++- Lib/test/test_ast.py | 678 ++++++++++++++++++++++++++++++++++--------- 2 files changed, 648 insertions(+), 139 deletions(-) diff --git a/Lib/ast.py b/Lib/ast.py index bfca4c3e2..f4d2f6e42 100644 --- a/Lib/ast.py +++ b/Lib/ast.py @@ -47,8 +47,8 @@ def parse(source, filename='', mode='exec', *, elif feature_version is None: feature_version = -1 # Else it should be an int giving the minor version for 3.x. - return compile(source, filename, mode, flags) - # _feature_version=feature_version) + return compile(source, filename, mode, flags, + _feature_version=feature_version) def literal_eval(node_or_string): @@ -59,11 +59,14 @@ def literal_eval(node_or_string): sets, booleans, and None. """ if isinstance(node_or_string, str): - node_or_string = parse(node_or_string, mode='eval') + node_or_string = parse(node_or_string.lstrip(" \t"), mode='eval') if isinstance(node_or_string, Expression): node_or_string = node_or_string.body def _raise_malformed_node(node): - raise ValueError(f'malformed node or string: {node!r}') + msg = "malformed node or string" + if lno := getattr(node, 'lineno', None): + msg += f' on line {lno}' + raise ValueError(msg + f': {node!r}') def _convert_num(node): if not isinstance(node, Constant) or type(node.value) not in (int, float, complex): _raise_malformed_node(node) @@ -794,6 +797,9 @@ class _Unparser(NodeVisitor): else: super().visit(node) + # Note: as visit() resets the output text, do NOT rely on + # NodeVisitor.generic_visit to handle any nodes (as it calls back in to + # the subclass visit() method, which resets self._source to an empty list) def visit(self, node): """Outputs a source code string that, if converted back to an ast (using ast.parse) will generate an AST equivalent to *node*""" @@ -1483,6 +1489,13 @@ class _Unparser(NodeVisitor): self.write(":") self.traverse(node.step) + def visit_Match(self, node): + self.fill("match ") + self.traverse(node.subject) + with self.block(): + for case in node.cases: + self.traverse(case) + def visit_arg(self, node): self.write(node.arg) if node.annotation: @@ -1567,6 +1580,94 @@ class _Unparser(NodeVisitor): self.write(" as ") self.traverse(node.optional_vars) + def visit_match_case(self, node): + self.fill("case ") + self.traverse(node.pattern) + if node.guard: + self.write(" if ") + self.traverse(node.guard) + with self.block(): + self.traverse(node.body) + + def visit_MatchValue(self, node): + self.traverse(node.value) + + def visit_MatchSingleton(self, node): + self._write_constant(node.value) + + def visit_MatchSequence(self, node): + with self.delimit("[", "]"): + self.interleave( + lambda: self.write(", "), self.traverse, node.patterns + ) + + def visit_MatchStar(self, node): + name = node.name + if name is None: + name = "_" + self.write(f"*{name}") + + def visit_MatchMapping(self, node): + def write_key_pattern_pair(pair): + k, p = pair + self.traverse(k) + self.write(": ") + self.traverse(p) + + with self.delimit("{", "}"): + keys = node.keys + self.interleave( + lambda: self.write(", "), + write_key_pattern_pair, + zip(keys, node.patterns, strict=True), + ) + rest = node.rest + if rest is not None: + if keys: + self.write(", ") + self.write(f"**{rest}") + + def visit_MatchClass(self, node): + self.set_precedence(_Precedence.ATOM, node.cls) + self.traverse(node.cls) + with self.delimit("(", ")"): + patterns = node.patterns + self.interleave( + lambda: self.write(", "), self.traverse, patterns + ) + attrs = node.kwd_attrs + if attrs: + def write_attr_pattern(pair): + attr, pattern = pair + self.write(f"{attr}=") + self.traverse(pattern) + + if patterns: + self.write(", ") + self.interleave( + lambda: self.write(", "), + write_attr_pattern, + zip(attrs, node.kwd_patterns, strict=True), + ) + + def visit_MatchAs(self, node): + name = node.name + pattern = node.pattern + if name is None: + self.write("_") + elif pattern is None: + self.write(node.name) + else: + with self.require_parens(_Precedence.TEST, node): + self.set_precedence(_Precedence.BOR, node.pattern) + self.traverse(node.pattern) + self.write(f" as {node.name}") + + def visit_MatchOr(self, node): + with self.require_parens(_Precedence.BOR, node): + self.set_precedence(_Precedence.BOR.next(), *node.patterns) + self.interleave(lambda: self.write(" | "), self.traverse, node.patterns) + def unparse(ast_obj): unparser = _Unparser() return unparser.visit(ast_obj) diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index f5c80b68d..953618e3b 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -1,7 +1,9 @@ import ast +import builtins import dis import os import sys +import types import unittest import warnings import weakref @@ -17,6 +19,8 @@ def to_tuple(t): result = [t.__class__.__name__] if hasattr(t, 'lineno') and hasattr(t, 'col_offset'): result.append((t.lineno, t.col_offset)) + if hasattr(t, 'end_lineno') and hasattr(t, 'end_col_offset'): + result[-1] += (t.end_lineno, t.end_col_offset) if t._fields is None: return tuple(result) for f in t._fields: @@ -245,6 +249,13 @@ eval_tests = [ class AST_Tests(unittest.TestCase): + def _is_ast_node(self, name, node): + if not isinstance(node, type): + return False + if "ast" not in node.__module__: + return False + return name != 'AST' and name[0].isupper() + def _assertTrueorder(self, ast_node, parent_pos): if not isinstance(ast_node, ast.AST) or ast_node._fields is None: return @@ -262,6 +273,7 @@ class AST_Tests(unittest.TestCase): self._assertTrueorder(child, first_pos) elif value is not None: self._assertTrueorder(value, parent_pos) + self.assertEqual(ast_node._fields, ast_node.__match_args__) # TODO: RUSTPYTHON @unittest.expectedFailure @@ -276,7 +288,7 @@ class AST_Tests(unittest.TestCase): x.vararg with self.assertRaises(TypeError): - # "_ast.AST constructor takes 0 positional arguments" + # "ast.AST constructor takes 0 positional arguments" ast.AST(2) # TODO: RUSTPYTHON @@ -329,6 +341,26 @@ class AST_Tests(unittest.TestCase): mod.body[0].module = " __future__ ".strip() compile(mod, "", "exec") + def test_alias(self): + im = ast.parse("from bar import y").body[0] + self.assertEqual(len(im.names), 1) + alias = im.names[0] + self.assertEqual(alias.name, 'y') + self.assertIsNone(alias.asname) + self.assertEqual(alias.lineno, 1) + self.assertEqual(alias.end_lineno, 1) + self.assertEqual(alias.col_offset, 16) + self.assertEqual(alias.end_col_offset, 17) + + im = ast.parse("from bar import *").body[0] + alias = im.names[0] + self.assertEqual(alias.name, '*') + self.assertIsNone(alias.asname) + self.assertEqual(alias.lineno, 1) + self.assertEqual(alias.end_lineno, 1) + self.assertEqual(alias.col_offset, 16) + self.assertEqual(alias.end_col_offset, 17) + def test_base_classes(self): self.assertTrue(issubclass(ast.For, ast.stmt)) self.assertTrue(issubclass(ast.Name, ast.expr)) @@ -341,7 +373,11 @@ class AST_Tests(unittest.TestCase): @unittest.expectedFailure def test_field_attr_existence(self): for name, item in ast.__dict__.items(): - if isinstance(item, type) and name != 'AST' and name[0].isupper(): + 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) @@ -354,9 +390,11 @@ class AST_Tests(unittest.TestCase): 'kw_defaults', 'kwarg', 'defaults')) with self.assertRaises(AttributeError): - x.vararg + x.args + self.assertIsNone(x.vararg) x = ast.arguments(*range(1, 8)) + self.assertEqual(x.args, 2) self.assertEqual(x.vararg, 3) def test_field_attr_writable(self): @@ -587,17 +625,26 @@ class AST_Tests(unittest.TestCase): m = ast.Module([ast.Expr(ast.expr(**pos), **pos)], []) with self.assertRaises(TypeError) as cm: compile(m, "", "exec") - self.assertIn("but got <_ast.expr", str(cm.exception)) + self.assertIn("but got ", "exec") self.assertIn("identifier must be of type str", str(cm.exception)) + def test_invalid_constant(self): + for invalid_constant in int, (1, 2, int), frozenset((1, 2, int)): + e = ast.Expression(body=ast.Constant(invalid_constant)) + ast.fix_missing_locations(e) + with self.assertRaisesRegex( + TypeError, "invalid type in Constant: type" + ): + compile(e, "", "eval") + # TODO: RUSTPYTHON @unittest.expectedFailure def test_empty_yield_from(self): @@ -606,7 +653,7 @@ class AST_Tests(unittest.TestCase): empty_yield_from.body[0].body[0].value.value = None with self.assertRaises(ValueError) as cm: compile(empty_yield_from, "", "exec") - self.assertIn("field value is required", str(cm.exception)) + self.assertIn("field 'value' is required", str(cm.exception)) @support.cpython_only def test_issue31592(self): @@ -658,6 +705,23 @@ class AST_Tests(unittest.TestCase): attr_b = tree.body[0].decorator_list[0].value self.assertEqual(attr_b.end_col_offset, 4) + def test_ast_asdl_signature(self): + self.assertEqual(ast.withitem.__doc__, "withitem(expr context_expr, expr? optional_vars)") + self.assertEqual(ast.GtE.__doc__, "GtE") + self.assertEqual(ast.Name.__doc__, "Name(identifier id, expr_context ctx)") + self.assertEqual(ast.cmpop.__doc__, "cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn") + expressions = [f" | {node.__doc__}" for node in ast.expr.__subclasses__()] + expressions[0] = f"expr = {ast.expr.__subclasses__()[0].__doc__}" + self.assertCountEqual(ast.expr.__doc__.split("\n"), expressions) + + def test_parenthesized_with_feature_version(self): + ast.parse('with (CtxManager() as example): ...', feature_version=(3, 10)) + # While advertised as a feature in Python 3.10, this was allowed starting 3.9 + ast.parse('with (CtxManager() as example): ...', feature_version=(3, 9)) + with self.assertRaises(SyntaxError): + ast.parse('with (CtxManager() as example): ...', feature_version=(3, 8)) + ast.parse('with CtxManager() as example: ...', feature_version=(3, 8)) + # TODO: RUSTPYTHON @unittest.expectedFailure def test_issue40614_feature_version(self): @@ -665,13 +729,18 @@ class AST_Tests(unittest.TestCase): with self.assertRaises(SyntaxError): ast.parse('f"{x=}"', feature_version=(3, 7)) + def test_assignment_expression_feature_version(self): + ast.parse('(x := 0)', feature_version=(3, 8)) + with self.assertRaises(SyntaxError): + ast.parse('(x := 0)', feature_version=(3, 7)) + # TODO: RUSTPYTHON @unittest.expectedFailure def test_constant_as_name(self): for constant in "True", "False", "None": expr = ast.Expression(ast.Name(constant, ast.Load())) ast.fix_missing_locations(expr) - with self.assertRaisesRegex(ValueError, f"Name node can't be used with '{constant}' constant"): + with self.assertRaisesRegex(ValueError, f"identifier field can't represent '{constant}' constant"): compile(expr, "", "eval") @@ -699,23 +768,84 @@ class ASTHelpers_Test(unittest.TestCase): node = ast.parse('spam(eggs, "and cheese")') self.assertEqual(ast.dump(node), "Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load()), " - "args=[Name(id='eggs', ctx=Load()), Constant(value='and cheese', kind=None)], " + "args=[Name(id='eggs', ctx=Load()), Constant(value='and cheese')], " "keywords=[]))], type_ignores=[])" ) self.assertEqual(ast.dump(node, annotate_fields=False), "Module([Expr(Call(Name('spam', Load()), [Name('eggs', Load()), " - "Constant('and cheese', None)], []))], [])" + "Constant('and cheese')], []))], [])" ) self.assertEqual(ast.dump(node, include_attributes=True), "Module(body=[Expr(value=Call(func=Name(id='spam', ctx=Load(), " "lineno=1, col_offset=0, end_lineno=1, end_col_offset=4), " "args=[Name(id='eggs', ctx=Load(), lineno=1, col_offset=5, " - "end_lineno=1, end_col_offset=9), Constant(value='and cheese', kind=None, " + "end_lineno=1, end_col_offset=9), Constant(value='and cheese', " "lineno=1, col_offset=11, end_lineno=1, end_col_offset=23)], keywords=[], " "lineno=1, col_offset=0, end_lineno=1, end_col_offset=24), " "lineno=1, col_offset=0, end_lineno=1, end_col_offset=24)], type_ignores=[])" ) + def test_dump_indent(self): + node = ast.parse('spam(eggs, "and cheese")') + self.assertEqual(ast.dump(node, indent=3), """\ +Module( + body=[ + Expr( + value=Call( + func=Name(id='spam', ctx=Load()), + args=[ + Name(id='eggs', ctx=Load()), + Constant(value='and cheese')], + keywords=[]))], + type_ignores=[])""") + self.assertEqual(ast.dump(node, annotate_fields=False, indent='\t'), """\ +Module( +\t[ +\t\tExpr( +\t\t\tCall( +\t\t\t\tName('spam', Load()), +\t\t\t\t[ +\t\t\t\t\tName('eggs', Load()), +\t\t\t\t\tConstant('and cheese')], +\t\t\t\t[]))], +\t[])""") + self.assertEqual(ast.dump(node, include_attributes=True, indent=3), """\ +Module( + body=[ + Expr( + value=Call( + func=Name( + id='spam', + ctx=Load(), + lineno=1, + col_offset=0, + end_lineno=1, + end_col_offset=4), + args=[ + Name( + id='eggs', + ctx=Load(), + lineno=1, + col_offset=5, + end_lineno=1, + end_col_offset=9), + Constant( + value='and cheese', + lineno=1, + col_offset=11, + end_lineno=1, + end_col_offset=23)], + keywords=[], + lineno=1, + col_offset=0, + end_lineno=1, + end_col_offset=24), + lineno=1, + col_offset=0, + end_lineno=1, + end_col_offset=24)], + type_ignores=[])""") + def test_dump_incomplete(self): node = ast.Raise(lineno=3, col_offset=4) self.assertEqual(ast.dump(node), @@ -751,16 +881,13 @@ class ASTHelpers_Test(unittest.TestCase): src = ast.parse('1 + 1', mode='eval') src.body.right = ast.copy_location(ast.Num(2), src.body.right) self.assertEqual(ast.dump(src, include_attributes=True), - 'Expression(body=BinOp(left=Constant(value=1, kind=None, lineno=1, col_offset=0, ' + 'Expression(body=BinOp(left=Constant(value=1, lineno=1, col_offset=0, ' 'end_lineno=1, end_col_offset=1), op=Add(), right=Constant(value=2, ' 'lineno=1, col_offset=4, end_lineno=1, end_col_offset=5), lineno=1, ' 'col_offset=0, end_lineno=1, end_col_offset=5))' ) src = ast.Call(col_offset=1, lineno=1, end_lineno=1, end_col_offset=1) - new = ast.copy_location(src, ast.Call( - col_offset=None, lineno=None, - end_lineno=None, end_col_offset=None - )) + new = ast.copy_location(src, ast.Call(col_offset=None, lineno=None)) self.assertIsNone(new.end_lineno) self.assertIsNone(new.end_col_offset) self.assertEqual(new.lineno, 1) @@ -777,7 +904,7 @@ class ASTHelpers_Test(unittest.TestCase): self.assertEqual(ast.dump(src, include_attributes=True), "Module(body=[Expr(value=Call(func=Name(id='write', ctx=Load(), " "lineno=1, col_offset=0, end_lineno=1, end_col_offset=5), " - "args=[Constant(value='spam', kind=None, lineno=1, col_offset=6, end_lineno=1, " + "args=[Constant(value='spam', lineno=1, col_offset=6, end_lineno=1, " "end_col_offset=12)], keywords=[], lineno=1, col_offset=0, end_lineno=1, " "end_col_offset=13), lineno=1, col_offset=0, end_lineno=1, " "end_col_offset=13), Expr(value=Call(func=Name(id='spam', ctx=Load(), " @@ -794,8 +921,8 @@ class ASTHelpers_Test(unittest.TestCase): src = ast.parse('1 + 1', mode='eval') self.assertEqual(ast.increment_lineno(src, n=3), src) self.assertEqual(ast.dump(src, include_attributes=True), - 'Expression(body=BinOp(left=Constant(value=1, kind=None, lineno=4, col_offset=0, ' - 'end_lineno=4, end_col_offset=1), op=Add(), right=Constant(value=1, kind=None, ' + 'Expression(body=BinOp(left=Constant(value=1, lineno=4, col_offset=0, ' + 'end_lineno=4, end_col_offset=1), op=Add(), right=Constant(value=1, ' 'lineno=4, col_offset=4, end_lineno=4, end_col_offset=5), lineno=4, ' 'col_offset=0, end_lineno=4, end_col_offset=5))' ) @@ -803,14 +930,13 @@ class ASTHelpers_Test(unittest.TestCase): src = ast.parse('1 + 1', mode='eval') self.assertEqual(ast.increment_lineno(src.body, n=3), src.body) self.assertEqual(ast.dump(src, include_attributes=True), - 'Expression(body=BinOp(left=Constant(value=1, kind=None, lineno=4, col_offset=0, ' - 'end_lineno=4, end_col_offset=1), op=Add(), right=Constant(value=1, kind=None, ' + 'Expression(body=BinOp(left=Constant(value=1, lineno=4, col_offset=0, ' + 'end_lineno=4, end_col_offset=1), op=Add(), right=Constant(value=1, ' 'lineno=4, col_offset=4, end_lineno=4, end_col_offset=5), lineno=4, ' 'col_offset=0, end_lineno=4, end_col_offset=5))' ) src = ast.Call( - func=ast.Name("test", ast.Load()), args=[], keywords=[], - lineno=1, end_lineno=None + func=ast.Name("test", ast.Load()), args=[], keywords=[], lineno=1 ) self.assertEqual(ast.increment_lineno(src).lineno, 2) self.assertIsNone(ast.increment_lineno(src).end_lineno) @@ -829,7 +955,7 @@ class ASTHelpers_Test(unittest.TestCase): self.assertEqual(next(iterator).value, 23) self.assertEqual(next(iterator).value, 42) self.assertEqual(ast.dump(next(iterator)), - "keyword(arg='eggs', value=Constant(value='leek', kind=None))" + "keyword(arg='eggs', value=Constant(value='leek'))" ) def test_get_docstring(self): @@ -923,6 +1049,7 @@ class ASTHelpers_Test(unittest.TestCase): self.assertEqual(ast.literal_eval('(True, False, None)'), (True, False, None)) self.assertEqual(ast.literal_eval('{1, 2, 3}'), {1, 2, 3}) self.assertEqual(ast.literal_eval('b"hi"'), b"hi") + self.assertEqual(ast.literal_eval('set()'), set()) self.assertRaises(ValueError, ast.literal_eval, 'foo()') self.assertEqual(ast.literal_eval('6'), 6) self.assertEqual(ast.literal_eval('+6'), 6) @@ -962,6 +1089,31 @@ class ASTHelpers_Test(unittest.TestCase): malformed = ast.Dict(keys=[ast.Constant(1)], values=[ast.Constant(2), ast.Constant(3)]) self.assertRaises(ValueError, ast.literal_eval, malformed) + def test_literal_eval_trailing_ws(self): + self.assertEqual(ast.literal_eval(" -1"), -1) + self.assertEqual(ast.literal_eval("\t\t-1"), -1) + self.assertEqual(ast.literal_eval(" \t -1"), -1) + self.assertRaises(IndentationError, ast.literal_eval, "\n -1") + + def test_literal_eval_malformed_lineno(self): + msg = r'malformed node or string on line 3:' + with self.assertRaisesRegex(ValueError, msg): + ast.literal_eval("{'a': 1,\n'b':2,\n'c':++3,\n'd':4}") + + node = ast.UnaryOp( + ast.UAdd(), ast.UnaryOp(ast.UAdd(), ast.Constant(6))) + self.assertIsNone(getattr(node, 'lineno', None)) + msg = r'malformed node or string:' + with self.assertRaisesRegex(ValueError, msg): + ast.literal_eval(node) + + def test_literal_eval_syntax_errors(self): + with self.assertRaisesRegex(SyntaxError, "unexpected indent"): + ast.literal_eval(r''' + \ + (\ + \ ''') + # TODO: RUSTPYTHON @unittest.expectedFailure def test_bad_integer(self): @@ -979,7 +1131,8 @@ class ASTHelpers_Test(unittest.TestCase): @unittest.expectedFailure def test_level_as_none(self): body = [ast.ImportFrom(module='time', - names=[ast.alias(name='sleep')], + names=[ast.alias(name='sleep', + lineno=0, col_offset=0)], level=None, lineno=0, col_offset=0)] mod = ast.Module(body, []) @@ -988,6 +1141,22 @@ class ASTHelpers_Test(unittest.TestCase): exec(code, ns) self.assertIn('sleep', ns) + def test_recursion_direct(self): + e = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0) + e.operand = e + with self.assertRaises(RecursionError): + with support.infinite_recursion(): + compile(ast.Expression(e), "", "eval") + + def test_recursion_indirect(self): + e = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0) + f = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0) + e.operand = f + f.operand = e + with self.assertRaises(RecursionError): + with support.infinite_recursion(): + compile(ast.Expression(e), "", "eval") + class ASTValidatorTests(unittest.TestCase): @@ -1398,11 +1567,11 @@ class ASTValidatorTests(unittest.TestCase): # TODO: RUSTPYTHON @unittest.expectedFailure 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()) @@ -1410,9 +1579,9 @@ class ASTValidatorTests(unittest.TestCase): 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") # TODO: RUSTPYTHON @@ -1455,6 +1624,151 @@ class ASTValidatorTests(unittest.TestCase): mod = ast.parse(source, fn) compile(mod, fn, "exec") + constant_1 = ast.Constant(1) + pattern_1 = ast.MatchValue(constant_1) + + constant_x = ast.Constant('x') + pattern_x = ast.MatchValue(constant_x) + + constant_true = ast.Constant(True) + pattern_true = ast.MatchSingleton(True) + + name_carter = ast.Name('carter', ast.Load()) + + _MATCH_PATTERNS = [ + ast.MatchValue( + ast.Attribute( + ast.Attribute( + ast.Name('x', ast.Store()), + 'y', ast.Load() + ), + 'z', ast.Load() + ) + ), + ast.MatchValue( + ast.Attribute( + ast.Attribute( + ast.Name('x', ast.Load()), + 'y', ast.Store() + ), + 'z', ast.Load() + ) + ), + ast.MatchValue( + ast.Constant(...) + ), + ast.MatchValue( + ast.Constant(True) + ), + ast.MatchValue( + ast.Constant((1,2,3)) + ), + ast.MatchSingleton('string'), + ast.MatchSequence([ + ast.MatchSingleton('string') + ]), + ast.MatchSequence( + [ + ast.MatchSequence( + [ + ast.MatchSingleton('string') + ] + ) + ] + ), + ast.MatchMapping( + [constant_1, constant_true], + [pattern_x] + ), + ast.MatchMapping( + [constant_true, constant_1], + [pattern_x, pattern_1], + rest='True' + ), + ast.MatchMapping( + [constant_true, ast.Starred(ast.Name('lol', ast.Load()), ast.Load())], + [pattern_x, pattern_1], + rest='legit' + ), + ast.MatchClass( + ast.Attribute( + ast.Attribute( + constant_x, + 'y', ast.Load()), + 'z', ast.Load()), + patterns=[], kwd_attrs=[], kwd_patterns=[] + ), + ast.MatchClass( + name_carter, + patterns=[], + kwd_attrs=['True'], + kwd_patterns=[pattern_1] + ), + ast.MatchClass( + name_carter, + patterns=[], + kwd_attrs=[], + kwd_patterns=[pattern_1] + ), + ast.MatchClass( + name_carter, + patterns=[ast.MatchSingleton('string')], + kwd_attrs=[], + kwd_patterns=[] + ), + ast.MatchClass( + name_carter, + patterns=[ast.MatchStar()], + kwd_attrs=[], + kwd_patterns=[] + ), + ast.MatchClass( + name_carter, + patterns=[], + kwd_attrs=[], + kwd_patterns=[ast.MatchStar()] + ), + ast.MatchSequence( + [ + ast.MatchStar("True") + ] + ), + ast.MatchAs( + name='False' + ), + ast.MatchOr( + [] + ), + ast.MatchOr( + [pattern_1] + ), + ast.MatchOr( + [pattern_1, pattern_x, ast.MatchSingleton('xxx')] + ), + ast.MatchAs(name="_"), + ast.MatchStar(name="x"), + ast.MatchSequence([ast.MatchStar("_")]), + ast.MatchMapping([], [], rest="_"), + ] + + def test_match_validation_pattern(self): + name_x = ast.Name('x', ast.Load()) + for pattern in self._MATCH_PATTERNS: + with self.subTest(ast.dump(pattern, indent=4)): + node = ast.Match( + subject=name_x, + cases = [ + ast.match_case( + pattern=pattern, + body = [ast.Pass()] + ) + ] + ) + node = ast.fix_missing_locations(node) + module = ast.Module([node], []) + with self.assertRaises(ValueError): + compile(module, "", "exec") + class ConstantTests(unittest.TestCase): """Tests on the ast.Constant node type.""" @@ -1783,6 +2097,7 @@ class EndPositionTests(unittest.TestCase): ''').strip() imp = ast.parse(s).body[0] self._check_end_pos(imp, 3, 1) + self._check_end_pos(imp.names[2], 2, 16) # TODO: RUSTPYTHON @unittest.expectedFailure @@ -1796,11 +2111,11 @@ class EndPositionTests(unittest.TestCase): ''').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) # TODO: RUSTPYTHON @@ -1980,6 +2295,17 @@ class EndPositionTests(unittest.TestCase): cdef = ast.parse(s).body[0] self.assertEqual(ast.get_source_segment(s, cdef.body[0], padded=True), s_method) + def test_source_segment_missing_info(self): + s = 'v = 1\r\nw = 1\nx = 1\n\ry = 1\r\n' + v, w, x, y = ast.parse(s).body + del v.lineno + del w.end_lineno + del x.col_offset + del y.end_col_offset + self.assertIsNone(ast.get_source_segment(s, v)) + self.assertIsNone(ast.get_source_segment(s, w)) + self.assertIsNone(ast.get_source_segment(s, x)) + self.assertIsNone(ast.get_source_segment(s, y)) class NodeVisitorTests(unittest.TestCase): def test_old_constant_nodes(self): @@ -2031,6 +2357,88 @@ class NodeVisitorTests(unittest.TestCase): ]) +@support.cpython_only +class ModuleStateTests(unittest.TestCase): + # bpo-41194, bpo-41261, bpo-41631: The _ast module uses a global state. + + def check_ast_module(self): + # Check that the _ast module still works as expected + code = 'x + 1' + filename = '' + mode = 'eval' + + # Create _ast.AST subclasses instances + ast_tree = compile(code, filename, mode, flags=ast.PyCF_ONLY_AST) + + # Call PyAST_Check() + code = compile(ast_tree, filename, mode) + self.assertIsInstance(code, types.CodeType) + + def test_reload_module(self): + # bpo-41194: Importing the _ast module twice must not crash. + with support.swap_item(sys.modules, '_ast', None): + del sys.modules['_ast'] + import _ast as ast1 + + del sys.modules['_ast'] + import _ast as ast2 + + self.check_ast_module() + + # Unloading the two _ast module instances must not crash. + del ast1 + del ast2 + support.gc_collect() + + self.check_ast_module() + + def test_sys_modules(self): + # bpo-41631: Test reproducing a Mercurial crash when PyAST_Check() + # imported the _ast module internally. + lazy_mod = object() + + def my_import(name, *args, **kw): + sys.modules[name] = lazy_mod + return lazy_mod + + with support.swap_item(sys.modules, '_ast', None): + del sys.modules['_ast'] + + with support.swap_attr(builtins, '__import__', my_import): + # Test that compile() does not import the _ast module + self.check_ast_module() + self.assertNotIn('_ast', sys.modules) + + # Sanity check of the test itself + import _ast + self.assertIs(_ast, lazy_mod) + + def test_subinterpreter(self): + # bpo-41631: Importing and using the _ast module in a subinterpreter + # must not crash. + code = dedent(''' + import _ast + import ast + import gc + import sys + import types + + # Create _ast.AST subclasses instances and call PyAST_Check() + ast_tree = compile('x+1', '', 'eval', + flags=ast.PyCF_ONLY_AST) + code = compile(ast_tree, 'string', 'eval') + if not isinstance(code, types.CodeType): + raise AssertionError + + # Unloading the _ast module must not crash. + del ast, _ast + del sys.modules['ast'], sys.modules['_ast'] + gc.collect() + ''') + res = support.run_in_subinterp(code) + self.assertEqual(res, 0) + + def main(): if __name__ != '__main__': return @@ -2048,112 +2456,112 @@ def main(): #### EVERYTHING BELOW IS GENERATED BY python Lib/test/test_ast.py -g ##### exec_results = [ -('Module', [('Expr', (1, 0), ('Constant', (1, 0), None, None))], []), -('Module', [('Expr', (1, 0), ('Constant', (1, 0), 'module docstring', None))], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 9))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (1, 9), ('Constant', (1, 9), 'function docstring', None))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [('arg', (1, 6), 'a', None, None)], None, [], [], None, []), [('Pass', (1, 10))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [('arg', (1, 6), 'a', None, None)], None, [], [], None, [('Constant', (1, 8), 0, None)]), [('Pass', (1, 12))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [], ('arg', (1, 7), 'args', None, None), [], [], None, []), [('Pass', (1, 14))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], ('arg', (1, 8), 'kwargs', None, None), []), [('Pass', (1, 17))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [('arg', (1, 6), 'a', None, None), ('arg', (1, 9), 'b', None, None), ('arg', (1, 14), 'c', None, None), ('arg', (1, 22), 'd', None, None), ('arg', (1, 28), 'e', None, None)], ('arg', (1, 35), 'args', None, None), [('arg', (1, 41), 'f', None, None)], [('Constant', (1, 43), 42, None)], ('arg', (1, 49), 'kwargs', None, None), [('Constant', (1, 11), 1, None), ('Constant', (1, 16), None, None), ('List', (1, 24), [], ('Load',)), ('Dict', (1, 30), [], [])]), [('Expr', (1, 58), ('Constant', (1, 58), 'doc for f()', None))], [], None, None)], []), -('Module', [('ClassDef', (1, 0), 'C', [], [], [('Pass', (1, 8))], [])], []), -('Module', [('ClassDef', (1, 0), 'C', [], [], [('Expr', (1, 9), ('Constant', (1, 9), 'docstring for class C', None))], [])], []), -('Module', [('ClassDef', (1, 0), 'C', [('Name', (1, 8), 'object', ('Load',))], [], [('Pass', (1, 17))], [])], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Return', (1, 8), ('Constant', (1, 15), 1, None))], [], None, None)], []), -('Module', [('Delete', (1, 0), [('Name', (1, 4), 'v', ('Del',))])], []), -('Module', [('Assign', (1, 0), [('Name', (1, 0), 'v', ('Store',))], ('Constant', (1, 4), 1, None), None)], []), -('Module', [('Assign', (1, 0), [('Tuple', (1, 0), [('Name', (1, 0), 'a', ('Store',)), ('Name', (1, 2), 'b', ('Store',))], ('Store',))], ('Name', (1, 6), 'c', ('Load',)), None)], []), -('Module', [('Assign', (1, 0), [('Tuple', (1, 0), [('Name', (1, 1), 'a', ('Store',)), ('Name', (1, 3), 'b', ('Store',))], ('Store',))], ('Name', (1, 8), 'c', ('Load',)), None)], []), -('Module', [('Assign', (1, 0), [('List', (1, 0), [('Name', (1, 1), 'a', ('Store',)), ('Name', (1, 3), 'b', ('Store',))], ('Store',))], ('Name', (1, 8), 'c', ('Load',)), None)], []), -('Module', [('AugAssign', (1, 0), ('Name', (1, 0), 'v', ('Store',)), ('Add',), ('Constant', (1, 5), 1, None))], []), -('Module', [('For', (1, 0), ('Name', (1, 4), 'v', ('Store',)), ('Name', (1, 9), 'v', ('Load',)), [('Pass', (1, 11))], [], None)], []), -('Module', [('While', (1, 0), ('Name', (1, 6), 'v', ('Load',)), [('Pass', (1, 8))], [])], []), -('Module', [('If', (1, 0), ('Name', (1, 3), 'v', ('Load',)), [('Pass', (1, 5))], [])], []), -('Module', [('If', (1, 0), ('Name', (1, 3), 'a', ('Load',)), [('Pass', (2, 2))], [('If', (3, 0), ('Name', (3, 5), 'b', ('Load',)), [('Pass', (4, 2))], [])])], []), -('Module', [('If', (1, 0), ('Name', (1, 3), 'a', ('Load',)), [('Pass', (2, 2))], [('If', (3, 0), ('Name', (3, 5), 'b', ('Load',)), [('Pass', (4, 2))], [('Pass', (6, 2))])])], []), -('Module', [('With', (1, 0), [('withitem', ('Name', (1, 5), 'x', ('Load',)), ('Name', (1, 10), 'y', ('Store',)))], [('Pass', (1, 13))], None)], []), -('Module', [('With', (1, 0), [('withitem', ('Name', (1, 5), 'x', ('Load',)), ('Name', (1, 10), 'y', ('Store',))), ('withitem', ('Name', (1, 13), 'z', ('Load',)), ('Name', (1, 18), 'q', ('Store',)))], [('Pass', (1, 21))], None)], []), -('Module', [('Raise', (1, 0), ('Call', (1, 6), ('Name', (1, 6), 'Exception', ('Load',)), [('Constant', (1, 16), 'string', None)], []), None)], []), -('Module', [('Try', (1, 0), [('Pass', (2, 2))], [('ExceptHandler', (3, 0), ('Name', (3, 7), 'Exception', ('Load',)), None, [('Pass', (4, 2))])], [], [])], []), -('Module', [('Try', (1, 0), [('Pass', (2, 2))], [], [], [('Pass', (4, 2))])], []), -('Module', [('Assert', (1, 0), ('Name', (1, 7), 'v', ('Load',)), None)], []), -('Module', [('Import', (1, 0), [('alias', 'sys', None)])], []), -('Module', [('ImportFrom', (1, 0), 'sys', [('alias', 'v', None)], 0)], []), -('Module', [('Global', (1, 0), ['v'])], []), -('Module', [('Expr', (1, 0), ('Constant', (1, 0), 1, None))], []), -('Module', [('Pass', (1, 0))], []), -('Module', [('For', (1, 0), ('Name', (1, 4), 'v', ('Store',)), ('Name', (1, 9), 'v', ('Load',)), [('Break', (1, 11))], [], None)], []), -('Module', [('For', (1, 0), ('Name', (1, 4), 'v', ('Store',)), ('Name', (1, 9), 'v', ('Load',)), [('Continue', (1, 11))], [], None)], []), -('Module', [('For', (1, 0), ('Tuple', (1, 4), [('Name', (1, 4), 'a', ('Store',)), ('Name', (1, 6), 'b', ('Store',))], ('Store',)), ('Name', (1, 11), 'c', ('Load',)), [('Pass', (1, 14))], [], None)], []), -('Module', [('For', (1, 0), ('Tuple', (1, 4), [('Name', (1, 5), 'a', ('Store',)), ('Name', (1, 7), 'b', ('Store',))], ('Store',)), ('Name', (1, 13), 'c', ('Load',)), [('Pass', (1, 16))], [], None)], []), -('Module', [('For', (1, 0), ('List', (1, 4), [('Name', (1, 5), 'a', ('Store',)), ('Name', (1, 7), 'b', ('Store',))], ('Store',)), ('Name', (1, 13), 'c', ('Load',)), [('Pass', (1, 16))], [], None)], []), -('Module', [('Expr', (1, 0), ('GeneratorExp', (1, 0), ('Tuple', (2, 4), [('Name', (3, 4), 'Aa', ('Load',)), ('Name', (5, 7), 'Bb', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (8, 4), [('Name', (8, 4), 'Aa', ('Store',)), ('Name', (10, 4), 'Bb', ('Store',))], ('Store',)), ('Name', (10, 10), 'Cc', ('Load',)), [], 0)]))], []), -('Module', [('Expr', (1, 0), ('DictComp', (1, 0), ('Name', (1, 1), 'a', ('Load',)), ('Name', (1, 5), 'b', ('Load',)), [('comprehension', ('Name', (1, 11), 'w', ('Store',)), ('Name', (1, 16), 'x', ('Load',)), [], 0), ('comprehension', ('Name', (1, 22), 'm', ('Store',)), ('Name', (1, 27), 'p', ('Load',)), [('Name', (1, 32), 'g', ('Load',))], 0)]))], []), -('Module', [('Expr', (1, 0), ('DictComp', (1, 0), ('Name', (1, 1), 'a', ('Load',)), ('Name', (1, 5), 'b', ('Load',)), [('comprehension', ('Tuple', (1, 11), [('Name', (1, 11), 'v', ('Store',)), ('Name', (1, 13), 'w', ('Store',))], ('Store',)), ('Name', (1, 18), 'x', ('Load',)), [], 0)]))], []), -('Module', [('Expr', (1, 0), ('SetComp', (1, 0), ('Name', (1, 1), 'r', ('Load',)), [('comprehension', ('Name', (1, 7), 'l', ('Store',)), ('Name', (1, 12), 'x', ('Load',)), [('Name', (1, 17), 'g', ('Load',))], 0)]))], []), -('Module', [('Expr', (1, 0), ('SetComp', (1, 0), ('Name', (1, 1), 'r', ('Load',)), [('comprehension', ('Tuple', (1, 7), [('Name', (1, 7), 'l', ('Store',)), ('Name', (1, 9), 'm', ('Store',))], ('Store',)), ('Name', (1, 14), 'x', ('Load',)), [], 0)]))], []), -('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1), ('Constant', (2, 1), 'async function', None)), ('Expr', (3, 1), ('Await', (3, 1), ('Call', (3, 7), ('Name', (3, 7), 'something', ('Load',)), [], [])))], [], None, None)], []), -('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncFor', (2, 1), ('Name', (2, 11), 'e', ('Store',)), ('Name', (2, 16), 'i', ('Load',)), [('Expr', (2, 19), ('Constant', (2, 19), 1, None))], [('Expr', (3, 7), ('Constant', (3, 7), 2, None))], None)], [], None, None)], []), -('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncWith', (2, 1), [('withitem', ('Name', (2, 12), 'a', ('Load',)), ('Name', (2, 17), 'b', ('Store',)))], [('Expr', (2, 20), ('Constant', (2, 20), 1, None))], None)], [], None, None)], []), -('Module', [('Expr', (1, 0), ('Dict', (1, 0), [None, ('Constant', (1, 10), 2, None)], [('Dict', (1, 3), [('Constant', (1, 4), 1, None)], [('Constant', (1, 6), 2, None)]), ('Constant', (1, 12), 3, None)]))], []), -('Module', [('Expr', (1, 0), ('Set', (1, 0), [('Starred', (1, 1), ('Set', (1, 2), [('Constant', (1, 3), 1, None), ('Constant', (1, 6), 2, None)]), ('Load',)), ('Constant', (1, 10), 3, None)]))], []), -('Module', [('AsyncFunctionDef', (1, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1), ('ListComp', (2, 1), ('Name', (2, 2), 'i', ('Load',)), [('comprehension', ('Name', (2, 14), 'b', ('Store',)), ('Name', (2, 19), 'c', ('Load',)), [], 1)]))], [], None, None)], []), -('Module', [('FunctionDef', (4, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 9))], [('Name', (1, 1), 'deco1', ('Load',)), ('Call', (2, 1), ('Name', (2, 1), 'deco2', ('Load',)), [], []), ('Call', (3, 1), ('Name', (3, 1), 'deco3', ('Load',)), [('Constant', (3, 7), 1, None)], [])], None, None)], []), -('Module', [('AsyncFunctionDef', (4, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 15))], [('Name', (1, 1), 'deco1', ('Load',)), ('Call', (2, 1), ('Name', (2, 1), 'deco2', ('Load',)), [], []), ('Call', (3, 1), ('Name', (3, 1), 'deco3', ('Load',)), [('Constant', (3, 7), 1, None)], [])], None, None)], []), -('Module', [('ClassDef', (4, 0), 'C', [], [], [('Pass', (4, 9))], [('Name', (1, 1), 'deco1', ('Load',)), ('Call', (2, 1), ('Name', (2, 1), 'deco2', ('Load',)), [], []), ('Call', (3, 1), ('Name', (3, 1), 'deco3', ('Load',)), [('Constant', (3, 7), 1, None)], [])])], []), -('Module', [('FunctionDef', (2, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9))], [('Call', (1, 1), ('Name', (1, 1), 'deco', ('Load',)), [('GeneratorExp', (1, 5), ('Name', (1, 6), 'a', ('Load',)), [('comprehension', ('Name', (1, 12), 'a', ('Store',)), ('Name', (1, 17), 'b', ('Load',)), [], 0)])], [])], None, None)], []), -('Module', [('FunctionDef', (2, 0), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9))], [('Attribute', (1, 1), ('Attribute', (1, 1), ('Name', (1, 1), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',))], None, None)], []), -('Module', [('Expr', (1, 0), ('NamedExpr', (1, 1), ('Name', (1, 1), 'a', ('Store',)), ('Constant', (1, 6), 1, None)))], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], [], None, [], [], None, []), [('Pass', (1, 14))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], [('arg', (1, 12), 'c', None, None), ('arg', (1, 15), 'd', None, None), ('arg', (1, 18), 'e', None, None)], None, [], [], None, []), [('Pass', (1, 22))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], [('arg', (1, 12), 'c', None, None)], None, [('arg', (1, 18), 'd', None, None), ('arg', (1, 21), 'e', None, None)], [None, None], None, []), [('Pass', (1, 25))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], [('arg', (1, 12), 'c', None, None)], None, [('arg', (1, 18), 'd', None, None), ('arg', (1, 21), 'e', None, None)], [None, None], ('arg', (1, 26), 'kwargs', None, None), []), [('Pass', (1, 35))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], [], None, [], [], None, [('Constant', (1, 8), 1, None)]), [('Pass', (1, 16))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], [('arg', (1, 14), 'b', None, None), ('arg', (1, 19), 'c', None, None)], None, [], [], None, [('Constant', (1, 8), 1, None), ('Constant', (1, 16), 2, None), ('Constant', (1, 21), 4, None)]), [('Pass', (1, 25))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], [('arg', (1, 14), 'b', None, None)], None, [('arg', (1, 22), 'c', None, None)], [('Constant', (1, 24), 4, None)], None, [('Constant', (1, 8), 1, None), ('Constant', (1, 16), 2, None)]), [('Pass', (1, 28))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], [('arg', (1, 14), 'b', None, None)], None, [('arg', (1, 22), 'c', None, None)], [None], None, [('Constant', (1, 8), 1, None), ('Constant', (1, 16), 2, None)]), [('Pass', (1, 26))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], [('arg', (1, 14), 'b', None, None)], None, [('arg', (1, 22), 'c', None, None)], [('Constant', (1, 24), 4, None)], ('arg', (1, 29), 'kwargs', None, None), [('Constant', (1, 8), 1, None), ('Constant', (1, 16), 2, None)]), [('Pass', (1, 38))], [], None, None)], []), -('Module', [('FunctionDef', (1, 0), 'f', ('arguments', [('arg', (1, 6), 'a', None, None)], [('arg', (1, 14), 'b', None, None)], None, [('arg', (1, 22), 'c', None, None)], [None], ('arg', (1, 27), 'kwargs', None, None), [('Constant', (1, 8), 1, None), ('Constant', (1, 16), 2, None)]), [('Pass', (1, 36))], [], None, None)], []), +('Module', [('Expr', (1, 0, 1, 4), ('Constant', (1, 0, 1, 4), None, None))], []), +('Module', [('Expr', (1, 0, 1, 18), ('Constant', (1, 0, 1, 18), 'module docstring', None))], []), +('Module', [('FunctionDef', (1, 0, 1, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (1, 9, 1, 13))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (1, 9, 1, 29), ('Constant', (1, 9, 1, 29), 'function docstring', None))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 14), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, []), [('Pass', (1, 10, 1, 14))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 16), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 0, None)]), [('Pass', (1, 12, 1, 16))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 18), 'f', ('arguments', [], [], ('arg', (1, 7, 1, 11), 'args', None, None), [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 21), 'f', ('arguments', [], [], None, [], [], ('arg', (1, 8, 1, 14), 'kwargs', None, None), []), [('Pass', (1, 17, 1, 21))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 71), 'f', ('arguments', [], [('arg', (1, 6, 1, 7), 'a', None, None), ('arg', (1, 9, 1, 10), 'b', None, None), ('arg', (1, 14, 1, 15), 'c', None, None), ('arg', (1, 22, 1, 23), 'd', None, None), ('arg', (1, 28, 1, 29), 'e', None, None)], ('arg', (1, 35, 1, 39), 'args', None, None), [('arg', (1, 41, 1, 42), 'f', None, None)], [('Constant', (1, 43, 1, 45), 42, None)], ('arg', (1, 49, 1, 55), 'kwargs', None, None), [('Constant', (1, 11, 1, 12), 1, None), ('Constant', (1, 16, 1, 20), None, None), ('List', (1, 24, 1, 26), [], ('Load',)), ('Dict', (1, 30, 1, 32), [], [])]), [('Expr', (1, 58, 1, 71), ('Constant', (1, 58, 1, 71), 'doc for f()', None))], [], None, None)], []), +('Module', [('ClassDef', (1, 0, 1, 12), 'C', [], [], [('Pass', (1, 8, 1, 12))], [])], []), +('Module', [('ClassDef', (1, 0, 1, 32), 'C', [], [], [('Expr', (1, 9, 1, 32), ('Constant', (1, 9, 1, 32), 'docstring for class C', None))], [])], []), +('Module', [('ClassDef', (1, 0, 1, 21), 'C', [('Name', (1, 8, 1, 14), 'object', ('Load',))], [], [('Pass', (1, 17, 1, 21))], [])], []), +('Module', [('FunctionDef', (1, 0, 1, 16), 'f', ('arguments', [], [], None, [], [], None, []), [('Return', (1, 8, 1, 16), ('Constant', (1, 15, 1, 16), 1, None))], [], None, None)], []), +('Module', [('Delete', (1, 0, 1, 5), [('Name', (1, 4, 1, 5), 'v', ('Del',))])], []), +('Module', [('Assign', (1, 0, 1, 5), [('Name', (1, 0, 1, 1), 'v', ('Store',))], ('Constant', (1, 4, 1, 5), 1, None), None)], []), +('Module', [('Assign', (1, 0, 1, 7), [('Tuple', (1, 0, 1, 3), [('Name', (1, 0, 1, 1), 'a', ('Store',)), ('Name', (1, 2, 1, 3), 'b', ('Store',))], ('Store',))], ('Name', (1, 6, 1, 7), 'c', ('Load',)), None)], []), +('Module', [('Assign', (1, 0, 1, 9), [('Tuple', (1, 0, 1, 5), [('Name', (1, 1, 1, 2), 'a', ('Store',)), ('Name', (1, 3, 1, 4), 'b', ('Store',))], ('Store',))], ('Name', (1, 8, 1, 9), 'c', ('Load',)), None)], []), +('Module', [('Assign', (1, 0, 1, 9), [('List', (1, 0, 1, 5), [('Name', (1, 1, 1, 2), 'a', ('Store',)), ('Name', (1, 3, 1, 4), 'b', ('Store',))], ('Store',))], ('Name', (1, 8, 1, 9), 'c', ('Load',)), None)], []), +('Module', [('AugAssign', (1, 0, 1, 6), ('Name', (1, 0, 1, 1), 'v', ('Store',)), ('Add',), ('Constant', (1, 5, 1, 6), 1, None))], []), +('Module', [('For', (1, 0, 1, 15), ('Name', (1, 4, 1, 5), 'v', ('Store',)), ('Name', (1, 9, 1, 10), 'v', ('Load',)), [('Pass', (1, 11, 1, 15))], [], None)], []), +('Module', [('While', (1, 0, 1, 12), ('Name', (1, 6, 1, 7), 'v', ('Load',)), [('Pass', (1, 8, 1, 12))], [])], []), +('Module', [('If', (1, 0, 1, 9), ('Name', (1, 3, 1, 4), 'v', ('Load',)), [('Pass', (1, 5, 1, 9))], [])], []), +('Module', [('If', (1, 0, 4, 6), ('Name', (1, 3, 1, 4), 'a', ('Load',)), [('Pass', (2, 2, 2, 6))], [('If', (3, 0, 4, 6), ('Name', (3, 5, 3, 6), 'b', ('Load',)), [('Pass', (4, 2, 4, 6))], [])])], []), +('Module', [('If', (1, 0, 6, 6), ('Name', (1, 3, 1, 4), 'a', ('Load',)), [('Pass', (2, 2, 2, 6))], [('If', (3, 0, 6, 6), ('Name', (3, 5, 3, 6), 'b', ('Load',)), [('Pass', (4, 2, 4, 6))], [('Pass', (6, 2, 6, 6))])])], []), +('Module', [('With', (1, 0, 1, 17), [('withitem', ('Name', (1, 5, 1, 6), 'x', ('Load',)), ('Name', (1, 10, 1, 11), 'y', ('Store',)))], [('Pass', (1, 13, 1, 17))], None)], []), +('Module', [('With', (1, 0, 1, 25), [('withitem', ('Name', (1, 5, 1, 6), 'x', ('Load',)), ('Name', (1, 10, 1, 11), 'y', ('Store',))), ('withitem', ('Name', (1, 13, 1, 14), 'z', ('Load',)), ('Name', (1, 18, 1, 19), 'q', ('Store',)))], [('Pass', (1, 21, 1, 25))], None)], []), +('Module', [('Raise', (1, 0, 1, 25), ('Call', (1, 6, 1, 25), ('Name', (1, 6, 1, 15), 'Exception', ('Load',)), [('Constant', (1, 16, 1, 24), 'string', None)], []), None)], []), +('Module', [('Try', (1, 0, 4, 6), [('Pass', (2, 2, 2, 6))], [('ExceptHandler', (3, 0, 4, 6), ('Name', (3, 7, 3, 16), 'Exception', ('Load',)), None, [('Pass', (4, 2, 4, 6))])], [], [])], []), +('Module', [('Try', (1, 0, 4, 6), [('Pass', (2, 2, 2, 6))], [], [], [('Pass', (4, 2, 4, 6))])], []), +('Module', [('Assert', (1, 0, 1, 8), ('Name', (1, 7, 1, 8), 'v', ('Load',)), None)], []), +('Module', [('Import', (1, 0, 1, 10), [('alias', (1, 7, 1, 10), 'sys', None)])], []), +('Module', [('ImportFrom', (1, 0, 1, 17), 'sys', [('alias', (1, 16, 1, 17), 'v', None)], 0)], []), +('Module', [('Global', (1, 0, 1, 8), ['v'])], []), +('Module', [('Expr', (1, 0, 1, 1), ('Constant', (1, 0, 1, 1), 1, None))], []), +('Module', [('Pass', (1, 0, 1, 4))], []), +('Module', [('For', (1, 0, 1, 16), ('Name', (1, 4, 1, 5), 'v', ('Store',)), ('Name', (1, 9, 1, 10), 'v', ('Load',)), [('Break', (1, 11, 1, 16))], [], None)], []), +('Module', [('For', (1, 0, 1, 19), ('Name', (1, 4, 1, 5), 'v', ('Store',)), ('Name', (1, 9, 1, 10), 'v', ('Load',)), [('Continue', (1, 11, 1, 19))], [], None)], []), +('Module', [('For', (1, 0, 1, 18), ('Tuple', (1, 4, 1, 7), [('Name', (1, 4, 1, 5), 'a', ('Store',)), ('Name', (1, 6, 1, 7), 'b', ('Store',))], ('Store',)), ('Name', (1, 11, 1, 12), 'c', ('Load',)), [('Pass', (1, 14, 1, 18))], [], None)], []), +('Module', [('For', (1, 0, 1, 20), ('Tuple', (1, 4, 1, 9), [('Name', (1, 5, 1, 6), 'a', ('Store',)), ('Name', (1, 7, 1, 8), 'b', ('Store',))], ('Store',)), ('Name', (1, 13, 1, 14), 'c', ('Load',)), [('Pass', (1, 16, 1, 20))], [], None)], []), +('Module', [('For', (1, 0, 1, 20), ('List', (1, 4, 1, 9), [('Name', (1, 5, 1, 6), 'a', ('Store',)), ('Name', (1, 7, 1, 8), 'b', ('Store',))], ('Store',)), ('Name', (1, 13, 1, 14), 'c', ('Load',)), [('Pass', (1, 16, 1, 20))], [], None)], []), +('Module', [('Expr', (1, 0, 11, 5), ('GeneratorExp', (1, 0, 11, 5), ('Tuple', (2, 4, 6, 5), [('Name', (3, 4, 3, 6), 'Aa', ('Load',)), ('Name', (5, 7, 5, 9), 'Bb', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (8, 4, 10, 6), [('Name', (8, 4, 8, 6), 'Aa', ('Store',)), ('Name', (10, 4, 10, 6), 'Bb', ('Store',))], ('Store',)), ('Name', (10, 10, 10, 12), 'Cc', ('Load',)), [], 0)]))], []), +('Module', [('Expr', (1, 0, 1, 34), ('DictComp', (1, 0, 1, 34), ('Name', (1, 1, 1, 2), 'a', ('Load',)), ('Name', (1, 5, 1, 6), 'b', ('Load',)), [('comprehension', ('Name', (1, 11, 1, 12), 'w', ('Store',)), ('Name', (1, 16, 1, 17), 'x', ('Load',)), [], 0), ('comprehension', ('Name', (1, 22, 1, 23), 'm', ('Store',)), ('Name', (1, 27, 1, 28), 'p', ('Load',)), [('Name', (1, 32, 1, 33), 'g', ('Load',))], 0)]))], []), +('Module', [('Expr', (1, 0, 1, 20), ('DictComp', (1, 0, 1, 20), ('Name', (1, 1, 1, 2), 'a', ('Load',)), ('Name', (1, 5, 1, 6), 'b', ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 14), [('Name', (1, 11, 1, 12), 'v', ('Store',)), ('Name', (1, 13, 1, 14), 'w', ('Store',))], ('Store',)), ('Name', (1, 18, 1, 19), 'x', ('Load',)), [], 0)]))], []), +('Module', [('Expr', (1, 0, 1, 19), ('SetComp', (1, 0, 1, 19), ('Name', (1, 1, 1, 2), 'r', ('Load',)), [('comprehension', ('Name', (1, 7, 1, 8), 'l', ('Store',)), ('Name', (1, 12, 1, 13), 'x', ('Load',)), [('Name', (1, 17, 1, 18), 'g', ('Load',))], 0)]))], []), +('Module', [('Expr', (1, 0, 1, 16), ('SetComp', (1, 0, 1, 16), ('Name', (1, 1, 1, 2), 'r', ('Load',)), [('comprehension', ('Tuple', (1, 7, 1, 10), [('Name', (1, 7, 1, 8), 'l', ('Store',)), ('Name', (1, 9, 1, 10), 'm', ('Store',))], ('Store',)), ('Name', (1, 14, 1, 15), 'x', ('Load',)), [], 0)]))], []), +('Module', [('AsyncFunctionDef', (1, 0, 3, 18), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 17), ('Constant', (2, 1, 2, 17), 'async function', None)), ('Expr', (3, 1, 3, 18), ('Await', (3, 1, 3, 18), ('Call', (3, 7, 3, 18), ('Name', (3, 7, 3, 16), 'something', ('Load',)), [], [])))], [], None, None)], []), +('Module', [('AsyncFunctionDef', (1, 0, 3, 8), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncFor', (2, 1, 3, 8), ('Name', (2, 11, 2, 12), 'e', ('Store',)), ('Name', (2, 16, 2, 17), 'i', ('Load',)), [('Expr', (2, 19, 2, 20), ('Constant', (2, 19, 2, 20), 1, None))], [('Expr', (3, 7, 3, 8), ('Constant', (3, 7, 3, 8), 2, None))], None)], [], None, None)], []), +('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', ('arguments', [], [], None, [], [], None, []), [('AsyncWith', (2, 1, 2, 21), [('withitem', ('Name', (2, 12, 2, 13), 'a', ('Load',)), ('Name', (2, 17, 2, 18), 'b', ('Store',)))], [('Expr', (2, 20, 2, 21), ('Constant', (2, 20, 2, 21), 1, None))], None)], [], None, None)], []), +('Module', [('Expr', (1, 0, 1, 14), ('Dict', (1, 0, 1, 14), [None, ('Constant', (1, 10, 1, 11), 2, None)], [('Dict', (1, 3, 1, 8), [('Constant', (1, 4, 1, 5), 1, None)], [('Constant', (1, 6, 1, 7), 2, None)]), ('Constant', (1, 12, 1, 13), 3, None)]))], []), +('Module', [('Expr', (1, 0, 1, 12), ('Set', (1, 0, 1, 12), [('Starred', (1, 1, 1, 8), ('Set', (1, 2, 1, 8), [('Constant', (1, 3, 1, 4), 1, None), ('Constant', (1, 6, 1, 7), 2, None)]), ('Load',)), ('Constant', (1, 10, 1, 11), 3, None)]))], []), +('Module', [('AsyncFunctionDef', (1, 0, 2, 21), 'f', ('arguments', [], [], None, [], [], None, []), [('Expr', (2, 1, 2, 21), ('ListComp', (2, 1, 2, 21), ('Name', (2, 2, 2, 3), 'i', ('Load',)), [('comprehension', ('Name', (2, 14, 2, 15), 'b', ('Store',)), ('Name', (2, 19, 2, 20), 'c', ('Load',)), [], 1)]))], [], None, None)], []), +('Module', [('FunctionDef', (4, 0, 4, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None)], []), +('Module', [('AsyncFunctionDef', (4, 0, 4, 19), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (4, 15, 4, 19))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])], None, None)], []), +('Module', [('ClassDef', (4, 0, 4, 13), 'C', [], [], [('Pass', (4, 9, 4, 13))], [('Name', (1, 1, 1, 6), 'deco1', ('Load',)), ('Call', (2, 1, 2, 8), ('Name', (2, 1, 2, 6), 'deco2', ('Load',)), [], []), ('Call', (3, 1, 3, 9), ('Name', (3, 1, 3, 6), 'deco3', ('Load',)), [('Constant', (3, 7, 3, 8), 1, None)], [])])], []), +('Module', [('FunctionDef', (2, 0, 2, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Call', (1, 1, 1, 19), ('Name', (1, 1, 1, 5), 'deco', ('Load',)), [('GeneratorExp', (1, 5, 1, 19), ('Name', (1, 6, 1, 7), 'a', ('Load',)), [('comprehension', ('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 17, 1, 18), 'b', ('Load',)), [], 0)])], [])], None, None)], []), +('Module', [('FunctionDef', (2, 0, 2, 13), 'f', ('arguments', [], [], None, [], [], None, []), [('Pass', (2, 9, 2, 13))], [('Attribute', (1, 1, 1, 6), ('Attribute', (1, 1, 1, 4), ('Name', (1, 1, 1, 2), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',))], None, None)], []), +('Module', [('Expr', (1, 0, 1, 8), ('NamedExpr', (1, 1, 1, 7), ('Name', (1, 1, 1, 2), 'a', ('Store',)), ('Constant', (1, 6, 1, 7), 1, None)))], []), +('Module', [('FunctionDef', (1, 0, 1, 18), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, []), [('Pass', (1, 14, 1, 18))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 26), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None), ('arg', (1, 15, 1, 16), 'd', None, None), ('arg', (1, 18, 1, 19), 'e', None, None)], None, [], [], None, []), [('Pass', (1, 22, 1, 26))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], None, []), [('Pass', (1, 25, 1, 29))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 39), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 12, 1, 13), 'c', None, None)], None, [('arg', (1, 18, 1, 19), 'd', None, None), ('arg', (1, 21, 1, 22), 'e', None, None)], [None, None], ('arg', (1, 26, 1, 32), 'kwargs', None, None), []), [('Pass', (1, 35, 1, 39))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 20), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None)]), [('Pass', (1, 16, 1, 20))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 29), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None), ('arg', (1, 19, 1, 20), 'c', None, None)], None, [], [], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None), ('Constant', (1, 21, 1, 22), 4, None)]), [('Pass', (1, 25, 1, 29))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 32), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 28, 1, 32))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 30), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], None, [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 26, 1, 30))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 42), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [('Constant', (1, 24, 1, 25), 4, None)], ('arg', (1, 29, 1, 35), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 38, 1, 42))], [], None, None)], []), +('Module', [('FunctionDef', (1, 0, 1, 40), 'f', ('arguments', [('arg', (1, 6, 1, 7), 'a', None, None)], [('arg', (1, 14, 1, 15), 'b', None, None)], None, [('arg', (1, 22, 1, 23), 'c', None, None)], [None], ('arg', (1, 27, 1, 33), 'kwargs', None, None), [('Constant', (1, 8, 1, 9), 1, None), ('Constant', (1, 16, 1, 17), 2, None)]), [('Pass', (1, 36, 1, 40))], [], None, None)], []), ] single_results = [ -('Interactive', [('Expr', (1, 0), ('BinOp', (1, 0), ('Constant', (1, 0), 1, None), ('Add',), ('Constant', (1, 2), 2, None)))]), +('Interactive', [('Expr', (1, 0, 1, 3), ('BinOp', (1, 0, 1, 3), ('Constant', (1, 0, 1, 1), 1, None), ('Add',), ('Constant', (1, 2, 1, 3), 2, None)))]), ] eval_results = [ -('Expression', ('Constant', (1, 0), None, None)), -('Expression', ('BoolOp', (1, 0), ('And',), [('Name', (1, 0), 'a', ('Load',)), ('Name', (1, 6), 'b', ('Load',))])), -('Expression', ('BinOp', (1, 0), ('Name', (1, 0), 'a', ('Load',)), ('Add',), ('Name', (1, 4), 'b', ('Load',)))), -('Expression', ('UnaryOp', (1, 0), ('Not',), ('Name', (1, 4), 'v', ('Load',)))), -('Expression', ('Lambda', (1, 0), ('arguments', [], [], None, [], [], None, []), ('Constant', (1, 7), None, None))), -('Expression', ('Dict', (1, 0), [('Constant', (1, 2), 1, None)], [('Constant', (1, 4), 2, None)])), -('Expression', ('Dict', (1, 0), [], [])), -('Expression', ('Set', (1, 0), [('Constant', (1, 1), None, None)])), -('Expression', ('Dict', (1, 0), [('Constant', (2, 6), 1, None)], [('Constant', (4, 10), 2, None)])), -('Expression', ('ListComp', (1, 0), ('Name', (1, 1), 'a', ('Load',)), [('comprehension', ('Name', (1, 7), 'b', ('Store',)), ('Name', (1, 12), 'c', ('Load',)), [('Name', (1, 17), 'd', ('Load',))], 0)])), -('Expression', ('GeneratorExp', (1, 0), ('Name', (1, 1), 'a', ('Load',)), [('comprehension', ('Name', (1, 7), 'b', ('Store',)), ('Name', (1, 12), 'c', ('Load',)), [('Name', (1, 17), 'd', ('Load',))], 0)])), -('Expression', ('ListComp', (1, 0), ('Tuple', (1, 1), [('Name', (1, 2), 'a', ('Load',)), ('Name', (1, 4), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11), [('Name', (1, 11), 'a', ('Store',)), ('Name', (1, 13), 'b', ('Store',))], ('Store',)), ('Name', (1, 18), 'c', ('Load',)), [], 0)])), -('Expression', ('ListComp', (1, 0), ('Tuple', (1, 1), [('Name', (1, 2), 'a', ('Load',)), ('Name', (1, 4), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11), [('Name', (1, 12), 'a', ('Store',)), ('Name', (1, 14), 'b', ('Store',))], ('Store',)), ('Name', (1, 20), 'c', ('Load',)), [], 0)])), -('Expression', ('ListComp', (1, 0), ('Tuple', (1, 1), [('Name', (1, 2), 'a', ('Load',)), ('Name', (1, 4), 'b', ('Load',))], ('Load',)), [('comprehension', ('List', (1, 11), [('Name', (1, 12), 'a', ('Store',)), ('Name', (1, 14), 'b', ('Store',))], ('Store',)), ('Name', (1, 20), 'c', ('Load',)), [], 0)])), -('Expression', ('SetComp', (1, 0), ('Tuple', (1, 1), [('Name', (1, 2), 'a', ('Load',)), ('Name', (1, 4), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11), [('Name', (1, 11), 'a', ('Store',)), ('Name', (1, 13), 'b', ('Store',))], ('Store',)), ('Name', (1, 18), 'c', ('Load',)), [], 0)])), -('Expression', ('SetComp', (1, 0), ('Tuple', (1, 1), [('Name', (1, 2), 'a', ('Load',)), ('Name', (1, 4), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11), [('Name', (1, 12), 'a', ('Store',)), ('Name', (1, 14), 'b', ('Store',))], ('Store',)), ('Name', (1, 20), 'c', ('Load',)), [], 0)])), -('Expression', ('SetComp', (1, 0), ('Tuple', (1, 1), [('Name', (1, 2), 'a', ('Load',)), ('Name', (1, 4), 'b', ('Load',))], ('Load',)), [('comprehension', ('List', (1, 11), [('Name', (1, 12), 'a', ('Store',)), ('Name', (1, 14), 'b', ('Store',))], ('Store',)), ('Name', (1, 20), 'c', ('Load',)), [], 0)])), -('Expression', ('GeneratorExp', (1, 0), ('Tuple', (1, 1), [('Name', (1, 2), 'a', ('Load',)), ('Name', (1, 4), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11), [('Name', (1, 11), 'a', ('Store',)), ('Name', (1, 13), 'b', ('Store',))], ('Store',)), ('Name', (1, 18), 'c', ('Load',)), [], 0)])), -('Expression', ('GeneratorExp', (1, 0), ('Tuple', (1, 1), [('Name', (1, 2), 'a', ('Load',)), ('Name', (1, 4), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11), [('Name', (1, 12), 'a', ('Store',)), ('Name', (1, 14), 'b', ('Store',))], ('Store',)), ('Name', (1, 20), 'c', ('Load',)), [], 0)])), -('Expression', ('GeneratorExp', (1, 0), ('Tuple', (1, 1), [('Name', (1, 2), 'a', ('Load',)), ('Name', (1, 4), 'b', ('Load',))], ('Load',)), [('comprehension', ('List', (1, 11), [('Name', (1, 12), 'a', ('Store',)), ('Name', (1, 14), 'b', ('Store',))], ('Store',)), ('Name', (1, 20), 'c', ('Load',)), [], 0)])), -('Expression', ('Compare', (1, 0), ('Constant', (1, 0), 1, None), [('Lt',), ('Lt',)], [('Constant', (1, 4), 2, None), ('Constant', (1, 8), 3, None)])), -('Expression', ('Call', (1, 0), ('Name', (1, 0), 'f', ('Load',)), [('Constant', (1, 2), 1, None), ('Constant', (1, 4), 2, None), ('Starred', (1, 10), ('Name', (1, 11), 'd', ('Load',)), ('Load',))], [('keyword', 'c', ('Constant', (1, 8), 3, None)), ('keyword', None, ('Name', (1, 15), 'e', ('Load',)))])), -('Expression', ('Call', (1, 0), ('Name', (1, 0), 'f', ('Load',)), [('Starred', (1, 2), ('List', (1, 3), [('Constant', (1, 4), 0, None), ('Constant', (1, 7), 1, None)], ('Load',)), ('Load',))], [])), -('Expression', ('Call', (1, 0), ('Name', (1, 0), 'f', ('Load',)), [('GeneratorExp', (1, 1), ('Name', (1, 2), 'a', ('Load',)), [('comprehension', ('Name', (1, 8), 'a', ('Store',)), ('Name', (1, 13), 'b', ('Load',)), [], 0)])], [])), -('Expression', ('Constant', (1, 0), 10, None)), -('Expression', ('Constant', (1, 0), 'string', None)), -('Expression', ('Attribute', (1, 0), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',))), -('Expression', ('Subscript', (1, 0), ('Name', (1, 0), 'a', ('Load',)), ('Slice', ('Name', (1, 2), 'b', ('Load',)), ('Name', (1, 4), 'c', ('Load',)), None), ('Load',))), -('Expression', ('Name', (1, 0), 'v', ('Load',))), -('Expression', ('List', (1, 0), [('Constant', (1, 1), 1, None), ('Constant', (1, 3), 2, None), ('Constant', (1, 5), 3, None)], ('Load',))), -('Expression', ('List', (1, 0), [], ('Load',))), -('Expression', ('Tuple', (1, 0), [('Constant', (1, 0), 1, None), ('Constant', (1, 2), 2, None), ('Constant', (1, 4), 3, None)], ('Load',))), -('Expression', ('Tuple', (1, 0), [('Constant', (1, 1), 1, None), ('Constant', (1, 3), 2, None), ('Constant', (1, 5), 3, None)], ('Load',))), -('Expression', ('Tuple', (1, 0), [], ('Load',))), -('Expression', ('Call', (1, 0), ('Attribute', (1, 0), ('Attribute', (1, 0), ('Attribute', (1, 0), ('Name', (1, 0), 'a', ('Load',)), 'b', ('Load',)), 'c', ('Load',)), 'd', ('Load',)), [('Subscript', (1, 8), ('Attribute', (1, 8), ('Name', (1, 8), 'a', ('Load',)), 'b', ('Load',)), ('Slice', ('Constant', (1, 12), 1, None), ('Constant', (1, 14), 2, None), None), ('Load',))], [])), +('Expression', ('Constant', (1, 0, 1, 4), None, None)), +('Expression', ('BoolOp', (1, 0, 1, 7), ('And',), [('Name', (1, 0, 1, 1), 'a', ('Load',)), ('Name', (1, 6, 1, 7), 'b', ('Load',))])), +('Expression', ('BinOp', (1, 0, 1, 5), ('Name', (1, 0, 1, 1), 'a', ('Load',)), ('Add',), ('Name', (1, 4, 1, 5), 'b', ('Load',)))), +('Expression', ('UnaryOp', (1, 0, 1, 5), ('Not',), ('Name', (1, 4, 1, 5), 'v', ('Load',)))), +('Expression', ('Lambda', (1, 0, 1, 11), ('arguments', [], [], None, [], [], None, []), ('Constant', (1, 7, 1, 11), None, None))), +('Expression', ('Dict', (1, 0, 1, 7), [('Constant', (1, 2, 1, 3), 1, None)], [('Constant', (1, 4, 1, 5), 2, None)])), +('Expression', ('Dict', (1, 0, 1, 2), [], [])), +('Expression', ('Set', (1, 0, 1, 7), [('Constant', (1, 1, 1, 5), None, None)])), +('Expression', ('Dict', (1, 0, 5, 6), [('Constant', (2, 6, 2, 7), 1, None)], [('Constant', (4, 10, 4, 11), 2, None)])), +('Expression', ('ListComp', (1, 0, 1, 19), ('Name', (1, 1, 1, 2), 'a', ('Load',)), [('comprehension', ('Name', (1, 7, 1, 8), 'b', ('Store',)), ('Name', (1, 12, 1, 13), 'c', ('Load',)), [('Name', (1, 17, 1, 18), 'd', ('Load',))], 0)])), +('Expression', ('GeneratorExp', (1, 0, 1, 19), ('Name', (1, 1, 1, 2), 'a', ('Load',)), [('comprehension', ('Name', (1, 7, 1, 8), 'b', ('Store',)), ('Name', (1, 12, 1, 13), 'c', ('Load',)), [('Name', (1, 17, 1, 18), 'd', ('Load',))], 0)])), +('Expression', ('ListComp', (1, 0, 1, 20), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 14), [('Name', (1, 11, 1, 12), 'a', ('Store',)), ('Name', (1, 13, 1, 14), 'b', ('Store',))], ('Store',)), ('Name', (1, 18, 1, 19), 'c', ('Load',)), [], 0)])), +('Expression', ('ListComp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), +('Expression', ('ListComp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('List', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), +('Expression', ('SetComp', (1, 0, 1, 20), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 14), [('Name', (1, 11, 1, 12), 'a', ('Store',)), ('Name', (1, 13, 1, 14), 'b', ('Store',))], ('Store',)), ('Name', (1, 18, 1, 19), 'c', ('Load',)), [], 0)])), +('Expression', ('SetComp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), +('Expression', ('SetComp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('List', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), +('Expression', ('GeneratorExp', (1, 0, 1, 20), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 14), [('Name', (1, 11, 1, 12), 'a', ('Store',)), ('Name', (1, 13, 1, 14), 'b', ('Store',))], ('Store',)), ('Name', (1, 18, 1, 19), 'c', ('Load',)), [], 0)])), +('Expression', ('GeneratorExp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('Tuple', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), +('Expression', ('GeneratorExp', (1, 0, 1, 22), ('Tuple', (1, 1, 1, 6), [('Name', (1, 2, 1, 3), 'a', ('Load',)), ('Name', (1, 4, 1, 5), 'b', ('Load',))], ('Load',)), [('comprehension', ('List', (1, 11, 1, 16), [('Name', (1, 12, 1, 13), 'a', ('Store',)), ('Name', (1, 14, 1, 15), 'b', ('Store',))], ('Store',)), ('Name', (1, 20, 1, 21), 'c', ('Load',)), [], 0)])), +('Expression', ('Compare', (1, 0, 1, 9), ('Constant', (1, 0, 1, 1), 1, None), [('Lt',), ('Lt',)], [('Constant', (1, 4, 1, 5), 2, None), ('Constant', (1, 8, 1, 9), 3, None)])), +('Expression', ('Call', (1, 0, 1, 17), ('Name', (1, 0, 1, 1), 'f', ('Load',)), [('Constant', (1, 2, 1, 3), 1, None), ('Constant', (1, 4, 1, 5), 2, None), ('Starred', (1, 10, 1, 12), ('Name', (1, 11, 1, 12), 'd', ('Load',)), ('Load',))], [('keyword', (1, 6, 1, 9), 'c', ('Constant', (1, 8, 1, 9), 3, None)), ('keyword', (1, 13, 1, 16), None, ('Name', (1, 15, 1, 16), 'e', ('Load',)))])), +('Expression', ('Call', (1, 0, 1, 10), ('Name', (1, 0, 1, 1), 'f', ('Load',)), [('Starred', (1, 2, 1, 9), ('List', (1, 3, 1, 9), [('Constant', (1, 4, 1, 5), 0, None), ('Constant', (1, 7, 1, 8), 1, None)], ('Load',)), ('Load',))], [])), +('Expression', ('Call', (1, 0, 1, 15), ('Name', (1, 0, 1, 1), 'f', ('Load',)), [('GeneratorExp', (1, 1, 1, 15), ('Name', (1, 2, 1, 3), 'a', ('Load',)), [('comprehension', ('Name', (1, 8, 1, 9), 'a', ('Store',)), ('Name', (1, 13, 1, 14), 'b', ('Load',)), [], 0)])], [])), +('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', (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', (1, 12, 1, 15), ('Constant', (1, 12, 1, 13), 1, None), ('Constant', (1, 14, 1, 15), 2, None), None), ('Load',))], [])), ] main() From 5ffb69b58d423aada0d9a55193667a8293b24540 Mon Sep 17 00:00:00 2001 From: CPython Developers <> Date: Thu, 11 Aug 2022 08:21:09 +0900 Subject: [PATCH 04/11] Update Python.asdl from CPython 3.10.6 --- ast/Python.asdl | 31 +++++++++++++++++++++++++------ ast/asdl.py | 10 +++++----- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/ast/Python.asdl b/ast/Python.asdl index b3abe1628..32fdc01a7 100644 --- a/ast/Python.asdl +++ b/ast/Python.asdl @@ -26,7 +26,7 @@ module Python | Assign(expr* targets, expr value, string? type_comment) | AugAssign(expr target, operator op, expr value) -- 'simple' indicates that we annotate simple name without parens - | AnnAssign(expr target, expr annotation, expr? value, bool simple) + | AnnAssign(expr target, expr annotation, expr? value, int simple) -- use 'orelse' because else is a keyword in target languages | For(expr target, expr iter, stmt* body, stmt* orelse, string? type_comment) @@ -36,12 +36,14 @@ module Python | With(withitem* items, stmt* body, string? type_comment) | AsyncWith(withitem* items, stmt* body, string? type_comment) + | Match(expr subject, match_case* cases) + | Raise(expr? exc, expr? cause) | Try(stmt* body, excepthandler* handlers, stmt* orelse, stmt* finalbody) | Assert(expr test, expr? msg) | Import(alias* names) - | ImportFrom(identifier? module, alias* names, int level) + | ImportFrom(identifier? module, alias* names, int? level) | Global(identifier* names) | Nonlocal(identifier* names) @@ -58,7 +60,7 @@ module Python | UnaryOp(unaryop op, expr operand) | Lambda(arguments args, expr body) | IfExp(expr test, expr body, expr orelse) - | Dict(expr?* keys, expr* values) + | Dict(expr* keys, expr* values) | Set(expr* elts) | ListComp(expr elt, comprehension* generators) | SetComp(expr elt, comprehension* generators) @@ -72,7 +74,7 @@ module Python -- x < 4 < 3 and (x < 4) < 3 | Compare(expr left, cmpop* ops, expr* comparators) | Call(expr func, expr* args, keyword* keywords) - | FormattedValue(expr value, conversion_flag? conversion, expr? format_spec) + | FormattedValue(expr value, int conversion, expr? format_spec) | JoinedStr(expr* values) | Constant(constant value, string? kind) @@ -101,13 +103,13 @@ module Python cmpop = Eq | NotEq | Lt | LtE | Gt | GtE | Is | IsNot | In | NotIn - comprehension = (expr target, expr iter, expr* ifs, bool is_async) + comprehension = (expr target, expr iter, expr* ifs, int is_async) excepthandler = ExceptHandler(expr? type, identifier? name, stmt* body) attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset) arguments = (arg* posonlyargs, arg* args, arg? vararg, arg* kwonlyargs, - expr?* kw_defaults, arg? kwarg, expr* defaults) + expr* kw_defaults, arg? kwarg, expr* defaults) arg = (identifier arg, expr? annotation, string? type_comment) attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset) @@ -118,8 +120,25 @@ module Python -- import name with optional 'as' alias. alias = (identifier name, identifier? asname) + attributes (int lineno, int col_offset, int? end_lineno, int? end_col_offset) withitem = (expr context_expr, expr? optional_vars) + match_case = (pattern pattern, expr? guard, stmt* body) + + pattern = MatchValue(expr value) + | MatchSingleton(constant value) + | MatchSequence(pattern* patterns) + | MatchMapping(expr* keys, pattern* patterns, identifier? rest) + | MatchClass(expr cls, pattern* patterns, identifier* kwd_attrs, pattern* kwd_patterns) + + | MatchStar(identifier? name) + -- The optional "rest" MatchMapping parameter handles capturing extra mapping keys + + | MatchAs(pattern? pattern, identifier? name) + | MatchOr(pattern* patterns) + + attributes (int lineno, int col_offset, int end_lineno, int end_col_offset) + type_ignore = TypeIgnore(int lineno, string tag) } diff --git a/ast/asdl.py b/ast/asdl.py index 74f84c898..e3e6c34d2 100644 --- a/ast/asdl.py +++ b/ast/asdl.py @@ -33,7 +33,7 @@ __all__ = [ # See the EBNF at the top of the file to understand the logical connection # between the various node types. -builtin_types = {'identifier', 'string', 'int', 'constant', 'bool', 'conversion_flag'} +builtin_types = {'identifier', 'string', 'int', 'constant'} class AST: def __repr__(self): @@ -204,7 +204,7 @@ def check(mod): def parse(filename): """Parse ASDL from the given file and return a Module node describing it.""" - with open(filename) as f: + with open(filename, encoding="utf-8") as f: parser = ASDLParser() return parser.parse(f.read()) @@ -340,12 +340,12 @@ class ASDLParser: def _parse_optional_field_quantifier(self): is_seq, is_opt = False, False - if self.cur_token.kind == TokenKind.Question: - is_opt = True - self._advance() if self.cur_token.kind == TokenKind.Asterisk: is_seq = True self._advance() + elif self.cur_token.kind == TokenKind.Question: + is_opt = True + self._advance() return is_seq, is_opt def _advance(self): From 089eafeabd68c5aad5a260084de4018d252b3b4d Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 12 Aug 2022 03:48:14 +0900 Subject: [PATCH 05/11] update asdl_rs.py for updated Python.asdl --- ast/asdl_rs.py | 28 +++++++++----- ast/src/constant.rs | 18 ++++++--- ast/src/unparse.rs | 36 +++++++++--------- bytecode/src/lib.rs | 3 ++ compiler/src/compile.rs | 75 +++++++++++++------------------------ compiler/src/symboltable.rs | 2 +- parser/python.lalrpop | 10 ++--- parser/src/fstring.rs | 12 +++--- vm/src/frame.rs | 7 ++++ 9 files changed, 96 insertions(+), 95 deletions(-) diff --git a/ast/asdl_rs.py b/ast/asdl_rs.py index 8f3dcd72e..27b8f4429 100755 --- a/ast/asdl_rs.py +++ b/ast/asdl_rs.py @@ -18,8 +18,6 @@ builtin_type_mapping = { 'string': 'String', 'int': 'usize', 'constant': 'Constant', - 'bool': 'bool', - 'conversion_flag': 'ConversionFlag', } assert builtin_type_mapping.keys() == asdl.builtin_types @@ -31,8 +29,10 @@ def get_rust_type(name): """ if name in asdl.builtin_types: return builtin_type_mapping[name] - else: + elif name.islower(): return "".join(part.capitalize() for part in name.split("_")) + else: + return name def is_simple(sum): @@ -252,12 +252,19 @@ class StructVisitor(TypeInfoEmitVisitor): if product.attributes: dataname = rustname + "Data" self.emit_attrs(depth) - self.emit(f"pub struct {dataname}{generics} {{", depth) + has_expr = any(f.type != "identifier" for f in product.fields) + if has_expr: + datadef = f'{dataname}{generics}' + else: + datadef = dataname + self.emit(f"pub struct {datadef} {{", depth) for f in product.fields: self.visit(f, typeinfo, "pub ", depth + 1) self.emit("}", depth) if product.attributes: # attributes should just be location info + if not has_expr: + generics_applied = "" self.emit(f"pub type {rustname} = Located<{dataname}{generics_applied}, U>;", depth); self.emit("", depth) @@ -422,7 +429,7 @@ class ClassDefVisitor(EmitVisitor): self.gen_classdef(name, product.fields, product.attributes, depth) def gen_classdef(self, name, fields, attrs, depth, base="AstNode"): - structname = "Node" + name + structname = "Node" + get_rust_type(name) self.emit(f'#[pyclass(module = "_ast", name = {json.dumps(name)}, base = {json.dumps(base)})]', depth) self.emit(f"struct {structname};", depth) self.emit("#[pyclass(flags(HAS_DICT, BASETYPE))]", depth) @@ -467,7 +474,8 @@ class ExtendModuleVisitor(EmitVisitor): self.visit(type.value, type.name, depth) def visitSum(self, sum, name, depth): - self.emit(f"{json.dumps(name)} => NodeKind{get_rust_type(name)}::make_class(&vm.ctx),", depth) + rust_name = get_rust_type(name) + self.emit(f"{json.dumps(name)} => NodeKind{rust_name}::make_class(&vm.ctx),", depth) for cons in sum.types: self.visit(cons, depth) @@ -478,7 +486,8 @@ class ExtendModuleVisitor(EmitVisitor): self.gen_extension(name, depth) def gen_extension(self, name, depth): - self.emit(f"{json.dumps(name)} => Node{name}::make_class(&vm.ctx),", depth) + rust_name = get_rust_type(name) + self.emit(f"{json.dumps(name)} => Node{rust_name}::make_class(&vm.ctx),", depth) class TraitImplVisitor(EmitVisitor): @@ -494,7 +503,6 @@ class TraitImplVisitor(EmitVisitor): if sum.attributes: enumname += "Kind" - self.emit(f"impl NamedNode for ast::{enumname} {{", depth) self.emit(f"const NAME: &'static str = {json.dumps(name)};", depth + 1) self.emit("}", depth) @@ -546,8 +554,8 @@ class TraitImplVisitor(EmitVisitor): self.emit("}", depth) def make_node(self, variant, fields, depth): - lines = [] - self.emit(f"let _node = AstNode.into_ref_with_type(_vm, Node{variant}::static_type().to_owned()).unwrap();", depth) + rust_variant = get_rust_type(variant) + self.emit(f"let _node = AstNode.into_ref_with_type(_vm, Node{rust_variant}::static_type().to_owned()).unwrap();", depth) if fields: self.emit("let _dict = _node.as_object().dict().unwrap();", depth) for f in fields: diff --git a/ast/src/constant.rs b/ast/src/constant.rs index 507b7bd95..0778f4f06 100644 --- a/ast/src/constant.rs +++ b/ast/src/constant.rs @@ -72,19 +72,19 @@ impl std::fmt::Display for Constant { /// Transforms a value prior to formatting it. #[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[repr(u8)] +#[repr(usize)] pub enum ConversionFlag { /// Converts by calling `str()`. - Str = b's', + Str = b's' as usize, /// Converts by calling `ascii()`. - Ascii = b'a', + Ascii = b'a' as usize, /// Converts by calling `repr()`. - Repr = b'r', + Repr = b'r' as usize, } impl ConversionFlag { - pub fn try_from_byte(b: u8) -> Option { - match b { + pub fn try_from_u32(b: usize) -> Option { + match b.try_into().ok()? { b's' => Some(Self::Str), b'a' => Some(Self::Ascii), b'r' => Some(Self::Repr), @@ -93,6 +93,12 @@ impl ConversionFlag { } } +impl From for ConversionFlag { + fn from(b: usize) -> Self { + Self::try_from_u32(b).unwrap() + } +} + #[cfg(feature = "constant-optimization")] #[non_exhaustive] #[derive(Default)] diff --git a/ast/src/unparse.rs b/ast/src/unparse.rs index 39deaef14..f0370b73f 100644 --- a/ast/src/unparse.rs +++ b/ast/src/unparse.rs @@ -149,13 +149,13 @@ impl<'a> Unparser<'a> { ExprKind::Dict { keys, values } => { self.p("{")?; let mut first = true; - for (k, v) in keys.iter().zip(values) { + let (packed, unpacked) = values.split_at(keys.len()); + for (k, v) in keys.iter().zip(packed) { self.p_delim(&mut first, ", ")?; - if let Some(k) = k { - write!(self, "{}: {}", **k, *v)?; - } else { - write!(self, "**{}", *v)?; - } + write!(self, "{}: {}", *k, *v)?; + } + for d in unpacked { + write!(self, "**{}", *d)?; } self.p("}")?; } @@ -281,7 +281,7 @@ impl<'a> Unparser<'a> { value, conversion, format_spec, - } => self.unparse_formatted(value, *conversion, format_spec.as_deref())?, + } => self.unparse_formatted(value, (*conversion).into(), format_spec.as_deref())?, ExprKind::JoinedStr { values } => self.unparse_joinedstr(values, false)?, ExprKind::Constant { value, kind } => { if let Some(kind) = kind { @@ -397,7 +397,7 @@ impl<'a> Unparser<'a> { self.unparse_arg(kwarg)?; if let Some(default) = i .checked_sub(defaults_start) - .and_then(|i| args.kw_defaults[i].as_deref()) + .and_then(|i| args.kw_defaults.get(i)) { write!(self, "={}", default)?; } @@ -419,7 +419,7 @@ impl<'a> Unparser<'a> { fn unparse_comp(&mut self, generators: &[Comprehension]) -> fmt::Result { for comp in generators { - self.p(if comp.is_async { + self.p(if comp.is_async > 0 { " async for " } else { " for " @@ -445,7 +445,7 @@ impl<'a> Unparser<'a> { fn unparse_formatted( &mut self, val: &Expr, - conversion: Option, + conversion: ConversionFlag, spec: Option<&Expr>, ) -> fmt::Result { let buffered = to_string_fmt(|f| Unparser::new(f).unparse_expr(val, precedence::TEST + 1)); @@ -459,14 +459,12 @@ impl<'a> Unparser<'a> { self.p(&buffered)?; drop(buffered); - if let Some(conv) = conversion { - let flag = match conv { - ConversionFlag::Str => "!s", - ConversionFlag::Ascii => "!a", - ConversionFlag::Repr => "!r", - }; - self.p(flag)?; - } + let flag = match conversion { + ConversionFlag::Str => "!s", + ConversionFlag::Ascii => "!a", + ConversionFlag::Repr => "!r", + }; + self.p(flag)?; if let Some(spec) = spec { self.p(":")?; @@ -492,7 +490,7 @@ impl<'a> Unparser<'a> { value, conversion, format_spec, - } => self.unparse_formatted(value, *conversion, format_spec.as_deref()), + } => self.unparse_formatted(value, (*conversion).into(), format_spec.as_deref()), _ => unreachable!(), } } diff --git a/bytecode/src/lib.rs b/bytecode/src/lib.rs index cf011b458..832ad8473 100644 --- a/bytecode/src/lib.rs +++ b/bytecode/src/lib.rs @@ -357,6 +357,7 @@ pub enum Instruction { for_call: bool, size: u32, }, + DictUpdate, BuildSlice { /// whether build a slice with a third step argument step: bool, @@ -1040,6 +1041,7 @@ impl Instruction { let nargs = if *unpack { *size } else { *size * 2 }; -(nargs as i32) + 1 } + DictUpdate => -1, BuildSlice { step } => -2 - (*step as i32) + 1, ListAppend { .. } | SetAdd { .. } => -1, MapAdd { .. } => -2, @@ -1202,6 +1204,7 @@ impl Instruction { unpack, for_call, } => w!(BuildMap, size, unpack, for_call), + DictUpdate => w!(DictUpdate), BuildSlice { step } => w!(BuildSlice, step), ListAppend { i } => w!(ListAppend, i), SetAdd { i } => w!(SetAdd, i), diff --git a/compiler/src/compile.rs b/compiler/src/compile.rs index 8c8438aee..efb5e0873 100644 --- a/compiler/src/compile.rs +++ b/compiler/src/compile.rs @@ -552,6 +552,7 @@ impl Compiler { Import { names } => { // import a, b, c as d for name in names { + let name = &name.node; self.emit_constant(ConstantData::Integer { value: num_traits::Zero::zero(), }); @@ -574,7 +575,7 @@ impl Compiler { module, names, } => { - let import_star = names.iter().any(|n| n.name == "*"); + let import_star = names.iter().any(|n| n.node.name == "*"); let from_list = if import_star { if self.ctx.in_func() { @@ -588,7 +589,7 @@ impl Compiler { names .iter() .map(|n| ConstantData::Str { - value: n.name.to_owned(), + value: n.node.name.to_owned(), }) .collect() }; @@ -597,7 +598,7 @@ impl Compiler { // from .... import (*fromlist) self.emit_constant(ConstantData::Integer { - value: (*level).into(), + value: (*level).unwrap_or(0).into(), }); self.emit_constant(ConstantData::Tuple { elements: from_list, @@ -615,6 +616,7 @@ impl Compiler { // from mod import a, b as c for name in names { + let name = &name.node; let idx = self.name(&name.name); // import symbol from module: self.emit(Instruction::ImportFrom { idx }); @@ -881,13 +883,11 @@ impl Compiler { let mut num_kw_only_defaults = 0; for (kw, default) in args.kwonlyargs.iter().zip(&args.kw_defaults) { - if let Some(default) = default { - self.emit_constant(ConstantData::Str { - value: kw.node.arg.clone(), - }); - self.compile_expression(default)?; - num_kw_only_defaults += 1; - } + self.emit_constant(ConstantData::Str { + value: kw.node.arg.clone(), + }); + self.compile_expression(default)?; + num_kw_only_defaults += 1; } if num_kw_only_defaults > 0 { self.emit(Instruction::BuildMap { @@ -1930,49 +1930,28 @@ impl Compiler { fn compile_dict( &mut self, - keys: &[Option>], + keys: &[ast::Expr], values: &[ast::Expr], ) -> CompileResult<()> { let mut size = 0; - let mut has_unpacking = false; - for (is_unpacking, subpairs) in &keys.iter().zip(values).group_by(|e| e.0.is_none()) { - if is_unpacking { - for (_, value) in subpairs { - self.compile_expression(value)?; - size += 1; - } - has_unpacking = true; - } else { - let mut subsize = 0; - for (key, value) in subpairs { - if let Some(key) = key { - self.compile_expression(key)?; - self.compile_expression(value)?; - subsize += 1; - } - } - self.emit(Instruction::BuildMap { - size: subsize, - unpack: false, - for_call: false, - }); - size += 1; - } + + let (packed_values, unpacked_values) = values.split_at(keys.len()); + for (key, value) in keys.iter().zip(packed_values) { + self.compile_expression(key)?; + self.compile_expression(value)?; + size += 1; } - if size == 0 { - self.emit(Instruction::BuildMap { - size, - unpack: false, - for_call: false, - }); - } - if size > 1 || has_unpacking { - self.emit(Instruction::BuildMap { - size, - unpack: true, - for_call: false, - }); + self.emit(Instruction::BuildMap { + size, + unpack: false, + for_call: false, + }); + + for value in unpacked_values { + self.compile_expression(value)?; + self.emit(Instruction::DictUpdate); } + Ok(()) } diff --git a/compiler/src/symboltable.rs b/compiler/src/symboltable.rs index 9a216cdf4..387656349 100644 --- a/compiler/src/symboltable.rs +++ b/compiler/src/symboltable.rs @@ -1094,7 +1094,7 @@ impl SymbolTableBuilder { ) -> SymbolTableResult { // Evaluate eventual default parameters: self.scan_expressions(&args.defaults, ExpressionContext::Load)?; - for expression in args.kw_defaults.iter().flatten() { + for expression in args.kw_defaults.iter() { self.scan_expression(expression, ExpressionContext::Load)?; } diff --git a/parser/python.lalrpop b/parser/python.lalrpop index bf3e0a401..3d2dd189e 100644 --- a/parser/python.lalrpop +++ b/parser/python.lalrpop @@ -131,7 +131,7 @@ ExpressionStatement: ast::Stmt = { target: Box::new(target), annotation: Box::new(annotation), value: rhs.map(Box::new), - simple, + simple: if simple { 1 } else { 0 }, }, } }, @@ -253,12 +253,12 @@ ImportStatement: ast::Stmt = { }, }; -ImportFromLocation: (usize, Option) = { +ImportFromLocation: (Option, Option) = { => { - (dots.iter().sum(), Some(name)) + (Some(dots.iter().sum()), Some(name)) }, => { - (dots.iter().sum(), None) + (Some(dots.iter().sum()), None) }, }; @@ -272,7 +272,7 @@ ImportAsNames: Vec = { "(" >> ","? ")" => i, "*" => { // Star import all - vec![ast::Alias { name: "*".to_string(), asname: None }] + vec![ast::Alias(ast::AliasData { name: "*".to_string(), asname: None })] }, }; diff --git a/parser/src/fstring.rs b/parser/src/fstring.rs index b0ebef7f3..9ffc116de 100644 --- a/parser/src/fstring.rs +++ b/parser/src/fstring.rs @@ -30,7 +30,7 @@ impl<'a> FStringParser<'a> { let mut expression = String::new(); let mut spec = None; let mut delims = Vec::new(); - let mut conversion = None; + let mut conversion = ConversionFlag::Str; let mut pred_expression_text = String::new(); let mut trailing_seq = String::new(); @@ -63,7 +63,7 @@ impl<'a> FStringParser<'a> { return Err(EmptyExpression); } - conversion = Some(match self.chars.next() { + conversion = match self.chars.next() { Some('s') => ConversionFlag::Str, Some('a') => ConversionFlag::Ascii, Some('r') => ConversionFlag::Repr, @@ -73,7 +73,7 @@ impl<'a> FStringParser<'a> { None => { return Err(ExpectedRbrace); } - }); + }; if let Some(&peek) = self.chars.peek() { if peek != '}' && peek != ':' { @@ -115,7 +115,7 @@ impl<'a> FStringParser<'a> { ) .parse()?, ), - conversion: None, + conversion: b's' as usize, format_spec: None, }), ); @@ -187,7 +187,7 @@ impl<'a> FStringParser<'a> { parse_fstring_expr(&expression) .map_err(|e| InvalidExpression(Box::new(e.error)))?, ), - conversion, + conversion: conversion as usize, format_spec: spec, })] } else { @@ -205,7 +205,7 @@ impl<'a> FStringParser<'a> { parse_fstring_expr(&expression) .map_err(|e| InvalidExpression(Box::new(e.error)))?, ), - conversion, + conversion: conversion as usize, format_spec: spec, }), ] diff --git a/vm/src/frame.rs b/vm/src/frame.rs index e5677eef4..4b60b296d 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -677,6 +677,13 @@ impl ExecutingFrame<'_> { unpack, for_call, } => self.execute_build_map(vm, *size, *unpack, *for_call), + bytecode::Instruction::DictUpdate => { + let other = self.pop_value(); + let dict = self.pop_value(); + let updated = vm.call_method(&dict, "update", (other,))?; + self.push_value(updated); + Ok(None) + } bytecode::Instruction::BuildSlice { step } => self.execute_build_slice(vm, *step), bytecode::Instruction::ListAppend { i } => { let item = self.pop_value(); From e5796e4f4ff1d526ff4c1f66df5c83aa23ae8d71 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Wed, 17 Aug 2022 04:12:32 +0900 Subject: [PATCH 06/11] black asdl_rs.py --- ast/asdl_rs.py | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/ast/asdl_rs.py b/ast/asdl_rs.py index 27b8f4429..a4c894aaf 100755 --- a/ast/asdl_rs.py +++ b/ast/asdl_rs.py @@ -14,10 +14,10 @@ TABSIZE = 4 AUTOGEN_MESSAGE = "// File automatically generated by {}.\n" builtin_type_mapping = { - 'identifier': 'Ident', - 'string': 'String', - 'int': 'usize', - 'constant': 'Constant', + "identifier": "Ident", + "string": "String", + "int": "usize", + "constant": "Constant", } assert builtin_type_mapping.keys() == asdl.builtin_types @@ -254,7 +254,7 @@ class StructVisitor(TypeInfoEmitVisitor): self.emit_attrs(depth) has_expr = any(f.type != "identifier" for f in product.fields) if has_expr: - datadef = f'{dataname}{generics}' + datadef = f"{dataname}{generics}" else: datadef = dataname self.emit(f"pub struct {datadef} {{", depth) @@ -265,7 +265,10 @@ class StructVisitor(TypeInfoEmitVisitor): # attributes should just be location info if not has_expr: generics_applied = "" - self.emit(f"pub type {rustname} = Located<{dataname}{generics_applied}, U>;", depth); + self.emit( + f"pub type {rustname} = Located<{dataname}{generics_applied}, U>;", + depth, + ) self.emit("", depth) @@ -430,7 +433,10 @@ class ClassDefVisitor(EmitVisitor): def gen_classdef(self, name, fields, attrs, depth, base="AstNode"): structname = "Node" + get_rust_type(name) - self.emit(f'#[pyclass(module = "_ast", name = {json.dumps(name)}, base = {json.dumps(base)})]', depth) + self.emit( + f'#[pyclass(module = "_ast", name = {json.dumps(name)}, base = {json.dumps(base)})]', + depth, + ) self.emit(f"struct {structname};", depth) self.emit("#[pyclass(flags(HAS_DICT, BASETYPE))]", depth) self.emit(f"impl {structname} {{", depth) @@ -475,7 +481,9 @@ class ExtendModuleVisitor(EmitVisitor): def visitSum(self, sum, name, depth): rust_name = get_rust_type(name) - self.emit(f"{json.dumps(name)} => NodeKind{rust_name}::make_class(&vm.ctx),", depth) + self.emit( + f"{json.dumps(name)} => NodeKind{rust_name}::make_class(&vm.ctx),", depth + ) for cons in sum.types: self.visit(cons, depth) @@ -555,7 +563,10 @@ class TraitImplVisitor(EmitVisitor): def make_node(self, variant, fields, depth): rust_variant = get_rust_type(variant) - self.emit(f"let _node = AstNode.into_ref_with_type(_vm, Node{rust_variant}::static_type().to_owned()).unwrap();", depth) + self.emit( + f"let _node = AstNode.into_ref_with_type(_vm, Node{rust_variant}::static_type().to_owned()).unwrap();", + depth, + ) if fields: self.emit("let _dict = _node.as_object().dict().unwrap();", depth) for f in fields: From 0d334a9b0e3e25659cc1374043451c6927032efb Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 12 Aug 2022 03:49:00 +0900 Subject: [PATCH 07/11] Update generated ast modules for changed asdl_rs.py --- ast/src/ast_gen.rs | 180 ++++++++++-- vm/src/stdlib/ast/gen.rs | 596 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 725 insertions(+), 51 deletions(-) diff --git a/ast/src/ast_gen.rs b/ast/src/ast_gen.rs index 03f7c3129..fda39b845 100644 --- a/ast/src/ast_gen.rs +++ b/ast/src/ast_gen.rs @@ -87,7 +87,7 @@ pub enum StmtKind { target: Box>, annotation: Box>, value: Option>>, - simple: bool, + simple: usize, }, For { target: Box>, @@ -123,6 +123,10 @@ pub enum StmtKind { body: Vec>, type_comment: Option, }, + Match { + subject: Box>, + cases: Vec>, + }, Raise { exc: Option>>, cause: Option>>, @@ -138,12 +142,12 @@ pub enum StmtKind { msg: Option>>, }, Import { - names: Vec, + names: Vec>, }, ImportFrom { module: Option, - names: Vec, - level: usize, + names: Vec>, + level: Option, }, Global { names: Vec, @@ -189,7 +193,7 @@ pub enum ExprKind { orelse: Box>, }, Dict { - keys: Vec>>>, + keys: Vec>, values: Vec>, }, Set { @@ -233,7 +237,7 @@ pub enum ExprKind { }, FormattedValue { value: Box>, - conversion: Option, + conversion: usize, format_spec: Option>>, }, JoinedStr { @@ -334,7 +338,7 @@ pub struct Comprehension { pub target: Box>, pub iter: Box>, pub ifs: Vec>, - pub is_async: bool, + pub is_async: usize, } #[derive(Debug, PartialEq)] @@ -353,7 +357,7 @@ pub struct Arguments { pub args: Vec>, pub vararg: Option>>, pub kwonlyargs: Vec>, - pub kw_defaults: Vec>>>, + pub kw_defaults: Vec>, pub kwarg: Option>>, pub defaults: Vec>, } @@ -374,10 +378,11 @@ pub struct KeywordData { pub type Keyword = Located, U>; #[derive(Debug, PartialEq)] -pub struct Alias { +pub struct AliasData { pub name: Ident, pub asname: Option, } +pub type Alias = Located; #[derive(Debug, PartialEq)] pub struct Withitem { @@ -385,6 +390,48 @@ pub struct Withitem { pub optional_vars: Option>>, } +#[derive(Debug, PartialEq)] +pub struct MatchCase { + pub pattern: Box>, + pub guard: Option>>, + pub body: Vec>, +} + +#[derive(Debug, PartialEq)] +pub enum PatternKind { + MatchValue { + value: Box>, + }, + MatchSingleton { + value: Constant, + }, + MatchSequence { + patterns: Vec>, + }, + MatchMapping { + keys: Vec>, + patterns: Vec>, + rest: Option, + }, + MatchClass { + cls: Box>, + patterns: Vec>, + kwd_attrs: Vec, + kwd_patterns: Vec>, + }, + MatchStar { + name: Option, + }, + MatchAs { + pattern: Option>>, + name: Option, + }, + MatchOr { + patterns: Vec>, + }, +} +pub type Pattern = Located, U>; + #[derive(Debug, PartialEq)] pub enum TypeIgnore { TypeIgnore { lineno: usize, tag: String }, @@ -449,7 +496,7 @@ pub mod fold { ) -> Result, Self::Error> { fold_keyword(self, node) } - fn fold_alias(&mut self, node: Alias) -> Result { + fn fold_alias(&mut self, node: Alias) -> Result, Self::Error> { fold_alias(self, node) } fn fold_withitem( @@ -458,6 +505,18 @@ pub mod fold { ) -> Result, Self::Error> { fold_withitem(self, node) } + fn fold_match_case( + &mut self, + node: MatchCase, + ) -> Result, Self::Error> { + fold_match_case(self, node) + } + fn fold_pattern( + &mut self, + node: Pattern, + ) -> Result, Self::Error> { + fold_pattern(self, node) + } fn fold_type_ignore(&mut self, node: TypeIgnore) -> Result { fold_type_ignore(self, node) } @@ -645,6 +704,10 @@ pub mod fold { body: Foldable::fold(body, folder)?, type_comment: Foldable::fold(type_comment, folder)?, }), + StmtKind::Match { subject, cases } => Ok(StmtKind::Match { + subject: Foldable::fold(subject, folder)?, + cases: Foldable::fold(cases, folder)?, + }), StmtKind::Raise { exc, cause } => Ok(StmtKind::Raise { exc: Foldable::fold(exc, folder)?, cause: Foldable::fold(cause, folder)?, @@ -1074,8 +1137,8 @@ pub mod fold { }) }) } - impl Foldable for Alias { - type Mapped = Alias; + impl Foldable for Alias { + type Mapped = Alias; fn fold + ?Sized>( self, folder: &mut F, @@ -1085,12 +1148,14 @@ pub mod fold { } pub fn fold_alias + ?Sized>( #[allow(unused)] folder: &mut F, - node: Alias, - ) -> Result { - let Alias { name, asname } = node; - Ok(Alias { - name: Foldable::fold(name, folder)?, - asname: Foldable::fold(asname, folder)?, + node: Alias, + ) -> Result, F::Error> { + fold_located(folder, node, |folder, node| { + let AliasData { name, asname } = node; + Ok(AliasData { + name: Foldable::fold(name, folder)?, + asname: Foldable::fold(asname, folder)?, + }) }) } impl Foldable for Withitem { @@ -1115,6 +1180,85 @@ pub mod fold { optional_vars: Foldable::fold(optional_vars, folder)?, }) } + impl Foldable for MatchCase { + type Mapped = MatchCase; + fn fold + ?Sized>( + self, + folder: &mut F, + ) -> Result { + folder.fold_match_case(self) + } + } + pub fn fold_match_case + ?Sized>( + #[allow(unused)] folder: &mut F, + node: MatchCase, + ) -> Result, F::Error> { + let MatchCase { + pattern, + guard, + body, + } = node; + Ok(MatchCase { + pattern: Foldable::fold(pattern, folder)?, + guard: Foldable::fold(guard, folder)?, + body: Foldable::fold(body, folder)?, + }) + } + impl Foldable for Pattern { + type Mapped = Pattern; + fn fold + ?Sized>( + self, + folder: &mut F, + ) -> Result { + folder.fold_pattern(self) + } + } + pub fn fold_pattern + ?Sized>( + #[allow(unused)] folder: &mut F, + node: Pattern, + ) -> Result, F::Error> { + fold_located(folder, node, |folder, node| match node { + PatternKind::MatchValue { value } => Ok(PatternKind::MatchValue { + value: Foldable::fold(value, folder)?, + }), + PatternKind::MatchSingleton { value } => Ok(PatternKind::MatchSingleton { + value: Foldable::fold(value, folder)?, + }), + PatternKind::MatchSequence { patterns } => Ok(PatternKind::MatchSequence { + patterns: Foldable::fold(patterns, folder)?, + }), + PatternKind::MatchMapping { + keys, + patterns, + rest, + } => Ok(PatternKind::MatchMapping { + keys: Foldable::fold(keys, folder)?, + patterns: Foldable::fold(patterns, folder)?, + rest: Foldable::fold(rest, folder)?, + }), + PatternKind::MatchClass { + cls, + patterns, + kwd_attrs, + kwd_patterns, + } => Ok(PatternKind::MatchClass { + cls: Foldable::fold(cls, folder)?, + patterns: Foldable::fold(patterns, folder)?, + kwd_attrs: Foldable::fold(kwd_attrs, folder)?, + kwd_patterns: Foldable::fold(kwd_patterns, folder)?, + }), + PatternKind::MatchStar { name } => Ok(PatternKind::MatchStar { + name: Foldable::fold(name, folder)?, + }), + PatternKind::MatchAs { pattern, name } => Ok(PatternKind::MatchAs { + pattern: Foldable::fold(pattern, folder)?, + name: Foldable::fold(name, folder)?, + }), + PatternKind::MatchOr { patterns } => Ok(PatternKind::MatchOr { + patterns: Foldable::fold(patterns, folder)?, + }), + }) + } impl Foldable for TypeIgnore { type Mapped = TypeIgnore; fn fold + ?Sized>( diff --git a/vm/src/stdlib/ast/gen.rs b/vm/src/stdlib/ast/gen.rs index c2980892d..26e1445c6 100644 --- a/vm/src/stdlib/ast/gen.rs +++ b/vm/src/stdlib/ast/gen.rs @@ -458,6 +458,32 @@ impl NodeAsyncWith { ); } } +#[pyclass(module = "_ast", name = "Match", base = "NodeKindStmt")] +struct NodeMatch; +#[pyclass(flags(HAS_DICT, BASETYPE))] +impl NodeMatch { + #[extend_class] + fn extend_class_with_fields(ctx: &Context, class: &'static Py) { + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ + ctx.new_str(ascii!("subject")).into(), + ctx.new_str(ascii!("cases")).into(), + ]) + .into(), + ); + class.set_attr( + identifier!(ctx, _attributes), + ctx.new_list(vec![ + ctx.new_str(ascii!("lineno")).into(), + ctx.new_str(ascii!("col_offset")).into(), + ctx.new_str(ascii!("end_lineno")).into(), + ctx.new_str(ascii!("end_col_offset")).into(), + ]) + .into(), + ); + } +} #[pyclass(module = "_ast", name = "Raise", base = "NodeKindStmt")] struct NodeRaise; #[pyclass(flags(HAS_DICT, BASETYPE))] @@ -1755,9 +1781,9 @@ impl NodeNotIn { } } #[pyclass(module = "_ast", name = "comprehension", base = "AstNode")] -struct Nodecomprehension; +struct NodeComprehension; #[pyclass(flags(HAS_DICT, BASETYPE))] -impl Nodecomprehension { +impl NodeComprehension { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &'static Py) { class.set_attr( @@ -1809,9 +1835,9 @@ impl NodeExceptHandler { } } #[pyclass(module = "_ast", name = "arguments", base = "AstNode")] -struct Nodearguments; +struct NodeArguments; #[pyclass(flags(HAS_DICT, BASETYPE))] -impl Nodearguments { +impl NodeArguments { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &'static Py) { class.set_attr( @@ -1831,9 +1857,9 @@ impl Nodearguments { } } #[pyclass(module = "_ast", name = "arg", base = "AstNode")] -struct Nodearg; +struct NodeArg; #[pyclass(flags(HAS_DICT, BASETYPE))] -impl Nodearg { +impl NodeArg { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &'static Py) { class.set_attr( @@ -1858,9 +1884,9 @@ impl Nodearg { } } #[pyclass(module = "_ast", name = "keyword", base = "AstNode")] -struct Nodekeyword; +struct NodeKeyword; #[pyclass(flags(HAS_DICT, BASETYPE))] -impl Nodekeyword { +impl NodeKeyword { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &'static Py) { class.set_attr( @@ -1884,9 +1910,9 @@ impl Nodekeyword { } } #[pyclass(module = "_ast", name = "alias", base = "AstNode")] -struct Nodealias; +struct NodeAlias; #[pyclass(flags(HAS_DICT, BASETYPE))] -impl Nodealias { +impl NodeAlias { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &'static Py) { class.set_attr( @@ -1897,13 +1923,22 @@ impl Nodealias { ]) .into(), ); - class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); + class.set_attr( + identifier!(ctx, _attributes), + ctx.new_list(vec![ + ctx.new_str(ascii!("lineno")).into(), + ctx.new_str(ascii!("col_offset")).into(), + ctx.new_str(ascii!("end_lineno")).into(), + ctx.new_str(ascii!("end_col_offset")).into(), + ]) + .into(), + ); } } #[pyclass(module = "_ast", name = "withitem", base = "AstNode")] -struct Nodewithitem; +struct NodeWithitem; #[pyclass(flags(HAS_DICT, BASETYPE))] -impl Nodewithitem { +impl NodeWithitem { #[extend_class] fn extend_class_with_fields(ctx: &Context, class: &'static Py) { class.set_attr( @@ -1917,6 +1952,224 @@ impl Nodewithitem { class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); } } +#[pyclass(module = "_ast", name = "match_case", base = "AstNode")] +struct NodeMatchCase; +#[pyclass(flags(HAS_DICT, BASETYPE))] +impl NodeMatchCase { + #[extend_class] + fn extend_class_with_fields(ctx: &Context, class: &'static Py) { + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ + ctx.new_str(ascii!("pattern")).into(), + ctx.new_str(ascii!("guard")).into(), + ctx.new_str(ascii!("body")).into(), + ]) + .into(), + ); + class.set_attr(identifier!(ctx, _attributes), ctx.new_list(vec![]).into()); + } +} +#[pyclass(module = "_ast", name = "pattern", base = "AstNode")] +struct NodeKindPattern; +#[pyclass(flags(HAS_DICT, BASETYPE))] +impl NodeKindPattern {} +#[pyclass(module = "_ast", name = "MatchValue", base = "NodeKindPattern")] +struct NodeMatchValue; +#[pyclass(flags(HAS_DICT, BASETYPE))] +impl NodeMatchValue { + #[extend_class] + fn extend_class_with_fields(ctx: &Context, class: &'static Py) { + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]) + .into(), + ); + class.set_attr( + identifier!(ctx, _attributes), + ctx.new_list(vec![ + ctx.new_str(ascii!("lineno")).into(), + ctx.new_str(ascii!("col_offset")).into(), + ctx.new_str(ascii!("end_lineno")).into(), + ctx.new_str(ascii!("end_col_offset")).into(), + ]) + .into(), + ); + } +} +#[pyclass(module = "_ast", name = "MatchSingleton", base = "NodeKindPattern")] +struct NodeMatchSingleton; +#[pyclass(flags(HAS_DICT, BASETYPE))] +impl NodeMatchSingleton { + #[extend_class] + fn extend_class_with_fields(ctx: &Context, class: &'static Py) { + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("value")).into()]) + .into(), + ); + class.set_attr( + identifier!(ctx, _attributes), + ctx.new_list(vec![ + ctx.new_str(ascii!("lineno")).into(), + ctx.new_str(ascii!("col_offset")).into(), + ctx.new_str(ascii!("end_lineno")).into(), + ctx.new_str(ascii!("end_col_offset")).into(), + ]) + .into(), + ); + } +} +#[pyclass(module = "_ast", name = "MatchSequence", base = "NodeKindPattern")] +struct NodeMatchSequence; +#[pyclass(flags(HAS_DICT, BASETYPE))] +impl NodeMatchSequence { + #[extend_class] + fn extend_class_with_fields(ctx: &Context, class: &'static Py) { + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("patterns")).into()]) + .into(), + ); + class.set_attr( + identifier!(ctx, _attributes), + ctx.new_list(vec![ + ctx.new_str(ascii!("lineno")).into(), + ctx.new_str(ascii!("col_offset")).into(), + ctx.new_str(ascii!("end_lineno")).into(), + ctx.new_str(ascii!("end_col_offset")).into(), + ]) + .into(), + ); + } +} +#[pyclass(module = "_ast", name = "MatchMapping", base = "NodeKindPattern")] +struct NodeMatchMapping; +#[pyclass(flags(HAS_DICT, BASETYPE))] +impl NodeMatchMapping { + #[extend_class] + fn extend_class_with_fields(ctx: &Context, class: &'static Py) { + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ + ctx.new_str(ascii!("keys")).into(), + ctx.new_str(ascii!("patterns")).into(), + ctx.new_str(ascii!("rest")).into(), + ]) + .into(), + ); + class.set_attr( + identifier!(ctx, _attributes), + ctx.new_list(vec![ + ctx.new_str(ascii!("lineno")).into(), + ctx.new_str(ascii!("col_offset")).into(), + ctx.new_str(ascii!("end_lineno")).into(), + ctx.new_str(ascii!("end_col_offset")).into(), + ]) + .into(), + ); + } +} +#[pyclass(module = "_ast", name = "MatchClass", base = "NodeKindPattern")] +struct NodeMatchClass; +#[pyclass(flags(HAS_DICT, BASETYPE))] +impl NodeMatchClass { + #[extend_class] + fn extend_class_with_fields(ctx: &Context, class: &'static Py) { + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ + ctx.new_str(ascii!("cls")).into(), + ctx.new_str(ascii!("patterns")).into(), + ctx.new_str(ascii!("kwd_attrs")).into(), + ctx.new_str(ascii!("kwd_patterns")).into(), + ]) + .into(), + ); + class.set_attr( + identifier!(ctx, _attributes), + ctx.new_list(vec![ + ctx.new_str(ascii!("lineno")).into(), + ctx.new_str(ascii!("col_offset")).into(), + ctx.new_str(ascii!("end_lineno")).into(), + ctx.new_str(ascii!("end_col_offset")).into(), + ]) + .into(), + ); + } +} +#[pyclass(module = "_ast", name = "MatchStar", base = "NodeKindPattern")] +struct NodeMatchStar; +#[pyclass(flags(HAS_DICT, BASETYPE))] +impl NodeMatchStar { + #[extend_class] + fn extend_class_with_fields(ctx: &Context, class: &'static Py) { + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("name")).into()]) + .into(), + ); + class.set_attr( + identifier!(ctx, _attributes), + ctx.new_list(vec![ + ctx.new_str(ascii!("lineno")).into(), + ctx.new_str(ascii!("col_offset")).into(), + ctx.new_str(ascii!("end_lineno")).into(), + ctx.new_str(ascii!("end_col_offset")).into(), + ]) + .into(), + ); + } +} +#[pyclass(module = "_ast", name = "MatchAs", base = "NodeKindPattern")] +struct NodeMatchAs; +#[pyclass(flags(HAS_DICT, BASETYPE))] +impl NodeMatchAs { + #[extend_class] + fn extend_class_with_fields(ctx: &Context, class: &'static Py) { + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ + ctx.new_str(ascii!("pattern")).into(), + ctx.new_str(ascii!("name")).into(), + ]) + .into(), + ); + class.set_attr( + identifier!(ctx, _attributes), + ctx.new_list(vec![ + ctx.new_str(ascii!("lineno")).into(), + ctx.new_str(ascii!("col_offset")).into(), + ctx.new_str(ascii!("end_lineno")).into(), + ctx.new_str(ascii!("end_col_offset")).into(), + ]) + .into(), + ); + } +} +#[pyclass(module = "_ast", name = "MatchOr", base = "NodeKindPattern")] +struct NodeMatchOr; +#[pyclass(flags(HAS_DICT, BASETYPE))] +impl NodeMatchOr { + #[extend_class] + fn extend_class_with_fields(ctx: &Context, class: &'static Py) { + class.set_attr( + identifier!(ctx, _fields), + ctx.new_list(vec![ctx.new_str(ascii!("patterns")).into()]) + .into(), + ); + class.set_attr( + identifier!(ctx, _attributes), + ctx.new_list(vec![ + ctx.new_str(ascii!("lineno")).into(), + ctx.new_str(ascii!("col_offset")).into(), + ctx.new_str(ascii!("end_lineno")).into(), + ctx.new_str(ascii!("end_col_offset")).into(), + ]) + .into(), + ); + } +} #[pyclass(module = "_ast", name = "type_ignore", base = "AstNode")] struct NodeKindTypeIgnore; #[pyclass(flags(HAS_DICT, BASETYPE))] @@ -2334,6 +2587,19 @@ impl Node for ast::StmtKind { .unwrap(); _node.into() } + ast::StmtKind::Match { subject, cases } => { + let _node = AstNode + .into_ref_with_type(_vm, NodeMatch::static_type().to_owned()) + .unwrap(); + let _dict = _node.as_object().dict().unwrap(); + _dict + .set_item("subject", subject.ast_to_object(_vm), _vm) + .unwrap(); + _dict + .set_item("cases", cases.ast_to_object(_vm), _vm) + .unwrap(); + _node.into() + } ast::StmtKind::Raise { exc, cause } => { let _node = AstNode .into_ref_with_type(_vm, NodeRaise::static_type().to_owned()) @@ -2629,6 +2895,14 @@ impl Node for ast::StmtKind { .map(|obj| Node::ast_from_object(_vm, obj)) .transpose()?, } + } else if _cls.is(NodeMatch::static_type()) { + ast::StmtKind::Match { + subject: Node::ast_from_object( + _vm, + get_node_field(_vm, &_object, "subject", "stmt")?, + )?, + cases: Node::ast_from_object(_vm, get_node_field(_vm, &_object, "cases", "stmt")?)?, + } } else if _cls.is(NodeRaise::static_type()) { ast::StmtKind::Raise { exc: get_node_field_opt(_vm, &_object, "exc")? @@ -2671,7 +2945,9 @@ impl Node for ast::StmtKind { .map(|obj| Node::ast_from_object(_vm, obj)) .transpose()?, names: Node::ast_from_object(_vm, get_node_field(_vm, &_object, "names", "stmt")?)?, - level: Node::ast_from_object(_vm, get_node_field(_vm, &_object, "level", "stmt")?)?, + level: get_node_field_opt(_vm, &_object, "level")? + .map(|obj| Node::ast_from_object(_vm, obj)) + .transpose()?, } } else if _cls.is(NodeGlobal::static_type()) { ast::StmtKind::Global { @@ -3186,9 +3462,10 @@ impl Node for ast::ExprKind { } else if _cls.is(NodeFormattedValue::static_type()) { ast::ExprKind::FormattedValue { value: Node::ast_from_object(_vm, get_node_field(_vm, &_object, "value", "expr")?)?, - conversion: get_node_field_opt(_vm, &_object, "conversion")? - .map(|obj| Node::ast_from_object(_vm, obj)) - .transpose()?, + conversion: Node::ast_from_object( + _vm, + get_node_field(_vm, &_object, "conversion", "expr")?, + )?, format_spec: get_node_field_opt(_vm, &_object, "format_spec")? .map(|obj| Node::ast_from_object(_vm, obj)) .transpose()?, @@ -3617,7 +3894,7 @@ impl Node for ast::Comprehension { is_async, } = self; let _node = AstNode - .into_ref_with_type(_vm, Nodecomprehension::static_type().to_owned()) + .into_ref_with_type(_vm, NodeComprehension::static_type().to_owned()) .unwrap(); let _dict = _node.as_object().dict().unwrap(); _dict @@ -3725,7 +4002,7 @@ impl Node for ast::Arguments { defaults, } = self; let _node = AstNode - .into_ref_with_type(_vm, Nodearguments::static_type().to_owned()) + .into_ref_with_type(_vm, NodeArguments::static_type().to_owned()) .unwrap(); let _dict = _node.as_object().dict().unwrap(); _dict @@ -3790,7 +4067,7 @@ impl Node for ast::ArgData { type_comment, } = self; let _node = AstNode - .into_ref_with_type(_vm, Nodearg::static_type().to_owned()) + .into_ref_with_type(_vm, NodeArg::static_type().to_owned()) .unwrap(); let _dict = _node.as_object().dict().unwrap(); _dict.set_item("arg", arg.ast_to_object(_vm), _vm).unwrap(); @@ -3825,7 +4102,7 @@ impl Node for ast::KeywordData { fn ast_to_object(self, _vm: &VirtualMachine) -> PyObjectRef { let ast::KeywordData { arg, value } = self; let _node = AstNode - .into_ref_with_type(_vm, Nodekeyword::static_type().to_owned()) + .into_ref_with_type(_vm, NodeKeyword::static_type().to_owned()) .unwrap(); let _dict = _node.as_object().dict().unwrap(); _dict.set_item("arg", arg.ast_to_object(_vm), _vm).unwrap(); @@ -3847,14 +4124,14 @@ impl Node for ast::KeywordData { }) } } -impl NamedNode for ast::Alias { +impl NamedNode for ast::AliasData { const NAME: &'static str = "alias"; } -impl Node for ast::Alias { +impl Node for ast::AliasData { fn ast_to_object(self, _vm: &VirtualMachine) -> PyObjectRef { - let ast::Alias { name, asname } = self; + let ast::AliasData { name, asname } = self; let _node = AstNode - .into_ref_with_type(_vm, Nodealias::static_type().to_owned()) + .into_ref_with_type(_vm, NodeAlias::static_type().to_owned()) .unwrap(); let _dict = _node.as_object().dict().unwrap(); _dict @@ -3866,7 +4143,11 @@ impl Node for ast::Alias { _node.into() } fn ast_from_object(_vm: &VirtualMachine, _object: PyObjectRef) -> PyResult { - Ok(ast::Alias { + let _location = ast::Location::new( + Node::ast_from_object(_vm, get_node_field(_vm, &_object, "lineno", "alias")?)?, + Node::ast_from_object(_vm, get_node_field(_vm, &_object, "col_offset", "alias")?)?, + ); + Ok(ast::AliasData { name: Node::ast_from_object(_vm, get_node_field(_vm, &_object, "name", "alias")?)?, asname: get_node_field_opt(_vm, &_object, "asname")? .map(|obj| Node::ast_from_object(_vm, obj)) @@ -3884,7 +4165,7 @@ impl Node for ast::Withitem { optional_vars, } = self; let _node = AstNode - .into_ref_with_type(_vm, Nodewithitem::static_type().to_owned()) + .into_ref_with_type(_vm, NodeWithitem::static_type().to_owned()) .unwrap(); let _dict = _node.as_object().dict().unwrap(); _dict @@ -3907,6 +4188,244 @@ impl Node for ast::Withitem { }) } } +impl NamedNode for ast::MatchCase { + const NAME: &'static str = "match_case"; +} +impl Node for ast::MatchCase { + fn ast_to_object(self, _vm: &VirtualMachine) -> PyObjectRef { + let ast::MatchCase { + pattern, + guard, + body, + } = self; + let _node = AstNode + .into_ref_with_type(_vm, NodeMatchCase::static_type().to_owned()) + .unwrap(); + let _dict = _node.as_object().dict().unwrap(); + _dict + .set_item("pattern", pattern.ast_to_object(_vm), _vm) + .unwrap(); + _dict + .set_item("guard", guard.ast_to_object(_vm), _vm) + .unwrap(); + _dict + .set_item("body", body.ast_to_object(_vm), _vm) + .unwrap(); + _node.into() + } + fn ast_from_object(_vm: &VirtualMachine, _object: PyObjectRef) -> PyResult { + Ok(ast::MatchCase { + pattern: Node::ast_from_object( + _vm, + get_node_field(_vm, &_object, "pattern", "match_case")?, + )?, + guard: get_node_field_opt(_vm, &_object, "guard")? + .map(|obj| Node::ast_from_object(_vm, obj)) + .transpose()?, + body: Node::ast_from_object(_vm, get_node_field(_vm, &_object, "body", "match_case")?)?, + }) + } +} +impl NamedNode for ast::PatternKind { + const NAME: &'static str = "pattern"; +} +impl Node for ast::PatternKind { + fn ast_to_object(self, _vm: &VirtualMachine) -> PyObjectRef { + match self { + ast::PatternKind::MatchValue { value } => { + let _node = AstNode + .into_ref_with_type(_vm, NodeMatchValue::static_type().to_owned()) + .unwrap(); + let _dict = _node.as_object().dict().unwrap(); + _dict + .set_item("value", value.ast_to_object(_vm), _vm) + .unwrap(); + _node.into() + } + ast::PatternKind::MatchSingleton { value } => { + let _node = AstNode + .into_ref_with_type(_vm, NodeMatchSingleton::static_type().to_owned()) + .unwrap(); + let _dict = _node.as_object().dict().unwrap(); + _dict + .set_item("value", value.ast_to_object(_vm), _vm) + .unwrap(); + _node.into() + } + ast::PatternKind::MatchSequence { patterns } => { + let _node = AstNode + .into_ref_with_type(_vm, NodeMatchSequence::static_type().to_owned()) + .unwrap(); + let _dict = _node.as_object().dict().unwrap(); + _dict + .set_item("patterns", patterns.ast_to_object(_vm), _vm) + .unwrap(); + _node.into() + } + ast::PatternKind::MatchMapping { + keys, + patterns, + rest, + } => { + let _node = AstNode + .into_ref_with_type(_vm, NodeMatchMapping::static_type().to_owned()) + .unwrap(); + let _dict = _node.as_object().dict().unwrap(); + _dict + .set_item("keys", keys.ast_to_object(_vm), _vm) + .unwrap(); + _dict + .set_item("patterns", patterns.ast_to_object(_vm), _vm) + .unwrap(); + _dict + .set_item("rest", rest.ast_to_object(_vm), _vm) + .unwrap(); + _node.into() + } + ast::PatternKind::MatchClass { + cls, + patterns, + kwd_attrs, + kwd_patterns, + } => { + let _node = AstNode + .into_ref_with_type(_vm, NodeMatchClass::static_type().to_owned()) + .unwrap(); + let _dict = _node.as_object().dict().unwrap(); + _dict.set_item("cls", cls.ast_to_object(_vm), _vm).unwrap(); + _dict + .set_item("patterns", patterns.ast_to_object(_vm), _vm) + .unwrap(); + _dict + .set_item("kwd_attrs", kwd_attrs.ast_to_object(_vm), _vm) + .unwrap(); + _dict + .set_item("kwd_patterns", kwd_patterns.ast_to_object(_vm), _vm) + .unwrap(); + _node.into() + } + ast::PatternKind::MatchStar { name } => { + let _node = AstNode + .into_ref_with_type(_vm, NodeMatchStar::static_type().to_owned()) + .unwrap(); + let _dict = _node.as_object().dict().unwrap(); + _dict + .set_item("name", name.ast_to_object(_vm), _vm) + .unwrap(); + _node.into() + } + ast::PatternKind::MatchAs { pattern, name } => { + let _node = AstNode + .into_ref_with_type(_vm, NodeMatchAs::static_type().to_owned()) + .unwrap(); + let _dict = _node.as_object().dict().unwrap(); + _dict + .set_item("pattern", pattern.ast_to_object(_vm), _vm) + .unwrap(); + _dict + .set_item("name", name.ast_to_object(_vm), _vm) + .unwrap(); + _node.into() + } + ast::PatternKind::MatchOr { patterns } => { + let _node = AstNode + .into_ref_with_type(_vm, NodeMatchOr::static_type().to_owned()) + .unwrap(); + let _dict = _node.as_object().dict().unwrap(); + _dict + .set_item("patterns", patterns.ast_to_object(_vm), _vm) + .unwrap(); + _node.into() + } + } + } + fn ast_from_object(_vm: &VirtualMachine, _object: PyObjectRef) -> PyResult { + let _location = ast::Location::new( + Node::ast_from_object(_vm, get_node_field(_vm, &_object, "lineno", "pattern")?)?, + Node::ast_from_object(_vm, get_node_field(_vm, &_object, "col_offset", "pattern")?)?, + ); + let _cls = _object.class(); + Ok(if _cls.is(NodeMatchValue::static_type()) { + ast::PatternKind::MatchValue { + value: Node::ast_from_object( + _vm, + get_node_field(_vm, &_object, "value", "pattern")?, + )?, + } + } else if _cls.is(NodeMatchSingleton::static_type()) { + ast::PatternKind::MatchSingleton { + value: Node::ast_from_object( + _vm, + get_node_field(_vm, &_object, "value", "pattern")?, + )?, + } + } else if _cls.is(NodeMatchSequence::static_type()) { + ast::PatternKind::MatchSequence { + patterns: Node::ast_from_object( + _vm, + get_node_field(_vm, &_object, "patterns", "pattern")?, + )?, + } + } else if _cls.is(NodeMatchMapping::static_type()) { + ast::PatternKind::MatchMapping { + keys: Node::ast_from_object( + _vm, + get_node_field(_vm, &_object, "keys", "pattern")?, + )?, + patterns: Node::ast_from_object( + _vm, + get_node_field(_vm, &_object, "patterns", "pattern")?, + )?, + rest: get_node_field_opt(_vm, &_object, "rest")? + .map(|obj| Node::ast_from_object(_vm, obj)) + .transpose()?, + } + } else if _cls.is(NodeMatchClass::static_type()) { + ast::PatternKind::MatchClass { + cls: Node::ast_from_object(_vm, get_node_field(_vm, &_object, "cls", "pattern")?)?, + patterns: Node::ast_from_object( + _vm, + get_node_field(_vm, &_object, "patterns", "pattern")?, + )?, + kwd_attrs: Node::ast_from_object( + _vm, + get_node_field(_vm, &_object, "kwd_attrs", "pattern")?, + )?, + kwd_patterns: Node::ast_from_object( + _vm, + get_node_field(_vm, &_object, "kwd_patterns", "pattern")?, + )?, + } + } else if _cls.is(NodeMatchStar::static_type()) { + ast::PatternKind::MatchStar { + name: get_node_field_opt(_vm, &_object, "name")? + .map(|obj| Node::ast_from_object(_vm, obj)) + .transpose()?, + } + } else if _cls.is(NodeMatchAs::static_type()) { + ast::PatternKind::MatchAs { + pattern: get_node_field_opt(_vm, &_object, "pattern")? + .map(|obj| Node::ast_from_object(_vm, obj)) + .transpose()?, + name: get_node_field_opt(_vm, &_object, "name")? + .map(|obj| Node::ast_from_object(_vm, obj)) + .transpose()?, + } + } else if _cls.is(NodeMatchOr::static_type()) { + ast::PatternKind::MatchOr { + patterns: Node::ast_from_object( + _vm, + get_node_field(_vm, &_object, "patterns", "pattern")?, + )?, + } + } else { + return Err(_vm.new_type_error(format!( + "expected some sort of pattern, but got {}", + _object.repr(_vm)? + ))); + }) + } +} impl NamedNode for ast::TypeIgnore { const NAME: &'static str = "type_ignore"; } @@ -3970,6 +4489,7 @@ pub fn extend_module_nodes(vm: &VirtualMachine, module: &PyObject) { "If" => NodeIf::make_class(&vm.ctx), "With" => NodeWith::make_class(&vm.ctx), "AsyncWith" => NodeAsyncWith::make_class(&vm.ctx), + "Match" => NodeMatch::make_class(&vm.ctx), "Raise" => NodeRaise::make_class(&vm.ctx), "Try" => NodeTry::make_class(&vm.ctx), "Assert" => NodeAssert::make_class(&vm.ctx), @@ -4046,14 +4566,24 @@ pub fn extend_module_nodes(vm: &VirtualMachine, module: &PyObject) { "IsNot" => NodeIsNot::make_class(&vm.ctx), "In" => NodeIn::make_class(&vm.ctx), "NotIn" => NodeNotIn::make_class(&vm.ctx), - "comprehension" => Nodecomprehension::make_class(&vm.ctx), + "comprehension" => NodeComprehension::make_class(&vm.ctx), "excepthandler" => NodeKindExcepthandler::make_class(&vm.ctx), "ExceptHandler" => NodeExceptHandler::make_class(&vm.ctx), - "arguments" => Nodearguments::make_class(&vm.ctx), - "arg" => Nodearg::make_class(&vm.ctx), - "keyword" => Nodekeyword::make_class(&vm.ctx), - "alias" => Nodealias::make_class(&vm.ctx), - "withitem" => Nodewithitem::make_class(&vm.ctx), + "arguments" => NodeArguments::make_class(&vm.ctx), + "arg" => NodeArg::make_class(&vm.ctx), + "keyword" => NodeKeyword::make_class(&vm.ctx), + "alias" => NodeAlias::make_class(&vm.ctx), + "withitem" => NodeWithitem::make_class(&vm.ctx), + "match_case" => NodeMatchCase::make_class(&vm.ctx), + "pattern" => NodeKindPattern::make_class(&vm.ctx), + "MatchValue" => NodeMatchValue::make_class(&vm.ctx), + "MatchSingleton" => NodeMatchSingleton::make_class(&vm.ctx), + "MatchSequence" => NodeMatchSequence::make_class(&vm.ctx), + "MatchMapping" => NodeMatchMapping::make_class(&vm.ctx), + "MatchClass" => NodeMatchClass::make_class(&vm.ctx), + "MatchStar" => NodeMatchStar::make_class(&vm.ctx), + "MatchAs" => NodeMatchAs::make_class(&vm.ctx), + "MatchOr" => NodeMatchOr::make_class(&vm.ctx), "type_ignore" => NodeKindTypeIgnore::make_class(&vm.ctx), "TypeIgnore" => NodeTypeIgnore::make_class(&vm.ctx), }) From 53b344866f0bd699a03ca6087e898372ec6e77fa Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 12 Aug 2022 05:24:19 +0900 Subject: [PATCH 08/11] Implement new features for updated python asdl --- Cargo.lock | 1 + ast/Cargo.toml | 1 + ast/src/constant.rs | 30 +------- ast/src/fold_helpers.rs | 8 +- ast/src/unparse.rs | 19 ++--- bytecode/src/lib.rs | 23 +++++- compiler/src/compile.rs | 58 +++++++-------- compiler/src/error.rs | 4 + compiler/src/symboltable.rs | 30 +++++--- extra_tests/snippets/builtin_dict.py | 2 +- parser/python.lalrpop | 73 +++++++++++++++---- parser/src/fstring.rs | 8 +- ...s__fstring_parse_selfdocumenting_base.snap | 2 +- ...tring_parse_selfdocumenting_base_more.snap | 4 +- ..._fstring_parse_selfdocumenting_format.snap | 3 +- ...parser__fstring__tests__parse_fstring.snap | 4 +- ..._fstring__tests__parse_fstring_equals.snap | 3 +- ...ing__tests__parse_fstring_nested_spec.snap | 7 +- ...ring__tests__parse_fstring_not_equals.snap | 3 +- ..._tests__parse_fstring_not_nested_spec.snap | 3 +- ...sts__parse_fstring_selfdoc_prec_space.snap | 2 +- ..._parse_fstring_selfdoc_trailing_space.snap | 2 +- ...ring__tests__parse_fstring_yield_expr.snap | 3 +- ...rser__tests__parse_dict_comprehension.snap | 2 +- ...ests__parse_double_list_comprehension.snap | 5 +- ...rser__tests__parse_list_comprehension.snap | 2 +- vm/src/builtins/dict.rs | 24 +++--- vm/src/frame.rs | 8 +- vm/src/stdlib/ast.rs | 4 +- 29 files changed, 182 insertions(+), 156 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ab5d65c7e..06b09c3c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1723,6 +1723,7 @@ name = "rustpython-ast" version = "0.1.0" dependencies = [ "num-bigint", + "rustpython-bytecode", "rustpython-common", ] diff --git a/ast/Cargo.toml b/ast/Cargo.toml index 8d1db18a8..996a01d89 100644 --- a/ast/Cargo.toml +++ b/ast/Cargo.toml @@ -13,3 +13,4 @@ unparse = ["rustpython-common"] [dependencies] num-bigint = "0.4.3" rustpython-common = { path = "../common", optional = true } +rustpython-bytecode = { path = "../bytecode"} diff --git a/ast/src/constant.rs b/ast/src/constant.rs index 0778f4f06..1d1655943 100644 --- a/ast/src/constant.rs +++ b/ast/src/constant.rs @@ -1,4 +1,5 @@ use num_bigint::BigInt; +pub use rustpython_bytecode::ConversionFlag; #[derive(Debug, PartialEq)] pub enum Constant { @@ -70,35 +71,6 @@ impl std::fmt::Display for Constant { } } -/// Transforms a value prior to formatting it. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[repr(usize)] -pub enum ConversionFlag { - /// Converts by calling `str()`. - Str = b's' as usize, - /// Converts by calling `ascii()`. - Ascii = b'a' as usize, - /// Converts by calling `repr()`. - Repr = b'r' as usize, -} - -impl ConversionFlag { - pub fn try_from_u32(b: usize) -> Option { - match b.try_into().ok()? { - b's' => Some(Self::Str), - b'a' => Some(Self::Ascii), - b'r' => Some(Self::Repr), - _ => None, - } - } -} - -impl From for ConversionFlag { - fn from(b: usize) -> Self { - Self::try_from_u32(b).unwrap() - } -} - #[cfg(feature = "constant-optimization")] #[non_exhaustive] #[derive(Default)] diff --git a/ast/src/fold_helpers.rs b/ast/src/fold_helpers.rs index 26a08b2fb..f15a9d5d0 100644 --- a/ast/src/fold_helpers.rs +++ b/ast/src/fold_helpers.rs @@ -63,10 +63,4 @@ macro_rules! simple_fold { }; } -simple_fold!( - usize, - String, - bool, - constant::Constant, - constant::ConversionFlag -); +simple_fold!(usize, String, bool, constant::Constant); diff --git a/ast/src/unparse.rs b/ast/src/unparse.rs index f0370b73f..70addae99 100644 --- a/ast/src/unparse.rs +++ b/ast/src/unparse.rs @@ -155,6 +155,7 @@ impl<'a> Unparser<'a> { write!(self, "{}: {}", *k, *v)?; } for d in unpacked { + self.p_delim(&mut first, ", ")?; write!(self, "**{}", *d)?; } self.p("}")?; @@ -281,7 +282,7 @@ impl<'a> Unparser<'a> { value, conversion, format_spec, - } => self.unparse_formatted(value, (*conversion).into(), format_spec.as_deref())?, + } => self.unparse_formatted(value, *conversion, format_spec.as_deref())?, ExprKind::JoinedStr { values } => self.unparse_joinedstr(values, false)?, ExprKind::Constant { value, kind } => { if let Some(kind) = kind { @@ -445,7 +446,7 @@ impl<'a> Unparser<'a> { fn unparse_formatted( &mut self, val: &Expr, - conversion: ConversionFlag, + conversion: usize, spec: Option<&Expr>, ) -> fmt::Result { let buffered = to_string_fmt(|f| Unparser::new(f).unparse_expr(val, precedence::TEST + 1)); @@ -459,12 +460,12 @@ impl<'a> Unparser<'a> { self.p(&buffered)?; drop(buffered); - let flag = match conversion { - ConversionFlag::Str => "!s", - ConversionFlag::Ascii => "!a", - ConversionFlag::Repr => "!r", - }; - self.p(flag)?; + if conversion != ConversionFlag::None as usize { + self.p("!")?; + let buf = &[conversion as u8]; + let c = std::str::from_utf8(buf).unwrap(); + self.p(c)?; + } if let Some(spec) = spec { self.p(":")?; @@ -490,7 +491,7 @@ impl<'a> Unparser<'a> { value, conversion, format_spec, - } => self.unparse_formatted(value, (*conversion).into(), format_spec.as_deref()), + } => self.unparse_formatted(value, *conversion, format_spec.as_deref()), _ => unreachable!(), } } diff --git a/bytecode/src/lib.rs b/bytecode/src/lib.rs index 832ad8473..ea490c59a 100644 --- a/bytecode/src/lib.rs +++ b/bytecode/src/lib.rs @@ -159,15 +159,30 @@ impl fmt::Display for Label { /// Transforms a value prior to formatting it. #[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[repr(u8)] pub enum ConversionFlag { /// No conversion - None, + None = 0, /// Converts by calling `str()`. - Str, + Str = b's', /// Converts by calling `ascii()`. - Ascii, + Ascii = b'a', /// Converts by calling `repr()`. - Repr, + Repr = b'r', +} + +impl TryFrom for ConversionFlag { + type Error = usize; + fn try_from(b: usize) -> Result { + let b = b.try_into().map_err(|_| b)?; + match b { + 0 => Ok(Self::None), + b's' => Ok(Self::Str), + b'a' => Ok(Self::Ascii), + b'r' => Ok(Self::Repr), + b => Err(b as usize), + } + } } /// The kind of Raise that occurred. diff --git a/compiler/src/compile.rs b/compiler/src/compile.rs index efb5e0873..6e5cbfc8a 100644 --- a/compiler/src/compile.rs +++ b/compiler/src/compile.rs @@ -680,6 +680,7 @@ impl Compiler { orelse, .. } => self.compile_for(target, iter, body, orelse, true)?, + Match { subject, cases } => self.compile_match(subject, cases)?, Raise { exc, cause } => { let kind = match exc { Some(value) => { @@ -881,17 +882,19 @@ impl Compiler { }); } - let mut num_kw_only_defaults = 0; - for (kw, default) in args.kwonlyargs.iter().zip(&args.kw_defaults) { - self.emit_constant(ConstantData::Str { - value: kw.node.arg.clone(), - }); - self.compile_expression(default)?; - num_kw_only_defaults += 1; - } - if num_kw_only_defaults > 0 { + if !args.kw_defaults.is_empty() { + let required_kw_count = args.kwonlyargs.len().saturating_sub(args.kw_defaults.len()); + for (kw, default) in args.kwonlyargs[required_kw_count..] + .iter() + .zip(&args.kw_defaults) + { + self.emit_constant(ConstantData::Str { + value: kw.node.arg.clone(), + }); + self.compile_expression(default)?; + } self.emit(Instruction::BuildMap { - size: num_kw_only_defaults, + size: args.kw_defaults.len() as u32, unpack: false, for_call: false, }); @@ -901,7 +904,7 @@ impl Compiler { if have_defaults { funcflags |= bytecode::MakeFunctionFlags::DEFAULTS; } - if num_kw_only_defaults > 0 { + if !args.kw_defaults.is_empty() { funcflags |= bytecode::MakeFunctionFlags::KW_ONLY_DEFAULTS; } @@ -1519,6 +1522,16 @@ impl Compiler { Ok(()) } + fn compile_match( + &mut self, + subject: &ast::Expr, + cases: &[ast::MatchCase], + ) -> CompileResult<()> { + eprintln!("match subject: {subject:?}"); + eprintln!("match cases: {cases:?}"); + Err(self.error(CompileErrorType::NotImplementedYet)) + } + fn compile_chained_comparison( &mut self, left: &ast::Expr, @@ -1928,11 +1941,7 @@ impl Compiler { Ok(()) } - fn compile_dict( - &mut self, - keys: &[ast::Expr], - values: &[ast::Expr], - ) -> CompileResult<()> { + fn compile_dict(&mut self, keys: &[ast::Expr], values: &[ast::Expr]) -> CompileResult<()> { let mut size = 0; let (packed_values, unpacked_values) = values.split_at(keys.len()); @@ -2099,7 +2108,7 @@ impl Compiler { }; self.compile_expression(value)?; self.emit(Instruction::FormatValue { - conversion: compile_conversion_flag(*conversion), + conversion: (*conversion).try_into().expect("invalid conversion flag"), }); } Name { id, .. } => self.load_name(id)?, @@ -2454,7 +2463,7 @@ impl Compiler { let mut loop_labels = vec![]; for generator in generators { - if generator.is_async { + if generator.is_async > 0 { unimplemented!("async for comprehensions"); } @@ -2543,7 +2552,7 @@ impl Compiler { return Err(self.error(CompileErrorType::InvalidFuturePlacement)); } for feature in features { - match &*feature.name { + match &*feature.node.name { // Python 3 features; we've already implemented them by default "nested_scopes" | "generators" | "division" | "absolute_import" | "with_statement" | "print_function" | "unicode_literals" => {} @@ -2667,17 +2676,6 @@ fn compile_location(location: &ast::Location) -> bytecode::Location { bytecode::Location::new(location.row(), location.column()) } -fn compile_conversion_flag( - conversion_flag: Option, -) -> bytecode::ConversionFlag { - match conversion_flag { - None => bytecode::ConversionFlag::None, - Some(ast::ConversionFlag::Ascii) => bytecode::ConversionFlag::Ascii, - Some(ast::ConversionFlag::Repr) => bytecode::ConversionFlag::Repr, - Some(ast::ConversionFlag::Str) => bytecode::ConversionFlag::Str, - } -} - fn compile_constant(value: &ast::Constant) -> ConstantData { match value { ast::Constant::None => ConstantData::None, diff --git a/compiler/src/error.rs b/compiler/src/error.rs index 1d2c1c2fc..2e125b01e 100644 --- a/compiler/src/error.rs +++ b/compiler/src/error.rs @@ -37,6 +37,7 @@ pub enum CompileErrorType { TooManyStarUnpack, EmptyWithItems, EmptyWithBody, + NotImplementedYet, // RustPython marker for unimplemented features } impl fmt::Display for CompileErrorType { @@ -78,6 +79,9 @@ impl fmt::Display for CompileErrorType { CompileErrorType::EmptyWithBody => { write!(f, "empty body on With") } + CompileErrorType::NotImplementedYet => { + write!(f, "RustPython does not implement this feature yet") + } } } } diff --git a/compiler/src/symboltable.rs b/compiler/src/symboltable.rs index 387656349..6dad4f23d 100644 --- a/compiler/src/symboltable.rs +++ b/compiler/src/symboltable.rs @@ -639,7 +639,7 @@ impl SymbolTableBuilder { if let ImportFrom { module, names, .. } = &statement.node { if module.as_deref() == Some("__future__") { for feature in names { - if feature.name == "annotations" { + if feature.node.name == "annotations" { self.future_annotations = true; } } @@ -739,13 +739,13 @@ impl SymbolTableBuilder { } Import { names } | ImportFrom { names, .. } => { for name in names { - if let Some(alias) = &name.asname { + if let Some(alias) = &name.node.asname { // `import mymodule as myalias` self.register_name(alias, SymbolUsage::Imported, location)?; } else { // `import module` self.register_name( - name.name.split('.').next().unwrap(), + name.node.name.split('.').next().unwrap(), SymbolUsage::Imported, location, )?; @@ -782,7 +782,7 @@ impl SymbolTableBuilder { } => { // https://github.com/python/cpython/blob/main/Python/symtable.c#L1233 match &target.node { - ast::ExprKind::Name { id, .. } if *simple => { + ast::ExprKind::Name { id, .. } if *simple > 0 => { self.register_name(id, SymbolUsage::AnnotationAssigned, location)?; } _ => { @@ -823,6 +823,15 @@ impl SymbolTableBuilder { self.scan_statements(orelse)?; self.scan_statements(finalbody)?; } + Match { + subject: _, + cases: _, + } => { + return Err(SymbolTableError { + error: "match expression is not implemented yet".to_owned(), + location: Location::default(), + }); + } Raise { exc, cause } => { if let Some(expression) = exc { self.scan_expression(expression, ExpressionContext::Load)?; @@ -875,12 +884,13 @@ impl SymbolTableBuilder { self.scan_expression(value, ExpressionContext::Load)?; } Dict { keys, values } => { - for (key, value) in keys.iter().zip(values) { - if let Some(key) = key { - self.scan_expression(key, context)?; - } else { - // dict unpacking marker - } + let (packed, unpacked) = values.split_at(keys.len()); + for (key, value) in keys.iter().zip(packed) { + self.scan_expression(key, context)?; + self.scan_expression(value, context)?; + } + for value in unpacked { + // dict unpacking marker self.scan_expression(value, context)?; } } diff --git a/extra_tests/snippets/builtin_dict.py b/extra_tests/snippets/builtin_dict.py index 19d9342f2..3ccea9723 100644 --- a/extra_tests/snippets/builtin_dict.py +++ b/extra_tests/snippets/builtin_dict.py @@ -285,7 +285,7 @@ y = {'b': 2, 'c': 2, 'd': 2} z = {'c': 3, 'd': 3, 'e': 3} w = {1: 1, **x, 2: 2, **y, 3: 3, **z, 4: 4} -assert w == {1: 1, 'a': 1, 'b': 2, 'c': 3, 2: 2, 'd': 3, 3: 3, 'e': 3, 4: 4} +assert w == {1: 1, 'a': 1, 'b': 2, 'c': 3, 2: 2, 'd': 3, 3: 3, 'e': 3, 4: 4} # not in cpython test suite assert str({True: True, 1.0: 1.0}) == str({True: 1.0}) diff --git a/parser/python.lalrpop b/parser/python.lalrpop index 3d2dd189e..f68096168 100644 --- a/parser/python.lalrpop +++ b/parser/python.lalrpop @@ -268,19 +268,19 @@ ImportDots: usize = { }; ImportAsNames: Vec = { - >> => i, - "(" >> ","? ")" => i, - "*" => { + >> => i, + "(" >> ","? ")" => i, + "*" => { // Star import all - vec![ast::Alias(ast::AliasData { name: "*".to_string(), asname: None })] + vec![ast::Alias::new(location, ast::AliasData { name: "*".to_string(), asname: None })] }, }; #[inline] ImportAsAlias: ast::Alias = { - => ast::Alias { name, asname: a.map(|a| a.1) }, -}; + => ast::Alias::new(location, ast::AliasData { name, asname: a.map(|a| a.1) }), +} // A name like abc or abc.def.ghi DottedName: String = { @@ -590,20 +590,26 @@ TypedParameter: ast::Arg = { // Use inline here to make sure the "," is not creating an ambiguity. // TODO: figure out another grammar that makes this inline no longer required. #[inline] -ParameterListStarArgs: (Option>, Vec, Vec>>, Option>) = { +ParameterListStarArgs: (Option>, Vec, Vec, Option>) = { "*" )*> )?> => { // Extract keyword arguments: - let mut kwonlyargs = vec![]; - let mut kw_defaults = vec![]; + let mut kwonlyargs = Vec::new(); + let mut kw_defaults = Vec::new(); + let mut kwargs = Vec::new(); for (name, value) in kw.into_iter().map(|x| x.1) { - kwonlyargs.push(name); - kw_defaults.push(value.map(Box::new)); + if let Some(value) = value { + kwonlyargs.push(name); + kw_defaults.push(value); + } else { + kwargs.push(name); + } } + kwargs.extend(kwonlyargs.into_iter()); let kwarg = kwarg.map(|n| n.1).flatten(); let va = va.map(Box::new); - (va, kwonlyargs, kw_defaults, kwarg) + (va, kwargs, kw_defaults, kwarg) } }; @@ -1039,7 +1045,42 @@ Atom: ast::Expr = { }.into()) }, "{" "}" => { - let (keys, values) = e.unwrap_or_default(); + let pairs = e.unwrap_or_default(); + + let (keys, values) = match pairs.iter().position(|(k,_)| k.is_none()) { + Some(unpack_idx) => { + let mut pairs = pairs; + let (keys, mut values): (_, Vec<_>) = pairs.drain(..unpack_idx).map(|(k, v)| (*k.unwrap(), v)).unzip(); + + fn build_map(items: &mut Vec<(ast::Expr, ast::Expr)>) -> ast::Expr { + let location = items[0].0.location; + let (keys, values) = items.drain(..).unzip(); + ast::Expr { + location, + custom: (), + node: ast::ExprKind::Dict { keys, values } + } + } + + let mut items = Vec::new(); + for (key, value) in pairs.into_iter() { + if let Some(key) = key { + items.push((*key, value)); + continue; + } + if !items.is_empty() { + values.push(build_map(&mut items)); + } + values.push(value); + } + if !items.is_empty() { + values.push(build_map(&mut items)); + } + (keys, values) + }, + None => pairs.into_iter().map(|(k, v)| (*k.unwrap(), v)).unzip() + }; + ast::Expr { location, custom: (), @@ -1079,8 +1120,8 @@ ListLiteralValues: Vec = { > ","? => e, }; -DictLiteralValues: (Vec>>, Vec) = { - > ","? => elements.into_iter().unzip(), +DictLiteralValues: Vec<(Option>, ast::Expr)> = { + > ","? => elements, }; DictEntry: (ast::Expr, ast::Expr) = { @@ -1151,7 +1192,7 @@ SingleForComprehension: ast::Comprehension = { target: Box::new(target), iter: Box::new(iter), ifs, - is_async + is_async: if is_async { 1 } else { 0 }, } } }; diff --git a/parser/src/fstring.rs b/parser/src/fstring.rs index 9ffc116de..157325aa3 100644 --- a/parser/src/fstring.rs +++ b/parser/src/fstring.rs @@ -30,7 +30,7 @@ impl<'a> FStringParser<'a> { let mut expression = String::new(); let mut spec = None; let mut delims = Vec::new(); - let mut conversion = ConversionFlag::Str; + let mut conversion = ConversionFlag::None; let mut pred_expression_text = String::new(); let mut trailing_seq = String::new(); @@ -115,7 +115,7 @@ impl<'a> FStringParser<'a> { ) .parse()?, ), - conversion: b's' as usize, + conversion: ConversionFlag::None as _, format_spec: None, }), ); @@ -187,7 +187,7 @@ impl<'a> FStringParser<'a> { parse_fstring_expr(&expression) .map_err(|e| InvalidExpression(Box::new(e.error)))?, ), - conversion: conversion as usize, + conversion: conversion as _, format_spec: spec, })] } else { @@ -205,7 +205,7 @@ impl<'a> FStringParser<'a> { parse_fstring_expr(&expression) .map_err(|e| InvalidExpression(Box::new(e.error)))?, ), - conversion: conversion as usize, + conversion: conversion as _, format_spec: spec, }), ] diff --git a/parser/src/snapshots/rustpython_parser__fstring__tests__fstring_parse_selfdocumenting_base.snap b/parser/src/snapshots/rustpython_parser__fstring__tests__fstring_parse_selfdocumenting_base.snap index 33156007c..dceb49d35 100644 --- a/parser/src/snapshots/rustpython_parser__fstring__tests__fstring_parse_selfdocumenting_base.snap +++ b/parser/src/snapshots/rustpython_parser__fstring__tests__fstring_parse_selfdocumenting_base.snap @@ -54,7 +54,7 @@ Located { ctx: Load, }, }, - conversion: None, + conversion: 0, format_spec: None, }, }, diff --git a/parser/src/snapshots/rustpython_parser__fstring__tests__fstring_parse_selfdocumenting_base_more.snap b/parser/src/snapshots/rustpython_parser__fstring__tests__fstring_parse_selfdocumenting_base_more.snap index 6cc933de4..2725dbf1d 100644 --- a/parser/src/snapshots/rustpython_parser__fstring__tests__fstring_parse_selfdocumenting_base_more.snap +++ b/parser/src/snapshots/rustpython_parser__fstring__tests__fstring_parse_selfdocumenting_base_more.snap @@ -67,7 +67,7 @@ Located { ctx: Load, }, }, - conversion: None, + conversion: 0, format_spec: None, }, }, @@ -128,7 +128,7 @@ Located { ctx: Load, }, }, - conversion: None, + conversion: 0, format_spec: None, }, }, diff --git a/parser/src/snapshots/rustpython_parser__fstring__tests__fstring_parse_selfdocumenting_format.snap b/parser/src/snapshots/rustpython_parser__fstring__tests__fstring_parse_selfdocumenting_format.snap index 9ba81d0fb..4ab56f070 100644 --- a/parser/src/snapshots/rustpython_parser__fstring__tests__fstring_parse_selfdocumenting_format.snap +++ b/parser/src/snapshots/rustpython_parser__fstring__tests__fstring_parse_selfdocumenting_format.snap @@ -1,7 +1,6 @@ --- source: parser/src/fstring.rs expression: parse_ast - --- Located { location: Location { @@ -55,7 +54,7 @@ Located { ctx: Load, }, }, - conversion: None, + conversion: 0, format_spec: Some( Located { location: Location { diff --git a/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring.snap b/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring.snap index 457853a5b..26af1d8e9 100644 --- a/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring.snap +++ b/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring.snap @@ -28,7 +28,7 @@ Located { ctx: Load, }, }, - conversion: None, + conversion: 0, format_spec: None, }, }, @@ -50,7 +50,7 @@ Located { ctx: Load, }, }, - conversion: None, + conversion: 0, format_spec: None, }, }, diff --git a/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_equals.snap b/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_equals.snap index 12176f12e..5a98ebdf0 100644 --- a/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_equals.snap +++ b/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_equals.snap @@ -1,7 +1,6 @@ --- source: parser/src/fstring.rs expression: parse_ast - --- Located { location: Location { @@ -58,7 +57,7 @@ Located { ], }, }, - conversion: None, + conversion: 0, format_spec: None, }, }, diff --git a/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_nested_spec.snap b/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_nested_spec.snap index 6bcd55732..8ba0b5661 100644 --- a/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_nested_spec.snap +++ b/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_nested_spec.snap @@ -1,7 +1,6 @@ --- source: parser/src/fstring.rs expression: parse_ast - --- Located { location: Location { @@ -29,7 +28,7 @@ Located { ctx: Load, }, }, - conversion: None, + conversion: 0, format_spec: Some( Located { location: Location { @@ -85,14 +84,14 @@ Located { ctx: Load, }, }, - conversion: None, + conversion: 0, format_spec: None, }, }, ], }, }, - conversion: None, + conversion: 0, format_spec: None, }, }, diff --git a/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_not_equals.snap b/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_not_equals.snap index 2cb6e1e2d..655bf1b32 100644 --- a/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_not_equals.snap +++ b/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_not_equals.snap @@ -1,7 +1,6 @@ --- source: parser/src/fstring.rs expression: parse_ast - --- Located { location: Location { @@ -58,7 +57,7 @@ Located { ], }, }, - conversion: None, + conversion: 0, format_spec: None, }, }, diff --git a/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_not_nested_spec.snap b/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_not_nested_spec.snap index 682465de8..8950ebbea 100644 --- a/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_not_nested_spec.snap +++ b/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_not_nested_spec.snap @@ -1,7 +1,6 @@ --- source: parser/src/fstring.rs expression: parse_ast - --- Located { location: Location { @@ -29,7 +28,7 @@ Located { ctx: Load, }, }, - conversion: None, + conversion: 0, format_spec: Some( Located { location: Location { diff --git a/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_selfdoc_prec_space.snap b/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_selfdoc_prec_space.snap index 4b9b44582..73eaf6e0d 100644 --- a/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_selfdoc_prec_space.snap +++ b/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_selfdoc_prec_space.snap @@ -54,7 +54,7 @@ Located { ctx: Load, }, }, - conversion: None, + conversion: 0, format_spec: None, }, }, diff --git a/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_selfdoc_trailing_space.snap b/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_selfdoc_trailing_space.snap index 09c0f32d2..e6ac5c13d 100644 --- a/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_selfdoc_trailing_space.snap +++ b/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_selfdoc_trailing_space.snap @@ -54,7 +54,7 @@ Located { ctx: Load, }, }, - conversion: None, + conversion: 0, format_spec: None, }, }, diff --git a/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_yield_expr.snap b/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_yield_expr.snap index 8c16ec3b5..37e0d05a1 100644 --- a/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_yield_expr.snap +++ b/parser/src/snapshots/rustpython_parser__fstring__tests__parse_fstring_yield_expr.snap @@ -1,7 +1,6 @@ --- source: parser/src/fstring.rs expression: parse_ast - --- Located { location: Location { @@ -28,7 +27,7 @@ Located { value: None, }, }, - conversion: None, + conversion: 0, format_spec: None, }, }, diff --git a/parser/src/snapshots/rustpython_parser__parser__tests__parse_dict_comprehension.snap b/parser/src/snapshots/rustpython_parser__parser__tests__parse_dict_comprehension.snap index 65369dc31..f7f9b52d2 100644 --- a/parser/src/snapshots/rustpython_parser__parser__tests__parse_dict_comprehension.snap +++ b/parser/src/snapshots/rustpython_parser__parser__tests__parse_dict_comprehension.snap @@ -56,7 +56,7 @@ Located { }, }, ifs: [], - is_async: false, + is_async: 0, }, ], }, diff --git a/parser/src/snapshots/rustpython_parser__parser__tests__parse_double_list_comprehension.snap b/parser/src/snapshots/rustpython_parser__parser__tests__parse_double_list_comprehension.snap index 4095f6488..52d4b6cef 100644 --- a/parser/src/snapshots/rustpython_parser__parser__tests__parse_double_list_comprehension.snap +++ b/parser/src/snapshots/rustpython_parser__parser__tests__parse_double_list_comprehension.snap @@ -1,7 +1,6 @@ --- source: parser/src/parser.rs expression: parse_ast - --- Located { location: Location { @@ -69,7 +68,7 @@ Located { }, }, ifs: [], - is_async: false, + is_async: 0, }, Comprehension { target: Located { @@ -172,7 +171,7 @@ Located { }, }, ], - is_async: false, + is_async: 0, }, ], }, diff --git a/parser/src/snapshots/rustpython_parser__parser__tests__parse_list_comprehension.snap b/parser/src/snapshots/rustpython_parser__parser__tests__parse_list_comprehension.snap index d67e166da..8a6d8eb8d 100644 --- a/parser/src/snapshots/rustpython_parser__parser__tests__parse_list_comprehension.snap +++ b/parser/src/snapshots/rustpython_parser__parser__tests__parse_list_comprehension.snap @@ -45,7 +45,7 @@ Located { }, }, ifs: [], - is_async: false, + is_async: 0, }, ], }, diff --git a/vm/src/builtins/dict.rs b/vm/src/builtins/dict.rs index 9d7f2f282..ca7348184 100644 --- a/vm/src/builtins/dict.rs +++ b/vm/src/builtins/dict.rs @@ -71,15 +71,12 @@ impl PyDict { } // Used in update and ior. - fn merge_object( - dict: &DictContentType, - other: PyObjectRef, - vm: &VirtualMachine, - ) -> PyResult<()> { + pub(crate) fn merge_object(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<()> { let other = match other.downcast_exact(vm) { - Ok(dict_other) => return Self::merge_dict(dict, dict_other, vm), + Ok(dict_other) => return self.merge_dict(dict_other, vm), Err(other) => other, }; + let dict = &self.entries; if let Some(keys) = vm.get_method(other.clone(), vm.ctx.intern_str("keys")) { let keys = vm.invoke(&keys?, ())?.get_iter(vm)?; while let PyIterReturn::Return(key) = keys.next(vm)? { @@ -108,11 +105,8 @@ impl PyDict { Ok(()) } - fn merge_dict( - dict: &DictContentType, - dict_other: PyDictRef, - vm: &VirtualMachine, - ) -> PyResult<()> { + fn merge_dict(&self, dict_other: PyDictRef, vm: &VirtualMachine) -> PyResult<()> { + let dict = &self.entries; let dict_size = &dict_other.size(); for (key, value) in &dict_other { dict.insert(vm, &*key, value)?; @@ -363,7 +357,7 @@ impl PyDict { vm: &VirtualMachine, ) -> PyResult<()> { if let OptionalArg::Present(dict_obj) = dict_obj { - Self::merge_object(&self.entries, dict_obj, vm)?; + self.merge_object(dict_obj, vm)?; } for (key, value) in kwargs.into_iter() { self.entries.insert(vm, &key, value)?; @@ -373,7 +367,7 @@ impl PyDict { #[pymethod(magic)] fn ior(zelf: PyRef, other: PyObjectRef, vm: &VirtualMachine) -> PyResult> { - PyDict::merge_object(&zelf.entries, other, vm)?; + zelf.merge_object(other, vm)?; Ok(zelf) } @@ -382,7 +376,7 @@ impl PyDict { let dicted: Result = other.downcast(); if let Ok(other) = dicted { let other_cp = other.copy(); - PyDict::merge_dict(&other_cp.entries, zelf, vm)?; + other_cp.merge_dict(zelf, vm)?; return Ok(other_cp.into_pyobject(vm)); } Ok(vm.ctx.not_implemented()) @@ -393,7 +387,7 @@ impl PyDict { let dicted: Result = other.downcast(); if let Ok(other) = dicted { let self_cp = self.copy(); - PyDict::merge_dict(&self_cp.entries, other, vm)?; + self_cp.merge_dict(other, vm)?; return Ok(self_cp.into_pyobject(vm)); } Ok(vm.ctx.not_implemented()) diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 4b60b296d..4dc391e15 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -679,9 +679,11 @@ impl ExecutingFrame<'_> { } => self.execute_build_map(vm, *size, *unpack, *for_call), bytecode::Instruction::DictUpdate => { let other = self.pop_value(); - let dict = self.pop_value(); - let updated = vm.call_method(&dict, "update", (other,))?; - self.push_value(updated); + let dict = self + .last_value_ref() + .downcast_ref::() + .expect("exact dict expected"); + dict.merge_object(other, vm)?; Ok(None) } bytecode::Instruction::BuildSlice { step } => self.execute_build_slice(vm, *step), diff --git a/vm/src/stdlib/ast.rs b/vm/src/stdlib/ast.rs index 7d080c7fe..2c8c05baf 100644 --- a/vm/src/stdlib/ast.rs +++ b/vm/src/stdlib/ast.rs @@ -252,8 +252,8 @@ impl Node for ast::ConversionFlag { fn ast_from_object(vm: &VirtualMachine, object: PyObjectRef) -> PyResult { i32::try_from_object(vm, object)? - .to_u8() - .and_then(ast::ConversionFlag::try_from_byte) + .to_usize() + .and_then(|f| f.try_into().ok()) .ok_or_else(|| vm.new_value_error("invalid conversion flag".to_owned())) } } From 4d0e3576bca516dbaa1aa2d4e3d1f92af0c43196 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 12 Aug 2022 06:42:07 +0900 Subject: [PATCH 09/11] Fix ast error types and messages --- vm/src/stdlib/ast.rs | 6 +++++- vm/src/stdlib/builtins.rs | 6 ++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/vm/src/stdlib/ast.rs b/vm/src/stdlib/ast.rs index 2c8c05baf..26c6d95f9 100644 --- a/vm/src/stdlib/ast.rs +++ b/vm/src/stdlib/ast.rs @@ -239,7 +239,11 @@ impl Node for ast::Constant { } builtins::singletons::PyNone => ast::Constant::None, builtins::slice::PyEllipsis => ast::Constant::Ellipsis, - _ => return Err(vm.new_type_error("unsupported type for constant".to_owned())), + obj => + return Err(vm.new_type_error(format!( + "invalid type in Constant: type '{}'", + obj.class().name() + ))), }); Ok(constant) } diff --git a/vm/src/stdlib/builtins.rs b/vm/src/stdlib/builtins.rs index 04739f724..f6154642c 100644 --- a/vm/src/stdlib/builtins.rs +++ b/vm/src/stdlib/builtins.rs @@ -109,6 +109,8 @@ mod builtins { dont_inherit: OptionalArg, #[pyarg(any, optional)] optimize: OptionalArg, + #[pyarg(any, optional)] + _feature_version: OptionalArg, } #[cfg(feature = "rustpython-compiler")] @@ -122,6 +124,10 @@ mod builtins { { use crate::{class::PyClassImpl, stdlib::ast}; + if args._feature_version.is_present() { + eprintln!("TODO: compile() got `_feature_version` but ignored"); + } + let mode_str = args.mode.as_str(); if args From 529d76ac1edf5cb0ac5917c94354e8871dedad66 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 12 Aug 2022 06:46:44 +0900 Subject: [PATCH 10/11] mark failing tests from test_ast.py --- Lib/test/test_ast.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py index 953618e3b..eafa62e25 100644 --- a/Lib/test/test_ast.py +++ b/Lib/test/test_ast.py @@ -341,6 +341,8 @@ class AST_Tests(unittest.TestCase): mod.body[0].module = " __future__ ".strip() compile(mod, "", "exec") + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_alias(self): im = ast.parse("from bar import y").body[0] self.assertEqual(len(im.names), 1) @@ -705,6 +707,8 @@ class AST_Tests(unittest.TestCase): attr_b = tree.body[0].decorator_list[0].value self.assertEqual(attr_b.end_col_offset, 4) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_ast_asdl_signature(self): self.assertEqual(ast.withitem.__doc__, "withitem(expr context_expr, expr? optional_vars)") self.assertEqual(ast.GtE.__doc__, "GtE") @@ -714,6 +718,8 @@ class AST_Tests(unittest.TestCase): expressions[0] = f"expr = {ast.expr.__subclasses__()[0].__doc__}" self.assertCountEqual(ast.expr.__doc__.split("\n"), expressions) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_parenthesized_with_feature_version(self): ast.parse('with (CtxManager() as example): ...', feature_version=(3, 10)) # While advertised as a feature in Python 3.10, this was allowed starting 3.9 @@ -729,6 +735,8 @@ class AST_Tests(unittest.TestCase): with self.assertRaises(SyntaxError): ast.parse('f"{x=}"', feature_version=(3, 7)) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_assignment_expression_feature_version(self): ast.parse('(x := 0)', feature_version=(3, 8)) with self.assertRaises(SyntaxError): @@ -785,6 +793,8 @@ class ASTHelpers_Test(unittest.TestCase): "lineno=1, col_offset=0, end_lineno=1, end_col_offset=24)], type_ignores=[])" ) + # TODO: RUSTPYTHON; redundant kind for Contant node + @unittest.expectedFailure def test_dump_indent(self): node = ast.parse('spam(eggs, "and cheese")') self.assertEqual(ast.dump(node, indent=3), """\ @@ -947,6 +957,8 @@ Module( self.assertEqual(d.pop('func').id, 'foo') self.assertEqual(d, {'keywords': [], 'args': []}) + # TODO: RUSTPYTHON; redundant kind for Contant node + @unittest.expectedFailure def test_iter_child_nodes(self): node = ast.parse("spam(23, 42, eggs='leek')", mode='eval') self.assertEqual(len(list(ast.iter_child_nodes(node.body))), 4) @@ -1089,6 +1101,8 @@ Module( malformed = ast.Dict(keys=[ast.Constant(1)], values=[ast.Constant(2), ast.Constant(3)]) self.assertRaises(ValueError, ast.literal_eval, malformed) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_literal_eval_trailing_ws(self): self.assertEqual(ast.literal_eval(" -1"), -1) self.assertEqual(ast.literal_eval("\t\t-1"), -1) @@ -1107,6 +1121,8 @@ Module( with self.assertRaisesRegex(ValueError, msg): ast.literal_eval(node) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_literal_eval_syntax_errors(self): with self.assertRaisesRegex(SyntaxError, "unexpected indent"): ast.literal_eval(r''' @@ -1127,8 +1143,6 @@ Module( compile(mod, 'test', 'exec') self.assertIn("invalid integer value: None", str(cm.exception)) - # TODO: RUSTPYTHON - @unittest.expectedFailure def test_level_as_none(self): body = [ast.ImportFrom(module='time', names=[ast.alias(name='sleep', @@ -1141,6 +1155,7 @@ Module( exec(code, ns) self.assertIn('sleep', ns) + @unittest.skip("TODO: RUSTPYTHON; crash") def test_recursion_direct(self): e = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0) e.operand = e @@ -1148,6 +1163,7 @@ Module( with support.infinite_recursion(): compile(ast.Expression(e), "", "eval") + @unittest.skip("TODO: RUSTPYTHON; crash") def test_recursion_indirect(self): e = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0) f = ast.UnaryOp(op=ast.Not(), lineno=0, col_offset=0) @@ -2295,6 +2311,8 @@ class EndPositionTests(unittest.TestCase): cdef = ast.parse(s).body[0] self.assertEqual(ast.get_source_segment(s, cdef.body[0], padded=True), s_method) + # TODO: RUSTPYTHON + @unittest.expectedFailure def test_source_segment_missing_info(self): s = 'v = 1\r\nw = 1\nx = 1\n\ry = 1\r\n' v, w, x, y = ast.parse(s).body From 9c31b365814a1fa79f86030e0271848b29b93213 Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Fri, 19 Aug 2022 04:52:14 +0900 Subject: [PATCH 11/11] minor style fix --- parser/src/error.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/parser/src/error.rs b/parser/src/error.rs index a0785e894..cc53ef2ff 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -160,11 +160,7 @@ impl From> for ParseError { LalrpopError::UnrecognizedToken { token, expected } => { // Hacky, but it's how CPython does it. See PyParser_AddToken, // in particular "Only one possible expected token" comment. - let expected = if expected.len() == 1 { - Some(expected[0].clone()) - } else { - None - }; + let expected = (expected.len() == 1).then(|| expected[0].clone()); ParseError { error: ParseErrorType::UnrecognizedToken(token.1, expected), location: token.0,