1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
*My [interpreter][abc-interpreter] for the pure, functional language [Clean][]
allows interpretation in both C and WebAssembly. The Clean compiler is written
in Clean, with a C backend. In my [Clean Sandbox][], I compile the C backend
with [Emscripten][] to [WebAssembly][], and interpret the Clean frontend in the
WebAssembly interpreter. Combined with a simple `make`-like tool and an editor,
this allows you to compile and run Clean code in the browser.*
[[toc]]
# Introduction
Browsers can run programs in only few languages; mainly JavaScript. But
JavaScript is a high-level scripting language that makes it hard to optimize
performance. [WebAssembly][] operates on a lower level than JavaScript, is more
complicated to write code in, but is a relatively easy compilation target for
common imperative languages like C. This means that C applications and
libraries can be ported to the browser relatively easily.
However, WebAssembly lacks some features that make it a difficult compilation
target for functional programming languages (in particular, non-local control
flow and tail calls). Some of these omissions are being implemented as post-MVP
features, but until then we need a workaround.
Back in 2019 I implemented such a workaround for the pure, functional
programming language [Clean][] (a close cousin of Haskell). The Clean compiler
compiles to the intermediate language ABC, which is designed for an abstract
imperative machine for graph rewriting. This ABC code is then converted to
actual machine code. My solution, published in IFL'2019,[^ifl-2019] involves an
interpreter for this intermediate ABC language. The interpreter logic is
written in a DSL which targets both C and WebAssembly, so that you can run it
both natively and in the browser.
Initially, we used this system in the [iTasks][] framework for workflow
management web applications. There, it allows you to send arbitrary Clean
values (including thunks) to the browser for evaluation there. This has two
benefits: (1) reducing server load by evaluating more on the client; (2) the
ability to write custom frontend components in Clean, which allows you to make
use of the same utility functions, the benefits of strong typing, etc.
However, the ABC interpreter is more widely applicable than the iTasks system.
To demonstrate this, I set out to run the Clean compiler itself in the browser.
You can see the result in the [Clean Sandbox][].
# High-level overview
In the end, the architecture turned out to be relatively simple. I needed the
following components:
- A file system to keep the files (taken from the Emscripten library).
- A simple `make`-like tool that checks which files have been modified and
calls the compiler for those files only.
- The compiler frontend (written in Clean), running in the ABC interpreter.
- The compiler backend (written in C), compiled with Emscripten to
WebAssembly.
- A linker for the generated ABC files (written in C, compiled to WebAssembly).
- The ABC interpreter to run the resulting 'executable'.
- A nice editor to let the user modify his Clean code. I use something based on
the [Monaco Editor][], but will not discuss it here as I want to focus on the
build pipeline.
Apart from the `make`-like tool, all these components were already available, I
only had to connect them together.
*Continue to read about the [implementation details][pipeline].*
[^ifl-2019]:
Camil Staps, John van Groningen and Rinus Plasmeijer, 2019.
[Lazy Interworking of Compiled and Interpreted Code for Sandboxing and Distributed Systems](https://camilstaps.nl/assets/pdf/ifl2019.pdf),
in Jurriën Stutterheim and Wei Ngan Chin (eds.),
*Implementation and Application of Functional Languages (IFL '19), September 25–27, 2019, Singapore, Singapore*.
doi: [10.1145/3412932.3412941](https://doi.org/10.1145/3412932.3412941)
[abc-interpreter]: https://gitlab.com/clean-and-itasks/abc-interpreter/
[Clean]: http://clean.cs.ru.nl/
[Clean Sandbox]: https://camilstaps.gitlab.io/clean-sandbox/
[Emscripten]: https://emscripten.org/
[iTasks]: https://gitlab.com/clean-and-itasks/itasks-sdk/
[Monaco Editor]: https://microsoft.github.io/monaco-editor/
[WebAssembly]: https://webassembly.org/
[introduction]: 2021-06-23-compiling-clean-in-the-browser-with-webassembly-part-1-introduction.html
[pipeline]: 2021-06-23-compiling-clean-in-the-browser-with-webassembly-part-2-the-pipeline.html
[integration]: 2021-06-23-compiling-clean-in-the-browser-with-webassembly-part-3-putting-it-all-together.html
|