WebAssembly Integration Guide
AILANG can run entirely in the browser using WebAssembly, enabling interactive demonstrations and online playgrounds without requiring server-side execution.
All AILANG browser demos run on WebAssembly — try them live:
- DocParse — Parse DOCX, PPTX, XLSX, PDF entirely in-browser
- Document Extractor — AI-powered extraction using WASM modules
- All 9 Demos — Full demo gallery
Overview
The AILANG WebAssembly build provides:
- Full Language Support: Complete AILANG interpreter compiled to WASM
- Standard Library Included: All 20 stdlib modules (
std/list,std/json, etc.) embedded and auto-loaded - Client-Side Execution: No server needed after initial load
- Small Bundle Size: ~33MB uncompressed (~7MB with gzip)
- React Integration: Ready-made component for easy integration
- Offline Capable: Works offline after first load
Quick Start
Option 1: From Release (Recommended)
Download the pre-built WASM bundle from the latest release. All three files are version-matched and built from the same commit:
# Download and extract — includes ailang.wasm, wasm_exec.js, ailang-repl.js
curl -L https://github.com/sunholo-data/ailang/releases/latest/download/ailang-wasm.tar.gz | tar -xz
The archive contains:
| File | Size | Description |
|---|---|---|
ailang.wasm | ~33MB | Compiled WASM binary with embedded stdlib |
wasm_exec.js | ~17KB | Go WASM runtime (version-matched to build toolchain) |
ailang-repl.js | ~5KB | JavaScript wrapper class (AilangREPL) |
Option 2: Build from Source
cd ailang
make build-wasm
# Copy wasm_exec.js from your Go installation
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
This produces bin/ailang.wasm. You'll also need ailang-repl.js from the web/ directory.
Integration Options
Option A: Docusaurus (Recommended)
- Copy assets:
cp ailang.wasm docs/static/wasm/
cp wasm_exec.js docs/static/wasm/
cp ailang-repl.js docs/src/components/
cp web/AilangRepl.jsx docs/src/components/
- Add to
docusaurus.config.js:
module.exports = {
scripts: [
{
src: '/wasm/wasm_exec.js',
async: false,
},
],
// ... rest of config
};
- Use in MDX:
---
title: Try AILANG
---
import AilangRepl from '@site/src/components/AilangRepl';
<AilangRepl />
Option B: Vanilla HTML
<!DOCTYPE html>
<html>
<head>
<title>AILANG REPL</title>
<script src="wasm_exec.js"></script>
<script src="ailang-repl.js"></script>
</head>
<body>
<div id="repl-container"></div>
<script>
const repl = new AilangREPL();
repl.init('/path/to/ailang.wasm').then(() => {
console.log('AILANG ready!');
// Evaluate expressions
const result = repl.eval('1 + 2');
console.log(result); // "3 :: Int"
});
</script>
</body>
</html>
Option C: React (Custom)
import { useEffect, useState } from 'react';
import AilangREPL from './ailang-repl';
export default function MyReplComponent() {
const [repl, setRepl] = useState(null);
const [result, setResult] = useState('');
useEffect(() => {
const replInstance = new AilangREPL();
replInstance.init('/wasm/ailang.wasm').then(() => {
setRepl(replInstance);
});
}, []);
const handleEval = (input) => {
if (repl) {
const output = repl.eval(input);
setResult(output);
}
};
return (
<div>
<input onKeyDown={(e) => {
if (e.key === 'Enter') handleEval(e.target.value);
}} />
<pre>{result}</pre>
</div>
);
}
JavaScript API
AilangREPL Class
const repl = new AilangREPL();
Methods
init(wasmPath)
Initialize the WASM module.
await repl.init('/wasm/ailang.wasm');
Parameters:
wasmPath(string): Path toailang.wasmfile
Returns: Promise that resolves when REPL is ready
eval(input)
Evaluate an AILANG expression.
const result = repl.eval('1 + 2');
// Returns: "3 :: Int"
Parameters:
input(string): AILANG code to evaluate
Returns: Result string (includes value and type)
command(cmd)
Execute a REPL command.
const type = repl.command(':type \x. x');
// Returns: "\x. x :: a -> a"
Parameters:
cmd(string): REPL command (e.g.,:type,:help)
Returns: Command output string
reset()
Reset the REPL environment.
repl.reset();
Returns: Status message
onReady(callback)
Register callback for when REPL is ready.
repl.onReady(() => {
console.log('REPL initialized!');
});
getVersion()
Get version information.
const version = repl.getVersion();
// Returns: "v0.7.2" (or null if not ready)
Returns: Version string or null
getVersionInfo()
Get detailed version information.
const info = repl.getVersionInfo();
// Returns: { version: "v0.7.2", buildTime: "2026-02-06T...", platform: "js/wasm" }
Returns: Object with version, buildTime, platform fields, or null
needsContinuation(line)
Check if a line needs continuation (for multi-line input UIs).
repl.needsContinuation('let x = 5 in'); // true
repl.needsContinuation('1 + 2'); // false
Returns: boolean
Module Loading API (v0.7.1+)
The WASM REPL supports loading complete AILANG modules, enabling complex browser-based demos with multiple function definitions.
The REPL evaluates expressions line-by-line, so function definitions like let add = \x. \y. x + y don't persist in scope for subsequent calls. The Module Loading API solves this by compiling entire modules and storing their exports for later use.
loadModule(name, code)
Load an AILANG module into the registry.
const result = repl.loadModule('math', `
let add: Int -> Int -> Int = \\x. \\y. x + y
let mul: Int -> Int -> Int = \\x. \\y. x * y
`);
if (result.success) {
console.log('Exports:', result.exports);
// Exports: ["add", "mul"]
} else {
console.error('Error:', result.error);
}
Parameters:
name(string): Module name (e.g.,"math","invoice_processor")code(string): AILANG source code
Returns: Object with:
success(boolean): Whether loading succeededexports(string[]): List of exported function names (on success)error(string): Error message (on failure)
For functions with numeric operations, you must include explicit type annotations:
// ✅ Works
let add: Int -> Int -> Int = \\x. \\y. x + y
// ❌ Fails with "ambiguous type variable"
let add = \\x. \\y. x + y
Modules can use explicit exports or export all bindings:
Explicit exports (recommended for libraries):
// Only public_func is exported, private_func is hidden
repl.loadModule('mylib', `
module mylib
export pure func public_func(x: int) -> int = x * 2
pure func private_func(x: int) -> int = x * 3
`);
// result.exports: ["public_func"]
Implicit exports (for REPL-style code):
// All top-level bindings are exported
repl.loadModule('utils', `
let double: Int -> Int = \\x. x * 2
let triple: Int -> Int = \\x. x * 3
`);
// result.exports: ["double", "triple"]
listModules() (v0.7.1+)
List all loaded modules.
const modules = repl.listModules();
// Returns: ["math", "utils"]
Returns: Array of module names
importModule(moduleName) (v0.7.1+)
Import a module's exports into the REPL environment.
repl.importModule('math');
// Now you can use: repl.eval('add(2)(3)')
Parameters:
moduleName(string): Name of a loaded module
Returns: Import result message
call(moduleName, funcName, ...args)
Call a function from a loaded module. This is a convenience method that:
- Looks up the function from the module registry
- Converts JavaScript arguments to AILANG values
- Invokes the function directly (no eval)
// Load a module
repl.loadModule('math', `
let add: Int -> Int -> Int = \\x. \\y. x + y
let greet = \\name. "Hello, " <> name
`);
// Call functions
const sum = repl.call('math', 'add', 2, 3);
if (sum.success) {
console.log(sum.result); // "5 :: Int"
}
const greeting = repl.call('math', 'greet', 'World');
if (greeting.success) {
console.log(greeting.result); // "\"Hello, World\" :: String"
}
Parameters:
moduleName(string): Module containing the functionfuncName(string): Function to call...args(any): Arguments (converted to AILANG values)
Returns: Object with:
success(boolean): Whether the call succeededresult(string): Result with value and type (on success)error(string): Error message (on failure)
Supported argument types:
| JavaScript Type | AILANG Syntax |
|---|---|
number | 42 or 3.14 |
string | "text" |
boolean | true / false |
array | [1, 2, 3] |
Module Loading Example
Here's a complete example building an invoice processor demo:
<!DOCTYPE html>
<html>
<head>
<title>Invoice Processor Demo</title>
<script src="wasm_exec.js"></script>
<script src="ailang-repl.js"></script>
</head>
<body>
<script>
const repl = new AilangREPL();
repl.init('/wasm/ailang.wasm').then(() => {
// Load the invoice processor module
const result = repl.loadModule('invoice', `
-- Invoice processing functions
let calculateTotal: Int -> Float -> Float = \\quantity. \\unitPrice.
int_to_float(quantity) * unitPrice
let applyDiscount: Float -> Float -> Float = \\total. \\discountPercent.
total * (1.0 - discountPercent / 100.0)
let formatCurrency: Float -> String = \\amount.
"$" <> float_to_string(amount)
`);
if (!result.success) {
console.error('Failed to load module:', result.error);
return;
}
console.log('Loaded exports:', result.exports);
// ["calculateTotal", "applyDiscount", "formatCurrency"]
// Process an invoice
const subtotal = repl.call('invoice', 'calculateTotal', 5, 19.99);
if (subtotal.success) {
console.log('Subtotal:', subtotal.result);
// "99.95 :: Float"
}
const total = repl.call('invoice', 'applyDiscount', 99.95, 10);
if (total.success) {
console.log('After 10% discount:', total.result);
// "89.955 :: Float"
}
// Or use eval directly after importing
repl.importModule('invoice');
const formatted = repl.eval('formatCurrency(89.95)');
console.log('Formatted:', formatted);
// "\"$89.95\" :: String"
});
</script>
</body>
</html>
Effect Handlers API (v0.7.1+)
The WASM REPL supports configuring AILANG's algebraic effect system from JavaScript. This enables browser-based programs to use effects like AI, IO, Net, FS, and more by providing JavaScript callback implementations.
AILANG tracks side effects in the type system. A function declared as func ask(q: string) -> string ! {AI} requires the AI capability to run. In the CLI, capabilities are granted via --caps. In the browser, you provide JavaScript implementations for each effect operation.
Low-Level Globals
These functions are registered on the global window object when the WASM module loads:
| Global Function | Purpose |
|---|---|
ailangSetEffectHandler(name, ops) | Override any effect with JS callbacks |
ailangSetAIHandler(fn) | Convenience wrapper for AI effect |
ailangGrantCapability(name) | Grant a capability without a handler |
ailangEvalAsync(expr) | Evaluate with async effect support |
ailangCallAsync(mod, fn, ...args) | Call module function with async effects |
AilangREPL Wrapper Methods
The AilangREPL class wraps all low-level globals with error handling:
const repl = new AilangREPL();
await repl.init('/wasm/ailang.wasm');
// Register effect handlers
repl.setEffectHandler('IO', 'print', (msg) => { output.textContent += msg; });
repl.setAIHandler(async (input) => { /* call LLM API */ });
repl.grantCapability('IO');
// Async evaluation (returns Promise)
const result = await repl.evalAsync('perform IO.print("hello")');
const output = await repl.callAsync('demo', 'processData', 'input');
The wrapper methods (repl.setEffectHandler()) provide error handling and readiness checks. The low-level globals (ailangSetEffectHandler()) are called directly on window and skip these checks. For most use cases, prefer the wrapper methods.