Tools
JavaScript
--target js compiles a program to one JavaScript file that runs with Node.js 18 or newer.
The file contains the program and a small runtime written in JavaScript, and needs nothing else installed.
burnc app.bn --target js # writes app.js
node app.js one two # arguments reach args()
burnc app.bn --target js -o dist/app.js
burn dump --js app.bn # print the JavaScript instead of writing itThe file starts with #!/usr/bin/env node, so after chmod +x app.js it also runs as ./app.js. In a project, set
target = "js" in burn.toml (or create one with burn init <name> --target js) and burn build writes
build/<name>.js.
What carries over
The JavaScript build uses the same type checker as the other backends and keeps their behaviour:
- every runtime check: index bounds, integer overflow, division by zero, null values,
asconversions to sized numbers, with the same messages and source locations as bvm; - strings, arrays, maps, records, structs, interfaces, enums with data,
match, closures and generics; - the standard library: printing and input, files (
readFile,writeFile,std/fs), processes (std/process, through Node'schild_process), HTTP (std/http, throughcurl), JSON, dates and times, math and random numbers; destroyand the "this object was destroyed" checks.
Memory is managed by the JavaScript engine instead of reference counting, so gc() does nothing and
BURN_MAX_HEAP_MB does not apply.
What differs
| bvm and native | JavaScript | |
|---|---|---|
int |
exact 64-bit integers | JavaScript numbers: exact up to 2^53; larger values are rounded, though overflow past 64 bits is still caught |
uint64 |
exact | exact for bit operations and wrapping, rounded when printed above 2^53 |
async fun |
runs in its own thread | runs to the end when it is called; await returns its result |
sleep(ms) |
sleeps | blocks the thread with Atomics.wait |
| speed | bvm optimizes while running; native code is fastest | Node's JIT; between bvm and native for most programs |
var big = 9007199254740993
print(big) // 9007199254740993 on bvm, 9007199254740992 in JavaScriptWhat the JavaScript backend cannot do
These features need bvm, so the compiler rejects them for --target js with an explanation:
- importing bytecode libraries (
import "geometry.bvmc"); @Nativefunctions, which a host program provides;- mixins (
@Inject,@Overwrite,@Redirect), which rewrite bvm bytecode.
How the code looks
Each Burn function becomes a JavaScript function, locals become parameters and let variables, records become
arrays tagged with their type, and checked operations call small helpers from the runtime. This function:
fun pick(xs: [int], i: int): int {
if (i + 1 > len(xs)) {
return 0
}
return xs[i]
}becomes:
function f1(l0, l1) {
if (($ov(l1 + 1, 1) > l0.length)) {
return 0;
}
return $idx(l0, l1, 2);
}$ov checks for integer overflow and $idx checks the index; the last argument of each is the source location
their error message points at.
The runtime is lib/js/prelude.js in the Burn repository; the compiler embeds it (compiler/src/js/js.bn). See
how the compiler works.