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