go.starlark.net@v0.0.0-20231101134539-556fd59b42f6/starlark/testdata/assign.star (about)

     1  # Tests of Starlark assignment.
     2  
     3  # This is a "chunked" file: each "---" effectively starts a new file.
     4  
     5  # tuple assignment
     6  load("assert.star", "assert")
     7  
     8  () = () # empty ok
     9  
    10  a, b, c = 1, 2, 3
    11  assert.eq(a, 1)
    12  assert.eq(b, 2)
    13  assert.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
    34  load("assert.star", "assert")
    35  
    36  [] = [] # empty ok
    37  
    38  [a, b, c] = [1, 2, 3]
    39  assert.eq(a, 1)
    40  assert.eq(b, 2)
    41  assert.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
    62  load("assert.star", "assert")
    63  
    64  # empty ok
    65  [] = ()
    66  () = []
    67  
    68  [a, b, c] = (1, 2, 3)
    69  assert.eq(a, 1)
    70  assert.eq(b, 2)
    71  assert.eq(c, 3)
    72  
    73  [a2, b2, c2] = 1, 2, 3 # bare tuple ok
    74  
    75  (d, e, f) = [1, 2, 3]
    76  assert.eq(d, 1)
    77  assert.eq(e, 2)
    78  assert.eq(f, 3)
    79  
    80  [g, h, (i, j)] = (1, 2, [3, 4])
    81  assert.eq(g, 1)
    82  assert.eq(h, 2)
    83  assert.eq(i, 3)
    84  assert.eq(j, 4)
    85  
    86  (k, l, [m, n]) = [1, 2, (3, 4)]
    87  assert.eq(k, 1)
    88  assert.eq(l, 2)
    89  assert.eq(m, 3)
    90  assert.eq(n, 4)
    91  
    92  ---
    93  # misc assignment
    94  load("assert.star", "assert")
    95  
    96  def 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  
   110  assignment()
   111  
   112  ---
   113  # augmented assignment
   114  
   115  load("assert.star", "assert")
   116  
   117  def f():
   118    x = 1
   119    x += 1
   120    assert.eq(x, 2)
   121    x *= 3
   122    assert.eq(x, 6)
   123  f()
   124  
   125  ---
   126  # effects of evaluating LHS occur only once
   127  
   128  load("assert.star", "assert")
   129  
   130  count = [0] # count[0] is the number of calls to f
   131  
   132  def f():
   133    count[0] += 1
   134    return count[0]
   135  
   136  x = [1, 2, 3]
   137  x[f()] += 1
   138  
   139  assert.eq(x, [1, 3, 3]) # sole call to f returned 1
   140  assert.eq(count[0], 1) # f was called only once
   141  
   142  ---
   143  # Order of evaluation.
   144  
   145  load("assert.star", "assert")
   146  
   147  calls = []
   148  
   149  def f(name, result):
   150    calls.append(name)
   151    return result
   152  
   153  # The right side is evaluated before the left in an ordinary assignment.
   154  calls.clear()
   155  f("array", [0])[f("index", 0)] = f("rhs", 0)
   156  assert.eq(calls, ["rhs", "array", "index"])
   157  
   158  calls.clear()
   159  f("lhs1", [0])[0], f("lhs2", [0])[0] = f("rhs1", 0), f("rhs2", 0)
   160  assert.eq(calls, ["rhs1", "rhs2", "lhs1", "lhs2"])
   161  
   162  # Left side is evaluated first (and only once) in an augmented assignment.
   163  calls.clear()
   164  f("array", [0])[f("index", 0)] += f("addend", 1)
   165  assert.eq(calls, ["array", "index", "addend"])
   166  
   167  ---
   168  # global referenced before assignment
   169  
   170  def f():
   171     return g ### "global variable g referenced before assignment"
   172  
   173  f()
   174  
   175  g = 1
   176  
   177  ---
   178  # Free variables are captured by reference, so this is ok.
   179  load("assert.star", "assert")
   180  
   181  def f():
   182     def g():
   183       return outer
   184     outer = 1
   185     return g()
   186  
   187  assert.eq(f(), 1)
   188  
   189  ---
   190  load("assert.star", "assert")
   191  
   192  printok = [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.
   198  def use_before_def():
   199    print(x) # dynamic error: local var referenced before assignment
   200    printok[0] = True
   201    x = 1  # makes 'x' local
   202  
   203  assert.fails(use_before_def, 'local variable x referenced before assignment')
   204  assert.true(not printok[0]) # execution of print statement failed
   205  
   206  ---
   207  x = [1]
   208  x.extend([2]) # ok
   209  
   210  def f():
   211     x += [4] ### "local variable x referenced before assignment"
   212  
   213  f()
   214  
   215  ---
   216  
   217  z += 3 ### "global variable z referenced before assignment"
   218  
   219  ---
   220  load("assert.star", "assert")
   221  
   222  # It's ok to define a global that shadows a built-in...
   223  list = []
   224  assert.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.
   229  assert.fails(lambda: tuple, "global variable tuple referenced before assignment")
   230  tuple = ()
   231  
   232  ---
   233  # option:set
   234  # Same as above, but set is dialect-specific;
   235  # we shouldn't notice any difference.
   236  load("assert.star", "assert")
   237  
   238  set = [1, 2, 3]
   239  assert.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.
   245  x = [[1, 2]]
   246  assert.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.
   252  x = [1, 2]
   253  _ = [x for _ in [3] for x in x] ### "local variable x referenced before assignment"
   254  
   255  ---
   256  load("assert.star", "assert")
   257  
   258  # assign singleton sequence to 1-tuple
   259  (x,) = (1,)
   260  assert.eq(x, 1)
   261  (y,) = [1]
   262  assert.eq(y, 1)
   263  
   264  # assign 1-tuple to variable
   265  z = (1,)
   266  assert.eq(type(z), "tuple")
   267  assert.eq(len(z), 1)
   268  assert.eq(z[0], 1)
   269  
   270  # assign value to parenthesized variable
   271  (a) = 1
   272  assert.eq(a, 1)
   273  
   274  ---
   275  # assignment to/from fields.
   276  load("assert.star", "assert", "freeze")
   277  
   278  hf = hasfields()
   279  hf.x = 1
   280  assert.eq(hf.x, 1)
   281  hf.x = [1, 2]
   282  hf.x += [3, 4]
   283  assert.eq(hf.x, [1, 2, 3, 4])
   284  freeze(hf)
   285  def setX(hf):
   286    hf.x = 2
   287  def setY(hf):
   288    hf.y = 3
   289  assert.fails(lambda: setX(hf), "cannot set field on a frozen hasfields")
   290  assert.fails(lambda: setY(hf), "cannot set field on a frozen hasfields")
   291  
   292  ---
   293  # destucturing assignment in a for loop.
   294  load("assert.star", "assert")
   295  
   296  def f():
   297    res = []
   298    for (x, y), z in [(["a", "b"], 3), (["c", "d"], 4)]:
   299      res.append((x, y, z))
   300    return res
   301  assert.eq(f(), [("a", "b", 3), ("c", "d", 4)])
   302  
   303  def g():
   304    a = {}
   305    for i, a[i] in [("one", 1), ("two", 2)]:
   306      pass
   307    return a
   308  assert.eq(g(), {"one": 1, "two": 2})
   309  
   310  ---
   311  # parenthesized LHS in augmented assignment (success)
   312  # option:globalreassign
   313  load("assert.star", "assert")
   314  
   315  a = 5
   316  (a) += 3
   317  assert.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
   326  load("assert.star", "assert")
   327  assert = 1
   328  load("assert.star", "assert")
   329  
   330  ---
   331  # option:globalreassign option:loadbindsglobally
   332  load("assert.star", "assert")
   333  assert = 1
   334  load("assert.star", "assert")
   335  
   336  ---
   337  # option:loadbindsglobally
   338  _ = assert ### "global variable assert referenced before assignment"
   339  load("assert.star", "assert")
   340  
   341  ---
   342  _ = assert ### "local variable assert referenced before assignment"
   343  load("assert.star", "assert")
   344  
   345  ---
   346  def f(): assert.eq(1, 1) # forward ref OK
   347  load("assert.star", "assert")
   348  f()
   349  
   350  ---
   351  # option:loadbindsglobally
   352  def f(): assert.eq(1, 1) # forward ref OK
   353  load("assert.star", "assert")
   354  f()