From 7487df3d84c571ff4a0e8f4b329655361faa9d05 Mon Sep 17 00:00:00 2001 From: George Thomas Date: Wed, 17 Jun 2026 15:22:51 +0100 Subject: [PATCH 01/14] Enable building with GHC 9.14 --- cabal.project | 7 +++++++ packages/coln-cli/coln-cli.cabal | 2 +- packages/coln-do/coln-do.cabal | 2 +- packages/coln-manual-dev/coln-manual-dev.cabal | 2 +- packages/diagnostician-html/diagnostician-html.cabal | 2 +- .../diagnostician-terminal/diagnostician-terminal.cabal | 2 +- packages/diagnostician/diagnostician.cabal | 4 ++-- packages/fnotation/fnotation.cabal | 4 ++-- 8 files changed, 16 insertions(+), 9 deletions(-) diff --git a/cabal.project b/cabal.project index 861dc68d..0c9c2a40 100644 --- a/cabal.project +++ b/cabal.project @@ -9,3 +9,10 @@ constraints: -- https://github.com/haskell/lsp/issues/641 lsp >= 2.8.0.0, lsp-types >= 2.4, + +if impl(ghc >= 9.14) + allow-newer: + -- https://github.com/dmwit/ordered-containers/pull/36 + ordered-containers:containers, + -- https://github.com/georgefst/prettyprinter-lucid/issues/7 + prettyprinter-lucid:base, diff --git a/packages/coln-cli/coln-cli.cabal b/packages/coln-cli/coln-cli.cabal index 0fd81be7..5e0e4360 100644 --- a/packages/coln-cli/coln-cli.cabal +++ b/packages/coln-cli/coln-cli.cabal @@ -23,7 +23,7 @@ executable coln Coln.CLI.REPL build-depends: - base ^>=4.21.0.0, + base ^>=4.21.0.0 || ^>=4.22, coln-compiler, coln-ls, coln-repl, diff --git a/packages/coln-do/coln-do.cabal b/packages/coln-do/coln-do.cabal index d662e134..7fa0548f 100644 --- a/packages/coln-do/coln-do.cabal +++ b/packages/coln-do/coln-do.cabal @@ -22,7 +22,7 @@ executable coln-do default-language: GHC2024 ghc-options: -Wall build-depends: - base ^>=4.21.0.0, + base ^>=4.21.0.0 || ^>=4.22, bytestring, directory, djot, diff --git a/packages/coln-manual-dev/coln-manual-dev.cabal b/packages/coln-manual-dev/coln-manual-dev.cabal index 630e321c..06ef1229 100644 --- a/packages/coln-manual-dev/coln-manual-dev.cabal +++ b/packages/coln-manual-dev/coln-manual-dev.cabal @@ -15,7 +15,7 @@ executable coln-manual-dev main-is: Main.hs build-depends: async, - base ^>=4.21.0.0, + base ^>=4.21.0.0 || ^>=4.22, bytestring, directory, extra, diff --git a/packages/diagnostician-html/diagnostician-html.cabal b/packages/diagnostician-html/diagnostician-html.cabal index a351c579..88458236 100644 --- a/packages/diagnostician-html/diagnostician-html.cabal +++ b/packages/diagnostician-html/diagnostician-html.cabal @@ -21,7 +21,7 @@ library -Wall build-depends: - base ^>=4.21.0.0, + base ^>=4.21.0.0 || ^>=4.22, diagnostician, lucid, prettyprinter, diff --git a/packages/diagnostician-terminal/diagnostician-terminal.cabal b/packages/diagnostician-terminal/diagnostician-terminal.cabal index df97d0d8..43ac98cf 100644 --- a/packages/diagnostician-terminal/diagnostician-terminal.cabal +++ b/packages/diagnostician-terminal/diagnostician-terminal.cabal @@ -23,7 +23,7 @@ library build-depends: ansi-terminal, - base ^>=4.21.0.0, + base ^>=4.21.0.0 || ^>=4.22, diagnostician, prettyprinter, prettyprinter-ansi-terminal, diff --git a/packages/diagnostician/diagnostician.cabal b/packages/diagnostician/diagnostician.cabal index e9cac219..3cede7de 100644 --- a/packages/diagnostician/diagnostician.cabal +++ b/packages/diagnostician/diagnostician.cabal @@ -37,7 +37,7 @@ library ghc-options: -Wall build-depends: - base ^>=4.21.0.0, + base ^>=4.21.0.0 || ^>=4.22, containers, prettyprinter, text, @@ -73,6 +73,6 @@ test-suite diagnostician-test ghc-options: -Wall build-depends: - base ^>=4.21.0.0, + base ^>=4.21.0.0 || ^>=4.22, containers, diagnostician, diff --git a/packages/fnotation/fnotation.cabal b/packages/fnotation/fnotation.cabal index e9c8b243..6f076f3a 100644 --- a/packages/fnotation/fnotation.cabal +++ b/packages/fnotation/fnotation.cabal @@ -48,7 +48,7 @@ library ghc-options: -Wall build-depends: - base ^>=4.21.0.0, + base ^>=4.21.0.0 || ^>=4.22, containers, diagnostician, hashable, @@ -94,7 +94,7 @@ test-suite fnotation-test ghc-options: -Wall build-depends: QuickCheck, - base ^>=4.21.0.0, + base ^>=4.21.0.0 || ^>=4.22, bytestring, containers, diagnostician, From 06060f034bfbb10575665fcae10a3a73ebffcb2c Mon Sep 17 00:00:00 2001 From: George Thomas Date: Wed, 17 Jun 2026 15:31:41 +0100 Subject: [PATCH 02/14] Add GHC Wasm compiler and enable using it to build the Coln compiler --- cabal.project | 14 +++++++++- flake.lock | 77 +++++++++++++++++++++++++++++++++++++++++++++++++-- flake.nix | 3 ++ 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/cabal.project b/cabal.project index 0c9c2a40..2108ffad 100644 --- a/cabal.project +++ b/cabal.project @@ -1,5 +1,17 @@ packages: - packages/*/*.cabal + packages/diagnostician + packages/diagnostician-terminal + packages/diagnostician-html + packages/fnotation + packages/coln-compiler +if !os(wasi) + packages: + packages/coln-manual-dev + packages/coln-do + packages/coln-repl + packages/coln-ls + packages/coln-cli + jobs: $ncpus semaphore: true tests: True diff --git a/flake.lock b/flake.lock index 664ba68e..145fa01a 100644 --- a/flake.lock +++ b/flake.lock @@ -18,7 +18,62 @@ "type": "github" } }, + "flake-utils_2": { + "inputs": { + "systems": "systems_2" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "ghc-wasm-meta": { + "inputs": { + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs" + }, + "locked": { + "host": "gitlab.haskell.org", + "lastModified": 1782204359, + "narHash": "sha256-iC+iPfZOCTrB/WZaNHb9CQsZ+9u78UO/dyVZ/3OZB+M=", + "owner": "haskell-wasm", + "repo": "ghc-wasm-meta", + "rev": "9480caba4d6e622a67298d81307086582cc3ffe6", + "type": "gitlab" + }, + "original": { + "host": "gitlab.haskell.org", + "owner": "haskell-wasm", + "repo": "ghc-wasm-meta", + "type": "gitlab" + } + }, "nixpkgs": { + "locked": { + "lastModified": 1781472460, + "narHash": "sha256-dqwpb1o0xIwb1rv3PPbpY7RBm8heFiOLAubszNLBefc=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "8c14fa3ccacddaec887134e523083b63c8ea57ac", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-26.05-darwin", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { "locked": { "lastModified": 1780145889, "narHash": "sha256-md0zn0RnwNvPyASas1yG5YUuwQ4ALA6ucL50l0DvqCo=", @@ -34,7 +89,7 @@ "type": "github" } }, - "nixpkgs_2": { + "nixpkgs_3": { "locked": { "lastModified": 1744536153, "narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=", @@ -53,13 +108,14 @@ "root": { "inputs": { "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs", + "ghc-wasm-meta": "ghc-wasm-meta", + "nixpkgs": "nixpkgs_2", "rust-overlay": "rust-overlay" } }, "rust-overlay": { "inputs": { - "nixpkgs": "nixpkgs_2" + "nixpkgs": "nixpkgs_3" }, "locked": { "lastModified": 1782184651, @@ -89,6 +145,21 @@ "repo": "default", "type": "github" } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } } }, "root": "root", diff --git a/flake.nix b/flake.nix index f6a52aa4..c95806db 100644 --- a/flake.nix +++ b/flake.nix @@ -3,6 +3,7 @@ nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05"; flake-utils.url = "github:numtide/flake-utils"; rust-overlay.url = "github:oxalica/rust-overlay"; + ghc-wasm-meta.url = "gitlab:haskell-wasm/ghc-wasm-meta?host=gitlab.haskell.org"; }; outputs = inputs@{ @@ -156,6 +157,7 @@ }; inherit (packages) forester coln-manual-dev; + haskell-wasm = inputs.ghc-wasm-meta.packages.${system}.default; in { inherit packages; @@ -177,6 +179,7 @@ forester fourmolu esbuild + haskell-wasm haskell.compiler.ghc912 haskell.packages.ghc912.haskell-language-server haskellPackages.cabal-gild From bdd4617f8c0de02887596356026bf0218b5638c2 Mon Sep 17 00:00:00 2001 From: George Thomas Date: Fri, 19 Jun 2026 18:35:00 +0100 Subject: [PATCH 03/14] Add package for building Coln compiler as Wasm reactor module --- cabal.project | 3 + flake.nix | 1 + packages/coln-do/app/ColnDo/Build.hs | 19 +++ packages/coln-wasm/Lib.hs | 67 ++++++++++ packages/coln-wasm/coln-wasm.cabal | 31 +++++ packages/coln-wasm/example.html | 185 +++++++++++++++++++++++++++ 6 files changed, 306 insertions(+) create mode 100644 packages/coln-wasm/Lib.hs create mode 100644 packages/coln-wasm/coln-wasm.cabal create mode 100644 packages/coln-wasm/example.html diff --git a/cabal.project b/cabal.project index 2108ffad..806f8104 100644 --- a/cabal.project +++ b/cabal.project @@ -11,6 +11,9 @@ if !os(wasi) packages/coln-repl packages/coln-ls packages/coln-cli +else + packages: + packages/coln-wasm jobs: $ncpus semaphore: true diff --git a/flake.nix b/flake.nix index c95806db..21a04742 100644 --- a/flake.nix +++ b/flake.nix @@ -193,6 +193,7 @@ openssl pkg-config reuse + simple-http-server tectonic typescript zlib diff --git a/packages/coln-do/app/ColnDo/Build.hs b/packages/coln-do/app/ColnDo/Build.hs index 651110a2..1c18120f 100644 --- a/packages/coln-do/app/ColnDo/Build.hs +++ b/packages/coln-do/app/ColnDo/Build.hs @@ -28,6 +28,25 @@ buildRules = do phony "build-haskell" $ do cmd_ "cabal build all" + let wasmBuildDir = "_build/wasm" + wasmDistDir = wasmBuildDir "dist" + wasmBin = wasmDistDir "coln.wasm" + jsffi = wasmDistDir "ghc_wasm_jsffi.js" + liftIO $ createDirectoryIfMissing True wasmDistDir + wasmBin %> \_ -> do + alwaysRerun + cmd_ "wasm32-wasi-cabal build coln-wasm" + StdoutTrim bin <- cmd "wasm32-wasi-cabal list-bin coln-wasm" + copyFileChanged bin wasmBin + jsffi %> \_ -> do + need [wasmBin] + StdoutTrim libdir <- cmd "wasm32-wasi-ghc --print-libdir" + cmd_ (libdir "post-link.mjs") "--input" wasmBin "--output" jsffi + phony "serve-example-frontend" $ do + need [wasmBin, jsffi] + copyFileChanged "packages/coln-wasm/example.html" (wasmBuildDir "index.html") + runAfter $ cmd_ "simple-http-server --nocache --index --open" wasmBuildDir + phony "build-rust" $ do cmd_ "cargo build" diff --git a/packages/coln-wasm/Lib.hs b/packages/coln-wasm/Lib.hs new file mode 100644 index 00000000..805120ed --- /dev/null +++ b/packages/coln-wasm/Lib.hs @@ -0,0 +1,67 @@ +module Lib () where + +import Coln.Backend.IR qualified as I +import Coln.Backend.Lower +import Coln.Core.Globals +import Coln.Diagnostics +import Coln.Frontend.Driver +import Control.Monad +import Data.Aeson.Text qualified as Aeson +import Data.Foldable +import Data.IORef +import Data.Map.Ordered qualified as OMap +import Data.Text (Text) +import Data.Text qualified as T +import Data.Text.Lazy qualified as TL +import Diagnostician +import Diagnostician.HTML (diagnosticToHtml) +import Foreign.StablePtr +import GHC.Wasm.Prim +import Lucid qualified +import Prettyprinter +import Prettyprinter.Render.Text qualified as Text + +data CompileResult = CompileResult + { ir :: [I.FlatRealm] + , diagnostics :: [Diagnostic ColnCode] + } +foreign export javascript "freeCompileResult" freeStablePtr :: StablePtr CompileResult -> IO () + +compile :: JSString -> IO (StablePtr CompileResult) +compile src = do + ref <- newIORef [] + globals <- topFromText (pureReporter ref) (newFile "" $ textFromJSString src) + let ir = map (uncurry lowerRealm) $ OMap.assocs globals.realms + diagnostics <- reverse <$> readIORef ref + newStablePtr CompileResult{ir, diagnostics} +foreign export javascript "compile" compile :: JSString -> IO (StablePtr CompileResult) + +getDiagnostics :: Bool -> StablePtr CompileResult -> IO JSVal +getDiagnostics asHtml = jsStringArray . map (textToJSString . TL.toStrict . render) . (.diagnostics) <=< deRefStablePtr + where + render = + if asHtml + then Lucid.renderText . diagnosticToHtml + else Text.renderLazy . layoutPretty defaultLayoutOptions . dpretty +foreign export javascript "getDiagnostics" getDiagnostics :: Bool -> StablePtr CompileResult -> IO JSVal + +prettyIr :: StablePtr CompileResult -> IO JSVal +prettyIr = jsStringArray . map (textToJSString . T.show) . (.ir) <=< deRefStablePtr +foreign export javascript "prettyIr" prettyIr :: StablePtr CompileResult -> IO JSVal + +irToJson :: StablePtr CompileResult -> IO JSString +irToJson = fmap (textToJSString . TL.toStrict . Aeson.encodeToLazyText . (.ir)) . deRefStablePtr +foreign export javascript "irToJson" irToJson :: StablePtr CompileResult -> IO JSString + +textToJSString :: Text -> JSString +textToJSString = toJSString . T.unpack +textFromJSString :: JSString -> Text +textFromJSString = T.pack . fromJSString + +foreign import javascript unsafe "[]" js_new_array :: IO JSVal +foreign import javascript unsafe "$1.push($2)" js_push_string :: JSVal -> JSString -> IO () +jsStringArray :: [JSString] -> IO JSVal +jsStringArray ss = do + arr <- js_new_array + for_ ss $ js_push_string arr + pure arr diff --git a/packages/coln-wasm/coln-wasm.cabal b/packages/coln-wasm/coln-wasm.cabal new file mode 100644 index 00000000..8c493b8f --- /dev/null +++ b/packages/coln-wasm/coln-wasm.cabal @@ -0,0 +1,31 @@ +cabal-version: 3.4 +name: coln-wasm +version: 0.1 + +executable coln-wasm + main-is: Lib.hs + hs-source-dirs: . + default-language: GHC2024 + default-extensions: + NoFieldSelectors + OverloadedRecordDot + OverloadedStrings + + build-depends: + aeson, + base, + coln-compiler, + containers, + diagnostician, + diagnostician-html, + fnotation, + ghc-experimental, + lucid, + ordered-containers, + prettyprinter, + text, + + ghc-options: + -Wall + -no-hs-main + -optl-mexec-model=reactor diff --git a/packages/coln-wasm/example.html b/packages/coln-wasm/example.html new file mode 100644 index 00000000..4f6a0933 --- /dev/null +++ b/packages/coln-wasm/example.html @@ -0,0 +1,185 @@ + + + + + Coln + + + +

