1use alloc::vec::Vec;
10use core::fmt;
11
12use crate::FORMAT_VERSION;
13use crate::inst::{Cx, write_const_preview, write_quoted};
14use crate::module::{Function, Module};
15use crate::types::ValType;
16
17fn named(f: &mut fmt::Formatter<'_>, m: &Module, id: crate::StrId) -> fmt::Result {
19 write!(f, "{id} ")?;
20 match m.string(id) {
21 Some(s) => write_quoted(f, s),
22 None => f.write_str("<invalid>"),
23 }
24}
25
26fn types_list(
27 f: &mut fmt::Formatter<'_>,
28 label: &str,
29 prefix: &str,
30 types: &[ValType],
31) -> fmt::Result {
32 if types.is_empty() {
33 return Ok(());
34 }
35 write!(f, " {label}")?;
36 for (i, ty) in types.iter().enumerate() {
37 write!(f, " {prefix}{i}:{ty}")?;
38 }
39 writeln!(f)
40}
41
42fn labels(func: &Function) -> Vec<u32> {
45 let len = func.code.len();
46 let mut out: Vec<u32> = func
47 .code
48 .iter()
49 .filter_map(crate::Inst::branch_target)
50 .map(|t| t.0)
51 .chain(func.tables.iter().flat_map(|t| {
52 t.targets
53 .iter()
54 .map(|t| t.0)
55 .chain(core::iter::once(t.default.0))
56 }))
57 .chain(func.handlers.iter().map(|h| h.target.0))
58 .filter(|&pc| (pc as usize) < len)
59 .collect();
60 out.sort_unstable();
61 out.dedup();
62 out
63}
64
65fn function(f: &mut fmt::Formatter<'_>, m: &Module, id: usize, func: &Function) -> fmt::Result {
66 write!(f, "\nfunc f{id} ")?;
67 named(f, m, func.name)?;
68 writeln!(f, " : {}", func.sig)?;
69 types_list(f, "regs", "r", &func.regs)?;
70 types_list(f, "captures", "u", &func.captures)?;
71 if !func.names.is_empty() {
72 f.write_str(" names")?;
73 for (i, s) in func.names.iter().enumerate() {
74 write!(f, " n{i}={s}")?;
75 }
76 writeln!(f)?;
77 }
78 if !func.type_refs.is_empty() {
79 f.write_str(" type_refs")?;
80 for (i, t) in func.type_refs.iter().enumerate() {
81 write!(f, " ty{i}={t}")?;
82 }
83 writeln!(f)?;
84 }
85 let labels = labels(func);
86 let cx = Cx {
87 labels: &labels,
88 module: Some(m),
89 func: Some(func),
90 };
91 let target = |f: &mut fmt::Formatter<'_>, pc: u32| -> fmt::Result {
92 match labels.binary_search(&pc) {
93 Ok(i) => write!(f, "L{i}"),
94 Err(_) => write!(f, "@{pc}"),
95 }
96 };
97 for (i, table) in func.tables.iter().enumerate() {
98 write!(f, " table jt{i} [")?;
99 for (j, t) in table.targets.iter().enumerate() {
100 if j > 0 {
101 f.write_str(", ")?;
102 }
103 target(f, t.0)?;
104 }
105 f.write_str("] default ")?;
106 target(f, table.default.0)?;
107 writeln!(f)?;
108 }
109 for h in &func.handlers {
110 write!(f, " try @{}..@{} -> ", h.start, h.end)?;
111 target(f, h.target.0)?;
112 writeln!(f, " catch {}", h.catch)?;
113 }
114 for local in &func.locals {
115 write!(f, " local {} ", local.reg)?;
116 named(f, m, local.name)?;
117 writeln!(f, " @{}..@{}", local.start, local.end)?;
118 }
119 for row in &func.lines {
120 writeln!(
121 f,
122 " line @{} {}:{}:{}",
123 row.pc, row.file, row.line, row.column
124 )?;
125 }
126 let mut next_label = 0usize;
127 for (pc, inst) in func.code.iter().enumerate() {
128 if labels.get(next_label).is_some_and(|&l| l as usize == pc) {
129 writeln!(f, "L{next_label}:")?;
130 next_label += 1;
131 }
132 write!(f, " {pc:04} ")?;
133 inst.render(f, &cx)?;
134 writeln!(f)?;
135 }
136 Ok(())
137}
138
139impl fmt::Display for Module {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 let m = self;
143 writeln!(f, "lsb {FORMAT_VERSION}")?;
144 if let Some(name) = m.name {
145 f.write_str("module ")?;
146 named(f, m, name)?;
147 writeln!(f)?;
148 }
149 if let Some(start) = m.start {
150 writeln!(f, "start {start}")?;
151 }
152
153 writeln!(f, "strings {}", m.strings.len())?;
154 for (i, s) in m.strings.iter().enumerate() {
155 write!(f, " s{i} ")?;
156 write_quoted(f, s)?;
157 writeln!(f)?;
158 }
159 writeln!(f, "types {}", m.types.len())?;
160 for (i, t) in m.types.iter().enumerate() {
161 writeln!(f, " t{i} {t}")?;
162 }
163 writeln!(f, "consts {}", m.consts.len())?;
164 for (i, c) in m.consts.iter().enumerate() {
165 write!(f, " k{i} {c}")?;
166 if let crate::Const::Str(_) = c {
167 f.write_str(" ; ")?;
168 write_const_preview(f, m, c)?;
169 }
170 writeln!(f)?;
171 }
172 writeln!(f, "imports {}", m.imports.len())?;
173 for (i, imp) in m.imports.iter().enumerate() {
174 write!(f, " imp{i} ")?;
175 named(f, m, imp.module)?;
176 f.write_str(" . ")?;
177 named(f, m, imp.name)?;
178 writeln!(f, " : {}", imp.sig)?;
179 }
180 writeln!(f, "globals {}", m.globals.len())?;
181 for (i, g) in m.globals.iter().enumerate() {
182 write!(f, " g{i} ")?;
183 named(f, m, g.name)?;
184 write!(f, " : {}", g.ty)?;
185 if g.mutable {
186 f.write_str(" mut")?;
187 }
188 if let Some(init) = g.init {
189 write!(f, " = {init}")?;
190 }
191 writeln!(f)?;
192 }
193 writeln!(f, "exports {}", m.exports.len())?;
194 for e in &m.exports {
195 f.write_str(" ")?;
196 named(f, m, e.name)?;
197 writeln!(f, " = {}", e.item)?;
198 }
199 writeln!(f, "hooks {}", m.hooks.len())?;
200 for b in &m.hooks {
201 writeln!(f, " {} = {}", b.hook, b.callee)?;
202 }
203 writeln!(f, "functions {}", m.functions.len())?;
204 for (i, func) in m.functions.iter().enumerate() {
205 function(f, m, i, func)?;
206 }
207 Ok(())
208 }
209}