Internal JavaScript bindings¶
Dream runs in the browser and Node as WebAssembly. Talking to JavaScript uses three pieces:
| Piece | What it's for | Docs |
|---|---|---|
extern fun |
a typed, fixed-signature function that lives in JS (Math.max, your glue code) |
this page |
js |
a dynamic handle to any live JS value, used with native syntax | The js type |
| function values | passing functions across the boundary in either direction | Callbacks |
@c(...) |
binds an extern to a C library in native executables and library outputs | C Interop |
Js.* is WASM/JS-host only: a native build aborts if guest code tries to call into JavaScript.
This page covers extern functions.
Declaring an extern function¶
An extern fun has a signature but no body. Call it like any other function:
By default it binds to a JS global of the same name (alert). Three things cooperate:
extern fundeclares the signature on the Dream side.@js("module", "field")optionally remaps which JS object and property it binds to (JS-only).- Dream stdlib hosts that exist on native and WASM use
@runtime("name")instead of@js. - The runtime marshals values, binds externs to JS globals, and bridges Promises for
extern async fun.
Restrictions
Extern functions cannot have a body, cannot be generic, and cannot be combined with public.
Remapping the import name¶
@js(module, name) controls which JS object and property the extern binds to:
@js(
"dom",
"setText"
) // binds to importObject["dom"]["setText"]
internal extern fun set_text(value: string): void;
@js(
"console"
) // module only -> field defaults to the function name
internal extern fun log(msg: string): void;
Dream runtime hosts (@runtime)¶
Stdlib functions implemented by the Dream runtime (files, process, crypto, …) bind with @runtime("name"). That is not JavaScript-only: WASM imports Dream.name and native dream run calls the C symbol name.
@runtime cannot be combined with @js, @c, or @intrinsic on the same extern. @native / @node / @web still restrict which targets may mention the API (@native @node @runtime("processRun")).
Running it from JavaScript¶
Compile a .dream file, then load the .wasm with the Dream runtime:
Optionally emit a smaller sibling *.web.runtime.js / *.node.runtime.js (only the host pieces that program needs) with --runtime plus one or both host flags. Without these flags, compile does not write a selective runtime — use the full shared host instead.
dream --runtime --web hello.dream # hello.web.runtime.js
dream --runtime --node hello.dream # hello.node.runtime.js
dream --runtime --web --node hello.dream # both in one compile
Release builds (--release / -O) also minify the selective runtime and emit
pre-compressed siblings — hello.wasm.gz / .br and hello.web.runtime.js.gz / .br.
Browsers never compress on their own; serve them with gzip_static / brotli_static
(nginx), a CDN, or any static server that negotiates encoding (e.g. npx serve).
Auto-binding to JS globals¶
For every extern you do not supply explicitly, the runtime resolves it against the JS global scope:
- The default
envmodule maps to a bare global —internal extern fun alert(...)binds toalert. @js("module", "name")maps to a property —@js("console", "log")binds toconsole.log,@js("Math", "max")toMath.max.
Built-in browser and Node APIs therefore need no glue. Pass imports only for your own functions, keyed by the Dream function name:
If an extern matches no global and you don't provide it, the runtime installs a stub that throws only if actually called — so the module still loads. For full control, use load(source, options) instead of run; it returns the instance without calling main.
Value marshaling¶
Arguments and returns convert between Dream and JavaScript:
| Dream type | As argument | As return value |
|---|---|---|
int, float, double |
number |
number |
bool |
boolean |
boolean |
string |
string |
return a string |
T[] |
Array of marshaled elements |
(pointer) |
object, classes, List<T> |
opaque pointer (number) |
(pointer) |
For reference types, read the underlying data with the instance helpers:
mod.readString(ptr); // UTF-16 string
mod.readArray(ptr, "int"); // -> number[]
mod.readList(ptr, "string"); // List<string> -> string[]
mod.readStruct(ptr, [ // class by field schema (declaration order)
{ name: "x", type: "int" },
{ name: "y", type: "int" },
]);
To hand a string back to Dream, call mod.writeString(str) (the runtime also does this for you when a return value is a string).
Beyond fixed signatures¶
extern fun is ideal for known signatures. For open-ended JS values (a DOM node, a fetch Response, a RegExp) you want to read and call natively, use the dynamic js type:
Functions cross the boundary in both directions too — see Callbacks.
Built on interop¶
- Regex —
Regexinsystem.text(not a JSRegExp).
Host feature matrix¶
Most stdlib packages behave identically on native, browser, and Node hosts. Check each retained package's platform notes for file access and process support. Unicode helpers and console input work on native and JS hosts; browser console input uses a prompt because there is no stdin.