Coln

+
+ + + +
+ +
+ +
+ +

+
+    
+  
+

From f311429b01bdf9a8b2c70d513846ec859f672841 Mon Sep 17 00:00:00 2001
From: George Thomas 
Date: Wed, 24 Jun 2026 12:20:11 +0100
Subject: [PATCH 04/14] Add missing license header

---
 packages/coln-wasm/Lib.hs | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/packages/coln-wasm/Lib.hs b/packages/coln-wasm/Lib.hs
index 805120ed..51bcc540 100644
--- a/packages/coln-wasm/Lib.hs
+++ b/packages/coln-wasm/Lib.hs
@@ -1,3 +1,7 @@
+-- SPDX-FileCopyrightText: 2026 Coln contributors
+--
+-- SPDX-License-Identifier: Apache-2.0 OR MIT
+
 module Lib () where
 
 import Coln.Backend.IR qualified as I

From 8a1cb4164b422c6f24c42c38cb012e3612128254 Mon Sep 17 00:00:00 2001
From: George Thomas 
Date: Wed, 24 Jun 2026 17:35:02 +0100
Subject: [PATCH 05/14] Avoid wrapping HTML diagnostics

---
 packages/diagnostician-html/src/Diagnostician/HTML.hs | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/packages/diagnostician-html/src/Diagnostician/HTML.hs b/packages/diagnostician-html/src/Diagnostician/HTML.hs
