HAC running in the browser via GNAT-LLVM (WebAssembly)

I’ve ported HAC ( GitHub - zertovitch/hac: HAC Ada Compiler - a small, quick Ada compiler fully in Ada · GitHub ) (by Gautier de Montmollin) to the web - it runs as WebAssembly, live, here:

Type an Ada (subset) program, and it is compiled and executed on the spot, entirely in your browser. Nothing is sent to or run on the server; the page is just static assets.

Two compilers are involved, so to be clear about which does what:

  • GNAT-LLVM (the GNAT front end on an LLVM back end) is what I used to build HAC itself into WebAssembly - a one-time, offline step.
  • HAC is the compiler you actually use on the page: that wasm build of HAC, running in your browser, compiles the Ada you type to its p-code and runs it on its VM.

A couple of points likely of interest here:

  • HAC is used unmodified. The wasm runtime now supports real Ada exception propagation (implemented with native WebAssembly exception handling), so HAC builds and runs from upstream sources as-is - no wasm-specific workarounds.
  • It is exercised seriously. HAC’s own regression suite - 133 tests, including the Advent of Code sets for 2020-2025 - passes in full (133/133) running through the wasm build.

Sources, for anyone who wants to look or build it:

Feedback welcome.

21 Likes

Wow!
I have a noob question regarding WebAssembly: how is the text in the editor widget passed to HAC?
Is there a local file system?

First the javascript side passes the file as a string + the filename

Then wasm (Ada) side creates a string stream and passes it to Build_Main:

But to answer your filesystem question, it could, emcc supports it, and perhaps it is next step, that would enable having multiple source files

1 Like

Just to clarify, hac on wasm emcc supports already loading from filesystem, just the hac_web example doesn’t at the moment because it is on the browser. But hac_cli.js (included in the hac_web example) does.

Example:

mypack.ads

package Mypack is
   function Double (X : Integer) return Integer;
end Mypack;

mypack.adb

package body Mypack is
   function Double (X : Integer) return Integer is
   begin
      return X * 2;
   end Double;
end Mypack;

main.adb

with HAT; use HAT;
with Mypack;
procedure Main is
begin
   Put_Line ("Using a separate package Mypack:");
   Put_Line ("Double (21) =" & Integer'Image (Mypack.Double (21)));
end Main;
Run and output:
$ node hac_cli.js main.adb
Using a separate package Mypack:
Double (21) = 42
3 Likes