Merge pull request #23 from walterschell/feature/5.4.5

Feature/5.4.5
This commit is contained in:
Walter Schell 2023-04-30 11:00:31 -04:00 committed by GitHub
commit b4d597e122
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
124 changed files with 1803 additions and 1170 deletions

View File

@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.1) cmake_minimum_required(VERSION 3.1)
project(lua LANGUAGES C VERSION 5.4.4) project(lua LANGUAGES C VERSION 5.4.5)
option(LUA_SUPPORT_DL "Support dynamic loading of compiled modules" OFF) option(LUA_SUPPORT_DL "Support dynamic loading of compiled modules" OFF)
option(LUA_BUILD_AS_CXX "Build lua as C++" OFF) option(LUA_BUILD_AS_CXX "Build lua as C++" OFF)
@ -25,8 +25,8 @@ else()
option(LUA_BUILD_COMPILER "Build luac compiler" ON) option(LUA_BUILD_COMPILER "Build luac compiler" ON)
endif() endif()
add_subdirectory(lua-5.4.4) add_subdirectory(lua-5.4.5)
if(LUA_ENABLE_TESTING) if(LUA_ENABLE_TESTING)
add_test(NAME lua-testsuite COMMAND lua -e "_U=true" all.lua WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lua-5.4.4-tests) add_test(NAME lua-testsuite COMMAND lua -e "_U=true" all.lua WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lua-5.4.5-tests)
endif() endif()

View File

@ -1,5 +1,5 @@
# Lua # Lua
CMake based build of Lua 5.4.4 CMake based build of Lua 5.4.5
| Build as C | Build as C++ | | Build as C | Build as C++ |
| --: | --: | | --: | --: |
| ![Build Linux](https://github.com/walterschell/Lua/actions/workflows/build-linux.yml/badge.svg?branch=master) | ![Build Linux as C++](https://github.com/walterschell/Lua/actions/workflows/build-linux-cxx.yml/badge.svg?branch=master) | | ![Build Linux](https://github.com/walterschell/Lua/actions/workflows/build-linux.yml/badge.svg?branch=master) | ![Build Linux as C++](https://github.com/walterschell/Lua/actions/workflows/build-linux-cxx.yml/badge.svg?branch=master) |
@ -13,3 +13,6 @@ add_subdirectory(lua)
... ...
target_link_libraries(<YOURTARGET> lua_static) target_link_libraries(<YOURTARGET> lua_static)
``` ```
# Important Note:
Depending on your use case, Lua v5.4.5 is API and ABI incompatible with v5.4.1-v5.4.4. A second parameter has been added to `lua_resetthread()`. See https://marc.info/?t=168182290600001&r=1&w=2 for more details.

View File

@ -163,6 +163,7 @@ f()
dofile('db.lua') dofile('db.lua')
assert(dofile('calls.lua') == deep and deep) assert(dofile('calls.lua') == deep and deep)
_G.deep = nil
olddofile('strings.lua') olddofile('strings.lua')
olddofile('literals.lua') olddofile('literals.lua')
dofile('tpack.lua') dofile('tpack.lua')

View File

@ -14,7 +14,7 @@ local pack = table.pack
-- standard error message for memory errors -- standard error message for memory errors
local MEMERRMSG = "not enough memory" local MEMERRMSG = "not enough memory"
function tcheck (t1, t2) local function tcheck (t1, t2)
assert(t1.n == (t2.n or #t2) + 1) assert(t1.n == (t2.n or #t2) + 1)
for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end
end end
@ -28,7 +28,7 @@ end
print('testing C API') print('testing C API')
a = T.testC("pushvalue R; return 1") local a = T.testC("pushvalue R; return 1")
assert(a == debug.getregistry()) assert(a == debug.getregistry())
@ -43,10 +43,10 @@ a = T.d2s(12458954321123.0)
assert(a == string.pack("d", 12458954321123.0)) assert(a == string.pack("d", 12458954321123.0))
assert(T.s2d(a) == 12458954321123.0) assert(T.s2d(a) == 12458954321123.0)
a,b,c = T.testC("pushnum 1; pushnum 2; pushnum 3; return 2") local a,b,c = T.testC("pushnum 1; pushnum 2; pushnum 3; return 2")
assert(a == 2 and b == 3 and not c) assert(a == 2 and b == 3 and not c)
f = T.makeCfunc("pushnum 1; pushnum 2; pushnum 3; return 2") local f = T.makeCfunc("pushnum 1; pushnum 2; pushnum 3; return 2")
a,b,c = f() a,b,c = f()
assert(a == 2 and b == 3 and not c) assert(a == 2 and b == 3 and not c)
@ -61,7 +61,7 @@ assert(a==false and b==true and c==false)
a,b,c = T.testC("gettop; return 2", 10, 20, 30, 40) a,b,c = T.testC("gettop; return 2", 10, 20, 30, 40)
assert(a == 40 and b == 5 and not c) assert(a == 40 and b == 5 and not c)
t = pack(T.testC("settop 5; return *", 2, 3)) local t = pack(T.testC("settop 5; return *", 2, 3))
tcheck(t, {n=4,2,3}) tcheck(t, {n=4,2,3})
t = pack(T.testC("settop 0; settop 15; return 10", 3, 1, 23)) t = pack(T.testC("settop 0; settop 15; return 10", 3, 1, 23))
@ -166,16 +166,17 @@ end
-- testing globals -- testing globals
_G.a = 14; _G.b = "a31" _G.AA = 14; _G.BB = "a31"
local a = {T.testC[[ local a = {T.testC[[
getglobal a; getglobal AA;
getglobal b; getglobal BB;
getglobal b; getglobal BB;
setglobal a; setglobal AA;
return * return *
]]} ]]}
assert(a[2] == 14 and a[3] == "a31" and a[4] == nil and _G.a == "a31") assert(a[2] == 14 and a[3] == "a31" and a[4] == nil and _G.AA == "a31")
_G.AA, _G.BB = nil
-- testing arith -- testing arith
assert(T.testC("pushnum 10; pushnum 20; arith /; return 1") == 0.5) assert(T.testC("pushnum 10; pushnum 20; arith /; return 1") == 0.5)
@ -199,13 +200,14 @@ a,b,c = T.testC([[pushnum 1;
pushstring 10; arith _; pushstring 10; arith _;
pushstring 5; return 3]]) pushstring 5; return 3]])
assert(a == 1 and b == -10 and c == "5") assert(a == 1 and b == -10 and c == "5")
mt = {__add = function (a,b) return setmetatable({a[1] + b[1]}, mt) end, local mt = {
__add = function (a,b) return setmetatable({a[1] + b[1]}, mt) end,
__mod = function (a,b) return setmetatable({a[1] % b[1]}, mt) end, __mod = function (a,b) return setmetatable({a[1] % b[1]}, mt) end,
__unm = function (a) return setmetatable({a[1]* 2}, mt) end} __unm = function (a) return setmetatable({a[1]* 2}, mt) end}
a,b,c = setmetatable({4}, mt), a,b,c = setmetatable({4}, mt),
setmetatable({8}, mt), setmetatable({8}, mt),
setmetatable({-3}, mt) setmetatable({-3}, mt)
x,y,z = T.testC("arith +; return 2", 10, a, b) local x,y,z = T.testC("arith +; return 2", 10, a, b)
assert(x == 10 and y[1] == 12 and z == nil) assert(x == 10 and y[1] == 12 and z == nil)
assert(T.testC("arith %; return 1", a, c)[1] == 4%-3) assert(T.testC("arith %; return 1", a, c)[1] == 4%-3)
assert(T.testC("arith _; arith +; arith %; return 1", b, a, c)[1] == assert(T.testC("arith _; arith +; arith %; return 1", b, a, c)[1] ==
@ -312,9 +314,9 @@ assert(T.testC("concat 1; return 1", "xuxu") == "xuxu")
-- testing lua_is -- testing lua_is
function B(x) return x and 1 or 0 end local function B (x) return x and 1 or 0 end
function count (x, n) local function count (x, n)
n = n or 2 n = n or 2
local prog = [[ local prog = [[
isnumber %d; isnumber %d;
@ -345,7 +347,7 @@ assert(count(nil, 15) == 100)
-- testing lua_to... -- testing lua_to...
function to (s, x, n) local function to (s, x, n)
n = n or 2 n = n or 2
return T.testC(string.format("%s %d; return 1", s, n), x) return T.testC(string.format("%s %d; return 1", s, n), x)
end end
@ -486,11 +488,12 @@ a = T.testC([[
pushvalue 3; insert -2; pcall 1 1 0; pushvalue 3; insert -2; pcall 1 1 0;
pcall 0 0 0; pcall 0 0 0;
return 1 return 1
]], "x=150", function (a) assert(a==nil); return 3 end) ]], "XX=150", function (a) assert(a==nil); return 3 end)
assert(type(a) == 'string' and x == 150) assert(type(a) == 'string' and XX == 150)
_G.XX = nil
function check3(p, ...) local function check3(p, ...)
local arg = {...} local arg = {...}
assert(#arg == 3) assert(#arg == 3)
assert(string.find(arg[3], p)) assert(string.find(arg[3], p))
@ -500,7 +503,7 @@ check3("%.", T.testC("loadfile 2; return *", "."))
check3("xxxx", T.testC("loadfile 2; return *", "xxxx")) check3("xxxx", T.testC("loadfile 2; return *", "xxxx"))
-- test errors in non protected threads -- test errors in non protected threads
function checkerrnopro (code, msg) local function checkerrnopro (code, msg)
local th = coroutine.create(function () end) -- create new thread local th = coroutine.create(function () end) -- create new thread
local stt, err = pcall(T.testC, th, code) -- run code there local stt, err = pcall(T.testC, th, code) -- run code there
assert(not stt and string.find(err, msg)) assert(not stt and string.find(err, msg))
@ -510,8 +513,9 @@ if not _soft then
collectgarbage("stop") -- avoid __gc with full stack collectgarbage("stop") -- avoid __gc with full stack
checkerrnopro("pushnum 3; call 0 0", "attempt to call") checkerrnopro("pushnum 3; call 0 0", "attempt to call")
print"testing stack overflow in unprotected thread" print"testing stack overflow in unprotected thread"
function f () f() end function F () F() end
checkerrnopro("getglobal 'f'; call 0 0;", "stack overflow") checkerrnopro("getglobal 'F'; call 0 0;", "stack overflow")
F = nil
collectgarbage("restart") collectgarbage("restart")
end end
print"+" print"+"
@ -588,7 +592,7 @@ assert(a[a] == "x")
b = setmetatable({p = a}, {}) b = setmetatable({p = a}, {})
getmetatable(b).__index = function (t, i) return t.p[i] end getmetatable(b).__index = function (t, i) return t.p[i] end
k, x = T.testC("gettable 3, return 2", 4, b, 20, 35, "x") local k, x = T.testC("gettable 3, return 2", 4, b, 20, 35, "x")
assert(x == 15 and k == 35) assert(x == 15 and k == 35)
k = T.testC("getfield 2 y, return 1", b) k = T.testC("getfield 2 y, return 1", b)
assert(k == 12) assert(k == 12)
@ -748,8 +752,8 @@ local i = T.ref{}
T.unref(i) T.unref(i)
assert(T.ref{} == i) assert(T.ref{} == i)
Arr = {} local Arr = {}
Lim = 100 local Lim = 100
for i=1,Lim do -- lock many objects for i=1,Lim do -- lock many objects
Arr[i] = T.ref({}) Arr[i] = T.ref({})
end end
@ -761,7 +765,7 @@ for i=1,Lim do -- unlock all them
T.unref(Arr[i]) T.unref(Arr[i])
end end
function printlocks () local function printlocks ()
local f = T.makeCfunc("gettable R; return 1") local f = T.makeCfunc("gettable R; return 1")
local n = f("n") local n = f("n")
print("n", n) print("n", n)
@ -793,8 +797,8 @@ assert(type(T.getref(a)) == 'table')
-- colect in cl the `val' of all collected userdata -- colect in cl the `val' of all collected userdata
tt = {} local tt = {}
cl = {n=0} local cl = {n=0}
A = nil; B = nil A = nil; B = nil
local F local F
F = function (x) F = function (x)
@ -817,6 +821,7 @@ F = function (x)
end end
tt.__gc = F tt.__gc = F
-- test whether udate collection frees memory in the right time -- test whether udate collection frees memory in the right time
do do
collectgarbage(); collectgarbage();
@ -853,9 +858,9 @@ end
collectgarbage("stop") collectgarbage("stop")
-- create 3 userdatas with tag `tt' -- create 3 userdatas with tag `tt'
a = T.newuserdata(0); debug.setmetatable(a, tt); na = T.udataval(a) a = T.newuserdata(0); debug.setmetatable(a, tt); local na = T.udataval(a)
b = T.newuserdata(0); debug.setmetatable(b, tt); nb = T.udataval(b) b = T.newuserdata(0); debug.setmetatable(b, tt); local nb = T.udataval(b)
c = T.newuserdata(0); debug.setmetatable(c, tt); nc = T.udataval(c) c = T.newuserdata(0); debug.setmetatable(c, tt); local nc = T.udataval(c)
-- create userdata without meta table -- create userdata without meta table
x = T.newuserdata(4) x = T.newuserdata(4)
@ -866,9 +871,9 @@ checkerr("FILE%* expected, got userdata", io.input, x)
assert(debug.getmetatable(x) == nil and debug.getmetatable(y) == nil) assert(debug.getmetatable(x) == nil and debug.getmetatable(y) == nil)
d=T.ref(a); local d = T.ref(a);
e=T.ref(b); local e = T.ref(b);
f=T.ref(c); local f = T.ref(c);
t = {T.getref(d), T.getref(e), T.getref(f)} t = {T.getref(d), T.getref(e), T.getref(f)}
assert(t[1] == a and t[2] == b and t[3] == c) assert(t[1] == a and t[2] == b and t[3] == c)
@ -888,7 +893,7 @@ tt=nil -- frees tt for GC
A = nil A = nil
b = nil b = nil
T.unref(d); T.unref(d);
n5 = T.newuserdata(0) local n5 = T.newuserdata(0)
debug.setmetatable(n5, {__gc=F}) debug.setmetatable(n5, {__gc=F})
n5 = T.udataval(n5) n5 = T.udataval(n5)
collectgarbage() collectgarbage()
@ -959,11 +964,11 @@ print'+'
-- testing changing hooks during hooks -- testing changing hooks during hooks
_G.t = {} _G.TT = {}
T.sethook([[ T.sethook([[
# set a line hook after 3 count hooks # set a line hook after 3 count hooks
sethook 4 0 ' sethook 4 0 '
getglobal t; getglobal TT;
pushvalue -3; append -2 pushvalue -3; append -2
pushvalue -2; append -2 pushvalue -2; append -2
']], "c", 3) ']], "c", 3)
@ -973,12 +978,13 @@ a = 1 -- count hook (set line hook)
a = 1 -- line hook a = 1 -- line hook
a = 1 -- line hook a = 1 -- line hook
debug.sethook() debug.sethook()
t = _G.t local t = _G.TT
assert(t[1] == "line") assert(t[1] == "line")
line = t[2] local line = t[2]
assert(t[3] == "line" and t[4] == line + 1) assert(t[3] == "line" and t[4] == line + 1)
assert(t[5] == "line" and t[6] == line + 2) assert(t[5] == "line" and t[6] == line + 2)
assert(t[7] == nil) assert(t[7] == nil)
_G.TT = nil
------------------------------------------------------------------------- -------------------------------------------------------------------------
@ -1003,6 +1009,7 @@ do -- testing errors during GC
collectgarbage("restart") collectgarbage("restart")
warn("@on") warn("@on")
end end
_G.A = nil
------------------------------------------------------------------------- -------------------------------------------------------------------------
-- test for userdata vals -- test for userdata vals
do do
@ -1032,8 +1039,8 @@ assert(a == 'alo' and b == '3')
T.doremote(L1, "_ERRORMESSAGE = nil") T.doremote(L1, "_ERRORMESSAGE = nil")
-- error: `sin' is not defined -- error: `sin' is not defined
a, _, b = T.doremote(L1, "return sin(1)") a, b, c = T.doremote(L1, "return sin(1)")
assert(a == nil and b == 2) -- 2 == run-time error assert(a == nil and c == 2) -- 2 == run-time error
-- error: syntax error -- error: syntax error
a, b, c = T.doremote(L1, "return a+") a, b, c = T.doremote(L1, "return a+")
@ -1204,7 +1211,7 @@ T.alloccount() -- remove limit
-- o that we get memory errors in all allocations of a given -- o that we get memory errors in all allocations of a given
-- task, until there is enough memory to complete the task without -- task, until there is enough memory to complete the task without
-- errors. -- errors.
function testbytes (s, f) local function testbytes (s, f)
collectgarbage() collectgarbage()
local M = T.totalmem() local M = T.totalmem()
local oldM = M local oldM = M
@ -1229,7 +1236,7 @@ end
-- task, until there is enough allocations to complete the task without -- task, until there is enough allocations to complete the task without
-- errors. -- errors.
function testalloc (s, f) local function testalloc (s, f)
collectgarbage() collectgarbage()
local M = 0 local M = 0
local a,b = nil local a,b = nil
@ -1296,12 +1303,12 @@ end)
-- testing threads -- testing threads
-- get main thread from registry (at index LUA_RIDX_MAINTHREAD == 1) -- get main thread from registry (at index LUA_RIDX_MAINTHREAD == 1)
mt = T.testC("rawgeti R 1; return 1") local mt = T.testC("rawgeti R 1; return 1")
assert(type(mt) == "thread" and coroutine.running() == mt) assert(type(mt) == "thread" and coroutine.running() == mt)
function expand (n,s) local function expand (n,s)
if n==0 then return "" end if n==0 then return "" end
local e = string.rep("=", n) local e = string.rep("=", n)
return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n", return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n",
@ -1311,9 +1318,10 @@ end
G=0; collectgarbage(); a =collectgarbage("count") G=0; collectgarbage(); a =collectgarbage("count")
load(expand(20,"G=G+1"))() load(expand(20,"G=G+1"))()
assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1) assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1)
G = nil
testamem("running code on new thread", function () testamem("running code on new thread", function ()
return T.doonnewstack("x=1") == 0 -- try to create thread return T.doonnewstack("local x=1") == 0 -- try to create thread
end) end)
@ -1327,13 +1335,13 @@ end)
local testprog = [[ local testprog = [[
local function foo () return end local function foo () return end
local t = {"x"} local t = {"x"}
a = "aaa" AA = "aaa"
for i = 1, #t do a=a..t[i] end for i = 1, #t do AA = AA .. t[i] end
return true return true
]] ]]
-- testing memory x dofile -- testing memory x dofile
_G.a = nil _G.AA = nil
local t =os.tmpname() local t =os.tmpname()
local f = assert(io.open(t, "w")) local f = assert(io.open(t, "w"))
f:write(testprog) f:write(testprog)
@ -1343,7 +1351,7 @@ testamem("dofile", function ()
return a and a() return a and a()
end) end)
assert(os.remove(t)) assert(os.remove(t))
assert(_G.a == "aaax") assert(_G.AA == "aaax")
-- other generic tests -- other generic tests
@ -1360,6 +1368,8 @@ testamem("dump/undump", function ()
return a and a() return a and a()
end) end)
_G.AA = nil
local t = os.tmpname() local t = os.tmpname()
testamem("file creation", function () testamem("file creation", function ()
local f = assert(io.open(t, 'w')) local f = assert(io.open(t, 'w'))
@ -1381,7 +1391,7 @@ testamem("constructors", function ()
end) end)
local a = 1 local a = 1
close = nil local close = nil
testamem("closure creation", function () testamem("closure creation", function ()
function close (b) function close (b)
return function (x) return b + x end return function (x) return b + x end

View File

@ -85,7 +85,7 @@ local DIR = "libs" .. dirsep
-- prepend DIR to a name and correct directory separators -- prepend DIR to a name and correct directory separators
local function D (x) local function D (x)
x = string.gsub(x, "/", dirsep) local x = string.gsub(x, "/", dirsep)
return DIR .. x return DIR .. x
end end
@ -106,7 +106,7 @@ local function createfiles (files, preextras, posextras)
end end
end end
function removefiles (files) local function removefiles (files)
for n in pairs(files) do for n in pairs(files) do
os.remove(D(n)) os.remove(D(n))
end end
@ -154,10 +154,9 @@ local try = function (p, n, r, ext)
assert(ext == x) assert(ext == x)
end end
a = require"names" local a = require"names"
assert(a[1] == "names" and a[2] == D"names.lua") assert(a[1] == "names" and a[2] == D"names.lua")
_G.a = nil
local st, msg = pcall(require, "err") local st, msg = pcall(require, "err")
assert(not st and string.find(msg, "arithmetic") and B == 15) assert(not st and string.find(msg, "arithmetic") and B == 15)
st, msg = pcall(require, "synerr") st, msg = pcall(require, "synerr")
@ -191,6 +190,7 @@ try("X", "XXxX", AA, "libs/XXxX")
removefiles(files) removefiles(files)
NAME, REQUIRED, AA, B = nil
-- testing require of sub-packages -- testing require of sub-packages
@ -223,7 +223,7 @@ assert(require"P1" == m and m.AA == 10)
removefiles(files) removefiles(files)
AA = nil
package.path = "" package.path = ""
assert(not pcall(require, "file_does_not_exist")) assert(not pcall(require, "file_does_not_exist"))
@ -305,6 +305,7 @@ else
assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1") assert(_ENV.x == "lib1.sub" and _ENV.y == DC"lib1")
assert(string.find(ext, "libs/lib1", 1, true)) assert(string.find(ext, "libs/lib1", 1, true))
assert(fs.id(45) == 45) assert(fs.id(45) == 45)
_ENV.x, _ENV.y = nil
end end
_ENV = _G _ENV = _G
@ -338,10 +339,10 @@ print("testing assignments, logical operators, and constructors")
local res, res2 = 27 local res, res2 = 27
a, b = 1, 2+3 local a, b = 1, 2+3
assert(a==1 and b==5) assert(a==1 and b==5)
a={} a={}
function f() return 10, 11, 12 end local function f() return 10, 11, 12 end
a.x, b, a[1] = 1, 2, f() a.x, b, a[1] = 1, 2, f()
assert(a.x==1 and b==2 and a[1]==10) assert(a.x==1 and b==2 and a[1]==10)
a[f()], b, a[f()+3] = f(), a, 'x' a[f()], b, a[f()+3] = f(), a, 'x'
@ -353,15 +354,15 @@ do
local a,b,c local a,b,c
a,b = 0, f(1) a,b = 0, f(1)
assert(a == 0 and b == 1) assert(a == 0 and b == 1)
A,b = 0, f(1) a,b = 0, f(1)
assert(A == 0 and b == 1) assert(a == 0 and b == 1)
a,b,c = 0,5,f(4) a,b,c = 0,5,f(4)
assert(a==0 and b==5 and c==1) assert(a==0 and b==5 and c==1)
a,b,c = 0,5,f(0) a,b,c = 0,5,f(0)
assert(a==0 and b==5 and c==nil) assert(a==0 and b==5 and c==nil)
end end
a, b, c, d = 1 and nil, 1 or nil, (1 and (nil or 1)), 6 local a, b, c, d = 1 and nil, 1 or nil, (1 and (nil or 1)), 6
assert(not a and b and c and d==6) assert(not a and b and c and d==6)
d = 20 d = 20
@ -419,6 +420,7 @@ assert(not pcall(function () local a = {[nil] = 10} end))
assert(a[nil] == undef) assert(a[nil] == undef)
a = nil a = nil
local a, b, c
a = {10,9,8,7,6,5,4,3,2; [-3]='a', [f]=print, a='a', b='ab'} a = {10,9,8,7,6,5,4,3,2; [-3]='a', [f]=print, a='a', b='ab'}
a, a.x, a.y = a, a[-3] a, a.x, a.y = a, a[-3]
assert(a[1]==10 and a[-3]==a.a and a[f]==print and a.x=='a' and not a.y) assert(a[1]==10 and a[-3]==a.a and a[f]==print and a.x=='a' and not a.y)
@ -434,6 +436,16 @@ a.aVeryLongName012345678901234567890123456789012345678901234567890123456789 ==
10) 10)
do
-- _ENV constant
local function foo ()
local _ENV <const> = 11
X = "hi"
end
local st, msg = pcall(foo)
assert(not st and string.find(msg, "number"))
end
-- test of large float/integer indices -- test of large float/integer indices
@ -445,7 +457,7 @@ while maxint ~= (maxint + 0.0) or (maxint - 1) ~= (maxint - 1.0) do
maxint = maxint // 2 maxint = maxint // 2
end end
maxintF = maxint + 0.0 -- float version local maxintF = maxint + 0.0 -- float version
assert(maxintF == maxint and math.type(maxintF) == "float" and assert(maxintF == maxint and math.type(maxintF) == "float" and
maxintF >= 2.0^14) maxintF >= 2.0^14)

View File

@ -32,7 +32,7 @@ setmetatable(env, {
}) })
X = nil X = nil
co = coroutine.wrap(f) local co = coroutine.wrap(f)
assert(co() == 's') assert(co() == 's')
assert(co() == 'g') assert(co() == 'g')
assert(co() == 'g') assert(co() == 'g')

View File

@ -38,6 +38,18 @@ d = d << 32
assert(a | b ~ c & d == 0xF4000000 << 32) assert(a | b ~ c & d == 0xF4000000 << 32)
assert(~~a == a and ~a == -1 ~ a and -d == ~d + 1) assert(~~a == a and ~a == -1 ~ a and -d == ~d + 1)
do -- constant folding
local code = string.format("return -1 >> %d", math.maxinteger)
assert(load(code)() == 0)
local code = string.format("return -1 >> %d", math.mininteger)
assert(load(code)() == 0)
local code = string.format("return -1 << %d", math.maxinteger)
assert(load(code)() == 0)
local code = string.format("return -1 << %d", math.mininteger)
assert(load(code)() == 0)
end
assert(-1 >> 1 == (1 << (numbits - 1)) - 1 and 1 << 31 == 0x80000000) assert(-1 >> 1 == (1 << (numbits - 1)) - 1 and 1 << 31 == 0x80000000)
assert(-1 >> (numbits - 1) == 1) assert(-1 >> (numbits - 1) == 1)
assert(-1 >> numbits == 0 and assert(-1 >> numbits == 0 and

View File

@ -16,7 +16,7 @@ assert(type(nil) == 'nil'
and type(type) == 'function') and type(type) == 'function')
assert(type(assert) == type(print)) assert(type(assert) == type(print))
function f (x) return a:x (x) end local function f (x) return a:x (x) end
assert(type(f) == 'function') assert(type(f) == 'function')
assert(not pcall(type)) assert(not pcall(type))
@ -33,10 +33,11 @@ do
assert(fact(5) == 120) assert(fact(5) == 120)
end end
assert(fact == false) assert(fact == false)
fact = nil
-- testing declarations -- testing declarations
a = {i = 10} local a = {i = 10}
self = 20 local self = 20
function a:x (x) return x+self.i end function a:x (x) return x+self.i end
function a.y (x) return x+self end function a.y (x) return x+self end
@ -72,6 +73,8 @@ f(1,2, -- this one too
3,4) 3,4)
assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == 'a') assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == 'a')
t = nil -- delete 't'
function fat(x) function fat(x)
if x <= 1 then return 1 if x <= 1 then return 1
else return x*load("return fat(" .. x-1 .. ")", "")() else return x*load("return fat(" .. x-1 .. ")", "")()
@ -80,26 +83,29 @@ end
assert(load "load 'assert(fat(6)==720)' () ")() assert(load "load 'assert(fat(6)==720)' () ")()
a = load('return fat(5), 3') a = load('return fat(5), 3')
a,b = a() local a,b = a()
assert(a == 120 and b == 3) assert(a == 120 and b == 3)
fat = nil
print('+') print('+')
function err_on_n (n) local function err_on_n (n)
if n==0 then error(); exit(1); if n==0 then error(); exit(1);
else err_on_n (n-1); exit(1); else err_on_n (n-1); exit(1);
end end
end end
do do
function dummy (n) local function dummy (n)
if n > 0 then if n > 0 then
assert(not pcall(err_on_n, n)) assert(not pcall(err_on_n, n))
dummy(n-1) dummy(n-1)
end end
end end
dummy(10)
end end
dummy(10) _G.deep = nil -- "declaration" (used by 'all.lua')
function deep (n) function deep (n)
if n>0 then deep(n-1) end if n>0 then deep(n-1) end
@ -151,6 +157,16 @@ do -- tail calls x varargs
end end
do -- C-stack overflow while handling C-stack overflow
local function loop ()
assert(pcall(loop))
end
local err, msg = xpcall(loop, loop)
assert(not err and string.find(msg, "error"))
end
do -- tail calls x chain of __call do -- tail calls x chain of __call
local n = 10000 -- depth local n = 10000 -- depth
@ -199,7 +215,7 @@ assert(a == 23 and (function (x) return x*2 end)(20) == 40)
-- testing closures -- testing closures
-- fixed-point operator -- fixed-point operator
Z = function (le) local Z = function (le)
local function a (f) local function a (f)
return le(function (x) return f(f)(x) end) return le(function (x) return f(f)(x) end)
end end
@ -209,14 +225,14 @@ Z = function (le)
-- non-recursive factorial -- non-recursive factorial
F = function (f) local F = function (f)
return function (n) return function (n)
if n == 0 then return 1 if n == 0 then return 1
else return n*f(n-1) end else return n*f(n-1) end
end end
end end
fat = Z(F) local fat = Z(F)
assert(fat(0) == 1 and fat(4) == 24 and Z(F)(5)==5*Z(F)(4)) assert(fat(0) == 1 and fat(4) == 24 and Z(F)(5)==5*Z(F)(4))
@ -227,22 +243,21 @@ local function g (z)
return f(z,z+1,z+2,z+3) return f(z,z+1,z+2,z+3)
end end
f = g(10) local f = g(10)
assert(f(9, 16) == 10+11+12+13+10+9+16+10) assert(f(9, 16) == 10+11+12+13+10+9+16+10)
Z, F, f = nil
print('+') print('+')
-- testing multiple returns -- testing multiple returns
function unlpack (t, i) local function unlpack (t, i)
i = i or 1 i = i or 1
if (i <= #t) then if (i <= #t) then
return t[i], unlpack(t, i+1) return t[i], unlpack(t, i+1)
end end
end end
function equaltab (t1, t2) local function equaltab (t1, t2)
assert(#t1 == #t2) assert(#t1 == #t2)
for i = 1, #t1 do for i = 1, #t1 do
assert(t1[i] == t2[i]) assert(t1[i] == t2[i])
@ -251,8 +266,8 @@ end
local pack = function (...) return (table.pack(...)) end local pack = function (...) return (table.pack(...)) end
function f() return 1,2,30,4 end local function f() return 1,2,30,4 end
function ret2 (a,b) return a,b end local function ret2 (a,b) return a,b end
local a,b,c,d = unlpack{1,2,3} local a,b,c,d = unlpack{1,2,3}
assert(a==1 and b==2 and c==3 and d==nil) assert(a==1 and b==2 and c==3 and d==nil)
@ -281,7 +296,7 @@ table.sort({10,9,8,4,19,23,0,0}, function (a,b) return a<b end, "extra arg")
local x = "-- a comment\0\0\0\n x = 10 + \n23; \ local x = "-- a comment\0\0\0\n x = 10 + \n23; \
local a = function () x = 'hi' end; \ local a = function () x = 'hi' end; \
return '\0'" return '\0'"
function read1 (x) local function read1 (x)
local i = 0 local i = 0
return function () return function ()
collectgarbage() collectgarbage()
@ -290,7 +305,7 @@ function read1 (x)
end end
end end
function cannotload (msg, a,b) local function cannotload (msg, a,b)
assert(not a and string.find(b, msg)) assert(not a and string.find(b, msg))
end end
@ -327,11 +342,26 @@ do -- another bug (in 5.4.0)
end end
do -- another bug (since 5.2)
-- corrupted binary dump: list of upvalue names is larger than number
-- of upvalues, overflowing the array of upvalues.
local code =
"\x1b\x4c\x75\x61\x54\x00\x19\x93\x0d\x0a\x1a\x0a\x04\x08\x08\x78\x56\z
\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x28\x77\x40\x00\x86\x40\z
\x74\x65\x6d\x70\x81\x81\x01\x00\x02\x82\x48\x00\x02\x00\xc7\x00\x01\z
\x00\x80\x80\x80\x82\x00\x00\x80\x81\x82\x78\x80\x82\x81\x86\x40\x74\z
\x65\x6d\x70"
assert(load(code)) -- segfaults in previous versions
end
x = string.dump(load("x = 1; return x")) x = string.dump(load("x = 1; return x"))
a = assert(load(read1(x), nil, "b")) a = assert(load(read1(x), nil, "b"))
assert(a() == 1 and _G.x == 1) assert(a() == 1 and _G.x == 1)
cannotload("attempt to load a binary chunk", load(read1(x), nil, "t")) cannotload("attempt to load a binary chunk", load(read1(x), nil, "t"))
cannotload("attempt to load a binary chunk", load(x, nil, "t")) cannotload("attempt to load a binary chunk", load(x, nil, "t"))
_G.x = nil
assert(not pcall(string.dump, print)) -- no dump of C functions assert(not pcall(string.dump, print)) -- no dump of C functions
@ -356,7 +386,7 @@ debug.setupvalue(x, 2, _G)
assert(x() == 123) assert(x() == 123)
assert(assert(load("return XX + ...", nil, nil, {XX = 13}))(4) == 17) assert(assert(load("return XX + ...", nil, nil, {XX = 13}))(4) == 17)
XX = nil
-- test generic load with nested functions -- test generic load with nested functions
x = [[ x = [[

View File

@ -4,7 +4,7 @@
print "testing closures" print "testing closures"
local A,B = 0,{g=10} local A,B = 0,{g=10}
function f(x) local function f(x)
local a = {} local a = {}
for i=1,1000 do for i=1,1000 do
local y = 0 local y = 0
@ -89,6 +89,7 @@ assert(r == "a" and s == "b")
-- testing closures with 'for' control variable x break -- testing closures with 'for' control variable x break
local f
for i=1,3 do for i=1,3 do
f = function () return i end f = function () return i end
break break
@ -139,7 +140,7 @@ assert(b('get') == 'xuxu')
b('set', 10); assert(b('get') == 14) b('set', 10); assert(b('get') == 14)
local w local y, w
-- testing multi-level closure -- testing multi-level closure
function f(x) function f(x)
return function (y) return function (y)
@ -230,6 +231,7 @@ t()
-- test for debug manipulation of upvalues -- test for debug manipulation of upvalues
local debug = require'debug' local debug = require'debug'
local foo1, foo2, foo3
do do
local a , b, c = 3, 5, 7 local a , b, c = 3, 5, 7
foo1 = function () return a+b end; foo1 = function () return a+b end;

View File

@ -86,7 +86,7 @@ checkKlist(foo, {1, 1.0, 2, 2.0, 0, 0.0})
-- testing opcodes -- testing opcodes
-- check that 'f' opcodes match '...' -- check that 'f' opcodes match '...'
function check (f, ...) local function check (f, ...)
local arg = {...} local arg = {...}
local c = T.listcode(f) local c = T.listcode(f)
for i=1, #arg do for i=1, #arg do
@ -99,7 +99,7 @@ end
-- check that 'f' opcodes match '...' and that 'f(p) == r'. -- check that 'f' opcodes match '...' and that 'f(p) == r'.
function checkR (f, p, r, ...) local function checkR (f, p, r, ...)
local r1 = f(p) local r1 = f(p)
assert(r == r1 and math.type(r) == math.type(r1)) assert(r == r1 and math.type(r) == math.type(r1))
check(f, ...) check(f, ...)
@ -107,7 +107,7 @@ end
-- check that 'a' and 'b' has the same opcodes -- check that 'a' and 'b' has the same opcodes
function checkequal (a, b) local function checkequal (a, b)
a = T.listcode(a) a = T.listcode(a)
b = T.listcode(b) b = T.listcode(b)
assert(#a == #b) assert(#a == #b)

View File

@ -11,6 +11,7 @@ local function checkload (s, msg)
end end
-- testing semicollons -- testing semicollons
local a
do ;;; end do ;;; end
; do ; a = 3; assert(a == 3) end; ; do ; a = 3; assert(a == 3) end;
; ;
@ -49,10 +50,10 @@ assert((((nil and true) or false) and true) == false)
local a,b = 1,nil; local a,b = 1,nil;
assert(-(1 or 2) == -1 and (1 and 2)+(-1.25 or -4) == 0.75); assert(-(1 or 2) == -1 and (1 and 2)+(-1.25 or -4) == 0.75);
x = ((b or a)+1 == 2 and (10 or a)+1 == 11); assert(x); local x = ((b or a)+1 == 2 and (10 or a)+1 == 11); assert(x);
x = (((2<3) or 1) == true and (2<3 and 4) == 4); assert(x); x = (((2<3) or 1) == true and (2<3 and 4) == 4); assert(x);
x,y=1,2; local x, y = 1, 2;
assert((x>y) and x or y == 2); assert((x>y) and x or y == 2);
x,y=2,1; x,y=2,1;
assert((x>y) and x or y == 2); assert((x>y) and x or y == 2);
@ -77,13 +78,13 @@ do -- testing operators with diffent kinds of constants
local gab = f(o1, o2) local gab = f(o1, o2)
_ENV.XX = o1 _ENV.XX = o1
code = string.format("return XX %s %s", op, o2) local code = string.format("return XX %s %s", op, o2)
res = assert(load(code))() local res = assert(load(code))()
assert(res == gab) assert(res == gab)
_ENV.XX = o2 _ENV.XX = o2
local code = string.format("return (%s) %s XX", o1, op) code = string.format("return (%s) %s XX", o1, op)
local res = assert(load(code))() res = assert(load(code))()
assert(res == gab) assert(res == gab)
code = string.format("return (%s) %s %s", o1, op, o2) code = string.format("return (%s) %s %s", o1, op, o2)
@ -92,6 +93,7 @@ do -- testing operators with diffent kinds of constants
end end
end end
end end
_ENV.XX = nil
end end
@ -100,10 +102,35 @@ repeat until 1; repeat until true;
while false do end; while nil do end; while false do end; while nil do end;
do -- test old bug (first name could not be an `upvalue') do -- test old bug (first name could not be an `upvalue')
local a; function f(x) x={a=1}; x={x=1}; x={G=1} end local a; local function f(x) x={a=1}; x={x=1}; x={G=1} end
end end
function f (i)
do -- bug since 5.4.0
-- create code with a table using more than 256 constants
local code = {"local x = {"}
for i = 1, 257 do
code[#code + 1] = i .. ".1,"
end
code[#code + 1] = "};"
code = table.concat(code)
-- add "ret" to the end of that code and checks that
-- it produces the expected value "val"
local function check (ret, val)
local code = code .. ret
code = load(code)
assert(code() == val)
end
check("return (1 ~ (2 or 3))", 1 ~ 2)
check("return (1 | (2 or 3))", 1 | 2)
check("return (1 + (2 or 3))", 1 + 2)
check("return (1 << (2 or 3))", 1 << 2)
end
local function f (i)
if type(i) ~= 'number' then return i,'jojo'; end; if type(i) ~= 'number' then return i,'jojo'; end;
if i > 0 then return i, f(i-1); end; if i > 0 then return i, f(i-1); end;
end end
@ -129,10 +156,10 @@ end
assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == nil) assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == nil)
for i=1,1000 do break; end; for i=1,1000 do break; end;
n=100; local n=100;
i=3; local i=3;
t = {}; local t = {};
a=nil local a=nil
while not a do while not a do
a=0; for i=1,n do for i=i,1,-1 do a=a+1; t[i]=1; end; end; a=0; for i=1,n do for i=i,1,-1 do a=a+1; t[i]=1; end; end;
end end
@ -175,14 +202,14 @@ a={y=1}
x = {a.y} x = {a.y}
assert(x[1] == 1) assert(x[1] == 1)
function f(i) local function f (i)
while 1 do while 1 do
if i>0 then i=i-1; if i>0 then i=i-1;
else return; end; else return; end;
end; end;
end; end;
function g(i) local function g(i)
while 1 do while 1 do
if i>0 then i=i-1 if i>0 then i=i-1
else return end else return end
@ -247,7 +274,7 @@ function g (a,b,c,d,e)
if not (a>=b or c or d and e or nil) then return 0; else return 1; end; if not (a>=b or c or d and e or nil) then return 0; else return 1; end;
end end
function h (a,b,c,d,e) local function h (a,b,c,d,e)
while (a>=b or c or (d and e) or nil) do return 1; end; while (a>=b or c or (d and e) or nil) do return 1; end;
return 0; return 0;
end; end;
@ -275,7 +302,7 @@ do
assert(a==2) assert(a==2)
end end
function F(a) local function F (a)
assert(debug.getinfo(1, "n").name == 'F') assert(debug.getinfo(1, "n").name == 'F')
return a,2,3 return a,2,3
end end
@ -368,6 +395,8 @@ for n = 1, level do
if i % 60000 == 0 then print('+') end if i % 60000 == 0 then print('+') end
end end
end end
IX = nil
_G.GLOB1 = nil
------------------------------------------------------------------ ------------------------------------------------------------------
-- testing some syntax errors (chosen through 'gcov') -- testing some syntax errors (chosen through 'gcov')

View File

@ -30,7 +30,8 @@ local function eqtab (t1, t2)
end end
_G.x = nil -- declare x _G.x = nil -- declare x
function foo (a, ...) _G.f = nil -- declare f
local function foo (a, ...)
local x, y = coroutine.running() local x, y = coroutine.running()
assert(x == f and y == false) assert(x == f and y == false)
-- next call should not corrupt coroutine (but must fail, -- next call should not corrupt coroutine (but must fail,
@ -67,10 +68,11 @@ assert(coroutine.status(f) == "dead")
s, a = coroutine.resume(f, "xuxu") s, a = coroutine.resume(f, "xuxu")
assert(not s and string.find(a, "dead") and coroutine.status(f) == "dead") assert(not s and string.find(a, "dead") and coroutine.status(f) == "dead")
_G.f = nil
-- yields in tail calls -- yields in tail calls
local function foo (i) return coroutine.yield(i) end local function foo (i) return coroutine.yield(i) end
f = coroutine.wrap(function () local f = coroutine.wrap(function ()
for i=1,10 do for i=1,10 do
assert(foo(i) == _G.x) assert(foo(i) == _G.x)
end end
@ -79,8 +81,10 @@ end)
for i=1,10 do _G.x = i; assert(f(i) == i) end for i=1,10 do _G.x = i; assert(f(i) == i) end
_G.x = 'xuxu'; assert(f('xuxu') == 'a') _G.x = 'xuxu'; assert(f('xuxu') == 'a')
_G.x = nil
-- recursive -- recursive
function pf (n, i) local function pf (n, i)
coroutine.yield(n) coroutine.yield(n)
pf(n*i, i+1) pf(n*i, i+1)
end end
@ -93,14 +97,14 @@ for i=1,10 do
end end
-- sieve -- sieve
function gen (n) local function gen (n)
return coroutine.wrap(function () return coroutine.wrap(function ()
for i=2,n do coroutine.yield(i) end for i=2,n do coroutine.yield(i) end
end) end)
end end
function filter (p, g) local function filter (p, g)
return coroutine.wrap(function () return coroutine.wrap(function ()
while 1 do while 1 do
local n = g() local n = g()
@ -221,14 +225,14 @@ do
-- <close> versus pcall in coroutines -- <close> versus pcall in coroutines
local X = false local X = false
local Y = false local Y = false
function foo () local function foo ()
local x <close> = func2close(function (self, err) local x <close> = func2close(function (self, err)
Y = debug.getinfo(2) Y = debug.getinfo(2)
X = err X = err
end) end)
error(43) error(43)
end end
co = coroutine.create(function () return pcall(foo) end) local co = coroutine.create(function () return pcall(foo) end)
local st1, st2, err = coroutine.resume(co) local st1, st2, err = coroutine.resume(co)
assert(st1 and not st2 and err == 43) assert(st1 and not st2 and err == 43)
assert(X == 43 and Y.what == "C") assert(X == 43 and Y.what == "C")
@ -275,7 +279,7 @@ end
-- yielding across C boundaries -- yielding across C boundaries
co = coroutine.wrap(function() local co = coroutine.wrap(function()
assert(not pcall(table.sort,{1,2,3}, coroutine.yield)) assert(not pcall(table.sort,{1,2,3}, coroutine.yield))
assert(coroutine.isyieldable()) assert(coroutine.isyieldable())
coroutine.yield(20) coroutine.yield(20)
@ -303,15 +307,15 @@ local r1, r2, v = f1(nil)
assert(r1 and not r2 and v[1] == (10 + 1)*10/2) assert(r1 and not r2 and v[1] == (10 + 1)*10/2)
function f (a, b) a = coroutine.yield(a); error{a + b} end local function f (a, b) a = coroutine.yield(a); error{a + b} end
function g(x) return x[1]*2 end local function g(x) return x[1]*2 end
co = coroutine.wrap(function () co = coroutine.wrap(function ()
coroutine.yield(xpcall(f, g, 10, 20)) coroutine.yield(xpcall(f, g, 10, 20))
end) end)
assert(co() == 10) assert(co() == 10)
r, msg = co(100) local r, msg = co(100)
assert(not r and msg == 240) assert(not r and msg == 240)
@ -373,9 +377,10 @@ assert(not a and b == foo and coroutine.status(x) == "dead")
a,b = coroutine.resume(x) a,b = coroutine.resume(x)
assert(not a and string.find(b, "dead") and coroutine.status(x) == "dead") assert(not a and string.find(b, "dead") and coroutine.status(x) == "dead")
goo = nil
-- co-routines x for loop -- co-routines x for loop
function all (a, n, k) local function all (a, n, k)
if k == 0 then coroutine.yield(a) if k == 0 then coroutine.yield(a)
else else
for i=1,n do for i=1,n do
@ -415,7 +420,7 @@ assert(f() == 43 and f() == 53)
-- old bug: attempt to resume itself -- old bug: attempt to resume itself
function co_func (current_co) local function co_func (current_co)
assert(coroutine.running() == current_co) assert(coroutine.running() == current_co)
assert(coroutine.resume(current_co) == false) assert(coroutine.resume(current_co) == false)
coroutine.yield(10, 20) coroutine.yield(10, 20)
@ -491,15 +496,16 @@ a = nil
-- access to locals of erroneous coroutines -- access to locals of erroneous coroutines
local x = coroutine.create (function () local x = coroutine.create (function ()
local a = 10 local a = 10
_G.f = function () a=a+1; return a end _G.F = function () a=a+1; return a end
error('x') error('x')
end) end)
assert(not coroutine.resume(x)) assert(not coroutine.resume(x))
-- overwrite previous position of local `a' -- overwrite previous position of local `a'
assert(not coroutine.resume(x, 1, 1, 1, 1, 1, 1, 1)) assert(not coroutine.resume(x, 1, 1, 1, 1, 1, 1, 1))
assert(_G.f() == 11) assert(_G.F() == 11)
assert(_G.f() == 12) assert(_G.F() == 12)
_G.F = nil
if not T then if not T then
@ -510,7 +516,7 @@ else
local turn local turn
function fact (t, x) local function fact (t, x)
assert(turn == t) assert(turn == t)
if x == 0 then return 1 if x == 0 then return 1
else return x*fact(t, x-1) else return x*fact(t, x-1)
@ -579,6 +585,7 @@ else
_G.X = nil; co(); assert(_G.X == line + 2 and _G.XX == nil) _G.X = nil; co(); assert(_G.X == line + 2 and _G.XX == nil)
_G.X = nil; co(); assert(_G.X == line + 3 and _G.XX == 20) _G.X = nil; co(); assert(_G.X == line + 3 and _G.XX == 20)
assert(co() == 10) assert(co() == 10)
_G.X = nil
-- testing yields in count hook -- testing yields in count hook
co = coroutine.wrap(function () co = coroutine.wrap(function ()
@ -656,6 +663,8 @@ else
assert(X == 'a a a' and Y == 'OK') assert(X == 'a a a' and Y == 'OK')
X, Y = nil
-- resuming running coroutine -- resuming running coroutine
C = coroutine.create(function () C = coroutine.create(function ()
@ -701,7 +710,7 @@ else
X = function (x) coroutine.yield(x, 'BB'); return 'CC' end; X = function (x) coroutine.yield(x, 'BB'); return 'CC' end;
return 'ok']])) return 'ok']]))
t = table.pack(T.testC(state, [[ local t = table.pack(T.testC(state, [[
rawgeti R 1 # get main thread rawgeti R 1 # get main thread
pushstring 'XX' pushstring 'XX'
getglobal X # get function for body getglobal X # get function for body
@ -730,31 +739,28 @@ end
-- leaving a pending coroutine open -- leaving a pending coroutine open
_X = coroutine.wrap(function () _G.TO_SURVIVE = coroutine.wrap(function ()
local a = 10 local a = 10
local x = function () a = a+1 end local x = function () a = a+1 end
coroutine.yield() coroutine.yield()
end) end)
_X() _G.TO_SURVIVE()
if not _soft then if not _soft then
-- bug (stack overflow) -- bug (stack overflow)
local j = 2^9 local lim = 1000000 -- stack limit; assume 32-bit machine
local lim = 1000000 -- (C stack limit; assume 32-bit machine) local t = {lim - 10, lim - 5, lim - 1, lim, lim + 1, lim + 5}
local t = {lim - 10, lim - 5, lim - 1, lim, lim + 1}
for i = 1, #t do for i = 1, #t do
local j = t[i] local j = t[i]
co = coroutine.create(function() local co = coroutine.create(function()
local t = {} return table.unpack({}, 1, j)
for i = 1, j do t[i] = i end
return table.unpack(t)
end) end)
local r, msg = coroutine.resume(co) local r, msg = coroutine.resume(co)
assert(not r) -- must fail for unpacking larger than stack limit
assert(j < lim or not r)
end end
co = nil
end end
@ -938,7 +944,7 @@ assert(run(function ()
do local _ENV = _ENV do local _ENV = _ENV
f = function () AAA = BBB + 1; return AAA end f = function () AAA = BBB + 1; return AAA end
end end
g = new(10); g.k.BBB = 10; local g = new(10); g.k.BBB = 10;
debug.setupvalue(f, 1, g) debug.setupvalue(f, 1, g)
assert(run(f, {"idx", "nidx", "idx"}) == 11) assert(run(f, {"idx", "nidx", "idx"}) == 11)
assert(g.k.AAA == 11) assert(g.k.AAA == 11)
@ -1078,6 +1084,8 @@ assert(#a == 3 and a[1] == a[2] and a[2] == a[3] and a[3] == 34)
-- testing yields with continuations -- testing yields with continuations
local y
co = coroutine.wrap(function (...) return co = coroutine.wrap(function (...) return
T.testC([[ # initial function T.testC([[ # initial function
yieldk 1 2 yieldk 1 2
@ -1130,6 +1138,9 @@ assert(x == "YIELD" and y == 4)
assert(not pcall(co)) -- coroutine should be dead assert(not pcall(co)) -- coroutine should be dead
_G.ctx = nil
_G.status = nil
-- bug in nCcalls -- bug in nCcalls
local co = coroutine.wrap(function () local co = coroutine.wrap(function ()

View File

@ -84,6 +84,32 @@ do -- bug in 5.4.0
end end
do -- bug since 5.4.0
local count = 0
print("chain of 'coroutine.close'")
-- create N coroutines forming a list so that each one, when closed,
-- closes the previous one. (With a large enough N, previous Lua
-- versions crash in this test.)
local coro = false
for i = 1, 1000 do
local previous = coro
coro = coroutine.create(function()
local cc <close> = setmetatable({}, {__close=function()
count = count + 1
if previous then
assert(coroutine.close(previous))
end
end})
coroutine.yield() -- leaves 'cc' pending to be closed
end)
assert(coroutine.resume(coro)) -- start it and run until it yields
end
local st, msg = coroutine.close(coro)
assert(not st and string.find(msg, "C stack overflow"))
print("final count: ", count)
end
do do
print("nesting of resuming yielded coroutines") print("nesting of resuming yielded coroutines")
local count = 0 local count = 0

View File

@ -16,7 +16,7 @@ end
assert(not debug.gethook()) assert(not debug.gethook())
local testline = 19 -- line where 'test' is defined local testline = 19 -- line where 'test' is defined
function test (s, l, p) -- this must be line 19 local function test (s, l, p) -- this must be line 19
collectgarbage() -- avoid gc during trace collectgarbage() -- avoid gc during trace
local function f (event, line) local function f (event, line)
assert(event == 'line') assert(event == 'line')
@ -50,7 +50,7 @@ end
-- test file and string names truncation -- test file and string names truncation
a = "function f () end" local a = "function f () end"
local function dostring (s, x) return load(s, x)() end local function dostring (s, x) return load(s, x)() end
dostring(a) dostring(a)
assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a)) assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a))
@ -72,7 +72,8 @@ dostring(a, string.format("=%s", string.rep('x', 500)))
assert(string.find(debug.getinfo(f).short_src, "^x*$")) assert(string.find(debug.getinfo(f).short_src, "^x*$"))
dostring(a, "=") dostring(a, "=")
assert(debug.getinfo(f).short_src == "") assert(debug.getinfo(f).short_src == "")
a = nil; f = nil; _G.a = nil; _G.f = nil;
_G[string.rep("p", 400)] = nil
repeat repeat
@ -120,6 +121,7 @@ else
end end
]], {2,3,4,7}) ]], {2,3,4,7})
test([[ test([[
local function foo() local function foo()
end end
@ -128,6 +130,7 @@ A = 1
A = 2 A = 2
A = 3 A = 3
]], {2, 3, 2, 4, 5, 6}) ]], {2, 3, 2, 4, 5, 6})
_G.A = nil
test([[-- test([[--
@ -175,6 +178,8 @@ end
test([[for i=1,4 do a=1 end]], {1,1,1,1}) test([[for i=1,4 do a=1 end]], {1,1,1,1})
_G.a = nil
do -- testing line info/trace with large gaps in source do -- testing line info/trace with large gaps in source
@ -194,6 +199,7 @@ do -- testing line info/trace with large gaps in source
end end
end end
end end
_G.a = nil
do -- testing active lines do -- testing active lines
@ -287,7 +293,6 @@ foo(200, 3, 4)
local a = {} local a = {}
for i = 1, (_soft and 100 or 1000) do a[i] = i end for i = 1, (_soft and 100 or 1000) do a[i] = i end
foo(table.unpack(a)) foo(table.unpack(a))
a = nil
@ -307,13 +312,14 @@ do -- test hook presence in debug info
debug.sethook() debug.sethook()
assert(count == 4) assert(count == 4)
end end
_ENV.a = nil
-- hook table has weak keys -- hook table has weak keys
assert(getmetatable(debug.getregistry()._HOOKKEY).__mode == 'k') assert(getmetatable(debug.getregistry()._HOOKKEY).__mode == 'k')
a = {}; L = nil a = {}; local L = nil
local glob = 1 local glob = 1
local oldglob = glob local oldglob = glob
debug.sethook(function (e,l) debug.sethook(function (e,l)
@ -354,7 +360,7 @@ function foo()
end; foo() -- set L end; foo() -- set L
-- check line counting inside strings and empty lines -- check line counting inside strings and empty lines
_ = 'alo\ local _ = 'alo\
alo' .. [[ alo' .. [[
]] ]]
@ -403,6 +409,7 @@ function g(a,b) return (a+1) + f() end
assert(g(0,0) == 30) assert(g(0,0) == 30)
_G.f, _G.g = nil
debug.sethook(nil); debug.sethook(nil);
assert(not debug.gethook()) assert(not debug.gethook())
@ -446,7 +453,7 @@ local function collectlocals (level)
end end
X = nil local X = nil
a = {} a = {}
function a:f (a, b, ...) local arg = {...}; local c = 13 end function a:f (a, b, ...) local arg = {...}; local c = 13 end
debug.sethook(function (e) debug.sethook(function (e)
@ -469,6 +476,7 @@ a:f(1,2,3,4,5)
assert(X.self == a and X.a == 1 and X.b == 2 and X.c == nil) assert(X.self == a and X.a == 1 and X.b == 2 and X.c == nil)
assert(XX == 12) assert(XX == 12)
assert(not debug.gethook()) assert(not debug.gethook())
_G.XX = nil
-- testing access to local variables in return hook (bug in 5.2) -- testing access to local variables in return hook (bug in 5.2)
@ -593,6 +601,7 @@ end
debug.sethook() debug.sethook()
local g, g1
-- tests for tail calls -- tests for tail calls
local function f (x) local function f (x)
@ -638,7 +647,7 @@ h(false)
debug.sethook() debug.sethook()
assert(b == 2) -- two tail calls assert(b == 2) -- two tail calls
lim = _soft and 3000 or 30000 local lim = _soft and 3000 or 30000
local function foo (x) local function foo (x)
if x==0 then if x==0 then
assert(debug.getinfo(2).what == "main") assert(debug.getinfo(2).what == "main")
@ -940,7 +949,7 @@ end
print("testing debug functions on chunk without debug info") print("testing debug functions on chunk without debug info")
prog = [[-- program to be loaded without debug information (strip) local prog = [[-- program to be loaded without debug information (strip)
local debug = require'debug' local debug = require'debug'
local a = 12 -- a local variable local a = 12 -- a local variable

View File

@ -114,12 +114,14 @@ checkmessage("a = {} | 1", "bitwise operation")
checkmessage("a = {} < 1", "attempt to compare") checkmessage("a = {} < 1", "attempt to compare")
checkmessage("a = {} <= 1", "attempt to compare") checkmessage("a = {} <= 1", "attempt to compare")
checkmessage("a=1; bbbb=2; a=math.sin(3)+bbbb(3)", "global 'bbbb'") checkmessage("aaa=1; bbbb=2; aaa=math.sin(3)+bbbb(3)", "global 'bbbb'")
checkmessage("a={}; do local a=1 end a:bbbb(3)", "method 'bbbb'") checkmessage("aaa={}; do local aaa=1 end aaa:bbbb(3)", "method 'bbbb'")
checkmessage("local a={}; a.bbbb(3)", "field 'bbbb'") checkmessage("local a={}; a.bbbb(3)", "field 'bbbb'")
assert(not string.find(doit"a={13}; local bbbb=1; a[bbbb](3)", "'bbbb'")) assert(not string.find(doit"aaa={13}; local bbbb=1; aaa[bbbb](3)", "'bbbb'"))
checkmessage("a={13}; local bbbb=1; a[bbbb](3)", "number") checkmessage("aaa={13}; local bbbb=1; aaa[bbbb](3)", "number")
checkmessage("a=(1)..{}", "a table value") checkmessage("aaa=(1)..{}", "a table value")
_G.aaa, _G.bbbb = nil
-- calls -- calls
checkmessage("local a; a(13)", "local 'a'") checkmessage("local a; a(13)", "local 'a'")
@ -134,12 +136,13 @@ checkmessage([[
-- tail calls -- tail calls
checkmessage("local a={}; return a.bbbb(3)", "field 'bbbb'") checkmessage("local a={}; return a.bbbb(3)", "field 'bbbb'")
checkmessage("a={}; do local a=1 end; return a:bbbb(3)", "method 'bbbb'") checkmessage("aaa={}; do local aaa=1 end; return aaa:bbbb(3)", "method 'bbbb'")
checkmessage("a = #print", "length of a function value") checkmessage("aaa = #print", "length of a function value")
checkmessage("a = #3", "length of a number value") checkmessage("aaa = #3", "length of a number value")
_G.aaa = nil
aaa = nil
checkmessage("aaa.bbb:ddd(9)", "global 'aaa'") checkmessage("aaa.bbb:ddd(9)", "global 'aaa'")
checkmessage("local aaa={bbb=1}; aaa.bbb:ddd(9)", "field 'bbb'") checkmessage("local aaa={bbb=1}; aaa.bbb:ddd(9)", "field 'bbb'")
checkmessage("local aaa={bbb={}}; aaa.bbb:ddd(9)", "method 'ddd'") checkmessage("local aaa={bbb={}}; aaa.bbb:ddd(9)", "method 'ddd'")
@ -152,15 +155,16 @@ checkmessage("local a,b,cc; (function () a.x = 1 end)()", "upvalue 'a'")
checkmessage("local _ENV = {x={}}; a = a + 1", "global 'a'") checkmessage("local _ENV = {x={}}; a = a + 1", "global 'a'")
checkmessage("b=1; local aaa={}; x=aaa+b", "local 'aaa'") checkmessage("BB=1; local aaa={}; x=aaa+BB", "local 'aaa'")
checkmessage("aaa={}; x=3.3/aaa", "global 'aaa'") checkmessage("aaa={}; x=3.3/aaa", "global 'aaa'")
checkmessage("aaa=2; b=nil;x=aaa*b", "global 'b'") checkmessage("aaa=2; BB=nil;x=aaa*BB", "global 'BB'")
checkmessage("aaa={}; x=-aaa", "global 'aaa'") checkmessage("aaa={}; x=-aaa", "global 'aaa'")
-- short circuit -- short circuit
checkmessage("a=1; local a,bbbb=2,3; a = math.sin(1) and bbbb(3)", checkmessage("aaa=1; local aaa,bbbb=2,3; aaa = math.sin(1) and bbbb(3)",
"local 'bbbb'")
checkmessage("aaa=1; local aaa,bbbb=2,3; aaa = bbbb(1) or aaa(3)",
"local 'bbbb'") "local 'bbbb'")
checkmessage("a=1; local a,bbbb=2,3; a = bbbb(1) or a(3)", "local 'bbbb'")
checkmessage("local a,b,c,f = 1,1,1; f((a and b) or c)", "local 'f'") checkmessage("local a,b,c,f = 1,1,1; f((a and b) or c)", "local 'f'")
checkmessage("local a,b,c = 1,1,1; ((a and b) or c)()", "call a number value") checkmessage("local a,b,c = 1,1,1; ((a and b) or c)()", "call a number value")
assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'")) assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'"))
@ -187,8 +191,8 @@ checkmessage("return ~-3e40", "has no integer representation")
checkmessage("return ~-3.009", "has no integer representation") checkmessage("return ~-3.009", "has no integer representation")
checkmessage("return 3.009 & 1", "has no integer representation") checkmessage("return 3.009 & 1", "has no integer representation")
checkmessage("return 34 >> {}", "table value") checkmessage("return 34 >> {}", "table value")
checkmessage("a = 24 // 0", "divide by zero") checkmessage("aaa = 24 // 0", "divide by zero")
checkmessage("a = 1 % 0", "'n%0'") checkmessage("aaa = 1 % 0", "'n%0'")
-- type error for an object which is neither in an upvalue nor a register. -- type error for an object which is neither in an upvalue nor a register.
@ -269,13 +273,13 @@ end
-- tests for field accesses after RK limit -- tests for field accesses after RK limit
local t = {} local t = {}
for i = 1, 1000 do for i = 1, 1000 do
t[i] = "a = x" .. i t[i] = "aaa = x" .. i
end end
local s = table.concat(t, "; ") local s = table.concat(t, "; ")
t = nil t = nil
checkmessage(s.."; a = bbb + 1", "global 'bbb'") checkmessage(s.."; aaa = bbb + 1", "global 'bbb'")
checkmessage("local _ENV=_ENV;"..s.."; a = bbb + 1", "global 'bbb'") checkmessage("local _ENV=_ENV;"..s.."; aaa = bbb + 1", "global 'bbb'")
checkmessage(s.."; local t = {}; a = t.bbb + 1", "field 'bbb'") checkmessage(s.."; local t = {}; aaa = t.bbb + 1", "field 'bbb'")
checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'") checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'")
checkmessage([[aaa=9 checkmessage([[aaa=9
@ -324,14 +328,17 @@ main()
]], "global 'NoSuchName'") ]], "global 'NoSuchName'")
print'+' print'+'
a = {}; setmetatable(a, {__index = string}) aaa = {}; setmetatable(aaa, {__index = string})
checkmessage("a:sub()", "bad self") checkmessage("aaa:sub()", "bad self")
checkmessage("string.sub('a', {})", "#2") checkmessage("string.sub('a', {})", "#2")
checkmessage("('a'):sub{}", "#1") checkmessage("('a'):sub{}", "#1")
checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'") checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'")
checkmessage("string.gsub('s', 's', setmetatable)", "'setmetatable'") checkmessage("string.gsub('s', 's', setmetatable)", "'setmetatable'")
_G.aaa = nil
-- tests for errors in coroutines -- tests for errors in coroutines
local function f (n) local function f (n)
@ -349,7 +356,7 @@ checkerr("yield across", f)
-- testing size of 'source' info; size of buffer for that info is -- testing size of 'source' info; size of buffer for that info is
-- LUA_IDSIZE, declared as 60 in luaconf. Get one position for '\0'. -- LUA_IDSIZE, declared as 60 in luaconf. Get one position for '\0'.
idsize = 60 - 1 local idsize = 60 - 1
local function checksize (source) local function checksize (source)
-- syntax error -- syntax error
local _, msg = load("x", source) local _, msg = load("x", source)
@ -411,13 +418,14 @@ x
local p = [[ local p = [[
function g() f() end function g() f() end
function f(x) error('a', X) end function f(x) error('a', XX) end
g() g()
]] ]]
X=3;lineerror((p), 3) XX=3;lineerror((p), 3)
X=0;lineerror((p), false) XX=0;lineerror((p), false)
X=1;lineerror((p), 2) XX=1;lineerror((p), 2)
X=2;lineerror((p), 1) XX=2;lineerror((p), 1)
_G.XX, _G.g, _G.f = nil
lineerror([[ lineerror([[
@ -436,6 +444,14 @@ if not b then
end end
end]], 5) end]], 5)
-- bug in 5.4.0
lineerror([[
local a = 0
local b = 1
local c = b % a
]], 3)
do do
-- Force a negative estimate for base line. Error in instruction 2 -- Force a negative estimate for base line. Error in instruction 2
-- (after VARARGPREP, GETGLOBAL), with first absolute line information -- (after VARARGPREP, GETGLOBAL), with first absolute line information
@ -449,11 +465,11 @@ if not _soft then
-- several tests that exaust the Lua stack -- several tests that exaust the Lua stack
collectgarbage() collectgarbage()
print"testing stack overflow" print"testing stack overflow"
C = 0 local C = 0
-- get line where stack overflow will happen -- get line where stack overflow will happen
local l = debug.getinfo(1, "l").currentline + 1 local l = debug.getinfo(1, "l").currentline + 1
local function auxy () C=C+1; auxy() end -- produce a stack overflow local function auxy () C=C+1; auxy() end -- produce a stack overflow
function y () function YY ()
collectgarbage("stop") -- avoid running finalizers without stack space collectgarbage("stop") -- avoid running finalizers without stack space
auxy() auxy()
collectgarbage("restart") collectgarbage("restart")
@ -465,9 +481,11 @@ if not _soft then
return (string.find(m, "stack overflow")) return (string.find(m, "stack overflow"))
end end
-- repeated stack overflows (to check stack recovery) -- repeated stack overflows (to check stack recovery)
assert(checkstackmessage(doit('y()'))) assert(checkstackmessage(doit('YY()')))
assert(checkstackmessage(doit('y()'))) assert(checkstackmessage(doit('YY()')))
assert(checkstackmessage(doit('y()'))) assert(checkstackmessage(doit('YY()')))
_G.YY = nil
-- error lines in stack overflow -- error lines in stack overflow
@ -561,7 +579,7 @@ do
end end
-- xpcall with arguments -- xpcall with arguments
a, b, c = xpcall(string.find, error, "alo", "al") local a, b, c = xpcall(string.find, error, "alo", "al")
assert(a and b == 1 and c == 2) assert(a and b == 1 and c == 2)
a, b, c = xpcall(string.find, function (x) return {} end, true, "al") a, b, c = xpcall(string.find, function (x) return {} end, true, "al")
assert(not a and type(b) == "table" and c == nil) assert(not a and type(b) == "table" and c == nil)
@ -581,11 +599,12 @@ checksyntax("a\1a = 1", "", "<\\1>", 1)
-- test 255 as first char in a chunk -- test 255 as first char in a chunk
checksyntax("\255a = 1", "", "<\\255>", 1) checksyntax("\255a = 1", "", "<\\255>", 1)
doit('I = load("a=9+"); a=3') doit('I = load("a=9+"); aaa=3')
assert(a==3 and not I) assert(_G.aaa==3 and not _G.I)
_G.I,_G.aaa = nil
print('+') print('+')
lim = 1000 local lim = 1000
if _soft then lim = 100 end if _soft then lim = 100 end
for i=1,lim do for i=1,lim do
doit('a = ') doit('a = ')

View File

@ -420,6 +420,9 @@ assert(i == 3 and x[1] == 3 and x[3] == 5)
assert(_G.X == 20) assert(_G.X == 20)
_G.X, _G.B = nil
print'+' print'+'
local _g = _G local _g = _G

View File

@ -507,15 +507,17 @@ load((io.lines(file, 1)))()
assert(_G.X == 4) assert(_G.X == 4)
load((io.lines(file, 3)))() load((io.lines(file, 3)))()
assert(_G.X == 8) assert(_G.X == 8)
_G.X = nil
print('+') print('+')
local x1 = "string\n\n\\com \"\"''coisas [[estranhas]] ]]'" local x1 = "string\n\n\\com \"\"''coisas [[estranhas]] ]]'"
io.output(file) io.output(file)
assert(io.write(string.format("x2 = %q\n-- comment without ending EOS", x1))) assert(io.write(string.format("X2 = %q\n-- comment without ending EOS", x1)))
io.close() io.close()
assert(loadfile(file))() assert(loadfile(file))()
assert(x1 == x2) assert(x1 == _G.X2)
_G.X2 = nil
print('+') print('+')
assert(os.remove(file)) assert(os.remove(file))
assert(not os.remove(file)) assert(not os.remove(file))
@ -825,8 +827,17 @@ checkerr("missing", os.time, {hour = 12}) -- missing date
if string.packsize("i") == 4 then -- 4-byte ints if string.packsize("i") == 4 then -- 4-byte ints
checkerr("field 'year' is out-of-bound", os.time, checkerr("field 'year' is out-of-bound", os.time,
{year = -(1 << 31) + 1899, month = 1, day = 1}) {year = -(1 << 31) + 1899, month = 1, day = 1})
checkerr("field 'year' is out-of-bound", os.time,
{year = -(1 << 31), month = 1, day = 1})
if math.maxinteger > 2^31 then -- larger lua_integer?
checkerr("field 'year' is out-of-bound", os.time,
{year = (1 << 31) + 1900, month = 1, day = 1})
end
end end
if not _port then if not _port then
-- test Posix-specific modifiers -- test Posix-specific modifiers
assert(type(os.date("%Ex")) == 'string') assert(type(os.date("%Ex")) == 'string')

View File

@ -125,7 +125,7 @@ do
end end
a:test() a:test()
_G.temp = nil
end end
@ -134,7 +134,7 @@ do local f = function () end end
print("functions with errors") print("functions with errors")
prog = [[ local prog = [[
do do
a = 10; a = 10;
function foo(x,y) function foo(x,y)
@ -153,22 +153,25 @@ do
end end
end end
end end
rawset(_G, "a", nil)
_G.x = nil
foo = nil do
print('long strings') foo = nil
x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789" print('long strings')
assert(string.len(x)==80) local x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
s = '' assert(string.len(x)==80)
k = math.min(300, (math.maxinteger // 80) // 2) local s = ''
for n = 1, k do s = s..x; j=tostring(n) end local k = math.min(300, (math.maxinteger // 80) // 2)
assert(string.len(s) == k*80) for n = 1, k do s = s..x; local j=tostring(n) end
s = string.sub(s, 1, 10000) assert(string.len(s) == k*80)
s, i = string.gsub(s, '(%d%d%d%d)', '') s = string.sub(s, 1, 10000)
assert(i==10000 // 4) local s, i = string.gsub(s, '(%d%d%d%d)', '')
s = nil assert(i==10000 // 4)
x = nil
assert(_G["while"] == 234) assert(_G["while"] == 234)
_G["while"] = nil
end
-- --
@ -227,8 +230,8 @@ end
print("clearing tables") print("clearing tables")
lim = 15 local lim = 15
a = {} local a = {}
-- fill a with `collectable' indices -- fill a with `collectable' indices
for i=1,lim do a[{}] = i end for i=1,lim do a[{}] = i end
b = {} b = {}
@ -552,6 +555,7 @@ do
for i=1,1000 do _ENV.a = {} end -- no collection during the loop for i=1,1000 do _ENV.a = {} end -- no collection during the loop
until gcinfo() > 2 * x until gcinfo() > 2 * x
collectgarbage"restart" collectgarbage"restart"
_ENV.a = nil
end end

View File

@ -11,17 +11,17 @@ CFLAGS = -Wall -std=gnu99 -O2 -I$(LUA_DIR) -fPIC -shared
all: lib1.so lib11.so lib2.so lib21.so lib2-v2.so all: lib1.so lib11.so lib2.so lib21.so lib2-v2.so
touch all touch all
lib1.so: lib1.c $(LUA_DIR)/luaconf.h lib1.so: lib1.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib1.so lib1.c $(CC) $(CFLAGS) -o lib1.so lib1.c
lib11.so: lib11.c $(LUA_DIR)/luaconf.h lib11.so: lib11.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib11.so lib11.c $(CC) $(CFLAGS) -o lib11.so lib11.c
lib2.so: lib2.c $(LUA_DIR)/luaconf.h lib2.so: lib2.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib2.so lib2.c $(CC) $(CFLAGS) -o lib2.so lib2.c
lib21.so: lib21.c $(LUA_DIR)/luaconf.h lib21.so: lib21.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib21.so lib21.c $(CC) $(CFLAGS) -o lib21.so lib21.c
lib2-v2.so: lib21.c $(LUA_DIR)/luaconf.h lib2-v2.so: lib21.c $(LUA_DIR)/luaconf.h $(LUA_DIR)/lua.h
$(CC) $(CFLAGS) -o lib2-v2.so lib22.c $(CC) $(CFLAGS) -o lib2-v2.so lib22.c

View File

@ -10,6 +10,7 @@ local function dostring (x) return assert(load(x), "")() end
dostring("x \v\f = \t\r 'a\0a' \v\f\f") dostring("x \v\f = \t\r 'a\0a' \v\f\f")
assert(x == 'a\0a' and string.len(x) == 3) assert(x == 'a\0a' and string.len(x) == 3)
_G.x = nil
-- escape sequences -- escape sequences
assert('\n\"\'\\' == [[ assert('\n\"\'\\' == [[
@ -129,16 +130,16 @@ end
-- long variable names -- long variable names
var1 = string.rep('a', 15000) .. '1' local var1 = string.rep('a', 15000) .. '1'
var2 = string.rep('a', 15000) .. '2' local var2 = string.rep('a', 15000) .. '2'
prog = string.format([[ local prog = string.format([[
%s = 5 %s = 5
%s = %s + 1 %s = %s + 1
return function () return %s - %s end return function () return %s - %s end
]], var1, var2, var1, var1, var2) ]], var1, var2, var1, var1, var2)
local f = dostring(prog) local f = dostring(prog)
assert(_G[var1] == 5 and _G[var2] == 6 and f() == -1) assert(_G[var1] == 5 and _G[var2] == 6 and f() == -1)
var1, var2, f = nil _G[var1], _G[var2] = nil
print('+') print('+')
-- escapes -- -- escapes --
@ -150,13 +151,13 @@ assert([[
$debug]] == "\n $debug") $debug]] == "\n $debug")
assert([[ [ ]] ~= [[ ] ]]) assert([[ [ ]] ~= [[ ] ]])
-- long strings -- -- long strings --
b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789" local b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
assert(string.len(b) == 960) assert(string.len(b) == 960)
prog = [=[ prog = [=[
print('+') print('+')
a1 = [["this is a 'string' with several 'quotes'"]] local a1 = [["this is a 'string' with several 'quotes'"]]
a2 = "'quotes'" local a2 = "'quotes'"
assert(string.find(a1, a2) == 34) assert(string.find(a1, a2) == 34)
print('+') print('+')
@ -164,12 +165,13 @@ print('+')
a1 = [==[temp = [[an arbitrary value]]; ]==] a1 = [==[temp = [[an arbitrary value]]; ]==]
assert(load(a1))() assert(load(a1))()
assert(temp == 'an arbitrary value') assert(temp == 'an arbitrary value')
_G.temp = nil
-- long strings -- -- long strings --
b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789" local b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
assert(string.len(b) == 960) assert(string.len(b) == 960)
print('+') print('+')
a = [[00123456789012345678901234567890123456789123456789012345678901234567890123456789 local a = [[00123456789012345678901234567890123456789123456789012345678901234567890123456789
00123456789012345678901234567890123456789123456789012345678901234567890123456789 00123456789012345678901234567890123456789123456789012345678901234567890123456789
00123456789012345678901234567890123456789123456789012345678901234567890123456789 00123456789012345678901234567890123456789123456789012345678901234567890123456789
00123456789012345678901234567890123456789123456789012345678901234567890123456789 00123456789012345678901234567890123456789123456789012345678901234567890123456789
@ -199,13 +201,11 @@ x = 1
]=] ]=]
print('+') print('+')
x = nil _G.x = nil
dostring(prog) dostring(prog)
assert(x) assert(x)
_G.x = nil
prog = nil
a = nil
b = nil
do -- reuse of long strings do -- reuse of long strings
@ -234,8 +234,8 @@ end
-- testing line ends -- testing line ends
prog = [[ prog = [[
a = 1 -- a comment local a = 1 -- a comment
b = 2 local b = 2
x = [=[ x = [=[
@ -252,10 +252,11 @@ for _, n in pairs{"\n", "\r", "\n\r", "\r\n"} do
assert(dostring(prog) == nn) assert(dostring(prog) == nn)
assert(_G.x == "hi\n" and _G.y == "\nhello\r\n\n") assert(_G.x == "hi\n" and _G.y == "\nhello\r\n\n")
end end
_G.x, _G.y = nil
-- testing comments and strings with long brackets -- testing comments and strings with long brackets
a = [==[]=]==] local a = [==[]=]==]
assert(a == "]=") assert(a == "]=")
a = [==[[===[[=[]]=][====[]]===]===]==] a = [==[[===[[=[]]=][====[]]===]===]==]

View File

@ -37,7 +37,7 @@ end
f = nil f = nil
local f local f
x = 1 local x = 1
a = nil a = nil
load('local a = {}')() load('local a = {}')()
@ -152,7 +152,7 @@ local dummy
local _ENV = (function (...) return ... end)(_G, dummy) -- { local _ENV = (function (...) return ... end)(_G, dummy) -- {
do local _ENV = {assert=assert}; assert(true) end do local _ENV = {assert=assert}; assert(true) end
mt = {_G = _G} local mt = {_G = _G}
local foo,x local foo,x
A = false -- "declare" A A = false -- "declare" A
do local _ENV = mt do local _ENV = mt
@ -174,6 +174,8 @@ do local _ENV = {assert=assert, A=10};
end end
assert(x==20) assert(x==20)
A = nil
do -- constants do -- constants
local a<const>, b, c<const> = 10, 20, 30 local a<const>, b, c<const> = 10, 20, 30
@ -360,6 +362,26 @@ do
end end
do
-- bug in 5.4.4: 'break' may generate wrong 'close' instruction when
-- leaving a loop block.
local closed = false
local o1 = setmetatable({}, {__close=function() closed = true end})
local function test()
for k, v in next, {}, nil, o1 do
local function f() return k end -- create an upvalue
break
end
assert(closed)
end
test()
end
do print("testing errors in __close") do print("testing errors in __close")
-- original error is in __close -- original error is in __close
@ -592,6 +614,28 @@ end
if rawget(_G, "T") then if rawget(_G, "T") then
do
-- bug in 5.4.3
-- 'lua_settop' may use a pointer to stack invalidated by 'luaF_close'
-- reduce stack size
collectgarbage(); collectgarbage(); collectgarbage()
-- force a stack reallocation
local function loop (n)
if n < 400 then loop(n + 1) end
end
-- close metamethod will reallocate the stack
local o = setmetatable({}, {__close = function () loop(0) end})
local script = [[toclose 2; settop 1; return 1]]
assert(T.testC(script, o) == script)
end
-- memory error inside closing function -- memory error inside closing function
local function foo () local function foo ()
local y <close> = func2close(function () T.alloccount() end) local y <close> = func2close(function () T.alloccount() end)
@ -669,7 +713,7 @@ if rawget(_G, "T") then
collectgarbage(); collectgarbage() collectgarbage(); collectgarbage()
m = T.totalmem() local m = T.totalmem()
collectgarbage("stop") collectgarbage("stop")
-- error in the first buffer allocation -- error in the first buffer allocation

View File

@ -44,7 +44,7 @@
void *l_Trick = 0; void *l_Trick = 0;
#define obj_at(L,k) s2v(L->ci->func + (k)) #define obj_at(L,k) s2v(L->ci->func.p + (k))
static int runC (lua_State *L, lua_State *L1, const char *pc); static int runC (lua_State *L, lua_State *L1, const char *pc);
@ -57,7 +57,7 @@ static void setnameval (lua_State *L, const char *name, int val) {
static void pushobject (lua_State *L, const TValue *o) { static void pushobject (lua_State *L, const TValue *o) {
setobj2s(L, L->top, o); setobj2s(L, L->top.p, o);
api_incr_top(L); api_incr_top(L);
} }
@ -419,7 +419,7 @@ static void checkLclosure (global_State *g, LClosure *cl) {
if (uv) { if (uv) {
checkobjrefN(g, clgc, uv); checkobjrefN(g, clgc, uv);
if (!upisopen(uv)) if (!upisopen(uv))
checkvalref(g, obj2gco(uv), uv->v); checkvalref(g, obj2gco(uv), uv->v.p);
} }
} }
} }
@ -428,7 +428,7 @@ static void checkLclosure (global_State *g, LClosure *cl) {
static int lua_checkpc (CallInfo *ci) { static int lua_checkpc (CallInfo *ci) {
if (!isLua(ci)) return 1; if (!isLua(ci)) return 1;
else { else {
StkId f = ci->func; StkId f = ci->func.p;
Proto *p = clLvalue(s2v(f))->p; Proto *p = clLvalue(s2v(f))->p;
return p->code <= ci->u.l.savedpc && return p->code <= ci->u.l.savedpc &&
ci->u.l.savedpc <= p->code + p->sizecode; ci->u.l.savedpc <= p->code + p->sizecode;
@ -441,19 +441,19 @@ static void checkstack (global_State *g, lua_State *L1) {
CallInfo *ci; CallInfo *ci;
UpVal *uv; UpVal *uv;
assert(!isdead(g, L1)); assert(!isdead(g, L1));
if (L1->stack == NULL) { /* incomplete thread? */ if (L1->stack.p == NULL) { /* incomplete thread? */
assert(L1->openupval == NULL && L1->ci == NULL); assert(L1->openupval == NULL && L1->ci == NULL);
return; return;
} }
for (uv = L1->openupval; uv != NULL; uv = uv->u.open.next) for (uv = L1->openupval; uv != NULL; uv = uv->u.open.next)
assert(upisopen(uv)); /* must be open */ assert(upisopen(uv)); /* must be open */
assert(L1->top <= L1->stack_last); assert(L1->top.p <= L1->stack_last.p);
assert(L1->tbclist <= L1->top); assert(L1->tbclist.p <= L1->top.p);
for (ci = L1->ci; ci != NULL; ci = ci->previous) { for (ci = L1->ci; ci != NULL; ci = ci->previous) {
assert(ci->top <= L1->stack_last); assert(ci->top.p <= L1->stack_last.p);
assert(lua_checkpc(ci)); assert(lua_checkpc(ci));
} }
for (o = L1->stack; o < L1->stack_last; o++) for (o = L1->stack.p; o < L1->stack_last.p; o++)
checkliveness(L1, s2v(o)); /* entire stack must have valid values */ checkliveness(L1, s2v(o)); /* entire stack must have valid values */
} }
@ -465,7 +465,7 @@ static void checkrefs (global_State *g, GCObject *o) {
break; break;
} }
case LUA_VUPVAL: { case LUA_VUPVAL: {
checkvalref(g, o, gco2upv(o)->v); checkvalref(g, o, gco2upv(o)->v.p);
break; break;
} }
case LUA_VTABLE: { case LUA_VTABLE: {
@ -533,7 +533,7 @@ static void checkobject (global_State *g, GCObject *o, int maybedead,
static lu_mem checkgraylist (global_State *g, GCObject *o) { static lu_mem checkgraylist (global_State *g, GCObject *o) {
int total = 0; /* count number of elements in the list */ int total = 0; /* count number of elements in the list */
((void)g); /* better to keep it available if we need to print an object */ cast_void(g); /* better to keep it if we need to print an object */
while (o) { while (o) {
assert(!!isgray(o) ^ (getage(o) == G_TOUCHED2)); assert(!!isgray(o) ^ (getage(o) == G_TOUCHED2));
assert(!testbit(o->marked, TESTBIT)); assert(!testbit(o->marked, TESTBIT));
@ -980,7 +980,7 @@ static int hash_query (lua_State *L) {
static int stacklevel (lua_State *L) { static int stacklevel (lua_State *L) {
unsigned long a = 0; unsigned long a = 0;
lua_pushinteger(L, (L->top - L->stack)); lua_pushinteger(L, (L->top.p - L->stack.p));
lua_pushinteger(L, stacksize(L)); lua_pushinteger(L, stacksize(L));
lua_pushinteger(L, L->nCcalls); lua_pushinteger(L, L->nCcalls);
lua_pushinteger(L, L->nci); lua_pushinteger(L, L->nci);
@ -1040,7 +1040,7 @@ static int string_query (lua_State *L) {
TString *ts; TString *ts;
int n = 0; int n = 0;
for (ts = tb->hash[s]; ts != NULL; ts = ts->u.hnext) { for (ts = tb->hash[s]; ts != NULL; ts = ts->u.hnext) {
setsvalue2s(L, L->top, ts); setsvalue2s(L, L->top.p, ts);
api_incr_top(L); api_incr_top(L);
n++; n++;
} }
@ -1055,7 +1055,7 @@ static int tref (lua_State *L) {
luaL_checkany(L, 1); luaL_checkany(L, 1);
lua_pushvalue(L, 1); lua_pushvalue(L, 1);
lua_pushinteger(L, luaL_ref(L, LUA_REGISTRYINDEX)); lua_pushinteger(L, luaL_ref(L, LUA_REGISTRYINDEX));
(void)level; /* to avoid warnings */ cast_void(level); /* to avoid warnings */
lua_assert(lua_gettop(L) == level+1); /* +1 for result */ lua_assert(lua_gettop(L) == level+1); /* +1 for result */
return 1; return 1;
} }
@ -1063,7 +1063,7 @@ static int tref (lua_State *L) {
static int getref (lua_State *L) { static int getref (lua_State *L) {
int level = lua_gettop(L); int level = lua_gettop(L);
lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_checkinteger(L, 1)); lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_checkinteger(L, 1));
(void)level; /* to avoid warnings */ cast_void(level); /* to avoid warnings */
lua_assert(lua_gettop(L) == level+1); lua_assert(lua_gettop(L) == level+1);
return 1; return 1;
} }
@ -1071,7 +1071,7 @@ static int getref (lua_State *L) {
static int unref (lua_State *L) { static int unref (lua_State *L) {
int level = lua_gettop(L); int level = lua_gettop(L);
luaL_unref(L, LUA_REGISTRYINDEX, cast_int(luaL_checkinteger(L, 1))); luaL_unref(L, LUA_REGISTRYINDEX, cast_int(luaL_checkinteger(L, 1)));
(void)level; /* to avoid warnings */ cast_void(level); /* to avoid warnings */
lua_assert(lua_gettop(L) == level); lua_assert(lua_gettop(L) == level);
return 0; return 0;
} }
@ -1533,7 +1533,7 @@ static int runC (lua_State *L, lua_State *L1, const char *pc) {
lua_newthread(L1); lua_newthread(L1);
} }
else if EQ("resetthread") { else if EQ("resetthread") {
lua_pushinteger(L1, lua_resetthread(L1)); lua_pushinteger(L1, lua_resetthread(L1, L));
} }
else if EQ("newuserdata") { else if EQ("newuserdata") {
lua_newuserdata(L1, getnum); lua_newuserdata(L1, getnum);
@ -1740,7 +1740,7 @@ static struct X { int x; } x;
else if EQ("tostring") { else if EQ("tostring") {
const char *s = lua_tostring(L1, getindex); const char *s = lua_tostring(L1, getindex);
const char *s1 = lua_pushstring(L1, s); const char *s1 = lua_pushstring(L1, s);
(void)s1; /* to avoid warnings */ cast_void(s1); /* to avoid warnings */
lua_longassert((s == NULL && s1 == NULL) || strcmp(s, s1) == 0); lua_longassert((s == NULL && s1 == NULL) || strcmp(s, s1) == 0);
} }
else if EQ("Ltolstring") { else if EQ("Ltolstring") {

View File

@ -125,6 +125,13 @@ LUA_API void *debug_realloc (void *ud, void *block,
#define LUAI_USER_ALIGNMENT_T union { char b[sizeof(void*) * 8]; } #define LUAI_USER_ALIGNMENT_T union { char b[sizeof(void*) * 8]; }
/*
** This one is not compatible with tests for opcode optimizations,
** as it blocks some optimizations
#define MAXINDEXRK 0
*/
/* make stack-overflow tests run faster */ /* make stack-overflow tests run faster */
#undef LUAI_MAXSTACK #undef LUAI_MAXSTACK
#define LUAI_MAXSTACK 50000 #define LUAI_MAXSTACK 50000

View File

@ -94,6 +94,33 @@ RUN('echo "print(10)\nprint(2)\n" | lua > %s', out)
checkout("10\n2\n") checkout("10\n2\n")
-- testing BOM
prepfile("\xEF\xBB\xBF")
RUN('lua %s > %s', prog, out)
checkout("")
prepfile("\xEF\xBB\xBFprint(3)")
RUN('lua %s > %s', prog, out)
checkout("3\n")
prepfile("\xEF\xBB\xBF# comment!!\nprint(3)")
RUN('lua %s > %s', prog, out)
checkout("3\n")
-- bad BOMs
prepfile("\xEF")
NoRun("unexpected symbol", 'lua %s > %s', prog, out)
prepfile("\xEF\xBB")
NoRun("unexpected symbol", 'lua %s > %s', prog, out)
prepfile("\xEFprint(3)")
NoRun("unexpected symbol", 'lua %s > %s', prog, out)
prepfile("\xEF\xBBprint(3)")
NoRun("unexpected symbol", 'lua %s > %s', prog, out)
-- test option '-' -- test option '-'
RUN('echo "print(arg[1])" | lua - -h > %s', out) RUN('echo "print(arg[1])" | lua - -h > %s', out)
checkout("-h\n") checkout("-h\n")
@ -312,7 +339,7 @@ prepfile("a = [[b\nc\nd\ne]]\n=a")
RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out) RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out)
checkprogout("b\nc\nd\ne\n\n") checkprogout("b\nc\nd\ne\n\n")
prompt = "alo" local prompt = "alo"
prepfile[[ -- prepfile[[ --
a = 2 a = 2
]] ]]
@ -363,7 +390,7 @@ NoRun("error object is a table value", [[lua %s]], prog)
-- chunk broken in many lines -- chunk broken in many lines
s = [=[ -- local s = [=[ --
function f ( x ) function f ( x )
local a = [[ local a = [[
xuxu xuxu
@ -385,12 +412,10 @@ checkprogout("101\n13\t22\n\n")
prepfile[[#comment in 1st line without \n at the end]] prepfile[[#comment in 1st line without \n at the end]]
RUN('lua %s', prog) RUN('lua %s', prog)
prepfile[[#test line number when file starts with comment line -- first-line comment with binary file
debug = require"debug" prepfile("#comment\n" .. string.dump(load("print(3)")))
print(debug.getinfo(1).currentline)
]]
RUN('lua %s > %s', prog, out) RUN('lua %s > %s', prog, out)
checkprogout('3\n') checkout('3\n')
-- close Lua with an open file -- close Lua with an open file
prepfile(string.format([[io.output(%q); io.write('alo')]], out)) prepfile(string.format([[io.output(%q); io.write('alo')]], out))

View File

@ -50,7 +50,7 @@ end
local msgf2i = "number.* has no integer representation" local msgf2i = "number.* has no integer representation"
-- float equality -- float equality
function eq (a,b,limit) local function eq (a,b,limit)
if not limit then if not limit then
if floatbits >= 50 then limit = 1E-11 if floatbits >= 50 then limit = 1E-11
else limit = 1E-5 else limit = 1E-5
@ -62,7 +62,7 @@ end
-- equality with types -- equality with types
function eqT (a,b) local function eqT (a,b)
return a == b and math.type(a) == math.type(b) return a == b and math.type(a) == math.type(b)
end end
@ -83,7 +83,7 @@ end
do do
local x = -1 local x = -1
local mz = 0/x -- minus zero local mz = 0/x -- minus zero
t = {[0] = 10, 20, 30, 40, 50} local t = {[0] = 10, 20, 30, 40, 50}
assert(t[mz] == t[0] and t[-0] == t[0]) assert(t[mz] == t[0] and t[-0] == t[0])
end end

View File

@ -9,6 +9,16 @@ local function checkerror (msg, f, ...)
end end
local function check (t, na, nh)
if not T then return end
local a, h = T.querytab(t)
if a ~= na or h ~= nh then
print(na, nh, a, h)
assert(nil)
end
end
local a = {} local a = {}
-- make sure table has lots of space in hash part -- make sure table has lots of space in hash part
@ -20,6 +30,25 @@ for i=1,100 do
assert(#a == i) assert(#a == i)
end end
do -- rehash moving elements from array to hash
local a = {}
for i = 1, 100 do a[i] = i end
check(a, 128, 0)
for i = 5, 95 do a[i] = nil end
check(a, 128, 0)
a.x = 1 -- force a re-hash
check(a, 4, 8)
for i = 1, 4 do assert(a[i] == i) end
for i = 5, 95 do assert(a[i] == nil) end
for i = 96, 100 do assert(a[i] == i) end
assert(a.x == 1)
end
-- testing ipairs -- testing ipairs
local x = 0 local x = 0
for k,v in ipairs{10,20,30;x=12} do for k,v in ipairs{10,20,30;x=12} do
@ -65,15 +94,6 @@ local function mp2 (n) -- minimum power of 2 >= n
end end
local function check (t, na, nh)
local a, h = T.querytab(t)
if a ~= na or h ~= nh then
print(na, nh, a, h)
assert(nil)
end
end
-- testing C library sizes -- testing C library sizes
do do
local s = 0 local s = 0
@ -169,7 +189,7 @@ end
-- size tests for vararg -- size tests for vararg
lim = 35 lim = 35
function foo (n, ...) local function foo (n, ...)
local arg = {...} local arg = {...}
check(arg, n, 0) check(arg, n, 0)
assert(select('#', ...) == n) assert(select('#', ...) == n)

View File

@ -9,12 +9,12 @@ local function checkerror (msg, f, ...)
end end
function f(s, p) local function f (s, p)
local i,e = string.find(s, p) local i,e = string.find(s, p)
if i then return string.sub(s, i, e) end if i then return string.sub(s, i, e) end
end end
a,b = string.find('', '') -- empty patterns are tricky local a,b = string.find('', '') -- empty patterns are tricky
assert(a == 1 and b == 0); assert(a == 1 and b == 0);
a,b = string.find('alo', '') a,b = string.find('alo', '')
assert(a == 1 and b == 0) assert(a == 1 and b == 0)
@ -88,7 +88,7 @@ assert(f("alo alo", "%C+") == "alo alo")
print('+') print('+')
function f1(s, p) local function f1 (s, p)
p = string.gsub(p, "%%([0-9])", function (s) p = string.gsub(p, "%%([0-9])", function (s)
return "%" .. (tonumber(s)+1) return "%" .. (tonumber(s)+1)
end) end)
@ -113,7 +113,7 @@ local abc = string.char(range(0, 127)) .. string.char(range(128, 255));
assert(string.len(abc) == 256) assert(string.len(abc) == 256)
function strset (p) local function strset (p)
local res = {s=''} local res = {s=''}
string.gsub(abc, p, function (c) res.s = res.s .. c end) string.gsub(abc, p, function (c) res.s = res.s .. c end)
return res.s return res.s
@ -147,7 +147,7 @@ assert(string.gsub('
assert(string.gsub('alo úlo ', ' +$', '') == 'alo úlo') -- trim assert(string.gsub('alo úlo ', ' +$', '') == 'alo úlo') -- trim
assert(string.gsub(' alo alo ', '^%s*(.-)%s*$', '%1') == 'alo alo') -- double trim assert(string.gsub(' alo alo ', '^%s*(.-)%s*$', '%1') == 'alo alo') -- double trim
assert(string.gsub('alo alo \n 123\n ', '%s+', ' ') == 'alo alo 123 ') assert(string.gsub('alo alo \n 123\n ', '%s+', ' ') == 'alo alo 123 ')
t = "abç d" local t = "abç d"
a, b = string.gsub(t, '(.)', '%1@') a, b = string.gsub(t, '(.)', '%1@')
assert('@'..a == string.gsub(t, '', '@') and b == 5) assert('@'..a == string.gsub(t, '', '@') and b == 5)
a, b = string.gsub('abçd', '(.)', '%0@', 2) a, b = string.gsub('abçd', '(.)', '%0@', 2)
@ -184,6 +184,7 @@ do
local function setglobal (n,v) rawset(_G, n, v) end local function setglobal (n,v) rawset(_G, n, v) end
string.gsub("a=roberto,roberto=a", "(%w+)=(%w%w*)", setglobal) string.gsub("a=roberto,roberto=a", "(%w+)=(%w%w*)", setglobal)
assert(_G.a=="roberto" and _G.roberto=="a") assert(_G.a=="roberto" and _G.roberto=="a")
_G.a = nil; _G.roberto = nil
end end
function f(a,b) return string.gsub(a,'.',b) end function f(a,b) return string.gsub(a,'.',b) end
@ -195,20 +196,21 @@ assert(string.gsub("alo $a='x'$ novamente $return a$",
"$([^$]*)%$", "$([^$]*)%$",
dostring) == "alo novamente x") dostring) == "alo novamente x")
x = string.gsub("$x=string.gsub('alo', '.', string.upper)$ assim vai para $return x$", local x = string.gsub("$x=string.gsub('alo', '.', string.upper)$ assim vai para $return x$",
"$([^$]*)%$", dostring) "$([^$]*)%$", dostring)
assert(x == ' assim vai para ALO') assert(x == ' assim vai para ALO')
_G.a, _G.x = nil
t = {} local t = {}
s = 'a alo jose joao' local s = 'a alo jose joao'
r = string.gsub(s, '()(%w+)()', function (a,w,b) local r = string.gsub(s, '()(%w+)()', function (a,w,b)
assert(string.len(w) == b-a); assert(string.len(w) == b-a);
t[a] = b-a; t[a] = b-a;
end) end)
assert(s == r and t[1] == 1 and t[3] == 3 and t[7] == 4 and t[13] == 4) assert(s == r and t[1] == 1 and t[3] == 3 and t[7] == 4 and t[13] == 4)
function isbalanced (s) local function isbalanced (s)
return not string.find(string.gsub(s, "%b()", ""), "[()]") return not string.find(string.gsub(s, "%b()", ""), "[()]")
end end
@ -251,7 +253,7 @@ if not _soft then
end end
-- recursive nest of gsubs -- recursive nest of gsubs
function rev (s) local function rev (s)
return string.gsub(s, "(.)(.+)", function (c,s1) return rev(s1)..c end) return string.gsub(s, "(.)(.+)", function (c,s1) return rev(s1)..c end)
end end

View File

@ -20,7 +20,7 @@ end
checkerror("wrong number of arguments", table.insert, {}, 2, 3, 4) checkerror("wrong number of arguments", table.insert, {}, 2, 3, 4)
local x,y,z,a,n local x,y,z,a,n
a = {}; lim = _soft and 200 or 2000 a = {}; local lim = _soft and 200 or 2000
for i=1, lim do a[i]=i end for i=1, lim do a[i]=i end
assert(select(lim, unpack(a)) == lim and select('#', unpack(a)) == lim) assert(select(lim, unpack(a)) == lim and select('#', unpack(a)) == lim)
x = unpack(a) x = unpack(a)
@ -222,7 +222,7 @@ a = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
table.sort(a) table.sort(a)
check(a) check(a)
function perm (s, n) local function perm (s, n)
n = n or #s n = n or #s
if n == 1 then if n == 1 then
local t = {unpack(s)} local t = {unpack(s)}
@ -248,7 +248,7 @@ perm{1,2,3,3,5}
perm{1,2,3,4,5,6} perm{1,2,3,4,5,6}
perm{2,2,3,3,5,6} perm{2,2,3,3,5,6}
function timesort (a, n, func, msg, pre) local function timesort (a, n, func, msg, pre)
local x = os.clock() local x = os.clock()
table.sort(a, func) table.sort(a, func)
x = (os.clock() - x) * 1000 x = (os.clock() - x) * 1000
@ -257,7 +257,7 @@ function timesort (a, n, func, msg, pre)
check(a, func) check(a, func)
end end
limit = 50000 local limit = 50000
if _soft then limit = 5000 end if _soft then limit = 5000 end
a = {} a = {}
@ -274,7 +274,7 @@ for i=1,limit do
a[i] = math.random() a[i] = math.random()
end end
x = os.clock(); i=0 local x = os.clock(); local i = 0
table.sort(a, function(x,y) i=i+1; return y<x end) table.sort(a, function(x,y) i=i+1; return y<x end)
x = (os.clock() - x) * 1000 x = (os.clock() - x) * 1000
print(string.format("Invert-sorting other %d elements in %.2f msec., with %i comparisons", print(string.format("Invert-sorting other %d elements in %.2f msec., with %i comparisons",
@ -289,18 +289,19 @@ timesort(a, limit, function(x,y) return nil end, "equal")
for i,v in pairs(a) do assert(v == false) end for i,v in pairs(a) do assert(v == false) end
A = {"álo", "\0first :-)", "alo", "then this one", "45", "and a new"} AA = {"álo", "\0first :-)", "alo", "then this one", "45", "and a new"}
table.sort(A) table.sort(AA)
check(A) check(AA)
table.sort(A, function (x, y) table.sort(AA, function (x, y)
load(string.format("A[%q] = ''", x), "")() load(string.format("AA[%q] = ''", x), "")()
collectgarbage() collectgarbage()
return x<y return x<y
end) end)
_G.AA = nil
tt = {__lt = function (a,b) return a.val < b.val end} local tt = {__lt = function (a,b) return a.val < b.val end}
a = {} a = {}
for i=1,10 do a[i] = {val=math.random(100)}; setmetatable(a[i], tt); end for i=1,10 do a[i] = {val=math.random(100)}; setmetatable(a[i], tt); end
table.sort(a) table.sort(a)

View File

@ -52,7 +52,7 @@ assert(("\000123456789"):sub(8) == "789")
-- testing string.find -- testing string.find
assert(string.find("123456789", "345") == 3) assert(string.find("123456789", "345") == 3)
a,b = string.find("123456789", "345") local a,b = string.find("123456789", "345")
assert(string.sub("123456789", a, b) == "345") assert(string.sub("123456789", a, b) == "345")
assert(string.find("1234567890123456789", "345", 3) == 3) assert(string.find("1234567890123456789", "345", 3) == 3)
assert(string.find("1234567890123456789", "345", 4) == 13) assert(string.find("1234567890123456789", "345", 4) == 13)
@ -192,7 +192,7 @@ do -- tests for '%p' format
end end
end end
x = '"ílo"\n\\' local x = '"ílo"\n\\'
assert(string.format('%q%s', x, x) == '"\\"ílo\\"\\\n\\\\""ílo"\n\\') assert(string.format('%q%s', x, x) == '"\\"ílo\\"\\\n\\\\""ílo"\n\\')
assert(string.format('%q', "\0") == [["\0"]]) assert(string.format('%q', "\0") == [["\0"]])
assert(load(string.format('return %q', x))() == x) assert(load(string.format('return %q', x))() == x)
@ -346,13 +346,18 @@ assert(string.format("%013i", -100) == "-000000000100")
assert(string.format("%2.5d", -100) == "-00100") assert(string.format("%2.5d", -100) == "-00100")
assert(string.format("%.u", 0) == "") assert(string.format("%.u", 0) == "")
assert(string.format("%+#014.0f", 100) == "+000000000100.") assert(string.format("%+#014.0f", 100) == "+000000000100.")
assert(string.format("% 1.0E", 100) == " 1E+02")
assert(string.format("%-16c", 97) == "a ") assert(string.format("%-16c", 97) == "a ")
assert(string.format("%+.3G", 1.5) == "+1.5") assert(string.format("%+.3G", 1.5) == "+1.5")
assert(string.format("% .1g", 2^10) == " 1e+03")
assert(string.format("%.0s", "alo") == "") assert(string.format("%.0s", "alo") == "")
assert(string.format("%.s", "alo") == "") assert(string.format("%.s", "alo") == "")
-- ISO C89 says that "The exponent always contains at least two digits",
-- but unlike ISO C99 it does not ensure that it contains "only as many
-- more digits as necessary".
assert(string.match(string.format("% 1.0E", 100), "^ 1E%+0+2$"))
assert(string.match(string.format("% .1g", 2^10), "^ 1e%+0+3$"))
-- errors in format -- errors in format
local function check (fmt, msg) local function check (fmt, msg)
@ -447,7 +452,7 @@ end
do do
local f = string.gmatch("1 2 3 4 5", "%d+") local f = string.gmatch("1 2 3 4 5", "%d+")
assert(f() == "1") assert(f() == "1")
co = coroutine.wrap(f) local co = coroutine.wrap(f)
assert(co() == "2") assert(co() == "2")
end end

View File

@ -35,7 +35,7 @@ print("\talignment: " .. align)
-- check errors in arguments -- check errors in arguments
function checkerror (msg, f, ...) local function checkerror (msg, f, ...)
local status, err = pcall(f, ...) local status, err = pcall(f, ...)
-- print(status, err, msg) -- print(status, err, msg)
assert(not status and string.find(err, msg)) assert(not status and string.find(err, msg))

View File

@ -97,9 +97,15 @@ do -- error indication in utf8.len
assert(not a and b == p) assert(not a and b == p)
end end
check("abc\xE3def", 4) check("abc\xE3def", 4)
check("汉字\x80", #("汉字") + 1)
check("\xF4\x9F\xBF", 1) check("\xF4\x9F\xBF", 1)
check("\xF4\x9F\xBF\xBF", 1) check("\xF4\x9F\xBF\xBF", 1)
-- spurious continuation bytes
check("汉字\x80", #("汉字") + 1)
check("\x80hello", 1)
check("hel\x80lo", 4)
check("汉字\xBF", #("汉字") + 1)
check("\xBFhello", 1)
check("hel\xBFlo", 4)
end end
-- errors in utf8.codes -- errors in utf8.codes
@ -112,12 +118,16 @@ do
end end
errorcodes("ab\xff") errorcodes("ab\xff")
errorcodes("\u{110000}") errorcodes("\u{110000}")
errorcodes("in\x80valid")
errorcodes("\xbfinvalid")
errorcodes("αλφ\xBFα")
-- calling interation function with invalid arguments -- calling interation function with invalid arguments
local f = utf8.codes("") local f = utf8.codes("")
assert(f("", 2) == nil) assert(f("", 2) == nil)
assert(f("", -1) == nil) assert(f("", -1) == nil)
assert(f("", math.mininteger) == nil) assert(f("", math.mininteger) == nil)
end end
-- error in initial position for offset -- error in initial position for offset
@ -220,7 +230,7 @@ do
check(s, {0x10000, 0x1FFFFF}, true) check(s, {0x10000, 0x1FFFFF}, true)
end end
x = "日本語a-4\0éó" local x = "日本語a-4\0éó"
check(x, {26085, 26412, 35486, 97, 45, 52, 0, 233, 243}) check(x, {26085, 26412, 35486, 97, 45, 52, 0, 233, 243})

View File

@ -3,13 +3,13 @@
print('testing vararg') print('testing vararg')
function f(a, ...) local function f (a, ...)
local x = {n = select('#', ...), ...} local x = {n = select('#', ...), ...}
for i = 1, x.n do assert(a[i] == x[i]) end for i = 1, x.n do assert(a[i] == x[i]) end
return x.n return x.n
end end
function c12 (...) local function c12 (...)
assert(arg == _G.arg) -- no local 'arg' assert(arg == _G.arg) -- no local 'arg'
local x = {...}; x.n = #x local x = {...}; x.n = #x
local res = (x.n==2 and x[1] == 1 and x[2] == 2) local res = (x.n==2 and x[1] == 1 and x[2] == 2)
@ -17,7 +17,7 @@ function c12 (...)
return res, 2 return res, 2
end end
function vararg (...) return {n = select('#', ...), ...} end local function vararg (...) return {n = select('#', ...), ...} end
local call = function (f, args) return f(table.unpack(args, 1, args.n)) end local call = function (f, args) return f(table.unpack(args, 1, args.n)) end
@ -29,7 +29,7 @@ assert(vararg().n == 0)
assert(vararg(nil, nil).n == 2) assert(vararg(nil, nil).n == 2)
assert(c12(1,2)==55) assert(c12(1,2)==55)
a,b = assert(call(c12, {1,2})) local a,b = assert(call(c12, {1,2}))
assert(a == 55 and b == 2) assert(a == 55 and b == 2)
a = call(c12, {1,2;n=2}) a = call(c12, {1,2;n=2})
assert(a == 55 and b == 2) assert(a == 55 and b == 2)
@ -49,7 +49,7 @@ function t:f (...) local arg = {...}; return self[...]+#arg end
assert(t:f(1,4) == 3 and t:f(2) == 11) assert(t:f(1,4) == 3 and t:f(2) == 11)
print('+') print('+')
lim = 20 local lim = 20
local i, a = 1, {} local i, a = 1, {}
while i <= lim do a[i] = i+0.3; i=i+1 end while i <= lim do a[i] = i+0.3; i=i+1 end
@ -59,7 +59,7 @@ function f(a, b, c, d, ...)
more[lim-4] == lim+0.3 and not more[lim-3]) more[lim-4] == lim+0.3 and not more[lim-3])
end end
function g(a,b,c) local function g (a,b,c)
assert(a == 1.3 and b == 2.3 and c == 3.3) assert(a == 1.3 and b == 2.3 and c == 3.3)
end end
@ -76,7 +76,7 @@ print("+")
-- new-style varargs -- new-style varargs
function oneless (a, ...) return ... end local function oneless (a, ...) return ... end
function f (n, a, ...) function f (n, a, ...)
local b local b
@ -99,8 +99,8 @@ assert(a==nil and b==nil and c==nil and d==nil and e==nil)
-- varargs for main chunks -- varargs for main chunks
f = load[[ return {...} ]] local f = load[[ return {...} ]]
x = f(2,3) local x = f(2,3)
assert(x[1] == 2 and x[2] == 3 and x[3] == undef) assert(x[1] == 2 and x[2] == 3 and x[3] == undef)

View File

@ -52,7 +52,7 @@ if _soft then return 10 end
print "testing large programs (>64k)" print "testing large programs (>64k)"
-- template to create a very big test file -- template to create a very big test file
prog = [[$ local prog = [[$
local a,b local a,b
@ -85,7 +85,7 @@ function b:xxx (a,b) return a+b end
assert(b:xxx(10, 12) == 22) -- pushself with non-constant index assert(b:xxx(10, 12) == 22) -- pushself with non-constant index
b["xxx"] = undef b["xxx"] = undef
s = 0; n=0 local s = 0; local n=0
for a,b in pairs(b) do s=s+b; n=n+1 end for a,b in pairs(b) do s=s+b; n=n+1 end
-- with 32-bit floats, exact value of 's' depends on summation order -- with 32-bit floats, exact value of 's' depends on summation order
assert(81800000.0 < s and s < 81860000 and n == 70001) assert(81800000.0 < s and s < 81860000 and n == 70001)
@ -93,7 +93,7 @@ assert(81800000.0 < s and s < 81860000 and n == 70001)
a = nil; b = nil a = nil; b = nil
print'+' print'+'
function f(x) b=x end local function f(x) b=x end
a = f{$3$} or 10 a = f{$3$} or 10
@ -118,7 +118,7 @@ local function sig (x)
return (x % 2 == 0) and '' or '-' return (x % 2 == 0) and '' or '-'
end end
F = { local F = {
function () -- $1$ function () -- $1$
for i=10,50009 do for i=10,50009 do
io.write('a', i, ' = ', sig(i), 5+((i-10)/2), ',\n') io.write('a', i, ' = ', sig(i), 5+((i-10)/2), ',\n')
@ -138,14 +138,14 @@ function () -- $3$
end, end,
} }
file = os.tmpname() local file = os.tmpname()
io.output(file) io.output(file)
for s in string.gmatch(prog, "$([^$]+)") do for s in string.gmatch(prog, "$([^$]+)") do
local n = tonumber(s) local n = tonumber(s)
if not n then io.write(s) else F[n]() end if not n then io.write(s) else F[n]() end
end end
io.close() io.close()
result = dofile(file) local result = dofile(file)
assert(os.remove(file)) assert(os.remove(file))
print'OK' print'OK'
return result return result

View File

@ -36,7 +36,7 @@ RM= rm -f
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE ======= # == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
# Convenience platforms targets. # Convenience platforms targets.
PLATS= guess aix bsd c89 freebsd generic linux linux-readline macosx mingw posix solaris PLATS= guess aix bsd c89 freebsd generic ios linux linux-readline macosx mingw posix solaris
# What to install. # What to install.
TO_BIN= lua luac TO_BIN= lua luac
@ -46,7 +46,7 @@ TO_MAN= lua.1 luac.1
# Lua version and release. # Lua version and release.
V= 5.4 V= 5.4
R= $V.4 R= $V.5
# Targets start here. # Targets start here.
all: $(PLAT) all: $(PLAT)

View File

@ -1,5 +1,5 @@
This is Lua 5.4.4, released on 13 Jan 2022. This is Lua 5.4.5, released on 18 Apr 2023.
For installation instructions, license details, and For installation instructions, license details, and
further information about Lua, see doc/readme.html. further information about Lua, see doc/readme.html.

View File

@ -32,7 +32,7 @@ For a complete introduction to Lua programming, see the book
<P> <P>
<SMALL> <SMALL>
Copyright &copy; 2020&ndash;2022 Lua.org, PUC-Rio. Copyright &copy; 2020&ndash;2023 Lua.org, PUC-Rio.
Freely available under the terms of the Freely available under the terms of the
<A HREF="http://www.lua.org/license.html">Lua license</A>. <A HREF="http://www.lua.org/license.html">Lua license</A>.
</SMALL> </SMALL>
@ -85,6 +85,8 @@ Freely available under the terms of the
<LI><A HREF="manual.html#3.4.9">3.4.9 &ndash; Table Constructors</A> <LI><A HREF="manual.html#3.4.9">3.4.9 &ndash; Table Constructors</A>
<LI><A HREF="manual.html#3.4.10">3.4.10 &ndash; Function Calls</A> <LI><A HREF="manual.html#3.4.10">3.4.10 &ndash; Function Calls</A>
<LI><A HREF="manual.html#3.4.11">3.4.11 &ndash; Function Definitions</A> <LI><A HREF="manual.html#3.4.11">3.4.11 &ndash; Function Definitions</A>
<LI><A HREF="manual.html#3.4.12">3.4.12 &ndash; Lists of expressions, multiple results, and adjustment<A>
</UL> </UL>
<LI><A HREF="manual.html#3.5">3.5 &ndash; Visibility Rules</A> <LI><A HREF="manual.html#3.5">3.5 &ndash; Visibility Rules</A>
</UL> </UL>
@ -613,7 +615,7 @@ Freely available under the terms of the
<A HREF="manual.html#pdf-LUA_HOOKLINE">LUA_HOOKLINE</A><BR> <A HREF="manual.html#pdf-LUA_HOOKLINE">LUA_HOOKLINE</A><BR>
<A HREF="manual.html#pdf-LUA_HOOKRET">LUA_HOOKRET</A><BR> <A HREF="manual.html#pdf-LUA_HOOKRET">LUA_HOOKRET</A><BR>
<A HREF="manual.html#pdf-LUA_HOOKTAILCALL">LUA_HOOKTAILCALL</A><BR> <A HREF="manual.html#pdf-LUA_HOOKTAILCALL">LUA_HOOKTAILCALL</A><BR>
<A HREF="manual.html#pdf-LUAL_BUFFERSIZE">LUAL_BUFFERSIZE</A><BR> <A HREF="manual.html#pdf-LUA_LOADED_TABLE">LUA_LOADED_TABLE</A><BR>
<A HREF="manual.html#pdf-LUA_MASKCALL">LUA_MASKCALL</A><BR> <A HREF="manual.html#pdf-LUA_MASKCALL">LUA_MASKCALL</A><BR>
<A HREF="manual.html#pdf-LUA_MASKCOUNT">LUA_MASKCOUNT</A><BR> <A HREF="manual.html#pdf-LUA_MASKCOUNT">LUA_MASKCOUNT</A><BR>
<A HREF="manual.html#pdf-LUA_MASKLINE">LUA_MASKLINE</A><BR> <A HREF="manual.html#pdf-LUA_MASKLINE">LUA_MASKLINE</A><BR>
@ -641,6 +643,7 @@ Freely available under the terms of the
<A HREF="manual.html#pdf-LUA_OPSHR">LUA_OPSHR</A><BR> <A HREF="manual.html#pdf-LUA_OPSHR">LUA_OPSHR</A><BR>
<A HREF="manual.html#pdf-LUA_OPSUB">LUA_OPSUB</A><BR> <A HREF="manual.html#pdf-LUA_OPSUB">LUA_OPSUB</A><BR>
<A HREF="manual.html#pdf-LUA_OPUNM">LUA_OPUNM</A><BR> <A HREF="manual.html#pdf-LUA_OPUNM">LUA_OPUNM</A><BR>
<A HREF="manual.html#pdf-LUA_PRELOAD_TABLE">LUA_PRELOAD_TABLE</A><BR>
<A HREF="manual.html#pdf-LUA_REFNIL">LUA_REFNIL</A><BR> <A HREF="manual.html#pdf-LUA_REFNIL">LUA_REFNIL</A><BR>
<A HREF="manual.html#pdf-LUA_REGISTRYINDEX">LUA_REGISTRYINDEX</A><BR> <A HREF="manual.html#pdf-LUA_REGISTRYINDEX">LUA_REGISTRYINDEX</A><BR>
<A HREF="manual.html#pdf-LUA_RIDX_GLOBALS">LUA_RIDX_GLOBALS</A><BR> <A HREF="manual.html#pdf-LUA_RIDX_GLOBALS">LUA_RIDX_GLOBALS</A><BR>
@ -657,6 +660,7 @@ Freely available under the terms of the
<A HREF="manual.html#pdf-LUA_TUSERDATA">LUA_TUSERDATA</A><BR> <A HREF="manual.html#pdf-LUA_TUSERDATA">LUA_TUSERDATA</A><BR>
<A HREF="manual.html#pdf-LUA_USE_APICHECK">LUA_USE_APICHECK</A><BR> <A HREF="manual.html#pdf-LUA_USE_APICHECK">LUA_USE_APICHECK</A><BR>
<A HREF="manual.html#pdf-LUA_YIELD">LUA_YIELD</A><BR> <A HREF="manual.html#pdf-LUA_YIELD">LUA_YIELD</A><BR>
<A HREF="manual.html#pdf-LUAL_BUFFERSIZE">LUAL_BUFFERSIZE</A><BR>
</TD> </TD>
</TR> </TR>
@ -664,10 +668,10 @@ Freely available under the terms of the
<P CLASS="footer"> <P CLASS="footer">
Last update: Last update:
Thu Jan 13 11:32:22 UTC 2022 Sat Apr 1 17:57:05 UTC 2023
</P> </P>
<!-- <!--
Last change: revised for Lua 5.4.4 Last change: revised for Lua 5.4.5
--> -->
</BODY> </BODY>

View File

Before

Width:  |  Height:  |  Size: 9.7 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

@ -1,5 +1,5 @@
.\" $Id: lua.man,v 1.14 2020/05/21 19:31:21 lhf Exp $ .\" $Id: lua.man,v 1.14 2022/09/23 09:06:36 lhf Exp $
.TH LUA 1 "$Date: 2020/05/21 19:31:21 $" .TH LUA 1 "$Date: 2022/09/23 09:06:36 $"
.SH NAME .SH NAME
lua \- Lua interpreter lua \- Lua interpreter
.SH SYNOPSIS .SH SYNOPSIS
@ -86,11 +86,17 @@ execute statement
enter interactive mode after executing enter interactive mode after executing
.IR script . .IR script .
.TP .TP
.BI \-l " name" .BI \-l " mod"
require library require library
.I name .I mod
into global into global
.IR name . .IR mod .
.TP
.BI \-l " g=mod"
require library
.I mod
into global
.IR g .
.TP .TP
.B \-v .B \-v
show version information. show version information.

View File

@ -19,7 +19,7 @@ by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes
<P> <P>
<SMALL> <SMALL>
Copyright &copy; 2020&ndash;2022 Lua.org, PUC-Rio. Copyright &copy; 2020&ndash;2023 Lua.org, PUC-Rio.
Freely available under the terms of the Freely available under the terms of the
<a href="http://www.lua.org/license.html">Lua license</a>. <a href="http://www.lua.org/license.html">Lua license</a>.
</SMALL> </SMALL>
@ -63,7 +63,7 @@ and rapid prototyping.
<p> <p>
Lua is implemented as a library, written in <em>clean C</em>, Lua is implemented as a library, written in <em>clean C</em>,
the common subset of Standard&nbsp;C and C++. the common subset of standard&nbsp;C and C++.
The Lua distribution includes a host program called <code>lua</code>, The Lua distribution includes a host program called <code>lua</code>,
which uses the Lua library to offer a complete, which uses the Lua library to offer a complete,
standalone Lua interpreter, standalone Lua interpreter,
@ -1379,7 +1379,9 @@ Lua also accepts hexadecimal constants,
which start with <code>0x</code> or <code>0X</code>. which start with <code>0x</code> or <code>0X</code>.
Hexadecimal constants also accept an optional fractional part Hexadecimal constants also accept an optional fractional part
plus an optional binary exponent, plus an optional binary exponent,
marked by a letter '<code>p</code>' or '<code>P</code>'. marked by a letter '<code>p</code>' or '<code>P</code>' and written in decimal.
(For instance, <code>0x1.fp10</code> denotes 1984,
which is <em>0x1f / 16</em> multiplied by <em>2<sup>10</sup></em>.)
<p> <p>
@ -1621,21 +1623,13 @@ Expressions are discussed in <a href="#3.4">&sect;3.4</a>.
<p> <p>
Before the assignment, Before the assignment,
the list of values is <em>adjusted</em> to the length of the list of values is <em>adjusted</em> to the length of
the list of variables. the list of variables (see <a href="#3.4.12">&sect;3.4.12</a>).
If there are more values than needed,
the excess values are thrown away.
If there are fewer values than needed,
the list is extended with <b>nil</b>'s.
If the list of expressions ends with a function call,
then all values returned by that call enter the list of values,
before the adjustment
(except when the call is enclosed in parentheses; see <a href="#3.4">&sect;3.4</a>).
<p> <p>
If a variable is both assigned and read If a variable is both assigned and read
inside a multiple assignment, inside a multiple assignment,
Lua ensures all reads get the value of the variable Lua ensures that all reads get the value of the variable
before the assignment. before the assignment.
Thus the code Thus the code
@ -1738,11 +1732,6 @@ where a label with the same name is visible,
even if this other label has been declared in an enclosing block. even if this other label has been declared in an enclosing block.
<p>
Labels and empty statements are called <em>void statements</em>,
as they perform no actions.
<p> <p>
The <b>break</b> statement terminates the execution of a The <b>break</b> statement terminates the execution of a
<b>while</b>, <b>repeat</b>, or <b>for</b> loop, <b>while</b>, <b>repeat</b>, or <b>for</b> loop,
@ -2059,7 +2048,7 @@ function calls are explained in <a href="#3.4.10">&sect;3.4.10</a>;
table constructors are explained in <a href="#3.4.9">&sect;3.4.9</a>. table constructors are explained in <a href="#3.4.9">&sect;3.4.9</a>.
Vararg expressions, Vararg expressions,
denoted by three dots ('<code>...</code>'), can only be used when denoted by three dots ('<code>...</code>'), can only be used when
directly inside a vararg function; directly inside a variadic function;
they are explained in <a href="#3.4.11">&sect;3.4.11</a>. they are explained in <a href="#3.4.11">&sect;3.4.11</a>.
@ -2074,52 +2063,6 @@ the unary logical <b>not</b> (see <a href="#3.4.5">&sect;3.4.5</a>),
and the unary <em>length operator</em> (see <a href="#3.4.7">&sect;3.4.7</a>). and the unary <em>length operator</em> (see <a href="#3.4.7">&sect;3.4.7</a>).
<p>
Both function calls and vararg expressions can result in multiple values.
If a function call is used as a statement (see <a href="#3.3.6">&sect;3.3.6</a>),
then its return list is adjusted to zero elements,
thus discarding all returned values.
If an expression is used as the last (or the only) element
of a list of expressions,
then no adjustment is made
(unless the expression is enclosed in parentheses).
In all other contexts,
Lua adjusts the result list to one element,
either discarding all values except the first one
or adding a single <b>nil</b> if there are no values.
<p>
Here are some examples:
<pre>
f() -- adjusted to 0 results
g(f(), x) -- f() is adjusted to 1 result
g(x, f()) -- g gets x plus all results from f()
a,b,c = f(), x -- f() is adjusted to 1 result (c gets nil)
a,b = ... -- a gets the first vararg argument, b gets
-- the second (both a and b can get nil if there
-- is no corresponding vararg argument)
a,b,c = x, f() -- f() is adjusted to 2 results
a,b,c = f() -- f() is adjusted to 3 results
return f() -- returns all results from f()
return ... -- returns all received vararg arguments
return x,y,f() -- returns x, y, and all results from f()
{f()} -- creates a list with all results from f()
{...} -- creates a list with all vararg arguments
{f(), nil} -- f() is adjusted to 1 result
</pre>
<p>
Any expression enclosed in parentheses always results in only one value.
Thus,
<code>(f(x,y,z))</code> is always a single value,
even if <code>f</code> returns several values.
(The value of <code>(f(x,y,z))</code> is the first value returned by <code>f</code>
or <b>nil</b> if <code>f</code> does not return any values.)
@ -2252,8 +2195,9 @@ Note that bitwise operators do not do this coercion.
<p> <p>
Nonetheless, it is always a good practice not to rely on these It is always a good practice not to rely on the
implicit coercions, as they are not always applied; implicit coercions from strings to numbers,
as they are not always applied;
in particular, <code>"1"==1</code> is false and <code>"1"&lt;1</code> raises an error in particular, <code>"1"==1</code> is false and <code>"1"&lt;1</code> raises an error
(see <a href="#3.4.4">&sect;3.4.4</a>). (see <a href="#3.4.4">&sect;3.4.4</a>).
These coercions exist mainly for compatibility and may be removed These coercions exist mainly for compatibility and may be removed
@ -2558,9 +2502,9 @@ The order of the assignments in a constructor is undefined.
<p> <p>
If the last field in the list has the form <code>exp</code> If the last field in the list has the form <code>exp</code>
and the expression is a function call or a vararg expression, and the expression is a multires expression,
then all values returned by this expression enter the list consecutively then all values returned by this expression enter the list consecutively
(see <a href="#3.4.10">&sect;3.4.10</a>). (see <a href="#3.4.12">&sect;3.4.12</a>).
<p> <p>
@ -2624,7 +2568,7 @@ A call of the form <code>return <em>functioncall</em></code> not in the
scope of a to-be-closed variable is called a <em>tail call</em>. scope of a to-be-closed variable is called a <em>tail call</em>.
Lua implements <em>proper tail calls</em> Lua implements <em>proper tail calls</em>
(or <em>proper tail recursion</em>): (or <em>proper tail recursion</em>):
in a tail call, In a tail call,
the called function reuses the stack entry of the calling function. the called function reuses the stack entry of the calling function.
Therefore, there is no limit on the number of nested tail calls that Therefore, there is no limit on the number of nested tail calls that
a program can execute. a program can execute.
@ -2727,22 +2671,16 @@ initialized with the argument values:
</pre><p> </pre><p>
When a Lua function is called, When a Lua function is called,
it adjusts its list of arguments to it adjusts its list of arguments to
the length of its list of parameters, the length of its list of parameters (see <a href="#3.4.12">&sect;3.4.12</a>),
unless the function is a <em>vararg function</em>, unless the function is a <em>variadic function</em>,
which is indicated by three dots ('<code>...</code>') which is indicated by three dots ('<code>...</code>')
at the end of its parameter list. at the end of its parameter list.
A vararg function does not adjust its argument list; A variadic function does not adjust its argument list;
instead, it collects all extra arguments and supplies them instead, it collects all extra arguments and supplies them
to the function through a <em>vararg expression</em>, to the function through a <em>vararg expression</em>,
which is also written as three dots. which is also written as three dots.
The value of this expression is a list of all actual extra arguments, The value of this expression is a list of all actual extra arguments,
similar to a function with multiple results. similar to a function with multiple results (see <a href="#3.4.12">&sect;3.4.12</a>).
If a vararg expression is used inside another expression
or in the middle of a list of expressions,
then its return list is adjusted to one element.
If the expression is used as the last element of a list of expressions,
then no adjustment is made
(unless that last expression is enclosed in parentheses).
<p> <p>
@ -2803,6 +2741,122 @@ is syntactic sugar for
<h3>3.4.12 &ndash; <a name="3.4.12">Lists of expressions, multiple results,
and adjustment</a></h3>
<p>
Both function calls and vararg expressions can result in multiple values.
These expressions are called <em>multires expressions</em>.
<p>
When a multires expression is used as the last element
of a list of expressions,
all results from the expression are added to the
list of values produced by the list of expressions.
Note that a single expression
in a place that expects a list of expressions
is the last expression in that (singleton) list.
<p>
These are the places where Lua expects a list of expressions:
<ul>
<li>A <b>return</b> statement,
for instance <code>return e1, e2, e3</code> (see <a href="#3.3.4">&sect;3.3.4</a>).</li>
<li>A table constructor,
for instance <code>{e1, e2, e3}</code> (see <a href="#3.4.9">&sect;3.4.9</a>).</li>
<li>The arguments of a function call,
for instance <code>foo(e1, e2, e3)</code> (see <a href="#3.4.10">&sect;3.4.10</a>).</li>
<li>A multiple assignment,
for instance <code>a , b, c = e1, e2, e3</code> (see <a href="#3.3.3">&sect;3.3.3</a>).</li>
<li>A local declaration,
for instance <code>local a , b, c = e1, e2, e3</code> (see <a href="#3.3.7">&sect;3.3.7</a>).</li>
<li>The initial values in a generic <b>for</b> loop,
for instance <code>for k in e1, e2, e3 do ... end</code> (see <a href="#3.3.5">&sect;3.3.5</a>).</li>
</ul><p>
In the last four cases,
the list of values from the list of expressions
must be <em>adjusted</em> to a specific length:
the number of parameters in a call to a non-variadic function
(see <a href="#3.4.11">&sect;3.4.11</a>),
the number of variables in a multiple assignment or
a local declaration,
and exactly four values for a generic <b>for</b> loop.
The <em>adjustment</em> follows these rules:
If there are more values than needed,
the extra values are thrown away;
if there are fewer values than needed,
the list is extended with <b>nil</b>'s.
When the list of expressions ends with a multires expression,
all results from that expression enter the list of values
before the adjustment.
<p>
When a multires expression is used
in a list of expressions without being the last element,
or in a place where the syntax expects a single expression,
Lua adjusts the result list of that expression to one element.
As a particular case,
the syntax expects a single expression inside a parenthesized expression;
therefore, adding parentheses around a multires expression
forces it to produce exactly one result.
<p>
We seldom need to use a vararg expression in a place
where the syntax expects a single expression.
(Usually it is simpler to add a regular parameter before
the variadic part and use that parameter.)
When there is such a need,
we recommend assigning the vararg expression
to a single variable and using that variable
in its place.
<p>
Here are some examples of uses of mutlres expressions.
In all cases, when the construction needs
"the n-th result" and there is no such result,
it uses a <b>nil</b>.
<pre>
print(x, f()) -- prints x and all results from f().
print(x, (f())) -- prints x and the first result from f().
print(f(), x) -- prints the first result from f() and x.
print(1 + f()) -- prints 1 added to the first result from f().
local x = ... -- x gets the first vararg argument.
x,y = ... -- x gets the first vararg argument,
-- y gets the second vararg argument.
x,y,z = w, f() -- x gets w, y gets the first result from f(),
-- z gets the second result from f().
x,y,z = f() -- x gets the first result from f(),
-- y gets the second result from f(),
-- z gets the third result from f().
x,y,z = f(), g() -- x gets the first result from f(),
-- y gets the first result from g(),
-- z gets the second result from g().
x,y,z = (f()) -- x gets the first result from f(), y and z get nil.
return f() -- returns all results from f().
return x, ... -- returns x and all received vararg arguments.
return x,y,f() -- returns x, y, and all results from f().
{f()} -- creates a list with all results from f().
{...} -- creates a list with all vararg arguments.
{f(), 5} -- creates a list with the first result from f() and 5.
</pre>
<h2>3.5 &ndash; <a name="3.5">Visibility Rules</a></h2> <h2>3.5 &ndash; <a name="3.5">Visibility Rules</a></h2>
@ -2813,6 +2867,7 @@ Lua is a lexically scoped language.
The scope of a local variable begins at the first statement after The scope of a local variable begins at the first statement after
its declaration and lasts until the last non-void statement its declaration and lasts until the last non-void statement
of the innermost block that includes the declaration. of the innermost block that includes the declaration.
(<em>Void statements</em> are labels and empty statements.)
Consider the following example: Consider the following example:
<pre> <pre>
@ -3071,7 +3126,7 @@ In general,
Lua's garbage collection can free or move internal memory Lua's garbage collection can free or move internal memory
and then invalidate pointers to internal strings. and then invalidate pointers to internal strings.
To allow a safe use of these pointers, To allow a safe use of these pointers,
The API guarantees that any pointer to a string in a stack index the API guarantees that any pointer to a string in a stack index
is valid while the string value at that index is not removed from the stack. is valid while the string value at that index is not removed from the stack.
(It can be moved to another index, though.) (It can be moved to another index, though.)
When the index is a pseudo-index (referring to an upvalue), When the index is a pseudo-index (referring to an upvalue),
@ -3537,7 +3592,7 @@ It is used in the auxiliary library by <a href="#luaL_newstate"><code>luaL_newst
return realloc(ptr, nsize); return realloc(ptr, nsize);
} }
</pre><p> </pre><p>
Note that Standard&nbsp;C ensures Note that ISO&nbsp;C ensures
that <code>free(NULL)</code> has no effect and that that <code>free(NULL)</code> has no effect and that
<code>realloc(NULL,size)</code> is equivalent to <code>malloc(size)</code>. <code>realloc(NULL,size)</code> is equivalent to <code>malloc(size)</code>.
@ -3785,8 +3840,7 @@ when called through this function.
<p> <p>
(Exceptionally, this function was introduced in release 5.4.3. (This function was introduced in release&nbsp;5.4.3.)
It is not present in previous 5.4 releases.)
@ -4542,7 +4596,7 @@ Pops a key from the stack,
and pushes a key&ndash;value pair from the table at the given index, and pushes a key&ndash;value pair from the table at the given index,
the "next" pair after the given key. the "next" pair after the given key.
If there are no more elements in the table, If there are no more elements in the table,
then <a href="#lua_next"><code>lua_next</code></a> returns 0 and pushes nothing. then <a href="#lua_next"><code>lua_next</code></a> returns&nbsp;0 and pushes nothing.
<p> <p>
@ -4985,6 +5039,7 @@ Also returns&nbsp;0 if any of the indices are not valid.
<p> <p>
Similar to <a href="#lua_gettable"><code>lua_gettable</code></a>, but does a raw access Similar to <a href="#lua_gettable"><code>lua_gettable</code></a>, but does a raw access
(i.e., without metamethods). (i.e., without metamethods).
The value at <code>index</code> must be a table.
@ -5051,6 +5106,7 @@ For other values, this call returns&nbsp;0.
<p> <p>
Similar to <a href="#lua_settable"><code>lua_settable</code></a>, but does a raw assignment Similar to <a href="#lua_settable"><code>lua_settable</code></a>, but does a raw assignment
(i.e., without metamethods). (i.e., without metamethods).
The value at <code>index</code> must be a table.
@ -5163,7 +5219,7 @@ and then pops the top element.
<hr><h3><a name="lua_resetthread"><code>lua_resetthread</code></a></h3><p> <hr><h3><a name="lua_resetthread"><code>lua_resetthread</code></a></h3><p>
<span class="apii">[-0, +?, &ndash;]</span> <span class="apii">[-0, +?, &ndash;]</span>
<pre>int lua_resetthread (lua_State *L);</pre> <pre>int lua_resetthread (lua_State *L, lua_State *from);</pre>
<p> <p>
Resets a thread, cleaning its call stack and closing all pending Resets a thread, cleaning its call stack and closing all pending
@ -5177,6 +5233,13 @@ In case of error,
leaves the error object on the top of the stack. leaves the error object on the top of the stack.
<p>
The parameter <code>from</code> represents the coroutine that is resetting <code>L</code>.
If there is no such coroutine,
this parameter can be <code>NULL</code>.
(This parameter was introduced in release&nbsp;5.4.5.)
@ -6033,7 +6096,7 @@ the number of parameters of the function
</li> </li>
<li><b><code>isvararg</code>: </b> <li><b><code>isvararg</code>: </b>
true if the function is a vararg function true if the function is a variadic function
(always true for C&nbsp;functions). (always true for C&nbsp;functions).
</li> </li>
@ -6773,7 +6836,7 @@ Equivalent to the sequence
<pre>void luaL_buffsub (luaL_Buffer *B, int n);</pre> <pre>void luaL_buffsub (luaL_Buffer *B, int n);</pre>
<p> <p>
Removes <code>n</code> bytes from the the buffer <code>B</code> Removes <code>n</code> bytes from the buffer <code>B</code>
(see <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>). (see <a href="#luaL_Buffer"><code>luaL_Buffer</code></a>).
The buffer must have at least that many bytes. The buffer must have at least that many bytes.
@ -6968,8 +7031,8 @@ It is defined as the following macro:
<pre> <pre>
(luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0)) (luaL_loadfile(L, filename) || lua_pcall(L, 0, LUA_MULTRET, 0))
</pre><p> </pre><p>
It returns <a href="#pdf-LUA_OK"><code>LUA_OK</code></a> if there are no errors, It returns&nbsp;0 (<a href="#pdf-LUA_OK"><code>LUA_OK</code></a>) if there are no errors,
or an error code in case of errors (see <a href="#4.4.1">&sect;4.4.1</a>). or 1 in case of errors.
@ -6986,8 +7049,8 @@ It is defined as the following macro:
<pre> <pre>
(luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0)) (luaL_loadstring(L, str) || lua_pcall(L, 0, LUA_MULTRET, 0))
</pre><p> </pre><p>
It returns <a href="#pdf-LUA_OK"><code>LUA_OK</code></a> if there are no errors, It returns&nbsp;0 (<a href="#pdf-LUA_OK"><code>LUA_OK</code></a>) if there are no errors,
or an error code in case of errors (see <a href="#4.4.1">&sect;4.4.1</a>). or 1 in case of errors.
@ -7294,7 +7357,7 @@ with <code>tname</code> in the registry.
<p> <p>
Creates a new Lua state. Creates a new Lua state.
It calls <a href="#lua_newstate"><code>lua_newstate</code></a> with an It calls <a href="#lua_newstate"><code>lua_newstate</code></a> with an
allocator based on the standard&nbsp;C allocation functions allocator based on the ISO&nbsp;C allocation functions
and then sets a warning function and a panic function (see <a href="#4.4">&sect;4.4</a>) and then sets a warning function and a panic function (see <a href="#4.4">&sect;4.4</a>)
that print messages to the standard error output. that print messages to the standard error output.
@ -7685,9 +7748,7 @@ to start the traceback.
<hr><h3><a name="luaL_typeerror"><code>luaL_typeerror</code></a></h3><p> <hr><h3><a name="luaL_typeerror"><code>luaL_typeerror</code></a></h3><p>
<span class="apii">[-0, +0, <em>v</em>]</span> <span class="apii">[-0, +0, <em>v</em>]</span>
<pre>const char *luaL_typeerror (lua_State *L, <pre>int luaL_typeerror (lua_State *L, int arg, const char *tname);</pre>
int arg,
const char *tname);</pre>
<p> <p>
Raises a type error for the argument <code>arg</code> Raises a type error for the argument <code>arg</code>
@ -8708,6 +8769,8 @@ When you require a module <code>modname</code> and
This variable is only a reference to the real table; This variable is only a reference to the real table;
assignments to this variable do not change the assignments to this variable do not change the
table used by <a href="#pdf-require"><code>require</code></a>. table used by <a href="#pdf-require"><code>require</code></a>.
The real table is stored in the C registry (see <a href="#4.3">&sect;4.3</a>),
indexed by the key <a name="pdf-LUA_LOADED_TABLE"><code>LUA_LOADED_TABLE</code></a>, a string.
@ -8745,7 +8808,7 @@ including if necessary a path and an extension.
<p> <p>
This function is not supported by Standard&nbsp;C. This functionality is not supported by ISO&nbsp;C.
As such, it is only available on some platforms As such, it is only available on some platforms
(Windows, Linux, Mac OS X, Solaris, BSD, (Windows, Linux, Mac OS X, Solaris, BSD,
plus other Unix systems that support the <code>dlfcn</code> standard). plus other Unix systems that support the <code>dlfcn</code> standard).
@ -8799,6 +8862,8 @@ A table to store loaders for specific modules
This variable is only a reference to the real table; This variable is only a reference to the real table;
assignments to this variable do not change the assignments to this variable do not change the
table used by <a href="#pdf-require"><code>require</code></a>. table used by <a href="#pdf-require"><code>require</code></a>.
The real table is stored in the C registry (see <a href="#4.3">&sect;4.3</a>),
indexed by the key <a name="pdf-LUA_PRELOAD_TABLE"><code>LUA_PRELOAD_TABLE</code></a>, a string.
@ -9311,7 +9376,7 @@ according to the format string <code>fmt</code> (see <a href="#6.4.2">&sect;6.4.
<p> <p>
Returns the size of a string resulting from <a href="#pdf-string.pack"><code>string.pack</code></a> Returns the length of a string resulting from <a href="#pdf-string.pack"><code>string.pack</code></a>
with the given format. with the given format.
The format string cannot have the variable-length options The format string cannot have the variable-length options
'<code>s</code>' or '<code>z</code>' (see <a href="#6.4.2">&sect;6.4.2</a>). '<code>s</code>' or '<code>z</code>' (see <a href="#6.4.2">&sect;6.4.2</a>).
@ -10093,7 +10158,7 @@ Returns the arc sine of <code>x</code> (in radians).
<p> <p>
Returns the arc tangent of <code>y/x</code> (in radians), Returns the arc tangent of <code>y/x</code> (in radians),
but uses the signs of both arguments to find the using the signs of both arguments to find the
quadrant of the result. quadrant of the result.
It also handles correctly the case of <code>x</code> being zero. It also handles correctly the case of <code>x</code> being zero.
@ -10953,7 +11018,7 @@ The default value for <code>code</code> is <b>true</b>.
<p> <p>
If the optional second argument <code>close</code> is true, If the optional second argument <code>close</code> is true,
closes the Lua state before exiting. the function closes the Lua state before exiting (see <a href="#lua_close"><code>lua_close</code></a>).
@ -11503,12 +11568,18 @@ The options are:
<li><b><code>-i</code>: </b> enter interactive mode after running <em>script</em>;</li> <li><b><code>-i</code>: </b> enter interactive mode after running <em>script</em>;</li>
<li><b><code>-l <em>mod</em></code>: </b> "require" <em>mod</em> and assign the <li><b><code>-l <em>mod</em></code>: </b> "require" <em>mod</em> and assign the
result to global <em>mod</em>;</li> result to global <em>mod</em>;</li>
<li><b><code>-l <em>g=mod</em></code>: </b> "require" <em>mod</em> and assign the
result to global <em>g</em>;</li>
<li><b><code>-v</code>: </b> print version information;</li> <li><b><code>-v</code>: </b> print version information;</li>
<li><b><code>-E</code>: </b> ignore environment variables;</li> <li><b><code>-E</code>: </b> ignore environment variables;</li>
<li><b><code>-W</code>: </b> turn warnings on;</li> <li><b><code>-W</code>: </b> turn warnings on;</li>
<li><b><code>--</code>: </b> stop handling options;</li> <li><b><code>--</code>: </b> stop handling options;</li>
<li><b><code>-</code>: </b> execute <code>stdin</code> as a file and stop handling options.</li> <li><b><code>-</code>: </b> execute <code>stdin</code> as a file and stop handling options.</li>
</ul><p> </ul><p>
(The form <code>-l <em>g=mod</em></code> was introduced in release&nbsp;5.4.4.)
<p>
After handling its options, <code>lua</code> runs the given <em>script</em>. After handling its options, <code>lua</code> runs the given <em>script</em>.
When called without arguments, When called without arguments,
<code>lua</code> behaves as <code>lua -v -i</code> <code>lua</code> behaves as <code>lua -v -i</code>
@ -11582,7 +11653,7 @@ If there is a script,
the script is called with arguments the script is called with arguments
<code>arg[1]</code>, &middot;&middot;&middot;, <code>arg[#arg]</code>. <code>arg[1]</code>, &middot;&middot;&middot;, <code>arg[#arg]</code>.
Like all chunks in Lua, Like all chunks in Lua,
the script is compiled as a vararg function. the script is compiled as a variadic function.
<p> <p>
@ -11949,10 +12020,10 @@ and LiteralString, see <a href="#3.1">&sect;3.1</a>.)
<P CLASS="footer"> <P CLASS="footer">
Last update: Last update:
Thu Jan 13 11:33:16 UTC 2022 Tue Apr 18 12:51:25 UTC 2023
</P> </P>
<!-- <!--
Last change: revised for Lua 5.4.4 Last change: revised for Lua 5.4.5
--> -->
</body></html> </body></html>

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -98,9 +98,6 @@ and
If you don't have the time or the inclination to compile Lua yourself, If you don't have the time or the inclination to compile Lua yourself,
get a binary from get a binary from
<A HREF="http://lua-users.org/wiki/LuaBinaries">LuaBinaries</A>. <A HREF="http://lua-users.org/wiki/LuaBinaries">LuaBinaries</A>.
Try also
<A HREF="http://luadist.org/">LuaDist</A>,
a multi-platform distribution of Lua that includes batteries.
<H3>Building Lua</H3> <H3>Building Lua</H3>
<P> <P>
@ -110,7 +107,7 @@ Here are the details.
<OL> <OL>
<LI> <LI>
Open a terminal window and move to Open a terminal window and move to
the top-level directory, which is named <TT>lua-5.4.4</TT>. the top-level directory, which is named <TT>lua-5.4.5</TT>.
The <TT>Makefile</TT> there controls both the build process and the installation process. The <TT>Makefile</TT> there controls both the build process and the installation process.
<P> <P>
<LI> <LI>
@ -121,7 +118,7 @@ The <TT>Makefile</TT> there controls both the build process and the installation
The platforms currently supported are: The platforms currently supported are:
<P> <P>
<P CLASS="display"> <P CLASS="display">
guess aix bsd c89 freebsd generic linux linux-readline macosx mingw posix solaris guess aix bsd c89 freebsd generic ios linux linux-readline macosx mingw posix solaris
</P> </P>
<P> <P>
If your platform is listed, just do "<KBD>make xxx</KBD>", where xxx If your platform is listed, just do "<KBD>make xxx</KBD>", where xxx
@ -303,7 +300,7 @@ For details, see
<A HREF="http://www.lua.org/license.html">this</A>. <A HREF="http://www.lua.org/license.html">this</A>.
<BLOCKQUOTE STYLE="padding-bottom: 0em"> <BLOCKQUOTE STYLE="padding-bottom: 0em">
Copyright &copy; 1994&ndash;2022 Lua.org, PUC-Rio. Copyright &copy; 1994&ndash;2023 Lua.org, PUC-Rio.
<P> <P>
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
@ -330,10 +327,10 @@ THE SOFTWARE.
<P CLASS="footer"> <P CLASS="footer">
Last update: Last update:
Mon Jan 3 09:54:18 UTC 2022 Mon Mar 27 21:22:06 UTC 2023
</P> </P>
<!-- <!--
Last change: revised for Lua 5.4.4 Last change: revised for Lua 5.4.5
--> -->
</BODY> </BODY>

View File

@ -18,14 +18,14 @@
#define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "4" #define LUA_VERSION_MINOR "4"
#define LUA_VERSION_RELEASE "4" #define LUA_VERSION_RELEASE "5"
#define LUA_VERSION_NUM 504 #define LUA_VERSION_NUM 504
#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 4) #define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 5)
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2022 Lua.org, PUC-Rio" #define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
@ -131,6 +131,16 @@ typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont); typedef void (*lua_WarnFunction) (void *ud, const char *msg, int tocont);
/*
** Type used by the debug API to collect debug information
*/
typedef struct lua_Debug lua_Debug;
/*
** Functions to be called by the debugger in specific events
*/
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
/* /*
@ -153,7 +163,7 @@ extern const char lua_ident[];
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud); LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L); LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L); LUA_API lua_State *(lua_newthread) (lua_State *L);
LUA_API int (lua_resetthread) (lua_State *L); LUA_API int (lua_resetthread) (lua_State *L, lua_State *from);
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf); LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
@ -442,12 +452,6 @@ LUA_API void (lua_closeslot) (lua_State *L, int idx);
#define LUA_MASKLINE (1 << LUA_HOOKLINE) #define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) #define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
typedef struct lua_Debug lua_Debug; /* activation record */
/* Functions to be called by the debugger in specific events */
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar); LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar); LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
@ -492,7 +496,7 @@ struct lua_Debug {
/****************************************************************************** /******************************************************************************
* Copyright (C) 1994-2022 Lua.org, PUC-Rio. * Copyright (C) 1994-2023 Lua.org, PUC-Rio.
* *
* Permission is hereby granted, free of charge, to any person obtaining * Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the * a copy of this software and associated documentation files (the

View File

@ -70,6 +70,12 @@
#endif #endif
#if defined(LUA_USE_IOS)
#define LUA_USE_POSIX
#define LUA_USE_DLOPEN
#endif
/* /*
@@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits. @@ LUAI_IS32INT is true iff 'int' has (at least) 32 bits.
*/ */
@ -728,7 +734,7 @@
** CHANGE it if you need a different limit. This limit is arbitrary; ** CHANGE it if you need a different limit. This limit is arbitrary;
** its only purpose is to stop Lua from consuming unlimited stack ** its only purpose is to stop Lua from consuming unlimited stack
** space (and to reserve some numbers for pseudo-indices). ** space (and to reserve some numbers for pseudo-indices).
** (It must fit into max(size_t)/32.) ** (It must fit into max(size_t)/32 and max(int)/2.)
*/ */
#if LUAI_IS32INT #if LUAI_IS32INT
#define LUAI_MAXSTACK 1000000 #define LUAI_MAXSTACK 1000000
@ -747,14 +753,15 @@
/* /*
@@ LUA_IDSIZE gives the maximum size for the description of the source @@ LUA_IDSIZE gives the maximum size for the description of the source
@@ of a function in debug information. ** of a function in debug information.
** CHANGE it if you want a different size. ** CHANGE it if you want a different size.
*/ */
#define LUA_IDSIZE 60 #define LUA_IDSIZE 60
/* /*
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system. @@ LUAL_BUFFERSIZE is the initial buffer size used by the lauxlib
** buffer system.
*/ */
#define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number))) #define LUAL_BUFFERSIZE ((int)(16 * sizeof(void*) * sizeof(lua_Number)))

View File

@ -30,7 +30,7 @@ CMCFLAGS=
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE ======= # == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
PLATS= guess aix bsd c89 freebsd generic linux linux-readline macosx mingw posix solaris PLATS= guess aix bsd c89 freebsd generic ios linux linux-readline macosx mingw posix solaris
LUA_A= liblua.a LUA_A= liblua.a
CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o CORE_O= lapi.o lcode.o lctype.o ldebug.o ldo.o ldump.o lfunc.o lgc.o llex.o lmem.o lobject.o lopcodes.o lparser.o lstate.o lstring.o ltable.o ltm.o lundump.o lvm.o lzio.o
@ -117,6 +117,9 @@ FreeBSD NetBSD OpenBSD freebsd:
generic: $(ALL) generic: $(ALL)
ios:
$(MAKE) $(ALL) SYSCFLAGS="-DLUA_USE_IOS"
Linux linux: linux-noreadline Linux linux: linux-noreadline
linux-noreadline: linux-noreadline:

View File

@ -60,27 +60,28 @@ const char lua_ident[] =
static TValue *index2value (lua_State *L, int idx) { static TValue *index2value (lua_State *L, int idx) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
if (idx > 0) { if (idx > 0) {
StkId o = ci->func + idx; StkId o = ci->func.p + idx;
api_check(L, idx <= L->ci->top - (ci->func + 1), "unacceptable index"); api_check(L, idx <= ci->top.p - (ci->func.p + 1), "unacceptable index");
if (o >= L->top) return &G(L)->nilvalue; if (o >= L->top.p) return &G(L)->nilvalue;
else return s2v(o); else return s2v(o);
} }
else if (!ispseudo(idx)) { /* negative index */ else if (!ispseudo(idx)) { /* negative index */
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
return s2v(L->top + idx); "invalid index");
return s2v(L->top.p + idx);
} }
else if (idx == LUA_REGISTRYINDEX) else if (idx == LUA_REGISTRYINDEX)
return &G(L)->l_registry; return &G(L)->l_registry;
else { /* upvalues */ else { /* upvalues */
idx = LUA_REGISTRYINDEX - idx; idx = LUA_REGISTRYINDEX - idx;
api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large"); api_check(L, idx <= MAXUPVAL + 1, "upvalue index too large");
if (ttisCclosure(s2v(ci->func))) { /* C closure? */ if (ttisCclosure(s2v(ci->func.p))) { /* C closure? */
CClosure *func = clCvalue(s2v(ci->func)); CClosure *func = clCvalue(s2v(ci->func.p));
return (idx <= func->nupvalues) ? &func->upvalue[idx-1] return (idx <= func->nupvalues) ? &func->upvalue[idx-1]
: &G(L)->nilvalue; : &G(L)->nilvalue;
} }
else { /* light C function or Lua function (through a hook)?) */ else { /* light C function or Lua function (through a hook)?) */
api_check(L, ttislcf(s2v(ci->func)), "caller not a C function"); api_check(L, ttislcf(s2v(ci->func.p)), "caller not a C function");
return &G(L)->nilvalue; /* no upvalues */ return &G(L)->nilvalue; /* no upvalues */
} }
} }
@ -94,14 +95,15 @@ static TValue *index2value (lua_State *L, int idx) {
l_sinline StkId index2stack (lua_State *L, int idx) { l_sinline StkId index2stack (lua_State *L, int idx) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
if (idx > 0) { if (idx > 0) {
StkId o = ci->func + idx; StkId o = ci->func.p + idx;
api_check(L, o < L->top, "invalid index"); api_check(L, o < L->top.p, "invalid index");
return o; return o;
} }
else { /* non-positive index */ else { /* non-positive index */
api_check(L, idx != 0 && -idx <= L->top - (ci->func + 1), "invalid index"); api_check(L, idx != 0 && -idx <= L->top.p - (ci->func.p + 1),
"invalid index");
api_check(L, !ispseudo(idx), "invalid index"); api_check(L, !ispseudo(idx), "invalid index");
return L->top + idx; return L->top.p + idx;
} }
} }
@ -112,17 +114,12 @@ LUA_API int lua_checkstack (lua_State *L, int n) {
lua_lock(L); lua_lock(L);
ci = L->ci; ci = L->ci;
api_check(L, n >= 0, "negative 'n'"); api_check(L, n >= 0, "negative 'n'");
if (L->stack_last - L->top > n) /* stack large enough? */ if (L->stack_last.p - L->top.p > n) /* stack large enough? */
res = 1; /* yes; check is OK */ res = 1; /* yes; check is OK */
else { /* no; need to grow stack */ else /* need to grow stack */
int inuse = cast_int(L->top - L->stack) + EXTRA_STACK;
if (inuse > LUAI_MAXSTACK - n) /* can grow without overflow? */
res = 0; /* no */
else /* try to grow stack */
res = luaD_growstack(L, n, 0); res = luaD_growstack(L, n, 0);
} if (res && ci->top.p < L->top.p + n)
if (res && ci->top < L->top + n) ci->top.p = L->top.p + n; /* adjust frame top */
ci->top = L->top + n; /* adjust frame top */
lua_unlock(L); lua_unlock(L);
return res; return res;
} }
@ -134,11 +131,11 @@ LUA_API void lua_xmove (lua_State *from, lua_State *to, int n) {
lua_lock(to); lua_lock(to);
api_checknelems(from, n); api_checknelems(from, n);
api_check(from, G(from) == G(to), "moving among independent states"); api_check(from, G(from) == G(to), "moving among independent states");
api_check(from, to->ci->top - to->top >= n, "stack overflow"); api_check(from, to->ci->top.p - to->top.p >= n, "stack overflow");
from->top -= n; from->top.p -= n;
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
setobjs2s(to, to->top, from->top + i); setobjs2s(to, to->top.p, from->top.p + i);
to->top++; /* stack already checked by previous 'api_check' */ to->top.p++; /* stack already checked by previous 'api_check' */
} }
lua_unlock(to); lua_unlock(to);
} }
@ -172,12 +169,12 @@ LUA_API lua_Number lua_version (lua_State *L) {
LUA_API int lua_absindex (lua_State *L, int idx) { LUA_API int lua_absindex (lua_State *L, int idx) {
return (idx > 0 || ispseudo(idx)) return (idx > 0 || ispseudo(idx))
? idx ? idx
: cast_int(L->top - L->ci->func) + idx; : cast_int(L->top.p - L->ci->func.p) + idx;
} }
LUA_API int lua_gettop (lua_State *L) { LUA_API int lua_gettop (lua_State *L) {
return cast_int(L->top - (L->ci->func + 1)); return cast_int(L->top.p - (L->ci->func.p + 1));
} }
@ -187,24 +184,24 @@ LUA_API void lua_settop (lua_State *L, int idx) {
ptrdiff_t diff; /* difference for new top */ ptrdiff_t diff; /* difference for new top */
lua_lock(L); lua_lock(L);
ci = L->ci; ci = L->ci;
func = ci->func; func = ci->func.p;
if (idx >= 0) { if (idx >= 0) {
api_check(L, idx <= ci->top - (func + 1), "new top too large"); api_check(L, idx <= ci->top.p - (func + 1), "new top too large");
diff = ((func + 1) + idx) - L->top; diff = ((func + 1) + idx) - L->top.p;
for (; diff > 0; diff--) for (; diff > 0; diff--)
setnilvalue(s2v(L->top++)); /* clear new slots */ setnilvalue(s2v(L->top.p++)); /* clear new slots */
} }
else { else {
api_check(L, -(idx+1) <= (L->top - (func + 1)), "invalid new top"); api_check(L, -(idx+1) <= (L->top.p - (func + 1)), "invalid new top");
diff = idx + 1; /* will "subtract" index (as it is negative) */ diff = idx + 1; /* will "subtract" index (as it is negative) */
} }
api_check(L, L->tbclist < L->top, "previous pop of an unclosed slot"); api_check(L, L->tbclist.p < L->top.p, "previous pop of an unclosed slot");
newtop = L->top + diff; newtop = L->top.p + diff;
if (diff < 0 && L->tbclist >= newtop) { if (diff < 0 && L->tbclist.p >= newtop) {
lua_assert(hastocloseCfunc(ci->nresults)); lua_assert(hastocloseCfunc(ci->nresults));
luaF_close(L, newtop, CLOSEKTOP, 0); newtop = luaF_close(L, newtop, CLOSEKTOP, 0);
} }
L->top = newtop; /* correct top only after closing any upvalue */ L->top.p = newtop; /* correct top only after closing any upvalue */
lua_unlock(L); lua_unlock(L);
} }
@ -213,10 +210,9 @@ LUA_API void lua_closeslot (lua_State *L, int idx) {
StkId level; StkId level;
lua_lock(L); lua_lock(L);
level = index2stack(L, idx); level = index2stack(L, idx);
api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist == level, api_check(L, hastocloseCfunc(L->ci->nresults) && L->tbclist.p == level,
"no variable to close at given level"); "no variable to close at given level");
luaF_close(L, level, CLOSEKTOP, 0); level = luaF_close(L, level, CLOSEKTOP, 0);
level = index2stack(L, idx); /* stack may be moved */
setnilvalue(s2v(level)); setnilvalue(s2v(level));
lua_unlock(L); lua_unlock(L);
} }
@ -245,7 +241,7 @@ l_sinline void reverse (lua_State *L, StkId from, StkId to) {
LUA_API void lua_rotate (lua_State *L, int idx, int n) { LUA_API void lua_rotate (lua_State *L, int idx, int n) {
StkId p, t, m; StkId p, t, m;
lua_lock(L); lua_lock(L);
t = L->top - 1; /* end of stack segment being rotated */ t = L->top.p - 1; /* end of stack segment being rotated */
p = index2stack(L, idx); /* start of segment */ p = index2stack(L, idx); /* start of segment */
api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'"); api_check(L, (n >= 0 ? n : -n) <= (t - p + 1), "invalid 'n'");
m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */ m = (n >= 0 ? t - n : p - n - 1); /* end of prefix */
@ -264,7 +260,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
api_check(L, isvalid(L, to), "invalid index"); api_check(L, isvalid(L, to), "invalid index");
setobj(L, to, fr); setobj(L, to, fr);
if (isupvalue(toidx)) /* function upvalue? */ if (isupvalue(toidx)) /* function upvalue? */
luaC_barrier(L, clCvalue(s2v(L->ci->func)), fr); luaC_barrier(L, clCvalue(s2v(L->ci->func.p)), fr);
/* LUA_REGISTRYINDEX does not need gc barrier /* LUA_REGISTRYINDEX does not need gc barrier
(collector revisits it before finishing collection) */ (collector revisits it before finishing collection) */
lua_unlock(L); lua_unlock(L);
@ -273,7 +269,7 @@ LUA_API void lua_copy (lua_State *L, int fromidx, int toidx) {
LUA_API void lua_pushvalue (lua_State *L, int idx) { LUA_API void lua_pushvalue (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
setobj2s(L, L->top, index2value(L, idx)); setobj2s(L, L->top.p, index2value(L, idx));
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -342,12 +338,12 @@ LUA_API void lua_arith (lua_State *L, int op) {
api_checknelems(L, 2); /* all other operations expect two operands */ api_checknelems(L, 2); /* all other operations expect two operands */
else { /* for unary operations, add fake 2nd operand */ else { /* for unary operations, add fake 2nd operand */
api_checknelems(L, 1); api_checknelems(L, 1);
setobjs2s(L, L->top, L->top - 1); setobjs2s(L, L->top.p, L->top.p - 1);
api_incr_top(L); api_incr_top(L);
} }
/* first operand at top - 2, second at top - 1; result go to top - 2 */ /* first operand at top - 2, second at top - 1; result go to top - 2 */
luaO_arith(L, op, s2v(L->top - 2), s2v(L->top - 1), L->top - 2); luaO_arith(L, op, s2v(L->top.p - 2), s2v(L->top.p - 1), L->top.p - 2);
L->top--; /* remove second operand */ L->top.p--; /* remove second operand */
lua_unlock(L); lua_unlock(L);
} }
@ -373,7 +369,7 @@ LUA_API int lua_compare (lua_State *L, int index1, int index2, int op) {
LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) { LUA_API size_t lua_stringtonumber (lua_State *L, const char *s) {
size_t sz = luaO_str2num(s, s2v(L->top)); size_t sz = luaO_str2num(s, s2v(L->top.p));
if (sz != 0) if (sz != 0)
api_incr_top(L); api_incr_top(L);
return sz; return sz;
@ -500,7 +496,7 @@ LUA_API const void *lua_topointer (lua_State *L, int idx) {
LUA_API void lua_pushnil (lua_State *L) { LUA_API void lua_pushnil (lua_State *L) {
lua_lock(L); lua_lock(L);
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -508,7 +504,7 @@ LUA_API void lua_pushnil (lua_State *L) {
LUA_API void lua_pushnumber (lua_State *L, lua_Number n) { LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
lua_lock(L); lua_lock(L);
setfltvalue(s2v(L->top), n); setfltvalue(s2v(L->top.p), n);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -516,7 +512,7 @@ LUA_API void lua_pushnumber (lua_State *L, lua_Number n) {
LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) { LUA_API void lua_pushinteger (lua_State *L, lua_Integer n) {
lua_lock(L); lua_lock(L);
setivalue(s2v(L->top), n); setivalue(s2v(L->top.p), n);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -531,7 +527,7 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
TString *ts; TString *ts;
lua_lock(L); lua_lock(L);
ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len); ts = (len == 0) ? luaS_new(L, "") : luaS_newlstr(L, s, len);
setsvalue2s(L, L->top, ts); setsvalue2s(L, L->top.p, ts);
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L); luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
@ -542,11 +538,11 @@ LUA_API const char *lua_pushlstring (lua_State *L, const char *s, size_t len) {
LUA_API const char *lua_pushstring (lua_State *L, const char *s) { LUA_API const char *lua_pushstring (lua_State *L, const char *s) {
lua_lock(L); lua_lock(L);
if (s == NULL) if (s == NULL)
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
else { else {
TString *ts; TString *ts;
ts = luaS_new(L, s); ts = luaS_new(L, s);
setsvalue2s(L, L->top, ts); setsvalue2s(L, L->top.p, ts);
s = getstr(ts); /* internal copy's address */ s = getstr(ts); /* internal copy's address */
} }
api_incr_top(L); api_incr_top(L);
@ -583,7 +579,7 @@ LUA_API const char *lua_pushfstring (lua_State *L, const char *fmt, ...) {
LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) { LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
lua_lock(L); lua_lock(L);
if (n == 0) { if (n == 0) {
setfvalue(s2v(L->top), fn); setfvalue(s2v(L->top.p), fn);
api_incr_top(L); api_incr_top(L);
} }
else { else {
@ -592,13 +588,13 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
api_check(L, n <= MAXUPVAL, "upvalue index too large"); api_check(L, n <= MAXUPVAL, "upvalue index too large");
cl = luaF_newCclosure(L, n); cl = luaF_newCclosure(L, n);
cl->f = fn; cl->f = fn;
L->top -= n; L->top.p -= n;
while (n--) { while (n--) {
setobj2n(L, &cl->upvalue[n], s2v(L->top + n)); setobj2n(L, &cl->upvalue[n], s2v(L->top.p + n));
/* does not need barrier because closure is white */ /* does not need barrier because closure is white */
lua_assert(iswhite(cl)); lua_assert(iswhite(cl));
} }
setclCvalue(L, s2v(L->top), cl); setclCvalue(L, s2v(L->top.p), cl);
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L); luaC_checkGC(L);
} }
@ -609,9 +605,9 @@ LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
LUA_API void lua_pushboolean (lua_State *L, int b) { LUA_API void lua_pushboolean (lua_State *L, int b) {
lua_lock(L); lua_lock(L);
if (b) if (b)
setbtvalue(s2v(L->top)); setbtvalue(s2v(L->top.p));
else else
setbfvalue(s2v(L->top)); setbfvalue(s2v(L->top.p));
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -619,7 +615,7 @@ LUA_API void lua_pushboolean (lua_State *L, int b) {
LUA_API void lua_pushlightuserdata (lua_State *L, void *p) { LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
lua_lock(L); lua_lock(L);
setpvalue(s2v(L->top), p); setpvalue(s2v(L->top.p), p);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -627,7 +623,7 @@ LUA_API void lua_pushlightuserdata (lua_State *L, void *p) {
LUA_API int lua_pushthread (lua_State *L) { LUA_API int lua_pushthread (lua_State *L) {
lua_lock(L); lua_lock(L);
setthvalue(L, s2v(L->top), L); setthvalue(L, s2v(L->top.p), L);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
return (G(L)->mainthread == L); return (G(L)->mainthread == L);
@ -644,16 +640,16 @@ l_sinline int auxgetstr (lua_State *L, const TValue *t, const char *k) {
const TValue *slot; const TValue *slot;
TString *str = luaS_new(L, k); TString *str = luaS_new(L, k);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) { if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
setobj2s(L, L->top, slot); setobj2s(L, L->top.p, slot);
api_incr_top(L); api_incr_top(L);
} }
else { else {
setsvalue2s(L, L->top, str); setsvalue2s(L, L->top.p, str);
api_incr_top(L); api_incr_top(L);
luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot); luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
} }
lua_unlock(L); lua_unlock(L);
return ttype(s2v(L->top - 1)); return ttype(s2v(L->top.p - 1));
} }
@ -680,13 +676,13 @@ LUA_API int lua_gettable (lua_State *L, int idx) {
TValue *t; TValue *t;
lua_lock(L); lua_lock(L);
t = index2value(L, idx); t = index2value(L, idx);
if (luaV_fastget(L, t, s2v(L->top - 1), slot, luaH_get)) { if (luaV_fastget(L, t, s2v(L->top.p - 1), slot, luaH_get)) {
setobj2s(L, L->top - 1, slot); setobj2s(L, L->top.p - 1, slot);
} }
else else
luaV_finishget(L, t, s2v(L->top - 1), L->top - 1, slot); luaV_finishget(L, t, s2v(L->top.p - 1), L->top.p - 1, slot);
lua_unlock(L); lua_unlock(L);
return ttype(s2v(L->top - 1)); return ttype(s2v(L->top.p - 1));
} }
@ -702,27 +698,27 @@ LUA_API int lua_geti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L); lua_lock(L);
t = index2value(L, idx); t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) { if (luaV_fastgeti(L, t, n, slot)) {
setobj2s(L, L->top, slot); setobj2s(L, L->top.p, slot);
} }
else { else {
TValue aux; TValue aux;
setivalue(&aux, n); setivalue(&aux, n);
luaV_finishget(L, t, &aux, L->top, slot); luaV_finishget(L, t, &aux, L->top.p, slot);
} }
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
return ttype(s2v(L->top - 1)); return ttype(s2v(L->top.p - 1));
} }
l_sinline int finishrawget (lua_State *L, const TValue *val) { l_sinline int finishrawget (lua_State *L, const TValue *val) {
if (isempty(val)) /* avoid copying empty items to the stack */ if (isempty(val)) /* avoid copying empty items to the stack */
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
else else
setobj2s(L, L->top, val); setobj2s(L, L->top.p, val);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
return ttype(s2v(L->top - 1)); return ttype(s2v(L->top.p - 1));
} }
@ -739,8 +735,8 @@ LUA_API int lua_rawget (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
t = gettable(L, idx); t = gettable(L, idx);
val = luaH_get(t, s2v(L->top - 1)); val = luaH_get(t, s2v(L->top.p - 1));
L->top--; /* remove key */ L->top.p--; /* remove key */
return finishrawget(L, val); return finishrawget(L, val);
} }
@ -767,7 +763,7 @@ LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
Table *t; Table *t;
lua_lock(L); lua_lock(L);
t = luaH_new(L); t = luaH_new(L);
sethvalue2s(L, L->top, t); sethvalue2s(L, L->top.p, t);
api_incr_top(L); api_incr_top(L);
if (narray > 0 || nrec > 0) if (narray > 0 || nrec > 0)
luaH_resize(L, t, narray, nrec); luaH_resize(L, t, narray, nrec);
@ -794,7 +790,7 @@ LUA_API int lua_getmetatable (lua_State *L, int objindex) {
break; break;
} }
if (mt != NULL) { if (mt != NULL) {
sethvalue2s(L, L->top, mt); sethvalue2s(L, L->top.p, mt);
api_incr_top(L); api_incr_top(L);
res = 1; res = 1;
} }
@ -810,12 +806,12 @@ LUA_API int lua_getiuservalue (lua_State *L, int idx, int n) {
o = index2value(L, idx); o = index2value(L, idx);
api_check(L, ttisfulluserdata(o), "full userdata expected"); api_check(L, ttisfulluserdata(o), "full userdata expected");
if (n <= 0 || n > uvalue(o)->nuvalue) { if (n <= 0 || n > uvalue(o)->nuvalue) {
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
t = LUA_TNONE; t = LUA_TNONE;
} }
else { else {
setobj2s(L, L->top, &uvalue(o)->uv[n - 1].uv); setobj2s(L, L->top.p, &uvalue(o)->uv[n - 1].uv);
t = ttype(s2v(L->top)); t = ttype(s2v(L->top.p));
} }
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
@ -835,14 +831,14 @@ static void auxsetstr (lua_State *L, const TValue *t, const char *k) {
TString *str = luaS_new(L, k); TString *str = luaS_new(L, k);
api_checknelems(L, 1); api_checknelems(L, 1);
if (luaV_fastget(L, t, str, slot, luaH_getstr)) { if (luaV_fastget(L, t, str, slot, luaH_getstr)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1)); luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
L->top--; /* pop value */ L->top.p--; /* pop value */
} }
else { else {
setsvalue2s(L, L->top, str); /* push 'str' (to make it a TValue) */ setsvalue2s(L, L->top.p, str); /* push 'str' (to make it a TValue) */
api_incr_top(L); api_incr_top(L);
luaV_finishset(L, t, s2v(L->top - 1), s2v(L->top - 2), slot); luaV_finishset(L, t, s2v(L->top.p - 1), s2v(L->top.p - 2), slot);
L->top -= 2; /* pop value and key */ L->top.p -= 2; /* pop value and key */
} }
lua_unlock(L); /* lock done by caller */ lua_unlock(L); /* lock done by caller */
} }
@ -862,12 +858,12 @@ LUA_API void lua_settable (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 2); api_checknelems(L, 2);
t = index2value(L, idx); t = index2value(L, idx);
if (luaV_fastget(L, t, s2v(L->top - 2), slot, luaH_get)) { if (luaV_fastget(L, t, s2v(L->top.p - 2), slot, luaH_get)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1)); luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
} }
else else
luaV_finishset(L, t, s2v(L->top - 2), s2v(L->top - 1), slot); luaV_finishset(L, t, s2v(L->top.p - 2), s2v(L->top.p - 1), slot);
L->top -= 2; /* pop index and value */ L->top.p -= 2; /* pop index and value */
lua_unlock(L); lua_unlock(L);
} }
@ -885,14 +881,14 @@ LUA_API void lua_seti (lua_State *L, int idx, lua_Integer n) {
api_checknelems(L, 1); api_checknelems(L, 1);
t = index2value(L, idx); t = index2value(L, idx);
if (luaV_fastgeti(L, t, n, slot)) { if (luaV_fastgeti(L, t, n, slot)) {
luaV_finishfastset(L, t, slot, s2v(L->top - 1)); luaV_finishfastset(L, t, slot, s2v(L->top.p - 1));
} }
else { else {
TValue aux; TValue aux;
setivalue(&aux, n); setivalue(&aux, n);
luaV_finishset(L, t, &aux, s2v(L->top - 1), slot); luaV_finishset(L, t, &aux, s2v(L->top.p - 1), slot);
} }
L->top--; /* pop value */ L->top.p--; /* pop value */
lua_unlock(L); lua_unlock(L);
} }
@ -902,16 +898,16 @@ static void aux_rawset (lua_State *L, int idx, TValue *key, int n) {
lua_lock(L); lua_lock(L);
api_checknelems(L, n); api_checknelems(L, n);
t = gettable(L, idx); t = gettable(L, idx);
luaH_set(L, t, key, s2v(L->top - 1)); luaH_set(L, t, key, s2v(L->top.p - 1));
invalidateTMcache(t); invalidateTMcache(t);
luaC_barrierback(L, obj2gco(t), s2v(L->top - 1)); luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
L->top -= n; L->top.p -= n;
lua_unlock(L); lua_unlock(L);
} }
LUA_API void lua_rawset (lua_State *L, int idx) { LUA_API void lua_rawset (lua_State *L, int idx) {
aux_rawset(L, idx, s2v(L->top - 2), 2); aux_rawset(L, idx, s2v(L->top.p - 2), 2);
} }
@ -927,9 +923,9 @@ LUA_API void lua_rawseti (lua_State *L, int idx, lua_Integer n) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
t = gettable(L, idx); t = gettable(L, idx);
luaH_setint(L, t, n, s2v(L->top - 1)); luaH_setint(L, t, n, s2v(L->top.p - 1));
luaC_barrierback(L, obj2gco(t), s2v(L->top - 1)); luaC_barrierback(L, obj2gco(t), s2v(L->top.p - 1));
L->top--; L->top.p--;
lua_unlock(L); lua_unlock(L);
} }
@ -940,11 +936,11 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
obj = index2value(L, objindex); obj = index2value(L, objindex);
if (ttisnil(s2v(L->top - 1))) if (ttisnil(s2v(L->top.p - 1)))
mt = NULL; mt = NULL;
else { else {
api_check(L, ttistable(s2v(L->top - 1)), "table expected"); api_check(L, ttistable(s2v(L->top.p - 1)), "table expected");
mt = hvalue(s2v(L->top - 1)); mt = hvalue(s2v(L->top.p - 1));
} }
switch (ttype(obj)) { switch (ttype(obj)) {
case LUA_TTABLE: { case LUA_TTABLE: {
@ -968,7 +964,7 @@ LUA_API int lua_setmetatable (lua_State *L, int objindex) {
break; break;
} }
} }
L->top--; L->top.p--;
lua_unlock(L); lua_unlock(L);
return 1; return 1;
} }
@ -984,11 +980,11 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue))) if (!(cast_uint(n) - 1u < cast_uint(uvalue(o)->nuvalue)))
res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */ res = 0; /* 'n' not in [1, uvalue(o)->nuvalue] */
else { else {
setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top - 1)); setobj(L, &uvalue(o)->uv[n - 1].uv, s2v(L->top.p - 1));
luaC_barrierback(L, gcvalue(o), s2v(L->top - 1)); luaC_barrierback(L, gcvalue(o), s2v(L->top.p - 1));
res = 1; res = 1;
} }
L->top--; L->top.p--;
lua_unlock(L); lua_unlock(L);
return res; return res;
} }
@ -1000,7 +996,8 @@ LUA_API int lua_setiuservalue (lua_State *L, int idx, int n) {
#define checkresults(L,na,nr) \ #define checkresults(L,na,nr) \
api_check(L, (nr) == LUA_MULTRET || (L->ci->top - L->top >= (nr) - (na)), \ api_check(L, (nr) == LUA_MULTRET \
|| (L->ci->top.p - L->top.p >= (nr) - (na)), \
"results from function overflow current stack size") "results from function overflow current stack size")
@ -1013,7 +1010,7 @@ LUA_API void lua_callk (lua_State *L, int nargs, int nresults,
api_checknelems(L, nargs+1); api_checknelems(L, nargs+1);
api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread"); api_check(L, L->status == LUA_OK, "cannot do calls on non-normal thread");
checkresults(L, nargs, nresults); checkresults(L, nargs, nresults);
func = L->top - (nargs+1); func = L->top.p - (nargs+1);
if (k != NULL && yieldable(L)) { /* need to prepare continuation? */ if (k != NULL && yieldable(L)) { /* need to prepare continuation? */
L->ci->u.c.k = k; /* save continuation */ L->ci->u.c.k = k; /* save continuation */
L->ci->u.c.ctx = ctx; /* save context */ L->ci->u.c.ctx = ctx; /* save context */
@ -1061,7 +1058,7 @@ LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
api_check(L, ttisfunction(s2v(o)), "error handler must be a function"); api_check(L, ttisfunction(s2v(o)), "error handler must be a function");
func = savestack(L, o); func = savestack(L, o);
} }
c.func = L->top - (nargs+1); /* function to be called */ c.func = L->top.p - (nargs+1); /* function to be called */
if (k == NULL || !yieldable(L)) { /* no continuation or no yieldable? */ if (k == NULL || !yieldable(L)) { /* no continuation or no yieldable? */
c.nresults = nresults; /* do a 'conventional' protected call */ c.nresults = nresults; /* do a 'conventional' protected call */
status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func); status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
@ -1096,12 +1093,12 @@ LUA_API int lua_load (lua_State *L, lua_Reader reader, void *data,
luaZ_init(L, &z, reader, data); luaZ_init(L, &z, reader, data);
status = luaD_protectedparser(L, &z, chunkname, mode); status = luaD_protectedparser(L, &z, chunkname, mode);
if (status == LUA_OK) { /* no errors? */ if (status == LUA_OK) { /* no errors? */
LClosure *f = clLvalue(s2v(L->top - 1)); /* get newly created function */ LClosure *f = clLvalue(s2v(L->top.p - 1)); /* get new function */
if (f->nupvalues >= 1) { /* does it have an upvalue? */ if (f->nupvalues >= 1) { /* does it have an upvalue? */
/* get global table from registry */ /* get global table from registry */
const TValue *gt = getGtable(L); const TValue *gt = getGtable(L);
/* set global table as 1st upvalue of 'f' (may be LUA_ENV) */ /* set global table as 1st upvalue of 'f' (may be LUA_ENV) */
setobj(L, f->upvals[0]->v, gt); setobj(L, f->upvals[0]->v.p, gt);
luaC_barrier(L, f->upvals[0], gt); luaC_barrier(L, f->upvals[0], gt);
} }
} }
@ -1115,7 +1112,7 @@ LUA_API int lua_dump (lua_State *L, lua_Writer writer, void *data, int strip) {
TValue *o; TValue *o;
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
o = s2v(L->top - 1); o = s2v(L->top.p - 1);
if (isLfunction(o)) if (isLfunction(o))
status = luaU_dump(L, getproto(o), writer, data, strip); status = luaU_dump(L, getproto(o), writer, data, strip);
else else
@ -1241,7 +1238,7 @@ LUA_API int lua_gc (lua_State *L, int what, ...) {
LUA_API int lua_error (lua_State *L) { LUA_API int lua_error (lua_State *L) {
TValue *errobj; TValue *errobj;
lua_lock(L); lua_lock(L);
errobj = s2v(L->top - 1); errobj = s2v(L->top.p - 1);
api_checknelems(L, 1); api_checknelems(L, 1);
/* error object is the memory error message? */ /* error object is the memory error message? */
if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg)) if (ttisshrstring(errobj) && eqshrstr(tsvalue(errobj), G(L)->memerrmsg))
@ -1259,12 +1256,12 @@ LUA_API int lua_next (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
api_checknelems(L, 1); api_checknelems(L, 1);
t = gettable(L, idx); t = gettable(L, idx);
more = luaH_next(L, t, L->top - 1); more = luaH_next(L, t, L->top.p - 1);
if (more) { if (more) {
api_incr_top(L); api_incr_top(L);
} }
else /* no more elements */ else /* no more elements */
L->top -= 1; /* remove key */ L->top.p -= 1; /* remove key */
lua_unlock(L); lua_unlock(L);
return more; return more;
} }
@ -1276,7 +1273,7 @@ LUA_API void lua_toclose (lua_State *L, int idx) {
lua_lock(L); lua_lock(L);
o = index2stack(L, idx); o = index2stack(L, idx);
nresults = L->ci->nresults; nresults = L->ci->nresults;
api_check(L, L->tbclist < o, "given index below or equal a marked one"); api_check(L, L->tbclist.p < o, "given index below or equal a marked one");
luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */ luaF_newtbcupval(L, o); /* create new to-be-closed upvalue */
if (!hastocloseCfunc(nresults)) /* function not marked yet? */ if (!hastocloseCfunc(nresults)) /* function not marked yet? */
L->ci->nresults = codeNresults(nresults); /* mark it */ L->ci->nresults = codeNresults(nresults); /* mark it */
@ -1291,7 +1288,7 @@ LUA_API void lua_concat (lua_State *L, int n) {
if (n > 0) if (n > 0)
luaV_concat(L, n); luaV_concat(L, n);
else { /* nothing to concatenate */ else { /* nothing to concatenate */
setsvalue2s(L, L->top, luaS_newlstr(L, "", 0)); /* push empty string */ setsvalue2s(L, L->top.p, luaS_newlstr(L, "", 0)); /* push empty string */
api_incr_top(L); api_incr_top(L);
} }
luaC_checkGC(L); luaC_checkGC(L);
@ -1303,7 +1300,7 @@ LUA_API void lua_len (lua_State *L, int idx) {
TValue *t; TValue *t;
lua_lock(L); lua_lock(L);
t = index2value(L, idx); t = index2value(L, idx);
luaV_objlen(L, L->top, t); luaV_objlen(L, L->top.p, t);
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
} }
@ -1348,7 +1345,7 @@ LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) {
lua_lock(L); lua_lock(L);
api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value"); api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value");
u = luaS_newudata(L, size, nuvalue); u = luaS_newudata(L, size, nuvalue);
setuvalue(L, s2v(L->top), u); setuvalue(L, s2v(L->top.p), u);
api_incr_top(L); api_incr_top(L);
luaC_checkGC(L); luaC_checkGC(L);
lua_unlock(L); lua_unlock(L);
@ -1374,7 +1371,7 @@ static const char *aux_upvalue (TValue *fi, int n, TValue **val,
Proto *p = f->p; Proto *p = f->p;
if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues))) if (!(cast_uint(n) - 1u < cast_uint(p->sizeupvalues)))
return NULL; /* 'n' not in [1, p->sizeupvalues] */ return NULL; /* 'n' not in [1, p->sizeupvalues] */
*val = f->upvals[n-1]->v; *val = f->upvals[n-1]->v.p;
if (owner) *owner = obj2gco(f->upvals[n - 1]); if (owner) *owner = obj2gco(f->upvals[n - 1]);
name = p->upvalues[n-1].name; name = p->upvalues[n-1].name;
return (name == NULL) ? "(no name)" : getstr(name); return (name == NULL) ? "(no name)" : getstr(name);
@ -1390,7 +1387,7 @@ LUA_API const char *lua_getupvalue (lua_State *L, int funcindex, int n) {
lua_lock(L); lua_lock(L);
name = aux_upvalue(index2value(L, funcindex), n, &val, NULL); name = aux_upvalue(index2value(L, funcindex), n, &val, NULL);
if (name) { if (name) {
setobj2s(L, L->top, val); setobj2s(L, L->top.p, val);
api_incr_top(L); api_incr_top(L);
} }
lua_unlock(L); lua_unlock(L);
@ -1408,8 +1405,8 @@ LUA_API const char *lua_setupvalue (lua_State *L, int funcindex, int n) {
api_checknelems(L, 1); api_checknelems(L, 1);
name = aux_upvalue(fi, n, &val, &owner); name = aux_upvalue(fi, n, &val, &owner);
if (name) { if (name) {
L->top--; L->top.p--;
setobj(L, val, s2v(L->top)); setobj(L, val, s2v(L->top.p));
luaC_barrier(L, owner, val); luaC_barrier(L, owner, val);
} }
lua_unlock(L); lua_unlock(L);

View File

@ -12,22 +12,25 @@
#include "lstate.h" #include "lstate.h"
/* Increments 'L->top', checking for stack overflows */ /* Increments 'L->top.p', checking for stack overflows */
#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \ #define api_incr_top(L) {L->top.p++; \
api_check(L, L->top.p <= L->ci->top.p, \
"stack overflow");} "stack overflow");}
/* /*
** If a call returns too many multiple returns, the callee may not have ** If a call returns too many multiple returns, the callee may not have
** stack space to accommodate all results. In this case, this macro ** stack space to accommodate all results. In this case, this macro
** increases its stack space ('L->ci->top'). ** increases its stack space ('L->ci->top.p').
*/ */
#define adjustresults(L,nres) \ #define adjustresults(L,nres) \
{ if ((nres) <= LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; } { if ((nres) <= LUA_MULTRET && L->ci->top.p < L->top.p) \
L->ci->top.p = L->top.p; }
/* Ensure the stack has at least 'n' elements */ /* Ensure the stack has at least 'n' elements */
#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \ #define api_checknelems(L,n) \
api_check(L, (n) < (L->top.p - L->ci->func.p), \
"not enough elements in the stack") "not enough elements in the stack")

View File

@ -526,13 +526,14 @@ static void newbox (lua_State *L) {
/* /*
** Compute new size for buffer 'B', enough to accommodate extra 'sz' ** Compute new size for buffer 'B', enough to accommodate extra 'sz'
** bytes. ** bytes. (The test for "not big enough" also gets the case when the
** computation of 'newsize' overflows.)
*/ */
static size_t newbuffsize (luaL_Buffer *B, size_t sz) { static size_t newbuffsize (luaL_Buffer *B, size_t sz) {
size_t newsize = B->size * 2; /* double buffer size */ size_t newsize = (B->size / 2) * 3; /* buffer size * 1.5 */
if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */ if (l_unlikely(MAX_SIZET - sz < B->n)) /* overflow in (B->n + sz)? */
return luaL_error(B->L, "buffer too large"); return luaL_error(B->L, "buffer too large");
if (newsize < B->n + sz) /* double is not big enough? */ if (newsize < B->n + sz) /* not big enough? */
newsize = B->n + sz; newsize = B->n + sz;
return newsize; return newsize;
} }
@ -611,7 +612,7 @@ LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
** box (if existent) is not on the top of the stack. So, instead of ** box (if existent) is not on the top of the stack. So, instead of
** calling 'luaL_addlstring', it replicates the code using -2 as the ** calling 'luaL_addlstring', it replicates the code using -2 as the
** last argument to 'prepbuffsize', signaling that the box is (or will ** last argument to 'prepbuffsize', signaling that the box is (or will
** be) bellow the string being added to the buffer. (Box creation can ** be) below the string being added to the buffer. (Box creation can
** trigger an emergency GC, so we should not remove the string from the ** trigger an emergency GC, so we should not remove the string from the
** stack before we have the space guaranteed.) ** stack before we have the space guaranteed.)
*/ */
@ -739,17 +740,18 @@ static int errfile (lua_State *L, const char *what, int fnameindex) {
} }
static int skipBOM (LoadF *lf) { /*
const char *p = "\xEF\xBB\xBF"; /* UTF-8 BOM mark */ ** Skip an optional BOM at the start of a stream. If there is an
int c; ** incomplete BOM (the first character is correct but the rest is
lf->n = 0; ** not), returns the first character anyway to force an error
do { ** (as no chunk can start with 0xEF).
c = getc(lf->f); */
if (c == EOF || c != *(const unsigned char *)p++) return c; static int skipBOM (FILE *f) {
lf->buff[lf->n++] = c; /* to be read by the parser */ int c = getc(f); /* read first character */
} while (*p != '\0'); if (c == 0xEF && getc(f) == 0xBB && getc(f) == 0xBF) /* correct BOM? */
lf->n = 0; /* prefix matched; discard it */ return getc(f); /* ignore BOM and return next char */
return getc(lf->f); /* return next character */ else /* no (valid) BOM */
return c; /* return first character */
} }
@ -760,13 +762,13 @@ static int skipBOM (LoadF *lf) {
** first "valid" character of the file (after the optional BOM and ** first "valid" character of the file (after the optional BOM and
** a first-line comment). ** a first-line comment).
*/ */
static int skipcomment (LoadF *lf, int *cp) { static int skipcomment (FILE *f, int *cp) {
int c = *cp = skipBOM(lf); int c = *cp = skipBOM(f);
if (c == '#') { /* first line is a comment (Unix exec. file)? */ if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */ do { /* skip first line */
c = getc(lf->f); c = getc(f);
} while (c != EOF && c != '\n'); } while (c != EOF && c != '\n');
*cp = getc(lf->f); /* skip end-of-line, if present */ *cp = getc(f); /* next character after comment, if present */
return 1; /* there was a comment */ return 1; /* there was a comment */
} }
else return 0; /* no comment */ else return 0; /* no comment */
@ -788,12 +790,16 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
lf.f = fopen(filename, "r"); lf.f = fopen(filename, "r");
if (lf.f == NULL) return errfile(L, "open", fnameindex); if (lf.f == NULL) return errfile(L, "open", fnameindex);
} }
if (skipcomment(&lf, &c)) /* read initial portion */ lf.n = 0;
lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */ if (skipcomment(lf.f, &c)) /* read initial portion */
if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */ lf.buff[lf.n++] = '\n'; /* add newline to correct line numbers */
if (c == LUA_SIGNATURE[0]) { /* binary file? */
lf.n = 0; /* remove possible newline */
if (filename) { /* "real" file? */
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
if (lf.f == NULL) return errfile(L, "reopen", fnameindex); if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
skipcomment(&lf, &c); /* re-read initial portion */ skipcomment(lf.f, &c); /* re-read initial portion */
}
} }
if (c != EOF) if (c != EOF)
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */

View File

@ -1351,6 +1351,35 @@ static int constfolding (FuncState *fs, int op, expdesc *e1,
} }
/*
** Convert a BinOpr to an OpCode (ORDER OPR - ORDER OP)
*/
l_sinline OpCode binopr2op (BinOpr opr, BinOpr baser, OpCode base) {
lua_assert(baser <= opr &&
((baser == OPR_ADD && opr <= OPR_SHR) ||
(baser == OPR_LT && opr <= OPR_LE)));
return cast(OpCode, (cast_int(opr) - cast_int(baser)) + cast_int(base));
}
/*
** Convert a UnOpr to an OpCode (ORDER OPR - ORDER OP)
*/
l_sinline OpCode unopr2op (UnOpr opr) {
return cast(OpCode, (cast_int(opr) - cast_int(OPR_MINUS)) +
cast_int(OP_UNM));
}
/*
** Convert a BinOpr to a tag method (ORDER OPR - ORDER TM)
*/
l_sinline TMS binopr2TM (BinOpr opr) {
lua_assert(OPR_ADD <= opr && opr <= OPR_SHR);
return cast(TMS, (cast_int(opr) - cast_int(OPR_ADD)) + cast_int(TM_ADD));
}
/* /*
** Emit code for unary expressions that "produce values" ** Emit code for unary expressions that "produce values"
** (everything but 'not'). ** (everything but 'not').
@ -1389,12 +1418,15 @@ static void finishbinexpval (FuncState *fs, expdesc *e1, expdesc *e2,
** Emit code for binary expressions that "produce values" over ** Emit code for binary expressions that "produce values" over
** two registers. ** two registers.
*/ */
static void codebinexpval (FuncState *fs, OpCode op, static void codebinexpval (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) { expdesc *e1, expdesc *e2, int line) {
int v2 = luaK_exp2anyreg(fs, e2); /* both operands are in registers */ OpCode op = binopr2op(opr, OPR_ADD, OP_ADD);
int v2 = luaK_exp2anyreg(fs, e2); /* make sure 'e2' is in a register */
/* 'e1' must be already in a register or it is a constant */
lua_assert((VNIL <= e1->k && e1->k <= VKSTR) ||
e1->k == VNONRELOC || e1->k == VRELOC);
lua_assert(OP_ADD <= op && op <= OP_SHR); lua_assert(OP_ADD <= op && op <= OP_SHR);
finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN, finishbinexpval(fs, e1, e2, op, v2, 0, line, OP_MMBIN, binopr2TM(opr));
cast(TMS, (op - OP_ADD) + TM_ADD));
} }
@ -1410,6 +1442,18 @@ static void codebini (FuncState *fs, OpCode op,
} }
/*
** Code binary operators with K operand.
*/
static void codebinK (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
TMS event = binopr2TM(opr);
int v2 = e2->u.info; /* K index */
OpCode op = binopr2op(opr, OPR_ADD, OP_ADDK);
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
}
/* Try to code a binary operator negating its second operand. /* Try to code a binary operator negating its second operand.
** For the metamethod, 2nd operand must keep its original value. ** For the metamethod, 2nd operand must keep its original value.
*/ */
@ -1437,24 +1481,27 @@ static void swapexps (expdesc *e1, expdesc *e2) {
} }
/*
** Code binary operators with no constant operand.
*/
static void codebinNoK (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) {
if (flip)
swapexps(e1, e2); /* back to original order */
codebinexpval(fs, opr, e1, e2, line); /* use standard operators */
}
/* /*
** Code arithmetic operators ('+', '-', ...). If second operand is a ** Code arithmetic operators ('+', '-', ...). If second operand is a
** constant in the proper range, use variant opcodes with K operands. ** constant in the proper range, use variant opcodes with K operands.
*/ */
static void codearith (FuncState *fs, BinOpr opr, static void codearith (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int flip, int line) { expdesc *e1, expdesc *e2, int flip, int line) {
TMS event = cast(TMS, opr + TM_ADD); if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) /* K operand? */
if (tonumeral(e2, NULL) && luaK_exp2K(fs, e2)) { /* K operand? */ codebinK(fs, opr, e1, e2, flip, line);
int v2 = e2->u.info; /* K index */ else /* 'e2' is neither an immediate nor a K operand */
OpCode op = cast(OpCode, opr + OP_ADDK); codebinNoK(fs, opr, e1, e2, flip, line);
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK, event);
}
else { /* 'e2' is neither an immediate nor a K operand */
OpCode op = cast(OpCode, opr + OP_ADD);
if (flip)
swapexps(e1, e2); /* back to original order */
codebinexpval(fs, op, e1, e2, line); /* use standard operators */
}
} }
@ -1471,35 +1518,27 @@ static void codecommutative (FuncState *fs, BinOpr op,
flip = 1; flip = 1;
} }
if (op == OPR_ADD && isSCint(e2)) /* immediate operand? */ if (op == OPR_ADD && isSCint(e2)) /* immediate operand? */
codebini(fs, cast(OpCode, OP_ADDI), e1, e2, flip, line, TM_ADD); codebini(fs, OP_ADDI, e1, e2, flip, line, TM_ADD);
else else
codearith(fs, op, e1, e2, flip, line); codearith(fs, op, e1, e2, flip, line);
} }
/* /*
** Code bitwise operations; they are all associative, so the function ** Code bitwise operations; they are all commutative, so the function
** tries to put an integer constant as the 2nd operand (a K operand). ** tries to put an integer constant as the 2nd operand (a K operand).
*/ */
static void codebitwise (FuncState *fs, BinOpr opr, static void codebitwise (FuncState *fs, BinOpr opr,
expdesc *e1, expdesc *e2, int line) { expdesc *e1, expdesc *e2, int line) {
int flip = 0; int flip = 0;
int v2; if (e1->k == VKINT) {
OpCode op;
if (e1->k == VKINT && luaK_exp2RK(fs, e1)) {
swapexps(e1, e2); /* 'e2' will be the constant operand */ swapexps(e1, e2); /* 'e2' will be the constant operand */
flip = 1; flip = 1;
} }
else if (!(e2->k == VKINT && luaK_exp2RK(fs, e2))) { /* no constants? */ if (e2->k == VKINT && luaK_exp2K(fs, e2)) /* K operand? */
op = cast(OpCode, opr + OP_ADD); codebinK(fs, opr, e1, e2, flip, line);
codebinexpval(fs, op, e1, e2, line); /* all-register opcodes */ else /* no constants */
return; codebinNoK(fs, opr, e1, e2, flip, line);
}
v2 = e2->u.info; /* index in K array */
op = cast(OpCode, opr + OP_ADDK);
lua_assert(ttisinteger(&fs->f->k[v2]));
finishbinexpval(fs, e1, e2, op, v2, flip, line, OP_MMBINK,
cast(TMS, opr + TM_ADD));
} }
@ -1507,25 +1546,27 @@ static void codebitwise (FuncState *fs, BinOpr opr,
** Emit code for order comparisons. When using an immediate operand, ** Emit code for order comparisons. When using an immediate operand,
** 'isfloat' tells whether the original value was a float. ** 'isfloat' tells whether the original value was a float.
*/ */
static void codeorder (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { static void codeorder (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
int r1, r2; int r1, r2;
int im; int im;
int isfloat = 0; int isfloat = 0;
OpCode op;
if (isSCnumber(e2, &im, &isfloat)) { if (isSCnumber(e2, &im, &isfloat)) {
/* use immediate operand */ /* use immediate operand */
r1 = luaK_exp2anyreg(fs, e1); r1 = luaK_exp2anyreg(fs, e1);
r2 = im; r2 = im;
op = cast(OpCode, (op - OP_LT) + OP_LTI); op = binopr2op(opr, OPR_LT, OP_LTI);
} }
else if (isSCnumber(e1, &im, &isfloat)) { else if (isSCnumber(e1, &im, &isfloat)) {
/* transform (A < B) to (B > A) and (A <= B) to (B >= A) */ /* transform (A < B) to (B > A) and (A <= B) to (B >= A) */
r1 = luaK_exp2anyreg(fs, e2); r1 = luaK_exp2anyreg(fs, e2);
r2 = im; r2 = im;
op = (op == OP_LT) ? OP_GTI : OP_GEI; op = binopr2op(opr, OPR_LT, OP_GTI);
} }
else { /* regular case, compare two registers */ else { /* regular case, compare two registers */
r1 = luaK_exp2anyreg(fs, e1); r1 = luaK_exp2anyreg(fs, e1);
r2 = luaK_exp2anyreg(fs, e2); r2 = luaK_exp2anyreg(fs, e2);
op = binopr2op(opr, OPR_LT, OP_LT);
} }
freeexps(fs, e1, e2); freeexps(fs, e1, e2);
e1->u.info = condjump(fs, op, r1, r2, isfloat, 1); e1->u.info = condjump(fs, op, r1, r2, isfloat, 1);
@ -1551,7 +1592,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
op = OP_EQI; op = OP_EQI;
r2 = im; /* immediate operand */ r2 = im; /* immediate operand */
} }
else if (luaK_exp2RK(fs, e2)) { /* 1st expression is constant? */ else if (luaK_exp2RK(fs, e2)) { /* 2nd expression is constant? */
op = OP_EQK; op = OP_EQK;
r2 = e2->u.info; /* constant index */ r2 = e2->u.info; /* constant index */
} }
@ -1568,16 +1609,16 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) {
/* /*
** Apply prefix operation 'op' to expression 'e'. ** Apply prefix operation 'op' to expression 'e'.
*/ */
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { void luaK_prefix (FuncState *fs, UnOpr opr, expdesc *e, int line) {
static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; static const expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP};
luaK_dischargevars(fs, e); luaK_dischargevars(fs, e);
switch (op) { switch (opr) {
case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */ case OPR_MINUS: case OPR_BNOT: /* use 'ef' as fake 2nd operand */
if (constfolding(fs, op + LUA_OPUNM, e, &ef)) if (constfolding(fs, opr + LUA_OPUNM, e, &ef))
break; break;
/* else */ /* FALLTHROUGH */ /* else */ /* FALLTHROUGH */
case OPR_LEN: case OPR_LEN:
codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line); codeunexpval(fs, unopr2op(opr), e, line);
break; break;
case OPR_NOT: codenot(fs, e); break; case OPR_NOT: codenot(fs, e); break;
default: lua_assert(0); default: lua_assert(0);
@ -1611,7 +1652,8 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
case OPR_SHL: case OPR_SHR: { case OPR_SHL: case OPR_SHR: {
if (!tonumeral(v, NULL)) if (!tonumeral(v, NULL))
luaK_exp2anyreg(fs, v); luaK_exp2anyreg(fs, v);
/* else keep numeral, which may be folded with 2nd operand */ /* else keep numeral, which may be folded or used as an immediate
operand */
break; break;
} }
case OPR_EQ: case OPR_NE: { case OPR_EQ: case OPR_NE: {
@ -1706,30 +1748,27 @@ void luaK_posfix (FuncState *fs, BinOpr opr,
/* coded as (r1 >> -I) */; /* coded as (r1 >> -I) */;
} }
else /* regular case (two registers) */ else /* regular case (two registers) */
codebinexpval(fs, OP_SHL, e1, e2, line); codebinexpval(fs, opr, e1, e2, line);
break; break;
} }
case OPR_SHR: { case OPR_SHR: {
if (isSCint(e2)) if (isSCint(e2))
codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR); /* r1 >> I */ codebini(fs, OP_SHRI, e1, e2, 0, line, TM_SHR); /* r1 >> I */
else /* regular case (two registers) */ else /* regular case (two registers) */
codebinexpval(fs, OP_SHR, e1, e2, line); codebinexpval(fs, opr, e1, e2, line);
break; break;
} }
case OPR_EQ: case OPR_NE: { case OPR_EQ: case OPR_NE: {
codeeq(fs, opr, e1, e2); codeeq(fs, opr, e1, e2);
break; break;
} }
case OPR_LT: case OPR_LE: {
OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ);
codeorder(fs, op, e1, e2);
break;
}
case OPR_GT: case OPR_GE: { case OPR_GT: case OPR_GE: {
/* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */ /* '(a > b)' <=> '(b < a)'; '(a >= b)' <=> '(b <= a)' */
OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ);
swapexps(e1, e2); swapexps(e1, e2);
codeorder(fs, op, e1, e2); opr = cast(BinOpr, (opr - OPR_GT) + OPR_LT);
} /* FALLTHROUGH */
case OPR_LT: case OPR_LE: {
codeorder(fs, opr, e1, e2);
break; break;
} }
default: lua_assert(0); default: lua_assert(0);

View File

@ -76,7 +76,7 @@ static int luaB_auxwrap (lua_State *L) {
if (l_unlikely(r < 0)) { /* error? */ if (l_unlikely(r < 0)) { /* error? */
int stat = lua_status(co); int stat = lua_status(co);
if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */ if (stat != LUA_OK && stat != LUA_YIELD) { /* error in the coroutine? */
stat = lua_resetthread(co); /* close its tbc variables */ stat = lua_resetthread(co, L); /* close its tbc variables */
lua_assert(stat != LUA_OK); lua_assert(stat != LUA_OK);
lua_xmove(co, L, 1); /* move error message to the caller */ lua_xmove(co, L, 1); /* move error message to the caller */
} }
@ -172,7 +172,7 @@ static int luaB_close (lua_State *L) {
int status = auxstatus(L, co); int status = auxstatus(L, co);
switch (status) { switch (status) {
case COS_DEAD: case COS_YIELD: { case COS_DEAD: case COS_YIELD: {
status = lua_resetthread(co); status = lua_resetthread(co, L);
if (status == LUA_OK) { if (status == LUA_OK) {
lua_pushboolean(L, 1); lua_pushboolean(L, 1);
return 1; return 1;

View File

@ -182,10 +182,10 @@ static const char *upvalname (const Proto *p, int uv) {
static const char *findvararg (CallInfo *ci, int n, StkId *pos) { static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
if (clLvalue(s2v(ci->func))->p->is_vararg) { if (clLvalue(s2v(ci->func.p))->p->is_vararg) {
int nextra = ci->u.l.nextraargs; int nextra = ci->u.l.nextraargs;
if (n >= -nextra) { /* 'n' is negative */ if (n >= -nextra) { /* 'n' is negative */
*pos = ci->func - nextra - (n + 1); *pos = ci->func.p - nextra - (n + 1);
return "(vararg)"; /* generic name for any vararg */ return "(vararg)"; /* generic name for any vararg */
} }
} }
@ -194,7 +194,7 @@ static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) { const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
StkId base = ci->func + 1; StkId base = ci->func.p + 1;
const char *name = NULL; const char *name = NULL;
if (isLua(ci)) { if (isLua(ci)) {
if (n < 0) /* access to vararg values? */ if (n < 0) /* access to vararg values? */
@ -203,7 +203,7 @@ const char *luaG_findlocal (lua_State *L, CallInfo *ci, int n, StkId *pos) {
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci)); name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
} }
if (name == NULL) { /* no 'standard' name? */ if (name == NULL) { /* no 'standard' name? */
StkId limit = (ci == L->ci) ? L->top : ci->next->func; StkId limit = (ci == L->ci) ? L->top.p : ci->next->func.p;
if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */ if (limit - base >= n && n > 0) { /* is 'n' inside 'ci' stack? */
/* generic name for any valid slot */ /* generic name for any valid slot */
name = isLua(ci) ? "(temporary)" : "(C temporary)"; name = isLua(ci) ? "(temporary)" : "(C temporary)";
@ -221,16 +221,16 @@ LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
const char *name; const char *name;
lua_lock(L); lua_lock(L);
if (ar == NULL) { /* information about non-active function? */ if (ar == NULL) { /* information about non-active function? */
if (!isLfunction(s2v(L->top - 1))) /* not a Lua function? */ if (!isLfunction(s2v(L->top.p - 1))) /* not a Lua function? */
name = NULL; name = NULL;
else /* consider live variables at function start (parameters) */ else /* consider live variables at function start (parameters) */
name = luaF_getlocalname(clLvalue(s2v(L->top - 1))->p, n, 0); name = luaF_getlocalname(clLvalue(s2v(L->top.p - 1))->p, n, 0);
} }
else { /* active function; get information through 'ar' */ else { /* active function; get information through 'ar' */
StkId pos = NULL; /* to avoid warnings */ StkId pos = NULL; /* to avoid warnings */
name = luaG_findlocal(L, ar->i_ci, n, &pos); name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) { if (name) {
setobjs2s(L, L->top, pos); setobjs2s(L, L->top.p, pos);
api_incr_top(L); api_incr_top(L);
} }
} }
@ -245,8 +245,8 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
lua_lock(L); lua_lock(L);
name = luaG_findlocal(L, ar->i_ci, n, &pos); name = luaG_findlocal(L, ar->i_ci, n, &pos);
if (name) { if (name) {
setobjs2s(L, pos, L->top - 1); setobjs2s(L, pos, L->top.p - 1);
L->top--; /* pop value */ L->top.p--; /* pop value */
} }
lua_unlock(L); lua_unlock(L);
return name; return name;
@ -289,7 +289,7 @@ static int nextline (const Proto *p, int currentline, int pc) {
static void collectvalidlines (lua_State *L, Closure *f) { static void collectvalidlines (lua_State *L, Closure *f) {
if (noLuaClosure(f)) { if (noLuaClosure(f)) {
setnilvalue(s2v(L->top)); setnilvalue(s2v(L->top.p));
api_incr_top(L); api_incr_top(L);
} }
else { else {
@ -298,7 +298,7 @@ static void collectvalidlines (lua_State *L, Closure *f) {
const Proto *p = f->l.p; const Proto *p = f->l.p;
int currentline = p->linedefined; int currentline = p->linedefined;
Table *t = luaH_new(L); /* new table to store active lines */ Table *t = luaH_new(L); /* new table to store active lines */
sethvalue2s(L, L->top, t); /* push it on stack */ sethvalue2s(L, L->top.p, t); /* push it on stack */
api_incr_top(L); api_incr_top(L);
setbtvalue(&v); /* boolean 'true' to be the value of all indices */ setbtvalue(&v); /* boolean 'true' to be the value of all indices */
if (!p->is_vararg) /* regular function? */ if (!p->is_vararg) /* regular function? */
@ -388,20 +388,20 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
lua_lock(L); lua_lock(L);
if (*what == '>') { if (*what == '>') {
ci = NULL; ci = NULL;
func = s2v(L->top - 1); func = s2v(L->top.p - 1);
api_check(L, ttisfunction(func), "function expected"); api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */ what++; /* skip the '>' */
L->top--; /* pop function */ L->top.p--; /* pop function */
} }
else { else {
ci = ar->i_ci; ci = ar->i_ci;
func = s2v(ci->func); func = s2v(ci->func.p);
lua_assert(ttisfunction(func)); lua_assert(ttisfunction(func));
} }
cl = ttisclosure(func) ? clvalue(func) : NULL; cl = ttisclosure(func) ? clvalue(func) : NULL;
status = auxgetinfo(L, what, ar, cl, ci); status = auxgetinfo(L, what, ar, cl, ci);
if (strchr(what, 'f')) { if (strchr(what, 'f')) {
setobj2s(L, L->top, func); setobj2s(L, L->top.p, func);
api_incr_top(L); api_incr_top(L);
} }
if (strchr(what, 'L')) if (strchr(what, 'L'))
@ -656,18 +656,19 @@ static const char *funcnamefromcall (lua_State *L, CallInfo *ci,
/* /*
** Check whether pointer 'o' points to some value in the stack ** Check whether pointer 'o' points to some value in the stack frame of
** frame of the current function. Because 'o' may not point to a ** the current function and, if so, returns its index. Because 'o' may
** value in this stack, we cannot compare it with the region ** not point to a value in this stack, we cannot compare it with the
** boundaries (undefined behaviour in ISO C). ** region boundaries (undefined behavior in ISO C).
*/ */
static int isinstack (CallInfo *ci, const TValue *o) { static int instack (CallInfo *ci, const TValue *o) {
StkId pos; int pos;
for (pos = ci->func + 1; pos < ci->top; pos++) { StkId base = ci->func.p + 1;
if (o == s2v(pos)) for (pos = 0; base + pos < ci->top.p; pos++) {
return 1; if (o == s2v(base + pos))
return pos;
} }
return 0; /* not found */ return -1; /* not found */
} }
@ -681,7 +682,7 @@ static const char *getupvalname (CallInfo *ci, const TValue *o,
LClosure *c = ci_func(ci); LClosure *c = ci_func(ci);
int i; int i;
for (i = 0; i < c->nupvalues; i++) { for (i = 0; i < c->nupvalues; i++) {
if (c->upvals[i]->v == o) { if (c->upvals[i]->v.p == o) {
*name = upvalname(c->p, i); *name = upvalname(c->p, i);
return "upvalue"; return "upvalue";
} }
@ -708,9 +709,11 @@ static const char *varinfo (lua_State *L, const TValue *o) {
const char *kind = NULL; const char *kind = NULL;
if (isLua(ci)) { if (isLua(ci)) {
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */ kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
if (!kind && isinstack(ci, o)) /* no? try a register */ if (!kind) { /* not an upvalue? */
kind = getobjname(ci_func(ci)->p, currentpc(ci), int reg = instack(ci, o); /* try a register */
cast_int(cast(StkId, o) - (ci->func + 1)), &name); if (reg >= 0) /* is 'o' a register? */
kind = getobjname(ci_func(ci)->p, currentpc(ci), reg, &name);
}
} }
return formatvarinfo(L, kind, name); return formatvarinfo(L, kind, name);
} }
@ -807,10 +810,10 @@ l_noret luaG_errormsg (lua_State *L) {
if (L->errfunc != 0) { /* is there an error handling function? */ if (L->errfunc != 0) { /* is there an error handling function? */
StkId errfunc = restorestack(L, L->errfunc); StkId errfunc = restorestack(L, L->errfunc);
lua_assert(ttisfunction(s2v(errfunc))); lua_assert(ttisfunction(s2v(errfunc)));
setobjs2s(L, L->top, L->top - 1); /* move argument */ setobjs2s(L, L->top.p, L->top.p - 1); /* move argument */
setobjs2s(L, L->top - 1, errfunc); /* push function */ setobjs2s(L, L->top.p - 1, errfunc); /* push function */
L->top++; /* assume EXTRA_STACK */ L->top.p++; /* assume EXTRA_STACK */
luaD_callnoyield(L, L->top - 2, 1); /* call it */ luaD_callnoyield(L, L->top.p - 2, 1); /* call it */
} }
luaD_throw(L, LUA_ERRRUN); luaD_throw(L, LUA_ERRRUN);
} }
@ -824,8 +827,11 @@ l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
va_start(argp, fmt); va_start(argp, fmt);
msg = luaO_pushvfstring(L, fmt, argp); /* format message */ msg = luaO_pushvfstring(L, fmt, argp); /* format message */
va_end(argp); va_end(argp);
if (isLua(ci)) /* if Lua function, add source:line information */ if (isLua(ci)) { /* if Lua function, add source:line information */
luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci)); luaG_addinfo(L, msg, ci_func(ci)->p->source, getcurrentline(ci));
setobjs2s(L, L->top.p - 2, L->top.p - 1); /* remove 'msg' */
L->top.p--;
}
luaG_errormsg(L); luaG_errormsg(L);
} }
@ -842,7 +848,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
if (p->lineinfo == NULL) /* no debug information? */ if (p->lineinfo == NULL) /* no debug information? */
return 0; return 0;
if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */ if (newpc - oldpc < MAXIWTHABS / 2) { /* not too far apart? */
int delta = 0; /* line diference */ int delta = 0; /* line difference */
int pc = oldpc; int pc = oldpc;
for (;;) { for (;;) {
int lineinfo = p->lineinfo[++pc]; int lineinfo = p->lineinfo[++pc];
@ -869,7 +875,7 @@ static int changedline (const Proto *p, int oldpc, int newpc) {
** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc' ** invalid; if so, use zero as a valid value. (A wrong but valid 'oldpc'
** at most causes an extra call to a line hook.) ** at most causes an extra call to a line hook.)
** This function is not "Protected" when called, so it should correct ** This function is not "Protected" when called, so it should correct
** 'L->top' before calling anything that can run the GC. ** 'L->top.p' before calling anything that can run the GC.
*/ */
int luaG_traceexec (lua_State *L, const Instruction *pc) { int luaG_traceexec (lua_State *L, const Instruction *pc) {
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
@ -892,7 +898,7 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) {
return 1; /* do not call hook again (VM yielded, so it did not move) */ return 1; /* do not call hook again (VM yielded, so it did not move) */
} }
if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */ if (!isIT(*(ci->u.l.savedpc - 1))) /* top not being used? */
L->top = ci->top; /* correct top */ L->top.p = ci->top.p; /* correct top */
if (counthook) if (counthook)
luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */ luaD_hook(L, LUA_HOOKCOUNT, -1, 0, 0); /* call count hook */
if (mask & LUA_MASKLINE) { if (mask & LUA_MASKLINE) {

View File

@ -15,7 +15,7 @@
/* Active Lua function (given call info) */ /* Active Lua function (given call info) */
#define ci_func(ci) (clLvalue(s2v((ci)->func))) #define ci_func(ci) (clLvalue(s2v((ci)->func.p)))
#define resethookcount(L) (L->hookcount = L->basehookcount) #define resethookcount(L) (L->hookcount = L->basehookcount)

View File

@ -104,11 +104,11 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) {
} }
default: { default: {
lua_assert(errorstatus(errcode)); /* real error */ lua_assert(errorstatus(errcode)); /* real error */
setobjs2s(L, oldtop, L->top - 1); /* error message on current top */ setobjs2s(L, oldtop, L->top.p - 1); /* error message on current top */
break; break;
} }
} }
L->top = oldtop + 1; L->top.p = oldtop + 1;
} }
@ -121,7 +121,7 @@ l_noret luaD_throw (lua_State *L, int errcode) {
global_State *g = G(L); global_State *g = G(L);
errcode = luaE_resetthread(L, errcode); /* close all upvalues */ errcode = luaE_resetthread(L, errcode); /* close all upvalues */
if (g->mainthread->errorJmp) { /* main thread has a handler? */ if (g->mainthread->errorJmp) { /* main thread has a handler? */
setobjs2s(L, g->mainthread->top++, L->top - 1); /* copy error obj. */ setobjs2s(L, g->mainthread->top.p++, L->top.p - 1); /* copy error obj. */
luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ luaD_throw(g->mainthread, errcode); /* re-throw in main thread */
} }
else { /* no handler at all; abort */ else { /* no handler at all; abort */
@ -157,16 +157,38 @@ int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
** Stack reallocation ** Stack reallocation
** =================================================================== ** ===================================================================
*/ */
static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
/*
** Change all pointers to the stack into offsets.
*/
static void relstack (lua_State *L) {
CallInfo *ci; CallInfo *ci;
UpVal *up; UpVal *up;
L->top = (L->top - oldstack) + newstack; L->top.offset = savestack(L, L->top.p);
L->tbclist = (L->tbclist - oldstack) + newstack; L->tbclist.offset = savestack(L, L->tbclist.p);
for (up = L->openupval; up != NULL; up = up->u.open.next) for (up = L->openupval; up != NULL; up = up->u.open.next)
up->v = s2v((uplevel(up) - oldstack) + newstack); up->v.offset = savestack(L, uplevel(up));
for (ci = L->ci; ci != NULL; ci = ci->previous) { for (ci = L->ci; ci != NULL; ci = ci->previous) {
ci->top = (ci->top - oldstack) + newstack; ci->top.offset = savestack(L, ci->top.p);
ci->func = (ci->func - oldstack) + newstack; ci->func.offset = savestack(L, ci->func.p);
}
}
/*
** Change back all offsets into pointers.
*/
static void correctstack (lua_State *L) {
CallInfo *ci;
UpVal *up;
L->top.p = restorestack(L, L->top.offset);
L->tbclist.p = restorestack(L, L->tbclist.offset);
for (up = L->openupval; up != NULL; up = up->u.open.next)
up->v.p = s2v(restorestack(L, up->v.offset));
for (ci = L->ci; ci != NULL; ci = ci->previous) {
ci->top.p = restorestack(L, ci->top.offset);
ci->func.p = restorestack(L, ci->func.offset);
if (isLua(ci)) if (isLua(ci))
ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */ ci->u.l.trap = 1; /* signal to update 'trap' in 'luaV_execute' */
} }
@ -176,44 +198,45 @@ static void correctstack (lua_State *L, StkId oldstack, StkId newstack) {
/* some space for error handling */ /* some space for error handling */
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) #define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
/* /*
** Reallocate the stack to a new size, correcting all pointers into ** Reallocate the stack to a new size, correcting all pointers into it.
** it. (There are pointers to a stack from its upvalues, from its list ** In ISO C, any pointer use after the pointer has been deallocated is
** of call infos, plus a few individual pointers.) The reallocation is ** undefined behavior. So, before the reallocation, all pointers are
** done in two steps (allocation + free) because the correction must be ** changed to offsets, and after the reallocation they are changed back
** done while both addresses (the old stack and the new one) are valid. ** to pointers. As during the reallocation the pointers are invalid, the
** (In ISO C, any pointer use after the pointer has been deallocated is ** reallocation cannot run emergency collections.
** undefined behavior.) **
** In case of allocation error, raise an error or return false according ** In case of allocation error, raise an error or return false according
** to 'raiseerror'. ** to 'raiseerror'.
*/ */
int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) { int luaD_reallocstack (lua_State *L, int newsize, int raiseerror) {
int oldsize = stacksize(L); int oldsize = stacksize(L);
int i; int i;
StkId newstack = luaM_reallocvector(L, NULL, 0, StkId newstack;
newsize + EXTRA_STACK, StackValue); int oldgcstop = G(L)->gcstopem;
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE); lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
relstack(L); /* change pointers to offsets */
G(L)->gcstopem = 1; /* stop emergency collection */
newstack = luaM_reallocvector(L, L->stack.p, oldsize + EXTRA_STACK,
newsize + EXTRA_STACK, StackValue);
G(L)->gcstopem = oldgcstop; /* restore emergency collection */
if (l_unlikely(newstack == NULL)) { /* reallocation failed? */ if (l_unlikely(newstack == NULL)) { /* reallocation failed? */
correctstack(L); /* change offsets back to pointers */
if (raiseerror) if (raiseerror)
luaM_error(L); luaM_error(L);
else return 0; /* do not raise an error */ else return 0; /* do not raise an error */
} }
/* number of elements to be copied to the new stack */ L->stack.p = newstack;
i = ((oldsize <= newsize) ? oldsize : newsize) + EXTRA_STACK; correctstack(L); /* change offsets back to pointers */
memcpy(newstack, L->stack, i * sizeof(StackValue)); L->stack_last.p = L->stack.p + newsize;
for (; i < newsize + EXTRA_STACK; i++) for (i = oldsize + EXTRA_STACK; i < newsize + EXTRA_STACK; i++)
setnilvalue(s2v(newstack + i)); /* erase new segment */ setnilvalue(s2v(newstack + i)); /* erase new segment */
correctstack(L, L->stack, newstack);
luaM_freearray(L, L->stack, oldsize + EXTRA_STACK);
L->stack = newstack;
L->stack_last = L->stack + newsize;
return 1; return 1;
} }
/* /*
** Try to grow the stack by at least 'n' elements. when 'raiseerror' ** Try to grow the stack by at least 'n' elements. When 'raiseerror'
** is true, raises any error; otherwise, return 0 in case of errors. ** is true, raises any error; otherwise, return 0 in case of errors.
*/ */
int luaD_growstack (lua_State *L, int n, int raiseerror) { int luaD_growstack (lua_State *L, int n, int raiseerror) {
@ -227,35 +250,38 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) {
luaD_throw(L, LUA_ERRERR); /* error inside message handler */ luaD_throw(L, LUA_ERRERR); /* error inside message handler */
return 0; /* if not 'raiseerror', just signal it */ return 0; /* if not 'raiseerror', just signal it */
} }
else { else if (n < LUAI_MAXSTACK) { /* avoids arithmetic overflows */
int newsize = 2 * size; /* tentative new size */ int newsize = 2 * size; /* tentative new size */
int needed = cast_int(L->top - L->stack) + n; int needed = cast_int(L->top.p - L->stack.p) + n;
if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */ if (newsize > LUAI_MAXSTACK) /* cannot cross the limit */
newsize = LUAI_MAXSTACK; newsize = LUAI_MAXSTACK;
if (newsize < needed) /* but must respect what was asked for */ if (newsize < needed) /* but must respect what was asked for */
newsize = needed; newsize = needed;
if (l_likely(newsize <= LUAI_MAXSTACK)) if (l_likely(newsize <= LUAI_MAXSTACK))
return luaD_reallocstack(L, newsize, raiseerror); return luaD_reallocstack(L, newsize, raiseerror);
else { /* stack overflow */ }
/* else stack overflow */
/* add extra size to be able to handle the error message */ /* add extra size to be able to handle the error message */
luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror); luaD_reallocstack(L, ERRORSTACKSIZE, raiseerror);
if (raiseerror) if (raiseerror)
luaG_runerror(L, "stack overflow"); luaG_runerror(L, "stack overflow");
return 0; return 0;
}
}
} }
/*
** Compute how much of the stack is being used, by computing the
** maximum top of all call frames in the stack and the current top.
*/
static int stackinuse (lua_State *L) { static int stackinuse (lua_State *L) {
CallInfo *ci; CallInfo *ci;
int res; int res;
StkId lim = L->top; StkId lim = L->top.p;
for (ci = L->ci; ci != NULL; ci = ci->previous) { for (ci = L->ci; ci != NULL; ci = ci->previous) {
if (lim < ci->top) lim = ci->top; if (lim < ci->top.p) lim = ci->top.p;
} }
lua_assert(lim <= L->stack_last); lua_assert(lim <= L->stack_last.p + EXTRA_STACK);
res = cast_int(lim - L->stack) + 1; /* part of stack in use */ res = cast_int(lim - L->stack.p) + 1; /* part of stack in use */
if (res < LUA_MINSTACK) if (res < LUA_MINSTACK)
res = LUA_MINSTACK; /* ensure a minimum size */ res = LUA_MINSTACK; /* ensure a minimum size */
return res; return res;
@ -273,17 +299,13 @@ static int stackinuse (lua_State *L) {
*/ */
void luaD_shrinkstack (lua_State *L) { void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L); int inuse = stackinuse(L);
int nsize = inuse * 2; /* proposed new size */ int max = (inuse > LUAI_MAXSTACK / 3) ? LUAI_MAXSTACK : inuse * 3;
int max = inuse * 3; /* maximum "reasonable" size */
if (max > LUAI_MAXSTACK) {
max = LUAI_MAXSTACK; /* respect stack limit */
if (nsize > LUAI_MAXSTACK)
nsize = LUAI_MAXSTACK;
}
/* if thread is currently not handling a stack overflow and its /* if thread is currently not handling a stack overflow and its
size is larger than maximum "reasonable" size, shrink it */ size is larger than maximum "reasonable" size, shrink it */
if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) if (inuse <= LUAI_MAXSTACK && stacksize(L) > max) {
int nsize = (inuse > LUAI_MAXSTACK / 2) ? LUAI_MAXSTACK : inuse * 2;
luaD_reallocstack(L, nsize, 0); /* ok if that fails */ luaD_reallocstack(L, nsize, 0); /* ok if that fails */
}
else /* don't change stack */ else /* don't change stack */
condmovestack(L,{},{}); /* (change only for debugging) */ condmovestack(L,{},{}); /* (change only for debugging) */
luaE_shrinkCI(L); /* shrink CI list */ luaE_shrinkCI(L); /* shrink CI list */
@ -292,7 +314,7 @@ void luaD_shrinkstack (lua_State *L) {
void luaD_inctop (lua_State *L) { void luaD_inctop (lua_State *L) {
luaD_checkstack(L, 1); luaD_checkstack(L, 1);
L->top++; L->top.p++;
} }
/* }================================================================== */ /* }================================================================== */
@ -309,8 +331,8 @@ void luaD_hook (lua_State *L, int event, int line,
if (hook && L->allowhook) { /* make sure there is a hook */ if (hook && L->allowhook) { /* make sure there is a hook */
int mask = CIST_HOOKED; int mask = CIST_HOOKED;
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
ptrdiff_t top = savestack(L, L->top); /* preserve original 'top' */ ptrdiff_t top = savestack(L, L->top.p); /* preserve original 'top' */
ptrdiff_t ci_top = savestack(L, ci->top); /* idem for 'ci->top' */ ptrdiff_t ci_top = savestack(L, ci->top.p); /* idem for 'ci->top' */
lua_Debug ar; lua_Debug ar;
ar.event = event; ar.event = event;
ar.currentline = line; ar.currentline = line;
@ -320,11 +342,11 @@ void luaD_hook (lua_State *L, int event, int line,
ci->u2.transferinfo.ftransfer = ftransfer; ci->u2.transferinfo.ftransfer = ftransfer;
ci->u2.transferinfo.ntransfer = ntransfer; ci->u2.transferinfo.ntransfer = ntransfer;
} }
if (isLua(ci) && L->top < ci->top) if (isLua(ci) && L->top.p < ci->top.p)
L->top = ci->top; /* protect entire activation register */ L->top.p = ci->top.p; /* protect entire activation register */
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */ luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
if (ci->top < L->top + LUA_MINSTACK) if (ci->top.p < L->top.p + LUA_MINSTACK)
ci->top = L->top + LUA_MINSTACK; ci->top.p = L->top.p + LUA_MINSTACK;
L->allowhook = 0; /* cannot call hooks inside a hook */ L->allowhook = 0; /* cannot call hooks inside a hook */
ci->callstatus |= mask; ci->callstatus |= mask;
lua_unlock(L); lua_unlock(L);
@ -332,8 +354,8 @@ void luaD_hook (lua_State *L, int event, int line,
lua_lock(L); lua_lock(L);
lua_assert(!L->allowhook); lua_assert(!L->allowhook);
L->allowhook = 1; L->allowhook = 1;
ci->top = restorestack(L, ci_top); ci->top.p = restorestack(L, ci_top);
L->top = restorestack(L, top); L->top.p = restorestack(L, top);
ci->callstatus &= ~mask; ci->callstatus &= ~mask;
} }
} }
@ -364,7 +386,7 @@ void luaD_hookcall (lua_State *L, CallInfo *ci) {
*/ */
static void rethook (lua_State *L, CallInfo *ci, int nres) { static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (L->hookmask & LUA_MASKRET) { /* is return hook on? */ if (L->hookmask & LUA_MASKRET) { /* is return hook on? */
StkId firstres = L->top - nres; /* index of first result */ StkId firstres = L->top.p - nres; /* index of first result */
int delta = 0; /* correction for vararg functions */ int delta = 0; /* correction for vararg functions */
int ftransfer; int ftransfer;
if (isLua(ci)) { if (isLua(ci)) {
@ -372,10 +394,10 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) {
if (p->is_vararg) if (p->is_vararg)
delta = ci->u.l.nextraargs + p->numparams + 1; delta = ci->u.l.nextraargs + p->numparams + 1;
} }
ci->func += delta; /* if vararg, back to virtual 'func' */ ci->func.p += delta; /* if vararg, back to virtual 'func' */
ftransfer = cast(unsigned short, firstres - ci->func); ftransfer = cast(unsigned short, firstres - ci->func.p);
luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */ luaD_hook(L, LUA_HOOKRET, -1, ftransfer, nres); /* call it */
ci->func -= delta; ci->func.p -= delta;
} }
if (isLua(ci = ci->previous)) if (isLua(ci = ci->previous))
L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */ L->oldpc = pcRel(ci->u.l.savedpc, ci_func(ci)->p); /* set 'oldpc' */
@ -394,9 +416,9 @@ StkId luaD_tryfuncTM (lua_State *L, StkId func) {
tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */ tm = luaT_gettmbyobj(L, s2v(func), TM_CALL); /* (after previous GC) */
if (l_unlikely(ttisnil(tm))) if (l_unlikely(ttisnil(tm)))
luaG_callerror(L, s2v(func)); /* nothing to call */ luaG_callerror(L, s2v(func)); /* nothing to call */
for (p = L->top; p > func; p--) /* open space for metamethod */ for (p = L->top.p; p > func; p--) /* open space for metamethod */
setobjs2s(L, p, p-1); setobjs2s(L, p, p-1);
L->top++; /* stack space pre-allocated by the caller */ L->top.p++; /* stack space pre-allocated by the caller */
setobj2s(L, func, tm); /* metamethod is the new function to be called */ setobj2s(L, func, tm); /* metamethod is the new function to be called */
return func; return func;
} }
@ -413,28 +435,29 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
int i; int i;
switch (wanted) { /* handle typical cases separately */ switch (wanted) { /* handle typical cases separately */
case 0: /* no values needed */ case 0: /* no values needed */
L->top = res; L->top.p = res;
return; return;
case 1: /* one value needed */ case 1: /* one value needed */
if (nres == 0) /* no results? */ if (nres == 0) /* no results? */
setnilvalue(s2v(res)); /* adjust with nil */ setnilvalue(s2v(res)); /* adjust with nil */
else /* at least one result */ else /* at least one result */
setobjs2s(L, res, L->top - nres); /* move it to proper place */ setobjs2s(L, res, L->top.p - nres); /* move it to proper place */
L->top = res + 1; L->top.p = res + 1;
return; return;
case LUA_MULTRET: case LUA_MULTRET:
wanted = nres; /* we want all results */ wanted = nres; /* we want all results */
break; break;
default: /* two/more results and/or to-be-closed variables */ default: /* two/more results and/or to-be-closed variables */
if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */ if (hastocloseCfunc(wanted)) { /* to-be-closed variables? */
ptrdiff_t savedres = savestack(L, res);
L->ci->callstatus |= CIST_CLSRET; /* in case of yields */ L->ci->callstatus |= CIST_CLSRET; /* in case of yields */
L->ci->u2.nres = nres; L->ci->u2.nres = nres;
luaF_close(L, res, CLOSEKTOP, 1); res = luaF_close(L, res, CLOSEKTOP, 1);
L->ci->callstatus &= ~CIST_CLSRET; L->ci->callstatus &= ~CIST_CLSRET;
if (L->hookmask) /* if needed, call hook after '__close's */ if (L->hookmask) { /* if needed, call hook after '__close's */
ptrdiff_t savedres = savestack(L, res);
rethook(L, L->ci, nres); rethook(L, L->ci, nres);
res = restorestack(L, savedres); /* close and hook can move stack */ res = restorestack(L, savedres); /* hook can move stack */
}
wanted = decodeNresults(wanted); wanted = decodeNresults(wanted);
if (wanted == LUA_MULTRET) if (wanted == LUA_MULTRET)
wanted = nres; /* we want all results */ wanted = nres; /* we want all results */
@ -442,14 +465,14 @@ l_sinline void moveresults (lua_State *L, StkId res, int nres, int wanted) {
break; break;
} }
/* generic case */ /* generic case */
firstresult = L->top - nres; /* index of first result */ firstresult = L->top.p - nres; /* index of first result */
if (nres > wanted) /* extra results? */ if (nres > wanted) /* extra results? */
nres = wanted; /* don't need them */ nres = wanted; /* don't need them */
for (i = 0; i < nres; i++) /* move all results to correct place */ for (i = 0; i < nres; i++) /* move all results to correct place */
setobjs2s(L, res + i, firstresult + i); setobjs2s(L, res + i, firstresult + i);
for (; i < wanted; i++) /* complete wanted number of results */ for (; i < wanted; i++) /* complete wanted number of results */
setnilvalue(s2v(res + i)); setnilvalue(s2v(res + i));
L->top = res + wanted; /* top points after the last result */ L->top.p = res + wanted; /* top points after the last result */
} }
@ -464,7 +487,7 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted))) if (l_unlikely(L->hookmask && !hastocloseCfunc(wanted)))
rethook(L, ci, nres); rethook(L, ci, nres);
/* move results to proper place */ /* move results to proper place */
moveresults(L, ci->func, nres, wanted); moveresults(L, ci->func.p, nres, wanted);
/* function cannot be in any of these cases when returning */ /* function cannot be in any of these cases when returning */
lua_assert(!(ci->callstatus & lua_assert(!(ci->callstatus &
(CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET))); (CIST_HOOKED | CIST_YPCALL | CIST_FIN | CIST_TRAN | CIST_CLSRET)));
@ -479,10 +502,10 @@ void luaD_poscall (lua_State *L, CallInfo *ci, int nres) {
l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret, l_sinline CallInfo *prepCallInfo (lua_State *L, StkId func, int nret,
int mask, StkId top) { int mask, StkId top) {
CallInfo *ci = L->ci = next_ci(L); /* new frame */ CallInfo *ci = L->ci = next_ci(L); /* new frame */
ci->func = func; ci->func.p = func;
ci->nresults = nret; ci->nresults = nret;
ci->callstatus = mask; ci->callstatus = mask;
ci->top = top; ci->top.p = top;
return ci; return ci;
} }
@ -496,10 +519,10 @@ l_sinline int precallC (lua_State *L, StkId func, int nresults,
CallInfo *ci; CallInfo *ci;
checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */ checkstackGCp(L, LUA_MINSTACK, func); /* ensure minimum stack size */
L->ci = ci = prepCallInfo(L, func, nresults, CIST_C, L->ci = ci = prepCallInfo(L, func, nresults, CIST_C,
L->top + LUA_MINSTACK); L->top.p + LUA_MINSTACK);
lua_assert(ci->top <= L->stack_last); lua_assert(ci->top.p <= L->stack_last.p);
if (l_unlikely(L->hookmask & LUA_MASKCALL)) { if (l_unlikely(L->hookmask & LUA_MASKCALL)) {
int narg = cast_int(L->top - func) - 1; int narg = cast_int(L->top.p - func) - 1;
luaD_hook(L, LUA_HOOKCALL, -1, 1, narg); luaD_hook(L, LUA_HOOKCALL, -1, 1, narg);
} }
lua_unlock(L); lua_unlock(L);
@ -531,17 +554,17 @@ int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
int nfixparams = p->numparams; int nfixparams = p->numparams;
int i; int i;
checkstackGCp(L, fsize - delta, func); checkstackGCp(L, fsize - delta, func);
ci->func -= delta; /* restore 'func' (if vararg) */ ci->func.p -= delta; /* restore 'func' (if vararg) */
for (i = 0; i < narg1; i++) /* move down function and arguments */ for (i = 0; i < narg1; i++) /* move down function and arguments */
setobjs2s(L, ci->func + i, func + i); setobjs2s(L, ci->func.p + i, func + i);
func = ci->func; /* moved-down function */ func = ci->func.p; /* moved-down function */
for (; narg1 <= nfixparams; narg1++) for (; narg1 <= nfixparams; narg1++)
setnilvalue(s2v(func + narg1)); /* complete missing arguments */ setnilvalue(s2v(func + narg1)); /* complete missing arguments */
ci->top = func + 1 + fsize; /* top for new function */ ci->top.p = func + 1 + fsize; /* top for new function */
lua_assert(ci->top <= L->stack_last); lua_assert(ci->top.p <= L->stack_last.p);
ci->u.l.savedpc = p->code; /* starting point */ ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus |= CIST_TAIL; ci->callstatus |= CIST_TAIL;
L->top = func + narg1; /* set top */ L->top.p = func + narg1; /* set top */
return -1; return -1;
} }
default: { /* not a function */ default: { /* not a function */
@ -574,15 +597,15 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
case LUA_VLCL: { /* Lua function */ case LUA_VLCL: { /* Lua function */
CallInfo *ci; CallInfo *ci;
Proto *p = clLvalue(s2v(func))->p; Proto *p = clLvalue(s2v(func))->p;
int narg = cast_int(L->top - func) - 1; /* number of real arguments */ int narg = cast_int(L->top.p - func) - 1; /* number of real arguments */
int nfixparams = p->numparams; int nfixparams = p->numparams;
int fsize = p->maxstacksize; /* frame size */ int fsize = p->maxstacksize; /* frame size */
checkstackGCp(L, fsize, func); checkstackGCp(L, fsize, func);
L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize); L->ci = ci = prepCallInfo(L, func, nresults, 0, func + 1 + fsize);
ci->u.l.savedpc = p->code; /* starting point */ ci->u.l.savedpc = p->code; /* starting point */
for (; narg < nfixparams; narg++) for (; narg < nfixparams; narg++)
setnilvalue(s2v(L->top++)); /* complete missing arguments */ setnilvalue(s2v(L->top.p++)); /* complete missing arguments */
lua_assert(ci->top <= L->stack_last); lua_assert(ci->top.p <= L->stack_last.p);
return ci; return ci;
} }
default: { /* not a function */ default: { /* not a function */
@ -598,12 +621,17 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) {
** Call a function (C or Lua) through C. 'inc' can be 1 (increment ** Call a function (C or Lua) through C. 'inc' can be 1 (increment
** number of recursive invocations in the C stack) or nyci (the same ** number of recursive invocations in the C stack) or nyci (the same
** plus increment number of non-yieldable calls). ** plus increment number of non-yieldable calls).
** This function can be called with some use of EXTRA_STACK, so it should
** check the stack before doing anything else. 'luaD_precall' already
** does that.
*/ */
l_sinline void ccall (lua_State *L, StkId func, int nResults, int inc) { l_sinline void ccall (lua_State *L, StkId func, int nResults, l_uint32 inc) {
CallInfo *ci; CallInfo *ci;
L->nCcalls += inc; L->nCcalls += inc;
if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) if (l_unlikely(getCcalls(L) >= LUAI_MAXCCALLS)) {
checkstackp(L, 0, func); /* free any use of EXTRA_STACK */
luaE_checkcstack(L); luaE_checkcstack(L);
}
if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */ if ((ci = luaD_precall(L, func, nResults)) != NULL) { /* Lua function? */
ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */ ci->callstatus = CIST_FRESH; /* mark that it is a "fresh" execute */
luaV_execute(L, ci); /* call it */ luaV_execute(L, ci); /* call it */
@ -651,8 +679,7 @@ static int finishpcallk (lua_State *L, CallInfo *ci) {
else { /* error */ else { /* error */
StkId func = restorestack(L, ci->u2.funcidx); StkId func = restorestack(L, ci->u2.funcidx);
L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */ L->allowhook = getoah(ci->callstatus); /* restore 'allowhook' */
luaF_close(L, func, status, 1); /* can yield or raise an error */ func = luaF_close(L, func, status, 1); /* can yield or raise an error */
func = restorestack(L, ci->u2.funcidx); /* stack may be moved */
luaD_seterrorobj(L, status, func); luaD_seterrorobj(L, status, func);
luaD_shrinkstack(L); /* restore stack size in case of overflow */ luaD_shrinkstack(L); /* restore stack size in case of overflow */
setcistrecst(ci, LUA_OK); /* clear original status */ setcistrecst(ci, LUA_OK); /* clear original status */
@ -740,8 +767,8 @@ static CallInfo *findpcall (lua_State *L) {
** coroutine error handler and should not kill the coroutine.) ** coroutine error handler and should not kill the coroutine.)
*/ */
static int resume_error (lua_State *L, const char *msg, int narg) { static int resume_error (lua_State *L, const char *msg, int narg) {
L->top -= narg; /* remove args from the stack */ L->top.p -= narg; /* remove args from the stack */
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */ setsvalue2s(L, L->top.p, luaS_new(L, msg)); /* push error message */
api_incr_top(L); api_incr_top(L);
lua_unlock(L); lua_unlock(L);
return LUA_ERRRUN; return LUA_ERRRUN;
@ -757,7 +784,7 @@ static int resume_error (lua_State *L, const char *msg, int narg) {
*/ */
static void resume (lua_State *L, void *ud) { static void resume (lua_State *L, void *ud) {
int n = *(cast(int*, ud)); /* number of arguments */ int n = *(cast(int*, ud)); /* number of arguments */
StkId firstArg = L->top - n; /* first argument */ StkId firstArg = L->top.p - n; /* first argument */
CallInfo *ci = L->ci; CallInfo *ci = L->ci;
if (L->status == LUA_OK) /* starting a coroutine? */ if (L->status == LUA_OK) /* starting a coroutine? */
ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */ ccall(L, firstArg - 1, LUA_MULTRET, 0); /* just call its body */
@ -765,7 +792,7 @@ static void resume (lua_State *L, void *ud) {
lua_assert(L->status == LUA_YIELD); lua_assert(L->status == LUA_YIELD);
L->status = LUA_OK; /* mark that it is running (again) */ L->status = LUA_OK; /* mark that it is running (again) */
if (isLua(ci)) { /* yielded inside a hook? */ if (isLua(ci)) { /* yielded inside a hook? */
L->top = firstArg; /* discard arguments */ L->top.p = firstArg; /* discard arguments */
luaV_execute(L, ci); /* just continue running Lua code */ luaV_execute(L, ci); /* just continue running Lua code */
} }
else { /* 'common' yield */ else { /* 'common' yield */
@ -808,7 +835,7 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
if (L->status == LUA_OK) { /* may be starting a coroutine */ if (L->status == LUA_OK) { /* may be starting a coroutine */
if (L->ci != &L->base_ci) /* not in base level? */ if (L->ci != &L->base_ci) /* not in base level? */
return resume_error(L, "cannot resume non-suspended coroutine", nargs); return resume_error(L, "cannot resume non-suspended coroutine", nargs);
else if (L->top - (L->ci->func + 1) == nargs) /* no function? */ else if (L->top.p - (L->ci->func.p + 1) == nargs) /* no function? */
return resume_error(L, "cannot resume dead coroutine", nargs); return resume_error(L, "cannot resume dead coroutine", nargs);
} }
else if (L->status != LUA_YIELD) /* ended with errors? */ else if (L->status != LUA_YIELD) /* ended with errors? */
@ -826,11 +853,11 @@ LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs,
lua_assert(status == L->status); /* normal end or yield */ lua_assert(status == L->status); /* normal end or yield */
else { /* unrecoverable error */ else { /* unrecoverable error */
L->status = cast_byte(status); /* mark thread as 'dead' */ L->status = cast_byte(status); /* mark thread as 'dead' */
luaD_seterrorobj(L, status, L->top); /* push error message */ luaD_seterrorobj(L, status, L->top.p); /* push error message */
L->ci->top = L->top; L->ci->top.p = L->top.p;
} }
*nresults = (status == LUA_YIELD) ? L->ci->u2.nyield *nresults = (status == LUA_YIELD) ? L->ci->u2.nyield
: cast_int(L->top - (L->ci->func + 1)); : cast_int(L->top.p - (L->ci->func.p + 1));
lua_unlock(L); lua_unlock(L);
return status; return status;
} }
@ -985,7 +1012,7 @@ int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
p.dyd.gt.arr = NULL; p.dyd.gt.size = 0; p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
p.dyd.label.arr = NULL; p.dyd.label.size = 0; p.dyd.label.arr = NULL; p.dyd.label.size = 0;
luaZ_initbuffer(L, &p.buff); luaZ_initbuffer(L, &p.buff);
status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc); status = luaD_pcall(L, f_parser, &p, savestack(L, L->top.p), L->errfunc);
luaZ_freebuffer(L, &p.buff); luaZ_freebuffer(L, &p.buff);
luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size); luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size); luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);

View File

@ -8,6 +8,7 @@
#define ldo_h #define ldo_h
#include "llimits.h"
#include "lobject.h" #include "lobject.h"
#include "lstate.h" #include "lstate.h"
#include "lzio.h" #include "lzio.h"
@ -23,7 +24,7 @@
** at every check. ** at every check.
*/ */
#define luaD_checkstackaux(L,n,pre,pos) \ #define luaD_checkstackaux(L,n,pre,pos) \
if (l_unlikely(L->stack_last - L->top <= (n))) \ if (l_unlikely(L->stack_last.p - L->top.p <= (n))) \
{ pre; luaD_growstack(L, n, 1); pos; } \ { pre; luaD_growstack(L, n, 1); pos; } \
else { condmovestack(L,pre,pos); } else { condmovestack(L,pre,pos); }
@ -32,11 +33,18 @@
#define savestack(L,p) ((char *)(p) - (char *)L->stack) #define savestack(L,pt) (cast_charp(pt) - cast_charp(L->stack.p))
#define restorestack(L,n) ((StkId)((char *)L->stack + (n))) #define restorestack(L,n) cast(StkId, cast_charp(L->stack.p) + (n))
/* macro to check stack size, preserving 'p' */ /* macro to check stack size, preserving 'p' */
#define checkstackp(L,n,p) \
luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p), /* save 'p' */ \
p = restorestack(L, t__)) /* 'pos' part: restore 'p' */
/* macro to check stack size and GC, preserving 'p' */
#define checkstackGCp(L,n,p) \ #define checkstackGCp(L,n,p) \
luaD_checkstackaux(L, n, \ luaD_checkstackaux(L, n, \
ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \ ptrdiff_t t__ = savestack(L, p); /* save 'p' */ \
@ -58,7 +66,8 @@ LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line, LUAI_FUNC void luaD_hook (lua_State *L, int event, int line,
int fTransfer, int nTransfer); int fTransfer, int nTransfer);
LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci); LUAI_FUNC void luaD_hookcall (lua_State *L, CallInfo *ci);
LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, int narg1, int delta); LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func,
int narg1, int delta);
LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults); LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults);
LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults);

View File

@ -10,6 +10,7 @@
#include "lprefix.h" #include "lprefix.h"
#include <limits.h>
#include <stddef.h> #include <stddef.h>
#include "lua.h" #include "lua.h"
@ -55,8 +56,11 @@ static void dumpByte (DumpState *D, int y) {
} }
/* dumpInt Buff Size */ /*
#define DIBS ((sizeof(size_t) * 8 / 7) + 1) ** 'dumpSize' buffer size: each byte can store up to 7 bits. (The "+6"
** rounds up the division.)
*/
#define DIBS ((sizeof(size_t) * CHAR_BIT + 6) / 7)
static void dumpSize (DumpState *D, size_t x) { static void dumpSize (DumpState *D, size_t x) {
lu_byte buff[DIBS]; lu_byte buff[DIBS];

View File

@ -50,8 +50,8 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
for (i = 0; i < cl->nupvalues; i++) { for (i = 0; i < cl->nupvalues; i++) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal)); GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o); UpVal *uv = gco2upv(o);
uv->v = &uv->u.value; /* make it closed */ uv->v.p = &uv->u.value; /* make it closed */
setnilvalue(uv->v); setnilvalue(uv->v.p);
cl->upvals[i] = uv; cl->upvals[i] = uv;
luaC_objbarrier(L, cl, uv); luaC_objbarrier(L, cl, uv);
} }
@ -62,12 +62,11 @@ void luaF_initupvals (lua_State *L, LClosure *cl) {
** Create a new upvalue at the given level, and link it to the list of ** Create a new upvalue at the given level, and link it to the list of
** open upvalues of 'L' after entry 'prev'. ** open upvalues of 'L' after entry 'prev'.
**/ **/
static UpVal *newupval (lua_State *L, int tbc, StkId level, UpVal **prev) { static UpVal *newupval (lua_State *L, StkId level, UpVal **prev) {
GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal)); GCObject *o = luaC_newobj(L, LUA_VUPVAL, sizeof(UpVal));
UpVal *uv = gco2upv(o); UpVal *uv = gco2upv(o);
UpVal *next = *prev; UpVal *next = *prev;
uv->v = s2v(level); /* current value lives in the stack */ uv->v.p = s2v(level); /* current value lives in the stack */
uv->tbc = tbc;
uv->u.open.next = next; /* link it to list of open upvalues */ uv->u.open.next = next; /* link it to list of open upvalues */
uv->u.open.previous = prev; uv->u.open.previous = prev;
if (next) if (next)
@ -96,7 +95,7 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
pp = &p->u.open.next; pp = &p->u.open.next;
} }
/* not found: create a new upvalue after 'pp' */ /* not found: create a new upvalue after 'pp' */
return newupval(L, 0, level, pp); return newupval(L, level, pp);
} }
@ -106,12 +105,12 @@ UpVal *luaF_findupval (lua_State *L, StkId level) {
** (This function assumes EXTRA_STACK.) ** (This function assumes EXTRA_STACK.)
*/ */
static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) { static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
StkId top = L->top; StkId top = L->top.p;
const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE); const TValue *tm = luaT_gettmbyobj(L, obj, TM_CLOSE);
setobj2s(L, top, tm); /* will call metamethod... */ setobj2s(L, top, tm); /* will call metamethod... */
setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */ setobj2s(L, top + 1, obj); /* with 'self' as the 1st argument */
setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */ setobj2s(L, top + 2, err); /* and error msg. as 2nd argument */
L->top = top + 3; /* add function and arguments */ L->top.p = top + 3; /* add function and arguments */
if (yy) if (yy)
luaD_call(L, top, 0); luaD_call(L, top, 0);
else else
@ -126,7 +125,7 @@ static void callclosemethod (lua_State *L, TValue *obj, TValue *err, int yy) {
static void checkclosemth (lua_State *L, StkId level) { static void checkclosemth (lua_State *L, StkId level) {
const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE); const TValue *tm = luaT_gettmbyobj(L, s2v(level), TM_CLOSE);
if (ttisnil(tm)) { /* no metamethod? */ if (ttisnil(tm)) { /* no metamethod? */
int idx = cast_int(level - L->ci->func); /* variable index */ int idx = cast_int(level - L->ci->func.p); /* variable index */
const char *vname = luaG_findlocal(L, L->ci, idx, NULL); const char *vname = luaG_findlocal(L, L->ci, idx, NULL);
if (vname == NULL) vname = "?"; if (vname == NULL) vname = "?";
luaG_runerror(L, "variable '%s' got a non-closable value", vname); luaG_runerror(L, "variable '%s' got a non-closable value", vname);
@ -160,23 +159,23 @@ static void prepcallclosemth (lua_State *L, StkId level, int status, int yy) {
** is used.) ** is used.)
*/ */
#define MAXDELTA \ #define MAXDELTA \
((256ul << ((sizeof(L->stack->tbclist.delta) - 1) * 8)) - 1) ((256ul << ((sizeof(L->stack.p->tbclist.delta) - 1) * 8)) - 1)
/* /*
** Insert a variable in the list of to-be-closed variables. ** Insert a variable in the list of to-be-closed variables.
*/ */
void luaF_newtbcupval (lua_State *L, StkId level) { void luaF_newtbcupval (lua_State *L, StkId level) {
lua_assert(level > L->tbclist); lua_assert(level > L->tbclist.p);
if (l_isfalse(s2v(level))) if (l_isfalse(s2v(level)))
return; /* false doesn't need to be closed */ return; /* false doesn't need to be closed */
checkclosemth(L, level); /* value must have a close method */ checkclosemth(L, level); /* value must have a close method */
while (cast_uint(level - L->tbclist) > MAXDELTA) { while (cast_uint(level - L->tbclist.p) > MAXDELTA) {
L->tbclist += MAXDELTA; /* create a dummy node at maximum delta */ L->tbclist.p += MAXDELTA; /* create a dummy node at maximum delta */
L->tbclist->tbclist.delta = 0; L->tbclist.p->tbclist.delta = 0;
} }
level->tbclist.delta = cast(unsigned short, level - L->tbclist); level->tbclist.delta = cast(unsigned short, level - L->tbclist.p);
L->tbclist = level; L->tbclist.p = level;
} }
@ -196,10 +195,10 @@ void luaF_closeupval (lua_State *L, StkId level) {
StkId upl; /* stack index pointed by 'uv' */ StkId upl; /* stack index pointed by 'uv' */
while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) { while ((uv = L->openupval) != NULL && (upl = uplevel(uv)) >= level) {
TValue *slot = &uv->u.value; /* new position for value */ TValue *slot = &uv->u.value; /* new position for value */
lua_assert(uplevel(uv) < L->top); lua_assert(uplevel(uv) < L->top.p);
luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */ luaF_unlinkupval(uv); /* remove upvalue from 'openupval' list */
setobj(L, slot, uv->v); /* move value to upvalue slot */ setobj(L, slot, uv->v.p); /* move value to upvalue slot */
uv->v = slot; /* now current value lives here */ uv->v.p = slot; /* now current value lives here */
if (!iswhite(uv)) { /* neither white nor dead? */ if (!iswhite(uv)) { /* neither white nor dead? */
nw2black(uv); /* closed upvalues cannot be gray */ nw2black(uv); /* closed upvalues cannot be gray */
luaC_barrier(L, uv, slot); luaC_barrier(L, uv, slot);
@ -209,31 +208,32 @@ void luaF_closeupval (lua_State *L, StkId level) {
/* /*
** Remove firt element from the tbclist plus its dummy nodes. ** Remove first element from the tbclist plus its dummy nodes.
*/ */
static void poptbclist (lua_State *L) { static void poptbclist (lua_State *L) {
StkId tbc = L->tbclist; StkId tbc = L->tbclist.p;
lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */ lua_assert(tbc->tbclist.delta > 0); /* first element cannot be dummy */
tbc -= tbc->tbclist.delta; tbc -= tbc->tbclist.delta;
while (tbc > L->stack && tbc->tbclist.delta == 0) while (tbc > L->stack.p && tbc->tbclist.delta == 0)
tbc -= MAXDELTA; /* remove dummy nodes */ tbc -= MAXDELTA; /* remove dummy nodes */
L->tbclist = tbc; L->tbclist.p = tbc;
} }
/* /*
** Close all upvalues and to-be-closed variables up to the given stack ** Close all upvalues and to-be-closed variables up to the given stack
** level. ** level. Return restored 'level'.
*/ */
void luaF_close (lua_State *L, StkId level, int status, int yy) { StkId luaF_close (lua_State *L, StkId level, int status, int yy) {
ptrdiff_t levelrel = savestack(L, level); ptrdiff_t levelrel = savestack(L, level);
luaF_closeupval(L, level); /* first, close the upvalues */ luaF_closeupval(L, level); /* first, close the upvalues */
while (L->tbclist >= level) { /* traverse tbc's down to that level */ while (L->tbclist.p >= level) { /* traverse tbc's down to that level */
StkId tbc = L->tbclist; /* get variable index */ StkId tbc = L->tbclist.p; /* get variable index */
poptbclist(L); /* remove it from list */ poptbclist(L); /* remove it from list */
prepcallclosemth(L, tbc, status, yy); /* close variable */ prepcallclosemth(L, tbc, status, yy); /* close variable */
level = restorestack(L, levelrel); level = restorestack(L, levelrel);
} }
return level;
} }

View File

@ -29,10 +29,10 @@
#define MAXUPVAL 255 #define MAXUPVAL 255
#define upisopen(up) ((up)->v != &(up)->u.value) #define upisopen(up) ((up)->v.p != &(up)->u.value)
#define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v)) #define uplevel(up) check_exp(upisopen(up), cast(StkId, (up)->v.p))
/* /*
@ -54,7 +54,7 @@ LUAI_FUNC void luaF_initupvals (lua_State *L, LClosure *cl);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level); LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level); LUAI_FUNC void luaF_newtbcupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level); LUAI_FUNC void luaF_closeupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (lua_State *L, StkId level, int status, int yy); LUAI_FUNC StkId luaF_close (lua_State *L, StkId level, int status, int yy);
LUAI_FUNC void luaF_unlinkupval (UpVal *uv); LUAI_FUNC void luaF_unlinkupval (UpVal *uv);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f); LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number, LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,

View File

@ -252,12 +252,13 @@ void luaC_fix (lua_State *L, GCObject *o) {
/* /*
** create a new collectable object (with given type and size) and link ** create a new collectable object (with given type, size, and offset)
** it to 'allgc' list. ** and link it to 'allgc' list.
*/ */
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) { GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz, size_t offset) {
global_State *g = G(L); global_State *g = G(L);
GCObject *o = cast(GCObject *, luaM_newobject(L, novariant(tt), sz)); char *p = cast_charp(luaM_newobject(L, novariant(tt), sz));
GCObject *o = cast(GCObject *, p + offset);
o->marked = luaC_white(g); o->marked = luaC_white(g);
o->tt = tt; o->tt = tt;
o->next = g->allgc; o->next = g->allgc;
@ -265,6 +266,11 @@ GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return o; return o;
} }
GCObject *luaC_newobj (lua_State *L, int tt, size_t sz) {
return luaC_newobjdt(L, tt, sz, 0);
}
/* }====================================================== */ /* }====================================================== */
@ -301,7 +307,7 @@ static void reallymarkobject (global_State *g, GCObject *o) {
set2gray(uv); /* open upvalues are kept gray */ set2gray(uv); /* open upvalues are kept gray */
else else
set2black(uv); /* closed upvalues are visited here */ set2black(uv); /* closed upvalues are visited here */
markvalue(g, uv->v); /* mark its content */ markvalue(g, uv->v.p); /* mark its content */
break; break;
} }
case LUA_VUSERDATA: { case LUA_VUSERDATA: {
@ -376,7 +382,7 @@ static int remarkupvals (global_State *g) {
work++; work++;
if (!iswhite(uv)) { /* upvalue already visited? */ if (!iswhite(uv)) { /* upvalue already visited? */
lua_assert(upisopen(uv) && isgray(uv)); lua_assert(upisopen(uv) && isgray(uv));
markvalue(g, uv->v); /* mark its value */ markvalue(g, uv->v.p); /* mark its value */
} }
} }
} }
@ -620,19 +626,19 @@ static int traverseLclosure (global_State *g, LClosure *cl) {
*/ */
static int traversethread (global_State *g, lua_State *th) { static int traversethread (global_State *g, lua_State *th) {
UpVal *uv; UpVal *uv;
StkId o = th->stack; StkId o = th->stack.p;
if (isold(th) || g->gcstate == GCSpropagate) if (isold(th) || g->gcstate == GCSpropagate)
linkgclist(th, g->grayagain); /* insert into 'grayagain' list */ linkgclist(th, g->grayagain); /* insert into 'grayagain' list */
if (o == NULL) if (o == NULL)
return 1; /* stack not completely built yet */ return 1; /* stack not completely built yet */
lua_assert(g->gcstate == GCSatomic || lua_assert(g->gcstate == GCSatomic ||
th->openupval == NULL || isintwups(th)); th->openupval == NULL || isintwups(th));
for (; o < th->top; o++) /* mark live elements in the stack */ for (; o < th->top.p; o++) /* mark live elements in the stack */
markvalue(g, s2v(o)); markvalue(g, s2v(o));
for (uv = th->openupval; uv != NULL; uv = uv->u.open.next) for (uv = th->openupval; uv != NULL; uv = uv->u.open.next)
markobject(g, uv); /* open upvalues cannot be collected */ markobject(g, uv); /* open upvalues cannot be collected */
if (g->gcstate == GCSatomic) { /* final traversal? */ if (g->gcstate == GCSatomic) { /* final traversal? */
for (; o < th->stack_last + EXTRA_STACK; o++) for (; o < th->stack_last.p + EXTRA_STACK; o++)
setnilvalue(s2v(o)); /* clear dead stack slice */ setnilvalue(s2v(o)); /* clear dead stack slice */
/* 'remarkupvals' may have removed thread from 'twups' list */ /* 'remarkupvals' may have removed thread from 'twups' list */
if (!isintwups(th) && th->openupval != NULL) { if (!isintwups(th) && th->openupval != NULL) {
@ -892,7 +898,7 @@ static GCObject *udata2finalize (global_State *g) {
static void dothecall (lua_State *L, void *ud) { static void dothecall (lua_State *L, void *ud) {
UNUSED(ud); UNUSED(ud);
luaD_callnoyield(L, L->top - 2, 0); luaD_callnoyield(L, L->top.p - 2, 0);
} }
@ -909,16 +915,16 @@ static void GCTM (lua_State *L) {
int oldgcstp = g->gcstp; int oldgcstp = g->gcstp;
g->gcstp |= GCSTPGC; /* avoid GC steps */ g->gcstp |= GCSTPGC; /* avoid GC steps */
L->allowhook = 0; /* stop debug hooks during GC metamethod */ L->allowhook = 0; /* stop debug hooks during GC metamethod */
setobj2s(L, L->top++, tm); /* push finalizer... */ setobj2s(L, L->top.p++, tm); /* push finalizer... */
setobj2s(L, L->top++, &v); /* ... and its argument */ setobj2s(L, L->top.p++, &v); /* ... and its argument */
L->ci->callstatus |= CIST_FIN; /* will run a finalizer */ L->ci->callstatus |= CIST_FIN; /* will run a finalizer */
status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top - 2), 0); status = luaD_pcall(L, dothecall, NULL, savestack(L, L->top.p - 2), 0);
L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */ L->ci->callstatus &= ~CIST_FIN; /* not running a finalizer anymore */
L->allowhook = oldah; /* restore hooks */ L->allowhook = oldah; /* restore hooks */
g->gcstp = oldgcstp; /* restore state */ g->gcstp = oldgcstp; /* restore state */
if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */ if (l_unlikely(status != LUA_OK)) { /* error while running __gc? */
luaE_warnerror(L, "__gc"); luaE_warnerror(L, "__gc");
L->top--; /* pops error object */ L->top.p--; /* pops error object */
} }
} }
} }
@ -1041,7 +1047,25 @@ void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt) {
** ======================================================= ** =======================================================
*/ */
static void setpause (global_State *g);
/*
** Set the "time" to wait before starting a new GC cycle; cycle will
** start when memory use hits the threshold of ('estimate' * pause /
** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
** because Lua cannot even start with less than PAUSEADJ bytes).
*/
static void setpause (global_State *g) {
l_mem threshold, debt;
int pause = getgcparam(g->gcpause);
l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
lua_assert(estimate > 0);
threshold = (pause < MAX_LMEM / estimate) /* overflow? */
? estimate * pause /* no overflow */
: MAX_LMEM; /* overflow; truncate to maximum */
debt = gettotalbytes(g) - threshold;
if (debt > 0) debt = 0;
luaE_setdebt(g, debt);
}
/* /*
@ -1285,6 +1309,15 @@ static void atomic2gen (lua_State *L, global_State *g) {
} }
/*
** Set debt for the next minor collection, which will happen when
** memory grows 'genminormul'%.
*/
static void setminordebt (global_State *g) {
luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
}
/* /*
** Enter generational mode. Must go until the end of an atomic cycle ** Enter generational mode. Must go until the end of an atomic cycle
** to ensure that all objects are correctly marked and weak tables ** to ensure that all objects are correctly marked and weak tables
@ -1297,6 +1330,7 @@ static lu_mem entergen (lua_State *L, global_State *g) {
luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */
numobjs = atomic(L); /* propagates all and then do the atomic stuff */ numobjs = atomic(L); /* propagates all and then do the atomic stuff */
atomic2gen(L, g); atomic2gen(L, g);
setminordebt(g); /* set debt assuming next cycle will be minor */
return numobjs; return numobjs;
} }
@ -1342,15 +1376,6 @@ static lu_mem fullgen (lua_State *L, global_State *g) {
} }
/*
** Set debt for the next minor collection, which will happen when
** memory grows 'genminormul'%.
*/
static void setminordebt (global_State *g) {
luaE_setdebt(g, -(cast(l_mem, (gettotalbytes(g) / 100)) * g->genminormul));
}
/* /*
** Does a major collection after last collection was a "bad collection". ** Does a major collection after last collection was a "bad collection".
** **
@ -1422,8 +1447,8 @@ static void genstep (lua_State *L, global_State *g) {
lu_mem numobjs = fullgen(L, g); /* do a major collection */ lu_mem numobjs = fullgen(L, g); /* do a major collection */
if (gettotalbytes(g) < majorbase + (majorinc / 2)) { if (gettotalbytes(g) < majorbase + (majorinc / 2)) {
/* collected at least half of memory growth since last major /* collected at least half of memory growth since last major
collection; keep doing minor collections */ collection; keep doing minor collections. */
setminordebt(g); lua_assert(g->lastatomic == 0);
} }
else { /* bad collection */ else { /* bad collection */
g->lastatomic = numobjs; /* signal that last collection was bad */ g->lastatomic = numobjs; /* signal that last collection was bad */
@ -1449,26 +1474,6 @@ static void genstep (lua_State *L, global_State *g) {
*/ */
/*
** Set the "time" to wait before starting a new GC cycle; cycle will
** start when memory use hits the threshold of ('estimate' * pause /
** PAUSEADJ). (Division by 'estimate' should be OK: it cannot be zero,
** because Lua cannot even start with less than PAUSEADJ bytes).
*/
static void setpause (global_State *g) {
l_mem threshold, debt;
int pause = getgcparam(g->gcpause);
l_mem estimate = g->GCestimate / PAUSEADJ; /* adjust 'estimate' */
lua_assert(estimate > 0);
threshold = (pause < MAX_LMEM / estimate) /* overflow? */
? estimate * pause /* no overflow */
: MAX_LMEM; /* overflow; truncate to maximum */
debt = gettotalbytes(g) - threshold;
if (debt > 0) debt = 0;
luaE_setdebt(g, debt);
}
/* /*
** Enter first sweep phase. ** Enter first sweep phase.
** The call to 'sweeptolive' makes the pointer point to an object ** The call to 'sweeptolive' makes the pointer point to an object
@ -1676,12 +1681,15 @@ static void incstep (lua_State *L, global_State *g) {
} }
/* /*
** performs a basic GC step if collector is running ** Performs a basic GC step if collector is running. (If collector is
** not running, set a reasonable debt to avoid it being called at
** every single check.)
*/ */
void luaC_step (lua_State *L) { void luaC_step (lua_State *L) {
global_State *g = G(L); global_State *g = G(L);
lua_assert(!g->gcemergency); if (!gcrunning(g)) /* not running? */
if (gcrunning(g)) { /* running? */ luaE_setdebt(g, -2000);
else {
if(isdecGCmodegen(g)) if(isdecGCmodegen(g))
genstep(L, g); genstep(L, g);
else else

View File

@ -172,24 +172,27 @@
#define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0) #define luaC_checkGC(L) luaC_condGC(L,(void)0,(void)0)
#define luaC_barrier(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
luaC_barrier_(L,obj2gco(p),gcvalue(v)) : cast_void(0))
#define luaC_barrierback(L,p,v) ( \
(iscollectable(v) && isblack(p) && iswhite(gcvalue(v))) ? \
luaC_barrierback_(L,p) : cast_void(0))
#define luaC_objbarrier(L,p,o) ( \ #define luaC_objbarrier(L,p,o) ( \
(isblack(p) && iswhite(o)) ? \ (isblack(p) && iswhite(o)) ? \
luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0)) luaC_barrier_(L,obj2gco(p),obj2gco(o)) : cast_void(0))
#define luaC_barrier(L,p,v) ( \
iscollectable(v) ? luaC_objbarrier(L,p,gcvalue(v)) : cast_void(0))
#define luaC_objbarrierback(L,p,o) ( \
(isblack(p) && iswhite(o)) ? luaC_barrierback_(L,p) : cast_void(0))
#define luaC_barrierback(L,p,v) ( \
iscollectable(v) ? luaC_objbarrierback(L, p, gcvalue(v)) : cast_void(0))
LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o); LUAI_FUNC void luaC_fix (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_freeallobjects (lua_State *L); LUAI_FUNC void luaC_freeallobjects (lua_State *L);
LUAI_FUNC void luaC_step (lua_State *L); LUAI_FUNC void luaC_step (lua_State *L);
LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask); LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency); LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz); LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz);
LUAI_FUNC GCObject *luaC_newobjdt (lua_State *L, int tt, size_t sz,
size_t offset);
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v); LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o); LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt); LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);

View File

@ -128,7 +128,7 @@ l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
** ensuring there is only one copy of each unique string. The table ** ensuring there is only one copy of each unique string. The table
** here is used as a set: the string enters as the key, while its value ** here is used as a set: the string enters as the key, while its value
** is irrelevant. We use the string itself as the value only because it ** is irrelevant. We use the string itself as the value only because it
** is a TValue readly available. Later, the code generation can change ** is a TValue readily available. Later, the code generation can change
** this value. ** this value.
*/ */
TString *luaX_newstring (LexState *ls, const char *str, size_t l) { TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
@ -138,12 +138,12 @@ TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
if (!ttisnil(o)) /* string already present? */ if (!ttisnil(o)) /* string already present? */
ts = keystrval(nodefromval(o)); /* get saved copy */ ts = keystrval(nodefromval(o)); /* get saved copy */
else { /* not in use yet */ else { /* not in use yet */
TValue *stv = s2v(L->top++); /* reserve stack space for string */ TValue *stv = s2v(L->top.p++); /* reserve stack space for string */
setsvalue(L, stv, ts); /* temporarily anchor the string */ setsvalue(L, stv, ts); /* temporarily anchor the string */
luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */ luaH_finishset(L, ls->h, stv, o, stv); /* t[string] = string */
/* table is not a metatable, so it does not need to invalidate cache */ /* table is not a metatable, so it does not need to invalidate cache */
luaC_checkGC(L); luaC_checkGC(L);
L->top--; /* remove string from stack */ L->top.p--; /* remove string from stack */
} }
return ts; return ts;
} }

View File

@ -71,11 +71,24 @@ typedef signed char ls_byte;
/* /*
** conversion of pointer to unsigned integer: ** conversion of pointer to unsigned integer: this is for hashing only;
** this is for hashing only; there is no problem if the integer ** there is no problem if the integer cannot hold the whole pointer
** cannot hold the whole pointer value ** value. (In strict ISO C this may cause undefined behavior, but no
** actual machine seems to bother.)
*/ */
#define point2uint(p) ((unsigned int)((size_t)(p) & UINT_MAX)) #if !defined(LUA_USE_C89) && defined(__STDC_VERSION__) && \
__STDC_VERSION__ >= 199901L
#include <stdint.h>
#if defined(UINTPTR_MAX) /* even in C99 this type is optional */
#define L_P2I uintptr_t
#else /* no 'intptr'? */
#define L_P2I uintmax_t /* use the largest available integer */
#endif
#else /* C89 option */
#define L_P2I size_t
#endif
#define point2uint(p) ((unsigned int)((L_P2I)(p) & UINT_MAX))

View File

@ -267,7 +267,7 @@ static int math_type (lua_State *L) {
/* try to find an integer type with at least 64 bits */ /* try to find an integer type with at least 64 bits */
#if (ULONG_MAX >> 31 >> 31) >= 3 #if ((ULONG_MAX >> 31) >> 31) >= 3
/* 'long' has at least 64 bits */ /* 'long' has at least 64 bits */
#define Rand64 unsigned long #define Rand64 unsigned long
@ -277,9 +277,9 @@ static int math_type (lua_State *L) {
/* there is a 'long long' type (which must have at least 64 bits) */ /* there is a 'long long' type (which must have at least 64 bits) */
#define Rand64 unsigned long long #define Rand64 unsigned long long
#elif (LUA_MAXUNSIGNED >> 31 >> 31) >= 3 #elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3
/* 'lua_Integer' has at least 64 bits */ /* 'lua_Unsigned' has at least 64 bits */
#define Rand64 lua_Unsigned #define Rand64 lua_Unsigned
#endif #endif
@ -500,12 +500,12 @@ static lua_Number I2d (Rand64 x) {
/* convert a 'Rand64' to a 'lua_Unsigned' */ /* convert a 'Rand64' to a 'lua_Unsigned' */
static lua_Unsigned I2UInt (Rand64 x) { static lua_Unsigned I2UInt (Rand64 x) {
return ((lua_Unsigned)trim32(x.h) << 31 << 1) | (lua_Unsigned)trim32(x.l); return (((lua_Unsigned)trim32(x.h) << 31) << 1) | (lua_Unsigned)trim32(x.l);
} }
/* convert a 'lua_Unsigned' to a 'Rand64' */ /* convert a 'lua_Unsigned' to a 'Rand64' */
static Rand64 Int2I (lua_Unsigned n) { static Rand64 Int2I (lua_Unsigned n) {
return packI((lu_int32)(n >> 31 >> 1), (lu_int32)n); return packI((lu_int32)((n >> 31) >> 1), (lu_int32)n);
} }
#endif /* } */ #endif /* } */

View File

@ -22,25 +22,6 @@
#include "lstate.h" #include "lstate.h"
#if defined(EMERGENCYGCTESTS)
/*
** First allocation will fail whenever not building initial state.
** (This fail will trigger 'tryagain' and a full GC cycle at every
** allocation.)
*/
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
if (completestate(g) && ns > 0) /* frees never fail */
return NULL; /* fail */
else /* normal allocation */
return (*g->frealloc)(g->ud, block, os, ns);
}
#else
#define firsttry(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
#endif
/* /*
** About the realloc function: ** About the realloc function:
@ -60,6 +41,43 @@ static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
*/ */
/*
** Macro to call the allocation function.
*/
#define callfrealloc(g,block,os,ns) ((*g->frealloc)(g->ud, block, os, ns))
/*
** When an allocation fails, it will try again after an emergency
** collection, except when it cannot run a collection. The GC should
** not be called while the state is not fully built, as the collector
** is not yet fully initialized. Also, it should not be called when
** 'gcstopem' is true, because then the interpreter is in the middle of
** a collection step.
*/
#define cantryagain(g) (completestate(g) && !g->gcstopem)
#if defined(EMERGENCYGCTESTS)
/*
** First allocation will fail except when freeing a block (frees never
** fail) and when it cannot try again; this fail will trigger 'tryagain'
** and a full GC cycle at every allocation.
*/
static void *firsttry (global_State *g, void *block, size_t os, size_t ns) {
if (ns > 0 && cantryagain(g))
return NULL; /* fail */
else /* normal allocation */
return callfrealloc(g, block, os, ns);
}
#else
#define firsttry(g,block,os,ns) callfrealloc(g, block, os, ns)
#endif
/* /*
@ -132,7 +150,7 @@ l_noret luaM_toobig (lua_State *L) {
void luaM_free_ (lua_State *L, void *block, size_t osize) { void luaM_free_ (lua_State *L, void *block, size_t osize) {
global_State *g = G(L); global_State *g = G(L);
lua_assert((osize == 0) == (block == NULL)); lua_assert((osize == 0) == (block == NULL));
(*g->frealloc)(g->ud, block, osize, 0); callfrealloc(g, block, osize, 0);
g->GCdebt -= osize; g->GCdebt -= osize;
} }
@ -140,19 +158,15 @@ void luaM_free_ (lua_State *L, void *block, size_t osize) {
/* /*
** In case of allocation fail, this function will do an emergency ** In case of allocation fail, this function will do an emergency
** collection to free some memory and then try the allocation again. ** collection to free some memory and then try the allocation again.
** The GC should not be called while state is not fully built, as the
** collector is not yet fully initialized. Also, it should not be called
** when 'gcstopem' is true, because then the interpreter is in the
** middle of a collection step.
*/ */
static void *tryagain (lua_State *L, void *block, static void *tryagain (lua_State *L, void *block,
size_t osize, size_t nsize) { size_t osize, size_t nsize) {
global_State *g = G(L); global_State *g = G(L);
if (completestate(g) && !g->gcstopem) { if (cantryagain(g)) {
luaC_fullgc(L, 1); /* try to free some memory... */ luaC_fullgc(L, 1); /* try to free some memory... */
return (*g->frealloc)(g->ud, block, osize, nsize); /* try again */ return callfrealloc(g, block, osize, nsize); /* try again */
} }
else return NULL; /* cannot free any memory without a full state */ else return NULL; /* cannot run an emergency collection */
} }

View File

@ -708,8 +708,13 @@ static const luaL_Reg ll_funcs[] = {
static void createsearcherstable (lua_State *L) { static void createsearcherstable (lua_State *L) {
static const lua_CFunction searchers[] = static const lua_CFunction searchers[] = {
{searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; searcher_preload,
searcher_Lua,
searcher_C,
searcher_Croot,
NULL
};
int i; int i;
/* create 'searchers' table */ /* create 'searchers' table */
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);

View File

@ -62,7 +62,7 @@ static lua_Integer intarith (lua_State *L, int op, lua_Integer v1,
case LUA_OPBOR: return intop(|, v1, v2); case LUA_OPBOR: return intop(|, v1, v2);
case LUA_OPBXOR: return intop(^, v1, v2); case LUA_OPBXOR: return intop(^, v1, v2);
case LUA_OPSHL: return luaV_shiftl(v1, v2); case LUA_OPSHL: return luaV_shiftl(v1, v2);
case LUA_OPSHR: return luaV_shiftl(v1, -v2); case LUA_OPSHR: return luaV_shiftr(v1, v2);
case LUA_OPUNM: return intop(-, 0, v1); case LUA_OPUNM: return intop(-, 0, v1);
case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1); case LUA_OPBNOT: return intop(^, ~l_castS2U(0), v1);
default: lua_assert(0); return 0; default: lua_assert(0); return 0;
@ -386,29 +386,39 @@ void luaO_tostring (lua_State *L, TValue *obj) {
** =================================================================== ** ===================================================================
*/ */
/* size for buffer space used by 'luaO_pushvfstring' */ /*
#define BUFVFS 200 ** Size for buffer space used by 'luaO_pushvfstring'. It should be
** (LUA_IDSIZE + MAXNUMBER2STR) + a minimal space for basic messages,
** so that 'luaG_addinfo' can work directly on the buffer.
*/
#define BUFVFS (LUA_IDSIZE + MAXNUMBER2STR + 95)
/* buffer used by 'luaO_pushvfstring' */ /* buffer used by 'luaO_pushvfstring' */
typedef struct BuffFS { typedef struct BuffFS {
lua_State *L; lua_State *L;
int pushed; /* number of string pieces already on the stack */ int pushed; /* true if there is a part of the result on the stack */
int blen; /* length of partial string in 'space' */ int blen; /* length of partial string in 'space' */
char space[BUFVFS]; /* holds last part of the result */ char space[BUFVFS]; /* holds last part of the result */
} BuffFS; } BuffFS;
/* /*
** Push given string to the stack, as part of the buffer, and ** Push given string to the stack, as part of the result, and
** join the partial strings in the stack into one. ** join it to previous partial result if there is one.
** It may call 'luaV_concat' while using one slot from EXTRA_STACK.
** This call cannot invoke metamethods, as both operands must be
** strings. It can, however, raise an error if the result is too
** long. In that case, 'luaV_concat' frees the extra slot before
** raising the error.
*/ */
static void pushstr (BuffFS *buff, const char *str, size_t l) { static void pushstr (BuffFS *buff, const char *str, size_t lstr) {
lua_State *L = buff->L; lua_State *L = buff->L;
setsvalue2s(L, L->top, luaS_newlstr(L, str, l)); setsvalue2s(L, L->top.p, luaS_newlstr(L, str, lstr));
L->top++; /* may use one extra slot */ L->top.p++; /* may use one slot from EXTRA_STACK */
buff->pushed++; if (!buff->pushed) /* no previous string on the stack? */
luaV_concat(L, buff->pushed); /* join partial results into one */ buff->pushed = 1; /* now there is one */
buff->pushed = 1; else /* join previous string with new one */
luaV_concat(L, 2);
} }
@ -454,7 +464,7 @@ static void addstr2buff (BuffFS *buff, const char *str, size_t slen) {
/* /*
** Add a number to the buffer. ** Add a numeral to the buffer.
*/ */
static void addnum2buff (BuffFS *buff, TValue *num) { static void addnum2buff (BuffFS *buff, TValue *num) {
char *numbuff = getbuff(buff, MAXNUMBER2STR); char *numbuff = getbuff(buff, MAXNUMBER2STR);
@ -532,7 +542,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) {
addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */ addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */
clearbuff(&buff); /* empty buffer into the stack */ clearbuff(&buff); /* empty buffer into the stack */
lua_assert(buff.pushed == 1); lua_assert(buff.pushed == 1);
return svalue(s2v(L->top - 1)); return svalue(s2v(L->top.p - 1));
} }

View File

@ -52,6 +52,8 @@ typedef union Value {
lua_CFunction f; /* light C functions */ lua_CFunction f; /* light C functions */
lua_Integer i; /* integer numbers */ lua_Integer i; /* integer numbers */
lua_Number n; /* float numbers */ lua_Number n; /* float numbers */
/* not used, but may avoid warnings for uninitialized value */
lu_byte ub;
} Value; } Value;
@ -155,6 +157,17 @@ typedef union StackValue {
/* index to stack elements */ /* index to stack elements */
typedef StackValue *StkId; typedef StackValue *StkId;
/*
** When reallocating the stack, change all pointers to the stack into
** proper offsets.
*/
typedef union {
StkId p; /* actual pointer */
ptrdiff_t offset; /* used while the stack is being reallocated */
} StkIdRel;
/* convert a 'StackValue' to a 'TValue' */ /* convert a 'StackValue' to a 'TValue' */
#define s2v(o) (&(o)->val) #define s2v(o) (&(o)->val)
@ -615,8 +628,10 @@ typedef struct Proto {
*/ */
typedef struct UpVal { typedef struct UpVal {
CommonHeader; CommonHeader;
lu_byte tbc; /* true if it represents a to-be-closed variable */ union {
TValue *v; /* points to stack or to its own value */ TValue *p; /* points to stack or to its own value */
ptrdiff_t offset; /* used while the stack is being reallocated */
} v;
union { union {
struct { /* (when open) */ struct { /* (when open) */
struct UpVal *next; /* linked list */ struct UpVal *next; /* linked list */

View File

@ -21,7 +21,7 @@ iABC C(8) | B(8) |k| A(8) | Op(7) |
iABx Bx(17) | A(8) | Op(7) | iABx Bx(17) | A(8) | Op(7) |
iAsBx sBx (signed)(17) | A(8) | Op(7) | iAsBx sBx (signed)(17) | A(8) | Op(7) |
iAx Ax(25) | Op(7) | iAx Ax(25) | Op(7) |
isJ sJ(25) | Op(7) | isJ sJ (signed)(25) | Op(7) |
A signed argument is represented in excess K: the represented value is A signed argument is represented in excess K: the represented value is
the written unsigned value minus K, where K is half the maximum for the the written unsigned value minus K, where K is half the maximum for the

View File

@ -30,23 +30,14 @@
*/ */
#if !defined(LUA_STRFTIMEOPTIONS) /* { */ #if !defined(LUA_STRFTIMEOPTIONS) /* { */
/* options for ANSI C 89 (only 1-char options) */
#define L_STRFTIMEC89 "aAbBcdHIjmMpSUwWxXyYZ%"
/* options for ISO C 99 and POSIX */
#define L_STRFTIMEC99 "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
/* options for Windows */
#define L_STRFTIMEWIN "aAbBcdHIjmMpSUwWxXyYzZ%" \
"||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
#if defined(LUA_USE_WINDOWS) #if defined(LUA_USE_WINDOWS)
#define LUA_STRFTIMEOPTIONS L_STRFTIMEWIN #define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYzZ%" \
#elif defined(LUA_USE_C89) "||" "#c#x#d#H#I#j#m#M#S#U#w#W#y#Y" /* two-char options */
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC89 #elif defined(LUA_USE_C89) /* ANSI C 89 (only 1-char options) */
#define LUA_STRFTIMEOPTIONS "aAbBcdHIjmMpSUwWxXyYZ%"
#else /* C99 specification */ #else /* C99 specification */
#define LUA_STRFTIMEOPTIONS L_STRFTIMEC99 #define LUA_STRFTIMEOPTIONS "aAbBcCdDeFgGhHIjmMnprRStTuUVwWxXyYzZ%" \
"||" "EcECExEXEyEY" "OdOeOHOIOmOMOSOuOUOVOwOWOy" /* two-char options */
#endif #endif
#endif /* } */ #endif /* } */
@ -138,12 +129,21 @@
/* }================================================================== */ /* }================================================================== */
#if !defined(l_system)
#if defined(LUA_USE_IOS)
/* Despite claiming to be ISO C, iOS does not implement 'system'. */
#define l_system(cmd) ((cmd) == NULL ? 0 : -1)
#else
#define l_system(cmd) system(cmd) /* default definition */
#endif
#endif
static int os_execute (lua_State *L) { static int os_execute (lua_State *L) {
const char *cmd = luaL_optstring(L, 1, NULL); const char *cmd = luaL_optstring(L, 1, NULL);
int stat; int stat;
errno = 0; errno = 0;
stat = system(cmd); stat = l_system(cmd);
if (cmd != NULL) if (cmd != NULL)
return luaL_execresult(L, stat); return luaL_execresult(L, stat);
else { else {
@ -260,9 +260,7 @@ static int getfield (lua_State *L, const char *key, int d, int delta) {
res = d; res = d;
} }
else { else {
/* unsigned avoids overflow when lua_Integer has 32 bits */ if (!(res >= 0 ? res - delta <= INT_MAX : INT_MIN + delta <= res))
if (!(res >= 0 ? (lua_Unsigned)res <= (lua_Unsigned)INT_MAX + delta
: (lua_Integer)INT_MIN + delta <= res))
return luaL_error(L, "field '%s' is out-of-bound", key); return luaL_error(L, "field '%s' is out-of-bound", key);
res -= delta; res -= delta;
} }

View File

@ -468,6 +468,7 @@ static void singlevar (LexState *ls, expdesc *var) {
expdesc key; expdesc key;
singlevaraux(fs, ls->envn, var, 1); /* get environment variable */ singlevaraux(fs, ls->envn, var, 1); /* get environment variable */
lua_assert(var->k != VVOID); /* this one must exist */ lua_assert(var->k != VVOID); /* this one must exist */
luaK_exp2anyregup(fs, var); /* but could be a constant */
codestring(&key, varname); /* key is variable name */ codestring(&key, varname); /* key is variable name */
luaK_indexed(fs, var, &key); /* env[varname] */ luaK_indexed(fs, var, &key); /* env[varname] */
} }
@ -520,12 +521,12 @@ static l_noret jumpscopeerror (LexState *ls, Labeldesc *gt) {
/* /*
** Solves the goto at index 'g' to given 'label' and removes it ** Solves the goto at index 'g' to given 'label' and removes it
** from the list of pending goto's. ** from the list of pending gotos.
** If it jumps into the scope of some variable, raises an error. ** If it jumps into the scope of some variable, raises an error.
*/ */
static void solvegoto (LexState *ls, int g, Labeldesc *label) { static void solvegoto (LexState *ls, int g, Labeldesc *label) {
int i; int i;
Labellist *gl = &ls->dyd->gt; /* list of goto's */ Labellist *gl = &ls->dyd->gt; /* list of gotos */
Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */ Labeldesc *gt = &gl->arr[g]; /* goto to be resolved */
lua_assert(eqstr(gt->name, label->name)); lua_assert(eqstr(gt->name, label->name));
if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */ if (l_unlikely(gt->nactvar < label->nactvar)) /* enter some scope? */
@ -579,7 +580,7 @@ static int newgotoentry (LexState *ls, TString *name, int line, int pc) {
/* /*
** Solves forward jumps. Check whether new label 'lb' matches any ** Solves forward jumps. Check whether new label 'lb' matches any
** pending gotos in current block and solves them. Return true ** pending gotos in current block and solves them. Return true
** if any of the goto's need to close upvalues. ** if any of the gotos need to close upvalues.
*/ */
static int solvegotos (LexState *ls, Labeldesc *lb) { static int solvegotos (LexState *ls, Labeldesc *lb) {
Labellist *gl = &ls->dyd->gt; Labellist *gl = &ls->dyd->gt;
@ -600,7 +601,7 @@ static int solvegotos (LexState *ls, Labeldesc *lb) {
/* /*
** Create a new label with the given 'name' at the given 'line'. ** Create a new label with the given 'name' at the given 'line'.
** 'last' tells whether label is the last non-op statement in its ** 'last' tells whether label is the last non-op statement in its
** block. Solves all pending goto's to this new label and adds ** block. Solves all pending gotos to this new label and adds
** a close instruction if necessary. ** a close instruction if necessary.
** Returns true iff it added a close instruction. ** Returns true iff it added a close instruction.
*/ */
@ -673,19 +674,19 @@ static void leaveblock (FuncState *fs) {
LexState *ls = fs->ls; LexState *ls = fs->ls;
int hasclose = 0; int hasclose = 0;
int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */ int stklevel = reglevel(fs, bl->nactvar); /* level outside the block */
if (bl->isloop) /* fix pending breaks? */ removevars(fs, bl->nactvar); /* remove block locals */
lua_assert(bl->nactvar == fs->nactvar); /* back to level on entry */
if (bl->isloop) /* has to fix pending breaks? */
hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0); hasclose = createlabel(ls, luaS_newliteral(ls->L, "break"), 0, 0);
if (!hasclose && bl->previous && bl->upval) if (!hasclose && bl->previous && bl->upval) /* still need a 'close'? */
luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0); luaK_codeABC(fs, OP_CLOSE, stklevel, 0, 0);
fs->bl = bl->previous;
removevars(fs, bl->nactvar);
lua_assert(bl->nactvar == fs->nactvar);
fs->freereg = stklevel; /* free registers */ fs->freereg = stklevel; /* free registers */
ls->dyd->label.n = bl->firstlabel; /* remove local labels */ ls->dyd->label.n = bl->firstlabel; /* remove local labels */
if (bl->previous) /* inner block? */ fs->bl = bl->previous; /* current block now is previous one */
movegotosout(fs, bl); /* update pending gotos to outer block */ if (bl->previous) /* was it a nested block? */
movegotosout(fs, bl); /* update pending gotos to enclosing block */
else { else {
if (bl->firstgoto < ls->dyd->gt.n) /* pending gotos in outer block? */ if (bl->firstgoto < ls->dyd->gt.n) /* still pending gotos? */
undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */ undefgoto(ls, &ls->dyd->gt.arr[bl->firstgoto]); /* error */
} }
} }
@ -1943,10 +1944,10 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
LexState lexstate; LexState lexstate;
FuncState funcstate; FuncState funcstate;
LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */ LClosure *cl = luaF_newLclosure(L, 1); /* create main closure */
setclLvalue2s(L, L->top, cl); /* anchor it (to avoid being collected) */ setclLvalue2s(L, L->top.p, cl); /* anchor it (to avoid being collected) */
luaD_inctop(L); luaD_inctop(L);
lexstate.h = luaH_new(L); /* create table for scanner */ lexstate.h = luaH_new(L); /* create table for scanner */
sethvalue2s(L, L->top, lexstate.h); /* anchor it */ sethvalue2s(L, L->top.p, lexstate.h); /* anchor it */
luaD_inctop(L); luaD_inctop(L);
funcstate.f = cl->p = luaF_newproto(L); funcstate.f = cl->p = luaF_newproto(L);
luaC_objbarrier(L, cl, cl->p); luaC_objbarrier(L, cl, cl->p);
@ -1960,7 +1961,7 @@ LClosure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs); lua_assert(!funcstate.prev && funcstate.nups == 1 && !lexstate.fs);
/* all scopes should be correctly finished */ /* all scopes should be correctly finished */
lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0); lua_assert(dyd->actvar.n == 0 && dyd->gt.n == 0 && dyd->label.n == 0);
L->top--; /* remove scanner's table */ L->top.p--; /* remove scanner's table */
return cl; /* closure is on the stack, too */ return cl; /* closure is on the stack, too */
} }

Some files were not shown because too many files have changed in this diff Show More