1#![recursion_limit = "8192"]
2
3use wasmparser::for_each_operator;
16
17macro_rules! define_opcode {
18 ($(@$proposal:ident $op:ident $({ $($payload:tt)* })? => $visit:ident)*) => {
19 #[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)]
24 #[allow(missing_docs)]
25 pub enum OpCode {
26 $(
27 $op,
28 )*
29 }
30
31 impl OpCode {
32 pub fn from_operator<'a>(op: &wasmparser::Operator<'a>) -> Self {
33 match op {
34 $(
35 wasmparser::Operator::$op{..} => Self::$op,
36 )*
37 }
38 }
39 }
40 }
41}
42for_each_operator!(define_opcode);
43
44pub enum OperatorByProposal<'a> {
46 ControlFlow(proposals::ControlFlowOperator<'a>),
47 MVP(proposals::MVPOperator),
48 Exceptions(proposals::ExceptionsOperator),
49 TailCall(proposals::TailCallOperator),
50 ReferenceTypes(proposals::ReferenceTypesOperator),
51 SignExtension(proposals::SignExtensionOperator),
52 SaturatingFloatToInt(proposals::SaturatingFloatToIntOperator),
53 BulkMemory(proposals::BulkMemoryOperator),
54 Threads(proposals::ThreadsOperator),
55 SIMD(proposals::SIMDOperator),
56 RelaxedSIMD(proposals::RelaxedSIMDOperator),
57 FunctionReferences(proposals::FunctionReferencesOperator),
58 MemoryControl(proposals::MemoryControlOperator),
59 GC(proposals::GCOperator),
60}
61
62macro_rules! impl_op_by_proposal {
63 ($(@$proposal:ident $op:ident $({ $($field:ident : $field_ty:ty),* $(,)? })? => $visit:ident)*) => {
64 impl<'a> From<wasmparser::Operator<'a>> for OperatorByProposal<'a> {
65 fn from(op: wasmparser::Operator<'a>) -> Self {
66 match op {
67 $(
68 wasmparser::Operator::$op $({ $($field),* })* => paste::paste!{ proposals::[< make_op_by_proposal_ $op:snake >] ( $($($field),* )* ) },
69 )*
70 }
71 }
72 }
73 }
74}
75for_each_operator!(impl_op_by_proposal);
76
77impl<'a> From<OperatorByProposal<'a>> for wasmparser::Operator<'a> {
78 fn from(op: OperatorByProposal<'a>) -> Self {
79 match op {
80 OperatorByProposal::ControlFlow(op) => op.into(),
81 OperatorByProposal::MVP(op) => op.into(),
82 OperatorByProposal::Exceptions(op) => op.into(),
83 OperatorByProposal::TailCall(op) => op.into(),
84 OperatorByProposal::ReferenceTypes(op) => op.into(),
85 OperatorByProposal::SignExtension(op) => op.into(),
86 OperatorByProposal::SaturatingFloatToInt(op) => op.into(),
87 OperatorByProposal::BulkMemory(op) => op.into(),
88 OperatorByProposal::Threads(op) => op.into(),
89 OperatorByProposal::SIMD(op) => op.into(),
90 OperatorByProposal::RelaxedSIMD(op) => op.into(),
91 OperatorByProposal::FunctionReferences(op) => op.into(),
92 OperatorByProposal::MemoryControl(op) => op.into(),
93 OperatorByProposal::GC(op) => op.into(),
94 }
95 }
96}
97
98pub mod proposals {
99 use super::*;
100
101 macro_rules! filter_operators {
103 ($d:tt $macro_name:ident (@ $filter_token:tt $(, !$filter_op:tt)* $(,)?) | $called_macro:ident($($args:tt)*)) => {
104 macro_rules! $macro_name {
105 ((munch) { $d ($d filtered:tt)* }) => {
106 $called_macro!{$($args)* $d ($d filtered)*}
107 };
108 $(
109 ((munch) { $d ($d filtered:tt)* } @$d proposal:ident $filter_op $d ({ $d ($d payload:tt)* })? => $d visit:ident $d ($d others:tt)*) => {
110 $macro_name!{(munch) { $d ($d filtered)* } $d ($d others)*}
111 };
112 )*
113 ((munch) { $d ($d filtered:tt)* } @$filter_token $d op:ident $d ({ $d ($d payload:tt)* })? => $d visit:ident $d ($d others:tt)*) => {
114 $macro_name!{(munch) { $d ($d filtered)* @$filter_token $d op $d ({ $d ($payload)* })? => $d visit } $d ($d others)*}
115 };
116 ((munch) { $d ($d filtered:tt)* } @$d proposal:ident $d op:ident $d ({ $d ($d payload:tt)* })? => $d visit:ident $d ($d others:tt)*) => {
117 $macro_name!{(munch) { $d ($d filtered)* } $d ($d others)*}
118 };
119 ($d ($d others:tt)*) => {
120 $macro_name!{(munch) { } $d ($d others)*}
121 }
122 }
123 }
124 }
125
126 macro_rules! define_make_operator_fn {
127 ($enum_name:ident( $struct_name:ident :: $op:ident $({ $($field:ident : $field_ty:ty),* $(,)? })? )) => {
128 paste::paste!{
129 #[inline(always)]
130 pub(crate) fn [< make_op_by_proposal_ $op:snake >] <'a> ( $($($field : $field_ty),* )* ) -> OperatorByProposal<'a> {
131 OperatorByProposal::$enum_name(
132 $struct_name::$op {$($($field),* )*}
133 )
134 }
135 }
136 }
137 }
138
139 macro_rules! define_proposal_operator {
141 ($struct_name:ident, $enum_name:ident $(@$proposal:ident $op:ident $({ $($field:ident : $field_ty:ty),* $(,)? })? => $visit:ident)*) => {
142 #[derive(Clone, Debug)]
143 #[doc = concat!("A subset of WebAssembly operations given by the ", stringify!($enum_name), " proposal")]
144 pub enum $struct_name {
145 $(
146 $op $({ $($field : $field_ty,)* })*,
147 )*
148 }
149
150 impl $struct_name {
151 pub fn opcode(&self) -> OpCode {
152 match &self {
153 $(
154 Self::$op { .. } => OpCode::$op,
155 )*
156 }
157 }
158 }
159
160 impl<'a> From<$struct_name> for wasmparser::Operator<'a> {
161 fn from(op: $struct_name) -> Self {
162 match op {
163 $(
164 $struct_name::$op $({ $($field,)* })* => wasmparser::Operator::$op $({ $($field,)* })*,
165 )*
166 }
167 }
168 }
169
170 $(
171 define_make_operator_fn! { $enum_name ( $struct_name :: $op $({ $($field : $field_ty),* })* ) }
172 )*
173 }
174 }
175
176 filter_operators!($ filter_define_mvp(@mvp,
177 !End,
178 !Block,
179 !Loop,
180 !If,
181 !Else,
182 !Br,
183 !BrIf,
184 !BrTable,
185 !Return,
186 !Call,
187 !CallIndirect,
188 ) | define_proposal_operator(MVPOperator, MVP));
189 for_each_operator!(filter_define_mvp);
190 filter_operators!($ filter_define_exceptions(@exceptions) | define_proposal_operator(ExceptionsOperator, Exceptions));
191 for_each_operator!(filter_define_exceptions);
192 filter_operators!($ filter_define_tail_call(@tail_call) | define_proposal_operator(TailCallOperator, TailCall));
193 for_each_operator!(filter_define_tail_call);
194 filter_operators!($ filter_define_reference_types(@reference_types) | define_proposal_operator(ReferenceTypesOperator, ReferenceTypes));
195 for_each_operator!(filter_define_reference_types);
196 filter_operators!($ filter_define_sign_extension(@sign_extension) | define_proposal_operator(SignExtensionOperator, SignExtension));
197 for_each_operator!(filter_define_sign_extension);
198 filter_operators!($ filter_define_saturating_float_to_int(@saturating_float_to_int) | define_proposal_operator(SaturatingFloatToIntOperator, SaturatingFloatToInt));
199 for_each_operator!(filter_define_saturating_float_to_int);
200 filter_operators!($ filter_define_bulk_memory(@bulk_memory) | define_proposal_operator(BulkMemoryOperator, BulkMemory));
201 for_each_operator!(filter_define_bulk_memory);
202 filter_operators!($ filter_define_threads(@threads) | define_proposal_operator(ThreadsOperator, Threads));
203 for_each_operator!(filter_define_threads);
204 filter_operators!($ filter_define_simd(@simd) | define_proposal_operator(SIMDOperator, SIMD));
205 for_each_operator!(filter_define_simd);
206 filter_operators!($ filter_define_relaxed_simd(@relaxed_simd) | define_proposal_operator(RelaxedSIMDOperator, RelaxedSIMD));
207 for_each_operator!(filter_define_relaxed_simd);
208 filter_operators!($ filter_define_function_references(@function_references) | define_proposal_operator(FunctionReferencesOperator, FunctionReferences));
209 for_each_operator!(filter_define_function_references);
210 filter_operators!($ filter_define_memory_control(@memory_control) | define_proposal_operator(MemoryControlOperator, MemoryControl));
211 for_each_operator!(filter_define_memory_control);
212 filter_operators!($ filter_define_gc(@gc) | define_proposal_operator(GCOperator, GC));
213 for_each_operator!(filter_define_gc);
214
215 impl<'a> OperatorByProposal<'a> {
216 pub fn opcode(&self) -> OpCode {
217 match self {
218 Self::ControlFlow(op) => op.opcode(),
219 Self::MVP(op) => op.opcode(),
220 Self::Exceptions(op) => op.opcode(),
221 Self::TailCall(op) => op.opcode(),
222 Self::ReferenceTypes(op) => op.opcode(),
223 Self::SignExtension(op) => op.opcode(),
224 Self::SaturatingFloatToInt(op) => op.opcode(),
225 Self::BulkMemory(op) => op.opcode(),
226 Self::Threads(op) => op.opcode(),
227 Self::SIMD(op) => op.opcode(),
228 Self::RelaxedSIMD(op) => op.opcode(),
229 Self::FunctionReferences(op) => op.opcode(),
230 Self::MemoryControl(op) => op.opcode(),
231 Self::GC(op) => op.opcode(),
232 }
233 }
234 }
235
236 pub enum ControlFlowOperator<'a> {
238 End,
239 Block {
240 blockty: wasmparser::BlockType,
241 },
242 Loop {
243 blockty: wasmparser::BlockType,
244 },
245 If {
246 blockty: wasmparser::BlockType,
247 },
248 Else,
249 Br {
250 relative_depth: u32,
251 },
252 BrIf {
253 relative_depth: u32,
254 },
255 BrTable {
256 targets: wasmparser::BrTable<'a>,
257 },
258 Return,
259 Call {
260 function_index: u32,
261 },
262 CallIndirect {
263 type_index: u32,
264 table_index: u32,
265 table_byte: u8,
266 },
267 }
268
269 impl<'a> ControlFlowOperator<'a> {
270 pub fn opcode(&self) -> OpCode {
271 match self {
272 ControlFlowOperator::End => OpCode::End,
273 ControlFlowOperator::Block { .. } => OpCode::Block,
274 ControlFlowOperator::Loop { .. } => OpCode::Loop,
275 ControlFlowOperator::If { .. } => OpCode::If,
276 ControlFlowOperator::Else => OpCode::Else,
277 ControlFlowOperator::Br { .. } => OpCode::Br,
278 ControlFlowOperator::BrIf { .. } => OpCode::BrIf,
279 ControlFlowOperator::BrTable { .. } => OpCode::BrTable,
280 ControlFlowOperator::Return => OpCode::Return,
281 ControlFlowOperator::Call { .. } => OpCode::Call,
282 ControlFlowOperator::CallIndirect { .. } => OpCode::CallIndirect,
283 }
284 }
285 }
286
287 impl<'a> From<ControlFlowOperator<'a>> for wasmparser::Operator<'a> {
288 fn from(op: ControlFlowOperator<'a>) -> Self {
289 match op {
290 ControlFlowOperator::End => wasmparser::Operator::End,
291 ControlFlowOperator::Block { blockty } => wasmparser::Operator::Block { blockty },
292 ControlFlowOperator::Loop { blockty } => wasmparser::Operator::Loop { blockty },
293 ControlFlowOperator::If { blockty } => wasmparser::Operator::If { blockty },
294 ControlFlowOperator::Else => wasmparser::Operator::Else,
295 ControlFlowOperator::Br { relative_depth } => {
296 wasmparser::Operator::Br { relative_depth }
297 }
298 ControlFlowOperator::BrIf { relative_depth } => {
299 wasmparser::Operator::BrIf { relative_depth }
300 }
301 ControlFlowOperator::BrTable { targets } => {
302 wasmparser::Operator::BrTable { targets }
303 }
304 ControlFlowOperator::Return => wasmparser::Operator::Return,
305 ControlFlowOperator::Call { function_index } => {
306 wasmparser::Operator::Call { function_index }
307 }
308 ControlFlowOperator::CallIndirect {
309 type_index,
310 table_index,
311 table_byte,
312 } => wasmparser::Operator::CallIndirect {
313 type_index,
314 table_index,
315 table_byte,
316 },
317 }
318 }
319 }
320
321 define_make_operator_fn! {ControlFlow(ControlFlowOperator::End)}
323 define_make_operator_fn! {ControlFlow(ControlFlowOperator::Block {
324 blockty: wasmparser::BlockType,
325 })}
326 define_make_operator_fn! {ControlFlow(ControlFlowOperator::Loop {
327 blockty: wasmparser::BlockType,
328 })}
329 define_make_operator_fn! {ControlFlow(ControlFlowOperator::If {
330 blockty: wasmparser::BlockType,
331 })}
332 define_make_operator_fn! {ControlFlow(ControlFlowOperator::Else)}
333 define_make_operator_fn! {ControlFlow(ControlFlowOperator::Br {
334 relative_depth: u32,
335 })}
336 define_make_operator_fn! {ControlFlow(ControlFlowOperator::BrIf {
337 relative_depth: u32,
338 })}
339 define_make_operator_fn! {ControlFlow(ControlFlowOperator::Return)}
340 define_make_operator_fn! {ControlFlow(ControlFlowOperator::Call {
341 function_index: u32,
342 })}
343 define_make_operator_fn! {ControlFlow(ControlFlowOperator::CallIndirect {
344 type_index: u32,
345 table_index: u32,
346 table_byte: u8,
347 })}
348 define_make_operator_fn! {ControlFlow(ControlFlowOperator::BrTable {
349 targets: wasmparser::BrTable<'a>,
350 })}
351}