Skip to content

Commit cd8c5fa

Browse files
committed
compile: implement starred assignment
1 parent e03f367 commit cd8c5fa

File tree

3 files changed

+140
-8
lines changed

3 files changed

+140
-8
lines changed

compile/compile.go

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1373,6 +1373,36 @@ func (c *compiler) comprehension(expr ast.Expr, generators []ast.Comprehension)
13731373
c.OpArg(vm.CALL_FUNCTION, 1)
13741374
}
13751375

1376+
// Compile a tuple or a list
1377+
func (c *compiler) tupleOrList(op byte, ctx ast.ExprContext, elts []ast.Expr) {
1378+
const INT_MAX = 0x7FFFFFFF
1379+
n := len(elts)
1380+
if ctx == ast.Store {
1381+
seen_star := false
1382+
for i, elt := range elts {
1383+
starred, isStarred := elt.(*ast.Starred)
1384+
if isStarred && !seen_star {
1385+
if i >= (1<<8) || n-i-1 >= (INT_MAX>>8) {
1386+
panic(py.ExceptionNewf(py.SyntaxError, "too many expressions in star-unpacking assignment"))
1387+
}
1388+
c.OpArg(vm.UNPACK_EX, uint32((i + ((n - i - 1) << 8))))
1389+
seen_star = true
1390+
// FIXME Overwrite the starred element
1391+
elts[i] = starred.Value
1392+
} else if isStarred {
1393+
panic(py.ExceptionNewf(py.SyntaxError, "two starred expressions in assignment"))
1394+
}
1395+
}
1396+
if !seen_star {
1397+
c.OpArg(vm.UNPACK_SEQUENCE, uint32(n))
1398+
}
1399+
}
1400+
c.Exprs(elts)
1401+
if ctx == ast.Load {
1402+
c.OpArg(op, uint32(n))
1403+
}
1404+
}
1405+
13761406
// Compile expressions
13771407
func (c *compiler) Exprs(exprs []ast.Expr) {
13781408
for _, expr := range exprs {
@@ -1624,23 +1654,26 @@ func (c *compiler) Expr(expr ast.Expr) {
16241654
case *ast.Starred:
16251655
// Value Expr
16261656
// Ctx ExprContext
1627-
panic("FIXME compile: Starred not implemented")
1657+
switch node.Ctx {
1658+
case ast.Store:
1659+
// In all legitimate cases, the Starred node was already replaced
1660+
// by tupleOrList: is that okay?
1661+
panic(py.ExceptionNewf(py.SyntaxError, "starred assignment target must be in a list or tuple"))
1662+
default:
1663+
panic(py.ExceptionNewf(py.SyntaxError, "can use starred expression only as assignment target"))
1664+
}
16281665
case *ast.Name:
16291666
// Id Identifier
16301667
// Ctx ExprContext
16311668
c.NameOp(string(node.Id), node.Ctx)
16321669
case *ast.List:
16331670
// Elts []Expr
16341671
// Ctx ExprContext
1635-
// FIXME do something with Ctx
1636-
c.Exprs(node.Elts)
1637-
c.OpArg(vm.BUILD_LIST, uint32(len(node.Elts)))
1672+
c.tupleOrList(vm.BUILD_LIST, node.Ctx, node.Elts)
16381673
case *ast.Tuple:
16391674
// Elts []Expr
16401675
// Ctx ExprContext
1641-
// FIXME do something with Ctx
1642-
c.Exprs(node.Elts)
1643-
c.OpArg(vm.BUILD_TUPLE, uint32(len(node.Elts)))
1676+
c.tupleOrList(vm.BUILD_TUPLE, node.Ctx, node.Elts)
16441677
default:
16451678
panic(py.ExceptionNewf(py.SyntaxError, "Unknown ExprBase: %v", expr))
16461679
}

compile/compile_data_test.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3841,4 +3841,93 @@ var compileTestData = []struct {
38413841
Firstlineno: 1,
38423842
Lnotab: "",
38433843
}, nil, ""},
3844+
{"*a = t", "exec", nil, py.SyntaxError, "starred assignment target must be in a list or tuple"},
3845+
{"a, *b = t", "exec", &py.Code{
3846+
Argcount: 0,
3847+
Kwonlyargcount: 0,
3848+
Nlocals: 0,
3849+
Stacksize: 2,
3850+
Flags: 64,
3851+
Code: "\x65\x00\x00\x5e\x01\x00\x5a\x01\x00\x5a\x02\x00\x64\x00\x00\x53",
3852+
Consts: []py.Object{py.None},
3853+
Names: []string{"t", "a", "b"},
3854+
Varnames: []string{},
3855+
Freevars: []string{},
3856+
Cellvars: []string{},
3857+
Filename: "<string>",
3858+
Name: "<module>",
3859+
Firstlineno: 1,
3860+
Lnotab: "",
3861+
}, nil, ""},
3862+
{"(a, *b) = t", "exec", &py.Code{
3863+
Argcount: 0,
3864+
Kwonlyargcount: 0,
3865+
Nlocals: 0,
3866+
Stacksize: 2,
3867+
Flags: 64,
3868+
Code: "\x65\x00\x00\x5e\x01\x00\x5a\x01\x00\x5a\x02\x00\x64\x00\x00\x53",
3869+
Consts: []py.Object{py.None},
3870+
Names: []string{"t", "a", "b"},
3871+
Varnames: []string{},
3872+
Freevars: []string{},
3873+
Cellvars: []string{},
3874+
Filename: "<string>",
3875+
Name: "<module>",
3876+
Firstlineno: 1,
3877+
Lnotab: "",
3878+
}, nil, ""},
3879+
{"[a, *b] = t", "exec", &py.Code{
3880+
Argcount: 0,
3881+
Kwonlyargcount: 0,
3882+
Nlocals: 0,
3883+
Stacksize: 2,
3884+
Flags: 64,
3885+
Code: "\x65\x00\x00\x5e\x01\x00\x5a\x01\x00\x5a\x02\x00\x64\x00\x00\x53",
3886+
Consts: []py.Object{py.None},
3887+
Names: []string{"t", "a", "b"},
3888+
Varnames: []string{},
3889+
Freevars: []string{},
3890+
Cellvars: []string{},
3891+
Filename: "<string>",
3892+
Name: "<module>",
3893+
Firstlineno: 1,
3894+
Lnotab: "",
3895+
}, nil, ""},
3896+
{"a, *b, c = t", "exec", &py.Code{
3897+
Argcount: 0,
3898+
Kwonlyargcount: 0,
3899+
Nlocals: 0,
3900+
Stacksize: 3,
3901+
Flags: 64,
3902+
Code: "\x65\x00\x00\x5e\x01\x01\x5a\x01\x00\x5a\x02\x00\x5a\x03\x00\x64\x00\x00\x53",
3903+
Consts: []py.Object{py.None},
3904+
Names: []string{"t", "a", "b", "c"},
3905+
Varnames: []string{},
3906+
Freevars: []string{},
3907+
Cellvars: []string{},
3908+
Filename: "<string>",
3909+
Name: "<module>",
3910+
Firstlineno: 1,
3911+
Lnotab: "",
3912+
}, nil, ""},
3913+
{"a, *b, *c = t", "exec", nil, py.SyntaxError, "two starred expressions in assignment"},
3914+
{"a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,*a = t", "exec", nil, py.SyntaxError, "too many expressions in star-unpacking assignment"},
3915+
{"a, b, *c", "exec", nil, py.SyntaxError, "can use starred expression only as assignment target"},
3916+
{"a, (b, c), d = t", "exec", &py.Code{
3917+
Argcount: 0,
3918+
Kwonlyargcount: 0,
3919+
Nlocals: 0,
3920+
Stacksize: 3,
3921+
Flags: 64,
3922+
Code: "\x65\x00\x00\x5c\x03\x00\x5a\x01\x00\x5c\x02\x00\x5a\x02\x00\x5a\x03\x00\x5a\x04\x00\x64\x00\x00\x53",
3923+
Consts: []py.Object{py.None},
3924+
Names: []string{"t", "a", "b", "c", "d"},
3925+
Varnames: []string{},
3926+
Freevars: []string{},
3927+
Cellvars: []string{},
3928+
Filename: "<string>",
3929+
Name: "<module>",
3930+
Firstlineno: 1,
3931+
Lnotab: "",
3932+
}, nil, ""},
38443933
}

compile/make_compile_test.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,17 @@ def f():
363363
''', "exec"),
364364
# ellipsis
365365
('''...''', "exec"),
366-
]
366+
# starred...
367+
('''*a = t''', "exec", SyntaxError),
368+
('''a, *b = t''', "exec"),
369+
('''(a, *b) = t''', "exec"),
370+
('''[a, *b] = t''', "exec"),
371+
('''a, *b, c = t''', "exec"),
372+
('''a, *b, *c = t''', "exec", SyntaxError),
373+
('''a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,*a = t''', "exec", SyntaxError),
374+
('''a, b, *c''', "exec", SyntaxError),
375+
('''a, (b, c), d = t''', "exec"),
376+
]
367377

368378
def string(s):
369379
if isinstance(s, str):

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy