libruntime-codegen provides runtime code templates for bundled Oak modules, including the module system implementation for both Oak native and JavaScript targets.
runtimeCodegen := import('runtime-codegen')
{ OakNativeRuntime: OakNativeRuntime, OakJSRuntime: OakJSRuntime } := import('runtime-codegen')
{ OakNativeRuntime: OakNativeRuntime, OakJSRuntime: OakJSRuntime
encodeWATString: encodeWATString, renderWasmBundle: renderWasmBundle } := import('runtime-codegen')
Oak source code for the module system runtime (native Oak target).
Provides:
__Oak_Modules- Module registry__Oak_Import_Aliases- Import alias mapping__oak_modularize(name, module)- Register module__oak_module_import(name)- Load module
{ OakNativeRuntime: OakNativeRuntime } := import('runtime-codegen')
// Used in bundled Oak code
bundleSource := OakNativeRuntime + '\n' + moduleCode
JavaScript code for the module system runtime (web target).
Provides:
- Module system (same functions as Oak runtime)
- Language primitives:
__oak_eq(a, b)- Deep equality comparison__oak_resolve_trampoline(fn, ...args)- Tail call optimization__oak_trampoline(fn, ...args)- Trampoline wrapper
- Helper functions for Oak semantics in JavaScript
{ OakJSRuntime: OakJSRuntime } := import('runtime-codegen')
// Used in web builds
jsBundleSource := OakJSRuntime + '\n' + transpiled JSCode
__Oak_Modules := {} // Stores all modules
__Oak_Import_Aliases := ? // Import path aliases
fn __oak_modularize(name, module) {
__Oak_Modules.(name) := module
}
// Usage in bundle:
__oak_modularize('utils.oak', fn { /* module code */ })
fn __oak_module_import(name) if ___runtime_lib?(name) {
true -> import(name) // Built-in library
_ -> if type(module := __Oak_Modules.(name)) {
:null -> if module := __Oak_Modules.(__Oak_Import_Aliases.(name)) {
? -> import(name)
_ -> {
mod := module()
__Oak_Modules.(name) := mod // Cache
mod
}
}
:function -> {
m := module()
__Oak_Modules.(name) := m // Cache
m
}
_ -> module // Already cached
}
}
const __Oak_Modules = {};
let __Oak_Import_Aliases;
function __oak_modularize(name, fn) {
__Oak_Modules[name] = fn;
}
function __oak_module_import(name) {
if (typeof __Oak_Modules[name] === 'object') {
return __Oak_Modules[name]; // Cached
}
const module = __Oak_Modules[name] ||
__Oak_Modules[__Oak_Import_Aliases[name]];
if (module) {
__Oak_Modules[name] = {}; // Break circular imports
return __Oak_Modules[name] = module();
} else {
throw new Error(`Could not import Oak module "${name}" at runtime`);
}
}function __oak_eq(a, b) {
// Handle Oak's empty value (_)
if (a === __Oak_Empty || b === __Oak_Empty) return true;
// Null handling
if (a == null && b == null) return true;
if (a == null || b == null) return false;
// Primitives
if (typeof a === 'boolean' || typeof a === 'number' ||
typeof a === 'symbol' || typeof a === 'function') {
return a === b;
}
// Strings (Oak strings need special handling)
a = __as_oak_string(a);
b = __as_oak_string(b);
if (typeof a !== typeof b) return false;
if (__is_oak_string(a) && __is_oak_string(b)) {
return a.valueOf() === b.valueOf();
}
// Collections (recursive comparison)
if (len(a) !== len(b)) return false;
for (const key of keys(a)) {
if (!__oak_eq(a[key], b[key])) return false;
}
return true;
}// Resolve trampoline to final value
function __oak_resolve_trampoline(fn, ...args) {
let result = fn(...args);
while (typeof result === 'object' &&
typeof result[Symbol.iterator] === 'function') {
result = result[Symbol.iterator]().next().value(...args);
}
return result;
}
// Create trampoline for tail recursion
function __oak_trampoline(fn, ...args) {
return function*() {
yield function() {
return fn(...args);
};
};
}{ OakNativeRuntime: OakNativeRuntime } := import('runtime-codegen')
bundleCode := OakNativeRuntime + '
__oak_modularize("main.oak", fn {
println("Hello from main!")
})
__oak_modularize("utils.oak", fn {
{ add: fn(a, b) { a + b } }
})
__oak_module_import("main.oak")
'
writeFile('bundle.oak', bundleCode)
{ OakJSRuntime: OakJSRuntime } := import('runtime-codegen')
jsBundleCode := OakJSRuntime + '
__oak_modularize("app", function() {
console.log("App loaded");
return { version: "1.0" };
});
__oak_module_import("app");
'
writeFile('bundle.js', jsBundleCode)
{ OakNativeRuntime: OakNativeRuntime, OakJSRuntime: OakJSRuntime } := import('runtime-codegen')
fn generateBundle(modules, target) {
runtime := if target {
:web -> OakJSRuntime
:native -> OakNativeRuntime
_ -> OakNativeRuntime
}
moduleCode := modules |> map(fn([name, code]) {
'__oak_modularize("' + name + '", function() {\n' +
code + '\n});'
}) |> join('\n\n')
entryCall := '__oak_module_import("' + modules.0.0 + '");'
runtime + '\n\n' + moduleCode + '\n\n' + entryCall
}
{ renderWasmBundle: renderWasmBundle } := import('runtime-codegen')
buildRender := import('build-render')
// renderWasmBundle produces WAT (WebAssembly Text) source embedding the Oak
// bundle in linear memory. Requires `wat2wasm` to produce binary .wasm.
fn generateWasmBundle(bundleNode, vfsFiles, encodeJSON, oakNativeRuntime, formatIdent, abort) {
renderOak := fn(node) buildRender.renderOakBundle(
node, vfsFiles, encodeJSON, oakNativeRuntime, formatIdent, abort
)
watSource := renderWasmBundle(bundleNode, renderOak)
writeFile('program.wat', watSource)
// Then convert: wat2wasm program.wat -o program.wasm
}
{ encodeWATString: encodeWATString } := import('runtime-codegen')
text := 'Hello, 世界!'
encoded := encodeWATString(text)
// encoded.byteLen => UTF-8 byte count (useful for sizing WASM memory)
// encoded.escaped => hex-escaped string for WAT data element
watData := '(data (i32.const 1024) "' << encoded.escaped << '")'
memoryPages := int((1024 + encoded.byteLen) / 65536) + 1
// JavaScript runtime breaks circular imports
__Oak_Modules[name] = {}; // Placeholder
return __Oak_Modules[name] = module(); // Replace with actualExample:
// a.js imports b.js, b.js imports a.js
__oak_modularize("a", function() {
const b = __oak_module_import("b"); // Gets placeholder {}
return { name: "A", b: b };
});
__oak_modularize("b", function() {
const a = __oak_module_import("a"); // Placeholder prevents infinite loop
return { name: "B", a: a };
});Both runtimes cache module results:
// First call: executes module function
utils := __oak_module_import('utils')
// Second call: returns cached result
utils2 := __oak_module_import('utils')
// utils === utils2 (same object)
Renders Oak AST nodes to WebAssembly Text (WAT) format. The resulting WAT module embeds the bundled Oak source code in linear memory and exports functions for a host Oak interpreter to execute.
Parameters:
bundleNode— Root AST node of the bundled programrenderOakBundle— Callbackfn(node)that renders an AST node to Oak source text
Returns: A WAT source string ready for conversion to binary WASM via wat2wasm.
Exports from the generated WAT module:
memory— Linear memory (sized to fit the bundle source)__oak_bundle_ptr(global) — Memory offset of the embedded Oak source__oak_bundle_len(global) — Byte length of the embedded Oak sourcerun()— Callsoak.runwith the bundle pointer and lengthbundle_ptr()— Returns__oak_bundle_ptrbundle_len()— Returns__oak_bundle_lenmain()— Entry point; delegates torun()
Imports required from host:
oak.run(ptr: i32, len: i32) → i32— Executes the Oak source at the given memory location
{ renderWasmBundle: renderWasmBundle } := import('runtime-codegen')
{ renderOakBundle: renderOakBundle } := import('build-render')
watSource := renderWasmBundle(bundleNode, renderOakBundle)
writeFile('program.wat', watSource)
Encodes an Oak string as a WAT data segment value. Returns the UTF-8 byte sequence as a hex-escaped string safe for use inside a WAT (data ...) element, along with the byte length.
Parameters:
s— Oak string to encode
Returns: An object { escaped: string, byteLen: int } where:
escaped— The string with non-printable and non-ASCII characters hex-escaped (\xx)byteLen— The total number of UTF-8 encoded bytes (used to size WASM memory)
{ encodeWATString: encodeWATString } := import('runtime-codegen')
encoded := encodeWATString('Hello, 世界')
// => { escaped: 'Hello, \e4\b8\96\e7\95\8c', byteLen: 13 }
wat := '(data (i32.const 1024) "' << encoded.escaped << '")'
Built-in function (Oak native only) that checks if a name is a runtime library.
___runtime_lib?('std') // => true
___runtime_lib?('http') // => true
___runtime_lib?('myapp') // => false
- Module functions are called only once
- Results are cached in
__Oak_Modules - Circular imports return placeholder object
- JavaScript runtime includes polyfills for Oak semantics
- Trampoline optimization prevents stack overflow
- Deep equality handles Oak's value semantics
- Circular imports may have incomplete exports
- Dynamic imports not supported
- Module names must be string literals
- No lazy loading
- No module hot-reloading
- Trampoline has overhead compared to native tail calls
- Bundling: Embed in bundled code
- Code generation: Template for module system
- Web deployment: JavaScript runtime for browsers
- Testing: Standalone module execution
- No sandboxing of module code
- All modules share global scope
- No module permission system
- Errors in one module can crash all
- build.md - Build system
- bundle-ast.md - AST bundling
- pack.md - Create executables
- Oak module system documentation