1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*!
The guest side of the larvae worm ABI.
A worm is a `wasm32` module that larvae loads and calls. wasm has no strings.
Thus all data crosses as an offset and a length into the linear memory of the
module. This crate owns that protocol, so a worm author does not write it:
```ignore
larvae_worm::frontend!(|source: &str, config: &str| -> anyhow::Result<String> {
luaux::compile_configured(source, Backend::Vide, &Config::parse(config)?)
});
```
The macro is not the only entry point. [`abi`] is public and documented. Thus
a worm with an unusual design can export the raw functions itself, without a
copy of the macro.
# The ABI
A worm exports `memory`, plus:
| export | signature |
|---|---|
| `larvae_alloc` | `(len: u32) -> ptr` |
| `larvae_dealloc` | `(ptr, len: u32)` |
| `larvae_transform` | `(src_ptr, src_len, cfg_ptr, cfg_len) -> *header` |
| `larvae_init` | `(cfg_ptr, cfg_len, rules_ptr, rules_len)` |
| `larvae_visit` | `(rule, epoch, node_id)` |
`larvae_transform` returns a pointer to a three word header,
`[out_ptr, out_len, ok]`. `ok` is 1 when the bytes are output and 0 when they
are an error message. The header lives in a static, so the host does not free
it. The host calls `larvae_dealloc(out_ptr, out_len)` when it has read the
payload out.
*/
/// The ABI revision this crate implements. It must match `api` in `worm.toml`.
pub const ABI_VERSION: u32 = 1;
pub use Node;
/**
Define a front-end worm. It takes source text and returns transformed source.
The closure takes the contents of the file and the `[config.<name>]` table of
the worm, serialized again as TOML. It returns the transformed source. Each
error type that implements [`Display`](core::fmt::Display) works, so
`anyhow::Result<String>` is valid.
```ignore
larvae_worm::frontend!(|source: &str, _config: &str| -> Result<String, String> {
Ok(source.replace("<>", "{}"))
});
```
The macro expands to the three exports in the module docs. Use it once per worm.
*/
/**
Define the rule half of a worm.
Each rule is a name and a handler. larvae calls a rule only on the nodes that
match the `filter` you declared in `worm.toml`. Thus undeclared kinds do not
cross the boundary.
```ignore
larvae_worm::rules! {
"strip_debug" => |node: larvae_worm::Node| {
if node.kind() == "CallExpr" && node.text().starts_with("dprint") {
node.remove();
}
},
}
```
Combine this macro with [`frontend!`](crate::frontend) when a worm holds both roles.
*/