Did you consider other systems languages (such as Zig, etc) before settling on Rust? As Iām at a calligraphy symposium I will check back on this, however laggardly.
Not really, no. The main reason is that the origins of the Nova JavaScript engine as a project (without the ECS / data-oriented design focus, that came later) are in the Deno runtime's Discord where a friend joked "so when are we starting our own JS engine?" in response to someone jokingly complaining about Deno using V8 which is of course written in C++.
So the project started as a "let's write a better JS engine than V8 in Rust!" kind of joke. Beyond that, I personally wanted to write in Rust, and it turns out that with sufficient abuse[1], the Rust borrow checker can be used to perform GC safety checks at compile time. This means that Nova can avoid rooting a lot of values during runtime because at compile time the borrow checker has already ensured that those values will never be used after a GC safepoint.
This is something that would not be feasible in other languages without significant custom checking infrastructure. As an example, Firefox / SpiderMonkey has a custom linter that checks that "no-GC" functions cannot accidentally call back into "GC" functions, but it is roughly a full-program analysis task and the checker is hand-written, custom code that sometimes lacks special cases for this function or that. In Nova, a "GC" function takes a move-only "GcScope" parameter by value (and all GC-able Values observe that value; when the value gets moved to a child call, all those observing Values invalidate; this is that GC safety checking), and "no-GC" functions take a copy "NoGcScope" parameter that can be created from a "GcScope" and that again observes the "GcScope". Through these, the borrow checker becomes the checker for this logic.