Skip to content

tufteddeer/gleam-webassembly

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8,880 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

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 @external attribute
  • exporting of functions using the new @wasm_export attribute

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:

Process overview

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.

process diagram explaining how Gleam is compiled to WebAssembly

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.

Features

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)

Usage

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

Using docker

docker run -v ./:/src -it ghcr.io/tufteddeer/gleam-webassembly:webassembly bash -c "gleam run --target webassembly"

Using cargo

Get the sourcecode.

You can build the project like any other Rust application. Then, use the binary like:

gleam run --target webassembly

or point cargo to the source directory and use cargo run

cargo run --manifest-path <path/to/compiler/src>/Cargo.toml -- build --target webassembly

Using nix

Get 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

Tests

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.

Supported targets

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.

Requirements

  • wasm-merge, Version 123 or compatible
  • a WebAssembly runtime, preferably Deno

Versions

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

Changes not directly related to WebAssembly

  • 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 run on 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

Lucy, Gleam's mascot

GitHub release Discord chat

 

Gleam is a friendly language for building type-safe systems that scale! For more information see the website.

Sponsors

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

About

A modified Gleam compiler to translate Gleam to WebAssembly

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors