wasmprinter/
operator.rs

1use super::{Config, Print, PrintTermcolor, Printer, State};
2use anyhow::{Result, anyhow, bail};
3use termcolor::{Ansi, NoColor};
4use wasmparser::VisitSimdOperator;
5use wasmparser::{
6    BlockType, BrTable, Catch, CompositeInnerType, ContType, FrameKind, FuncType, Handle, MemArg,
7    ModuleArity, Operator, OperatorsReader, Ordering, RefType, ResumeTable, SubType, TryTable,
8    VisitOperator,
9};
10
11pub struct OperatorState {
12    op_offset: usize,
13    nesting_start: u32,
14    label: u32,
15    label_indices: Vec<u32>,
16    sep: OperatorSeparator,
17}
18
19impl OperatorState {
20    pub fn new(printer: &Printer, sep: OperatorSeparator) -> Self {
21        OperatorState {
22            op_offset: 0,
23            nesting_start: printer.nesting,
24            label: 0,
25            label_indices: Vec::new(),
26            sep,
27        }
28    }
29}
30
31pub struct PrintOperator<'printer, 'state, 'a, 'b> {
32    pub(super) printer: &'printer mut Printer<'a, 'b>,
33    state: &'state mut State,
34    operator_state: &'printer mut OperatorState,
35}
36
37struct FoldedInstruction {
38    plain: String,
39    folded: Vec<FoldedInstruction>,
40    results: u32,
41    offset: usize,
42}
43
44struct Block {
45    ty: BlockType,
46    kind: FrameKind,
47    plain: String,
48    folded: Vec<FoldedInstruction>,
49    predicate: Option<Vec<FoldedInstruction>>,
50    consequent: Option<(Vec<FoldedInstruction>, usize)>,
51    offset: usize,
52}
53
54pub struct PrintOperatorFolded<'printer, 'state, 'a, 'b> {
55    pub(super) printer: &'printer mut Printer<'a, 'b>,
56    state: &'state mut State,
57    operator_state: &'printer mut OperatorState,
58    control: Vec<Block>,
59    branch_hint: Option<FoldedInstruction>,
60    original_separator: OperatorSeparator,
61}
62
63#[derive(Copy, Clone)]
64pub enum OperatorSeparator {
65    Newline,
66    None,
67    NoneThenSpace,
68    Space,
69}
70
71impl<'printer, 'state, 'a, 'b> PrintOperator<'printer, 'state, 'a, 'b> {
72    pub(super) fn new(
73        printer: &'printer mut Printer<'a, 'b>,
74        state: &'state mut State,
75        operator_state: &'printer mut OperatorState,
76    ) -> Self {
77        PrintOperator {
78            printer,
79            state,
80            operator_state,
81        }
82    }
83
84    fn push_str(&mut self, s: &str) -> Result<()> {
85        self.printer.result.write_str(s)?;
86        Ok(())
87    }
88
89    fn result(&mut self) -> &mut dyn Print {
90        self.printer.result
91    }
92
93    fn separator(&mut self) -> Result<()> {
94        match self.operator_state.sep {
95            OperatorSeparator::Newline => self.printer.newline(self.operator_state.op_offset),
96            OperatorSeparator::None => Ok(()),
97            OperatorSeparator::NoneThenSpace => {
98                self.operator_state.sep = OperatorSeparator::Space;
99                Ok(())
100            }
101            OperatorSeparator::Space => self.push_str(" "),
102        }
103    }
104
105    /// Called just before an instruction that introduces a block such as
106    /// `block`, `if`, `loop`, etc.
107    fn block_start(&mut self) -> Result<()> {
108        self.separator()?;
109        self.printer.nesting += 1;
110        self.operator_state
111            .label_indices
112            .push(self.operator_state.label);
113        Ok(())
114    }
115
116    /// Used for `else` and `delegate`
117    fn block_mid(&mut self) -> Result<()> {
118        self.printer.nesting -= 1;
119        self.separator()?;
120        self.printer.nesting += 1;
121        Ok(())
122    }
123
124    /// Used for `end` to terminate the prior block.
125    fn block_end(&mut self) -> Result<()> {
126        if self.printer.nesting > self.operator_state.nesting_start {
127            self.printer.nesting -= 1;
128        }
129        self.separator()?;
130        Ok(())
131    }
132
133    fn blockty(&mut self, ty: BlockType) -> Result<()> {
134        let has_name = self.blockty_without_label_comment(ty)?;
135        self.maybe_blockty_label_comment(has_name)
136    }
137
138    fn blockty_without_label_comment(&mut self, ty: BlockType) -> Result<bool> {
139        let key = (self.state.core.funcs, self.operator_state.label);
140        let has_name = match self.state.core.label_names.index_to_name.get(&key) {
141            Some(name) => {
142                write!(self.printer.result, " ")?;
143                name.write(self.printer)?;
144                true
145            }
146            None if self.printer.config.name_unnamed => {
147                // Subtract one from the depth here because the label was
148                // already pushed onto our stack when the instruction was
149                // entered so its own label is one less.
150                let depth = self.cur_depth() - 1;
151                write!(self.result(), " $#label{depth}")?;
152                true
153            }
154            None => false,
155        };
156        match ty {
157            BlockType::Empty => {}
158            BlockType::Type(t) => {
159                self.push_str(" ")?;
160                self.printer.start_group("result ")?;
161                self.printer.print_valtype(self.state, t)?;
162                self.printer.end_group()?;
163            }
164            BlockType::FuncType(idx) => {
165                self.push_str(" ")?;
166                self.printer
167                    .print_core_functype_idx(self.state, idx, None)?;
168            }
169        }
170        Ok(has_name)
171    }
172
173    fn maybe_blockty_label_comment(&mut self, has_name: bool) -> Result<()> {
174        if !has_name {
175            let depth = self.cur_depth();
176            self.push_str(" ")?;
177            self.result().start_comment()?;
178            match self.operator_state.sep {
179                OperatorSeparator::Newline | OperatorSeparator::None => {
180                    write!(self.result(), ";; label = @{depth}")
181                }
182                _ => write!(self.result(), " (; label = @{depth} ;)"),
183            }?;
184            self.result().reset_color()?;
185        }
186
187        self.operator_state.label += 1;
188        Ok(())
189    }
190
191    fn cur_depth(&self) -> u32 {
192        self.printer.nesting - self.operator_state.nesting_start
193    }
194
195    fn tag_index(&mut self, index: u32) -> Result<()> {
196        self.push_str(" ")?;
197        self.printer.print_idx(&self.state.core.tag_names, index)?;
198        Ok(())
199    }
200
201    fn relative_depth(&mut self, depth: u32) -> Result<()> {
202        self.push_str(" ")?;
203        match self.cur_depth().checked_sub(depth) {
204            // If this relative depth is in-range relative to the current depth,
205            // then try to print a name for this label. Label names are tracked
206            // as a stack where the depth matches `cur_depth` roughly, but label
207            // names don't account for the function name so offset by one more
208            // here.
209            Some(i) => {
210                let name = i
211                    .checked_sub(1)
212                    .and_then(|idx| self.operator_state.label_indices.get(idx as usize).copied())
213                    .and_then(|label_idx| {
214                        let key = (self.state.core.funcs, label_idx);
215                        self.state.core.label_names.index_to_name.get(&key)
216                    });
217
218                // This is a bit tricky, but if there's a shallower label than
219                // this target which shares the same name then we can't print
220                // the name-based version. Names resolve to the nearest label
221                // in the case of shadowing, which would be the wrong behavior
222                // here. All that can be done is to print the index down below
223                // instead.
224                let name_conflict = name.is_some()
225                    && self.operator_state.label_indices[i as usize..]
226                        .iter()
227                        .any(|other_label| {
228                            let key = (self.state.core.funcs, *other_label);
229                            if let Some(other) = self.state.core.label_names.index_to_name.get(&key)
230                            {
231                                if name.unwrap().name == other.name {
232                                    return true;
233                                }
234                            }
235                            false
236                        });
237
238                match name {
239                    // Only print the name if one is found and there's also no
240                    // name conflict.
241                    Some(name) if !name_conflict => name.write(self.printer)?,
242
243                    // If there's no name conflict, and we're synthesizing
244                    // names, and this isn't targeting the function itself then
245                    // print a synthesized names.
246                    //
247                    // Note that synthesized label names don't handle the
248                    // function itself, so i==0, branching to a function label,
249                    // is not supported and otherwise labels are offset by 1.
250                    None if !name_conflict && self.printer.config.name_unnamed && i > 0 => {
251                        self.result().start_name()?;
252                        write!(self.result(), "$#label{}", i - 1)?;
253                        self.result().reset_color()?;
254                    }
255
256                    _ => {
257                        // Last-ditch resort, we gotta print the index.
258                        self.result().start_name()?;
259                        write!(self.result(), "{depth}")?;
260                        self.result().reset_color()?;
261
262                        // Unnamed labels have helpful `@N` labels printed for
263                        // them so also try to print where this index is going
264                        // (label-wise). Don't do this for a name conflict
265                        // though because we wouldn't have printed the numbered
266                        // label, and also don't do it for the function itself
267                        // since the function has no label we can synthesize.
268                        if !name_conflict && i > 0 {
269                            self.result().start_comment()?;
270                            write!(self.result(), " (;@{i};)")?;
271                            self.result().reset_color()?;
272                        }
273                    }
274                }
275            }
276
277            // This branch is out of range. Print the raw integer and then leave
278            // a hopefully-helpful comment indicating that it's going nowhere.
279            None => write!(self.result(), "{depth} (; INVALID ;)")?,
280        }
281        Ok(())
282    }
283
284    fn targets(&mut self, targets: BrTable<'_>) -> Result<()> {
285        for item in targets.targets().chain([Ok(targets.default())]) {
286            self.relative_depth(item?)?;
287        }
288        Ok(())
289    }
290
291    fn function_index(&mut self, idx: u32) -> Result<()> {
292        self.push_str(" ")?;
293        self.printer.print_idx(&self.state.core.func_names, idx)
294    }
295
296    fn local_index(&mut self, idx: u32) -> Result<()> {
297        self.push_str(" ")?;
298        self.printer
299            .print_local_idx(self.state, self.state.core.funcs, idx)
300    }
301
302    fn global_index(&mut self, idx: u32) -> Result<()> {
303        self.push_str(" ")?;
304        self.printer.print_idx(&self.state.core.global_names, idx)
305    }
306
307    fn table_index(&mut self, idx: u32) -> Result<()> {
308        self.push_str(" ")?;
309        self.printer.print_idx(&self.state.core.table_names, idx)
310    }
311
312    fn table(&mut self, idx: u32) -> Result<()> {
313        self.table_index(idx)
314    }
315
316    fn memory_index(&mut self, idx: u32) -> Result<()> {
317        self.push_str(" ")?;
318        self.printer.print_idx(&self.state.core.memory_names, idx)
319    }
320
321    fn type_index(&mut self, idx: u32) -> Result<()> {
322        self.push_str(" ")?;
323        self.printer.print_core_type_ref(self.state, idx)
324    }
325
326    fn cont_type_index(&mut self, idx: u32) -> Result<()> {
327        self.push_str(" ")?;
328        self.printer.print_idx(&self.state.core.type_names, idx)
329    }
330
331    fn argument_index(&mut self, idx: u32) -> Result<()> {
332        self.cont_type_index(idx)
333    }
334
335    fn result_index(&mut self, idx: u32) -> Result<()> {
336        self.cont_type_index(idx)
337    }
338
339    fn array_type_index(&mut self, idx: u32) -> Result<()> {
340        self.push_str(" ")?;
341        self.printer.print_idx(&self.state.core.type_names, idx)
342    }
343
344    fn array_type_index_dst(&mut self, idx: u32) -> Result<()> {
345        self.push_str(" ")?;
346        self.printer.print_idx(&self.state.core.type_names, idx)
347    }
348
349    fn array_type_index_src(&mut self, idx: u32) -> Result<()> {
350        self.push_str(" ")?;
351        self.printer.print_idx(&self.state.core.type_names, idx)
352    }
353
354    fn array_size(&mut self, array_size: u32) -> Result<()> {
355        write!(&mut self.printer.result, " {array_size}")?;
356        Ok(())
357    }
358
359    fn struct_type_index(&mut self, idx: u32) -> Result<()> {
360        self.push_str(" ")?;
361        self.printer.print_idx(&self.state.core.type_names, idx)
362    }
363
364    fn from_ref_type(&mut self, ref_ty: RefType) -> Result<()> {
365        self.push_str(" ")?;
366        self.printer.print_reftype(self.state, ref_ty)
367    }
368
369    fn to_ref_type(&mut self, ref_ty: RefType) -> Result<()> {
370        self.push_str(" ")?;
371        self.printer.print_reftype(self.state, ref_ty)
372    }
373
374    fn data_index(&mut self, idx: u32) -> Result<()> {
375        self.push_str(" ")?;
376        self.printer.print_idx(&self.state.core.data_names, idx)
377    }
378
379    fn array_data_index(&mut self, idx: u32) -> Result<()> {
380        self.push_str(" ")?;
381        self.printer.print_idx(&self.state.core.data_names, idx)
382    }
383
384    fn elem_index(&mut self, idx: u32) -> Result<()> {
385        self.push_str(" ")?;
386        self.printer.print_idx(&self.state.core.element_names, idx)
387    }
388
389    fn array_elem_index(&mut self, idx: u32) -> Result<()> {
390        self.push_str(" ")?;
391        self.printer.print_idx(&self.state.core.element_names, idx)
392    }
393
394    fn lane(&mut self, lane: u8) -> Result<()> {
395        write!(self.result(), " {lane}")?;
396        Ok(())
397    }
398
399    fn lanes(&mut self, lanes: [u8; 16]) -> Result<()> {
400        for lane in lanes.iter() {
401            write!(self.result(), " {lane}")?;
402        }
403        Ok(())
404    }
405
406    fn memarg(&mut self, memarg: MemArg) -> Result<()> {
407        if memarg.memory != 0 {
408            self.memory_index(memarg.memory)?;
409        }
410        if memarg.offset != 0 {
411            write!(self.result(), " offset={}", memarg.offset)?;
412        }
413        if memarg.align != memarg.max_align {
414            let align = 1_u64 << memarg.align;
415            write!(self.result(), " align={align}")?;
416        }
417        Ok(())
418    }
419
420    fn ordering(&mut self, ordering: Ordering) -> Result<()> {
421        write!(
422            self.result(),
423            " {}",
424            match ordering {
425                Ordering::SeqCst => "seq_cst",
426                Ordering::AcqRel => "acq_rel",
427            }
428        )?;
429        Ok(())
430    }
431
432    fn try_table(&mut self, table: TryTable) -> Result<()> {
433        let has_name = self.blockty_without_label_comment(table.ty)?;
434
435        // Nesting has already been incremented but labels for catch start above
436        // this `try_table` not at the `try_table`. Temporarily decrement this
437        // nesting count and increase it below after printing catch clauses.
438        self.printer.nesting -= 2;
439        let try_table_label = self.operator_state.label_indices.pop().unwrap();
440
441        for catch in table.catches {
442            self.result().write_str(" ")?;
443            match catch {
444                Catch::One { tag, label } => {
445                    self.printer.start_group("catch")?;
446                    self.tag_index(tag)?;
447                    self.relative_depth(label)?;
448                    self.printer.end_group()?;
449                }
450                Catch::OneRef { tag, label } => {
451                    self.printer.start_group("catch_ref")?;
452                    self.tag_index(tag)?;
453                    self.relative_depth(label)?;
454                    self.printer.end_group()?;
455                }
456                Catch::All { label } => {
457                    self.printer.start_group("catch_all")?;
458                    self.relative_depth(label)?;
459                    self.printer.end_group()?;
460                }
461                Catch::AllRef { label } => {
462                    self.printer.start_group("catch_all_ref")?;
463                    self.relative_depth(label)?;
464                    self.printer.end_group()?;
465                }
466            }
467        }
468        self.operator_state.label_indices.push(try_table_label);
469        self.printer.nesting += 2;
470        self.maybe_blockty_label_comment(has_name)?;
471        Ok(())
472    }
473
474    fn resume_table(&mut self, table: ResumeTable) -> Result<()> {
475        // The start_group("resume/resume_throw") have already
476        // increased the nesting depth, but the labels are defined
477        // above this `resume` or `resume_throw`. Therefore we
478        // temporarily decrement this nesting count and increase it
479        // below after printing the on clauses.
480        self.printer.nesting -= 1;
481        for handle in table.handlers {
482            self.result().write_str(" ")?;
483            self.printer.start_group("on")?;
484            match handle {
485                Handle::OnLabel { tag, label } => {
486                    self.tag_index(tag)?;
487                    self.relative_depth(label)?;
488                }
489                Handle::OnSwitch { tag } => {
490                    self.tag_index(tag)?;
491                    self.result().write_str(" switch")?;
492                }
493            }
494            self.printer.end_group()?;
495        }
496        self.printer.nesting += 1;
497        Ok(())
498    }
499}
500
501macro_rules! define_visit {
502    // General structure of all the operator printer methods:
503    //
504    // * Print the name of the insruction as defined in this macro
505    // * Print any payload, as necessary
506    ($(@$proposal:ident $op:ident $({ $($arg:ident: $argty:ty),* })? => $visit:ident ($($ann:tt)*) )*) => ($(
507        fn $visit(&mut self $( , $($arg: $argty),* )?) -> Self::Output {
508            define_visit!(before_op self $op);
509            self.push_str(define_visit!(name $op))?;
510            $(
511                define_visit!(payload self $op $($arg)*);
512            )?
513
514            define_visit!(after_op self $op);
515            Ok(())
516        }
517    )*);
518
519    // Control-flow related opcodes have special handling to manage nested
520    // depth as well as the stack of labels.
521    //
522    // The catch-all for "before an op" is "print an newline"
523    (before_op $self:ident Loop) => ($self.block_start()?;);
524    (before_op $self:ident Block) => ($self.block_start()?;);
525    (before_op $self:ident If) => ($self.block_start()?;);
526    (before_op $self:ident Try) => ($self.block_start()?;);
527    (before_op $self:ident TryTable) => ($self.block_start()?;);
528    (before_op $self:ident Catch) => ($self.block_mid()?;);
529    (before_op $self:ident CatchAll) => ($self.block_mid()?;);
530    (before_op $self:ident Delegate) => ($self.block_end()?;);
531    (before_op $self:ident Else) => ($self.block_mid()?;);
532    (before_op $self:ident End) => ($self.block_end()?;);
533    (before_op $self:ident $op:ident) => ($self.separator()?;);
534
535    // After some opcodes the label stack is popped.
536    // (after_op $self:ident Delegate) => ($self.label_indices.pop(););
537    (after_op $self:ident End) => ($self.operator_state.label_indices.pop(););
538    (after_op $self:ident $op:ident) => ();
539
540    // How to print the payload of an instruction. There are a number of
541    // instructions that have special cases such as avoiding printing anything
542    // when an index is 0 or similar. The final case in this list is the
543    // catch-all which prints each payload individually based on the name of the
544    // payload field.
545    (payload $self:ident CallIndirect $ty:ident $table:ident) => (
546        if $table != 0 {
547            $self.table_index($table)?;
548        }
549        $self.type_index($ty)?;
550    );
551    (payload $self:ident ReturnCallIndirect $ty:ident $table:ident) => (
552        if $table != 0 {
553            $self.table_index($table)?;
554        }
555        $self.type_index($ty)?;
556    );
557    (payload $self:ident CallRef $ty:ident) => (
558        $self.push_str(" ")?;
559        $self.printer.print_idx(&$self.state.core.type_names, $ty)?;
560    );
561    (payload $self:ident ReturnCallRef $ty:ident) => (
562        $self.push_str(" ")?;
563        $self.printer.print_idx(&$self.state.core.type_names, $ty)?;
564    );
565    (payload $self:ident TypedSelect $select_ty:ident) => (
566        $self.push_str(" ")?;
567        $self.printer.start_group("result ")?;
568        $self.printer.print_valtype($self.state, $select_ty)?;
569        $self.printer.end_group()?;
570    );
571    (payload $self:ident TypedSelectMulti $select_tys:ident) => (
572        $self.push_str(" ")?;
573        $self.printer.start_group("result")?;
574        $self.printer.print_valtypes($self.state, $select_tys)?;
575        $self.printer.end_group()?;
576    );
577    (payload $self:ident RefNull $hty:ident) => (
578        $self.push_str(" ")?;
579        $self.printer.print_heaptype($self.state, $hty)?;
580    );
581    (payload $self:ident TableInit $segment:ident $table:ident) => (
582        if $table != 0 {
583            $self.table_index($table)?;
584        }
585        $self.elem_index($segment)?;
586    );
587    (payload $self:ident TableCopy $dst:ident $src:ident) => (
588        if $src != 0 || $dst != 0 {
589            $self.table_index($dst)?;
590            $self.table_index($src)?;
591        }
592    );
593    (payload $self:ident MemoryGrow $mem:ident) => (
594        if $mem != 0 {
595            $self.memory_index($mem)?;
596        }
597    );
598    (payload $self:ident MemorySize $mem:ident) => (
599        if $mem != 0 {
600            $self.memory_index($mem)?;
601        }
602    );
603    (payload $self:ident MemoryInit $segment:ident $mem:ident) => (
604        if $mem != 0 {
605            $self.memory_index($mem)?;
606        }
607        $self.data_index($segment)?;
608    );
609    (payload $self:ident MemoryCopy $dst:ident $src:ident) => (
610        if $src != 0 || $dst != 0 {
611            $self.memory_index($dst)?;
612            $self.memory_index($src)?;
613        }
614    );
615    (payload $self:ident MemoryFill $mem:ident) => (
616        if $mem != 0 {
617            $self.memory_index($mem)?;
618        }
619    );
620    (payload $self:ident MemoryDiscard $mem:ident) => (
621        if $mem != 0 {
622            $self.memory_index($mem)?;
623        }
624    );
625    (payload $self:ident I32Const $val:ident) => (
626        $self.result().start_literal()?;
627        write!($self.result(), " {}", $val)?;
628        $self.result().reset_color()?;
629    );
630    (payload $self:ident I64Const $val:ident) => (
631        $self.result().start_literal()?;
632        write!($self.result(), " {}", $val)?;
633        $self.result().reset_color()?;
634    );
635    (payload $self:ident F32Const $val:ident) => (
636        $self.push_str(" ")?;
637        $self.printer.print_f32($val.bits())?;
638    );
639    (payload $self:ident F64Const $val:ident) => (
640        $self.push_str(" ")?;
641        $self.printer.print_f64($val.bits())?;
642    );
643    (payload $self:ident V128Const $val:ident) => (
644        $self.printer.print_type_keyword(" i32x4")?;
645        $self.result().start_literal()?;
646        for chunk in $val.bytes().chunks(4) {
647            write!(
648                $self.result(),
649                " 0x{:02x}{:02x}{:02x}{:02x}",
650                chunk[3],
651                chunk[2],
652                chunk[1],
653                chunk[0],
654            )?;
655        }
656        $self.result().reset_color()?;
657    );
658    (payload $self:ident RefTestNonNull $hty:ident) => (
659        $self.push_str(" ")?;
660        let rty = RefType::new(false, $hty)
661            .ok_or_else(|| anyhow!("implementation limit: type index too large"))?;
662        $self.printer.print_reftype($self.state, rty)?;
663    );
664    (payload $self:ident RefTestNullable $hty:ident) => (
665        $self.push_str(" ")?;
666        let rty = RefType::new(true, $hty)
667            .ok_or_else(|| anyhow!("implementation limit: type index too large"))?;
668        $self.printer.print_reftype($self.state, rty)?;
669    );
670    (payload $self:ident RefCastNonNull $hty:ident) => (
671        $self.push_str(" ")?;
672        let rty = RefType::new(false, $hty)
673            .ok_or_else(|| anyhow!("implementation limit: type index too large"))?;
674        $self.printer.print_reftype($self.state, rty)?;
675    );
676    (payload $self:ident RefCastNullable $hty:ident) => (
677        $self.push_str(" ")?;
678        let rty = RefType::new(true, $hty)
679            .ok_or_else(|| anyhow!("implementation limit: type index too large"))?;
680        $self.printer.print_reftype($self.state, rty)?;
681    );
682    (payload $self:ident StructGet $ty:ident $field:ident) => (
683        $self.struct_type_index($ty)?;
684        $self.push_str(" ")?;
685        $self.printer.print_field_idx($self.state, $ty, $field)?;
686    );
687    (payload $self:ident StructGetS $ty:ident $field:ident) => (
688        $self.struct_type_index($ty)?;
689        $self.push_str(" ")?;
690        $self.printer.print_field_idx($self.state, $ty, $field)?;
691    );
692    (payload $self:ident StructGetU $ty:ident $field:ident) => (
693        $self.struct_type_index($ty)?;
694        $self.push_str(" ")?;
695        $self.printer.print_field_idx($self.state, $ty, $field)?;
696    );
697    (payload $self:ident StructSet $ty:ident $field:ident) => (
698        $self.struct_type_index($ty)?;
699        $self.push_str(" ")?;
700        $self.printer.print_field_idx($self.state, $ty, $field)?;
701    );
702    (payload $self:ident StructAtomicGet $order:ident $ty:ident $field:ident) => (
703        $self.ordering($order)?;
704        $self.struct_type_index($ty)?;
705        $self.push_str(" ")?;
706        $self.printer.print_field_idx($self.state, $ty, $field)?;
707    );
708    (payload $self:ident StructAtomicGetS $order:ident $ty:ident $field:ident) => (
709        $self.ordering($order)?;
710        $self.struct_type_index($ty)?;
711        $self.push_str(" ")?;
712        $self.printer.print_field_idx($self.state, $ty, $field)?;
713    );
714    (payload $self:ident StructAtomicGetU $order:ident $ty:ident $field:ident) => (
715        $self.ordering($order)?;
716        $self.struct_type_index($ty)?;
717        $self.push_str(" ")?;
718        $self.printer.print_field_idx($self.state, $ty, $field)?;
719    );
720    (payload $self:ident StructAtomicSet $order:ident $ty:ident $field:ident) => (
721        $self.ordering($order)?;
722        $self.struct_type_index($ty)?;
723        $self.push_str(" ")?;
724        $self.printer.print_field_idx($self.state, $ty, $field)?;
725    );
726    (payload $self:ident StructAtomicRmwAdd $order:ident $ty:ident $field:ident) => (
727        $self.ordering($order)?;
728        $self.struct_type_index($ty)?;
729        $self.push_str(" ")?;
730        $self.printer.print_field_idx($self.state, $ty, $field)?;
731    );
732    (payload $self:ident StructAtomicRmwSub $order:ident $ty:ident $field:ident) => (
733        $self.ordering($order)?;
734        $self.struct_type_index($ty)?;
735        $self.push_str(" ")?;
736        $self.printer.print_field_idx($self.state, $ty, $field)?;
737    );
738    (payload $self:ident StructAtomicRmwAnd $order:ident $ty:ident $field:ident) => (
739        $self.ordering($order)?;
740        $self.struct_type_index($ty)?;
741        $self.push_str(" ")?;
742        $self.printer.print_field_idx($self.state, $ty, $field)?;
743    );
744    (payload $self:ident StructAtomicRmwOr $order:ident $ty:ident $field:ident) => (
745        $self.ordering($order)?;
746        $self.struct_type_index($ty)?;
747        $self.push_str(" ")?;
748        $self.printer.print_field_idx($self.state, $ty, $field)?;
749    );
750    (payload $self:ident StructAtomicRmwXor $order:ident $ty:ident $field:ident) => (
751        $self.ordering($order)?;
752        $self.struct_type_index($ty)?;
753        $self.push_str(" ")?;
754        $self.printer.print_field_idx($self.state, $ty, $field)?;
755    );
756    (payload $self:ident StructAtomicRmwXchg $order:ident $ty:ident $field:ident) => (
757        $self.ordering($order)?;
758        $self.struct_type_index($ty)?;
759        $self.push_str(" ")?;
760        $self.printer.print_field_idx($self.state, $ty, $field)?;
761    );
762    (payload $self:ident StructAtomicRmwCmpxchg $order:ident $ty:ident $field:ident) => (
763        $self.ordering($order)?;
764        $self.struct_type_index($ty)?;
765        $self.push_str(" ")?;
766        $self.printer.print_field_idx($self.state, $ty, $field)?;
767    );
768    (payload $self:ident $op:ident $($arg:ident)*) => (
769        $($self.$arg($arg)?;)*
770    );
771
772    (name Block) => ("block");
773    (name If) => ("if");
774    (name Else) => ("else");
775    (name Loop) => ("loop");
776    (name End) => ("end");
777    (name Unreachable) => ("unreachable");
778    (name Nop) => ("nop");
779    (name Br) => ("br");
780    (name BrIf) => ("br_if");
781    (name BrOnNull) => ("br_on_null");
782    (name BrOnNonNull) => ("br_on_non_null");
783    (name BrTable) => ("br_table");
784    (name Return) => ("return");
785    (name Call) => ("call");
786    (name CallIndirect) => ("call_indirect");
787    (name CallRef) => ("call_ref");
788    (name ReturnCall) => ("return_call");
789    (name ReturnCallIndirect) => ("return_call_indirect");
790    (name ReturnCallRef) => ("return_call_ref");
791    (name Drop) => ("drop");
792    (name Select) => ("select");
793    (name TypedSelect) => ("select");
794    (name TypedSelectMulti) => ("select");
795    (name LocalGet) => ("local.get");
796    (name LocalSet) => ("local.set");
797    (name LocalTee) => ("local.tee");
798    (name GlobalGet) => ("global.get");
799    (name GlobalSet) => ("global.set");
800    (name TableGet) => ("table.get");
801    (name TableSet) => ("table.set");
802    (name I32Load) => ("i32.load");
803    (name I64Load) => ("i64.load");
804    (name F32Load) => ("f32.load");
805    (name F64Load) => ("f64.load");
806    (name I32Load8S) => ("i32.load8_s");
807    (name I32Load8U) => ("i32.load8_u");
808    (name I32Load16S) => ("i32.load16_s");
809    (name I32Load16U) => ("i32.load16_u");
810    (name I64Load8S) => ("i64.load8_s");
811    (name I64Load8U) => ("i64.load8_u");
812    (name I64Load16S) => ("i64.load16_s");
813    (name I64Load16U) => ("i64.load16_u");
814    (name I64Load32S) => ("i64.load32_s");
815    (name I64Load32U) => ("i64.load32_u");
816    (name I32Store) => ("i32.store");
817    (name I64Store) => ("i64.store");
818    (name F32Store) => ("f32.store");
819    (name F64Store) => ("f64.store");
820    (name I32Store8) => ("i32.store8");
821    (name I32Store16) => ("i32.store16");
822    (name I64Store8) => ("i64.store8");
823    (name I64Store16) => ("i64.store16");
824    (name I64Store32) => ("i64.store32");
825    (name MemorySize) => ("memory.size");
826    (name MemoryGrow) => ("memory.grow");
827    (name MemoryInit) => ("memory.init");
828    (name MemoryCopy) => ("memory.copy");
829    (name MemoryFill) => ("memory.fill");
830    (name MemoryDiscard) => ("memory.discard");
831    (name DataDrop) => ("data.drop");
832    (name ElemDrop) => ("elem.drop");
833    (name TableInit) => ("table.init");
834    (name TableCopy) => ("table.copy");
835    (name TableFill) => ("table.fill");
836    (name TableSize) => ("table.size");
837    (name TableGrow) => ("table.grow");
838    (name RefAsNonNull) => ("ref.as_non_null");
839    (name RefNull) => ("ref.null");
840    (name RefEq) => ("ref.eq");
841    (name RefIsNull) => ("ref.is_null");
842    (name RefFunc) => ("ref.func");
843    (name I32Const) => ("i32.const");
844    (name I64Const) => ("i64.const");
845    (name F32Const) => ("f32.const");
846    (name F64Const) => ("f64.const");
847    (name I32Clz) => ("i32.clz");
848    (name I32Ctz) => ("i32.ctz");
849    (name I32Popcnt) => ("i32.popcnt");
850    (name I32Add) => ("i32.add");
851    (name I32Sub) => ("i32.sub");
852    (name I32Mul) => ("i32.mul");
853    (name I32DivS) => ("i32.div_s");
854    (name I32DivU) => ("i32.div_u");
855    (name I32RemS) => ("i32.rem_s");
856    (name I32RemU) => ("i32.rem_u");
857    (name I32And) => ("i32.and");
858    (name I32Or) => ("i32.or");
859    (name I32Xor) => ("i32.xor");
860    (name I32Shl) => ("i32.shl");
861    (name I32ShrS) => ("i32.shr_s");
862    (name I32ShrU) => ("i32.shr_u");
863    (name I32Rotl) => ("i32.rotl");
864    (name I32Rotr) => ("i32.rotr");
865    (name I64Clz) => ("i64.clz");
866    (name I64Ctz) => ("i64.ctz");
867    (name I64Popcnt) => ("i64.popcnt");
868    (name I64Add) => ("i64.add");
869    (name I64Sub) => ("i64.sub");
870    (name I64Mul) => ("i64.mul");
871    (name I64DivS) => ("i64.div_s");
872    (name I64DivU) => ("i64.div_u");
873    (name I64RemS) => ("i64.rem_s");
874    (name I64RemU) => ("i64.rem_u");
875    (name I64And) => ("i64.and");
876    (name I64Or) => ("i64.or");
877    (name I64Xor) => ("i64.xor");
878    (name I64Shl) => ("i64.shl");
879    (name I64ShrS) => ("i64.shr_s");
880    (name I64ShrU) => ("i64.shr_u");
881    (name I64Rotl) => ("i64.rotl");
882    (name I64Rotr) => ("i64.rotr");
883    (name F32Abs) => ("f32.abs");
884    (name F32Neg) => ("f32.neg");
885    (name F32Ceil) => ("f32.ceil");
886    (name F32Floor) => ("f32.floor");
887    (name F32Trunc) => ("f32.trunc");
888    (name F32Nearest) => ("f32.nearest");
889    (name F32Sqrt) => ("f32.sqrt");
890    (name F32Add) => ("f32.add");
891    (name F32Sub) => ("f32.sub");
892    (name F32Mul) => ("f32.mul");
893    (name F32Div) => ("f32.div");
894    (name F32Min) => ("f32.min");
895    (name F32Max) => ("f32.max");
896    (name F32Copysign) => ("f32.copysign");
897    (name F64Abs) => ("f64.abs");
898    (name F64Neg) => ("f64.neg");
899    (name F64Ceil) => ("f64.ceil");
900    (name F64Floor) => ("f64.floor");
901    (name F64Trunc) => ("f64.trunc");
902    (name F64Nearest) => ("f64.nearest");
903    (name F64Sqrt) => ("f64.sqrt");
904    (name F64Add) => ("f64.add");
905    (name F64Sub) => ("f64.sub");
906    (name F64Mul) => ("f64.mul");
907    (name F64Div) => ("f64.div");
908    (name F64Min) => ("f64.min");
909    (name F64Max) => ("f64.max");
910    (name F64Copysign) => ("f64.copysign");
911    (name I32Eqz) => ("i32.eqz");
912    (name I32Eq) => ("i32.eq");
913    (name I32Ne) => ("i32.ne");
914    (name I32LtS) => ("i32.lt_s");
915    (name I32LtU) => ("i32.lt_u");
916    (name I32GtS) => ("i32.gt_s");
917    (name I32GtU) => ("i32.gt_u");
918    (name I32LeS) => ("i32.le_s");
919    (name I32LeU) => ("i32.le_u");
920    (name I32GeS) => ("i32.ge_s");
921    (name I32GeU) => ("i32.ge_u");
922    (name I64Eqz) => ("i64.eqz");
923    (name I64Eq) => ("i64.eq");
924    (name I64Ne) => ("i64.ne");
925    (name I64LtS) => ("i64.lt_s");
926    (name I64LtU) => ("i64.lt_u");
927    (name I64GtS) => ("i64.gt_s");
928    (name I64GtU) => ("i64.gt_u");
929    (name I64LeS) => ("i64.le_s");
930    (name I64LeU) => ("i64.le_u");
931    (name I64GeS) => ("i64.ge_s");
932    (name I64GeU) => ("i64.ge_u");
933    (name F32Eq) => ("f32.eq");
934    (name F32Ne) => ("f32.ne");
935    (name F32Lt) => ("f32.lt");
936    (name F32Gt) => ("f32.gt");
937    (name F32Le) => ("f32.le");
938    (name F32Ge) => ("f32.ge");
939    (name F64Eq) => ("f64.eq");
940    (name F64Ne) => ("f64.ne");
941    (name F64Lt) => ("f64.lt");
942    (name F64Gt) => ("f64.gt");
943    (name F64Le) => ("f64.le");
944    (name F64Ge) => ("f64.ge");
945    (name I32WrapI64) => ("i32.wrap_i64");
946    (name I32TruncF32S) => ("i32.trunc_f32_s");
947    (name I32TruncF32U) => ("i32.trunc_f32_u");
948    (name I32TruncF64S) => ("i32.trunc_f64_s");
949    (name I32TruncF64U) => ("i32.trunc_f64_u");
950    (name I64ExtendI32S) => ("i64.extend_i32_s");
951    (name I64ExtendI32U) => ("i64.extend_i32_u");
952    (name I64TruncF32S) => ("i64.trunc_f32_s");
953    (name I64TruncF32U) => ("i64.trunc_f32_u");
954    (name I64TruncF64S) => ("i64.trunc_f64_s");
955    (name I64TruncF64U) => ("i64.trunc_f64_u");
956    (name F32ConvertI32S) => ("f32.convert_i32_s");
957    (name F32ConvertI32U) => ("f32.convert_i32_u");
958    (name F32ConvertI64S) => ("f32.convert_i64_s");
959    (name F32ConvertI64U) => ("f32.convert_i64_u");
960    (name F32DemoteF64) => ("f32.demote_f64");
961    (name F64ConvertI32S) => ("f64.convert_i32_s");
962    (name F64ConvertI32U) => ("f64.convert_i32_u");
963    (name F64ConvertI64S) => ("f64.convert_i64_s");
964    (name F64ConvertI64U) => ("f64.convert_i64_u");
965    (name F64PromoteF32) => ("f64.promote_f32");
966    (name I32ReinterpretF32) => ("i32.reinterpret_f32");
967    (name I64ReinterpretF64) => ("i64.reinterpret_f64");
968    (name F32ReinterpretI32) => ("f32.reinterpret_i32");
969    (name F64ReinterpretI64) => ("f64.reinterpret_i64");
970    (name I32TruncSatF32S) => ("i32.trunc_sat_f32_s");
971    (name I32TruncSatF32U) => ("i32.trunc_sat_f32_u");
972    (name I32TruncSatF64S) => ("i32.trunc_sat_f64_s");
973    (name I32TruncSatF64U) => ("i32.trunc_sat_f64_u");
974    (name I64TruncSatF32S) => ("i64.trunc_sat_f32_s");
975    (name I64TruncSatF32U) => ("i64.trunc_sat_f32_u");
976    (name I64TruncSatF64S) => ("i64.trunc_sat_f64_s");
977    (name I64TruncSatF64U) => ("i64.trunc_sat_f64_u");
978    (name I32Extend8S) => ("i32.extend8_s");
979    (name I32Extend16S) => ("i32.extend16_s");
980    (name I64Extend8S) => ("i64.extend8_s");
981    (name I64Extend16S) => ("i64.extend16_s");
982    (name I64Extend32S) => ("i64.extend32_s");
983    (name MemoryAtomicNotify) => ("memory.atomic.notify");
984    (name MemoryAtomicWait32) => ("memory.atomic.wait32");
985    (name MemoryAtomicWait64) => ("memory.atomic.wait64");
986    (name AtomicFence) => ("atomic.fence");
987    (name I32AtomicLoad) => ("i32.atomic.load");
988    (name I64AtomicLoad) => ("i64.atomic.load");
989    (name I32AtomicLoad8U) => ("i32.atomic.load8_u");
990    (name I32AtomicLoad16U) => ("i32.atomic.load16_u");
991    (name I64AtomicLoad8U) => ("i64.atomic.load8_u");
992    (name I64AtomicLoad16U) => ("i64.atomic.load16_u");
993    (name I64AtomicLoad32U) => ("i64.atomic.load32_u");
994    (name I32AtomicStore) => ("i32.atomic.store");
995    (name I64AtomicStore) => ("i64.atomic.store");
996    (name I32AtomicStore8) => ("i32.atomic.store8");
997    (name I32AtomicStore16) => ("i32.atomic.store16");
998    (name I64AtomicStore8) => ("i64.atomic.store8");
999    (name I64AtomicStore16) => ("i64.atomic.store16");
1000    (name I64AtomicStore32) => ("i64.atomic.store32");
1001    (name I32AtomicRmwAdd) => ("i32.atomic.rmw.add");
1002    (name I64AtomicRmwAdd) => ("i64.atomic.rmw.add");
1003    (name I32AtomicRmw8AddU) => ("i32.atomic.rmw8.add_u");
1004    (name I32AtomicRmw16AddU) => ("i32.atomic.rmw16.add_u");
1005    (name I64AtomicRmw8AddU) => ("i64.atomic.rmw8.add_u");
1006    (name I64AtomicRmw16AddU) => ("i64.atomic.rmw16.add_u");
1007    (name I64AtomicRmw32AddU) => ("i64.atomic.rmw32.add_u");
1008    (name I32AtomicRmwSub) => ("i32.atomic.rmw.sub");
1009    (name I64AtomicRmwSub) => ("i64.atomic.rmw.sub");
1010    (name I32AtomicRmw8SubU) => ("i32.atomic.rmw8.sub_u");
1011    (name I32AtomicRmw16SubU) => ("i32.atomic.rmw16.sub_u");
1012    (name I64AtomicRmw8SubU) => ("i64.atomic.rmw8.sub_u");
1013    (name I64AtomicRmw16SubU) => ("i64.atomic.rmw16.sub_u");
1014    (name I64AtomicRmw32SubU) => ("i64.atomic.rmw32.sub_u");
1015    (name I32AtomicRmwAnd) => ("i32.atomic.rmw.and");
1016    (name I64AtomicRmwAnd) => ("i64.atomic.rmw.and");
1017    (name I32AtomicRmw8AndU) => ("i32.atomic.rmw8.and_u");
1018    (name I32AtomicRmw16AndU) => ("i32.atomic.rmw16.and_u");
1019    (name I64AtomicRmw8AndU) => ("i64.atomic.rmw8.and_u");
1020    (name I64AtomicRmw16AndU) => ("i64.atomic.rmw16.and_u");
1021    (name I64AtomicRmw32AndU) => ("i64.atomic.rmw32.and_u");
1022    (name I32AtomicRmwOr) => ("i32.atomic.rmw.or");
1023    (name I64AtomicRmwOr) => ("i64.atomic.rmw.or");
1024    (name I32AtomicRmw8OrU) => ("i32.atomic.rmw8.or_u");
1025    (name I32AtomicRmw16OrU) => ("i32.atomic.rmw16.or_u");
1026    (name I64AtomicRmw8OrU) => ("i64.atomic.rmw8.or_u");
1027    (name I64AtomicRmw16OrU) => ("i64.atomic.rmw16.or_u");
1028    (name I64AtomicRmw32OrU) => ("i64.atomic.rmw32.or_u");
1029    (name I32AtomicRmwXor) => ("i32.atomic.rmw.xor");
1030    (name I64AtomicRmwXor) => ("i64.atomic.rmw.xor");
1031    (name I32AtomicRmw8XorU) => ("i32.atomic.rmw8.xor_u");
1032    (name I32AtomicRmw16XorU) => ("i32.atomic.rmw16.xor_u");
1033    (name I64AtomicRmw8XorU) => ("i64.atomic.rmw8.xor_u");
1034    (name I64AtomicRmw16XorU) => ("i64.atomic.rmw16.xor_u");
1035    (name I64AtomicRmw32XorU) => ("i64.atomic.rmw32.xor_u");
1036    (name I32AtomicRmwXchg) => ("i32.atomic.rmw.xchg");
1037    (name I64AtomicRmwXchg) => ("i64.atomic.rmw.xchg");
1038    (name I32AtomicRmw8XchgU) => ("i32.atomic.rmw8.xchg_u");
1039    (name I32AtomicRmw16XchgU) => ("i32.atomic.rmw16.xchg_u");
1040    (name I64AtomicRmw8XchgU) => ("i64.atomic.rmw8.xchg_u");
1041    (name I64AtomicRmw16XchgU) => ("i64.atomic.rmw16.xchg_u");
1042    (name I64AtomicRmw32XchgU) => ("i64.atomic.rmw32.xchg_u");
1043    (name I32AtomicRmwCmpxchg) => ("i32.atomic.rmw.cmpxchg");
1044    (name I64AtomicRmwCmpxchg) => ("i64.atomic.rmw.cmpxchg");
1045    (name I32AtomicRmw8CmpxchgU) => ("i32.atomic.rmw8.cmpxchg_u");
1046    (name I32AtomicRmw16CmpxchgU) => ("i32.atomic.rmw16.cmpxchg_u");
1047    (name I64AtomicRmw8CmpxchgU) => ("i64.atomic.rmw8.cmpxchg_u");
1048    (name I64AtomicRmw16CmpxchgU) => ("i64.atomic.rmw16.cmpxchg_u");
1049    (name I64AtomicRmw32CmpxchgU) => ("i64.atomic.rmw32.cmpxchg_u");
1050    (name V128Load) => ("v128.load");
1051    (name V128Load8x8S) => ("v128.load8x8_s");
1052    (name V128Load8x8U) => ("v128.load8x8_u");
1053    (name V128Load16x4S) => ("v128.load16x4_s");
1054    (name V128Load16x4U) => ("v128.load16x4_u");
1055    (name V128Load32x2S) => ("v128.load32x2_s");
1056    (name V128Load32x2U) => ("v128.load32x2_u");
1057    (name V128Load8Splat) => ("v128.load8_splat");
1058    (name V128Load16Splat) => ("v128.load16_splat");
1059    (name V128Load32Splat) => ("v128.load32_splat");
1060    (name V128Load64Splat) => ("v128.load64_splat");
1061    (name V128Load32Zero) => ("v128.load32_zero");
1062    (name V128Load64Zero) => ("v128.load64_zero");
1063    (name V128Store) => ("v128.store");
1064    (name V128Load8Lane) => ("v128.load8_lane");
1065    (name V128Load16Lane) => ("v128.load16_lane");
1066    (name V128Load32Lane) => ("v128.load32_lane");
1067    (name V128Load64Lane) => ("v128.load64_lane");
1068    (name V128Store8Lane) => ("v128.store8_lane");
1069    (name V128Store16Lane) => ("v128.store16_lane");
1070    (name V128Store32Lane) => ("v128.store32_lane");
1071    (name V128Store64Lane) => ("v128.store64_lane");
1072    (name V128Const) => ("v128.const");
1073    (name I8x16Shuffle) => ("i8x16.shuffle");
1074    (name I8x16ExtractLaneS) => ("i8x16.extract_lane_s");
1075    (name I8x16ExtractLaneU) => ("i8x16.extract_lane_u");
1076    (name I8x16ReplaceLane) => ("i8x16.replace_lane");
1077    (name I16x8ExtractLaneS) => ("i16x8.extract_lane_s");
1078    (name I16x8ExtractLaneU) => ("i16x8.extract_lane_u");
1079    (name I16x8ReplaceLane) => ("i16x8.replace_lane");
1080    (name I32x4ExtractLane) => ("i32x4.extract_lane");
1081    (name I32x4ReplaceLane) => ("i32x4.replace_lane");
1082    (name I64x2ExtractLane) => ("i64x2.extract_lane");
1083    (name I64x2ReplaceLane) => ("i64x2.replace_lane");
1084    (name F32x4ExtractLane) => ("f32x4.extract_lane");
1085    (name F32x4ReplaceLane) => ("f32x4.replace_lane");
1086    (name F64x2ExtractLane) => ("f64x2.extract_lane");
1087    (name F64x2ReplaceLane) => ("f64x2.replace_lane");
1088    (name I8x16Swizzle) => ("i8x16.swizzle");
1089    (name I8x16Splat) => ("i8x16.splat");
1090    (name I16x8Splat) => ("i16x8.splat");
1091    (name I32x4Splat) => ("i32x4.splat");
1092    (name I64x2Splat) => ("i64x2.splat");
1093    (name F32x4Splat) => ("f32x4.splat");
1094    (name F64x2Splat) => ("f64x2.splat");
1095    (name I8x16Eq) => ("i8x16.eq");
1096    (name I8x16Ne) => ("i8x16.ne");
1097    (name I8x16LtS) => ("i8x16.lt_s");
1098    (name I8x16LtU) => ("i8x16.lt_u");
1099    (name I8x16GtS) => ("i8x16.gt_s");
1100    (name I8x16GtU) => ("i8x16.gt_u");
1101    (name I8x16LeS) => ("i8x16.le_s");
1102    (name I8x16LeU) => ("i8x16.le_u");
1103    (name I8x16GeS) => ("i8x16.ge_s");
1104    (name I8x16GeU) => ("i8x16.ge_u");
1105    (name I16x8Eq) => ("i16x8.eq");
1106    (name I16x8Ne) => ("i16x8.ne");
1107    (name I16x8LtS) => ("i16x8.lt_s");
1108    (name I16x8LtU) => ("i16x8.lt_u");
1109    (name I16x8GtS) => ("i16x8.gt_s");
1110    (name I16x8GtU) => ("i16x8.gt_u");
1111    (name I16x8LeS) => ("i16x8.le_s");
1112    (name I16x8LeU) => ("i16x8.le_u");
1113    (name I16x8GeS) => ("i16x8.ge_s");
1114    (name I16x8GeU) => ("i16x8.ge_u");
1115    (name I32x4Eq) => ("i32x4.eq");
1116    (name I32x4Ne) => ("i32x4.ne");
1117    (name I32x4LtS) => ("i32x4.lt_s");
1118    (name I32x4LtU) => ("i32x4.lt_u");
1119    (name I32x4GtS) => ("i32x4.gt_s");
1120    (name I32x4GtU) => ("i32x4.gt_u");
1121    (name I32x4LeS) => ("i32x4.le_s");
1122    (name I32x4LeU) => ("i32x4.le_u");
1123    (name I32x4GeS) => ("i32x4.ge_s");
1124    (name I32x4GeU) => ("i32x4.ge_u");
1125    (name I64x2Eq) => ("i64x2.eq");
1126    (name I64x2Ne) => ("i64x2.ne");
1127    (name I64x2LtS) => ("i64x2.lt_s");
1128    (name I64x2GtS) => ("i64x2.gt_s");
1129    (name I64x2LeS) => ("i64x2.le_s");
1130    (name I64x2GeS) => ("i64x2.ge_s");
1131    (name F32x4Eq) => ("f32x4.eq");
1132    (name F32x4Ne) => ("f32x4.ne");
1133    (name F32x4Lt) => ("f32x4.lt");
1134    (name F32x4Gt) => ("f32x4.gt");
1135    (name F32x4Le) => ("f32x4.le");
1136    (name F32x4Ge) => ("f32x4.ge");
1137    (name F64x2Eq) => ("f64x2.eq");
1138    (name F64x2Ne) => ("f64x2.ne");
1139    (name F64x2Lt) => ("f64x2.lt");
1140    (name F64x2Gt) => ("f64x2.gt");
1141    (name F64x2Le) => ("f64x2.le");
1142    (name F64x2Ge) => ("f64x2.ge");
1143    (name V128Not) => ("v128.not");
1144    (name V128And) => ("v128.and");
1145    (name V128AndNot) => ("v128.andnot");
1146    (name V128Or) => ("v128.or");
1147    (name V128Xor) => ("v128.xor");
1148    (name V128Bitselect) => ("v128.bitselect");
1149    (name V128AnyTrue) => ("v128.any_true");
1150    (name I8x16Abs) => ("i8x16.abs");
1151    (name I8x16Neg) => ("i8x16.neg");
1152    (name I8x16Popcnt) => ("i8x16.popcnt");
1153    (name I8x16AllTrue) => ("i8x16.all_true");
1154    (name I8x16Bitmask) => ("i8x16.bitmask");
1155    (name I8x16NarrowI16x8S) => ("i8x16.narrow_i16x8_s");
1156    (name I8x16NarrowI16x8U) => ("i8x16.narrow_i16x8_u");
1157    (name I8x16Shl) => ("i8x16.shl");
1158    (name I8x16ShrS) => ("i8x16.shr_s");
1159    (name I8x16ShrU) => ("i8x16.shr_u");
1160    (name I8x16Add) => ("i8x16.add");
1161    (name I8x16AddSatS) => ("i8x16.add_sat_s");
1162    (name I8x16AddSatU) => ("i8x16.add_sat_u");
1163    (name I8x16Sub) => ("i8x16.sub");
1164    (name I8x16SubSatS) => ("i8x16.sub_sat_s");
1165    (name I8x16SubSatU) => ("i8x16.sub_sat_u");
1166    (name I8x16MinS) => ("i8x16.min_s");
1167    (name I8x16MinU) => ("i8x16.min_u");
1168    (name I8x16MaxS) => ("i8x16.max_s");
1169    (name I8x16MaxU) => ("i8x16.max_u");
1170    (name I8x16AvgrU) => ("i8x16.avgr_u");
1171    (name I16x8ExtAddPairwiseI8x16S) => ("i16x8.extadd_pairwise_i8x16_s");
1172    (name I16x8ExtAddPairwiseI8x16U) => ("i16x8.extadd_pairwise_i8x16_u");
1173    (name I16x8Abs) => ("i16x8.abs");
1174    (name I16x8Neg) => ("i16x8.neg");
1175    (name I16x8Q15MulrSatS) => ("i16x8.q15mulr_sat_s");
1176    (name I16x8AllTrue) => ("i16x8.all_true");
1177    (name I16x8Bitmask) => ("i16x8.bitmask");
1178    (name I16x8NarrowI32x4S) => ("i16x8.narrow_i32x4_s");
1179    (name I16x8NarrowI32x4U) => ("i16x8.narrow_i32x4_u");
1180    (name I16x8ExtendLowI8x16S) => ("i16x8.extend_low_i8x16_s");
1181    (name I16x8ExtendHighI8x16S) => ("i16x8.extend_high_i8x16_s");
1182    (name I16x8ExtendLowI8x16U) => ("i16x8.extend_low_i8x16_u");
1183    (name I16x8ExtendHighI8x16U) => ("i16x8.extend_high_i8x16_u");
1184    (name I16x8Shl) => ("i16x8.shl");
1185    (name I16x8ShrS) => ("i16x8.shr_s");
1186    (name I16x8ShrU) => ("i16x8.shr_u");
1187    (name I16x8Add) => ("i16x8.add");
1188    (name I16x8AddSatS) => ("i16x8.add_sat_s");
1189    (name I16x8AddSatU) => ("i16x8.add_sat_u");
1190    (name I16x8Sub) => ("i16x8.sub");
1191    (name I16x8SubSatS) => ("i16x8.sub_sat_s");
1192    (name I16x8SubSatU) => ("i16x8.sub_sat_u");
1193    (name I16x8Mul) => ("i16x8.mul");
1194    (name I16x8MinS) => ("i16x8.min_s");
1195    (name I16x8MinU) => ("i16x8.min_u");
1196    (name I16x8MaxS) => ("i16x8.max_s");
1197    (name I16x8MaxU) => ("i16x8.max_u");
1198    (name I16x8AvgrU) => ("i16x8.avgr_u");
1199    (name I16x8ExtMulLowI8x16S) => ("i16x8.extmul_low_i8x16_s");
1200    (name I16x8ExtMulHighI8x16S) => ("i16x8.extmul_high_i8x16_s");
1201    (name I16x8ExtMulLowI8x16U) => ("i16x8.extmul_low_i8x16_u");
1202    (name I16x8ExtMulHighI8x16U) => ("i16x8.extmul_high_i8x16_u");
1203    (name I32x4ExtAddPairwiseI16x8S) => ("i32x4.extadd_pairwise_i16x8_s");
1204    (name I32x4ExtAddPairwiseI16x8U) => ("i32x4.extadd_pairwise_i16x8_u");
1205    (name I32x4Abs) => ("i32x4.abs");
1206    (name I32x4Neg) => ("i32x4.neg");
1207    (name I32x4AllTrue) => ("i32x4.all_true");
1208    (name I32x4Bitmask) => ("i32x4.bitmask");
1209    (name I32x4ExtendLowI16x8S) => ("i32x4.extend_low_i16x8_s");
1210    (name I32x4ExtendHighI16x8S) => ("i32x4.extend_high_i16x8_s");
1211    (name I32x4ExtendLowI16x8U) => ("i32x4.extend_low_i16x8_u");
1212    (name I32x4ExtendHighI16x8U) => ("i32x4.extend_high_i16x8_u");
1213    (name I32x4Shl) => ("i32x4.shl");
1214    (name I32x4ShrS) => ("i32x4.shr_s");
1215    (name I32x4ShrU) => ("i32x4.shr_u");
1216    (name I32x4Add) => ("i32x4.add");
1217    (name I32x4Sub) => ("i32x4.sub");
1218    (name I32x4Mul) => ("i32x4.mul");
1219    (name I32x4MinS) => ("i32x4.min_s");
1220    (name I32x4MinU) => ("i32x4.min_u");
1221    (name I32x4MaxS) => ("i32x4.max_s");
1222    (name I32x4MaxU) => ("i32x4.max_u");
1223    (name I32x4DotI16x8S) => ("i32x4.dot_i16x8_s");
1224    (name I32x4ExtMulLowI16x8S) => ("i32x4.extmul_low_i16x8_s");
1225    (name I32x4ExtMulHighI16x8S) => ("i32x4.extmul_high_i16x8_s");
1226    (name I32x4ExtMulLowI16x8U) => ("i32x4.extmul_low_i16x8_u");
1227    (name I32x4ExtMulHighI16x8U) => ("i32x4.extmul_high_i16x8_u");
1228    (name I64x2Abs) => ("i64x2.abs");
1229    (name I64x2Neg) => ("i64x2.neg");
1230    (name I64x2AllTrue) => ("i64x2.all_true");
1231    (name I64x2Bitmask) => ("i64x2.bitmask");
1232    (name I64x2ExtendLowI32x4S) => ("i64x2.extend_low_i32x4_s");
1233    (name I64x2ExtendHighI32x4S) => ("i64x2.extend_high_i32x4_s");
1234    (name I64x2ExtendLowI32x4U) => ("i64x2.extend_low_i32x4_u");
1235    (name I64x2ExtendHighI32x4U) => ("i64x2.extend_high_i32x4_u");
1236    (name I64x2Shl) => ("i64x2.shl");
1237    (name I64x2ShrS) => ("i64x2.shr_s");
1238    (name I64x2ShrU) => ("i64x2.shr_u");
1239    (name I64x2Add) => ("i64x2.add");
1240    (name I64x2Sub) => ("i64x2.sub");
1241    (name I64x2Mul) => ("i64x2.mul");
1242    (name I64x2ExtMulLowI32x4S) => ("i64x2.extmul_low_i32x4_s");
1243    (name I64x2ExtMulHighI32x4S) => ("i64x2.extmul_high_i32x4_s");
1244    (name I64x2ExtMulLowI32x4U) => ("i64x2.extmul_low_i32x4_u");
1245    (name I64x2ExtMulHighI32x4U) => ("i64x2.extmul_high_i32x4_u");
1246    (name F32x4Ceil) => ("f32x4.ceil");
1247    (name F32x4Floor) => ("f32x4.floor");
1248    (name F32x4Trunc) => ("f32x4.trunc");
1249    (name F32x4Nearest) => ("f32x4.nearest");
1250    (name F32x4Abs) => ("f32x4.abs");
1251    (name F32x4Neg) => ("f32x4.neg");
1252    (name F32x4Sqrt) => ("f32x4.sqrt");
1253    (name F32x4Add) => ("f32x4.add");
1254    (name F32x4Sub) => ("f32x4.sub");
1255    (name F32x4Mul) => ("f32x4.mul");
1256    (name F32x4Div) => ("f32x4.div");
1257    (name F32x4Min) => ("f32x4.min");
1258    (name F32x4Max) => ("f32x4.max");
1259    (name F32x4PMin) => ("f32x4.pmin");
1260    (name F32x4PMax) => ("f32x4.pmax");
1261    (name F64x2Ceil) => ("f64x2.ceil");
1262    (name F64x2Floor) => ("f64x2.floor");
1263    (name F64x2Trunc) => ("f64x2.trunc");
1264    (name F64x2Nearest) => ("f64x2.nearest");
1265    (name F64x2Abs) => ("f64x2.abs");
1266    (name F64x2Neg) => ("f64x2.neg");
1267    (name F64x2Sqrt) => ("f64x2.sqrt");
1268    (name F64x2Add) => ("f64x2.add");
1269    (name F64x2Sub) => ("f64x2.sub");
1270    (name F64x2Mul) => ("f64x2.mul");
1271    (name F64x2Div) => ("f64x2.div");
1272    (name F64x2Min) => ("f64x2.min");
1273    (name F64x2Max) => ("f64x2.max");
1274    (name F64x2PMin) => ("f64x2.pmin");
1275    (name F64x2PMax) => ("f64x2.pmax");
1276    (name I32x4TruncSatF32x4S) => ("i32x4.trunc_sat_f32x4_s");
1277    (name I32x4TruncSatF32x4U) => ("i32x4.trunc_sat_f32x4_u");
1278    (name F32x4ConvertI32x4S) => ("f32x4.convert_i32x4_s");
1279    (name F32x4ConvertI32x4U) => ("f32x4.convert_i32x4_u");
1280    (name I32x4TruncSatF64x2SZero) => ("i32x4.trunc_sat_f64x2_s_zero");
1281    (name I32x4TruncSatF64x2UZero) => ("i32x4.trunc_sat_f64x2_u_zero");
1282    (name F64x2ConvertLowI32x4S) => ("f64x2.convert_low_i32x4_s");
1283    (name F64x2ConvertLowI32x4U) => ("f64x2.convert_low_i32x4_u");
1284    (name F32x4DemoteF64x2Zero) => ("f32x4.demote_f64x2_zero");
1285    (name F64x2PromoteLowF32x4) => ("f64x2.promote_low_f32x4");
1286    (name I8x16RelaxedSwizzle) => ("i8x16.relaxed_swizzle");
1287    (name I32x4RelaxedTruncF32x4S) => ("i32x4.relaxed_trunc_f32x4_s");
1288    (name I32x4RelaxedTruncF32x4U) => ("i32x4.relaxed_trunc_f32x4_u");
1289    (name I32x4RelaxedTruncF64x2SZero) => ("i32x4.relaxed_trunc_f64x2_s_zero");
1290    (name I32x4RelaxedTruncF64x2UZero) => ("i32x4.relaxed_trunc_f64x2_u_zero");
1291    (name F32x4RelaxedMadd) => ("f32x4.relaxed_madd");
1292    (name F32x4RelaxedNmadd) => ("f32x4.relaxed_nmadd");
1293    (name F64x2RelaxedMadd) => ("f64x2.relaxed_madd");
1294    (name F64x2RelaxedNmadd) => ("f64x2.relaxed_nmadd");
1295    (name I8x16RelaxedLaneselect) => ("i8x16.relaxed_laneselect");
1296    (name I16x8RelaxedLaneselect) => ("i16x8.relaxed_laneselect");
1297    (name I32x4RelaxedLaneselect) => ("i32x4.relaxed_laneselect");
1298    (name I64x2RelaxedLaneselect) => ("i64x2.relaxed_laneselect");
1299    (name F32x4RelaxedMin) => ("f32x4.relaxed_min");
1300    (name F32x4RelaxedMax) => ("f32x4.relaxed_max");
1301    (name F64x2RelaxedMin) => ("f64x2.relaxed_min");
1302    (name F64x2RelaxedMax) => ("f64x2.relaxed_max");
1303    (name I16x8RelaxedQ15mulrS) => ("i16x8.relaxed_q15mulr_s");
1304    (name I16x8RelaxedDotI8x16I7x16S) => ("i16x8.relaxed_dot_i8x16_i7x16_s");
1305    (name I32x4RelaxedDotI8x16I7x16AddS) => ("i32x4.relaxed_dot_i8x16_i7x16_add_s");
1306    (name StructNew) => ("struct.new");
1307    (name StructNewDefault) => ("struct.new_default");
1308    (name StructGet) => ("struct.get");
1309    (name StructGetS) => ("struct.get_s");
1310    (name StructGetU) => ("struct.get_u");
1311    (name StructSet) => ("struct.set");
1312    (name ArrayNew) => ("array.new");
1313    (name ArrayNewDefault) => ("array.new_default");
1314    (name ArrayNewFixed) => ("array.new_fixed");
1315    (name ArrayNewData) => ("array.new_data");
1316    (name ArrayNewElem) => ("array.new_elem");
1317    (name ArrayGet) => ("array.get");
1318    (name ArrayGetS) => ("array.get_s");
1319    (name ArrayGetU) => ("array.get_u");
1320    (name ArraySet) => ("array.set");
1321    (name ArrayLen) => ("array.len");
1322    (name ArrayFill) => ("array.fill");
1323    (name ArrayCopy) => ("array.copy");
1324    (name ArrayInitData) => ("array.init_data");
1325    (name ArrayInitElem) => ("array.init_elem");
1326    (name AnyConvertExtern) => ("any.convert_extern");
1327    (name ExternConvertAny) => ("extern.convert_any");
1328    (name RefTestNonNull) => ("ref.test");
1329    (name RefTestNullable) => ("ref.test");
1330    (name RefCastNonNull) => ("ref.cast");
1331    (name RefCastNullable) => ("ref.cast");
1332    (name BrOnCast) => ("br_on_cast");
1333    (name BrOnCastFail) => ("br_on_cast_fail");
1334    (name RefI31) => ("ref.i31");
1335    (name I31GetS) => ("i31.get_s");
1336    (name I31GetU) => ("i31.get_u");
1337    (name TryTable) => ("try_table");
1338    (name Throw) => ("throw");
1339    (name ThrowRef) => ("throw_ref");
1340    (name Rethrow) => ("rethrow");
1341    (name Try) => ("try");
1342    (name Catch) => ("catch");
1343    (name CatchAll) => ("catch_all");
1344    (name Delegate) => ("delegate");
1345    (name GlobalAtomicGet) => ("global.atomic.get");
1346    (name GlobalAtomicSet) => ("global.atomic.set");
1347    (name GlobalAtomicRmwAdd) => ("global.atomic.rmw.add");
1348    (name GlobalAtomicRmwSub) => ("global.atomic.rmw.sub");
1349    (name GlobalAtomicRmwAnd) => ("global.atomic.rmw.and");
1350    (name GlobalAtomicRmwOr) => ("global.atomic.rmw.or");
1351    (name GlobalAtomicRmwXor) => ("global.atomic.rmw.xor");
1352    (name GlobalAtomicRmwXchg) => ("global.atomic.rmw.xchg");
1353    (name GlobalAtomicRmwCmpxchg) => ("global.atomic.rmw.cmpxchg");
1354    (name TableAtomicGet) => ("table.atomic.get");
1355    (name TableAtomicSet) => ("table.atomic.set");
1356    (name TableAtomicRmwXchg) => ("table.atomic.rmw.xchg");
1357    (name TableAtomicRmwCmpxchg) => ("table.atomic.rmw.cmpxchg");
1358    (name StructAtomicGet) => ("struct.atomic.get");
1359    (name StructAtomicGetS) => ("struct.atomic.get_s");
1360    (name StructAtomicGetU) => ("struct.atomic.get_u");
1361    (name StructAtomicSet) => ("struct.atomic.set");
1362    (name StructAtomicRmwAdd) => ("struct.atomic.rmw.add");
1363    (name StructAtomicRmwSub) => ("struct.atomic.rmw.sub");
1364    (name StructAtomicRmwAnd) => ("struct.atomic.rmw.and");
1365    (name StructAtomicRmwOr) => ("struct.atomic.rmw.or");
1366    (name StructAtomicRmwXor) => ("struct.atomic.rmw.xor");
1367    (name StructAtomicRmwXchg) => ("struct.atomic.rmw.xchg");
1368    (name StructAtomicRmwCmpxchg) => ("struct.atomic.rmw.cmpxchg");
1369    (name ArrayAtomicGet) => ("array.atomic.get");
1370    (name ArrayAtomicGetS) => ("array.atomic.get_s");
1371    (name ArrayAtomicGetU) => ("array.atomic.get_u");
1372    (name ArrayAtomicSet) => ("array.atomic.set");
1373    (name ArrayAtomicRmwAdd) => ("array.atomic.rmw.add");
1374    (name ArrayAtomicRmwSub) => ("array.atomic.rmw.sub");
1375    (name ArrayAtomicRmwAnd) => ("array.atomic.rmw.and");
1376    (name ArrayAtomicRmwOr) => ("array.atomic.rmw.or");
1377    (name ArrayAtomicRmwXor) => ("array.atomic.rmw.xor");
1378    (name ArrayAtomicRmwXchg) => ("array.atomic.rmw.xchg");
1379    (name ArrayAtomicRmwCmpxchg) => ("array.atomic.rmw.cmpxchg");
1380    (name RefI31Shared) => ("ref.i31_shared");
1381    (name ContNew) => ("cont.new");
1382    (name ContBind) => ("cont.bind");
1383    (name Suspend) => ("suspend");
1384    (name Resume) => ("resume");
1385    (name ResumeThrow) => ("resume_throw");
1386    (name Switch) => ("switch");
1387    (name I64Add128) => ("i64.add128");
1388    (name I64Sub128) => ("i64.sub128");
1389    (name I64MulWideS) => ("i64.mul_wide_s");
1390    (name I64MulWideU) => ("i64.mul_wide_u");
1391}
1392
1393impl<'a> VisitOperator<'a> for PrintOperator<'_, '_, '_, '_> {
1394    type Output = Result<()>;
1395
1396    fn simd_visitor(&mut self) -> Option<&mut dyn VisitSimdOperator<'a, Output = Self::Output>> {
1397        Some(self)
1398    }
1399
1400    wasmparser::for_each_visit_operator!(define_visit);
1401}
1402
1403impl<'a> VisitSimdOperator<'a> for PrintOperator<'_, '_, '_, '_> {
1404    wasmparser::for_each_visit_simd_operator!(define_visit);
1405}
1406
1407pub trait OpPrinter {
1408    fn branch_hint(&mut self, offset: usize, taken: bool) -> Result<()>;
1409    fn set_offset(&mut self, offset: usize);
1410    fn visit_operator(
1411        &mut self,
1412        reader: &mut OperatorsReader<'_>,
1413        annotation: Option<&str>,
1414    ) -> Result<()>;
1415    fn finalize(&mut self, annotation: Option<&str>) -> Result<()>;
1416    fn use_color(&self) -> bool;
1417}
1418
1419impl OpPrinter for PrintOperator<'_, '_, '_, '_> {
1420    fn branch_hint(&mut self, offset: usize, taken: bool) -> Result<()> {
1421        self.printer.newline(offset)?;
1422        let desc = if taken { "\"\\01\"" } else { "\"\\00\"" };
1423        self.printer.result.start_comment()?;
1424        write!(self.printer.result, "(@metadata.code.branch_hint {desc})")?;
1425        self.printer.result.reset_color()?;
1426        Ok(())
1427    }
1428
1429    fn set_offset(&mut self, offset: usize) {
1430        self.operator_state.op_offset = offset;
1431    }
1432
1433    fn visit_operator(
1434        &mut self,
1435        reader: &mut OperatorsReader<'_>,
1436        annotation: Option<&str>,
1437    ) -> Result<()> {
1438        reader.visit_operator(self)??;
1439        if let Some(s) = annotation {
1440            self.printer.newline_unknown_pos()?;
1441            self.result().start_comment()?;
1442            write!(self.result(), ";; {s}")?;
1443            self.result().reset_color()?;
1444        }
1445        Ok(())
1446    }
1447
1448    fn finalize(&mut self, annotation: Option<&str>) -> Result<()> {
1449        if let Some(s) = annotation {
1450            self.printer.newline_unknown_pos()?;
1451            self.result().start_comment()?;
1452            write!(self.printer.result, ";; {s}")?;
1453            self.result().reset_color()?;
1454        }
1455        Ok(())
1456    }
1457
1458    fn use_color(&self) -> bool {
1459        self.printer.result.supports_async_color()
1460    }
1461}
1462
1463impl OpPrinter for PrintOperatorFolded<'_, '_, '_, '_> {
1464    fn branch_hint(&mut self, offset: usize, taken: bool) -> Result<()> {
1465        let mut hint = String::new();
1466        hint.push_str("@metadata.code.branch_hint ");
1467        hint.push_str(if taken { "\"\\01\"" } else { "\"\\00\"" });
1468        self.branch_hint = Some(FoldedInstruction {
1469            plain: hint,
1470            folded: Vec::new(),
1471            results: 0,
1472            offset,
1473        });
1474        Ok(())
1475    }
1476
1477    fn set_offset(&mut self, offset: usize) {
1478        self.operator_state.op_offset = offset;
1479    }
1480
1481    fn visit_operator(
1482        &mut self,
1483        reader: &mut OperatorsReader<'_>,
1484        annotation: Option<&str>,
1485    ) -> Result<()> {
1486        let operator = reader.clone().read()?;
1487        let (params, results) = operator.operator_arity(self).unwrap_or((0, 0));
1488        let mut buf_color = PrintTermcolor(Ansi::new(Vec::new()));
1489        let mut buf_nocolor = PrintTermcolor(NoColor::new(Vec::new()));
1490        let internal_config = Config {
1491            name_unnamed: self.printer.config.name_unnamed,
1492            ..Default::default()
1493        };
1494        let mut internal_printer = Printer {
1495            config: &internal_config,
1496            result: if self.use_color() {
1497                &mut buf_color
1498            } else {
1499                &mut buf_nocolor
1500            },
1501            nesting: self.printer.nesting,
1502            line: self.printer.line,
1503            group_lines: Vec::new(),
1504            code_section_hints: Vec::new(),
1505        };
1506
1507        let mut op_printer =
1508            PrintOperator::new(&mut internal_printer, self.state, self.operator_state);
1509        reader.visit_operator(&mut op_printer)??;
1510        if let Some(s) = annotation {
1511            internal_printer.result.start_comment()?;
1512            write!(internal_printer.result, " (; {s}")?;
1513            internal_printer.result.start_comment()?;
1514            write!(internal_printer.result, " ;)")?;
1515            internal_printer.result.reset_color()?;
1516        }
1517
1518        self.printer.nesting = internal_printer.nesting;
1519        self.printer.line = internal_printer.line;
1520
1521        let inst = String::from_utf8(if self.use_color() {
1522            buf_color.0.into_inner()
1523        } else {
1524            buf_nocolor.0.into_inner()
1525        })
1526        .expect("invalid UTF-8");
1527
1528        match operator {
1529            Operator::Loop { blockty } => self.push_block(blockty, FrameKind::Loop, inst),
1530            Operator::Block { blockty } => self.push_block(blockty, FrameKind::Block, inst),
1531            Operator::TryTable { try_table } => {
1532                self.push_block(try_table.ty, FrameKind::TryTable, inst)
1533            }
1534            Operator::If { blockty } => self.push_if(blockty, inst),
1535            Operator::Else => self.handle_else(),
1536            Operator::End => self.handle_end(results),
1537
1538            Operator::Try { .. }
1539            | Operator::Catch { .. }
1540            | Operator::CatchAll { .. }
1541            | Operator::Delegate { .. } => {
1542                bail!("legacy-exceptions not supported")
1543            }
1544            _ => self.handle_plain(inst, params, results),
1545        }
1546    }
1547
1548    // Recurse through the stack and print each folded instruction.
1549    fn finalize(&mut self, annotation: Option<&str>) -> Result<()> {
1550        if self.control.len() != 1 {
1551            bail!("instruction sequence not closed");
1552        }
1553        for inst in &self.control.last().unwrap().folded {
1554            PrintOperatorFolded::print(&mut self.printer, &mut self.original_separator, &inst)?;
1555        }
1556        if let Some(s) = annotation {
1557            self.printer.newline_unknown_pos()?;
1558            self.printer.result.start_comment()?;
1559            write!(self.printer.result, ";; {s}")?;
1560            self.printer.result.reset_color()?;
1561        }
1562        Ok(())
1563    }
1564
1565    fn use_color(&self) -> bool {
1566        self.printer.result.supports_async_color()
1567    }
1568}
1569
1570impl ModuleArity for PrintOperatorFolded<'_, '_, '_, '_> {
1571    fn tag_type_arity(&self, tag_idx: u32) -> Option<(u32, u32)> {
1572        self.sub_type_arity(
1573            self.sub_type_at(
1574                *self
1575                    .state
1576                    .core
1577                    .tag_to_type
1578                    .get(tag_idx as usize)?
1579                    .as_ref()?,
1580            )?,
1581        )
1582    }
1583
1584    fn type_index_of_function(&self, func_idx: u32) -> Option<u32> {
1585        *self.state.core.func_to_type.get(func_idx as usize)?
1586    }
1587
1588    fn sub_type_at(&self, type_idx: u32) -> Option<&SubType> {
1589        self.state.core.types.get(type_idx as usize)?.as_ref()
1590    }
1591
1592    fn func_type_of_cont_type(&self, c: &ContType) -> Option<&FuncType> {
1593        let st = self.sub_type_at(c.0.unpack().as_module_index()?)?;
1594        if let CompositeInnerType::Func(ft) = &st.composite_type.inner {
1595            Some(ft)
1596        } else {
1597            None
1598        }
1599    }
1600
1601    fn sub_type_of_ref_type(&self, rt: &RefType) -> Option<&SubType> {
1602        self.sub_type_at(rt.type_index()?.as_module_index()?)
1603    }
1604
1605    fn control_stack_height(&self) -> u32 {
1606        self.control.len() as u32
1607    }
1608
1609    fn label_block(&self, depth: u32) -> Option<(BlockType, FrameKind)> {
1610        let cur_depth = self.printer.nesting - self.operator_state.nesting_start;
1611        if self.control.len() != cur_depth as usize + 1 {
1612            return None;
1613        }
1614        match (self.control.len() - 1).checked_sub(depth as usize) {
1615            Some(i) => Some((self.control[i].ty, self.control[i].kind)),
1616            None => None,
1617        }
1618    }
1619}
1620
1621impl<'printer, 'state, 'a, 'b> PrintOperatorFolded<'printer, 'state, 'a, 'b> {
1622    pub(super) fn new(
1623        printer: &'printer mut Printer<'a, 'b>,
1624        state: &'state mut State,
1625        operator_state: &'printer mut OperatorState,
1626    ) -> Self {
1627        let original_separator = operator_state.sep;
1628        operator_state.sep = OperatorSeparator::None;
1629
1630        PrintOperatorFolded {
1631            printer,
1632            state,
1633            operator_state,
1634            control: Vec::new(),
1635            branch_hint: None,
1636            original_separator,
1637        }
1638    }
1639
1640    // Set up the outermost block, representing the unnamed function label.
1641    pub fn begin_function(&mut self, func_idx: u32) -> Result<()> {
1642        match self.state.core.func_to_type.get(func_idx as usize) {
1643            Some(Some(type_idx)) => self.control.push(Block {
1644                ty: BlockType::FuncType(*type_idx),
1645                kind: FrameKind::Block,
1646                plain: String::new(),
1647                folded: Vec::new(),
1648                predicate: None,
1649                consequent: None,
1650                offset: self.operator_state.op_offset,
1651            }),
1652            _ => bail!("invalid func_idx"),
1653        }
1654
1655        Ok(())
1656    }
1657
1658    // Set up a catch-all block to represent the constant expression's operand stack.
1659    pub fn begin_const_expr(&mut self) {
1660        self.control.push(Block {
1661            ty: BlockType::Empty,
1662            kind: FrameKind::Block,
1663            plain: String::new(),
1664            folded: Vec::new(),
1665            predicate: None,
1666            consequent: None,
1667            offset: 0,
1668        });
1669    }
1670
1671    // Handle a "plain" (non-block) instruction. The behavior resembles WABT's WatWriter::PushExpr().
1672    // Each instruction will pop some number of operands off the stack to become the "children"
1673    // of the foldedinst phrase. In the presence of multi-value instructions with more than 1 result,
1674    // it may not be possible to hit the params target exactly. This doesn't necessarily mean the
1675    // Wasm is invalid, but it can't be represented sensibly in folded form.
1676    fn handle_plain(&mut self, plain: String, params: u32, mut results: u32) -> Result<()> {
1677        let stack = match self.control.last_mut() {
1678            Some(stack) => stack,
1679            None => bail!("instruction without enclosing block"),
1680        };
1681
1682        let mut first_param = stack.folded.len();
1683        let mut param_count: u32 = 0;
1684        if params > 0 {
1685            for (pos, inst) in stack.folded.iter().enumerate().rev() {
1686                param_count = param_count.saturating_add(inst.results);
1687                if param_count == params {
1688                    first_param = pos;
1689                    break;
1690                } else if param_count > params {
1691                    // unfoldable instruction
1692                    results = u32::MAX;
1693                    break;
1694                }
1695            }
1696        }
1697
1698        let mut inst = FoldedInstruction {
1699            plain,
1700            folded: stack.folded.drain(first_param..).collect(),
1701            results,
1702            offset: self.operator_state.op_offset,
1703        };
1704        if let Some(hint) = self.branch_hint.take() {
1705            inst.folded.push(hint);
1706        }
1707        stack.folded.push(inst);
1708
1709        Ok(())
1710    }
1711
1712    // Print a folded instruction to the "real" printer. First print the "plain"
1713    // instruction, then recursively print each instruction that was folded in to the
1714    // foldedinst phrase.
1715    fn print(
1716        printer: &mut Printer,
1717        sep: &mut OperatorSeparator,
1718        inst: &FoldedInstruction,
1719    ) -> Result<()> {
1720        match sep {
1721            OperatorSeparator::Newline => printer.newline(inst.offset)?,
1722            OperatorSeparator::None => (),
1723            OperatorSeparator::NoneThenSpace => *sep = OperatorSeparator::Space,
1724            OperatorSeparator::Space => printer.result.write_str(" ")?,
1725        }
1726
1727        printer.result.write_str("(")?;
1728        printer.result.write_str(&inst.plain)?;
1729        if inst.folded.is_empty() && inst.plain.contains(";;") {
1730            // Wasm line comment (e.g. label annotation) shouldn't comment out the closing parenthesis
1731            printer.newline(inst.offset)?;
1732        }
1733        printer.nesting += 1;
1734        for fi in &inst.folded {
1735            PrintOperatorFolded::print(printer, sep, &fi)?;
1736        }
1737        printer.nesting -= 1;
1738        printer.result.write_str(")")?;
1739        Ok(())
1740    }
1741
1742    // The folding printer doesn't try to handle branch hints attached to blocks other than `if`.
1743    fn reject_branch_hint(&mut self) -> Result<()> {
1744        if self.branch_hint.is_some() {
1745            bail!("branch hints are only supported on an `if` or a plain instructions");
1746        }
1747        Ok(())
1748    }
1749
1750    fn push_block(&mut self, ty: BlockType, kind: FrameKind, plain: String) -> Result<()> {
1751        self.reject_branch_hint()?;
1752        self.control.push(Block {
1753            ty,
1754            kind,
1755            plain,
1756            folded: Vec::new(),
1757            predicate: None,
1758            consequent: None,
1759            offset: self.operator_state.op_offset,
1760        });
1761        Ok(())
1762    }
1763
1764    fn push_if(&mut self, ty: BlockType, plain: String) -> Result<()> {
1765        let mut predicate = Vec::new();
1766        if let Some(phrase) = self
1767            .control
1768            .last_mut()
1769            .ok_or_else(|| anyhow!("no enclosing block"))?
1770            .folded
1771            .pop()
1772        {
1773            predicate.push(phrase)
1774        }
1775        if let Some(hint) = self.branch_hint.take() {
1776            predicate.push(hint);
1777        }
1778        self.control.push(Block {
1779            ty,
1780            kind: FrameKind::If,
1781            plain,
1782            folded: Vec::new(),
1783            predicate: Some(predicate),
1784            consequent: None,
1785            offset: self.operator_state.op_offset,
1786        });
1787        Ok(())
1788    }
1789
1790    fn handle_else(&mut self) -> Result<()> {
1791        self.reject_branch_hint()?;
1792        match self.control.pop() {
1793            Some(Block {
1794                ty,
1795                kind: FrameKind::If,
1796                plain,
1797                predicate,
1798                folded,
1799                offset,
1800                ..
1801            }) => self.control.push(Block {
1802                ty,
1803                kind: FrameKind::Else,
1804                plain,
1805                folded: Vec::new(),
1806                predicate,
1807                consequent: Some((folded, offset)),
1808                offset: self.operator_state.op_offset,
1809            }),
1810            _ => bail!("no enclosing if block"),
1811        }
1812
1813        Ok(())
1814    }
1815
1816    // The end instruction closes the current block and transforms it to the
1817    // corresponding form of foldedinst belonging to the parent block. This reuses/abuses
1818    // the "plain" nomenclature to also represent the opening delimiters
1819    // of block instructions and other block-like clauses (e.g. "then", "else").
1820    fn handle_end(&mut self, results: u32) -> Result<()> {
1821        self.reject_branch_hint()?;
1822        let frame = self.control.pop();
1823        let inst = match frame {
1824            Some(Block {
1825                kind: FrameKind::Block | FrameKind::Loop | FrameKind::TryTable,
1826                plain,
1827                folded,
1828                offset,
1829                ..
1830            }) => FoldedInstruction {
1831                plain,
1832                folded,
1833                results,
1834                offset,
1835            },
1836            Some(Block {
1837                kind: FrameKind::If,
1838                plain,
1839                folded,
1840                predicate: Some(predicate),
1841                offset,
1842                ..
1843            }) => {
1844                let then_clause = FoldedInstruction {
1845                    plain: String::from("then"),
1846                    folded,
1847                    results,
1848                    offset,
1849                };
1850                let mut folded = predicate;
1851                folded.push(then_clause);
1852                FoldedInstruction {
1853                    plain,
1854                    folded,
1855                    results,
1856                    offset,
1857                }
1858            }
1859            Some(Block {
1860                kind: FrameKind::Else,
1861                plain,
1862                folded,
1863                predicate: Some(predicate),
1864                consequent: Some((consequent, if_offset)),
1865                offset,
1866                ..
1867            }) => {
1868                let then_clause = FoldedInstruction {
1869                    plain: String::from("then"),
1870                    folded: consequent,
1871                    results,
1872                    offset: if_offset,
1873                };
1874                let else_clause = FoldedInstruction {
1875                    plain: String::from("else"),
1876                    folded,
1877                    results,
1878                    offset,
1879                };
1880                let mut folded = predicate;
1881                folded.push(then_clause);
1882                folded.push(else_clause);
1883                FoldedInstruction {
1884                    plain,
1885                    folded,
1886                    results,
1887                    offset: if_offset,
1888                }
1889            }
1890            _ => bail!("unhandled frame kind"),
1891        };
1892
1893        self.control
1894            .last_mut()
1895            .ok_or_else(|| anyhow!("end without outer block"))?
1896            .folded
1897            .push(inst);
1898        Ok(())
1899    }
1900}