github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/runtime/lua/locals.lua (about)

     1  --
     2  -- const tests
     3  --
     4  
     5  local function test(src)
     6      local res, err = load(src)
     7      if res ~= nil then
     8          print(pcall(res))
     9      else
    10          print(false, err)
    11      end
    12  end
    13  
    14  test[[
    15      local foo <const> = 25
    16      return foo
    17  ]]
    18  --> =true	25
    19  
    20  test[[
    21      local foo <const> = "hello"
    22      foo = "bye"
    23  ]]
    24  --> ~false\t.*attempt to reassign constant variable 'foo'
    25  
    26  test[[
    27      local foo <const> = 25
    28      local foo = foo + 2
    29      return foo
    30  ]]
    31  --> =true	27
    32  
    33  test[[
    34      local foo, bar <const> = 25, 32
    35      do
    36          local bar
    37          bar = 72
    38      end
    39      foo = foo + 2
    40      bar = bar - 1
    41      return foo + bar
    42  ]]
    43  --> ~false\t.*attempt to reassign constant variable 'bar'
    44  
    45  test[[
    46      local x <const> = 2
    47      local function foo()
    48          x = 3
    49          return x
    50      end
    51      return foo()
    52  ]]
    53  --> ~false\t.*attempt to reassign constant variable 'x'
    54  
    55  --
    56  -- to-be-closed tests
    57  --
    58  
    59  test[[
    60      local x <close> = nil
    61      x = 3
    62  ]]
    63  --> ~false\t.*attempt to reassign constant variable 'x'
    64  
    65  test[[
    66      local x <close> = 1
    67  ]]
    68  --> ~false\t.*to be closed value missing a __close metamethod
    69  
    70  function make(msg, err)
    71      t = {}
    72      setmetatable(t, {__close = function (x, e) 
    73          if e ~= nil then
    74              print(msg, e)
    75          else
    76              print(msg)
    77          end
    78          if err ~= nil then 
    79              error(err)
    80          end
    81      end})
    82      return t
    83  end
    84  
    85  do
    86      local x <close> = make("x")
    87      print("a")
    88  end
    89  print("b")
    90  --> =a
    91  --> =x
    92  --> =b
    93  
    94  do
    95      local x <close> = make("x")
    96      local y <close> = make("y")
    97  end
    98  --> =y
    99  --> =x
   100  
   101  do
   102      local x <close>, y <close> = make("aa"), make("bb")
   103  end
   104  --> =bb
   105  --> =aa
   106  
   107  -- errors in close metamethods.  If a one produces an error, it looks like the
   108  -- next one is fed that error.
   109  pcall(function()
   110      local x <close> = make("x")
   111      local y <close> = make("y", "YY")
   112      local z <close> = make("z")
   113      local t <close> = make("t", "TT")
   114      error("ERROR")
   115  end)
   116  --> ~t\t.*ERROR
   117  --> ~z\t.*TT
   118  --> ~y\t.*TT
   119  --> ~x\t.*YY
   120  
   121  -- A function to test to-be-closed variables
   122  local s
   123  function mk(a)
   124      t = {}
   125      s = s .. '+' .. a
   126      setmetatable(t, {__close = function () s = s .. '-' .. a end})
   127      return t
   128  end
   129  
   130  -- How it works
   131  do
   132      s = "start"
   133      local v <close> = mk("bob")
   134      print(s)
   135      --> =start+bob
   136  end
   137  print(s)
   138  --> =start+bob-bob
   139  
   140  do
   141      s = "start"
   142      local function f()
   143          local a <close> = mk("a")
   144          for i = 1, 3 do
   145              local b <close> = mk("b"..i)
   146          end
   147          do
   148              local c <close> = mk("c")
   149              do
   150                  local d <close> = mk("d")
   151                  return
   152              end
   153          end
   154      end
   155      f()
   156      print(s)
   157      --> =start+a+b1-b1+b2-b2+b3-b3+c+d-d-c-a
   158  end
   159  
   160  do
   161      s = "start"
   162      local function f(n)
   163          local x <close> = mk("x"..n)
   164          if n > 0 then
   165              f(n - 1)
   166          else
   167              error("stop")
   168          end
   169      end
   170      print(pcall(f, 3))
   171      --> ~false\t.*: stop
   172      print(s)
   173      --> =start+x3+x2+x1+x0-x0-x1-x2-x3
   174  end
   175  
   176  do
   177      print(pcall(function()
   178          local x <close> = {}
   179          print"we don't get to here"
   180      end))
   181      --> ~false\t.*missing a __close metamethod
   182  
   183      print(pcall(function()
   184          local x <close> = mk("x")
   185          getmetatable(x).__close = nil
   186          local x <close> = make("haha")
   187          print"we get here"
   188      end))
   189      --> =we get here
   190      --> =haha
   191      --> ~false\t.*missing a __close metamethod
   192  
   193  end
   194  
   195  -- close actions are run before return debug hooks.  The test below shows that
   196  -- because 'myfunction' is output.
   197  do
   198      local function myfunction()
   199          local function close()
   200              debug.sethook(function()
   201                  print(debug.getinfo(2).name)
   202              end, "r")
   203          end
   204          local t = {}
   205          setmetatable(t, {__close=close})
   206          local x <close> = t
   207      end
   208      myfunction()
   209      --> =sethook
   210      --> =close
   211      --> =myfunction
   212      debug.sethook()
   213  end
   214  
   215  -- Tail calls are disabled when there are pending to-be-closed variables.
   216  do
   217      s = "start"
   218      local function g()
   219          local y <close> = mk("y")
   220      end
   221      local function f()
   222          local x <close> = mk("x")
   223          return g() -- This isn't a tail call
   224      end
   225      f()
   226      print(s)
   227      --> =start+x+y-y-x
   228      -- x is closed after y, showing that g() wasn't a tail-call.
   229  end