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