The age of AI makes this possible: Because the Dart VM blocks the UI thread on macOS, I figured I could ask GPT to write me a new VM - of course using Rust, because that's the goto language for rewrites – that would allow me to run small Dart programs.
And it worked.
I spent years studying compiler construction and VMs, working in that field for a couple of years, and while I would probably be able to do this on my own, that would take days if not weeks and hence, I wouldn't consider doing it just for fun.
Now, I got a working PoC in less than two hours.
Here's my prompt, in case you want to create your own personal VM, too.
[after explaining the problem and the wish to write 1980s games]
So, why not create a new VM using Rust that runs on the UI thread and provides a special library (i.e. based on minifb) that can be used to do display simple retro pixel graphics.
For a PoC, only a subset of Dart needs to be supported. The VM must support hot reload, though. I can use the usual Dart IDE tooling to write the program, but run the code with a new VM. That VM can assume that all code is valid. Also, execution speed isn't an issue.
Start by inventing a simple API to create a window, access its pixmap, set or get ARGB pixels, update the window's content, receive mouse and key events and a close event. Create a typical game framework based on that, e.g. a loop to update the game, paint everything, flip the buffers. To omit async operations, we can query for events in a loop.
After we agreed upon this, design the subset of Dart required. Then design the VM instructions needed to implement that. We could either use a Dart program that uses the analyzer package to parse source code and resolve types to generate a bytecode. Or do this in Rust because it is easier/faster. The latter is the final goal, but for a PoC the former might quicker to implement. Present the result for review, then implement everything.
Runtime errors must contain the original line number. The format must be compatible to Dart's way so that the IDE doesn't notice that it doesn't run the original Dart VM.
Also come up with a dozen or so examples. One might be a snake game controlled by the arrow keys. While the game is running, it must be possible to for example modify the color of the snake and the VM shall automatically hot-reload the changed source code, re-compile it and replace the old methods with the new ones, and the color will change with the next screen update, keeping the state of the game.
GPT Sol medium needed 15min to come up with a first version that demo'd hot reloading to change a color. It then took 30min to implement most of Dart, extending the initial minimal compiler. It chose to write the compiler in Dart, emitting byte code in an unoptimized mnemonic format which is then re-loaded by the Rust VM. It made a simple error not correctly wiring up key events, but after me complaining about it, it continued to implement more advanced features, writing more demos (like pong or life) in another 46min. And frankly, I was surprised that its design was quite good (by the book, one could say) and quite practical.
Using Dart to compile the Dart source unfortunately imposes a 5s startup tax, but once the Dart compiler and its analyzer package have been loaded, reloading my examples happens nearly instantly.
While I'm writing these lines, GPT is adding tests, searching for (and finding) edge cases and it is quite spooky to watch it to remote control Visual Studio Code to change source code while watching the also remote controlled example app.