Personally, I'm using Haxe with its Lua backend. While wrapping Lua APIs is a pain, and some dynamic patterns are hard to represent directly, Haxe provides a lot of the things that Lua lacks: a gradual static type system, more familiar JS-based syntax, syntactic sugar for lambdas, sane handling of `this` in methods, control over inlining, immutable variables, generics, null safety, powerful hygienic macros, somewhat usable standard library, extension functions (Kotlin/Scala3 like), partial function application, hash and array comprehensions, functional operators on collections, limited operator overloading via abstracts, built-in LSP server, and a lot more.
I do this in the context of scripting my window manager, and plan to try this with Nginx/OpenRESTY. I feel like pairing LuaJIT runtime with Haxe compilation creates incredibly powerful combination. Lua provides coroutines, tail call elimination including corecursive functions, lightweight and fast JITed VM, a package manager (luarocks), bindings to important C libraries, FFI, reflection (everything is a table anyway), and more. The integration between Haxe and Lua is not yet seamless, and Lua compiler backend is one of the least developed, but even in this state I'm very happy with the combination of compile-time and run-time features I get.
Ha interesting, I didn't really expect a serious answer but very cool. I looked into haxe a while back when I was gearing up for a significantly complex project targeting lua 5.1.
I ended not using it mostly because of unfamiliarity and it felt like it would add a fair bit of complexity. Didn't want to pick up a whole new ecosystem for that project.
I ended up using fennel, which solves most of my practical problems with lua without really making anything harder. Doesn't help with the package ecosystem or build process but I ended up just taking that compromise.
Don't regret it, still use fennel anywhere I'm forced to use lua, including hammerspoon and mud client scripting. I think if I was going to work heavily in lua long-term I'd go back and invest in haxe for it.
Personally, I'm using Haxe with its Lua backend. While wrapping Lua APIs is a pain, and some dynamic patterns are hard to represent directly, Haxe provides a lot of the things that Lua lacks: a gradual static type system, more familiar JS-based syntax, syntactic sugar for lambdas, sane handling of `this` in methods, control over inlining, immutable variables, generics, null safety, powerful hygienic macros, somewhat usable standard library, extension functions (Kotlin/Scala3 like), partial function application, hash and array comprehensions, functional operators on collections, limited operator overloading via abstracts, built-in LSP server, and a lot more.
I do this in the context of scripting my window manager, and plan to try this with Nginx/OpenRESTY. I feel like pairing LuaJIT runtime with Haxe compilation creates incredibly powerful combination. Lua provides coroutines, tail call elimination including corecursive functions, lightweight and fast JITed VM, a package manager (luarocks), bindings to important C libraries, FFI, reflection (everything is a table anyway), and more. The integration between Haxe and Lua is not yet seamless, and Lua compiler backend is one of the least developed, but even in this state I'm very happy with the combination of compile-time and run-time features I get.