|
| 1 | +# WebAssembly |
| 2 | + |
| 3 | +Perry can compile TypeScript to WebAssembly using `--target wasm`. |
| 4 | + |
| 5 | +## Building |
| 6 | + |
| 7 | +```bash |
| 8 | +# Self-contained HTML (default) |
| 9 | +perry app.ts -o app --target wasm |
| 10 | +open app.html |
| 11 | + |
| 12 | +# Raw .wasm binary |
| 13 | +perry app.ts -o app.wasm --target wasm |
| 14 | +``` |
| 15 | + |
| 16 | +The default output is a single `.html` file containing a base64-embedded WASM binary and a JavaScript runtime bridge. If the output path ends with `.wasm`, a raw WASM binary is produced instead. |
| 17 | + |
| 18 | +## How It Works |
| 19 | + |
| 20 | +The `perry-codegen-wasm` crate compiles HIR directly to WASM bytecode using `wasm-encoder`. Unlike `--target web` (which emits JavaScript), this target produces real WebAssembly with a thin JS bridge for host APIs like `console.log` and string operations. |
| 21 | + |
| 22 | +The NaN-boxing scheme matches the native perry-runtime — f64 values with STRING_TAG/POINTER_TAG — so the same value representation is used across native and WASM targets. |
| 23 | + |
| 24 | +## Supported Features |
| 25 | + |
| 26 | +- **Functions**: definitions, calls, parameters, return values |
| 27 | +- **Control flow**: `if`/`else`, `while`, `for`, `switch`, `break`, `continue`, `try`/`catch`/`finally` |
| 28 | +- **Data types**: numbers (f64), strings, booleans, `undefined`, `null` |
| 29 | +- **Operators**: arithmetic, comparison, logical, unary, update (`++`/`--`) |
| 30 | +- **String operations**: literals, concatenation, `charAt`, `substring`, `indexOf`, `slice`, `toLowerCase`, `toUpperCase`, `trim`, `includes`, `startsWith`, `endsWith`, `replace`, `split`, `.length` |
| 31 | +- **Math**: `Math.floor`, `Math.ceil`, `Math.round`, `Math.abs`, `Math.sqrt`, `Math.pow`, `Math.min`, `Math.max`, `Math.log`, `Math.random` |
| 32 | +- **Console**: `console.log()`, `console.warn()`, `console.error()` |
| 33 | +- **Type operations**: `typeof`, `parseInt`, `parseFloat` |
| 34 | +- **Other**: template literals, conditional expressions, `Date.now()` |
| 35 | + |
| 36 | +## JavaScript Runtime Bridge |
| 37 | + |
| 38 | +The WASM binary imports ~25 JavaScript functions for host interop: |
| 39 | + |
| 40 | +- **Strings**: creation, concatenation, comparison, method dispatch |
| 41 | +- **Console**: output formatting with NaN-boxed value conversion |
| 42 | +- **Math**: delegation to `Math.*` built-ins |
| 43 | +- **Memory**: access via `WebAssembly.Memory` buffer |
| 44 | + |
| 45 | +Strings are managed via a global string table in JavaScript, with IDs passed as NaN-boxed values to and from WASM. |
| 46 | + |
| 47 | +## Limitations |
| 48 | + |
| 49 | +The WASM target is newer than native and web targets. Current limitations: |
| 50 | + |
| 51 | +- No object or array support (in progress) |
| 52 | +- No closures |
| 53 | +- No classes or `instanceof` |
| 54 | +- No async/await or Promises |
| 55 | +- No UI widgets (`perry/ui` is not available) |
| 56 | +- Switch statements use cascading if/else (no WASM table jumps) |
| 57 | + |
| 58 | +## Minification |
| 59 | + |
| 60 | +Use `--minify` to minify the JavaScript runtime bridge in the HTML output: |
| 61 | + |
| 62 | +```bash |
| 63 | +perry app.ts -o app --target wasm --minify |
| 64 | +``` |
| 65 | + |
| 66 | +## Example |
| 67 | + |
| 68 | +```typescript |
| 69 | +function fibonacci(n: number): number { |
| 70 | + if (n <= 1) return n; |
| 71 | + return fibonacci(n - 1) + fibonacci(n - 2); |
| 72 | +} |
| 73 | + |
| 74 | +console.log(fibonacci(10)); // 55 |
| 75 | +``` |
| 76 | + |
| 77 | +```bash |
| 78 | +perry fib.ts -o fib --target wasm |
| 79 | +# Produces fib.html — open in any browser |
| 80 | +``` |
| 81 | + |
| 82 | +## Next Steps |
| 83 | + |
| 84 | +- [Web](web.md) — JavaScript target (full UI support) |
| 85 | +- [Platform Overview](overview.md) — All platforms |
0 commit comments