diff options
author | Philipp Janda <siffiejoe@gmx.net> | 2015-01-20 11:35:16 +0100 |
---|---|---|
committer | Philipp Janda <siffiejoe@gmx.net> | 2015-01-20 11:35:16 +0100 |
commit | 866cb79f65c844b3fcfa99d2caa4bf19930dbc6d (patch) | |
tree | 338699b9df9b2c99cec053321790e9a5960c4b3b | |
parent | e52c3c4e7af665acd23e63fd3ae85f2c8ae87e49 (diff) | |
download | lua-compat-5.3-866cb79f65c844b3fcfa99d2caa4bf19930dbc6d.tar.gz lua-compat-5.3-866cb79f65c844b3fcfa99d2caa4bf19930dbc6d.tar.bz2 lua-compat-5.3-866cb79f65c844b3fcfa99d2caa4bf19930dbc6d.zip |
luajit already has yieldable (x)pcall, add tests for code from compat52
-rw-r--r-- | README.md | 5 | ||||
-rw-r--r-- | c-api/compat-5.3.h | 1 | ||||
-rw-r--r-- | compat53.lua | 318 | ||||
-rwxr-xr-x | tests/test.lua | 346 |
4 files changed, 511 insertions, 159 deletions
@@ -116,6 +116,8 @@ For Lua 5.1 additionally: | |||
116 | * `luaL_Stream` | 116 | * `luaL_Stream` |
117 | * `LUA_FILEHANDLE` | 117 | * `LUA_FILEHANDLE` |
118 | * `lua_absindex` | 118 | * `lua_absindex` |
119 | * `lua_arith` | ||
120 | * `lua_compare` | ||
119 | * `lua_len`, `lua_rawlen`, and `luaL_len` | 121 | * `lua_len`, `lua_rawlen`, and `luaL_len` |
120 | * `lua_copy` | 122 | * `lua_copy` |
121 | * `lua_pushglobaltable` | 123 | * `lua_pushglobaltable` |
@@ -141,9 +143,8 @@ For Lua 5.1 additionally: | |||
141 | * the following C API functions/macros: | 143 | * the following C API functions/macros: |
142 | * `lua_isyieldable` | 144 | * `lua_isyieldable` |
143 | * `lua_getextraspace` | 145 | * `lua_getextraspace` |
144 | * `lua_arith` (not at all in 5.1, operators missing in 5.2) | 146 | * `lua_arith` (new operators missing) |
145 | * `lua_pushfstring` (new formats) | 147 | * `lua_pushfstring` (new formats) |
146 | * `lua_compare` (5.1) | ||
147 | * `lua_upvalueid` (5.1) | 148 | * `lua_upvalueid` (5.1) |
148 | * `lua_upvaluejoin` (5.1) | 149 | * `lua_upvaluejoin` (5.1) |
149 | * `lua_version` (5.1) | 150 | * `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 @@ | |||
40 | #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 | 40 | #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 |
41 | 41 | ||
42 | /* XXX not implemented: | 42 | /* XXX not implemented: |
43 | * lua_arith (new operators) | ||
43 | * lua_upvalueid | 44 | * lua_upvalueid |
44 | * lua_upvaluejoin | 45 | * lua_upvaluejoin |
45 | * lua_version | 46 | * 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 | |||
336 | function debug.setuservalue(obj, value) | 336 | function debug.setuservalue(obj, value) |
337 | if type(obj) ~= "userdata" then | 337 | if type(obj) ~= "userdata" then |
338 | error("bad argument #1 to 'setuservalue' (userdata expected, got ".. | 338 | error("bad argument #1 to 'setuservalue' (userdata expected, got ".. |
339 | type(obj)..")", 0) | 339 | type(obj)..")", 2) |
340 | end | 340 | end |
341 | if value == nil then value = _G end | 341 | if value == nil then value = _G end |
342 | if type(value) ~= "table" then | 342 | if type(value) ~= "table" then |
343 | error("bad argument #2 to 'setuservalue' (table expected, got ".. | 343 | error("bad argument #2 to 'setuservalue' (table expected, got ".. |
344 | type(value)..")", 0) | 344 | type(value)..")", 2) |
345 | end | 345 | end |
346 | return debug_setfenv(obj, value) | 346 | return debug_setfenv(obj, value) |
347 | end | 347 | end |
@@ -366,96 +366,98 @@ if lua_version < "5.3" then | |||
366 | end | 366 | end |
367 | end -- not luajit with compat52 enabled | 367 | end -- not luajit with compat52 enabled |
368 | 368 | ||
369 | local debug_getinfo = debug.getinfo | 369 | if not is_luajit then |
370 | local function calculate_trace_level(co, level) | 370 | local debug_getinfo = debug.getinfo |
371 | if level ~= nil then | 371 | local function calculate_trace_level(co, level) |
372 | for out = 1, 1/0 do | 372 | if level ~= nil then |
373 | local info = (co==nil) and debug_getinfo(out, "") or debug_getinfo(co, out, "") | 373 | for out = 1, 1/0 do |
374 | if info == nil then | 374 | local info = (co==nil) and debug_getinfo(out, "") or debug_getinfo(co, out, "") |
375 | local max = out-1 | 375 | if info == nil then |
376 | if level <= max then | 376 | local max = out-1 |
377 | return level | 377 | if level <= max then |
378 | return level | ||
379 | end | ||
380 | return nil, level-max | ||
378 | end | 381 | end |
379 | return nil, level-max | ||
380 | end | 382 | end |
381 | end | 383 | end |
384 | return 1 | ||
382 | end | 385 | end |
383 | return 1 | ||
384 | end | ||
385 | 386 | ||
386 | local stack_pattern = "\nstack traceback:" | 387 | local stack_pattern = "\nstack traceback:" |
387 | local stack_replace = "" | 388 | local stack_replace = "" |
388 | local debug_traceback = debug.traceback | 389 | local debug_traceback = debug.traceback |
389 | function debug.traceback(co, msg, level) | 390 | function debug.traceback(co, msg, level) |
390 | local lvl | 391 | local lvl |
391 | local nilmsg | 392 | local nilmsg |
392 | if type(co) ~= "thread" then | 393 | if type(co) ~= "thread" then |
393 | co, msg, level = coroutine_running(), co, msg | 394 | co, msg, level = coroutine_running(), co, msg |
394 | end | 395 | end |
395 | if msg == nil then | 396 | if msg == nil then |
396 | msg = "" | 397 | msg = "" |
397 | nilmsg = true | 398 | nilmsg = true |
398 | elseif type(msg) ~= "string" then | 399 | elseif type(msg) ~= "string" then |
399 | return msg | 400 | return msg |
400 | end | 401 | end |
401 | if co == nil then | 402 | if co == nil then |
402 | msg = debug_traceback(msg, level or 1) | 403 | msg = debug_traceback(msg, level or 1) |
403 | else | ||
404 | local xpco = xpcall_running[co] | ||
405 | if xpco ~= nil then | ||
406 | lvl, level = calculate_trace_level(xpco, level) | ||
407 | if lvl then | ||
408 | msg = debug_traceback(xpco, msg, lvl) | ||
409 | else | ||
410 | msg = msg..stack_pattern | ||
411 | end | ||
412 | lvl, level = calculate_trace_level(co, level) | ||
413 | if lvl then | ||
414 | local trace = debug_traceback(co, "", lvl) | ||
415 | msg = msg..trace:gsub(stack_pattern, stack_replace) | ||
416 | end | ||
417 | else | 404 | else |
418 | co = pcall_callOf[co] or co | 405 | local xpco = xpcall_running[co] |
419 | lvl, level = calculate_trace_level(co, level) | 406 | if xpco ~= nil then |
420 | if lvl then | 407 | lvl, level = calculate_trace_level(xpco, level) |
421 | msg = debug_traceback(co, msg, lvl) | 408 | if lvl then |
409 | msg = debug_traceback(xpco, msg, lvl) | ||
410 | else | ||
411 | msg = msg..stack_pattern | ||
412 | end | ||
413 | lvl, level = calculate_trace_level(co, level) | ||
414 | if lvl then | ||
415 | local trace = debug_traceback(co, "", lvl) | ||
416 | msg = msg..trace:gsub(stack_pattern, stack_replace) | ||
417 | end | ||
422 | else | 418 | else |
423 | msg = msg..stack_pattern | 419 | co = pcall_callOf[co] or co |
424 | end | 420 | lvl, level = calculate_trace_level(co, level) |
425 | end | 421 | if lvl then |
426 | co = pcall_previous[co] | 422 | msg = debug_traceback(co, msg, lvl) |
427 | while co ~= nil do | 423 | else |
428 | lvl, level = calculate_trace_level(co, level) | 424 | msg = msg..stack_pattern |
429 | if lvl then | 425 | end |
430 | local trace = debug_traceback(co, "", lvl) | ||
431 | msg = msg..trace:gsub(stack_pattern, stack_replace) | ||
432 | end | 426 | end |
433 | co = pcall_previous[co] | 427 | co = pcall_previous[co] |
428 | while co ~= nil do | ||
429 | lvl, level = calculate_trace_level(co, level) | ||
430 | if lvl then | ||
431 | local trace = debug_traceback(co, "", lvl) | ||
432 | msg = msg..trace:gsub(stack_pattern, stack_replace) | ||
433 | end | ||
434 | co = pcall_previous[co] | ||
435 | end | ||
436 | end | ||
437 | if nilmsg then | ||
438 | msg = msg:gsub("^\n", "") | ||
434 | end | 439 | end |
440 | msg = msg:gsub("\n\t%(tail call%): %?", "\000") | ||
441 | msg = msg:gsub("\n\t%.%.%.\n", "\001\n") | ||
442 | msg = msg:gsub("\n\t%.%.%.$", "\001") | ||
443 | msg = msg:gsub("(%z+)\001(%z+)", function(some, other) | ||
444 | return "\n\t(..."..#some+#other.."+ tail call(s)...)" | ||
445 | end) | ||
446 | msg = msg:gsub("\001(%z+)", function(zeros) | ||
447 | return "\n\t(..."..#zeros.."+ tail call(s)...)" | ||
448 | end) | ||
449 | msg = msg:gsub("(%z+)\001", function(zeros) | ||
450 | return "\n\t(..."..#zeros.."+ tail call(s)...)" | ||
451 | end) | ||
452 | msg = msg:gsub("%z+", function(zeros) | ||
453 | return "\n\t(..."..#zeros.." tail call(s)...)" | ||
454 | end) | ||
455 | msg = msg:gsub("\001", function(zeros) | ||
456 | return "\n\t..." | ||
457 | end) | ||
458 | return msg | ||
435 | end | 459 | end |
436 | if nilmsg then | 460 | end -- is not luajit |
437 | msg = msg:gsub("^\n", "") | ||
438 | end | ||
439 | msg = msg:gsub("\n\t%(tail call%): %?", "\000") | ||
440 | msg = msg:gsub("\n\t%.%.%.\n", "\001\n") | ||
441 | msg = msg:gsub("\n\t%.%.%.$", "\001") | ||
442 | msg = msg:gsub("(%z+)\001(%z+)", function(some, other) | ||
443 | return "\n\t(..."..#some+#other.."+ tail call(s)...)" | ||
444 | end) | ||
445 | msg = msg:gsub("\001(%z+)", function(zeros) | ||
446 | return "\n\t(..."..#zeros.."+ tail call(s)...)" | ||
447 | end) | ||
448 | msg = msg:gsub("(%z+)\001", function(zeros) | ||
449 | return "\n\t(..."..#zeros.."+ tail call(s)...)" | ||
450 | end) | ||
451 | msg = msg:gsub("%z+", function(zeros) | ||
452 | return "\n\t(..."..#zeros.." tail call(s)...)" | ||
453 | end) | ||
454 | msg = msg:gsub("\001", function(zeros) | ||
455 | return "\n\t..." | ||
456 | end) | ||
457 | return msg | ||
458 | end | ||
459 | end -- debug table available | 461 | end -- debug table available |
460 | 462 | ||
461 | 463 | ||
@@ -501,7 +503,7 @@ if lua_version < "5.3" then | |||
501 | local ld_type = type(ld) | 503 | local ld_type = type(ld) |
502 | if ld_type ~= "function" then | 504 | if ld_type ~= "function" then |
503 | error("bad argument #1 to 'load' (function expected, got ".. | 505 | error("bad argument #1 to 'load' (function expected, got ".. |
504 | ld_type..")", 0) | 506 | ld_type..")", 2) |
505 | end | 507 | end |
506 | if mode ~= "bt" then | 508 | if mode ~= "bt" then |
507 | local checked, merr = false, nil | 509 | local checked, merr = false, nil |
@@ -564,7 +566,7 @@ if lua_version < "5.3" then | |||
564 | function rawlen(v) | 566 | function rawlen(v) |
565 | local t = type(v) | 567 | local t = type(v) |
566 | if t ~= "string" and t ~= "table" then | 568 | if t ~= "string" and t ~= "table" then |
567 | error("bad argument #1 to 'rawlen' (table or string expected)", 0) | 569 | error("bad argument #1 to 'rawlen' (table or string expected)", 2) |
568 | end | 570 | end |
569 | return #v | 571 | return #v |
570 | end | 572 | end |
@@ -622,92 +624,94 @@ if lua_version < "5.3" then | |||
622 | 624 | ||
623 | local coroutine_yield = coroutine.yield | 625 | local coroutine_yield = coroutine.yield |
624 | function coroutine.yield(...) | 626 | function coroutine.yield(...) |
625 | local co = coroutine_running() | 627 | local co, flag = coroutine_running() |
626 | if co then | 628 | if co and not flag then |
627 | return coroutine_yield(...) | 629 | return coroutine_yield(...) |
628 | else | 630 | else |
629 | error("attempt to yield from outside a coroutine", 0) | 631 | error("attempt to yield from outside a coroutine", 0) |
630 | end | 632 | end |
631 | end | 633 | end |
632 | 634 | ||
633 | local coroutine_resume = coroutine.resume | 635 | if not is_luajit then |
634 | function coroutine.resume(co, ...) | 636 | local coroutine_resume = coroutine.resume |
635 | if co == main_coroutine then | 637 | function coroutine.resume(co, ...) |
636 | return false, "cannot resume non-suspended coroutine" | 638 | if co == main_coroutine then |
637 | else | 639 | return false, "cannot resume non-suspended coroutine" |
638 | return coroutine_resume(co, ...) | 640 | else |
641 | return coroutine_resume(co, ...) | ||
642 | end | ||
639 | end | 643 | end |
640 | end | ||
641 | 644 | ||
642 | local coroutine_status = coroutine.status | 645 | local coroutine_status = coroutine.status |
643 | function coroutine.status(co) | 646 | function coroutine.status(co) |
644 | local notmain = coroutine_running() | 647 | local notmain = coroutine_running() |
645 | if co == main_coroutine then | 648 | if co == main_coroutine then |
646 | return notmain and "normal" or "running" | 649 | return notmain and "normal" or "running" |
647 | else | 650 | else |
648 | return coroutine_status(co) | 651 | return coroutine_status(co) |
652 | end | ||
649 | end | 653 | end |
650 | end | ||
651 | 654 | ||
652 | local function pcall_results(current, call, success, ...) | 655 | local function pcall_results(current, call, success, ...) |
653 | if coroutine_status(call) == "suspended" then | 656 | if coroutine_status(call) == "suspended" then |
654 | return pcall_results(current, call, coroutine_resume(call, coroutine_yield(...))) | 657 | return pcall_results(current, call, coroutine_resume(call, coroutine_yield(...))) |
658 | end | ||
659 | if pcall_previous then | ||
660 | pcall_previous[call] = nil | ||
661 | local main = pcall_mainOf[call] | ||
662 | if main == current then current = nil end | ||
663 | pcall_callOf[main] = current | ||
664 | end | ||
665 | pcall_mainOf[call] = nil | ||
666 | return success, ... | ||
655 | end | 667 | end |
656 | if pcall_previous then | 668 | local function pcall_exec(current, call, ...) |
657 | pcall_previous[call] = nil | 669 | local main = pcall_mainOf[current] or current |
658 | local main = pcall_mainOf[call] | 670 | pcall_mainOf[call] = main |
659 | if main == current then current = nil end | 671 | if pcall_previous then |
660 | pcall_callOf[main] = current | 672 | pcall_previous[call] = current |
673 | pcall_callOf[main] = call | ||
674 | end | ||
675 | return pcall_results(current, call, coroutine_resume(call, ...)) | ||
661 | end | 676 | end |
662 | pcall_mainOf[call] = nil | 677 | local coroutine_create52 = coroutine.create |
663 | return success, ... | 678 | local function pcall_coroutine(func) |
664 | end | 679 | if type(func) ~= "function" then |
665 | local function pcall_exec(current, call, ...) | 680 | local callable = func |
666 | local main = pcall_mainOf[current] or current | 681 | func = function (...) return callable(...) end |
667 | pcall_mainOf[call] = main | 682 | end |
668 | if pcall_previous then | 683 | return coroutine_create52(func) |
669 | pcall_previous[call] = current | ||
670 | pcall_callOf[main] = call | ||
671 | end | 684 | end |
672 | return pcall_results(current, call, coroutine_resume(call, ...)) | 685 | function pcall(func, ...) |
673 | end | 686 | local current = coroutine_running() |
674 | local coroutine_create52 = coroutine.create | 687 | if not current then return _pcall(func, ...) end |
675 | local function pcall_coroutine(func) | 688 | return pcall_exec(current, pcall_coroutine(func), ...) |
676 | if type(func) ~= "function" then | ||
677 | local callable = func | ||
678 | func = function (...) return callable(...) end | ||
679 | end | 689 | end |
680 | return coroutine_create52(func) | ||
681 | end | ||
682 | function pcall(func, ...) | ||
683 | local current = coroutine_running() | ||
684 | if not current then return _pcall(func, ...) end | ||
685 | return pcall_exec(current, pcall_coroutine(func), ...) | ||
686 | end | ||
687 | 690 | ||
688 | local function xpcall_catch(current, call, msgh, success, ...) | 691 | local function xpcall_catch(current, call, msgh, success, ...) |
689 | if not success then | 692 | if not success then |
690 | xpcall_running[current] = call | 693 | xpcall_running[current] = call |
691 | local ok, result = _pcall(msgh, ...) | 694 | local ok, result = _pcall(msgh, ...) |
692 | xpcall_running[current] = nil | 695 | xpcall_running[current] = nil |
693 | if not ok then | 696 | if not ok then |
694 | return false, "error in error handling ("..tostring(result)..")" | 697 | return false, "error in error handling ("..tostring(result)..")" |
698 | end | ||
699 | return false, result | ||
695 | end | 700 | end |
696 | return false, result | 701 | return true, ... |
697 | end | 702 | end |
698 | return true, ... | 703 | local _xpcall = xpcall |
699 | end | 704 | local _unpack = unpack |
700 | local _xpcall = xpcall | 705 | function xpcall(f, msgh, ...) |
701 | local _unpack = unpack | 706 | local current = coroutine_running() |
702 | function xpcall(f, msgh, ...) | 707 | if not current then |
703 | local current = coroutine_running() | 708 | local args, n = { ... }, select('#', ...) |
704 | if not current then | 709 | return _xpcall(function() return f(_unpack(args, 1, n)) end, msgh) |
705 | local args, n = { ... }, select('#', ...) | 710 | end |
706 | return _xpcall(function() return f(_unpack(args, 1, n)) end, msgh) | 711 | local call = pcall_coroutine(f) |
712 | return xpcall_catch(current, call, msgh, pcall_exec(current, call, ...)) | ||
707 | end | 713 | end |
708 | local call = pcall_coroutine(f) | 714 | end -- not luajit |
709 | return xpcall_catch(current, call, msgh, pcall_exec(current, call, ...)) | ||
710 | end | ||
711 | 715 | ||
712 | 716 | ||
713 | if not is_luajit then | 717 | if not is_luajit then |
@@ -806,6 +810,7 @@ if lua_version < "5.3" then | |||
806 | return addqt[c] or string_format("\\%03d", c:byte()) | 810 | return addqt[c] or string_format("\\%03d", c:byte()) |
807 | end | 811 | end |
808 | 812 | ||
813 | local _unpack = unpack | ||
809 | function string.format(fmt, ...) | 814 | function string.format(fmt, ...) |
810 | local args, n = { ... }, select('#', ...) | 815 | local args, n = { ... }, select('#', ...) |
811 | local i = 0 | 816 | local i = 0 |
@@ -846,12 +851,13 @@ if lua_version < "5.3" then | |||
846 | if var_1 == nil then | 851 | if var_1 == nil then |
847 | if st.doclose then st.f:close() end | 852 | if st.doclose then st.f:close() end |
848 | if (...) ~= nil then | 853 | if (...) ~= nil then |
849 | error((...), 0) | 854 | error((...), 2) |
850 | end | 855 | end |
851 | end | 856 | end |
852 | return var_1, ... | 857 | return var_1, ... |
853 | end | 858 | end |
854 | 859 | ||
860 | local _unpack = unpack | ||
855 | function lines_iterator(st) | 861 | function lines_iterator(st) |
856 | return helper(st, st.f:read(_unpack(st, 1, st.n))) | 862 | return helper(st, st.f:read(_unpack(st, 1, st.n))) |
857 | end | 863 | end |
@@ -864,14 +870,14 @@ if lua_version < "5.3" then | |||
864 | local doclose, file, msg | 870 | local doclose, file, msg |
865 | if fname ~= nil then | 871 | if fname ~= nil then |
866 | doclose, file, msg = true, io_open(fname, "r") | 872 | doclose, file, msg = true, io_open(fname, "r") |
867 | if not file then error(msg, 0) end | 873 | if not file then error(msg, 2) end |
868 | else | 874 | else |
869 | doclose, file = false, io_input() | 875 | doclose, file = false, io_input() |
870 | end | 876 | end |
871 | local st = { f=file, doclose=doclose, n=select('#', ...), ... } | 877 | local st = { f=file, doclose=doclose, n=select('#', ...), ... } |
872 | for i = 1, st.n do | 878 | for i = 1, st.n do |
873 | if type(st[i]) ~= "number" and not valid_format[st[i]] then | 879 | if type(st[i]) ~= "number" and not valid_format[st[i]] then |
874 | error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 0) | 880 | error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) |
875 | end | 881 | end |
876 | end | 882 | end |
877 | return lines_iterator, st | 883 | return lines_iterator, st |
@@ -894,12 +900,12 @@ if lua_version < "5.3" then | |||
894 | 900 | ||
895 | file_meta.__index.lines = function(self, ...) | 901 | file_meta.__index.lines = function(self, ...) |
896 | if io_type(self) == "closed file" then | 902 | if io_type(self) == "closed file" then |
897 | error("attempt to use a closed file", 0) | 903 | error("attempt to use a closed file", 2) |
898 | end | 904 | end |
899 | local st = { f=self, doclose=false, n=select('#', ...), ... } | 905 | local st = { f=self, doclose=false, n=select('#', ...), ... } |
900 | for i = 1, st.n do | 906 | for i = 1, st.n do |
901 | if type(st[i]) ~= "number" and not valid_format[st[i]] then | 907 | if type(st[i]) ~= "number" and not valid_format[st[i]] then |
902 | error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 0) | 908 | error("bad argument #"..(i+1).." to 'for iterator' (invalid format)", 2) |
903 | end | 909 | end |
904 | end | 910 | end |
905 | return lines_iterator, st | 911 | 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 @@ | |||
1 | #!/usr/bin/env lua | 1 | #!/usr/bin/env lua |
2 | 2 | ||
3 | local F, tproxy, ___ | 3 | local F, tproxy, writefile, noprint, ___ |
4 | do | 4 | do |
5 | local type, unpack = type, table.unpack or unpack | 5 | local type, unpack = type, table.unpack or unpack |
6 | local assert, io = assert, io | ||
6 | function F(...) | 7 | function F(...) |
7 | local args, n = { ... }, select('#', ...) | 8 | local args, n = { ... }, select('#', ...) |
8 | for i = 1, n do | 9 | for i = 1, n do |
@@ -20,6 +21,12 @@ do | |||
20 | __len = function() return #t end, | 21 | __len = function() return #t end, |
21 | }), t | 22 | }), t |
22 | end | 23 | end |
24 | function writefile(name, contents, bin) | ||
25 | local f = assert(io.open(name, bin and "wb" or "w")) | ||
26 | f:write(contents) | ||
27 | f:close() | ||
28 | end | ||
29 | function noprint() end | ||
23 | local sep = ("="):rep(70) | 30 | local sep = ("="):rep(70) |
24 | function ___() | 31 | function ___() |
25 | print(sep) | 32 | print(sep) |
@@ -27,6 +34,7 @@ do | |||
27 | end | 34 | end |
28 | 35 | ||
29 | local V = _VERSION:gsub("^.*(%d+)%.(%d+)$", "%1%2") | 36 | local V = _VERSION:gsub("^.*(%d+)%.(%d+)$", "%1%2") |
37 | if jit then V = "jit" end | ||
30 | 38 | ||
31 | print( "testing Lua API ..." ) | 39 | print( "testing Lua API ..." ) |
32 | package.path = "../?.lua;"..package.path | 40 | package.path = "../?.lua;"..package.path |
@@ -217,6 +225,342 @@ print("math.ult", pcall(math.ult, 1, 2.1)) | |||
217 | ___'' | 225 | ___'' |
218 | 226 | ||
219 | 227 | ||
228 | print("testing Lua API for Lua 5.1 ...") | ||
229 | |||
230 | ___'' | ||
231 | print("debug.getuservalue()", F(debug.getuservalue(false))) | ||
232 | print("debug.setuservalue()", pcall(function() | ||
233 | debug.setuservalue(false, {}) | ||
234 | end)) | ||
235 | print("debug.setmetatable()", F(debug.setmetatable({}, {}))) | ||
236 | |||
237 | |||
238 | ___'' | ||
239 | do | ||
240 | local t = setmetatable({}, { | ||
241 | __pairs = function() return pairs({ a = "a" }) end, | ||
242 | }) | ||
243 | for k,v in pairs(t) do | ||
244 | print("pairs()", k, v) | ||
245 | end | ||
246 | end | ||
247 | |||
248 | |||
249 | ___'' | ||
250 | do | ||
251 | local code = "print('hello world')\n" | ||
252 | local badcode = "print('blub\n" | ||
253 | print("load()", pcall(function() load(true) end)) | ||
254 | print("load()", F(load(badcode))) | ||
255 | print("load()", F(load(code))) | ||
256 | print("load()", F(load(code, "[L]"))) | ||
257 | print("load()", F(load(code, "[L]", "b"))) | ||
258 | print("load()", F(load(code, "[L]", "t"))) | ||
259 | print("load()", F(load(code, "[L]", "bt"))) | ||
260 | local f = load(code, "[L]", "bt", {}) | ||
261 | print("load()", pcall(f)) | ||
262 | f = load(code, "[L]", "bt", { print = noprint }) | ||
263 | print("load()", pcall(f)) | ||
264 | local bytecode = string.dump(f) | ||
265 | print("load()", F(load(bytecode))) | ||
266 | print("load()", F(load(bytecode, "[L]"))) | ||
267 | print("load()", F(load(bytecode, "[L]", "b"))) | ||
268 | print("load()", F(load(bytecode, "[L]", "t"))) | ||
269 | print("load()", F(load(bytecode, "[L]", "bt"))) | ||
270 | f = load(bytecode, "[L]", "bt", {}) | ||
271 | print("load()", pcall(f)) | ||
272 | f = load(bytecode, "[L]", "bt", { print = noprint }) | ||
273 | print("load()", pcall(f)) | ||
274 | local function make_loader(code) | ||
275 | local mid = math.floor( #code/2 ) | ||
276 | local array = { code:sub(1, mid), code:sub(mid+1) } | ||
277 | local i = 0 | ||
278 | return function() | ||
279 | i = i + 1 | ||
280 | return array[i] | ||
281 | end | ||
282 | end | ||
283 | print("load()", F(load(make_loader(badcode)))) | ||
284 | print("load()", F(load(make_loader(code)))) | ||
285 | print("load()", F(load(make_loader(code), "[L]"))) | ||
286 | print("load()", F(load(make_loader(code), "[L]", "b"))) | ||
287 | print("load()", F(load(make_loader(code), "[L]", "t"))) | ||
288 | print("load()", F(load(make_loader(code), "[L]", "bt"))) | ||
289 | f = load(make_loader(code), "[L]", "bt", {}) | ||
290 | print("load()", pcall(f)) | ||
291 | f = load(make_loader(code), "[L]", "bt", { print = noprint }) | ||
292 | print("load()", pcall(f)) | ||
293 | print("load()", F(load(make_loader(bytecode)))) | ||
294 | print("load()", F(load(make_loader(bytecode), "[L]"))) | ||
295 | print("load()", F(load(make_loader(bytecode), "[L]", "b"))) | ||
296 | print("load()", F(load(make_loader(bytecode), "[L]", "t"))) | ||
297 | print("load()", F(load(make_loader(bytecode), "[L]", "bt"))) | ||
298 | f = load(make_loader(bytecode), "[L]", "bt", {}) | ||
299 | print("load()", pcall(f)) | ||
300 | f = load(make_loader(bytecode), "[L]", "bt", { print = noprint }) | ||
301 | print("load()", pcall(f)) | ||
302 | writefile("good.lua", code) | ||
303 | writefile("bad.lua", badcode) | ||
304 | writefile("good.luac", bytecode, true) | ||
305 | print("loadfile()", F(loadfile("bad.lua"))) | ||
306 | print("loadfile()", F(loadfile("good.lua"))) | ||
307 | print("loadfile()", F(loadfile("good.lua", "b"))) | ||
308 | print("loadfile()", F(loadfile("good.lua", "t"))) | ||
309 | print("loadfile()", F(loadfile("good.lua", "bt"))) | ||
310 | f = loadfile("good.lua", "bt", {}) | ||
311 | print("loadfile()", pcall(f)) | ||
312 | f = loadfile("good.lua", "bt", { print = noprint }) | ||
313 | print("loadfile()", pcall(f)) | ||
314 | print("loadfile()", F(loadfile("good.luac"))) | ||
315 | print("loadfile()", F(loadfile("good.luac", "b"))) | ||
316 | print("loadfile()", F(loadfile("good.luac", "t"))) | ||
317 | print("loadfile()", F(loadfile("good.luac", "bt"))) | ||
318 | f = loadfile("good.luac", "bt", {}) | ||
319 | print("loadfile()", pcall(f)) | ||
320 | f = loadfile("good.luac", "bt", { print = noprint }) | ||
321 | print("loadfile()", pcall(f)) | ||
322 | os.remove("good.lua") | ||
323 | os.remove("bad.lua") | ||
324 | os.remove("good.luac") | ||
325 | end | ||
326 | |||
327 | |||
328 | ___'' | ||
329 | do | ||
330 | local function func(throw) | ||
331 | if throw then | ||
332 | error("argh") | ||
333 | else | ||
334 | return 1, 2, 3 | ||
335 | end | ||
336 | end | ||
337 | local function tb(err) return "|"..err.."|" end | ||
338 | print("xpcall()", xpcall(func, debug.traceback, false)) | ||
339 | print("xpcall()", xpcall(func, debug.traceback, true)) | ||
340 | print("xpcall()", xpcall(func, tb, true)) | ||
341 | local function func2(cb) | ||
342 | print("xpcall()", xpcall(cb, debug.traceback, "str")) | ||
343 | end | ||
344 | local function func3(cb) | ||
345 | print("pcall()", pcall(cb, "str")) | ||
346 | end | ||
347 | local function cb(arg) | ||
348 | coroutine.yield(2) | ||
349 | return arg | ||
350 | end | ||
351 | local c = coroutine.wrap(func2) | ||
352 | print("xpcall()", c(cb)) | ||
353 | print("xpcall()", c()) | ||
354 | local c = coroutine.wrap(func3) | ||
355 | print("pcall()", c(cb)) | ||
356 | print("pcall()", c()) | ||
357 | end | ||
358 | |||
359 | |||
360 | ___'' | ||
361 | do | ||
362 | local t = setmetatable({ 1 }, { __len = function() return 5 end }) | ||
363 | print("rawlen()", rawlen(t), rawlen("123")) | ||
364 | end | ||
365 | |||
366 | |||
367 | ___'' | ||
368 | print("os.execute()", os.execute("exit 1")) | ||
369 | io.flush() | ||
370 | print("os.execute()", os.execute("echo 'hello world!'")) | ||
371 | io.flush() | ||
372 | print("os.execute()", os.execute("no_such_file")) | ||
373 | |||
374 | |||
375 | ___'' | ||
376 | do | ||
377 | local t = table.pack("a", nil, "b", nil) | ||
378 | print("table.(un)pack()", t.n, table.unpack(t, 1, t.n)) | ||
379 | end | ||
380 | |||
381 | |||
382 | ___'' | ||
383 | do | ||
384 | print("coroutine.running()", F(coroutine.wrap(function() | ||
385 | return coroutine.running() | ||
386 | end)())) | ||
387 | print("coroutine.running()", F(coroutine.running())) | ||
388 | local main_co, co1, co2 = coroutine.running() | ||
389 | -- coroutine.yield | ||
390 | print("coroutine.yield()", pcall(function() | ||
391 | coroutine.yield(1, 2, 3) | ||
392 | end)) | ||
393 | print("coroutine.yield()", coroutine.wrap(function() | ||
394 | coroutine.yield(1, 2, 3) | ||
395 | end)()) | ||
396 | print("coroutine.resume()", coroutine.resume(main_co, 1, 2, 3)) | ||
397 | co1 = coroutine.create(function(a, b, c) | ||
398 | print("coroutine.resume()", a, b, c) | ||
399 | return a, b, c | ||
400 | end) | ||
401 | print("coroutine.resume()", coroutine.resume(co1, 1, 2, 3)) | ||
402 | co1 = coroutine.create(function() | ||
403 | print("coroutine.status()", "[co1] main is", coroutine.status(main_co)) | ||
404 | print("coroutine.status()", "[co1] co2 is", coroutine.status(co2)) | ||
405 | end) | ||
406 | co2 = coroutine.create(function() | ||
407 | print("coroutine.status()", "[co2] main is", coroutine.status(main_co)) | ||
408 | print("coroutine.status()", "[co2] co2 is", coroutine.status(co2)) | ||
409 | coroutine.yield() | ||
410 | coroutine.resume(co1) | ||
411 | end) | ||
412 | print("coroutine.status()", coroutine.status(main_co)) | ||
413 | print("coroutine.status()", coroutine.status(co2)) | ||
414 | coroutine.resume(co2) | ||
415 | print("coroutine.status()", F(coroutine.status(co2))) | ||
416 | coroutine.resume(co2) | ||
417 | print("coroutine.status()", F(coroutine.status(co2))) | ||
418 | end | ||
419 | |||
420 | |||
421 | ___'' | ||
422 | print("math.log()", math.log(1000)) | ||
423 | print("math.log()", math.log(1000, 10)) | ||
424 | |||
425 | |||
426 | ___'' | ||
427 | do | ||
428 | local path, prefix = "./?.lua;?/init.lua;../?.lua", "package.searchpath()" | ||
429 | print(prefix, package.searchpath("no.such.module", path)) | ||
430 | print(prefix, package.searchpath("no.such.module", "")) | ||
431 | print(prefix, package.searchpath("compat52", path)) | ||
432 | print(prefix, package.searchpath("no:such:module", path, ":", "|")) | ||
433 | end | ||
434 | |||
435 | |||
436 | ___'' | ||
437 | do | ||
438 | local function mod_func() return {} end | ||
439 | local function my_searcher(name) | ||
440 | if name == "my.module" then | ||
441 | print("package.searchers", "my.module found") | ||
442 | return mod_func | ||
443 | end | ||
444 | end | ||
445 | local function my_searcher2(name) | ||
446 | if name == "my.module" then | ||
447 | print("package.searchers", "my.module found 2") | ||
448 | return mod_func | ||
449 | end | ||
450 | end | ||
451 | table.insert(package.searchers, my_searcher) | ||
452 | require("my.module") | ||
453 | package.loaded["my.module"] = nil | ||
454 | local new_s = { my_searcher2 } | ||
455 | for i,f in ipairs(package.searchers) do | ||
456 | new_s[i+1] = f | ||
457 | end | ||
458 | package.searchers = new_s | ||
459 | require("my.module") | ||
460 | end | ||
461 | |||
462 | |||
463 | ___'' | ||
464 | do | ||
465 | print("string.find()", ("abc\0abc\0abc"):find("[^a\0]+")) | ||
466 | print("string.find()", ("abc\0abc\0abc"):find("%w+\0", 5)) | ||
467 | for x in ("abc\0def\0ghi"):gmatch("[^\0]+") do | ||
468 | print("string.gmatch()", x) | ||
469 | end | ||
470 | for x in ("abc\0def\0ghi"):gmatch("%w*\0") do | ||
471 | print("string.gmatch()", #x) | ||
472 | end | ||
473 | print("string.gsub()", ("abc\0def\0ghi"):gsub("[\0]", "X")) | ||
474 | print("string.gsub()", ("abc\0def\0ghi"):gsub("%w*\0", "X")) | ||
475 | print("string.gsub()", ("abc\0def\0ghi"):gsub("%A", "X")) | ||
476 | print("string.match()", ("abc\0abc\0abc"):match("([^\0a]+)")) | ||
477 | print("string.match()", #("abc\0abc\0abc"):match(".*\0")) | ||
478 | print("string.rep()", string.rep("a", 0)) | ||
479 | print("string.rep()", string.rep("b", 1)) | ||
480 | print("string.rep()", string.rep("c", 4)) | ||
481 | print("string.rep()", string.rep("a", 0, "|")) | ||
482 | print("string.rep()", string.rep("b", 1, "|")) | ||
483 | print("string.rep()", string.rep("c", 4, "|")) | ||
484 | local _tostring = tostring | ||
485 | function tostring(v) | ||
486 | if type(v) == "number" then | ||
487 | return "(".._tostring(v)..")" | ||
488 | else | ||
489 | return _tostring(v) | ||
490 | end | ||
491 | end | ||
492 | print("string.format()", string.format("%q", "\"\\\0000\0010\r0\n0\t0\"")) | ||
493 | print("string.format()", string.format("%12.3fx%%sxx%.6s", 3.1, {})) | ||
494 | print("string.format()", string.format("%-3f %%%s %%s", 3.1, true)) | ||
495 | print("string.format()", string.format("% 3.2g %%d %%%s", 3.1, nil)) | ||
496 | print("string.format()", string.format("%+3d %%d %%%%%10.6s", 3, io.stdout)) | ||
497 | print("string.format()", pcall(function() | ||
498 | print("string.format()", string.format("%d %%s", {})) | ||
499 | end)) | ||
500 | tostring = _tostring | ||
501 | end | ||
502 | |||
503 | |||
504 | ___'' | ||
505 | do | ||
506 | print("io.write()", io.type(io.write("hello world\n"))) | ||
507 | local f = assert(io.tmpfile()) | ||
508 | print("file:write()", io.type(f:write("hello world\n"))) | ||
509 | f:close() | ||
510 | end | ||
511 | |||
512 | |||
513 | ___'' | ||
514 | do | ||
515 | writefile("data.txt", "123 18.8 hello world\ni'm here\n") | ||
516 | for a,b in io.lines("test.lua", 2, "*l") do | ||
517 | print("io.lines()", a, b) | ||
518 | break | ||
519 | end | ||
520 | for l in io.lines("test.lua") do | ||
521 | print("io.lines()", l) | ||
522 | break | ||
523 | end | ||
524 | for n1,n2,rest in io.lines("data.txt", "*n", "*n", "*a") do | ||
525 | print("io.lines()", n1, n2, rest) | ||
526 | end | ||
527 | for l in io.lines("data.txt") do | ||
528 | print("io.lines()", l) | ||
529 | end | ||
530 | print("io.lines()", pcall(function() | ||
531 | for l in io.lines("data.txt", "*x") do print(l) end | ||
532 | end)) | ||
533 | print("io.lines()", pcall(function() | ||
534 | for l in io.lines("no_such_file.txt") do print(l) end | ||
535 | end)) | ||
536 | local f = assert(io.open("test.lua", "r")) | ||
537 | for a,b in f:lines(2, "*l") do | ||
538 | print("file:lines()", a, b) | ||
539 | break | ||
540 | end | ||
541 | f:close() | ||
542 | f = assert(io.open("data.txt", "r")) | ||
543 | for n1,n2,rest in f:lines("*n", "*n", "*a") do | ||
544 | print("file:lines()", n1, n2, rest) | ||
545 | end | ||
546 | f:close() | ||
547 | f = assert(io.open("data.txt", "r")) | ||
548 | for l in f:lines() do | ||
549 | print("file:lines()", l) | ||
550 | end | ||
551 | f:close() | ||
552 | print("file:lines()", pcall(function() | ||
553 | for l in f:lines() do print(l) end | ||
554 | end)) | ||
555 | print("file:lines()", pcall(function() | ||
556 | local f = assert(io.open("data.txt", "r")) | ||
557 | for l in f:lines("*l", "*x") do print(l) end | ||
558 | f:close() | ||
559 | end)) | ||
560 | os.remove("data.txt") | ||
561 | end | ||
562 | ___'' | ||
563 | |||
220 | 564 | ||
221 | print("testing C API ...") | 565 | print("testing C API ...") |
222 | local mod = require("testmod") | 566 | local mod = require("testmod") |