1#![deny(missing_docs)]
10#![cfg_attr(docsrs, feature(doc_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_at_pos(offset)?; #[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.result.newline()?;
762 break;
763 }
764
765 other => match other.as_section() {
766 Some((id, _)) => bail!("found unknown section `{}`", id),
767 None => bail!("found unknown payload"),
768 },
769 }
770 }
771
772 Ok(())
773 }
774
775 fn update_custom_section_place(&self, states: &mut Vec<State>, place: &'static str) {
776 if let Some(last) = states.last_mut() {
777 if let Some((prev, prev_line)) = &mut last.custom_section_place {
778 if *prev_line != self.line {
779 *prev = place;
780 *prev_line = self.line;
781 }
782 }
783 }
784 }
785
786 fn update_custom_section_line(&self, states: &mut Vec<State>) {
787 if let Some(last) = states.last_mut() {
788 if let Some((_, prev_line)) = &mut last.custom_section_place {
789 *prev_line = self.line;
790 }
791 }
792 }
793
794 fn start_group(&mut self, name: &str) -> Result<()> {
795 write!(self.result, "(")?;
796 self.result.start_keyword()?;
797 write!(self.result, "{name}")?;
798 self.result.reset_color()?;
799 self.nesting += 1;
800 self.group_lines.push(self.line);
801 Ok(())
802 }
803
804 fn end_group(&mut self) -> Result<()> {
805 self.nesting -= 1;
806 if let Some(line) = self.group_lines.pop() {
807 if line != self.line {
808 self.newline_unknown_pos()?;
809 }
810 }
811 self.result.write_str(")")?;
812 Ok(())
813 }
814
815 fn end_group_at_pos(&mut self, offset: usize) -> Result<()> {
816 self.nesting -= 1;
817 let start_group_line = self.group_lines.pop();
818 if self.config.print_offsets {
819 self.newline(offset)?;
820 } else if let Some(line) = start_group_line {
821 if line != self.line {
822 self.newline(offset)?;
823 }
824 }
825 self.result.write_str(")")?;
826 Ok(())
827 }
828
829 fn register_names(&mut self, state: &mut State, names: NameSectionReader<'_>) -> Result<()> {
830 fn indirect_name_map<K>(
831 into: &mut NamingMap<(u32, u32), K>,
832 names: IndirectNameMap<'_>,
833 name: &str,
834 ) -> Result<()> {
835 for indirect in names {
836 let indirect = indirect?;
837 let mut used = match name {
838 "label" => None,
840 "local" | "field" => Some(HashSet::new()),
841 _ => unimplemented!("{name} is an unknown type of indirect names"),
842 };
843 for naming in indirect.names {
844 let naming = naming?;
845 into.index_to_name.insert(
846 (indirect.index, naming.index),
847 Naming::new(naming.name, naming.index, name, used.as_mut()),
848 );
849 }
850 }
851 Ok(())
852 }
853
854 for section in names {
855 match section? {
856 Name::Module { name, .. } => {
857 let name = Naming::new(name, 0, "module", None);
858 state.name = Some(name);
859 }
860 Name::Function(n) => name_map(&mut state.core.func_names, n, "func")?,
861 Name::Local(n) => indirect_name_map(&mut state.core.local_names, n, "local")?,
862 Name::Label(n) => indirect_name_map(&mut state.core.label_names, n, "label")?,
863 Name::Type(n) => name_map(&mut state.core.type_names, n, "type")?,
864 Name::Table(n) => name_map(&mut state.core.table_names, n, "table")?,
865 Name::Memory(n) => name_map(&mut state.core.memory_names, n, "memory")?,
866 Name::Global(n) => name_map(&mut state.core.global_names, n, "global")?,
867 Name::Element(n) => name_map(&mut state.core.element_names, n, "elem")?,
868 Name::Data(n) => name_map(&mut state.core.data_names, n, "data")?,
869 Name::Field(n) => indirect_name_map(&mut state.core.field_names, n, "field")?,
870 Name::Tag(n) => name_map(&mut state.core.tag_names, n, "tag")?,
871 Name::Unknown { .. } => (),
872 }
873 }
874 Ok(())
875 }
876
877 fn print_rec(
878 &mut self,
879 state: &mut State,
880 offset: Option<usize>,
881 rec: RecGroup,
882 is_component: bool,
883 ) -> Result<()> {
884 if rec.is_explicit_rec_group() {
885 if is_component {
886 self.start_group("core rec")?;
887 } else {
888 self.start_group("rec")?;
889 }
890 for ty in rec.into_types() {
891 match offset {
892 Some(offset) => self.newline(offset + 2)?,
893 None => self.newline_unknown_pos()?,
894 }
895 self.print_type(state, ty, false)?;
896 }
897 self.end_group()?; } else {
899 assert_eq!(rec.types().len(), 1);
900 let ty = rec.into_types().next().unwrap();
901 self.print_type(state, ty, is_component)?;
902 }
903 Ok(())
904 }
905
906 fn print_type(&mut self, state: &mut State, ty: SubType, is_component: bool) -> Result<()> {
907 if is_component {
908 self.start_group("core type ")?;
909 } else {
910 self.start_group("type ")?;
911 }
912 let ty_idx = state.core.types.len() as u32;
913 self.print_name(&state.core.type_names, ty_idx)?;
914 self.result.write_str(" ")?;
915 self.print_sub(state, &ty, ty_idx)?;
916 self.end_group()?; state.core.types.push(Some(ty));
918 Ok(())
919 }
920
921 fn print_sub(&mut self, state: &State, ty: &SubType, ty_idx: u32) -> Result<u32> {
922 let r = if !ty.is_final || !ty.supertype_idx.is_none() {
923 self.start_group("sub")?;
924 self.print_sub_type(state, ty)?;
925 let r = self.print_composite(state, &ty.composite_type, ty_idx)?;
926 self.end_group()?; r
928 } else {
929 self.print_composite(state, &ty.composite_type, ty_idx)?
930 };
931 Ok(r)
932 }
933
934 fn print_composite(&mut self, state: &State, ty: &CompositeType, ty_idx: u32) -> Result<u32> {
935 if ty.shared {
936 self.start_group("shared")?;
937 self.result.write_str(" ")?;
938 }
939 if let Some(idx) = ty.describes_idx {
940 self.start_group("describes")?;
941 self.result.write_str(" ")?;
942 self.print_idx(&state.core.type_names, idx.as_module_index().unwrap())?;
943 self.end_group()?;
944 self.result.write_str(" ")?;
945 }
946 if let Some(idx) = ty.descriptor_idx {
947 self.start_group("descriptor")?;
948 self.result.write_str(" ")?;
949 self.print_idx(&state.core.type_names, idx.as_module_index().unwrap())?;
950 self.end_group()?;
951 self.result.write_str(" ")?;
952 }
953 let r = match &ty.inner {
954 CompositeInnerType::Func(ty) => {
955 self.start_group("func")?;
956 let r = self.print_func_type(state, ty, None)?;
957 self.end_group()?; r
959 }
960 CompositeInnerType::Array(ty) => {
961 self.start_group("array")?;
962 let r = self.print_array_type(state, ty)?;
963 self.end_group()?; r
965 }
966 CompositeInnerType::Struct(ty) => {
967 self.start_group("struct")?;
968 let r = self.print_struct_type(state, ty, ty_idx)?;
969 self.end_group()?; r
971 }
972 CompositeInnerType::Cont(ty) => {
973 self.start_group("cont")?;
974 let r = self.print_cont_type(state, ty)?;
975 self.end_group()?; r
977 }
978 };
979 if ty.shared {
980 self.end_group()?; }
982 Ok(r)
983 }
984
985 fn print_types(&mut self, state: &mut State, parser: TypeSectionReader<'_>) -> Result<()> {
986 for ty in parser.into_iter_with_offsets() {
987 let (offset, rec_group) = ty?;
988 self.newline(offset)?;
989 self.print_rec(state, Some(offset), rec_group, false)?;
990 }
991 Ok(())
992 }
993
994 fn print_core_functype_idx(
995 &mut self,
996 state: &State,
997 idx: u32,
998 names_for: Option<u32>,
999 ) -> Result<Option<u32>> {
1000 self.print_core_type_ref(state, idx)?;
1001
1002 match state.core.types.get(idx as usize) {
1003 Some(Some(SubType {
1004 composite_type:
1005 CompositeType {
1006 inner: CompositeInnerType::Func(ty),
1007 shared: false,
1008 descriptor_idx: None,
1009 describes_idx: None,
1010 },
1011 ..
1012 })) => self.print_func_type(state, ty, names_for).map(Some),
1013 Some(Some(_)) | Some(None) | None => Ok(None),
1014 }
1015 }
1016
1017 fn print_func_type(
1020 &mut self,
1021 state: &State,
1022 ty: &FuncType,
1023 names_for: Option<u32>,
1024 ) -> Result<u32> {
1025 if !ty.params().is_empty() {
1026 self.result.write_str(" ")?;
1027 }
1028
1029 let mut params = NamedLocalPrinter::new("param");
1030 for (i, param) in ty.params().iter().enumerate() {
1034 params.start_local(names_for, i as u32, self, state)?;
1035 self.print_valtype(state, *param)?;
1036 params.end_local(self)?;
1037 }
1038 params.finish(self)?;
1039 if !ty.results().is_empty() {
1040 self.result.write_str(" ")?;
1041 self.start_group("result")?;
1042 for result in ty.results().iter() {
1043 self.result.write_str(" ")?;
1044 self.print_valtype(state, *result)?;
1045 }
1046 self.end_group()?;
1047 }
1048 Ok(ty.params().len() as u32)
1049 }
1050
1051 fn print_field_type(
1052 &mut self,
1053 state: &State,
1054 ty: &FieldType,
1055 ty_field_idx: Option<(u32, u32)>,
1056 ) -> Result<u32> {
1057 self.result.write_str(" ")?;
1058 if let Some(idxs @ (_, field_idx)) = ty_field_idx {
1059 match state.core.field_names.index_to_name.get(&idxs) {
1060 Some(name) => {
1061 name.write_identifier(self)?;
1062 self.result.write_str(" ")?;
1063 }
1064 None if self.config.name_unnamed => write!(self.result, "$#field{field_idx} ")?,
1065 None => {}
1066 }
1067 }
1068 if ty.mutable {
1069 self.result.write_str("(mut ")?;
1070 }
1071 self.print_storage_type(state, ty.element_type)?;
1072 if ty.mutable {
1073 self.result.write_str(")")?;
1074 }
1075 Ok(0)
1076 }
1077
1078 fn print_array_type(&mut self, state: &State, ty: &ArrayType) -> Result<u32> {
1079 self.print_field_type(state, &ty.0, None)
1080 }
1081
1082 fn print_struct_type(&mut self, state: &State, ty: &StructType, ty_idx: u32) -> Result<u32> {
1083 for (field_index, field) in ty.fields.iter().enumerate() {
1084 self.result.write_str(" (field")?;
1085 self.print_field_type(state, field, Some((ty_idx, field_index as u32)))?;
1086 self.result.write_str(")")?;
1087 }
1088 Ok(0)
1089 }
1090
1091 fn print_cont_type(&mut self, state: &State, ct: &ContType) -> Result<u32> {
1092 self.result.write_str(" ")?;
1093 self.print_idx(&state.core.type_names, ct.0.as_module_index().unwrap())?;
1094 Ok(0)
1095 }
1096
1097 fn print_sub_type(&mut self, state: &State, ty: &SubType) -> Result<u32> {
1098 self.result.write_str(" ")?;
1099 if ty.is_final {
1100 self.result.write_str("final ")?;
1101 }
1102 if let Some(idx) = ty.supertype_idx {
1103 self.print_idx(&state.core.type_names, idx.as_module_index().unwrap())?;
1104 self.result.write_str(" ")?;
1105 }
1106 Ok(0)
1107 }
1108
1109 fn print_storage_type(&mut self, state: &State, ty: StorageType) -> Result<()> {
1110 match ty {
1111 StorageType::I8 => self.result.write_str("i8")?,
1112 StorageType::I16 => self.result.write_str("i16")?,
1113 StorageType::Val(val_type) => self.print_valtype(state, val_type)?,
1114 }
1115 Ok(())
1116 }
1117
1118 fn print_valtype(&mut self, state: &State, ty: ValType) -> Result<()> {
1119 match ty {
1120 ValType::I32 => self.print_type_keyword("i32")?,
1121 ValType::I64 => self.print_type_keyword("i64")?,
1122 ValType::F32 => self.print_type_keyword("f32")?,
1123 ValType::F64 => self.print_type_keyword("f64")?,
1124 ValType::V128 => self.print_type_keyword("v128")?,
1125 ValType::Ref(rt) => self.print_reftype(state, rt)?,
1126 }
1127 Ok(())
1128 }
1129
1130 fn print_valtypes(&mut self, state: &State, tys: Vec<ValType>) -> Result<()> {
1131 for ty in tys {
1132 self.result.write_str(" ")?;
1133 self.print_valtype(state, ty)?;
1134 }
1135 Ok(())
1136 }
1137
1138 fn print_reftype(&mut self, state: &State, ty: RefType) -> Result<()> {
1139 if ty.is_nullable() {
1140 match ty.as_non_null() {
1141 RefType::FUNC => self.print_type_keyword("funcref")?,
1142 RefType::EXTERN => self.print_type_keyword("externref")?,
1143 RefType::I31 => self.print_type_keyword("i31ref")?,
1144 RefType::ANY => self.print_type_keyword("anyref")?,
1145 RefType::NONE => self.print_type_keyword("nullref")?,
1146 RefType::NOEXTERN => self.print_type_keyword("nullexternref")?,
1147 RefType::NOFUNC => self.print_type_keyword("nullfuncref")?,
1148 RefType::EQ => self.print_type_keyword("eqref")?,
1149 RefType::STRUCT => self.print_type_keyword("structref")?,
1150 RefType::ARRAY => self.print_type_keyword("arrayref")?,
1151 RefType::EXN => self.print_type_keyword("exnref")?,
1152 RefType::NOEXN => self.print_type_keyword("nullexnref")?,
1153 _ => {
1154 self.start_group("ref")?;
1155 self.result.write_str(" null ")?;
1156 self.print_heaptype(state, ty.heap_type())?;
1157 self.end_group()?;
1158 }
1159 }
1160 } else {
1161 self.start_group("ref ")?;
1162 self.print_heaptype(state, ty.heap_type())?;
1163 self.end_group()?;
1164 }
1165 Ok(())
1166 }
1167
1168 fn print_heaptype(&mut self, state: &State, ty: HeapType) -> Result<()> {
1169 match ty {
1170 HeapType::Concrete(i) => {
1171 self.print_idx(&state.core.type_names, i.as_module_index().unwrap())?;
1172 }
1173 HeapType::Exact(i) => {
1174 self.start_group("exact ")?;
1175 self.print_idx(&state.core.type_names, i.as_module_index().unwrap())?;
1176 self.end_group()?;
1177 }
1178 HeapType::Abstract { shared, ty } => {
1179 use AbstractHeapType::*;
1180 if shared {
1181 self.start_group("shared ")?;
1182 }
1183 match ty {
1184 Func => self.print_type_keyword("func")?,
1185 Extern => self.print_type_keyword("extern")?,
1186 Any => self.print_type_keyword("any")?,
1187 None => self.print_type_keyword("none")?,
1188 NoExtern => self.print_type_keyword("noextern")?,
1189 NoFunc => self.print_type_keyword("nofunc")?,
1190 Eq => self.print_type_keyword("eq")?,
1191 Struct => self.print_type_keyword("struct")?,
1192 Array => self.print_type_keyword("array")?,
1193 I31 => self.print_type_keyword("i31")?,
1194 Exn => self.print_type_keyword("exn")?,
1195 NoExn => self.print_type_keyword("noexn")?,
1196 Cont => self.print_type_keyword("cont")?,
1197 NoCont => self.print_type_keyword("nocont")?,
1198 }
1199 if shared {
1200 self.end_group()?;
1201 }
1202 }
1203 }
1204 Ok(())
1205 }
1206
1207 fn print_type_keyword(&mut self, keyword: &str) -> Result<()> {
1208 self.result.start_type()?;
1209 self.result.write_str(keyword)?;
1210 self.result.reset_color()?;
1211 Ok(())
1212 }
1213
1214 fn print_imports(&mut self, state: &mut State, parser: ImportSectionReader<'_>) -> Result<()> {
1215 for import in parser.into_iter_with_offsets() {
1216 let (offset, import) = import?;
1217 self.newline(offset)?;
1218 self.print_import(state, &import, true)?;
1219 match import.ty {
1220 TypeRef::Func(idx) => {
1221 debug_assert!(state.core.func_to_type.len() == state.core.funcs as usize);
1222 state.core.funcs += 1;
1223 state.core.func_to_type.push(Some(idx))
1224 }
1225 TypeRef::Table(_) => state.core.tables += 1,
1226 TypeRef::Memory(_) => state.core.memories += 1,
1227 TypeRef::Tag(TagType {
1228 kind: _,
1229 func_type_idx: idx,
1230 }) => {
1231 debug_assert!(state.core.tag_to_type.len() == state.core.tags as usize);
1232 state.core.tags += 1;
1233 state.core.tag_to_type.push(Some(idx))
1234 }
1235 TypeRef::Global(_) => state.core.globals += 1,
1236 }
1237 }
1238 Ok(())
1239 }
1240
1241 fn print_import(&mut self, state: &State, import: &Import<'_>, index: bool) -> Result<()> {
1242 self.start_group("import ")?;
1243 self.print_str(import.module)?;
1244 self.result.write_str(" ")?;
1245 self.print_str(import.name)?;
1246 self.result.write_str(" ")?;
1247 self.print_import_ty(state, &import.ty, index)?;
1248 self.end_group()?;
1249 Ok(())
1250 }
1251
1252 fn print_import_ty(&mut self, state: &State, ty: &TypeRef, index: bool) -> Result<()> {
1253 match ty {
1254 TypeRef::Func(f) => {
1255 self.start_group("func ")?;
1256 if index {
1257 self.print_name(&state.core.func_names, state.core.funcs)?;
1258 self.result.write_str(" ")?;
1259 }
1260 self.print_core_type_ref(state, *f)?;
1261 }
1262 TypeRef::Table(f) => self.print_table_type(state, f, index)?,
1263 TypeRef::Memory(f) => self.print_memory_type(state, f, index)?,
1264 TypeRef::Tag(f) => self.print_tag_type(state, f, index)?,
1265 TypeRef::Global(f) => self.print_global_type(state, f, index)?,
1266 }
1267 self.end_group()?;
1268 Ok(())
1269 }
1270
1271 fn print_table_type(&mut self, state: &State, ty: &TableType, index: bool) -> Result<()> {
1272 self.start_group("table ")?;
1273 if index {
1274 self.print_name(&state.core.table_names, state.core.tables)?;
1275 self.result.write_str(" ")?;
1276 }
1277 if ty.shared {
1278 self.print_type_keyword("shared ")?;
1279 }
1280 if ty.table64 {
1281 self.print_type_keyword("i64 ")?;
1282 }
1283 self.print_limits(ty.initial, ty.maximum)?;
1284 self.result.write_str(" ")?;
1285 self.print_reftype(state, ty.element_type)?;
1286 Ok(())
1287 }
1288
1289 fn print_memory_type(&mut self, state: &State, ty: &MemoryType, index: bool) -> Result<()> {
1290 self.start_group("memory ")?;
1291 if index {
1292 self.print_name(&state.core.memory_names, state.core.memories)?;
1293 self.result.write_str(" ")?;
1294 }
1295 if ty.memory64 {
1296 self.print_type_keyword("i64 ")?;
1297 }
1298 self.print_limits(ty.initial, ty.maximum)?;
1299 if ty.shared {
1300 self.print_type_keyword(" shared")?;
1301 }
1302 if let Some(p) = ty.page_size_log2 {
1303 let p = 1_u64
1304 .checked_shl(p)
1305 .ok_or_else(|| anyhow!("left shift overflow").context("invalid page size"))?;
1306
1307 self.result.write_str(" ")?;
1308 self.start_group("pagesize ")?;
1309 write!(self.result, "{p:#x}")?;
1310 self.end_group()?;
1311 }
1312 Ok(())
1313 }
1314
1315 fn print_tag_type(&mut self, state: &State, ty: &TagType, index: bool) -> Result<()> {
1316 self.start_group("tag ")?;
1317 if index {
1318 self.print_name(&state.core.tag_names, state.core.tags)?;
1319 self.result.write_str(" ")?;
1320 }
1321 self.print_core_functype_idx(state, ty.func_type_idx, None)?;
1322 Ok(())
1323 }
1324
1325 fn print_limits<T>(&mut self, initial: T, maximum: Option<T>) -> Result<()>
1326 where
1327 T: fmt::Display,
1328 {
1329 self.result.start_literal()?;
1330 write!(self.result, "{initial}")?;
1331 if let Some(max) = maximum {
1332 write!(self.result, " {max}")?;
1333 }
1334 self.result.reset_color()?;
1335 Ok(())
1336 }
1337
1338 fn print_global_type(&mut self, state: &State, ty: &GlobalType, index: bool) -> Result<()> {
1339 self.start_group("global ")?;
1340 if index {
1341 self.print_name(&state.core.global_names, state.core.globals)?;
1342 self.result.write_str(" ")?;
1343 }
1344 if ty.shared || ty.mutable {
1345 self.result.write_str("(")?;
1346 if ty.shared {
1347 self.print_type_keyword("shared ")?;
1348 }
1349 if ty.mutable {
1350 self.print_type_keyword("mut ")?;
1351 }
1352 self.print_valtype(state, ty.content_type)?;
1353 self.result.write_str(")")?;
1354 } else {
1355 self.print_valtype(state, ty.content_type)?;
1356 }
1357 Ok(())
1358 }
1359
1360 fn print_tables(&mut self, state: &mut State, parser: TableSectionReader<'_>) -> Result<()> {
1361 for table in parser.into_iter_with_offsets() {
1362 let (offset, table) = table?;
1363 self.newline(offset)?;
1364 self.print_table_type(state, &table.ty, true)?;
1365 match &table.init {
1366 TableInit::RefNull => {}
1367 TableInit::Expr(expr) => {
1368 self.result.write_str(" ")?;
1369 self.print_const_expr(state, expr, self.config.fold_instructions)?;
1370 }
1371 }
1372 self.end_group()?;
1373 state.core.tables += 1;
1374 }
1375 Ok(())
1376 }
1377
1378 fn print_memories(&mut self, state: &mut State, parser: MemorySectionReader<'_>) -> Result<()> {
1379 for memory in parser.into_iter_with_offsets() {
1380 let (offset, memory) = memory?;
1381 self.newline(offset)?;
1382 self.print_memory_type(state, &memory, true)?;
1383 self.end_group()?;
1384 state.core.memories += 1;
1385 }
1386 Ok(())
1387 }
1388
1389 fn print_tags(&mut self, state: &mut State, parser: TagSectionReader<'_>) -> Result<()> {
1390 for tag in parser.into_iter_with_offsets() {
1391 let (offset, tag) = tag?;
1392 self.newline(offset)?;
1393 self.print_tag_type(state, &tag, true)?;
1394 self.end_group()?;
1395 debug_assert!(state.core.tag_to_type.len() == state.core.tags as usize);
1396 state.core.tags += 1;
1397 state.core.tag_to_type.push(Some(tag.func_type_idx));
1398 }
1399 Ok(())
1400 }
1401
1402 fn print_globals(&mut self, state: &mut State, parser: GlobalSectionReader<'_>) -> Result<()> {
1403 for global in parser.into_iter_with_offsets() {
1404 let (offset, global) = global?;
1405 self.newline(offset)?;
1406 self.print_global_type(state, &global.ty, true)?;
1407 self.result.write_str(" ")?;
1408 self.print_const_expr(state, &global.init_expr, self.config.fold_instructions)?;
1409 self.end_group()?;
1410 state.core.globals += 1;
1411 }
1412 Ok(())
1413 }
1414
1415 fn print_code_section_entry(
1416 &mut self,
1417 state: &mut State,
1418 body: &FunctionBody<'_>,
1419 validator: Option<operand_stack::FuncValidator>,
1420 ) -> Result<()> {
1421 self.newline(body.get_binary_reader().original_position())?;
1422 self.start_group("func ")?;
1423 let func_idx = state.core.funcs;
1424 self.print_name(&state.core.func_names, func_idx)?;
1425 self.result.write_str(" ")?;
1426 let ty = match state.core.func_to_type.get(func_idx as usize) {
1427 Some(Some(x)) => *x,
1428 _ => panic!("invalid function type"),
1429 };
1430 let params = self
1431 .print_core_functype_idx(state, ty, Some(func_idx))?
1432 .unwrap_or(0);
1433
1434 let hints = match self.code_section_hints.last() {
1437 Some((f, _)) if *f == func_idx => {
1438 let (_, hints) = self.code_section_hints.pop().unwrap();
1439 hints
1440 }
1441 _ => Vec::new(),
1442 };
1443
1444 if self.config.print_skeleton {
1445 self.result.write_str(" ...")?;
1446 self.end_group()?;
1447 } else {
1448 let end_pos =
1449 self.print_func_body(state, func_idx, params, &body, &hints, validator)?;
1450 self.end_group_at_pos(end_pos)?;
1451 }
1452
1453 state.core.funcs += 1;
1454 Ok(())
1455 }
1456
1457 fn print_func_body(
1458 &mut self,
1459 state: &mut State,
1460 func_idx: u32,
1461 params: u32,
1462 body: &FunctionBody<'_>,
1463 branch_hints: &[(usize, BranchHint)],
1464 mut validator: Option<operand_stack::FuncValidator>,
1465 ) -> Result<usize> {
1466 let mut first = true;
1467 let mut local_idx = 0;
1468 let mut locals = NamedLocalPrinter::new("local");
1469 let mut reader = body.get_binary_reader();
1470 let func_start = reader.original_position();
1471 for _ in 0..reader.read_var_u32()? {
1472 let offset = reader.original_position();
1473 let cnt = reader.read_var_u32()?;
1474 let ty = reader.read()?;
1475 if MAX_LOCALS
1476 .checked_sub(local_idx)
1477 .and_then(|s| s.checked_sub(cnt))
1478 .is_none()
1479 {
1480 bail!("function exceeds the maximum number of locals that can be printed");
1481 }
1482 for _ in 0..cnt {
1483 if first {
1484 self.newline(offset)?;
1485 first = false;
1486 }
1487 locals.start_local(Some(func_idx), params + local_idx, self, state)?;
1488 self.print_valtype(state, ty)?;
1489 locals.end_local(self)?;
1490 local_idx += 1;
1491 }
1492 }
1493 locals.finish(self)?;
1494
1495 if let Some(f) = &mut validator {
1496 if let Err(e) = f.read_locals(body.get_binary_reader()) {
1497 validator = None;
1498 self.newline_unknown_pos()?;
1499 write!(self.result, ";; locals are invalid: {e}")?;
1500 }
1501 }
1502
1503 let nesting_start = self.nesting;
1504 let fold_instructions = self.config.fold_instructions;
1505 let mut operator_state = OperatorState::new(self, OperatorSeparator::Newline);
1506
1507 let end_pos = if fold_instructions {
1508 let mut folded_printer = PrintOperatorFolded::new(self, state, &mut operator_state);
1509 folded_printer.set_offset(func_start);
1510 folded_printer.begin_function(func_idx)?;
1511 Self::print_operators(
1512 &mut reader,
1513 branch_hints,
1514 func_start,
1515 &mut folded_printer,
1516 validator,
1517 )?
1518 } else {
1519 let mut flat_printer = PrintOperator::new(self, state, &mut operator_state);
1520 Self::print_operators(
1521 &mut reader,
1522 branch_hints,
1523 func_start,
1524 &mut flat_printer,
1525 validator,
1526 )?
1527 };
1528
1529 if self.nesting != nesting_start {
1535 self.nesting = nesting_start;
1536 self.newline(reader.original_position())?;
1537 }
1538
1539 Ok(end_pos)
1540 }
1541
1542 fn print_operators<'a, O: OpPrinter>(
1543 body: &mut BinaryReader<'a>,
1544 mut branch_hints: &[(usize, BranchHint)],
1545 func_start: usize,
1546 op_printer: &mut O,
1547 mut validator: Option<operand_stack::FuncValidator>,
1548 ) -> Result<usize> {
1549 let mut ops = OperatorsReader::new(body.clone());
1550 while !ops.eof() {
1551 if ops.is_end_then_eof() {
1552 let mut annotation = None;
1553 if let Some(f) = &mut validator {
1554 match f.visit_operator(&ops, true) {
1555 Ok(()) => {}
1556 Err(_) => {
1557 annotation = Some(String::from("type mismatch at end of expression"))
1558 }
1559 }
1560 }
1561
1562 let end_pos = ops.original_position();
1563 ops.read()?; ops.finish()?;
1565 op_printer.finalize(annotation.as_deref())?;
1566 return Ok(end_pos);
1567 }
1568
1569 if let Some(((hint_offset, hint), rest)) = branch_hints.split_first() {
1572 if hint.func_offset == (ops.original_position() - func_start) as u32 {
1573 branch_hints = rest;
1574 op_printer.branch_hint(*hint_offset, hint.taken)?;
1575 }
1576 }
1577 let mut annotation = None;
1578 if let Some(f) = &mut validator {
1579 let result = f
1580 .visit_operator(&ops, false)
1581 .map_err(anyhow::Error::from)
1582 .and_then(|()| f.visualize_operand_stack(op_printer.use_color()));
1583 match result {
1584 Ok(s) => annotation = Some(s),
1585 Err(_) => {
1586 validator = None;
1587 annotation = Some(String::from("(invalid)"));
1588 }
1589 }
1590 }
1591 op_printer.set_offset(ops.original_position());
1592 op_printer.visit_operator(&mut ops, annotation.as_deref())?;
1593 }
1594 ops.finish()?; bail!("unexpected end of operators");
1596 }
1597
1598 fn newline(&mut self, offset: usize) -> Result<()> {
1599 self.print_newline(Some(offset))
1600 }
1601
1602 fn newline_unknown_pos(&mut self) -> Result<()> {
1603 self.print_newline(None)
1604 }
1605
1606 fn print_newline(&mut self, offset: Option<usize>) -> Result<()> {
1607 self.result.newline()?;
1608 self.result.start_line(offset);
1609
1610 if self.config.print_offsets {
1611 match offset {
1612 Some(offset) => {
1613 self.result.start_comment()?;
1614 write!(self.result, "(;@{offset:<6x};)")?;
1615 self.result.reset_color()?;
1616 }
1617 None => self.result.write_str(" ")?,
1618 }
1619 }
1620 self.line += 1;
1621
1622 for _ in 0..self.nesting.min(MAX_NESTING_TO_PRINT) {
1626 self.result.write_str(&self.config.indent_text)?;
1627 }
1628 Ok(())
1629 }
1630
1631 fn print_exports(&mut self, state: &State, data: ExportSectionReader) -> Result<()> {
1632 for export in data.into_iter_with_offsets() {
1633 let (offset, export) = export?;
1634 self.newline(offset)?;
1635 self.print_export(state, &export)?;
1636 }
1637 Ok(())
1638 }
1639
1640 fn print_export(&mut self, state: &State, export: &Export) -> Result<()> {
1641 self.start_group("export ")?;
1642 self.print_str(export.name)?;
1643 self.result.write_str(" ")?;
1644 self.print_external_kind(state, export.kind, export.index)?;
1645 self.end_group()?; Ok(())
1647 }
1648
1649 fn print_external_kind(&mut self, state: &State, kind: ExternalKind, index: u32) -> Result<()> {
1650 match kind {
1651 ExternalKind::Func => {
1652 self.start_group("func ")?;
1653 self.print_idx(&state.core.func_names, index)?;
1654 }
1655 ExternalKind::Table => {
1656 self.start_group("table ")?;
1657 self.print_idx(&state.core.table_names, index)?;
1658 }
1659 ExternalKind::Global => {
1660 self.start_group("global ")?;
1661 self.print_idx(&state.core.global_names, index)?;
1662 }
1663 ExternalKind::Memory => {
1664 self.start_group("memory ")?;
1665 self.print_idx(&state.core.memory_names, index)?;
1666 }
1667 ExternalKind::Tag => {
1668 self.start_group("tag ")?;
1669 write!(self.result, "{index}")?;
1670 }
1671 }
1672 self.end_group()?;
1673 Ok(())
1674 }
1675
1676 fn print_core_type_ref(&mut self, state: &State, idx: u32) -> Result<()> {
1677 self.start_group("type ")?;
1678 self.print_idx(&state.core.type_names, idx)?;
1679 self.end_group()?;
1680 Ok(())
1681 }
1682
1683 fn print_idx<K>(&mut self, names: &NamingMap<u32, K>, idx: u32) -> Result<()>
1688 where
1689 K: NamingNamespace,
1690 {
1691 self._print_idx(&names.index_to_name, idx, K::desc())
1692 }
1693
1694 fn _print_idx(&mut self, names: &HashMap<u32, Naming>, idx: u32, desc: &str) -> Result<()> {
1695 self.result.start_name()?;
1696 match names.get(&idx) {
1697 Some(name) => name.write_identifier(self)?,
1698 None if self.config.name_unnamed => write!(self.result, "$#{desc}{idx}")?,
1699 None => write!(self.result, "{idx}")?,
1700 }
1701 self.result.reset_color()?;
1702 Ok(())
1703 }
1704
1705 fn print_local_idx(&mut self, state: &State, func: u32, idx: u32) -> Result<()> {
1706 self.result.start_name()?;
1707 match state.core.local_names.index_to_name.get(&(func, idx)) {
1708 Some(name) => name.write_identifier(self)?,
1709 None if self.config.name_unnamed => write!(self.result, "$#local{idx}")?,
1710 None => write!(self.result, "{idx}")?,
1711 }
1712 self.result.reset_color()?;
1713 Ok(())
1714 }
1715
1716 fn print_field_idx(&mut self, state: &State, ty: u32, idx: u32) -> Result<()> {
1717 self.result.start_name()?;
1718 match state.core.field_names.index_to_name.get(&(ty, idx)) {
1719 Some(name) => name.write_identifier(self)?,
1720 None if self.config.name_unnamed => write!(self.result, "$#field{idx}")?,
1721 None => write!(self.result, "{idx}")?,
1722 }
1723 self.result.reset_color()?;
1724 Ok(())
1725 }
1726
1727 fn print_name<K>(&mut self, names: &NamingMap<u32, K>, cur_idx: u32) -> Result<()>
1728 where
1729 K: NamingNamespace,
1730 {
1731 self._print_name(&names.index_to_name, cur_idx, K::desc())
1732 }
1733
1734 fn _print_name(
1735 &mut self,
1736 names: &HashMap<u32, Naming>,
1737 cur_idx: u32,
1738 desc: &str,
1739 ) -> Result<()> {
1740 self.result.start_name()?;
1741 match names.get(&cur_idx) {
1742 Some(name) => {
1743 name.write(self)?;
1744 self.result.write_str(" ")?;
1745 }
1746 None if self.config.name_unnamed => {
1747 write!(self.result, "$#{desc}{cur_idx} ")?;
1748 }
1749 None => {}
1750 }
1751 write!(self.result, "(;{cur_idx};)")?;
1752 self.result.reset_color()?;
1753 Ok(())
1754 }
1755
1756 fn print_elems(&mut self, state: &mut State, data: ElementSectionReader) -> Result<()> {
1757 for (i, elem) in data.into_iter_with_offsets().enumerate() {
1758 let (offset, mut elem) = elem?;
1759 self.newline(offset)?;
1760 self.start_group("elem ")?;
1761 self.print_name(&state.core.element_names, i as u32)?;
1762 match &mut elem.kind {
1763 ElementKind::Passive => {}
1764 ElementKind::Declared => self.result.write_str(" declare")?,
1765 ElementKind::Active {
1766 table_index,
1767 offset_expr,
1768 } => {
1769 if let Some(table_index) = *table_index {
1770 self.result.write_str(" ")?;
1771 self.start_group("table ")?;
1772 self.print_idx(&state.core.table_names, table_index)?;
1773 self.end_group()?;
1774 }
1775 self.result.write_str(" ")?;
1776 self.print_const_expr_sugar(state, offset_expr, "offset")?;
1777 }
1778 }
1779 self.result.write_str(" ")?;
1780
1781 if self.config.print_skeleton {
1782 self.result.write_str("...")?;
1783 } else {
1784 match elem.items {
1785 ElementItems::Functions(reader) => {
1786 self.result.write_str("func")?;
1787 for idx in reader {
1788 self.result.write_str(" ")?;
1789 self.print_idx(&state.core.func_names, idx?)?
1790 }
1791 }
1792 ElementItems::Expressions(ty, reader) => {
1793 self.print_reftype(state, ty)?;
1794 for expr in reader {
1795 self.result.write_str(" ")?;
1796 self.print_const_expr_sugar(state, &expr?, "item")?
1797 }
1798 }
1799 }
1800 }
1801 self.end_group()?;
1802 }
1803 Ok(())
1804 }
1805
1806 fn print_data(&mut self, state: &mut State, data: DataSectionReader) -> Result<()> {
1807 for (i, data) in data.into_iter_with_offsets().enumerate() {
1808 let (offset, data) = data?;
1809 self.newline(offset)?;
1810 self.start_group("data ")?;
1811 self.print_name(&state.core.data_names, i as u32)?;
1812 self.result.write_str(" ")?;
1813 match &data.kind {
1814 DataKind::Passive => {}
1815 DataKind::Active {
1816 memory_index,
1817 offset_expr,
1818 } => {
1819 if *memory_index != 0 {
1820 self.start_group("memory ")?;
1821 self.print_idx(&state.core.memory_names, *memory_index)?;
1822 self.end_group()?;
1823 self.result.write_str(" ")?;
1824 }
1825 self.print_const_expr_sugar(state, offset_expr, "offset")?;
1826 self.result.write_str(" ")?;
1827 }
1828 }
1829 if self.config.print_skeleton {
1830 self.result.write_str("...")?;
1831 } else {
1832 self.print_bytes(data.data)?;
1833 }
1834 self.end_group()?;
1835 }
1836 Ok(())
1837 }
1838
1839 fn print_const_expr_sugar(
1843 &mut self,
1844 state: &mut State,
1845 expr: &ConstExpr,
1846 explicit: &str,
1847 ) -> Result<()> {
1848 self.start_group("")?;
1849 let mut reader = expr.get_operators_reader();
1850
1851 if reader.read().is_ok() && !reader.is_end_then_eof() {
1852 write!(self.result, "{explicit} ")?;
1853 self.print_const_expr(state, expr, self.config.fold_instructions)?;
1854 } else {
1855 self.print_const_expr(state, expr, false)?;
1856 }
1857
1858 self.end_group()?;
1859 Ok(())
1860 }
1861
1862 fn print_const_expr(&mut self, state: &mut State, expr: &ConstExpr, fold: bool) -> Result<()> {
1864 let mut reader = expr.get_binary_reader();
1865 let mut operator_state = OperatorState::new(self, OperatorSeparator::NoneThenSpace);
1866
1867 if fold {
1868 let mut folded_printer = PrintOperatorFolded::new(self, state, &mut operator_state);
1869 folded_printer.begin_const_expr();
1870 Self::print_operators(&mut reader, &[], 0, &mut folded_printer, None)?;
1871 } else {
1872 let mut op_printer = PrintOperator::new(self, state, &mut operator_state);
1873 Self::print_operators(&mut reader, &[], 0, &mut op_printer, None)?;
1874 }
1875
1876 Ok(())
1877 }
1878
1879 fn print_str(&mut self, name: &str) -> Result<()> {
1880 self.result.start_literal()?;
1881 self.result.write_str("\"")?;
1882 self.print_str_contents(name)?;
1883 self.result.write_str("\"")?;
1884 self.result.reset_color()?;
1885 Ok(())
1886 }
1887
1888 fn print_str_contents(&mut self, name: &str) -> Result<()> {
1889 for c in name.chars() {
1890 let v = c as u32;
1891 if (0x20..0x7f).contains(&v) && c != '"' && c != '\\' && v < 0xff {
1892 write!(self.result, "{c}")?;
1893 } else {
1894 write!(self.result, "\\u{{{v:x}}}",)?;
1895 }
1896 }
1897 Ok(())
1898 }
1899
1900 fn print_bytes(&mut self, bytes: &[u8]) -> Result<()> {
1901 self.result.start_literal()?;
1902 self.result.write_str("\"")?;
1903 for byte in bytes {
1904 if *byte >= 0x20 && *byte < 0x7f && *byte != b'"' && *byte != b'\\' {
1905 write!(self.result, "{}", *byte as char)?;
1906 } else {
1907 self.hex_byte(*byte)?;
1908 }
1909 }
1910 self.result.write_str("\"")?;
1911 self.result.reset_color()?;
1912 Ok(())
1913 }
1914
1915 fn hex_byte(&mut self, byte: u8) -> Result<()> {
1916 write!(self.result, "\\{byte:02x}")?;
1917 Ok(())
1918 }
1919
1920 fn print_known_custom_section(&mut self, section: CustomSectionReader<'_>) -> Result<bool> {
1921 match section.as_known() {
1922 KnownCustom::Producers(s) => {
1926 self.newline(section.range().start)?;
1927 self.print_producers_section(s)?;
1928 Ok(true)
1929 }
1930 KnownCustom::Dylink0(s) => {
1931 self.newline(section.range().start)?;
1932 self.print_dylink0_section(s)?;
1933 Ok(true)
1934 }
1935
1936 KnownCustom::Name(_) | KnownCustom::BranchHints(_) => Ok(true),
1939 #[cfg(feature = "component-model")]
1940 KnownCustom::ComponentName(_) => Ok(true),
1941
1942 _ => Ok(false),
1943 }
1944 }
1945
1946 fn print_raw_custom_section(
1947 &mut self,
1948 state: &State,
1949 section: CustomSectionReader<'_>,
1950 ) -> Result<()> {
1951 self.newline(section.range().start)?;
1952 self.start_group("@custom ")?;
1953 self.print_str(section.name())?;
1954 if let Some((place, _)) = state.custom_section_place {
1955 write!(self.result, " ({place})")?;
1956 }
1957 self.result.write_str(" ")?;
1958 if self.config.print_skeleton {
1959 self.result.write_str("...")?;
1960 } else {
1961 self.print_bytes(section.data())?;
1962 }
1963 self.end_group()?;
1964 Ok(())
1965 }
1966
1967 fn print_producers_section(&mut self, section: ProducersSectionReader<'_>) -> Result<()> {
1968 self.start_group("@producers")?;
1969 for field in section {
1970 let field = field?;
1971 for value in field.values.into_iter_with_offsets() {
1972 let (offset, value) = value?;
1973 self.newline(offset)?;
1974 self.start_group(field.name)?;
1975 self.result.write_str(" ")?;
1976 self.print_str(value.name)?;
1977 self.result.write_str(" ")?;
1978 self.print_str(value.version)?;
1979 self.end_group()?;
1980 }
1981 }
1982 self.end_group()?;
1983 Ok(())
1984 }
1985
1986 fn print_dylink0_section(&mut self, mut section: Dylink0SectionReader<'_>) -> Result<()> {
1987 self.start_group("@dylink.0")?;
1988 loop {
1989 let start = section.original_position();
1990 let next = match section.next() {
1991 Some(Ok(next)) => next,
1992 Some(Err(e)) => return Err(e.into()),
1993 None => break,
1994 };
1995 match next {
1996 Dylink0Subsection::MemInfo(info) => {
1997 self.newline(start)?;
1998 self.start_group("mem-info")?;
1999 if info.memory_size > 0 || info.memory_alignment > 0 {
2000 write!(
2001 self.result,
2002 " (memory {} {})",
2003 info.memory_size, info.memory_alignment
2004 )?;
2005 }
2006 if info.table_size > 0 || info.table_alignment > 0 {
2007 write!(
2008 self.result,
2009 " (table {} {})",
2010 info.table_size, info.table_alignment
2011 )?;
2012 }
2013 self.end_group()?;
2014 }
2015 Dylink0Subsection::Needed(needed) => {
2016 self.newline(start)?;
2017 self.start_group("needed")?;
2018 for s in needed {
2019 self.result.write_str(" ")?;
2020 self.print_str(s)?;
2021 }
2022 self.end_group()?;
2023 }
2024 Dylink0Subsection::ExportInfo(info) => {
2025 for info in info {
2026 self.newline(start)?;
2027 self.start_group("export-info ")?;
2028 self.print_str(info.name)?;
2029 self.print_dylink0_flags(info.flags)?;
2030 self.end_group()?;
2031 }
2032 }
2033 Dylink0Subsection::ImportInfo(info) => {
2034 for info in info {
2035 self.newline(start)?;
2036 self.start_group("import-info ")?;
2037 self.print_str(info.module)?;
2038 self.result.write_str(" ")?;
2039 self.print_str(info.field)?;
2040 self.print_dylink0_flags(info.flags)?;
2041 self.end_group()?;
2042 }
2043 }
2044 Dylink0Subsection::RuntimePath(runtime_path) => {
2045 self.newline(start)?;
2046 self.start_group("runtime-path")?;
2047 for s in runtime_path {
2048 self.result.write_str(" ")?;
2049 self.print_str(s)?;
2050 }
2051 self.end_group()?;
2052 }
2053 Dylink0Subsection::Unknown { ty, .. } => {
2054 bail!("don't know how to print dylink.0 subsection id {ty}");
2055 }
2056 }
2057 }
2058 self.end_group()?;
2059 Ok(())
2060 }
2061
2062 fn print_dylink0_flags(&mut self, mut flags: SymbolFlags) -> Result<()> {
2063 macro_rules! print_flag {
2064 ($($name:ident = $text:tt)*) => ({$(
2065 if flags.contains(SymbolFlags::$name) {
2066 flags.remove(SymbolFlags::$name);
2067 write!(self.result, concat!(" ", $text))?;
2068 }
2069 )*})
2070 }
2071 print_flag! {
2073 BINDING_WEAK = "binding-weak"
2074 BINDING_LOCAL = "binding-local"
2075 VISIBILITY_HIDDEN = "visibility-hidden"
2076 UNDEFINED = "undefined"
2077 EXPORTED = "exported"
2078 EXPLICIT_NAME = "explicit-name"
2079 NO_STRIP = "no-strip"
2080 TLS = "tls"
2081 ABSOLUTE = "absolute"
2082 }
2083 if !flags.is_empty() {
2084 write!(self.result, " {flags:#x}")?;
2085 }
2086 Ok(())
2087 }
2088
2089 fn register_branch_hint_section(&mut self, section: BranchHintSectionReader<'_>) -> Result<()> {
2090 self.code_section_hints.clear();
2091 for func in section {
2092 let func = func?;
2093 if self.code_section_hints.len() >= MAX_WASM_FUNCTIONS as usize {
2094 bail!("found too many hints");
2095 }
2096 if func.hints.count() >= MAX_WASM_FUNCTION_SIZE {
2097 bail!("found too many hints");
2098 }
2099 let hints = func
2100 .hints
2101 .into_iter_with_offsets()
2102 .collect::<wasmparser::Result<Vec<_>>>()?;
2103 self.code_section_hints.push((func.func, hints));
2104 }
2105 self.code_section_hints.reverse();
2106 Ok(())
2107 }
2108}
2109
2110struct NamedLocalPrinter {
2111 group_name: &'static str,
2112 in_group: bool,
2113 end_group_after_local: bool,
2114 first: bool,
2115}
2116
2117impl NamedLocalPrinter {
2118 fn new(group_name: &'static str) -> NamedLocalPrinter {
2119 NamedLocalPrinter {
2120 group_name,
2121 in_group: false,
2122 end_group_after_local: false,
2123 first: true,
2124 }
2125 }
2126
2127 fn start_local(
2128 &mut self,
2129 func: Option<u32>,
2130 local: u32,
2131 dst: &mut Printer,
2132 state: &State,
2133 ) -> Result<()> {
2134 let name = state
2135 .core
2136 .local_names
2137 .index_to_name
2138 .get(&(func.unwrap_or(u32::MAX), local));
2139
2140 if name.is_some() && self.in_group {
2143 dst.end_group()?;
2144 self.in_group = false;
2145 }
2146
2147 if self.first {
2148 self.first = false;
2149 } else {
2150 dst.result.write_str(" ")?;
2151 }
2152
2153 if !self.in_group {
2156 dst.start_group(self.group_name)?;
2157 dst.result.write_str(" ")?;
2158 self.in_group = true;
2159 }
2160
2161 match name {
2163 Some(name) => {
2164 name.write(dst)?;
2165 dst.result.write_str(" ")?;
2166 self.end_group_after_local = true;
2167 }
2168 None if dst.config.name_unnamed && func.is_some() => {
2169 write!(dst.result, "$#local{local} ")?;
2170 self.end_group_after_local = true;
2171 }
2172 None => {
2173 self.end_group_after_local = false;
2174 }
2175 }
2176 Ok(())
2177 }
2178
2179 fn end_local(&mut self, dst: &mut Printer) -> Result<()> {
2180 if self.end_group_after_local {
2181 dst.end_group()?;
2182 self.end_group_after_local = false;
2183 self.in_group = false;
2184 }
2185 Ok(())
2186 }
2187 fn finish(self, dst: &mut Printer) -> Result<()> {
2188 if self.in_group {
2189 dst.end_group()?;
2190 }
2191 Ok(())
2192 }
2193}
2194
2195macro_rules! print_float {
2196 ($name:ident $float:ident $uint:ident $sint:ident $exp_bits:tt) => {
2197 fn $name(&mut self, mut bits: $uint) -> Result<()> {
2198 let int_width = mem::size_of::<$uint>() * 8;
2200 let exp_width = $exp_bits;
2201 let mantissa_width = int_width - 1 - exp_width;
2202 let bias = (1 << (exp_width - 1)) - 1;
2203 let max_exp = (1 as $sint) << (exp_width - 1);
2204 let min_exp = -max_exp + 1;
2205
2206 let f = $float::from_bits(bits);
2208 if bits >> (int_width - 1) != 0 {
2209 bits ^= 1 << (int_width - 1);
2210 self.result.write_str("-")?;
2211 }
2212 if f.is_infinite() {
2213 self.result.start_literal()?;
2214 self.result.write_str("inf ")?;
2215 self.result.start_comment()?;
2216 write!(self.result, "(;={f};)")?;
2217 self.result.reset_color()?;
2218 return Ok(());
2219 }
2220 if f.is_nan() {
2221 let payload = bits & ((1 << mantissa_width) - 1);
2222 self.result.start_literal()?;
2223 if payload == 1 << (mantissa_width - 1) {
2224 self.result.write_str("nan ")?;
2225 self.result.start_comment()?;
2226 write!(self.result, "(;={f};)")?;
2227 } else {
2228 write!(self.result, "nan:{:#x} ", payload)?;
2229 self.result.start_comment()?;
2230 write!(self.result, "(;={f};)")?;
2231 }
2232 self.result.reset_color()?;
2233 return Ok(());
2234 }
2235
2236 let mut exponent = (((bits << 1) as $sint) >> (mantissa_width + 1)).wrapping_sub(bias);
2252 exponent = (exponent << (int_width - exp_width)) >> (int_width - exp_width);
2253 let mut fraction = bits & ((1 << mantissa_width) - 1);
2254 self.result.start_literal()?;
2255 self.result.write_str("0x")?;
2256 if bits == 0 {
2257 self.result.write_str("0p+0")?;
2258 } else {
2259 self.result.write_str("1")?;
2260 if fraction > 0 {
2261 fraction <<= (int_width - mantissa_width);
2262
2263 if exponent == min_exp {
2267 let leading = fraction.leading_zeros();
2268 if (leading as usize) < int_width - 1 {
2269 fraction <<= leading + 1;
2270 } else {
2271 fraction = 0;
2272 }
2273 exponent -= leading as $sint;
2274 }
2275
2276 self.result.write_str(".")?;
2277 while fraction > 0 {
2278 write!(self.result, "{:x}", fraction >> (int_width - 4))?;
2279 fraction <<= 4;
2280 }
2281 }
2282 write!(self.result, "p{:+}", exponent)?;
2283 }
2284 self.result.start_comment()?;
2285 write!(self.result, " (;={};)", f)?;
2286 self.result.reset_color()?;
2287 Ok(())
2288 }
2289 };
2290}
2291
2292impl Printer<'_, '_> {
2293 print_float!(print_f32 f32 u32 i32 8);
2294 print_float!(print_f64 f64 u64 i64 11);
2295}
2296
2297impl Naming {
2298 fn new<'a>(
2299 name: &'a str,
2300 index: u32,
2301 group: &str,
2302 used: Option<&mut HashSet<&'a str>>,
2303 ) -> Naming {
2304 let mut kind = NamingKind::DollarName;
2305 if name.chars().any(|c| !is_idchar(c)) {
2306 kind = NamingKind::DollarQuotedName;
2307 }
2308
2309 if name.is_empty()
2328 || name.starts_with('#')
2329 || used.map(|set| !set.insert(name)).unwrap_or(false)
2330 {
2331 kind = NamingKind::SyntheticPrefix(format!("#{group}{index}"));
2332 }
2333 return Naming {
2334 kind,
2335 name: name.to_string(),
2336 };
2337
2338 fn is_idchar(c: char) -> bool {
2340 matches!(
2341 c,
2342 '0'..='9'
2343 | 'a'..='z'
2344 | 'A'..='Z'
2345 | '!'
2346 | '#'
2347 | '$'
2348 | '%'
2349 | '&'
2350 | '\''
2351 | '*'
2352 | '+'
2353 | '-'
2354 | '.'
2355 | '/'
2356 | ':'
2357 | '<'
2358 | '='
2359 | '>'
2360 | '?'
2361 | '@'
2362 | '\\'
2363 | '^'
2364 | '_'
2365 | '`'
2366 | '|'
2367 | '~'
2368 )
2369 }
2370 }
2371
2372 fn write_identifier(&self, printer: &mut Printer<'_, '_>) -> Result<()> {
2373 match &self.kind {
2374 NamingKind::DollarName => {
2375 printer.result.write_str("$")?;
2376 printer.result.write_str(&self.name)?;
2377 }
2378 NamingKind::DollarQuotedName => {
2379 printer.result.write_str("$\"")?;
2380 printer.print_str_contents(&self.name)?;
2381 printer.result.write_str("\"")?;
2382 }
2383 NamingKind::SyntheticPrefix(prefix) => {
2384 printer.result.write_str("$\"")?;
2385 printer.result.write_str(&prefix)?;
2386 printer.result.write_str(" ")?;
2387 printer.print_str_contents(&self.name)?;
2388 printer.result.write_str("\"")?;
2389 }
2390 }
2391 Ok(())
2392 }
2393
2394 fn write(&self, dst: &mut Printer<'_, '_>) -> Result<()> {
2395 self.write_identifier(dst)?;
2396 match &self.kind {
2397 NamingKind::DollarName | NamingKind::DollarQuotedName => {}
2398
2399 NamingKind::SyntheticPrefix(_) => {
2400 dst.result.write_str(" ")?;
2401 dst.start_group("@name \"")?;
2402 dst.print_str_contents(&self.name)?;
2403 dst.result.write_str("\"")?;
2404 dst.end_group()?;
2405 }
2406 }
2407 Ok(())
2408 }
2409}
2410
2411trait NamingNamespace {
2413 fn desc() -> &'static str;
2414}
2415
2416macro_rules! naming_namespaces {
2417 ($(struct $name:ident => $desc:tt)*) => ($(
2418 struct $name;
2419
2420 impl NamingNamespace for $name {
2421 fn desc() -> &'static str { $desc }
2422 }
2423 )*)
2424}
2425
2426naming_namespaces! {
2427 struct NameFunc => "func"
2428 struct NameGlobal => "global"
2429 struct NameMemory => "memory"
2430 struct NameLocal => "local"
2431 struct NameLabel => "label"
2432 struct NameTable => "table"
2433 struct NameType => "type"
2434 struct NameField => "field"
2435 struct NameData => "data"
2436 struct NameElem => "elem"
2437 struct NameTag => "tag"
2438}
2439
2440#[cfg(feature = "component-model")]
2441naming_namespaces! {
2442 struct NameModule => "module"
2443 struct NameInstance => "instance"
2444 struct NameValue => "value"
2445 struct NameComponent => "component"
2446}
2447
2448fn name_map<K>(into: &mut NamingMap<u32, K>, names: NameMap<'_>, name: &str) -> Result<()> {
2449 let mut used = HashSet::new();
2450 for naming in names {
2451 let naming = naming?;
2452 into.index_to_name.insert(
2453 naming.index,
2454 Naming::new(naming.name, naming.index, name, Some(&mut used)),
2455 );
2456 }
2457 Ok(())
2458}