I would like to use ROC as an embedded language in both web and desktop targets (wasmtime?) under sandbox environments. The scripting language has to export functions which will then be called by host. Is this possible? What is a good example to follow? (My host language is Rust). Or is this not a good usecase for roc?
Hi @swoorup joshi,
This is our wasm example. Unfortunately we made a mistake in testing it, so it silently broke, see also #7756. @Brendan Hansknecht @Luke Boswell do you know what happened to the glue.zig file required by web-assembly-platform/host.zig?
This roc wasm project may still work though
hmm, is there an example for rust? I am not familiar with zig :sweat_smile:. I am also wondering if it is somehow possible to embed the compiler into the host language.
I saw some old chats about using it with other host like bevy, but it was quite a while back. I am unsure if roc is still suitable for such embedded usecase?
hmm, is there an example for rust?
embed the compiler into the host language.
The wasm repl may be the example you want, it's available for use here. This is a nice image of how it works.
Interesting, I'll take a look.
Here's an example of using Roc for the front-end https://github.com/niclas-ahden/joy
I believe @Niclas Ahden is using this currently.
The story will be much nicer in future with the new zig compiler I think, as there's a few workarounds and challenges to do this using the current rust compiler design.
Oh interesting, I didn't know joy was using wasm.
I hope it will still be easier with Rust. :stuck_out_tongue_wink:
Luke Boswell said:
The story will be much nicer in future with the new zig compiler I think, as there's a few workarounds and challenges to do this using the current rust compiler design.
Unrelated, does zig compile to C or is able to directly compile to native code or wasm. I see some reference to c code, not sure what they are meant for.
It can do all 3
To c, native, and wasm
To c is pretty rare, but is used as part of the zig compiler bootstrapping, so it is well tested.
thanks, still playing around with examples, One thing isn't clear to me. Can roc compiler be itself be embedded as a wasm binary? So that it compiles roc files into other wasm files? So the compiler can be called from either browser directly or via wasmtime.
compiler be itself be embedded as a wasm binary? So that it compiles roc files into other wasm files?
Yes, I believe that is how the wasm repl works.
Oh right, that makes sense. Somehow looking at the architecture image I was thinking it was compiled on the server. (Still lot to digest)
The wasm repl archive may be useful to clarify things:
roc_repl_wasm.tar.gz
thinking it was compiled on the server.
No, it's all wasm and a bit of js
I think I need a index.html file to load those wasm files as well?
Yes, that archive is not standalone, see:
https://github.com/roc-lang/roc/blob/main/www/public/site.js
view-source:https://www.roc-lang.org/repl
https://github.com/roc-lang/roc/blob/c320a1bca567b5bcafa8f31f472120b6b5977e0b/www/content/repl/index.md
The build procure is described in https://github.com/roc-lang/roc/blob/c320a1bca567b5bcafa8f31f472120b6b5977e0b/crates/repl_wasm/README.md and https://github.com/roc-lang/roc/blob/c320a1bca567b5bcafa8f31f472120b6b5977e0b/www/README.md (builds the full roc website).
Thank you, does roc has any guidelines for interoping with rust types like algebraic data types? enums?
https://flinect.com/blog/rust-wasm-with-typescript-serde
We commonly refer to that interop code as glue.
We have a command to generate it but that generated code requires some manual fixing up. joy code probably provides the best guidance for you.
swoorup joshi said:
I hope it will still be easier with Rust. :stuck_out_tongue_wink:
Luke Boswell said:
The story will be much nicer in future with the new zig compiler I think, as there's a few workarounds and challenges to do this using the current rust compiler design.
I don't mean building the platform in Rust (as compared to Zig) .. but the new compiler that is being re-written in Zig (as opposed to the current one that is written in Rust).
:D
Tried building repl_wasm from main branch. Got errors building :/
error: failed to run custom build command for `roc_bitcode v0.0.1 (/Users/swoorup.joshi/github/roc-programming/roc/crates/compiler/builtins/bitcode)`
Caused by:
process didn't exit successfully: `/Users/swoorup.joshi/github/roc-programming/roc/target/release/build/roc_bitcode-1b9319928098b482/build-script-build` (exit status: 1)
--- stdout
cargo:rerun-if-changed=build.rs
Compiling zig object `object` to: /Users/swoorup.joshi/github/roc-programming/roc/crates/compiler/builtins/bitcode/zig-out/builtins-host.o
--- stderr
An internal compiler expectation was broken.
This is definitely a compiler bug.
Please file an issue here: <https://github.com/roc-lang/roc/issues/new/choose>
zig build object -Drelease=true failed 10 times in a row. The following error is unlikely to be a flaky error: object
+- install generated to builtins-host.o
+- zig build-obj builtins-host ReleaseFast native-macos 5 errors
src/main.zig:385:13: error: expected pointer type, found 'fn (dec.RocDec) callconv(.c) i128'
@export(func, .{ .name = "roc_builtins." ++ func_name, .linkage = .strong });
^~~~
src/main.zig:400:20: note: called from here
exportBuiltinFn(func, "dec." ++ func_name);
Did you use nix develop
to set up the dependencies?
Now trying to use nix develop, previously was using directly from system install zig and rust.
Yeah, your error seems to come from a wrong zig version. It's best to use nix develop because you need more than just zig and rust.
Looks like its compiling.
Although Kinda prefer devenv to nix develop, because that's all I used before, and doesn't drop me to bash from my fish shell. :sweat_smile:
nvm, looks like I just use fish from the bash shell
This is actually the first time I heard about devenv, it looks interesting :eyes:
its built atop of nix, and think covers most of the develop use-cases with extra few bells and whistles.
Does roc support WIT https://component-model.bytecodealliance.org/design/wit.html#enums by any chance?
I've never heard of WIT before, If anyone knows, it's @Brian Carroll
I was following along with how zed created their extension model in this blog https://zed.dev/blog/zed-decoded-extensions and came across it. Having a common IDL would make life so much easier.
Hey Anton! We never did anything for WIT and I'm not super familiar with it. Looking at the link, I think you could write a "Roc glue" plugin for it if you wanted to. That would make the most sense.
By the way @swoorup joshi, if you want to use your existing shell with a nix flake you can use direnv and optionally add nix-direnv. Then, in the repo, run direnv allow
and it'll add the devshell packages to your current shell.
hello again, I am starting to get a feel and play with roc code, and trying to basically get the repl_wasm running using wasmtime instead of js
But I am currently running into a crash, which I am not sure how to address.
I replace all js runner/functions with WastimeApp like so: https://github.com/Swoorup/roc-wasm-playground/blob/main/src/wasm_runner.rs
Running it gives
Enter an expression to evaluate, or a definition (like x = 1) to use later.
- ctrl-v + ctrl-j makes a newline
- :q quits
- :help shows this text again
>
thread 'main' panicked at library/core/src/panicking.rs:226:5:
unsafe precondition(s) violated: slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`
This indicates a bug in the program. This Undefined Behavior check is optional, and cannot be relied on for safety.
stack backtrace:
0: __rustc::rust_begin_unwind
at /rustc/27d6200a70601f6fcf419bf2f9e37989f3624ca4/library/std/src/panicking.rs:697:5
1: core::panicking::panic_nounwind_fmt::runtime
at /rustc/27d6200a70601f6fcf419bf2f9e37989f3624ca4/library/core/src/panicking.rs:117:22
2: core::panicking::panic_nounwind_fmt
at /rustc/27d6200a70601f6fcf419bf2f9e37989f3624ca4/library/core/src/intrinsics/mod.rs:3196:9
3: core::panicking::panic_nounwind
at /rustc/27d6200a70601f6fcf419bf2f9e37989f3624ca4/library/core/src/panicking.rs:226:5
4: core::slice::raw::from_raw_parts::precondition_check
at /Users/swoorup.joshi/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ub_checks.rs:68:21
5: core::slice::raw::from_raw_parts
at /Users/swoorup.joshi/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ub_checks.rs:75:17
6: roc_serialize::bytes::deserialize_slice
at /Users/swoorup.joshi/.cargo/git/checkouts/roc-5d067ed4e211e472/b552466/crates/compiler/serialize/src/bytes.rs:35:26
7: roc_can::abilities::serialize::deserialize_solved_implementations
at /Users/swoorup.joshi/.cargo/git/checkouts/roc-5d067ed4e211e472/b552466/crates/compiler/can/src/abilities.rs:1197:35
8: roc_can::module::TypeState::deserialize
at /Users/swoorup.joshi/.cargo/git/checkouts/roc-5d067ed4e211e472/b552466/crates/compiler/can/src/module.rs:1212:13
9: roc_load::deserialize_help
at /Users/swoorup.joshi/.cargo/git/checkouts/roc-5d067ed4e211e472/b552466/crates/compiler/load/src/lib.rs:240:28
10: roc_load::read_cached_types
at /Users/swoorup.joshi/.cargo/git/checkouts/roc-5d067ed4e211e472/b552466/crates/compiler/load/src/lib.rs:265:39
11: roc_load::load
at /Users/swoorup.joshi/.cargo/git/checkouts/roc-5d067ed4e211e472/b552466/crates/compiler/load/src/lib.rs:37:24
12: roc_load::load_and_monomorphize_from_str
at /Users/swoorup.joshi/.cargo/git/checkouts/roc-5d067ed4e211e472/b552466/crates/compiler/load/src/lib.rs:117:11
13: roc_repl_eval::gen::compile_to_mono
at /Users/swoorup.joshi/.cargo/git/checkouts/roc-5d067ed4e211e472/b552466/crates/repl_eval/src/gen.rs:64:18
14: roc_repl_ui::repl_state::ReplState::step
at /Users/swoorup.joshi/.cargo/git/checkouts/roc-5d067ed4e211e472/b552466/crates/repl_ui/src/repl_state.rs:260:36
15: test_roc_playground::repl::entrypoint_from_wasmtime::{{closure}}::{{closure}}
at ./src/repl.rs:201:9
16: std::thread::local::LocalKey<T>::try_with
at /Users/swoorup.joshi/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/thread/local.rs:315:12
17: std::thread::local::LocalKey<T>::with
at /Users/swoorup.joshi/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/thread/local.rs:279:15
18: test_roc_playground::repl::entrypoint_from_wasmtime::{{closure}}
at ./src/repl.rs:199:18
19: test_roc_playground::stdin_runner::stdin_to_entrypoint::{{closure}}
at ./src/stdin_runner.rs:60:62
20: test_roc_playground::main::{{closure}}
at ./src/main.rs:44:65
21: <core::pin::Pin<P> as core::future::future::Future>::poll
at /Users/swoorup.joshi/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/future/future.rs:124:9
22: tokio::runtime::park::CachedParkThread::block_on::{{closure}}
at /Users/swoorup.joshi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.45.0/src/runtime/park.rs:284:60
23: tokio::task::coop::with_budget
at /Users/swoorup.joshi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.45.0/src/task/coop/mod.rs:167:5
24: tokio::task::coop::budget
at /Users/swoorup.joshi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.45.0/src/task/coop/mod.rs:133:5
25: tokio::runtime::park::CachedParkThread::block_on
at /Users/swoorup.joshi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.45.0/src/runtime/park.rs:284:31
26: tokio::runtime::context::blocking::BlockingRegionGuard::block_on
at /Users/swoorup.joshi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.45.0/src/runtime/context/blocking.rs:66:9
27: tokio::runtime::scheduler::multi_thread::MultiThread::block_on::{{closure}}
at /Users/swoorup.joshi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.45.0/src/runtime/scheduler/multi_thread/mod.rs:87:13
28: tokio::runtime::context::runtime::enter_runtime
at /Users/swoorup.joshi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.45.0/src/runtime/context/runtime.rs:65:16
29: tokio::runtime::scheduler::multi_thread::MultiThread::block_on
at /Users/swoorup.joshi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.45.0/src/runtime/scheduler/multi_thread/mod.rs:86:9
30: tokio::runtime::runtime::Runtime::block_on_inner
at /Users/swoorup.joshi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.45.0/src/runtime/runtime.rs:358:45
31: tokio::runtime::runtime::Runtime::block_on
at /Users/swoorup.joshi/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/tokio-1.45.0/src/runtime/runtime.rs:328:13
32: test_roc_playground::main
at ./src/main.rs:40:5
33: core::ops::function::FnOnce::call_once
at /Users/swoorup.joshi/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
thread caused non-unwinding panic. aborting.
fish: Job 1, 'echo 1 + 1 | RUST_BACKTRACE=1 c…' terminated by signal SIGABRT (Abort)
Any ideas?
My only guess is that wasm has a different alignment to CPUs. As such, this fails. I would try just running without the undefined behaviour check (might just need to run in release build).
But otherwise debugging probably means checking pointers and alignment.
I wonder if wasmtime aligns differently from browsers
Goodpoint, will try running in release. Trying to grok much information as I can, since i am new to using wasm in general xD
Damn that worked lol. Feels cool.
test-roc-playground on main [!] is 📦 v0.1.0 via 🦀 v1.88.0-nightly via ❄️ impure (devenv-shell-env) took 4s
❯ ./target/release/test-roc-playground --stdin
>
Enter an expression to evaluate, or a definition (like x = 1) to use later.
- ctrl-v + ctrl-j makes a newline
- :q quits
- :help shows this text again
> 1 + 1
2<span class='color-green'> : </span>Num *
>
Last updated: Jul 26 2025 at 12:14 UTC