Skip to content

Commit 8a59f15

Browse files
authored
Annotated assignment syntax (#1432)
* Annotated assignment syntax * Update generator script * Rename to AnnotatedAssignStatement
1 parent 176a6c9 commit 8a59f15

6 files changed

Lines changed: 123 additions & 4 deletions

File tree

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the Apache 2.0 License.
3+
// See the LICENSE file in the project root for more information.
4+
5+
#nullable enable
6+
7+
using IronPython.Runtime.Binding;
8+
9+
using MSAst = System.Linq.Expressions;
10+
11+
namespace IronPython.Compiler.Ast {
12+
13+
public class AnnotatedAssignStatement : Statement {
14+
public AnnotatedAssignStatement(Expression target, Expression annotation, Expression? value, bool simple) {
15+
Target = target;
16+
Annotation = annotation;
17+
Value = value;
18+
Simple = simple;
19+
}
20+
21+
public Expression Target { get; }
22+
23+
public Expression Annotation { get; }
24+
25+
public Expression? Value { get; }
26+
27+
public bool Simple { get; }
28+
29+
public override MSAst.Expression Reduce() {
30+
if (Value is null) {
31+
return Empty();
32+
} else {
33+
return Target.TransformSet(Span, Value, PythonOperationKind.None);
34+
}
35+
}
36+
37+
public override void Walk(PythonWalker walker) {
38+
if (walker.Walk(this)) {
39+
Target.Walk(walker);
40+
Annotation.Walk(walker);
41+
Value?.Walk(walker);
42+
}
43+
walker.PostWalk(this);
44+
}
45+
}
46+
}

Src/IronPython/Compiler/Ast/PythonNameBinder.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,14 @@ public override bool Walk(AssignmentStatement node) {
189189
return true;
190190
}
191191

192+
// AnnotatedAssignStatement
193+
public override bool Walk(AnnotatedAssignStatement node) {
194+
node.Parent = _currentScope;
195+
node.Target.Walk(_define);
196+
return true;
197+
}
198+
199+
// AugmentedAssignStatement
192200
public override bool Walk(AugmentedAssignStatement node) {
193201
node.Parent = _currentScope;
194202
node.Left.Walk(_define);
@@ -727,7 +735,6 @@ public override bool Walk(NameExpression node) {
727735
return true;
728736
}
729737

730-
731738
// NonlocalStatement
732739
public override bool Walk(NonlocalStatement node) {
733740
node.Parent = _currentScope;

Src/IronPython/Compiler/Ast/PythonWalker.Generated.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ public virtual void PostWalk(YieldExpression node) { }
124124
public virtual bool Walk(YieldFromExpression node) { return true; }
125125
public virtual void PostWalk(YieldFromExpression node) { }
126126

127+
// AnnotatedAssignStatement
128+
public virtual bool Walk(AnnotatedAssignStatement node) { return true; }
129+
public virtual void PostWalk(AnnotatedAssignStatement node) { }
130+
127131
// AssertStatement
128132
public virtual bool Walk(AssertStatement node) { return true; }
129133
public virtual void PostWalk(AssertStatement node) { }
@@ -379,6 +383,10 @@ public override void PostWalk(YieldExpression node) { }
379383
public override bool Walk(YieldFromExpression node) { return false; }
380384
public override void PostWalk(YieldFromExpression node) { }
381385

386+
// AnnotatedAssignStatement
387+
public override bool Walk(AnnotatedAssignStatement node) { return false; }
388+
public override void PostWalk(AnnotatedAssignStatement node) { }
389+
382390
// AssertStatement
383391
public override bool Walk(AssertStatement node) { return false; }
384392
public override void PostWalk(AssertStatement node) { }

Src/IronPython/Compiler/Parser.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,14 +660,33 @@ private Statement FinishAssignments(Expression right) {
660660
return assign;
661661
}
662662

663-
// expr_stmt: testlist_star_expr (augassign (yield_expr|testlist) | ('=' (yield_expr|testlist_star_expr))*)
663+
// expr_stmt: testlist_star_expr (annassign | augassign (yield_expr|testlist) | ('=' (yield_expr|testlist_star_expr))*)
664664
// augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' | '**=' | '//=')
665665
private Statement ParseExprStmt() {
666666
Expression ret = ParseTestListStarExpr();
667667
if (ret is ErrorExpression) {
668668
NextToken();
669669
}
670670

671+
// annassign
672+
if (MaybeEat(TokenKind.Colon)) {
673+
if (ret.CheckAssign() is { } assignError) {
674+
ReportSyntaxError(ret.StartIndex, ret.EndIndex, assignError, ErrorCodes.SyntaxError | ErrorCodes.NoCaret);
675+
}
676+
677+
var annotation = ParseTest();
678+
if (MaybeEat(TokenKind.Assign)) {
679+
var right = ParseTest();
680+
var assign = new AnnotatedAssignStatement(ret, annotation, right, ret is NameExpression);
681+
assign.SetLoc(_globalParent, ret.StartIndex, right.EndIndex);
682+
return assign;
683+
} else {
684+
var assign = new AnnotatedAssignStatement(ret, annotation, null, ret is NameExpression);
685+
assign.SetLoc(_globalParent, ret.IndexSpan);
686+
return assign;
687+
}
688+
}
689+
671690
if (PeekToken(TokenKind.Assign)) {
672691
return FinishAssignments(ret);
673692
}

Src/IronPython/Modules/_ast.cs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ internal static stmt Convert(Statement stmt) {
214214
stmt ast = stmt switch {
215215
FunctionDefinition s => new FunctionDef(s),
216216
ReturnStatement s => new Return(s),
217+
AnnotatedAssignStatement s => new AnnAssign(s),
217218
AssignmentStatement s => new Assign(s),
218219
AugmentedAssignStatement s => new AugAssign(s),
219220
DelStatement s => new Delete(s),
@@ -711,6 +712,43 @@ public class And : boolop {
711712
internal static readonly And Instance = new And();
712713
}
713714

715+
[PythonType]
716+
public class AnnAssign : stmt {
717+
public AnnAssign() {
718+
_fields = PythonTuple.MakeTuple(new[] { nameof(target), nameof(annotation), nameof(value), nameof(simple) });
719+
}
720+
721+
public AnnAssign(expr target, expr annotation, expr value, int simple, [Optional] int? lineno, [Optional] int? col_offset)
722+
: this() {
723+
this.target = target;
724+
this.annotation = annotation;
725+
this.value = value;
726+
this.simple = simple;
727+
_lineno = lineno;
728+
_col_offset = col_offset;
729+
}
730+
731+
internal AnnAssign(AnnotatedAssignStatement stmt)
732+
: this() {
733+
target = Convert(stmt.Target, Store.Instance);
734+
annotation = Convert(stmt.Annotation);
735+
value = stmt.Value is null ? null : Convert(stmt.Value);
736+
simple = stmt.Simple ? 1 : 0;
737+
}
738+
739+
internal override Statement Revert() {
740+
return new AnnotatedAssignStatement(expr.Revert(target), expr.Revert(annotation), expr.Revert(value), simple != 0);
741+
}
742+
743+
public expr target { get; set; }
744+
745+
public expr annotation { get; set; }
746+
747+
public expr value { get; set; }
748+
749+
public int simple { get; set; }
750+
}
751+
714752
[PythonType]
715753
public class Assert : stmt {
716754
public Assert() {

Src/Scripts/generate_walker.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def get_ast(assembly, roots):
3131
if node.IsAbstract: continue
3232

3333
for root in roots:
34-
if inherits(node, root) and node.IsPublic:
34+
if inherits(node, root) and node.IsPublic:
3535
sets[root].add(node.Name)
3636
break
3737

@@ -40,7 +40,7 @@ def get_ast(assembly, roots):
4040
result.extend(sorted(list(sets[root])))
4141

4242
return result
43-
43+
4444
def gen_walker(cw, nodes, method, value):
4545
space = 0
4646
for node in nodes:
@@ -77,6 +77,7 @@ def gen_python_name_binder(cw):
7777
"DelStatement",
7878
"ClassDefinition",
7979
"FunctionDefinition",
80+
"AnnotatedAssignStatement",
8081
"AugmentedAssignStatement",
8182
"AssignmentStatement",
8283
"RaiseStatement",

0 commit comments

Comments
 (0)