# rwat

[![Crates.io](https://img.shields.io/crates/v/rwat.svg)](https://crates.io/crates/rwat)

`rwat` means `reloc wat`: it parses annotated wat into a wasm binary while automatically emitting `linking` and `reloc.CODE` custom sections.

The main entry point is:

```rust
pub fn parse_rwat(wat: &str) -> wast::parser::Result<Vec<u8>>
```

## Annotations

`rwat` extends plain wat with three annotations:

- `(@rwat)`: required on the module header to enable `rwat` parsing.
- `(@sym)` or `(@sym (name "..."))`: declares a symbol for a function/table import or function/table definition.
- `(@reloc)`: marks the immediately preceding relocatable instruction as requiring a relocation entry. This includes `call`, `return_call`, `call_indirect`, `return_call_indirect`, and table instructions such as `table.get`, `table.copy`, and `table.size`.

For function or table definitions, if you write `(@sym)` without an explicit name, `rwat` uses the item ID as the symbol name when available.

Currently, `rwat` only emits two WebAssembly relocation types: `R_WASM_FUNCTION_INDEX_LEB` for function indices and `R_WASM_TABLE_NUMBER_LEB` for table indices.

## How It Works

At a high level, `rwat` uses `wast` for text parsing and normal wasm emission, `wasmparser` for reading back section/operator offsets, and `wasm-encoder` for assembling the final output:

```text
annotated wat
    |
    | 1. scan custom annotations
    |    - (@rwat)
    |    - (@sym)
    |    - (@reloc)
    v
custom annotation metadata
    +
    | 2. parse the same source as normal wat with `wast`
    v
wast AST / resolved module
    |
    | 3. `wast` encodes the module
    v
plain wasm bytes
    |
    | 4. `wasmparser` reads raw sections
    |    and decodes the code section
    v
code section + relocatable-immediate offsets
    |
    | 5. patch function/table immediates
    |    to fixed-width 5-byte LEBs when `(@reloc)` is present
    |    so relocation offsets stay stable
    v
patched code section
    |
    | 6. emit `linking` symbol table
    |    and `reloc.CODE` entries
    v
`wasm-encoder` final assembly
    |
    v
final wasm object bytes
```

## Why Not Use `wast` Directly

`rwat` still uses `wast` for standard wat parsing and encoding, but it cannot rely on `wast` alone for this extension:

- `wast` does not understand `(@sym)` and `(@reloc)` as first-class syntax, because these annotations are custom to `rwat` rather than part of the official wat grammar.
- The parser/encoder integration points needed to preserve annotation metadata through encoding are mostly private APIs, so an external crate cannot directly plug this behavior into `wast`.
- getting such changes accepted upstream in `wast` would be difficult,
- carrying a private `wast` fork would create ongoing maintenance cost.

## Example

The [examples/add](examples/add) directory builds two wat files separately, then links them with `wasm-ld`: `add.wat` defines the `add` symbol, and `main.wat` imports it, marks the call as relocatable, and defines `main(a, b)`.

```sh
cargo install rwat --locked
rwat examples/add/add.wat -o add.o
rwat examples/add/main.wat -o main.o
wasm-ld --no-entry --export=main main.o add.o -o main.wasm
# 42
wasmtime --invoke main main.wasm 20 22
```
