# Differential-test manifest. Tab-separated: <status>\t<case>\t<description>
# status = pass  -> lua2wasm MUST match reference Lua 5.5
# status = xfail -> captured bug; lua2wasm currently does NOT match. When it
#                   starts matching, the harness fails (XPASS) -> promote to pass.
#
# Regression anchors (currently correct) -----------------------------------
pass	ok_arith	int/float arithmetic, bitwise, wraparound
pass	ok_strings	string lib: case, sub, rep, format, match, gsub-fn
pass	ok_tables	table lib + pairs/sort iteration
pass	ok_closures	closures, varargs, multi-return, pcall
# Fixed: float formatter (formatFloat round-trip + cFormatG) ----------------
pass	float_tostring_exp	exponent-form float no longer gets a spurious ".0"
pass	float_neg_zero	negative zero keeps its sign
pass	format_g_smallexp	%g switches to exponent form below 1e-4
pass	float_precision	floats print enough digits to round-trip
# Fixed: pattern-engine empty matches (short-circuit guard + e!=lastmatch) ---
pass	gsub_empty_pat	gsub with "" pattern no longer traps
pass	gsub_empty_match	empty-match " *" no longer doubles separators
pass	match_empty_pat	match/find with "" pattern no longer traps
# Fixed: stdlib gaps (concat range, hex floats, next nil) -------------------
pass	table_concat_range	table.concat honors i/j range args
pass	tonumber_hex_float	tonumber parses hex floats
pass	next_empty	next({}) returns nil
# Fixed: math fidelity (log2/log10 special-case, 1^inf guard) ---------------
pass	math_log_base	math.log base 2/10 uses log2/log10
pass	pow_one_inf	1^inf is 1.0
# Fixed: misc (paren adjust-to-one, %q newline) -----------------------------
pass	paren_truncation	(f()) is adjusted to a single value
pass	format_q_newline	%q emits backslash + real newline
# Fixed: int //0 and %0 raise a catchable error (were nil payloads) ---------
# (semantic check only — exact error wording is not asserted, by design)
pass	div_zero_int	int // 0 raises a catchable string error
pass	mod_zero_int	int % 0 raises a catchable string error
pass	arith_err_msg	arithmetic on a non-number raises a catchable string error
# Fixed: spec-corner batch (found by the corner-case sweep) -----------------
pass	for_int_overflow	numeric for terminates on integer overflow (was infinite loop)
pass	format_d_noninteger	%d on a non-integer raises a catchable error (was silent 0)
pass	format_q_literals	%q emits type-preserving literals for number/bool/nil
# Corner-case regression anchors (broad spec coverage) ----------------------
pass	corners_numbers	int/float type, key normalization, mixed compare, tointeger
pass	corners_strings	compare/length with NUL, sub/rep/byte, format combos, tonumber
pass	corners_patterns	classes, frontier, sets, captures, backrefs, gsub fn/table
pass	corners_tables	insert/remove/move/sort/pack/unpack/ipairs
pass	corners_metatables	index/newindex/eq/lt/le/len/concat/call/tostring/arith
pass	corners_lang	select, multi-assign, and/or/not, goto, break, repeat, pcall/xpcall
# Fixed: `global` is a contextual keyword, usable as an ordinary name --------
pass	global_as_name	`global = 5`, `global.x`, `t.global` accepted (not forced into a decl)
# Fixed: error(nil)/error() yields the string "<no error object>" (Lua 5.5) --
pass	error_no_object	nil error object becomes "<no error object>" at pcall/xpcall boundary
# Fixed: indexing a non-table raises an "index" error, not a "call" error ----
pass	index_nonindexable	index of nil/number is a catchable error mentioning "index"
# Fixed: method calls in tail position are proper tail calls (constant stack) -
pass	method_tail_call	`return self:m(...)` is TCO'd like `return f(...)`
# Fixed: table.concat rejects non-string/number elements (was silently coerced)
pass	concat_invalid_value	concat of a boolean/table element is a catchable error
# Fixed: multiple-assignment eval order (LHS before stores; right-to-left) -----
pass	multi_assign_order	t[i] captures old i; repeated target keeps leftmost value
# Fixed: for-loop control var is fresh per iteration (closures capture distinct)
pass	loop_var_capture	closures over a for-loop variable see per-iteration values
# Fixed: numeric-for is float when init or step is float (limit type irrelevant)
pass	for_num_float_type	`for i=1,3,1.0` makes i a float from the first iteration
# Fixed: utf8.codes iterator — out-of-range pos -> nil (was a trap), strict errors
pass	utf8_codes_iter	codes iterator stops on out-of-range pos; invalid seq is catchable
# Fixed: gmatch empty matches suppressed when end == previous end (e~=lastmatch)
pass	gmatch_empty	gmatch no longer doubles/ trails spurious empty matches
# Fixed: tostring of table/function uses "type: 0xADDR" (was bare "table")
pass	tostring_addr	tostring shape/stability/distinctness for tables and functions
# Fixed: getmetatable(string) returns the shared string metatable (was nil)
pass	getmetatable_string	strings expose {__index = string} via getmetatable
# Fixed: setmetatable type-checks args (was an illegal-cast trap on non-tables)
pass	setmetatable_typecheck	setmetatable on a non-table is a catchable error
# Fixed: tonumber validates base in [2,36] (out-of-range was silently nil)
pass	tonumber_base_range	tonumber with an out-of-range base is a catchable error
# Fixed: utf8.offset returns (start,end) + bounds/continuation errors (Lua 5.5)
pass	utf8_offset	utf8.offset two-value return; out-of-bounds/continuation are errors
# Fixed: utf8.len/utf8.codepoint validate positions (out-of-range was clamped)
pass	utf8_len_codepoint_bounds	len/codepoint raise "out of bounds" instead of clamping
# Fixed: utf8.char accepts 0..0x7FFFFFFF with extended 4-6 byte encoding
pass	utf8_char_range	utf8.char range/byte-counts incl. >U+10FFFF (was capped at 0x10FFFF)
# Fixed: string.format %p ("0x<addr>" for ref types, "(null)" otherwise)
pass	format_p	%p formats address-bearing values vs (null), was echoed literally
# Fixed: os.date strftime specifiers %a/%A/%b/%B/%I/%c/%x (C-locale names)
pass	os_date_strftime	os.date supports name/12-hour/%c/%x specifiers (UTC, deterministic)
# Fixed: os.time(table) builds a timestamp from a date table (was ignored)
pass	os_time_table	os.time(table) round-trips via os.date; required-field/type errors
# Fixed: tostring(float) default is %.15g (Lua 5.5), not %.14g
pass	float_tostring_15g	float tostring widened to %.15g; %.17g fallback when needed
# Fixed: table.insert/remove validate position bounds and arity (was silent/trap)
pass	table_insert_remove_bounds	insert/remove raise on out-of-range pos / wrong arity
#
# Captured bugs (xfail) ----------------------------------------------------
# Found by the 2026-05-21 sweep over README "incomplete/partial features" and
# "runtime sharp edges". Note: error-message *wording* and chunk-name
# formatting are intentionally not tracked; only semantic behavior.
#
# -- fixed in this sweep (now regression anchors) --
pass	math_arg_coerce	math.* coerce numeric strings; non-number raises catchable "number expected"
pass	obj_addr_distinct	function tostring/%p carries a stable, distinct per-object address
pass	compare_type_msg	order-compare error names operand types (two table values / table with number)
pass	mt_name	__name renames an object in tostring and type-aware compare errors
pass	deep_recursion	deep non-tail recursion raises a catchable "stack overflow"
pass	os_difftime	os.difftime(t2,t1) returns the second difference as a float
pass	os_setlocale	os.setlocale query/"C" returns "C"
pass	io_default_files	io.input()/io.output() return default handles; io.write routes through them
pass	math_minmax_ult	min/max use the full < operator; ult coerces int strings, rejects non-integers
#
# -- deferred: large milestone (open a discussion before tackling) --
# Full <close> on early exits needs close calls injected before every
# return/break/goto crossing a close scope PLUS try_table error-path unwinding
# — invasive changes to control-flow and exception lowering. Niche feature;
# natural-block-exit close already works. Kept captured.
pass	close_early_exit	<close> runs __close on return/break/goto/error exits, reverse order
#
# -- blocked by hard constraints / missing metadata (kept captured) --
xfail	nan_sign	tostring(0/0) sign is platform-dependent (WASM canonicalises NaN positive)
xfail	mt_gc	__gc finalizers impossible: no bundled GC, no WasmGC finalization hook
xfail	mt_mode	__mode weak tables impossible: WasmGC has no weak references
xfail	collectgarbage_count	no managed GC to report live memory for "count"
xfail	debug_getinfo	nparams/nups/isvararg/linedefined need codegen debug metadata we don't retain
xfail	strict_global	Lua 5.5 strict-global rejection is compile-time (harness sees <compile-fail>)
xfail	goto_into_scope	reject goto into a local's scope — compile-time parity (needs parser machinery)
pass	math_fmod	fuzzer-found: float fmod precision for large magnitudes
pass	float_mod_sign	fuzzer-found: float % zero-sign follows dividend, not always +0
pass	format_str_coerce	fuzzer-found: string.format coerces numeric-string args, errors otherwise
pass	math_tointeger_coerce	fuzzer-found: math.tointeger coerces numeric strings
pass	format_int_range	fuzzer-found: %d on out-of-i64-range float raises (was a giant int)
pass	format_hash_dot	fuzzer-found (review #11): %#.0f/%#.0e force a decimal point
pass	nil_nan_key	fuzzer-found (review #8): nil/NaN table key raises on t[k]=v and {[k]=v}
pass	builtin_arity	audit-found: builtins requiring an arg raise on zero args (luaL_checkany)
pass	find_coerce	code-review #7: string.find coerces numeric subject/pattern args
pass	format_flag_validity	code-review #12: string.format rejects invalid flag/conversion combos
pass	format_s_zeros	fuzzer-found: %s with a modifier rejects an embedded NUL (string contains zeros)
pass	format_validation_extra	code-review #12: string.format rejects %q-modifier/%c-precision/%%-modifier/%F/length-mod/oversized width
pass	format_c_mask	fuzzer-found: %c outputs the 64-bit low byte (n & 0xff), not Number(iv)&0xff
pass	sort_badcmp_detect	code-review #9: table.sort detects an inconsistent comparator (faithful auxsort port, size-exact vs lua5.5)
