A playground for Hare

I built a thing:

Hare Playground

And this is what it looks like:1

Screenshot of the Hare Playground, the default code example on the left, the out to the right

It's an online playground for the Hare programming language. Code is sent to the server for compilation and execution. It responds with the standard and error output serialized into JSON, which gets rendered in the output box in the frontend. This works just the same as other playgrounds.

It's a bit slow and might crash on you, but it works (if it doesn't: reload).

Why?

Because I wanted to do something fun and learn Hare. Hare is a rather new systems programming language (started in 2020) that's inspired by C, but promises to do few things better. The original blog post Hare's advances compared to C has a good overview on that.

This project gave me the opportunity to explore a couple of areas in Hare, read through the documentation and the Hare codebase and even fix a few bugs in existing code.

I might write another more detailed blog post on my impressions. For now I can say that it was a few fun nights learning and exploring a new language.

How?

The whole codebase is in the hare-playground repository. In about 500 lines of my own code plus 3 external libraries I implemented the webserver part, including routing and static file serving. I bet it has memory leaks.

fn route_request(buf: *io::stream, serv_req: *http::server_request) (void | http_err) = {
	let request = &serv_req.request;
	switch (request.method) {
	case "GET" =>
		switch (request.target.path) {
		case "/" => handle_index(buf, serv_req);
		case =>
			handle_file(buf, serv_req)?;
			return;
		};
	case "POST" =>
		switch (request.target.path) {
		case "/v1/exec" => handle_exec(buf, serv_req)?;
		case => return notfound;
		};
	case "OPTIONS" =>
		handle_cors(serv_req);
		return;
	case => return notfound;
	};
};

The "router" part of the webserver2

The external libraries I pulled in are:

  1. hare-logfmt for formatted logging messages (though I only log the minimum).
  2. hare-json for parsing from and serializing to JSON (unmodified from upstream).
  3. hare-http for the webserver parts: listening on a socket, parsing HTTP, creating the request and response objects. I added a couple of commits to fix some issues (available in my fork, I'll upstream them).

I also wrote a small wrapper around pthread, just so my server can handle more than one request at a time.

To run the user-submitted Hare code the server launches hare in a bubblewrap sandbox. This should make it somewhat safe to deal with arbitrary input. The whole thing runs in a VM on fly.io, so even if a sandbox escape is possible the worst an attacker can do is break the VM and ruin the playground for others.

The whole backend even works on macOS (without the sandbox, do not run in production!), thanks to the Darwin port of Hare (and some of my own fixes on top). I wrapped that in a Nix flake for easy installation. nix develop is all you need in the playground repository.

The frontend is some basic HTML3, a couple of lines of JavaScript and htmx. The code editor is Codejar, a small one-file editor implementation. Code highlighting is handled by highlight.js No JavaScript transpiler or bundler needed. And yes, I use htmx, but still return JSON from the server and add it to the DOM using JavaScript in the right places. I'd rather not do the whole HTML escape in Hare right now server-side. Initially I built this using the JavaScript parts of codapi, but I ended up rolling it myself using htmx, as that gives me more freedom placing & styling the button elements and controlling the output.

Production when?

I will keep the playground running on Fly (for now). I do not plan to work on it much further. This is after all a playground for me to learn the language a bit and not a more serious long-term project. The code is open-source (MPL licensed).


Footnotes:

1

Sorry, no dark mode yet.
2: The syntax highlighter on this site doesn't know about hare, so this code is tagged as C.
3: Thanks to Dennis for showing me how simple Flexbox is to use.