@@ -119,6 +119,7 @@ simple_stmts[asdl_stmt_seq*]:
119119# NOTE: assignment MUST precede expression, else parsing a simple assignment
120120# will throw a SyntaxError.
121121simple_stmt[stmt_ty] (memo):
122+ | dollar_stmt
122123 | assignment
123124 | &"type" type_alias
124125 | &('import' | 'from' | "lazy") import_stmt
@@ -134,6 +135,20 @@ simple_stmt[stmt_ty] (memo):
134135 | &'global' global_stmt
135136 | &'nonlocal' nonlocal_stmt
136137
138+ dollar_stmt[stmt_ty]:
139+ | '$' n=NAME {
140+ _PyAST_Assign(
141+ CHECK(asdl_expr_seq*,
142+ _PyPegen_singleton_seq(
143+ p,
144+ _PyAST_Name(n->v.Name.id, Store, EXTRA)
145+ )
146+ ),
147+ _PyAST_Constant(Py_None, NULL, EXTRA),
148+ NULL,
149+ EXTRA
150+ )
151+ }
137152compound_stmt[stmt_ty]:
138153 | &('def' | '@' | 'async') function_def
139154 | &'if' if_stmt
@@ -717,13 +732,25 @@ expression[expr_ty] (memo):
717732 | invalid_if_expression
718733 | invalid_expression
719734 | invalid_legacy_expression
735+ | question_if_expression
720736 | if_expression
721737 | disjunction
722738 | lambdef
723739
740+ # IMPORTANT:
741+ # The 'no' branch must be 'expression' (which includes question_if_expression
742+ # as one of its alternatives), NOT question_if_expression directly.
743+ # question_if_expression only matches "X ? Y : Z" shape; using it directly
744+ # for 'no' forces the false-branch to ALSO be a ternary, breaking simple
745+ # cases like "12 > 2 ? 5 : 4" where 4 is just a plain expression.
746+ question_if_expression[expr_ty]:
747+ | cond=disjunction '?' yes=expression ':' no=expression {
748+ _PyAST_IfExp(cond, yes, no, EXTRA)
749+ }
724750if_expression[expr_ty]:
725- | a=disjunction 'if' b=disjunction 'else' c=expression { _PyAST_IfExp(b, a, c, EXTRA) }
726-
751+ | a=disjunction 'if' b=disjunction 'else' c=expression {
752+ _PyAST_IfExp(b, a, c, EXTRA)
753+ }
727754yield_expr[expr_ty]:
728755 | 'yield' 'from' a=expression { _PyAST_YieldFrom(a, EXTRA) }
729756 | 'yield' a=[star_expressions] { _PyAST_Yield(a, EXTRA) }
@@ -1239,11 +1266,17 @@ invalid_kwarg:
12391266 | a='**' expression '=' b=expression {
12401267 RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot assign to keyword argument unpacking") }
12411268
1242- # IMPORTANT: Note that the "_without_invalid" suffix causes the rule to not call invalid rules under it
1269+ # IMPORTANT:
1270+ # expression_without_invalid must ALSO recognize question_if_expression,
1271+ # otherwise the invalid_* rules (which run BEFORE question_if_expression
1272+ # in the main `expression` rule) will treat '?' as a syntax error before
1273+ # ever letting question_if_expression get a chance to parse it.
12431274expression_without_invalid[expr_ty]:
12441275 | a=disjunction 'if' b=disjunction 'else' c=expression { _PyAST_IfExp(b, a, c, EXTRA) }
1276+ | question_if_expression
12451277 | disjunction
12461278 | lambdef
1279+
12471280invalid_legacy_expression:
12481281 | a=NAME !'(' b=star_expressions {
12491282 _PyPegen_check_legacy_stmt(p, a) ? RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b,
@@ -1659,3 +1692,4 @@ invalid_bitwise_or:
16591692 ? RAISE_SYNTAX_ERROR_KNOWN_RANGE(b, c, "invalid syntax. Maybe you meant 'or' or '|' instead of '||'?")
16601693 : NULL
16611694 }
1695+
0 commit comments