Yeah, I think this would be really useful! When we had the old allocator that suffered from memory fragmentation I was going to add something like this so you could restart from a clean slate but wound up fixing the allocator again. Just recently while testing Lua performance I noticed that its random hash seed has a noticeable impact, so I went ahead and added a playdate.restart() function so that I can do multiple passes of a test with a new seed each time without having to quit and restart the test manually. It works pretty well, only problem I've hit so far is it crashes when you open the menu--must be a global pointer referencing the old lua state that needs to get cleared out. The way I have it working now is you call it with an optional string:
playdate.restart(message)
and then message is available on the next round at playdate.argv[2]. So, for example, your main.lua could just be (totally untested code here
)
playdate.file.run(playdate.argv[2] or "menu")
then menu.lua would have your top-level menu and when you select an item you'd call, say, playdate.restart("level1") to run level1.lua in a freshly-initialized environment. If you need to move any additional state between modules you could use the datastore functions. (There's no hard limit to how big message can be, but I wouldn't push it; if it's too big the strdup() will fail and you'll restart with an empty argv[2].)
Keep an eye out for this in 1.14!