index cb299293..4b878b8b 100644
--- a/packages/diagnostician-html/src/Diagnostician/HTML.hs
+++ b/packages/diagnostician-html/src/Diagnostician/HTML.hs
@@ -9,7 +9,7 @@ module Diagnostician.HTML (
 import Data.Text (Text)
 import Diagnostician
 import Lucid (Html, class_, div_, span_)
-import Prettyprinter (defaultLayoutOptions, layoutPretty)
+import Prettyprinter (LayoutOptions (LayoutOptions, layoutPageWidth), PageWidth (Unbounded), layoutPretty)
 import Prettyprinter.Lucid (renderHtml)
 import Prettyprinter.Render.Util.SimpleDocTree (treeForm)
 
@@ -21,7 +21,7 @@ diagnosticToHtml d =
     . renderHtml
     . treeForm
     . fmap (span_ . pure @[] . class_ . ("ann-" <>) . annClassSuffix)
-    . layoutPretty defaultLayoutOptions
+    . layoutPretty LayoutOptions{layoutPageWidth = Unbounded}
     $ dpretty d
 
 severityClassSuffix :: Severity -> Text

From 1298b7e724df68f7e3de3d331ead22586fd26229 Mon Sep 17 00:00:00 2001
From: George Thomas 
Date: Wed, 24 Jun 2026 18:05:43 +0100
Subject: [PATCH 06/14] Enable specifying port on which to serve example app

---
 packages/coln-do/app/ColnDo/Build.hs | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/packages/coln-do/app/ColnDo/Build.hs b/packages/coln-do/app/ColnDo/Build.hs
index 1c18120f..4294d909 100644
--- a/packages/coln-do/app/ColnDo/Build.hs
+++ b/packages/coln-do/app/ColnDo/Build.hs
@@ -5,6 +5,7 @@
 module ColnDo.Build where
 
 import ColnDo.Common
+import Data.Maybe
 import System.Directory (createDirectoryIfMissing)
 import System.Info qualified
 
@@ -44,8 +45,9 @@ buildRules = do
     cmd_ (libdir  "post-link.mjs") "--input" wasmBin "--output" jsffi
   phony "serve-example-frontend" $ do
     need [wasmBin, jsffi]
+    port <- fromMaybe "8000" <$> getEnv "PORT"
     copyFileChanged "packages/coln-wasm/example.html" (wasmBuildDir  "index.html")
-    runAfter $ cmd_ "simple-http-server --nocache --index --open" wasmBuildDir
+    runAfter $ cmd_ "simple-http-server --nocache --index --open" "--port" port wasmBuildDir
 
   phony "build-rust" $ do
     cmd_ "cargo build"

From b48cdf557b5e6319873f8e5be7f77633218f55fc Mon Sep 17 00:00:00 2001
From: George Thomas 
Date: Wed, 24 Jun 2026 18:28:23 +0100
Subject: [PATCH 07/14] Migrate Wasm lib build from Shake to Just

---
 packages/coln-do/app/ColnDo/Build.hs | 21 ---------------------
 packages/coln-wasm/justfile          | 14 ++++++++++++++
 2 files changed, 14 insertions(+), 21 deletions(-)
 create mode 100644 packages/coln-wasm/justfile

diff --git a/packages/coln-do/app/ColnDo/Build.hs b/packages/coln-do/app/ColnDo/Build.hs
index 4294d909..651110a2 100644
--- a/packages/coln-do/app/ColnDo/Build.hs
+++ b/packages/coln-do/app/ColnDo/Build.hs
@@ -5,7 +5,6 @@
 module ColnDo.Build where
 
 import ColnDo.Common
-import Data.Maybe
 import System.Directory (createDirectoryIfMissing)
 import System.Info qualified
 
@@ -29,26 +28,6 @@ buildRules = do
   phony "build-haskell" $ do
     cmd_ "cabal build all"
 
-  let wasmBuildDir = "_build/wasm"
-      wasmDistDir = wasmBuildDir  "dist"
-      wasmBin = wasmDistDir  "coln.wasm"
-      jsffi = wasmDistDir  "ghc_wasm_jsffi.js"
-  liftIO $ createDirectoryIfMissing True wasmDistDir
-  wasmBin %> \_ -> do
-    alwaysRerun
-    cmd_ "wasm32-wasi-cabal build coln-wasm"
-    StdoutTrim bin <- cmd "wasm32-wasi-cabal list-bin coln-wasm"
-    copyFileChanged bin wasmBin
-  jsffi %> \_ -> do
-    need [wasmBin]
-    StdoutTrim libdir <- cmd "wasm32-wasi-ghc --print-libdir"
-    cmd_ (libdir  "post-link.mjs") "--input" wasmBin "--output" jsffi
-  phony "serve-example-frontend" $ do
-    need [wasmBin, jsffi]
-    port <- fromMaybe "8000" <$> getEnv "PORT"
-    copyFileChanged "packages/coln-wasm/example.html" (wasmBuildDir  "index.html")
-    runAfter $ cmd_ "simple-http-server --nocache --index --open" "--port" port wasmBuildDir
-
   phony "build-rust" $ do
     cmd_ "cargo build"
 
diff --git a/packages/coln-wasm/justfile b/packages/coln-wasm/justfile
new file mode 100644
index 00000000..808969f1
--- /dev/null
+++ b/packages/coln-wasm/justfile
@@ -0,0 +1,14 @@
+build_dir := "../../_build/wasm"
+dist_dir := build_dir / "dist"
+
+build:
+    #!/usr/bin/env bash
+    mkdir -p {{ dist_dir }}
+    wasm32-wasi-cabal build coln-wasm
+    cp "$(wasm32-wasi-cabal list-bin coln-wasm)" {{ dist_dir }}/coln.wasm
+    libdir="$(wasm32-wasi-ghc --print-libdir)"
+    "$libdir/post-link.mjs" --input {{ dist_dir }}/coln.wasm --output {{ dist_dir }}/ghc_wasm_jsffi.js
+
+serve-example port="8000": build
+    cp example.html {{ build_dir }}/index.html
+    simple-http-server --nocache --index --open --port {{ port }} {{ build_dir }}

From 3334bda3b9b08abe8fdb14497575299997053d17 Mon Sep 17 00:00:00 2001
From: George Thomas 
Date: Wed, 24 Jun 2026 18:45:20 +0100
Subject: [PATCH 08/14] Add examples, reactivity and better styling

---
 packages/coln-wasm/example.html | 183 +++++++++++++++++++++-----------
 packages/coln-wasm/justfile     |   5 +
 2 files changed, 127 insertions(+), 61 deletions(-)

diff --git a/packages/coln-wasm/example.html b/packages/coln-wasm/example.html
index 4f6a0933..deb3a56f 100644
--- a/packages/coln-wasm/example.html
+++ b/packages/coln-wasm/example.html
@@ -5,95 +5,133 @@
     Coln
     
   
   
-    

Coln

-
- - - -
- -
- -
- -

+    
+
+

Coln

+ +
+

Source

+ +

Diagnostics

+
+

IR

+
+

JSON

+

+    
diff --git a/packages/coln-wasm/justfile b/packages/coln-wasm/justfile index 808969f1..27dfa9a5 100644 --- a/packages/coln-wasm/justfile +++ b/packages/coln-wasm/justfile @@ -10,5 +10,10 @@ build: "$libdir/post-link.mjs" --input {{ dist_dir }}/coln.wasm --output {{ dist_dir }}/ghc_wasm_jsffi.js serve-example port="8000": build + #!/usr/bin/env bash cp example.html {{ build_dir }}/index.html + examples_dir="{{ build_dir }}/examples" + mkdir -p "$examples_dir" + cp ../../packages/coln-compiler/test/*.coln "$examples_dir/" + ls -1 "$examples_dir"/*.coln | xargs -n1 basename | jq -nR '[inputs]' > "$examples_dir/index.json" simple-http-server --nocache --index --open --port {{ port }} {{ build_dir }} From c5f289026fa5ad4bf119151843b3e490ae5fd9f9 Mon Sep 17 00:00:00 2001 From: George Thomas Date: Wed, 24 Jun 2026 18:49:06 +0100 Subject: [PATCH 09/14] Add jq to Nix shell --- flake.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/flake.nix b/flake.nix index 21a04742..6575e345 100644 --- a/flake.nix +++ b/flake.nix @@ -183,6 +183,7 @@ haskell.compiler.ghc912 haskell.packages.ghc912.haskell-language-server haskellPackages.cabal-gild + jq just nodejs pnpm From 9eeabbafef7004dbcbf0e92eb324ec65f60d492b Mon Sep 17 00:00:00 2001 From: George Thomas Date: Thu, 25 Jun 2026 09:52:54 +0100 Subject: [PATCH 10/14] Fix IR separators --- packages/coln-wasm/example.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/coln-wasm/example.html b/packages/coln-wasm/example.html index deb3a56f..834f9103 100644 --- a/packages/coln-wasm/example.html +++ b/packages/coln-wasm/example.html @@ -90,7 +90,7 @@ .output { border: solid 1px var(--border); background: var(--alt-bg); - > div:not(:last-child) { + > :not(:last-child) { border-bottom: solid 1px var(--border); } } From 7be7fb9e67c464a22b9de010988aad6930d3b2a9 Mon Sep 17 00:00:00 2001 From: George Thomas Date: Thu, 25 Jun 2026 10:17:53 +0100 Subject: [PATCH 11/14] Make Just Bash scripts safer --- packages/coln-wasm/justfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/coln-wasm/justfile b/packages/coln-wasm/justfile index 27dfa9a5..b9f6ebac 100644 --- a/packages/coln-wasm/justfile +++ b/packages/coln-wasm/justfile @@ -3,6 +3,7 @@ dist_dir := build_dir / "dist" build: #!/usr/bin/env bash + set -euxo pipefail mkdir -p {{ dist_dir }} wasm32-wasi-cabal build coln-wasm cp "$(wasm32-wasi-cabal list-bin coln-wasm)" {{ dist_dir }}/coln.wasm @@ -11,6 +12,7 @@ build: serve-example port="8000": build #!/usr/bin/env bash + set -euxo pipefail cp example.html {{ build_dir }}/index.html examples_dir="{{ build_dir }}/examples" mkdir -p "$examples_dir" From 3afe1f0930bae97f9ebedf6216854e8949079d4f Mon Sep 17 00:00:00 2001 From: George Thomas Date: Thu, 25 Jun 2026 11:31:31 +0100 Subject: [PATCH 12/14] Revert GHC 9.14 bounds expansions for non-Wasm packages Since these pacakges are under `if !os(wasi)` in `cabal.project` and we're still using 9.12 for native builds, they haven't actually been tested with 9.14. --- packages/coln-cli/coln-cli.cabal | 2 +- packages/coln-do/coln-do.cabal | 2 +- packages/coln-manual-dev/coln-manual-dev.cabal | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/coln-cli/coln-cli.cabal b/packages/coln-cli/coln-cli.cabal index 5e0e4360..0fd81be7 100644 --- a/packages/coln-cli/coln-cli.cabal +++ b/packages/coln-cli/coln-cli.cabal @@ -23,7 +23,7 @@ executable coln Coln.CLI.REPL build-depends: - base ^>=4.21.0.0 || ^>=4.22, + base ^>=4.21.0.0, coln-compiler, coln-ls, coln-repl, diff --git a/packages/coln-do/coln-do.cabal b/packages/coln-do/coln-do.cabal index 7fa0548f..d662e134 100644 --- a/packages/coln-do/coln-do.cabal +++ b/packages/coln-do/coln-do.cabal @@ -22,7 +22,7 @@ executable coln-do default-language: GHC2024 ghc-options: -Wall build-depends: - base ^>=4.21.0.0 || ^>=4.22, + base ^>=4.21.0.0, bytestring, directory, djot, diff --git a/packages/coln-manual-dev/coln-manual-dev.cabal b/packages/coln-manual-dev/coln-manual-dev.cabal index 06ef1229..630e321c 100644 --- a/packages/coln-manual-dev/coln-manual-dev.cabal +++ b/packages/coln-manual-dev/coln-manual-dev.cabal @@ -15,7 +15,7 @@ executable coln-manual-dev main-is: Main.hs build-depends: async, - base ^>=4.21.0.0 || ^>=4.22, + base ^>=4.21.0.0, bytestring, directory, extra, From 18c8cea1fff32437312b5b3f79600514c08bfebb Mon Sep 17 00:00:00 2001 From: George Thomas Date: Thu, 25 Jun 2026 12:01:55 +0100 Subject: [PATCH 13/14] Add README for Coln compiler Wasm library --- packages/coln-wasm/README.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 packages/coln-wasm/README.md diff --git a/packages/coln-wasm/README.md b/packages/coln-wasm/README.md new file mode 100644 index 00000000..7b424c29 --- /dev/null +++ b/packages/coln-wasm/README.md @@ -0,0 +1,3 @@ +# Coln compiler Wasm library + +This package can be compiled with the [GHC WebAssembly backend](https://downloads.haskell.org/ghc/latest/docs/users_guide/wasm.html) to produce a [WASI reactor module](https://github.com/WebAssembly/WASI/blob/wasi-0.1/application-abi.md#current-unstable-abi). See [this example](./example.html) for how to call it from JavaScript. The example app can be launched with `just serve-example`. All necessary tools, including a Wasm-targeting GHC and Cabal, are provided by this repository's top-level Nix shell. From b5f61e402242c1c697de7898b4dc7dbe71185a41 Mon Sep 17 00:00:00 2001 From: George Thomas Date: Thu, 25 Jun 2026 12:03:18 +0100 Subject: [PATCH 14/14] Rename Coln compiler Wasm library --- cabal.project | 2 +- packages/{coln-wasm => coln-compiler-wasm}/Lib.hs | 0 packages/{coln-wasm => coln-compiler-wasm}/README.md | 0 .../coln-compiler-wasm.cabal} | 4 ++-- packages/{coln-wasm => coln-compiler-wasm}/example.html | 0 packages/{coln-wasm => coln-compiler-wasm}/justfile | 4 ++-- 6 files changed, 5 insertions(+), 5 deletions(-) rename packages/{coln-wasm => coln-compiler-wasm}/Lib.hs (100%) rename packages/{coln-wasm => coln-compiler-wasm}/README.md (100%) rename packages/{coln-wasm/coln-wasm.cabal => coln-compiler-wasm/coln-compiler-wasm.cabal} (89%) rename packages/{coln-wasm => coln-compiler-wasm}/example.html (100%) rename packages/{coln-wasm => coln-compiler-wasm}/justfile (85%) diff --git a/cabal.project b/cabal.project index 806f8104..9fba4982 100644 --- a/cabal.project +++ b/cabal.project @@ -13,7 +13,7 @@ if !os(wasi) packages/coln-cli else packages: - packages/coln-wasm + packages/coln-compiler-wasm jobs: $ncpus semaphore: true diff --git a/packages/coln-wasm/Lib.hs b/packages/coln-compiler-wasm/Lib.hs similarity index 100% rename from packages/coln-wasm/Lib.hs rename to packages/coln-compiler-wasm/Lib.hs diff --git a/packages/coln-wasm/README.md b/packages/coln-compiler-wasm/README.md similarity index 100% rename from packages/coln-wasm/README.md rename to packages/coln-compiler-wasm/README.md diff --git a/packages/coln-wasm/coln-wasm.cabal b/packages/coln-compiler-wasm/coln-compiler-wasm.cabal similarity index 89% rename from packages/coln-wasm/coln-wasm.cabal rename to packages/coln-compiler-wasm/coln-compiler-wasm.cabal index 8c493b8f..3f5272f1 100644 --- a/packages/coln-wasm/coln-wasm.cabal +++ b/packages/coln-compiler-wasm/coln-compiler-wasm.cabal @@ -1,8 +1,8 @@ cabal-version: 3.4 -name: coln-wasm +name: coln-compiler-wasm version: 0.1 -executable coln-wasm +executable coln-compiler-wasm main-is: Lib.hs hs-source-dirs: . default-language: GHC2024 diff --git a/packages/coln-wasm/example.html b/packages/coln-compiler-wasm/example.html similarity index 100% rename from packages/coln-wasm/example.html rename to packages/coln-compiler-wasm/example.html diff --git a/packages/coln-wasm/justfile b/packages/coln-compiler-wasm/justfile similarity index 85% rename from packages/coln-wasm/justfile rename to packages/coln-compiler-wasm/justfile index b9f6ebac..d67454d4 100644 --- a/packages/coln-wasm/justfile +++ b/packages/coln-compiler-wasm/justfile @@ -5,8 +5,8 @@ build: #!/usr/bin/env bash set -euxo pipefail mkdir -p {{ dist_dir }} - wasm32-wasi-cabal build coln-wasm - cp "$(wasm32-wasi-cabal list-bin coln-wasm)" {{ dist_dir }}/coln.wasm + wasm32-wasi-cabal build coln-compiler-wasm + cp "$(wasm32-wasi-cabal list-bin coln-compiler-wasm)" {{ dist_dir }}/coln.wasm libdir="$(wasm32-wasi-ghc --print-libdir)" "$libdir/post-link.mjs" --input {{ dist_dir }}/coln.wasm --output {{ dist_dir }}/ghc_wasm_jsffi.js