* [Tarantool-patches] [WIP luajit 01/15] test: add PUC-Rio Lua 5.1 test suite
2021-03-04 10:23 [Tarantool-patches] [WIP luajit 00/15] Adapt LuaVela test suites Sergey Kaplun via Tarantool-patches
@ 2021-03-04 10:23 ` Sergey Kaplun via Tarantool-patches
2021-03-04 10:23 ` [Tarantool-patches] [WIP luajit 02/15] test: adapt PUC-Rio Lua 5.1 test suite for LuaJIT Sergey Kaplun via Tarantool-patches
` (15 subsequent siblings)
16 siblings, 0 replies; 26+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-03-04 10:23 UTC (permalink / raw)
To: Sergey Ostanevich, Igor Munkin; +Cc: tarantool-patches
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=UTF-8, Size: 210272 bytes --]
This patch adds PUC-Rio Lua 5.1 test suite as a part of the LuaJIT
test suite. Source code taken verbatim from
https://www.lua.org/tests/lua5.1-tests.tar.gz.
<lib1.c> and <lib2.c> is slightly modified to be consistent with the
current LuaJIT's LuaC API.
Some tests may fail after this commit. They will be disabled
or adapted in the next patches.
Part of tarantool/tarantool#5845
Part of tarantool/tarantool#4473
---
.luacheckrc | 5 +-
test/CMakeLists.txt | 2 +
test/PUC-Lua-5.1-tests/CMakeLists.txt | 89 ++
test/PUC-Lua-5.1-tests/README | 41 +
test/PUC-Lua-5.1-tests/all.lua | 137 +++
test/PUC-Lua-5.1-tests/api.lua | 711 +++++++++++++++
test/PUC-Lua-5.1-tests/attrib.lua | 339 ++++++++
test/PUC-Lua-5.1-tests/big.lua | 381 ++++++++
test/PUC-Lua-5.1-tests/calls.lua | 294 +++++++
test/PUC-Lua-5.1-tests/checktable.lua | 77 ++
test/PUC-Lua-5.1-tests/closure.lua | 422 +++++++++
test/PUC-Lua-5.1-tests/code.lua | 143 +++
test/PUC-Lua-5.1-tests/constructs.lua | 240 ++++++
test/PUC-Lua-5.1-tests/db.lua | 499 +++++++++++
test/PUC-Lua-5.1-tests/errors.lua | 250 ++++++
test/PUC-Lua-5.1-tests/etc/ltests.c | 1147 +++++++++++++++++++++++++
test/PUC-Lua-5.1-tests/etc/ltests.h | 92 ++
test/PUC-Lua-5.1-tests/events.lua | 360 ++++++++
test/PUC-Lua-5.1-tests/files.lua | 324 +++++++
test/PUC-Lua-5.1-tests/gc.lua | 312 +++++++
test/PUC-Lua-5.1-tests/libs/lib1.c | 40 +
test/PUC-Lua-5.1-tests/libs/lib11.c | 18 +
test/PUC-Lua-5.1-tests/libs/lib2.c | 28 +
test/PUC-Lua-5.1-tests/libs/lib21.c | 18 +
test/PUC-Lua-5.1-tests/literals.lua | 176 ++++
test/PUC-Lua-5.1-tests/locals.lua | 127 +++
test/PUC-Lua-5.1-tests/main.lua | 159 ++++
test/PUC-Lua-5.1-tests/math.lua | 208 +++++
test/PUC-Lua-5.1-tests/nextvar.lua | 396 +++++++++
test/PUC-Lua-5.1-tests/pm.lua | 273 ++++++
test/PUC-Lua-5.1-tests/sort.lua | 74 ++
test/PUC-Lua-5.1-tests/strings.lua | 176 ++++
test/PUC-Lua-5.1-tests/vararg.lua | 126 +++
test/PUC-Lua-5.1-tests/verybig.lua | 100 +++
34 files changed, 7782 insertions(+), 2 deletions(-)
create mode 100644 test/PUC-Lua-5.1-tests/CMakeLists.txt
create mode 100644 test/PUC-Lua-5.1-tests/README
create mode 100755 test/PUC-Lua-5.1-tests/all.lua
create mode 100644 test/PUC-Lua-5.1-tests/api.lua
create mode 100644 test/PUC-Lua-5.1-tests/attrib.lua
create mode 100644 test/PUC-Lua-5.1-tests/big.lua
create mode 100644 test/PUC-Lua-5.1-tests/calls.lua
create mode 100644 test/PUC-Lua-5.1-tests/checktable.lua
create mode 100644 test/PUC-Lua-5.1-tests/closure.lua
create mode 100644 test/PUC-Lua-5.1-tests/code.lua
create mode 100644 test/PUC-Lua-5.1-tests/constructs.lua
create mode 100644 test/PUC-Lua-5.1-tests/db.lua
create mode 100644 test/PUC-Lua-5.1-tests/errors.lua
create mode 100644 test/PUC-Lua-5.1-tests/etc/ltests.c
create mode 100644 test/PUC-Lua-5.1-tests/etc/ltests.h
create mode 100644 test/PUC-Lua-5.1-tests/events.lua
create mode 100644 test/PUC-Lua-5.1-tests/files.lua
create mode 100644 test/PUC-Lua-5.1-tests/gc.lua
create mode 100644 test/PUC-Lua-5.1-tests/libs/lib1.c
create mode 100644 test/PUC-Lua-5.1-tests/libs/lib11.c
create mode 100644 test/PUC-Lua-5.1-tests/libs/lib2.c
create mode 100644 test/PUC-Lua-5.1-tests/libs/lib21.c
create mode 100644 test/PUC-Lua-5.1-tests/literals.lua
create mode 100644 test/PUC-Lua-5.1-tests/locals.lua
create mode 100644 test/PUC-Lua-5.1-tests/main.lua
create mode 100644 test/PUC-Lua-5.1-tests/math.lua
create mode 100644 test/PUC-Lua-5.1-tests/nextvar.lua
create mode 100644 test/PUC-Lua-5.1-tests/pm.lua
create mode 100644 test/PUC-Lua-5.1-tests/sort.lua
create mode 100644 test/PUC-Lua-5.1-tests/strings.lua
create mode 100644 test/PUC-Lua-5.1-tests/vararg.lua
create mode 100644 test/PUC-Lua-5.1-tests/verybig.lua
diff --git a/.luacheckrc b/.luacheckrc
index 0a5d001..d49301b 100644
--- a/.luacheckrc
+++ b/.luacheckrc
@@ -3,9 +3,10 @@ std = 'luajit'
-- This fork also introduces a new global for misc API namespace.
read_globals = { 'misc' }
--- These files are inherited from the vanilla LuaJIT and need to
--- be coherent with the upstream.
+-- These files are inherited from the vanilla LuaJIT or different
+-- test suites and need to be coherent with the upstream.
exclude_files = {
'dynasm/',
'src/',
+ 'test/PUC-Lua-5.1-tests/',
}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index d166c9d..8e6b4f9 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -32,9 +32,11 @@ else()
)
endif()
+add_subdirectory(PUC-Lua-5.1-tests)
add_subdirectory(tarantool-tests)
add_custom_target(${PROJECT_NAME}-test DEPENDS
+ PUC-Lua-5.1-tests
tarantool-tests
)
diff --git a/test/PUC-Lua-5.1-tests/CMakeLists.txt b/test/PUC-Lua-5.1-tests/CMakeLists.txt
new file mode 100644
index 0000000..ed32a84
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/CMakeLists.txt
@@ -0,0 +1,89 @@
+# Test suite that has been added from PUC-Rio Lua 5.1 test archive
+# in scope of https://github.com/tarantool/tarantool/issues/4473.
+
+# See the rationale in the root CMakeLists.txt.
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+
+set(TEST_RUNNER ${CMAKE_CURRENT_SOURCE_DIR}/all.lua)
+set(LIB_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/libs)
+set(TESTLIB_PATH ${CMAKE_CURRENT_BINARY_DIR}/libs)
+
+# XXX: -fPIC is required to linking with static library.
+if(NOT BUILDMODE STREQUAL "static")
+ # Build additional C libraries for tests.
+ macro(build_lib lib sources)
+ add_library(${lib} SHARED EXCLUDE_FROM_ALL ${sources})
+ target_include_directories(${lib} PRIVATE
+ ${LUAJIT_SOURCE_DIR}
+ )
+ set_target_properties(${lib} PROPERTIES
+ LIBRARY_OUTPUT_DIRECTORY "${TESTLIB_PATH}"
+ PREFIX ""
+ )
+ if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ set_target_properties(${lib} PROPERTIES
+ LINK_FLAGS "-undefined dynamic_lookup"
+ )
+ endif()
+ target_link_libraries(${lib} PRIVATE libluajit_shared)
+ list(APPEND TESTLIBS ${lib})
+ endmacro()
+
+ build_lib(lib1 ${LIB_SOURCES}/lib1.c)
+ build_lib(lib11 ${LIB_SOURCES}/lib1.c ${LIB_SOURCES}/lib11.c)
+ build_lib(lib2 ${LIB_SOURCES}/lib2.c)
+ build_lib(lib21 ${LIB_SOURCES}/lib2.c ${LIB_SOURCES}/lib21.c)
+
+ set(LIB2COPY "${TESTLIB_PATH}/lib2${CMAKE_SHARED_LIBRARY_SUFFIX}")
+ set(LIB_COPY "${TESTLIB_PATH}/-lib2${CMAKE_SHARED_LIBRARY_SUFFIX}")
+
+ add_custom_command(
+ COMMENT "Copping lib2 to -lib2 for PUC-Rio Lua 5.1 tests"
+ OUTPUT ${LIB_COPY}
+ DEPENDS ${TESTLIBS}
+ COMMAND ${CMAKE_COMMAND} -E copy ${LIB2COPY} ${LIB_COPY}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ )
+ list(APPEND TESTLIBS ${LIB_COPY})
+endif()
+
+set(CUSTOM_TEST_DIR ${TESTLIB_PATH}/P1)
+add_custom_command(
+ COMMENT "Create directory for PUC-Rio Lua 5.1 tests"
+ OUTPUT ${CUSTOM_TEST_DIR}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${CUSTOM_TEST_DIR}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+set(LUA_PATH "?\;${CMAKE_CURRENT_SOURCE_DIR}/?.lua")
+
+# TODO: PUC-Rio Lua 5.1 test suite also has special header
+# <ltests.h> and <ltests.c> translation unit to check some
+# internal behaviour of the Lua implementation (see etc/
+# directory). It modifies realloc function to check memory
+# consistency and also contains tests for yield in hooks
+# and for the Lua C API.
+# But, unfortunately, <ltests.c> depends on specific PUC-Rio Lua 5.1
+# internal headers and should be adopted for LuaJIT.
+
+add_custom_target(PUC-Lua-5.1-tests
+ DEPENDS ${LUAJIT_TEST_BINARY} ${TESTLIBS} ${CUSTOM_TEST_DIR}
+)
+
+add_custom_command(TARGET PUC-Lua-5.1-tests
+ COMMENT "Running PUC-Rio Lua 5.1 tests"
+ COMMAND
+ env
+ # Tarantool doesn't support LUA_INIT and most likely it
+ # never will.
+ # See https://github.com/tarantool/tarantool/issues/5744
+ # for more info.
+ # LUA_PATH="${CMAKE_CURRENT_BINARY_DIR}/?.lua\;\;"
+ # LUA_INIT="package.path='?\;'..package.path"
+ # So use less preferable way for tests.
+ LUA_PATH="${LUA_PATH}\;\;"
+ ${LUAJIT_TEST_BINARY} ${TEST_RUNNER}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+)
+
+# vim: expandtab tabstop=2 shiftwidth=2
diff --git a/test/PUC-Lua-5.1-tests/README b/test/PUC-Lua-5.1-tests/README
new file mode 100644
index 0000000..e2d4b28
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/README
@@ -0,0 +1,41 @@
+This tarball contains the official test scripts for Lua 5.1.
+Unlike Lua itself, these tests do not aim portability, small footprint,
+or easy of use. (Their main goal is to try to crash Lua.) They are not
+intended for general use. You are wellcome to use them, but expect to
+have to "dirt your hands".
+
+The tarball should expand in the following contents:
+ - several .lua scripts with the tests
+ - a main "all.lua" Lua script that invokes all the other scripts
+ - a subdirectory "libs" with an empty subdirectory "libs/P1",
+ to be used by the scripts
+ - a subdirectory "etc" with some extra files
+
+To run the tests, do as follows:
+
+- go to the test directory
+
+- set LUA_PATH to "?;./?.lua" (or, better yet, set LUA_PATH to "./?.lua;;"
+ and LUA_INIT to "package.path = '?;'..package.path")
+
+- run "lua all.lua"
+
+
+--------------------------------------------
+Internal tests
+--------------------------------------------
+
+Some tests need a special library, "testC", that gives access to
+several internal structures in Lua.
+This library is only available when Lua is compiled in debug mode.
+The scripts automatically detect its absence and skip those tests.
+
+If you want to run these tests, move etc/ltests.c and etc/ltests.h to
+the directory with the source Lua files, and recompile Lua with
+the option -DLUA_USER_H='"ltests.h"' (or its equivalent to define
+LUA_USER_H as the string "ltests.h", including the quotes). This
+option not only adds the testC library, but it adds several other
+internal tests as well. After the recompilation, run the tests
+as before.
+
+
diff --git a/test/PUC-Lua-5.1-tests/all.lua b/test/PUC-Lua-5.1-tests/all.lua
new file mode 100755
index 0000000..8c4afac
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/all.lua
@@ -0,0 +1,137 @@
+#!../lua
+
+math.randomseed(0)
+
+collectgarbage("setstepmul", 180)
+collectgarbage("setpause", 190)
+
+
+--[=[
+ example of a long [comment],
+ [[spanning several [lines]]]
+
+]=]
+
+print("current path:\n " .. string.gsub(package.path, ";", "\n "))
+
+
+local msgs = {}
+function Message (m)
+ print(m)
+ msgs[#msgs+1] = string.sub(m, 3, -3)
+end
+
+
+local c = os.clock()
+
+assert(os.setlocale"C")
+
+local T,print,gcinfo,format,write,assert,type =
+ T,print,gcinfo,string.format,io.write,assert,type
+
+local function formatmem (m)
+ if m < 1024 then return m
+ else
+ m = m/1024 - m/1024%1
+ if m < 1024 then return m.."K"
+ else
+ m = m/1024 - m/1024%1
+ return m.."M"
+ end
+ end
+end
+
+local showmem = function ()
+ if not T then
+ print(format(" ---- total memory: %s ----\n", formatmem(gcinfo())))
+ else
+ T.checkmemory()
+ local a,b,c = T.totalmem()
+ local d,e = gcinfo()
+ print(format(
+ "\n ---- total memory: %s (%dK), max use: %s, blocks: %d\n",
+ formatmem(a), d, formatmem(c), b))
+ end
+end
+
+
+--
+-- redefine dofile to run files through dump/undump
+--
+dofile = function (n)
+ showmem()
+ local f = assert(loadfile(n))
+ local b = string.dump(f)
+ f = assert(loadstring(b))
+ return f()
+end
+
+dofile('main.lua')
+
+do
+ local u = newproxy(true)
+ local newproxy, stderr = newproxy, io.stderr
+ getmetatable(u).__gc = function (o)
+ stderr:write'.'
+ newproxy(o)
+ end
+end
+
+local f = assert(loadfile('gc.lua'))
+f()
+dofile('db.lua')
+assert(dofile('calls.lua') == deep and deep)
+dofile('strings.lua')
+dofile('literals.lua')
+assert(dofile('attrib.lua') == 27)
+assert(dofile('locals.lua') == 5)
+dofile('constructs.lua')
+dofile('code.lua')
+do
+ local f = coroutine.wrap(assert(loadfile('big.lua')))
+ assert(f() == 'b')
+ assert(f() == 'a')
+end
+dofile('nextvar.lua')
+dofile('pm.lua')
+dofile('api.lua')
+assert(dofile('events.lua') == 12)
+dofile('vararg.lua')
+dofile('closure.lua')
+dofile('errors.lua')
+dofile('math.lua')
+dofile('sort.lua')
+assert(dofile('verybig.lua') == 10); collectgarbage()
+dofile('files.lua')
+
+if #msgs > 0 then
+ print("\ntests not performed:")
+ for i=1,#msgs do
+ print(msgs[i])
+ end
+ print()
+end
+
+print("final OK !!!")
+print('cleaning all!!!!')
+
+debug.sethook(function (a) assert(type(a) == 'string') end, "cr")
+
+local _G, collectgarbage, showmem, print, format, clock =
+ _G, collectgarbage, showmem, print, format, os.clock
+
+local a={}
+for n in pairs(_G) do a[n] = 1 end
+a.tostring = nil
+a.___Glob = nil
+for n in pairs(a) do _G[n] = nil end
+
+a = nil
+collectgarbage()
+collectgarbage()
+collectgarbage()
+collectgarbage()
+collectgarbage()
+collectgarbage();showmem()
+
+print(format("\n\ntotal time: %.2f\n", clock()-c))
diff --git a/test/PUC-Lua-5.1-tests/api.lua b/test/PUC-Lua-5.1-tests/api.lua
new file mode 100644
index 0000000..c955ebf
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/api.lua
@@ -0,0 +1,711 @@
+
+if T==nil then
+ (Message or print)('\a\n >>> testC not active: skipping API tests <<<\n\a')
+ return
+end
+
+
+
+function tcheck (t1, t2)
+ table.remove(t1, 1) -- remove code
+ assert(table.getn(t1) == table.getn(t2))
+ for i=1,table.getn(t1) do assert(t1[i] == t2[i]) end
+end
+
+function pack(...) return arg end
+
+
+print('testing C API')
+
+-- testing allignment
+a = T.d2s(12458954321123)
+assert(string.len(a) == 8) -- sizeof(double)
+assert(T.s2d(a) == 12458954321123)
+
+a,b,c = T.testC("pushnum 1; pushnum 2; pushnum 3; return 2")
+assert(a == 2 and b == 3 and not c)
+
+-- test that all trues are equal
+a,b,c = T.testC("pushbool 1; pushbool 2; pushbool 0; return 3")
+assert(a == b and a == true and c == false)
+a,b,c = T.testC"pushbool 0; pushbool 10; pushnil;\
+ tobool -3; tobool -3; tobool -3; return 3"
+assert(a==0 and b==1 and c==0)
+
+
+a,b,c = T.testC("gettop; return 2", 10, 20, 30, 40)
+assert(a == 40 and b == 5 and not c)
+
+t = pack(T.testC("settop 5; gettop; return .", 2, 3))
+tcheck(t, {n=4,2,3})
+
+t = pack(T.testC("settop 0; settop 15; return 10", 3, 1, 23))
+assert(t.n == 10 and t[1] == nil and t[10] == nil)
+
+t = pack(T.testC("remove -2; gettop; return .", 2, 3, 4))
+tcheck(t, {n=2,2,4})
+
+t = pack(T.testC("insert -1; gettop; return .", 2, 3))
+tcheck(t, {n=2,2,3})
+
+t = pack(T.testC("insert 3; gettop; return .", 2, 3, 4, 5))
+tcheck(t, {n=4,2,5,3,4})
+
+t = pack(T.testC("replace 2; gettop; return .", 2, 3, 4, 5))
+tcheck(t, {n=3,5,3,4})
+
+t = pack(T.testC("replace -2; gettop; return .", 2, 3, 4, 5))
+tcheck(t, {n=3,2,3,5})
+
+t = pack(T.testC("remove 3; gettop; return .", 2, 3, 4, 5))
+tcheck(t, {n=3,2,4,5})
+
+t = pack(T.testC("insert 3; pushvalue 3; remove 3; pushvalue 2; remove 2; \
+ insert 2; pushvalue 1; remove 1; insert 1; \
+ insert -2; pushvalue -2; remove -3; gettop; return .",
+ 2, 3, 4, 5, 10, 40, 90))
+tcheck(t, {n=7,2,3,4,5,10,40,90})
+
+t = pack(T.testC("concat 5; gettop; return .", "alo", 2, 3, "joao", 12))
+tcheck(t, {n=1,"alo23joao12"})
+
+-- testing MULTRET
+t = pack(T.testC("rawcall 2,-1; gettop; return .",
+ function (a,b) return 1,2,3,4,a,b end, "alo", "joao"))
+tcheck(t, {n=6,1,2,3,4,"alo", "joao"})
+
+do -- test returning more results than fit in the caller stack
+ local a = {}
+ for i=1,1000 do a[i] = true end; a[999] = 10
+ local b = T.testC([[call 1 -1; pop 1; tostring -1; return 1]], unpack, a)
+ assert(b == "10")
+end
+
+
+-- testing lessthan
+assert(T.testC("lessthan 2 5, return 1", 3, 2, 2, 4, 2, 2))
+assert(T.testC("lessthan 5 2, return 1", 4, 2, 2, 3, 2, 2))
+assert(not T.testC("lessthan 2 -3, return 1", "4", "2", "2", "3", "2", "2"))
+assert(not T.testC("lessthan -3 2, return 1", "3", "2", "2", "4", "2", "2"))
+
+local b = {__lt = function (a,b) return a[1] < b[1] end}
+local a1,a3,a4 = setmetatable({1}, b),
+ setmetatable({3}, b),
+ setmetatable({4}, b)
+assert(T.testC("lessthan 2 5, return 1", a3, 2, 2, a4, 2, 2))
+assert(T.testC("lessthan 5 -6, return 1", a4, 2, 2, a3, 2, 2))
+a,b = T.testC("lessthan 5 -6, return 2", a1, 2, 2, a3, 2, 20)
+assert(a == 20 and b == false)
+
+
+-- testing lua_is
+
+function count (x, n)
+ n = n or 2
+ local prog = [[
+ isnumber %d;
+ isstring %d;
+ isfunction %d;
+ iscfunction %d;
+ istable %d;
+ isuserdata %d;
+ isnil %d;
+ isnull %d;
+ return 8
+ ]]
+ prog = string.format(prog, n, n, n, n, n, n, n, n)
+ local a,b,c,d,e,f,g,h = T.testC(prog, x)
+ return a+b+c+d+e+f+g+(100*h)
+end
+
+assert(count(3) == 2)
+assert(count('alo') == 1)
+assert(count('32') == 2)
+assert(count({}) == 1)
+assert(count(print) == 2)
+assert(count(function () end) == 1)
+assert(count(nil) == 1)
+assert(count(io.stdin) == 1)
+assert(count(nil, 15) == 100)
+
+-- testing lua_to...
+
+function to (s, x, n)
+ n = n or 2
+ return T.testC(string.format("%s %d; return 1", s, n), x)
+end
+
+assert(to("tostring", {}) == nil)
+assert(to("tostring", "alo") == "alo")
+assert(to("tostring", 12) == "12")
+assert(to("tostring", 12, 3) == nil)
+assert(to("objsize", {}) == 0)
+assert(to("objsize", "alo\0\0a") == 6)
+assert(to("objsize", T.newuserdata(0)) == 0)
+assert(to("objsize", T.newuserdata(101)) == 101)
+assert(to("objsize", 12) == 2)
+assert(to("objsize", 12, 3) == 0)
+assert(to("tonumber", {}) == 0)
+assert(to("tonumber", "12") == 12)
+assert(to("tonumber", "s2") == 0)
+assert(to("tonumber", 1, 20) == 0)
+a = to("tocfunction", math.deg)
+assert(a(3) == math.deg(3) and a ~= math.deg)
+
+
+-- testing errors
+
+a = T.testC([[
+ loadstring 2; call 0,1;
+ pushvalue 3; insert -2; call 1, 1;
+ call 0, 0;
+ return 1
+]], "x=150", function (a) assert(a==nil); return 3 end)
+
+assert(type(a) == 'string' and x == 150)
+
+function check3(p, ...)
+ assert(arg.n == 3)
+ assert(string.find(arg[3], p))
+end
+check3(":1:", T.testC("loadstring 2; gettop; return .", "x="))
+check3("cannot read", T.testC("loadfile 2; gettop; return .", "."))
+check3("cannot open xxxx", T.testC("loadfile 2; gettop; return .", "xxxx"))
+
+-- testing table access
+
+a = {x=0, y=12}
+x, y = T.testC("gettable 2; pushvalue 4; gettable 2; return 2",
+ a, 3, "y", 4, "x")
+assert(x == 0 and y == 12)
+T.testC("settable -5", a, 3, 4, "x", 15)
+assert(a.x == 15)
+a[a] = print
+x = T.testC("gettable 2; return 1", a) -- table and key are the same object!
+assert(x == print)
+T.testC("settable 2", a, "x") -- table and key are the same object!
+assert(a[a] == "x")
+
+b = setmetatable({p = a}, {})
+getmetatable(b).__index = function (t, i) return t.p[i] end
+k, x = T.testC("gettable 3, return 2", 4, b, 20, 35, "x")
+assert(x == 15 and k == 35)
+getmetatable(b).__index = function (t, i) return a[i] end
+getmetatable(b).__newindex = function (t, i,v ) a[i] = v end
+y = T.testC("insert 2; gettable -5; return 1", 2, 3, 4, "y", b)
+assert(y == 12)
+k = T.testC("settable -5, return 1", b, 3, 4, "x", 16)
+assert(a.x == 16 and k == 4)
+a[b] = 'xuxu'
+y = T.testC("gettable 2, return 1", b)
+assert(y == 'xuxu')
+T.testC("settable 2", b, 19)
+assert(a[b] == 19)
+
+-- testing next
+a = {}
+t = pack(T.testC("next; gettop; return .", a, nil))
+tcheck(t, {n=1,a})
+a = {a=3}
+t = pack(T.testC("next; gettop; return .", a, nil))
+tcheck(t, {n=3,a,'a',3})
+t = pack(T.testC("next; pop 1; next; gettop; return .", a, nil))
+tcheck(t, {n=1,a})
+
+
+
+-- testing upvalues
+
+do
+ local A = T.testC[[ pushnum 10; pushnum 20; pushcclosure 2; return 1]]
+ t, b, c = A([[pushvalue U0; pushvalue U1; pushvalue U2; return 3]])
+ assert(b == 10 and c == 20 and type(t) == 'table')
+ a, b = A([[tostring U3; tonumber U4; return 2]])
+ assert(a == nil and b == 0)
+ A([[pushnum 100; pushnum 200; replace U2; replace U1]])
+ b, c = A([[pushvalue U1; pushvalue U2; return 2]])
+ assert(b == 100 and c == 200)
+ A([[replace U2; replace U1]], {x=1}, {x=2})
+ b, c = A([[pushvalue U1; pushvalue U2; return 2]])
+ assert(b.x == 1 and c.x == 2)
+ T.checkmemory()
+end
+
+local f = T.testC[[ pushnum 10; pushnum 20; pushcclosure 2; return 1]]
+assert(T.upvalue(f, 1) == 10 and
+ T.upvalue(f, 2) == 20 and
+ T.upvalue(f, 3) == nil)
+T.upvalue(f, 2, "xuxu")
+assert(T.upvalue(f, 2) == "xuxu")
+
+
+-- testing environments
+
+assert(T.testC"pushvalue G; return 1" == _G)
+assert(T.testC"pushvalue E; return 1" == _G)
+local a = {}
+T.testC("replace E; return 1", a)
+assert(T.testC"pushvalue G; return 1" == _G)
+assert(T.testC"pushvalue E; return 1" == a)
+assert(debug.getfenv(T.testC) == a)
+assert(debug.getfenv(T.upvalue) == _G)
+-- userdata inherit environment
+local u = T.testC"newuserdata 0; return 1"
+assert(debug.getfenv(u) == a)
+-- functions inherit environment
+u = T.testC"pushcclosure 0; return 1"
+assert(debug.getfenv(u) == a)
+debug.setfenv(T.testC, _G)
+assert(T.testC"pushvalue E; return 1" == _G)
+
+local b = newproxy()
+assert(debug.getfenv(b) == _G)
+assert(debug.setfenv(b, a))
+assert(debug.getfenv(b) == a)
+
+
+
+-- testing locks (refs)
+
+-- reuse of references
+local i = T.ref{}
+T.unref(i)
+assert(T.ref{} == i)
+
+Arr = {}
+Lim = 100
+for i=1,Lim do -- lock many objects
+ Arr[i] = T.ref({})
+end
+
+assert(T.ref(nil) == -1 and T.getref(-1) == nil)
+T.unref(-1); T.unref(-1)
+
+for i=1,Lim do -- unlock all them
+ T.unref(Arr[i])
+end
+
+function printlocks ()
+ local n = T.testC("gettable R; return 1", "n")
+ print("n", n)
+ for i=0,n do
+ print(i, T.testC("gettable R; return 1", i))
+ end
+end
+
+
+for i=1,Lim do -- lock many objects
+ Arr[i] = T.ref({})
+end
+
+for i=1,Lim,2 do -- unlock half of them
+ T.unref(Arr[i])
+end
+
+assert(type(T.getref(Arr[2])) == 'table')
+
+
+assert(T.getref(-1) == nil)
+
+
+a = T.ref({})
+
+collectgarbage()
+
+assert(type(T.getref(a)) == 'table')
+
+
+-- colect in cl the `val' of all collected userdata
+tt = {}
+cl = {n=0}
+A = nil; B = nil
+local F
+F = function (x)
+ local udval = T.udataval(x)
+ table.insert(cl, udval)
+ local d = T.newuserdata(100) -- cria lixo
+ d = nil
+ assert(debug.getmetatable(x).__gc == F)
+ loadstring("table.insert({}, {})")() -- cria mais lixo
+ collectgarbage() -- forca coleta de lixo durante coleta!
+ assert(debug.getmetatable(x).__gc == F) -- coleta anterior nao melou isso?
+ local dummy = {} -- cria lixo durante coleta
+ if A ~= nil then
+ assert(type(A) == "userdata")
+ assert(T.udataval(A) == B)
+ debug.getmetatable(A) -- just acess it
+ end
+ A = x -- ressucita userdata
+ B = udval
+ return 1,2,3
+end
+tt.__gc = F
+
+-- test whether udate collection frees memory in the right time
+do
+ collectgarbage();
+ collectgarbage();
+ local x = collectgarbage("count");
+ local a = T.newuserdata(5001)
+ assert(T.testC("objsize 2; return 1", a) == 5001)
+ assert(collectgarbage("count") >= x+4)
+ a = nil
+ collectgarbage();
+ assert(collectgarbage("count") <= x+1)
+ -- udata without finalizer
+ x = collectgarbage("count")
+ collectgarbage("stop")
+ for i=1,1000 do newproxy(false) end
+ assert(collectgarbage("count") > x+10)
+ collectgarbage()
+ assert(collectgarbage("count") <= x+1)
+ -- udata with finalizer
+ x = collectgarbage("count")
+ collectgarbage()
+ collectgarbage("stop")
+ a = newproxy(true)
+ getmetatable(a).__gc = function () end
+ for i=1,1000 do newproxy(a) end
+ assert(collectgarbage("count") >= x+10)
+ collectgarbage() -- this collection only calls TM, without freeing memory
+ assert(collectgarbage("count") >= x+10)
+ collectgarbage() -- now frees memory
+ assert(collectgarbage("count") <= x+1)
+end
+
+
+collectgarbage("stop")
+
+-- create 3 userdatas with tag `tt'
+a = T.newuserdata(0); debug.setmetatable(a, tt); na = T.udataval(a)
+b = T.newuserdata(0); debug.setmetatable(b, tt); nb = T.udataval(b)
+c = T.newuserdata(0); debug.setmetatable(c, tt); nc = T.udataval(c)
+
+-- create userdata without meta table
+x = T.newuserdata(4)
+y = T.newuserdata(0)
+
+assert(debug.getmetatable(x) == nil and debug.getmetatable(y) == nil)
+
+d=T.ref(a);
+e=T.ref(b);
+f=T.ref(c);
+t = {T.getref(d), T.getref(e), T.getref(f)}
+assert(t[1] == a and t[2] == b and t[3] == c)
+
+t=nil; a=nil; c=nil;
+T.unref(e); T.unref(f)
+
+collectgarbage()
+
+-- check that unref objects have been collected
+assert(table.getn(cl) == 1 and cl[1] == nc)
+
+x = T.getref(d)
+assert(type(x) == 'userdata' and debug.getmetatable(x) == tt)
+x =nil
+tt.b = b -- create cycle
+tt=nil -- frees tt for GC
+A = nil
+b = nil
+T.unref(d);
+n5 = T.newuserdata(0)
+debug.setmetatable(n5, {__gc=F})
+n5 = T.udataval(n5)
+collectgarbage()
+assert(table.getn(cl) == 4)
+-- check order of collection
+assert(cl[2] == n5 and cl[3] == nb and cl[4] == na)
+
+
+a, na = {}, {}
+for i=30,1,-1 do
+ a[i] = T.newuserdata(0)
+ debug.setmetatable(a[i], {__gc=F})
+ na[i] = T.udataval(a[i])
+end
+cl = {}
+a = nil; collectgarbage()
+assert(table.getn(cl) == 30)
+for i=1,30 do assert(cl[i] == na[i]) end
+na = nil
+
+
+for i=2,Lim,2 do -- unlock the other half
+ T.unref(Arr[i])
+end
+
+x = T.newuserdata(41); debug.setmetatable(x, {__gc=F})
+assert(T.testC("objsize 2; return 1", x) == 41)
+cl = {}
+a = {[x] = 1}
+x = T.udataval(x)
+collectgarbage()
+-- old `x' cannot be collected (`a' still uses it)
+assert(table.getn(cl) == 0)
+for n in pairs(a) do a[n] = nil end
+collectgarbage()
+assert(table.getn(cl) == 1 and cl[1] == x) -- old `x' must be collected
+
+-- testing lua_equal
+assert(T.testC("equal 2 4; return 1", print, 1, print, 20))
+assert(T.testC("equal 3 2; return 1", 'alo', "alo"))
+assert(T.testC("equal 2 3; return 1", nil, nil))
+assert(not T.testC("equal 2 3; return 1", {}, {}))
+assert(not T.testC("equal 2 3; return 1"))
+assert(not T.testC("equal 2 3; return 1", 3))
+
+-- testing lua_equal with fallbacks
+do
+ local map = {}
+ local t = {__eq = function (a,b) return map[a] == map[b] end}
+ local function f(x)
+ local u = T.newuserdata(0)
+ debug.setmetatable(u, t)
+ map[u] = x
+ return u
+ end
+ assert(f(10) == f(10))
+ assert(f(10) ~= f(11))
+ assert(T.testC("equal 2 3; return 1", f(10), f(10)))
+ assert(not T.testC("equal 2 3; return 1", f(10), f(20)))
+ t.__eq = nil
+ assert(f(10) ~= f(10))
+end
+
+print'+'
+
+
+
+-------------------------------------------------------------------------
+do -- testing errors during GC
+ local a = {}
+ for i=1,20 do
+ a[i] = T.newuserdata(i) -- creates several udata
+ end
+ for i=1,20,2 do -- mark half of them to raise error during GC
+ debug.setmetatable(a[i], {__gc = function (x) error("error inside gc") end})
+ end
+ for i=2,20,2 do -- mark the other half to count and to create more garbage
+ debug.setmetatable(a[i], {__gc = function (x) loadstring("A=A+1")() end})
+ end
+ _G.A = 0
+ a = 0
+ while 1 do
+ if xpcall(collectgarbage, function (s) a=a+1 end) then
+ break -- stop if no more errors
+ end
+ end
+ assert(a == 10) -- number of errors
+ assert(A == 10) -- number of normal collections
+end
+-------------------------------------------------------------------------
+-- test for userdata vals
+do
+ local a = {}; local lim = 30
+ for i=0,lim do a[i] = T.pushuserdata(i) end
+ for i=0,lim do assert(T.udataval(a[i]) == i) end
+ for i=0,lim do assert(T.pushuserdata(i) == a[i]) end
+ for i=0,lim do a[a[i]] = i end
+ for i=0,lim do a[T.pushuserdata(i)] = i end
+ assert(type(tostring(a[1])) == "string")
+end
+
+
+-------------------------------------------------------------------------
+-- testing multiple states
+T.closestate(T.newstate());
+L1 = T.newstate()
+assert(L1)
+assert(pack(T.doremote(L1, "function f () return 'alo', 3 end; f()")).n == 0)
+
+a, b = T.doremote(L1, "return f()")
+assert(a == 'alo' and b == '3')
+
+T.doremote(L1, "_ERRORMESSAGE = nil")
+-- error: `sin' is not defined
+a, b = T.doremote(L1, "return sin(1)")
+assert(a == nil and b == 2) -- 2 == run-time error
+
+-- error: syntax error
+a, b, c = T.doremote(L1, "return a+")
+assert(a == nil and b == 3 and type(c) == "string") -- 3 == syntax error
+
+T.loadlib(L1)
+a, b = T.doremote(L1, [[
+ a = strlibopen()
+ a = packageopen()
+ a = baselibopen(); assert(a == _G and require("_G") == a)
+ a = iolibopen(); assert(type(a.read) == "function")
+ assert(require("io") == a)
+ a = tablibopen(); assert(type(a.insert) == "function")
+ a = dblibopen(); assert(type(a.getlocal) == "function")
+ a = mathlibopen(); assert(type(a.sin) == "function")
+ return string.sub('okinama', 1, 2)
+]])
+assert(a == "ok")
+
+T.closestate(L1);
+
+L1 = T.newstate()
+T.loadlib(L1)
+T.doremote(L1, "a = {}")
+T.testC(L1, [[pushstring a; gettable G; pushstring x; pushnum 1;
+ settable -3]])
+assert(T.doremote(L1, "return a.x") == "1")
+
+T.closestate(L1)
+
+L1 = nil
+
+print('+')
+
+-------------------------------------------------------------------------
+-- testing memory limits
+-------------------------------------------------------------------------
+collectgarbage()
+T.totalmem(T.totalmem()+5000) -- set low memory limit (+5k)
+assert(not pcall(loadstring"local a={}; for i=1,100000 do a[i]=i end"))
+T.totalmem(1000000000) -- restore high limit
+
+
+local function stack(x) if x>0 then stack(x-1) end end
+
+-- test memory errors; increase memory limit in small steps, so that
+-- we get memory errors in different parts of a given task, up to there
+-- is enough memory to complete the task without errors
+function testamem (s, f)
+ collectgarbage()
+ stack(10) -- ensure minimum stack size
+ local M = T.totalmem()
+ local oldM = M
+ local a,b = nil
+ while 1 do
+ M = M+3 -- increase memory limit in small steps
+ T.totalmem(M)
+ a, b = pcall(f)
+ if a and b then break end -- stop when no more errors
+ collectgarbage()
+ if not a and not string.find(b, "memory") then -- `real' error?
+ T.totalmem(1000000000) -- restore high limit
+ error(b, 0)
+ end
+ end
+ T.totalmem(1000000000) -- restore high limit
+ print("\nlimit for " .. s .. ": " .. M-oldM)
+ return b
+end
+
+
+-- testing memory errors when creating a new state
+
+b = testamem("state creation", T.newstate)
+T.closestate(b); -- close new state
+
+
+-- testing threads
+
+function expand (n,s)
+ if n==0 then return "" end
+ local e = string.rep("=", n)
+ return string.format("T.doonnewstack([%s[ %s;\n collectgarbage(); %s]%s])\n",
+ e, s, expand(n-1,s), e)
+end
+
+G=0; collectgarbage(); a =collectgarbage("count")
+loadstring(expand(20,"G=G+1"))()
+assert(G==20); collectgarbage(); -- assert(gcinfo() <= a+1)
+
+testamem("thread creation", function ()
+ return T.doonnewstack("x=1") == 0 -- try to create thread
+end)
+
+
+-- testing memory x compiler
+
+testamem("loadstring", function ()
+ return loadstring("x=1") -- try to do a loadstring
+end)
+
+
+local testprog = [[
+local function foo () return end
+local t = {"x"}
+a = "aaa"
+for _, v in ipairs(t) do a=a..v end
+return true
+]]
+
+-- testing memory x dofile
+_G.a = nil
+local t =os.tmpname()
+local f = assert(io.open(t, "w"))
+f:write(testprog)
+f:close()
+testamem("dofile", function ()
+ local a = loadfile(t)
+ return a and a()
+end)
+assert(os.remove(t))
+assert(_G.a == "aaax")
+
+
+-- other generic tests
+
+testamem("string creation", function ()
+ local a, b = string.gsub("alo alo", "(a)", function (x) return x..'b' end)
+ return (a == 'ablo ablo')
+end)
+
+testamem("dump/undump", function ()
+ local a = loadstring(testprog)
+ local b = a and string.dump(a)
+ a = b and loadstring(b)
+ return a and a()
+end)
+
+local t = os.tmpname()
+testamem("file creation", function ()
+ local f = assert(io.open(t, 'w'))
+ assert (not io.open"nomenaoexistente")
+ io.close(f);
+ return not loadfile'nomenaoexistente'
+end)
+assert(os.remove(t))
+
+testamem("table creation", function ()
+ local a, lim = {}, 10
+ for i=1,lim do a[i] = i; a[i..'a'] = {} end
+ return (type(a[lim..'a']) == 'table' and a[lim] == lim)
+end)
+
+local a = 1
+close = nil
+testamem("closure creation", function ()
+ function close (b,c)
+ return function (x) return a+b+c+x end
+ end
+ return (close(2,3)(4) == 10)
+end)
+
+testamem("coroutines", function ()
+ local a = coroutine.wrap(function ()
+ coroutine.yield(string.rep("a", 10))
+ return {}
+ end)
+ assert(string.len(a()) == 10)
+ return a()
+end)
+
+print'+'
+
+-- testing some auxlib functions
+assert(T.gsub("alo.alo.uhuh.", ".", "//") == "alo//alo//uhuh//")
+assert(T.gsub("alo.alo.uhuh.", "alo", "//") == "//.//.uhuh.")
+assert(T.gsub("", "alo", "//") == "")
+assert(T.gsub("...", ".", "/.") == "/././.")
+assert(T.gsub("...", "...", "") == "")
+
+
+print'OK'
+
diff --git a/test/PUC-Lua-5.1-tests/attrib.lua b/test/PUC-Lua-5.1-tests/attrib.lua
new file mode 100644
index 0000000..655669b
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/attrib.lua
@@ -0,0 +1,339 @@
+do --[
+
+print "testing require"
+
+assert(require"string" == string)
+assert(require"math" == math)
+assert(require"table" == table)
+assert(require"io" == io)
+assert(require"os" == os)
+assert(require"debug" == debug)
+assert(require"coroutine" == coroutine)
+
+assert(type(package.path) == "string")
+assert(type(package.cpath) == "string")
+assert(type(package.loaded) == "table")
+assert(type(package.preload) == "table")
+
+
+local DIR = "libs/"
+
+local function createfiles (files, preextras, posextras)
+ for n,c in pairs(files) do
+ io.output(DIR..n)
+ io.write(string.format(preextras, n))
+ io.write(c)
+ io.write(string.format(posextras, n))
+ io.close(io.output())
+ end
+end
+
+function removefiles (files)
+ for n in pairs(files) do
+ os.remove(DIR..n)
+ end
+end
+
+local files = {
+ ["A.lua"] = "",
+ ["B.lua"] = "assert(...=='B');require 'A'",
+ ["A.lc"] = "",
+ ["A"] = "",
+ ["L"] = "",
+ ["XXxX"] = "",
+ ["C.lua"] = "package.loaded[...] = 25; require'C'"
+}
+
+AA = nil
+local extras = [[
+NAME = '%s'
+REQUIRED = ...
+return AA]]
+
+createfiles(files, "", extras)
+
+
+local oldpath = package.path
+
+package.path = string.gsub("D/?.lua;D/?.lc;D/?;D/??x?;D/L", "D/", DIR)
+
+local try = function (p, n, r)
+ NAME = nil
+ local rr = require(p)
+ assert(NAME == n)
+ assert(REQUIRED == p)
+ assert(rr == r)
+end
+
+assert(require"C" == 25)
+assert(require"C" == 25)
+AA = nil
+try('B', 'B.lua', true)
+assert(package.loaded.B)
+assert(require"B" == true)
+assert(package.loaded.A)
+package.loaded.A = nil
+try('B', nil, true) -- should not reload package
+try('A', 'A.lua', true)
+package.loaded.A = nil
+os.remove(DIR..'A.lua')
+AA = {}
+try('A', 'A.lc', AA) -- now must find second option
+assert(require("A") == AA)
+AA = false
+try('K', 'L', false) -- default option
+try('K', 'L', false) -- default option (should reload it)
+assert(rawget(_G, "_REQUIREDNAME") == nil)
+
+AA = "x"
+try("X", "XXxX", AA)
+
+
+removefiles(files)
+
+
+-- testing require of sub-packages
+
+package.path = string.gsub("D/?.lua;D/?/init.lua", "D/", DIR)
+
+files = {
+ ["P1/init.lua"] = "AA = 10",
+ ["P1/xuxu.lua"] = "AA = 20",
+}
+
+createfiles(files, "module(..., package.seeall)\n", "")
+AA = 0
+
+local m = assert(require"P1")
+assert(m == P1 and m._NAME == "P1" and AA == 0 and m.AA == 10)
+assert(require"P1" == P1 and P1 == m)
+assert(require"P1" == P1)
+assert(P1._PACKAGE == "")
+
+local m = assert(require"P1.xuxu")
+assert(m == P1.xuxu and m._NAME == "P1.xuxu" and AA == 0 and m.AA == 20)
+assert(require"P1.xuxu" == P1.xuxu and P1.xuxu == m)
+assert(require"P1.xuxu" == P1.xuxu)
+assert(require"P1" == P1)
+assert(P1.xuxu._PACKAGE == "P1.")
+assert(P1.AA == 10 and P1._PACKAGE == "")
+assert(P1._G == _G and P1.xuxu._G == _G)
+
+
+
+removefiles(files)
+
+
+package.path = ""
+assert(not pcall(require, "file_does_not_exist"))
+package.path = "??\0?"
+assert(not pcall(require, "file_does_not_exist1"))
+
+package.path = oldpath
+
+-- check 'require' error message
+local fname = "file_does_not_exist2"
+local m, err = pcall(require, fname)
+for t in string.gmatch(package.path..";"..package.cpath, "[^;]+") do
+ t = string.gsub(t, "?", fname)
+ assert(string.find(err, t, 1, true))
+end
+
+
+local function import(...)
+ local f = {...}
+ return function (m)
+ for i=1, #f do m[f[i]] = _G[f[i]] end
+ end
+end
+
+local assert, module, package = assert, module, package
+X = nil; x = 0; assert(_G.x == 0) -- `x' must be a global variable
+module"X"; x = 1; assert(_M.x == 1)
+module"X.a.b.c"; x = 2; assert(_M.x == 2)
+module("X.a.b", package.seeall); x = 3
+assert(X._NAME == "X" and X.a.b.c._NAME == "X.a.b.c" and X.a.b._NAME == "X.a.b")
+assert(X._M == X and X.a.b.c._M == X.a.b.c and X.a.b._M == X.a.b)
+assert(X.x == 1 and X.a.b.c.x == 2 and X.a.b.x == 3)
+assert(X._PACKAGE == "" and X.a.b.c._PACKAGE == "X.a.b." and
+ X.a.b._PACKAGE == "X.a.")
+assert(_PACKAGE.."c" == "X.a.c")
+assert(X.a._NAME == nil and X.a._M == nil)
+module("X.a", import("X")) ; x = 4
+assert(X.a._NAME == "X.a" and X.a.x == 4 and X.a._M == X.a)
+module("X.a.b", package.seeall); assert(x == 3); x = 5
+assert(_NAME == "X.a.b" and X.a.b.x == 5)
+
+assert(X._G == nil and X.a._G == nil and X.a.b._G == _G and X.a.b.c._G == nil)
+
+setfenv(1, _G)
+assert(x == 0)
+
+assert(not pcall(module, "x"))
+assert(not pcall(module, "math.sin"))
+
+
+-- testing C libraries
+
+
+local p = "" -- On Mac OS X, redefine this to "_"
+
+-- assert(loadlib == package.loadlib) -- only for compatibility
+local f, err, when = package.loadlib("libs/lib1.so", p.."luaopen_lib1")
+if not f then
+ (Message or print)('\a\n >>> cannot load dynamic library <<<\n\a')
+ print(err, when)
+else
+ f() -- open library
+ assert(require("lib1") == lib1)
+ collectgarbage()
+ assert(lib1.id("x") == "x")
+ f = assert(package.loadlib("libs/lib1.so", p.."anotherfunc"))
+ assert(f(10, 20) == "1020\n")
+ f, err, when = package.loadlib("libs/lib1.so", p.."xuxu")
+ assert(not f and type(err) == "string" and when == "init")
+ package.cpath = "libs/?.so"
+ require"lib2"
+ assert(lib2.id("x") == "x")
+ local fs = require"lib1.sub"
+ assert(fs == lib1.sub and next(lib1.sub) == nil)
+ module("lib2", package.seeall)
+ f = require"-lib2"
+ assert(f.id("x") == "x" and _M == f and _NAME == "lib2")
+ module("lib1.sub", package.seeall)
+ assert(_M == fs)
+ setfenv(1, _G)
+
+end
+f, err, when = package.loadlib("donotexist", p.."xuxu")
+assert(not f and type(err) == "string" and (when == "open" or when == "absent"))
+
+
+-- testing preload
+
+do
+ local p = package
+ package = {}
+ p.preload.pl = function (...)
+ module(...)
+ function xuxu (x) return x+20 end
+ end
+
+ require"pl"
+ assert(require"pl" == pl)
+ assert(pl.xuxu(10) == 30)
+
+ package = p
+ assert(type(package.path) == "string")
+end
+
+
+
+end --]
+
+print('+')
+
+print("testing assignments, logical operators, and constructors")
+
+local res, res2 = 27
+
+a, b = 1, 2+3
+assert(a==1 and b==5)
+a={}
+function f() return 10, 11, 12 end
+a.x, b, a[1] = 1, 2, f()
+assert(a.x==1 and b==2 and a[1]==10)
+a[f()], b, a[f()+3] = f(), a, 'x'
+assert(a[10] == 10 and b == a and a[13] == 'x')
+
+do
+ local f = function (n) local x = {}; for i=1,n do x[i]=i end;
+ return unpack(x) end;
+ local a,b,c
+ a,b = 0, f(1)
+ assert(a == 0 and b == 1)
+ A,b = 0, f(1)
+ assert(A == 0 and b == 1)
+ a,b,c = 0,5,f(4)
+ assert(a==0 and b==5 and c==1)
+ a,b,c = 0,5,f(0)
+ assert(a==0 and b==5 and c==nil)
+end
+
+
+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)
+
+d = 20
+a, b, c, d = f()
+assert(a==10 and b==11 and c==12 and d==nil)
+a,b = f(), 1, 2, 3, f()
+assert(a==10 and b==1)
+
+assert(a<b == false and a>b == true)
+assert((10 and 2) == 2)
+assert((10 or 2) == 10)
+assert((10 or assert(nil)) == 10)
+assert(not (nil and assert(nil)))
+assert((nil or "alo") == "alo")
+assert((nil and 10) == nil)
+assert((false and 10) == false)
+assert((true or 10) == true)
+assert((false or 10) == 10)
+assert(false ~= nil)
+assert(nil ~= false)
+assert(not nil == true)
+assert(not not nil == false)
+assert(not not 1 == true)
+assert(not not a == true)
+assert(not not (6 or nil) == true)
+assert(not not (nil and 56) == false)
+assert(not not (nil and true) == false)
+print('+')
+
+a = {}
+a[true] = 20
+a[false] = 10
+assert(a[1<2] == 20 and a[1>2] == 10)
+
+function f(a) return a end
+
+local a = {}
+for i=3000,-3000,-1 do a[i] = i; end
+a[10e30] = "alo"; a[true] = 10; a[false] = 20
+assert(a[10e30] == 'alo' and a[not 1] == 20 and a[10<20] == 10)
+for i=3000,-3000,-1 do assert(a[i] == i); end
+a[print] = assert
+a[f] = print
+a[a] = a
+assert(a[a][a][a][a][print] == assert)
+a[print](a[a[f]] == a[print])
+a = nil
+
+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]
+assert(a[1]==10 and a[-3]==a.a and a[f]==print and a.x=='a' and not a.y)
+a[1], f(a)[2], b, c = {['alo']=assert}, 10, a[1], a[f], 6, 10, 23, f(a), 2
+a[1].alo(a[2]==10 and b==10 and c==print)
+
+a[2^31] = 10; a[2^31+1] = 11; a[-2^31] = 12;
+a[2^32] = 13; a[-2^32] = 14; a[2^32+1] = 15; a[10^33] = 16;
+
+assert(a[2^31] == 10 and a[2^31+1] == 11 and a[-2^31] == 12 and
+ a[2^32] == 13 and a[-2^32] == 14 and a[2^32+1] == 15 and
+ a[10^33] == 16)
+
+a = nil
+
+
+do
+ local a,i,j,b
+ a = {'a', 'b'}; i=1; j=2; b=a
+ i, a[i], a, j, a[j], a[i+j] = j, i, i, b, j, i
+ assert(i == 2 and b[1] == 1 and a == 1 and j == b and b[2] == 2 and
+ b[3] == 1)
+end
+
+print('OK')
+
+return res
diff --git a/test/PUC-Lua-5.1-tests/big.lua b/test/PUC-Lua-5.1-tests/big.lua
new file mode 100644
index 0000000..9261288
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/big.lua
@@ -0,0 +1,381 @@
+print "testing string length overflow"
+
+local longs = string.rep("\0", 2^25)
+local function catter (i)
+ return assert(loadstring(
+ string.format("return function(a) return a%s end",
+ string.rep("..a", i-1))))()
+end
+rep129 = catter(129)
+local a, b = pcall(rep129, longs)
+assert(not a and string.find(b, "overflow"))
+print('+')
+
+
+require "checktable"
+
+--[[ lots of empty lines (to force SETLINEW)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+--]]
+
+
+a,b = nil,nil
+while not b do
+if a then
+b = { -- lots of strings (to force JMPW and PUSHCONSTANTW)
+"n1", "n2", "n3", "n4", "n5", "n6", "n7", "n8", "n9", "n10",
+"n11", "n12", "j301", "j302", "j303", "j304", "j305", "j306", "j307", "j308",
+"j309", "a310", "n311", "n312", "n313", "n314", "n315", "n316", "n317", "n318",
+"n319", "n320", "n321", "n322", "n323", "n324", "n325", "n326", "n327", "n328",
+"a329", "n330", "n331", "n332", "n333", "n334", "n335", "n336", "n337", "n338",
+"n339", "n340", "n341", "z342", "n343", "n344", "n345", "n346", "n347", "n348",
+"n349", "n350", "n351", "n352", "r353", "n354", "n355", "n356", "n357", "n358",
+"n359", "n360", "n361", "n362", "n363", "n364", "n365", "n366", "z367", "n368",
+"n369", "n370", "n371", "n372", "n373", "n374", "n375", "a376", "n377", "n378",
+"n379", "n380", "n381", "n382", "n383", "n384", "n385", "n386", "n387", "n388",
+"n389", "n390", "n391", "n392", "n393", "n394", "n395", "n396", "n397", "n398",
+"n399", "n400", "n13", "n14", "n15", "n16", "n17", "n18", "n19", "n20",
+"n21", "n22", "n23", "a24", "n25", "n26", "n27", "n28", "n29", "j30",
+"n31", "n32", "n33", "n34", "n35", "n36", "n37", "n38", "n39", "n40",
+"n41", "n42", "n43", "n44", "n45", "n46", "n47", "n48", "n49", "n50",
+"n51", "n52", "n53", "n54", "n55", "n56", "n57", "n58", "n59", "n60",
+"n61", "n62", "n63", "n64", "n65", "a66", "z67", "n68", "n69", "n70",
+"n71", "n72", "n73", "n74", "n75", "n76", "n77", "n78", "n79", "n80",
+"n81", "n82", "n83", "n84", "n85", "n86", "n87", "n88", "n89", "n90",
+"n91", "n92", "n93", "n94", "n95", "n96", "n97", "n98", "n99", "n100",
+"n201", "n202", "n203", "n204", "n205", "n206", "n207", "n208", "n209", "n210",
+"n211", "n212", "n213", "n214", "n215", "n216", "n217", "n218", "n219", "n220",
+"n221", "n222", "n223", "n224", "n225", "n226", "n227", "n228", "n229", "n230",
+"n231", "n232", "n233", "n234", "n235", "n236", "n237", "n238", "n239", "a240",
+"a241", "a242", "a243", "a244", "a245", "a246", "a247", "a248", "a249", "n250",
+"n251", "n252", "n253", "n254", "n255", "n256", "n257", "n258", "n259", "n260",
+"n261", "n262", "n263", "n264", "n265", "n266", "n267", "n268", "n269", "n270",
+"n271", "n272", "n273", "n274", "n275", "n276", "n277", "n278", "n279", "n280",
+"n281", "n282", "n283", "n284", "n285", "n286", "n287", "n288", "n289", "n290",
+"n291", "n292", "n293", "n294", "n295", "n296", "n297", "n298", "n299"
+; x=23}
+else a = 1 end
+
+
+end
+
+assert(b.x == 23)
+print('+')
+
+stat(b)
+
+repeat
+a = {
+n1 = 1.5, n2 = 2.5, n3 = 3.5, n4 = 4.5, n5 = 5.5, n6 = 6.5, n7 = 7.5,
+n8 = 8.5, n9 = 9.5, n10 = 10.5, n11 = 11.5, n12 = 12.5,
+j301 = 301.5, j302 = 302.5, j303 = 303.5, j304 = 304.5, j305 = 305.5,
+j306 = 306.5, j307 = 307.5, j308 = 308.5, j309 = 309.5, a310 = 310.5,
+n311 = 311.5, n312 = 312.5, n313 = 313.5, n314 = 314.5, n315 = 315.5,
+n316 = 316.5, n317 = 317.5, n318 = 318.5, n319 = 319.5, n320 = 320.5,
+n321 = 321.5, n322 = 322.5, n323 = 323.5, n324 = 324.5, n325 = 325.5,
+n326 = 326.5, n327 = 327.5, n328 = 328.5, a329 = 329.5, n330 = 330.5,
+n331 = 331.5, n332 = 332.5, n333 = 333.5, n334 = 334.5, n335 = 335.5,
+n336 = 336.5, n337 = 337.5, n338 = 338.5, n339 = 339.5, n340 = 340.5,
+n341 = 341.5, z342 = 342.5, n343 = 343.5, n344 = 344.5, n345 = 345.5,
+n346 = 346.5, n347 = 347.5, n348 = 348.5, n349 = 349.5, n350 = 350.5,
+n351 = 351.5, n352 = 352.5, r353 = 353.5, n354 = 354.5, n355 = 355.5,
+n356 = 356.5, n357 = 357.5, n358 = 358.5, n359 = 359.5, n360 = 360.5,
+n361 = 361.5, n362 = 362.5, n363 = 363.5, n364 = 364.5, n365 = 365.5,
+n366 = 366.5, z367 = 367.5, n368 = 368.5, n369 = 369.5, n370 = 370.5,
+n371 = 371.5, n372 = 372.5, n373 = 373.5, n374 = 374.5, n375 = 375.5,
+a376 = 376.5, n377 = 377.5, n378 = 378.5, n379 = 379.5, n380 = 380.5,
+n381 = 381.5, n382 = 382.5, n383 = 383.5, n384 = 384.5, n385 = 385.5,
+n386 = 386.5, n387 = 387.5, n388 = 388.5, n389 = 389.5, n390 = 390.5,
+n391 = 391.5, n392 = 392.5, n393 = 393.5, n394 = 394.5, n395 = 395.5,
+n396 = 396.5, n397 = 397.5, n398 = 398.5, n399 = 399.5, n400 = 400.5,
+n13 = 13.5, n14 = 14.5, n15 = 15.5, n16 = 16.5, n17 = 17.5,
+n18 = 18.5, n19 = 19.5, n20 = 20.5, n21 = 21.5, n22 = 22.5,
+n23 = 23.5, a24 = 24.5, n25 = 25.5, n26 = 26.5, n27 = 27.5,
+n28 = 28.5, n29 = 29.5, j30 = 30.5, n31 = 31.5, n32 = 32.5,
+n33 = 33.5, n34 = 34.5, n35 = 35.5, n36 = 36.5, n37 = 37.5,
+n38 = 38.5, n39 = 39.5, n40 = 40.5, n41 = 41.5, n42 = 42.5,
+n43 = 43.5, n44 = 44.5, n45 = 45.5, n46 = 46.5, n47 = 47.5,
+n48 = 48.5, n49 = 49.5, n50 = 50.5, n51 = 51.5, n52 = 52.5,
+n53 = 53.5, n54 = 54.5, n55 = 55.5, n56 = 56.5, n57 = 57.5,
+n58 = 58.5, n59 = 59.5, n60 = 60.5, n61 = 61.5, n62 = 62.5,
+n63 = 63.5, n64 = 64.5, n65 = 65.5, a66 = 66.5, z67 = 67.5,
+n68 = 68.5, n69 = 69.5, n70 = 70.5, n71 = 71.5, n72 = 72.5,
+n73 = 73.5, n74 = 74.5, n75 = 75.5, n76 = 76.5, n77 = 77.5,
+n78 = 78.5, n79 = 79.5, n80 = 80.5, n81 = 81.5, n82 = 82.5,
+n83 = 83.5, n84 = 84.5, n85 = 85.5, n86 = 86.5, n87 = 87.5,
+n88 = 88.5, n89 = 89.5, n90 = 90.5, n91 = 91.5, n92 = 92.5,
+n93 = 93.5, n94 = 94.5, n95 = 95.5, n96 = 96.5, n97 = 97.5,
+n98 = 98.5, n99 = 99.5, n100 = 100.5, n201 = 201.5, n202 = 202.5,
+n203 = 203.5, n204 = 204.5, n205 = 205.5, n206 = 206.5, n207 = 207.5,
+n208 = 208.5, n209 = 209.5, n210 = 210.5, n211 = 211.5, n212 = 212.5,
+n213 = 213.5, n214 = 214.5, n215 = 215.5, n216 = 216.5, n217 = 217.5,
+n218 = 218.5, n219 = 219.5, n220 = 220.5, n221 = 221.5, n222 = 222.5,
+n223 = 223.5, n224 = 224.5, n225 = 225.5, n226 = 226.5, n227 = 227.5,
+n228 = 228.5, n229 = 229.5, n230 = 230.5, n231 = 231.5, n232 = 232.5,
+n233 = 233.5, n234 = 234.5, n235 = 235.5, n236 = 236.5, n237 = 237.5,
+n238 = 238.5, n239 = 239.5, a240 = 240.5, a241 = 241.5, a242 = 242.5,
+a243 = 243.5, a244 = 244.5, a245 = 245.5, a246 = 246.5, a247 = 247.5,
+a248 = 248.5, a249 = 249.5, n250 = 250.5, n251 = 251.5, n252 = 252.5,
+n253 = 253.5, n254 = 254.5, n255 = 255.5, n256 = 256.5, n257 = 257.5,
+n258 = 258.5, n259 = 259.5, n260 = 260.5, n261 = 261.5, n262 = 262.5,
+n263 = 263.5, n264 = 264.5, n265 = 265.5, n266 = 266.5, n267 = 267.5,
+n268 = 268.5, n269 = 269.5, n270 = 270.5, n271 = 271.5, n272 = 272.5,
+n273 = 273.5, n274 = 274.5, n275 = 275.5, n276 = 276.5, n277 = 277.5,
+n278 = 278.5, n279 = 279.5, n280 = 280.5, n281 = 281.5, n282 = 282.5,
+n283 = 283.5, n284 = 284.5, n285 = 285.5, n286 = 286.5, n287 = 287.5,
+n288 = 288.5, n289 = 289.5, n290 = 290.5, n291 = 291.5, n292 = 292.5,
+n293 = 293.5, n294 = 294.5, n295 = 295.5, n296 = 296.5, n297 = 297.5,
+n298 = 298.5, n299 = 299.5, j300 = 300} or 1
+until 1
+
+assert(a.n299 == 299.5)
+xxx = 1
+assert(xxx == 1)
+
+stat(a)
+
+function a:findfield (f)
+ local i,v = next(self, nil)
+ while i ~= f do
+ if not i then return end
+ i,v = next(self, i)
+ end
+ return v
+end
+
+local ii = 0
+i = 1
+while b[i] do
+ local r = a:findfield(b[i]);
+ assert(a[b[i]] == r)
+ ii = math.max(ii,i)
+ i = i+1
+end
+
+assert(ii == 299)
+
+function xxxx (x) coroutine.yield('b'); return ii+x end
+
+assert(xxxx(10) == 309)
+
+a = nil
+b = nil
+a1 = nil
+
+print("tables with table indices:")
+i = 1; a={}
+while i <= 1023 do a[{}] = i; i=i+1 end
+stat(a)
+a = nil
+
+print("tables with function indices:")
+a={}
+for i=1,511 do local x; a[function () return x end] = i end
+stat(a)
+a = nil
+
+print'OK'
+
+return 'a'
diff --git a/test/PUC-Lua-5.1-tests/calls.lua b/test/PUC-Lua-5.1-tests/calls.lua
new file mode 100644
index 0000000..788f9a1
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/calls.lua
@@ -0,0 +1,294 @@
+print("testing functions and calls")
+
+-- get the opportunity to test 'type' too ;)
+
+assert(type(1<2) == 'boolean')
+assert(type(true) == 'boolean' and type(false) == 'boolean')
+assert(type(nil) == 'nil' and type(-3) == 'number' and type'x' == 'string' and
+ type{} == 'table' and type(type) == 'function')
+
+assert(type(assert) == type(print))
+f = nil
+function f (x) return a:x (x) end
+assert(type(f) == 'function')
+
+
+-- testing local-function recursion
+fact = false
+do
+ local res = 1
+ local function fact (n)
+ if n==0 then return res
+ else return n*fact(n-1)
+ end
+ end
+ assert(fact(5) == 120)
+end
+assert(fact == false)
+
+-- testing declarations
+a = {i = 10}
+self = 20
+function a:x (x) return x+self.i end
+function a.y (x) return x+self end
+
+assert(a:x(1)+10 == a.y(1))
+
+a.t = {i=-100}
+a["t"].x = function (self, a,b) return self.i+a+b end
+
+assert(a.t:x(2,3) == -95)
+
+do
+ local a = {x=0}
+ function a:add (x) self.x, a.y = self.x+x, 20; return self end
+ assert(a:add(10):add(20):add(30).x == 60 and a.y == 20)
+end
+
+local a = {b={c={}}}
+
+function a.b.c.f1 (x) return x+1 end
+function a.b.c:f2 (x,y) self[x] = y end
+assert(a.b.c.f1(4) == 5)
+a.b.c:f2('k', 12); assert(a.b.c.k == 12)
+
+print('+')
+
+t = nil -- 'declare' t
+function f(a,b,c) local d = 'a'; t={a,b,c,d} end
+
+f( -- this line change must be valid
+ 1,2)
+assert(t[1] == 1 and t[2] == 2 and t[3] == nil and t[4] == 'a')
+f(1,2, -- this one too
+ 3,4)
+assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == 'a')
+
+function fat(x)
+ if x <= 1 then return 1
+ else return x*loadstring("return fat(" .. x-1 .. ")")()
+ end
+end
+
+assert(loadstring "loadstring 'assert(fat(6)==720)' () ")()
+a = loadstring('return fat(5), 3')
+a,b = a()
+assert(a == 120 and b == 3)
+print('+')
+
+function err_on_n (n)
+ if n==0 then error(); exit(1);
+ else err_on_n (n-1); exit(1);
+ end
+end
+
+do
+ function dummy (n)
+ if n > 0 then
+ assert(not pcall(err_on_n, n))
+ dummy(n-1)
+ end
+ end
+end
+
+dummy(10)
+
+function deep (n)
+ if n>0 then deep(n-1) end
+end
+deep(10)
+deep(200)
+
+-- testing tail call
+function deep (n) if n>0 then return deep(n-1) else return 101 end end
+assert(deep(30000) == 101)
+a = {}
+function a:deep (n) if n>0 then return self:deep(n-1) else return 101 end end
+assert(a:deep(30000) == 101)
+
+print('+')
+
+
+a = nil
+(function (x) a=x end)(23)
+assert(a == 23 and (function (x) return x*2 end)(20) == 40)
+
+
+local x,y,z,a
+a = {}; lim = 2000
+for i=1, lim do a[i]=i end
+assert(select(lim, unpack(a)) == lim and select('#', unpack(a)) == lim)
+x = unpack(a)
+assert(x == 1)
+x = {unpack(a)}
+assert(table.getn(x) == lim and x[1] == 1 and x[lim] == lim)
+x = {unpack(a, lim-2)}
+assert(table.getn(x) == 3 and x[1] == lim-2 and x[3] == lim)
+x = {unpack(a, 10, 6)}
+assert(next(x) == nil) -- no elements
+x = {unpack(a, 11, 10)}
+assert(next(x) == nil) -- no elements
+x,y = unpack(a, 10, 10)
+assert(x == 10 and y == nil)
+x,y,z = unpack(a, 10, 11)
+assert(x == 10 and y == 11 and z == nil)
+a,x = unpack{1}
+assert(a==1 and x==nil)
+a,x = unpack({1,2}, 1, 1)
+assert(a==1 and x==nil)
+
+
+-- testing closures
+
+-- fixed-point operator
+Y = function (le)
+ local function a (f)
+ return le(function (x) return f(f)(x) end)
+ end
+ return a(a)
+ end
+
+
+-- non-recursive factorial
+
+F = function (f)
+ return function (n)
+ if n == 0 then return 1
+ else return n*f(n-1) end
+ end
+ end
+
+fat = Y(F)
+
+assert(fat(0) == 1 and fat(4) == 24 and Y(F)(5)==5*Y(F)(4))
+
+local function g (z)
+ local function f (a,b,c,d)
+ return function (x,y) return a+b+c+d+a+x+y+z end
+ end
+ return f(z,z+1,z+2,z+3)
+end
+
+f = g(10)
+assert(f(9, 16) == 10+11+12+13+10+9+16+10)
+
+Y, F, f = nil
+print('+')
+
+-- testing multiple returns
+
+function unlpack (t, i)
+ i = i or 1
+ if (i <= table.getn(t)) then
+ return t[i], unlpack(t, i+1)
+ end
+end
+
+function equaltab (t1, t2)
+ assert(table.getn(t1) == table.getn(t2))
+ for i,v1 in ipairs(t1) do
+ assert(v1 == t2[i])
+ end
+end
+
+local function pack (...)
+ local x = {...}
+ x.n = select('#', ...)
+ return x
+end
+
+function f() return 1,2,30,4 end
+function ret2 (a,b) return a,b end
+
+local a,b,c,d = unlpack{1,2,3}
+assert(a==1 and b==2 and c==3 and d==nil)
+a = {1,2,3,4,false,10,'alo',false,assert}
+equaltab(pack(unlpack(a)), a)
+equaltab(pack(unlpack(a), -1), {1,-1})
+a,b,c,d = ret2(f()), ret2(f())
+assert(a==1 and b==1 and c==2 and d==nil)
+a,b,c,d = unlpack(pack(ret2(f()), ret2(f())))
+assert(a==1 and b==1 and c==2 and d==nil)
+a,b,c,d = unlpack(pack(ret2(f()), (ret2(f()))))
+assert(a==1 and b==1 and c==nil and d==nil)
+
+a = ret2{ unlpack{1,2,3}, unlpack{3,2,1}, unlpack{"a", "b"}}
+assert(a[1] == 1 and a[2] == 3 and a[3] == "a" and a[4] == "b")
+
+
+-- testing calls with 'incorrect' arguments
+rawget({}, "x", 1)
+rawset({}, "x", 1, 2)
+assert(math.sin(1,2) == math.sin(1))
+table.sort({10,9,8,4,19,23,0,0}, function (a,b) return a<b end, "extra arg")
+
+
+-- test for generic load
+x = "-- a comment\0\0\0\n x = 10 + \n23; \
+ local a = function () x = 'hi' end; \
+ return '\0'"
+local i = 0
+function read1 (x)
+ return function ()
+ collectgarbage()
+ i=i+1
+ return string.sub(x, i, i)
+ end
+end
+
+a = assert(load(read1(x), "modname"))
+assert(a() == "\0" and _G.x == 33)
+assert(debug.getinfo(a).source == "modname")
+
+x = string.dump(loadstring("x = 1; return x"))
+i = 0
+a = assert(load(read1(x)))
+assert(a() == 1 and _G.x == 1)
+
+i = 0
+local a, b = load(read1("*a = 123"))
+assert(not a and type(b) == "string" and i == 2)
+
+a, b = load(function () error("hhi") end)
+assert(not a and string.find(b, "hhi"))
+
+-- test generic load with nested functions
+x = [[
+ return function (x)
+ return function (y)
+ return function (z)
+ return x+y+z
+ end
+ end
+ end
+]]
+
+a = assert(load(read1(x)))
+assert(a()(2)(3)(10) == 15)
+
+
+-- test for dump/undump with upvalues
+local a, b = 20, 30
+x = loadstring(string.dump(function (x)
+ if x == "set" then a = 10+b; b = b+1 else
+ return a
+ end
+end))
+assert(x() == nil)
+assert(debug.setupvalue(x, 1, "hi") == "a")
+assert(x() == "hi")
+assert(debug.setupvalue(x, 2, 13) == "b")
+assert(not debug.setupvalue(x, 3, 10)) -- only 2 upvalues
+x("set")
+assert(x() == 23)
+x("set")
+assert(x() == 24)
+
+
+-- test for bug in parameter adjustment
+assert((function () return nil end)(4) == nil)
+assert((function () local a; return a end)(4) == nil)
+assert((function (a) return a end)() == nil)
+
+print('OK')
+return deep
diff --git a/test/PUC-Lua-5.1-tests/checktable.lua b/test/PUC-Lua-5.1-tests/checktable.lua
new file mode 100644
index 0000000..f0938be
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/checktable.lua
@@ -0,0 +1,77 @@
+
+assert(rawget(_G, "stat") == nil) -- module not loaded before
+
+if T == nil then
+ stat = function () print"`querytab' nao ativo" end
+ return
+end
+
+
+function checktable (t)
+ local asize, hsize, ff = T.querytab(t)
+ local l = {}
+ for i=0,hsize-1 do
+ local key,val,next = T.querytab(t, i + asize)
+ if key == nil then
+ assert(l[i] == nil and val==nil and next==nil)
+ elseif key == "<undef>" then
+ assert(val==nil)
+ else
+ assert(t[key] == val)
+ local mp = T.hash(key, t)
+ if l[i] then
+ assert(l[i] == mp)
+ elseif mp ~= i then
+ l[i] = mp
+ else -- list head
+ l[mp] = {mp} -- first element
+ while next do
+ assert(ff <= next and next < hsize)
+ if l[next] then assert(l[next] == mp) else l[next] = mp end
+ table.insert(l[mp], next)
+ key,val,next = T.querytab(t, next)
+ assert(key)
+ end
+ end
+ end
+ end
+ l.asize = asize; l.hsize = hsize; l.ff = ff
+ return l
+end
+
+function mostra (t)
+ local asize, hsize, ff = T.querytab(t)
+ print(asize, hsize, ff)
+ print'------'
+ for i=0,asize-1 do
+ local _, v = T.querytab(t, i)
+ print(string.format("[%d] -", i), v)
+ end
+ print'------'
+ for i=0,hsize-1 do
+ print(i, T.querytab(t, i+asize))
+ end
+ print'-------------'
+end
+
+function stat (t)
+ t = checktable(t)
+ local nelem, nlist = 0, 0
+ local maxlist = {}
+ for i=0,t.hsize-1 do
+ if type(t[i]) == 'table' then
+ local n = table.getn(t[i])
+ nlist = nlist+1
+ nelem = nelem + n
+ if not maxlist[n] then maxlist[n] = 0 end
+ maxlist[n] = maxlist[n]+1
+ end
+ end
+ print(string.format("hsize=%d elements=%d load=%.2f med.len=%.2f (asize=%d)",
+ t.hsize, nelem, nelem/t.hsize, nelem/nlist, t.asize))
+ for i=1,table.getn(maxlist) do
+ local n = maxlist[i] or 0
+ print(string.format("%5d %10d %.2f%%", i, n, n*100/nlist))
+ end
+end
+
diff --git a/test/PUC-Lua-5.1-tests/closure.lua b/test/PUC-Lua-5.1-tests/closure.lua
new file mode 100644
index 0000000..27ca0ad
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/closure.lua
@@ -0,0 +1,422 @@
+print "testing closures and coroutines"
+
+local A,B = 0,{g=10}
+function f(x)
+ local a = {}
+ for i=1,1000 do
+ local y = 0
+ do
+ a[i] = function () B.g = B.g+1; y = y+x; return y+A end
+ end
+ end
+ local dummy = function () return a[A] end
+ collectgarbage()
+ A = 1; assert(dummy() == a[1]); A = 0;
+ assert(a[1]() == x)
+ assert(a[3]() == x)
+ collectgarbage()
+ assert(B.g == 12)
+ return a
+end
+
+a = f(10)
+-- force a GC in this level
+local x = {[1] = {}} -- to detect a GC
+setmetatable(x, {__mode = 'kv'})
+while x[1] do -- repeat until GC
+ local a = A..A..A..A -- create garbage
+ A = A+1
+end
+assert(a[1]() == 20+A)
+assert(a[1]() == 30+A)
+assert(a[2]() == 10+A)
+collectgarbage()
+assert(a[2]() == 20+A)
+assert(a[2]() == 30+A)
+assert(a[3]() == 20+A)
+assert(a[8]() == 10+A)
+assert(getmetatable(x).__mode == 'kv')
+assert(B.g == 19)
+
+-- testing closures with 'for' control variable
+a = {}
+for i=1,10 do
+ a[i] = {set = function(x) i=x end, get = function () return i end}
+ if i == 3 then break end
+end
+assert(a[4] == nil)
+a[1].set(10)
+assert(a[2].get() == 2)
+a[2].set('a')
+assert(a[3].get() == 3)
+assert(a[2].get() == 'a')
+
+a = {}
+for i, k in pairs{'a', 'b'} do
+ a[i] = {set = function(x, y) i=x; k=y end,
+ get = function () return i, k end}
+ if i == 2 then break end
+end
+a[1].set(10, 20)
+local r,s = a[2].get()
+assert(r == 2 and s == 'b')
+r,s = a[1].get()
+assert(r == 10 and s == 20)
+a[2].set('a', 'b')
+r,s = a[2].get()
+assert(r == "a" and s == "b")
+
+
+-- testing closures with 'for' control variable x break
+for i=1,3 do
+ f = function () return i end
+ break
+end
+assert(f() == 1)
+
+for k, v in pairs{"a", "b"} do
+ f = function () return k, v end
+ break
+end
+assert(({f()})[1] == 1)
+assert(({f()})[2] == "a")
+
+
+-- testing closure x break x return x errors
+
+local b
+function f(x)
+ local first = 1
+ while 1 do
+ if x == 3 and not first then return end
+ local a = 'xuxu'
+ b = function (op, y)
+ if op == 'set' then
+ a = x+y
+ else
+ return a
+ end
+ end
+ if x == 1 then do break end
+ elseif x == 2 then return
+ else if x ~= 3 then error() end
+ end
+ first = nil
+ end
+end
+
+for i=1,3 do
+ f(i)
+ assert(b('get') == 'xuxu')
+ b('set', 10); assert(b('get') == 10+i)
+ b = nil
+end
+
+pcall(f, 4);
+assert(b('get') == 'xuxu')
+b('set', 10); assert(b('get') == 14)
+
+
+local w
+-- testing multi-level closure
+function f(x)
+ return function (y)
+ return function (z) return w+x+y+z end
+ end
+end
+
+y = f(10)
+w = 1.345
+assert(y(20)(30) == 60+w)
+
+-- testing closures x repeat-until
+
+local a = {}
+local i = 1
+repeat
+ local x = i
+ a[i] = function () i = x+1; return x end
+until i > 10 or a[i]() ~= x
+assert(i == 11 and a[1]() == 1 and a[3]() == 3 and i == 4)
+
+print'+'
+
+
+-- test for correctly closing upvalues in tail calls of vararg functions
+local function t ()
+ local function c(a,b) assert(a=="test" and b=="OK") end
+ local function v(f, ...) c("test", f() ~= 1 and "FAILED" or "OK") end
+ local x = 1
+ return v(function() return x end)
+end
+t()
+
+
+-- coroutine tests
+
+local f
+
+assert(coroutine.running() == nil)
+
+
+-- tests for global environment
+
+local function foo (a)
+ setfenv(0, a)
+ coroutine.yield(getfenv())
+ assert(getfenv(0) == a)
+ assert(getfenv(1) == _G)
+ assert(getfenv(loadstring"") == a)
+ return getfenv()
+end
+
+f = coroutine.wrap(foo)
+local a = {}
+assert(f(a) == _G)
+local a,b = pcall(f)
+assert(a and b == _G)
+
+
+-- tests for multiple yield/resume arguments
+
+local function eqtab (t1, t2)
+ assert(table.getn(t1) == table.getn(t2))
+ for i,v in ipairs(t1) do
+ assert(t2[i] == v)
+ end
+end
+
+_G.x = nil -- declare x
+function foo (a, ...)
+ assert(coroutine.running() == f)
+ assert(coroutine.status(f) == "running")
+ local arg = {...}
+ for i=1,table.getn(arg) do
+ _G.x = {coroutine.yield(unpack(arg[i]))}
+ end
+ return unpack(a)
+end
+
+f = coroutine.create(foo)
+assert(type(f) == "thread" and coroutine.status(f) == "suspended")
+assert(string.find(tostring(f), "thread"))
+local s,a,b,c,d
+s,a,b,c,d = coroutine.resume(f, {1,2,3}, {}, {1}, {'a', 'b', 'c'})
+assert(s and a == nil and coroutine.status(f) == "suspended")
+s,a,b,c,d = coroutine.resume(f)
+eqtab(_G.x, {})
+assert(s and a == 1 and b == nil)
+s,a,b,c,d = coroutine.resume(f, 1, 2, 3)
+eqtab(_G.x, {1, 2, 3})
+assert(s and a == 'a' and b == 'b' and c == 'c' and d == nil)
+s,a,b,c,d = coroutine.resume(f, "xuxu")
+eqtab(_G.x, {"xuxu"})
+assert(s and a == 1 and b == 2 and c == 3 and d == nil)
+assert(coroutine.status(f) == "dead")
+s, a = coroutine.resume(f, "xuxu")
+assert(not s and string.find(a, "dead") and coroutine.status(f) == "dead")
+
+
+-- yields in tail calls
+local function foo (i) return coroutine.yield(i) end
+f = coroutine.wrap(function ()
+ for i=1,10 do
+ assert(foo(i) == _G.x)
+ end
+ return 'a'
+end)
+for i=1,10 do _G.x = i; assert(f(i) == i) end
+_G.x = 'xuxu'; assert(f('xuxu') == 'a')
+
+-- recursive
+function pf (n, i)
+ coroutine.yield(n)
+ pf(n*i, i+1)
+end
+
+f = coroutine.wrap(pf)
+local s=1
+for i=1,10 do
+ assert(f(1, 1) == s)
+ s = s*i
+end
+
+-- sieve
+function gen (n)
+ return coroutine.wrap(function ()
+ for i=2,n do coroutine.yield(i) end
+ end)
+end
+
+
+function filter (p, g)
+ return coroutine.wrap(function ()
+ while 1 do
+ local n = g()
+ if n == nil then return end
+ if math.mod(n, p) ~= 0 then coroutine.yield(n) end
+ end
+ end)
+end
+
+local x = gen(100)
+local a = {}
+while 1 do
+ local n = x()
+ if n == nil then break end
+ table.insert(a, n)
+ x = filter(n, x)
+end
+
+assert(table.getn(a) == 25 and a[table.getn(a)] == 97)
+
+
+-- errors in coroutines
+function foo ()
+ assert(debug.getinfo(1).currentline == debug.getinfo(foo).linedefined + 1)
+ assert(debug.getinfo(2).currentline == debug.getinfo(goo).linedefined)
+ coroutine.yield(3)
+ error(foo)
+end
+
+function goo() foo() end
+x = coroutine.wrap(goo)
+assert(x() == 3)
+local a,b = pcall(x)
+assert(not a and b == foo)
+
+x = coroutine.create(goo)
+a,b = coroutine.resume(x)
+assert(a and b == 3)
+a,b = coroutine.resume(x)
+assert(not a and b == foo and coroutine.status(x) == "dead")
+a,b = coroutine.resume(x)
+assert(not a and string.find(b, "dead") and coroutine.status(x) == "dead")
+
+
+-- co-routines x for loop
+function all (a, n, k)
+ if k == 0 then coroutine.yield(a)
+ else
+ for i=1,n do
+ a[k] = i
+ all(a, n, k-1)
+ end
+ end
+end
+
+local a = 0
+for t in coroutine.wrap(function () all({}, 5, 4) end) do
+ a = a+1
+end
+assert(a == 5^4)
+
+
+-- access to locals of collected corroutines
+local C = {}; setmetatable(C, {__mode = "kv"})
+local x = coroutine.wrap (function ()
+ local a = 10
+ local function f () a = a+10; return a end
+ while true do
+ a = a+1
+ coroutine.yield(f)
+ end
+ end)
+
+C[1] = x;
+
+local f = x()
+assert(f() == 21 and x()() == 32 and x() == f)
+x = nil
+collectgarbage()
+assert(C[1] == nil)
+assert(f() == 43 and f() == 53)
+
+
+-- old bug: attempt to resume itself
+
+function co_func (current_co)
+ assert(coroutine.running() == current_co)
+ assert(coroutine.resume(current_co) == false)
+ assert(coroutine.resume(current_co) == false)
+ return 10
+end
+
+local co = coroutine.create(co_func)
+local a,b = coroutine.resume(co, co)
+assert(a == true and b == 10)
+assert(coroutine.resume(co, co) == false)
+assert(coroutine.resume(co, co) == false)
+
+-- access to locals of erroneous coroutines
+local x = coroutine.create (function ()
+ local a = 10
+ _G.f = function () a=a+1; return a end
+ error('x')
+ end)
+
+assert(not coroutine.resume(x))
+-- overwrite previous position of local `a'
+assert(not coroutine.resume(x, 1, 1, 1, 1, 1, 1, 1))
+assert(_G.f() == 11)
+assert(_G.f() == 12)
+
+
+if not T then
+ (Message or print)('\a\n >>> testC not active: skipping yield/hook tests <<<\n\a')
+else
+
+ local turn
+
+ function fact (t, x)
+ assert(turn == t)
+ if x == 0 then return 1
+ else return x*fact(t, x-1)
+ end
+ end
+
+ local A,B,a,b = 0,0,0,0
+
+ local x = coroutine.create(function ()
+ T.setyhook("", 2)
+ A = fact("A", 10)
+ end)
+
+ local y = coroutine.create(function ()
+ T.setyhook("", 3)
+ B = fact("B", 11)
+ end)
+
+ while A==0 or B==0 do
+ if A==0 then turn = "A"; T.resume(x) end
+ if B==0 then turn = "B"; T.resume(y) end
+ end
+
+ assert(B/A == 11)
+end
+
+
+-- leaving a pending coroutine open
+_X = coroutine.wrap(function ()
+ local a = 10
+ local x = function () a = a+1 end
+ coroutine.yield()
+ end)
+
+_X()
+
+
+-- coroutine environments
+co = coroutine.create(function ()
+ coroutine.yield(getfenv(0))
+ return loadstring("return a")()
+ end)
+
+a = {a = 15}
+debug.setfenv(co, a)
+assert(debug.getfenv(co) == a)
+assert(select(2, coroutine.resume(co)) == a)
+assert(select(2, coroutine.resume(co)) == a.a)
+
+
+print'OK'
diff --git a/test/PUC-Lua-5.1-tests/code.lua b/test/PUC-Lua-5.1-tests/code.lua
new file mode 100644
index 0000000..875d488
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/code.lua
@@ -0,0 +1,143 @@
+
+if T==nil then
+ (Message or print)('\a\n >>> testC not active: skipping opcode tests <<<\n\a')
+ return
+end
+print "testing code generation and optimizations"
+
+
+-- this code gave an error for the code checker
+do
+ local function f (a)
+ for k,v,w in a do end
+ end
+end
+
+
+function check (f, ...)
+ local c = T.listcode(f)
+ for i=1, arg.n do
+ -- print(arg[i], c[i])
+ assert(string.find(c[i], '- '..arg[i]..' *%d'))
+ end
+ assert(c[arg.n+2] == nil)
+end
+
+
+function checkequal (a, b)
+ a = T.listcode(a)
+ b = T.listcode(b)
+ for i = 1, table.getn(a) do
+ a[i] = string.gsub(a[i], '%b()', '') -- remove line number
+ b[i] = string.gsub(b[i], '%b()', '') -- remove line number
+ assert(a[i] == b[i])
+ end
+end
+
+
+-- some basic instructions
+check(function ()
+ (function () end){f()}
+end, 'CLOSURE', 'NEWTABLE', 'GETGLOBAL', 'CALL', 'SETLIST', 'CALL', 'RETURN')
+
+
+-- sequence of LOADNILs
+check(function ()
+ local a,b,c
+ local d; local e;
+ a = nil; d=nil
+end, 'RETURN')
+
+
+-- single return
+check (function (a,b,c) return a end, 'RETURN')
+
+
+-- infinite loops
+check(function () while true do local a = -1 end end,
+'LOADK', 'JMP', 'RETURN')
+
+check(function () while 1 do local a = -1 end end,
+'LOADK', 'JMP', 'RETURN')
+
+check(function () repeat local x = 1 until false end,
+'LOADK', 'JMP', 'RETURN')
+
+check(function () repeat local x until nil end,
+'LOADNIL', 'JMP', 'RETURN')
+
+check(function () repeat local x = 1 until true end,
+'LOADK', 'RETURN')
+
+
+-- concat optimization
+check(function (a,b,c,d) return a..b..c..d end,
+ 'MOVE', 'MOVE', 'MOVE', 'MOVE', 'CONCAT', 'RETURN')
+
+-- not
+check(function () return not not nil end, 'LOADBOOL', 'RETURN')
+check(function () return not not false end, 'LOADBOOL', 'RETURN')
+check(function () return not not true end, 'LOADBOOL', 'RETURN')
+check(function () return not not 1 end, 'LOADBOOL', 'RETURN')
+
+-- direct access to locals
+check(function ()
+ local a,b,c,d
+ a = b*2
+ c[4], a[b] = -((a + d/-20.5 - a[b]) ^ a.x), b
+end,
+ 'MUL',
+ 'DIV', 'ADD', 'GETTABLE', 'SUB', 'GETTABLE', 'POW',
+ 'UNM', 'SETTABLE', 'SETTABLE', 'RETURN')
+
+
+-- direct access to constants
+check(function ()
+ local a,b
+ a.x = 0
+ a.x = b
+ a[b] = 'y'
+ a = 1 - a
+ b = 1/a
+ b = 5+4
+ a[true] = false
+end,
+ 'SETTABLE', 'SETTABLE', 'SETTABLE', 'SUB', 'DIV', 'LOADK',
+ 'SETTABLE', 'RETURN')
+
+local function f () return -((2^8 + -(-1)) % 8)/2 * 4 - 3 end
+
+check(f, 'LOADK', 'RETURN')
+assert(f() == -5)
+
+check(function ()
+ local a,b,c
+ b[c], a = c, b
+ b[a], a = c, b
+ a, b = c, a
+ a = a
+end,
+ 'MOVE', 'MOVE', 'SETTABLE',
+ 'MOVE', 'MOVE', 'MOVE', 'SETTABLE',
+ 'MOVE', 'MOVE', 'MOVE',
+ -- no code for a = a
+ 'RETURN')
+
+
+-- x == nil , x ~= nil
+checkequal(function () if (a==nil) then a=1 end; if a~=nil then a=1 end end,
+ function () if (a==9) then a=1 end; if a~=9 then a=1 end end)
+
+check(function () if a==nil then a=1 end end,
+'GETGLOBAL', 'EQ', 'JMP', 'LOADK', 'SETGLOBAL', 'RETURN')
+
+-- de morgan
+checkequal(function () local a; if not (a or b) then b=a end end,
+ function () local a; if (not a and not b) then b=a end end)
+
+checkequal(function (l) local a; return 0 <= a and a <= l end,
+ function (l) local a; return not (not(a >= 0) or not(a <= l)) end)
+
+
+print 'OK'
+
diff --git a/test/PUC-Lua-5.1-tests/constructs.lua b/test/PUC-Lua-5.1-tests/constructs.lua
new file mode 100644
index 0000000..5fb3798
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/constructs.lua
@@ -0,0 +1,240 @@
+print "testing syntax"
+
+-- testing priorities
+
+assert(2^3^2 == 2^(3^2));
+assert(2^3*4 == (2^3)*4);
+assert(2^-2 == 1/4 and -2^- -2 == - - -4);
+assert(not nil and 2 and not(2>3 or 3<2));
+assert(-3-1-5 == 0+0-9);
+assert(-2^2 == -4 and (-2)^2 == 4 and 2*2-3-1 == 0);
+assert(2*1+3/3 == 3 and 1+2 .. 3*1 == "33");
+assert(not(2+1 > 3*1) and "a".."b" > "a");
+
+assert(not ((true or false) and nil))
+assert( true or false and nil)
+
+local a,b = 1,nil;
+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);
+x = (((2<3) or 1) == true and (2<3 and 4) == 4); assert(x);
+
+x,y=1,2;
+assert((x>y) and x or y == 2);
+x,y=2,1;
+assert((x>y) and x or y == 2);
+
+assert(1234567890 == tonumber('1234567890') and 1234567890+1 == 1234567891)
+
+
+-- silly loops
+repeat until 1; repeat until true;
+while false do end; while nil do end;
+
+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
+end
+
+function f (i)
+ if type(i) ~= 'number' then return i,'jojo'; end;
+ if i > 0 then return i, f(i-1); end;
+end
+
+x = {f(3), f(5), f(10);};
+assert(x[1] == 3 and x[2] == 5 and x[3] == 10 and x[4] == 9 and x[12] == 1);
+assert(x[nil] == nil)
+x = {f'alo', f'xixi', nil};
+assert(x[1] == 'alo' and x[2] == 'xixi' and x[3] == nil);
+x = {f'alo'..'xixi'};
+assert(x[1] == 'aloxixi')
+x = {f{}}
+assert(x[2] == 'jojo' and type(x[1]) == 'table')
+
+
+local f = function (i)
+ if i < 10 then return 'a';
+ elseif i < 20 then return 'b';
+ elseif i < 30 then return 'c';
+ end;
+end
+
+assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == nil)
+
+for i=1,1000 do break; end;
+n=100;
+i=3;
+t = {};
+a=nil
+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;
+end
+assert(a == n*(n+1)/2 and i==3);
+assert(t[1] and t[n] and not t[0] and not t[n+1])
+
+function f(b)
+ local x = 1;
+ repeat
+ local a;
+ if b==1 then local b=1; x=10; break
+ elseif b==2 then x=20; break;
+ elseif b==3 then x=30;
+ else local a,b,c,d=math.sin(1); x=x+1;
+ end
+ until x>=12;
+ return x;
+end;
+
+assert(f(1) == 10 and f(2) == 20 and f(3) == 30 and f(4)==12)
+
+
+local f = function (i)
+ if i < 10 then return 'a'
+ elseif i < 20 then return 'b'
+ elseif i < 30 then return 'c'
+ else return 8
+ end
+end
+
+assert(f(3) == 'a' and f(12) == 'b' and f(26) == 'c' and f(100) == 8)
+
+local a, b = nil, 23
+x = {f(100)*2+3 or a, a or b+2}
+assert(x[1] == 19 and x[2] == 25)
+x = {f=2+3 or a, a = b+2}
+assert(x.f == 5 and x.a == 25)
+
+a={y=1}
+x = {a.y}
+assert(x[1] == 1)
+
+function f(i)
+ while 1 do
+ if i>0 then i=i-1;
+ else return; end;
+ end;
+end;
+
+function g(i)
+ while 1 do
+ if i>0 then i=i-1
+ else return end
+ end
+end
+
+f(10); g(10);
+
+do
+ function f () return 1,2,3; end
+ local a, b, c = f();
+ assert(a==1 and b==2 and c==3)
+ a, b, c = (f());
+ assert(a==1 and b==nil and c==nil)
+end
+
+local a,b = 3 and f();
+assert(a==1 and b==nil)
+
+function g() f(); return; end;
+assert(g() == nil)
+function g() return nil or f() end
+a,b = g()
+assert(a==1 and b==nil)
+
+print'+';
+
+
+f = [[
+return function ( a , b , c , d , e )
+ local x = a >= b or c or ( d and e ) or nil
+ return x
+end , { a = 1 , b = 2 >= 1 , } or { 1 };
+]]
+f = string.gsub(f, "%s+", "\n"); -- force a SETLINE between opcodes
+f,a = loadstring(f)();
+assert(a.a == 1 and a.b)
+
+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;
+end
+
+function h (a,b,c,d,e)
+ while (a>=b or c or (d and e) or nil) do return 1; end;
+ return 0;
+end;
+
+assert(f(2,1) == true and g(2,1) == 1 and h(2,1) == 1)
+assert(f(1,2,'a') == 'a' and g(1,2,'a') == 1 and h(1,2,'a') == 1)
+assert(f(1,2,'a')
+~= -- force SETLINE before nil
+nil, "")
+assert(f(1,2,'a') == 'a' and g(1,2,'a') == 1 and h(1,2,'a') == 1)
+assert(f(1,2,nil,1,'x') == 'x' and g(1,2,nil,1,'x') == 1 and
+ h(1,2,nil,1,'x') == 1)
+assert(f(1,2,nil,nil,'x') == nil and g(1,2,nil,nil,'x') == 0 and
+ h(1,2,nil,nil,'x') == 0)
+assert(f(1,2,nil,1,nil) == nil and g(1,2,nil,1,nil) == 0 and
+ h(1,2,nil,1,nil) == 0)
+
+assert(1 and 2<3 == true and 2<3 and 'a'<'b' == true)
+x = 2<3 and not 3; assert(x==false)
+x = 2<1 or (2>1 and 'a'); assert(x=='a')
+
+
+do
+ local a; if nil then a=1; else a=2; end; -- this nil comes as PUSHNIL 2
+ assert(a==2)
+end
+
+function F(a)
+ assert(debug.getinfo(1, "n").name == 'F')
+ return a,2,3
+end
+
+a,b = F(1)~=nil; assert(a == true and b == nil);
+a,b = F(nil)==nil; assert(a == true and b == nil)
+
+----------------------------------------------------------------
+-- creates all combinations of
+-- [not] ([not] arg op [not] (arg op [not] arg ))
+-- and tests each one
+
+function ID(x) return x end
+
+function f(t, i)
+ local b = t.n
+ local res = math.mod(math.floor(i/c), b)+1
+ c = c*b
+ return t[res]
+end
+
+local arg = {" ( 1 < 2 ) ", " ( 1 >= 2 ) ", " F ( ) ", " nil "; n=4}
+
+local op = {" and ", " or ", " == ", " ~= "; n=4}
+
+local neg = {" ", " not "; n=2}
+
+local i = 0
+repeat
+ c = 1
+ local s = f(neg, i)..'ID('..f(neg, i)..f(arg, i)..f(op, i)..
+ f(neg, i)..'ID('..f(arg, i)..f(op, i)..f(neg, i)..f(arg, i)..'))'
+ local s1 = string.gsub(s, 'ID', '')
+ K,X,NX,WX1,WX2 = nil
+ s = string.format([[
+ local a = %s
+ local b = not %s
+ K = b
+ local xxx;
+ if %s then X = a else X = b end
+ if %s then NX = b else NX = a end
+ while %s do WX1 = a; break end
+ while %s do WX2 = a; break end
+ repeat if (%s) then break end; assert(b) until not(%s)
+ ]], s1, s, s1, s, s1, s, s1, s, s)
+ assert(loadstring(s))()
+ assert(X and not NX and not WX1 == K and not WX2 == K)
+ if math.mod(i,4000) == 0 then print('+') end
+ i = i+1
+until i==c
+
+print'OK'
diff --git a/test/PUC-Lua-5.1-tests/db.lua b/test/PUC-Lua-5.1-tests/db.lua
new file mode 100644
index 0000000..9d2c86f
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/db.lua
@@ -0,0 +1,499 @@
+-- testing debug library
+
+local function dostring(s) return assert(loadstring(s))() end
+
+print"testing debug library and debug information"
+
+do
+local a=1
+end
+
+function test (s, l, p)
+ collectgarbage() -- avoid gc during trace
+ local function f (event, line)
+ assert(event == 'line')
+ local l = table.remove(l, 1)
+ if p then print(l, line) end
+ assert(l == line, "wrong trace!!")
+ end
+ debug.sethook(f,"l"); loadstring(s)(); debug.sethook()
+ assert(table.getn(l) == 0)
+end
+
+
+do
+ local a = debug.getinfo(print)
+ assert(a.what == "C" and a.short_src == "[C]")
+ local b = debug.getinfo(test, "SfL")
+ assert(b.name == nil and b.what == "Lua" and b.linedefined == 11 and
+ b.lastlinedefined == b.linedefined + 10 and
+ b.func == test and not string.find(b.short_src, "%["))
+ assert(b.activelines[b.linedefined + 1] and
+ b.activelines[b.lastlinedefined])
+ assert(not b.activelines[b.linedefined] and
+ not b.activelines[b.lastlinedefined + 1])
+end
+
+
+-- test file and string names truncation
+a = "function f () end"
+local function dostring (s, x) return loadstring(s, x)() end
+dostring(a)
+assert(debug.getinfo(f).short_src == string.format('[string "%s"]', a))
+dostring(a..string.format("; %s\n=1", string.rep('p', 400)))
+assert(string.find(debug.getinfo(f).short_src, '^%[string [^\n]*%.%.%."%]$'))
+dostring("\n"..a)
+assert(debug.getinfo(f).short_src == '[string "..."]')
+dostring(a, "")
+assert(debug.getinfo(f).short_src == '[string ""]')
+dostring(a, "@xuxu")
+assert(debug.getinfo(f).short_src == "xuxu")
+dostring(a, "@"..string.rep('p', 1000)..'t')
+assert(string.find(debug.getinfo(f).short_src, "^%.%.%.p*t$"))
+dostring(a, "=xuxu")
+assert(debug.getinfo(f).short_src == "xuxu")
+dostring(a, string.format("=%s", string.rep('x', 500)))
+assert(string.find(debug.getinfo(f).short_src, "^x*"))
+dostring(a, "=")
+assert(debug.getinfo(f).short_src == "")
+a = nil; f = nil;
+
+
+repeat
+ local g = {x = function ()
+ local a = debug.getinfo(2)
+ assert(a.name == 'f' and a.namewhat == 'local')
+ a = debug.getinfo(1)
+ assert(a.name == 'x' and a.namewhat == 'field')
+ return 'xixi'
+ end}
+ local f = function () return 1+1 and (not 1 or g.x()) end
+ assert(f() == 'xixi')
+ g = debug.getinfo(f)
+ assert(g.what == "Lua" and g.func == f and g.namewhat == "" and not g.name)
+
+ function f (x, name) -- local!
+ name = name or 'f'
+ local a = debug.getinfo(1)
+ assert(a.name == name and a.namewhat == 'local')
+ return x
+ end
+
+ -- breaks in different conditions
+ if 3>4 then break end; f()
+ if 3<4 then a=1 else break end; f()
+ while 1 do local x=10; break end; f()
+ local b = 1
+ if 3>4 then return math.sin(1) end; f()
+ a = 3<4; f()
+ a = 3<4 or 1; f()
+ repeat local x=20; if 4>3 then f() else break end; f() until 1
+ g = {}
+ f(g).x = f(2) and f(10)+f(9)
+ assert(g.x == f(19))
+ function g(x) if not x then return 3 end return (x('a', 'x')) end
+ assert(g(f) == 'a')
+until 1
+
+test([[if
+math.sin(1)
+then
+ a=1
+else
+ a=2
+end
+]], {2,4,7})
+
+test([[--
+if nil then
+ a=1
+else
+ a=2
+end
+]], {2,5,6})
+
+test([[a=1
+repeat
+ a=a+1
+until a==3
+]], {1,3,4,3,4})
+
+test([[ do
+ return
+end
+]], {2})
+
+test([[local a
+a=1
+while a<=3 do
+ a=a+1
+end
+]], {2,3,4,3,4,3,4,3,5})
+
+test([[while math.sin(1) do
+ if math.sin(1)
+ then
+ break
+ end
+end
+a=1]], {1,2,4,7})
+
+test([[for i=1,3 do
+ a=i
+end
+]], {1,2,1,2,1,2,1,3})
+
+test([[for i,v in pairs{'a','b'} do
+ a=i..v
+end
+]], {1,2,1,2,1,3})
+
+test([[for i=1,4 do a=1 end]], {1,1,1,1,1})
+
+
+
+print'+'
+
+a = {}; L = nil
+local glob = 1
+local oldglob = glob
+debug.sethook(function (e,l)
+ collectgarbage() -- force GC during a hook
+ local f, m, c = debug.gethook()
+ assert(m == 'crl' and c == 0)
+ if e == "line" then
+ if glob ~= oldglob then
+ L = l-1 -- get the first line where "glob" has changed
+ oldglob = glob
+ end
+ elseif e == "call" then
+ local f = debug.getinfo(2, "f").func
+ a[f] = 1
+ else assert(e == "return")
+ end
+end, "crl")
+
+function f(a,b)
+ collectgarbage()
+ local _, x = debug.getlocal(1, 1)
+ local _, y = debug.getlocal(1, 2)
+ assert(x == a and y == b)
+ assert(debug.setlocal(2, 3, "pera") == "AA".."AA")
+ assert(debug.setlocal(2, 4, "maçã") == "B")
+ x = debug.getinfo(2)
+ assert(x.func == g and x.what == "Lua" and x.name == 'g' and
+ x.nups == 0 and string.find(x.source, "^@.*db%.lua"))
+ glob = glob+1
+ assert(debug.getinfo(1, "l").currentline == L+1)
+ assert(debug.getinfo(1, "l").currentline == L+2)
+end
+
+function foo()
+ glob = glob+1
+ assert(debug.getinfo(1, "l").currentline == L+1)
+end; foo() -- set L
+-- check line counting inside strings and empty lines
+
+_ = 'alo\
+alo' .. [[
+
+]]
+--[[
+]]
+assert(debug.getinfo(1, "l").currentline == L+11) -- check count of lines
+
+
+function g(...)
+ do local a,b,c; a=math.sin(40); end
+ local feijao
+ local AAAA,B = "xuxu", "mamão"
+ f(AAAA,B)
+ assert(AAAA == "pera" and B == "maçã")
+ do
+ local B = 13
+ local x,y = debug.getlocal(1,5)
+ assert(x == 'B' and y == 13)
+ end
+end
+
+g()
+
+
+assert(a[f] and a[g] and a[assert] and a[debug.getlocal] and not a[print])
+
+
+-- tests for manipulating non-registered locals (C and Lua temporaries)
+
+local n, v = debug.getlocal(0, 1)
+assert(v == 0 and n == "(*temporary)")
+local n, v = debug.getlocal(0, 2)
+assert(v == 2 and n == "(*temporary)")
+assert(not debug.getlocal(0, 3))
+assert(not debug.getlocal(0, 0))
+
+function f()
+ assert(select(2, debug.getlocal(2,3)) == 1)
+ assert(not debug.getlocal(2,4))
+ debug.setlocal(2, 3, 10)
+ return 20
+end
+
+function g(a,b) return (a+1) + f() end
+
+assert(g(0,0) == 30)
+
+
+debug.sethook(nil);
+assert(debug.gethook() == nil)
+
+
+-- testing access to function arguments
+
+X = nil
+a = {}
+function a:f (a, b, ...) local c = 13 end
+debug.sethook(function (e)
+ assert(e == "call")
+ dostring("XX = 12") -- test dostring inside hooks
+ -- testing errors inside hooks
+ assert(not pcall(loadstring("a='joao'+1")))
+ debug.sethook(function (e, l)
+ assert(debug.getinfo(2, "l").currentline == l)
+ local f,m,c = debug.gethook()
+ assert(e == "line")
+ assert(m == 'l' and c == 0)
+ debug.sethook(nil) -- hook is called only once
+ assert(not X) -- check that
+ X = {}; local i = 1
+ local x,y
+ while 1 do
+ x,y = debug.getlocal(2, i)
+ if x==nil then break end
+ X[x] = y
+ i = i+1
+ end
+ end, "l")
+end, "c")
+
+a:f(1,2,3,4,5)
+assert(X.self == a and X.a == 1 and X.b == 2 and X.arg.n == 3 and X.c == nil)
+assert(XX == 12)
+assert(debug.gethook() == nil)
+
+
+-- testing upvalue access
+local function getupvalues (f)
+ local t = {}
+ local i = 1
+ while true do
+ local name, value = debug.getupvalue(f, i)
+ if not name then break end
+ assert(not t[name])
+ t[name] = value
+ i = i + 1
+ end
+ return t
+end
+
+local a,b,c = 1,2,3
+local function foo1 (a) b = a; return c end
+local function foo2 (x) a = x; return c+b end
+assert(debug.getupvalue(foo1, 3) == nil)
+assert(debug.getupvalue(foo1, 0) == nil)
+assert(debug.setupvalue(foo1, 3, "xuxu") == nil)
+local t = getupvalues(foo1)
+assert(t.a == nil and t.b == 2 and t.c == 3)
+t = getupvalues(foo2)
+assert(t.a == 1 and t.b == 2 and t.c == 3)
+assert(debug.setupvalue(foo1, 1, "xuxu") == "b")
+assert(({debug.getupvalue(foo2, 3)})[2] == "xuxu")
+-- cannot manipulate C upvalues from Lua
+assert(debug.getupvalue(io.read, 1) == nil)
+assert(debug.setupvalue(io.read, 1, 10) == nil)
+
+
+-- testing count hooks
+local a=0
+debug.sethook(function (e) a=a+1 end, "", 1)
+a=0; for i=1,1000 do end; assert(1000 < a and a < 1012)
+debug.sethook(function (e) a=a+1 end, "", 4)
+a=0; for i=1,1000 do end; assert(250 < a and a < 255)
+local f,m,c = debug.gethook()
+assert(m == "" and c == 4)
+debug.sethook(function (e) a=a+1 end, "", 4000)
+a=0; for i=1,1000 do end; assert(a == 0)
+debug.sethook(print, "", 2^24 - 1) -- count upperbound
+local f,m,c = debug.gethook()
+assert(({debug.gethook()})[3] == 2^24 - 1)
+debug.sethook()
+
+
+-- tests for tail calls
+local function f (x)
+ if x then
+ assert(debug.getinfo(1, "S").what == "Lua")
+ local tail = debug.getinfo(2)
+ assert(not pcall(getfenv, 3))
+ assert(tail.what == "tail" and tail.short_src == "(tail call)" and
+ tail.linedefined == -1 and tail.func == nil)
+ assert(debug.getinfo(3, "f").func == g1)
+ assert(getfenv(3))
+ assert(debug.getinfo(4, "S").what == "tail")
+ assert(not pcall(getfenv, 5))
+ assert(debug.getinfo(5, "S").what == "main")
+ assert(getfenv(5))
+ print"+"
+ end
+end
+
+function g(x) return f(x) end
+
+function g1(x) g(x) end
+
+local function h (x) local f=g1; return f(x) end
+
+h(true)
+
+local b = {}
+debug.sethook(function (e) table.insert(b, e) end, "cr")
+h(false)
+debug.sethook()
+local res = {"return", -- first return (from sethook)
+ "call", "call", "call", "call",
+ "return", "tail return", "return", "tail return",
+ "call", -- last call (to sethook)
+}
+for _, k in ipairs(res) do assert(k == table.remove(b, 1)) end
+
+
+lim = 30000
+local function foo (x)
+ if x==0 then
+ assert(debug.getinfo(lim+2).what == "main")
+ for i=2,lim do assert(debug.getinfo(i, "S").what == "tail") end
+ else return foo(x-1)
+ end
+end
+
+foo(lim)
+
+
+print"+"
+
+
+-- testing traceback
+
+assert(debug.traceback(print) == print)
+assert(debug.traceback(print, 4) == print)
+assert(string.find(debug.traceback("hi", 4), "^hi\n"))
+assert(string.find(debug.traceback("hi"), "^hi\n"))
+assert(not string.find(debug.traceback("hi"), "'traceback'"))
+assert(string.find(debug.traceback("hi", 0), "'traceback'"))
+assert(string.find(debug.traceback(), "^stack traceback:\n"))
+
+-- testing debugging of coroutines
+
+local function checktraceback (co, p)
+ local tb = debug.traceback(co)
+ local i = 0
+ for l in string.gmatch(tb, "[^\n]+\n?") do
+ assert(i == 0 or string.find(l, p[i]))
+ i = i+1
+ end
+ assert(p[i] == nil)
+end
+
+
+local function f (n)
+ if n > 0 then return f(n-1)
+ else coroutine.yield() end
+end
+
+local co = coroutine.create(f)
+coroutine.resume(co, 3)
+checktraceback(co, {"yield", "db.lua", "tail", "tail", "tail"})
+
+
+co = coroutine.create(function (x)
+ local a = 1
+ coroutine.yield(debug.getinfo(1, "l"))
+ coroutine.yield(debug.getinfo(1, "l").currentline)
+ return a
+ end)
+
+local tr = {}
+local foo = function (e, l) table.insert(tr, l) end
+debug.sethook(co, foo, "l")
+
+local _, l = coroutine.resume(co, 10)
+local x = debug.getinfo(co, 1, "lfLS")
+assert(x.currentline == l.currentline and x.activelines[x.currentline])
+assert(type(x.func) == "function")
+for i=x.linedefined + 1, x.lastlinedefined do
+ assert(x.activelines[i])
+ x.activelines[i] = nil
+end
+assert(next(x.activelines) == nil) -- no 'extra' elements
+assert(debug.getinfo(co, 2) == nil)
+local a,b = debug.getlocal(co, 1, 1)
+assert(a == "x" and b == 10)
+a,b = debug.getlocal(co, 1, 2)
+assert(a == "a" and b == 1)
+debug.setlocal(co, 1, 2, "hi")
+assert(debug.gethook(co) == foo)
+assert(table.getn(tr) == 2 and
+ tr[1] == l.currentline-1 and tr[2] == l.currentline)
+
+a,b,c = pcall(coroutine.resume, co)
+assert(a and b and c == l.currentline+1)
+checktraceback(co, {"yield", "in function <"})
+
+a,b = coroutine.resume(co)
+assert(a and b == "hi")
+assert(table.getn(tr) == 4 and tr[4] == l.currentline+2)
+assert(debug.gethook(co) == foo)
+assert(debug.gethook() == nil)
+checktraceback(co, {})
+
+
+-- check traceback of suspended (or dead with error) coroutines
+
+function f(i) if i==0 then error(i) else coroutine.yield(); f(i-1) end end
+
+co = coroutine.create(function (x) f(x) end)
+a, b = coroutine.resume(co, 3)
+t = {"'yield'", "'f'", "in function <"}
+while coroutine.status(co) == "suspended" do
+ checktraceback(co, t)
+ a, b = coroutine.resume(co)
+ table.insert(t, 2, "'f'") -- one more recursive call to 'f'
+end
+t[1] = "'error'"
+checktraceback(co, t)
+
+
+-- test acessing line numbers of a coroutine from a resume inside
+-- a C function (this is a known bug in Lua 5.0)
+
+local function g(x)
+ coroutine.yield(x)
+end
+
+local function f (i)
+ debug.sethook(function () end, "l")
+ for j=1,1000 do
+ g(i+j)
+ end
+end
+
+local co = coroutine.wrap(f)
+co(10)
+pcall(co)
+pcall(co)
+
+
+assert(type(debug.getregistry()) == "table")
+
+
+print"OK"
+
diff --git a/test/PUC-Lua-5.1-tests/errors.lua b/test/PUC-Lua-5.1-tests/errors.lua
new file mode 100644
index 0000000..e881211
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/errors.lua
@@ -0,0 +1,250 @@
+print("testing errors")
+
+function doit (s)
+ local f, msg = loadstring(s)
+ if f == nil then return msg end
+ local cond, msg = pcall(f)
+ return (not cond) and msg
+end
+
+
+function checkmessage (prog, msg)
+ assert(string.find(doit(prog), msg, 1, true))
+end
+
+function checksyntax (prog, extra, token, line)
+ local msg = doit(prog)
+ token = string.gsub(token, "(%p)", "%%%1")
+ local pt = string.format([[^%%[string ".*"%%]:%d: .- near '%s'$]],
+ line, token)
+ assert(string.find(msg, pt))
+ assert(string.find(msg, msg, 1, true))
+end
+
+
+-- test error message with no extra info
+assert(doit("error('hi', 0)") == 'hi')
+
+-- test error message with no info
+assert(doit("error()") == nil)
+
+
+-- test common errors/errors that crashed in the past
+assert(doit("unpack({}, 1, n=2^30)"))
+assert(doit("a=math.sin()"))
+assert(not doit("tostring(1)") and doit("tostring()"))
+assert(doit"tonumber()")
+assert(doit"repeat until 1; a")
+checksyntax("break label", "", "label", 1)
+assert(doit";")
+assert(doit"a=1;;")
+assert(doit"return;;")
+assert(doit"assert(false)")
+assert(doit"assert(nil)")
+assert(doit"a=math.sin\n(3)")
+assert(doit("function a (... , ...) end"))
+assert(doit("function a (, ...) end"))
+
+checksyntax([[
+ local a = {4
+
+]], "'}' expected (to close '{' at line 1)", "<eof>", 3)
+
+
+-- tests for better error messages
+
+checkmessage("a=1; bbbb=2; a=math.sin(3)+bbbb(3)", "global 'bbbb'")
+checkmessage("a=1; local a,bbbb=2,3; a = math.sin(1) and bbbb(3)",
+ "local 'bbbb'")
+checkmessage("a={}; do local a=1 end a:bbbb(3)", "method 'bbbb'")
+checkmessage("local a={}; a.bbbb(3)", "field 'bbbb'")
+assert(not string.find(doit"a={13}; local bbbb=1; a[bbbb](3)", "'bbbb'"))
+checkmessage("a={13}; local bbbb=1; a[bbbb](3)", "number")
+
+aaa = nil
+checkmessage("aaa.bbb:ddd(9)", "global 'aaa'")
+checkmessage("local aaa={bbb=1}; aaa.bbb:ddd(9)", "field 'bbb'")
+checkmessage("local aaa={bbb={}}; aaa.bbb:ddd(9)", "method 'ddd'")
+checkmessage("local a,b,c; (function () a = b+1 end)()", "upvalue 'b'")
+assert(not doit"local aaa={bbb={ddd=next}}; aaa.bbb:ddd(nil)")
+
+checkmessage("b=1; local aaa='a'; x=aaa+b", "local 'aaa'")
+checkmessage("aaa={}; x=3/aaa", "global 'aaa'")
+checkmessage("aaa='2'; b=nil;x=aaa*b", "global 'b'")
+checkmessage("aaa={}; x=-aaa", "global 'aaa'")
+assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'"))
+assert(not string.find(doit"aaa={}; (aaa or aaa)()", "'aaa'"))
+
+checkmessage([[aaa=9
+repeat until 3==3
+local x=math.sin(math.cos(3))
+if math.sin(1) == x then return math.sin(1) end -- tail call
+local a,b = 1, {
+ {x='a'..'b'..'c', y='b', z=x},
+ {1,2,3,4,5} or 3+3<=3+3,
+ 3+1>3+1,
+ {d = x and aaa[x or y]}}
+]], "global 'aaa'")
+
+checkmessage([[
+local x,y = {},1
+if math.sin(1) == 0 then return 3 end -- return
+x.a()]], "field 'a'")
+
+checkmessage([[
+prefix = nil
+insert = nil
+while 1 do
+ local a
+ if nil then break end
+ insert(prefix, a)
+end]], "global 'insert'")
+
+checkmessage([[ -- tail call
+ return math.sin("a")
+]], "'sin'")
+
+checkmessage([[collectgarbage("nooption")]], "invalid option")
+
+checkmessage([[x = print .. "a"]], "concatenate")
+
+checkmessage("getmetatable(io.stdin).__gc()", "no value")
+
+print'+'
+
+
+-- testing line error
+
+function lineerror (s)
+ local err,msg = pcall(loadstring(s))
+ local line = string.match(msg, ":(%d+):")
+ return line and line+0
+end
+
+assert(lineerror"local a\n for i=1,'a' do \n print(i) \n end" == 2)
+assert(lineerror"\n local a \n for k,v in 3 \n do \n print(k) \n end" == 3)
+assert(lineerror"\n\n for k,v in \n 3 \n do \n print(k) \n end" == 4)
+assert(lineerror"function a.x.y ()\na=a+1\nend" == 1)
+
+local p = [[
+function g() f() end
+function f(x) error('a', X) end
+g()
+]]
+X=3;assert(lineerror(p) == 3)
+X=0;assert(lineerror(p) == nil)
+X=1;assert(lineerror(p) == 2)
+X=2;assert(lineerror(p) == 1)
+
+lineerror = nil
+
+C = 0
+local l = debug.getinfo(1, "l").currentline; function y () C=C+1; y() end
+
+local function checkstackmessage (m)
+ return (string.find(m, "^.-:%d+: stack overflow"))
+end
+assert(checkstackmessage(doit('y()')))
+assert(checkstackmessage(doit('y()')))
+assert(checkstackmessage(doit('y()')))
+-- teste de linhas em erro
+C = 0
+local l1
+local function g()
+ l1 = debug.getinfo(1, "l").currentline; y()
+end
+local _, stackmsg = xpcall(g, debug.traceback)
+local stack = {}
+for line in string.gmatch(stackmsg, "[^\n]*") do
+ local curr = string.match(line, ":(%d+):")
+ if curr then table.insert(stack, tonumber(curr)) end
+end
+local i=1
+while stack[i] ~= l1 do
+ assert(stack[i] == l)
+ i = i+1
+end
+assert(i > 15)
+
+
+-- error in error handling
+local res, msg = xpcall(error, error)
+assert(not res and type(msg) == 'string')
+
+local function f (x)
+ if x==0 then error('a\n')
+ else
+ local aux = function () return f(x-1) end
+ local a,b = xpcall(aux, aux)
+ return a,b
+ end
+end
+f(3)
+
+-- non string messages
+function f() error{msg='x'} end
+res, msg = xpcall(f, function (r) return {msg=r.msg..'y'} end)
+assert(msg.msg == 'xy')
+
+print('+')
+checksyntax("syntax error", "", "error", 1)
+checksyntax("1.000", "", "1.000", 1)
+checksyntax("[[a]]", "", "[[a]]", 1)
+checksyntax("'aa'", "", "'aa'", 1)
+
+-- test 255 as first char in a chunk
+checksyntax("\255a = 1", "", "\255", 1)
+
+doit('I = loadstring("a=9+"); a=3')
+assert(a==3 and I == nil)
+print('+')
+
+lim = 1000
+if rawget(_G, "_soft") then lim = 100 end
+for i=1,lim do
+ doit('a = ')
+ doit('a = 4+nil')
+end
+
+
+-- testing syntax limits
+local function testrep (init, rep)
+ local s = "local a; "..init .. string.rep(rep, 400)
+ local a,b = loadstring(s)
+ assert(not a and string.find(b, "syntax levels"))
+end
+testrep("a=", "{")
+testrep("a=", "(")
+testrep("", "a(")
+testrep("", "do ")
+testrep("", "while a do ")
+testrep("", "if a then else ")
+testrep("", "function foo () ")
+testrep("a=", "a..")
+testrep("a=", "a^")
+
+
+-- testing other limits
+-- upvalues
+local s = "function foo ()\n local "
+for j = 1,70 do
+ s = s.."a"..j..", "
+end
+s = s.."b\n"
+for j = 1,70 do
+ s = s.."function foo"..j.." ()\n a"..j.."=3\n"
+end
+local a,b = loadstring(s)
+assert(string.find(b, "line 3"))
+
+-- local variables
+s = "\nfunction foo ()\n local "
+for j = 1,300 do
+ s = s.."a"..j..", "
+end
+s = s.."b\n"
+local a,b = loadstring(s)
+assert(string.find(b, "line 2"))
+
+
+print('OK')
diff --git a/test/PUC-Lua-5.1-tests/etc/ltests.c b/test/PUC-Lua-5.1-tests/etc/ltests.c
new file mode 100644
index 0000000..be949e5
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/etc/ltests.c
@@ -0,0 +1,1147 @@
+/*
+** $Id: ltests.c,v 2.36 2006/01/10 13:13:06 roberto Exp $
+** Internal Module for Debugging of the Lua Implementation
+** See Copyright Notice in lua.h
+*/
+
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define ltests_c
+#define LUA_CORE
+
+#include "lua.h"
+
+#include "lapi.h"
+#include "lauxlib.h"
+#include "lcode.h"
+#include "ldebug.h"
+#include "ldo.h"
+#include "lfunc.h"
+#include "lmem.h"
+#include "lopcodes.h"
+#include "lstate.h"
+#include "lstring.h"
+#include "ltable.h"
+#include "lualib.h"
+
+
+
+/*
+** The whole module only makes sense with LUA_DEBUG on
+*/
+#if defined(LUA_DEBUG)
+
+
+int Trick = 0;
+
+
+static lua_State *lua_state = NULL;
+
+int islocked = 0;
+
+
+#define obj_at(L,k) (L->ci->base+(k) - 1)
+
+
+static void setnameval (lua_State *L, const char *name, int val) {
+ lua_pushstring(L, name);
+ lua_pushinteger(L, val);
+ lua_settable(L, -3);
+}
+
+
+/*
+** {======================================================================
+** Controlled version for realloc.
+** =======================================================================
+*/
+
+#define MARK 0x55 /* 01010101 (a nice pattern) */
+
+#ifndef EXTERNMEMCHECK
+/* full memory check */
+#define HEADER (sizeof(L_Umaxalign)) /* ensures maximum alignment for HEADER */
+#define MARKSIZE 16 /* size of marks after each block */
+#define blockhead(b) (cast(char *, b) - HEADER)
+#define setsize(newblock, size) (*cast(size_t *, newblock) = size)
+#define checkblocksize(b, size) (size == (*cast(size_t *, blockhead(b))))
+#define fillmem(mem,size) memset(mem, -MARK, size)
+#else
+/* external memory check: don't do it twice */
+#define HEADER 0
+#define MARKSIZE 0
+#define blockhead(b) (b)
+#define setsize(newblock, size) /* empty */
+#define checkblocksize(b,size) (1)
+#define fillmem(mem,size) /* empty */
+#endif
+
+
+Memcontrol memcontrol = {0L, 0L, 0L, ULONG_MAX};
+
+
+static void *checkblock (void *block, size_t size) {
+ void *b = blockhead(block);
+ int i;
+ for (i=0;i<MARKSIZE;i++)
+ lua_assert(*(cast(char *, b)+HEADER+size+i) == MARK+i); /* corrupted block? */
+ return b;
+}
+
+
+static void freeblock (Memcontrol *mc, void *block, size_t size) {
+ if (block) {
+ lua_assert(checkblocksize(block, size));
+ block = checkblock(block, size);
+ fillmem(block, size+HEADER+MARKSIZE); /* erase block */
+ free(block); /* free original block */
+ mc->numblocks--;
+ mc->total -= size;
+ }
+}
+
+
+void *debug_realloc (void *ud, void *block, size_t oldsize, size_t size) {
+ Memcontrol *mc = cast(Memcontrol *, ud);
+ lua_assert(oldsize == 0 || checkblocksize(block, oldsize));
+ if (size == 0) {
+ freeblock(mc, block, oldsize);
+ return NULL;
+ }
+ else if (size > oldsize && mc->total+size-oldsize > mc->memlimit)
+ return NULL; /* to test memory allocation errors */
+ else {
+ void *newblock;
+ int i;
+ size_t realsize = HEADER+size+MARKSIZE;
+ size_t commonsize = (oldsize < size) ? oldsize : size;
+ if (realsize < size) return NULL; /* overflow! */
+ newblock = malloc(realsize); /* alloc a new block */
+ if (newblock == NULL) return NULL;
+ if (block) {
+ memcpy(cast(char *, newblock)+HEADER, block, commonsize);
+ freeblock(mc, block, oldsize); /* erase (and check) old copy */
+ }
+ /* initialize new part of the block with something `weird' */
+ fillmem(cast(char *, newblock)+HEADER+commonsize, size-commonsize);
+ mc->total += size;
+ if (mc->total > mc->maxmem)
+ mc->maxmem = mc->total;
+ mc->numblocks++;
+ setsize(newblock, size);
+ for (i=0;i<MARKSIZE;i++)
+ *(cast(char *, newblock)+HEADER+size+i) = cast(char, MARK+i);
+ return cast(char *, newblock)+HEADER;
+ }
+}
+
+
+/* }====================================================================== */
+
+
+
+/*
+** {======================================================
+** Functions to check memory consistency
+** =======================================================
+*/
+
+static int testobjref1 (global_State *g, GCObject *f, GCObject *t) {
+ if (isdead(g,t)) return 0;
+ if (g->gcstate == GCSpropagate)
+ return !isblack(f) || !iswhite(t);
+ else if (g->gcstate == GCSfinalize)
+ return iswhite(f);
+ else
+ return 1;
+}
+
+
+static void printobj (global_State *g, GCObject *o) {
+ int i = 0;
+ GCObject *p;
+ for (p = g->rootgc; p != o && p != NULL; p = p->gch.next) i++;
+ if (p == NULL) i = -1;
+ printf("%d:%s(%p)-%c(%02X)", i, luaT_typenames[o->gch.tt], (void *)o,
+ isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', o->gch.marked);
+}
+
+
+static int testobjref (global_State *g, GCObject *f, GCObject *t) {
+ int r = testobjref1(g,f,t);
+ if (!r) {
+ printf("%d(%02X) - ", g->gcstate, g->currentwhite);
+ printobj(g, f);
+ printf("\t-> ");
+ printobj(g, t);
+ printf("\n");
+ }
+ return r;
+}
+
+#define checkobjref(g,f,t) lua_assert(testobjref(g,f,obj2gco(t)))
+
+#define checkvalref(g,f,t) lua_assert(!iscollectable(t) || \
+ ((ttype(t) == (t)->value.gc->gch.tt) && testobjref(g,f,gcvalue(t))))
+
+
+
+static void checktable (global_State *g, Table *h) {
+ int i;
+ int weakkey = 0;
+ int weakvalue = 0;
+ const TValue *mode;
+ GCObject *hgc = obj2gco(h);
+ if (h->metatable)
+ checkobjref(g, hgc, h->metatable);
+ mode = gfasttm(g, h->metatable, TM_MODE);
+ if (mode && ttisstring(mode)) { /* is there a weak mode? */
+ weakkey = (strchr(svalue(mode), 'k') != NULL);
+ weakvalue = (strchr(svalue(mode), 'v') != NULL);
+ }
+ i = h->sizearray;
+ while (i--)
+ checkvalref(g, hgc, &h->array[i]);
+ i = sizenode(h);
+ while (i--) {
+ Node *n = gnode(h, i);
+ if (!ttisnil(gval(n))) {
+ lua_assert(!ttisnil(gkey(n)));
+ checkvalref(g, hgc, gkey(n));
+ checkvalref(g, hgc, gval(n));
+ }
+ }
+}
+
+
+/*
+** All marks are conditional because a GC may happen while the
+** prototype is still being created
+*/
+static void checkproto (global_State *g, Proto *f) {
+ int i;
+ GCObject *fgc = obj2gco(f);
+ if (f->source) checkobjref(g, fgc, f->source);
+ for (i=0; i<f->sizek; i++) {
+ if (ttisstring(f->k+i))
+ checkobjref(g, fgc, rawtsvalue(f->k+i));
+ }
+ for (i=0; i<f->sizeupvalues; i++) {
+ if (f->upvalues[i])
+ checkobjref(g, fgc, f->upvalues[i]);
+ }
+ for (i=0; i<f->sizep; i++) {
+ if (f->p[i])
+ checkobjref(g, fgc, f->p[i]);
+ }
+ for (i=0; i<f->sizelocvars; i++) {
+ if (f->locvars[i].varname)
+ checkobjref(g, fgc, f->locvars[i].varname);
+ }
+}
+
+
+
+static void checkclosure (global_State *g, Closure *cl) {
+ GCObject *clgc = obj2gco(cl);
+ checkobjref(g, clgc, cl->l.env);
+ if (cl->c.isC) {
+ int i;
+ for (i=0; i<cl->c.nupvalues; i++)
+ checkvalref(g, clgc, &cl->c.upvalue[i]);
+ }
+ else {
+ int i;
+ lua_assert(cl->l.nupvalues == cl->l.p->nups);
+ checkobjref(g, clgc, cl->l.p);
+ for (i=0; i<cl->l.nupvalues; i++) {
+ if (cl->l.upvals[i]) {
+ lua_assert(cl->l.upvals[i]->tt == LUA_TUPVAL);
+ checkobjref(g, clgc, cl->l.upvals[i]);
+ }
+ }
+ }
+}
+
+
+static void checkstack (global_State *g, lua_State *L1) {
+ StkId o;
+ CallInfo *ci;
+ GCObject *uvo;
+ lua_assert(!isdead(g, obj2gco(L1)));
+ for (uvo = L1->openupval; uvo != NULL; uvo = uvo->gch.next) {
+ UpVal *uv = gco2uv(uvo);
+ lua_assert(uv->v != &uv->u.value); /* must be open */
+ lua_assert(!isblack(uvo)); /* open upvalues cannot be black */
+ }
+ checkliveness(g, gt(L1));
+ if (L1->base_ci) {
+ for (ci = L1->base_ci; ci <= L1->ci; ci++) {
+ lua_assert(ci->top <= L1->stack_last);
+ lua_assert(lua_checkpc(L1, ci));
+ }
+ }
+ else lua_assert(L1->size_ci == 0);
+ if (L1->stack) {
+ for (o = L1->stack; o < L1->top; o++)
+ checkliveness(g, o);
+ }
+ else lua_assert(L1->stacksize == 0);
+}
+
+
+static void checkobject (global_State *g, GCObject *o) {
+ if (isdead(g, o))
+/* lua_assert(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep);*/
+{ if (!(g->gcstate == GCSsweepstring || g->gcstate == GCSsweep))
+printf(">>> %d %s %02x\n", g->gcstate, luaT_typenames[o->gch.tt], o->gch.marked);
+}
+ else {
+ if (g->gcstate == GCSfinalize)
+ lua_assert(iswhite(o));
+ switch (o->gch.tt) {
+ case LUA_TUPVAL: {
+ UpVal *uv = gco2uv(o);
+ lua_assert(uv->v == &uv->u.value); /* must be closed */
+ lua_assert(!isgray(o)); /* closed upvalues are never gray */
+ checkvalref(g, o, uv->v);
+ break;
+ }
+ case LUA_TUSERDATA: {
+ Table *mt = gco2u(o)->metatable;
+ if (mt) checkobjref(g, o, mt);
+ break;
+ }
+ case LUA_TTABLE: {
+ checktable(g, gco2h(o));
+ break;
+ }
+ case LUA_TTHREAD: {
+ checkstack(g, gco2th(o));
+ break;
+ }
+ case LUA_TFUNCTION: {
+ checkclosure(g, gco2cl(o));
+ break;
+ }
+ case LUA_TPROTO: {
+ checkproto(g, gco2p(o));
+ break;
+ }
+ default: lua_assert(0);
+ }
+ }
+}
+
+
+int lua_checkpc (lua_State *L, pCallInfo ci) {
+ if (ci == L->base_ci || !f_isLua(ci)) return 1;
+ else {
+ Proto *p = ci_func(ci)->l.p;
+ if (ci < L->ci)
+ return p->code <= ci->savedpc && ci->savedpc <= p->code + p->sizecode;
+ else
+ return p->code <= L->savedpc && L->savedpc <= p->code + p->sizecode;
+ }
+}
+
+
+int lua_checkmemory (lua_State *L) {
+ global_State *g = G(L);
+ GCObject *o;
+ UpVal *uv;
+ checkstack(g, g->mainthread);
+ for (o = g->rootgc; o != obj2gco(g->mainthread); o = o->gch.next)
+ checkobject(g, o);
+ for (o = o->gch.next; o != NULL; o = o->gch.next) {
+ lua_assert(o->gch.tt == LUA_TUSERDATA);
+ checkobject(g, o);
+ }
+ for (uv = g->uvhead.u.l.next; uv != &g->uvhead; uv = uv->u.l.next) {
+ lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
+ lua_assert(uv->v != &uv->u.value); /* must be open */
+ lua_assert(!isblack(obj2gco(uv))); /* open upvalues are never black */
+ checkvalref(g, obj2gco(uv), uv->v);
+ }
+ return 0;
+}
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** Disassembler
+** =======================================================
+*/
+
+
+static char *buildop (Proto *p, int pc, char *buff) {
+ Instruction i = p->code[pc];
+ OpCode o = GET_OPCODE(i);
+ const char *name = luaP_opnames[o];
+ int line = getline(p, pc);
+ sprintf(buff, "(%4d) %4d - ", line, pc);
+ switch (getOpMode(o)) {
+ case iABC:
+ sprintf(buff+strlen(buff), "%-12s%4d %4d %4d", name,
+ GETARG_A(i), GETARG_B(i), GETARG_C(i));
+ break;
+ case iABx:
+ sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_Bx(i));
+ break;
+ case iAsBx:
+ sprintf(buff+strlen(buff), "%-12s%4d %4d", name, GETARG_A(i), GETARG_sBx(i));
+ break;
+ }
+ return buff;
+}
+
+
+#if 0
+void luaI_printcode (Proto *pt, int size) {
+ int pc;
+ for (pc=0; pc<size; pc++) {
+ char buff[100];
+ printf("%s\n", buildop(pt, pc, buff));
+ }
+ printf("-------\n");
+}
+#endif
+
+
+static int listcode (lua_State *L) {
+ int pc;
+ Proto *p;
+ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
+ 1, "Lua function expected");
+ p = clvalue(obj_at(L, 1))->l.p;
+ lua_newtable(L);
+ setnameval(L, "maxstack", p->maxstacksize);
+ setnameval(L, "numparams", p->numparams);
+ for (pc=0; pc<p->sizecode; pc++) {
+ char buff[100];
+ lua_pushinteger(L, pc+1);
+ lua_pushstring(L, buildop(p, pc, buff));
+ lua_settable(L, -3);
+ }
+ return 1;
+}
+
+
+static int listk (lua_State *L) {
+ Proto *p;
+ int i;
+ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
+ 1, "Lua function expected");
+ p = clvalue(obj_at(L, 1))->l.p;
+ lua_createtable(L, p->sizek, 0);
+ for (i=0; i<p->sizek; i++) {
+ luaA_pushobject(L, p->k+i);
+ lua_rawseti(L, -2, i+1);
+ }
+ return 1;
+}
+
+
+static int listlocals (lua_State *L) {
+ Proto *p;
+ int pc = luaL_checkint(L, 2) - 1;
+ int i = 0;
+ const char *name;
+ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1),
+ 1, "Lua function expected");
+ p = clvalue(obj_at(L, 1))->l.p;
+ while ((name = luaF_getlocalname(p, ++i, pc)) != NULL)
+ lua_pushstring(L, name);
+ return i-1;
+}
+
+/* }====================================================== */
+
+
+
+
+static int get_limits (lua_State *L) {
+ lua_createtable(L, 0, 5);
+ setnameval(L, "BITS_INT", LUAI_BITSINT);
+ setnameval(L, "LFPF", LFIELDS_PER_FLUSH);
+ setnameval(L, "MAXVARS", LUAI_MAXVARS);
+ setnameval(L, "MAXSTACK", MAXSTACK);
+ setnameval(L, "MAXUPVALUES", LUAI_MAXUPVALUES);
+ setnameval(L, "NUM_OPCODES", NUM_OPCODES);
+ return 1;
+}
+
+
+static int mem_query (lua_State *L) {
+ if (lua_isnone(L, 1)) {
+ lua_pushinteger(L, memcontrol.total);
+ lua_pushinteger(L, memcontrol.numblocks);
+ lua_pushinteger(L, memcontrol.maxmem);
+ return 3;
+ }
+ else {
+ memcontrol.memlimit = luaL_checkint(L, 1);
+ return 0;
+ }
+}
+
+
+static int settrick (lua_State *L) {
+ Trick = lua_tointeger(L, 1);
+ return 0;
+}
+
+
+/*static int set_gcstate (lua_State *L) {
+ static const char *const state[] = {"propagate", "sweep", "finalize"};
+ return 0;
+}*/
+
+
+static int get_gccolor (lua_State *L) {
+ TValue *o;
+ luaL_checkany(L, 1);
+ o = obj_at(L, 1);
+ if (!iscollectable(o))
+ lua_pushstring(L, "no collectable");
+ else
+ lua_pushstring(L, iswhite(gcvalue(o)) ? "white" :
+ isblack(gcvalue(o)) ? "black" : "grey");
+ return 1;
+}
+
+
+static int gcstate (lua_State *L) {
+ switch(G(L)->gcstate) {
+ case GCSpropagate: lua_pushstring(L, "propagate"); break;
+ case GCSsweepstring: lua_pushstring(L, "sweep strings"); break;
+ case GCSsweep: lua_pushstring(L, "sweep"); break;
+ case GCSfinalize: lua_pushstring(L, "finalize"); break;
+ }
+ return 1;
+}
+
+
+static int hash_query (lua_State *L) {
+ if (lua_isnone(L, 2)) {
+ luaL_argcheck(L, lua_type(L, 1) == LUA_TSTRING, 1, "string expected");
+ lua_pushinteger(L, tsvalue(obj_at(L, 1))->hash);
+ }
+ else {
+ TValue *o = obj_at(L, 1);
+ Table *t;
+ luaL_checktype(L, 2, LUA_TTABLE);
+ t = hvalue(obj_at(L, 2));
+ lua_pushinteger(L, luaH_mainposition(t, o) - t->node);
+ }
+ return 1;
+}
+
+
+static int stacklevel (lua_State *L) {
+ unsigned long a = 0;
+ lua_pushinteger(L, (L->top - L->stack));
+ lua_pushinteger(L, (L->stack_last - L->stack));
+ lua_pushinteger(L, (L->ci - L->base_ci));
+ lua_pushinteger(L, (L->end_ci - L->base_ci));
+ lua_pushinteger(L, (unsigned long)&a);
+ return 5;
+}
+
+
+static int table_query (lua_State *L) {
+ const Table *t;
+ int i = luaL_optint(L, 2, -1);
+ luaL_checktype(L, 1, LUA_TTABLE);
+ t = hvalue(obj_at(L, 1));
+ if (i == -1) {
+ lua_pushinteger(L, t->sizearray);
+ lua_pushinteger(L, luaH_isdummy(t->node) ? 0 : sizenode(t));
+ lua_pushinteger(L, t->lastfree - t->node);
+ }
+ else if (i < t->sizearray) {
+ lua_pushinteger(L, i);
+ luaA_pushobject(L, &t->array[i]);
+ lua_pushnil(L);
+ }
+ else if ((i -= t->sizearray) < sizenode(t)) {
+ if (!ttisnil(gval(gnode(t, i))) ||
+ ttisnil(gkey(gnode(t, i))) ||
+ ttisnumber(gkey(gnode(t, i)))) {
+ luaA_pushobject(L, key2tval(gnode(t, i)));
+ }
+ else
+ lua_pushliteral(L, "<undef>");
+ luaA_pushobject(L, gval(gnode(t, i)));
+ if (gnext(&t->node[i]))
+ lua_pushinteger(L, gnext(&t->node[i]) - t->node);
+ else
+ lua_pushnil(L);
+ }
+ return 3;
+}
+
+
+static int string_query (lua_State *L) {
+ stringtable *tb = &G(L)->strt;
+ int s = luaL_optint(L, 2, 0) - 1;
+ if (s==-1) {
+ lua_pushinteger(L ,tb->nuse);
+ lua_pushinteger(L ,tb->size);
+ return 2;
+ }
+ else if (s < tb->size) {
+ GCObject *ts;
+ int n = 0;
+ for (ts = tb->hash[s]; ts; ts = ts->gch.next) {
+ setsvalue2s(L, L->top, gco2ts(ts));
+ incr_top(L);
+ n++;
+ }
+ return n;
+ }
+ return 0;
+}
+
+
+static int tref (lua_State *L) {
+ int level = lua_gettop(L);
+ int lock = luaL_optint(L, 2, 1);
+ luaL_checkany(L, 1);
+ lua_pushvalue(L, 1);
+ lua_pushinteger(L, lua_ref(L, lock));
+ lua_assert(lua_gettop(L) == level+1); /* +1 for result */
+ return 1;
+}
+
+static int getref (lua_State *L) {
+ int level = lua_gettop(L);
+ lua_getref(L, luaL_checkint(L, 1));
+ lua_assert(lua_gettop(L) == level+1);
+ return 1;
+}
+
+static int unref (lua_State *L) {
+ int level = lua_gettop(L);
+ lua_unref(L, luaL_checkint(L, 1));
+ lua_assert(lua_gettop(L) == level);
+ return 0;
+}
+
+
+static int upvalue (lua_State *L) {
+ int n = luaL_checkint(L, 2);
+ luaL_checktype(L, 1, LUA_TFUNCTION);
+ if (lua_isnone(L, 3)) {
+ const char *name = lua_getupvalue(L, 1, n);
+ if (name == NULL) return 0;
+ lua_pushstring(L, name);
+ return 2;
+ }
+ else {
+ const char *name = lua_setupvalue(L, 1, n);
+ lua_pushstring(L, name);
+ return 1;
+ }
+}
+
+
+static int newuserdata (lua_State *L) {
+ size_t size = luaL_checkint(L, 1);
+ char *p = cast(char *, lua_newuserdata(L, size));
+ while (size--) *p++ = '\0';
+ return 1;
+}
+
+
+static int pushuserdata (lua_State *L) {
+ lua_pushlightuserdata(L, cast(void *, luaL_checkint(L, 1)));
+ return 1;
+}
+
+
+static int udataval (lua_State *L) {
+ lua_pushinteger(L, cast(long, lua_touserdata(L, 1)));
+ return 1;
+}
+
+
+static int doonnewstack (lua_State *L) {
+ lua_State *L1 = lua_newthread(L);
+ size_t l;
+ const char *s = luaL_checklstring(L, 1, &l);
+ int status = luaL_loadbuffer(L1, s, l, s);
+ if (status == 0)
+ status = lua_pcall(L1, 0, 0, 0);
+ lua_pushinteger(L, status);
+ return 1;
+}
+
+
+static int s2d (lua_State *L) {
+ lua_pushnumber(L, *cast(const double *, luaL_checkstring(L, 1)));
+ return 1;
+}
+
+
+static int d2s (lua_State *L) {
+ double d = luaL_checknumber(L, 1);
+ lua_pushlstring(L, cast(char *, &d), sizeof(d));
+ return 1;
+}
+
+
+static int num2int (lua_State *L) {
+ lua_pushinteger(L, lua_tointeger(L, 1));
+ return 1;
+}
+
+
+static int newstate (lua_State *L) {
+ void *ud;
+ lua_Alloc f = lua_getallocf(L, &ud);
+ lua_State *L1 = lua_newstate(f, ud);
+ if (L1)
+ lua_pushinteger(L, (unsigned long)L1);
+ else
+ lua_pushnil(L);
+ return 1;
+}
+
+
+static int loadlib (lua_State *L) {
+ static const luaL_Reg libs[] = {
+ {"baselibopen", luaopen_base},
+ {"dblibopen", luaopen_debug},
+ {"iolibopen", luaopen_io},
+ {"mathlibopen", luaopen_math},
+ {"strlibopen", luaopen_string},
+ {"tablibopen", luaopen_table},
+ {"packageopen", luaopen_package},
+ {NULL, NULL}
+ };
+ lua_State *L1 = cast(lua_State *,
+ cast(unsigned long, luaL_checknumber(L, 1)));
+ lua_pushvalue(L1, LUA_GLOBALSINDEX);
+ luaL_register(L1, NULL, libs);
+ return 0;
+}
+
+static int closestate (lua_State *L) {
+ lua_State *L1 = cast(lua_State *, cast(unsigned long, luaL_checknumber(L, 1)));
+ lua_close(L1);
+ return 0;
+}
+
+static int doremote (lua_State *L) {
+ lua_State *L1 = cast(lua_State *,cast(unsigned long,luaL_checknumber(L, 1)));
+ size_t lcode;
+ const char *code = luaL_checklstring(L, 2, &lcode);
+ int status;
+ lua_settop(L1, 0);
+ status = luaL_loadbuffer(L1, code, lcode, code);
+ if (status == 0)
+ status = lua_pcall(L1, 0, LUA_MULTRET, 0);
+ if (status != 0) {
+ lua_pushnil(L);
+ lua_pushinteger(L, status);
+ lua_pushstring(L, lua_tostring(L1, -1));
+ return 3;
+ }
+ else {
+ int i = 0;
+ while (!lua_isnone(L1, ++i))
+ lua_pushstring(L, lua_tostring(L1, i));
+ lua_pop(L1, i-1);
+ return i-1;
+ }
+}
+
+
+static int log2_aux (lua_State *L) {
+ lua_pushinteger(L, luaO_log2(luaL_checkint(L, 1)));
+ return 1;
+}
+
+static int int2fb_aux (lua_State *L) {
+ int b = luaO_int2fb(luaL_checkint(L, 1));
+ lua_pushinteger(L, b);
+ lua_pushinteger(L, luaO_fb2int(b));
+ return 2;
+}
+
+
+
+/*
+** {======================================================
+** function to test the API with C. It interprets a kind of assembler
+** language with calls to the API, so the test can be driven by Lua code
+** =======================================================
+*/
+
+static const char *const delimits = " \t\n,;";
+
+static void skip (const char **pc) {
+ while (**pc != '\0' && strchr(delimits, **pc)) (*pc)++;
+}
+
+static int getnum_aux (lua_State *L, const char **pc) {
+ int res = 0;
+ int sig = 1;
+ skip(pc);
+ if (**pc == '.') {
+ res = cast_int(lua_tonumber(L, -1));
+ lua_pop(L, 1);
+ (*pc)++;
+ return res;
+ }
+ else if (**pc == '-') {
+ sig = -1;
+ (*pc)++;
+ }
+ while (isdigit(cast_int(**pc))) res = res*10 + (*(*pc)++) - '0';
+ return sig*res;
+}
+
+static const char *getname_aux (char *buff, const char **pc) {
+ int i = 0;
+ skip(pc);
+ while (**pc != '\0' && !strchr(delimits, **pc))
+ buff[i++] = *(*pc)++;
+ buff[i] = '\0';
+ return buff;
+}
+
+
+static int getindex_aux (lua_State *L, const char **pc) {
+ skip(pc);
+ switch (*(*pc)++) {
+ case 'R': return LUA_REGISTRYINDEX;
+ case 'G': return LUA_GLOBALSINDEX;
+ case 'E': return LUA_ENVIRONINDEX;
+ case 'U': return lua_upvalueindex(getnum_aux(L, pc));
+ default: (*pc)--; return getnum_aux(L, pc);
+ }
+}
+
+#define EQ(s1) (strcmp(s1, inst) == 0)
+
+#define getnum (getnum_aux(L, &pc))
+#define getname (getname_aux(buff, &pc))
+#define getindex (getindex_aux(L, &pc))
+
+
+static int testC (lua_State *L) {
+ char buff[30];
+ lua_State *L1;
+ const char *pc;
+ if (lua_isnumber(L, 1)) {
+ L1 = cast(lua_State *,cast(unsigned long,luaL_checknumber(L, 1)));
+ pc = luaL_checkstring(L, 2);
+ }
+ else {
+ L1 = L;
+ pc = luaL_checkstring(L, 1);
+ }
+ for (;;) {
+ const char *inst = getname;
+ if EQ("") return 0;
+ else if EQ("isnumber") {
+ lua_pushinteger(L1, lua_isnumber(L1, getindex));
+ }
+ else if EQ("isstring") {
+ lua_pushinteger(L1, lua_isstring(L1, getindex));
+ }
+ else if EQ("istable") {
+ lua_pushinteger(L1, lua_istable(L1, getindex));
+ }
+ else if EQ("iscfunction") {
+ lua_pushinteger(L1, lua_iscfunction(L1, getindex));
+ }
+ else if EQ("isfunction") {
+ lua_pushinteger(L1, lua_isfunction(L1, getindex));
+ }
+ else if EQ("isuserdata") {
+ lua_pushinteger(L1, lua_isuserdata(L1, getindex));
+ }
+ else if EQ("isudataval") {
+ lua_pushinteger(L1, lua_islightuserdata(L1, getindex));
+ }
+ else if EQ("isnil") {
+ lua_pushinteger(L1, lua_isnil(L1, getindex));
+ }
+ else if EQ("isnull") {
+ lua_pushinteger(L1, lua_isnone(L1, getindex));
+ }
+ else if EQ("tonumber") {
+ lua_pushnumber(L1, lua_tonumber(L1, getindex));
+ }
+ else if EQ("tostring") {
+ const char *s = lua_tostring(L1, getindex);
+ lua_pushstring(L1, s);
+ }
+ else if EQ("objsize") {
+ lua_pushinteger(L1, lua_objlen(L1, getindex));
+ }
+ else if EQ("tocfunction") {
+ lua_pushcfunction(L1, lua_tocfunction(L1, getindex));
+ }
+ else if EQ("return") {
+ return getnum;
+ }
+ else if EQ("gettop") {
+ lua_pushinteger(L1, lua_gettop(L1));
+ }
+ else if EQ("settop") {
+ lua_settop(L1, getnum);
+ }
+ else if EQ("pop") {
+ lua_pop(L1, getnum);
+ }
+ else if EQ("pushnum") {
+ lua_pushinteger(L1, getnum);
+ }
+ else if EQ("pushstring") {
+ lua_pushstring(L1, getname);
+ }
+ else if EQ("pushnil") {
+ lua_pushnil(L1);
+ }
+ else if EQ("pushbool") {
+ lua_pushboolean(L1, getnum);
+ }
+ else if EQ("newuserdata") {
+ lua_newuserdata(L1, getnum);
+ }
+ else if EQ("tobool") {
+ lua_pushinteger(L1, lua_toboolean(L1, getindex));
+ }
+ else if EQ("pushvalue") {
+ lua_pushvalue(L1, getindex);
+ }
+ else if EQ("pushcclosure") {
+ lua_pushcclosure(L1, testC, getnum);
+ }
+ else if EQ("remove") {
+ lua_remove(L1, getnum);
+ }
+ else if EQ("insert") {
+ lua_insert(L1, getnum);
+ }
+ else if EQ("replace") {
+ lua_replace(L1, getindex);
+ }
+ else if EQ("gettable") {
+ lua_gettable(L1, getindex);
+ }
+ else if EQ("settable") {
+ lua_settable(L1, getindex);
+ }
+ else if EQ("next") {
+ lua_next(L1, -2);
+ }
+ else if EQ("concat") {
+ lua_concat(L1, getnum);
+ }
+ else if EQ("lessthan") {
+ int a = getindex;
+ lua_pushboolean(L1, lua_lessthan(L1, a, getindex));
+ }
+ else if EQ("equal") {
+ int a = getindex;
+ lua_pushboolean(L1, lua_equal(L1, a, getindex));
+ }
+ else if EQ("rawcall") {
+ int narg = getnum;
+ int nres = getnum;
+ lua_call(L1, narg, nres);
+ }
+ else if EQ("call") {
+ int narg = getnum;
+ int nres = getnum;
+ lua_pcall(L1, narg, nres, 0);
+ }
+ else if EQ("loadstring") {
+ size_t sl;
+ const char *s = luaL_checklstring(L1, getnum, &sl);
+ luaL_loadbuffer(L1, s, sl, s);
+ }
+ else if EQ("loadfile") {
+ luaL_loadfile(L1, luaL_checkstring(L1, getnum));
+ }
+ else if EQ("setmetatable") {
+ lua_setmetatable(L1, getindex);
+ }
+ else if EQ("getmetatable") {
+ if (lua_getmetatable(L1, getindex) == 0)
+ lua_pushnil(L1);
+ }
+ else if EQ("type") {
+ lua_pushstring(L1, luaL_typename(L1, getnum));
+ }
+ else if EQ("getn") {
+ int i = getindex;
+ lua_pushinteger(L1, luaL_getn(L1, i));
+ }
+#ifndef luaL_setn
+ else if EQ("setn") {
+ int i = getindex;
+ int n = cast_int(lua_tonumber(L1, -1));
+ luaL_setn(L1, i, n);
+ lua_pop(L1, 1);
+ }
+#endif
+ else if EQ("throw") {
+#if defined(__cplusplus)
+static struct X { int x; } x;
+ throw x;
+#else
+ luaL_error(L1, "C++");
+#endif
+ break;
+ }
+ else luaL_error(L, "unknown instruction %s", buff);
+ }
+ return 0;
+}
+
+/* }====================================================== */
+
+
+/*
+** {======================================================
+** tests for yield inside hooks
+** =======================================================
+*/
+
+static void yieldf (lua_State *L, lua_Debug *ar) {
+ lua_yield(L, 0);
+}
+
+static int setyhook (lua_State *L) {
+ if (lua_isnoneornil(L, 1))
+ lua_sethook(L, NULL, 0, 0); /* turn off hooks */
+ else {
+ const char *smask = luaL_checkstring(L, 1);
+ int count = luaL_optint(L, 2, 0);
+ int mask = 0;
+ if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
+ if (count > 0) mask |= LUA_MASKCOUNT;
+ lua_sethook(L, yieldf, mask, count);
+ }
+ return 0;
+}
+
+
+static int coresume (lua_State *L) {
+ int status;
+ lua_State *co = lua_tothread(L, 1);
+ luaL_argcheck(L, co, 1, "coroutine expected");
+ status = lua_resume(co, 0);
+ if (status != 0) {
+ lua_pushboolean(L, 0);
+ lua_insert(L, -2);
+ return 2; /* return false + error message */
+ }
+ else {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+}
+
+/* }====================================================== */
+
+
+
+/*
+** {======================================================
+** tests auxlib functions
+** =======================================================
+*/
+
+static int auxgsub (lua_State *L) {
+ const char *s1 = luaL_checkstring(L, 1);
+ const char *s2 = luaL_checkstring(L, 2);
+ const char *s3 = luaL_checkstring(L, 3);
+ lua_settop(L, 3);
+ luaL_gsub(L, s1, s2, s3);
+ lua_assert(lua_gettop(L) == 4);
+ return 1;
+}
+
+
+/* }====================================================== */
+
+
+
+static const struct luaL_Reg tests_funcs[] = {
+ {"checkmemory", lua_checkmemory},
+ {"closestate", closestate},
+ {"d2s", d2s},
+ {"doonnewstack", doonnewstack},
+ {"doremote", doremote},
+ {"gccolor", get_gccolor},
+ {"gcstate", gcstate},
+ {"getref", getref},
+ {"gsub", auxgsub},
+ {"hash", hash_query},
+ {"int2fb", int2fb_aux},
+ {"limits", get_limits},
+ {"listcode", listcode},
+ {"listk", listk},
+ {"listlocals", listlocals},
+ {"loadlib", loadlib},
+ {"log2", log2_aux},
+ {"newstate", newstate},
+ {"newuserdata", newuserdata},
+ {"num2int", num2int},
+ {"pushuserdata", pushuserdata},
+ {"querystr", string_query},
+ {"querytab", table_query},
+ {"ref", tref},
+ {"resume", coresume},
+ {"s2d", s2d},
+ {"setyhook", setyhook},
+ {"stacklevel", stacklevel},
+ {"testC", testC},
+ {"totalmem", mem_query},
+ {"trick", settrick},
+ {"udataval", udataval},
+ {"unref", unref},
+ {"upvalue", upvalue},
+ {NULL, NULL}
+};
+
+
+int luaB_opentests (lua_State *L) {
+ void *ud;
+ lua_assert(lua_getallocf(L, &ud) == debug_realloc);
+ lua_assert(ud == cast(void *, &memcontrol));
+ lua_setallocf(L, lua_getallocf(L, NULL), ud);
+ lua_state = L; /* keep first state to be opened */
+ luaL_register(L, "T", tests_funcs);
+ return 0;
+}
+
+
+#undef main
+int main (int argc, char *argv[]) {
+ int ret;
+ char *limit = getenv("MEMLIMIT");
+ if (limit)
+ memcontrol.memlimit = strtoul(limit, NULL, 10);
+ ret = l_main(argc, argv);
+ lua_assert(memcontrol.numblocks == 0);
+ lua_assert(memcontrol.total == 0);
+ return ret;
+}
+
+#endif
diff --git a/test/PUC-Lua-5.1-tests/etc/ltests.h b/test/PUC-Lua-5.1-tests/etc/ltests.h
new file mode 100644
index 0000000..e570212
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/etc/ltests.h
@@ -0,0 +1,92 @@
+/*
+** $Id: ltests.h,v 2.17 2005/12/27 17:12:00 roberto Exp $
+** Internal Header for Debugging of the Lua Implementation
+** See Copyright Notice in lua.h
+*/
+
+#ifndef ltests_h
+#define ltests_h
+
+
+#include <stdlib.h>
+
+
+#define LUA_DEBUG
+
+#undef NDEBUG
+#include <assert.h>
+#define lua_assert(c) assert(c)
+
+
+/* to avoid warnings, and to make sure value is really unused */
+#define UNUSED(x) (x=0, (void)(x))
+
+
+/* memory allocator control variables */
+typedef struct Memcontrol {
+ unsigned long numblocks;
+ unsigned long total;
+ unsigned long maxmem;
+ unsigned long memlimit;
+} Memcontrol;
+
+LUAI_DATA Memcontrol memcontrol;
+
+
+/*
+** generic variable for debug tricks
+*/
+LUAI_DATA int Trick;
+
+
+void *debug_realloc (void *ud, void *block, size_t osize, size_t nsize);
+
+#ifdef lua_c
+#define luaL_newstate() lua_newstate(debug_realloc, &memcontrol)
+#endif
+
+
+typedef struct CallInfo *pCallInfo;
+
+int lua_checkmemory (lua_State *L);
+int lua_checkpc (lua_State *L, pCallInfo ci);
+
+
+/* test for lock/unlock */
+#undef luai_userstateopen
+#undef luai_userstatethread
+#undef lua_lock
+#undef lua_unlock
+#undef LUAI_EXTRASPACE
+
+struct L_EXTRA { int lock; int *plock; };
+#define LUAI_EXTRASPACE sizeof(struct L_EXTRA)
+#define getlock(l) (cast(struct L_EXTRA *, l) - 1)
+#define luai_userstateopen(l) \
+ (getlock(l)->lock = 0, getlock(l)->plock = &(getlock(l)->lock))
+#define luai_userstatethread(l,l1) (getlock(l1)->plock = getlock(l)->plock)
+#define lua_lock(l) lua_assert((*getlock(l)->plock)++ == 0)
+#define lua_unlock(l) lua_assert(--(*getlock(l)->plock) == 0)
+
+
+int luaB_opentests (lua_State *L);
+
+#ifdef lua_c
+#define luaL_openlibs(L) { (luaL_openlibs)(L); luaB_opentests(L); }
+#endif
+
+
+
+/* real main will be defined at `ltests.c' */
+int l_main (int argc, char *argv[]);
+#define main l_main
+
+
+
+/* change some sizes to give some bugs a chance */
+
+#undef LUAL_BUFFERSIZE
+#define LUAL_BUFFERSIZE 27
+#define MINSTRTABSIZE 2
+
+#endif
diff --git a/test/PUC-Lua-5.1-tests/events.lua b/test/PUC-Lua-5.1-tests/events.lua
new file mode 100644
index 0000000..5234b00
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/events.lua
@@ -0,0 +1,360 @@
+print('testing metatables')
+
+X = 20; B = 30
+
+setfenv(1, setmetatable({}, {__index=_G}))
+
+collectgarbage()
+
+X = X+10
+assert(X == 30 and _G.X == 20)
+B = false
+assert(B == false)
+B = nil
+assert(B == 30)
+
+assert(getmetatable{} == nil)
+assert(getmetatable(4) == nil)
+assert(getmetatable(nil) == nil)
+a={}; setmetatable(a, {__metatable = "xuxu",
+ __tostring=function(x) return x.name end})
+assert(getmetatable(a) == "xuxu")
+assert(tostring(a) == nil)
+-- cannot change a protected metatable
+assert(pcall(setmetatable, a, {}) == false)
+a.name = "gororoba"
+assert(tostring(a) == "gororoba")
+
+local a, t = {10,20,30; x="10", y="20"}, {}
+assert(setmetatable(a,t) == a)
+assert(getmetatable(a) == t)
+assert(setmetatable(a,nil) == a)
+assert(getmetatable(a) == nil)
+assert(setmetatable(a,t) == a)
+
+
+function f (t, i, e)
+ assert(not e)
+ local p = rawget(t, "parent")
+ return (p and p[i]+3), "dummy return"
+end
+
+t.__index = f
+
+a.parent = {z=25, x=12, [4] = 24}
+assert(a[1] == 10 and a.z == 28 and a[4] == 27 and a.x == "10")
+
+collectgarbage()
+
+a = setmetatable({}, t)
+function f(t, i, v) rawset(t, i, v-3) end
+t.__newindex = f
+a[1] = 30; a.x = "101"; a[5] = 200
+assert(a[1] == 27 and a.x == 98 and a[5] == 197)
+
+
+local c = {}
+a = setmetatable({}, t)
+t.__newindex = c
+a[1] = 10; a[2] = 20; a[3] = 90
+assert(c[1] == 10 and c[2] == 20 and c[3] == 90)
+
+
+do
+ local a;
+ a = setmetatable({}, {__index = setmetatable({},
+ {__index = setmetatable({},
+ {__index = function (_,n) return a[n-3]+4, "lixo" end})})})
+ a[0] = 20
+ for i=0,10 do
+ assert(a[i*3] == 20 + i*4)
+ end
+end
+
+
+do -- newindex
+ local foi
+ local a = {}
+ for i=1,10 do a[i] = 0; a['a'..i] = 0; end
+ setmetatable(a, {__newindex = function (t,k,v) foi=true; rawset(t,k,v) end})
+ foi = false; a[1]=0; assert(not foi)
+ foi = false; a['a1']=0; assert(not foi)
+ foi = false; a['a11']=0; assert(foi)
+ foi = false; a[11]=0; assert(foi)
+ foi = false; a[1]=nil; assert(not foi)
+ foi = false; a[1]=nil; assert(foi)
+end
+
+
+function f (t, ...) return t, {...} end
+t.__call = f
+
+do
+ local x,y = a(unpack{'a', 1})
+ assert(x==a and y[1]=='a' and y[2]==1 and y[3]==nil)
+ x,y = a()
+ assert(x==a and y[1]==nil)
+end
+
+
+local b = setmetatable({}, t)
+setmetatable(b,t)
+
+function f(op)
+ return function (...) cap = {[0] = op, ...} ; return (...) end
+end
+t.__add = f("add")
+t.__sub = f("sub")
+t.__mul = f("mul")
+t.__div = f("div")
+t.__mod = f("mod")
+t.__unm = f("unm")
+t.__pow = f("pow")
+
+assert(b+5 == b)
+assert(cap[0] == "add" and cap[1] == b and cap[2] == 5 and cap[3]==nil)
+assert(b+'5' == b)
+assert(cap[0] == "add" and cap[1] == b and cap[2] == '5' and cap[3]==nil)
+assert(5+b == 5)
+assert(cap[0] == "add" and cap[1] == 5 and cap[2] == b and cap[3]==nil)
+assert('5'+b == '5')
+assert(cap[0] == "add" and cap[1] == '5' and cap[2] == b and cap[3]==nil)
+b=b-3; assert(getmetatable(b) == t)
+assert(5-a == 5)
+assert(cap[0] == "sub" and cap[1] == 5 and cap[2] == a and cap[3]==nil)
+assert('5'-a == '5')
+assert(cap[0] == "sub" and cap[1] == '5' and cap[2] == a and cap[3]==nil)
+assert(a*a == a)
+assert(cap[0] == "mul" and cap[1] == a and cap[2] == a and cap[3]==nil)
+assert(a/0 == a)
+assert(cap[0] == "div" and cap[1] == a and cap[2] == 0 and cap[3]==nil)
+assert(a%2 == a)
+assert(cap[0] == "mod" and cap[1] == a and cap[2] == 2 and cap[3]==nil)
+assert(-a == a)
+assert(cap[0] == "unm" and cap[1] == a)
+assert(a^4 == a)
+assert(cap[0] == "pow" and cap[1] == a and cap[2] == 4 and cap[3]==nil)
+assert(a^'4' == a)
+assert(cap[0] == "pow" and cap[1] == a and cap[2] == '4' and cap[3]==nil)
+assert(4^a == 4)
+assert(cap[0] == "pow" and cap[1] == 4 and cap[2] == a and cap[3]==nil)
+assert('4'^a == '4')
+assert(cap[0] == "pow" and cap[1] == '4' and cap[2] == a and cap[3]==nil)
+
+
+t = {}
+t.__lt = function (a,b,c)
+ collectgarbage()
+ assert(c == nil)
+ if type(a) == 'table' then a = a.x end
+ if type(b) == 'table' then b = b.x end
+ return a<b, "dummy"
+end
+
+function Op(x) return setmetatable({x=x}, t) end
+
+local function test ()
+ assert(not(Op(1)<Op(1)) and (Op(1)<Op(2)) and not(Op(2)<Op(1)))
+ assert(not(Op('a')<Op('a')) and (Op('a')<Op('b')) and not(Op('b')<Op('a')))
+ assert((Op(1)<=Op(1)) and (Op(1)<=Op(2)) and not(Op(2)<=Op(1)))
+ assert((Op('a')<=Op('a')) and (Op('a')<=Op('b')) and not(Op('b')<=Op('a')))
+ assert(not(Op(1)>Op(1)) and not(Op(1)>Op(2)) and (Op(2)>Op(1)))
+ assert(not(Op('a')>Op('a')) and not(Op('a')>Op('b')) and (Op('b')>Op('a')))
+ assert((Op(1)>=Op(1)) and not(Op(1)>=Op(2)) and (Op(2)>=Op(1)))
+ assert((Op('a')>=Op('a')) and not(Op('a')>=Op('b')) and (Op('b')>=Op('a')))
+end
+
+test()
+
+t.__le = function (a,b,c)
+ assert(c == nil)
+ if type(a) == 'table' then a = a.x end
+ if type(b) == 'table' then b = b.x end
+ return a<=b, "dummy"
+end
+
+test() -- retest comparisons, now using both `lt' and `le'
+
+
+-- test `partial order'
+
+local function Set(x)
+ local y = {}
+ for _,k in pairs(x) do y[k] = 1 end
+ return setmetatable(y, t)
+end
+
+t.__lt = function (a,b)
+ for k in pairs(a) do
+ if not b[k] then return false end
+ b[k] = nil
+ end
+ return next(b) ~= nil
+end
+
+t.__le = nil
+
+assert(Set{1,2,3} < Set{1,2,3,4})
+assert(not(Set{1,2,3,4} < Set{1,2,3,4}))
+assert((Set{1,2,3,4} <= Set{1,2,3,4}))
+assert((Set{1,2,3,4} >= Set{1,2,3,4}))
+assert((Set{1,3} <= Set{3,5})) -- wrong!! model needs a `le' method ;-)
+
+t.__le = function (a,b)
+ for k in pairs(a) do
+ if not b[k] then return false end
+ end
+ return true
+end
+
+assert(not (Set{1,3} <= Set{3,5})) -- now its OK!
+assert(not(Set{1,3} <= Set{3,5}))
+assert(not(Set{1,3} >= Set{3,5}))
+
+t.__eq = function (a,b)
+ for k in pairs(a) do
+ if not b[k] then return false end
+ b[k] = nil
+ end
+ return next(b) == nil
+end
+
+local s = Set{1,3,5}
+assert(s == Set{3,5,1})
+assert(not rawequal(s, Set{3,5,1}))
+assert(rawequal(s, s))
+assert(Set{1,3,5,1} == Set{3,5,1})
+assert(Set{1,3,5} ~= Set{3,5,1,6})
+t[Set{1,3,5}] = 1
+assert(t[Set{1,3,5}] == nil) -- `__eq' is not valid for table accesses
+
+
+t.__concat = function (a,b,c)
+ assert(c == nil)
+ if type(a) == 'table' then a = a.val end
+ if type(b) == 'table' then b = b.val end
+ if A then return a..b
+ else
+ return setmetatable({val=a..b}, t)
+ end
+end
+
+c = {val="c"}; setmetatable(c, t)
+d = {val="d"}; setmetatable(d, t)
+
+A = true
+assert(c..d == 'cd')
+assert(0 .."a".."b"..c..d.."e".."f"..(5+3).."g" == "0abcdef8g")
+
+A = false
+x = c..d
+assert(getmetatable(x) == t and x.val == 'cd')
+x = 0 .."a".."b"..c..d.."e".."f".."g"
+assert(x.val == "0abcdefg")
+
+
+-- test comparison compatibilities
+local t1, t2, c, d
+t1 = {}; c = {}; setmetatable(c, t1)
+d = {}
+t1.__eq = function () return true end
+t1.__lt = function () return true end
+assert(c ~= d and not pcall(function () return c < d end))
+setmetatable(d, t1)
+assert(c == d and c < d and not(d <= c))
+t2 = {}
+t2.__eq = t1.__eq
+t2.__lt = t1.__lt
+setmetatable(d, t2)
+assert(c == d and c < d and not(d <= c))
+
+
+
+-- test for several levels of calls
+local i
+local tt = {
+ __call = function (t, ...)
+ i = i+1
+ if t.f then return t.f(...)
+ else return {...}
+ end
+ end
+}
+
+local a = setmetatable({}, tt)
+local b = setmetatable({f=a}, tt)
+local c = setmetatable({f=b}, tt)
+
+i = 0
+x = c(3,4,5)
+assert(i == 3 and x[1] == 3 and x[3] == 5)
+
+
+assert(_G.X == 20)
+assert(_G == getfenv(0))
+
+print'+'
+
+local _g = _G
+setfenv(1, setmetatable({}, {__index=function (_,k) return _g[k] end}))
+
+-- testing proxies
+assert(getmetatable(newproxy()) == nil)
+assert(getmetatable(newproxy(false)) == nil)
+
+local u = newproxy(true)
+
+getmetatable(u).__newindex = function (u,k,v)
+ getmetatable(u)[k] = v
+end
+
+getmetatable(u).__index = function (u,k)
+ return getmetatable(u)[k]
+end
+
+for i=1,10 do u[i] = i end
+for i=1,10 do assert(u[i] == i) end
+
+local k = newproxy(u)
+assert(getmetatable(k) == getmetatable(u))
+
+
+a = {}
+rawset(a, "x", 1, 2, 3)
+assert(a.x == 1 and rawget(a, "x", 3) == 1)
+
+print '+'
+
+-- testing metatables for basic types
+mt = {}
+debug.setmetatable(10, mt)
+assert(getmetatable(-2) == mt)
+mt.__index = function (a,b) return a+b end
+assert((10)[3] == 13)
+assert((10)["3"] == 13)
+debug.setmetatable(23, nil)
+assert(getmetatable(-2) == nil)
+
+debug.setmetatable(true, mt)
+assert(getmetatable(false) == mt)
+mt.__index = function (a,b) return a or b end
+assert((true)[false] == true)
+assert((false)[false] == false)
+debug.setmetatable(false, nil)
+assert(getmetatable(true) == nil)
+
+debug.setmetatable(nil, mt)
+assert(getmetatable(nil) == mt)
+mt.__add = function (a,b) return (a or 0) + (b or 0) end
+assert(10 + nil == 10)
+assert(nil + 23 == 23)
+assert(nil + nil == 0)
+debug.setmetatable(nil, nil)
+assert(getmetatable(nil) == nil)
+
+debug.setmetatable(nil, {})
+
+
+print 'OK'
+
+return 12
diff --git a/test/PUC-Lua-5.1-tests/files.lua b/test/PUC-Lua-5.1-tests/files.lua
new file mode 100644
index 0000000..903488c
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/files.lua
@@ -0,0 +1,324 @@
+
+print('testing i/o')
+
+assert(io.input(io.stdin) == io.stdin)
+assert(io.output(io.stdout) == io.stdout)
+
+
+assert(type(io.input()) == "userdata" and io.type(io.output()) == "file")
+assert(io.type(8) == nil)
+local a = {}; setmetatable(a, {})
+assert(io.type(a) == nil)
+
+local a,b,c = io.open('xuxu_nao_existe')
+assert(not a and type(b) == "string" and type(c) == "number")
+
+a,b,c = io.open('/a/b/c/d', 'w')
+assert(not a and type(b) == "string" and type(c) == "number")
+
+local file = os.tmpname()
+local otherfile = os.tmpname()
+
+assert(os.setlocale('C', 'all'))
+
+io.input(io.stdin); io.output(io.stdout);
+
+os.remove(file)
+assert(loadfile(file) == nil)
+assert(io.open(file) == nil)
+io.output(file)
+assert(io.output() ~= io.stdout)
+
+assert(io.output():seek() == 0)
+assert(io.write("alo alo"))
+assert(io.output():seek() == string.len("alo alo"))
+assert(io.output():seek("cur", -3) == string.len("alo alo")-3)
+assert(io.write("joao"))
+assert(io.output():seek("end") == string.len("alo joao"))
+
+assert(io.output():seek("set") == 0)
+
+assert(io.write('"álo"', "{a}\n", "second line\n", "third line \n"))
+assert(io.write('çfourth_line'))
+io.output(io.stdout)
+collectgarbage() -- file should be closed by GC
+assert(io.input() == io.stdin and rawequal(io.output(), io.stdout))
+print('+')
+
+-- test GC for files
+collectgarbage()
+for i=1,120 do
+ for i=1,5 do
+ io.input(file)
+ assert(io.open(file, 'r'))
+ io.lines(file)
+ end
+ collectgarbage()
+end
+
+assert(os.rename(file, otherfile))
+assert(os.rename(file, otherfile) == nil)
+
+io.output(io.open(otherfile, "a"))
+assert(io.write("\n\n\t\t 3450\n"));
+io.close()
+
+-- test line generators
+assert(os.rename(otherfile, file))
+io.output(otherfile)
+local f = io.lines(file)
+while f() do end;
+assert(not pcall(f)) -- read lines after EOF
+assert(not pcall(f)) -- read lines after EOF
+-- copy from file to otherfile
+for l in io.lines(file) do io.write(l, "\n") end
+io.close()
+-- copy from otherfile back to file
+local f = assert(io.open(otherfile))
+assert(io.type(f) == "file")
+io.output(file)
+assert(io.output():read() == nil)
+for l in f:lines() do io.write(l, "\n") end
+assert(f:close()); io.close()
+assert(not pcall(io.close, f)) -- error trying to close again
+assert(tostring(f) == "file (closed)")
+assert(io.type(f) == "closed file")
+io.input(file)
+f = io.open(otherfile):lines()
+for l in io.lines() do assert(l == f()) end
+assert(os.remove(otherfile))
+
+io.input(file)
+do -- test error returns
+ local a,b,c = io.input():write("xuxu")
+ assert(not a and type(b) == "string" and type(c) == "number")
+end
+assert(io.read(0) == "") -- not eof
+assert(io.read(5, '*l') == '"álo"')
+assert(io.read(0) == "")
+assert(io.read() == "second line")
+local x = io.input():seek()
+assert(io.read() == "third line ")
+assert(io.input():seek("set", x))
+assert(io.read('*l') == "third line ")
+assert(io.read(1) == "ç")
+assert(io.read(string.len"fourth_line") == "fourth_line")
+assert(io.input():seek("cur", -string.len"fourth_line"))
+assert(io.read() == "fourth_line")
+assert(io.read() == "") -- empty line
+assert(io.read('*n') == 3450)
+assert(io.read(1) == '\n')
+assert(io.read(0) == nil) -- end of file
+assert(io.read(1) == nil) -- end of file
+assert(({io.read(1)})[2] == nil)
+assert(io.read() == nil) -- end of file
+assert(({io.read()})[2] == nil)
+assert(io.read('*n') == nil) -- end of file
+assert(({io.read('*n')})[2] == nil)
+assert(io.read('*a') == '') -- end of file (OK for `*a')
+assert(io.read('*a') == '') -- end of file (OK for `*a')
+collectgarbage()
+print('+')
+io.close(io.input())
+assert(not pcall(io.read))
+
+assert(os.remove(file))
+
+local t = '0123456789'
+for i=1,12 do t = t..t; end
+assert(string.len(t) == 10*2^12)
+
+io.output(file)
+io.write("alo\n")
+io.close()
+assert(not pcall(io.write))
+local f = io.open(file, "a")
+io.output(f)
+collectgarbage()
+
+assert(io.write(' ' .. t .. ' '))
+assert(io.write(';', 'end of file\n'))
+f:flush(); io.flush()
+f:close()
+print('+')
+
+io.input(file)
+assert(io.read() == "alo")
+assert(io.read(1) == ' ')
+assert(io.read(string.len(t)) == t)
+assert(io.read(1) == ' ')
+assert(io.read(0))
+assert(io.read('*a') == ';end of file\n')
+assert(io.read(0) == nil)
+assert(io.close(io.input()))
+
+assert(os.remove(file))
+print('+')
+
+local x1 = "string\n\n\\com \"\"''coisas [[estranhas]] ]]'"
+io.output(file)
+assert(io.write(string.format("x2 = %q\n-- comment without ending EOS", x1)))
+io.close()
+assert(loadfile(file))()
+assert(x1 == x2)
+print('+')
+assert(os.remove(file))
+assert(os.remove(file) == nil)
+assert(os.remove(otherfile) == nil)
+
+io.output(file)
+assert(io.write("qualquer coisa\n"))
+assert(io.write("mais qualquer coisa"))
+io.close()
+io.output(assert(io.open(otherfile, 'wb')))
+assert(io.write("outra coisa\0\1\3\0\0\0\0\255\0"))
+io.close()
+
+local filehandle = assert(io.open(file, 'r'))
+local otherfilehandle = assert(io.open(otherfile, 'rb'))
+assert(filehandle ~= otherfilehandle)
+assert(type(filehandle) == "userdata")
+assert(filehandle:read('*l') == "qualquer coisa")
+io.input(otherfilehandle)
+assert(io.read(string.len"outra coisa") == "outra coisa")
+assert(filehandle:read('*l') == "mais qualquer coisa")
+filehandle:close();
+assert(type(filehandle) == "userdata")
+io.input(otherfilehandle)
+assert(io.read(4) == "\0\1\3\0")
+assert(io.read(3) == "\0\0\0")
+assert(io.read(0) == "") -- 255 is not eof
+assert(io.read(1) == "\255")
+assert(io.read('*a') == "\0")
+assert(not io.read(0))
+assert(otherfilehandle == io.input())
+otherfilehandle:close()
+assert(os.remove(file))
+assert(os.remove(otherfile))
+collectgarbage()
+
+io.output(file)
+io.write[[
+ 123.4 -56e-2 not a number
+second line
+third line
+
+and the rest of the file
+]]
+io.close()
+io.input(file)
+local _,a,b,c,d,e,h,__ = io.read(1, '*n', '*n', '*l', '*l', '*l', '*a', 10)
+assert(io.close(io.input()))
+assert(_ == ' ' and __ == nil)
+assert(type(a) == 'number' and a==123.4 and b==-56e-2)
+assert(d=='second line' and e=='third line')
+assert(h==[[
+
+and the rest of the file
+]])
+assert(os.remove(file))
+collectgarbage()
+
+-- testing buffers
+do
+ local f = assert(io.open(file, "w"))
+ local fr = assert(io.open(file, "r"))
+ assert(f:setvbuf("full", 2000))
+ f:write("x")
+ assert(fr:read("*all") == "") -- full buffer; output not written yet
+ f:close()
+ fr:seek("set")
+ assert(fr:read("*all") == "x") -- `close' flushes it
+ f = assert(io.open(file), "w")
+ assert(f:setvbuf("no"))
+ f:write("x")
+ fr:seek("set")
+ assert(fr:read("*all") == "x") -- no buffer; output is ready
+ f:close()
+ f = assert(io.open(file, "a"))
+ assert(f:setvbuf("line"))
+ f:write("x")
+ fr:seek("set", 1)
+ assert(fr:read("*all") == "") -- line buffer; no output without `\n'
+ f:write("a\n")
+ fr:seek("set", 1)
+ assert(fr:read("*all") == "xa\n") -- now we have a whole line
+ f:close(); fr:close()
+end
+
+
+-- testing large files (> BUFSIZ)
+io.output(file)
+for i=1,5001 do io.write('0123456789123') end
+io.write('\n12346')
+io.close()
+io.input(file)
+local x = io.read('*a')
+io.input():seek('set', 0)
+local y = io.read(30001)..io.read(1005)..io.read(0)..io.read(1)..io.read(100003)
+assert(x == y and string.len(x) == 5001*13 + 6)
+io.input():seek('set', 0)
+y = io.read() -- huge line
+assert(x == y..'\n'..io.read())
+assert(io.read() == nil)
+io.close(io.input())
+assert(os.remove(file))
+x = nil; y = nil
+
+x, y = pcall(io.popen, "ls")
+if x then
+ assert(y:read("*a"))
+ assert(y:close())
+else
+ (Message or print)('\a\n >>> popen not available<<<\n\a')
+end
+
+print'+'
+
+local t = os.time()
+T = os.date("*t", t)
+loadstring(os.date([[assert(T.year==%Y and T.month==%m and T.day==%d and
+ T.hour==%H and T.min==%M and T.sec==%S and
+ T.wday==%w+1 and T.yday==%j and type(T.isdst) == 'boolean')]], t))()
+
+assert(os.time(T) == t)
+
+T = os.date("!*t", t)
+loadstring(os.date([[!assert(T.year==%Y and T.month==%m and T.day==%d and
+ T.hour==%H and T.min==%M and T.sec==%S and
+ T.wday==%w+1 and T.yday==%j and type(T.isdst) == 'boolean')]], t))()
+
+do
+ local T = os.date("*t")
+ local t = os.time(T)
+ assert(type(T.isdst) == 'boolean')
+ T.isdst = nil
+ local t1 = os.time(T)
+ assert(t == t1) -- if isdst is absent uses correct default
+end
+
+t = os.time(T)
+T.year = T.year-1;
+local t1 = os.time(T)
+-- allow for leap years
+assert(math.abs(os.difftime(t,t1)/(24*3600) - 365) < 2)
+
+t = os.time()
+t1 = os.time(os.date("*t"))
+assert(os.difftime(t1,t) <= 2)
+
+local t1 = os.time{year=2000, month=10, day=1, hour=23, min=12, sec=17}
+local t2 = os.time{year=2000, month=10, day=1, hour=23, min=10, sec=19}
+assert(os.difftime(t1,t2) == 60*2-2)
+
+io.output(io.stdout)
+local d = os.date('%d')
+local m = os.date('%m')
+local a = os.date('%Y')
+local ds = os.date('%w') + 1
+local h = os.date('%H')
+local min = os.date('%M')
+local s = os.date('%S')
+io.write(string.format('test done on %2.2d/%2.2d/%d', d, m, a))
+io.write(string.format(', at %2.2d:%2.2d:%2.2d\n', h, min, s))
+io.write(string.format('%s\n', _VERSION))
diff --git a/test/PUC-Lua-5.1-tests/gc.lua b/test/PUC-Lua-5.1-tests/gc.lua
new file mode 100644
index 0000000..86a9f75
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/gc.lua
@@ -0,0 +1,312 @@
+print('testing garbage collection')
+
+collectgarbage()
+
+_G["while"] = 234
+
+limit = 5000
+
+
+
+contCreate = 0
+
+print('tables')
+while contCreate <= limit do
+ local a = {}; a = nil
+ contCreate = contCreate+1
+end
+
+a = "a"
+
+contCreate = 0
+print('strings')
+while contCreate <= limit do
+ a = contCreate .. "b";
+ a = string.gsub(a, '(%d%d*)', string.upper)
+ a = "a"
+ contCreate = contCreate+1
+end
+
+
+contCreate = 0
+
+a = {}
+
+print('functions')
+function a:test ()
+ while contCreate <= limit do
+ loadstring(string.format("function temp(a) return 'a%d' end", contCreate))()
+ assert(temp() == string.format('a%d', contCreate))
+ contCreate = contCreate+1
+ end
+end
+
+a:test()
+
+-- collection of functions without locals, globals, etc.
+do local f = function () end end
+
+
+print("functions with errors")
+prog = [[
+do
+ a = 10;
+ function foo(x,y)
+ a = sin(a+0.456-0.23e-12);
+ return function (z) return sin(%x+z) end
+ end
+ local x = function (w) a=a+w; end
+end
+]]
+do
+ local step = 1
+ if rawget(_G, "_soft") then step = 13 end
+ for i=1, string.len(prog), step do
+ for j=i, string.len(prog), step do
+ pcall(loadstring(string.sub(prog, i, j)))
+ end
+ end
+end
+
+print('long strings')
+x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789"
+assert(string.len(x)==80)
+s = ''
+n = 0
+k = 300
+while n < k do s = s..x; n=n+1; j=tostring(n) end
+assert(string.len(s) == k*80)
+s = string.sub(s, 1, 20000)
+s, i = string.gsub(s, '(%d%d%d%d)', math.sin)
+assert(i==20000/4)
+s = nil
+x = nil
+
+assert(_G["while"] == 234)
+
+
+local bytes = gcinfo()
+while 1 do
+ local nbytes = gcinfo()
+ if nbytes < bytes then break end -- run until gc
+ bytes = nbytes
+ a = {}
+end
+
+
+local function dosteps (siz)
+ collectgarbage()
+ collectgarbage"stop"
+ local a = {}
+ for i=1,100 do a[i] = {{}}; local b = {} end
+ local x = gcinfo()
+ local i = 0
+ repeat
+ i = i+1
+ until collectgarbage("step", siz)
+ assert(gcinfo() < x)
+ return i
+end
+
+assert(dosteps(0) > 10)
+assert(dosteps(6) < dosteps(2))
+assert(dosteps(10000) == 1)
+assert(collectgarbage("step", 1000000) == true)
+assert(collectgarbage("step", 1000000))
+
+
+do
+ local x = gcinfo()
+ collectgarbage()
+ collectgarbage"stop"
+ repeat
+ local a = {}
+ until gcinfo() > 1000
+ collectgarbage"restart"
+ repeat
+ local a = {}
+ until gcinfo() < 1000
+end
+
+lim = 15
+a = {}
+-- fill a with `collectable' indices
+for i=1,lim do a[{}] = i end
+b = {}
+for k,v in pairs(a) do b[k]=v end
+-- remove all indices and collect them
+for n in pairs(b) do
+ a[n] = nil
+ assert(type(n) == 'table' and next(n) == nil)
+ collectgarbage()
+end
+b = nil
+collectgarbage()
+for n in pairs(a) do error'cannot be here' end
+for i=1,lim do a[i] = i end
+for i=1,lim do assert(a[i] == i) end
+
+
+print('weak tables')
+a = {}; setmetatable(a, {__mode = 'k'});
+-- fill a with some `collectable' indices
+for i=1,lim do a[{}] = i end
+-- and some non-collectable ones
+for i=1,lim do local t={}; a[t]=t end
+for i=1,lim do a[i] = i end
+for i=1,lim do local s=string.rep('@', i); a[s] = s..'#' end
+collectgarbage()
+local i = 0
+for k,v in pairs(a) do assert(k==v or k..'#'==v); i=i+1 end
+assert(i == 3*lim)
+
+a = {}; setmetatable(a, {__mode = 'v'});
+a[1] = string.rep('b', 21)
+collectgarbage()
+assert(a[1]) -- strings are *values*
+a[1] = nil
+-- fill a with some `collectable' values (in both parts of the table)
+for i=1,lim do a[i] = {} end
+for i=1,lim do a[i..'x'] = {} end
+-- and some non-collectable ones
+for i=1,lim do local t={}; a[t]=t end
+for i=1,lim do a[i+lim]=i..'x' end
+collectgarbage()
+local i = 0
+for k,v in pairs(a) do assert(k==v or k-lim..'x' == v); i=i+1 end
+assert(i == 2*lim)
+
+a = {}; setmetatable(a, {__mode = 'vk'});
+local x, y, z = {}, {}, {}
+-- keep only some items
+a[1], a[2], a[3] = x, y, z
+a[string.rep('$', 11)] = string.rep('$', 11)
+-- fill a with some `collectable' values
+for i=4,lim do a[i] = {} end
+for i=1,lim do a[{}] = i end
+for i=1,lim do local t={}; a[t]=t end
+collectgarbage()
+assert(next(a) ~= nil)
+local i = 0
+for k,v in pairs(a) do
+ assert((k == 1 and v == x) or
+ (k == 2 and v == y) or
+ (k == 3 and v == z) or k==v);
+ i = i+1
+end
+assert(i == 4)
+x,y,z=nil
+collectgarbage()
+assert(next(a) == string.rep('$', 11))
+
+
+-- testing userdata
+collectgarbage("stop") -- stop collection
+local u = newproxy(true)
+local s = 0
+local a = {[u] = 0}; setmetatable(a, {__mode = 'vk'})
+for i=1,10 do a[newproxy(u)] = i end
+for k in pairs(a) do assert(getmetatable(k) == getmetatable(u)) end
+local a1 = {}; for k,v in pairs(a) do a1[k] = v end
+for k,v in pairs(a1) do a[v] = k end
+for i =1,10 do assert(a[i]) end
+getmetatable(u).a = a1
+getmetatable(u).u = u
+do
+ local u = u
+ getmetatable(u).__gc = function (o)
+ assert(a[o] == 10-s)
+ assert(a[10-s] == nil) -- udata already removed from weak table
+ assert(getmetatable(o) == getmetatable(u))
+ assert(getmetatable(o).a[o] == 10-s)
+ s=s+1
+ end
+end
+a1, u = nil
+assert(next(a) ~= nil)
+collectgarbage()
+assert(s==11)
+collectgarbage()
+assert(next(a) == nil) -- finalized keys are removed in two cycles
+
+
+-- __gc x weak tables
+local u = newproxy(true)
+setmetatable(getmetatable(u), {__mode = "v"})
+getmetatable(u).__gc = function (o) os.exit(1) end -- cannot happen
+collectgarbage()
+
+local u = newproxy(true)
+local m = getmetatable(u)
+m.x = {[{0}] = 1; [0] = {1}}; setmetatable(m.x, {__mode = "kv"});
+m.__gc = function (o)
+ assert(next(getmetatable(o).x) == nil)
+ m = 10
+end
+u, m = nil
+collectgarbage()
+assert(m==10)
+
+
+-- errors during collection
+u = newproxy(true)
+getmetatable(u).__gc = function () error "!!!" end
+u = nil
+assert(not pcall(collectgarbage))
+
+
+if not rawget(_G, "_soft") then
+ print("deep structures")
+ local a = {}
+ for i = 1,200000 do
+ a = {next = a}
+ end
+ collectgarbage()
+end
+
+-- create many threads with self-references and open upvalues
+local thread_id = 0
+local threads = {}
+
+function fn(thread)
+ local x = {}
+ threads[thread_id] = function()
+ thread = x
+ end
+ coroutine.yield()
+end
+
+while thread_id < 1000 do
+ local thread = coroutine.create(fn)
+ coroutine.resume(thread, thread)
+ thread_id = thread_id + 1
+end
+
+
+
+-- create a userdata to be collected when state is closed
+do
+ local newproxy,assert,type,print,getmetatable =
+ newproxy,assert,type,print,getmetatable
+ local u = newproxy(true)
+ local tt = getmetatable(u)
+ ___Glob = {u} -- avoid udata being collected before program end
+ tt.__gc = function (o)
+ assert(getmetatable(o) == tt)
+ -- create new objects during GC
+ local a = 'xuxu'..(10+3)..'joao', {}
+ ___Glob = o -- ressurect object!
+ newproxy(o) -- creates a new one with same metatable
+ print(">>> closing state " .. "<<<\n")
+ end
+end
+
+-- create several udata to raise errors when collected while closing state
+do
+ local u = newproxy(true)
+ getmetatable(u).__gc = function (o) return o + 1 end
+ table.insert(___Glob, u) -- preserve udata until the end
+ for i = 1,10 do table.insert(___Glob, newproxy(u)) end
+end
+
+print('OK')
diff --git a/test/PUC-Lua-5.1-tests/libs/lib1.c b/test/PUC-Lua-5.1-tests/libs/lib1.c
new file mode 100644
index 0000000..22fe6de
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/libs/lib1.c
@@ -0,0 +1,40 @@
+/*
+** compile with
+** Linux: gcc -Wall -O2 -I.. -ansi -shared -o lib1.so lib1.c
+** Mac OS X: export MACOSX_DEPLOYMENT_TARGET=10.3
+** gcc -bundle -undefined dynamic_lookup -Wall -O2 -o lib1.so lib1.c
+*/
+
+
+#include "lua.h"
+#include "lauxlib.h"
+
+static int id (lua_State *L) {
+ return lua_gettop(L);
+}
+
+
+static const struct luaL_Reg funcs[] = {
+ {"id", id},
+ {NULL, NULL}
+};
+
+
+int anotherfunc (lua_State *L) {
+ lua_pushfstring(L, "%f%f\n", lua_tonumber(L, 1), lua_tonumber(L, 2));
+ return 1;
+}
+
+
+int luaopen_lib1_sub (lua_State *L) {
+ luaL_register(L, "lib1.sub", funcs + 1);
+ return 1;
+}
+
+
+int luaopen_lib1 (lua_State *L) {
+ luaL_register(L, "lib1", funcs);
+ return 1;
+}
+
+
diff --git a/test/PUC-Lua-5.1-tests/libs/lib11.c b/test/PUC-Lua-5.1-tests/libs/lib11.c
new file mode 100644
index 0000000..3efa3d3
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/libs/lib11.c
@@ -0,0 +1,18 @@
+/*
+** compile with
+** Linux: gcc -Wall -O2 -I.. -ansi -shared -o lib1.so lib1.c
+** Mac OS X: export MACOSX_DEPLOYMENT_TARGET=10.3
+** gcc -bundle -undefined dynamic_lookup -Wall -O2 -o lib1.so lib1.c
+*/
+
+
+#include "lua.h"
+
+
+int luaopen_lib1 (lua_State *L);
+
+int luaopen_lib11 (lua_State *L) {
+ return luaopen_lib1(L);
+}
+
+
diff --git a/test/PUC-Lua-5.1-tests/libs/lib2.c b/test/PUC-Lua-5.1-tests/libs/lib2.c
new file mode 100644
index 0000000..876a212
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/libs/lib2.c
@@ -0,0 +1,28 @@
+/*
+** compile with
+** gcc -Wall -O2 -I.. -ansi -shared -o lib1.so lib1.c
+*/
+
+
+#include "lua.h"
+#include "lauxlib.h"
+
+static int id (lua_State *L) {
+ return lua_gettop(L);
+}
+
+
+static const struct luaL_Reg funcs[] = {
+ {"id", id},
+ {NULL, NULL}
+};
+
+
+int luaopen_lib2 (lua_State *L) {
+ luaL_register(L, "lib2", funcs);
+ lua_pushnumber(L, 0.5);
+ lua_setglobal(L, "x");
+ return 1;
+}
+
+
diff --git a/test/PUC-Lua-5.1-tests/libs/lib21.c b/test/PUC-Lua-5.1-tests/libs/lib21.c
new file mode 100644
index 0000000..167507f
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/libs/lib21.c
@@ -0,0 +1,18 @@
+/*
+** compile with
+** Linux: gcc -Wall -O2 -I.. -ansi -shared -o lib1.so lib1.c
+** Mac OS X: export MACOSX_DEPLOYMENT_TARGET=10.3
+** gcc -bundle -undefined dynamic_lookup -Wall -O2 -o lib1.so lib1.c
+*/
+
+
+#include "lua.h"
+
+
+int luaopen_lib2 (lua_State *L);
+
+int luaopen_lib21 (lua_State *L) {
+ return luaopen_lib2(L);
+}
+
+
diff --git a/test/PUC-Lua-5.1-tests/literals.lua b/test/PUC-Lua-5.1-tests/literals.lua
new file mode 100644
index 0000000..01d84d5
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/literals.lua
@@ -0,0 +1,176 @@
+print('testing scanner')
+
+local function dostring (x) return assert(loadstring(x))() end
+
+dostring("x = 'a\0a'")
+assert(x == 'a\0a' and string.len(x) == 3)
+
+-- escape sequences
+assert('\n\"\'\\' == [[
+
+"'\]])
+
+assert(string.find("\a\b\f\n\r\t\v", "^%c%c%c%c%c%c%c$"))
+
+-- assume ASCII just for tests:
+assert("\09912" == 'c12')
+assert("\99ab" == 'cab')
+assert("\099" == '\99')
+assert("\099\n" == 'c\10')
+assert('\0\0\0alo' == '\0' .. '\0\0' .. 'alo')
+
+assert(010 .. 020 .. -030 == "1020-30")
+
+-- long variable names
+
+var = string.rep('a', 15000)
+prog = string.format("%s = 5", var)
+dostring(prog)
+assert(_G[var] == 5)
+var = nil
+print('+')
+
+-- escapes --
+assert("\n\t" == [[
+
+ ]])
+assert([[
+
+ $debug]] == "\n $debug")
+assert([[ [ ]] ~= [[ ] ]])
+-- long strings --
+b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
+assert(string.len(b) == 960)
+prog = [=[
+print('+')
+
+a1 = [["isto e' um string com várias 'aspas'"]]
+a2 = "'aspas'"
+
+assert(string.find(a1, a2) == 31)
+print('+')
+
+a1 = [==[temp = [[um valor qualquer]]; ]==]
+assert(loadstring(a1))()
+assert(temp == 'um valor qualquer')
+-- long strings --
+b = "001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789001234567890123456789012345678901234567891234567890123456789012345678901234567890012345678901234567890123456789012345678912345678901234567890123456789012345678900123456789012345678901234567890123456789123456789012345678901234567890123456789"
+assert(string.len(b) == 960)
+print('+')
+
+a = [[00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+00123456789012345678901234567890123456789123456789012345678901234567890123456789
+]]
+assert(string.len(a) == 1863)
+assert(string.sub(a, 1, 40) == string.sub(b, 1, 40))
+x = 1
+]=]
+
+print('+')
+x = nil
+dostring(prog)
+assert(x)
+
+prog = nil
+a = nil
+b = nil
+
+
+-- testing line ends
+prog = [[
+a = 1 -- a comment
+b = 2
+
+
+x = [=[
+hi
+]=]
+y = "\
+hello\r\n\
+"
+return debug.getinfo(1).currentline
+]]
+
+for _, n in pairs{"\n", "\r", "\n\r", "\r\n"} do
+ local prog, nn = string.gsub(prog, "\n", n)
+ assert(dostring(prog) == nn)
+ assert(_G.x == "hi\n" and _G.y == "\nhello\r\n\n")
+end
+
+
+-- testing comments and strings with long brackets
+a = [==[]=]==]
+assert(a == "]=")
+
+a = [==[[===[[=[]]=][====[]]===]===]==]
+assert(a == "[===[[=[]]=][====[]]===]===")
+
+a = [====[[===[[=[]]=][====[]]===]===]====]
+assert(a == "[===[[=[]]=][====[]]===]===")
+
+a = [=[]]]]]]]]]=]
+assert(a == "]]]]]]]]")
+
+
+--[===[
+x y z [==[ blu foo
+]==
+]
+]=]==]
+error error]=]===]
+
+-- generate all strings of four of these chars
+local x = {"=", "[", "]", "\n"}
+local len = 4
+local function gen (c, n)
+ if n==0 then coroutine.yield(c)
+ else
+ for _, a in pairs(x) do
+ gen(c..a, n-1)
+ end
+ end
+end
+
+for s in coroutine.wrap(function () gen("", len) end) do
+ assert(s == loadstring("return [====[\n"..s.."]====]")())
+end
+
+
+-- testing decimal point locale
+if os.setlocale("pt_BR") or os.setlocale("ptb") then
+ assert(tonumber("3,4") == 3.4 and tonumber"3.4" == nil)
+ assert(assert(loadstring("return 3.4"))() == 3.4)
+ assert(assert(loadstring("return .4,3"))() == .4)
+ assert(assert(loadstring("return 4."))() == 4.)
+ assert(assert(loadstring("return 4.+.5"))() == 4.5)
+ local a,b = loadstring("return 4.5.")
+ assert(string.find(b, "'4%.5%.'"))
+ assert(os.setlocale("C"))
+else
+ (Message or print)(
+ '\a\n >>> pt_BR locale not available: skipping decimal point tests <<<\n\a')
+end
+
+
+print('OK')
diff --git a/test/PUC-Lua-5.1-tests/locals.lua b/test/PUC-Lua-5.1-tests/locals.lua
new file mode 100644
index 0000000..011645a
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/locals.lua
@@ -0,0 +1,127 @@
+print('testing local variables plus some extra stuff')
+
+do
+ local i = 10
+ do local i = 100; assert(i==100) end
+ do local i = 1000; assert(i==1000) end
+ assert(i == 10)
+ if i ~= 10 then
+ local i = 20
+ else
+ local i = 30
+ assert(i == 30)
+ end
+end
+
+
+
+f = nil
+
+local f
+x = 1
+
+a = nil
+loadstring('local a = {}')()
+assert(type(a) ~= 'table')
+
+function f (a)
+ local _1, _2, _3, _4, _5
+ local _6, _7, _8, _9, _10
+ local x = 3
+ local b = a
+ local c,d = a,b
+ if (d == b) then
+ local x = 'q'
+ x = b
+ assert(x == 2)
+ else
+ assert(nil)
+ end
+ assert(x == 3)
+ local f = 10
+end
+
+local b=10
+local a; repeat local b; a,b=1,2; assert(a+1==b); until a+b==3
+
+
+assert(x == 1)
+
+f(2)
+assert(type(f) == 'function')
+
+
+-- testing globals ;-)
+do
+ local f = {}
+ local _G = _G
+ for i=1,10 do f[i] = function (x) A=A+1; return A, _G.getfenv(x) end end
+ A=10; assert(f[1]() == 11)
+ for i=1,10 do assert(setfenv(f[i], {A=i}) == f[i]) end
+ assert(f[3]() == 4 and A == 11)
+ local a,b = f[8](1)
+ assert(b.A == 9)
+ a,b = f[8](0)
+ assert(b.A == 11) -- `real' global
+ local g
+ local function f () assert(setfenv(2, {a='10'}) == g) end
+ g = function () f(); _G.assert(_G.getfenv(1).a == '10') end
+ g(); assert(getfenv(g).a == '10')
+end
+
+-- test for global table of loaded chunks
+local function foo (s)
+ return loadstring(s)
+end
+
+assert(getfenv(foo("")) == _G)
+local a = {loadstring = loadstring}
+setfenv(foo, a)
+assert(getfenv(foo("")) == _G)
+setfenv(0, a) -- change global environment
+assert(getfenv(foo("")) == a)
+setfenv(0, _G)
+
+
+-- testing limits for special instructions
+
+local a
+local p = 4
+for i=2,31 do
+ for j=-3,3 do
+ assert(loadstring(string.format([[local a=%s;a=a+
+ %s;
+ assert(a
+ ==2^%s)]], j, p-j, i))) ()
+ assert(loadstring(string.format([[local a=%s;
+ a=a-%s;
+ assert(a==-2^%s)]], -j, p-j, i))) ()
+ assert(loadstring(string.format([[local a,b=0,%s;
+ a=b-%s;
+ assert(a==-2^%s)]], -j, p-j, i))) ()
+ end
+ p =2*p
+end
+
+print'+'
+
+
+if rawget(_G, "querytab") then
+ -- testing clearing of dead elements from tables
+ collectgarbage("stop") -- stop GC
+ local a = {[{}] = 4, [3] = 0, alo = 1,
+ a1234567890123456789012345678901234567890 = 10}
+
+ local t = querytab(a)
+
+ for k,_ in pairs(a) do a[k] = nil end
+ collectgarbage() -- restore GC and collect dead fiels in `a'
+ for i=0,t-1 do
+ local k = querytab(a, i)
+ assert(k == nil or type(k) == 'number' or k == 'alo')
+ end
+end
+
+print('OK')
+
+return 5,f
diff --git a/test/PUC-Lua-5.1-tests/main.lua b/test/PUC-Lua-5.1-tests/main.lua
new file mode 100644
index 0000000..f520896
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/main.lua
@@ -0,0 +1,159 @@
+# testing special comment on first line
+
+print ("testing lua.c options")
+
+assert(os.execute() ~= 0) -- machine has a system command
+
+prog = os.tmpname()
+otherprog = os.tmpname()
+out = os.tmpname()
+
+do
+ local i = 0
+ while arg[i] do i=i-1 end
+ progname = '"'..arg[i+1]..'"'
+end
+print(progname)
+
+local prepfile = function (s, p)
+ p = p or prog
+ io.output(p)
+ io.write(s)
+ assert(io.close())
+end
+
+function checkout (s)
+ io.input(out)
+ local t = io.read("*a")
+ io.input():close()
+ assert(os.remove(out))
+ if s ~= t then print(string.format("'%s' - '%s'\n", s, t)) end
+ assert(s == t)
+ return t
+end
+
+function auxrun (...)
+ local s = string.format(...)
+ s = string.gsub(s, "lua", progname, 1)
+ return os.execute(s)
+end
+
+function RUN (...)
+ assert(auxrun(...) == 0)
+end
+
+function NoRun (...)
+ print("\n(the next error is expected by the test)")
+ assert(auxrun(...) ~= 0)
+end
+
+-- test 2 files
+prepfile("print(1); a=2")
+prepfile("print(a)", otherprog)
+RUN("lua -l %s -l%s -lstring -l io %s > %s", prog, otherprog, otherprog, out)
+checkout("1\n2\n2\n")
+
+local a = [[
+ assert(table.getn(arg) == 3 and arg[1] == 'a' and
+ arg[2] == 'b' and arg[3] == 'c')
+ assert(arg[-1] == '--' and arg[-2] == "-e " and arg[-3] == %s)
+ assert(arg[4] == nil and arg[-4] == nil)
+ local a, b, c = ...
+ assert(... == 'a' and a == 'a' and b == 'b' and c == 'c')
+]]
+a = string.format(a, progname)
+prepfile(a)
+RUN('lua "-e " -- %s a b c', prog)
+
+prepfile"assert(arg==nil)"
+prepfile("assert(arg)", otherprog)
+RUN("lua -l%s - < %s", prog, otherprog)
+
+prepfile""
+RUN("lua - < %s > %s", prog, out)
+checkout("")
+
+-- test many arguments
+prepfile[[print(({...})[30])]]
+RUN("lua %s %s > %s", prog, string.rep(" a", 30), out)
+checkout("a\n")
+
+RUN([[lua "-eprint(1)" -ea=3 -e "print(a)" > %s]], out)
+checkout("1\n3\n")
+
+prepfile[[
+ print(
+1, a
+)
+]]
+RUN("lua - < %s > %s", prog, out)
+checkout("1\tnil\n")
+
+prepfile[[
+= (6*2-6) -- ===
+a
+= 10
+print(a)
+= a]]
+RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out)
+checkout("6\n10\n10\n\n")
+
+prepfile("a = [[b\nc\nd\ne]]\n=a")
+print(prog)
+RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out)
+checkout("b\nc\nd\ne\n\n")
+
+prompt = "alo"
+prepfile[[ --
+a = 2
+]]
+RUN([[lua "-e_PROMPT='%s'" -i < %s > %s]], prompt, prog, out)
+checkout(string.rep(prompt, 3).."\n")
+
+s = [=[ --
+function f ( x )
+ local a = [[
+xuxu
+]]
+ local b = "\
+xuxu\n"
+ if x == 11 then return 1 , 2 end --[[ test multiple returns ]]
+ return x + 1
+ --\\
+end
+=( f( 10 ) )
+assert( a == b )
+=f( 11 ) ]=]
+s = string.gsub(s, ' ', '\n\n')
+prepfile(s)
+RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out)
+checkout("11\n1\t2\n\n")
+
+prepfile[[#comment in 1st line without \n at the end]]
+RUN("lua %s", prog)
+
+prepfile("#comment with a binary file\n"..string.dump(loadstring("print(1)")))
+RUN("lua %s > %s", prog, out)
+checkout("1\n")
+
+prepfile("#comment with a binary file\r\n"..string.dump(loadstring("print(1)")))
+RUN("lua %s > %s", prog, out)
+checkout("1\n")
+
+-- close Lua with an open file
+prepfile(string.format([[io.output(%q); io.write('alo')]], out))
+RUN("lua %s", prog)
+checkout('alo')
+
+assert(os.remove(prog))
+assert(os.remove(otherprog))
+assert(not os.remove(out))
+
+RUN("lua -v")
+
+NoRun("lua -h")
+NoRun("lua -e")
+NoRun("lua -e a")
+NoRun("lua -f")
+
+print("OK")
diff --git a/test/PUC-Lua-5.1-tests/math.lua b/test/PUC-Lua-5.1-tests/math.lua
new file mode 100644
index 0000000..5076f38
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/math.lua
@@ -0,0 +1,208 @@
+print("testing numbers and math lib")
+
+do
+ local a,b,c = "2", " 3e0 ", " 10 "
+ assert(a+b == 5 and -b == -3 and b+"2" == 5 and "10"-c == 0)
+ assert(type(a) == 'string' and type(b) == 'string' and type(c) == 'string')
+ assert(a == "2" and b == " 3e0 " and c == " 10 " and -c == -" 10 ")
+ assert(c%a == 0 and a^b == 8)
+end
+
+
+do
+ local a,b = math.modf(3.5)
+ assert(a == 3 and b == 0.5)
+ assert(math.huge > 10e30)
+ assert(-math.huge < -10e30)
+end
+
+function f(...)
+ if select('#', ...) == 1 then
+ return (...)
+ else
+ return "***"
+ end
+end
+
+assert(tonumber{} == nil)
+assert(tonumber'+0.01' == 1/100 and tonumber'+.01' == 0.01 and
+ tonumber'.01' == 0.01 and tonumber'-1.' == -1 and
+ tonumber'+1.' == 1)
+assert(tonumber'+ 0.01' == nil and tonumber'+.e1' == nil and
+ tonumber'1e' == nil and tonumber'1.0e+' == nil and
+ tonumber'.' == nil)
+assert(tonumber('-12') == -10-2)
+assert(tonumber('-1.2e2') == - - -120)
+assert(f(tonumber('1 a')) == nil)
+assert(f(tonumber('e1')) == nil)
+assert(f(tonumber('e 1')) == nil)
+assert(f(tonumber(' 3.4.5 ')) == nil)
+assert(f(tonumber('')) == nil)
+assert(f(tonumber('', 8)) == nil)
+assert(f(tonumber(' ')) == nil)
+assert(f(tonumber(' ', 9)) == nil)
+assert(f(tonumber('99', 8)) == nil)
+assert(tonumber(' 1010 ', 2) == 10)
+assert(tonumber('10', 36) == 36)
+--assert(tonumber('\n -10 \n', 36) == -36)
+--assert(tonumber('-fFfa', 16) == -(10+(16*(15+(16*(15+(16*15)))))))
+assert(tonumber('fFfa', 15) == nil)
+--assert(tonumber(string.rep('1', 42), 2) + 1 == 2^42)
+assert(tonumber(string.rep('1', 32), 2) + 1 == 2^32)
+--assert(tonumber('-fffffFFFFF', 16)-1 == -2^40)
+assert(tonumber('ffffFFFF', 16)+1 == 2^32)
+
+assert(1.1 == 1.+.1)
+assert(100.0 == 1E2 and .01 == 1e-2)
+assert(1111111111111111-1111111111111110== 1000.00e-03)
+-- 1234567890123456
+assert(1.1 == '1.'+'.1')
+assert('1111111111111111'-'1111111111111110' == tonumber" +0.001e+3 \n\t")
+
+function eq (a,b,limit)
+ if not limit then limit = 10E-10 end
+ return math.abs(a-b) <= limit
+end
+
+assert(0.1e-30 > 0.9E-31 and 0.9E30 < 0.1e31)
+
+assert(0.123456 > 0.123455)
+
+assert(tonumber('+1.23E30') == 1.23*10^30)
+
+-- testing order operators
+assert(not(1<1) and (1<2) and not(2<1))
+assert(not('a'<'a') and ('a'<'b') and not('b'<'a'))
+assert((1<=1) and (1<=2) and not(2<=1))
+assert(('a'<='a') and ('a'<='b') and not('b'<='a'))
+assert(not(1>1) and not(1>2) and (2>1))
+assert(not('a'>'a') and not('a'>'b') and ('b'>'a'))
+assert((1>=1) and not(1>=2) and (2>=1))
+assert(('a'>='a') and not('a'>='b') and ('b'>='a'))
+
+-- testing mod operator
+assert(-4%3 == 2)
+assert(4%-3 == -2)
+assert(math.pi - math.pi % 1 == 3)
+assert(math.pi - math.pi % 0.001 == 3.141)
+
+local function testbit(a, n)
+ return a/2^n % 2 >= 1
+end
+
+assert(eq(math.sin(-9.8)^2 + math.cos(-9.8)^2, 1))
+assert(eq(math.tan(math.pi/4), 1))
+assert(eq(math.sin(math.pi/2), 1) and eq(math.cos(math.pi/2), 0))
+assert(eq(math.atan(1), math.pi/4) and eq(math.acos(0), math.pi/2) and
+ eq(math.asin(1), math.pi/2))
+assert(eq(math.deg(math.pi/2), 90) and eq(math.rad(90), math.pi/2))
+assert(math.abs(-10) == 10)
+assert(eq(math.atan2(1,0), math.pi/2))
+assert(math.ceil(4.5) == 5.0)
+assert(math.floor(4.5) == 4.0)
+assert(math.mod(10,3) == 1)
+assert(eq(math.sqrt(10)^2, 10))
+assert(eq(math.log10(2), math.log(2)/math.log(10)))
+assert(eq(math.exp(0), 1))
+assert(eq(math.sin(10), math.sin(10%(2*math.pi))))
+local v,e = math.frexp(math.pi)
+assert(eq(math.ldexp(v,e), math.pi))
+
+assert(eq(math.tanh(3.5), math.sinh(3.5)/math.cosh(3.5)))
+
+assert(tonumber(' 1.3e-2 ') == 1.3e-2)
+assert(tonumber(' -1.00000000000001 ') == -1.00000000000001)
+
+-- testing constant limits
+-- 2^23 = 8388608
+assert(8388609 + -8388609 == 0)
+assert(8388608 + -8388608 == 0)
+assert(8388607 + -8388607 == 0)
+
+if rawget(_G, "_soft") then return end
+
+f = io.tmpfile()
+assert(f)
+f:write("a = {")
+i = 1
+repeat
+ f:write("{", math.sin(i), ", ", math.cos(i), ", ", i/3, "},\n")
+ i=i+1
+until i > 1000
+f:write("}")
+f:seek("set", 0)
+assert(loadstring(f:read('*a')))()
+assert(f:close())
+
+assert(eq(a[300][1], math.sin(300)))
+assert(eq(a[600][1], math.sin(600)))
+assert(eq(a[500][2], math.cos(500)))
+assert(eq(a[800][2], math.cos(800)))
+assert(eq(a[200][3], 200/3))
+assert(eq(a[1000][3], 1000/3, 0.001))
+print('+')
+
+do -- testing NaN
+ local NaN = 10e500 - 10e400
+ assert(NaN ~= NaN)
+ assert(not (NaN < NaN))
+ assert(not (NaN <= NaN))
+ assert(not (NaN > NaN))
+ assert(not (NaN >= NaN))
+ assert(not (0 < NaN))
+ assert(not (NaN < 0))
+ local a = {}
+ assert(not pcall(function () a[NaN] = 1 end))
+ assert(a[NaN] == nil)
+ a[1] = 1
+ assert(not pcall(function () a[NaN] = 1 end))
+ assert(a[NaN] == nil)
+end
+
+require "checktable"
+stat(a)
+
+a = nil
+
+-- testing implicit convertions
+
+local a,b = '10', '20'
+assert(a*b == 200 and a+b == 30 and a-b == -10 and a/b == 0.5 and -b == -20)
+assert(a == '10' and b == '20')
+
+
+math.randomseed(0)
+
+local i = 0
+local Max = 0
+local Min = 2
+repeat
+ local t = math.random()
+ Max = math.max(Max, t)
+ Min = math.min(Min, t)
+ i=i+1
+ flag = eq(Max, 1, 0.001) and eq(Min, 0, 0.001)
+until flag or i>10000
+assert(0 <= Min and Max<1)
+assert(flag);
+
+for i=1,10 do
+ local t = math.random(5)
+ assert(1 <= t and t <= 5)
+end
+
+i = 0
+Max = -200
+Min = 200
+repeat
+ local t = math.random(-10,0)
+ Max = math.max(Max, t)
+ Min = math.min(Min, t)
+ i=i+1
+ flag = (Max == 0 and Min == -10)
+until flag or i>10000
+assert(-10 <= Min and Max<=0)
+assert(flag);
+
+
+print('OK')
diff --git a/test/PUC-Lua-5.1-tests/nextvar.lua b/test/PUC-Lua-5.1-tests/nextvar.lua
new file mode 100644
index 0000000..7ceaa75
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/nextvar.lua
@@ -0,0 +1,396 @@
+print('testing tables, next, and for')
+
+local a = {}
+
+-- make sure table has lots of space in hash part
+for i=1,100 do a[i.."+"] = true end
+for i=1,100 do a[i.."+"] = nil end
+-- fill hash part with numeric indices testing size operator
+for i=1,100 do
+ a[i] = true
+ assert(#a == i)
+end
+
+
+if T then
+-- testing table sizes
+
+local l2 = math.log(2)
+local function log2 (x) return math.log(x)/l2 end
+
+local function mp2 (n) -- minimum power of 2 >= n
+ local mp = 2^math.ceil(log2(n))
+ assert(n == 0 or (mp/2 < n and n <= mp))
+ return mp
+end
+
+local function fb (n)
+ local r, nn = T.int2fb(n)
+ assert(r < 256)
+ return nn
+end
+
+-- test fb function
+local a = 1
+local lim = 2^30
+while a < lim do
+ local n = fb(a)
+ assert(a <= n and n <= a*1.125)
+ a = math.ceil(a*1.3)
+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 constructor sizes
+local lim = 40
+local s = 'return {'
+for i=1,lim do
+ s = s..i..','
+ local s = s
+ for k=0,lim do
+ local t = loadstring(s..'}')()
+ assert(#t == i)
+ check(t, fb(i), mp2(k))
+ s = string.format('%sa%d=%d,', s, k, k)
+ end
+end
+
+
+-- tests with unknown number of elements
+local a = {}
+for i=1,lim do a[i] = i end -- build auxiliary table
+for k=0,lim do
+ local a = {unpack(a,1,k)}
+ assert(#a == k)
+ check(a, k, 0)
+ a = {1,2,3,unpack(a,1,k)}
+ check(a, k+3, 0)
+ assert(#a == k + 3)
+end
+
+
+print'+'
+
+-- testing tables dynamically built
+local lim = 130
+local a = {}; a[2] = 1; check(a, 0, 1)
+a = {}; a[0] = 1; check(a, 0, 1); a[2] = 1; check(a, 0, 2)
+a = {}; a[0] = 1; a[1] = 1; check(a, 1, 1)
+a = {}
+for i = 1,lim do
+ a[i] = 1
+ assert(#a == i)
+ check(a, mp2(i), 0)
+end
+
+a = {}
+for i = 1,lim do
+ a['a'..i] = 1
+ assert(#a == 0)
+ check(a, 0, mp2(i))
+end
+
+a = {}
+for i=1,16 do a[i] = i end
+check(a, 16, 0)
+for i=1,11 do a[i] = nil end
+for i=30,40 do a[i] = nil end -- force a rehash (?)
+check(a, 0, 8)
+a[10] = 1
+for i=30,40 do a[i] = nil end -- force a rehash (?)
+check(a, 0, 8)
+for i=1,14 do a[i] = nil end
+for i=30,50 do a[i] = nil end -- force a rehash (?)
+check(a, 0, 4)
+
+-- reverse filling
+for i=1,lim do
+ local a = {}
+ for i=i,1,-1 do a[i] = i end -- fill in reverse
+ check(a, mp2(i), 0)
+end
+
+-- size tests for vararg
+lim = 35
+function foo (n, ...)
+ local arg = {...}
+ check(arg, n, 0)
+ assert(select('#', ...) == n)
+ arg[n+1] = true
+ check(arg, mp2(n+1), 0)
+ arg.x = true
+ check(arg, mp2(n+1), 1)
+end
+local a = {}
+for i=1,lim do a[i] = true; foo(i, unpack(a)) end
+
+end
+
+
+-- test size operation on empty tables
+assert(#{} == 0)
+assert(#{nil} == 0)
+assert(#{nil, nil} == 0)
+assert(#{nil, nil, nil} == 0)
+assert(#{nil, nil, nil, nil} == 0)
+print'+'
+
+
+local nofind = {}
+
+a,b,c = 1,2,3
+a,b,c = nil
+
+local function find (name)
+ local n,v
+ while 1 do
+ n,v = next(_G, n)
+ if not n then return nofind end
+ assert(v ~= nil)
+ if n == name then return v end
+ end
+end
+
+local function find1 (name)
+ for n,v in pairs(_G) do
+ if n==name then return v end
+ end
+ return nil -- not found
+end
+
+do -- create 10000 new global variables
+ for i=1,10000 do _G[i] = i end
+end
+
+
+a = {x=90, y=8, z=23}
+assert(table.foreach(a, function(i,v) if i=='x' then return v end end) == 90)
+assert(table.foreach(a, function(i,v) if i=='a' then return v end end) == nil)
+table.foreach({}, error)
+
+table.foreachi({x=10, y=20}, error)
+local a = {n = 1}
+table.foreachi({n=3}, function (i, v)
+ assert(a.n == i and not v)
+ a.n=a.n+1
+end)
+a = {10,20,30,nil,50}
+table.foreachi(a, function (i,v) assert(a[i] == v) end)
+assert(table.foreachi({'a', 'b', 'c'}, function (i,v)
+ if i==2 then return v end
+ end) == 'b')
+
+
+assert(print==find("print") and print == find1("print"))
+assert(_G["print"]==find("print"))
+assert(assert==find1("assert"))
+assert(nofind==find("return"))
+assert(not find1("return"))
+_G["ret" .. "urn"] = nil
+assert(nofind==find("return"))
+_G["xxx"] = 1
+assert(xxx==find("xxx"))
+print('+')
+
+a = {}
+for i=0,10000 do
+ if math.mod(i,10) ~= 0 then
+ a['x'..i] = i
+ end
+end
+
+n = {n=0}
+for i,v in pairs(a) do
+ n.n = n.n+1
+ assert(i and v and a[i] == v)
+end
+assert(n.n == 9000)
+a = nil
+
+-- remove those 10000 new global variables
+for i=1,10000 do _G[i] = nil end
+
+do -- clear global table
+ local a = {}
+ local preserve = {io = 1, string = 1, debug = 1, os = 1,
+ coroutine = 1, table = 1, math = 1}
+ for n,v in pairs(_G) do a[n]=v end
+ for n,v in pairs(a) do
+ if not preserve[n] and type(v) ~= "function" and
+ not string.find(n, "^[%u_]") then
+ _G[n] = nil
+ end
+ collectgarbage()
+ end
+end
+
+local function foo ()
+ local getfenv, setfenv, assert, next =
+ getfenv, setfenv, assert, next
+ local n = {gl1=3}
+ setfenv(foo, n)
+ assert(getfenv(foo) == getfenv(1))
+ assert(getfenv(foo) == n)
+ assert(print == nil and gl1 == 3)
+ gl1 = nil
+ gl = 1
+ assert(n.gl == 1 and next(n, 'gl') == nil)
+end
+foo()
+
+print'+'
+
+local function checknext (a)
+ local b = {}
+ table.foreach(a, function (k,v) b[k] = v end)
+ for k,v in pairs(b) do assert(a[k] == v) end
+ for k,v in pairs(a) do assert(b[k] == v) end
+ b = {}
+ do local k,v = next(a); while k do b[k] = v; k,v = next(a,k) end end
+ for k,v in pairs(b) do assert(a[k] == v) end
+ for k,v in pairs(a) do assert(b[k] == v) end
+end
+
+checknext{1,x=1,y=2,z=3}
+checknext{1,2,x=1,y=2,z=3}
+checknext{1,2,3,x=1,y=2,z=3}
+checknext{1,2,3,4,x=1,y=2,z=3}
+checknext{1,2,3,4,5,x=1,y=2,z=3}
+
+assert(table.getn{} == 0)
+assert(table.getn{[-1] = 2} == 0)
+assert(table.getn{1,2,3,nil,nil} == 3)
+for i=0,40 do
+ local a = {}
+ for j=1,i do a[j]=j end
+ assert(table.getn(a) == i)
+end
+
+
+assert(table.maxn{} == 0)
+assert(table.maxn{["1000"] = true} == 0)
+assert(table.maxn{["1000"] = true, [24.5] = 3} == 24.5)
+assert(table.maxn{[1000] = true} == 1000)
+assert(table.maxn{[10] = true, [100*math.pi] = print} == 100*math.pi)
+
+
+-- int overflow
+a = {}
+for i=0,50 do a[math.pow(2,i)] = true end
+assert(a[table.getn(a)])
+
+print("+")
+
+
+-- erasing values
+local t = {[{1}] = 1, [{2}] = 2, [string.rep("x ", 4)] = 3,
+ [100.3] = 4, [4] = 5}
+
+local n = 0
+for k, v in pairs( t ) do
+ n = n+1
+ assert(t[k] == v)
+ t[k] = nil
+ collectgarbage()
+ assert(t[k] == nil)
+end
+assert(n == 5)
+
+
+local function test (a)
+ table.insert(a, 10); table.insert(a, 2, 20);
+ table.insert(a, 1, -1); table.insert(a, 40);
+ table.insert(a, table.getn(a)+1, 50)
+ table.insert(a, 2, -2)
+ assert(table.remove(a,1) == -1)
+ assert(table.remove(a,1) == -2)
+ assert(table.remove(a,1) == 10)
+ assert(table.remove(a,1) == 20)
+ assert(table.remove(a,1) == 40)
+ assert(table.remove(a,1) == 50)
+ assert(table.remove(a,1) == nil)
+end
+
+a = {n=0, [-7] = "ban"}
+test(a)
+assert(a.n == 0 and a[-7] == "ban")
+
+a = {[-7] = "ban"};
+test(a)
+assert(a.n == nil and table.getn(a) == 0 and a[-7] == "ban")
+
+
+table.insert(a, 1, 10); table.insert(a, 1, 20); table.insert(a, 1, -1)
+assert(table.remove(a) == 10)
+assert(table.remove(a) == 20)
+assert(table.remove(a) == -1)
+
+a = {'c', 'd'}
+table.insert(a, 3, 'a')
+table.insert(a, 'b')
+assert(table.remove(a, 1) == 'c')
+assert(table.remove(a, 1) == 'd')
+assert(table.remove(a, 1) == 'a')
+assert(table.remove(a, 1) == 'b')
+assert(table.getn(a) == 0 and a.n == nil)
+print("+")
+
+a = {}
+for i=1,1000 do
+ a[i] = i; a[i-1] = nil
+end
+assert(next(a,nil) == 1000 and next(a,1000) == nil)
+
+assert(next({}) == nil)
+assert(next({}, nil) == nil)
+
+for a,b in pairs{} do error"not here" end
+for i=1,0 do error'not here' end
+for i=0,1,-1 do error'not here' end
+a = nil; for i=1,1 do assert(not a); a=1 end; assert(a)
+a = nil; for i=1,1,-1 do assert(not a); a=1 end; assert(a)
+
+a = 0; for i=0, 1, 0.1 do a=a+1 end; assert(a==11)
+-- precision problems
+--a = 0; for i=1, 0, -0.01 do a=a+1 end; assert(a==101)
+a = 0; for i=0, 0.999999999, 0.1 do a=a+1 end; assert(a==10)
+a = 0; for i=1, 1, 1 do a=a+1 end; assert(a==1)
+a = 0; for i=1e10, 1e10, -1 do a=a+1 end; assert(a==1)
+a = 0; for i=1, 0.99999, 1 do a=a+1 end; assert(a==0)
+a = 0; for i=99999, 1e5, -1 do a=a+1 end; assert(a==0)
+a = 0; for i=1, 0.99999, -1 do a=a+1 end; assert(a==1)
+
+-- conversion
+a = 0; for i="10","1","-2" do a=a+1 end; assert(a==5)
+
+
+collectgarbage()
+
+
+-- testing generic 'for'
+
+local function f (n, p)
+ local t = {}; for i=1,p do t[i] = i*10 end
+ return function (_,n)
+ if n > 0 then
+ n = n-1
+ return n, unpack(t)
+ end
+ end, nil, n
+end
+
+local x = 0
+for n,a,b,c,d in f(5,3) do
+ x = x+1
+ assert(a == 10 and b == 20 and c == 30 and d == nil)
+end
+assert(x == 5)
+
+print"OK"
diff --git a/test/PUC-Lua-5.1-tests/pm.lua b/test/PUC-Lua-5.1-tests/pm.lua
new file mode 100644
index 0000000..fa125dc
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/pm.lua
@@ -0,0 +1,273 @@
+print('testing pattern matching')
+
+function f(s, p)
+ local i,e = string.find(s, p)
+ if i then return string.sub(s, i, e) end
+end
+
+function f1(s, p)
+ p = string.gsub(p, "%%([0-9])", function (s) return "%" .. (s+1) end)
+ p = string.gsub(p, "^(^?)", "%1()", 1)
+ p = string.gsub(p, "($?)$", "()%1", 1)
+ local t = {string.match(s, p)}
+ return string.sub(s, t[1], t[#t] - 1)
+end
+
+a,b = string.find('', '') -- empty patterns are tricky
+assert(a == 1 and b == 0);
+a,b = string.find('alo', '')
+assert(a == 1 and b == 0)
+a,b = string.find('a\0o a\0o a\0o', 'a', 1) -- first position
+assert(a == 1 and b == 1)
+a,b = string.find('a\0o a\0o a\0o', 'a\0o', 2) -- starts in the midle
+assert(a == 5 and b == 7)
+a,b = string.find('a\0o a\0o a\0o', 'a\0o', 9) -- starts in the midle
+assert(a == 9 and b == 11)
+a,b = string.find('a\0a\0a\0a\0\0ab', '\0ab', 2); -- finds at the end
+assert(a == 9 and b == 11);
+a,b = string.find('a\0a\0a\0a\0\0ab', 'b') -- last position
+assert(a == 11 and b == 11)
+assert(string.find('a\0a\0a\0a\0\0ab', 'b\0') == nil) -- check ending
+assert(string.find('', '\0') == nil)
+assert(string.find('alo123alo', '12') == 4)
+assert(string.find('alo123alo', '^12') == nil)
+
+assert(f('aloALO', '%l*') == 'alo')
+assert(f('aLo_ALO', '%a*') == 'aLo')
+
+assert(f('aaab', 'a*') == 'aaa');
+assert(f('aaa', '^.*$') == 'aaa');
+assert(f('aaa', 'b*') == '');
+assert(f('aaa', 'ab*a') == 'aa')
+assert(f('aba', 'ab*a') == 'aba')
+assert(f('aaab', 'a+') == 'aaa')
+assert(f('aaa', '^.+$') == 'aaa')
+assert(f('aaa', 'b+') == nil)
+assert(f('aaa', 'ab+a') == nil)
+assert(f('aba', 'ab+a') == 'aba')
+assert(f('a$a', '.$') == 'a')
+assert(f('a$a', '.%$') == 'a$')
+assert(f('a$a', '.$.') == 'a$a')
+assert(f('a$a', '$$') == nil)
+assert(f('a$b', 'a$') == nil)
+assert(f('a$a', '$') == '')
+assert(f('', 'b*') == '')
+assert(f('aaa', 'bb*') == nil)
+assert(f('aaab', 'a-') == '')
+assert(f('aaa', '^.-$') == 'aaa')
+assert(f('aabaaabaaabaaaba', 'b.*b') == 'baaabaaabaaab')
+assert(f('aabaaabaaabaaaba', 'b.-b') == 'baaab')
+assert(f('alo xo', '.o$') == 'xo')
+assert(f(' \n isto é assim', '%S%S*') == 'isto')
+assert(f(' \n isto é assim', '%S*$') == 'assim')
+assert(f(' \n isto é assim', '[a-z]*$') == 'assim')
+assert(f('um caracter ? extra', '[^%sa-z]') == '?')
+assert(f('', 'a?') == '')
+assert(f('á', 'á?') == 'á')
+assert(f('ábl', 'á?b?l?') == 'ábl')
+assert(f(' ábl', 'á?b?l?') == '')
+assert(f('aa', '^aa?a?a') == 'aa')
+assert(f(']]]áb', '[^]]') == 'á')
+assert(f("0alo alo", "%x*") == "0a")
+assert(f("alo alo", "%C+") == "alo alo")
+print('+')
+
+assert(f1('alo alx 123 b\0o b\0o', '(..*) %1') == "b\0o b\0o")
+assert(f1('axz123= 4= 4 34', '(.+)=(.*)=%2 %1') == '3= 4= 4 3')
+assert(f1('=======', '^(=*)=%1$') == '=======')
+assert(string.match('==========', '^([=]*)=%1$') == nil)
+
+local function range (i, j)
+ if i <= j then
+ return i, range(i+1, j)
+ end
+end
+
+local abc = string.char(range(0, 255));
+
+assert(string.len(abc) == 256)
+
+function strset (p)
+ local res = {s=''}
+ string.gsub(abc, p, function (c) res.s = res.s .. c end)
+ return res.s
+end;
+
+assert(string.len(strset('[\200-\210]')) == 11)
+
+assert(strset('[a-z]') == "abcdefghijklmnopqrstuvwxyz")
+assert(strset('[a-z%d]') == strset('[%da-uu-z]'))
+assert(strset('[a-]') == "-a")
+assert(strset('[^%W]') == strset('[%w]'))
+assert(strset('[]%%]') == '%]')
+assert(strset('[a%-z]') == '-az')
+assert(strset('[%^%[%-a%]%-b]') == '-[]^ab')
+assert(strset('%Z') == strset('[\1-\255]'))
+assert(strset('.') == strset('[\1-\255%z]'))
+print('+');
+
+assert(string.match("alo xyzK", "(%w+)K") == "xyz")
+assert(string.match("254 K", "(%d*)K") == "")
+assert(string.match("alo ", "(%w*)$") == "")
+assert(string.match("alo ", "(%w+)$") == nil)
+assert(string.find("(álo)", "%(á") == 1)
+local a, b, c, d, e = string.match("âlo alo", "^(((.).).* (%w*))$")
+assert(a == 'âlo alo' and b == 'âl' and c == 'â' and d == 'alo' and e == nil)
+a, b, c, d = string.match('0123456789', '(.+(.?)())')
+assert(a == '0123456789' and b == '' and c == 11 and d == nil)
+print('+')
+
+assert(string.gsub('ülo ülo', 'ü', 'x') == 'xlo xlo')
+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 \n 123\n ', '%s+', ' ') == 'alo alo 123 ')
+t = "abç d"
+a, b = string.gsub(t, '(.)', '%1@')
+assert('@'..a == string.gsub(t, '', '@') and b == 5)
+a, b = string.gsub('abçd', '(.)', '%0@', 2)
+assert(a == 'a@b@çd' and b == 2)
+assert(string.gsub('alo alo', '()[al]', '%1') == '12o 56o')
+assert(string.gsub("abc=xyz", "(%w*)(%p)(%w+)", "%3%2%1-%0") ==
+ "xyz=abc-abc=xyz")
+assert(string.gsub("abc", "%w", "%1%0") == "aabbcc")
+assert(string.gsub("abc", "%w+", "%0%1") == "abcabc")
+assert(string.gsub('áéí', '$', '\0óú') == 'áéí\0óú')
+assert(string.gsub('', '^', 'r') == 'r')
+assert(string.gsub('', '$', 'r') == 'r')
+print('+')
+
+assert(string.gsub("um (dois) tres (quatro)", "(%(%w+%))", string.upper) ==
+ "um (DOIS) tres (QUATRO)")
+
+do
+ local function setglobal (n,v) rawset(_G, n, v) end
+ string.gsub("a=roberto,roberto=a", "(%w+)=(%w%w*)", setglobal)
+ assert(_G.a=="roberto" and _G.roberto=="a")
+end
+
+function f(a,b) return string.gsub(a,'.',b) end
+assert(string.gsub("trocar tudo em |teste|b| é |beleza|al|", "|([^|]*)|([^|]*)|", f) ==
+ "trocar tudo em bbbbb é alalalalalal")
+
+local function dostring (s) return loadstring(s)() or "" end
+assert(string.gsub("alo $a=1$ novamente $return a$", "$([^$]*)%$", dostring) ==
+ "alo novamente 1")
+
+x = string.gsub("$x=string.gsub('alo', '.', string.upper)$ assim vai para $return x$",
+ "$([^$]*)%$", dostring)
+assert(x == ' assim vai para ALO')
+
+t = {}
+s = 'a alo jose joao'
+r = string.gsub(s, '()(%w+)()', function (a,w,b)
+ assert(string.len(w) == b-a);
+ t[a] = b-a;
+ end)
+assert(s == r and t[1] == 1 and t[3] == 3 and t[7] == 4 and t[13] == 4)
+
+
+function isbalanced (s)
+ return string.find(string.gsub(s, "%b()", ""), "[()]") == nil
+end
+
+assert(isbalanced("(9 ((8))(\0) 7) \0\0 a b ()(c)() a"))
+assert(not isbalanced("(9 ((8) 7) a b (\0 c) a"))
+assert(string.gsub("alo 'oi' alo", "%b''", '"') == 'alo " alo')
+
+
+local t = {"apple", "orange", "lime"; n=0}
+assert(string.gsub("x and x and x", "x", function () t.n=t.n+1; return t[t.n] end)
+ == "apple and orange and lime")
+
+t = {n=0}
+string.gsub("first second word", "%w%w*", function (w) t.n=t.n+1; t[t.n] = w end)
+assert(t[1] == "first" and t[2] == "second" and t[3] == "word" and t.n == 3)
+
+t = {n=0}
+assert(string.gsub("first second word", "%w+",
+ function (w) t.n=t.n+1; t[t.n] = w end, 2) == "first second word")
+assert(t[1] == "first" and t[2] == "second" and t[3] == nil)
+
+assert(not pcall(string.gsub, "alo", "(.", print))
+assert(not pcall(string.gsub, "alo", ".)", print))
+assert(not pcall(string.gsub, "alo", "(.", {}))
+assert(not pcall(string.gsub, "alo", "(.)", "%2"))
+assert(not pcall(string.gsub, "alo", "(%1)", "a"))
+assert(not pcall(string.gsub, "alo", "(%0)", "a"))
+
+-- big strings
+local a = string.rep('a', 300000)
+assert(string.find(a, '^a*.?$'))
+assert(not string.find(a, '^a*.?b$'))
+assert(string.find(a, '^a-.?$'))
+
+-- deep nest of gsubs
+function rev (s)
+ return string.gsub(s, "(.)(.+)", function (c,s1) return rev(s1)..c end)
+end
+
+local x = string.rep('012345', 10)
+assert(rev(rev(x)) == x)
+
+
+-- gsub with tables
+assert(string.gsub("alo alo", ".", {}) == "alo alo")
+assert(string.gsub("alo alo", "(.)", {a="AA", l=""}) == "AAo AAo")
+assert(string.gsub("alo alo", "(.).", {a="AA", l="K"}) == "AAo AAo")
+assert(string.gsub("alo alo", "((.)(.?))", {al="AA", o=false}) == "AAo AAo")
+
+assert(string.gsub("alo alo", "().", {2,5,6}) == "256 alo")
+
+t = {}; setmetatable(t, {__index = function (t,s) return string.upper(s) end})
+assert(string.gsub("a alo b hi", "%w%w+", t) == "a ALO b HI")
+
+
+-- tests for gmatch
+assert(string.gfind == string.gmatch)
+local a = 0
+for i in string.gmatch('abcde', '()') do assert(i == a+1); a=i end
+assert(a==6)
+
+t = {n=0}
+for w in string.gmatch("first second word", "%w+") do
+ t.n=t.n+1; t[t.n] = w
+end
+assert(t[1] == "first" and t[2] == "second" and t[3] == "word")
+
+t = {3, 6, 9}
+for i in string.gmatch ("xuxx uu ppar r", "()(.)%2") do
+ assert(i == table.remove(t, 1))
+end
+assert(table.getn(t) == 0)
+
+t = {}
+for i,j in string.gmatch("13 14 10 = 11, 15= 16, 22=23", "(%d+)%s*=%s*(%d+)") do
+ t[i] = j
+end
+a = 0
+for k,v in pairs(t) do assert(k+1 == v+0); a=a+1 end
+assert(a == 3)
+
+
+-- tests for `%f' (`frontiers')
+
+assert(string.gsub("aaa aa a aaa a", "%f[%w]a", "x") == "xaa xa x xaa x")
+assert(string.gsub("[[]] [][] [[[[", "%f[[].", "x") == "x[]] x]x] x[[[")
+assert(string.gsub("01abc45de3", "%f[%d]", ".") == ".01abc.45de.3")
+assert(string.gsub("01abc45 de3x", "%f[%D]%w", ".") == "01.bc45 de3.")
+assert(string.gsub("function", "%f[\1-\255]%w", ".") == ".unction")
+assert(string.gsub("function", "%f[^\1-\255]", ".") == "function.")
+
+local i, e = string.find(" alo aalo allo", "%f[%S].-%f[%s].-%f[%S]")
+assert(i == 2 and e == 5)
+local k = string.match(" alo aalo allo", "%f[%S](.-%f[%s].-%f[%S])")
+assert(k == 'alo ')
+
+local a = {1, 5, 9, 14, 17,}
+for k in string.gmatch("alo alo th02 is 1hat", "()%f[%w%d]") do
+ assert(table.remove(a, 1) == k)
+end
+assert(table.getn(a) == 0)
+
+
+print('OK')
diff --git a/test/PUC-Lua-5.1-tests/sort.lua b/test/PUC-Lua-5.1-tests/sort.lua
new file mode 100644
index 0000000..6fccd49
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/sort.lua
@@ -0,0 +1,74 @@
+print"testing sort"
+
+
+function check (a, f)
+ f = f or function (x,y) return x<y end;
+ for n=table.getn(a),2,-1 do
+ assert(not f(a[n], a[n-1]))
+ end
+end
+
+a = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
+ "Oct", "Nov", "Dec"}
+
+table.sort(a)
+check(a)
+
+limit = 30000
+if rawget(_G, "_soft") then limit = 5000 end
+
+a = {}
+for i=1,limit do
+ a[i] = math.random()
+end
+
+local x = os.clock()
+table.sort(a)
+print(string.format("Sorting %d elements in %.2f sec.", limit, os.clock()-x))
+check(a)
+
+x = os.clock()
+table.sort(a)
+print(string.format("Re-sorting %d elements in %.2f sec.", limit, os.clock()-x))
+check(a)
+
+a = {}
+for i=1,limit do
+ a[i] = math.random()
+end
+
+x = os.clock(); i=0
+table.sort(a, function(x,y) i=i+1; return y<x end)
+print(string.format("Invert-sorting other %d elements in %.2f sec., with %i comparisons",
+ limit, os.clock()-x, i))
+check(a, function(x,y) return y<x end)
+
+
+table.sort{} -- empty array
+
+for i=1,limit do a[i] = false end
+x = os.clock();
+table.sort(a, function(x,y) return nil end)
+print(string.format("Sorting %d equal elements in %.2f sec.", limit, os.clock()-x))
+check(a, function(x,y) return nil end)
+for i,v in pairs(a) do assert(not v or i=='n' and v==limit) end
+
+a = {"álo", "\0first :-)", "alo", "then this one", "45", "and a new"}
+table.sort(a)
+check(a)
+
+table.sort(a, function (x, y)
+ loadstring(string.format("a[%q] = ''", x))()
+ collectgarbage()
+ return x<y
+ end)
+
+
+tt = {__lt = function (a,b) return a.val < b.val end}
+a = {}
+for i=1,10 do a[i] = {val=math.random(100)}; setmetatable(a[i], tt); end
+table.sort(a)
+check(a, tt.__lt)
+check(a)
+
+print"OK"
diff --git a/test/PUC-Lua-5.1-tests/strings.lua b/test/PUC-Lua-5.1-tests/strings.lua
new file mode 100644
index 0000000..237dbad
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/strings.lua
@@ -0,0 +1,176 @@
+print('testing strings and string library')
+
+assert('alo' < 'alo1')
+assert('' < 'a')
+assert('alo\0alo' < 'alo\0b')
+assert('alo\0alo\0\0' > 'alo\0alo\0')
+assert('alo' < 'alo\0')
+assert('alo\0' > 'alo')
+assert('\0' < '\1')
+assert('\0\0' < '\0\1')
+assert('\1\0a\0a' <= '\1\0a\0a')
+assert(not ('\1\0a\0b' <= '\1\0a\0a'))
+assert('\0\0\0' < '\0\0\0\0')
+assert(not('\0\0\0\0' < '\0\0\0'))
+assert('\0\0\0' <= '\0\0\0\0')
+assert(not('\0\0\0\0' <= '\0\0\0'))
+assert('\0\0\0' <= '\0\0\0')
+assert('\0\0\0' >= '\0\0\0')
+assert(not ('\0\0b' < '\0\0a\0'))
+print('+')
+
+assert(string.sub("123456789",2,4) == "234")
+assert(string.sub("123456789",7) == "789")
+assert(string.sub("123456789",7,6) == "")
+assert(string.sub("123456789",7,7) == "7")
+assert(string.sub("123456789",0,0) == "")
+assert(string.sub("123456789",-10,10) == "123456789")
+assert(string.sub("123456789",1,9) == "123456789")
+assert(string.sub("123456789",-10,-20) == "")
+assert(string.sub("123456789",-1) == "9")
+assert(string.sub("123456789",-4) == "6789")
+assert(string.sub("123456789",-6, -4) == "456")
+assert(string.sub("\000123456789",3,5) == "234")
+assert(("\000123456789"):sub(8) == "789")
+print('+')
+
+assert(string.find("123456789", "345") == 3)
+a,b = string.find("123456789", "345")
+assert(string.sub("123456789", a, b) == "345")
+assert(string.find("1234567890123456789", "345", 3) == 3)
+assert(string.find("1234567890123456789", "345", 4) == 13)
+assert(string.find("1234567890123456789", "346", 4) == nil)
+assert(string.find("1234567890123456789", ".45", -9) == 13)
+assert(string.find("abcdefg", "\0", 5, 1) == nil)
+assert(string.find("", "") == 1)
+assert(string.find('', 'aaa', 1) == nil)
+assert(('alo(.)alo'):find('(.)', 1, 1) == 4)
+print('+')
+
+assert(string.len("") == 0)
+assert(string.len("\0\0\0") == 3)
+assert(string.len("1234567890") == 10)
+
+assert(#"" == 0)
+assert(#"\0\0\0" == 3)
+assert(#"1234567890" == 10)
+
+assert(string.byte("a") == 97)
+assert(string.byte("á") > 127)
+assert(string.byte(string.char(255)) == 255)
+assert(string.byte(string.char(0)) == 0)
+assert(string.byte("\0") == 0)
+assert(string.byte("\0\0alo\0x", -1) == string.byte('x'))
+assert(string.byte("ba", 2) == 97)
+assert(string.byte("\n\n", 2, -1) == 10)
+assert(string.byte("\n\n", 2, 2) == 10)
+assert(string.byte("") == nil)
+assert(string.byte("hi", -3) == nil)
+assert(string.byte("hi", 3) == nil)
+assert(string.byte("hi", 9, 10) == nil)
+assert(string.byte("hi", 2, 1) == nil)
+assert(string.char() == "")
+assert(string.char(0, 255, 0) == "\0\255\0")
+assert(string.char(0, string.byte("á"), 0) == "\0á\0")
+assert(string.char(string.byte("ál\0óu", 1, -1)) == "ál\0óu")
+assert(string.char(string.byte("ál\0óu", 1, 0)) == "")
+assert(string.char(string.byte("ál\0óu", -10, 100)) == "ál\0óu")
+print('+')
+
+assert(string.upper("ab\0c") == "AB\0C")
+assert(string.lower("\0ABCc%$") == "\0abcc%$")
+assert(string.rep('teste', 0) == '')
+assert(string.rep('tés\00tê', 2) == 'tés\0têtés\000tê')
+assert(string.rep('', 10) == '')
+
+assert(string.reverse"" == "")
+assert(string.reverse"\0\1\2\3" == "\3\2\1\0")
+assert(string.reverse"\0001234" == "4321\0")
+
+for i=0,30 do assert(string.len(string.rep('a', i)) == i) end
+
+assert(type(tostring(nil)) == 'string')
+assert(type(tostring(12)) == 'string')
+assert(''..12 == '12' and type(12 .. '') == 'string')
+assert(string.find(tostring{}, 'table:'))
+assert(string.find(tostring(print), 'function:'))
+assert(tostring(1234567890123) == '1234567890123')
+assert(#tostring('\0') == 1)
+assert(tostring(true) == "true")
+assert(tostring(false) == "false")
+print('+')
+
+x = '"ílo"\n\\'
+assert(string.format('%q%s', x, x) == '"\\"ílo\\"\\\n\\\\""ílo"\n\\')
+assert(string.format('%q', "\0") == [["\000"]])
+assert(string.format("\0%c\0%c%x\0", string.byte("á"), string.byte("b"), 140) ==
+ "\0á\0b8c\0")
+assert(string.format('') == "")
+assert(string.format("%c",34)..string.format("%c",48)..string.format("%c",90)..string.format("%c",100) ==
+ string.format("%c%c%c%c", 34, 48, 90, 100))
+assert(string.format("%s\0 is not \0%s", 'not be', 'be') == 'not be\0 is not \0be')
+assert(string.format("%%%d %010d", 10, 23) == "%10 0000000023")
+assert(tonumber(string.format("%f", 10.3)) == 10.3)
+x = string.format('"%-50s"', 'a')
+assert(#x == 52)
+assert(string.sub(x, 1, 4) == '"a ')
+
+assert(string.format("-%.20s.20s", string.rep("%", 2000)) == "-"..string.rep("%", 20)..".20s")
+assert(string.format('"-%20s.20s"', string.rep("%", 2000)) ==
+ string.format("%q", "-"..string.rep("%", 2000)..".20s"))
+
+
+-- longest number that can be formated
+assert(string.len(string.format('%99.99f', -1e308)) >= 100)
+
+assert(loadstring("return 1\n--comentário sem EOL no final")() == 1)
+
+
+assert(table.concat{} == "")
+assert(table.concat({}, 'x') == "")
+assert(table.concat({'\0', '\0\1', '\0\1\2'}, '.\0.') == "\0.\0.\0\1.\0.\0\1\2")
+local a = {}; for i=1,3000 do a[i] = "xuxu" end
+assert(table.concat(a, "123").."123" == string.rep("xuxu123", 3000))
+assert(table.concat(a, "b", 20, 20) == "xuxu")
+assert(table.concat(a, "", 20, 21) == "xuxuxuxu")
+assert(table.concat(a, "", 22, 21) == "")
+assert(table.concat(a, "3", 2999) == "xuxu3xuxu")
+
+a = {"a","b","c"}
+assert(table.concat(a, ",", 1, 0) == "")
+assert(table.concat(a, ",", 1, 1) == "a")
+assert(table.concat(a, ",", 1, 2) == "a,b")
+assert(table.concat(a, ",", 2) == "b,c")
+assert(table.concat(a, ",", 3) == "c")
+assert(table.concat(a, ",", 4) == "")
+
+local locales = { "ptb", "ISO-8859-1", "pt_BR" }
+local function trylocale (w)
+ for _, l in ipairs(locales) do
+ if os.setlocale(l, w) then return true end
+ end
+ return false
+end
+
+if not trylocale("collate") then
+ print("locale not supported")
+else
+ assert("alo" < "álo" and "álo" < "amo")
+end
+
+if not trylocale("ctype") then
+ print("locale not supported")
+else
+ assert(string.gsub("áéíóú", "%a", "x") == "xxxxx")
+ assert(string.gsub("áÁéÉ", "%l", "x") == "xÁxÉ")
+ assert(string.gsub("áÁéÉ", "%u", "x") == "áxéx")
+ assert(string.upper"áÁé{xuxu}ção" == "ÁÁÉ{XUXU}ÇÃO")
+end
+
+os.setlocale("C")
+assert(os.setlocale() == 'C')
+assert(os.setlocale(nil, "numeric") == 'C')
+
+print('OK')
+
+
diff --git a/test/PUC-Lua-5.1-tests/vararg.lua b/test/PUC-Lua-5.1-tests/vararg.lua
new file mode 100644
index 0000000..ae068fa
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/vararg.lua
@@ -0,0 +1,126 @@
+print('testing vararg')
+
+_G.arg = nil
+
+function f(a, ...)
+ assert(type(arg) == 'table')
+ assert(type(arg.n) == 'number')
+ for i=1,arg.n do assert(a[i]==arg[i]) end
+ return arg.n
+end
+
+function c12 (...)
+ assert(arg == nil)
+ local x = {...}; x.n = table.getn(x)
+ local res = (x.n==2 and x[1] == 1 and x[2] == 2)
+ if res then res = 55 end
+ return res, 2
+end
+
+function vararg (...) return arg end
+
+local call = function (f, args) return f(unpack(args, 1, args.n)) end
+
+assert(f() == 0)
+assert(f({1,2,3}, 1, 2, 3) == 3)
+assert(f({"alo", nil, 45, f, nil}, "alo", nil, 45, f, nil) == 5)
+
+assert(c12(1,2)==55)
+a,b = assert(call(c12, {1,2}))
+assert(a == 55 and b == 2)
+a = call(c12, {1,2;n=2})
+assert(a == 55 and b == 2)
+a = call(c12, {1,2;n=1})
+assert(not a)
+assert(c12(1,2,3) == false)
+local a = vararg(call(next, {_G,nil;n=2}))
+local b,c = next(_G)
+assert(a[1] == b and a[2] == c and a.n == 2)
+a = vararg(call(call, {c12, {1,2}}))
+assert(a.n == 2 and a[1] == 55 and a[2] == 2)
+a = call(print, {'+'})
+assert(a == nil)
+
+local t = {1, 10}
+function t:f (...) return self[arg[1]]+arg.n end
+assert(t:f(1,4) == 3 and t:f(2) == 11)
+print('+')
+
+lim = 20
+local i, a = 1, {}
+while i <= lim do a[i] = i+0.3; i=i+1 end
+
+function f(a, b, c, d, ...)
+ local more = {...}
+ assert(a == 1.3 and more[1] == 5.3 and
+ more[lim-4] == lim+0.3 and not more[lim-3])
+end
+
+function g(a,b,c)
+ assert(a == 1.3 and b == 2.3 and c == 3.3)
+end
+
+call(f, a)
+call(g, a)
+
+a = {}
+i = 1
+while i <= lim do a[i] = i; i=i+1 end
+assert(call(math.max, a) == lim)
+
+print("+")
+
+
+-- new-style varargs
+
+function oneless (a, ...) return ... end
+
+function f (n, a, ...)
+ local b
+ assert(arg == nil)
+ if n == 0 then
+ local b, c, d = ...
+ return a, b, c, d, oneless(oneless(oneless(...)))
+ else
+ n, b, a = n-1, ..., a
+ assert(b == ...)
+ return f(n, a, ...)
+ end
+end
+
+a,b,c,d,e = assert(f(10,5,4,3,2,1))
+assert(a==5 and b==4 and c==3 and d==2 and e==1)
+
+a,b,c,d,e = f(4)
+assert(a==nil and b==nil and c==nil and d==nil and e==nil)
+
+
+-- varargs for main chunks
+f = loadstring[[ return {...} ]]
+x = f(2,3)
+assert(x[1] == 2 and x[2] == 3 and x[3] == nil)
+
+
+f = loadstring[[
+ local x = {...}
+ for i=1,select('#', ...) do assert(x[i] == select(i, ...)) end
+ assert(x[select('#', ...)+1] == nil)
+ return true
+]]
+
+assert(f("a", "b", nil, {}, assert))
+assert(f())
+
+a = {select(3, unpack{10,20,30,40})}
+assert(table.getn(a) == 2 and a[1] == 30 and a[2] == 40)
+a = {select(1)}
+assert(next(a) == nil)
+a = {select(-1, 3, 5, 7)}
+assert(a[1] == 7 and a[2] == nil)
+a = {select(-2, 3, 5, 7)}
+assert(a[1] == 5 and a[2] == 7 and a[3] == nil)
+pcall(select, 10000)
+pcall(select, -10000)
+
+print('OK')
+
diff --git a/test/PUC-Lua-5.1-tests/verybig.lua b/test/PUC-Lua-5.1-tests/verybig.lua
new file mode 100644
index 0000000..59e0142
--- /dev/null
+++ b/test/PUC-Lua-5.1-tests/verybig.lua
@@ -0,0 +1,100 @@
+if rawget(_G, "_soft") then return 10 end
+
+print "testing large programs (>64k)"
+
+-- template to create a very big test file
+prog = [[$
+
+local a,b
+
+b = {$1$
+ b30009 = 65534,
+ b30010 = 65535,
+ b30011 = 65536,
+ b30012 = 65537,
+ b30013 = 16777214,
+ b30014 = 16777215,
+ b30015 = 16777216,
+ b30016 = 16777217,
+ b30017 = 4294967294,
+ b30018 = 4294967295,
+ b30019 = 4294967296,
+ b30020 = 4294967297,
+ b30021 = -65534,
+ b30022 = -65535,
+ b30023 = -65536,
+ b30024 = -4294967297,
+ b30025 = 15012.5,
+ $2$
+};
+
+assert(b.a50008 == 25004 and b["a11"] == 5.5)
+assert(b.a33007 == 16503.5 and b.a50009 == 25004.5)
+assert(b["b"..30024] == -4294967297)
+
+function b:xxx (a,b) return a+b end
+assert(b:xxx(10, 12) == 22) -- pushself with non-constant index
+b.xxx = nil
+
+s = 0; n=0
+for a,b in pairs(b) do s=s+b; n=n+1 end
+assert(s==13977183656.5 and n==70001)
+
+require "checktable"
+stat(b)
+
+a = nil; b = nil
+print'+'
+
+function f(x) b=x end
+
+a = f{$3$} or 10
+
+assert(a==10)
+assert(b[1] == "a10" and b[2] == 5 and b[table.getn(b)-1] == "a50009")
+
+
+function xxxx (x) return b[x] end
+
+assert(xxxx(3) == "a11")
+
+a = nil; b=nil
+xxxx = nil
+
+return 10
+
+]]
+
+-- functions to fill in the $n$
+F = {
+function () -- $1$
+ for i=10,50009 do
+ io.write('a', i, ' = ', 5+((i-10)/2), ',\n')
+ end
+end,
+
+function () -- $2$
+ for i=30026,50009 do
+ io.write('b', i, ' = ', 15013+((i-30026)/2), ',\n')
+ end
+end,
+
+function () -- $3$
+ for i=10,50009 do
+ io.write('"a', i, '", ', 5+((i-10)/2), ',\n')
+ end
+end,
+}
+
+file = os.tmpname()
+io.output(file)
+for s in string.gmatch(prog, "$([^$]+)") do
+ local n = tonumber(s)
+ if not n then io.write(s) else F[n]() end
+end
+io.close()
+result = dofile(file)
+assert(os.remove(file))
+print'OK'
+return result
+
--
2.28.0
^ permalink raw reply [flat|nested] 26+ messages in thread
* [Tarantool-patches] [WIP luajit 04/15] test: add LuaJIT-test-cleanup test suite
2021-03-04 10:23 [Tarantool-patches] [WIP luajit 00/15] Adapt LuaVela test suites Sergey Kaplun via Tarantool-patches
` (2 preceding siblings ...)
2021-03-04 10:23 ` [Tarantool-patches] [WIP luajit 03/15] test: adapt Lua 5.1 test suite for Tarantool Sergey Kaplun via Tarantool-patches
@ 2021-03-04 10:23 ` Sergey Kaplun via Tarantool-patches
2021-03-04 10:23 ` [Tarantool-patches] [WIP luajit 05/15] test: change tests to match de5568e Sergey Kaplun via Tarantool-patches
` (12 subsequent siblings)
16 siblings, 0 replies; 26+ messages in thread
From: Sergey Kaplun via Tarantool-patches @ 2021-03-04 10:23 UTC (permalink / raw)
To: Sergey Ostanevich, Igor Munkin; +Cc: tarantool-patches
This patch adds LuaJIT-test-cleanup test suite:
https://github.com/LuaJIT/LuaJIT-test-cleanup
Some tests may fail after this commit. They will be disabled
or adapted in the next patches.
Part of tarantool/tarantool#4064
Part of tarantool/tarantool#4473
---
Mergen Imeev <imeevma@gmail.com>: Author
Sergey Kaplun <skaplun@tarantool.org>: glanced commit message, made
commit consistence with the tarantool branch.
.luacheckrc | 1 +
test/CMakeLists.txt | 2 +
test/LuaJIT-tests/CMakeLists.txt | 20 +
test/LuaJIT-tests/README.md | 110 +++
test/LuaJIT-tests/bc/constov.lua | 16 +
test/LuaJIT-tests/bc/index | 1 +
test/LuaJIT-tests/common/expect_error.lua | 16 +
test/LuaJIT-tests/common/ffi_util.inc | 41 +
.../common/test_runner_canary.lua | 1 +
test/LuaJIT-tests/computations.lua | 113 +++
test/LuaJIT-tests/index | 6 +
test/LuaJIT-tests/lang/andor.lua | 61 ++
test/LuaJIT-tests/lang/assignment.lua | 46 +
test/LuaJIT-tests/lang/compare.lua | 323 +++++++
test/LuaJIT-tests/lang/compare_nan.lua | 99 +++
test/LuaJIT-tests/lang/concat.lua | 112 +++
test/LuaJIT-tests/lang/constant/index | 2 +
test/LuaJIT-tests/lang/constant/number.lua | 12 +
test/LuaJIT-tests/lang/constant/table.lua | 15 +
test/LuaJIT-tests/lang/coroutine.lua | 8 +
test/LuaJIT-tests/lang/for.lua | 45 +
test/LuaJIT-tests/lang/gc.lua | 42 +
test/LuaJIT-tests/lang/goto.lua | 149 ++++
test/LuaJIT-tests/lang/index | 18 +
test/LuaJIT-tests/lang/length.lua | 23 +
test/LuaJIT-tests/lang/meta/arith.lua | 118 +++
test/LuaJIT-tests/lang/meta/arith_jit.lua | 68 ++
test/LuaJIT-tests/lang/meta/call.lua | 81 ++
test/LuaJIT-tests/lang/meta/cat.lua | 61 ++
test/LuaJIT-tests/lang/meta/comp.lua | 120 +++
test/LuaJIT-tests/lang/meta/comp_jit.lua | 104 +++
test/LuaJIT-tests/lang/meta/debuginfo.lua | 81 ++
test/LuaJIT-tests/lang/meta/eq.lua | 30 +
test/LuaJIT-tests/lang/meta/eq_jit.lua | 35 +
test/LuaJIT-tests/lang/meta/framegap.lua | 24 +
test/LuaJIT-tests/lang/meta/index | 14 +
test/LuaJIT-tests/lang/meta/index.lua | 60 ++
test/LuaJIT-tests/lang/meta/len.lua | 42 +
test/LuaJIT-tests/lang/meta/newindex.lua | 69 ++
test/LuaJIT-tests/lang/meta/nomm.lua | 21 +
test/LuaJIT-tests/lang/modulo.lua | 46 +
test/LuaJIT-tests/lang/self.lua | 19 +
test/LuaJIT-tests/lang/table.lua | 32 +
test/LuaJIT-tests/lang/tail_recursion.lua | 20 +
test/LuaJIT-tests/lang/upvalue/closure.lua | 84 ++
test/LuaJIT-tests/lang/upvalue/index | 1 +
test/LuaJIT-tests/lang/vararg_jit.lua | 95 +++
test/LuaJIT-tests/lib/base/assert.lua | 33 +
test/LuaJIT-tests/lib/base/error.lua | 43 +
test/LuaJIT-tests/lib/base/getfenv.lua | 13 +
.../LuaJIT-tests/lib/base/getsetmetatable.lua | 33 +
test/LuaJIT-tests/lib/base/index | 11 +
test/LuaJIT-tests/lib/base/ipairs.lua | 41 +
test/LuaJIT-tests/lib/base/next.lua | 17 +
test/LuaJIT-tests/lib/base/pairs.lua | 73 ++
test/LuaJIT-tests/lib/base/pcall_jit.lua | 74 ++
test/LuaJIT-tests/lib/base/select.lua | 105 +++
.../lib/base/tonumber_tostring.lua | 81 ++
test/LuaJIT-tests/lib/base/xpcall_jit.lua | 83 ++
test/LuaJIT-tests/lib/bit.lua | 98 +++
test/LuaJIT-tests/lib/contents.lua | 155 ++++
test/LuaJIT-tests/lib/coroutine/index | 1 +
test/LuaJIT-tests/lib/coroutine/yield.lua | 109 +++
test/LuaJIT-tests/lib/ffi/bit64.lua | 130 +++
test/LuaJIT-tests/lib/ffi/cdata_var.lua | 47 ++
test/LuaJIT-tests/lib/ffi/copy_fill.lua | 64 ++
test/LuaJIT-tests/lib/ffi/err.lua | 35 +
test/LuaJIT-tests/lib/ffi/ffi_arith_ptr.lua | 106 +++
test/LuaJIT-tests/lib/ffi/ffi_bitfield.lua | 108 +++
test/LuaJIT-tests/lib/ffi/ffi_call.lua | 266 ++++++
test/LuaJIT-tests/lib/ffi/ffi_callback.lua | 158 ++++
test/LuaJIT-tests/lib/ffi/ffi_const.lua | 113 +++
test/LuaJIT-tests/lib/ffi/ffi_convert.lua | 787 ++++++++++++++++++
test/LuaJIT-tests/lib/ffi/ffi_enum.lua | 57 ++
.../lib/ffi/ffi_gcstep_recursive.lua | 66 ++
test/LuaJIT-tests/lib/ffi/ffi_jit_arith.lua | 155 ++++
test/LuaJIT-tests/lib/ffi/ffi_jit_call.lua | 154 ++++
test/LuaJIT-tests/lib/ffi/ffi_jit_conv.lua | 277 ++++++
test/LuaJIT-tests/lib/ffi/ffi_lex_number.lua | 51 ++
test/LuaJIT-tests/lib/ffi/ffi_metatype.lua | 245 ++++++
test/LuaJIT-tests/lib/ffi/ffi_new.lua | 106 +++
test/LuaJIT-tests/lib/ffi/ffi_parse_array.lua | 78 ++
test/LuaJIT-tests/lib/ffi/ffi_parse_basic.lua | 131 +++
test/LuaJIT-tests/lib/ffi/ffi_parse_cdef.lua | 77 ++
.../LuaJIT-tests/lib/ffi/ffi_parse_struct.lua | 259 ++++++
test/LuaJIT-tests/lib/ffi/ffi_tabov.lua | 12 +
test/LuaJIT-tests/lib/ffi/index | 12 +
test/LuaJIT-tests/lib/ffi/istype.lua | 88 ++
test/LuaJIT-tests/lib/ffi/jit_array.lua | 104 +++
test/LuaJIT-tests/lib/ffi/jit_complex.lua | 109 +++
test/LuaJIT-tests/lib/ffi/jit_misc.lua | 109 +++
test/LuaJIT-tests/lib/ffi/jit_struct.lua | 201 +++++
test/LuaJIT-tests/lib/ffi/meta_tostring.lua | 55 ++
test/LuaJIT-tests/lib/ffi/redir.lua | 19 +
test/LuaJIT-tests/lib/ffi/type_punning.lua | 138 +++
test/LuaJIT-tests/lib/index | 8 +
test/LuaJIT-tests/lib/math/abs.lua | 16 +
test/LuaJIT-tests/lib/math/constants.lua | 8 +
test/LuaJIT-tests/lib/math/index | 3 +
test/LuaJIT-tests/lib/math/random.lua | 47 ++
test/LuaJIT-tests/lib/string/byte.lua | 92 ++
test/LuaJIT-tests/lib/string/char.lua | 29 +
test/LuaJIT-tests/lib/string/dump.lua | 31 +
test/LuaJIT-tests/lib/string/format/index | 1 +
test/LuaJIT-tests/lib/string/format/num.lua | 184 ++++
test/LuaJIT-tests/lib/string/index | 11 +
test/LuaJIT-tests/lib/string/len.lua | 14 +
test/LuaJIT-tests/lib/string/lower_upper.lua | 51 ++
test/LuaJIT-tests/lib/string/metatable.lua | 3 +
.../lib/string/multiple_functions.lua | 16 +
test/LuaJIT-tests/lib/string/rep.lua | 68 ++
test/LuaJIT-tests/lib/string/reverse.lua | 13 +
test/LuaJIT-tests/lib/string/sub.lua | 189 +++++
test/LuaJIT-tests/lib/table/concat.lua | 55 ++
test/LuaJIT-tests/lib/table/index | 6 +
test/LuaJIT-tests/lib/table/insert.lua | 17 +
test/LuaJIT-tests/lib/table/misc.lua | 58 ++
test/LuaJIT-tests/lib/table/new.lua | 11 +
test/LuaJIT-tests/lib/table/pack.lua | 7 +
test/LuaJIT-tests/lib/table/remove.lua | 42 +
test/LuaJIT-tests/lib/table/sort.lua | 27 +
test/LuaJIT-tests/misc/alias_alloc.lua | 54 ++
test/LuaJIT-tests/misc/api_call.lua | 98 +++
test/LuaJIT-tests/misc/catch_wrap.lua | 45 +
test/LuaJIT-tests/misc/coro_traceback.lua | 8 +
test/LuaJIT-tests/misc/coro_yield.lua | 111 +++
test/LuaJIT-tests/misc/debug_gc.lua | 47 ++
test/LuaJIT-tests/misc/dualnum.lua | 47 ++
test/LuaJIT-tests/misc/for_dir.lua | 13 +
test/LuaJIT-tests/misc/fori_coerce.lua | 33 +
test/LuaJIT-tests/misc/gc_rechain.lua | 32 +
test/LuaJIT-tests/misc/gc_trace.lua | 37 +
test/LuaJIT-tests/misc/gcstep.lua | 33 +
test/LuaJIT-tests/misc/hook_active.lua | 95 +++
test/LuaJIT-tests/misc/hook_line.lua | 41 +
test/LuaJIT-tests/misc/hook_norecord.lua | 12 +
test/LuaJIT-tests/misc/hook_record.lua | 8 +
test/LuaJIT-tests/misc/hook_top.lua | 55 ++
test/LuaJIT-tests/misc/jit_flush.lua | 50 ++
test/LuaJIT-tests/misc/lightud.lua | 88 ++
test/LuaJIT-tests/misc/loop_unroll.lua | 35 +
test/LuaJIT-tests/misc/parse_comp.lua | 13 +
test/LuaJIT-tests/misc/parse_esc.lua | 7 +
test/LuaJIT-tests/misc/parse_misc.lua | 31 +
test/LuaJIT-tests/misc/phi_conv.lua | 53 ++
test/LuaJIT-tests/misc/recurse_deep.lua | 29 +
test/LuaJIT-tests/misc/recurse_tail.lua | 22 +
test/LuaJIT-tests/misc/stack_gc.lua | 15 +
test/LuaJIT-tests/misc/stack_purge.lua | 25 +
test/LuaJIT-tests/misc/stackov.lua | 40 +
test/LuaJIT-tests/misc/stackovc.lua | 4 +
test/LuaJIT-tests/misc/tcall_base.lua | 20 +
test/LuaJIT-tests/misc/tcall_loop.lua | 8 +
test/LuaJIT-tests/misc/tonumber_scan.lua | 180 ++++
test/LuaJIT-tests/misc/uclo.lua | 91 ++
test/LuaJIT-tests/misc/unordered_jit.lua | 96 +++
test/LuaJIT-tests/misc/wbarrier.lua | 7 +
test/LuaJIT-tests/misc/wbarrier_jit.lua | 18 +
test/LuaJIT-tests/misc/wbarrier_obar.lua | 22 +
test/LuaJIT-tests/opt/dse/array.lua | 197 +++++
test/LuaJIT-tests/opt/dse/field.lua | 70 ++
test/LuaJIT-tests/opt/dse/index | 2 +
test/LuaJIT-tests/opt/fold/index | 1 +
test/LuaJIT-tests/opt/fold/kfold.lua | 81 ++
test/LuaJIT-tests/opt/fuse.lua | 5 +
test/LuaJIT-tests/opt/fwd/hrefk_rollback.lua | 32 +
test/LuaJIT-tests/opt/fwd/index | 3 +
test/LuaJIT-tests/opt/fwd/tnew_tdup.lua | 69 ++
test/LuaJIT-tests/opt/fwd/upval.lua | 50 ++
test/LuaJIT-tests/opt/index | 6 +
test/LuaJIT-tests/opt/loop/index | 1 +
test/LuaJIT-tests/opt/loop/unroll.lua | 32 +
test/LuaJIT-tests/opt/sink/alloc.lua | 126 +++
test/LuaJIT-tests/opt/sink/ffi.lua | 121 +++
test/LuaJIT-tests/opt/sink/ffi_nosink.lua | 45 +
test/LuaJIT-tests/opt/sink/index | 4 +
test/LuaJIT-tests/opt/sink/nosink.lua | 109 +++
test/LuaJIT-tests/src/cpptest.cpp | 129 +++
test/LuaJIT-tests/src/ctest.c | 339 ++++++++
test/LuaJIT-tests/sysdep/catch_cpp.lua | 71 ++
test/LuaJIT-tests/sysdep/ffi_include_gtk.lua | 9 +
test/LuaJIT-tests/sysdep/ffi_include_std.lua | 36 +
test/LuaJIT-tests/sysdep/ffi_lib_c.lua | 87 ++
test/LuaJIT-tests/sysdep/ffi_lib_z.lua | 107 +++
test/LuaJIT-tests/test.lua | 416 +++++++++
test/LuaJIT-tests/trace/exit_frame.lua | 79 ++
test/LuaJIT-tests/trace/exit_growstack.lua | 28 +
test/LuaJIT-tests/trace/exit_jfuncf.lua | 30 +
test/LuaJIT-tests/trace/gc64_slot_revival.lua | 18 +
test/LuaJIT-tests/trace/index | 7 +
test/LuaJIT-tests/trace/phi/copyspill.lua | 53 ++
test/LuaJIT-tests/trace/phi/index | 3 +
test/LuaJIT-tests/trace/phi/ref.lua | 131 +++
test/LuaJIT-tests/trace/phi/rotate.lua | 149 ++++
test/LuaJIT-tests/trace/snap.lua | 47 ++
test/LuaJIT-tests/trace/stitch.lua | 19 +
.../unportable/ffi_arith_int64.lua | 68 ++
test/LuaJIT-tests/unportable/math_special.lua | 55 ++
198 files changed, 13259 insertions(+)
create mode 100644 test/LuaJIT-tests/CMakeLists.txt
create mode 100644 test/LuaJIT-tests/README.md
create mode 100644 test/LuaJIT-tests/bc/constov.lua
create mode 100644 test/LuaJIT-tests/bc/index
create mode 100644 test/LuaJIT-tests/common/expect_error.lua
create mode 100644 test/LuaJIT-tests/common/ffi_util.inc
create mode 100644 test/LuaJIT-tests/common/test_runner_canary.lua
create mode 100644 test/LuaJIT-tests/computations.lua
create mode 100644 test/LuaJIT-tests/index
create mode 100644 test/LuaJIT-tests/lang/andor.lua
create mode 100644 test/LuaJIT-tests/lang/assignment.lua
create mode 100644 test/LuaJIT-tests/lang/compare.lua
create mode 100644 test/LuaJIT-tests/lang/compare_nan.lua
create mode 100644 test/LuaJIT-tests/lang/concat.lua
create mode 100644 test/LuaJIT-tests/lang/constant/index
create mode 100644 test/LuaJIT-tests/lang/constant/number.lua
create mode 100644 test/LuaJIT-tests/lang/constant/table.lua
create mode 100644 test/LuaJIT-tests/lang/coroutine.lua
create mode 100644 test/LuaJIT-tests/lang/for.lua
create mode 100644 test/LuaJIT-tests/lang/gc.lua
create mode 100644 test/LuaJIT-tests/lang/goto.lua
create mode 100644 test/LuaJIT-tests/lang/index
create mode 100644 test/LuaJIT-tests/lang/length.lua
create mode 100644 test/LuaJIT-tests/lang/meta/arith.lua
create mode 100644 test/LuaJIT-tests/lang/meta/arith_jit.lua
create mode 100644 test/LuaJIT-tests/lang/meta/call.lua
create mode 100644 test/LuaJIT-tests/lang/meta/cat.lua
create mode 100644 test/LuaJIT-tests/lang/meta/comp.lua
create mode 100644 test/LuaJIT-tests/lang/meta/comp_jit.lua
create mode 100644 test/LuaJIT-tests/lang/meta/debuginfo.lua
create mode 100644 test/LuaJIT-tests/lang/meta/eq.lua
create mode 100644 test/LuaJIT-tests/lang/meta/eq_jit.lua
create mode 100644 test/LuaJIT-tests/lang/meta/framegap.lua
create mode 100644 test/LuaJIT-tests/lang/meta/index
create mode 100644 test/LuaJIT-tests/lang/meta/index.lua
create mode 100644 test/LuaJIT-tests/lang/meta/len.lua
create mode 100644 test/LuaJIT-tests/lang/meta/newindex.lua
create mode 100644 test/LuaJIT-tests/lang/meta/nomm.lua
create mode 100644 test/LuaJIT-tests/lang/modulo.lua
create mode 100644 test/LuaJIT-tests/lang/self.lua
create mode 100644 test/LuaJIT-tests/lang/table.lua
create mode 100644 test/LuaJIT-tests/lang/tail_recursion.lua
create mode 100644 test/LuaJIT-tests/lang/upvalue/closure.lua
create mode 100644 test/LuaJIT-tests/lang/upvalue/index
create mode 100644 test/LuaJIT-tests/lang/vararg_jit.lua
create mode 100644 test/LuaJIT-tests/lib/base/assert.lua
create mode 100644 test/LuaJIT-tests/lib/base/error.lua
create mode 100644 test/LuaJIT-tests/lib/base/getfenv.lua
create mode 100644 test/LuaJIT-tests/lib/base/getsetmetatable.lua
create mode 100644 test/LuaJIT-tests/lib/base/index
create mode 100644 test/LuaJIT-tests/lib/base/ipairs.lua
create mode 100644 test/LuaJIT-tests/lib/base/next.lua
create mode 100644 test/LuaJIT-tests/lib/base/pairs.lua
create mode 100644 test/LuaJIT-tests/lib/base/pcall_jit.lua
create mode 100644 test/LuaJIT-tests/lib/base/select.lua
create mode 100644 test/LuaJIT-tests/lib/base/tonumber_tostring.lua
create mode 100644 test/LuaJIT-tests/lib/base/xpcall_jit.lua
create mode 100644 test/LuaJIT-tests/lib/bit.lua
create mode 100644 test/LuaJIT-tests/lib/contents.lua
create mode 100644 test/LuaJIT-tests/lib/coroutine/index
create mode 100644 test/LuaJIT-tests/lib/coroutine/yield.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/bit64.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/cdata_var.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/copy_fill.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/err.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_arith_ptr.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_bitfield.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_call.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_callback.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_const.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_convert.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_enum.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_gcstep_recursive.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_jit_arith.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_jit_call.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_jit_conv.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_lex_number.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_metatype.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_new.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_parse_array.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_parse_basic.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_parse_cdef.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_parse_struct.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/ffi_tabov.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/index
create mode 100644 test/LuaJIT-tests/lib/ffi/istype.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/jit_array.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/jit_complex.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/jit_misc.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/jit_struct.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/meta_tostring.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/redir.lua
create mode 100644 test/LuaJIT-tests/lib/ffi/type_punning.lua
create mode 100644 test/LuaJIT-tests/lib/index
create mode 100644 test/LuaJIT-tests/lib/math/abs.lua
create mode 100644 test/LuaJIT-tests/lib/math/constants.lua
create mode 100644 test/LuaJIT-tests/lib/math/index
create mode 100644 test/LuaJIT-tests/lib/math/random.lua
create mode 100644 test/LuaJIT-tests/lib/string/byte.lua
create mode 100644 test/LuaJIT-tests/lib/string/char.lua
create mode 100644 test/LuaJIT-tests/lib/string/dump.lua
create mode 100644 test/LuaJIT-tests/lib/string/format/index
create mode 100644 test/LuaJIT-tests/lib/string/format/num.lua
create mode 100644 test/LuaJIT-tests/lib/string/index
create mode 100644 test/LuaJIT-tests/lib/string/len.lua
create mode 100644 test/LuaJIT-tests/lib/string/lower_upper.lua
create mode 100644 test/LuaJIT-tests/lib/string/metatable.lua
create mode 100644 test/LuaJIT-tests/lib/string/multiple_functions.lua
create mode 100644 test/LuaJIT-tests/lib/string/rep.lua
create mode 100644 test/LuaJIT-tests/lib/string/reverse.lua
create mode 100644 test/LuaJIT-tests/lib/string/sub.lua
create mode 100644 test/LuaJIT-tests/lib/table/concat.lua
create mode 100644 test/LuaJIT-tests/lib/table/index
create mode 100644 test/LuaJIT-tests/lib/table/insert.lua
create mode 100644 test/LuaJIT-tests/lib/table/misc.lua
create mode 100644 test/LuaJIT-tests/lib/table/new.lua
create mode 100644 test/LuaJIT-tests/lib/table/pack.lua
create mode 100644 test/LuaJIT-tests/lib/table/remove.lua
create mode 100644 test/LuaJIT-tests/lib/table/sort.lua
create mode 100644 test/LuaJIT-tests/misc/alias_alloc.lua
create mode 100644 test/LuaJIT-tests/misc/api_call.lua
create mode 100644 test/LuaJIT-tests/misc/catch_wrap.lua
create mode 100644 test/LuaJIT-tests/misc/coro_traceback.lua
create mode 100644 test/LuaJIT-tests/misc/coro_yield.lua
create mode 100644 test/LuaJIT-tests/misc/debug_gc.lua
create mode 100644 test/LuaJIT-tests/misc/dualnum.lua
create mode 100644 test/LuaJIT-tests/misc/for_dir.lua
create mode 100644 test/LuaJIT-tests/misc/fori_coerce.lua
create mode 100644 test/LuaJIT-tests/misc/gc_rechain.lua
create mode 100644 test/LuaJIT-tests/misc/gc_trace.lua
create mode 100644 test/LuaJIT-tests/misc/gcstep.lua
create mode 100644 test/LuaJIT-tests/misc/hook_active.lua
create mode 100644 test/LuaJIT-tests/misc/hook_line.lua
create mode 100644 test/LuaJIT-tests/misc/hook_norecord.lua
create mode 100644 test/LuaJIT-tests/misc/hook_record.lua
create mode 100644 test/LuaJIT-tests/misc/hook_top.lua
create mode 100644 test/LuaJIT-tests/misc/jit_flush.lua
create mode 100644 test/LuaJIT-tests/misc/lightud.lua
create mode 100644 test/LuaJIT-tests/misc/loop_unroll.lua
create mode 100644 test/LuaJIT-tests/misc/parse_comp.lua
create mode 100644 test/LuaJIT-tests/misc/parse_esc.lua
create mode 100644 test/LuaJIT-tests/misc/parse_misc.lua
create mode 100644 test/LuaJIT-tests/misc/phi_conv.lua
create mode 100644 test/LuaJIT-tests/misc/recurse_deep.lua
create mode 100644 test/LuaJIT-tests/misc/recurse_tail.lua
create mode 100644 test/LuaJIT-tests/misc/stack_gc.lua
create mode 100644 test/LuaJIT-tests/misc/stack_purge.lua
create mode 100644 test/LuaJIT-tests/misc/stackov.lua
create mode 100644 test/LuaJIT-tests/misc/stackovc.lua
create mode 100644 test/LuaJIT-tests/misc/tcall_base.lua
create mode 100644 test/LuaJIT-tests/misc/tcall_loop.lua
create mode 100644 test/LuaJIT-tests/misc/tonumber_scan.lua
create mode 100644 test/LuaJIT-tests/misc/uclo.lua
create mode 100644 test/LuaJIT-tests/misc/unordered_jit.lua
create mode 100644 test/LuaJIT-tests/misc/wbarrier.lua
create mode 100644 test/LuaJIT-tests/misc/wbarrier_jit.lua
create mode 100644 test/LuaJIT-tests/misc/wbarrier_obar.lua
create mode 100644 test/LuaJIT-tests/opt/dse/array.lua
create mode 100644 test/LuaJIT-tests/opt/dse/field.lua
create mode 100644 test/LuaJIT-tests/opt/dse/index
create mode 100644 test/LuaJIT-tests/opt/fold/index
create mode 100644 test/LuaJIT-tests/opt/fold/kfold.lua
create mode 100644 test/LuaJIT-tests/opt/fuse.lua
create mode 100644 test/LuaJIT-tests/opt/fwd/hrefk_rollback.lua
create mode 100644 test/LuaJIT-tests/opt/fwd/index
create mode 100644 test/LuaJIT-tests/opt/fwd/tnew_tdup.lua
create mode 100644 test/LuaJIT-tests/opt/fwd/upval.lua
create mode 100644 test/LuaJIT-tests/opt/index
create mode 100644 test/LuaJIT-tests/opt/loop/index
create mode 100644 test/LuaJIT-tests/opt/loop/unroll.lua
create mode 100644 test/LuaJIT-tests/opt/sink/alloc.lua
create mode 100644 test/LuaJIT-tests/opt/sink/ffi.lua
create mode 100644 test/LuaJIT-tests/opt/sink/ffi_nosink.lua
create mode 100644 test/LuaJIT-tests/opt/sink/index
create mode 100644 test/LuaJIT-tests/opt/sink/nosink.lua
create mode 100644 test/LuaJIT-tests/src/cpptest.cpp
create mode 100644 test/LuaJIT-tests/src/ctest.c
create mode 100644 test/LuaJIT-tests/sysdep/catch_cpp.lua
create mode 100644 test/LuaJIT-tests/sysdep/ffi_include_gtk.lua
create mode 100644 test/LuaJIT-tests/sysdep/ffi_include_std.lua
create mode 100644 test/LuaJIT-tests/sysdep/ffi_lib_c.lua
create mode 100644 test/LuaJIT-tests/sysdep/ffi_lib_z.lua
create mode 100644 test/LuaJIT-tests/test.lua
create mode 100644 test/LuaJIT-tests/trace/exit_frame.lua
create mode 100644 test/LuaJIT-tests/trace/exit_growstack.lua
create mode 100644 test/LuaJIT-tests/trace/exit_jfuncf.lua
create mode 100644 test/LuaJIT-tests/trace/gc64_slot_revival.lua
create mode 100644 test/LuaJIT-tests/trace/index
create mode 100644 test/LuaJIT-tests/trace/phi/copyspill.lua
create mode 100644 test/LuaJIT-tests/trace/phi/index
create mode 100644 test/LuaJIT-tests/trace/phi/ref.lua
create mode 100644 test/LuaJIT-tests/trace/phi/rotate.lua
create mode 100644 test/LuaJIT-tests/trace/snap.lua
create mode 100644 test/LuaJIT-tests/trace/stitch.lua
create mode 100644 test/LuaJIT-tests/unportable/ffi_arith_int64.lua
create mode 100644 test/LuaJIT-tests/unportable/math_special.lua
diff --git a/.luacheckrc b/.luacheckrc
index d49301b..cbd2912 100644
--- a/.luacheckrc
+++ b/.luacheckrc
@@ -8,5 +8,6 @@ read_globals = { 'misc' }
exclude_files = {
'dynasm/',
'src/',
+ 'test/LuaJIT-tests/',
'test/PUC-Lua-5.1-tests/',
}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
index 8e6b4f9..1f9a379 100644
--- a/test/CMakeLists.txt
+++ b/test/CMakeLists.txt
@@ -32,10 +32,12 @@ else()
)
endif()
+add_subdirectory(LuaJIT-tests)
add_subdirectory(PUC-Lua-5.1-tests)
add_subdirectory(tarantool-tests)
add_custom_target(${PROJECT_NAME}-test DEPENDS
+ LuaJIT-tests
PUC-Lua-5.1-tests
tarantool-tests
)
diff --git a/test/LuaJIT-tests/CMakeLists.txt b/test/LuaJIT-tests/CMakeLists.txt
new file mode 100644
index 0000000..51a72d1
--- /dev/null
+++ b/test/LuaJIT-tests/CMakeLists.txt
@@ -0,0 +1,20 @@
+# See the rationale in the root CMakeLists.txt
+cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
+
+add_custom_target(LuaJIT-tests DEPENDS ${LUAJIT_TEST_BINARY})
+
+add_custom_command(TARGET LuaJIT-tests
+ COMMENT "Running LuaJIT-tests"
+ COMMAND
+ # Tarantool doesn't support LUA_INIT and most likely it
+ # never will.
+ # See https://github.com/tarantool/tarantool/issues/5744
+ # for more info.
+ # So use less preferable way for tests.
+ # See the root CMakeLists.txt for more info.
+ ${LUAJIT_TEST_COMMAND} ${CMAKE_CURRENT_SOURCE_DIR}/test.lua
+ +slow +ffi +bit +jit
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+# vim: expandtab tabstop=2 shiftwidth=2
diff --git a/test/LuaJIT-tests/README.md b/test/LuaJIT-tests/README.md
new file mode 100644
index 0000000..ff16ac8
--- /dev/null
+++ b/test/LuaJIT-tests/README.md
@@ -0,0 +1,110 @@
+This directory contains the LuaJIT test suite, or at least something which
+will evolve into the LuaJIT test suite. Large chunks of the suite can also
+be run with any other Lua 5.1 or 5.2 interpreter.
+
+## Running the test suite ##
+
+To run the default test suite, run `test.lua` using the Lua interpreter you
+wish to test, for example:
+
+ $ ~/luajit-2.0/src/luajit test.lua
+
+If the test suite passes, the final line printed to stdout will be
+`NNN passed`, and the exit code of the process will be zero. If any tests
+fail, the exit code will be non-zero. If the failures caused catastrophic
+termination of the entire process (such as a segmentation fault or assertion
+failure), the last line of output will be number and name of the test which
+caused the catastrophe. If the failures weren't catastrophic, the penultimate
+line of output will be `NNN passed, MMM failed`, and the last line will say
+how to re-run just the failing tests.
+
+Various flags and options can be passed to `test.lua` to control which tests
+are run, and in which order. Run `lua test.lua --help` for details.
+
+## Structure of the test suite ##
+
+The test suite consists of a directory tree. Within said tree there are various
+`.lua` files, and within every `.lua` file there are one or more tests. Every
+directory in the tree contains a file called `index`, which enumerates the
+members of the directory which contribute to the test suite (this is done to
+avoid an external dependency for directory iteration, and to allow metadata to
+be specified at the file/directory level). Every `.lua` file is structured as:
+
+ << local definitions >>
+ << test 1 >>
+ ...
+ << test N >>
+
+Where `<< local definitions >>` consists of Lua code to act as a common prefix
+for every test in the file, and each `<< test >>` looks like:
+
+ do --- <<name>> <<metadata>>
+ << code >>
+ end
+
+Where `<<name>>` is (almost) free-form, and `<< code >>` is Lua code which
+performs some actions and probably calls `assert` alot. The `<<metadata>>`
+fragment can be used to specify the conditions under which the test should
+or should not run, to adjust the environment in which the test is run, and to
+allow key/value pairs to be specified in a standard place/format.
+
+Some common pieces of metadata are:
+ * `+luajit>=2.1` - The test requires LuaJIT 2.1 or later to run.
+ * `+lua<5.2` - The test requires Lua 5.1 or earlier to run (all versions of
+ LuaJIT report themselves as 5.1).
+ * `+ffi` - The test requires the `ffi` library to be present.
+ * `+bit` - The test requires the `bit` library to be present.
+ * `+jit` - The test requires JIT compilation be available and turned on.
+ * `+slow` - The test is too slow to run as part of the default suite, and
+ thus requires `+slow` to be specified on the command line.
+ * `!private_G` - The test modifies globals, and thus needs to be run with a
+ private (shallow) copy of `_G`.
+
+Lua code which is common across all (or some) tests in a single file can be
+written at the top of the file as part of `<< local definitions >>`. Code
+which is common across multiple files lives in the `common` directory, and
+is pulled into applicable tests by means of `local x = require"common.x"`.
+
+It is intended that most `.lua` files in the test suite can be exercised
+without the test runner by just passing them to a Lua interpreter. In such
+cases, metadata is ignored, the tests are executed from top to bottom, and
+any failure results in later tests not running. Also note that the test
+runner converts every test into a separate function, which causes references
+to local definitions to become upvalue accesses rather than local variable
+accesses - in some cases this can cause differences in behaviour.
+
+## Extending the test suite ##
+
+First of all, decide where your new test(s) should live. This might be within
+an existing `.lua` file, or might involve creating new files and/or directories.
+If new files are created, remember to add them to the `index` file of the
+enclosing directory. If new directories are created, remember to create an
+`index` file in said directory, and add the new directory to the `index` file
+in the parent directory.
+
+Once you've decided in which file the test(s) should live, you're ready to add
+your test(s) to said file. Each test should be wrapped in a `do`/`end` block,
+and given some kind of name (after the `do` keyword, as in `do --- <<name>>`).
+The test should call `assert` to confirm whether the thing under test is
+behaving, or otherwise raise an error if the thing under test is misbehaving.
+Your test(s) should not write to stdout or stderr, nor should they mutate
+global state. After your test(s) are written, you should be able to determine
+which features they require, and put on metadata appropriately.
+
+## Completing the tidy-up of the test suite ##
+
+Some files/directories in this directory need some thought:
+
+ * `common/ffi_util.inc` - Needs renaming and being made `require`-able.
+ * `lib/ffi` - Tests need converting to structure described in this document.
+ * `lib/table/misc.lua` - Tests need organising and converting to structure
+ described in this document.
+ * `misc` - Tests need organising and converting to structure described in
+ this document.
+ * `src` - C/C++ source which needs to be compiled into a dynamic library and
+ loaded for certain tests. Need to figure out a good way of handling
+ C/C++ source.
+ * `sysdep` - Need to figure out a good way of handling these.
+ * `unportable` - Need to figure out a good way of handling these.
+
+After that, consult the README file by Mike in the directory above this one.
diff --git a/test/LuaJIT-tests/bc/constov.lua b/test/LuaJIT-tests/bc/constov.lua
new file mode 100644
index 0000000..5827840
--- /dev/null
+++ b/test/LuaJIT-tests/bc/constov.lua
@@ -0,0 +1,16 @@
+
+do --- float
+ local t = { "local x\n" }
+ for i=2,65537 do t[i] = "x="..i..".5\n" end
+ assert(loadstring(table.concat(t)) ~= nil)
+ t[65538] = "x=65538.5"
+ assert(loadstring(table.concat(t)) == nil)
+end
+
+do --- int
+ local t = { "local x\n" }
+ for i=2,65537 do t[i] = "x='"..i.."'\n" end
+ assert(loadstring(table.concat(t)) ~= nil)
+ t[65538] = "x='65538'"
+ assert(loadstring(table.concat(t)) == nil)
+end
diff --git a/test/LuaJIT-tests/bc/index b/test/LuaJIT-tests/bc/index
new file mode 100644
index 0000000..dead10f
--- /dev/null
+++ b/test/LuaJIT-tests/bc/index
@@ -0,0 +1 @@
+constov.lua +slow
diff --git a/test/LuaJIT-tests/common/expect_error.lua b/test/LuaJIT-tests/common/expect_error.lua
new file mode 100644
index 0000000..e155090
--- /dev/null
+++ b/test/LuaJIT-tests/common/expect_error.lua
@@ -0,0 +1,16 @@
+return function(f, msg)
+ local ok, err = pcall(f)
+ if ok then error("error check unexpectedly succeeded", 2) end
+ if msg then
+ if type(err) ~= "string" then
+ error("error check failed with "..tostring(err), 2)
+ end
+ local line, err2 = string.match(err, ":(%d*): (.*)")
+ if err2 ~= msg then
+ if err2:gsub(" got no value", " got nil") == msg then
+ return
+ end
+ error("error check failed with "..err, 2)
+ end
+ end
+end
diff --git a/test/LuaJIT-tests/common/ffi_util.inc b/test/LuaJIT-tests/common/ffi_util.inc
new file mode 100644
index 0000000..1eee8dd
--- /dev/null
+++ b/test/LuaJIT-tests/common/ffi_util.inc
@@ -0,0 +1,41 @@
+-- This should be turned into a proper module and not use globals.
+-- Or combined into a generiv test utility module. With FFI
+-- functionality turned off, if the FFI module is not built-in.
+
+local ffi = require("ffi")
+
+function checkfail(t, f)
+ f = f or ffi.typeof
+ for i=1,1e9 do
+ local tp = t[i]
+ if not tp then break end
+ assert(pcall(f, tp) == false, tp)
+ end
+end
+
+function checktypes(t)
+ for i=1,1e9,3 do
+ local tp = t[i+2]
+ if not tp then break end
+ local id = ffi.typeof(tp)
+ assert(ffi.sizeof(id) == t[i], tp)
+ assert(ffi.alignof(id) == t[i+1], tp)
+ end
+end
+
+function fails(f, ...)
+ if pcall(f, ...) ~= false then error("failure expected", 2) end
+end
+
+local incroot = os.getenv("INCROOT") or "/usr/include"
+local cdefs = os.getenv("CDEFS") or ""
+
+function include(name)
+ local flags = ffi.abi("32bit") and "-m32" or "-m64"
+ if string.sub(name, 1, 1) ~= "/" then name = incroot.."/"..name end
+ local fp = assert(io.popen("cc -E -P "..flags.." "..cdefs.." "..name))
+ local s = fp:read("*a")
+ fp:close()
+ ffi.cdef(s)
+end
+
diff --git a/test/LuaJIT-tests/common/test_runner_canary.lua b/test/LuaJIT-tests/common/test_runner_canary.lua
new file mode 100644
index 0000000..fc9cadc
--- /dev/null
+++ b/test/LuaJIT-tests/common/test_runner_canary.lua
@@ -0,0 +1 @@
+return "canary is alive"
diff --git a/test/LuaJIT-tests/computations.lua b/test/LuaJIT-tests/computations.lua
new file mode 100644
index 0000000..4fce7fc
--- /dev/null
+++ b/test/LuaJIT-tests/computations.lua
@@ -0,0 +1,113 @@
+do --- ack
+ local function Ack(m, n)
+ if m == 0 then return n+1 end
+ if n == 0 then return Ack(m-1, 1) end
+ return Ack(m-1, (Ack(m, n-1))) -- The parentheses are deliberate.
+ end
+
+ assert(Ack(3,5) == 253)
+end
+
+do --- ack notail
+ local function Ack(m, n)
+ if m == 0 then return n+1 end
+ if n == 0 then return Ack(m-1, 1) end
+ return (Ack(m-1, (Ack(m, n-1)))) -- The parentheses are deliberate.
+ end
+
+ assert(Ack(3,5) == 253)
+end
+
+do --- fac
+ local function fac(n)
+ local x = 1
+ for i=2,n do
+ x = x * i
+ end
+ return x
+ end
+
+ assert(fac(10) == 3628800)
+end
+
+do --- ffib
+ local function ffib(n)
+ if n <= 2 then return n,1 end
+ if n % 2 == 1 then
+ local a,b = ffib((n-1)/2)
+ local aa = a*a
+ return aa+a*(b+b), aa+b*b
+ else
+ local a,b = ffib(n/2-1)
+ local ab = a+b
+ return ab*ab+a*a, (ab+b)*a
+ end
+ end
+
+ local function fib(n)
+ return (ffib(n))
+ end
+
+ assert(fib(40) == 165580141)
+ assert(fib(39) == 102334155)
+ assert(fib(77) == 8944394323791464)
+end
+
+do --- fib
+ local function fib(n)
+ if n < 2 then return 1 end
+ return fib(n-2) + fib(n-1)
+ end
+
+ assert(fib(27) == 317811)
+end
+
+do --- nsieve
+ local function nsieve(m)
+ local isPrime = {}
+ for i=2,m do isPrime[i] = true end
+ local count = 0
+ for i=2,m do
+ if isPrime[i] then
+ for k=i+i,m,i do isPrime[k] = false end
+ count = count + 1
+ end
+ end
+ return count
+ end
+
+ assert(nsieve(100) == 25)
+ assert(nsieve(12345) == 1474)
+end
+
+do --- recsum
+ local function sum(n)
+ if n == 1 then return 1 end
+ return n + sum(n-1)
+ end
+
+ for i=1, 100 do
+ assert(sum(i) == i*(i+1)/2)
+ end
+end
+
+do --- recsump
+ local abs = math.abs
+ local function sum(n)
+ if n == 1 then return 1 end
+ return abs(n + sum(n-1))
+ end
+
+ for i=1, 100 do
+ assert(sum(i) == i*(i+1)/2)
+ end
+end
+
+do --- tak
+ local function tak(x, y, z)
+ if y >= x then return z end
+ return tak(tak(x-1, y, z), tak(y-1, z, x), (tak(z-1, x, y)))
+ end
+
+ assert(tak(21, 14, 7) == 14)
+end
diff --git a/test/LuaJIT-tests/index b/test/LuaJIT-tests/index
new file mode 100644
index 0000000..bd4081e
--- /dev/null
+++ b/test/LuaJIT-tests/index
@@ -0,0 +1,6 @@
+lang
+lib
+bc +luajit>=2
+computations.lua
+trace +jit
+opt +jit
diff --git a/test/LuaJIT-tests/lang/andor.lua b/test/LuaJIT-tests/lang/andor.lua
new file mode 100644
index 0000000..55b2c75
--- /dev/null
+++ b/test/LuaJIT-tests/lang/andor.lua
@@ -0,0 +1,61 @@
+do --- smoke
+ local x = ((1 or false) and true) or false
+ assert(x == true)
+end
+
+do --- allcases
+ local basiccases = {
+ {"nil", nil},
+ {"false", false},
+ {"true", true},
+ {"10", 10},
+ }
+
+ local mem = {basiccases} -- for memoization
+
+ local function allcases (n)
+ if mem[n] then return mem[n] end
+ local res = {}
+ -- include all smaller cases
+ for _, v in ipairs(allcases(n - 1)) do
+ res[#res + 1] = v
+ end
+ for i = 1, n - 1 do
+ for _, v1 in ipairs(allcases(i)) do
+ for _, v2 in ipairs(allcases(n - i)) do
+ res[#res + 1] = {
+ "(" .. v1[1] .. " and " .. v2[1] .. ")",
+ v1[2] and v2[2]
+ }
+ res[#res + 1] = {
+ "(" .. v1[1] .. " or " .. v2[1] .. ")",
+ v1[2] or v2[2]
+ }
+ end
+ end
+ end
+ mem[n] = res -- memoize
+ return res
+ end
+
+ for _, v in pairs(allcases(4)) do
+ local res = (loadstring or load)("return " .. v[1])()
+ if res ~= v[2] then
+ error(string.format("bad conditional eval\n%s\nexpected: %s\ngot: %s",
+ v[1], tostring(v[2]), tostring(res)))
+ end
+ end
+end
+
+do --- tracefib
+ -- 0001 KSHORT 1 2
+ -- 0002 ISGE 0 1
+ -- 0003 JMP 1 => 0006
+ -- 0004 KSHORT 1 1
+ -- 0005 JMP 1 => 0013
+ -- ^^^ must be 2
+ -- fix in jmp_patchtestreg
+ local function fib(n) return (n < 2) and 1 or fib(n-1)+fib(n-2) end
+ assert(fib(5) == 8)
+ assert(fib(10) == 89)
+end
diff --git a/test/LuaJIT-tests/lang/assignment.lua b/test/LuaJIT-tests/lang/assignment.lua
new file mode 100644
index 0000000..e9745ef
--- /dev/null
+++ b/test/LuaJIT-tests/lang/assignment.lua
@@ -0,0 +1,46 @@
+local assert = assert
+
+do --- local
+ local a, b, c
+ a, b, c = 0, 1
+ assert(a == 0)
+ assert(b == 1)
+ assert(c == nil)
+ a, b = a+1, b+1, a+b
+ assert(a == 1)
+ assert(b == 2)
+ a, b, c = 0
+ assert(a == 0)
+ assert(b == nil)
+ assert(c == nil)
+end
+
+do --- global !private_G
+ a, b, c = 0, 1
+ assert(a == 0)
+ assert(b == 1)
+ assert(c == nil)
+ a, b = a+1, b+1, a+b
+ assert(a == 1)
+ assert(b == 2)
+ a, b, c = 0
+ assert(a == 0)
+ assert(b == nil)
+ assert(c == nil)
+end
+
+do --- local lhs in key on lhs
+ local a = {}
+ local i = 3
+ i, a[i] = i+1, 20
+ assert(i == 4)
+ assert(a[3] == 20)
+end
+
+do --- global lhs in key on lhs !private_G
+ a = {}
+ i = 3
+ i, a[i] = i+1, 20
+ assert(i == 4)
+ assert(a[3] == 20)
+end
diff --git a/test/LuaJIT-tests/lang/compare.lua b/test/LuaJIT-tests/lang/compare.lua
new file mode 100644
index 0000000..09c5488
--- /dev/null
+++ b/test/LuaJIT-tests/lang/compare.lua
@@ -0,0 +1,323 @@
+local function lt(x, y)
+ if x < y then return true else return false end
+end
+
+local function le(x, y)
+ if x <= y then return true else return false end
+end
+
+local function gt(x, y)
+ if x > y then return true else return false end
+end
+
+local function ge(x, y)
+ if x >= y then return true else return false end
+end
+
+local function eq(x, y)
+ if x == y then return true else return false end
+end
+
+local function ne(x, y)
+ if x ~= y then return true else return false end
+end
+
+
+local function ltx1(x)
+ if x < 1 then return true else return false end
+end
+
+local function lex1(x)
+ if x <= 1 then return true else return false end
+end
+
+local function gtx1(x)
+ if x > 1 then return true else return false end
+end
+
+local function gex1(x)
+ if x >= 1 then return true else return false end
+end
+
+local function eqx1(x)
+ if x == 1 then return true else return false end
+end
+
+local function nex1(x)
+ if x ~= 1 then return true else return false end
+end
+
+
+local function lt1x(x)
+ if 1 < x then return true else return false end
+end
+
+local function le1x(x)
+ if 1 <= x then return true else return false end
+end
+
+local function gt1x(x)
+ if 1 > x then return true else return false end
+end
+
+local function ge1x(x)
+ if 1 >= x then return true else return false end
+end
+
+local function eq1x(x)
+ if 1 == x then return true else return false end
+end
+
+local function ne1x(x)
+ if 1 ~= x then return true else return false end
+end
+
+local function check(a, b)
+ if a ~= b then
+ error("check failed with "..tostring(a).." ~= "..tostring(b), 2)
+ end
+end
+
+do --- 1,2
+ local x,y = 1,2
+
+ check(x<y, true)
+ check(x<=y, true)
+ check(x>y, false)
+ check(x>=y, false)
+ check(x==y, false)
+ check(x~=y, true)
+
+ check(1<y, true)
+ check(1<=y, true)
+ check(1>y, false)
+ check(1>=y, false)
+ check(1==y, false)
+ check(1~=y, true)
+
+ check(x<2, true)
+ check(x<=2, true)
+ check(x>2, false)
+ check(x>=2, false)
+ check(x==2, false)
+ check(x~=2, true)
+
+ check(lt(x,y), true)
+ check(le(x,y), true)
+ check(gt(x,y), false)
+ check(ge(x,y), false)
+ check(eq(y,x), false)
+ check(ne(y,x), true)
+end
+
+do --- 2,1
+ local x,y = 2,1
+
+ check(x<y, false)
+ check(x<=y, false)
+ check(x>y, true)
+ check(x>=y, true)
+ check(x==y, false)
+ check(x~=y, true)
+
+ check(2<y, false)
+ check(2<=y, false)
+ check(2>y, true)
+ check(2>=y, true)
+ check(2==y, false)
+ check(2~=y, true)
+
+ check(x<1, false)
+ check(x<=1, false)
+ check(x>1, true)
+ check(x>=1, true)
+ check(x==1, false)
+ check(x~=1, true)
+
+ check(lt(x,y), false)
+ check(le(x,y), false)
+ check(gt(x,y), true)
+ check(ge(x,y), true)
+ check(eq(y,x), false)
+ check(ne(y,x), true)
+end
+
+do --- 1,1
+ local x,y = 1,1
+
+ check(x<y, false)
+ check(x<=y, true)
+ check(x>y, false)
+ check(x>=y, true)
+ check(x==y, true)
+ check(x~=y, false)
+
+ check(1<y, false)
+ check(1<=y, true)
+ check(1>y, false)
+ check(1>=y, true)
+ check(1==y, true)
+ check(1~=y, false)
+
+ check(x<1, false)
+ check(x<=1, true)
+ check(x>1, false)
+ check(x>=1, true)
+ check(x==1, true)
+ check(x~=1, false)
+
+ check(lt(x,y), false)
+ check(le(x,y), true)
+ check(gt(x,y), false)
+ check(ge(x,y), true)
+ check(eq(y,x), true)
+ check(ne(y,x), false)
+end
+
+do --- 2
+ check(lt1x(2), true)
+ check(le1x(2), true)
+ check(gt1x(2), false)
+ check(ge1x(2), false)
+ check(eq1x(2), false)
+ check(ne1x(2), true)
+
+ check(ltx1(2), false)
+ check(lex1(2), false)
+ check(gtx1(2), true)
+ check(gex1(2), true)
+ check(eqx1(2), false)
+ check(nex1(2), true)
+end
+
+do --- 1
+ check(lt1x(1), false)
+ check(le1x(1), true)
+ check(gt1x(1), false)
+ check(ge1x(1), true)
+ check(eq1x(1), true)
+ check(ne1x(1), false)
+
+ check(ltx1(1), false)
+ check(lex1(1), true)
+ check(gtx1(1), false)
+ check(gex1(1), true)
+ check(eqx1(1), true)
+ check(nex1(1), false)
+end
+
+do --- 0
+ check(lt1x(0), false)
+ check(le1x(0), false)
+ check(gt1x(0), true)
+ check(ge1x(0), true)
+ check(eq1x(0), false)
+ check(ne1x(0), true)
+
+ check(ltx1(0), true)
+ check(lex1(0), true)
+ check(gtx1(0), false)
+ check(gex1(0), false)
+ check(eqx1(0), false)
+ check(nex1(0), true)
+end
+
+do --- pcall
+ assert(not pcall(function()
+ local a, b = 10.5, nil
+ return a < b
+ end))
+end
+
+do --- bit +bit
+ for i=1,100 do
+ assert(bit.tobit(i+0x7fffffff) < 0)
+ end
+ for i=1,100 do
+ assert(bit.tobit(i+0x7fffffff) <= 0)
+ end
+end
+
+do --- string 1 255
+ local a = "\255\255\255\255"
+ local b = "\1\1\1\1"
+
+ assert(a > b)
+ assert(a > b)
+ assert(a >= b)
+ assert(b <= a)
+end
+
+do --- String comparisons:
+ local function str_cmp(a, b, lt, gt, le, ge)
+ assert(a<b == lt)
+ assert(a>b == gt)
+ assert(a<=b == le)
+ assert(a>=b == ge)
+ assert((not (a<b)) == (not lt))
+ assert((not (a>b)) == (not gt))
+ assert((not (a<=b)) == (not le))
+ assert((not (a>=b)) == (not ge))
+ end
+
+ local function str_lo(a, b)
+ str_cmp(a, b, true, false, true, false)
+ end
+
+ local function str_eq(a, b)
+ str_cmp(a, b, false, false, true, true)
+ end
+
+ local function str_hi(a, b)
+ str_cmp(a, b, false, true, false, true)
+ end
+
+ str_lo("a", "b")
+ str_eq("a", "a")
+ str_hi("b", "a")
+
+ str_lo("a", "aa")
+ str_hi("aa", "a")
+
+ str_lo("a", "a\0")
+ str_hi("a\0", "a")
+end
+
+do --- obj_eq/ne
+ local function obj_eq(a, b)
+ assert(a==b == true)
+ assert(a~=b == false)
+ end
+
+ local function obj_ne(a, b)
+ assert(a==b == false)
+ assert(a~=b == true)
+ end
+
+ obj_eq(nil, nil)
+ obj_ne(nil, false)
+ obj_ne(nil, true)
+
+ obj_ne(false, nil)
+ obj_eq(false, false)
+ obj_ne(false, true)
+
+ obj_ne(true, nil)
+ obj_ne(true, false)
+ obj_eq(true, true)
+
+ obj_eq(1, 1)
+ obj_ne(1, 2)
+ obj_ne(2, 1)
+
+ obj_eq("a", "a")
+ obj_ne("a", "b")
+ obj_ne("a", 1)
+ obj_ne(1, "a")
+
+ local t, t2 = {}, {}
+ obj_eq(t, t)
+ obj_ne(t, t2)
+ obj_ne(t, 1)
+ obj_ne(t, "")
+end
diff --git a/test/LuaJIT-tests/lang/compare_nan.lua b/test/LuaJIT-tests/lang/compare_nan.lua
new file mode 100644
index 0000000..878f39a
--- /dev/null
+++ b/test/LuaJIT-tests/lang/compare_nan.lua
@@ -0,0 +1,99 @@
+
+local function check(a, b)
+ if a ~= b then
+ error("check failed with "..tostring(a).." ~= "..tostring(b), 2)
+ end
+end
+
+local nan, one = 0/0, 1
+
+do --- nan nan
+ check(nan<nan, false)
+ check(nan<=nan, false)
+ check(nan>nan, false)
+ check(nan>=nan, false)
+ check(nan==nan, false)
+ check(nan~=nan, true)
+end
+
+do --- nan one
+ check(nan<one, false)
+ check(nan<=one, false)
+ check(nan>one, false)
+ check(nan>=one, false)
+ check(nan==one, false)
+ check(nan~=one, true)
+end
+
+do --- one nan
+ check(one<nan, false)
+ check(one<=nan, false)
+ check(one>nan, false)
+ check(one>=nan, false)
+ check(one==nan, false)
+ check(one~=nan, true)
+end
+
+do --- nan 1
+ check(nan<1, false)
+ check(nan<=1, false)
+ check(nan>1, false)
+ check(nan>=1, false)
+ check(nan==1, false)
+ check(nan~=1, true)
+end
+
+do --- 1 nan
+ check(1<nan, false)
+ check(1<=nan, false)
+ check(1>nan, false)
+ check(1>=nan, false)
+ check(1==nan, false)
+ check(1~=nan, true)
+end
+
+do --- not nan nan
+ check(not (nan<nan), true)
+ check(not (nan<=nan), true)
+ check(not (nan>nan), true)
+ check(not (nan>=nan), true)
+ check(not (nan==nan), true)
+ check(not (nan~=nan), false)
+end
+
+do --- not nan one
+ check(not (nan<one), true)
+ check(not (nan<=one), true)
+ check(not (nan>one), true)
+ check(not (nan>=one), true)
+ check(not (nan==one), true)
+ check(not (nan~=one), false)
+end
+
+do --- not one nan
+ check(not (one<nan), true)
+ check(not (one<=nan), true)
+ check(not (one>nan), true)
+ check(not (one>=nan), true)
+ check(not (one==nan), true)
+ check(not (one~=nan), false)
+end
+
+do --- not nan 1
+ check(not (nan<1), true)
+ check(not (nan<=1), true)
+ check(not (nan>1), true)
+ check(not (nan>=1), true)
+ check(not (nan==1), true)
+ check(not (nan~=1), false)
+end
+
+do --- not 1 nan
+ check(not (1<nan), true)
+ check(not (1<=nan), true)
+ check(not (1>nan), true)
+ check(not (1>=nan), true)
+ check(not (1==nan), true)
+ check(not (1~=nan), false)
+end
+
diff --git a/test/LuaJIT-tests/lang/concat.lua b/test/LuaJIT-tests/lang/concat.lua
new file mode 100644
index 0000000..04d665b
--- /dev/null
+++ b/test/LuaJIT-tests/lang/concat.lua
@@ -0,0 +1,112 @@
+do --- Constant folding
+ local y
+ for i=1,100 do y = "a".."b" end
+ assert(y == "ab")
+ for i=1,100 do y = "ab"..(1).."cd"..(1.5) end
+ assert(y == "ab1cd1.5")
+end
+
+do --- Fuse conversions to strings
+ local y
+ local x = "a"
+ for i=1,100 do y = x..i end
+ assert(y == "a100")
+ x = "a"
+ for i=1.5,100.5 do y = x..i end
+ assert(y == "a100.5")
+end
+
+do --- Fuse string construction
+ local y
+ local x = "abc"
+ for i=1,100 do y = "x"..string.sub(x, 2) end
+ assert(y == "xbc")
+end
+
+do --- CSE, sink
+ local y
+ local x = "a"
+ for i=1,100 do y = x.."b" end
+ assert(y == "ab")
+end
+
+do --- CSE, two buffers in parallel, no sink
+ local y, z
+ local x1, x2 = "xx", "yy"
+ for i=1,100 do y = x1.."a"..x1; z = x1.."a"..x2 end
+ assert(y == "xxaxx")
+ assert(z == "xxayy")
+ x1 = "xx"
+ for i=1,100 do y = x1.."a"..x1; z = x1.."b"..x1 end
+ assert(y == "xxaxx")
+ assert(z == "xxbxx")
+end
+
+do --- Append, CSE
+ local y, z
+ local x = "a"
+ for i=1,100 do
+ y = x.."b"
+ y = y.."c"
+ end
+ assert(y == "abc")
+ x = "a"
+ for i=1,100 do
+ y = x.."b"
+ z = y.."c"
+ end
+ assert(y == "ab")
+ assert(z == "abc")
+ x = "a"
+ for i=1,100 do
+ y = x.."b"
+ z = y..i
+ end
+ assert(y == "ab")
+ assert(z == "ab100")
+end
+
+do --- Append, FOLD
+ local a, b = "x"
+ for i=1,100 do b = (a.."y").."" end
+ assert(b == "xy")
+end
+
+do --- Append to buffer, sink
+ local x = "a"
+ for i=1,100 do x = x.."b" end
+ assert(x == "a"..string.rep("b", 100))
+ x = "a"
+ for i=1,100 do x = x.."bc" end
+ assert(x == "a"..string.rep("bc", 100))
+end
+
+do --- Append to two buffers in parallel, no append, no sink
+ local y, z = "xx", "yy"
+ for i=1,100 do y = y.."a"; z = z.."b" end
+ assert(y == "xx"..string.rep("a", 100))
+ assert(z == "yy"..string.rep("b", 100))
+end
+
+do --- Sink into side-exit
+ local x = "a"
+ local z
+ for i=1,200 do
+ local y = x.."b"
+ if i > 100 then
+ z = y..i
+ end
+ end
+ assert(z == "ab200")
+end
+
+do --- Very long strings
+ for i, s in ipairs{"a", "bc", "def"} do
+ for n = 1, 20 do
+ s = s .. s
+ end
+ assert(#s == 2^20*i)
+ assert(s:sub(1, 6) == s:sub(7, 12))
+ assert(s:sub(1, 6) == s:sub(-6, -1))
+ end
+end
diff --git a/test/LuaJIT-tests/lang/constant/index b/test/LuaJIT-tests/lang/constant/index
new file mode 100644
index 0000000..e738357
--- /dev/null
+++ b/test/LuaJIT-tests/lang/constant/index
@@ -0,0 +1,2 @@
+number.lua
+table.lua
diff --git a/test/LuaJIT-tests/lang/constant/number.lua b/test/LuaJIT-tests/lang/constant/number.lua
new file mode 100644
index 0000000..fb67356
--- /dev/null
+++ b/test/LuaJIT-tests/lang/constant/number.lua
@@ -0,0 +1,12 @@
+do --- exp
+ assert(1e5 == 100000)
+ assert(1e+5 == 100000)
+ assert(1e-5 == 0.00001)
+end
+
+do --- hex exp +hexfloat !lex
+ assert(0xe+9 == 23)
+ assert(0xep9 == 7168)
+ assert(0xep+9 == 7168)
+ assert(0xep-9 == 0.02734375)
+end
diff --git a/test/LuaJIT-tests/lang/constant/table.lua b/test/LuaJIT-tests/lang/constant/table.lua
new file mode 100644
index 0000000..899d0f6
--- /dev/null
+++ b/test/LuaJIT-tests/lang/constant/table.lua
@@ -0,0 +1,15 @@
+
+do --- tnew
+ local a = nil
+ local b = {}
+ local t = {[true] = a, [false] = b or 1}
+ assert(t[true] == nil)
+ assert(t[false] == b)
+end
+
+do --- tdup
+ local b = {}
+ local t = {[true] = nil, [false] = b or 1}
+ assert(t[true] == nil)
+ assert(t[false] == b)
+end
diff --git a/test/LuaJIT-tests/lang/coroutine.lua b/test/LuaJIT-tests/lang/coroutine.lua
new file mode 100644
index 0000000..405135c
--- /dev/null
+++ b/test/LuaJIT-tests/lang/coroutine.lua
@@ -0,0 +1,8 @@
+do --- traceback
+ local co = coroutine.create(function()
+ local x = nil
+ local y = x.x
+ end)
+ assert(coroutine.resume(co) == false)
+ debug.traceback(co)
+end
diff --git a/test/LuaJIT-tests/lang/for.lua b/test/LuaJIT-tests/lang/for.lua
new file mode 100644
index 0000000..4982b32
--- /dev/null
+++ b/test/LuaJIT-tests/lang/for.lua
@@ -0,0 +1,45 @@
+do --- direction
+ local a,b,c = 10,1,-1
+ for i=1,20 do
+ if c == -1 then
+ a,b,c = 1,10,1
+ else
+ a,b,c = 10,1,-1
+ end
+ local x = 0
+ for i=a,b,c do for j=1,10 do end x=x+1 end
+ assert(x == 10)
+ end
+end
+
+do --- coerce to integer at 13
+ local n = 1
+ local x = 0
+ for i=1,20 do
+ for j=n,100 do x = x + 1 end
+ if i == 13 then n = "2" end
+ end
+ assert(x == 1993)
+end
+
+do --- coerce to integer at 10
+ local n = 1
+ local x = 0
+ for i=1,20 do
+ for j=n,100 do x = x + 1 end
+ if i == 10 then n = "2" end
+ end
+ assert(x == 1990)
+end
+
+do --- cannot coerce to integer at 10
+ local function f()
+ local n = 1
+ local x = 0
+ for i=1,20 do
+ for j=n,100 do x = x + 1 end
+ if i == 10 then n = "x" end
+ end
+ end
+ assert(not pcall(f))
+end
diff --git a/test/LuaJIT-tests/lang/gc.lua b/test/LuaJIT-tests/lang/gc.lua
new file mode 100644
index 0000000..35e6a1f
--- /dev/null
+++ b/test/LuaJIT-tests/lang/gc.lua
@@ -0,0 +1,42 @@
+do --- rechain
+ local k
+
+ collectgarbage()
+
+ local t = {}
+ t.ac = 1
+
+ t.nn = 1
+ t.mm = 1
+ t.nn = nil
+ t.mm = nil
+
+ k = "a".."i"
+ t[k] = 2
+
+ t.ad = 3
+
+ t[k] = nil
+ k = nil
+
+ collectgarbage()
+
+ k = "a".."f"
+ t[k] = 4
+
+ t.ak = 5
+
+ assert(t[k] == 4)
+end
+
+do --- TSETM gc
+ local function f()
+ collectgarbage()
+ return "a", "b"
+ end
+ for i = 1, 10 do
+ local t = {f()}
+ assert(t[1] == "a")
+ assert(t[2] == "b")
+ end
+end
diff --git a/test/LuaJIT-tests/lang/goto.lua b/test/LuaJIT-tests/lang/goto.lua
new file mode 100644
index 0000000..1563a23
--- /dev/null
+++ b/test/LuaJIT-tests/lang/goto.lua
@@ -0,0 +1,149 @@
+local loadstring = loadstring or load
+
+local function expect(src, msg)
+ local ok, err = loadstring(src)
+ if msg then
+ assert(not ok and string.find(err, msg), err)
+ else
+ assert(ok, err)
+ end
+end
+
+do --- Basic goto and label semantics.
+ -- Error: duplicate label.
+ expect("::a:: ::a::", "'a'")
+ expect("::a:: ::b:: do ::b:: end ::a::", "'a'")
+
+ -- Error: undefined label.
+ expect("goto a", "'a'")
+ expect("goto a; ::b::", "'a'")
+ expect("do ::a:: end; goto a", "'a'")
+ expect("goto a; do ::a:: end", "'a'")
+ expect("break", "break")
+ expect("if x then break end", "break")
+
+ -- Error: goto into variable scope.
+ expect("goto a; local x; ::a:: local y", "'x'")
+ expect("do local v,w; goto a; end; local x; ::a:: local y", "'x'")
+ expect("repeat goto a; local x; ::a:: until x", "'x'")
+
+ ::a:: do goto a; ::a:: end -- Forward jump, not an infinite loop.
+end
+
+do --- Goto is not a keyword. -compat5.2 !lex !private_G
+ goto = 1
+end
+
+do --- Goto is a keyword. +compat5.2
+ expect("goto = 1", "<name>")
+end
+
+do --- Trailing label is considered to be out of scope.
+ local x = 11
+ do
+ goto a
+ goto a
+ local y = 22
+ x = y
+ ::a::
+ ::b::
+ end
+ assert(x == 11)
+end
+
+do --- Trailing labels and empty statements are considered to be out of scope. +compat5.2 !lex
+ local x = 11
+ do
+ goto a
+ goto a
+ local y = 22
+ x = y
+ ::a:: ;;
+ ::b:: ;;
+ end
+ assert(x == 11)
+end
+
+do --- Simple loop with cross-jumping.
+ local x = 1
+ while true do
+ goto b
+ ::a:: if x < 100 then goto c end
+ goto d
+ ::b:: x = x + 1; goto a
+ ::c::
+ end
+ ::d::
+ assert(x == 100)
+end
+
+do --- Backwards goto must close upval.
+ local t = {}
+ local i = 1
+ ::a::
+ local x
+ t[i] = function() return x end
+ x = i
+ i = i + 1
+ if i <= 2 then goto a end
+ assert(t[1]() == 1)
+ assert(t[2]() == 2)
+end
+
+do --- Break must close upval, even if closure is parsed after break.
+ local foo
+ repeat
+ local x
+ ::a::
+ if x then break end
+ function foo() return x end
+ x = true
+ goto a
+ until false
+ assert(foo() == true)
+end
+
+do --- Label prevents joining to KNIL. -lua==5.2
+ local k = 0
+ local x
+ ::foo::
+ local y
+ assert(y == nil)
+ y = true
+ k = k + 1
+ if k < 2 then goto foo end
+end
+
+do --- Break resolved from the right scope.
+ local function p(lvl)
+ lvl = lvl or 1
+ while true do
+ lvl = lvl + 1
+ if lvl == nil then break end
+ local idx = 1
+ while true do
+ if key == nil then break end
+ idx = idx + 1
+ end
+ end
+ end
+end
+
+do --- Do not join twice with UCLO.
+ while true do
+ do
+ local x
+ local function f() return x end
+ end
+ break
+ end
+
+ while true do
+ do
+ local x
+ local function f() return x end
+ end
+ goto foo
+ end
+ ::foo::
+end
diff --git a/test/LuaJIT-tests/lang/index b/test/LuaJIT-tests/lang/index
new file mode 100644
index 0000000..88e2edf
--- /dev/null
+++ b/test/LuaJIT-tests/lang/index
@@ -0,0 +1,18 @@
+andor.lua
+assignment.lua
+compare.lua
+compare_nan.lua
+constant
+for.lua
+length.lua
+modulo.lua
+concat.lua
+self.lua
+table.lua
+upvalue
+coroutine.lua
+tail_recursion.lua
+vararg_jit.lua
+gc.lua
+goto.lua +goto
+meta
diff --git a/test/LuaJIT-tests/lang/length.lua b/test/LuaJIT-tests/lang/length.lua
new file mode 100644
index 0000000..67c68ae
--- /dev/null
+++ b/test/LuaJIT-tests/lang/length.lua
@@ -0,0 +1,23 @@
+
+do --- length increasing and decreasing in loop
+ local t = {}
+ for i=1,100 do t[#t+1] = i end
+ assert(#t == 100)
+ for i=1,100 do t[#t] = nil end
+ assert(#t == 0)
+end
+
+do --- length increasing in loop with existing element
+ local t = {}
+ t[90] = 999
+ for i=1,100 do t[#t+1] = i end
+ assert(#t > 100 and t[#t] == 100)
+end
+
+do --- length decreasing in loop with erased element
+ local t = {}
+ for i=1,100 do t[i] = i end
+ t[10] = nil
+ for i=1,99 do t[#t] = nil end
+ assert(#t == 0)
+end
diff --git a/test/LuaJIT-tests/lang/meta/arith.lua b/test/LuaJIT-tests/lang/meta/arith.lua
new file mode 100644
index 0000000..17de4c8
--- /dev/null
+++ b/test/LuaJIT-tests/lang/meta/arith.lua
@@ -0,0 +1,118 @@
+local function create(arith, v1, v2)
+ local meta = {
+ __add=function(a,b) return arith("add", a, b) end,
+ __sub=function(a,b) return arith("sub", a, b) end,
+ __mul=function(a,b) return arith("mul", a, b) end,
+ __div=function(a,b) return arith("div", a, b) end,
+ __mod=function(a,b) return arith("mod", a, b) end,
+ __pow=function(a,b) return arith("pow", a, b) end,
+ __unm=function(a,b) return arith("unm", a, b) end,
+ }
+ return setmetatable({v1}, meta), setmetatable({v2}, meta)
+end
+
+do --- op
+ local a, b = create(function(op,a,b) return op end)
+ assert(a+b == "add")
+ assert(a-b == "sub")
+ assert(a*b == "mul")
+ assert(a/b == "div")
+ assert(a%b == "mod")
+ assert(a^b == "pow")
+ assert(-a == "unm")
+end
+
+do --- lhs
+ local a, b = create(function(op,a,b) return a[1] end, "foo", 42)
+ assert(a+b == "foo")
+ assert(a-b == "foo")
+ assert(a*b == "foo")
+ assert(a/b == "foo")
+ assert(a%b == "foo")
+ assert(a^b == "foo")
+ assert(-a == "foo")
+end
+
+do --- rhs
+ local a, b = create(function(op,a,b) return b[1] end, 42, "foo")
+ assert(a+b == "foo")
+ assert(a-b == "foo")
+ assert(a*b == "foo")
+ assert(a/b == "foo")
+ assert(a%b == "foo")
+ assert(a^b == "foo")
+ assert(-a == 42)
+end
+
+do --- meta only lhs
+ local a, b = create(function(op,a,b) return a[1]+b end, 39), 3
+ assert(a+b == 42)
+ assert(a-b == 42)
+ assert(a*b == 42)
+ assert(a/b == 42)
+ assert(a%b == 42)
+ assert(a^b == 42)
+end
+
+do --- meta only rhs
+ local a, b = 39, create(function(op,a,b) return a+b[1] end, 3)
+ assert(a+b == 42)
+ assert(a-b == 42)
+ assert(a*b == 42)
+ assert(a/b == 42)
+ assert(a%b == 42)
+ assert(a^b == 42)
+end
+
+do --- defaults string, int
+ local a, b = "39", 3
+ assert(a+b == 42)
+ assert(a-b == 36)
+ assert(a*b == 117)
+ assert(a/b == 13)
+ assert(a%b == 0)
+ assert(a^b == 59319)
+ assert(-a == -39)
+end
+
+do --- defaults int, string
+ local a, b = 39, "3"
+ assert(a+b == 42)
+ assert(a-b == 36)
+ assert(a*b == 117)
+ assert(a/b == 13)
+ assert(a%b == 0)
+ assert(a^b == 59319)
+ assert(-a == -39)
+end
+
+do --- defaults string, string
+ local a, b = "39", "3"
+ assert(a+b == 42)
+ assert(a-b == 36)
+ assert(a*b == 117)
+ assert(a/b == 13)
+ assert(a%b == 0)
+ assert(a^b == 59319)
+ assert(-a == -39)
+end
+
+do --- defaults string, kint
+ local a = "39"
+ assert(a+3 == 42)
+ assert(a-3 == 36)
+ assert(a*3 == 117)
+ assert(a/3 == 13)
+ assert(a%3 == 0)
+ assert(a^3 == 59319)
+end
+
+do --- defaults kint, string
+ local b = "3"
+ assert(39+b == 42)
+ assert(39-b == 36)
+ assert(39*b == 117)
+ assert(39/b == 13)
+ assert(39%b == 0)
+ assert(39^b == 59319)
+end
diff --git a/test/LuaJIT-tests/lang/meta/arith_jit.lua b/test/LuaJIT-tests/lang/meta/arith_jit.lua
new file mode 100644
index 0000000..2cb35db
--- /dev/null
+++ b/test/LuaJIT-tests/lang/meta/arith_jit.lua
@@ -0,0 +1,68 @@
+
+do --- assert rhs
+ local t = {}
+ local mt = {
+ __add = function(a, b) assert(b == t); return a+11 end,
+ __sub = function(a, b) assert(b == t); return a+12 end,
+ __mul = function(a, b) assert(b == t); return a+13 end,
+ __div = function(a, b) assert(b == t); return a+14 end,
+ __mod = function(a, b) assert(b == t); return a+15 end,
+ __pow = function(a, b) assert(b == t); return a+16 end,
+ __unm = function(a, b) assert(a == t and b == t); return 17 end,
+ }
+ t = setmetatable(t, mt)
+ do local x = 0; for i=1,100 do x = x + t end; assert(x == 1100); end
+ do local x = 0; for i=1,100 do x = x - t end; assert(x == 1200); end
+ do local x = 0; for i=1,100 do x = x * t end; assert(x == 1300); end
+ do local x = 0; for i=1,100 do x = x / t end; assert(x == 1400); end
+ do local x = 0; for i=1,100 do x = x % t end; assert(x == 1500); end
+ do local x = 0; for i=1,100 do x = x ^ t end; assert(x == 1600); end
+ do local x = 0; for i=1,100 do x = x + (-t) end; assert(x == 1700); end
+end
+
+do --- assert lhs
+ local t = {}
+ local mt = {
+ __add = function(a, b) assert(a == t); return b+11 end,
+ __sub = function(a, b) assert(a == t); return b+12 end,
+ __mul = function(a, b) assert(a == t); return b+13 end,
+ __div = function(a, b) assert(a == t); return b+14 end,
+ __mod = function(a, b) assert(a == t); return b+15 end,
+ __pow = function(a, b) assert(a == t); return b+16 end,
+ }
+ t = setmetatable(t, mt)
+ do local x = 0; for i=1,100 do x = t + x end; assert(x == 1100); end
+ do local x = 0; for i=1,100 do x = t - x end; assert(x == 1200); end
+ do local x = 0; for i=1,100 do x = t * x end; assert(x == 1300); end
+ do local x = 0; for i=1,100 do x = t / x end; assert(x == 1400); end
+ do local x = 0; for i=1,100 do x = t % x end; assert(x == 1500); end
+ do local x = 0; for i=1,100 do x = t ^ x end; assert(x == 1600); end
+end
+
+do --- assert both sides
+ local t = {}
+ local mt = {
+ __add = function(a, b) assert(a == t and b == t); return 11 end,
+ __sub = function(a, b) assert(a == t and b == t); return 12 end,
+ __mul = function(a, b) assert(a == t and b == t); return 13 end,
+ __div = function(a, b) assert(a == t and b == t); return 14 end,
+ __mod = function(a, b) assert(a == t and b == t); return 15 end,
+ __pow = function(a, b) assert(a == t and b == t); return 16 end,
+ }
+ t = setmetatable(t, mt)
+ do local x = 0; for i=1,100 do x = t + t end; assert(x == 11); end
+ do local x = 0; for i=1,100 do x = t - t end; assert(x == 12); end
+ do local x = 0; for i=1,100 do x = t * t end; assert(x == 13); end
+ do local x = 0; for i=1,100 do x = t / t end; assert(x == 14); end
+ do local x = 0; for i=1,100 do x = t % t end; assert(x == 15); end
+ do local x = 0; for i=1,100 do x = t ^ t end; assert(x == 16); end
+end
+
+do --- adjust no result to one result
+ local t = {}
+ local mt = { __add = function(a, b) end }
+ t = setmetatable(t, mt)
+ local x
+ for i=1,100 do x = t+t end
+ assert(x == nil)
+end
diff --git a/test/LuaJIT-tests/lang/meta/call.lua b/test/LuaJIT-tests/lang/meta/call.lua
new file mode 100644
index 0000000..c77c0dd
--- /dev/null
+++ b/test/LuaJIT-tests/lang/meta/call.lua
@@ -0,0 +1,81 @@
+
+local function callmeta(o, a, b)
+ return o, a, b
+end
+
+local meta = { __call = callmeta }
+
+do --- table
+ local t = setmetatable({}, meta)
+ local o,a,b = t()
+ assert(o == t and a == nil and b == nil)
+ local o,a,b = t("foo")
+ assert(o == t and a == "foo" and b == nil)
+ local o,a,b = t("foo", "bar")
+ assert(o == t and a == "foo" and b == "bar")
+end
+
+do --- userdata +lua<5.2
+ local u = newproxy(true)
+ getmetatable(u).__call = callmeta
+
+ local o,a,b = u()
+ assert(o == u and a == nil and b == nil)
+ local o,a,b = u("foo")
+ assert(o == u and a == "foo" and b == nil)
+ local o,a,b = u("foo", "bar")
+ assert(o == u and a == "foo" and b == "bar")
+end
+
+do --- number
+ debug.setmetatable(0, meta)
+ local o,a,b = (42)()
+ assert(o == 42 and a == nil and b == nil)
+ local o,a,b = (42)("foo")
+ assert(o == 42 and a == "foo" and b == nil)
+ local o,a,b = (42)("foo", "bar")
+ assert(o == 42 and a == "foo" and b == "bar")
+ debug.setmetatable(0, nil)
+end
+
+do --- table with changing metamethod
+ local tc = setmetatable({}, { __call = function(o,a,b) return o end})
+ local ta = setmetatable({}, { __add = tc})
+ local o,a = ta + ta
+ assert(o == tc and a == nil)
+
+ getmetatable(tc).__call = function(o,a,b) return a end
+ local o,a = ta + ta
+ assert(o == ta and a == nil)
+end
+
+do --- jit table
+ local t = setmetatable({}, { __call = function(t, a) return 100-a end })
+ for i=1,100 do assert(t(i) == 100-i) end
+end
+
+do --- jit table rawget as metamethod
+ local t = setmetatable({}, { __call = rawget })
+ for i=1,100 do t[i] = 100-i end
+ for i=1,100 do assert(t(i) == 100-i) end
+end
+
+do --- jit number
+ debug.setmetatable(0, { __call = function(n) return 100-n end })
+ for i=1,100 do assert((i)() == 100-i) end
+ debug.setmetatable(0, nil)
+end
+
+do --- jit newindex pcall
+ local t = setmetatable({}, { __newindex = pcall, __call = rawset })
+ for i=1,100 do t[i] = 100-i end
+ for i=1,100 do assert(t[i] == 100-i) end
+end
+
+do --- jit index pcall
+ local t = setmetatable({}, {
+ __index = pcall, __newindex = rawset,
+ __call = function(t, i) t[i] = 100-i end,
+ })
+ for i=1,100 do assert(t[i] == true and rawget(t, i) == 100-i) end
+end
diff --git a/test/LuaJIT-tests/lang/meta/cat.lua b/test/LuaJIT-tests/lang/meta/cat.lua
new file mode 100644
index 0000000..48a89e4
--- /dev/null
+++ b/test/LuaJIT-tests/lang/meta/cat.lua
@@ -0,0 +1,61 @@
+local function create(cat, v1, v2)
+ local meta = { __concat = cat }
+ return setmetatable({v1}, meta), setmetatable({v2}, meta)
+end
+
+do --- default
+ local a, b, c = "foo", "bar", "baz"
+ assert(a..b == "foobar")
+ assert(a..b..c == "foobarbaz")
+end
+
+do --- lhs
+ local a, b = create(function(a, b) return a end)
+ assert(a..b == a)
+ assert(b..a == b)
+ assert(a..b..b == a)
+ assert(a..a..b == a)
+ assert(a..b..a == a)
+ assert(a..b..b..b..b..b..b..b == a)
+end
+
+do --- rhs
+ local a, b = create(function(a, b) return b end)
+ assert(a..b == b)
+ assert(b..a == a)
+ assert(a..b..b == b)
+ assert(a..a..b == b)
+ assert(b..b..a == a)
+ assert(a..a..a..a..a..a..a..b == b)
+end
+
+do --- mixed types
+ local a, b = create(function(a, b)
+ return (type(a) == "string" and a or a[1])..
+ (type(b) == "string" and b or b[1])
+ end, "a", "b")
+ assert(a..b == "ab")
+ assert(a..b == "ab")
+ assert(a..b..b == "abb")
+ assert(a..b..a == "aba")
+ assert(a..a..a..a..a..a..a..b == "aaaaaaab")
+ assert(a..a..a.."x".."x"..a..a..b == "aaaxxaab")
+ assert("x"..a..a..a..a..a..a..b == "xaaaaaab")
+ assert(a..b..a..b..a.."x".."x".."x" == "ababaxxx")
+end
+
+do --- jit mixed types
+ local a, b = create(function(a, b)
+ if a ~= b then local x = gg end
+ return (type(a) == "string" and a or a[1])..
+ (type(b) == "string" and b or b[1])
+ end, "a", "b")
+ local y
+ for i=1,100 do y = a..b end
+ assert(y == "ab")
+ for i=1,100 do y = a..b.."x" end
+ assert(y == "abx")
+ for i=1,100 do y = a..b.. 1 .. "z" end
+ assert(y == "ab1z")
+end
+
diff --git a/test/LuaJIT-tests/lang/meta/comp.lua b/test/LuaJIT-tests/lang/meta/comp.lua
new file mode 100644
index 0000000..23f18b0
--- /dev/null
+++ b/test/LuaJIT-tests/lang/meta/comp.lua
@@ -0,0 +1,120 @@
+
+local function create(comp, v1, v2)
+ local meta = {
+ __lt=function(a,b) return comp("lt", a, b) end,
+ __le=function(a,b) return comp("le", a, b) end,
+ }
+ return setmetatable({v1}, meta), setmetatable({v2}, meta)
+end
+
+do --- __lt and __le xop
+ local xop
+ local a, b = create(function(op,a,b) xop = op; return "" end)
+ assert(a<b == true and xop == "lt"); xop = nil
+ assert(a>b == true and xop == "lt"); xop = nil
+ assert(a<=b == true and xop == "le"); xop = nil
+ assert(a>=b == true and xop == "le"); xop = nil
+
+ assert(not (a<b) == false and xop == "lt"); xop = nil
+ assert(not (a>b) == false and xop == "lt"); xop = nil
+ assert(not (a<=b) == false and xop == "le"); xop = nil
+ assert(not (a>=b) == false and xop == "le"); xop = nil
+
+ -- __le metamethod is optional and substituted with arg+res inverted __lt.
+ local f = getmetatable(a).__le
+ getmetatable(a).__le = nil
+ assert(a<b == true and xop == "lt"); xop = nil
+ assert(a>b == true and xop == "lt"); xop = nil
+ assert(a<=b == false and xop == "lt"); xop = nil
+ assert(a>=b == false and xop == "lt"); xop = nil
+
+ assert(not (a<b) == false and xop == "lt"); xop = nil
+ assert(not (a>b) == false and xop == "lt"); xop = nil
+ assert(not (a<=b) == true and xop == "lt"); xop = nil
+ assert(not (a>=b) == true and xop == "lt"); xop = nil
+ getmetatable(a).__le = f
+
+ -- Different metatable, but same metamethod works, too.
+ setmetatable(b, { __lt = getmetatable(b).__lt, __le = getmetatable(b).__le })
+ assert(a<b == true and xop == "lt"); xop = nil
+ assert(a>b == true and xop == "lt"); xop = nil
+ assert(a<=b == true and xop == "le"); xop = nil
+ assert(a>=b == true and xop == "le"); xop = nil
+
+ assert(not (a<b) == false and xop == "lt"); xop = nil
+ assert(not (a>b) == false and xop == "lt"); xop = nil
+ assert(not (a<=b) == false and xop == "le"); xop = nil
+ assert(not (a>=b) == false and xop == "le"); xop = nil
+end
+
+do --- __lt and __le values
+ local a, b = create(function(op,a,b)
+ if op == "lt" then return a[1]<b[1] else return a[1]<=b[1] end end, 1, 2)
+ assert(a<b == true)
+ assert(a>b == false)
+ assert(a<=b == true)
+ assert(a>=b == false)
+
+ assert(not (a<b) == false)
+ assert(not (a>b) == true)
+ assert(not (a<=b) == false)
+ assert(not (a>=b) == true)
+
+ b[1] = 1
+ assert(a<b == false)
+ assert(a>b == false)
+ assert(a<=b == true)
+ assert(a>=b == true)
+
+ assert(not (a<b) == true)
+ assert(not (a>b) == true)
+ assert(not (a<=b) == false)
+ assert(not (a>=b) == false)
+
+ a[1] = 2
+ assert(a<b == false)
+ assert(a>b == true)
+ assert(a<=b == false)
+ assert(a>=b == true)
+
+ assert(not (a<b) == true)
+ assert(not (a>b) == false)
+ assert(not (a<=b) == true)
+ assert(not (a>=b) == false)
+
+ -- __le metamethod is optional and substituted with arg+res inverted __lt.
+ getmetatable(a).__le = nil
+ a[1] = 1
+ b[1] = 2
+ assert(a<b == true)
+ assert(a>b == false)
+ assert(a<=b == true)
+ assert(a>=b == false)
+
+ assert(not (a<b) == false)
+ assert(not (a>b) == true)
+ assert(not (a<=b) == false)
+ assert(not (a>=b) == true)
+
+ b[1] = 1
+ assert(a<b == false)
+ assert(a>b == false)
+ assert(a<=b == true)
+ assert(a>=b == true)
+
+ assert(not (a<b) == true)
+ assert(not (a>b) == true)
+ assert(not (a<=b) == false)
+ assert(not (a>=b) == false)
+
+ a[1] = 2
+ assert(a<b == false)
+ assert(a>b == true)
+ assert(a<=b == false)
+ assert(a>=b == true)
+
+ assert(not (a<b) == true)
+ assert(not (a>b) == false)
+ assert(not (a<=b) == true)
+ assert(not (a>=b) == false)
+end
diff --git a/test/LuaJIT-tests/lang/meta/comp_jit.lua b/test/LuaJIT-tests/lang/meta/comp_jit.lua
new file mode 100644
index 0000000..d0a19d8
--- /dev/null
+++ b/test/LuaJIT-tests/lang/meta/comp_jit.lua
@@ -0,0 +1,104 @@
+do --- coverage
+ local lt, le = false, false
+ local t, u = {}, {}
+ local x, ax, bx
+ local function ck(xx, a, b)
+ if x ~= xx then error("bad x", 2) end
+ if ax ~= a then error("bad ax", 2) end
+ if bx ~= b then error("bad bx", 2) end
+ end
+ local mt = {
+ __lt = function(a, b) ax=a; bx=b; return lt end,
+ __le = function(a, b) ax=a; bx=b; return le end,
+ }
+ t = setmetatable(t, mt)
+ u = setmetatable(u, mt)
+ lt, le = false, false
+ x = 0; for i=1,100 do x = t < u and 2 or 1 end ck(1, t, u)
+ x = 0; for i=1,100 do x = t <= u and 2 or 1 end ck(1, t, u)
+ x = 0; for i=1,100 do x = t > u and 2 or 1 end ck(1, u, t)
+ x = 0; for i=1,100 do x = t >= u and 2 or 1 end ck(1, u, t)
+ x = 0; for i=1,100 do x = not (t < u) and 2 or 1 end ck(2, t, u)
+ x = 0; for i=1,100 do x = not (t <= u) and 2 or 1 end ck(2, t, u)
+ x = 0; for i=1,100 do x = not (t > u) and 2 or 1 end ck(2, u, t)
+ x = 0; for i=1,100 do x = not (t >= u) and 2 or 1 end ck(2, u, t)
+ lt, le = false, true
+ x = 0; for i=1,100 do x = t < u and 2 or 1 end ck(1, t, u)
+ x = 0; for i=1,100 do x = t <= u and 2 or 1 end ck(2, t, u)
+ x = 0; for i=1,100 do x = t > u and 2 or 1 end ck(1, u, t)
+ x = 0; for i=1,100 do x = t >= u and 2 or 1 end ck(2, u, t)
+ x = 0; for i=1,100 do x = not (t < u) and 2 or 1 end ck(2, t, u)
+ x = 0; for i=1,100 do x = not (t <= u) and 2 or 1 end ck(1, t, u)
+ x = 0; for i=1,100 do x = not (t > u) and 2 or 1 end ck(2, u, t)
+ x = 0; for i=1,100 do x = not (t >= u) and 2 or 1 end ck(1, u, t)
+ lt, le = true, false
+ x = 0; for i=1,100 do x = t < u and 2 or 1 end ck(2, t, u)
+ x = 0; for i=1,100 do x = t <= u and 2 or 1 end ck(1, t, u)
+ x = 0; for i=1,100 do x = t > u and 2 or 1 end ck(2, u, t)
+ x = 0; for i=1,100 do x = t >= u and 2 or 1 end ck(1, u, t)
+ x = 0; for i=1,100 do x = not (t < u) and 2 or 1 end ck(1, t, u)
+ x = 0; for i=1,100 do x = not (t <= u) and 2 or 1 end ck(2, t, u)
+ x = 0; for i=1,100 do x = not (t > u) and 2 or 1 end ck(1, u, t)
+ x = 0; for i=1,100 do x = not (t >= u) and 2 or 1 end ck(2, u, t)
+ lt, le = true, true
+ x = 0; for i=1,100 do x = t < u and 2 or 1 end ck(2, t, u)
+ x = 0; for i=1,100 do x = t <= u and 2 or 1 end ck(2, t, u)
+ x = 0; for i=1,100 do x = t > u and 2 or 1 end ck(2, u, t)
+ x = 0; for i=1,100 do x = t >= u and 2 or 1 end ck(2, u, t)
+ x = 0; for i=1,100 do x = not (t < u) and 2 or 1 end ck(1, t, u)
+ x = 0; for i=1,100 do x = not (t <= u) and 2 or 1 end ck(1, t, u)
+ x = 0; for i=1,100 do x = not (t > u) and 2 or 1 end ck(1, u, t)
+ x = 0; for i=1,100 do x = not (t >= u) and 2 or 1 end ck(1, u, t)
+ mt.__le = nil
+ lt = false
+ x = 0; for i=1,100 do x = t < u and 2 or 1 end ck(1, t, u)
+ x = 0; for i=1,100 do x = t <= u and 2 or 1 end ck(2, u, t)
+ x = 0; for i=1,100 do x = t > u and 2 or 1 end ck(1, u, t)
+ x = 0; for i=1,100 do x = t >= u and 2 or 1 end ck(2, t, u)
+ x = 0; for i=1,100 do x = not (t < u) and 2 or 1 end ck(2, t, u)
+ x = 0; for i=1,100 do x = not (t <= u) and 2 or 1 end ck(1, u, t)
+ x = 0; for i=1,100 do x = not (t > u) and 2 or 1 end ck(2, u, t)
+ x = 0; for i=1,100 do x = not (t >= u) and 2 or 1 end ck(1, t, u)
+ lt = true
+ x = 0; for i=1,100 do x = t < u and 2 or 1 end ck(2, t, u)
+ x = 0; for i=1,100 do x = t <= u and 2 or 1 end ck(1, u, t)
+ x = 0; for i=1,100 do x = t > u and 2 or 1 end ck(2, u, t)
+ x = 0; for i=1,100 do x = t >= u and 2 or 1 end ck(1, t, u)
+ x = 0; for i=1,100 do x = not (t < u) and 2 or 1 end ck(1, t, u)
+ x = 0; for i=1,100 do x = not (t <= u) and 2 or 1 end ck(2, u, t)
+ x = 0; for i=1,100 do x = not (t > u) and 2 or 1 end ck(1, u, t)
+ x = 0; for i=1,100 do x = not (t >= u) and 2 or 1 end ck(2, t, u)
+end
+
+do --- Mixed metamethods for ordered comparisons.
+ local mt1 = { __lt = function(a, b) return a[1] < b[1] end }
+ local mt2 = { __lt = function(a, b) return a[1] < b[1] end }
+ local t1 = setmetatable({1}, mt1)
+ local t2 = setmetatable({2}, mt2)
+ do
+ local x
+ for i=1,100 do x = t1 <= t1 end
+ assert(x == true)
+ end
+ local ok, ret = pcall(function()
+ local x
+ for i=1,100 do x = t1 < t2 end
+ return x
+ end)
+ if table.pack then
+ assert(ok and ret == true)
+ else
+ assert(not ok)
+ end
+ local ok, ret = pcall(function()
+ local x
+ for i=1,100 do x = t1 <= t2 end
+ return x
+ end)
+ if table.pack then
+ assert(ok and ret == true)
+ else
+ assert(not ok)
+ end
+end
+
diff --git a/test/LuaJIT-tests/lang/meta/debuginfo.lua b/test/LuaJIT-tests/lang/meta/debuginfo.lua
new file mode 100644
index 0000000..a99941f
--- /dev/null
+++ b/test/LuaJIT-tests/lang/meta/debuginfo.lua
@@ -0,0 +1,81 @@
+
+local what
+
+local function mm(a, b)
+ local dbg = debug.getinfo(1)
+ what = dbg.namewhat == "metamethod" and dbg.name or
+ dbg.namewhat.." "..(dbg.name or "?")
+end
+
+local function ck(s)
+ assert(what == s, "bad debug info for metamethod "..s)
+end
+
+local mt = {
+ __index = mm,
+ __newindex = mm,
+ __eq = mm,
+ __add = mm,
+ __sub = mm,
+ __mul = mm,
+ __div = mm,
+ __mod = mm,
+ __pow = mm,
+ __unm = mm,
+ __len = mm,
+ __lt = mm,
+ __le = mm,
+ __concat = mm,
+ __call = mm,
+}
+
+do --- table metamethods +goto
+ local t = setmetatable({}, mt)
+ local t2 = setmetatable({}, mt)
+
+ local x = t.x; ck("__index")
+ t.x = 1; ck("__newindex")
+ local x = t + t; ck("__add")
+ local x = t - t; ck("__sub")
+ local x = t * t; ck("__mul")
+ local x = t / t; ck("__div")
+ local x = t % t; ck("__mod")
+ local x = t ^ t; ck("__pow")
+ local x = -t; ck("__unm")
+ local x = t..t; ck("__concat")
+ local x = t(); ck("local t")
+
+ local x = t == t2; ck("__eq")
+ local x = t ~= t2; ck("__eq")
+ local x = t < t2; ck("__lt")
+ local x = t > t2; ck("__lt")
+ local x = t <= t2; ck("__le")
+ local x = t >= t2; ck("__le")
+end
+
+do --- userdata metamethods +luajit
+ local u = newproxy()
+ local u2 = newproxy()
+ debug.setmetatable(u, mt)
+ debug.setmetatable(u2, mt)
+
+ local x = u.x; ck("__index")
+ u.x = 1; ck("__newindex")
+ local x = u + u; ck("__add")
+ local x = u - u; ck("__sub")
+ local x = u * u; ck("__mul")
+ local x = u / u; ck("__div")
+ local x = u % u; ck("__mod")
+ local x = u ^ u; ck("__pow")
+ local x = -u; ck("__unm")
+ local x = #u; ck("__len")
+ local x = u..u; ck("__concat")
+ local x = u(); ck("local u")
+
+ local x = u == u2; ck("__eq")
+ local x = u ~= u2; ck("__eq")
+ local x = u < u2; ck("__lt")
+ local x = u > u2; ck("__lt")
+ local x = u <= u2; ck("__le")
+ local x = u >= u2; ck("__le")
+end
diff --git a/test/LuaJIT-tests/lang/meta/eq.lua b/test/LuaJIT-tests/lang/meta/eq.lua
new file mode 100644
index 0000000..ebf6043
--- /dev/null
+++ b/test/LuaJIT-tests/lang/meta/eq.lua
@@ -0,0 +1,30 @@
+local function create(equal, v1, v2)
+ local meta = { __eq = equal }
+ return setmetatable({v1}, meta), setmetatable({v2}, meta)
+end
+
+do --- __eq xop
+ local xop
+ local a, b = create(function(a,b) xop = "eq" return "" end)
+ assert(a==b == true and xop == "eq"); xop = nil
+ assert(a~=b == false and xop == "eq"); xop = nil
+
+ -- Different metatable, but same metamethod works, too.
+ setmetatable(b, { __eq = getmetatable(b).__eq })
+ assert(a==b == true and xop == "eq"); xop = nil
+ assert(a~=b == false and xop == "eq"); xop = nil
+end
+
+do --- __eq values
+ local a, b = create(function(a,b) return a[1] == b[1] end, 1, 2)
+ assert(a==b == false)
+ assert(a~=b == true)
+
+ b[1] = 1
+ assert(a==b == true)
+ assert(a~=b == false)
+
+ a[1] = 2
+ assert(a==b == false)
+ assert(a~=b == true)
+end
diff --git a/test/LuaJIT-tests/lang/meta/eq_jit.lua b/test/LuaJIT-tests/lang/meta/eq_jit.lua
new file mode 100644
index 0000000..47e1420
--- /dev/null
+++ b/test/LuaJIT-tests/lang/meta/eq_jit.lua
@@ -0,0 +1,35 @@
+
+do --- coverage
+ local eq = false
+ local t, u = {}, {}
+ local x, ax, bx
+ local function ck(xx, a, b)
+ if x ~= xx then error("bad x", 2) end
+ if ax ~= a then error("bad ax", 2) end
+ if bx ~= b then error("bad bx", 2) end
+ end
+ local mt = {
+ __eq = function(a, b) ax=a; bx=b; return eq end,
+ }
+ t = setmetatable(t, mt)
+ u = setmetatable(u, mt)
+ eq = false
+ x = 0; for i=1,100 do x = t == u and 2 or 1 end ck(1, t, u)
+ x = 0; for i=1,100 do x = t ~= u and 2 or 1 end ck(2, t, u)
+ x = 0; for i=1,100 do x = not (t == u) and 2 or 1 end ck(2, t, u)
+ x = 0; for i=1,100 do x = not (t ~= u) and 2 or 1 end ck(1, t, u)
+ eq = true
+ x = 0; for i=1,100 do x = t == u and 2 or 1 end ck(2, t, u)
+ x = 0; for i=1,100 do x = t ~= u and 2 or 1 end ck(1, t, u)
+ x = 0; for i=1,100 do x = not (t == u) and 2 or 1 end ck(1, t, u)
+ x = 0; for i=1,100 do x = not (t ~= u) and 2 or 1 end ck(2, t, u)
+end
+
+do --- non-constant objects +bit
+ local bit = require("bit")
+ local mt = { __eq = function(a, b) return true end }
+ local tt = { [0] = setmetatable({}, mt), setmetatable({}, mt) }
+ for i=0,100 do
+ assert(tt[0] == tt[bit.band(i, 1)])
+ end
+end
diff --git a/test/LuaJIT-tests/lang/meta/framegap.lua b/test/LuaJIT-tests/lang/meta/framegap.lua
new file mode 100644
index 0000000..0080633
--- /dev/null
+++ b/test/LuaJIT-tests/lang/meta/framegap.lua
@@ -0,0 +1,24 @@
+do --- untitled
+ local t = setmetatable({}, { __add = function(a, b)
+ if b > 200 then
+ for j=1,10 do end
+ return b+3
+ elseif b > 100 then
+ return b+2
+ else
+ return b+1
+ end
+ end })
+
+ local function f(t, i)
+ do return t+i end
+ -- Force large frame with unassigned slots below mm.
+ do local a,b,c,d,e,f,g,h,i,j,k end
+ end
+
+ local x = 0
+ for i=1,300 do
+ x = f(t, i)
+ end
+ assert(x == 303)
+end
diff --git a/test/LuaJIT-tests/lang/meta/index b/test/LuaJIT-tests/lang/meta/index
new file mode 100644
index 0000000..f114e78
--- /dev/null
+++ b/test/LuaJIT-tests/lang/meta/index
@@ -0,0 +1,14 @@
+arith.lua
+arith_jit.lua
+call.lua
+cat.lua
+comp.lua
+comp_jit.lua
+eq.lua
+eq_jit.lua
+framegap.lua
+index.lua
+len.lua
+newindex.lua
+nomm.lua
+debuginfo.lua
diff --git a/test/LuaJIT-tests/lang/meta/index.lua b/test/LuaJIT-tests/lang/meta/index.lua
new file mode 100644
index 0000000..4d6d0ff
--- /dev/null
+++ b/test/LuaJIT-tests/lang/meta/index.lua
@@ -0,0 +1,60 @@
+do --- table 1
+ local t=setmetatable({}, {__index=function(t,k)
+ return 100-k
+ end})
+
+ for i=1,100 do assert(t[i] == 100-i) end
+
+ for i=1,100 do t[i] = i end
+ for i=1,100 do assert(t[i] == i) end
+
+ for i=1,100 do t[i] = nil end
+ for i=1,100 do assert(t[i] == 100-i) end
+end
+
+do --- table 2
+ local x
+ local t2=setmetatable({}, {__index=function(t,k)
+ x = k
+ end})
+
+ assert(t2[1] == nil)
+ assert(x == 1)
+
+ assert(t2.foo == nil)
+ assert(x == "foo")
+end
+
+do --- userdata +lua<5.2
+ local u = newproxy(true)
+ getmetatable(u).__index = { foo = u, bar = 42 }
+
+ local x = 0
+ for i=1,100 do
+ x = x + u.bar
+ u = u.foo
+ end
+ assert(x == 4200)
+
+ x = 0
+ for i=1,100 do
+ u = u.foo
+ x = x + u.bar
+ end
+ assert(x == 4200)
+end
+
+do --- string
+ local s = "foo"
+ local mt = debug.getmetatable(s)
+ debug.setmetatable(s, {__index = {s = s, len = string.len}})
+ local x = 0
+ local t = {}
+ for i=1,100 do
+ x = x + s:len()
+ s = s.s
+ t[s] = t -- Hash store with same type prevents hoisting
+ end
+ debug.setmetatable(s, mt)
+ assert(x == 300)
+end
diff --git a/test/LuaJIT-tests/lang/meta/len.lua b/test/LuaJIT-tests/lang/meta/len.lua
new file mode 100644
index 0000000..2410daa
--- /dev/null
+++ b/test/LuaJIT-tests/lang/meta/len.lua
@@ -0,0 +1,42 @@
+local compat52 = table.pack
+local mt = { __len = function(o, o2)
+ if compat52 then
+ assert(o2 == o)
+ else
+ assert(o2 == nil)
+ end
+ return 42
+end }
+
+do --- table
+ local t = {1,2,3}
+ assert(#t == 3)
+ assert(#"abcdef" == 6)
+
+ setmetatable(t, { __foo = function() end })
+ assert(#t == 3)
+ assert(#t == 3)
+
+ setmetatable(t, mt)
+ if compat52 then
+ assert(#t == 42) -- __len DOES work on tables.
+ assert(rawlen(t) == 3)
+ else
+ assert(#t == 3) -- __len does NOT work on tables.
+ end
+end
+
+do --- userdata +lua<5.2
+ local u = newproxy(true)
+ getmetatable(u).__len = function(o) return 42 end
+ assert(#u == 42)
+ local x = 0
+ for i=1,100 do x = x + #u end
+ assert(x == 4200)
+end
+
+do --- number
+ debug.setmetatable(0, mt)
+ assert(#1 == 42)
+ debug.setmetatable(0, nil)
+end
diff --git a/test/LuaJIT-tests/lang/meta/newindex.lua b/test/LuaJIT-tests/lang/meta/newindex.lua
new file mode 100644
index 0000000..6c46b8c
--- /dev/null
+++ b/test/LuaJIT-tests/lang/meta/newindex.lua
@@ -0,0 +1,69 @@
+do --- table 1
+ local t=setmetatable({}, {__newindex=function(t,k,v)
+ rawset(t, k, 100-v)
+ end})
+
+ for i=1,100 do t[i] = i end
+ for i=1,100 do assert(t[i] == 100-i) end
+
+ for i=1,100 do t[i] = i end
+ for i=1,100 do assert(t[i] == i) end
+
+ for i=1,100 do t[i] = nil end
+ for i=1,100 do t[i] = i end
+ for i=1,100 do assert(t[i] == 100-i) end
+end
+
+do --- jit gaining href
+ local count = 0
+ local t = setmetatable({ foo = nil },
+ { __newindex=function() count = count + 1 end })
+ for j=1,2 do
+ for i=1,100 do t.foo = 1 end
+ rawset(t, "foo", 1)
+ end
+ assert(count == 100)
+end
+
+do --- jit gaining aref
+ local count = 0
+ local t = setmetatable({ nil },
+ { __newindex=function() count = count + 1 end })
+ for j=1,2 do
+ for i=1,100 do t[1] = 1 end
+ rawset(t, 1, 1)
+ end
+ assert(count == 100)
+end
+
+do --- resize
+ local grandparent = {}
+ grandparent.__newindex = function(s,_,_) tostring(s) end
+
+ local parent = {}
+ parent.__newindex = parent
+ parent.bar = 1
+ setmetatable(parent, grandparent)
+
+ local child = setmetatable({}, parent)
+ child.foo = _
+end
+
+do --- str
+ local t=setmetatable({}, {__newindex=function(t,k,v)
+ assert(v == "foo"..k)
+ rawset(t, k, "bar"..k)
+ end})
+
+ for i=1,100 do t[i]="foo"..i end
+ for i=1,100 do assert(t[i] == "bar"..i) end
+
+ for i=1,100 do t[i]="baz"..i end
+ for i=1,100 do assert(t[i] == "baz"..i) end
+
+ local t=setmetatable({foo=1,bar=1,baz=1},{})
+ t.baz=nil
+ t.baz=2
+ t.baz=nil
+ t.baz=2
+end
diff --git a/test/LuaJIT-tests/lang/meta/nomm.lua b/test/LuaJIT-tests/lang/meta/nomm.lua
new file mode 100644
index 0000000..2b3db86
--- /dev/null
+++ b/test/LuaJIT-tests/lang/meta/nomm.lua
@@ -0,0 +1,21 @@
+
+do --- untitled
+ local keys = {}
+ for i=1,100 do keys[i] = "foo" end
+ keys[95] = "__index"
+ local function fidx(t, k) return 12345 end
+ local mt = { foo = 1, __index = "" }
+ local t = setmetatable({ 1 }, mt)
+ t[1] = nil
+ mt.__index = nil
+ local x = nil
+ for i=1,100 do
+ mt[keys[i]] = fidx
+ if t[1] then
+ if not x then x = i end
+ assert(t[1] == 12345)
+ end
+ end
+ assert(x == 95)
+end
+
diff --git a/test/LuaJIT-tests/lang/modulo.lua b/test/LuaJIT-tests/lang/modulo.lua
new file mode 100644
index 0000000..eddaea7
--- /dev/null
+++ b/test/LuaJIT-tests/lang/modulo.lua
@@ -0,0 +1,46 @@
+local assert, floor = assert, math.floor
+
+do --- integer equivalence
+ for x=-5,5 do
+ for y=-5,5 do
+ if y ~= 0 then
+ assert(x%y == x-floor(x/y)*y)
+ end
+ end
+ end
+end
+
+do --- fractional equivalence
+ for x=-5,5,0.25 do
+ for y=-5,5,0.25 do
+ if y ~= 0 then
+ assert(x%y == x-floor(x/y)*y)
+ end
+ end
+ end
+end
+
+do --- jit constant RHS
+ local y = 0
+ for x=-100,123 do
+ y = y + x%17
+ end
+ assert(y == 1777)
+end
+
+do --- jit constant LHS, with exit
+ local y = 0
+ for x=-100,123 do
+ if x ~= 0 then
+ y = y + 85%x
+ end
+ end
+ assert(y == 2059)
+end
+
+do --- divide by zero
+ local x = 1%0
+ assert(x ~= x)
+ x = floor(0/0)
+ assert(x ~= x)
+end
diff --git a/test/LuaJIT-tests/lang/self.lua b/test/LuaJIT-tests/lang/self.lua
new file mode 100644
index 0000000..d374666
--- /dev/null
+++ b/test/LuaJIT-tests/lang/self.lua
@@ -0,0 +1,19 @@
+do --- trivial setget
+ local t = {}
+
+ function t:set(x)
+ self.a=x
+ end
+
+ function t:get()
+ return self.a
+ end
+
+ t:set("foo")
+ assert(t:get() == "foo")
+ assert(t.a == "foo")
+
+ t:set(42)
+ assert(t:get() == 42)
+ assert(t.a == 42)
+end
diff --git a/test/LuaJIT-tests/lang/table.lua b/test/LuaJIT-tests/lang/table.lua
new file mode 100644
index 0000000..3ff38cf
--- /dev/null
+++ b/test/LuaJIT-tests/lang/table.lua
@@ -0,0 +1,32 @@
+do --- tables as keys in tables
+ local fwd, bck = {}, {}
+ for i = 1,100 do
+ local v = {}
+ fwd[i] = v
+ bck[v] = i
+ end
+ for i = 1,100 do
+ local v = fwd[i]
+ assert(type(v) == "table")
+ assert(bck[v] == i)
+ end
+end
+
+do --- some tables as keys in tables
+ local fwd, bck = {}, {}
+ for i = 1,100 do
+ local v = {}
+ fwd[i] = v
+ if i > 90 then
+ bck[v] = i
+ end
+ end
+ local n = 0
+ for i = 1, 100 do
+ local v = fwd[i]
+ if bck[v] then
+ n = n + 1
+ end
+ end
+ assert(n == 10)
+end
diff --git a/test/LuaJIT-tests/lang/tail_recursion.lua b/test/LuaJIT-tests/lang/tail_recursion.lua
new file mode 100644
index 0000000..78f071f
--- /dev/null
+++ b/test/LuaJIT-tests/lang/tail_recursion.lua
@@ -0,0 +1,20 @@
+do --- self
+ local tr1
+ function tr1(n)
+ if n <= 0 then return 0 end
+ return tr1(n-1)
+ end
+ assert(tr1(200) == 0)
+end
+
+do --- mutual
+ local tr1, tr2
+ function tr1(n)
+ if n <= 0 then return 0 end
+ return tr2(n-1)
+ end
+ function tr2(n)
+ return tr1(n)
+ end
+ assert(tr2(200) == 0)
+end
diff --git a/test/LuaJIT-tests/lang/upvalue/closure.lua b/test/LuaJIT-tests/lang/upvalue/closure.lua
new file mode 100644
index 0000000..faa4de1
--- /dev/null
+++ b/test/LuaJIT-tests/lang/upvalue/closure.lua
@@ -0,0 +1,84 @@
+do --- for
+ local z1, z2
+ for i=1,10 do
+ local function f() return i end
+ if z1 then z2 = f else z1 = f end
+ end
+ assert(z1() == 1)
+ assert(z2() == 10)
+end
+
+do --- while
+ local z1, z2
+ local i = 1
+ while i <= 10 do
+ local j = i
+ local function f() return j end
+ if z1 then z2 = f else z1 = f end
+ i = i + 1
+ end
+ assert(z1() == 1)
+ assert(z2() == 10)
+end
+
+do --- repeat
+ local z1, z2
+ local i = 1
+ repeat
+ local j = i
+ local function f() return j end
+ if z1 then z2 = f else z1 = f end
+ i = i + 1
+ until i > 10
+ assert(z1() == 1)
+ assert(z2() == 10)
+end
+
+do --- func
+ local function ff(x)
+ return function() return x end
+ end
+ local z1, z2
+ for i=1,10 do
+ local f = ff(i)
+ if z1 then z2 = f else z1 = f end
+ end
+ assert(z1() == 1)
+ assert(z2() == 10)
+end
+
+do --- recursive type change
+ local function f1(a)
+ if a > 0 then
+ local b = f1(a - 1)
+ return function()
+ if type(b) == "function" then
+ return a + b()
+ end
+ return a + b
+ end
+ end
+ return a
+ end
+
+ local function f2(a)
+ return f1(a)()
+ end
+
+ for i = 1, 41 do
+ local r = f2(4) + f2(4)
+ assert(r == 20)
+ end
+end
+
+do --- Don't mark upvalue as immutable if written to after prototype definition
+ local x = 1
+ local function f()
+ local y = 0
+ for i=1,100 do y=y+x end
+ return y
+ end
+ assert(f() == 100)
+ x = 2
+ assert(f() == 200)
+end
diff --git a/test/LuaJIT-tests/lang/upvalue/index b/test/LuaJIT-tests/lang/upvalue/index
new file mode 100644
index 0000000..3c170db
--- /dev/null
+++ b/test/LuaJIT-tests/lang/upvalue/index
@@ -0,0 +1 @@
+closure.lua
diff --git a/test/LuaJIT-tests/lang/vararg_jit.lua b/test/LuaJIT-tests/lang/vararg_jit.lua
new file mode 100644
index 0000000..4e78f96
--- /dev/null
+++ b/test/LuaJIT-tests/lang/vararg_jit.lua
@@ -0,0 +1,95 @@
+
+do --- 1
+ local function f(a, b, c, ...)
+ assert(c == nil)
+ assert(a == 100-b)
+ return 100-a, 100-b
+ end
+ for i=1,100 do
+ local x, y = f(i, 100-i)
+ assert(x == 100-i)
+ assert(y == i)
+ end
+end
+
+do --- 2
+ local function f(a, b, ...)
+ if a > b then return b end
+ return a
+ end
+ local x = 0
+ for i=1,200 do
+ x = x + f(i, 100, 99, 88, 77)
+ end
+ assert(x == 15050)
+end
+
+do --- 3
+ local function f(a, b, ...)
+ local c, d = ...
+ if c > d then return d end
+ return c
+ end
+ local x = 0
+ for i=1,200 do
+ x = x + f(77, 88, i, 100)
+ end
+ assert(x == 15050)
+end
+
+do --- 4
+ local function f(a, b, ...)
+ if a > b then end
+ return ...
+ end
+ local x = 0
+ for i=1,200 do
+ x = x + f(i, 100, i, 100)
+ assert(f(i, 100) == nil)
+ assert(f(i, 100, 2) == 2)
+ end
+ assert(x == 20100)
+end
+
+do --- 5
+ local function f(a, ...)
+ local x, y = 0, 0
+ for i=1,100 do
+ local b, c = ...
+ x = x + b
+ y = y + c
+ end
+ assert(x == 200 and y == 300)
+ end
+ f(1, 2, 3)
+end
+
+do --- 6
+ local function f(a, ...)
+ local t = {[0]=9, 9}
+ local v, w, x, y = 0, 0, 0, 0
+ for i=1,100 do
+ v, w = ...
+ t[0] = 9; t[1] = 9;
+ x, y = ...
+ end
+ assert(v == 2 and w == 3 and x == 2 and y == 3)
+ end
+ f(1, 2, 3)
+end
+
+do --- 7
+ local function f(a, b, ...)
+ for i=1,100 do
+ local c, d = ...
+ assert(a == c);
+ assert(b == d);
+ end
+ end
+ f(2, 3, 2, 3)
+ f(2, nil, 2)
+ f(nil, nil)
+ f(nil)
+ f()
+end
+
diff --git a/test/LuaJIT-tests/lib/base/assert.lua b/test/LuaJIT-tests/lib/base/assert.lua
new file mode 100644
index 0000000..9c30ba0
--- /dev/null
+++ b/test/LuaJIT-tests/lib/base/assert.lua
@@ -0,0 +1,33 @@
+do --- pass through one
+ assert(assert(true) == true)
+ assert(assert(3) == 3)
+ assert(assert(1.5) == 1.5)
+ assert(assert("x") == "x")
+ local f = function() end
+ assert(assert(f) == f)
+ local t = {}
+ assert(assert(t) == t)
+end
+
+do --- pass through many
+ local b, c = assert("b", "c")
+ assert(b == "b")
+ assert(c == "c")
+ local d, e, f, g = assert("d", 5, true, false)
+ assert(d == "d")
+ assert(e == 5)
+ assert(f == true)
+ assert(g == false)
+end
+
+do --- raise on nil
+ local ok, err = pcall(assert, nil)
+ assert(ok == false)
+ assert(err == "assertion failed!")
+end
+
+do --- raise on false
+ local ok, err = pcall(assert, false, "msg")
+ assert(ok == false)
+ assert(err == "msg")
+end
diff --git a/test/LuaJIT-tests/lib/base/error.lua b/test/LuaJIT-tests/lib/base/error.lua
new file mode 100644
index 0000000..9193085
--- /dev/null
+++ b/test/LuaJIT-tests/lib/base/error.lua
@@ -0,0 +1,43 @@
+do --- no message
+ local ok, msg = pcall(error)
+ assert(ok == false)
+ assert(msg == nil)
+end
+
+do --- level 0
+ local ok, msg = pcall(error, "emsg", 0)
+ assert(ok == false)
+ assert(msg == "emsg")
+end
+
+do --- default level
+ local ok, msg = pcall(error, "emsg")
+ assert(ok == false)
+ assert(msg == "emsg")
+end
+
+do --- default level in xpcall
+ local line
+ local ok, msg = xpcall(function()
+ local x
+ line = debug.getinfo(1, "l").currentline; error("emsg")
+ end, function(m)
+ assert(debug.getlocal(3, 1) == "x")
+ return m .."xp"
+ end)
+ assert(ok == false)
+ assert(msg:find("^.-:".. line ..": emsgxp$"))
+end
+
+do --- level 2 in xpcall
+ local line
+ local ok, msg = xpcall(function()
+ local function f() error("emsg", 2) end
+ line = debug.getinfo(1, "l").currentline; f()
+ end, function(m)
+ assert(debug.getlocal(4, 1) == "f")
+ return m .."xp2"
+ end)
+ assert(ok == false)
+ assert(msg:find("^.-:".. line ..": emsgxp2$"))
+end
diff --git a/test/LuaJIT-tests/lib/base/getfenv.lua b/test/LuaJIT-tests/lib/base/getfenv.lua
new file mode 100644
index 0000000..9c00ed7
--- /dev/null
+++ b/test/LuaJIT-tests/lib/base/getfenv.lua
@@ -0,0 +1,13 @@
+do --- untitled
+ local x
+ local function f()
+ x = getfenv(0)
+ end
+ local co = coroutine.create(f)
+ local t = {}
+ debug.setfenv(co, t)
+ for i=1,50 do f() f() f() end
+ assert(x == getfenv(0))
+ coroutine.resume(co)
+ assert(x == t)
+end
diff --git a/test/LuaJIT-tests/lib/base/getsetmetatable.lua b/test/LuaJIT-tests/lib/base/getsetmetatable.lua
new file mode 100644
index 0000000..7d57343
--- /dev/null
+++ b/test/LuaJIT-tests/lib/base/getsetmetatable.lua
@@ -0,0 +1,33 @@
+
+do --- get __metatable
+ local t = setmetatable({}, { __metatable = "foo" })
+ for i=1,100 do assert(getmetatable(t) == "foo") end
+end
+
+do --- jit smoke
+ local mt = {}
+ local t = setmetatable({}, mt)
+ for i=1,100 do assert(getmetatable(t) == mt) end
+ for i=1,100 do assert(setmetatable(t, mt) == t) end
+end
+
+do --- jit assorted
+ local mt = {}
+ local t = {}
+ for i=1,200 do t[i] = setmetatable({}, mt) end
+ t[150] = setmetatable({}, { __metatable = "foo" })
+ for i=1,200 do
+ if not pcall(setmetatable, t[i], mt) then assert(i == 150) end
+ end
+ for i=1,200 do assert(getmetatable(t[i]) == mt or i == 150) end
+ for i=1,200 do
+ if not pcall(setmetatable, t[i], nil) then assert(i == 150) end
+ end
+ for i=1,200 do assert(getmetatable(t[i]) == nil or i == 150) end
+end
+
+do --- jit get primitive metatable
+ local x = true
+ for i=1,100 do x = getmetatable(i) end
+ assert(x == nil)
+end
diff --git a/test/LuaJIT-tests/lib/base/index b/test/LuaJIT-tests/lib/base/index
new file mode 100644
index 0000000..942c53c
--- /dev/null
+++ b/test/LuaJIT-tests/lib/base/index
@@ -0,0 +1,11 @@
+assert.lua
+error.lua
+getfenv.lua +lua<5.2
+getsetmetatable.lua
+ipairs.lua
+next.lua
+pairs.lua
+pcall_jit.lua
+select.lua
+tonumber_tostring.lua
+xpcall_jit.lua +compat5.2
diff --git a/test/LuaJIT-tests/lib/base/ipairs.lua b/test/LuaJIT-tests/lib/base/ipairs.lua
new file mode 100644
index 0000000..a9de087
--- /dev/null
+++ b/test/LuaJIT-tests/lib/base/ipairs.lua
@@ -0,0 +1,41 @@
+do --- small integer values
+ local t = { 4,5,6,7,8,9,10 }
+ local n = 0
+ for i,v in ipairs(t) do
+ assert(v == i+3)
+ n = n + 1
+ end
+ assert(n == 7)
+end
+
+do --- jit key=value
+ local t = {}
+ for i=1,100 do t[i]=i end
+ local n = 0
+ for i,v in ipairs(t) do
+ assert(i == v)
+ n = n + 1
+ end
+ assert(n == 100)
+end
+
+do --- untitled
+ local t = {}
+ local o = {{}, {}}
+ for i=1,100 do
+ local c = i..""
+ t[i] = c
+ o[1][c] = i
+ o[2][c] = i
+ end
+ o[1]["90"] = nil
+
+ local n = 0
+ for _, c in ipairs(t) do
+ for i = 1, 2 do
+ o[i][c] = o[i][c] or 1
+ n = n + 1
+ end
+ end
+ assert(n == 200)
+end
diff --git a/test/LuaJIT-tests/lib/base/next.lua b/test/LuaJIT-tests/lib/base/next.lua
new file mode 100644
index 0000000..0e40615
--- /dev/null
+++ b/test/LuaJIT-tests/lib/base/next.lua
@@ -0,0 +1,17 @@
+do --- _G 1
+ local ok, err = pcall(next, _G, 1)
+ assert(not ok)
+ local ok, err = pcall(function() next(_G, 1) end)
+ assert(not ok)
+end
+
+do --- as iterator
+ local t = { foo = 9, bar = 10, 4, 5, 6 }
+ local r = {}
+ local function dummy() end
+ local function f(next)
+ for k,v in next,t,nil do r[#r+1] = k; if v == 5 then f(dummy) end end
+ end
+ f(next)
+ assert(#r == 5)
+end
diff --git a/test/LuaJIT-tests/lib/base/pairs.lua b/test/LuaJIT-tests/lib/base/pairs.lua
new file mode 100644
index 0000000..4d89d42
--- /dev/null
+++ b/test/LuaJIT-tests/lib/base/pairs.lua
@@ -0,0 +1,73 @@
+
+do --- nometatable
+ local t = {}
+ for i=1,10 do t[i] = i+100 end
+ local a, b = 0, 0
+ for j=1,100 do for k,v in ipairs(t) do a = a + k; b = b + v end end
+ assert(a == 5500)
+ assert(b == 105500)
+ a, b = 0, 0
+ for j=1,100 do for k,v in pairs(t) do a = a + k; b = b + v end end
+ assert(a == 5500)
+ assert(b == 105500)
+end
+
+do --- empty metatable
+ local t = setmetatable({}, {})
+ for i=1,10 do t[i] = i+100 end
+ local a, b = 0, 0
+ for j=1,100 do for k,v in ipairs(t) do a = a + k; b = b + v end end
+ assert(a == 5500)
+ assert(b == 105500)
+ a, b = 0, 0
+ for j=1,100 do for k,v in pairs(t) do a = a + k; b = b + v end end
+ assert(a == 5500)
+ assert(b == 105500)
+end
+
+do --- metamethods +compat5.2
+ local function iter(t, i)
+ i = i + 1
+ if t[i] then return i, t[i]+2 end
+ end
+ local function itergen(t)
+ return iter, t, 0
+ end
+ local t = setmetatable({}, { __pairs = itergen, __ipairs = itergen })
+ for i=1,10 do t[i] = i+100 end
+ local a, b = 0, 0
+ for j=1,100 do for k,v in ipairs(t) do a = a + k; b = b + v end end
+ assert(a == 5500)
+ assert(b == 107500)
+ a, b = 0, 0
+ for j=1,100 do for k,v in pairs(t) do a = a + k; b = b + v end end
+ assert(a == 5500)
+ assert(b == 107500)
+end
+
+do --- _G
+ local n = 0
+ for k,v in pairs(_G) do
+ assert(_G[k] == v)
+ n = n + 1
+ end
+ assert(n >= 35)
+end
+
+do --- count
+ local function count(t)
+ local n = 0
+ for i,v in pairs(t) do
+ n = n + 1
+ end
+ return n;
+ end
+ assert(count({ 4,5,6,nil,8,nil,10}) == 5)
+ assert(count({ [0] = 3, 4,5,6,nil,8,nil,10}) == 6)
+ assert(count({ foo=1, bar=2, baz=3 }) == 3)
+ assert(count({ foo=1, bar=2, baz=3, boo=4 }) == 4)
+ assert(count({ 4,5,6,nil,8,nil,10, foo=1, bar=2, baz=3 }) == 8)
+ local t = { foo=1, bar=2, baz=3, boo=4 }
+ t.bar = nil; t.boo = nil
+ assert(count(t) == 2)
+end
diff --git a/test/LuaJIT-tests/lib/base/pcall_jit.lua b/test/LuaJIT-tests/lib/base/pcall_jit.lua
new file mode 100644
index 0000000..dc9cd5f
--- /dev/null
+++ b/test/LuaJIT-tests/lib/base/pcall_jit.lua
@@ -0,0 +1,74 @@
+
+do --- square sum
+ local function f(x) return x*x end
+ local x = 0
+ for i=1,100 do
+ local ok1, ok2, ok3, y = pcall(pcall, pcall, f, i)
+ if not ok1 or not ok2 or not ok3 then break end
+ x = x + y
+ end
+ assert(x == 338350)
+end
+
+do --- sqrt square sum
+ local x = 0
+ for i=1,100 do
+ local ok1, ok2, ok3, y = pcall(pcall, pcall, math.sqrt, i*i)
+ if not ok1 or not ok2 or not ok3 then break end
+ x = x + y
+ end
+ assert(x == 5050)
+end
+
+do --- sum with error
+ local function f(x)
+ if x >= 150 then error("test", 0) end
+ return x end
+ local x = 0
+ for i=1,200 do
+ local ok1, ok2, ok3, y = pcall(pcall, pcall, f, i)
+ if not ok1 or not ok2 or not ok3 then
+ assert(ok1 and ok2 and not ok3)
+ assert(y == "test")
+ break
+ end
+ x = x + y
+ end
+ assert(x == 11175)
+end
+
+do --- sum or square
+ local function f(x)
+ if x >= 150 then return x*x end
+ return x
+ end
+ local x = 0
+ for i=1,200 do
+ local ok1, ok2, ok3, y = pcall(pcall, pcall, f, i)
+ if not ok1 or not ok2 or not ok3 then break end
+ x = x + y
+ end
+ assert(x == 1584100)
+end
+
+do --- sum or square with error
+ local function f(x)
+ if x >= 150 then
+ if x >= 175 then error("test", 0) end
+ return x*x
+ end
+ return x
+ end
+ local x = 0
+ for i=1,200 do
+ local ok1, ok2, ok3, y = pcall(pcall, pcall, f, i)
+ if not ok1 or not ok2 or not ok3 then
+ assert(ok1 and ok2 and not ok3)
+ assert(y == "test")
+ -- note: no break, so we get an exit to interpreter
+ else
+ x = x + y
+ end
+ end
+ assert(x == 668575)
+end
diff --git a/test/LuaJIT-tests/lib/base/select.lua b/test/LuaJIT-tests/lib/base/select.lua
new file mode 100644
index 0000000..8278e5e
--- /dev/null
+++ b/test/LuaJIT-tests/lib/base/select.lua
@@ -0,0 +1,105 @@
+
+do --- select #
+-- Test whether select("#", 3, 4) returns the correct number of arguments.
+ local x = 0
+ for i=1,100 do
+ x = x + select("#", 3, 4)
+ end
+ assert(x == 200)
+end
+
+do --- select modf
+-- Test whether select("#", func()) also works with func returning multiple values
+ local x = 0
+ math.frexp(3)
+ for i=1,100 do
+ x = x + select("#", math.modf(i))
+ end
+ assert(x == 200)
+end
+
+do --- select 1
+ local x = 0
+ for i=1,100 do
+ x = x + select(1, i)
+ end
+ assert(x == 5050)
+end
+
+do --- select 2
+ local x, y = 0, 0
+ for i=1,100 do
+ local a, b = select(2, 1, i, i+10)
+ x = x + a
+ y = y + b
+ end
+ assert(x == 5050 and y == 6050)
+end
+
+do --- select vararg #
+ local function f(a, ...)
+ local x = 0
+ for i=1,select('#', ...) do
+ x = x + select(i, ...)
+ end
+ assert(x == a)
+ end
+ for i=1,100 do
+ f(1, 1)
+ f(3, 1, 2)
+ f(15, 1, 2, 3, 4, 5)
+ f(0)
+ f(3200, string.byte(string.rep(" ", 100), 1, 100))
+ end
+end
+
+do --- select vararg i
+ local function f(a, ...)
+ local x = 0
+ for i=1,20 do
+ local b = select(i, ...)
+ if b then x = x + b else x = x + 9 end
+ end
+ assert(x == a)
+ end
+ for i=1,100 do
+ f(172, 1)
+ f(165, 1, 2)
+ f(150, 1, 2, 3, 4, 5)
+ f(180)
+ f(640, string.byte(string.rep(" ", 100), 1, 100))
+ end
+end
+
+do --- select vararg 4
+ local function f(a, ...)
+ local x = 0
+ for i=1,20 do
+ local b = select(4, ...)
+ if b then x = x + b else x = x + 9 end
+ end
+ assert(x == a)
+ end
+ for i=1,100 do
+ f(180, 1)
+ f(180, 1, 2)
+ f(80, 1, 2, 3, 4, 5)
+ f(180)
+ f(640, string.byte(string.rep(" ", 100), 1, 100))
+ end
+end
+
+do --- varg-select specialisation requires guard against select
+ local select = select
+ local exptyp = "number"
+ local function f(...)
+ for i = 1, 100 do
+ assert(type((select('#', ...))) == exptyp)
+ if i == 75 then
+ select = function() return "" end
+ exptyp = "string"
+ end
+ end
+ end
+ f(1)
+end
diff --git a/test/LuaJIT-tests/lib/base/tonumber_tostring.lua b/test/LuaJIT-tests/lib/base/tonumber_tostring.lua
new file mode 100644
index 0000000..e7f576c
--- /dev/null
+++ b/test/LuaJIT-tests/lib/base/tonumber_tostring.lua
@@ -0,0 +1,81 @@
+
+do --- tonumber int
+ local x = 0
+ for i=1,100 do x = x + tonumber(i) end
+ assert(x == 5050)
+end
+
+do --- tonumber float
+ local x = 0
+ for i=1.5,100.5 do x = x + tonumber(i) end
+ assert(x == 5100)
+end
+
+do --- tostring int / tonumber
+ local t = {}
+ for i=1,100 do t[i] = tostring(i) end
+ local x = 0
+ for i=1,100 do assert(type(t[i]) == "string"); x = x + tonumber(t[i]) end
+ assert(x == 5050)
+end
+
+do --- tostring float / tonumber
+ local t = {}
+ for i=1,100 do t[i] = tostring(i+0.5) end
+ local x = 0
+ for i=1,100 do assert(type(t[i]) == "string"); x = x + tonumber(t[i]) end
+ assert(x == 5100)
+end
+
+do --- tonumber table
+ for i=1,100 do assert(tonumber({}) == nil) end
+end
+
+do --- tostring int / tostring
+ local t = {}
+ for i=1,100 do t[i] = tostring(i) end
+ for i=1,100 do t[i] = tostring(t[i]) end
+ local x = 0
+ for i=1,100 do assert(type(t[i]) == "string"); x = x + t[i] end
+ assert(x == 5050)
+end
+
+do --- tostring table __tostring
+ local mt = { __tostring = function(t) return tostring(t[1]) end }
+ local t = {}
+ for i=1,100 do t[i] = setmetatable({i}, mt) end
+ for i=1,100 do t[i] = tostring(t[i]) end
+ local x = 0
+ for i=1,100 do assert(type(t[i]) == "string"); x = x + t[i] end
+ assert(x == 5050)
+end
+
+do --- tostring table __tostring __call
+ local r = setmetatable({},
+ { __call = function(x, t) return tostring(t[1]) end })
+ local mt = { __tostring = r }
+ local t = {}
+ for i=1,100 do t[i] = setmetatable({i}, mt) end
+ for i=1,100 do t[i] = tostring(t[i]) end
+ local x = 0
+ for i=1,100 do assert(type(t[i]) == "string"); x = x + t[i] end
+ assert(x == 5050)
+end
+
+do --- print calls overridden tostring +lua<5.2
+ local x = false
+ local co = coroutine.create(function() print(1) end)
+ debug.setfenv(co, setmetatable({}, { __index = {
+ tostring = function() x = true end }}))
+ coroutine.resume(co)
+ assert(x == true)
+end
+
+do --- tonumber base 2
+ assert(tonumber(111, 2) == 7)
+end
+
+do --- __tostring must be callable
+ local t = setmetatable({}, { __tostring = "" })
+ assert(pcall(function() tostring(t) end) == false)
+end
diff --git a/test/LuaJIT-tests/lib/base/xpcall_jit.lua b/test/LuaJIT-tests/lib/base/xpcall_jit.lua
new file mode 100644
index 0000000..f4993cc
--- /dev/null
+++ b/test/LuaJIT-tests/lib/base/xpcall_jit.lua
@@ -0,0 +1,83 @@
+local function tr(err) return "tr"..err end
+
+do --- square sum
+ local function f(x) return x*x end
+ local x = 0
+ for i=1,100 do
+ local ok1, ok2, ok3, y = xpcall(xpcall, tr, xpcall, tr, f, tr, i)
+ if not ok1 or not ok2 or not ok3 then break end
+ x = x + y
+ end
+ assert(x == 338350)
+end
+
+do --- sqrt square sum
+ local x = 0
+ for i=1,100 do
+ local ok1, ok2, ok3, y = xpcall(xpcall, tr, xpcall, tr, math.sqrt, tr, i*i)
+ if not ok1 or not ok2 or not ok3 then break end
+ x = x + y
+ end
+ assert(x == 5050)
+end
+
+do --- sum with error
+ local function f(x)
+ if x >= 150 then error("test", 0) end
+ return x end
+ local x = 0
+ for i=1,200 do
+ local ok1, ok2, ok3, y = xpcall(xpcall, tr, xpcall, tr, f, tr, i)
+ if not ok1 or not ok2 or not ok3 then
+ assert(ok1 and ok2 and not ok3)
+ assert(y == "trtest")
+ break
+ end
+ x = x + y
+ end
+ assert(x == 11175)
+end
+
+do --- square with error
+ local function f(x)
+ if x >= 150 then return x*x end
+ return x
+ end
+ local x = 0
+ for i=1,200 do
+ local ok1, ok2, ok3, y = xpcall(xpcall, tr, xpcall, tr, f, tr, i)
+ if not ok1 or not ok2 or not ok3 then break end
+ x = x + y
+ end
+ assert(x == 1584100)
+end
+
+do --- sum or square with error
+ local function f(x)
+ if x >= 150 then
+ if x >= 175 then error("test", 0) end
+ return x*x
+ end
+ return x
+ end
+ local x = 0
+ for i=1,200 do
+ local ok1, ok2, ok3, y = xpcall(xpcall, tr, xpcall, tr, f, tr, i)
+ if not ok1 or not ok2 or not ok3 then
+ assert(ok1 and ok2 and not ok3)
+ assert(y == "trtest")
+ -- note: no break, so we get an exit to interpreter
+ else
+ x = x + y
+ end
+ end
+ assert(x == 668575)
+end
+
+do --- xpcall swap after recorder error
+ local x = 0
+ for i=1,100 do
+ local ok1, ok2, ok3, err = xpcall(xpcall, tr, xpcall, tr, error, tr, "test", 0)
+ assert(ok1 and ok2 and not ok3 and err == "trtest")
+ end
+end
diff --git a/test/LuaJIT-tests/lib/bit.lua b/test/LuaJIT-tests/lib/bit.lua
new file mode 100644
index 0000000..1adf550
--- /dev/null
+++ b/test/LuaJIT-tests/lib/bit.lua
@@ -0,0 +1,98 @@
+local bit = require"bit"
+local byte, ipairs, tostring, pcall = string.byte, ipairs, tostring, pcall
+
+local vb = {
+ 0, 1, -1, 2, -2, 0x12345678, 0x87654321,
+ 0x33333333, 0x77777777, 0x55aa55aa, 0xaa55aa55,
+ 0x7fffffff, 0x80000000, 0xffffffff
+}
+
+local function cksum(name, s, r)
+ local z = 0
+ for i=1,#s do z = (z + byte(s, i)*i) % 2147483629 end
+ if z ~= r then
+ error("bit."..name.." test failed (got "..z..", expected "..r..")", 0)
+ end
+end
+
+local function check_unop(name, r)
+ local f = bit[name]
+ local s = ""
+ if pcall(f) or pcall(f, "z") or pcall(f, true) then
+ error("bit."..name.." fails to detect argument errors", 0)
+ end
+ for _,x in ipairs(vb) do s = s..","..tostring(f(x)) end
+ cksum(name, s, r)
+end
+
+local function check_binop(name, r)
+ local f = bit[name]
+ local s = ""
+ if pcall(f) or pcall(f, "z") or pcall(f, true) then
+ error("bit."..name.." fails to detect argument errors", 0)
+ end
+ for _,x in ipairs(vb) do
+ for _2,y in ipairs(vb) do s = s..","..tostring(f(x, y)) --[[io.write(_, " ", _2, " ", x, " ", y, " ", f(x, y), "\n")]] end
+ end
+ cksum(name, s, r)
+end
+
+local function check_binop_range(name, r, yb, ye)
+ local f = bit[name]
+ local s = ""
+ if pcall(f) or pcall(f, "z") or pcall(f, true) or pcall(f, 1, true) then
+ error("bit."..name.." fails to detect argument errors", 0)
+ end
+ for _,x in ipairs(vb) do
+ for y=yb,ye do s = s..","..tostring(f(x, y)) end
+ end
+ cksum(name, s, r)
+end
+
+local function check_shift(name, r)
+ check_binop_range(name, r, 0, 31)
+end
+
+do --- Minimal sanity checks.
+ assert(0x7fffffff == 2147483647, "broken hex literals")
+ assert(0xffffffff == -1 or 0xffffffff == 2^32-1, "broken hex literals")
+ assert(tostring(-1) == "-1", "broken tostring()")
+ assert(tostring(0xffffffff) == "-1" or tostring(0xffffffff) == "4294967295", "broken tostring()")
+end
+
+do --- Basic argument processing.
+ assert(bit.tobit(1) == 1)
+ assert(bit.band(1) == 1)
+ assert(bit.bxor(1,2) == 3)
+ assert(bit.bor(1,2,4,8,16,32,64,128) == 255)
+end
+
+do --- unop test vectors
+ check_unop("tobit", 277312)
+ check_unop("bnot", 287870)
+ check_unop("bswap", 307611)
+end
+
+do --- binop test vectors
+ check_binop("band", 41206764)
+ check_binop("bor", 51253663)
+ check_binop("bxor", 79322427)
+end
+
+do --- shift test vectors
+ check_shift("lshift", 325260344)
+ check_shift("rshift", 139061800)
+ check_shift("arshift", 111364720)
+ check_shift("rol", 302401155)
+ check_shift("ror", 302316761)
+end
+
+do --- tohex test vectors
+ check_binop_range("tohex", 47880306, -8, 8)
+end
+
+do --- Don't propagate TOBIT narrowing across two conversions.
+ local tobit = bit.tobit
+ local k = 0x8000000000003
+ for i=1,100 do assert(tobit(k % (2^32)) == 3) end
+end
diff --git a/test/LuaJIT-tests/lib/contents.lua b/test/LuaJIT-tests/lib/contents.lua
new file mode 100644
index 0000000..a1d8b9b
--- /dev/null
+++ b/test/LuaJIT-tests/lib/contents.lua
@@ -0,0 +1,155 @@
+local function check(m, expected, exclude)
+ local t = {}
+ local ex = {}
+ if exclude then
+ for k in exclude:gmatch"[^:]+" do
+ ex[k] = true
+ end
+ end
+ for k in pairs(m) do
+ if not ex[k] then
+ t[#t+1] = tostring(k)
+ end
+ end
+ table.sort(t)
+ local got = table.concat(t, ":")
+ if got ~= expected then
+ error("got: \""..got.."\"\nexpected: \""..expected.."\"", 2)
+ end
+end
+
+do --- base
+ check(_G, "_G:_VERSION:arg:assert:collectgarbage:coroutine:debug:dofile:error:getmetatable:io:ipairs:load:loadfile:math:next:os:package:pairs:pcall:print:rawequal:rawget:rawset:require:select:setmetatable:string:table:tonumber:tostring:type:xpcall", "rawlen:bit:bit32:jit:gcinfo:setfenv:getfenv:loadstring:unpack:module:newproxy")
+end
+
+do --- pre-5.2 base +lua<5.2
+ assert(gcinfo)
+ assert(setfenv)
+ assert(getfenv)
+ assert(loadstring)
+ assert(unpack)
+ assert(module)
+ assert(newproxy)
+end
+
+do --- 5.2 base +lua>=5.2
+ assert(not gcinfo)
+ assert(not setfenv)
+ assert(not getfenv)
+ assert(not loadstring)
+ assert(not unpack)
+ assert(not module)
+ assert(not newproxy)
+end
+
+do --- pre-5.2 base rawlen -compat5.2
+ assert(not rawlen)
+end
+
+do --- 5.2 base rawlen +compat5.2
+ assert(rawlen)
+end
+
+do --- math
+ check(math, "abs:acos:asin:atan:atan2:ceil:cos:cosh:deg:exp:floor:fmod:frexp:huge:ldexp:log:max:min:modf:pi:pow:rad:random:randomseed:sin:sinh:sqrt:tan:tanh", "log10:mod")
+end
+
+do --- pre-5.2 math +lua<5.2 -compat5.2
+ assert(math.mod)
+ assert(math.log10)
+end
+
+do --- 5.2 math +lua>=5.2
+ assert(not math.mod)
+ assert(not math.log10)
+end
+
+do --- string
+ check(string, "byte:char:dump:find:format:gmatch:gsub:len:lower:match:rep:reverse:sub:upper", "gfind")
+end
+
+do --- pre-5.2 string +lua<5.2 -compat5.2
+ assert(string.gfind)
+end
+
+do --- 5.2 string +lua>=5.2
+ assert(not string.gfind)
+end
+
+do --- pre-5.2 table +lua<5.2
+ check(table, "concat:foreach:foreachi:getn:insert:maxn:remove:sort", "pack:unpack:setn:new")
+end
+
+do --- 5.2 table +lua>=5.2
+ check(table, "concat:insert:pack:remove:sort:unpack")
+end
+
+do --- pre-5.2 table.pack -compat5.2
+ assert(not table.pack)
+ assert(not table.unpack)
+end
+
+do --- 5.2 table.pack +compat5.2
+ assert(table.pack)
+ assert(table.unpack)
+end
+
+do --- io
+ check(io, "close:flush:input:lines:open:output:popen:read:stderr:stdin:stdout:tmpfile:type:write")
+end
+
+do --- io file
+ check(debug.getmetatable(io.stdin), "__gc:__index:__tostring:close:flush:lines:read:seek:setvbuf:write")
+end
+
+do --- os
+ check(os, "clock:date:difftime:execute:exit:getenv:remove:rename:setlocale:time:tmpname")
+end
+
+do --- debug
+ check(debug, "debug:gethook:getinfo:getlocal:getmetatable:getregistry:getupvalue:sethook:setlocal:setmetatable:setupvalue:traceback", "getfenv:setfenv:upvalueid:upvaluejoin:getuservalue:setuservalue")
+end
+
+-- TODO: Check versional differences in debug library
+
+do --- package
+ check(package, "config:cpath:loaded:loadlib:path:preload", "searchpath:loaders:searchers:seeall")
+end
+
+do --- pre-5.2 package +lua<5.2
+ assert(package.loaders)
+ assert(not package.searchers)
+ assert(package.seeall)
+end
+
+do --- 5.2 package +lua>=5.2
+ assert(not package.loaders)
+ assert(package.searchers)
+ assert(not package.seeall)
+end
+
+do --- package.loaders
+ check(package.loaders or package.searchers, "1:2:3:4")
+end
+
+do --- package.loaded
+ local loaded = {}
+ for k, v in pairs(package.loaded) do
+ if type(k) ~= "string" or (k:sub(1, 7) ~= "common." and k:sub(1, 4) ~= "jit.") then
+ loaded[k] = v
+ end
+ end
+ check(loaded, "_G:coroutine:debug:io:math:os:package:string:table", "bit:bit32:common:ffi:jit:table.new")
+end
+
+do --- bit +bit
+ check(bit, "arshift:band:bnot:bor:bswap:bxor:lshift:rol:ror:rshift:tobit:tohex")
+end
+
+do --- ffi +ffi
+ check(require"ffi", "C:abi:alignof:arch:cast:cdef:copy:errno:fill:gc:istype:load:metatype:new:offsetof:os:sizeof:string:typeof", "typeinfo")
+end
+
+do --- ffi 2.1 +fii +luajit>=2.1
+ assert(require"ffi".typeinfo)
+end
diff --git a/test/LuaJIT-tests/lib/coroutine/index b/test/LuaJIT-tests/lib/coroutine/index
new file mode 100644
index 0000000..9c5c17e
--- /dev/null
+++ b/test/LuaJIT-tests/lib/coroutine/index
@@ -0,0 +1 @@
+yield.lua
diff --git a/test/LuaJIT-tests/lib/coroutine/yield.lua b/test/LuaJIT-tests/lib/coroutine/yield.lua
new file mode 100644
index 0000000..d995bf8
--- /dev/null
+++ b/test/LuaJIT-tests/lib/coroutine/yield.lua
@@ -0,0 +1,109 @@
+local create = coroutine.create
+local wrap = coroutine.wrap
+local resume = coroutine.resume
+local yield = coroutine.yield
+
+do --- Stack overflow on return (create)
+ wrap(function()
+ local co = create(function()
+ yield(string.byte(string.rep(" ", 100), 1, 100))
+ end)
+ assert(select('#', resume(co)) == 101)
+ end)()
+end
+
+do --- Stack overflow on return (wrap)
+ wrap(function()
+ local f = wrap(function()
+ yield(string.byte(string.rep(" ", 100), 1, 100))
+ end)
+ assert(select('#', f()) == 100)
+ end)()
+end
+
+do --- cogen
+ local function cogen(x)
+ return wrap(function(n) repeat x = x+n; n = yield(x) until false end),
+ wrap(function(n) repeat x = x*n; n = yield(x) until false end)
+ end
+
+ local a,b=cogen(3)
+ local c,d=cogen(5)
+ assert(d(b(c(a(d(b(c(a(1)))))))) == 168428160)
+end
+
+do --- cofunc +luajit
+ local function verify(what, expect, ...)
+ local got = {...}
+ for i=1,100 do
+ if expect[i] ~= got[i] then
+ error("FAIL " .. what)
+ end
+ if expect[i] == nil then
+ break
+ end
+ end
+ end
+
+ local function cofunc(...)
+ verify("call", { 1, "foo" }, ...)
+ verify("yield", { "bar" }, yield(2, "test"))
+ verify("pcall yield", { true, "again" }, pcall(yield, "from pcall"))
+ return "end"
+ end
+
+ local co = create(cofunc)
+ verify("resume", { true, 2, "test" }, resume(co, 1, "foo"))
+ verify("resume pcall", { true, "from pcall" }, resume(co, "bar"))
+ verify("resume end", { true, "end" }, resume(co, "again"))
+end
+
+do --- assorted +luajit
+ local function verify(expect, func, ...)
+ local co = create(func)
+ for i=1,100 do
+ local ok, res = resume(co, ...)
+ if not ok then
+ if expect[i] ~= nil then
+ error("too few results: ["..i.."] = "..tostring(expect[i]).." (got: "..tostring(res)..")")
+ end
+ break
+ end
+ if expect[i] ~= res then
+ error("bad result: ["..i.."] = "..tostring(res).." (should be: "..tostring(expect[i])..")")
+ end
+ end
+ end
+
+ verify({ 42, 99 },
+ function(x) pcall(yield, x) return 99 end,
+ 42)
+
+ verify({ 42, 99 },
+ function(x) pcall(function(y) yield(y) end, x) return 99 end,
+ 42)
+
+ verify({ 42, 99 },
+ function(x) xpcall(yield, debug.traceback, x) return 99 end,
+ 42)
+
+ verify({ 45, 44, 43, 42, 99 },
+ function(x, y)
+ for i in
+ function(o, k)
+ yield(o+k)
+ if k ~= 0 then return k-1 end
+ end,x,y do
+ end
+ return 99
+ end,
+ 42, 3)
+
+ verify({ 84, 99 },
+ function(x)
+ local o = setmetatable({ x },
+ {__add = function(a, b) yield(a[1]+b[1]) return 99 end })
+ return o+o
+ end,
+ 42)
+end
diff --git a/test/LuaJIT-tests/lib/ffi/bit64.lua b/test/LuaJIT-tests/lib/ffi/bit64.lua
new file mode 100644
index 0000000..d1b47be
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/bit64.lua
@@ -0,0 +1,130 @@
+local ffi = require("ffi")
+local bit = require("bit")
+
+local tobit, bnot, bswap = bit.tobit, bit.bnot, bit.bswap
+local band, bor, bxor = bit.band, bit.bor, bit.bxor
+local shl, shr, sar = bit.lshift, bit.rshift, bit.arshift
+local rol, ror = bit.rol, bit.ror
+
+ffi.cdef[[
+typedef enum { ZZI = -1 } ienum_t;
+typedef enum { ZZU } uenum_t;
+]]
+
+do --- smoke tobit
+ assert(tobit(0xfedcba9876543210ll) == 0x76543210)
+ assert(tobit(0xfedcba9876543210ull) == 0x76543210)
+end
+
+do --- smoke band
+ assert(tostring(band(1ll, 1, 1ll, -1)) == "1LL")
+ assert(tostring(band(1ll, 1, 1ull, -1)) == "1ULL")
+end
+
+do --- smoke shl
+ assert(shl(10ll, 2) == 40)
+ assert(shl(10, 2ll) == 40)
+ assert(shl(10ll, 2ll) == 40)
+end
+
+do --- smoke tohex
+ assert(bit.tohex(0x123456789abcdef0LL) == "123456789abcdef0")
+end
+
+do --- tobit/band assorted C types
+ for _,tp in ipairs{"int", "ienum_t", "uenum_t", "int64_t", "uint64_t"} do
+ local x = ffi.new(tp, 10)
+ local y = tobit(x)
+ local z = band(x)
+ assert(type(y) == "number" and y == 10)
+ assert(type(z) == "cdata" and z == 10)
+ end
+end
+
+do --- tobit/band negative unsigned enum
+ local x = ffi.new("uenum_t", -10)
+ local y = tobit(x)
+ local z = band(x)
+ assert(type(y) == "number")
+ assert(y == -10)
+ assert(type(z) == "cdata")
+ assert(z == 2^32-10)
+end
+
+do --- jit band/bor/bxor
+ local a = 0x123456789abcdef0LL
+ local y1, y2, y3, y4, y5, y6
+ for i=1,100 do
+ y1 = band(a, 0x000000005a5a5a5aLL)
+ y2 = band(a, 0x5a5a5a5a00000000LL)
+ y3 = band(a, 0xffffffff5a5a5a5aLL)
+ y4 = band(a, 0x5a5a5a5affffffffLL)
+ y5 = band(a, 0xffffffff00000000LL)
+ y6 = band(a, 0x00000000ffffffffLL)
+ end
+ assert(y1 == 0x000000001a185a50LL)
+ assert(y2 == 0x1210525800000000LL)
+ assert(y3 == 0x123456781a185a50LL)
+ assert(y4 == 0x121052589abcdef0LL)
+ assert(y5 == 0x1234567800000000LL)
+ assert(y6 == 0x000000009abcdef0LL)
+ for i=1,100 do
+ y1 = bor(a, 0x000000005a5a5a5aLL)
+ y2 = bor(a, 0x5a5a5a5a00000000LL)
+ y3 = bor(a, 0xffffffff5a5a5a5aLL)
+ y4 = bor(a, 0x5a5a5a5affffffffLL)
+ y5 = bor(a, 0xffffffff00000000LL)
+ y6 = bor(a, 0x00000000ffffffffLL)
+ end
+ assert(y1 == 0x12345678dafedefaLL)
+ assert(y2 == 0x5a7e5e7a9abcdef0LL)
+ assert(y3 == 0xffffffffdafedefaLL)
+ assert(y4 == 0x5a7e5e7affffffffLL)
+ assert(y5 == 0xffffffff9abcdef0LL)
+ assert(y6 == 0x12345678ffffffffLL)
+ for i=1,100 do
+ y1 = bxor(a, 0x000000005a5a5a5aLL)
+ y2 = bxor(a, 0x5a5a5a5a00000000LL)
+ y3 = bxor(a, 0xffffffff5a5a5a5aLL)
+ y4 = bxor(a, 0x5a5a5a5affffffffLL)
+ y5 = bxor(a, 0xffffffff00000000LL)
+ y6 = bxor(a, 0x00000000ffffffffLL)
+ end
+ assert(y1 == 0x12345678c0e684aaLL)
+ assert(y2 == 0x486e0c229abcdef0LL)
+ assert(y3 == 0xedcba987c0e684aaLL)
+ assert(y4 == 0x486e0c226543210fLL)
+ assert(y5 == 0xedcba9879abcdef0LL)
+ assert(y6 == 0x123456786543210fLL)
+end
+
+do --- jit shift/xor
+ local a, b = 0x123456789abcdef0LL, 0x31415926535898LL
+ for i=1,200 do
+ a = bxor(a, b); b = sar(b, 14) + shl(b, 50)
+ a = a - b; b = shl(b, 5) + sar(b, 59)
+ b = bxor(a, b); b = b - shl(b, 13) - shr(b, 51)
+ end
+ assert(b == -7993764627526027113LL)
+end
+
+do --- jit rotate/xor
+ local a, b = 0x123456789abcdef0LL, 0x31415926535898LL
+ for i=1,200 do
+ a = bxor(a, b); b = rol(b, 14)
+ a = a - b; b = rol(b, 5)
+ b = bxor(a, b); b = b - rol(b, 13)
+ end
+ assert(b == -6199148037344061526LL)
+end
+
+do --- jit all ops
+ local a, b = 0x123456789abcdef0LL, 0x31415926535898LL
+ for i=1,200 do
+ a = bxor(a, b); b = rol(b, a)
+ a = a - b; b = shr(b, a) + shl(b, bnot(a))
+ b = bxor(a, b); b = b - bswap(b)
+ end
+ assert(b == -8881785180777266821LL)
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/cdata_var.lua b/test/LuaJIT-tests/lib/ffi/cdata_var.lua
new file mode 100644
index 0000000..42d6028
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/cdata_var.lua
@@ -0,0 +1,47 @@
+local ffi = require("ffi")
+
+do --- byte array allocations
+ local typ = ffi.typeof"uint8_t[?]"
+ for i = 4, 24 do
+ for d = -5, 5 do
+ local sz = 2^i + d
+ assert(ffi.sizeof(typ, sz) == sz)
+ local mem = ffi.new(typ, sz)
+ assert(ffi.sizeof(mem) == sz)
+ mem[0] = 0x21
+ mem[1] = 0x32
+ mem[2] = 0x43
+ mem[sz-3] = 0x54
+ mem[sz-2] = 0x65
+ mem[sz-1] = 0x76
+ assert(mem[0] == 0x21)
+ assert(mem[1] == 0x32)
+ assert(mem[2] == 0x43)
+ assert(mem[3] == 0)
+ assert(mem[sz-4] == 0)
+ assert(mem[sz-3] == 0x54)
+ assert(mem[sz-2] == 0x65)
+ assert(mem[sz-1] == 0x76)
+ end
+ end
+end
+
+do --- int array allocations
+ local typ = ffi.typeof"int32_t[?]"
+ for i = 2, 17 do
+ for d = -2, 2 do
+ local sz = 2^i + d
+ assert(ffi.sizeof(typ, sz) == sz*4)
+ local mem = ffi.new(typ, sz)
+ assert(ffi.sizeof(mem) == sz*4)
+ mem[0] = -3
+ mem[sz-1] = -4
+ assert(mem[0] == -3)
+ if sz ~= 2 then
+ assert(mem[1] == 0)
+ assert(mem[sz-2] == 0)
+ end
+ assert(mem[sz-1] == -4)
+ end
+ end
+end
diff --git a/test/LuaJIT-tests/lib/ffi/copy_fill.lua b/test/LuaJIT-tests/lib/ffi/copy_fill.lua
new file mode 100644
index 0000000..2956381
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/copy_fill.lua
@@ -0,0 +1,64 @@
+local ffi = require("ffi")
+
+do --- misc
+ local arr = ffi.typeof("char[11]")
+ local a = arr()
+ local b = arr()
+ local c = arr()
+
+ for i=0,9 do a[i] = 97+i; b[i] = 106-i end
+ a[10] = 0; b[10] = 0;
+
+ ffi.copy(c, a, 11)
+ for i=0,9 do assert(c[i] == 97+i) end
+ assert(ffi.string(c) == "abcdefghij")
+
+ ffi.copy(c, b, 5)
+ for i=0,4 do assert(c[i] == 106-i) end
+ for i=5,9 do assert(c[i] == 97+i) end
+ assert(ffi.string(c) == "jihgffghij")
+
+ c[7] = 0
+ assert(ffi.string(c) == "jihgffg")
+
+ c[10] = 1
+ ffi.copy(c, "ABCDEFGHIJ")
+ for i=0,9 do assert(c[i] == 65+i) end
+ assert(c[10] == 0)
+ assert(ffi.string(c) == "ABCDEFGHIJ")
+
+ ffi.copy(c, "abcdefghij", 5)
+ assert(ffi.string(c) == "abcdeFGHIJ")
+
+ ffi.fill(c, 10, 65)
+ assert(ffi.string(c) == "AAAAAAAAAA")
+ for i=10,0,-1 do ffi.fill(c, i, 96+i) end
+ assert(ffi.string(c) == "abcdefghij")
+ ffi.fill(c, 10)
+ assert(c[0] == 0)
+ assert(c[9] == 0)
+
+ -- test length parameter to ffi.string
+ ffi.fill(c, 10, 65)
+ assert(ffi.string(c, 5) == "AAAAA")
+end
+
+do --- jit char[10]
+ local a = ffi.new("char[10]", 64)
+ local x
+ for i=1,100 do a[0] = i; x = ffi.string(a, 10) end
+ assert(x == "d@@@@@@@@@")
+end
+
+do --- jit char[1]
+ local a = ffi.new("char[1]")
+ local x, y
+ for i=1,100 do
+ a[0] = i
+ x = ffi.string(a, 1)
+ a[0] = 126
+ y = ffi.string(a, 1)
+ end
+ assert(x == "d" and y == "~")
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/err.lua b/test/LuaJIT-tests/lib/ffi/err.lua
new file mode 100644
index 0000000..4472365
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/err.lua
@@ -0,0 +1,35 @@
+local ffi = require("ffi")
+
+do --- error in FFI metamethod: don't print metamethod frame.
+ local ok, err = xpcall(function()
+ local x = (1ll).foo
+ end, debug.traceback)
+ assert(ok == false)
+ assert(not string.find(err, "__index"))
+end
+
+do --- tailcall in regular metamethod: keep metamethod frame.
+ local ok, err = xpcall(function()
+ local t = setmetatable({}, {__index = function() return rawget("x") end })
+ local y = t[1]
+ end, debug.traceback)
+ assert(ok == false)
+ assert(string.find(err, "__index"))
+end
+
+do --- error in FFI metamethod: set correct PC.
+ ffi.cdef[[
+typedef struct { int x; int y; } ffi_err_point;
+ffi_err_point ffi_err_strchr(ffi_err_point* op1, ffi_err_point* op2) asm("strchr");
+]]
+ local point = ffi.metatype("ffi_err_point", { __add = ffi.C.ffi_err_strchr })
+ local function foo()
+ local p = point{ 3, 4 }
+ local r = p + p
+ local r = p + 5
+ end
+ local ok, err = xpcall(foo, debug.traceback)
+ local line = debug.getinfo(foo).linedefined+3
+ assert(string.match(err, "traceback:[^:]*:"..line..":"))
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_arith_ptr.lua b/test/LuaJIT-tests/lib/ffi/ffi_arith_ptr.lua
new file mode 100644
index 0000000..8cf890c
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_arith_ptr.lua
@@ -0,0 +1,106 @@
+local ffi = require("ffi")
+
+dofile("../common/ffi_util.inc")
+
+ffi.cdef[[
+typedef struct { int a,b,c; } foo1_t;
+void free(void *);
+void *malloc(size_t);
+struct incomplete;
+]]
+
+do
+ local a = ffi.new("int[10]")
+ local p1 = a+0
+ p1[0] = 1;
+ p1[1] = 2;
+ assert(a[0] == 1)
+ assert(a[1] == 2)
+ assert(a == p1)
+ assert(not (a ~= p1))
+ assert(p1 <= a)
+ assert(a <= p1)
+ assert(not (p1 < a))
+ assert(not (a < p1))
+ assert(a ~= nil)
+ assert(not (a == nil))
+ assert(p1 ~= nil)
+ assert(not (p1 == nil))
+
+ local p2 = a+2
+ p2[0] = 3;
+ p2[1] = 4;
+ assert(a[2] == 3)
+ assert(a[3] == 4)
+ assert(p2 - p1 == 2)
+ assert(p1 - p2 == -2)
+ assert(p1 ~= p2)
+ assert(not (p1 == p2))
+ assert(p1 < p2)
+ assert(p2 > p1)
+ assert(not (p1 > p2))
+ assert(not (p2 < p1))
+ assert(p1 <= p2)
+ assert(p2 >= p1)
+ assert(not (p1 >= p2))
+ assert(not (p2 <= p1))
+
+ local p3 = a-2
+ assert(p3[2] == 1)
+ assert(p3[3] == 2)
+ local p4 = a+(-3)
+ assert(p4[5] == 3)
+ assert(p4[6] == 4)
+ -- bad: adding two pointers or subtracting a pointer
+ fails(function(p1, p2) return p1 + p2 end, p1, p2)
+ fails(function(p1) return 1 - p1 end, p1)
+ -- bad: subtracting different pointer types
+ fails(function(p1) return p1 - ffi.new("char[1]") end, p1)
+ -- but different qualifiers are ok
+ local b = ffi.cast("const int *", a+5)
+ assert(b - a == 5)
+end
+
+do
+ local p1 = ffi.cast("void *", 0)
+ local p2 = ffi.cast("int *", 1)
+ assert(p1 == p1)
+ assert(p2 == p2)
+ assert(p1 ~= p2)
+ assert(p1 == nil)
+ assert(p2 ~= nil)
+end
+
+do
+ local f1 = ffi.C.free
+ local f2 = ffi.C.malloc
+ local p1 = ffi.cast("void *", f1)
+ assert(f1 == f1)
+ assert(f1 ~= nil)
+ assert(f1 ~= f2)
+ assert(p1 == f1)
+ assert(p1 ~= f2)
+ assert(f1 < f2 or f1 > f2)
+ fails(function(f1) return f1 + 1 end, f1)
+end
+
+do
+ local s = ffi.new("foo1_t[10]")
+ local p1 = s+3
+ p1.a = 1; p1.b = 2; p1.c = 3
+ p1[1].a = 4; p1[1].b = 5; p1[1].c = 6
+ assert(s[3].a == 1 and s[3].b == 2 and s[3].c == 3)
+ assert(s[4].a == 4 and s[4].b == 5 and s[4].c == 6)
+ local p2 = s+6
+ assert(p2 - p1 == 3)
+ assert(p1 - p2 == -3)
+end
+
+do
+ local mem = ffi.new("int[1]")
+ local p = ffi.cast("struct incomplete *", mem)
+ fails(function(p) return p+1 end, p)
+ local ok, err = pcall(function(p) return p[1] end, p)
+ assert(not ok and err:match("size.*unknown"))
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_bitfield.lua b/test/LuaJIT-tests/lib/ffi/ffi_bitfield.lua
new file mode 100644
index 0000000..cd0b181
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_bitfield.lua
@@ -0,0 +1,108 @@
+local ffi = require("ffi")
+
+dofile("../common/ffi_util.inc")
+
+do
+ local x = ffi.new([[
+ union {
+ uint32_t u;
+ struct { int a:10,b:10,c:11,d:1; };
+ struct { unsigned int e:10,f:10,g:11,h:1; };
+ struct { int8_t i:4,j:5,k:5,l:3; };
+ struct { _Bool b0:1,b1:1,b2:1,b3:1; };
+ }
+ ]])
+
+ -- bitfield access
+ x.u = 0xffffffff
+ assert(x.a == -1 and x.b == -1 and x.c == -1 and x.d == -1)
+ assert(x.e == 1023 and x.f == 1023 and x.g == 2047 and x.h == 1)
+ assert(x.i == -1 and x.j == -1 and x.k == -1 and x.l == -1)
+ assert(x.b0 == true and x.b1 == true and x.b2 == true and x.b3 == true)
+ x.u = 0x12345678
+ if ffi.abi("le") then
+ assert(x.a == -392 and x.b == 277 and x.c == 291 and x.d == 0)
+ assert(x.e == 632 and x.f == 277 and x.g == 291 and x.h == 0)
+ assert(x.i == -8 and x.j == -10 and x.k == -12 and x.l == 1)
+ assert(x.b0 == false and x.b1 == false and x.b2 == false and x.b3 == true)
+ else
+ assert(x.a == 72 and x.b == -187 and x.c == 828 and x.d == 0)
+ assert(x.e == 72 and x.f == 837 and x.g == 828 and x.h == 0)
+ assert(x.i == 1 and x.j == 6 and x.k == 10 and x.l == -2)
+ assert(x.b0 == false and x.b1 == false and x.b2 == false and x.b3 == true)
+ end
+ x.u = 0xe8d30edc
+ if ffi.abi("le") then
+ assert(x.a == -292 and x.b == 195 and x.c == -371 and x.d == -1)
+ assert(x.e == 732 and x.f == 195 and x.g == 1677 and x.h == 1)
+ assert(x.i == -4 and x.j == 14 and x.k == -13 and x.l == -2)
+ assert(x.b0 == false and x.b1 == false and x.b2 == true and x.b3 == true)
+ else
+ assert(x.a == -93 and x.b == 304 and x.c == -146 and x.d == 0)
+ assert(x.e == 931 and x.f == 304 and x.g == 1902 and x.h == 0)
+ assert(x.i == -2 and x.j == -6 and x.k == 1 and x.l == -2)
+ assert(x.b0 == true and x.b1 == true and x.b2 == true and x.b3 == false)
+ end
+
+ -- bitfield insert
+ x.u = 0xffffffff
+ x.a = 0
+ if ffi.abi("le") then
+ assert(x.u == 0xfffffc00)
+ else
+ assert(x.u == 0x003fffff)
+ end
+ x.u = 0
+ x.a = -1
+ if ffi.abi("le") then
+ assert(x.u == 0x3ff)
+ else
+ assert(x.u == 0xffc00000)
+ end
+ x.u = 0xffffffff
+ x.b = 0
+ if ffi.abi("le") then
+ assert(x.u == 0xfff003ff)
+ else
+ assert(x.u == 0xffc00fff)
+ end
+ x.u = 0
+ x.b = -1
+ if ffi.abi("le") then
+ assert(x.u == 0x000ffc00)
+ else
+ assert(x.u == 0x003ff000)
+ end
+
+ -- cumulative bitfield insert
+ x.u = 0xffffffff
+ if ffi.abi("le") then
+ x.a = -392; x.b = 277; x.c = 291; x.d = 0
+ else
+ x.a = 72; x.b = -187; x.c = 828; x.d = 0
+ end
+ assert(x.u == 0x12345678)
+ x.u = 0
+ if ffi.abi("le") then
+ x.a = -392; x.b = 277; x.c = 291; x.d = 0
+ else
+ x.a = 72; x.b = -187; x.c = 828; x.d = 0
+ end
+ assert(x.u == 0x12345678)
+ x.u = 0xffffffff
+ x.b0 = true; x.b1 = false; x.b2 = true; x.b3 = false
+ if ffi.abi("le") then
+ assert(x.u == 0xfffffff5)
+ else
+ assert(x.u == 0xafffffff)
+ end
+ x.u = 0
+ x.b0 = true; x.b1 = false; x.b2 = true; x.b3 = false
+ if ffi.abi("le") then
+ assert(x.u == 0x00000005)
+ else
+ assert(x.u == 0xa0000000)
+ end
+
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_call.lua b/test/LuaJIT-tests/lib/ffi/ffi_call.lua
new file mode 100644
index 0000000..1eb5e90
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_call.lua
@@ -0,0 +1,266 @@
+
+local ffi = require("ffi")
+
+dofile("../common/ffi_util.inc")
+
+local tonumber = tonumber
+
+ffi.cdef[[
+typedef struct s_ii { int x, y; } s_ii;
+typedef struct s_jj { int64_t x, y; } s_jj;
+typedef struct s_ff { float x, y; } s_ff;
+typedef struct s_dd { double x, y; } s_dd;
+typedef struct s_8i { int a,b,c,d,e,f,g,h; } s_8i;
+
+int call_i(int a);
+int call_ii(int a, int b);
+int call_10i(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j);
+
+typedef enum { XYZ } e_u;
+
+e_u call_ie(e_u a) asm("call_i");
+
+int64_t call_ji(int64_t a, int b);
+int64_t call_ij(int a, int64_t b);
+int64_t call_jj(int64_t a, int64_t b);
+
+double call_dd(double a, double b);
+double call_10d(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j);
+
+float call_ff(float a, float b);
+float call_10f(float a, float b, float c, float d, float e, float f, float g, float h, float i, float j);
+
+double call_idifjd(int a, double b, int c, float d, int64_t e, double f);
+
+int call_p_i(int *a);
+int *call_p_p(int *a);
+int call_pp_i(int *a, int *b);
+
+double call_ividi(int a, ...);
+
+complex call_dd_cd(double a, double b);
+complex call_cd(complex a);
+complex call_cdcd(complex a, complex b);
+
+complex float call_ff_cf(float a, float b);
+complex float call_cf(complex float a);
+complex float call_cfcf(complex float a, complex float b);
+
+s_ii call_sii(s_ii a);
+s_jj call_sjj(s_jj a);
+s_ff call_sff(s_ff a);
+s_dd call_sdd(s_dd a);
+s_8i call_s8i(s_8i a);
+s_ii call_siisii(s_ii a, s_ii b);
+s_ff call_sffsff(s_ff a, s_ff b);
+s_dd call_sddsdd(s_dd a, s_dd b);
+s_8i call_s8is8i(s_8i a, s_8i b);
+s_8i call_is8ii(int a, s_8i b, int c);
+
+int __fastcall fastcall_void(void);
+int __fastcall fastcall_i(int a);
+int __fastcall fastcall_ii(int a, int b);
+int __fastcall fastcall_iii(int a, int b, int c);
+int64_t __fastcall fastcall_ji(int64_t a, int b);
+double __fastcall fastcall_dd(double a, double b);
+int __fastcall fastcall_pp_i(int *a, int *b);
+s_ii __fastcall fastcall_siisii(s_ii a, s_ii b);
+s_dd __fastcall fastcall_sddsdd(s_dd a, s_dd b);
+
+int __stdcall stdcall_i(int a);
+int __stdcall stdcall_ii(int a, int b);
+double __stdcall stdcall_dd(double a, double b);
+float __stdcall stdcall_ff(float a, float b);
+]]
+
+local C = ffi.load("../clib/ctest")
+
+assert(C.call_i(-42) == -41)
+assert(C.call_ii(-42, 17) == -42+17)
+assert(C.call_10i(-42, 17, 12345, 9987, -100, 11, 51, 0x12345678, 338, -78901234) == -42+17+12345+9987-100+11+51+0x12345678+338-78901234)
+
+assert(C.call_ie(123) == 124)
+
+assert(tonumber(C.call_ji(0x123456789LL, -17)) == tonumber(0x123456789LL-17))
+assert(tonumber(C.call_ij(-17, 0x123456789LL)) == tonumber(0x123456789LL-17))
+assert(tonumber(C.call_jj(-42, 17)) == -42+17)
+assert(tonumber(C.call_jj(0x123456789abcdef0LL, -0x789abcde99887766LL)) == tonumber(0x123456789abcdef0LL-0x789abcde99887766LL))
+
+assert(C.call_dd(12.5, -3.25) == 12.5-3.25)
+assert(C.call_10d(-42.5, 17.125, 12345.5, 9987, -100.625, 11, 51, 0x12345678, 338, -78901234.75) == -42.5+17.125+12345.5+9987-100.625+11+51+0x12345678+338-78901234.75)
+
+assert(C.call_ff(12.5, -3.25) == 12.5-3.25)
+assert(C.call_10f(-42.5, 17.125, 12345.5, 9987, -100.625, 11, 51, 0x123456, 338, -789012.75) == -42.5+17.125+12345.5+9987-100.625+11+51+0x123456+338-789012.75)
+
+assert(C.call_idifjd(-42, 17.125, 0x12345, -100.625, 12345678901234, -789012.75) == -42+17.125+0x12345-100.625+12345678901234-789012.75)
+
+do
+ local a = ffi.new("int[10]", -42)
+ assert(C.call_p_i(a) == -42+1)
+ assert(tonumber(ffi.cast("intptr_t", C.call_p_p(a+3))) == tonumber(ffi.cast("intptr_t", a+4)))
+ assert(C.call_pp_i(a+8, a+5) == 3)
+end
+
+-- vararg
+assert(C.call_ividi(-42, ffi.new("int", 17), 12.5, ffi.new("int", 131)) == -42+17+12.5+131)
+
+-- complex
+if pcall(function() return C.call_dd_cd end) then
+ do
+ local c = C.call_dd_cd(12.5, -3.25)
+ assert(c.re == 12.5 and c.im == -3.25*2)
+ end
+ do
+ local c1 = ffi.new("complex", 12.5, -3.25)
+ local cz = C.call_cd(c1)
+ assert(cz.re == 12.5+1 and cz.im == -3.25-2)
+ end
+ do
+ local c1 = ffi.new("complex", 12.5, -3.25)
+ local c2 = ffi.new("complex", -17.125, 100.625)
+ local cz = C.call_cdcd(c1, c2)
+ assert(cz.re == 12.5-17.125 and cz.im == -3.25+100.625)
+ end
+
+ do
+ local c = C.call_ff_cf(12.5, -3.25)
+ assert(c.re == 12.5 and c.im == -3.25*2)
+ end
+ do
+ local c1 = ffi.new("complex float", 12.5, -3.25)
+ local cz = C.call_cf(c1)
+ assert(cz.re == 12.5+1 and cz.im == -3.25-2)
+ end
+ do
+ local c1 = ffi.new("complex float", 12.5, -3.25)
+ local c2 = ffi.new("complex float", -17.125, 100.625)
+ local cz = C.call_cfcf(c1, c2)
+ assert(cz.re == 12.5-17.125 and cz.im == -3.25+100.625)
+ end
+end
+
+-- structs
+do
+ local s1 = ffi.new("s_ii", -42, 17)
+ local sz = C.call_sii(s1)
+ assert(s1.x == -42 and s1.y == 17)
+ assert(sz.x == -42 and sz.y == 17)
+end
+
+do
+ local s1 = ffi.new("s_jj", 0x123456789abcdef0LL, -0x789abcde99887766LL)
+ local sz = C.call_sjj(s1)
+ assert(s1.x == 0x123456789abcdef0LL)
+ assert(s1.y == -0x789abcde99887766LL)
+ assert(sz.x == 0x123456789abcdef0LL)
+ assert(sz.y == -0x789abcde99887766LL)
+end
+
+do
+ local s1 = ffi.new("s_ff", 12.5, -3.25)
+ local sz = C.call_sff(s1)
+ assert(s1.x == 12.5 and s1.y == -3.25)
+ assert(sz.x == 12.5 and sz.y == -3.25)
+end
+
+do
+ local s1 = ffi.new("s_dd", 12.5, -3.25)
+ local sz = C.call_sdd(s1)
+ assert(s1.x == 12.5 and s1.y == -3.25)
+ assert(sz.x == 12.5 and sz.y == -3.25)
+end
+
+do
+ local s1 = ffi.new("s_8i", -42, 17, 12345, 9987, -100, 11, 51, 0x12345678)
+ local sz = C.call_s8i(s1)
+ assert(s1.a+s1.b+s1.c+s1.d+s1.e+s1.f+s1.g+s1.h == -42+17+12345+9987-100+11+51+0x12345678)
+ assert(sz.a+sz.b+sz.c+sz.d+sz.e+sz.f+sz.g+sz.h == -42+17+12345+9987-100+11+51+0x12345678)
+end
+
+do
+ local s1 = ffi.new("s_ii", -42, 17)
+ local s2 = ffi.new("s_ii", 0x12345, -98765)
+ local sz = C.call_siisii(s1, s2)
+ assert(s1.x == -42 and s1.y == 17)
+ assert(s2.x == 0x12345 and s2.y == -98765)
+ assert(sz.x == -42+0x12345 and sz.y == 17-98765)
+end
+
+do
+ local s1 = ffi.new("s_ff", 12.5, -3.25)
+ local s2 = ffi.new("s_ff", -17.125, 100.625)
+ local sz = C.call_sffsff(s1, s2)
+ assert(s1.x == 12.5 and s1.y == -3.25)
+ assert(s2.x == -17.125 and s2.y == 100.625)
+ assert(sz.x == 12.5-17.125 and sz.y == -3.25+100.625)
+end
+
+do
+ local s1 = ffi.new("s_dd", 12.5, -3.25)
+ local s2 = ffi.new("s_dd", -17.125, 100.625)
+ local sz = C.call_sddsdd(s1, s2)
+ assert(s1.x == 12.5 and s1.y == -3.25)
+ assert(s2.x == -17.125 and s2.y == 100.625)
+ assert(sz.x == 12.5-17.125 and sz.y == -3.25+100.625)
+end
+
+do
+ local s1 = ffi.new("s_8i", -42, 17, 12345, 9987, -100, 11, 51, 0x12345678)
+ local s2 = ffi.new("s_8i", 99, 311, 98765, -51, 312, 97, 17, 0x44332211)
+ local sz = C.call_s8is8i(s1, s2)
+ assert(s1.a+s1.b+s1.c+s1.d+s1.e+s1.f+s1.g+s1.h == -42+17+12345+9987-100+11+51+0x12345678)
+ assert(s2.a+s2.b+s2.c+s2.d+s2.e+s2.f+s2.g+s2.h == 99+311+98765-51+312+97+17+0x44332211)
+ assert(sz.a+sz.b+sz.c+sz.d+sz.e+sz.f+sz.g+sz.h == -42+17+12345+9987-100+11+51+0x12345678 + 99+311+98765-51+312+97+17+0x44332211)
+ assert(sz.a == -42+99)
+ assert(sz.h == 0x12345678+0x44332211)
+end
+
+do
+ local s1 = ffi.new("s_8i", -42, 17, 12345, 9987, -100, 11, 51, 0x12345678)
+ local sz = C.call_is8ii(19, s1, -51)
+ assert(s1.a+s1.b+s1.c+s1.d+s1.e+s1.f+s1.g+s1.h == -42+17+12345+9987-100+11+51+0x12345678)
+ assert(sz.a+sz.b+sz.c+sz.d+sz.e+sz.f+sz.g+sz.h == -42+17+12345+9987-100+11+51+0x12345678 + 19-51)
+ assert(sz.a == -42+19)
+ assert(sz.c == 12345-51)
+end
+
+-- target-specific
+if jit.arch == "x86" then
+ assert(C.fastcall_void() == 1)
+ assert(C.fastcall_i(-42) == -41)
+ assert(C.fastcall_ii(-42, 17) == -42+17)
+ assert(C.fastcall_iii(-42, 17, 139) == -42+17+139)
+ assert(tonumber(C.fastcall_ji(0x123456789LL, -17)) == tonumber(0x123456789LL-17))
+ assert(C.fastcall_dd(12.5, -3.25) == 12.5-3.25)
+
+ do
+ local a = ffi.new("int[10]", -42)
+ assert(C.fastcall_pp_i(a+8, a+5) == 3)
+ end
+
+ do
+ local s1 = ffi.new("s_ii", -42, 17)
+ local s2 = ffi.new("s_ii", 0x12345, -98765)
+ local sz = C.fastcall_siisii(s1, s2)
+ assert(s1.x == -42 and s1.y == 17)
+ assert(s2.x == 0x12345 and s2.y == -98765)
+ assert(sz.x == -42+0x12345 and sz.y == 17-98765)
+ end
+
+ do
+ local s1 = ffi.new("s_dd", 12.5, -3.25)
+ local s2 = ffi.new("s_dd", -17.125, 100.625)
+ local sz = C.fastcall_sddsdd(s1, s2)
+ assert(s1.x == 12.5 and s1.y == -3.25)
+ assert(s2.x == -17.125 and s2.y == 100.625)
+ assert(sz.x == 12.5-17.125 and sz.y == -3.25+100.625)
+ end
+
+ if jit.os == "Windows" then
+ assert(C.stdcall_i(-42) == -41)
+ assert(C.stdcall_ii(-42, 17) == -42+17)
+ assert(C.stdcall_dd(12.5, -3.25) == 12.5-3.25)
+ assert(C.stdcall_ff(12.5, -3.25) == 12.5-3.25)
+ end
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_callback.lua b/test/LuaJIT-tests/lib/ffi/ffi_callback.lua
new file mode 100644
index 0000000..1fd14bd
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_callback.lua
@@ -0,0 +1,158 @@
+
+local ffi = require("ffi")
+
+ffi.cdef[[
+void qsort(void *base, size_t nmemb, size_t size,
+ int (*compar)(const uint8_t *, const uint8_t *));
+]]
+
+do
+ local cb = ffi.cast("int (*)(int, int, int)", function(a, b, c)
+ return a+b+c
+ end)
+
+ assert(cb(10, 99, 13) == 122)
+
+ -- Don't compile call to blacklisted function.
+ for i=1,200 do
+ if i > 60 then assert(cb(10, 99, 13) == 122) end
+ end
+end
+
+do
+ assert(ffi.cast("int64_t (*)(int64_t, int64_t, int64_t)", function(a, b, c)
+ return a+b+c
+ end)(12345678901234567LL, 70000000000000001LL, 10000000909090904LL) ==
+ 12345678901234567LL+70000000000000001LL+10000000909090904LL)
+
+ assert(ffi.cast("double (*)(double, float, double)", function(a, b, c)
+ return a+b+c
+ end)(7.125, -123.25, 9999.33) == 7.125-123.25+9999.33)
+
+ assert(ffi.cast("double (*)(int, double)", function(a, b)
+ return a+b
+ end)(12345, 7.125) == 12345 + 7.125)
+
+ assert(ffi.cast("float (*)(double, float, double)", function(a, b, c)
+ return a+b+c
+ end)(7.125, -123.25, 9999.33) == 9883.205078125)
+
+ assert(ffi.cast("int (*)(int, int, int, int, int, int, int, int, int, int)",
+ function(a, b, c, d, e, f, g, h, i, j)
+ return a+b+c+d+e+f+g+h+i+j
+ end)(-42, 17, 12345, 9987, -100, 11, 51, 0x12345678, 338, -78901234) ==
+ -42+17+12345+9987-100+11+51+0x12345678+338-78901234)
+
+ assert(ffi.cast("double (*)(double, double, double, double, double, double, double, double, double, double)",
+ function(a, b, c, d, e, f, g, h, i, j)
+ return a+b+c+d+e+f+g+h+i+j
+ end)(-42.5, 17.125, 12345.5, 9987, -100.625, 11, 51, 0x12345678, 338, -78901234.75) ==
+ -42.5+17.125+12345.5+9987-100.625+11+51+0x12345678+338-78901234.75)
+end
+
+-- Target-specific tests.
+if jit.arch == "x86" then
+ assert(ffi.cast("__fastcall int (*)(int, int, int)", function(a, b, c)
+ return a+b+c
+ end)(10, 99, 13) == 122)
+
+ assert(ffi.cast("__stdcall int (*)(int, int, int)", function(a, b, c)
+ return a+b+c
+ end)(10, 99, 13) == 122)
+
+ -- Test reordering.
+ assert(ffi.cast("int64_t __fastcall (*)(int64_t, int, int)", function(a, b, c)
+ return a+b+c
+ end)(12345678901234567LL, 12345, 989797123) ==
+ 12345678901234567LL+12345+989797123)
+end
+
+-- Error handling.
+do
+ local function f()
+ return
+ end -- Error for result conversion triggered here.
+ local ok, err = pcall(ffi.cast("int (*)(void)", f))
+ assert(ok == false)
+ assert(string.match(err, ":"..debug.getinfo(f, "S").lastlinedefined..":"))
+
+ assert(pcall(ffi.cast("int (*)(void)", function() end)) == false)
+ assert(pcall(ffi.cast("int (*)(void)", function() error("test") end)) == false)
+ assert(pcall(ffi.cast("int (*)(void)", function(a) return a+1 end)) == false)
+
+ assert(pcall(ffi.cast("int (*)(int,int,int,int, int,int,int,int, int)", function() error("test") end), 1,1,1,1, 1,1,1,1, 1) == false)
+ assert(pcall(ffi.cast("int (*)(int,int,int,int, int,int,int,int, int)", function() error("test") end), 1,1,1,1, 1,1,1,1, 1) == false)
+end
+
+do
+ local function cmp(pa, pb)
+ local a, b = pa[0], pb[0]
+ if a < b then
+ return -1
+ elseif a > b then
+ return 1
+ else
+ return 0
+ end
+ end
+
+ local arr = ffi.new("uint8_t[?]", 256)
+ for i=0,255 do arr[i] = math.random(0, 255) end
+ ffi.C.qsort(arr, 256, 1, cmp)
+ for i=0,254 do assert(arr[i] <= arr[i+1]) end
+end
+
+if ffi.abi"win" then
+ ffi.cdef[[
+ typedef int (__stdcall *WNDENUMPROC)(void *hwnd, intptr_t l);
+ int EnumWindows(WNDENUMPROC func, intptr_t l);
+ int SendMessageA(void *hwnd, uint32_t msg, int w, intptr_t l);
+ enum { WM_GETTEXT = 13 };
+ ]]
+
+ local C = ffi.C
+ local buf = ffi.new("char[?]", 256)
+ local lbuf = ffi.cast("intptr_t", buf)
+ local count = 0
+ C.EnumWindows(function(hwnd, l)
+ if C.SendMessageA(hwnd, C.WM_GETTEXT, 255, lbuf) ~= 0 then
+ count = count + 1
+ end
+ return true
+ end, 0)
+ assert(count > 10)
+end
+
+do
+ local cb = ffi.cast("int(*)(void)", function() return 1 end)
+ assert(cb() == 1)
+ cb:free()
+ assert(pcall(cb) == false)
+ assert(pcall(cb.free, cb) == false)
+ assert(pcall(cb.set, cb, function() end) == false)
+ cb = ffi.cast("int(*)(void)", function() return 2 end)
+ assert(cb() == 2)
+ cb:set(function() return 3 end)
+ assert(cb() == 3)
+end
+
+do
+ local ft = ffi.typeof("void(*)(void)")
+ local function f() end
+ local t = {}
+ for i=1,4 do
+ for i=1,400 do t[i] = ft(f) end
+ for i=1,400 do t[i]:free() end
+ end
+end
+
+do
+ assert(ffi.cast("int (*)()", function() return string.byte"A" end)() == 65)
+end
+
+do
+ local f = ffi.cast("void (*)(void)", function() debug.traceback() end)
+ debug.sethook(function() debug.sethook(nil, "", 0); f() end, "", 1)
+ local x
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_const.lua b/test/LuaJIT-tests/lib/ffi/ffi_const.lua
new file mode 100644
index 0000000..d42133a
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_const.lua
@@ -0,0 +1,113 @@
+local ffi = require("ffi")
+
+dofile("../common/ffi_util.inc")
+
+ffi.cdef[[
+typedef struct s_t {
+ int v, w;
+} s_t;
+
+typedef const s_t cs_t;
+
+typedef enum en_t { EE } en_t;
+
+typedef struct pcs_t {
+ int v;
+ const int w;
+} pcs_t;
+
+typedef struct foo_t {
+ static const int cc = 17;
+ enum { CC = -37 };
+ int i;
+ const int ci;
+ int bi:8;
+ const int cbi:8;
+ en_t e;
+ const en_t ce;
+ int a[10];
+ const int ca[10];
+ const char cac[10];
+ s_t s;
+ cs_t cs;
+ pcs_t pcs1, pcs2;
+ const struct {
+ int ni;
+ };
+ complex cx;
+ const complex ccx;
+ complex *cp;
+ const complex *ccp;
+} foo_t;
+]]
+
+do
+ local foo_t = ffi.typeof("foo_t")
+ local x = foo_t()
+
+ -- constval
+ assert(x.cc == 17)
+ fails(function(x) x.cc = 1 end, x)
+ assert(x.CC == -37)
+ fails(function(x) x.CC = 1 end, x)
+
+ -- fields
+ x.i = 1
+ fails(function(x) x.ci = 1 end, x)
+ x.e = 1
+ fails(function(x) x.ce = 1 end, x)
+
+ -- bitfields
+ x.bi = 1
+ fails(function(x) x.cbi = 1 end, x)
+
+ -- arrays
+ do
+ local a = ffi.new("int[10]")
+ a[0] = 1
+ local ca = ffi.new("const int[10]")
+ fails(function(ca) ca[0] = 1 end, ca)
+ end
+ x.a[0] = 1
+ fails(function(x) x.ca[0] = 1 end, x)
+ fails(function(x) x.a = x.ca end, x) -- incompatible type
+ fails(function(x) x.ca = x.a end, x)
+ fails(function(x) x.ca = {} end, x)
+ fails(function(x) x.cac = "abc" end, x)
+
+ -- structs
+ do
+ local s = ffi.new("s_t")
+ s.v = 1
+ local cs = ffi.new("cs_t")
+ fails(function(cs) cs.v = 1 end, cs)
+ end
+ x.s.v = 1
+ fails(function(x) x.cs.v = 1 end, x)
+ x.s = x.cs
+ fails(function(x) x.cs = x.s end, x)
+ fails(function(x) x.cs = {} end, x)
+
+ -- pseudo-const structs
+ x.pcs1.v = 1
+ fails(function(x) x.pcs1.w = 1 end, x)
+ fails(function(x) x.pcs1 = x.pcs2 end, x)
+ fails(function(x) x.pcs1 = {} end, x)
+
+ -- transparent structs
+ local y = x.ni
+ fails(function(x) x.ni = 1 end, x)
+
+ -- complex subtype is implicitly const and doesn't inherit const attribute
+ x.cx = 1
+ fails(function(x) x.ccx = 1 end, x)
+ do
+ local cxa = ffi.new("complex[1]")
+ local ccxa = ffi.new("const complex[1]")
+ x.cp = cxa
+ x.ccp = cxa
+ fails(function(x) x.cp = ccxa end, x)
+ x.ccp = ccxa
+ end
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_convert.lua b/test/LuaJIT-tests/lib/ffi/ffi_convert.lua
new file mode 100644
index 0000000..bd3fb1f
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_convert.lua
@@ -0,0 +1,787 @@
+local ffi = require("ffi")
+
+local ctest = require("ctest")
+
+dofile("../common/ffi_util.inc")
+
+local tonumber = tonumber
+
+ffi.cdef[[
+typedef struct bar_t {
+ int v, w;
+} bar_t;
+// Same structure, but treated as different struct.
+typedef struct barx_t {
+ int v, w;
+} barx_t;
+
+typedef struct nest_t {
+ int a,b;
+ struct { int c,d; };
+ struct { int e1,e2; } e;
+ int f[2];
+} nest_t;
+
+typedef union uni_t {
+ int8_t a;
+ int16_t b;
+ int32_t c;
+} uni_t;
+
+typedef struct arrinc_t {
+ int a[];
+} arrinc_t;
+
+typedef enum uenum_t {
+ UE0, UE71 = 71, UE72
+} uenum_t;
+
+typedef enum ienum_t {
+ IE0, IEM12 = -12, IEM11
+} ienum_t;
+
+typedef struct foo_t {
+ bool b;
+ int8_t i8;
+ uint8_t u8;
+ int16_t i16;
+ uint16_t u16;
+ int32_t i32;
+ uint32_t u32;
+ int64_t i64;
+ uint64_t u64;
+ float f;
+ double d;
+ complex cf;
+ complex cd;
+ uint8_t __attribute__((mode(__V16QI__))) v16qi;
+ int __attribute__((mode(__V4SI__))) v4si;
+ double __attribute__((mode(__V2DF__))) v2df;
+ int *pi;
+ int *__ptr32 p32i;
+ const int *pci;
+ volatile int *pvi;
+ int **ppi;
+ const int **ppci;
+ void **ppv;
+ char *(*ppf)(char *, const char *);
+ int ai[10];
+ int ai_guard;
+ int ai2[10];
+ char ac[10];
+ char ac_guard;
+ bar_t s;
+ bar_t s2;
+ bar_t *ps;
+ const bar_t *pcs;
+ barx_t sx;
+ struct { int a,b,c; } si;
+ int si_guard;
+ nest_t sn;
+ uni_t ui;
+ uenum_t ue;
+ ienum_t ie;
+} foo_t;
+
+char *strcpy(char *dest, const char *src);
+typedef struct FILE FILE;
+int fileno(FILE *stream);
+int _fileno(FILE *stream);
+]]
+
+do
+ local foo_t = ffi.typeof("foo_t")
+ local sz = ffi.sizeof(foo_t)
+ local x = foo_t()
+ local y = foo_t()
+ ffi.fill(x, sz, 0xff)
+ ffi.fill(y, sz, 0xee)
+
+ -- unknown member
+ fails(function(x) local a = x.bad end, x)
+ fails(function(x) x.bad = 1 end, x)
+ -- too many initializers
+ fails(function(x) x.d = ffi.new("double", 1,2) end, x)
+
+ -- conversions to bool
+ x.b = false
+ assert(x.b == false)
+ x.b = true
+ assert(x.b == true)
+ x.b = 0
+ assert(x.b == false)
+ x.b = 10
+ assert(x.b == true)
+ y.b = false
+ x.b = y.b
+ assert(x.b == false)
+ x.b = ffi.new("bool", true)
+ assert(x.b == true)
+ x.b = ffi.cast("bool", false)
+ assert(x.b == false)
+ x.b = ffi.new("int32_t", 17)
+ assert(x.b == true)
+ x.b = ffi.new("int32_t", 0)
+ assert(x.b == false)
+
+ -- conversions from bool
+ x.i32 = true
+ assert(x.i32 == 1)
+ x.i32 = false
+ assert(x.i32 == 0)
+ x.i8 = ffi.new("bool", true)
+ assert(x.i8 == 1)
+ x.i8 = ffi.new("bool", false)
+ assert(x.i8 == 0)
+ x.d = true
+ assert(x.d == 1)
+ x.d = ffi.new("bool", false)
+ assert(x.d == 0)
+ -- assignment of bool to other types is not allowed
+ fails(function(x) x.cd = true end, x)
+ fails(function(x) x.v4si = true end, x)
+ fails(function(x) x.ai = true end, x)
+ fails(function(x) x.s = true end, x)
+
+ -- int to int conversions
+ x.i8 = 99
+ assert(x.i8 == 99)
+ x.i8 = -99
+ assert(x.i8 == -99)
+ x.i8 = 128
+ assert(x.i8 == -128)
+ x.i8 = 0xfffe
+ assert(x.i8 == -2)
+ y.i8 = 91
+ x.i8 = y.i8
+ assert(x.i8 == 91)
+ x.i8 = ffi.new("uint8_t", 0xb7)
+ assert(x.i8 == -73)
+ x.i8 = ffi.new("int16_t", 0x7fa0)
+ assert(x.i8 == -96)
+ x.i8 = ffi.new("int32_t", 0xff91)
+ assert(x.i8 == -111)
+ x.i8 = ffi.new("int64_t", 0xff81)
+ assert(x.i8 == -127)
+
+ x.u8 = 99
+ assert(x.u8 == 99)
+ x.u8 = -99
+ assert(x.u8 == 256-99)
+ x.u8 = 128
+ assert(x.u8 == 128)
+ x.u8 = 0xfffe
+ assert(x.u8 == 0xfe)
+ x.u8 = ffi.new("int8_t", -73)
+ assert(x.u8 == 0xb7)
+ x.u8 = ffi.new("int16_t", 0x7fa0)
+ assert(x.u8 == 0xa0)
+ x.u8 = ffi.new("int32_t", 0xff91)
+ assert(x.u8 == 0x91)
+ x.u8 = ffi.new("int64_t", 0xff81)
+ assert(x.u8 == 0x81)
+
+ x.i16 = 99
+ assert(x.i16 == 99)
+ x.i16 = -99
+ assert(x.i16 == -99)
+ x.i16 = 32768
+ assert(x.i16 == -32768)
+ x.i16 = 0xffffffe
+ assert(x.i16 == -2)
+ x.i16 = ffi.new("int8_t", -10)
+ assert(x.i16 == -10)
+ x.i16 = ffi.new("uint8_t", 254)
+ assert(x.i16 == 254)
+ x.i16 = ffi.new("uint16_t", 0xefa0)
+ assert(x.i16 == 0xefa0-65536)
+ x.i16 = ffi.new("int32_t", 0xffe291)
+ assert(x.i16 == 0xe291-65536)
+ x.i16 = ffi.new("int64_t", 0xffd481)
+ assert(x.i16 == 0xd481-65536)
+
+ x.u16 = 99
+ assert(x.u16 == 99)
+ x.u16 = -99
+ assert(x.u16 == 65536-99)
+ x.u16 = 32768
+ assert(x.u16 == 32768)
+ x.u16 = 0xffffffe
+ assert(x.u16 == 65534)
+ x.u16 = ffi.new("int8_t", -10)
+ assert(x.u16 == 65536-10)
+ x.u16 = ffi.new("uint8_t", 254)
+ assert(x.u16 == 254)
+ x.u16 = ffi.new("int16_t", 0xefa0-65536)
+ assert(x.u16 == 0xefa0)
+ x.u16 = ffi.new("int32_t", 0xffe291)
+ assert(x.u16 == 0xe291)
+ x.u16 = ffi.new("int64_t", 0xffd481)
+ assert(x.u16 == 0xd481)
+
+ x.i32 = 99
+ assert(x.i32 == 99)
+ x.i32 = -99
+ assert(x.i32 == -99)
+ -- double to int conversion for values >= 0x80000000 is undefined
+ x.i32 = ffi.new("int8_t", -10)
+ assert(x.i32 == -10)
+ x.i32 = ffi.new("uint8_t", 254)
+ assert(x.i32 == 254)
+ x.i32 = ffi.new("int16_t", -517)
+ assert(x.i32 == -517)
+ x.i32 = ffi.new("uint16_t", 35876)
+ assert(x.i32 == 35876)
+ x.i32 = ffi.new("uint32_t", 0xffffe291)
+ assert(x.i32 == 0xffffe291-2^32)
+ x.i32 = ffi.new("int64_t", 15*2^32-317)
+ assert(x.i32 == -317)
+
+ x.u32 = 99
+ assert(x.u32 == 99)
+ -- x.u32 = -99 -- this is undefined on some architectures
+ -- assert(x.u32 == 2^32-99)
+ x.u32 = 0x87654321
+ assert(x.u32 == 0x87654321)
+ x.u32 = ffi.new("int8_t", -10)
+ assert(x.u32 == 2^32-10)
+ x.u32 = ffi.new("uint8_t", 254)
+ assert(x.u32 == 254)
+ x.u32 = ffi.new("int16_t", -517)
+ assert(x.u32 == 2^32-517)
+ x.u32 = ffi.new("uint16_t", 35876)
+ assert(x.u32 == 35876)
+ x.u32 = ffi.new("int32_t", 0xffffe291-2^32)
+ assert(x.u32 == 0xffffe291)
+ x.u32 = ffi.new("int64_t", 15*2^32-317)
+ assert(x.u32 == 2^32-317)
+
+ x.i64 = 99
+ assert(tonumber(x.i64) == 99)
+ x.i64 = -99
+ assert(tonumber(x.i64) == -99)
+ x.i64 = 0x1234*2^32+0x87654321
+ assert(tonumber(x.i64) == 0x1234*2^32+0x87654321)
+ -- double to int64 conversion for values >= 2^63-1 is undefined
+ x.i64 = ffi.new("int8_t", -10)
+ assert(tonumber(x.i64) == -10)
+ x.i64 = ffi.new("uint8_t", 254)
+ assert(tonumber(x.i64) == 254)
+ x.i64 = ffi.new("int16_t", -517)
+ assert(tonumber(x.i64) == -517)
+ x.i64 = ffi.new("uint16_t", 35876)
+ assert(tonumber(x.i64) == 35876)
+ x.i64 = ffi.new("int32_t", -12345678)
+ assert(tonumber(x.i64) == -12345678)
+ x.i64 = ffi.new("uint32_t", 0xffeeddcc)
+ assert(tonumber(x.i64) == 0xffeeddcc)
+ x.i64 = ffi.new("uint64_t", 0xffeeddcc*2^32)
+ assert(tonumber(x.i64) == 0xffeeddcc*2^32-2^64)
+
+ x.u64 = 99
+ assert(tonumber(x.u64) == 99)
+ -- x.u64 = -99 -- this is undefined on some architectures
+ -- assert(tonumber(x.u64) == 2^64-99)
+ x.u64 = 0x1234*2^32+0x87654321
+ assert(tonumber(x.u64) == 0x1234*2^32+0x87654321)
+ -- double to int64 conversion for values >= 2^63-1 is undefined
+ x.u64 = ffi.new("int8_t", -10)
+ assert(tonumber(x.u64) == 2^64-10)
+ x.u64 = ffi.new("uint8_t", 254)
+ assert(tonumber(x.u64) == 254)
+ x.u64 = ffi.new("int16_t", -517)
+ assert(tonumber(x.u64) == 2^64-517)
+ x.u64 = ffi.new("uint16_t", 35876)
+ assert(tonumber(x.u64) == 35876)
+ x.u64 = ffi.new("int32_t", -12345678)
+ assert(tonumber(x.u64) == 2^64-12345678)
+ x.u64 = ffi.new("uint32_t", 0xffeeddcc)
+ assert(tonumber(x.u64) == 0xffeeddcc)
+ x.u64 = ffi.new("int64_t", -0x7feeddcc*2^32)
+ assert(tonumber(x.u64) == 2^64-0x7feeddcc*2^32)
+
+ -- FP to int conversions, test for truncation
+ x.i32 = 1.9
+ assert(x.i32 == 1)
+ x.i32 = 2.9
+ assert(x.i32 == 2)
+ x.i32 = -1.9
+ assert(x.i32 == -1)
+ x.i32 = -2.9
+ assert(x.i32 == -2)
+ x.i8 = 1.9
+ assert(x.i8 == 1)
+ x.u8 = 1.9
+ assert(x.u8 == 1)
+ x.i16 = 1.9
+ assert(x.i16 == 1)
+ x.u16 = 1.9
+ assert(x.u16 == 1)
+ x.u32 = 1.9
+ assert(x.u32 == 1)
+ x.u64 = 1.9
+ assert(tonumber(x.u64) == 1)
+
+ -- int to FP conversions (most tested above)
+ x.f = ffi.new("int32_t", -17)
+ assert(x.f == -17)
+ x.d = ffi.new("int32_t", -17)
+ assert(x.d == -17)
+ -- test for rounding due to precision loss
+ x.f = -1717986919
+ assert(x.f == -1717986944)
+ x.f = ffi.new("int32_t", 0x77777777)
+ assert(x.f == 0x77777780)
+ x.d = ffi.new("union { uint32_t u32[2]; uint64_t u64; }",
+ {{ 0x77777777, 0x77777777}}).u64
+ assert(x.d == 0x77777777*2^32 + 0x77777800)
+
+ -- complex initialization
+ x.cd = ffi.new("complex", 9.125, -78.5)
+ assert(x.cd.re == 9.125 and x.cd.im == -78.5)
+ x.cd = ffi.new("complex", {9.125, -78.5})
+ assert(x.cd.re == 9.125 and x.cd.im == -78.5)
+ -- too many initializers
+ fails(function(x) x.cd = ffi.new("complex", 1,2,3) end, x)
+
+ -- conversions between FP and complex
+ x.cf = -17.25
+ assert(x.cf.re == -17.25 and x.cf.im == 0)
+ x.cf = ffi.new("complex float", -57.5) -- missing initializer
+ assert(x.cf.re == -57.5 and x.cf.im == 0)
+ x.cf = ffi.new("complex float", 9.125, -78.5)
+ assert(x.cf.re == 9.125 and x.cf.im == -78.5)
+ x.cf = ffi.new("complex double", 9.125, -78.5)
+ assert(x.cf.re == 9.125 and x.cf.im == -78.5)
+
+ x.cd = -17.25
+ assert(x.cd.re == -17.25 and x.cd.im == 0)
+ x.cd = ffi.new("complex double", -57.5) -- missing initializer
+ assert(x.cd.re == -57.5 and x.cd.im == 0)
+ x.cd = ffi.new("complex float", 9.125, -78.5)
+ assert(x.cd.re == 9.125 and x.cd.im == -78.5)
+ x.cd = ffi.new("complex double", 9.125, -78.5)
+ assert(x.cd.re == 9.125 and x.cd.im == -78.5)
+
+ x.f = ffi.new("complex float", 9.125, -78.5)
+ assert(x.f == 9.125)
+ x.f = ffi.new("complex double", 9.125, -78.5)
+ assert(x.f == 9.125)
+
+ x.d = ffi.new("complex float", 9.125, -78.5)
+ assert(x.d == 9.125)
+ x.d = ffi.new("complex double", 9.125, -78.5)
+ assert(x.d == 9.125)
+
+ -- conversions between int and complex
+ x.cd = ffi.new("int32_t", -138)
+ assert(x.cd.re == -138 and x.cd.im == 0)
+ x.i32 = ffi.new("complex", 9.125, -78.5)
+ assert(x.i32 == 9)
+
+ -- vector initialization
+ x.v4si = ffi.new("int __attribute__((mode(__V4SI__)))", 1, 2, 3, 4)
+ assert(x.v4si[0] == 1 and x.v4si[1] == 2 and
+ x.v4si[2] == 3 and x.v4si[3] == 4)
+ x.v2df = ffi.new("double __attribute__((mode(__V2DF__)))", {3.5, -6.75})
+ assert(x.v2df[0] == 3.5 and x.v2df[1] == -6.75)
+ -- too many initializers
+ fails(function(x)
+ x.v4si = ffi.new("int __attribute__((mode(__V4SI__)))", 1,2,3,4,5)
+ end, x)
+
+ -- conversions to vectors
+ x.v4si = -17
+ assert(x.v4si[0] == -17 and x.v4si[1] == -17 and
+ x.v4si[2] == -17 and x.v4si[3] == -17)
+ x.v4si = ffi.new("int32_t", 712)
+ assert(x.v4si[0] == 712 and x.v4si[1] == 712 and
+ x.v4si[2] == 712 and x.v4si[3] == 712)
+ x.v2df = 12.5
+ assert(x.v2df[0] == 12.5 and x.v2df[1] == 12.5)
+ x.v2df = ffi.new("complex", 9.125, -78.5)
+ assert(x.v2df[0] == 9.125 and x.v2df[1] == 9.125)
+
+ -- assignment of same-sized but differently-typed vectors
+ x.v16qi = 99
+ x.v4si = 0x33333333
+ x.v16qi = x.v4si
+ assert(x.v16qi[0] == 0x33 and x.v16qi[15] == 0x33)
+
+ -- string converted to enum
+ -- x.ue = -1 -- this is undefined on some architectures
+ -- assert(x.ue == 0xffffffff)
+ x.ue = "UE0"
+ assert(x.ue == 0)
+ x.ue = "UE72"
+ assert(x.ue == 72)
+ x.ie = -1
+ assert(x.ie == -1)
+ x.ie = "IE0"
+ assert(x.ie == 0)
+ x.ie = "IEM11"
+ assert(x.ie == -11)
+
+ x.pi = x.pi
+ -- assignment to pointer with higher qualifiers is ok
+ x.pci = x.pi
+ x.pvi = x.pi
+ -- assignment to pointer with lower qualifiers is not ok
+ fails(function(x) x.pi = x.pci end, x)
+ fails(function(x) x.pi = x.pvi end, x)
+ fails(function(x) x.pci = x.pvi end, x)
+ fails(function(x) x.pvi = x.pci end, x)
+ -- assignment of pointers with incompatible child types is not ok
+ fails(function(x) x.ppi = x.ai end, x)
+ fails(function(x) x.ppi = x.pi end, x)
+ fails(function(x) x.ppv = x.ppi end, x)
+ -- qualifiers of child types must match, higher qualifiers not ok
+ fails(function(x) x.ppci = x.ppi end, x)
+ fails(function(x) x.ppi = x.ppci end, x)
+
+ -- pointer/int conversions are not allowed by default
+ fails(function(x) x.pi = 1 end, x)
+ fails(function(x) x.i32 = x.pi end, x)
+ assert(tonumber(x.pi) == nil)
+ assert(tonumber(x.ai) == nil)
+ assert(tonumber(x.si) == nil)
+
+ -- but pointer/int casts are allowed
+ x.pi = ffi.cast("int *", ffi.new("int32_t", 0x12345678))
+ x.i32 = ffi.cast("int32_t", x.pi)
+ assert(x.i32 == 0x12345678)
+ x.pi = ffi.cast("int *", 1234560.3)
+ x.i32 = ffi.cast("int32_t", x.pi)
+ assert(x.i32 == 1234560)
+ -- bad cast from non-TValue double to pointer
+ fails(function(x)
+ ffi.cast("int *", ffi.new("double", 1.5))
+ end, x)
+
+ -- nil sets a pointer to NULL
+ x.pi = nil
+ assert(tonumber(ffi.cast("uintptr_t", x.pi)) == 0)
+
+ -- userdata and lightuserdata are treated as void *
+ do
+ local u = newproxy()
+ local uaddr = _G.tonumber(string.match(tostring(u), "(0x.*)"))
+ x.pi = u
+ assert(tonumber(ffi.cast("uintptr_t", x.pi)) == uaddr)
+ x.pi = ctest.lightud(12345678)
+ assert(tonumber(ffi.cast("uintptr_t", x.pi)) == 12345678)
+ end
+
+ -- io.* file converts to file handle (as a void *)
+ if ffi.abi("win") then
+ assert(ffi.C._fileno(io.stdout) == 1)
+ assert(ffi.C._fileno(io.stderr) == 2)
+ local x
+ for i=1,100 do x = ffi.C._fileno(io.stderr) end
+ assert(x == 2)
+ else
+ assert(ffi.C.fileno(io.stdout) == 1)
+ assert(ffi.C.fileno(io.stderr) == 2)
+ local x
+ for i=1,100 do x = ffi.C.fileno(io.stderr) end
+ assert(x == 2)
+ end
+
+ -- truncation/extension of __ptr32
+ if ffi.abi("64bit") then
+ x.pi = ffi.cast("int *", 15*2^32+0x12345678)
+ assert(tonumber(ffi.cast("uintptr_t", x.pi)) == 15*2^32+0x12345678)
+ x.p32i = x.pi
+ assert(tonumber(ffi.cast("uintptr_t", x.p32i)) == 0x12345678)
+ x.pi = ffi.cast("int *", 0x1234*2^32+0x56780000)
+ x.pi = x.p32i
+ assert(tonumber(ffi.cast("uintptr_t", x.pi)) == 0x12345678)
+ end
+
+ -- reference initialization
+ do
+ x.ai[0] = 712
+ local ri = ffi.new("int &", x.ai)
+ assert(tonumber(ri) == 712)
+ local ra = ffi.new("int (&)[10]", ffi.cast("int (*)[10]", x.ai))
+ assert(ra[0] == 712)
+ end
+
+ -- ffi.sizeof follows references
+ assert(ffi.sizeof(x.ai) == 4*10)
+ -- ffi.offsetof follows references
+ assert(ffi.offsetof(x.s, "v") == 0)
+ assert(ffi.offsetof(x.s, "w") == 4)
+
+ -- ffi.fill writes the right amount
+ ffi.fill(x.ai2, ffi.sizeof(x.ai2), 0x72)
+ ffi.fill(x.ai, ffi.sizeof(x.ai), 0x13)
+ assert(x.ai[0] == 0x13131313)
+ assert(x.ai[9] == 0x13131313)
+ assert(x.ai2[0] == 0x72727272)
+ assert(x.ai2[9] == 0x72727272)
+
+ -- array cannot be assigned a pointer
+ fails(function(x) x.ai = x.pi end, x)
+ -- but pointer can be assigned the address of an array
+ x.pi = x.ai2
+ assert(x.pi[0] == 0x72727272)
+ assert(x.pi[9] == 0x72727272)
+ x.pi = x.ai
+ assert(x.pi[0] == 0x13131313)
+ assert(x.pi[9] == 0x13131313)
+ x.ai = x.ai2 -- array copy
+ assert(x.ai[0] == 0x72727272)
+ assert(x.ai[9] == 0x72727272)
+ -- reflected via pointer, too
+ assert(x.pi[0] == 0x72727272)
+ assert(x.pi[9] == 0x72727272)
+ -- mismatched type or size in array copy
+ fails(function(x) x.ai = x.ac end, x)
+ fails(function(x) x.ai = ffi.new("int[20]") end, x)
+ fails(function(x) x.ai = ffi.new("arrinc_t").a end, x)
+ fails(function(x) ffi.new("arrinc_t").a = x.ai end, x)
+
+ ffi.fill(x.s2, ffi.sizeof(x.s2), 0x59)
+ x.s.v = 0x12345678
+ x.s.w = 0x789abcde
+ assert(x.s.v == 0x12345678)
+ assert(x.s.w == 0x789abcde)
+
+ -- struct cannot be assigned a pointer
+ fails(function(x) x.s = x.ps end, x)
+ -- but pointer can be assigned the address of a struct
+ x.ps = x.s
+ assert(x.ps.v == 0x12345678)
+ assert(x.ps.w == 0x789abcde)
+ x.pcs = x.s
+ assert(x.pcs.v == 0x12345678)
+ assert(x.pcs.w == 0x789abcde)
+ x.s = x.s2 -- struct copy
+ assert(x.s.v == 0x59595959)
+ assert(x.s.w == 0x59595959)
+ -- reflected via pointer, too
+ assert(x.ps.v == 0x59595959)
+ assert(x.ps.w == 0x59595959)
+
+ -- structs must be identical, structural equivalence is not enough
+ fails(function(x) x.ps = x.sx end, x)
+ fails(function(x) x.s = x.sx end, x)
+
+ -- string copy to arrays
+ x.ac_guard = 99
+ ffi.fill(x.ac, 10, 0x37)
+ x.ac = "ABCD"
+ assert(x.ac[0] == 65+0)
+ assert(x.ac[3] == 65+3)
+ assert(x.ac[4] == 0)
+ assert(x.ac[5] == 0x37)
+ x.ac = "ABCDEFGHI"
+ assert(x.ac[8] == 65+8)
+ assert(x.ac[9] == 0)
+ x.ac = "ABCDEFGHIJ" -- reduced size
+ assert(x.ac[8] == 65+8)
+ assert(x.ac[9] == 65+9)
+ x.ac = "ABCDEFGHIJKLM"
+ assert(x.ac[8] == 65+8)
+ assert(x.ac[9] == 65+9)
+ do -- copy to a[?]
+ local vx = ffi.new("struct { char ac[?]; }", 20)
+ ffi.fill(vx.ac, 20, 0x37)
+ vx.ac = "ABCDEFGHI"
+ assert(vx.ac[8] == 65+8)
+ assert(vx.ac[9] == 0)
+ end
+ do -- copy to a[0]
+ local vx = ffi.new("union { char ac[0]; char c[20]; }")
+ ffi.fill(vx.ac, 20, 0x37)
+ vx.ac = "ABCDEFGHI"
+ assert(vx.ac[8] == 65+8)
+ assert(vx.ac[9] == 0)
+ end
+ -- mismatched type or size in string copy
+ fails(function(x) x.i32 = "ABCD" end, x)
+ fails(function(x) x.ai = "ABCD" end, x)
+ assert(x.ac_guard == 99) -- Check guard
+
+ -- array initialization
+ x.ai = ffi.new("int[10]") -- zero fill
+ for i=0,9 do assert(x.ai[i] == 0) end
+ x.ai = ffi.new("int[10]", -67) -- replicate first element
+ for i=0,9 do assert(x.ai[i] == -67) end
+ x.ai = ffi.new("int[10]", 42, -27) -- remainder filled with zero
+ assert(x.ai[0] == 42)
+ assert(x.ai[1] == -27)
+ for i=2,9 do assert(x.ai[i] == 0) end
+ x.ai = ffi.new("int[10]", 1,2,3,4,5,6,7,8,9,10)
+ for i=0,9 do assert(x.ai[i] == i+1) end
+ x.ai = ffi.new("int[10]", {1,2,3,4,5,6,7,8,9,10})
+ for i=0,9 do assert(x.ai[i] == i+1) end
+ -- VLA initialization
+ do
+ local v = ffi.new("int[?]", 4)
+ for i=0,3 do assert(v[i] == 0) end
+ local v = ffi.new("int[?]", 4, 833)
+ for i=0,3 do assert(v[i] == 833) end
+ local v = ffi.new("int[?]", 4, 12, -9)
+ assert(v[0] == 12 and v[1] == -9 and v[2] == 0 and v[3] == 0)
+ local v = ffi.new("int[?]", 4, 1,2,3,4)
+ assert(v[0] == 1 and v[1] == 2 and v[2] == 3 and v[3] == 4)
+ end
+ -- too many initializers
+ fails(function(x) x.ai = {1,2,3,4,5,6,7,8,9,10,11} end, x)
+ for i=0,9 do assert(x.ai[i] == i+1) end -- but it's partially executed
+ fails(function(x)
+ local v = ffi.new("int[?]", 4, 1,2,3,4,5)
+ end, x)
+
+ -- struct initialization
+ x.sn = ffi.new("nest_t") -- zero fill
+ assert(x.sn.e.e2 == 0)
+ x.sn = ffi.new("nest_t", 1,2) -- remainder filled with zero
+ assert(x.sn.a == 1 and x.sn.b == 2 and x.sn.c == 0 and x.sn.d == 0)
+ assert(x.sn.e.e1 == 0 and x.sn.e.e2 == 0)
+ assert(x.sn.f[0] == 0 and x.sn.f[1] == 0)
+ x.sn = ffi.new("nest_t", 1,2,3,4,{5,6},{7,8}) -- multi-value init
+ assert(x.sn.a == 1 and x.sn.b == 2 and x.sn.c == 3 and x.sn.d == 4)
+ assert(x.sn.e.e1 == 5 and x.sn.e.e2 == 6)
+ assert(x.sn.f[0] == 7 and x.sn.f[1] == 8)
+ x.sn = ffi.new("nest_t", {1,2,3,4,{5,6},{7,8}}) -- single-value init
+ assert(x.sn.a == 1 and x.sn.b == 2 and x.sn.c == 3 and x.sn.d == 4)
+ assert(x.sn.e.e1 == 5 and x.sn.e.e2 == 6)
+ assert(x.sn.f[0] == 7 and x.sn.f[1] == 8)
+ -- VLS initialization
+ do
+ local v = ffi.new("struct { int x; int a[?]; }", 4)
+ assert(v.x == 0)
+ for i=0,3 do assert(v.a[i] == 0) end
+ local v = ffi.new("struct { int x; int a[?]; }", 4, 9, {833})
+ assert(v.x == 9)
+ -- NYI: fill up VLA in VLS. currently seen as indefinite length
+ -- for i=0,3 do assert(v.a[i] == 833) end
+ assert(v.a[0] == 833 and v.a[1] == 0 and v.a[2] == 0 and v.a[3] == 0)
+ end
+ -- no multi-value init beyond first level
+ fails(function(x)
+ x.sn = ffi.new("nest_t", 1,2,3,4,5,6,7,8)
+ end, x)
+ -- too many initializers
+ fails(function(x)
+ x.sn = ffi.new("nest_t", 1,2,3,4,{5,6},{7,8}, 9)
+ end, x)
+
+ -- union initialization
+ x.ui = ffi.new("uni_t") -- zero fill
+ assert(x.ui.a == 0 and x.ui.b == 0 and x.ui.c == 0)
+ x.ui = ffi.new("uni_t", 255) -- initialize first field, remainder is zero
+ if ffi.abi("le") then
+ assert(x.ui.a == -1 and x.ui.b == 255 and x.ui.c == 255)
+ else
+ assert(x.ui.a == -1 and x.ui.b == -256 and x.ui.c == -16777216)
+ end
+ -- too many initializers
+ fails(function(x)
+ x.sn = ffi.new("uni_t", 1,2)
+ end, x)
+ fails(function()
+ ffi.new("union { struct { int x; }; int y; }", 1,2)
+ end)
+
+ -- table converted to array
+ ffi.fill(x.ai, ffi.sizeof(x.ai), 0x13)
+ x.ai_guard = 99
+ x.ai = {} -- zero fill
+ for i=0,9 do assert(x.ai[i] == 0) end
+ x.ai = {42} -- replicate
+ for i=0,9 do assert(x.ai[i] == 42) end
+ x.ai = {[0] = -67} -- replicate from index 0
+ for i=0,9 do assert(x.ai[i] == -67) end
+ x.ai = {42, -27} -- remainder filled with zero
+ assert(x.ai[0] == 42)
+ assert(x.ai[1] == -27)
+ for i=2,9 do assert(x.ai[i] == 0) end
+ assert(x.ai_guard == 99) -- Check guard
+
+ -- table converted to struct
+ ffi.fill(x.si, ffi.sizeof(x.si), 0x74)
+ x.si_guard = 97
+ -- convert from array part
+ x.si = {} -- zero fill
+ assert(x.si.a == 0 and x.si.b == 0 and x.si.c == 0)
+ x.si = {42, 18} -- fill fields in order
+ assert(x.si.a == 42 and x.si.b == 18 and x.si.c == 0)
+ x.si = {[0] = -67, 12} -- fill fields in order from index 0
+ assert(x.si.a == -67 and x.si.b == 12 and x.si.c == 0)
+ x.si = {42, -27, 19, 8} -- too many initializers ignored
+ assert(x.si.a == 42 and x.si.b == -27 and x.si.c == 19)
+ -- convert from hash part
+ x.si = {b = 12}
+ assert(x.si.a == 0 and x.si.b == 12 and x.si.c == 0)
+ x.si = {b = 12, c = 85, a = 35}
+ assert(x.si.a == 35 and x.si.b == 12 and x.si.c == 85)
+ x.si = {b = 19, foo = 1, bar = 2} -- unknown initializers ignored
+ assert(x.si.a == 0 and x.si.b == 19 and x.si.c == 0)
+ x.si = {b = 12, 5, 6, 7} -- hash part ignored if array part exists
+ assert(x.si.a == 5 and x.si.b == 6 and x.si.c == 7)
+ assert(x.si_guard == 97) -- Check guard
+
+ -- table converted to struct with transparent/nested structs and arrays
+ ffi.fill(x.sn, ffi.sizeof(x.sn), 0x74)
+ x.sn = {} -- zero fill
+ assert(x.sn.e.e2 == 0)
+ x.sn = {1,2,3,4,{5,6},{7,8}}
+ assert(x.sn.a == 1 and x.sn.b == 2 and x.sn.c == 3 and x.sn.d == 4)
+ assert(x.sn.e.e1 == 5 and x.sn.e.e2 == 6)
+ assert(x.sn.f[0] == 7 and x.sn.f[1] == 8)
+ x.sn = {c = 10, e = {11,12}, f = {13,14}}
+ assert(x.sn.a == 0 and x.sn.b == 0 and x.sn.c == 10 and x.sn.d == 0)
+ assert(x.sn.e.e1 == 11 and x.sn.e.e2 == 12)
+ assert(x.sn.f[0] == 13 and x.sn.f[1] == 14)
+
+ -- table converted to union
+ ffi.fill(x.ui, ffi.sizeof(x.ui), 0x58)
+ x.ui = {} -- zero fill
+ assert(x.ui.a == 0 and x.ui.b == 0 and x.ui.c == 0)
+ x.ui = {255, -1, -1} -- only first initializer used
+ if ffi.abi("le") then
+ assert(x.ui.a == -1 and x.ui.b == 255 and x.ui.c == 255)
+ else
+ assert(x.ui.a == -1 and x.ui.b == -256 and x.ui.c == -16777216)
+ end
+ x.ui = {b = -1} -- initialize a specific element of the union
+ if ffi.abi("le") then
+ assert(x.ui.a == -1 and x.ui.b == -1 and x.ui.c == 65535)
+ else
+ assert(x.ui.a == -1 and x.ui.b == -1 and x.ui.c == -65536)
+ end
+
+ -- copy constructor
+ do
+ x.s.v = 1; x.s.w = 2
+ local s = ffi.new("bar_t", x.s)
+ assert(s.v == 1 and s.w == 2)
+ for i=0,9 do x.ai[i] = i end
+ local a = ffi.new("int[10]", x.ai)
+ for i=0,9 do assert(a[i] == i) end
+ end
+
+ -- assignment to function pointer
+ x.ppf = ffi.C.strcpy
+end
+
+do
+ collectgarbage()
+ local oc = collectgarbage("count")
+ local cd = ffi.new"struct { struct { int a; } x;}"
+ local function f(cd)
+ local x
+ for i=1,1e5 do x = cd.x end
+ end
+ for i=1,2 do
+ f(cd)
+ local nc = collectgarbage("count")
+ assert(nc < oc + 200, "GC step missing for cdata __index")
+ jit.off(f)
+ end
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_enum.lua b/test/LuaJIT-tests/lib/ffi/ffi_enum.lua
new file mode 100644
index 0000000..e8e40ad
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_enum.lua
@@ -0,0 +1,57 @@
+
+local ffi = require("ffi")
+
+dofile("../common/ffi_util.inc")
+
+ffi.cdef[[
+typedef enum enum_i { FOO_I = -1, II = 10 } enum_i;
+typedef enum enum_u { FOO_U = 1, UU = 10 } enum_u;
+
+enum_i call_ei_i(int a) asm("call_i");
+enum_u call_eu_i(int a) asm("call_i");
+int call_i_ei(enum_i a) asm("call_i");
+int call_i_eu(enum_u a) asm("call_i");
+]]
+
+local C = ffi.load("../clib/ctest")
+
+do
+
+ local t = ffi.new("enum_i[100]")
+ for i=0,99 do t[i] = "II" end
+ for i=0,99 do assert(t[i] == "II") end
+ for i=0,99 do assert(t[i] >= "II") end
+ for i=0,99 do t[i] = -10 end
+ for i=0,99 do assert(t[i] == -10) end
+ for i=0,99 do assert(t[i] ~= 2147483648) end
+ for i=1,99 do assert(t[i] == t[i-1]) end
+ assert(t[0]+1 == -9)
+ assert(t[0] ~= "BB")
+ fails(function() return t[0] > "BB" end)
+
+ local u = ffi.new("enum_u[100]")
+ for i=0,99 do u[i] = "UU" end
+ for i=0,99 do assert(u[i] == "UU") end
+ for i=0,99 do assert(u[i] >= "UU") end
+ for i=0,99 do u[i] = 4294967296-10 end
+ for i=0,99 do assert(u[i] == 4294967296-10) end
+ for i=0,99 do assert(u[i] ~= -10) end
+ for i=1,99 do assert(u[i] == u[i-1]) end
+ assert(u[0]+1 == 4294967296-9)
+
+ for i=0,99 do assert(t[i] ~= u[i]) end
+end
+
+do
+ for i=0,99 do assert(C.call_ei_i(9) == "II") end
+ for i=0,99 do assert(C.call_eu_i(9) == "UU") end
+ for i=0,99 do assert(C.call_i_ei("II") == 11) end
+ for i=0,99 do assert(C.call_i_eu("UU") == 11) end
+end
+
+do
+ local f = ffi.cast("bool (*)(enum_i)", function(e) return e == "II" end)
+ assert(f("II"))
+ assert(not f(0))
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_gcstep_recursive.lua b/test/LuaJIT-tests/lib/ffi/ffi_gcstep_recursive.lua
new file mode 100644
index 0000000..cb19df1
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_gcstep_recursive.lua
@@ -0,0 +1,66 @@
+-- From Robert G. Jakabosky, 2012-03-20
+
+local N=tonumber(arg[1] or 10000)
+
+local ffi=require"ffi"
+
+ffi.cdef[[
+struct Buffer { void *buf; };
+typedef struct Buffer Buffer;
+]]
+
+local Buffer_mt = { __index = {} }
+local Buffer = ffi.typeof("Buffer")
+
+-- used to track alive objects
+local nobj_obj_flags = {}
+
+local function obj_to_id(ptr)
+ return tonumber(ffi.cast('uintptr_t', ffi.cast('void *', ptr)))
+end
+
+function obj_type_Buffer_push(val)
+ local obj = Buffer(val)
+ local id = obj_to_id(obj)
+ nobj_obj_flags[id] = true
+ return obj
+end
+
+local function Buffer_new(len)
+ local buf = ffi.cast('void *', 0xdeadbeef)
+ return obj_type_Buffer_push(buf)
+end
+
+function obj_type_Buffer_delete(obj)
+ local id = obj_to_id(obj)
+ if not nobj_obj_flags[id] then return nil end
+ nobj_obj_flags[id] = nil
+ return obj.buf
+end
+
+local getmeta = debug.getmetatable
+
+local function Buffer_close(self)
+ local buf = obj_type_Buffer_delete(self)
+ getmeta("Buffer_close") -- cause trace to abort
+ if buf then
+ self.buf = nil
+ end
+end
+Buffer_mt.__gc = Buffer_close
+Buffer_mt.__index.close = Buffer_close
+
+ffi.metatype(Buffer, Buffer_mt)
+
+local cdata = {}
+for x=1,2 do
+ cdata = {}
+ for i=1,N do
+ cdata[i] = Buffer_new(1)
+ end
+ for i=1,N do
+ cdata[i]:close()
+ end
+ cdata = nil
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_jit_arith.lua b/test/LuaJIT-tests/lib/ffi/ffi_jit_arith.lua
new file mode 100644
index 0000000..0554fe6
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_jit_arith.lua
@@ -0,0 +1,155 @@
+local ffi = require("ffi")
+
+do
+ local a = ffi.new("int64_t[?]", 101)
+ for i=1,100 do a[i] = -2 end
+ for i=1,100 do a[i] = i end
+ local x, y, m = 0ll, 0ll, 0ll
+ for i=1,100 do x = x + a[i]; y = y - a[i]; m = -a[i] end
+ assert(x == 5050)
+ assert(y == -5050)
+ assert(m == -100)
+ local z, z0 = 1ll, 3ll
+ for i=1,100 do z = a[i] * z0 end
+ assert(z == 300)
+ for i=1,100 do z = a[i] * 4ll end -- test MUL -> BSHL rule
+ assert(z == 400)
+ z, z0 = 1ll, 0x123456789abcdef0ll
+ for i=1,100 do z = z0 / a[i] end
+ assert(z == 0x123456789abcdef0ll / 100)
+ z, z0 = 1ll, 0x123456789abcdef0ll
+ for i=1,100 do z = z0 % a[i] end
+ assert(z == 0x123456789abcdef0ll % 100)
+ -- use multiple 64 bit PHIs
+ local t, u, v, w = 0ll, 0ll, 0ll, 0ll
+ for i=1,100 do t = t + a[i]; u = u + a[i]; v = v + a[i]; w = w + a[i] end
+ assert(t == 5050)
+ assert(u == 5050)
+ assert(v == 5050)
+ assert(w == 5050)
+end
+
+do
+ local a = ffi.new("uint64_t[?]", 101)
+ for i=1,100 do a[i] = i end
+ local x, y, m = 0ull, 0ull, 0ull
+ for i=1,100 do x = x + a[i]; y = y - a[i]; m = -a[i] end
+ assert(x == 5050)
+ assert(y == 0ull-5050)
+ assert(m == -100ull)
+ local z, z0 = 1ull, 3ll
+ for i=1,100 do z = a[i] * z0 end
+ assert(z == 300)
+ z, z0 = 1ull, 0x123456789abcdef0ull
+ for i=1,100 do z = z0 / a[i] end
+ assert(z == 0x123456789abcdef0ull / 100)
+ z, z0 = 1ull, 0x123456789abcdef0ull
+ for i=1,100 do z = z0 % a[i] end
+ assert(z == 0x123456789abcdef0ull % 100)
+end
+
+do
+ local x = 0ll
+ for i=1,100 do x = x + (-2ll) ^ (bit.band(i, 15)+1ll) end
+ assert(x == 262120)
+end
+
+do
+ local x, a = 0ll, -2ll
+ for i=1,100 do x = x + a ^ (bit.band(i, 15)+1ll) end
+ assert(x == 262120)
+end
+
+do
+ local x = 0ull
+ for i=1,100 do x = x + (-2ll) ^ (bit.band(i, 15)+1ull) end
+ assert(x == 262120)
+end
+
+do
+ for i=1,200 do local j = bit.band(i, 7); assert((j == 0ll) == (j == 0)) end
+ for i=1,200 do assert((i < 100ll) == (i < 100)) end
+ for i=1,200 do assert((i <= 100ll) == (i <= 100)) end
+ for i=-100,100 do assert((i > 100ull) == (i < 0)) end
+end
+
+do
+ local a = ffi.new("int64_t[?]", 100)
+ for i=0,99 do
+ a[i] = math.random(0, 2^32)*0x100000000LL + math.random(0, 2^32)
+ end
+ a[92] = 0x10000000LL
+ a[93] = 0x10000001LL
+ a[94] = math.random(0, 2^32)
+ a[95] = a[94] + 0x100000000LL
+ a[96] = a[94] + 0x100000001LL
+ a[97] = a[20]
+ a[98] = 0
+ a[99] = -1
+
+ local function cksum(b)
+ local bxor, rol = bit.bxor, bit.rol
+ local x = 0
+ for i=0,#b do x = rol(bxor(x, (b[i] and i or 0)), 7) end
+ return x
+ end
+
+ local s = [[
+ local a, b = ...
+ local k = 0
+ for i=0,99 do
+ for j=0,99 do
+ b[k] = a[i] %s a[j]
+ k = k + 1
+ end
+ end
+ ]]
+
+ local ap = ffi.new("int64_t *", a)
+ local b = {}
+ for i=1,2 do
+ for _,cmp in ipairs{ "==", "~=", "<", "<=", ">", ">=" } do
+ local f = assert(loadstring(string.format(s, cmp), "operator"..cmp))
+ f(ap, b)
+ local r1 = cksum(b)
+ jit.off(f)
+ f(ap, b)
+ local r2 = cksum(b)
+ assert(r1 == r2)
+ end
+ ap = ffi.new("uint64_t *", a)
+ end
+end
+
+do
+ local a, b = ffi.new("char *"), ffi.new("char *")
+ local z
+ for i=1,100 do z = a-b end
+end
+
+do
+ local x = true
+ local abc = ffi.cast("const char *", "abc")
+ for i=1,100 do x = abc == "abc" end
+ assert(x == true)
+ for i=1,100 do x = abc == "xyz" end
+ assert(x == false)
+ for i=1,100 do x = 0LL == "" end
+ assert(x == false)
+ for i=1,100 do x = 0LL == false end
+ assert(x == false)
+ for i=1,100 do x = 0LL == nil end
+ assert(x == false)
+end
+
+-- ra_destpair
+do
+ local x, y = 0, 0
+ for i=1,100 do
+ x = x + i/3LL
+ y = y + i/5LL
+ end
+ assert(x == 1650)
+ assert(y == 970)
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_jit_call.lua b/test/LuaJIT-tests/lib/ffi/ffi_jit_call.lua
new file mode 100644
index 0000000..b79d60b
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_jit_call.lua
@@ -0,0 +1,154 @@
+
+local ffi = require("ffi")
+
+ffi.cdef[[
+int call_10i(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j);
+double call_10d(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j);
+float call_10f(float a, float b, float c, float d, float e, float f, float g, float h, float i, float j);
+int64_t call_ij(int a, int64_t b);
+bool call_b(int a) asm("call_i");
+
+int64_t call_max(double,double,double,double,double,double,double,double,double,double,double,double,double,double,double,double,double) asm("call_10d");
+
+int64_t call_10j_p(int a, int b, int c, int d, int e, int f, int g, int h, int i, const char *p) asm("call_10j");
+
+int8_t call_i_i8(int a) asm("call_i");
+uint8_t call_i_u8(int a) asm("call_i");
+int16_t call_i_i16(int a) asm("call_i");
+uint16_t call_i_u16(int a) asm("call_i");
+int call_i8_i(int8_t a) asm("call_i");
+int call_u8_i(uint8_t a) asm("call_i");
+int call_i16_i(int16_t a) asm("call_i");
+int call_u16_i(uint16_t a) asm("call_i");
+
+int __fastcall fastcall_void(void);
+int __fastcall fastcall_i(int a);
+int __fastcall fastcall_ii(int a, int b);
+int __fastcall fastcall_iii(int a, int b, int c);
+int64_t __fastcall fastcall_ji(int64_t a, int b);
+double __fastcall fastcall_dd(double a, double b);
+int __fastcall fastcall_pp_i(int *a, int *b);
+
+int __stdcall stdcall_i(int a);
+int __stdcall stdcall_ii(int a, int b);
+double __stdcall stdcall_dd(double a, double b);
+float __stdcall stdcall_ff(float a, float b);
+]]
+
+local lib = ffi.load("../clib/ctest")
+
+do
+ local x
+ for i=1,100 do
+ x = lib.call_10i(-42, 17, 12345, 9987, -100, 11, 51, 0x12345678, 338, -78901234)
+ end
+ assert(x == -42+17+12345+9987-100+11+51+0x12345678+338-78901234)
+end
+
+do
+ for i=1,100 do
+ pcall(lib.call_max, i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i,i)
+ end
+end
+
+if ffi.abi("64bit") then
+ local y = ffi.cast("void *", 0x123456789abcdefLL)
+ local x
+ for i=1,100 do
+ lib.call_10j_p(0,0,0,0,0,0,0,0,0, y)
+ x = lib.call_10j_p(0,0,0,0,0,0,0,0,0, nil)
+ end
+ assert(x == 0)
+end
+
+do
+ local x = 0
+ for i=1,100 do
+ x = x + lib.call_ij(100+i, i*0x300000002LL)
+ end
+ assert(x == 0x3b2e0000623eLL)
+end
+
+do
+ local x
+ for i=1,100 do
+ x = lib.call_10d(-42.5, 17.125, 12345.5, 9987, -100.625, 11, 51, 0x12345678, 338, -78901234.75)
+ end
+ assert(x == -42.5+17.125+12345.5+9987-100.625+11+51+0x12345678+338-78901234.75)
+end
+
+do
+ local x
+ for i=1,100 do
+ x = lib.call_10f(-42.5, 17.125, 12345.5, 9987, -100.625, 11, 51, 0x123456, 338, -789012.75)
+ end
+ assert(x == -42.5+17.125+12345.5+9987-100.625+11+51+0x123456+338-789012.75)
+end
+
+do
+ local x
+ for i=-100,100 do
+ if not lib.call_b(i) then x = i end
+ end
+ assert(x == -1)
+ local t = {}
+ for i=1,100 do t[i] = -1 end
+ t[90] = 0
+ for i=1,100 do
+ if lib.call_b(t[i]) then x = i end
+ end
+ assert(x == 90)
+end
+
+do
+ local function tail(x)
+ return lib.call_b(x)
+ end
+ for i=1,100 do local a,b,c = tail(1), tail(1), tail(1) end
+end
+
+do
+ local x = 0
+ for i=0x01010080,0x010100ff do x = x + lib.call_i_i8(i) end
+ assert(x == -8128)
+ x = 0
+ for i=0x01010080,0x010100ff do x = x + lib.call_i_u8(i) end
+ assert(x == 24384)
+ x = 0
+ for i=0x0101ff80,0x0101ffff do x = x + lib.call_i_i16(i) end
+ assert(x == -8128)
+ x = 0
+ for i=0x0101ff80,0x0101ffff do x = x + lib.call_i_u16(i) end
+ assert(x == 8314944)
+ x = 0
+ for i=0x01010080,0x010100ff do x = x + lib.call_i8_i(i) end
+ assert(x == -8128)
+ x = 0
+ for i=0x01010080,0x010100ff do x = x + lib.call_u8_i(i) end
+ assert(x == 24640)
+ x = 0
+ for i=0x0101ff80,0x0101ffff do x = x + lib.call_i16_i(i) end
+ assert(x == -8128)
+ x = 0
+ for i=0x0101ff80,0x0101ffff do x = x + lib.call_u16_i(i) end
+ assert(x == 8380480)
+end
+
+-- target-specific
+if jit.arch == "x86" then
+ for i=1,100 do assert(lib.fastcall_i(-42) == -41) end
+ for i=1,100 do assert(lib.fastcall_ii(-42, 17) == -42+17) end
+ for i=1,100 do assert(lib.fastcall_iii(-42, 17, 139) == -42+17+139) end
+ for i=1,100 do assert(lib.fastcall_ji(0x123456789LL, -17) == 0x123456789LL-17) end
+ for i=1,100 do assert(lib.fastcall_dd(12.5, -3.25) == 12.5-3.25) end
+ local x = lib.fastcall_ji
+ for i=1,100 do assert(x(0x123456789LL, -17) == 0x123456789LL-17) end
+
+ if jit.os == "Windows" then
+ for i=1,100 do assert(lib.stdcall_i(-42) == -41) end
+ for i=1,100 do assert(lib.stdcall_ii(-42, 17) == -42+17) end
+ for i=1,100 do assert(lib.stdcall_dd(12.5, -3.25) == 12.5-3.25) end
+ for i=1,100 do assert(lib.stdcall_ff(12.5, -3.25) == 12.5-3.25) end
+ end
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_jit_conv.lua b/test/LuaJIT-tests/lib/ffi/ffi_jit_conv.lua
new file mode 100644
index 0000000..d4707db
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_jit_conv.lua
@@ -0,0 +1,277 @@
+local ffi = require("ffi")
+
+local ctest = require("ctest")
+
+do
+ local s = ffi.new("struct { int32_t x; }")
+ s.x = -0x12345678
+ for i=1,100 do
+ s.x = s.x + 1 -- narrowed
+ end
+ assert(s.x == -0x12345678+100)
+end
+
+do
+ local s = ffi.new("struct { uint32_t x; }")
+ s.x = 0x81234567
+ for i=1,100 do
+ s.x = s.x + 1 -- CONV.num.u32, CONV.u32.num (no narrowing yet)
+ end
+ assert(s.x == 0x81234567+100)
+end
+
+do
+ local s = ffi.new("struct { int8_t x; }")
+ s.x = 42
+ for i=1,100 do
+ s.x = s.x + 1
+ assert(s.x >= -128 and s.x <= 127) -- fwd -> CONV.int.i8
+ end
+ assert(s.x == 142-256)
+end
+
+do
+ local s = ffi.new("struct { uint8_t x; }")
+ s.x = 200
+ for i=1,100 do
+ s.x = s.x + 1
+ assert(s.x >= 0 and s.x <= 255) -- fwd -> CONV.int.u8
+ end
+ assert(s.x == 300-256)
+end
+
+do
+ local s = ffi.new("struct { int16_t x; }")
+ s.x = 32700
+ for i=1,100 do
+ s.x = s.x + 1
+ assert(s.x >= -32768 and s.x <= 32767) -- fwd -> CONV.int.i16
+ end
+ assert(s.x == 32800-65536)
+end
+
+do
+ local s = ffi.new("struct { uint16_t x; }")
+ s.x = 65450
+ for i=1,100 do
+ s.x = s.x + 1
+ assert(s.x >= 0 and s.x <= 65535) -- fwd -> CONV.int.u16
+ end
+ assert(s.x == 65550-65536)
+end
+
+do
+ local s = ffi.new("union { int32_t x; uint32_t y; }")
+ s.x = 0x7fffffff - 60
+ local x,y = 0,0
+ for i=1,100 do
+ if s.x == 0x7fffffff then s.x = -0x80000000 else s.x = s.x + 1 end
+ x = x + s.x -- fwd -> CONV.num.int
+ y = y + s.y -- fwd -> CONV.num.u32
+ end
+ assert(s.x == 0x7fffffff - 60 + 100 - 2^32)
+ assert(s.y == 0x7fffffff - 60 + 100)
+ assert(y == (0x7fffffff - 60) * 100 + 5050)
+ assert(x == y - 40*2^32)
+end
+
+do
+ local s = ffi.new("union { int32_t x; uint32_t y; }")
+ local x, z = 0, 2^31 + 42
+ for i=1,100 do
+ s.y = z
+ x = x + s.x -- fwd -> CONV.int.u32 (dummy)
+ end
+ assert(x == 100*(-2^31 + 42))
+end
+
+do
+ local s = ffi.new("union { int8_t x; uint8_t y; }")
+ s.x = 42
+ local x,y = 0,0
+ for i=1,100 do
+ s.x = s.x + 1
+ x = x + s.x -- fwd -> CONV.int.i8, CONV.num.int
+ y = y + s.y -- fwd -> CONV.int.u8, CONV.num.int
+ end
+ assert(s.x == 142 - 256)
+ assert(s.y == 142)
+ assert(y == 42 * 100 + 5050)
+ assert(x == y - (100-(127-42))*256)
+end
+
+do
+ local a = ffi.new("uint32_t[?]", 101)
+ for i=1,100 do a[i] = 0x80000000+i end
+ local x = 0
+ for i=1,100 do
+ x = bit.bxor(x, a[i]) -- FOLD TOBIT + CONV.num.u32
+ end
+ assert(x == 100)
+end
+
+do
+ local a = ffi.new("uint32_t[?]", 101)
+ for i=1,100 do a[i] = 0x80000000+i end
+ local x = 0
+ for i=1,100 do
+ x = bit.bxor(a[i], 0) -- FOLD TOBIT + CONV.num.u32
+ end
+ assert(x == -0x80000000+100)
+end
+
+do
+ local v = ffi.new("float", 12.5)
+ local x = 0
+ for i=1,100 do
+ x = x + tonumber(v) -- CONV.num.flt
+ end
+ assert(x == 100*12.5)
+end
+
+do
+ local v = ffi.new("uint32_t", 0x80000000)
+ local x = 0
+ for i=1,100 do
+ x = x + tonumber(v) -- CONV.num.u32
+ end
+ assert(x == 100*0x80000000)
+end
+
+do
+ local v = ffi.new("int64_t", 0x1234567800000000ll)
+ local x = 0
+ for i=1,100 do
+ x = x + tonumber(v) -- CONV.num.i64
+ end
+ assert(x == 100*0x12345678*2^32)
+end
+
+do
+ local v = ffi.new("uint64_t", 0x89abcdef00000000ull)
+ local x = 0
+ for i=1,100 do
+ x = x + tonumber(v) -- CONV.num.u64
+ end
+ assert(x == 100*0x89abcdef*2^32)
+end
+
+do
+ local a = ffi.new("int64_t[?]", 101)
+ for i=1,100 do a[i] = -i end
+ local x = 0
+ for i=1,100 do
+ x = x + tonumber(a[i]) -- CONV.num.i64
+ end
+ assert(x == -5050)
+end
+
+do
+ local a = ffi.new("uint64_t[?]", 101)
+ for i=1,100 do a[i] = 2^63+2^32*i end
+ local x = 0
+ for i=1,100 do
+ x = x + tonumber(a[i]) -- CONV.num.u64
+ end
+ assert(x == 2^63*100+2^32*5050)
+end
+
+do
+ local v = ffi.new("complex", 12.5, -3.25)
+ local x = 0
+ for i=1,100 do
+ x = x + tonumber(v)
+ end
+ assert(x == 100*12.5)
+end
+
+do
+ local s = ffi.new("struct { int64_t x;}")
+ for i=1,100 do
+ s.x = 0x123456789abcdef0LL
+ end
+ assert(tonumber(s.x) == tonumber(0x123456789abcdef0LL))
+end
+
+do
+ local s = ffi.new("struct { uint64_t x;}")
+ for i=1,100 do
+ s.x = 0x823456789abcdef0ULL
+ end
+ assert(tonumber(s.x) == tonumber(0x823456789abcdef0ULL))
+end
+
+do
+ ffi.cdef[[
+ typedef enum { AA, BB, CC = -42 } foo_i;
+ typedef enum { DD, EE, FF = 0x80000000u } foo_u;
+ ]]
+ local s = ffi.new("struct { foo_i x; foo_u y;}")
+ for i=1,100 do
+ s.x = "CC"
+ assert(s.x == -42)
+ s.x = "BB"
+ assert(s.x == 1)
+ s.y = "FF"
+ assert(s.y == 0x80000000)
+ end
+ local st = ffi.typeof(s)
+ for i=1,100 do s = st() end
+ assert(s.x == 0 and s.y == 0)
+ for i=1,100 do s = st("CC", "EE") end
+ assert(s.x == -42 and s.y == 1)
+ local ei = ffi.new("foo_i", "CC")
+ local eu = ffi.new("foo_u", "EE")
+ for i=1,100 do s = st(ei, eu) end
+ assert(s.x == -42 and s.y == 1)
+ local x
+ for i=1,100 do x = tonumber(ei) end
+ assert(x == -42)
+end
+
+do
+ local s = ffi.new("struct { const char *x; const char *y;}")
+ local a, tmp = "abcd", "ab"
+ for i=1,100 do
+ s.x = "abc"
+ s.y = string.sub(a, 1, 2)
+ end
+ assert(ffi.string(s.x) == "abc")
+ assert(ffi.string(s.y) == "ab")
+end
+
+do
+ local s = ffi.new("struct { bool b[200]; int i[200]; double d[200];}")
+ for i=0,199 do s.i[i] = i-100; s.d[i] = i-100 end
+ for i=0,99 do s.b[i] = 0 end
+ for i=100,199 do s.b[i] = 1 end
+ for i=0,99 do assert(s.b[i] == false) end
+ for i=100,199 do assert(s.b[i] == true) end
+ for i=0,199 do s.b[i] = s.i[i] end
+ for i=0,199 do assert(s.b[i] == (i ~= 100)) end
+ for i=0,199 do s.b[i] = s.d[i] end
+ for i=0,199 do assert(s.b[i] == (i ~= 100)) end
+end
+
+do
+ local a = ffi.new("int16_t[100]", 1)
+ for i=1,99 do a[i] = a[i] + a[i-1] end
+ assert(a[99] == 100)
+end
+
+do
+ local ud = ctest.lightud(12345678)
+ local s = ffi.new("struct { void *p; }")
+ for i=1,100 do
+ assert(ffi.cast("uintptr_t", ud) == 12345678)
+ s.p = ud
+ end
+ assert(ffi.cast("uintptr_t", s.p) == 12345678)
+end
+
+do
+ local x = ffi.new("struct { int & x;}", ffi.new("int[1]", 42))
+ local z
+ for i=1,100 do z = x.x end
+ assert(z == 42)
+end
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_lex_number.lua b/test/LuaJIT-tests/lib/ffi/ffi_lex_number.lua
new file mode 100644
index 0000000..e26650e
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_lex_number.lua
@@ -0,0 +1,51 @@
+local ffi = require("ffi")
+
+dofile("../common/ffi_util.inc")
+
+local function checklex(t)
+ for i=1,1e9,2 do
+ local s = t[i+1]
+ if not s then break end
+ local s2 = assert(loadstring("return tostring("..s..")"))()
+ if s2 ~= t[i] then
+ print(s2)
+ error("lexer failed for '"..s.."'", 2)
+ end
+ end
+end
+
+checklex{
+ "0LL", "0ll",
+ "0LL", "0LL",
+ "0ULL", "0ull",
+ "0ULL", "0ULl",
+ "18446744073709551615ULL", "18446744073709551615llu",
+ "9223372036854775807LL", "0x7fffffffffffffffll",
+ "9223372036854775808ULL", "0x8000000000000000ull",
+ "1311768467463790320LL", "0x123456789abcdef0ll",
+ "-1LL", "-1ll",
+ "18446744073709551615ULL", "-1ull",
+ "-9223372036854775807LL", "-0x7fffffffffffffffll",
+ "9223372036854775808ULL", "-0x8000000000000000ull",
+ "0+0i", "0i",
+ "0+0i", "0I",
+ "0+12.5i", "12.5i",
+ "0+4660i", "0x1234i",
+ "0+infI", "1e400i",
+ "0-infI", "-1e400i",
+ "0-12.5i", "-12.5i",
+ "0-0i", "-0i",
+}
+
+checkfail({
+ "0l",
+ "0lll",
+ "0u",
+ "0ul",
+ "0ulll",
+ "0wll",
+ "0xll",
+ ".0ll",
+ "0ii",
+}, function(s) assert(loadstring("return "..s)) end)
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_metatype.lua b/test/LuaJIT-tests/lib/ffi/ffi_metatype.lua
new file mode 100644
index 0000000..2db717f
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_metatype.lua
@@ -0,0 +1,245 @@
+local ffi = require("ffi")
+
+dofile("../common/ffi_util.inc")
+
+ffi.cdef[[
+typedef struct { int x; } idx1_t;
+typedef struct { int x; } idx2_t;
+typedef struct { int x; } idx3_t;
+typedef struct { int x,y; } arith_t;
+typedef struct { void *p; } gc_t;
+]]
+
+local function ptreq(a, b)
+ return ffi.cast("void *", a) == ffi.cast("void *", b)
+end
+
+do
+ local nidx = {}
+ local tp = ffi.metatype("idx1_t", {
+ __index = { foo = 99, method = function(c, v) return v end },
+ __newindex = nidx,
+ })
+
+ fails(function() ffi.metatype("idx1_t", {}) end)
+
+ local s = tp(1234)
+ assert(s.foo == 99)
+ assert(s.x == 1234)
+ -- bad field in __index metatable
+ fails(function(s) local x = s.bar end, s)
+ assert(s:method(123) == 123)
+ s.bar = 42
+ assert(nidx.bar == 42)
+
+ local cs = ffi.new("const idx1_t", 9876)
+ assert(cs.foo == 99)
+ assert(cs.x == 9876)
+ -- write to const struct
+ fails(function(cs) cs.bar = 42 end, cs)
+
+ local cp = ffi.new("const idx1_t *", cs)
+ assert(cp.foo == 99)
+ assert(cp.x == 9876)
+ -- write to const struct pointer
+ fails(function(cp) cp.bar = 42 end, cp)
+end
+
+do
+ local uc, uk, uv
+ local tp = ffi.metatype("idx2_t", {
+ __index = function(c, k, x, y)
+ assert(x == nil and y == nil)
+ uc, uk = c, k; return 99
+ end,
+ __newindex = function(c, k, v) uc, uk, uv = c, k, v end,
+ })
+
+ local s = tp(1234)
+ assert(s.foo == 99)
+ assert(ptreq(uc, s) and uk == "foo" and uv == nil); uc,uk,uv=nil,nil,nil
+ assert(s.x == 1234)
+ assert(uc == nil and uk == nil and uv == nil); uc,uk,uv=nil,nil,nil
+
+ s.bar = 42
+ assert(ptreq(uc, s) and uk == "bar" and uv == 42); uc,uk,uv=nil,nil,nil
+ s[10] = 11
+ assert(ptreq(uc, s) and uk == 10 and uv == 11); uc,uk,uv=nil,nil,nil
+
+ local p = ffi.new("idx2_t *", s)
+ assert(p.foo == 99)
+ assert(ptreq(uc, p) and uk == "foo" and uv == nil); uc,uk,uv=nil,nil,nil
+ assert(p.x == 1234)
+ assert(uc == nil and uk == nil and uv == nil); uc,uk,uv=nil,nil,nil
+ -- pointer dereference has precedence
+ assert(ptreq(p[0], p))
+ assert(uc == nil and uk == nil and uv == nil); uc,uk,uv=nil,nil,nil
+ -- pointer dereference has precedence
+ fails(function(p) p[0] = 11 end, p)
+end
+
+do
+ local uc, uk, uv
+ local ti, tn = {}, {}
+ local tp = ffi.metatype("idx3_t", {
+ __index = setmetatable(ti,
+ { __index = function(c, k) uc, uk = c, k; return 99 end }),
+ __newindex = setmetatable(tn,
+ { __newindex = function(c, k, v) uc, uk, uv = c, k, v end }),
+ })
+
+ local s = tp(1234)
+ assert(s.foo == 99)
+ assert(uc == ti and uk == "foo" and uv == nil)
+ uc, uk, uv = nil, nil, nil
+ assert(s.x == 1234)
+ assert(uc == nil and uk == nil and uv == nil)
+
+ s.bar = 42
+ assert(uc == tn and uk == "bar" and uv == 42)
+ uc, uk, uv = nil, nil, nil
+ s[10] = 11
+ assert(uc == tn and uk == 10 and uv == 11)
+ uc, uk, uv = nil, nil, nil
+end
+
+do
+ local tp
+ tp = ffi.metatype("arith_t", {
+ __add = function(a, b) return tp(a.x+b.x, a.y+b.y) end,
+ __sub = function(a, b) return tp(a.x-b.x, a.y-b.y) end,
+ __mul = function(a, z) return tp(a.x*z, a.y*z) end,
+ __div = function(z, a) return tp(a.x*z, a.y*z) end,
+ __concat = setmetatable({}, { __call = function(x) return 99 end }),
+ __len = function(x) return 2 end,
+ __call = function(a) return a.x+a.y end,
+ __tostring = function(a) return "foo" end,
+ __newindex = function(a, k, v) a.y = v end,
+ __index = {
+ diff = function(a) return a.x-a.y end,
+ },
+ })
+
+ local a = tp(10, 20)
+ local b = tp(1, 2)
+ local c = a + b
+ assert(c.x == 11 and c.y == 22)
+ assert(c:diff() == -11)
+ assert(c() == 33)
+ local d = a - b
+ assert(d.x == 9 and d.y == 18)
+ assert(d:diff() == -9)
+ assert(d() == 27)
+ local e = a * 3
+ assert(e.x == 30 and e.y == 60)
+ local f = 3LL / a
+ assert(f.x == 30 and f.y == 60)
+ assert(1 .. c == 99)
+ assert(c .. 1 == 99)
+ assert(c .. d == 99)
+ assert(tostring(c) == "foo")
+ assert(tostring(ffi.cast("arith_t *", c)) == "foo")
+ c.foo = 42
+ assert(c.y == 42)
+
+ local p = ffi.new("arith_t *", a)
+ local g1 = p + p
+ assert(g1.x == 20 and g1.y == 40)
+ local g2 = p[0] + p[0]
+ assert(g2.x == 20 and g2.y == 40)
+ assert(p() == 30)
+
+ local q = ffi.new("arith_t &", a)
+ fails(function(p) local y = q[0] + q[0] end, q)
+ local h = q + q
+ assert(h.x == 20 and h.y == 40)
+
+ local diff = 0
+ for i=1,100 do diff = a:diff() end
+ assert(diff == -10)
+
+ for i=1,100 do c.foo = i end
+ assert(c.y == 100)
+
+ local z = tp(1, 3)
+ for i=1,100 do z = z + a end
+ assert(z.x == 1001 and z.y == 2003)
+
+ local x = 0
+ for i=1,100 do x = x + #a end
+ assert(x == 200)
+
+ local x = 0
+ for i=1,100 do x = x + p() end
+ assert(x == 3000)
+end
+
+do
+ local count = 0
+ local tp = ffi.metatype("gc_t", {
+ __gc = function(x) count = count + 1 end,
+ })
+
+ local a = tp()
+ a = nil
+ collectgarbage()
+ assert(count == 1)
+ local b,c = tp(), tp()
+ b = nil
+ collectgarbage()
+ assert(count == 2)
+ c = nil
+ collectgarbage()
+ assert(count == 3)
+
+ local z
+ for i=1,100 do z = tp() end
+ z = nil
+ collectgarbage()
+ assert(count == 103)
+
+ local t = {}
+ for i=1,100 do t[i] = tp() end
+ for i=1,100 do ffi.gc(t[i], nil) end
+ t = nil
+ collectgarbage()
+ assert(count == 103)
+end
+
+do
+ local tp = ffi.metatype([[
+struct {
+ static const int Z42 = 42;
+ enum { Z39 = 39 };
+ int x;
+}]], {
+ __new = function(tp, x)
+ return ffi.new(tp, x or -1)
+ end,
+ __index = { test = function(x) return x+1 end, x = "hello" }
+ })
+ assert(tp.Z42 == 42)
+ assert(tp.Z39 == 39)
+ assert(tp.test(99) == 100)
+ fails(function() tp.Z42 = 1 end)
+ fails(function() tp.Z39 = 1 end)
+ assert(tp.x == "hello") -- Not sure this is a good idea to allow that.
+ fails(function() tp.x = 1 end)
+ local o = tp()
+ assert(o.Z42 == 42)
+ assert(o.Z39 == 39)
+ assert(o.test(55) == 56)
+ fails(function() o.Z42 = 1 end)
+ fails(function() o.Z39 = 1 end)
+ assert(o.x == -1)
+ o.x = 5
+ assert(o.x == 5)
+end
+
+do
+ local fb = ffi.new("struct { int x; }", 99)
+ local xt = ffi.metatype("struct { }", { __index = fb })
+ local o = xt()
+ assert(o.x == 99)
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_new.lua b/test/LuaJIT-tests/lib/ffi/ffi_new.lua
new file mode 100644
index 0000000..9cdbd53
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_new.lua
@@ -0,0 +1,106 @@
+local ffi = require("ffi")
+local bit = require("bit")
+
+dofile("../common/ffi_util.inc")
+
+ffi.cdef([[
+typedef struct { int a,b,c; } foo1_t;
+typedef int foo2_t[?];
+void *malloc(size_t size);
+void free(void *ptr);
+]])
+
+do
+ assert(ffi.sizeof("foo1_t") == 12)
+ local cd = ffi.new("foo1_t")
+ assert(ffi.sizeof(cd) == 12)
+ local foo1_t = ffi.typeof("foo1_t")
+ assert(ffi.sizeof(foo1_t) == 12)
+ cd = foo1_t()
+ assert(ffi.sizeof(cd) == 12)
+end
+
+do
+ assert(ffi.sizeof("foo2_t", 3) == 12)
+ local cd = ffi.new("foo2_t", 3)
+ assert(ffi.sizeof(cd) == 12)
+ local foo2_t = ffi.typeof("foo2_t")
+ fails(ffi.sizeof, foo2_t)
+ assert(ffi.sizeof(foo2_t, 3) == 12)
+ cd = foo2_t(3)
+ assert(ffi.sizeof(cd) == 12)
+end
+
+do
+ local tpi = ffi.typeof("int")
+ local tpb = ffi.typeof("uint8_t")
+ local t = {}
+ for i=1,200 do t[i] = tpi end
+ t[100] = tpb
+ local x = 0
+ for i=1,200 do x = x + tonumber(ffi.new(t[i], 257)) end
+ assert(x == 199*257 + 1)
+end
+
+do
+ local oc = collectgarbage("count")
+ for al=0,15 do
+ local align = 2^al -- 1, 2, 4, ..., 32768
+ local ct = ffi.typeof("struct { char __attribute__((aligned("..align.."))) a; }")
+ for i=1,100 do
+ local cd = ct()
+ local addr = tonumber(ffi.cast("intptr_t", ffi.cast("void *", cd)))
+ assert(bit.band(addr, align-1) == 0)
+ end
+ end
+ local nc = collectgarbage("count")
+ assert(nc < oc + 3000, "GC step missing for ffi.new")
+end
+
+do
+ local t = {}
+ for i=1,100 do t[i] = ffi.new("int[?]", i) end
+ assert(ffi.sizeof(t[100]) == 400)
+ for i=0,99 do assert(t[100][i] == 0) end
+end
+
+do
+ local t = {}
+ local ct = ffi.typeof("struct { double x; int y[?];}")
+ for i=1,100 do t[i] = ct(i) end
+ assert(ffi.sizeof(t[100]) == 408)
+ for i=0,99 do assert(t[100].y[i] == 0) end
+end
+
+do
+ local ct = ffi.typeof("struct __attribute__((aligned(16))) { int x; }")
+ local y
+ for i=1,200 do
+ local x = ct()
+ if i == 150 then y = x end
+ end
+ assert(bit.band(ffi.cast("intptr_t", ffi.cast("void *", y)), 15) == 0)
+end
+
+do
+ local q
+ local p = ffi.gc(ffi.new("int[1]"), function(x) q = x end)
+ p = nil
+ collectgarbage()
+ assert(type(q) == "cdata")
+ q = nil
+ collectgarbage()
+ assert(q == nil)
+end
+
+do
+ local p = ffi.gc(ffi.C.malloc(2^20), ffi.C.free)
+ p = nil
+ collectgarbage()
+end
+
+do
+ local p = ffi.gc(ffi.new("int[1]"), function(x) assert(type(x) == "cdata") end)
+ -- test for lua_close() cleanup.
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_parse_array.lua b/test/LuaJIT-tests/lib/ffi/ffi_parse_array.lua
new file mode 100644
index 0000000..3a9616d
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_parse_array.lua
@@ -0,0 +1,78 @@
+local ffi = require("ffi")
+
+dofile("../common/ffi_util.inc")
+
+checkfail{
+ "int [",
+ "int [-1]",
+ "int [[1]]",
+ "int [10][]",
+ "int [10][?]",
+ "int [][]",
+ "int [][?]",
+ "int [?][]",
+ "int [?][?]",
+ "int [0x10000][0x2000]",
+ "int [256][256][256][256]",
+ "int [10](void)",
+ "int (void)[10]",
+ "int &[10]",
+ "union { double x; int a[?]; }",
+}
+
+ffi.cdef([[
+ typedef int foo1_t[10];
+ typedef foo1_t foo2_t[5];
+]])
+assert(ffi.sizeof("foo1_t") == 40)
+assert(ffi.sizeof("foo2_t") == 200)
+
+local P = ffi.sizeof("void *")
+
+checktypes{
+ 10, 1, "char [10]",
+ 4*10, 4, "int [10]",
+ 4*10, 4, "int [10]",
+ 4*10*5, 4, "int [10][5]",
+ 4*10*5*3*2*7, 4, "int [10][5][3][2][7]",
+ 4*10*5, 4, "int ([10])[5]",
+ P*10, P, "int *[10]",
+ P, P, "int (*)[10]",
+ P*5, P, "int (*[5])[10]",
+ 8*10, 4, "struct { int x; char y; } [10]",
+ P*5*10, P, "volatile int *(* const *[5][10])(void)",
+ nil, 4, "int []",
+ 4*10, 8, "int __attribute__((aligned(8))) [10]",
+ 4*10, 8, "__attribute__((aligned(8))) int [10]",
+ 4*10, 8, "int [10] __attribute__((aligned(8)))",
+ 97, 1, "char ['a']",
+ 83, 1, "char ['\\123']",
+ 79, 1, "char ['\x4F']",
+ 5, 1, "char [sizeof(\"aa\" \"bb\")]",
+ 80, 8, "double [10]",
+}
+
+do
+ assert(ffi.sizeof("int [?]", 10) == 4*10)
+ local id = ffi.typeof("const short [?]")
+ assert(ffi.sizeof(id, 10) == 2*10)
+ assert(ffi.sizeof(id, 0) == 0*10)
+ fails(ffi.sizeof, id)
+ assert(ffi.sizeof(id, -1) == nil)
+ assert(ffi.sizeof(id, 0x80000000) == nil)
+ assert(ffi.sizeof(id, 0x40000000) == nil)
+ assert(ffi.sizeof(id, 0x3fffffff) == 2*0x3fffffff)
+end
+
+do
+ assert(ffi.sizeof("struct { double x; int a[?]; }", 10) == 8+4*10)
+ local id = ffi.typeof("struct { int x; short a[?]; }")
+ assert(ffi.sizeof(id, 10) == 4+2*10)
+ assert(ffi.sizeof(id, 0) == 4+0*10)
+ fails(ffi.sizeof, id)
+ assert(ffi.sizeof(id, -1) == nil)
+ assert(ffi.sizeof(id, 0x80000000) == nil)
+ assert(ffi.sizeof(id, 0x40000000) == nil)
+ assert(ffi.sizeof(id, 0x3ffffffd) == 4+2*0x3ffffffd)
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_parse_basic.lua b/test/LuaJIT-tests/lib/ffi/ffi_parse_basic.lua
new file mode 100644
index 0000000..c054bcf
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_parse_basic.lua
@@ -0,0 +1,131 @@
+local ffi = require("ffi")
+
+dofile("../common/ffi_util.inc")
+
+checkfail{
+ "",
+ " ",
+ "\n",
+ "1",
+ ".",
+ ";",
+ ",",
+ "*",
+ "[]",
+ "()",
+ "(*)",
+ "//",
+ "/*",
+ "xyz",
+ "const",
+ "volatile",
+ "typedef",
+ "extern",
+ "static",
+ "auto",
+ "register",
+ "struct",
+ "union",
+ "sizeof",
+ "int int",
+ "int char",
+ "int double",
+ "int;",
+}
+
+checktypes{
+ 1, 1, "char",
+ 1, 1, " \n\r\t\vchar \n\r\t\v",
+ 1, 1, "ch\\\nar",
+ 1, 1, "char /* abc */",
+ 1, 1, "char /* abc */ const",
+ 1, 1, "char // abc\n const",
+}
+
+checktypes{
+ nil, 1, "void",
+ 1, 1, "bool",
+ 1, 1, "_Bool",
+ 4, 4, "_Bool int",
+ 1, 1, "char",
+ 1, 1, "signed char",
+ 1, 1, "unsigned char",
+ 2, 2, "short",
+ 2, 2, "signed short",
+ 2, 2, "unsigned short",
+ 4, 4, "int",
+ 4, 4, "signed int",
+ 4, 4, "unsigned int",
+ 4, 4, "signed",
+ 4, 4, "unsigned",
+ 4, 4, "float",
+ 8, 8, "long long",
+ 8, 8, "signed long long",
+ 8, 8, "unsigned long long",
+ 8, 8, "double",
+ -- NYI: long double is architecture- and compiler-specific.
+ 8, 4, "_Complex float",
+ 16, 8, "_Complex",
+ 16, 8, "_Complex double",
+}
+
+-- mode/vector_size attributes
+checktypes{
+ 1, 1, "int __attribute__((mode(QI)))",
+ 2, 2, "int __attribute__((mode(HI)))",
+ 4, 4, "int __attribute__((mode(SI)))",
+ 8, 8, "int __attribute__((mode(DI)))",
+ 16, 16, "int __attribute__((mode(TI)))",
+ 32, 16, "int __attribute__((mode(OI)))",
+ 4, 4, "float __attribute__((mode(SF)))",
+ 8, 8, "float __attribute__((mode(DF)))",
+ 2, 2, "int __attribute__((mode(V2QI)))",
+ 16, 16, "float __attribute__((mode(V4SF)))",
+ 32, 16, "double __attribute__((mode(V8SF)))",
+ 8, 8, "char __attribute__((vector_size(8)))",
+ 16, 16, "int __attribute__((vector_size(16)))",
+ 32, 16, "double __attribute__((vector_size(32)))",
+ 64, 16, "double __attribute__((vector_size(64)))",
+}
+
+-- ABI-specific types:
+local L = (ffi.abi("32bit") or ffi.abi("win")) and 4 or 8
+local P = ffi.abi("32bit") and 4 or 8
+local W = ffi.abi("win") and 2 or 4
+
+checktypes{
+ L, L, "long",
+ L, L, "signed long",
+ L, L, "unsigned long",
+ P, P, "int *",
+ P, P, "int **",
+ 4, 4, "int * __ptr32",
+}
+
+checktypes{
+ P, P, "ptrdiff_t",
+ P, P, "size_t",
+ W, W, "wchar_t",
+ 1, 1, "int8_t",
+ 2, 2, "int16_t",
+ 4, 4, "int32_t",
+ 8, 8, "int64_t",
+ 1, 1, "uint8_t",
+ 2, 2, "uint16_t",
+ 4, 4, "uint32_t",
+ 8, 8, "uint64_t",
+ P, P, "intptr_t",
+ P, P, "uintptr_t",
+}
+
+checktypes{
+ 1, 8, "char __attribute__((aligned(8)))",
+ 1, 8, "char __attribute((aligned(8)))",
+ 1, 8, "char __attribute__((__aligned__(8)))",
+ 1, 8, "__attribute__((aligned(8))) char",
+ 1, 8, "char __declspec(align(8))",
+ 1, 8, "__declspec(align(8)) char",
+ 1, 2, "char __attribute__((aligned(8))) const __attribute__((aligned(2)))",
+ 1, 16, "char __attribute__((aligned(8))) const __attribute__((aligned(16)))",
+}
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_parse_cdef.lua b/test/LuaJIT-tests/lib/ffi/ffi_parse_cdef.lua
new file mode 100644
index 0000000..4bb5d90
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_parse_cdef.lua
@@ -0,0 +1,77 @@
+local ffi = require("ffi")
+
+dofile("../common/ffi_util.inc")
+
+checkfail({
+ "int",
+ "int aa1; int aa2 ",
+ "static int x;",
+ "static const long long x = 1;", -- NYI
+ "static const double x = 1;", -- NYI
+ "static const bool x = 1;", -- NYI (intentional, need true/false)
+ "struct { static int x = 1; };",
+ ";;static int y"
+}, ffi.cdef)
+
+ffi.cdef[[
+static const int K_42a = 42;
+static const char K_42b = 42+256;
+static const short K_M1a = 65535;
+static const unsigned short K_65535a = 65535;
+static const int K_1b = 0xffffffff >> 31;
+static const int K_1c = 0xffffffffu >> 31;
+static const int K_M1b = (int)0xffffffff >> 31;
+]]
+
+checktypes{
+ 42, 1, "char[K_42a]",
+ 42, 1, "char[K_42b]",
+ 1, 1, "char[-K_M1a]",
+ 65535, 1, "char[K_65535a]",
+ 1, 1, "char[K_1b]",
+ 1, 1, "char[K_1c]",
+ 1, 1, "char[-K_M1b]",
+}
+
+ffi.cdef[[
+struct str1 {
+ enum {
+ K_99 = 99
+ };
+ static const int K_55 = 55;
+} extk;
+]]
+
+checktypes{
+ 99, 1, "char[K_99]",
+ 99, 1, "char[extk.K_99]",
+ 99, 1, "char[((struct str1)0).K_99]",
+ 99, 1, "char[((struct str1 *)0)->K_99]",
+ 55, 1, "char[extk.K_55]",
+}
+
+checkfail{
+ "char[K_55]",
+}
+
+ffi.cdef[[
+extern int func1(void);
+extern int func2();
+static int func3();
+static inline int func4(int n)
+{
+ int i, k = 0;
+ float x = 1.0f;
+ for (i = 0; i < n; i++) {
+ k += i;
+ }
+ return k;
+}
+;;;
+]]
+
+ffi.cdef[[
+int ext1;
+extern int ext2;
+]]
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_parse_struct.lua b/test/LuaJIT-tests/lib/ffi/ffi_parse_struct.lua
new file mode 100644
index 0000000..16a3d05
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_parse_struct.lua
@@ -0,0 +1,259 @@
+local ffi = require("ffi")
+
+dofile("../common/ffi_util.inc")
+
+checkfail{
+ "struct",
+ "struct {",
+ "struct xx xx {}",
+ "struct { int x }",
+ "struct { int x, }",
+ "struct { int x,y }",
+ "struct { void x; }",
+ "struct { int x(void); }",
+ "struct recursive1 { struct recursive1 { } x; }",
+ "union",
+ "union {",
+ "union xx xx {}",
+ "union { int x }",
+ "union { int x, }",
+ "union { int x,y }",
+ "union { void x; }",
+ "union { int x(void); }",
+ "union recursive1 { union recursive1 { } x; }",
+}
+
+-- NYI: rollback doesn't recover struct state
+-- ffi.cdef("struct zzz")
+-- fails(ffi.cdef, "struct zzz { int")
+-- ffi.cdef("struct zzz { int x; }")
+
+ffi.cdef("struct foo; typedef struct foo foo_t;")
+assert(ffi.sizeof("struct foo") == nil)
+assert(ffi.sizeof("foo_t") == nil)
+ffi.cdef("struct foo { int x,y; };")
+assert(ffi.sizeof("struct foo") == 8)
+assert(ffi.sizeof("foo_t") == 8)
+assert(ffi.sizeof(ffi.typeof("struct foo")) == 8)
+assert(ffi.sizeof(ffi.typeof("foo_t")) == 8)
+ffi.cdef("struct foo;")
+fails(ffi.cdef, "struct foo {};")
+fails(ffi.cdef, "union foo;")
+fails(ffi.cdef, "union foo {};")
+fails(ffi.cdef, "enum foo;")
+fails(ffi.cdef, "enum foo { ZZZ1 };")
+
+local P = ffi.sizeof("void *")
+local A = (ffi.arch == "x86" and not ffi.abi("win")) and 4 or 8
+
+checktypes{
+ 0, 1, "struct {}",
+ 1, 1, "struct { char x; }",
+ 2, 1, "struct { char x,y; }",
+ 4, 1, "struct { char x,y; char a,b; }",
+ 4, 2, "struct { char x; short y; }",
+ 4, 2, "struct { short x; char y; }",
+ 8, 4, "struct { char x; int y; }",
+ 8, 4, "struct { int x; char y; }",
+ 12, 4, "struct { char x; int y; char z; }",
+ P*4, P, "struct { char x,*y,**z,a,b,c,d; }",
+ 64, 4, "struct { struct { struct { struct { int x,y; } a,b; } a,b; } a,b; }",
+ 4, 4, "struct { struct { struct { struct { int x; }; }; }; }",
+ 8, 4, "struct { struct foo; }",
+ 8, 4, "struct { foo_t; }",
+ 8, 8, "struct __attribute__((aligned(sizeof(foo_t)))) { int a; }",
+ 6, 2, "struct { char a; char x; short y; char z; char c; }",
+ 10, 2, "struct { char a; struct { char x; short y; char z; } b; char c; }",
+ 8, A, "struct { double a; }",
+ A+8, A, "struct { int a; double b; }",
+ 8, A, "struct { long long a; }",
+ A+8, A, "struct { int a; long long b; }",
+ 16, A, "struct { _Complex a; }",
+ A+16, A, "struct { int a; _Complex b; }",
+ 8, 8, "struct { float __attribute__((mode(__V2SF__))) a; }",
+ 16, 8, "struct { int a; float __attribute__((mode(__V2SF__))) b; }",
+ 16, 8, "struct { float __attribute__((mode(__V2SF__))) a[2]; }",
+ 24, 8, "struct { int a; float __attribute__((mode(__V2SF__))) b[2]; }",
+ 16, 16, "struct { float __attribute__((vector_size(16))) a; }",
+ 32, 16, "struct { int a; float __attribute__((vector_size(16))) b; }",
+}
+
+checktypes{
+ 0, 1, "union {}",
+ 1, 1, "union { char x; }",
+ 1, 1, "union { char x,y; }",
+ 2, 2, "union { char x; short y; }",
+ 2, 2, "union { short x; char y; }",
+ 4, 4, "union { char x; int y; }",
+ 4, 4, "union { int x; char y; }",
+ 4, 4, "union { char x; int y; short z; }",
+ P, P, "union { char x,*y,**z,a,b,c,d; }",
+ 4, 4, "union { union { union { union { int x,y; } a,b; } a,b; } a,b; }",
+ 4, 4, "union { union { union { union { int x; }; }; }; }",
+ 2, 2, "union { union { short x; }; char y; }",
+ 2, 2, "union { struct { short x; }; char y; }",
+ 4, 2, "struct { union { short x; }; char y; }",
+ 2, 1, "union { struct { char a,b; }; char y; }",
+ 2, 1, "struct { union { char a,b; }; char y; }",
+ 8, A, "union { double a; }",
+ 8, A, "union { int a; double b; }",
+ 8, A, "union { long long a; }",
+ 8, A, "union { int a; long long b; }",
+ 16, A, "union { _Complex a; }",
+ 16, A, "union { int a; _Complex b; }",
+ 8, 8, "union { float __attribute__((mode(__V2SF__))) a; }",
+ 8, 8, "union { int a; float __attribute__((mode(__V2SF__))) b; }",
+ 16, 16, "union { float __attribute__((vector_size(16))) a; }",
+ 16, 16, "union { int a; float __attribute__((vector_size(16))) b; }",
+}
+
+do
+ local ct
+ ct = ffi.typeof("struct { int a; char b; short c; int d; }")
+ assert(ffi.offsetof(ct, "a") == 0)
+ assert(ffi.offsetof(ct, "b") == 4)
+ assert(ffi.offsetof(ct, "c") == 6)
+ assert(ffi.offsetof(ct, "d") == 8)
+ ct = ffi.typeof("struct { char a; struct { char x; short y; char z; }; char c; }")
+ assert(ffi.offsetof(ct, "a") == 0)
+ assert(ffi.offsetof(ct, "x") == 2)
+ assert(ffi.offsetof(ct, "y") == 4)
+ assert(ffi.offsetof(ct, "z") == 6)
+ assert(ffi.offsetof(ct, "c") == 8)
+ ct = ffi.typeof("struct { char a; struct { short b; struct { int c; }; }; }")
+ assert(ffi.offsetof(ct, "a") == 0)
+ assert(ffi.offsetof(ct, "b") == 4)
+ assert(ffi.offsetof(ct, "c") == 8)
+ ct = ffi.typeof("struct { int a; double b; }")
+ assert(ffi.offsetof(ct, "a") == 0)
+ assert(ffi.offsetof(ct, "b") == A)
+end
+
+checkfail{
+ "struct { int :; }",
+ "struct { int a:; }",
+ "struct { int a:bad; }",
+ "struct { int a:0; }",
+ "struct { int a:33; }",
+ "struct { int a:-1; }",
+ "struct { _Bool a:2; }",
+ "struct { double a:2; }",
+ "struct { complex a:2; }",
+ "struct { int __attribute__((mode(__TI__))) a:2; }",
+ "struct { int __attribute__((vector_size(16))) a:2; }",
+ "struct { int a[2]:2; }",
+ "struct { void a:2; }",
+}
+
+checktypes{
+ 4, 4, "struct { unsigned a:1; }",
+ 4, 4, "struct { unsigned a:1, b:1, c:1; }",
+ 1, 1, "struct { _Bool a:1, b:1, c:1; }",
+ 8, 4, "struct { unsigned a:16, b:16, c:16; }",
+ 8, 4, "struct { unsigned a:17, b:16, c:16; }",
+ 12, 4, "struct { unsigned a:17, b:16, c:17; }",
+ 12, 4, "struct { unsigned a:16, b:17, c:16; }",
+ 8, 4, "struct { unsigned a:16, :16, c:16; }",
+ 8, 4, "struct { unsigned a:17, :16, c:16; }",
+ 12, 4, "struct { unsigned a:17, :16, c:17; }",
+ 12, 4, "struct { unsigned a:16, :17, c:16; }",
+ 8, 4, "struct { unsigned a:16, :0, c:16; }",
+ 4, 4, "struct { unsigned a:16, b:16, :0, :0; }",
+ 8, 4, "struct { unsigned a:16, :0, :0, :0, c:16; }",
+ 1, 1, "struct { char a:1; _Bool b:1; }",
+ 1, 1, "struct { char a:1; signed char b:1; unsigned char c:1; }",
+}
+
+-- NYI: bit fields > 32 bit
+-- local L = ffi.alignof("struct { long long a; }")
+-- checktypes{
+-- L, L, "struct { long long a:1; }",
+-- }
+
+-- Bit field packing.
+checktypes{
+ 1, 1, "struct { _Bool a:1, b:1, c:1; }",
+ 4, 4, "struct { short a:9; int b:9; char c; }",
+ 4, 4, "struct { char a; int b:7; }",
+ 4, 4, "struct { short a; char b; int c:7; }",
+ 4, 4, "struct { char a:7; int b:7; int c:7; int d:10; }",
+ 4, 1, "struct { char a:7; char b:7; char c:7; char d:7; }",
+ 4, 4, "struct { char a:7; int b:7, c:7, d:7; int e:4; }",
+ 4, 4, "struct { char a:7; int b:7, c:7, d:7; char e:4; }",
+ 5, 1, "struct { char a:7; char b:7, c:7, d:7; char e:4; }",
+ 4, 1, "struct __attribute__((packed)) { char a:7; char b:7, c:7, d:7; char e:4; }",
+ 4, 4, "struct { char a:7; int b:7; int c:7; int d:10; }",
+ 8, 4, "struct { char a:7; int b:7; char c:7; int d:10; }",
+ 4, 1, "struct __attribute__((packed)) { char a:7; int b:7; char c:7; int d:10; }",
+ 4, 1, "struct { char a:7; int b:7; char c:7; int d:10; } __attribute__((packed))",
+ 2, 1, "struct __attribute__((packed)) { char a:4; char b:8; }",
+ 2, 1, "struct __attribute__((packed)) { char a:4; char :0; char b:4; }",
+ 1, 1, "struct __attribute__((packed)) { _Bool a:1; _Bool b:1; }",
+ 2, 1, "struct __attribute__((packed)) { _Bool a:1; _Bool b:1 __attribute((aligned(1))); }",
+ 4, 2, "struct __attribute__((packed)) { _Bool a:1; _Bool b:1 __attribute((aligned(2))); }",
+ 8, 4, "struct { _Bool a:1; int b __attribute((aligned(2))); }",
+ 16, 8, "struct { _Bool a:1; int b __attribute((aligned(8))); }",
+ 6, 2, "struct { _Bool a:1; int b __attribute((aligned(2))) __attribute((packed)); }",
+ 6, 2, "struct __attribute__((packed)) { _Bool a:1; int b __attribute((aligned(2))); }",
+ 6, 2, "struct __attribute__((packed)) { _Bool a:1; int b __attribute((aligned(2))) __attribute((packed)); }",
+}
+
+do
+ ffi.cdef[[
+ struct foo_packorig { char a; int b; short c; };
+ #pragma pack(1)
+ struct foo_pack1 { char a; int b; short c; };
+ #pragma pack(2)
+ struct foo_pack2 { char a; int b; short c; };
+ #pragma pack(4)
+ struct foo_pack4 { char a; int b; short c; };
+ #pragma pack(8)
+ struct foo_pack8 { char a; int b; short c; };
+ #pragma pack()
+ struct foo_packdef { char a; int b; short c; };
+ #pragma pack(push)
+ struct foo_packpush { char a; int b; short c; };
+ #pragma pack(1)
+ struct foo_packpush1 { char a; int b; short c; };
+ #pragma pack(pop)
+ struct foo_packpop { char a; int b; short c; };
+ #pragma pack(push,2)
+ struct foo_packpush2 { char a; int b; short c; };
+ #pragma pack(pop)
+ struct foo_packpop2 { char a; int b; short c; };
+ ]]
+
+ assert(ffi.sizeof("struct foo_packorig") == 12)
+ assert(ffi.sizeof("struct foo_pack1") == 7)
+ assert(ffi.sizeof("struct foo_pack2") == 8)
+ assert(ffi.sizeof("struct foo_pack4") == 12)
+ assert(ffi.sizeof("struct foo_pack8") == 12)
+ assert(ffi.sizeof("struct foo_packdef") == 12)
+ assert(ffi.sizeof("struct foo_packpush") == 12)
+ assert(ffi.sizeof("struct foo_packpush1") == 7)
+ assert(ffi.sizeof("struct foo_packpop") == 12)
+ assert(ffi.sizeof("struct foo_packpush2") == 8)
+ assert(ffi.sizeof("struct foo_packpop2") == 12)
+end
+
+do
+ ffi.cdef[[
+ #pragma pack(2)
+ struct foo_packalign8 {
+ char a; int y __attribute((aligned(8)));
+ };
+ typedef int __attribute((aligned(8))) int_align8;
+ struct foo_packintalign8 {
+ char a; int_align8 y;
+ };
+ typedef int __attribute((aligned(1))) int_align1;
+ struct foo_packintalign1 {
+ char a; int_align1 y;
+ };
+ ]]
+
+ assert(ffi.sizeof("struct foo_packalign8") == 6)
+ assert(ffi.sizeof("struct foo_packintalign8") == 6)
+ assert(ffi.sizeof("struct foo_packintalign1") == 5)
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/ffi_tabov.lua b/test/LuaJIT-tests/lib/ffi/ffi_tabov.lua
new file mode 100644
index 0000000..ba62196
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/ffi_tabov.lua
@@ -0,0 +1,12 @@
+local ffi = require("ffi")
+
+local last = 0
+
+assert(pcall(function()
+ for i=1,65536 do
+ last = i
+ ffi.typeof"struct {}"
+ end
+end) == false)
+
+assert(last > 20000)
diff --git a/test/LuaJIT-tests/lib/ffi/index b/test/LuaJIT-tests/lib/ffi/index
new file mode 100644
index 0000000..59e36dd
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/index
@@ -0,0 +1,12 @@
+bit64.lua +luajit>=2.1
+cdata_var.lua
+copy_fill.lua
+err.lua
+istype.lua
+jit_array.lua
+jit_complex.lua
+jit_misc.lua
+jit_struct.lua
+meta_tostring.lua
+redir.lua
+type_punning.lua
diff --git a/test/LuaJIT-tests/lib/ffi/istype.lua b/test/LuaJIT-tests/lib/ffi/istype.lua
new file mode 100644
index 0000000..5aba775
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/istype.lua
@@ -0,0 +1,88 @@
+local ffi = require("ffi")
+
+do --- 1
+ local void_t = ffi.typeof("void")
+ assert(ffi.istype(void_t, void_t))
+ assert(ffi.istype("const void", void_t))
+
+ assert(ffi.istype("void", "void") == false) -- 2nd arg is a string.
+ assert(ffi.istype("double", 1.5) == false) -- 2nd arg is a number.
+end
+
+do --- 2
+ local i8_t = ffi.typeof("int8_t")
+ local u8_t = ffi.typeof("uint8_t")
+ local i32_t = ffi.typeof("int32_t")
+ assert(ffi.istype(i32_t, i32_t) == true)
+ assert(ffi.istype("const int32_t", i32_t) == true)
+
+ assert(ffi.istype("bool", u8_t) == false)
+ assert(ffi.istype(i8_t, u8_t) == false)
+ assert(ffi.istype(i32_t, u8_t) == false)
+ assert(ffi.istype(u8_t, i32_t) == false)
+ assert(ffi.istype("double", i32_t) == false)
+
+ assert(ffi.istype("int64_t", ffi.typeof("long long")))
+ assert(ffi.istype("long long", ffi.typeof("int64_t")))
+end
+
+do --- 3
+ local ptr_t = ffi.typeof("int *")
+ local p = ptr_t()
+ assert(ffi.istype(ptr_t, ptr_t) == true)
+ assert(ffi.istype(ptr_t, p) == true)
+ assert(ffi.istype(p, ptr_t) == true)
+ assert(ffi.istype("const int *", ptr_t) == true)
+ assert(ffi.istype("const int * const", ptr_t) == true)
+ assert(ffi.istype("unsigned int *", ptr_t) == true)
+
+ assert(ffi.istype("char *", ptr_t) == false)
+ assert(ffi.istype("void *", ptr_t) == false)
+end
+
+do --- 4
+ ffi.cdef[[
+typedef int istype_arr_t[10];
+typedef const istype_arr_t istype_carr_t;
+typedef struct { int x; } istype_struct_t;
+]]
+
+ local arr_t = ffi.typeof("istype_arr_t")
+ local carr_t = ffi.typeof("istype_carr_t")
+ assert(ffi.istype(arr_t, arr_t) == true)
+ assert(ffi.istype("int[10]", arr_t) == true)
+
+ assert(ffi.istype("int[11]", arr_t) == false)
+ assert(ffi.istype("int[]", arr_t) == false)
+ assert(ffi.istype("int *", arr_t) == false)
+
+ assert(ffi.istype("const int[10]", arr_t) == true)
+ assert(ffi.istype("volatile int[10]", arr_t) == true)
+ assert(ffi.istype(carr_t, arr_t) == true)
+
+ local struct_t = ffi.typeof("istype_struct_t")
+ local structp_t = ffi.typeof("istype_struct_t *")
+ assert(ffi.istype(struct_t, struct_t) == true)
+ assert(ffi.istype("const istype_struct_t", struct_t) == true)
+ assert(ffi.istype("struct { int x; }", struct_t) == false)
+ assert(ffi.istype(struct_t, structp_t) == true) -- struct ptr is ok for struct.
+ assert(ffi.istype(structp_t, struct_t) == false)
+end
+
+do --- 5
+ local int_t = ffi.typeof("int")
+ local t = {}
+ for i=1,200 do t[i] = int_t() end
+ t[100] = ffi.new("uint8_t")
+ local x = 0
+ for i=1,200 do if not ffi.istype("int", t[i]) then x = x + i end end
+ assert(x == 100)
+ x = 0
+ for i=1,200 do if not ffi.istype(int_t, t[i]) then x = x + i end end
+ assert(x == 100)
+ for i=1,200 do t[i] = int_t end
+ t[100] = ffi.typeof("uint8_t")
+ x = 0
+ for i=1,200 do if not ffi.istype(t[i], int_t) then x = x + i end end
+ assert(x == 100)
+end
diff --git a/test/LuaJIT-tests/lib/ffi/jit_array.lua b/test/LuaJIT-tests/lib/ffi/jit_array.lua
new file mode 100644
index 0000000..e8de4af
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/jit_array.lua
@@ -0,0 +1,104 @@
+local ffi = require("ffi")
+
+do --- smoke
+ local types = {
+ "int8_t", "uint8_t",
+ "int16_t", "uint16_t",
+ "int32_t", "uint32_t",
+ "int64_t", "uint64_t",
+ "float", "double",
+ }
+ for j,tp in ipairs(types) do
+ local t = ffi.new(tp.."[?]", 301)
+ for i=1,300 do t[i] = 1 end
+ for i=1,300 do assert(t[i] == 1) end
+ for i=1,300 do t[i] = t[i-1] end -- reassoc across PHIs, a[i-1] forwarding
+ for i=1,300 do assert(t[i] == 0) end
+ for i=1,300 do t[i] = i end
+ local x = 0
+ for i=1,300 do x = x + t[i] end
+ if tp == "int8_t" then assert(x == 862)
+ elseif tp == "uint8_t" then assert(x == 33630)
+ else assert(x == 45150) end
+ end
+end
+
+do --- int array pointer arithmetic
+ local a = ffi.new("int[?]", 101)
+ local p = a+1;
+ for i=1,100 do
+ p[0] = i
+ assert(p - a == i) -- pointer difference
+ p = p + 1 -- pointer increment by 4 bytes
+ end
+ for i=1,100 do assert(a[i] == i) end
+ for i=1,100 do assert((a+i)[0] == i) end -- pointer arithmetic
+ for i=1,100 do assert((i+a)[0] == i) end -- pointer arithmetic
+end
+
+do --- double array pointer arithmetic
+ local a = ffi.new("double[?]", 101)
+ local p = a+1;
+ for i=1,100 do
+ p[0] = i
+ p = p + 1 -- pointer increment by 8 bytes
+ end
+ for i=1,100 do assert(a[i] == i) end
+ for i=1,100 do assert((a+i)[0] == i) end -- pointer arithmetic
+end
+
+do --- double array pointer comparisons +bit
+ local a = ffi.new("double[?]", 201)
+ local p = a+3
+ for i=1,200 do local j = bit.band(i, 7); assert((a+j == p) == (j == 3)) end
+ p = a+100;
+ for i=1,200 do assert((a+i < p) == (i < 100)) end
+ for i=1,200 do assert((a+i <= p) == (i <= 100)) end
+end
+
+do --- constant offset in double array index
+ local a = ffi.new("double[?]", 100)
+ for i=1,100 do a[i-1LL] = i end
+ for i=1,100 do assert(a[100LL-i] == 101-i) end
+end
+
+do --- fixed index of minus one
+ local a = ffi.new("int[10]")
+ local p = a+1
+ local k = ffi.new("int", -1)
+ a[0] = 42
+ for i=1,100 do assert(p[-1] == 42); assert(p[k] == 42) end
+end
+
+do --- uint8_t array element comparisons
+ local a = ffi.new("uint8_t[?]", 256)
+ for i=0,255 do a[i] = i end
+ for i=1,255 do assert(a[i] >= 1) end
+ for i=0,254 do assert(a[i] <= 254) end
+end
+
+do --- int32_t array bit/bswap tricks +bit
+ local a = ffi.new("int32_t[?]", 256)
+ local tobit, bswap, shl = bit.tobit, bit.bswap, bit.lshift
+ for i=0,255 do a[i] = bswap(i+0x12345600) end
+ for i=0,255 do assert(a[i] == tobit(shl(i, 24)+0x00563412)) end
+ for i=0,255 do assert(bswap(a[i]) == tobit(i+0x12345600)) end
+end
+
+do --- int32_t shift/rotate/and +bit
+ local a = ffi.new("int32_t[?]", 256)
+ local shl, shr, rol, band = bit.lshift, bit.rshift, bit.rol, bit.band
+ for i=0,255 do a[i] = i + shl(i, 8) + shl(i, 16) end
+
+ for i=0,255 do assert(shl(band(a[i], 0xff), 8) == shl(i, 8)) end
+ for i=0,255 do assert(band(shl(a[i], 8), 0xff00) == shl(i, 8)) end
+
+ for i=0,255 do assert(shr(band(a[i], 0xff00), 8) == i) end
+ for i=0,255 do assert(band(shr(a[i], 8), 255) == i) end
+
+ for i=0,255 do assert(rol(band(a[i], 0xff), 8) == shl(i, 8)) end
+ for i=0,255 do assert(band(rol(a[i], 8), 0xff00) == shl(i, 8)) end
+
+ for i=0,255 do assert(shl(band(a[i], 0x000000ff), 24) == shl(i, 24)) end
+ for i=0,255 do assert(shr(band(a[i], 0xffff0000), 16) == i) end
+end
diff --git a/test/LuaJIT-tests/lib/ffi/jit_complex.lua b/test/LuaJIT-tests/lib/ffi/jit_complex.lua
new file mode 100644
index 0000000..3296f0c
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/jit_complex.lua
@@ -0,0 +1,109 @@
+local ffi = require("ffi")
+
+local cx = ffi.typeof("complex")
+local cxf = ffi.typeof("complex float")
+
+ffi.cdef[[
+typedef struct jit_complex_chain_t {
+ struct jit_complex_chain_t *next;
+ complex c;
+} jit_complex_chain_t;
+]]
+
+do --- field access
+ local c = cx(1, 2)
+ local x
+ for i=1,100 do
+ x = c.re + c.im
+ end
+ assert(x == 3)
+end
+
+do --- one element circular chain, named indexing
+ local cp = ffi.new("jit_complex_chain_t")
+ local p = cp
+ p.next = p
+ p.c = cx(1, 2)
+ local x,y = 0,0
+ for i=1,100 do
+ x = x + p.c.re
+ y = y + p.c.im
+ p = p.next
+ end
+ assert(x == 100)
+ assert(y == 200)
+end
+
+do --- one element circular chain, array indexing
+ local cp = ffi.new("jit_complex_chain_t")
+ local p = cp
+ p.next = p
+ p.c = cx(1, 2)
+ local x,y = 0,0
+ for i=1,100 do
+ x = x + p.c[0]
+ y = y + p.c[1]
+ p = p.next
+ end
+ assert(x == 100)
+ assert(y == 200)
+end
+
+do --- one-arg initialiser
+ local ca = ffi.new("complex[?]", 101)
+ for i=1,100 do
+ ca[i] = cx(i) -- handled as init single
+ end
+ local x,y = 0,0
+ for i=1,100 do
+ x = x + ca[i].re
+ y = y + ca[i].im
+ end
+ assert(x == 5050)
+ assert(y == 0)
+end
+
+do --- two-arg initialiser
+ local ca = ffi.new("complex[?]", 101)
+ for i=1,100 do
+ ca[i] = cx(i, -i)
+ end
+ local x,y = 0,0
+ for i=1,100 do
+ x = x + ca[i].re
+ y = y + ca[i].im
+ end
+ assert(x == 5050)
+ assert(y == -5050)
+end
+
+do --- float<>double conversions
+ local ca = ffi.new("complex[?]", 101)
+ local caf = ffi.new("complex float[?]", 101)
+ for i=1,100 do
+ ca[i] = cxf(i, -i)
+ caf[i] = cx(i, -i)
+ end
+ local x,y = 0,0
+ for i=1,100 do
+ x = x + caf[i].re + ca[i].re
+ y = y + caf[i].im + ca[i].im
+ end
+ assert(x == 2*5050)
+ assert(y == -2*5050)
+end
+
+do --- Complex struct field
+ local s = ffi.new("struct { complex x;}")
+ for i=1,100 do
+ s.x = 12.5i
+ end
+ assert(s.x.re == 0)
+ assert(s.x.im == 12.5)
+end
+
+do --- Index overflow for complex is ignored
+ local c = cx(1, 2)
+ local x
+ for i=1e7,1e7+100 do x = c[i] end
+end
diff --git a/test/LuaJIT-tests/lib/ffi/jit_misc.lua b/test/LuaJIT-tests/lib/ffi/jit_misc.lua
new file mode 100644
index 0000000..41e4737
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/jit_misc.lua
@@ -0,0 +1,109 @@
+local ffi = require("ffi")
+
+do --- errno
+ ffi.errno(42)
+ local x = 0
+ for i=1,100 do x = x + ffi.errno() end
+ assert(x == 4200)
+ ffi.errno(0)
+end
+
+do --- string
+ local a = ffi.new("uint8_t[?]", 101)
+ for i=0,99 do a[i] = i end
+ local s
+ for i=1,90 do s = ffi.string(a+i, 10) end
+ assert(s == "Z[\\]^_`abc")
+ for i=1,90 do s = ffi.string(a+i) end
+ assert(s == "Z[\\]^_`abc")
+end
+
+do --- fill
+ local a = ffi.new("uint8_t[?]", 100)
+ local x = 0
+ for i=0,90 do x = x + a[i]; ffi.fill(a+i, 10, i); x = x + a[i] end
+ assert(x == 8100)
+ for i=1,100 do ffi.fill(a, 15, 0x1234) end
+ assert(a[0] == 0x34 and a[14] == 0x34 and a[15] == 15)
+ local b = ffi.new("uint32_t[?]", 104)
+ for i=0,100 do ffi.fill(b+i, 15, 0x1234) end
+ assert(b[0] == 0x34343434)
+ assert(b[103] == (ffi.abi("le") and 0x343434 or 0x34343400))
+end
+
+do --- copy array elements
+ local a = ffi.new("uint8_t[?]", 100)
+ local b = ffi.new("uint8_t[?]", 100)
+ for i=0,99 do b[i] = i end
+ local x = 0
+ for i=0,90 do x = x + a[i]; ffi.copy(a+i, b+i, 1); x = x + a[i] end
+ assert(x == 4095)
+ local x = 0
+ for i=0,90 do ffi.copy(b+i, a+90-i, 10); x = x + b[i] end
+ assert(x == 4095)
+end
+
+do --- copy from string
+ local a = ffi.new("uint8_t[?]", 100, 42)
+ for i=0,90 do ffi.copy(a+i, "abc") end
+ local x = 0
+ for i=0,99 do x = x + a[i] end
+ assert(x == 9276)
+end
+
+do --- copy structures
+ local tp = ffi.typeof("struct { int x, y; }")
+ local a = tp(1, 2)
+ local b = tp(3, 4)
+ local x = 0
+ for i=1,100 do a.y = i; ffi.copy(b, a, 8); x = x + b.y end
+ assert(x == 5050)
+ local x = 0
+ for i=1,100 do a.y = i; local t = tp(a); x = x + t.y end
+ assert(x == 5050)
+end
+
+do --- init struct from first field, complex
+ local tp = ffi.typeof("struct { complex x, y; }")
+ local cx = ffi.typeof("complex")
+ local a = tp(cx(1, 2), cx(3, 4))
+ local x = 0
+ for i=1,100 do a.y = i; local t = tp(a); x = x + t.y.re end
+ assert(x == 5050)
+end
+
+do --- int array as parameterised type
+ local tp = ffi.typeof("int[10]")
+ local a = tp(42)
+ local b = ffi.new(ffi.typeof("struct { $ x; }", tp))
+ for i=1,100 do b.x = a end
+ assert(b.x[0] == 42 and b.x[9] == 42)
+end
+
+do --- double array as parameterised type
+ local tp = ffi.typeof("double[5]")
+ local a = tp(42)
+ local b = ffi.new(ffi.typeof("struct { $ x; }", tp))
+ for i=1,100 do b.x = a end
+ assert(b.x[0] == 42 and b.x[4] == 42)
+ b.x[0] = 0
+ for i=1,100 do ffi.copy(b.x, a, ffi.sizeof(a)) end
+ assert(b.x[0] == 42 and b.x[4] == 42)
+end
+
+do --- abi
+ local x, y
+ for i=1,100 do x = ffi.abi("32bit"); y = ffi.abi("64bit") end
+ assert(x == ffi.abi("32bit"))
+ assert(y == ffi.abi("64bit"))
+ for _,s in ipairs{"64bit", "32bit", "fpu", "softfp", "hardfp", "eabi", "win", "le", "be"} do
+ for i=1,100 do x = ffi.abi(s) end
+ assert(x == ffi.abi(s))
+ end
+end
+
+do --- typeof constructed typeof
+ local ct = ffi.typeof("struct { int x; }")
+ local cd = ct()
+ for i=1,100 do assert(ffi.typeof(cd) == ct) end
+end
diff --git a/test/LuaJIT-tests/lib/ffi/jit_struct.lua b/test/LuaJIT-tests/lib/ffi/jit_struct.lua
new file mode 100644
index 0000000..8aa64c1
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/jit_struct.lua
@@ -0,0 +1,201 @@
+local ffi = require("ffi")
+
+ffi.cdef[[
+typedef struct { int a, b, c; } jit_struct_foo_t;
+typedef struct { int a, b, c; } jit_struct_foo2_t;
+typedef struct { int a[10]; int b[10]; } jit_struct_sarr_t;
+typedef struct jit_struct_chain_t {
+ struct jit_struct_chain_t *next;
+ int v;
+} jit_struct_chain_t;
+]]
+
+do --- iteration variable as field name
+ local s = ffi.new("jit_struct_foo_t")
+ for j,k in ipairs{ "a", "b", "c" } do
+ for i=1,100 do s[k] = s[k] + j end
+ end
+ assert(s.a == 100)
+ assert(s.b == 200)
+ assert(s.c == 300)
+end
+
+do --- constant field names
+ local s = ffi.new("jit_struct_foo_t")
+ for i=1,100 do
+ s.a = s.a + 1
+ s.b = s.b + 2
+ s.c = s.c + 3
+ end
+ assert(s.a == 100)
+ assert(s.b == 200)
+ assert(s.c == 300)
+end
+
+do --- constants from structure
+ local s = ffi.new("jit_struct_foo_t")
+ local s2 = ffi.new("jit_struct_foo2_t", 1, 2, 3)
+ for i=1,100 do
+ s.a = s.a + s2.a
+ s.b = s.b + s2.b
+ s.c = s.c + s2.c
+ end
+ assert(s.a == 100)
+ assert(s.b == 200)
+ assert(s.c == 300)
+end
+
+do --- adding to array elements
+ local s = ffi.new("jit_struct_sarr_t")
+ for i=1,100 do
+ s.a[5] = s.a[5] + 1
+ s.b[5] = s.b[5] + 2
+ end
+ assert(s.a[5] == 100)
+ assert(s.b[5] == 200)
+end
+
+do --- double indexing
+ local s = ffi.new([[
+ struct {
+ struct {
+ int x;
+ int b[10];
+ } a[100];
+ }]])
+ s.a[10].b[4] = 10
+ s.a[95].b[4] = 95
+ local x = 0
+ for i=1,100 do
+ x = x + s.a[i-1].b[4] -- reassociate offsets for base and index
+ end
+ assert(x == 105)
+end
+
+do --- structurally identical
+ local s1 = ffi.new("struct { int a; }")
+ local s2 = ffi.new("struct { int a; }")
+ local x = 0
+ for j=1,2 do
+ for i=1,100 do
+ s2.a = i
+ s1.a = 1
+ x = x + s2.a -- cannot forward across aliasing store
+ end
+ if j == 1 then
+ assert(x == 5050)
+ s2 = s1
+ x = 0
+ else
+ assert(x == 100)
+ end
+ end
+end
+
+do --- structurally different
+ local s1 = ffi.new("struct { int a; }")
+ local s2 = ffi.new("struct { char a; }")
+ local x = 0
+ for j=1,2 do
+ for i=1,100 do
+ s2.a = i
+ s1.a = 1
+ x = x + s2.a -- can forward across aliasing store
+ end
+ if j == 1 then
+ assert(x == 5050)
+ s2 = s1 -- this will cause a side trace
+ x = 0
+ else
+ assert(x == 100)
+ end
+ end
+end
+
+do --- union
+ local s = ffi.new("union { uint8_t a; int8_t b; }")
+ local x = 0
+ for i=1,200 do
+ s.a = i
+ x = x + s.b -- same offset, but must not alias (except if sign-extended)
+ end
+ assert(x == 1412)
+end
+
+do --- circular chain
+ local s1 = ffi.new("jit_struct_chain_t")
+ local s2 = ffi.new("jit_struct_chain_t")
+ local s3 = ffi.new("jit_struct_chain_t")
+ s1.next = s2
+ s2.next = s3
+ s3.next = s1
+ local p = s1
+ for i=1,99 do
+ p.v = i
+ p = p.next
+ end
+ assert(s1.v == 97)
+ assert(s2.v == 98)
+ assert(s3.v == 99)
+end
+
+do --- int struct initialiser
+ local ct = ffi.typeof("struct { int a,b,c; }")
+ local x,y,z = 0,0,0
+ for i=1,100 do
+ local s = ct(i, i+1)
+ x = x + s.a
+ y = y + s.b
+ z = z + s.c
+ end
+ assert(x == 5050)
+ assert(y == 5150)
+ assert(z == 0)
+end
+
+do --- double struct initialiser
+ local ct = ffi.typeof("struct { double a,b,c; }")
+ local x,y,z = 0,0,0
+ for i=1,100 do
+ local s = ct(i, i+1)
+ x = x + s.a
+ y = y + s.b
+ z = z + s.c
+ end
+ assert(x == 5050)
+ assert(y == 5150)
+ assert(z == 0)
+end
+
+do --- pointer / int struct initialiser
+ local s1 = ffi.new("jit_struct_chain_t")
+ local s
+ for i=1,100 do
+ s = ffi.new("jit_struct_chain_t", s1, i)
+ end
+ assert(tonumber(ffi.cast("int", s.next)) ==
+ tonumber(ffi.cast("int", ffi.cast("jit_struct_chain_t *", s1))))
+ assert(s.v == 100)
+end
+
+do --- unstable pointer/int type struct initialiser
+ local ct = ffi.typeof("struct { int *p; int y; }")
+ local s
+ for i=1,200 do
+ if i == 100 then ct = ffi.typeof("jit_struct_chain_t") end
+ s = ct(nil, 10)
+ end
+ assert(s.v == 10)
+end
+
+do --- upvalued int box
+ local s = ffi.new("struct { int x; }", 42)
+ local function f()
+ for i=1,100 do
+ s.x = i
+ assert(s.x == i)
+ end
+ end
+ f()
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/meta_tostring.lua b/test/LuaJIT-tests/lib/ffi/meta_tostring.lua
new file mode 100644
index 0000000..bb065e1
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/meta_tostring.lua
@@ -0,0 +1,55 @@
+local ffi = require("ffi")
+
+ffi.cdef[[
+typedef union meta_tostring_foo_t {
+ int64_t i64;
+ uint64_t u64;
+ complex cd;
+ double d[2];
+ complex float cf;
+ float f[2];
+} meta_tostring_foo_t;
+]]
+
+do --- tostring/typeof semi-roundtrip
+ assert(tostring(ffi.typeof("int (*(*[1][2])[3][4])[5][6]")) ==
+ "ctype<int (*(*[1][2])[3][4])[5][6]>")
+ assert(tostring(ffi.typeof("int (*const)(void)")) ==
+ "ctype<int (*const)()>")
+ assert(tostring(ffi.typeof("complex float(*(void))[2]")) ==
+ "ctype<complex float (*())[2]>")
+ assert(tostring(ffi.typeof("complex*")) == "ctype<complex *>")
+end
+
+do --- assorted union fields
+ local foo_t = ffi.typeof("meta_tostring_foo_t")
+ local x = foo_t()
+
+ assert(tostring(foo_t) == "ctype<union meta_tostring_foo_t>")
+ assert(string.find(tostring(x), "^cdata<union meta_tostring_foo_t>: "))
+
+ x.i64 = -1;
+ assert(tostring(x.i64) == "-1LL")
+ assert(tostring(x.u64) == "18446744073709551615ULL")
+
+ x.d[0] = 12.5
+ x.d[1] = -753.125
+ assert(tostring(x.cd) == "12.5-753.125i")
+ x.d[0] = -12.5
+ x.d[1] = 753.125
+ assert(tostring(x.cd) == "-12.5+753.125i")
+ x.d[0] = 0/-1
+ x.d[1] = 0/-1
+ assert(tostring(x.cd) == "-0-0i")
+ x.d[0] = 1/0
+ x.d[1] = -1/0
+ assert(tostring(x.cd) == "inf-infI")
+ x.d[0] = -1/0
+ x.d[1] = 0/0
+ assert(tostring(x.cd) == "-inf+nanI")
+
+ x.f[0] = 12.5
+ x.f[1] = -753.125
+ assert(tostring(x.cf) == "12.5-753.125i")
+end
+
diff --git a/test/LuaJIT-tests/lib/ffi/redir.lua b/test/LuaJIT-tests/lib/ffi/redir.lua
new file mode 100644
index 0000000..c492055
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/redir.lua
@@ -0,0 +1,19 @@
+local ffi = require("ffi")
+
+do --- function
+ ffi.cdef[[
+ int redir_foo(const char *s) asm("strlen");
+ ]]
+
+ assert(ffi.C.redir_foo("abcd") == 4)
+end
+
+do --- variable -windows
+ ffi.cdef[[
+ int redir_bar asm("errno");
+ ]]
+
+ ffi.C.redir_bar = 14
+ assert(ffi.C.redir_bar == 14)
+ ffi.C.redir_bar = 0
+end
diff --git a/test/LuaJIT-tests/lib/ffi/type_punning.lua b/test/LuaJIT-tests/lib/ffi/type_punning.lua
new file mode 100644
index 0000000..ac70b4b
--- /dev/null
+++ b/test/LuaJIT-tests/lib/ffi/type_punning.lua
@@ -0,0 +1,138 @@
+local ffi = require("ffi")
+
+local u = ffi.new([[
+union {
+ int8_t i8[8];
+ uint8_t u8[8];
+ int16_t i16[4];
+ uint16_t u16[4];
+ int32_t i32[2];
+ uint32_t u32[2];
+ int64_t i64[1];
+ uint64_t u64[1];
+ void *v[2];
+ float f[2];
+ double d[1];
+}
+]])
+
+do --- float -> u32 type punning at same offset
+ local x = 0LL
+ for i=1,100 do
+ u.f[0] = i
+ x = x + u.u32[0]
+ end
+ assert(x == 110888222720LL)
+end
+
+do --- double -> u64 type punning at same offset
+ local x = 0LL
+ for i=1,100 do
+ u.d[0] = i
+ x = x + u.u64[0]
+ end
+ assert(x == 1886586031403171840ULL)
+end
+
+do --- i8 -> u8 type punning at same offset (fwd -> CONV.int.u8)
+ local x = 0
+ for i=-100,100 do
+ u.i8[0] = i
+ x = x + u.u8[0]
+ end
+ assert(x == 25600)
+end
+
+do --- p32/p64 -> u64 type punning at same offset (32 bit: different size)
+ local x = 0LL
+ u.u64[0] = 0
+ for i=-100,150 do
+ u.v[0] = ffi.cast("void *", ffi.cast("ptrdiff_t", i))
+ x = x + u.u64[0]
+ end
+ assert(x == (ffi.abi"64bit" and 6275ULL or
+ (ffi.abi"le" and 0x6400001883ULL or 0x188300000000ULL)))
+end
+
+do --- u16 -> u8 type punning at overlapping offsets [0]
+ local x = 0
+ for i=255,520 do
+ u.u16[0] = i
+ x = x + u.u8[0]
+ end
+ assert(x == (ffi.abi"be" and 274 or 32931))
+end
+
+do --- u16 -> u8 type punning at overlapping offsets [1]
+ local x = 0
+ for i=255,520 do
+ u.u16[0] = i
+ x = x + u.u8[1]
+ end
+ assert(x == (ffi.abi"le" and 274 or 32931))
+end
+
+do --- i16 -> i32 type punning at overlapping offsets [0]
+ local x = 0
+ u.i32[0] = 0
+ for i=-100,150 do
+ u.i16[0] = i
+ x = x + u.i32[0]
+ end
+ assert(x == (ffi.abi"be" and 411238400 or 6559875))
+end
+
+do --- i16 -> i32 type punning at overlapping offsets [1]
+ local x = 0
+ u.i32[0] = 0
+ for i=-100,150 do
+ u.i16[1] = i
+ x = x + u.i32[0]
+ end
+ assert(x == (ffi.abi"le" and 411238400 or 6559875))
+end
+
+do --- double -> i32 type punning at overlapping offsets [0]
+ local x = 0
+ for i=1.5,120,1.1 do
+ u.d[0] = i
+ x = x + u.i32[0]
+ end
+ assert(x == (ffi.abi"be" and 116468870297 or -858993573))
+end
+
+do --- double -> i32 type punning at overlapping offsets [1]
+ local x = 0
+ for i=1.5,120,1.1 do
+ u.d[0] = i
+ x = x + u.i32[1]
+ end
+ assert(x == (ffi.abi"le" and 116468870297 or -858993573))
+end
+
+do --- u32 -> u64 type punning, constify u, 32 bit SPLIT: fold KPTR
+ local u = ffi.new("union { struct { uint32_t lo, hi; }; uint64_t u64; }")
+
+ local function conv(lo, hi)
+ u.lo = lo
+ u.hi = hi
+ return u.u64
+ end
+
+ local x = 0ll
+ for i=1,100 do
+ x = x + conv(i, i)
+ end
+ assert(x == 21689584849850ULL)
+end
+
+do --- u64 -> u32 -> u64 type punning with KPTR
+ local s = ffi.new("union { int64_t q; int32_t i[2]; }")
+ local function f()
+ s.q = 0
+ s.i[1] = 1
+ return s.q
+ end
+ for i=1,50 do f() f() f() end
+ assert(f() ~= 0)
+end
diff --git a/test/LuaJIT-tests/lib/index b/test/LuaJIT-tests/lib/index
new file mode 100644
index 0000000..cc9d7d7
--- /dev/null
+++ b/test/LuaJIT-tests/lib/index
@@ -0,0 +1,8 @@
+base
+bit.lua +bit
+math
+string
+table
+coroutine
+ffi +ffi
+contents.lua
\ No newline at end of file
diff --git a/test/LuaJIT-tests/lib/math/abs.lua b/test/LuaJIT-tests/lib/math/abs.lua
new file mode 100644
index 0000000..4223a78
--- /dev/null
+++ b/test/LuaJIT-tests/lib/math/abs.lua
@@ -0,0 +1,16 @@
+local abs = math.abs
+local expect_error = require"common.expect_error"
+
+do --- smoke
+ assert(abs(-1.5) == 1.5)
+ assert(abs("-1.5") == 1.5)
+end
+
+do --- argcheck
+ expect_error(function() abs() end,
+ "bad argument #1 to 'abs' (number expected, got no value)")
+ expect_error(function() abs(false) end,
+ "bad argument #1 to 'abs' (number expected, got boolean)")
+ expect_error(function() abs("a") end,
+ "bad argument #1 to 'abs' (number expected, got string)")
+end
diff --git a/test/LuaJIT-tests/lib/math/constants.lua b/test/LuaJIT-tests/lib/math/constants.lua
new file mode 100644
index 0000000..ec35b4c
--- /dev/null
+++ b/test/LuaJIT-tests/lib/math/constants.lua
@@ -0,0 +1,8 @@
+do --- pi
+ assert(math.pi == 3.141592653589793)
+end
+
+do --- huge
+ assert(math.huge > 0)
+ assert(1/math.huge == 0)
+end
diff --git a/test/LuaJIT-tests/lib/math/index b/test/LuaJIT-tests/lib/math/index
new file mode 100644
index 0000000..944e1ae
--- /dev/null
+++ b/test/LuaJIT-tests/lib/math/index
@@ -0,0 +1,3 @@
+abs.lua
+constants.lua
+random.lua
diff --git a/test/LuaJIT-tests/lib/math/random.lua b/test/LuaJIT-tests/lib/math/random.lua
new file mode 100644
index 0000000..dc2ca00
--- /dev/null
+++ b/test/LuaJIT-tests/lib/math/random.lua
@@ -0,0 +1,47 @@
+local random = math.random
+local MAX_SEED = 10
+
+do --- generally uniform in range [0, 1)
+ local N = 100
+ local min, max = math.min, math.max
+ for j=1,MAX_SEED do
+ math.randomseed(j)
+ local lo, hi, sum = math.huge, -math.huge, 0
+ for i=1,N do
+ local x = random()
+ assert(0 <= x and x < 1)
+ sum = sum + x
+ lo = min(lo, x)
+ hi = max(hi, x)
+ end
+ assert(lo*N < 15 and (1-hi)*N < 15)
+ assert(sum > N*0.45 and sum < N*0.55)
+ end
+end
+
+do --- all in range [1, 10]
+ math.randomseed(1)
+ local counts = setmetatable({}, {__index = function() return 0 end})
+ for i = 1, 100 do
+ local n = random(10)
+ counts[n] = counts[n] + 1
+ end
+ for i = 1, 10 do
+ assert(counts[i])
+ counts[i] = nil
+ end
+ assert(not next(counts))
+end
+
+do --- all in range [-3, 11]
+ math.randomseed(1)
+ local seen = setmetatable({}, {__index = function() return false end})
+ for i = 1, 120 do
+ seen[random(-3, 11)] = true
+ end
+ for i = -3, 11 do
+ assert(seen[i])
+ seen[i] = nil
+ end
+ assert(not next(seen))
+end
diff --git a/test/LuaJIT-tests/lib/string/byte.lua b/test/LuaJIT-tests/lib/string/byte.lua
new file mode 100644
index 0000000..697a2c2
--- /dev/null
+++ b/test/LuaJIT-tests/lib/string/byte.lua
@@ -0,0 +1,92 @@
+local band, bor = bit and bit.band, bit and bit.bor
+local byte = string.byte
+
+do --- simple
+ local a, b = ("foo"):byte(1)
+ assert(type(a) == "number")
+ assert(b == nil)
+ local c, d = ("foo"):byte(2, 3)
+ assert(type(c) == "number")
+ assert(c == d)
+ assert(c ~= a)
+end
+
+do --- Fixed slice [i,i+k] or overflow +bit
+ local s = "abcdefg"
+ local x,y,z
+ for j=100,107 do
+ for i=1,j do x,y,z = byte("abcdefg", band(i, 7), band(i+2, 7)) end
+ local a,b,c = byte("abcdefg", band(j, 7), band(j+2, 7))
+ assert(x == a and y == b and z == c)
+ end
+ for j=100,107 do
+ for i=1,j do x,y,z = byte(s, band(i, 7), band(i+2, 7)) end
+ local a,b,c = byte(s, band(j, 7), band(j+2, 7))
+ assert(x == a and y == b and z == c)
+ end
+end
+
+do --- Positive slice [i,len] or overflow +bit
+ local s = "abc"
+ local x,y,z
+ for j=100,107 do
+ for i=1,j do x,y,z = byte("abc", band(i, 7), -1) end
+ local a,b,c = byte("abc", band(j, 7), -1)
+ assert(x == a and y == b and z == c)
+ end
+ for j=100,107 do
+ for i=1,j do x,y,z = byte(s, band(i, 7), -1) end
+ local a,b,c = byte(s, band(j, 7), -1)
+ assert(x == a and y == b and z == c)
+ end
+end
+
+do --- Negative slice [-i,len] or underflow +bit
+ local s = "abc"
+ local x,y,z
+ for j=-100,-107,-1 do
+ for i=-1,j,-1 do x,y,z = byte("abc", bor(i, -8), -1) end
+ local a,b,c = byte("abc", bor(j, -8), -1)
+ assert(x == a and y == b and z == c)
+ end
+ for j=-100,-107,-1 do
+ for i=-1,j,-1 do x,y,z = byte(s, bor(i, -8), -1) end
+ local a,b,c = byte(s, bor(j, -8), -1)
+ assert(x == a and y == b and z == c)
+ end
+end
+
+do --- Positive slice [1,i] or overflow +bit
+ local s = "abc"
+ local x,y,z
+ for j=100,107 do
+ for i=1,j do x,y,z = byte("abc", 1, band(i, 7)) end
+ local a,b,c = byte("abc", 1, band(j, 7))
+ assert(x == a and y == b and z == c)
+ end
+ for j=100,107 do
+ for i=1,j do x,y,z = byte(s, 1, band(i, 7)) end
+ local a,b,c = byte(s, 1, band(j, 7))
+ assert(x == a and y == b and z == c)
+ end
+end
+
+do --- Negative slice [1,-i] or underflow +bit
+ local s = "abc"
+ local x,y,z
+ for j=-100,-107,-1 do
+ for i=-1,j,-1 do x,y,z = byte("abc", 1, bor(i, -8)) end
+ local a,b,c = byte("abc", 1, bor(j, -8))
+ assert(x == a and y == b and z == c)
+ end
+ for j=-100,-107,-1 do
+ for i=-1,j,-1 do x,y,z = byte(s, 1, bor(i, -8)) end
+ local a,b,c = byte(s, 1, bor(j, -8))
+ assert(x == a and y == b and z == c)
+ end
+end
+
+do --- Check for slot stack overflow
+ local s = string.rep("x", 500)
+ for i=1,100 do byte(s, 1, 500) end
+end
diff --git a/test/LuaJIT-tests/lib/string/char.lua b/test/LuaJIT-tests/lib/string/char.lua
new file mode 100644
index 0000000..544767d
--- /dev/null
+++ b/test/LuaJIT-tests/lib/string/char.lua
@@ -0,0 +1,29 @@
+local char = string.char
+
+do --- jit one char
+ local y
+ for i=1,100 do y = char(65) end
+ assert(y == "A")
+ local x = 97
+ for i=1,100 do y = char(x) end
+ assert(y == "a")
+ x = "98"
+ for i=1,100 do y = char(x) end
+ assert(y == "b")
+ for i=1,100 do y = char(32+i) end
+ assert(y == "\132")
+end
+
+do --- jit until out of bounds
+ local y
+ assert(not pcall(function()
+ for i=1,200 do y = char(100+i) end
+ end))
+ assert(y == "\255")
+end
+
+do --- jit five chars
+ local y
+ for i=1,100 do y = char(65, 66, i, 67, 68) end
+ assert(y == "ABdCD")
+end
diff --git a/test/LuaJIT-tests/lib/string/dump.lua b/test/LuaJIT-tests/lib/string/dump.lua
new file mode 100644
index 0000000..216c6eb
--- /dev/null
+++ b/test/LuaJIT-tests/lib/string/dump.lua
@@ -0,0 +1,31 @@
+local loadstring = loadstring or load
+
+do --- Must unpatch modified bytecode with ILOOP/JLOOP etc.
+ local function foo()
+ local t = {}
+ for i=1,100 do t[i] = i end
+ for a,b in ipairs(t) do end
+ local m = 0
+ while m < 100 do m = m + 1 end
+ end
+
+ local d1 = string.dump(foo)
+ foo()
+ assert(string.dump(foo) == d1)
+ if jit then jit.off(foo) end
+ foo()
+ assert(string.dump(foo) == d1)
+ local d2 = string.dump(loadstring(d1, ""), true)
+ local d3 = string.dump(assert(loadstring(d2, "")), true)
+ assert(d2 == d3)
+ assert(loadstring(string.dump(assert(loadstring(d2, "")))))
+end
+
+do --- roundtrip constants
+ local function f1() return -0x80000000 end
+ local function f2() return 0.971234567 end
+ assert(f1() == -0x80000000)
+ assert(loadstring(string.dump(f1), "")() == -0x80000000)
+ assert(f2() == 0.971234567)
+ assert(loadstring(string.dump(f2), "")() == 0.971234567)
+end
diff --git a/test/LuaJIT-tests/lib/string/format/index b/test/LuaJIT-tests/lib/string/format/index
new file mode 100644
index 0000000..4408853
--- /dev/null
+++ b/test/LuaJIT-tests/lib/string/format/index
@@ -0,0 +1 @@
+num.lua
diff --git a/test/LuaJIT-tests/lib/string/format/num.lua b/test/LuaJIT-tests/lib/string/format/num.lua
new file mode 100644
index 0000000..e8cb33f
--- /dev/null
+++ b/test/LuaJIT-tests/lib/string/format/num.lua
@@ -0,0 +1,184 @@
+local format, type, tonumber = string.format, type, tonumber
+
+local function check(input, fstr, output, inputN)
+ local actual = format(fstr, inputN or tonumber(input))
+ if actual == output then return end
+ local t = type(output)
+ if t == "string" then
+ if output:find"[[%]]" then
+ local s, e = actual:find((output:gsub("%.", "%%.")))
+ if s == 1 and e == #actual then return end
+ end
+ end
+ error(format("expected string.format(%q, %q) == %q, but got %q",
+ fstr, input, output, actual))
+end
+
+do --- small denormals at low precision +hexfloat !lex
+ assert(("%.9e"):format(0x1.0E00D1p-1050) == "8.742456525e-317")
+ assert(("%.13e"):format(0x1.1Cp-1068) == "3.5078660854729e-322")
+end
+
+do --- smoke
+ local cases = {
+ -- input, %e, %f, %g
+ { "0", "0.000000e+00", "0.000000", "0"},
+ { "1", "1.000000e+00", "1.000000", "1"},
+ { "0.5", "5.000000e-01", "0.500000", "0.5"},
+ { "123", "1.230000e+02", "123.000000", "123"},
+ {"0.0078125", "7.812500e-03", "0.00781[23]", "0.0078125"},
+ { "1.109375", "1.109375e+00", "1.109375", "1.1093[78]"},
+ { "0.999995", "9.999950e-01", "0.999995", "0.999995"},
+ {"0.9999995", "9.999995e-01", "1.000000", "1"},
+ { "99999.95", "9.999995e+04", "99999.950000", "99999.9"},
+ {"999999.95", "9.999999e+05", "999999.950000", "1e+06"},
+ {"123456978", "1.234570e+08", "123456978.000000", "1.23457e+08"},
+ { "33.3", "3.330000e+01", "33.300000", "33.3"},
+ }
+ for _, t in ipairs(cases) do
+ local n = tonumber(t[1])
+ check(t[1], "%e", t[2], n)
+ check(t[1], "%f", t[3], n)
+ check(t[1], "%g", t[4], n)
+ end
+end
+
+do --- easily enumerable cases of %a, %A +hexfloat
+ for i = 1, 16 do
+ check(1+(i-1)/16, "%.1a", "0x1.".. ("0123456789abcdef"):sub(i,i) .."p+0")
+ check(16+(i-1), "%.1A", "0X1.".. ("0123456789ABCDEF"):sub(i,i) .."P+4")
+ end
+end
+
+do --- easily enumerable cases of %f
+ for i = 1, 16 do
+ check(("1"):rep(i), "%#2.0f", ("1"):rep(i)..".")
+ end
+end
+
+do --- easily enumerable cases of %e
+ local z, f, c = ("0"):byte(), math.floor, string.char
+ for p = 0, 14 do
+ local head = "1.".. ("0"):rep(p)
+ local fmt = "%#.".. c(z + f(p / 10), z + (p % 10)) .."e"
+ for i = 1, 99 do
+ local istr = c(z + f(i / 10), z + (i % 10))
+ check("1e-".. istr, fmt, head .."e-".. istr)
+ check("1e+".. istr, fmt, head .."e+".. istr)
+ end
+ for i = 100, 308 do
+ local istr = c(z + f(i / 100), z + f(i / 10) % 10, z + (i % 10))
+ check("1e-".. istr, fmt, head .."e-".. istr)
+ check("1e+".. istr, fmt, head .."e+".. istr)
+ end
+ end
+end
+
+do --- assorted
+ check("0", "%.14g", "0")
+ check("1e-310", "%.0g", "1e-310")
+ check("1e8", "%010.5g", "000001e+08")
+ check("1e8", "% -10.5g", " 1e+08 ")
+ check("4e123", "%+#.0e", "+4.e+123")
+ check("1e49", "%.0f", "9999999999999999464902769475481793196872414789632")
+ check("1e50", "%.0f", "100000000000000007629769841091887003294964970946560")
+ check("1e50", "%.35g", "1.00000000000000007629769841091887e+50")
+ check("1e50", "%40.35g", " 1.00000000000000007629769841091887e+50")
+ check("1e50", "%#+40.34g", "+1.000000000000000076297698410918870e+50")
+ check("1e50", "%-40.35g", "1.00000000000000007629769841091887e+50 ")
+ check("0.5", "%.0f", "[01]")
+ check("0.25", "%.1f", "0.[23]")
+ check("999999.95", "%.7g", "999999.9")
+ check("999.99995", "%.7g", "1000")
+ check("6.9039613742e-314", "%.3e", "6.904e-314")
+
+ check(1e-323, "%.99g", "9.8813129168249308835313758573644274473011960522864"..
+ "9528851171365001351014540417503730599672723271985e-324")
+ check(1e308, "%.99f", "1000000000000000010979063629440455417404923096773118"..
+ "463368106829031575854049114915371633289784946888990612496697211725"..
+ "156115902837431400883283070091981460460312716645029330271856974896"..
+ "995885590433383844661650011784268976262129451776280911957867074581"..
+ "22783970171784415105291802893207873272974885715430223118336.000000"..
+ "000000000000000000000000000000000000000000000000000000000000000000"..
+ "000000000000000000000000000")
+ check("1", "%.99f", "1."..("0"):rep(99))
+ check("5", "%99g", (" "):rep(98).."5")
+ check("5", "%099g", ("0"):rep(98).."5")
+ check("5", "%-99g", "5".. (" "):rep(98))
+ check("5", "%0-99g", "5".. (" "):rep(98))
+
+ check((2^53-1)*2^971, "%e", "1.797693e+308")
+ check((2^53-1)*2^971, "%.0e", "2e+308")
+
+ check("0", "%.14g", "0")
+
+ check("0.15", "%.1f", "0.1")
+ check("0.45", "%.1f", "0.5")
+ check("0.55", "%.1f", "0.6")
+ check("0.85", "%.1f", "0.8")
+end
+
+do --- assorted %a +luajit>=2.1
+ check((2^53-1)*2^971, "%a", "0x1.fffffffffffffp+1023")
+ check((2^53-1)*2^971, "%.0a", "0x2p+1023")
+ check("0", "%a", "0x0p+0")
+ check("1.53173828125", "%1.8a", "0x1.88200000p+0")
+ check("1.53173828125", "%8.1a", "0x1.9p+0") -- libc on OSX gets this wrong
+ check("1.5317", "%8.1a", "0x1.9p+0")
+ check("1.53", "%8.1a", "0x1.8p+0")
+ check("-1.5", "%11.2a", " -0x1.80p+0")
+ check("3.14159265358", "%a", "0x1.921fb5443d6f4p+1")
+ check("3.14159265358", "%A", "0X1.921FB5443D6F4P+1")
+end
+
+do --- Cases where inprecision can easily affect rounding
+ check("2.28579528986935e-262", "%.14g", "2.2857952898694e-262")
+ check("4.86009084710405e+243", "%.14g", "4.8600908471041e+243")
+ check("6.28108398359615e+258", "%.14g", "6.2810839835962e+258")
+ check("4.29911075733405e+250", "%.14g", "4.2991107573341e+250")
+ check("8.5068432121065e+244", "% .13g", " 8.506843212107e+244")
+ check("8.1919113161235899e+233", "%.40g", "8.191911316123589934222156598061"..
+ "949037266e+233")
+ check("7.1022381748280933e+272", "%.40g", "7.102238174828093393858336547341"..
+ "897013319e+272")
+ check("5.8018368514358030e+261", "%.67g", "5.801836851435803025936253580958"..
+ "042578728799220447411839451694590343e+261")
+ check("7.9225909325493999e-199", "%.26g", "7.922590932549399935196127e-199")
+ check("2.4976643533685383e-153", "%.43g", "2.497664353368538321643894302495"..
+ "469512999562e-153")
+ check("9.796500001282779e+222", "%.4g", "9.797e+222")
+ check("7.7169235e-227", "%e", "7.716923e-227")
+ check("7.7169235000000044e-227", "%e", "7.716924e-227")
+ check("5.3996444915000004e+87", "%.9e", "5.399644492e+87")
+ check("2.03037546395e-49", "%.10e", "2.0303754640e-49")
+ check("3.38759425741500027e+65", "%.11e", "3.38759425742e+65")
+ check("1.013960434983135e-66", "%.0e", "1e-66")
+ check("1.32423054454835e-204", "%.13e", "1.3242305445484e-204")
+ check("5.9005060812045502e+100", "%.13e", "5.9005060812046e+100")
+end
+
+do --- ExploringBinary.com/print-precision-of-dyadic-fractions-varies-by-language/
+ check(5404319552844595/2^53, "%.53g", "0.5999999999999999777955395074968691"..
+ "9152736663818359375")
+ check(2^-1074, "%.99e", "4.940656458412465441765687928682213723650598026143"..
+ "247644255856825006755072702087518652998363616359924e-324")
+ check(1-2^-53, "%1.53f", "0.99999999999999988897769753748434595763683319091"..
+ "796875")
+end
+
+do --- ExploringBinary.com/incorrect-floating-point-to-decimal-conversions/
+ check("1.0551955", "%.7g", "1.055195")
+ check("8.330400913327153", "%.15f", "8.330400913327153")
+ check("9194.25055964485", "%.14g", "9194.2505596449")
+ check("816.2665949149578", "%.16g", "816.2665949149578")
+ check("95.47149571505499", "%.16g", "95.47149571505498")
+end
+
+do --- big f +luajit>=2.1
+ check("9.522938016739373", "%.15F", "9.522938016739372")
+end
+
+do --- RandomASCII.wordpress.com/2013/02/07/
+ check("6.10351562e-05", "%1.8e", "6.1035156[23]e%-05")
+ check("4.3037358649999999e-15", "%1.8e", "4.30373586e-15")
+end
diff --git a/test/LuaJIT-tests/lib/string/index b/test/LuaJIT-tests/lib/string/index
new file mode 100644
index 0000000..c0638e9
--- /dev/null
+++ b/test/LuaJIT-tests/lib/string/index
@@ -0,0 +1,11 @@
+metatable.lua
+byte.lua
+char.lua
+dump.lua
+format
+len.lua
+lower_upper.lua
+multiple_functions.lua
+rep.lua
+reverse.lua
+sub.lua
diff --git a/test/LuaJIT-tests/lib/string/len.lua b/test/LuaJIT-tests/lib/string/len.lua
new file mode 100644
index 0000000..8ed7e8a
--- /dev/null
+++ b/test/LuaJIT-tests/lib/string/len.lua
@@ -0,0 +1,14 @@
+local len = string.len
+local expect_error = require"common.expect_error"
+
+do --- smoke
+ assert(len("abc") == 3)
+ assert(len(123) == 3)
+end
+
+do --- argcheck
+ expect_error(function() len() end,
+ "bad argument #1 to 'len' (string expected, got nil)")
+ expect_error(function() len(false) end,
+ "bad argument #1 to 'len' (string expected, got boolean)")
+end
diff --git a/test/LuaJIT-tests/lib/string/lower_upper.lua b/test/LuaJIT-tests/lib/string/lower_upper.lua
new file mode 100644
index 0000000..7370c44
--- /dev/null
+++ b/test/LuaJIT-tests/lib/string/lower_upper.lua
@@ -0,0 +1,51 @@
+do --- smoke
+ assert(("abc123DEF_<>"):lower() == "abc123def_<>")
+ assert(("abc123DEF_<>"):upper() == "ABC123DEF_<>")
+end
+
+do --- repeated
+ local l = "the quick brown fox..."
+ local u = "THE QUICK BROWN FOX..."
+ local s = l
+ for i = 1, 75 do
+ s = s:upper()
+ assert(s == u)
+ s = s:lower()
+ assert(s == l)
+ end
+end
+
+do --- repeated with growing string
+ local y, z
+ local x = "aBcDe"
+ for i=1,100 do
+ y = string.upper(x)
+ z = y.."fgh"
+ end
+ assert(y == "ABCDE")
+ assert(z == "ABCDEfgh")
+end
+
+do --- misc upper
+ local y
+ for i=1,100 do y = string.upper("aBc9") end
+ assert(y == "ABC9")
+ local x = ":abCd+"
+ for i=1,100 do y = string.upper(x) end
+ assert(y == ":ABCD+")
+ x = 1234
+ for i=1,100 do y = string.upper(x) end
+ assert(y == "1234")
+end
+
+do --- misc lower
+ local y
+ for i=1,100 do y = string.lower("aBc9") end
+ assert(y == "abc9")
+ local x = ":abcd+"
+ for i=1,100 do y = string.lower(x) end
+ assert(y == ":abcd+")
+ x = 1234
+ for i=1,100 do y = string.lower(x) end
+ assert(y == "1234")
+end
diff --git a/test/LuaJIT-tests/lib/string/metatable.lua b/test/LuaJIT-tests/lib/string/metatable.lua
new file mode 100644
index 0000000..d39ed43
--- /dev/null
+++ b/test/LuaJIT-tests/lib/string/metatable.lua
@@ -0,0 +1,3 @@
+do --- __index metamethod is string library
+ assert(debug.getmetatable("").__index == string)
+end
diff --git a/test/LuaJIT-tests/lib/string/multiple_functions.lua b/test/LuaJIT-tests/lib/string/multiple_functions.lua
new file mode 100644
index 0000000..7b9d0f1
--- /dev/null
+++ b/test/LuaJIT-tests/lib/string/multiple_functions.lua
@@ -0,0 +1,16 @@
+do --- string_op
+ local t, y = {}, {}
+ for i=1,100 do t[i] = string.char(i, 16+i, 32+i) end
+ for i=1,100 do t[i] = string.reverse(t[i]) end
+ assert(t[100] == "\132\116\100")
+ for i=1,100 do t[i] = string.reverse(t[i]) end
+ for i=1,100 do assert(t[i] == string.char(i, 16+i, 32+i)) end
+ for i=1,100 do y[i] = string.upper(t[i]) end
+ assert(y[65] == "AQA")
+ assert(y[97] == "AQ\129")
+ assert(y[100] == "DT\132")
+ for i=1,100 do y[i] = string.lower(t[i]) end
+ assert(y[65] == "aqa")
+ assert(y[97] == "aq\129")
+ assert(y[100] == "dt\132")
+end
diff --git a/test/LuaJIT-tests/lib/string/rep.lua b/test/LuaJIT-tests/lib/string/rep.lua
new file mode 100644
index 0000000..550c15b
--- /dev/null
+++ b/test/LuaJIT-tests/lib/string/rep.lua
@@ -0,0 +1,68 @@
+local rep = string.rep
+
+do --- smoke
+ assert(("p"):rep(0) == "")
+ assert(("a"):rep(3) == "aaa")
+ assert(("x\0z"):rep(4) == "x\0zx\0zx\0zx\0z")
+end
+
+do --- versus concat
+ local s = ""
+ for i = 1, 75 do
+ s = s .. "{}"
+ assert(s == ("{}"):rep(i))
+ end
+end
+
+do --- misc
+ local y
+ for i=1,100 do y = rep("a", 10) end
+ assert(y == "aaaaaaaaaa")
+ for i=1,100 do y = rep("ab", 10) end
+ assert(y == "abababababababababab")
+ local x = "a"
+ for i=1,100 do y = rep(x, 10) end
+ assert(y == "aaaaaaaaaa")
+ local n = 10
+ for i=1,100 do y = rep(x, n) end
+ assert(y == "aaaaaaaaaa")
+ x = "ab"
+ for i=1,100 do y = rep(x, n) end
+ assert(y == "abababababababababab")
+ x = 12
+ n = "10"
+ for i=1,100 do y = rep(x, n) end
+ assert(y == "12121212121212121212")
+end
+
+do --- separator +goto
+ local y
+ for i=1,100 do y = rep("ab", 10, "c") end
+ assert(y == "abcabcabcabcabcabcabcabcabcab")
+end
+
+do --- iterate to table
+ local t = {}
+ for i=1,100 do t[i] = rep("ab", i-85) end
+ assert(t[100] == "ababababababababababababababab")
+end
+
+do --- iterate to table with sep +goto
+ local t = {}
+ for i=1,100 do t[i] = rep("ab", i-85, "c") end
+ assert(t[85] == "")
+ assert(t[86] == "ab")
+ assert(t[87] == "abcab")
+ assert(t[100] == "abcabcabcabcabcabcabcabcabcabcabcabcabcabcab")
+end
+
+do --- iterate and concat
+ local y, z
+ local x = "ab"
+ for i=1,100 do
+ y = rep(x, i-90)
+ z = y.."fgh"
+ end
+ assert(y == "abababababababababab")
+ assert(z == "ababababababababababfgh")
+end
diff --git a/test/LuaJIT-tests/lib/string/reverse.lua b/test/LuaJIT-tests/lib/string/reverse.lua
new file mode 100644
index 0000000..deaade7
--- /dev/null
+++ b/test/LuaJIT-tests/lib/string/reverse.lua
@@ -0,0 +1,13 @@
+local reverse = string.reverse
+
+do --- misc
+ local y
+ for i=1,100 do y = reverse("abc") end
+ assert(y == "cba")
+ local x = "abcd"
+ for i=1,100 do y = reverse(x) end
+ assert(y == "dcba")
+ x = 1234
+ for i=1,100 do y = reverse(x) end
+ assert(y == "4321")
+end
diff --git a/test/LuaJIT-tests/lib/string/sub.lua b/test/LuaJIT-tests/lib/string/sub.lua
new file mode 100644
index 0000000..ecb8021
--- /dev/null
+++ b/test/LuaJIT-tests/lib/string/sub.lua
@@ -0,0 +1,189 @@
+local band, bor = bit and bit.band, bit and bit.bor
+local sub = string.sub
+local expect_error = require"common.expect_error"
+
+do --- smoke
+ assert(sub("abc", 2) == "bc")
+ assert(sub(123, "2") == "23")
+end
+
+do --- argcheck
+ expect_error(function() sub("abc", false) end,
+ "bad argument #2 to 'sub' (number expected, got boolean)")
+ expect_error(function() ("abc"):sub(false) end,
+ "bad argument #1 to 'sub' (number expected, got boolean)")
+end
+
+do --- all bar substrings
+ local subs = {
+ {"b", "ba", "bar"},
+ { "", "a", "ar"},
+ { "", "", "r"}
+ }
+ for i = 1, 3 do
+ for j = 1, 3 do
+ assert(sub("bar", i, j) == subs[i][j])
+ assert(sub("bar", -4+i, j) == subs[i][j])
+ assert(sub("bar", i, -4+j) == subs[i][j])
+ assert(sub("bar", -4+i, -4+j) == subs[i][j])
+ end
+ end
+end
+
+do --- Positive slice [i,len] or overflow +bit
+ local s = "abc"
+ local x
+ for j=100,107 do
+ for i=1,j do x = sub("abc", band(i, 7)) end
+ assert(x == sub("abc", band(j, 7)))
+ end
+ for j=100,107 do
+ for i=1,j do x = sub(s, band(i, 7)) end
+ assert(x == sub(s, band(j, 7)))
+ end
+end
+
+do --- Negative slice [-i,len] or underflow +bit
+ local s = "abc"
+ local x
+ for j=-100,-107,-1 do
+ for i=-1,j,-1 do x = sub("abc", bor(i, -8)) end
+ assert(x == sub("abc", bor(j, -8)))
+ end
+ for j=-100,-107,-1 do
+ for i=-1,j,-1 do x = sub(s, bor(i, -8)) end
+ assert(x == sub(s, bor(j, -8)))
+ end
+end
+
+do --- Positive slice [1,i] or overflow +bit
+ local s = "abc"
+ local x
+ for j=100,107 do
+ for i=1,j do x = sub("abc", 1, band(i, 7)) end
+ assert(x == sub("abc", 1, band(j, 7)))
+ end
+ for j=100,107 do
+ for i=1,j do x = sub(s, 1, band(i, 7)) end
+ assert(x == sub(s, 1, band(j, 7)))
+ end
+end
+
+do --- Negative slice [1,-i] or underflow +bit
+ local s = "abc"
+ local x
+ for j=-100,-107,-1 do
+ for i=-1,j,-1 do x = sub("abc", 1, bor(i, -8)) end
+ assert(x == sub("abc", 1, bor(j, -8)))
+ end
+ for j=-100,-107,-1 do
+ for i=-1,j,-1 do x = sub(s, 1, bor(i, -8)) end
+ assert(x == sub(s, 1, bor(j, -8)))
+ end
+end
+
+do --- jit sub 1 eq
+ local s = "abcde"
+ local x = 0
+ for i=1,100 do
+ if sub(s, 1, 1) == "a" then x = x + 1 end
+ end
+ assert(x == 100)
+end
+
+do --- jit sub 1 ne (contents)
+ local s = "abcde"
+ local x = 0
+ for i=1,100 do
+ if sub(s, 1, 1) == "b" then x = x + 1 end
+ end
+ assert(x == 0)
+end
+
+do --- jit sub 1 ne (rhs too long)
+ local s = "abcde"
+ local x = 0
+ for i=1,100 do
+ if sub(s, 1, 1) == "ab" then x = x + 1 end
+ end
+ assert(x == 0)
+end
+
+do --- jit sub 1,2 ne
+ local s = "abcde"
+ local x = 0
+ for i=1,100 do
+ if sub(s, 1, 2) == "a" then x = x + 1 end
+ end
+ assert(x == 0)
+end
+
+do --- jit sub 1,k eq
+ local s = "abcde"
+ local x = 0
+ local k = 1
+ for i=1,100 do
+ if sub(s, 1, k) == "a" then x = x + 1 end
+ end
+ assert(x == 100)
+end
+
+do --- jit sub 1,k ne (contents)
+ local s = "abcde"
+ local x = 0
+ local k = 1
+ for i=1,100 do
+ if sub(s, 1, k) == "b" then x = x + 1 end
+ end
+ assert(x == 0)
+end
+
+do --- jit sub 1,k ne (rhs too long)
+ local s = "abcde"
+ local x = 0
+ local k = 1
+ for i=1,100 do
+ if sub(s, 1, k) == "ab" then x = x + 1 end
+ end
+ assert(x == 0)
+end
+
+do --- jit sub 1,2 eq
+ local s = "abcde"
+ local x = 0
+ for i=1,100 do
+ if sub(s, 1, 2) == "ab" then x = x + 1 end
+ end
+ assert(x == 100)
+end
+
+do --- jit sub 1,3 eq
+ local s = "abcde"
+ local x = 0
+ for i=1,100 do
+ if sub(s, 1, 3) == "abc" then x = x + 1 end
+ end
+ assert(x == 100)
+end
+
+do --- jit sub 1,4 eq
+ local s = "abcde"
+ local x = 0
+ for i=1,100 do
+ if sub(s, 1, 4) == "abcd" then x = x + 1 end
+ end
+ assert(x == 100)
+end
+
+do --- jit sub i,i
+ local t = {}
+ local line = string.rep("..XX", 100)
+ local i = 1
+ local c = line:sub(i, i)
+ while c ~= "" and c ~= "Z" do
+ t[i] = c == "X" and "Y" or c
+ i = i + 1
+ c = line:sub(i, i)
+ end
+ assert(table.concat(t) == string.rep("..YY", 100))
+end
diff --git a/test/LuaJIT-tests/lib/table/concat.lua b/test/LuaJIT-tests/lib/table/concat.lua
new file mode 100644
index 0000000..1f2a2f9
--- /dev/null
+++ b/test/LuaJIT-tests/lib/table/concat.lua
@@ -0,0 +1,55 @@
+local concat, assert, pcall = table.concat, assert, pcall
+
+do --- table.concat
+ local t = {a=1,b=2,c=3,d=4,e=5}
+ t[1] = 4
+ t[3] = 6
+ local ok, err = pcall(concat, t, "", 1, 3)
+ assert(not ok and err:match("index 2 "))
+ local q = {}
+ for i=1,100 do q[i] = {9,8,7} end
+ q[90] = t
+ for i=1,100 do
+ assert(pcall(concat, q[i], "", 1, 3) == (i ~= 90))
+ end
+ t[2] = 5 -- index 1 - 3 in hash part
+ q[91] = {}
+ q[92] = {9}
+ for i=1,100 do q[i] = concat(q[i], "x") end
+ assert(q[90] == "4x5x6")
+ assert(q[91] == "")
+ assert(q[92] == "9")
+ assert(q[93] == "9x8x7")
+end
+
+do --- table.concat must inhibit CSE and DSE
+ local t = {1,2,3}
+ local y, z
+ for i=1,100 do
+ y = concat(t, "x", 1, 3)
+ t[2] = i
+ z = concat(t, "x", 1, 3)
+ end
+ assert(y == "1x99x3")
+ assert(z == "1x100x3")
+end
+
+do --- table.concat must inhibit CSE and DSE 2
+ local y
+ for i=1,100 do
+ local t = {1,2,3}
+ t[2] = 4
+ y = concat(t, "x")
+ t[2] = 9
+ end
+ assert(y == "1x4x3")
+end
+
+do --- table.concat must inhibit CSE and DSE 3
+ local t = {[0]={}, {}, {}, {}}
+ for i=1,30 do
+ for j=3,0,-1 do
+ t[j].x = t[j-1]
+ end
+ end
+end
diff --git a/test/LuaJIT-tests/lib/table/index b/test/LuaJIT-tests/lib/table/index
new file mode 100644
index 0000000..bd3af0b
--- /dev/null
+++ b/test/LuaJIT-tests/lib/table/index
@@ -0,0 +1,6 @@
+concat.lua
+insert.lua
+new.lua +table.new
+pack.lua +compat5.2
+remove.lua
+sort.lua
diff --git a/test/LuaJIT-tests/lib/table/insert.lua b/test/LuaJIT-tests/lib/table/insert.lua
new file mode 100644
index 0000000..91d4dd8
--- /dev/null
+++ b/test/LuaJIT-tests/lib/table/insert.lua
@@ -0,0 +1,17 @@
+local tinsert = table.insert
+local assert = assert
+
+do --- table.insert(t,i)
+ local t = {}
+ for i=1,100 do t[i] = i end
+ for i=1,100 do tinsert(t, i) end
+ assert(#t == 200 and t[100] == 100 and t[200] == 100)
+end
+
+do --- table.insert(t,i,i)
+ local t = {}
+ for i=1,200 do t[i] = i end
+ for i=101,200 do tinsert(t, i, i) end
+ assert(#t == 300 and t[101] == 101 and t[200] == 200 and t[300] == 200)
+end
+
diff --git a/test/LuaJIT-tests/lib/table/misc.lua b/test/LuaJIT-tests/lib/table/misc.lua
new file mode 100644
index 0000000..e0e2fc5
--- /dev/null
+++ b/test/LuaJIT-tests/lib/table/misc.lua
@@ -0,0 +1,58 @@
+-- TODO: Organise
+
+-- ABC elim
+-- +opt +abc
+do
+ local s, t = {}, {}
+ for i=1,100 do t[i] = 1 end
+ for i=1,100 do s[i] = t end
+ s[90] = {}
+ local n = 100
+ for i=1,n do s[i][i] = i end
+end
+
+--- TSETM
+-- Initialize table with multiple return values
+do
+ local function f(a,b,c)
+ return a,b,c
+ end
+
+ local t
+
+ t = {(f(1,2,3))}
+ assert(t[1] == 1 and t[2] == nil and t[3] == nil)
+
+ t = {f(1,2,3)}
+ assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == nil)
+ t = {f(1,2,3),}
+ assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == nil)
+
+ t = {f(1,2,3), f(4,5,6)}
+ assert(t[1] == 1 and t[2] == 4 and t[3] == 5 and t[4] == 6 and t[5] == nil)
+
+ t = {
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ f(2,3,4)}
+ assert(t[255] == 1 and t[256] == 2 and t[257] == 3 and t[258] == 4 and t[259] == nil)
+end
+
+--- TSETM 2
+-- Initialize table with function returning 2 constant return values
+do
+ local function f() return 9, 10 end
+ local t
+ for i=1,100 do t = { 1, 2, 3, f() } end
+ assert(t[1] == 1 and t[2] == 2 and t[3] == 3 and t[4] == 9 and t[5] == 10 and
+ t[6] == nil)
+end
+
+
+
diff --git a/test/LuaJIT-tests/lib/table/new.lua b/test/LuaJIT-tests/lib/table/new.lua
new file mode 100644
index 0000000..483c129
--- /dev/null
+++ b/test/LuaJIT-tests/lib/table/new.lua
@@ -0,0 +1,11 @@
+local tnew = require"table.new"
+
+do --- table.new
+ local x, y
+ for i=1,100 do
+ x = tnew(100, 30)
+ assert(type(x) == "table")
+ if i == 90 then y = x end
+ end
+ assert(x ~= y)
+end
diff --git a/test/LuaJIT-tests/lib/table/pack.lua b/test/LuaJIT-tests/lib/table/pack.lua
new file mode 100644
index 0000000..5bd6ecb
--- /dev/null
+++ b/test/LuaJIT-tests/lib/table/pack.lua
@@ -0,0 +1,7 @@
+do --- empty
+ local t = table.pack()
+ assert(type(t) == "table")
+ assert(t.n == 0)
+ assert(t[0] == nil)
+ assert(t[1] == nil)
+end
diff --git a/test/LuaJIT-tests/lib/table/remove.lua b/test/LuaJIT-tests/lib/table/remove.lua
new file mode 100644
index 0000000..1b24a4f
--- /dev/null
+++ b/test/LuaJIT-tests/lib/table/remove.lua
@@ -0,0 +1,42 @@
+local tremove = table.remove
+local assert = assert
+
+do --- table.remove(t) removes correct entries
+ local t = {}
+ for i=1,200 do t[i] = i end
+ for i=1,100 do tremove(t) end
+ assert(#t == 100 and t[100] == 100)
+end
+
+do --- table.remove(t) returns the removed entry
+ local t = {}
+ for i=1,200 do t[i] = i end
+ for i=1,100 do assert(tremove(t) == 201-i) end
+ assert(#t == 100 and t[100] == 100)
+end
+
+do --- table.remove(t, 1) removes and returns the first entry
+ local t = {}
+ for i=1,200 do t[i] = i end
+ for i=1,100 do assert(tremove(t, 1) == i) end
+ assert(#t == 100 and t[100] == 200)
+end
+
+do --- TSETR hash part +table.new
+ local tnew = require"table.new"
+ local t = tnew(0, 16)
+ for i=10,1,-1 do t[i] = i+3 end
+ for i=10,1,-1 do assert(tremove(t) == i+3) end
+ assert(#t == 0)
+end
+
+do --- TSETR write barrier +table.new
+ local tnew = require"table.new"
+ for _, t in ipairs{{}, tnew(0, 16)} do
+ for i = 1, 10 do t[i] = {i} end
+ for i = 1, 10 do
+ collectgarbage()
+ assert(tremove(t, 1)[1] == i)
+ end
+ end
+end
diff --git a/test/LuaJIT-tests/lib/table/sort.lua b/test/LuaJIT-tests/lib/table/sort.lua
new file mode 100644
index 0000000..6a86fcf
--- /dev/null
+++ b/test/LuaJIT-tests/lib/table/sort.lua
@@ -0,0 +1,27 @@
+-- Really a test for lua_lessthan()
+local N = 1000
+
+do --- numbers
+ math.randomseed(42)
+ local t = {}
+ for i=1,N do t[i] = math.random(N) end
+ table.sort(t)
+ for i=2,N do assert(t[i-1] <= t[i]) end
+end
+
+do --- strings
+ math.randomseed(42)
+ local t = {}
+ for i=1,N do t[i] = math.random(1, N/10).."" end
+ table.sort(t)
+ for i=2,N do assert(t[i-1] <= t[i]) end
+end
+
+do --- tables
+ math.randomseed(42)
+ local mt = { __lt = function(a,b) return a[1] < b[1] end }
+ local t = {}
+ for i=1,N do t[i] = setmetatable({ math.random(N) }, mt) end
+ table.sort(t)
+ for i=2,N do assert(t[i-1][1] <= t[i][1]) end
+end
diff --git a/test/LuaJIT-tests/misc/alias_alloc.lua b/test/LuaJIT-tests/misc/alias_alloc.lua
new file mode 100644
index 0000000..02fe618
--- /dev/null
+++ b/test/LuaJIT-tests/misc/alias_alloc.lua
@@ -0,0 +1,54 @@
+
+do
+ local t = {1}
+ local x
+ for i=1,100 do
+ local v = {i}
+ t[1] = v[1]
+ x = v[1]
+ end
+ assert(x == 100 and t[1] == 100)
+end
+
+do
+ local t = {1}
+ local x,y
+ for i=1,100 do
+ local v = {i}
+ local w = {i+1}
+ x = v[1]
+ y = w[1]
+ end
+ assert(x == 100 and y == 101)
+end
+
+do
+ local mt = {}
+ local t = setmetatable({}, mt)
+ local x
+ for i=1,100 do
+ local v = {}
+ setmetatable(v, getmetatable(t))
+ assert(getmetatable(v) == mt)
+ end
+end
+
+-- See also sink_alloc.lua
+do
+ local x,k={1,2},{3,4}
+ for i=1,100 do x = {x[1]+k[1], x[2]+k[2]} end
+ assert(x[1] == 301)
+ assert(x[2] == 402)
+end
+
+-- FLOAD for tab.asize/tab.array crossing NEWREF.
+do
+ local t = {1}
+ for i=1,100 do
+ local v = {}
+ local w = {}
+ v[1] = t[1]
+ w[1] = t[1]
+ end
+end
+
diff --git a/test/LuaJIT-tests/misc/api_call.lua b/test/LuaJIT-tests/misc/api_call.lua
new file mode 100644
index 0000000..7dbd5e4
--- /dev/null
+++ b/test/LuaJIT-tests/misc/api_call.lua
@@ -0,0 +1,98 @@
+local ctest = require("ctest")
+
+local function ret0() end
+local function ret1() return 1 end
+local function ret2() return 1,2 end
+local function ret3() return 1,2,3 end
+local function retva(...) return ... end
+local function ret1va(...) return 1,... end
+
+local function pack(...)
+ return { n = select('#', ...), ... }
+end
+
+local function ck(res, ...)
+ local ok = pack(...)
+ if res.n ~= ok.n then error("nresults wrong: "..res.n.." ~= "..ok.n, 2) end
+ for i=1,res.n do
+ if res[i] ~= ok[i] then
+ error("result["..i.."] wrong: "..tostring(res[i]).." ~= "..tostring(ok[i]), 2)
+ end
+ end
+end
+
+local function test_adjust_results(testfunc)
+
+ local function cc(nres, f, ...)
+ return pack(testfunc(nres, f, ...))
+ end
+
+ ck(cc(0, ret0))
+ ck(cc(0, ret1))
+ ck(cc(0, ret2))
+ ck(cc(0, ret3))
+ ck(cc(0, retva))
+
+ ck(cc(1, ret0), nil)
+ ck(cc(1, ret1), 1)
+ ck(cc(1, ret2), 1)
+ ck(cc(1, ret3), 1)
+ ck(cc(1, retva), nil)
+ ck(cc(1, retva, 1), 1)
+
+ ck(cc(2, ret0), nil, nil)
+ ck(cc(2, ret1), 1, nil)
+ ck(cc(2, ret2), 1, 2)
+ ck(cc(2, ret3), 1, 2)
+ ck(cc(2, retva), nil, nil)
+ ck(cc(2, retva, 1), 1, nil)
+ ck(cc(2, retva, 1, 2), 1, 2)
+
+ ck(cc(-1, ret0))
+ ck(cc(-1, ret1), 1)
+ ck(cc(-1, ret2), 1, 2)
+ ck(cc(-1, ret3), 1, 2, 3)
+ ck(cc(-1, retva))
+ ck(cc(-1, retva, 1), 1)
+ ck(cc(-1, retva, 1, 2), 1, 2)
+end
+
+test_adjust_results(ctest.call)
+test_adjust_results(ctest.pcall_err)
+
+
+local function gcshrink()
+ for i=1,10 do collectgarbage() end
+end
+
+assert(select('#', ctest.call(2000, gcshrink)) == 2000)
+gcshrink()
+assert(select('#', ctest.call(7000, gcshrink)) == 7000)
+gcshrink()
+
+local function test_yield(resume, yield)
+ local function inpcall()
+ ck(pack(yield(6, 7)), 18, 19)
+ end
+ local co = coroutine.create(function(...)
+ ck(pack(...), 11, 12)
+ ck(pack(yield(1, 2)))
+ ck(pack(yield()), 13, 14, 15)
+ ck(pack(yield(3, 4, 5)), 16, 17)
+ assert(pcall(inpcall) == true)
+ return 8, 9
+ end)
+
+ ck(pack(resume(co, 11, 12)), true, 1, 2)
+ ck(pack(resume(co)), true)
+ ck(pack(resume(co, 13, 14, 15)), true, 3, 4, 5)
+ ck(pack(resume(co, 16, 17)), true, 6, 7)
+ ck(pack(resume(co, 18, 19)), true, 8, 9)
+ assert(resume(co) == false)
+end
+
+test_yield(coroutine.resume, coroutine.yield)
+test_yield(ctest.resume, coroutine.yield)
+test_yield(coroutine.resume, ctest.yield)
+test_yield(ctest.resume, ctest.yield)
+
diff --git a/test/LuaJIT-tests/misc/catch_wrap.lua b/test/LuaJIT-tests/misc/catch_wrap.lua
new file mode 100644
index 0000000..7f656bc
--- /dev/null
+++ b/test/LuaJIT-tests/misc/catch_wrap.lua
@@ -0,0 +1,45 @@
+
+local cp = require("cpptest")
+cp.wrapon()
+
+do
+ local a, b = pcall(cp.catch, function() return "x" end)
+ assert(a == true and b == "x")
+end
+
+do
+ local a, b = pcall(function() cp.throw("foo") end)
+ assert(a == false and b == "foo")
+end
+
+local unwind
+do
+ local a, b = pcall(cp.catch, function() cp.throw("foo") end)
+ unwind = a
+ assert((a == false and b == "foo") or (a == true and b == "catch ..."))
+end
+
+do
+ local st = cp.alloc(function() return cp.isalloc() end)
+ assert(st == true)
+ assert(cp.isalloc() == false)
+end
+
+do
+ local a, b = pcall(cp.alloc, function()
+ assert(cp.isalloc() == true)
+ return "foo", cp.throw
+ end)
+ assert(a == false and b == "foo")
+ assert(cp.isalloc() == false)
+end
+
+do
+ local a, b = pcall(cp.alloc, function()
+ assert(cp.isalloc() == true)
+ return "foo", error
+ end)
+ assert(a == false and b == "foo")
+ if unwind then assert(cp.isalloc() == false) end
+end
+
diff --git a/test/LuaJIT-tests/misc/coro_traceback.lua b/test/LuaJIT-tests/misc/coro_traceback.lua
new file mode 100644
index 0000000..2676d2c
--- /dev/null
+++ b/test/LuaJIT-tests/misc/coro_traceback.lua
@@ -0,0 +1,8 @@
+
+local co = coroutine.create(function()
+ local x = nil
+ local y = x.x
+end)
+assert(coroutine.resume(co) == false)
+debug.traceback(co)
+
diff --git a/test/LuaJIT-tests/misc/coro_yield.lua b/test/LuaJIT-tests/misc/coro_yield.lua
new file mode 100644
index 0000000..ae3206e
--- /dev/null
+++ b/test/LuaJIT-tests/misc/coro_yield.lua
@@ -0,0 +1,111 @@
+local create = coroutine.create
+local wrap = coroutine.wrap
+local resume = coroutine.resume
+local yield = coroutine.yield
+
+-- Test stack overflow handling on return from coroutine.
+do
+ wrap(function()
+ local co = create(function()
+ yield(string.byte(string.rep(" ", 100), 1, 100))
+ end)
+ assert(select('#', resume(co)) == 101)
+ end)()
+end
+
+do
+ wrap(function()
+ local f = wrap(function()
+ yield(string.byte(string.rep(" ", 100), 1, 100))
+ end)
+ assert(select('#', f()) == 100)
+ end)()
+end
+
+do
+ local function cogen(x)
+ return wrap(function(n) repeat x = x+n; n = yield(x) until false end),
+ wrap(function(n) repeat x = x*n; n = yield(x) until false end)
+ end
+
+ local a,b=cogen(3)
+ local c,d=cogen(5)
+ assert(d(b(c(a(d(b(c(a(1)))))))) == 168428160)
+end
+
+do
+ local function verify(what, expect, ...)
+ local got = {...}
+ for i=1,100 do
+ if expect[i] ~= got[i] then
+ error("FAIL " .. what)
+ end
+ if expect[i] == nil then
+ break
+ end
+ end
+ end
+
+ local function cofunc(...)
+ verify("call", { 1, "foo" }, ...)
+ verify("yield", { "bar" }, yield(2, "test"))
+ verify("pcall yield", { true, "again" }, pcall(yield, "from pcall"))
+ return "end"
+ end
+
+ local co = create(cofunc)
+ verify("resume", { true, 2, "test" }, resume(co, 1, "foo"))
+ verify("resume pcall", { true, "from pcall" }, resume(co, "bar"))
+ verify("resume end", { true, "end" }, resume(co, "again"))
+end
+
+do
+ local function verify(expect, func, ...)
+ local co = create(func)
+ for i=1,100 do
+ local ok, res = resume(co, ...)
+ if not ok then
+ if expect[i] ~= nil then
+ error("too few results: ["..i.."] = "..tostring(expect[i]).." (got: "..tostring(res)..")")
+ end
+ break
+ end
+ if expect[i] ~= res then
+ error("bad result: ["..i.."] = "..tostring(res).." (should be: "..tostring(expect[i])..")")
+ end
+ end
+ end
+
+ verify({ 42, 99 },
+ function(x) pcall(yield, x) return 99 end,
+ 42)
+
+ verify({ 42, 99 },
+ function(x) pcall(function(y) yield(y) end, x) return 99 end,
+ 42)
+
+ verify({ 42, 99 },
+ function(x) xpcall(yield, debug.traceback, x) return 99 end,
+ 42)
+
+ verify({ 45, 44, 43, 42, 99 },
+ function(x, y)
+ for i in
+ function(o, k)
+ yield(o+k)
+ if k ~= 0 then return k-1 end
+ end,x,y do
+ end
+ return 99
+ end,
+ 42, 3)
+
+ verify({ 84, 99 },
+ function(x)
+ local o = setmetatable({ x },
+ {__add = function(a, b) yield(a[1]+b[1]) return 99 end })
+ return o+o
+ end,
+ 42)
+end
+
diff --git a/test/LuaJIT-tests/misc/debug_gc.lua b/test/LuaJIT-tests/misc/debug_gc.lua
new file mode 100644
index 0000000..30fb2b9
--- /dev/null
+++ b/test/LuaJIT-tests/misc/debug_gc.lua
@@ -0,0 +1,47 @@
+
+-- Do not run this test unless the JIT compiler is turned off.
+if jit and jit.status and jit.status() then return end
+
+local caught, caught_line, caught_mm
+
+local function gcmeta()
+ if caught ~= "end" then
+-- print(debug.traceback())
+ -- This may point to the wrong instruction if in a JIT trace.
+ -- But there's no guarantee if, when or where any GC steps occur.
+ local dbg = debug.getinfo(2)
+ caught_line = dbg.currentline
+ caught_mm = debug.getinfo(1).name
+ caught = true
+ end
+end
+
+local function testgc(mm, f)
+ collectgarbage()
+ caught = false
+ local u = newproxy(true)
+ getmetatable(u).__gc = gcmeta
+ u = nil
+ for i=1,100000 do
+ f(i)
+ -- This check may be hoisted. __gc is not supposed to have side-effects.
+ if caught then break end
+ end
+ if not caught then
+ error(mm.." metamethod not called", 2)
+ end
+ if type(caught_line) ~= "number" or caught_line < 0 then
+ error("bad linenumber in debug info", 2)
+ end
+ if caught_mm ~= mm then
+ error("bad name for metamethod in debug info", 2)
+ end
+end
+
+local x
+testgc("__gc", function(i) x = {} end)
+testgc("__gc", function(i) x = {1} end)
+testgc("__gc", function(i) x = function() end end)
+testgc("__concat", function(i) x = i.."" end)
+
+caught = "end"
diff --git a/test/LuaJIT-tests/misc/dualnum.lua b/test/LuaJIT-tests/misc/dualnum.lua
new file mode 100644
index 0000000..5f1288c
--- /dev/null
+++ b/test/LuaJIT-tests/misc/dualnum.lua
@@ -0,0 +1,47 @@
+
+-- Positive overflow
+do
+ local x = 0
+ for i=2147483446,2147483647,2 do x = x + 1 end
+ assert(x == 101)
+end
+
+-- Negative overflow
+do
+ local x = 0
+ for i=-2147483447,-2147483648,-2 do x = x + 1 end
+ assert(x == 101)
+end
+
+-- SLOAD with number to integer conversion.
+do
+ local k = 1
+ local a, b, c = 1/k, 20/k, 1/k
+ for i=1,20 do
+ for j=a,b,c do end
+ end
+end
+
+do
+ local function fmin(a, b)
+ for i=1,100 do a = math.min(a, b) end
+ return a
+ end
+ local function fmax(a, b)
+ for i=1,100 do a = math.max(a, b) end
+ return a
+ end
+ assert(fmin(1, 3) == 1)
+ assert(fmin(3, 1) == 1)
+ assert(fmin(-1, 3) == -1)
+ assert(fmin(3, -1) == -1)
+ assert(fmin(-1, -3) == -3)
+ assert(fmin(-3, -1) == -3)
+ assert(fmax(1, 3) == 3)
+ assert(fmax(3, 1) == 3)
+ assert(fmax(-1, 3) == 3)
+ assert(fmax(3, -1) == 3)
+ assert(fmax(-1, -3) == -1)
+ assert(fmax(-3, -1) == -1)
+end
+
diff --git a/test/LuaJIT-tests/misc/for_dir.lua b/test/LuaJIT-tests/misc/for_dir.lua
new file mode 100644
index 0000000..4dd38de
--- /dev/null
+++ b/test/LuaJIT-tests/misc/for_dir.lua
@@ -0,0 +1,13 @@
+
+local a,b,c = 10,1,-1
+for i=1,20 do
+ if c == -1 then
+ a,b,c = 1,10,1
+ else
+ a,b,c = 10,1,-1
+ end
+ local x = 0
+ for i=a,b,c do for j=1,10 do end x=x+1 end
+ assert(x == 10)
+end
+
diff --git a/test/LuaJIT-tests/misc/fori_coerce.lua b/test/LuaJIT-tests/misc/fori_coerce.lua
new file mode 100644
index 0000000..7330943
--- /dev/null
+++ b/test/LuaJIT-tests/misc/fori_coerce.lua
@@ -0,0 +1,33 @@
+
+do
+ local n = 1
+ local x = 0
+ for i=1,20 do
+ for j=n,100 do x = x + 1 end
+ if i == 13 then n = "2" end
+ end
+ assert(x == 1993)
+end
+
+do
+ local n = 1
+ local x = 0
+ for i=1,20 do
+ for j=n,100 do x = x + 1 end
+ if i == 10 then n = "2" end
+ end
+ assert(x == 1990)
+end
+
+do
+ local function f()
+ local n = 1
+ local x = 0
+ for i=1,20 do
+ for j=n,100 do x = x + 1 end
+ if i == 10 then n = "x" end
+ end
+ end
+ assert(not pcall(f))
+end
+
diff --git a/test/LuaJIT-tests/misc/gc_rechain.lua b/test/LuaJIT-tests/misc/gc_rechain.lua
new file mode 100644
index 0000000..285f408
--- /dev/null
+++ b/test/LuaJIT-tests/misc/gc_rechain.lua
@@ -0,0 +1,32 @@
+
+do
+ local k
+
+ collectgarbage()
+
+ local t = {}
+ t.ac = 1
+
+ t.nn = 1
+ t.mm = 1
+ t.nn = nil
+ t.mm = nil
+
+ k = "a".."i"
+ t[k] = 2
+
+ t.ad = 3
+
+ t[k] = nil
+ k = nil
+
+ collectgarbage()
+
+ k = "a".."f"
+ t[k] = 4
+
+ t.ak = 5
+
+ assert(t[k] == 4)
+end
+
diff --git a/test/LuaJIT-tests/misc/gc_trace.lua b/test/LuaJIT-tests/misc/gc_trace.lua
new file mode 100644
index 0000000..bc38ce0
--- /dev/null
+++ b/test/LuaJIT-tests/misc/gc_trace.lua
@@ -0,0 +1,37 @@
+
+if not jit or not jit.status or not jit.status() then return end
+
+collectgarbage()
+for j=1,100 do
+ loadstring("for i=1,100 do end")()
+end
+local jutil = require("jit.util")
+assert(jutil.traceinfo(90) == nil)
+collectgarbage()
+assert(jutil.traceinfo(1) == nil)
+assert(jutil.traceinfo(2) == nil)
+assert(jutil.traceinfo(3) == nil)
+
+do
+ local f
+ local function reccb(tr)
+ if f == nil then
+ collectgarbage()
+ local info = jutil.traceinfo(tr)
+ jutil.tracek(tr, -info.nk)
+ -- Error in lj_ir_kvalue() if KGC not marked.
+ -- Only caught with assertions or Valgrind.
+ end
+ end
+ jit.attach(reccb, "record")
+ for i=1,200 do
+ if i % 5 == 0 then
+ f = function() end
+ elseif f then
+ f()
+ f = nil
+ end
+ end
+ jit.attach(reccb)
+end
+
diff --git a/test/LuaJIT-tests/misc/gcstep.lua b/test/LuaJIT-tests/misc/gcstep.lua
new file mode 100644
index 0000000..533356b
--- /dev/null
+++ b/test/LuaJIT-tests/misc/gcstep.lua
@@ -0,0 +1,33 @@
+
+local function testgc(what, func)
+ collectgarbage()
+ local oc = gcinfo()
+ func()
+ local nc = gcinfo()
+ assert(nc < oc*4, "GC step missing for "..what)
+end
+
+testgc("TNEW", function()
+ for i=1,10000 do
+ local t = {}
+ end
+end)
+
+testgc("TDUP", function()
+ for i=1,10000 do
+ local t = {1}
+ end
+end)
+
+testgc("FNEW", function()
+ for i=1,10000 do
+ local function f() end
+ end
+end)
+
+testgc("CAT", function()
+ for i=1,10000 do
+ local s = "x"..i
+ end
+end)
+
diff --git a/test/LuaJIT-tests/misc/hook_active.lua b/test/LuaJIT-tests/misc/hook_active.lua
new file mode 100644
index 0000000..37dfc37
--- /dev/null
+++ b/test/LuaJIT-tests/misc/hook_active.lua
@@ -0,0 +1,95 @@
+local ctest = require("ctest")
+
+local called = 0
+local function clearhook() debug.sethook(nil, "", 0) end
+
+-- Return from pcall with active hook must prepend true. FF pcall.
+called = 0
+debug.sethook(function() called=called+1; assert(pcall(function() end) == true); clearhook() end, "", 1)
+do local x = 1 end
+assert(called == 1)
+
+-- Hook with special caught error must not unblock hooks. FF pcall.
+called = 0
+debug.sethook(function() called=called+1; pcall(nil); clearhook() end, "", 1)
+do local x = 1 end
+assert(called == 1)
+
+-- Hook with caught error must not unblock hooks. FF pcall.
+called = 0
+local function p2() error("") end
+debug.sethook(function() called=called+1; pcall(p2); clearhook() end, "", 1)
+do local x = 1 end
+assert(called == 1)
+
+-- Hook with special caught error must not unblock hooks. C pcall.
+called = 0
+debug.sethook(function() called=called+1; ctest.pcall(nil); clearhook() end, "", 1)
+do local x = 1 end
+assert(called == 1)
+
+-- Hook with caught error must not unblock hooks. C pcall
+called = 0
+local function p2() error("") end
+debug.sethook(function() called=called+1; ctest.pcall(p2); clearhook() end, "", 1)
+do local x = 1 end
+assert(called == 1)
+
+-- Regular pcall must not block hooks.
+debug.sethook(function() called=called+1 end, "", 1)
+pcall(function() end)
+called = 0
+do local x = 1 end
+assert(called > 0)
+pcall(function() error("") end)
+called = 0
+do local x = 1 end
+assert(called > 0)
+ctest.pcall(function() end)
+called = 0
+do local x = 1 end
+assert(called > 0)
+ctest.pcall(function() error("") end)
+called = 0
+do local x = 1 end
+assert(called > 0)
+clearhook()
+
+-- Hook with uncaught error must unblock hooks. FF pcall
+called = 0
+pcall(function()
+ debug.sethook(function()
+ local old = called
+ called = 1
+ if old == 0 then error("") end
+ end, "", 1)
+ do local x = 1 end
+end)
+assert(called == 1)
+called = 2
+do local x = 1 end
+assert(called == 1, "hook not unblocked after uncaught error")
+clearhook()
+called = 2
+do local x = 1 end
+assert(called == 2)
+
+-- Hook with uncaught error must unblock hooks. C pcall
+called = 0
+ctest.pcall(function()
+ debug.sethook(function()
+ local old = called
+ called = 1
+ if old == 0 then error("") end
+ end, "", 1)
+ do local x = 1 end
+end)
+assert(called == 1)
+called = 2
+do local x = 1 end
+assert(called == 1, "hook not unblocked after uncaught error")
+clearhook()
+called = 2
+do local x = 1 end
+assert(called == 2)
+
diff --git a/test/LuaJIT-tests/misc/hook_line.lua b/test/LuaJIT-tests/misc/hook_line.lua
new file mode 100644
index 0000000..36f7108
--- /dev/null
+++ b/test/LuaJIT-tests/misc/hook_line.lua
@@ -0,0 +1,41 @@
+local lines = {}
+local function hook()
+ lines[#lines+1] = debug.getinfo(2).currentline
+end
+
+local function dummy()
+end -- <-- line 7
+
+debug.sethook(hook, "l", 0)
+-- <-- line 10
+local x
+dummy()
+local y = 1
+dummy() dummy()
+local z = 2; local r = true
+while y < 4 do y = y + 1 end
+while z < 4 do
+ z = z + 1
+end
+-- <-- line 20
+local v
+debug.sethook(nil, "", 0)
+
+assert(#lines > 0)
+while lines[1] < 10 do table.remove(lines, 1) end
+while lines[#lines] > 20 do table.remove(lines) end
+
+local s = table.concat(lines, " ")
+assert(s == "11 12 7 13 14 7 7 15 16 16 16 16 17 18 17 18 17" or
+ s == "11 12 7 13 14 7 14 7 15 16 16 16 16 17 18 17 18 17")
+
+lines = {}
+local function f()
+ if true then return end
+ local function x() end
+end -- <-- line 36
+debug.sethook(hook, "l", 0)
+f()
+debug.sethook(nil, "", 0)
+for i=1,#lines do assert(lines[i] ~= 36) end
+
diff --git a/test/LuaJIT-tests/misc/hook_norecord.lua b/test/LuaJIT-tests/misc/hook_norecord.lua
new file mode 100644
index 0000000..8e7cba0
--- /dev/null
+++ b/test/LuaJIT-tests/misc/hook_norecord.lua
@@ -0,0 +1,12 @@
+
+if not jit or not jit.status or not jit.status() then return end
+
+local called = false
+local function f() local x = "wrong"; called = true end
+jit.off(f)
+debug.sethook(f, "", 5)
+for i=1,1000 do local a,b,c,d,e,f=1,2,3,4,5,6 end
+assert(called)
+-- Check that no trace was generated.
+assert(require("jit.util").traceinfo(1) == nil)
+
diff --git a/test/LuaJIT-tests/misc/hook_record.lua b/test/LuaJIT-tests/misc/hook_record.lua
new file mode 100644
index 0000000..6f1646d
--- /dev/null
+++ b/test/LuaJIT-tests/misc/hook_record.lua
@@ -0,0 +1,8 @@
+
+if not jit or not jit.status or not jit.status() then return end
+
+debug.sethook(function() for i=1,100 do end end, "", 10)
+for i=1,10 do end
+debug.sethook()
+assert((require("jit.util").traceinfo(1)))
+
diff --git a/test/LuaJIT-tests/misc/hook_top.lua b/test/LuaJIT-tests/misc/hook_top.lua
new file mode 100644
index 0000000..f809fce
--- /dev/null
+++ b/test/LuaJIT-tests/misc/hook_top.lua
@@ -0,0 +1,55 @@
+
+local t = {}
+for i=1,26 do t[i] = string.char(96+i) end
+
+local function tcheck(t1, t2)
+ assert(#t1 == #t2)
+ for i=1,#t1 do assert(t1[i] == t2[i]) end
+end
+
+local function foo1(...) -- VARG RETM
+ return ...
+end
+
+local function foo2(...) -- VARG UCLO RETM
+ local function dummy() end
+ return ...
+end
+
+local function foo3(...) -- VARG UCLO -> RETM
+ do return ... end
+ local function dummy() end
+end
+
+local function foo4() -- UCLO UCLO RET
+ do
+ local x
+ local function dummy() return x end
+ end
+end
+
+called = false
+debug.sethook(function() local x = "wrong"; called = true end, "", 1)
+tcheck(t, {foo1(unpack(t))}) -- CALLM TSETM
+assert(called)
+called = false
+tcheck(t, {foo2(unpack(t))})
+assert(called)
+called = false
+tcheck(t, {foo2(unpack(t))})
+assert(called)
+called = false
+foo4()
+assert(called)
+
+debug.sethook(function()
+ local name, val = debug.getlocal(2, 1)
+ assert(name == "a" and val == nil)
+ debug.setlocal(2, 1, "bar")
+ debug.sethook(nil)
+end, "c")
+local function foo5(a)
+ assert(a == "bar")
+end
+foo5()
+
diff --git a/test/LuaJIT-tests/misc/jit_flush.lua b/test/LuaJIT-tests/misc/jit_flush.lua
new file mode 100644
index 0000000..ead1e4e
--- /dev/null
+++ b/test/LuaJIT-tests/misc/jit_flush.lua
@@ -0,0 +1,50 @@
+
+if not jit or not jit.status or not jit.status() then return end
+
+for i=1,100 do
+ if i==50 then jit.flush(2) end
+ for j=1,100 do end
+ for j=1,100 do end
+end
+
+jit.flush()
+
+local function f() for i=1,100 do end end
+for i=1,100 do local x = gcinfo(); f() end
+
+jit.flush()
+
+local function fib(n)
+ if n < 2 then return 1 end
+ return fib(n-2) + fib(n-1)
+end
+
+fib(11)
+
+jit.flush()
+
+local names = {}
+for i=1,100 do names[i] = i end
+
+function f()
+ for k,v in ipairs(names) do end
+end
+
+f()
+
+for i=1,2 do
+ f()
+ f()
+ jit.flush()
+end
+
+jit.flush()
+
+jit.flush(1) -- ignored
+jit.flush(2) -- ignored
+for i=1,1e7 do end -- causes trace #1
+
+jit.flush(2) -- ignored
+jit.flush(1) -- ok
+jit.flush(1) -- crashes
+
diff --git a/test/LuaJIT-tests/misc/lightud.lua b/test/LuaJIT-tests/misc/lightud.lua
new file mode 100644
index 0000000..4974d50
--- /dev/null
+++ b/test/LuaJIT-tests/misc/lightud.lua
@@ -0,0 +1,88 @@
+local ctest = require("ctest")
+
+local lightud = ctest.lightud
+local assert = assert
+
+-- x64 lightud tests
+if jit and jit.arch == "x64" then
+ do
+ local ud1 = lightud(0x12345678)
+ local ud2 = lightud(0x12345678)
+ assert(ud1 == ud2)
+ assert(tostring(ud1) == "userdata: 0x12345678")
+ end
+ do
+ local ud1 = lightud(1)
+ local ud2 = lightud(2)
+ assert(ud1 ~= ud2)
+ end
+ do
+ local ud1 = lightud(2^47-1)
+ local ud2 = lightud(2^47-1)
+ assert(ud1 == ud2)
+ assert(tostring(ud1) == "userdata: 0x7fffffffffff")
+ end
+ do
+ local ud1 = lightud(0x12345678+123*2^32)
+ local ud2 = lightud(0x12345678+456*2^32)
+ for i=1,100 do assert(ud1 ~= ud2) end
+ end
+ assert(tostring(lightud(0x5abc*2^32 + 0xdef01234)) == "userdata: 0x5abcdef01234")
+ assert(pcall(lightud, 2^47) == false)
+ assert(pcall(lightud, 2^64-2048) == false)
+end
+
+assert(getmetatable(lightud(1)) == nil)
+
+-- lightuserdata SLOAD value and HREF key
+do
+ local ud = lightud(12345)
+ local t = {[ud] = 42}
+ for i=1,100 do
+ assert(t[ud] == 42)
+ end
+end
+
+-- lightuserdata NEWREF key
+do
+ local ud = lightud(12345)
+ for i=1,100 do
+ local t = {[ud] = 42}
+ assert(t[ud] == 42)
+ end
+end
+
+-- lightuserdata ASTORE/HSTORE value
+do
+ local ud = lightud(12345)
+ local t = {}
+ for i=1,100 do
+ t[i] = ud
+ end
+ assert(t[100] == ud)
+end
+
+-- lightuserdata sync to stack
+do
+ local ud = lightud(12345)
+ local x = nil
+ for j=1,20 do
+ for i=1,50 do
+ x = ud
+ end
+ assert(x == ud)
+ end
+end
+
+-- lightuserdata vs. number type check
+do
+ local t = {}
+ for i=1,200 do t[i] = i end
+ t[180] = lightud(12345)
+ local x = 0
+ assert(not pcall(function(t)
+ for i=1,200 do x = x + t[i] end
+ end, t))
+ assert(x == 16110)
+end
+
diff --git a/test/LuaJIT-tests/misc/loop_unroll.lua b/test/LuaJIT-tests/misc/loop_unroll.lua
new file mode 100644
index 0000000..1700fac
--- /dev/null
+++ b/test/LuaJIT-tests/misc/loop_unroll.lua
@@ -0,0 +1,35 @@
+
+-- type instability on loop unroll -> record unroll
+do
+ local flip = true
+ for i=1,100 do flip = not flip end
+ assert(flip == true)
+end
+
+do
+ local t = {}
+ local a, b, c = 1, "", t
+ for i=1,100 do a,b,c=b,c,a end
+ assert(c == 1 and a == "" and b == t)
+end
+
+-- FAILFOLD on loop unroll -> LJ_TRERR_GFAIL -> record unroll
+do
+ local t = { 1, 2 }
+ local k = 2
+ local x = 0
+ for i=1,200 do
+ x = x + t[k]
+ k = k == 1 and 2 or 1
+ end
+ assert(x == 300 and k == 2)
+end
+
+-- Unroll if inner loop aborts.
+local j = 0
+for i = 1,100 do
+ repeat
+ j = j+1
+ until true
+end
+
diff --git a/test/LuaJIT-tests/misc/parse_comp.lua b/test/LuaJIT-tests/misc/parse_comp.lua
new file mode 100644
index 0000000..5e1948d
--- /dev/null
+++ b/test/LuaJIT-tests/misc/parse_comp.lua
@@ -0,0 +1,13 @@
+
+do
+ local f = {{n=5}}
+ local a = f[1].n
+ assert(1 < a)
+ assert(1 < (f[1].n))
+ assert(1 < f[1].n)
+end
+
+do
+ tt = { a = 1 }
+ assert(not(0 >= tt.a))
+end
diff --git a/test/LuaJIT-tests/misc/parse_esc.lua b/test/LuaJIT-tests/misc/parse_esc.lua
new file mode 100644
index 0000000..4bcce0e
--- /dev/null
+++ b/test/LuaJIT-tests/misc/parse_esc.lua
@@ -0,0 +1,7 @@
+assert("\79\126" == "O~")
+assert("\x4f\x7e" == "O~")
+assert(loadstring[[return "\xxx"]] == nil)
+assert(loadstring[[return "\xxx"]] == nil)
+assert(assert(loadstring[[return "abc \z
+
+ def"]])() == "abc def")
diff --git a/test/LuaJIT-tests/misc/parse_misc.lua b/test/LuaJIT-tests/misc/parse_misc.lua
new file mode 100644
index 0000000..8031ec1
--- /dev/null
+++ b/test/LuaJIT-tests/misc/parse_misc.lua
@@ -0,0 +1,31 @@
+
+-- Ambiguous syntax: function call vs. new statement.
+if os.getenv("LUA52") then
+ assert(assert(loadstring([[
+local function f() return 99 end
+return f
+()
+]]))() == 99)
+else
+ assert(loadstring([[
+local function f() return 99 end
+return f
+()
+]]) == nil)
+end
+
+-- UTF-8 identifiers.
+assert(loadstring([[
+local ä = 1
+local aäa = 2
+local äöü·€晶 = 3
+
+assert(ä == 1)
+assert(aäa == 2)
+assert(äöü·€晶 == 3)
+
+assert(#"ä" == 2)
+assert(#"aäa" == 4)
+assert(#"äöü·€晶" == 14)
+]]))()
+
diff --git a/test/LuaJIT-tests/misc/phi_conv.lua b/test/LuaJIT-tests/misc/phi_conv.lua
new file mode 100644
index 0000000..8d7bea5
--- /dev/null
+++ b/test/LuaJIT-tests/misc/phi_conv.lua
@@ -0,0 +1,53 @@
+
+local bit = require("bit")
+
+local Rm = {}
+for i=0,16 do Rm[i] = 0 end
+
+for k=1,10 do
+ local seed = 1
+ for i=16,0,-1 do
+ seed = bit.band(seed*9069, 0x7fffffff)
+ Rm[i] = seed
+ end
+ assert(seed == 1952688301)
+end
+
+local retindex = 0
+local retdata = { 3, 1, 1, 1, 0, 3, 1, 0, 0, 2, 0, 2, 0, 0, 3, 1, 1, 1, 1 }
+
+local function get_bits()
+ retindex = retindex + 1
+ return retdata[retindex]
+end
+
+local hufcodes = { [0] = true, [4] = true, [11] = true, [36] = true, [68] = true }
+
+local maskhuf = { 0x0002, 0x0003, 0x0004, 0x0005, }
+
+local function decodeCode()
+ local lookup = get_bits()
+ local code = hufcodes[lookup]
+ local z = {1,1,1,1}
+ if not code then
+ for i = 1, 4 do
+ lookup = bit.bor(lookup, bit.lshift(get_bits(), i + 1))
+ -- need PHI for CONV num.int of lookup, used in snapshot
+ code = hufcodes[lookup + maskhuf[i]]
+ if code then break end
+ end
+ end
+ assert(code)
+ return code
+end
+
+local function test()
+ for i = 1, 6 do
+ decodeCode()
+ end
+end
+
+if jit and jit.status and jit.status() then jit.opt.start("hotloop=1") end
+
+test()
+
diff --git a/test/LuaJIT-tests/misc/recurse_deep.lua b/test/LuaJIT-tests/misc/recurse_deep.lua
new file mode 100644
index 0000000..9b9af29
--- /dev/null
+++ b/test/LuaJIT-tests/misc/recurse_deep.lua
@@ -0,0 +1,29 @@
+
+do
+ local function sum(n)
+ if n == 1 then return 1 end
+ return n + sum(n-1)
+ end
+ assert(sum(200) == 20100)
+end
+
+do
+ local pcall = pcall
+ local tr1
+ local x = 0
+ function tr1(n)
+ if n <= 0 then return end
+ x = x + 1
+ return pcall(tr1, n-1)
+ end
+ assert(tr1(200) == true and x == 200)
+end
+
+do
+ local function fib(n)
+ if n < 2 then return 1 end
+ return fib(n-2) + fib(n-1)
+ end
+ assert(fib(15) == 987)
+end
+
diff --git a/test/LuaJIT-tests/misc/recurse_tail.lua b/test/LuaJIT-tests/misc/recurse_tail.lua
new file mode 100644
index 0000000..ef76443
--- /dev/null
+++ b/test/LuaJIT-tests/misc/recurse_tail.lua
@@ -0,0 +1,22 @@
+
+do
+ local tr1
+ function tr1(n)
+ if n <= 0 then return 0 end
+ return tr1(n-1)
+ end
+ assert(tr1(200) == 0)
+end
+
+do
+ local tr1, tr2
+ function tr1(n)
+ if n <= 0 then return 0 end
+ return tr2(n-1)
+ end
+ function tr2(n)
+ return tr1(n)
+ end
+ assert(tr2(200) == 0)
+end
+
diff --git a/test/LuaJIT-tests/misc/stack_gc.lua b/test/LuaJIT-tests/misc/stack_gc.lua
new file mode 100644
index 0000000..656a06a
--- /dev/null
+++ b/test/LuaJIT-tests/misc/stack_gc.lua
@@ -0,0 +1,15 @@
+
+do
+ local t = setmetatable({}, { __index=function(t, k)
+ k = k - 1
+ if k == 0 then
+ collectgarbage() -- Mark stack, including holes.
+ return 0
+ else
+ return t[k] -- Leaves holes in each frame.
+ end
+ do local a,b,c,d,e,f,g,h,i,j,k,l,m,n end -- Ensure bigger frame size.
+ end})
+ local x = t[50]
+end
+
diff --git a/test/LuaJIT-tests/misc/stack_purge.lua b/test/LuaJIT-tests/misc/stack_purge.lua
new file mode 100644
index 0000000..bfaee0f
--- /dev/null
+++ b/test/LuaJIT-tests/misc/stack_purge.lua
@@ -0,0 +1,25 @@
+
+-- Must preserve the modified function slot in the RET snapshot.
+local function a()
+ local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_
+ local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_
+ local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_
+ return 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+end
+
+local function b()
+ return a()
+end
+
+local function c()
+ for j=1,10 do
+ for i=1,50 do b() b() b() end
+ collectgarbage()
+ local t = {}
+ for i=1,50 do t = {t} end
+ end
+end
+
+jit.off(c)
+c()
+
diff --git a/test/LuaJIT-tests/misc/stackov.lua b/test/LuaJIT-tests/misc/stackov.lua
new file mode 100644
index 0000000..ef105af
--- /dev/null
+++ b/test/LuaJIT-tests/misc/stackov.lua
@@ -0,0 +1,40 @@
+
+local function f()
+ f()
+end
+
+local err, s = xpcall(f, debug.traceback)
+assert(err == false)
+
+local first = string.match(s, "[^\n]+")
+local line = debug.getinfo(f, "S").linedefined+1
+assert(string.match(first, ":"..line..": stack overflow$"))
+
+local n = 1
+for _ in string.gmatch(s, "\n") do n = n + 1 end
+assert(n == 1+1+11+1+10)
+
+local function g(i)
+ g(i)
+end
+
+local err, s = xpcall(g, debug.traceback, 1)
+assert(err == false)
+
+--[[
+-- too slow
+local function vtail(...)
+ return vtail(1, ...)
+end
+
+local err, s = xpcall(vtail, debug.traceback, 1)
+assert(err == false)
+--]]
+
+local function vcall(...)
+ vcall(1, ...)
+end
+
+local err, s = xpcall(vcall, debug.traceback, 1)
+assert(err == false)
+
diff --git a/test/LuaJIT-tests/misc/stackovc.lua b/test/LuaJIT-tests/misc/stackovc.lua
new file mode 100644
index 0000000..c00bcbd
--- /dev/null
+++ b/test/LuaJIT-tests/misc/stackovc.lua
@@ -0,0 +1,4 @@
+local j = 1e4
+local co = coroutine.create(function() t = {} for i = 1, j do t[i] = i end return unpack(t) end)
+local ok, err = coroutine.resume(co)
+assert(not ok and string.find(err, "unpack"))
diff --git a/test/LuaJIT-tests/misc/tcall_base.lua b/test/LuaJIT-tests/misc/tcall_base.lua
new file mode 100644
index 0000000..c6c4ae1
--- /dev/null
+++ b/test/LuaJIT-tests/misc/tcall_base.lua
@@ -0,0 +1,20 @@
+
+local r = 0
+local function g()
+ r = r + 1
+ for i=1,100 do end
+end
+
+local function f()
+ for j=1,20 do
+ if j > 19 then
+ return g() -- Tailcall at base.
+ -- Let this link to the already compiled loop in g().
+ end
+ end
+end
+
+g() -- Compile this loop first.
+for i=1,50 do f() end
+assert(r == 51)
+
diff --git a/test/LuaJIT-tests/misc/tcall_loop.lua b/test/LuaJIT-tests/misc/tcall_loop.lua
new file mode 100644
index 0000000..d3c6f1a
--- /dev/null
+++ b/test/LuaJIT-tests/misc/tcall_loop.lua
@@ -0,0 +1,8 @@
+local function f(i)
+ if i > 0 then return f(i-1) end
+ return 1
+end
+
+local x = 0
+for i=1,100 do x = x + f(1000) end
+assert(x == 100)
diff --git a/test/LuaJIT-tests/misc/tonumber_scan.lua b/test/LuaJIT-tests/misc/tonumber_scan.lua
new file mode 100644
index 0000000..78e1ca3
--- /dev/null
+++ b/test/LuaJIT-tests/misc/tonumber_scan.lua
@@ -0,0 +1,180 @@
+local ffi = require("ffi")
+local bit = require("bit")
+
+ffi.cdef[[
+double strtod(const char *, char **);
+]]
+
+local t = {
+ -- errors
+ false, "",
+ false, " ",
+ false, "+",
+ false, "z",
+ false, ".",
+ false, ".z",
+ false, "0.z",
+ false, ".0z",
+ false, "0xz",
+ false, "0x.z",
+ false, "0x0.z",
+ false, "0x.0z",
+ false, ".e5",
+ false, ".p4",
+ false, "1.p4",
+ false, "1.p+4",
+ false, "0x1.e+4",
+ false, "infi",
+ false, "+ 1",
+ false, "- 9",
+ -- misc
+ 0x3ff0000000000000ULL, " \t\n\v\f\r 1",
+ -- inf/nan
+ 0x7ff0000000000000ULL, "iNF",
+ 0xfff0000000000000ULL, "-Inf",
+ 0x7ff0000000000000ULL, "+iNfInItY",
+ 0xfff0000000000000ULL, "-INFINITY",
+ 0xfff8000000000000ULL, "naN",
+ 0xfff8000000000000ULL, "+NaN",
+ 0xfff8000000000000ULL, "-nAn",
+ -- smallest/largest numbers
+ 0x0000000000000000ULL, "0e1000",
+ 0x0000000000000000ULL, "0e-1000",
+ 0x0000000000000000ULL, "0x0p2000",
+ 0x0000000000000000ULL, "0x0p-2000",
+ 0x7ff0000000000000ULL, "1e1000",
+ 0x0000000000000000ULL, "1e-1000",
+ 0xfff0000000000000ULL, "-1e1000",
+-- wrong for DUALNUM: 0x8000000000000000ULL, "-1e-1000",
+ 0x7ff0000000000000ULL, "0x1p2000",
+ 0x0000000000000000ULL, "0x1p-2000",
+ 0xfff0000000000000ULL, "-0x1p2000",
+-- wrong for DUALNUM: 0x8000000000000000ULL, "-0x1p-2000",
+ 0x0010000000000000ULL, "2.2250738585072014e-308",
+ 0x7fefffffffffffffULL, "1.7976931348623158e+308",
+ 0x8000b8157268fdafULL, "-1e-309",
+ 0x000ac941b426dd3bULL, "1.5e-308",
+ 0x000ac941b426dd3bULL, "0x0.ac941b426dd3b7p-1022",
+ 0x0000000000000001ULL, "4.9406564584124654e-324",
+ 0x000f9c7573d7fe52ULL, "2.171e-308",
+ 0x241d21ecf36d4a22ULL, "1.0020284025808569e-134",
+ 0x0000000000000001ULL, "0x1p-1074",
+ 0x0000000000000000ULL, "0x1p-1075",
+ 0x0000000000000000ULL, "0x1p-1076",
+ 0x0000000000000000ULL, "0x0.ffffffffffffffffffffffffffp-1075",
+ 0x0000000000000000ULL, "0x1.00000000000000000000000000p-1075",
+ 0x0000000000000001ULL, "0x1.00000000000000000000000001p-1075",
+ 0x7fe0000000000000ULL, "0x1p1023",
+ 0x7ff0000000000000ULL, "0x1p1024",
+ 0x7ff0000000000000ULL, "0x1p1025",
+ 0x7ff0000000000000ULL, "0x3p1023",
+ 0x7ff0000000000000ULL, "0x3.ffffffffffffecp1023",
+ 0xfff0000000000000ULL, "-0xf7dcba98765432p969",
+ 0x7fefffffffffffffULL, "0x1.fffffffffffff0000000000000p1023",
+ 0x7fefffffffffffffULL, "0x1.fffffffffffff0000000000001p1023",
+ 0x7fefffffffffffffULL, "0x1.fffffffffffff7ffffffffffffp1023",
+ 0x7ff0000000000000ULL, "0x1.fffffffffffff8000000000000p1023",
+ 0x7fefffffffffffffULL, "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.0",
+ 0x7fefffffffffffffULL, "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497791.999",
+ 0x7ff0000000000000ULL, "179769313486231580793728971405303415079934132710037826936173778980444968292764750946649017977587207096330286416692887910946555547851940402630657488671505820681908902000708383676273854845817711531764475730270069855571366959622842914819860834936475292719074168444365510704342711559699508093042880177904174497792.0",
+ 0x3ff0000000000000ULL, "0x100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000p-1028",
+ 0x1214e2995454ee0bULL, "0."..string.rep("0", 220).."1"..string.rep("4", 800),
+ -- http://www.exploringbinary.com/15-digit-quick-and-dirty-conversions-dont-round-trip/
+ 0x04409cf3929ffbc3ULL, "3.409452297963e-288",
+ 0x7fe02b4782a6c378ULL, "9.08344e+307",
+ 0x6e05e258a3929ee5ULL, "9.88819e+221",
+ -- http://www.exploringbinary.com/incorrectly-rounded-conversions-in-gcc-and-glibc/
+ 0x3fe0000000000002ULL, "0.500000000000000166533453693773481063544750213623046875",
+ 0x42c0000000000002ULL, "3.518437208883201171875e13",
+ 0x404f44abd5aa7ca4ULL, "62.5364939768271845828",
+ 0x3e0bd5cbaef0fd0cULL, "8.10109172351e-10",
+ 0x3ff8000000000000ULL, "1.50000000000000011102230246251565404236316680908203125",
+ 0x433fffffffffffffULL, "9007199254740991.4999999999999999999999999999999995",
+ 0x7ecd2e77eb6e3fadULL, "6.253649397682718e+302",
+ 0x7ecd2e77eb6e3fadULL, "6.2536493976827180e+302",
+ -- http://www.exploringbinary.com/incorrectly-rounded-conversions-in-visual-c-plus-plus/
+ 0x43405e6cec57761aULL, "9214843084008499",
+ 0x3fe0000000000002ULL, "0.500000000000000166533453693773481063544750213623046875",
+ 0x44997a3c7271b021ULL, "30078505129381147446200",
+ 0x4458180d5bad2e3eULL, "1777820000000000000001",
+ 0x3fe0000000000002ULL, "0.500000000000000166547006220929549868969843373633921146392822265625",
+ 0x3fe0000000000002ULL, "0.50000000000000016656055874808561867439493653364479541778564453125",
+ 0x3fd92bb352c4623aULL, "0.3932922657273",
+ -- http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+ 0x0010000000000000ULL, "2.2250738585072012e-308",
+ -- http://www.exploringbinary.com/incorrectly-rounded-subnormal-conversions-in-java/
+ 0x0000000008000000ULL, "6.631236871469758276785396630275967243399099947355303144249971758736286630139265439618068200788048744105960420552601852889715006376325666595539603330361800519107591783233358492337208057849499360899425128640718856616503093444922854759159988160304439909868291973931426625698663157749836252274523485312442358651207051292453083278116143932569727918709786004497872322193856150225415211997283078496319412124640111777216148110752815101775295719811974338451936095907419622417538473679495148632480391435931767981122396703443803335529756003353209830071832230689201383015598792184172909927924176339315507402234836120730914783168400715462440053817592702766213559042115986763819482654128770595766806872783349146967171293949598850675682115696218943412532098591327667236328125e-316",
+ 0x0000000000010000ULL, "3.237883913302901289588352412501532174863037669423108059901297049552301970670676565786835742587799557860615776559838283435514391084153169252689190564396459577394618038928365305143463955100356696665629202017331344031730044369360205258345803431471660032699580731300954848363975548690010751530018881758184174569652173110473696022749934638425380623369774736560008997404060967498028389191878963968575439222206416981462690113342524002724385941651051293552601421155333430225237291523843322331326138431477823591142408800030775170625915670728657003151953664260769822494937951845801530895238439819708403389937873241463484205608000027270531106827387907791444918534771598750162812548862768493201518991668028251730299953143924168545708663913273994694463908672332763671875e-319",
+ 0x0000800000000100ULL, "6.953355807847677105972805215521891690222119817145950754416205607980030131549636688806115726399441880065386399864028691275539539414652831584795668560082999889551357784961446896042113198284213107935110217162654939802416034676213829409720583759540476786936413816541621287843248433202369209916612249676005573022703244799714622116542188837770376022371172079559125853382801396219552418839469770514904192657627060319372847562301074140442660237844114174497210955449896389180395827191602886654488182452409583981389442783377001505462015745017848754574668342161759496661766020028752888783387074850773192997102997936619876226688096314989645766000479009083731736585750335262099860150896718774401964796827166283225641992040747894382698751809812609536720628966577351093292236328125e-310",
+ 0x0000000000010800ULL, "3.339068557571188581835713701280943911923401916998521771655656997328440314559615318168849149074662609099998113009465566426808170378434065722991659642619467706034884424989741080790766778456332168200464651593995817371782125010668346652995912233993254584461125868481633343674905074271064409763090708017856584019776878812425312008812326260363035474811532236853359905334625575404216060622858633280744301892470300555678734689978476870369853549413277156622170245846166991655321535529623870646888786637528995592800436177901746286272273374471701452991433047257863864601424252024791567368195056077320885329384322332391564645264143400798619665040608077549162173963649264049738362290606875883456826586710961041737908872035803481241600376705491726170293986797332763671875e-319",
+ -- EGLIBC 2.16 tests
+ 0x4028b0a3d70a3d71ULL, "12.345",
+ 0x441ac4da03bc47e4ULL, "12.345e19",
+ 0xc197d78400000000ULL, "-.1e+9",
+ 0x3fc0000000000000ULL, ".125",
+ 0x4415af1d78b58c40ULL, "1e20",
+ 0x0000000000000000ULL, "0e-19",
+ 0x3051144f2d9a718bULL, "5.9e-76",
+ 0x4024000000000000ULL, "0x1.4p+3",
+ 0x4024000000000000ULL, "0xAp0",
+ 0x4024000000000000ULL, "0x0Ap0",
+ 0x4024000000000000ULL, "0x0A",
+ 0x4064000000000000ULL, "0xA0",
+ 0x4064000000000000ULL, "0x0.A0p8",
+ 0x4064000000000000ULL, "0x0.50p9",
+ 0x4064000000000000ULL, "0x0.28p10",
+ 0x4064000000000000ULL, "0x0.14p11",
+ 0x4064000000000000ULL, "0x0.0A0p12",
+ 0x4064000000000000ULL, "0x0.050p13",
+ 0x4064000000000000ULL, "0x0.028p14",
+ 0x4064000000000000ULL, "0x0.014p15",
+ 0x4064000000000000ULL, "0x00.00A0p16",
+ 0x4064000000000000ULL, "0x00.0050p17",
+ 0x4064000000000000ULL, "0x00.0028p18",
+ 0x4064000000000000ULL, "0x00.0014p19",
+ 0x0008000000000000ULL, "0x1p-1023",
+ 0x0008000000000000ULL, "0x0.8p-1022",
+ 0x3ff0000140000000ULL, "0x80000Ap-23",
+ 0x0000000000000000ULL, "1e-324",
+ 0x4370000000000000ULL, "0x100000000000008p0",
+ 0x4370000000000000ULL, "0x100000000000008.p0",
+ 0x4370000000000000ULL, "0x100000000000008.00p0",
+ 0x43f0000000000000ULL, "0x10000000000000800p0",
+ 0x43f0000000000001ULL, "0x10000000000000801p0",
+ -- Fuzzing
+ 0x699783fbf2d24ea5ULL, "449999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999",
+ 0x43f158e460913d00ULL, "2e19",
+}
+
+local function tohex64(x)
+ return "0x"..bit.tohex(tonumber(x/2LL^32))..bit.tohex(tonumber(x%2LL^32)).."ULL"
+end
+
+local conv = tonumber
+
+if arg and arg[1] == "strtod" then
+ local e = ffi.new("char *[1]")
+ function conv(s)
+ local d = ffi.C.strtod(s, e)
+ return (e[0][0] == 0 and #s ~= 0) and d or nil
+ end
+end
+
+local u = ffi.new("union { double d; uint64_t x; }")
+
+for i=1,#t,2 do
+ local y, s = t[i], t[i+1]
+ local d = conv(s)
+ local ok
+ if d == nil then
+ ok = (y == false)
+ else
+ u.d = d
+ ok = (y == u.x)
+ end
+ if not ok then
+ io.write('FAIL: "', s, '"\n GOT: ', d and tohex64(u.x) or "nil", " OK: ", y and tohex64(y) or "nil", "\n\n")
+-- print(" "..tohex64(u.x)..", \""..s.."\",")
+ end
+end
+
diff --git a/test/LuaJIT-tests/misc/uclo.lua b/test/LuaJIT-tests/misc/uclo.lua
new file mode 100644
index 0000000..bd9bd24
--- /dev/null
+++ b/test/LuaJIT-tests/misc/uclo.lua
@@ -0,0 +1,91 @@
+
+local function test_for()
+ local z1, z2
+ for i=1,10 do
+ local function f() return i end
+ if z1 then z2 = f else z1 = f end
+ end
+ assert(z1() == 1)
+ assert(z2() == 10)
+end
+
+local function test_while()
+ local z1, z2
+ local i = 1
+ while i <= 10 do
+ local j = i
+ local function f() return j end
+ if z1 then z2 = f else z1 = f end
+ i = i + 1
+ end
+ assert(z1() == 1)
+ assert(z2() == 10)
+end
+
+local function test_repeat()
+ local z1, z2
+ local i = 1
+ repeat
+ local j = i
+ local function f() return j end
+ if z1 then z2 = f else z1 = f end
+ i = i + 1
+ until i > 10
+ assert(z1() == 1)
+ assert(z2() == 10)
+end
+
+local function test_func()
+ local function ff(x)
+ return function() return x end
+ end
+ local z1, z2
+ for i=1,10 do
+ local f = ff(i)
+ if z1 then z2 = f else z1 = f end
+ end
+ assert(z1() == 1)
+ assert(z2() == 10)
+end
+
+test_for()
+test_while()
+test_repeat()
+test_func()
+
+do
+ local function f1(a)
+ if a > 0 then
+ local b = f1(a - 1)
+ return function()
+ if type(b) == "function" then
+ return a + b()
+ end
+ return a + b
+ end
+ end
+ return a
+ end
+
+ local function f2(a)
+ return f1(a)()
+ end
+
+ for i = 1, 41 do
+ local r = f2(4) + f2(4)
+ end
+end
+
+-- Don't mark upvalue as immutable if written to after prototype definition.
+do
+ local x = 1
+ local function f()
+ local y = 0
+ for i=1,100 do y=y+x end
+ return y
+ end
+ assert(f() == 100)
+ x = 2
+ assert(f() == 200)
+end
+
diff --git a/test/LuaJIT-tests/misc/unordered_jit.lua b/test/LuaJIT-tests/misc/unordered_jit.lua
new file mode 100644
index 0000000..5ff1a1b
--- /dev/null
+++ b/test/LuaJIT-tests/misc/unordered_jit.lua
@@ -0,0 +1,96 @@
+
+local nan = 0/0
+local t = {}
+for i=1,100 do t[i] = i+0.5 end
+for i=101,200 do t[i] = nan end
+
+do
+ local z = 0
+ for i=1,200 do if t[i] > 1000 then z=i end end
+ assert(z == 0)
+end
+
+do
+ local z = 0
+ for i=1,200 do if not (t[i] < 1000) then z=i end end
+ assert(z == 200)
+end
+
+do
+ local z = 0
+ for i=1,200 do if t[i] <= 1000 then z=i end end
+ assert(z == 100)
+end
+
+do
+ local z = 0
+ for i=1,200 do if not (t[i] >= 1000) then z=i end end
+ assert(z == 200)
+end
+
+do
+ local z = 0
+ for i=1,200 do if t[i] > 0 then z=i end end
+ assert(z == 100)
+end
+
+do
+ local z = 0
+ for i=1,200 do if not (t[i] < 0) then z=i end end
+ assert(z == 200)
+end
+
+do
+ local z = 0
+ for i=1,200 do if t[i] <= 0 then z=i end end
+ assert(z == 0)
+end
+
+do
+ local z = 0
+ for i=1,200 do if not (t[i] >= 0) then z=i end end
+ assert(z == 200)
+end
+
+do local z; for i=1,100 do z = 0/0 end; assert(z ~= z) end
+
+do local z; for i=1,100 do z = nan == nan end; assert(z == false) end
+do local z; for i=1,100 do z = nan == 1 end; assert(z == false) end
+do local z; for i=1,100 do z = 1 == nan end; assert(z == false) end
+
+do local z; for i=1,100 do z = nan ~= nan end; assert(z == true) end
+do local z; for i=1,100 do z = nan ~= 1 end; assert(z == true) end
+do local z; for i=1,100 do z = 1 ~= nan end; assert(z == true) end
+
+do local z; for i=1,100 do z = nan < nan end; assert(z == false) end
+do local z; for i=1,100 do z = nan < 1 end; assert(z == false) end
+do local z; for i=1,100 do z = 1 < nan end; assert(z == false) end
+
+do local z; for i=1,100 do z = not (nan < nan) end; assert(z == true) end
+do local z; for i=1,100 do z = not (nan < 1) end; assert(z == true) end
+do local z; for i=1,100 do z = not (1 < nan) end; assert(z == true) end
+
+do local z; for i=1,100 do z = nan > nan end; assert(z == false) end
+do local z; for i=1,100 do z = nan > 1 end; assert(z == false) end
+do local z; for i=1,100 do z = 1 > nan end; assert(z == false) end
+
+do local z; for i=1,100 do z = not (nan > nan) end; assert(z == true) end
+do local z; for i=1,100 do z = not (nan > 1) end; assert(z == true) end
+do local z; for i=1,100 do z = not (1 > nan) end; assert(z == true) end
+
+do local z; for i=1,100 do z = nan <= nan end; assert(z == false) end
+do local z; for i=1,100 do z = nan <= 1 end; assert(z == false) end
+do local z; for i=1,100 do z = 1 <= nan end; assert(z == false) end
+
+do local z; for i=1,100 do z = not (nan <= nan) end; assert(z == true) end
+do local z; for i=1,100 do z = not (nan <= 1) end; assert(z == true) end
+do local z; for i=1,100 do z = not (1 <= nan) end; assert(z == true) end
+
+do local z; for i=1,100 do z = nan >= nan end; assert(z == false) end
+do local z; for i=1,100 do z = nan >= 1 end; assert(z == false) end
+do local z; for i=1,100 do z = 1 >= nan end; assert(z == false) end
+
+do local z; for i=1,100 do z = not (nan >= nan) end; assert(z == true) end
+do local z; for i=1,100 do z = not (nan >= 1) end; assert(z == true) end
+do local z; for i=1,100 do z = not (1 >= nan) end; assert(z == true) end
+
diff --git a/test/LuaJIT-tests/misc/wbarrier.lua b/test/LuaJIT-tests/misc/wbarrier.lua
new file mode 100644
index 0000000..5536625
--- /dev/null
+++ b/test/LuaJIT-tests/misc/wbarrier.lua
@@ -0,0 +1,7 @@
+local t={}
+for i=1,20000 do
+ t[i] = tostring(i)
+end
+for i=1,#t do
+ assert(t[i] == tostring(i))
+end
diff --git a/test/LuaJIT-tests/misc/wbarrier_jit.lua b/test/LuaJIT-tests/misc/wbarrier_jit.lua
new file mode 100644
index 0000000..2c8dd7f
--- /dev/null
+++ b/test/LuaJIT-tests/misc/wbarrier_jit.lua
@@ -0,0 +1,18 @@
+
+do
+ local t = {[0]={}}
+ for i=1,1e5 do t[i] = {t[i-1]} end
+ for i=1,1e5 do assert(t[i][1] == t[i-1]) end
+end
+
+do
+ local f
+ do
+ local x = 0
+ function f()
+ for i=1,1e5 do x = {i} end
+ end
+ end
+ f()
+end
+
diff --git a/test/LuaJIT-tests/misc/wbarrier_obar.lua b/test/LuaJIT-tests/misc/wbarrier_obar.lua
new file mode 100644
index 0000000..258db21
--- /dev/null
+++ b/test/LuaJIT-tests/misc/wbarrier_obar.lua
@@ -0,0 +1,22 @@
+-- DSE of USTORE must eliminate OBAR, too.
+
+if jit and jit.opt then pcall(jit.opt.start, "-sink") end
+
+local f
+do
+ local x
+ f = function()
+ local y = 0
+ for i=1,10000 do
+ x = {1}
+ if y > 0 then end
+ x = 1
+ end
+ end
+end
+
+collectgarbage()
+collectgarbage("setstepmul", 1)
+collectgarbage("restart")
+f()
+
diff --git a/test/LuaJIT-tests/opt/dse/array.lua b/test/LuaJIT-tests/opt/dse/array.lua
new file mode 100644
index 0000000..8c76624
--- /dev/null
+++ b/test/LuaJIT-tests/opt/dse/array.lua
@@ -0,0 +1,197 @@
+local assert = assert
+
+-- Same value ----------------------------------------------------------------
+
+do --- 1
+-- Store with same ref and same value.
+-- 2nd store eliminated. All stores in loop eliminated.
+ local t = { 1, 2 }
+ for i=1,100 do
+ t[1] = 11
+ assert(t[1] == 11)
+ t[1] = 11
+ assert(t[1] == 11)
+ end
+ assert(t[1] == 11)
+end
+
+do --- 2
+-- Store with different tab, same idx and same value.
+-- All stores in loop eliminated.
+ local t1 = { 1, 2 }
+ local t2 = { 1, 2 }
+ for i=1,100 do
+ t1[1] = 11
+ assert(t1[1] == 11)
+ t2[1] = 11
+ assert(t2[1] == 11)
+ end
+ assert(t1[1] == 11)
+ assert(t2[1] == 11)
+end
+
+do --- 3
+-- Store with same tab, different const idx and same value.
+-- All stores in loop eliminated. Also disambiguated.
+ local t = { 1, 2 }
+ for i=1,100 do
+ t[1] = 11
+ assert(t[1] == 11)
+ t[2] = 11
+ assert(t[2] == 11)
+ end
+ assert(t[1] == 11)
+ assert(t[2] == 11)
+end
+
+do --- 4
+-- Store with different tab, different const idx and same value.
+-- All stores in loop eliminated. Also disambiguated.
+ local t1 = { 1, 2 }
+ local t2 = { 1, 2 }
+ for i=1,100 do
+ t1[1] = 11
+ assert(t1[1] == 11)
+ t2[2] = 11
+ assert(t2[2] == 11)
+ end
+ assert(t1[1] == 11)
+ assert(t2[2] == 11)
+end
+
+do --- 5
+-- Store with different tab, different non-const idx and same value.
+-- All stores in loop eliminated. Not disambiguated (but not needed).
+ local t1 = { 1, 2 }
+ local t2 = { 1, 2 }
+ local k = 1
+ for i=1,100 do
+ t1[k] = 11
+ assert(t1[k] == 11)
+ t2[2] = 11
+ assert(t2[2] == 11)
+ end
+ assert(t1[1] == 11)
+ assert(t2[2] == 11)
+end
+
+do --- 6
+-- Store with same ref, same value and aliased loads.
+-- 2nd store eliminated. Not disambiguated (but not needed).
+ local t1 = { 1, 2 }
+ local t2 = t1
+ for i=1,100 do
+ t1[1] = 11
+ assert(t2[1] == 11)
+ t1[1] = 11
+ assert(t2[1] == 11)
+ end
+ assert(t1[1] == 11)
+end
+
+-- Different value -----------------------------------------------------------
+
+do --- 7
+-- Store with same ref and different value.
+-- 1st store eliminated. All stores in loop eliminated.
+ local t = { 1, 2 }
+ for i=1,100 do
+ assert(true)
+ t[1] = 11
+ assert(t[1] == 11)
+ t[1] = 22
+ assert(t[1] == 22)
+ end
+ assert(t[1] == 22)
+end
+
+do --- 8
+-- Store with different tab, same idx and different value.
+-- Cannot eliminate any stores (would need dynamic disambiguation).
+ local t1 = { 1, 2 }
+ local t2 = { 1, 2 }
+ for i=1,100 do
+ assert(true)
+ t1[1] = 11
+ assert(t1[1] == 11)
+ t2[1] = 22
+ assert(t2[1] == 22)
+ end
+ assert(t1[1] == 11)
+ assert(t2[1] == 22)
+end
+
+do --- 9
+-- Store with same tab, different const idx and different value.
+-- Disambiguated. All stores in loop eliminated.
+ local t = { 1, 2 }
+ for i=1,100 do
+ assert(true)
+ t[1] = 11
+ assert(t[1] == 11)
+ t[2] = 22
+ assert(t[2] == 22)
+ end
+ assert(t[1] == 11)
+ assert(t[2] == 22)
+end
+
+do --- 10
+-- Store with different tab, different const idx and different value.
+-- Disambiguated. All stores in loop eliminated.
+ local t1 = { 1, 2 }
+ local t2 = { 1, 2 }
+ for i=1,100 do
+ assert(true)
+ t1[1] = 11
+ assert(t1[1] == 11)
+ t2[2] = 22
+ assert(t2[2] == 22)
+ end
+ assert(t1[1] == 11)
+ assert(t2[2] == 22)
+end
+
+do --- 11
+-- Store with different tab, different non-const idx and different value.
+-- Cannot eliminate any stores (would need dynamic disambiguation).
+ local t1 = { 1, 2 }
+ local t2 = { 1, 2 }
+ local k = 1
+ for i=1,100 do
+ assert(true)
+ t1[k] = 11
+ assert(t1[k] == 11)
+ t2[2] = 22
+ assert(t2[2] == 22)
+ end
+ assert(t1[1] == 11)
+ assert(t2[2] == 22)
+end
+
+do --- 12
+-- Store with same ref, different value and aliased loads.
+-- Cannot eliminate any stores (would need dynamic disambiguation).
+ local t1 = { 1, 2 }
+ local t2 = t1
+ for i=1,100 do
+ assert(true)
+ t1[1] = 11
+ assert(t2[1] == 11)
+ t1[1] = 22
+ assert(t2[1] == 22)
+ end
+ assert(t1[1] == 22)
+end
+
+do --- CALLL must inhibit DSE.
+ local a,b
+ local t = {1,2}
+ for i=1,100 do
+ t[2]=nil
+ a=#t
+ t[2]=2
+ b=#t
+ end
+ assert(a == 1 and b == 2)
+end
diff --git a/test/LuaJIT-tests/opt/dse/field.lua b/test/LuaJIT-tests/opt/dse/field.lua
new file mode 100644
index 0000000..d8a5411
--- /dev/null
+++ b/test/LuaJIT-tests/opt/dse/field.lua
@@ -0,0 +1,70 @@
+local getmetatable, setmetatable = getmetatable, setmetatable
+
+do --- 1. Store with same ref and same value. All stores in loop eliminated.
+ local mt = {}
+ local t = {}
+ for i=1,100 do
+ setmetatable(t, mt)
+ assert(getmetatable(t) == mt)
+ setmetatable(t, mt)
+ assert(getmetatable(t) == mt)
+ end
+ assert(getmetatable(t) == mt)
+end
+
+do --- 2. Store with different ref and same value. All stores in loop eliminated.
+ local mt = {}
+ local t1 = {}
+ local t2 = {}
+ for i=1,100 do
+ setmetatable(t1, mt)
+ assert(getmetatable(t1) == mt)
+ setmetatable(t2, mt)
+ assert(getmetatable(t2) == mt)
+ end
+ assert(getmetatable(t1) == mt)
+ assert(getmetatable(t2) == mt)
+end
+
+do --- 3. Store with different ref and different value. Cannot eliminate any stores.
+ local mt1 = {}
+ local mt2 = {}
+ local t1 = {}
+ local t2 = {}
+ for i=1,100 do
+ setmetatable(t1, mt1)
+ assert(getmetatable(t1) == mt1)
+ setmetatable(t2, mt2)
+ assert(getmetatable(t2) == mt2)
+ end
+ assert(getmetatable(t1) == mt1)
+ assert(getmetatable(t2) == mt2)
+end
+
+do --- 4. Store with same ref and different value. 2nd store remains in loop.
+ local mt1 = {}
+ local mt2 = {}
+ local t = {}
+ for i=1,100 do
+ setmetatable(t, mt1)
+ assert(getmetatable(t) == mt1)
+ setmetatable(t, mt2)
+ assert(getmetatable(t) == mt2)
+ end
+ assert(getmetatable(t) == mt2)
+end
+
+do --- 5. Store with same ref, different value and aliased loads.
+-- Cannot eliminate any stores.
+ local mt1 = {}
+ local mt2 = {}
+ local t1 = {}
+ local t2 = t1
+ for i=1,100 do
+ setmetatable(t1, mt1)
+ assert(getmetatable(t2) == mt1)
+ setmetatable(t1, mt2)
+ assert(getmetatable(t2) == mt2)
+ end
+ assert(getmetatable(t1) == mt2)
+end
diff --git a/test/LuaJIT-tests/opt/dse/index b/test/LuaJIT-tests/opt/dse/index
new file mode 100644
index 0000000..7b8ad1f
--- /dev/null
+++ b/test/LuaJIT-tests/opt/dse/index
@@ -0,0 +1,2 @@
+array.lua
+field.lua
diff --git a/test/LuaJIT-tests/opt/fold/index b/test/LuaJIT-tests/opt/fold/index
new file mode 100644
index 0000000..8b4648c
--- /dev/null
+++ b/test/LuaJIT-tests/opt/fold/index
@@ -0,0 +1 @@
+kfold.lua
diff --git a/test/LuaJIT-tests/opt/fold/kfold.lua b/test/LuaJIT-tests/opt/fold/kfold.lua
new file mode 100644
index 0000000..9cd3919
--- /dev/null
+++ b/test/LuaJIT-tests/opt/fold/kfold.lua
@@ -0,0 +1,81 @@
+do --- operators
+ local y = 0
+ for i=1,100 do local a, b = 23, 11; y = a+b end; assert(y == 23+11)
+ for i=1,100 do local a, b = 23, 11; y = a-b end; assert(y == 23-11)
+ for i=1,100 do local a, b = 23, 11; y = a*b end; assert(y == 23*11)
+ for i=1,100 do local a, b = 23, 11; y = a/b end; assert(y == 23/11)
+ for i=1,100 do local a, b = 23, 11; y = a%b end; assert(y == 23%11)
+ for i=1,100 do local a, b = 23, 11; y = a^b end; assert(y == 23^11)
+
+ for i=1,100 do local a, b = 23.5, 11.5; y = a+b end; assert(y == 23.5+11.5)
+ for i=1,100 do local a, b = 23.5, 11.5; y = a-b end; assert(y == 23.5-11.5)
+ for i=1,100 do local a, b = 23.5, 11.5; y = a*b end; assert(y == 23.5*11.5)
+ for i=1,100 do local a, b = 23.5, 11.5; y = a/b end; assert(y == 23.5/11.5)
+ for i=1,100 do local a, b = 23.5, 11.5; y = a%b end; assert(y == 23.5%11.5)
+end
+
+do --- abs
+ local y = 0
+ for i=1,100 do local a=23; y = math.abs(a) end; assert(y == math.abs(23))
+ for i=1,100 do local a=-23; y = math.abs(a) end; assert(y == math.abs(-23))
+ for i=1,100 do local a=23.5; y = math.abs(a) end; assert(y == math.abs(23.5))
+ for i=1,100 do local a=-23.5; y = math.abs(a) end; assert(y==math.abs(-23.5))
+ for i=1,100 do local a=-2^31; y = math.abs(a) end; assert(y==math.abs(-2^31))
+end
+
+do --- atan2 ldexp
+ local y = 0
+ for i=1,100 do local a, b = 23, 11; y = math.atan2(a, b) end
+ assert(y == math.atan2(23, 11))
+ for i=1,100 do local a, b = 23, 11; y = math.ldexp(a, b) end
+ assert(y == math.ldexp(23, 11))
+end
+
+do --- minmax
+ local y = 0
+ for i=1,100 do local a, b = 23, 11; y = math.min(a, b) end
+ assert(y == math.min(23, 11))
+ for i=1,100 do local a, b = 23, 11; y = math.max(a, b) end
+ assert(y == math.max(23, 11))
+ for i=1,100 do local a, b = 23.5, 11.5; y = math.min(a, b) end
+ assert(y == math.min(23.5, 11.5))
+ for i=1,100 do local a, b = 23.5, 11.5; y = math.max(a, b) end
+ assert(y == math.max(23.5, 11.5))
+ for i=1,100 do local a, b = 11, 23; y = math.min(a, b) end
+ assert(y == math.min(11, 23))
+ for i=1,100 do local a, b = 11, 23; y = math.max(a, b) end
+ assert(y == math.max(11, 23))
+ for i=1,100 do local a, b = 11.5, 23.5; y = math.min(a, b) end
+ assert(y == math.min(11.5, 23.5))
+ for i=1,100 do local a, b = 11.5, 23.5; y = math.max(a, b) end
+ assert(y == math.max(11.5, 23.5))
+end
+
+do --- floorceil
+ local y = 0
+ for i=1,100 do local a=23; y=math.floor(a) end assert(y==math.floor(23))
+ for i=1,100 do local a=23.5; y=math.floor(a) end assert(y==math.floor(23.5))
+ for i=1,100 do local a=-23; y=math.floor(a) end assert(y==math.floor(-23))
+ for i=1,100 do local a=-23.5; y=math.floor(a) end assert(y==math.floor(-23.5))
+ for i=1,100 do local a=-0; y=math.floor(a) end assert(y==math.floor(-0))
+ for i=1,100 do local a=23; y=math.ceil(a) end assert(y==math.ceil(23))
+ for i=1,100 do local a=23.5; y=math.ceil(a) end assert(y==math.ceil(23.5))
+ for i=1,100 do local a=-23; y=math.ceil(a) end assert(y==math.ceil(-23))
+ for i=1,100 do local a=-23.5; y=math.ceil(a) end assert(y==math.ceil(-23.5))
+ for i=1,100 do local a=-0; y=math.ceil(a) end assert(y==math.ceil(-0))
+end
+
+do --- sqrt exp log trig
+ local y = 0
+ for i=1,100 do local a=23; y=math.sqrt(a) end assert(y==math.sqrt(23))
+ for i=1,100 do local a=23; y=math.exp(a) end assert(y==math.exp(23))
+ for i=1,100 do local a=23; y=math.log(a) end assert(y==math.log(23))
+ for i=1,100 do local a=23; y=math.log10(a) end assert(y==math.log10(23))
+ for i=1,100 do local a=23; y=math.sin(a) end assert(y==math.sin(23))
+ for i=1,100 do local a=23; y=math.cos(a) end assert(y==math.cos(23))
+ for i=1,100 do local a=23; y=math.tan(a) end assert(y==math.tan(23))
+end
+
+do --- exp -luajit==2.0
+ assert((10^-2 - 0.01) == 0)
+end
diff --git a/test/LuaJIT-tests/opt/fuse.lua b/test/LuaJIT-tests/opt/fuse.lua
new file mode 100644
index 0000000..a68381e
--- /dev/null
+++ b/test/LuaJIT-tests/opt/fuse.lua
@@ -0,0 +1,5 @@
+do --- Don't fuse i+101 on x64.
+-- (except if i is sign-extended to 64 bit or addressing is limited to 32 bit)
+ local t = {}
+ for i=-100,-1 do t[i+101] = 1 end
+end
diff --git a/test/LuaJIT-tests/opt/fwd/hrefk_rollback.lua b/test/LuaJIT-tests/opt/fwd/hrefk_rollback.lua
new file mode 100644
index 0000000..5a6ad87
--- /dev/null
+++ b/test/LuaJIT-tests/opt/fwd/hrefk_rollback.lua
@@ -0,0 +1,32 @@
+do --- https://github.com/LuaJIT/LuaJIT/issues/124
+ local function foo(a, b, f)
+ return f and (a.f0 < b.f1 and
+ b.f0 < a.f1 and
+ a.f2 < b.f3 and
+ b.f2 < a.f3)
+ end
+
+ local function bar(f0, f1, f2, f3, X, f)
+ for _, v in ipairs(X) do
+ local b = {}
+ b.f0 = 0
+ b.f2 = v
+ b.f1 = b.f0 + 1
+ b.f3 = b.f2 + 1
+
+ if foo({f0 = f0, f1 = f1, f2 = f2, f3 = f3}, b, f) then
+ return false
+ end
+ end
+
+ return true
+ end
+
+ local X = { 0, 1, 0, 0 }
+
+ for i = 1, 20 do
+ assert(bar(0, 1, 2, 3, X, true))
+ end
+
+ assert(not bar(0, 1, 1, 2, X, true))
+end
diff --git a/test/LuaJIT-tests/opt/fwd/index b/test/LuaJIT-tests/opt/fwd/index
new file mode 100644
index 0000000..5bb1537
--- /dev/null
+++ b/test/LuaJIT-tests/opt/fwd/index
@@ -0,0 +1,3 @@
+hrefk_rollback.lua
+tnew_tdup.lua
+upval.lua
diff --git a/test/LuaJIT-tests/opt/fwd/tnew_tdup.lua b/test/LuaJIT-tests/opt/fwd/tnew_tdup.lua
new file mode 100644
index 0000000..9e18fa3
--- /dev/null
+++ b/test/LuaJIT-tests/opt/fwd/tnew_tdup.lua
@@ -0,0 +1,69 @@
+do --- 1.
+ local x = 2
+ for i=1,100 do
+ local t = {} -- TNEW: DCE
+ x = t.foo -- HREF -> niltv: folded
+ end
+ assert(x == nil)
+end
+
+do --- 2.
+ local x = 2
+ for i=1,100 do
+ local t = {1} -- TDUP: DCE
+ x = t.foo -- HREF -> niltv: folded
+ end
+ assert(x == nil)
+end
+
+do --- 3.
+ local x = 2
+ for i=1,100 do
+ local t = {}
+ t[1] = 11 -- NEWREF + HSTORE
+ x = t[1] -- AREF + ALOAD, no forwarding, no fold
+ end
+ assert(x == 11)
+end
+
+do --- 4. HREFK not eliminated. Ditto for the EQ(FLOAD(t, #tab.hmask), k).
+ local x = 2
+ for i=1,100 do
+ local t = {}
+ t.foo = 11 -- NEWREF + HSTORE
+ x = t.foo -- HREFK + HLOAD: store forwarding
+ end
+ assert(x == 11)
+end
+
+do --- 5. HREFK not eliminated. Ditto for the EQ(FLOAD(t, #tab.hmask), k).
+ local x = 2
+ for i=1,100 do
+ local t = {foo=11} -- TDUP
+ x = t.foo -- HREFK + non-nil HLOAD: folded
+ end
+ assert(x == 11)
+end
+
+do --- 6.
+ local x = 2
+ local k = 1
+ for i=1,100 do
+ local t = {[0]=11} -- TDUP
+ t[k] = 22 -- AREF + ASTORE aliasing
+ x = t[0] -- AREF + ALOAD, no fold
+ end
+ assert(x == 11)
+end
+
+do --- 7.
+ local setmetatable = setmetatable
+ local mt = { __newindex = function(t, k, v)
+ assert(k == "foo")
+ assert(v == 11)
+ end }
+ for i=1,100 do
+ local t = setmetatable({}, mt)
+ t.foo = 11
+ end
+end
diff --git a/test/LuaJIT-tests/opt/fwd/upval.lua b/test/LuaJIT-tests/opt/fwd/upval.lua
new file mode 100644
index 0000000..a3e83df
--- /dev/null
+++ b/test/LuaJIT-tests/opt/fwd/upval.lua
@@ -0,0 +1,50 @@
+do --- 1. Open upvalue above base slot, aliasing an SSA value.
+ local x = 7
+ local function a() x = x + 1 end
+ local function b() x = x + 2 end
+ for i=1,100 do a(); b(); x = x + 5 end
+ assert(x == 807)
+end
+
+do --- 2. Open upvalue below base slot. UREFO CSE for a.x + b.x, but not x in loop.
+ -- ULOAD not disambiguated. 2x ULOAD + 2x USTORE (+ 1x DSE USTORE).
+ local x = 7
+ (function()
+ local function a() x = x + 1 end
+ local function b() x = x + 2 end
+ for i=1,100 do a(); b(); x = x + 5 end
+ end)()
+ assert(x == 807)
+end
+
+do --- 3. Closed upvalue. UREFC CSE for a.x + b.x, but not x in loop.
+ -- ULOAD not disambiguated. 2x ULOAD + 2x USTORE (+ 1x DSE for USTORE).
+ local xx = (function()
+ local x = 7
+ local function a() x = x + 1 end
+ local function b() x = x + 2 end
+ return function() for i=1,100 do a(); b(); x = x + 5 end; return x end
+ end)()()
+ assert(xx == 807)
+end
+
+do --- 4. Open upvalue below base slot. Forwarded. 1x USTORE (+ 1x DSE USTORE).
+ local x = 7
+ (function()
+ local function a() x = x + 1 end
+ for i=1,100 do a(); a() end
+ end)()
+ assert(x == 207)
+end
+
+do --- 5. Closed upvalue. Forwarded. 1x USTORE (+ 1x DSE USTORE).
+ local xx = (function()
+ local x = 7
+ return function()
+ local function a() x = x + 1 end
+ for i=1,100 do a(); a() end
+ return x
+ end
+ end)()()
+ assert(xx == 207)
+end
diff --git a/test/LuaJIT-tests/opt/index b/test/LuaJIT-tests/opt/index
new file mode 100644
index 0000000..94d50ae
--- /dev/null
+++ b/test/LuaJIT-tests/opt/index
@@ -0,0 +1,6 @@
+dse +dse
+fold +fold
+fwd +fwd
+fuse.lua +fuse
+loop +loop
+sink +sink
diff --git a/test/LuaJIT-tests/opt/loop/index b/test/LuaJIT-tests/opt/loop/index
new file mode 100644
index 0000000..e582023
--- /dev/null
+++ b/test/LuaJIT-tests/opt/loop/index
@@ -0,0 +1 @@
+unroll.lua
diff --git a/test/LuaJIT-tests/opt/loop/unroll.lua b/test/LuaJIT-tests/opt/loop/unroll.lua
new file mode 100644
index 0000000..6fbd565
--- /dev/null
+++ b/test/LuaJIT-tests/opt/loop/unroll.lua
@@ -0,0 +1,32 @@
+do --- type instability on loop unroll -> record unroll
+ local flip = true
+ for i=1,100 do flip = not flip end
+ assert(flip == true)
+end
+
+do --- untitled
+ local t = {}
+ local a, b, c = 1, "", t
+ for i=1,100 do a,b,c=b,c,a end
+ assert(c == 1 and a == "" and b == t)
+end
+
+do --- FAILFOLD on loop unroll -> LJ_TRERR_GFAIL -> record unroll
+ local t = { 1, 2 }
+ local k = 2
+ local x = 0
+ for i=1,200 do
+ x = x + t[k]
+ k = k == 1 and 2 or 1
+ end
+ assert(x == 300 and k == 2)
+end
+
+do --- Unroll if inner loop aborts.
+ local j = 0
+ for i = 1,100 do
+ repeat
+ j = j+1
+ until true
+ end
+end
diff --git a/test/LuaJIT-tests/opt/sink/alloc.lua b/test/LuaJIT-tests/opt/sink/alloc.lua
new file mode 100644
index 0000000..bb2a0f7
--- /dev/null
+++ b/test/LuaJIT-tests/opt/sink/alloc.lua
@@ -0,0 +1,126 @@
+local assert = assert
+
+do --- DCE or sink trivial TNEW or TDUP.
+ for i=1,100 do local t={} end
+ for i=1,100 do local t={1} end
+end
+
+do --- Sink TNEW/TDUP + ASTORE/HSTORE.
+ for i=1,100 do local t={i}; assert(t[1] == i) end
+ for i=1,100 do local t={foo=i}; assert(t.foo == i) end
+ for i=1,100 do local t={1,i}; assert(t[2] == i) end
+ for i=1,100 do local t={bar=1,foo=i}; assert(t.foo == i) end
+end
+
+do --- Sink outermost table of nested TNEW.
+ local x
+ for i=1,100 do
+ local t = {[0]={{1,i}}}
+ if i == 90 then x = t end
+ assert(t[0][1][2] == i)
+ end
+ assert(x[0][1][2] == 90)
+ for i=1,100 do
+ local t = {foo={bar={baz=i}}}
+ if i == 90 then x = t end
+ assert(t.foo.bar.baz == i)
+ end
+ assert(x.foo.bar.baz == 90)
+end
+
+do --- Sink one TNEW + FSTORE.
+ for i=1,100 do local t = setmetatable({}, {}) end
+end
+
+do --- Sink TDUP or TDUP + HSTORE. Guard of HREFK eliminated.
+ local x
+ for i=1,100 do local t = { foo = 1 }; x = t.foo; end
+ assert(x == 1)
+ for i=1,100 do local t = { foo = i }; x = t.foo; end
+ assert(x == 100)
+end
+
+do --- Sink of simplified complex add, unused in next iteration, drop PHI.
+ local x={1,2}
+ for i=1,100 do x = {x[1]+3, x[2]+4} end
+ assert(x[1] == 301)
+ assert(x[2] == 402)
+end
+
+do --- Sink of complex add, unused in next iteration, drop PHI.
+ local x,k={1.5,2.5},{3.5,4.5}
+ for i=1,100 do x = {x[1]+k[1], x[2]+k[2]} end
+ assert(x[1] == 351.5)
+ assert(x[2] == 452.5)
+end
+
+do --- Sink of TDUP with stored values that are both PHI and non-PHI.
+ local x,k={1,2},{3,4}
+ for i=1,100 do x = {x[1]+k[1], k[2]} end
+ assert(x[1] == 301)
+ assert(x[2] == 4)
+end
+
+do --- Sink of CONV.
+ local t = {1}
+ local x,y
+ for i=1,200 do
+ local v = {i}
+ local w = {i+1}
+ x = v[1]
+ y = w[1]
+ if i > 100 then end
+ end
+ assert(x == 200 and y == 201)
+end
+
+do --- Sink of stores with numbers.
+ local x = {1.5, 0}
+ for i=1,200 do x = {x[1]+1, 99.5}; x[2]=4.5; if i > 100 then end end
+ assert(x[1] == 201.5)
+ assert(x[2] == 4.5)
+end
+
+do --- Sink of stores with constants.
+ for i=1,100 do local t = {false}; t[1] = true; if i > 100 then g=t end end
+end
+
+do --- Sink with two references to the same table.
+ for i=1,200 do
+ local t = {i}
+ local q = t
+ if i > 100 then assert(t == q) end
+ end
+end
+
+do --- point
+ local point
+ point = {
+ new = function(self, x, y)
+ return setmetatable({x=x, y=y}, self)
+ end,
+ __add = function(a, b)
+ return point:new(a.x + b.x, a.y + b.y)
+ end,
+ }
+ point.__index = point
+ local a, b = point:new(1, 1), point:new(2, 2)
+ for i=1,100 do a = (a + b) + b end
+ assert(a.x == 401)
+ assert(a.y == 401)
+ assert(getmetatable(a) == point)
+ for i=1,200 do a = (a + b) + b; if i > 100 then end end
+ assert(a.x == 1201)
+ assert(a.y == 1201)
+ assert(getmetatable(a) == point)
+end
+
+do --- untitled
+ local t = {}
+ for i=1,20 do t[i] = 1 end
+ for i=1,20 do
+ for a,b in ipairs(t) do
+ local s = {i}
+ end
+ end
+end
diff --git a/test/LuaJIT-tests/opt/sink/ffi.lua b/test/LuaJIT-tests/opt/sink/ffi.lua
new file mode 100644
index 0000000..0bba097
--- /dev/null
+++ b/test/LuaJIT-tests/opt/sink/ffi.lua
@@ -0,0 +1,121 @@
+local ffi = require("ffi")
+
+do --- incrementing
+ local x = 10000000000000ll
+ for i=1,100 do x=x+1 end
+ assert(x == 10000000000100ll)
+end
+
+do --- hoistable increment !private_G
+ local x = 10000000000000ll
+ local z
+ for i=1,100 do z=x+1 end
+ assert(z == 10000000000001ll)
+ for i=1,100 do local y=x; z=x+1; g=y end
+ assert(z == 10000000000001ll)
+ assert(g == 10000000000000ll)
+end
+
+do --- escaping hoistable increment
+ local x = 10000000000000ll
+ for i=1,100 do local y=x+1; if i == 90 then x=y end end
+ assert(x == 10000000000001ll)
+end
+
+do --- escaping addition
+ local x = 10000000000000ll
+ for i=1,100 do local y=x+i; if i == 90 then x=y end end
+ assert(x == 10000000000090ll)
+end
+
+do --- conditional addition / incrementing
+ local x = 10000000000000ll
+ for i=1,200 do local y=x+i; if i > 100 then x=y end end
+ assert(x == 10000000015050ll)
+end
+
+do --- incrementing pointer
+ local a = ffi.new("int[?]", 100)
+ local p = a
+ for i=0,99 do p[0]=i; p=p+1 end
+ assert(p == a+100)
+ for i=0,99 do assert(a[i] == i) end
+end
+
+do --- mutating complex
+ local cx = ffi.typeof("complex")
+ local x = cx(1, 2)
+ local k = cx(3, 4)
+ for i=1,100 do x = cx(x.re+k.re, x.im+k.im) end
+ assert(x.re == 301)
+ assert(x.im == 402)
+end
+
+do --- mutating struct
+ local st = ffi.typeof("struct { int a; int64_t b; double c; }")
+ local x = st(1, 20000000000LL, 3.5)
+ local k = st(3, 4, 5.0)
+ for i=1,100 do x = st(x.a+k.a, x.b+k.b, x.c+k.c) end
+ assert(x.a == 301)
+ assert(x.b == 20000000400LL)
+ assert(x.c == 503.5)
+ local y, z
+ for i=1,100 do
+ local x = st(i, i, i)
+ if i == 90 then y = st(x.a, x.b, x.c) end
+ x.b = x.b + 20000000000LL
+ if i == 95 then z = st(x.a, x.b, x.c) end
+ end
+ assert(y.a == 90)
+ assert(y.b == 90)
+ assert(y.c == 90)
+ assert(z.a == 95)
+ assert(z.b == 20000000095LL)
+ assert(z.c == 95)
+ for i=1,200 do
+ local x = st(i, i, i)
+ if i > 100 then y = st(x.a, x.b, x.c) end
+ x.b = x.b + 20000000000LL
+ if i > 150 then z = st(x.a, x.b, x.c) end
+ end
+ assert(y.a == 200)
+ assert(y.b == 200)
+ assert(y.c == 200)
+ assert(z.a == 200)
+ assert(z.b == 20000000200LL)
+ assert(z.c == 200)
+end
+
+do --- mutating struct 2
+ local st = ffi.typeof("struct { int64_t a; double b; float c; }")
+ local x = st(1, 2.5, 3.25)
+ local k = st(3, 4, 5)
+ for i=1,100 do x = st(x.a+k.a, x.b+k.b, x.c+k.c) end
+ assert(x.a == 301)
+ assert(x.b == 402.5)
+ assert(x.c == 503.25)
+end
+
+do --- escaping loop counter to float
+ local st = ffi.typeof("struct { float a; }")
+ local x
+ for i=1,200 do
+ local y = st(i)
+ if i > 100 then x = y end
+ end
+ assert(x.a == 200)
+end
+
+do --- 64 bit crash bug !private_G
+ local t = {}
+ for i=1,200 do t[i] = "abcd" end
+ local r
+ for i=1,200 do
+ local a,b,c,d
+ local g = t[201-i] -- Non-zero stack slot above.
+ local v = ffi.cast("const char *", t[i]) -- Uses 32 bit stack slot!
+ a,b,c,d = {v[0]},{v[1]},{v[2]},{v[3]} -- Force above to spill.
+ r = {{i}} -- Spill due to call.
+ if i > 100 then z = v[0]+a[1]+b[1]+c[1]+d[1] end -- Crash for 64 bit ptr v.
+ end
+end
diff --git a/test/LuaJIT-tests/opt/sink/ffi_nosink.lua b/test/LuaJIT-tests/opt/sink/ffi_nosink.lua
new file mode 100644
index 0000000..8f7cced
--- /dev/null
+++ b/test/LuaJIT-tests/opt/sink/ffi_nosink.lua
@@ -0,0 +1,45 @@
+local ffi = require("ffi")
+
+do --- escaping global !private_G
+ local x = 0ll
+ for i=1,100 do x=x+1; g=x end
+ assert(x == 100ll)
+ assert(g == 100ll)
+end
+
+do --- preincrement escaping global !private_G
+ local x = 0ll
+ for i=1,100 do local y=x; x=x+1; g=y end
+ assert(x == 100ll)
+ assert(g == 99ll)
+end
+
+do --- escaping global and local !private_G
+ local x = 0ll
+ local z
+ for i=1,100 do z=x+1; g=z end
+ assert(z == 1ll)
+ assert(g == 1ll)
+end
+
+do --- swapping
+ local x,y = 0ll, 0ll
+ for i=1,100 do y,x=x,x+1 end
+ assert(x == 100ll)
+ assert(y == 99ll)
+end
+
+do --- pointer to self
+ local st = ffi.typeof("struct { void *p; }")
+ local x
+ for i=1,100 do x = st(); x.p = x end
+ assert(x.p == ffi.cast("void *", x))
+end
+
+do --- strchr
+ ffi.cdef[[char *strchr(char *, int);]]
+ for i=1,100 do
+ local p = ffi.new("char[2]");
+ ffi.C.strchr(p, 32)
+ end
+end
diff --git a/test/LuaJIT-tests/opt/sink/index b/test/LuaJIT-tests/opt/sink/index
new file mode 100644
index 0000000..8bfa370
--- /dev/null
+++ b/test/LuaJIT-tests/opt/sink/index
@@ -0,0 +1,4 @@
+alloc.lua
+nosink.lua
+ffi.lua +ffi
+ffi_nosink.lua +ffi
diff --git a/test/LuaJIT-tests/opt/sink/nosink.lua b/test/LuaJIT-tests/opt/sink/nosink.lua
new file mode 100644
index 0000000..762aace
--- /dev/null
+++ b/test/LuaJIT-tests/opt/sink/nosink.lua
@@ -0,0 +1,109 @@
+local assert = assert
+
+do --- Cannot sink TNEW, aliased load.
+ local k = 1
+ for i=1,100 do local t={i}; assert(t[k]==i) end
+ for i=1,100 do local t={}; t[k]=i; assert(t[1]==i) end
+end
+
+do --- Cannot sink TNEW, escaping to upvalue.
+ (function()
+ local uv
+ return function()
+ for i=1,100 do uv = {i} end
+ assert(uv[1] == 100)
+ end
+ end)()()
+end
+
+do --- Cannot sink TNEW, escaping through a store.
+ local t = {}
+ for i=1,100 do t[1] = {i} end
+ for i=1,100 do t.foo = {i} end
+ for i=1,100 do setmetatable(t, {i}) end
+ assert(t[1][1] == 100)
+ assert(t.foo[1] == 100)
+ assert(getmetatable(t)[1] == 100)
+end
+
+do --- Cannot sink TNEW, iteratively escaping through a store.
+ local t = {}
+ for i=1,100 do t[1] = {i}; t[1][1] = {i} end
+ assert(t[1][1][1] == 100)
+end
+
+do --- Cannot sink TNEW, escaping to next iteration (unused in 1st variant).
+ local t;
+ for i=1,200 do t = {i} end
+ assert(t[1] == 200)
+ for i=1,200 do if i > 100 then assert(t[1] == i-1) end t = {i} end
+ assert(t[1] == 200)
+end
+
+do --- Cannot sink TNEW, escaping to next iteration (snapshot ref).
+ local t,x
+ for i=1,100 do x=t; t={i} end
+ assert(t[1] == 100)
+ assert(x[1] == 99)
+end
+
+do --- Cannot sink TNEW, escaping to next iteration (IR/snapshot ref).
+ local t
+ for i=1,100 do t={t} end
+ assert(type(t[1][1][1]) == "table")
+end
+
+do --- Cannot sink inner TNEW, escaping to next iteration (IR ref).
+ -- (Could sink outer TNEW, but the logic for stores to PHI allocs is too simple).
+ local t = {42, 43}
+ for i=1,100 do t={t[2], {i}} end
+ assert(t[2][1] == 100)
+ assert(t[1][1] == 99)
+end
+
+do --- Cannot sink TNEW, cross-PHI ref (and snapshot ref).
+ local x,y
+ for i=1,100 do x,y={i},x end
+ assert(x[1] == 100)
+ assert(y[1] == 99)
+end
+
+do --- Cannot sink TNEW, cross-PHI ref (and snapshot ref).
+ local x,y
+ for i=1,100 do x,y=y,{i} end
+ assert(x[1] == 99)
+ assert(y[1] == 100)
+end
+
+do --- Cannot sink TNEW, escaping to exit.
+ local function f(n, t)
+ if n == 0 then return t end
+ return (f(n-1, {t}))
+ end
+ local t = f(100, 42)
+ assert(type(t[1][1][1]) == "table")
+ t = f(3, 42)
+ assert(t[1][1][1] == 42)
+end
+
+do --- Cannot sink TNEW, escaping to exit.
+ local function f(n)
+ if n == 0 then return 42 end
+ local t = f(n-1)
+ return {t}
+ end
+ for i=1,20 do
+ local t = f(100)
+ assert(type(t[1][1][1]) == "table")
+ end
+ local t = f(3)
+ assert(t[1][1][1] == 42)
+end
+
+do --- Cannot sink, since nested inner table is non-PHI.
+ local a, b = {{1}}, {{1}}
+ for i=1,10000 do -- Need to force GC exit sometimes
+ a = {{a[1][1]+b[1][1]}}
+ end
+ assert(a[1][1] == 10001)
+end
diff --git a/test/LuaJIT-tests/src/cpptest.cpp b/test/LuaJIT-tests/src/cpptest.cpp
new file mode 100644
index 0000000..a5893ed
--- /dev/null
+++ b/test/LuaJIT-tests/src/cpptest.cpp
@@ -0,0 +1,129 @@
+
+#include <stdio.h>
+
+extern "C" {
+#define LUA_LIB
+#include "lua.h"
+#include "lauxlib.h"
+#include "luajit.h"
+}
+
+static int testobj_alloc;
+
+class TestObj {
+public:
+ TestObj(int x) { foo = x; testobj_alloc = 1; }
+ ~TestObj() { testobj_alloc = 0; }
+private:
+ int foo;
+};
+
+static int ct_alloc(lua_State *L)
+{
+ TestObj foo(1);
+ lua_pushlightuserdata(L, (void *)&foo);
+ lua_call(L, lua_gettop(L)-1, LUA_MULTRET);
+ if (lua_iscfunction(L, -1)) {
+ lua_CFunction f = lua_tocfunction(L, -1);
+ lua_pop(L, 1);
+ f(L);
+ }
+ return lua_gettop(L);
+}
+
+static int ct_isalloc(lua_State *L)
+{
+ lua_pushboolean(L, testobj_alloc);
+ return 1;
+}
+
+static int ct_usereg(lua_State *L)
+{
+ int n = luaL_checkint(L, 1);
+ int m = luaL_checkint(L, 2);
+ int i;
+ int a = 0, b = 0, c = 0, d = 0, e = 0, f = 0;
+ for (i = 0; i < n; i++) {
+ a = (a + 1) ^ 0x12345678;
+ b = (b + 2) ^ 0x12345678;
+ c = (c + 3) ^ 0x12345678;
+ d = (d + 4) ^ 0x12345678;
+ e = (e + 5) ^ 0x12345678;
+ f = (f + 5) ^ 0x12345678;
+ if (i == m) {
+ if (i & 1)
+ lua_pcall(L, 1, 0, 0);
+ else
+ lua_call(L, 1, 0);
+ }
+ }
+ lua_pushinteger(L, a);
+ lua_pushinteger(L, b);
+ lua_pushinteger(L, c);
+ lua_pushinteger(L, d);
+ lua_pushinteger(L, e);
+ lua_pushinteger(L, f);
+ return 6;
+}
+
+static int ct_catch(lua_State *L)
+{
+ try {
+ lua_call(L, lua_gettop(L)-1, LUA_MULTRET);
+ return lua_gettop(L);
+ } catch (const char *s) {
+ lua_pushstring(L, s);
+ } catch (...) {
+ lua_pushliteral(L, "catch ...");
+ }
+ return 1;
+}
+
+static int ct_throw(lua_State *L)
+{
+ const char *s = lua_tostring(L, 1);
+ throw(s);
+ return 0;
+}
+
+static int ct_wrap(lua_State *L, lua_CFunction f)
+{
+ try {
+ return f(L);
+ } catch (const char *s) {
+ lua_pushstring(L, s);
+ }
+ return lua_error(L);
+}
+
+static int ct_wrapon(lua_State *L)
+{
+ lua_pushlightuserdata(L, (void *)ct_wrap);
+ luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC|LUAJIT_MODE_ON);
+ return 0;
+}
+
+static int ct_wrapoff(lua_State *L)
+{
+ luaJIT_setmode(L, 0, LUAJIT_MODE_WRAPCFUNC|LUAJIT_MODE_OFF);
+ return 0;
+}
+
+static luaL_Reg ct_funcs[] = {
+ {"isalloc", ct_isalloc },
+ {"alloc", ct_alloc },
+ {"usereg", ct_usereg },
+ {"catch", ct_catch },
+ {"throw", ct_throw },
+ {"wrapon", ct_wrapon },
+ {"wrapoff", ct_wrapoff },
+ {NULL, NULL}
+};
+
+extern "C" {
+LUA_API int luaopen_cpptest(lua_State *L)
+{
+ luaL_register(L, "cpptest", ct_funcs);
+ return 1;
+}
+}
diff --git a/test/LuaJIT-tests/src/ctest.c b/test/LuaJIT-tests/src/ctest.c
new file mode 100644
index 0000000..d257567
--- /dev/null
+++ b/test/LuaJIT-tests/src/ctest.c
@@ -0,0 +1,339 @@
+
+#define LUA_LIB
+#include "lua.h"
+#include "lauxlib.h"
+
+/* ------------------------------------------------------------------------ */
+
+#ifdef _MSC_VER
+typedef __int8 int8_t;
+typedef __int16 int16_t;
+typedef __int32 int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+#else
+#include <stdint.h>
+#define complex _Complex
+#endif
+
+#if defined(__i386) || defined(__i386__) || defined(_M_IX86)
+#ifdef _MSC_VER
+#define LJ_FASTCALL __fastcall
+#define LJ_STDCALL __stdcall
+#else
+#define LJ_FASTCALL __attribute__((fastcall))
+#define LJ_STDCALL __attribute__((stdcall))
+#endif
+#endif
+
+typedef struct s_ii { int x, y; } s_ii;
+typedef struct s_jj { int64_t x, y; } s_jj;
+typedef struct s_ff { float x, y; } s_ff;
+typedef struct s_dd { double x, y; } s_dd;
+typedef struct s_8i { int a,b,c,d,e,f,g,h; } s_8i;
+
+LUA_API int call_i(int a) { return a+1; }
+LUA_API int call_ii(int a, int b) { return a+b; }
+LUA_API int call_10i(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j) { return a+b+c+d+e+f+g+h+i+j; }
+
+LUA_API int64_t call_10j(int a, int b, int c, int d, int e, int f, int g, int h, int i, int64_t j) { return a+b+c+d+e+f+g+h+i+j; }
+
+LUA_API int64_t call_ji(int64_t a, int b) { return a+b; }
+LUA_API int64_t call_ij(int a, int64_t b) { return a+b; }
+LUA_API int64_t call_jj(int64_t a, int64_t b) { return a+b; }
+
+LUA_API double call_dd(double a, double b) { return a+b; }
+LUA_API double call_10d(double a, double b, double c, double d, double e, double f, double g, double h, double i, double j) { return a+b+c+d+e+f+g+h+i+j; }
+
+LUA_API float call_ff(float a, float b) { return a+b; }
+LUA_API float call_10f(float a, float b, float c, float d, float e, float f, float g, float h, float i, float j) { return a+b+c+d+e+f+g+h+i+j; }
+
+LUA_API double call_idifjd(int a, double b, int c, float d, int64_t e, double f) { return a+b+c+d+e+f; }
+
+LUA_API int call_p_i(int *a) { return *a+1; }
+LUA_API int *call_p_p(int *a) { return a+1; }
+LUA_API int call_pp_i(int *a, int *b) { return (int)(a-b); }
+
+#include <stdarg.h>
+
+LUA_API double call_ividi(int a, ...)
+{
+ double y;
+ va_list argp;
+ va_start(argp, a);
+ y = a;
+ y += va_arg(argp, int);
+ y += va_arg(argp, double);
+ y += va_arg(argp, int);
+ va_end(argp);
+ return y;
+}
+
+#ifdef complex
+LUA_API complex call_dd_cd(double a, double b) { return a+b*2i; }
+LUA_API complex call_cd(complex a) { return a+1-2i; }
+LUA_API complex call_cdcd(complex a, complex b) { return a+b; }
+
+LUA_API complex float call_ff_cf(float a, float b) { return a+b*2i; }
+LUA_API complex float call_cf(complex float a) { return a+1-2i; }
+LUA_API complex float call_cfcf(complex float a, complex float b) { return a+b; }
+#endif
+
+LUA_API s_ii call_sii(s_ii a) { return a; }
+LUA_API s_jj call_sjj(s_jj a) { return a; }
+LUA_API s_ff call_sff(s_ff a) { return a; }
+LUA_API s_dd call_sdd(s_dd a) { return a; }
+LUA_API s_8i call_s8i(s_8i a) { return a; }
+LUA_API s_ii call_siisii(s_ii a, s_ii b)
+{
+ s_ii c;
+ c.x = a.x + b.x;
+ c.y = a.y + b.y;
+ return c;
+}
+LUA_API s_ff call_sffsff(s_ff a, s_ff b)
+{
+ s_ff c;
+ c.x = a.x + b.x;
+ c.y = a.y + b.y;
+ return c;
+}
+LUA_API s_dd call_sddsdd(s_dd a, s_dd b)
+{
+ s_dd c;
+ c.x = a.x + b.x;
+ c.y = a.y + b.y;
+ return c;
+}
+LUA_API s_8i call_s8is8i(s_8i a, s_8i b)
+{
+ s_8i c;
+ c.a = a.a + b.a;
+ c.b = a.b + b.b;
+ c.c = a.c + b.c;
+ c.d = a.d + b.d;
+ c.e = a.e + b.e;
+ c.f = a.f + b.f;
+ c.g = a.g + b.g;
+ c.h = a.h + b.h;
+ return c;
+}
+LUA_API s_8i call_is8ii(int a, s_8i b, int c)
+{
+ b.a += a;
+ b.c += c;
+ return b;
+}
+
+#ifdef LJ_FASTCALL
+LUA_API int LJ_FASTCALL fastcall_void(void) { return 1; }
+LUA_API int LJ_FASTCALL fastcall_i(int a) { return a+1; }
+LUA_API int LJ_FASTCALL fastcall_ii(int a, int b) { return a+b; }
+LUA_API int LJ_FASTCALL fastcall_iii(int a, int b, int c) { return a+b+c; }
+LUA_API int64_t LJ_FASTCALL fastcall_ji(int64_t a, int b) { return a+b; }
+LUA_API double LJ_FASTCALL fastcall_dd(double a, double b) { return a+b; }
+LUA_API int LJ_FASTCALL fastcall_pp_i(int *a, int *b) { return (int)(a-b); }
+LUA_API s_ii LJ_FASTCALL fastcall_siisii(s_ii a, s_ii b)
+{
+ s_ii c;
+ c.x = a.x + b.x;
+ c.y = a.y + b.y;
+ return c;
+}
+LUA_API s_dd LJ_FASTCALL fastcall_sddsdd(s_dd a, s_dd b)
+{
+ s_dd c;
+ c.x = a.x + b.x;
+ c.y = a.y + b.y;
+ return c;
+}
+#endif
+
+#if defined(LJ_STDCALL) && defined(_WIN32)
+LUA_API int LJ_STDCALL stdcall_i(int a) { return a+1; }
+LUA_API int LJ_STDCALL stdcall_ii(int a, int b) { return a+b; }
+LUA_API double LJ_STDCALL stdcall_dd(double a, double b) { return a+b; }
+LUA_API float LJ_STDCALL stdcall_ff(float a, float b) { return a+b; }
+#endif
+
+/* ------------------------------------------------------------------------ */
+
+static int ct_call(lua_State *L)
+{
+ int nresults = luaL_checkint(L, 1);
+ luaL_checkstack(L, nresults, "too many results");
+ lua_call(L, lua_gettop(L)-2, nresults);
+ return lua_gettop(L)-1;
+}
+
+static int ct_callon(lua_State *L)
+{
+ lua_State *co = lua_tothread(L, 1);
+ int nargs = lua_gettop(L)-1;
+ int nresults;
+ lua_xmove(L, co, nargs);
+ lua_call(co, nargs-1, LUA_MULTRET);
+ nresults = lua_gettop(co);
+ lua_xmove(co, L, nresults);
+ return nresults;
+}
+
+static int ct_pcall_err(lua_State *L)
+{
+ int nresults = luaL_checkint(L, 1);
+ luaL_checkstack(L, nresults, "too many results");
+ if (lua_pcall(L, lua_gettop(L)-2, nresults, 0))
+ lua_error(L);
+ return lua_gettop(L)-1;
+}
+
+static int ct_pcall(lua_State *L)
+{
+ int status;
+ luaL_checkany(L, 1);
+ status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0);
+ lua_pushboolean(L, (status == 0));
+ lua_insert(L, 1);
+ return lua_gettop(L); /* return status + all results */
+}
+
+static int ct_xpcall(lua_State *L)
+{
+ int status;
+ luaL_checkany(L, 2);
+ lua_settop(L, 2);
+ lua_insert(L, 1); /* put error function under function to be called */
+ status = lua_pcall(L, 0, LUA_MULTRET, 1);
+ lua_pushboolean(L, (status == 0));
+ lua_replace(L, 1);
+ return lua_gettop(L); /* return status + all results */
+}
+
+#define CO_RUN 0 /* running */
+#define CO_SUS 1 /* suspended */
+#define CO_NOR 2 /* 'normal' (it resumed another coroutine) */
+#define CO_DEAD 3
+
+static const char *const statnames[] =
+ {"running", "suspended", "normal", "dead"};
+
+static int costatus(lua_State *L, lua_State *co) {
+ if (L == co) return CO_RUN;
+ switch (lua_status(co)) {
+ case LUA_YIELD:
+ return CO_SUS;
+ case 0: {
+ lua_Debug ar;
+ if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */
+ return CO_NOR; /* it is running */
+ else if (lua_gettop(co) == 0)
+ return CO_DEAD;
+ else
+ return CO_SUS; /* initial state */
+ }
+ default: /* some error occured */
+ return CO_DEAD;
+ }
+}
+
+static int auxresume(lua_State *L, lua_State *co, int narg) {
+ int status = costatus(L, co);
+ if (!lua_checkstack(co, narg))
+ luaL_error(L, "too many arguments to resume");
+ if (status != CO_SUS) {
+ lua_pushfstring(L, "cannot resume %s coroutine", statnames[status]);
+ return -1; /* error flag */
+ }
+ lua_xmove(L, co, narg);
+ status = lua_resume(co, narg);
+ if (status == 0 || status == LUA_YIELD) {
+ int nres = lua_gettop(co);
+ if (!lua_checkstack(L, nres + 1))
+ luaL_error(L, "too many results to resume");
+ lua_xmove(co, L, nres); /* move yielded values */
+ return nres;
+ }
+ else {
+ lua_xmove(co, L, 1); /* move error message */
+ return -1; /* error flag */
+ }
+}
+
+static int ct_resume(lua_State *L) {
+ lua_State *co = lua_tothread(L, 1);
+ int r;
+ luaL_argcheck(L, co, 1, "coroutine expected");
+ r = auxresume(L, co, lua_gettop(L) - 1);
+ if (r < 0) {
+ lua_pushboolean(L, 0);
+ lua_insert(L, -2);
+ return 2; /* return false + error message */
+ }
+ else {
+ lua_pushboolean(L, 1);
+ lua_insert(L, -(r + 1));
+ return r + 1; /* return true + `resume' returns */
+ }
+}
+
+static int ct_auxwrap(lua_State *L) {
+ lua_State *co = lua_tothread(L, lua_upvalueindex(1));
+ int r = auxresume(L, co, lua_gettop(L));
+ if (r < 0) {
+ if (lua_isstring(L, -1)) { /* error object is a string? */
+ luaL_where(L, 1); /* add extra info */
+ lua_insert(L, -2);
+ lua_concat(L, 2);
+ }
+ lua_error(L); /* propagate error */
+ }
+ return r;
+}
+
+static int ct_cocreate(lua_State *L) {
+ lua_State *NL = lua_newthread(L);
+ luaL_argcheck(L, lua_isfunction(L, 1) && !lua_iscfunction(L, 1), 1,
+ "Lua function expected");
+ lua_pushvalue(L, 1); /* move function to top */
+ lua_xmove(L, NL, 1); /* move function from L to NL */
+ return 1;
+}
+
+
+static int ct_wrap(lua_State *L) {
+ ct_cocreate(L);
+ lua_pushcclosure(L, ct_auxwrap, 1);
+ return 1;
+}
+
+static int ct_yield(lua_State *L) {
+ return lua_yield(L, lua_gettop(L));
+}
+
+static int ct_lightud(lua_State *L)
+{
+ lua_pushlightuserdata(L, (void *)(ptrdiff_t)lua_tonumber(L, 1));
+ return 1;
+}
+
+static luaL_Reg ct_funcs[] = {
+ {"call", ct_call },
+ {"callon", ct_callon },
+ {"pcall", ct_pcall },
+ {"xpcall", ct_xpcall },
+ {"pcall_err", ct_pcall_err },
+ {"resume", ct_resume },
+ {"wrap", ct_wrap },
+ {"yield", ct_yield },
+ {"lightud", ct_lightud },
+ {NULL, NULL}
+};
+
+LUA_API int luaopen_ctest(lua_State *L)
+{
+ luaL_register(L, "ctest", ct_funcs);
+ return 1;
+}
diff --git a/test/LuaJIT-tests/sysdep/catch_cpp.lua b/test/LuaJIT-tests/sysdep/catch_cpp.lua
new file mode 100644
index 0000000..b225100
--- /dev/null
+++ b/test/LuaJIT-tests/sysdep/catch_cpp.lua
@@ -0,0 +1,71 @@
+
+local cp = require("cpptest")
+
+do
+ local a, b = pcall(cp.catch, function() return "x" end)
+ assert(a == true and b == "x")
+end
+
+do
+ local a, b = pcall(function() cp.throw("foo") end)
+ assert(a == false and b == "C++ exception")
+end
+
+local unwind
+do
+ local a, b = pcall(cp.catch, function() cp.throw("foo") end)
+ unwind = a
+ assert((a == false and b == "C++ exception") or (a == true and b == "foo"))
+end
+
+do
+ local st = cp.alloc(function() return cp.isalloc() end)
+ assert(st == true)
+ assert(cp.isalloc() == false)
+end
+
+do
+ local a, b = pcall(cp.alloc, function()
+ assert(cp.isalloc() == true)
+ return "foo", cp.throw
+ end)
+ assert(a == false and b == "C++ exception")
+ assert(cp.isalloc() == false)
+end
+
+if unwind then
+ local a, b = pcall(cp.alloc, function()
+ assert(cp.isalloc() == true)
+ return "foo", error
+ end)
+ assert(a == false and b == "foo")
+ assert(cp.isalloc() == false)
+end
+
+do
+ local a,b,c,d,e,f = cp.usereg(100, 50, function() end, false)
+ assert(a==164 and b==312 and c==428 and d==3696 and e==404 and f==404)
+end
+
+do
+ local function test()
+ cp.usereg(100, 40, error, "foo")
+ end
+ local a,b,c,d,e,f = cp.usereg(100, 51, test, false)
+ assert(a==164 and b==312 and c==428 and d==3696 and e==404 and f==404)
+end
+
+do
+ local t = {};
+ t.t = t;
+ local function foo()
+ for i=1,100 do
+ local a,b,c,d,e,f = t, t.t, t.t.t, t.t.t.t, t.t.t.t.t, t.t.t.t.t.t
+ local g,h,j,k,l = f.t, f.t.t, f.t.t.t, f.t.t.t.t, f.t.t.t.t.t
+ local m = { a,b,c,d,e,f,g,h,j,k,l }
+ end
+ end
+ local a,b,c,d,e,f = cp.usereg(100, 50, foo, false)
+ assert(a==164 and b==312 and c==428 and d==3696 and e==404 and f==404)
+end
+
diff --git a/test/LuaJIT-tests/sysdep/ffi_include_gtk.lua b/test/LuaJIT-tests/sysdep/ffi_include_gtk.lua
new file mode 100644
index 0000000..a4bfcea
--- /dev/null
+++ b/test/LuaJIT-tests/sysdep/ffi_include_gtk.lua
@@ -0,0 +1,9 @@
+local ffi = require("ffi")
+
+dofile("../common/ffi_util.inc")
+
+if cdefs == "" then
+ cdefs = "-pthread -D_REENTRANT -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/gio-unix-2.0/ -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/directfb -I/usr/include/libpng12 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -I/usr/lib/x86_64-linux-gnu/gtk-2.0/include -I/usr/include/gdk-pixbuf-2.0"
+end
+
+include"/usr/include/gtk-2.0/gtk/gtk.h"
diff --git a/test/LuaJIT-tests/sysdep/ffi_include_std.lua b/test/LuaJIT-tests/sysdep/ffi_include_std.lua
new file mode 100644
index 0000000..b88c82b
--- /dev/null
+++ b/test/LuaJIT-tests/sysdep/ffi_include_std.lua
@@ -0,0 +1,36 @@
+local ffi = require("ffi")
+
+dofile("../common/ffi_util.inc")
+
+do
+ local fp = assert(io.open("/tmp/__tmp.c", "w"))
+ fp:write[[
+#include <sqlite3.h>
+#include <thread_db.h>
+#include <resolv.h>
+#include <mpfr.h>
+#include <mpc.h>
+#include <curses.h>
+#include <form.h>
+#include <aio.h>
+#include <unistd.h>
+#include <zlib.h>
+#include <netdb.h>
+#include <math.h>
+#include <tgmath.h>
+#include <complex.h>
+#include <elf.h>
+#include <mqueue.h>
+#include <regex.h>
+#include <fcntl.h>
+]]
+ fp:close()
+
+ local flags = ffi.abi("32bit") and "-m32" or "-m64"
+ fp = assert(io.popen("cc -E -P -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE /tmp/__tmp.c "..flags))
+ local s = fp:read("*a")
+ fp:close()
+ os.remove("/tmp/__tmp.c")
+ ffi.cdef(s)
+end
+
diff --git a/test/LuaJIT-tests/sysdep/ffi_lib_c.lua b/test/LuaJIT-tests/sysdep/ffi_lib_c.lua
new file mode 100644
index 0000000..a368d75
--- /dev/null
+++ b/test/LuaJIT-tests/sysdep/ffi_lib_c.lua
@@ -0,0 +1,87 @@
+local ffi = require("ffi")
+
+ffi.cdef[[
+// libc/libm
+int sprintf(char *buf, const char *fmt, ...);
+double pow(double x, double y);
+int rmdir(const char *name);
+int errno;
+
+// Windows
+unsigned int GetSystemDirectoryA(char *buf, unsigned int sz);
+char *CharUpperA(char *str);
+int GdiFlush(void);
+int _rmdir(const char *name);
+static const int _O_TEXT = 0x4000;
+static const int _O_BINARY = 0x8000;
+int *_errno(void);
+int _fmode;
+
+// Lua/C API
+typedef struct lua_State lua_State;
+typedef double lua_Number;
+lua_State *luaL_newstate(void);
+void luaL_openlibs(lua_State *L);
+void lua_close(lua_State *L);
+int luaL_loadstring(lua_State *L, const char *s);
+int lua_pcall(lua_State *L, int nargs, int nresults, int errfunc);
+lua_Number lua_tonumber(lua_State *L, int idx);
+]]
+
+local C = ffi.C
+
+do
+ local buf = ffi.new("char[?]", 100)
+ local n = C.sprintf(buf, "test %g %s", 12.5, "foo")
+ assert(ffi.string(buf, n) == "test 12.5 foo")
+end
+
+assert(ffi.C.pow(2.5, 5) == 97.65625)
+
+if ffi.abi("win") then
+ do
+ local buf = ffi.new("char[?]", 4, "abc")
+ C.CharUpperA(buf)
+ assert(ffi.string(buf) == "ABC")
+ end
+
+ do
+ local buf = ffi.new("char[?]", 256)
+ local len = C.GetSystemDirectoryA(buf, 255)
+ local s = ffi.string(buf, len)
+ assert(string.find(string.lower(s), "\\system32"))
+ end
+
+ assert(C.GdiFlush() == 1)
+
+ assert(ffi.C._rmdir("/tmp/does_not_exist") == -1)
+ assert(ffi.C._errno()[0] == 2)
+
+ ffi.C._fmode = ffi.C._O_BINARY
+ assert(ffi.C._fmode == ffi.C._O_BINARY)
+ ffi.C._fmode = ffi.C._O_TEXT
+else
+ assert(ffi.C.rmdir("/tmp/does_not_exist") == -1)
+ assert(ffi.C.errno == 2)
+
+ ffi.C.errno = 17
+ assert(ffi.C.errno == 17)
+ ffi.C.errno = 0
+end
+
+do
+ local L = C.luaL_newstate()
+ local s = "local x = 0; for i=1,100 do x=x+i end; return x"
+ C.luaL_openlibs(L)
+ assert(C.luaL_loadstring(L, s) == 0)
+ assert(C.lua_pcall(L, 0, 1, 0) == 0)
+ assert(C.lua_tonumber(L, -1) == 5050)
+ C.lua_close(L)
+end
+
+do
+ if not (ffi.os == "Windows" or ffi.os == "Other") then
+ ffi.load("pthread")
+ end
+end
+
diff --git a/test/LuaJIT-tests/sysdep/ffi_lib_z.lua b/test/LuaJIT-tests/sysdep/ffi_lib_z.lua
new file mode 100644
index 0000000..69a19ae
--- /dev/null
+++ b/test/LuaJIT-tests/sysdep/ffi_lib_z.lua
@@ -0,0 +1,107 @@
+local ffi = require("ffi")
+
+local compress, uncompress
+
+if ffi.abi("win") then
+
+ ffi.cdef[[
+ int RtlGetCompressionWorkSpaceSize(uint16_t fmt,
+ unsigned long *wsbufsz, unsigned long *wsfragsz);
+ int RtlCompressBuffer(uint16_t fmt,
+ const uint8_t *src, unsigned long srclen,
+ uint8_t *dst, unsigned long dstsz,
+ unsigned long chunk, unsigned long *dstlen, void *workspace);
+ int RtlDecompressBuffer(uint16_t fmt,
+ uint8_t *dst, unsigned long dstsz,
+ const uint8_t *src, unsigned long srclen,
+ unsigned long *dstlen);
+ ]]
+
+ local ntdll = ffi.load("ntdll")
+
+ local fmt = 0x0102
+ local workspace
+ do
+ local res = ffi.new("unsigned long[2]")
+ ntdll.RtlGetCompressionWorkSpaceSize(fmt, res, res+1)
+ workspace = ffi.new("uint8_t[?]", res[0])
+ end
+
+ function compress(txt)
+ local buf = ffi.new("uint8_t[?]", 4096)
+ local buflen = ffi.new("unsigned long[1]")
+ local res = ntdll.RtlCompressBuffer(fmt, txt, #txt, buf, 4096,
+ 4096, buflen, workspace)
+ assert(res == 0)
+ return ffi.string(buf, buflen[0])
+ end
+
+ function uncompress(comp, n)
+ local buf = ffi.new("uint8_t[?]", n)
+ local buflen = ffi.new("unsigned long[1]")
+ local res = ntdll.RtlDecompressBuffer(fmt, buf, n, comp, #comp, buflen)
+ assert(res == 0)
+ return ffi.string(buf, buflen[0])
+ end
+
+else
+
+ ffi.cdef[[
+ unsigned long compressBound(unsigned long sourceLen);
+ int compress2(uint8_t *dest, unsigned long *destLen,
+ const uint8_t *source, unsigned long sourceLen, int level);
+ int uncompress(uint8_t *dest, unsigned long *destLen,
+ const uint8_t *source, unsigned long sourceLen);
+ ]]
+
+ local zlib = ffi.load("z")
+
+ function compress(txt)
+ local n = tonumber(zlib.compressBound(#txt))
+ local buf = ffi.new("uint8_t[?]", n)
+ local buflen = ffi.new("unsigned long[1]", n)
+ local res = zlib.compress2(buf, buflen, txt, #txt, 9)
+ assert(res == 0)
+ return ffi.string(buf, tonumber(buflen[0]))
+ end
+
+ function uncompress(comp, n)
+ local buf = ffi.new("uint8_t[?]", n)
+ local buflen = ffi.new("unsigned long[1]", n)
+ local res = zlib.uncompress(buf, buflen, comp, #comp)
+ assert(res == 0)
+ return ffi.string(buf, tonumber(buflen[0]))
+ end
+
+end
+
+ local txt = [[Rebellious subjects, enemies to peace,
+Profaners of this neighbour-stained steel,--
+Will they not hear? What, ho! you men, you beasts,
+That quench the fire of your pernicious rage
+With purple fountains issuing from your veins,
+On pain of torture, from those bloody hands
+Throw your mistemper'd weapons to the ground,
+And hear the sentence of your moved prince.
+Three civil brawls, bred of an airy word,
+By thee, old Capulet, and Montague,
+Have thrice disturb'd the quiet of our streets,
+And made Verona's ancient citizens
+Cast by their grave beseeming ornaments,
+To wield old partisans, in hands as old,
+Canker'd with peace, to part your canker'd hate:
+If ever you disturb our streets again,
+Your lives shall pay the forfeit of the peace.
+For this time, all the rest depart away:
+You Capulet; shall go along with me:
+And, Montague, come you this afternoon,
+To know our further pleasure in this case,
+To old Free-town, our common judgment-place.
+Once more, on pain of death, all men depart.]]
+txt = txt..txt..txt..txt
+
+local c = compress(txt)
+assert(2*#c < #txt)
+local txt2 = uncompress(c, #txt)
+assert(txt2 == txt)
+
diff --git a/test/LuaJIT-tests/test.lua b/test/LuaJIT-tests/test.lua
new file mode 100644
index 0000000..b064eff
--- /dev/null
+++ b/test/LuaJIT-tests/test.lua
@@ -0,0 +1,416 @@
+local assert, io_open, io_lines, io_write, load, type, xpcall =
+ assert, io.open, io.lines, io.write, load, type, xpcall
+local debug_traceback, math_random, tonumber, loadstring =
+ debug.traceback, math.random, tonumber, loadstring or load
+
+local dirsep = package.config:match"^(.-)\n"
+local own_file = debug.getinfo(1, "S").source:match"^@(.*)" or arg[0]
+local own_dir = own_file:match("^.*[/".. dirsep .."]")
+
+local function default_tags()
+ local tags = {}
+
+ -- Lua version and features
+ tags.lua = tonumber(_VERSION:match"%d+%.%d+")
+ if table.pack then
+ tags["compat5.2"] = true
+ end
+ if loadstring"return 0xep+9" then
+ tags.hexfloat = true
+ end
+ if loadstring"goto x ::x::" then
+ tags["goto"] = true
+ end
+
+ -- Libraries
+ for _, lib in ipairs{"bit", "ffi", "jit.profile", "table.new"} do
+ if pcall(require, lib) then
+ tags[lib] = true
+ end
+ end
+
+ -- LuaJIT-specific
+ if jit then
+ tags.luajit = tonumber(jit.version:match"%d+%.%d+")
+ tags[jit.arch:lower()] = true
+ if jit.os ~= "Other" then
+ tags[jit.os:lower()] = true
+ end
+ if jit.status() then
+ tags.jit = true
+ end
+ for _, flag in ipairs{select(2, jit.status())} do
+ tags[flag:lower()] = true
+ end
+ end
+
+ -- Environment
+ if dirsep == "\\" then
+ tags.windows = true
+ end
+ if tags.ffi then
+ local abi = require"ffi".abi
+ for _, param in ipairs{"le", "be", "fpu", "softfp", "hardfp", "eabi"} do
+ if abi(param) then
+ tags[param] = true
+ end
+ end
+ if abi"win" then tags.winabi = true end
+ if abi"32bit" then tags.abi32 = true end
+ if abi"64bit" then tags.abi64 = true end
+ else
+ local bytecode = string.dump(function()end)
+ if bytecode:find"^\27Lua[\80-\89]" then
+ tags[bytecode:byte(7, 7) == 0 and "be" or "le"] = true
+ tags["abi".. (bytecode:byte(9, 9) * 8)] = true
+ end
+ end
+
+ return tags
+end
+
+local function want_meta(opts, meta)
+ if not opts.want_meta_cache then
+ opts.want_meta_cache = setmetatable({}, {__index = function(t, meta)
+ local result = true
+ for polarity, tag, cond in meta:gmatch"([+-])([^ <>=]+)([<>=0-9.]*)" do
+ local tagval = opts.tags[tag]
+ local condresult
+ if cond == "" or not tagval then
+ condresult = tagval
+ else
+ condresult = assert(loadstring("return (...) ".. cond))(tagval)
+ end
+ if polarity == "-" then
+ condresult = not condresult
+ end
+ if not condresult then
+ result = false
+ break
+ end
+ end
+ t[meta] = result
+ return result
+ end})
+ end
+ return opts.want_meta_cache[meta]
+end
+
+local function parse_args(t)
+ local opts = {
+ tags = default_tags(),
+ want_meta = want_meta,
+ }
+ local result = opts
+
+ local i, tlen = 1, #t
+ local joinedval = ""
+ local function flagval()
+ local val
+ if joinedval ~= "" then
+ val = joinedval:sub(2)
+ joinedval = ""
+ else
+ val = t[i]
+ if not val then error("Expected value after ".. t[i-1]) end
+ i = i + 1
+ end
+ return val
+ end
+
+ while i <= tlen do
+ local arg = t[i]
+ i = i + 1
+ if arg:sub(1, 2) == "--" then
+ arg, joinedval = arg:match"^([^=]+)(=?.*)$"
+ if arg == "--quiet" then
+ opts.quiet = true
+ elseif arg == "--shuffle" then
+ local seed = tonumber(flagval())
+ if not seed then error("Expected numeric seed after --shuffle") end
+ opts.shuffle = seed
+ elseif arg == "--shard" then
+ local i, s = flagval():match"^(%d+)/(%d+)$"
+ if not s then error("Expected integer/integer after --shard") end
+ opts.shard = {initial = tonumber(i), step = tonumber(s)}
+ elseif arg == "--version" then
+ io_write("LuaJIT test-suite runner v0.1\n")
+ result = nil
+ elseif arg == "--help" then
+ io_write("Usage: ", _G and _G.arg and _G.arg[-1] or "luajit", " ")
+ io_write(own_file, " [flags] [tags] [root] [numbers]\n")
+ io_write"\n"
+ io_write"Root specifies either a directory of tests, or the name of\n"
+ io_write"a particular .lua test file, defaulting to all tests if not given.\n"
+ io_write"Tags are specified in the form +tag_name or -tag_name, and\n"
+ io_write"are used to turn on or off groups of tests. For example,\n"
+ io_write"pass -ffi to skip tests relating to the ffi library, or\n"
+ io_write"pass +slow to enable running of slow tests.\n"
+ io_write"Numbers can be passed to only run particular tests.\n"
+ io_write"The available flags are:\n"
+ io_write" --quiet\n"
+ io_write" --shuffle=SEED\n"
+ io_write" --shard=INDEX/NUM_SHARDS\n"
+ io_write" --version\n"
+ io_write" --help\n"
+ result = nil
+ else
+ error("Unsupported flag: ".. arg)
+ end
+ if joinedval ~= "" then
+ error(arg .." does not expect an argument")
+ end
+ elseif arg:find"^[-+]" then
+ opts.tags[arg:sub(2)] = (arg:sub(1, 1) == "+")
+ elseif arg:find"^%d+$" then
+ if not opts.numbers_to_run then
+ opts.numbers_to_run = {}
+ end
+ opts.numbers_to_run[tonumber(arg)] = true
+ elseif not opts.root then
+ opts.root = arg
+ else
+ error("Unexpected argument ".. arg)
+ end
+ end
+ return result
+end
+
+local function scan_tests(path, opts)
+ if path:sub(-4, -4) == "." then
+ local f = assert(io_open(path, "rb"))
+ local contents = f:read"*a"
+ f:close()
+ local prefix = "return {"
+ local code = contents:gsub("()(do +%-%-%- +)([^\r\n]+)",
+ function(pos, marker, info)
+ if pos ~= 1 then
+ pos = pos - 1
+ if contents:sub(pos, pos) ~= "\n" then
+ return marker .. info
+ end
+ end
+ local result = ("%s%q,function()"):format(prefix, info)
+ prefix = ","
+ if info:find" !lex" and not opts:want_meta(info:sub((info:find" +[-+@!]"))) then
+ result = result .."end--[========["
+ prefix = "]========]".. prefix
+ end
+ return result
+ end)
+ if prefix:sub(-1) ~= "," then
+ error("No tests found in ".. path)
+ end
+ prefix = prefix .."}"
+ return assert(load(function()
+ local result = code
+ code = code ~= prefix and prefix or nil
+ return result
+ end, "@".. path))()
+ else
+ if path ~= "" and path:sub(-1) ~= "/" and path:sub(-1) ~= dirsep then
+ path = path .. dirsep
+ end
+ local result = {}
+ local i = 1
+ for line in io_lines(path .."index") do
+ if line ~= "" then
+ local metaidx = line:find" +[-+@]"
+ local name = line
+ local want_these = true
+ if metaidx then
+ name = line:sub(1, metaidx - 1)
+ want_these = opts:want_meta(line:sub(metaidx))
+ end
+ if want_these then
+ result[i] = line
+ result[i+1] = scan_tests(path .. name, opts)
+ i = i + 2
+ end
+ end
+ end
+ return result
+ end
+end
+
+local function upvalue_iterator(f, i)
+ i = i + 1
+ local name, val = debug.getupvalue(f, i)
+ return name and i, name, val
+end
+
+local function upvalues_of(f)
+ return upvalue_iterator, f, 0
+end
+
+local function append_tree_to_plan(test_tree, opts, plan, prefix)
+ local prefi
+ for i = 1, #test_tree, 2 do
+ local info = test_tree[i]
+ local name = info
+ local want_these = true
+ local metaidx = info:find" +[-+@!]"
+ if metaidx then
+ name = info:sub(1, metaidx - 1)
+ want_these = opts:want_meta(info:sub(metaidx))
+ end
+ local planlen = #plan
+ if want_these then
+ local test = test_tree[i+1]
+ if type(test) == "table" then
+ append_tree_to_plan(test, opts, plan, prefix .. name .. dirsep)
+ else
+ if not prefi then
+ prefi = prefix:sub(1, -2)
+ end
+ plan[#plan+1] = {prefi, name, test}
+ end
+ end
+ if metaidx and info:find"!" then
+ for modifier in info:gmatch"!([^ ]+)" do
+ if modifier == "private_G" then
+ local G = setmetatable({}, {__index = _G})
+ G._G = G
+ local function Gfn() return G end
+ for i = planlen+1, #plan do
+ local test = plan[i][3]
+ if setfenv then
+ setfenv(test, G)
+ else
+ for i, name in upvalues_of(test) do
+ if name == "_ENV" then
+ debug.upvaluejoin(test, i, Gfn, 1)
+ break
+ end
+ end
+ end
+ end
+ elseif modifier == "lex" then
+ -- Handled during test scanning
+ else
+ error("Unsupported modifier \"".. modifier .."\" in ".. prefix)
+ end
+ end
+ end
+ end
+ return plan
+end
+
+local function seal_globals()
+ local sealed_mt = {__newindex = function()
+ error("Tests should not mutate global state", 3)
+ end}
+ local function seal(t)
+ if getmetatable(t) then return end
+ setmetatable(t, sealed_mt)
+ for k, v in pairs(t) do
+ if type(v) == "table" then seal(v) end
+ end
+ end
+ seal(_G)
+
+ if getmetatable(package.loaded) == sealed_mt then
+ setmetatable(package.loaded, nil)
+ end
+end
+
+local function check_package_path()
+ local ok, res = pcall(require, "common.test_runner_canary")
+ if not ok then
+ if own_dir then
+ local _, psep, placeholder = package.config:match"^(.-)\n(.-)\n(.-)\n"
+ package.path = package.path .. psep .. own_dir .. placeholder ..".lua"
+ ok, res = pcall(require, "common.test_runner_canary")
+ end
+ if not ok then
+ error(res)
+ end
+ end
+ assert(res == "canary is alive")
+end
+
+local function mutate_plan(plan, opts)
+ if opts.shuffle then
+ math.randomseed(opts.shuffle)
+ for i = #plan, 2, -1 do
+ local n = math_random(1, i)
+ plan[i], plan[n] = plan[n], plan[i]
+ end
+ end
+ if opts.shard then
+ local shard_plan = {}
+ for i = opts.shard.initial, #plan, opts.shard.step do
+ shard_plan[#shard_plan + 1] = plan[i]
+ end
+ plan = shard_plan
+ end
+ if opts.numbers_to_run then
+ for i = 1, #plan do
+ if not opts.numbers_to_run[i] then
+ plan[i][3] = false
+ end
+ end
+ for k in pairs(opts.numbers_to_run) do
+ if not plan[k] then
+ error("Test number ".. k .." is not part of the plan")
+ end
+ end
+ end
+ return plan
+end
+
+local function execute_plan(plan, opts)
+ if #plan == 0 then
+ error("No tests selected")
+ end
+ local progress_format = ("[%%%dd/%d] "):format(#tostring(#plan), #plan)
+ local num_tests_run = 0
+ local fail_numbers = {}
+ for i = 1, #plan do
+ local plan_i = plan[i]
+ local test = plan_i[3]
+ if test then
+ local file, name = plan_i[1], plan_i[2]
+ if not opts.quiet then
+ io_write(progress_format:format(i), file)
+ io_write(file == "" and "" or " --- ", name, "\n")
+ end
+ local ok, err = xpcall(test, debug_traceback)
+ if not ok then
+ if opts.quiet then
+ io_write(progress_format:format(i), file)
+ io_write(file == "" and "" or " --- ", name, "\n")
+ end
+ fail_numbers[#fail_numbers + 1] = i
+ io_write(err, "\n")
+ end
+ num_tests_run = num_tests_run + 1
+ end
+ end
+ if #fail_numbers == 0 then
+ io_write(num_tests_run, " passed\n")
+ return true
+ else
+ io_write(num_tests_run - #fail_numbers, " passed, ")
+ io_write(#fail_numbers, " failed\n")
+ if not opts.quiet and num_tests_run ~= #fail_numbers then
+ io_write("to run just failing tests, pass command line arguments: ")
+ io_write(table.concat(fail_numbers, " "), "\n")
+ end
+ return false
+ end
+end
+
+local opts = parse_args{...}
+if not opts then
+ return
+end
+seal_globals()
+check_package_path()
+local test_tree = scan_tests(opts.root or own_dir or "", opts)
+local plan = append_tree_to_plan(test_tree, opts, {}, "")
+plan = mutate_plan(plan, opts)
+local all_good = execute_plan(plan, opts)
+if not all_good then
+ os.exit(1)
+end
diff --git a/test/LuaJIT-tests/trace/exit_frame.lua b/test/LuaJIT-tests/trace/exit_frame.lua
new file mode 100644
index 0000000..9537c56
--- /dev/null
+++ b/test/LuaJIT-tests/trace/exit_frame.lua
@@ -0,0 +1,79 @@
+do --- global assignments !private_G
+ g = 0
+ gf = 1
+ gz = 2
+
+ local function f(i)
+ if i == 90 then
+ gf = gf + 1
+ return true
+ end
+ g = g + 1
+ end
+
+ local function z(i)
+ if f(i) then
+ gz = gz + 1
+ end
+ end
+
+ for j=1,5 do
+ for i=1,100 do z(i) end
+ end
+
+ assert(g == 495)
+ assert(gf == 6)
+ assert(gz == 7)
+end
+
+do --- mutual recursion
+ local f, g
+ function f(j)
+ if j >= 0 then return g(j-1) end
+ end
+ function g(j)
+ for i=1,200 do
+ if i > 100 then return f(j) end
+ end
+ end
+ for k=1,20 do g(20) end
+end
+
+do --- multi-path mutual recursion
+ local f, g
+ function f(j, k)
+ if j >= 0 then return g(j-1, k) end
+ if k >= 0 then return g(20, k-1) end
+ end
+ function g(j, k)
+ for i=1,200 do
+ if i > 100 then return f(j, k) end
+ end
+ end
+ g(20, 20)
+end
+
+do --- late mutual recursion
+ local k = 0
+ local f, g
+
+ function g(a)
+ -- 'a' is an SLOAD #1 from f's frame and still at slot #1
+ -- Avoid losing a in exit if the SLOAD is ignored
+ if k > 10 then k = 0 end
+ k= k + 1
+ return f(a)
+ end
+
+ function f(a,b,c,d,e)
+ if not e then e =1 end
+ a=a+1
+ if a > 1000 then return end
+ for i=1,100 do
+ e=e+1
+ if i > 90 then return g(a) end
+ end
+ end
+
+ f(1,2,3,4,5)
+end
diff --git a/test/LuaJIT-tests/trace/exit_growstack.lua b/test/LuaJIT-tests/trace/exit_growstack.lua
new file mode 100644
index 0000000..658a31a
--- /dev/null
+++ b/test/LuaJIT-tests/trace/exit_growstack.lua
@@ -0,0 +1,28 @@
+do --- Exit needs to grow stack before slot fill.
+ local function f(i)
+ local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a;
+ local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a;
+ local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a;
+ if i==90 then return end
+ end
+ for j=1,5 do
+ collectgarbage() -- Shrink stack.
+ for i=1,100 do f(i) end
+ end
+end
+
+do --- Exit needs to grow stack after slot fill.
+ local function g(i)
+ if i==90 then return end
+ do return end
+ do
+ local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a;
+ local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a;
+ local a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a;
+ end
+ end
+ for j=1,5 do
+ collectgarbage() -- Shrink stack.
+ for i=1,100 do g(i) end
+ end
+end
diff --git a/test/LuaJIT-tests/trace/exit_jfuncf.lua b/test/LuaJIT-tests/trace/exit_jfuncf.lua
new file mode 100644
index 0000000..67ad7c3
--- /dev/null
+++ b/test/LuaJIT-tests/trace/exit_jfuncf.lua
@@ -0,0 +1,30 @@
+do --- everything
+ local assert = assert
+
+ local function rec(a, b, c, d, e, f)
+ assert(f == a+1)
+ if b == 0 then return 7 end
+ do local x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31, x32, x33, x34, x35, x36, x37, x38, x39, x40, x41, x42, x43, x44, x45, x46, x47, x48, x49, x50, x51, x52, x53, x54, x55, x56, x57, x58, x59, x60, x61, x62, x63, x64, x65, x66, x67, x68, x69, x70, x71, x72, x73, x74, x75, x76, x77, x78, x79, x80, x81, x82, x83, x84, x85, x86, x87, x88, x89, x90, x91, x92, x93, x94, x95, x96, x97, x98, x99, x100 end
+ return rec(a, b-1, c, d, e, f)+1
+ end
+
+ -- Compile recursive function.
+ assert(rec(42, 200, 1, 2, 3, 43) == 207)
+
+ local function trec()
+ return rec(42, 0, 1, 2, 3, 43)
+ end
+
+ -- Compile function jumping to JFUNCF.
+ for i=1,200 do
+ gcinfo()
+ assert(trec() == 7)
+ end
+
+ -- Shrink stack.
+ for j=1,10 do collectgarbage() end
+
+ -- Cause an exit due to stack growth with PC pointing to JFUNCF.
+ -- Needs to load RD with nres+1 and not with the bytecode RD.
+ assert(trec() == 7)
+end
diff --git a/test/LuaJIT-tests/trace/gc64_slot_revival.lua b/test/LuaJIT-tests/trace/gc64_slot_revival.lua
new file mode 100644
index 0000000..40b9d87
--- /dev/null
+++ b/test/LuaJIT-tests/trace/gc64_slot_revival.lua
@@ -0,0 +1,18 @@
+do --- BC_KNIL
+ local function f(x, y) end
+ for i = 1,100 do
+ f(i, i)
+ f(nil, nil)
+ end
+end
+
+do --- BC_VARG
+ local function f() end
+ local function g(...)
+ f()
+ f(...)
+ end
+ for i = 1,100 do
+ g()
+ end
+end
diff --git a/test/LuaJIT-tests/trace/index b/test/LuaJIT-tests/trace/index
new file mode 100644
index 0000000..ea7a22e
--- /dev/null
+++ b/test/LuaJIT-tests/trace/index
@@ -0,0 +1,7 @@
+exit_frame.lua
+exit_growstack.lua
+exit_jfuncf.lua
+gc64_slot_revival.lua
+phi
+snap.lua
+stitch.lua
diff --git a/test/LuaJIT-tests/trace/phi/copyspill.lua b/test/LuaJIT-tests/trace/phi/copyspill.lua
new file mode 100644
index 0000000..17a8698
--- /dev/null
+++ b/test/LuaJIT-tests/trace/phi/copyspill.lua
@@ -0,0 +1,53 @@
+do --- mat4mul !private_G
+function mat4mul(a11, a21, a31, a41,
+ a12, a22, a32, a42,
+ a13, a23, a33, a43,
+ a14, a24, a34, a44,
+ b11, b21, b31, b41,
+ b12, b22, b32, b42,
+ b13, b23, b33, b43,
+ b14, b24, b34, b44)
+ return a11*b11+a21*b12+a31*b13+a41*b14,
+ a11*b21+a21*b22+a31*b23+a41*b24,
+ a11*b31+a21*b32+a31*b33+a41*b34,
+ a11*b41+a21*b42+a31*b43+a41*b44,
+ a12*b11+a22*b12+a32*b13+a42*b14,
+ a12*b21+a22*b22+a32*b23+a42*b24,
+ a12*b31+a22*b32+a32*b33+a42*b34,
+ a12*b41+a22*b42+a32*b43+a42*b44,
+ a13*b11+a23*b12+a33*b13+a43*b14,
+ a13*b21+a23*b22+a33*b23+a43*b24,
+ a13*b31+a23*b32+a33*b33+a43*b34,
+ a13*b41+a23*b42+a33*b43+a43*b44,
+ a14*b11+a24*b12+a34*b13+a44*b14,
+ a14*b21+a24*b22+a34*b23+a44*b24,
+ a14*b31+a24*b32+a34*b33+a44*b34,
+ a14*b41+a24*b42+a34*b43+a44*b44
+end
+
+local a11, a21, a31, a41 = 1, 0, 0, 0
+local a12, a22, a32, a42 = 0, 1, 0, 0
+local a13, a23, a33, a43 = 0, 0, 1, 0
+local a14, a24, a34, a44 = 0, 0, 0, 1
+
+local b11, b21, b31, b41 = 0, 0, -1, 0
+local b12, b22, b32, b42 = 0, 1, 0, 0
+local b13, b23, b33, b43 = 1, 0, 0, 0
+local b14, b24, b34, b44 = 0, 0, 0, 1
+
+for i = 1, 1000 do
+ a11, a21, a31, a41,
+ a12, a22, a32, a42,
+ a13, a23, a33, a43,
+ a14, a24, a34, a44 = mat4mul(a11, a21, a31, a41,
+ a12, a22, a32, a42,
+ a13, a23, a33, a43,
+ a14, a24, a34, a44,
+ b11, b21, b31, b41,
+ b12, b22, b32, b42,
+ b13, b23, b33, b43,
+ b14, b24, b34, b44)
+end
+assert(a11 == 1)
+assert(a31 == 0)
+end
diff --git a/test/LuaJIT-tests/trace/phi/index b/test/LuaJIT-tests/trace/phi/index
new file mode 100644
index 0000000..74a0733
--- /dev/null
+++ b/test/LuaJIT-tests/trace/phi/index
@@ -0,0 +1,3 @@
+copyspill.lua
+ref.lua
+rotate.lua
diff --git a/test/LuaJIT-tests/trace/phi/ref.lua b/test/LuaJIT-tests/trace/phi/ref.lua
new file mode 100644
index 0000000..3662912
--- /dev/null
+++ b/test/LuaJIT-tests/trace/phi/ref.lua
@@ -0,0 +1,131 @@
+do --- rref points into invariant part 1
+ local x,y=1,2; for i=1,100 do x=x+y; y=i end
+ assert(y == 100)
+end
+
+do --- rref points into invariant part 2
+ local x,y=1,2; for i=1,100.5 do x=x+y; y=i end
+ assert(y == 100)
+end
+
+do --- rref points into invariant part 3
+ local x,y=1,2; for i=1,100 do x,y=y,x end
+ assert(x == 1)
+ assert(y == 2)
+end
+
+do --- rref points into invariant part 4
+ local x,y,z=1,2,3; for i=1,100 do x,y,z=y,z,x end
+ assert(x == 2)
+ assert(y == 3)
+ assert(z == 1)
+end
+
+do --- rref points into invariant part 5
+ local x,y,z=1,2,3; for i=1,100 do x,y,z=z,x,y end
+ assert(x == 3)
+ assert(y == 1)
+ assert(z == 2)
+end
+
+do --- rref points into invariant part 6
+ local a,x,y,z=0,1,2,3; for i=1,100 do a=a+x; x=y; y=z; z=i end
+ assert(a == 4759)
+ assert(x == 98)
+ assert(y == 99)
+ assert(z == 100)
+end
+
+do --- variant slot, but no corresponding SLOAD i-1
+ local x,y=1,2; for i=1,100 do x=i; y=i-1 end
+ assert(x == 100)
+ assert(y == 99)
+end
+
+do --- variant slot, but no corresponding SLOAD i+1
+ local x,y=1,2; for i=1,100 do x=i; y=i+1 end
+ assert(x == 100)
+ assert(y == 101)
+end
+
+do --- variant slot, but no corresponding SLOAD side exit
+ local x=0; for i=1,100 do if i==90 then break end x=i end
+ assert(x == 89)
+end
+
+do --- dup lref from variant slot (suppressed)
+ local x,y=1,2; for i=1,100 do x=i; y=i end
+ assert(x == 100)
+ assert(y == 100)
+end
+
+do --- const rref
+ local x,y=1,2 local bxor,tobit=bit.bxor,bit.tobit;
+ for i=1,100 do x=bxor(i,y); y=tobit(i+1) end
+ assert(x == 0)
+ assert(y == 101)
+end
+
+do --- dup rref (ok)
+ local x,y,z1,z2=1,2,3,4 local bxor,tobit=bit.bxor,bit.tobit;
+ for i=1,100 do x=bxor(i,y); z2=tobit(i+5); z1=bxor(x,i+5); y=tobit(i+1) end
+ assert(x == 0)
+ assert(y == 101)
+ assert(z1 == 105)
+ assert(z2 == 105)
+end
+
+do --- variant slot, no corresponding SLOAD
+ for i=1,5 do
+ local a, b = 1, 2
+ local bits = 0
+ while a ~= b do
+ bits = bits + 1
+ a = b
+ b = bit.lshift(b, 1)
+ end
+ assert(bits == 32)
+ end
+end
+
+do --- don't eliminate PHI if referenced from snapshot
+ local t = { 0 }
+ local a = 0
+ for i=1,100 do
+ local b = t[1]
+ t[1] = i + a
+ a = b
+ end
+ assert(a == 2500)
+ assert(t[1] == 2550)
+end
+
+do --- don't eliminate PHI if referenced from snapshot
+ local x = 1
+ local function f()
+ local t = {}
+ for i=1,200 do t[i] = i end
+ for i=1,200 do
+ local x1 = x
+ x = t[i]
+ if i > 100 then return x1 end
+ end
+ end
+ assert(f() == 100)
+end
+
+do --- don't eliminate PHI if referenced from another non-redundant PHI
+ local t = {}
+ for i=1,256 do
+ local a, b, k = i, math.floor(i/2), -i
+ while a > 1 and t[b] > k do
+ t[a] = t[b]
+ a = b
+ b = math.floor(a/2)
+ end
+ t[a] = k
+ end
+ local x = 0
+ for i=1,256 do x = x + bit.bxor(i, t[i]) end
+ assert(x == -41704)
+end
diff --git a/test/LuaJIT-tests/trace/phi/rotate.lua b/test/LuaJIT-tests/trace/phi/rotate.lua
new file mode 100644
index 0000000..cb751e0
--- /dev/null
+++ b/test/LuaJIT-tests/trace/phi/rotate.lua
@@ -0,0 +1,149 @@
+do --- rot8
+ local function rot8r(n)
+ local a,b,c,d,e,f,g,h=1,2,3,4,5,6,7,8
+ for x=1,n do
+ a,b,c,d,e,f,g,h=h,a,b,c,d,e,f,g
+ end
+ return table.concat{a,b,c,d,e,f,g,h}
+ end
+
+ local function rot8l(n)
+ local a,b,c,d,e,f,g,h=1,2,3,4,5,6,7,8
+ for x=1,n do
+ a,b,c,d,e,f,g,h=b,c,d,e,f,g,h,a
+ end
+ return table.concat{a,b,c,d,e,f,g,h}
+ end
+
+ assert(rot8r(0) == "12345678")
+ assert(rot8r(10) == "78123456")
+ assert(rot8r(105) == "81234567")
+ assert(rot8r(0) == "12345678")
+ assert(rot8r(1) == "81234567")
+ assert(rot8r(2) == "78123456")
+ assert(rot8r(0) == "12345678")
+ assert(rot8r(1) == "81234567")
+ assert(rot8r(2) == "78123456")
+ assert(rot8r(105) == "81234567")
+
+ assert(rot8l(0) == "12345678")
+ assert(rot8l(10) == "34567812")
+ assert(rot8l(105) == "23456781")
+ assert(rot8l(0) == "12345678")
+ assert(rot8l(1) == "23456781")
+ assert(rot8l(2) == "34567812")
+ assert(rot8l(0) == "12345678")
+ assert(rot8l(1) == "23456781")
+ assert(rot8l(2) == "34567812")
+
+ assert(rot8r(100) == "56781234")
+ assert(rot8l(100) == "56781234")
+end
+
+do --- rot9
+ local function rot9r(n)
+ local a,b,c,d,e,f,g,h,i=1,2,3,4,5,6,7,8,9
+ for x=1,n do
+ a,b,c,d,e,f,g,h,i=i,a,b,c,d,e,f,g,h
+ end
+ return table.concat{a,b,c,d,e,f,g,h,i}
+ end
+
+ local function rot9l(n)
+ local a,b,c,d,e,f,g,h,i=1,2,3,4,5,6,7,8,9
+ for x=1,n do
+ a,b,c,d,e,f,g,h,i=b,c,d,e,f,g,h,i,a
+ end
+ return table.concat{a,b,c,d,e,f,g,h,i}
+ end
+
+ assert(rot9r(0) == "123456789")
+ assert(rot9r(10) == "912345678")
+ assert(rot9r(105) == "456789123")
+ assert(rot9r(0) == "123456789")
+ assert(rot9r(1) == "912345678")
+ assert(rot9r(2) == "891234567")
+ assert(rot9r(0) == "123456789")
+ assert(rot9r(1) == "912345678")
+ assert(rot9r(2) == "891234567")
+ assert(rot9r(105) == "456789123")
+
+ assert(rot9l(0) == "123456789")
+ assert(rot9l(10) == "234567891")
+ assert(rot9l(105) == "789123456")
+ assert(rot9l(0) == "123456789")
+ assert(rot9l(1) == "234567891")
+ assert(rot9l(2) == "345678912")
+ assert(rot9l(0) == "123456789")
+ assert(rot9l(1) == "234567891")
+ assert(rot9l(2) == "345678912")
+
+ assert(rot9r(100) == "912345678")
+ assert(rot9l(100) == "234567891")
+end
+
+do --- rot18
+ local function rot18r(N)
+ local a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18
+ for x=1,N do
+ a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r=r,a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q
+ end
+ return table.concat{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r}
+ end
+
+ local function rot18l(N)
+ local a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18
+ for x=1,N do
+ a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r=b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,a
+ end
+ return table.concat{a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r}
+ end
+
+ assert(rot18r(0) == "123456789101112131415161718")
+ assert(rot18r(10) == "910111213141516171812345678")
+ assert(rot18r(105) == "456789101112131415161718123")
+ assert(rot18r(0) == "123456789101112131415161718")
+ assert(rot18r(1) == "181234567891011121314151617")
+ assert(rot18r(2) == "171812345678910111213141516")
+ assert(rot18r(0) == "123456789101112131415161718")
+ assert(rot18r(1) == "181234567891011121314151617")
+ assert(rot18r(2) == "171812345678910111213141516")
+ assert(rot18r(105) == "456789101112131415161718123")
+
+ assert(rot18l(0) == "123456789101112131415161718")
+ assert(rot18l(10) == "111213141516171812345678910")
+ assert(rot18l(105) == "161718123456789101112131415")
+ assert(rot18l(0) == "123456789101112131415161718")
+ assert(rot18l(1) == "234567891011121314151617181")
+ assert(rot18l(2) == "345678910111213141516171812")
+ assert(rot18l(0) == "123456789101112131415161718")
+ assert(rot18l(1) == "234567891011121314151617181")
+ assert(rot18l(2) == "345678910111213141516171812")
+
+ assert(rot18r(100) == "910111213141516171812345678")
+ assert(rot18l(100) == "111213141516171812345678910")
+end
+
+do --- rotx
+ local function rot9r(n, m)
+ local a,b,c,d,e,f,g,h,i=1,2,3,4,5,6,7,8,9
+ local s = ""
+ for x=1,n do
+ a,b,c,d,e,f,g,h,i=i,a,b,c,d,e,f,g,h
+ if x == m then s = table.concat{a,b,c,d,e,f,g,h,i} end
+ c,d = d,c
+ end
+ return table.concat{a,b,c,d,e,f,g,h,i, s}
+ end
+
+ assert(rot9r(0,0) == "123456789")
+ assert(rot9r(10,0) == "893124567")
+ assert(rot9r(105,0) == "913245678")
+ assert(rot9r(105,90) == "913245678891324567")
+ assert(rot9r(0,0) == "123456789")
+ assert(rot9r(1,0) == "913245678")
+ assert(rot9r(2,0) == "893124567")
+ assert(rot9r(1,1) == "913245678912345678")
+ assert(rot9r(2,1) == "893124567912345678")
+ assert(rot9r(2,2) == "893124567891324567")
+end
diff --git a/test/LuaJIT-tests/trace/snap.lua b/test/LuaJIT-tests/trace/snap.lua
new file mode 100644
index 0000000..ba26326
--- /dev/null
+++ b/test/LuaJIT-tests/trace/snap.lua
@@ -0,0 +1,47 @@
+do --- gcexit
+ local x = 0
+ local t
+ for i=1,1000 do
+ if i >= 100 then
+ -- causes an exit for atomic phase
+ -- must not merge snapshot #0 with comparison since it has the wrong PC
+ if i < 150 then x=x+1 end
+ t = {i}
+ end
+ end
+ assert(x == 50)
+ assert(t[1] == 1000)
+end
+
+
+do --- top !private_G
+ function randomtable(entries, depth)
+ if depth == 0 then
+ return tostring(math.random(2)) -- snapshot between return and CALLMT
+ end
+ local t = {}
+ for k=1,entries do
+ t[k] = randomtable(entries, depth-1)
+ end
+ return t
+ end
+
+ local t = randomtable(10, 2)
+end
+
+do --- top2
+ local function f()
+ gcinfo()
+ local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_
+ local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_
+ local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_
+ local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_
+ local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_
+ local _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_
+ end
+
+ for i=1,100 do
+ f()
+ if i % 3 == 0 then collectgarbage() end
+ end
+end
diff --git a/test/LuaJIT-tests/trace/stitch.lua b/test/LuaJIT-tests/trace/stitch.lua
new file mode 100644
index 0000000..3f7f973
--- /dev/null
+++ b/test/LuaJIT-tests/trace/stitch.lua
@@ -0,0 +1,19 @@
+do --- octal
+ local tonumber = tonumber
+ local function octal(s) return tonumber(s, 8) end
+ for i=1,100 do
+ octal("1")
+ octal("1")
+ octal("1")
+ end
+end
+
+do --- coroutines
+ local t = {
+ [0] = function() end,
+ coroutine.wrap(function() while true do coroutine.yield() end end),
+ }
+ for i=1,100 do
+ t[i % 2]()
+ end
+end
diff --git a/test/LuaJIT-tests/unportable/ffi_arith_int64.lua b/test/LuaJIT-tests/unportable/ffi_arith_int64.lua
new file mode 100644
index 0000000..c05e02a
--- /dev/null
+++ b/test/LuaJIT-tests/unportable/ffi_arith_int64.lua
@@ -0,0 +1,68 @@
+local ffi = require("ffi")
+
+local int = ffi.typeof("int")
+
+local inp = {
+ 0, 0.5, -0.5, 1.5, -1.5, 1, -1, 2, -2, 37, -37, false,
+ int(0), int(1), int(-1), int(2), int(-2), int(37), int(-37), false,
+ 0ll, 1ll, -1ll, 2ll, -2ll, 37ll, -37ll, false,
+ 0ull, 1ull, -1ull, 2ull, -2ull, 37ull, -37ull,
+}
+
+local function cksum(s, r)
+ local z = 0
+ for i=1,#s do z = (z + string.byte(s, i)*i) % 2147483629 end
+ if z ~= r then
+ error("test failed (got "..z..", expected "..r..") for:\n"..s, 3)
+ end
+end
+
+local function tostr(n)
+ if type(n) == "cdata" then return tostring(n)
+ elseif n ~= n then return "nan"
+ else return string.format("%+1.5g", n) end
+end
+
+local function check(f, expected, y)
+ local inp = inp
+ local out = {}
+ for i=1,#inp do
+ if inp[i] then out[i] = tostr(f(inp[i], y)) else out[i] = "\n" end
+ end
+ local got = string.gsub(table.concat(out, " ").."\n", "\n ", "\n")
+ cksum(got, expected)
+end
+
+jit.off(check)
+
+local function check2(f, exparray)
+ local k = 1
+ for j=1,#inp do
+ local y = inp[j]
+ if y then
+ check(f, exparray[k], y)
+ k = k + 1
+ end
+ end
+end
+
+check(function(x) return -x end, 1174528)
+
+check2(function(x, y) return x+y end,
+{1171039,1239261,1239303,1011706,1490711,949996,1415869,756412,1682910,768883,2201023,1265370,1015700,1556902,807607,1862947,814710,2423097,1265370,1015700,1556902,807607,1862947,814710,2423097,4833809,2909723,7784653,1736671,10743770,1126700,13324037,})
+
+check2(function(x, y) return x-y end,
+{1171039,1239303,1239261,1490711,1011706,1415869,949996,1682910,756412,2201023,768883,1265370,1556902,1015700,1862947,807607,2423097,814710,1265370,1556902,1015700,1862947,807607,2423097,814710,4833809,7784653,2909723,10743770,1736671,13324037,1126700,})
+
+check2(function(x, y) return x*y end,
+{470257,637182,637132,1308150,1311627,1171039,1174528,1083877,1087553,1561321,1564869,564568,1265370,1269122,1265037,1268973,1643392,1647266,564568,1265370,1269122,1265037,1268973,1643392,1647266,827768,4833809,4847593,4823713,4838210,5230281,5244035,})
+
+check2(function(x, y) return x/y end,
+{7946210,7360895,7360865,1580465,927251,1171039,622069,1252901,704706,1542087,960011,14749620,1265370,695208,1188639,661058,1049280,587329,14749620,1265370,695208,1188639,661058,1049280,587329,15042810,4833809,828129,4559889,828509,4208862,828929,})
+
+
+check2(function(x, y) return x%y end,
+{7653740,7304160,7304160,527871,851988,527061,850910,556674,717022,610671,613599,14749620,564568,894526,618652,785052,641760,644574,14749620,564568,894526,618652,785052,641760,644574,15042810,827768,2913108,829285,1737261,951059,959905,})
+
+check2(function(x, y) return x^y end,
+{471871,702627,720692,1385612,1803393,1171039,1772007,763817,1583994,4486762,2380423,566647,1265370,2319256,770581,1990479,4566660,2319835,566647,1265370,2319256,770581,1990479,4566660,2319835,830322,4833809,4644705,1071753,2822313,7709069,4647021,})
diff --git a/test/LuaJIT-tests/unportable/math_special.lua b/test/LuaJIT-tests/unportable/math_special.lua
new file mode 100644
index 0000000..4916101
--- /dev/null
+++ b/test/LuaJIT-tests/unportable/math_special.lua
@@ -0,0 +1,55 @@
+
+local inp = { 0, -"0", 0.5, -0.5, 1, -1, 1/0, -1/0, 0/0 }
+
+local function tostr(n)
+ if n == 0 and 1/n < 0 then return "-0"
+ elseif 1/n == 0 then return n < 0 and "-inf" or "+inf"
+ elseif n ~= n then return "nan"
+ else return string.format("%+1.5g", n) end
+end
+
+local function check(f, expected)
+ local inp = inp
+ local out = {}
+ for i=1,#inp do out[i] = tostr(f(inp[i])) end
+ local got = table.concat(out, " ")
+ if got ~= expected then
+ error("got: \""..got.."\"\nexpected: \""..expected.."\"", 2)
+ end
+end
+
+check(function(x) return x end, "+0 -0 +0.5 -0.5 +1 -1 +inf -inf nan")
+
+local powcheck = {
+ "+1 +1 +1 +1 +1 +1 +1 +1 +1",
+ "+1 +1 +1 +1 +1 +1 +1 +1 +1",
+ "+0 +0 +0.70711 nan +1 nan +inf +inf nan",
+ "+inf +inf +1.4142 nan +1 nan +0 +0 nan",
+ "+0 -0 +0.5 -0.5 +1 -1 +inf -inf nan",
+ "+inf -inf +2 -2 +1 -1 +0 -0 nan",
+ "+0 +0 +0 +0 +1 +1 +inf +inf nan",
+ "+inf +inf +inf +inf +1 +1 +0 +0 nan",
+ "nan nan nan nan +1 nan nan nan nan",
+}
+for j=1,#inp do
+ local y = inp[j]
+ check(function(x) return x^y end, powcheck[j])
+end
+
+check(math.abs, "+0 +0 +0.5 +0.5 +1 +1 +inf +inf nan")
+check(math.floor, "+0 -0 +0 -1 +1 -1 +inf -inf nan")
+check(math.ceil, "+0 -0 +1 -0 +1 -1 +inf -inf nan")
+check(math.sqrt, "+0 -0 +0.70711 nan +1 nan +inf nan nan")
+check(math.sin, "+0 -0 +0.47943 -0.47943 +0.84147 -0.84147 nan nan nan")
+check(math.cos, "+1 +1 +0.87758 +0.87758 +0.5403 +0.5403 nan nan nan")
+check(math.tan, "+0 -0 +0.5463 -0.5463 +1.5574 -1.5574 nan nan nan")
+check(math.asin, "+0 -0 +0.5236 -0.5236 +1.5708 -1.5708 nan nan nan")
+check(math.acos, "+1.5708 +1.5708 +1.0472 +2.0944 +0 +3.1416 nan nan nan")
+check(math.atan, "+0 -0 +0.46365 -0.46365 +0.7854 -0.7854 +1.5708 -1.5708 nan")
+check(math.log, "-inf -inf -0.69315 nan +0 nan +inf nan nan")
+check(math.log10, "-inf -inf -0.30103 nan +0 nan +inf nan nan")
+check(math.exp, "+1 +1 +1.6487 +0.60653 +2.7183 +0.36788 +inf +0 nan")
+
+-- Pointless: deg, rad, min, max, pow
+-- LATER: %, fmod, frexp, ldexp, modf, sinh, cosh, tanh
+
--
2.28.0
^ permalink raw reply [flat|nested] 26+ messages in thread