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() 355