wit_component_update/
printing.rs

1use anyhow::{anyhow, bail, Result};
2use std::collections::HashMap;
3use std::fmt::{self, Write};
4use std::mem;
5use wit_parser::*;
6
7// NB: keep in sync with `crates/wit-parser/src/ast/lex.rs`
8const PRINT_SEMICOLONS_DEFAULT: bool = true;
9const PRINT_F32_F64_DEFAULT: bool = false;
10
11/// A utility for printing WebAssembly interface definitions to a string.
12pub struct WitPrinter {
13    output: Output,
14
15    // Count of how many items in this current block have been printed to print
16    // a blank line between each item, but not the first item.
17    any_items: bool,
18
19    // Whether to print doc comments.
20    emit_docs: bool,
21
22    print_semicolons: bool,
23    print_f32_f64: bool,
24}
25
26impl Default for WitPrinter {
27    fn default() -> Self {
28        Self {
29            output: Default::default(),
30            any_items: false,
31            emit_docs: true,
32            print_semicolons: match std::env::var("WIT_REQUIRE_SEMICOLONS") {
33                Ok(s) => s == "1",
34                Err(_) => PRINT_SEMICOLONS_DEFAULT,
35            },
36            print_f32_f64: match std::env::var("WIT_REQUIRE_F32_F64") {
37                Ok(s) => s == "1",
38                Err(_) => PRINT_F32_F64_DEFAULT,
39            },
40        }
41    }
42}
43
44impl WitPrinter {
45    /// Configure whether doc comments will be printed.
46    ///
47    /// Defaults to true.
48    pub fn emit_docs(&mut self, enabled: bool) -> &mut Self {
49        self.emit_docs = enabled;
50        self
51    }
52
53    /// Print the given WIT package to a string.
54    pub fn print(&mut self, resolve: &Resolve, pkgid: PackageId) -> Result<String> {
55        let pkg = &resolve.packages[pkgid];
56        self.print_docs(&pkg.docs);
57        self.output.push_str("package ");
58        self.print_name(&pkg.name.namespace);
59        self.output.push_str(":");
60        self.print_name(&pkg.name.name);
61        if let Some(version) = &pkg.name.version {
62            self.output.push_str(&format!("@{version}"));
63        }
64        self.print_semicolon();
65        self.output.push_str("\n\n");
66        for (name, id) in pkg.interfaces.iter() {
67            self.print_docs(&resolve.interfaces[*id].docs);
68            self.output.push_str("interface ");
69            self.print_name(name);
70            self.output.push_str(" {\n");
71            self.print_interface(resolve, *id)?;
72            writeln!(&mut self.output, "}}\n")?;
73        }
74
75        for (name, id) in pkg.worlds.iter() {
76            self.print_docs(&resolve.worlds[*id].docs);
77            self.output.push_str("world ");
78            self.print_name(name);
79            self.output.push_str(" {\n");
80            self.print_world(resolve, *id)?;
81            writeln!(&mut self.output, "}}")?;
82        }
83
84        Ok(std::mem::take(&mut self.output).into())
85    }
86
87    fn print_semicolon(&mut self) {
88        if self.print_semicolons {
89            self.output.push_str(";");
90        }
91    }
92
93    fn new_item(&mut self) {
94        if self.any_items {
95            self.output.push_str("\n");
96        }
97        self.any_items = true;
98    }
99
100    /// Print the given WebAssembly interface to a string.
101    fn print_interface(&mut self, resolve: &Resolve, id: InterfaceId) -> Result<()> {
102        let prev_items = mem::replace(&mut self.any_items, false);
103        let interface = &resolve.interfaces[id];
104
105        let mut resource_funcs = HashMap::new();
106        let mut freestanding = Vec::new();
107        for (name, func) in interface.functions.iter() {
108            if let Some(id) = resource_func(func) {
109                resource_funcs.entry(id).or_insert(Vec::new()).push(func);
110            } else {
111                freestanding.push((name, func));
112            }
113        }
114
115        self.print_types(
116            resolve,
117            TypeOwner::Interface(id),
118            interface
119                .types
120                .iter()
121                .map(|(name, id)| (name.as_str(), *id)),
122            &resource_funcs,
123        )?;
124
125        for (name, func) in freestanding {
126            self.new_item();
127            self.print_docs(&func.docs);
128            self.print_name(name);
129            self.output.push_str(": ");
130            self.print_function(resolve, func)?;
131            self.print_semicolon();
132            self.output.push_str("\n");
133        }
134
135        self.any_items = prev_items;
136
137        Ok(())
138    }
139
140    fn print_types<'a>(
141        &mut self,
142        resolve: &Resolve,
143        owner: TypeOwner,
144        types: impl Iterator<Item = (&'a str, TypeId)>,
145        resource_funcs: &HashMap<TypeId, Vec<&Function>>,
146    ) -> Result<()> {
147        // Partition types defined in this interface into either those imported
148        // from foreign interfaces or those defined locally.
149        let mut types_to_declare = Vec::new();
150        let mut types_to_import: Vec<(_, Vec<_>)> = Vec::new();
151        for (name, ty_id) in types {
152            let ty = &resolve.types[ty_id];
153            if let TypeDefKind::Type(Type::Id(other)) = ty.kind {
154                let other = &resolve.types[other];
155                match other.owner {
156                    TypeOwner::None => {}
157                    other_owner if owner != other_owner => {
158                        let other_name = other
159                            .name
160                            .as_ref()
161                            .ok_or_else(|| anyhow!("cannot import unnamed type"))?;
162                        if let Some((owner, list)) = types_to_import.last_mut() {
163                            if *owner == other_owner {
164                                list.push((name, other_name));
165                                continue;
166                            }
167                        }
168                        types_to_import.push((other_owner, vec![(name, other_name)]));
169                        continue;
170                    }
171                    _ => {}
172                }
173            }
174
175            types_to_declare.push(ty_id);
176        }
177
178        // Generate a `use` statement for all imported types.
179        let my_pkg = match owner {
180            TypeOwner::Interface(id) => resolve.interfaces[id].package.unwrap(),
181            TypeOwner::World(id) => resolve.worlds[id].package.unwrap(),
182            TypeOwner::None => unreachable!(),
183        };
184        for (owner, tys) in types_to_import {
185            self.any_items = true;
186            write!(&mut self.output, "use ")?;
187            let id = match owner {
188                TypeOwner::Interface(id) => id,
189                // it's only possible to import types from interfaces at
190                // this time.
191                _ => unreachable!(),
192            };
193            self.print_path_to_interface(resolve, id, my_pkg)?;
194            write!(&mut self.output, ".{{")?;
195            for (i, (my_name, other_name)) in tys.into_iter().enumerate() {
196                if i > 0 {
197                    write!(&mut self.output, ", ")?;
198                }
199                if my_name == other_name {
200                    self.print_name(my_name);
201                } else {
202                    self.print_name(other_name);
203                    self.output.push_str(" as ");
204                    self.print_name(my_name);
205                }
206            }
207            write!(&mut self.output, "}}")?;
208            self.print_semicolon();
209            self.output.push_str("\n");
210        }
211
212        for id in types_to_declare {
213            self.new_item();
214            self.print_docs(&resolve.types[id].docs);
215            match resolve.types[id].kind {
216                TypeDefKind::Resource => self.print_resource(
217                    resolve,
218                    id,
219                    resource_funcs.get(&id).unwrap_or(&Vec::new()),
220                )?,
221                _ => self.declare_type(resolve, &Type::Id(id))?,
222            }
223        }
224
225        Ok(())
226    }
227
228    fn print_resource(&mut self, resolve: &Resolve, id: TypeId, funcs: &[&Function]) -> Result<()> {
229        let ty = &resolve.types[id];
230        self.output.push_str("resource ");
231        self.print_name(ty.name.as_ref().expect("resources must be named"));
232        if funcs.is_empty() {
233            self.print_semicolon();
234            self.output.push_str("\n");
235            return Ok(());
236        }
237        self.output.push_str(" {\n");
238        for func in funcs {
239            match &func.kind {
240                FunctionKind::Constructor(_) => {
241                    self.print_docs(&func.docs);
242                }
243                FunctionKind::Method(_) => {
244                    self.print_docs(&func.docs);
245                    self.print_name(func.item_name());
246                    self.output.push_str(": ");
247                }
248                FunctionKind::Static(_) => {
249                    self.print_docs(&func.docs);
250                    self.print_name(func.item_name());
251                    self.output.push_str(": ");
252                    self.output.push_str("static ");
253                }
254                FunctionKind::Freestanding => unreachable!(),
255            }
256            self.print_function(resolve, func)?;
257            self.print_semicolon();
258            self.output.push_str("\n");
259        }
260        self.output.push_str("}\n");
261
262        Ok(())
263    }
264
265    fn print_function(&mut self, resolve: &Resolve, func: &Function) -> Result<()> {
266        // Constructors are named slightly differently.
267        match &func.kind {
268            FunctionKind::Constructor(_) => self.output.push_str("constructor("),
269            _ => self.output.push_str("func("),
270        }
271
272        // Methods don't print their `self` argument
273        let params_to_skip = match &func.kind {
274            FunctionKind::Method(_) => 1,
275            _ => 0,
276        };
277        for (i, (name, ty)) in func.params.iter().skip(params_to_skip).enumerate() {
278            if i > 0 {
279                self.output.push_str(", ");
280            }
281            self.print_name(name);
282            self.output.push_str(": ");
283            self.print_type_name(resolve, ty)?;
284        }
285        self.output.push_str(")");
286
287        // constructors don't have their results printed
288        if let FunctionKind::Constructor(_) = func.kind {
289            return Ok(());
290        }
291
292        match &func.results {
293            Results::Named(rs) => match rs.len() {
294                0 => (),
295                _ => {
296                    self.output.push_str(" -> (");
297                    for (i, (name, ty)) in rs.iter().enumerate() {
298                        if i > 0 {
299                            self.output.push_str(", ");
300                        }
301                        self.print_name(name);
302                        self.output.push_str(": ");
303                        self.print_type_name(resolve, ty)?;
304                    }
305                    self.output.push_str(")");
306                }
307            },
308            Results::Anon(ty) => {
309                self.output.push_str(" -> ");
310                self.print_type_name(resolve, ty)?;
311            }
312        }
313        Ok(())
314    }
315
316    fn print_world(&mut self, resolve: &Resolve, id: WorldId) -> Result<()> {
317        let prev_items = mem::replace(&mut self.any_items, false);
318        let world = &resolve.worlds[id];
319        let pkgid = world.package.unwrap();
320        let mut types = Vec::new();
321        let mut resource_funcs = HashMap::new();
322        for (name, import) in world.imports.iter() {
323            match import {
324                WorldItem::Type(t) => match name {
325                    WorldKey::Name(s) => types.push((s.as_str(), *t)),
326                    WorldKey::Interface(_) => unreachable!(),
327                },
328                _ => {
329                    if let WorldItem::Function(f) = import {
330                        if let Some(id) = resource_func(f) {
331                            resource_funcs.entry(id).or_insert(Vec::new()).push(f);
332                            continue;
333                        }
334                    }
335                    self.print_world_item(resolve, name, import, pkgid, "import")?;
336                    // Don't put a blank line between imports, but count
337                    // imports as having printed something so if anything comes
338                    // after them then a blank line is printed after imports.
339                    self.any_items = true;
340                }
341            }
342        }
343        self.print_types(
344            resolve,
345            TypeOwner::World(id),
346            types.into_iter(),
347            &resource_funcs,
348        )?;
349        if !world.exports.is_empty() {
350            self.new_item();
351        }
352        for (name, export) in world.exports.iter() {
353            self.print_world_item(resolve, name, export, pkgid, "export")?;
354        }
355        self.any_items = prev_items;
356        Ok(())
357    }
358
359    fn print_world_item(
360        &mut self,
361        resolve: &Resolve,
362        name: &WorldKey,
363        item: &WorldItem,
364        cur_pkg: PackageId,
365        desc: &str,
366    ) -> Result<()> {
367        // Print inline item docs
368        if matches!(name, WorldKey::Name(_)) {
369            self.print_docs(match item {
370                WorldItem::Interface(id) => &resolve.interfaces[*id].docs,
371                WorldItem::Function(f) => &f.docs,
372                // Types are handled separately
373                WorldItem::Type(_) => unreachable!(),
374            });
375        }
376
377        self.output.push_str(desc);
378        self.output.push_str(" ");
379        match name {
380            WorldKey::Name(name) => {
381                self.print_name(name);
382                self.output.push_str(": ");
383                match item {
384                    WorldItem::Interface(id) => {
385                        assert!(resolve.interfaces[*id].name.is_none());
386                        writeln!(self.output, "interface {{")?;
387                        self.print_interface(resolve, *id)?;
388                        writeln!(self.output, "}}")?;
389                    }
390                    WorldItem::Function(f) => {
391                        self.print_function(resolve, f)?;
392                        self.print_semicolon();
393                        self.output.push_str("\n");
394                    }
395                    // Types are handled separately
396                    WorldItem::Type(_) => unreachable!(),
397                }
398            }
399            WorldKey::Interface(id) => {
400                match item {
401                    WorldItem::Interface(id2) => assert_eq!(id, id2),
402                    _ => unreachable!(),
403                }
404                self.print_path_to_interface(resolve, *id, cur_pkg)?;
405                self.print_semicolon();
406                self.output.push_str("\n");
407            }
408        }
409        Ok(())
410    }
411
412    fn print_path_to_interface(
413        &mut self,
414        resolve: &Resolve,
415        interface: InterfaceId,
416        cur_pkg: PackageId,
417    ) -> Result<()> {
418        let iface = &resolve.interfaces[interface];
419        if iface.package == Some(cur_pkg) {
420            self.print_name(iface.name.as_ref().unwrap());
421        } else {
422            let pkg = &resolve.packages[iface.package.unwrap()].name;
423            self.print_name(&pkg.namespace);
424            self.output.push_str(":");
425            self.print_name(&pkg.name);
426            self.output.push_str("/");
427            self.print_name(iface.name.as_ref().unwrap());
428            if let Some(version) = &pkg.version {
429                self.output.push_str(&format!("@{version}"));
430            }
431        }
432        Ok(())
433    }
434
435    fn print_type_name(&mut self, resolve: &Resolve, ty: &Type) -> Result<()> {
436        match ty {
437            Type::Bool => self.output.push_str("bool"),
438            Type::U8 => self.output.push_str("u8"),
439            Type::U16 => self.output.push_str("u16"),
440            Type::U32 => self.output.push_str("u32"),
441            Type::U64 => self.output.push_str("u64"),
442            Type::S8 => self.output.push_str("s8"),
443            Type::S16 => self.output.push_str("s16"),
444            Type::S32 => self.output.push_str("s32"),
445            Type::S64 => self.output.push_str("s64"),
446            Type::F32 => {
447                if self.print_f32_f64 {
448                    self.output.push_str("f32")
449                } else {
450                    self.output.push_str("f32")
451                }
452            }
453            Type::F64 => {
454                if self.print_f32_f64 {
455                    self.output.push_str("f64")
456                } else {
457                    self.output.push_str("f64")
458                }
459            }
460            Type::Char => self.output.push_str("char"),
461            Type::String => self.output.push_str("string"),
462
463            Type::Id(id) => {
464                let ty = &resolve.types[*id];
465                if let Some(name) = &ty.name {
466                    self.print_name(name);
467                    return Ok(());
468                }
469
470                match &ty.kind {
471                    TypeDefKind::Handle(h) => {
472                        self.print_handle_type(resolve, h, false)?;
473                    }
474                    TypeDefKind::Resource => {
475                        bail!("resolve has an unnamed resource type");
476                    }
477                    TypeDefKind::Tuple(t) => {
478                        self.print_tuple_type(resolve, t)?;
479                    }
480                    TypeDefKind::Option(t) => {
481                        self.print_option_type(resolve, t)?;
482                    }
483                    TypeDefKind::Result(t) => {
484                        self.print_result_type(resolve, t)?;
485                    }
486                    TypeDefKind::Record(_) => {
487                        bail!("resolve has an unnamed record type");
488                    }
489                    TypeDefKind::Flags(_) => {
490                        bail!("resolve has unnamed flags type")
491                    }
492                    TypeDefKind::Enum(_) => {
493                        bail!("resolve has unnamed enum type")
494                    }
495                    TypeDefKind::Variant(_) => {
496                        bail!("resolve has unnamed variant type")
497                    }
498                    TypeDefKind::List(ty) => {
499                        self.output.push_str("list<");
500                        self.print_type_name(resolve, ty)?;
501                        self.output.push_str(">");
502                    }
503                    TypeDefKind::Type(ty) => self.print_type_name(resolve, ty)?,
504                    TypeDefKind::Future(_) => {
505                        todo!("document has an unnamed future type")
506                    }
507                    TypeDefKind::Stream(_) => {
508                        todo!("document has an unnamed stream type")
509                    }
510                    TypeDefKind::Unknown => unreachable!(),
511                }
512            }
513        }
514
515        Ok(())
516    }
517
518    fn print_handle_type(
519        &mut self,
520        resolve: &Resolve,
521        handle: &Handle,
522        force_handle_type_printed: bool,
523    ) -> Result<()> {
524        match handle {
525            Handle::Own(ty) => {
526                let ty = &resolve.types[*ty];
527                if force_handle_type_printed {
528                    self.output.push_str("own<");
529                }
530                self.print_name(
531                    ty.name
532                        .as_ref()
533                        .ok_or_else(|| anyhow!("unnamed resource type"))?,
534                );
535                if force_handle_type_printed {
536                    self.output.push_str(">");
537                }
538            }
539
540            Handle::Borrow(ty) => {
541                self.output.push_str("borrow<");
542                let ty = &resolve.types[*ty];
543                self.print_name(
544                    ty.name
545                        .as_ref()
546                        .ok_or_else(|| anyhow!("unnamed resource type"))?,
547                );
548                self.output.push_str(">");
549            }
550        }
551
552        Ok(())
553    }
554
555    fn print_tuple_type(&mut self, resolve: &Resolve, tuple: &Tuple) -> Result<()> {
556        self.output.push_str("tuple<");
557        for (i, ty) in tuple.types.iter().enumerate() {
558            if i > 0 {
559                self.output.push_str(", ");
560            }
561            self.print_type_name(resolve, ty)?;
562        }
563        self.output.push_str(">");
564
565        Ok(())
566    }
567
568    fn print_option_type(&mut self, resolve: &Resolve, payload: &Type) -> Result<()> {
569        self.output.push_str("option<");
570        self.print_type_name(resolve, payload)?;
571        self.output.push_str(">");
572        Ok(())
573    }
574
575    fn print_result_type(&mut self, resolve: &Resolve, result: &Result_) -> Result<()> {
576        match result {
577            Result_ {
578                ok: Some(ok),
579                err: Some(err),
580            } => {
581                self.output.push_str("result<");
582                self.print_type_name(resolve, ok)?;
583                self.output.push_str(", ");
584                self.print_type_name(resolve, err)?;
585                self.output.push_str(">");
586            }
587            Result_ {
588                ok: None,
589                err: Some(err),
590            } => {
591                self.output.push_str("result<_, ");
592                self.print_type_name(resolve, err)?;
593                self.output.push_str(">");
594            }
595            Result_ {
596                ok: Some(ok),
597                err: None,
598            } => {
599                self.output.push_str("result<");
600                self.print_type_name(resolve, ok)?;
601                self.output.push_str(">");
602            }
603            Result_ {
604                ok: None,
605                err: None,
606            } => {
607                self.output.push_str("result");
608            }
609        }
610        Ok(())
611    }
612
613    fn declare_type(&mut self, resolve: &Resolve, ty: &Type) -> Result<()> {
614        match ty {
615            Type::Bool
616            | Type::U8
617            | Type::U16
618            | Type::U32
619            | Type::U64
620            | Type::S8
621            | Type::S16
622            | Type::S32
623            | Type::S64
624            | Type::F32
625            | Type::F64
626            | Type::Char
627            | Type::String => return Ok(()),
628
629            Type::Id(id) => {
630                let ty = &resolve.types[*id];
631                match &ty.kind {
632                    TypeDefKind::Handle(h) => {
633                        self.declare_handle(resolve, ty.name.as_deref(), h)?
634                    }
635                    TypeDefKind::Resource => panic!("resources should be processed separately"),
636                    TypeDefKind::Record(r) => {
637                        self.declare_record(resolve, ty.name.as_deref(), r)?
638                    }
639                    TypeDefKind::Tuple(t) => self.declare_tuple(resolve, ty.name.as_deref(), t)?,
640                    TypeDefKind::Flags(f) => self.declare_flags(ty.name.as_deref(), f)?,
641                    TypeDefKind::Variant(v) => {
642                        self.declare_variant(resolve, ty.name.as_deref(), v)?
643                    }
644                    TypeDefKind::Option(t) => {
645                        self.declare_option(resolve, ty.name.as_deref(), t)?
646                    }
647                    TypeDefKind::Result(r) => {
648                        self.declare_result(resolve, ty.name.as_deref(), r)?
649                    }
650                    TypeDefKind::Enum(e) => self.declare_enum(ty.name.as_deref(), e)?,
651                    TypeDefKind::List(inner) => {
652                        self.declare_list(resolve, ty.name.as_deref(), inner)?
653                    }
654                    TypeDefKind::Type(inner) => match ty.name.as_deref() {
655                        Some(name) => {
656                            self.output.push_str("type ");
657                            self.print_name(name);
658                            self.output.push_str(" = ");
659                            self.print_type_name(resolve, inner)?;
660                            self.print_semicolon();
661                            self.output.push_str("\n");
662                        }
663                        None => bail!("unnamed type in document"),
664                    },
665                    TypeDefKind::Future(_) => todo!("declare future"),
666                    TypeDefKind::Stream(_) => todo!("declare stream"),
667                    TypeDefKind::Unknown => unreachable!(),
668                }
669            }
670        }
671        Ok(())
672    }
673
674    fn declare_handle(
675        &mut self,
676        resolve: &Resolve,
677        name: Option<&str>,
678        handle: &Handle,
679    ) -> Result<()> {
680        match name {
681            Some(name) => {
682                self.output.push_str("type ");
683                self.print_name(name);
684                self.output.push_str(" = ");
685                // Note that the `true` here forces owned handles to be printed
686                // as `own<T>`. The purpose of this is because `type a = b`, if
687                // `b` is a resource, is encoded differently as `type a =
688                // own<b>`. By forcing a handle to be printed here it's staying
689                // true to what's in the WIT document.
690                self.print_handle_type(resolve, handle, true)?;
691                self.print_semicolon();
692                self.output.push_str("\n");
693
694                Ok(())
695            }
696            None => bail!("document has unnamed handle type"),
697        }
698    }
699
700    fn declare_record(
701        &mut self,
702        resolve: &Resolve,
703        name: Option<&str>,
704        record: &Record,
705    ) -> Result<()> {
706        match name {
707            Some(name) => {
708                self.output.push_str("record ");
709                self.print_name(name);
710                self.output.push_str(" {\n");
711                for field in &record.fields {
712                    self.print_docs(&field.docs);
713                    self.print_name(&field.name);
714                    self.output.push_str(": ");
715                    self.print_type_name(resolve, &field.ty)?;
716                    self.output.push_str(",\n");
717                }
718                self.output.push_str("}\n");
719                Ok(())
720            }
721            None => bail!("document has unnamed record type"),
722        }
723    }
724
725    fn declare_tuple(
726        &mut self,
727        resolve: &Resolve,
728        name: Option<&str>,
729        tuple: &Tuple,
730    ) -> Result<()> {
731        if let Some(name) = name {
732            self.output.push_str("type ");
733            self.print_name(name);
734            self.output.push_str(" = ");
735            self.print_tuple_type(resolve, tuple)?;
736            self.print_semicolon();
737            self.output.push_str("\n");
738        }
739        Ok(())
740    }
741
742    fn declare_flags(&mut self, name: Option<&str>, flags: &Flags) -> Result<()> {
743        match name {
744            Some(name) => {
745                self.output.push_str("flags ");
746                self.print_name(name);
747                self.output.push_str(" {\n");
748                for flag in &flags.flags {
749                    self.print_docs(&flag.docs);
750                    self.print_name(&flag.name);
751                    self.output.push_str(",\n");
752                }
753                self.output.push_str("}\n");
754            }
755            None => bail!("document has unnamed flags type"),
756        }
757        Ok(())
758    }
759
760    fn declare_variant(
761        &mut self,
762        resolve: &Resolve,
763        name: Option<&str>,
764        variant: &Variant,
765    ) -> Result<()> {
766        let name = match name {
767            Some(name) => name,
768            None => bail!("document has unnamed variant type"),
769        };
770        self.output.push_str("variant ");
771        self.print_name(name);
772        self.output.push_str(" {\n");
773        for case in &variant.cases {
774            self.print_docs(&case.docs);
775            self.print_name(&case.name);
776            if let Some(ty) = case.ty {
777                self.output.push_str("(");
778                self.print_type_name(resolve, &ty)?;
779                self.output.push_str(")");
780            }
781            self.output.push_str(",\n");
782        }
783        self.output.push_str("}\n");
784        Ok(())
785    }
786
787    fn declare_option(
788        &mut self,
789        resolve: &Resolve,
790        name: Option<&str>,
791        payload: &Type,
792    ) -> Result<()> {
793        if let Some(name) = name {
794            self.output.push_str("type ");
795            self.print_name(name);
796            self.output.push_str(" = ");
797            self.print_option_type(resolve, payload)?;
798            self.print_semicolon();
799            self.output.push_str("\n");
800        }
801        Ok(())
802    }
803
804    fn declare_result(
805        &mut self,
806        resolve: &Resolve,
807        name: Option<&str>,
808        result: &Result_,
809    ) -> Result<()> {
810        if let Some(name) = name {
811            self.output.push_str("type ");
812            self.print_name(name);
813            self.output.push_str(" = ");
814            self.print_result_type(resolve, result)?;
815            self.print_semicolon();
816            self.output.push_str("\n");
817        }
818        Ok(())
819    }
820
821    fn declare_enum(&mut self, name: Option<&str>, enum_: &Enum) -> Result<()> {
822        let name = match name {
823            Some(name) => name,
824            None => bail!("document has unnamed enum type"),
825        };
826        self.output.push_str("enum ");
827        self.print_name(name);
828        self.output.push_str(" {\n");
829        for case in &enum_.cases {
830            self.print_docs(&case.docs);
831            self.print_name(&case.name);
832            self.output.push_str(",\n");
833        }
834        self.output.push_str("}\n");
835        Ok(())
836    }
837
838    fn declare_list(&mut self, resolve: &Resolve, name: Option<&str>, ty: &Type) -> Result<()> {
839        if let Some(name) = name {
840            self.output.push_str("type ");
841            self.print_name(name);
842            self.output.push_str(" = list<");
843            self.print_type_name(resolve, ty)?;
844            self.output.push_str(">");
845            self.print_semicolon();
846            self.output.push_str("\n");
847            return Ok(());
848        }
849
850        Ok(())
851    }
852
853    fn print_name(&mut self, name: &str) {
854        if is_keyword(name) {
855            self.output.push_str("%");
856        }
857        self.output.push_str(name);
858    }
859
860    fn print_docs(&mut self, docs: &Docs) {
861        if self.emit_docs {
862            if let Some(contents) = &docs.contents {
863                for line in contents.lines() {
864                    self.output.push_str("/// ");
865                    self.output.push_str(line);
866                    self.output.push_str("\n");
867                }
868            }
869        }
870    }
871}
872
873fn resource_func(f: &Function) -> Option<TypeId> {
874    match f.kind {
875        FunctionKind::Freestanding => None,
876        FunctionKind::Method(id) | FunctionKind::Constructor(id) | FunctionKind::Static(id) => {
877            Some(id)
878        }
879    }
880}
881
882fn is_keyword(name: &str) -> bool {
883    matches!(
884        name,
885        "use"
886            | "type"
887            | "func"
888            | "u8"
889            | "u16"
890            | "u32"
891            | "u64"
892            | "s8"
893            | "s16"
894            | "s32"
895            | "s64"
896            | "f32"
897            | "f64"
898            | "float32"
899            | "float64"
900            | "char"
901            | "resource"
902            | "record"
903            | "flags"
904            | "variant"
905            | "enum"
906            | "bool"
907            | "string"
908            | "option"
909            | "result"
910            | "future"
911            | "stream"
912            | "list"
913            | "own"
914            | "borrow"
915            | "_"
916            | "as"
917            | "from"
918            | "static"
919            | "interface"
920            | "tuple"
921            | "world"
922            | "import"
923            | "export"
924            | "package"
925            | "with"
926            | "include"
927            | "constructor"
928    )
929}
930
931/// Helper structure to help maintain an indentation level when printing source,
932/// modeled after the support in `wit-bindgen-core`.
933#[derive(Default)]
934struct Output {
935    indent: usize,
936    output: String,
937}
938
939impl Output {
940    fn push_str(&mut self, src: &str) {
941        let lines = src.lines().collect::<Vec<_>>();
942        for (i, line) in lines.iter().enumerate() {
943            let trimmed = line.trim();
944            if trimmed.starts_with('}') && self.output.ends_with("  ") {
945                self.output.pop();
946                self.output.pop();
947            }
948            self.output.push_str(if lines.len() == 1 {
949                line
950            } else {
951                line.trim_start()
952            });
953            if trimmed.ends_with('{') {
954                self.indent += 1;
955            }
956            if trimmed.starts_with('}') {
957                // Note that a `saturating_sub` is used here to prevent a panic
958                // here in the case of invalid code being generated in debug
959                // mode. It's typically easier to debug those issues through
960                // looking at the source code rather than getting a panic.
961                self.indent = self.indent.saturating_sub(1);
962            }
963            if i != lines.len() - 1 || src.ends_with('\n') {
964                // Trim trailing whitespace, if any, then push an indented
965                // newline
966                while let Some(c) = self.output.chars().next_back() {
967                    if c.is_whitespace() && c != '\n' {
968                        self.output.pop();
969                    } else {
970                        break;
971                    }
972                }
973                self.output.push('\n');
974                for _ in 0..self.indent {
975                    self.output.push_str("  ");
976                }
977            }
978        }
979    }
980}
981
982impl Write for Output {
983    fn write_str(&mut self, s: &str) -> fmt::Result {
984        self.push_str(s);
985        Ok(())
986    }
987}
988
989impl From<Output> for String {
990    fn from(output: Output) -> String {
991        output.output
992    }
993}