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) | TypeRef::FuncExact(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::FuncExact(f) => {
1263 self.start_group("func ")?;
1264 if index {
1265 self.print_name(&state.core.func_names, state.core.funcs)?;
1266 self.result.write_str(" ")?;
1267 }
1268 self.start_group("exact ")?;
1269 self.print_core_type_ref(state, *f)?;
1270 self.end_group()?;
1271 }
1272 TypeRef::Table(f) => self.print_table_type(state, f, index)?,
1273 TypeRef::Memory(f) => self.print_memory_type(state, f, index)?,
1274 TypeRef::Tag(f) => self.print_tag_type(state, f, index)?,
1275 TypeRef::Global(f) => self.print_global_type(state, f, index)?,
1276 }
1277 self.end_group()?;
1278 Ok(())
1279 }
1280
1281 fn print_table_type(&mut self, state: &State, ty: &TableType, index: bool) -> Result<()> {
1282 self.start_group("table ")?;
1283 if index {
1284 self.print_name(&state.core.table_names, state.core.tables)?;
1285 self.result.write_str(" ")?;
1286 }
1287 if ty.shared {
1288 self.print_type_keyword("shared ")?;
1289 }
1290 if ty.table64 {
1291 self.print_type_keyword("i64 ")?;
1292 }
1293 self.print_limits(ty.initial, ty.maximum)?;
1294 self.result.write_str(" ")?;
1295 self.print_reftype(state, ty.element_type)?;
1296 Ok(())
1297 }
1298
1299 fn print_memory_type(&mut self, state: &State, ty: &MemoryType, index: bool) -> Result<()> {
1300 self.start_group("memory ")?;
1301 if index {
1302 self.print_name(&state.core.memory_names, state.core.memories)?;
1303 self.result.write_str(" ")?;
1304 }
1305 if ty.memory64 {
1306 self.print_type_keyword("i64 ")?;
1307 }
1308 self.print_limits(ty.initial, ty.maximum)?;
1309 if ty.shared {
1310 self.print_type_keyword(" shared")?;
1311 }
1312 if let Some(p) = ty.page_size_log2 {
1313 let p = 1_u64
1314 .checked_shl(p)
1315 .ok_or_else(|| anyhow!("left shift overflow").context("invalid page size"))?;
1316
1317 self.result.write_str(" ")?;
1318 self.start_group("pagesize ")?;
1319 write!(self.result, "{p:#x}")?;
1320 self.end_group()?;
1321 }
1322 Ok(())
1323 }
1324
1325 fn print_tag_type(&mut self, state: &State, ty: &TagType, index: bool) -> Result<()> {
1326 self.start_group("tag ")?;
1327 if index {
1328 self.print_name(&state.core.tag_names, state.core.tags)?;
1329 self.result.write_str(" ")?;
1330 }
1331 self.print_core_functype_idx(state, ty.func_type_idx, None)?;
1332 Ok(())
1333 }
1334
1335 fn print_limits<T>(&mut self, initial: T, maximum: Option<T>) -> Result<()>
1336 where
1337 T: fmt::Display,
1338 {
1339 self.result.start_literal()?;
1340 write!(self.result, "{initial}")?;
1341 if let Some(max) = maximum {
1342 write!(self.result, " {max}")?;
1343 }
1344 self.result.reset_color()?;
1345 Ok(())
1346 }
1347
1348 fn print_global_type(&mut self, state: &State, ty: &GlobalType, index: bool) -> Result<()> {
1349 self.start_group("global ")?;
1350 if index {
1351 self.print_name(&state.core.global_names, state.core.globals)?;
1352 self.result.write_str(" ")?;
1353 }
1354 if ty.shared || ty.mutable {
1355 self.result.write_str("(")?;
1356 if ty.shared {
1357 self.print_type_keyword("shared ")?;
1358 }
1359 if ty.mutable {
1360 self.print_type_keyword("mut ")?;
1361 }
1362 self.print_valtype(state, ty.content_type)?;
1363 self.result.write_str(")")?;
1364 } else {
1365 self.print_valtype(state, ty.content_type)?;
1366 }
1367 Ok(())
1368 }
1369
1370 fn print_tables(&mut self, state: &mut State, parser: TableSectionReader<'_>) -> Result<()> {
1371 for table in parser.into_iter_with_offsets() {
1372 let (offset, table) = table?;
1373 self.newline(offset)?;
1374 self.print_table_type(state, &table.ty, true)?;
1375 match &table.init {
1376 TableInit::RefNull => {}
1377 TableInit::Expr(expr) => {
1378 self.result.write_str(" ")?;
1379 self.print_const_expr(state, expr, self.config.fold_instructions)?;
1380 }
1381 }
1382 self.end_group()?;
1383 state.core.tables += 1;
1384 }
1385 Ok(())
1386 }
1387
1388 fn print_memories(&mut self, state: &mut State, parser: MemorySectionReader<'_>) -> Result<()> {
1389 for memory in parser.into_iter_with_offsets() {
1390 let (offset, memory) = memory?;
1391 self.newline(offset)?;
1392 self.print_memory_type(state, &memory, true)?;
1393 self.end_group()?;
1394 state.core.memories += 1;
1395 }
1396 Ok(())
1397 }
1398
1399 fn print_tags(&mut self, state: &mut State, parser: TagSectionReader<'_>) -> Result<()> {
1400 for tag in parser.into_iter_with_offsets() {
1401 let (offset, tag) = tag?;
1402 self.newline(offset)?;
1403 self.print_tag_type(state, &tag, true)?;
1404 self.end_group()?;
1405 debug_assert!(state.core.tag_to_type.len() == state.core.tags as usize);
1406 state.core.tags += 1;
1407 state.core.tag_to_type.push(Some(tag.func_type_idx));
1408 }
1409 Ok(())
1410 }
1411
1412 fn print_globals(&mut self, state: &mut State, parser: GlobalSectionReader<'_>) -> Result<()> {
1413 for global in parser.into_iter_with_offsets() {
1414 let (offset, global) = global?;
1415 self.newline(offset)?;
1416 self.print_global_type(state, &global.ty, true)?;
1417 self.result.write_str(" ")?;
1418 self.print_const_expr(state, &global.init_expr, self.config.fold_instructions)?;
1419 self.end_group()?;
1420 state.core.globals += 1;
1421 }
1422 Ok(())
1423 }
1424
1425 fn print_code_section_entry(
1426 &mut self,
1427 state: &mut State,
1428 body: &FunctionBody<'_>,
1429 validator: Option<operand_stack::FuncValidator>,
1430 ) -> Result<()> {
1431 self.newline(body.get_binary_reader().original_position())?;
1432 self.start_group("func ")?;
1433 let func_idx = state.core.funcs;
1434 self.print_name(&state.core.func_names, func_idx)?;
1435 self.result.write_str(" ")?;
1436 let ty = match state.core.func_to_type.get(func_idx as usize) {
1437 Some(Some(x)) => *x,
1438 _ => panic!("invalid function type"),
1439 };
1440 let params = self
1441 .print_core_functype_idx(state, ty, Some(func_idx))?
1442 .unwrap_or(0);
1443
1444 let hints = match self.code_section_hints.last() {
1447 Some((f, _)) if *f == func_idx => {
1448 let (_, hints) = self.code_section_hints.pop().unwrap();
1449 hints
1450 }
1451 _ => Vec::new(),
1452 };
1453
1454 if self.config.print_skeleton {
1455 self.result.write_str(" ...")?;
1456 self.end_group()?;
1457 } else {
1458 let end_pos =
1459 self.print_func_body(state, func_idx, params, &body, &hints, validator)?;
1460 self.end_group_at_pos(end_pos)?;
1461 }
1462
1463 state.core.funcs += 1;
1464 Ok(())
1465 }
1466
1467 fn print_func_body(
1468 &mut self,
1469 state: &mut State,
1470 func_idx: u32,
1471 params: u32,
1472 body: &FunctionBody<'_>,
1473 branch_hints: &[(usize, BranchHint)],
1474 mut validator: Option<operand_stack::FuncValidator>,
1475 ) -> Result<usize> {
1476 let mut first = true;
1477 let mut local_idx = 0;
1478 let mut locals = NamedLocalPrinter::new("local");
1479 let mut reader = body.get_binary_reader();
1480 let func_start = reader.original_position();
1481 for _ in 0..reader.read_var_u32()? {
1482 let offset = reader.original_position();
1483 let cnt = reader.read_var_u32()?;
1484 let ty = reader.read()?;
1485 if MAX_LOCALS
1486 .checked_sub(local_idx)
1487 .and_then(|s| s.checked_sub(cnt))
1488 .is_none()
1489 {
1490 bail!("function exceeds the maximum number of locals that can be printed");
1491 }
1492 for _ in 0..cnt {
1493 if first {
1494 self.newline(offset)?;
1495 first = false;
1496 }
1497 locals.start_local(Some(func_idx), params + local_idx, self, state)?;
1498 self.print_valtype(state, ty)?;
1499 locals.end_local(self)?;
1500 local_idx += 1;
1501 }
1502 }
1503 locals.finish(self)?;
1504
1505 if let Some(f) = &mut validator {
1506 if let Err(e) = f.read_locals(body.get_binary_reader()) {
1507 validator = None;
1508 self.newline_unknown_pos()?;
1509 write!(self.result, ";; locals are invalid: {e}")?;
1510 }
1511 }
1512
1513 let nesting_start = self.nesting;
1514 let fold_instructions = self.config.fold_instructions;
1515 let mut operator_state = OperatorState::new(self, OperatorSeparator::Newline);
1516
1517 let end_pos = if fold_instructions {
1518 let mut folded_printer = PrintOperatorFolded::new(self, state, &mut operator_state);
1519 folded_printer.set_offset(func_start);
1520 folded_printer.begin_function(func_idx)?;
1521 Self::print_operators(
1522 &mut reader,
1523 branch_hints,
1524 func_start,
1525 &mut folded_printer,
1526 validator,
1527 )?
1528 } else {
1529 let mut flat_printer = PrintOperator::new(self, state, &mut operator_state);
1530 Self::print_operators(
1531 &mut reader,
1532 branch_hints,
1533 func_start,
1534 &mut flat_printer,
1535 validator,
1536 )?
1537 };
1538
1539 if self.nesting != nesting_start {
1545 self.nesting = nesting_start;
1546 self.newline(reader.original_position())?;
1547 }
1548
1549 Ok(end_pos)
1550 }
1551
1552 fn print_operators<'a, O: OpPrinter>(
1553 body: &mut BinaryReader<'a>,
1554 mut branch_hints: &[(usize, BranchHint)],
1555 func_start: usize,
1556 op_printer: &mut O,
1557 mut validator: Option<operand_stack::FuncValidator>,
1558 ) -> Result<usize> {
1559 let mut ops = OperatorsReader::new(body.clone());
1560 while !ops.eof() {
1561 if ops.is_end_then_eof() {
1562 let mut annotation = None;
1563 if let Some(f) = &mut validator {
1564 match f.visit_operator(&ops, true) {
1565 Ok(()) => {}
1566 Err(_) => {
1567 annotation = Some(String::from("type mismatch at end of expression"))
1568 }
1569 }
1570 }
1571
1572 let end_pos = ops.original_position();
1573 ops.read()?; ops.finish()?;
1575 op_printer.finalize(annotation.as_deref())?;
1576 return Ok(end_pos);
1577 }
1578
1579 if let Some(((hint_offset, hint), rest)) = branch_hints.split_first() {
1582 if hint.func_offset == (ops.original_position() - func_start) as u32 {
1583 branch_hints = rest;
1584 op_printer.branch_hint(*hint_offset, hint.taken)?;
1585 }
1586 }
1587 let mut annotation = None;
1588 if let Some(f) = &mut validator {
1589 let result = f
1590 .visit_operator(&ops, false)
1591 .map_err(anyhow::Error::from)
1592 .and_then(|()| f.visualize_operand_stack(op_printer.use_color()));
1593 match result {
1594 Ok(s) => annotation = Some(s),
1595 Err(_) => {
1596 validator = None;
1597 annotation = Some(String::from("(invalid)"));
1598 }
1599 }
1600 }
1601 op_printer.set_offset(ops.original_position());
1602 op_printer.visit_operator(&mut ops, annotation.as_deref())?;
1603 }
1604 ops.finish()?; bail!("unexpected end of operators");
1606 }
1607
1608 fn newline(&mut self, offset: usize) -> Result<()> {
1609 self.print_newline(Some(offset))
1610 }
1611
1612 fn newline_unknown_pos(&mut self) -> Result<()> {
1613 self.print_newline(None)
1614 }
1615
1616 fn print_newline(&mut self, offset: Option<usize>) -> Result<()> {
1617 self.result.newline()?;
1618 self.result.start_line(offset);
1619
1620 if self.config.print_offsets {
1621 match offset {
1622 Some(offset) => {
1623 self.result.start_comment()?;
1624 write!(self.result, "(;@{offset:<6x};)")?;
1625 self.result.reset_color()?;
1626 }
1627 None => self.result.write_str(" ")?,
1628 }
1629 }
1630 self.line += 1;
1631
1632 for _ in 0..self.nesting.min(MAX_NESTING_TO_PRINT) {
1636 self.result.write_str(&self.config.indent_text)?;
1637 }
1638 Ok(())
1639 }
1640
1641 fn print_exports(&mut self, state: &State, data: ExportSectionReader) -> Result<()> {
1642 for export in data.into_iter_with_offsets() {
1643 let (offset, export) = export?;
1644 self.newline(offset)?;
1645 self.print_export(state, &export)?;
1646 }
1647 Ok(())
1648 }
1649
1650 fn print_export(&mut self, state: &State, export: &Export) -> Result<()> {
1651 self.start_group("export ")?;
1652 self.print_str(export.name)?;
1653 self.result.write_str(" ")?;
1654 self.print_external_kind(state, export.kind, export.index)?;
1655 self.end_group()?; Ok(())
1657 }
1658
1659 fn print_external_kind(&mut self, state: &State, kind: ExternalKind, index: u32) -> Result<()> {
1660 match kind {
1661 ExternalKind::Func | ExternalKind::FuncExact => {
1662 self.start_group("func ")?;
1663 self.print_idx(&state.core.func_names, index)?;
1664 }
1665 ExternalKind::Table => {
1666 self.start_group("table ")?;
1667 self.print_idx(&state.core.table_names, index)?;
1668 }
1669 ExternalKind::Global => {
1670 self.start_group("global ")?;
1671 self.print_idx(&state.core.global_names, index)?;
1672 }
1673 ExternalKind::Memory => {
1674 self.start_group("memory ")?;
1675 self.print_idx(&state.core.memory_names, index)?;
1676 }
1677 ExternalKind::Tag => {
1678 self.start_group("tag ")?;
1679 write!(self.result, "{index}")?;
1680 }
1681 }
1682 self.end_group()?;
1683 Ok(())
1684 }
1685
1686 fn print_core_type_ref(&mut self, state: &State, idx: u32) -> Result<()> {
1687 self.start_group("type ")?;
1688 self.print_idx(&state.core.type_names, idx)?;
1689 self.end_group()?;
1690 Ok(())
1691 }
1692
1693 fn print_idx<K>(&mut self, names: &NamingMap<u32, K>, idx: u32) -> Result<()>
1698 where
1699 K: NamingNamespace,
1700 {
1701 self._print_idx(&names.index_to_name, idx, K::desc())
1702 }
1703
1704 fn _print_idx(&mut self, names: &HashMap<u32, Naming>, idx: u32, desc: &str) -> Result<()> {
1705 self.result.start_name()?;
1706 match names.get(&idx) {
1707 Some(name) => name.write_identifier(self)?,
1708 None if self.config.name_unnamed => write!(self.result, "$#{desc}{idx}")?,
1709 None => write!(self.result, "{idx}")?,
1710 }
1711 self.result.reset_color()?;
1712 Ok(())
1713 }
1714
1715 fn print_local_idx(&mut self, state: &State, func: u32, idx: u32) -> Result<()> {
1716 self.result.start_name()?;
1717 match state.core.local_names.index_to_name.get(&(func, idx)) {
1718 Some(name) => name.write_identifier(self)?,
1719 None if self.config.name_unnamed => write!(self.result, "$#local{idx}")?,
1720 None => write!(self.result, "{idx}")?,
1721 }
1722 self.result.reset_color()?;
1723 Ok(())
1724 }
1725
1726 fn print_field_idx(&mut self, state: &State, ty: u32, idx: u32) -> Result<()> {
1727 self.result.start_name()?;
1728 match state.core.field_names.index_to_name.get(&(ty, idx)) {
1729 Some(name) => name.write_identifier(self)?,
1730 None if self.config.name_unnamed => write!(self.result, "$#field{idx}")?,
1731 None => write!(self.result, "{idx}")?,
1732 }
1733 self.result.reset_color()?;
1734 Ok(())
1735 }
1736
1737 fn print_name<K>(&mut self, names: &NamingMap<u32, K>, cur_idx: u32) -> Result<()>
1738 where
1739 K: NamingNamespace,
1740 {
1741 self._print_name(&names.index_to_name, cur_idx, K::desc())
1742 }
1743
1744 fn _print_name(
1745 &mut self,
1746 names: &HashMap<u32, Naming>,
1747 cur_idx: u32,
1748 desc: &str,
1749 ) -> Result<()> {
1750 self.result.start_name()?;
1751 match names.get(&cur_idx) {
1752 Some(name) => {
1753 name.write(self)?;
1754 self.result.write_str(" ")?;
1755 }
1756 None if self.config.name_unnamed => {
1757 write!(self.result, "$#{desc}{cur_idx} ")?;
1758 }
1759 None => {}
1760 }
1761 write!(self.result, "(;{cur_idx};)")?;
1762 self.result.reset_color()?;
1763 Ok(())
1764 }
1765
1766 fn print_elems(&mut self, state: &mut State, data: ElementSectionReader) -> Result<()> {
1767 for (i, elem) in data.into_iter_with_offsets().enumerate() {
1768 let (offset, mut elem) = elem?;
1769 self.newline(offset)?;
1770 self.start_group("elem ")?;
1771 self.print_name(&state.core.element_names, i as u32)?;
1772 match &mut elem.kind {
1773 ElementKind::Passive => {}
1774 ElementKind::Declared => self.result.write_str(" declare")?,
1775 ElementKind::Active {
1776 table_index,
1777 offset_expr,
1778 } => {
1779 if let Some(table_index) = *table_index {
1780 self.result.write_str(" ")?;
1781 self.start_group("table ")?;
1782 self.print_idx(&state.core.table_names, table_index)?;
1783 self.end_group()?;
1784 }
1785 self.result.write_str(" ")?;
1786 self.print_const_expr_sugar(state, offset_expr, "offset")?;
1787 }
1788 }
1789 self.result.write_str(" ")?;
1790
1791 if self.config.print_skeleton {
1792 self.result.write_str("...")?;
1793 } else {
1794 match elem.items {
1795 ElementItems::Functions(reader) => {
1796 self.result.write_str("func")?;
1797 for idx in reader {
1798 self.result.write_str(" ")?;
1799 self.print_idx(&state.core.func_names, idx?)?
1800 }
1801 }
1802 ElementItems::Expressions(ty, reader) => {
1803 self.print_reftype(state, ty)?;
1804 for expr in reader {
1805 self.result.write_str(" ")?;
1806 self.print_const_expr_sugar(state, &expr?, "item")?
1807 }
1808 }
1809 }
1810 }
1811 self.end_group()?;
1812 }
1813 Ok(())
1814 }
1815
1816 fn print_data(&mut self, state: &mut State, data: DataSectionReader) -> Result<()> {
1817 for (i, data) in data.into_iter_with_offsets().enumerate() {
1818 let (offset, data) = data?;
1819 self.newline(offset)?;
1820 self.start_group("data ")?;
1821 self.print_name(&state.core.data_names, i as u32)?;
1822 self.result.write_str(" ")?;
1823 match &data.kind {
1824 DataKind::Passive => {}
1825 DataKind::Active {
1826 memory_index,
1827 offset_expr,
1828 } => {
1829 if *memory_index != 0 {
1830 self.start_group("memory ")?;
1831 self.print_idx(&state.core.memory_names, *memory_index)?;
1832 self.end_group()?;
1833 self.result.write_str(" ")?;
1834 }
1835 self.print_const_expr_sugar(state, offset_expr, "offset")?;
1836 self.result.write_str(" ")?;
1837 }
1838 }
1839 if self.config.print_skeleton {
1840 self.result.write_str("...")?;
1841 } else {
1842 self.print_bytes(data.data)?;
1843 }
1844 self.end_group()?;
1845 }
1846 Ok(())
1847 }
1848
1849 fn print_const_expr_sugar(
1853 &mut self,
1854 state: &mut State,
1855 expr: &ConstExpr,
1856 explicit: &str,
1857 ) -> Result<()> {
1858 self.start_group("")?;
1859 let mut reader = expr.get_operators_reader();
1860
1861 if reader.read().is_ok() && !reader.is_end_then_eof() {
1862 write!(self.result, "{explicit} ")?;
1863 self.print_const_expr(state, expr, self.config.fold_instructions)?;
1864 } else {
1865 self.print_const_expr(state, expr, false)?;
1866 }
1867
1868 self.end_group()?;
1869 Ok(())
1870 }
1871
1872 fn print_const_expr(&mut self, state: &mut State, expr: &ConstExpr, fold: bool) -> Result<()> {
1874 let mut reader = expr.get_binary_reader();
1875 let mut operator_state = OperatorState::new(self, OperatorSeparator::NoneThenSpace);
1876
1877 if fold {
1878 let mut folded_printer = PrintOperatorFolded::new(self, state, &mut operator_state);
1879 folded_printer.begin_const_expr();
1880 Self::print_operators(&mut reader, &[], 0, &mut folded_printer, None)?;
1881 } else {
1882 let mut op_printer = PrintOperator::new(self, state, &mut operator_state);
1883 Self::print_operators(&mut reader, &[], 0, &mut op_printer, None)?;
1884 }
1885
1886 Ok(())
1887 }
1888
1889 fn print_str(&mut self, name: &str) -> Result<()> {
1890 self.result.start_literal()?;
1891 self.result.write_str("\"")?;
1892 self.print_str_contents(name)?;
1893 self.result.write_str("\"")?;
1894 self.result.reset_color()?;
1895 Ok(())
1896 }
1897
1898 fn print_str_contents(&mut self, name: &str) -> Result<()> {
1899 for c in name.chars() {
1900 let v = c as u32;
1901 if (0x20..0x7f).contains(&v) && c != '"' && c != '\\' && v < 0xff {
1902 write!(self.result, "{c}")?;
1903 } else {
1904 write!(self.result, "\\u{{{v:x}}}",)?;
1905 }
1906 }
1907 Ok(())
1908 }
1909
1910 fn print_bytes(&mut self, bytes: &[u8]) -> Result<()> {
1911 self.result.start_literal()?;
1912 self.result.write_str("\"")?;
1913 for byte in bytes {
1914 if *byte >= 0x20 && *byte < 0x7f && *byte != b'"' && *byte != b'\\' {
1915 write!(self.result, "{}", *byte as char)?;
1916 } else {
1917 self.hex_byte(*byte)?;
1918 }
1919 }
1920 self.result.write_str("\"")?;
1921 self.result.reset_color()?;
1922 Ok(())
1923 }
1924
1925 fn hex_byte(&mut self, byte: u8) -> Result<()> {
1926 write!(self.result, "\\{byte:02x}")?;
1927 Ok(())
1928 }
1929
1930 fn print_known_custom_section(&mut self, section: CustomSectionReader<'_>) -> Result<bool> {
1931 match section.as_known() {
1932 KnownCustom::Producers(s) => {
1936 self.newline(section.range().start)?;
1937 self.print_producers_section(s)?;
1938 Ok(true)
1939 }
1940 KnownCustom::Dylink0(s) => {
1941 self.newline(section.range().start)?;
1942 self.print_dylink0_section(s)?;
1943 Ok(true)
1944 }
1945
1946 KnownCustom::Name(_) | KnownCustom::BranchHints(_) => Ok(true),
1949 #[cfg(feature = "component-model")]
1950 KnownCustom::ComponentName(_) => Ok(true),
1951
1952 _ => Ok(false),
1953 }
1954 }
1955
1956 fn print_raw_custom_section(
1957 &mut self,
1958 state: &State,
1959 section: CustomSectionReader<'_>,
1960 ) -> Result<()> {
1961 self.newline(section.range().start)?;
1962 self.start_group("@custom ")?;
1963 self.print_str(section.name())?;
1964 if let Some((place, _)) = state.custom_section_place {
1965 write!(self.result, " ({place})")?;
1966 }
1967 self.result.write_str(" ")?;
1968 if self.config.print_skeleton {
1969 self.result.write_str("...")?;
1970 } else {
1971 self.print_bytes(section.data())?;
1972 }
1973 self.end_group()?;
1974 Ok(())
1975 }
1976
1977 fn print_producers_section(&mut self, section: ProducersSectionReader<'_>) -> Result<()> {
1978 self.start_group("@producers")?;
1979 for field in section {
1980 let field = field?;
1981 for value in field.values.into_iter_with_offsets() {
1982 let (offset, value) = value?;
1983 self.newline(offset)?;
1984 self.start_group(field.name)?;
1985 self.result.write_str(" ")?;
1986 self.print_str(value.name)?;
1987 self.result.write_str(" ")?;
1988 self.print_str(value.version)?;
1989 self.end_group()?;
1990 }
1991 }
1992 self.end_group()?;
1993 Ok(())
1994 }
1995
1996 fn print_dylink0_section(&mut self, mut section: Dylink0SectionReader<'_>) -> Result<()> {
1997 self.start_group("@dylink.0")?;
1998 loop {
1999 let start = section.original_position();
2000 let next = match section.next() {
2001 Some(Ok(next)) => next,
2002 Some(Err(e)) => return Err(e.into()),
2003 None => break,
2004 };
2005 match next {
2006 Dylink0Subsection::MemInfo(info) => {
2007 self.newline(start)?;
2008 self.start_group("mem-info")?;
2009 if info.memory_size > 0 || info.memory_alignment > 0 {
2010 write!(
2011 self.result,
2012 " (memory {} {})",
2013 info.memory_size, info.memory_alignment
2014 )?;
2015 }
2016 if info.table_size > 0 || info.table_alignment > 0 {
2017 write!(
2018 self.result,
2019 " (table {} {})",
2020 info.table_size, info.table_alignment
2021 )?;
2022 }
2023 self.end_group()?;
2024 }
2025 Dylink0Subsection::Needed(needed) => {
2026 self.newline(start)?;
2027 self.start_group("needed")?;
2028 for s in needed {
2029 self.result.write_str(" ")?;
2030 self.print_str(s)?;
2031 }
2032 self.end_group()?;
2033 }
2034 Dylink0Subsection::ExportInfo(info) => {
2035 for info in info {
2036 self.newline(start)?;
2037 self.start_group("export-info ")?;
2038 self.print_str(info.name)?;
2039 self.print_dylink0_flags(info.flags)?;
2040 self.end_group()?;
2041 }
2042 }
2043 Dylink0Subsection::ImportInfo(info) => {
2044 for info in info {
2045 self.newline(start)?;
2046 self.start_group("import-info ")?;
2047 self.print_str(info.module)?;
2048 self.result.write_str(" ")?;
2049 self.print_str(info.field)?;
2050 self.print_dylink0_flags(info.flags)?;
2051 self.end_group()?;
2052 }
2053 }
2054 Dylink0Subsection::RuntimePath(runtime_path) => {
2055 self.newline(start)?;
2056 self.start_group("runtime-path")?;
2057 for s in runtime_path {
2058 self.result.write_str(" ")?;
2059 self.print_str(s)?;
2060 }
2061 self.end_group()?;
2062 }
2063 Dylink0Subsection::Unknown { ty, .. } => {
2064 bail!("don't know how to print dylink.0 subsection id {ty}");
2065 }
2066 }
2067 }
2068 self.end_group()?;
2069 Ok(())
2070 }
2071
2072 fn print_dylink0_flags(&mut self, mut flags: SymbolFlags) -> Result<()> {
2073 macro_rules! print_flag {
2074 ($($name:ident = $text:tt)*) => ({$(
2075 if flags.contains(SymbolFlags::$name) {
2076 flags.remove(SymbolFlags::$name);
2077 write!(self.result, concat!(" ", $text))?;
2078 }
2079 )*})
2080 }
2081 print_flag! {
2083 BINDING_WEAK = "binding-weak"
2084 BINDING_LOCAL = "binding-local"
2085 VISIBILITY_HIDDEN = "visibility-hidden"
2086 UNDEFINED = "undefined"
2087 EXPORTED = "exported"
2088 EXPLICIT_NAME = "explicit-name"
2089 NO_STRIP = "no-strip"
2090 TLS = "tls"
2091 ABSOLUTE = "absolute"
2092 }
2093 if !flags.is_empty() {
2094 write!(self.result, " {flags:#x}")?;
2095 }
2096 Ok(())
2097 }
2098
2099 fn register_branch_hint_section(&mut self, section: BranchHintSectionReader<'_>) -> Result<()> {
2100 self.code_section_hints.clear();
2101 for func in section {
2102 let func = func?;
2103 if self.code_section_hints.len() >= MAX_WASM_FUNCTIONS as usize {
2104 bail!("found too many hints");
2105 }
2106 if func.hints.count() >= MAX_WASM_FUNCTION_SIZE {
2107 bail!("found too many hints");
2108 }
2109 let hints = func
2110 .hints
2111 .into_iter_with_offsets()
2112 .collect::<wasmparser::Result<Vec<_>>>()?;
2113 self.code_section_hints.push((func.func, hints));
2114 }
2115 self.code_section_hints.reverse();
2116 Ok(())
2117 }
2118}
2119
2120struct NamedLocalPrinter {
2121 group_name: &'static str,
2122 in_group: bool,
2123 end_group_after_local: bool,
2124 first: bool,
2125}
2126
2127impl NamedLocalPrinter {
2128 fn new(group_name: &'static str) -> NamedLocalPrinter {
2129 NamedLocalPrinter {
2130 group_name,
2131 in_group: false,
2132 end_group_after_local: false,
2133 first: true,
2134 }
2135 }
2136
2137 fn start_local(
2138 &mut self,
2139 func: Option<u32>,
2140 local: u32,
2141 dst: &mut Printer,
2142 state: &State,
2143 ) -> Result<()> {
2144 let name = state
2145 .core
2146 .local_names
2147 .index_to_name
2148 .get(&(func.unwrap_or(u32::MAX), local));
2149
2150 if name.is_some() && self.in_group {
2153 dst.end_group()?;
2154 self.in_group = false;
2155 }
2156
2157 if self.first {
2158 self.first = false;
2159 } else {
2160 dst.result.write_str(" ")?;
2161 }
2162
2163 if !self.in_group {
2166 dst.start_group(self.group_name)?;
2167 dst.result.write_str(" ")?;
2168 self.in_group = true;
2169 }
2170
2171 match name {
2173 Some(name) => {
2174 name.write(dst)?;
2175 dst.result.write_str(" ")?;
2176 self.end_group_after_local = true;
2177 }
2178 None if dst.config.name_unnamed && func.is_some() => {
2179 write!(dst.result, "$#local{local} ")?;
2180 self.end_group_after_local = true;
2181 }
2182 None => {
2183 self.end_group_after_local = false;
2184 }
2185 }
2186 Ok(())
2187 }
2188
2189 fn end_local(&mut self, dst: &mut Printer) -> Result<()> {
2190 if self.end_group_after_local {
2191 dst.end_group()?;
2192 self.end_group_after_local = false;
2193 self.in_group = false;
2194 }
2195 Ok(())
2196 }
2197 fn finish(self, dst: &mut Printer) -> Result<()> {
2198 if self.in_group {
2199 dst.end_group()?;
2200 }
2201 Ok(())
2202 }
2203}
2204
2205macro_rules! print_float {
2206 ($name:ident $float:ident $uint:ident $sint:ident $exp_bits:tt) => {
2207 fn $name(&mut self, mut bits: $uint) -> Result<()> {
2208 let int_width = mem::size_of::<$uint>() * 8;
2210 let exp_width = $exp_bits;
2211 let mantissa_width = int_width - 1 - exp_width;
2212 let bias = (1 << (exp_width - 1)) - 1;
2213 let max_exp = (1 as $sint) << (exp_width - 1);
2214 let min_exp = -max_exp + 1;
2215
2216 let f = $float::from_bits(bits);
2218 if bits >> (int_width - 1) != 0 {
2219 bits ^= 1 << (int_width - 1);
2220 self.result.write_str("-")?;
2221 }
2222 if f.is_infinite() {
2223 self.result.start_literal()?;
2224 self.result.write_str("inf ")?;
2225 self.result.start_comment()?;
2226 write!(self.result, "(;={f};)")?;
2227 self.result.reset_color()?;
2228 return Ok(());
2229 }
2230 if f.is_nan() {
2231 let payload = bits & ((1 << mantissa_width) - 1);
2232 self.result.start_literal()?;
2233 if payload == 1 << (mantissa_width - 1) {
2234 self.result.write_str("nan ")?;
2235 self.result.start_comment()?;
2236 write!(self.result, "(;={f};)")?;
2237 } else {
2238 write!(self.result, "nan:{:#x} ", payload)?;
2239 self.result.start_comment()?;
2240 write!(self.result, "(;={f};)")?;
2241 }
2242 self.result.reset_color()?;
2243 return Ok(());
2244 }
2245
2246 let mut exponent = (((bits << 1) as $sint) >> (mantissa_width + 1)).wrapping_sub(bias);
2262 exponent = (exponent << (int_width - exp_width)) >> (int_width - exp_width);
2263 let mut fraction = bits & ((1 << mantissa_width) - 1);
2264 self.result.start_literal()?;
2265 self.result.write_str("0x")?;
2266 if bits == 0 {
2267 self.result.write_str("0p+0")?;
2268 } else {
2269 self.result.write_str("1")?;
2270 if fraction > 0 {
2271 fraction <<= (int_width - mantissa_width);
2272
2273 if exponent == min_exp {
2277 let leading = fraction.leading_zeros();
2278 if (leading as usize) < int_width - 1 {
2279 fraction <<= leading + 1;
2280 } else {
2281 fraction = 0;
2282 }
2283 exponent -= leading as $sint;
2284 }
2285
2286 self.result.write_str(".")?;
2287 while fraction > 0 {
2288 write!(self.result, "{:x}", fraction >> (int_width - 4))?;
2289 fraction <<= 4;
2290 }
2291 }
2292 write!(self.result, "p{:+}", exponent)?;
2293 }
2294 self.result.start_comment()?;
2295 write!(self.result, " (;={};)", f)?;
2296 self.result.reset_color()?;
2297 Ok(())
2298 }
2299 };
2300}
2301
2302impl Printer<'_, '_> {
2303 print_float!(print_f32 f32 u32 i32 8);
2304 print_float!(print_f64 f64 u64 i64 11);
2305}
2306
2307impl Naming {
2308 fn new<'a>(
2309 name: &'a str,
2310 index: u32,
2311 group: &str,
2312 used: Option<&mut HashSet<&'a str>>,
2313 ) -> Naming {
2314 let mut kind = NamingKind::DollarName;
2315 if name.chars().any(|c| !is_idchar(c)) {
2316 kind = NamingKind::DollarQuotedName;
2317 }
2318
2319 if name.is_empty()
2338 || name.starts_with('#')
2339 || used.map(|set| !set.insert(name)).unwrap_or(false)
2340 {
2341 kind = NamingKind::SyntheticPrefix(format!("#{group}{index}"));
2342 }
2343 return Naming {
2344 kind,
2345 name: name.to_string(),
2346 };
2347
2348 fn is_idchar(c: char) -> bool {
2350 matches!(
2351 c,
2352 '0'..='9'
2353 | 'a'..='z'
2354 | 'A'..='Z'
2355 | '!'
2356 | '#'
2357 | '$'
2358 | '%'
2359 | '&'
2360 | '\''
2361 | '*'
2362 | '+'
2363 | '-'
2364 | '.'
2365 | '/'
2366 | ':'
2367 | '<'
2368 | '='
2369 | '>'
2370 | '?'
2371 | '@'
2372 | '\\'
2373 | '^'
2374 | '_'
2375 | '`'
2376 | '|'
2377 | '~'
2378 )
2379 }
2380 }
2381
2382 fn write_identifier(&self, printer: &mut Printer<'_, '_>) -> Result<()> {
2383 match &self.kind {
2384 NamingKind::DollarName => {
2385 printer.result.write_str("$")?;
2386 printer.result.write_str(&self.name)?;
2387 }
2388 NamingKind::DollarQuotedName => {
2389 printer.result.write_str("$\"")?;
2390 printer.print_str_contents(&self.name)?;
2391 printer.result.write_str("\"")?;
2392 }
2393 NamingKind::SyntheticPrefix(prefix) => {
2394 printer.result.write_str("$\"")?;
2395 printer.result.write_str(&prefix)?;
2396 printer.result.write_str(" ")?;
2397 printer.print_str_contents(&self.name)?;
2398 printer.result.write_str("\"")?;
2399 }
2400 }
2401 Ok(())
2402 }
2403
2404 fn write(&self, dst: &mut Printer<'_, '_>) -> Result<()> {
2405 self.write_identifier(dst)?;
2406 match &self.kind {
2407 NamingKind::DollarName | NamingKind::DollarQuotedName => {}
2408
2409 NamingKind::SyntheticPrefix(_) => {
2410 dst.result.write_str(" ")?;
2411 dst.start_group("@name \"")?;
2412 dst.print_str_contents(&self.name)?;
2413 dst.result.write_str("\"")?;
2414 dst.end_group()?;
2415 }
2416 }
2417 Ok(())
2418 }
2419}
2420
2421trait NamingNamespace {
2423 fn desc() -> &'static str;
2424}
2425
2426macro_rules! naming_namespaces {
2427 ($(struct $name:ident => $desc:tt)*) => ($(
2428 struct $name;
2429
2430 impl NamingNamespace for $name {
2431 fn desc() -> &'static str { $desc }
2432 }
2433 )*)
2434}
2435
2436naming_namespaces! {
2437 struct NameFunc => "func"
2438 struct NameGlobal => "global"
2439 struct NameMemory => "memory"
2440 struct NameLocal => "local"
2441 struct NameLabel => "label"
2442 struct NameTable => "table"
2443 struct NameType => "type"
2444 struct NameField => "field"
2445 struct NameData => "data"
2446 struct NameElem => "elem"
2447 struct NameTag => "tag"
2448}
2449
2450#[cfg(feature = "component-model")]
2451naming_namespaces! {
2452 struct NameModule => "module"
2453 struct NameInstance => "instance"
2454 struct NameValue => "value"
2455 struct NameComponent => "component"
2456}
2457
2458fn name_map<K>(into: &mut NamingMap<u32, K>, names: NameMap<'_>, name: &str) -> Result<()> {
2459 let mut used = HashSet::new();
2460 for naming in names {
2461 let naming = naming?;
2462 into.index_to_name.insert(
2463 naming.index,
2464 Naming::new(naming.name, naming.index, name, Some(&mut used)),
2465 );
2466 }
2467 Ok(())
2468}