From a273241fe6386718cc741c852f783ad5a0138e2b Mon Sep 17 00:00:00 2001 From: Mike Pall Date: Sun, 31 Jan 2016 19:56:41 +0100 Subject: [PATCH 01/68] Initial commit --- README | 77 +++ bench/PARAM_arm.txt | 29 + bench/PARAM_mips.txt | 29 + bench/PARAM_ppc.txt | 29 + bench/PARAM_x86.txt | 29 + bench/SUMCOL_1.txt | 1000 +++++++++++++++++++++++++++ bench/TEST_md5sum.txt | 20 + bench/array3d.lua | 59 ++ bench/binary-trees.lua | 47 ++ bench/chameneos.lua | 68 ++ bench/coroutine-ring.lua | 42 ++ bench/euler14-bit.lua | 22 + bench/fannkuch.lua | 50 ++ bench/fasta.lua | 95 +++ bench/k-nucleotide.lua | 58 ++ bench/life.lua | 111 +++ bench/mandelbrot-bit.lua | 33 + bench/mandelbrot.lua | 23 + bench/md5.lua | 183 +++++ bench/meteor.lua | 220 ++++++ bench/nbody.lua | 119 ++++ bench/nsieve-bit-fp.lua | 37 + bench/nsieve-bit.lua | 27 + bench/nsieve.lua | 21 + bench/partialsums.lua | 29 + bench/pidigits-nogmp.lua | 100 +++ bench/ray.lua | 135 ++++ bench/recursive-ack.lua | 8 + bench/recursive-fib.lua | 7 + bench/revcomp.lua | 37 + bench/scimark-2010-12-20.lua | 400 +++++++++++ bench/scimark-fft.lua | 1 + bench/scimark-lu.lua | 1 + bench/scimark-sor.lua | 1 + bench/scimark-sparse.lua | 1 + bench/scimark_lib.lua | 297 ++++++++ bench/series.lua | 34 + bench/spectral-norm.lua | 40 ++ bench/sum-file.lua | 6 + test/clib/cpptest.cpp | 129 ++++ test/clib/ctest.c | 339 +++++++++ test/common/ffi_util.inc | 41 ++ test/ffi/ffi_arith_ptr.lua | 106 +++ test/ffi/ffi_bit64.lua | 120 ++++ test/ffi/ffi_bitfield.lua | 108 +++ test/ffi/ffi_call.lua | 266 +++++++ test/ffi/ffi_callback.lua | 158 +++++ test/ffi/ffi_const.lua | 113 +++ test/ffi/ffi_convert.lua | 787 +++++++++++++++++++++ test/ffi/ffi_copy_fill.lua | 64 ++ test/ffi/ffi_enum.lua | 57 ++ test/ffi/ffi_err.lua | 38 + test/ffi/ffi_gcstep_recursive.lua | 66 ++ test/ffi/ffi_istype.lua | 89 +++ test/ffi/ffi_jit_arith.lua | 155 +++++ test/ffi/ffi_jit_array.lua | 104 +++ test/ffi/ffi_jit_call.lua | 154 +++++ test/ffi/ffi_jit_complex.lua | 111 +++ test/ffi/ffi_jit_conv.lua | 277 ++++++++ test/ffi/ffi_jit_misc.lua | 110 +++ test/ffi/ffi_jit_struct.lua | 201 ++++++ test/ffi/ffi_lex_number.lua | 51 ++ test/ffi/ffi_meta_tostring.lua | 54 ++ test/ffi/ffi_metatype.lua | 245 +++++++ test/ffi/ffi_new.lua | 106 +++ test/ffi/ffi_nosink.lua | 45 ++ test/ffi/ffi_parse_array.lua | 78 +++ test/ffi/ffi_parse_basic.lua | 131 ++++ test/ffi/ffi_parse_cdef.lua | 77 +++ test/ffi/ffi_parse_struct.lua | 259 +++++++ test/ffi/ffi_redir.lua | 22 + test/ffi/ffi_sink.lua | 122 ++++ test/ffi/ffi_tabov.lua | 12 + test/ffi/ffi_type_punning.lua | 147 ++++ test/misc/ack.lua | 12 + test/misc/ack_notail.lua | 12 + test/misc/alias_alloc.lua | 54 ++ test/misc/api_call.lua | 98 +++ test/misc/argcheck.lua | 40 ++ test/misc/assign_tset_prevnil.lua | 11 + test/misc/assign_tset_tmp.lua | 5 + test/misc/bit_op.lua | 90 +++ test/misc/cat_jit.lua | 113 +++ test/misc/catch_wrap.lua | 45 ++ test/misc/compare.lua | 232 +++++++ test/misc/constov.lua | 19 + test/misc/coro_traceback.lua | 8 + test/misc/coro_yield.lua | 111 +++ test/misc/debug_gc.lua | 47 ++ test/misc/debug_meta.lua | 79 +++ test/misc/dse_array.lua | 200 ++++++ test/misc/dse_field.lua | 77 +++ test/misc/dualnum.lua | 47 ++ test/misc/exit_frame.lua | 80 +++ test/misc/exit_growstack.lua | 24 + test/misc/exit_jfuncf.lua | 30 + test/misc/fac.lua | 13 + test/misc/fastfib.lua | 26 + test/misc/fib.lua | 11 + test/misc/for_dir.lua | 13 + test/misc/fori_coerce.lua | 33 + test/misc/fuse.lua | 8 + test/misc/fwd_hrefk_rollback.lua | 34 + test/misc/fwd_tnew_tdup.lua | 78 +++ test/misc/fwd_upval.lua | 57 ++ test/misc/gc_rechain.lua | 32 + test/misc/gc_trace.lua | 37 + test/misc/gcstep.lua | 33 + test/misc/getfenv.lua | 15 + test/misc/goto.lua | 156 +++++ test/misc/hook_active.lua | 95 +++ test/misc/hook_line.lua | 41 ++ test/misc/hook_norecord.lua | 12 + test/misc/hook_record.lua | 8 + test/misc/hook_top.lua | 55 ++ test/misc/iter.lua | 85 +++ test/misc/jit_flush.lua | 50 ++ test/misc/kfold.lua | 81 +++ test/misc/libfuncs.lua | 63 ++ test/misc/lightud.lua | 88 +++ test/misc/loop_unroll.lua | 35 + test/misc/math_random.lua | 21 + test/misc/meta_arith.lua | 103 +++ test/misc/meta_arith_jit.lua | 68 ++ test/misc/meta_call.lua | 78 +++ test/misc/meta_cat.lua | 62 ++ test/misc/meta_comp.lua | 151 ++++ test/misc/meta_comp_jit.lua | 104 +++ test/misc/meta_eq.lua | 66 ++ test/misc/meta_eq_jit.lua | 36 + test/misc/meta_framegap.lua | 23 + test/misc/meta_getset.lua | 34 + test/misc/meta_len.lua | 43 ++ test/misc/meta_nomm.lua | 21 + test/misc/meta_pairs.lua | 47 ++ test/misc/meta_tget.lua | 25 + test/misc/meta_tget_nontab.lua | 33 + test/misc/meta_tset.lua | 15 + test/misc/meta_tset_nilget.lua | 23 + test/misc/meta_tset_resize.lua | 10 + test/misc/meta_tset_str.lua | 18 + test/misc/modulo.lua | 42 ++ test/misc/nsieve.lua | 20 + test/misc/parse_andor.lua | 58 ++ test/misc/parse_comp.lua | 13 + test/misc/parse_esc.lua | 7 + test/misc/parse_hex.lua | 7 + test/misc/parse_misc.lua | 31 + test/misc/pcall_jit.lua | 75 ++ test/misc/phi_conv.lua | 53 ++ test/misc/phi_copyspill.lua | 51 ++ test/misc/phi_ref.lua | 141 ++++ test/misc/phi_rot18.lua | 39 ++ test/misc/phi_rot8.lua | 39 ++ test/misc/phi_rot9.lua | 39 ++ test/misc/phi_rotx.lua | 21 + test/misc/recsum.lua | 11 + test/misc/recsump.lua | 11 + test/misc/recurse_deep.lua | 29 + test/misc/recurse_tail.lua | 22 + test/misc/select.lua | 88 +++ test/misc/self.lua | 18 + test/misc/sink_alloc.lua | 140 ++++ test/misc/sink_nosink.lua | 124 ++++ test/misc/snap_gcexit.lua | 16 + test/misc/snap_top.lua | 16 + test/misc/snap_top2.lua | 15 + test/misc/sort.lua | 23 + test/misc/stack_gc.lua | 15 + test/misc/stack_purge.lua | 25 + test/misc/stackov.lua | 40 ++ test/misc/stackovc.lua | 4 + test/misc/stitch.lua | 21 + test/misc/strcmp.lua | 11 + test/misc/string_byte.lua | 90 +++ test/misc/string_char.lua | 28 + test/misc/string_dump.lua | 31 + test/misc/string_op.lua | 110 +++ test/misc/string_sub.lua | 60 ++ test/misc/string_sub_opt.lua | 109 +++ test/misc/table_insert.lua | 18 + test/misc/table_misc.lua | 131 ++++ test/misc/table_remove.lua | 25 + test/misc/tak.lua | 12 + test/misc/tcall_base.lua | 20 + test/misc/tcall_loop.lua | 8 + test/misc/tlen_loop.lua | 23 + test/misc/tnew_tdup.lua | 16 + test/misc/tonumber_scan.lua | 180 +++++ test/misc/tonumber_tostring.lua | 82 +++ test/misc/uclo.lua | 91 +++ test/misc/unordered.lua | 79 +++ test/misc/unordered_jit.lua | 96 +++ test/misc/vararg_jit.lua | 95 +++ test/misc/wbarrier.lua | 7 + test/misc/wbarrier_jit.lua | 18 + test/misc/wbarrier_obar.lua | 22 + test/misc/xpcall_jit.lua | 86 +++ test/sysdep/catch_cpp.lua | 71 ++ test/sysdep/ffi_include_gtk.lua | 9 + test/sysdep/ffi_include_std.lua | 36 + test/sysdep/ffi_lib_c.lua | 87 +++ test/sysdep/ffi_lib_z.lua | 107 +++ test/unportable/ffi_arith_int64.lua | 68 ++ test/unportable/math_special.lua | 55 ++ 205 files changed, 15176 insertions(+) create mode 100644 README create mode 100644 bench/PARAM_arm.txt create mode 100644 bench/PARAM_mips.txt create mode 100644 bench/PARAM_ppc.txt create mode 100644 bench/PARAM_x86.txt create mode 100644 bench/SUMCOL_1.txt create mode 100644 bench/TEST_md5sum.txt create mode 100644 bench/array3d.lua create mode 100644 bench/binary-trees.lua create mode 100644 bench/chameneos.lua create mode 100644 bench/coroutine-ring.lua create mode 100644 bench/euler14-bit.lua create mode 100644 bench/fannkuch.lua create mode 100644 bench/fasta.lua create mode 100644 bench/k-nucleotide.lua create mode 100644 bench/life.lua create mode 100644 bench/mandelbrot-bit.lua create mode 100644 bench/mandelbrot.lua create mode 100644 bench/md5.lua create mode 100644 bench/meteor.lua create mode 100644 bench/nbody.lua create mode 100644 bench/nsieve-bit-fp.lua create mode 100644 bench/nsieve-bit.lua create mode 100644 bench/nsieve.lua create mode 100644 bench/partialsums.lua create mode 100644 bench/pidigits-nogmp.lua create mode 100644 bench/ray.lua create mode 100644 bench/recursive-ack.lua create mode 100644 bench/recursive-fib.lua create mode 100644 bench/revcomp.lua create mode 100644 bench/scimark-2010-12-20.lua create mode 100644 bench/scimark-fft.lua create mode 100644 bench/scimark-lu.lua create mode 100644 bench/scimark-sor.lua create mode 100644 bench/scimark-sparse.lua create mode 100644 bench/scimark_lib.lua create mode 100644 bench/series.lua create mode 100644 bench/spectral-norm.lua create mode 100644 bench/sum-file.lua create mode 100644 test/clib/cpptest.cpp create mode 100644 test/clib/ctest.c create mode 100644 test/common/ffi_util.inc create mode 100644 test/ffi/ffi_arith_ptr.lua create mode 100644 test/ffi/ffi_bit64.lua create mode 100644 test/ffi/ffi_bitfield.lua create mode 100644 test/ffi/ffi_call.lua create mode 100644 test/ffi/ffi_callback.lua create mode 100644 test/ffi/ffi_const.lua create mode 100644 test/ffi/ffi_convert.lua create mode 100644 test/ffi/ffi_copy_fill.lua create mode 100644 test/ffi/ffi_enum.lua create mode 100644 test/ffi/ffi_err.lua create mode 100644 test/ffi/ffi_gcstep_recursive.lua create mode 100644 test/ffi/ffi_istype.lua create mode 100644 test/ffi/ffi_jit_arith.lua create mode 100644 test/ffi/ffi_jit_array.lua create mode 100644 test/ffi/ffi_jit_call.lua create mode 100644 test/ffi/ffi_jit_complex.lua create mode 100644 test/ffi/ffi_jit_conv.lua create mode 100644 test/ffi/ffi_jit_misc.lua create mode 100644 test/ffi/ffi_jit_struct.lua create mode 100644 test/ffi/ffi_lex_number.lua create mode 100644 test/ffi/ffi_meta_tostring.lua create mode 100644 test/ffi/ffi_metatype.lua create mode 100644 test/ffi/ffi_new.lua create mode 100644 test/ffi/ffi_nosink.lua create mode 100644 test/ffi/ffi_parse_array.lua create mode 100644 test/ffi/ffi_parse_basic.lua create mode 100644 test/ffi/ffi_parse_cdef.lua create mode 100644 test/ffi/ffi_parse_struct.lua create mode 100644 test/ffi/ffi_redir.lua create mode 100644 test/ffi/ffi_sink.lua create mode 100644 test/ffi/ffi_tabov.lua create mode 100644 test/ffi/ffi_type_punning.lua create mode 100644 test/misc/ack.lua create mode 100644 test/misc/ack_notail.lua create mode 100644 test/misc/alias_alloc.lua create mode 100644 test/misc/api_call.lua create mode 100644 test/misc/argcheck.lua create mode 100644 test/misc/assign_tset_prevnil.lua create mode 100644 test/misc/assign_tset_tmp.lua create mode 100644 test/misc/bit_op.lua create mode 100644 test/misc/cat_jit.lua create mode 100644 test/misc/catch_wrap.lua create mode 100644 test/misc/compare.lua create mode 100644 test/misc/constov.lua create mode 100644 test/misc/coro_traceback.lua create mode 100644 test/misc/coro_yield.lua create mode 100644 test/misc/debug_gc.lua create mode 100644 test/misc/debug_meta.lua create mode 100644 test/misc/dse_array.lua create mode 100644 test/misc/dse_field.lua create mode 100644 test/misc/dualnum.lua create mode 100644 test/misc/exit_frame.lua create mode 100644 test/misc/exit_growstack.lua create mode 100644 test/misc/exit_jfuncf.lua create mode 100644 test/misc/fac.lua create mode 100644 test/misc/fastfib.lua create mode 100644 test/misc/fib.lua create mode 100644 test/misc/for_dir.lua create mode 100644 test/misc/fori_coerce.lua create mode 100644 test/misc/fuse.lua create mode 100644 test/misc/fwd_hrefk_rollback.lua create mode 100644 test/misc/fwd_tnew_tdup.lua create mode 100644 test/misc/fwd_upval.lua create mode 100644 test/misc/gc_rechain.lua create mode 100644 test/misc/gc_trace.lua create mode 100644 test/misc/gcstep.lua create mode 100644 test/misc/getfenv.lua create mode 100644 test/misc/goto.lua create mode 100644 test/misc/hook_active.lua create mode 100644 test/misc/hook_line.lua create mode 100644 test/misc/hook_norecord.lua create mode 100644 test/misc/hook_record.lua create mode 100644 test/misc/hook_top.lua create mode 100644 test/misc/iter.lua create mode 100644 test/misc/jit_flush.lua create mode 100644 test/misc/kfold.lua create mode 100644 test/misc/libfuncs.lua create mode 100644 test/misc/lightud.lua create mode 100644 test/misc/loop_unroll.lua create mode 100644 test/misc/math_random.lua create mode 100644 test/misc/meta_arith.lua create mode 100644 test/misc/meta_arith_jit.lua create mode 100644 test/misc/meta_call.lua create mode 100644 test/misc/meta_cat.lua create mode 100644 test/misc/meta_comp.lua create mode 100644 test/misc/meta_comp_jit.lua create mode 100644 test/misc/meta_eq.lua create mode 100644 test/misc/meta_eq_jit.lua create mode 100644 test/misc/meta_framegap.lua create mode 100644 test/misc/meta_getset.lua create mode 100644 test/misc/meta_len.lua create mode 100644 test/misc/meta_nomm.lua create mode 100644 test/misc/meta_pairs.lua create mode 100644 test/misc/meta_tget.lua create mode 100644 test/misc/meta_tget_nontab.lua create mode 100644 test/misc/meta_tset.lua create mode 100644 test/misc/meta_tset_nilget.lua create mode 100644 test/misc/meta_tset_resize.lua create mode 100644 test/misc/meta_tset_str.lua create mode 100644 test/misc/modulo.lua create mode 100644 test/misc/nsieve.lua create mode 100644 test/misc/parse_andor.lua create mode 100644 test/misc/parse_comp.lua create mode 100644 test/misc/parse_esc.lua create mode 100644 test/misc/parse_hex.lua create mode 100644 test/misc/parse_misc.lua create mode 100644 test/misc/pcall_jit.lua create mode 100644 test/misc/phi_conv.lua create mode 100644 test/misc/phi_copyspill.lua create mode 100644 test/misc/phi_ref.lua create mode 100644 test/misc/phi_rot18.lua create mode 100644 test/misc/phi_rot8.lua create mode 100644 test/misc/phi_rot9.lua create mode 100644 test/misc/phi_rotx.lua create mode 100644 test/misc/recsum.lua create mode 100644 test/misc/recsump.lua create mode 100644 test/misc/recurse_deep.lua create mode 100644 test/misc/recurse_tail.lua create mode 100644 test/misc/select.lua create mode 100644 test/misc/self.lua create mode 100644 test/misc/sink_alloc.lua create mode 100644 test/misc/sink_nosink.lua create mode 100644 test/misc/snap_gcexit.lua create mode 100644 test/misc/snap_top.lua create mode 100644 test/misc/snap_top2.lua create mode 100644 test/misc/sort.lua create mode 100644 test/misc/stack_gc.lua create mode 100644 test/misc/stack_purge.lua create mode 100644 test/misc/stackov.lua create mode 100644 test/misc/stackovc.lua create mode 100644 test/misc/stitch.lua create mode 100644 test/misc/strcmp.lua create mode 100644 test/misc/string_byte.lua create mode 100644 test/misc/string_char.lua create mode 100644 test/misc/string_dump.lua create mode 100644 test/misc/string_op.lua create mode 100644 test/misc/string_sub.lua create mode 100644 test/misc/string_sub_opt.lua create mode 100644 test/misc/table_insert.lua create mode 100644 test/misc/table_misc.lua create mode 100644 test/misc/table_remove.lua create mode 100644 test/misc/tak.lua create mode 100644 test/misc/tcall_base.lua create mode 100644 test/misc/tcall_loop.lua create mode 100644 test/misc/tlen_loop.lua create mode 100644 test/misc/tnew_tdup.lua create mode 100644 test/misc/tonumber_scan.lua create mode 100644 test/misc/tonumber_tostring.lua create mode 100644 test/misc/uclo.lua create mode 100644 test/misc/unordered.lua create mode 100644 test/misc/unordered_jit.lua create mode 100644 test/misc/vararg_jit.lua create mode 100644 test/misc/wbarrier.lua create mode 100644 test/misc/wbarrier_jit.lua create mode 100644 test/misc/wbarrier_obar.lua create mode 100644 test/misc/xpcall_jit.lua create mode 100644 test/sysdep/catch_cpp.lua create mode 100644 test/sysdep/ffi_include_gtk.lua create mode 100644 test/sysdep/ffi_include_std.lua create mode 100644 test/sysdep/ffi_lib_c.lua create mode 100644 test/sysdep/ffi_lib_z.lua create mode 100644 test/unportable/ffi_arith_int64.lua create mode 100644 test/unportable/math_special.lua diff --git a/README b/README new file mode 100644 index 0000000000..5258c4df27 --- /dev/null +++ b/README @@ -0,0 +1,77 @@ +******************************************** +** THIS IS NOT THE TEST SUITE FOR LUAJIT! ** +******************************************** + +In fact it doesn't even have the steps to build it or run it, +so please don't complain. + +This repo is a place to collect and cleanup tests for LuaJIT. +They should eventually be merged into the main LuaJIT repo. + +It's definitely not in the best state and needs a serious +cleanup effort. Sorry. + + +Many issues need to be resolved before the merge can be performed: + +- Choose a portable test runner + Requirement: very few dependencies, possibly Lua/Shell only + +- Minimal test runner library, wherever assert() is not enough + +- Debugging test failures is a lot simpler, when individual tests can still + be run from the LuaJIT command line without any big dependencies + +- Define consistent grouping of all tests + +- Define consistent naming of all tests + +- Split everything into a lot of tiny tests + +- Reduce time taken to run the test suite + Separate tiers, parallelized testing + +- Some tests can only run under certain configurations (e.g. FFI) + +- Some tests need a clean slate to give reproducible results + Most others should be run from the same state for performance resons + +- Hard to check that the JIT compiler actually generates the intended code + Maybe use a test matching variant of the jit.dump module + +- Portability concerns + +- Avoiding undefined behavior in tests or ignoring it + +- Matrix of architectures + configuration options that need testing + +- Merge tests from other sources, e.g. the various Lua test suites. + +- Tests should go into the LuaJIT git repo, but in separate tarballs + for the releases + + +There are some benchmarks, too: + +- Some of the benchmarks can be used as tests (with low scaling) + by checksumming their output and comparing against known good results + +- Most benchmarks need different scalings to be useful for comparison + on all architectures + + +Note from Mike Pall: + +I've removed all tests of undeterminable origin or that weren't explicitly +contributed with the intention of being part of a public test suite. + +I hereby put all Lua/LuaJIT tests and benchmarks that I wrote under the +public domain. I've removed any copyright headers. + +If I've forgotten an attribution or you want your contributed test to be +removed, please open an issue. + +There are some benchmarks that bear other copyrights, probably public +domain, BSD or MIT licensed. If the status cannot be determined, they +need to be replaced or removed before merging with the LuaJIT repo. + diff --git a/bench/PARAM_arm.txt b/bench/PARAM_arm.txt new file mode 100644 index 0000000000..a07fd010b2 --- /dev/null +++ b/bench/PARAM_arm.txt @@ -0,0 +1,29 @@ +array3d 200 +binary-trees 13 +chameneos 1e6 +coroutine-ring 3e6 +euler14-bit 5e6 +fannkuch 10 +fasta 2e6 +k-nucleotide 5e5 FASTA_500000 +life +mandelbrot 2000 +mandelbrot-bit 2000 +md5 5000 +nbody 1e6 +nsieve 9 +nsieve-bit 9 +nsieve-bit-fp 9 +partialsums 2e6 +pidigits-nogmp 2000 +ray 4 +recursive-ack 9 +recursive-fib 37 +revcomp 1e6 FASTA_1000000 +scimark-fft 2000 +scimark-lu 300 +scimark-sor 5000 +scimark-sparse 5e3 +series 1500 +spectral-norm 1000 +sum-file 1000 SUMCOL_1000 diff --git a/bench/PARAM_mips.txt b/bench/PARAM_mips.txt new file mode 100644 index 0000000000..e6bcadbacd --- /dev/null +++ b/bench/PARAM_mips.txt @@ -0,0 +1,29 @@ +array3d 50 +binary-trees 10 +chameneos 5e4 +coroutine-ring 2e5 +euler14-bit 2e4 +fannkuch 8 +fasta 2e4 +k-nucleotide 1e4 FASTA_10000 +life +mandelbrot 150 +mandelbrot-bit 150 +md5 10 +nbody 1e4 +nsieve 4 +nsieve-bit 4 +nsieve-bit-fp 2 +partialsums 5e4 +pidigits-nogmp 150 +ray 2 +recursive-ack 7 +recursive-fib 29 +revcomp 5e4 FASTA_50000 +scimark-fft 20 +scimark-lu 3 +scimark-sor 40 +scimark-sparse 100 +series 50 +spectral-norm 100 +sum-file 100 SUMCOL_100 diff --git a/bench/PARAM_ppc.txt b/bench/PARAM_ppc.txt new file mode 100644 index 0000000000..c8319a158c --- /dev/null +++ b/bench/PARAM_ppc.txt @@ -0,0 +1,29 @@ +array3d 200 +binary-trees 13 +chameneos 1e6 +coroutine-ring 4e6 +euler14-bit 1e6 +fannkuch 9 +fasta 5e5 +k-nucleotide 1e5 FASTA_100000 +life +mandelbrot 800 +mandelbrot-bit 800 +md5 500 +nbody 1e5 +nsieve 8 +nsieve-bit 8 +nsieve-bit-fp 8 +partialsums 5e5 +pidigits-nogmp 800 +ray 5 +recursive-ack 9 +recursive-fib 34 +revcomp 1e6 FASTA_1000000 +scimark-fft 500 +scimark-lu 100 +scimark-sor 1000 +scimark-sparse 3000 +series 1000 +spectral-norm 200 +sum-file 1000 SUMCOL_1000 diff --git a/bench/PARAM_x86.txt b/bench/PARAM_x86.txt new file mode 100644 index 0000000000..87088d7b13 --- /dev/null +++ b/bench/PARAM_x86.txt @@ -0,0 +1,29 @@ +array3d 300 +binary-trees 16 +chameneos 1e7 +coroutine-ring 2e7 +euler14-bit 2e7 +fannkuch 11 +fasta 25e6 +k-nucleotide 5e6 FASTA_5000000 +life +mandelbrot 5000 +mandelbrot-bit 5000 +md5 20000 +nbody 5e6 +nsieve 12 +nsieve-bit 12 +nsieve-bit-fp 12 +partialsums 1e7 +pidigits-nogmp 5000 +ray 9 +recursive-ack 10 +recursive-fib 40 +revcomp 5e6 FASTA_5000000 +scimark-fft 50000 +scimark-lu 5000 +scimark-sor 50000 +scimark-sparse 15e4 +series 10000 +spectral-norm 3000 +sum-file 5000 SUMCOL_5000 diff --git a/bench/SUMCOL_1.txt b/bench/SUMCOL_1.txt new file mode 100644 index 0000000000..956aba1447 --- /dev/null +++ b/bench/SUMCOL_1.txt @@ -0,0 +1,1000 @@ +276 +498 +-981 +770 +-401 +702 +966 +950 +-853 +-53 +-293 +604 +288 +892 +-697 +204 +96 +408 +880 +-7 +-817 +422 +-261 +-485 +-77 +826 +184 +864 +-751 +626 +812 +-369 +-353 +-371 +488 +-83 +-659 +24 +524 +-21 +840 +-757 +-17 +-973 +-843 +260 +858 +-389 +-521 +-99 +482 +-561 +-213 +630 +766 +932 +112 +-419 +-877 +762 +266 +-837 +170 +834 +746 +764 +922 +-89 +576 +-63 +90 +684 +316 +506 +-959 +708 +70 +252 +-747 +342 +-593 +-895 +-937 +-707 +350 +588 +-201 +-683 +-113 +-511 +-867 +322 +202 +472 +150 +-9 +-643 +28 +336 +86 +-925 +836 +-473 +-451 +-971 +-805 +-619 +84 +-67 +806 +270 +366 +334 +-555 +-557 +-331 +-409 +-553 +-145 +-71 +528 +490 +492 +828 +628 +-961 +536 +-859 +-271 +974 +-671 +-749 +414 +-257 +778 +56 +598 +-437 +-899 +-785 +-987 +32 +-999 +132 +-821 +-209 +402 +-543 +194 +-967 +294 +-943 +-285 +-483 +-97 +660 +-481 +-829 +-309 +-597 +-855 +80 +-355 +192 +-823 +436 +916 +282 +-629 +612 +-329 +-535 +780 +-47 +706 +110 +756 +-857 +-933 +-345 +-523 +718 +-31 +902 +678 +540 +698 +456 +-399 +126 +412 +-563 +-321 +-487 +-641 +-195 +-199 +-955 +772 +570 +18 +-217 +886 +984 +-721 +-995 +46 +-989 +946 +64 +716 +-719 +-869 +-579 +776 +450 +936 +980 +-439 +-977 +-455 +-997 +6 +268 +-269 +-421 +328 +352 +578 +-575 +476 +976 +-57 +-469 +544 +582 +-43 +510 +-939 +-581 +-337 +-203 +-737 +-827 +852 +-279 +-803 +-911 +-865 +548 +48 +-75 +416 +-275 +688 +-255 +-687 +-461 +-233 +420 +912 +-901 +-299 +12 +568 +694 +-411 +-883 +-327 +-361 +-339 +646 +-137 +-905 +670 +686 +-131 +-849 +-825 +256 +228 +-841 +68 +368 +-909 +242 +298 +118 +10 +222 +954 +-493 +-459 +-445 +608 +-765 +34 +468 +-715 +690 +-185 +-551 +-571 +-241 +292 +92 +768 +-923 +956 +614 +8 +730 +208 +-417 +300 +136 +-59 +-251 +-539 +166 +798 +866 +454 +-391 +-317 +668 +502 +-15 +994 +854 +-189 +666 +446 +-565 +-5 +42 +-227 +-87 +-779 +26 +312 +354 +754 +396 +-515 +220 +872 +654 +88 +-667 +250 +572 +952 +72 +982 +972 +-529 +-471 +-533 +-427 +538 +154 +-457 +-819 +750 +152 +452 +-41 +838 +-489 +418 +-649 +-637 +-197 +74 +394 +-653 +-727 +-435 +-23 +348 +638 +-611 +914 +-357 +-743 +-685 +580 +-247 +-577 +54 +-931 +-3 +558 +-793 +-443 +-759 +162 +-811 +384 +720 +-117 +900 +-519 +-39 +744 +432 +286 +-873 +380 +-167 +-283 +430 +-155 +-755 +206 +100 +364 +-677 +332 +-567 +382 +-605 +-181 +676 +-475 +-845 +910 +546 +14 +398 +616 +-769 +424 +992 +-235 +-239 +774 +478 +-919 +168 +-771 +-773 +-69 +-509 +930 +550 +-463 +178 +-861 +-761 +-795 +234 +-831 +-61 +-979 +-851 +-665 +-709 +896 +742 +-123 +590 +-693 +-887 +-379 +144 +-717 +20 +174 +82 +464 +30 +-969 +-349 +-531 +-799 +-661 +-647 +-623 +878 +148 +-545 +238 +-259 +554 +726 +-37 +-797 +98 +78 +-591 +-975 +962 +120 +906 +-207 +656 +-171 +652 +188 +672 +-133 +-91 +224 +818 +-333 +-839 +-499 +22 +-739 +142 +378 +-403 +-315 +370 +284 +122 +230 +-527 +-127 +442 +534 +160 +722 +262 +-657 +304 +258 +-103 +960 +-495 +-265 +634 +-101 +480 +-363 +308 +76 +-949 +-585 +904 +146 +-703 +164 +850 +246 +732 +-725 +566 +274 +-163 +-935 +-681 +-229 +254 +-733 +-547 +-273 +-903 +736 +-711 +794 +392 +-655 +-549 +808 +-429 +484 +-701 +-617 +804 +36 +-775 +-335 +-927 +714 +-177 +-325 +-413 +-963 +114 +-253 +-789 +-645 +40 +434 +898 +924 +-19 +738 +788 +280 +-121 +594 +-913 +426 +816 +-373 +-45 +340 +-109 +-323 +58 +-249 +940 +-297 +988 +998 +-607 +-745 +-633 +-115 +996 +-893 +696 +400 +848 +500 +-263 +562 +-807 +-105 +-603 +658 +-73 +-863 +448 +680 +-157 +-161 +728 +814 +-477 +-375 +1000 +-631 +-991 +362 +156 +-187 +-705 +-917 +-449 +-741 +556 +440 +-589 +-11 +-359 +-891 +-801 +-153 +-381 +938 +-173 +-243 +618 +-599 +-497 +486 +128 +790 +460 +-27 +-305 +-205 +-215 +324 +-341 +50 +458 +52 +-621 +874 +386 +560 +-569 +-51 +802 +786 +920 +-425 +466 +444 +-507 +-915 +346 +622 +-679 +784 +-689 +388 +508 +-613 +-313 +-447 +564 +-897 +-211 +-225 +-615 +-367 +186 +894 +-65 +-453 +-245 +602 +496 +-651 +-601 +820 +226 +-695 +-119 +372 +180 +94 +214 +542 +648 +-871 +592 +584 +824 +796 +374 +-945 +-311 +516 +942 +-221 +-433 +200 +-465 +-953 +870 +868 +-879 +518 +356 +-223 +682 +990 +-191 +-541 +-951 +-921 +-319 +-169 +-291 +-289 +792 +876 +306 +-491 +326 +-885 +62 +514 +-929 +318 +-231 +632 +44 +-107 +644 +-267 +-343 +-847 +934 +734 +-505 +-351 +574 +-627 +636 +-93 +-431 +-835 +428 +-183 +-151 +2 +-813 +-595 +958 +-141 +692 +-385 +610 +-179 +376 +948 +198 +-675 +964 +-907 +918 +-165 +-1 +406 +748 +-111 +532 +-55 +-281 +740 +504 +236 +-29 +662 +-713 +-537 +196 +-587 +822 +-135 +700 +-35 +674 +-407 +240 +-673 +-669 +-393 +470 +-525 +-875 +-383 +-625 +296 +-85 +-147 +-277 +800 +-691 +-143 +16 +-983 +-303 +290 +-139 +172 +320 +512 +596 +640 +664 +-791 +-783 +-387 +-735 +-467 +-301 +810 +134 +216 +278 +176 +606 +140 +-787 +978 +586 +890 +882 +-753 +-13 +970 +-941 +-175 +-777 +-809 +-441 +-347 +-377 +390 +-423 +842 +642 +190 +302 +438 +704 +310 +-49 +124 +-781 +-287 +724 +-767 +830 +620 +-295 +244 +-159 +-307 +-397 +66 +-237 +314 +-79 +624 +710 +272 +-365 +928 +856 +138 +-479 +520 +832 +862 +760 +846 +-81 +106 +-513 +-193 +650 +782 +-517 +944 +218 +712 +-663 +-559 +462 +-635 +-25 +182 +530 +844 +330 +-833 +102 +-881 +108 +-947 +-763 +-405 +232 +410 +104 +-729 +-149 +-889 +888 +360 +968 +908 +116 +-815 +-129 +522 +-723 +-993 +860 +-503 +926 +-219 +-415 +60 +158 +-609 +-501 +986 +-699 +-583 +884 +212 +210 +-957 +526 +-985 +552 +344 +-395 +-95 +338 +248 +494 +130 +404 +358 +600 +-639 +-125 +-33 +-965 +752 +474 +-731 +758 +-573 +4 +38 +264 diff --git a/bench/TEST_md5sum.txt b/bench/TEST_md5sum.txt new file mode 100644 index 0000000000..15aa8a1c8f --- /dev/null +++ b/bench/TEST_md5sum.txt @@ -0,0 +1,20 @@ +binarytrees 10 7202f4e13df7abc5ad8c07f05fe9d644 +chameneos 1e5 a629ce12f63050c6656bce175258cf8f +cheapconcr 1000 d29799d1e263810a4db7bbf43ca66499 +cheapconcw 1000 d29799d1e263810a4db7bbf43ca66499 +fannkuch 8 51e5e372cbc5471ea8940b20ad782319 +fasta 1e5 78cd327de6f0a5667da0aa9349888279 +knucleotide x 88efb24c1fed533959ed84bb32c88142 = 0 and x < self.nx, "x outside PA") + assert(y >= 0 and y < self.ny, "y outside PA") + assert(z >= 0 and z < self.nz, "z outside PA") + local pos = (z*self.ny + y)*self.nx + x + local image = self.image + if self.packed then + local maxv = self.max_voltage + if p > maxv then self.max_voltage = p*2.0 end + local oldp = image[pos] or 0.0 -- Works with uninitialized table, too + if oldp > maxv then p = p + maxv*2.0 end + image[pos] = p + else + image[pos] = p + end + self.changed = true + self.changed_recently = true +end + +local function array_points(self) + local y, z = 0, 0 + return function(self, x) + x = x + 1 + if x >= self.nx then + x = 0 + y = y + 1 + if y >= self.ny then + y = 0 + z = z + 1 + if z >= self.nz then + return nil, nil, nil + end + end + end + return x, y, z + end, self, 0 +end + +local function array_new(nx, ny, nz, packed) + return { + nx = nx, ny = ny, nz = nz, + packed = packed, max_voltage = 0.0, + changed = false, changed_recently = false, + image = {}, -- Preferably use a fixed-type, pre-sized array here. + set = array_set, + points = array_points, + } +end + +local dim = tonumber(arg and arg[1]) or 300 -- Array dimension dim^3 +local packed = arg and arg[2] == "packed" -- Packed image or flat +local arr = array_new(dim, dim, dim, packed) + +for x,y,z in arr:points() do + arr:set(x, y, z, x*x) +end +assert(arr.image[dim^3-1] == (dim-1)^2) + diff --git a/bench/binary-trees.lua b/bench/binary-trees.lua new file mode 100644 index 0000000000..bf0404666f --- /dev/null +++ b/bench/binary-trees.lua @@ -0,0 +1,47 @@ + +local function BottomUpTree(item, depth) + if depth > 0 then + local i = item + item + depth = depth - 1 + local left, right = BottomUpTree(i-1, depth), BottomUpTree(i, depth) + return { item, left, right } + else + return { item } + end +end + +local function ItemCheck(tree) + if tree[2] then + return tree[1] + ItemCheck(tree[2]) - ItemCheck(tree[3]) + else + return tree[1] + end +end + +local N = tonumber(arg and arg[1]) or 0 +local mindepth = 4 +local maxdepth = mindepth + 2 +if maxdepth < N then maxdepth = N end + +do + local stretchdepth = maxdepth + 1 + local stretchtree = BottomUpTree(0, stretchdepth) + io.write(string.format("stretch tree of depth %d\t check: %d\n", + stretchdepth, ItemCheck(stretchtree))) +end + +local longlivedtree = BottomUpTree(0, maxdepth) + +for depth=mindepth,maxdepth,2 do + local iterations = 2 ^ (maxdepth - depth + mindepth) + local check = 0 + for i=1,iterations do + check = check + ItemCheck(BottomUpTree(1, depth)) + + ItemCheck(BottomUpTree(-1, depth)) + end + io.write(string.format("%d\t trees of depth %d\t check: %d\n", + iterations*2, depth, check)) +end + +io.write(string.format("long lived tree of depth %d\t check: %d\n", + maxdepth, ItemCheck(longlivedtree))) diff --git a/bench/chameneos.lua b/bench/chameneos.lua new file mode 100644 index 0000000000..78b64c3f3b --- /dev/null +++ b/bench/chameneos.lua @@ -0,0 +1,68 @@ + +local co = coroutine +local create, resume, yield = co.create, co.resume, co.yield + +local N = tonumber(arg and arg[1]) or 10 +local first, second + +-- Meet another creature. +local function meet(me) + while second do yield() end -- Wait until meeting place clears. + local other = first + if other then -- Hey, I found a new friend! + first = nil + second = me + else -- Sniff, nobody here (yet). + local n = N - 1 + if n < 0 then return end -- Uh oh, the mall is closed. + N = n + first = me + repeat yield(); other = second until other -- Wait for another creature. + second = nil + yield() -- Be nice and let others meet up. + end + return other +end + +-- Create a very social creature. +local function creature(color) + return create(function() + local me = color + for met=0,1000000000 do + local other = meet(me) + if not other then return met end + if me ~= other then + if me == "blue" then me = other == "red" and "yellow" or "red" + elseif me == "red" then me = other == "blue" and "yellow" or "blue" + else me = other == "blue" and "red" or "blue" end + end + end + end) +end + +-- Trivial round-robin scheduler. +local function schedule(threads) + local resume = resume + local nthreads, meetings = #threads, 0 + repeat + for i=1,nthreads do + local thr = threads[i] + if not thr then return meetings end + local ok, met = resume(thr) + if met then + meetings = meetings + met + threads[i] = nil + end + end + until false +end + +-- A bunch of colorful creatures. +local threads = { + creature("blue"), + creature("red"), + creature("yellow"), + creature("blue"), +} + +io.write(schedule(threads), "\n") diff --git a/bench/coroutine-ring.lua b/bench/coroutine-ring.lua new file mode 100644 index 0000000000..1e8c5ef688 --- /dev/null +++ b/bench/coroutine-ring.lua @@ -0,0 +1,42 @@ +-- The Computer Language Benchmarks Game +-- http://shootout.alioth.debian.org/ +-- contributed by Sam Roberts +-- reviewed by Bruno Massa + +local n = tonumber(arg and arg[1]) or 2e7 + +-- fixed size pool +local poolsize = 503 +local threads = {} + +-- cache these to avoid global environment lookups +local create = coroutine.create +local resume = coroutine.resume +local yield = coroutine.yield + +local id = 1 +local token = 0 +local ok + +local body = function(token) + while true do + token = yield(token + 1) + end +end + +-- create all threads +for id = 1, poolsize do + threads[id] = create(body) +end + +-- send the token +repeat + if id == poolsize then + id = 1 + else + id = id + 1 + end + ok, token = resume(threads[id], token) +until token == n + +io.write(id, "\n") diff --git a/bench/euler14-bit.lua b/bench/euler14-bit.lua new file mode 100644 index 0000000000..537f2bf322 --- /dev/null +++ b/bench/euler14-bit.lua @@ -0,0 +1,22 @@ + +local bit = require("bit") +local bnot, bor, band = bit.bnot, bit.bor, bit.band +local shl, shr = bit.lshift, bit.rshift + +local N = tonumber(arg and arg[1]) or 10000000 +local cache, m, n = { 1 }, 1, 1 +if arg and arg[2] then cache = nil end +for i=2,N do + local j = i + for len=1,1000000000 do + j = bor(band(shr(j,1), band(j,1)-1), band(shl(j,1)+j+1, bnot(band(j,1)-1))) + if cache then + local x = cache[j]; if x then j = x+len; break end + elseif j == 1 then + j = len+1; break + end + end + if cache then cache[i] = j end + if j > m then m, n = j, i end +end +io.write("Found ", n, " (chain length: ", m, ")\n") diff --git a/bench/fannkuch.lua b/bench/fannkuch.lua new file mode 100644 index 0000000000..2a4cd4267a --- /dev/null +++ b/bench/fannkuch.lua @@ -0,0 +1,50 @@ + +local function fannkuch(n) + local p, q, s, odd, check, maxflips = {}, {}, {}, true, 0, 0 + for i=1,n do p[i] = i; q[i] = i; s[i] = i end + repeat + -- Print max. 30 permutations. + if check < 30 then + if not p[n] then return maxflips end -- Catch n = 0, 1, 2. + io.write(unpack(p)); io.write("\n") + check = check + 1 + end + -- Copy and flip. + local q1 = p[1] -- Cache 1st element. + if p[n] ~= n and q1 ~= 1 then -- Avoid useless work. + for i=2,n do q[i] = p[i] end -- Work on a copy. + local flips = 1 -- Flip ... + while true do + local qq = q[q1] + if qq == 1 then -- ... until 1st element is 1. + if flips > maxflips then maxflips = flips end -- New maximum? + break + end + q[q1] = q1 + if q1 >= 4 then + local i, j = 2, q1 - 1 + repeat q[i], q[j] = q[j], q[i]; i = i + 1; j = j - 1; until i >= j + end + q1 = qq + flips=flips+1 + end + end + -- Permute. + if odd then + p[2], p[1] = p[1], p[2]; odd = false -- Rotate 1<-2. + else + p[2], p[3] = p[3], p[2]; odd = true -- Rotate 1<-2 and 1<-2<-3. + for i=3,n do + local sx = s[i] + if sx ~= 1 then s[i] = sx-1; break end + if i == n then return maxflips end -- Out of permutations. + s[i] = i + -- Rotate 1<-...<-i+1. + local t=p[1]; for j=i+1,1,-1 do p[j],t=t,p[j] end + end + end + until false +end + +local n = tonumber(arg and arg[1]) or 1 +io.write("Pfannkuchen(", n, ") = ", fannkuch(n), "\n") diff --git a/bench/fasta.lua b/bench/fasta.lua new file mode 100644 index 0000000000..7ce6080411 --- /dev/null +++ b/bench/fasta.lua @@ -0,0 +1,95 @@ + +local Last = 42 +local function random(max) + local y = (Last * 3877 + 29573) % 139968 + Last = y + return (max * y) / 139968 +end + +local function make_repeat_fasta(id, desc, s, n) + local write, sub = io.write, string.sub + write(">", id, " ", desc, "\n") + local p, sn, s2 = 1, #s, s..s + for i=60,n,60 do + write(sub(s2, p, p + 59), "\n") + p = p + 60; if p > sn then p = p - sn end + end + local tail = n % 60 + if tail > 0 then write(sub(s2, p, p + tail-1), "\n") end +end + +local function make_random_fasta(id, desc, bs, n) + io.write(">", id, " ", desc, "\n") + loadstring([=[ + local write, char, unpack, n, random = io.write, string.char, unpack, ... + local buf, p = {}, 1 + for i=60,n,60 do + for j=p,p+59 do ]=]..bs..[=[ end + buf[p+60] = 10; p = p + 61 + if p >= 2048 then write(char(unpack(buf, 1, p-1))); p = 1 end + end + local tail = n % 60 + if tail > 0 then + for j=p,p+tail-1 do ]=]..bs..[=[ end + p = p + tail; buf[p] = 10; p = p + 1 + end + write(char(unpack(buf, 1, p-1))) + ]=], desc)(n, random) +end + +local function bisect(c, p, lo, hi) + local n = hi - lo + if n == 0 then return "buf[j] = "..c[hi].."\n" end + local mid = math.floor(n / 2) + return "if r < "..p[lo+mid].." then\n"..bisect(c, p, lo, lo+mid).. + "else\n"..bisect(c, p, lo+mid+1, hi).."end\n" +end + +local function make_bisect(tab) + local c, p, sum = {}, {}, 0 + for i,row in ipairs(tab) do + c[i] = string.byte(row[1]) + sum = sum + row[2] + p[i] = sum + end + return "local r = random(1)\n"..bisect(c, p, 1, #tab) +end + +local alu = + "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG".. + "GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA".. + "CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT".. + "ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA".. + "GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG".. + "AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC".. + "AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA" + +local iub = make_bisect{ + { "a", 0.27 }, + { "c", 0.12 }, + { "g", 0.12 }, + { "t", 0.27 }, + { "B", 0.02 }, + { "D", 0.02 }, + { "H", 0.02 }, + { "K", 0.02 }, + { "M", 0.02 }, + { "N", 0.02 }, + { "R", 0.02 }, + { "S", 0.02 }, + { "V", 0.02 }, + { "W", 0.02 }, + { "Y", 0.02 }, +} + +local homosapiens = make_bisect{ + { "a", 0.3029549426680 }, + { "c", 0.1979883004921 }, + { "g", 0.1975473066391 }, + { "t", 0.3015094502008 }, +} + +local N = tonumber(arg and arg[1]) or 1000 +make_repeat_fasta('ONE', 'Homo sapiens alu', alu, N*2) +make_random_fasta('TWO', 'IUB ambiguity codes', iub, N*3) +make_random_fasta('THREE', 'Homo sapiens frequency', homosapiens, N*5) diff --git a/bench/k-nucleotide.lua b/bench/k-nucleotide.lua new file mode 100644 index 0000000000..0bfb41bec5 --- /dev/null +++ b/bench/k-nucleotide.lua @@ -0,0 +1,58 @@ + +local function kfrequency(seq, freq, k, frame) + local sub = string.sub + local k1 = k - 1 + for i=frame,#seq-k1,k do + local c = sub(seq, i, i+k1) + freq[c] = (freq[c] or 0) + 1 + end +end + +local function count(seq, frag) + local k = #frag + local freq = {} + for frame=1,k do kfrequency(seq, freq, k, frame) end + io.write(freq[frag] or 0, "\t", frag, "\n") +end + +local function frequency(seq, k) + local freq = {} + for frame=1,k do kfrequency(seq, freq, k, frame) end + local sfreq, sn, sum = {}, 1, 0 + for c,v in pairs(freq) do sfreq[sn] = c; sn = sn + 1; sum = sum + v end + table.sort(sfreq, function(a, b) + local fa, fb = freq[a], freq[b] + return fa == fb and a > b or fa > fb + end) + for _,c in ipairs(sfreq) do + io.write(string.format("%s %0.3f\n", c, (freq[c]*100)/sum)) + end + io.write("\n") +end + +local function readseq() + local sub = string.sub + for line in io.lines() do + if sub(line, 1, 1) == ">" and sub(line, 2, 6) == "THREE" then break end + end + local lines, ln = {}, 0 + for line in io.lines() do + local c = sub(line, 1, 1) + if c == ">" then + break + elseif c ~= ";" then + ln = ln + 1 + lines[ln] = line + end + end + return string.upper(table.concat(lines, "", 1, ln)) +end + +local seq = readseq() +frequency(seq, 1) +frequency(seq, 2) +count(seq, "GGT") +count(seq, "GGTA") +count(seq, "GGTATT") +count(seq, "GGTATTTTAATT") +count(seq, "GGTATTTTAATTTATAGT") diff --git a/bench/life.lua b/bench/life.lua new file mode 100644 index 0000000000..911d9fe177 --- /dev/null +++ b/bench/life.lua @@ -0,0 +1,111 @@ +-- life.lua +-- original by Dave Bollinger posted to lua-l +-- modified to use ANSI terminal escape sequences +-- modified to use for instead of while + +local write=io.write + +ALIVE="¥" DEAD="þ" +ALIVE="O" DEAD="-" + +function delay() -- NOTE: SYSTEM-DEPENDENT, adjust as necessary + for i=1,10000 do end + -- local i=os.clock()+1 while(os.clock() 0 do + local xm1,x,xp1,xi=self.w-1,self.w,1,self.w + while xi > 0 do + local sum = self[ym1][xm1] + self[ym1][x] + self[ym1][xp1] + + self[y][xm1] + self[y][xp1] + + self[yp1][xm1] + self[yp1][x] + self[yp1][xp1] + next[y][x] = ((sum==2) and self[y][x]) or ((sum==3) and 1) or 0 + xm1,x,xp1,xi = x,xp1,xp1+1,xi-1 + end + ym1,y,yp1,yi = y,yp1,yp1+1,yi-1 + end +end + +-- output the array to screen +function _CELLS:draw() + local out="" -- accumulate to reduce flicker + for y=1,self.h do + for x=1,self.w do + out=out..(((self[y][x]>0) and ALIVE) or DEAD) + end + out=out.."\n" + end + write(out) +end + +-- constructor +function CELLS(w,h) + local c = ARRAY2D(w,h) + c.spawn = _CELLS.spawn + c.evolve = _CELLS.evolve + c.draw = _CELLS.draw + return c +end + +-- +-- shapes suitable for use with spawn() above +-- +HEART = { 1,0,1,1,0,1,1,1,1; w=3,h=3 } +GLIDER = { 0,0,1,1,0,1,0,1,1; w=3,h=3 } +EXPLODE = { 0,1,0,1,1,1,1,0,1,0,1,0; w=3,h=4 } +FISH = { 0,1,1,1,1,1,0,0,0,1,0,0,0,0,1,1,0,0,1,0; w=5,h=4 } +BUTTERFLY = { 1,0,0,0,1,0,1,1,1,0,1,0,0,0,1,1,0,1,0,1,1,0,0,0,1; w=5,h=5 } + +-- the main routine +function LIFE(w,h) + -- create two arrays + local thisgen = CELLS(w,h) + local nextgen = CELLS(w,h) + + -- create some life + -- about 1000 generations of fun, then a glider steady-state + thisgen:spawn(GLIDER,5,4) + thisgen:spawn(EXPLODE,25,10) + thisgen:spawn(FISH,4,12) + + -- run until break + local gen=1 + write("\027[2J") -- ANSI clear screen + while 1 do + thisgen:evolve(nextgen) + thisgen,nextgen = nextgen,thisgen + write("\027[H") -- ANSI home cursor + thisgen:draw() + write("Life - generation ",gen,"\n") + gen=gen+1 + if gen>2000 then break end + --delay() -- no delay + end +end + +LIFE(40,20) diff --git a/bench/mandelbrot-bit.lua b/bench/mandelbrot-bit.lua new file mode 100644 index 0000000000..91d96975c8 --- /dev/null +++ b/bench/mandelbrot-bit.lua @@ -0,0 +1,33 @@ + +local bit = require("bit") +local bor, band = bit.bor, bit.band +local shl, shr, rol = bit.lshift, bit.rshift, bit.rol +local write, char, unpack = io.write, string.char, unpack +local N = tonumber(arg and arg[1]) or 100 +local M, buf = 2/N, {} +write("P4\n", N, " ", N, "\n") +for y=0,N-1 do + local Ci, b, p = y*M-1, -16777216, 0 + local Ciq = Ci*Ci + for x=0,N-1,2 do + local Cr, Cr2 = x*M-1.5, (x+1)*M-1.5 + local Zr, Zi, Zrq, Ziq = Cr, Ci, Cr*Cr, Ciq + local Zr2, Zi2, Zrq2, Ziq2 = Cr2, Ci, Cr2*Cr2, Ciq + b = rol(b, 2) + for i=1,49 do + Zi = Zr*Zi*2 + Ci; Zi2 = Zr2*Zi2*2 + Ci + Zr = Zrq-Ziq + Cr; Zr2 = Zrq2-Ziq2 + Cr2 + Ziq = Zi*Zi; Ziq2 = Zi2*Zi2 + Zrq = Zr*Zr; Zrq2 = Zr2*Zr2 + if band(b, 2) ~= 0 and Zrq+Ziq > 4.0 then b = band(b, -3) end + if band(b, 1) ~= 0 and Zrq2+Ziq2 > 4.0 then b = band(b, -2) end + if band(b, 3) == 0 then break end + end + if b >= 0 then p = p + 1; buf[p] = b; b = -16777216; end + end + if b ~= -16777216 then + if band(N, 1) ~= 0 then b = shr(b, 1) end + p = p + 1; buf[p] = shl(b, 8-band(N, 7)) + end + write(char(unpack(buf, 1, p))) +end diff --git a/bench/mandelbrot.lua b/bench/mandelbrot.lua new file mode 100644 index 0000000000..0ef595a2fe --- /dev/null +++ b/bench/mandelbrot.lua @@ -0,0 +1,23 @@ + +local write, char, unpack = io.write, string.char, unpack +local N = tonumber(arg and arg[1]) or 100 +local M, ba, bb, buf = 2/N, 2^(N%8+1)-1, 2^(8-N%8), {} +write("P4\n", N, " ", N, "\n") +for y=0,N-1 do + local Ci, b, p = y*M-1, 1, 0 + for x=0,N-1 do + local Cr = x*M-1.5 + local Zr, Zi, Zrq, Ziq = Cr, Ci, Cr*Cr, Ci*Ci + b = b + b + for i=1,49 do + Zi = Zr*Zi*2 + Ci + Zr = Zrq-Ziq + Cr + Ziq = Zi*Zi + Zrq = Zr*Zr + if Zrq+Ziq > 4.0 then b = b + 1; break; end + end + if b >= 256 then p = p + 1; buf[p] = 511 - b; b = 1; end + end + if b ~= 1 then p = p + 1; buf[p] = (ba-b)*bb; end + write(char(unpack(buf, 1, p))) +end diff --git a/bench/md5.lua b/bench/md5.lua new file mode 100644 index 0000000000..fdf6b4a7c7 --- /dev/null +++ b/bench/md5.lua @@ -0,0 +1,183 @@ + +local bit = require("bit") +local tobit, tohex, bnot = bit.tobit or bit.cast, bit.tohex, bit.bnot +local bor, band, bxor = bit.bor, bit.band, bit.bxor +local lshift, rshift, rol, bswap = bit.lshift, bit.rshift, bit.rol, bit.bswap +local byte, char, sub, rep = string.byte, string.char, string.sub, string.rep + +if not rol then -- Replacement function if rotates are missing. + local bor, shl, shr = bit.bor, bit.lshift, bit.rshift + function rol(a, b) return bor(shl(a, b), shr(a, 32-b)) end +end + +if not bswap then -- Replacement function if bswap is missing. + local bor, band, shl, shr = bit.bor, bit.band, bit.lshift, bit.rshift + function bswap(a) + return bor(shr(a, 24), band(shr(a, 8), 0xff00), + shl(band(a, 0xff00), 8), shl(a, 24)); + end +end + +if not tohex then -- (Unreliable) replacement function if tohex is missing. + function tohex(a) + return string.sub(string.format("%08x", a), -8) + end +end + +local function tr_f(a, b, c, d, x, s) + return rol(bxor(d, band(b, bxor(c, d))) + a + x, s) + b +end + +local function tr_g(a, b, c, d, x, s) + return rol(bxor(c, band(d, bxor(b, c))) + a + x, s) + b +end + +local function tr_h(a, b, c, d, x, s) + return rol(bxor(b, c, d) + a + x, s) + b +end + +local function tr_i(a, b, c, d, x, s) + return rol(bxor(c, bor(b, bnot(d))) + a + x, s) + b +end + +local function transform(x, a1, b1, c1, d1) + local a, b, c, d = a1, b1, c1, d1 + + a = tr_f(a, b, c, d, x[ 1] + 0xd76aa478, 7) + d = tr_f(d, a, b, c, x[ 2] + 0xe8c7b756, 12) + c = tr_f(c, d, a, b, x[ 3] + 0x242070db, 17) + b = tr_f(b, c, d, a, x[ 4] + 0xc1bdceee, 22) + a = tr_f(a, b, c, d, x[ 5] + 0xf57c0faf, 7) + d = tr_f(d, a, b, c, x[ 6] + 0x4787c62a, 12) + c = tr_f(c, d, a, b, x[ 7] + 0xa8304613, 17) + b = tr_f(b, c, d, a, x[ 8] + 0xfd469501, 22) + a = tr_f(a, b, c, d, x[ 9] + 0x698098d8, 7) + d = tr_f(d, a, b, c, x[10] + 0x8b44f7af, 12) + c = tr_f(c, d, a, b, x[11] + 0xffff5bb1, 17) + b = tr_f(b, c, d, a, x[12] + 0x895cd7be, 22) + a = tr_f(a, b, c, d, x[13] + 0x6b901122, 7) + d = tr_f(d, a, b, c, x[14] + 0xfd987193, 12) + c = tr_f(c, d, a, b, x[15] + 0xa679438e, 17) + b = tr_f(b, c, d, a, x[16] + 0x49b40821, 22) + + a = tr_g(a, b, c, d, x[ 2] + 0xf61e2562, 5) + d = tr_g(d, a, b, c, x[ 7] + 0xc040b340, 9) + c = tr_g(c, d, a, b, x[12] + 0x265e5a51, 14) + b = tr_g(b, c, d, a, x[ 1] + 0xe9b6c7aa, 20) + a = tr_g(a, b, c, d, x[ 6] + 0xd62f105d, 5) + d = tr_g(d, a, b, c, x[11] + 0x02441453, 9) + c = tr_g(c, d, a, b, x[16] + 0xd8a1e681, 14) + b = tr_g(b, c, d, a, x[ 5] + 0xe7d3fbc8, 20) + a = tr_g(a, b, c, d, x[10] + 0x21e1cde6, 5) + d = tr_g(d, a, b, c, x[15] + 0xc33707d6, 9) + c = tr_g(c, d, a, b, x[ 4] + 0xf4d50d87, 14) + b = tr_g(b, c, d, a, x[ 9] + 0x455a14ed, 20) + a = tr_g(a, b, c, d, x[14] + 0xa9e3e905, 5) + d = tr_g(d, a, b, c, x[ 3] + 0xfcefa3f8, 9) + c = tr_g(c, d, a, b, x[ 8] + 0x676f02d9, 14) + b = tr_g(b, c, d, a, x[13] + 0x8d2a4c8a, 20) + + a = tr_h(a, b, c, d, x[ 6] + 0xfffa3942, 4) + d = tr_h(d, a, b, c, x[ 9] + 0x8771f681, 11) + c = tr_h(c, d, a, b, x[12] + 0x6d9d6122, 16) + b = tr_h(b, c, d, a, x[15] + 0xfde5380c, 23) + a = tr_h(a, b, c, d, x[ 2] + 0xa4beea44, 4) + d = tr_h(d, a, b, c, x[ 5] + 0x4bdecfa9, 11) + c = tr_h(c, d, a, b, x[ 8] + 0xf6bb4b60, 16) + b = tr_h(b, c, d, a, x[11] + 0xbebfbc70, 23) + a = tr_h(a, b, c, d, x[14] + 0x289b7ec6, 4) + d = tr_h(d, a, b, c, x[ 1] + 0xeaa127fa, 11) + c = tr_h(c, d, a, b, x[ 4] + 0xd4ef3085, 16) + b = tr_h(b, c, d, a, x[ 7] + 0x04881d05, 23) + a = tr_h(a, b, c, d, x[10] + 0xd9d4d039, 4) + d = tr_h(d, a, b, c, x[13] + 0xe6db99e5, 11) + c = tr_h(c, d, a, b, x[16] + 0x1fa27cf8, 16) + b = tr_h(b, c, d, a, x[ 3] + 0xc4ac5665, 23) + + a = tr_i(a, b, c, d, x[ 1] + 0xf4292244, 6) + d = tr_i(d, a, b, c, x[ 8] + 0x432aff97, 10) + c = tr_i(c, d, a, b, x[15] + 0xab9423a7, 15) + b = tr_i(b, c, d, a, x[ 6] + 0xfc93a039, 21) + a = tr_i(a, b, c, d, x[13] + 0x655b59c3, 6) + d = tr_i(d, a, b, c, x[ 4] + 0x8f0ccc92, 10) + c = tr_i(c, d, a, b, x[11] + 0xffeff47d, 15) + b = tr_i(b, c, d, a, x[ 2] + 0x85845dd1, 21) + a = tr_i(a, b, c, d, x[ 9] + 0x6fa87e4f, 6) + d = tr_i(d, a, b, c, x[16] + 0xfe2ce6e0, 10) + c = tr_i(c, d, a, b, x[ 7] + 0xa3014314, 15) + b = tr_i(b, c, d, a, x[14] + 0x4e0811a1, 21) + a = tr_i(a, b, c, d, x[ 5] + 0xf7537e82, 6) + d = tr_i(d, a, b, c, x[12] + 0xbd3af235, 10) + c = tr_i(c, d, a, b, x[ 3] + 0x2ad7d2bb, 15) + b = tr_i(b, c, d, a, x[10] + 0xeb86d391, 21) + + return tobit(a+a1), tobit(b+b1), tobit(c+c1), tobit(d+d1) +end + +-- Note: this is copying the original string and NOT particularly fast. +-- A library for struct unpacking would make this task much easier. +local function md5(msg) + local len = #msg + msg = msg.."\128"..rep("\0", 63 - band(len + 8, 63)) + ..char(band(lshift(len, 3), 255), band(rshift(len, 5), 255), + band(rshift(len, 13), 255), band(rshift(len, 21), 255)) + .."\0\0\0\0" + local a, b, c, d = 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 + local x, k = {}, 1 + for i=1,#msg,4 do + local m0, m1, m2, m3 = byte(msg, i, i+3) + x[k] = bor(m0, lshift(m1, 8), lshift(m2, 16), lshift(m3, 24)) + if k == 16 then + a, b, c, d = transform(x, a, b, c, d) + k = 1 + else + k = k + 1 + end + end + return tohex(bswap(a))..tohex(bswap(b))..tohex(bswap(c))..tohex(bswap(d)) +end + +assert(md5('') == 'd41d8cd98f00b204e9800998ecf8427e') +assert(md5('a') == '0cc175b9c0f1b6a831c399e269772661') +assert(md5('abc') == '900150983cd24fb0d6963f7d28e17f72') +assert(md5('message digest') == 'f96b697d7cb7938d525a2f31aaf161d0') +assert(md5('abcdefghijklmnopqrstuvwxyz') == 'c3fcd3d76192e4007dfb496cca67e13b') +assert(md5('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') == + 'd174ab98d277d9f5a5611c2c9f419d9f') +assert(md5('12345678901234567890123456789012345678901234567890123456789012345678901234567890') == + '57edf4a22be3c955ac49da2e2107b67a') + +local N = tonumber(arg and arg[1]) or 10000 + + -- Credits: William Shakespeare, Romeo and Juliet +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 + txt = txt..txt..txt..txt + +for i=1,N do + res = md5(txt) +end +assert(res == 'a831e91e0f70eddcb70dc61c6f82f6cd') + diff --git a/bench/meteor.lua b/bench/meteor.lua new file mode 100644 index 0000000000..80588ab532 --- /dev/null +++ b/bench/meteor.lua @@ -0,0 +1,220 @@ + +-- Generate a decision tree based solver for the meteor puzzle. +local function generatesolver(countinit) + local pairs, ipairs, format = pairs, ipairs, string.format + local byte, min, sort = string.byte, math.min, table.sort + + -- Cached position to distance lookup. + local dist = setmetatable({}, { __index = function(t, xy) + local x = xy%10; local y = (xy-x)/10 + if (x+y)%2 == 1 then y = y + 1; x = 10 - x end + local d = xy + 256*x*x + 1024*y*y; t[xy] = d; return d + end}) + + -- Lookup table to validate a cell and to find its successor. + local ok = {} + for i=0,150 do ok[i] = false end + for i=99,0,-1 do + local x = i%10 + if ((i-x)/10+x)%2 == 0 then + ok[i] = i + (ok[i+1] and 1 or (ok[i+2] and 2 or 3)) + end + end + + -- Temporary board state for the island checks. + local islands, slide = {}, {20,22,24,26,28,31,33,35,37,39} + local bbc, bb = 0, {} + for i=0,19 do bb[i] = false; bb[i+80] = false end + for i=20,79 do bb[i] = ok[i] end + + -- Recursive flood fill algorithm. + local function fill(bb, p) + bbc = bbc + 1 + local n = p+2; if bb[n] then bb[n] = false; fill(bb, n) end + n = p-2; if bb[n] then bb[n] = false; fill(bb, n) end + n = p-9; if bb[n] then bb[n] = false; fill(bb, n) end + n = p-11; if bb[n] then bb[n] = false; fill(bb, n) end + n = p+9; if bb[n] then bb[n] = false; fill(bb, n) end + n = p+11; if bb[n] then bb[n] = false; fill(bb, n) end + end + + -- Generate pruned, sliding decision trees. + local dtrees = {{}, {}, {}, {}, {}, {}, {}, {}, {}, {}} + local rot = { nil, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {} } + for k=0,9 do + -- Generate 10 initial pieces from line noise. :-) + local t = { 60, 62, byte("@BMBIK@KT@GPIKR@IKIKT@GK@KM@BG", k*3+1, k*3+3) } + rot[1] = t + for i,xy in ipairs(t) do + local x = xy%10; local y = (xy-x-60)/10 + -- Add 11 more variations by rotating and flipping. + for j=2,12 do + if j == 7 then y = -y else x,y = (x+3*y)/2, (y-x)/2 end + rot[j][i] = x+10*y + end + end + for r,v in ipairs(rot) do + -- Exploit symmetry and leave out half of the orientations of one piece. + -- The selected piece gives the best reduction of the solution space. + if k ~= 3 or r%2 == 0 then + -- Normalize to origin, add distance, sort by distance from origin. + local m = min(v[1], v[2], v[3], v[4], v[5]) + for i=1,5 do v[i] = dist[v[i]-m] end + sort(v) + local v2, v3, v4, v5 = v[2]%256, v[3]%256, v[4]%256, v[5]%256 + -- Slide the piece across 2 rows, prune the tree, check for islands. + for j,p in ipairs(slide) do + bb[p] = false + if ok[p+v2] and ok[p+v3] and ok[p+v4] and ok[p+v5] then -- Prune. + for i=p+1,79 do bb[i] = ok[i] end -- Clear remaining board. + bb[p+v2] = false; bb[p+v3] = false -- Add piece. + bb[p+v4] = false; bb[p+v5] = false + bbc = j -- Flood fill and count the filled positions. + if bb[71] then bb[71] = false; fill(bb, 71) end -- Lower left. + if bb[79] then bb[79] = false; fill(bb, 79) end -- Lower right. + local di = 0 + if bbc < 22 then bbc = 26 + elseif bbc < 26 then -- Island found, locate it, fill from above. + for i=p+2,79 do if bb[i] then di = i-p; break end end + for i=p-9,p-1 do if ok[i] then fill(bb, i) bbc = bbc - 1 end end + end + if bbc == 26 then -- Prune boards with static islands. + local tb = dtrees[j] -- Build decision tree in distance order. + local ta = tb[v2]; if not ta then ta = {}; tb[v2] = ta end + tb = ta[v3]; if not tb then tb = {}; ta[v3] = tb end + ta = tb[v4]; if not ta then ta = {}; tb[v4] = ta; islands[ta] = di + elseif islands[ta] ~= di then islands[ta] = 0 end + ta[v5] = di*10+k -- Leaves hold island check and piece number. + end + end + end + end + end + end + + local s = "local u0,u1,u2,u3,u4,u5,u6,u7,u8,u9" -- Piece use flags. + for p=0,99 do if ok[p] then s = s..",b"..p end end -- Board cells. + s = s.."\n"..[[ +local countinit = ... +local count = countinit +local bmin, bmax, pcs = 9, 0, {} +local smin, smax +local write, reverse = io.write, string.reverse + +-- Print min/max boards. +local function printboard(s) + local flip = true + for x in string.gmatch(string.gsub(s, ".", "%1 "), "..........") do + write(x, flip and "\n " or "\n") + flip = not flip + end + write("\n") +end + +-- Print result. +local function printresult() + write(countinit-count, " solutions found\n\n") + printboard(smin) + printboard(smax) +end + +-- Generate piece lookup array from the order of use. +local function genp() + local p = pcs + p[u0] = "0" p[u1] = "1" p[u2] = "2" p[u3] = "3" p[u4] = "4" + p[u5] = "5" p[u6] = "6" p[u7] = "7" p[u8] = "8" p[u9] = "9" + return p +end + +-- Goal function. +local function f91(k) + if k ~= 10 then return end + count = count - 2 -- Need to count the symmetric solution, too. + repeat + -- Quick precheck before constructing the string. + local b0, b99 = b0, b99 + if b0 <= bmin then bmin = b0 elseif b0 >= bmax then bmax = b0 + elseif b99 <= bmin then bmin = b99 elseif b99 >= bmax then bmax = b99 + else break end + -- Translate the filled board to a string. + local p = genp() + local s = p[b0] ]] + for p=2,99 do if ok[p] then s = s.."..p[b"..p.."]" end end + s = s..[[ + -- Remember min/max boards, dito for the symmetric board. + if not smin then smin = s; smax = s + elseif s < smin then smin = s elseif s > smax then smax = s end + s = reverse(s) + if s < smin then smin = s elseif s > smax then smax = s end + until true + if count <= 0 then error() end -- Early abort if max count given. +end +local f93 = f91 +]] + + -- Recursively convert the decision tree to Lua code. + local function codetree(tree, d, p, pn) + local found, s = false, "" + d = d + 1 + for a,t in pairs(tree) do + local b = p+a + if b < 100 then -- Prune the tree at the lower border. + local pp = b ~= pn and pn or ok[b] -- Find maximum successor function. + if d >= 5 then -- Try to place the last cell of a piece and advance. + found = true + local u = t%10 + local di = (t-u)/10 + if di ~= 0 and d == 5 then + di = di + p; if pp == di then pp = ok[di] end + s = format("%sif b%d and not u%d and not b%d then b%d=k u%d=k f%d(k) u%d=N b%d=N end\n", + s, di, u, b, b, u, pp, u, b) + else + s = format("%sif not u%d and not b%d then b%d=k u%d=k f%d(k) u%d=N b%d=N end\n", + s, u, b, b, u, pp, u, b) + end + else -- Try to place an intermediate cell. + local di = d ~= 4 and 0 or islands[t] + if di == 0 then + local st = codetree(t, d, p, pp) + if st then + found = true + s = format("%sif not b%d then b%d=k\n%sb%d=N end\n", s, b, b, st, b) + end + else -- Combine island checks. + di = di + p; if pp == di then pp = ok[di] end + local st = codetree(t, 6, p, pp) + if st then + found = true + s = format("%sif b%d and not b%d then b%d=k\n%sb%d=N end\n", s, di, b, b, st, b) + end + end + end + end + end + return found and s + end + + -- Embed the decision tree into a function hierarchy. + local j = 5 + for p=88,0,-1 do + local pn = ok[p] + if pn then + s = format("%slocal function f%d(k)\nlocal N if b%d then return f%d(k) end k=k+1 b%d=k\n%sb%d=N end\n", + s, p, p, pn, p, codetree(dtrees[j], 1, p, pn), p) + j = j - 1; if j == 0 then j = 10 end + end + end + + -- Compile and return solver function and result getter. + return loadstring(s.."return f0, printresult\n", "solver")(countinit) +end + +-- Generate the solver function hierarchy. +local solver, printresult = generatesolver(tonumber(arg and arg[1]) or 10000) + +-- The optimizer for LuaJIT 1.1.x is not helpful here, so turn it off. +if jit and jit.opt and jit.version_num < 10200 then jit.opt.start(0) end + +-- Run the solver protected to get partial results (max count or ctrl-c). +pcall(solver, 0) +printresult() diff --git a/bench/nbody.lua b/bench/nbody.lua new file mode 100644 index 0000000000..e0ff8f7712 --- /dev/null +++ b/bench/nbody.lua @@ -0,0 +1,119 @@ + +local sqrt = math.sqrt + +local PI = 3.141592653589793 +local SOLAR_MASS = 4 * PI * PI +local DAYS_PER_YEAR = 365.24 +local bodies = { + { -- Sun + x = 0, + y = 0, + z = 0, + vx = 0, + vy = 0, + vz = 0, + mass = SOLAR_MASS + }, + { -- Jupiter + x = 4.84143144246472090e+00, + y = -1.16032004402742839e+00, + z = -1.03622044471123109e-01, + vx = 1.66007664274403694e-03 * DAYS_PER_YEAR, + vy = 7.69901118419740425e-03 * DAYS_PER_YEAR, + vz = -6.90460016972063023e-05 * DAYS_PER_YEAR, + mass = 9.54791938424326609e-04 * SOLAR_MASS + }, + { -- Saturn + x = 8.34336671824457987e+00, + y = 4.12479856412430479e+00, + z = -4.03523417114321381e-01, + vx = -2.76742510726862411e-03 * DAYS_PER_YEAR, + vy = 4.99852801234917238e-03 * DAYS_PER_YEAR, + vz = 2.30417297573763929e-05 * DAYS_PER_YEAR, + mass = 2.85885980666130812e-04 * SOLAR_MASS + }, + { -- Uranus + x = 1.28943695621391310e+01, + y = -1.51111514016986312e+01, + z = -2.23307578892655734e-01, + vx = 2.96460137564761618e-03 * DAYS_PER_YEAR, + vy = 2.37847173959480950e-03 * DAYS_PER_YEAR, + vz = -2.96589568540237556e-05 * DAYS_PER_YEAR, + mass = 4.36624404335156298e-05 * SOLAR_MASS + }, + { -- Neptune + x = 1.53796971148509165e+01, + y = -2.59193146099879641e+01, + z = 1.79258772950371181e-01, + vx = 2.68067772490389322e-03 * DAYS_PER_YEAR, + vy = 1.62824170038242295e-03 * DAYS_PER_YEAR, + vz = -9.51592254519715870e-05 * DAYS_PER_YEAR, + mass = 5.15138902046611451e-05 * SOLAR_MASS + } +} + +local function advance(bodies, nbody, dt) + for i=1,nbody do + local bi = bodies[i] + local bix, biy, biz, bimass = bi.x, bi.y, bi.z, bi.mass + local bivx, bivy, bivz = bi.vx, bi.vy, bi.vz + for j=i+1,nbody do + local bj = bodies[j] + local dx, dy, dz = bix-bj.x, biy-bj.y, biz-bj.z + local mag = sqrt(dx*dx + dy*dy + dz*dz) + mag = dt / (mag * mag * mag) + local bm = bj.mass*mag + bivx = bivx - (dx * bm) + bivy = bivy - (dy * bm) + bivz = bivz - (dz * bm) + bm = bimass*mag + bj.vx = bj.vx + (dx * bm) + bj.vy = bj.vy + (dy * bm) + bj.vz = bj.vz + (dz * bm) + end + bi.vx = bivx + bi.vy = bivy + bi.vz = bivz + bi.x = bix + dt * bivx + bi.y = biy + dt * bivy + bi.z = biz + dt * bivz + end +end + +local function energy(bodies, nbody) + local e = 0 + for i=1,nbody do + local bi = bodies[i] + local vx, vy, vz, bim = bi.vx, bi.vy, bi.vz, bi.mass + e = e + (0.5 * bim * (vx*vx + vy*vy + vz*vz)) + for j=i+1,nbody do + local bj = bodies[j] + local dx, dy, dz = bi.x-bj.x, bi.y-bj.y, bi.z-bj.z + local distance = sqrt(dx*dx + dy*dy + dz*dz) + e = e - ((bim * bj.mass) / distance) + end + end + return e +end + +local function offsetMomentum(b, nbody) + local px, py, pz = 0, 0, 0 + for i=1,nbody do + local bi = b[i] + local bim = bi.mass + px = px + (bi.vx * bim) + py = py + (bi.vy * bim) + pz = pz + (bi.vz * bim) + end + b[1].vx = -px / SOLAR_MASS + b[1].vy = -py / SOLAR_MASS + b[1].vz = -pz / SOLAR_MASS +end + +local N = tonumber(arg and arg[1]) or 1000 +local nbody = #bodies + +offsetMomentum(bodies, nbody) +io.write( string.format("%0.9f",energy(bodies, nbody)), "\n") +for i=1,N do advance(bodies, nbody, 0.01) end +io.write( string.format("%0.9f",energy(bodies, nbody)), "\n") diff --git a/bench/nsieve-bit-fp.lua b/bench/nsieve-bit-fp.lua new file mode 100644 index 0000000000..3971ec1f1e --- /dev/null +++ b/bench/nsieve-bit-fp.lua @@ -0,0 +1,37 @@ + +local floor, ceil = math.floor, math.ceil + +local precision = 50 -- Maximum precision of lua_Number (minus safety margin). +local onebits = (2^precision)-1 + +local function nsieve(p, m) + local cm = ceil(m/precision) + do local onebits = onebits; for i=0,cm do p[i] = onebits end end + local count, idx, bit = 0, 2, 2 + for i=2,m do + local r = p[idx] / bit + if r - floor(r) >= 0.5 then -- Bit set? + local kidx, kbit = idx, bit + for k=i+i,m,i do + kidx = kidx + i + while kidx >= cm do kidx = kidx - cm; kbit = kbit + kbit end + local x = p[kidx] + local r = x / kbit + if r - floor(r) >= 0.5 then p[kidx] = x - kbit*0.5 end -- Clear bit. + end + count = count + 1 + end + idx = idx + 1 + if idx >= cm then idx = 0; bit = bit + bit end + end + return count +end + +local N = tonumber(arg and arg[1]) or 1 +if N < 2 then N = 2 end +local primes = {} + +for i=0,2 do + local m = (2^(N-i))*10000 + io.write(string.format("Primes up to %8d %8d\n", m, nsieve(primes, m))) +end diff --git a/bench/nsieve-bit.lua b/bench/nsieve-bit.lua new file mode 100644 index 0000000000..820a372647 --- /dev/null +++ b/bench/nsieve-bit.lua @@ -0,0 +1,27 @@ + +local bit = require("bit") +local band, bxor, rshift, rol = bit.band, bit.bxor, bit.rshift, bit.rol + +local function nsieve(p, m) + local count = 0 + for i=0,rshift(m, 5) do p[i] = -1 end + for i=2,m do + if band(rshift(p[rshift(i, 5)], i), 1) ~= 0 then + count = count + 1 + for j=i+i,m,i do + local jx = rshift(j, 5) + p[jx] = band(p[jx], rol(-2, j)) + end + end + end + return count +end + +local N = tonumber(arg and arg[1]) or 1 +if N < 2 then N = 2 end +local primes = {} + +for i=0,2 do + local m = (2^(N-i))*10000 + io.write(string.format("Primes up to %8d %8d\n", m, nsieve(primes, m))) +end diff --git a/bench/nsieve.lua b/bench/nsieve.lua new file mode 100644 index 0000000000..6de0524f95 --- /dev/null +++ b/bench/nsieve.lua @@ -0,0 +1,21 @@ + +local function nsieve(p, m) + for i=2,m do p[i] = true end + local count = 0 + for i=2,m do + if p[i] then + for k=i+i,m,i do p[k] = false end + count = count + 1 + end + end + return count +end + +local N = tonumber(arg and arg[1]) or 1 +if N < 2 then N = 2 end +local primes = {} + +for i=0,2 do + local m = (2^(N-i))*10000 + io.write(string.format("Primes up to %8d %8d\n", m, nsieve(primes, m))) +end diff --git a/bench/partialsums.lua b/bench/partialsums.lua new file mode 100644 index 0000000000..46bb9da35f --- /dev/null +++ b/bench/partialsums.lua @@ -0,0 +1,29 @@ + +local n = tonumber(arg[1]) +local function pr(fmt, x) io.write(string.format(fmt, x)) end + +local a1, a2, a3, a4, a5, a6, a7, a8, a9, alt = 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 +local sqrt, sin, cos = math.sqrt, math.sin, math.cos +for k=1,n do + local k2, sk, ck = k*k, sin(k), cos(k) + local k3 = k2*k + a1 = a1 + (2/3)^k + a2 = a2 + 1/sqrt(k) + a3 = a3 + 1/(k2+k) + a4 = a4 + 1/(k3*sk*sk) + a5 = a5 + 1/(k3*ck*ck) + a6 = a6 + 1/k + a7 = a7 + 1/k2 + a8 = a8 + alt/k + a9 = a9 + alt/(k+k-1) + alt = -alt +end +pr("%.9f\t(2/3)^k\n", a1) +pr("%.9f\tk^-0.5\n", a2) +pr("%.9f\t1/k(k+1)\n", a3) +pr("%.9f\tFlint Hills\n", a4) +pr("%.9f\tCookson Hills\n", a5) +pr("%.9f\tHarmonic\n", a6) +pr("%.9f\tRiemann Zeta\n", a7) +pr("%.9f\tAlternating Harmonic\n", a8) +pr("%.9f\tGregory\n", a9) diff --git a/bench/pidigits-nogmp.lua b/bench/pidigits-nogmp.lua new file mode 100644 index 0000000000..63a1cb0ee8 --- /dev/null +++ b/bench/pidigits-nogmp.lua @@ -0,0 +1,100 @@ + +-- Start of dynamically compiled chunk. +local chunk = [=[ + +-- Factory function for multi-precision number (mpn) operations. +local function fmm(fa, fb) + return loadstring([[ + return function(y, a, ka, b, kb) + local carry, n = 0, #a ]]..(fb == 0 and "" or [[ + local na, nb = n, #b -- Need to adjust lengths. 1 element suffices here. + if na > nb then b[na] = 0 elseif na < nb then a[nb] = 0; n = nb end + ]])..[[ + for i=1,n do -- Sum up all elements and propagate carry. + local x = a[i] ]]..(fa == 2 and "*ka" or "").. + (fb == 2 and "+b[i]*kb" or (fb == 1 and "+b[i]" or ""))..[[ + carry + if x < RADIX and x >= 0 then carry = 0; y[i] = x -- Check for overflow. + else local d = x % RADIX; carry = (x-d) / RADIX; y[i] = d end + end + y[n+1] = nil -- Truncate target. 1 element suffices here. + if carry == 0 then while n > 0 and y[n] == 0 do y[n] = nil end + elseif carry == -1 then y[n] = y[n] - RADIX else y[n+1] = carry end + ]]..(fb == 0 and "" or [[ -- Undo length adjustment. + if na > nb then b[na] = nil elseif na < nb and y ~= a then a[nb] = nil end + ]])..[[ + return y + end]])() +end + +-- Generate needed mpn functions. +local mm_kk, mm_k1, mm_k0, mm_11 = fmm(2, 2), fmm(2, 1), fmm(2, 0), fmm(1, 1) + +-- Choose the most efficient mpn function for y = a*ka + b*kb at run-time. +local function mm(y, a, ka, b, kb) + local f = mm_kk + if kb == 0 or #b == 0 then if ka == 1 then return a else f = mm_k0 end + elseif kb == 1 then if ka == 1 then f = mm_11 else f = mm_k1 end end + return f(y, a, ka, b, kb) +end + +-- Compose matrix with numbers on the right. +local function compose_r(aq,ar,as,at, bq,br,bs,bt) + mm(ar, ar,bq, at,br) mm(at, at,bt, ar,bs) + mm(as, as,bt, aq,bs) mm(aq, aq,bq, nil,0) +end + +-- Compose matrix with numbers on the left. +local function compose_l(aq,ar,as,at, bq,br,bs,bt) + mm(ar, ar,bt, aq,br) mm(at, at,bt, as,br) + mm(as, as,bq, at,bs) mm(aq, aq,bq, nil,0) +end + +-- Extract one digit. +local u, v, jj = {}, {}, 0 +local function extract(q,r,s,t, j) + local u = j == jj + 1 and mm(u, u,1, q,1) or mm(u, q,j, r,1); jj = j + local v = mm(v, t,1, s,j) + local nu, nv, y = #u, #v + if nu == nv then + if nu == 1 then y = u[1] / v[1] + else y = (u[nu]*RADIX + u[nu-1]) / (v[nv]*RADIX + v[nv-1]) end + elseif nu == nv+1 then y = (u[nu]*RADIX + u[nv]) / v[nv] + else return 0 end + return math.floor(y) +end + +-- Coroutine which yields successive digits of PI. +return coroutine.wrap(function() + local q, r, s, t, k = {1}, {}, {}, {1}, 1 + repeat + local y = extract(q,r,s,t, 3) + if y == extract(q,r,s,t, 4) then + coroutine.yield(y) + compose_r(q,r,s,t, 10, -10*y, 0, 1) + else + compose_l(q,r,s,t, k, 4*k+2, 0, 2*k+1) + k = k + 1 + end + until false +end) + +]=] -- End of dynamically compiled chunk. + +local N = tonumber(arg and arg[1]) or 27 +local RADIX = N < 6500 and 2^36 or 2^32 -- Avoid overflow. + +-- Substitute radix and compile chunk. +local pidigit = loadstring(string.gsub(chunk, "RADIX", tostring(RADIX)))() + +-- Print lines with 10 digits. +for i=10,N,10 do + for j=1,10 do io.write(pidigit()) end + io.write("\t:", i, "\n") +end + +-- Print remaining digits (if any). +local n10 = N % 10 +if n10 ~= 0 then + for i=1,n10 do io.write(pidigit()) end + io.write(string.rep(" ", 10-n10), "\t:", N, "\n") +end diff --git a/bench/ray.lua b/bench/ray.lua new file mode 100644 index 0000000000..2acc24c0bf --- /dev/null +++ b/bench/ray.lua @@ -0,0 +1,135 @@ +local sqrt = math.sqrt +local huge = math.huge + +local delta = 1 +while delta * delta + 1 ~= 1 do + delta = delta * 0.5 +end + +local function length(x, y, z) return sqrt(x*x + y*y + z*z) end +local function vlen(v) return length(v[1], v[2], v[3]) end +local function mul(c, x, y, z) return c*x, c*y, c*z end +local function unitise(x, y, z) return mul(1/length(x, y, z), x, y, z) end +local function dot(x1, y1, z1, x2, y2, z2) + return x1*x2 + y1*y2 + z1*z2 +end + +local function vsub(a, b) return a[1] - b[1], a[2] - b[2], a[3] - b[3] end +local function vdot(a, b) return dot(a[1], a[2], a[3], b[1], b[2], b[3]) end + + +local sphere = {} +function sphere:new(centre, radius) + self.__index = self + return setmetatable({centre=centre, radius=radius}, self) +end + +local function sphere_distance(self, origin, dir) + local vx, vy, vz = vsub(self.centre, origin) + local b = dot(vx, vy, vz, dir[1], dir[2], dir[3]) + local r = self.radius + local disc = r*r + b*b - vx*vx-vy*vy-vz*vz + if disc < 0 then return huge end + local d = sqrt(disc) + local t2 = b + d + if t2 < 0 then return huge end + local t1 = b - d + return t1 > 0 and t1 or t2 +end + +function sphere:intersect(origin, dir, best) + local lambda = sphere_distance(self, origin, dir) + if lambda < best[1] then + local c = self.centre + best[1] = lambda + local b2 = best[2] + b2[1], b2[2], b2[3] = + unitise( + origin[1] - c[1] + lambda * dir[1], + origin[2] - c[2] + lambda * dir[2], + origin[3] - c[3] + lambda * dir[3]) + end +end + +local group = {} +function group:new(bound) + self.__index = self + return setmetatable({bound=bound, children={}}, self) +end + +function group:add(s) + self.children[#self.children+1] = s +end + +function group:intersect(origin, dir, best) + local lambda = sphere_distance(self.bound, origin, dir) + if lambda < best[1] then + for _, c in ipairs(self.children) do + c:intersect(origin, dir, best) + end + end +end + +local hit = { 0, 0, 0 } +local ilight +local best = { huge, { 0, 0, 0 } } + +local function ray_trace(light, camera, dir, scene) + best[1] = huge + scene:intersect(camera, dir, best) + local b1 = best[1] + if b1 == huge then return 0 end + local b2 = best[2] + local g = vdot(b2, light) + if g >= 0 then return 0 end + hit[1] = camera[1] + b1*dir[1] + delta*b2[1] + hit[2] = camera[2] + b1*dir[2] + delta*b2[2] + hit[3] = camera[3] + b1*dir[3] + delta*b2[3] + best[1] = huge + scene:intersect(hit, ilight, best) + if best[1] == huge then + return -g + else + return 0 + end +end + +local function create(level, centre, radius) + local s = sphere:new(centre, radius) + if level == 1 then return s end + local gr = group:new(sphere:new(centre, 3*radius)) + gr:add(s) + local rn = 3*radius/sqrt(12) + for dz = -1,1,2 do + for dx = -1,1,2 do + gr:add(create(level-1, { centre[1] + rn*dx, centre[2] + rn, centre[3] + rn*dz }, radius*0.5)) + end + end + return gr +end + + +local level, n, ss = tonumber(arg[1]) or 9, tonumber(arg[2]) or 256, 4 +local iss = 1/ss +local gf = 255/(ss*ss) + +io.write(("P5\n%d %d\n255\n"):format(n, n)) +local light = { unitise(-1, -3, 2) } +ilight = { -light[1], -light[2], -light[3] } +local camera = { 0, 0, -4 } +local dir = { 0, 0, 0 } + +local scene = create(level, {0, -1, 0}, 1) + +for y = n/2-1, -n/2, -1 do + for x = -n/2, n/2-1 do + local g = 0 + for d = y, y+.99, iss do + for e = x, x+.99, iss do + dir[1], dir[2], dir[3] = unitise(e, d, n) + g = g + ray_trace(light, camera, dir, scene) + end + end + io.write(string.char(math.floor(0.5 + g*gf))) + end +end diff --git a/bench/recursive-ack.lua b/bench/recursive-ack.lua new file mode 100644 index 0000000000..fad30589bc --- /dev/null +++ b/bench/recursive-ack.lua @@ -0,0 +1,8 @@ +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 + +local N = tonumber(arg and arg[1]) or 10 +io.write("Ack(3,", N ,"): ", Ack(3,N), "\n") diff --git a/bench/recursive-fib.lua b/bench/recursive-fib.lua new file mode 100644 index 0000000000..ef9950decb --- /dev/null +++ b/bench/recursive-fib.lua @@ -0,0 +1,7 @@ +local function fib(n) + if n < 2 then return 1 end + return fib(n-2) + fib(n-1) +end + +local n = tonumber(arg[1]) or 10 +io.write(string.format("Fib(%d): %d\n", n, fib(n))) diff --git a/bench/revcomp.lua b/bench/revcomp.lua new file mode 100644 index 0000000000..34fe347bf9 --- /dev/null +++ b/bench/revcomp.lua @@ -0,0 +1,37 @@ + +local sub = string.sub +iubc = setmetatable({ + A="T", C="G", B="V", D="H", K="M", R="Y", + a="T", c="G", b="V", d="H", k="M", r="Y", + T="A", G="C", V="B", H="D", M="K", Y="R", U="A", + t="A", g="C", v="B", h="D", m="K", y="R", u="A", + N="N", S="S", W="W", n="N", s="S", w="W", +}, { __index = function(t, s) + local r = t[sub(s, 2)]..t[sub(s, 1, 1)]; t[s] = r; return r end }) + +local wcode = [=[ +return function(t, n) + if n == 1 then return end + local iubc, sub, write = iubc, string.sub, io.write + local s = table.concat(t, "", 1, n-1) + for i=#s-59,1,-60 do + write(]=] +for i=59,3,-4 do wcode = wcode.."iubc[sub(s, i+"..(i-3)..", i+"..i..")], " end +wcode = wcode..[=["\n") + end + local r = #s % 60 + if r ~= 0 then + for i=r,1,-4 do write(iubc[sub(s, i-3 < 1 and 1 or i-3, i)]) end + write("\n") + end +end +]=] +local writerev = loadstring(wcode)() + +local t, n = {}, 1 +for line in io.lines() do + local c = sub(line, 1, 1) + if c == ">" then writerev(t, n); io.write(line, "\n"); n = 1 + elseif c ~= ";" then t[n] = line; n = n + 1 end +end +writerev(t, n) diff --git a/bench/scimark-2010-12-20.lua b/bench/scimark-2010-12-20.lua new file mode 100644 index 0000000000..353acb7cbc --- /dev/null +++ b/bench/scimark-2010-12-20.lua @@ -0,0 +1,400 @@ +------------------------------------------------------------------------------ +-- Lua SciMark (2010-12-20). +-- +-- A literal translation of SciMark 2.0a, written in Java and C. +-- Credits go to the original authors Roldan Pozo and Bruce Miller. +-- See: http://math.nist.gov/scimark2/ +------------------------------------------------------------------------------ + +local SCIMARK_VERSION = "2010-12-10" +local SCIMARK_COPYRIGHT = "Copyright (C) 2006-2010 Mike Pall" + +local MIN_TIME = 2.0 +local RANDOM_SEED = 101009 -- Must be odd. +local SIZE_SELECT = "small" + +local benchmarks = { + "FFT", "SOR", "MC", "SPARSE", "LU", + small = { + FFT = { 1024 }, + SOR = { 100 }, + MC = { }, + SPARSE = { 1000, 5000 }, + LU = { 100 }, + }, + large = { + FFT = { 1048576 }, + SOR = { 1000 }, + MC = { }, + SPARSE = { 100000, 1000000 }, + LU = { 1000 }, + }, +} + +local abs, log, sin, floor = math.abs, math.log, math.sin, math.floor +local pi, clock = math.pi, os.clock +local format = string.format + +------------------------------------------------------------------------------ +-- Select array type: Lua tables or native (FFI) arrays +------------------------------------------------------------------------------ + +local darray, iarray + +local function array_init() + if jit and jit.status and jit.status() then + local ok, ffi = pcall(require, "ffi") + if ok then + darray = ffi.typeof("double[?]") + iarray = ffi.typeof("int[?]") + return + end + end + function darray(n) return {} end + iarray = darray +end + +------------------------------------------------------------------------------ +-- This is a Lagged Fibonacci Pseudo-random Number Generator with +-- j, k, M = 5, 17, 31. Pretty weak, but same as C/Java SciMark. +------------------------------------------------------------------------------ + +local rand, rand_init + +if jit and jit.status and jit.status() then + -- LJ2 has bit operations and zero-based arrays (internally). + local bit = require("bit") + local band, sar = bit.band, bit.arshift + function rand_init(seed) + local Rm, Rj, Ri = iarray(17), 16, 11 + for i=0,16 do Rm[i] = 0 end + for i=16,0,-1 do + seed = band(seed*9069, 0x7fffffff) + Rm[i] = seed + end + function rand() + local i = band(Ri+1, sar(Ri-16, 31)) + local j = band(Rj+1, sar(Rj-16, 31)) + Ri, Rj = i, j + local k = band(Rm[i] - Rm[j], 0x7fffffff) + Rm[j] = k + return k * (1.0/2147483647.0) + end + end +else + -- Better for standard Lua with one-based arrays and without bit operations. + function rand_init(seed) + local Rm, Rj = {}, 1 + for i=1,17 do Rm[i] = 0 end + for i=17,1,-1 do + seed = (seed*9069) % (2^31) + Rm[i] = seed + end + function rand() + local j, m = Rj, Rm + local h = j - 5 + if h < 1 then h = h + 17 end + local k = m[h] - m[j] + if k < 0 then k = k + 2147483647 end + m[j] = k + if j < 17 then Rj = j + 1 else Rj = 1 end + return k * (1.0/2147483647.0) + end + end +end + +local function random_vector(n) + local v = darray(n+1) + for x=1,n do v[x] = rand() end + return v +end + +local function random_matrix(m, n) + local a = {} + for y=1,m do + local v = darray(n+1) + a[y] = v + for x=1,n do v[x] = rand() end + end + return a +end + +------------------------------------------------------------------------------ +-- FFT: Fast Fourier Transform. +------------------------------------------------------------------------------ + +local function fft_bitreverse(v, n) + local j = 0 + for i=0,2*n-4,2 do + if i < j then + v[i+1], v[i+2], v[j+1], v[j+2] = v[j+1], v[j+2], v[i+1], v[i+2] + end + local k = n + while k <= j do j = j - k; k = k / 2 end + j = j + k + end +end + +local function fft_transform(v, n, dir) + if n <= 1 then return end + fft_bitreverse(v, n) + local dual = 1 + repeat + local dual2 = 2*dual + for i=1,2*n-1,2*dual2 do + local j = i+dual2 + local ir, ii = v[i], v[i+1] + local jr, ji = v[j], v[j+1] + v[j], v[j+1] = ir - jr, ii - ji + v[i], v[i+1] = ir + jr, ii + ji + end + local theta = dir * pi / dual + local s, s2 = sin(theta), 2.0 * sin(theta * 0.5)^2 + local wr, wi = 1.0, 0.0 + for a=3,dual2-1,2 do + wr, wi = wr - s*wi - s2*wr, wi + s*wr - s2*wi + for i=a,a+2*(n-dual2),2*dual2 do + local j = i+dual2 + local jr, ji = v[j], v[j+1] + local dr, di = wr*jr - wi*ji, wr*ji + wi*jr + local ir, ii = v[i], v[i+1] + v[j], v[j+1] = ir - dr, ii - di + v[i], v[i+1] = ir + dr, ii + di + end + end + dual = dual2 + until dual >= n +end + +function benchmarks.FFT(n) + local l2n = log(n)/log(2) + if l2n % 1 ~= 0 then + io.stderr:write("Error: FFT data length is not a power of 2\n") + os.exit(1) + end + local v = random_vector(n*2) + return function(cycles) + local norm = 1.0 / n + for p=1,cycles do + fft_transform(v, n, -1) + fft_transform(v, n, 1) + for i=1,n*2 do v[i] = v[i] * norm end + end + return ((5*n-2)*l2n + 2*(n+1)) * cycles + end +end + +------------------------------------------------------------------------------ +-- SOR: Jacobi Successive Over-Relaxation. +------------------------------------------------------------------------------ + +local function sor_run(mat, m, n, cycles, omega) + local om4, om1 = omega*0.25, 1.0-omega + m = m - 1 + n = n - 1 + for i=1,cycles do + for y=2,m do + local v, vp, vn = mat[y], mat[y-1], mat[y+1] + for x=2,n do + v[x] = om4*((vp[x]+vn[x])+(v[x-1]+v[x+1])) + om1*v[x] + end + end + end +end + +function benchmarks.SOR(n) + local mat = random_matrix(n, n) + return function(cycles) + sor_run(mat, n, n, cycles, 1.25) + return (n-1)*(n-1)*cycles*6 + end +end + +------------------------------------------------------------------------------ +-- MC: Monte Carlo Integration. +------------------------------------------------------------------------------ + +local function mc_integrate(cycles) + local under_curve = 0 + local rand = rand + for i=1,cycles do + local x = rand() + local y = rand() + if x*x + y*y <= 1.0 then under_curve = under_curve + 1 end + end + return (under_curve/cycles) * 4 +end + +function benchmarks.MC() + return function(cycles) + local res = mc_integrate(cycles) + assert(math.sqrt(cycles)*math.abs(res-math.pi) < 5.0, "bad MC result") + return cycles * 4 -- Way off, but same as SciMark in C/Java. + end +end + +------------------------------------------------------------------------------ +-- Sparse Matrix Multiplication. +------------------------------------------------------------------------------ + +local function sparse_mult(n, cycles, vy, val, row, col, vx) + for p=1,cycles do + for r=1,n do + local sum = 0 + for i=row[r],row[r+1]-1 do sum = sum + vx[col[i]] * val[i] end + vy[r] = sum + end + end +end + +function benchmarks.SPARSE(n, nz) + local nr = floor(nz/n) + local anz = nr*n + local vx = random_vector(n) + local val = random_vector(anz) + local vy, col, row = darray(n+1), iarray(nz+1), iarray(n+2) + row[1] = 1 + for r=1,n do + local step = floor(r/nr) + if step < 1 then step = 1 end + local rr = row[r] + row[r+1] = rr+nr + for i=0,nr-1 do col[rr+i] = 1+i*step end + end + return function(cycles) + sparse_mult(n, cycles, vy, val, row, col, vx) + return anz*cycles*2 + end +end + +------------------------------------------------------------------------------ +-- LU: Dense Matrix Factorization. +------------------------------------------------------------------------------ + +local function lu_factor(a, pivot, m, n) + local min_m_n = m < n and m or n + for j=1,min_m_n do + local jp, t = j, abs(a[j][j]) + for i=j+1,m do + local ab = abs(a[i][j]) + if ab > t then + jp = i + t = ab + end + end + pivot[j] = jp + if a[jp][j] == 0 then error("zero pivot") end + if jp ~= j then a[j], a[jp] = a[jp], a[j] end + if j < m then + local recp = 1.0 / a[j][j] + for k=j+1,m do + local v = a[k] + v[j] = v[j] * recp + end + end + if j < min_m_n then + for i=j+1,m do + local vi, vj = a[i], a[j] + local eij = vi[j] + for k=j+1,n do vi[k] = vi[k] - eij * vj[k] end + end + end + end +end + +local function matrix_alloc(m, n) + local a = {} + for y=1,m do a[y] = darray(n+1) end + return a +end + +local function matrix_copy(dst, src, m, n) + for y=1,m do + local vd, vs = dst[y], src[y] + for x=1,n do vd[x] = vs[x] end + end +end + +function benchmarks.LU(n) + local mat = random_matrix(n, n) + local tmp = matrix_alloc(n, n) + local pivot = iarray(n+1) + return function(cycles) + for i=1,cycles do + matrix_copy(tmp, mat, n, n) + lu_factor(tmp, pivot, n, n) + end + return 2.0/3.0*n*n*n*cycles + end +end + +------------------------------------------------------------------------------ +-- Main program. +------------------------------------------------------------------------------ + +local function printf(...) + io.write(format(...)) +end + +local function fmtparams(p1, p2) + if p2 then return format("[%d, %d]", p1, p2) + elseif p1 then return format("[%d]", p1) end + return "" +end + +local function measure(min_time, name, ...) + array_init() + rand_init(RANDOM_SEED) + local run = benchmarks[name](...) + local cycles = 1 + repeat + local tm = clock() + local flops = run(cycles, ...) + tm = clock() - tm + if tm >= min_time then + local res = flops / tm * 1.0e-6 + local p1, p2 = ... + printf("%-7s %8.2f %s\n", name, res, fmtparams(...)) + return res + end + cycles = cycles * 2 + until false +end + +printf("Lua SciMark %s based on SciMark 2.0a. %s.\n\n", + SCIMARK_VERSION, SCIMARK_COPYRIGHT) + +while arg and arg[1] do + local a = table.remove(arg, 1) + if a == "-noffi" then + package.preload.ffi = nil + elseif a == "-small" then + SIZE_SELECT = "small" + elseif a == "-large" then + SIZE_SELECT = "large" + elseif benchmarks[a] then + local p = benchmarks[SIZE_SELECT][a] + measure(MIN_TIME, a, tonumber(arg[1]) or p[1], tonumber(arg[2]) or p[2]) + return + else + printf("Usage: scimark [-noffi] [-small|-large] [BENCH params...]\n\n") + printf("BENCH -small -large\n") + printf("---------------------------------------\n") + for _,name in ipairs(benchmarks) do + printf("%-7s %-13s %s\n", name, + fmtparams(unpack(benchmarks.small[name])), + fmtparams(unpack(benchmarks.large[name]))) + end + printf("\n") + os.exit(1) + end +end + +local params = benchmarks[SIZE_SELECT] +local sum = 0 +for _,name in ipairs(benchmarks) do + sum = sum + measure(MIN_TIME, name, unpack(params[name])) +end +printf("\nSciMark %8.2f [%s problem sizes]\n", sum / #benchmarks, SIZE_SELECT) +io.flush() + diff --git a/bench/scimark-fft.lua b/bench/scimark-fft.lua new file mode 100644 index 0000000000..c05bb69a6b --- /dev/null +++ b/bench/scimark-fft.lua @@ -0,0 +1 @@ +require("scimark_lib").FFT(1024)(tonumber(arg and arg[1]) or 50000) diff --git a/bench/scimark-lu.lua b/bench/scimark-lu.lua new file mode 100644 index 0000000000..7636d994c6 --- /dev/null +++ b/bench/scimark-lu.lua @@ -0,0 +1 @@ +require("scimark_lib").LU(100)(tonumber(arg and arg[1]) or 5000) diff --git a/bench/scimark-sor.lua b/bench/scimark-sor.lua new file mode 100644 index 0000000000..e537e9867f --- /dev/null +++ b/bench/scimark-sor.lua @@ -0,0 +1 @@ +require("scimark_lib").SOR(100)(tonumber(arg and arg[1]) or 50000) diff --git a/bench/scimark-sparse.lua b/bench/scimark-sparse.lua new file mode 100644 index 0000000000..01a2258df9 --- /dev/null +++ b/bench/scimark-sparse.lua @@ -0,0 +1 @@ +require("scimark_lib").SPARSE(1000, 5000)(tonumber(arg and arg[1]) or 150000) diff --git a/bench/scimark_lib.lua b/bench/scimark_lib.lua new file mode 100644 index 0000000000..aeffd75a62 --- /dev/null +++ b/bench/scimark_lib.lua @@ -0,0 +1,297 @@ +------------------------------------------------------------------------------ +-- Lua SciMark (2010-03-15). +-- +-- A literal translation of SciMark 2.0a, written in Java and C. +-- Credits go to the original authors Roldan Pozo and Bruce Miller. +-- See: http://math.nist.gov/scimark2/ +------------------------------------------------------------------------------ + + +local SCIMARK_VERSION = "2010-03-15" + +local RANDOM_SEED = 101009 -- Must be odd. + +local abs, log, sin, floor = math.abs, math.log, math.sin, math.floor +local pi, clock = math.pi, os.clock + +local benchmarks = {} + +------------------------------------------------------------------------------ +-- This is a Lagged Fibonacci Pseudo-random Number Generator with +-- j, k, M = 5, 17, 31. Pretty weak, but same as C/Java SciMark. +------------------------------------------------------------------------------ + +local rand, rand_init + +if jit and jit.status and jit.status() then + -- LJ2 has bit operations and zero-based arrays (internally). + local bit = require("bit") + local band, sar = bit.band, bit.arshift + local Rm, Rj, Ri = {}, 0, 0 + for i=0,16 do Rm[i] = 0 end + function rand_init(seed) + Rj, Ri = 16, 11 + for i=16,0,-1 do + seed = band(seed*9069, 0x7fffffff) + Rm[i] = seed + end + end + function rand() + local i = band(Ri+1, sar(Ri-16, 31)) + local j = band(Rj+1, sar(Rj-16, 31)) + Ri, Rj = i, j + local k = band(Rm[i] - Rm[j], 0x7fffffff) + Rm[j] = k + return k * (1.0/2147483647.0) + end +else + -- Better for standard Lua with one-based arrays and without bit operations. + local Rm, Rj = {}, 1 + for i=1,17 do Rm[i] = 0 end + function rand_init(seed) + Rj = 1 + for i=17,1,-1 do + seed = (seed*9069) % (2^31) + Rm[i] = seed + end + end + function rand() + local j, m = Rj, Rm + local h = j - 5 + if h < 1 then h = h + 17 end + local k = m[h] - m[j] + if k < 0 then k = k + 2147483647 end + m[j] = k + if j < 17 then Rj = j + 1 else Rj = 1 end + return k * (1.0/2147483647.0) + end +end + +local function random_vector(n) + local v = {} + for x=1,n do v[x] = rand() end + return v +end + +local function random_matrix(m, n) + local a = {} + for y=1,m do + local v = {} + a[y] = v + for x=1,n do v[x] = rand() end + end + return a +end + +------------------------------------------------------------------------------ +-- FFT: Fast Fourier Transform. +------------------------------------------------------------------------------ + +local function fft_bitreverse(v, n) + local j = 0 + for i=0,2*n-4,2 do + if i < j then + v[i+1], v[i+2], v[j+1], v[j+2] = v[j+1], v[j+2], v[i+1], v[i+2] + end + local k = n + while k <= j do j = j - k; k = k / 2 end + j = j + k + end +end + +local function fft_transform(v, n, dir) + if n <= 1 then return end + fft_bitreverse(v, n) + local dual = 1 + repeat + local dual2 = 2*dual + for i=1,2*n-1,2*dual2 do + local j = i+dual2 + local ir, ii = v[i], v[i+1] + local jr, ji = v[j], v[j+1] + v[j], v[j+1] = ir - jr, ii - ji + v[i], v[i+1] = ir + jr, ii + ji + end + local theta = dir * pi / dual + local s, s2 = sin(theta), 2.0 * sin(theta * 0.5)^2 + local wr, wi = 1.0, 0.0 + for a=3,dual2-1,2 do + wr, wi = wr - s*wi - s2*wr, wi + s*wr - s2*wi + for i=a,a+2*(n-dual2),2*dual2 do + local j = i+dual2 + local jr, ji = v[j], v[j+1] + local dr, di = wr*jr - wi*ji, wr*ji + wi*jr + local ir, ii = v[i], v[i+1] + v[j], v[j+1] = ir - dr, ii - di + v[i], v[i+1] = ir + dr, ii + di + end + end + dual = dual2 + until dual >= n +end + +function benchmarks.FFT(n) + local l2n = log(n)/log(2) + if l2n % 1 ~= 0 then + io.stderr:write("Error: FFT data length is not a power of 2\n") + os.exit(1) + end + local v = random_vector(n*2) + return function(cycles) + local norm = 1.0 / n + for p=1,cycles do + fft_transform(v, n, -1) + fft_transform(v, n, 1) + for i=1,n*2 do v[i] = v[i] * norm end + end + return ((5*n-2)*l2n + 2*(n+1)) * cycles + end +end + +------------------------------------------------------------------------------ +-- SOR: Jacobi Successive Over-Relaxation. +------------------------------------------------------------------------------ + +local function sor_run(mat, m, n, cycles, omega) + local om4, om1 = omega*0.25, 1.0-omega + m = m - 1 + n = n - 1 + for i=1,cycles do + for y=2,m do + local v, vp, vn = mat[y], mat[y-1], mat[y+1] + for x=2,n do + v[x] = om4*((vp[x]+vn[x])+(v[x-1]+v[x+1])) + om1*v[x] + end + end + end +end + +function benchmarks.SOR(n) + local mat = random_matrix(n, n) + return function(cycles) + sor_run(mat, n, n, cycles, 1.25) + return (n-1)*(n-1)*cycles*6 + end +end + +------------------------------------------------------------------------------ +-- MC: Monte Carlo Integration. +------------------------------------------------------------------------------ + +local function mc_integrate(cycles) + local under_curve = 0 + local rand = rand + for i=1,cycles do + local x = rand() + local y = rand() + if x*x + y*y <= 1.0 then under_curve = under_curve + 1 end + end + return (under_curve/cycles) * 4 +end + +function benchmarks.MC() + return function(cycles) + local res = mc_integrate(cycles) + assert(math.sqrt(cycles)*math.abs(res-math.pi) < 5.0, "bad MC result") + return cycles * 4 -- Way off, but same as SciMark in C/Java. + end +end + +------------------------------------------------------------------------------ +-- Sparse Matrix Multiplication. +------------------------------------------------------------------------------ + +local function sparse_mult(n, cycles, vy, val, row, col, vx) + for p=1,cycles do + for r=1,n do + local sum = 0 + for i=row[r],row[r+1]-1 do sum = sum + vx[col[i]] * val[i] end + vy[r] = sum + end + end +end + +function benchmarks.SPARSE(n, nz) + local nr = floor(nz/n) + local anz = nr*n + local vx = random_vector(n) + local val = random_vector(anz) + local vy, col, row = {}, {}, {} + row[1] = 1 + for r=1,n do + local step = floor(r/nr) + if step < 1 then step = 1 end + local rr = row[r] + row[r+1] = rr+nr + for i=0,nr-1 do col[rr+i] = 1+i*step end + end + return function(cycles) + sparse_mult(n, cycles, vy, val, row, col, vx) + return anz*cycles*2 + end +end + +------------------------------------------------------------------------------ +-- LU: Dense Matrix Factorization. +------------------------------------------------------------------------------ + +local function lu_factor(a, pivot, m, n) + local min_m_n = m < n and m or n + for j=1,min_m_n do + local jp, t = j, abs(a[j][j]) + for i=j+1,m do + local ab = abs(a[i][j]) + if ab > t then + jp = i + t = ab + end + end + pivot[j] = jp + if a[jp][j] == 0 then error("zero pivot") end + if jp ~= j then a[j], a[jp] = a[jp], a[j] end + if j < m then + local recp = 1.0 / a[j][j] + for k=j+1,m do + local v = a[k] + v[j] = v[j] * recp + end + end + if j < min_m_n then + for i=j+1,m do + local vi, vj = a[i], a[j] + local eij = vi[j] + for k=j+1,n do vi[k] = vi[k] - eij * vj[k] end + end + end + end +end + +local function matrix_alloc(m, n) + local a = {} + for y=1,m do a[y] = {} end + return a +end + +local function matrix_copy(dst, src, m, n) + for y=1,m do + local vd, vs = dst[y], src[y] + for x=1,n do vd[x] = vs[x] end + end +end + +function benchmarks.LU(n) + local mat = random_matrix(n, n) + local tmp = matrix_alloc(n, n) + local pivot = {} + return function(cycles) + for i=1,cycles do + matrix_copy(tmp, mat, n, n) + lu_factor(tmp, pivot, n, n) + end + return 2.0/3.0*n*n*n*cycles + end +end + +rand_init(RANDOM_SEED) + +return benchmarks diff --git a/bench/series.lua b/bench/series.lua new file mode 100644 index 0000000000..f766cb3247 --- /dev/null +++ b/bench/series.lua @@ -0,0 +1,34 @@ + +local function integrate(x0, x1, nsteps, omegan, f) + local x, dx = x0, (x1-x0)/nsteps + local rvalue = ((x0+1)^x0 * f(omegan*x0)) / 2 + for i=3,nsteps do + x = x + dx + rvalue = rvalue + (x+1)^x * f(omegan*x) + end + return (rvalue + ((x1+1)^x1 * f(omegan*x1)) / 2) * dx +end + +local function series(n) + local sin, cos = math.sin, math.cos + local omega = math.pi + local t = {} + + t[1] = integrate(0, 2, 1000, 0, function() return 1 end) / 2 + t[2] = 0 + + for i=2,n do + t[2*i-1] = integrate(0, 2, 1000, omega*i, cos) + t[2*i] = integrate(0, 2, 1000, omega*i, sin) + end + + return t +end + +local n = tonumber(arg and arg[1]) or 10000 +local tm = os.clock() +local t = series(n) +tm = os.clock() - tm +assert(math.abs(t[1]-2.87295) < 0.00001) +io.write(string.format("size %d, %.2f s, %.1f iterations/s\n", + n, tm, (2*n-1)/tm)) diff --git a/bench/spectral-norm.lua b/bench/spectral-norm.lua new file mode 100644 index 0000000000..ecc8011208 --- /dev/null +++ b/bench/spectral-norm.lua @@ -0,0 +1,40 @@ + +local function A(i, j) + local ij = i+j-1 + return 1.0 / (ij * (ij-1) * 0.5 + i) +end + +local function Av(x, y, N) + for i=1,N do + local a = 0 + for j=1,N do a = a + x[j] * A(i, j) end + y[i] = a + end +end + +local function Atv(x, y, N) + for i=1,N do + local a = 0 + for j=1,N do a = a + x[j] * A(j, i) end + y[i] = a + end +end + +local function AtAv(x, y, t, N) + Av(x, t, N) + Atv(t, y, N) +end + +local N = tonumber(arg and arg[1]) or 100 +local u, v, t = {}, {}, {} +for i=1,N do u[i] = 1 end + +for i=1,10 do AtAv(u, v, t, N) AtAv(v, u, t, N) end + +local vBv, vv = 0, 0 +for i=1,N do + local ui, vi = u[i], v[i] + vBv = vBv + ui*vi + vv = vv + vi*vi +end +io.write(string.format("%0.9f\n", math.sqrt(vBv / vv))) diff --git a/bench/sum-file.lua b/bench/sum-file.lua new file mode 100644 index 0000000000..c9e618fdf5 --- /dev/null +++ b/bench/sum-file.lua @@ -0,0 +1,6 @@ + +local sum = 0 +for line in io.lines() do + sum = sum + line +end +io.write(sum, "\n") diff --git a/test/clib/cpptest.cpp b/test/clib/cpptest.cpp new file mode 100644 index 0000000000..a5893ed600 --- /dev/null +++ b/test/clib/cpptest.cpp @@ -0,0 +1,129 @@ + +#include + +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/clib/ctest.c b/test/clib/ctest.c new file mode 100644 index 0000000000..d257567b98 --- /dev/null +++ b/test/clib/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 +#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 + +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/common/ffi_util.inc b/test/common/ffi_util.inc new file mode 100644 index 0000000000..1eee8dd933 --- /dev/null +++ b/test/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/ffi/ffi_arith_ptr.lua b/test/ffi/ffi_arith_ptr.lua new file mode 100644 index 0000000000..8cf890c608 --- /dev/null +++ b/test/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/ffi/ffi_bit64.lua b/test/ffi/ffi_bit64.lua new file mode 100644 index 0000000000..46cf60143c --- /dev/null +++ b/test/ffi/ffi_bit64.lua @@ -0,0 +1,120 @@ +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; +]] + +assert(tobit(0xfedcba9876543210ll) == 0x76543210) +assert(tobit(0xfedcba9876543210ull) == 0x76543210) + +assert(tostring(band(1ll, 1, 1ll, -1)) == "1LL") +assert(tostring(band(1ll, 1, 1ull, -1)) == "1ULL") + +assert(shl(10ll, 2) == 40) +assert(shl(10, 2ll) == 40) +assert(shl(10ll, 2ll) == 40) + +assert(bit.tohex(0x123456789abcdef0LL) == "123456789abcdef0") + +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 + +do + 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 + 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 + 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 + 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 + 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/ffi/ffi_bitfield.lua b/test/ffi/ffi_bitfield.lua new file mode 100644 index 0000000000..cd0b1815bd --- /dev/null +++ b/test/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/ffi/ffi_call.lua b/test/ffi/ffi_call.lua new file mode 100644 index 0000000000..1eb5e906b1 --- /dev/null +++ b/test/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/ffi/ffi_callback.lua b/test/ffi/ffi_callback.lua new file mode 100644 index 0000000000..1fd14bd0d2 --- /dev/null +++ b/test/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/ffi/ffi_const.lua b/test/ffi/ffi_const.lua new file mode 100644 index 0000000000..d42133ad94 --- /dev/null +++ b/test/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/ffi/ffi_convert.lua b/test/ffi/ffi_convert.lua new file mode 100644 index 0000000000..bd3fb1f903 --- /dev/null +++ b/test/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/ffi/ffi_copy_fill.lua b/test/ffi/ffi_copy_fill.lua new file mode 100644 index 0000000000..ef060bad05 --- /dev/null +++ b/test/ffi/ffi_copy_fill.lua @@ -0,0 +1,64 @@ +local ffi = require("ffi") + +do + 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 + 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 + 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/ffi/ffi_enum.lua b/test/ffi/ffi_enum.lua new file mode 100644 index 0000000000..e8e40ad084 --- /dev/null +++ b/test/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/ffi/ffi_err.lua b/test/ffi/ffi_err.lua new file mode 100644 index 0000000000..bd23658a2d --- /dev/null +++ b/test/ffi/ffi_err.lua @@ -0,0 +1,38 @@ +local ffi = require("ffi") + +-- error in FFI metamethod: don't print metamethod frame. +do + local ok, err = xpcall(function() + local x = (1ll).foo + end, debug.traceback) + assert(ok == false) + assert(not string.find(err, "__index")) +end + +-- tailcall in regular metamethod: keep metamethod frame. +do + 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 + +-- error in FFI metamethod: set correct PC. +do + ffi.cdef[[ +typedef struct { int x; int y; } point; +point strchr(point* op1, point* op2); +]] + local point = ffi.metatype("point", { __add = ffi.C.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/ffi/ffi_gcstep_recursive.lua b/test/ffi/ffi_gcstep_recursive.lua new file mode 100644 index 0000000000..cb19df1141 --- /dev/null +++ b/test/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/ffi/ffi_istype.lua b/test/ffi/ffi_istype.lua new file mode 100644 index 0000000000..fb538bdd4e --- /dev/null +++ b/test/ffi/ffi_istype.lua @@ -0,0 +1,89 @@ +local ffi = require("ffi") + +ffi.cdef[[ +typedef int arr_t[10]; +typedef const arr_t carr_t; +typedef struct { int x; } struct_t; +]] + +do + 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 + 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 + 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 + local arr_t = ffi.typeof("arr_t") + local carr_t = ffi.typeof("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("struct_t") + local structp_t = ffi.typeof("struct_t *") + assert(ffi.istype(struct_t, struct_t) == true) + assert(ffi.istype("const 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 + 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/ffi/ffi_jit_arith.lua b/test/ffi/ffi_jit_arith.lua new file mode 100644 index 0000000000..0554fe60aa --- /dev/null +++ b/test/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/ffi/ffi_jit_array.lua b/test/ffi/ffi_jit_array.lua new file mode 100644 index 0000000000..13e26dbe33 --- /dev/null +++ b/test/ffi/ffi_jit_array.lua @@ -0,0 +1,104 @@ +local ffi = require("ffi") + +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 + +do + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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/ffi/ffi_jit_call.lua b/test/ffi/ffi_jit_call.lua new file mode 100644 index 0000000000..b79d60b106 --- /dev/null +++ b/test/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/ffi/ffi_jit_complex.lua b/test/ffi/ffi_jit_complex.lua new file mode 100644 index 0000000000..4d3191cbe7 --- /dev/null +++ b/test/ffi/ffi_jit_complex.lua @@ -0,0 +1,111 @@ +local ffi = require("ffi") + +local cx = ffi.typeof("complex") +local cxf = ffi.typeof("complex float") + +ffi.cdef[[ +typedef struct cc_t { + struct cc_t *next; + complex c; +} cc_t; +]] + +do + local c = cx(1, 2) + local x + for i=1,100 do + x = c.re + c.im + end + assert(x == 3) +end + +do + local cp = ffi.new("cc_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 + local cp = ffi.new("cc_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 + 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 + 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 + 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 + 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 + +-- Index overflow for complex is ignored +do + local c = cx(1, 2) + local x + for i=1e7,1e7+100 do x = c[i] end +end + diff --git a/test/ffi/ffi_jit_conv.lua b/test/ffi/ffi_jit_conv.lua new file mode 100644 index 0000000000..d4707db7a8 --- /dev/null +++ b/test/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/ffi/ffi_jit_misc.lua b/test/ffi/ffi_jit_misc.lua new file mode 100644 index 0000000000..800509afcd --- /dev/null +++ b/test/ffi/ffi_jit_misc.lua @@ -0,0 +1,110 @@ +local ffi = require("ffi") + +do + ffi.errno(42) + local x = 0 + for i=1,100 do x = x + ffi.errno() end + assert(x == 4200) + ffi.errno(0) +end + +do + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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/ffi/ffi_jit_struct.lua b/test/ffi/ffi_jit_struct.lua new file mode 100644 index 0000000000..e42743c90c --- /dev/null +++ b/test/ffi/ffi_jit_struct.lua @@ -0,0 +1,201 @@ +local ffi = require("ffi") + +ffi.cdef[[ +typedef struct { int a, b, c; } foo_t; +typedef struct { int a, b, c; } foo2_t; +typedef struct { int a[10]; int b[10]; } sarr_t; +typedef struct chain_t { + struct chain_t *next; + int v; +} chain_t; +]] + +do + local s = ffi.new("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 + local s = ffi.new("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 + local s = ffi.new("foo_t") + local s2 = ffi.new("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 + local s = ffi.new("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 + 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 + 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 + 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 + 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 + local s1 = ffi.new("chain_t") + local s2 = ffi.new("chain_t") + local s3 = ffi.new("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 + 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 + 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 + local s1 = ffi.new("chain_t") + local s + for i=1,100 do + s = ffi.new("chain_t", s1, i) + end + assert(tonumber(ffi.cast("int", s.next)) == + tonumber(ffi.cast("int", ffi.cast("chain_t *", s1)))) + assert(s.v == 100) +end + +do + local ct = ffi.typeof("struct { int *p; int y; }") + local s + for i=1,200 do + if i == 100 then ct = ffi.typeof("chain_t") end + s = ct(nil, 10) + end + assert(s.v == 10) +end + +do + 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/ffi/ffi_lex_number.lua b/test/ffi/ffi_lex_number.lua new file mode 100644 index 0000000000..e26650effd --- /dev/null +++ b/test/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/ffi/ffi_meta_tostring.lua b/test/ffi/ffi_meta_tostring.lua new file mode 100644 index 0000000000..57a34fca9d --- /dev/null +++ b/test/ffi/ffi_meta_tostring.lua @@ -0,0 +1,54 @@ +local ffi = require("ffi") + +ffi.cdef[[ +typedef union foo_t { + int64_t i64; + uint64_t u64; + complex cd; + double d[2]; + complex float cf; + float f[2]; +} foo_t; +]] + +do + local foo_t = ffi.typeof("foo_t") + local x = foo_t() + local s + + assert(tostring(foo_t) == "ctype") + assert(string.match(tostring(x), "^cdata: ")) + + assert(tostring(ffi.typeof("int (*(*[1][2])[3][4])[5][6]")) == + "ctype") + assert(tostring(ffi.typeof("int (*const)(void)")) == + "ctype") + assert(tostring(ffi.typeof("complex float(*(void))[2]")) == + "ctype") + assert(tostring(ffi.typeof("complex*")) == "ctype") + + 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/ffi/ffi_metatype.lua b/test/ffi/ffi_metatype.lua new file mode 100644 index 0000000000..2db717f479 --- /dev/null +++ b/test/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/ffi/ffi_new.lua b/test/ffi/ffi_new.lua new file mode 100644 index 0000000000..9cdbd538cb --- /dev/null +++ b/test/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/ffi/ffi_nosink.lua b/test/ffi/ffi_nosink.lua new file mode 100644 index 0000000000..ae51dde1a1 --- /dev/null +++ b/test/ffi/ffi_nosink.lua @@ -0,0 +1,45 @@ +local ffi = require("ffi") + +do + local x = 0ll + for i=1,100 do x=x+1; g=x end + assert(x == 100ll) + assert(g == 100ll) +end + +do + 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 + local x = 0ll + local z + for i=1,100 do z=x+1; g=z end + assert(z == 1ll) + assert(g == 1ll) +end + +do + local x,y = 0ll, 0ll + for i=1,100 do y,x=x,x+1 end + assert(x == 100ll) + assert(y == 99ll) +end + +do + 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 + 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/ffi/ffi_parse_array.lua b/test/ffi/ffi_parse_array.lua new file mode 100644 index 0000000000..3a9616d730 --- /dev/null +++ b/test/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/ffi/ffi_parse_basic.lua b/test/ffi/ffi_parse_basic.lua new file mode 100644 index 0000000000..c054bcfb89 --- /dev/null +++ b/test/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/ffi/ffi_parse_cdef.lua b/test/ffi/ffi_parse_cdef.lua new file mode 100644 index 0000000000..4bb5d903eb --- /dev/null +++ b/test/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/ffi/ffi_parse_struct.lua b/test/ffi/ffi_parse_struct.lua new file mode 100644 index 0000000000..16a3d053e4 --- /dev/null +++ b/test/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/ffi/ffi_redir.lua b/test/ffi/ffi_redir.lua new file mode 100644 index 0000000000..72e6e307bc --- /dev/null +++ b/test/ffi/ffi_redir.lua @@ -0,0 +1,22 @@ +local ffi = require("ffi") + +ffi.cdef[[ +int foo(const char *s) asm("strlen"); +]] + +assert(ffi.C.foo("abcd") == 4) + +if ffi.abi("win") then + ffi.cdef[[ + int bar asm("_fmode"); + ]] +else + ffi.cdef[[ + int bar asm("errno"); + ]] +end + +ffi.C.bar = 14 +assert(ffi.C.bar == 14) +ffi.C.bar = 0 + diff --git a/test/ffi/ffi_sink.lua b/test/ffi/ffi_sink.lua new file mode 100644 index 0000000000..ea65912764 --- /dev/null +++ b/test/ffi/ffi_sink.lua @@ -0,0 +1,122 @@ +local ffi = require("ffi") + +do + local x = 10000000000000ll + for i=1,100 do x=x+1 end + assert(x == 10000000000100ll) +end + +do + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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/ffi/ffi_tabov.lua b/test/ffi/ffi_tabov.lua new file mode 100644 index 0000000000..ba621960bd --- /dev/null +++ b/test/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/ffi/ffi_type_punning.lua b/test/ffi/ffi_type_punning.lua new file mode 100644 index 0000000000..b889b52f25 --- /dev/null +++ b/test/ffi/ffi_type_punning.lua @@ -0,0 +1,147 @@ +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]; +} +]]) + +-- float -> u32 type punning at same offset +do + local x = 0LL + for i=1,100 do + u.f[0] = i + x = x + u.u32[0] + end + assert(x == 110888222720LL) +end + +-- double -> u64 type punning at same offset +do + local x = 0LL + for i=1,100 do + u.d[0] = i + x = x + u.u64[0] + end + assert(x == 1886586031403171840ULL) +end + +-- i8 -> u8 type punning at same offset (fwd -> CONV.int.u8) +do + local x = 0 + for i=-100,100 do + u.i8[0] = i + x = x + u.u8[0] + end + assert(x == 25600) +end + +-- p32/p64 -> u64 type punning at same offset (32 bit: different size) +do + 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 + +-- u16 -> u8 type punning at overlapping offsets +do + 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 + 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 + +-- i16 -> i32 type punning at overlapping offsets +do + 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 + 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 + +-- double -> i32 type punning at overlapping offsets +do + 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 + 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 + +-- u32 -> u64 type punning, constify u, 32 bit SPLIT: fold KPTR +do + 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 + +-- u64 -> u32 -> u64 type punning with KPTR +do + 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/misc/ack.lua b/test/misc/ack.lua new file mode 100644 index 0000000000..bcc1316e1e --- /dev/null +++ b/test/misc/ack.lua @@ -0,0 +1,12 @@ +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 + +if arg and arg[1] then + local N = tonumber(arg and arg[1]) + io.write("Ack(3,", N ,"): ", Ack(3,N), "\n") +else + assert(Ack(3,5) == 253) +end diff --git a/test/misc/ack_notail.lua b/test/misc/ack_notail.lua new file mode 100644 index 0000000000..e14c003afd --- /dev/null +++ b/test/misc/ack_notail.lua @@ -0,0 +1,12 @@ +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 + +if arg and arg[1] then + local N = tonumber(arg and arg[1]) + io.write("Ack(3,", N ,"): ", Ack(3,N), "\n") +else + assert(Ack(3,5) == 253) +end diff --git a/test/misc/alias_alloc.lua b/test/misc/alias_alloc.lua new file mode 100644 index 0000000000..02fe618d81 --- /dev/null +++ b/test/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/misc/api_call.lua b/test/misc/api_call.lua new file mode 100644 index 0000000000..7dbd5e4011 --- /dev/null +++ b/test/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/misc/argcheck.lua b/test/misc/argcheck.lua new file mode 100644 index 0000000000..de3cb70ad7 --- /dev/null +++ b/test/misc/argcheck.lua @@ -0,0 +1,40 @@ + +local function check(f, msg) + local ok, err = pcall(f) + if ok then error("error check unexpectedly succeeded", 2) end + 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 error("error check failed with "..err, 2) end +end + +assert(math.abs(-1.5) == 1.5) +assert(math.abs("-1.5") == 1.5) + +check(function() math.abs() end, + "bad argument #1 to 'abs' (number expected, got no value)") +check(function() math.abs(false) end, + "bad argument #1 to 'abs' (number expected, got boolean)") +check(function() math.abs("a") end, + "bad argument #1 to 'abs' (number expected, got string)") +string.abs = math.abs +check(function() ("a"):abs() end, + "calling 'abs' on bad self (number expected, got string)") + +assert(string.len("abc") == 3) +assert(string.len(123) == 3) + +check(function() string.len() end, + "bad argument #1 to 'len' (string expected, got nil)") +check(function() string.len(false) end, + "bad argument #1 to 'len' (string expected, got boolean)") + +assert(string.sub("abc", 2) == "bc") +assert(string.sub(123, "2") == "23") + +check(function() string.sub("abc", false) end, + "bad argument #2 to 'sub' (number expected, got boolean)") +check(function() ("abc"):sub(false) end, + "bad argument #1 to 'sub' (number expected, got boolean)") + diff --git a/test/misc/assign_tset_prevnil.lua b/test/misc/assign_tset_prevnil.lua new file mode 100644 index 0000000000..202153c612 --- /dev/null +++ b/test/misc/assign_tset_prevnil.lua @@ -0,0 +1,11 @@ +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) diff --git a/test/misc/assign_tset_tmp.lua b/test/misc/assign_tset_tmp.lua new file mode 100644 index 0000000000..909d5aadaa --- /dev/null +++ b/test/misc/assign_tset_tmp.lua @@ -0,0 +1,5 @@ +a = {} +i = 3 +i, a[i] = i+1, 20 +assert(i == 4) +assert(a[3] == 20) diff --git a/test/misc/bit_op.lua b/test/misc/bit_op.lua new file mode 100644 index 0000000000..4bab240c03 --- /dev/null +++ b/test/misc/bit_op.lua @@ -0,0 +1,90 @@ +-- Test cases for bit operations library. Public domain. + +local bit = require"bit" + +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 + string.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 _,y in ipairs(vb) do s = s..","..tostring(f(x, y)) 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 + +-- 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()") + +-- 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) + +-- Apply operations to test vectors and compare checksums. +check_unop("tobit", 277312) +check_unop("bnot", 287870) +check_unop("bswap", 307611) + +check_binop("band", 41206764) +check_binop("bor", 51253663) +check_binop("bxor", 79322427) + +check_shift("lshift", 325260344) +check_shift("rshift", 139061800) +check_shift("arshift", 111364720) +check_shift("rol", 302401155) +check_shift("ror", 302316761) + +check_binop_range("tohex", 47880306, -8, 8) + +-- 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 + diff --git a/test/misc/cat_jit.lua b/test/misc/cat_jit.lua new file mode 100644 index 0000000000..858a15bf45 --- /dev/null +++ b/test/misc/cat_jit.lua @@ -0,0 +1,113 @@ + +-- Constant folding +do + 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 + +-- Fuse conversions to strings +do + 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 + +-- Fuse string construction +do + local y + local x = "abc" + for i=1,100 do y = "x"..string.sub(x, 2) end + assert(y == "xbc") +end + +-- CSE, sink +do + local y + local x = "a" + for i=1,100 do y = x.."b" end + assert(y == "ab") +end + +-- CSE, two buffers in parallel, no sink +do + 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 + +-- Append, CSE +do + 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 + +-- Append, FOLD +do + local a, b = "x" + for i=1,100 do b = (a.."y").."" end + assert(b == "xy") +end + +-- Append to buffer, sink +do + 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 + +-- Append to two buffers in parallel, no append, no sink +do + 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 + +-- Sink into side-exit +do + 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 + diff --git a/test/misc/catch_wrap.lua b/test/misc/catch_wrap.lua new file mode 100644 index 0000000000..7f656bcc26 --- /dev/null +++ b/test/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/misc/compare.lua b/test/misc/compare.lua new file mode 100644 index 0000000000..96a52d90d2 --- /dev/null +++ b/test/misc/compare.lua @@ -0,0 +1,232 @@ +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 + +local x,y = 1,2 + +check(xy, false) +check(x>=y, false) +check(x==y, false) +check(x~=y, true) + +check(1y, 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) + +local x,y = 2,1 + +check(xy, true) +check(x>=y, true) +check(x==y, false) +check(x~=y, true) + +check(2y, 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) + +local x,y = 1,1 + +check(xy, false) +check(x>=y, true) +check(x==y, true) +check(x~=y, false) + +check(1y, 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) + + +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) + + +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) + + +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) + +do + assert(not pcall(function() + local a, b = 10.5, nil + return a < b + end)) +end + +do + 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 + diff --git a/test/misc/constov.lua b/test/misc/constov.lua new file mode 100644 index 0000000000..341cf32930 --- /dev/null +++ b/test/misc/constov.lua @@ -0,0 +1,19 @@ + +if not os.getenv("SLOWTEST") then return end + +do + 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 + 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/misc/coro_traceback.lua b/test/misc/coro_traceback.lua new file mode 100644 index 0000000000..2676d2c68e --- /dev/null +++ b/test/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/misc/coro_yield.lua b/test/misc/coro_yield.lua new file mode 100644 index 0000000000..ae3206e05b --- /dev/null +++ b/test/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/misc/debug_gc.lua b/test/misc/debug_gc.lua new file mode 100644 index 0000000000..30fb2b99b9 --- /dev/null +++ b/test/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/misc/debug_meta.lua b/test/misc/debug_meta.lua new file mode 100644 index 0000000000..5954bbfad5 --- /dev/null +++ b/test/misc/debug_meta.lua @@ -0,0 +1,79 @@ + +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, +} + +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; ck("__len") -- Not called for tables +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") + +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") + diff --git a/test/misc/dse_array.lua b/test/misc/dse_array.lua new file mode 100644 index 0000000000..af1725fe20 --- /dev/null +++ b/test/misc/dse_array.lua @@ -0,0 +1,200 @@ + +local assert = assert + +-- Same value ---------------------------------------------------------------- + +-- 1. Store with same ref and same value. +-- 2nd store eliminated. All stores in loop eliminated. +do + 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 + +-- 2. Store with different tab, same idx and same value. +-- All stores in loop eliminated. +do + 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 + +-- 3. Store with same tab, different const idx and same value. +-- All stores in loop eliminated. Also disambiguated. +do + 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 + +-- 4. Store with different tab, different const idx and same value. +-- All stores in loop eliminated. Also disambiguated. +do + 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 + +-- 5. Store with different tab, different non-const idx and same value. +-- All stores in loop eliminated. Not disambiguated (but not needed). +do + 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 + +-- 6. Store with same ref, same value and aliased loads. +-- 2nd store eliminated. Not disambiguated (but not needed). +do + 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 ----------------------------------------------------------- + +-- 7. Store with same ref and different value. +-- 1st store eliminated. All stores in loop eliminated. +do + 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 + +-- 8. Store with different tab, same idx and different value. +-- Cannot eliminate any stores (would need dynamic disambiguation). +do + 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 + +-- 9. Store with same tab, different const idx and different value. +-- Disambiguated. All stores in loop eliminated. +do + 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 + +-- 10. Store with different tab, different const idx and different value. +-- Disambiguated. All stores in loop eliminated. +do + 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 + +-- 11. Store with different tab, different non-const idx and different value. +-- Cannot eliminate any stores (would need dynamic disambiguation). +do + 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 + +-- 12. Store with same ref, different value and aliased loads. +-- Cannot eliminate any stores (would need dynamic disambiguation). +do + 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 + +-- CALLL must inhibit DSE. +do + 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/misc/dse_field.lua b/test/misc/dse_field.lua new file mode 100644 index 0000000000..497cd9ecfe --- /dev/null +++ b/test/misc/dse_field.lua @@ -0,0 +1,77 @@ + +local getmetatable, setmetatable = getmetatable, setmetatable + +-- 1. Store with same ref and same value. All stores in loop eliminated. +do + 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 + +-- 2. Store with different ref and same value. All stores in loop eliminated. +do + 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 + +-- 3. Store with different ref and different value. Cannot eliminate any stores. +do + 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 + +-- 4. Store with same ref and different value. 2nd store remains in loop. +do + 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 + +-- 5. Store with same ref, different value and aliased loads. +-- Cannot eliminate any stores. +do + 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/misc/dualnum.lua b/test/misc/dualnum.lua new file mode 100644 index 0000000000..5f1288c8df --- /dev/null +++ b/test/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/misc/exit_frame.lua b/test/misc/exit_frame.lua new file mode 100644 index 0000000000..897984872b --- /dev/null +++ b/test/misc/exit_frame.lua @@ -0,0 +1,80 @@ +do + 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 + 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 + 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 + 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/misc/exit_growstack.lua b/test/misc/exit_growstack.lua new file mode 100644 index 0000000000..548b55565a --- /dev/null +++ b/test/misc/exit_growstack.lua @@ -0,0 +1,24 @@ +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 -- Exit needs to grow stack before slot fill. +end +for j=1,5 do + collectgarbage() -- Shrink stack. + for i=1,100 do f(i) end +end + +local function g(i) + if i==90 then return end -- Exit needs to grow stack after slot fill. + 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 diff --git a/test/misc/exit_jfuncf.lua b/test/misc/exit_jfuncf.lua new file mode 100644 index 0000000000..7e452ef44f --- /dev/null +++ b/test/misc/exit_jfuncf.lua @@ -0,0 +1,30 @@ + +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) + diff --git a/test/misc/fac.lua b/test/misc/fac.lua new file mode 100644 index 0000000000..86dc427070 --- /dev/null +++ b/test/misc/fac.lua @@ -0,0 +1,13 @@ +local function fac(n) + local x = 1 + for i=2,n do + x = x * i + end + return x +end + +if arg and arg[1] then + print(fac(tonumber(arg[1]))) +else + assert(fac(10) == 3628800) +end diff --git a/test/misc/fastfib.lua b/test/misc/fastfib.lua new file mode 100644 index 0000000000..80394bdd08 --- /dev/null +++ b/test/misc/fastfib.lua @@ -0,0 +1,26 @@ + +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 + +if arg and arg[1] then + local n = tonumber(arg and arg[1]) or 10 + io.write(string.format("Fib(%d): %.0f\n", n, fib(n))) +else + assert(fib(40) == 165580141) + assert(fib(39) == 102334155) + assert(fib(77) == 8944394323791464) +end diff --git a/test/misc/fib.lua b/test/misc/fib.lua new file mode 100644 index 0000000000..74eb046496 --- /dev/null +++ b/test/misc/fib.lua @@ -0,0 +1,11 @@ +local function fib(n) + if n < 2 then return 1 end + return fib(n-2) + fib(n-1) +end + +if arg and arg[1] then + local n = tonumber(arg[1]) or 10 + io.write(string.format("Fib(%d): %d\n", n, fib(n))) +else + assert(fib(27) == 317811) +end diff --git a/test/misc/for_dir.lua b/test/misc/for_dir.lua new file mode 100644 index 0000000000..4dd38dee0d --- /dev/null +++ b/test/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/misc/fori_coerce.lua b/test/misc/fori_coerce.lua new file mode 100644 index 0000000000..7330943bd8 --- /dev/null +++ b/test/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/misc/fuse.lua b/test/misc/fuse.lua new file mode 100644 index 0000000000..c4e077c87d --- /dev/null +++ b/test/misc/fuse.lua @@ -0,0 +1,8 @@ + +-- Don't fuse i+101 on x64. +-- Except if i is sign-extended to 64 bit or addressing is limited to 32 bit. +do + local t = {} + for i=-100,-1 do t[i+101] = 1 end +end + diff --git a/test/misc/fwd_hrefk_rollback.lua b/test/misc/fwd_hrefk_rollback.lua new file mode 100644 index 0000000000..1c4d597923 --- /dev/null +++ b/test/misc/fwd_hrefk_rollback.lua @@ -0,0 +1,34 @@ + +-- 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)) + diff --git a/test/misc/fwd_tnew_tdup.lua b/test/misc/fwd_tnew_tdup.lua new file mode 100644 index 0000000000..105263ca08 --- /dev/null +++ b/test/misc/fwd_tnew_tdup.lua @@ -0,0 +1,78 @@ + +-- 1. +do + local x = 2 + for i=1,100 do + local t = {} -- TNEW: DCE + x = t.foo -- HREF -> niltv: folded + end + assert(x == nil) +end + +-- 2. +do + local x = 2 + for i=1,100 do + local t = {1} -- TDUP: DCE + x = t.foo -- HREF -> niltv: folded + end + assert(x == nil) +end + +-- 3. +do + 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 + +-- 4. HREFK not eliminated. Ditto for the EQ(FLOAD(t, #tab.hmask), k). +do + 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 + +-- 5. HREFK not eliminated. Ditto for the EQ(FLOAD(t, #tab.hmask), k). +do + 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 + +-- 6. +do + 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 + +-- 7. +do + 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/misc/fwd_upval.lua b/test/misc/fwd_upval.lua new file mode 100644 index 0000000000..7fb360d2d3 --- /dev/null +++ b/test/misc/fwd_upval.lua @@ -0,0 +1,57 @@ + +-- 1. Open upvalue above base slot, aliasing an SSA value. +do + 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 + +-- 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). +do + 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 + +-- 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). +do + 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 + +-- 4. Open upvalue below base slot. Forwarded. 1x USTORE (+ 1x DSE USTORE). +do + local x = 7 + (function() + local function a() x = x + 1 end + for i=1,100 do a(); a() end + end)() + assert(x == 207) +end + +-- 5. Closed upvalue. Forwarded. 1x USTORE (+ 1x DSE USTORE). +do + 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/misc/gc_rechain.lua b/test/misc/gc_rechain.lua new file mode 100644 index 0000000000..285f408671 --- /dev/null +++ b/test/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/misc/gc_trace.lua b/test/misc/gc_trace.lua new file mode 100644 index 0000000000..bc38ce0ca3 --- /dev/null +++ b/test/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/misc/gcstep.lua b/test/misc/gcstep.lua new file mode 100644 index 0000000000..533356b76e --- /dev/null +++ b/test/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/misc/getfenv.lua b/test/misc/getfenv.lua new file mode 100644 index 0000000000..48a261a7a0 --- /dev/null +++ b/test/misc/getfenv.lua @@ -0,0 +1,15 @@ + +do + 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/misc/goto.lua b/test/misc/goto.lua new file mode 100644 index 0000000000..8553a8aa90 --- /dev/null +++ b/test/misc/goto.lua @@ -0,0 +1,156 @@ + +-- Basic goto and label semantics. +do + local function expect(src, msg) + local ok, err = loadstring(src) + if msg then + assert(not ok and string.find(err, msg)) + else + assert(ok) + end + end + + -- 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'") + + if os.getenv("LUA52") then + expect("goto = 1", "") + else + expect("goto = 1") + end + + ::a:: do goto a; ::a:: end -- Forward jump, not an infinite loop. +end + +-- Trailing label is considered to be out of scope. +do + local x = 11 + do + goto a + goto a + local y = 22 + x = y + ::a:: + ::b:: + end + assert(x == 11) + if os.getenv("LUA52") then + assert(loadstring([[ + local x = 11 + do + goto a + goto a + local y = 22 + x = y + ::a:: ;; + ::b:: ;; + end + return x + ]])() == 11) + end +end + +-- Simple loop with cross-jumping. +do + 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 + +-- Backwards goto must close upval. +do + 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 + +-- Break must close upval, even if closure is parsed after break. +do + 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 + +-- Label prevents joining to KNIL. +do + local k = 0 + local x + ::foo:: + local y + assert(y == nil) + y = true + k = k + 1 + if k < 2 then goto foo end +end + +-- Break resolved from the right scope. +do + 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 not join twice with UCLO. +do + 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/misc/hook_active.lua b/test/misc/hook_active.lua new file mode 100644 index 0000000000..37dfc37937 --- /dev/null +++ b/test/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/misc/hook_line.lua b/test/misc/hook_line.lua new file mode 100644 index 0000000000..36f710807a --- /dev/null +++ b/test/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/misc/hook_norecord.lua b/test/misc/hook_norecord.lua new file mode 100644 index 0000000000..8e7cba05ea --- /dev/null +++ b/test/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/misc/hook_record.lua b/test/misc/hook_record.lua new file mode 100644 index 0000000000..6f1646dead --- /dev/null +++ b/test/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/misc/hook_top.lua b/test/misc/hook_top.lua new file mode 100644 index 0000000000..f809fcea64 --- /dev/null +++ b/test/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/misc/iter.lua b/test/misc/iter.lua new file mode 100644 index 0000000000..4811812eef --- /dev/null +++ b/test/misc/iter.lua @@ -0,0 +1,85 @@ + +do + local n = 0 + for k,v in pairs(_G) do + assert(_G[k] == v) + n = n + 1 + end + assert(n >= 40) +end + +do + 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 + 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 + +do + 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 + local ok, err = pcall(next, _G, 1) + assert(not ok) + local ok, err = pcall(function() next(_G, 1) end) + assert(not ok) +end + +do + 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 + + for _, c in ipairs(t) do + for i = 1, 2 do + o[i][c] = o[i][c] or 1 + end + end +end + +do + 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/misc/jit_flush.lua b/test/misc/jit_flush.lua new file mode 100644 index 0000000000..ead1e4e991 --- /dev/null +++ b/test/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/misc/kfold.lua b/test/misc/kfold.lua new file mode 100644 index 0000000000..1a532f16d8 --- /dev/null +++ b/test/misc/kfold.lua @@ -0,0 +1,81 @@ + +do + 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) + for i=1,100 do local a, b = 8, 11.5; y = a^b end; assert(y == 8^11.5) +end + +do + 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 + 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 + 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 + 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 + 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 + +assert((10^-2 - 0.01) == 0) diff --git a/test/misc/libfuncs.lua b/test/misc/libfuncs.lua new file mode 100644 index 0000000000..d0cf42ff07 --- /dev/null +++ b/test/misc/libfuncs.lua @@ -0,0 +1,63 @@ + +local function check(m, expected) + local t = {} + for k in pairs(m) do t[#t+1] = tostring(k) end + table.sort(t) + local got = table.concat(t, ":") + if got ~= expected then + error("got: \""..got.."\"\nexpected: \""..expected.."\"", 2) + end +end + +local bit = bit +_G.bit = nil +_G.jit = nil +table.setn = nil +package.searchpath = nil + +if os.getenv("LUA52") then + check(_G, "_G:_VERSION:arg:assert:collectgarbage:coroutine:debug:dofile:error:gcinfo:getfenv:getmetatable:io:ipairs:load:loadfile:loadstring:math:module:newproxy:next:os:package:pairs:pcall:print:rawequal:rawget:rawlen:rawset:require:select:setfenv:setmetatable:string:table:tonumber:tostring:type:unpack:xpcall") + check(math, "abs:acos:asin:atan:atan2:ceil:cos:cosh:deg:exp:floor:fmod:frexp:huge:ldexp:log:log10:max:min:modf:pi:pow:rad:random:randomseed:sin:sinh:sqrt:tan:tanh") + check(string, "byte:char:dump:find:format:gmatch:gsub:len:lower:match:rep:reverse:sub:upper") + check(table, "concat:foreach:foreachi:getn:insert:maxn:pack:remove:sort:unpack") +else + check(_G, "_G:_VERSION:arg:assert:collectgarbage:coroutine:debug:dofile:error:gcinfo:getfenv:getmetatable:io:ipairs:load:loadfile:loadstring:math:module:newproxy:next:os:package:pairs:pcall:print:rawequal:rawget:rawset:require:select:setfenv:setmetatable:string:table:tonumber:tostring:type:unpack:xpcall") + check(math, "abs:acos:asin:atan:atan2:ceil:cos:cosh:deg:exp:floor:fmod:frexp:huge:ldexp:log:log10:max:min:mod:modf:pi:pow:rad:random:randomseed:sin:sinh:sqrt:tan:tanh") + check(string, "byte:char:dump:find:format:gfind:gmatch:gsub:len:lower:match:rep:reverse:sub:upper") + check(table, "concat:foreach:foreachi:getn:insert:maxn:remove:sort") +end + +check(io, "close:flush:input:lines:open:output:popen:read:stderr:stdin:stdout:tmpfile:type:write") + +check(debug.getmetatable(io.stdin), "__gc:__index:__tostring:close:flush:lines:read:seek:setvbuf:write") + +check(os, "clock:date:difftime:execute:exit:getenv:remove:rename:setlocale:time:tmpname") + +if os.getenv("LUA52") then + check(debug, "debug:getfenv:gethook:getinfo:getlocal:getmetatable:getregistry:getupvalue:getuservalue:setfenv:sethook:setlocal:setmetatable:setupvalue:setuservalue:traceback:upvalueid:upvaluejoin") +else + check(debug, "debug:getfenv:gethook:getinfo:getlocal:getmetatable:getregistry:getupvalue:setfenv:sethook:setlocal:setmetatable:setupvalue:traceback:upvalueid:upvaluejoin") +end + +check(package, "config:cpath:loaded:loaders:loadlib:path:preload:seeall") + +check(package.loaders, "1:2:3:4") +package.loaded.bit = nil +package.loaded.jit = nil +package.loaded["jit.util"] = nil +package.loaded["jit.opt"] = nil +check(package.loaded, "_G:coroutine:debug:io:math:os:package:string:table") + +if bit then + check(bit, "arshift:band:bnot:bor:bswap:bxor:lshift:rol:ror:rshift:tobit:tohex") +end + +local ok, ffi = pcall(require, "ffi") +if ok then + check(ffi, "C:abi:alignof:arch:cast:cdef:copy:errno:fill:gc:istype:load:metatype:new:offsetof:os:sizeof:string:typeinfo:typeof") +end + +assert(math.pi == 3.141592653589793) +assert(math.huge > 0 and 1/math.huge == 0) +assert(debug.getmetatable("").__index == string) + diff --git a/test/misc/lightud.lua b/test/misc/lightud.lua new file mode 100644 index 0000000000..4974d50fcb --- /dev/null +++ b/test/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/misc/loop_unroll.lua b/test/misc/loop_unroll.lua new file mode 100644 index 0000000000..1700fac910 --- /dev/null +++ b/test/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/misc/math_random.lua b/test/misc/math_random.lua new file mode 100644 index 0000000000..391ee2d901 --- /dev/null +++ b/test/misc/math_random.lua @@ -0,0 +1,21 @@ + +local random = math.random +local randomseed = math.randomseed + +do + local N = 1000 + local min, max = math.min, math.max + for j=1,100 do + randomseed(j) + local lo, hi, sum = math.huge, -math.huge, 0 + for i=1,N do + local x = random() + 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 + diff --git a/test/misc/meta_arith.lua b/test/misc/meta_arith.lua new file mode 100644 index 0000000000..f9028fcd0a --- /dev/null +++ b/test/misc/meta_arith.lua @@ -0,0 +1,103 @@ + +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 + +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") + +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") + +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) + + +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) + +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) + + +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) + +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) + +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) + + +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) + +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) + diff --git a/test/misc/meta_arith_jit.lua b/test/misc/meta_arith_jit.lua new file mode 100644 index 0000000000..485cebf53e --- /dev/null +++ b/test/misc/meta_arith_jit.lua @@ -0,0 +1,68 @@ + +do + 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 + 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 + 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 + 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/misc/meta_call.lua b/test/misc/meta_call.lua new file mode 100644 index 0000000000..5cc22be109 --- /dev/null +++ b/test/misc/meta_call.lua @@ -0,0 +1,78 @@ + +local function callmeta(o, a, b) + return o, a, b +end + +local meta = { __call = callmeta } + +do + 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 + 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 + +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) + +do + 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 + local t = setmetatable({}, { __call = function(t, a) return 100-a end }) + for i=1,100 do assert(t(i) == 100-i) end +end + +do + 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 + +debug.setmetatable(0, { __call = function(n) return 100-n end }) +for i=1,100 do assert((i)() == 100-i) end +debug.setmetatable(0, nil) + +do + 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 + 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/misc/meta_cat.lua b/test/misc/meta_cat.lua new file mode 100644 index 0000000000..6f9e9fff39 --- /dev/null +++ b/test/misc/meta_cat.lua @@ -0,0 +1,62 @@ + +do + local a, b, c = "foo", "bar", "baz" + assert(a..b == "foobar") + assert(a..b..c == "foobarbaz") +end + +local function create(cat, v1, v2) + local meta = { __concat = cat } + return setmetatable({v1}, meta), setmetatable({v2}, meta) +end + +do + 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 + 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 + 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 + 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/misc/meta_comp.lua b/test/misc/meta_comp.lua new file mode 100644 index 0000000000..e265bef2c5 --- /dev/null +++ b/test/misc/meta_comp.lua @@ -0,0 +1,151 @@ + +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 + +local xop +local a, b = create(function(op,a,b) xop = op; return "" end) +assert(ab == 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 (ab) == 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(ab == 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 (ab) == 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(ab == 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 (ab) == 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 + +local a, b = create(function(op,a,b) + if op == "lt" then return a[1]b == false) +assert(a<=b == true) +assert(a>=b == false) + +assert(not (ab) == true) +assert(not (a<=b) == false) +assert(not (a>=b) == true) + +b[1] = 1 +assert(ab == false) +assert(a<=b == true) +assert(a>=b == true) + +assert(not (ab) == true) +assert(not (a<=b) == false) +assert(not (a>=b) == false) + +a[1] = 2 +assert(ab == true) +assert(a<=b == false) +assert(a>=b == true) + +assert(not (ab) == 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(ab == false) +assert(a<=b == true) +assert(a>=b == false) + +assert(not (ab) == true) +assert(not (a<=b) == false) +assert(not (a>=b) == true) + +b[1] = 1 +assert(ab == false) +assert(a<=b == true) +assert(a>=b == true) + +assert(not (ab) == true) +assert(not (a<=b) == false) +assert(not (a>=b) == false) + +a[1] = 2 +assert(ab == true) +assert(a<=b == false) +assert(a>=b == true) + +assert(not (ab) == false) +assert(not (a<=b) == true) +assert(not (a>=b) == false) + +-- String comparisons: +local function str_cmp(a, b, lt, gt, le, ge) + assert(ab == gt) + assert(a<=b == le) + assert(a>=b == ge) + assert((not (ab)) == (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") + diff --git a/test/misc/meta_comp_jit.lua b/test/misc/meta_comp_jit.lua new file mode 100644 index 0000000000..57f711283e --- /dev/null +++ b/test/misc/meta_comp_jit.lua @@ -0,0 +1,104 @@ + +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) + +-- Mixed metamethods for ordered comparisons. +do + 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 os.getenv("LUA52") 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 os.getenv("LUA52") then + assert(ok and ret == true) + else + assert(not ok) + end +end + diff --git a/test/misc/meta_eq.lua b/test/misc/meta_eq.lua new file mode 100644 index 0000000000..786f480423 --- /dev/null +++ b/test/misc/meta_eq.lua @@ -0,0 +1,66 @@ + +local function create(equal, v1, v2) + local meta = { __eq = equal } + return setmetatable({v1}, meta), setmetatable({v2}, meta) +end + +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 + +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) + + +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, "") + diff --git a/test/misc/meta_eq_jit.lua b/test/misc/meta_eq_jit.lua new file mode 100644 index 0000000000..ad5d68f18b --- /dev/null +++ b/test/misc/meta_eq_jit.lua @@ -0,0 +1,36 @@ + +do + 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 + 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/misc/meta_framegap.lua b/test/misc/meta_framegap.lua new file mode 100644 index 0000000000..4f2f719ae2 --- /dev/null +++ b/test/misc/meta_framegap.lua @@ -0,0 +1,23 @@ + +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) diff --git a/test/misc/meta_getset.lua b/test/misc/meta_getset.lua new file mode 100644 index 0000000000..3f5c1da19c --- /dev/null +++ b/test/misc/meta_getset.lua @@ -0,0 +1,34 @@ + +do + local t = setmetatable({}, { __metatable = "foo" }) + for i=1,100 do assert(getmetatable(t) == "foo") end +end + +do + 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 + 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 + local x = true + for i=1,100 do x = getmetatable(i) end + assert(x == nil) +end + diff --git a/test/misc/meta_len.lua b/test/misc/meta_len.lua new file mode 100644 index 0000000000..6e77678de5 --- /dev/null +++ b/test/misc/meta_len.lua @@ -0,0 +1,43 @@ + +local lua52 = os.getenv("LUA52") + +local mt = { __len = function(o, o2) + if lua52 then + assert(o2 == o) + else + assert(o2 == nil) + end + return 42 +end } + +do + 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 lua52 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 + 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 + +debug.setmetatable(0, mt) +assert(#1 == 42) +debug.setmetatable(0, nil) + diff --git a/test/misc/meta_nomm.lua b/test/misc/meta_nomm.lua new file mode 100644 index 0000000000..457d0ee288 --- /dev/null +++ b/test/misc/meta_nomm.lua @@ -0,0 +1,21 @@ + +do + 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/misc/meta_pairs.lua b/test/misc/meta_pairs.lua new file mode 100644 index 0000000000..802a56ff6d --- /dev/null +++ b/test/misc/meta_pairs.lua @@ -0,0 +1,47 @@ + +do + 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 + 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 + +if os.getenv("LUA52") then + 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 + diff --git a/test/misc/meta_tget.lua b/test/misc/meta_tget.lua new file mode 100644 index 0000000000..7c051009ec --- /dev/null +++ b/test/misc/meta_tget.lua @@ -0,0 +1,25 @@ + +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 + + +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") + diff --git a/test/misc/meta_tget_nontab.lua b/test/misc/meta_tget_nontab.lua new file mode 100644 index 0000000000..3c40a514de --- /dev/null +++ b/test/misc/meta_tget_nontab.lua @@ -0,0 +1,33 @@ + +do + 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 + local s = "foo" + string.s = s + 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 + assert(x == 300) +end + diff --git a/test/misc/meta_tset.lua b/test/misc/meta_tset.lua new file mode 100644 index 0000000000..f844e1b567 --- /dev/null +++ b/test/misc/meta_tset.lua @@ -0,0 +1,15 @@ + +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 + diff --git a/test/misc/meta_tset_nilget.lua b/test/misc/meta_tset_nilget.lua new file mode 100644 index 0000000000..1fdebab383 --- /dev/null +++ b/test/misc/meta_tset_nilget.lua @@ -0,0 +1,23 @@ + +do + 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 + 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 + diff --git a/test/misc/meta_tset_resize.lua b/test/misc/meta_tset_resize.lua new file mode 100644 index 0000000000..a58dac1136 --- /dev/null +++ b/test/misc/meta_tset_resize.lua @@ -0,0 +1,10 @@ +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 = _ diff --git a/test/misc/meta_tset_str.lua b/test/misc/meta_tset_str.lua new file mode 100644 index 0000000000..b72be3a8e5 --- /dev/null +++ b/test/misc/meta_tset_str.lua @@ -0,0 +1,18 @@ + +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 + diff --git a/test/misc/modulo.lua b/test/misc/modulo.lua new file mode 100644 index 0000000000..fefb02cf1e --- /dev/null +++ b/test/misc/modulo.lua @@ -0,0 +1,42 @@ + +for x=-5,5 do + for y=-5,5 do + if y ~= 0 then + assert(x%y == x-math.floor(x/y)*y) + end + end +end + +for x=-5,5,0.25 do + for y=-5,5,0.25 do + if y ~= 0 then + assert(x%y == x-math.floor(x/y)*y) + end + end +end + +do + local y = 0 + for x=-100,123 do + y = y + x%17 + end + assert(y == 1777) +end + +do + local y = 0 + for x=-100,123 do + if x ~= 0 then + y = y + 85%x + end + end + assert(y == 2059) +end + +do + local x = 1%0 + assert(x ~= x) + x = math.floor(0/0) + assert(x ~= x) +end + diff --git a/test/misc/nsieve.lua b/test/misc/nsieve.lua new file mode 100644 index 0000000000..49dc1c8df7 --- /dev/null +++ b/test/misc/nsieve.lua @@ -0,0 +1,20 @@ +local function nsieve(m, 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 + +local flags = {} +if arg and arg[1] then + local N = tonumber(arg and arg[1]) + io.write(string.format("Primes up to %8d %8d", N, nsieve(N,flags)), "\n") +else + assert(nsieve(100, flags) == 25) + assert(nsieve(12345, flags) == 1474) +end diff --git a/test/misc/parse_andor.lua b/test/misc/parse_andor.lua new file mode 100644 index 0000000000..2c796cb375 --- /dev/null +++ b/test/misc/parse_andor.lua @@ -0,0 +1,58 @@ +local x = ((1 or false) and true) or false +assert(x == true) + +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("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 + +do + -- 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/misc/parse_comp.lua b/test/misc/parse_comp.lua new file mode 100644 index 0000000000..5e1948da80 --- /dev/null +++ b/test/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/misc/parse_esc.lua b/test/misc/parse_esc.lua new file mode 100644 index 0000000000..4bcce0e864 --- /dev/null +++ b/test/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/misc/parse_hex.lua b/test/misc/parse_hex.lua new file mode 100644 index 0000000000..bb6da92538 --- /dev/null +++ b/test/misc/parse_hex.lua @@ -0,0 +1,7 @@ +assert(1e5 == 100000) +assert(1e+5 == 100000) +assert(1e-5 == 0.00001) +assert(0xe+9 == 23) +assert(0xep9 == 7168) +assert(0xep+9 == 7168) +assert(0xep-9 == 0.02734375) diff --git a/test/misc/parse_misc.lua b/test/misc/parse_misc.lua new file mode 100644 index 0000000000..8031ec171f --- /dev/null +++ b/test/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/misc/pcall_jit.lua b/test/misc/pcall_jit.lua new file mode 100644 index 0000000000..f5dbe62024 --- /dev/null +++ b/test/misc/pcall_jit.lua @@ -0,0 +1,75 @@ + +do + 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 + 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 + 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 + 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 + 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/misc/phi_conv.lua b/test/misc/phi_conv.lua new file mode 100644 index 0000000000..8d7bea5fdc --- /dev/null +++ b/test/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/misc/phi_copyspill.lua b/test/misc/phi_copyspill.lua new file mode 100644 index 0000000000..c62d66fbb4 --- /dev/null +++ b/test/misc/phi_copyspill.lua @@ -0,0 +1,51 @@ +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) diff --git a/test/misc/phi_ref.lua b/test/misc/phi_ref.lua new file mode 100644 index 0000000000..7493ef466f --- /dev/null +++ b/test/misc/phi_ref.lua @@ -0,0 +1,141 @@ +-- rref points into invariant part +do + local x,y=1,2; for i=1,100 do x=x+y; y=i end + assert(y == 100) +end + +do + local x,y=1,2; for i=1,100.5 do x=x+y; y=i end + assert(y == 100) +end + +do + local x,y=1,2; for i=1,100 do x,y=y,x end + assert(x == 1) + assert(y == 2) +end + +do + 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 + 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 + 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 + +-- variant slot, but no corresponding SLOAD +do + local x,y=1,2; for i=1,100 do x=i; y=i-1 end + assert(x == 100) + assert(y == 99) +end + +do + local x,y=1,2; for i=1,100 do x=i; y=i+1 end + assert(x == 100) + assert(y == 101) +end + +do + local x=0; for i=1,100 do if i==90 then break end x=i end + assert(x == 89) +end + +-- dup lref from variant slot (suppressed) +do + local x,y=1,2; for i=1,100 do x=i; y=i end + assert(x == 100) + assert(y == 100) +end + +-- const rref +do + 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 + +-- dup rref (ok) +do + 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 + +-- variant slot, no corresponding SLOAD, +do + 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 + +-- don't eliminate PHI if referenced from snapshot +do + 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 + +-- don't eliminate PHI if referenced from snapshot +do + 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 + +-- don't eliminate PHI if referenced from another non-redundant PHI +do + 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/misc/phi_rot18.lua b/test/misc/phi_rot18.lua new file mode 100644 index 0000000000..b57b040539 --- /dev/null +++ b/test/misc/phi_rot18.lua @@ -0,0 +1,39 @@ +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") diff --git a/test/misc/phi_rot8.lua b/test/misc/phi_rot8.lua new file mode 100644 index 0000000000..2c249b76da --- /dev/null +++ b/test/misc/phi_rot8.lua @@ -0,0 +1,39 @@ +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") diff --git a/test/misc/phi_rot9.lua b/test/misc/phi_rot9.lua new file mode 100644 index 0000000000..e7b2821fb7 --- /dev/null +++ b/test/misc/phi_rot9.lua @@ -0,0 +1,39 @@ +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") diff --git a/test/misc/phi_rotx.lua b/test/misc/phi_rotx.lua new file mode 100644 index 0000000000..c8c8b1eb35 --- /dev/null +++ b/test/misc/phi_rotx.lua @@ -0,0 +1,21 @@ +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") diff --git a/test/misc/recsum.lua b/test/misc/recsum.lua new file mode 100644 index 0000000000..a25336d1c3 --- /dev/null +++ b/test/misc/recsum.lua @@ -0,0 +1,11 @@ + +do + local function sum(n) + if n == 1 then return 1 end + return n + sum(n-1) + end + for i=1,tonumber(arg and arg[1]) or 100 do + assert(sum(100) == 5050) + end +end + diff --git a/test/misc/recsump.lua b/test/misc/recsump.lua new file mode 100644 index 0000000000..2285018180 --- /dev/null +++ b/test/misc/recsump.lua @@ -0,0 +1,11 @@ + +do + 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,tonumber(arg and arg[1]) or 100 do + assert(sum(100) == 5050) + end +end diff --git a/test/misc/recurse_deep.lua b/test/misc/recurse_deep.lua new file mode 100644 index 0000000000..9b9af2952f --- /dev/null +++ b/test/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/misc/recurse_tail.lua b/test/misc/recurse_tail.lua new file mode 100644 index 0000000000..ef76443211 --- /dev/null +++ b/test/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/misc/select.lua b/test/misc/select.lua new file mode 100644 index 0000000000..4d9cda853b --- /dev/null +++ b/test/misc/select.lua @@ -0,0 +1,88 @@ + +do + local x = 0 + for i=1,100 do + x = x + select("#", 3, 4) + end + assert(x == 200) +end + +do + local x = 0 + for i=1,100 do + x = x + select("#", math.modf(i)) + end + assert(x == 200) +end + +do + local x = 0 + for i=1,100 do + x = x + select(1, i) + end + assert(x == 5050) +end + +do + 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 + 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 + 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 + 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 + diff --git a/test/misc/self.lua b/test/misc/self.lua new file mode 100644 index 0000000000..afb95ce041 --- /dev/null +++ b/test/misc/self.lua @@ -0,0 +1,18 @@ +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) + diff --git a/test/misc/sink_alloc.lua b/test/misc/sink_alloc.lua new file mode 100644 index 0000000000..55f4218e63 --- /dev/null +++ b/test/misc/sink_alloc.lua @@ -0,0 +1,140 @@ + +local assert = assert + +-- DCE or sink trivial TNEW or TDUP. +do + for i=1,100 do local t={} end + for i=1,100 do local t={1} end +end + +-- Sink TNEW/TDUP + ASTORE/HSTORE. +do + 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 + +-- Sink outermost table of nested TNEW. +do + 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 + +-- Sink one TNEW + FSTORE. +do + for i=1,100 do local t = setmetatable({}, {}) end +end + +-- Sink TDUP or TDUP + HSTORE. Guard of HREFK eliminated. +do + 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 + +-- Sink of simplified complex add, unused in next iteration, drop PHI. +do + 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 + +-- Sink of complex add, unused in next iteration, drop PHI. +do + 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 + +-- Sink of TDUP with stored values that are both PHI and non-PHI. +do + 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 + +-- Sink of CONV. +do + 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 + +-- Sink of stores with numbers. +do + 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 + +-- Sink of stores with constants. +do + for i=1,100 do local t = {false}; t[1] = true; if i > 100 then g=t end end +end + +-- Sink with two references to the same table. +do + for i=1,200 do + local t = {i} + local q = t + if i > 100 then assert(t == q) end + end +end + +do + 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 + 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/misc/sink_nosink.lua b/test/misc/sink_nosink.lua new file mode 100644 index 0000000000..5badfd2690 --- /dev/null +++ b/test/misc/sink_nosink.lua @@ -0,0 +1,124 @@ + +local assert = assert + +-- Cannot sink TNEW, aliased load. +do + 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 + +-- Cannot sink TNEW, escaping to upvalue. +do + (function() + local uv + return function() + for i=1,100 do uv = {i} end + assert(uv[1] == 100) + end + end)()() +end + +-- Cannot sink TNEW, escaping through a store. +do + 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 + +-- Cannot sink TNEW, iteratively escaping through a store. +do + local t = {} + for i=1,100 do t[1] = {i}; t[1][1] = {i} end + assert(t[1][1][1] == 100) +end + +-- Cannot sink TNEW, escaping to next iteration (unused in 1st variant). +do + 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 + +-- Cannot sink TNEW, escaping to next iteration (snapshot ref). +do + local t,x + for i=1,100 do x=t; t={i} end + assert(t[1] == 100) + assert(x[1] == 99) +end + +-- Cannot sink TNEW, escaping to next iteration (IR/snapshot ref). +do + local t + for i=1,100 do t={t} end + assert(type(t[1][1][1]) == "table") +end + +-- Could sink outer TNEW, but the logic for stores to PHI allocs is too simple. +-- Cannot sink inner TNEW, escaping to next iteration (IR ref). +do + 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 + +-- Cannot sink TNEW, cross-PHI ref (and snapshot ref). +do + local x,y + for i=1,100 do x,y={i},x end + assert(x[1] == 100) + assert(y[1] == 99) +end + +-- Cannot sink TNEW, cross-PHI ref (and snapshot ref). +do + local x,y + for i=1,100 do x,y=y,{i} end + assert(x[1] == 99) + assert(y[1] == 100) +end + +-- Cannot sink TNEW, escaping to exit. +do + 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 + +-- Cannot sink TNEW, escaping to exit. +do + 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 + t = f(3) + assert(t[1][1][1] == 42) +end + +-- Cannot sink, since nested inner table is non-PHI. +do + 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/misc/snap_gcexit.lua b/test/misc/snap_gcexit.lua new file mode 100644 index 0000000000..37fce65ae4 --- /dev/null +++ b/test/misc/snap_gcexit.lua @@ -0,0 +1,16 @@ + +do + 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 + diff --git a/test/misc/snap_top.lua b/test/misc/snap_top.lua new file mode 100644 index 0000000000..a717a15989 --- /dev/null +++ b/test/misc/snap_top.lua @@ -0,0 +1,16 @@ + +do + 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 + diff --git a/test/misc/snap_top2.lua b/test/misc/snap_top2.lua new file mode 100644 index 0000000000..4504dc3e23 --- /dev/null +++ b/test/misc/snap_top2.lua @@ -0,0 +1,15 @@ + +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 diff --git a/test/misc/sort.lua b/test/misc/sort.lua new file mode 100644 index 0000000000..4b2e40129e --- /dev/null +++ b/test/misc/sort.lua @@ -0,0 +1,23 @@ +-- Really a test for lua_lessthan() + +local N = 1000 + +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 + +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 + +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 + diff --git a/test/misc/stack_gc.lua b/test/misc/stack_gc.lua new file mode 100644 index 0000000000..656a06a054 --- /dev/null +++ b/test/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/misc/stack_purge.lua b/test/misc/stack_purge.lua new file mode 100644 index 0000000000..bfaee0f3e9 --- /dev/null +++ b/test/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/misc/stackov.lua b/test/misc/stackov.lua new file mode 100644 index 0000000000..ef105af6f9 --- /dev/null +++ b/test/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/misc/stackovc.lua b/test/misc/stackovc.lua new file mode 100644 index 0000000000..c00bcbd825 --- /dev/null +++ b/test/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/misc/stitch.lua b/test/misc/stitch.lua new file mode 100644 index 0000000000..1eba1810bb --- /dev/null +++ b/test/misc/stitch.lua @@ -0,0 +1,21 @@ + +do + 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 + 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/misc/strcmp.lua b/test/misc/strcmp.lua new file mode 100644 index 0000000000..53d1ce5f0e --- /dev/null +++ b/test/misc/strcmp.lua @@ -0,0 +1,11 @@ + +do + 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 + diff --git a/test/misc/string_byte.lua b/test/misc/string_byte.lua new file mode 100644 index 0000000000..cd565ecb48 --- /dev/null +++ b/test/misc/string_byte.lua @@ -0,0 +1,90 @@ + +local band, bor = bit.band, bit.bor +local byte = string.byte + +-- Fixed slice [i,i+k] or overflow +do + 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 + +-- Positive slice [i,len] or overflow +do + 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 + +-- Negative slice [-i,len] or underflow +do + 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 + +-- Positive slice [1,i] or overflow +do + 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 + +-- Negative slice [1,-i] or underflow +do + 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 + +-- Check for slot stack overflow +do + local s = string.rep("x", 500) + for i=1,100 do byte(s, 1, 500) end +end + diff --git a/test/misc/string_char.lua b/test/misc/string_char.lua new file mode 100644 index 0000000000..3920c3a4c2 --- /dev/null +++ b/test/misc/string_char.lua @@ -0,0 +1,28 @@ + +do + local y + for i=1,100 do y = string.char(65) end + assert(y == "A") + local x = 97 + for i=1,100 do y = string.char(x) end + assert(y == "a") + x = "98" + for i=1,100 do y = string.char(x) end + assert(y == "b") + for i=1,100 do y = string.char(32+i) end + assert(y == "\132") +end + +do + local y + assert(not pcall(function() + for i=1,200 do y = string.char(100+i) end + end)) + assert(y == "\255") +end + +do + local y + for i=1,100 do y = string.char(65, 66, i, 67, 68) end + assert(y == "ABdCD") +end diff --git a/test/misc/string_dump.lua b/test/misc/string_dump.lua new file mode 100644 index 0000000000..a255b8a895 --- /dev/null +++ b/test/misc/string_dump.lua @@ -0,0 +1,31 @@ + +-- Must unpatch modified bytecode with ILOOP/JLOOP etc. +do + 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) + jit.off(foo) + 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 + 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/misc/string_op.lua b/test/misc/string_op.lua new file mode 100644 index 0000000000..6adb790ee2 --- /dev/null +++ b/test/misc/string_op.lua @@ -0,0 +1,110 @@ + +do + local y + for i=1,100 do y = string.reverse("abc") end + assert(y == "cba") + local x = "abcd" + for i=1,100 do y = string.reverse(x) end + assert(y == "dcba") + x = 1234 + for i=1,100 do y = string.reverse(x) end + assert(y == "4321") +end + +do + 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 + 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 + +do + 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 + +do + 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 + local y + for i=1,100 do y = string.rep("a", 10) end + assert(y == "aaaaaaaaaa") + for i=1,100 do y = string.rep("ab", 10) end + assert(y == "abababababababababab") + for i=1,100 do y = string.rep("ab", 10, "c") end + assert(y == "abcabcabcabcabcabcabcabcabcab") + local x = "a" + for i=1,100 do y = string.rep(x, 10) end + assert(y == "aaaaaaaaaa") + local n = 10 + for i=1,100 do y = string.rep(x, n) end + assert(y == "aaaaaaaaaa") + x = "ab" + for i=1,100 do y = string.rep(x, n) end + assert(y == "abababababababababab") + x = 12 + n = "10" + for i=1,100 do y = string.rep(x, n) end + assert(y == "12121212121212121212") +end + +do + local t = {} + for i=1,100 do t[i] = string.rep("ab", i-85) end + assert(t[100] == "ababababababababababababababab") + for i=1,100 do t[i] = string.rep("ab", i-85, "c") end + assert(t[85] == "") + assert(t[86] == "ab") + assert(t[87] == "abcab") + assert(t[100] == "abcabcabcabcabcabcabcabcabcabcabcabcabcabcab") +end + +do + local y, z + local x = "ab" + for i=1,100 do + y = string.rep(x, i-90) + z = y.."fgh" + end + assert(y == "abababababababababab") + assert(z == "ababababababababababfgh") +end + diff --git a/test/misc/string_sub.lua b/test/misc/string_sub.lua new file mode 100644 index 0000000000..2cdfac766a --- /dev/null +++ b/test/misc/string_sub.lua @@ -0,0 +1,60 @@ + +local band, bor = bit.band, bit.bor +local sub = string.sub + +-- Positive slice [i,len] or overflow +do + 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 + +-- Negative slice [-i,len] or underflow +do + 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 + +-- Positive slice [1,i] or overflow +do + 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 + +-- Negative slice [1,-i] or underflow +do + 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 + diff --git a/test/misc/string_sub_opt.lua b/test/misc/string_sub_opt.lua new file mode 100644 index 0000000000..235767aff8 --- /dev/null +++ b/test/misc/string_sub_opt.lua @@ -0,0 +1,109 @@ + +do + local s = "abcde" + local x = 0 + for i=1,100 do + if string.sub(s, 1, 1) == "a" then x = x + 1 end + end + assert(x == 100) +end + +do + local s = "abcde" + local x = 0 + for i=1,100 do + if string.sub(s, 1, 1) == "b" then x = x + 1 end + end + assert(x == 0) +end + +do + local s = "abcde" + local x = 0 + for i=1,100 do + if string.sub(s, 1, 1) == "ab" then x = x + 1 end + end + assert(x == 0) +end + +do + local s = "abcde" + local x = 0 + for i=1,100 do + if string.sub(s, 1, 2) == "a" then x = x + 1 end + end + assert(x == 0) +end + +do + local s = "abcde" + local x = 0 + local k = 1 + for i=1,100 do + if string.sub(s, 1, k) == "a" then x = x + 1 end + end + assert(x == 100) +end + +do + local s = "abcde" + local x = 0 + local k = 1 + for i=1,100 do + if string.sub(s, 1, k) == "b" then x = x + 1 end + end + assert(x == 0) +end + +do + local s = "abcde" + local x = 0 + local k = 1 + for i=1,100 do + if string.sub(s, 1, k) == "ab" then x = x + 1 end + end + assert(x == 0) +end + +---- + +do + local s = "abcde" + local x = 0 + for i=1,100 do + if string.sub(s, 1, 2) == "ab" then x = x + 1 end + end + assert(x == 100) +end + +do + local s = "abcde" + local x = 0 + for i=1,100 do + if string.sub(s, 1, 3) == "abc" then x = x + 1 end + end + assert(x == 100) +end + +do + local s = "abcde" + local x = 0 + for i=1,100 do + if string.sub(s, 1, 4) == "abcd" then x = x + 1 end + end + assert(x == 100) +end + +do + 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/misc/table_insert.lua b/test/misc/table_insert.lua new file mode 100644 index 0000000000..28a094dae9 --- /dev/null +++ b/test/misc/table_insert.lua @@ -0,0 +1,18 @@ + +local tinsert = table.insert +local assert = assert + +do + 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 + 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/misc/table_misc.lua b/test/misc/table_misc.lua new file mode 100644 index 0000000000..9362b254ea --- /dev/null +++ b/test/misc/table_misc.lua @@ -0,0 +1,131 @@ + +-- ABC elim +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 +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 + +do + local function f() return 9, 10 end + 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 + +-- table.new +do + local tnew = require("table.new") + local x, y + for i=1,100 do + x = tnew(100, 30) + if i == 90 then y = x end + end + assert(x ~= y) +end + +-- table.concat +do + local t = {a=1,b=2,c=3,d=4,e=5} + t[1] = 4 + t[3] = 6 + local ok, err = pcall(table.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(table.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] = table.concat(q[i], "x") end + assert(q[90] == "4x5x6") + assert(q[91] == "") + assert(q[92] == "9") + assert(q[93] == "9x8x7") +end + +-- table.concat must inhibit CSE and DSE +do + local t = {1,2,3} + local y, z + for i=1,100 do + y = table.concat(t, "x", 1, 3) + t[2] = i + z = table.concat(t, "x", 1, 3) + end + assert(y == "1x99x3") + assert(z == "1x100x3") +end + +do + local y + for i=1,100 do + local t = {1,2,3} + t[2] = 4 + y = table.concat(t, "x") + t[2] = 9 + end + assert(y == "1x4x3") +end + +do + local t = {[0]={}, {}, {}, {}} + for i=1,30 do + for j=3,0,-1 do + t[j].x = t[j-1] + end + end +end + +-- table.pack +if os.getenv("LUA52") then + local t + + t = table.pack() + assert(t.n == 0 and t[0] == nil and t[1] == nil) + + t = table.pack(99) + assert(t.n == 1 and t[0] == nil and t[1] == 99 and t[2] == nil) + + t = table.pack(nil, nil, nil) + assert(t.n == 3 and t[0] == nil and t[1] == nil and t[2] == nil and t[3] == nil and t[4] == nil) +end + diff --git a/test/misc/table_remove.lua b/test/misc/table_remove.lua new file mode 100644 index 0000000000..d8cdd19dcb --- /dev/null +++ b/test/misc/table_remove.lua @@ -0,0 +1,25 @@ + +local tremove = table.remove +local assert = assert + +do + 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 + 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 + 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 + diff --git a/test/misc/tak.lua b/test/misc/tak.lua new file mode 100644 index 0000000000..a67478350c --- /dev/null +++ b/test/misc/tak.lua @@ -0,0 +1,12 @@ + +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 + +if arg and arg[1] then + local N = tonumber(arg and arg[1]) or 7 + print(tak(3*N, 2*N, N)) +else + assert(tak(21, 14, 7) == 14) +end diff --git a/test/misc/tcall_base.lua b/test/misc/tcall_base.lua new file mode 100644 index 0000000000..c6c4ae1a31 --- /dev/null +++ b/test/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/misc/tcall_loop.lua b/test/misc/tcall_loop.lua new file mode 100644 index 0000000000..d3c6f1a6de --- /dev/null +++ b/test/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/misc/tlen_loop.lua b/test/misc/tlen_loop.lua new file mode 100644 index 0000000000..050f23c389 --- /dev/null +++ b/test/misc/tlen_loop.lua @@ -0,0 +1,23 @@ + +do + local t = {} + for i=1,100 do t[#t+1] = i end + assert(#t == 100) + for i=1,100 do t[#t] = nil end +end + +do + local t = {} + t[90] = 999 + for i=1,100 do t[#t+1] = i end + assert(#t > 100 and t[#t] == 100) +end + +do + 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/misc/tnew_tdup.lua b/test/misc/tnew_tdup.lua new file mode 100644 index 0000000000..140d05dee3 --- /dev/null +++ b/test/misc/tnew_tdup.lua @@ -0,0 +1,16 @@ + +do + local a = nil + local b = {} + local t = {[true] = a, [false] = b or 1} + assert(t[true] == nil) + assert(t[false] == b) +end + +do + local b = {} + local t = {[true] = nil, [false] = b or 1} + assert(t[true] == nil) + assert(t[false] == b) +end + diff --git a/test/misc/tonumber_scan.lua b/test/misc/tonumber_scan.lua new file mode 100644 index 0000000000..78e1ca3ee5 --- /dev/null +++ b/test/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/misc/tonumber_tostring.lua b/test/misc/tonumber_tostring.lua new file mode 100644 index 0000000000..d611b2c3c4 --- /dev/null +++ b/test/misc/tonumber_tostring.lua @@ -0,0 +1,82 @@ + +do + local x = 0 + for i=1,100 do x = x + tonumber(i) end + assert(x == 5050) +end + +do + local x = 0 + for i=1.5,100.5 do x = x + tonumber(i) end + assert(x == 5100) +end + +do + 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 + 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 + for i=1,100 do assert(tonumber({}) == nil) end +end + +do + 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 + 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 + 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 + 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 + assert(tonumber(111, 2) == 7) +end + +do + local t = setmetatable({}, { __tostring = "" }) + assert(pcall(function() tostring(t) end) == false) +end + diff --git a/test/misc/uclo.lua b/test/misc/uclo.lua new file mode 100644 index 0000000000..bd9bd24299 --- /dev/null +++ b/test/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/misc/unordered.lua b/test/misc/unordered.lua new file mode 100644 index 0000000000..9e71046de9 --- /dev/null +++ b/test/misc/unordered.lua @@ -0,0 +1,79 @@ + +local function check(a, b) + if a ~= b then + error("check failed with "..tostring(a).." ~= "..tostring(b), 2) + end +end + +local x,y = 0/0,1 + +check(xx, false) +check(x>=x, false) +check(x==x, false) +check(x~=x, true) + +check(xy, false) +check(x>=y, false) +check(x==y, false) +check(x~=y, true) + +check(yx, false) +check(y>=x, false) +check(y==x, false) +check(y~=x, true) + +check(x<1, false) +check(x<=1, false) +check(x>1, false) +check(x>=1, false) +check(x==1, false) +check(x~=1, true) + +check(1x, false) +check(1>=x, false) +check(1==x, false) +check(1~=x, true) + +check(not (xx), true) +check(not (x>=x), true) +check(not (x==x), true) +check(not (x~=x), false) + +check(not (xy), true) +check(not (x>=y), true) +check(not (x==y), true) +check(not (x~=y), false) + +check(not (yx), true) +check(not (y>=x), true) +check(not (y==x), true) +check(not (y~=x), false) + +check(not (x<1), true) +check(not (x<=1), true) +check(not (x>1), true) +check(not (x>=1), true) +check(not (x==1), true) +check(not (x~=1), false) + +check(not (1x), true) +check(not (1>=x), true) +check(not (1==x), true) +check(not (1~=x), false) + diff --git a/test/misc/unordered_jit.lua b/test/misc/unordered_jit.lua new file mode 100644 index 0000000000..5ff1a1bafd --- /dev/null +++ b/test/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/misc/vararg_jit.lua b/test/misc/vararg_jit.lua new file mode 100644 index 0000000000..98874a31bf --- /dev/null +++ b/test/misc/vararg_jit.lua @@ -0,0 +1,95 @@ + +do + 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 + 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 + 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 + 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 + 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 + 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 + 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/misc/wbarrier.lua b/test/misc/wbarrier.lua new file mode 100644 index 0000000000..5536625a36 --- /dev/null +++ b/test/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/misc/wbarrier_jit.lua b/test/misc/wbarrier_jit.lua new file mode 100644 index 0000000000..2c8dd7fbcb --- /dev/null +++ b/test/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/misc/wbarrier_obar.lua b/test/misc/wbarrier_obar.lua new file mode 100644 index 0000000000..258db2158e --- /dev/null +++ b/test/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/misc/xpcall_jit.lua b/test/misc/xpcall_jit.lua new file mode 100644 index 0000000000..61ffc8e64c --- /dev/null +++ b/test/misc/xpcall_jit.lua @@ -0,0 +1,86 @@ + +local function tr(err) return "tr"..err end + +do + 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 + 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 + 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 + 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 + 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 + local x = 0 + for i=1,100 do + -- Test xpcall swap after recorder error. + 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/sysdep/catch_cpp.lua b/test/sysdep/catch_cpp.lua new file mode 100644 index 0000000000..b2251009a5 --- /dev/null +++ b/test/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/sysdep/ffi_include_gtk.lua b/test/sysdep/ffi_include_gtk.lua new file mode 100644 index 0000000000..a4bfceacaf --- /dev/null +++ b/test/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/sysdep/ffi_include_std.lua b/test/sysdep/ffi_include_std.lua new file mode 100644 index 0000000000..b88c82bdae --- /dev/null +++ b/test/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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +]] + 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/sysdep/ffi_lib_c.lua b/test/sysdep/ffi_lib_c.lua new file mode 100644 index 0000000000..a368d750f7 --- /dev/null +++ b/test/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/sysdep/ffi_lib_z.lua b/test/sysdep/ffi_lib_z.lua new file mode 100644 index 0000000000..69a19aedcd --- /dev/null +++ b/test/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/unportable/ffi_arith_int64.lua b/test/unportable/ffi_arith_int64.lua new file mode 100644 index 0000000000..c05e02a974 --- /dev/null +++ b/test/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/unportable/math_special.lua b/test/unportable/math_special.lua new file mode 100644 index 0000000000..49161014a7 --- /dev/null +++ b/test/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 + From 46e1fea56b9263f5234923f1028643abb76766f1 Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Sun, 21 Feb 2016 18:28:58 +0100 Subject: [PATCH 02/68] Add first part of test framework: parse tests. --- tester.lua | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 tester.lua diff --git a/tester.lua b/tester.lua new file mode 100644 index 0000000000..065bd5c1de --- /dev/null +++ b/tester.lua @@ -0,0 +1,76 @@ +--- Shallow table copy +local function cp(t) + local t1 = {} + for k,v in pairs(t) do t1[k]=v end + return t1 +end + +--- Path tokenizer, builds a table t for which t.token=true +-- @param fn string containing a filename (fullpath) +-- @return table for which keys token = true +local function tags_from_path(fn) + local tags = {} + for token in fn:gmatch("[^\\/]+") do + local token_lua = token:match("(.*)%.lua$") + tags[token_lua or token] = true + end + return tags +end + +--- Parser for the tests. +-- @param fn string containing a filename (fullpath) +-- @return array containing test specs (name, code, description, tags) +-- @return lookup table for tests +-- @return prelude table containing prelude code, description and tags. +local function parse_test(fn) + local tests = {} + local lookup_tests = {} + local prelude = { + description = {}, + code = {}, + tags = tags_from_path(fn), + } + local current_test = prelude + local function store_test() + if current_test and current_test~=prelude then + current_test.code = table.concat(current_test.code,"\n") + current_test.description = table.concat(current_test.description,"\n") + tests[#tests+1] = current_test + lookup_tests[current_test.name] = #tests + end + end + for line in io.lines(fn) do + if line:match("^%-%-%-") then + -- Next test is reached + store_test() + local testname = line:match("^%-%-%-%s*(.*)$") + if lookup_tests[testname] then + error("Test "..testname.." is defined twice in the same file. Please give the tests unique names.") + end + -- Add current test to the tests table and start new current test table. + current_test = { + name = testname, + description = cp(prelude.description), + tags = cp(prelude.tags), + code = cp(prelude.code), + } + elseif line:match("^%-%-") and #current_test.code==#prelude.code then + -- Continue building current test description (and possibly tags) + current_test.description[#current_test.description+1] = line:match("^%-%-%s*(.*)$") + for tag in line:gmatch("%+([A-Za-z_][A-Za-z0-9_]*)") do + current_test.tags[tag] = true + end + else + current_test.code[#current_test.code+1] = line + end + end + store_test() + prelude.code = table.concat(prelude.code,"\n") + prelude.description = table.concat(prelude.description,"\n") + return tests, lookup_tests, prelude +end + + +return { + parse = parse_test +} From a4ec002690ec5b386db6809e8e0771f8db057608 Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Sun, 21 Feb 2016 19:20:51 +0100 Subject: [PATCH 03/68] Add index() and extract() to tester module. index(paths) recursively indexes the tests in paths. extract(test,[fn]) extracts the test to filename fn. --- tester.lua | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/tester.lua b/tester.lua index 065bd5c1de..07ba2fa07f 100644 --- a/tester.lua +++ b/tester.lua @@ -1,3 +1,6 @@ +local lfs = require("lfs") +local tconcat = table.concat + --- Shallow table copy local function cp(t) local t1 = {} @@ -33,8 +36,6 @@ local function parse_test(fn) local current_test = prelude local function store_test() if current_test and current_test~=prelude then - current_test.code = table.concat(current_test.code,"\n") - current_test.description = table.concat(current_test.description,"\n") tests[#tests+1] = current_test lookup_tests[current_test.name] = #tests end @@ -70,7 +71,63 @@ local function parse_test(fn) return tests, lookup_tests, prelude end +-- Recursively parse the path and store the tests in test_index +-- @param path string containing a path to a file or directory +-- @param test_index array containing the tables with {tests,lookup,prelude} +-- @param test_index_lookup lookup table containing keys = paths of the test +-- files and values = respective indices in test_index +local function recursive_parse(path,test_index,test_index_lookup) + print(path) + local att = lfs.attributes(path) + if att.mode=="directory" then + for path2 in lfs.dir(path) do + if path2~=".." and path2~="." then + recursive_parse(path.."/"..path2,test_index,test_index_lookup) + end + end + elseif att.mode=="file" then + local tests, tests_lookup, prelude = parse_test(path) + if tests then + test_index[#test_index+1] = {tests=tests, lookup=tests_lookup, prelude=prelude} + test_index_lookup[path] = #test_index + end + end +end + +--- Walk the directory tree and index tests. +-- @param paths array of paths that should be indexed. +-- @return array of tables containing { tests, lookup, prelude } as returned by +-- parse +-- @return lookup table containing keys = paths of the test files and values = +-- respective indices in test_index +local function index_tests(paths) + local test_index = {} + local test_index_lookup = {} + for _,path in ipairs(paths) do + recursive_parse(path,test_index,test_index_lookup) + end + return test_index, test_index_lookup +end + +--- Extract a test into a directory +--@param test the test table returned by parse, containing name, description, tags, code +--@param fn string containing filename where the test should be extracted (default:os.tmpname()) +--@return filename to where the test was extracted +local function extract_test(test,fn) + fn = fn or os.tmpname() + local f = io.open(fn,"w") + if not f then + error("Could not write to file "..fn) + end + f:write("--- ",test.name,"\n") + f:write("--",tconcat(test.description,"\n--"),"\n") + f:write(tconcat(test.code,"\n")) + f:close() + return fn +end return { - parse = parse_test + parse = parse_test, + index = index_tests, + extract = extract_test, } From a4dd1e0394977fb1eca54f51b888a7876aae5d6a Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Sun, 21 Feb 2016 21:54:25 +0100 Subject: [PATCH 04/68] Add run_single() and run() to tester module. Only consider .lua files in index(). Add utility function build_codestring. --- tester.lua | 94 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 80 insertions(+), 14 deletions(-) diff --git a/tester.lua b/tester.lua index 07ba2fa07f..775de13b3e 100644 --- a/tester.lua +++ b/tester.lua @@ -29,13 +29,15 @@ local function parse_test(fn) local tests = {} local lookup_tests = {} local prelude = { + name = "prelude of "..fn, + fn = fn, description = {}, code = {}, tags = tags_from_path(fn), } local current_test = prelude local function store_test() - if current_test and current_test~=prelude then + if current_test~=prelude then tests[#tests+1] = current_test lookup_tests[current_test.name] = #tests end @@ -51,6 +53,7 @@ local function parse_test(fn) -- Add current test to the tests table and start new current test table. current_test = { name = testname, + fn = fn, description = cp(prelude.description), tags = cp(prelude.tags), code = cp(prelude.code), @@ -61,14 +64,13 @@ local function parse_test(fn) for tag in line:gmatch("%+([A-Za-z_][A-Za-z0-9_]*)") do current_test.tags[tag] = true end - else + else current_test.code[#current_test.code+1] = line end end store_test() - prelude.code = table.concat(prelude.code,"\n") - prelude.description = table.concat(prelude.description,"\n") - return tests, lookup_tests, prelude + tests[0] = prelude + return tests, lookup_tests end -- Recursively parse the path and store the tests in test_index @@ -77,7 +79,6 @@ end -- @param test_index_lookup lookup table containing keys = paths of the test -- files and values = respective indices in test_index local function recursive_parse(path,test_index,test_index_lookup) - print(path) local att = lfs.attributes(path) if att.mode=="directory" then for path2 in lfs.dir(path) do @@ -85,9 +86,9 @@ local function recursive_parse(path,test_index,test_index_lookup) recursive_parse(path.."/"..path2,test_index,test_index_lookup) end end - elseif att.mode=="file" then + elseif att.mode=="file" and path:match("%.lua$") then local tests, tests_lookup, prelude = parse_test(path) - if tests then + if tests then test_index[#test_index+1] = {tests=tests, lookup=tests_lookup, prelude=prelude} test_index_lookup[path] = #test_index end @@ -109,25 +110,90 @@ local function index_tests(paths) return test_index, test_index_lookup end +--- Build the string containing the chunk of a single test, including name and +-- description. +-- @param test table containing a test's name, description and code +-- @return string containing the code snippet for the test, including comments. +local function build_codestring(test) + return tconcat({ + "--- ", test.name, + "\n--", tconcat(test.description,"\n--"), "\n", + tconcat(test.code,"\n") + }) +end + --- Extract a test into a directory ---@param test the test table returned by parse, containing name, description, tags, code ---@param fn string containing filename where the test should be extracted (default:os.tmpname()) ---@return filename to where the test was extracted +-- @param test the test table returned by parse, containing name, description, tags, code +-- @param fn string containing filename where the test should be extracted (default:os.tmpname()) +-- @return filename to where the test was extracted local function extract_test(test,fn) fn = fn or os.tmpname() local f = io.open(fn,"w") if not f then error("Could not write to file "..fn) end - f:write("--- ",test.name,"\n") - f:write("--",tconcat(test.description,"\n--"),"\n") - f:write(tconcat(test.code,"\n")) + f:write(build_codestring(test)) f:close() return fn end +--- Run a single test, possibly externally with luajitcmd. +-- @param test: single test object containing name, description, tags, code. +-- @param luajitcmd string containing the luajit command to run external tests. +-- If luajitcmd is defined, the test is extracted into a file and run externally. +-- If left empty, the test is run internally with pcall. +-- @return true (pass) or false (fail) +-- @return msg error message in case of failure +local function run_single_test(test,luajitcmd) + if luajitcmd then + local fn = extract_test(test) + local ret = os.execute(luajitcmd.." "..fn) + return ret==0 + end + local code = build_codestring(test) + local load_ok, load_res = pcall(loadstring,code) + if load_ok then + return pcall(load_res) + else + return load_ok, load_res + end +end + +-- Recursively run tests in paths. +-- @param paths array of paths to recursively run tests in. +-- @param luajitcmd string containing the luajit command to run external tests. +-- If luajitcmd is defined, the test is extracted into a file and run externally. +-- If left empty, the test is run internally with pcall. +-- @return number of passed tests +-- @return number of failed tests +-- @return array of failed tests +-- @return array of corresponding error messages +local function run_tests(paths,luajitcmd) + local pass, fail = 0,0 + local failed_tests = {} + local errors = {} + local test_index = index_tests(paths) + for i,test_block in ipairs(test_index) do + -- key 0 is the prelude block. + for j=0,#test_block.tests do + local test = test_block.tests[j] + local ok, res = run_single_test(test) + if ok then + pass = pass+1 + else + fail = fail+1 + failed_tests[#failed_tests+1] = test + errors[#errors+1] = res + end + end + end + return pass, fail, failed_tests, errors +end + return { parse = parse_test, index = index_tests, extract = extract_test, + run_single = run_single_test, + run = run_tests, } From 639480bc6dc03918d4585231abf0280cefa996eb Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Sun, 21 Feb 2016 23:47:43 +0100 Subject: [PATCH 05/68] Add filter() to tester module for filtering tags Add utility function check_tags(). Remove lookup-related return values. Simplify structure of test_index. Improve error in recursive_path(). run_tests() now accepts a test_index. --- tester.lua | 94 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 34 deletions(-) diff --git a/tester.lua b/tester.lua index 775de13b3e..c762ea238d 100644 --- a/tester.lua +++ b/tester.lua @@ -23,11 +23,9 @@ end --- Parser for the tests. -- @param fn string containing a filename (fullpath) -- @return array containing test specs (name, code, description, tags) --- @return lookup table for tests --- @return prelude table containing prelude code, description and tags. local function parse_test(fn) local tests = {} - local lookup_tests = {} + local lookup = {} local prelude = { name = "prelude of "..fn, fn = fn, @@ -37,17 +35,15 @@ local function parse_test(fn) } local current_test = prelude local function store_test() - if current_test~=prelude then - tests[#tests+1] = current_test - lookup_tests[current_test.name] = #tests - end + tests[#tests+1] = current_test + lookup[current_test.name] = #tests end for line in io.lines(fn) do if line:match("^%-%-%-") then -- Next test is reached store_test() local testname = line:match("^%-%-%-%s*(.*)$") - if lookup_tests[testname] then + if lookup[testname] then error("Test "..testname.." is defined twice in the same file. Please give the tests unique names.") end -- Add current test to the tests table and start new current test table. @@ -69,45 +65,37 @@ local function parse_test(fn) end end store_test() - tests[0] = prelude - return tests, lookup_tests + return tests end -- Recursively parse the path and store the tests in test_index -- @param path string containing a path to a file or directory --- @param test_index array containing the tables with {tests,lookup,prelude} --- @param test_index_lookup lookup table containing keys = paths of the test --- files and values = respective indices in test_index -local function recursive_parse(path,test_index,test_index_lookup) - local att = lfs.attributes(path) +-- @param test_index array containing the tables with tests per file +local function recursive_parse(path,test_index) + local att, err = lfs.attributes(path) + if not att then + error("Could not parse "..path..": "..err) + end if att.mode=="directory" then for path2 in lfs.dir(path) do if path2~=".." and path2~="." then - recursive_parse(path.."/"..path2,test_index,test_index_lookup) + recursive_parse(path.."/"..path2,test_index) end end elseif att.mode=="file" and path:match("%.lua$") then - local tests, tests_lookup, prelude = parse_test(path) - if tests then - test_index[#test_index+1] = {tests=tests, lookup=tests_lookup, prelude=prelude} - test_index_lookup[path] = #test_index - end + test_index[#test_index+1] = parse_test(path) end end --- Walk the directory tree and index tests. -- @param paths array of paths that should be indexed. --- @return array of tables containing { tests, lookup, prelude } as returned by --- parse --- @return lookup table containing keys = paths of the test files and values = --- respective indices in test_index +-- @return array of tables containing tests returned by parse local function index_tests(paths) local test_index = {} - local test_index_lookup = {} for _,path in ipairs(paths) do - recursive_parse(path,test_index,test_index_lookup) + recursive_parse(path,test_index) end - return test_index, test_index_lookup + return test_index end --- Build the string containing the chunk of a single test, including name and @@ -159,7 +147,7 @@ local function run_single_test(test,luajitcmd) end end --- Recursively run tests in paths. +--- Recursively run tests in paths. -- @param paths array of paths to recursively run tests in. -- @param luajitcmd string containing the luajit command to run external tests. -- If luajitcmd is defined, the test is extracted into a file and run externally. @@ -168,15 +156,12 @@ end -- @return number of failed tests -- @return array of failed tests -- @return array of corresponding error messages -local function run_tests(paths,luajitcmd) +local function run_tests(test_index,luajitcmd) local pass, fail = 0,0 local failed_tests = {} local errors = {} - local test_index = index_tests(paths) for i,test_block in ipairs(test_index) do - -- key 0 is the prelude block. - for j=0,#test_block.tests do - local test = test_block.tests[j] + for j,test in ipairs(test_block) do local ok, res = run_single_test(test) if ok then pass = pass+1 @@ -190,10 +175,51 @@ local function run_tests(paths,luajitcmd) return pass, fail, failed_tests, errors end +--- Check whether tags are in tags_inc and none are in tags_exc. +-- @param tags Array of tags to test +-- @param tags_inc Array of tags to include +-- @param tags_exc Array of tags to exclude +local function check_tags(tags,tags_inc,tags_exc) + local include = false + for _,tag_inc in ipairs(tags_inc) do + if tags[tag_inc] then + include = true + break + end + end + if not include then return false end + for _,tag_exc in ipairs(tags_exc) do + if tags[tag_exc] then + return false + end + end + return true +end + +--- Select tests with tags_inc without tags_exc. +-- @param test_index array of test_blocks +-- @param tags_inc array of tags to include +-- @param tags_exc array of tags to exclude +local function filter_tests(test_index,tags_inc,tags_exc) + local tests_filtered = {} + for i,test_block in ipairs(test_index) do + local tests_i + for j, test in ipairs(test_block) do + if check_tags(test.tags,tags_inc,tags_exc) then + tests_i = tests_i or {} + tests_i[#tests_i+1]= test + end + end + tests_filtered[#tests_filtered+1] = tests_i + end + return tests_filtered +end + return { parse = parse_test, index = index_tests, extract = extract_test, run_single = run_single_test, run = run_tests, + filter = filter_tests, } From af54fa1304d262df6f4b971a1eb993edfd82f24d Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Mon, 22 Feb 2016 00:44:00 +0100 Subject: [PATCH 06/68] Add verbose option to run() and run_single() Fix default include behaviour for tags Fix extension for tmp filenames --- tester.lua | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/tester.lua b/tester.lua index c762ea238d..d984f5807f 100644 --- a/tester.lua +++ b/tester.lua @@ -115,7 +115,7 @@ end -- @param fn string containing filename where the test should be extracted (default:os.tmpname()) -- @return filename to where the test was extracted local function extract_test(test,fn) - fn = fn or os.tmpname() + fn = fn or os.tmpname()..".lua" local f = io.open(fn,"w") if not f then error("Could not write to file "..fn) @@ -126,13 +126,14 @@ local function extract_test(test,fn) end --- Run a single test, possibly externally with luajitcmd. --- @param test: single test object containing name, description, tags, code. +-- @param test single test object containing name, description, tags, code. +-- @param verbose boolean indicating verbosity -- @param luajitcmd string containing the luajit command to run external tests. -- If luajitcmd is defined, the test is extracted into a file and run externally. -- If left empty, the test is run internally with pcall. -- @return true (pass) or false (fail) -- @return msg error message in case of failure -local function run_single_test(test,luajitcmd) +local function run_single_test(test,verbose,luajitcmd) if luajitcmd then local fn = extract_test(test) local ret = os.execute(luajitcmd.." "..fn) @@ -141,14 +142,23 @@ local function run_single_test(test,luajitcmd) local code = build_codestring(test) local load_ok, load_res = pcall(loadstring,code) if load_ok then - return pcall(load_res) + local ok, res = pcall(load_res) + if verbose then + io.write(ok and "PASS " or "FAIL ",test.name,"\n") + if not ok then io.write(" "..(res or "(no error message)"),"\n") end + end + return ok, res else + if verbose then + io.write("SYNT ",test.name,load_res or "(no error message)","\n") + end return load_ok, load_res end end --- Recursively run tests in paths. -- @param paths array of paths to recursively run tests in. +-- @param verbose boolean indicating verbosity -- @param luajitcmd string containing the luajit command to run external tests. -- If luajitcmd is defined, the test is extracted into a file and run externally. -- If left empty, the test is run internally with pcall. @@ -156,13 +166,13 @@ end -- @return number of failed tests -- @return array of failed tests -- @return array of corresponding error messages -local function run_tests(test_index,luajitcmd) +local function run_tests(test_index,verbose,luajitcmd) local pass, fail = 0,0 local failed_tests = {} local errors = {} for i,test_block in ipairs(test_index) do for j,test in ipairs(test_block) do - local ok, res = run_single_test(test) + local ok, res = run_single_test(test,verbose,luajitcmd) if ok then pass = pass+1 else @@ -176,11 +186,14 @@ local function run_tests(test_index,luajitcmd) end --- Check whether tags are in tags_inc and none are in tags_exc. +-- If tags_inc is empty, default inclusion is true. -- @param tags Array of tags to test -- @param tags_inc Array of tags to include -- @param tags_exc Array of tags to exclude +-- @return boolean indicating inclusion local function check_tags(tags,tags_inc,tags_exc) local include = false + if #tags_inc==0 then include = true end for _,tag_inc in ipairs(tags_inc) do if tags[tag_inc] then include = true @@ -197,6 +210,7 @@ local function check_tags(tags,tags_inc,tags_exc) end --- Select tests with tags_inc without tags_exc. +-- If tags_inc is empty, select all tests by default. -- @param test_index array of test_blocks -- @param tags_inc array of tags to include -- @param tags_exc array of tags to exclude From b0b3a201ad4a95de3885bd8c4372adb5963ce043 Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Mon, 22 Feb 2016 00:47:41 +0100 Subject: [PATCH 07/68] Add test.lua for running and filtering tests. --- test.lua | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 test.lua diff --git a/test.lua b/test.lua new file mode 100644 index 0000000000..8b51591ac3 --- /dev/null +++ b/test.lua @@ -0,0 +1,60 @@ +local t = require("tester") +local tconcat, iowrite = table.concat, io.write +local tagpat_inc = "^%+([A-Za-z_][A-Za-z0-9_]*)$" +local tagpat_exc = "^%-([A-Za-z_][A-Za-z0-9_]*)$" +local args = {...} +local paths, tags_inc, tags_exc = {}, {}, {} +local verbose = false + +local function print_help() + io.write[[ +Usage: luajit test.lua path1 path2 +tagtofilter +orthistag -tagtoexclude -andthistag +Options: + path Recursively include tests in path. Default: test + +tag_inc Include only tests with tag tag_inc. Multiple include tags are ORed. + -tag_exc Exclude tests with tag tag_exc. + --help Print this help message. + --verbose Explicitly list all tests. +]] +end + +for _,arg in ipairs(args) do + if not arg:match("^[+-]") then + paths[#paths+1]=arg + elseif arg:match(tagpat_inc) then + tags_inc[#tags_inc+1]=arg:match(tagpat_inc) + elseif arg:match(tagpat_exc) then + tags_exc[#tags_exc+1]=arg:match(tagpat_exc) + elseif arg:match("%-%-verbose") then + verbose = true + elseif arg:match("%-%-help") then + print_help() + return + end +end + +if #paths==0 then paths[1]="test" end +iowrite("Running tests in \"",tconcat(paths,"\",\""),"\"") +if #tags_inc > 0 then + iowrite(" with tags ",tconcat(tags_inc,",")) +end +if #tags_exc > 0 then + iowrite(" but without tags ",tconcat(tags_exc,",")) +end +iowrite("\n") + +local index = t.index(paths) +index = t.filter(index,tags_inc,tags_exc) +local pass, fail, failed_tests, errors = t.run(index,verbose) + +iowrite("Passed ",pass,"/",pass+fail," tests.\n") +if fail==0 then return end + +iowrite("Failed tests:\n") +for i=1,fail do + iowrite(string.rep("-",72),"\n") + iowrite("Name: ",failed_tests[i].name,"\n") + iowrite("Error: ",errors[i] or "(no error message)","\n") + iowrite("Filename: ",t.extract(failed_tests[i]),"\n") +end + From 24d2b97879890e4c7b3bc6baa02fac6bc4164848 Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Mon, 22 Feb 2016 00:48:45 +0100 Subject: [PATCH 08/68] Move some tests into new structure and adapt comments to test runner. --- test/{misc => libs/core}/select.lua | 11 +++++ .../table/insert.lua} | 2 + .../table_misc.lua => libs/table/misc.lua} | 41 +++++-------------- .../table/remove.lua} | 3 ++ test/libs_ext/table.lua | 37 +++++++++++++++++ 5 files changed, 64 insertions(+), 30 deletions(-) rename test/{misc => libs/core}/select.lua (80%) rename test/{misc/table_insert.lua => libs/table/insert.lua} (88%) rename test/{misc/table_misc.lua => libs/table/misc.lua} (80%) rename test/{misc/table_remove.lua => libs/table/remove.lua} (75%) create mode 100644 test/libs_ext/table.lua diff --git a/test/misc/select.lua b/test/libs/core/select.lua similarity index 80% rename from test/misc/select.lua rename to test/libs/core/select.lua index 4d9cda853b..5431609072 100644 --- a/test/misc/select.lua +++ b/test/libs/core/select.lua @@ -1,4 +1,8 @@ +-- Tests for the basic function select(). +-- +select +fast +--- select # +-- Test whether select("#", 3, 4) returns the correct number of arguments. do local x = 0 for i=1,100 do @@ -7,6 +11,8 @@ do assert(x == 200) end +--- select modf +-- Test whether select("#", func()) also works with func returning multiple values do local x = 0 for i=1,100 do @@ -15,6 +21,7 @@ do assert(x == 200) end +--- select 1 do local x = 0 for i=1,100 do @@ -23,6 +30,7 @@ do assert(x == 5050) end +--- select 2 do local x, y = 0, 0 for i=1,100 do @@ -33,6 +41,7 @@ do assert(x == 5050 and y == 6050) end +--- select vararg # do local function f(a, ...) local x = 0 @@ -50,6 +59,7 @@ do end end +--- select vararg i do local function f(a, ...) local x = 0 @@ -68,6 +78,7 @@ do end end +--- select vararg 4 do local function f(a, ...) local x = 0 diff --git a/test/misc/table_insert.lua b/test/libs/table/insert.lua similarity index 88% rename from test/misc/table_insert.lua rename to test/libs/table/insert.lua index 28a094dae9..d4d617cc83 100644 --- a/test/misc/table_insert.lua +++ b/test/libs/table/insert.lua @@ -2,6 +2,7 @@ local tinsert = table.insert local assert = assert +--- table.insert(t,i) do local t = {} for i=1,100 do t[i] = i end @@ -9,6 +10,7 @@ do assert(#t == 200 and t[100] == 100 and t[200] == 100) end +--- table.insert(t,i,i) do local t = {} for i=1,200 do t[i] = i end diff --git a/test/misc/table_misc.lua b/test/libs/table/misc.lua similarity index 80% rename from test/misc/table_misc.lua rename to test/libs/table/misc.lua index 9362b254ea..ba6375172f 100644 --- a/test/misc/table_misc.lua +++ b/test/libs/table/misc.lua @@ -1,5 +1,5 @@ - --- ABC elim +-- ABC elim +-- +opt +abc do local s, t = {}, {} for i=1,100 do t[i] = 1 end @@ -9,7 +9,8 @@ do for i=1,n do s[i][i] = i end end --- TSETM +--- TSETM +-- Initialize table with multiple return values do local function f(a,b,c) return a,b,c @@ -41,25 +42,17 @@ do 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 --- table.new -do - local tnew = require("table.new") - local x, y - for i=1,100 do - x = tnew(100, 30) - if i == 90 then y = x end - end - assert(x ~= y) -end - --- table.concat +--- table.concat do local t = {a=1,b=2,c=3,d=4,e=5} t[1] = 4 @@ -82,7 +75,7 @@ do assert(q[93] == "9x8x7") end --- table.concat must inhibit CSE and DSE +--- table.concat must inhibit CSE and DSE do local t = {1,2,3} local y, z @@ -95,6 +88,7 @@ do assert(z == "1x100x3") end +--- table.concat must inhibit CSE and DSE 2 do local y for i=1,100 do @@ -106,6 +100,7 @@ do assert(y == "1x4x3") end +--- table.concat must inhibit CSE and DSE 3 do local t = {[0]={}, {}, {}, {}} for i=1,30 do @@ -115,17 +110,3 @@ do end end --- table.pack -if os.getenv("LUA52") then - local t - - t = table.pack() - assert(t.n == 0 and t[0] == nil and t[1] == nil) - - t = table.pack(99) - assert(t.n == 1 and t[0] == nil and t[1] == 99 and t[2] == nil) - - t = table.pack(nil, nil, nil) - assert(t.n == 3 and t[0] == nil and t[1] == nil and t[2] == nil and t[3] == nil and t[4] == nil) -end - diff --git a/test/misc/table_remove.lua b/test/libs/table/remove.lua similarity index 75% rename from test/misc/table_remove.lua rename to test/libs/table/remove.lua index d8cdd19dcb..67a594b206 100644 --- a/test/misc/table_remove.lua +++ b/test/libs/table/remove.lua @@ -2,6 +2,7 @@ local tremove = table.remove local assert = assert +--- table.remove(t) removes correct entries do local t = {} for i=1,200 do t[i] = i end @@ -9,6 +10,7 @@ do assert(#t == 100 and t[100] == 100) end +--- table.remove(t) returns the removed entry do local t = {} for i=1,200 do t[i] = i end @@ -16,6 +18,7 @@ do assert(#t == 100 and t[100] == 100) end +--- table.remove(t, 1) removes and returns the first entry do local t = {} for i=1,200 do t[i] = i end diff --git a/test/libs_ext/table.lua b/test/libs_ext/table.lua new file mode 100644 index 0000000000..03c221912d --- /dev/null +++ b/test/libs_ext/table.lua @@ -0,0 +1,37 @@ +--- table.new +do + local tnew = require("table.new") + local x, y + for i=1,100 do + x = tnew(100, 30) + if i == 90 then y = x end + end + assert(x ~= y) +end + +--- table.pack() +-- +lua52 +do + if os.getenv("LUA52") then + local t = table.pack() + assert(t.n == 0 and t[0] == nil and t[1] == nil) + end +end + +--- table.pack(99) +-- +lua52 +do + if os.getenv("LUA52") then + local t = table.pack(99) + assert(t.n == 1 and t[0] == nil and t[1] == 99 and t[2] == nil) + end +end + +--- table.pack(nils) +-- +lua52 +do + if os.getenv("LUA52") then + local t = table.pack(nil, nil, nil) + assert(t.n == 3 and t[0] == nil and t[1] == nil and t[2] == nil and t[3] == nil and t[4] == nil) + end +end From 5f331e709847087ede9cf7ffba0481971cbe67e2 Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Mon, 22 Feb 2016 00:55:21 +0100 Subject: [PATCH 09/68] Avoid string.rep in test.lua --- test.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test.lua b/test.lua index 8b51591ac3..ef22f7c0bf 100644 --- a/test.lua +++ b/test.lua @@ -52,7 +52,7 @@ if fail==0 then return end iowrite("Failed tests:\n") for i=1,fail do - iowrite(string.rep("-",72),"\n") + iowrite("----------------------------------------------------------") iowrite("Name: ",failed_tests[i].name,"\n") iowrite("Error: ",errors[i] or "(no error message)","\n") iowrite("Filename: ",t.extract(failed_tests[i]),"\n") From 0d975fa2e0709ee29f4ca8dd3bb01f20f1d39616 Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Sat, 27 Feb 2016 21:19:28 +0100 Subject: [PATCH 10/68] Clean up test script (args, tag patterns) --- test.lua | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/test.lua b/test.lua index ef22f7c0bf..ae3d8ce57d 100644 --- a/test.lua +++ b/test.lua @@ -1,10 +1,10 @@ local t = require("tester") local tconcat, iowrite = table.concat, io.write -local tagpat_inc = "^%+([A-Za-z_][A-Za-z0-9_]*)$" -local tagpat_exc = "^%-([A-Za-z_][A-Za-z0-9_]*)$" -local args = {...} +local tagpat_inc = "^%+([_%a][_%w]*)$" +local tagpat_exc = "^%-([_%a][_%w]*)$" local paths, tags_inc, tags_exc = {}, {}, {} local verbose = false +local arg = arg or {...} local function print_help() io.write[[ @@ -18,16 +18,16 @@ Options: ]] end -for _,arg in ipairs(args) do - if not arg:match("^[+-]") then - paths[#paths+1]=arg - elseif arg:match(tagpat_inc) then - tags_inc[#tags_inc+1]=arg:match(tagpat_inc) - elseif arg:match(tagpat_exc) then - tags_exc[#tags_exc+1]=arg:match(tagpat_exc) - elseif arg:match("%-%-verbose") then +for _,a in ipairs(arg) do + if not a:match("^[+-]") then + paths[#paths+1]=a + elseif a:match(tagpat_inc) then + tags_inc[#tags_inc+1]=a:match(tagpat_inc) + elseif a:match(tagpat_exc) then + tags_exc[#tags_exc+1]=a:match(tagpat_exc) + elseif a:match("%-%-verbose") then verbose = true - elseif arg:match("%-%-help") then + elseif a:match("%-%-help") then print_help() return end From 885905822525b418fb5c750d79218c5cc5b55760 Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Sat, 27 Feb 2016 21:47:10 +0100 Subject: [PATCH 11/68] Implement @key: value matching in parse() function of tester module --- tester.lua | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/tester.lua b/tester.lua index d984f5807f..30b341197c 100644 --- a/tester.lua +++ b/tester.lua @@ -20,6 +20,14 @@ local function tags_from_path(fn) return tags end +-- Patterns for parsing out test data. +local identifier_pat = "([_%a][_%w]*)" +local delim_pat = "^%-%-%-" +local name_pat = delim_pat.."%s*(.*)" +local desc_pat = "^%-%-(.*)" +local tag_pat = "%+"..identifier_pat +local kv_pat = "@"..identifier_pat.."%s*:%s*([^@]*)" + --- Parser for the tests. -- @param fn string containing a filename (fullpath) -- @return array containing test specs (name, code, description, tags) @@ -39,10 +47,10 @@ local function parse_test(fn) lookup[current_test.name] = #tests end for line in io.lines(fn) do - if line:match("^%-%-%-") then + if line:match(delim_pat) then -- Next test is reached store_test() - local testname = line:match("^%-%-%-%s*(.*)$") + local testname = line:match(name_pat) if lookup[testname] then error("Test "..testname.." is defined twice in the same file. Please give the tests unique names.") end @@ -54,12 +62,15 @@ local function parse_test(fn) tags = cp(prelude.tags), code = cp(prelude.code), } - elseif line:match("^%-%-") and #current_test.code==#prelude.code then - -- Continue building current test description (and possibly tags) - current_test.description[#current_test.description+1] = line:match("^%-%-%s*(.*)$") - for tag in line:gmatch("%+([A-Za-z_][A-Za-z0-9_]*)") do + elseif line:match(desc_pat) and #current_test.code==#prelude.code then + -- Continue building current test description, and possibly extract tags and key-value pairs + current_test.description[#current_test.description+1] = line:match(desc_pat) + for tag in line:gmatch(tag_pat) do current_test.tags[tag] = true end + for key,value in line:gmatch(kv_pat) do + current_test[key] = value:gsub("%s*$","") + end else current_test.code[#current_test.code+1] = line end From 16b32934688148d89a8f9b2d4cde60228a000de4 Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Sat, 27 Feb 2016 21:51:47 +0100 Subject: [PATCH 12/68] Don't print an empty description in build_codestring() in tester module --- tester.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tester.lua b/tester.lua index 30b341197c..f7b98c0af5 100644 --- a/tester.lua +++ b/tester.lua @@ -116,7 +116,8 @@ end local function build_codestring(test) return tconcat({ "--- ", test.name, - "\n--", tconcat(test.description,"\n--"), "\n", + #test.description>0 and "\n--" or "", + tconcat(test.description,"\n--"), "\n", tconcat(test.code,"\n") }) end From 765714f63f7594b11e985d482fc8b69d8669889b Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Sat, 27 Feb 2016 21:57:54 +0100 Subject: [PATCH 13/68] Put @key: value pairs in separate attributes table in parse() --- tester.lua | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tester.lua b/tester.lua index f7b98c0af5..97961ecd8d 100644 --- a/tester.lua +++ b/tester.lua @@ -26,7 +26,7 @@ local delim_pat = "^%-%-%-" local name_pat = delim_pat.."%s*(.*)" local desc_pat = "^%-%-(.*)" local tag_pat = "%+"..identifier_pat -local kv_pat = "@"..identifier_pat.."%s*:%s*([^@]*)" +local attrib_pat = "@"..identifier_pat.."%s*:%s*([^@]*)" --- Parser for the tests. -- @param fn string containing a filename (fullpath) @@ -40,6 +40,7 @@ local function parse_test(fn) description = {}, code = {}, tags = tags_from_path(fn), + attributes = {}, } local current_test = prelude local function store_test() @@ -61,6 +62,7 @@ local function parse_test(fn) description = cp(prelude.description), tags = cp(prelude.tags), code = cp(prelude.code), + attributes = cp(prelude.attributes), } elseif line:match(desc_pat) and #current_test.code==#prelude.code then -- Continue building current test description, and possibly extract tags and key-value pairs @@ -68,8 +70,8 @@ local function parse_test(fn) for tag in line:gmatch(tag_pat) do current_test.tags[tag] = true end - for key,value in line:gmatch(kv_pat) do - current_test[key] = value:gsub("%s*$","") + for key,value in line:gmatch(attrib_pat) do + current_test.attributes[key] = value:gsub("%s*$","") end else current_test.code[#current_test.code+1] = line From 14bfa87fa8253dc1c61d2fd6340f51d17ef49e48 Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Sat, 27 Feb 2016 23:11:24 +0100 Subject: [PATCH 14/68] Add --runcmd='x' option to test runner --- test.lua | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test.lua b/test.lua index ae3d8ce57d..e5a51838db 100644 --- a/test.lua +++ b/test.lua @@ -5,7 +5,7 @@ local tagpat_exc = "^%-([_%a][_%w]*)$" local paths, tags_inc, tags_exc = {}, {}, {} local verbose = false local arg = arg or {...} - +local runcmd local function print_help() io.write[[ Usage: luajit test.lua path1 path2 +tagtofilter +orthistag -tagtoexclude -andthistag @@ -15,6 +15,9 @@ Options: -tag_exc Exclude tests with tag tag_exc. --help Print this help message. --verbose Explicitly list all tests. + --runcmd='cmd' + If runcmd is defined, Command to run the tests with, externally, e.g. + --runcmd="luajit -joff" ]] end @@ -30,6 +33,8 @@ for _,a in ipairs(arg) do elseif a:match("%-%-help") then print_help() return + elseif a:match("%-%-runcmd") then + runcmd = a:match("%-%-runcmd=(.*)") end end @@ -45,7 +50,7 @@ iowrite("\n") local index = t.index(paths) index = t.filter(index,tags_inc,tags_exc) -local pass, fail, failed_tests, errors = t.run(index,verbose) +local pass, fail, failed_tests, errors = t.run(index,verbose,runcmd) iowrite("Passed ",pass,"/",pass+fail," tests.\n") if fail==0 then return end From a6e5102927af20584a42246a60989a362efacdc3 Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Sat, 27 Feb 2016 23:19:51 +0100 Subject: [PATCH 15/68] Capture stderr when tests are run externally in run_single() I.e. when runcmd is defined. Also print PASS/FAIL info for external runs in verbose mode. --- tester.lua | 63 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/tester.lua b/tester.lua index 97961ecd8d..ebced127eb 100644 --- a/tester.lua +++ b/tester.lua @@ -124,7 +124,7 @@ local function build_codestring(test) }) end ---- Extract a test into a directory +--- Extract a test to a file. -- @param test the test table returned by parse, containing name, description, tags, code -- @param fn string containing filename where the test should be extracted (default:os.tmpname()) -- @return filename to where the test was extracted @@ -139,54 +139,67 @@ local function extract_test(test,fn) return fn end ---- Run a single test, possibly externally with luajitcmd. +--- Run a single test, possibly externally with runcmd. -- @param test single test object containing name, description, tags, code. -- @param verbose boolean indicating verbosity --- @param luajitcmd string containing the luajit command to run external tests. --- If luajitcmd is defined, the test is extracted into a file and run externally. +-- @param runcmd string containing the luajit command to run external tests. +-- If runcmd is defined, the test is extracted into a file and run externally. -- If left empty, the test is run internally with pcall. +-- @param workdir string containing the directory where runcmd is run and +-- the test is extracted. -- @return true (pass) or false (fail) -- @return msg error message in case of failure -local function run_single_test(test,verbose,luajitcmd) - if luajitcmd then - local fn = extract_test(test) - local ret = os.execute(luajitcmd.." "..fn) - return ret==0 - end - local code = build_codestring(test) - local load_ok, load_res = pcall(loadstring,code) - if load_ok then - local ok, res = pcall(load_res) - if verbose then - io.write(ok and "PASS " or "FAIL ",test.name,"\n") - if not ok then io.write(" "..(res or "(no error message)"),"\n") end +local function run_single_test(test,verbose,runcmd,workdir) + local ok, res + if runcmd then + workdir = workdir or "." + local fn = extract_test(test,workdir.."/current_test.lua") + local fnerr = fn:gsub("%.lua$",".err") + local status = os.execute(runcmd.." "..fn.." 2> "..fnerr) + ok = status==0 + if not ok then + local ferr = io.open(fnerr) + if ferr then + res = ferr:read("*a") + ferr:close() + end end - return ok, res else - if verbose then - io.write("SYNT ",test.name,load_res or "(no error message)","\n") + local code = build_codestring(test) + local load_ok, load_res = pcall(loadstring,code) + if not load_ok then + if verbose then + io.write("SYNT ",test.name,"\n ",load_res or "(no error message)","\n") + end + return load_ok, load_res + else + ok, res = pcall(load_res) end - return load_ok, load_res end + if verbose then + io.write(ok and "PASS " or "FAIL ",test.name,"\n") + if not ok then io.write(" "..(res or "(no error message)"),"\n") end + end + return ok, res end --- Recursively run tests in paths. -- @param paths array of paths to recursively run tests in. -- @param verbose boolean indicating verbosity --- @param luajitcmd string containing the luajit command to run external tests. --- If luajitcmd is defined, the test is extracted into a file and run externally. +-- @param runcmd string containing the luajit command to run external tests. +-- If runcmd is defined, the test is extracted into a file and run externally. -- If left empty, the test is run internally with pcall. -- @return number of passed tests -- @return number of failed tests -- @return array of failed tests -- @return array of corresponding error messages -local function run_tests(test_index,verbose,luajitcmd) +local function run_tests(test_index,verbose,runcmd) local pass, fail = 0,0 local failed_tests = {} local errors = {} for i,test_block in ipairs(test_index) do for j,test in ipairs(test_block) do - local ok, res = run_single_test(test,verbose,luajitcmd) + local ok, res = run_single_test(test,verbose,runcmd) if ok then pass = pass+1 else From 91cb29bc9db812014fae9ef04207622192c0785c Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Sun, 28 Feb 2016 00:38:24 +0100 Subject: [PATCH 16/68] Add workdir argument to extract() in tester module --- tester.lua | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/tester.lua b/tester.lua index ebced127eb..77b61164fa 100644 --- a/tester.lua +++ b/tester.lua @@ -125,11 +125,19 @@ local function build_codestring(test) end --- Extract a test to a file. --- @param test the test table returned by parse, containing name, description, tags, code --- @param fn string containing filename where the test should be extracted (default:os.tmpname()) +-- @param test the test table returned by parse, containing name, description, +-- tags, code and attributes +-- @param workdir string containing the directory where the test is extracted; +-- the directory is created if needed (default: ".") +-- @param fn string containing filename where the test should be extracted +-- (default: test_fn__test_name.lua) -- @return filename to where the test was extracted -local function extract_test(test,fn) - fn = fn or os.tmpname()..".lua" +local function extract_test(test,workdir,fn) + fn = fn or (test.fn:gsub("%.lua$","").."__"..test.name):gsub("[^%a]","_")..".lua" + if workdir then + lfs.mkdir(workdir) + fn = workdir.."/"..fn + end local f = io.open(fn,"w") if not f then error("Could not write to file "..fn) @@ -153,7 +161,7 @@ local function run_single_test(test,verbose,runcmd,workdir) local ok, res if runcmd then workdir = workdir or "." - local fn = extract_test(test,workdir.."/current_test.lua") + local fn = extract_test(test,workdir,"current_test.lua") local fnerr = fn:gsub("%.lua$",".err") local status = os.execute(runcmd.." "..fn.." 2> "..fnerr) ok = status==0 From 82586b19f34242c85758970751e13d11ab3e583c Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Sun, 28 Feb 2016 00:38:58 +0100 Subject: [PATCH 17/68] Improve filenames of extracted tests and error reporting in test runner --- test.lua | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/test.lua b/test.lua index e5a51838db..9ea05ed462 100644 --- a/test.lua +++ b/test.lua @@ -1,3 +1,9 @@ +-- test.lua +-- +-- Recursively run tests in the given paths, filtered by the given tags. +-- Failed tests are extracted to the directory "failed_tests", and error +-- details are appended. + local t = require("tester") local tconcat, iowrite = table.concat, io.write local tagpat_inc = "^%+([_%a][_%w]*)$" @@ -55,11 +61,26 @@ local pass, fail, failed_tests, errors = t.run(index,verbose,runcmd) iowrite("Passed ",pass,"/",pass+fail," tests.\n") if fail==0 then return end +local function report_fail(test,err) + local extfn = t.extract(test,"failed_tests") + iowrite("----------------------------------------------------------", + "\nname: ",test.name, + "\nerror: ",err or "(no error message)", + "\nsource file: ",test.fn, + "\nextracted to file: ",extfn, + "\n") + -- Append error message for completeness + local extf = io.open(extfn,"a") + if extf then + extf:write("\n--[===[\nTest failed at ",os.date(), + "\nruncmd: ",runcmd or "(internal pcall)", + "\nerror:\n",err or "(no error message)", + "\n]===]\n") + end +end + iowrite("Failed tests:\n") -for i=1,fail do - iowrite("----------------------------------------------------------") - iowrite("Name: ",failed_tests[i].name,"\n") - iowrite("Error: ",errors[i] or "(no error message)","\n") - iowrite("Filename: ",t.extract(failed_tests[i]),"\n") +for i,failed_test in ipairs(failed_tests) do + report_fail(failed_test,errors[i]) end From 1d7aaed648c016109f5756dbbe7e155248b9901e Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Mon, 29 Feb 2016 10:32:09 +0100 Subject: [PATCH 18/68] Moved proposed test runner and examples into 'experimental' directory. --- {test => experimental}/libs/core/select.lua | 0 {test => experimental}/libs/table/insert.lua | 0 {test => experimental}/libs/table/misc.lua | 0 {test => experimental}/libs/table/remove.lua | 0 {test => experimental}/libs_ext/table.lua | 0 test.lua => experimental/test.lua | 0 tester.lua => experimental/tester.lua | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename {test => experimental}/libs/core/select.lua (100%) rename {test => experimental}/libs/table/insert.lua (100%) rename {test => experimental}/libs/table/misc.lua (100%) rename {test => experimental}/libs/table/remove.lua (100%) rename {test => experimental}/libs_ext/table.lua (100%) rename test.lua => experimental/test.lua (100%) rename tester.lua => experimental/tester.lua (100%) diff --git a/test/libs/core/select.lua b/experimental/libs/core/select.lua similarity index 100% rename from test/libs/core/select.lua rename to experimental/libs/core/select.lua diff --git a/test/libs/table/insert.lua b/experimental/libs/table/insert.lua similarity index 100% rename from test/libs/table/insert.lua rename to experimental/libs/table/insert.lua diff --git a/test/libs/table/misc.lua b/experimental/libs/table/misc.lua similarity index 100% rename from test/libs/table/misc.lua rename to experimental/libs/table/misc.lua diff --git a/test/libs/table/remove.lua b/experimental/libs/table/remove.lua similarity index 100% rename from test/libs/table/remove.lua rename to experimental/libs/table/remove.lua diff --git a/test/libs_ext/table.lua b/experimental/libs_ext/table.lua similarity index 100% rename from test/libs_ext/table.lua rename to experimental/libs_ext/table.lua diff --git a/test.lua b/experimental/test.lua similarity index 100% rename from test.lua rename to experimental/test.lua diff --git a/tester.lua b/experimental/tester.lua similarity index 100% rename from tester.lua rename to experimental/tester.lua From 581a474d757bcc559f6a5787c4fbf5e59e8c5514 Mon Sep 17 00:00:00 2001 From: Lesley De Cruz Date: Mon, 29 Feb 2016 10:36:05 +0100 Subject: [PATCH 19/68] Put subtests in 'test' dir --- experimental/{ => test}/libs/core/select.lua | 0 experimental/{ => test}/libs/table/insert.lua | 0 experimental/{ => test}/libs/table/misc.lua | 0 experimental/{ => test}/libs/table/remove.lua | 0 experimental/{ => test}/libs_ext/table.lua | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename experimental/{ => test}/libs/core/select.lua (100%) rename experimental/{ => test}/libs/table/insert.lua (100%) rename experimental/{ => test}/libs/table/misc.lua (100%) rename experimental/{ => test}/libs/table/remove.lua (100%) rename experimental/{ => test}/libs_ext/table.lua (100%) diff --git a/experimental/libs/core/select.lua b/experimental/test/libs/core/select.lua similarity index 100% rename from experimental/libs/core/select.lua rename to experimental/test/libs/core/select.lua diff --git a/experimental/libs/table/insert.lua b/experimental/test/libs/table/insert.lua similarity index 100% rename from experimental/libs/table/insert.lua rename to experimental/test/libs/table/insert.lua diff --git a/experimental/libs/table/misc.lua b/experimental/test/libs/table/misc.lua similarity index 100% rename from experimental/libs/table/misc.lua rename to experimental/test/libs/table/misc.lua diff --git a/experimental/libs/table/remove.lua b/experimental/test/libs/table/remove.lua similarity index 100% rename from experimental/libs/table/remove.lua rename to experimental/test/libs/table/remove.lua diff --git a/experimental/libs_ext/table.lua b/experimental/test/libs_ext/table.lua similarity index 100% rename from experimental/libs_ext/table.lua rename to experimental/test/libs_ext/table.lua From 488e3fb746782a02229ecfcad2e843376d8d3a6d Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Sun, 3 Apr 2016 21:56:19 +0100 Subject: [PATCH 20/68] Shake things up. --- experimental/test.lua | 86 ---- experimental/test/libs_ext/table.lua | 37 -- experimental/tester.lua | 274 ------------ test/README.md | 110 +++++ test/{misc => bc}/constov.lua | 35 +- test/bc/index | 1 + test/common/expect_error.lua | 16 + test/common/test_runner_canary.lua | 1 + test/computations.lua | 113 +++++ test/index | 6 + test/lang/andor.lua | 61 +++ test/lang/assignment.lua | 46 ++ test/lang/compare.lua | 249 +++++++++++ test/{misc/cat_jit.lua => lang/concat.lua} | 214 +++++---- test/lang/constant/index | 1 + test/lang/constant/number.lua | 12 + test/lang/coroutine.lua | 8 + test/lang/for.lua | 45 ++ test/lang/gc.lua | 30 ++ test/lang/index | 12 + test/lang/modulo.lua | 46 ++ test/lang/self.lua | 19 + test/lang/tail_recursion.lua | 20 + test/lang/upvalue/closure.lua | 84 ++++ test/lang/upvalue/index | 1 + test/lib/base/assert.lua | 33 ++ test/lib/base/error.lua | 43 ++ test/lib/base/getfenv.lua | 13 + test/lib/base/index | 5 + .../libs/core => test/lib/base}/select.lua | 204 ++++----- test/{misc => lib/base}/xpcall_jit.lua | 169 ++++---- test/lib/bit.lua | 98 +++++ test/lib/contents.lua | 151 +++++++ test/lib/coroutine/index | 1 + test/lib/coroutine/yield.lua | 109 +++++ test/{ => lib}/ffi/ffi_arith_ptr.lua | 0 test/{ => lib}/ffi/ffi_bit64.lua | 0 test/{ => lib}/ffi/ffi_bitfield.lua | 0 test/{ => lib}/ffi/ffi_call.lua | 0 test/{ => lib}/ffi/ffi_callback.lua | 0 test/{ => lib}/ffi/ffi_const.lua | 0 test/{ => lib}/ffi/ffi_convert.lua | 0 test/{ => lib}/ffi/ffi_copy_fill.lua | 0 test/{ => lib}/ffi/ffi_enum.lua | 0 test/{ => lib}/ffi/ffi_err.lua | 0 test/{ => lib}/ffi/ffi_gcstep_recursive.lua | 0 test/{ => lib}/ffi/ffi_istype.lua | 0 test/{ => lib}/ffi/ffi_jit_arith.lua | 0 test/{ => lib}/ffi/ffi_jit_array.lua | 0 test/{ => lib}/ffi/ffi_jit_call.lua | 0 test/{ => lib}/ffi/ffi_jit_complex.lua | 0 test/{ => lib}/ffi/ffi_jit_conv.lua | 0 test/{ => lib}/ffi/ffi_jit_misc.lua | 0 test/{ => lib}/ffi/ffi_jit_struct.lua | 0 test/{ => lib}/ffi/ffi_lex_number.lua | 0 test/{ => lib}/ffi/ffi_meta_tostring.lua | 0 test/{ => lib}/ffi/ffi_metatype.lua | 0 test/{ => lib}/ffi/ffi_new.lua | 0 test/{ => lib}/ffi/ffi_nosink.lua | 0 test/{ => lib}/ffi/ffi_parse_array.lua | 0 test/{ => lib}/ffi/ffi_parse_basic.lua | 0 test/{ => lib}/ffi/ffi_parse_cdef.lua | 0 test/{ => lib}/ffi/ffi_parse_struct.lua | 0 test/{ => lib}/ffi/ffi_redir.lua | 0 test/{ => lib}/ffi/ffi_sink.lua | 0 test/{ => lib}/ffi/ffi_tabov.lua | 0 test/{ => lib}/ffi/ffi_type_punning.lua | 0 test/lib/index | 8 + test/lib/math/abs.lua | 16 + test/lib/math/constants.lua | 8 + test/lib/math/index | 3 + test/lib/math/random.lua | 47 ++ .../string_byte.lua => lib/string/byte.lua} | 182 ++++---- test/lib/string/char.lua | 29 ++ .../string_dump.lua => lib/string/dump.lua} | 60 ++- test/lib/string/format/index | 1 + test/lib/string/format/num.lua | 184 ++++++++ test/lib/string/index | 9 + test/lib/string/len.lua | 14 + test/lib/string/lower_upper.lua | 16 + test/lib/string/metatable.lua | 3 + test/lib/string/rep.lua | 13 + test/lib/string/sub.lua | 189 ++++++++ test/lib/table/concat.lua | 55 +++ test/lib/table/index | 6 + .../test/libs => test/lib}/table/insert.lua | 7 +- .../test/libs => test/lib}/table/misc.lua | 60 +-- test/lib/table/new.lua | 11 + test/lib/table/pack.lua | 7 + .../test/libs => test/lib}/table/remove.lua | 11 +- test/lib/table/sort.lua | 27 ++ test/misc/ack.lua | 12 - test/misc/ack_notail.lua | 12 - test/misc/argcheck.lua | 40 -- test/misc/assign_tset_prevnil.lua | 11 - test/misc/assign_tset_tmp.lua | 5 - test/misc/bit_op.lua | 90 ---- test/misc/compare.lua | 232 ---------- test/misc/exit_growstack.lua | 24 - test/misc/exit_jfuncf.lua | 30 -- test/misc/fac.lua | 13 - test/misc/fastfib.lua | 26 -- test/misc/fib.lua | 11 - test/misc/fuse.lua | 8 - test/misc/fwd_hrefk_rollback.lua | 34 -- test/misc/libfuncs.lua | 63 --- test/misc/math_random.lua | 21 - test/misc/modulo.lua | 42 -- test/misc/nsieve.lua | 20 - test/misc/parse_andor.lua | 58 --- test/misc/recsum.lua | 11 - test/misc/recsump.lua | 11 - test/misc/self.lua | 18 - test/misc/snap_gcexit.lua | 16 - test/misc/snap_top.lua | 16 - test/misc/snap_top2.lua | 15 - test/misc/sort.lua | 23 - test/misc/string_char.lua | 28 -- test/misc/string_sub.lua | 60 --- test/misc/string_sub_opt.lua | 109 ----- test/misc/tak.lua | 12 - .../{misc/dse_array.lua => opt/dse/array.lua} | 397 +++++++++-------- .../{misc/dse_field.lua => opt/dse/field.lua} | 147 +++---- test/opt/dse/index | 2 + test/opt/fold/index | 1 + test/{misc => opt/fold}/kfold.lua | 162 +++---- test/opt/fuse.lua | 5 + test/opt/fwd/hrefk_rollback.lua | 32 ++ test/opt/fwd/index | 3 + .../fwd/tnew_tdup.lua} | 147 +++---- .../{misc/fwd_upval.lua => opt/fwd/upval.lua} | 107 +++-- test/opt/index | 6 + test/opt/loop/index | 1 + test/opt/loop/unroll.lua | 32 ++ .../sink_alloc.lua => opt/sink/alloc.lua} | 266 ++++++------ test/opt/sink/index | 2 + .../sink_nosink.lua => opt/sink/nosink.lua} | 233 +++++----- test/{clib => src}/cpptest.cpp | 0 test/{clib => src}/ctest.c | 0 test/test.lua | 409 ++++++++++++++++++ test/{misc => trace}/exit_frame.lua | 159 ++++--- test/trace/exit_growstack.lua | 28 ++ test/trace/exit_jfuncf.lua | 30 ++ test/trace/index | 5 + test/trace/snap.lua | 47 ++ test/{misc => trace}/stitch.lua | 40 +- 146 files changed, 3817 insertions(+), 2834 deletions(-) delete mode 100644 experimental/test.lua delete mode 100644 experimental/test/libs_ext/table.lua delete mode 100644 experimental/tester.lua create mode 100644 test/README.md rename test/{misc => bc}/constov.lua (87%) create mode 100644 test/bc/index create mode 100644 test/common/expect_error.lua create mode 100644 test/common/test_runner_canary.lua create mode 100644 test/computations.lua create mode 100644 test/index create mode 100644 test/lang/andor.lua create mode 100644 test/lang/assignment.lua create mode 100644 test/lang/compare.lua rename test/{misc/cat_jit.lua => lang/concat.lua} (79%) create mode 100644 test/lang/constant/index create mode 100644 test/lang/constant/number.lua create mode 100644 test/lang/coroutine.lua create mode 100644 test/lang/for.lua create mode 100644 test/lang/gc.lua create mode 100644 test/lang/index create mode 100644 test/lang/modulo.lua create mode 100644 test/lang/self.lua create mode 100644 test/lang/tail_recursion.lua create mode 100644 test/lang/upvalue/closure.lua create mode 100644 test/lang/upvalue/index create mode 100644 test/lib/base/assert.lua create mode 100644 test/lib/base/error.lua create mode 100644 test/lib/base/getfenv.lua create mode 100644 test/lib/base/index rename {experimental/test/libs/core => test/lib/base}/select.lua (71%) rename test/{misc => lib/base}/xpcall_jit.lua (87%) create mode 100644 test/lib/bit.lua create mode 100644 test/lib/contents.lua create mode 100644 test/lib/coroutine/index create mode 100644 test/lib/coroutine/yield.lua rename test/{ => lib}/ffi/ffi_arith_ptr.lua (100%) rename test/{ => lib}/ffi/ffi_bit64.lua (100%) rename test/{ => lib}/ffi/ffi_bitfield.lua (100%) rename test/{ => lib}/ffi/ffi_call.lua (100%) rename test/{ => lib}/ffi/ffi_callback.lua (100%) rename test/{ => lib}/ffi/ffi_const.lua (100%) rename test/{ => lib}/ffi/ffi_convert.lua (100%) rename test/{ => lib}/ffi/ffi_copy_fill.lua (100%) rename test/{ => lib}/ffi/ffi_enum.lua (100%) rename test/{ => lib}/ffi/ffi_err.lua (100%) rename test/{ => lib}/ffi/ffi_gcstep_recursive.lua (100%) rename test/{ => lib}/ffi/ffi_istype.lua (100%) rename test/{ => lib}/ffi/ffi_jit_arith.lua (100%) rename test/{ => lib}/ffi/ffi_jit_array.lua (100%) rename test/{ => lib}/ffi/ffi_jit_call.lua (100%) rename test/{ => lib}/ffi/ffi_jit_complex.lua (100%) rename test/{ => lib}/ffi/ffi_jit_conv.lua (100%) rename test/{ => lib}/ffi/ffi_jit_misc.lua (100%) rename test/{ => lib}/ffi/ffi_jit_struct.lua (100%) rename test/{ => lib}/ffi/ffi_lex_number.lua (100%) rename test/{ => lib}/ffi/ffi_meta_tostring.lua (100%) rename test/{ => lib}/ffi/ffi_metatype.lua (100%) rename test/{ => lib}/ffi/ffi_new.lua (100%) rename test/{ => lib}/ffi/ffi_nosink.lua (100%) rename test/{ => lib}/ffi/ffi_parse_array.lua (100%) rename test/{ => lib}/ffi/ffi_parse_basic.lua (100%) rename test/{ => lib}/ffi/ffi_parse_cdef.lua (100%) rename test/{ => lib}/ffi/ffi_parse_struct.lua (100%) rename test/{ => lib}/ffi/ffi_redir.lua (100%) rename test/{ => lib}/ffi/ffi_sink.lua (100%) rename test/{ => lib}/ffi/ffi_tabov.lua (100%) rename test/{ => lib}/ffi/ffi_type_punning.lua (100%) create mode 100644 test/lib/index create mode 100644 test/lib/math/abs.lua create mode 100644 test/lib/math/constants.lua create mode 100644 test/lib/math/index create mode 100644 test/lib/math/random.lua rename test/{misc/string_byte.lua => lib/string/byte.lua} (76%) create mode 100644 test/lib/string/char.lua rename test/{misc/string_dump.lua => lib/string/dump.lua} (83%) create mode 100644 test/lib/string/format/index create mode 100644 test/lib/string/format/num.lua create mode 100644 test/lib/string/index create mode 100644 test/lib/string/len.lua create mode 100644 test/lib/string/lower_upper.lua create mode 100644 test/lib/string/metatable.lua create mode 100644 test/lib/string/rep.lua create mode 100644 test/lib/string/sub.lua create mode 100644 test/lib/table/concat.lua create mode 100644 test/lib/table/index rename {experimental/test/libs => test/lib}/table/insert.lua (87%) rename {experimental/test/libs => test/lib}/table/misc.lua (57%) create mode 100644 test/lib/table/new.lua create mode 100644 test/lib/table/pack.lua rename {experimental/test/libs => test/lib}/table/remove.lua (73%) create mode 100644 test/lib/table/sort.lua delete mode 100644 test/misc/ack.lua delete mode 100644 test/misc/ack_notail.lua delete mode 100644 test/misc/argcheck.lua delete mode 100644 test/misc/assign_tset_prevnil.lua delete mode 100644 test/misc/assign_tset_tmp.lua delete mode 100644 test/misc/bit_op.lua delete mode 100644 test/misc/compare.lua delete mode 100644 test/misc/exit_growstack.lua delete mode 100644 test/misc/exit_jfuncf.lua delete mode 100644 test/misc/fac.lua delete mode 100644 test/misc/fastfib.lua delete mode 100644 test/misc/fib.lua delete mode 100644 test/misc/fuse.lua delete mode 100644 test/misc/fwd_hrefk_rollback.lua delete mode 100644 test/misc/libfuncs.lua delete mode 100644 test/misc/math_random.lua delete mode 100644 test/misc/modulo.lua delete mode 100644 test/misc/nsieve.lua delete mode 100644 test/misc/parse_andor.lua delete mode 100644 test/misc/recsum.lua delete mode 100644 test/misc/recsump.lua delete mode 100644 test/misc/self.lua delete mode 100644 test/misc/snap_gcexit.lua delete mode 100644 test/misc/snap_top.lua delete mode 100644 test/misc/snap_top2.lua delete mode 100644 test/misc/sort.lua delete mode 100644 test/misc/string_char.lua delete mode 100644 test/misc/string_sub.lua delete mode 100644 test/misc/string_sub_opt.lua delete mode 100644 test/misc/tak.lua rename test/{misc/dse_array.lua => opt/dse/array.lua} (59%) rename test/{misc/dse_field.lua => opt/dse/field.lua} (72%) create mode 100644 test/opt/dse/index create mode 100644 test/opt/fold/index rename test/{misc => opt/fold}/kfold.lua (93%) create mode 100644 test/opt/fuse.lua create mode 100644 test/opt/fwd/hrefk_rollback.lua create mode 100644 test/opt/fwd/index rename test/{misc/fwd_tnew_tdup.lua => opt/fwd/tnew_tdup.lua} (80%) rename test/{misc/fwd_upval.lua => opt/fwd/upval.lua} (60%) create mode 100644 test/opt/index create mode 100644 test/opt/loop/index create mode 100644 test/opt/loop/unroll.lua rename test/{misc/sink_alloc.lua => opt/sink/alloc.lua} (76%) create mode 100644 test/opt/sink/index rename test/{misc/sink_nosink.lua => opt/sink/nosink.lua} (64%) rename test/{clib => src}/cpptest.cpp (100%) rename test/{clib => src}/ctest.c (100%) create mode 100644 test/test.lua rename test/{misc => trace}/exit_frame.lua (84%) create mode 100644 test/trace/exit_growstack.lua create mode 100644 test/trace/exit_jfuncf.lua create mode 100644 test/trace/index create mode 100644 test/trace/snap.lua rename test/{misc => trace}/stitch.lua (86%) diff --git a/experimental/test.lua b/experimental/test.lua deleted file mode 100644 index 9ea05ed462..0000000000 --- a/experimental/test.lua +++ /dev/null @@ -1,86 +0,0 @@ --- test.lua --- --- Recursively run tests in the given paths, filtered by the given tags. --- Failed tests are extracted to the directory "failed_tests", and error --- details are appended. - -local t = require("tester") -local tconcat, iowrite = table.concat, io.write -local tagpat_inc = "^%+([_%a][_%w]*)$" -local tagpat_exc = "^%-([_%a][_%w]*)$" -local paths, tags_inc, tags_exc = {}, {}, {} -local verbose = false -local arg = arg or {...} -local runcmd -local function print_help() - io.write[[ -Usage: luajit test.lua path1 path2 +tagtofilter +orthistag -tagtoexclude -andthistag -Options: - path Recursively include tests in path. Default: test - +tag_inc Include only tests with tag tag_inc. Multiple include tags are ORed. - -tag_exc Exclude tests with tag tag_exc. - --help Print this help message. - --verbose Explicitly list all tests. - --runcmd='cmd' - If runcmd is defined, Command to run the tests with, externally, e.g. - --runcmd="luajit -joff" -]] -end - -for _,a in ipairs(arg) do - if not a:match("^[+-]") then - paths[#paths+1]=a - elseif a:match(tagpat_inc) then - tags_inc[#tags_inc+1]=a:match(tagpat_inc) - elseif a:match(tagpat_exc) then - tags_exc[#tags_exc+1]=a:match(tagpat_exc) - elseif a:match("%-%-verbose") then - verbose = true - elseif a:match("%-%-help") then - print_help() - return - elseif a:match("%-%-runcmd") then - runcmd = a:match("%-%-runcmd=(.*)") - end -end - -if #paths==0 then paths[1]="test" end -iowrite("Running tests in \"",tconcat(paths,"\",\""),"\"") -if #tags_inc > 0 then - iowrite(" with tags ",tconcat(tags_inc,",")) -end -if #tags_exc > 0 then - iowrite(" but without tags ",tconcat(tags_exc,",")) -end -iowrite("\n") - -local index = t.index(paths) -index = t.filter(index,tags_inc,tags_exc) -local pass, fail, failed_tests, errors = t.run(index,verbose,runcmd) - -iowrite("Passed ",pass,"/",pass+fail," tests.\n") -if fail==0 then return end - -local function report_fail(test,err) - local extfn = t.extract(test,"failed_tests") - iowrite("----------------------------------------------------------", - "\nname: ",test.name, - "\nerror: ",err or "(no error message)", - "\nsource file: ",test.fn, - "\nextracted to file: ",extfn, - "\n") - -- Append error message for completeness - local extf = io.open(extfn,"a") - if extf then - extf:write("\n--[===[\nTest failed at ",os.date(), - "\nruncmd: ",runcmd or "(internal pcall)", - "\nerror:\n",err or "(no error message)", - "\n]===]\n") - end -end - -iowrite("Failed tests:\n") -for i,failed_test in ipairs(failed_tests) do - report_fail(failed_test,errors[i]) -end - diff --git a/experimental/test/libs_ext/table.lua b/experimental/test/libs_ext/table.lua deleted file mode 100644 index 03c221912d..0000000000 --- a/experimental/test/libs_ext/table.lua +++ /dev/null @@ -1,37 +0,0 @@ ---- table.new -do - local tnew = require("table.new") - local x, y - for i=1,100 do - x = tnew(100, 30) - if i == 90 then y = x end - end - assert(x ~= y) -end - ---- table.pack() --- +lua52 -do - if os.getenv("LUA52") then - local t = table.pack() - assert(t.n == 0 and t[0] == nil and t[1] == nil) - end -end - ---- table.pack(99) --- +lua52 -do - if os.getenv("LUA52") then - local t = table.pack(99) - assert(t.n == 1 and t[0] == nil and t[1] == 99 and t[2] == nil) - end -end - ---- table.pack(nils) --- +lua52 -do - if os.getenv("LUA52") then - local t = table.pack(nil, nil, nil) - assert(t.n == 3 and t[0] == nil and t[1] == nil and t[2] == nil and t[3] == nil and t[4] == nil) - end -end diff --git a/experimental/tester.lua b/experimental/tester.lua deleted file mode 100644 index 77b61164fa..0000000000 --- a/experimental/tester.lua +++ /dev/null @@ -1,274 +0,0 @@ -local lfs = require("lfs") -local tconcat = table.concat - ---- Shallow table copy -local function cp(t) - local t1 = {} - for k,v in pairs(t) do t1[k]=v end - return t1 -end - ---- Path tokenizer, builds a table t for which t.token=true --- @param fn string containing a filename (fullpath) --- @return table for which keys token = true -local function tags_from_path(fn) - local tags = {} - for token in fn:gmatch("[^\\/]+") do - local token_lua = token:match("(.*)%.lua$") - tags[token_lua or token] = true - end - return tags -end - --- Patterns for parsing out test data. -local identifier_pat = "([_%a][_%w]*)" -local delim_pat = "^%-%-%-" -local name_pat = delim_pat.."%s*(.*)" -local desc_pat = "^%-%-(.*)" -local tag_pat = "%+"..identifier_pat -local attrib_pat = "@"..identifier_pat.."%s*:%s*([^@]*)" - ---- Parser for the tests. --- @param fn string containing a filename (fullpath) --- @return array containing test specs (name, code, description, tags) -local function parse_test(fn) - local tests = {} - local lookup = {} - local prelude = { - name = "prelude of "..fn, - fn = fn, - description = {}, - code = {}, - tags = tags_from_path(fn), - attributes = {}, - } - local current_test = prelude - local function store_test() - tests[#tests+1] = current_test - lookup[current_test.name] = #tests - end - for line in io.lines(fn) do - if line:match(delim_pat) then - -- Next test is reached - store_test() - local testname = line:match(name_pat) - if lookup[testname] then - error("Test "..testname.." is defined twice in the same file. Please give the tests unique names.") - end - -- Add current test to the tests table and start new current test table. - current_test = { - name = testname, - fn = fn, - description = cp(prelude.description), - tags = cp(prelude.tags), - code = cp(prelude.code), - attributes = cp(prelude.attributes), - } - elseif line:match(desc_pat) and #current_test.code==#prelude.code then - -- Continue building current test description, and possibly extract tags and key-value pairs - current_test.description[#current_test.description+1] = line:match(desc_pat) - for tag in line:gmatch(tag_pat) do - current_test.tags[tag] = true - end - for key,value in line:gmatch(attrib_pat) do - current_test.attributes[key] = value:gsub("%s*$","") - end - else - current_test.code[#current_test.code+1] = line - end - end - store_test() - return tests -end - --- Recursively parse the path and store the tests in test_index --- @param path string containing a path to a file or directory --- @param test_index array containing the tables with tests per file -local function recursive_parse(path,test_index) - local att, err = lfs.attributes(path) - if not att then - error("Could not parse "..path..": "..err) - end - if att.mode=="directory" then - for path2 in lfs.dir(path) do - if path2~=".." and path2~="." then - recursive_parse(path.."/"..path2,test_index) - end - end - elseif att.mode=="file" and path:match("%.lua$") then - test_index[#test_index+1] = parse_test(path) - end -end - ---- Walk the directory tree and index tests. --- @param paths array of paths that should be indexed. --- @return array of tables containing tests returned by parse -local function index_tests(paths) - local test_index = {} - for _,path in ipairs(paths) do - recursive_parse(path,test_index) - end - return test_index -end - ---- Build the string containing the chunk of a single test, including name and --- description. --- @param test table containing a test's name, description and code --- @return string containing the code snippet for the test, including comments. -local function build_codestring(test) - return tconcat({ - "--- ", test.name, - #test.description>0 and "\n--" or "", - tconcat(test.description,"\n--"), "\n", - tconcat(test.code,"\n") - }) -end - ---- Extract a test to a file. --- @param test the test table returned by parse, containing name, description, --- tags, code and attributes --- @param workdir string containing the directory where the test is extracted; --- the directory is created if needed (default: ".") --- @param fn string containing filename where the test should be extracted --- (default: test_fn__test_name.lua) --- @return filename to where the test was extracted -local function extract_test(test,workdir,fn) - fn = fn or (test.fn:gsub("%.lua$","").."__"..test.name):gsub("[^%a]","_")..".lua" - if workdir then - lfs.mkdir(workdir) - fn = workdir.."/"..fn - end - local f = io.open(fn,"w") - if not f then - error("Could not write to file "..fn) - end - f:write(build_codestring(test)) - f:close() - return fn -end - ---- Run a single test, possibly externally with runcmd. --- @param test single test object containing name, description, tags, code. --- @param verbose boolean indicating verbosity --- @param runcmd string containing the luajit command to run external tests. --- If runcmd is defined, the test is extracted into a file and run externally. --- If left empty, the test is run internally with pcall. --- @param workdir string containing the directory where runcmd is run and --- the test is extracted. --- @return true (pass) or false (fail) --- @return msg error message in case of failure -local function run_single_test(test,verbose,runcmd,workdir) - local ok, res - if runcmd then - workdir = workdir or "." - local fn = extract_test(test,workdir,"current_test.lua") - local fnerr = fn:gsub("%.lua$",".err") - local status = os.execute(runcmd.." "..fn.." 2> "..fnerr) - ok = status==0 - if not ok then - local ferr = io.open(fnerr) - if ferr then - res = ferr:read("*a") - ferr:close() - end - end - else - local code = build_codestring(test) - local load_ok, load_res = pcall(loadstring,code) - if not load_ok then - if verbose then - io.write("SYNT ",test.name,"\n ",load_res or "(no error message)","\n") - end - return load_ok, load_res - else - ok, res = pcall(load_res) - end - end - if verbose then - io.write(ok and "PASS " or "FAIL ",test.name,"\n") - if not ok then io.write(" "..(res or "(no error message)"),"\n") end - end - return ok, res -end - ---- Recursively run tests in paths. --- @param paths array of paths to recursively run tests in. --- @param verbose boolean indicating verbosity --- @param runcmd string containing the luajit command to run external tests. --- If runcmd is defined, the test is extracted into a file and run externally. --- If left empty, the test is run internally with pcall. --- @return number of passed tests --- @return number of failed tests --- @return array of failed tests --- @return array of corresponding error messages -local function run_tests(test_index,verbose,runcmd) - local pass, fail = 0,0 - local failed_tests = {} - local errors = {} - for i,test_block in ipairs(test_index) do - for j,test in ipairs(test_block) do - local ok, res = run_single_test(test,verbose,runcmd) - if ok then - pass = pass+1 - else - fail = fail+1 - failed_tests[#failed_tests+1] = test - errors[#errors+1] = res - end - end - end - return pass, fail, failed_tests, errors -end - ---- Check whether tags are in tags_inc and none are in tags_exc. --- If tags_inc is empty, default inclusion is true. --- @param tags Array of tags to test --- @param tags_inc Array of tags to include --- @param tags_exc Array of tags to exclude --- @return boolean indicating inclusion -local function check_tags(tags,tags_inc,tags_exc) - local include = false - if #tags_inc==0 then include = true end - for _,tag_inc in ipairs(tags_inc) do - if tags[tag_inc] then - include = true - break - end - end - if not include then return false end - for _,tag_exc in ipairs(tags_exc) do - if tags[tag_exc] then - return false - end - end - return true -end - ---- Select tests with tags_inc without tags_exc. --- If tags_inc is empty, select all tests by default. --- @param test_index array of test_blocks --- @param tags_inc array of tags to include --- @param tags_exc array of tags to exclude -local function filter_tests(test_index,tags_inc,tags_exc) - local tests_filtered = {} - for i,test_block in ipairs(test_index) do - local tests_i - for j, test in ipairs(test_block) do - if check_tags(test.tags,tags_inc,tags_exc) then - tests_i = tests_i or {} - tests_i[#tests_i+1]= test - end - end - tests_filtered[#tests_filtered+1] = tests_i - end - return tests_filtered -end - -return { - parse = parse_test, - index = index_tests, - extract = extract_test, - run_single = run_single_test, - run = run_tests, - filter = filter_tests, -} diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000000..f72290f225 --- /dev/null +++ b/test/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 --- <> <> + << code >> + end + +Where `<>` is (almost) free-form, and `<< code >>` is Lua code which +performs some actions and probably calls `assert` alot. The `<>` +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 --- <>`). +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/misc/constov.lua b/test/bc/constov.lua similarity index 87% rename from test/misc/constov.lua rename to test/bc/constov.lua index 341cf32930..de1e2a6d5d 100644 --- a/test/misc/constov.lua +++ b/test/bc/constov.lua @@ -1,19 +1,16 @@ - -if not os.getenv("SLOWTEST") then return end - -do - 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 - 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 - + +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/bc/index b/test/bc/index new file mode 100644 index 0000000000..3954d57600 --- /dev/null +++ b/test/bc/index @@ -0,0 +1 @@ +constov.lua +slow diff --git a/test/common/expect_error.lua b/test/common/expect_error.lua new file mode 100644 index 0000000000..7643416720 --- /dev/null +++ b/test/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/common/test_runner_canary.lua b/test/common/test_runner_canary.lua new file mode 100644 index 0000000000..138ad84c9e --- /dev/null +++ b/test/common/test_runner_canary.lua @@ -0,0 +1 @@ +return "canary is alive" diff --git a/test/computations.lua b/test/computations.lua new file mode 100644 index 0000000000..439febee7e --- /dev/null +++ b/test/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/index b/test/index new file mode 100644 index 0000000000..256118eb9b --- /dev/null +++ b/test/index @@ -0,0 +1,6 @@ +lang +lib +bc +luajit>=2 +computations.lua +trace +jit +opt +jit diff --git a/test/lang/andor.lua b/test/lang/andor.lua new file mode 100644 index 0000000000..dc4296faa3 --- /dev/null +++ b/test/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/lang/assignment.lua b/test/lang/assignment.lua new file mode 100644 index 0000000000..34c7b52df7 --- /dev/null +++ b/test/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/lang/compare.lua b/test/lang/compare.lua new file mode 100644 index 0000000000..fdabef5e8d --- /dev/null +++ b/test/lang/compare.lua @@ -0,0 +1,249 @@ +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(xy, false) + check(x>=y, false) + check(x==y, false) + check(x~=y, true) + + check(1y, 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(xy, true) + check(x>=y, true) + check(x==y, false) + check(x~=y, true) + + check(2y, 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(xy, false) + check(x>=y, true) + check(x==y, true) + check(x~=y, false) + + check(1y, 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 diff --git a/test/misc/cat_jit.lua b/test/lang/concat.lua similarity index 79% rename from test/misc/cat_jit.lua rename to test/lang/concat.lua index 858a15bf45..c7af134f92 100644 --- a/test/misc/cat_jit.lua +++ b/test/lang/concat.lua @@ -1,113 +1,101 @@ - --- Constant folding -do - 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 - --- Fuse conversions to strings -do - 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 - --- Fuse string construction -do - local y - local x = "abc" - for i=1,100 do y = "x"..string.sub(x, 2) end - assert(y == "xbc") -end - --- CSE, sink -do - local y - local x = "a" - for i=1,100 do y = x.."b" end - assert(y == "ab") -end - --- CSE, two buffers in parallel, no sink -do - 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 - --- Append, CSE -do - 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 - --- Append, FOLD -do - local a, b = "x" - for i=1,100 do b = (a.."y").."" end - assert(b == "xy") -end - --- Append to buffer, sink -do - 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 - --- Append to two buffers in parallel, no append, no sink -do - 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 - --- Sink into side-exit -do - 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 --- 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 diff --git a/test/lang/constant/index b/test/lang/constant/index new file mode 100644 index 0000000000..05bc1edb01 --- /dev/null +++ b/test/lang/constant/index @@ -0,0 +1 @@ +number.lua diff --git a/test/lang/constant/number.lua b/test/lang/constant/number.lua new file mode 100644 index 0000000000..c0514e7389 --- /dev/null +++ b/test/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/lang/coroutine.lua b/test/lang/coroutine.lua new file mode 100644 index 0000000000..769e64ffab --- /dev/null +++ b/test/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/lang/for.lua b/test/lang/for.lua new file mode 100644 index 0000000000..b16508e1d3 --- /dev/null +++ b/test/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/lang/gc.lua b/test/lang/gc.lua new file mode 100644 index 0000000000..0c50450646 --- /dev/null +++ b/test/lang/gc.lua @@ -0,0 +1,30 @@ +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 diff --git a/test/lang/index b/test/lang/index new file mode 100644 index 0000000000..743c5bce9e --- /dev/null +++ b/test/lang/index @@ -0,0 +1,12 @@ +andor.lua +assignment.lua +compare.lua +constant +for.lua +modulo.lua +concat.lua +self.lua +upvalue +coroutine.lua +tail_recursion.lua +gc.lua diff --git a/test/lang/modulo.lua b/test/lang/modulo.lua new file mode 100644 index 0000000000..eddaea77fa --- /dev/null +++ b/test/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/lang/self.lua b/test/lang/self.lua new file mode 100644 index 0000000000..48f58d30c8 --- /dev/null +++ b/test/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/lang/tail_recursion.lua b/test/lang/tail_recursion.lua new file mode 100644 index 0000000000..22bab72f95 --- /dev/null +++ b/test/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/lang/upvalue/closure.lua b/test/lang/upvalue/closure.lua new file mode 100644 index 0000000000..34083223c7 --- /dev/null +++ b/test/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/lang/upvalue/index b/test/lang/upvalue/index new file mode 100644 index 0000000000..58931de651 --- /dev/null +++ b/test/lang/upvalue/index @@ -0,0 +1 @@ +closure.lua diff --git a/test/lib/base/assert.lua b/test/lib/base/assert.lua new file mode 100644 index 0000000000..6f1ef548c1 --- /dev/null +++ b/test/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/lib/base/error.lua b/test/lib/base/error.lua new file mode 100644 index 0000000000..74aac75437 --- /dev/null +++ b/test/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/lib/base/getfenv.lua b/test/lib/base/getfenv.lua new file mode 100644 index 0000000000..29e288c13f --- /dev/null +++ b/test/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/lib/base/index b/test/lib/base/index new file mode 100644 index 0000000000..16adea05e2 --- /dev/null +++ b/test/lib/base/index @@ -0,0 +1,5 @@ +assert.lua +error.lua +getfenv.lua +lua<5.2 +select.lua +xpcall_jit.lua +compat5.2 diff --git a/experimental/test/libs/core/select.lua b/test/lib/base/select.lua similarity index 71% rename from experimental/test/libs/core/select.lua rename to test/lib/base/select.lua index 5431609072..5c8ac55170 100644 --- a/experimental/test/libs/core/select.lua +++ b/test/lib/base/select.lua @@ -1,99 +1,105 @@ --- Tests for the basic function select(). --- +select +fast - ---- select # --- Test whether select("#", 3, 4) returns the correct number of arguments. -do - local x = 0 - for i=1,100 do - x = x + select("#", 3, 4) - end - assert(x == 200) -end - ---- select modf --- Test whether select("#", func()) also works with func returning multiple values -do - local x = 0 - for i=1,100 do - x = x + select("#", math.modf(i)) - end - assert(x == 200) -end - ---- select 1 -do - local x = 0 - for i=1,100 do - x = x + select(1, i) - end - assert(x == 5050) -end - ---- select 2 -do - 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 - ---- select vararg # -do - 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 - ---- select vararg i -do - 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 - ---- select vararg 4 -do - 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 --- 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/misc/xpcall_jit.lua b/test/lib/base/xpcall_jit.lua similarity index 87% rename from test/misc/xpcall_jit.lua rename to test/lib/base/xpcall_jit.lua index 61ffc8e64c..32c8e1c472 100644 --- a/test/misc/xpcall_jit.lua +++ b/test/lib/base/xpcall_jit.lua @@ -1,86 +1,83 @@ - -local function tr(err) return "tr"..err end - -do - 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 - 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 - 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 - 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 - 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 - local x = 0 - for i=1,100 do - -- Test xpcall swap after recorder error. - 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 - +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/lib/bit.lua b/test/lib/bit.lua new file mode 100644 index 0000000000..a37b28a37e --- /dev/null +++ b/test/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/lib/contents.lua b/test/lib/contents.lua new file mode 100644 index 0000000000..bb9f2cf79f --- /dev/null +++ b/test/lib/contents.lua @@ -0,0 +1,151 @@ +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 + 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 + 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:typeinfo:typeof") +end diff --git a/test/lib/coroutine/index b/test/lib/coroutine/index new file mode 100644 index 0000000000..4c9e320b48 --- /dev/null +++ b/test/lib/coroutine/index @@ -0,0 +1 @@ +yield.lua diff --git a/test/lib/coroutine/yield.lua b/test/lib/coroutine/yield.lua new file mode 100644 index 0000000000..4cc98de9c5 --- /dev/null +++ b/test/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/ffi/ffi_arith_ptr.lua b/test/lib/ffi/ffi_arith_ptr.lua similarity index 100% rename from test/ffi/ffi_arith_ptr.lua rename to test/lib/ffi/ffi_arith_ptr.lua diff --git a/test/ffi/ffi_bit64.lua b/test/lib/ffi/ffi_bit64.lua similarity index 100% rename from test/ffi/ffi_bit64.lua rename to test/lib/ffi/ffi_bit64.lua diff --git a/test/ffi/ffi_bitfield.lua b/test/lib/ffi/ffi_bitfield.lua similarity index 100% rename from test/ffi/ffi_bitfield.lua rename to test/lib/ffi/ffi_bitfield.lua diff --git a/test/ffi/ffi_call.lua b/test/lib/ffi/ffi_call.lua similarity index 100% rename from test/ffi/ffi_call.lua rename to test/lib/ffi/ffi_call.lua diff --git a/test/ffi/ffi_callback.lua b/test/lib/ffi/ffi_callback.lua similarity index 100% rename from test/ffi/ffi_callback.lua rename to test/lib/ffi/ffi_callback.lua diff --git a/test/ffi/ffi_const.lua b/test/lib/ffi/ffi_const.lua similarity index 100% rename from test/ffi/ffi_const.lua rename to test/lib/ffi/ffi_const.lua diff --git a/test/ffi/ffi_convert.lua b/test/lib/ffi/ffi_convert.lua similarity index 100% rename from test/ffi/ffi_convert.lua rename to test/lib/ffi/ffi_convert.lua diff --git a/test/ffi/ffi_copy_fill.lua b/test/lib/ffi/ffi_copy_fill.lua similarity index 100% rename from test/ffi/ffi_copy_fill.lua rename to test/lib/ffi/ffi_copy_fill.lua diff --git a/test/ffi/ffi_enum.lua b/test/lib/ffi/ffi_enum.lua similarity index 100% rename from test/ffi/ffi_enum.lua rename to test/lib/ffi/ffi_enum.lua diff --git a/test/ffi/ffi_err.lua b/test/lib/ffi/ffi_err.lua similarity index 100% rename from test/ffi/ffi_err.lua rename to test/lib/ffi/ffi_err.lua diff --git a/test/ffi/ffi_gcstep_recursive.lua b/test/lib/ffi/ffi_gcstep_recursive.lua similarity index 100% rename from test/ffi/ffi_gcstep_recursive.lua rename to test/lib/ffi/ffi_gcstep_recursive.lua diff --git a/test/ffi/ffi_istype.lua b/test/lib/ffi/ffi_istype.lua similarity index 100% rename from test/ffi/ffi_istype.lua rename to test/lib/ffi/ffi_istype.lua diff --git a/test/ffi/ffi_jit_arith.lua b/test/lib/ffi/ffi_jit_arith.lua similarity index 100% rename from test/ffi/ffi_jit_arith.lua rename to test/lib/ffi/ffi_jit_arith.lua diff --git a/test/ffi/ffi_jit_array.lua b/test/lib/ffi/ffi_jit_array.lua similarity index 100% rename from test/ffi/ffi_jit_array.lua rename to test/lib/ffi/ffi_jit_array.lua diff --git a/test/ffi/ffi_jit_call.lua b/test/lib/ffi/ffi_jit_call.lua similarity index 100% rename from test/ffi/ffi_jit_call.lua rename to test/lib/ffi/ffi_jit_call.lua diff --git a/test/ffi/ffi_jit_complex.lua b/test/lib/ffi/ffi_jit_complex.lua similarity index 100% rename from test/ffi/ffi_jit_complex.lua rename to test/lib/ffi/ffi_jit_complex.lua diff --git a/test/ffi/ffi_jit_conv.lua b/test/lib/ffi/ffi_jit_conv.lua similarity index 100% rename from test/ffi/ffi_jit_conv.lua rename to test/lib/ffi/ffi_jit_conv.lua diff --git a/test/ffi/ffi_jit_misc.lua b/test/lib/ffi/ffi_jit_misc.lua similarity index 100% rename from test/ffi/ffi_jit_misc.lua rename to test/lib/ffi/ffi_jit_misc.lua diff --git a/test/ffi/ffi_jit_struct.lua b/test/lib/ffi/ffi_jit_struct.lua similarity index 100% rename from test/ffi/ffi_jit_struct.lua rename to test/lib/ffi/ffi_jit_struct.lua diff --git a/test/ffi/ffi_lex_number.lua b/test/lib/ffi/ffi_lex_number.lua similarity index 100% rename from test/ffi/ffi_lex_number.lua rename to test/lib/ffi/ffi_lex_number.lua diff --git a/test/ffi/ffi_meta_tostring.lua b/test/lib/ffi/ffi_meta_tostring.lua similarity index 100% rename from test/ffi/ffi_meta_tostring.lua rename to test/lib/ffi/ffi_meta_tostring.lua diff --git a/test/ffi/ffi_metatype.lua b/test/lib/ffi/ffi_metatype.lua similarity index 100% rename from test/ffi/ffi_metatype.lua rename to test/lib/ffi/ffi_metatype.lua diff --git a/test/ffi/ffi_new.lua b/test/lib/ffi/ffi_new.lua similarity index 100% rename from test/ffi/ffi_new.lua rename to test/lib/ffi/ffi_new.lua diff --git a/test/ffi/ffi_nosink.lua b/test/lib/ffi/ffi_nosink.lua similarity index 100% rename from test/ffi/ffi_nosink.lua rename to test/lib/ffi/ffi_nosink.lua diff --git a/test/ffi/ffi_parse_array.lua b/test/lib/ffi/ffi_parse_array.lua similarity index 100% rename from test/ffi/ffi_parse_array.lua rename to test/lib/ffi/ffi_parse_array.lua diff --git a/test/ffi/ffi_parse_basic.lua b/test/lib/ffi/ffi_parse_basic.lua similarity index 100% rename from test/ffi/ffi_parse_basic.lua rename to test/lib/ffi/ffi_parse_basic.lua diff --git a/test/ffi/ffi_parse_cdef.lua b/test/lib/ffi/ffi_parse_cdef.lua similarity index 100% rename from test/ffi/ffi_parse_cdef.lua rename to test/lib/ffi/ffi_parse_cdef.lua diff --git a/test/ffi/ffi_parse_struct.lua b/test/lib/ffi/ffi_parse_struct.lua similarity index 100% rename from test/ffi/ffi_parse_struct.lua rename to test/lib/ffi/ffi_parse_struct.lua diff --git a/test/ffi/ffi_redir.lua b/test/lib/ffi/ffi_redir.lua similarity index 100% rename from test/ffi/ffi_redir.lua rename to test/lib/ffi/ffi_redir.lua diff --git a/test/ffi/ffi_sink.lua b/test/lib/ffi/ffi_sink.lua similarity index 100% rename from test/ffi/ffi_sink.lua rename to test/lib/ffi/ffi_sink.lua diff --git a/test/ffi/ffi_tabov.lua b/test/lib/ffi/ffi_tabov.lua similarity index 100% rename from test/ffi/ffi_tabov.lua rename to test/lib/ffi/ffi_tabov.lua diff --git a/test/ffi/ffi_type_punning.lua b/test/lib/ffi/ffi_type_punning.lua similarity index 100% rename from test/ffi/ffi_type_punning.lua rename to test/lib/ffi/ffi_type_punning.lua diff --git a/test/lib/index b/test/lib/index new file mode 100644 index 0000000000..c15ccfd6a6 --- /dev/null +++ b/test/lib/index @@ -0,0 +1,8 @@ +base +bit.lua +bit +math +string +table +coroutine + +contents.lua \ No newline at end of file diff --git a/test/lib/math/abs.lua b/test/lib/math/abs.lua new file mode 100644 index 0000000000..660a6cc37d --- /dev/null +++ b/test/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/lib/math/constants.lua b/test/lib/math/constants.lua new file mode 100644 index 0000000000..5f8a4f79d8 --- /dev/null +++ b/test/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/lib/math/index b/test/lib/math/index new file mode 100644 index 0000000000..f17d52e780 --- /dev/null +++ b/test/lib/math/index @@ -0,0 +1,3 @@ +abs.lua +constants.lua +random.lua diff --git a/test/lib/math/random.lua b/test/lib/math/random.lua new file mode 100644 index 0000000000..4ee799b2e2 --- /dev/null +++ b/test/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/misc/string_byte.lua b/test/lib/string/byte.lua similarity index 76% rename from test/misc/string_byte.lua rename to test/lib/string/byte.lua index cd565ecb48..21b1231737 100644 --- a/test/misc/string_byte.lua +++ b/test/lib/string/byte.lua @@ -1,90 +1,92 @@ - -local band, bor = bit.band, bit.bor -local byte = string.byte - --- Fixed slice [i,i+k] or overflow -do - 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 - --- Positive slice [i,len] or overflow -do - 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 - --- Negative slice [-i,len] or underflow -do - 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 - --- Positive slice [1,i] or overflow -do - 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 - --- Negative slice [1,-i] or underflow -do - 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 - --- Check for slot stack overflow -do - local s = string.rep("x", 500) - for i=1,100 do byte(s, 1, 500) end -end - +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/lib/string/char.lua b/test/lib/string/char.lua new file mode 100644 index 0000000000..dff92e3202 --- /dev/null +++ b/test/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/misc/string_dump.lua b/test/lib/string/dump.lua similarity index 83% rename from test/misc/string_dump.lua rename to test/lib/string/dump.lua index a255b8a895..075e37e5d6 100644 --- a/test/misc/string_dump.lua +++ b/test/lib/string/dump.lua @@ -1,31 +1,29 @@ - --- Must unpatch modified bytecode with ILOOP/JLOOP etc. -do - 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) - jit.off(foo) - 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 - 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 +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/lib/string/format/index b/test/lib/string/format/index new file mode 100644 index 0000000000..682f3b8ebe --- /dev/null +++ b/test/lib/string/format/index @@ -0,0 +1 @@ +num.lua diff --git a/test/lib/string/format/num.lua b/test/lib/string/format/num.lua new file mode 100644 index 0000000000..279f3c2304 --- /dev/null +++ b/test/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/lib/string/index b/test/lib/string/index new file mode 100644 index 0000000000..a51f80651c --- /dev/null +++ b/test/lib/string/index @@ -0,0 +1,9 @@ +metatable.lua +byte.lua +char.lua +dump.lua +format +len.lua +lower_upper.lua +rep.lua +sub.lua diff --git a/test/lib/string/len.lua b/test/lib/string/len.lua new file mode 100644 index 0000000000..8d9c7e57a6 --- /dev/null +++ b/test/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/lib/string/lower_upper.lua b/test/lib/string/lower_upper.lua new file mode 100644 index 0000000000..52c5739706 --- /dev/null +++ b/test/lib/string/lower_upper.lua @@ -0,0 +1,16 @@ +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 diff --git a/test/lib/string/metatable.lua b/test/lib/string/metatable.lua new file mode 100644 index 0000000000..9861ee7e3c --- /dev/null +++ b/test/lib/string/metatable.lua @@ -0,0 +1,3 @@ +do --- __index metamethod is string library + assert(debug.getmetatable("").__index == string) +end diff --git a/test/lib/string/rep.lua b/test/lib/string/rep.lua new file mode 100644 index 0000000000..d06b4ee4ed --- /dev/null +++ b/test/lib/string/rep.lua @@ -0,0 +1,13 @@ +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 diff --git a/test/lib/string/sub.lua b/test/lib/string/sub.lua new file mode 100644 index 0000000000..981f2924a0 --- /dev/null +++ b/test/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/lib/table/concat.lua b/test/lib/table/concat.lua new file mode 100644 index 0000000000..514a883fc6 --- /dev/null +++ b/test/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/lib/table/index b/test/lib/table/index new file mode 100644 index 0000000000..e400606b0d --- /dev/null +++ b/test/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/experimental/test/libs/table/insert.lua b/test/lib/table/insert.lua similarity index 87% rename from experimental/test/libs/table/insert.lua rename to test/lib/table/insert.lua index d4d617cc83..91d4dd8767 100644 --- a/experimental/test/libs/table/insert.lua +++ b/test/lib/table/insert.lua @@ -1,17 +1,14 @@ - local tinsert = table.insert local assert = assert ---- table.insert(t,i) -do +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 ---- table.insert(t,i,i) -do +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 diff --git a/experimental/test/libs/table/misc.lua b/test/lib/table/misc.lua similarity index 57% rename from experimental/test/libs/table/misc.lua rename to test/lib/table/misc.lua index ba6375172f..e0e2fc592f 100644 --- a/experimental/test/libs/table/misc.lua +++ b/test/lib/table/misc.lua @@ -1,4 +1,6 @@ --- ABC elim +-- TODO: Organise + +-- ABC elim -- +opt +abc do local s, t = {}, {} @@ -52,61 +54,5 @@ do t[6] == nil) end ---- table.concat -do - local t = {a=1,b=2,c=3,d=4,e=5} - t[1] = 4 - t[3] = 6 - local ok, err = pcall(table.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(table.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] = table.concat(q[i], "x") end - assert(q[90] == "4x5x6") - assert(q[91] == "") - assert(q[92] == "9") - assert(q[93] == "9x8x7") -end - ---- table.concat must inhibit CSE and DSE -do - local t = {1,2,3} - local y, z - for i=1,100 do - y = table.concat(t, "x", 1, 3) - t[2] = i - z = table.concat(t, "x", 1, 3) - end - assert(y == "1x99x3") - assert(z == "1x100x3") -end ---- table.concat must inhibit CSE and DSE 2 -do - local y - for i=1,100 do - local t = {1,2,3} - t[2] = 4 - y = table.concat(t, "x") - t[2] = 9 - end - assert(y == "1x4x3") -end - ---- table.concat must inhibit CSE and DSE 3 -do - 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/lib/table/new.lua b/test/lib/table/new.lua new file mode 100644 index 0000000000..8e422477cc --- /dev/null +++ b/test/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/lib/table/pack.lua b/test/lib/table/pack.lua new file mode 100644 index 0000000000..b76e22fd51 --- /dev/null +++ b/test/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/experimental/test/libs/table/remove.lua b/test/lib/table/remove.lua similarity index 73% rename from experimental/test/libs/table/remove.lua rename to test/lib/table/remove.lua index 67a594b206..604f588ab5 100644 --- a/experimental/test/libs/table/remove.lua +++ b/test/lib/table/remove.lua @@ -1,28 +1,23 @@ - local tremove = table.remove local assert = assert ---- table.remove(t) removes correct entries -do +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 ---- table.remove(t) returns the removed entry -do +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 ---- table.remove(t, 1) removes and returns the first entry -do +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 - diff --git a/test/lib/table/sort.lua b/test/lib/table/sort.lua new file mode 100644 index 0000000000..c95a895e10 --- /dev/null +++ b/test/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/misc/ack.lua b/test/misc/ack.lua deleted file mode 100644 index bcc1316e1e..0000000000 --- a/test/misc/ack.lua +++ /dev/null @@ -1,12 +0,0 @@ -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 - -if arg and arg[1] then - local N = tonumber(arg and arg[1]) - io.write("Ack(3,", N ,"): ", Ack(3,N), "\n") -else - assert(Ack(3,5) == 253) -end diff --git a/test/misc/ack_notail.lua b/test/misc/ack_notail.lua deleted file mode 100644 index e14c003afd..0000000000 --- a/test/misc/ack_notail.lua +++ /dev/null @@ -1,12 +0,0 @@ -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 - -if arg and arg[1] then - local N = tonumber(arg and arg[1]) - io.write("Ack(3,", N ,"): ", Ack(3,N), "\n") -else - assert(Ack(3,5) == 253) -end diff --git a/test/misc/argcheck.lua b/test/misc/argcheck.lua deleted file mode 100644 index de3cb70ad7..0000000000 --- a/test/misc/argcheck.lua +++ /dev/null @@ -1,40 +0,0 @@ - -local function check(f, msg) - local ok, err = pcall(f) - if ok then error("error check unexpectedly succeeded", 2) end - 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 error("error check failed with "..err, 2) end -end - -assert(math.abs(-1.5) == 1.5) -assert(math.abs("-1.5") == 1.5) - -check(function() math.abs() end, - "bad argument #1 to 'abs' (number expected, got no value)") -check(function() math.abs(false) end, - "bad argument #1 to 'abs' (number expected, got boolean)") -check(function() math.abs("a") end, - "bad argument #1 to 'abs' (number expected, got string)") -string.abs = math.abs -check(function() ("a"):abs() end, - "calling 'abs' on bad self (number expected, got string)") - -assert(string.len("abc") == 3) -assert(string.len(123) == 3) - -check(function() string.len() end, - "bad argument #1 to 'len' (string expected, got nil)") -check(function() string.len(false) end, - "bad argument #1 to 'len' (string expected, got boolean)") - -assert(string.sub("abc", 2) == "bc") -assert(string.sub(123, "2") == "23") - -check(function() string.sub("abc", false) end, - "bad argument #2 to 'sub' (number expected, got boolean)") -check(function() ("abc"):sub(false) end, - "bad argument #1 to 'sub' (number expected, got boolean)") - diff --git a/test/misc/assign_tset_prevnil.lua b/test/misc/assign_tset_prevnil.lua deleted file mode 100644 index 202153c612..0000000000 --- a/test/misc/assign_tset_prevnil.lua +++ /dev/null @@ -1,11 +0,0 @@ -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) diff --git a/test/misc/assign_tset_tmp.lua b/test/misc/assign_tset_tmp.lua deleted file mode 100644 index 909d5aadaa..0000000000 --- a/test/misc/assign_tset_tmp.lua +++ /dev/null @@ -1,5 +0,0 @@ -a = {} -i = 3 -i, a[i] = i+1, 20 -assert(i == 4) -assert(a[3] == 20) diff --git a/test/misc/bit_op.lua b/test/misc/bit_op.lua deleted file mode 100644 index 4bab240c03..0000000000 --- a/test/misc/bit_op.lua +++ /dev/null @@ -1,90 +0,0 @@ --- Test cases for bit operations library. Public domain. - -local bit = require"bit" - -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 + string.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 _,y in ipairs(vb) do s = s..","..tostring(f(x, y)) 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 - --- 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()") - --- 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) - --- Apply operations to test vectors and compare checksums. -check_unop("tobit", 277312) -check_unop("bnot", 287870) -check_unop("bswap", 307611) - -check_binop("band", 41206764) -check_binop("bor", 51253663) -check_binop("bxor", 79322427) - -check_shift("lshift", 325260344) -check_shift("rshift", 139061800) -check_shift("arshift", 111364720) -check_shift("rol", 302401155) -check_shift("ror", 302316761) - -check_binop_range("tohex", 47880306, -8, 8) - --- 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 - diff --git a/test/misc/compare.lua b/test/misc/compare.lua deleted file mode 100644 index 96a52d90d2..0000000000 --- a/test/misc/compare.lua +++ /dev/null @@ -1,232 +0,0 @@ -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 - -local x,y = 1,2 - -check(xy, false) -check(x>=y, false) -check(x==y, false) -check(x~=y, true) - -check(1y, 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) - -local x,y = 2,1 - -check(xy, true) -check(x>=y, true) -check(x==y, false) -check(x~=y, true) - -check(2y, 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) - -local x,y = 1,1 - -check(xy, false) -check(x>=y, true) -check(x==y, true) -check(x~=y, false) - -check(1y, 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) - - -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) - - -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) - - -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) - -do - assert(not pcall(function() - local a, b = 10.5, nil - return a < b - end)) -end - -do - 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 - diff --git a/test/misc/exit_growstack.lua b/test/misc/exit_growstack.lua deleted file mode 100644 index 548b55565a..0000000000 --- a/test/misc/exit_growstack.lua +++ /dev/null @@ -1,24 +0,0 @@ -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 -- Exit needs to grow stack before slot fill. -end -for j=1,5 do - collectgarbage() -- Shrink stack. - for i=1,100 do f(i) end -end - -local function g(i) - if i==90 then return end -- Exit needs to grow stack after slot fill. - 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 diff --git a/test/misc/exit_jfuncf.lua b/test/misc/exit_jfuncf.lua deleted file mode 100644 index 7e452ef44f..0000000000 --- a/test/misc/exit_jfuncf.lua +++ /dev/null @@ -1,30 +0,0 @@ - -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) - diff --git a/test/misc/fac.lua b/test/misc/fac.lua deleted file mode 100644 index 86dc427070..0000000000 --- a/test/misc/fac.lua +++ /dev/null @@ -1,13 +0,0 @@ -local function fac(n) - local x = 1 - for i=2,n do - x = x * i - end - return x -end - -if arg and arg[1] then - print(fac(tonumber(arg[1]))) -else - assert(fac(10) == 3628800) -end diff --git a/test/misc/fastfib.lua b/test/misc/fastfib.lua deleted file mode 100644 index 80394bdd08..0000000000 --- a/test/misc/fastfib.lua +++ /dev/null @@ -1,26 +0,0 @@ - -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 - -if arg and arg[1] then - local n = tonumber(arg and arg[1]) or 10 - io.write(string.format("Fib(%d): %.0f\n", n, fib(n))) -else - assert(fib(40) == 165580141) - assert(fib(39) == 102334155) - assert(fib(77) == 8944394323791464) -end diff --git a/test/misc/fib.lua b/test/misc/fib.lua deleted file mode 100644 index 74eb046496..0000000000 --- a/test/misc/fib.lua +++ /dev/null @@ -1,11 +0,0 @@ -local function fib(n) - if n < 2 then return 1 end - return fib(n-2) + fib(n-1) -end - -if arg and arg[1] then - local n = tonumber(arg[1]) or 10 - io.write(string.format("Fib(%d): %d\n", n, fib(n))) -else - assert(fib(27) == 317811) -end diff --git a/test/misc/fuse.lua b/test/misc/fuse.lua deleted file mode 100644 index c4e077c87d..0000000000 --- a/test/misc/fuse.lua +++ /dev/null @@ -1,8 +0,0 @@ - --- Don't fuse i+101 on x64. --- Except if i is sign-extended to 64 bit or addressing is limited to 32 bit. -do - local t = {} - for i=-100,-1 do t[i+101] = 1 end -end - diff --git a/test/misc/fwd_hrefk_rollback.lua b/test/misc/fwd_hrefk_rollback.lua deleted file mode 100644 index 1c4d597923..0000000000 --- a/test/misc/fwd_hrefk_rollback.lua +++ /dev/null @@ -1,34 +0,0 @@ - --- 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)) - diff --git a/test/misc/libfuncs.lua b/test/misc/libfuncs.lua deleted file mode 100644 index d0cf42ff07..0000000000 --- a/test/misc/libfuncs.lua +++ /dev/null @@ -1,63 +0,0 @@ - -local function check(m, expected) - local t = {} - for k in pairs(m) do t[#t+1] = tostring(k) end - table.sort(t) - local got = table.concat(t, ":") - if got ~= expected then - error("got: \""..got.."\"\nexpected: \""..expected.."\"", 2) - end -end - -local bit = bit -_G.bit = nil -_G.jit = nil -table.setn = nil -package.searchpath = nil - -if os.getenv("LUA52") then - check(_G, "_G:_VERSION:arg:assert:collectgarbage:coroutine:debug:dofile:error:gcinfo:getfenv:getmetatable:io:ipairs:load:loadfile:loadstring:math:module:newproxy:next:os:package:pairs:pcall:print:rawequal:rawget:rawlen:rawset:require:select:setfenv:setmetatable:string:table:tonumber:tostring:type:unpack:xpcall") - check(math, "abs:acos:asin:atan:atan2:ceil:cos:cosh:deg:exp:floor:fmod:frexp:huge:ldexp:log:log10:max:min:modf:pi:pow:rad:random:randomseed:sin:sinh:sqrt:tan:tanh") - check(string, "byte:char:dump:find:format:gmatch:gsub:len:lower:match:rep:reverse:sub:upper") - check(table, "concat:foreach:foreachi:getn:insert:maxn:pack:remove:sort:unpack") -else - check(_G, "_G:_VERSION:arg:assert:collectgarbage:coroutine:debug:dofile:error:gcinfo:getfenv:getmetatable:io:ipairs:load:loadfile:loadstring:math:module:newproxy:next:os:package:pairs:pcall:print:rawequal:rawget:rawset:require:select:setfenv:setmetatable:string:table:tonumber:tostring:type:unpack:xpcall") - check(math, "abs:acos:asin:atan:atan2:ceil:cos:cosh:deg:exp:floor:fmod:frexp:huge:ldexp:log:log10:max:min:mod:modf:pi:pow:rad:random:randomseed:sin:sinh:sqrt:tan:tanh") - check(string, "byte:char:dump:find:format:gfind:gmatch:gsub:len:lower:match:rep:reverse:sub:upper") - check(table, "concat:foreach:foreachi:getn:insert:maxn:remove:sort") -end - -check(io, "close:flush:input:lines:open:output:popen:read:stderr:stdin:stdout:tmpfile:type:write") - -check(debug.getmetatable(io.stdin), "__gc:__index:__tostring:close:flush:lines:read:seek:setvbuf:write") - -check(os, "clock:date:difftime:execute:exit:getenv:remove:rename:setlocale:time:tmpname") - -if os.getenv("LUA52") then - check(debug, "debug:getfenv:gethook:getinfo:getlocal:getmetatable:getregistry:getupvalue:getuservalue:setfenv:sethook:setlocal:setmetatable:setupvalue:setuservalue:traceback:upvalueid:upvaluejoin") -else - check(debug, "debug:getfenv:gethook:getinfo:getlocal:getmetatable:getregistry:getupvalue:setfenv:sethook:setlocal:setmetatable:setupvalue:traceback:upvalueid:upvaluejoin") -end - -check(package, "config:cpath:loaded:loaders:loadlib:path:preload:seeall") - -check(package.loaders, "1:2:3:4") -package.loaded.bit = nil -package.loaded.jit = nil -package.loaded["jit.util"] = nil -package.loaded["jit.opt"] = nil -check(package.loaded, "_G:coroutine:debug:io:math:os:package:string:table") - -if bit then - check(bit, "arshift:band:bnot:bor:bswap:bxor:lshift:rol:ror:rshift:tobit:tohex") -end - -local ok, ffi = pcall(require, "ffi") -if ok then - check(ffi, "C:abi:alignof:arch:cast:cdef:copy:errno:fill:gc:istype:load:metatype:new:offsetof:os:sizeof:string:typeinfo:typeof") -end - -assert(math.pi == 3.141592653589793) -assert(math.huge > 0 and 1/math.huge == 0) -assert(debug.getmetatable("").__index == string) - diff --git a/test/misc/math_random.lua b/test/misc/math_random.lua deleted file mode 100644 index 391ee2d901..0000000000 --- a/test/misc/math_random.lua +++ /dev/null @@ -1,21 +0,0 @@ - -local random = math.random -local randomseed = math.randomseed - -do - local N = 1000 - local min, max = math.min, math.max - for j=1,100 do - randomseed(j) - local lo, hi, sum = math.huge, -math.huge, 0 - for i=1,N do - local x = random() - 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 - diff --git a/test/misc/modulo.lua b/test/misc/modulo.lua deleted file mode 100644 index fefb02cf1e..0000000000 --- a/test/misc/modulo.lua +++ /dev/null @@ -1,42 +0,0 @@ - -for x=-5,5 do - for y=-5,5 do - if y ~= 0 then - assert(x%y == x-math.floor(x/y)*y) - end - end -end - -for x=-5,5,0.25 do - for y=-5,5,0.25 do - if y ~= 0 then - assert(x%y == x-math.floor(x/y)*y) - end - end -end - -do - local y = 0 - for x=-100,123 do - y = y + x%17 - end - assert(y == 1777) -end - -do - local y = 0 - for x=-100,123 do - if x ~= 0 then - y = y + 85%x - end - end - assert(y == 2059) -end - -do - local x = 1%0 - assert(x ~= x) - x = math.floor(0/0) - assert(x ~= x) -end - diff --git a/test/misc/nsieve.lua b/test/misc/nsieve.lua deleted file mode 100644 index 49dc1c8df7..0000000000 --- a/test/misc/nsieve.lua +++ /dev/null @@ -1,20 +0,0 @@ -local function nsieve(m, 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 - -local flags = {} -if arg and arg[1] then - local N = tonumber(arg and arg[1]) - io.write(string.format("Primes up to %8d %8d", N, nsieve(N,flags)), "\n") -else - assert(nsieve(100, flags) == 25) - assert(nsieve(12345, flags) == 1474) -end diff --git a/test/misc/parse_andor.lua b/test/misc/parse_andor.lua deleted file mode 100644 index 2c796cb375..0000000000 --- a/test/misc/parse_andor.lua +++ /dev/null @@ -1,58 +0,0 @@ -local x = ((1 or false) and true) or false -assert(x == true) - -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("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 - -do - -- 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/misc/recsum.lua b/test/misc/recsum.lua deleted file mode 100644 index a25336d1c3..0000000000 --- a/test/misc/recsum.lua +++ /dev/null @@ -1,11 +0,0 @@ - -do - local function sum(n) - if n == 1 then return 1 end - return n + sum(n-1) - end - for i=1,tonumber(arg and arg[1]) or 100 do - assert(sum(100) == 5050) - end -end - diff --git a/test/misc/recsump.lua b/test/misc/recsump.lua deleted file mode 100644 index 2285018180..0000000000 --- a/test/misc/recsump.lua +++ /dev/null @@ -1,11 +0,0 @@ - -do - 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,tonumber(arg and arg[1]) or 100 do - assert(sum(100) == 5050) - end -end diff --git a/test/misc/self.lua b/test/misc/self.lua deleted file mode 100644 index afb95ce041..0000000000 --- a/test/misc/self.lua +++ /dev/null @@ -1,18 +0,0 @@ -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) - diff --git a/test/misc/snap_gcexit.lua b/test/misc/snap_gcexit.lua deleted file mode 100644 index 37fce65ae4..0000000000 --- a/test/misc/snap_gcexit.lua +++ /dev/null @@ -1,16 +0,0 @@ - -do - 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 - diff --git a/test/misc/snap_top.lua b/test/misc/snap_top.lua deleted file mode 100644 index a717a15989..0000000000 --- a/test/misc/snap_top.lua +++ /dev/null @@ -1,16 +0,0 @@ - -do - 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 - diff --git a/test/misc/snap_top2.lua b/test/misc/snap_top2.lua deleted file mode 100644 index 4504dc3e23..0000000000 --- a/test/misc/snap_top2.lua +++ /dev/null @@ -1,15 +0,0 @@ - -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 diff --git a/test/misc/sort.lua b/test/misc/sort.lua deleted file mode 100644 index 4b2e40129e..0000000000 --- a/test/misc/sort.lua +++ /dev/null @@ -1,23 +0,0 @@ --- Really a test for lua_lessthan() - -local N = 1000 - -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 - -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 - -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 - diff --git a/test/misc/string_char.lua b/test/misc/string_char.lua deleted file mode 100644 index 3920c3a4c2..0000000000 --- a/test/misc/string_char.lua +++ /dev/null @@ -1,28 +0,0 @@ - -do - local y - for i=1,100 do y = string.char(65) end - assert(y == "A") - local x = 97 - for i=1,100 do y = string.char(x) end - assert(y == "a") - x = "98" - for i=1,100 do y = string.char(x) end - assert(y == "b") - for i=1,100 do y = string.char(32+i) end - assert(y == "\132") -end - -do - local y - assert(not pcall(function() - for i=1,200 do y = string.char(100+i) end - end)) - assert(y == "\255") -end - -do - local y - for i=1,100 do y = string.char(65, 66, i, 67, 68) end - assert(y == "ABdCD") -end diff --git a/test/misc/string_sub.lua b/test/misc/string_sub.lua deleted file mode 100644 index 2cdfac766a..0000000000 --- a/test/misc/string_sub.lua +++ /dev/null @@ -1,60 +0,0 @@ - -local band, bor = bit.band, bit.bor -local sub = string.sub - --- Positive slice [i,len] or overflow -do - 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 - --- Negative slice [-i,len] or underflow -do - 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 - --- Positive slice [1,i] or overflow -do - 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 - --- Negative slice [1,-i] or underflow -do - 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 - diff --git a/test/misc/string_sub_opt.lua b/test/misc/string_sub_opt.lua deleted file mode 100644 index 235767aff8..0000000000 --- a/test/misc/string_sub_opt.lua +++ /dev/null @@ -1,109 +0,0 @@ - -do - local s = "abcde" - local x = 0 - for i=1,100 do - if string.sub(s, 1, 1) == "a" then x = x + 1 end - end - assert(x == 100) -end - -do - local s = "abcde" - local x = 0 - for i=1,100 do - if string.sub(s, 1, 1) == "b" then x = x + 1 end - end - assert(x == 0) -end - -do - local s = "abcde" - local x = 0 - for i=1,100 do - if string.sub(s, 1, 1) == "ab" then x = x + 1 end - end - assert(x == 0) -end - -do - local s = "abcde" - local x = 0 - for i=1,100 do - if string.sub(s, 1, 2) == "a" then x = x + 1 end - end - assert(x == 0) -end - -do - local s = "abcde" - local x = 0 - local k = 1 - for i=1,100 do - if string.sub(s, 1, k) == "a" then x = x + 1 end - end - assert(x == 100) -end - -do - local s = "abcde" - local x = 0 - local k = 1 - for i=1,100 do - if string.sub(s, 1, k) == "b" then x = x + 1 end - end - assert(x == 0) -end - -do - local s = "abcde" - local x = 0 - local k = 1 - for i=1,100 do - if string.sub(s, 1, k) == "ab" then x = x + 1 end - end - assert(x == 0) -end - ----- - -do - local s = "abcde" - local x = 0 - for i=1,100 do - if string.sub(s, 1, 2) == "ab" then x = x + 1 end - end - assert(x == 100) -end - -do - local s = "abcde" - local x = 0 - for i=1,100 do - if string.sub(s, 1, 3) == "abc" then x = x + 1 end - end - assert(x == 100) -end - -do - local s = "abcde" - local x = 0 - for i=1,100 do - if string.sub(s, 1, 4) == "abcd" then x = x + 1 end - end - assert(x == 100) -end - -do - 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/misc/tak.lua b/test/misc/tak.lua deleted file mode 100644 index a67478350c..0000000000 --- a/test/misc/tak.lua +++ /dev/null @@ -1,12 +0,0 @@ - -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 - -if arg and arg[1] then - local N = tonumber(arg and arg[1]) or 7 - print(tak(3*N, 2*N, N)) -else - assert(tak(21, 14, 7) == 14) -end diff --git a/test/misc/dse_array.lua b/test/opt/dse/array.lua similarity index 59% rename from test/misc/dse_array.lua rename to test/opt/dse/array.lua index af1725fe20..867a7372c7 100644 --- a/test/misc/dse_array.lua +++ b/test/opt/dse/array.lua @@ -1,200 +1,197 @@ - -local assert = assert - --- Same value ---------------------------------------------------------------- - --- 1. Store with same ref and same value. --- 2nd store eliminated. All stores in loop eliminated. -do - 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 - --- 2. Store with different tab, same idx and same value. --- All stores in loop eliminated. -do - 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 - --- 3. Store with same tab, different const idx and same value. --- All stores in loop eliminated. Also disambiguated. -do - 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 - --- 4. Store with different tab, different const idx and same value. --- All stores in loop eliminated. Also disambiguated. -do - 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 - --- 5. Store with different tab, different non-const idx and same value. --- All stores in loop eliminated. Not disambiguated (but not needed). -do - 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 - --- 6. Store with same ref, same value and aliased loads. --- 2nd store eliminated. Not disambiguated (but not needed). -do - 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 ----------------------------------------------------------- - --- 7. Store with same ref and different value. --- 1st store eliminated. All stores in loop eliminated. -do - 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 - --- 8. Store with different tab, same idx and different value. --- Cannot eliminate any stores (would need dynamic disambiguation). -do - 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 - --- 9. Store with same tab, different const idx and different value. --- Disambiguated. All stores in loop eliminated. -do - 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 - --- 10. Store with different tab, different const idx and different value. --- Disambiguated. All stores in loop eliminated. -do - 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 - --- 11. Store with different tab, different non-const idx and different value. --- Cannot eliminate any stores (would need dynamic disambiguation). -do - 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 - --- 12. Store with same ref, different value and aliased loads. --- Cannot eliminate any stores (would need dynamic disambiguation). -do - 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 - --- CALLL must inhibit DSE. -do - 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 - +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/misc/dse_field.lua b/test/opt/dse/field.lua similarity index 72% rename from test/misc/dse_field.lua rename to test/opt/dse/field.lua index 497cd9ecfe..9b544577fb 100644 --- a/test/misc/dse_field.lua +++ b/test/opt/dse/field.lua @@ -1,77 +1,70 @@ - -local getmetatable, setmetatable = getmetatable, setmetatable - --- 1. Store with same ref and same value. All stores in loop eliminated. -do - 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 - --- 2. Store with different ref and same value. All stores in loop eliminated. -do - 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 - --- 3. Store with different ref and different value. Cannot eliminate any stores. -do - 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 - --- 4. Store with same ref and different value. 2nd store remains in loop. -do - 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 - --- 5. Store with same ref, different value and aliased loads. --- Cannot eliminate any stores. -do - 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 - +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/opt/dse/index b/test/opt/dse/index new file mode 100644 index 0000000000..6d9d9478ec --- /dev/null +++ b/test/opt/dse/index @@ -0,0 +1,2 @@ +array.lua +field.lua diff --git a/test/opt/fold/index b/test/opt/fold/index new file mode 100644 index 0000000000..3bc303fd0c --- /dev/null +++ b/test/opt/fold/index @@ -0,0 +1 @@ +kfold.lua diff --git a/test/misc/kfold.lua b/test/opt/fold/kfold.lua similarity index 93% rename from test/misc/kfold.lua rename to test/opt/fold/kfold.lua index 1a532f16d8..1db29084db 100644 --- a/test/misc/kfold.lua +++ b/test/opt/fold/kfold.lua @@ -1,81 +1,81 @@ - -do - 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) - for i=1,100 do local a, b = 8, 11.5; y = a^b end; assert(y == 8^11.5) -end - -do - 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 - 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 - 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 - 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 - 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 - -assert((10^-2 - 0.01) == 0) +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 + assert((10^-2 - 0.01) == 0) +end diff --git a/test/opt/fuse.lua b/test/opt/fuse.lua new file mode 100644 index 0000000000..57c5c9df03 --- /dev/null +++ b/test/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/opt/fwd/hrefk_rollback.lua b/test/opt/fwd/hrefk_rollback.lua new file mode 100644 index 0000000000..32ba95d28c --- /dev/null +++ b/test/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/opt/fwd/index b/test/opt/fwd/index new file mode 100644 index 0000000000..74d3bdbd69 --- /dev/null +++ b/test/opt/fwd/index @@ -0,0 +1,3 @@ +hrefk_rollback.lua +tnew_tdup.lua +upval.lua diff --git a/test/misc/fwd_tnew_tdup.lua b/test/opt/fwd/tnew_tdup.lua similarity index 80% rename from test/misc/fwd_tnew_tdup.lua rename to test/opt/fwd/tnew_tdup.lua index 105263ca08..375863f69f 100644 --- a/test/misc/fwd_tnew_tdup.lua +++ b/test/opt/fwd/tnew_tdup.lua @@ -1,78 +1,69 @@ - --- 1. -do - local x = 2 - for i=1,100 do - local t = {} -- TNEW: DCE - x = t.foo -- HREF -> niltv: folded - end - assert(x == nil) -end - --- 2. -do - local x = 2 - for i=1,100 do - local t = {1} -- TDUP: DCE - x = t.foo -- HREF -> niltv: folded - end - assert(x == nil) -end - --- 3. -do - 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 - --- 4. HREFK not eliminated. Ditto for the EQ(FLOAD(t, #tab.hmask), k). -do - 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 - --- 5. HREFK not eliminated. Ditto for the EQ(FLOAD(t, #tab.hmask), k). -do - 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 - --- 6. -do - 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 - --- 7. -do - 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 - +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/misc/fwd_upval.lua b/test/opt/fwd/upval.lua similarity index 60% rename from test/misc/fwd_upval.lua rename to test/opt/fwd/upval.lua index 7fb360d2d3..5bc1cc96cb 100644 --- a/test/misc/fwd_upval.lua +++ b/test/opt/fwd/upval.lua @@ -1,57 +1,50 @@ - --- 1. Open upvalue above base slot, aliasing an SSA value. -do - 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 - --- 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). -do - 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 - --- 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). -do - 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 - --- 4. Open upvalue below base slot. Forwarded. 1x USTORE (+ 1x DSE USTORE). -do - local x = 7 - (function() - local function a() x = x + 1 end - for i=1,100 do a(); a() end - end)() - assert(x == 207) -end - --- 5. Closed upvalue. Forwarded. 1x USTORE (+ 1x DSE USTORE). -do - 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 - +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/opt/index b/test/opt/index new file mode 100644 index 0000000000..2aeaa8f16d --- /dev/null +++ b/test/opt/index @@ -0,0 +1,6 @@ +dse +dse +fold +fold +fwd +fwd +fuse.lua +fuse +loop +loop +sink +sink diff --git a/test/opt/loop/index b/test/opt/loop/index new file mode 100644 index 0000000000..321efe23fb --- /dev/null +++ b/test/opt/loop/index @@ -0,0 +1 @@ +unroll.lua diff --git a/test/opt/loop/unroll.lua b/test/opt/loop/unroll.lua new file mode 100644 index 0000000000..4c856a5813 --- /dev/null +++ b/test/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/misc/sink_alloc.lua b/test/opt/sink/alloc.lua similarity index 76% rename from test/misc/sink_alloc.lua rename to test/opt/sink/alloc.lua index 55f4218e63..a83e8f05ac 100644 --- a/test/misc/sink_alloc.lua +++ b/test/opt/sink/alloc.lua @@ -1,140 +1,126 @@ - -local assert = assert - --- DCE or sink trivial TNEW or TDUP. -do - for i=1,100 do local t={} end - for i=1,100 do local t={1} end -end - --- Sink TNEW/TDUP + ASTORE/HSTORE. -do - 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 - --- Sink outermost table of nested TNEW. -do - 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 - --- Sink one TNEW + FSTORE. -do - for i=1,100 do local t = setmetatable({}, {}) end -end - --- Sink TDUP or TDUP + HSTORE. Guard of HREFK eliminated. -do - 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 - --- Sink of simplified complex add, unused in next iteration, drop PHI. -do - 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 - --- Sink of complex add, unused in next iteration, drop PHI. -do - 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 - --- Sink of TDUP with stored values that are both PHI and non-PHI. -do - 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 - --- Sink of CONV. -do - 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 - --- Sink of stores with numbers. -do - 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 - --- Sink of stores with constants. -do - for i=1,100 do local t = {false}; t[1] = true; if i > 100 then g=t end end -end - --- Sink with two references to the same table. -do - for i=1,200 do - local t = {i} - local q = t - if i > 100 then assert(t == q) end - end -end - -do - 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 - 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 - +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/opt/sink/index b/test/opt/sink/index new file mode 100644 index 0000000000..b3a78ebe09 --- /dev/null +++ b/test/opt/sink/index @@ -0,0 +1,2 @@ +alloc.lua +nosink.lua diff --git a/test/misc/sink_nosink.lua b/test/opt/sink/nosink.lua similarity index 64% rename from test/misc/sink_nosink.lua rename to test/opt/sink/nosink.lua index 5badfd2690..3a1bdf0752 100644 --- a/test/misc/sink_nosink.lua +++ b/test/opt/sink/nosink.lua @@ -1,124 +1,109 @@ - -local assert = assert - --- Cannot sink TNEW, aliased load. -do - 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 - --- Cannot sink TNEW, escaping to upvalue. -do - (function() - local uv - return function() - for i=1,100 do uv = {i} end - assert(uv[1] == 100) - end - end)()() -end - --- Cannot sink TNEW, escaping through a store. -do - 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 - --- Cannot sink TNEW, iteratively escaping through a store. -do - local t = {} - for i=1,100 do t[1] = {i}; t[1][1] = {i} end - assert(t[1][1][1] == 100) -end - --- Cannot sink TNEW, escaping to next iteration (unused in 1st variant). -do - 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 - --- Cannot sink TNEW, escaping to next iteration (snapshot ref). -do - local t,x - for i=1,100 do x=t; t={i} end - assert(t[1] == 100) - assert(x[1] == 99) -end - --- Cannot sink TNEW, escaping to next iteration (IR/snapshot ref). -do - local t - for i=1,100 do t={t} end - assert(type(t[1][1][1]) == "table") -end - --- Could sink outer TNEW, but the logic for stores to PHI allocs is too simple. --- Cannot sink inner TNEW, escaping to next iteration (IR ref). -do - 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 - --- Cannot sink TNEW, cross-PHI ref (and snapshot ref). -do - local x,y - for i=1,100 do x,y={i},x end - assert(x[1] == 100) - assert(y[1] == 99) -end - --- Cannot sink TNEW, cross-PHI ref (and snapshot ref). -do - local x,y - for i=1,100 do x,y=y,{i} end - assert(x[1] == 99) - assert(y[1] == 100) -end - --- Cannot sink TNEW, escaping to exit. -do - 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 - --- Cannot sink TNEW, escaping to exit. -do - 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 - t = f(3) - assert(t[1][1][1] == 42) -end - --- Cannot sink, since nested inner table is non-PHI. -do - 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 - +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/clib/cpptest.cpp b/test/src/cpptest.cpp similarity index 100% rename from test/clib/cpptest.cpp rename to test/src/cpptest.cpp diff --git a/test/clib/ctest.c b/test/src/ctest.c similarity index 100% rename from test/clib/ctest.c rename to test/src/ctest.c diff --git a/test/test.lua b/test/test.lua new file mode 100644 index 0000000000..bf16c2745a --- /dev/null +++ b/test/test.lua @@ -0,0 +1,409 @@ +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 + + -- 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, #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 + if not opts.quiet then + local file, name = plan_i[1], plan_i[2] + 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 + 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/misc/exit_frame.lua b/test/trace/exit_frame.lua similarity index 84% rename from test/misc/exit_frame.lua rename to test/trace/exit_frame.lua index 897984872b..c8297cb0bc 100644 --- a/test/misc/exit_frame.lua +++ b/test/trace/exit_frame.lua @@ -1,80 +1,79 @@ -do - 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 - 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 - 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 - 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 - +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/trace/exit_growstack.lua b/test/trace/exit_growstack.lua new file mode 100644 index 0000000000..20accdf8bb --- /dev/null +++ b/test/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/trace/exit_jfuncf.lua b/test/trace/exit_jfuncf.lua new file mode 100644 index 0000000000..4895fbf0a7 --- /dev/null +++ b/test/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/trace/index b/test/trace/index new file mode 100644 index 0000000000..00e4d3badc --- /dev/null +++ b/test/trace/index @@ -0,0 +1,5 @@ +exit_frame.lua +exit_growstack.lua +exit_jfuncf.lua +snap.lua +stitch.lua diff --git a/test/trace/snap.lua b/test/trace/snap.lua new file mode 100644 index 0000000000..ca31595f0e --- /dev/null +++ b/test/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/misc/stitch.lua b/test/trace/stitch.lua similarity index 86% rename from test/misc/stitch.lua rename to test/trace/stitch.lua index 1eba1810bb..55ce5c4151 100644 --- a/test/misc/stitch.lua +++ b/test/trace/stitch.lua @@ -1,21 +1,19 @@ - -do - 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 - 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 - +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 From 74d256ffcd4eafd5868a7a808752d5bc371dad82 Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Sat, 9 Apr 2016 15:19:21 +0100 Subject: [PATCH 21/68] Remove some already-modernised tests from misc. --- test/misc/getfenv.lua | 15 --------------- test/misc/parse_hex.lua | 7 ------- test/misc/strcmp.lua | 11 ----------- 3 files changed, 33 deletions(-) delete mode 100644 test/misc/getfenv.lua delete mode 100644 test/misc/parse_hex.lua delete mode 100644 test/misc/strcmp.lua diff --git a/test/misc/getfenv.lua b/test/misc/getfenv.lua deleted file mode 100644 index 48a261a7a0..0000000000 --- a/test/misc/getfenv.lua +++ /dev/null @@ -1,15 +0,0 @@ - -do - 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/misc/parse_hex.lua b/test/misc/parse_hex.lua deleted file mode 100644 index bb6da92538..0000000000 --- a/test/misc/parse_hex.lua +++ /dev/null @@ -1,7 +0,0 @@ -assert(1e5 == 100000) -assert(1e+5 == 100000) -assert(1e-5 == 0.00001) -assert(0xe+9 == 23) -assert(0xep9 == 7168) -assert(0xep+9 == 7168) -assert(0xep-9 == 0.02734375) diff --git a/test/misc/strcmp.lua b/test/misc/strcmp.lua deleted file mode 100644 index 53d1ce5f0e..0000000000 --- a/test/misc/strcmp.lua +++ /dev/null @@ -1,11 +0,0 @@ - -do - 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 - From b8bbda318eeee305f1cadd09d96c9cd59ba63ef2 Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Sat, 9 Apr 2016 15:15:40 +0100 Subject: [PATCH 22/68] Modernise goto test. --- test/{misc => lang}/goto.lua | 81 ++++++++++++++++-------------------- test/lang/index | 1 + test/test.lua | 3 ++ 3 files changed, 41 insertions(+), 44 deletions(-) rename test/{misc => lang}/goto.lua (66%) diff --git a/test/misc/goto.lua b/test/lang/goto.lua similarity index 66% rename from test/misc/goto.lua rename to test/lang/goto.lua index 8553a8aa90..1563a234ae 100644 --- a/test/misc/goto.lua +++ b/test/lang/goto.lua @@ -1,15 +1,15 @@ +local loadstring = loadstring or load --- Basic goto and label semantics. -do - local function expect(src, msg) - local ok, err = loadstring(src) - if msg then - assert(not ok and string.find(err, msg)) - else - assert(ok) - end +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'") @@ -27,17 +27,18 @@ do expect("do local v,w; goto a; end; local x; ::a:: local y", "'x'") expect("repeat goto a; local x; ::a:: until x", "'x'") - if os.getenv("LUA52") then - expect("goto = 1", "") - else - expect("goto = 1") - end - ::a:: do goto a; ::a:: end -- Forward jump, not an infinite loop. end --- Trailing label is considered to be out of scope. -do +do --- Goto is not a keyword. -compat5.2 !lex !private_G + goto = 1 +end + +do --- Goto is a keyword. +compat5.2 + expect("goto = 1", "") +end + +do --- Trailing label is considered to be out of scope. local x = 11 do goto a @@ -48,24 +49,22 @@ do ::b:: end assert(x == 11) - if os.getenv("LUA52") then - assert(loadstring([[ - local x = 11 - do - goto a - goto a - local y = 22 - x = y - ::a:: ;; - ::b:: ;; - end - return 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 --- Simple loop with cross-jumping. -do +do --- Simple loop with cross-jumping. local x = 1 while true do goto b @@ -78,8 +77,7 @@ do assert(x == 100) end --- Backwards goto must close upval. -do +do --- Backwards goto must close upval. local t = {} local i = 1 ::a:: @@ -92,8 +90,7 @@ do assert(t[2]() == 2) end --- Break must close upval, even if closure is parsed after break. -do +do --- Break must close upval, even if closure is parsed after break. local foo repeat local x @@ -106,8 +103,7 @@ do assert(foo() == true) end --- Label prevents joining to KNIL. -do +do --- Label prevents joining to KNIL. -lua==5.2 local k = 0 local x ::foo:: @@ -118,8 +114,7 @@ do if k < 2 then goto foo end end --- Break resolved from the right scope. -do +do --- Break resolved from the right scope. local function p(lvl) lvl = lvl or 1 while true do @@ -134,8 +129,7 @@ do end end --- Do not join twice with UCLO. -do +do --- Do not join twice with UCLO. while true do do local x @@ -153,4 +147,3 @@ do end ::foo:: end - diff --git a/test/lang/index b/test/lang/index index 743c5bce9e..1cdf404ee6 100644 --- a/test/lang/index +++ b/test/lang/index @@ -10,3 +10,4 @@ upvalue coroutine.lua tail_recursion.lua gc.lua +goto.lua +goto diff --git a/test/test.lua b/test/test.lua index bf16c2745a..e31660185d 100644 --- a/test/test.lua +++ b/test/test.lua @@ -18,6 +18,9 @@ local function default_tags() 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 From f40304dded5d07a0dd755751c811cd8ccaf9565b Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Sat, 9 Apr 2016 15:29:53 +0100 Subject: [PATCH 23/68] Modernise string_op test. --- test/lib/string/index | 2 + test/lib/string/lower_upper.lua | 35 ++++++++ test/lib/string/multiple_functions.lua | 16 ++++ test/lib/string/rep.lua | 47 +++++++++++ test/lib/string/reverse.lua | 13 +++ test/misc/string_op.lua | 110 ------------------------- 6 files changed, 113 insertions(+), 110 deletions(-) create mode 100644 test/lib/string/multiple_functions.lua create mode 100644 test/lib/string/reverse.lua delete mode 100644 test/misc/string_op.lua diff --git a/test/lib/string/index b/test/lib/string/index index a51f80651c..bad5cffec2 100644 --- a/test/lib/string/index +++ b/test/lib/string/index @@ -5,5 +5,7 @@ dump.lua format len.lua lower_upper.lua +multiple_functions.lua rep.lua +reverse.lua sub.lua diff --git a/test/lib/string/lower_upper.lua b/test/lib/string/lower_upper.lua index 52c5739706..1a05fc353c 100644 --- a/test/lib/string/lower_upper.lua +++ b/test/lib/string/lower_upper.lua @@ -14,3 +14,38 @@ do --- repeated 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/lib/string/multiple_functions.lua b/test/lib/string/multiple_functions.lua new file mode 100644 index 0000000000..725803d66d --- /dev/null +++ b/test/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/lib/string/rep.lua b/test/lib/string/rep.lua index d06b4ee4ed..5a27e5321b 100644 --- a/test/lib/string/rep.lua +++ b/test/lib/string/rep.lua @@ -1,3 +1,5 @@ +local rep = string.rep + do --- smoke assert(("p"):rep(0) == "") assert(("a"):rep(3) == "aaa") @@ -11,3 +13,48 @@ do --- versus concat 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") + for i=1,100 do y = rep("ab", 10, "c") end + assert(y == "abcabcabcabcabcabcabcabcabcab") + 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 --- iterate to table + local t = {} + for i=1,100 do t[i] = rep("ab", i-85) end + assert(t[100] == "ababababababababababababababab") + 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/lib/string/reverse.lua b/test/lib/string/reverse.lua new file mode 100644 index 0000000000..34a8ffb013 --- /dev/null +++ b/test/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/misc/string_op.lua b/test/misc/string_op.lua deleted file mode 100644 index 6adb790ee2..0000000000 --- a/test/misc/string_op.lua +++ /dev/null @@ -1,110 +0,0 @@ - -do - local y - for i=1,100 do y = string.reverse("abc") end - assert(y == "cba") - local x = "abcd" - for i=1,100 do y = string.reverse(x) end - assert(y == "dcba") - x = 1234 - for i=1,100 do y = string.reverse(x) end - assert(y == "4321") -end - -do - 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 - 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 - -do - 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 - -do - 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 - local y - for i=1,100 do y = string.rep("a", 10) end - assert(y == "aaaaaaaaaa") - for i=1,100 do y = string.rep("ab", 10) end - assert(y == "abababababababababab") - for i=1,100 do y = string.rep("ab", 10, "c") end - assert(y == "abcabcabcabcabcabcabcabcabcab") - local x = "a" - for i=1,100 do y = string.rep(x, 10) end - assert(y == "aaaaaaaaaa") - local n = 10 - for i=1,100 do y = string.rep(x, n) end - assert(y == "aaaaaaaaaa") - x = "ab" - for i=1,100 do y = string.rep(x, n) end - assert(y == "abababababababababab") - x = 12 - n = "10" - for i=1,100 do y = string.rep(x, n) end - assert(y == "12121212121212121212") -end - -do - local t = {} - for i=1,100 do t[i] = string.rep("ab", i-85) end - assert(t[100] == "ababababababababababababababab") - for i=1,100 do t[i] = string.rep("ab", i-85, "c") end - assert(t[85] == "") - assert(t[86] == "ab") - assert(t[87] == "abcab") - assert(t[100] == "abcabcabcabcabcabcabcabcabcabcabcabcabcabcab") -end - -do - local y, z - local x = "ab" - for i=1,100 do - y = string.rep(x, i-90) - z = y.."fgh" - end - assert(y == "abababababababababab") - assert(z == "ababababababababababfgh") -end - From e002a085ddb075099c0a18fc4f09d928ff9334bd Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Sat, 9 Apr 2016 17:22:43 +0100 Subject: [PATCH 24/68] Improve reporting of failing tests in --quiet mode. --- test/test.lua | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/test.lua b/test/test.lua index e31660185d..1e842d4333 100644 --- a/test/test.lua +++ b/test/test.lua @@ -370,13 +370,17 @@ local function execute_plan(plan, opts) 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 - local file, name = plan_i[1], plan_i[2] 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 From 6a7e3429706507f057e0cfd14d11b36ef5513bd7 Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Sat, 9 Apr 2016 17:28:21 +0100 Subject: [PATCH 25/68] Modernise misc/meta_* tests. --- test/lang/compare.lua | 74 +++++++++ test/lang/index | 1 + test/lang/meta/arith.lua | 118 ++++++++++++++ .../meta/arith_jit.lua} | 8 +- .../meta_call.lua => lang/meta/call.lua} | 41 ++--- test/{misc/meta_cat.lua => lang/meta/cat.lua} | 19 ++- test/lang/meta/comp.lua | 120 ++++++++++++++ test/lang/meta/comp_jit.lua | 104 ++++++++++++ test/lang/meta/eq.lua | 30 ++++ .../meta_eq_jit.lua => lang/meta/eq_jit.lua} | 5 +- test/lang/meta/framegap.lua | 24 +++ test/lang/meta/index | 13 ++ test/lang/meta/index.lua | 60 +++++++ test/{misc/meta_len.lua => lang/meta/len.lua} | 21 ++- test/lang/meta/newindex.lua | 69 ++++++++ .../meta_nomm.lua => lang/meta/nomm.lua} | 2 +- .../base/getsetmetatable.lua} | 9 +- test/lib/base/index | 2 + .../meta_pairs.lua => lib/base/pairs.lua} | 6 +- test/misc/meta_arith.lua | 103 ------------ test/misc/meta_comp.lua | 151 ------------------ test/misc/meta_comp_jit.lua | 104 ------------ test/misc/meta_eq.lua | 66 -------- test/misc/meta_framegap.lua | 23 --- test/misc/meta_tget.lua | 25 --- test/misc/meta_tget_nontab.lua | 33 ---- test/misc/meta_tset.lua | 15 -- test/misc/meta_tset_nilget.lua | 23 --- test/misc/meta_tset_resize.lua | 10 -- test/misc/meta_tset_str.lua | 18 --- 30 files changed, 670 insertions(+), 627 deletions(-) create mode 100644 test/lang/meta/arith.lua rename test/{misc/meta_arith_jit.lua => lang/meta/arith_jit.lua} (96%) rename test/{misc/meta_call.lua => lang/meta/call.lua} (70%) rename test/{misc/meta_cat.lua => lang/meta/cat.lua} (94%) create mode 100644 test/lang/meta/comp.lua create mode 100644 test/lang/meta/comp_jit.lua create mode 100644 test/lang/meta/eq.lua rename test/{misc/meta_eq_jit.lua => lang/meta/eq_jit.lua} (95%) create mode 100644 test/lang/meta/framegap.lua create mode 100644 test/lang/meta/index create mode 100644 test/lang/meta/index.lua rename test/{misc/meta_len.lua => lang/meta/len.lua} (75%) create mode 100644 test/lang/meta/newindex.lua rename test/{misc/meta_nomm.lua => lang/meta/nomm.lua} (96%) rename test/{misc/meta_getset.lua => lib/base/getsetmetatable.lua} (89%) rename test/{misc/meta_pairs.lua => lib/base/pairs.lua} (94%) delete mode 100644 test/misc/meta_arith.lua delete mode 100644 test/misc/meta_comp.lua delete mode 100644 test/misc/meta_comp_jit.lua delete mode 100644 test/misc/meta_eq.lua delete mode 100644 test/misc/meta_framegap.lua delete mode 100644 test/misc/meta_tget.lua delete mode 100644 test/misc/meta_tget_nontab.lua delete mode 100644 test/misc/meta_tset.lua delete mode 100644 test/misc/meta_tset_nilget.lua delete mode 100644 test/misc/meta_tset_resize.lua delete mode 100644 test/misc/meta_tset_str.lua diff --git a/test/lang/compare.lua b/test/lang/compare.lua index fdabef5e8d..9b38ff5e2f 100644 --- a/test/lang/compare.lua +++ b/test/lang/compare.lua @@ -247,3 +247,77 @@ do --- string 1 255 assert(a >= b) assert(b <= a) end + +do --- String comparisons: + local function str_cmp(a, b, lt, gt, le, ge) + assert(ab == gt) + assert(a<=b == le) + assert(a>=b == ge) + assert((not (ab)) == (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/lang/index b/test/lang/index index 1cdf404ee6..457490ef30 100644 --- a/test/lang/index +++ b/test/lang/index @@ -11,3 +11,4 @@ coroutine.lua tail_recursion.lua gc.lua goto.lua +goto +meta diff --git a/test/lang/meta/arith.lua b/test/lang/meta/arith.lua new file mode 100644 index 0000000000..17de4c8cde --- /dev/null +++ b/test/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/misc/meta_arith_jit.lua b/test/lang/meta/arith_jit.lua similarity index 96% rename from test/misc/meta_arith_jit.lua rename to test/lang/meta/arith_jit.lua index 485cebf53e..2cb35dbb37 100644 --- a/test/misc/meta_arith_jit.lua +++ b/test/lang/meta/arith_jit.lua @@ -1,5 +1,5 @@ -do +do --- assert rhs local t = {} local mt = { __add = function(a, b) assert(b == t); return a+11 end, @@ -20,7 +20,7 @@ do do local x = 0; for i=1,100 do x = x + (-t) end; assert(x == 1700); end end -do +do --- assert lhs local t = {} local mt = { __add = function(a, b) assert(a == t); return b+11 end, @@ -39,7 +39,7 @@ do do local x = 0; for i=1,100 do x = t ^ x end; assert(x == 1600); end end -do +do --- assert both sides local t = {} local mt = { __add = function(a, b) assert(a == t and b == t); return 11 end, @@ -58,7 +58,7 @@ do do local x = 0; for i=1,100 do x = t ^ t end; assert(x == 16); end end -do +do --- adjust no result to one result local t = {} local mt = { __add = function(a, b) end } t = setmetatable(t, mt) diff --git a/test/misc/meta_call.lua b/test/lang/meta/call.lua similarity index 70% rename from test/misc/meta_call.lua rename to test/lang/meta/call.lua index 5cc22be109..c77c0dd8ff 100644 --- a/test/misc/meta_call.lua +++ b/test/lang/meta/call.lua @@ -5,7 +5,7 @@ end local meta = { __call = callmeta } -do +do --- table local t = setmetatable({}, meta) local o,a,b = t() assert(o == t and a == nil and b == nil) @@ -15,7 +15,7 @@ do assert(o == t and a == "foo" and b == "bar") end -do +do --- userdata +lua<5.2 local u = newproxy(true) getmetatable(u).__call = callmeta @@ -27,16 +27,18 @@ do assert(o == u and a == "foo" and b == "bar") end -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) +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 +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 @@ -47,32 +49,33 @@ do assert(o == ta and a == nil) end -do +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 +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 -debug.setmetatable(0, { __call = function(n) return 100-n end }) -for i=1,100 do assert((i)() == 100-i) end -debug.setmetatable(0, nil) +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 +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 +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/misc/meta_cat.lua b/test/lang/meta/cat.lua similarity index 94% rename from test/misc/meta_cat.lua rename to test/lang/meta/cat.lua index 6f9e9fff39..48a89e4d68 100644 --- a/test/misc/meta_cat.lua +++ b/test/lang/meta/cat.lua @@ -1,16 +1,15 @@ +local function create(cat, v1, v2) + local meta = { __concat = cat } + return setmetatable({v1}, meta), setmetatable({v2}, meta) +end -do +do --- default local a, b, c = "foo", "bar", "baz" assert(a..b == "foobar") assert(a..b..c == "foobarbaz") end -local function create(cat, v1, v2) - local meta = { __concat = cat } - return setmetatable({v1}, meta), setmetatable({v2}, meta) -end - -do +do --- lhs local a, b = create(function(a, b) return a end) assert(a..b == a) assert(b..a == b) @@ -20,7 +19,7 @@ do assert(a..b..b..b..b..b..b..b == a) end -do +do --- rhs local a, b = create(function(a, b) return b end) assert(a..b == b) assert(b..a == a) @@ -30,7 +29,7 @@ do assert(a..a..a..a..a..a..a..b == b) end -do +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]) @@ -45,7 +44,7 @@ do assert(a..b..a..b..a.."x".."x".."x" == "ababaxxx") end -do +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]).. diff --git a/test/lang/meta/comp.lua b/test/lang/meta/comp.lua new file mode 100644 index 0000000000..23f18b08ec --- /dev/null +++ b/test/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(ab == 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 (ab) == 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(ab == 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 (ab) == 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(ab == 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 (ab) == 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 == false) + assert(a<=b == true) + assert(a>=b == false) + + assert(not (ab) == true) + assert(not (a<=b) == false) + assert(not (a>=b) == true) + + b[1] = 1 + assert(ab == false) + assert(a<=b == true) + assert(a>=b == true) + + assert(not (ab) == true) + assert(not (a<=b) == false) + assert(not (a>=b) == false) + + a[1] = 2 + assert(ab == true) + assert(a<=b == false) + assert(a>=b == true) + + assert(not (ab) == 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(ab == false) + assert(a<=b == true) + assert(a>=b == false) + + assert(not (ab) == true) + assert(not (a<=b) == false) + assert(not (a>=b) == true) + + b[1] = 1 + assert(ab == false) + assert(a<=b == true) + assert(a>=b == true) + + assert(not (ab) == true) + assert(not (a<=b) == false) + assert(not (a>=b) == false) + + a[1] = 2 + assert(ab == true) + assert(a<=b == false) + assert(a>=b == true) + + assert(not (ab) == false) + assert(not (a<=b) == true) + assert(not (a>=b) == false) +end diff --git a/test/lang/meta/comp_jit.lua b/test/lang/meta/comp_jit.lua new file mode 100644 index 0000000000..d0a19d80a2 --- /dev/null +++ b/test/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/lang/meta/eq.lua b/test/lang/meta/eq.lua new file mode 100644 index 0000000000..ebf604357c --- /dev/null +++ b/test/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/misc/meta_eq_jit.lua b/test/lang/meta/eq_jit.lua similarity index 95% rename from test/misc/meta_eq_jit.lua rename to test/lang/meta/eq_jit.lua index ad5d68f18b..47e14207cf 100644 --- a/test/misc/meta_eq_jit.lua +++ b/test/lang/meta/eq_jit.lua @@ -1,5 +1,5 @@ -do +do --- coverage local eq = false local t, u = {}, {} local x, ax, bx @@ -25,7 +25,7 @@ do x = 0; for i=1,100 do x = not (t ~= u) and 2 or 1 end ck(2, t, u) end -do +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) } @@ -33,4 +33,3 @@ do assert(tt[0] == tt[bit.band(i, 1)]) end end - diff --git a/test/lang/meta/framegap.lua b/test/lang/meta/framegap.lua new file mode 100644 index 0000000000..0080633a24 --- /dev/null +++ b/test/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/lang/meta/index b/test/lang/meta/index new file mode 100644 index 0000000000..bf2f457625 --- /dev/null +++ b/test/lang/meta/index @@ -0,0 +1,13 @@ +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 diff --git a/test/lang/meta/index.lua b/test/lang/meta/index.lua new file mode 100644 index 0000000000..4d6d0ffee3 --- /dev/null +++ b/test/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/misc/meta_len.lua b/test/lang/meta/len.lua similarity index 75% rename from test/misc/meta_len.lua rename to test/lang/meta/len.lua index 6e77678de5..2410daa617 100644 --- a/test/misc/meta_len.lua +++ b/test/lang/meta/len.lua @@ -1,8 +1,6 @@ - -local lua52 = os.getenv("LUA52") - +local compat52 = table.pack local mt = { __len = function(o, o2) - if lua52 then + if compat52 then assert(o2 == o) else assert(o2 == nil) @@ -10,7 +8,7 @@ local mt = { __len = function(o, o2) return 42 end } -do +do --- table local t = {1,2,3} assert(#t == 3) assert(#"abcdef" == 6) @@ -20,7 +18,7 @@ do assert(#t == 3) setmetatable(t, mt) - if lua52 then + if compat52 then assert(#t == 42) -- __len DOES work on tables. assert(rawlen(t) == 3) else @@ -28,7 +26,7 @@ do end end -do +do --- userdata +lua<5.2 local u = newproxy(true) getmetatable(u).__len = function(o) return 42 end assert(#u == 42) @@ -37,7 +35,8 @@ do assert(x == 4200) end -debug.setmetatable(0, mt) -assert(#1 == 42) -debug.setmetatable(0, nil) - +do --- number + debug.setmetatable(0, mt) + assert(#1 == 42) + debug.setmetatable(0, nil) +end diff --git a/test/lang/meta/newindex.lua b/test/lang/meta/newindex.lua new file mode 100644 index 0000000000..6c46b8cbdc --- /dev/null +++ b/test/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/misc/meta_nomm.lua b/test/lang/meta/nomm.lua similarity index 96% rename from test/misc/meta_nomm.lua rename to test/lang/meta/nomm.lua index 457d0ee288..2b3db86fd1 100644 --- a/test/misc/meta_nomm.lua +++ b/test/lang/meta/nomm.lua @@ -1,5 +1,5 @@ -do +do --- untitled local keys = {} for i=1,100 do keys[i] = "foo" end keys[95] = "__index" diff --git a/test/misc/meta_getset.lua b/test/lib/base/getsetmetatable.lua similarity index 89% rename from test/misc/meta_getset.lua rename to test/lib/base/getsetmetatable.lua index 3f5c1da19c..7d57343ec5 100644 --- a/test/misc/meta_getset.lua +++ b/test/lib/base/getsetmetatable.lua @@ -1,17 +1,17 @@ -do +do --- get __metatable local t = setmetatable({}, { __metatable = "foo" }) for i=1,100 do assert(getmetatable(t) == "foo") end end -do +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 +do --- jit assorted local mt = {} local t = {} for i=1,200 do t[i] = setmetatable({}, mt) end @@ -26,9 +26,8 @@ do for i=1,200 do assert(getmetatable(t[i]) == nil or i == 150) end end -do +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/lib/base/index b/test/lib/base/index index 16adea05e2..c9ddd19535 100644 --- a/test/lib/base/index +++ b/test/lib/base/index @@ -1,5 +1,7 @@ assert.lua error.lua getfenv.lua +lua<5.2 +getsetmetatable.lua +pairs.lua select.lua xpcall_jit.lua +compat5.2 diff --git a/test/misc/meta_pairs.lua b/test/lib/base/pairs.lua similarity index 94% rename from test/misc/meta_pairs.lua rename to test/lib/base/pairs.lua index 802a56ff6d..ac0b9de367 100644 --- a/test/misc/meta_pairs.lua +++ b/test/lib/base/pairs.lua @@ -1,5 +1,5 @@ -do +do --- nometatable local t = {} for i=1,10 do t[i] = i+100 end local a, b = 0, 0 @@ -12,7 +12,7 @@ do assert(b == 105500) end -do +do --- empty metatable local t = setmetatable({}, {}) for i=1,10 do t[i] = i+100 end local a, b = 0, 0 @@ -25,7 +25,7 @@ do assert(b == 105500) end -if os.getenv("LUA52") then +do --- metamethods +compat5.2 local function iter(t, i) i = i + 1 if t[i] then return i, t[i]+2 end diff --git a/test/misc/meta_arith.lua b/test/misc/meta_arith.lua deleted file mode 100644 index f9028fcd0a..0000000000 --- a/test/misc/meta_arith.lua +++ /dev/null @@ -1,103 +0,0 @@ - -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 - -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") - -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") - -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) - - -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) - -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) - - -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) - -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) - -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) - - -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) - -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) - diff --git a/test/misc/meta_comp.lua b/test/misc/meta_comp.lua deleted file mode 100644 index e265bef2c5..0000000000 --- a/test/misc/meta_comp.lua +++ /dev/null @@ -1,151 +0,0 @@ - -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 - -local xop -local a, b = create(function(op,a,b) xop = op; return "" end) -assert(ab == 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 (ab) == 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(ab == 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 (ab) == 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(ab == 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 (ab) == 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 - -local a, b = create(function(op,a,b) - if op == "lt" then return a[1]b == false) -assert(a<=b == true) -assert(a>=b == false) - -assert(not (ab) == true) -assert(not (a<=b) == false) -assert(not (a>=b) == true) - -b[1] = 1 -assert(ab == false) -assert(a<=b == true) -assert(a>=b == true) - -assert(not (ab) == true) -assert(not (a<=b) == false) -assert(not (a>=b) == false) - -a[1] = 2 -assert(ab == true) -assert(a<=b == false) -assert(a>=b == true) - -assert(not (ab) == 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(ab == false) -assert(a<=b == true) -assert(a>=b == false) - -assert(not (ab) == true) -assert(not (a<=b) == false) -assert(not (a>=b) == true) - -b[1] = 1 -assert(ab == false) -assert(a<=b == true) -assert(a>=b == true) - -assert(not (ab) == true) -assert(not (a<=b) == false) -assert(not (a>=b) == false) - -a[1] = 2 -assert(ab == true) -assert(a<=b == false) -assert(a>=b == true) - -assert(not (ab) == false) -assert(not (a<=b) == true) -assert(not (a>=b) == false) - --- String comparisons: -local function str_cmp(a, b, lt, gt, le, ge) - assert(ab == gt) - assert(a<=b == le) - assert(a>=b == ge) - assert((not (ab)) == (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") - diff --git a/test/misc/meta_comp_jit.lua b/test/misc/meta_comp_jit.lua deleted file mode 100644 index 57f711283e..0000000000 --- a/test/misc/meta_comp_jit.lua +++ /dev/null @@ -1,104 +0,0 @@ - -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) - --- Mixed metamethods for ordered comparisons. -do - 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 os.getenv("LUA52") 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 os.getenv("LUA52") then - assert(ok and ret == true) - else - assert(not ok) - end -end - diff --git a/test/misc/meta_eq.lua b/test/misc/meta_eq.lua deleted file mode 100644 index 786f480423..0000000000 --- a/test/misc/meta_eq.lua +++ /dev/null @@ -1,66 +0,0 @@ - -local function create(equal, v1, v2) - local meta = { __eq = equal } - return setmetatable({v1}, meta), setmetatable({v2}, meta) -end - -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 - -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) - - -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, "") - diff --git a/test/misc/meta_framegap.lua b/test/misc/meta_framegap.lua deleted file mode 100644 index 4f2f719ae2..0000000000 --- a/test/misc/meta_framegap.lua +++ /dev/null @@ -1,23 +0,0 @@ - -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) diff --git a/test/misc/meta_tget.lua b/test/misc/meta_tget.lua deleted file mode 100644 index 7c051009ec..0000000000 --- a/test/misc/meta_tget.lua +++ /dev/null @@ -1,25 +0,0 @@ - -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 - - -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") - diff --git a/test/misc/meta_tget_nontab.lua b/test/misc/meta_tget_nontab.lua deleted file mode 100644 index 3c40a514de..0000000000 --- a/test/misc/meta_tget_nontab.lua +++ /dev/null @@ -1,33 +0,0 @@ - -do - 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 - local s = "foo" - string.s = s - 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 - assert(x == 300) -end - diff --git a/test/misc/meta_tset.lua b/test/misc/meta_tset.lua deleted file mode 100644 index f844e1b567..0000000000 --- a/test/misc/meta_tset.lua +++ /dev/null @@ -1,15 +0,0 @@ - -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 - diff --git a/test/misc/meta_tset_nilget.lua b/test/misc/meta_tset_nilget.lua deleted file mode 100644 index 1fdebab383..0000000000 --- a/test/misc/meta_tset_nilget.lua +++ /dev/null @@ -1,23 +0,0 @@ - -do - 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 - 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 - diff --git a/test/misc/meta_tset_resize.lua b/test/misc/meta_tset_resize.lua deleted file mode 100644 index a58dac1136..0000000000 --- a/test/misc/meta_tset_resize.lua +++ /dev/null @@ -1,10 +0,0 @@ -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 = _ diff --git a/test/misc/meta_tset_str.lua b/test/misc/meta_tset_str.lua deleted file mode 100644 index b72be3a8e5..0000000000 --- a/test/misc/meta_tset_str.lua +++ /dev/null @@ -1,18 +0,0 @@ - -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 - From 1bee68fde248b84b15a1b4c27ec8df2145d1f00a Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Sat, 9 Apr 2016 17:35:22 +0100 Subject: [PATCH 26/68] PUC-Rio Lua compatibility. --- test/lib/string/dump.lua | 2 ++ test/lib/string/rep.lua | 12 ++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/test/lib/string/dump.lua b/test/lib/string/dump.lua index 075e37e5d6..ef0a9d56c8 100644 --- a/test/lib/string/dump.lua +++ b/test/lib/string/dump.lua @@ -1,3 +1,5 @@ +local loadstring = loadstring or load + do --- Must unpatch modified bytecode with ILOOP/JLOOP etc. local function foo() local t = {} diff --git a/test/lib/string/rep.lua b/test/lib/string/rep.lua index 5a27e5321b..c97ec10bc9 100644 --- a/test/lib/string/rep.lua +++ b/test/lib/string/rep.lua @@ -20,8 +20,6 @@ do --- misc assert(y == "aaaaaaaaaa") for i=1,100 do y = rep("ab", 10) end assert(y == "abababababababababab") - for i=1,100 do y = rep("ab", 10, "c") end - assert(y == "abcabcabcabcabcabcabcabcabcab") local x = "a" for i=1,100 do y = rep(x, 10) end assert(y == "aaaaaaaaaa") @@ -37,10 +35,20 @@ do --- misc 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") From bcd286b8de5a60da7be9e846e96aa1c6f1048b51 Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Sat, 9 Apr 2016 22:15:16 +0100 Subject: [PATCH 27/68] Modernise more tests. --- test/lang/constant/index | 1 + .../tnew_tdup.lua => lang/constant/table.lua} | 31 ++-- test/lang/index | 1 + test/{misc/tlen_loop.lua => lang/length.lua} | 46 +++--- test/lib/base/index | 3 + test/lib/base/ipairs.lua | 41 +++++ test/lib/base/next.lua | 17 ++ test/lib/base/pairs.lua | 26 +++ test/{misc => lib/base}/tonumber_tostring.lua | 23 ++- test/misc/iter.lua | 85 ---------- test/misc/phi_rot18.lua | 39 ----- test/misc/phi_rot8.lua | 39 ----- test/misc/phi_rot9.lua | 39 ----- test/misc/phi_rotx.lua | 21 --- test/trace/index | 1 + .../phi/copyspill.lua} | 2 + test/trace/phi/index | 3 + test/{misc/phi_ref.lua => trace/phi/ref.lua} | 42 ++--- test/trace/phi/rotate.lua | 149 ++++++++++++++++++ 19 files changed, 309 insertions(+), 300 deletions(-) rename test/{misc/tnew_tdup.lua => lang/constant/table.lua} (86%) rename test/{misc/tlen_loop.lua => lang/length.lua} (62%) create mode 100644 test/lib/base/ipairs.lua create mode 100644 test/lib/base/next.lua rename test/{misc => lib/base}/tonumber_tostring.lua (83%) delete mode 100644 test/misc/iter.lua delete mode 100644 test/misc/phi_rot18.lua delete mode 100644 test/misc/phi_rot8.lua delete mode 100644 test/misc/phi_rot9.lua delete mode 100644 test/misc/phi_rotx.lua rename test/{misc/phi_copyspill.lua => trace/phi/copyspill.lua} (98%) create mode 100644 test/trace/phi/index rename test/{misc/phi_ref.lua => trace/phi/ref.lua} (74%) create mode 100644 test/trace/phi/rotate.lua diff --git a/test/lang/constant/index b/test/lang/constant/index index 05bc1edb01..61db9ef549 100644 --- a/test/lang/constant/index +++ b/test/lang/constant/index @@ -1 +1,2 @@ number.lua +table.lua diff --git a/test/misc/tnew_tdup.lua b/test/lang/constant/table.lua similarity index 86% rename from test/misc/tnew_tdup.lua rename to test/lang/constant/table.lua index 140d05dee3..1e8e3de22c 100644 --- a/test/misc/tnew_tdup.lua +++ b/test/lang/constant/table.lua @@ -1,16 +1,15 @@ - -do - local a = nil - local b = {} - local t = {[true] = a, [false] = b or 1} - assert(t[true] == nil) - assert(t[false] == b) -end - -do - local b = {} - local t = {[true] = nil, [false] = b or 1} - assert(t[true] == nil) - assert(t[false] == b) -end - + +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/lang/index b/test/lang/index index 457490ef30..3901d82ff8 100644 --- a/test/lang/index +++ b/test/lang/index @@ -3,6 +3,7 @@ assignment.lua compare.lua constant for.lua +length.lua modulo.lua concat.lua self.lua diff --git a/test/misc/tlen_loop.lua b/test/lang/length.lua similarity index 62% rename from test/misc/tlen_loop.lua rename to test/lang/length.lua index 050f23c389..1974b8257c 100644 --- a/test/misc/tlen_loop.lua +++ b/test/lang/length.lua @@ -1,23 +1,23 @@ - -do - local t = {} - for i=1,100 do t[#t+1] = i end - assert(#t == 100) - for i=1,100 do t[#t] = nil end -end - -do - local t = {} - t[90] = 999 - for i=1,100 do t[#t+1] = i end - assert(#t > 100 and t[#t] == 100) -end - -do - 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 - + +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/lib/base/index b/test/lib/base/index index c9ddd19535..1c9f2be9dd 100644 --- a/test/lib/base/index +++ b/test/lib/base/index @@ -2,6 +2,9 @@ assert.lua error.lua getfenv.lua +lua<5.2 getsetmetatable.lua +ipairs.lua +next.lua pairs.lua select.lua +tonumber_tostring.lua xpcall_jit.lua +compat5.2 diff --git a/test/lib/base/ipairs.lua b/test/lib/base/ipairs.lua new file mode 100644 index 0000000000..66ac9f0ae3 --- /dev/null +++ b/test/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/lib/base/next.lua b/test/lib/base/next.lua new file mode 100644 index 0000000000..af0ee6642c --- /dev/null +++ b/test/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/lib/base/pairs.lua b/test/lib/base/pairs.lua index ac0b9de367..4d89d42d39 100644 --- a/test/lib/base/pairs.lua +++ b/test/lib/base/pairs.lua @@ -45,3 +45,29 @@ do --- metamethods +compat5.2 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/misc/tonumber_tostring.lua b/test/lib/base/tonumber_tostring.lua similarity index 83% rename from test/misc/tonumber_tostring.lua rename to test/lib/base/tonumber_tostring.lua index d611b2c3c4..e7f576cea3 100644 --- a/test/misc/tonumber_tostring.lua +++ b/test/lib/base/tonumber_tostring.lua @@ -1,17 +1,17 @@ -do +do --- tonumber int local x = 0 for i=1,100 do x = x + tonumber(i) end assert(x == 5050) end -do +do --- tonumber float local x = 0 for i=1.5,100.5 do x = x + tonumber(i) end assert(x == 5100) end -do +do --- tostring int / tonumber local t = {} for i=1,100 do t[i] = tostring(i) end local x = 0 @@ -19,7 +19,7 @@ do assert(x == 5050) end -do +do --- tostring float / tonumber local t = {} for i=1,100 do t[i] = tostring(i+0.5) end local x = 0 @@ -27,11 +27,11 @@ do assert(x == 5100) end -do +do --- tonumber table for i=1,100 do assert(tonumber({}) == nil) end end -do +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 @@ -40,7 +40,7 @@ do assert(x == 5050) end -do +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 @@ -50,7 +50,7 @@ do assert(x == 5050) end -do +do --- tostring table __tostring __call local r = setmetatable({}, { __call = function(x, t) return tostring(t[1]) end }) local mt = { __tostring = r } @@ -62,7 +62,7 @@ do assert(x == 5050) end -do +do --- print calls overridden tostring +lua<5.2 local x = false local co = coroutine.create(function() print(1) end) debug.setfenv(co, setmetatable({}, { __index = { @@ -71,12 +71,11 @@ do assert(x == true) end -do +do --- tonumber base 2 assert(tonumber(111, 2) == 7) end -do +do --- __tostring must be callable local t = setmetatable({}, { __tostring = "" }) assert(pcall(function() tostring(t) end) == false) end - diff --git a/test/misc/iter.lua b/test/misc/iter.lua deleted file mode 100644 index 4811812eef..0000000000 --- a/test/misc/iter.lua +++ /dev/null @@ -1,85 +0,0 @@ - -do - local n = 0 - for k,v in pairs(_G) do - assert(_G[k] == v) - n = n + 1 - end - assert(n >= 40) -end - -do - 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 - 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 - -do - 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 - local ok, err = pcall(next, _G, 1) - assert(not ok) - local ok, err = pcall(function() next(_G, 1) end) - assert(not ok) -end - -do - 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 - - for _, c in ipairs(t) do - for i = 1, 2 do - o[i][c] = o[i][c] or 1 - end - end -end - -do - 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/misc/phi_rot18.lua b/test/misc/phi_rot18.lua deleted file mode 100644 index b57b040539..0000000000 --- a/test/misc/phi_rot18.lua +++ /dev/null @@ -1,39 +0,0 @@ -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") diff --git a/test/misc/phi_rot8.lua b/test/misc/phi_rot8.lua deleted file mode 100644 index 2c249b76da..0000000000 --- a/test/misc/phi_rot8.lua +++ /dev/null @@ -1,39 +0,0 @@ -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") diff --git a/test/misc/phi_rot9.lua b/test/misc/phi_rot9.lua deleted file mode 100644 index e7b2821fb7..0000000000 --- a/test/misc/phi_rot9.lua +++ /dev/null @@ -1,39 +0,0 @@ -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") diff --git a/test/misc/phi_rotx.lua b/test/misc/phi_rotx.lua deleted file mode 100644 index c8c8b1eb35..0000000000 --- a/test/misc/phi_rotx.lua +++ /dev/null @@ -1,21 +0,0 @@ -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") diff --git a/test/trace/index b/test/trace/index index 00e4d3badc..2703d2f3b7 100644 --- a/test/trace/index +++ b/test/trace/index @@ -1,5 +1,6 @@ exit_frame.lua exit_growstack.lua exit_jfuncf.lua +phi snap.lua stitch.lua diff --git a/test/misc/phi_copyspill.lua b/test/trace/phi/copyspill.lua similarity index 98% rename from test/misc/phi_copyspill.lua rename to test/trace/phi/copyspill.lua index c62d66fbb4..17a8698f56 100644 --- a/test/misc/phi_copyspill.lua +++ b/test/trace/phi/copyspill.lua @@ -1,3 +1,4 @@ +do --- mat4mul !private_G function mat4mul(a11, a21, a31, a41, a12, a22, a32, a42, a13, a23, a33, a43, @@ -49,3 +50,4 @@ for i = 1, 1000 do end assert(a11 == 1) assert(a31 == 0) +end diff --git a/test/trace/phi/index b/test/trace/phi/index new file mode 100644 index 0000000000..76799b894f --- /dev/null +++ b/test/trace/phi/index @@ -0,0 +1,3 @@ +copyspill.lua +ref.lua +rotate.lua diff --git a/test/misc/phi_ref.lua b/test/trace/phi/ref.lua similarity index 74% rename from test/misc/phi_ref.lua rename to test/trace/phi/ref.lua index 7493ef466f..3662912d27 100644 --- a/test/misc/phi_ref.lua +++ b/test/trace/phi/ref.lua @@ -1,35 +1,34 @@ --- rref points into invariant part -do +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 +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 +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 +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 +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 +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) @@ -37,41 +36,37 @@ do assert(z == 100) end --- variant slot, but no corresponding SLOAD -do +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 +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 +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 --- dup lref from variant slot (suppressed) -do +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 --- const rref -do +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 --- dup rref (ok) -do +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) @@ -80,8 +75,7 @@ do assert(z2 == 105) end --- variant slot, no corresponding SLOAD, -do +do --- variant slot, no corresponding SLOAD for i=1,5 do local a, b = 1, 2 local bits = 0 @@ -94,8 +88,7 @@ do end end --- don't eliminate PHI if referenced from snapshot -do +do --- don't eliminate PHI if referenced from snapshot local t = { 0 } local a = 0 for i=1,100 do @@ -107,8 +100,7 @@ do assert(t[1] == 2550) end --- don't eliminate PHI if referenced from snapshot -do +do --- don't eliminate PHI if referenced from snapshot local x = 1 local function f() local t = {} @@ -122,8 +114,7 @@ do assert(f() == 100) end --- don't eliminate PHI if referenced from another non-redundant PHI -do +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 @@ -138,4 +129,3 @@ do for i=1,256 do x = x + bit.bxor(i, t[i]) end assert(x == -41704) end - diff --git a/test/trace/phi/rotate.lua b/test/trace/phi/rotate.lua new file mode 100644 index 0000000000..b80f07e184 --- /dev/null +++ b/test/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 From 3e5cca793103b14f5bf863dda74f37caa2916303 Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Sun, 10 Apr 2016 20:06:15 +0100 Subject: [PATCH 28/68] Modernise some tests. --- test/lang/compare_nan.lua | 99 +++++++++++++++++++++++++++ test/lang/index | 2 + test/lang/meta/debuginfo.lua | 81 ++++++++++++++++++++++ test/lang/meta/index | 1 + test/{misc => lang}/vararg_jit.lua | 14 ++-- test/lib/base/index | 1 + test/{misc => lib/base}/pcall_jit.lua | 11 ++- test/misc/debug_meta.lua | 79 --------------------- test/misc/unordered.lua | 79 --------------------- 9 files changed, 196 insertions(+), 171 deletions(-) create mode 100644 test/lang/compare_nan.lua create mode 100644 test/lang/meta/debuginfo.lua rename test/{misc => lang}/vararg_jit.lua (95%) rename test/{misc => lib/base}/pcall_jit.lua (92%) delete mode 100644 test/misc/debug_meta.lua delete mode 100644 test/misc/unordered.lua diff --git a/test/lang/compare_nan.lua b/test/lang/compare_nan.lua new file mode 100644 index 0000000000..1468f83e1d --- /dev/null +++ b/test/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(nannan, false) + check(nan>=nan, false) + check(nan==nan, false) + check(nan~=nan, true) +end + +do --- nan one + check(nanone, false) + check(nan>=one, false) + check(nan==one, false) + check(nan~=one, true) +end + +do --- one nan + check(onenan, 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(1nan, false) + check(1>=nan, false) + check(1==nan, false) + check(1~=nan, true) +end + +do --- not nan nan + check(not (nannan), true) + check(not (nan>=nan), true) + check(not (nan==nan), true) + check(not (nan~=nan), false) +end + +do --- not nan one + check(not (nanone), true) + check(not (nan>=one), true) + check(not (nan==one), true) + check(not (nan~=one), false) +end + +do --- not one nan + check(not (onenan), 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 (1nan), true) + check(not (1>=nan), true) + check(not (1==nan), true) + check(not (1~=nan), false) +end + diff --git a/test/lang/index b/test/lang/index index 3901d82ff8..b466207f7c 100644 --- a/test/lang/index +++ b/test/lang/index @@ -1,6 +1,7 @@ andor.lua assignment.lua compare.lua +compare_nan.lua constant for.lua length.lua @@ -10,6 +11,7 @@ self.lua upvalue coroutine.lua tail_recursion.lua +vararg_jit.lua gc.lua goto.lua +goto meta diff --git a/test/lang/meta/debuginfo.lua b/test/lang/meta/debuginfo.lua new file mode 100644 index 0000000000..a99941fa26 --- /dev/null +++ b/test/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/lang/meta/index b/test/lang/meta/index index bf2f457625..174eae08d7 100644 --- a/test/lang/meta/index +++ b/test/lang/meta/index @@ -11,3 +11,4 @@ index.lua len.lua newindex.lua nomm.lua +debuginfo.lua diff --git a/test/misc/vararg_jit.lua b/test/lang/vararg_jit.lua similarity index 95% rename from test/misc/vararg_jit.lua rename to test/lang/vararg_jit.lua index 98874a31bf..4e78f96b5d 100644 --- a/test/misc/vararg_jit.lua +++ b/test/lang/vararg_jit.lua @@ -1,5 +1,5 @@ -do +do --- 1 local function f(a, b, c, ...) assert(c == nil) assert(a == 100-b) @@ -12,7 +12,7 @@ do end end -do +do --- 2 local function f(a, b, ...) if a > b then return b end return a @@ -24,7 +24,7 @@ do assert(x == 15050) end -do +do --- 3 local function f(a, b, ...) local c, d = ... if c > d then return d end @@ -37,7 +37,7 @@ do assert(x == 15050) end -do +do --- 4 local function f(a, b, ...) if a > b then end return ... @@ -51,7 +51,7 @@ do assert(x == 20100) end -do +do --- 5 local function f(a, ...) local x, y = 0, 0 for i=1,100 do @@ -64,7 +64,7 @@ do f(1, 2, 3) end -do +do --- 6 local function f(a, ...) local t = {[0]=9, 9} local v, w, x, y = 0, 0, 0, 0 @@ -78,7 +78,7 @@ do f(1, 2, 3) end -do +do --- 7 local function f(a, b, ...) for i=1,100 do local c, d = ... diff --git a/test/lib/base/index b/test/lib/base/index index 1c9f2be9dd..a78cff8dcb 100644 --- a/test/lib/base/index +++ b/test/lib/base/index @@ -5,6 +5,7 @@ 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/misc/pcall_jit.lua b/test/lib/base/pcall_jit.lua similarity index 92% rename from test/misc/pcall_jit.lua rename to test/lib/base/pcall_jit.lua index f5dbe62024..dc9cd5fa8b 100644 --- a/test/misc/pcall_jit.lua +++ b/test/lib/base/pcall_jit.lua @@ -1,5 +1,5 @@ -do +do --- square sum local function f(x) return x*x end local x = 0 for i=1,100 do @@ -10,7 +10,7 @@ do assert(x == 338350) end -do +do --- sqrt square sum local x = 0 for i=1,100 do local ok1, ok2, ok3, y = pcall(pcall, pcall, math.sqrt, i*i) @@ -20,7 +20,7 @@ do assert(x == 5050) end -do +do --- sum with error local function f(x) if x >= 150 then error("test", 0) end return x end @@ -37,7 +37,7 @@ do assert(x == 11175) end -do +do --- sum or square local function f(x) if x >= 150 then return x*x end return x @@ -51,7 +51,7 @@ do assert(x == 1584100) end -do +do --- sum or square with error local function f(x) if x >= 150 then if x >= 175 then error("test", 0) end @@ -72,4 +72,3 @@ do end assert(x == 668575) end - diff --git a/test/misc/debug_meta.lua b/test/misc/debug_meta.lua deleted file mode 100644 index 5954bbfad5..0000000000 --- a/test/misc/debug_meta.lua +++ /dev/null @@ -1,79 +0,0 @@ - -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, -} - -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; ck("__len") -- Not called for tables -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") - -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") - diff --git a/test/misc/unordered.lua b/test/misc/unordered.lua deleted file mode 100644 index 9e71046de9..0000000000 --- a/test/misc/unordered.lua +++ /dev/null @@ -1,79 +0,0 @@ - -local function check(a, b) - if a ~= b then - error("check failed with "..tostring(a).." ~= "..tostring(b), 2) - end -end - -local x,y = 0/0,1 - -check(xx, false) -check(x>=x, false) -check(x==x, false) -check(x~=x, true) - -check(xy, false) -check(x>=y, false) -check(x==y, false) -check(x~=y, true) - -check(yx, false) -check(y>=x, false) -check(y==x, false) -check(y~=x, true) - -check(x<1, false) -check(x<=1, false) -check(x>1, false) -check(x>=1, false) -check(x==1, false) -check(x~=1, true) - -check(1x, false) -check(1>=x, false) -check(1==x, false) -check(1~=x, true) - -check(not (xx), true) -check(not (x>=x), true) -check(not (x==x), true) -check(not (x~=x), false) - -check(not (xy), true) -check(not (x>=y), true) -check(not (x==y), true) -check(not (x~=y), false) - -check(not (yx), true) -check(not (y>=x), true) -check(not (y==x), true) -check(not (y~=x), false) - -check(not (x<1), true) -check(not (x<=1), true) -check(not (x>1), true) -check(not (x>=1), true) -check(not (x==1), true) -check(not (x~=1), false) - -check(not (1x), true) -check(not (1>=x), true) -check(not (1==x), true) -check(not (1~=x), false) - From 9f1451d820f8687e092c6a1340febd4961561d8c Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Sun, 10 Apr 2016 20:21:24 +0100 Subject: [PATCH 29/68] Normalise line endings. --- test/README.md | 220 +++---- test/bc/constov.lua | 32 +- test/bc/index | 2 +- test/common/expect_error.lua | 32 +- test/common/test_runner_canary.lua | 2 +- test/computations.lua | 226 +++---- test/index | 12 +- test/lang/andor.lua | 122 ++-- test/lang/assignment.lua | 92 +-- test/lang/compare.lua | 646 +++++++++---------- test/lang/compare_nan.lua | 198 +++--- test/lang/concat.lua | 202 +++--- test/lang/constant/index | 4 +- test/lang/constant/number.lua | 24 +- test/lang/constant/table.lua | 30 +- test/lang/coroutine.lua | 16 +- test/lang/for.lua | 90 +-- test/lang/gc.lua | 60 +- test/lang/index | 34 +- test/lang/length.lua | 46 +- test/lang/meta/index | 28 +- test/lang/self.lua | 38 +- test/lang/tail_recursion.lua | 40 +- test/lang/upvalue/closure.lua | 168 ++--- test/lang/upvalue/index | 2 +- test/lib/base/assert.lua | 66 +- test/lib/base/error.lua | 86 +-- test/lib/base/getfenv.lua | 26 +- test/lib/base/index | 22 +- test/lib/base/ipairs.lua | 82 +-- test/lib/base/next.lua | 34 +- test/lib/base/select.lua | 210 +++---- test/lib/base/xpcall_jit.lua | 166 ++--- test/lib/bit.lua | 196 +++--- test/lib/contents.lua | 302 ++++----- test/lib/coroutine/index | 2 +- test/lib/coroutine/yield.lua | 218 +++---- test/lib/index | 14 +- test/lib/math/abs.lua | 32 +- test/lib/math/constants.lua | 16 +- test/lib/math/index | 6 +- test/lib/math/random.lua | 94 +-- test/lib/string/byte.lua | 184 +++--- test/lib/string/char.lua | 58 +- test/lib/string/dump.lua | 62 +- test/lib/string/format/index | 2 +- test/lib/string/format/num.lua | 368 +++++------ test/lib/string/index | 22 +- test/lib/string/len.lua | 28 +- test/lib/string/lower_upper.lua | 102 +-- test/lib/string/metatable.lua | 6 +- test/lib/string/multiple_functions.lua | 32 +- test/lib/string/rep.lua | 136 ++-- test/lib/string/reverse.lua | 26 +- test/lib/string/sub.lua | 378 +++++------ test/lib/table/concat.lua | 110 ++-- test/lib/table/index | 12 +- test/lib/table/new.lua | 22 +- test/lib/table/pack.lua | 14 +- test/lib/table/sort.lua | 54 +- test/opt/dse/array.lua | 394 ++++++------ test/opt/dse/field.lua | 140 ++--- test/opt/dse/index | 4 +- test/opt/fold/index | 2 +- test/opt/fold/kfold.lua | 162 ++--- test/opt/fuse.lua | 10 +- test/opt/fwd/hrefk_rollback.lua | 64 +- test/opt/fwd/index | 6 +- test/opt/fwd/tnew_tdup.lua | 138 ++-- test/opt/fwd/upval.lua | 100 +-- test/opt/index | 12 +- test/opt/loop/index | 2 +- test/opt/loop/unroll.lua | 64 +- test/opt/sink/alloc.lua | 252 ++++---- test/opt/sink/index | 4 +- test/opt/sink/nosink.lua | 218 +++---- test/test.lua | 832 ++++++++++++------------- test/trace/exit_frame.lua | 158 ++--- test/trace/exit_growstack.lua | 56 +- test/trace/exit_jfuncf.lua | 60 +- test/trace/index | 12 +- test/trace/phi/index | 6 +- test/trace/phi/rotate.lua | 298 ++++----- test/trace/snap.lua | 94 +-- test/trace/stitch.lua | 38 +- 85 files changed, 4340 insertions(+), 4340 deletions(-) diff --git a/test/README.md b/test/README.md index f72290f225..ff16ac8ef8 100644 --- a/test/README.md +++ b/test/README.md @@ -1,110 +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 --- <> <> - << code >> - end - -Where `<>` is (almost) free-form, and `<< code >>` is Lua code which -performs some actions and probably calls `assert` alot. The `<>` -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 --- <>`). -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. +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 --- <> <> + << code >> + end + +Where `<>` is (almost) free-form, and `<< code >>` is Lua code which +performs some actions and probably calls `assert` alot. The `<>` +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 --- <>`). +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/bc/constov.lua b/test/bc/constov.lua index de1e2a6d5d..5827840b46 100644 --- a/test/bc/constov.lua +++ b/test/bc/constov.lua @@ -1,16 +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 + +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/bc/index b/test/bc/index index 3954d57600..dead10f555 100644 --- a/test/bc/index +++ b/test/bc/index @@ -1 +1 @@ -constov.lua +slow +constov.lua +slow diff --git a/test/common/expect_error.lua b/test/common/expect_error.lua index 7643416720..e155090eda 100644 --- a/test/common/expect_error.lua +++ b/test/common/expect_error.lua @@ -1,16 +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 +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/common/test_runner_canary.lua b/test/common/test_runner_canary.lua index 138ad84c9e..fc9cadc637 100644 --- a/test/common/test_runner_canary.lua +++ b/test/common/test_runner_canary.lua @@ -1 +1 @@ -return "canary is alive" +return "canary is alive" diff --git a/test/computations.lua b/test/computations.lua index 439febee7e..4fce7fcd4a 100644 --- a/test/computations.lua +++ b/test/computations.lua @@ -1,113 +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 +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/index b/test/index index 256118eb9b..bd4081e39e 100644 --- a/test/index +++ b/test/index @@ -1,6 +1,6 @@ -lang -lib -bc +luajit>=2 -computations.lua -trace +jit -opt +jit +lang +lib +bc +luajit>=2 +computations.lua +trace +jit +opt +jit diff --git a/test/lang/andor.lua b/test/lang/andor.lua index dc4296faa3..55b2c756e5 100644 --- a/test/lang/andor.lua +++ b/test/lang/andor.lua @@ -1,61 +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 +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/lang/assignment.lua b/test/lang/assignment.lua index 34c7b52df7..e9745ef667 100644 --- a/test/lang/assignment.lua +++ b/test/lang/assignment.lua @@ -1,46 +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 +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/lang/compare.lua b/test/lang/compare.lua index 9b38ff5e2f..09c5488d15 100644 --- a/test/lang/compare.lua +++ b/test/lang/compare.lua @@ -1,323 +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(xy, false) - check(x>=y, false) - check(x==y, false) - check(x~=y, true) - - check(1y, 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(xy, true) - check(x>=y, true) - check(x==y, false) - check(x~=y, true) - - check(2y, 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(xy, false) - check(x>=y, true) - check(x==y, true) - check(x~=y, false) - - check(1y, 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(ab == gt) - assert(a<=b == le) - assert(a>=b == ge) - assert((not (ab)) == (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 +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(xy, false) + check(x>=y, false) + check(x==y, false) + check(x~=y, true) + + check(1y, 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(xy, true) + check(x>=y, true) + check(x==y, false) + check(x~=y, true) + + check(2y, 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(xy, false) + check(x>=y, true) + check(x==y, true) + check(x~=y, false) + + check(1y, 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(ab == gt) + assert(a<=b == le) + assert(a>=b == ge) + assert((not (ab)) == (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/lang/compare_nan.lua b/test/lang/compare_nan.lua index 1468f83e1d..878f39a7f5 100644 --- a/test/lang/compare_nan.lua +++ b/test/lang/compare_nan.lua @@ -1,99 +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(nannan, false) - check(nan>=nan, false) - check(nan==nan, false) - check(nan~=nan, true) -end - -do --- nan one - check(nanone, false) - check(nan>=one, false) - check(nan==one, false) - check(nan~=one, true) -end - -do --- one nan - check(onenan, 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(1nan, false) - check(1>=nan, false) - check(1==nan, false) - check(1~=nan, true) -end - -do --- not nan nan - check(not (nannan), true) - check(not (nan>=nan), true) - check(not (nan==nan), true) - check(not (nan~=nan), false) -end - -do --- not nan one - check(not (nanone), true) - check(not (nan>=one), true) - check(not (nan==one), true) - check(not (nan~=one), false) -end - -do --- not one nan - check(not (onenan), 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 (1nan), true) - check(not (1>=nan), true) - check(not (1==nan), true) - check(not (1~=nan), false) -end - + +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(nannan, false) + check(nan>=nan, false) + check(nan==nan, false) + check(nan~=nan, true) +end + +do --- nan one + check(nanone, false) + check(nan>=one, false) + check(nan==one, false) + check(nan~=one, true) +end + +do --- one nan + check(onenan, 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(1nan, false) + check(1>=nan, false) + check(1==nan, false) + check(1~=nan, true) +end + +do --- not nan nan + check(not (nannan), true) + check(not (nan>=nan), true) + check(not (nan==nan), true) + check(not (nan~=nan), false) +end + +do --- not nan one + check(not (nanone), true) + check(not (nan>=one), true) + check(not (nan==one), true) + check(not (nan~=one), false) +end + +do --- not one nan + check(not (onenan), 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 (1nan), true) + check(not (1>=nan), true) + check(not (1==nan), true) + check(not (1~=nan), false) +end + diff --git a/test/lang/concat.lua b/test/lang/concat.lua index c7af134f92..50dd450c99 100644 --- a/test/lang/concat.lua +++ b/test/lang/concat.lua @@ -1,101 +1,101 @@ -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 --- 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 diff --git a/test/lang/constant/index b/test/lang/constant/index index 61db9ef549..e738357d79 100644 --- a/test/lang/constant/index +++ b/test/lang/constant/index @@ -1,2 +1,2 @@ -number.lua -table.lua +number.lua +table.lua diff --git a/test/lang/constant/number.lua b/test/lang/constant/number.lua index c0514e7389..fb67356e7f 100644 --- a/test/lang/constant/number.lua +++ b/test/lang/constant/number.lua @@ -1,12 +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 +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/lang/constant/table.lua b/test/lang/constant/table.lua index 1e8e3de22c..899d0f671c 100644 --- a/test/lang/constant/table.lua +++ b/test/lang/constant/table.lua @@ -1,15 +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 + +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/lang/coroutine.lua b/test/lang/coroutine.lua index 769e64ffab..405135c968 100644 --- a/test/lang/coroutine.lua +++ b/test/lang/coroutine.lua @@ -1,8 +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 +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/lang/for.lua b/test/lang/for.lua index b16508e1d3..4982b32b95 100644 --- a/test/lang/for.lua +++ b/test/lang/for.lua @@ -1,45 +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 +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/lang/gc.lua b/test/lang/gc.lua index 0c50450646..f820418084 100644 --- a/test/lang/gc.lua +++ b/test/lang/gc.lua @@ -1,30 +1,30 @@ -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 --- 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 diff --git a/test/lang/index b/test/lang/index index b466207f7c..df5ed675c5 100644 --- a/test/lang/index +++ b/test/lang/index @@ -1,17 +1,17 @@ -andor.lua -assignment.lua -compare.lua -compare_nan.lua -constant -for.lua -length.lua -modulo.lua -concat.lua -self.lua -upvalue -coroutine.lua -tail_recursion.lua -vararg_jit.lua -gc.lua -goto.lua +goto -meta +andor.lua +assignment.lua +compare.lua +compare_nan.lua +constant +for.lua +length.lua +modulo.lua +concat.lua +self.lua +upvalue +coroutine.lua +tail_recursion.lua +vararg_jit.lua +gc.lua +goto.lua +goto +meta diff --git a/test/lang/length.lua b/test/lang/length.lua index 1974b8257c..67c68ae70a 100644 --- a/test/lang/length.lua +++ b/test/lang/length.lua @@ -1,23 +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 + +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/lang/meta/index b/test/lang/meta/index index 174eae08d7..f114e78d04 100644 --- a/test/lang/meta/index +++ b/test/lang/meta/index @@ -1,14 +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 +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/lang/self.lua b/test/lang/self.lua index 48f58d30c8..d37466642d 100644 --- a/test/lang/self.lua +++ b/test/lang/self.lua @@ -1,19 +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 +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/lang/tail_recursion.lua b/test/lang/tail_recursion.lua index 22bab72f95..78f071fd22 100644 --- a/test/lang/tail_recursion.lua +++ b/test/lang/tail_recursion.lua @@ -1,20 +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 +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/lang/upvalue/closure.lua b/test/lang/upvalue/closure.lua index 34083223c7..faa4de1c3c 100644 --- a/test/lang/upvalue/closure.lua +++ b/test/lang/upvalue/closure.lua @@ -1,84 +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 +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/lang/upvalue/index b/test/lang/upvalue/index index 58931de651..3c170db922 100644 --- a/test/lang/upvalue/index +++ b/test/lang/upvalue/index @@ -1 +1 @@ -closure.lua +closure.lua diff --git a/test/lib/base/assert.lua b/test/lib/base/assert.lua index 6f1ef548c1..9c30ba029c 100644 --- a/test/lib/base/assert.lua +++ b/test/lib/base/assert.lua @@ -1,33 +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 +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/lib/base/error.lua b/test/lib/base/error.lua index 74aac75437..9193085423 100644 --- a/test/lib/base/error.lua +++ b/test/lib/base/error.lua @@ -1,43 +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 +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/lib/base/getfenv.lua b/test/lib/base/getfenv.lua index 29e288c13f..9c00ed7cd1 100644 --- a/test/lib/base/getfenv.lua +++ b/test/lib/base/getfenv.lua @@ -1,13 +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 +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/lib/base/index b/test/lib/base/index index a78cff8dcb..942c53c0f2 100644 --- a/test/lib/base/index +++ b/test/lib/base/index @@ -1,11 +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 +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/lib/base/ipairs.lua b/test/lib/base/ipairs.lua index 66ac9f0ae3..a9de087e26 100644 --- a/test/lib/base/ipairs.lua +++ b/test/lib/base/ipairs.lua @@ -1,41 +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 +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/lib/base/next.lua b/test/lib/base/next.lua index af0ee6642c..0e40615afe 100644 --- a/test/lib/base/next.lua +++ b/test/lib/base/next.lua @@ -1,17 +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 +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/lib/base/select.lua b/test/lib/base/select.lua index 5c8ac55170..8278e5e999 100644 --- a/test/lib/base/select.lua +++ b/test/lib/base/select.lua @@ -1,105 +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 + +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/lib/base/xpcall_jit.lua b/test/lib/base/xpcall_jit.lua index 32c8e1c472..f4993cc619 100644 --- a/test/lib/base/xpcall_jit.lua +++ b/test/lib/base/xpcall_jit.lua @@ -1,83 +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 +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/lib/bit.lua b/test/lib/bit.lua index a37b28a37e..1adf550781 100644 --- a/test/lib/bit.lua +++ b/test/lib/bit.lua @@ -1,98 +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 +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/lib/contents.lua b/test/lib/contents.lua index bb9f2cf79f..b2a1a7adbc 100644 --- a/test/lib/contents.lua +++ b/test/lib/contents.lua @@ -1,151 +1,151 @@ -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 - 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 - 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:typeinfo:typeof") -end +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 + 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 + 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:typeinfo:typeof") +end diff --git a/test/lib/coroutine/index b/test/lib/coroutine/index index 4c9e320b48..9c5c17ec19 100644 --- a/test/lib/coroutine/index +++ b/test/lib/coroutine/index @@ -1 +1 @@ -yield.lua +yield.lua diff --git a/test/lib/coroutine/yield.lua b/test/lib/coroutine/yield.lua index 4cc98de9c5..d995bf87e1 100644 --- a/test/lib/coroutine/yield.lua +++ b/test/lib/coroutine/yield.lua @@ -1,109 +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 +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/lib/index b/test/lib/index index c15ccfd6a6..b22eaf883c 100644 --- a/test/lib/index +++ b/test/lib/index @@ -1,8 +1,8 @@ -base -bit.lua +bit -math -string -table -coroutine - +base +bit.lua +bit +math +string +table +coroutine + contents.lua \ No newline at end of file diff --git a/test/lib/math/abs.lua b/test/lib/math/abs.lua index 660a6cc37d..4223a78062 100644 --- a/test/lib/math/abs.lua +++ b/test/lib/math/abs.lua @@ -1,16 +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 +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/lib/math/constants.lua b/test/lib/math/constants.lua index 5f8a4f79d8..ec35b4cecb 100644 --- a/test/lib/math/constants.lua +++ b/test/lib/math/constants.lua @@ -1,8 +1,8 @@ -do --- pi - assert(math.pi == 3.141592653589793) -end - -do --- huge - assert(math.huge > 0) - assert(1/math.huge == 0) -end +do --- pi + assert(math.pi == 3.141592653589793) +end + +do --- huge + assert(math.huge > 0) + assert(1/math.huge == 0) +end diff --git a/test/lib/math/index b/test/lib/math/index index f17d52e780..944e1aebd4 100644 --- a/test/lib/math/index +++ b/test/lib/math/index @@ -1,3 +1,3 @@ -abs.lua -constants.lua -random.lua +abs.lua +constants.lua +random.lua diff --git a/test/lib/math/random.lua b/test/lib/math/random.lua index 4ee799b2e2..dc2ca00bda 100644 --- a/test/lib/math/random.lua +++ b/test/lib/math/random.lua @@ -1,47 +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 +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/lib/string/byte.lua b/test/lib/string/byte.lua index 21b1231737..697a2c2e72 100644 --- a/test/lib/string/byte.lua +++ b/test/lib/string/byte.lua @@ -1,92 +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 +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/lib/string/char.lua b/test/lib/string/char.lua index dff92e3202..544767de03 100644 --- a/test/lib/string/char.lua +++ b/test/lib/string/char.lua @@ -1,29 +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 +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/lib/string/dump.lua b/test/lib/string/dump.lua index ef0a9d56c8..216c6eb8bf 100644 --- a/test/lib/string/dump.lua +++ b/test/lib/string/dump.lua @@ -1,31 +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 +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/lib/string/format/index b/test/lib/string/format/index index 682f3b8ebe..4408853633 100644 --- a/test/lib/string/format/index +++ b/test/lib/string/format/index @@ -1 +1 @@ -num.lua +num.lua diff --git a/test/lib/string/format/num.lua b/test/lib/string/format/num.lua index 279f3c2304..e8cb33f3ce 100644 --- a/test/lib/string/format/num.lua +++ b/test/lib/string/format/num.lua @@ -1,184 +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 +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/lib/string/index b/test/lib/string/index index bad5cffec2..c0638e9c34 100644 --- a/test/lib/string/index +++ b/test/lib/string/index @@ -1,11 +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 +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/lib/string/len.lua b/test/lib/string/len.lua index 8d9c7e57a6..8ed7e8ae49 100644 --- a/test/lib/string/len.lua +++ b/test/lib/string/len.lua @@ -1,14 +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 +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/lib/string/lower_upper.lua b/test/lib/string/lower_upper.lua index 1a05fc353c..7370c44ce1 100644 --- a/test/lib/string/lower_upper.lua +++ b/test/lib/string/lower_upper.lua @@ -1,51 +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 +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/lib/string/metatable.lua b/test/lib/string/metatable.lua index 9861ee7e3c..d39ed43264 100644 --- a/test/lib/string/metatable.lua +++ b/test/lib/string/metatable.lua @@ -1,3 +1,3 @@ -do --- __index metamethod is string library - assert(debug.getmetatable("").__index == string) -end +do --- __index metamethod is string library + assert(debug.getmetatable("").__index == string) +end diff --git a/test/lib/string/multiple_functions.lua b/test/lib/string/multiple_functions.lua index 725803d66d..7b9d0f1383 100644 --- a/test/lib/string/multiple_functions.lua +++ b/test/lib/string/multiple_functions.lua @@ -1,16 +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 +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/lib/string/rep.lua b/test/lib/string/rep.lua index c97ec10bc9..550c15b8a8 100644 --- a/test/lib/string/rep.lua +++ b/test/lib/string/rep.lua @@ -1,68 +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 +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/lib/string/reverse.lua b/test/lib/string/reverse.lua index 34a8ffb013..deaade7cef 100644 --- a/test/lib/string/reverse.lua +++ b/test/lib/string/reverse.lua @@ -1,13 +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 +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/lib/string/sub.lua b/test/lib/string/sub.lua index 981f2924a0..ecb80216c9 100644 --- a/test/lib/string/sub.lua +++ b/test/lib/string/sub.lua @@ -1,189 +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 +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/lib/table/concat.lua b/test/lib/table/concat.lua index 514a883fc6..1f2a2f924d 100644 --- a/test/lib/table/concat.lua +++ b/test/lib/table/concat.lua @@ -1,55 +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 +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/lib/table/index b/test/lib/table/index index e400606b0d..bd3af0bef1 100644 --- a/test/lib/table/index +++ b/test/lib/table/index @@ -1,6 +1,6 @@ -concat.lua -insert.lua -new.lua +table.new -pack.lua +compat5.2 -remove.lua -sort.lua +concat.lua +insert.lua +new.lua +table.new +pack.lua +compat5.2 +remove.lua +sort.lua diff --git a/test/lib/table/new.lua b/test/lib/table/new.lua index 8e422477cc..483c1298fe 100644 --- a/test/lib/table/new.lua +++ b/test/lib/table/new.lua @@ -1,11 +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 +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/lib/table/pack.lua b/test/lib/table/pack.lua index b76e22fd51..5bd6ecbe0e 100644 --- a/test/lib/table/pack.lua +++ b/test/lib/table/pack.lua @@ -1,7 +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 +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/lib/table/sort.lua b/test/lib/table/sort.lua index c95a895e10..6a86fcf382 100644 --- a/test/lib/table/sort.lua +++ b/test/lib/table/sort.lua @@ -1,27 +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 +-- 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/opt/dse/array.lua b/test/opt/dse/array.lua index 867a7372c7..8c766248a3 100644 --- a/test/opt/dse/array.lua +++ b/test/opt/dse/array.lua @@ -1,197 +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 +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/opt/dse/field.lua b/test/opt/dse/field.lua index 9b544577fb..d8a5411c75 100644 --- a/test/opt/dse/field.lua +++ b/test/opt/dse/field.lua @@ -1,70 +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 +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/opt/dse/index b/test/opt/dse/index index 6d9d9478ec..7b8ad1f4cd 100644 --- a/test/opt/dse/index +++ b/test/opt/dse/index @@ -1,2 +1,2 @@ -array.lua -field.lua +array.lua +field.lua diff --git a/test/opt/fold/index b/test/opt/fold/index index 3bc303fd0c..8b4648c788 100644 --- a/test/opt/fold/index +++ b/test/opt/fold/index @@ -1 +1 @@ -kfold.lua +kfold.lua diff --git a/test/opt/fold/kfold.lua b/test/opt/fold/kfold.lua index 1db29084db..4100bf9150 100644 --- a/test/opt/fold/kfold.lua +++ b/test/opt/fold/kfold.lua @@ -1,81 +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 - assert((10^-2 - 0.01) == 0) -end +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 + assert((10^-2 - 0.01) == 0) +end diff --git a/test/opt/fuse.lua b/test/opt/fuse.lua index 57c5c9df03..a68381ef07 100644 --- a/test/opt/fuse.lua +++ b/test/opt/fuse.lua @@ -1,5 +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 +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/opt/fwd/hrefk_rollback.lua b/test/opt/fwd/hrefk_rollback.lua index 32ba95d28c..5a6ad87688 100644 --- a/test/opt/fwd/hrefk_rollback.lua +++ b/test/opt/fwd/hrefk_rollback.lua @@ -1,32 +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 +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/opt/fwd/index b/test/opt/fwd/index index 74d3bdbd69..5bb1537f0a 100644 --- a/test/opt/fwd/index +++ b/test/opt/fwd/index @@ -1,3 +1,3 @@ -hrefk_rollback.lua -tnew_tdup.lua -upval.lua +hrefk_rollback.lua +tnew_tdup.lua +upval.lua diff --git a/test/opt/fwd/tnew_tdup.lua b/test/opt/fwd/tnew_tdup.lua index 375863f69f..9e18fa3bd1 100644 --- a/test/opt/fwd/tnew_tdup.lua +++ b/test/opt/fwd/tnew_tdup.lua @@ -1,69 +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 +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/opt/fwd/upval.lua b/test/opt/fwd/upval.lua index 5bc1cc96cb..a3e83dff4e 100644 --- a/test/opt/fwd/upval.lua +++ b/test/opt/fwd/upval.lua @@ -1,50 +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 +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/opt/index b/test/opt/index index 2aeaa8f16d..94d50aecfd 100644 --- a/test/opt/index +++ b/test/opt/index @@ -1,6 +1,6 @@ -dse +dse -fold +fold -fwd +fwd -fuse.lua +fuse -loop +loop -sink +sink +dse +dse +fold +fold +fwd +fwd +fuse.lua +fuse +loop +loop +sink +sink diff --git a/test/opt/loop/index b/test/opt/loop/index index 321efe23fb..e582023481 100644 --- a/test/opt/loop/index +++ b/test/opt/loop/index @@ -1 +1 @@ -unroll.lua +unroll.lua diff --git a/test/opt/loop/unroll.lua b/test/opt/loop/unroll.lua index 4c856a5813..6fbd565afc 100644 --- a/test/opt/loop/unroll.lua +++ b/test/opt/loop/unroll.lua @@ -1,32 +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 +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/opt/sink/alloc.lua b/test/opt/sink/alloc.lua index a83e8f05ac..bb2a0f7272 100644 --- a/test/opt/sink/alloc.lua +++ b/test/opt/sink/alloc.lua @@ -1,126 +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 +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/opt/sink/index b/test/opt/sink/index index b3a78ebe09..137f46ab31 100644 --- a/test/opt/sink/index +++ b/test/opt/sink/index @@ -1,2 +1,2 @@ -alloc.lua -nosink.lua +alloc.lua +nosink.lua diff --git a/test/opt/sink/nosink.lua b/test/opt/sink/nosink.lua index 3a1bdf0752..762aaced57 100644 --- a/test/opt/sink/nosink.lua +++ b/test/opt/sink/nosink.lua @@ -1,109 +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 +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/test.lua b/test/test.lua index 1e842d4333..6d5fb6daa4 100644 --- a/test/test.lua +++ b/test/test.lua @@ -1,416 +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, #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 +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, #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/trace/exit_frame.lua b/test/trace/exit_frame.lua index c8297cb0bc..9537c56342 100644 --- a/test/trace/exit_frame.lua +++ b/test/trace/exit_frame.lua @@ -1,79 +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 +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/trace/exit_growstack.lua b/test/trace/exit_growstack.lua index 20accdf8bb..658a31a509 100644 --- a/test/trace/exit_growstack.lua +++ b/test/trace/exit_growstack.lua @@ -1,28 +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 +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/trace/exit_jfuncf.lua b/test/trace/exit_jfuncf.lua index 4895fbf0a7..67ad7c369d 100644 --- a/test/trace/exit_jfuncf.lua +++ b/test/trace/exit_jfuncf.lua @@ -1,30 +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 +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/trace/index b/test/trace/index index 2703d2f3b7..7299d4f0ee 100644 --- a/test/trace/index +++ b/test/trace/index @@ -1,6 +1,6 @@ -exit_frame.lua -exit_growstack.lua -exit_jfuncf.lua -phi -snap.lua -stitch.lua +exit_frame.lua +exit_growstack.lua +exit_jfuncf.lua +phi +snap.lua +stitch.lua diff --git a/test/trace/phi/index b/test/trace/phi/index index 76799b894f..74a07333c4 100644 --- a/test/trace/phi/index +++ b/test/trace/phi/index @@ -1,3 +1,3 @@ -copyspill.lua -ref.lua -rotate.lua +copyspill.lua +ref.lua +rotate.lua diff --git a/test/trace/phi/rotate.lua b/test/trace/phi/rotate.lua index b80f07e184..cb751e0b9f 100644 --- a/test/trace/phi/rotate.lua +++ b/test/trace/phi/rotate.lua @@ -1,149 +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 +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/trace/snap.lua b/test/trace/snap.lua index ca31595f0e..ba26326e0f 100644 --- a/test/trace/snap.lua +++ b/test/trace/snap.lua @@ -1,47 +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 +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/trace/stitch.lua b/test/trace/stitch.lua index 55ce5c4151..3f7f97342f 100644 --- a/test/trace/stitch.lua +++ b/test/trace/stitch.lua @@ -1,19 +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 +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 From 9c27a59d8e412902b854dabb83c5b6bfbed626e5 Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Sat, 16 Apr 2016 15:51:24 +0100 Subject: [PATCH 30/68] Fix batch modifier application. --- test/test.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test.lua b/test/test.lua index 6d5fb6daa4..b064eff7b4 100644 --- a/test/test.lua +++ b/test/test.lua @@ -272,7 +272,7 @@ local function append_tree_to_plan(test_tree, opts, plan, prefix) local G = setmetatable({}, {__index = _G}) G._G = G local function Gfn() return G end - for i = planlen, #plan do + for i = planlen+1, #plan do local test = plan[i][3] if setfenv then setfenv(test, G) From a82c499a0d3a000c1776a2723649fb6d241f0528 Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Sun, 24 Apr 2016 00:03:58 +0100 Subject: [PATCH 31/68] Modernise some FFI tests. --- test/lib/ffi/{ffi_bit64.lua => bit64.lua} | 48 ++++++++------ .../ffi/{ffi_copy_fill.lua => copy_fill.lua} | 6 +- test/lib/ffi/ffi_redir.lua | 22 ------- test/lib/ffi/index | 7 ++ .../ffi/{ffi_jit_array.lua => jit_array.lua} | 58 ++++++++--------- .../{ffi_jit_struct.lua => jit_struct.lua} | 64 +++++++++---------- ...fi_meta_tostring.lua => meta_tostring.lua} | 27 ++++---- test/lib/ffi/redir.lua | 19 ++++++ ...{ffi_type_punning.lua => type_punning.lua} | 33 ++++------ test/lib/index | 2 +- .../ffi/ffi_sink.lua => opt/sink/ffi.lua} | 31 +++++---- test/{lib/ffi => opt/sink}/ffi_nosink.lua | 12 ++-- test/opt/sink/index | 2 + 13 files changed, 169 insertions(+), 162 deletions(-) rename test/lib/ffi/{ffi_bit64.lua => bit64.lua} (76%) rename test/lib/ffi/{ffi_copy_fill.lua => copy_fill.lua} (96%) delete mode 100644 test/lib/ffi/ffi_redir.lua create mode 100644 test/lib/ffi/index rename test/lib/ffi/{ffi_jit_array.lua => jit_array.lua} (70%) rename test/lib/ffi/{ffi_jit_struct.lua => jit_struct.lua} (69%) rename test/lib/ffi/{ffi_meta_tostring.lua => meta_tostring.lua} (69%) create mode 100644 test/lib/ffi/redir.lua rename test/lib/ffi/{ffi_type_punning.lua => type_punning.lua} (75%) rename test/{lib/ffi/ffi_sink.lua => opt/sink/ffi.lua} (79%) rename test/{lib/ffi => opt/sink}/ffi_nosink.lua (79%) diff --git a/test/lib/ffi/ffi_bit64.lua b/test/lib/ffi/bit64.lua similarity index 76% rename from test/lib/ffi/ffi_bit64.lua rename to test/lib/ffi/bit64.lua index 46cf60143c..d1b47bef7b 100644 --- a/test/lib/ffi/ffi_bit64.lua +++ b/test/lib/ffi/bit64.lua @@ -11,27 +11,37 @@ typedef enum { ZZI = -1 } ienum_t; typedef enum { ZZU } uenum_t; ]] -assert(tobit(0xfedcba9876543210ll) == 0x76543210) -assert(tobit(0xfedcba9876543210ull) == 0x76543210) +do --- smoke tobit + assert(tobit(0xfedcba9876543210ll) == 0x76543210) + assert(tobit(0xfedcba9876543210ull) == 0x76543210) +end -assert(tostring(band(1ll, 1, 1ll, -1)) == "1LL") -assert(tostring(band(1ll, 1, 1ull, -1)) == "1ULL") +do --- smoke band + assert(tostring(band(1ll, 1, 1ll, -1)) == "1LL") + assert(tostring(band(1ll, 1, 1ull, -1)) == "1ULL") +end -assert(shl(10ll, 2) == 40) -assert(shl(10, 2ll) == 40) -assert(shl(10ll, 2ll) == 40) +do --- smoke shl + assert(shl(10ll, 2) == 40) + assert(shl(10, 2ll) == 40) + assert(shl(10ll, 2ll) == 40) +end -assert(bit.tohex(0x123456789abcdef0LL) == "123456789abcdef0") +do --- smoke tohex + assert(bit.tohex(0x123456789abcdef0LL) == "123456789abcdef0") +end -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) +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 +do --- tobit/band negative unsigned enum local x = ffi.new("uenum_t", -10) local y = tobit(x) local z = band(x) @@ -41,7 +51,7 @@ do assert(z == 2^32-10) end -do +do --- jit band/bor/bxor local a = 0x123456789abcdef0LL local y1, y2, y3, y4, y5, y6 for i=1,100 do @@ -88,7 +98,7 @@ do assert(y6 == 0x123456786543210fLL) end -do +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) @@ -98,7 +108,7 @@ do assert(b == -7993764627526027113LL) end -do +do --- jit rotate/xor local a, b = 0x123456789abcdef0LL, 0x31415926535898LL for i=1,200 do a = bxor(a, b); b = rol(b, 14) @@ -108,7 +118,7 @@ do assert(b == -6199148037344061526LL) end -do +do --- jit all ops local a, b = 0x123456789abcdef0LL, 0x31415926535898LL for i=1,200 do a = bxor(a, b); b = rol(b, a) diff --git a/test/lib/ffi/ffi_copy_fill.lua b/test/lib/ffi/copy_fill.lua similarity index 96% rename from test/lib/ffi/ffi_copy_fill.lua rename to test/lib/ffi/copy_fill.lua index ef060bad05..295638182d 100644 --- a/test/lib/ffi/ffi_copy_fill.lua +++ b/test/lib/ffi/copy_fill.lua @@ -1,6 +1,6 @@ local ffi = require("ffi") -do +do --- misc local arr = ffi.typeof("char[11]") local a = arr() local b = arr() @@ -43,14 +43,14 @@ do assert(ffi.string(c, 5) == "AAAAA") end -do +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 +do --- jit char[1] local a = ffi.new("char[1]") local x, y for i=1,100 do diff --git a/test/lib/ffi/ffi_redir.lua b/test/lib/ffi/ffi_redir.lua deleted file mode 100644 index 72e6e307bc..0000000000 --- a/test/lib/ffi/ffi_redir.lua +++ /dev/null @@ -1,22 +0,0 @@ -local ffi = require("ffi") - -ffi.cdef[[ -int foo(const char *s) asm("strlen"); -]] - -assert(ffi.C.foo("abcd") == 4) - -if ffi.abi("win") then - ffi.cdef[[ - int bar asm("_fmode"); - ]] -else - ffi.cdef[[ - int bar asm("errno"); - ]] -end - -ffi.C.bar = 14 -assert(ffi.C.bar == 14) -ffi.C.bar = 0 - diff --git a/test/lib/ffi/index b/test/lib/ffi/index new file mode 100644 index 0000000000..0ccd1ab531 --- /dev/null +++ b/test/lib/ffi/index @@ -0,0 +1,7 @@ +bit64.lua +bit +copy_fill.lua +jit_array.lua +jit_struct.lua +meta_tostring.lua +redir.lua +type_punning.lua diff --git a/test/lib/ffi/ffi_jit_array.lua b/test/lib/ffi/jit_array.lua similarity index 70% rename from test/lib/ffi/ffi_jit_array.lua rename to test/lib/ffi/jit_array.lua index 13e26dbe33..e8de4af13c 100644 --- a/test/lib/ffi/ffi_jit_array.lua +++ b/test/lib/ffi/jit_array.lua @@ -1,28 +1,29 @@ local ffi = require("ffi") -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 +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 +do --- int array pointer arithmetic local a = ffi.new("int[?]", 101) local p = a+1; for i=1,100 do @@ -35,7 +36,7 @@ do for i=1,100 do assert((i+a)[0] == i) end -- pointer arithmetic end -do +do --- double array pointer arithmetic local a = ffi.new("double[?]", 101) local p = a+1; for i=1,100 do @@ -46,7 +47,7 @@ do for i=1,100 do assert((a+i)[0] == i) end -- pointer arithmetic end -do +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 @@ -55,13 +56,13 @@ do for i=1,200 do assert((a+i <= p) == (i <= 100)) end end -do +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 +do --- fixed index of minus one local a = ffi.new("int[10]") local p = a+1 local k = ffi.new("int", -1) @@ -69,14 +70,14 @@ do for i=1,100 do assert(p[-1] == 42); assert(p[k] == 42) end end -do +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 +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 @@ -84,7 +85,7 @@ do for i=0,255 do assert(bswap(a[i]) == tobit(i+0x12345600)) end end -do +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 @@ -101,4 +102,3 @@ do 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/lib/ffi/ffi_jit_struct.lua b/test/lib/ffi/jit_struct.lua similarity index 69% rename from test/lib/ffi/ffi_jit_struct.lua rename to test/lib/ffi/jit_struct.lua index e42743c90c..8aa64c1bca 100644 --- a/test/lib/ffi/ffi_jit_struct.lua +++ b/test/lib/ffi/jit_struct.lua @@ -1,17 +1,17 @@ local ffi = require("ffi") ffi.cdef[[ -typedef struct { int a, b, c; } foo_t; -typedef struct { int a, b, c; } foo2_t; -typedef struct { int a[10]; int b[10]; } sarr_t; -typedef struct chain_t { - struct chain_t *next; +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; -} chain_t; +} jit_struct_chain_t; ]] -do - local s = ffi.new("foo_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 @@ -20,8 +20,8 @@ do assert(s.c == 300) end -do - local s = ffi.new("foo_t") +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 @@ -32,9 +32,9 @@ do assert(s.c == 300) end -do - local s = ffi.new("foo_t") - local s2 = ffi.new("foo2_t", 1, 2, 3) +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 @@ -45,8 +45,8 @@ do assert(s.c == 300) end -do - local s = ffi.new("sarr_t") +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 @@ -55,7 +55,7 @@ do assert(s.b[5] == 200) end -do +do --- double indexing local s = ffi.new([[ struct { struct { @@ -72,7 +72,7 @@ do assert(x == 105) end -do +do --- structurally identical local s1 = ffi.new("struct { int a; }") local s2 = ffi.new("struct { int a; }") local x = 0 @@ -92,7 +92,7 @@ do end end -do +do --- structurally different local s1 = ffi.new("struct { int a; }") local s2 = ffi.new("struct { char a; }") local x = 0 @@ -112,7 +112,7 @@ do end end -do +do --- union local s = ffi.new("union { uint8_t a; int8_t b; }") local x = 0 for i=1,200 do @@ -122,10 +122,10 @@ do assert(x == 1412) end -do - local s1 = ffi.new("chain_t") - local s2 = ffi.new("chain_t") - local s3 = ffi.new("chain_t") +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 @@ -139,7 +139,7 @@ do assert(s3.v == 99) end -do +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 @@ -153,7 +153,7 @@ do assert(z == 0) end -do +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 @@ -167,28 +167,28 @@ do assert(z == 0) end -do - local s1 = ffi.new("chain_t") +do --- pointer / int struct initialiser + local s1 = ffi.new("jit_struct_chain_t") local s for i=1,100 do - s = ffi.new("chain_t", s1, i) + s = ffi.new("jit_struct_chain_t", s1, i) end assert(tonumber(ffi.cast("int", s.next)) == - tonumber(ffi.cast("int", ffi.cast("chain_t *", s1)))) + tonumber(ffi.cast("int", ffi.cast("jit_struct_chain_t *", s1)))) assert(s.v == 100) end -do +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("chain_t") end + if i == 100 then ct = ffi.typeof("jit_struct_chain_t") end s = ct(nil, 10) end assert(s.v == 10) end -do +do --- upvalued int box local s = ffi.new("struct { int x; }", 42) local function f() for i=1,100 do diff --git a/test/lib/ffi/ffi_meta_tostring.lua b/test/lib/ffi/meta_tostring.lua similarity index 69% rename from test/lib/ffi/ffi_meta_tostring.lua rename to test/lib/ffi/meta_tostring.lua index 57a34fca9d..bb065e16ab 100644 --- a/test/lib/ffi/ffi_meta_tostring.lua +++ b/test/lib/ffi/meta_tostring.lua @@ -1,31 +1,32 @@ local ffi = require("ffi") ffi.cdef[[ -typedef union foo_t { +typedef union meta_tostring_foo_t { int64_t i64; uint64_t u64; complex cd; double d[2]; complex float cf; float f[2]; -} foo_t; +} meta_tostring_foo_t; ]] -do - local foo_t = ffi.typeof("foo_t") - local x = foo_t() - local s - - assert(tostring(foo_t) == "ctype") - assert(string.match(tostring(x), "^cdata: ")) - +do --- tostring/typeof semi-roundtrip assert(tostring(ffi.typeof("int (*(*[1][2])[3][4])[5][6]")) == - "ctype") + "ctype") assert(tostring(ffi.typeof("int (*const)(void)")) == - "ctype") + "ctype") assert(tostring(ffi.typeof("complex float(*(void))[2]")) == - "ctype") + "ctype") assert(tostring(ffi.typeof("complex*")) == "ctype") +end + +do --- assorted union fields + local foo_t = ffi.typeof("meta_tostring_foo_t") + local x = foo_t() + + assert(tostring(foo_t) == "ctype") + assert(string.find(tostring(x), "^cdata: ")) x.i64 = -1; assert(tostring(x.i64) == "-1LL") diff --git a/test/lib/ffi/redir.lua b/test/lib/ffi/redir.lua new file mode 100644 index 0000000000..c492055adc --- /dev/null +++ b/test/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/lib/ffi/ffi_type_punning.lua b/test/lib/ffi/type_punning.lua similarity index 75% rename from test/lib/ffi/ffi_type_punning.lua rename to test/lib/ffi/type_punning.lua index b889b52f25..ac70b4b4cb 100644 --- a/test/lib/ffi/ffi_type_punning.lua +++ b/test/lib/ffi/type_punning.lua @@ -16,8 +16,7 @@ union { } ]]) --- float -> u32 type punning at same offset -do +do --- float -> u32 type punning at same offset local x = 0LL for i=1,100 do u.f[0] = i @@ -26,8 +25,7 @@ do assert(x == 110888222720LL) end --- double -> u64 type punning at same offset -do +do --- double -> u64 type punning at same offset local x = 0LL for i=1,100 do u.d[0] = i @@ -36,8 +34,7 @@ do assert(x == 1886586031403171840ULL) end --- i8 -> u8 type punning at same offset (fwd -> CONV.int.u8) -do +do --- i8 -> u8 type punning at same offset (fwd -> CONV.int.u8) local x = 0 for i=-100,100 do u.i8[0] = i @@ -46,8 +43,7 @@ do assert(x == 25600) end --- p32/p64 -> u64 type punning at same offset (32 bit: different size) -do +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 @@ -58,8 +54,7 @@ do (ffi.abi"le" and 0x6400001883ULL or 0x188300000000ULL))) end --- u16 -> u8 type punning at overlapping offsets -do +do --- u16 -> u8 type punning at overlapping offsets [0] local x = 0 for i=255,520 do u.u16[0] = i @@ -68,7 +63,7 @@ do assert(x == (ffi.abi"be" and 274 or 32931)) end -do +do --- u16 -> u8 type punning at overlapping offsets [1] local x = 0 for i=255,520 do u.u16[0] = i @@ -77,8 +72,7 @@ do assert(x == (ffi.abi"le" and 274 or 32931)) end --- i16 -> i32 type punning at overlapping offsets -do +do --- i16 -> i32 type punning at overlapping offsets [0] local x = 0 u.i32[0] = 0 for i=-100,150 do @@ -88,7 +82,7 @@ do assert(x == (ffi.abi"be" and 411238400 or 6559875)) end -do +do --- i16 -> i32 type punning at overlapping offsets [1] local x = 0 u.i32[0] = 0 for i=-100,150 do @@ -98,8 +92,7 @@ do assert(x == (ffi.abi"le" and 411238400 or 6559875)) end --- double -> i32 type punning at overlapping offsets -do +do --- double -> i32 type punning at overlapping offsets [0] local x = 0 for i=1.5,120,1.1 do u.d[0] = i @@ -108,7 +101,7 @@ do assert(x == (ffi.abi"be" and 116468870297 or -858993573)) end -do +do --- double -> i32 type punning at overlapping offsets [1] local x = 0 for i=1.5,120,1.1 do u.d[0] = i @@ -117,8 +110,7 @@ do assert(x == (ffi.abi"le" and 116468870297 or -858993573)) end --- u32 -> u64 type punning, constify u, 32 bit SPLIT: fold KPTR -do +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) @@ -134,8 +126,7 @@ do assert(x == 21689584849850ULL) end --- u64 -> u32 -> u64 type punning with KPTR -do +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 diff --git a/test/lib/index b/test/lib/index index b22eaf883c..cc9d7d7301 100644 --- a/test/lib/index +++ b/test/lib/index @@ -4,5 +4,5 @@ math string table coroutine - +ffi +ffi contents.lua \ No newline at end of file diff --git a/test/lib/ffi/ffi_sink.lua b/test/opt/sink/ffi.lua similarity index 79% rename from test/lib/ffi/ffi_sink.lua rename to test/opt/sink/ffi.lua index ea65912764..0bba0978d2 100644 --- a/test/lib/ffi/ffi_sink.lua +++ b/test/opt/sink/ffi.lua @@ -1,12 +1,12 @@ local ffi = require("ffi") -do +do --- incrementing local x = 10000000000000ll for i=1,100 do x=x+1 end assert(x == 10000000000100ll) end -do +do --- hoistable increment !private_G local x = 10000000000000ll local z for i=1,100 do z=x+1 end @@ -16,25 +16,25 @@ do assert(g == 10000000000000ll) end -do +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 +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 +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 +do --- incrementing pointer local a = ffi.new("int[?]", 100) local p = a for i=0,99 do p[0]=i; p=p+1 end @@ -42,7 +42,7 @@ do for i=0,99 do assert(a[i] == i) end end -do +do --- mutating complex local cx = ffi.typeof("complex") local x = cx(1, 2) local k = cx(3, 4) @@ -51,7 +51,7 @@ do assert(x.im == 402) end -do +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) @@ -86,7 +86,7 @@ do assert(z.c == 200) end -do +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) @@ -96,7 +96,7 @@ do assert(x.c == 503.25) end -do +do --- escaping loop counter to float local st = ffi.typeof("struct { float a; }") local x for i=1,200 do @@ -106,17 +106,16 @@ do assert(x.a == 200) end -do +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. + 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/lib/ffi/ffi_nosink.lua b/test/opt/sink/ffi_nosink.lua similarity index 79% rename from test/lib/ffi/ffi_nosink.lua rename to test/opt/sink/ffi_nosink.lua index ae51dde1a1..8f7cced264 100644 --- a/test/lib/ffi/ffi_nosink.lua +++ b/test/opt/sink/ffi_nosink.lua @@ -1,20 +1,20 @@ local ffi = require("ffi") -do +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 +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 +do --- escaping global and local !private_G local x = 0ll local z for i=1,100 do z=x+1; g=z end @@ -22,21 +22,21 @@ do assert(g == 1ll) end -do +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 +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 +do --- strchr ffi.cdef[[char *strchr(char *, int);]] for i=1,100 do local p = ffi.new("char[2]"); diff --git a/test/opt/sink/index b/test/opt/sink/index index 137f46ab31..8bfa370e50 100644 --- a/test/opt/sink/index +++ b/test/opt/sink/index @@ -1,2 +1,4 @@ alloc.lua nosink.lua +ffi.lua +ffi +ffi_nosink.lua +ffi From d7985d1c6530f2461f46a05441e6923b127a6646 Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Sun, 24 Apr 2016 16:51:48 +0100 Subject: [PATCH 32/68] Modernise more ffi tests. --- test/lib/ffi/{ffi_err.lua => err.lua} | 15 ++++----- test/lib/ffi/index | 4 +++ test/lib/ffi/{ffi_istype.lua => istype.lua} | 33 +++++++++---------- .../{ffi_jit_complex.lua => jit_complex.lua} | 28 ++++++++-------- .../ffi/{ffi_jit_misc.lua => jit_misc.lua} | 23 +++++++------ 5 files changed, 50 insertions(+), 53 deletions(-) rename test/lib/ffi/{ffi_err.lua => err.lua} (63%) rename test/lib/ffi/{ffi_istype.lua => istype.lua} (84%) rename test/lib/ffi/{ffi_jit_complex.lua => jit_complex.lua} (77%) rename test/lib/ffi/{ffi_jit_misc.lua => jit_misc.lua} (90%) diff --git a/test/lib/ffi/ffi_err.lua b/test/lib/ffi/err.lua similarity index 63% rename from test/lib/ffi/ffi_err.lua rename to test/lib/ffi/err.lua index bd23658a2d..44723657c0 100644 --- a/test/lib/ffi/ffi_err.lua +++ b/test/lib/ffi/err.lua @@ -1,7 +1,6 @@ local ffi = require("ffi") --- error in FFI metamethod: don't print metamethod frame. -do +do --- error in FFI metamethod: don't print metamethod frame. local ok, err = xpcall(function() local x = (1ll).foo end, debug.traceback) @@ -9,8 +8,7 @@ do assert(not string.find(err, "__index")) end --- tailcall in regular metamethod: keep metamethod frame. -do +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] @@ -19,13 +17,12 @@ do assert(string.find(err, "__index")) end --- error in FFI metamethod: set correct PC. -do +do --- error in FFI metamethod: set correct PC. ffi.cdef[[ -typedef struct { int x; int y; } point; -point strchr(point* op1, point* op2); +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("point", { __add = ffi.C.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 diff --git a/test/lib/ffi/index b/test/lib/ffi/index index 0ccd1ab531..c4091fb727 100644 --- a/test/lib/ffi/index +++ b/test/lib/ffi/index @@ -1,6 +1,10 @@ bit64.lua +bit copy_fill.lua +err.lua +istype.lua jit_array.lua +jit_complex.lua +jit_misc.lua jit_struct.lua meta_tostring.lua redir.lua diff --git a/test/lib/ffi/ffi_istype.lua b/test/lib/ffi/istype.lua similarity index 84% rename from test/lib/ffi/ffi_istype.lua rename to test/lib/ffi/istype.lua index fb538bdd4e..5aba7759e7 100644 --- a/test/lib/ffi/ffi_istype.lua +++ b/test/lib/ffi/istype.lua @@ -1,12 +1,6 @@ local ffi = require("ffi") -ffi.cdef[[ -typedef int arr_t[10]; -typedef const arr_t carr_t; -typedef struct { int x; } struct_t; -]] - -do +do --- 1 local void_t = ffi.typeof("void") assert(ffi.istype(void_t, void_t)) assert(ffi.istype("const void", void_t)) @@ -15,7 +9,7 @@ do assert(ffi.istype("double", 1.5) == false) -- 2nd arg is a number. end -do +do --- 2 local i8_t = ffi.typeof("int8_t") local u8_t = ffi.typeof("uint8_t") local i32_t = ffi.typeof("int32_t") @@ -32,7 +26,7 @@ do assert(ffi.istype("long long", ffi.typeof("int64_t"))) end -do +do --- 3 local ptr_t = ffi.typeof("int *") local p = ptr_t() assert(ffi.istype(ptr_t, ptr_t) == true) @@ -46,9 +40,15 @@ do assert(ffi.istype("void *", ptr_t) == false) end -do - local arr_t = ffi.typeof("arr_t") - local carr_t = ffi.typeof("carr_t") +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) @@ -60,16 +60,16 @@ do assert(ffi.istype("volatile int[10]", arr_t) == true) assert(ffi.istype(carr_t, arr_t) == true) - local struct_t = ffi.typeof("struct_t") - local structp_t = ffi.typeof("struct_t *") + 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 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 +do --- 5 local int_t = ffi.typeof("int") local t = {} for i=1,200 do t[i] = int_t() end @@ -86,4 +86,3 @@ do 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/lib/ffi/ffi_jit_complex.lua b/test/lib/ffi/jit_complex.lua similarity index 77% rename from test/lib/ffi/ffi_jit_complex.lua rename to test/lib/ffi/jit_complex.lua index 4d3191cbe7..3296f0cbfa 100644 --- a/test/lib/ffi/ffi_jit_complex.lua +++ b/test/lib/ffi/jit_complex.lua @@ -4,13 +4,13 @@ local cx = ffi.typeof("complex") local cxf = ffi.typeof("complex float") ffi.cdef[[ -typedef struct cc_t { - struct cc_t *next; +typedef struct jit_complex_chain_t { + struct jit_complex_chain_t *next; complex c; -} cc_t; +} jit_complex_chain_t; ]] -do +do --- field access local c = cx(1, 2) local x for i=1,100 do @@ -19,8 +19,8 @@ do assert(x == 3) end -do - local cp = ffi.new("cc_t") +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) @@ -34,8 +34,8 @@ do assert(y == 200) end -do - local cp = ffi.new("cc_t") +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) @@ -49,7 +49,7 @@ do assert(y == 200) end -do +do --- one-arg initialiser local ca = ffi.new("complex[?]", 101) for i=1,100 do ca[i] = cx(i) -- handled as init single @@ -63,7 +63,7 @@ do assert(y == 0) end -do +do --- two-arg initialiser local ca = ffi.new("complex[?]", 101) for i=1,100 do ca[i] = cx(i, -i) @@ -77,7 +77,7 @@ do assert(y == -5050) end -do +do --- float<>double conversions local ca = ffi.new("complex[?]", 101) local caf = ffi.new("complex float[?]", 101) for i=1,100 do @@ -93,7 +93,7 @@ do assert(y == -2*5050) end -do +do --- Complex struct field local s = ffi.new("struct { complex x;}") for i=1,100 do s.x = 12.5i @@ -102,10 +102,8 @@ do assert(s.x.im == 12.5) end --- Index overflow for complex is ignored -do +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/lib/ffi/ffi_jit_misc.lua b/test/lib/ffi/jit_misc.lua similarity index 90% rename from test/lib/ffi/ffi_jit_misc.lua rename to test/lib/ffi/jit_misc.lua index 800509afcd..41e4737bc7 100644 --- a/test/lib/ffi/ffi_jit_misc.lua +++ b/test/lib/ffi/jit_misc.lua @@ -1,6 +1,6 @@ local ffi = require("ffi") -do +do --- errno ffi.errno(42) local x = 0 for i=1,100 do x = x + ffi.errno() end @@ -8,7 +8,7 @@ do ffi.errno(0) end -do +do --- string local a = ffi.new("uint8_t[?]", 101) for i=0,99 do a[i] = i end local s @@ -18,7 +18,7 @@ do assert(s == "Z[\\]^_`abc") end -do +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 @@ -31,7 +31,7 @@ do assert(b[103] == (ffi.abi("le") and 0x343434 or 0x34343400)) end -do +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 @@ -43,7 +43,7 @@ do assert(x == 4095) end -do +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 @@ -51,7 +51,7 @@ do assert(x == 9276) end -do +do --- copy structures local tp = ffi.typeof("struct { int x, y; }") local a = tp(1, 2) local b = tp(3, 4) @@ -63,7 +63,7 @@ do assert(x == 5050) end -do +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)) @@ -72,7 +72,7 @@ do assert(x == 5050) end -do +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)) @@ -80,7 +80,7 @@ do assert(b.x[0] == 42 and b.x[9] == 42) end -do +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)) @@ -91,7 +91,7 @@ do assert(b.x[0] == 42 and b.x[4] == 42) end -do +do --- abi local x, y for i=1,100 do x = ffi.abi("32bit"); y = ffi.abi("64bit") end assert(x == ffi.abi("32bit")) @@ -102,9 +102,8 @@ do end end -do +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 - From 703e9cfb827f51c8bd900ebcb3ed4994f4a62672 Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Fri, 6 May 2016 22:26:46 +0100 Subject: [PATCH 33/68] Skip some tests under LuaJIT 2.0 --- test/lib/contents.lua | 6 +++++- test/lib/ffi/index | 2 +- test/opt/fold/kfold.lua | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/lib/contents.lua b/test/lib/contents.lua index b2a1a7adbc..0328c98917 100644 --- a/test/lib/contents.lua +++ b/test/lib/contents.lua @@ -147,5 +147,9 @@ do --- bit +bit 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:typeinfo:typeof") + 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/lib/ffi/index b/test/lib/ffi/index index c4091fb727..bda633000d 100644 --- a/test/lib/ffi/index +++ b/test/lib/ffi/index @@ -1,4 +1,4 @@ -bit64.lua +bit +bit64.lua +luajit>=2.1 copy_fill.lua err.lua istype.lua diff --git a/test/opt/fold/kfold.lua b/test/opt/fold/kfold.lua index 4100bf9150..9cd39190de 100644 --- a/test/opt/fold/kfold.lua +++ b/test/opt/fold/kfold.lua @@ -76,6 +76,6 @@ do --- sqrt exp log trig for i=1,100 do local a=23; y=math.tan(a) end assert(y==math.tan(23)) end -do --- exp +do --- exp -luajit==2.0 assert((10^-2 - 0.01) == 0) end From c3224bb76a67a4828af07d37cc10f4538c6e8953 Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Wed, 5 Oct 2016 00:54:50 +0100 Subject: [PATCH 34/68] Exercise TSETR and TSETM slow paths. --- test/lang/gc.lua | 12 ++++++++++++ test/lib/table/remove.lua | 19 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/test/lang/gc.lua b/test/lang/gc.lua index f820418084..35e6a1f336 100644 --- a/test/lang/gc.lua +++ b/test/lang/gc.lua @@ -28,3 +28,15 @@ do --- rechain 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/lib/table/remove.lua b/test/lib/table/remove.lua index 604f588ab5..1b24a4fb8c 100644 --- a/test/lib/table/remove.lua +++ b/test/lib/table/remove.lua @@ -21,3 +21,22 @@ do --- table.remove(t, 1) removes and returns the first entry 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 From 0dda7b2700ded31372d97edb98cf5fa5ca5d3f5b Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 8 Oct 2016 14:04:27 +0100 Subject: [PATCH 35/68] issue #8 baseline checkin of Lua 5.1 test suite --- lua5.1-tests/all.lua | 137 +++++ lua5.1-tests/api.lua | 711 ++++++++++++++++++++++ lua5.1-tests/attrib.lua | 339 +++++++++++ lua5.1-tests/big.lua | 381 ++++++++++++ lua5.1-tests/calls.lua | 294 +++++++++ lua5.1-tests/checktable.lua | 77 +++ lua5.1-tests/closure.lua | 422 +++++++++++++ lua5.1-tests/code.lua | 143 +++++ lua5.1-tests/constructs.lua | 240 ++++++++ lua5.1-tests/db.lua | 499 +++++++++++++++ lua5.1-tests/docs/README | 41 ++ lua5.1-tests/errors.lua | 250 ++++++++ lua5.1-tests/etc/ltests.c | 1147 +++++++++++++++++++++++++++++++++++ lua5.1-tests/etc/ltests.h | 92 +++ lua5.1-tests/events.lua | 360 +++++++++++ lua5.1-tests/files.lua | 324 ++++++++++ lua5.1-tests/gc.lua | 312 ++++++++++ lua5.1-tests/libs/lib1.c | 40 ++ lua5.1-tests/libs/lib11.c | 18 + lua5.1-tests/libs/lib2.c | 28 + lua5.1-tests/libs/lib21.c | 18 + lua5.1-tests/libs/makefile | 16 + lua5.1-tests/literals.lua | 176 ++++++ lua5.1-tests/locals.lua | 127 ++++ lua5.1-tests/main.lua | 159 +++++ lua5.1-tests/math.lua | 208 +++++++ lua5.1-tests/nextvar.lua | 396 ++++++++++++ lua5.1-tests/pm.lua | 273 +++++++++ lua5.1-tests/sort.lua | 74 +++ lua5.1-tests/strings.lua | 176 ++++++ lua5.1-tests/vararg.lua | 126 ++++ lua5.1-tests/verybig.lua | 100 +++ 32 files changed, 7704 insertions(+) create mode 100755 lua5.1-tests/all.lua create mode 100644 lua5.1-tests/api.lua create mode 100644 lua5.1-tests/attrib.lua create mode 100644 lua5.1-tests/big.lua create mode 100644 lua5.1-tests/calls.lua create mode 100644 lua5.1-tests/checktable.lua create mode 100644 lua5.1-tests/closure.lua create mode 100644 lua5.1-tests/code.lua create mode 100644 lua5.1-tests/constructs.lua create mode 100644 lua5.1-tests/db.lua create mode 100644 lua5.1-tests/docs/README create mode 100644 lua5.1-tests/errors.lua create mode 100644 lua5.1-tests/etc/ltests.c create mode 100644 lua5.1-tests/etc/ltests.h create mode 100644 lua5.1-tests/events.lua create mode 100644 lua5.1-tests/files.lua create mode 100644 lua5.1-tests/gc.lua create mode 100644 lua5.1-tests/libs/lib1.c create mode 100644 lua5.1-tests/libs/lib11.c create mode 100644 lua5.1-tests/libs/lib2.c create mode 100644 lua5.1-tests/libs/lib21.c create mode 100644 lua5.1-tests/libs/makefile create mode 100644 lua5.1-tests/literals.lua create mode 100644 lua5.1-tests/locals.lua create mode 100644 lua5.1-tests/main.lua create mode 100644 lua5.1-tests/math.lua create mode 100644 lua5.1-tests/nextvar.lua create mode 100644 lua5.1-tests/pm.lua create mode 100644 lua5.1-tests/sort.lua create mode 100644 lua5.1-tests/strings.lua create mode 100644 lua5.1-tests/vararg.lua create mode 100644 lua5.1-tests/verybig.lua diff --git a/lua5.1-tests/all.lua b/lua5.1-tests/all.lua new file mode 100755 index 0000000000..8c4afaced7 --- /dev/null +++ b/lua5.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/lua5.1-tests/api.lua b/lua5.1-tests/api.lua new file mode 100644 index 0000000000..c2d262f07b --- /dev/null +++ b/lua5.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/lua5.1-tests/attrib.lua b/lua5.1-tests/attrib.lua new file mode 100644 index 0000000000..b14d686643 --- /dev/null +++ b/lua5.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(ab == 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/lua5.1-tests/big.lua b/lua5.1-tests/big.lua new file mode 100644 index 0000000000..92612880ea --- /dev/null +++ b/lua5.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/lua5.1-tests/calls.lua b/lua5.1-tests/calls.lua new file mode 100644 index 0000000000..788f9a1cd1 --- /dev/null +++ b/lua5.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" 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/lua5.1-tests/closure.lua b/lua5.1-tests/closure.lua new file mode 100644 index 0000000000..94f72ae4a1 --- /dev/null +++ b/lua5.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/lua5.1-tests/code.lua b/lua5.1-tests/code.lua new file mode 100644 index 0000000000..efb13c7ae3 --- /dev/null +++ b/lua5.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/lua5.1-tests/constructs.lua b/lua5.1-tests/constructs.lua new file mode 100644 index 0000000000..470f85396f --- /dev/null +++ b/lua5.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/lua5.1-tests/db.lua b/lua5.1-tests/db.lua new file mode 100644 index 0000000000..09496f6fa5 --- /dev/null +++ b/lua5.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/lua5.1-tests/docs/README b/lua5.1-tests/docs/README new file mode 100644 index 0000000000..e2d4b28501 --- /dev/null +++ b/lua5.1-tests/docs/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/lua5.1-tests/errors.lua b/lua5.1-tests/errors.lua new file mode 100644 index 0000000000..3cc3211d7c --- /dev/null +++ b/lua5.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)", "", 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/lua5.1-tests/etc/ltests.c b/lua5.1-tests/etc/ltests.c new file mode 100644 index 0000000000..b14608bed5 --- /dev/null +++ b/lua5.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 +#include +#include +#include +#include + +#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;inumblocks--; + 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;igcstate == 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; isizek; i++) { + if (ttisstring(f->k+i)) + checkobjref(g, fgc, rawtsvalue(f->k+i)); + } + for (i=0; isizeupvalues; i++) { + if (f->upvalues[i]) + checkobjref(g, fgc, f->upvalues[i]); + } + for (i=0; isizep; i++) { + if (f->p[i]) + checkobjref(g, fgc, f->p[i]); + } + for (i=0; isizelocvars; 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; ic.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; il.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; pcl.p; + lua_newtable(L); + setnameval(L, "maxstack", p->maxstacksize); + setnameval(L, "numparams", p->numparams); + for (pc=0; pcsizecode; 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; isizek; 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, ""); + 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/lua5.1-tests/etc/ltests.h b/lua5.1-tests/etc/ltests.h new file mode 100644 index 0000000000..e5702127f8 --- /dev/null +++ b/lua5.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 + + +#define LUA_DEBUG + +#undef NDEBUG +#include +#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/lua5.1-tests/events.lua b/lua5.1-tests/events.lua new file mode 100644 index 0000000000..5234b007a0 --- /dev/null +++ b/lua5.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 aOp(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/lua5.1-tests/files.lua b/lua5.1-tests/files.lua new file mode 100644 index 0000000000..4175dc34a0 --- /dev/null +++ b/lua5.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/lua5.1-tests/gc.lua b/lua5.1-tests/gc.lua new file mode 100644 index 0000000000..86a9f7582c --- /dev/null +++ b/lua5.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/lua5.1-tests/libs/lib1.c b/lua5.1-tests/libs/lib1.c new file mode 100644 index 0000000000..da2c41481d --- /dev/null +++ b/lua5.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/lua5.1-tests/libs/lib11.c b/lua5.1-tests/libs/lib11.c new file mode 100644 index 0000000000..3efa3d3eb6 --- /dev/null +++ b/lua5.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/lua5.1-tests/libs/lib2.c b/lua5.1-tests/libs/lib2.c new file mode 100644 index 0000000000..9972cbe43d --- /dev/null +++ b/lua5.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/lua5.1-tests/libs/lib21.c b/lua5.1-tests/libs/lib21.c new file mode 100644 index 0000000000..167507f99b --- /dev/null +++ b/lua5.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/lua5.1-tests/libs/makefile b/lua5.1-tests/libs/makefile new file mode 100644 index 0000000000..03c33a3470 --- /dev/null +++ b/lua5.1-tests/libs/makefile @@ -0,0 +1,16 @@ +all: lib1.so lib11.so lib2.so lib21.so -lib2.so + +lib1.so: lib1.c + gcc -Wall -O2 -I../../ -ansi -shared -o lib1.so lib1.c + +lib11.so: lib11.c + gcc -Wall -O2 -I../../ -ansi -shared -o lib11.so lib11.c + +lib2.so: lib2.c + gcc -Wall -O2 -I../../ -ansi -shared -o lib2.so lib2.c + +lib21.so: lib21.c + gcc -Wall -O2 -I../../ -ansi -shared -o lib21.so lib21.c + +-lib2.so: lib2.so + cp lib2.so ./-lib2.so diff --git a/lua5.1-tests/literals.lua b/lua5.1-tests/literals.lua new file mode 100644 index 0000000000..01d84d5af6 --- /dev/null +++ b/lua5.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/lua5.1-tests/locals.lua b/lua5.1-tests/locals.lua new file mode 100644 index 0000000000..b0fc556f69 --- /dev/null +++ b/lua5.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/lua5.1-tests/main.lua b/lua5.1-tests/main.lua new file mode 100644 index 0000000000..22b4f74b02 --- /dev/null +++ b/lua5.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/lua5.1-tests/math.lua b/lua5.1-tests/math.lua new file mode 100644 index 0000000000..5076f38d77 --- /dev/null +++ b/lua5.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/lua5.1-tests/nextvar.lua b/lua5.1-tests/nextvar.lua new file mode 100644 index 0000000000..23be43d8ec --- /dev/null +++ b/lua5.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/lua5.1-tests/pm.lua b/lua5.1-tests/pm.lua new file mode 100644 index 0000000000..fa125dc979 --- /dev/null +++ b/lua5.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/lua5.1-tests/sort.lua b/lua5.1-tests/sort.lua new file mode 100644 index 0000000000..6fccd49ea2 --- /dev/null +++ b/lua5.1-tests/sort.lua @@ -0,0 +1,74 @@ +print"testing sort" + + +function check (a, f) + f = f or function (x,y) return x '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/lua5.1-tests/vararg.lua b/lua5.1-tests/vararg.lua new file mode 100644 index 0000000000..ae068facfd --- /dev/null +++ b/lua5.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/lua5.1-tests/verybig.lua b/lua5.1-tests/verybig.lua new file mode 100644 index 0000000000..59e0142a17 --- /dev/null +++ b/lua5.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 + From e6fc702477377eff589e237d92d5644b7870ceb2 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 8 Oct 2016 15:26:05 +0100 Subject: [PATCH 36/68] Create README.md --- lua5.1-tests/README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 lua5.1-tests/README.md diff --git a/lua5.1-tests/README.md b/lua5.1-tests/README.md new file mode 100644 index 0000000000..aa8e81112e --- /dev/null +++ b/lua5.1-tests/README.md @@ -0,0 +1,18 @@ +# Lua 5.1 Test Suite + +This directory contains a modified version of the Lua 5.1 test suite. The modifications are primarily to disable or amend some tests +so that the test suite can be run. + +## Running the test suite + +You need to have `luajit` on your path. + +On UNIX systems just execute: +``` +./run.sh +``` + +## Tests disabled or ignored +Wherever tests have been switched off or ignored a comment has been added and the code has been made conditional. These failures will +be investigated and either the tests will be modified or permanently disabled depending upon whether the issue is one of compatibility +or a defect in LuaJIT. From e832e541b29067e449643bb586fd9b1eece1f8cd Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 8 Oct 2016 15:29:04 +0100 Subject: [PATCH 37/68] Update README.md --- lua5.1-tests/README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lua5.1-tests/README.md b/lua5.1-tests/README.md index aa8e81112e..a902cacaaf 100644 --- a/lua5.1-tests/README.md +++ b/lua5.1-tests/README.md @@ -15,4 +15,12 @@ On UNIX systems just execute: ## Tests disabled or ignored Wherever tests have been switched off or ignored a comment has been added and the code has been made conditional. These failures will be investigated and either the tests will be modified or permanently disabled depending upon whether the issue is one of compatibility -or a defect in LuaJIT. +or a defect in LuaJIT. + +Example of excluded test: +``` +if not jit then + -- FIXME tests fail in LuaJIT + dofile('main.lua') +end +``` From 1cb616175fed20629d1ff63363ff543d84577552 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 8 Oct 2016 16:30:08 +0100 Subject: [PATCH 38/68] issue #8 initial attempt to get the tests running --- lua5.1-tests/all.lua | 11 +++++++---- lua5.1-tests/closure.lua | 3 ++- lua5.1-tests/errors.lua | 15 +++++++++------ lua5.1-tests/literals.lua | 3 ++- lua5.1-tests/run.sh | 18 ++++++++++++++++++ lua5.1-tests/strings.lua | 15 +++++++++------ lua5.1-tests/vararg.lua | 16 ++++++++++------ 7 files changed, 57 insertions(+), 24 deletions(-) create mode 100644 lua5.1-tests/run.sh diff --git a/lua5.1-tests/all.lua b/lua5.1-tests/all.lua index 8c4afaced7..30c1c72e86 100755 --- a/lua5.1-tests/all.lua +++ b/lua5.1-tests/all.lua @@ -66,7 +66,8 @@ dofile = function (n) return f() end -dofile('main.lua') +-- FIXME tests fail in LuaJIT +--dofile('main.lua') do local u = newproxy(true) @@ -77,9 +78,11 @@ do end end -local f = assert(loadfile('gc.lua')) -f() -dofile('db.lua') +-- FIXME tests fail in LuaJIT +-- local f = assert(loadfile('gc.lua')) +-- f() +-- FIXME tests fail in LuaJIT +-- dofile('db.lua') assert(dofile('calls.lua') == deep and deep) dofile('strings.lua') dofile('literals.lua') diff --git a/lua5.1-tests/closure.lua b/lua5.1-tests/closure.lua index 94f72ae4a1..6643c83769 100644 --- a/lua5.1-tests/closure.lua +++ b/lua5.1-tests/closure.lua @@ -174,7 +174,8 @@ f = coroutine.wrap(foo) local a = {} assert(f(a) == _G) local a,b = pcall(f) -assert(a and b == _G) +-- FIXME assertion fails in LuaJIT +--assert(a and b == _G) -- tests for multiple yield/resume arguments diff --git a/lua5.1-tests/errors.lua b/lua5.1-tests/errors.lua index 3cc3211d7c..864d640730 100644 --- a/lua5.1-tests/errors.lua +++ b/lua5.1-tests/errors.lua @@ -72,8 +72,9 @@ 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'")) +-- FIXME assertion fails in LuaJIT +--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 @@ -100,9 +101,10 @@ while 1 do insert(prefix, a) end]], "global 'insert'") -checkmessage([[ -- tail call - return math.sin("a") -]], "'sin'") +-- FIXME assertion fails in LuaJIT +--checkmessage([[ -- tail call +-- return math.sin("a") +--]], "'sin'") checkmessage([[collectgarbage("nooption")]], "invalid option") @@ -193,7 +195,8 @@ checksyntax("[[a]]", "", "[[a]]", 1) checksyntax("'aa'", "", "'aa'", 1) -- test 255 as first char in a chunk -checksyntax("\255a = 1", "", "\255", 1) +-- FIXME assertion fails in LuaJIT +-- checksyntax("\255a = 1", "", "\255", 1) doit('I = loadstring("a=9+"); a=3') assert(a==3 and I == nil) diff --git a/lua5.1-tests/literals.lua b/lua5.1-tests/literals.lua index 01d84d5af6..49d4763e2a 100644 --- a/lua5.1-tests/literals.lua +++ b/lua5.1-tests/literals.lua @@ -159,7 +159,8 @@ 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) +-- FIXME assertion fails in LuaJIT + --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.) diff --git a/lua5.1-tests/run.sh b/lua5.1-tests/run.sh new file mode 100644 index 0000000000..ba4537fd66 --- /dev/null +++ b/lua5.1-tests/run.sh @@ -0,0 +1,18 @@ +export LUA_PATH="?;./?.lua" +export LUA_INIT="package.path = '?;'..package.path" + +luajit -joff all.lua +if [ $? != 0 ] +then + echo "all.lua tests failed with JIT on" + exit 1 +fi + + +luajit -jon all.lua +if [ $? != 0 ] +then + echo "all.lua tests failed with JIT off" + exit 1 +fi + diff --git a/lua5.1-tests/strings.lua b/lua5.1-tests/strings.lua index 237dbad36f..bf48f28b91 100644 --- a/lua5.1-tests/strings.lua +++ b/lua5.1-tests/strings.lua @@ -102,7 +102,8 @@ print('+') x = '"ílo"\n\\' assert(string.format('%q%s', x, x) == '"\\"ílo\\"\\\n\\\\""ílo"\n\\') -assert(string.format('%q', "\0") == [["\000"]]) +-- FIXME assertion fails in LuaJIT +--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('') == "") @@ -155,16 +156,18 @@ end if not trylocale("collate") then print("locale not supported") else - assert("alo" < "álo" and "álo" < "amo") +-- FIXME assertion fails in LuaJIT +-- 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") +-- FIXME assertion fails in LuaJIT +-- 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") diff --git a/lua5.1-tests/vararg.lua b/lua5.1-tests/vararg.lua index ae068facfd..453511f3a3 100644 --- a/lua5.1-tests/vararg.lua +++ b/lua5.1-tests/vararg.lua @@ -21,9 +21,10 @@ 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) +-- FIXME assertion fails in LuaJIT +--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})) @@ -35,15 +36,18 @@ 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) +-- FIXME assertion fails in LuaJIT +--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) +-- FIXME assertion fails in LuaJIT +--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) +-- FIXME assertion fails in LuaJIT +--assert(t:f(1,4) == 3 and t:f(2) == 11) print('+') lim = 20 From 0497c7b23c31a1d9e24a518795ce6096b35170b0 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 8 Oct 2016 16:32:28 +0100 Subject: [PATCH 39/68] issue #8 initial attempt to get the tests running --- lua5.1-tests/README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lua5.1-tests/README.md b/lua5.1-tests/README.md index a902cacaaf..81544c0671 100644 --- a/lua5.1-tests/README.md +++ b/lua5.1-tests/README.md @@ -19,8 +19,6 @@ or a defect in LuaJIT. Example of excluded test: ``` -if not jit then - -- FIXME tests fail in LuaJIT - dofile('main.lua') -end +-- FIXME tests fail in LuaJIT +-- dofile('main.lua') ``` From 45b22589b364201ba0ac7e3c3db36f8ed2d6eeed Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 8 Oct 2016 16:34:32 +0100 Subject: [PATCH 40/68] issue #8 initial attempt to get the tests running --- lua5.1-tests/run.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua5.1-tests/run.sh b/lua5.1-tests/run.sh index ba4537fd66..2cd06ae16f 100644 --- a/lua5.1-tests/run.sh +++ b/lua5.1-tests/run.sh @@ -4,7 +4,7 @@ export LUA_INIT="package.path = '?;'..package.path" luajit -joff all.lua if [ $? != 0 ] then - echo "all.lua tests failed with JIT on" + echo "all.lua tests failed with JIT off" exit 1 fi @@ -12,7 +12,7 @@ fi luajit -jon all.lua if [ $? != 0 ] then - echo "all.lua tests failed with JIT off" + echo "all.lua tests failed with JIT on" exit 1 fi From b1163138341459fae54ac1a369931473f708b6e5 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 8 Oct 2016 19:11:01 +0100 Subject: [PATCH 41/68] Update README.md --- lua5.1-tests/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lua5.1-tests/README.md b/lua5.1-tests/README.md index 81544c0671..464365b307 100644 --- a/lua5.1-tests/README.md +++ b/lua5.1-tests/README.md @@ -3,13 +3,17 @@ This directory contains a modified version of the Lua 5.1 test suite. The modifications are primarily to disable or amend some tests so that the test suite can be run. +## LuaJIT build options + +Some tests will fail if LUA 5.2 compatibility is turned on. + ## Running the test suite You need to have `luajit` on your path. On UNIX systems just execute: ``` -./run.sh +sh run.sh ``` ## Tests disabled or ignored From ea00addbe87e47feeb313b31874b08490efba5c7 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 8 Oct 2016 19:15:56 +0100 Subject: [PATCH 42/68] issue #8 add 5.2.2 tests --- lua-5.2.2-tests/all.lua | 259 ++++++ lua-5.2.2-tests/api.lua | 1009 +++++++++++++++++++++ lua-5.2.2-tests/attrib.lua | 421 +++++++++ lua-5.2.2-tests/big.lua | 79 ++ lua-5.2.2-tests/bitwise.lua | 115 +++ lua-5.2.2-tests/calls.lua | 310 +++++++ lua-5.2.2-tests/checktable.lua | 77 ++ lua-5.2.2-tests/closure.lua | 244 +++++ lua-5.2.2-tests/code.lua | 182 ++++ lua-5.2.2-tests/constructs.lua | 310 +++++++ lua-5.2.2-tests/coroutine.lua | 728 +++++++++++++++ lua-5.2.2-tests/db.lua | 631 +++++++++++++ lua-5.2.2-tests/errors.lua | 422 +++++++++ lua-5.2.2-tests/events.lua | 388 ++++++++ lua-5.2.2-tests/files.lua | 615 +++++++++++++ lua-5.2.2-tests/gc.lua | 575 ++++++++++++ lua-5.2.2-tests/goto.lua | 173 ++++ lua-5.2.2-tests/libs/lib1.c | 49 + lua-5.2.2-tests/libs/lib11.c | 18 + lua-5.2.2-tests/libs/lib2.c | 29 + lua-5.2.2-tests/libs/lib21.c | 18 + lua-5.2.2-tests/libs/makefile | 26 + lua-5.2.2-tests/literals.lua | 258 ++++++ lua-5.2.2-tests/locals.lua | 157 ++++ lua-5.2.2-tests/ltests/ltests.c | 1506 +++++++++++++++++++++++++++++++ lua-5.2.2-tests/ltests/ltests.h | 93 ++ lua-5.2.2-tests/main.lua | 260 ++++++ lua-5.2.2-tests/math.lua | 287 ++++++ lua-5.2.2-tests/nextvar.lua | 461 ++++++++++ lua-5.2.2-tests/pm.lua | 344 +++++++ lua-5.2.2-tests/sort.lua | 167 ++++ lua-5.2.2-tests/strings.lua | 281 ++++++ lua-5.2.2-tests/vararg.lua | 125 +++ lua-5.2.2-tests/verybig.lua | 144 +++ 34 files changed, 10761 insertions(+) create mode 100755 lua-5.2.2-tests/all.lua create mode 100644 lua-5.2.2-tests/api.lua create mode 100644 lua-5.2.2-tests/attrib.lua create mode 100644 lua-5.2.2-tests/big.lua create mode 100755 lua-5.2.2-tests/bitwise.lua create mode 100644 lua-5.2.2-tests/calls.lua create mode 100644 lua-5.2.2-tests/checktable.lua create mode 100644 lua-5.2.2-tests/closure.lua create mode 100644 lua-5.2.2-tests/code.lua create mode 100644 lua-5.2.2-tests/constructs.lua create mode 100644 lua-5.2.2-tests/coroutine.lua create mode 100644 lua-5.2.2-tests/db.lua create mode 100644 lua-5.2.2-tests/errors.lua create mode 100644 lua-5.2.2-tests/events.lua create mode 100644 lua-5.2.2-tests/files.lua create mode 100644 lua-5.2.2-tests/gc.lua create mode 100644 lua-5.2.2-tests/goto.lua create mode 100644 lua-5.2.2-tests/libs/lib1.c create mode 100644 lua-5.2.2-tests/libs/lib11.c create mode 100644 lua-5.2.2-tests/libs/lib2.c create mode 100644 lua-5.2.2-tests/libs/lib21.c create mode 100644 lua-5.2.2-tests/libs/makefile create mode 100644 lua-5.2.2-tests/literals.lua create mode 100644 lua-5.2.2-tests/locals.lua create mode 100644 lua-5.2.2-tests/ltests/ltests.c create mode 100644 lua-5.2.2-tests/ltests/ltests.h create mode 100644 lua-5.2.2-tests/main.lua create mode 100644 lua-5.2.2-tests/math.lua create mode 100644 lua-5.2.2-tests/nextvar.lua create mode 100644 lua-5.2.2-tests/pm.lua create mode 100644 lua-5.2.2-tests/sort.lua create mode 100644 lua-5.2.2-tests/strings.lua create mode 100644 lua-5.2.2-tests/vararg.lua create mode 100644 lua-5.2.2-tests/verybig.lua diff --git a/lua-5.2.2-tests/all.lua b/lua-5.2.2-tests/all.lua new file mode 100755 index 0000000000..d2840a9adf --- /dev/null +++ b/lua-5.2.2-tests/all.lua @@ -0,0 +1,259 @@ +#!../lua + +local version = "Lua 5.2" +if _VERSION ~= version then + io.stderr:write("\nThis test suite is for ", version, ", not for ", _VERSION, + "\nExiting tests\n") + return +end + + +-- next variables control the execution of some tests +-- true means no test (so an undefined variable does not skip a test) +-- defaults are for Linux; test everything + +_soft = false -- true to avoid long or memory consuming tests +_port = false -- true to avoid non-portable tests +_no32 = false -- true to avoid tests that assume 32 bits +_nomsg = false -- true to avoid messages about tests not performed +_noposix = false -- false assumes LUA_USE_POSIX +_nolonglong = false -- false assumes LUA_USE_LONGLONG +_noformatA = false -- false assumes LUA_USE_AFORMAT + + +local usertests = rawget(_G, "_U") + +if usertests then + -- tests for sissies ;) Avoid problems + _soft = true + _port = true + _no32 = true + _nomsg = true + _noposix = true + _nolonglong = true + _noformatA = true; +end + +-- no "internal" tests for user tests +if usertests then T = nil end + +T = rawget(_G, "T") -- avoid problems with 'strict' module + +package.path = "?;./?.lua" .. package.path + +math.randomseed(0) + +collectgarbage("setstepmul", 200) +collectgarbage("setpause", 200) + + +--[=[ + example of a long [comment], + [[spanning several [lines]]] + +]=] + +print("current path:\n****" .. package.path .. "****\n") + + +local c = os.clock() + +local collectgarbage = collectgarbage + +do -- ( + +-- track messages for tests not performed +local msgs = {} +function Message (m) + if not _nomsg then + print(m) + msgs[#msgs+1] = string.sub(m, 3, -3) + end +end + +assert(os.setlocale"C") + +local T,print,format,write,assert,type,unpack,floor = + T,print,string.format,io.write,assert,type,table.unpack,math.floor + +-- use K for 1000 and M for 1000000 (not 2^10 -- 2^20) +local function F (m) + local function round (m) + m = m + 0.04999 + return m - (m % 0.1) -- keep one decimal digit + end + if m < 1000 then return m + else + m = m / 1000 + if m < 1000 then return round(m).."K" + else + return round(m/1000).."M" + end + end +end + +local showmem +if not T then + local max = 0 + showmem = function () + local m = collectgarbage("count") * 1024 + max = (m > max) and m or max + print(format(" ---- total memory: %s, max memory: %s ----\n", + F(m), F(max))) + end +else + showmem = function () + T.checkmemory() + local total, numblocks, maxmem = T.totalmem() + local count = collectgarbage("count") + print(format( + "\n ---- total memory: %s (%.0fK), max use: %s, blocks: %d\n", + F(total), count, F(maxmem), numblocks)) + print(format("\t(strings: %d, tables: %d, functions: %d, ".. + "\n\tudata: %d, threads: %d)", + T.totalmem"string", T.totalmem"table", T.totalmem"function", + T.totalmem"userdata", T.totalmem"thread")) + end +end + + +-- +-- redefine dofile to run files through dump/undump +-- +local function report (n) print("\n***** FILE '"..n.."'*****") end +local olddofile = dofile +dofile = function (n) + showmem() + report(n) + local f = assert(loadfile(n)) + local b = string.dump(f) + f = assert(load(b)) + return f() +end + +dofile('main.lua') + +do + local next, setmetatable, stderr = next, setmetatable, io.stderr + local mt = {} + -- each time a table is collected, create a new one to be + -- collected next cycle + mt.__gc = function (o) + stderr:write'.' -- mark progress + local n = setmetatable({}, mt) -- replicate object + o = nil + local a,b,c,d,e = nil -- erase 'o' from the stack + end + local n = setmetatable({}, mt) -- replicate object +end + +report"gc.lua" +local f = assert(loadfile('gc.lua')) +f() + +collectgarbage("generational") +dofile('db.lua') +assert(dofile('calls.lua') == deep and deep) +olddofile('strings.lua') +olddofile('literals.lua') +assert(dofile('attrib.lua') == 27) + +collectgarbage("incremental") -- redo some tests in incremental mode +olddofile('strings.lua') +olddofile('literals.lua') +dofile('constructs.lua') +dofile('api.lua') + +collectgarbage("generational") -- back to generational mode +collectgarbage("setpause", 200) +collectgarbage("setmajorinc", 500) +assert(dofile('locals.lua') == 5) +dofile('constructs.lua') +dofile('code.lua') +if not _G._soft then + report('big.lua') + 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('coroutine.lua') +dofile('goto.lua') +dofile('errors.lua') +dofile('math.lua') +dofile('sort.lua') +dofile('bitwise.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 !!!") + +local debug = require "debug" + +debug.sethook(function (a) assert(type(a) == 'string') end, "cr") + +-- to survive outside block +_G.showmem = showmem + +end --) + +local _G, showmem, print, format, clock, assert, open = + _G, showmem, print, string.format, os.clock, assert, io.open + +-- file with time of last performed test +local fname = T and "time-debug.txt" or "time.txt" +local lasttime + +if not usertests then + -- open file with time of last performed test + local f = io.open(fname) + if f then + lasttime = assert(tonumber(f:read'*a')) + f:close(); + else -- no such file; assume it is recording time for first time + lasttime = nil + end +end + +-- erase (almost) all globals +print('cleaning all!!!!') +for n in pairs(_G) do + if not ({___Glob = 1, tostring = 1})[n] then + _G[n] = nil + end +end + + +collectgarbage() +collectgarbage() +collectgarbage() +collectgarbage() +collectgarbage() +collectgarbage();showmem() + +local time = clock() - c + +print(format("\n\ntotal time: %.2f\n", time)) + +if not usertests then + lasttime = lasttime or time -- if there is no last time, ignore difference + -- check whether current test time differs more than 5% from last time + local diff = (time - lasttime) / time + local tolerance = 0.05 -- 5% + assert(diff < tolerance and diff > -tolerance) + assert(open(fname, "w")):write(time):close() +end + diff --git a/lua-5.2.2-tests/api.lua b/lua-5.2.2-tests/api.lua new file mode 100644 index 0000000000..a367fc8f05 --- /dev/null +++ b/lua-5.2.2-tests/api.lua @@ -0,0 +1,1009 @@ + +if T==nil then + (Message or print)('\a\n >>> testC not active: skipping API tests <<<\n\a') + return +end + +local debug = require "debug" + +local pack = table.pack + + +function tcheck (t1, t2) + assert(t1.n == (t2.n or #t2) + 1) + for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end +end + + +print('testing C API') + +a = T.testC("pushvalue R; return 1") +assert(a == debug.getregistry()) + + +-- absindex +assert(T.testC("settop 10; absindex -1; return 1") == 10) +assert(T.testC("settop 5; absindex -5; return 1") == 1) +assert(T.testC("settop 10; absindex 1; return 1") == 1) +assert(T.testC("settop 10; absindex R; return 1") < -10) + +-- 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) + +f = T.makeCfunc("pushnum 1; pushnum 2; pushnum 3; return 2") +a,b,c = f() +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==false and b==true and c==false) + + +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("copy 3 4; gettop; return .", 2, 3, 4, 5)) +tcheck(t, {n=4,2,3,3,5}) + +t = pack(T.testC("copy -3 -1; gettop; return .", 2, 3, 4, 5)) +tcheck(t, {n=4,2,3,4,3}) + + + + +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("call 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([[pcall 1 -1; pop 1; tostring -1; return 1]], + table.unpack, a) + assert(b == "10") +end + + +-- testing globals +_G.a = 14; _G.b = "a31" +local a = {T.testC[[ + getglobal a; + getglobal b; + getglobal b; + setglobal a; + gettop; + return . +]]} +assert(a[2] == 14 and a[3] == "a31" and a[4] == nil and _G.a == "a31") + + +-- testing arith +assert(T.testC("pushnum 10; pushnum 20; arith /; return 1") == 0.5) +assert(T.testC("pushnum 10; pushnum 20; arith -; return 1") == -10) +assert(T.testC("pushnum 10; pushnum -20; arith *; return 1") == -200) +assert(T.testC("pushnum 10; pushnum 3; arith ^; return 1") == 1000) +assert(T.testC("pushnum 10; pushstring 20; arith /; return 1") == 0.5) +assert(T.testC("pushstring 10; pushnum 20; arith -; return 1") == -10) +assert(T.testC("pushstring 10; pushstring -20; arith *; return 1") == -200) +assert(T.testC("pushstring 10; pushstring 3; arith ^; return 1") == 1000) +a,b,c = T.testC([[pushnum 1; + pushstring 10; arith _; + pushstring 5; return 3]]) +assert(a == 1 and b == -10 and c == "5") +mt = {__add = function (a,b) return setmetatable({a[1] + b[1]}, mt) end, + __mod = function (a,b) return setmetatable({a[1] % b[1]}, mt) end, + __unm = function (a) return setmetatable({a[1]* 2}, mt) end} +a,b,c = setmetatable({4}, mt), + setmetatable({8}, mt), + setmetatable({-3}, mt) +x,y,z = T.testC("arith +; return 2", 10, a, b) +assert(x == 10 and y[1] == 12 and z == nil) +assert(T.testC("arith %; return 1", a, c)[1] == 4%-3) +assert(T.testC("arith _; arith +; arith %; return 1", b, a, c)[1] == + 8 % (4 + (-3)*2)) + + +-- testing compare +-- EQ = 0; LT = 1; LE = 2 + +-- testing lessthan and lessequal +assert(T.testC("compare 2 5 1, return 1", 3, 2, 2, 4, 2, 2)) +assert(T.testC("compare 2 5 2, return 1", 3, 2, 2, 4, 2, 2)) +assert(not T.testC("compare 3 4 1, return 1", 3, 2, 2, 4, 2, 2)) +assert(T.testC("compare 3 4 2, return 1", 3, 2, 2, 4, 2, 2)) +assert(T.testC("compare 5 2 1, return 1", 4, 2, 2, 3, 2, 2)) +assert(not T.testC("compare 2 -3 1, return 1", "4", "2", "2", "3", "2", "2")) +assert(not T.testC("compare -3 2 1, return 1", "3", "2", "2", "4", "2", "2")) + +-- non-valid indices produce false +assert(not T.testC("compare 1 4 1, return 1")) +assert(not T.testC("compare 9 1 2, return 1")) +assert(not T.testC("compare 9 9 0, return 1")) + +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("compare 2 5 1, return 1", a3, 2, 2, a4, 2, 2)) +assert(T.testC("compare 2 5 2, return 1", a3, 2, 2, a4, 2, 2)) +assert(T.testC("compare 5 -6 1, return 1", a4, 2, 2, a3, 2, 2)) +a,b = T.testC("compare 5 -6 1, return 2", a1, 2, 2, a3, 2, 20) +assert(a == 20 and b == false) +a,b = T.testC("compare 5 -6 2, return 2", a1, 2, 2, a3, 2, 20) +assert(a == 20 and b == false) +a,b = T.testC("compare 5 -6 2, return 2", a1, 2, 2, a1, 2, 20) +assert(a == 20 and b == true) + +-- testing length +local t = setmetatable({x = 20}, {__len = function (t) return t.x end}) +a,b,c = T.testC([[ + len 2; + Llen 2; + objsize 2; + return 3 +]], t) +assert(a == 20 and b == 20 and c == 0) + +t.x = "234"; t[1] = 20 +a,b,c = T.testC([[ + len 2; + Llen 2; + objsize 2; + return 3 +]], t) +assert(a == "234" and b == 234 and c == 1) + +t.x = print; t[1] = 20 +a,c = T.testC([[ + len 2; + objsize 2; + return 2 +]], t) +assert(a == print and c == 1) + + +-- testing __concat + +a = setmetatable({x="u"}, {__concat = function (a,b) return a.x..'.'..b.x end}) +x,y = T.testC([[ + pushnum 5 + pushvalue 2; + pushvalue 2; + concat 2; + pushvalue -2; + return 2; +]], a, a) +assert(x == a..a and y == 5) + +-- concat with 0 elements +assert(T.testC("concat 0; return 1") == "") + +-- concat with 1 element +assert(T.testC("concat 1; return 1", "xuxu") == "xuxu") + + + +-- testing lua_is + +function B(x) return x and 1 or 0 end + +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 B(a)+B(b)+B(c)+B(d)+B(e)+B(f)+B(g)+(100*B(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", {1,2,3}) == 3) +assert(to("objsize", "alo\0\0a") == 6) +assert(to("objsize", T.newuserdata(0)) == 0) +assert(to("objsize", T.newuserdata(101)) == 101) +assert(to("objsize", 124) == 0) +assert(to("objsize", true) == 0) +assert(to("tonumber", {}) == 0) +assert(to("tonumber", "12") == 12) +assert(to("tonumber", "s2") == 0) +assert(to("tonumber", 1, 20) == 0) +assert(to("topointer", 10) == 0) +assert(to("topointer", true) == 0) +assert(to("topointer", T.pushuserdata(20)) == 20) +assert(to("topointer", io.read) ~= 0) +assert(to("func2num", 20) == 0) +assert(to("func2num", T.pushuserdata(10)) == 0) +assert(to("func2num", io.read) ~= 0) +a = to("tocfunction", math.deg) +assert(a(3) == math.deg(3) and a == math.deg) + + + +-- testing deep C stack +do + collectgarbage("stop") + local s, msg = pcall(T.testC, "checkstack 1000023 XXXX") -- too deep + assert(not s and string.find(msg, "XXXX")) + s = string.rep("pushnil;checkstack 1 XX;", 1000000) + s, msg = pcall(T.testC, s) + assert(not s and string.find(msg, "XX")) + collectgarbage("restart") +end + +local prog = {"checkstack 30000 msg", "newtable"} +for i = 1,12000 do + prog[#prog + 1] = "pushnum " .. i + prog[#prog + 1] = "pushnum " .. i * 10 +end + +prog[#prog + 1] = "rawgeti R 2" -- get global table in registry +prog[#prog + 1] = "insert " .. -(2*12000 + 2) + +for i = 1,12000 do + prog[#prog + 1] = "settable " .. -(2*(12000 - i + 1) + 1) +end + +prog[#prog + 1] = "return 2" + +prog = table.concat(prog, ";") +local g, t = T.testC(prog) +assert(g == _G) +for i = 1,12000 do assert(t[i] == i*10); t[i] = nil end +assert(next(t) == nil) +prog, g, t = nil + +-- testing errors + +a = T.testC([[ + loadstring 2; pcall 0,1; + pushvalue 3; insert -2; pcall 1, 1; + pcall 0, 0; + return 1 +]], "x=150", function (a) assert(a==nil); return 3 end) + +assert(type(a) == 'string' and x == 150) + +function check3(p, ...) + local arg = {...} + assert(#arg == 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")) + +-- test errors in non protected threads +function checkerrnopro (code, msg) + L = coroutine.create(function () end) + local stt, err = pcall(T.testC, code) + assert(not stt and string.find(err, msg)) +end + +checkerrnopro("pushnum 3; call 0 0", "attempt to call") +function f () f() end +checkerrnopro("getglobal 'f'; call 0 0;", "stack overflow") + + +-- 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 + + +-- testing absent upvalues from C-function pointers +assert(T.testC[[isnull U1; return 1]] == true) +assert(T.testC[[isnull U100; return 1]] == true) +assert(T.testC[[pushvalue U1; return 1]] == nil) + +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") + + +-- large closures +do + local A = "checkstack 300 msg;" .. + string.rep("pushnum 10;", 255) .. + "pushcclosure 255; return 1" + A = T.testC(A) + for i=1,255 do + assert(A(("pushvalue U%d; return 1"):format(i)) == 10) + end + assert(A("isnull U256; return 1")) + assert(not A("isnil U256; return 1")) +end + + + +-- bug in 5.1.2 +assert(not pcall(debug.setuservalue, 3, {})) +assert(not pcall(debug.setuservalue, nil, {})) +assert(not pcall(debug.setuservalue, T.pushuserdata(1), {})) + +local b = T.newuserdata(0) +local a = {} +assert(debug.getuservalue(b) == nil) +assert(debug.setuservalue(b, a)) +assert(debug.getuservalue(b) == a) +assert(debug.setuservalue(b, nil)) +assert(debug.getuservalue(b) == nil) + +assert(debug.getuservalue(4) == nil) + + + +-- 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 f = T.makeCfunc("gettable R; return 1") + local n = f("n") + print("n", n) + for i=0,n do + print(i, f(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) + assert(load("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 T.newuserdata(0) end + assert(collectgarbage("count") > x+10) + collectgarbage() + assert(collectgarbage("count") <= x+1) + -- udata with finalizer + x = collectgarbage("count") + collectgarbage() + collectgarbage("stop") + a = {__gc = function () end} + for i=1,1000 do debug.setmetatable(T.newuserdata(0), 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) + collectgarbage("restart") +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(not pcall(io.input, a)) +assert(not pcall(io.input, x)) + +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(#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(#cl == 4) +-- check order of collection +assert(cl[2] == n5 and cl[3] == nb and cl[4] == na) + +collectgarbage"restart" + + +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(#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(#cl == 0) +for n in pairs(a) do a[n] = nil end +collectgarbage() +assert(#cl == 1 and cl[1] == x) -- old `x' must be collected + +-- testing lua_equal +assert(T.testC("compare 2 4 0; return 1", print, 1, print, 20)) +assert(T.testC("compare 3 2 0; return 1", 'alo', "alo")) +assert(T.testC("compare 2 3 0; return 1", nil, nil)) +assert(not T.testC("compare 2 3 0; return 1", {}, {})) +assert(not T.testC("compare 2 3 0; return 1")) +assert(not T.testC("compare 2 3 0; 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("compare 2 3 0; return 1", f(10), f(10))) + assert(not T.testC("compare 2 3 0; return 1", f(10), f(20))) + t.__eq = nil + assert(f(10) ~= f(10)) +end + +print'+' + + + +-- testing changing hooks during hooks +_G.t = {} +T.sethook([[ + # set a line hook after 3 count hooks + sethook 4 0 ' + getglobal t; + pushvalue -3; append -2 + pushvalue -2; append -2 + ']], "c", 3) +local a = 1 -- counting +a = 1 -- counting +a = 1 -- count hook (set line hook) +a = 1 -- line hook +a = 1 -- line hook +debug.sethook() +t = _G.t +assert(t[1] == "line") +line = t[2] +assert(t[3] == "line" and t[4] == line + 1) +assert(t[5] == "line" and t[6] == line + 2) +assert(t[7] == nil) + + +------------------------------------------------------------------------- +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 errors 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) load("A=A+1")() end}) + end + _G.A = 0 + a = 0 + while 1 do + local stat, msg = pcall(collectgarbage) + if stat then + break -- stop when no more errors + else + a = a + 1 + assert(string.find(msg, "__gc")) + 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(T.doremote(L1, "X='a'; return 'a'") == 'a') + + +assert(#pack(T.doremote(L1, "function f () return 'alo', 3 end; f()")) == 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 c == 3 and type(b) == "string") -- 3 == syntax error + +T.loadlib(L1) +a, b, c = T.doremote(L1, [[ + string = require'string' + a = require'_G'; assert(a == _G and require("_G") == a) + io = require'io'; assert(type(io.read) == "function") + assert(require("io") == io) + a = require'table'; assert(type(a.insert) == "function") + a = require'debug'; assert(type(a.getlocal) == "function") + a = require'math'; 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, [[getglobal "a"; pushstring "x"; pushnum 1; + settable -3]]) +assert(T.doremote(L1, "return a.x") == "1") + +T.closestate(L1) + +L1 = nil + +print('+') + +------------------------------------------------------------------------- +-- testing memory limits +------------------------------------------------------------------------- +assert(not pcall(T.newuserdata, 2^32-4)) +collectgarbage() +T.totalmem(T.totalmem()+5000) -- set low memory limit (+5k) +assert(not pcall(load"local a={}; for i=1,100000 do a[i]=i end")) +T.totalmem(1000000000) -- restore high limit + +-- 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(); collectgarbage() + local M = T.totalmem() + local oldM = M + local a,b = nil + while 1 do + M = M+7 -- increase memory limit in small steps + T.totalmem(M) + a, b = pcall(f) + T.totalmem(1000000000) -- restore high limit + if a and b then break end -- stop when no more errors + collectgarbage() + if not a and not -- `real' error? + (string.find(b, "memory") or string.find(b, "overflow")) then + error(b, 0) -- propagate it + end + end + 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 + +-- get main thread from registry (at index LUA_RIDX_MAINTHREAD == 1) +mt = T.testC("rawgeti R 1; return 1") +assert(type(mt) == "thread" and coroutine.running() == mt) + + + +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") +load(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 load("x=1") -- try to do load a string +end) + + +local testprog = [[ +local function foo () return end +local t = {"x"} +a = "aaa" +for i = 1, #t do a=a..t[i] 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 = load(testprog) + local b = a and string.dump(a) + a = b and load(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) + +testamem("constructors", function () + local a = {10, 20, 30, 40, 50; a=1, b=2, c=3, d=4, e=5} + return (type(a) == 'table' and a.e == 5) +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 +local function gsub (a, b, c) + a, b = T.testC("gsub 2 3 4; gettop; return 2", a, b, c) + assert(b == 5) + return a +end + +assert(gsub("alo.alo.uhuh.", ".", "//") == "alo//alo//uhuh//") +assert(gsub("alo.alo.uhuh.", "alo", "//") == "//.//.uhuh.") +assert(gsub("", "alo", "//") == "") +assert(gsub("...", ".", "/.") == "/././.") +assert(gsub("...", "...", "") == "") + + +-- testing luaL_newmetatable +local mt_xuxu, res, top = T.testC("newmetatable xuxu; gettop; return 3") +assert(type(mt_xuxu) == "table" and res and top == 3) +local d, res, top = T.testC("newmetatable xuxu; gettop; return 3") +assert(mt_xuxu == d and not res and top == 3) +d, res, top = T.testC("newmetatable xuxu1; gettop; return 3") +assert(mt_xuxu ~= d and res and top == 3) + +x = T.newuserdata(0); +y = T.newuserdata(0); +T.testC("pushstring xuxu; gettable R; setmetatable 2", x) +assert(getmetatable(x) == mt_xuxu) + +-- testing luaL_testudata +-- correct metatable +local res1, res2, top = T.testC([[testudata -1 xuxu + testudata 2 xuxu + gettop + return 3]], x) +assert(res1 and res2 and top == 4) + +-- wrong metatable +res1, res2, top = T.testC([[testudata -1 xuxu1 + testudata 2 xuxu1 + gettop + return 3]], x) +assert(not res1 and not res2 and top == 4) + +-- non-existent type +res1, res2, top = T.testC([[testudata -1 xuxu2 + testudata 2 xuxu2 + gettop + return 3]], x) +assert(not res1 and not res2 and top == 4) + +-- userdata has no metatable +res1, res2, top = T.testC([[testudata -1 xuxu + testudata 2 xuxu + gettop + return 3]], y) +assert(not res1 and not res2 and top == 4) + +-- erase metatables +do + local r = debug.getregistry() + assert(r.xuxu == mt_xuxu and r.xuxu1 == d) + r.xuxu = nil; r.xuxu1 = nil +end + +print'OK' + diff --git a/lua-5.2.2-tests/attrib.lua b/lua-5.2.2-tests/attrib.lua new file mode 100644 index 0000000000..2fdc0673b3 --- /dev/null +++ b/lua-5.2.2-tests/attrib.lua @@ -0,0 +1,421 @@ +-- The tests for 'require' assume some specific directories and libraries; +-- better to avoid them in generic machines + +if not _port then --[ + +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"coroutine" == coroutine) + +assert(type(package.path) == "string") +assert(type(package.cpath) == "string") +assert(type(package.loaded) == "table") +assert(type(package.preload) == "table") + +assert(type(package.config) == "string") +print("package config: "..string.gsub(package.config, "\n", "|")) + +do + -- create a path with 'max' templates, + -- each with 1-10 repetitions of '?' + local max = 2000 + local t = {} + for i = 1,max do t[i] = string.rep("?", i%10 + 1) end + t[#t + 1] = ";" -- empty template + local path = table.concat(t, ";") + -- use that path in a search + local s, err = package.searchpath("xuxu", path) + -- search fails; check that message has an occurence of + -- '??????????' with ? replaced by xuxu and at least 'max' lines + assert(not s and + string.find(err, string.rep("xuxu", 10)) and + #string.gsub(err, "[^\n]", "") >= max) + -- path with one very long template + local path = string.rep("?", max) + local s, err = package.searchpath("xuxu", path) + assert(not s and string.find(err, string.rep('xuxu', max))) +end + +do + local oldpath = package.path + package.path = {} + local s, err = pcall(require, "no-such-file") + assert(not s and string.find(err, "package.path")) + package.path = oldpath +end + +print('+') + +-- auxiliary directory with C modules and temporary files +local DIR = "libs/" + +-- prepend DIR to a name +local function D (x) return DIR .. x end + + +local function createfiles (files, preextras, posextras) + for n,c in pairs(files) do + io.output(D(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(D(n)) + end +end + +local files = { + ["names.lua"] = "do return {...} end\n", + ["err.lua"] = "B = 15; a = a + 1;", + ["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) + +-- testing explicit "dir" separator in 'searchpath' +assert(package.searchpath("C.lua", D"?", "", "") == D"C.lua") +assert(package.searchpath("C.lua", D"?", ".", ".") == D"C.lua") +assert(package.searchpath("--x-", D"?", "-", "X") == D"XXxX") +assert(package.searchpath("---xX", D"?", "---", "XX") == D"XXxX") +assert(package.searchpath(D"C.lua", "?", "/") == D"C.lua") +assert(package.searchpath(".\\C.lua", D"?", "\\") == D"./C.lua") + +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 + +a = require"names" +assert(a[1] == "names" and a[2] == D"names.lua") + +_G.a = nil +assert(not pcall(require, "err")) +assert(B == 15) + +assert(package.searchpath("C", package.path) == D"C.lua") +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) +assert(require"C" == 25) +package.loaded.A = nil +try('B', nil, true) -- should not reload package +try('A', 'A.lua', true) +package.loaded.A = nil +os.remove(D'A.lua') +AA = {} +try('A', 'A.lc', AA) -- now must find second option +assert(package.searchpath("A", package.path) == D"A.lc") +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 + +local _G = _G + +package.path = string.gsub("D/?.lua;D/?/init.lua", "D/", DIR) + +files = { + ["P1/init.lua"] = "AA = 10", + ["P1/xuxu.lua"] = "AA = 20", +} + +createfiles(files, "_ENV = {}\n", "\nreturn _ENV\n") +AA = 0 + +local m = assert(require"P1") +assert(AA == 0 and m.AA == 10) +assert(require"P1" == m) +assert(require"P1" == m) + +assert(package.searchpath("P1.xuxu", package.path) == D"P1/xuxu.lua") +m.xuxu = assert(require"P1.xuxu") +assert(AA == 0 and m.xuxu.AA == 20) +assert(require"P1.xuxu" == m.xuxu) +assert(require"P1.xuxu" == m.xuxu) +assert(require"P1" == m and m.AA == 10) + + +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 + +-- cannot change environment of a C function +assert(not pcall(module, 'XUXU')) + + + +-- testing require of C libraries + + +local p = "" -- On Mac OS X, redefine this to "_" + +-- check whether loadlib works in this system +local st, err, when = package.loadlib(D"lib1.so", "*") +if not st then + local f, err, when = package.loadlib("donotexist", p.."xuxu") + assert(not f and type(err) == "string" and when == "absent") + ;(Message or print)('\a\n >>> cannot load dynamic library <<<\n\a') + print(err, when) +else + -- tests for loadlib + local f = assert(package.loadlib(D"lib1.so", p.."onefunction")) + local a, b = f(15, 25) + assert(a == 25 and b == 15) + + f = assert(package.loadlib(D"lib1.so", p.."anotherfunc")) + assert(f(10, 20) == "1020\n") + + -- check error messages + local f, err, when = package.loadlib(D"lib1.so", p.."xuxu") + assert(not f and type(err) == "string" and when == "init") + f, err, when = package.loadlib("donotexist", p.."xuxu") + assert(not f and type(err) == "string" and when == "open") + + -- symbols from 'lib1' must be visible to other libraries + f = assert(package.loadlib(D"lib11.so", p.."luaopen_lib11")) + assert(f() == "exported") + + -- test C modules with prefixes in names + package.cpath = D"?.so" + local lib2 = require"v-lib2" + -- check correct access to global environment and correct + -- parameters + assert(_ENV.x == "v-lib2" and _ENV.y == D"v-lib2.so") + assert(lib2.id("x") == "x") + + -- test C submodules + local fs = require"lib1.sub" + assert(_ENV.x == "lib1.sub" and _ENV.y == D"lib1.so") + assert(fs.id(45) == 45) +end + +_ENV = _G + + +-- testing preload + +do + local p = package + package = {} + p.preload.pl = function (...) + local _ENV = {...} + function xuxu (x) return x+20 end + return _ENV + end + + local pl = require"pl" + assert(require"pl" == pl) + assert(pl.xuxu(10) == 30) + assert(pl[1] == "pl" and pl[2] == nil) + + package = p + assert(type(package.path) == "string") +end + +print('+') + +end --] + +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 table.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(ab == 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) + +assert({} ~= {}) +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]) +assert(not pcall(function () local a = {}; a[nil] = 10 end)) +assert(not pcall(function () local a = {[nil] = 10} end)) +assert(a[nil] == nil) +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 + + +-- test conflicts in multiple assignment +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 + +-- repeat test with upvalues +do + local a,i,j,b + a = {'a', 'b'}; i=1; j=2; b=a + local function foo () + i, a[i], a, j, a[j], a[i+j] = j, i, i, b, j, i + end + foo() + assert(i == 2 and b[1] == 1 and a == 1 and j == b and b[2] == 2 and + b[3] == 1) + local t = {} + (function (a) t[a], a = 10, 20 end)(1); + assert(t[1] == 10) +end + +-- bug in 5.2 beta +local function foo () + local a + return function () + local b + a, b = 3, 14 -- local and upvalue have same index + return a, b + end +end + +local a, b = foo()() +assert(a == 3 and b == 14) + +print('OK') + +return res + diff --git a/lua-5.2.2-tests/big.lua b/lua-5.2.2-tests/big.lua new file mode 100644 index 0000000000..0c8ab2017c --- /dev/null +++ b/lua-5.2.2-tests/big.lua @@ -0,0 +1,79 @@ +if _soft then + return 'a' +end + +print "testing large tables" + +local debug = require"debug" + +local lim = 2^18 + 1000 +local prog = { "local y = {0" } +for i = 1, lim do prog[#prog + 1] = i end +prog[#prog + 1] = "}\n" +prog[#prog + 1] = "X = y\n" +prog[#prog + 1] = ("assert(X[%d] == %d)"):format(lim - 1, lim - 2) +prog[#prog + 1] = "return 0" +prog = table.concat(prog, ";") + +local env = {string = string, assert = assert} +local f = assert(load(prog, nil, nil, env)) + +f() +assert(env.X[lim] == lim - 1 and env.X[lim + 1] == lim) +for k in pairs(env) do env[k] = nil end + +-- yields during accesses larger than K (in RK) +setmetatable(env, { + __index = function (t, n) coroutine.yield('g'); return _G[n] end, + __newindex = function (t, n, v) coroutine.yield('s'); _G[n] = v end, +}) + +X = nil +co = coroutine.wrap(f) +assert(co() == 's') +assert(co() == 'g') +assert(co() == 'g') +assert(co() == 0) + +assert(X[lim] == lim - 1 and X[lim + 1] == lim) + +-- errors in accesses larger than K (in RK) +getmetatable(env).__index = function () end +getmetatable(env).__newindex = function () end +local e, m = pcall(f) +assert(not e and m:find("global 'X'")) + +-- errors in metamethods +getmetatable(env).__newindex = function () error("hi") end +local e, m = xpcall(f, debug.traceback) +assert(not e and m:find("'__newindex'")) + +f, X = nil + +coroutine.yield'b' + +if not _no32 then -- { + +print "testing string length overflow" + +local repstrings = 192 -- number of strings to be concatenated +local ssize = math.ceil(2^32 / repstrings) + 1 -- size of each string + +assert(repstrings * ssize > 2^32) -- this should be larger than maximum size_t + +local longs = string.rep("\0", ssize) -- create one long string + +-- create function to concatentate 'repstrings' copies of its argument +local rep = assert(load( + "local a = ...; return " .. string.rep("a", repstrings, ".."))) + +local a, b = pcall(rep, longs) -- call that function + +-- it should fail without creating string (result would be too large) +assert(not a and string.find(b, "overflow")) + +end -- } + +print'OK' + +return 'a' diff --git a/lua-5.2.2-tests/bitwise.lua b/lua-5.2.2-tests/bitwise.lua new file mode 100755 index 0000000000..afa158ddf8 --- /dev/null +++ b/lua-5.2.2-tests/bitwise.lua @@ -0,0 +1,115 @@ +print("testing bitwise operations") + +assert(bit32.band() == bit32.bnot(0)) +assert(bit32.btest() == true) +assert(bit32.bor() == 0) +assert(bit32.bxor() == 0) + +assert(bit32.band() == bit32.band(0xffffffff)) +assert(bit32.band(1,2) == 0) + + +-- out-of-range numbers +assert(bit32.band(-1) == 0xffffffff) +assert(bit32.band(2^33 - 1) == 0xffffffff) +assert(bit32.band(-2^33 - 1) == 0xffffffff) +assert(bit32.band(2^33 + 1) == 1) +assert(bit32.band(-2^33 + 1) == 1) +assert(bit32.band(-2^40) == 0) +assert(bit32.band(2^40) == 0) +assert(bit32.band(-2^40 - 2) == 0xfffffffe) +assert(bit32.band(2^40 - 4) == 0xfffffffc) + +assert(bit32.lrotate(0, -1) == 0) +assert(bit32.lrotate(0, 7) == 0) +assert(bit32.lrotate(0x12345678, 4) == 0x23456781) +assert(bit32.rrotate(0x12345678, -4) == 0x23456781) +assert(bit32.lrotate(0x12345678, -8) == 0x78123456) +assert(bit32.rrotate(0x12345678, 8) == 0x78123456) +assert(bit32.lrotate(0xaaaaaaaa, 2) == 0xaaaaaaaa) +assert(bit32.lrotate(0xaaaaaaaa, -2) == 0xaaaaaaaa) +for i = -50, 50 do + assert(bit32.lrotate(0x89abcdef, i) == bit32.lrotate(0x89abcdef, i%32)) +end + +assert(bit32.lshift(0x12345678, 4) == 0x23456780) +assert(bit32.lshift(0x12345678, 8) == 0x34567800) +assert(bit32.lshift(0x12345678, -4) == 0x01234567) +assert(bit32.lshift(0x12345678, -8) == 0x00123456) +assert(bit32.lshift(0x12345678, 32) == 0) +assert(bit32.lshift(0x12345678, -32) == 0) +assert(bit32.rshift(0x12345678, 4) == 0x01234567) +assert(bit32.rshift(0x12345678, 8) == 0x00123456) +assert(bit32.rshift(0x12345678, 32) == 0) +assert(bit32.rshift(0x12345678, -32) == 0) +assert(bit32.arshift(0x12345678, 0) == 0x12345678) +assert(bit32.arshift(0x12345678, 1) == 0x12345678 / 2) +assert(bit32.arshift(0x12345678, -1) == 0x12345678 * 2) +assert(bit32.arshift(-1, 1) == 0xffffffff) +assert(bit32.arshift(-1, 24) == 0xffffffff) +assert(bit32.arshift(-1, 32) == 0xffffffff) +assert(bit32.arshift(-1, -1) == (-1 * 2) % 2^32) + +print("+") +-- some special cases +local c = {0, 1, 2, 3, 10, 0x80000000, 0xaaaaaaaa, 0x55555555, + 0xffffffff, 0x7fffffff} + +for _, b in pairs(c) do + assert(bit32.band(b) == b) + assert(bit32.band(b, b) == b) + assert(bit32.btest(b, b) == (b ~= 0)) + assert(bit32.band(b, b, b) == b) + assert(bit32.btest(b, b, b) == (b ~= 0)) + assert(bit32.band(b, bit32.bnot(b)) == 0) + assert(bit32.bor(b, bit32.bnot(b)) == bit32.bnot(0)) + assert(bit32.bor(b) == b) + assert(bit32.bor(b, b) == b) + assert(bit32.bor(b, b, b) == b) + assert(bit32.bxor(b) == b) + assert(bit32.bxor(b, b) == 0) + assert(bit32.bxor(b, 0) == b) + assert(bit32.bnot(b) ~= b) + assert(bit32.bnot(bit32.bnot(b)) == b) + assert(bit32.bnot(b) == 2^32 - 1 - b) + assert(bit32.lrotate(b, 32) == b) + assert(bit32.rrotate(b, 32) == b) + assert(bit32.lshift(bit32.lshift(b, -4), 4) == bit32.band(b, bit32.bnot(0xf))) + assert(bit32.rshift(bit32.rshift(b, 4), -4) == bit32.band(b, bit32.bnot(0xf))) + for i = -40, 40 do + assert(bit32.lshift(b, i) == math.floor((b * 2^i) % 2^32)) + end +end + +assert(not pcall(bit32.band, {})) +assert(not pcall(bit32.bnot, "a")) +assert(not pcall(bit32.lshift, 45)) +assert(not pcall(bit32.lshift, 45, print)) +assert(not pcall(bit32.rshift, 45, print)) + +print("+") + + +-- testing extract/replace + +assert(bit32.extract(0x12345678, 0, 4) == 8) +assert(bit32.extract(0x12345678, 4, 4) == 7) +assert(bit32.extract(0xa0001111, 28, 4) == 0xa) +assert(bit32.extract(0xa0001111, 31, 1) == 1) +assert(bit32.extract(0x50000111, 31, 1) == 0) +assert(bit32.extract(0xf2345679, 0, 32) == 0xf2345679) + +assert(not pcall(bit32.extract, 0, -1)) +assert(not pcall(bit32.extract, 0, 32)) +assert(not pcall(bit32.extract, 0, 0, 33)) +assert(not pcall(bit32.extract, 0, 31, 2)) + +assert(bit32.replace(0x12345678, 5, 28, 4) == 0x52345678) +assert(bit32.replace(0x12345678, 0x87654321, 0, 32) == 0x87654321) +assert(bit32.replace(0, 1, 2) == 2^2) +assert(bit32.replace(0, -1, 4) == 2^4) +assert(bit32.replace(-1, 0, 31) == 2^31 - 1) +assert(bit32.replace(-1, 0, 1, 2) == 2^32 - 7) + + +print'OK' diff --git a/lua-5.2.2-tests/calls.lua b/lua-5.2.2-tests/calls.lua new file mode 100644 index 0000000000..77afa746be --- /dev/null +++ b/lua-5.2.2-tests/calls.lua @@ -0,0 +1,310 @@ +print("testing functions and calls") + +local debug = require "debug" + +-- 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*load("return fat(" .. x-1 .. ")")() + end +end + +assert(load "load 'assert(fat(6)==720)' () ")() +a = load('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) + + +-- testing closures + +-- fixed-point operator +Z = 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 = Z(F) + +assert(fat(0) == 1 and fat(4) == 24 and Z(F)(5)==5*Z(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) + +Z, F, f = nil +print('+') + +-- testing multiple returns + +function unlpack (t, i) + i = i or 1 + if (i <= #t) then + return t[i], unlpack(t, i+1) + end +end + +function equaltab (t1, t2) + assert(#t1 == #t2) + for i = 1, #t1 do + assert(t1[i] == t2[i]) + end +end + +local pack = function (...) return (table.pack(...)) 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" 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/lua-5.2.2-tests/closure.lua b/lua-5.2.2-tests/closure.lua new file mode 100644 index 0000000000..738002d2a7 --- /dev/null +++ b/lua-5.2.2-tests/closure.lua @@ -0,0 +1,244 @@ +print "testing closures" + +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 + +local 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 equality +a = {} +for i = 1, 5 do a[i] = function (x) return x + a + _ENV end end +assert(a[3] == a[4] and a[4] == a[5]) + +for i = 1, 5 do a[i] = function (x) return i + a + _ENV end end +assert(a[3] ~= a[4] and a[4] ~= a[5]) + +local function f() + return function (x) return math.sin(_ENV[x]) end +end +assert(f() == f()) + + +-- 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 = {} +local t = {"a", "b"} +for i = 1, #t do + local k = t[i] + 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 = 1, #t do + local v = t[k] + 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) + + +-- testing closures created in 'then' and 'else' parts of 'if's +a = {} +for i = 1, 10 do + if i % 3 == 0 then + local y = 0 + a[i] = function (x) local t = y; y = x; return t end + elseif i % 3 == 1 then + goto L1 + error'not here' + ::L1:: + local y = 1 + a[i] = function (x) local t = y; y = x; return t end + elseif i % 3 == 2 then + local t + goto l4 + ::l4a:: a[i] = t; goto l4b + error("should never be here!") + ::l4:: + local y = 2 + t = function (x) local t = y; y = x; return t end + goto l4a + error("should never be here!") + ::l4b:: + end +end + +for i = 1, 10 do + assert(a[i](i * 10) == i % 3 and a[i]() == i * 10) +end + +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() + + +-- test for debug manipulation of upvalues +local debug = require'debug' + +do + local a , b, c = 3, 5, 7 + foo1 = function () return a+b end; + foo2 = function () return b+a end; + do + local a = 10 + foo3 = function () return a+b end; + end +end + +assert(debug.upvalueid(foo1, 1)) +assert(debug.upvalueid(foo1, 2)) +assert(not pcall(debug.upvalueid, foo1, 3)) +assert(debug.upvalueid(foo1, 1) == debug.upvalueid(foo2, 2)) +assert(debug.upvalueid(foo1, 2) == debug.upvalueid(foo2, 1)) +assert(debug.upvalueid(foo3, 1)) +assert(debug.upvalueid(foo1, 1) ~= debug.upvalueid(foo3, 1)) +assert(debug.upvalueid(foo1, 2) == debug.upvalueid(foo3, 2)) + +assert(debug.upvalueid(string.gmatch("x", "x"), 1) ~= nil) + +assert(foo1() == 3 + 5 and foo2() == 5 + 3) +debug.upvaluejoin(foo1, 2, foo2, 2) +assert(foo1() == 3 + 3 and foo2() == 5 + 3) +assert(foo3() == 10 + 5) +debug.upvaluejoin(foo3, 2, foo2, 1) +assert(foo3() == 10 + 5) +debug.upvaluejoin(foo3, 2, foo2, 2) +assert(foo3() == 10 + 3) + +assert(not pcall(debug.upvaluejoin, foo1, 3, foo2, 1)) +assert(not pcall(debug.upvaluejoin, foo1, 1, foo2, 3)) +assert(not pcall(debug.upvaluejoin, foo1, 0, foo2, 1)) +assert(not pcall(debug.upvaluejoin, print, 1, foo2, 1)) +assert(not pcall(debug.upvaluejoin, {}, 1, foo2, 1)) +assert(not pcall(debug.upvaluejoin, foo1, 1, print, 1)) + +print'OK' diff --git a/lua-5.2.2-tests/code.lua b/lua-5.2.2-tests/code.lua new file mode 100644 index 0000000000..a0317c5524 --- /dev/null +++ b/lua-5.2.2-tests/code.lua @@ -0,0 +1,182 @@ +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 arg = {...} + local c = T.listcode(f) + for i=1, #arg do + -- print(arg[i], c[i]) + assert(string.find(c[i], '- '..arg[i]..' *%d')) + end + assert(c[#arg+2] == nil) +end + + +function checkequal (a, b) + a = T.listcode(a) + b = T.listcode(b) + for i = 1, #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', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN') + + +-- sequence of LOADNILs +check(function () + local a,b,c + local d; local e; + local f,g,h; + d = nil; d=nil; b=nil; a=nil; c=nil; +end, 'LOADNIL', 'RETURN') + +check(function () + local a,b,c,d = 1,1,1,1 + d=nil;c=nil;b=nil;a=nil +end, 'LOADK', 'LOADK', 'LOADK', 'LOADK', 'LOADNIL', 'RETURN') + +do + local a,b,c,d = 1,1,1,1 + d=nil;c=nil;b=nil;a=nil + assert(a == nil and b == nil and c == nil and d == nil) +end + + +-- 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 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, + 'LOADNIL', + '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, + 'LOADNIL', + 'SETTABLE', 'SETTABLE', 'SETTABLE', 'SUB', 'DIV', 'LOADK', + 'SETTABLE', 'RETURN') + +-- constant folding +local function f () return -((2^8 + -(-1)) % 8)/2 * 4 - 3 end + +check(f, 'LOADK', 'RETURN') +assert(f() == -5) + + +-- bug in constant folding for 5.1 +check(function () return -nil end, + 'LOADNIL', 'UNM', 'RETURN') + + +check(function () + local a,b,c + b[c], a = c, b + b[a], a = c, b + a, b = c, a + a = a +end, + 'LOADNIL', + '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, +'GETTABUP', 'EQ', 'JMP', 'SETTABUP', '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) + + +-- if-goto optimizations +check(function (a) + if a == 1 then goto l1 + elseif a == 2 then goto l2 + elseif a == 3 then goto l2 + else if a == 4 then goto l3 + else goto l3 + end + end + ::l1:: ::l2:: ::l3:: ::l4:: +end, 'EQ', 'JMP', 'EQ', 'JMP', 'EQ', 'JMP', 'EQ', 'JMP', 'JMP', 'RETURN') + +checkequal( +function (a) while a < 10 do a = a + 1 end end, +function (a) ::L2:: if not(a < 10) then goto L1 end; a = a + 1; + goto L2; ::L1:: end +) + +checkequal( +function (a) while a < 10 do a = a + 1 end end, +function (a) while true do if not(a < 10) then break end; a = a + 1; end end +) + +print 'OK' + diff --git a/lua-5.2.2-tests/constructs.lua b/lua-5.2.2-tests/constructs.lua new file mode 100644 index 0000000000..6dd77fe291 --- /dev/null +++ b/lua-5.2.2-tests/constructs.lua @@ -0,0 +1,310 @@ +;;print "testing syntax";; + +local debug = require "debug" + +-- testing semicollons +do ;;; end +; do ; a = 3; assert(a == 3) end; +; + + +-- 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) + +-- old bug +assert((((1 or false) and true) or false) == true) +assert((((nil and true) or false) and true) == false) + +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 = load(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.fmod(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(load(s))() + assert(X and not NX and not WX1 == K and not WX2 == K) + if math.fmod(i,4000) == 0 then print('+') end + i = i+1 +until i==c + +print '+' + +------------------------------------------------------------------ +print 'testing short-circuit optimizations' + +_ENV.GLOB1 = 1 +_ENV.GLOB2 = 2 + +local basiccases = { + {"nil", nil}, + {"false", false}, + {"true", true}, + {"10", 10}, + {"(_ENV.GLOB1 < _ENV.GLOB2)", true}, + {"(_ENV.GLOB2 < _ENV.GLOB1)", false}, +} + + +local binops = { + {" and ", function (a,b) if not a then return a else return b end end}, + {" or ", function (a,b) if a then return a else return b end end}, +} + +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 + for _, op in ipairs(binops) do + res[#res + 1] = { + "(" .. v1[1] .. op[1] .. v2[1] .. ")", + op[2](v1[2], v2[2]) + } + end + end + end + print('+') + end + mem[n] = res -- memoize + return res +end + +-- do not do too many combinations for soft tests +local level = _soft and 3 or 4 + +for _, v in pairs(allcases(level)) do + local res = load("return " .. v[1])() + assert(res == v[2]) +end +------------------------------------------------------------------ + +print'OK' diff --git a/lua-5.2.2-tests/coroutine.lua b/lua-5.2.2-tests/coroutine.lua new file mode 100644 index 0000000000..85086e5839 --- /dev/null +++ b/lua-5.2.2-tests/coroutine.lua @@ -0,0 +1,728 @@ +print "testing coroutines" + +local debug = require'debug' + +local f + +local main, ismain = coroutine.running() +assert(type(main) == "thread" and ismain) +assert(not coroutine.resume(main)) +assert(not pcall(coroutine.yield)) + + + +-- tests for multiple yield/resume arguments + +local function eqtab (t1, t2) + assert(#t1 == #t2) + for i = 1, #t1 do + local v = t1[i] + assert(t2[i] == v) + end +end + +_G.x = nil -- declare x +function foo (a, ...) + local x, y = coroutine.running() + assert(x == f and y == false) + assert(coroutine.status(f) == "running") + local arg = {...} + for i=1,#arg do + _G.x = {coroutine.yield(table.unpack(arg[i]))} + end + return table.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.fmod(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(#a == 25 and a[#a] == 97) + + +-- yielding across C boundaries + +co = coroutine.wrap(function() + assert(not pcall(table.sort,{1,2,3}, coroutine.yield)) + coroutine.yield(20) + return 30 + end) + +assert(co() == 20) +assert(co() == 30) + + +local f = function (s, i) return coroutine.yield(i) end + +local f1 = coroutine.wrap(function () + return xpcall(pcall, function (...) return ... end, + function () + local s = 0 + for i in f, nil, 1 do pcall(function () s = s + i end) end + error({s}) + end) + end) + +f1() +for i = 1, 10 do assert(f1(i) == i) end +local r1, r2, v = f1(nil) +assert(r1 and not r2 and v[1] == (10 + 1)*10/2) + + +function f (a, b) a = coroutine.yield(a); error{a + b} end +function g(x) return x[1]*2 end + +co = coroutine.wrap(function () + coroutine.yield(xpcall(f, g, 10, 20)) + end) + +assert(co() == 10) +r, msg = co(100) +assert(not r and msg == 240) + + +-- 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) + + +-- attempt to resume 'normal' coroutine +co1 = coroutine.create(function () return co2() end) +co2 = coroutine.wrap(function () + assert(coroutine.status(co1) == 'normal') + assert(not coroutine.resume(co1)) + coroutine.yield(3) + end) + +a,b = coroutine.resume(co1) +assert(a and b == 3) +assert(coroutine.status(co1) == 'dead') + +-- infinite recursion of coroutines +a = function(a) coroutine.wrap(a)(a) end +assert(not pcall(a, a)) + + +-- 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 + print "testing yields inside hooks" + + 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.sethook("yield 0", "", 2) + A = fact("A", 10) + end) + + local y = coroutine.create(function () + T.sethook("yield 0", "", 3) + B = fact("B", 11) + end) + + while A==0 or B==0 do + if A==0 then turn = "A"; assert(T.resume(x)) end + if B==0 then turn = "B"; assert(T.resume(y)) end + end + + assert(B/A == 11) + + local line = debug.getinfo(1, "l").currentline + 2 -- get line number + local function foo () + local x = 10 --<< this line is 'line' + x = x + 10 + _G.XX = x + end + + -- testing yields in line hook + local co = coroutine.wrap(function () + T.sethook("setglobal X; yield 0", "l", 0); foo(); return 10 end) + + _G.XX = nil; + _G.X = nil; co(); assert(_G.X == line) + _G.X = nil; co(); assert(_G.X == line + 1) + _G.X = nil; co(); assert(_G.X == line + 2 and _G.XX == nil) + _G.X = nil; co(); assert(_G.X == line + 3 and _G.XX == 20) + assert(co() == 10) + + -- testing yields in count hook + co = coroutine.wrap(function () + T.sethook("yield 0", "", 1); foo(); return 10 end) + + _G.XX = nil; + local c = 0 + repeat c = c + 1; local a = co() until a == 10 + assert(_G.XX == 20 and c == 10) + + co = coroutine.wrap(function () + T.sethook("yield 0", "", 2); foo(); return 10 end) + + _G.XX = nil; + local c = 0 + repeat c = c + 1; local a = co() until a == 10 + assert(_G.XX == 20 and c == 5) + _G.X = nil; _G.XX = nil + + + print "testing coroutine API" + + -- reusing a thread + assert(T.testC([[ + newthread # create thread + pushvalue 2 # push body + pushstring 'a a a' # push argument + xmove 0 3 2 # move values to new thread + resume -1, 1 # call it first time + pushstatus + xmove 3 0 0 # move results back to stack + setglobal X # result + setglobal Y # status + pushvalue 2 # push body (to call it again) + pushstring 'b b b' + xmove 0 3 2 + resume -1, 1 # call it again + pushstatus + xmove 3 0 0 + return 1 # return result + ]], function (...) return ... end) == 'b b b') + + assert(X == 'a a a' and Y == 'OK') + + + -- resuming running coroutine + C = coroutine.create(function () + return T.testC([[ + pushnum 10; + pushnum 20; + resume -3 2; + pushstatus + gettop; + return 3]], C) + end) + local a, b, c, d = coroutine.resume(C) + assert(a == true and string.find(b, "non%-suspended") and + c == "ERRRUN" and d == 4) + + a, b, c, d = T.testC([[ + rawgeti R 1 # get main thread + pushnum 10; + pushnum 20; + resume -3 2; + pushstatus + gettop; + return 4]]) + assert(a == coroutine.running() and string.find(b, "non%-suspended") and + c == "ERRRUN" and d == 4) + + + -- using a main thread as a coroutine + local state = T.newstate() + T.loadlib(state) + + assert(T.doremote(state, [[ + coroutine = require'coroutine'; + X = function (x) coroutine.yield(x, 'BB'); return 'CC' end; + return 'ok']])) + + t = table.pack(T.testC(state, [[ + rawgeti R 1 # get main thread + pushstring 'XX' + getglobal X # get function for body + pushstring AA # arg + resume 1 1 # 'resume' shadows previous stack! + gettop + setglobal T # top + setglobal B # second yielded value + setglobal A # fist yielded value + rawgeti R 1 # get main thread + pushnum 5 # arg (noise) + resume 1 1 # after coroutine ends, previous stack is back + pushstatus + gettop + return . + ]])) + assert(t.n == 4 and t[2] == 'XX' and t[3] == 'CC' and t[4] == 'OK') + assert(T.doremote(state, "return T") == '2') + assert(T.doremote(state, "return A") == 'AA') + assert(T.doremote(state, "return B") == 'BB') + + T.closestate(state) + + print'+' + +end + + +-- leaving a pending coroutine open +_X = coroutine.wrap(function () + local a = 10 + local x = function () a = a+1 end + coroutine.yield() + end) + +_X() + + +if not _soft then + -- bug (stack overflow) + local j = 2^9 + local lim = 1000000 -- (C stack limit; assume 32-bit machine) + local t = {lim - 10, lim - 5, lim - 1, lim, lim + 1} + for i = 1, #t do + local j = t[i] + co = coroutine.create(function() + local t = {} + for i = 1, j do t[i] = i end + return table.unpack(t) + end) + local r, msg = coroutine.resume(co) + assert(not r) + end +end + + +assert(coroutine.running() == main) + +print"+" + + +print"testing yields inside metamethods" + +local mt = { + __eq = function(a,b) coroutine.yield(nil, "eq"); return a.x == b.x end, + __lt = function(a,b) coroutine.yield(nil, "lt"); return a.x < b.x end, + __le = function(a,b) coroutine.yield(nil, "le"); return a - b <= 0 end, + __add = function(a,b) coroutine.yield(nil, "add"); return a.x + b.x end, + __sub = function(a,b) coroutine.yield(nil, "sub"); return a.x - b.x end, + __concat = function(a,b) + coroutine.yield(nil, "concat"); + a = type(a) == "table" and a.x or a + b = type(b) == "table" and b.x or b + return a .. b + end, + __index = function (t,k) coroutine.yield(nil, "idx"); return t.k[k] end, + __newindex = function (t,k,v) coroutine.yield(nil, "nidx"); t.k[k] = v end, +} + + +local function new (x) + return setmetatable({x = x, k = {}}, mt) +end + + +local a = new(10) +local b = new(12) +local c = new"hello" + +local function run (f, t) + local i = 1 + local c = coroutine.wrap(f) + while true do + local res, stat = c() + if res then assert(t[i] == nil); return res, t end + assert(stat == t[i]) + i = i + 1 + end +end + + +assert(run(function () if (a>=b) then return '>=' else return '<' end end, + {"le", "sub"}) == "<") +-- '<=' using '<' +mt.__le = nil +assert(run(function () if (a<=b) then return '<=' else return '>' end end, + {"lt"}) == "<=") +assert(run(function () if (a==b) then return '==' else return '~=' end end, + {"eq"}) == "~=") + +assert(run(function () return a..b end, {"concat"}) == "1012") + +assert(run(function() return a .. b .. c .. a end, + {"concat", "concat", "concat"}) == "1012hello10") + +assert(run(function() return "a" .. "b" .. a .. "c" .. c .. b .. "x" end, + {"concat", "concat", "concat"}) == "ab10chello12x") + +assert(run(function () + a.BB = print + return a.BB + end, {"nidx", "idx"}) == print) + +-- getuptable & setuptable +do local _ENV = _ENV + f = function () AAA = BBB + 1; return AAA end +end +g = new(10); g.k.BBB = 10; +debug.setupvalue(f, 1, g) +assert(run(f, {"idx", "nidx", "idx"}) == 11) +assert(g.k.AAA == 11) + +print"+" + +print"testing yields inside 'for' iterators" + +local f = function (s, i) + if i%2 == 0 then coroutine.yield(nil, "for") end + if i < s then return i + 1 end + end + +assert(run(function () + local s = 0 + for i in f, 4, 0 do s = s + i end + return s + end, {"for", "for", "for"}) == 10) + + + +-- tests for coroutine API +if T==nil then + (Message or print)('\a\n >>> testC not active: skipping coroutine API tests <<<\n\a') + return +end + +print('testing coroutine API') + +local function apico (...) + local x = {...} + return coroutine.wrap(function () + return T.testC(table.unpack(x)) + end) +end + +local a = {apico( +[[ + pushstring errorcode + pcallk 1 0 2; + invalid command (should not arrive here) +]], +[[getctx; gettop; return .]], +"stackmark", +error +)()} +assert(#a == 6 and + a[3] == "stackmark" and + a[4] == "errorcode" and + a[5] == "ERRRUN" and + a[6] == 2) -- 'ctx' to pcallk + +local co = apico( + "pushvalue 2; pushnum 10; pcallk 1 2 3; invalid command;", + coroutine.yield, + "getctx; pushvalue 2; pushstring a; pcallk 1 0 4; invalid command", + "getctx; gettop; return .") + +assert(co() == 10) +assert(co(20, 30) == 'a') +a = {co()} +assert(#a == 10 and + a[2] == coroutine.yield and + a[5] == 20 and a[6] == 30 and + a[7] == "YIELD" and a[8] == 3 and + a[9] == "YIELD" and a[10] == 4) +assert(not pcall(co)) -- coroutine is dead now + + +f = T.makeCfunc("pushnum 3; pushnum 5; yield 1;") +co = coroutine.wrap(function () + assert(f() == 23); assert(f() == 23); return 10 +end) +assert(co(23,16) == 5) +assert(co(23,16) == 5) +assert(co(23,16) == 10) + + +-- testing coroutines with C bodies +f = T.makeCfunc([[ + pushnum 102 + yieldk 1 U2 + return 2 +]], +[[ + pushnum 23 # continuation + gettop + return . +]]) + +x = coroutine.wrap(f) +assert(x() == 102) +assert(x() == 23) + + +f = T.makeCfunc[[pushstring 'a'; pushnum 102; yield 2; ]] + +a, b, c, d = T.testC([[newthread; pushvalue 2; xmove 0 3 1; resume 3 0; + pushstatus; xmove 3 0 0; resume 3 0; pushstatus; + return 4; ]], f) + +assert(a == 'YIELD' and b == 'a' and c == 102 and d == 'OK') + + +-- testing chain of suspendable C calls + +local count = 3 -- number of levels + +f = T.makeCfunc([[ + remove 1; # remove argument + pushvalue U3; # get selection function + call 0 1; # call it (result is 'f' or 'yield') + pushstring hello # single argument for selected function + pushupvalueindex 2; # index of continuation program + callk 1 -1 .; # call selected function + errorerror # should never arrive here +]], +[[ + # continuation program + pushnum 34 # return value + gettop + return . # return all results +]], +function () -- selection function + count = count - 1 + if count == 0 then return coroutine.yield + else return f + end +end +) + +co = coroutine.wrap(function () return f(nil) end) +assert(co() == "hello") -- argument to 'yield' +a = {co()} +-- three '34's (one from each pending C call) +assert(#a == 3 and a[1] == a[2] and a[2] == a[3] and a[3] == 34) + + +-- testing yields with continuations + +co = coroutine.wrap(function (...) return + T.testC([[ + getctx + yieldk 3 2 + nonexec error + ]], + [[ # continuation + getctx + yieldk 2 3 + ]], + [[ # continuation + getctx + yieldk 2 4 + ]], + [[ # continuation + pushvalue 6; pushnum 10; pushnum 20; + pcall 2 0 # call should throw an error and execution continues + pop 1 # remove error message + pushvalue 6 + getctx + pcallk 2 2 5 # call should throw an error and jump to continuation + cannot be here! + ]], + [[ # continuation + gettop + return . + ]], + function (a,b) x=a; y=b; error("errmsg") end, + ... +) +end) + +local a = {co(3,4,6)}; assert(a[1] == 6 and a[2] == "OK" and a[3] == 0) +a = {co()}; assert(a[1] == "YIELD" and a[2] == 2) +a = {co()}; assert(a[1] == "YIELD" and a[2] == 3) +a = {co(7,8)}; +-- original arguments +assert(type(a[1]) == 'string' and type(a[2]) == 'string' and + type(a[3]) == 'string' and type(a[4]) == 'string' and + type(a[5]) == 'string' and type(a[6]) == 'function') +-- arguments left from fist resume +assert(a[7] == 3 and a[8] == 4) +-- arguments to last resume +assert(a[9] == 7 and a[10] == 8) +-- error message and nothing more +assert(a[11]:find("errmsg") and #a == 11) +-- check arguments to pcallk +assert(x == "YIELD" and y == 4) + +assert(not pcall(co)) -- coroutine should be dead + +-- testing ctx + +a,b = T.testC( + [[ pushstring print; pcallk 0 0 12 # error + getctx; return 2 ]]) +assert(a == "OK" and b == 0) -- no ctx outside continuations + + +-- bug in nCcalls +local co = coroutine.wrap(function () + local a = {pcall(pcall,pcall,pcall,pcall,pcall,pcall,pcall,error,"hi")} + return pcall(assert, table.unpack(a)) +end) + +local a = {co()} +assert(a[10] == "hi") + + +print'OK' diff --git a/lua-5.2.2-tests/db.lua b/lua-5.2.2-tests/db.lua new file mode 100644 index 0000000000..d3d8c25bb0 --- /dev/null +++ b/lua-5.2.2-tests/db.lua @@ -0,0 +1,631 @@ +-- testing debug library + +debug = require "debug" + +local function dostring(s) return assert(load(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"); load(s)(); debug.sethook() + assert(#l == 0) +end + + +do + assert(not pcall(debug.getinfo, print, "X")) -- invalid option + assert(debug.getinfo(1000) == nil) -- out of range level + assert(debug.getinfo(-1) == nil) -- out of range level + local a = debug.getinfo(print) + assert(a.what == "C" and a.short_src == "[C]") + a = debug.getinfo(print, "L") + assert(a.activelines == nil) + local b = debug.getinfo(test, "SfL") + assert(b.name == nil and b.what == "Lua" and b.linedefined == 13 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 load(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(a..string.format("; %s=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,3,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 +]], {1,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,3,6}) + +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'+' + +-- invalid levels in [gs]etlocal +assert(not pcall(debug.getlocal, 20, 1)) +assert(not pcall(debug.setlocal, -1, 1, 10)) + + +-- parameter names +local function foo (a,b,...) local d, e end +local co = coroutine.create(foo) + +assert(debug.getlocal(foo, 1) == 'a') +assert(debug.getlocal(foo, 2) == 'b') +assert(debug.getlocal(foo, 3) == nil) +assert(debug.getlocal(co, foo, 1) == 'a') +assert(debug.getlocal(co, foo, 2) == 'b') +assert(debug.getlocal(co, foo, 3) == nil) + +assert(debug.getlocal(print, 1) == nil) + + +-- varargs +local function foo (a, ...) + local t = table.pack(...) + for i = 1, t.n do + local n, v = debug.getlocal(1, -i) + assert(n == "(*vararg)" and v == t[i]) + end + assert(not debug.getlocal(1, -(t.n + 1))) + assert(not debug.setlocal(1, -(t.n + 1), 30)) + if t.n > 0 then + (function (x) + assert(debug.setlocal(2, -1, x) == "(*vararg)") + assert(debug.setlocal(2, -t.n, x) == "(*vararg)") + end)(430) + assert(... == 430) + end +end + +foo() +foo(print) +foo(200, 3, 4) +local a = {} +for i = 1,1000 do a[i] = i end +foo(table.unpack(a)) +a = nil + +-- access to vararg in non-vararg function +local function foo () return debug.getlocal(1, -1) end +assert(foo(10) == nil) + + +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 == 1 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(...) + local arg = {...} + 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 arg = {...}; 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(load("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.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") +-- upvalues of C functions are allways "called" "" (the empty string) +assert(debug.getupvalue(string.gmatch("x", "x"), 1) == "") + + +-- 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) + +if not _no32 then + debug.sethook(print, "", 2^24 - 1) -- count upperbound + local f,m,c = debug.gethook() + assert(({debug.gethook()})[3] == 2^24 - 1) +end + +debug.sethook() + + +-- tests for tail calls +local function f (x) + if x then + assert(debug.getinfo(1, "S").what == "Lua") + assert(debug.getinfo(1, "t").istailcall == true) + local tail = debug.getinfo(2) + assert(tail.func == g1 and tail.istailcall == true) + assert(debug.getinfo(3, "S").what == "main") + 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", "tail call", "call", "tail call", + "return", "return", + "call", -- last call (to sethook) +} +for i = 1, #res do assert(res[i] == table.remove(b, 1)) end + +b = 0 +debug.sethook(function (e) + if e == "tail call" then + b = b + 1 + assert(debug.getinfo(2, "t").istailcall == true) + else + assert(debug.getinfo(2, "t").istailcall == false) + end + end, "c") +h(false) +debug.sethook() +assert(b == 2) -- two tail calls + +lim = 30000 +if _soft then limit = 3000 end +local function foo (x) + if x==0 then + assert(debug.getinfo(2).what == "main") + local info = debug.getinfo(1) + assert(info.istailcall == true and info.func == foo) + else return foo(x-1) + end +end + +foo(lim) + + +print"+" + + +-- testing local function information +co = load[[ + local A = function () + return x + end + return +]] + +local a = 0 +-- 'A' should be visible to debugger only after its complete definition +debug.sethook(function (e, l) + if l == 3 then a = a + 1; assert(debug.getlocal(2, 1) == "(*temporary)") + elseif l == 4 then a = a + 1; assert(debug.getlocal(2, 1) == "A") + end +end, "l") +co() -- run local function definition +debug.sethook() -- turn off hook +assert(a == 2) -- ensure all two lines where hooked + +-- 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 nparams, nups e isvararg +local t = debug.getinfo(print, "u") +assert(t.isvararg == true and t.nparams == 0 and t.nups == 0) + +t = debug.getinfo(function (a,b,c) end, "u") +assert(t.isvararg == false and t.nparams == 3 and t.nups == 0) + +t = debug.getinfo(function (a,b,...) return t[a] end, "u") +assert(t.isvararg == true and t.nparams == 2 and t.nups == 1) + +t = debug.getinfo(1) -- main +assert(t.isvararg == true and t.nparams == 0 and t.nups == 1 and + debug.getupvalue(t.func, 1) == "_ENV") + + +-- testing debugging of coroutines + +local function checktraceback (co, p, level) + local tb = debug.traceback(co, nil, level) + 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 f(n-1) + else coroutine.yield() end +end + +local co = coroutine.create(f) +coroutine.resume(co, 3) +checktraceback(co, {"yield", "db.lua", "db.lua", "db.lua", "db.lua"}) +checktraceback(co, {"db.lua", "db.lua", "db.lua", "db.lua"}, 1) +checktraceback(co, {"db.lua", "db.lua", "db.lua"}, 2) +checktraceback(co, {"db.lua"}, 4) +checktraceback(co, {}, 40) + + +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) if l then table.insert(tr, l) end end +debug.sethook(co, foo, "lcr") + +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(#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(#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") + + +-- test tagmethod information +local a = {} +local function f (t) + local info = debug.getinfo(1); + assert(info.namewhat == "metamethod") + a.op = info.name + return info.name +end +setmetatable(a, { + __index = f; __add = f; __div = f; __mod = f; __concat = f; __pow = f; + __eq = f; __le = f; __lt = f; +}) + +local b = setmetatable({}, getmetatable(a)) + +assert(a[3] == "__index" and a^3 == "__pow" and a..a == "__concat") +assert(a/3 == "__div" and 3%a == "__mod") +assert (a==b and a.op == "__eq") +assert (a>=b and a.op == "__le") +assert (a>b and a.op == "__lt") + + +print"OK" + diff --git a/lua-5.2.2-tests/errors.lua b/lua-5.2.2-tests/errors.lua new file mode 100644 index 0000000000..6d91bdc0bd --- /dev/null +++ b/lua-5.2.2-tests/errors.lua @@ -0,0 +1,422 @@ +print("testing errors") + +local debug = require"debug" + +-- avoid problems with 'strict' module (which may generate other error messages) +local mt = getmetatable(_G) or {} +local oldmm = mt.__index +mt.__index = nil + +function doit (s) + local f, msg = load(s) + if f == nil then return msg end + local cond, msg = pcall(f) + return (not cond) and msg +end + + +function checkmessage (prog, msg) + local m = doit(prog) + assert(string.find(m, msg, 1, true)) +end + +function checksyntax (prog, extra, token, line) + local msg = doit(prog) + if not string.find(token, "^<%a") and not string.find(token, "^char%(") + then token = "'"..token.."'" end + 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 +if not _no32 then + assert(doit("table.unpack({}, 1, n=2^30)")) +end +assert(doit("a=math.sin()")) +assert(not doit("tostring(1)") and doit("tostring()")) +assert(doit"tonumber()") +assert(doit"repeat until 1; a") +assert(doit"return;;") +assert(doit"assert(false)") +assert(doit"assert(nil)") +assert(doit("function a (... , ...) end")) +assert(doit("function a (, ...) end")) +assert(doit("local t={}; t = t[#t] + 1")) + +checksyntax([[ + local a = {4 + +]], "'}' expected (to close '{' at line 1)", "", 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") +checkmessage("a=(1)..{}", "a table value") + +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("local _ENV = {x={}}; a = a + 1", "global 'a'") + +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("print(print < 10)", "function") +checkmessage("print(print < print)", "two function") + + +-- passing light userdata instead of full userdata +_G.D = debug +checkmessage([[ + -- create light udata + local x = D.upvalueid(function () return debug end, 1) + D.setuservalue(x, {}) +]], "light userdata") +_G.D = nil + + +-- global functions +checkmessage("(io.write or print){}", "io.write") +checkmessage("(collectgarbage or print){}", "collectgarbage") + +-- tests for field accesses after RK limit +local t = {} +for i = 1, 1000 do + t[i] = "a = x" .. i +end +local s = table.concat(t, "; ") +t = nil +checkmessage(s.."; a = bbb + 1", "global 'bbb'") +checkmessage("local _ENV=_ENV;"..s.."; a = bbb + 1", "global 'bbb'") +checkmessage(s.."; local t = {}; a = t.bbb + 1", "field 'bbb'") +checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'") + +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") + +checkmessage([[ +local Var +local function main() + NoSuchName (function() Var=0 end) +end +main() +]], "global 'NoSuchName'") +print'+' + +a = {}; setmetatable(a, {__index = string}) +checkmessage("a:sub()", "bad self") +checkmessage("string.sub('a', {})", "#2") +checkmessage("('a'):sub{}", "#1") + +checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'") +-- next message may be 'setmetatable' or '_G.setmetatable' +checkmessage("string.gsub('s', 's', setmetatable)", "setmetatable'") + +-- tests for errors in coroutines + +function f (n) + local c = coroutine.create(f) + local a,b = coroutine.resume(c) + return b +end +assert(string.find(f(), "C stack overflow")) + +checkmessage("coroutine.yield()", "outside a coroutine") + +f1 = function () table.sort({1,2,3}, coroutine.yield) end +f = coroutine.wrap(function () return pcall(f1) end) +assert(string.find(select(2, f()), "yield across")) + + +-- testing size of 'source' info; size of buffer for that info is +-- LUA_IDSIZE, declared as 60 in luaconf. Get one position for '\0'. +idsize = 60 - 1 +local function checksize (source) + -- syntax error + local _, msg = load("x", source) + msg = string.match(msg, "^([^:]*):") -- get source (1st part before ':') + assert(msg:len() <= idsize) +end + +for i = 60 - 10, 60 + 10 do -- check border cases around 60 + checksize("@" .. string.rep("x", i)) -- file names + checksize(string.rep("x", i - 10)) -- string sources + checksize("=" .. string.rep("x", i)) -- exact sources +end + + +-- testing line error + +local function lineerror (s, l) + local err,msg = pcall(load(s)) + local line = string.match(msg, ":(%d+):") + assert((line and line+0) == l) +end + +lineerror("local a\n for i=1,'a' do \n print(i) \n end", 2) +lineerror("\n local a \n for k,v in 3 \n do \n print(k) \n end", 3) +lineerror("\n\n for k,v in \n 3 \n do \n print(k) \n end", 4) +lineerror("function a.x.y ()\na=a+1\nend", 1) + +lineerror("a = \na\n+\n{}", 3) +lineerror("a = \n3\n+\n(\n4\n/\nprint)", 6) +lineerror("a = \nprint\n+\n(\n4\n/\n7)", 3) + +lineerror("a\n=\n-\n\nprint\n;", 3) + +lineerror([[ +a +( +23) +]], 1) + +lineerror([[ +local a = {x = 13} +a +. +x +( +23 +) +]], 2) + +lineerror([[ +local a = {x = 13} +a +. +x +( +23 + a +) +]], 6) + +local p = [[ +function g() f() end +function f(x) error('a', X) end +g() +]] +X=3;lineerror((p), 3) +X=0;lineerror((p), nil) +X=1;lineerror((p), 2) +X=2;lineerror((p), 1) + + +if not _soft then + -- several tests that exaust the Lua stack + 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 + -- repeated stack overflows (to check stack recovery) + assert(checkstackmessage(doit('y()'))) + print('+') + assert(checkstackmessage(doit('y()'))) + print('+') + assert(checkstackmessage(doit('y()'))) + print('+') + + + -- error lines in stack overflow + C = 0 + local l1 + local function g(x) + l1 = debug.getinfo(x, "l").currentline; y() + end + local _, stackmsg = xpcall(g, debug.traceback, 1) + print('+') + 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') + print('+') + + 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) + + local function loop (x,y,z) return 1 + loop(x, y, z) end + + local res, msg = xpcall(loop, function (m) + assert(string.find(m, "stack overflow")) + local res, msg = pcall(loop) + assert(string.find(msg, "error handling")) + assert(math.sin(0) == 0) + return 15 + end) + assert(msg == 15) + + res, msg = pcall(function () + for i = 999900, 1000000, 1 do table.unpack({}, 1, i) end + end) + assert(string.find(msg, "too many results")) + +end + + +-- 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') + +-- xpcall with arguments +a, b, c = xpcall(string.find, error, "alo", "al") +assert(a and b == 1 and c == 2) +a, b, c = xpcall(string.find, function (x) return {} end, true, "al") +assert(not a and type(b) == "table" and c == nil) + +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", "", "char(255)", 1) + +doit('I = load("a=9+"); a=3') +assert(a==3 and I == nil) +print('+') + +lim = 1000 +if _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 = load(s) + assert(not a and string.find(b, "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^") + +local s = ("a,"):rep(200).."a=nil" +local a,b = load(s) +assert(not a and string.find(b, "levels")) + + +-- testing other limits +-- upvalues +local lim = 127 +local s = "local function fooA ()\n local " +for j = 1,lim do + s = s.."a"..j..", " +end +s = s.."b,c\n" +s = s.."local function fooB ()\n local " +for j = 1,lim do + s = s.."b"..j..", " +end +s = s.."b\n" +s = s.."function fooC () return b+c" +local c = 1+2 +for j = 1,lim do + s = s.."+a"..j.."+b"..j + c = c + 2 +end +s = s.."\nend end end" +local a,b = load(s) +assert(c > 255 and string.find(b, "too many upvalues") and + string.find(b, "line 5")) + +-- local variables +s = "\nfunction foo ()\n local " +for j = 1,300 do + s = s.."a"..j..", " +end +s = s.."b\n" +local a,b = load(s) +assert(string.find(b, "line 2")) + +mt.__index = oldmm + +print('OK') diff --git a/lua-5.2.2-tests/events.lua b/lua-5.2.2-tests/events.lua new file mode 100644 index 0000000000..b3e5c4124a --- /dev/null +++ b/lua-5.2.2-tests/events.lua @@ -0,0 +1,388 @@ +print('testing metatables') + +X = 20; B = 30 + +_ENV = 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 +setmetatable(t, t) -- causes a bug in 5.1 ! +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 + + +setmetatable(t, nil) +function f (t, ...) return t, {...} end +t.__call = f + +do + local x,y = a(table.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") +t.__len = f("len") + +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) +assert(#a == a) +assert(cap[0] == "len" and cap[1] == a) + + +-- test for rawlen +t = setmetatable({1,2,3}, {__len = function () return 10 end}) +assert(#t == 10 and rawlen(t) == 3) +assert(rawlen"abc" == 3) +assert(not pcall(rawlen, io.stdin)) +assert(not pcall(rawlen, 34)) +assert(not pcall(rawlen)) + +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 aOp(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((1 >= Op(1)) and not(1 >= Op(2)) and (Op(2) >= 1)) + assert((Op('a')>=Op('a')) and not(Op('a')>=Op('b')) and (Op('b')>=Op('a'))) + assert(('a' >= Op('a')) and not(Op('a') >= '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 +assert((c..d..c..d).val == 'cdcd') +x = c..d +assert(getmetatable(x) == t and x.val == 'cd') +x = 0 .."a".."b"..c..d.."e".."f".."g" +assert(x.val == "0abcdefg") + + +-- concat metamethod x numbers (bug in 5.1.1) +c = {} +local x +setmetatable(c, {__concat = function (a,b) + assert(type(a) == "number" and b == c or type(b) == "number" and a == c) + return c +end}) +assert(c..5 == c and 5 .. c == c) +assert(4 .. c .. 5 == c and 4 .. 5 .. 6 .. 7 .. c == c) + + +-- 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 +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) + +print'+' + +local _g = _G +_ENV = setmetatable({}, {__index=function (_,k) return _g[k] end}) + + +a = {} +rawset(a, "x", 1, 2, 3) +assert(a.x == 1 and rawget(a, "x", 3) == 1) + +print '+' + +-- testing metatables for basic types +local debug = require'debug' +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, {}) + + +-- loops in delegation +a = {}; setmetatable(a, a); a.__index = a; a.__newindex = a +assert(not pcall(function (a,b) return a[b] end, a, 10)) +assert(not pcall(function (a,b,c) a[b] = c end, a, 10, true)) + +-- bug in 5.1 +T, K, V = nil +grandparent = {} +grandparent.__newindex = function(t,k,v) T=t; K=k; V=v end + +parent = {} +parent.__newindex = parent +setmetatable(parent, grandparent) + +child = setmetatable({}, parent) +child.foo = 10 --> CRASH (on some machines) +assert(T == parent and K == "foo" and V == 10) + +print 'OK' + +return 12 + + diff --git a/lua-5.2.2-tests/files.lua b/lua-5.2.2-tests/files.lua new file mode 100644 index 0000000000..db7e24550f --- /dev/null +++ b/lua-5.2.2-tests/files.lua @@ -0,0 +1,615 @@ +debug = require "debug" + +assert(type(os.getenv"PATH") == "string") + +assert(io.input(io.stdin) == io.stdin) +assert(not pcall(io.input, "non-existent-file")) +assert(io.output(io.stdout) == io.stdout) + +-- cannot close standard files +assert(not io.close(io.stdin) and + not io.stdout:close() and + not io.stderr:close()) + + +assert(type(io.input()) == "userdata" and io.type(io.output()) == "file") +assert(type(io.stdin) == "userdata" and io.type(io.stderr) == "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 f, msg = io.open(file, "w") +if not f then + (Message or print)("'os.tmpname' file cannot be open; skipping file tests") + +else --{ most tests here need tmpname +f:close() + +print('testing i/o') + +local otherfile = os.tmpname() + +assert(not pcall(io.open, file, "rw")) -- invalid mode +assert(not pcall(io.open, file, "rb+")) -- invalid mode +assert(not pcall(io.open, file, "r+bk")) -- invalid mode +assert(not pcall(io.open, file, "")) -- invalid mode +assert(not pcall(io.open, file, "+")) -- invalid mode +assert(not pcall(io.open, file, "b")) -- invalid mode +assert(io.open(file, "r+b")):close() +assert(io.open(file, "r+")):close() +assert(io.open(file, "rb")):close() + +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"):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 + +io.input():close() +io.close() + +assert(os.rename(file, otherfile)) +assert(os.rename(file, otherfile) == nil) + +io.output(io.open(otherfile, "ab")) +assert(io.write("\n\n\t\t 3450\n")); +io.close() + +-- test line generators +assert(not pcall(io.lines, "non-existent-file")) +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(tostring(f):sub(1, 5) == "file ") +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 +f = nil; collectgarbage() +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 \n") +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(30000) == 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"):write("\n") +io.close() +assert(not pcall(io.write)) +local f = io.open(file, "a+b") +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())) + + +-- test errors in read/write +do + local function ismsg (m) + -- error message is not a code number + return (type(m) == "string" and tonumber(m) == nil) + end + + -- read + local f = io.open(file, "w") + local r, m, c = f:read() + assert(r == nil and ismsg(m) and type(c) == "number") + assert(f:close()) + -- write + f = io.open(file, "r") + r, m, c = f:write("whatever") + assert(r == nil and ismsg(m) and type(c) == "number") + assert(f:close()) + -- lines + f = io.open(file, "w") + r, m = pcall(f:lines()) + assert(r == false and ismsg(m)) + assert(f:close()) +end + +assert(os.remove(file)) + +-- test for *L format +io.output(file); io.write"\n\nline\nother":close() +io.input(file) +assert(io.read"*L" == "\n") +assert(io.read"*L" == "\n") +assert(io.read"*L" == "line\n") +assert(io.read"*L" == "other") +assert(io.read"*L" == nil) +io.input():close() + +local f = assert(io.open(file)) +local s = "" +for l in f:lines("*L") do s = s .. l end +assert(s == "\n\nline\nother") +f:close() + +io.input(file) +s = "" +for l in io.lines(nil, "*L") do s = s .. l end +assert(s == "\n\nline\nother") +io.input():close() + +s = "" +for l in io.lines(file, "*L") do s = s .. l end +assert(s == "\n\nline\nother") + +s = "" +for l in io.lines(file, "*l") do s = s .. l end +assert(s == "lineother") + +io.output(file); io.write"a = 10 + 34\na = 2*a\na = -a\n":close() +local t = {} +load(io.lines(file, "*L"), nil, nil, t)() +assert(t.a == -((10 + 34) * 2)) + + +-- test for multipe arguments in 'lines' +io.output(file); io.write"0123456789\n":close() +for a,b in io.lines(file, 1, 1) do + if a == "\n" then assert(b == nil) + else assert(tonumber(a) == b - 1) + end +end + +for a,b,c in io.lines(file, 1, 2, "*a") do + assert(a == "0" and b == "12" and c == "3456789\n") +end + +for a,b,c in io.lines(file, "*a", 0, 1) do + if a == "" then break end + assert(a == "0123456789\n" and b == nil and c == nil) +end +collectgarbage() -- to close file in previous iteration + +io.output(file); io.write"00\n10\n20\n30\n40\n":close() +for a, b in io.lines(file, "*n", "*n") do + if a == 40 then assert(b == nil) + else assert(a == b - 10) + end +end + + +-- test load x lines +io.output(file); +io.write[[ +local y += X +X = +X * +2 + +X; +X = +X +- y; +]]:close() +_G.X = 1 +assert(not load(io.lines(file))) +collectgarbage() -- to close file in previous iteration +load(io.lines(file, "*L"))() +assert(_G.X == 2) +load(io.lines(file, 1))() +assert(_G.X == 4) +load(io.lines(file, 3))() +assert(_G.X == 8) + +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) + +-- testing loadfile +local function testloadfile (s, expres) + io.output(file) + if s then io.write(s) end + io.close() + local res = assert(loadfile(file))() + assert(os.remove(file)) + assert(res == expres) +end + +-- loading empty file +testloadfile(nil, nil) + +-- loading file with initial comment without end of line +testloadfile("# a non-ending comment", nil) + + +-- checking Unicode BOM in files +testloadfile("\xEF\xBB\xBF# some comment\nreturn 234", 234) +testloadfile("\xEF\xBB\xBFreturn 239", 239) +testloadfile("\xEF\xBB\xBF", nil) -- empty file with a BOM + + +-- checking line numbers in files with initial comments +testloadfile("# a comment\nreturn debug.getinfo(1).currentline", 2) + + +-- loading binary file +io.output(io.open(file, "wb")) +assert(io.write(string.dump(function () return 10, '\0alo\255', 'hi' end))) +io.close() +a, b, c = assert(loadfile(file))() +assert(a == 10 and b == "\0alo\255" and c == "hi") +assert(os.remove(file)) + +-- bug in 5.2.1 +do + io.output(io.open(file, "wb")) + -- save function with no upvalues + assert(io.write(string.dump(function () return 1 end))) + io.close() + f = assert(loadfile(file, "b", {})) + assert(type(f) == "function" and f() == 1) + assert(os.remove(file)) +end + +-- loading binary file with initial comment +io.output(io.open(file, "wb")) +assert(io.write("#this is a comment for a binary file\0\n", + string.dump(function () return 20, '\0\0\0' end))) +io.close() +a, b, c = assert(loadfile(file))() +assert(a == 20 and b == "\0\0\0" and c == nil) +assert(os.remove(file)) + + +-- 'loadfile' with 'env' +do + local f = io.open(file, 'w') + f:write[[ + if (...) then a = 15; return b, c, d + else return _ENV + end + ]] + f:close() + local t = {b = 12, c = "xuxu", d = print} + local f = assert(loadfile(file, 't', t)) + local b, c, d = f(1) + assert(t.a == 15 and b == 12 and c == t.c and d == print) + assert(f() == t) + f = assert(loadfile(file, 't', nil)) + assert(f() == nil) + f = assert(loadfile(file)) + assert(f() == _G) + assert(os.remove(file)) +end + + +-- 'loadfile' x modes +do + io.open(file, 'w'):write("return 10"):close() + local s, m = loadfile(file, 'b') + assert(not s and string.find(m, "a text chunk")) + io.open(file, 'w'):write("\27 return 10"):close() + local s, m = loadfile(file, 't') + assert(not s and string.find(m, "a binary chunk")) + assert(os.remove(file)) +end + + +io.output(file) +assert(io.write("qualquer coisa\n")) +assert(io.write("mais qualquer coisa")) +io.close() +assert(io.output(assert(io.open(otherfile, 'wb'))) + :write("outra coisa\0\1\3\0\0\0\0\255\0") + :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) + :write[[ + 123.4 -56e-2 not a number +second line +third line + +and the rest of the file +]] + :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"):seek("set", 1) + assert(fr:read("*all") == "xa\n") -- now we have a whole line + f:close(); fr:close() + assert(os.remove(file)) +end + + +if not _soft then + print("testing large files (> BUFSIZ)") + io.output(file) + for i=1,5001 do io.write('0123456789123') end + io.write('\n12346'):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 +end + +if not _noposix then + print("testing popen/pclose and execute") + local tests = { + -- command, what, code + {"ls > /dev/null", "ok"}, + {"not-to-be-found-command", "exit"}, + {"exit 3", "exit", 3}, + {"exit 129", "exit", 129}, + {"kill -s HUP $$", "signal", 1}, + {"kill -s KILL $$", "signal", 9}, + {"sh -c 'kill -s HUP $$'", "exit"}, + {'lua -e "os.exit(20, true)"', "exit", 20}, + } + print("\n(some error messages are expected now)") + for _, v in ipairs(tests) do + local x, y, z = io.popen(v[1]):close() + local x1, y1, z1 = os.execute(v[1]) + assert(x == x1 and y == y1 and z == z1) + if v[2] == "ok" then + assert(x == true and y == 'exit' and z == 0) + else + assert(x == nil and y == v[2]) -- correct status and 'what' + -- correct code if known (but always different from 0) + assert((v[3] == nil and z > 0) or v[3] == z) + end + end +end + + +-- testing tmpfile +f = io.tmpfile() +assert(io.type(f) == "file") +f:write("alo") +f:seek("set") +assert(f:read"*a" == "alo") + +end --} + +print'+' + + +assert(os.date("") == "") +assert(os.date("!") == "") +local x = string.rep("a", 10000) +assert(os.date(x) == x) +local t = os.time() +D = os.date("*t", t) +assert(os.date(string.rep("%d", 1000), t) == + string.rep(os.date("%d", t), 1000)) +assert(os.date(string.rep("%", 200)) == string.rep("%", 100)) + +local t = os.time() +D = os.date("*t", t) +load(os.date([[assert(D.year==%Y and D.month==%m and D.day==%d and + D.hour==%H and D.min==%M and D.sec==%S and + D.wday==%w+1 and D.yday==%j and type(D.isdst) == 'boolean')]], t))() + +assert(not pcall(os.date, "%9")) -- invalid conversion specifier +assert(not pcall(os.date, "%")) -- invalid conversion specifier +assert(not pcall(os.date, "%O")) -- invalid conversion specifier +assert(not pcall(os.date, "%E")) -- invalid conversion specifier +assert(not pcall(os.date, "%Ea")) -- invalid conversion specifier + +if not _noposix then + assert(type(os.date("%Ex")) == 'string') + assert(type(os.date("%Oy")) == 'string') +end + +assert(os.time(D) == t) +assert(not pcall(os.time, {hour = 12})) + +D = os.date("!*t", t) +load(os.date([[!assert(D.year==%Y and D.month==%m and D.day==%d and + D.hour==%H and D.min==%M and D.sec==%S and + D.wday==%w+1 and D.yday==%j and type(D.isdst) == 'boolean')]], t))() + +do + local D = os.date("*t") + local t = os.time(D) + assert(type(D.isdst) == 'boolean') + D.isdst = nil + local t1 = os.time(D) + assert(t == t1) -- if isdst is absent uses correct default +end + +t = os.time(D) +D.year = D.year-1; +local t1 = os.time(D) +-- 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} +local t2 = os.time{year=2000, month=10, day=1, hour=23, min=10, sec=19} +assert(os.difftime(t1,t2) == 60*2-19) + +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/lua-5.2.2-tests/gc.lua b/lua-5.2.2-tests/gc.lua new file mode 100644 index 0000000000..828a829d8a --- /dev/null +++ b/lua-5.2.2-tests/gc.lua @@ -0,0 +1,575 @@ +print('testing garbage collection') + +collectgarbage() + +assert(collectgarbage("isrunning")) + +local function gcinfo () return collectgarbage"count" * 1024 end + + +-- test weird parameters +do + -- save original parameters + local a = collectgarbage("setpause", 200) + local b = collectgarbage("setstepmul", 200) + local t = {0, 2, 10, 90, 500, 5000, 30000, 2^31 - 2} + for i = 1, #t do + local p = t[i] + for j = 1, #t do + local m = t[j] + collectgarbage("setpause", p) + collectgarbage("setstepmul", m) + collectgarbage("step", 0) + collectgarbage("step", 10000) + end + end + -- restore original parameters + collectgarbage("setpause", a) + collectgarbage("setstepmul", b) + collectgarbage() +end + + +_G["while"] = 234 + +limit = 5000 + + +local function GC1 () + local u + local b -- must be declared after 'u' (to be above it in the stack) + local finish = false + u = setmetatable({}, {__gc = function () finish = true end}) + b = {34} + repeat u = {} until finish + assert(b[1] == 34) -- 'u' was collected, but 'b' was not + + finish = false; local i = 1 + u = setmetatable({}, {__gc = function () finish = true end}) + repeat i = i + 1; u = i .. i until finish + assert(b[1] == 34) -- 'u' was collected, but 'b' was not + + finish = false + u = setmetatable({}, {__gc = function () finish = true end}) + repeat local i; u = function () return i end until finish + assert(b[1] == 34) -- 'u' was collected, but 'b' was not +end + +local function GC() GC1(); GC1() end + + +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 + load(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 _soft then step = 13 end + for i=1, string.len(prog), step do + for j=i, string.len(prog), step do + pcall(load(string.sub(prog, i, j))) + end + end +end + +foo = nil +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 k,b = collectgarbage("count") +assert(k*1024 == math.floor(k)*1024 + b) + +print("steps") + +local bytes = gcinfo() +while 1 do + local nbytes = gcinfo() + if nbytes < bytes then break end -- run until gc + bytes = nbytes + a = {} +end + +print("steps (2)") + +local function dosteps (siz) + assert(not collectgarbage("isrunning")) + collectgarbage() + assert(not collectgarbage("isrunning")) + local a = {} + for i=1,100 do a[i] = {{}}; local b = {} end + local x = gcinfo() + local i = 0 + repeat -- do steps until it completes a collection cycle + i = i+1 + until collectgarbage("step", siz) + assert(gcinfo() < x) + return i +end + +collectgarbage"stop" + +if not _port then + -- test the "size" of basic GC steps (whatever they mean...) + assert(dosteps(0) > 10) + assert(dosteps(10) < dosteps(2)) +end + +-- collector should do a full collection with so many steps +assert(dosteps(100000) == 1) +assert(collectgarbage("step", 1000000) == true) +assert(collectgarbage("step", 1000000) == true) + +assert(not collectgarbage("isrunning")) +collectgarbage"restart" +assert(collectgarbage("isrunning")) + + +if not _port then + -- test the pace of the collector + collectgarbage(); collectgarbage() + local x = gcinfo() + collectgarbage"stop" + assert(not collectgarbage("isrunning")) + repeat + local a = {} + until gcinfo() > 3 * x + collectgarbage"restart" + assert(collectgarbage("isrunning")) + repeat + local a = {} + until gcinfo() <= x * 2 +end + + +print("clearing tables") +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 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 == 2*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)) + + +-- 'bug' in 5.1 +a = {} +local t = {x = 10} +local C = setmetatable({key = t}, {__mode = 'v'}) +local C1 = setmetatable({[t] = 1}, {__mode = 'k'}) +a.x = t -- this should not prevent 't' from being removed from + -- weak table 'C' by the time 'a' is finalized + +setmetatable(a, {__gc = function (u) + assert(C.key == nil) + assert(type(next(C1)) == 'table') + end}) + +a, t = nil +collectgarbage() +collectgarbage() +assert(next(C) == nil and next(C1) == nil) +C, C1 = nil + + +-- ephemerons +local mt = {__mode = 'k'} +a = {10,20,30,40}; setmetatable(a, mt) +x = nil +for i = 1, 100 do local n = {}; a[n] = {k = {x}}; x = n end +GC() +local n = x +local i = 0 +while n do n = a[n].k[1]; i = i + 1 end +assert(i == 100) +x = nil +GC() +for i = 1, 4 do assert(a[i] == i * 10); a[i] = nil end +assert(next(a) == nil) + +local K = {} +a[K] = {} +for i=1,10 do a[K][i] = {}; a[a[K][i]] = setmetatable({}, mt) end +x = nil +local k = 1 +for j = 1,100 do + local n = {}; local nk = k%10 + 1 + a[a[K][nk]][n] = {x, k = k}; x = n; k = nk +end +GC() +local n = x +local i = 0 +while n do local t = a[a[K][k]][n]; n = t[1]; k = t.k; i = i + 1 end +assert(i == 100) +K = nil +GC() +assert(next(a) == nil) + + +-- testing errors during GC +do +collectgarbage("stop") -- stop collection +local u = {} +local s = {}; setmetatable(s, {__mode = 'k'}) +setmetatable(u, {__gc = function (o) + local i = s[o] + s[i] = true + assert(not s[i - 1]) -- check proper finalization order + if i == 8 then error("here") end -- error during GC +end}) + +for i = 6, 10 do + local n = setmetatable({}, getmetatable(u)) + s[n] = i +end + +assert(not pcall(collectgarbage)) +for i = 8, 10 do assert(s[i]) end + +for i = 1, 5 do + local n = setmetatable({}, getmetatable(u)) + s[n] = i +end + +collectgarbage() +for i = 1, 10 do assert(s[i]) end + +getmetatable(u).__gc = false + + +-- __gc errors with non-string messages +setmetatable({}, {__gc = function () error{} end}) +local a, b = pcall(collectgarbage) +assert(not a and type(b) == "string" and string.find(b, "error in __gc")) + +end +print '+' + + +-- testing userdata +if T==nil then + (Message or print)('\a\n >>> testC not active: skipping userdata GC tests <<<\n\a') + +else + + local function newproxy(u) + return debug.setmetatable(T.newuserdata(0), debug.getmetatable(u)) + end + + collectgarbage("stop") -- stop collection + local u = newproxy(nil) + debug.setmetatable(u, {__gc = 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 +end + + +-- __gc x weak tables +local u = setmetatable({}, {__gc = true}) +-- __gc metamethod should be collected before running +setmetatable(getmetatable(u), {__mode = "v"}) +getmetatable(u).__gc = function (o) os.exit(1) end -- cannot happen +u = nil +collectgarbage() + +local u = setmetatable({}, {__gc = 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 = setmetatable({}, {__gc = function () error "!!!" end}) +u = nil +assert(not pcall(collectgarbage)) + + +if not _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 = {} + +local 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 + +do + collectgarbage() + collectgarbage"stop" + local x = gcinfo() + repeat + for i=1,1000 do _ENV.a = {} end + collectgarbage("step", 1) -- steps should not unblock the collector + until gcinfo() > 2 * x + collectgarbage"restart" +end + + +if T then -- tests for weird cases collecting upvalues + local a = 1200 + local f = function () return a end -- create upvalue for 'a' + assert(f() == 1200) + + -- erase reference to upvalue 'a', mark it as dead, but does not collect it + T.gcstate("pause"); collectgarbage("stop") + f = nil + T.gcstate("sweepstring") + + -- this function will reuse that dead upvalue... + f = function () return a end + assert(f() == 1200) + + -- create coroutine with local variable 'b' + local co = coroutine.wrap(function() + local b = 150 + coroutine.yield(function () return b end) + end) + + T.gcstate("pause") + assert(co()() == 150) -- create upvalue for 'b' + + -- mark upvalue 'b' as dead, but does not collect it + T.gcstate("sweepstring") + + co() -- finish coroutine, "closing" that dead upvalue + + assert(f() == 1200) + collectgarbage("restart") + + print"+" +end + + +if T then + local debug = require "debug" + collectgarbage("generational"); collectgarbage("stop") + x = T.newuserdata(0) + T.gcstate("propagate") -- ensure 'x' is old + T.gcstate("sweepstring") + T.gcstate("propagate") + assert(string.find(T.gccolor(x), "/old")) + local y = T.newuserdata(0) + debug.setmetatable(y, {__gc = true}) -- bless the new udata before... + debug.setmetatable(x, {__gc = true}) -- ...the old one + assert(string.find(T.gccolor(y), "white")) + T.checkmemory() + collectgarbage("incremental"); collectgarbage("restart") +end + + +if T then + print("emergency collections") + collectgarbage() + collectgarbage() + T.totalmem(T.totalmem() + 200) + for i=1,200 do local a = {} end + T.totalmem(1000000000) + collectgarbage() + local t = T.totalmem("table") + local a = {{}, {}, {}} -- create 4 new tables + assert(T.totalmem("table") == t + 4) + t = T.totalmem("function") + a = function () end -- create 1 new closure + assert(T.totalmem("function") == t + 1) + t = T.totalmem("thread") + a = coroutine.create(function () end) -- create 1 new coroutine + assert(T.totalmem("thread") == t + 1) +end + +-- create an object to be collected when state is closed +do + local setmetatable,assert,type,print,getmetatable = + setmetatable,assert,type,print,getmetatable + local tt = {} + tt.__gc = function (o) + assert(getmetatable(o) == tt) + -- create new objects during GC + local a = 'xuxu'..(10+3)..'joao', {} + ___Glob = o -- ressurect object! + setmetatable({}, tt) -- creates a new one with same metatable + print(">>> closing state " .. "<<<\n") + end + local u = setmetatable({}, tt) + ___Glob = {u} -- avoid object being collected before program end +end + +-- create several objects to raise errors when collected while closing state +do + local mt = {__gc = function (o) return o + 1 end} + for i = 1,10 do + -- create object and preserve it until the end + table.insert(___Glob, setmetatable({}, mt)) + end +end + +-- just to make sure +assert(collectgarbage'isrunning') + +print('OK') diff --git a/lua-5.2.2-tests/goto.lua b/lua-5.2.2-tests/goto.lua new file mode 100644 index 0000000000..d881715640 --- /dev/null +++ b/lua-5.2.2-tests/goto.lua @@ -0,0 +1,173 @@ +local function errmsg (code, m) + local st, msg = load(code) + assert(not st and string.find(msg, m)) +end + +-- cannot see label inside block +errmsg([[ goto l1; do ::l1:: end ]], "label 'l1'") +errmsg([[ do ::l1:: end goto l1; ]], "label 'l1'") + +-- repeated label +errmsg([[ ::l1:: ::l1:: ]], "label 'l1'") + + +-- undefined label +errmsg([[ goto l1; local aa ::l1:: ::l2:: print(3) ]], "local 'aa'") + +-- jumping over variable definition +errmsg([[ +do local bb, cc; goto l1; end +local aa +::l1:: print(3) +]], "local 'aa'") + +-- jumping into a block +errmsg([[ do ::l1:: end goto l1 ]], "label 'l1'") +errmsg([[ goto l1 do ::l1:: end ]], "label 'l1'") + +-- cannot continue a repeat-until with variables +errmsg([[ + repeat + if x then goto cont end + local xuxu = 10 + ::cont:: + until xuxu < x +]], "local 'xuxu'") + +-- simple gotos +local x +do + local y = 12 + goto l1 + ::l2:: x = x + 1; goto l3 + ::l1:: x = y; goto l2 +end +::l3:: ::l3_1:: assert(x == 13) + + +-- long labels +do + local prog = [[ + do + local a = 1 + goto l%sa; a = a + 1 + ::l%sa:: a = a + 10 + goto l%sb; a = a + 2 + ::l%sb:: a = a + 20 + return a + end + ]] + local label = string.rep("0123456789", 40) + prog = string.format(prog, label, label, label, label) + assert(assert(load(prog))() == 31) +end + +-- goto to correct label when nested +do goto l3; ::l3:: end -- does not loop jumping to previous label 'l3' + +-- ok to jump over local dec. to end of block +do + goto l1 + local a = 23 + x = a + ::l1::; +end + +while true do + goto l4 + goto l1 -- ok to jump over local dec. to end of block + goto l1 -- multiple uses of same label + local x = 45 + ::l1:: ;;; +end +::l4:: assert(x == 13) + +if print then + goto l1 -- ok to jump over local dec. to end of block + error("should not be here") + goto l2 -- ok to jump over local dec. to end of block + local x + ::l1:: ; ::l2:: ;; +else end + +-- to repeat a label in a different function is OK +local function foo () + local a = {} + goto l3 + ::l1:: a[#a + 1] = 1; goto l2; + ::l2:: a[#a + 1] = 2; goto l5; + ::l3:: + ::l3a:: a[#a + 1] = 3; goto l1; + ::l4:: a[#a + 1] = 4; goto l6; + ::l5:: a[#a + 1] = 5; goto l4; + ::l6:: assert(a[1] == 3 and a[2] == 1 and a[3] == 2 and + a[4] == 5 and a[5] == 4) + if not a[6] then a[6] = true; goto l3a end -- do it twice +end + +::l6:: foo() + + + +-------------------------------------------------------------------------------- +-- testing closing of upvalues + +local function foo () + local a = {} + do + local i = 1 + local k = 0 + a[0] = function (y) k = y end + ::l1:: do + local x + if i > 2 then goto l2 end + a[i] = function (y) if y then x = y else return x + k end end + i = i + 1 + goto l1 + end + end + ::l2:: return a +end + +local a = foo() +a[1](10); a[2](20) +assert(a[1]() == 10 and a[2]() == 20 and a[3] == nil) +a[0](13) +assert(a[1]() == 23 and a[2]() == 33) + +-------------------------------------------------------------------------------- +-- testing if x goto optimizations + +local function testG (a) + if a == 1 then + goto l1 + error("should never be here!") + elseif a == 2 then goto l2 + elseif a == 3 then goto l3 + elseif a == 4 then + goto l1 -- go to inside the block + error("should never be here!") + ::l1:: a = a + 1 -- must go to 'if' end + else + goto l4 + ::l4a:: a = a * 2; goto l4b + error("should never be here!") + ::l4:: goto l4a + error("should never be here!") + ::l4b:: + end + do return a end + ::l2:: do return "2" end + ::l3:: do return "3" end + ::l1:: return "1" +end + +assert(testG(1) == "1") +assert(testG(2) == "2") +assert(testG(3) == "3") +assert(testG(4) == 5) +assert(testG(5) == 10) +-------------------------------------------------------------------------------- + + +print'OK' diff --git a/lua-5.2.2-tests/libs/lib1.c b/lua-5.2.2-tests/libs/lib1.c new file mode 100644 index 0000000000..0cac7c9817 --- /dev/null +++ b/lua-5.2.2-tests/libs/lib1.c @@ -0,0 +1,49 @@ +/* +** 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} +}; + + +/* function used by lib11.c */ +int lib1_export (lua_State *L) { + lua_pushstring(L, "exported"); + return 1; +} + + +int onefunction (lua_State *L) { + lua_settop(L, 2); + lua_pushvalue(L, 1); + return 2; +} + + +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) { + lua_setglobal(L, "y"); + lua_setglobal(L, "x"); + luaL_newlib(L, funcs); + return 1; +} + diff --git a/lua-5.2.2-tests/libs/lib11.c b/lua-5.2.2-tests/libs/lib11.c new file mode 100644 index 0000000000..835a00c69b --- /dev/null +++ b/lua-5.2.2-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" + +/* function from lib1.c */ +int lib1_export (lua_State *L); + +int luaopen_lib11 (lua_State *L) { + return lib1_export(L); +} + + diff --git a/lua-5.2.2-tests/libs/lib2.c b/lua-5.2.2-tests/libs/lib2.c new file mode 100644 index 0000000000..e48d41aad1 --- /dev/null +++ b/lua-5.2.2-tests/libs/lib2.c @@ -0,0 +1,29 @@ +/* +** 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) { + lua_settop(L, 2); + lua_setglobal(L, "y"); /* y gets 2nd parameter */ + lua_setglobal(L, "x"); /* x gets 1st parameter */ + luaL_newlib(L, funcs); + return 1; +} + + diff --git a/lua-5.2.2-tests/libs/lib21.c b/lua-5.2.2-tests/libs/lib21.c new file mode 100644 index 0000000000..167507f99b --- /dev/null +++ b/lua-5.2.2-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/lua-5.2.2-tests/libs/makefile b/lua-5.2.2-tests/libs/makefile new file mode 100644 index 0000000000..1f9eeada5f --- /dev/null +++ b/lua-5.2.2-tests/libs/makefile @@ -0,0 +1,26 @@ +# change this variable to point to the directory with Lua headers +# of the version being tested +LUA_DIR = ../.. + +CC = gcc + +# compilation should generate Dynamic-Link Libraries +CFLAGS = -Wall -O2 -I$(LUA_DIR) -ansi -fpic -shared + +# libraries used by the tests +all: lib1.so lib11.so lib2.so lib21.so v-lib2.so + +lib1.so: lib1.c + $(CC) $(CFLAGS) -o lib1.so lib1.c + +lib11.so: lib11.c + $(CC) $(CFLAGS) -o lib11.so lib11.c + +lib2.so: lib2.c + $(CC) $(CFLAGS) -o lib2.so lib2.c + +lib21.so: lib21.c + $(CC) $(CFLAGS) -o lib21.so lib21.c + +v-lib2.so: lib2.so + mv lib2.so ./v-lib2.so diff --git a/lua-5.2.2-tests/literals.lua b/lua-5.2.2-tests/literals.lua new file mode 100644 index 0000000000..36e2fcf4e3 --- /dev/null +++ b/lua-5.2.2-tests/literals.lua @@ -0,0 +1,258 @@ +print('testing scanner') + +debug = require "debug" + + +local function dostring (x) return assert(load(x))() end + +dostring("x \v\f = \t\r 'a\0a' \v\f\f") +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") + +-- hexadecimal escapes +assert("\x00\x05\x10\x1f\x3C\xfF\xe8" == "\0\5\16\31\60\255\232") + +local function lexstring (x, y, n) + local f = assert(load('return '..x..', debug.getinfo(1).currentline')) + local s, l = f() + assert(s == y and l == n) +end + +lexstring("'abc\\z \n efg'", "abcefg", 2) +lexstring("'abc\\z \n\n\n'", "abc", 4) +lexstring("'\\z \n\t\f\v\n'", "", 3) +lexstring("[[\nalo\nalo\n\n]]", "alo\nalo\n\n", 5) +lexstring("[[\nalo\ralo\n\n]]", "alo\nalo\n\n", 5) +lexstring("[[\nalo\ralo\r\n]]", "alo\nalo\n", 4) +lexstring("[[\ralo\n\ralo\r\n]]", "alo\nalo\n", 4) +lexstring("[[alo]\n]alo]]", "alo]\n]alo", 2) + +assert("abc\z + def\z + ghi\z + " == 'abcdefghi') + +-- Error in escape sequences +local function lexerror (s, err) + local st, msg = load('return '..s) + if err ~= '' then err = "'"..err.."'" end + assert(not st and string.find(msg, "near "..err, 1, true)) +end +lexerror([["abc\x"]], [[\x"]]) +lexerror([["abc\x]], [[\x]]) +lexerror([["\x]], [[\x]]) +lexerror([["\x5"]], [[\x5"]]) +lexerror([["\x5]], [[\x5]]) +lexerror([["\xr"]], [[\xr]]) +lexerror([["\xr]], [[\xr]]) +lexerror([["\x.]], [[\x.]]) +lexerror([["\x8%"]], [[\x8%]]) +lexerror([["\xAG]], [[\xAG]]) +lexerror([["\g"]], [[\g]]) +lexerror([["\g]], [[\g]]) +lexerror([["\."]], [[\.]]) + +lexerror([["\999"]], [[\999]]) +lexerror([["xyz\300"]], [[\300]]) +lexerror([[" \256"]], [[\256]]) + + +-- unfinished strings +lexerror("[=[alo]]", "") +lexerror("[=[alo]=", "") +lexerror("[=[alo]", "") +lexerror("'alo", "") +lexerror("'alo \\z \n\n", "") +lexerror("'alo \\z", "") +lexerror([['alo \98]], "") + +-- valid characters in variable names +for i = 0, 255 do + local s = string.char(i) + assert(not string.find(s, "[a-zA-Z_]") == not load(s .. "=1")) + assert(not string.find(s, "[a-zA-Z_0-9]") == + not load("a" .. s .. "1 = 1")) +end + + +-- 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(load(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 == load("return [====[\n"..s.."]====]")()) +end + + +-- testing decimal point locale +if os.setlocale("pt_BR") or os.setlocale("ptb") then + assert(not load("á = 3")) -- parser still works with C locale + assert(not load("a = (3,4)")) + assert(tonumber("3,4") == 3.4 and tonumber"3.4" == nil) + assert(assert(load("return 3.4"))() == 3.4) + assert(assert(load("return .4,3"))() == .4) + assert(assert(load("return 4."))() == 4.) + assert(assert(load("return 4.+.5"))() == 4.5) + local a,b = load("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 + + +-- testing %q x line ends +local s = "a string with \r and \n and \r\n and \n\r" +local c = string.format("return %q", s) +assert(assert(load(c))() == s) + +-- testing errors +assert(not load"a = 'non-ending string") +assert(not load"a = 'non-ending string\n'") +assert(not load"a = '\\345'") +assert(not load"a = [=x]") + +print('OK') diff --git a/lua-5.2.2-tests/locals.lua b/lua-5.2.2-tests/locals.lua new file mode 100644 index 0000000000..a290e5bc07 --- /dev/null +++ b/lua-5.2.2-tests/locals.lua @@ -0,0 +1,157 @@ +print('testing local variables and environments') + +local debug = require"debug" + + +-- bug in 5.1: + +local function f(x) x = nil; return x end +assert(f(10) == nil) + +local function f() local x; return x end +assert(f(10) == nil) + +local function f(x) x = nil; local y; return x, y end +assert(f(10) == nil and select(2, f(20)) == nil) + +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 +load('local a = {}')() +assert(a == nil) + +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') + + +local function getenv (f) + local a,b = debug.getupvalue(f, 1) + assert(a == '_ENV') + return b +end + +-- test for global table of loaded chunks +assert(getenv(load"a=3") == _G) +local c = {}; local f = load("a = 3", nil, nil, c) +assert(getenv(f) == c) +assert(c.a == nil) +f() +assert(c.a == 3) + +-- testing limits for special instructions + +if not _soft then + local a + local p = 4 + for i=2,31 do + for j=-3,3 do + assert(load(string.format([[local a=%s; + a=a+%s; + assert(a ==2^%s)]], j, p-j, i))) () + assert(load(string.format([[local a=%s; + a=a-%s; + assert(a==-2^%s)]], -j, p-j, i))) () + assert(load(string.format([[local a,b=0,%s; + a=b-%s; + assert(a==-2^%s)]], -j, p-j, i))) () + end + p =2*p + end +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 + + +-- testing lexical environments + +assert(_ENV == _G) + +do local _ENV = (function (...) return ... end)(_G, dummy) + +do local _ENV = {assert=assert}; assert(true) end +mt = {_G = _G} +local foo,x +do local _ENV = mt + function foo (x) + A = x + do local _ENV = _G; A = 1000 end + return function (x) return A .. x end + end +end +assert(getenv(foo) == mt) +x = foo('hi'); assert(mt.A == 'hi' and A == 1000) +assert(x('*') == mt.A .. '*') + +do local _ENV = {assert=assert, A=10}; + do local _ENV = {assert=assert, A=20}; + assert(A==20);x=A + end + assert(A==10 and x==20) +end +assert(x==20) + + +print('OK') + +return 5,f + +end + diff --git a/lua-5.2.2-tests/ltests/ltests.c b/lua-5.2.2-tests/ltests/ltests.c new file mode 100644 index 0000000000..8d76f5af5d --- /dev/null +++ b/lua-5.2.2-tests/ltests/ltests.c @@ -0,0 +1,1506 @@ +/* +** $Id: ltests.c,v 2.134 2012/10/03 12:36:46 roberto Exp $ +** Internal Module for Debugging of the Lua Implementation +** See Copyright Notice in lua.h +*/ + + +#include +#include +#include +#include + +#define ltests_c +#define LUA_CORE + +#include "lua.h" + +#include "lapi.h" +#include "lauxlib.h" +#include "lcode.h" +#include "lctype.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) + + +void *l_Trick = 0; + + +int islocked = 0; + + +#define obj_at(L,k) (L->ci->func + (k)) + + +static void setnameval (lua_State *L, const char *name, int val) { + lua_pushstring(L, name); + lua_pushinteger(L, val); + lua_settable(L, -3); +} + + +static void pushobject (lua_State *L, const TValue *o) { + setobj2s(L, L->top, o); + api_incr_top(L); +} + + +static int tpanic (lua_State *L) { + fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", + lua_tostring(L, -1)); + return (exit(EXIT_FAILURE), 0); /* do not return to Lua */ +} + + +/* +** {====================================================================== +** Controlled version for realloc. +** ======================================================================= +*/ + +#define MARK 0x55 /* 01010101 (a nice pattern) */ + +typedef union Header { + L_Umaxalign a; /* ensures maximum alignment for Header */ + struct { + size_t size; + int type; + } d; +} Header; + + +#if !defined(EXTERNMEMCHECK) + +/* full memory check */ +#define MARKSIZE 16 /* size of marks after each block */ +#define fillmem(mem,size) memset(mem, -MARK, size) + +#else + +/* external memory check: don't do it twice */ +#define MARKSIZE 0 +#define fillmem(mem,size) /* empty */ + +#endif + + +Memcontrol l_memcontrol = + {0L, 0L, 0L, 0L, {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}}; + + +static void freeblock (Memcontrol *mc, Header *block) { + if (block) { + size_t size = block->d.size; + int i; + for (i = 0; i < MARKSIZE; i++) /* check marks after block */ + lua_assert(*(cast(char *, block + 1) + size + i) == MARK); + mc->objcount[block->d.type]--; + fillmem(block, sizeof(Header) + size + MARKSIZE); /* erase block */ + free(block); /* actually free block */ + mc->numblocks--; /* update counts */ + mc->total -= size; + } +} + + +void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) { + Memcontrol *mc = cast(Memcontrol *, ud); + Header *block = cast(Header *, b); + int type; + if (mc->memlimit == 0) { /* first time? */ + char *limit = getenv("MEMLIMIT"); /* initialize memory limit */ + mc->memlimit = limit ? strtoul(limit, NULL, 10) : ULONG_MAX; + } + if (block == NULL) { + type = (oldsize < LUA_NUMTAGS) ? oldsize : 0; + oldsize = 0; + } + else { + block--; /* go to real header */ + type = block->d.type; + lua_assert(oldsize == block->d.size); + } + if (size == 0) { + freeblock(mc, block); + return NULL; + } + else if (size > oldsize && mc->total+size-oldsize > mc->memlimit) + return NULL; /* fake a memory allocation error */ + else { + Header *newblock; + int i; + size_t commonsize = (oldsize < size) ? oldsize : size; + size_t realsize = sizeof(Header) + size + MARKSIZE; + if (realsize < size) return NULL; /* arithmetic overflow! */ + newblock = cast(Header *, malloc(realsize)); /* alloc a new block */ + if (newblock == NULL) return NULL; /* really out of memory? */ + if (block) { + memcpy(newblock + 1, block + 1, commonsize); /* copy old contents */ + freeblock(mc, block); /* erase (and check) old copy */ + } + /* initialize new part of the block with something `weird' */ + fillmem(cast(char *, newblock + 1) + commonsize, size - commonsize); + /* initialize marks after block */ + for (i = 0; i < MARKSIZE; i++) + *(cast(char *, newblock + 1) + size + i) = MARK; + newblock->d.size = size; + newblock->d.type = type; + mc->total += size; + if (mc->total > mc->maxmem) + mc->maxmem = mc->total; + mc->numblocks++; + mc->objcount[type]++; + return newblock + 1; + } +} + + +/* }====================================================================== */ + + + +/* +** {====================================================== +** Functions to check memory consistency +** ======================================================= +*/ + + +static int testobjref1 (global_State *g, GCObject *f, GCObject *t) { + if (isdead(g,t)) return 0; + if (!issweepphase(g)) + return !(isblack(f) && iswhite(t)); + else return 1; +} + + +static void printobj (global_State *g, GCObject *o) { + int i = 1; + GCObject *p; + for (p = g->allgc; p != o && p != NULL; p = gch(p)->next) i++; + if (p == NULL) { + i = 1; + for (p = g->finobj; p != o && p != NULL; p = gch(p)->next) i++; + if (p == NULL) i = 0; /* zero means 'not found' */ + else i = -i; /* negative means 'found in findobj list */ + } + printf("||%d:%s(%p)-%c(%02X)||", i, ttypename(gch(o)->tt), (void *)o, + isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', gch(o)->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))) + + +static void checkvalref (global_State *g, GCObject *f, const TValue *t) { + if (iscollectable(t)) { + lua_assert(righttt(t)); + lua_assert(testobjref(g, f, gcvalue(t))); + } +} + + +static void checktable (global_State *g, Table *h) { + int i; + Node *n, *limit = gnode(h, sizenode(h)); + GCObject *hgc = obj2gco(h); + if (h->metatable) + checkobjref(g, hgc, h->metatable); + for (i = 0; i < h->sizearray; i++) + checkvalref(g, hgc, &h->array[i]); + for (n = gnode(h, 0); n < limit; n++) { + 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; isizek; i++) { + if (ttisstring(f->k+i)) + checkobjref(g, fgc, rawtsvalue(f->k+i)); + } + for (i=0; isizeupvalues; i++) { + if (f->upvalues[i].name) + checkobjref(g, fgc, f->upvalues[i].name); + } + for (i=0; isizep; i++) { + if (f->p[i]) + checkobjref(g, fgc, f->p[i]); + } + for (i=0; isizelocvars; i++) { + if (f->locvars[i].varname) + checkobjref(g, fgc, f->locvars[i].varname); + } +} + + + +static void checkCclosure (global_State *g, CClosure *cl) { + GCObject *clgc = obj2gco(cl); + int i; + for (i = 0; i < cl->nupvalues; i++) + checkvalref(g, clgc, &cl->upvalue[i]); +} + + +static void checkLclosure (global_State *g, LClosure *cl) { + GCObject *clgc = obj2gco(cl); + int i; + if (cl->p) checkobjref(g, clgc, cl->p); + for (i=0; inupvalues; i++) { + if (cl->upvals[i]) { + lua_assert(cl->upvals[i]->tt == LUA_TUPVAL); + checkobjref(g, clgc, cl->upvals[i]); + } + } +} + + +static int lua_checkpc (pCallInfo ci) { + if (!isLua(ci)) return 1; + else { + Proto *p = ci_func(ci)->p; + return p->code <= ci->u.l.savedpc && + ci->u.l.savedpc <= p->code + p->sizecode; + } +} + + +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 = gch(uvo)->next) { + UpVal *uv = gco2uv(uvo); + lua_assert(uv->v != &uv->u.value); /* must be open */ + lua_assert(!isblack(uvo)); /* open upvalues cannot be black */ + } + for (ci = L1->ci; ci != NULL; ci = ci->previous) { + lua_assert(ci->top <= L1->stack_last); + lua_assert(lua_checkpc(ci)); + } + 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, int maybedead) { + if (isdead(g, o)) + lua_assert(maybedead); + else { + if (g->gcstate == GCSpause) + lua_assert(iswhite(o)); + switch (gch(o)->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, gco2t(o)); + break; + } + case LUA_TTHREAD: { + checkstack(g, gco2th(o)); + break; + } + case LUA_TLCL: { + checkLclosure(g, gco2lcl(o)); + break; + } + case LUA_TCCL: { + checkCclosure(g, gco2ccl(o)); + break; + } + case LUA_TPROTO: { + checkproto(g, gco2p(o)); + break; + } + case LUA_TSHRSTR: + case LUA_TLNGSTR: break; + default: lua_assert(0); + } + } +} + + +#define TESTGRAYBIT 7 + +static void checkgraylist (GCObject *l) { + while (l) { + lua_assert(isgray(l)); + lua_assert(!testbit(l->gch.marked, TESTGRAYBIT)); + l_setbit(l->gch.marked, TESTGRAYBIT); + switch (gch(l)->tt) { + case LUA_TTABLE: l = gco2t(l)->gclist; break; + case LUA_TLCL: l = gco2lcl(l)->gclist; break; + case LUA_TCCL: l = gco2ccl(l)->gclist; break; + case LUA_TTHREAD: l = gco2th(l)->gclist; break; + case LUA_TPROTO: l = gco2p(l)->gclist; break; + default: lua_assert(0); /* other objects cannot be gray */ + } + } +} + + +/* +** mark all objects in gray lists with the TESTGRAYBIT, so that +** 'checkmemory' can check that all gray objects are in a gray list +*/ +static void markgrays (global_State *g) { + if (!keepinvariant(g)) return; + checkgraylist(g->gray); + checkgraylist(g->grayagain); + checkgraylist(g->weak); + checkgraylist(g->ephemeron); + checkgraylist(g->allweak); +} + + +static void checkold (global_State *g, GCObject *o) { + int isold = 0; + for (; o != NULL; o = gch(o)->next) { + if (isold(o)) { /* old generation? */ + lua_assert(isgenerational(g)); + if (!issweepphase(g)) + isold = 1; + } + else lua_assert(!isold); /* non-old object cannot be after an old one */ + if (isgray(o)) { + lua_assert(!keepinvariant(g) || testbit(o->gch.marked, TESTGRAYBIT)); + resetbit(o->gch.marked, TESTGRAYBIT); + } + lua_assert(!testbit(o->gch.marked, TESTGRAYBIT)); + } +} + + +int lua_checkmemory (lua_State *L) { + global_State *g = G(L); + GCObject *o; + UpVal *uv; + int maybedead; + if (keepinvariant(g)) { + lua_assert(!iswhite(obj2gco(g->mainthread))); + lua_assert(!iswhite(gcvalue(&g->l_registry))); + } + else /* generational mode keeps collector in 'propagate' state */ + lua_assert(!isgenerational(g)); + lua_assert(!isdead(g, gcvalue(&g->l_registry))); + checkstack(g, g->mainthread); + resetbit(g->mainthread->marked, TESTGRAYBIT); + /* check 'allgc' list */ + markgrays(g); + checkold(g, g->allgc); + lua_assert(g->sweepgc == NULL || issweepphase(g)); + maybedead = 0; + for (o = g->allgc; o != NULL; o = gch(o)->next) { + if (g->sweepgc && o == *g->sweepgc) + maybedead = 1; /* part of the list not yet sweeped */ + checkobject(g, o, maybedead); + lua_assert(!testbit(o->gch.marked, SEPARATED)); + } + /* check 'finobj' list */ + checkold(g, g->finobj); + for (o = g->finobj; o != NULL; o = gch(o)->next) { + lua_assert(testbit(o->gch.marked, SEPARATED)); + lua_assert(gch(o)->tt == LUA_TUSERDATA || + gch(o)->tt == LUA_TTABLE); + checkobject(g, o, 0); + } + /* check 'tobefnz' list */ + checkold(g, g->tobefnz); + for (o = g->tobefnz; o != NULL; o = gch(o)->next) { + lua_assert(!iswhite(o) || g->gcstate == GCSpause); + lua_assert(!isdead(g, o) && testbit(o->gch.marked, SEPARATED)); + lua_assert(gch(o)->tt == LUA_TUSERDATA || + gch(o)->tt == LUA_TTABLE); + } + /* check 'uvhead' list */ + 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 */ + if (!isdead(g, obj2gco(uv))) + 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 = getfuncline(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; + case iAx: + sprintf(buff+strlen(buff), "%-12s%4d", name, GETARG_Ax(i)); + break; + } + return buff; +} + + +#if 0 +void luaI_printcode (Proto *pt, int size) { + int pc; + for (pc=0; pcmaxstacksize); + setnameval(L, "numparams", p->numparams); + for (pc=0; pcsizecode; 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 = getproto(obj_at(L, 1)); + lua_createtable(L, p->sizek, 0); + for (i=0; isizek; i++) { + 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 = getproto(obj_at(L, 1)); + 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, "MAXSTACK", MAXSTACK); + setnameval(L, "NUM_OPCODES", NUM_OPCODES); + return 1; +} + + +static int mem_query (lua_State *L) { + if (lua_isnone(L, 1)) { + lua_pushinteger(L, l_memcontrol.total); + lua_pushinteger(L, l_memcontrol.numblocks); + lua_pushinteger(L, l_memcontrol.maxmem); + return 3; + } + else if (lua_isnumber(L, 1)) { + l_memcontrol.memlimit = luaL_checkint(L, 1); + return 0; + } + else { + const char *t = luaL_checkstring(L, 1); + int i; + for (i = LUA_NUMTAGS - 1; i >= 0; i--) { + if (strcmp(t, ttypename(i)) == 0) { + lua_pushinteger(L, l_memcontrol.objcount[i]); + return 1; + } + } + return luaL_error(L, "unkown type '%s'", t); + } +} + + +static int settrick (lua_State *L) { + if (ttisnil(obj_at(L, 1))) + l_Trick = NULL; + else + l_Trick = gcvalue(obj_at(L, 1)); + 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 { + int marked = gcvalue(o)->gch.marked; + int n = 1; + lua_pushstring(L, iswhite(gcvalue(o)) ? "white" : + isblack(gcvalue(o)) ? "black" : "grey"); + if (testbit(marked, FINALIZEDBIT)) { + lua_pushliteral(L, "/finalized"); n++; + } + if (testbit(marked, SEPARATED)) { + lua_pushliteral(L, "/separated"); n++; + } + if (testbit(marked, FIXEDBIT)) { + lua_pushliteral(L, "/fixed"); n++; + } + if (testbit(marked, OLDBIT)) { + lua_pushliteral(L, "/old"); n++; + } + lua_concat(L, n); + } + return 1; +} + + +static int gc_state (lua_State *L) { + static const char *statenames[] = {"propagate", "atomic", + "sweepstring", "sweepudata", "sweep", "pause", ""}; + int option = luaL_checkoption(L, 1, "", statenames); + if (option == GCSpause + 1) { + lua_pushstring(L, statenames[G(L)->gcstate]); + return 1; + } + else { + global_State *g = G(L); + if (g->gckind == KGC_GEN && option == GCSpause) + luaL_error(L, "cannot go to 'pause' state in generational mode"); + lua_lock(L); + if (option < g->gcstate) { /* must cross 'pause'? */ + luaC_runtilstate(L, bitmask(GCSpause)); /* run until pause */ + if (g->gckind == KGC_GEN) + g->gcstate = GCSpropagate; /* skip pause in gen. mode */ + } + luaC_runtilstate(L, bitmask(option)); + lua_assert(G(L)->gcstate == option); + lua_unlock(L); + return 0; + } +} + + +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, (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); + 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)))) { + pushobject(L, gkey(gnode(t, i))); + } + else + lua_pushliteral(L, ""); + 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 = gch(ts)->next) { + setsvalue2s(L, L->top, rawgco2ts(ts)); + api_incr_top(L); + n++; + } + return n; + } + return 0; +} + + +static int tref (lua_State *L) { + int level = lua_gettop(L); + luaL_checkany(L, 1); + lua_pushvalue(L, 1); + lua_pushinteger(L, luaL_ref(L, LUA_REGISTRYINDEX)); + lua_assert(lua_gettop(L) == level+1); /* +1 for result */ + return 1; +} + +static int getref (lua_State *L) { + int level = lua_gettop(L); + lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_checkint(L, 1)); + lua_assert(lua_gettop(L) == level+1); + return 1; +} + +static int unref (lua_State *L) { + int level = lua_gettop(L); + luaL_unref(L, LUA_REGISTRYINDEX, 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_checkinteger(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 == LUA_OK) + 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_atpanic(L1, tpanic); + lua_pushlightuserdata(L, L1); + } + else + lua_pushnil(L); + return 1; +} + + +static lua_State *getstate (lua_State *L) { + lua_State *L1 = cast(lua_State *, lua_touserdata(L, 1)); + luaL_argcheck(L, L1 != NULL, 1, "state expected"); + return L1; +} + + +static int loadlib (lua_State *L) { + static const luaL_Reg libs[] = { + {"_G", luaopen_base}, + {"coroutine", luaopen_coroutine}, + {"debug", luaopen_debug}, + {"io", luaopen_io}, + {"os", luaopen_os}, + {"math", luaopen_math}, + {"string", luaopen_string}, + {"table", luaopen_table}, + {NULL, NULL} + }; + lua_State *L1 = getstate(L); + int i; + luaL_requiref(L1, "package", luaopen_package, 1); + luaL_getsubtable(L1, LUA_REGISTRYINDEX, "_PRELOAD"); + for (i = 0; libs[i].name; i++) { + lua_pushcfunction(L1, libs[i].func); + lua_setfield(L1, -2, libs[i].name); + } + return 0; +} + +static int closestate (lua_State *L) { + lua_State *L1 = getstate(L); + lua_close(L1); + return 0; +} + +static int doremote (lua_State *L) { + lua_State *L1 = getstate(L); + 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 == LUA_OK) + status = lua_pcall(L1, 0, LUA_MULTRET, 0); + if (status != LUA_OK) { + lua_pushnil(L); + lua_pushstring(L, lua_tostring(L1, -1)); + lua_pushinteger(L, status); + 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 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 void sethookaux (lua_State *L, int mask, int count, const char *code); + +static const char *const delimits = " \t\n,;"; + +static void skip (const char **pc) { + for (;;) { + if (**pc != '\0' && strchr(delimits, **pc)) (*pc)++; + else if (**pc == '#') { + while (**pc != '\n' && **pc != '\0') (*pc)++; + } + else break; + } +} + +static int getnum_aux (lua_State *L, lua_State *L1, const char **pc) { + int res = 0; + int sig = 1; + skip(pc); + if (**pc == '.') { + res = lua_tointeger(L1, -1); + lua_pop(L1, 1); + (*pc)++; + return res; + } + else if (**pc == '-') { + sig = -1; + (*pc)++; + } + if (!lisdigit(cast_uchar(**pc))) + luaL_error(L, "number expected (%s)", *pc); + while (lisdigit(cast_uchar(**pc))) res = res*10 + (*(*pc)++) - '0'; + return sig*res; +} + +static const char *getstring_aux (lua_State *L, char *buff, const char **pc) { + int i = 0; + skip(pc); + if (**pc == '"' || **pc == '\'') { /* quoted string? */ + int quote = *(*pc)++; + while (**pc != quote) { + if (**pc == '\0') luaL_error(L, "unfinished string in C script"); + buff[i++] = *(*pc)++; + } + (*pc)++; + } + else { + while (**pc != '\0' && !strchr(delimits, **pc)) + buff[i++] = *(*pc)++; + } + buff[i] = '\0'; + return buff; +} + + +static int getindex_aux (lua_State *L, lua_State *L1, const char **pc) { + skip(pc); + switch (*(*pc)++) { + case 'R': return LUA_REGISTRYINDEX; + case 'G': return luaL_error(L, "deprecated index 'G'"); + case 'U': return lua_upvalueindex(getnum_aux(L, L1, pc)); + default: (*pc)--; return getnum_aux(L, L1, pc); + } +} + + +static void pushcode (lua_State *L, int code) { + static const char *const codes[] = {"OK", "YIELD", "ERRRUN", + "ERRSYNTAX", "ERRMEM", "ERRGCMM", "ERRERR"}; + lua_pushstring(L, codes[code]); +} + + +#define EQ(s1) (strcmp(s1, inst) == 0) + +#define getnum (getnum_aux(L, L1, &pc)) +#define getstring (getstring_aux(L, buff, &pc)) +#define getindex (getindex_aux(L, L1, &pc)) + + +static int testC (lua_State *L); +static int Cfunck (lua_State *L); + +static int runC (lua_State *L, lua_State *L1, const char *pc) { + char buff[300]; + int status = 0; + if (pc == NULL) return luaL_error(L, "attempt to runC null script"); + for (;;) { + const char *inst = getstring; + if EQ("") return 0; + else if EQ("absindex") { + lua_pushnumber(L1, lua_absindex(L1, getindex)); + } + else if EQ("isnumber") { + lua_pushboolean(L1, lua_isnumber(L1, getindex)); + } + else if EQ("isstring") { + lua_pushboolean(L1, lua_isstring(L1, getindex)); + } + else if EQ("istable") { + lua_pushboolean(L1, lua_istable(L1, getindex)); + } + else if EQ("iscfunction") { + lua_pushboolean(L1, lua_iscfunction(L1, getindex)); + } + else if EQ("isfunction") { + lua_pushboolean(L1, lua_isfunction(L1, getindex)); + } + else if EQ("isuserdata") { + lua_pushboolean(L1, lua_isuserdata(L1, getindex)); + } + else if EQ("isudataval") { + lua_pushboolean(L1, lua_islightuserdata(L1, getindex)); + } + else if EQ("isnil") { + lua_pushboolean(L1, lua_isnil(L1, getindex)); + } + else if EQ("isnull") { + lua_pushboolean(L1, lua_isnone(L1, getindex)); + } + else if EQ("tonumber") { + lua_pushnumber(L1, lua_tonumber(L1, getindex)); + } + else if EQ("topointer") { + lua_pushnumber(L1, cast(size_t, lua_topointer(L1, getindex))); + } + else if EQ("tostring") { + const char *s = lua_tostring(L1, getindex); + const char *s1 = lua_pushstring(L1, s); + lua_assert((s == NULL && s1 == NULL) || (strcmp)(s, s1) == 0); + } + else if EQ("objsize") { + lua_pushinteger(L1, lua_rawlen(L1, getindex)); + } + else if EQ("len") { + lua_len(L1, getindex); + } + else if EQ("Llen") { + lua_pushinteger(L1, luaL_len(L1, getindex)); + } + else if EQ("tocfunction") { + lua_pushcfunction(L1, lua_tocfunction(L1, getindex)); + } + else if EQ("func2num") { + lua_CFunction func = lua_tocfunction(L1, getindex); + lua_pushnumber(L1, cast(size_t, func)); + } + else if EQ("return") { + int n = getnum; + if (L1 != L) { + int i; + for (i = 0; i < n; i++) + lua_pushstring(L, lua_tostring(L1, -(n - i))); + } + return n; + } + 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, getstring); + } + else if EQ("pushnil") { + lua_pushnil(L1); + } + else if EQ("pushbool") { + lua_pushboolean(L1, getnum); + } + else if EQ("newtable") { + lua_newtable(L1); + } + else if EQ("newuserdata") { + lua_newuserdata(L1, getnum); + } + else if EQ("tobool") { + lua_pushboolean(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("pushupvalueindex") { + lua_pushinteger(L1, lua_upvalueindex(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("copy") { + int f = getindex; + lua_copy(L1, f, getindex); + } + else if EQ("gettable") { + lua_gettable(L1, getindex); + } + else if EQ("getglobal") { + lua_getglobal(L1, getstring); + } + else if EQ("getfield") { + int t = getindex; + lua_getfield(L1, t, getstring); + } + else if EQ("setfield") { + int t = getindex; + lua_setfield(L1, t, getstring); + } + else if EQ("rawgeti") { + int t = getindex; + lua_rawgeti(L1, t, getnum); + } + else if EQ("settable") { + lua_settable(L1, getindex); + } + else if EQ("setglobal") { + lua_setglobal(L1, getstring); + } + else if EQ("next") { + lua_next(L1, -2); + } + else if EQ("concat") { + lua_concat(L1, getnum); + } + else if EQ("print") { + int n = getnum; + if (n != 0) { + printf("%s\n", luaL_tolstring(L1, n, NULL)); + lua_pop(L1, 1); + } + else { + int i; + n = lua_gettop(L1); + for (i = 1; i <= n; i++) { + printf("%s ", luaL_tolstring(L1, i, NULL)); + lua_pop(L1, 1); + } + printf("\n"); + } + } + else if EQ("arith") { + static char ops[] = "+-*/%^_"; + int op; + skip(&pc); + op = strchr(ops, *pc++) - ops; + lua_arith(L1, op); + } + else if EQ("compare") { + int a = getindex; + int b = getindex; + lua_pushboolean(L1, lua_compare(L1, a, b, getnum)); + } + else if EQ("call") { + int narg = getnum; + int nres = getnum; + lua_call(L1, narg, nres); + } + else if EQ("pcall") { + int narg = getnum; + int nres = getnum; + status = lua_pcall(L1, narg, nres, 0); + } + else if EQ("pcallk") { + int narg = getnum; + int nres = getnum; + int i = getindex; + status = lua_pcallk(L1, narg, nres, 0, i, Cfunck); + } + else if EQ("callk") { + int narg = getnum; + int nres = getnum; + int i = getindex; + lua_callk(L1, narg, nres, i, Cfunck); + } + else if EQ("yield") { + return lua_yield(L1, getnum); + } + else if EQ("yieldk") { + int nres = getnum; + int i = getindex; + return lua_yieldk(L1, nres, i, Cfunck); + } + else if EQ("newthread") { + lua_newthread(L1); + } + else if EQ("resume") { + int i = getindex; + status = lua_resume(lua_tothread(L1, i), L, getnum); + } + else if EQ("pushstatus") { + pushcode(L1, status); + } + else if EQ("xmove") { + int f = getindex; + int t = getindex; + lua_State *fs = (f == 0) ? L1 : lua_tothread(L1, f); + lua_State *ts = (t == 0) ? L1 : lua_tothread(L1, t); + int n = getnum; + if (n == 0) n = lua_gettop(fs); + lua_xmove(fs, ts, n); + } + 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("append") { + int t = getindex; + int i = lua_rawlen(L1, t); + lua_rawseti(L1, t, i + 1); + } + else if EQ("getctx") { + int i = 0; + int s = lua_getctx(L1, &i); + pushcode(L1, s); + lua_pushinteger(L1, i); + } + else if EQ("checkstack") { + int sz = getnum; + luaL_checkstack(L1, sz, getstring); + } + else if EQ("newmetatable") { + lua_pushboolean(L1, luaL_newmetatable(L1, getstring)); + } + else if EQ("testudata") { + int i = getindex; + lua_pushboolean(L1, luaL_testudata(L1, i, getstring) != NULL); + } + else if EQ("gsub") { + int a = getnum; int b = getnum; int c = getnum; + luaL_gsub(L1, lua_tostring(L1, a), + lua_tostring(L1, b), + lua_tostring(L1, c)); + } + else if EQ("sethook") { + int mask = getnum; + int count = getnum; + sethookaux(L1, mask, count, getstring); + } + 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; +} + + +static int testC (lua_State *L) { + lua_State *L1; + const char *pc; + if (lua_isuserdata(L, 1)) { + L1 = getstate(L); + pc = luaL_checkstring(L, 2); + } + else if (lua_isthread(L, 1)) { + L1 = lua_tothread(L, 1); + pc = luaL_checkstring(L, 2); + } + else { + L1 = L; + pc = luaL_checkstring(L, 1); + } + return runC(L, L1, pc); +} + + +static int Cfunc (lua_State *L) { + return runC(L, L, lua_tostring(L, lua_upvalueindex(1))); +} + + +static int Cfunck (lua_State *L) { + int i = 0; + lua_getctx(L, &i); + return runC(L, L, lua_tostring(L, i)); +} + + +static int makeCfunc (lua_State *L) { + luaL_checkstring(L, 1); + lua_pushcclosure(L, Cfunc, lua_gettop(L)); + return 1; +} + + +/* }====================================================== */ + + +/* +** {====================================================== +** tests for C hooks +** ======================================================= +*/ + +/* +** C hook that runs the C script stored in registry.C_HOOK[L] +*/ +static void Chook (lua_State *L, lua_Debug *ar) { + const char *scpt; + const char *const events [] = {"call", "ret", "line", "count", "tailcall"}; + lua_getfield(L, LUA_REGISTRYINDEX, "C_HOOK"); + lua_pushlightuserdata(L, L); + lua_gettable(L, -2); /* get C_HOOK[L] (script saved by sethookaux) */ + scpt = lua_tostring(L, -1); /* not very religious (string will be popped) */ + lua_pop(L, 2); /* remove C_HOOK and script */ + lua_pushstring(L, events[ar->event]); /* may be used by script */ + lua_pushinteger(L, ar->currentline); /* may be used by script */ + runC(L, L, scpt); /* run script from C_HOOK[L] */ +} + + +/* +** sets registry.C_HOOK[L] = scpt and sets Chook as a hook +*/ +static void sethookaux (lua_State *L, int mask, int count, const char *scpt) { + if (*scpt == '\0') { /* no script? */ + lua_sethook(L, NULL, 0, 0); /* turn off hooks */ + return; + } + lua_getfield(L, LUA_REGISTRYINDEX, "C_HOOK"); /* get C_HOOK table */ + if (!lua_istable(L, -1)) { /* no hook table? */ + lua_pop(L, 1); /* remove previous value */ + lua_newtable(L); /* create new C_HOOK table */ + lua_pushvalue(L, -1); + lua_setfield(L, LUA_REGISTRYINDEX, "C_HOOK"); /* register it */ + } + lua_pushlightuserdata(L, L); + lua_pushstring(L, scpt); + lua_settable(L, -3); /* C_HOOK[L] = script */ + lua_sethook(L, Chook, mask, count); +} + + +static int sethook (lua_State *L) { + if (lua_isnoneornil(L, 1)) + lua_sethook(L, NULL, 0, 0); /* turn off hooks */ + else { + const char *scpt = luaL_checkstring(L, 1); + const char *smask = luaL_checkstring(L, 2); + int count = luaL_optint(L, 3, 0); + int mask = 0; + if (strchr(smask, 'c')) mask |= LUA_MASKCALL; + if (strchr(smask, 'r')) mask |= LUA_MASKRET; + if (strchr(smask, 'l')) mask |= LUA_MASKLINE; + if (count > 0) mask |= LUA_MASKCOUNT; + sethookaux(L, mask, count, scpt); + } + 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, L, 0); + if (status != LUA_OK && status != LUA_YIELD) { + lua_pushboolean(L, 0); + lua_insert(L, -2); + return 2; /* return false + error message */ + } + else { + lua_pushboolean(L, 1); + return 1; + } +} + +/* }====================================================== */ + + + +static const struct luaL_Reg tests_funcs[] = { + {"checkmemory", lua_checkmemory}, + {"closestate", closestate}, + {"d2s", d2s}, + {"doonnewstack", doonnewstack}, + {"doremote", doremote}, + {"gccolor", get_gccolor}, + {"gcstate", gc_state}, + {"getref", getref}, + {"hash", hash_query}, + {"int2fb", int2fb_aux}, + {"limits", get_limits}, + {"listcode", listcode}, + {"listk", listk}, + {"listlocals", listlocals}, + {"loadlib", loadlib}, + {"newstate", newstate}, + {"newuserdata", newuserdata}, + {"num2int", num2int}, + {"pushuserdata", pushuserdata}, + {"querystr", string_query}, + {"querytab", table_query}, + {"ref", tref}, + {"resume", coresume}, + {"s2d", s2d}, + {"sethook", sethook}, + {"stacklevel", stacklevel}, + {"testC", testC}, + {"makeCfunc", makeCfunc}, + {"totalmem", mem_query}, + {"trick", settrick}, + {"udataval", udataval}, + {"unref", unref}, + {"upvalue", upvalue}, + {NULL, NULL} +}; + + +static void checkfinalmem (void) { + lua_assert(l_memcontrol.numblocks == 0); + lua_assert(l_memcontrol.total == 0); +} + + +int luaB_opentests (lua_State *L) { + void *ud; + lua_atpanic(L, &tpanic); + atexit(checkfinalmem); + lua_assert(lua_getallocf(L, &ud) == debug_realloc); + lua_assert(ud == cast(void *, &l_memcontrol)); + lua_setallocf(L, lua_getallocf(L, NULL), ud); + luaL_newlib(L, tests_funcs); + return 1; +} + +#endif diff --git a/lua-5.2.2-tests/ltests/ltests.h b/lua-5.2.2-tests/ltests/ltests.h new file mode 100644 index 0000000000..7a9d329df2 --- /dev/null +++ b/lua-5.2.2-tests/ltests/ltests.h @@ -0,0 +1,93 @@ +/* +** $Id: ltests.h,v 2.33 2010/07/28 15:51:59 roberto Exp $ +** Internal Header for Debugging of the Lua Implementation +** See Copyright Notice in lua.h +*/ + +#ifndef ltests_h +#define ltests_h + + +#include + +/* do not use compatibility macros in Lua code */ +#undef LUA_COMPAT_API + +#define LUA_DEBUG + +#undef NDEBUG +#include +#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; + unsigned long objcount[LUA_NUMTAGS]; +} Memcontrol; + +extern Memcontrol l_memcontrol; + + +/* +** generic variable for debug tricks +*/ +extern void *l_Trick; + + +void *debug_realloc (void *ud, void *block, size_t osize, size_t nsize); + + +typedef struct CallInfo *pCallInfo; + +int lua_checkmemory (lua_State *L); + + +/* test for lock/unlock */ +#undef luai_userstateopen +#undef luai_userstatethread +#undef lua_lock +#undef lua_unlock + +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 luai_userstatefree(l,l1) \ + lua_assert(getlock(l)->plock == getlock(l1)->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); + + +#if defined(lua_c) +#define luaL_newstate() lua_newstate(debug_realloc, &l_memcontrol) +#define luaL_openlibs(L) \ + { (luaL_openlibs)(L); luaL_requiref(L, "T", luaB_opentests, 1); } +#endif + + + +/* change some sizes to give some bugs a chance */ + +#undef LUAL_BUFFERSIZE +#define LUAL_BUFFERSIZE 23 +#define MINSTRTABSIZE 2 + + +#undef LUAI_USER_ALIGNMENT_T +#define LUAI_USER_ALIGNMENT_T union { char b[32]; } + + +#endif diff --git a/lua-5.2.2-tests/main.lua b/lua-5.2.2-tests/main.lua new file mode 100644 index 0000000000..fa6bf0e2db --- /dev/null +++ b/lua-5.2.2-tests/main.lua @@ -0,0 +1,260 @@ +# testing special comment on first line + +-- most (all?) tests here assume a reasonable "Unix-like" shell +if _port then return end + +print ("testing lua.c options") + +assert(os.execute()) -- 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: "..progname) + +local prepfile = function (s, p) + p = p or prog + io.output(p) + io.write(s) + assert(io.close()) +end + +function getoutput () + io.input(out) + local t = io.read("*a") + io.input():close() + assert(os.remove(out)) + return t +end + +function checkprogout (s) + local t = getoutput() + for line in string.gmatch(s, ".-\n") do + assert(string.find(t, line, 1, true)) + end +end + +function checkout (s) + local t = getoutput() + 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(...)) +end + +function NoRun (...) + assert(not auxrun(...)) +end + +function NoRunMsg (...) + print("\n(the next error is expected by the test)") + return NoRun(...) +end + +-- test environment variables used by Lua +prepfile("print(package.path)") + +RUN("env LUA_INIT= LUA_PATH=x lua %s > %s", prog, out) +checkout("x\n") + +RUN("env LUA_INIT= LUA_PATH_5_2=y LUA_PATH=x lua %s > %s", prog, out) +checkout("y\n") + +prepfile("print(package.cpath)") + +RUN("env LUA_INIT= LUA_CPATH=xuxu lua %s > %s", prog, out) +checkout("xuxu\n") + +RUN("env LUA_INIT= LUA_CPATH_5_2=yacc LUA_CPATH=x lua %s > %s", prog, out) +checkout("yacc\n") + +prepfile("print(X)") +RUN('env LUA_INIT="X=3" lua %s > %s', prog, out) +checkout("3\n") + +prepfile("print(X)") +RUN('env LUA_INIT_5_2="X=10" LUA_INIT="X=3" lua %s > %s', prog, out) +checkout("10\n") + +-- test option '-E' +prepfile("print(package.path, package.cpath)") +RUN('env LUA_INIT="error(10)" LUA_PATH=xxx LUA_CPATH=xxx lua -E %s > %s', + prog, out) +local defaultpath = getoutput() +defaultpath = string.match(defaultpath, "^(.-)\t") -- remove tab +assert(not string.find(defaultpath, "xxx") and string.find(defaultpath, "lua")) + + +-- test replacement of ';;' to default path +local function convert (p) + prepfile("print(package.path)") + RUN('env LUA_PATH="%s" lua %s > %s', p, prog, out) + local expected = getoutput() + expected = string.sub(expected, 1, -2) -- cut final end of line + assert(string.gsub(p, ";;", ";"..defaultpath..";") == expected) +end + +convert(";") +convert(";;") +convert(";;;") +convert(";;;;") +convert(";;;;;") +convert(";;a;;;bc") + + +-- test 2 files +prepfile("print(1); a=2; return {x=15}") +prepfile(("print(a); print(_G['%s'].x)"):format(prog), otherprog) +RUN('env LUA_PATH="?;;" lua -l %s -l%s -lstring -l io %s > %s', prog, otherprog, otherprog, out) +checkout("1\n2\n15\n2\n15\n") + +local a = [[ + assert(#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('env LUA_PATH="?;;" 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) +checkprogout("6\n10\n10\n\n") + +prepfile("a = [[b\nc\nd\ne]]\n=a") +print("temporary program file: "..prog) +RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out) +checkprogout("b\nc\nd\ne\n\n") + +prompt = "alo" +prepfile[[ -- +a = 2 +]] +RUN([[lua "-e_PROMPT='%s'" -i < %s > %s]], prompt, prog, out) +local t = getoutput() +assert(string.find(t, prompt .. ".*" .. prompt .. ".*" .. prompt)) + +-- test for error objects +prepfile[[ +debug = require "debug" +m = {x=0} +setmetatable(m, {__tostring = function(x) + return debug.getinfo(4).currentline + x.x +end}) +error(m) +]] +NoRun([[lua %s 2> %s]], prog, out) -- no message +checkout(progname..": 6\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) +checkprogout("11\n1\t2\n\n") + +prepfile[[#comment in 1st line without \n at the end]] +RUN("lua %s", prog) + +prepfile[[#test line number when file starts with comment line +debug = require"debug" +print(debug.getinfo(1).currentline) +]] +RUN("lua %s > %s", prog, out) +checkprogout('3') + +-- close Lua with an open file +prepfile(string.format([[io.output(%q); io.write('alo')]], out)) +RUN("lua %s", prog) +checkout('alo') + +-- bug in 5.2 beta (extra \0 after version line) +RUN([[lua -v -e'print"hello"' > %s]], out) +t = getoutput() +assert(string.find(t, "PUC%-Rio\nhello")) + + +-- testing os.exit +prepfile("os.exit(nil, true)") +RUN("lua %s", prog) +prepfile("os.exit(0, true)") +RUN("lua %s", prog) +prepfile("os.exit(true, true)") +RUN("lua %s", prog) +prepfile("os.exit(1, true)") +NoRun("lua %s", prog) -- no message +prepfile("os.exit(false, true)") +NoRun("lua %s", prog) -- no message + +assert(os.remove(prog)) +assert(os.remove(otherprog)) +assert(not os.remove(out)) + +RUN("lua -v") + +NoRunMsg("lua -h") +NoRunMsg("lua -e") +NoRunMsg("lua -e a") +NoRunMsg("lua -f") + +print("OK") diff --git a/lua-5.2.2-tests/math.lua b/lua-5.2.2-tests/math.lua new file mode 100644 index 0000000000..9dbeca646b --- /dev/null +++ b/lua-5.2.2-tests/math.lua @@ -0,0 +1,287 @@ +print("testing numbers and math lib") + + +-- basic float notation +assert(0e12 == 0 and .0 == 0 and 0. == 0 and .2e2 == 20 and 2.E-1 == 0.2) + +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 == 08) + a = 0 + assert(a == -a and 0 == -0) +end + +do + local x = -1 + local mz = 0/x -- minus zero + t = {[0] = 10, 20, 30, 40, 50} + assert(t[mz] == t[0] and t[-0] == t[0]) +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 + + +-- testing numeric strings + +assert("2" + 1 == 3) +assert("2 " + 1 == 3) +assert(" -2 " + 1 == -1) +assert(" -0xa " + 1 == -9) + + +-- testing 'tonumber' +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('-012') == -010-2) +assert(tonumber('-1.2e2') == - - -120) + +assert(tonumber("0xffffffffffff") == 2^(4*12) - 1) +assert(tonumber("0x"..string.rep("f", 150)) == 2^(4*150) - 1) +assert(tonumber('0x3.' .. string.rep('0', 100)) == 3) +assert(tonumber('0x0.' .. string.rep('0', 150).."1") == 2^(-4*151)) + +-- testing 'tonumber' with base +assert(tonumber(' 001010 ', 2) == 10) +assert(tonumber(' 001010 ', 10) == 001010) +assert(tonumber(' -1010 ', 2) == -10) +assert(tonumber('10', 36) == 36) +assert(tonumber(' -10 ', 36) == -36) +assert(tonumber(' +1Z ', 36) == 36 + 35) +assert(tonumber(' -1z ', 36) == -36 + -35) +assert(tonumber('-fFfa', 16) == -(10+(16*(15+(16*(15+(16*15))))))) +assert(tonumber(string.rep('1', 42), 2) + 1 == 2^42) +assert(tonumber(string.rep('1', 34), 2) + 1 == 2^34) +assert(tonumber('ffffFFFF', 16)+1 == 2^32) +assert(tonumber('0ffffFFFF', 16)+1 == 2^32) +assert(tonumber('-0ffffffFFFF', 16) - 1 == -2^40) +for i = 2,36 do + assert(tonumber('\t10000000000\t', i) == i^10) +end + +-- testing 'tonumber' fo invalid formats +assert(f(tonumber('fFfa', 15)) == nil) +assert(f(tonumber('099', 8)) == nil) +assert(f(tonumber('1\0', 2)) == nil) +assert(f(tonumber('', 8)) == nil) +assert(f(tonumber(' ', 9)) == nil) +assert(f(tonumber(' ', 9)) == nil) +assert(f(tonumber('0xf', 10)) == nil) + +assert(f(tonumber('inf')) == nil) +assert(f(tonumber(' INF ')) == nil) +assert(f(tonumber('Nan')) == nil) +assert(f(tonumber('nan')) == nil) + +assert(f(tonumber(' ')) == nil) +assert(f(tonumber('')) == nil) +assert(f(tonumber('1 a')) == nil) +assert(f(tonumber('1\0')) == nil) +assert(f(tonumber('1 \0')) == nil) +assert(f(tonumber('1\0 ')) == nil) +assert(f(tonumber('e1')) == nil) +assert(f(tonumber('e 1')) == nil) +assert(f(tonumber(' 3.4.5 ')) == nil) + + +-- testing 'tonumber' for invalid hexadecimal formats + +assert(tonumber('0x') == nil) +assert(tonumber('x') == nil) +assert(tonumber('x3') == nil) +assert(tonumber('00x2') == nil) +assert(tonumber('0x 2') == nil) +assert(tonumber('0 x2') == nil) +assert(tonumber('23x') == nil) +assert(tonumber('- 0xaa') == nil) + + +-- testing hexadecimal numerals + +assert(0x10 == 16 and 0xfff == 2^12 - 1 and 0XFB == 251) +assert(0x0p12 == 0 and 0x.0p-3 == 0) +assert(0xFFFFFFFF == 2^32 - 1) +assert(tonumber('+0x2') == 2) +assert(tonumber('-0xaA') == -170) +assert(tonumber('-0xffFFFfff') == -2^32 + 1) + +-- possible confusion with decimal exponent +assert(0E+1 == 0 and 0xE+1 == 15 and 0xe-1 == 13) + + +-- floating hexas + +assert(tonumber(' 0x2.5 ') == 0x25/16) +assert(tonumber(' -0x2.5 ') == -0x25/16) +assert(tonumber(' +0x0.51p+8 ') == 0x51) +assert(tonumber('0x0.51p') == nil) +assert(tonumber('0x5p+-2') == nil) +assert(0x.FfffFFFF == 1 - '0x.00000001') +assert('0xA.a' + 0 == 10 + 10/16) +assert(0xa.aP4 == 0XAA) +assert(0x4P-2 == 1) +assert(0x1.1 == '0x1.' + '+0x.1') + + +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.23E18') == 1.23*10^18) + +-- 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.fmod(10,3) == 1) +assert(eq(math.sqrt(10)^2, 10)) +assert(eq(math.log(2, 10), math.log(2)/math.log(10))) +assert(eq(math.log(2, 2), 1)) +assert(eq(math.log(9, 3), 2)) +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) + +-- 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') + + +if not _port then + print("testing -0 and NaN") + local mz, z = -0, 0 + assert(mz == z) + assert(1/mz < 0 and 0 < 1/z) + local a = {[mz] = 1} + assert(a[z] == 1 and a[mz] == 1) + local inf = math.huge * 2 + 1 + mz, z = -1/inf, 1/inf + assert(mz == z) + assert(1/mz < 0 and 0 < 1/z) + local NaN = inf - inf + assert(NaN ~= NaN) + assert(not (NaN < NaN)) + assert(not (NaN <= NaN)) + assert(not (NaN > NaN)) + assert(not (NaN >= NaN)) + assert(not (0 < NaN) and not (NaN < 0)) + local NaN1 = 0/0 + assert(NaN ~= NaN1 and not (NaN <= NaN1) and not (NaN1 <= NaN)) + 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) + -- string with same binary representation as 0.0 (may create problems + -- for constant manipulation in the pre-compiler) + local a1, a2, a3, a4, a5 = 0, 0, "\0\0\0\0\0\0\0\0", 0, "\0\0\0\0\0\0\0\0" + assert(a1 == a2 and a2 == a4 and a1 ~= a3) + assert(a3 == a5) +end + + +if not _port then + print("testing 'math.random'") + math.randomseed(0) + + local function aux (x1, x2, p) + local Max = -math.huge + local Min = math.huge + for i = 0, 20000 do + local t = math.random(table.unpack(p)) + Max = math.max(Max, t) + Min = math.min(Min, t) + if eq(Max, x2, 0.001) and eq(Min, x1, 0.001) then + goto ok + end + end + -- loop ended without satisfing condition + assert(false) + ::ok:: + assert(x1 <= Min and Max<=x2) + end + + aux(0, 1, {}) + aux(-10, 0, {-10,0}) +end + +for i=1,10 do + local t = math.random(5) + assert(1 <= t and t <= 5) +end + + +print('OK') diff --git a/lua-5.2.2-tests/nextvar.lua b/lua-5.2.2-tests/nextvar.lua new file mode 100644 index 0000000000..65fa79090b --- /dev/null +++ b/lua-5.2.2-tests/nextvar.lua @@ -0,0 +1,461 @@ +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 + +-- testing ipairs +local x = 0 +for k,v in ipairs{10,20,30;x=12} do + x = x + 1 + assert(k == x and v == x * 10) +end + +for _ in ipairs{x=12, y=24} do assert(nil) end + +-- test for 'false' x ipair +x = false +local i = 0 +for k,v in ipairs{true,false,true,false} do + i = i + 1 + x = not x + assert(x == v) +end +assert(i == 4) + +-- iterator function is always the same +assert(type(ipairs{}) == 'function' and ipairs{} == ipairs{}) + +if T then --[ +-- testing table sizes + +local function log2 (x) return math.log(x, 2) 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 C library sizes +do + local s = 0 + for _ in pairs(math) do s = s + 1 end + check(math, 0, mp2(s)) +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 = load(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 = {table.unpack(a,1,k)} + assert(#a == k) + check(a, k, 0) + a = {1,2,3,table.unpack(a,1,k)} + check(a, k+3, 0) + assert(#a == k + 3) +end + + +-- 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) +if not _port then + for i=1,11 do a[i] = nil end + for i=30,50 do a[i] = nil end -- force a rehash (?) + check(a, 0, 8) -- only 5 elements in the table + a[10] = 1 + for i=30,50 do a[i] = nil end -- force a rehash (?) + check(a, 0, 8) -- only 6 elements in the table + for i=1,14 do a[i] = nil end + for i=18,50 do a[i] = nil end -- force a rehash (?) + check(a, 0, 4) -- only 2 elements ([15] and [16]) +end + +-- 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, table.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 + + +-- next uses always the same iteraction function +assert(next{} == next{}) + +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 + + +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.fmod(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 + +do -- clear global table + local a = {} + for n,v in pairs(_G) do a[n]=v end + for n,v in pairs(a) do + if not package.loaded[n] and type(v) ~= "function" and + not string.find(n, "^[%u_]") then + _G[n] = nil + end + collectgarbage() + end +end + + +-- + +local function checknext (a) + local 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(#{} == 0) +assert(#{[-1] = 2} == 0) +assert(#{1,2,3,nil,nil} == 3) +for i=0,40 do + local a = {} + for j=1,i do a[j]=j end + assert(#a == i) +end + +-- 'maxn' is now deprecated, but it is easily defined in Lua +function table.maxn (t) + local max = 0 + for k in pairs(t) do + max = (type(k) == 'number') and math.max(max, k) or max + end + return max +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) + +table.maxn = nil + +-- int overflow +a = {} +for i=0,50 do a[math.pow(2,i)] = true end +assert(a[#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) + assert(not pcall(table.insert, a, 2, 20)); + table.insert(a, 10); table.insert(a, 2, 20); + table.insert(a, 1, -1); table.insert(a, 40); + table.insert(a, #a+1, 50) + table.insert(a, 2, -2) + assert(not pcall(table.insert, a, 0, 20)); + assert(not pcall(table.insert, a, #a + 2, 20)); + 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) + assert(table.remove(a) == nil) + assert(table.remove(a, #a) == 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 #a == 0 and a[-7] == "ban") + +a = {[-1] = "ban"} +test(a) +assert(#a == 0 and table.remove(a) == nil and a[-1] == "ban") + +a = {[0] = "ban"} +assert(#a == 0 and table.remove(a) == "ban" and a[0] == nil) + +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) +assert(table.remove(a) == nil) + +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.remove(a, 1) == nil) +assert(#a == 0 and a.n == nil) + +a = {10,20,30,40} +assert(table.remove(a, #a + 1) == nil) +assert(not pcall(table.remove, a, 0)) +assert(a[#a] == 40) +assert(table.remove(a, #a) == 40) +assert(a[#a] == 30) +assert(table.remove(a, 2) == 20) +assert(a[#a] == 30 and #a == 2) +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) + +if not _port then + print("testing precision in numeric for") + local a = 0; for i=0, 1, 0.1 do a=a+1 end; assert(a==11) + 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) +end + +-- 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, table.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) + + + +-- testing __pairs and __ipairs metamethod +a = {} +do + local x,y,z = pairs(a) + assert(type(x) == 'function' and y == a and z == nil) +end + +local function foo (e,i) + assert(e == a) + if i <= 10 then return i+1, i+2 end +end + +local function foo1 (e,i) + i = i + 1 + assert(e == a) + if i <= e.n then return i,a[i] end +end + +setmetatable(a, {__pairs = function (x) return foo, x, 0 end}) + +local i = 0 +for k,v in pairs(a) do + i = i + 1 + assert(k == i and v == k+1) +end + +a.n = 5 +a[3] = 30 + +a = {n=10} +setmetatable(a, {__len = function (x) return x.n end, + __ipairs = function (x) return function (e,i) + if i < #e then return i+1 end + end, x, 0 end}) +i = 0 +for k,v in ipairs(a) do + i = i + 1 + assert(k == i and v == nil) +end +assert(i == a.n) + +print"OK" diff --git a/lua-5.2.2-tests/pm.lua b/lua-5.2.2-tests/pm.lua new file mode 100644 index 0000000000..8e402948f7 --- /dev/null +++ b/lua-5.2.2-tests/pm.lua @@ -0,0 +1,344 @@ +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(string.match("aaab", ".*b") == "aaab") +assert(string.match("aaa", ".*a") == "aaa") +assert(string.match("b", ".*b") == "b") + +assert(string.match("aaab", ".+b") == "aaab") +assert(string.match("aaa", ".+a") == "aaa") +assert(not string.match("b", ".+b")) + +assert(string.match("aaab", ".?b") == "ab") +assert(string.match("aaa", ".?a") == "aa") +assert(string.match("b", ".?b") == "b") + +assert(f('aloALO', '%l*') == 'alo') +assert(f('aLo_ALO', '%a*') == 'aLo') + +assert(f(" \n\r*&\n\r xuxu \n\n", "%g%g%g+") == "xuxu") + +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 load(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")) + +-- bug since 2.5 (C-stack overflow) +do + local function f (size) + local s = string.rep("a", size) + local p = string.rep(".?", size) + return pcall(string.match, s, p) + end + local r, m = f(80) + assert(r and #m == 80) + r, m = f(200000) + assert(not r and string.find(m, "too complex")) +end + +if not _soft then + -- 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-.?$')) + + -- bug in 5.1.2 + a = string.rep('a', 10000) .. string.rep('b', 10000) + assert(not pcall(string.gsub, a, 'b')) +end + +-- recursive nest of gsubs +function rev (s) + return string.gsub(s, "(.)(.+)", function (c,s1) return rev(s1)..c end) +end + +local x = "abcdef" +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 +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(#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.") + +assert(string.find("a", "%f[a]") == 1) +assert(string.find("a", "%f[^%z]") == 1) +assert(string.find("a", "%f[^%l]") == 2) +assert(string.find("aba", "%f[a%z]") == 3) +assert(string.find("aba", "%f[%z]") == 4) +assert(not string.find("aba", "%f[%l%z]")) +assert(not string.find("aba", "%f[^%l%z]")) + +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(#a == 0) + + +-- malformed patterns +local function malform (p, m) + m = m or "malformed" + local r, msg = pcall(string.find, "a", p) + assert(not r and string.find(msg, m)) +end + +malform("[a") +malform("[]") +malform("[^]") +malform("[a%]") +malform("[a%") +malform("%b") +malform("%ba") +malform("%") +malform("%f", "missing") + +-- \0 in patterns +assert(string.match("ab\0\1\2c", "[\0-\2]+") == "\0\1\2") +assert(string.match("ab\0\1\2c", "[\0-\0]+") == "\0") +assert(string.find("b$a", "$\0?") == 2) +assert(string.find("abc\0efg", "%\0") == 4) +assert(string.match("abc\0efg\0\1e\1g", "%b\0\1") == "\0efg\0\1e\1") +assert(string.match("abc\0\0\0", "%\0+") == "\0\0\0") +assert(string.match("abc\0\0\0", "%\0%\0?") == "\0\0") + +-- magic char after \0 +assert(string.find("abc\0\0","\0.") == 4) +assert(string.find("abcx\0\0abc\0abc","x\0\0abc\0a.") == 4) + +print('OK') + diff --git a/lua-5.2.2-tests/sort.lua b/lua-5.2.2-tests/sort.lua new file mode 100644 index 0000000000..41b865c57a --- /dev/null +++ b/lua-5.2.2-tests/sort.lua @@ -0,0 +1,167 @@ +print "testing (parts of) table library" + +print "testing unpack" + +local unpack = table.unpack + +local x,y,z,a,n +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(#x == lim and x[1] == 1 and x[lim] == lim) +x = {unpack(a, lim-2)} +assert(#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) + +if not _no32 then + assert(not pcall(unpack, {}, 0, 2^31-1)) + assert(not pcall(unpack, {}, 1, 2^31-1)) + assert(not pcall(unpack, {}, -(2^31), 2^31-1)) + assert(not pcall(unpack, {}, -(2^31 - 1), 2^31-1)) + assert(pcall(unpack, {}, 2^31-1, 0)) + assert(pcall(unpack, {}, 2^31-1, 1)) + pcall(unpack, {}, 1, 2^31) + a, b = unpack({[2^31-1] = 20}, 2^31-1, 2^31-1) + assert(a == 20 and b == nil) + a, b = unpack({[2^31-1] = 20}, 2^31-2, 2^31-1) + assert(a == nil and b == 20) +end + +print "testing pack" + +a = table.pack() +assert(a[1] == nil and a.n == 0) + +a = table.pack(table) +assert(a[1] == table and a.n == 1) + +a = table.pack(nil, nil, nil, nil) +assert(a[1] == nil and a.n == 4) + + +print"testing sort" + + +-- test checks for invalid order functions +local function check (t) + local function f(a, b) assert(a and b); return true end + local s, e = pcall(table.sort, t, f) + assert(not s and e:find("invalid order function")) +end + +check{1,2,3,4} +check{1,2,3,4,5} +check{1,2,3,4,5,6} + + +function check (a, f) + f = f or function (x,y) return x '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") +if not _no32 then + assert(string.sub("123456789",-2^31, -4) == "123456") + assert(string.sub("123456789",-2^31, 2^31 - 1) == "123456789") + assert(string.sub("123456789",-2^31, -2^31) == "") +end +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("", "", 1) == 1) +assert(not string.find("", "", 2)) +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("\xe4") > 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("\xe4"), 0) == "\0\xe4\0") +assert(string.char(string.byte("\xe4l\0óu", 1, -1)) == "\xe4l\0óu") +assert(string.char(string.byte("\xe4l\0óu", 1, 0)) == "") +assert(string.char(string.byte("\xe4l\0óu", -10, 100)) == "\xe4l\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) == '') + +-- repetitions with separator +assert(string.rep('teste', 0, 'xuxu') == '') +assert(string.rep('teste', 1, 'xuxu') == 'teste') +assert(string.rep('\1\0\1', 2, '\0\0') == '\1\0\1\0\0\1\0\1') +assert(string.rep('', 10, '.') == string.rep('.', 9)) +if not _no32 then + assert(not pcall(string.rep, "aa", 2^30)) + assert(not pcall(string.rep, "", 2^30, "aa")) +end + +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") == [["\0"]]) +assert(load(string.format('return %q', x))() == x) +x = "\0\1\0023\5\0009" +assert(load(string.format('return %q', x))() == x) +assert(string.format("\0%c\0%c%x\0", string.byte("\xe4"), string.byte("b"), 140) == + "\0\xe4\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")) + +-- format x tostring +assert(string.format("%s %s", nil, true) == "nil true") +assert(string.format("%s %.4s", false, true) == "false true") +assert(string.format("%.3s %.3s", false, true) == "fal tru") +local m = setmetatable({}, {__tostring = function () return "hello" end}) +assert(string.format("%s %.10s", m, m) == "hello hello") + + +assert(string.format("%x", 0.3) == "0") +assert(string.format("%02x", 0.1) == "00") +assert(string.format("%08X", 2^32 - 1) == "FFFFFFFF") +assert(string.format("%+08d", 2^31 - 1) == "+2147483647") +assert(string.format("%+08d", -2^31) == "-2147483648") + + +-- longest number that can be formated +assert(string.len(string.format('%99.99f', -1e308)) >= 100) + + + +if not _nolonglong then + print("testing large numbers for format") + assert(string.format("%8x", 2^52 - 1) == "fffffffffffff") + assert(string.format("%d", -1) == "-1") + assert(tonumber(string.format("%u", 2^62)) == 2^62) + assert(string.format("%8x", 0xffffffff) == "ffffffff") + assert(string.format("%8x", 0x7fffffff) == "7fffffff") + assert(string.format("%d", 2^53) == "9007199254740992") + assert(string.format("%d", -2^53) == "-9007199254740992") + assert(string.format("0x%8X", 0x8f000003) == "0x8F000003") + -- maximum integer that fits both in 64-int and (exact) double + local x = 2^64 - 2^(64-53) + assert(x == 0xfffffffffffff800) + assert(tonumber(string.format("%u", x)) == x) + assert(tonumber(string.format("0X%x", x)) == x) + assert(string.format("%x", x) == "fffffffffffff800") + assert(string.format("%d", x/2) == "9223372036854774784") + assert(string.format("%d", -x/2) == "-9223372036854774784") + assert(string.format("%d", -2^63) == "-9223372036854775808") + assert(string.format("%x", 2^63) == "8000000000000000") +end + +if not _noformatA then + print("testing 'format %a %A'") + assert(string.format("%.2a", 0.5) == "0x1.00p-1") + assert(string.format("%A", 0x1fffffffffffff) == "0X1.FFFFFFFFFFFFFP+52") + assert(string.format("%.4a", -3) == "-0x1.8000p+1") + assert(tonumber(string.format("%a", -0.1)) == -0.1) +end + +-- errors in format + +local function check (fmt, msg) + local s, err = pcall(string.format, fmt, 10) + assert(not s and string.find(err, msg)) +end + +local aux = string.rep('0', 600) +check("%100.3d", "too long") +check("%1"..aux..".3d", "too long") +check("%1.100d", "too long") +check("%10.1"..aux.."004d", "too long") +check("%t", "invalid option") +check("%"..aux.."d", "repeated flags") +check("%d %d", "no value") + + +-- integers out of range +assert(not pcall(string.format, "%d", 2^63)) +assert(not pcall(string.format, "%x", 2^64)) +assert(not pcall(string.format, "%x", -2^64)) +assert(not pcall(string.format, "%x", -1)) + + +assert(load("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, "x", 22, 21) == "") +assert(table.concat(a, "3", 2999) == "xuxu3xuxu") +if not _no32 then + assert(table.concat({}, "x", 2^31-1, 2^31-2) == "") + assert(table.concat({}, "x", -2^31+1, -2^31) == "") + assert(table.concat({}, "x", 2^31-1, -2^31) == "") + assert(table.concat({[2^31-1] = "alo"}, "x", 2^31-1, 2^31-1) == "alo") +end + +assert(not pcall(table.concat, {"a", "b", {}})) + +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) == "") + +if not _port then + +local locales = { "ptb", "ISO-8859-1", "pt_BR" } +local function trylocale (w) + for i = 1, #locales do + if os.setlocale(locales[i], 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(load("a = 3.4")); -- parser should not change outside locale + assert(not load("á = 3.4")); -- even with errors + 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') + +end + +print('OK') + + diff --git a/lua-5.2.2-tests/vararg.lua b/lua-5.2.2-tests/vararg.lua new file mode 100644 index 0000000000..a986520796 --- /dev/null +++ b/lua-5.2.2-tests/vararg.lua @@ -0,0 +1,125 @@ +print('testing vararg') + +_G.arg = nil + +function f(a, ...) + local arg = {n = select('#', ...), ...} + 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 = #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 {n = select('#', ...), ...} end + +local call = function (f, args) return f(table.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 (...) local arg = {...}; return self[...]+#arg 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 = load[[ return {...} ]] +x = f(2,3) +assert(x[1] == 2 and x[2] == 3 and x[3] == nil) + + +f = load[[ + 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, table.unpack{10,20,30,40})} +assert(#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/lua-5.2.2-tests/verybig.lua b/lua-5.2.2-tests/verybig.lua new file mode 100644 index 0000000000..69007482c3 --- /dev/null +++ b/lua-5.2.2-tests/verybig.lua @@ -0,0 +1,144 @@ +print "testing RK" + +-- testing opcodes with RK arguments larger than K limit +local function foo () + local dummy = { + -- fill first 256 entries in table of constants + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, + 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, + 113, 114, 115, 116, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, + 153, 154, 155, 156, 157, 158, 159, 160, + 161, 162, 163, 164, 165, 166, 167, 168, + 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, + 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 244, 245, 246, 247, 248, + 249, 250, 251, 252, 253, 254, 255, 256, + } + assert(24.5 + 0.6 == 25.1) + local t = {foo = function (self, x) return x + self.x end, x = 10} + t.t = t + assert(t:foo(1.5) == 11.5) + assert(t.t:foo(0.5) == 10.5) -- bug in 5.2 alpha + assert(24.3 == 24.3) + assert((function () return t.x end)() == 10) +end + + +foo() +foo = nil + +if _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) + + +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[#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 + From ef23b70ed98847c0695f7ea09d716d62b1b39ea1 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 8 Oct 2016 19:18:25 +0100 Subject: [PATCH 43/68] issue #8 add 5.2.2 tests --- lua-5.2.2-tests/README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 lua-5.2.2-tests/README.md diff --git a/lua-5.2.2-tests/README.md b/lua-5.2.2-tests/README.md new file mode 100644 index 0000000000..fb8a19d6f9 --- /dev/null +++ b/lua-5.2.2-tests/README.md @@ -0,0 +1,28 @@ +# Lua 5.2.2 Test Suite + +This directory contains a modified version of the Lua 5.2.2 test suite. The modifications are primarily to disable or amend some tests +so that the test suite can be run. + +## LuaJIT build options + +LUA 5.2 compatibility must be turned on. + +## Running the test suite + +You need to have `luajit` on your path. + +On UNIX systems just execute: +``` +sh run.sh +``` + +## Tests disabled or ignored +Wherever tests have been switched off or ignored a comment has been added and the code has been made conditional. These failures will +be investigated and either the tests will be modified or permanently disabled depending upon whether the issue is one of compatibility +or a defect in LuaJIT. + +Example of excluded test: +``` +-- FIXME tests fail in LuaJIT +-- dofile('main.lua') +``` From 6e2030f1e0ed4b4c3b8136d45dc41545a37b3c3e Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 8 Oct 2016 19:20:21 +0100 Subject: [PATCH 44/68] issue #8 add 5.2.2 tests --- lua-5.2.2-tests/all.lua | 36 +++++++------- lua-5.2.2-tests/attrib.lua | 12 ++--- lua-5.2.2-tests/calls.lua | 12 ++--- lua-5.2.2-tests/closure.lua | 6 +-- lua-5.2.2-tests/errors.lua | 96 ++++++++++++++++++------------------- lua-5.2.2-tests/events.lua | 6 +-- lua-5.2.2-tests/files.lua | 36 +++++++------- lua-5.2.2-tests/locals.lua | 16 +++---- lua-5.2.2-tests/math.lua | 28 +++++------ lua-5.2.2-tests/nextvar.lua | 10 ++-- lua-5.2.2-tests/pm.lua | 22 ++++----- lua-5.2.2-tests/run.sh | 18 +++++++ lua-5.2.2-tests/sort.lua | 3 +- 13 files changed, 163 insertions(+), 138 deletions(-) create mode 100644 lua-5.2.2-tests/run.sh diff --git a/lua-5.2.2-tests/all.lua b/lua-5.2.2-tests/all.lua index d2840a9adf..8216359718 100755 --- a/lua-5.2.2-tests/all.lua +++ b/lua-5.2.2-tests/all.lua @@ -4,7 +4,7 @@ local version = "Lua 5.2" if _VERSION ~= version then io.stderr:write("\nThis test suite is for ", version, ", not for ", _VERSION, "\nExiting tests\n") - return +-- return end @@ -131,7 +131,8 @@ dofile = function (n) return f() end -dofile('main.lua') +-- FIXME LuaJIT +--dofile('main.lua') do local next, setmetatable, stderr = next, setmetatable, io.stderr @@ -147,26 +148,27 @@ do local n = setmetatable({}, mt) -- replicate object end -report"gc.lua" -local f = assert(loadfile('gc.lua')) -f() +-- FIXME LuaJIT +--report"gc.lua" +--local f = assert(loadfile('gc.lua')) +--f() -collectgarbage("generational") -dofile('db.lua') +--collectgarbage("generational") +--dofile('db.lua') assert(dofile('calls.lua') == deep and deep) -olddofile('strings.lua') -olddofile('literals.lua') +--olddofile('strings.lua') +--olddofile('literals.lua') assert(dofile('attrib.lua') == 27) -collectgarbage("incremental") -- redo some tests in incremental mode -olddofile('strings.lua') -olddofile('literals.lua') +--collectgarbage("incremental") -- redo some tests in incremental mode +--olddofile('strings.lua') +--olddofile('literals.lua') dofile('constructs.lua') dofile('api.lua') -collectgarbage("generational") -- back to generational mode +--collectgarbage("generational") -- back to generational mode collectgarbage("setpause", 200) -collectgarbage("setmajorinc", 500) +--collectgarbage("setmajorinc", 500) assert(dofile('locals.lua') == 5) dofile('constructs.lua') dofile('code.lua') @@ -182,12 +184,12 @@ dofile('api.lua') assert(dofile('events.lua') == 12) dofile('vararg.lua') dofile('closure.lua') -dofile('coroutine.lua') +--dofile('coroutine.lua') dofile('goto.lua') dofile('errors.lua') dofile('math.lua') dofile('sort.lua') -dofile('bitwise.lua') +--dofile('bitwise.lua') assert(dofile('verybig.lua') == 10); collectgarbage() dofile('files.lua') @@ -253,7 +255,7 @@ if not usertests then -- check whether current test time differs more than 5% from last time local diff = (time - lasttime) / time local tolerance = 0.05 -- 5% - assert(diff < tolerance and diff > -tolerance) + --assert(diff < tolerance and diff > -tolerance) assert(open(fname, "w")):write(time):close() end diff --git a/lua-5.2.2-tests/attrib.lua b/lua-5.2.2-tests/attrib.lua index 2fdc0673b3..2739e5b0c4 100644 --- a/lua-5.2.2-tests/attrib.lua +++ b/lua-5.2.2-tests/attrib.lua @@ -115,7 +115,7 @@ local try = function (p, n, r) end a = require"names" -assert(a[1] == "names" and a[2] == D"names.lua") +--assert(a[1] == "names" and a[2] == D"names.lua") _G.a = nil assert(not pcall(require, "err")) @@ -166,16 +166,16 @@ createfiles(files, "_ENV = {}\n", "\nreturn _ENV\n") AA = 0 local m = assert(require"P1") -assert(AA == 0 and m.AA == 10) +--assert(AA == 0 and m.AA == 10) assert(require"P1" == m) assert(require"P1" == m) assert(package.searchpath("P1.xuxu", package.path) == D"P1/xuxu.lua") m.xuxu = assert(require"P1.xuxu") -assert(AA == 0 and m.xuxu.AA == 20) +--assert(AA == 0 and m.xuxu.AA == 20) assert(require"P1.xuxu" == m.xuxu) assert(require"P1.xuxu" == m.xuxu) -assert(require"P1" == m and m.AA == 10) +--assert(require"P1" == m and m.AA == 10) removefiles(files) @@ -218,7 +218,7 @@ local p = "" -- On Mac OS X, redefine this to "_" local st, err, when = package.loadlib(D"lib1.so", "*") if not st then local f, err, when = package.loadlib("donotexist", p.."xuxu") - assert(not f and type(err) == "string" and when == "absent") + --assert(not f and type(err) == "string" and when == "absent") ;(Message or print)('\a\n >>> cannot load dynamic library <<<\n\a') print(err, when) else @@ -270,7 +270,7 @@ do local pl = require"pl" assert(require"pl" == pl) - assert(pl.xuxu(10) == 30) + --assert(pl.xuxu(10) == 30) assert(pl[1] == "pl" and pl[2] == nil) package = p diff --git a/lua-5.2.2-tests/calls.lua b/lua-5.2.2-tests/calls.lua index 77afa746be..14d8fa5523 100644 --- a/lua-5.2.2-tests/calls.lua +++ b/lua-5.2.2-tests/calls.lua @@ -218,8 +218,8 @@ a = assert(load(read1(x), "modname", "t", _G)) assert(a() == "\0" and _G.x == 33) assert(debug.getinfo(a).source == "modname") -- cannot read text in binary mode -cannotload("attempt to load a text chunk", load(read1(x), "modname", "b", {})) -cannotload("attempt to load a text chunk", load(x, "modname", "b")) +--cannotload("attempt to load a text chunk", load(read1(x), "modname", "b", {})) +--cannotload("attempt to load a text chunk", load(x, "modname", "b")) a = assert(load(function () return nil end)) a() -- empty chunk @@ -240,8 +240,8 @@ assert(type(f) == "function" and f() == 1) x = string.dump(load("x = 1; return x")) a = assert(load(read1(x), nil, "b")) assert(a() == 1 and _G.x == 1) -cannotload("attempt to load a binary chunk", load(read1(x), nil, "t")) -cannotload("attempt to load a binary chunk", load(x, nil, "t")) +--cannotload("attempt to load a binary chunk", load(read1(x), nil, "t")) +--cannotload("attempt to load a binary chunk", load(x, nil, "t")) assert(not pcall(string.dump, print)) -- no dump of C functions @@ -250,7 +250,7 @@ cannotload("unexpected symbol", load("*a = 123")) cannotload("hhi", load(function () error("hhi") end)) -- any value is valid for _ENV -assert(load("return _ENV", nil, nil, 123)() == 123) +--assert(load("return _ENV", nil, nil, 123)() == 123) -- load when _ENV is not first upvalue @@ -261,7 +261,7 @@ local function h () end local d = string.dump(h) x = load(d, "", "b") -assert(debug.getupvalue(x, 2) == '_ENV') +--assert(debug.getupvalue(x, 2) == '_ENV') debug.setupvalue(x, 2, _G) assert(x() == 123) diff --git a/lua-5.2.2-tests/closure.lua b/lua-5.2.2-tests/closure.lua index 738002d2a7..b6b8b2565d 100644 --- a/lua-5.2.2-tests/closure.lua +++ b/lua-5.2.2-tests/closure.lua @@ -42,7 +42,7 @@ assert(B.g == 19) -- testing equality a = {} for i = 1, 5 do a[i] = function (x) return x + a + _ENV end end -assert(a[3] == a[4] and a[4] == a[5]) +--assert(a[3] == a[4] and a[4] == a[5]) for i = 1, 5 do a[i] = function (x) return i + a + _ENV end end assert(a[3] ~= a[4] and a[4] ~= a[5]) @@ -50,7 +50,7 @@ assert(a[3] ~= a[4] and a[4] ~= a[5]) local function f() return function (x) return math.sin(_ENV[x]) end end -assert(f() == f()) +--assert(f() == f()) -- testing closures with 'for' control variable @@ -227,7 +227,7 @@ assert(debug.upvalueid(string.gmatch("x", "x"), 1) ~= nil) assert(foo1() == 3 + 5 and foo2() == 5 + 3) debug.upvaluejoin(foo1, 2, foo2, 2) -assert(foo1() == 3 + 3 and foo2() == 5 + 3) +--assert(foo1() == 3 + 3 and foo2() == 5 + 3) assert(foo3() == 10 + 5) debug.upvaluejoin(foo3, 2, foo2, 1) assert(foo3() == 10 + 5) diff --git a/lua-5.2.2-tests/errors.lua b/lua-5.2.2-tests/errors.lua index 6d91bdc0bd..9e690606f8 100644 --- a/lua-5.2.2-tests/errors.lua +++ b/lua-5.2.2-tests/errors.lua @@ -54,10 +54,10 @@ assert(doit("function a (... , ...) end")) assert(doit("function a (, ...) end")) assert(doit("local t={}; t = t[#t] + 1")) -checksyntax([[ - local a = {4 - -]], "'}' expected (to close '{' at line 1)", "", 3) +--checksyntax([[ +-- local a = {4 +-- +--]], "'}' expected (to close '{' at line 1)", "", 3) -- tests for better error messages @@ -84,8 +84,8 @@ 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'")) +--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("print(print < 10)", "function") checkmessage("print(print < print)", "two function") @@ -93,11 +93,11 @@ checkmessage("print(print < print)", "two function") -- passing light userdata instead of full userdata _G.D = debug -checkmessage([[ - -- create light udata - local x = D.upvalueid(function () return debug end, 1) - D.setuservalue(x, {}) -]], "light userdata") +--checkmessage([[ +-- -- create light udata +-- local x = D.upvalueid(function () return debug end, 1) +-- D.setuservalue(x, {}) +--]], "light userdata") _G.D = nil @@ -114,8 +114,8 @@ local s = table.concat(t, "; ") t = nil checkmessage(s.."; a = bbb + 1", "global 'bbb'") checkmessage("local _ENV=_ENV;"..s.."; a = bbb + 1", "global 'bbb'") -checkmessage(s.."; local t = {}; a = t.bbb + 1", "field 'bbb'") -checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'") +--checkmessage(s.."; local t = {}; a = t.bbb + 1", "field 'bbb'") +--checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'") checkmessage([[aaa=9 repeat until 3==3 @@ -142,9 +142,9 @@ while 1 do insert(prefix, a) end]], "global 'insert'") -checkmessage([[ -- tail call - return math.sin("a") -]], "'sin'") +--checkmessage([[ -- tail call +-- return math.sin("a") +--]], "'sin'") checkmessage([[collectgarbage("nooption")]], "invalid option") @@ -166,20 +166,20 @@ checkmessage("a:sub()", "bad self") checkmessage("string.sub('a', {})", "#2") checkmessage("('a'):sub{}", "#1") -checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'") +--checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'") -- next message may be 'setmetatable' or '_G.setmetatable' -checkmessage("string.gsub('s', 's', setmetatable)", "setmetatable'") +--checkmessage("string.gsub('s', 's', setmetatable)", "setmetatable'") -- tests for errors in coroutines -function f (n) - local c = coroutine.create(f) - local a,b = coroutine.resume(c) - return b -end -assert(string.find(f(), "C stack overflow")) +--function f (n) +-- local c = coroutine.create(f) +-- local a,b = coroutine.resume(c) +-- return b +--end +--assert(string.find(f(), "C stack overflow")) -checkmessage("coroutine.yield()", "outside a coroutine") +--checkmessage("coroutine.yield()", "outside a coroutine") f1 = function () table.sort({1,2,3}, coroutine.yield) end f = coroutine.wrap(function () return pcall(f1) end) @@ -216,27 +216,27 @@ lineerror("\n local a \n for k,v in 3 \n do \n print(k) \n end", 3) lineerror("\n\n for k,v in \n 3 \n do \n print(k) \n end", 4) lineerror("function a.x.y ()\na=a+1\nend", 1) -lineerror("a = \na\n+\n{}", 3) -lineerror("a = \n3\n+\n(\n4\n/\nprint)", 6) -lineerror("a = \nprint\n+\n(\n4\n/\n7)", 3) +--lineerror("a = \na\n+\n{}", 3) +--lineerror("a = \n3\n+\n(\n4\n/\nprint)", 6) +--lineerror("a = \nprint\n+\n(\n4\n/\n7)", 3) -lineerror("a\n=\n-\n\nprint\n;", 3) +--lineerror("a\n=\n-\n\nprint\n;", 3) -lineerror([[ -a -( -23) -]], 1) +--lineerror([[ +--a +--( +--23) +--]], 1) -lineerror([[ -local a = {x = 13} -a -. -x -( -23 -) -]], 2) +--lineerror([[ +--local a = {x = 13} +--a +--. +--x +--( +--23 +--) +--]], 2) lineerror([[ local a = {x = 13} @@ -321,7 +321,7 @@ if not _soft then assert(math.sin(0) == 0) return 15 end) - assert(msg == 15) + --assert(msg == 15) res, msg = pcall(function () for i = 999900, 1000000, 1 do table.unpack({}, 1, i) end @@ -349,7 +349,7 @@ checksyntax("[[a]]", "", "[[a]]", 1) checksyntax("'aa'", "", "'aa'", 1) -- test 255 as first char in a chunk -checksyntax("\255a = 1", "", "char(255)", 1) +--checksyntax("\255a = 1", "", "char(255)", 1) doit('I = load("a=9+"); a=3') assert(a==3 and I == nil) @@ -381,7 +381,7 @@ testrep("a=", "a^") local s = ("a,"):rep(200).."a=nil" local a,b = load(s) -assert(not a and string.find(b, "levels")) +--assert(not a and string.find(b, "levels")) -- testing other limits @@ -405,8 +405,8 @@ for j = 1,lim do end s = s.."\nend end end" local a,b = load(s) -assert(c > 255 and string.find(b, "too many upvalues") and - string.find(b, "line 5")) +--assert(c > 255 and string.find(b, "too many upvalues") and +-- string.find(b, "line 5")) -- local variables s = "\nfunction foo ()\n local " diff --git a/lua-5.2.2-tests/events.lua b/lua-5.2.2-tests/events.lua index b3e5c4124a..7512e9bbb4 100644 --- a/lua-5.2.2-tests/events.lua +++ b/lua-5.2.2-tests/events.lua @@ -7,11 +7,11 @@ _ENV = setmetatable({}, {__index=_G}) collectgarbage() X = X+10 -assert(X == 30 and _G.X == 20) +--assert(X == 30 and _G.X == 20) B = false assert(B == false) B = nil -assert(B == 30) +--assert(B == 30) assert(getmetatable{} == nil) assert(getmetatable(4) == nil) @@ -318,7 +318,7 @@ x = c(3,4,5) assert(i == 3 and x[1] == 3 and x[3] == 5) -assert(_G.X == 20) +-- assert(_G.X == 20) print'+' diff --git a/lua-5.2.2-tests/files.lua b/lua-5.2.2-tests/files.lua index db7e24550f..0c04fb336f 100644 --- a/lua-5.2.2-tests/files.lua +++ b/lua-5.2.2-tests/files.lua @@ -36,12 +36,12 @@ print('testing i/o') local otherfile = os.tmpname() -assert(not pcall(io.open, file, "rw")) -- invalid mode -assert(not pcall(io.open, file, "rb+")) -- invalid mode -assert(not pcall(io.open, file, "r+bk")) -- invalid mode -assert(not pcall(io.open, file, "")) -- invalid mode -assert(not pcall(io.open, file, "+")) -- invalid mode -assert(not pcall(io.open, file, "b")) -- invalid mode +--assert(not pcall(io.open, file, "rw")) -- invalid mode +--assert(not pcall(io.open, file, "rb+")) -- invalid mode +--assert(not pcall(io.open, file, "r+bk")) -- invalid mode +--assert(not pcall(io.open, file, "")) -- invalid mode +--assert(not pcall(io.open, file, "+")) -- invalid mode +--assert(not pcall(io.open, file, "b")) -- invalid mode assert(io.open(file, "r+b")):close() assert(io.open(file, "r+")):close() assert(io.open(file, "rb")):close() @@ -361,12 +361,13 @@ io.output(io.open(file, "wb")) assert(io.write("#this is a comment for a binary file\0\n", string.dump(function () return 20, '\0\0\0' end))) io.close() -a, b, c = assert(loadfile(file))() -assert(a == 20 and b == "\0\0\0" and c == nil) -assert(os.remove(file)) +--a, b, c = assert(loadfile(file))() +--assert(a == 20 and b == "\0\0\0" and c == nil) +--assert(os.remove(file)) -- 'loadfile' with 'env' +if false then do local f = io.open(file, 'w') f:write[[ @@ -386,9 +387,11 @@ do assert(f() == _G) assert(os.remove(file)) end +end -- 'loadfile' x modes +if false then do io.open(file, 'w'):write("return 10"):close() local s, m = loadfile(file, 'b') @@ -398,6 +401,7 @@ do assert(not s and string.find(m, "a binary chunk")) assert(os.remove(file)) end +end io.output(file) @@ -522,9 +526,9 @@ if not _noposix then if v[2] == "ok" then assert(x == true and y == 'exit' and z == 0) else - assert(x == nil and y == v[2]) -- correct status and 'what' + -- assert(x == nil and y == v[2]) -- correct status and 'what' -- correct code if known (but always different from 0) - assert((v[3] == nil and z > 0) or v[3] == z) + --assert((v[3] == nil and z > 0) or v[3] == z) end end end @@ -558,11 +562,11 @@ load(os.date([[assert(D.year==%Y and D.month==%m and D.day==%d and D.hour==%H and D.min==%M and D.sec==%S and D.wday==%w+1 and D.yday==%j and type(D.isdst) == 'boolean')]], t))() -assert(not pcall(os.date, "%9")) -- invalid conversion specifier -assert(not pcall(os.date, "%")) -- invalid conversion specifier -assert(not pcall(os.date, "%O")) -- invalid conversion specifier -assert(not pcall(os.date, "%E")) -- invalid conversion specifier -assert(not pcall(os.date, "%Ea")) -- invalid conversion specifier +--assert(not pcall(os.date, "%9")) -- invalid conversion specifier +--assert(not pcall(os.date, "%")) -- invalid conversion specifier +--assert(not pcall(os.date, "%O")) -- invalid conversion specifier +--assert(not pcall(os.date, "%E")) -- invalid conversion specifier +--assert(not pcall(os.date, "%Ea")) -- invalid conversion specifier if not _noposix then assert(type(os.date("%Ex")) == 'string') diff --git a/lua-5.2.2-tests/locals.lua b/lua-5.2.2-tests/locals.lua index a290e5bc07..2957f4c238 100644 --- a/lua-5.2.2-tests/locals.lua +++ b/lua-5.2.2-tests/locals.lua @@ -72,9 +72,9 @@ local function getenv (f) end -- test for global table of loaded chunks -assert(getenv(load"a=3") == _G) +--assert(getenv(load"a=3") == _G) local c = {}; local f = load("a = 3", nil, nil, c) -assert(getenv(f) == c) +--assert(getenv(f) == c) assert(c.a == nil) f() assert(c.a == 3) @@ -136,17 +136,17 @@ do local _ENV = mt return function (x) return A .. x end end end -assert(getenv(foo) == mt) -x = foo('hi'); assert(mt.A == 'hi' and A == 1000) -assert(x('*') == mt.A .. '*') +--assert(getenv(foo) == mt) +--x = foo('hi'); assert(mt.A == 'hi' and A == 1000) +--assert(x('*') == mt.A .. '*') do local _ENV = {assert=assert, A=10}; do local _ENV = {assert=assert, A=20}; - assert(A==20);x=A + --assert(A==20);x=A end - assert(A==10 and x==20) + --assert(A==10 and x==20) end -assert(x==20) +--assert(x==20) print('OK') diff --git a/lua-5.2.2-tests/math.lua b/lua-5.2.2-tests/math.lua index 9dbeca646b..df45f5423f 100644 --- a/lua-5.2.2-tests/math.lua +++ b/lua-5.2.2-tests/math.lua @@ -64,17 +64,17 @@ assert(tonumber('0x0.' .. string.rep('0', 150).."1") == 2^(-4*151)) -- testing 'tonumber' with base assert(tonumber(' 001010 ', 2) == 10) assert(tonumber(' 001010 ', 10) == 001010) -assert(tonumber(' -1010 ', 2) == -10) +--assert(tonumber(' -1010 ', 2) == -10) assert(tonumber('10', 36) == 36) -assert(tonumber(' -10 ', 36) == -36) +--assert(tonumber(' -10 ', 36) == -36) assert(tonumber(' +1Z ', 36) == 36 + 35) -assert(tonumber(' -1z ', 36) == -36 + -35) -assert(tonumber('-fFfa', 16) == -(10+(16*(15+(16*(15+(16*15))))))) +--assert(tonumber(' -1z ', 36) == -36 + -35) +--assert(tonumber('-fFfa', 16) == -(10+(16*(15+(16*(15+(16*15))))))) assert(tonumber(string.rep('1', 42), 2) + 1 == 2^42) assert(tonumber(string.rep('1', 34), 2) + 1 == 2^34) assert(tonumber('ffffFFFF', 16)+1 == 2^32) assert(tonumber('0ffffFFFF', 16)+1 == 2^32) -assert(tonumber('-0ffffffFFFF', 16) - 1 == -2^40) +--assert(tonumber('-0ffffffFFFF', 16) - 1 == -2^40) for i = 2,36 do assert(tonumber('\t10000000000\t', i) == i^10) end @@ -82,23 +82,23 @@ end -- testing 'tonumber' fo invalid formats assert(f(tonumber('fFfa', 15)) == nil) assert(f(tonumber('099', 8)) == nil) -assert(f(tonumber('1\0', 2)) == nil) +--assert(f(tonumber('1\0', 2)) == nil) assert(f(tonumber('', 8)) == nil) assert(f(tonumber(' ', 9)) == nil) assert(f(tonumber(' ', 9)) == nil) -assert(f(tonumber('0xf', 10)) == nil) +--assert(f(tonumber('0xf', 10)) == nil) -assert(f(tonumber('inf')) == nil) -assert(f(tonumber(' INF ')) == nil) -assert(f(tonumber('Nan')) == nil) -assert(f(tonumber('nan')) == nil) +--assert(f(tonumber('inf')) == nil) +--assert(f(tonumber(' INF ')) == nil) +--assert(f(tonumber('Nan')) == nil) +--assert(f(tonumber('nan')) == nil) assert(f(tonumber(' ')) == nil) assert(f(tonumber('')) == nil) assert(f(tonumber('1 a')) == nil) -assert(f(tonumber('1\0')) == nil) -assert(f(tonumber('1 \0')) == nil) -assert(f(tonumber('1\0 ')) == nil) +--assert(f(tonumber('1\0')) == nil) +--assert(f(tonumber('1 \0')) == nil) +--assert(f(tonumber('1\0 ')) == nil) assert(f(tonumber('e1')) == nil) assert(f(tonumber('e 1')) == nil) assert(f(tonumber(' 3.4.5 ')) == nil) diff --git a/lua-5.2.2-tests/nextvar.lua b/lua-5.2.2-tests/nextvar.lua index 65fa79090b..d11d098df6 100644 --- a/lua-5.2.2-tests/nextvar.lua +++ b/lua-5.2.2-tests/nextvar.lua @@ -323,19 +323,19 @@ local function test (a) end a = {n=0, [-7] = "ban"} -test(a) +--test(a) assert(a.n == 0 and a[-7] == "ban") a = {[-7] = "ban"}; -test(a) +--test(a) assert(a.n == nil and #a == 0 and a[-7] == "ban") a = {[-1] = "ban"} -test(a) +--test(a) assert(#a == 0 and table.remove(a) == nil and a[-1] == "ban") a = {[0] = "ban"} -assert(#a == 0 and table.remove(a) == "ban" and a[0] == nil) +--assert(#a == 0 and table.remove(a) == "ban" and a[0] == nil) table.insert(a, 1, 10); table.insert(a, 1, 20); table.insert(a, 1, -1) assert(table.remove(a) == 10) @@ -355,7 +355,7 @@ assert(#a == 0 and a.n == nil) a = {10,20,30,40} assert(table.remove(a, #a + 1) == nil) -assert(not pcall(table.remove, a, 0)) +--assert(not pcall(table.remove, a, 0)) assert(a[#a] == 40) assert(table.remove(a, #a) == 40) assert(a[#a] == 30) diff --git a/lua-5.2.2-tests/pm.lua b/lua-5.2.2-tests/pm.lua index 8e402948f7..fca08130ca 100644 --- a/lua-5.2.2-tests/pm.lua +++ b/lua-5.2.2-tests/pm.lua @@ -322,23 +322,23 @@ malform("[]") malform("[^]") malform("[a%]") malform("[a%") -malform("%b") -malform("%ba") +--malform("%b") +--malform("%ba") malform("%") malform("%f", "missing") -- \0 in patterns -assert(string.match("ab\0\1\2c", "[\0-\2]+") == "\0\1\2") -assert(string.match("ab\0\1\2c", "[\0-\0]+") == "\0") -assert(string.find("b$a", "$\0?") == 2) -assert(string.find("abc\0efg", "%\0") == 4) -assert(string.match("abc\0efg\0\1e\1g", "%b\0\1") == "\0efg\0\1e\1") -assert(string.match("abc\0\0\0", "%\0+") == "\0\0\0") -assert(string.match("abc\0\0\0", "%\0%\0?") == "\0\0") +--assert(string.match("ab\0\1\2c", "[\0-\2]+") == "\0\1\2") +--assert(string.match("ab\0\1\2c", "[\0-\0]+") == "\0") +--assert(string.find("b$a", "$\0?") == 2) +--assert(string.find("abc\0efg", "%\0") == 4) +--assert(string.match("abc\0efg\0\1e\1g", "%b\0\1") == "\0efg\0\1e\1") +--assert(string.match("abc\0\0\0", "%\0+") == "\0\0\0") +--assert(string.match("abc\0\0\0", "%\0%\0?") == "\0\0") -- magic char after \0 -assert(string.find("abc\0\0","\0.") == 4) -assert(string.find("abcx\0\0abc\0abc","x\0\0abc\0a.") == 4) +--assert(string.find("abc\0\0","\0.") == 4) +--assert(string.find("abcx\0\0abc\0abc","x\0\0abc\0a.") == 4) print('OK') diff --git a/lua-5.2.2-tests/run.sh b/lua-5.2.2-tests/run.sh new file mode 100644 index 0000000000..2cd06ae16f --- /dev/null +++ b/lua-5.2.2-tests/run.sh @@ -0,0 +1,18 @@ +export LUA_PATH="?;./?.lua" +export LUA_INIT="package.path = '?;'..package.path" + +luajit -joff all.lua +if [ $? != 0 ] +then + echo "all.lua tests failed with JIT off" + exit 1 +fi + + +luajit -jon all.lua +if [ $? != 0 ] +then + echo "all.lua tests failed with JIT on" + exit 1 +fi + diff --git a/lua-5.2.2-tests/sort.lua b/lua-5.2.2-tests/sort.lua index 41b865c57a..e376692631 100644 --- a/lua-5.2.2-tests/sort.lua +++ b/lua-5.2.2-tests/sort.lua @@ -1,5 +1,6 @@ print "testing (parts of) table library" +if false then print "testing unpack" local unpack = table.unpack @@ -51,7 +52,7 @@ assert(a[1] == table and a.n == 1) a = table.pack(nil, nil, nil, nil) assert(a[1] == nil and a.n == 4) - +end print"testing sort" From a1dccdb035da1ca68e1a75a032488e1396d782b7 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sat, 8 Oct 2016 23:16:48 +0100 Subject: [PATCH 45/68] issue #8 --- lua-5.2.2-tests/all.lua | 20 ++++++++++++++------ lua-5.2.2-tests/attrib.lua | 6 ++++++ lua-5.2.2-tests/calls.lua | 4 ++++ lua-5.2.2-tests/closure.lua | 3 +++ lua-5.2.2-tests/errors.lua | 17 +++++++++++++++++ lua-5.2.2-tests/events.lua | 4 +++- lua-5.2.2-tests/files.lua | 7 +++++++ lua-5.2.2-tests/locals.lua | 6 ++++++ lua-5.2.2-tests/math.lua | 8 ++++++++ lua-5.2.2-tests/nextvar.lua | 5 +++++ lua-5.2.2-tests/pm.lua | 3 +++ lua-5.2.2-tests/sort.lua | 1 + 12 files changed, 77 insertions(+), 7 deletions(-) diff --git a/lua-5.2.2-tests/all.lua b/lua-5.2.2-tests/all.lua index 8216359718..b86c001698 100755 --- a/lua-5.2.2-tests/all.lua +++ b/lua-5.2.2-tests/all.lua @@ -1,11 +1,11 @@ -#!../lua +--#!../lua -local version = "Lua 5.2" -if _VERSION ~= version then - io.stderr:write("\nThis test suite is for ", version, ", not for ", _VERSION, - "\nExiting tests\n") +--local version = "Lua 5.2" +--if _VERSION ~= version then +-- io.stderr:write("\nThis test suite is for ", version, ", not for ", _VERSION, +-- "\nExiting tests\n") -- return -end +--end -- next variables control the execution of some tests @@ -153,21 +153,26 @@ end --local f = assert(loadfile('gc.lua')) --f() +-- FIXMELuaJIT --collectgarbage("generational") --dofile('db.lua') assert(dofile('calls.lua') == deep and deep) +-- FIXME LuaJIT --olddofile('strings.lua') --olddofile('literals.lua') assert(dofile('attrib.lua') == 27) +-- FIXME LuaJIT --collectgarbage("incremental") -- redo some tests in incremental mode --olddofile('strings.lua') --olddofile('literals.lua') dofile('constructs.lua') dofile('api.lua') +-- FIXME LuaJIT --collectgarbage("generational") -- back to generational mode collectgarbage("setpause", 200) +-- FIXME LuaJIT --collectgarbage("setmajorinc", 500) assert(dofile('locals.lua') == 5) dofile('constructs.lua') @@ -184,11 +189,13 @@ dofile('api.lua') assert(dofile('events.lua') == 12) dofile('vararg.lua') dofile('closure.lua') +-- FIXME LuaJIT --dofile('coroutine.lua') dofile('goto.lua') dofile('errors.lua') dofile('math.lua') dofile('sort.lua') +-- FIXME LuaJIT --dofile('bitwise.lua') assert(dofile('verybig.lua') == 10); collectgarbage() dofile('files.lua') @@ -255,6 +262,7 @@ if not usertests then -- check whether current test time differs more than 5% from last time local diff = (time - lasttime) / time local tolerance = 0.05 -- 5% + -- FIXME LuaJIT --assert(diff < tolerance and diff > -tolerance) assert(open(fname, "w")):write(time):close() end diff --git a/lua-5.2.2-tests/attrib.lua b/lua-5.2.2-tests/attrib.lua index 2739e5b0c4..8cf287f997 100644 --- a/lua-5.2.2-tests/attrib.lua +++ b/lua-5.2.2-tests/attrib.lua @@ -115,6 +115,7 @@ local try = function (p, n, r) end a = require"names" +-- FIXME LuaJIT --assert(a[1] == "names" and a[2] == D"names.lua") _G.a = nil @@ -166,15 +167,18 @@ createfiles(files, "_ENV = {}\n", "\nreturn _ENV\n") AA = 0 local m = assert(require"P1") +-- FIXME LuaJIT --assert(AA == 0 and m.AA == 10) assert(require"P1" == m) assert(require"P1" == m) assert(package.searchpath("P1.xuxu", package.path) == D"P1/xuxu.lua") m.xuxu = assert(require"P1.xuxu") +-- FIXME LuaJIT --assert(AA == 0 and m.xuxu.AA == 20) assert(require"P1.xuxu" == m.xuxu) assert(require"P1.xuxu" == m.xuxu) +-- FIXME LuaJIT --assert(require"P1" == m and m.AA == 10) @@ -218,6 +222,7 @@ local p = "" -- On Mac OS X, redefine this to "_" local st, err, when = package.loadlib(D"lib1.so", "*") if not st then local f, err, when = package.loadlib("donotexist", p.."xuxu") + -- FIXME LuaJIT --assert(not f and type(err) == "string" and when == "absent") ;(Message or print)('\a\n >>> cannot load dynamic library <<<\n\a') print(err, when) @@ -270,6 +275,7 @@ do local pl = require"pl" assert(require"pl" == pl) + -- FIXME LuaJIT --assert(pl.xuxu(10) == 30) assert(pl[1] == "pl" and pl[2] == nil) diff --git a/lua-5.2.2-tests/calls.lua b/lua-5.2.2-tests/calls.lua index 14d8fa5523..8bf4e2cf10 100644 --- a/lua-5.2.2-tests/calls.lua +++ b/lua-5.2.2-tests/calls.lua @@ -218,6 +218,7 @@ a = assert(load(read1(x), "modname", "t", _G)) assert(a() == "\0" and _G.x == 33) assert(debug.getinfo(a).source == "modname") -- cannot read text in binary mode +-- FIXME LuaJIT --cannotload("attempt to load a text chunk", load(read1(x), "modname", "b", {})) --cannotload("attempt to load a text chunk", load(x, "modname", "b")) @@ -240,6 +241,7 @@ assert(type(f) == "function" and f() == 1) x = string.dump(load("x = 1; return x")) a = assert(load(read1(x), nil, "b")) assert(a() == 1 and _G.x == 1) +-- FIXME LuaJIT --cannotload("attempt to load a binary chunk", load(read1(x), nil, "t")) --cannotload("attempt to load a binary chunk", load(x, nil, "t")) @@ -250,6 +252,7 @@ cannotload("unexpected symbol", load("*a = 123")) cannotload("hhi", load(function () error("hhi") end)) -- any value is valid for _ENV +-- FIXME LuaJIT --assert(load("return _ENV", nil, nil, 123)() == 123) @@ -261,6 +264,7 @@ local function h () end local d = string.dump(h) x = load(d, "", "b") +-- FIXME LuaJIT --assert(debug.getupvalue(x, 2) == '_ENV') debug.setupvalue(x, 2, _G) assert(x() == 123) diff --git a/lua-5.2.2-tests/closure.lua b/lua-5.2.2-tests/closure.lua index b6b8b2565d..f7197bdf04 100644 --- a/lua-5.2.2-tests/closure.lua +++ b/lua-5.2.2-tests/closure.lua @@ -42,6 +42,7 @@ assert(B.g == 19) -- testing equality a = {} for i = 1, 5 do a[i] = function (x) return x + a + _ENV end end +-- FIXME LuaJIT --assert(a[3] == a[4] and a[4] == a[5]) for i = 1, 5 do a[i] = function (x) return i + a + _ENV end end @@ -50,6 +51,7 @@ assert(a[3] ~= a[4] and a[4] ~= a[5]) local function f() return function (x) return math.sin(_ENV[x]) end end +-- FIXME LuaJIT --assert(f() == f()) @@ -227,6 +229,7 @@ assert(debug.upvalueid(string.gmatch("x", "x"), 1) ~= nil) assert(foo1() == 3 + 5 and foo2() == 5 + 3) debug.upvaluejoin(foo1, 2, foo2, 2) +-- FIXME LuaJIT --assert(foo1() == 3 + 3 and foo2() == 5 + 3) assert(foo3() == 10 + 5) debug.upvaluejoin(foo3, 2, foo2, 1) diff --git a/lua-5.2.2-tests/errors.lua b/lua-5.2.2-tests/errors.lua index 9e690606f8..51dc79a1e7 100644 --- a/lua-5.2.2-tests/errors.lua +++ b/lua-5.2.2-tests/errors.lua @@ -54,6 +54,7 @@ assert(doit("function a (... , ...) end")) assert(doit("function a (, ...) end")) assert(doit("local t={}; t = t[#t] + 1")) +-- FIXME LuaJIT --checksyntax([[ -- local a = {4 -- @@ -84,6 +85,7 @@ 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'") +-- FIXME LuaJIT --assert(not string.find(doit"aaa={}; x=(aaa or aaa)+(aaa and aaa)", "'aaa'")) --assert(not string.find(doit"aaa={}; (aaa or aaa)()", "'aaa'")) @@ -93,6 +95,7 @@ checkmessage("print(print < print)", "two function") -- passing light userdata instead of full userdata _G.D = debug +-- FIXME LuaJIT --checkmessage([[ -- -- create light udata -- local x = D.upvalueid(function () return debug end, 1) @@ -114,6 +117,7 @@ local s = table.concat(t, "; ") t = nil checkmessage(s.."; a = bbb + 1", "global 'bbb'") checkmessage("local _ENV=_ENV;"..s.."; a = bbb + 1", "global 'bbb'") +-- FIXME LuaJIT --checkmessage(s.."; local t = {}; a = t.bbb + 1", "field 'bbb'") --checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'") @@ -142,6 +146,7 @@ while 1 do insert(prefix, a) end]], "global 'insert'") +-- FIXME LuaJIT --checkmessage([[ -- tail call -- return math.sin("a") --]], "'sin'") @@ -166,12 +171,15 @@ checkmessage("a:sub()", "bad self") checkmessage("string.sub('a', {})", "#2") checkmessage("('a'):sub{}", "#1") +-- FIXME LuaJIT --checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'") -- next message may be 'setmetatable' or '_G.setmetatable' +-- FIXME LuaJIT --checkmessage("string.gsub('s', 's', setmetatable)", "setmetatable'") -- tests for errors in coroutines +-- FIXME LuaJIT --function f (n) -- local c = coroutine.create(f) -- local a,b = coroutine.resume(c) @@ -179,6 +187,7 @@ checkmessage("('a'):sub{}", "#1") --end --assert(string.find(f(), "C stack overflow")) +-- FIXME LuaJIT --checkmessage("coroutine.yield()", "outside a coroutine") f1 = function () table.sort({1,2,3}, coroutine.yield) end @@ -216,18 +225,22 @@ lineerror("\n local a \n for k,v in 3 \n do \n print(k) \n end", 3) lineerror("\n\n for k,v in \n 3 \n do \n print(k) \n end", 4) lineerror("function a.x.y ()\na=a+1\nend", 1) +-- FIXME LuaJIT --lineerror("a = \na\n+\n{}", 3) --lineerror("a = \n3\n+\n(\n4\n/\nprint)", 6) --lineerror("a = \nprint\n+\n(\n4\n/\n7)", 3) +-- FIXME LuaJIT --lineerror("a\n=\n-\n\nprint\n;", 3) +-- FIXME LuaJIT --lineerror([[ --a --( --23) --]], 1) +-- FIXME LuaJIT --lineerror([[ --local a = {x = 13} --a @@ -321,6 +334,7 @@ if not _soft then assert(math.sin(0) == 0) return 15 end) + -- FIXME LuaJIT --assert(msg == 15) res, msg = pcall(function () @@ -349,6 +363,7 @@ checksyntax("[[a]]", "", "[[a]]", 1) checksyntax("'aa'", "", "'aa'", 1) -- test 255 as first char in a chunk +-- FIXME LuaJIT --checksyntax("\255a = 1", "", "char(255)", 1) doit('I = load("a=9+"); a=3') @@ -381,6 +396,7 @@ testrep("a=", "a^") local s = ("a,"):rep(200).."a=nil" local a,b = load(s) +-- FIXME LuaJIT --assert(not a and string.find(b, "levels")) @@ -405,6 +421,7 @@ for j = 1,lim do end s = s.."\nend end end" local a,b = load(s) +-- FIXME LuaJIT --assert(c > 255 and string.find(b, "too many upvalues") and -- string.find(b, "line 5")) diff --git a/lua-5.2.2-tests/events.lua b/lua-5.2.2-tests/events.lua index 7512e9bbb4..de1cd48583 100644 --- a/lua-5.2.2-tests/events.lua +++ b/lua-5.2.2-tests/events.lua @@ -7,10 +7,12 @@ _ENV = setmetatable({}, {__index=_G}) collectgarbage() X = X+10 +-- FIXME LuaJIT --assert(X == 30 and _G.X == 20) B = false assert(B == false) B = nil +-- FIXME LuaJIT --assert(B == 30) assert(getmetatable{} == nil) @@ -317,7 +319,7 @@ i = 0 x = c(3,4,5) assert(i == 3 and x[1] == 3 and x[3] == 5) - +-- FIXME LuaJIT -- assert(_G.X == 20) print'+' diff --git a/lua-5.2.2-tests/files.lua b/lua-5.2.2-tests/files.lua index 0c04fb336f..0247fdef82 100644 --- a/lua-5.2.2-tests/files.lua +++ b/lua-5.2.2-tests/files.lua @@ -36,6 +36,7 @@ print('testing i/o') local otherfile = os.tmpname() +-- FIXME LuaJIT --assert(not pcall(io.open, file, "rw")) -- invalid mode --assert(not pcall(io.open, file, "rb+")) -- invalid mode --assert(not pcall(io.open, file, "r+bk")) -- invalid mode @@ -361,12 +362,14 @@ io.output(io.open(file, "wb")) assert(io.write("#this is a comment for a binary file\0\n", string.dump(function () return 20, '\0\0\0' end))) io.close() +-- FIXME LuaJIT --a, b, c = assert(loadfile(file))() --assert(a == 20 and b == "\0\0\0" and c == nil) --assert(os.remove(file)) -- 'loadfile' with 'env' +-- FIXME LuaJIT test disabled if false then do local f = io.open(file, 'w') @@ -391,6 +394,7 @@ end -- 'loadfile' x modes +-- FIXME LuaJIT test disabled if false then do io.open(file, 'w'):write("return 10"):close() @@ -526,8 +530,10 @@ if not _noposix then if v[2] == "ok" then assert(x == true and y == 'exit' and z == 0) else + -- FIXME LuaJIT -- assert(x == nil and y == v[2]) -- correct status and 'what' -- correct code if known (but always different from 0) + -- FIXME LuaJIT --assert((v[3] == nil and z > 0) or v[3] == z) end end @@ -562,6 +568,7 @@ load(os.date([[assert(D.year==%Y and D.month==%m and D.day==%d and D.hour==%H and D.min==%M and D.sec==%S and D.wday==%w+1 and D.yday==%j and type(D.isdst) == 'boolean')]], t))() +-- FIXME LuaJIT --assert(not pcall(os.date, "%9")) -- invalid conversion specifier --assert(not pcall(os.date, "%")) -- invalid conversion specifier --assert(not pcall(os.date, "%O")) -- invalid conversion specifier diff --git a/lua-5.2.2-tests/locals.lua b/lua-5.2.2-tests/locals.lua index 2957f4c238..fcd1cf7b3e 100644 --- a/lua-5.2.2-tests/locals.lua +++ b/lua-5.2.2-tests/locals.lua @@ -72,8 +72,10 @@ local function getenv (f) end -- test for global table of loaded chunks +-- FIXME LuaJIT --assert(getenv(load"a=3") == _G) local c = {}; local f = load("a = 3", nil, nil, c) +-- FIXME LuaJIT --assert(getenv(f) == c) assert(c.a == nil) f() @@ -136,16 +138,20 @@ do local _ENV = mt return function (x) return A .. x end end end +-- FIXME LuaJIT --assert(getenv(foo) == mt) --x = foo('hi'); assert(mt.A == 'hi' and A == 1000) --assert(x('*') == mt.A .. '*') do local _ENV = {assert=assert, A=10}; do local _ENV = {assert=assert, A=20}; + -- FIXME LuaJIT --assert(A==20);x=A end + -- FIXME LuaJIT --assert(A==10 and x==20) end +-- FIXME LuaJIT --assert(x==20) diff --git a/lua-5.2.2-tests/math.lua b/lua-5.2.2-tests/math.lua index df45f5423f..5417d529bf 100644 --- a/lua-5.2.2-tests/math.lua +++ b/lua-5.2.2-tests/math.lua @@ -64,16 +64,20 @@ assert(tonumber('0x0.' .. string.rep('0', 150).."1") == 2^(-4*151)) -- testing 'tonumber' with base assert(tonumber(' 001010 ', 2) == 10) assert(tonumber(' 001010 ', 10) == 001010) +-- FIXME LuaJIT --assert(tonumber(' -1010 ', 2) == -10) assert(tonumber('10', 36) == 36) +-- FIXME LuaJIT --assert(tonumber(' -10 ', 36) == -36) assert(tonumber(' +1Z ', 36) == 36 + 35) +-- FIXME LuaJIT --assert(tonumber(' -1z ', 36) == -36 + -35) --assert(tonumber('-fFfa', 16) == -(10+(16*(15+(16*(15+(16*15))))))) assert(tonumber(string.rep('1', 42), 2) + 1 == 2^42) assert(tonumber(string.rep('1', 34), 2) + 1 == 2^34) assert(tonumber('ffffFFFF', 16)+1 == 2^32) assert(tonumber('0ffffFFFF', 16)+1 == 2^32) +-- FIXME LuaJIT --assert(tonumber('-0ffffffFFFF', 16) - 1 == -2^40) for i = 2,36 do assert(tonumber('\t10000000000\t', i) == i^10) @@ -82,12 +86,15 @@ end -- testing 'tonumber' fo invalid formats assert(f(tonumber('fFfa', 15)) == nil) assert(f(tonumber('099', 8)) == nil) +-- FIXME LuaJIT --assert(f(tonumber('1\0', 2)) == nil) assert(f(tonumber('', 8)) == nil) assert(f(tonumber(' ', 9)) == nil) assert(f(tonumber(' ', 9)) == nil) +-- FIXME LuaJIT --assert(f(tonumber('0xf', 10)) == nil) +-- FIXME LuaJIT --assert(f(tonumber('inf')) == nil) --assert(f(tonumber(' INF ')) == nil) --assert(f(tonumber('Nan')) == nil) @@ -96,6 +103,7 @@ assert(f(tonumber(' ', 9)) == nil) assert(f(tonumber(' ')) == nil) assert(f(tonumber('')) == nil) assert(f(tonumber('1 a')) == nil) +-- FIXME LuaJIT --assert(f(tonumber('1\0')) == nil) --assert(f(tonumber('1 \0')) == nil) --assert(f(tonumber('1\0 ')) == nil) diff --git a/lua-5.2.2-tests/nextvar.lua b/lua-5.2.2-tests/nextvar.lua index d11d098df6..6f5550fba0 100644 --- a/lua-5.2.2-tests/nextvar.lua +++ b/lua-5.2.2-tests/nextvar.lua @@ -323,18 +323,22 @@ local function test (a) end a = {n=0, [-7] = "ban"} +-- FIXME LuaJIT --test(a) assert(a.n == 0 and a[-7] == "ban") a = {[-7] = "ban"}; +-- FIXME LuaJIT --test(a) assert(a.n == nil and #a == 0 and a[-7] == "ban") a = {[-1] = "ban"} +-- FIXME LuaJIT --test(a) assert(#a == 0 and table.remove(a) == nil and a[-1] == "ban") a = {[0] = "ban"} +-- FIXME LuaJIT --assert(#a == 0 and table.remove(a) == "ban" and a[0] == nil) table.insert(a, 1, 10); table.insert(a, 1, 20); table.insert(a, 1, -1) @@ -355,6 +359,7 @@ assert(#a == 0 and a.n == nil) a = {10,20,30,40} assert(table.remove(a, #a + 1) == nil) +-- FIXME LuaJIT --assert(not pcall(table.remove, a, 0)) assert(a[#a] == 40) assert(table.remove(a, #a) == 40) diff --git a/lua-5.2.2-tests/pm.lua b/lua-5.2.2-tests/pm.lua index fca08130ca..30bfaadb37 100644 --- a/lua-5.2.2-tests/pm.lua +++ b/lua-5.2.2-tests/pm.lua @@ -322,12 +322,14 @@ malform("[]") malform("[^]") malform("[a%]") malform("[a%") +-- FIXME LuaJIT --malform("%b") --malform("%ba") malform("%") malform("%f", "missing") -- \0 in patterns +-- FIXME LuaJIT --assert(string.match("ab\0\1\2c", "[\0-\2]+") == "\0\1\2") --assert(string.match("ab\0\1\2c", "[\0-\0]+") == "\0") --assert(string.find("b$a", "$\0?") == 2) @@ -337,6 +339,7 @@ malform("%f", "missing") --assert(string.match("abc\0\0\0", "%\0%\0?") == "\0\0") -- magic char after \0 +-- FIXME LuaJIT --assert(string.find("abc\0\0","\0.") == 4) --assert(string.find("abcx\0\0abc\0abc","x\0\0abc\0a.") == 4) diff --git a/lua-5.2.2-tests/sort.lua b/lua-5.2.2-tests/sort.lua index e376692631..85b9cf4c2a 100644 --- a/lua-5.2.2-tests/sort.lua +++ b/lua-5.2.2-tests/sort.lua @@ -1,5 +1,6 @@ print "testing (parts of) table library" +-- FIXME LuaJIT pack/unpack tests disabled if false then print "testing unpack" From 3e731388db9e1803e44adf5bf43a7b837e788663 Mon Sep 17 00:00:00 2001 From: bandhu Date: Fri, 7 Oct 2016 18:49:22 +0100 Subject: [PATCH 46/68] issue #8 add dummy file to ensure directory is saved in git --- lua5.1-tests/libs/P1/dummy | 1 + 1 file changed, 1 insertion(+) create mode 100644 lua5.1-tests/libs/P1/dummy diff --git a/lua5.1-tests/libs/P1/dummy b/lua5.1-tests/libs/P1/dummy new file mode 100644 index 0000000000..421376db9e --- /dev/null +++ b/lua5.1-tests/libs/P1/dummy @@ -0,0 +1 @@ +dummy From cd429000dd954477ebf789edbb73c805f0f86e6e Mon Sep 17 00:00:00 2001 From: bandhu Date: Fri, 7 Oct 2016 18:53:45 +0100 Subject: [PATCH 47/68] issue #8 add dummy file to ensure directory is saved in git --- lua-5.2.2-tests/libs/P1/dummy | 1 + 1 file changed, 1 insertion(+) create mode 100644 lua-5.2.2-tests/libs/P1/dummy diff --git a/lua-5.2.2-tests/libs/P1/dummy b/lua-5.2.2-tests/libs/P1/dummy new file mode 100644 index 0000000000..421376db9e --- /dev/null +++ b/lua-5.2.2-tests/libs/P1/dummy @@ -0,0 +1 @@ +dummy From b0a75b45a6d99e73472906cc668d1c7804f5147b Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Sat, 8 Oct 2016 16:32:12 +0000 Subject: [PATCH 48/68] Added bench/roulette.lua This benchmark exhibits non-deterministic performance. --- bench/roulette.lua | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 bench/roulette.lua diff --git a/bench/roulette.lua b/bench/roulette.lua new file mode 100644 index 0000000000..77c9fbb2b5 --- /dev/null +++ b/bench/roulette.lua @@ -0,0 +1,20 @@ +-- Russian Roulette simulator +-- This benchmark includes randomness from an external source that can +-- produce non-deterministic performance. +-- See https://github.com/LuaJIT/LuaJIT/issues/218 + +math.randomseed(os.time()) + +local population = 100e6 +local live = 0 +local die = 0 + +for i = 1, population do + if math.random(6) == 6 then + die = die + 1 + else + live = live + 1 + end +end + +print(("Survived %d/%d (%.3f%%)"):format(live, population, live*100/(live+die))) From a71cd6d99cac83d71730860ca94b901385d6c46d Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Sun, 9 Oct 2016 08:59:43 +0000 Subject: [PATCH 49/68] roulette: Stop seeding the random number generator The test harness shuold do this in some suitable way e.g. with values that are reproducible but still contain entropy for the JIT. --- bench/roulette.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bench/roulette.lua b/bench/roulette.lua index 77c9fbb2b5..968d42a744 100644 --- a/bench/roulette.lua +++ b/bench/roulette.lua @@ -3,7 +3,8 @@ -- produce non-deterministic performance. -- See https://github.com/LuaJIT/LuaJIT/issues/218 -math.randomseed(os.time()) +-- (Let the test harness determine the random seed) +-- math.randomseed(os.time()) local population = 100e6 local live = 0 From 318dedd6db46fd512ec59038aa6b0958a4370b1c Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sun, 9 Oct 2016 16:26:38 +0100 Subject: [PATCH 50/68] Update README.md --- lua5.1-tests/README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lua5.1-tests/README.md b/lua5.1-tests/README.md index 464365b307..1b493c5da5 100644 --- a/lua5.1-tests/README.md +++ b/lua5.1-tests/README.md @@ -1,7 +1,6 @@ # Lua 5.1 Test Suite -This directory contains a modified version of the Lua 5.1 test suite. The modifications are primarily to disable or amend some tests -so that the test suite can be run. +This directory contains a modified version of the [Lua 5.1 test suite](http://www.lua.org/tests/). The modifications are primarily to disable or amend some tests so that the test suite can be run. ## LuaJIT build options @@ -16,10 +15,13 @@ On UNIX systems just execute: sh run.sh ``` +## Platform Status + +The modified test suite passes on OSX El Capitan and Ubuntu 14.04. + ## Tests disabled or ignored Wherever tests have been switched off or ignored a comment has been added and the code has been made conditional. These failures will -be investigated and either the tests will be modified or permanently disabled depending upon whether the issue is one of compatibility -or a defect in LuaJIT. +be investigated and either the tests will be modified so that they work for LuaJIT or optionally enabled depending upon whether the issue is one of compatibility or a defect in LuaJIT. Example of excluded test: ``` From 8e20d26a66efdd4d31b2afd4edfb2c01ad3e18ee Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Sun, 9 Oct 2016 16:30:04 +0100 Subject: [PATCH 51/68] Update README.md --- lua-5.2.2-tests/README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lua-5.2.2-tests/README.md b/lua-5.2.2-tests/README.md index fb8a19d6f9..3b37dcd2a4 100644 --- a/lua-5.2.2-tests/README.md +++ b/lua-5.2.2-tests/README.md @@ -1,7 +1,6 @@ # Lua 5.2.2 Test Suite -This directory contains a modified version of the Lua 5.2.2 test suite. The modifications are primarily to disable or amend some tests -so that the test suite can be run. +This directory contains a modified version of the [Lua 5.2.2 test suite](http://www.lua.org/tests/). The modifications are primarily to disable or amend some tests so that the test suite can be run. ## LuaJIT build options @@ -15,11 +14,13 @@ On UNIX systems just execute: ``` sh run.sh ``` +## Platform Status + +The modified test suite passes on OSX El Capitan and Ubuntu 14.04. ## Tests disabled or ignored Wherever tests have been switched off or ignored a comment has been added and the code has been made conditional. These failures will -be investigated and either the tests will be modified or permanently disabled depending upon whether the issue is one of compatibility -or a defect in LuaJIT. +be investigated and either the tests will be modified so that they work for LuaJIT or optionally enabled depending upon whether the issue is one of compatibility or a defect in LuaJIT. Example of excluded test: ``` From 2faff35640775c24f1bf7035d30ac727b82c4265 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Tue, 11 Oct 2016 23:11:44 +0100 Subject: [PATCH 52/68] issue #8 add strings.lua and literals.lua to the execution --- lua-5.2.2-tests/all.lua | 4 +-- lua-5.2.2-tests/literals.lua | 63 +++++++++++++++++++----------------- lua-5.2.2-tests/strings.lua | 23 +++++++------ 3 files changed, 49 insertions(+), 41 deletions(-) diff --git a/lua-5.2.2-tests/all.lua b/lua-5.2.2-tests/all.lua index b86c001698..029f5de9e8 100755 --- a/lua-5.2.2-tests/all.lua +++ b/lua-5.2.2-tests/all.lua @@ -158,8 +158,8 @@ end --dofile('db.lua') assert(dofile('calls.lua') == deep and deep) -- FIXME LuaJIT ---olddofile('strings.lua') ---olddofile('literals.lua') +olddofile('strings.lua') +olddofile('literals.lua') assert(dofile('attrib.lua') == 27) -- FIXME LuaJIT diff --git a/lua-5.2.2-tests/literals.lua b/lua-5.2.2-tests/literals.lua index 36e2fcf4e3..b641a71b98 100644 --- a/lua-5.2.2-tests/literals.lua +++ b/lua-5.2.2-tests/literals.lua @@ -53,40 +53,44 @@ local function lexerror (s, err) if err ~= '' then err = "'"..err.."'" end assert(not st and string.find(msg, "near "..err, 1, true)) end -lexerror([["abc\x"]], [[\x"]]) -lexerror([["abc\x]], [[\x]]) -lexerror([["\x]], [[\x]]) -lexerror([["\x5"]], [[\x5"]]) -lexerror([["\x5]], [[\x5]]) -lexerror([["\xr"]], [[\xr]]) -lexerror([["\xr]], [[\xr]]) -lexerror([["\x.]], [[\x.]]) -lexerror([["\x8%"]], [[\x8%]]) -lexerror([["\xAG]], [[\xAG]]) -lexerror([["\g"]], [[\g]]) -lexerror([["\g]], [[\g]]) -lexerror([["\."]], [[\.]]) - -lexerror([["\999"]], [[\999]]) -lexerror([["xyz\300"]], [[\300]]) -lexerror([[" \256"]], [[\256]]) +-- FIXME LuaJIT +--lexerror([["abc\x"]], [[\x"]]) +--lexerror([["abc\x]], [[\x]]) +--lexerror([["\x]], [[\x]]) +--lexerror([["\x5"]], [[\x5"]]) +--lexerror([["\x5]], [[\x5]]) +--lexerror([["\xr"]], [[\xr]]) +--lexerror([["\xr]], [[\xr]]) +--lexerror([["\x.]], [[\x.]]) +--lexerror([["\x8%"]], [[\x8%]]) +--lexerror([["\xAG]], [[\xAG]]) +--lexerror([["\g"]], [[\g]]) +--lexerror([["\g]], [[\g]]) +--lexerror([["\."]], [[\.]]) + +--FIXME LuaJIT +--lexerror([["\999"]], [[\999]]) +--lexerror([["xyz\300"]], [[\300]]) +--lexerror([[" \256"]], [[\256]]) -- unfinished strings -lexerror("[=[alo]]", "") -lexerror("[=[alo]=", "") -lexerror("[=[alo]", "") -lexerror("'alo", "") -lexerror("'alo \\z \n\n", "") -lexerror("'alo \\z", "") -lexerror([['alo \98]], "") +--FIXME LuaJIT +--lexerror("[=[alo]]", "") +--lexerror("[=[alo]=", "") +--lexerror("[=[alo]", "") +--lexerror("'alo", "") +--lexerror("'alo \\z \n\n", "") +--lexerror("'alo \\z", "") +--lexerror([['alo \98]], "") -- valid characters in variable names for i = 0, 255 do local s = string.char(i) - assert(not string.find(s, "[a-zA-Z_]") == not load(s .. "=1")) - assert(not string.find(s, "[a-zA-Z_0-9]") == - not load("a" .. s .. "1 = 1")) + -- FIXME LuaJIT + --assert(not string.find(s, "[a-zA-Z_]") == not load(s .. "=1")) + --assert(not string.find(s, "[a-zA-Z_0-9]") == + -- not load("a" .. s .. "1 = 1")) end @@ -228,9 +232,10 @@ end -- testing decimal point locale if os.setlocale("pt_BR") or os.setlocale("ptb") then - assert(not load("á = 3")) -- parser still works with C locale + -- FIXME LuaJIT + --assert(not load("á = 3")) -- parser still works with C locale assert(not load("a = (3,4)")) - assert(tonumber("3,4") == 3.4 and tonumber"3.4" == nil) + --assert(tonumber("3,4") == 3.4 and tonumber"3.4" == nil) assert(assert(load("return 3.4"))() == 3.4) assert(assert(load("return .4,3"))() == .4) assert(assert(load("return 4."))() == 4.) diff --git a/lua-5.2.2-tests/strings.lua b/lua-5.2.2-tests/strings.lua index b9ef47006d..93b3412871 100644 --- a/lua-5.2.2-tests/strings.lua +++ b/lua-5.2.2-tests/strings.lua @@ -208,10 +208,11 @@ check("%d %d", "no value") -- integers out of range -assert(not pcall(string.format, "%d", 2^63)) -assert(not pcall(string.format, "%x", 2^64)) -assert(not pcall(string.format, "%x", -2^64)) -assert(not pcall(string.format, "%x", -1)) +--FIXME LuaJIT +--assert(not pcall(string.format, "%d", 2^63)) +--assert(not pcall(string.format, "%x", 2^64)) +--assert(not pcall(string.format, "%x", -2^64)) +--assert(not pcall(string.format, "%x", -1)) assert(load("return 1\n--comentário sem EOL no final")() == 1) @@ -256,18 +257,20 @@ end if not trylocale("collate") then print("locale not supported") else - assert("alo" < "álo" and "álo" < "amo") + -- FIXME LuaJIT + --assert("alo" < "álo" and "álo" < "amo") end if not trylocale("ctype") then print("locale not supported") else assert(load("a = 3.4")); -- parser should not change outside locale - assert(not load("á = 3.4")); -- even with errors - 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") + -- FIXME LuaJIT + --assert(not load("á = 3.4")); -- even with errors + --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") From ad494d6dfbfac0fd88c467ab6fe24d57beda656a Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Tue, 11 Oct 2016 23:13:33 +0100 Subject: [PATCH 53/68] issue #8 add strings.lua and literals.lua to the execution --- lua-5.2.2-tests/run.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lua-5.2.2-tests/run.sh b/lua-5.2.2-tests/run.sh index 2cd06ae16f..4bdd530455 100644 --- a/lua-5.2.2-tests/run.sh +++ b/lua-5.2.2-tests/run.sh @@ -1,7 +1,7 @@ export LUA_PATH="?;./?.lua" export LUA_INIT="package.path = '?;'..package.path" -luajit -joff all.lua +luajit -joff -e"_port=1" all.lua if [ $? != 0 ] then echo "all.lua tests failed with JIT off" @@ -9,7 +9,7 @@ then fi -luajit -jon all.lua +luajit -jon -e"_port=1" all.lua if [ $? != 0 ] then echo "all.lua tests failed with JIT on" From 6fe6fbe777a01c2e700937081090b1cd6ae23686 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Wed, 12 Oct 2016 00:44:08 +0100 Subject: [PATCH 54/68] add coroutine.lua --- lua-5.2.2-tests/coroutine.lua | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lua-5.2.2-tests/coroutine.lua b/lua-5.2.2-tests/coroutine.lua index 85086e5839..ccfcfd4465 100644 --- a/lua-5.2.2-tests/coroutine.lua +++ b/lua-5.2.2-tests/coroutine.lua @@ -1,5 +1,8 @@ print "testing coroutines" +--FIXME LuaJIT +T = nil + local debug = require'debug' local f @@ -239,8 +242,9 @@ assert(a and b == 3) assert(coroutine.status(co1) == 'dead') -- infinite recursion of coroutines -a = function(a) coroutine.wrap(a)(a) end -assert(not pcall(a, a)) +-- FIXME LuaJIT +--a = function(a) coroutine.wrap(a)(a) end +--assert(not pcall(a, a)) -- access to locals of erroneous coroutines @@ -517,8 +521,9 @@ do local _ENV = _ENV end g = new(10); g.k.BBB = 10; debug.setupvalue(f, 1, g) -assert(run(f, {"idx", "nidx", "idx"}) == 11) -assert(g.k.AAA == 11) +--FIXME LuaJIT +--assert(run(f, {"idx", "nidx", "idx"}) == 11) +--assert(g.k.AAA == 11) print"+" From 7897e7fff3f04e65838c316ee9caf27f78e9f76b Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Tue, 11 Oct 2016 20:51:35 -0700 Subject: [PATCH 55/68] Add tests for allocation of variable-sized cdata --- test/lib/ffi/cdata_var.lua | 41 ++++++++++++++++++++++++++++++++++++++ test/lib/ffi/index | 1 + 2 files changed, 42 insertions(+) create mode 100644 test/lib/ffi/cdata_var.lua diff --git a/test/lib/ffi/cdata_var.lua b/test/lib/ffi/cdata_var.lua new file mode 100644 index 0000000000..d388c00233 --- /dev/null +++ b/test/lib/ffi/cdata_var.lua @@ -0,0 +1,41 @@ +local ffi = require("ffi") + +do --- byte array allocations + local typ = ffi.typeof"uint8_t[?]" + for i = 4, 20 do + for d = -3, 3 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[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) + assert(mem[sz-1] == -4) + end + end +end diff --git a/test/lib/ffi/index b/test/lib/ffi/index index bda633000d..59e36dd8b0 100644 --- a/test/lib/ffi/index +++ b/test/lib/ffi/index @@ -1,4 +1,5 @@ bit64.lua +luajit>=2.1 +cdata_var.lua copy_fill.lua err.lua istype.lua From e7b029b023362d02b8c761cdc338f4a6f53ebec5 Mon Sep 17 00:00:00 2001 From: Dibyendu Majumdar Date: Wed, 12 Oct 2016 12:55:33 +0100 Subject: [PATCH 56/68] issue #8 removing tests --- lua-5.2.2-tests/README.md | 29 - lua-5.2.2-tests/all.lua | 269 ------ lua-5.2.2-tests/api.lua | 1009 --------------------- lua-5.2.2-tests/attrib.lua | 427 --------- lua-5.2.2-tests/big.lua | 79 -- lua-5.2.2-tests/bitwise.lua | 115 --- lua-5.2.2-tests/calls.lua | 314 ------- lua-5.2.2-tests/checktable.lua | 77 -- lua-5.2.2-tests/closure.lua | 247 ----- lua-5.2.2-tests/code.lua | 182 ---- lua-5.2.2-tests/constructs.lua | 310 ------- lua-5.2.2-tests/coroutine.lua | 733 --------------- lua-5.2.2-tests/db.lua | 631 ------------- lua-5.2.2-tests/errors.lua | 439 --------- lua-5.2.2-tests/events.lua | 390 -------- lua-5.2.2-tests/files.lua | 626 ------------- lua-5.2.2-tests/gc.lua | 575 ------------ lua-5.2.2-tests/goto.lua | 173 ---- lua-5.2.2-tests/libs/P1/dummy | 1 - lua-5.2.2-tests/libs/lib1.c | 49 - lua-5.2.2-tests/libs/lib11.c | 18 - lua-5.2.2-tests/libs/lib2.c | 29 - lua-5.2.2-tests/libs/lib21.c | 18 - lua-5.2.2-tests/libs/makefile | 26 - lua-5.2.2-tests/literals.lua | 263 ------ lua-5.2.2-tests/locals.lua | 163 ---- lua-5.2.2-tests/ltests/ltests.c | 1506 ------------------------------- lua-5.2.2-tests/ltests/ltests.h | 93 -- lua-5.2.2-tests/main.lua | 260 ------ lua-5.2.2-tests/math.lua | 295 ------ lua-5.2.2-tests/nextvar.lua | 466 ---------- lua-5.2.2-tests/pm.lua | 347 ------- lua-5.2.2-tests/run.sh | 18 - lua-5.2.2-tests/sort.lua | 169 ---- lua-5.2.2-tests/strings.lua | 284 ------ lua-5.2.2-tests/vararg.lua | 125 --- lua-5.2.2-tests/verybig.lua | 144 --- lua5.1-tests/README.md | 30 - lua5.1-tests/all.lua | 140 --- lua5.1-tests/api.lua | 711 --------------- lua5.1-tests/attrib.lua | 339 ------- lua5.1-tests/big.lua | 381 -------- lua5.1-tests/calls.lua | 294 ------ lua5.1-tests/checktable.lua | 77 -- lua5.1-tests/closure.lua | 423 --------- lua5.1-tests/code.lua | 143 --- lua5.1-tests/constructs.lua | 240 ----- lua5.1-tests/db.lua | 499 ---------- lua5.1-tests/docs/README | 41 - lua5.1-tests/errors.lua | 253 ------ lua5.1-tests/etc/ltests.c | 1147 ----------------------- lua5.1-tests/etc/ltests.h | 92 -- lua5.1-tests/events.lua | 360 -------- lua5.1-tests/files.lua | 324 ------- lua5.1-tests/gc.lua | 312 ------- lua5.1-tests/libs/P1/dummy | 1 - lua5.1-tests/libs/lib1.c | 40 - lua5.1-tests/libs/lib11.c | 18 - lua5.1-tests/libs/lib2.c | 28 - lua5.1-tests/libs/lib21.c | 18 - lua5.1-tests/libs/makefile | 16 - lua5.1-tests/literals.lua | 177 ---- lua5.1-tests/locals.lua | 127 --- lua5.1-tests/main.lua | 159 ---- lua5.1-tests/math.lua | 208 ----- lua5.1-tests/nextvar.lua | 396 -------- lua5.1-tests/pm.lua | 273 ------ lua5.1-tests/run.sh | 18 - lua5.1-tests/sort.lua | 74 -- lua5.1-tests/strings.lua | 179 ---- lua5.1-tests/vararg.lua | 130 --- lua5.1-tests/verybig.lua | 100 -- 72 files changed, 18667 deletions(-) delete mode 100644 lua-5.2.2-tests/README.md delete mode 100755 lua-5.2.2-tests/all.lua delete mode 100644 lua-5.2.2-tests/api.lua delete mode 100644 lua-5.2.2-tests/attrib.lua delete mode 100644 lua-5.2.2-tests/big.lua delete mode 100755 lua-5.2.2-tests/bitwise.lua delete mode 100644 lua-5.2.2-tests/calls.lua delete mode 100644 lua-5.2.2-tests/checktable.lua delete mode 100644 lua-5.2.2-tests/closure.lua delete mode 100644 lua-5.2.2-tests/code.lua delete mode 100644 lua-5.2.2-tests/constructs.lua delete mode 100644 lua-5.2.2-tests/coroutine.lua delete mode 100644 lua-5.2.2-tests/db.lua delete mode 100644 lua-5.2.2-tests/errors.lua delete mode 100644 lua-5.2.2-tests/events.lua delete mode 100644 lua-5.2.2-tests/files.lua delete mode 100644 lua-5.2.2-tests/gc.lua delete mode 100644 lua-5.2.2-tests/goto.lua delete mode 100644 lua-5.2.2-tests/libs/P1/dummy delete mode 100644 lua-5.2.2-tests/libs/lib1.c delete mode 100644 lua-5.2.2-tests/libs/lib11.c delete mode 100644 lua-5.2.2-tests/libs/lib2.c delete mode 100644 lua-5.2.2-tests/libs/lib21.c delete mode 100644 lua-5.2.2-tests/libs/makefile delete mode 100644 lua-5.2.2-tests/literals.lua delete mode 100644 lua-5.2.2-tests/locals.lua delete mode 100644 lua-5.2.2-tests/ltests/ltests.c delete mode 100644 lua-5.2.2-tests/ltests/ltests.h delete mode 100644 lua-5.2.2-tests/main.lua delete mode 100644 lua-5.2.2-tests/math.lua delete mode 100644 lua-5.2.2-tests/nextvar.lua delete mode 100644 lua-5.2.2-tests/pm.lua delete mode 100644 lua-5.2.2-tests/run.sh delete mode 100644 lua-5.2.2-tests/sort.lua delete mode 100644 lua-5.2.2-tests/strings.lua delete mode 100644 lua-5.2.2-tests/vararg.lua delete mode 100644 lua-5.2.2-tests/verybig.lua delete mode 100644 lua5.1-tests/README.md delete mode 100755 lua5.1-tests/all.lua delete mode 100644 lua5.1-tests/api.lua delete mode 100644 lua5.1-tests/attrib.lua delete mode 100644 lua5.1-tests/big.lua delete mode 100644 lua5.1-tests/calls.lua delete mode 100644 lua5.1-tests/checktable.lua delete mode 100644 lua5.1-tests/closure.lua delete mode 100644 lua5.1-tests/code.lua delete mode 100644 lua5.1-tests/constructs.lua delete mode 100644 lua5.1-tests/db.lua delete mode 100644 lua5.1-tests/docs/README delete mode 100644 lua5.1-tests/errors.lua delete mode 100644 lua5.1-tests/etc/ltests.c delete mode 100644 lua5.1-tests/etc/ltests.h delete mode 100644 lua5.1-tests/events.lua delete mode 100644 lua5.1-tests/files.lua delete mode 100644 lua5.1-tests/gc.lua delete mode 100644 lua5.1-tests/libs/P1/dummy delete mode 100644 lua5.1-tests/libs/lib1.c delete mode 100644 lua5.1-tests/libs/lib11.c delete mode 100644 lua5.1-tests/libs/lib2.c delete mode 100644 lua5.1-tests/libs/lib21.c delete mode 100644 lua5.1-tests/libs/makefile delete mode 100644 lua5.1-tests/literals.lua delete mode 100644 lua5.1-tests/locals.lua delete mode 100644 lua5.1-tests/main.lua delete mode 100644 lua5.1-tests/math.lua delete mode 100644 lua5.1-tests/nextvar.lua delete mode 100644 lua5.1-tests/pm.lua delete mode 100644 lua5.1-tests/run.sh delete mode 100644 lua5.1-tests/sort.lua delete mode 100644 lua5.1-tests/strings.lua delete mode 100644 lua5.1-tests/vararg.lua delete mode 100644 lua5.1-tests/verybig.lua diff --git a/lua-5.2.2-tests/README.md b/lua-5.2.2-tests/README.md deleted file mode 100644 index 3b37dcd2a4..0000000000 --- a/lua-5.2.2-tests/README.md +++ /dev/null @@ -1,29 +0,0 @@ -# Lua 5.2.2 Test Suite - -This directory contains a modified version of the [Lua 5.2.2 test suite](http://www.lua.org/tests/). The modifications are primarily to disable or amend some tests so that the test suite can be run. - -## LuaJIT build options - -LUA 5.2 compatibility must be turned on. - -## Running the test suite - -You need to have `luajit` on your path. - -On UNIX systems just execute: -``` -sh run.sh -``` -## Platform Status - -The modified test suite passes on OSX El Capitan and Ubuntu 14.04. - -## Tests disabled or ignored -Wherever tests have been switched off or ignored a comment has been added and the code has been made conditional. These failures will -be investigated and either the tests will be modified so that they work for LuaJIT or optionally enabled depending upon whether the issue is one of compatibility or a defect in LuaJIT. - -Example of excluded test: -``` --- FIXME tests fail in LuaJIT --- dofile('main.lua') -``` diff --git a/lua-5.2.2-tests/all.lua b/lua-5.2.2-tests/all.lua deleted file mode 100755 index 029f5de9e8..0000000000 --- a/lua-5.2.2-tests/all.lua +++ /dev/null @@ -1,269 +0,0 @@ ---#!../lua - ---local version = "Lua 5.2" ---if _VERSION ~= version then --- io.stderr:write("\nThis test suite is for ", version, ", not for ", _VERSION, --- "\nExiting tests\n") --- return ---end - - --- next variables control the execution of some tests --- true means no test (so an undefined variable does not skip a test) --- defaults are for Linux; test everything - -_soft = false -- true to avoid long or memory consuming tests -_port = false -- true to avoid non-portable tests -_no32 = false -- true to avoid tests that assume 32 bits -_nomsg = false -- true to avoid messages about tests not performed -_noposix = false -- false assumes LUA_USE_POSIX -_nolonglong = false -- false assumes LUA_USE_LONGLONG -_noformatA = false -- false assumes LUA_USE_AFORMAT - - -local usertests = rawget(_G, "_U") - -if usertests then - -- tests for sissies ;) Avoid problems - _soft = true - _port = true - _no32 = true - _nomsg = true - _noposix = true - _nolonglong = true - _noformatA = true; -end - --- no "internal" tests for user tests -if usertests then T = nil end - -T = rawget(_G, "T") -- avoid problems with 'strict' module - -package.path = "?;./?.lua" .. package.path - -math.randomseed(0) - -collectgarbage("setstepmul", 200) -collectgarbage("setpause", 200) - - ---[=[ - example of a long [comment], - [[spanning several [lines]]] - -]=] - -print("current path:\n****" .. package.path .. "****\n") - - -local c = os.clock() - -local collectgarbage = collectgarbage - -do -- ( - --- track messages for tests not performed -local msgs = {} -function Message (m) - if not _nomsg then - print(m) - msgs[#msgs+1] = string.sub(m, 3, -3) - end -end - -assert(os.setlocale"C") - -local T,print,format,write,assert,type,unpack,floor = - T,print,string.format,io.write,assert,type,table.unpack,math.floor - --- use K for 1000 and M for 1000000 (not 2^10 -- 2^20) -local function F (m) - local function round (m) - m = m + 0.04999 - return m - (m % 0.1) -- keep one decimal digit - end - if m < 1000 then return m - else - m = m / 1000 - if m < 1000 then return round(m).."K" - else - return round(m/1000).."M" - end - end -end - -local showmem -if not T then - local max = 0 - showmem = function () - local m = collectgarbage("count") * 1024 - max = (m > max) and m or max - print(format(" ---- total memory: %s, max memory: %s ----\n", - F(m), F(max))) - end -else - showmem = function () - T.checkmemory() - local total, numblocks, maxmem = T.totalmem() - local count = collectgarbage("count") - print(format( - "\n ---- total memory: %s (%.0fK), max use: %s, blocks: %d\n", - F(total), count, F(maxmem), numblocks)) - print(format("\t(strings: %d, tables: %d, functions: %d, ".. - "\n\tudata: %d, threads: %d)", - T.totalmem"string", T.totalmem"table", T.totalmem"function", - T.totalmem"userdata", T.totalmem"thread")) - end -end - - --- --- redefine dofile to run files through dump/undump --- -local function report (n) print("\n***** FILE '"..n.."'*****") end -local olddofile = dofile -dofile = function (n) - showmem() - report(n) - local f = assert(loadfile(n)) - local b = string.dump(f) - f = assert(load(b)) - return f() -end - --- FIXME LuaJIT ---dofile('main.lua') - -do - local next, setmetatable, stderr = next, setmetatable, io.stderr - local mt = {} - -- each time a table is collected, create a new one to be - -- collected next cycle - mt.__gc = function (o) - stderr:write'.' -- mark progress - local n = setmetatable({}, mt) -- replicate object - o = nil - local a,b,c,d,e = nil -- erase 'o' from the stack - end - local n = setmetatable({}, mt) -- replicate object -end - --- FIXME LuaJIT ---report"gc.lua" ---local f = assert(loadfile('gc.lua')) ---f() - --- FIXMELuaJIT ---collectgarbage("generational") ---dofile('db.lua') -assert(dofile('calls.lua') == deep and deep) --- FIXME LuaJIT -olddofile('strings.lua') -olddofile('literals.lua') -assert(dofile('attrib.lua') == 27) - --- FIXME LuaJIT ---collectgarbage("incremental") -- redo some tests in incremental mode ---olddofile('strings.lua') ---olddofile('literals.lua') -dofile('constructs.lua') -dofile('api.lua') - --- FIXME LuaJIT ---collectgarbage("generational") -- back to generational mode -collectgarbage("setpause", 200) --- FIXME LuaJIT ---collectgarbage("setmajorinc", 500) -assert(dofile('locals.lua') == 5) -dofile('constructs.lua') -dofile('code.lua') -if not _G._soft then - report('big.lua') - 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') --- FIXME LuaJIT ---dofile('coroutine.lua') -dofile('goto.lua') -dofile('errors.lua') -dofile('math.lua') -dofile('sort.lua') --- FIXME LuaJIT ---dofile('bitwise.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 !!!") - -local debug = require "debug" - -debug.sethook(function (a) assert(type(a) == 'string') end, "cr") - --- to survive outside block -_G.showmem = showmem - -end --) - -local _G, showmem, print, format, clock, assert, open = - _G, showmem, print, string.format, os.clock, assert, io.open - --- file with time of last performed test -local fname = T and "time-debug.txt" or "time.txt" -local lasttime - -if not usertests then - -- open file with time of last performed test - local f = io.open(fname) - if f then - lasttime = assert(tonumber(f:read'*a')) - f:close(); - else -- no such file; assume it is recording time for first time - lasttime = nil - end -end - --- erase (almost) all globals -print('cleaning all!!!!') -for n in pairs(_G) do - if not ({___Glob = 1, tostring = 1})[n] then - _G[n] = nil - end -end - - -collectgarbage() -collectgarbage() -collectgarbage() -collectgarbage() -collectgarbage() -collectgarbage();showmem() - -local time = clock() - c - -print(format("\n\ntotal time: %.2f\n", time)) - -if not usertests then - lasttime = lasttime or time -- if there is no last time, ignore difference - -- check whether current test time differs more than 5% from last time - local diff = (time - lasttime) / time - local tolerance = 0.05 -- 5% - -- FIXME LuaJIT - --assert(diff < tolerance and diff > -tolerance) - assert(open(fname, "w")):write(time):close() -end - diff --git a/lua-5.2.2-tests/api.lua b/lua-5.2.2-tests/api.lua deleted file mode 100644 index a367fc8f05..0000000000 --- a/lua-5.2.2-tests/api.lua +++ /dev/null @@ -1,1009 +0,0 @@ - -if T==nil then - (Message or print)('\a\n >>> testC not active: skipping API tests <<<\n\a') - return -end - -local debug = require "debug" - -local pack = table.pack - - -function tcheck (t1, t2) - assert(t1.n == (t2.n or #t2) + 1) - for i = 2, t1.n do assert(t1[i] == t2[i - 1]) end -end - - -print('testing C API') - -a = T.testC("pushvalue R; return 1") -assert(a == debug.getregistry()) - - --- absindex -assert(T.testC("settop 10; absindex -1; return 1") == 10) -assert(T.testC("settop 5; absindex -5; return 1") == 1) -assert(T.testC("settop 10; absindex 1; return 1") == 1) -assert(T.testC("settop 10; absindex R; return 1") < -10) - --- 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) - -f = T.makeCfunc("pushnum 1; pushnum 2; pushnum 3; return 2") -a,b,c = f() -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==false and b==true and c==false) - - -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("copy 3 4; gettop; return .", 2, 3, 4, 5)) -tcheck(t, {n=4,2,3,3,5}) - -t = pack(T.testC("copy -3 -1; gettop; return .", 2, 3, 4, 5)) -tcheck(t, {n=4,2,3,4,3}) - - - - -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("call 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([[pcall 1 -1; pop 1; tostring -1; return 1]], - table.unpack, a) - assert(b == "10") -end - - --- testing globals -_G.a = 14; _G.b = "a31" -local a = {T.testC[[ - getglobal a; - getglobal b; - getglobal b; - setglobal a; - gettop; - return . -]]} -assert(a[2] == 14 and a[3] == "a31" and a[4] == nil and _G.a == "a31") - - --- testing arith -assert(T.testC("pushnum 10; pushnum 20; arith /; return 1") == 0.5) -assert(T.testC("pushnum 10; pushnum 20; arith -; return 1") == -10) -assert(T.testC("pushnum 10; pushnum -20; arith *; return 1") == -200) -assert(T.testC("pushnum 10; pushnum 3; arith ^; return 1") == 1000) -assert(T.testC("pushnum 10; pushstring 20; arith /; return 1") == 0.5) -assert(T.testC("pushstring 10; pushnum 20; arith -; return 1") == -10) -assert(T.testC("pushstring 10; pushstring -20; arith *; return 1") == -200) -assert(T.testC("pushstring 10; pushstring 3; arith ^; return 1") == 1000) -a,b,c = T.testC([[pushnum 1; - pushstring 10; arith _; - pushstring 5; return 3]]) -assert(a == 1 and b == -10 and c == "5") -mt = {__add = function (a,b) return setmetatable({a[1] + b[1]}, mt) end, - __mod = function (a,b) return setmetatable({a[1] % b[1]}, mt) end, - __unm = function (a) return setmetatable({a[1]* 2}, mt) end} -a,b,c = setmetatable({4}, mt), - setmetatable({8}, mt), - setmetatable({-3}, mt) -x,y,z = T.testC("arith +; return 2", 10, a, b) -assert(x == 10 and y[1] == 12 and z == nil) -assert(T.testC("arith %; return 1", a, c)[1] == 4%-3) -assert(T.testC("arith _; arith +; arith %; return 1", b, a, c)[1] == - 8 % (4 + (-3)*2)) - - --- testing compare --- EQ = 0; LT = 1; LE = 2 - --- testing lessthan and lessequal -assert(T.testC("compare 2 5 1, return 1", 3, 2, 2, 4, 2, 2)) -assert(T.testC("compare 2 5 2, return 1", 3, 2, 2, 4, 2, 2)) -assert(not T.testC("compare 3 4 1, return 1", 3, 2, 2, 4, 2, 2)) -assert(T.testC("compare 3 4 2, return 1", 3, 2, 2, 4, 2, 2)) -assert(T.testC("compare 5 2 1, return 1", 4, 2, 2, 3, 2, 2)) -assert(not T.testC("compare 2 -3 1, return 1", "4", "2", "2", "3", "2", "2")) -assert(not T.testC("compare -3 2 1, return 1", "3", "2", "2", "4", "2", "2")) - --- non-valid indices produce false -assert(not T.testC("compare 1 4 1, return 1")) -assert(not T.testC("compare 9 1 2, return 1")) -assert(not T.testC("compare 9 9 0, return 1")) - -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("compare 2 5 1, return 1", a3, 2, 2, a4, 2, 2)) -assert(T.testC("compare 2 5 2, return 1", a3, 2, 2, a4, 2, 2)) -assert(T.testC("compare 5 -6 1, return 1", a4, 2, 2, a3, 2, 2)) -a,b = T.testC("compare 5 -6 1, return 2", a1, 2, 2, a3, 2, 20) -assert(a == 20 and b == false) -a,b = T.testC("compare 5 -6 2, return 2", a1, 2, 2, a3, 2, 20) -assert(a == 20 and b == false) -a,b = T.testC("compare 5 -6 2, return 2", a1, 2, 2, a1, 2, 20) -assert(a == 20 and b == true) - --- testing length -local t = setmetatable({x = 20}, {__len = function (t) return t.x end}) -a,b,c = T.testC([[ - len 2; - Llen 2; - objsize 2; - return 3 -]], t) -assert(a == 20 and b == 20 and c == 0) - -t.x = "234"; t[1] = 20 -a,b,c = T.testC([[ - len 2; - Llen 2; - objsize 2; - return 3 -]], t) -assert(a == "234" and b == 234 and c == 1) - -t.x = print; t[1] = 20 -a,c = T.testC([[ - len 2; - objsize 2; - return 2 -]], t) -assert(a == print and c == 1) - - --- testing __concat - -a = setmetatable({x="u"}, {__concat = function (a,b) return a.x..'.'..b.x end}) -x,y = T.testC([[ - pushnum 5 - pushvalue 2; - pushvalue 2; - concat 2; - pushvalue -2; - return 2; -]], a, a) -assert(x == a..a and y == 5) - --- concat with 0 elements -assert(T.testC("concat 0; return 1") == "") - --- concat with 1 element -assert(T.testC("concat 1; return 1", "xuxu") == "xuxu") - - - --- testing lua_is - -function B(x) return x and 1 or 0 end - -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 B(a)+B(b)+B(c)+B(d)+B(e)+B(f)+B(g)+(100*B(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", {1,2,3}) == 3) -assert(to("objsize", "alo\0\0a") == 6) -assert(to("objsize", T.newuserdata(0)) == 0) -assert(to("objsize", T.newuserdata(101)) == 101) -assert(to("objsize", 124) == 0) -assert(to("objsize", true) == 0) -assert(to("tonumber", {}) == 0) -assert(to("tonumber", "12") == 12) -assert(to("tonumber", "s2") == 0) -assert(to("tonumber", 1, 20) == 0) -assert(to("topointer", 10) == 0) -assert(to("topointer", true) == 0) -assert(to("topointer", T.pushuserdata(20)) == 20) -assert(to("topointer", io.read) ~= 0) -assert(to("func2num", 20) == 0) -assert(to("func2num", T.pushuserdata(10)) == 0) -assert(to("func2num", io.read) ~= 0) -a = to("tocfunction", math.deg) -assert(a(3) == math.deg(3) and a == math.deg) - - - --- testing deep C stack -do - collectgarbage("stop") - local s, msg = pcall(T.testC, "checkstack 1000023 XXXX") -- too deep - assert(not s and string.find(msg, "XXXX")) - s = string.rep("pushnil;checkstack 1 XX;", 1000000) - s, msg = pcall(T.testC, s) - assert(not s and string.find(msg, "XX")) - collectgarbage("restart") -end - -local prog = {"checkstack 30000 msg", "newtable"} -for i = 1,12000 do - prog[#prog + 1] = "pushnum " .. i - prog[#prog + 1] = "pushnum " .. i * 10 -end - -prog[#prog + 1] = "rawgeti R 2" -- get global table in registry -prog[#prog + 1] = "insert " .. -(2*12000 + 2) - -for i = 1,12000 do - prog[#prog + 1] = "settable " .. -(2*(12000 - i + 1) + 1) -end - -prog[#prog + 1] = "return 2" - -prog = table.concat(prog, ";") -local g, t = T.testC(prog) -assert(g == _G) -for i = 1,12000 do assert(t[i] == i*10); t[i] = nil end -assert(next(t) == nil) -prog, g, t = nil - --- testing errors - -a = T.testC([[ - loadstring 2; pcall 0,1; - pushvalue 3; insert -2; pcall 1, 1; - pcall 0, 0; - return 1 -]], "x=150", function (a) assert(a==nil); return 3 end) - -assert(type(a) == 'string' and x == 150) - -function check3(p, ...) - local arg = {...} - assert(#arg == 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")) - --- test errors in non protected threads -function checkerrnopro (code, msg) - L = coroutine.create(function () end) - local stt, err = pcall(T.testC, code) - assert(not stt and string.find(err, msg)) -end - -checkerrnopro("pushnum 3; call 0 0", "attempt to call") -function f () f() end -checkerrnopro("getglobal 'f'; call 0 0;", "stack overflow") - - --- 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 - - --- testing absent upvalues from C-function pointers -assert(T.testC[[isnull U1; return 1]] == true) -assert(T.testC[[isnull U100; return 1]] == true) -assert(T.testC[[pushvalue U1; return 1]] == nil) - -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") - - --- large closures -do - local A = "checkstack 300 msg;" .. - string.rep("pushnum 10;", 255) .. - "pushcclosure 255; return 1" - A = T.testC(A) - for i=1,255 do - assert(A(("pushvalue U%d; return 1"):format(i)) == 10) - end - assert(A("isnull U256; return 1")) - assert(not A("isnil U256; return 1")) -end - - - --- bug in 5.1.2 -assert(not pcall(debug.setuservalue, 3, {})) -assert(not pcall(debug.setuservalue, nil, {})) -assert(not pcall(debug.setuservalue, T.pushuserdata(1), {})) - -local b = T.newuserdata(0) -local a = {} -assert(debug.getuservalue(b) == nil) -assert(debug.setuservalue(b, a)) -assert(debug.getuservalue(b) == a) -assert(debug.setuservalue(b, nil)) -assert(debug.getuservalue(b) == nil) - -assert(debug.getuservalue(4) == nil) - - - --- 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 f = T.makeCfunc("gettable R; return 1") - local n = f("n") - print("n", n) - for i=0,n do - print(i, f(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) - assert(load("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 T.newuserdata(0) end - assert(collectgarbage("count") > x+10) - collectgarbage() - assert(collectgarbage("count") <= x+1) - -- udata with finalizer - x = collectgarbage("count") - collectgarbage() - collectgarbage("stop") - a = {__gc = function () end} - for i=1,1000 do debug.setmetatable(T.newuserdata(0), 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) - collectgarbage("restart") -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(not pcall(io.input, a)) -assert(not pcall(io.input, x)) - -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(#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(#cl == 4) --- check order of collection -assert(cl[2] == n5 and cl[3] == nb and cl[4] == na) - -collectgarbage"restart" - - -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(#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(#cl == 0) -for n in pairs(a) do a[n] = nil end -collectgarbage() -assert(#cl == 1 and cl[1] == x) -- old `x' must be collected - --- testing lua_equal -assert(T.testC("compare 2 4 0; return 1", print, 1, print, 20)) -assert(T.testC("compare 3 2 0; return 1", 'alo', "alo")) -assert(T.testC("compare 2 3 0; return 1", nil, nil)) -assert(not T.testC("compare 2 3 0; return 1", {}, {})) -assert(not T.testC("compare 2 3 0; return 1")) -assert(not T.testC("compare 2 3 0; 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("compare 2 3 0; return 1", f(10), f(10))) - assert(not T.testC("compare 2 3 0; return 1", f(10), f(20))) - t.__eq = nil - assert(f(10) ~= f(10)) -end - -print'+' - - - --- testing changing hooks during hooks -_G.t = {} -T.sethook([[ - # set a line hook after 3 count hooks - sethook 4 0 ' - getglobal t; - pushvalue -3; append -2 - pushvalue -2; append -2 - ']], "c", 3) -local a = 1 -- counting -a = 1 -- counting -a = 1 -- count hook (set line hook) -a = 1 -- line hook -a = 1 -- line hook -debug.sethook() -t = _G.t -assert(t[1] == "line") -line = t[2] -assert(t[3] == "line" and t[4] == line + 1) -assert(t[5] == "line" and t[6] == line + 2) -assert(t[7] == nil) - - -------------------------------------------------------------------------- -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 errors 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) load("A=A+1")() end}) - end - _G.A = 0 - a = 0 - while 1 do - local stat, msg = pcall(collectgarbage) - if stat then - break -- stop when no more errors - else - a = a + 1 - assert(string.find(msg, "__gc")) - 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(T.doremote(L1, "X='a'; return 'a'") == 'a') - - -assert(#pack(T.doremote(L1, "function f () return 'alo', 3 end; f()")) == 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 c == 3 and type(b) == "string") -- 3 == syntax error - -T.loadlib(L1) -a, b, c = T.doremote(L1, [[ - string = require'string' - a = require'_G'; assert(a == _G and require("_G") == a) - io = require'io'; assert(type(io.read) == "function") - assert(require("io") == io) - a = require'table'; assert(type(a.insert) == "function") - a = require'debug'; assert(type(a.getlocal) == "function") - a = require'math'; 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, [[getglobal "a"; pushstring "x"; pushnum 1; - settable -3]]) -assert(T.doremote(L1, "return a.x") == "1") - -T.closestate(L1) - -L1 = nil - -print('+') - -------------------------------------------------------------------------- --- testing memory limits -------------------------------------------------------------------------- -assert(not pcall(T.newuserdata, 2^32-4)) -collectgarbage() -T.totalmem(T.totalmem()+5000) -- set low memory limit (+5k) -assert(not pcall(load"local a={}; for i=1,100000 do a[i]=i end")) -T.totalmem(1000000000) -- restore high limit - --- 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(); collectgarbage() - local M = T.totalmem() - local oldM = M - local a,b = nil - while 1 do - M = M+7 -- increase memory limit in small steps - T.totalmem(M) - a, b = pcall(f) - T.totalmem(1000000000) -- restore high limit - if a and b then break end -- stop when no more errors - collectgarbage() - if not a and not -- `real' error? - (string.find(b, "memory") or string.find(b, "overflow")) then - error(b, 0) -- propagate it - end - end - 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 - --- get main thread from registry (at index LUA_RIDX_MAINTHREAD == 1) -mt = T.testC("rawgeti R 1; return 1") -assert(type(mt) == "thread" and coroutine.running() == mt) - - - -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") -load(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 load("x=1") -- try to do load a string -end) - - -local testprog = [[ -local function foo () return end -local t = {"x"} -a = "aaa" -for i = 1, #t do a=a..t[i] 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 = load(testprog) - local b = a and string.dump(a) - a = b and load(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) - -testamem("constructors", function () - local a = {10, 20, 30, 40, 50; a=1, b=2, c=3, d=4, e=5} - return (type(a) == 'table' and a.e == 5) -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 -local function gsub (a, b, c) - a, b = T.testC("gsub 2 3 4; gettop; return 2", a, b, c) - assert(b == 5) - return a -end - -assert(gsub("alo.alo.uhuh.", ".", "//") == "alo//alo//uhuh//") -assert(gsub("alo.alo.uhuh.", "alo", "//") == "//.//.uhuh.") -assert(gsub("", "alo", "//") == "") -assert(gsub("...", ".", "/.") == "/././.") -assert(gsub("...", "...", "") == "") - - --- testing luaL_newmetatable -local mt_xuxu, res, top = T.testC("newmetatable xuxu; gettop; return 3") -assert(type(mt_xuxu) == "table" and res and top == 3) -local d, res, top = T.testC("newmetatable xuxu; gettop; return 3") -assert(mt_xuxu == d and not res and top == 3) -d, res, top = T.testC("newmetatable xuxu1; gettop; return 3") -assert(mt_xuxu ~= d and res and top == 3) - -x = T.newuserdata(0); -y = T.newuserdata(0); -T.testC("pushstring xuxu; gettable R; setmetatable 2", x) -assert(getmetatable(x) == mt_xuxu) - --- testing luaL_testudata --- correct metatable -local res1, res2, top = T.testC([[testudata -1 xuxu - testudata 2 xuxu - gettop - return 3]], x) -assert(res1 and res2 and top == 4) - --- wrong metatable -res1, res2, top = T.testC([[testudata -1 xuxu1 - testudata 2 xuxu1 - gettop - return 3]], x) -assert(not res1 and not res2 and top == 4) - --- non-existent type -res1, res2, top = T.testC([[testudata -1 xuxu2 - testudata 2 xuxu2 - gettop - return 3]], x) -assert(not res1 and not res2 and top == 4) - --- userdata has no metatable -res1, res2, top = T.testC([[testudata -1 xuxu - testudata 2 xuxu - gettop - return 3]], y) -assert(not res1 and not res2 and top == 4) - --- erase metatables -do - local r = debug.getregistry() - assert(r.xuxu == mt_xuxu and r.xuxu1 == d) - r.xuxu = nil; r.xuxu1 = nil -end - -print'OK' - diff --git a/lua-5.2.2-tests/attrib.lua b/lua-5.2.2-tests/attrib.lua deleted file mode 100644 index 8cf287f997..0000000000 --- a/lua-5.2.2-tests/attrib.lua +++ /dev/null @@ -1,427 +0,0 @@ --- The tests for 'require' assume some specific directories and libraries; --- better to avoid them in generic machines - -if not _port then --[ - -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"coroutine" == coroutine) - -assert(type(package.path) == "string") -assert(type(package.cpath) == "string") -assert(type(package.loaded) == "table") -assert(type(package.preload) == "table") - -assert(type(package.config) == "string") -print("package config: "..string.gsub(package.config, "\n", "|")) - -do - -- create a path with 'max' templates, - -- each with 1-10 repetitions of '?' - local max = 2000 - local t = {} - for i = 1,max do t[i] = string.rep("?", i%10 + 1) end - t[#t + 1] = ";" -- empty template - local path = table.concat(t, ";") - -- use that path in a search - local s, err = package.searchpath("xuxu", path) - -- search fails; check that message has an occurence of - -- '??????????' with ? replaced by xuxu and at least 'max' lines - assert(not s and - string.find(err, string.rep("xuxu", 10)) and - #string.gsub(err, "[^\n]", "") >= max) - -- path with one very long template - local path = string.rep("?", max) - local s, err = package.searchpath("xuxu", path) - assert(not s and string.find(err, string.rep('xuxu', max))) -end - -do - local oldpath = package.path - package.path = {} - local s, err = pcall(require, "no-such-file") - assert(not s and string.find(err, "package.path")) - package.path = oldpath -end - -print('+') - --- auxiliary directory with C modules and temporary files -local DIR = "libs/" - --- prepend DIR to a name -local function D (x) return DIR .. x end - - -local function createfiles (files, preextras, posextras) - for n,c in pairs(files) do - io.output(D(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(D(n)) - end -end - -local files = { - ["names.lua"] = "do return {...} end\n", - ["err.lua"] = "B = 15; a = a + 1;", - ["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) - --- testing explicit "dir" separator in 'searchpath' -assert(package.searchpath("C.lua", D"?", "", "") == D"C.lua") -assert(package.searchpath("C.lua", D"?", ".", ".") == D"C.lua") -assert(package.searchpath("--x-", D"?", "-", "X") == D"XXxX") -assert(package.searchpath("---xX", D"?", "---", "XX") == D"XXxX") -assert(package.searchpath(D"C.lua", "?", "/") == D"C.lua") -assert(package.searchpath(".\\C.lua", D"?", "\\") == D"./C.lua") - -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 - -a = require"names" --- FIXME LuaJIT ---assert(a[1] == "names" and a[2] == D"names.lua") - -_G.a = nil -assert(not pcall(require, "err")) -assert(B == 15) - -assert(package.searchpath("C", package.path) == D"C.lua") -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) -assert(require"C" == 25) -package.loaded.A = nil -try('B', nil, true) -- should not reload package -try('A', 'A.lua', true) -package.loaded.A = nil -os.remove(D'A.lua') -AA = {} -try('A', 'A.lc', AA) -- now must find second option -assert(package.searchpath("A", package.path) == D"A.lc") -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 - -local _G = _G - -package.path = string.gsub("D/?.lua;D/?/init.lua", "D/", DIR) - -files = { - ["P1/init.lua"] = "AA = 10", - ["P1/xuxu.lua"] = "AA = 20", -} - -createfiles(files, "_ENV = {}\n", "\nreturn _ENV\n") -AA = 0 - -local m = assert(require"P1") --- FIXME LuaJIT ---assert(AA == 0 and m.AA == 10) -assert(require"P1" == m) -assert(require"P1" == m) - -assert(package.searchpath("P1.xuxu", package.path) == D"P1/xuxu.lua") -m.xuxu = assert(require"P1.xuxu") --- FIXME LuaJIT ---assert(AA == 0 and m.xuxu.AA == 20) -assert(require"P1.xuxu" == m.xuxu) -assert(require"P1.xuxu" == m.xuxu) --- FIXME LuaJIT ---assert(require"P1" == m and m.AA == 10) - - -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 - --- cannot change environment of a C function -assert(not pcall(module, 'XUXU')) - - - --- testing require of C libraries - - -local p = "" -- On Mac OS X, redefine this to "_" - --- check whether loadlib works in this system -local st, err, when = package.loadlib(D"lib1.so", "*") -if not st then - local f, err, when = package.loadlib("donotexist", p.."xuxu") - -- FIXME LuaJIT - --assert(not f and type(err) == "string" and when == "absent") - ;(Message or print)('\a\n >>> cannot load dynamic library <<<\n\a') - print(err, when) -else - -- tests for loadlib - local f = assert(package.loadlib(D"lib1.so", p.."onefunction")) - local a, b = f(15, 25) - assert(a == 25 and b == 15) - - f = assert(package.loadlib(D"lib1.so", p.."anotherfunc")) - assert(f(10, 20) == "1020\n") - - -- check error messages - local f, err, when = package.loadlib(D"lib1.so", p.."xuxu") - assert(not f and type(err) == "string" and when == "init") - f, err, when = package.loadlib("donotexist", p.."xuxu") - assert(not f and type(err) == "string" and when == "open") - - -- symbols from 'lib1' must be visible to other libraries - f = assert(package.loadlib(D"lib11.so", p.."luaopen_lib11")) - assert(f() == "exported") - - -- test C modules with prefixes in names - package.cpath = D"?.so" - local lib2 = require"v-lib2" - -- check correct access to global environment and correct - -- parameters - assert(_ENV.x == "v-lib2" and _ENV.y == D"v-lib2.so") - assert(lib2.id("x") == "x") - - -- test C submodules - local fs = require"lib1.sub" - assert(_ENV.x == "lib1.sub" and _ENV.y == D"lib1.so") - assert(fs.id(45) == 45) -end - -_ENV = _G - - --- testing preload - -do - local p = package - package = {} - p.preload.pl = function (...) - local _ENV = {...} - function xuxu (x) return x+20 end - return _ENV - end - - local pl = require"pl" - assert(require"pl" == pl) - -- FIXME LuaJIT - --assert(pl.xuxu(10) == 30) - assert(pl[1] == "pl" and pl[2] == nil) - - package = p - assert(type(package.path) == "string") -end - -print('+') - -end --] - -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 table.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(ab == 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) - -assert({} ~= {}) -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]) -assert(not pcall(function () local a = {}; a[nil] = 10 end)) -assert(not pcall(function () local a = {[nil] = 10} end)) -assert(a[nil] == nil) -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 - - --- test conflicts in multiple assignment -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 - --- repeat test with upvalues -do - local a,i,j,b - a = {'a', 'b'}; i=1; j=2; b=a - local function foo () - i, a[i], a, j, a[j], a[i+j] = j, i, i, b, j, i - end - foo() - assert(i == 2 and b[1] == 1 and a == 1 and j == b and b[2] == 2 and - b[3] == 1) - local t = {} - (function (a) t[a], a = 10, 20 end)(1); - assert(t[1] == 10) -end - --- bug in 5.2 beta -local function foo () - local a - return function () - local b - a, b = 3, 14 -- local and upvalue have same index - return a, b - end -end - -local a, b = foo()() -assert(a == 3 and b == 14) - -print('OK') - -return res - diff --git a/lua-5.2.2-tests/big.lua b/lua-5.2.2-tests/big.lua deleted file mode 100644 index 0c8ab2017c..0000000000 --- a/lua-5.2.2-tests/big.lua +++ /dev/null @@ -1,79 +0,0 @@ -if _soft then - return 'a' -end - -print "testing large tables" - -local debug = require"debug" - -local lim = 2^18 + 1000 -local prog = { "local y = {0" } -for i = 1, lim do prog[#prog + 1] = i end -prog[#prog + 1] = "}\n" -prog[#prog + 1] = "X = y\n" -prog[#prog + 1] = ("assert(X[%d] == %d)"):format(lim - 1, lim - 2) -prog[#prog + 1] = "return 0" -prog = table.concat(prog, ";") - -local env = {string = string, assert = assert} -local f = assert(load(prog, nil, nil, env)) - -f() -assert(env.X[lim] == lim - 1 and env.X[lim + 1] == lim) -for k in pairs(env) do env[k] = nil end - --- yields during accesses larger than K (in RK) -setmetatable(env, { - __index = function (t, n) coroutine.yield('g'); return _G[n] end, - __newindex = function (t, n, v) coroutine.yield('s'); _G[n] = v end, -}) - -X = nil -co = coroutine.wrap(f) -assert(co() == 's') -assert(co() == 'g') -assert(co() == 'g') -assert(co() == 0) - -assert(X[lim] == lim - 1 and X[lim + 1] == lim) - --- errors in accesses larger than K (in RK) -getmetatable(env).__index = function () end -getmetatable(env).__newindex = function () end -local e, m = pcall(f) -assert(not e and m:find("global 'X'")) - --- errors in metamethods -getmetatable(env).__newindex = function () error("hi") end -local e, m = xpcall(f, debug.traceback) -assert(not e and m:find("'__newindex'")) - -f, X = nil - -coroutine.yield'b' - -if not _no32 then -- { - -print "testing string length overflow" - -local repstrings = 192 -- number of strings to be concatenated -local ssize = math.ceil(2^32 / repstrings) + 1 -- size of each string - -assert(repstrings * ssize > 2^32) -- this should be larger than maximum size_t - -local longs = string.rep("\0", ssize) -- create one long string - --- create function to concatentate 'repstrings' copies of its argument -local rep = assert(load( - "local a = ...; return " .. string.rep("a", repstrings, ".."))) - -local a, b = pcall(rep, longs) -- call that function - --- it should fail without creating string (result would be too large) -assert(not a and string.find(b, "overflow")) - -end -- } - -print'OK' - -return 'a' diff --git a/lua-5.2.2-tests/bitwise.lua b/lua-5.2.2-tests/bitwise.lua deleted file mode 100755 index afa158ddf8..0000000000 --- a/lua-5.2.2-tests/bitwise.lua +++ /dev/null @@ -1,115 +0,0 @@ -print("testing bitwise operations") - -assert(bit32.band() == bit32.bnot(0)) -assert(bit32.btest() == true) -assert(bit32.bor() == 0) -assert(bit32.bxor() == 0) - -assert(bit32.band() == bit32.band(0xffffffff)) -assert(bit32.band(1,2) == 0) - - --- out-of-range numbers -assert(bit32.band(-1) == 0xffffffff) -assert(bit32.band(2^33 - 1) == 0xffffffff) -assert(bit32.band(-2^33 - 1) == 0xffffffff) -assert(bit32.band(2^33 + 1) == 1) -assert(bit32.band(-2^33 + 1) == 1) -assert(bit32.band(-2^40) == 0) -assert(bit32.band(2^40) == 0) -assert(bit32.band(-2^40 - 2) == 0xfffffffe) -assert(bit32.band(2^40 - 4) == 0xfffffffc) - -assert(bit32.lrotate(0, -1) == 0) -assert(bit32.lrotate(0, 7) == 0) -assert(bit32.lrotate(0x12345678, 4) == 0x23456781) -assert(bit32.rrotate(0x12345678, -4) == 0x23456781) -assert(bit32.lrotate(0x12345678, -8) == 0x78123456) -assert(bit32.rrotate(0x12345678, 8) == 0x78123456) -assert(bit32.lrotate(0xaaaaaaaa, 2) == 0xaaaaaaaa) -assert(bit32.lrotate(0xaaaaaaaa, -2) == 0xaaaaaaaa) -for i = -50, 50 do - assert(bit32.lrotate(0x89abcdef, i) == bit32.lrotate(0x89abcdef, i%32)) -end - -assert(bit32.lshift(0x12345678, 4) == 0x23456780) -assert(bit32.lshift(0x12345678, 8) == 0x34567800) -assert(bit32.lshift(0x12345678, -4) == 0x01234567) -assert(bit32.lshift(0x12345678, -8) == 0x00123456) -assert(bit32.lshift(0x12345678, 32) == 0) -assert(bit32.lshift(0x12345678, -32) == 0) -assert(bit32.rshift(0x12345678, 4) == 0x01234567) -assert(bit32.rshift(0x12345678, 8) == 0x00123456) -assert(bit32.rshift(0x12345678, 32) == 0) -assert(bit32.rshift(0x12345678, -32) == 0) -assert(bit32.arshift(0x12345678, 0) == 0x12345678) -assert(bit32.arshift(0x12345678, 1) == 0x12345678 / 2) -assert(bit32.arshift(0x12345678, -1) == 0x12345678 * 2) -assert(bit32.arshift(-1, 1) == 0xffffffff) -assert(bit32.arshift(-1, 24) == 0xffffffff) -assert(bit32.arshift(-1, 32) == 0xffffffff) -assert(bit32.arshift(-1, -1) == (-1 * 2) % 2^32) - -print("+") --- some special cases -local c = {0, 1, 2, 3, 10, 0x80000000, 0xaaaaaaaa, 0x55555555, - 0xffffffff, 0x7fffffff} - -for _, b in pairs(c) do - assert(bit32.band(b) == b) - assert(bit32.band(b, b) == b) - assert(bit32.btest(b, b) == (b ~= 0)) - assert(bit32.band(b, b, b) == b) - assert(bit32.btest(b, b, b) == (b ~= 0)) - assert(bit32.band(b, bit32.bnot(b)) == 0) - assert(bit32.bor(b, bit32.bnot(b)) == bit32.bnot(0)) - assert(bit32.bor(b) == b) - assert(bit32.bor(b, b) == b) - assert(bit32.bor(b, b, b) == b) - assert(bit32.bxor(b) == b) - assert(bit32.bxor(b, b) == 0) - assert(bit32.bxor(b, 0) == b) - assert(bit32.bnot(b) ~= b) - assert(bit32.bnot(bit32.bnot(b)) == b) - assert(bit32.bnot(b) == 2^32 - 1 - b) - assert(bit32.lrotate(b, 32) == b) - assert(bit32.rrotate(b, 32) == b) - assert(bit32.lshift(bit32.lshift(b, -4), 4) == bit32.band(b, bit32.bnot(0xf))) - assert(bit32.rshift(bit32.rshift(b, 4), -4) == bit32.band(b, bit32.bnot(0xf))) - for i = -40, 40 do - assert(bit32.lshift(b, i) == math.floor((b * 2^i) % 2^32)) - end -end - -assert(not pcall(bit32.band, {})) -assert(not pcall(bit32.bnot, "a")) -assert(not pcall(bit32.lshift, 45)) -assert(not pcall(bit32.lshift, 45, print)) -assert(not pcall(bit32.rshift, 45, print)) - -print("+") - - --- testing extract/replace - -assert(bit32.extract(0x12345678, 0, 4) == 8) -assert(bit32.extract(0x12345678, 4, 4) == 7) -assert(bit32.extract(0xa0001111, 28, 4) == 0xa) -assert(bit32.extract(0xa0001111, 31, 1) == 1) -assert(bit32.extract(0x50000111, 31, 1) == 0) -assert(bit32.extract(0xf2345679, 0, 32) == 0xf2345679) - -assert(not pcall(bit32.extract, 0, -1)) -assert(not pcall(bit32.extract, 0, 32)) -assert(not pcall(bit32.extract, 0, 0, 33)) -assert(not pcall(bit32.extract, 0, 31, 2)) - -assert(bit32.replace(0x12345678, 5, 28, 4) == 0x52345678) -assert(bit32.replace(0x12345678, 0x87654321, 0, 32) == 0x87654321) -assert(bit32.replace(0, 1, 2) == 2^2) -assert(bit32.replace(0, -1, 4) == 2^4) -assert(bit32.replace(-1, 0, 31) == 2^31 - 1) -assert(bit32.replace(-1, 0, 1, 2) == 2^32 - 7) - - -print'OK' diff --git a/lua-5.2.2-tests/calls.lua b/lua-5.2.2-tests/calls.lua deleted file mode 100644 index 8bf4e2cf10..0000000000 --- a/lua-5.2.2-tests/calls.lua +++ /dev/null @@ -1,314 +0,0 @@ -print("testing functions and calls") - -local debug = require "debug" - --- 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*load("return fat(" .. x-1 .. ")")() - end -end - -assert(load "load 'assert(fat(6)==720)' () ")() -a = load('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) - - --- testing closures - --- fixed-point operator -Z = 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 = Z(F) - -assert(fat(0) == 1 and fat(4) == 24 and Z(F)(5)==5*Z(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) - -Z, F, f = nil -print('+') - --- testing multiple returns - -function unlpack (t, i) - i = i or 1 - if (i <= #t) then - return t[i], unlpack(t, i+1) - end -end - -function equaltab (t1, t2) - assert(#t1 == #t2) - for i = 1, #t1 do - assert(t1[i] == t2[i]) - end -end - -local pack = function (...) return (table.pack(...)) 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" 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/lua-5.2.2-tests/closure.lua b/lua-5.2.2-tests/closure.lua deleted file mode 100644 index f7197bdf04..0000000000 --- a/lua-5.2.2-tests/closure.lua +++ /dev/null @@ -1,247 +0,0 @@ -print "testing closures" - -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 - -local 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 equality -a = {} -for i = 1, 5 do a[i] = function (x) return x + a + _ENV end end --- FIXME LuaJIT ---assert(a[3] == a[4] and a[4] == a[5]) - -for i = 1, 5 do a[i] = function (x) return i + a + _ENV end end -assert(a[3] ~= a[4] and a[4] ~= a[5]) - -local function f() - return function (x) return math.sin(_ENV[x]) end -end --- FIXME LuaJIT ---assert(f() == f()) - - --- 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 = {} -local t = {"a", "b"} -for i = 1, #t do - local k = t[i] - 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 = 1, #t do - local v = t[k] - 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) - - --- testing closures created in 'then' and 'else' parts of 'if's -a = {} -for i = 1, 10 do - if i % 3 == 0 then - local y = 0 - a[i] = function (x) local t = y; y = x; return t end - elseif i % 3 == 1 then - goto L1 - error'not here' - ::L1:: - local y = 1 - a[i] = function (x) local t = y; y = x; return t end - elseif i % 3 == 2 then - local t - goto l4 - ::l4a:: a[i] = t; goto l4b - error("should never be here!") - ::l4:: - local y = 2 - t = function (x) local t = y; y = x; return t end - goto l4a - error("should never be here!") - ::l4b:: - end -end - -for i = 1, 10 do - assert(a[i](i * 10) == i % 3 and a[i]() == i * 10) -end - -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() - - --- test for debug manipulation of upvalues -local debug = require'debug' - -do - local a , b, c = 3, 5, 7 - foo1 = function () return a+b end; - foo2 = function () return b+a end; - do - local a = 10 - foo3 = function () return a+b end; - end -end - -assert(debug.upvalueid(foo1, 1)) -assert(debug.upvalueid(foo1, 2)) -assert(not pcall(debug.upvalueid, foo1, 3)) -assert(debug.upvalueid(foo1, 1) == debug.upvalueid(foo2, 2)) -assert(debug.upvalueid(foo1, 2) == debug.upvalueid(foo2, 1)) -assert(debug.upvalueid(foo3, 1)) -assert(debug.upvalueid(foo1, 1) ~= debug.upvalueid(foo3, 1)) -assert(debug.upvalueid(foo1, 2) == debug.upvalueid(foo3, 2)) - -assert(debug.upvalueid(string.gmatch("x", "x"), 1) ~= nil) - -assert(foo1() == 3 + 5 and foo2() == 5 + 3) -debug.upvaluejoin(foo1, 2, foo2, 2) --- FIXME LuaJIT ---assert(foo1() == 3 + 3 and foo2() == 5 + 3) -assert(foo3() == 10 + 5) -debug.upvaluejoin(foo3, 2, foo2, 1) -assert(foo3() == 10 + 5) -debug.upvaluejoin(foo3, 2, foo2, 2) -assert(foo3() == 10 + 3) - -assert(not pcall(debug.upvaluejoin, foo1, 3, foo2, 1)) -assert(not pcall(debug.upvaluejoin, foo1, 1, foo2, 3)) -assert(not pcall(debug.upvaluejoin, foo1, 0, foo2, 1)) -assert(not pcall(debug.upvaluejoin, print, 1, foo2, 1)) -assert(not pcall(debug.upvaluejoin, {}, 1, foo2, 1)) -assert(not pcall(debug.upvaluejoin, foo1, 1, print, 1)) - -print'OK' diff --git a/lua-5.2.2-tests/code.lua b/lua-5.2.2-tests/code.lua deleted file mode 100644 index a0317c5524..0000000000 --- a/lua-5.2.2-tests/code.lua +++ /dev/null @@ -1,182 +0,0 @@ -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 arg = {...} - local c = T.listcode(f) - for i=1, #arg do - -- print(arg[i], c[i]) - assert(string.find(c[i], '- '..arg[i]..' *%d')) - end - assert(c[#arg+2] == nil) -end - - -function checkequal (a, b) - a = T.listcode(a) - b = T.listcode(b) - for i = 1, #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', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN') - - --- sequence of LOADNILs -check(function () - local a,b,c - local d; local e; - local f,g,h; - d = nil; d=nil; b=nil; a=nil; c=nil; -end, 'LOADNIL', 'RETURN') - -check(function () - local a,b,c,d = 1,1,1,1 - d=nil;c=nil;b=nil;a=nil -end, 'LOADK', 'LOADK', 'LOADK', 'LOADK', 'LOADNIL', 'RETURN') - -do - local a,b,c,d = 1,1,1,1 - d=nil;c=nil;b=nil;a=nil - assert(a == nil and b == nil and c == nil and d == nil) -end - - --- 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 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, - 'LOADNIL', - '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, - 'LOADNIL', - 'SETTABLE', 'SETTABLE', 'SETTABLE', 'SUB', 'DIV', 'LOADK', - 'SETTABLE', 'RETURN') - --- constant folding -local function f () return -((2^8 + -(-1)) % 8)/2 * 4 - 3 end - -check(f, 'LOADK', 'RETURN') -assert(f() == -5) - - --- bug in constant folding for 5.1 -check(function () return -nil end, - 'LOADNIL', 'UNM', 'RETURN') - - -check(function () - local a,b,c - b[c], a = c, b - b[a], a = c, b - a, b = c, a - a = a -end, - 'LOADNIL', - '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, -'GETTABUP', 'EQ', 'JMP', 'SETTABUP', '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) - - --- if-goto optimizations -check(function (a) - if a == 1 then goto l1 - elseif a == 2 then goto l2 - elseif a == 3 then goto l2 - else if a == 4 then goto l3 - else goto l3 - end - end - ::l1:: ::l2:: ::l3:: ::l4:: -end, 'EQ', 'JMP', 'EQ', 'JMP', 'EQ', 'JMP', 'EQ', 'JMP', 'JMP', 'RETURN') - -checkequal( -function (a) while a < 10 do a = a + 1 end end, -function (a) ::L2:: if not(a < 10) then goto L1 end; a = a + 1; - goto L2; ::L1:: end -) - -checkequal( -function (a) while a < 10 do a = a + 1 end end, -function (a) while true do if not(a < 10) then break end; a = a + 1; end end -) - -print 'OK' - diff --git a/lua-5.2.2-tests/constructs.lua b/lua-5.2.2-tests/constructs.lua deleted file mode 100644 index 6dd77fe291..0000000000 --- a/lua-5.2.2-tests/constructs.lua +++ /dev/null @@ -1,310 +0,0 @@ -;;print "testing syntax";; - -local debug = require "debug" - --- testing semicollons -do ;;; end -; do ; a = 3; assert(a == 3) end; -; - - --- 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) - --- old bug -assert((((1 or false) and true) or false) == true) -assert((((nil and true) or false) and true) == false) - -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 = load(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.fmod(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(load(s))() - assert(X and not NX and not WX1 == K and not WX2 == K) - if math.fmod(i,4000) == 0 then print('+') end - i = i+1 -until i==c - -print '+' - ------------------------------------------------------------------- -print 'testing short-circuit optimizations' - -_ENV.GLOB1 = 1 -_ENV.GLOB2 = 2 - -local basiccases = { - {"nil", nil}, - {"false", false}, - {"true", true}, - {"10", 10}, - {"(_ENV.GLOB1 < _ENV.GLOB2)", true}, - {"(_ENV.GLOB2 < _ENV.GLOB1)", false}, -} - - -local binops = { - {" and ", function (a,b) if not a then return a else return b end end}, - {" or ", function (a,b) if a then return a else return b end end}, -} - -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 - for _, op in ipairs(binops) do - res[#res + 1] = { - "(" .. v1[1] .. op[1] .. v2[1] .. ")", - op[2](v1[2], v2[2]) - } - end - end - end - print('+') - end - mem[n] = res -- memoize - return res -end - --- do not do too many combinations for soft tests -local level = _soft and 3 or 4 - -for _, v in pairs(allcases(level)) do - local res = load("return " .. v[1])() - assert(res == v[2]) -end ------------------------------------------------------------------- - -print'OK' diff --git a/lua-5.2.2-tests/coroutine.lua b/lua-5.2.2-tests/coroutine.lua deleted file mode 100644 index ccfcfd4465..0000000000 --- a/lua-5.2.2-tests/coroutine.lua +++ /dev/null @@ -1,733 +0,0 @@ -print "testing coroutines" - ---FIXME LuaJIT -T = nil - -local debug = require'debug' - -local f - -local main, ismain = coroutine.running() -assert(type(main) == "thread" and ismain) -assert(not coroutine.resume(main)) -assert(not pcall(coroutine.yield)) - - - --- tests for multiple yield/resume arguments - -local function eqtab (t1, t2) - assert(#t1 == #t2) - for i = 1, #t1 do - local v = t1[i] - assert(t2[i] == v) - end -end - -_G.x = nil -- declare x -function foo (a, ...) - local x, y = coroutine.running() - assert(x == f and y == false) - assert(coroutine.status(f) == "running") - local arg = {...} - for i=1,#arg do - _G.x = {coroutine.yield(table.unpack(arg[i]))} - end - return table.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.fmod(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(#a == 25 and a[#a] == 97) - - --- yielding across C boundaries - -co = coroutine.wrap(function() - assert(not pcall(table.sort,{1,2,3}, coroutine.yield)) - coroutine.yield(20) - return 30 - end) - -assert(co() == 20) -assert(co() == 30) - - -local f = function (s, i) return coroutine.yield(i) end - -local f1 = coroutine.wrap(function () - return xpcall(pcall, function (...) return ... end, - function () - local s = 0 - for i in f, nil, 1 do pcall(function () s = s + i end) end - error({s}) - end) - end) - -f1() -for i = 1, 10 do assert(f1(i) == i) end -local r1, r2, v = f1(nil) -assert(r1 and not r2 and v[1] == (10 + 1)*10/2) - - -function f (a, b) a = coroutine.yield(a); error{a + b} end -function g(x) return x[1]*2 end - -co = coroutine.wrap(function () - coroutine.yield(xpcall(f, g, 10, 20)) - end) - -assert(co() == 10) -r, msg = co(100) -assert(not r and msg == 240) - - --- 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) - - --- attempt to resume 'normal' coroutine -co1 = coroutine.create(function () return co2() end) -co2 = coroutine.wrap(function () - assert(coroutine.status(co1) == 'normal') - assert(not coroutine.resume(co1)) - coroutine.yield(3) - end) - -a,b = coroutine.resume(co1) -assert(a and b == 3) -assert(coroutine.status(co1) == 'dead') - --- infinite recursion of coroutines --- FIXME LuaJIT ---a = function(a) coroutine.wrap(a)(a) end ---assert(not pcall(a, a)) - - --- 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 - print "testing yields inside hooks" - - 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.sethook("yield 0", "", 2) - A = fact("A", 10) - end) - - local y = coroutine.create(function () - T.sethook("yield 0", "", 3) - B = fact("B", 11) - end) - - while A==0 or B==0 do - if A==0 then turn = "A"; assert(T.resume(x)) end - if B==0 then turn = "B"; assert(T.resume(y)) end - end - - assert(B/A == 11) - - local line = debug.getinfo(1, "l").currentline + 2 -- get line number - local function foo () - local x = 10 --<< this line is 'line' - x = x + 10 - _G.XX = x - end - - -- testing yields in line hook - local co = coroutine.wrap(function () - T.sethook("setglobal X; yield 0", "l", 0); foo(); return 10 end) - - _G.XX = nil; - _G.X = nil; co(); assert(_G.X == line) - _G.X = nil; co(); assert(_G.X == line + 1) - _G.X = nil; co(); assert(_G.X == line + 2 and _G.XX == nil) - _G.X = nil; co(); assert(_G.X == line + 3 and _G.XX == 20) - assert(co() == 10) - - -- testing yields in count hook - co = coroutine.wrap(function () - T.sethook("yield 0", "", 1); foo(); return 10 end) - - _G.XX = nil; - local c = 0 - repeat c = c + 1; local a = co() until a == 10 - assert(_G.XX == 20 and c == 10) - - co = coroutine.wrap(function () - T.sethook("yield 0", "", 2); foo(); return 10 end) - - _G.XX = nil; - local c = 0 - repeat c = c + 1; local a = co() until a == 10 - assert(_G.XX == 20 and c == 5) - _G.X = nil; _G.XX = nil - - - print "testing coroutine API" - - -- reusing a thread - assert(T.testC([[ - newthread # create thread - pushvalue 2 # push body - pushstring 'a a a' # push argument - xmove 0 3 2 # move values to new thread - resume -1, 1 # call it first time - pushstatus - xmove 3 0 0 # move results back to stack - setglobal X # result - setglobal Y # status - pushvalue 2 # push body (to call it again) - pushstring 'b b b' - xmove 0 3 2 - resume -1, 1 # call it again - pushstatus - xmove 3 0 0 - return 1 # return result - ]], function (...) return ... end) == 'b b b') - - assert(X == 'a a a' and Y == 'OK') - - - -- resuming running coroutine - C = coroutine.create(function () - return T.testC([[ - pushnum 10; - pushnum 20; - resume -3 2; - pushstatus - gettop; - return 3]], C) - end) - local a, b, c, d = coroutine.resume(C) - assert(a == true and string.find(b, "non%-suspended") and - c == "ERRRUN" and d == 4) - - a, b, c, d = T.testC([[ - rawgeti R 1 # get main thread - pushnum 10; - pushnum 20; - resume -3 2; - pushstatus - gettop; - return 4]]) - assert(a == coroutine.running() and string.find(b, "non%-suspended") and - c == "ERRRUN" and d == 4) - - - -- using a main thread as a coroutine - local state = T.newstate() - T.loadlib(state) - - assert(T.doremote(state, [[ - coroutine = require'coroutine'; - X = function (x) coroutine.yield(x, 'BB'); return 'CC' end; - return 'ok']])) - - t = table.pack(T.testC(state, [[ - rawgeti R 1 # get main thread - pushstring 'XX' - getglobal X # get function for body - pushstring AA # arg - resume 1 1 # 'resume' shadows previous stack! - gettop - setglobal T # top - setglobal B # second yielded value - setglobal A # fist yielded value - rawgeti R 1 # get main thread - pushnum 5 # arg (noise) - resume 1 1 # after coroutine ends, previous stack is back - pushstatus - gettop - return . - ]])) - assert(t.n == 4 and t[2] == 'XX' and t[3] == 'CC' and t[4] == 'OK') - assert(T.doremote(state, "return T") == '2') - assert(T.doremote(state, "return A") == 'AA') - assert(T.doremote(state, "return B") == 'BB') - - T.closestate(state) - - print'+' - -end - - --- leaving a pending coroutine open -_X = coroutine.wrap(function () - local a = 10 - local x = function () a = a+1 end - coroutine.yield() - end) - -_X() - - -if not _soft then - -- bug (stack overflow) - local j = 2^9 - local lim = 1000000 -- (C stack limit; assume 32-bit machine) - local t = {lim - 10, lim - 5, lim - 1, lim, lim + 1} - for i = 1, #t do - local j = t[i] - co = coroutine.create(function() - local t = {} - for i = 1, j do t[i] = i end - return table.unpack(t) - end) - local r, msg = coroutine.resume(co) - assert(not r) - end -end - - -assert(coroutine.running() == main) - -print"+" - - -print"testing yields inside metamethods" - -local mt = { - __eq = function(a,b) coroutine.yield(nil, "eq"); return a.x == b.x end, - __lt = function(a,b) coroutine.yield(nil, "lt"); return a.x < b.x end, - __le = function(a,b) coroutine.yield(nil, "le"); return a - b <= 0 end, - __add = function(a,b) coroutine.yield(nil, "add"); return a.x + b.x end, - __sub = function(a,b) coroutine.yield(nil, "sub"); return a.x - b.x end, - __concat = function(a,b) - coroutine.yield(nil, "concat"); - a = type(a) == "table" and a.x or a - b = type(b) == "table" and b.x or b - return a .. b - end, - __index = function (t,k) coroutine.yield(nil, "idx"); return t.k[k] end, - __newindex = function (t,k,v) coroutine.yield(nil, "nidx"); t.k[k] = v end, -} - - -local function new (x) - return setmetatable({x = x, k = {}}, mt) -end - - -local a = new(10) -local b = new(12) -local c = new"hello" - -local function run (f, t) - local i = 1 - local c = coroutine.wrap(f) - while true do - local res, stat = c() - if res then assert(t[i] == nil); return res, t end - assert(stat == t[i]) - i = i + 1 - end -end - - -assert(run(function () if (a>=b) then return '>=' else return '<' end end, - {"le", "sub"}) == "<") --- '<=' using '<' -mt.__le = nil -assert(run(function () if (a<=b) then return '<=' else return '>' end end, - {"lt"}) == "<=") -assert(run(function () if (a==b) then return '==' else return '~=' end end, - {"eq"}) == "~=") - -assert(run(function () return a..b end, {"concat"}) == "1012") - -assert(run(function() return a .. b .. c .. a end, - {"concat", "concat", "concat"}) == "1012hello10") - -assert(run(function() return "a" .. "b" .. a .. "c" .. c .. b .. "x" end, - {"concat", "concat", "concat"}) == "ab10chello12x") - -assert(run(function () - a.BB = print - return a.BB - end, {"nidx", "idx"}) == print) - --- getuptable & setuptable -do local _ENV = _ENV - f = function () AAA = BBB + 1; return AAA end -end -g = new(10); g.k.BBB = 10; -debug.setupvalue(f, 1, g) ---FIXME LuaJIT ---assert(run(f, {"idx", "nidx", "idx"}) == 11) ---assert(g.k.AAA == 11) - -print"+" - -print"testing yields inside 'for' iterators" - -local f = function (s, i) - if i%2 == 0 then coroutine.yield(nil, "for") end - if i < s then return i + 1 end - end - -assert(run(function () - local s = 0 - for i in f, 4, 0 do s = s + i end - return s - end, {"for", "for", "for"}) == 10) - - - --- tests for coroutine API -if T==nil then - (Message or print)('\a\n >>> testC not active: skipping coroutine API tests <<<\n\a') - return -end - -print('testing coroutine API') - -local function apico (...) - local x = {...} - return coroutine.wrap(function () - return T.testC(table.unpack(x)) - end) -end - -local a = {apico( -[[ - pushstring errorcode - pcallk 1 0 2; - invalid command (should not arrive here) -]], -[[getctx; gettop; return .]], -"stackmark", -error -)()} -assert(#a == 6 and - a[3] == "stackmark" and - a[4] == "errorcode" and - a[5] == "ERRRUN" and - a[6] == 2) -- 'ctx' to pcallk - -local co = apico( - "pushvalue 2; pushnum 10; pcallk 1 2 3; invalid command;", - coroutine.yield, - "getctx; pushvalue 2; pushstring a; pcallk 1 0 4; invalid command", - "getctx; gettop; return .") - -assert(co() == 10) -assert(co(20, 30) == 'a') -a = {co()} -assert(#a == 10 and - a[2] == coroutine.yield and - a[5] == 20 and a[6] == 30 and - a[7] == "YIELD" and a[8] == 3 and - a[9] == "YIELD" and a[10] == 4) -assert(not pcall(co)) -- coroutine is dead now - - -f = T.makeCfunc("pushnum 3; pushnum 5; yield 1;") -co = coroutine.wrap(function () - assert(f() == 23); assert(f() == 23); return 10 -end) -assert(co(23,16) == 5) -assert(co(23,16) == 5) -assert(co(23,16) == 10) - - --- testing coroutines with C bodies -f = T.makeCfunc([[ - pushnum 102 - yieldk 1 U2 - return 2 -]], -[[ - pushnum 23 # continuation - gettop - return . -]]) - -x = coroutine.wrap(f) -assert(x() == 102) -assert(x() == 23) - - -f = T.makeCfunc[[pushstring 'a'; pushnum 102; yield 2; ]] - -a, b, c, d = T.testC([[newthread; pushvalue 2; xmove 0 3 1; resume 3 0; - pushstatus; xmove 3 0 0; resume 3 0; pushstatus; - return 4; ]], f) - -assert(a == 'YIELD' and b == 'a' and c == 102 and d == 'OK') - - --- testing chain of suspendable C calls - -local count = 3 -- number of levels - -f = T.makeCfunc([[ - remove 1; # remove argument - pushvalue U3; # get selection function - call 0 1; # call it (result is 'f' or 'yield') - pushstring hello # single argument for selected function - pushupvalueindex 2; # index of continuation program - callk 1 -1 .; # call selected function - errorerror # should never arrive here -]], -[[ - # continuation program - pushnum 34 # return value - gettop - return . # return all results -]], -function () -- selection function - count = count - 1 - if count == 0 then return coroutine.yield - else return f - end -end -) - -co = coroutine.wrap(function () return f(nil) end) -assert(co() == "hello") -- argument to 'yield' -a = {co()} --- three '34's (one from each pending C call) -assert(#a == 3 and a[1] == a[2] and a[2] == a[3] and a[3] == 34) - - --- testing yields with continuations - -co = coroutine.wrap(function (...) return - T.testC([[ - getctx - yieldk 3 2 - nonexec error - ]], - [[ # continuation - getctx - yieldk 2 3 - ]], - [[ # continuation - getctx - yieldk 2 4 - ]], - [[ # continuation - pushvalue 6; pushnum 10; pushnum 20; - pcall 2 0 # call should throw an error and execution continues - pop 1 # remove error message - pushvalue 6 - getctx - pcallk 2 2 5 # call should throw an error and jump to continuation - cannot be here! - ]], - [[ # continuation - gettop - return . - ]], - function (a,b) x=a; y=b; error("errmsg") end, - ... -) -end) - -local a = {co(3,4,6)}; assert(a[1] == 6 and a[2] == "OK" and a[3] == 0) -a = {co()}; assert(a[1] == "YIELD" and a[2] == 2) -a = {co()}; assert(a[1] == "YIELD" and a[2] == 3) -a = {co(7,8)}; --- original arguments -assert(type(a[1]) == 'string' and type(a[2]) == 'string' and - type(a[3]) == 'string' and type(a[4]) == 'string' and - type(a[5]) == 'string' and type(a[6]) == 'function') --- arguments left from fist resume -assert(a[7] == 3 and a[8] == 4) --- arguments to last resume -assert(a[9] == 7 and a[10] == 8) --- error message and nothing more -assert(a[11]:find("errmsg") and #a == 11) --- check arguments to pcallk -assert(x == "YIELD" and y == 4) - -assert(not pcall(co)) -- coroutine should be dead - --- testing ctx - -a,b = T.testC( - [[ pushstring print; pcallk 0 0 12 # error - getctx; return 2 ]]) -assert(a == "OK" and b == 0) -- no ctx outside continuations - - --- bug in nCcalls -local co = coroutine.wrap(function () - local a = {pcall(pcall,pcall,pcall,pcall,pcall,pcall,pcall,error,"hi")} - return pcall(assert, table.unpack(a)) -end) - -local a = {co()} -assert(a[10] == "hi") - - -print'OK' diff --git a/lua-5.2.2-tests/db.lua b/lua-5.2.2-tests/db.lua deleted file mode 100644 index d3d8c25bb0..0000000000 --- a/lua-5.2.2-tests/db.lua +++ /dev/null @@ -1,631 +0,0 @@ --- testing debug library - -debug = require "debug" - -local function dostring(s) return assert(load(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"); load(s)(); debug.sethook() - assert(#l == 0) -end - - -do - assert(not pcall(debug.getinfo, print, "X")) -- invalid option - assert(debug.getinfo(1000) == nil) -- out of range level - assert(debug.getinfo(-1) == nil) -- out of range level - local a = debug.getinfo(print) - assert(a.what == "C" and a.short_src == "[C]") - a = debug.getinfo(print, "L") - assert(a.activelines == nil) - local b = debug.getinfo(test, "SfL") - assert(b.name == nil and b.what == "Lua" and b.linedefined == 13 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 load(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(a..string.format("; %s=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,3,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 -]], {1,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,3,6}) - -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'+' - --- invalid levels in [gs]etlocal -assert(not pcall(debug.getlocal, 20, 1)) -assert(not pcall(debug.setlocal, -1, 1, 10)) - - --- parameter names -local function foo (a,b,...) local d, e end -local co = coroutine.create(foo) - -assert(debug.getlocal(foo, 1) == 'a') -assert(debug.getlocal(foo, 2) == 'b') -assert(debug.getlocal(foo, 3) == nil) -assert(debug.getlocal(co, foo, 1) == 'a') -assert(debug.getlocal(co, foo, 2) == 'b') -assert(debug.getlocal(co, foo, 3) == nil) - -assert(debug.getlocal(print, 1) == nil) - - --- varargs -local function foo (a, ...) - local t = table.pack(...) - for i = 1, t.n do - local n, v = debug.getlocal(1, -i) - assert(n == "(*vararg)" and v == t[i]) - end - assert(not debug.getlocal(1, -(t.n + 1))) - assert(not debug.setlocal(1, -(t.n + 1), 30)) - if t.n > 0 then - (function (x) - assert(debug.setlocal(2, -1, x) == "(*vararg)") - assert(debug.setlocal(2, -t.n, x) == "(*vararg)") - end)(430) - assert(... == 430) - end -end - -foo() -foo(print) -foo(200, 3, 4) -local a = {} -for i = 1,1000 do a[i] = i end -foo(table.unpack(a)) -a = nil - --- access to vararg in non-vararg function -local function foo () return debug.getlocal(1, -1) end -assert(foo(10) == nil) - - -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 == 1 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(...) - local arg = {...} - 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 arg = {...}; 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(load("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.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") --- upvalues of C functions are allways "called" "" (the empty string) -assert(debug.getupvalue(string.gmatch("x", "x"), 1) == "") - - --- 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) - -if not _no32 then - debug.sethook(print, "", 2^24 - 1) -- count upperbound - local f,m,c = debug.gethook() - assert(({debug.gethook()})[3] == 2^24 - 1) -end - -debug.sethook() - - --- tests for tail calls -local function f (x) - if x then - assert(debug.getinfo(1, "S").what == "Lua") - assert(debug.getinfo(1, "t").istailcall == true) - local tail = debug.getinfo(2) - assert(tail.func == g1 and tail.istailcall == true) - assert(debug.getinfo(3, "S").what == "main") - 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", "tail call", "call", "tail call", - "return", "return", - "call", -- last call (to sethook) -} -for i = 1, #res do assert(res[i] == table.remove(b, 1)) end - -b = 0 -debug.sethook(function (e) - if e == "tail call" then - b = b + 1 - assert(debug.getinfo(2, "t").istailcall == true) - else - assert(debug.getinfo(2, "t").istailcall == false) - end - end, "c") -h(false) -debug.sethook() -assert(b == 2) -- two tail calls - -lim = 30000 -if _soft then limit = 3000 end -local function foo (x) - if x==0 then - assert(debug.getinfo(2).what == "main") - local info = debug.getinfo(1) - assert(info.istailcall == true and info.func == foo) - else return foo(x-1) - end -end - -foo(lim) - - -print"+" - - --- testing local function information -co = load[[ - local A = function () - return x - end - return -]] - -local a = 0 --- 'A' should be visible to debugger only after its complete definition -debug.sethook(function (e, l) - if l == 3 then a = a + 1; assert(debug.getlocal(2, 1) == "(*temporary)") - elseif l == 4 then a = a + 1; assert(debug.getlocal(2, 1) == "A") - end -end, "l") -co() -- run local function definition -debug.sethook() -- turn off hook -assert(a == 2) -- ensure all two lines where hooked - --- 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 nparams, nups e isvararg -local t = debug.getinfo(print, "u") -assert(t.isvararg == true and t.nparams == 0 and t.nups == 0) - -t = debug.getinfo(function (a,b,c) end, "u") -assert(t.isvararg == false and t.nparams == 3 and t.nups == 0) - -t = debug.getinfo(function (a,b,...) return t[a] end, "u") -assert(t.isvararg == true and t.nparams == 2 and t.nups == 1) - -t = debug.getinfo(1) -- main -assert(t.isvararg == true and t.nparams == 0 and t.nups == 1 and - debug.getupvalue(t.func, 1) == "_ENV") - - --- testing debugging of coroutines - -local function checktraceback (co, p, level) - local tb = debug.traceback(co, nil, level) - 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 f(n-1) - else coroutine.yield() end -end - -local co = coroutine.create(f) -coroutine.resume(co, 3) -checktraceback(co, {"yield", "db.lua", "db.lua", "db.lua", "db.lua"}) -checktraceback(co, {"db.lua", "db.lua", "db.lua", "db.lua"}, 1) -checktraceback(co, {"db.lua", "db.lua", "db.lua"}, 2) -checktraceback(co, {"db.lua"}, 4) -checktraceback(co, {}, 40) - - -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) if l then table.insert(tr, l) end end -debug.sethook(co, foo, "lcr") - -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(#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(#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") - - --- test tagmethod information -local a = {} -local function f (t) - local info = debug.getinfo(1); - assert(info.namewhat == "metamethod") - a.op = info.name - return info.name -end -setmetatable(a, { - __index = f; __add = f; __div = f; __mod = f; __concat = f; __pow = f; - __eq = f; __le = f; __lt = f; -}) - -local b = setmetatable({}, getmetatable(a)) - -assert(a[3] == "__index" and a^3 == "__pow" and a..a == "__concat") -assert(a/3 == "__div" and 3%a == "__mod") -assert (a==b and a.op == "__eq") -assert (a>=b and a.op == "__le") -assert (a>b and a.op == "__lt") - - -print"OK" - diff --git a/lua-5.2.2-tests/errors.lua b/lua-5.2.2-tests/errors.lua deleted file mode 100644 index 51dc79a1e7..0000000000 --- a/lua-5.2.2-tests/errors.lua +++ /dev/null @@ -1,439 +0,0 @@ -print("testing errors") - -local debug = require"debug" - --- avoid problems with 'strict' module (which may generate other error messages) -local mt = getmetatable(_G) or {} -local oldmm = mt.__index -mt.__index = nil - -function doit (s) - local f, msg = load(s) - if f == nil then return msg end - local cond, msg = pcall(f) - return (not cond) and msg -end - - -function checkmessage (prog, msg) - local m = doit(prog) - assert(string.find(m, msg, 1, true)) -end - -function checksyntax (prog, extra, token, line) - local msg = doit(prog) - if not string.find(token, "^<%a") and not string.find(token, "^char%(") - then token = "'"..token.."'" end - 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 -if not _no32 then - assert(doit("table.unpack({}, 1, n=2^30)")) -end -assert(doit("a=math.sin()")) -assert(not doit("tostring(1)") and doit("tostring()")) -assert(doit"tonumber()") -assert(doit"repeat until 1; a") -assert(doit"return;;") -assert(doit"assert(false)") -assert(doit"assert(nil)") -assert(doit("function a (... , ...) end")) -assert(doit("function a (, ...) end")) -assert(doit("local t={}; t = t[#t] + 1")) - --- FIXME LuaJIT ---checksyntax([[ --- local a = {4 --- ---]], "'}' expected (to close '{' at line 1)", "", 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") -checkmessage("a=(1)..{}", "a table value") - -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("local _ENV = {x={}}; a = a + 1", "global 'a'") - -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'") --- FIXME LuaJIT ---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("print(print < 10)", "function") -checkmessage("print(print < print)", "two function") - - --- passing light userdata instead of full userdata -_G.D = debug --- FIXME LuaJIT ---checkmessage([[ --- -- create light udata --- local x = D.upvalueid(function () return debug end, 1) --- D.setuservalue(x, {}) ---]], "light userdata") -_G.D = nil - - --- global functions -checkmessage("(io.write or print){}", "io.write") -checkmessage("(collectgarbage or print){}", "collectgarbage") - --- tests for field accesses after RK limit -local t = {} -for i = 1, 1000 do - t[i] = "a = x" .. i -end -local s = table.concat(t, "; ") -t = nil -checkmessage(s.."; a = bbb + 1", "global 'bbb'") -checkmessage("local _ENV=_ENV;"..s.."; a = bbb + 1", "global 'bbb'") --- FIXME LuaJIT ---checkmessage(s.."; local t = {}; a = t.bbb + 1", "field 'bbb'") ---checkmessage(s.."; local t = {}; t:bbb()", "method 'bbb'") - -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'") - --- FIXME LuaJIT ---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") - -checkmessage([[ -local Var -local function main() - NoSuchName (function() Var=0 end) -end -main() -]], "global 'NoSuchName'") -print'+' - -a = {}; setmetatable(a, {__index = string}) -checkmessage("a:sub()", "bad self") -checkmessage("string.sub('a', {})", "#2") -checkmessage("('a'):sub{}", "#1") - --- FIXME LuaJIT ---checkmessage("table.sort({1,2,3}, table.sort)", "'table.sort'") --- next message may be 'setmetatable' or '_G.setmetatable' --- FIXME LuaJIT ---checkmessage("string.gsub('s', 's', setmetatable)", "setmetatable'") - --- tests for errors in coroutines - --- FIXME LuaJIT ---function f (n) --- local c = coroutine.create(f) --- local a,b = coroutine.resume(c) --- return b ---end ---assert(string.find(f(), "C stack overflow")) - --- FIXME LuaJIT ---checkmessage("coroutine.yield()", "outside a coroutine") - -f1 = function () table.sort({1,2,3}, coroutine.yield) end -f = coroutine.wrap(function () return pcall(f1) end) -assert(string.find(select(2, f()), "yield across")) - - --- testing size of 'source' info; size of buffer for that info is --- LUA_IDSIZE, declared as 60 in luaconf. Get one position for '\0'. -idsize = 60 - 1 -local function checksize (source) - -- syntax error - local _, msg = load("x", source) - msg = string.match(msg, "^([^:]*):") -- get source (1st part before ':') - assert(msg:len() <= idsize) -end - -for i = 60 - 10, 60 + 10 do -- check border cases around 60 - checksize("@" .. string.rep("x", i)) -- file names - checksize(string.rep("x", i - 10)) -- string sources - checksize("=" .. string.rep("x", i)) -- exact sources -end - - --- testing line error - -local function lineerror (s, l) - local err,msg = pcall(load(s)) - local line = string.match(msg, ":(%d+):") - assert((line and line+0) == l) -end - -lineerror("local a\n for i=1,'a' do \n print(i) \n end", 2) -lineerror("\n local a \n for k,v in 3 \n do \n print(k) \n end", 3) -lineerror("\n\n for k,v in \n 3 \n do \n print(k) \n end", 4) -lineerror("function a.x.y ()\na=a+1\nend", 1) - --- FIXME LuaJIT ---lineerror("a = \na\n+\n{}", 3) ---lineerror("a = \n3\n+\n(\n4\n/\nprint)", 6) ---lineerror("a = \nprint\n+\n(\n4\n/\n7)", 3) - --- FIXME LuaJIT ---lineerror("a\n=\n-\n\nprint\n;", 3) - --- FIXME LuaJIT ---lineerror([[ ---a ---( ---23) ---]], 1) - --- FIXME LuaJIT ---lineerror([[ ---local a = {x = 13} ---a ---. ---x ---( ---23 ---) ---]], 2) - -lineerror([[ -local a = {x = 13} -a -. -x -( -23 + a -) -]], 6) - -local p = [[ -function g() f() end -function f(x) error('a', X) end -g() -]] -X=3;lineerror((p), 3) -X=0;lineerror((p), nil) -X=1;lineerror((p), 2) -X=2;lineerror((p), 1) - - -if not _soft then - -- several tests that exaust the Lua stack - 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 - -- repeated stack overflows (to check stack recovery) - assert(checkstackmessage(doit('y()'))) - print('+') - assert(checkstackmessage(doit('y()'))) - print('+') - assert(checkstackmessage(doit('y()'))) - print('+') - - - -- error lines in stack overflow - C = 0 - local l1 - local function g(x) - l1 = debug.getinfo(x, "l").currentline; y() - end - local _, stackmsg = xpcall(g, debug.traceback, 1) - print('+') - 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') - print('+') - - 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) - - local function loop (x,y,z) return 1 + loop(x, y, z) end - - local res, msg = xpcall(loop, function (m) - assert(string.find(m, "stack overflow")) - local res, msg = pcall(loop) - assert(string.find(msg, "error handling")) - assert(math.sin(0) == 0) - return 15 - end) - -- FIXME LuaJIT - --assert(msg == 15) - - res, msg = pcall(function () - for i = 999900, 1000000, 1 do table.unpack({}, 1, i) end - end) - assert(string.find(msg, "too many results")) - -end - - --- 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') - --- xpcall with arguments -a, b, c = xpcall(string.find, error, "alo", "al") -assert(a and b == 1 and c == 2) -a, b, c = xpcall(string.find, function (x) return {} end, true, "al") -assert(not a and type(b) == "table" and c == nil) - -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 --- FIXME LuaJIT ---checksyntax("\255a = 1", "", "char(255)", 1) - -doit('I = load("a=9+"); a=3') -assert(a==3 and I == nil) -print('+') - -lim = 1000 -if _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 = load(s) - assert(not a and string.find(b, "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^") - -local s = ("a,"):rep(200).."a=nil" -local a,b = load(s) --- FIXME LuaJIT ---assert(not a and string.find(b, "levels")) - - --- testing other limits --- upvalues -local lim = 127 -local s = "local function fooA ()\n local " -for j = 1,lim do - s = s.."a"..j..", " -end -s = s.."b,c\n" -s = s.."local function fooB ()\n local " -for j = 1,lim do - s = s.."b"..j..", " -end -s = s.."b\n" -s = s.."function fooC () return b+c" -local c = 1+2 -for j = 1,lim do - s = s.."+a"..j.."+b"..j - c = c + 2 -end -s = s.."\nend end end" -local a,b = load(s) --- FIXME LuaJIT ---assert(c > 255 and string.find(b, "too many upvalues") and --- string.find(b, "line 5")) - --- local variables -s = "\nfunction foo ()\n local " -for j = 1,300 do - s = s.."a"..j..", " -end -s = s.."b\n" -local a,b = load(s) -assert(string.find(b, "line 2")) - -mt.__index = oldmm - -print('OK') diff --git a/lua-5.2.2-tests/events.lua b/lua-5.2.2-tests/events.lua deleted file mode 100644 index de1cd48583..0000000000 --- a/lua-5.2.2-tests/events.lua +++ /dev/null @@ -1,390 +0,0 @@ -print('testing metatables') - -X = 20; B = 30 - -_ENV = setmetatable({}, {__index=_G}) - -collectgarbage() - -X = X+10 --- FIXME LuaJIT ---assert(X == 30 and _G.X == 20) -B = false -assert(B == false) -B = nil --- FIXME LuaJIT ---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 -setmetatable(t, t) -- causes a bug in 5.1 ! -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 - - -setmetatable(t, nil) -function f (t, ...) return t, {...} end -t.__call = f - -do - local x,y = a(table.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") -t.__len = f("len") - -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) -assert(#a == a) -assert(cap[0] == "len" and cap[1] == a) - - --- test for rawlen -t = setmetatable({1,2,3}, {__len = function () return 10 end}) -assert(#t == 10 and rawlen(t) == 3) -assert(rawlen"abc" == 3) -assert(not pcall(rawlen, io.stdin)) -assert(not pcall(rawlen, 34)) -assert(not pcall(rawlen)) - -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 aOp(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((1 >= Op(1)) and not(1 >= Op(2)) and (Op(2) >= 1)) - assert((Op('a')>=Op('a')) and not(Op('a')>=Op('b')) and (Op('b')>=Op('a'))) - assert(('a' >= Op('a')) and not(Op('a') >= '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 -assert((c..d..c..d).val == 'cdcd') -x = c..d -assert(getmetatable(x) == t and x.val == 'cd') -x = 0 .."a".."b"..c..d.."e".."f".."g" -assert(x.val == "0abcdefg") - - --- concat metamethod x numbers (bug in 5.1.1) -c = {} -local x -setmetatable(c, {__concat = function (a,b) - assert(type(a) == "number" and b == c or type(b) == "number" and a == c) - return c -end}) -assert(c..5 == c and 5 .. c == c) -assert(4 .. c .. 5 == c and 4 .. 5 .. 6 .. 7 .. c == c) - - --- 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 -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) - --- FIXME LuaJIT --- assert(_G.X == 20) - -print'+' - -local _g = _G -_ENV = setmetatable({}, {__index=function (_,k) return _g[k] end}) - - -a = {} -rawset(a, "x", 1, 2, 3) -assert(a.x == 1 and rawget(a, "x", 3) == 1) - -print '+' - --- testing metatables for basic types -local debug = require'debug' -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, {}) - - --- loops in delegation -a = {}; setmetatable(a, a); a.__index = a; a.__newindex = a -assert(not pcall(function (a,b) return a[b] end, a, 10)) -assert(not pcall(function (a,b,c) a[b] = c end, a, 10, true)) - --- bug in 5.1 -T, K, V = nil -grandparent = {} -grandparent.__newindex = function(t,k,v) T=t; K=k; V=v end - -parent = {} -parent.__newindex = parent -setmetatable(parent, grandparent) - -child = setmetatable({}, parent) -child.foo = 10 --> CRASH (on some machines) -assert(T == parent and K == "foo" and V == 10) - -print 'OK' - -return 12 - - diff --git a/lua-5.2.2-tests/files.lua b/lua-5.2.2-tests/files.lua deleted file mode 100644 index 0247fdef82..0000000000 --- a/lua-5.2.2-tests/files.lua +++ /dev/null @@ -1,626 +0,0 @@ -debug = require "debug" - -assert(type(os.getenv"PATH") == "string") - -assert(io.input(io.stdin) == io.stdin) -assert(not pcall(io.input, "non-existent-file")) -assert(io.output(io.stdout) == io.stdout) - --- cannot close standard files -assert(not io.close(io.stdin) and - not io.stdout:close() and - not io.stderr:close()) - - -assert(type(io.input()) == "userdata" and io.type(io.output()) == "file") -assert(type(io.stdin) == "userdata" and io.type(io.stderr) == "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 f, msg = io.open(file, "w") -if not f then - (Message or print)("'os.tmpname' file cannot be open; skipping file tests") - -else --{ most tests here need tmpname -f:close() - -print('testing i/o') - -local otherfile = os.tmpname() - --- FIXME LuaJIT ---assert(not pcall(io.open, file, "rw")) -- invalid mode ---assert(not pcall(io.open, file, "rb+")) -- invalid mode ---assert(not pcall(io.open, file, "r+bk")) -- invalid mode ---assert(not pcall(io.open, file, "")) -- invalid mode ---assert(not pcall(io.open, file, "+")) -- invalid mode ---assert(not pcall(io.open, file, "b")) -- invalid mode -assert(io.open(file, "r+b")):close() -assert(io.open(file, "r+")):close() -assert(io.open(file, "rb")):close() - -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"):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 - -io.input():close() -io.close() - -assert(os.rename(file, otherfile)) -assert(os.rename(file, otherfile) == nil) - -io.output(io.open(otherfile, "ab")) -assert(io.write("\n\n\t\t 3450\n")); -io.close() - --- test line generators -assert(not pcall(io.lines, "non-existent-file")) -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(tostring(f):sub(1, 5) == "file ") -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 -f = nil; collectgarbage() -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 \n") -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(30000) == 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"):write("\n") -io.close() -assert(not pcall(io.write)) -local f = io.open(file, "a+b") -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())) - - --- test errors in read/write -do - local function ismsg (m) - -- error message is not a code number - return (type(m) == "string" and tonumber(m) == nil) - end - - -- read - local f = io.open(file, "w") - local r, m, c = f:read() - assert(r == nil and ismsg(m) and type(c) == "number") - assert(f:close()) - -- write - f = io.open(file, "r") - r, m, c = f:write("whatever") - assert(r == nil and ismsg(m) and type(c) == "number") - assert(f:close()) - -- lines - f = io.open(file, "w") - r, m = pcall(f:lines()) - assert(r == false and ismsg(m)) - assert(f:close()) -end - -assert(os.remove(file)) - --- test for *L format -io.output(file); io.write"\n\nline\nother":close() -io.input(file) -assert(io.read"*L" == "\n") -assert(io.read"*L" == "\n") -assert(io.read"*L" == "line\n") -assert(io.read"*L" == "other") -assert(io.read"*L" == nil) -io.input():close() - -local f = assert(io.open(file)) -local s = "" -for l in f:lines("*L") do s = s .. l end -assert(s == "\n\nline\nother") -f:close() - -io.input(file) -s = "" -for l in io.lines(nil, "*L") do s = s .. l end -assert(s == "\n\nline\nother") -io.input():close() - -s = "" -for l in io.lines(file, "*L") do s = s .. l end -assert(s == "\n\nline\nother") - -s = "" -for l in io.lines(file, "*l") do s = s .. l end -assert(s == "lineother") - -io.output(file); io.write"a = 10 + 34\na = 2*a\na = -a\n":close() -local t = {} -load(io.lines(file, "*L"), nil, nil, t)() -assert(t.a == -((10 + 34) * 2)) - - --- test for multipe arguments in 'lines' -io.output(file); io.write"0123456789\n":close() -for a,b in io.lines(file, 1, 1) do - if a == "\n" then assert(b == nil) - else assert(tonumber(a) == b - 1) - end -end - -for a,b,c in io.lines(file, 1, 2, "*a") do - assert(a == "0" and b == "12" and c == "3456789\n") -end - -for a,b,c in io.lines(file, "*a", 0, 1) do - if a == "" then break end - assert(a == "0123456789\n" and b == nil and c == nil) -end -collectgarbage() -- to close file in previous iteration - -io.output(file); io.write"00\n10\n20\n30\n40\n":close() -for a, b in io.lines(file, "*n", "*n") do - if a == 40 then assert(b == nil) - else assert(a == b - 10) - end -end - - --- test load x lines -io.output(file); -io.write[[ -local y -= X -X = -X * -2 + -X; -X = -X -- y; -]]:close() -_G.X = 1 -assert(not load(io.lines(file))) -collectgarbage() -- to close file in previous iteration -load(io.lines(file, "*L"))() -assert(_G.X == 2) -load(io.lines(file, 1))() -assert(_G.X == 4) -load(io.lines(file, 3))() -assert(_G.X == 8) - -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) - --- testing loadfile -local function testloadfile (s, expres) - io.output(file) - if s then io.write(s) end - io.close() - local res = assert(loadfile(file))() - assert(os.remove(file)) - assert(res == expres) -end - --- loading empty file -testloadfile(nil, nil) - --- loading file with initial comment without end of line -testloadfile("# a non-ending comment", nil) - - --- checking Unicode BOM in files -testloadfile("\xEF\xBB\xBF# some comment\nreturn 234", 234) -testloadfile("\xEF\xBB\xBFreturn 239", 239) -testloadfile("\xEF\xBB\xBF", nil) -- empty file with a BOM - - --- checking line numbers in files with initial comments -testloadfile("# a comment\nreturn debug.getinfo(1).currentline", 2) - - --- loading binary file -io.output(io.open(file, "wb")) -assert(io.write(string.dump(function () return 10, '\0alo\255', 'hi' end))) -io.close() -a, b, c = assert(loadfile(file))() -assert(a == 10 and b == "\0alo\255" and c == "hi") -assert(os.remove(file)) - --- bug in 5.2.1 -do - io.output(io.open(file, "wb")) - -- save function with no upvalues - assert(io.write(string.dump(function () return 1 end))) - io.close() - f = assert(loadfile(file, "b", {})) - assert(type(f) == "function" and f() == 1) - assert(os.remove(file)) -end - --- loading binary file with initial comment -io.output(io.open(file, "wb")) -assert(io.write("#this is a comment for a binary file\0\n", - string.dump(function () return 20, '\0\0\0' end))) -io.close() --- FIXME LuaJIT ---a, b, c = assert(loadfile(file))() ---assert(a == 20 and b == "\0\0\0" and c == nil) ---assert(os.remove(file)) - - --- 'loadfile' with 'env' --- FIXME LuaJIT test disabled -if false then -do - local f = io.open(file, 'w') - f:write[[ - if (...) then a = 15; return b, c, d - else return _ENV - end - ]] - f:close() - local t = {b = 12, c = "xuxu", d = print} - local f = assert(loadfile(file, 't', t)) - local b, c, d = f(1) - assert(t.a == 15 and b == 12 and c == t.c and d == print) - assert(f() == t) - f = assert(loadfile(file, 't', nil)) - assert(f() == nil) - f = assert(loadfile(file)) - assert(f() == _G) - assert(os.remove(file)) -end -end - - --- 'loadfile' x modes --- FIXME LuaJIT test disabled -if false then -do - io.open(file, 'w'):write("return 10"):close() - local s, m = loadfile(file, 'b') - assert(not s and string.find(m, "a text chunk")) - io.open(file, 'w'):write("\27 return 10"):close() - local s, m = loadfile(file, 't') - assert(not s and string.find(m, "a binary chunk")) - assert(os.remove(file)) -end -end - - -io.output(file) -assert(io.write("qualquer coisa\n")) -assert(io.write("mais qualquer coisa")) -io.close() -assert(io.output(assert(io.open(otherfile, 'wb'))) - :write("outra coisa\0\1\3\0\0\0\0\255\0") - :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) - :write[[ - 123.4 -56e-2 not a number -second line -third line - -and the rest of the file -]] - :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"):seek("set", 1) - assert(fr:read("*all") == "xa\n") -- now we have a whole line - f:close(); fr:close() - assert(os.remove(file)) -end - - -if not _soft then - print("testing large files (> BUFSIZ)") - io.output(file) - for i=1,5001 do io.write('0123456789123') end - io.write('\n12346'):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 -end - -if not _noposix then - print("testing popen/pclose and execute") - local tests = { - -- command, what, code - {"ls > /dev/null", "ok"}, - {"not-to-be-found-command", "exit"}, - {"exit 3", "exit", 3}, - {"exit 129", "exit", 129}, - {"kill -s HUP $$", "signal", 1}, - {"kill -s KILL $$", "signal", 9}, - {"sh -c 'kill -s HUP $$'", "exit"}, - {'lua -e "os.exit(20, true)"', "exit", 20}, - } - print("\n(some error messages are expected now)") - for _, v in ipairs(tests) do - local x, y, z = io.popen(v[1]):close() - local x1, y1, z1 = os.execute(v[1]) - assert(x == x1 and y == y1 and z == z1) - if v[2] == "ok" then - assert(x == true and y == 'exit' and z == 0) - else - -- FIXME LuaJIT - -- assert(x == nil and y == v[2]) -- correct status and 'what' - -- correct code if known (but always different from 0) - -- FIXME LuaJIT - --assert((v[3] == nil and z > 0) or v[3] == z) - end - end -end - - --- testing tmpfile -f = io.tmpfile() -assert(io.type(f) == "file") -f:write("alo") -f:seek("set") -assert(f:read"*a" == "alo") - -end --} - -print'+' - - -assert(os.date("") == "") -assert(os.date("!") == "") -local x = string.rep("a", 10000) -assert(os.date(x) == x) -local t = os.time() -D = os.date("*t", t) -assert(os.date(string.rep("%d", 1000), t) == - string.rep(os.date("%d", t), 1000)) -assert(os.date(string.rep("%", 200)) == string.rep("%", 100)) - -local t = os.time() -D = os.date("*t", t) -load(os.date([[assert(D.year==%Y and D.month==%m and D.day==%d and - D.hour==%H and D.min==%M and D.sec==%S and - D.wday==%w+1 and D.yday==%j and type(D.isdst) == 'boolean')]], t))() - --- FIXME LuaJIT ---assert(not pcall(os.date, "%9")) -- invalid conversion specifier ---assert(not pcall(os.date, "%")) -- invalid conversion specifier ---assert(not pcall(os.date, "%O")) -- invalid conversion specifier ---assert(not pcall(os.date, "%E")) -- invalid conversion specifier ---assert(not pcall(os.date, "%Ea")) -- invalid conversion specifier - -if not _noposix then - assert(type(os.date("%Ex")) == 'string') - assert(type(os.date("%Oy")) == 'string') -end - -assert(os.time(D) == t) -assert(not pcall(os.time, {hour = 12})) - -D = os.date("!*t", t) -load(os.date([[!assert(D.year==%Y and D.month==%m and D.day==%d and - D.hour==%H and D.min==%M and D.sec==%S and - D.wday==%w+1 and D.yday==%j and type(D.isdst) == 'boolean')]], t))() - -do - local D = os.date("*t") - local t = os.time(D) - assert(type(D.isdst) == 'boolean') - D.isdst = nil - local t1 = os.time(D) - assert(t == t1) -- if isdst is absent uses correct default -end - -t = os.time(D) -D.year = D.year-1; -local t1 = os.time(D) --- 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} -local t2 = os.time{year=2000, month=10, day=1, hour=23, min=10, sec=19} -assert(os.difftime(t1,t2) == 60*2-19) - -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/lua-5.2.2-tests/gc.lua b/lua-5.2.2-tests/gc.lua deleted file mode 100644 index 828a829d8a..0000000000 --- a/lua-5.2.2-tests/gc.lua +++ /dev/null @@ -1,575 +0,0 @@ -print('testing garbage collection') - -collectgarbage() - -assert(collectgarbage("isrunning")) - -local function gcinfo () return collectgarbage"count" * 1024 end - - --- test weird parameters -do - -- save original parameters - local a = collectgarbage("setpause", 200) - local b = collectgarbage("setstepmul", 200) - local t = {0, 2, 10, 90, 500, 5000, 30000, 2^31 - 2} - for i = 1, #t do - local p = t[i] - for j = 1, #t do - local m = t[j] - collectgarbage("setpause", p) - collectgarbage("setstepmul", m) - collectgarbage("step", 0) - collectgarbage("step", 10000) - end - end - -- restore original parameters - collectgarbage("setpause", a) - collectgarbage("setstepmul", b) - collectgarbage() -end - - -_G["while"] = 234 - -limit = 5000 - - -local function GC1 () - local u - local b -- must be declared after 'u' (to be above it in the stack) - local finish = false - u = setmetatable({}, {__gc = function () finish = true end}) - b = {34} - repeat u = {} until finish - assert(b[1] == 34) -- 'u' was collected, but 'b' was not - - finish = false; local i = 1 - u = setmetatable({}, {__gc = function () finish = true end}) - repeat i = i + 1; u = i .. i until finish - assert(b[1] == 34) -- 'u' was collected, but 'b' was not - - finish = false - u = setmetatable({}, {__gc = function () finish = true end}) - repeat local i; u = function () return i end until finish - assert(b[1] == 34) -- 'u' was collected, but 'b' was not -end - -local function GC() GC1(); GC1() end - - -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 - load(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 _soft then step = 13 end - for i=1, string.len(prog), step do - for j=i, string.len(prog), step do - pcall(load(string.sub(prog, i, j))) - end - end -end - -foo = nil -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 k,b = collectgarbage("count") -assert(k*1024 == math.floor(k)*1024 + b) - -print("steps") - -local bytes = gcinfo() -while 1 do - local nbytes = gcinfo() - if nbytes < bytes then break end -- run until gc - bytes = nbytes - a = {} -end - -print("steps (2)") - -local function dosteps (siz) - assert(not collectgarbage("isrunning")) - collectgarbage() - assert(not collectgarbage("isrunning")) - local a = {} - for i=1,100 do a[i] = {{}}; local b = {} end - local x = gcinfo() - local i = 0 - repeat -- do steps until it completes a collection cycle - i = i+1 - until collectgarbage("step", siz) - assert(gcinfo() < x) - return i -end - -collectgarbage"stop" - -if not _port then - -- test the "size" of basic GC steps (whatever they mean...) - assert(dosteps(0) > 10) - assert(dosteps(10) < dosteps(2)) -end - --- collector should do a full collection with so many steps -assert(dosteps(100000) == 1) -assert(collectgarbage("step", 1000000) == true) -assert(collectgarbage("step", 1000000) == true) - -assert(not collectgarbage("isrunning")) -collectgarbage"restart" -assert(collectgarbage("isrunning")) - - -if not _port then - -- test the pace of the collector - collectgarbage(); collectgarbage() - local x = gcinfo() - collectgarbage"stop" - assert(not collectgarbage("isrunning")) - repeat - local a = {} - until gcinfo() > 3 * x - collectgarbage"restart" - assert(collectgarbage("isrunning")) - repeat - local a = {} - until gcinfo() <= x * 2 -end - - -print("clearing tables") -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 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 == 2*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)) - - --- 'bug' in 5.1 -a = {} -local t = {x = 10} -local C = setmetatable({key = t}, {__mode = 'v'}) -local C1 = setmetatable({[t] = 1}, {__mode = 'k'}) -a.x = t -- this should not prevent 't' from being removed from - -- weak table 'C' by the time 'a' is finalized - -setmetatable(a, {__gc = function (u) - assert(C.key == nil) - assert(type(next(C1)) == 'table') - end}) - -a, t = nil -collectgarbage() -collectgarbage() -assert(next(C) == nil and next(C1) == nil) -C, C1 = nil - - --- ephemerons -local mt = {__mode = 'k'} -a = {10,20,30,40}; setmetatable(a, mt) -x = nil -for i = 1, 100 do local n = {}; a[n] = {k = {x}}; x = n end -GC() -local n = x -local i = 0 -while n do n = a[n].k[1]; i = i + 1 end -assert(i == 100) -x = nil -GC() -for i = 1, 4 do assert(a[i] == i * 10); a[i] = nil end -assert(next(a) == nil) - -local K = {} -a[K] = {} -for i=1,10 do a[K][i] = {}; a[a[K][i]] = setmetatable({}, mt) end -x = nil -local k = 1 -for j = 1,100 do - local n = {}; local nk = k%10 + 1 - a[a[K][nk]][n] = {x, k = k}; x = n; k = nk -end -GC() -local n = x -local i = 0 -while n do local t = a[a[K][k]][n]; n = t[1]; k = t.k; i = i + 1 end -assert(i == 100) -K = nil -GC() -assert(next(a) == nil) - - --- testing errors during GC -do -collectgarbage("stop") -- stop collection -local u = {} -local s = {}; setmetatable(s, {__mode = 'k'}) -setmetatable(u, {__gc = function (o) - local i = s[o] - s[i] = true - assert(not s[i - 1]) -- check proper finalization order - if i == 8 then error("here") end -- error during GC -end}) - -for i = 6, 10 do - local n = setmetatable({}, getmetatable(u)) - s[n] = i -end - -assert(not pcall(collectgarbage)) -for i = 8, 10 do assert(s[i]) end - -for i = 1, 5 do - local n = setmetatable({}, getmetatable(u)) - s[n] = i -end - -collectgarbage() -for i = 1, 10 do assert(s[i]) end - -getmetatable(u).__gc = false - - --- __gc errors with non-string messages -setmetatable({}, {__gc = function () error{} end}) -local a, b = pcall(collectgarbage) -assert(not a and type(b) == "string" and string.find(b, "error in __gc")) - -end -print '+' - - --- testing userdata -if T==nil then - (Message or print)('\a\n >>> testC not active: skipping userdata GC tests <<<\n\a') - -else - - local function newproxy(u) - return debug.setmetatable(T.newuserdata(0), debug.getmetatable(u)) - end - - collectgarbage("stop") -- stop collection - local u = newproxy(nil) - debug.setmetatable(u, {__gc = 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 -end - - --- __gc x weak tables -local u = setmetatable({}, {__gc = true}) --- __gc metamethod should be collected before running -setmetatable(getmetatable(u), {__mode = "v"}) -getmetatable(u).__gc = function (o) os.exit(1) end -- cannot happen -u = nil -collectgarbage() - -local u = setmetatable({}, {__gc = 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 = setmetatable({}, {__gc = function () error "!!!" end}) -u = nil -assert(not pcall(collectgarbage)) - - -if not _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 = {} - -local 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 - -do - collectgarbage() - collectgarbage"stop" - local x = gcinfo() - repeat - for i=1,1000 do _ENV.a = {} end - collectgarbage("step", 1) -- steps should not unblock the collector - until gcinfo() > 2 * x - collectgarbage"restart" -end - - -if T then -- tests for weird cases collecting upvalues - local a = 1200 - local f = function () return a end -- create upvalue for 'a' - assert(f() == 1200) - - -- erase reference to upvalue 'a', mark it as dead, but does not collect it - T.gcstate("pause"); collectgarbage("stop") - f = nil - T.gcstate("sweepstring") - - -- this function will reuse that dead upvalue... - f = function () return a end - assert(f() == 1200) - - -- create coroutine with local variable 'b' - local co = coroutine.wrap(function() - local b = 150 - coroutine.yield(function () return b end) - end) - - T.gcstate("pause") - assert(co()() == 150) -- create upvalue for 'b' - - -- mark upvalue 'b' as dead, but does not collect it - T.gcstate("sweepstring") - - co() -- finish coroutine, "closing" that dead upvalue - - assert(f() == 1200) - collectgarbage("restart") - - print"+" -end - - -if T then - local debug = require "debug" - collectgarbage("generational"); collectgarbage("stop") - x = T.newuserdata(0) - T.gcstate("propagate") -- ensure 'x' is old - T.gcstate("sweepstring") - T.gcstate("propagate") - assert(string.find(T.gccolor(x), "/old")) - local y = T.newuserdata(0) - debug.setmetatable(y, {__gc = true}) -- bless the new udata before... - debug.setmetatable(x, {__gc = true}) -- ...the old one - assert(string.find(T.gccolor(y), "white")) - T.checkmemory() - collectgarbage("incremental"); collectgarbage("restart") -end - - -if T then - print("emergency collections") - collectgarbage() - collectgarbage() - T.totalmem(T.totalmem() + 200) - for i=1,200 do local a = {} end - T.totalmem(1000000000) - collectgarbage() - local t = T.totalmem("table") - local a = {{}, {}, {}} -- create 4 new tables - assert(T.totalmem("table") == t + 4) - t = T.totalmem("function") - a = function () end -- create 1 new closure - assert(T.totalmem("function") == t + 1) - t = T.totalmem("thread") - a = coroutine.create(function () end) -- create 1 new coroutine - assert(T.totalmem("thread") == t + 1) -end - --- create an object to be collected when state is closed -do - local setmetatable,assert,type,print,getmetatable = - setmetatable,assert,type,print,getmetatable - local tt = {} - tt.__gc = function (o) - assert(getmetatable(o) == tt) - -- create new objects during GC - local a = 'xuxu'..(10+3)..'joao', {} - ___Glob = o -- ressurect object! - setmetatable({}, tt) -- creates a new one with same metatable - print(">>> closing state " .. "<<<\n") - end - local u = setmetatable({}, tt) - ___Glob = {u} -- avoid object being collected before program end -end - --- create several objects to raise errors when collected while closing state -do - local mt = {__gc = function (o) return o + 1 end} - for i = 1,10 do - -- create object and preserve it until the end - table.insert(___Glob, setmetatable({}, mt)) - end -end - --- just to make sure -assert(collectgarbage'isrunning') - -print('OK') diff --git a/lua-5.2.2-tests/goto.lua b/lua-5.2.2-tests/goto.lua deleted file mode 100644 index d881715640..0000000000 --- a/lua-5.2.2-tests/goto.lua +++ /dev/null @@ -1,173 +0,0 @@ -local function errmsg (code, m) - local st, msg = load(code) - assert(not st and string.find(msg, m)) -end - --- cannot see label inside block -errmsg([[ goto l1; do ::l1:: end ]], "label 'l1'") -errmsg([[ do ::l1:: end goto l1; ]], "label 'l1'") - --- repeated label -errmsg([[ ::l1:: ::l1:: ]], "label 'l1'") - - --- undefined label -errmsg([[ goto l1; local aa ::l1:: ::l2:: print(3) ]], "local 'aa'") - --- jumping over variable definition -errmsg([[ -do local bb, cc; goto l1; end -local aa -::l1:: print(3) -]], "local 'aa'") - --- jumping into a block -errmsg([[ do ::l1:: end goto l1 ]], "label 'l1'") -errmsg([[ goto l1 do ::l1:: end ]], "label 'l1'") - --- cannot continue a repeat-until with variables -errmsg([[ - repeat - if x then goto cont end - local xuxu = 10 - ::cont:: - until xuxu < x -]], "local 'xuxu'") - --- simple gotos -local x -do - local y = 12 - goto l1 - ::l2:: x = x + 1; goto l3 - ::l1:: x = y; goto l2 -end -::l3:: ::l3_1:: assert(x == 13) - - --- long labels -do - local prog = [[ - do - local a = 1 - goto l%sa; a = a + 1 - ::l%sa:: a = a + 10 - goto l%sb; a = a + 2 - ::l%sb:: a = a + 20 - return a - end - ]] - local label = string.rep("0123456789", 40) - prog = string.format(prog, label, label, label, label) - assert(assert(load(prog))() == 31) -end - --- goto to correct label when nested -do goto l3; ::l3:: end -- does not loop jumping to previous label 'l3' - --- ok to jump over local dec. to end of block -do - goto l1 - local a = 23 - x = a - ::l1::; -end - -while true do - goto l4 - goto l1 -- ok to jump over local dec. to end of block - goto l1 -- multiple uses of same label - local x = 45 - ::l1:: ;;; -end -::l4:: assert(x == 13) - -if print then - goto l1 -- ok to jump over local dec. to end of block - error("should not be here") - goto l2 -- ok to jump over local dec. to end of block - local x - ::l1:: ; ::l2:: ;; -else end - --- to repeat a label in a different function is OK -local function foo () - local a = {} - goto l3 - ::l1:: a[#a + 1] = 1; goto l2; - ::l2:: a[#a + 1] = 2; goto l5; - ::l3:: - ::l3a:: a[#a + 1] = 3; goto l1; - ::l4:: a[#a + 1] = 4; goto l6; - ::l5:: a[#a + 1] = 5; goto l4; - ::l6:: assert(a[1] == 3 and a[2] == 1 and a[3] == 2 and - a[4] == 5 and a[5] == 4) - if not a[6] then a[6] = true; goto l3a end -- do it twice -end - -::l6:: foo() - - - --------------------------------------------------------------------------------- --- testing closing of upvalues - -local function foo () - local a = {} - do - local i = 1 - local k = 0 - a[0] = function (y) k = y end - ::l1:: do - local x - if i > 2 then goto l2 end - a[i] = function (y) if y then x = y else return x + k end end - i = i + 1 - goto l1 - end - end - ::l2:: return a -end - -local a = foo() -a[1](10); a[2](20) -assert(a[1]() == 10 and a[2]() == 20 and a[3] == nil) -a[0](13) -assert(a[1]() == 23 and a[2]() == 33) - --------------------------------------------------------------------------------- --- testing if x goto optimizations - -local function testG (a) - if a == 1 then - goto l1 - error("should never be here!") - elseif a == 2 then goto l2 - elseif a == 3 then goto l3 - elseif a == 4 then - goto l1 -- go to inside the block - error("should never be here!") - ::l1:: a = a + 1 -- must go to 'if' end - else - goto l4 - ::l4a:: a = a * 2; goto l4b - error("should never be here!") - ::l4:: goto l4a - error("should never be here!") - ::l4b:: - end - do return a end - ::l2:: do return "2" end - ::l3:: do return "3" end - ::l1:: return "1" -end - -assert(testG(1) == "1") -assert(testG(2) == "2") -assert(testG(3) == "3") -assert(testG(4) == 5) -assert(testG(5) == 10) --------------------------------------------------------------------------------- - - -print'OK' diff --git a/lua-5.2.2-tests/libs/P1/dummy b/lua-5.2.2-tests/libs/P1/dummy deleted file mode 100644 index 421376db9e..0000000000 --- a/lua-5.2.2-tests/libs/P1/dummy +++ /dev/null @@ -1 +0,0 @@ -dummy diff --git a/lua-5.2.2-tests/libs/lib1.c b/lua-5.2.2-tests/libs/lib1.c deleted file mode 100644 index 0cac7c9817..0000000000 --- a/lua-5.2.2-tests/libs/lib1.c +++ /dev/null @@ -1,49 +0,0 @@ -/* -** 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} -}; - - -/* function used by lib11.c */ -int lib1_export (lua_State *L) { - lua_pushstring(L, "exported"); - return 1; -} - - -int onefunction (lua_State *L) { - lua_settop(L, 2); - lua_pushvalue(L, 1); - return 2; -} - - -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) { - lua_setglobal(L, "y"); - lua_setglobal(L, "x"); - luaL_newlib(L, funcs); - return 1; -} - diff --git a/lua-5.2.2-tests/libs/lib11.c b/lua-5.2.2-tests/libs/lib11.c deleted file mode 100644 index 835a00c69b..0000000000 --- a/lua-5.2.2-tests/libs/lib11.c +++ /dev/null @@ -1,18 +0,0 @@ -/* -** 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" - -/* function from lib1.c */ -int lib1_export (lua_State *L); - -int luaopen_lib11 (lua_State *L) { - return lib1_export(L); -} - - diff --git a/lua-5.2.2-tests/libs/lib2.c b/lua-5.2.2-tests/libs/lib2.c deleted file mode 100644 index e48d41aad1..0000000000 --- a/lua-5.2.2-tests/libs/lib2.c +++ /dev/null @@ -1,29 +0,0 @@ -/* -** 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) { - lua_settop(L, 2); - lua_setglobal(L, "y"); /* y gets 2nd parameter */ - lua_setglobal(L, "x"); /* x gets 1st parameter */ - luaL_newlib(L, funcs); - return 1; -} - - diff --git a/lua-5.2.2-tests/libs/lib21.c b/lua-5.2.2-tests/libs/lib21.c deleted file mode 100644 index 167507f99b..0000000000 --- a/lua-5.2.2-tests/libs/lib21.c +++ /dev/null @@ -1,18 +0,0 @@ -/* -** 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/lua-5.2.2-tests/libs/makefile b/lua-5.2.2-tests/libs/makefile deleted file mode 100644 index 1f9eeada5f..0000000000 --- a/lua-5.2.2-tests/libs/makefile +++ /dev/null @@ -1,26 +0,0 @@ -# change this variable to point to the directory with Lua headers -# of the version being tested -LUA_DIR = ../.. - -CC = gcc - -# compilation should generate Dynamic-Link Libraries -CFLAGS = -Wall -O2 -I$(LUA_DIR) -ansi -fpic -shared - -# libraries used by the tests -all: lib1.so lib11.so lib2.so lib21.so v-lib2.so - -lib1.so: lib1.c - $(CC) $(CFLAGS) -o lib1.so lib1.c - -lib11.so: lib11.c - $(CC) $(CFLAGS) -o lib11.so lib11.c - -lib2.so: lib2.c - $(CC) $(CFLAGS) -o lib2.so lib2.c - -lib21.so: lib21.c - $(CC) $(CFLAGS) -o lib21.so lib21.c - -v-lib2.so: lib2.so - mv lib2.so ./v-lib2.so diff --git a/lua-5.2.2-tests/literals.lua b/lua-5.2.2-tests/literals.lua deleted file mode 100644 index b641a71b98..0000000000 --- a/lua-5.2.2-tests/literals.lua +++ /dev/null @@ -1,263 +0,0 @@ -print('testing scanner') - -debug = require "debug" - - -local function dostring (x) return assert(load(x))() end - -dostring("x \v\f = \t\r 'a\0a' \v\f\f") -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") - --- hexadecimal escapes -assert("\x00\x05\x10\x1f\x3C\xfF\xe8" == "\0\5\16\31\60\255\232") - -local function lexstring (x, y, n) - local f = assert(load('return '..x..', debug.getinfo(1).currentline')) - local s, l = f() - assert(s == y and l == n) -end - -lexstring("'abc\\z \n efg'", "abcefg", 2) -lexstring("'abc\\z \n\n\n'", "abc", 4) -lexstring("'\\z \n\t\f\v\n'", "", 3) -lexstring("[[\nalo\nalo\n\n]]", "alo\nalo\n\n", 5) -lexstring("[[\nalo\ralo\n\n]]", "alo\nalo\n\n", 5) -lexstring("[[\nalo\ralo\r\n]]", "alo\nalo\n", 4) -lexstring("[[\ralo\n\ralo\r\n]]", "alo\nalo\n", 4) -lexstring("[[alo]\n]alo]]", "alo]\n]alo", 2) - -assert("abc\z - def\z - ghi\z - " == 'abcdefghi') - --- Error in escape sequences -local function lexerror (s, err) - local st, msg = load('return '..s) - if err ~= '' then err = "'"..err.."'" end - assert(not st and string.find(msg, "near "..err, 1, true)) -end --- FIXME LuaJIT ---lexerror([["abc\x"]], [[\x"]]) ---lexerror([["abc\x]], [[\x]]) ---lexerror([["\x]], [[\x]]) ---lexerror([["\x5"]], [[\x5"]]) ---lexerror([["\x5]], [[\x5]]) ---lexerror([["\xr"]], [[\xr]]) ---lexerror([["\xr]], [[\xr]]) ---lexerror([["\x.]], [[\x.]]) ---lexerror([["\x8%"]], [[\x8%]]) ---lexerror([["\xAG]], [[\xAG]]) ---lexerror([["\g"]], [[\g]]) ---lexerror([["\g]], [[\g]]) ---lexerror([["\."]], [[\.]]) - ---FIXME LuaJIT ---lexerror([["\999"]], [[\999]]) ---lexerror([["xyz\300"]], [[\300]]) ---lexerror([[" \256"]], [[\256]]) - - --- unfinished strings ---FIXME LuaJIT ---lexerror("[=[alo]]", "") ---lexerror("[=[alo]=", "") ---lexerror("[=[alo]", "") ---lexerror("'alo", "") ---lexerror("'alo \\z \n\n", "") ---lexerror("'alo \\z", "") ---lexerror([['alo \98]], "") - --- valid characters in variable names -for i = 0, 255 do - local s = string.char(i) - -- FIXME LuaJIT - --assert(not string.find(s, "[a-zA-Z_]") == not load(s .. "=1")) - --assert(not string.find(s, "[a-zA-Z_0-9]") == - -- not load("a" .. s .. "1 = 1")) -end - - --- 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(load(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 == load("return [====[\n"..s.."]====]")()) -end - - --- testing decimal point locale -if os.setlocale("pt_BR") or os.setlocale("ptb") then - -- FIXME LuaJIT - --assert(not load("á = 3")) -- parser still works with C locale - assert(not load("a = (3,4)")) - --assert(tonumber("3,4") == 3.4 and tonumber"3.4" == nil) - assert(assert(load("return 3.4"))() == 3.4) - assert(assert(load("return .4,3"))() == .4) - assert(assert(load("return 4."))() == 4.) - assert(assert(load("return 4.+.5"))() == 4.5) - local a,b = load("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 - - --- testing %q x line ends -local s = "a string with \r and \n and \r\n and \n\r" -local c = string.format("return %q", s) -assert(assert(load(c))() == s) - --- testing errors -assert(not load"a = 'non-ending string") -assert(not load"a = 'non-ending string\n'") -assert(not load"a = '\\345'") -assert(not load"a = [=x]") - -print('OK') diff --git a/lua-5.2.2-tests/locals.lua b/lua-5.2.2-tests/locals.lua deleted file mode 100644 index fcd1cf7b3e..0000000000 --- a/lua-5.2.2-tests/locals.lua +++ /dev/null @@ -1,163 +0,0 @@ -print('testing local variables and environments') - -local debug = require"debug" - - --- bug in 5.1: - -local function f(x) x = nil; return x end -assert(f(10) == nil) - -local function f() local x; return x end -assert(f(10) == nil) - -local function f(x) x = nil; local y; return x, y end -assert(f(10) == nil and select(2, f(20)) == nil) - -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 -load('local a = {}')() -assert(a == nil) - -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') - - -local function getenv (f) - local a,b = debug.getupvalue(f, 1) - assert(a == '_ENV') - return b -end - --- test for global table of loaded chunks --- FIXME LuaJIT ---assert(getenv(load"a=3") == _G) -local c = {}; local f = load("a = 3", nil, nil, c) --- FIXME LuaJIT ---assert(getenv(f) == c) -assert(c.a == nil) -f() -assert(c.a == 3) - --- testing limits for special instructions - -if not _soft then - local a - local p = 4 - for i=2,31 do - for j=-3,3 do - assert(load(string.format([[local a=%s; - a=a+%s; - assert(a ==2^%s)]], j, p-j, i))) () - assert(load(string.format([[local a=%s; - a=a-%s; - assert(a==-2^%s)]], -j, p-j, i))) () - assert(load(string.format([[local a,b=0,%s; - a=b-%s; - assert(a==-2^%s)]], -j, p-j, i))) () - end - p =2*p - end -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 - - --- testing lexical environments - -assert(_ENV == _G) - -do local _ENV = (function (...) return ... end)(_G, dummy) - -do local _ENV = {assert=assert}; assert(true) end -mt = {_G = _G} -local foo,x -do local _ENV = mt - function foo (x) - A = x - do local _ENV = _G; A = 1000 end - return function (x) return A .. x end - end -end --- FIXME LuaJIT ---assert(getenv(foo) == mt) ---x = foo('hi'); assert(mt.A == 'hi' and A == 1000) ---assert(x('*') == mt.A .. '*') - -do local _ENV = {assert=assert, A=10}; - do local _ENV = {assert=assert, A=20}; - -- FIXME LuaJIT - --assert(A==20);x=A - end - -- FIXME LuaJIT - --assert(A==10 and x==20) -end --- FIXME LuaJIT ---assert(x==20) - - -print('OK') - -return 5,f - -end - diff --git a/lua-5.2.2-tests/ltests/ltests.c b/lua-5.2.2-tests/ltests/ltests.c deleted file mode 100644 index 8d76f5af5d..0000000000 --- a/lua-5.2.2-tests/ltests/ltests.c +++ /dev/null @@ -1,1506 +0,0 @@ -/* -** $Id: ltests.c,v 2.134 2012/10/03 12:36:46 roberto Exp $ -** Internal Module for Debugging of the Lua Implementation -** See Copyright Notice in lua.h -*/ - - -#include -#include -#include -#include - -#define ltests_c -#define LUA_CORE - -#include "lua.h" - -#include "lapi.h" -#include "lauxlib.h" -#include "lcode.h" -#include "lctype.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) - - -void *l_Trick = 0; - - -int islocked = 0; - - -#define obj_at(L,k) (L->ci->func + (k)) - - -static void setnameval (lua_State *L, const char *name, int val) { - lua_pushstring(L, name); - lua_pushinteger(L, val); - lua_settable(L, -3); -} - - -static void pushobject (lua_State *L, const TValue *o) { - setobj2s(L, L->top, o); - api_incr_top(L); -} - - -static int tpanic (lua_State *L) { - fprintf(stderr, "PANIC: unprotected error in call to Lua API (%s)\n", - lua_tostring(L, -1)); - return (exit(EXIT_FAILURE), 0); /* do not return to Lua */ -} - - -/* -** {====================================================================== -** Controlled version for realloc. -** ======================================================================= -*/ - -#define MARK 0x55 /* 01010101 (a nice pattern) */ - -typedef union Header { - L_Umaxalign a; /* ensures maximum alignment for Header */ - struct { - size_t size; - int type; - } d; -} Header; - - -#if !defined(EXTERNMEMCHECK) - -/* full memory check */ -#define MARKSIZE 16 /* size of marks after each block */ -#define fillmem(mem,size) memset(mem, -MARK, size) - -#else - -/* external memory check: don't do it twice */ -#define MARKSIZE 0 -#define fillmem(mem,size) /* empty */ - -#endif - - -Memcontrol l_memcontrol = - {0L, 0L, 0L, 0L, {0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L}}; - - -static void freeblock (Memcontrol *mc, Header *block) { - if (block) { - size_t size = block->d.size; - int i; - for (i = 0; i < MARKSIZE; i++) /* check marks after block */ - lua_assert(*(cast(char *, block + 1) + size + i) == MARK); - mc->objcount[block->d.type]--; - fillmem(block, sizeof(Header) + size + MARKSIZE); /* erase block */ - free(block); /* actually free block */ - mc->numblocks--; /* update counts */ - mc->total -= size; - } -} - - -void *debug_realloc (void *ud, void *b, size_t oldsize, size_t size) { - Memcontrol *mc = cast(Memcontrol *, ud); - Header *block = cast(Header *, b); - int type; - if (mc->memlimit == 0) { /* first time? */ - char *limit = getenv("MEMLIMIT"); /* initialize memory limit */ - mc->memlimit = limit ? strtoul(limit, NULL, 10) : ULONG_MAX; - } - if (block == NULL) { - type = (oldsize < LUA_NUMTAGS) ? oldsize : 0; - oldsize = 0; - } - else { - block--; /* go to real header */ - type = block->d.type; - lua_assert(oldsize == block->d.size); - } - if (size == 0) { - freeblock(mc, block); - return NULL; - } - else if (size > oldsize && mc->total+size-oldsize > mc->memlimit) - return NULL; /* fake a memory allocation error */ - else { - Header *newblock; - int i; - size_t commonsize = (oldsize < size) ? oldsize : size; - size_t realsize = sizeof(Header) + size + MARKSIZE; - if (realsize < size) return NULL; /* arithmetic overflow! */ - newblock = cast(Header *, malloc(realsize)); /* alloc a new block */ - if (newblock == NULL) return NULL; /* really out of memory? */ - if (block) { - memcpy(newblock + 1, block + 1, commonsize); /* copy old contents */ - freeblock(mc, block); /* erase (and check) old copy */ - } - /* initialize new part of the block with something `weird' */ - fillmem(cast(char *, newblock + 1) + commonsize, size - commonsize); - /* initialize marks after block */ - for (i = 0; i < MARKSIZE; i++) - *(cast(char *, newblock + 1) + size + i) = MARK; - newblock->d.size = size; - newblock->d.type = type; - mc->total += size; - if (mc->total > mc->maxmem) - mc->maxmem = mc->total; - mc->numblocks++; - mc->objcount[type]++; - return newblock + 1; - } -} - - -/* }====================================================================== */ - - - -/* -** {====================================================== -** Functions to check memory consistency -** ======================================================= -*/ - - -static int testobjref1 (global_State *g, GCObject *f, GCObject *t) { - if (isdead(g,t)) return 0; - if (!issweepphase(g)) - return !(isblack(f) && iswhite(t)); - else return 1; -} - - -static void printobj (global_State *g, GCObject *o) { - int i = 1; - GCObject *p; - for (p = g->allgc; p != o && p != NULL; p = gch(p)->next) i++; - if (p == NULL) { - i = 1; - for (p = g->finobj; p != o && p != NULL; p = gch(p)->next) i++; - if (p == NULL) i = 0; /* zero means 'not found' */ - else i = -i; /* negative means 'found in findobj list */ - } - printf("||%d:%s(%p)-%c(%02X)||", i, ttypename(gch(o)->tt), (void *)o, - isdead(g,o)?'d':isblack(o)?'b':iswhite(o)?'w':'g', gch(o)->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))) - - -static void checkvalref (global_State *g, GCObject *f, const TValue *t) { - if (iscollectable(t)) { - lua_assert(righttt(t)); - lua_assert(testobjref(g, f, gcvalue(t))); - } -} - - -static void checktable (global_State *g, Table *h) { - int i; - Node *n, *limit = gnode(h, sizenode(h)); - GCObject *hgc = obj2gco(h); - if (h->metatable) - checkobjref(g, hgc, h->metatable); - for (i = 0; i < h->sizearray; i++) - checkvalref(g, hgc, &h->array[i]); - for (n = gnode(h, 0); n < limit; n++) { - 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; isizek; i++) { - if (ttisstring(f->k+i)) - checkobjref(g, fgc, rawtsvalue(f->k+i)); - } - for (i=0; isizeupvalues; i++) { - if (f->upvalues[i].name) - checkobjref(g, fgc, f->upvalues[i].name); - } - for (i=0; isizep; i++) { - if (f->p[i]) - checkobjref(g, fgc, f->p[i]); - } - for (i=0; isizelocvars; i++) { - if (f->locvars[i].varname) - checkobjref(g, fgc, f->locvars[i].varname); - } -} - - - -static void checkCclosure (global_State *g, CClosure *cl) { - GCObject *clgc = obj2gco(cl); - int i; - for (i = 0; i < cl->nupvalues; i++) - checkvalref(g, clgc, &cl->upvalue[i]); -} - - -static void checkLclosure (global_State *g, LClosure *cl) { - GCObject *clgc = obj2gco(cl); - int i; - if (cl->p) checkobjref(g, clgc, cl->p); - for (i=0; inupvalues; i++) { - if (cl->upvals[i]) { - lua_assert(cl->upvals[i]->tt == LUA_TUPVAL); - checkobjref(g, clgc, cl->upvals[i]); - } - } -} - - -static int lua_checkpc (pCallInfo ci) { - if (!isLua(ci)) return 1; - else { - Proto *p = ci_func(ci)->p; - return p->code <= ci->u.l.savedpc && - ci->u.l.savedpc <= p->code + p->sizecode; - } -} - - -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 = gch(uvo)->next) { - UpVal *uv = gco2uv(uvo); - lua_assert(uv->v != &uv->u.value); /* must be open */ - lua_assert(!isblack(uvo)); /* open upvalues cannot be black */ - } - for (ci = L1->ci; ci != NULL; ci = ci->previous) { - lua_assert(ci->top <= L1->stack_last); - lua_assert(lua_checkpc(ci)); - } - 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, int maybedead) { - if (isdead(g, o)) - lua_assert(maybedead); - else { - if (g->gcstate == GCSpause) - lua_assert(iswhite(o)); - switch (gch(o)->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, gco2t(o)); - break; - } - case LUA_TTHREAD: { - checkstack(g, gco2th(o)); - break; - } - case LUA_TLCL: { - checkLclosure(g, gco2lcl(o)); - break; - } - case LUA_TCCL: { - checkCclosure(g, gco2ccl(o)); - break; - } - case LUA_TPROTO: { - checkproto(g, gco2p(o)); - break; - } - case LUA_TSHRSTR: - case LUA_TLNGSTR: break; - default: lua_assert(0); - } - } -} - - -#define TESTGRAYBIT 7 - -static void checkgraylist (GCObject *l) { - while (l) { - lua_assert(isgray(l)); - lua_assert(!testbit(l->gch.marked, TESTGRAYBIT)); - l_setbit(l->gch.marked, TESTGRAYBIT); - switch (gch(l)->tt) { - case LUA_TTABLE: l = gco2t(l)->gclist; break; - case LUA_TLCL: l = gco2lcl(l)->gclist; break; - case LUA_TCCL: l = gco2ccl(l)->gclist; break; - case LUA_TTHREAD: l = gco2th(l)->gclist; break; - case LUA_TPROTO: l = gco2p(l)->gclist; break; - default: lua_assert(0); /* other objects cannot be gray */ - } - } -} - - -/* -** mark all objects in gray lists with the TESTGRAYBIT, so that -** 'checkmemory' can check that all gray objects are in a gray list -*/ -static void markgrays (global_State *g) { - if (!keepinvariant(g)) return; - checkgraylist(g->gray); - checkgraylist(g->grayagain); - checkgraylist(g->weak); - checkgraylist(g->ephemeron); - checkgraylist(g->allweak); -} - - -static void checkold (global_State *g, GCObject *o) { - int isold = 0; - for (; o != NULL; o = gch(o)->next) { - if (isold(o)) { /* old generation? */ - lua_assert(isgenerational(g)); - if (!issweepphase(g)) - isold = 1; - } - else lua_assert(!isold); /* non-old object cannot be after an old one */ - if (isgray(o)) { - lua_assert(!keepinvariant(g) || testbit(o->gch.marked, TESTGRAYBIT)); - resetbit(o->gch.marked, TESTGRAYBIT); - } - lua_assert(!testbit(o->gch.marked, TESTGRAYBIT)); - } -} - - -int lua_checkmemory (lua_State *L) { - global_State *g = G(L); - GCObject *o; - UpVal *uv; - int maybedead; - if (keepinvariant(g)) { - lua_assert(!iswhite(obj2gco(g->mainthread))); - lua_assert(!iswhite(gcvalue(&g->l_registry))); - } - else /* generational mode keeps collector in 'propagate' state */ - lua_assert(!isgenerational(g)); - lua_assert(!isdead(g, gcvalue(&g->l_registry))); - checkstack(g, g->mainthread); - resetbit(g->mainthread->marked, TESTGRAYBIT); - /* check 'allgc' list */ - markgrays(g); - checkold(g, g->allgc); - lua_assert(g->sweepgc == NULL || issweepphase(g)); - maybedead = 0; - for (o = g->allgc; o != NULL; o = gch(o)->next) { - if (g->sweepgc && o == *g->sweepgc) - maybedead = 1; /* part of the list not yet sweeped */ - checkobject(g, o, maybedead); - lua_assert(!testbit(o->gch.marked, SEPARATED)); - } - /* check 'finobj' list */ - checkold(g, g->finobj); - for (o = g->finobj; o != NULL; o = gch(o)->next) { - lua_assert(testbit(o->gch.marked, SEPARATED)); - lua_assert(gch(o)->tt == LUA_TUSERDATA || - gch(o)->tt == LUA_TTABLE); - checkobject(g, o, 0); - } - /* check 'tobefnz' list */ - checkold(g, g->tobefnz); - for (o = g->tobefnz; o != NULL; o = gch(o)->next) { - lua_assert(!iswhite(o) || g->gcstate == GCSpause); - lua_assert(!isdead(g, o) && testbit(o->gch.marked, SEPARATED)); - lua_assert(gch(o)->tt == LUA_TUSERDATA || - gch(o)->tt == LUA_TTABLE); - } - /* check 'uvhead' list */ - 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 */ - if (!isdead(g, obj2gco(uv))) - 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 = getfuncline(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; - case iAx: - sprintf(buff+strlen(buff), "%-12s%4d", name, GETARG_Ax(i)); - break; - } - return buff; -} - - -#if 0 -void luaI_printcode (Proto *pt, int size) { - int pc; - for (pc=0; pcmaxstacksize); - setnameval(L, "numparams", p->numparams); - for (pc=0; pcsizecode; 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 = getproto(obj_at(L, 1)); - lua_createtable(L, p->sizek, 0); - for (i=0; isizek; i++) { - 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 = getproto(obj_at(L, 1)); - 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, "MAXSTACK", MAXSTACK); - setnameval(L, "NUM_OPCODES", NUM_OPCODES); - return 1; -} - - -static int mem_query (lua_State *L) { - if (lua_isnone(L, 1)) { - lua_pushinteger(L, l_memcontrol.total); - lua_pushinteger(L, l_memcontrol.numblocks); - lua_pushinteger(L, l_memcontrol.maxmem); - return 3; - } - else if (lua_isnumber(L, 1)) { - l_memcontrol.memlimit = luaL_checkint(L, 1); - return 0; - } - else { - const char *t = luaL_checkstring(L, 1); - int i; - for (i = LUA_NUMTAGS - 1; i >= 0; i--) { - if (strcmp(t, ttypename(i)) == 0) { - lua_pushinteger(L, l_memcontrol.objcount[i]); - return 1; - } - } - return luaL_error(L, "unkown type '%s'", t); - } -} - - -static int settrick (lua_State *L) { - if (ttisnil(obj_at(L, 1))) - l_Trick = NULL; - else - l_Trick = gcvalue(obj_at(L, 1)); - 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 { - int marked = gcvalue(o)->gch.marked; - int n = 1; - lua_pushstring(L, iswhite(gcvalue(o)) ? "white" : - isblack(gcvalue(o)) ? "black" : "grey"); - if (testbit(marked, FINALIZEDBIT)) { - lua_pushliteral(L, "/finalized"); n++; - } - if (testbit(marked, SEPARATED)) { - lua_pushliteral(L, "/separated"); n++; - } - if (testbit(marked, FIXEDBIT)) { - lua_pushliteral(L, "/fixed"); n++; - } - if (testbit(marked, OLDBIT)) { - lua_pushliteral(L, "/old"); n++; - } - lua_concat(L, n); - } - return 1; -} - - -static int gc_state (lua_State *L) { - static const char *statenames[] = {"propagate", "atomic", - "sweepstring", "sweepudata", "sweep", "pause", ""}; - int option = luaL_checkoption(L, 1, "", statenames); - if (option == GCSpause + 1) { - lua_pushstring(L, statenames[G(L)->gcstate]); - return 1; - } - else { - global_State *g = G(L); - if (g->gckind == KGC_GEN && option == GCSpause) - luaL_error(L, "cannot go to 'pause' state in generational mode"); - lua_lock(L); - if (option < g->gcstate) { /* must cross 'pause'? */ - luaC_runtilstate(L, bitmask(GCSpause)); /* run until pause */ - if (g->gckind == KGC_GEN) - g->gcstate = GCSpropagate; /* skip pause in gen. mode */ - } - luaC_runtilstate(L, bitmask(option)); - lua_assert(G(L)->gcstate == option); - lua_unlock(L); - return 0; - } -} - - -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, (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); - 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)))) { - pushobject(L, gkey(gnode(t, i))); - } - else - lua_pushliteral(L, ""); - 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 = gch(ts)->next) { - setsvalue2s(L, L->top, rawgco2ts(ts)); - api_incr_top(L); - n++; - } - return n; - } - return 0; -} - - -static int tref (lua_State *L) { - int level = lua_gettop(L); - luaL_checkany(L, 1); - lua_pushvalue(L, 1); - lua_pushinteger(L, luaL_ref(L, LUA_REGISTRYINDEX)); - lua_assert(lua_gettop(L) == level+1); /* +1 for result */ - return 1; -} - -static int getref (lua_State *L) { - int level = lua_gettop(L); - lua_rawgeti(L, LUA_REGISTRYINDEX, luaL_checkint(L, 1)); - lua_assert(lua_gettop(L) == level+1); - return 1; -} - -static int unref (lua_State *L) { - int level = lua_gettop(L); - luaL_unref(L, LUA_REGISTRYINDEX, 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_checkinteger(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 == LUA_OK) - 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_atpanic(L1, tpanic); - lua_pushlightuserdata(L, L1); - } - else - lua_pushnil(L); - return 1; -} - - -static lua_State *getstate (lua_State *L) { - lua_State *L1 = cast(lua_State *, lua_touserdata(L, 1)); - luaL_argcheck(L, L1 != NULL, 1, "state expected"); - return L1; -} - - -static int loadlib (lua_State *L) { - static const luaL_Reg libs[] = { - {"_G", luaopen_base}, - {"coroutine", luaopen_coroutine}, - {"debug", luaopen_debug}, - {"io", luaopen_io}, - {"os", luaopen_os}, - {"math", luaopen_math}, - {"string", luaopen_string}, - {"table", luaopen_table}, - {NULL, NULL} - }; - lua_State *L1 = getstate(L); - int i; - luaL_requiref(L1, "package", luaopen_package, 1); - luaL_getsubtable(L1, LUA_REGISTRYINDEX, "_PRELOAD"); - for (i = 0; libs[i].name; i++) { - lua_pushcfunction(L1, libs[i].func); - lua_setfield(L1, -2, libs[i].name); - } - return 0; -} - -static int closestate (lua_State *L) { - lua_State *L1 = getstate(L); - lua_close(L1); - return 0; -} - -static int doremote (lua_State *L) { - lua_State *L1 = getstate(L); - 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 == LUA_OK) - status = lua_pcall(L1, 0, LUA_MULTRET, 0); - if (status != LUA_OK) { - lua_pushnil(L); - lua_pushstring(L, lua_tostring(L1, -1)); - lua_pushinteger(L, status); - 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 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 void sethookaux (lua_State *L, int mask, int count, const char *code); - -static const char *const delimits = " \t\n,;"; - -static void skip (const char **pc) { - for (;;) { - if (**pc != '\0' && strchr(delimits, **pc)) (*pc)++; - else if (**pc == '#') { - while (**pc != '\n' && **pc != '\0') (*pc)++; - } - else break; - } -} - -static int getnum_aux (lua_State *L, lua_State *L1, const char **pc) { - int res = 0; - int sig = 1; - skip(pc); - if (**pc == '.') { - res = lua_tointeger(L1, -1); - lua_pop(L1, 1); - (*pc)++; - return res; - } - else if (**pc == '-') { - sig = -1; - (*pc)++; - } - if (!lisdigit(cast_uchar(**pc))) - luaL_error(L, "number expected (%s)", *pc); - while (lisdigit(cast_uchar(**pc))) res = res*10 + (*(*pc)++) - '0'; - return sig*res; -} - -static const char *getstring_aux (lua_State *L, char *buff, const char **pc) { - int i = 0; - skip(pc); - if (**pc == '"' || **pc == '\'') { /* quoted string? */ - int quote = *(*pc)++; - while (**pc != quote) { - if (**pc == '\0') luaL_error(L, "unfinished string in C script"); - buff[i++] = *(*pc)++; - } - (*pc)++; - } - else { - while (**pc != '\0' && !strchr(delimits, **pc)) - buff[i++] = *(*pc)++; - } - buff[i] = '\0'; - return buff; -} - - -static int getindex_aux (lua_State *L, lua_State *L1, const char **pc) { - skip(pc); - switch (*(*pc)++) { - case 'R': return LUA_REGISTRYINDEX; - case 'G': return luaL_error(L, "deprecated index 'G'"); - case 'U': return lua_upvalueindex(getnum_aux(L, L1, pc)); - default: (*pc)--; return getnum_aux(L, L1, pc); - } -} - - -static void pushcode (lua_State *L, int code) { - static const char *const codes[] = {"OK", "YIELD", "ERRRUN", - "ERRSYNTAX", "ERRMEM", "ERRGCMM", "ERRERR"}; - lua_pushstring(L, codes[code]); -} - - -#define EQ(s1) (strcmp(s1, inst) == 0) - -#define getnum (getnum_aux(L, L1, &pc)) -#define getstring (getstring_aux(L, buff, &pc)) -#define getindex (getindex_aux(L, L1, &pc)) - - -static int testC (lua_State *L); -static int Cfunck (lua_State *L); - -static int runC (lua_State *L, lua_State *L1, const char *pc) { - char buff[300]; - int status = 0; - if (pc == NULL) return luaL_error(L, "attempt to runC null script"); - for (;;) { - const char *inst = getstring; - if EQ("") return 0; - else if EQ("absindex") { - lua_pushnumber(L1, lua_absindex(L1, getindex)); - } - else if EQ("isnumber") { - lua_pushboolean(L1, lua_isnumber(L1, getindex)); - } - else if EQ("isstring") { - lua_pushboolean(L1, lua_isstring(L1, getindex)); - } - else if EQ("istable") { - lua_pushboolean(L1, lua_istable(L1, getindex)); - } - else if EQ("iscfunction") { - lua_pushboolean(L1, lua_iscfunction(L1, getindex)); - } - else if EQ("isfunction") { - lua_pushboolean(L1, lua_isfunction(L1, getindex)); - } - else if EQ("isuserdata") { - lua_pushboolean(L1, lua_isuserdata(L1, getindex)); - } - else if EQ("isudataval") { - lua_pushboolean(L1, lua_islightuserdata(L1, getindex)); - } - else if EQ("isnil") { - lua_pushboolean(L1, lua_isnil(L1, getindex)); - } - else if EQ("isnull") { - lua_pushboolean(L1, lua_isnone(L1, getindex)); - } - else if EQ("tonumber") { - lua_pushnumber(L1, lua_tonumber(L1, getindex)); - } - else if EQ("topointer") { - lua_pushnumber(L1, cast(size_t, lua_topointer(L1, getindex))); - } - else if EQ("tostring") { - const char *s = lua_tostring(L1, getindex); - const char *s1 = lua_pushstring(L1, s); - lua_assert((s == NULL && s1 == NULL) || (strcmp)(s, s1) == 0); - } - else if EQ("objsize") { - lua_pushinteger(L1, lua_rawlen(L1, getindex)); - } - else if EQ("len") { - lua_len(L1, getindex); - } - else if EQ("Llen") { - lua_pushinteger(L1, luaL_len(L1, getindex)); - } - else if EQ("tocfunction") { - lua_pushcfunction(L1, lua_tocfunction(L1, getindex)); - } - else if EQ("func2num") { - lua_CFunction func = lua_tocfunction(L1, getindex); - lua_pushnumber(L1, cast(size_t, func)); - } - else if EQ("return") { - int n = getnum; - if (L1 != L) { - int i; - for (i = 0; i < n; i++) - lua_pushstring(L, lua_tostring(L1, -(n - i))); - } - return n; - } - 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, getstring); - } - else if EQ("pushnil") { - lua_pushnil(L1); - } - else if EQ("pushbool") { - lua_pushboolean(L1, getnum); - } - else if EQ("newtable") { - lua_newtable(L1); - } - else if EQ("newuserdata") { - lua_newuserdata(L1, getnum); - } - else if EQ("tobool") { - lua_pushboolean(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("pushupvalueindex") { - lua_pushinteger(L1, lua_upvalueindex(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("copy") { - int f = getindex; - lua_copy(L1, f, getindex); - } - else if EQ("gettable") { - lua_gettable(L1, getindex); - } - else if EQ("getglobal") { - lua_getglobal(L1, getstring); - } - else if EQ("getfield") { - int t = getindex; - lua_getfield(L1, t, getstring); - } - else if EQ("setfield") { - int t = getindex; - lua_setfield(L1, t, getstring); - } - else if EQ("rawgeti") { - int t = getindex; - lua_rawgeti(L1, t, getnum); - } - else if EQ("settable") { - lua_settable(L1, getindex); - } - else if EQ("setglobal") { - lua_setglobal(L1, getstring); - } - else if EQ("next") { - lua_next(L1, -2); - } - else if EQ("concat") { - lua_concat(L1, getnum); - } - else if EQ("print") { - int n = getnum; - if (n != 0) { - printf("%s\n", luaL_tolstring(L1, n, NULL)); - lua_pop(L1, 1); - } - else { - int i; - n = lua_gettop(L1); - for (i = 1; i <= n; i++) { - printf("%s ", luaL_tolstring(L1, i, NULL)); - lua_pop(L1, 1); - } - printf("\n"); - } - } - else if EQ("arith") { - static char ops[] = "+-*/%^_"; - int op; - skip(&pc); - op = strchr(ops, *pc++) - ops; - lua_arith(L1, op); - } - else if EQ("compare") { - int a = getindex; - int b = getindex; - lua_pushboolean(L1, lua_compare(L1, a, b, getnum)); - } - else if EQ("call") { - int narg = getnum; - int nres = getnum; - lua_call(L1, narg, nres); - } - else if EQ("pcall") { - int narg = getnum; - int nres = getnum; - status = lua_pcall(L1, narg, nres, 0); - } - else if EQ("pcallk") { - int narg = getnum; - int nres = getnum; - int i = getindex; - status = lua_pcallk(L1, narg, nres, 0, i, Cfunck); - } - else if EQ("callk") { - int narg = getnum; - int nres = getnum; - int i = getindex; - lua_callk(L1, narg, nres, i, Cfunck); - } - else if EQ("yield") { - return lua_yield(L1, getnum); - } - else if EQ("yieldk") { - int nres = getnum; - int i = getindex; - return lua_yieldk(L1, nres, i, Cfunck); - } - else if EQ("newthread") { - lua_newthread(L1); - } - else if EQ("resume") { - int i = getindex; - status = lua_resume(lua_tothread(L1, i), L, getnum); - } - else if EQ("pushstatus") { - pushcode(L1, status); - } - else if EQ("xmove") { - int f = getindex; - int t = getindex; - lua_State *fs = (f == 0) ? L1 : lua_tothread(L1, f); - lua_State *ts = (t == 0) ? L1 : lua_tothread(L1, t); - int n = getnum; - if (n == 0) n = lua_gettop(fs); - lua_xmove(fs, ts, n); - } - 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("append") { - int t = getindex; - int i = lua_rawlen(L1, t); - lua_rawseti(L1, t, i + 1); - } - else if EQ("getctx") { - int i = 0; - int s = lua_getctx(L1, &i); - pushcode(L1, s); - lua_pushinteger(L1, i); - } - else if EQ("checkstack") { - int sz = getnum; - luaL_checkstack(L1, sz, getstring); - } - else if EQ("newmetatable") { - lua_pushboolean(L1, luaL_newmetatable(L1, getstring)); - } - else if EQ("testudata") { - int i = getindex; - lua_pushboolean(L1, luaL_testudata(L1, i, getstring) != NULL); - } - else if EQ("gsub") { - int a = getnum; int b = getnum; int c = getnum; - luaL_gsub(L1, lua_tostring(L1, a), - lua_tostring(L1, b), - lua_tostring(L1, c)); - } - else if EQ("sethook") { - int mask = getnum; - int count = getnum; - sethookaux(L1, mask, count, getstring); - } - 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; -} - - -static int testC (lua_State *L) { - lua_State *L1; - const char *pc; - if (lua_isuserdata(L, 1)) { - L1 = getstate(L); - pc = luaL_checkstring(L, 2); - } - else if (lua_isthread(L, 1)) { - L1 = lua_tothread(L, 1); - pc = luaL_checkstring(L, 2); - } - else { - L1 = L; - pc = luaL_checkstring(L, 1); - } - return runC(L, L1, pc); -} - - -static int Cfunc (lua_State *L) { - return runC(L, L, lua_tostring(L, lua_upvalueindex(1))); -} - - -static int Cfunck (lua_State *L) { - int i = 0; - lua_getctx(L, &i); - return runC(L, L, lua_tostring(L, i)); -} - - -static int makeCfunc (lua_State *L) { - luaL_checkstring(L, 1); - lua_pushcclosure(L, Cfunc, lua_gettop(L)); - return 1; -} - - -/* }====================================================== */ - - -/* -** {====================================================== -** tests for C hooks -** ======================================================= -*/ - -/* -** C hook that runs the C script stored in registry.C_HOOK[L] -*/ -static void Chook (lua_State *L, lua_Debug *ar) { - const char *scpt; - const char *const events [] = {"call", "ret", "line", "count", "tailcall"}; - lua_getfield(L, LUA_REGISTRYINDEX, "C_HOOK"); - lua_pushlightuserdata(L, L); - lua_gettable(L, -2); /* get C_HOOK[L] (script saved by sethookaux) */ - scpt = lua_tostring(L, -1); /* not very religious (string will be popped) */ - lua_pop(L, 2); /* remove C_HOOK and script */ - lua_pushstring(L, events[ar->event]); /* may be used by script */ - lua_pushinteger(L, ar->currentline); /* may be used by script */ - runC(L, L, scpt); /* run script from C_HOOK[L] */ -} - - -/* -** sets registry.C_HOOK[L] = scpt and sets Chook as a hook -*/ -static void sethookaux (lua_State *L, int mask, int count, const char *scpt) { - if (*scpt == '\0') { /* no script? */ - lua_sethook(L, NULL, 0, 0); /* turn off hooks */ - return; - } - lua_getfield(L, LUA_REGISTRYINDEX, "C_HOOK"); /* get C_HOOK table */ - if (!lua_istable(L, -1)) { /* no hook table? */ - lua_pop(L, 1); /* remove previous value */ - lua_newtable(L); /* create new C_HOOK table */ - lua_pushvalue(L, -1); - lua_setfield(L, LUA_REGISTRYINDEX, "C_HOOK"); /* register it */ - } - lua_pushlightuserdata(L, L); - lua_pushstring(L, scpt); - lua_settable(L, -3); /* C_HOOK[L] = script */ - lua_sethook(L, Chook, mask, count); -} - - -static int sethook (lua_State *L) { - if (lua_isnoneornil(L, 1)) - lua_sethook(L, NULL, 0, 0); /* turn off hooks */ - else { - const char *scpt = luaL_checkstring(L, 1); - const char *smask = luaL_checkstring(L, 2); - int count = luaL_optint(L, 3, 0); - int mask = 0; - if (strchr(smask, 'c')) mask |= LUA_MASKCALL; - if (strchr(smask, 'r')) mask |= LUA_MASKRET; - if (strchr(smask, 'l')) mask |= LUA_MASKLINE; - if (count > 0) mask |= LUA_MASKCOUNT; - sethookaux(L, mask, count, scpt); - } - 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, L, 0); - if (status != LUA_OK && status != LUA_YIELD) { - lua_pushboolean(L, 0); - lua_insert(L, -2); - return 2; /* return false + error message */ - } - else { - lua_pushboolean(L, 1); - return 1; - } -} - -/* }====================================================== */ - - - -static const struct luaL_Reg tests_funcs[] = { - {"checkmemory", lua_checkmemory}, - {"closestate", closestate}, - {"d2s", d2s}, - {"doonnewstack", doonnewstack}, - {"doremote", doremote}, - {"gccolor", get_gccolor}, - {"gcstate", gc_state}, - {"getref", getref}, - {"hash", hash_query}, - {"int2fb", int2fb_aux}, - {"limits", get_limits}, - {"listcode", listcode}, - {"listk", listk}, - {"listlocals", listlocals}, - {"loadlib", loadlib}, - {"newstate", newstate}, - {"newuserdata", newuserdata}, - {"num2int", num2int}, - {"pushuserdata", pushuserdata}, - {"querystr", string_query}, - {"querytab", table_query}, - {"ref", tref}, - {"resume", coresume}, - {"s2d", s2d}, - {"sethook", sethook}, - {"stacklevel", stacklevel}, - {"testC", testC}, - {"makeCfunc", makeCfunc}, - {"totalmem", mem_query}, - {"trick", settrick}, - {"udataval", udataval}, - {"unref", unref}, - {"upvalue", upvalue}, - {NULL, NULL} -}; - - -static void checkfinalmem (void) { - lua_assert(l_memcontrol.numblocks == 0); - lua_assert(l_memcontrol.total == 0); -} - - -int luaB_opentests (lua_State *L) { - void *ud; - lua_atpanic(L, &tpanic); - atexit(checkfinalmem); - lua_assert(lua_getallocf(L, &ud) == debug_realloc); - lua_assert(ud == cast(void *, &l_memcontrol)); - lua_setallocf(L, lua_getallocf(L, NULL), ud); - luaL_newlib(L, tests_funcs); - return 1; -} - -#endif diff --git a/lua-5.2.2-tests/ltests/ltests.h b/lua-5.2.2-tests/ltests/ltests.h deleted file mode 100644 index 7a9d329df2..0000000000 --- a/lua-5.2.2-tests/ltests/ltests.h +++ /dev/null @@ -1,93 +0,0 @@ -/* -** $Id: ltests.h,v 2.33 2010/07/28 15:51:59 roberto Exp $ -** Internal Header for Debugging of the Lua Implementation -** See Copyright Notice in lua.h -*/ - -#ifndef ltests_h -#define ltests_h - - -#include - -/* do not use compatibility macros in Lua code */ -#undef LUA_COMPAT_API - -#define LUA_DEBUG - -#undef NDEBUG -#include -#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; - unsigned long objcount[LUA_NUMTAGS]; -} Memcontrol; - -extern Memcontrol l_memcontrol; - - -/* -** generic variable for debug tricks -*/ -extern void *l_Trick; - - -void *debug_realloc (void *ud, void *block, size_t osize, size_t nsize); - - -typedef struct CallInfo *pCallInfo; - -int lua_checkmemory (lua_State *L); - - -/* test for lock/unlock */ -#undef luai_userstateopen -#undef luai_userstatethread -#undef lua_lock -#undef lua_unlock - -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 luai_userstatefree(l,l1) \ - lua_assert(getlock(l)->plock == getlock(l1)->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); - - -#if defined(lua_c) -#define luaL_newstate() lua_newstate(debug_realloc, &l_memcontrol) -#define luaL_openlibs(L) \ - { (luaL_openlibs)(L); luaL_requiref(L, "T", luaB_opentests, 1); } -#endif - - - -/* change some sizes to give some bugs a chance */ - -#undef LUAL_BUFFERSIZE -#define LUAL_BUFFERSIZE 23 -#define MINSTRTABSIZE 2 - - -#undef LUAI_USER_ALIGNMENT_T -#define LUAI_USER_ALIGNMENT_T union { char b[32]; } - - -#endif diff --git a/lua-5.2.2-tests/main.lua b/lua-5.2.2-tests/main.lua deleted file mode 100644 index fa6bf0e2db..0000000000 --- a/lua-5.2.2-tests/main.lua +++ /dev/null @@ -1,260 +0,0 @@ -# testing special comment on first line - --- most (all?) tests here assume a reasonable "Unix-like" shell -if _port then return end - -print ("testing lua.c options") - -assert(os.execute()) -- 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: "..progname) - -local prepfile = function (s, p) - p = p or prog - io.output(p) - io.write(s) - assert(io.close()) -end - -function getoutput () - io.input(out) - local t = io.read("*a") - io.input():close() - assert(os.remove(out)) - return t -end - -function checkprogout (s) - local t = getoutput() - for line in string.gmatch(s, ".-\n") do - assert(string.find(t, line, 1, true)) - end -end - -function checkout (s) - local t = getoutput() - 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(...)) -end - -function NoRun (...) - assert(not auxrun(...)) -end - -function NoRunMsg (...) - print("\n(the next error is expected by the test)") - return NoRun(...) -end - --- test environment variables used by Lua -prepfile("print(package.path)") - -RUN("env LUA_INIT= LUA_PATH=x lua %s > %s", prog, out) -checkout("x\n") - -RUN("env LUA_INIT= LUA_PATH_5_2=y LUA_PATH=x lua %s > %s", prog, out) -checkout("y\n") - -prepfile("print(package.cpath)") - -RUN("env LUA_INIT= LUA_CPATH=xuxu lua %s > %s", prog, out) -checkout("xuxu\n") - -RUN("env LUA_INIT= LUA_CPATH_5_2=yacc LUA_CPATH=x lua %s > %s", prog, out) -checkout("yacc\n") - -prepfile("print(X)") -RUN('env LUA_INIT="X=3" lua %s > %s', prog, out) -checkout("3\n") - -prepfile("print(X)") -RUN('env LUA_INIT_5_2="X=10" LUA_INIT="X=3" lua %s > %s', prog, out) -checkout("10\n") - --- test option '-E' -prepfile("print(package.path, package.cpath)") -RUN('env LUA_INIT="error(10)" LUA_PATH=xxx LUA_CPATH=xxx lua -E %s > %s', - prog, out) -local defaultpath = getoutput() -defaultpath = string.match(defaultpath, "^(.-)\t") -- remove tab -assert(not string.find(defaultpath, "xxx") and string.find(defaultpath, "lua")) - - --- test replacement of ';;' to default path -local function convert (p) - prepfile("print(package.path)") - RUN('env LUA_PATH="%s" lua %s > %s', p, prog, out) - local expected = getoutput() - expected = string.sub(expected, 1, -2) -- cut final end of line - assert(string.gsub(p, ";;", ";"..defaultpath..";") == expected) -end - -convert(";") -convert(";;") -convert(";;;") -convert(";;;;") -convert(";;;;;") -convert(";;a;;;bc") - - --- test 2 files -prepfile("print(1); a=2; return {x=15}") -prepfile(("print(a); print(_G['%s'].x)"):format(prog), otherprog) -RUN('env LUA_PATH="?;;" lua -l %s -l%s -lstring -l io %s > %s', prog, otherprog, otherprog, out) -checkout("1\n2\n15\n2\n15\n") - -local a = [[ - assert(#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('env LUA_PATH="?;;" 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) -checkprogout("6\n10\n10\n\n") - -prepfile("a = [[b\nc\nd\ne]]\n=a") -print("temporary program file: "..prog) -RUN([[lua -e"_PROMPT='' _PROMPT2=''" -i < %s > %s]], prog, out) -checkprogout("b\nc\nd\ne\n\n") - -prompt = "alo" -prepfile[[ -- -a = 2 -]] -RUN([[lua "-e_PROMPT='%s'" -i < %s > %s]], prompt, prog, out) -local t = getoutput() -assert(string.find(t, prompt .. ".*" .. prompt .. ".*" .. prompt)) - --- test for error objects -prepfile[[ -debug = require "debug" -m = {x=0} -setmetatable(m, {__tostring = function(x) - return debug.getinfo(4).currentline + x.x -end}) -error(m) -]] -NoRun([[lua %s 2> %s]], prog, out) -- no message -checkout(progname..": 6\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) -checkprogout("11\n1\t2\n\n") - -prepfile[[#comment in 1st line without \n at the end]] -RUN("lua %s", prog) - -prepfile[[#test line number when file starts with comment line -debug = require"debug" -print(debug.getinfo(1).currentline) -]] -RUN("lua %s > %s", prog, out) -checkprogout('3') - --- close Lua with an open file -prepfile(string.format([[io.output(%q); io.write('alo')]], out)) -RUN("lua %s", prog) -checkout('alo') - --- bug in 5.2 beta (extra \0 after version line) -RUN([[lua -v -e'print"hello"' > %s]], out) -t = getoutput() -assert(string.find(t, "PUC%-Rio\nhello")) - - --- testing os.exit -prepfile("os.exit(nil, true)") -RUN("lua %s", prog) -prepfile("os.exit(0, true)") -RUN("lua %s", prog) -prepfile("os.exit(true, true)") -RUN("lua %s", prog) -prepfile("os.exit(1, true)") -NoRun("lua %s", prog) -- no message -prepfile("os.exit(false, true)") -NoRun("lua %s", prog) -- no message - -assert(os.remove(prog)) -assert(os.remove(otherprog)) -assert(not os.remove(out)) - -RUN("lua -v") - -NoRunMsg("lua -h") -NoRunMsg("lua -e") -NoRunMsg("lua -e a") -NoRunMsg("lua -f") - -print("OK") diff --git a/lua-5.2.2-tests/math.lua b/lua-5.2.2-tests/math.lua deleted file mode 100644 index 5417d529bf..0000000000 --- a/lua-5.2.2-tests/math.lua +++ /dev/null @@ -1,295 +0,0 @@ -print("testing numbers and math lib") - - --- basic float notation -assert(0e12 == 0 and .0 == 0 and 0. == 0 and .2e2 == 20 and 2.E-1 == 0.2) - -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 == 08) - a = 0 - assert(a == -a and 0 == -0) -end - -do - local x = -1 - local mz = 0/x -- minus zero - t = {[0] = 10, 20, 30, 40, 50} - assert(t[mz] == t[0] and t[-0] == t[0]) -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 - - --- testing numeric strings - -assert("2" + 1 == 3) -assert("2 " + 1 == 3) -assert(" -2 " + 1 == -1) -assert(" -0xa " + 1 == -9) - - --- testing 'tonumber' -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('-012') == -010-2) -assert(tonumber('-1.2e2') == - - -120) - -assert(tonumber("0xffffffffffff") == 2^(4*12) - 1) -assert(tonumber("0x"..string.rep("f", 150)) == 2^(4*150) - 1) -assert(tonumber('0x3.' .. string.rep('0', 100)) == 3) -assert(tonumber('0x0.' .. string.rep('0', 150).."1") == 2^(-4*151)) - --- testing 'tonumber' with base -assert(tonumber(' 001010 ', 2) == 10) -assert(tonumber(' 001010 ', 10) == 001010) --- FIXME LuaJIT ---assert(tonumber(' -1010 ', 2) == -10) -assert(tonumber('10', 36) == 36) --- FIXME LuaJIT ---assert(tonumber(' -10 ', 36) == -36) -assert(tonumber(' +1Z ', 36) == 36 + 35) --- FIXME LuaJIT ---assert(tonumber(' -1z ', 36) == -36 + -35) ---assert(tonumber('-fFfa', 16) == -(10+(16*(15+(16*(15+(16*15))))))) -assert(tonumber(string.rep('1', 42), 2) + 1 == 2^42) -assert(tonumber(string.rep('1', 34), 2) + 1 == 2^34) -assert(tonumber('ffffFFFF', 16)+1 == 2^32) -assert(tonumber('0ffffFFFF', 16)+1 == 2^32) --- FIXME LuaJIT ---assert(tonumber('-0ffffffFFFF', 16) - 1 == -2^40) -for i = 2,36 do - assert(tonumber('\t10000000000\t', i) == i^10) -end - --- testing 'tonumber' fo invalid formats -assert(f(tonumber('fFfa', 15)) == nil) -assert(f(tonumber('099', 8)) == nil) --- FIXME LuaJIT ---assert(f(tonumber('1\0', 2)) == nil) -assert(f(tonumber('', 8)) == nil) -assert(f(tonumber(' ', 9)) == nil) -assert(f(tonumber(' ', 9)) == nil) --- FIXME LuaJIT ---assert(f(tonumber('0xf', 10)) == nil) - --- FIXME LuaJIT ---assert(f(tonumber('inf')) == nil) ---assert(f(tonumber(' INF ')) == nil) ---assert(f(tonumber('Nan')) == nil) ---assert(f(tonumber('nan')) == nil) - -assert(f(tonumber(' ')) == nil) -assert(f(tonumber('')) == nil) -assert(f(tonumber('1 a')) == nil) --- FIXME LuaJIT ---assert(f(tonumber('1\0')) == nil) ---assert(f(tonumber('1 \0')) == nil) ---assert(f(tonumber('1\0 ')) == nil) -assert(f(tonumber('e1')) == nil) -assert(f(tonumber('e 1')) == nil) -assert(f(tonumber(' 3.4.5 ')) == nil) - - --- testing 'tonumber' for invalid hexadecimal formats - -assert(tonumber('0x') == nil) -assert(tonumber('x') == nil) -assert(tonumber('x3') == nil) -assert(tonumber('00x2') == nil) -assert(tonumber('0x 2') == nil) -assert(tonumber('0 x2') == nil) -assert(tonumber('23x') == nil) -assert(tonumber('- 0xaa') == nil) - - --- testing hexadecimal numerals - -assert(0x10 == 16 and 0xfff == 2^12 - 1 and 0XFB == 251) -assert(0x0p12 == 0 and 0x.0p-3 == 0) -assert(0xFFFFFFFF == 2^32 - 1) -assert(tonumber('+0x2') == 2) -assert(tonumber('-0xaA') == -170) -assert(tonumber('-0xffFFFfff') == -2^32 + 1) - --- possible confusion with decimal exponent -assert(0E+1 == 0 and 0xE+1 == 15 and 0xe-1 == 13) - - --- floating hexas - -assert(tonumber(' 0x2.5 ') == 0x25/16) -assert(tonumber(' -0x2.5 ') == -0x25/16) -assert(tonumber(' +0x0.51p+8 ') == 0x51) -assert(tonumber('0x0.51p') == nil) -assert(tonumber('0x5p+-2') == nil) -assert(0x.FfffFFFF == 1 - '0x.00000001') -assert('0xA.a' + 0 == 10 + 10/16) -assert(0xa.aP4 == 0XAA) -assert(0x4P-2 == 1) -assert(0x1.1 == '0x1.' + '+0x.1') - - -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.23E18') == 1.23*10^18) - --- 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.fmod(10,3) == 1) -assert(eq(math.sqrt(10)^2, 10)) -assert(eq(math.log(2, 10), math.log(2)/math.log(10))) -assert(eq(math.log(2, 2), 1)) -assert(eq(math.log(9, 3), 2)) -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) - --- 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') - - -if not _port then - print("testing -0 and NaN") - local mz, z = -0, 0 - assert(mz == z) - assert(1/mz < 0 and 0 < 1/z) - local a = {[mz] = 1} - assert(a[z] == 1 and a[mz] == 1) - local inf = math.huge * 2 + 1 - mz, z = -1/inf, 1/inf - assert(mz == z) - assert(1/mz < 0 and 0 < 1/z) - local NaN = inf - inf - assert(NaN ~= NaN) - assert(not (NaN < NaN)) - assert(not (NaN <= NaN)) - assert(not (NaN > NaN)) - assert(not (NaN >= NaN)) - assert(not (0 < NaN) and not (NaN < 0)) - local NaN1 = 0/0 - assert(NaN ~= NaN1 and not (NaN <= NaN1) and not (NaN1 <= NaN)) - 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) - -- string with same binary representation as 0.0 (may create problems - -- for constant manipulation in the pre-compiler) - local a1, a2, a3, a4, a5 = 0, 0, "\0\0\0\0\0\0\0\0", 0, "\0\0\0\0\0\0\0\0" - assert(a1 == a2 and a2 == a4 and a1 ~= a3) - assert(a3 == a5) -end - - -if not _port then - print("testing 'math.random'") - math.randomseed(0) - - local function aux (x1, x2, p) - local Max = -math.huge - local Min = math.huge - for i = 0, 20000 do - local t = math.random(table.unpack(p)) - Max = math.max(Max, t) - Min = math.min(Min, t) - if eq(Max, x2, 0.001) and eq(Min, x1, 0.001) then - goto ok - end - end - -- loop ended without satisfing condition - assert(false) - ::ok:: - assert(x1 <= Min and Max<=x2) - end - - aux(0, 1, {}) - aux(-10, 0, {-10,0}) -end - -for i=1,10 do - local t = math.random(5) - assert(1 <= t and t <= 5) -end - - -print('OK') diff --git a/lua-5.2.2-tests/nextvar.lua b/lua-5.2.2-tests/nextvar.lua deleted file mode 100644 index 6f5550fba0..0000000000 --- a/lua-5.2.2-tests/nextvar.lua +++ /dev/null @@ -1,466 +0,0 @@ -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 - --- testing ipairs -local x = 0 -for k,v in ipairs{10,20,30;x=12} do - x = x + 1 - assert(k == x and v == x * 10) -end - -for _ in ipairs{x=12, y=24} do assert(nil) end - --- test for 'false' x ipair -x = false -local i = 0 -for k,v in ipairs{true,false,true,false} do - i = i + 1 - x = not x - assert(x == v) -end -assert(i == 4) - --- iterator function is always the same -assert(type(ipairs{}) == 'function' and ipairs{} == ipairs{}) - -if T then --[ --- testing table sizes - -local function log2 (x) return math.log(x, 2) 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 C library sizes -do - local s = 0 - for _ in pairs(math) do s = s + 1 end - check(math, 0, mp2(s)) -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 = load(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 = {table.unpack(a,1,k)} - assert(#a == k) - check(a, k, 0) - a = {1,2,3,table.unpack(a,1,k)} - check(a, k+3, 0) - assert(#a == k + 3) -end - - --- 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) -if not _port then - for i=1,11 do a[i] = nil end - for i=30,50 do a[i] = nil end -- force a rehash (?) - check(a, 0, 8) -- only 5 elements in the table - a[10] = 1 - for i=30,50 do a[i] = nil end -- force a rehash (?) - check(a, 0, 8) -- only 6 elements in the table - for i=1,14 do a[i] = nil end - for i=18,50 do a[i] = nil end -- force a rehash (?) - check(a, 0, 4) -- only 2 elements ([15] and [16]) -end - --- 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, table.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 - - --- next uses always the same iteraction function -assert(next{} == next{}) - -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 - - -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.fmod(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 - -do -- clear global table - local a = {} - for n,v in pairs(_G) do a[n]=v end - for n,v in pairs(a) do - if not package.loaded[n] and type(v) ~= "function" and - not string.find(n, "^[%u_]") then - _G[n] = nil - end - collectgarbage() - end -end - - --- - -local function checknext (a) - local 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(#{} == 0) -assert(#{[-1] = 2} == 0) -assert(#{1,2,3,nil,nil} == 3) -for i=0,40 do - local a = {} - for j=1,i do a[j]=j end - assert(#a == i) -end - --- 'maxn' is now deprecated, but it is easily defined in Lua -function table.maxn (t) - local max = 0 - for k in pairs(t) do - max = (type(k) == 'number') and math.max(max, k) or max - end - return max -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) - -table.maxn = nil - --- int overflow -a = {} -for i=0,50 do a[math.pow(2,i)] = true end -assert(a[#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) - assert(not pcall(table.insert, a, 2, 20)); - table.insert(a, 10); table.insert(a, 2, 20); - table.insert(a, 1, -1); table.insert(a, 40); - table.insert(a, #a+1, 50) - table.insert(a, 2, -2) - assert(not pcall(table.insert, a, 0, 20)); - assert(not pcall(table.insert, a, #a + 2, 20)); - 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) - assert(table.remove(a) == nil) - assert(table.remove(a, #a) == nil) -end - -a = {n=0, [-7] = "ban"} --- FIXME LuaJIT ---test(a) -assert(a.n == 0 and a[-7] == "ban") - -a = {[-7] = "ban"}; --- FIXME LuaJIT ---test(a) -assert(a.n == nil and #a == 0 and a[-7] == "ban") - -a = {[-1] = "ban"} --- FIXME LuaJIT ---test(a) -assert(#a == 0 and table.remove(a) == nil and a[-1] == "ban") - -a = {[0] = "ban"} --- FIXME LuaJIT ---assert(#a == 0 and table.remove(a) == "ban" and a[0] == nil) - -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) -assert(table.remove(a) == nil) - -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.remove(a, 1) == nil) -assert(#a == 0 and a.n == nil) - -a = {10,20,30,40} -assert(table.remove(a, #a + 1) == nil) --- FIXME LuaJIT ---assert(not pcall(table.remove, a, 0)) -assert(a[#a] == 40) -assert(table.remove(a, #a) == 40) -assert(a[#a] == 30) -assert(table.remove(a, 2) == 20) -assert(a[#a] == 30 and #a == 2) -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) - -if not _port then - print("testing precision in numeric for") - local a = 0; for i=0, 1, 0.1 do a=a+1 end; assert(a==11) - 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) -end - --- 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, table.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) - - - --- testing __pairs and __ipairs metamethod -a = {} -do - local x,y,z = pairs(a) - assert(type(x) == 'function' and y == a and z == nil) -end - -local function foo (e,i) - assert(e == a) - if i <= 10 then return i+1, i+2 end -end - -local function foo1 (e,i) - i = i + 1 - assert(e == a) - if i <= e.n then return i,a[i] end -end - -setmetatable(a, {__pairs = function (x) return foo, x, 0 end}) - -local i = 0 -for k,v in pairs(a) do - i = i + 1 - assert(k == i and v == k+1) -end - -a.n = 5 -a[3] = 30 - -a = {n=10} -setmetatable(a, {__len = function (x) return x.n end, - __ipairs = function (x) return function (e,i) - if i < #e then return i+1 end - end, x, 0 end}) -i = 0 -for k,v in ipairs(a) do - i = i + 1 - assert(k == i and v == nil) -end -assert(i == a.n) - -print"OK" diff --git a/lua-5.2.2-tests/pm.lua b/lua-5.2.2-tests/pm.lua deleted file mode 100644 index 30bfaadb37..0000000000 --- a/lua-5.2.2-tests/pm.lua +++ /dev/null @@ -1,347 +0,0 @@ -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(string.match("aaab", ".*b") == "aaab") -assert(string.match("aaa", ".*a") == "aaa") -assert(string.match("b", ".*b") == "b") - -assert(string.match("aaab", ".+b") == "aaab") -assert(string.match("aaa", ".+a") == "aaa") -assert(not string.match("b", ".+b")) - -assert(string.match("aaab", ".?b") == "ab") -assert(string.match("aaa", ".?a") == "aa") -assert(string.match("b", ".?b") == "b") - -assert(f('aloALO', '%l*') == 'alo') -assert(f('aLo_ALO', '%a*') == 'aLo') - -assert(f(" \n\r*&\n\r xuxu \n\n", "%g%g%g+") == "xuxu") - -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 load(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")) - --- bug since 2.5 (C-stack overflow) -do - local function f (size) - local s = string.rep("a", size) - local p = string.rep(".?", size) - return pcall(string.match, s, p) - end - local r, m = f(80) - assert(r and #m == 80) - r, m = f(200000) - assert(not r and string.find(m, "too complex")) -end - -if not _soft then - -- 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-.?$')) - - -- bug in 5.1.2 - a = string.rep('a', 10000) .. string.rep('b', 10000) - assert(not pcall(string.gsub, a, 'b')) -end - --- recursive nest of gsubs -function rev (s) - return string.gsub(s, "(.)(.+)", function (c,s1) return rev(s1)..c end) -end - -local x = "abcdef" -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 -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(#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.") - -assert(string.find("a", "%f[a]") == 1) -assert(string.find("a", "%f[^%z]") == 1) -assert(string.find("a", "%f[^%l]") == 2) -assert(string.find("aba", "%f[a%z]") == 3) -assert(string.find("aba", "%f[%z]") == 4) -assert(not string.find("aba", "%f[%l%z]")) -assert(not string.find("aba", "%f[^%l%z]")) - -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(#a == 0) - - --- malformed patterns -local function malform (p, m) - m = m or "malformed" - local r, msg = pcall(string.find, "a", p) - assert(not r and string.find(msg, m)) -end - -malform("[a") -malform("[]") -malform("[^]") -malform("[a%]") -malform("[a%") --- FIXME LuaJIT ---malform("%b") ---malform("%ba") -malform("%") -malform("%f", "missing") - --- \0 in patterns --- FIXME LuaJIT ---assert(string.match("ab\0\1\2c", "[\0-\2]+") == "\0\1\2") ---assert(string.match("ab\0\1\2c", "[\0-\0]+") == "\0") ---assert(string.find("b$a", "$\0?") == 2) ---assert(string.find("abc\0efg", "%\0") == 4) ---assert(string.match("abc\0efg\0\1e\1g", "%b\0\1") == "\0efg\0\1e\1") ---assert(string.match("abc\0\0\0", "%\0+") == "\0\0\0") ---assert(string.match("abc\0\0\0", "%\0%\0?") == "\0\0") - --- magic char after \0 --- FIXME LuaJIT ---assert(string.find("abc\0\0","\0.") == 4) ---assert(string.find("abcx\0\0abc\0abc","x\0\0abc\0a.") == 4) - -print('OK') - diff --git a/lua-5.2.2-tests/run.sh b/lua-5.2.2-tests/run.sh deleted file mode 100644 index 4bdd530455..0000000000 --- a/lua-5.2.2-tests/run.sh +++ /dev/null @@ -1,18 +0,0 @@ -export LUA_PATH="?;./?.lua" -export LUA_INIT="package.path = '?;'..package.path" - -luajit -joff -e"_port=1" all.lua -if [ $? != 0 ] -then - echo "all.lua tests failed with JIT off" - exit 1 -fi - - -luajit -jon -e"_port=1" all.lua -if [ $? != 0 ] -then - echo "all.lua tests failed with JIT on" - exit 1 -fi - diff --git a/lua-5.2.2-tests/sort.lua b/lua-5.2.2-tests/sort.lua deleted file mode 100644 index 85b9cf4c2a..0000000000 --- a/lua-5.2.2-tests/sort.lua +++ /dev/null @@ -1,169 +0,0 @@ -print "testing (parts of) table library" - --- FIXME LuaJIT pack/unpack tests disabled -if false then -print "testing unpack" - -local unpack = table.unpack - -local x,y,z,a,n -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(#x == lim and x[1] == 1 and x[lim] == lim) -x = {unpack(a, lim-2)} -assert(#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) - -if not _no32 then - assert(not pcall(unpack, {}, 0, 2^31-1)) - assert(not pcall(unpack, {}, 1, 2^31-1)) - assert(not pcall(unpack, {}, -(2^31), 2^31-1)) - assert(not pcall(unpack, {}, -(2^31 - 1), 2^31-1)) - assert(pcall(unpack, {}, 2^31-1, 0)) - assert(pcall(unpack, {}, 2^31-1, 1)) - pcall(unpack, {}, 1, 2^31) - a, b = unpack({[2^31-1] = 20}, 2^31-1, 2^31-1) - assert(a == 20 and b == nil) - a, b = unpack({[2^31-1] = 20}, 2^31-2, 2^31-1) - assert(a == nil and b == 20) -end - -print "testing pack" - -a = table.pack() -assert(a[1] == nil and a.n == 0) - -a = table.pack(table) -assert(a[1] == table and a.n == 1) - -a = table.pack(nil, nil, nil, nil) -assert(a[1] == nil and a.n == 4) -end - -print"testing sort" - - --- test checks for invalid order functions -local function check (t) - local function f(a, b) assert(a and b); return true end - local s, e = pcall(table.sort, t, f) - assert(not s and e:find("invalid order function")) -end - -check{1,2,3,4} -check{1,2,3,4,5} -check{1,2,3,4,5,6} - - -function check (a, f) - f = f or function (x,y) return x '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") -if not _no32 then - assert(string.sub("123456789",-2^31, -4) == "123456") - assert(string.sub("123456789",-2^31, 2^31 - 1) == "123456789") - assert(string.sub("123456789",-2^31, -2^31) == "") -end -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("", "", 1) == 1) -assert(not string.find("", "", 2)) -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("\xe4") > 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("\xe4"), 0) == "\0\xe4\0") -assert(string.char(string.byte("\xe4l\0óu", 1, -1)) == "\xe4l\0óu") -assert(string.char(string.byte("\xe4l\0óu", 1, 0)) == "") -assert(string.char(string.byte("\xe4l\0óu", -10, 100)) == "\xe4l\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) == '') - --- repetitions with separator -assert(string.rep('teste', 0, 'xuxu') == '') -assert(string.rep('teste', 1, 'xuxu') == 'teste') -assert(string.rep('\1\0\1', 2, '\0\0') == '\1\0\1\0\0\1\0\1') -assert(string.rep('', 10, '.') == string.rep('.', 9)) -if not _no32 then - assert(not pcall(string.rep, "aa", 2^30)) - assert(not pcall(string.rep, "", 2^30, "aa")) -end - -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") == [["\0"]]) -assert(load(string.format('return %q', x))() == x) -x = "\0\1\0023\5\0009" -assert(load(string.format('return %q', x))() == x) -assert(string.format("\0%c\0%c%x\0", string.byte("\xe4"), string.byte("b"), 140) == - "\0\xe4\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")) - --- format x tostring -assert(string.format("%s %s", nil, true) == "nil true") -assert(string.format("%s %.4s", false, true) == "false true") -assert(string.format("%.3s %.3s", false, true) == "fal tru") -local m = setmetatable({}, {__tostring = function () return "hello" end}) -assert(string.format("%s %.10s", m, m) == "hello hello") - - -assert(string.format("%x", 0.3) == "0") -assert(string.format("%02x", 0.1) == "00") -assert(string.format("%08X", 2^32 - 1) == "FFFFFFFF") -assert(string.format("%+08d", 2^31 - 1) == "+2147483647") -assert(string.format("%+08d", -2^31) == "-2147483648") - - --- longest number that can be formated -assert(string.len(string.format('%99.99f', -1e308)) >= 100) - - - -if not _nolonglong then - print("testing large numbers for format") - assert(string.format("%8x", 2^52 - 1) == "fffffffffffff") - assert(string.format("%d", -1) == "-1") - assert(tonumber(string.format("%u", 2^62)) == 2^62) - assert(string.format("%8x", 0xffffffff) == "ffffffff") - assert(string.format("%8x", 0x7fffffff) == "7fffffff") - assert(string.format("%d", 2^53) == "9007199254740992") - assert(string.format("%d", -2^53) == "-9007199254740992") - assert(string.format("0x%8X", 0x8f000003) == "0x8F000003") - -- maximum integer that fits both in 64-int and (exact) double - local x = 2^64 - 2^(64-53) - assert(x == 0xfffffffffffff800) - assert(tonumber(string.format("%u", x)) == x) - assert(tonumber(string.format("0X%x", x)) == x) - assert(string.format("%x", x) == "fffffffffffff800") - assert(string.format("%d", x/2) == "9223372036854774784") - assert(string.format("%d", -x/2) == "-9223372036854774784") - assert(string.format("%d", -2^63) == "-9223372036854775808") - assert(string.format("%x", 2^63) == "8000000000000000") -end - -if not _noformatA then - print("testing 'format %a %A'") - assert(string.format("%.2a", 0.5) == "0x1.00p-1") - assert(string.format("%A", 0x1fffffffffffff) == "0X1.FFFFFFFFFFFFFP+52") - assert(string.format("%.4a", -3) == "-0x1.8000p+1") - assert(tonumber(string.format("%a", -0.1)) == -0.1) -end - --- errors in format - -local function check (fmt, msg) - local s, err = pcall(string.format, fmt, 10) - assert(not s and string.find(err, msg)) -end - -local aux = string.rep('0', 600) -check("%100.3d", "too long") -check("%1"..aux..".3d", "too long") -check("%1.100d", "too long") -check("%10.1"..aux.."004d", "too long") -check("%t", "invalid option") -check("%"..aux.."d", "repeated flags") -check("%d %d", "no value") - - --- integers out of range ---FIXME LuaJIT ---assert(not pcall(string.format, "%d", 2^63)) ---assert(not pcall(string.format, "%x", 2^64)) ---assert(not pcall(string.format, "%x", -2^64)) ---assert(not pcall(string.format, "%x", -1)) - - -assert(load("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, "x", 22, 21) == "") -assert(table.concat(a, "3", 2999) == "xuxu3xuxu") -if not _no32 then - assert(table.concat({}, "x", 2^31-1, 2^31-2) == "") - assert(table.concat({}, "x", -2^31+1, -2^31) == "") - assert(table.concat({}, "x", 2^31-1, -2^31) == "") - assert(table.concat({[2^31-1] = "alo"}, "x", 2^31-1, 2^31-1) == "alo") -end - -assert(not pcall(table.concat, {"a", "b", {}})) - -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) == "") - -if not _port then - -local locales = { "ptb", "ISO-8859-1", "pt_BR" } -local function trylocale (w) - for i = 1, #locales do - if os.setlocale(locales[i], w) then return true end - end - return false -end - -if not trylocale("collate") then - print("locale not supported") -else - -- FIXME LuaJIT - --assert("alo" < "álo" and "álo" < "amo") -end - -if not trylocale("ctype") then - print("locale not supported") -else - assert(load("a = 3.4")); -- parser should not change outside locale - -- FIXME LuaJIT - --assert(not load("á = 3.4")); -- even with errors - --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') - -end - -print('OK') - - diff --git a/lua-5.2.2-tests/vararg.lua b/lua-5.2.2-tests/vararg.lua deleted file mode 100644 index a986520796..0000000000 --- a/lua-5.2.2-tests/vararg.lua +++ /dev/null @@ -1,125 +0,0 @@ -print('testing vararg') - -_G.arg = nil - -function f(a, ...) - local arg = {n = select('#', ...), ...} - 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 = #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 {n = select('#', ...), ...} end - -local call = function (f, args) return f(table.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 (...) local arg = {...}; return self[...]+#arg 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 = load[[ return {...} ]] -x = f(2,3) -assert(x[1] == 2 and x[2] == 3 and x[3] == nil) - - -f = load[[ - 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, table.unpack{10,20,30,40})} -assert(#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/lua-5.2.2-tests/verybig.lua b/lua-5.2.2-tests/verybig.lua deleted file mode 100644 index 69007482c3..0000000000 --- a/lua-5.2.2-tests/verybig.lua +++ /dev/null @@ -1,144 +0,0 @@ -print "testing RK" - --- testing opcodes with RK arguments larger than K limit -local function foo () - local dummy = { - -- fill first 256 entries in table of constants - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, - 145, 146, 147, 148, 149, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, 206, 207, 208, - 209, 210, 211, 212, 213, 214, 215, 216, - 217, 218, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 228, 229, 230, 231, 232, - 233, 234, 235, 236, 237, 238, 239, 240, - 241, 242, 243, 244, 245, 246, 247, 248, - 249, 250, 251, 252, 253, 254, 255, 256, - } - assert(24.5 + 0.6 == 25.1) - local t = {foo = function (self, x) return x + self.x end, x = 10} - t.t = t - assert(t:foo(1.5) == 11.5) - assert(t.t:foo(0.5) == 10.5) -- bug in 5.2 alpha - assert(24.3 == 24.3) - assert((function () return t.x end)() == 10) -end - - -foo() -foo = nil - -if _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) - - -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[#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 - diff --git a/lua5.1-tests/README.md b/lua5.1-tests/README.md deleted file mode 100644 index 1b493c5da5..0000000000 --- a/lua5.1-tests/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# Lua 5.1 Test Suite - -This directory contains a modified version of the [Lua 5.1 test suite](http://www.lua.org/tests/). The modifications are primarily to disable or amend some tests so that the test suite can be run. - -## LuaJIT build options - -Some tests will fail if LUA 5.2 compatibility is turned on. - -## Running the test suite - -You need to have `luajit` on your path. - -On UNIX systems just execute: -``` -sh run.sh -``` - -## Platform Status - -The modified test suite passes on OSX El Capitan and Ubuntu 14.04. - -## Tests disabled or ignored -Wherever tests have been switched off or ignored a comment has been added and the code has been made conditional. These failures will -be investigated and either the tests will be modified so that they work for LuaJIT or optionally enabled depending upon whether the issue is one of compatibility or a defect in LuaJIT. - -Example of excluded test: -``` --- FIXME tests fail in LuaJIT --- dofile('main.lua') -``` diff --git a/lua5.1-tests/all.lua b/lua5.1-tests/all.lua deleted file mode 100755 index 30c1c72e86..0000000000 --- a/lua5.1-tests/all.lua +++ /dev/null @@ -1,140 +0,0 @@ -#!../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 - --- FIXME tests fail in LuaJIT ---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 - --- FIXME tests fail in LuaJIT --- local f = assert(loadfile('gc.lua')) --- f() --- FIXME tests fail in LuaJIT --- 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/lua5.1-tests/api.lua b/lua5.1-tests/api.lua deleted file mode 100644 index c2d262f07b..0000000000 --- a/lua5.1-tests/api.lua +++ /dev/null @@ -1,711 +0,0 @@ - -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/lua5.1-tests/attrib.lua b/lua5.1-tests/attrib.lua deleted file mode 100644 index b14d686643..0000000000 --- a/lua5.1-tests/attrib.lua +++ /dev/null @@ -1,339 +0,0 @@ -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(ab == 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/lua5.1-tests/big.lua b/lua5.1-tests/big.lua deleted file mode 100644 index 92612880ea..0000000000 --- a/lua5.1-tests/big.lua +++ /dev/null @@ -1,381 +0,0 @@ -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/lua5.1-tests/calls.lua b/lua5.1-tests/calls.lua deleted file mode 100644 index 788f9a1cd1..0000000000 --- a/lua5.1-tests/calls.lua +++ /dev/null @@ -1,294 +0,0 @@ -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" 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/lua5.1-tests/closure.lua b/lua5.1-tests/closure.lua deleted file mode 100644 index 6643c83769..0000000000 --- a/lua5.1-tests/closure.lua +++ /dev/null @@ -1,423 +0,0 @@ -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) --- FIXME assertion fails in LuaJIT ---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/lua5.1-tests/code.lua b/lua5.1-tests/code.lua deleted file mode 100644 index efb13c7ae3..0000000000 --- a/lua5.1-tests/code.lua +++ /dev/null @@ -1,143 +0,0 @@ - -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/lua5.1-tests/constructs.lua b/lua5.1-tests/constructs.lua deleted file mode 100644 index 470f85396f..0000000000 --- a/lua5.1-tests/constructs.lua +++ /dev/null @@ -1,240 +0,0 @@ -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/lua5.1-tests/db.lua b/lua5.1-tests/db.lua deleted file mode 100644 index 09496f6fa5..0000000000 --- a/lua5.1-tests/db.lua +++ /dev/null @@ -1,499 +0,0 @@ --- 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/lua5.1-tests/docs/README b/lua5.1-tests/docs/README deleted file mode 100644 index e2d4b28501..0000000000 --- a/lua5.1-tests/docs/README +++ /dev/null @@ -1,41 +0,0 @@ -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/lua5.1-tests/errors.lua b/lua5.1-tests/errors.lua deleted file mode 100644 index 864d640730..0000000000 --- a/lua5.1-tests/errors.lua +++ /dev/null @@ -1,253 +0,0 @@ -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)", "", 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'") --- FIXME assertion fails in LuaJIT ---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'") - --- FIXME assertion fails in LuaJIT ---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 --- FIXME assertion fails in LuaJIT --- 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/lua5.1-tests/etc/ltests.c b/lua5.1-tests/etc/ltests.c deleted file mode 100644 index b14608bed5..0000000000 --- a/lua5.1-tests/etc/ltests.c +++ /dev/null @@ -1,1147 +0,0 @@ -/* -** $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 -#include -#include -#include -#include - -#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;inumblocks--; - 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;igcstate == 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; isizek; i++) { - if (ttisstring(f->k+i)) - checkobjref(g, fgc, rawtsvalue(f->k+i)); - } - for (i=0; isizeupvalues; i++) { - if (f->upvalues[i]) - checkobjref(g, fgc, f->upvalues[i]); - } - for (i=0; isizep; i++) { - if (f->p[i]) - checkobjref(g, fgc, f->p[i]); - } - for (i=0; isizelocvars; 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; ic.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; il.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; pcl.p; - lua_newtable(L); - setnameval(L, "maxstack", p->maxstacksize); - setnameval(L, "numparams", p->numparams); - for (pc=0; pcsizecode; 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; isizek; 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, ""); - 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/lua5.1-tests/etc/ltests.h b/lua5.1-tests/etc/ltests.h deleted file mode 100644 index e5702127f8..0000000000 --- a/lua5.1-tests/etc/ltests.h +++ /dev/null @@ -1,92 +0,0 @@ -/* -** $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 - - -#define LUA_DEBUG - -#undef NDEBUG -#include -#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/lua5.1-tests/events.lua b/lua5.1-tests/events.lua deleted file mode 100644 index 5234b007a0..0000000000 --- a/lua5.1-tests/events.lua +++ /dev/null @@ -1,360 +0,0 @@ -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 aOp(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/lua5.1-tests/files.lua b/lua5.1-tests/files.lua deleted file mode 100644 index 4175dc34a0..0000000000 --- a/lua5.1-tests/files.lua +++ /dev/null @@ -1,324 +0,0 @@ - -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/lua5.1-tests/gc.lua b/lua5.1-tests/gc.lua deleted file mode 100644 index 86a9f7582c..0000000000 --- a/lua5.1-tests/gc.lua +++ /dev/null @@ -1,312 +0,0 @@ -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/lua5.1-tests/libs/P1/dummy b/lua5.1-tests/libs/P1/dummy deleted file mode 100644 index 421376db9e..0000000000 --- a/lua5.1-tests/libs/P1/dummy +++ /dev/null @@ -1 +0,0 @@ -dummy diff --git a/lua5.1-tests/libs/lib1.c b/lua5.1-tests/libs/lib1.c deleted file mode 100644 index da2c41481d..0000000000 --- a/lua5.1-tests/libs/lib1.c +++ /dev/null @@ -1,40 +0,0 @@ -/* -** 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/lua5.1-tests/libs/lib11.c b/lua5.1-tests/libs/lib11.c deleted file mode 100644 index 3efa3d3eb6..0000000000 --- a/lua5.1-tests/libs/lib11.c +++ /dev/null @@ -1,18 +0,0 @@ -/* -** 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/lua5.1-tests/libs/lib2.c b/lua5.1-tests/libs/lib2.c deleted file mode 100644 index 9972cbe43d..0000000000 --- a/lua5.1-tests/libs/lib2.c +++ /dev/null @@ -1,28 +0,0 @@ -/* -** 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/lua5.1-tests/libs/lib21.c b/lua5.1-tests/libs/lib21.c deleted file mode 100644 index 167507f99b..0000000000 --- a/lua5.1-tests/libs/lib21.c +++ /dev/null @@ -1,18 +0,0 @@ -/* -** 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/lua5.1-tests/libs/makefile b/lua5.1-tests/libs/makefile deleted file mode 100644 index 03c33a3470..0000000000 --- a/lua5.1-tests/libs/makefile +++ /dev/null @@ -1,16 +0,0 @@ -all: lib1.so lib11.so lib2.so lib21.so -lib2.so - -lib1.so: lib1.c - gcc -Wall -O2 -I../../ -ansi -shared -o lib1.so lib1.c - -lib11.so: lib11.c - gcc -Wall -O2 -I../../ -ansi -shared -o lib11.so lib11.c - -lib2.so: lib2.c - gcc -Wall -O2 -I../../ -ansi -shared -o lib2.so lib2.c - -lib21.so: lib21.c - gcc -Wall -O2 -I../../ -ansi -shared -o lib21.so lib21.c - --lib2.so: lib2.so - cp lib2.so ./-lib2.so diff --git a/lua5.1-tests/literals.lua b/lua5.1-tests/literals.lua deleted file mode 100644 index 49d4763e2a..0000000000 --- a/lua5.1-tests/literals.lua +++ /dev/null @@ -1,177 +0,0 @@ -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 --- FIXME assertion fails in LuaJIT - --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/lua5.1-tests/locals.lua b/lua5.1-tests/locals.lua deleted file mode 100644 index b0fc556f69..0000000000 --- a/lua5.1-tests/locals.lua +++ /dev/null @@ -1,127 +0,0 @@ -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/lua5.1-tests/main.lua b/lua5.1-tests/main.lua deleted file mode 100644 index 22b4f74b02..0000000000 --- a/lua5.1-tests/main.lua +++ /dev/null @@ -1,159 +0,0 @@ -# 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/lua5.1-tests/math.lua b/lua5.1-tests/math.lua deleted file mode 100644 index 5076f38d77..0000000000 --- a/lua5.1-tests/math.lua +++ /dev/null @@ -1,208 +0,0 @@ -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/lua5.1-tests/nextvar.lua b/lua5.1-tests/nextvar.lua deleted file mode 100644 index 23be43d8ec..0000000000 --- a/lua5.1-tests/nextvar.lua +++ /dev/null @@ -1,396 +0,0 @@ -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/lua5.1-tests/pm.lua b/lua5.1-tests/pm.lua deleted file mode 100644 index fa125dc979..0000000000 --- a/lua5.1-tests/pm.lua +++ /dev/null @@ -1,273 +0,0 @@ -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/lua5.1-tests/run.sh b/lua5.1-tests/run.sh deleted file mode 100644 index 2cd06ae16f..0000000000 --- a/lua5.1-tests/run.sh +++ /dev/null @@ -1,18 +0,0 @@ -export LUA_PATH="?;./?.lua" -export LUA_INIT="package.path = '?;'..package.path" - -luajit -joff all.lua -if [ $? != 0 ] -then - echo "all.lua tests failed with JIT off" - exit 1 -fi - - -luajit -jon all.lua -if [ $? != 0 ] -then - echo "all.lua tests failed with JIT on" - exit 1 -fi - diff --git a/lua5.1-tests/sort.lua b/lua5.1-tests/sort.lua deleted file mode 100644 index 6fccd49ea2..0000000000 --- a/lua5.1-tests/sort.lua +++ /dev/null @@ -1,74 +0,0 @@ -print"testing sort" - - -function check (a, f) - f = f or function (x,y) return x '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\\') --- FIXME assertion fails in LuaJIT ---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 --- FIXME assertion fails in LuaJIT --- assert("alo" < "álo" and "álo" < "amo") -end - -if not trylocale("ctype") then - print("locale not supported") -else --- FIXME assertion fails in LuaJIT --- 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/lua5.1-tests/vararg.lua b/lua5.1-tests/vararg.lua deleted file mode 100644 index 453511f3a3..0000000000 --- a/lua5.1-tests/vararg.lua +++ /dev/null @@ -1,130 +0,0 @@ -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 - --- FIXME assertion fails in LuaJIT ---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) --- FIXME assertion fails in LuaJIT ---assert(a[1] == b and a[2] == c and a.n == 2) -a = vararg(call(call, {c12, {1,2}})) --- FIXME assertion fails in LuaJIT ---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 --- FIXME assertion fails in LuaJIT ---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/lua5.1-tests/verybig.lua b/lua5.1-tests/verybig.lua deleted file mode 100644 index 59e0142a17..0000000000 --- a/lua5.1-tests/verybig.lua +++ /dev/null @@ -1,100 +0,0 @@ -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 - From 071f050107ead4e717562dace5859e799d146ebe Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Wed, 12 Oct 2016 10:17:29 -0700 Subject: [PATCH 57/68] Exercise string concat some more --- test/lang/concat.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/lang/concat.lua b/test/lang/concat.lua index 50dd450c99..04d665b2b7 100644 --- a/test/lang/concat.lua +++ b/test/lang/concat.lua @@ -99,3 +99,14 @@ do --- Sink into side-exit 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 From bcf938bcb6c546831f880993cd2918b1fa111f0f Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Wed, 12 Oct 2016 10:21:10 -0700 Subject: [PATCH 58/68] Extend cdata_var test slightly --- test/lib/ffi/cdata_var.lua | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/test/lib/ffi/cdata_var.lua b/test/lib/ffi/cdata_var.lua index d388c00233..42d6028a53 100644 --- a/test/lib/ffi/cdata_var.lua +++ b/test/lib/ffi/cdata_var.lua @@ -2,8 +2,8 @@ local ffi = require("ffi") do --- byte array allocations local typ = ffi.typeof"uint8_t[?]" - for i = 4, 20 do - for d = -3, 3 do + 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) @@ -17,6 +17,8 @@ do --- byte array allocations 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) @@ -35,6 +37,10 @@ do --- int array allocations 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 From f333908a8699b2f5148b8f7bb621b7a5d8430788 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Mon, 17 Oct 2016 08:45:49 +0000 Subject: [PATCH 59/68] Added bench/PARAM_x86_CI.txt (CI params) This file specifies benchmarks to run for CI. This list is based on PARAM_x86.txt. I removed benchmarks that error and checked that everything runs for between 0.1s and 10s on the CI servers. Full run takes around 50s. --- bench/PARAM_x86_CI.txt | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 bench/PARAM_x86_CI.txt diff --git a/bench/PARAM_x86_CI.txt b/bench/PARAM_x86_CI.txt new file mode 100644 index 0000000000..0a90016863 --- /dev/null +++ b/bench/PARAM_x86_CI.txt @@ -0,0 +1,27 @@ +array3d 300 +binary-trees 16 +chameneos 1e7 +coroutine-ring 2e7 +euler14-bit 2e7 +fannkuch 11 +fasta 5e6 +life +mandelbrot 5000 +mandelbrot-bit 5000 +md5 20000 +nbody 5e6 +nsieve 12 +nsieve-bit 12 +nsieve-bit-fp 12 +partialsums 1e7 +pidigits-nogmp 5000 +ray 9 +recursive-ack 10 +recursive-fib 40 +scimark-fft 50000 +scimark-lu 5000 +scimark-sor 50000 +scimark-sparse 15e4 +series 10000 +spectral-norm 3000 +roulette From 73139f88ca1ac3865b766f6f92d07ecd71210dd0 Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Wed, 19 Oct 2016 21:04:50 +0100 Subject: [PATCH 60/68] Disable some tests under 5.2 compatibility --- test/lib/contents.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/lib/contents.lua b/test/lib/contents.lua index 0328c98917..a1d8b9b982 100644 --- a/test/lib/contents.lua +++ b/test/lib/contents.lua @@ -54,7 +54,7 @@ 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 +do --- pre-5.2 math +lua<5.2 -compat5.2 assert(math.mod) assert(math.log10) end @@ -68,7 +68,7 @@ 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 +do --- pre-5.2 string +lua<5.2 -compat5.2 assert(string.gfind) end From 14c132e6aef4a13e351adde3b08b64e5063ed04b Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Wed, 19 Oct 2016 21:42:19 +0100 Subject: [PATCH 61/68] Add tests for table indexing (inspired by #221) --- test/lang/index | 1 + test/lang/table.lua | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 test/lang/table.lua diff --git a/test/lang/index b/test/lang/index index df5ed675c5..88e2edfac7 100644 --- a/test/lang/index +++ b/test/lang/index @@ -8,6 +8,7 @@ length.lua modulo.lua concat.lua self.lua +table.lua upvalue coroutine.lua tail_recursion.lua diff --git a/test/lang/table.lua b/test/lang/table.lua new file mode 100644 index 0000000000..3ff38cfe78 --- /dev/null +++ b/test/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 From 63a6f7e28c2c886ab9eebdc3f52d5943b580550d Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Wed, 19 Oct 2016 22:20:25 +0100 Subject: [PATCH 62/68] Add test for BC_KNIL slot revival under LJ_GC64 --- test/trace/gc64_slot_revival.lua | 7 +++++++ test/trace/index | 1 + 2 files changed, 8 insertions(+) create mode 100644 test/trace/gc64_slot_revival.lua diff --git a/test/trace/gc64_slot_revival.lua b/test/trace/gc64_slot_revival.lua new file mode 100644 index 0000000000..a262e2c73f --- /dev/null +++ b/test/trace/gc64_slot_revival.lua @@ -0,0 +1,7 @@ +do --- BC_KNIL + local function f(x, y) end + for i = 1,100 do + f(i, i) + f(nil, nil) + end +end diff --git a/test/trace/index b/test/trace/index index 7299d4f0ee..ea7a22e066 100644 --- a/test/trace/index +++ b/test/trace/index @@ -1,6 +1,7 @@ exit_frame.lua exit_growstack.lua exit_jfuncf.lua +gc64_slot_revival.lua phi snap.lua stitch.lua From 014708bceb70550a3ab8d539cff14d9085ca9cb8 Mon Sep 17 00:00:00 2001 From: Peter Cawley Date: Wed, 19 Oct 2016 22:26:51 +0100 Subject: [PATCH 63/68] Add test for BC_VARG slot revival --- test/trace/gc64_slot_revival.lua | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/trace/gc64_slot_revival.lua b/test/trace/gc64_slot_revival.lua index a262e2c73f..40b9d87180 100644 --- a/test/trace/gc64_slot_revival.lua +++ b/test/trace/gc64_slot_revival.lua @@ -5,3 +5,14 @@ do --- BC_KNIL 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 From 5ccbcfe6837b7691d2b21deb8bfd0392cd87ed23 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Tue, 14 Mar 2017 11:22:26 +0000 Subject: [PATCH 64/68] Make test 366 pass by adding "move:" to expectation I have cherry-picked this change from commit 52015c1f5bc7a9c60f29c2c4109b9be0905eeef3 of @DemiMarie's `fixed-goto` branch published at LuaJIT/LuaJIT-test-cleanup#13. I hope it is right! :-) --- test/lib/contents.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib/contents.lua b/test/lib/contents.lua index a1d8b9b982..422920ce7f 100644 --- a/test/lib/contents.lua +++ b/test/lib/contents.lua @@ -77,7 +77,7 @@ do --- 5.2 string +lua>=5.2 end do --- pre-5.2 table +lua<5.2 - check(table, "concat:foreach:foreachi:getn:insert:maxn:remove:sort", "pack:unpack:setn:new") + check(table, "concat:foreach:foreachi:getn:insert:maxn:move:remove:sort", "pack:unpack:setn:new") end do --- 5.2 table +lua>=5.2 From 065909239bc0646d2a205c0c1c55e1eede28cc48 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Mon, 20 Mar 2017 10:26:30 +0000 Subject: [PATCH 65/68] Remove submodule for testsuite --- .gitmodules | 3 --- submodules/raptorjit-testsuite | 1 - 2 files changed, 4 deletions(-) delete mode 160000 submodules/raptorjit-testsuite diff --git a/.gitmodules b/.gitmodules index dda617edd1..e69de29bb2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "submodules/raptorjit-testsuite"] - path = submodules/raptorjit-testsuite - url = https://github.com/raptorjit/raptorjit-testsuite diff --git a/submodules/raptorjit-testsuite b/submodules/raptorjit-testsuite deleted file mode 160000 index e094845a4e..0000000000 --- a/submodules/raptorjit-testsuite +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e094845a4e662aa65254e3faeef4f8435333f364 From c025664d8c293f81cdb6ad8207c02bf20b28b16c Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Mon, 20 Mar 2017 12:17:56 +0000 Subject: [PATCH 66/68] nix: pin nixpkgs, pin clang 4.0, run test suite --- README.md | 12 +++++++++++- default.nix | 28 ++++++++++++++-------------- pkgs.nix | 1 + raptorjit.nix | 29 +++++++++++++++++++++++++++++ test.nix | 19 +++++++++++++++++++ 5 files changed, 74 insertions(+), 15 deletions(-) create mode 100644 pkgs.nix create mode 100644 raptorjit.nix create mode 100644 test.nix diff --git a/README.md b/README.md index 1c4189b8b9..244264570e 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,10 @@ bootstrapping (see [default.nix](default.nix)). The recommended way to build RaptorJIT is with nix, which provides the dependencies automatically, but you can build manually if you prefer. +Building with nix will be slow the first time due to downloading +toolchains and related dependencies. This is all cached for future +builds. + #### Build with nix Install nix: @@ -84,12 +88,18 @@ Install nix: $ curl https://nixos.org/nix/install | sh ``` -Build in batch-mode (option 1): +Build in batch-mode and run the test suite (option 1a): ```shell $ nix-build # produces result/bin/raptorjit ``` +Build in batch-mode without the test suite (option 1b): + +```shell +$ nix-build -A raptorjit +``` + Build interactively (option 2): ```shell diff --git a/default.nix b/default.nix index ec052bff76..903946ee36 100644 --- a/default.nix +++ b/default.nix @@ -7,24 +7,24 @@ # # See README.md for usage instructions. -{ pkgs ? (import {}) # Use default nix distro (for now...) +args @ { + pkgs ? (import ./pkgs.nix) {} , source ? ./. , version ? "dev" }: -with pkgs; -with clangStdenv; # Clang instead of GCC +let + callPackage = (pkgs.lib.callPackageWith { inherit pkgs; inherit source; inherit version; }); + raptorjit = (callPackage ./raptorjit.nix {}); + test = name: args: (callPackage ./test.nix { inherit raptorjit; inherit name; inherit args; }); +in -mkDerivation rec { - name = "raptorjit-${version}"; - inherit version; - src = lib.cleanSource source; - buildInputs = [ luajit ]; # LuaJIT to bootstrap DynASM - installPhase = '' - mkdir -p $out/bin - cp src/luajit $out/bin/raptorjit - ''; - - enableParallelBuilding = true; # Do 'make -j' +# Build RaptorJIT and run mulitple test suites. +{ + raptorjit = raptorjit; + test-O3 = test "O3" "-O3"; + test-O2 = test "O2" "-O2"; + test-O1 = test "O1" "-O1"; + test-nojit = test "nojit" "-joff"; } diff --git a/pkgs.nix b/pkgs.nix new file mode 100644 index 0000000000..a48840921d --- /dev/null +++ b/pkgs.nix @@ -0,0 +1 @@ +import (fetchTarball https://github.com/NixOS/nixpkgs-channels/archive/6a0155d2b7cb10aef1c63b654a2b172d78fd89b4.tar.gz) diff --git a/raptorjit.nix b/raptorjit.nix new file mode 100644 index 0000000000..c516e94c67 --- /dev/null +++ b/raptorjit.nix @@ -0,0 +1,29 @@ +# default.nix - define the build environment for RaptorJIT +# +# This file can be used by 'nix-build' or 'nix-shell' to create a +# pristine build environment with precisely the expected software in +# $PATH. This makes it possible to build raptorjit in the same way on +# any machine. +# +# See README.md for usage instructions. + +{ pkgs ? (import ./pkgs.nix) {} +, source ? ./. +, version ? "dev" }: + +with pkgs; +with llvmPackages_4.stdenv; # Use clang 4.0 + +mkDerivation rec { + name = "raptorjit-${version}"; + inherit version; + src = source; + buildInputs = [ luajit ]; # LuaJIT to bootstrap DynASM + installPhase = '' + mkdir -p $out/bin + cp src/luajit $out/bin/raptorjit + ''; + + enableParallelBuilding = true; # Do 'make -j' +} + diff --git a/test.nix b/test.nix new file mode 100644 index 0000000000..bf4338827c --- /dev/null +++ b/test.nix @@ -0,0 +1,19 @@ +{ pkgs, raptorjit, source, name, args }: + +pkgs.stdenv.mkDerivation { + name = "test-${name}"; + src = source; + buildInputs = [ raptorjit ]; + phases = "unpackPhase buildPhase"; + buildPhase = '' + mkdir $out + cd testsuite/test + echo "Running testsuite with ${args} and output to $out/log.txt" + raptorjit ${args} test.lua 2>&1 > $out/log.txt + result=$? + echo -n "*** TEST RESULTS (${args}): " + tail -1 $out/log.txt + exit $result + ''; +} + From 82487c76b39253057e1867a7530603686d2020fd Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Mon, 20 Mar 2017 12:21:37 +0000 Subject: [PATCH 67/68] Travis-CI: Update now that nix runs the test suite --- .travis.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index c3475c4200..aae0fa0642 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,9 @@ language: nix sudo: false env: - - jit=-O3 - - jit=-O2 - - jit=-O1 - - jit=-joff + - test=test-O3 + - test=test-O2 + - test=test-O1 + - test=test-nojit script: - - nix-build - - result/bin/raptorjit -e 'for i = 1, 1000 do end' - - git submodule init submodules/raptorjit-testsuite - - (cd submodules/raptorjit-testsuite/test; ../../../result/bin/raptorjit $jit test.lua +slow) + - nix-build -A $test From 398bd28467f54b521742291206abf1d254bdc429 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Mon, 20 Mar 2017 14:08:50 +0000 Subject: [PATCH 68/68] Cleaned up nix expressions --- default.nix | 8 +++----- raptorjit.nix | 13 ++----------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/default.nix b/default.nix index 903946ee36..552fa8751d 100644 --- a/default.nix +++ b/default.nix @@ -7,11 +7,9 @@ # # See README.md for usage instructions. -args @ { - pkgs ? (import ./pkgs.nix) {} -, source ? ./. -, version ? "dev" -}: +{ pkgs ? (import ./pkgs.nix) {} +, source ? pkgs.lib.cleanSource ./. +, version ? "dev" }: let callPackage = (pkgs.lib.callPackageWith { inherit pkgs; inherit source; inherit version; }); diff --git a/raptorjit.nix b/raptorjit.nix index c516e94c67..152a62e089 100644 --- a/raptorjit.nix +++ b/raptorjit.nix @@ -1,15 +1,6 @@ -# default.nix - define the build environment for RaptorJIT -# -# This file can be used by 'nix-build' or 'nix-shell' to create a -# pristine build environment with precisely the expected software in -# $PATH. This makes it possible to build raptorjit in the same way on -# any machine. -# -# See README.md for usage instructions. +# raptorjit.nix - compile RaptorJIT with reference toolchain -{ pkgs ? (import ./pkgs.nix) {} -, source ? ./. -, version ? "dev" }: +{ pkgs, source, version }: with pkgs; with llvmPackages_4.stdenv; # Use clang 4.0