This is a fork of the Gleam language compiler.
This compiler can be used to translate Gleam programs into WebAssembly binaries.
An example application showcasing the performance improvement gained by compiling Gleam to WebAssembly instead of JavaScript is available here (source).
A list containing all implemented features of the Gleam language is included below.
Key features are:
- a time and space efficient implementation of generics and custom types (based on work by Lutze, Schuster, Brachthäuser)
- tail recursion
- imports of JavaScript and WebAssembly functions using the
@externalattribute - exporting of functions using the new
@wasm_exportattribute
The Gleam version is 1.9.1.
Most of the code is in the compiler-core/src/wasm.rs file and the compiler-core/src/webassembly module
In addition to the incomplete features below, future work should focus on restructuring the translation process. While the current version is working, it could probably be improved by adding more intermediary steps to perform transformations on the AST before translating it to wasm.
You may also be interested in previous work:
Changes are made primarily at the backend. The generated AST first undergoes monomorphization, so generic types can be mostly ignored in the next steps.
After some extra work to gather information on Tuples, Custom Types and anonymous functions, the AST is translated to WebAssembly. Most of this preparation should probably be refactored so that is creates additional, intermediary ASTs because the current approach (AST + additional infos in other data structures) is hard to extend and maintain.
The implementation allows including .wat files, which may contain handwritten or generated .wasm code from other sources. This is useful to access runtime features or WebAssembly instructions and could be useful to implement a standard library targeting WebAssembly.
The result is a single .wasm file that can be executed by the runtime.
The implementation lacks support for multiple Gleam modules/files. My plan was to support this by translating each module into a separate .wasm module and merge them at the end (like it's done with external .wasm modules). While this should still be possible, it would require some workarrounds because WebAssembly has limited support regarding type exports. Manually copying the types to every module and deduplicating after the merge might work though.
The following aspects of the Gleam language tour are at least partially supported
| Feature | Status | Bemerkung |
|---|---|---|
| Hello World | ✔️ | Only in JS-Engine using console.log with @external, no stlib support |
| Ints | ✅ | |
| Floats | ✅ | |
| Equality | ✔️ | Not for Tuples (implementation would be similar to custom types) |
| Strings | ✔️ | Only in Engines supporting JS builtins. No escape sequences yet |
| Bools | ✅ | |
| Assignments | ✅ | |
| Discard patterns | ✅ | |
| Blocks | ✅ | |
| Lists | ✅ | |
| Constants | ✔️ | Just Int and Float |
| Functions | ✅ | |
| Higher order functions | ✅ | |
| Anonymous functions | ✔️ | Immediately calling a fn expression is not implemented yet |
| Function captures | ✅ | |
| Generic functions | ✔️ | No polymorphic recursion |
| Pipelines | ✔️ | Not for echo |
| Case expressions | ✔️ | Single subject, no guards, no alternative patterns |
| Variable patterns | ✅ | |
| String patterns | ✅ | |
| List patterns | ✅ | |
| Recursion | ✅ | |
| Tail calls | ✅ | Tail calls are optimized |
| List recursion | ✅ | |
| Tuples | ✔️ | As long as they are not generic used together with records |
| Custom Types | ✔️ | No cyclic references |
| Records | ✅ | |
| Record accessors | ✅ | |
| Record pattern matching | ✔️ | Only in case patterns |
| Record updates | ✅ | |
| Generic custom types | ✅ | |
| Nil | ✅ | |
| Todo/Panic | ✔️ | Without message, since strings and printing to stdout is not supported everywhere |
| Externals | ✅ | Currently, functions having the @external attribute must provide a default implementation ({panic} is sufficient) |
If you are not familiar with Gleam, checkout tutorial.
Use the following gleam.toml:
name = "yourprojectname"
version = "1.0.0"
[dependencies]
[dev-dependencies]
[webassembly]
runtime = "deno"Please note that dependencies and tests are currently not supported. Remove them.
Your project must consist of a single .gleam file with at least the main function (pub fn main).
In the next steps, we assume the current working directory is the Gleam project root.
The WebAssembly artifacts are in build/dev/webassembly/<package>.
Use GLEAM_LOG=trace to see all log messages.
The easiest way to use the compiler and execute the programs is with Docker
or Nix because they include the Deno runtime
and wasm-tools, which is required for some features.
When you use gleam run it will print the return value of the main function.
For advanced features like importing JavaScript or WebAssembly-Functions or exporting functions from the module, see the examples here and here
docker run -v ./:/src -it ghcr.io/tufteddeer/gleam-webassembly:webassembly bash -c "gleam run --target webassembly"Get the sourcecode.
You can build the project like any other Rust application. Then, use the binary like:
gleam run --target webassemblyor point cargo to the source directory and use cargo run
cargo run --manifest-path <path/to/compiler/src>/Cargo.toml -- build --target webassemblyGet the sourcecode. Inside the Gleam project, use
nix run <path/to/compiler/src> -- run --target webassembly
todo: nix run https://github.com/tufteddeer/gleam-webassembly -- run --target webassembly would be nicer, but
since the repo is currently private we must fetch the source ourselves
Make sure you have Rust, Deno and all dependencies installed (further down this page)
cd test-wasm-js-parity/testrunner/
deno test -A
This will build the compiler and execute all test cases contained in test-wasm-js-parity/gleam to ensure equal
behavior between Gleam compiled to JS and Wasm.
tl;dr: use Deno or the browser
The best supported targets are Deno and the browser (recent Chrome versions). Builds made for Deno are compatible with the browser.
The runtime (default: Deno) has to be configured in the gleam.toml file, not via 'gleam run --runtime'. While this might work with different JS based runtimes, it won't work with others like Wasmtime. This is because the selected runtime affects code generation (e.g JS String builtin imports) and must be known when building the binary.
[webassembly]
runtime = "deno"Wasmtime is supported, as long as no strings are used.
Hosts executing Wasm Component Model binaries are barely supported and only as long as the used types are limited to integer and float values (example). To build modules to be used with the component model, use 'componentmodel' as runtime.
- wasm-merge, Version 123 or compatible
- a WebAssembly runtime, preferably Deno
The following versions where used to develop and test the project
- Gleam 1.9.1
- wasmtime 31
- wasm-merge 123
- wasm-tools 1.229
- Chrome 137
- Deno 2.2
- Rust 1.87
- a nix flake to build Gleam including a development shell with Deno, Wasmtime and some Wasm tools needed in compatible versions
- a Docker image with all required tools to try Gleam with WebAssembly
gleam runon Deno prints the return value of the main function for easier testing- springled some
#[allow(clippy::XXX)]over upstream code to suppress new lints - ci: clippy is pinned to 1.87 so it does not surprise me with new lints every few weeks
- pinned gleam stdlib to a version that supports gleam 1.9.1 in some test projects since newer versions require a newer gleam binary, disabled some tests with the same problem
Gleam is a friendly language for building type-safe systems that scale! For more information see the website.
Gleam is kindly supported by its sponsors. If you would like to support Gleam please consider sponsoring its development on GitHub.
Thank you to our sponsors! Gleam would not be possible without you.
Aaron Gunderson - Abdulrhman Alkhodiry - Abel Jimenez - ad-ops - Adam Brodzinski - Adam Johnston - Adam Wyłuda - Adi Iyengar - Adrian Mouat - Ajit Krishna - Aleksei Gurianov - Alembic - Alex - Alex Houseago - Alex Manning - Alex Viscreanu - Alexander Koutmos - Alexander Stensrud - Alexandre Del Vecchio - Ameen Radwan - Andrea Bueide - AndreHogberg - Andrew Muratov - Antharuu - Anthony Khong - Anthony Maxwell - Anthony Scotti - Arthur Weagel - Arya Irani - Azure Flash - Barry Moore - Bartek Górny - Ben Martin - Ben Marx - Ben Myles - Benjamin Kane - Benjamin Peinhardt - bgw - Bjarte Aarmo Lund - Bjoern Paschen - Brad Mehder - Brendan P. - brettkolodny - Brian Dawn - Brian Glusman - Bruce Williams - Bruno Michel - bucsi - Cam Ray - Cameron Presley - Carlo Munguia - Carlos Saltos - Chad Selph - Charlie Duong - Charlie Govea - Chew Choon Keat - Chris Donnelly - Chris King - Chris Lloyd - Chris Ohk - Chris Rybicki - Christopher David Shirk - Christopher De Vries - Christopher Dieringer - Christopher Jung - Christopher Keele - CJ Salem - clangley - Clifford Anderson - Coder - Cole Lawrence - Colin - Comamoca - Constantin (Cleo) Winkler - Corentin J. - Daigo Shitara - Damir Vandic - Dan Dresselhaus - Dan Strong - Danielle Maywood - Danny Arnold - Danny Martini - Dave Lucia - David Bernheisel - David Cornu - David Sancho - Dennis Dang - dennistruemper - Diemo Gebhardt - Dillon Mulroy - Dima Utkin - Dmitry Poroh - DoctorCobweb - Donnie Flood - ds2600 - Dylan Carlson - Ed Hinrichsen - Edon Gashi - eeeli24 - Eileen Noonan - eli - Emma - EMR Technical Solutions - Endo Shogo - Eric Koslow - Erik Terpstra - erikareads - ErikML - erlend-axelsson - Ernesto Malave - Ethan Olpin - Evaldo Bratti - Evan Johnson - evanasse - Fabrizio Damicelli - Fede Esteban - Felix Mayer - Fernando Farias - Filip Figiel - Florian Kraft - Francis Hamel - frankwang - G-J van Rooyen - Gabriel Vincent - Geir Arne Hjelle - Georg Hartmann - George - Georgi Martsenkov - ggobbe - Giacomo Cavalieri - Giovanni Kock Bonetti - Graham Vasquez - grotto - Guilherme de Maio - Guillaume Heu - Guillaume Hivert - Hammad Javed - Hannes Nevalainen - Hannes Schnaitter - Hans Raaf - Hayleigh Thompson - Hazel Bachrach - Henning Dahlheim - Henrik Tudborg - Henry Warren - Heyang Zhou - Hubert Małkowski - human154 - Humberto Piaia - Iain H - Ian González - Ian M. Jones - Igor Montagner - Igor Rumiha - ILLIA NEGOVORA - Ingrid - inoas - Isaac - Isaac Harris-Holt - Isaac McQueen - Ismael Abreu - István Bozsó - Ivar Vong - Jacob Lamb - Jake Cleary - Jake Wood - Jakob Ladegaard Møller - James Birtles - James MacAulay - Jan Pieper - Jan Skriver Sørensen - Jean-Adrien Ducastaing - Jean-Luc Geering - Jen Stehlik - jiangplus - Jimpjorps™ - Joey Kilpatrick - Joey Trapp - Johan Strand - John Björk - John Gallagher - John Pavlick - John Strunk - Jojor - Jon Lambert - Jonas E. P - Jonas Hedman Engström - jooaf - Joseph Lozano - Joshua Steele - Julian Hirn - Julian Lukwata - Julian Schurhammer - Justin Lubin - Jérôme Schaeffer - Kemp Brinson - Kero van Gelder - Kevin Schweikert - Kramer Hampton - Kritsada Sunthornwutthikrai - Kryštof Řezáč - Krzysztof G. - Leandro Ostera - Lee Jarvis - Leon Qadirie - Leonardo Donelli - lidashuang - Lily Rose - liv - Loïc Tosser - Lucas Pellegrinelli - Lukas Bjarre - Lukas Meihsner - Luke Amdor - Luna - Manuel Rubio - Marcos - marcusandre - Mariano Uvalle - Marius Kalvø - Mark Holmes - Mark Markaryan - Martijn Gribnau - Martin Janiczek - Martin Poelstra - Martin Rechsteiner - martonkaufmann - Matt Champagne - Matt Heise - Matt Mullenweg - Matt Robinson - Matt Savoia - Matt Van Horn - Matthew Whitworth - Max McDonnell - metame - METATEXX GmbH - Metin Emiroğlu - Michael Duffy - Michael Jones - Michael Mazurczak - Michael McClintock - Mikael Karlsson - Mike Roach - Mikey J - MoeDev - MzRyuKa - n8n - Workflow Automation - Natanael Sirqueira - Nathaniel Knight - Nayuki - NFIBrokerage - Nick Chapman - Nick Reynolds - Nicklas Sindlev Andersen - NicoVIII - Niket Shah - Nikolai S. K. - Ninaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - NineFX - Nomio - Ocean - Olaf Sebelin - OldhamMade - Oliver Medhurst - Oliver Tosky - optizio - Patrick Wheeler - Paul Guse - Pawel Biernacki - Pedro Correa - Pete Jodo - Peter Rice - Philpax - Pierrot - Qdentity - Race Williams - Rasmus - Ray - Raúl Chouza - re.natillas - Redmar Kerkhoff - Reilly Tucker Siemens - Renato Massaro - Renovator - Richard Viney - Rico Leuthold - Rintaro Okamura - Ripta Pasay - Rob - Robert Attard - Robert Ellen - Robert Malko - Rodrigo Álvarez - Ronan Harris - Rotabull - Rupus Reinefjord - Ruslan Ustitc - Ryan Moore - Sam Aaron - Sam Zanca - sambit - Sammy Isseyegh - Santi Lertsumran - Savva - Saša Jurić - Scott Trinh - Scott Weber - Scott Wey - Scott Zhu Reeves - Sean Jensen-Grey - Sean Roberts - Sebastian Porto - sekun - Seve Salazar - Shane Poppleton - Shuqian Hon - Sigma - Simone Vittori - Stefan - Stefan Hagen - Steinar Eliassen - Stephen Belanger - Steve Powers - Strandinator - Sławomir Ehlert - Theo Harris - Thomas - Thomas Coopman - Thomas Ernst - Tim Brown - Timo Sulg - Tom Schuster - Tomasz Kowal - tommaisey - Travis Johnson - Tristan de Cacqueray - Tristan Sloughter - Tudor Luca - tymak - upsidedowncake - Valerio Viperino - Vic Valenzuela - Victor Rodrigues - Viv Verner - Volker Rabe - Walton Hoops - Weizheng Liu - wheatfox - Willyboar - Wilson Silva - Xucong Zhan - Yamen Sader - Yasuo Higano - yoshi~ - Zsombor Gasparin - ZWubs - ~1814730 - ~1847917 - ~1867501 - Éber Freitas Dias

