bpo-40618: Disallow invalid targets in augassign and except clauses (GH-20083)

This commit fixes the new parser to disallow invalid targets in the
following scenarios:
- Augmented assignments must only accept a single target (Name,
  Attribute or Subscript), but no tuples or lists.
- `except` clauses should only accept a single `Name` as a target.

Co-authored-by: Pablo Galindo <Pablogsal@gmail.com>
diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py
index 02ba8a8..e1a402e 100644
--- a/Lib/test/test_grammar.py
+++ b/Lib/test/test_grammar.py
@@ -1279,7 +1279,7 @@
     def test_try(self):
         ### try_stmt: 'try' ':' suite (except_clause ':' suite)+ ['else' ':' suite]
         ###         | 'try' ':' suite 'finally' ':' suite
-        ### except_clause: 'except' [expr ['as' expr]]
+        ### except_clause: 'except' [expr ['as' NAME]]
         try:
             1/0
         except ZeroDivisionError:
@@ -1297,6 +1297,9 @@
         except (EOFError, TypeError, ZeroDivisionError) as msg: pass
         try: pass
         finally: pass
+        with self.assertRaises(SyntaxError):
+            compile("try:\n    pass\nexcept Exception as a.b:\n    pass", "?", "exec")
+            compile("try:\n    pass\nexcept Exception as a[b]:\n    pass", "?", "exec")
 
     def test_suite(self):
         # simple_stmt | NEWLINE INDENT NEWLINE* (stmt NEWLINE*)+ DEDENT
diff --git a/Lib/test/test_peg_parser.py b/Lib/test/test_peg_parser.py
index df2d46d..71e0719 100644
--- a/Lib/test/test_peg_parser.py
+++ b/Lib/test/test_peg_parser.py
@@ -35,6 +35,9 @@
     ('attribute_simple', 'a.b'),
     ('attributes_subscript', 'a.b[0]'),
     ('augmented_assignment', 'x += 42'),
+    ('augmented_assignment_attribute', 'a.b.c += 42'),
+    ('augmented_assignment_paren', '(x) += 42'),
+    ('augmented_assignment_paren_subscript', '(x[0]) -= 42'),
     ('binop_add', '1 + 1'),
     ('binop_add_multiple', '1 + 1 + 1 + 1'),
     ('binop_all', '1 + 2 * 5 + 3 ** 2 - -3'),
@@ -547,6 +550,11 @@
         with a as (x, y):
             pass
      '''),
+    ('with_list_target',
+     '''
+        with a as [x, y]:
+            pass
+     '''),
     ('yield', 'yield'),
     ('yield_expr', 'yield a'),
     ('yield_from', 'yield from a'),
@@ -560,6 +568,9 @@
     ("annotation_tuple", "(a,): int"),
     ("annotation_tuple_without_paren", "a,: int"),
     ("assignment_keyword", "a = if"),
+    ("augmented_assignment_list", "[a, b] += 1"),
+    ("augmented_assignment_tuple", "a, b += 1"),
+    ("augmented_assignment_tuple_paren", "(a, b) += (1, 2)"),
     ("comprehension_lambda", "(a for a in lambda: b)"),
     ("comprehension_else", "(a for a in b if c else d"),
     ("del_call", "del a()"),
@@ -589,6 +600,20 @@
              a
      """),
     ("not_terminated_string", "a = 'example"),
+    ("try_except_attribute_target",
+     """
+     try:
+         pass
+     except Exception as a.b:
+         pass
+     """),
+    ("try_except_subscript_target",
+     """
+     try:
+         pass
+     except Exception as a[0]:
+         pass
+     """),
 ]
 
 FAIL_SPECIALIZED_MESSAGE_CASES = [
diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py
index 06636ae..a3a1015 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -129,6 +129,18 @@
 Traceback (most recent call last):
 SyntaxError: cannot assign to conditional expression
 
+>>> a, b += 1, 2
+Traceback (most recent call last):
+SyntaxError: invalid syntax
+
+>>> (a, b) += 1, 2
+Traceback (most recent call last):
+SyntaxError: cannot assign to tuple
+
+>>> [a, b] += 1, 2
+Traceback (most recent call last):
+SyntaxError: cannot assign to list
+
 From compiler_complex_args():
 
 >>> def f(None=1):