Coverage Report

Created: 2026-03-26 07:41

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