JS Compatibility Gaps
Gaps between JavaScript and Tish that may require workarounds.
This page documents gaps discovered when porting JavaScript patterns to Tish. Resolved gaps are listed for reference.
Test backends / deployment target matrix (2025-03 audit)
Integration tests run per target. Results as of audit:
Cranelift/WASI curated list (17 files): fn_any, strict_equality, switch, do_while, typeof, try_catch, json, math, builtins, uri, inc_dec, exponentiation, void, rest_params, arrow_functions, array_methods, types.
Excluded from Cranelift/WASI (stack-underflow/scope bugs): nested_loops, objects, optional_chaining, spread, template_literals, higher_order_methods, the destructuring.tish integration file (and other full-language tests), and others.
The bytecode VM (used by tish run --backend vm, Cranelift, and WASI) has known gaps. For example, optional_chaining.tish runs correctly with the interpreter (--backend interp) and Node, but with the VM it may error. Destructuring in function parameters is implemented for the interpreter, Rust codegen, and JS target, but not for the VM (use fn f(props) { let { a } = props; ... } on VM-only paths). Use the repo script ./scripts/run_parity_compare.sh (or just parity) in the tish repo to compare outputs across runtimes (interp, vm, rust, cranelift, wasi, node).
Resolved (as of 2025-03)
Number.prototype.toFixed(digits?) ✓
Tish now supports n.toFixed(digits) for formatting numbers with fixed decimal places (0–20). Returns a string.
console.log((3.14159).toFixed(2)) // "3.14"
console.log("$" + total.toFixed(2)) // currency formattingSee Numbers for details.
indexOf(search, fromIndex?) ✓
Tish now supports the optional fromIndex parameter: s.indexOf("x", 5).
String index semantics ✓
All string methods now use character (Unicode scalar) indices consistently: indexOf, slice, substring, charAt, length. No more byte-offset confusion with multi-byte UTF-8.
RegExp exec() result index property ✓
exec() returns an array-like object with [0], [1], ... and "index" (match start as character offset). Access via m["index"].
let m = RegExp("(\\d+)").exec("abc123")
console.log(m[0]) // "123"
console.log(m["index"]) // 3String.prototype.replace with function replacer ✓
When the search value is a RegExp and the replacement is a function, the function is invoked for each match. Callback receives (match, g1, g2, ..., index, fullString).
let result = "hello 123 world 456".replace(RegExp("(\\d+)", "g"), (match, g1) => "[" + g1 + "]")
// result: "hello [123] world [456]"Supported in both interpreter and compiled modes.
See also
- Tish vs JavaScript — High-level differences
- Strings — String builtin reference
- ECMA Alignment — Plan alignment