1#![deny(missing_docs)]
10#![cfg_attr(docsrs, feature(doc_auto_cfg))]
11
12use anyhow::{Context, Result, anyhow, bail};
13use operator::{OpPrinter, OperatorSeparator, OperatorState, PrintOperator, PrintOperatorFolded};
14use std::collections::{HashMap, HashSet};
15use std::fmt;
16use std::io;
17use std::marker;
18use std::mem;
19use std::path::Path;
20use wasmparser::*;
21
22const MAX_LOCALS: u32 = 50000;
23const MAX_NESTING_TO_PRINT: u32 = 50;
24const MAX_WASM_FUNCTIONS: u32 = 1_000_000;
25const MAX_WASM_FUNCTION_SIZE: u32 = 128 * 1024;
26
27#[cfg(feature = "component-model")]
28mod component;
29#[cfg(feature = "validate")]
30mod operand_stack;
31#[cfg(not(feature = "validate"))]
32mod operand_stack_disabled;
33#[cfg(not(feature = "validate"))]
34use operand_stack_disabled as operand_stack;
35mod operator;
36mod print;
37
38pub use self::print::*;
39
40pub fn print_file(file: impl AsRef<Path>) -> Result<String> {
43 let file = file.as_ref();
44 let contents = std::fs::read(file).context(format!("failed to read `{}`", file.display()))?;
45 print_bytes(contents)
46}
47
48pub fn print_bytes(wasm: impl AsRef<[u8]>) -> Result<String> {
51 let mut dst = String::new();
52 Config::new().print(wasm.as_ref(), &mut PrintFmtWrite(&mut dst))?;
53 Ok(dst)
54}
55
56#[derive(Debug)]
61pub struct Config {
62 print_offsets: bool,
63 print_skeleton: bool,
64 name_unnamed: bool,
65 fold_instructions: bool,
66 indent_text: String,
67 print_operand_stack: bool,
68}
69
70impl Default for Config {
71 fn default() -> Self {
72 Self {
73 print_offsets: false,
74 print_skeleton: false,
75 name_unnamed: false,
76 fold_instructions: false,
77 indent_text: " ".to_string(),
78 print_operand_stack: false,
79 }
80 }
81}
82
83struct Printer<'cfg, 'env> {
85 config: &'cfg Config,
86 result: &'cfg mut (dyn Print + 'env),
87 nesting: u32,
88 line: usize,
89 group_lines: Vec<usize>,
90 code_section_hints: Vec<(u32, Vec<(usize, BranchHint)>)>,
91}
92
93#[derive(Default)]
94struct CoreState {
95 types: Vec<Option<SubType>>,
96 funcs: u32,
97 func_to_type: Vec<Option<u32>>,
98 memories: u32,
99 tags: u32,
100 tag_to_type: Vec<Option<u32>>,
101 globals: u32,
102 tables: u32,
103 #[cfg(feature = "component-model")]
104 modules: u32,
105 #[cfg(feature = "component-model")]
106 instances: u32,
107 func_names: NamingMap<u32, NameFunc>,
108 local_names: NamingMap<(u32, u32), NameLocal>,
109 label_names: NamingMap<(u32, u32), NameLabel>,
110 type_names: NamingMap<u32, NameType>,
111 field_names: NamingMap<(u32, u32), NameField>,
112 tag_names: NamingMap<u32, NameTag>,
113 table_names: NamingMap<u32, NameTable>,
114 memory_names: NamingMap<u32, NameMemory>,
115 global_names: NamingMap<u32, NameGlobal>,
116 element_names: NamingMap<u32, NameElem>,
117 data_names: NamingMap<u32, NameData>,
118 #[cfg(feature = "component-model")]
119 module_names: NamingMap<u32, NameModule>,
120 #[cfg(feature = "component-model")]
121 instance_names: NamingMap<u32, NameInstance>,
122}
123
124struct NamingMap<T, K> {
134 index_to_name: HashMap<T, Naming>,
135 _marker: marker::PhantomData<K>,
136}
137
138impl<T, K> Default for NamingMap<T, K> {
139 fn default() -> NamingMap<T, K> {
140 NamingMap {
141 index_to_name: HashMap::new(),
142 _marker: marker::PhantomData,
143 }
144 }
145}
146
147#[derive(Default)]
148#[cfg(feature = "component-model")]
149struct ComponentState {
150 types: u32,
151 funcs: u32,
152 instances: u32,
153 components: u32,
154 values: u32,
155 type_names: NamingMap<u32, NameType>,
156 func_names: NamingMap<u32, NameFunc>,
157 component_names: NamingMap<u32, NameComponent>,
158 instance_names: NamingMap<u32, NameInstance>,
159 value_names: NamingMap<u32, NameValue>,
160}
161
162struct State {
163 encoding: Encoding,
164 name: Option<Naming>,
165 core: CoreState,
166 #[cfg(feature = "component-model")]
167 component: ComponentState,
168 custom_section_place: Option<(&'static str, usize)>,
169 }
177
178impl State {
179 fn new(encoding: Encoding) -> Self {
180 Self {
181 encoding,
182 name: None,
183 core: CoreState::default(),
184 #[cfg(feature = "component-model")]
185 component: ComponentState::default(),
186 custom_section_place: None,
187 }
188 }
189}
190
191struct Naming {
192 name: String,
193 kind: NamingKind,
194}
195
196enum NamingKind {
197 DollarName,
198 DollarQuotedName,
199 SyntheticPrefix(String),
200}
201
202impl Config {
203 pub fn new() -> Self {
206 Self::default()
207 }
208
209 pub fn print_offsets(&mut self, print: bool) -> &mut Self {
212 self.print_offsets = print;
213 self
214 }
215
216 pub fn print_skeleton(&mut self, print: bool) -> &mut Self {
219 self.print_skeleton = print;
220 self
221 }
222
223 pub fn name_unnamed(&mut self, enable: bool) -> &mut Self {
234 self.name_unnamed = enable;
235 self
236 }
237
238 pub fn fold_instructions(&mut self, enable: bool) -> &mut Self {
254 self.fold_instructions = enable;
255 self
256 }
257
258 #[cfg(feature = "validate")]
277 pub fn print_operand_stack(&mut self, enable: bool) -> &mut Self {
278 self.print_operand_stack = enable;
279 self
280 }
281
282 pub fn indent_text(&mut self, text: impl Into<String>) -> &mut Self {
289 self.indent_text = text.into();
290 self
291 }
292
293 pub fn print(&self, wasm: &[u8], result: &mut impl Print) -> Result<()> {
298 Printer {
299 config: self,
300 result,
301 code_section_hints: Vec::new(),
302 group_lines: Vec::new(),
303 line: 0,
304 nesting: 0,
305 }
306 .print_contents(wasm)
307 }
308
309 pub fn offsets_and_lines<'a>(
312 &self,
313 wasm: &[u8],
314 storage: &'a mut String,
315 ) -> Result<impl Iterator<Item = (Option<usize>, &'a str)> + 'a> {
316 struct TrackingPrint<'a> {
317 dst: &'a mut String,
318 lines: Vec<usize>,
319 line_offsets: Vec<Option<usize>>,
320 }
321
322 impl Print for TrackingPrint<'_> {
323 fn write_str(&mut self, s: &str) -> io::Result<()> {
324 self.dst.push_str(s);
325 Ok(())
326 }
327 fn start_line(&mut self, offset: Option<usize>) {
328 self.lines.push(self.dst.len());
329 self.line_offsets.push(offset);
330 }
331 }
332
333 let mut output = TrackingPrint {
334 dst: storage,
335 lines: Vec::new(),
336 line_offsets: Vec::new(),
337 };
338 self.print(wasm, &mut output)?;
339
340 let TrackingPrint {
341 dst,
342 lines,
343 line_offsets,
344 } = output;
345 let end = dst.len();
346 let dst = &dst[..];
347 let mut offsets = line_offsets.into_iter();
348 let mut lines = lines.into_iter().peekable();
349
350 Ok(std::iter::from_fn(move || {
351 let offset = offsets.next()?;
352 let i = lines.next()?;
353 let j = lines.peek().copied().unwrap_or(end);
354 let line = &dst[i..j];
355 Some((offset, line))
356 }))
357 }
358}
359
360impl Printer<'_, '_> {
361 fn read_names<'a>(
362 &mut self,
363 mut bytes: &'a [u8],
364 mut parser: Parser,
365 state: &mut State,
366 ) -> Result<()> {
367 loop {
368 let payload = match parser.parse(bytes, true)? {
369 Chunk::NeedMoreData(_) => unreachable!(),
370 Chunk::Parsed { payload, consumed } => {
371 bytes = &bytes[consumed..];
372 payload
373 }
374 };
375
376 match payload {
377 Payload::CodeSectionStart { size, .. } => {
378 if size as usize > bytes.len() {
379 bail!("invalid code section size");
380 }
381 bytes = &bytes[size as usize..];
382 parser.skip_section();
383 }
384 #[cfg(feature = "component-model")]
385 Payload::ModuleSection {
386 unchecked_range: range,
387 ..
388 }
389 | Payload::ComponentSection {
390 unchecked_range: range,
391 ..
392 } => {
393 let offset = range.end - range.start;
394 if offset > bytes.len() {
395 bail!("invalid module or component section range");
396 }
397 bytes = &bytes[offset..];
398 }
399
400 Payload::CustomSection(c) => {
401 match c.as_known() {
403 KnownCustom::Name(reader) => {
404 drop(self.register_names(state, reader));
405 }
406 #[cfg(feature = "component-model")]
407 KnownCustom::ComponentName(reader) => {
408 drop(self.register_component_names(state, reader));
409 }
410 KnownCustom::BranchHints(reader) => {
411 drop(self.register_branch_hint_section(reader));
412 }
413 _ => {}
414 }
415 }
416
417 Payload::End(_) => break,
418 _ => {}
419 }
420 }
421
422 Ok(())
423 }
424
425 fn ensure_module(states: &[State]) -> Result<()> {
426 if !matches!(states.last().unwrap().encoding, Encoding::Module) {
427 bail!("a module section was encountered when parsing a component");
428 }
429
430 Ok(())
431 }
432
433 #[cfg(feature = "component-model")]
434 fn ensure_component(states: &[State]) -> Result<()> {
435 if !matches!(states.last().unwrap().encoding, Encoding::Component) {
436 bail!("a component section was encountered when parsing a module");
437 }
438
439 Ok(())
440 }
441
442 fn print_contents(&mut self, mut bytes: &[u8]) -> Result<()> {
443 self.result.start_line(Some(0));
444
445 let mut expected = None;
446 let mut states: Vec<State> = Vec::new();
447 let mut parser = Parser::new(0);
448 #[cfg(feature = "component-model")]
449 let mut parsers = Vec::new();
450
451 let mut validator = if self.config.print_operand_stack {
452 operand_stack::Validator::new()
453 } else {
454 None
455 };
456
457 loop {
458 let payload = match parser.parse(bytes, true)? {
459 Chunk::NeedMoreData(_) => unreachable!(),
460 Chunk::Parsed { payload, consumed } => {
461 bytes = &bytes[consumed..];
462 payload
463 }
464 };
465 if let Some(validator) = &mut validator {
466 match validator.payload(&payload) {
467 Ok(()) => {}
468 Err(e) => {
469 self.newline_unknown_pos()?;
470 write!(self.result, ";; module or component is invalid: {e}")?;
471 }
472 }
473 }
474 match payload {
475 Payload::Version { encoding, .. } => {
476 if let Some(e) = expected {
477 if encoding != e {
478 bail!("incorrect encoding for nested module or component");
479 }
480 expected = None;
481 }
482
483 assert!(states.last().map(|s| s.encoding) != Some(Encoding::Module));
484
485 match encoding {
486 Encoding::Module => {
487 states.push(State::new(Encoding::Module));
488 states.last_mut().unwrap().custom_section_place =
489 Some(("before first", self.line));
490 if states.len() > 1 {
491 self.start_group("core module")?;
492 } else {
493 self.start_group("module")?;
494 }
495
496 #[cfg(feature = "component-model")]
497 if states.len() > 1 {
498 let parent = &states[states.len() - 2];
499 self.result.write_str(" ")?;
500 self.print_name(&parent.core.module_names, parent.core.modules)?;
501 }
502 }
503 Encoding::Component => {
504 #[cfg(feature = "component-model")]
505 {
506 states.push(State::new(Encoding::Component));
507 self.start_group("component")?;
508
509 if states.len() > 1 {
510 let parent = &states[states.len() - 2];
511 self.result.write_str(" ")?;
512 self.print_name(
513 &parent.component.component_names,
514 parent.component.components,
515 )?;
516 }
517 }
518 #[cfg(not(feature = "component-model"))]
519 {
520 bail!(
521 "support for printing components disabled \
522 at compile-time"
523 );
524 }
525 }
526 }
527
528 let len = states.len();
529 let state = states.last_mut().unwrap();
530
531 self.read_names(bytes, parser.clone(), state)?;
534
535 if len == 1 {
536 if let Some(name) = state.name.as_ref() {
537 self.result.write_str(" ")?;
538 name.write(self)?;
539 }
540 }
541 }
542 Payload::CustomSection(c) => {
543 let printed =
546 self.result
547 .print_custom_section(c.name(), c.data_offset(), c.data())?;
548 if printed {
549 self.update_custom_section_line(&mut states);
550 continue;
551 }
552
553 let state = states.last().unwrap();
558 let start = self.nesting;
559 match c.as_known() {
560 KnownCustom::Unknown => self.print_raw_custom_section(state, c.clone())?,
561 _ => {
562 match (Printer {
563 config: self.config,
564 result: &mut PrintFmtWrite(String::new()),
565 nesting: 0,
566 line: 0,
567 group_lines: Vec::new(),
568 code_section_hints: Vec::new(),
569 })
570 .print_known_custom_section(c.clone())
571 {
572 Ok(true) => {
573 self.print_known_custom_section(c.clone())?;
574 }
575 Ok(false) => self.print_raw_custom_section(state, c.clone())?,
576 Err(e) if !e.is::<BinaryReaderError>() => return Err(e),
577 Err(e) => {
578 let msg = format!(
579 "failed to parse custom section `{}`: {e}",
580 c.name()
581 );
582 for line in msg.lines() {
583 self.newline(c.data_offset())?;
584 write!(self.result, ";; {line}")?;
585 }
586 self.print_raw_custom_section(state, c.clone())?
587 }
588 }
589 }
590 }
591 assert!(self.nesting == start);
592 self.update_custom_section_line(&mut states);
593 }
594 Payload::TypeSection(s) => {
595 self.print_types(states.last_mut().unwrap(), s)?;
596 self.update_custom_section_place(&mut states, "after type");
597 }
598 Payload::ImportSection(s) => {
599 Self::ensure_module(&states)?;
600 self.print_imports(states.last_mut().unwrap(), s)?;
601 self.update_custom_section_place(&mut states, "after import");
602 }
603 Payload::FunctionSection(reader) => {
604 Self::ensure_module(&states)?;
605 if reader.count() > MAX_WASM_FUNCTIONS {
606 bail!(
607 "module contains {} functions which exceeds the limit of {}",
608 reader.count(),
609 MAX_WASM_FUNCTIONS
610 );
611 }
612 for ty in reader {
613 states.last_mut().unwrap().core.func_to_type.push(Some(ty?))
614 }
615 self.update_custom_section_place(&mut states, "after func");
616 }
617 Payload::TableSection(s) => {
618 Self::ensure_module(&states)?;
619 self.print_tables(states.last_mut().unwrap(), s)?;
620 self.update_custom_section_place(&mut states, "after table");
621 }
622 Payload::MemorySection(s) => {
623 Self::ensure_module(&states)?;
624 self.print_memories(states.last_mut().unwrap(), s)?;
625 self.update_custom_section_place(&mut states, "after memory");
626 }
627 Payload::TagSection(s) => {
628 Self::ensure_module(&states)?;
629 self.print_tags(states.last_mut().unwrap(), s)?;
630 self.update_custom_section_place(&mut states, "after tag");
631 }
632 Payload::GlobalSection(s) => {
633 Self::ensure_module(&states)?;
634 self.print_globals(states.last_mut().unwrap(), s)?;
635 self.update_custom_section_place(&mut states, "after global");
636 }
637 Payload::ExportSection(s) => {
638 Self::ensure_module(&states)?;
639 self.print_exports(states.last().unwrap(), s)?;
640 self.update_custom_section_place(&mut states, "after export");
641 }
642 Payload::StartSection { func, range } => {
643 Self::ensure_module(&states)?;
644 self.newline(range.start)?;
645 self.start_group("start ")?;
646 self.print_idx(&states.last().unwrap().core.func_names, func)?;
647 self.end_group()?;
648 self.update_custom_section_place(&mut states, "after start");
649 }
650 Payload::ElementSection(s) => {
651 Self::ensure_module(&states)?;
652 self.print_elems(states.last_mut().unwrap(), s)?;
653 self.update_custom_section_place(&mut states, "after elem");
654 }
655 Payload::CodeSectionStart { .. } => {
656 Self::ensure_module(&states)?;
657 }
658 Payload::CodeSectionEntry(body) => {
659 self.print_code_section_entry(
660 states.last_mut().unwrap(),
661 &body,
662 validator.as_mut().and_then(|v| v.next_func()),
663 )?;
664 self.update_custom_section_place(&mut states, "after code");
665 }
666 Payload::DataCountSection { .. } => {
667 Self::ensure_module(&states)?;
668 }
670 Payload::DataSection(s) => {
671 Self::ensure_module(&states)?;
672 self.print_data(states.last_mut().unwrap(), s)?;
673 self.update_custom_section_place(&mut states, "after data");
674 }
675
676 #[cfg(feature = "component-model")]
677 Payload::ModuleSection {
678 parser: inner,
679 unchecked_range: range,
680 } => {
681 Self::ensure_component(&states)?;
682 expected = Some(Encoding::Module);
683 parsers.push(parser);
684 parser = inner;
685 self.newline(range.start)?;
686 }
687 #[cfg(feature = "component-model")]
688 Payload::InstanceSection(s) => {
689 Self::ensure_component(&states)?;
690 self.print_instances(states.last_mut().unwrap(), s)?;
691 }
692 #[cfg(feature = "component-model")]
693 Payload::CoreTypeSection(s) => self.print_core_types(&mut states, s)?,
694 #[cfg(feature = "component-model")]
695 Payload::ComponentSection {
696 parser: inner,
697 unchecked_range: range,
698 } => {
699 Self::ensure_component(&states)?;
700 expected = Some(Encoding::Component);
701 parsers.push(parser);
702 parser = inner;
703 self.newline(range.start)?;
704 }
705 #[cfg(feature = "component-model")]
706 Payload::ComponentInstanceSection(s) => {
707 Self::ensure_component(&states)?;
708 self.print_component_instances(states.last_mut().unwrap(), s)?;
709 }
710 #[cfg(feature = "component-model")]
711 Payload::ComponentAliasSection(s) => {
712 Self::ensure_component(&states)?;
713 self.print_component_aliases(&mut states, s)?;
714 }
715 #[cfg(feature = "component-model")]
716 Payload::ComponentTypeSection(s) => {
717 Self::ensure_component(&states)?;
718 self.print_component_types(&mut states, s)?;
719 }
720 #[cfg(feature = "component-model")]
721 Payload::ComponentCanonicalSection(s) => {
722 Self::ensure_component(&states)?;
723 self.print_canonical_functions(states.last_mut().unwrap(), s)?;
724 }
725 #[cfg(feature = "component-model")]
726 Payload::ComponentStartSection { start, range } => {
727 Self::ensure_component(&states)?;
728 self.print_component_start(states.last_mut().unwrap(), range.start, start)?;
729 }
730 #[cfg(feature = "component-model")]
731 Payload::ComponentImportSection(s) => {
732 Self::ensure_component(&states)?;
733 self.print_component_imports(states.last_mut().unwrap(), s)?;
734 }
735 #[cfg(feature = "component-model")]
736 Payload::ComponentExportSection(s) => {
737 Self::ensure_component(&states)?;
738 self.print_component_exports(states.last_mut().unwrap(), s)?;
739 }
740
741 Payload::End(offset) => {
742 self.end_group()?; #[cfg(feature = "component-model")]
745 {
746 let state = states.pop().unwrap();
747 if let Some(parent) = states.last_mut() {
748 match state.encoding {
749 Encoding::Module => {
750 parent.core.modules += 1;
751 }
752 Encoding::Component => {
753 parent.component.components += 1;
754 }
755 }
756 parser = parsers.pop().unwrap();
757
758 continue;
759 }
760 }
761 self.newline(offset)?;
762 if self.config.print_offsets {
763 self.result.newline()?;
764 }
765 break;
766 }
767
768 other => match other.as_section() {
769 Some((id, _)) => bail!("found unknown section `{}`", id),
770 None => bail!("found unknown payload"),
771 },
772 }
773 }
774
775 Ok(())
776 }
777
778 fn update_custom_section_place(&self, states: &mut Vec<State>, place: &'static str) {
779 if let Some(last) = states.last_mut() {
780 if let Some((prev, prev_line)) = &mut last.custom_section_place {
781 if *prev_line != self.line {
782 *prev = place;
783 *prev_line = self.line;
784 }
785 }
786 }
787 }
788
789 fn update_custom_section_line(&self, states: &mut Vec<State>) {
790 if let Some(last) = states.last_mut() {
791 if let Some((_, prev_line)) = &mut last.custom_section_place {
792 *prev_line = self.line;
793 }
794 }
795 }
796
797 fn start_group(&mut self, name: &str) -> Result<()> {
798 write!(self.result, "(")?;
799 self.result.start_keyword()?;
800 write!(self.result, "{name}")?;
801 self.result.reset_color()?;
802 self.nesting += 1;
803 self.group_lines.push(self.line);
804 Ok(())
805 }
806
807 fn end_group(&mut self) -> Result<()> {
808 self.nesting -= 1;
809 if let Some(line) = self.group_lines.pop() {
810 if line != self.line {
811 self.newline_unknown_pos()?;
812 }
813 }
814 self.result.write_str(")")?;
815 Ok(())
816 }
817
818 fn register_names(&mut self, state: &mut State, names: NameSectionReader<'_>) -> Result<()> {
819 fn indirect_name_map<K>(
820 into: &mut NamingMap<(u32, u32), K>,
821 names: IndirectNameMap<'_>,
822 name: &str,
823 ) -> Result<()> {
824 for indirect in names {
825 let indirect = indirect?;
826 let mut used = match name {
827 "label" => None,
829 "local" | "field" => Some(HashSet::new()),
830 _ => unimplemented!("{name} is an unknown type of indirect names"),
831 };
832 for naming in indirect.names {
833 let naming = naming?;
834 into.index_to_name.insert(
835 (indirect.index, naming.index),
836 Naming::new(naming.name, naming.index, name, used.as_mut()),
837 );
838 }
839 }
840 Ok(())
841 }
842
843 for section in names {
844 match section? {
845 Name::Module { name, .. } => {
846 let name = Naming::new(name, 0, "module", None);
847 state.name = Some(name);
848 }
849 Name::Function(n) => name_map(&mut state.core.func_names, n, "func")?,
850 Name::Local(n) => indirect_name_map(&mut state.core.local_names, n, "local")?,
851 Name::Label(n) => indirect_name_map(&mut state.core.label_names, n, "label")?,
852 Name::Type(n) => name_map(&mut state.core.type_names, n, "type")?,
853 Name::Table(n) => name_map(&mut state.core.table_names, n, "table")?,
854 Name::Memory(n) => name_map(&mut state.core.memory_names, n, "memory")?,
855 Name::Global(n) => name_map(&mut state.core.global_names, n, "global")?,
856 Name::Element(n) => name_map(&mut state.core.element_names, n, "elem")?,
857 Name::Data(n) => name_map(&mut state.core.data_names, n, "data")?,
858 Name::Field(n) => indirect_name_map(&mut state.core.field_names, n, "field")?,
859 Name::Tag(n) => name_map(&mut state.core.tag_names, n, "tag")?,
860 Name::Unknown { .. } => (),
861 }
862 }
863 Ok(())
864 }
865
866 fn print_rec(
867 &mut self,
868 state: &mut State,
869 offset: Option<usize>,
870 rec: RecGroup,
871 is_component: bool,
872 ) -> Result<()> {
873 if rec.is_explicit_rec_group() {
874 if is_component {
875 self.start_group("core rec")?;
876 } else {
877 self.start_group("rec")?;
878 }
879 for ty in rec.into_types() {
880 match offset {
881 Some(offset) => self.newline(offset + 2)?,
882 None => self.newline_unknown_pos()?,
883 }
884 self.print_type(state, ty, false)?;
885 }
886 self.end_group()?; } else {
888 assert_eq!(rec.types().len(), 1);
889 let ty = rec.into_types().next().unwrap();
890 self.print_type(state, ty, is_component)?;
891 }
892 Ok(())
893 }
894
895 fn print_type(&mut self, state: &mut State, ty: SubType, is_component: bool) -> Result<()> {
896 if is_component {
897 self.start_group("core type ")?;
898 } else {
899 self.start_group("type ")?;
900 }
901 let ty_idx = state.core.types.len() as u32;
902 self.print_name(&state.core.type_names, ty_idx)?;
903 self.result.write_str(" ")?;
904 self.print_sub(state, &ty, ty_idx)?;
905 self.end_group()?; state.core.types.push(Some(ty));
907 Ok(())
908 }
909
910 fn print_sub(&mut self, state: &State, ty: &SubType, ty_idx: u32) -> Result<u32> {
911 let r = if !ty.is_final || !ty.supertype_idx.is_none() {
912 self.start_group("sub")?;
913 self.print_sub_type(state, ty)?;
914 let r = self.print_composite(state, &ty.composite_type, ty_idx)?;
915 self.end_group()?; r
917 } else {
918 self.print_composite(state, &ty.composite_type, ty_idx)?
919 };
920 Ok(r)
921 }
922
923 fn print_composite(&mut self, state: &State, ty: &CompositeType, ty_idx: u32) -> Result<u32> {
924 if ty.shared {
925 self.start_group("shared")?;
926 self.result.write_str(" ")?;
927 }
928 let r = match &ty.inner {
929 CompositeInnerType::Func(ty) => {
930 self.start_group("func")?;
931 let r = self.print_func_type(state, ty, None)?;
932 self.end_group()?; r
934 }
935 CompositeInnerType::Array(ty) => {
936 self.start_group("array")?;
937 let r = self.print_array_type(state, ty)?;
938 self.end_group()?; r
940 }
941 CompositeInnerType::Struct(ty) => {
942 self.start_group("struct")?;
943 let r = self.print_struct_type(state, ty, ty_idx)?;
944 self.end_group()?; r
946 }
947 CompositeInnerType::Cont(ty) => {
948 self.start_group("cont")?;
949 let r = self.print_cont_type(state, ty)?;
950 self.end_group()?; r
952 }
953 };
954 if ty.shared {
955 self.end_group()?; }
957 Ok(r)
958 }
959
960 fn print_types(&mut self, state: &mut State, parser: TypeSectionReader<'_>) -> Result<()> {
961 for ty in parser.into_iter_with_offsets() {
962 let (offset, rec_group) = ty?;
963 self.newline(offset)?;
964 self.print_rec(state, Some(offset), rec_group, false)?;
965 }
966 Ok(())
967 }
968
969 fn print_core_functype_idx(
970 &mut self,
971 state: &State,
972 idx: u32,
973 names_for: Option<u32>,
974 ) -> Result<Option<u32>> {
975 self.print_core_type_ref(state, idx)?;
976
977 match state.core.types.get(idx as usize) {
978 Some(Some(SubType {
979 composite_type:
980 CompositeType {
981 inner: CompositeInnerType::Func(ty),
982 shared: false,
983 },
984 ..
985 })) => self.print_func_type(state, ty, names_for).map(Some),
986 Some(Some(_)) | Some(None) | None => Ok(None),
987 }
988 }
989
990 fn print_func_type(
993 &mut self,
994 state: &State,
995 ty: &FuncType,
996 names_for: Option<u32>,
997 ) -> Result<u32> {
998 if !ty.params().is_empty() {
999 self.result.write_str(" ")?;
1000 }
1001
1002 let mut params = NamedLocalPrinter::new("param");
1003 for (i, param) in ty.params().iter().enumerate() {
1007 params.start_local(names_for, i as u32, self, state)?;
1008 self.print_valtype(state, *param)?;
1009 params.end_local(self)?;
1010 }
1011 params.finish(self)?;
1012 if !ty.results().is_empty() {
1013 self.result.write_str(" ")?;
1014 self.start_group("result")?;
1015 for result in ty.results().iter() {
1016 self.result.write_str(" ")?;
1017 self.print_valtype(state, *result)?;
1018 }
1019 self.end_group()?;
1020 }
1021 Ok(ty.params().len() as u32)
1022 }
1023
1024 fn print_field_type(
1025 &mut self,
1026 state: &State,
1027 ty: &FieldType,
1028 ty_field_idx: Option<(u32, u32)>,
1029 ) -> Result<u32> {
1030 self.result.write_str(" ")?;
1031 if let Some(idxs @ (_, field_idx)) = ty_field_idx {
1032 match state.core.field_names.index_to_name.get(&idxs) {
1033 Some(name) => {
1034 name.write_identifier(self)?;
1035 self.result.write_str(" ")?;
1036 }
1037 None if self.config.name_unnamed => write!(self.result, "$#field{field_idx} ")?,
1038 None => {}
1039 }
1040 }
1041 if ty.mutable {
1042 self.result.write_str("(mut ")?;
1043 }
1044 self.print_storage_type(state, ty.element_type)?;
1045 if ty.mutable {
1046 self.result.write_str(")")?;
1047 }
1048 Ok(0)
1049 }
1050
1051 fn print_array_type(&mut self, state: &State, ty: &ArrayType) -> Result<u32> {
1052 self.print_field_type(state, &ty.0, None)
1053 }
1054
1055 fn print_struct_type(&mut self, state: &State, ty: &StructType, ty_idx: u32) -> Result<u32> {
1056 for (field_index, field) in ty.fields.iter().enumerate() {
1057 self.result.write_str(" (field")?;
1058 self.print_field_type(state, field, Some((ty_idx, field_index as u32)))?;
1059 self.result.write_str(")")?;
1060 }
1061 Ok(0)
1062 }
1063
1064 fn print_cont_type(&mut self, state: &State, ct: &ContType) -> Result<u32> {
1065 self.result.write_str(" ")?;
1066 self.print_idx(&state.core.type_names, ct.0.as_module_index().unwrap())?;
1067 Ok(0)
1068 }
1069
1070 fn print_sub_type(&mut self, state: &State, ty: &SubType) -> Result<u32> {
1071 self.result.write_str(" ")?;
1072 if ty.is_final {
1073 self.result.write_str("final ")?;
1074 }
1075 if let Some(idx) = ty.supertype_idx {
1076 self.print_idx(&state.core.type_names, idx.as_module_index().unwrap())?;
1077 self.result.write_str(" ")?;
1078 }
1079 Ok(0)
1080 }
1081
1082 fn print_storage_type(&mut self, state: &State, ty: StorageType) -> Result<()> {
1083 match ty {
1084 StorageType::I8 => self.result.write_str("i8")?,
1085 StorageType::I16 => self.result.write_str("i16")?,
1086 StorageType::Val(val_type) => self.print_valtype(state, val_type)?,
1087 }
1088 Ok(())
1089 }
1090
1091 fn print_valtype(&mut self, state: &State, ty: ValType) -> Result<()> {
1092 match ty {
1093 ValType::I32 => self.print_type_keyword("i32")?,
1094 ValType::I64 => self.print_type_keyword("i64")?,
1095 ValType::F32 => self.print_type_keyword("f32")?,
1096 ValType::F64 => self.print_type_keyword("f64")?,
1097 ValType::V128 => self.print_type_keyword("v128")?,
1098 ValType::Ref(rt) => self.print_reftype(state, rt)?,
1099 }
1100 Ok(())
1101 }
1102
1103 fn print_valtypes(&mut self, state: &State, tys: Vec<ValType>) -> Result<()> {
1104 for ty in tys {
1105 self.result.write_str(" ")?;
1106 self.print_valtype(state, ty)?;
1107 }
1108 Ok(())
1109 }
1110
1111 fn print_reftype(&mut self, state: &State, ty: RefType) -> Result<()> {
1112 if ty.is_nullable() {
1113 match ty.as_non_null() {
1114 RefType::FUNC => self.print_type_keyword("funcref")?,
1115 RefType::EXTERN => self.print_type_keyword("externref")?,
1116 RefType::I31 => self.print_type_keyword("i31ref")?,
1117 RefType::ANY => self.print_type_keyword("anyref")?,
1118 RefType::NONE => self.print_type_keyword("nullref")?,
1119 RefType::NOEXTERN => self.print_type_keyword("nullexternref")?,
1120 RefType::NOFUNC => self.print_type_keyword("nullfuncref")?,
1121 RefType::EQ => self.print_type_keyword("eqref")?,
1122 RefType::STRUCT => self.print_type_keyword("structref")?,
1123 RefType::ARRAY => self.print_type_keyword("arrayref")?,
1124 RefType::EXN => self.print_type_keyword("exnref")?,
1125 RefType::NOEXN => self.print_type_keyword("nullexnref")?,
1126 _ => {
1127 self.start_group("ref")?;
1128 self.result.write_str(" null ")?;
1129 self.print_heaptype(state, ty.heap_type())?;
1130 self.end_group()?;
1131 }
1132 }
1133 } else {
1134 self.start_group("ref ")?;
1135 self.print_heaptype(state, ty.heap_type())?;
1136 self.end_group()?;
1137 }
1138 Ok(())
1139 }
1140
1141 fn print_heaptype(&mut self, state: &State, ty: HeapType) -> Result<()> {
1142 match ty {
1143 HeapType::Concrete(i) => {
1144 self.print_idx(&state.core.type_names, i.as_module_index().unwrap())?;
1145 }
1146 HeapType::Abstract { shared, ty } => {
1147 use AbstractHeapType::*;
1148 if shared {
1149 self.start_group("shared ")?;
1150 }
1151 match ty {
1152 Func => self.print_type_keyword("func")?,
1153 Extern => self.print_type_keyword("extern")?,
1154 Any => self.print_type_keyword("any")?,
1155 None => self.print_type_keyword("none")?,
1156 NoExtern => self.print_type_keyword("noextern")?,
1157 NoFunc => self.print_type_keyword("nofunc")?,
1158 Eq => self.print_type_keyword("eq")?,
1159 Struct => self.print_type_keyword("struct")?,
1160 Array => self.print_type_keyword("array")?,
1161 I31 => self.print_type_keyword("i31")?,
1162 Exn => self.print_type_keyword("exn")?,
1163 NoExn => self.print_type_keyword("noexn")?,
1164 Cont => self.print_type_keyword("cont")?,
1165 NoCont => self.print_type_keyword("nocont")?,
1166 }
1167 if shared {
1168 self.end_group()?;
1169 }
1170 }
1171 }
1172 Ok(())
1173 }
1174
1175 fn print_type_keyword(&mut self, keyword: &str) -> Result<()> {
1176 self.result.start_type()?;
1177 self.result.write_str(keyword)?;
1178 self.result.reset_color()?;
1179 Ok(())
1180 }
1181
1182 fn print_imports(&mut self, state: &mut State, parser: ImportSectionReader<'_>) -> Result<()> {
1183 for import in parser.into_iter_with_offsets() {
1184 let (offset, import) = import?;
1185 self.newline(offset)?;
1186 self.print_import(state, &import, true)?;
1187 match import.ty {
1188 TypeRef::Func(idx) => {
1189 debug_assert!(state.core.func_to_type.len() == state.core.funcs as usize);
1190 state.core.funcs += 1;
1191 state.core.func_to_type.push(Some(idx))
1192 }
1193 TypeRef::Table(_) => state.core.tables += 1,
1194 TypeRef::Memory(_) => state.core.memories += 1,
1195 TypeRef::Tag(TagType {
1196 kind: _,
1197 func_type_idx: idx,
1198 }) => {
1199 debug_assert!(state.core.tag_to_type.len() == state.core.tags as usize);
1200 state.core.tags += 1;
1201 state.core.tag_to_type.push(Some(idx))
1202 }
1203 TypeRef::Global(_) => state.core.globals += 1,
1204 }
1205 }
1206 Ok(())
1207 }
1208
1209 fn print_import(&mut self, state: &State, import: &Import<'_>, index: bool) -> Result<()> {
1210 self.start_group("import ")?;
1211 self.print_str(import.module)?;
1212 self.result.write_str(" ")?;
1213 self.print_str(import.name)?;
1214 self.result.write_str(" ")?;
1215 self.print_import_ty(state, &import.ty, index)?;
1216 self.end_group()?;
1217 Ok(())
1218 }
1219
1220 fn print_import_ty(&mut self, state: &State, ty: &TypeRef, index: bool) -> Result<()> {
1221 match ty {
1222 TypeRef::Func(f) => {
1223 self.start_group("func ")?;
1224 if index {
1225 self.print_name(&state.core.func_names, state.core.funcs)?;
1226 self.result.write_str(" ")?;
1227 }
1228 self.print_core_type_ref(state, *f)?;
1229 }
1230 TypeRef::Table(f) => self.print_table_type(state, f, index)?,
1231 TypeRef::Memory(f) => self.print_memory_type(state, f, index)?,
1232 TypeRef::Tag(f) => self.print_tag_type(state, f, index)?,
1233 TypeRef::Global(f) => self.print_global_type(state, f, index)?,
1234 }
1235 self.end_group()?;
1236 Ok(())
1237 }
1238
1239 fn print_table_type(&mut self, state: &State, ty: &TableType, index: bool) -> Result<()> {
1240 self.start_group("table ")?;
1241 if index {
1242 self.print_name(&state.core.table_names, state.core.tables)?;
1243 self.result.write_str(" ")?;
1244 }
1245 if ty.shared {
1246 self.print_type_keyword("shared ")?;
1247 }
1248 if ty.table64 {
1249 self.print_type_keyword("i64 ")?;
1250 }
1251 self.print_limits(ty.initial, ty.maximum)?;
1252 self.result.write_str(" ")?;
1253 self.print_reftype(state, ty.element_type)?;
1254 Ok(())
1255 }
1256
1257 fn print_memory_type(&mut self, state: &State, ty: &MemoryType, index: bool) -> Result<()> {
1258 self.start_group("memory ")?;
1259 if index {
1260 self.print_name(&state.core.memory_names, state.core.memories)?;
1261 self.result.write_str(" ")?;
1262 }
1263 if ty.memory64 {
1264 self.print_type_keyword("i64 ")?;
1265 }
1266 self.print_limits(ty.initial, ty.maximum)?;
1267 if ty.shared {
1268 self.print_type_keyword(" shared")?;
1269 }
1270 if let Some(p) = ty.page_size_log2 {
1271 let p = 1_u64
1272 .checked_shl(p)
1273 .ok_or_else(|| anyhow!("left shift overflow").context("invalid page size"))?;
1274
1275 self.result.write_str(" ")?;
1276 self.start_group("pagesize ")?;
1277 write!(self.result, "{p:#x}")?;
1278 self.end_group()?;
1279 }
1280 Ok(())
1281 }
1282
1283 fn print_tag_type(&mut self, state: &State, ty: &TagType, index: bool) -> Result<()> {
1284 self.start_group("tag ")?;
1285 if index {
1286 self.print_name(&state.core.tag_names, state.core.tags)?;
1287 self.result.write_str(" ")?;
1288 }
1289 self.print_core_functype_idx(state, ty.func_type_idx, None)?;
1290 Ok(())
1291 }
1292
1293 fn print_limits<T>(&mut self, initial: T, maximum: Option<T>) -> Result<()>
1294 where
1295 T: fmt::Display,
1296 {
1297 self.result.start_literal()?;
1298 write!(self.result, "{initial}")?;
1299 if let Some(max) = maximum {
1300 write!(self.result, " {max}")?;
1301 }
1302 self.result.reset_color()?;
1303 Ok(())
1304 }
1305
1306 fn print_global_type(&mut self, state: &State, ty: &GlobalType, index: bool) -> Result<()> {
1307 self.start_group("global ")?;
1308 if index {
1309 self.print_name(&state.core.global_names, state.core.globals)?;
1310 self.result.write_str(" ")?;
1311 }
1312 if ty.shared || ty.mutable {
1313 self.result.write_str("(")?;
1314 if ty.shared {
1315 self.print_type_keyword("shared ")?;
1316 }
1317 if ty.mutable {
1318 self.print_type_keyword("mut ")?;
1319 }
1320 self.print_valtype(state, ty.content_type)?;
1321 self.result.write_str(")")?;
1322 } else {
1323 self.print_valtype(state, ty.content_type)?;
1324 }
1325 Ok(())
1326 }
1327
1328 fn print_tables(&mut self, state: &mut State, parser: TableSectionReader<'_>) -> Result<()> {
1329 for table in parser.into_iter_with_offsets() {
1330 let (offset, table) = table?;
1331 self.newline(offset)?;
1332 self.print_table_type(state, &table.ty, true)?;
1333 match &table.init {
1334 TableInit::RefNull => {}
1335 TableInit::Expr(expr) => {
1336 self.result.write_str(" ")?;
1337 self.print_const_expr(state, expr, self.config.fold_instructions)?;
1338 }
1339 }
1340 self.end_group()?;
1341 state.core.tables += 1;
1342 }
1343 Ok(())
1344 }
1345
1346 fn print_memories(&mut self, state: &mut State, parser: MemorySectionReader<'_>) -> Result<()> {
1347 for memory in parser.into_iter_with_offsets() {
1348 let (offset, memory) = memory?;
1349 self.newline(offset)?;
1350 self.print_memory_type(state, &memory, true)?;
1351 self.end_group()?;
1352 state.core.memories += 1;
1353 }
1354 Ok(())
1355 }
1356
1357 fn print_tags(&mut self, state: &mut State, parser: TagSectionReader<'_>) -> Result<()> {
1358 for tag in parser.into_iter_with_offsets() {
1359 let (offset, tag) = tag?;
1360 self.newline(offset)?;
1361 self.print_tag_type(state, &tag, true)?;
1362 self.end_group()?;
1363 debug_assert!(state.core.tag_to_type.len() == state.core.tags as usize);
1364 state.core.tags += 1;
1365 state.core.tag_to_type.push(Some(tag.func_type_idx));
1366 }
1367 Ok(())
1368 }
1369
1370 fn print_globals(&mut self, state: &mut State, parser: GlobalSectionReader<'_>) -> Result<()> {
1371 for global in parser.into_iter_with_offsets() {
1372 let (offset, global) = global?;
1373 self.newline(offset)?;
1374 self.print_global_type(state, &global.ty, true)?;
1375 self.result.write_str(" ")?;
1376 self.print_const_expr(state, &global.init_expr, self.config.fold_instructions)?;
1377 self.end_group()?;
1378 state.core.globals += 1;
1379 }
1380 Ok(())
1381 }
1382
1383 fn print_code_section_entry(
1384 &mut self,
1385 state: &mut State,
1386 body: &FunctionBody<'_>,
1387 validator: Option<operand_stack::FuncValidator>,
1388 ) -> Result<()> {
1389 self.newline(body.get_binary_reader().original_position())?;
1390 self.start_group("func ")?;
1391 let func_idx = state.core.funcs;
1392 self.print_name(&state.core.func_names, func_idx)?;
1393 self.result.write_str(" ")?;
1394 let ty = match state.core.func_to_type.get(func_idx as usize) {
1395 Some(Some(x)) => *x,
1396 _ => panic!("invalid function type"),
1397 };
1398 let params = self
1399 .print_core_functype_idx(state, ty, Some(func_idx))?
1400 .unwrap_or(0);
1401
1402 let hints = match self.code_section_hints.last() {
1405 Some((f, _)) if *f == func_idx => {
1406 let (_, hints) = self.code_section_hints.pop().unwrap();
1407 hints
1408 }
1409 _ => Vec::new(),
1410 };
1411
1412 if self.config.print_skeleton {
1413 self.result.write_str(" ...")?;
1414 } else {
1415 self.print_func_body(state, func_idx, params, &body, &hints, validator)?;
1416 }
1417
1418 self.end_group()?;
1419 state.core.funcs += 1;
1420 Ok(())
1421 }
1422
1423 fn print_func_body(
1424 &mut self,
1425 state: &mut State,
1426 func_idx: u32,
1427 params: u32,
1428 body: &FunctionBody<'_>,
1429 branch_hints: &[(usize, BranchHint)],
1430 mut validator: Option<operand_stack::FuncValidator>,
1431 ) -> Result<()> {
1432 let mut first = true;
1433 let mut local_idx = 0;
1434 let mut locals = NamedLocalPrinter::new("local");
1435 let mut reader = body.get_binary_reader();
1436 let func_start = reader.original_position();
1437 for _ in 0..reader.read_var_u32()? {
1438 let offset = reader.original_position();
1439 let cnt = reader.read_var_u32()?;
1440 let ty = reader.read()?;
1441 if MAX_LOCALS
1442 .checked_sub(local_idx)
1443 .and_then(|s| s.checked_sub(cnt))
1444 .is_none()
1445 {
1446 bail!("function exceeds the maximum number of locals that can be printed");
1447 }
1448 for _ in 0..cnt {
1449 if first {
1450 self.newline(offset)?;
1451 first = false;
1452 }
1453 locals.start_local(Some(func_idx), params + local_idx, self, state)?;
1454 self.print_valtype(state, ty)?;
1455 locals.end_local(self)?;
1456 local_idx += 1;
1457 }
1458 }
1459 locals.finish(self)?;
1460
1461 if let Some(f) = &mut validator {
1462 if let Err(e) = f.read_locals(body.get_binary_reader()) {
1463 validator = None;
1464 self.newline_unknown_pos()?;
1465 write!(self.result, ";; locals are invalid: {e}")?;
1466 }
1467 }
1468
1469 let nesting_start = self.nesting;
1470 let fold_instructions = self.config.fold_instructions;
1471 let mut operator_state = OperatorState::new(self, OperatorSeparator::Newline);
1472
1473 if fold_instructions {
1474 let mut folded_printer = PrintOperatorFolded::new(self, state, &mut operator_state);
1475 folded_printer.set_offset(func_start);
1476 folded_printer.begin_function(func_idx)?;
1477 Self::print_operators(
1478 &mut reader,
1479 branch_hints,
1480 func_start,
1481 &mut folded_printer,
1482 validator,
1483 )?;
1484 } else {
1485 let mut flat_printer = PrintOperator::new(self, state, &mut operator_state);
1486 Self::print_operators(
1487 &mut reader,
1488 branch_hints,
1489 func_start,
1490 &mut flat_printer,
1491 validator,
1492 )?;
1493 }
1494
1495 if self.nesting != nesting_start {
1501 self.nesting = nesting_start;
1502 self.newline(reader.original_position())?;
1503 }
1504
1505 Ok(())
1506 }
1507
1508 fn print_operators<'a, O: OpPrinter>(
1509 body: &mut BinaryReader<'a>,
1510 mut branch_hints: &[(usize, BranchHint)],
1511 func_start: usize,
1512 op_printer: &mut O,
1513 mut validator: Option<operand_stack::FuncValidator>,
1514 ) -> Result<()> {
1515 let mut ops = OperatorsReader::new(body.clone());
1516 while !ops.eof() {
1517 if ops.is_end_then_eof() {
1518 let mut annotation = None;
1519 if let Some(f) = &mut validator {
1520 match f.visit_operator(&ops, true) {
1521 Ok(()) => {}
1522 Err(_) => {
1523 annotation = Some(String::from("type mismatch at end of expression"))
1524 }
1525 }
1526 }
1527
1528 ops.read()?; ops.finish()?;
1530 op_printer.finalize(annotation.as_deref())?;
1531 return Ok(());
1532 }
1533
1534 if let Some(((hint_offset, hint), rest)) = branch_hints.split_first() {
1537 if hint.func_offset == (ops.original_position() - func_start) as u32 {
1538 branch_hints = rest;
1539 op_printer.branch_hint(*hint_offset, hint.taken)?;
1540 }
1541 }
1542 let mut annotation = None;
1543 if let Some(f) = &mut validator {
1544 let result = f
1545 .visit_operator(&ops, false)
1546 .map_err(anyhow::Error::from)
1547 .and_then(|()| f.visualize_operand_stack(op_printer.use_color()));
1548 match result {
1549 Ok(s) => annotation = Some(s),
1550 Err(_) => {
1551 validator = None;
1552 annotation = Some(String::from("(invalid)"));
1553 }
1554 }
1555 }
1556 op_printer.set_offset(ops.original_position());
1557 op_printer.visit_operator(&mut ops, annotation.as_deref())?;
1558 }
1559 ops.finish()?; bail!("unexpected end of operators");
1561 }
1562
1563 fn newline(&mut self, offset: usize) -> Result<()> {
1564 self.print_newline(Some(offset))
1565 }
1566
1567 fn newline_unknown_pos(&mut self) -> Result<()> {
1568 self.print_newline(None)
1569 }
1570
1571 fn print_newline(&mut self, offset: Option<usize>) -> Result<()> {
1572 self.result.newline()?;
1573 self.result.start_line(offset);
1574
1575 if self.config.print_offsets {
1576 match offset {
1577 Some(offset) => {
1578 self.result.start_comment()?;
1579 write!(self.result, "(;@{offset:<6x};)")?;
1580 self.result.reset_color()?;
1581 }
1582 None => self.result.write_str(" ")?,
1583 }
1584 }
1585 self.line += 1;
1586
1587 for _ in 0..self.nesting.min(MAX_NESTING_TO_PRINT) {
1591 self.result.write_str(&self.config.indent_text)?;
1592 }
1593 Ok(())
1594 }
1595
1596 fn print_exports(&mut self, state: &State, data: ExportSectionReader) -> Result<()> {
1597 for export in data.into_iter_with_offsets() {
1598 let (offset, export) = export?;
1599 self.newline(offset)?;
1600 self.print_export(state, &export)?;
1601 }
1602 Ok(())
1603 }
1604
1605 fn print_export(&mut self, state: &State, export: &Export) -> Result<()> {
1606 self.start_group("export ")?;
1607 self.print_str(export.name)?;
1608 self.result.write_str(" ")?;
1609 self.print_external_kind(state, export.kind, export.index)?;
1610 self.end_group()?; Ok(())
1612 }
1613
1614 fn print_external_kind(&mut self, state: &State, kind: ExternalKind, index: u32) -> Result<()> {
1615 match kind {
1616 ExternalKind::Func => {
1617 self.start_group("func ")?;
1618 self.print_idx(&state.core.func_names, index)?;
1619 }
1620 ExternalKind::Table => {
1621 self.start_group("table ")?;
1622 self.print_idx(&state.core.table_names, index)?;
1623 }
1624 ExternalKind::Global => {
1625 self.start_group("global ")?;
1626 self.print_idx(&state.core.global_names, index)?;
1627 }
1628 ExternalKind::Memory => {
1629 self.start_group("memory ")?;
1630 self.print_idx(&state.core.memory_names, index)?;
1631 }
1632 ExternalKind::Tag => {
1633 self.start_group("tag ")?;
1634 write!(self.result, "{index}")?;
1635 }
1636 }
1637 self.end_group()?;
1638 Ok(())
1639 }
1640
1641 fn print_core_type_ref(&mut self, state: &State, idx: u32) -> Result<()> {
1642 self.start_group("type ")?;
1643 self.print_idx(&state.core.type_names, idx)?;
1644 self.end_group()?;
1645 Ok(())
1646 }
1647
1648 fn print_idx<K>(&mut self, names: &NamingMap<u32, K>, idx: u32) -> Result<()>
1653 where
1654 K: NamingNamespace,
1655 {
1656 self._print_idx(&names.index_to_name, idx, K::desc())
1657 }
1658
1659 fn _print_idx(&mut self, names: &HashMap<u32, Naming>, idx: u32, desc: &str) -> Result<()> {
1660 self.result.start_name()?;
1661 match names.get(&idx) {
1662 Some(name) => name.write_identifier(self)?,
1663 None if self.config.name_unnamed => write!(self.result, "$#{desc}{idx}")?,
1664 None => write!(self.result, "{idx}")?,
1665 }
1666 self.result.reset_color()?;
1667 Ok(())
1668 }
1669
1670 fn print_local_idx(&mut self, state: &State, func: u32, idx: u32) -> Result<()> {
1671 self.result.start_name()?;
1672 match state.core.local_names.index_to_name.get(&(func, idx)) {
1673 Some(name) => name.write_identifier(self)?,
1674 None if self.config.name_unnamed => write!(self.result, "$#local{idx}")?,
1675 None => write!(self.result, "{idx}")?,
1676 }
1677 self.result.reset_color()?;
1678 Ok(())
1679 }
1680
1681 fn print_field_idx(&mut self, state: &State, ty: u32, idx: u32) -> Result<()> {
1682 self.result.start_name()?;
1683 match state.core.field_names.index_to_name.get(&(ty, idx)) {
1684 Some(name) => name.write_identifier(self)?,
1685 None if self.config.name_unnamed => write!(self.result, "$#field{idx}")?,
1686 None => write!(self.result, "{idx}")?,
1687 }
1688 self.result.reset_color()?;
1689 Ok(())
1690 }
1691
1692 fn print_name<K>(&mut self, names: &NamingMap<u32, K>, cur_idx: u32) -> Result<()>
1693 where
1694 K: NamingNamespace,
1695 {
1696 self._print_name(&names.index_to_name, cur_idx, K::desc())
1697 }
1698
1699 fn _print_name(
1700 &mut self,
1701 names: &HashMap<u32, Naming>,
1702 cur_idx: u32,
1703 desc: &str,
1704 ) -> Result<()> {
1705 self.result.start_name()?;
1706 match names.get(&cur_idx) {
1707 Some(name) => {
1708 name.write(self)?;
1709 self.result.write_str(" ")?;
1710 }
1711 None if self.config.name_unnamed => {
1712 write!(self.result, "$#{desc}{cur_idx} ")?;
1713 }
1714 None => {}
1715 }
1716 write!(self.result, "(;{cur_idx};)")?;
1717 self.result.reset_color()?;
1718 Ok(())
1719 }
1720
1721 fn print_elems(&mut self, state: &mut State, data: ElementSectionReader) -> Result<()> {
1722 for (i, elem) in data.into_iter_with_offsets().enumerate() {
1723 let (offset, mut elem) = elem?;
1724 self.newline(offset)?;
1725 self.start_group("elem ")?;
1726 self.print_name(&state.core.element_names, i as u32)?;
1727 match &mut elem.kind {
1728 ElementKind::Passive => {}
1729 ElementKind::Declared => self.result.write_str(" declare")?,
1730 ElementKind::Active {
1731 table_index,
1732 offset_expr,
1733 } => {
1734 if let Some(table_index) = *table_index {
1735 self.result.write_str(" ")?;
1736 self.start_group("table ")?;
1737 self.print_idx(&state.core.table_names, table_index)?;
1738 self.end_group()?;
1739 }
1740 self.result.write_str(" ")?;
1741 self.print_const_expr_sugar(state, offset_expr, "offset")?;
1742 }
1743 }
1744 self.result.write_str(" ")?;
1745
1746 if self.config.print_skeleton {
1747 self.result.write_str("...")?;
1748 } else {
1749 match elem.items {
1750 ElementItems::Functions(reader) => {
1751 self.result.write_str("func")?;
1752 for idx in reader {
1753 self.result.write_str(" ")?;
1754 self.print_idx(&state.core.func_names, idx?)?
1755 }
1756 }
1757 ElementItems::Expressions(ty, reader) => {
1758 self.print_reftype(state, ty)?;
1759 for expr in reader {
1760 self.result.write_str(" ")?;
1761 self.print_const_expr_sugar(state, &expr?, "item")?
1762 }
1763 }
1764 }
1765 }
1766 self.end_group()?;
1767 }
1768 Ok(())
1769 }
1770
1771 fn print_data(&mut self, state: &mut State, data: DataSectionReader) -> Result<()> {
1772 for (i, data) in data.into_iter_with_offsets().enumerate() {
1773 let (offset, data) = data?;
1774 self.newline(offset)?;
1775 self.start_group("data ")?;
1776 self.print_name(&state.core.data_names, i as u32)?;
1777 self.result.write_str(" ")?;
1778 match &data.kind {
1779 DataKind::Passive => {}
1780 DataKind::Active {
1781 memory_index,
1782 offset_expr,
1783 } => {
1784 if *memory_index != 0 {
1785 self.start_group("memory ")?;
1786 self.print_idx(&state.core.memory_names, *memory_index)?;
1787 self.end_group()?;
1788 self.result.write_str(" ")?;
1789 }
1790 self.print_const_expr_sugar(state, offset_expr, "offset")?;
1791 self.result.write_str(" ")?;
1792 }
1793 }
1794 if self.config.print_skeleton {
1795 self.result.write_str("...")?;
1796 } else {
1797 self.print_bytes(data.data)?;
1798 }
1799 self.end_group()?;
1800 }
1801 Ok(())
1802 }
1803
1804 fn print_const_expr_sugar(
1808 &mut self,
1809 state: &mut State,
1810 expr: &ConstExpr,
1811 explicit: &str,
1812 ) -> Result<()> {
1813 self.start_group("")?;
1814 let mut reader = expr.get_operators_reader();
1815
1816 if reader.read().is_ok() && !reader.is_end_then_eof() {
1817 write!(self.result, "{explicit} ")?;
1818 self.print_const_expr(state, expr, self.config.fold_instructions)?;
1819 } else {
1820 self.print_const_expr(state, expr, false)?;
1821 }
1822
1823 self.end_group()?;
1824 Ok(())
1825 }
1826
1827 fn print_const_expr(&mut self, state: &mut State, expr: &ConstExpr, fold: bool) -> Result<()> {
1829 let mut reader = expr.get_binary_reader();
1830 let mut operator_state = OperatorState::new(self, OperatorSeparator::NoneThenSpace);
1831
1832 if fold {
1833 let mut folded_printer = PrintOperatorFolded::new(self, state, &mut operator_state);
1834 folded_printer.begin_const_expr();
1835 Self::print_operators(&mut reader, &[], 0, &mut folded_printer, None)?;
1836 } else {
1837 let mut op_printer = PrintOperator::new(self, state, &mut operator_state);
1838 Self::print_operators(&mut reader, &[], 0, &mut op_printer, None)?;
1839 }
1840
1841 Ok(())
1842 }
1843
1844 fn print_str(&mut self, name: &str) -> Result<()> {
1845 self.result.start_literal()?;
1846 self.result.write_str("\"")?;
1847 self.print_str_contents(name)?;
1848 self.result.write_str("\"")?;
1849 self.result.reset_color()?;
1850 Ok(())
1851 }
1852
1853 fn print_str_contents(&mut self, name: &str) -> Result<()> {
1854 for c in name.chars() {
1855 let v = c as u32;
1856 if (0x20..0x7f).contains(&v) && c != '"' && c != '\\' && v < 0xff {
1857 write!(self.result, "{c}")?;
1858 } else {
1859 write!(self.result, "\\u{{{v:x}}}",)?;
1860 }
1861 }
1862 Ok(())
1863 }
1864
1865 fn print_bytes(&mut self, bytes: &[u8]) -> Result<()> {
1866 self.result.start_literal()?;
1867 self.result.write_str("\"")?;
1868 for byte in bytes {
1869 if *byte >= 0x20 && *byte < 0x7f && *byte != b'"' && *byte != b'\\' {
1870 write!(self.result, "{}", *byte as char)?;
1871 } else {
1872 self.hex_byte(*byte)?;
1873 }
1874 }
1875 self.result.write_str("\"")?;
1876 self.result.reset_color()?;
1877 Ok(())
1878 }
1879
1880 fn hex_byte(&mut self, byte: u8) -> Result<()> {
1881 write!(self.result, "\\{byte:02x}")?;
1882 Ok(())
1883 }
1884
1885 fn print_known_custom_section(&mut self, section: CustomSectionReader<'_>) -> Result<bool> {
1886 match section.as_known() {
1887 KnownCustom::Producers(s) => {
1891 self.newline(section.range().start)?;
1892 self.print_producers_section(s)?;
1893 Ok(true)
1894 }
1895 KnownCustom::Dylink0(s) => {
1896 self.newline(section.range().start)?;
1897 self.print_dylink0_section(s)?;
1898 Ok(true)
1899 }
1900
1901 KnownCustom::Name(_) | KnownCustom::BranchHints(_) => Ok(true),
1904 #[cfg(feature = "component-model")]
1905 KnownCustom::ComponentName(_) => Ok(true),
1906
1907 _ => Ok(false),
1908 }
1909 }
1910
1911 fn print_raw_custom_section(
1912 &mut self,
1913 state: &State,
1914 section: CustomSectionReader<'_>,
1915 ) -> Result<()> {
1916 self.newline(section.range().start)?;
1917 self.start_group("@custom ")?;
1918 self.print_str(section.name())?;
1919 if let Some((place, _)) = state.custom_section_place {
1920 write!(self.result, " ({place})")?;
1921 }
1922 self.result.write_str(" ")?;
1923 if self.config.print_skeleton {
1924 self.result.write_str("...")?;
1925 } else {
1926 self.print_bytes(section.data())?;
1927 }
1928 self.end_group()?;
1929 Ok(())
1930 }
1931
1932 fn print_producers_section(&mut self, section: ProducersSectionReader<'_>) -> Result<()> {
1933 self.start_group("@producers")?;
1934 for field in section {
1935 let field = field?;
1936 for value in field.values.into_iter_with_offsets() {
1937 let (offset, value) = value?;
1938 self.newline(offset)?;
1939 self.start_group(field.name)?;
1940 self.result.write_str(" ")?;
1941 self.print_str(value.name)?;
1942 self.result.write_str(" ")?;
1943 self.print_str(value.version)?;
1944 self.end_group()?;
1945 }
1946 }
1947 self.end_group()?;
1948 Ok(())
1949 }
1950
1951 fn print_dylink0_section(&mut self, mut section: Dylink0SectionReader<'_>) -> Result<()> {
1952 self.start_group("@dylink.0")?;
1953 loop {
1954 let start = section.original_position();
1955 let next = match section.next() {
1956 Some(Ok(next)) => next,
1957 Some(Err(e)) => return Err(e.into()),
1958 None => break,
1959 };
1960 match next {
1961 Dylink0Subsection::MemInfo(info) => {
1962 self.newline(start)?;
1963 self.start_group("mem-info")?;
1964 if info.memory_size > 0 || info.memory_alignment > 0 {
1965 write!(
1966 self.result,
1967 " (memory {} {})",
1968 info.memory_size, info.memory_alignment
1969 )?;
1970 }
1971 if info.table_size > 0 || info.table_alignment > 0 {
1972 write!(
1973 self.result,
1974 " (table {} {})",
1975 info.table_size, info.table_alignment
1976 )?;
1977 }
1978 self.end_group()?;
1979 }
1980 Dylink0Subsection::Needed(needed) => {
1981 self.newline(start)?;
1982 self.start_group("needed")?;
1983 for s in needed {
1984 self.result.write_str(" ")?;
1985 self.print_str(s)?;
1986 }
1987 self.end_group()?;
1988 }
1989 Dylink0Subsection::ExportInfo(info) => {
1990 for info in info {
1991 self.newline(start)?;
1992 self.start_group("export-info ")?;
1993 self.print_str(info.name)?;
1994 self.print_dylink0_flags(info.flags)?;
1995 self.end_group()?;
1996 }
1997 }
1998 Dylink0Subsection::ImportInfo(info) => {
1999 for info in info {
2000 self.newline(start)?;
2001 self.start_group("import-info ")?;
2002 self.print_str(info.module)?;
2003 self.result.write_str(" ")?;
2004 self.print_str(info.field)?;
2005 self.print_dylink0_flags(info.flags)?;
2006 self.end_group()?;
2007 }
2008 }
2009 Dylink0Subsection::RuntimePath(runtime_path) => {
2010 self.newline(start)?;
2011 self.start_group("runtime-path")?;
2012 for s in runtime_path {
2013 self.result.write_str(" ")?;
2014 self.print_str(s)?;
2015 }
2016 self.end_group()?;
2017 }
2018 Dylink0Subsection::Unknown { ty, .. } => {
2019 bail!("don't know how to print dylink.0 subsection id {ty}");
2020 }
2021 }
2022 }
2023 self.end_group()?;
2024 Ok(())
2025 }
2026
2027 fn print_dylink0_flags(&mut self, mut flags: SymbolFlags) -> Result<()> {
2028 macro_rules! print_flag {
2029 ($($name:ident = $text:tt)*) => ({$(
2030 if flags.contains(SymbolFlags::$name) {
2031 flags.remove(SymbolFlags::$name);
2032 write!(self.result, concat!(" ", $text))?;
2033 }
2034 )*})
2035 }
2036 print_flag! {
2038 BINDING_WEAK = "binding-weak"
2039 BINDING_LOCAL = "binding-local"
2040 VISIBILITY_HIDDEN = "visibility-hidden"
2041 UNDEFINED = "undefined"
2042 EXPORTED = "exported"
2043 EXPLICIT_NAME = "explicit-name"
2044 NO_STRIP = "no-strip"
2045 TLS = "tls"
2046 ABSOLUTE = "absolute"
2047 }
2048 if !flags.is_empty() {
2049 write!(self.result, " {flags:#x}")?;
2050 }
2051 Ok(())
2052 }
2053
2054 fn register_branch_hint_section(&mut self, section: BranchHintSectionReader<'_>) -> Result<()> {
2055 self.code_section_hints.clear();
2056 for func in section {
2057 let func = func?;
2058 if self.code_section_hints.len() >= MAX_WASM_FUNCTIONS as usize {
2059 bail!("found too many hints");
2060 }
2061 if func.hints.count() >= MAX_WASM_FUNCTION_SIZE {
2062 bail!("found too many hints");
2063 }
2064 let hints = func
2065 .hints
2066 .into_iter_with_offsets()
2067 .collect::<wasmparser::Result<Vec<_>>>()?;
2068 self.code_section_hints.push((func.func, hints));
2069 }
2070 self.code_section_hints.reverse();
2071 Ok(())
2072 }
2073}
2074
2075struct NamedLocalPrinter {
2076 group_name: &'static str,
2077 in_group: bool,
2078 end_group_after_local: bool,
2079 first: bool,
2080}
2081
2082impl NamedLocalPrinter {
2083 fn new(group_name: &'static str) -> NamedLocalPrinter {
2084 NamedLocalPrinter {
2085 group_name,
2086 in_group: false,
2087 end_group_after_local: false,
2088 first: true,
2089 }
2090 }
2091
2092 fn start_local(
2093 &mut self,
2094 func: Option<u32>,
2095 local: u32,
2096 dst: &mut Printer,
2097 state: &State,
2098 ) -> Result<()> {
2099 let name = state
2100 .core
2101 .local_names
2102 .index_to_name
2103 .get(&(func.unwrap_or(u32::MAX), local));
2104
2105 if name.is_some() && self.in_group {
2108 dst.end_group()?;
2109 self.in_group = false;
2110 }
2111
2112 if self.first {
2113 self.first = false;
2114 } else {
2115 dst.result.write_str(" ")?;
2116 }
2117
2118 if !self.in_group {
2121 dst.start_group(self.group_name)?;
2122 dst.result.write_str(" ")?;
2123 self.in_group = true;
2124 }
2125
2126 match name {
2128 Some(name) => {
2129 name.write(dst)?;
2130 dst.result.write_str(" ")?;
2131 self.end_group_after_local = true;
2132 }
2133 None if dst.config.name_unnamed && func.is_some() => {
2134 write!(dst.result, "$#local{local} ")?;
2135 self.end_group_after_local = true;
2136 }
2137 None => {
2138 self.end_group_after_local = false;
2139 }
2140 }
2141 Ok(())
2142 }
2143
2144 fn end_local(&mut self, dst: &mut Printer) -> Result<()> {
2145 if self.end_group_after_local {
2146 dst.end_group()?;
2147 self.end_group_after_local = false;
2148 self.in_group = false;
2149 }
2150 Ok(())
2151 }
2152 fn finish(self, dst: &mut Printer) -> Result<()> {
2153 if self.in_group {
2154 dst.end_group()?;
2155 }
2156 Ok(())
2157 }
2158}
2159
2160macro_rules! print_float {
2161 ($name:ident $float:ident $uint:ident $sint:ident $exp_bits:tt) => {
2162 fn $name(&mut self, mut bits: $uint) -> Result<()> {
2163 let int_width = mem::size_of::<$uint>() * 8;
2165 let exp_width = $exp_bits;
2166 let mantissa_width = int_width - 1 - exp_width;
2167 let bias = (1 << (exp_width - 1)) - 1;
2168 let max_exp = (1 as $sint) << (exp_width - 1);
2169 let min_exp = -max_exp + 1;
2170
2171 let f = $float::from_bits(bits);
2173 if bits >> (int_width - 1) != 0 {
2174 bits ^= 1 << (int_width - 1);
2175 self.result.write_str("-")?;
2176 }
2177 if f.is_infinite() {
2178 self.result.start_literal()?;
2179 self.result.write_str("inf ")?;
2180 self.result.start_comment()?;
2181 write!(self.result, "(;={f};)")?;
2182 self.result.reset_color()?;
2183 return Ok(());
2184 }
2185 if f.is_nan() {
2186 let payload = bits & ((1 << mantissa_width) - 1);
2187 self.result.start_literal()?;
2188 if payload == 1 << (mantissa_width - 1) {
2189 self.result.write_str("nan ")?;
2190 self.result.start_comment()?;
2191 write!(self.result, "(;={f};)")?;
2192 } else {
2193 write!(self.result, "nan:{:#x} ", payload)?;
2194 self.result.start_comment()?;
2195 write!(self.result, "(;={f};)")?;
2196 }
2197 self.result.reset_color()?;
2198 return Ok(());
2199 }
2200
2201 let mut exponent = (((bits << 1) as $sint) >> (mantissa_width + 1)).wrapping_sub(bias);
2217 exponent = (exponent << (int_width - exp_width)) >> (int_width - exp_width);
2218 let mut fraction = bits & ((1 << mantissa_width) - 1);
2219 self.result.start_literal()?;
2220 self.result.write_str("0x")?;
2221 if bits == 0 {
2222 self.result.write_str("0p+0")?;
2223 } else {
2224 self.result.write_str("1")?;
2225 if fraction > 0 {
2226 fraction <<= (int_width - mantissa_width);
2227
2228 if exponent == min_exp {
2232 let leading = fraction.leading_zeros();
2233 if (leading as usize) < int_width - 1 {
2234 fraction <<= leading + 1;
2235 } else {
2236 fraction = 0;
2237 }
2238 exponent -= leading as $sint;
2239 }
2240
2241 self.result.write_str(".")?;
2242 while fraction > 0 {
2243 write!(self.result, "{:x}", fraction >> (int_width - 4))?;
2244 fraction <<= 4;
2245 }
2246 }
2247 write!(self.result, "p{:+}", exponent)?;
2248 }
2249 self.result.start_comment()?;
2250 write!(self.result, " (;={};)", f)?;
2251 self.result.reset_color()?;
2252 Ok(())
2253 }
2254 };
2255}
2256
2257impl Printer<'_, '_> {
2258 print_float!(print_f32 f32 u32 i32 8);
2259 print_float!(print_f64 f64 u64 i64 11);
2260}
2261
2262impl Naming {
2263 fn new<'a>(
2264 name: &'a str,
2265 index: u32,
2266 group: &str,
2267 used: Option<&mut HashSet<&'a str>>,
2268 ) -> Naming {
2269 let mut kind = NamingKind::DollarName;
2270 if name.chars().any(|c| !is_idchar(c)) {
2271 kind = NamingKind::DollarQuotedName;
2272 }
2273
2274 if name.is_empty()
2293 || name.starts_with('#')
2294 || used.map(|set| !set.insert(name)).unwrap_or(false)
2295 {
2296 kind = NamingKind::SyntheticPrefix(format!("#{group}{index}"));
2297 }
2298 return Naming {
2299 kind,
2300 name: name.to_string(),
2301 };
2302
2303 fn is_idchar(c: char) -> bool {
2305 matches!(
2306 c,
2307 '0'..='9'
2308 | 'a'..='z'
2309 | 'A'..='Z'
2310 | '!'
2311 | '#'
2312 | '$'
2313 | '%'
2314 | '&'
2315 | '\''
2316 | '*'
2317 | '+'
2318 | '-'
2319 | '.'
2320 | '/'
2321 | ':'
2322 | '<'
2323 | '='
2324 | '>'
2325 | '?'
2326 | '@'
2327 | '\\'
2328 | '^'
2329 | '_'
2330 | '`'
2331 | '|'
2332 | '~'
2333 )
2334 }
2335 }
2336
2337 fn write_identifier(&self, printer: &mut Printer<'_, '_>) -> Result<()> {
2338 match &self.kind {
2339 NamingKind::DollarName => {
2340 printer.result.write_str("$")?;
2341 printer.result.write_str(&self.name)?;
2342 }
2343 NamingKind::DollarQuotedName => {
2344 printer.result.write_str("$\"")?;
2345 printer.print_str_contents(&self.name)?;
2346 printer.result.write_str("\"")?;
2347 }
2348 NamingKind::SyntheticPrefix(prefix) => {
2349 printer.result.write_str("$\"")?;
2350 printer.result.write_str(&prefix)?;
2351 printer.result.write_str(" ")?;
2352 printer.print_str_contents(&self.name)?;
2353 printer.result.write_str("\"")?;
2354 }
2355 }
2356 Ok(())
2357 }
2358
2359 fn write(&self, dst: &mut Printer<'_, '_>) -> Result<()> {
2360 self.write_identifier(dst)?;
2361 match &self.kind {
2362 NamingKind::DollarName | NamingKind::DollarQuotedName => {}
2363
2364 NamingKind::SyntheticPrefix(_) => {
2365 dst.result.write_str(" ")?;
2366 dst.start_group("@name \"")?;
2367 dst.print_str_contents(&self.name)?;
2368 dst.result.write_str("\"")?;
2369 dst.end_group()?;
2370 }
2371 }
2372 Ok(())
2373 }
2374}
2375
2376trait NamingNamespace {
2378 fn desc() -> &'static str;
2379}
2380
2381macro_rules! naming_namespaces {
2382 ($(struct $name:ident => $desc:tt)*) => ($(
2383 struct $name;
2384
2385 impl NamingNamespace for $name {
2386 fn desc() -> &'static str { $desc }
2387 }
2388 )*)
2389}
2390
2391naming_namespaces! {
2392 struct NameFunc => "func"
2393 struct NameGlobal => "global"
2394 struct NameMemory => "memory"
2395 struct NameLocal => "local"
2396 struct NameLabel => "label"
2397 struct NameTable => "table"
2398 struct NameType => "type"
2399 struct NameField => "field"
2400 struct NameData => "data"
2401 struct NameElem => "elem"
2402 struct NameTag => "tag"
2403}
2404
2405#[cfg(feature = "component-model")]
2406naming_namespaces! {
2407 struct NameModule => "module"
2408 struct NameInstance => "instance"
2409 struct NameValue => "value"
2410 struct NameComponent => "component"
2411}
2412
2413fn name_map<K>(into: &mut NamingMap<u32, K>, names: NameMap<'_>, name: &str) -> Result<()> {
2414 let mut used = HashSet::new();
2415 for naming in names {
2416 let naming = naming?;
2417 into.index_to_name.insert(
2418 naming.index,
2419 Naming::new(naming.name, naming.index, name, Some(&mut used)),
2420 );
2421 }
2422 Ok(())
2423}