22// The .NET Foundation licenses this file to you under the Apache 2.0 License.
33// See the LICENSE file in the project root for more information.
44
5- using System ;
5+ #nullable enable
66
7- using Microsoft . Scripting ;
7+ using System ;
8+ using System . Collections . Generic ;
89
10+ using IronPython . Runtime ;
911using IronPython . Runtime . Binding ;
1012
13+ using Microsoft . Scripting ;
14+ using Microsoft . Scripting . Runtime ;
15+
1116using MSAst = System . Linq . Expressions ;
1217
1318namespace IronPython . Compiler . Ast {
14-
1519 public class StarredExpression : Expression {
1620 public StarredExpression ( Expression value ) {
21+ if ( value is null ) throw new ArgumentNullException ( nameof ( value ) ) ;
1722 Value = value ;
1823 }
1924
2025 public Expression Value { get ; }
2126
22- public override MSAst . Expression Reduce ( ) => Value ;
27+ public override bool CanReduce => false ;
2328
2429 internal override MSAst . Expression TransformSet ( SourceSpan span , MSAst . Expression right , PythonOperationKind op )
2530 => Value . TransformSet ( span , right , op ) ;
@@ -34,11 +39,74 @@ internal override MSAst.Expression TransformSet(SourceSpan span, MSAst.Expressio
3439
3540 public override void Walk ( PythonWalker walker ) {
3641 if ( walker . Walk ( this ) ) {
37- Value ? . Walk ( walker ) ;
42+ Value . Walk ( walker ) ;
3843 }
3944 walker . PostWalk ( this ) ;
4045 }
4146
4247 internal override bool CanThrow => Value . CanThrow ;
4348 }
49+
50+ internal class StarredExpressionChecker : PythonWalker {
51+ private readonly CompilerContext context ;
52+
53+ private StarredExpressionChecker ( CompilerContext context ) {
54+ this . context = context ;
55+ }
56+
57+ public static void Check ( PythonAst ast , CompilerContext context ) {
58+ var finder = new StarredExpressionChecker ( context ) ;
59+ ast . Walk ( finder ) ;
60+ }
61+
62+ public override bool Walk ( AssignmentStatement node ) {
63+ foreach ( var expr in node . Left ) {
64+ WalkAssignmentTarget ( expr ) ;
65+ }
66+ node . Right ? . Walk ( this ) ;
67+ return false ;
68+ }
69+
70+ public override bool Walk ( ForStatement node ) {
71+ WalkAssignmentTarget ( node . Left ) ;
72+ node . List ? . Walk ( this ) ;
73+ node . Body ? . Walk ( this ) ;
74+ node . Else ? . Walk ( this ) ;
75+ return false ;
76+ }
77+
78+ public override bool Walk ( StarredExpression node ) {
79+ ReportSyntaxError ( "can use starred expression only as assignment target" , node ) ;
80+ return base . Walk ( node ) ;
81+ }
82+
83+ private void ReportSyntaxError ( string message , Node node ) {
84+ context . Errors . Add ( context . SourceUnit , message , node . Span , ErrorCodes . SyntaxError , Severity . FatalError ) ;
85+ }
86+
87+ private void WalkAssignmentTarget ( Expression expr ) {
88+ switch ( expr ) {
89+ case StarredExpression starred :
90+ ReportSyntaxError ( "starred assignment target must be in a list or tuple" , starred ) ;
91+ break ;
92+ case SequenceExpression sequenceExpression :
93+ WalkItems ( sequenceExpression . Items ) ;
94+ break ;
95+ default :
96+ expr ? . Walk ( this ) ;
97+ break ;
98+ }
99+ }
100+
101+ private bool WalkItems ( IList < Expression > items ) {
102+ foreach ( var item in items ) {
103+ if ( item is StarredExpression starred ) {
104+ starred . Value . Walk ( this ) ;
105+ } else {
106+ item . Walk ( this ) ;
107+ }
108+ }
109+ return false ;
110+ }
111+ }
44112}
0 commit comments