1#![deny(missing_docs)]
8
9use anyhow::Context;
10use std::fmt::Write;
11use std::path::Path;
12use wasmprinter::Printer;
13use wit_parser::*;
14
15pub fn print_file(file: impl AsRef<Path>) -> anyhow::Result<String> {
22 _print_file(file.as_ref())
23}
24
25fn _print_file(file: &Path) -> anyhow::Result<String> {
26 let contents = std::fs::read(file).context(format!("failed to read `{}`", file.display()))?;
27 _print_bytes(&contents)
28}
29
30pub fn print_bytes(wasm: impl AsRef<[u8]>) -> anyhow::Result<String> {
37 _print_bytes(wasm.as_ref())
38}
39
40fn _print_bytes(wasm: &[u8]) -> anyhow::Result<String> {
41 let mut printer = Printer::new();
42 printer.add_custom_section_printer(wit_schema_version::SECTION_NAME, print_wit);
43 printer.print(wasm)
44}
45
46fn print_wit(printer: &mut Printer, offset: usize, bytes: &[u8]) -> anyhow::Result<()> {
47 let mut parser = Parser::new(offset, bytes).context("failed to parse header")?;
48 let mut func = 0;
49 while !parser.is_empty() {
50 match parser.section().context("failed to parse section")? {
51 Section::Type(types) => {
52 let ret = printer.result_mut();
53 for (i, ty) in types.into_iter().enumerate() {
54 let ty = ty.context("failed to parse type")?;
55 write!(ret, "\n (@interface type (;{};) (func", i)?;
56 for param in ty.params.iter() {
57 ret.push_str(" (param ");
58 push_ty(ret, param);
59 ret.push_str(")");
60 }
61 for result in ty.results.iter() {
62 ret.push_str(" (result ");
63 push_ty(ret, result);
64 ret.push_str(")");
65 }
66 ret.push_str("))");
67 }
68 }
69 Section::Import(imports) => {
70 let ret = printer.result_mut();
71 for i in imports {
72 let i = i.context("failed to parse import")?;
73 write!(
74 ret,
75 "\n (@interface import \"{}\" \"{}\" \
76 (func (;{};) (type {})))",
77 i.module, i.name, func, i.ty,
78 )?;
79 func += 1;
80 }
81 }
82 Section::Export(exports) => {
83 let ret = printer.result_mut();
84 for e in exports {
85 let e = e.context("failed to parse export")?;
86 ret.push_str("\n (@interface export ");
87 ret.push_str("\"");
88 ret.push_str(e.name);
89 ret.push_str("\" (func ");
90 ret.push_str(&format!("{}", e.func));
91 ret.push_str("))");
92 }
93 }
94 Section::Func(funcs) => {
95 for f in funcs {
96 let f = f.context("failed to parse func")?;
97 write!(
98 printer.result_mut(),
99 "\n (@interface func (;{};) (type {})",
100 func,
101 f.ty
102 )?;
103 for instr in f.instrs() {
104 let instr = instr.context("failed to parse instruction")?;
105 printer.result_mut().push_str("\n ");
106 push_instr(printer, &instr)?;
107 }
108 printer.result_mut().push_str(")");
109 func += 1;
110 }
111 }
112 Section::Implement(implements) => {
113 for i in implements {
114 let i = i.context("failed to parse implement")?;
115 printer
116 .result_mut()
117 .push_str("\n (@interface implement (func ");
118 printer.print_func_idx(i.core_func)?;
119 printer.result_mut().push_str(") (func ");
120 printer
121 .result_mut()
122 .push_str(&format!("{}", i.adapter_func));
123 printer.result_mut().push_str("))");
124 }
125 }
126 }
127 }
128 return Ok(());
129
130 fn push_ty(ret: &mut String, param: &ValType) {
131 match param {
132 ValType::S8 => ret.push_str("s8"),
133 ValType::S16 => ret.push_str("s16"),
134 ValType::S32 => ret.push_str("s32"),
135 ValType::S64 => ret.push_str("s64"),
136 ValType::U8 => ret.push_str("u8"),
137 ValType::U16 => ret.push_str("u16"),
138 ValType::U32 => ret.push_str("u32"),
139 ValType::U64 => ret.push_str("u64"),
140 ValType::F32 => ret.push_str("f32"),
141 ValType::F64 => ret.push_str("f64"),
142 ValType::String => ret.push_str("string"),
143 ValType::Externref => ret.push_str("externref"),
144 ValType::I32 => ret.push_str("i32"),
145 ValType::I64 => ret.push_str("i64"),
146 }
147 }
148
149 fn push_instr(ret: &mut Printer, instr: &Instruction) -> anyhow::Result<()> {
150 use Instruction::*;
151
152 match instr {
153 ArgGet(i) => write!(ret.result_mut(), "arg.get {}", i)?,
154 CallCore(i) => {
155 ret.result_mut().push_str("call-core ");
156 ret.print_func_idx(*i)?;
157 }
158 End => ret.result_mut().push_str("end"),
159 MemoryToString(mem) => {
160 ret.result_mut().push_str("memory-to-string");
161 if *mem != 0 {
162 write!(ret.result_mut(), " {}", mem)?;
163 }
164 }
165 StringToMemory(payload) => {
166 ret.result_mut().push_str("string-to-memory ");
167 ret.print_func_idx(payload.malloc)?;
168 if payload.mem != 0 {
169 write!(ret.result_mut(), " {}", payload.mem)?;
170 }
171 }
172 CallAdapter(f) => write!(ret.result_mut(), "call-adapter {}", f)?,
173 DeferCallCore(f) => {
174 ret.result_mut().push_str("defer-call-core ");
175 ret.print_func_idx(*f)?;
176 }
177
178 I32ToS8 => ret.result_mut().push_str("i32-to-s8"),
179 I32ToS8X => ret.result_mut().push_str("i32-to-s8x"),
180 I32ToU8 => ret.result_mut().push_str("i32-to-u8"),
181 I32ToS16 => ret.result_mut().push_str("i32-to-s16"),
182 I32ToS16X => ret.result_mut().push_str("i32-to-s16x"),
183 I32ToU16 => ret.result_mut().push_str("i32-to-u16"),
184 I32ToS32 => ret.result_mut().push_str("i32-to-s32"),
185 I32ToU32 => ret.result_mut().push_str("i32-to-u32"),
186 I32ToS64 => ret.result_mut().push_str("i32-to-s64"),
187 I32ToU64 => ret.result_mut().push_str("i32-to-u64"),
188
189 I64ToS8 => ret.result_mut().push_str("i64-to-s8"),
190 I64ToS8X => ret.result_mut().push_str("i64-to-s8x"),
191 I64ToU8 => ret.result_mut().push_str("i64-to-u8"),
192 I64ToS16 => ret.result_mut().push_str("i64-to-s16"),
193 I64ToS16X => ret.result_mut().push_str("i64-to-s16x"),
194 I64ToU16 => ret.result_mut().push_str("i64-to-u16"),
195 I64ToS32 => ret.result_mut().push_str("i64-to-s32"),
196 I64ToS32X => ret.result_mut().push_str("i64-to-s32x"),
197 I64ToU32 => ret.result_mut().push_str("i64-to-u32"),
198 I64ToS64 => ret.result_mut().push_str("i64-to-s64"),
199 I64ToU64 => ret.result_mut().push_str("i64-to-u64"),
200
201 S8ToI32 => ret.result_mut().push_str("s8-to-i32"),
202 U8ToI32 => ret.result_mut().push_str("u8-to-i32"),
203 S16ToI32 => ret.result_mut().push_str("s16-to-i32"),
204 U16ToI32 => ret.result_mut().push_str("u16-to-i32"),
205 S32ToI32 => ret.result_mut().push_str("s32-to-i32"),
206 U32ToI32 => ret.result_mut().push_str("u32-to-i32"),
207 S64ToI32 => ret.result_mut().push_str("s64-to-i32"),
208 S64ToI32X => ret.result_mut().push_str("s64-to-i32x"),
209 U64ToI32 => ret.result_mut().push_str("u64-to-i32"),
210 U64ToI32X => ret.result_mut().push_str("u64-to-i32x"),
211
212 S8ToI64 => ret.result_mut().push_str("s8-to-i64"),
213 U8ToI64 => ret.result_mut().push_str("u8-to-i64"),
214 S16ToI64 => ret.result_mut().push_str("s16-to-i64"),
215 U16ToI64 => ret.result_mut().push_str("u16-to-i64"),
216 S32ToI64 => ret.result_mut().push_str("s32-to-i64"),
217 U32ToI64 => ret.result_mut().push_str("u32-to-i64"),
218 S64ToI64 => ret.result_mut().push_str("s64-to-i64"),
219 U64ToI64 => ret.result_mut().push_str("u64-to-i64"),
220 }
221
222 Ok(())
223 }
224}