1use std::collections::HashMap;
2use std::fmt::{self};
3use std::str::FromStr;
4
5pub use indexmap::IndexMap;
6
7#[derive(Debug, Clone, PartialEq, Eq, Hash)]
8pub enum Nullable {
9 True,
10 False,
11}
12
13impl fmt::Display for Nullable {
14 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15 match self {
16 Nullable::True => write!(f, "null"),
17 Nullable::False => write!(f, ""),
18 }
19 }
20}
21
22#[derive(Debug, Clone, Eq, PartialEq)]
23pub struct StructField {
24 pub name: Option<String>,
25 pub ty: WasmType,
26 pub mutable: bool,
27}
28
29impl fmt::Display for StructField {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 let name = self.name.clone().unwrap_or_default();
32 let ty = if self.mutable {
33 format!("(mut {})", self.ty)
34 } else {
35 format!("{}", self.ty)
36 };
37 writeln!(f, "(field {name} {ty}")
38 }
39}
40
41#[derive(Debug, Clone, Eq, PartialEq)]
42pub struct Signature {
43 pub params: Vec<WasmType>,
44 pub result: Option<Box<WasmType>>,
45}
46
47#[derive(Debug, Clone, Eq, PartialEq)]
48pub enum WasmType {
49 I32,
50 I64,
51 F32,
52 F64,
53 I8,
54 I31Ref,
55 Anyref,
56 Ref(String, Nullable),
57 Array {
58 mutable: bool,
59 ty: Box<WasmType>,
60 },
61 Struct(Vec<StructField>),
62 Func(Box<Signature>),
63 Tag {
64 name: String,
65 signature: Box<Signature>,
66 },
67}
68
69impl WasmType {
70 pub fn is_numeric(&self) -> bool {
71 use WasmType::*;
72 matches!(self, I32 | I64 | F32 | I8 | I31Ref)
73 }
74
75 pub fn compatible_numeric_types(left: &Self, right: &Self) -> bool {
76 use WasmType::*;
77 matches!(
78 (left, right),
79 (I32, I32)
80 | (I32, I64)
81 | (I32, I8)
82 | (I32, I31Ref)
83 | (I64, I32)
84 | (I64, I64)
85 | (I64, I8)
86 | (I64, I31Ref)
87 | (I8, I32)
88 | (I8, I64)
89 | (I8, I8)
90 | (I8, I31Ref)
91 | (I31Ref, I32)
92 | (I31Ref, I64)
93 | (I31Ref, I8)
94 | (I31Ref, I31Ref)
95 | (F32, F32)
96 | (F32, F64)
97 | (F64, F32)
98 | (F64, F64)
99 )
100 }
101
102 pub fn broader_numeric_type(left: &Self, right: &Self) -> Self {
103 use WasmType::*;
104 match (left, right) {
105 (I32, I32) => I32,
106 (I32, I64) => I64,
107 (I32, I8) => I32,
108 (I32, I31Ref) => I32,
109 (I64, I32) => I64,
110 (I64, I64) => I64,
111 (I64, I8) => I64,
112 (I64, I31Ref) => I64,
113 (I8, I32) => I32,
114 (I8, I64) => I64,
115 (I8, I8) => I8,
116 (I8, I31Ref) => I31Ref,
117 (I31Ref, I32) => I32,
118 (I31Ref, I64) => I64,
119 (I31Ref, I8) => I31Ref,
120 (I31Ref, I31Ref) => I31Ref,
121 (F32, F32) => F32,
122 (F32, F64) => F64,
123 (F64, F32) => F64,
124 (F64, F64) => F64,
125 _ => panic!("Both types need to be numeric. Left: {left:?}, Right: {right:?}."),
126 }
127 }
128
129 pub fn convert_to_instruction(&self, to_type: &Self) -> Vec<WatInstruction> {
130 use WasmType::*;
131 match (self, to_type) {
132 (I32, I32) => vec![],
133 (I32, I64) => vec![WatInstruction::I64ExtendI32S],
134 (I32, I31Ref) => vec![WatInstruction::RefI31],
135 (I64, I32) => vec![WatInstruction::I32WrapI64],
136 (I64, I64) => vec![],
137 (I64, I31Ref) => vec![WatInstruction::I32WrapI64, WatInstruction::RefI31],
138 (I31Ref, I32) => vec![WatInstruction::I31GetS],
139 (I31Ref, I64) => vec![WatInstruction::I31GetS, WatInstruction::I64ExtendI32S],
140 (I31Ref, I31Ref) => vec![],
141 (F32, F32) => vec![],
142 (F32, F64) => vec![WatInstruction::F64PromoteF32],
143 (F64, F32) => vec![WatInstruction::F32DemoteF64],
144 (F64, F64) => vec![],
145 _ => panic!("Can't convert {self:?} to {to_type:?}"),
146 }
147 }
148}
149
150impl fmt::Display for WasmType {
151 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
152 match self {
153 WasmType::I32 => write!(f, "i32"),
154 WasmType::I64 => write!(f, "i64"),
155 WasmType::F32 => write!(f, "f32"),
156 WasmType::F64 => write!(f, "f64"),
157 WasmType::I8 => write!(f, "i8"),
158 WasmType::Anyref => write!(f, "anyref"),
159 WasmType::I31Ref => write!(f, "i31ref"),
160 WasmType::Ref(name, nullable) => write!(f, "(ref {nullable} {name})"),
161 WasmType::Array { mutable, ty } => {
162 let m = if *mutable {
163 format!("(mut {ty})")
164 } else {
165 ty.to_string()
166 };
167 write!(f, "(array {m})")
168 }
169 WasmType::Struct(fields) => {
170 write!(f, "(struct")?;
171 for field in fields {
172 write!(f, " {field}")?;
173 }
174 write!(f, ")")
175 }
176 WasmType::Func(signature) => {
177 write!(f, "(func")?;
178 for param in &signature.params {
179 write!(f, " (param {param})")?;
180 }
181 if let Some(result) = &signature.result {
182 write!(f, " (result {result})")?;
183 }
184 write!(f, ")")
185 }
186 WasmType::Tag { name, signature } => {
187 write!(f, "(tag {name}")?;
188 for param in &signature.params {
189 write!(f, " (param {param})")?;
190 }
191 if let Some(result) = &signature.result {
192 write!(f, " (result {result})")?;
193 }
194 write!(f, ")")
195 }
196 }
197 }
198}
199
200#[derive(Debug, Clone)]
201pub struct WasmError;
202
203impl FromStr for WasmType {
204 fn from_str(s: &str) -> Result<Self, Self::Err> {
206 let str = match s {
207 "i32" => Self::I32,
208 "i64" => Self::I64,
209 "f32" => Self::F32,
210 "f64" => Self::F64,
211 "i8" => Self::I8,
212 "i31ref" => Self::I31Ref,
213 "anyref" => Self::Anyref,
214 "bool" => Self::I32,
218 _ => {
219 Self::Ref(format!("${s}"), Nullable::False)
221 }
222 };
223
224 Ok(str)
225 }
226
227 type Err = WasmError;
228}
229
230#[derive(Debug, Clone)]
231pub enum WatInstruction {
232 Nop,
233 Local {
234 name: String,
235 r#type: WasmType,
236 },
237 GlobalGet(String),
238 LocalGet(String),
239 LocalSet(String),
240 Call(String),
241
242 I32Const(i32),
243 I64Const(i64),
244 F32Const(f32),
245 F64Const(f64),
246
247 I32Eqz,
248 I64Eqz,
249 F32Eqz,
250 F64Eqz,
251
252 I32Eq,
253 I64Eq,
254 F32Eq,
255 F64Eq,
256
257 I32GeS,
258 I64ExtendI32S,
259 I32WrapI64,
260 I31GetS,
261 F64PromoteF32,
262 F32DemoteF64,
263
264 StructNew(String),
265 StructGet(String, String),
266 StructSet(String, String),
267 ArrayNew(String),
268 ArrayNewFixed(String, u16),
269 ArrayLen,
270 ArrayGet(String),
271 ArrayGetU(String),
272 ArraySet(String),
273 RefNull(WasmType),
274 Ref(String),
275 RefFunc(String),
276 Type(String),
277 Return,
278 ReturnCall(String),
279 Block {
280 label: String,
281 instructions: Vec<WatInstruction>,
282 },
283 Loop {
284 label: String,
285 instructions: Vec<WatInstruction>,
286 },
287 If {
288 then: Vec<WatInstruction>,
289 r#else: Option<Vec<WatInstruction>>,
290 },
291 BrIf(String),
292 Br(String),
293 Empty,
294 Log,
295 Identifier(String),
296 Drop,
297 LocalTee(String),
298 RefI31,
299 Throw(String),
300 Try {
301 try_block: Box<WatInstruction>,
302 catches: Vec<Box<WatInstruction>>,
303 catch_all: Option<Box<WatInstruction>>,
304 },
305 Catch(String, Box<WatInstruction>),
306 CatchAll(Box<WatInstruction>),
307 I32Add,
308 I64Add,
309 F32Add,
310 F64Add,
311}
312
313impl WatInstruction {
314 pub fn local(name: impl Into<String>, r#type: WasmType) -> Box<Self> {
315 Box::new(Self::Local {
316 name: name.into(),
317 r#type,
318 })
319 }
320
321 pub fn global_get(name: impl Into<String>) -> Self {
322 Self::GlobalGet(name.into())
323 }
324
325 pub fn local_get(name: impl Into<String>) -> Self {
326 Self::LocalGet(name.into())
327 }
328
329 pub fn local_set(name: impl Into<String>) -> Self {
330 Self::LocalSet(name.into())
331 }
332
333 pub fn local_tee(name: impl Into<String>) -> Self {
334 Self::LocalTee(name.into())
335 }
336
337 pub fn call(name: impl Into<String>) -> Self {
338 Self::Call(name.into())
339 }
340
341 pub fn i32_const(value: i32) -> Self {
342 Self::I32Const(value)
343 }
344
345 pub fn f64_const(value: f64) -> Box<Self> {
346 Box::new(Self::F64Const(value))
347 }
348
349 pub fn struct_new(name: impl Into<String>) -> Self {
350 Self::StructNew(name.into())
351 }
352
353 pub fn struct_get(name: impl Into<String>, field_name: impl Into<String>) -> Self {
354 Self::StructGet(name.into(), field_name.into())
355 }
356
357 pub fn struct_set(name: impl Into<String>, field_name: impl Into<String>) -> Self {
358 Self::StructSet(name.into(), field_name.into())
359 }
360
361 pub fn array_new(
362 name: impl Into<String>,
363 _init: Box<WatInstruction>,
364 _length: Box<WatInstruction>,
365 ) -> Box<Self> {
366 Box::new(Self::ArrayNew(name.into()))
367 }
368
369 pub fn array_get(name: impl Into<String>) -> Self {
370 Self::ArrayGet(name.into())
371 }
372
373 pub fn array_get_u(name: impl Into<String>) -> Self {
374 Self::ArrayGetU(name.into())
375 }
376
377 pub fn array_set(name: impl Into<String>) -> Self {
378 Self::ArraySet(name.into())
379 }
380
381 pub fn ref_null(r#type: WasmType) -> Box<Self> {
382 Box::new(Self::RefNull(r#type))
383 }
384
385 pub fn ref_func(name: impl Into<String>) -> Box<Self> {
386 Box::new(Self::RefFunc(name.into()))
387 }
388
389 pub fn type_(name: impl Into<String>) -> Box<Self> {
390 Box::new(Self::Type(name.into()))
391 }
392
393 pub fn r#return() -> Box<Self> {
394 Box::new(Self::Return)
395 }
396
397 pub fn return_call(name: impl Into<String>) -> Box<Self> {
398 Box::new(Self::ReturnCall(name.into()))
399 }
400
401 pub fn block(label: impl Into<String>, instructions: Vec<WatInstruction>) -> Self {
402 Self::Block {
403 label: label.into(),
404 instructions,
405 }
406 }
407
408 pub fn r#loop(label: impl Into<String>, instructions: Vec<WatInstruction>) -> Self {
409 Self::Loop {
410 label: label.into(),
411 instructions,
412 }
413 }
414
415 pub fn r#if(then: Vec<WatInstruction>, r#else: Option<Vec<WatInstruction>>) -> Self {
416 Self::If { then, r#else }
417 }
418
419 pub fn br_if(label: impl Into<String>) -> Self {
420 Self::BrIf(label.into())
421 }
422
423 pub fn br(label: impl Into<String>) -> Self {
424 Self::Br(label.into())
425 }
426
427 pub fn empty() -> Box<Self> {
428 Box::new(Self::Empty)
429 }
430
431 pub fn drop() -> Box<Self> {
432 Box::new(Self::Drop)
433 }
434
435 pub fn i32_eqz() -> Box<Self> {
436 Box::new(Self::I32Eqz)
437 }
438
439 pub fn ref_i31() -> Self {
440 Self::RefI31
441 }
442
443 pub fn throw(label: impl Into<String>) -> Self {
444 Self::Throw(label.into())
445 }
446
447 pub fn r#type(name: impl Into<String>) -> Box<Self> {
448 Box::new(Self::Type(name.into()))
449 }
450
451 pub fn r#try(
452 try_block: Box<Self>,
453 catches: Vec<Box<Self>>,
454 catch_all: Option<Box<Self>>,
455 ) -> Box<Self> {
456 Box::new(Self::Try {
457 try_block,
458 catches,
459 catch_all,
460 })
461 }
462
463 pub fn catch(label: impl Into<String>, instr: Box<Self>) -> Box<Self> {
464 Box::new(Self::Catch(label.into(), instr))
465 }
466
467 pub fn is_return(&self) -> bool {
468 matches!(self, Self::Return)
469 }
470
471 pub fn is_call(&self) -> bool {
472 matches!(self, Self::Call { .. })
473 }
474}
475
476impl fmt::Display for WatInstruction {
477 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
478 match self {
479 WatInstruction::I32Add => write!(f, "(i32.add)"),
480 WatInstruction::I64Add => write!(f, "(i64.add)"),
481 WatInstruction::F32Add => write!(f, "(f32.add)"),
482 WatInstruction::F64Add => write!(f, "(f64.add)"),
483
484 WatInstruction::Nop => Ok(()),
485 WatInstruction::Local { name, r#type } => write!(f, "(local {} {})", name, r#type),
486 WatInstruction::GlobalGet(name) => write!(f, "(global.get {})", name),
487 WatInstruction::LocalGet(name) => write!(f, "(local.get {})", name),
488 WatInstruction::LocalSet(name) => write!(f, "(local.set {})", name),
489 WatInstruction::Call(name) => writeln!(f, "(call {})", name),
490
491 WatInstruction::I32Const(value) => write!(f, "(i32.const {})", value),
492 WatInstruction::I64Const(value) => write!(f, "(i64.const {})", value),
493 WatInstruction::F32Const(value) => write!(f, "(f32.const {})", value),
494 WatInstruction::F64Const(value) => write!(f, "(f64.const {})", value),
495
496 WatInstruction::I32GeS => writeln!(f, "(i32.ge_s)"),
497
498 WatInstruction::StructNew(name) => write!(f, "(struct.new {})", name),
499 WatInstruction::StructGet(name, field) => write!(f, "(struct.get {name} {field})"),
500 WatInstruction::StructSet(name, field) => write!(f, "(struct.set {name} {field})"),
501 WatInstruction::ArrayNew(name) => {
502 write!(f, "(array.new {name})")
503 }
504 WatInstruction::ArrayLen => write!(f, "(array.len)"),
505 WatInstruction::ArrayGet(ty) => write!(f, "(array.get {ty})"),
506 WatInstruction::ArrayGetU(ty) => write!(f, "(array.get_u {ty})"),
507 WatInstruction::ArraySet(ty) => write!(f, "(array.set {ty})"),
508 WatInstruction::ArrayNewFixed(typeidx, n) => {
509 write!(f, "(array.new_fixed {typeidx} {n})")
510 }
511 WatInstruction::RefNull(r#type) => write!(f, "(ref.null {})", r#type),
512 WatInstruction::RefFunc(name) => write!(f, "(ref.func ${})", name),
513 WatInstruction::Return => write!(f, "return"),
514 WatInstruction::ReturnCall(name) => write!(f, "(return_call {name})"),
515 WatInstruction::Block {
516 label,
517 instructions,
518 } => {
519 writeln!(f, "(block {label}")?;
520 for instruction in instructions {
521 writeln!(f, " {}", instruction)?;
522 }
523 write!(f, ")")
524 }
525 WatInstruction::Loop {
526 label,
527 instructions,
528 } => {
529 writeln!(f, "(loop {label}")?;
530 for instruction in instructions {
531 writeln!(f, " {}", instruction)?;
532 }
533 write!(f, ")")
534 }
535 WatInstruction::If { then, r#else } => {
536 write!(f, "(if (then")?;
537 for instruction in then {
538 write!(f, " {}", instruction)?;
539 }
540 write!(f, ")")?;
541 if let Some(else_block) = r#else {
542 write!(f, " (else")?;
543 for instruction in else_block {
544 write!(f, " {}", instruction)?;
545 }
546 write!(f, ")")?;
547 }
548 write!(f, ")")
549 }
550 WatInstruction::BrIf(label) => write!(f, "(br_if {})", label),
551 WatInstruction::Br(label) => write!(f, "(br {})", label),
552 WatInstruction::Type(name) => write!(f, "{}", name),
553 WatInstruction::Empty => Ok(()),
554 WatInstruction::Log => {
555 writeln!(f, "(call $log)")
556 }
557 WatInstruction::Identifier(s) => write!(f, "{}", s),
558 WatInstruction::Ref(s) => write!(f, "(ref ${})", s),
559 WatInstruction::Drop => writeln!(f, "(drop)"),
560 WatInstruction::LocalTee(name) => write!(f, "(local.tee {})", name),
561
562 WatInstruction::I32Eqz => write!(f, "(i32.eqz)"),
563 WatInstruction::I64Eqz => write!(f, "(i64.eqz)"),
564 WatInstruction::F32Eqz => write!(f, "(f32.eqz)"),
565 WatInstruction::F64Eqz => write!(f, "(f64.eqz)"),
566
567 WatInstruction::RefI31 => write!(f, "(ref.i31)"),
568 WatInstruction::Throw(label) => write!(f, "(throw {label})"),
569 WatInstruction::Try {
570 try_block,
571 catches,
572 catch_all,
573 } => {
574 writeln!(
575 f,
576 "\ntry\n{try_block}{}{}\nend",
577 catches
578 .iter()
579 .map(|c| c.to_string())
580 .collect::<Vec<String>>()
581 .join(""),
582 catch_all
583 .clone()
584 .map(|c| c.to_string())
585 .unwrap_or("".to_string())
586 )
587 }
588 WatInstruction::Catch(label, instr) => writeln!(f, "\ncatch {label}\n{instr}"),
589 WatInstruction::CatchAll(instr) => writeln!(f, "\ncatch_all\n{instr}"),
590 WatInstruction::I64ExtendI32S => writeln!(f, "(i64.extend_32_s)"),
591 WatInstruction::I32WrapI64 => writeln!(f, "(i32.wrap_i64)"),
592 WatInstruction::I31GetS => writeln!(f, "(i31.get_s)"),
593 WatInstruction::F64PromoteF32 => writeln!(f, "(f64.promote_f32)"),
594 WatInstruction::F32DemoteF64 => writeln!(f, "(f32.demote_f64)"),
595 WatInstruction::I32Eq => writeln!(f, "(i32.eq)"),
596 WatInstruction::I64Eq => writeln!(f, "(i64.eq)"),
597 WatInstruction::F32Eq => writeln!(f, "(f32.eq)"),
598 WatInstruction::F64Eq => writeln!(f, "(f64.eq)"),
599 }
600 }
601}
602
603#[derive(Debug, Clone)]
604pub struct WatFunction {
605 pub name: String,
606 pub params: Vec<(String, WasmType)>,
607 pub return_type: Option<WasmType>,
608 pub locals: HashMap<String, WasmType>,
609 pub locals_counters: HashMap<String, u32>,
610 pub body: Vec<Box<WatInstruction>>,
611}
612
613impl WatFunction {
614 pub fn new(name: impl Into<String>) -> Self {
615 WatFunction {
616 name: name.into(),
617 params: Vec::new(),
618 return_type: None,
619 locals: HashMap::new(),
620 locals_counters: HashMap::new(),
621 body: Vec::new(),
622 }
623 }
624
625 pub fn add_param(&mut self, name: impl Into<String>, type_: &WasmType) {
626 self.params.push((name.into(), type_.clone()));
627 }
628
629 pub fn set_return_type(&mut self, type_: WasmType) {
630 self.return_type = Some(type_);
631 }
632
633 pub fn add_local_exact(&mut self, name: impl Into<String>, r#type: WasmType) {
634 self.locals.insert(name.into(), r#type);
635 }
636
637 pub fn add_local(&mut self, name: impl Into<String>, r#type: WasmType) -> String {
638 let name = name.into();
639
640 let counter = self.locals_counters.entry(name.clone()).or_insert(0);
641 *counter += 1;
642 let name = format!("{name}-{counter}");
643 self.locals.insert(name.clone(), r#type);
644
645 name
646 }
647
648 pub fn add_instruction(&mut self, instruction: WatInstruction) {
649 self.body.push(Box::new(instruction));
650 }
651}
652
653impl fmt::Display for WatFunction {
654 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
655 write!(f, "(func ${}", self.name)?;
656 for (name, type_) in &self.params {
657 write!(f, " (param {} {})", name, type_)?;
658 }
659 if let Some(return_type) = &self.return_type {
660 write!(f, " (result {})", return_type)?;
661 }
662 writeln!(f)?;
663 for (name, type_) in &self.locals {
664 writeln!(f, " (local {} {})", name, type_)?;
665 }
666 for instruction in &self.body {
667 writeln!(f, " {}", instruction)?;
668 }
669 writeln!(f, ")")
670 }
671}
672
673#[derive(Debug, Clone, Default)]
674pub struct WatModule {
675 pub tags: IndexMap<String, String>,
676 pub types: IndexMap<String, WasmType>,
677 pub imports: Vec<(String, String, WasmType)>,
678 pub functions: Vec<WatFunction>,
679 pub exports: Vec<(String, String, String)>,
681 pub globals: Vec<(String, WasmType, WatInstruction)>,
682 pub data: Vec<(usize, String)>,
683 pub data_offset: usize,
684 pub data_offsets: HashMap<String, usize>,
685 pub memories: HashMap<String, i32>,
686}
687
688impl WatModule {
689 pub fn new() -> Self {
690 WatModule {
691 tags: IndexMap::new(),
692 types: IndexMap::new(),
693 imports: Vec::new(),
694 functions: Vec::new(),
695 exports: Vec::new(),
696 globals: Vec::new(),
697 data: Vec::new(),
698 data_offset: 100,
699 data_offsets: HashMap::new(),
700 memories: HashMap::new(),
701 }
702 }
703
704 pub fn add_function(&mut self, function: WatFunction) {
705 self.functions.push(function);
706 }
707
708 pub fn get_function_mut(&mut self, name: &str) -> Option<&mut WatFunction> {
709 self.functions.iter_mut().find(|f| f.name == name)
710 }
711
712 pub fn add_type(&mut self, name: impl Into<String>, ty: WasmType) {
713 self.types.insert(name.into(), ty);
714 }
715
716 pub fn add_data(&mut self, content: String) -> (usize, usize) {
717 let len = content.len();
718 let offset = self.data_offset;
719 if let Some(offset) = self.data_offsets.get(&content) {
720 (*offset, len)
721 } else {
722 self.data.push((offset, content.clone()));
723 self.data_offsets.insert(content, offset);
724 self.data_offset += if len % 4 == 0 {
725 len
726 } else {
727 len + (4 - len % 4)
729 };
730
731 (offset, len)
732 }
733 }
734
735 pub fn add_memory(&mut self, label: impl Into<String>, size: i32) {
736 self.memories.insert(label.into(), size);
737 }
738
739 pub fn add_export(
740 &mut self,
741 export_name: impl Into<String>,
742 export_type: impl Into<String>,
743 name: impl Into<String>,
744 ) {
745 self.exports
746 .push((export_name.into(), export_type.into(), name.into()));
747 }
748
749 pub fn add_import(
750 &mut self,
751 namespace: impl Into<String>,
752 name: impl Into<String>,
753 ty: WasmType,
754 ) {
755 self.imports.push((namespace.into(), name.into(), ty));
756 }
757}
758
759impl fmt::Display for WatModule {
760 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
761 writeln!(f, "(module")?;
762 for (name, ty) in &self.types {
764 writeln!(f, " (type {name} {ty})")?;
765 }
766
767 for (label, typeidx) in &self.tags {
769 writeln!(f, " (tag {label} (type {typeidx}))")?;
770 }
771
772 for (module, name, type_) in &self.imports {
774 writeln!(f, " (import \"{}\" \"{}\" {})", module, name, type_)?;
775 }
776
777 for (label, size) in &self.memories {
779 writeln!(f, " (memory {label} {size})")?;
780 }
781
782 for (offset, data) in &self.data {
784 write!(f, " (data (i32.const {}) \"", offset)?;
785 for &byte in data.as_bytes() {
787 match byte {
788 b'"' => write!(f, "\\\"")?,
789 b'\\' => write!(f, "\\\\")?,
790 b'\n' => write!(f, "\\n")?,
791 b'\r' => write!(f, "\\r")?,
792 b'\t' => write!(f, "\\t")?,
793 _ if byte.is_ascii_graphic() || byte == b' ' => write!(f, "{}", byte as char)?,
794 _ => write!(f, "\\{:02x}", byte)?,
795 }
796 }
797 writeln!(f, "\")")?;
798 }
799
800 for (name, type_, init) in &self.globals {
802 writeln!(f, " (global ${} {} {})", name, type_, init)?;
803 }
804
805 for function in &self.functions {
807 writeln!(f, "(elem declare func ${})", function.name)?;
808 }
809
810 for function in &self.functions {
812 write!(f, " {}", function)?;
813 }
814
815 for (name, export_type, internal_name) in &self.exports {
817 writeln!(
818 f,
819 " (export \"{}\" ({export_type} {}))",
820 name, internal_name
821 )?;
822 }
823
824 writeln!(f, ")")?;
825
826 Ok(())
827 }
828}