1# Tests of Starlark assignment.
2
3# This is a "chunked" file: each "---" effectively starts a new file.
4
5# tuple assignment
6load("assert.star", "assert")
7
8() = () # empty ok
9
10a, b, c = 1, 2, 3
11assert.eq(a, 1)
12assert.eq(b, 2)
13assert.eq(c, 3)
14
15(d, e, f,) = (1, 2, 3) # trailing comma ok
16---
17(a, b, c) = 1 ### "got int in sequence assignment"
18---
19(a, b) = () ### "too few values to unpack"
20---
21(a, b) = (1,) ### "too few values to unpack"
22---
23(a, b, c) = (1, 2) ### "too few values to unpack"
24---
25(a, b) = (1, 2, 3) ### "too many values to unpack"
26---
27() = 1 ### "got int in sequence assignment"
28---
29() = (1,) ### "too many values to unpack"
30---
31() = (1, 2) ### "too many values to unpack"
32---
33# list assignment
34load("assert.star", "assert")
35
36[] = [] # empty ok
37
38[a, b, c] = [1, 2, 3]
39assert.eq(a, 1)
40assert.eq(b, 2)
41assert.eq(c, 3)
42
43[d, e, f,] = [1, 2, 3] # trailing comma ok
44---
45[a, b, c] = 1 ### "got int in sequence assignment"
46---
47[a, b] = [] ### "too few values to unpack"
48---
49[a, b] = [1] ### "too few values to unpack"
50---
51[a, b, c] = [1, 2] ### "too few values to unpack"
52---
53[a, b] = [1, 2, 3] ### "too many values to unpack"
54---
55[] = 1 ### "got int in sequence assignment"
56---
57[] = [1] ### "too many values to unpack"
58---
59[] = [1, 2] ### "too many values to unpack"
60---
61# list-tuple assignment
62load("assert.star", "assert")
63
64# empty ok
65[] = ()
66() = []
67
68[a, b, c] = (1, 2, 3)
69assert.eq(a, 1)
70assert.eq(b, 2)
71assert.eq(c, 3)
72
73[a2, b2, c2] = 1, 2, 3 # bare tuple ok
74
75(d, e, f) = [1, 2, 3]
76assert.eq(d, 1)
77assert.eq(e, 2)
78assert.eq(f, 3)
79
80[g, h, (i, j)] = (1, 2, [3, 4])
81assert.eq(g, 1)
82assert.eq(h, 2)
83assert.eq(i, 3)
84assert.eq(j, 4)
85
86(k, l, [m, n]) = [1, 2, (3, 4)]
87assert.eq(k, 1)
88assert.eq(l, 2)
89assert.eq(m, 3)
90assert.eq(n, 4)
91
92---
93# misc assignment
94load("assert.star", "assert")
95
96def assignment():
97 a = [1, 2, 3]
98 a[1] = 5
99 assert.eq(a, [1, 5, 3])
100 a[-2] = 2
101 assert.eq(a, [1, 2, 3])
102 assert.eq("%d %d" % (5, 7), "5 7")
103 x={}
104 x[1] = 2
105 x[1] += 3
106 assert.eq(x[1], 5)
107 def f12(): x[(1, "abc", {})] = 1
108 assert.fails(f12, "unhashable type: dict")
109
110assignment()
111
112---
113# augmented assignment
114
115load("assert.star", "assert")
116
117def f():
118 x = 1
119 x += 1
120 assert.eq(x, 2)
121 x *= 3
122 assert.eq(x, 6)
123f()
124
125---
126# effects of evaluating LHS occur only once
127
128load("assert.star", "assert")
129
130count = [0] # count[0] is the number of calls to f
131
132def f():
133 count[0] += 1
134 return count[0]
135
136x = [1, 2, 3]
137x[f()] += 1
138
139assert.eq(x, [1, 3, 3]) # sole call to f returned 1
140assert.eq(count[0], 1) # f was called only once
141
142---
143# Order of evaluation.
144
145load("assert.star", "assert")
146
147calls = []
148
149def f(name, result):
150 calls.append(name)
151 return result
152
153# The right side is evaluated before the left in an ordinary assignment.
154calls.clear()
155f("array", [0])[f("index", 0)] = f("rhs", 0)
156assert.eq(calls, ["rhs", "array", "index"])
157
158calls.clear()
159f("lhs1", [0])[0], f("lhs2", [0])[0] = f("rhs1", 0), f("rhs2", 0)
160assert.eq(calls, ["rhs1", "rhs2", "lhs1", "lhs2"])
161
162# Left side is evaluated first (and only once) in an augmented assignment.
163calls.clear()
164f("array", [0])[f("index", 0)] += f("addend", 1)
165assert.eq(calls, ["array", "index", "addend"])
166
167---
168# global referenced before assignment
169
170def f():
171 return g ### "global variable g referenced before assignment"
172
173f()
174
175g = 1
176
177---
178# Free variables are captured by reference, so this is ok.
179load("assert.star", "assert")
180
181def f():
182 def g():
183 return outer
184 outer = 1
185 return g()
186
187assert.eq(f(), 1)
188
189---
190load("assert.star", "assert")
191
192printok = [False]
193
194# This program should resolve successfully but fail dynamically.
195# However, the Java implementation currently reports the dynamic
196# error at the x=1 statement (b/33975425). I think we need to simplify
197# the resolver algorithm to what we have implemented.
198def use_before_def():
199 print(x) # dynamic error: local var referenced before assignment
200 printok[0] = True
201 x = 1 # makes 'x' local
202
203assert.fails(use_before_def, 'local variable x referenced before assignment')
204assert.true(not printok[0]) # execution of print statement failed
205
206---
207x = [1]
208x.extend([2]) # ok
209
210def f():
211 x += [4] ### "local variable x referenced before assignment"
212
213f()
214
215---
216
217z += 3 ### "global variable z referenced before assignment"
218
219---
220load("assert.star", "assert")
221
222# It's ok to define a global that shadows a built-in...
223list = []
224assert.eq(type(list), "list")
225
226# ...but then all uses refer to the global,
227# even if they occur before the binding use.
228# See github.com/google/skylark/issues/116.
229assert.fails(lambda: tuple, "global variable tuple referenced before assignment")
230tuple = ()
231
232---
233# option:set
234# Same as above, but set is dialect-specific;
235# we shouldn't notice any difference.
236load("assert.star", "assert")
237
238set = [1, 2, 3]
239assert.eq(type(set), "list")
240
241# As in Python 2 and Python 3,
242# all 'in x' expressions in a comprehension are evaluated
243# in the comprehension's lexical block, except the first,
244# which is resolved in the outer block.
245x = [[1, 2]]
246assert.eq([x for x in x for y in x],
247 [[1, 2], [1, 2]])
248
249---
250# A comprehension establishes a single new lexical block,
251# not one per 'for' clause.
252x = [1, 2]
253_ = [x for _ in [3] for x in x] ### "local variable x referenced before assignment"
254
255---
256load("assert.star", "assert")
257
258# assign singleton sequence to 1-tuple
259(x,) = (1,)
260assert.eq(x, 1)
261(y,) = [1]
262assert.eq(y, 1)
263
264# assign 1-tuple to variable
265z = (1,)
266assert.eq(type(z), "tuple")
267assert.eq(len(z), 1)
268assert.eq(z[0], 1)
269
270# assign value to parenthesized variable
271(a) = 1
272assert.eq(a, 1)
273
274---
275# assignment to/from fields.
276load("assert.star", "assert", "freeze")
277
278hf = hasfields()
279hf.x = 1
280assert.eq(hf.x, 1)
281hf.x = [1, 2]
282hf.x += [3, 4]
283assert.eq(hf.x, [1, 2, 3, 4])
284freeze(hf)
285def setX(hf):
286 hf.x = 2
287def setY(hf):
288 hf.y = 3
289assert.fails(lambda: setX(hf), "cannot set field on a frozen hasfields")
290assert.fails(lambda: setY(hf), "cannot set field on a frozen hasfields")
291
292---
293# destucturing assignment in a for loop.
294load("assert.star", "assert")
295
296def f():
297 res = []
298 for (x, y), z in [(["a", "b"], 3), (["c", "d"], 4)]:
299 res.append((x, y, z))
300 return res
301assert.eq(f(), [("a", "b", 3), ("c", "d", 4)])
302
303def g():
304 a = {}
305 for i, a[i] in [("one", 1), ("two", 2)]:
306 pass
307 return a
308assert.eq(g(), {"one": 1, "two": 2})
309
310---
311# parenthesized LHS in augmented assignment (success)
312# option:globalreassign
313load("assert.star", "assert")
314
315a = 5
316(a) += 3
317assert.eq(a, 8)
318
319---
320# parenthesized LHS in augmented assignment (error)
321
322(a) += 5 ### "global variable a referenced before assignment"
323
324---
325# option:globalreassign
326load("assert.star", "assert")
327assert = 1
328load("assert.star", "assert")
329
330---
331# option:globalreassign option:loadbindsglobally
332load("assert.star", "assert")
333assert = 1
334load("assert.star", "assert")
335
336---
337# option:loadbindsglobally
338_ = assert ### "global variable assert referenced before assignment"
339load("assert.star", "assert")
340
341---
342_ = assert ### "local variable assert referenced before assignment"
343load("assert.star", "assert")
344
345---
346def f(): assert.eq(1, 1) # forward ref OK
347load("assert.star", "assert")
348f()
349
350---
351# option:loadbindsglobally
352def f(): assert.eq(1, 1) # forward ref OK
353load("assert.star", "assert")
354f()
View as plain text