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 if let Some(params) = &func.params {
70 writeln!(f, " params {params}")?;
71 }
72 types_list(f, "regs", "r", &func.regs)?;
73 types_list(f, "captures", "u", &func.captures)?;
74 if !func.names.is_empty() {
75 f.write_str(" names")?;
76 for (i, s) in func.names.iter().enumerate() {
77 write!(f, " n{i}={s}")?;
78 }
79 writeln!(f)?;
80 }
81 if !func.type_refs.is_empty() {
82 f.write_str(" type_refs")?;
83 for (i, t) in func.type_refs.iter().enumerate() {
84 write!(f, " ty{i}={t}")?;
85 }
86 writeln!(f)?;
87 }
88 let labels = labels(func);
89 let cx = Cx {
90 labels: &labels,
91 module: Some(m),
92 func: Some(func),
93 };
94 let target = |f: &mut fmt::Formatter<'_>, pc: u32| -> fmt::Result {
95 match labels.binary_search(&pc) {
96 Ok(i) => write!(f, "L{i}"),
97 Err(_) => write!(f, "@{pc}"),
98 }
99 };
100 for (i, table) in func.tables.iter().enumerate() {
101 write!(f, " table jt{i} [")?;
102 for (j, t) in table.targets.iter().enumerate() {
103 if j > 0 {
104 f.write_str(", ")?;
105 }
106 target(f, t.0)?;
107 }
108 f.write_str("] default ")?;
109 target(f, table.default.0)?;
110 writeln!(f)?;
111 }
112 for (i, shape) in func.shapes.iter().enumerate() {
113 writeln!(f, " shape cs{i} {shape}")?;
114 }
115 for h in &func.handlers {
116 write!(f, " try @{}..@{} -> ", h.start, h.end)?;
117 target(f, h.target.0)?;
118 writeln!(f, " catch {}", h.catch)?;
119 }
120 for local in &func.locals {
121 write!(f, " local {} ", local.reg)?;
122 named(f, m, local.name)?;
123 writeln!(f, " @{}..@{}", local.start, local.end)?;
124 }
125 for row in &func.lines {
126 writeln!(
127 f,
128 " line @{} {}:{}:{}",
129 row.pc, row.file, row.line, row.column
130 )?;
131 }
132 let mut next_label = 0usize;
133 for (pc, inst) in func.code.iter().enumerate() {
134 if labels.get(next_label).is_some_and(|&l| l as usize == pc) {
135 writeln!(f, "L{next_label}:")?;
136 next_label += 1;
137 }
138 write!(f, " {pc:04} ")?;
139 inst.render(f, &cx)?;
140 writeln!(f)?;
141 }
142 Ok(())
143}
144
145impl fmt::Display for Module {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 let m = self;
149 writeln!(f, "lsb {FORMAT_VERSION}")?;
150 if let Some(name) = m.name {
151 f.write_str("module ")?;
152 named(f, m, name)?;
153 writeln!(f)?;
154 }
155 if let Some(start) = m.start {
156 writeln!(f, "start {start}")?;
157 }
158
159 writeln!(f, "strings {}", m.strings.len())?;
160 for (i, s) in m.strings.iter().enumerate() {
161 write!(f, " s{i} ")?;
162 write_quoted(f, s)?;
163 writeln!(f)?;
164 }
165 writeln!(f, "types {}", m.types.len())?;
166 for (i, t) in m.types.iter().enumerate() {
167 writeln!(f, " t{i} {t}")?;
168 }
169 writeln!(f, "consts {}", m.consts.len())?;
170 for (i, c) in m.consts.iter().enumerate() {
171 write!(f, " k{i} {c}")?;
172 if let crate::Const::Str(_) = c {
173 f.write_str(" ; ")?;
174 write_const_preview(f, m, c)?;
175 }
176 writeln!(f)?;
177 }
178 writeln!(f, "imports {}", m.imports.len())?;
179 for (i, imp) in m.imports.iter().enumerate() {
180 write!(f, " imp{i} ")?;
181 named(f, m, imp.module)?;
182 f.write_str(" . ")?;
183 named(f, m, imp.name)?;
184 write!(f, " : {}", imp.sig)?;
185 if let Some(params) = &imp.params {
186 write!(f, " params {params}")?;
187 }
188 writeln!(f)?;
189 }
190 writeln!(f, "globals {}", m.globals.len())?;
191 for (i, g) in m.globals.iter().enumerate() {
192 write!(f, " g{i} ")?;
193 named(f, m, g.name)?;
194 write!(f, " : {}", g.ty)?;
195 if g.mutable {
196 f.write_str(" mut")?;
197 }
198 if let Some(init) = g.init {
199 write!(f, " = {init}")?;
200 }
201 writeln!(f)?;
202 }
203 writeln!(f, "exports {}", m.exports.len())?;
204 for e in &m.exports {
205 f.write_str(" ")?;
206 named(f, m, e.name)?;
207 writeln!(f, " = {}", e.item)?;
208 }
209 writeln!(f, "hooks {}", m.hooks.len())?;
210 for b in &m.hooks {
211 writeln!(f, " {} = {}", b.hook, b.callee)?;
212 }
213 writeln!(f, "functions {}", m.functions.len())?;
214 for (i, func) in m.functions.iter().enumerate() {
215 function(f, m, i, func)?;
216 }
217 Ok(())
218 }
219}