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