Webby Lua

Lua is fun. And while I like that it's not part of very complicated web browser tech or something, being able to run it in the browser can be kind of nice. I like using it for example code in posts. And I like having examples that can be run and maybe modified on the page:

local vowels = "aeiou"
for i = 1, 15 do
  local j = (i - 1) % #vowels + 1
  print(vowels:sub(j, j):rep(i) .. "h")
end

I've done some cleaning up of the code I use for this and put it in a repo. It's set up so that it deploys a couple of examples to GitHub pages.

The Lua implementation is C code that compiles pretty easily and you can Emscipten-compile it to wasm. I don't really know my way around that kind of stuff, but I found a wasm_lua repo on GitHub, and that had dealt with the stuff I didn't know how to do. I've made some small changes to the main.c file and made different example pages, but my repo is mostly just that repo.

How does?

There's a C program that consist of Lua and a main.c with:

Crun_lua(sourcecode)JSLualua_web_send(code, payload))

The idea is that the JS side is the most infrastructury side:

The Lua code is usually more "core domain" code. The code that is written in a REPL or used as example code in a post. The lua_web_send C function is available in Lua as the webSend Lua function. In the initialization code I typically replace it with a web table that I do some metatable stuff to so I can e.g. do web.html("<p>hello</p>") in order code "web" and payload "<p>hello</p>" to the JS side.

If something is more complicated than just sending a message to the JS side, I can add functions to web manually. I have a web.require that does some coroutine stuff so that it can send the code "require" along with a URL to the JS side and then suspend the coroutine before the C function returns control to the JS side. The JS can then make the HTTP request to get the source code for the required library and send it to the Lua side in a way that resumes the suspended coroutine and loads the library. There's a bit of juggling but like it's fun.

Blep.

One more string of Lua code

Changed it a little:

Crun_lua(runner, script)JSLualua_web_send(code, payload))

Two arguments are sent in the JS to C/Lua direction as well now. Kind of similar to the code/payload thing, but runner and script are both strings with Lua code. The runner should be a piece of Lua code that returns a function that will be used to run the script.

I typically ended up wrapping the Lua code in some piece of "runner code" before sending it to the C/Lua side. Probably because I needed things to run in coroutines in order to get some kind of input (like from downloading a file or from an input field on the page) without blocking. So instead of sending <code> I'd send helperfunction(function() <code> end) or something. And then do something else for resuming the coroutine later.

It wasn't much of a problem doing that by concatenating strings on the JS side, but by sending two strings I can compile the code that is e.g. written by the user as is, without having it wrapped in additional stuff. If there's a compilation error, I guess it's nice that the error reporting reports on the code the user sees on the page instead of on something more altered...