diff options
Diffstat (limited to 'starlark/testdata/assign.star')
-rw-r--r-- | starlark/testdata/assign.star | 354 |
1 files changed, 354 insertions, 0 deletions
diff --git a/starlark/testdata/assign.star b/starlark/testdata/assign.star new file mode 100644 index 0000000..7f579f0 --- /dev/null +++ b/starlark/testdata/assign.star @@ -0,0 +1,354 @@ +# Tests of Starlark assignment. + +# This is a "chunked" file: each "---" effectively starts a new file. + +# tuple assignment +load("assert.star", "assert") + +() = () # empty ok + +a, b, c = 1, 2, 3 +assert.eq(a, 1) +assert.eq(b, 2) +assert.eq(c, 3) + +(d, e, f,) = (1, 2, 3) # trailing comma ok +--- +(a, b, c) = 1 ### "got int in sequence assignment" +--- +(a, b) = () ### "too few values to unpack" +--- +(a, b) = (1,) ### "too few values to unpack" +--- +(a, b, c) = (1, 2) ### "too few values to unpack" +--- +(a, b) = (1, 2, 3) ### "too many values to unpack" +--- +() = 1 ### "got int in sequence assignment" +--- +() = (1,) ### "too many values to unpack" +--- +() = (1, 2) ### "too many values to unpack" +--- +# list assignment +load("assert.star", "assert") + +[] = [] # empty ok + +[a, b, c] = [1, 2, 3] +assert.eq(a, 1) +assert.eq(b, 2) +assert.eq(c, 3) + +[d, e, f,] = [1, 2, 3] # trailing comma ok +--- +[a, b, c] = 1 ### "got int in sequence assignment" +--- +[a, b] = [] ### "too few values to unpack" +--- +[a, b] = [1] ### "too few values to unpack" +--- +[a, b, c] = [1, 2] ### "too few values to unpack" +--- +[a, b] = [1, 2, 3] ### "too many values to unpack" +--- +[] = 1 ### "got int in sequence assignment" +--- +[] = [1] ### "too many values to unpack" +--- +[] = [1, 2] ### "too many values to unpack" +--- +# list-tuple assignment +load("assert.star", "assert") + +# empty ok +[] = () +() = [] + +[a, b, c] = (1, 2, 3) +assert.eq(a, 1) +assert.eq(b, 2) +assert.eq(c, 3) + +[a2, b2, c2] = 1, 2, 3 # bare tuple ok + +(d, e, f) = [1, 2, 3] +assert.eq(d, 1) +assert.eq(e, 2) +assert.eq(f, 3) + +[g, h, (i, j)] = (1, 2, [3, 4]) +assert.eq(g, 1) +assert.eq(h, 2) +assert.eq(i, 3) +assert.eq(j, 4) + +(k, l, [m, n]) = [1, 2, (3, 4)] +assert.eq(k, 1) +assert.eq(l, 2) +assert.eq(m, 3) +assert.eq(n, 4) + +--- +# misc assignment +load("assert.star", "assert") + +def assignment(): + a = [1, 2, 3] + a[1] = 5 + assert.eq(a, [1, 5, 3]) + a[-2] = 2 + assert.eq(a, [1, 2, 3]) + assert.eq("%d %d" % (5, 7), "5 7") + x={} + x[1] = 2 + x[1] += 3 + assert.eq(x[1], 5) + def f12(): x[(1, "abc", {})] = 1 + assert.fails(f12, "unhashable type: dict") + +assignment() + +--- +# augmented assignment + +load("assert.star", "assert") + +def f(): + x = 1 + x += 1 + assert.eq(x, 2) + x *= 3 + assert.eq(x, 6) +f() + +--- +# effects of evaluating LHS occur only once + +load("assert.star", "assert") + +count = [0] # count[0] is the number of calls to f + +def f(): + count[0] += 1 + return count[0] + +x = [1, 2, 3] +x[f()] += 1 + +assert.eq(x, [1, 3, 3]) # sole call to f returned 1 +assert.eq(count[0], 1) # f was called only once + +--- +# Order of evaluation. + +load("assert.star", "assert") + +calls = [] + +def f(name, result): + calls.append(name) + return result + +# The right side is evaluated before the left in an ordinary assignment. +calls.clear() +f("array", [0])[f("index", 0)] = f("rhs", 0) +assert.eq(calls, ["rhs", "array", "index"]) + +calls.clear() +f("lhs1", [0])[0], f("lhs2", [0])[0] = f("rhs1", 0), f("rhs2", 0) +assert.eq(calls, ["rhs1", "rhs2", "lhs1", "lhs2"]) + +# Left side is evaluated first (and only once) in an augmented assignment. +calls.clear() +f("array", [0])[f("index", 0)] += f("addend", 1) +assert.eq(calls, ["array", "index", "addend"]) + +--- +# global referenced before assignment + +def f(): + return g ### "global variable g referenced before assignment" + +f() + +g = 1 + +--- +# Free variables are captured by reference, so this is ok. +load("assert.star", "assert") + +def f(): + def g(): + return outer + outer = 1 + return g() + +assert.eq(f(), 1) + +--- +load("assert.star", "assert") + +printok = [False] + +# This program should resolve successfully but fail dynamically. +# However, the Java implementation currently reports the dynamic +# error at the x=1 statement (b/33975425). I think we need to simplify +# the resolver algorithm to what we have implemented. +def use_before_def(): + print(x) # dynamic error: local var referenced before assignment + printok[0] = True + x = 1 # makes 'x' local + +assert.fails(use_before_def, 'local variable x referenced before assignment') +assert.true(not printok[0]) # execution of print statement failed + +--- +x = [1] +x.extend([2]) # ok + +def f(): + x += [4] ### "local variable x referenced before assignment" + +f() + +--- + +z += 3 ### "global variable z referenced before assignment" + +--- +load("assert.star", "assert") + +# It's ok to define a global that shadows a built-in... +list = [] +assert.eq(type(list), "list") + +# ...but then all uses refer to the global, +# even if they occur before the binding use. +# See github.com/google/skylark/issues/116. +assert.fails(lambda: tuple, "global variable tuple referenced before assignment") +tuple = () + +--- +# option:set +# Same as above, but set is dialect-specific; +# we shouldn't notice any difference. +load("assert.star", "assert") + +set = [1, 2, 3] +assert.eq(type(set), "list") + +# As in Python 2 and Python 3, +# all 'in x' expressions in a comprehension are evaluated +# in the comprehension's lexical block, except the first, +# which is resolved in the outer block. +x = [[1, 2]] +assert.eq([x for x in x for y in x], + [[1, 2], [1, 2]]) + +--- +# A comprehension establishes a single new lexical block, +# not one per 'for' clause. +x = [1, 2] +_ = [x for _ in [3] for x in x] ### "local variable x referenced before assignment" + +--- +load("assert.star", "assert") + +# assign singleton sequence to 1-tuple +(x,) = (1,) +assert.eq(x, 1) +(y,) = [1] +assert.eq(y, 1) + +# assign 1-tuple to variable +z = (1,) +assert.eq(type(z), "tuple") +assert.eq(len(z), 1) +assert.eq(z[0], 1) + +# assign value to parenthesized variable +(a) = 1 +assert.eq(a, 1) + +--- +# assignment to/from fields. +load("assert.star", "assert", "freeze") + +hf = hasfields() +hf.x = 1 +assert.eq(hf.x, 1) +hf.x = [1, 2] +hf.x += [3, 4] +assert.eq(hf.x, [1, 2, 3, 4]) +freeze(hf) +def setX(hf): + hf.x = 2 +def setY(hf): + hf.y = 3 +assert.fails(lambda: setX(hf), "cannot set field on a frozen hasfields") +assert.fails(lambda: setY(hf), "cannot set field on a frozen hasfields") + +--- +# destucturing assignment in a for loop. +load("assert.star", "assert") + +def f(): + res = [] + for (x, y), z in [(["a", "b"], 3), (["c", "d"], 4)]: + res.append((x, y, z)) + return res +assert.eq(f(), [("a", "b", 3), ("c", "d", 4)]) + +def g(): + a = {} + for i, a[i] in [("one", 1), ("two", 2)]: + pass + return a +assert.eq(g(), {"one": 1, "two": 2}) + +--- +# parenthesized LHS in augmented assignment (success) +# option:globalreassign +load("assert.star", "assert") + +a = 5 +(a) += 3 +assert.eq(a, 8) + +--- +# parenthesized LHS in augmented assignment (error) + +(a) += 5 ### "global variable a referenced before assignment" + +--- +# option:globalreassign +load("assert.star", "assert") +assert = 1 +load("assert.star", "assert") + +--- +# option:globalreassign option:loadbindsglobally +load("assert.star", "assert") +assert = 1 +load("assert.star", "assert") + +--- +# option:loadbindsglobally +_ = assert ### "global variable assert referenced before assignment" +load("assert.star", "assert") + +--- +_ = assert ### "local variable assert referenced before assignment" +load("assert.star", "assert") + +--- +def f(): assert.eq(1, 1) # forward ref OK +load("assert.star", "assert") +f() + +--- +# option:loadbindsglobally +def f(): assert.eq(1, 1) # forward ref OK +load("assert.star", "assert") +f() |