From 866cb79f65c844b3fcfa99d2caa4bf19930dbc6d Mon Sep 17 00:00:00 2001 From: Philipp Janda Date: Tue, 20 Jan 2015 11:35:16 +0100 Subject: luajit already has yieldable (x)pcall, add tests for code from compat52 --- README.md | 5 +- c-api/compat-5.3.h | 1 + compat53.lua | 318 ++++++++++++++++++++++++------------------------ tests/test.lua | 346 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 511 insertions(+), 159 deletions(-) diff --git a/README.md b/README.md index 26800e3..c04d2d1 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,8 @@ For Lua 5.1 additionally: * `luaL_Stream` * `LUA_FILEHANDLE` * `lua_absindex` +* `lua_arith` +* `lua_compare` * `lua_len`, `lua_rawlen`, and `luaL_len` * `lua_copy` * `lua_pushglobaltable` @@ -141,9 +143,8 @@ For Lua 5.1 additionally: * the following C API functions/macros: * `lua_isyieldable` * `lua_getextraspace` - * `lua_arith` (not at all in 5.1, operators missing in 5.2) + * `lua_arith` (new operators missing) * `lua_pushfstring` (new formats) - * `lua_compare` (5.1) * `lua_upvalueid` (5.1) * `lua_upvaluejoin` (5.1) * `lua_version` (5.1) diff --git a/c-api/compat-5.3.h b/c-api/compat-5.3.h index 3905a10..8f38719 100644 --- a/c-api/compat-5.3.h +++ b/c-api/compat-5.3.h @@ -40,6 +40,7 @@ #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 /* XXX not implemented: + * lua_arith (new operators) * lua_upvalueid * lua_upvaluejoin * lua_version diff --git a/compat53.lua b/compat53.lua index 5f88e8b..67a8c8f 100644 --- a/compat53.lua +++ b/compat53.lua @@ -336,12 +336,12 @@ if lua_version < "5.3" then function debug.setuservalue(obj, value) if type(obj) ~= "userdata" then error("bad argument #1 to 'setuservalue' (userdata expected, got ".. - type(obj)..")", 0) + type(obj)..")", 2) end if value == nil then value = _G end if type(value) ~= "table" then error("bad argument #2 to 'setuservalue' (table expected, got ".. - type(value)..")", 0) + type(value)..")", 2) end return debug_setfenv(obj, value) end @@ -366,96 +366,98 @@ if lua_version < "5.3" then end end -- not luajit with compat52 enabled - local debug_getinfo = debug.getinfo - local function calculate_trace_level(co, level) - if level ~= nil then - for out = 1, 1/0 do - local info = (co==nil) and debug_getinfo(out, "") or debug_getinfo(co, out, "") - if info == nil then - local max = out-1 - if level <= max then - return level + if not is_luajit then + local debug_getinfo = debug.getinfo + local function calculate_trace_level(co, level) + if level ~= nil then + for out = 1, 1/0 do + local info = (co==nil) and debug_getinfo(out, "") or debug_getinfo(co, out, "") + if info == nil then + local max = out-1 + if level <= max then + return level + end + return nil, level-max end - return nil, level-max end end + return 1 end - return 1 - end - local stack_pattern = "\nstack traceback:" - local stack_replace = "" - local debug_traceback = debug.traceback - function debug.traceback(co, msg, level) - local lvl - local nilmsg - if type(co) ~= "thread" then - co, msg, level = coroutine_running(), co, msg - end - if msg == nil then - msg = "" - nilmsg = true - elseif type(msg) ~= "string" then - return msg - end - if co == nil then - msg = debug_traceback(msg, level or 1) - else - local xpco = xpcall_running[co] - if xpco ~= nil then - lvl, level = calculate_trace_level(xpco, level) - if lvl then - msg = debug_traceback(xpco, msg, lvl) - else - msg = msg..stack_pattern - end - lvl, level = calculate_trace_level(co, level) - if lvl then - local trace = debug_traceback(co, "", lvl) - msg = msg..trace:gsub(stack_pattern, stack_replace) - end + local stack_pattern = "\nstack traceback:" + local stack_replace = "" + local debug_traceback = debug.traceback + function debug.traceback(co, msg, level) + local lvl + local nilmsg + if type(co) ~= "thread" then + co, msg, level = coroutine_running(), co, msg + end + if msg == nil then + msg = "" + nilmsg = true + elseif type(msg) ~= "string" then + return msg + end + if co == nil then + msg = debug_traceback(msg, level or 1) else - co = pcall_callOf[co] or co - lvl, level = calculate_trace_level(co, level) - if lvl then - msg = debug_traceback(co, msg, lvl) + local xpco = xpcall_running[co] + if xpco ~= nil then + lvl, level = calculate_trace_level(xpco, level) + if lvl then + msg = debug_traceback(xpco, msg, lvl) + else + msg = msg..stack_pattern + end + lvl, level = calculate_trace_level(co, level) + if lvl then + local trace = debug_traceback(co, "", lvl) + msg = msg..trace:gsub(stack_pattern, stack_replace) + end else - msg = msg..stack_pattern - end - end - co = pcall_previous[co] - while co ~= nil do - lvl, level = calculate_trace_level(co, level) - if lvl then - local trace = debug_traceback(co, "", lvl) - msg = msg..trace:gsub(stack_pattern, stack_replace) + co = pcall_callOf[co] or co + lvl, level = calculate_trace_level(co, level) + if lvl then + msg = debug_traceback(co, msg, lvl) + else + msg = msg..stack_pattern + end end co = pcall_previous[co] + while co ~= nil do + lvl, level = calculate_trace_level(co, level) + if lvl then + local trace = debug_traceback(co, "", lvl) + msg = msg..trace:gsub(stack_pattern, stack_replace) + end + co = pcall_previous[co] + end + end + if nilmsg then + msg = msg:gsub("^\n", "") end + msg = msg:gsub("\n\t%(tail call%): %?", "\000") + msg = msg:gsub("\n\t%.%.%.\n", "\001\n") + msg = msg:gsub("\n\t%.%.%.$", "\001") + msg = msg:gsub("(%z+)\001(%z+)", function(some, other) + return "\n\t(..."..#some+#other.."+ tail call(s)...)" + end) + msg = msg:gsub("\001(%z+)", function(zeros) + return "\n\t(..."..#zeros.."+ tail call(s)...)" + end) + msg = msg:gsub("(%z+)\001", function(zeros) + return "\n\t(..."..#zeros.."+ tail call(s)...)" + end) + msg = msg:gsub("%z+", function(zeros) + return "\n\t(..."..#zeros.." tail call(s)...)" + end) + msg = msg:gsub("\001", function(zeros) + return "\n\t..." + end) + return msg end - if nilmsg then - msg = msg:gsub("^\n", "") - end - msg = msg:gsub("\n\t%(tail call%): %?", "\000") - msg = msg:gsub("\n\t%.%.%.\n", "\001\n") - msg = msg:gsub("\n\t%.%.%.$", "\001") - msg = msg:gsub("(%z+)\001(%z+)", function(some, other) - return "\n\t(..."..#some+#other.."+ tail call(s)...)" - end) - msg = msg:gsub("\001(%z+)", function(zeros) - return "\n\t(..."..#zeros.."+ tail call(s)...)" - end) - msg = msg:gsub("(%z+)\001", function(zeros) - return "\n\t(..."..#zeros.."+ tail call(s)...)" - end) - msg = msg:gsub("%z+", function(zeros) - return "\n\t(..."..#zeros.." tail call(s)...)" - end) - msg = msg:gsub("\001", function(zeros) - return "\n\t..." - end) - return msg - end + end -- is not luajit end -- debug table available @@ -501,7 +503,7 @@ if lua_version < "5.3" then local ld_type = type(ld) if ld_type ~= "function" then error("bad argument #1 to 'load' (function expected, got ".. - ld_type..")", 0) + ld_type..")", 2) end if mode ~= "bt" then local checked, merr = false, nil @@ -564,7 +566,7 @@ if lua_version < "5.3" then function rawlen(v) local t = type(v) if t ~= "string" and t ~= "table" then - error("bad argument #1 to 'rawlen' (table or string expected)", 0) + error("bad argument #1 to 'rawlen' (table or string expected)", 2) end return #v end @@ -622,92 +624,94 @@ if lua_version < "5.3" then local coroutine_yield = coroutine.yield function coroutine.yield(...) - local co = coroutine_running() - if co then + local co, flag = coroutine_running() + if co and not flag then return coroutine_yield(...) else error("attempt to yield from outside a coroutine", 0) end end - local coroutine_resume = coroutine.resume - function coroutine.resume(co, ...) - if co == main_coroutine then - return false, "cannot resume non-suspended coroutine" - else - return coroutine_resume(co, ...) + if not is_luajit then + local coroutine_resume = coroutine.resume + function coroutine.resume(co, ...) + if co == main_coroutine then + return false, "cannot resume non-suspended coroutine" + else + return coroutine_resume(co, ...) + end end - end - local coroutine_status = coroutine.status - function coroutine.status(co) - local notmain = coroutine_running() - if co == main_coroutine then - return notmain and "normal" or "running" - else - return coroutine_status(co) + local coroutine_status = coroutine.status + function coroutine.status(co) + local notmain = coroutine_running() + if co == main_coroutine then + return notmain and "normal" or "running" + else + return coroutine_status(co) + end end - end - local function pcall_results(current, call, success, ...) - if coroutine_status(call) == "suspended" then - return pcall_results(current, call, coroutine_resume(call, coroutine_yield(...))) + local function pcall_results(current, call, success, ...) + if coroutine_status(call) == "suspended" then + return pcall_results(current, call, coroutine_resume(call, coroutine_yield(...))) + end + if pcall_previous then + pcall_previous[call] = nil + local main = pcall_mainOf[call] + if main == current then current = nil end + pcall_callOf[main] = current + end + pcall_mainOf[call] = nil + return success, ... end - if pcall_previous then - pcall_previous[call] = nil - local main = pcall_mainOf[call] - if main == current then current = nil end - pcall_callOf[main] = current + local function pcall_exec(current, call, ...) + local main = pcall_mainOf[current] or current + pcall_mainOf[call] = main + if pcall_previous then + pcall_previous[call] = current + pcall_callOf[main] = call + end + return pcall_results(current, call, coroutine_resume(call, ...)) end - pcall_mainOf[call] = nil - return success, ... - end - local function pcall_exec(current, call, ...) - local main = pcall_mainOf[current] or current - pcall_mainOf[call] = main - if pcall_previous then - pcall_previous[call] = current - pcall_callOf[main] = call + local coroutine_create52 = coroutine.create + local function pcall_coroutine(func) + if type(func) ~= "function" then + local callable = func + func = function (...) return callable(...) end + end + return coroutine_create52(func) end - return pcall_results(current, call, coroutine_resume(call, ...)) - end - local coroutine_create52 = coroutine.create - local function pcall_coroutine(func) - if type(func) ~= "function" then - local callable = func - func = function (...) return callable(...) end + function pcall(func, ...) + local current = coroutine_running() + if not current then return _pcall(func, ...) end + return pcall_exec(current, pcall_coroutine(func), ...) end - return coroutine_create52(func) - end - function pcall(func, ...) - local current = coroutine_running() - if not current then return _pcall(func, ...) end - return pcall_exec(current, pcall_coroutine(func), ...) - end - local function xpcall_catch(current, call, msgh, success, ...) - if not success then - xpcall_running[current] = call - local ok, result = _pcall(msgh, ...) - xpcall_running[current] = nil - if not ok then - return false, "error in error handling ("..tostring(result)..")" + local function xpcall_catch(current, call, msgh, success, ...) + if not success then + xpcall_running[current] = call + local ok, result = _pcall(msgh, ...) + xpcall_running[current] = nil + if not ok then + return false, "error in error handling ("..tostring(result)..")" + end + return false, result end - return false, result + return true, ... end - return true, ... - end - local _xpcall = xpcall - local _unpack = unpack - function xpcall(f, msgh, ...) - local current = coroutine_running() - if not current then - local args, n = { ... }, select('#', ...) - return _xpcall(function() return f(_unpack(args, 1, n)) end, msgh) + local _xpcall = xpcall + local _unpack = unpack + function xpcall(f, msgh, ...) + local current = coroutine_running() + if not current then + local args, n = { ... }, select('#', ...) + return _xpcall(function() return f(_unpack(args, 1, n)) end, msgh) + end + local call = pcall_coroutine(f) + return xpcall_catch(current, call, msgh, pcall_exec(current, call, ...)) end - local call = pcall_coroutine(f) - return xpcall_catch(current, call, msgh, pcall_exec(current, call, ...)) - end + end -- not luajit if not is_luajit then @@ -806,6 +810,7 @@ if lua_version < "5.3" then return addqt[c] or string_format("\\%03d", c:byte()) end + local _unpack = unpack function string.format(fmt, ...) local args, n = { ... }, select('#', ...) local i = 0 @@ -846,12 +851,13 @@ if lua_version < "5.3" then if var_1 == nil then if st.doclose then st.f:close() end if (...) ~= nil then - error((...), 0) + error((...), 2) end end return var_1, ... end + local _unpack = unpack function lines_iterator(st) return helper(st, st.f:read(_unpack(st, 1, st.n))) end @@ -864,14 +870,14 @@ if lua_version < "5.3" then local doclose, file, msg if fname ~= nil then doclose, file, msg = true, io_open(fname, "r") - if not file then error(msg, 0) end + if not file then error(msg, 2) end else doclose, file = false, io_input() end local st = { f=file, doclose=doclose, n=select('#', ...), ... } for i = 1, st.n do if type(st[i]) ~= "number" and not valid_format[st[i]] then - error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 0) + error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) end end return lines_iterator, st @@ -894,12 +900,12 @@ if lua_version < "5.3" then file_meta.__index.lines = function(self, ...) if io_type(self) == "closed file" then - error("attempt to use a closed file", 0) + error("attempt to use a closed file", 2) end local st = { f=self, doclose=false, n=select('#', ...), ... } for i = 1, st.n do if type(st[i]) ~= "number" and not valid_format[st[i]] then - error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 0) + error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) end end return lines_iterator, st diff --git a/tests/test.lua b/tests/test.lua index 423fb5b..98259fe 100755 --- a/tests/test.lua +++ b/tests/test.lua @@ -1,8 +1,9 @@ #!/usr/bin/env lua -local F, tproxy, ___ +local F, tproxy, writefile, noprint, ___ do local type, unpack = type, table.unpack or unpack + local assert, io = assert, io function F(...) local args, n = { ... }, select('#', ...) for i = 1, n do @@ -20,6 +21,12 @@ do __len = function() return #t end, }), t end + function writefile(name, contents, bin) + local f = assert(io.open(name, bin and "wb" or "w")) + f:write(contents) + f:close() + end + function noprint() end local sep = ("="):rep(70) function ___() print(sep) @@ -27,6 +34,7 @@ do end local V = _VERSION:gsub("^.*(%d+)%.(%d+)$", "%1%2") +if jit then V = "jit" end print( "testing Lua API ..." ) package.path = "../?.lua;"..package.path @@ -217,6 +225,342 @@ print("math.ult", pcall(math.ult, 1, 2.1)) ___'' +print("testing Lua API for Lua 5.1 ...") + +___'' +print("debug.getuservalue()", F(debug.getuservalue(false))) +print("debug.setuservalue()", pcall(function() + debug.setuservalue(false, {}) +end)) +print("debug.setmetatable()", F(debug.setmetatable({}, {}))) + + +___'' +do + local t = setmetatable({}, { + __pairs = function() return pairs({ a = "a" }) end, + }) + for k,v in pairs(t) do + print("pairs()", k, v) + end +end + + +___'' +do + local code = "print('hello world')\n" + local badcode = "print('blub\n" + print("load()", pcall(function() load(true) end)) + print("load()", F(load(badcode))) + print("load()", F(load(code))) + print("load()", F(load(code, "[L]"))) + print("load()", F(load(code, "[L]", "b"))) + print("load()", F(load(code, "[L]", "t"))) + print("load()", F(load(code, "[L]", "bt"))) + local f = load(code, "[L]", "bt", {}) + print("load()", pcall(f)) + f = load(code, "[L]", "bt", { print = noprint }) + print("load()", pcall(f)) + local bytecode = string.dump(f) + print("load()", F(load(bytecode))) + print("load()", F(load(bytecode, "[L]"))) + print("load()", F(load(bytecode, "[L]", "b"))) + print("load()", F(load(bytecode, "[L]", "t"))) + print("load()", F(load(bytecode, "[L]", "bt"))) + f = load(bytecode, "[L]", "bt", {}) + print("load()", pcall(f)) + f = load(bytecode, "[L]", "bt", { print = noprint }) + print("load()", pcall(f)) + local function make_loader(code) + local mid = math.floor( #code/2 ) + local array = { code:sub(1, mid), code:sub(mid+1) } + local i = 0 + return function() + i = i + 1 + return array[i] + end + end + print("load()", F(load(make_loader(badcode)))) + print("load()", F(load(make_loader(code)))) + print("load()", F(load(make_loader(code), "[L]"))) + print("load()", F(load(make_loader(code), "[L]", "b"))) + print("load()", F(load(make_loader(code), "[L]", "t"))) + print("load()", F(load(make_loader(code), "[L]", "bt"))) + f = load(make_loader(code), "[L]", "bt", {}) + print("load()", pcall(f)) + f = load(make_loader(code), "[L]", "bt", { print = noprint }) + print("load()", pcall(f)) + print("load()", F(load(make_loader(bytecode)))) + print("load()", F(load(make_loader(bytecode), "[L]"))) + print("load()", F(load(make_loader(bytecode), "[L]", "b"))) + print("load()", F(load(make_loader(bytecode), "[L]", "t"))) + print("load()", F(load(make_loader(bytecode), "[L]", "bt"))) + f = load(make_loader(bytecode), "[L]", "bt", {}) + print("load()", pcall(f)) + f = load(make_loader(bytecode), "[L]", "bt", { print = noprint }) + print("load()", pcall(f)) + writefile("good.lua", code) + writefile("bad.lua", badcode) + writefile("good.luac", bytecode, true) + print("loadfile()", F(loadfile("bad.lua"))) + print("loadfile()", F(loadfile("good.lua"))) + print("loadfile()", F(loadfile("good.lua", "b"))) + print("loadfile()", F(loadfile("good.lua", "t"))) + print("loadfile()", F(loadfile("good.lua", "bt"))) + f = loadfile("good.lua", "bt", {}) + print("loadfile()", pcall(f)) + f = loadfile("good.lua", "bt", { print = noprint }) + print("loadfile()", pcall(f)) + print("loadfile()", F(loadfile("good.luac"))) + print("loadfile()", F(loadfile("good.luac", "b"))) + print("loadfile()", F(loadfile("good.luac", "t"))) + print("loadfile()", F(loadfile("good.luac", "bt"))) + f = loadfile("good.luac", "bt", {}) + print("loadfile()", pcall(f)) + f = loadfile("good.luac", "bt", { print = noprint }) + print("loadfile()", pcall(f)) + os.remove("good.lua") + os.remove("bad.lua") + os.remove("good.luac") +end + + +___'' +do + local function func(throw) + if throw then + error("argh") + else + return 1, 2, 3 + end + end + local function tb(err) return "|"..err.."|" end + print("xpcall()", xpcall(func, debug.traceback, false)) + print("xpcall()", xpcall(func, debug.traceback, true)) + print("xpcall()", xpcall(func, tb, true)) + local function func2(cb) + print("xpcall()", xpcall(cb, debug.traceback, "str")) + end + local function func3(cb) + print("pcall()", pcall(cb, "str")) + end + local function cb(arg) + coroutine.yield(2) + return arg + end + local c = coroutine.wrap(func2) + print("xpcall()", c(cb)) + print("xpcall()", c()) + local c = coroutine.wrap(func3) + print("pcall()", c(cb)) + print("pcall()", c()) +end + + +___'' +do + local t = setmetatable({ 1 }, { __len = function() return 5 end }) + print("rawlen()", rawlen(t), rawlen("123")) +end + + +___'' +print("os.execute()", os.execute("exit 1")) +io.flush() +print("os.execute()", os.execute("echo 'hello world!'")) +io.flush() +print("os.execute()", os.execute("no_such_file")) + + +___'' +do + local t = table.pack("a", nil, "b", nil) + print("table.(un)pack()", t.n, table.unpack(t, 1, t.n)) +end + + +___'' +do + print("coroutine.running()", F(coroutine.wrap(function() + return coroutine.running() + end)())) + print("coroutine.running()", F(coroutine.running())) + local main_co, co1, co2 = coroutine.running() + -- coroutine.yield + print("coroutine.yield()", pcall(function() + coroutine.yield(1, 2, 3) + end)) + print("coroutine.yield()", coroutine.wrap(function() + coroutine.yield(1, 2, 3) + end)()) + print("coroutine.resume()", coroutine.resume(main_co, 1, 2, 3)) + co1 = coroutine.create(function(a, b, c) + print("coroutine.resume()", a, b, c) + return a, b, c + end) + print("coroutine.resume()", coroutine.resume(co1, 1, 2, 3)) + co1 = coroutine.create(function() + print("coroutine.status()", "[co1] main is", coroutine.status(main_co)) + print("coroutine.status()", "[co1] co2 is", coroutine.status(co2)) + end) + co2 = coroutine.create(function() + print("coroutine.status()", "[co2] main is", coroutine.status(main_co)) + print("coroutine.status()", "[co2] co2 is", coroutine.status(co2)) + coroutine.yield() + coroutine.resume(co1) + end) + print("coroutine.status()", coroutine.status(main_co)) + print("coroutine.status()", coroutine.status(co2)) + coroutine.resume(co2) + print("coroutine.status()", F(coroutine.status(co2))) + coroutine.resume(co2) + print("coroutine.status()", F(coroutine.status(co2))) +end + + +___'' +print("math.log()", math.log(1000)) +print("math.log()", math.log(1000, 10)) + + +___'' +do + local path, prefix = "./?.lua;?/init.lua;../?.lua", "package.searchpath()" + print(prefix, package.searchpath("no.such.module", path)) + print(prefix, package.searchpath("no.such.module", "")) + print(prefix, package.searchpath("compat52", path)) + print(prefix, package.searchpath("no:such:module", path, ":", "|")) +end + + +___'' +do + local function mod_func() return {} end + local function my_searcher(name) + if name == "my.module" then + print("package.searchers", "my.module found") + return mod_func + end + end + local function my_searcher2(name) + if name == "my.module" then + print("package.searchers", "my.module found 2") + return mod_func + end + end + table.insert(package.searchers, my_searcher) + require("my.module") + package.loaded["my.module"] = nil + local new_s = { my_searcher2 } + for i,f in ipairs(package.searchers) do + new_s[i+1] = f + end + package.searchers = new_s + require("my.module") +end + + +___'' +do + print("string.find()", ("abc\0abc\0abc"):find("[^a\0]+")) + print("string.find()", ("abc\0abc\0abc"):find("%w+\0", 5)) + for x in ("abc\0def\0ghi"):gmatch("[^\0]+") do + print("string.gmatch()", x) + end + for x in ("abc\0def\0ghi"):gmatch("%w*\0") do + print("string.gmatch()", #x) + end + print("string.gsub()", ("abc\0def\0ghi"):gsub("[\0]", "X")) + print("string.gsub()", ("abc\0def\0ghi"):gsub("%w*\0", "X")) + print("string.gsub()", ("abc\0def\0ghi"):gsub("%A", "X")) + print("string.match()", ("abc\0abc\0abc"):match("([^\0a]+)")) + print("string.match()", #("abc\0abc\0abc"):match(".*\0")) + print("string.rep()", string.rep("a", 0)) + print("string.rep()", string.rep("b", 1)) + print("string.rep()", string.rep("c", 4)) + print("string.rep()", string.rep("a", 0, "|")) + print("string.rep()", string.rep("b", 1, "|")) + print("string.rep()", string.rep("c", 4, "|")) + local _tostring = tostring + function tostring(v) + if type(v) == "number" then + return "(".._tostring(v)..")" + else + return _tostring(v) + end + end + print("string.format()", string.format("%q", "\"\\\0000\0010\r0\n0\t0\"")) + print("string.format()", string.format("%12.3fx%%sxx%.6s", 3.1, {})) + print("string.format()", string.format("%-3f %%%s %%s", 3.1, true)) + print("string.format()", string.format("% 3.2g %%d %%%s", 3.1, nil)) + print("string.format()", string.format("%+3d %%d %%%%%10.6s", 3, io.stdout)) + print("string.format()", pcall(function() + print("string.format()", string.format("%d %%s", {})) + end)) + tostring = _tostring +end + + +___'' +do + print("io.write()", io.type(io.write("hello world\n"))) + local f = assert(io.tmpfile()) + print("file:write()", io.type(f:write("hello world\n"))) + f:close() +end + + +___'' +do + writefile("data.txt", "123 18.8 hello world\ni'm here\n") + for a,b in io.lines("test.lua", 2, "*l") do + print("io.lines()", a, b) + break + end + for l in io.lines("test.lua") do + print("io.lines()", l) + break + end + for n1,n2,rest in io.lines("data.txt", "*n", "*n", "*a") do + print("io.lines()", n1, n2, rest) + end + for l in io.lines("data.txt") do + print("io.lines()", l) + end + print("io.lines()", pcall(function() + for l in io.lines("data.txt", "*x") do print(l) end + end)) + print("io.lines()", pcall(function() + for l in io.lines("no_such_file.txt") do print(l) end + end)) + local f = assert(io.open("test.lua", "r")) + for a,b in f:lines(2, "*l") do + print("file:lines()", a, b) + break + end + f:close() + f = assert(io.open("data.txt", "r")) + for n1,n2,rest in f:lines("*n", "*n", "*a") do + print("file:lines()", n1, n2, rest) + end + f:close() + f = assert(io.open("data.txt", "r")) + for l in f:lines() do + print("file:lines()", l) + end + f:close() + print("file:lines()", pcall(function() + for l in f:lines() do print(l) end + end)) + print("file:lines()", pcall(function() + local f = assert(io.open("data.txt", "r")) + for l in f:lines("*l", "*x") do print(l) end + f:close() + end)) + os.remove("data.txt") +end +___'' + print("testing C API ...") local mod = require("testmod") -- cgit v1.2.3-55-g6feb