Skip to main content

wit_component/
printing.rs

1use anyhow::{Result, anyhow, bail};
2use std::borrow::Cow;
3use std::collections::HashMap;
4use std::fmt::Display;
5use std::mem;
6use std::ops::Deref;
7use wit_parser::*;
8
9/// A utility for printing WebAssembly interface definitions to a string.
10pub struct WitPrinter<O: Output = OutputToString> {
11    /// Visitor that holds the WIT document being printed.
12    pub output: O,
13
14    // Count of how many items in this current block have been printed to print
15    // a blank line between each item, but not the first item.
16    any_items: bool,
17
18    // Whether to print doc comments.
19    emit_docs: bool,
20}
21
22impl Default for WitPrinter {
23    fn default() -> Self {
24        Self::new(OutputToString::default())
25    }
26}
27
28impl<O: Output> WitPrinter<O> {
29    /// Create new instance.
30    pub fn new(output: O) -> Self {
31        Self {
32            output,
33            any_items: false,
34            emit_docs: true,
35        }
36    }
37
38    /// Prints the specified `pkg` which is located in `resolve` to `O`.
39    ///
40    /// The `nested` list of packages are other packages to include at the end
41    /// of the output in `package ... { ... }` syntax.
42    pub fn print(&mut self, resolve: &Resolve, pkg: PackageId, nested: &[PackageId]) -> Result<()> {
43        self.print_package(resolve, pkg, true)?;
44        for (i, pkg_id) in nested.iter().enumerate() {
45            if i > 0 {
46                self.output.newline();
47                self.output.newline();
48            }
49            self.print_package(resolve, *pkg_id, false)?;
50        }
51        Ok(())
52    }
53
54    /// Configure whether doc comments will be printed.
55    ///
56    /// Defaults to true.
57    pub fn emit_docs(&mut self, enabled: bool) -> &mut Self {
58        self.emit_docs = enabled;
59        self
60    }
61
62    /// Prints the specified `pkg`.
63    ///
64    /// If `is_main` is not set, nested package notation is used.
65    pub fn print_package(
66        &mut self,
67        resolve: &Resolve,
68        pkg: PackageId,
69        is_main: bool,
70    ) -> Result<()> {
71        let pkg = &resolve.packages[pkg];
72        self.print_package_outer(pkg)?;
73
74        if is_main {
75            self.output.semicolon();
76            self.output.newline();
77        } else {
78            self.output.indent_start();
79        }
80
81        for (name, id) in pkg.interfaces.iter() {
82            self.print_interface_outer(resolve, *id, name)?;
83            self.output.indent_start();
84            self.print_interface(resolve, *id)?;
85            self.output.indent_end();
86            if is_main {
87                self.output.newline();
88            }
89        }
90
91        for (name, id) in pkg.worlds.iter() {
92            self.print_docs(&resolve.worlds[*id].docs);
93            self.print_stability(&resolve.worlds[*id].stability);
94            self.output.keyword("world");
95            self.output.str(" ");
96            self.print_name_type(name, TypeKind::WorldDeclaration);
97            self.output.indent_start();
98            self.print_world(resolve, *id)?;
99            self.output.indent_end();
100        }
101        if !is_main {
102            self.output.indent_end();
103        }
104        Ok(())
105    }
106
107    /// Print the specified package without its content.
108    /// Does not print the semicolon nor starts the indentation.
109    pub fn print_package_outer(&mut self, pkg: &Package) -> Result<()> {
110        self.print_docs(&pkg.docs);
111        self.output.keyword("package");
112        self.output.str(" ");
113        self.print_name_type(&pkg.name.namespace, TypeKind::NamespaceDeclaration);
114        self.output.str(":");
115        self.print_name_type(&pkg.name.name, TypeKind::PackageNameDeclaration);
116        if let Some(version) = &pkg.name.version {
117            self.print_name_type(&format!("@{version}"), TypeKind::VersionDeclaration);
118        }
119        Ok(())
120    }
121
122    fn new_item(&mut self) {
123        if self.any_items {
124            self.output.newline();
125        }
126        self.any_items = true;
127    }
128
129    /// Print the given WebAssembly interface without its content.
130    /// Does not print the semicolon nor starts the indentation.
131    pub fn print_interface_outer(
132        &mut self,
133        resolve: &Resolve,
134        id: InterfaceId,
135        name: &str,
136    ) -> Result<()> {
137        self.print_docs(&resolve.interfaces[id].docs);
138        self.print_stability(&resolve.interfaces[id].stability);
139        self.output.keyword("interface");
140        self.output.str(" ");
141        self.print_name_type(name, TypeKind::InterfaceDeclaration);
142        Ok(())
143    }
144
145    /// Print the inner content of a given WebAssembly interface.
146    pub fn print_interface(&mut self, resolve: &Resolve, id: InterfaceId) -> Result<()> {
147        let prev_items = mem::replace(&mut self.any_items, false);
148        let interface = &resolve.interfaces[id];
149
150        let mut resource_funcs = HashMap::new();
151        let mut freestanding = Vec::new();
152        for (_, func) in interface.functions.iter() {
153            if let Some(id) = func.kind.resource() {
154                resource_funcs.entry(id).or_insert(Vec::new()).push(func);
155            } else {
156                freestanding.push(func);
157            }
158        }
159
160        self.print_types(
161            resolve,
162            TypeOwner::Interface(id),
163            interface
164                .types
165                .iter()
166                .map(|(name, id)| (name.as_str(), *id)),
167            &resource_funcs,
168        )?;
169
170        for func in freestanding {
171            self.new_item();
172            self.print_docs(&func.docs);
173            self.print_stability(&func.stability);
174            self.print_name_type(func.item_name(), TypeKind::FunctionFreestanding);
175            self.output.str(": ");
176            self.print_function(resolve, func)?;
177            self.output.semicolon();
178        }
179
180        self.any_items = prev_items;
181
182        Ok(())
183    }
184
185    /// Print types of an interface.
186    pub fn print_types<'a>(
187        &mut self,
188        resolve: &Resolve,
189        owner: TypeOwner,
190        types: impl Iterator<Item = (&'a str, TypeId)>,
191        resource_funcs: &HashMap<TypeId, Vec<&Function>>,
192    ) -> Result<()> {
193        // Partition types defined in this interface into either those imported
194        // from foreign interfaces or those defined locally.
195        let mut types_to_declare = Vec::new();
196        let mut types_to_import: Vec<(_, &_, Vec<_>)> = Vec::new();
197        for (name, ty_id) in types {
198            let ty = &resolve.types[ty_id];
199            if let TypeDefKind::Type(Type::Id(other)) = ty.kind {
200                let other = &resolve.types[other];
201                match other.owner {
202                    TypeOwner::None => {}
203                    other_owner if owner != other_owner => {
204                        let other_name = other
205                            .name
206                            .as_ref()
207                            .ok_or_else(|| anyhow!("cannot import unnamed type"))?;
208                        if let Some((owner, stability, list)) = types_to_import.last_mut() {
209                            if *owner == other_owner && ty.stability == **stability {
210                                list.push((name, other_name));
211                                continue;
212                            }
213                        }
214                        types_to_import.push((
215                            other_owner,
216                            &ty.stability,
217                            vec![(name, other_name)],
218                        ));
219                        continue;
220                    }
221                    _ => {}
222                }
223            }
224
225            types_to_declare.push(ty_id);
226        }
227
228        // Generate a `use` statement for all imported types.
229        let my_pkg = match owner {
230            TypeOwner::Interface(id) => resolve.interfaces[id].package.unwrap(),
231            TypeOwner::World(id) => resolve.worlds[id].package.unwrap(),
232            TypeOwner::None => unreachable!(),
233        };
234        for (owner, stability, tys) in types_to_import {
235            self.any_items = true;
236            self.print_stability(stability);
237            self.output.keyword("use");
238            self.output.str(" ");
239            let id = match owner {
240                TypeOwner::Interface(id) => id,
241                // it's only possible to import types from interfaces at
242                // this time.
243                _ => unreachable!(),
244            };
245            self.print_path_to_interface(resolve, id, my_pkg)?;
246            self.output.str(".{"); // Note: not changing the indentation.
247            for (i, (my_name, other_name)) in tys.into_iter().enumerate() {
248                if i > 0 {
249                    self.output.str(", ");
250                }
251                if my_name == other_name {
252                    self.print_name_type(my_name, TypeKind::TypeImport);
253                } else {
254                    self.print_name_type(other_name, TypeKind::TypeImport);
255                    self.output.str(" ");
256                    self.output.keyword("as");
257                    self.output.str(" ");
258                    self.print_name_type(my_name, TypeKind::TypeAlias);
259                }
260            }
261            self.output.str("}"); // Note: not changing the indentation.
262            self.output.semicolon();
263        }
264
265        for id in types_to_declare {
266            self.new_item();
267            self.print_docs(&resolve.types[id].docs);
268            self.print_stability(&resolve.types[id].stability);
269            match resolve.types[id].kind {
270                TypeDefKind::Resource => self.print_resource(
271                    resolve,
272                    id,
273                    resource_funcs.get(&id).unwrap_or(&Vec::new()),
274                )?,
275                _ => self.declare_type(resolve, &Type::Id(id))?,
276            }
277        }
278
279        Ok(())
280    }
281
282    fn print_resource(&mut self, resolve: &Resolve, id: TypeId, funcs: &[&Function]) -> Result<()> {
283        let ty = &resolve.types[id];
284        self.output.ty("resource", TypeKind::BuiltIn);
285        self.output.str(" ");
286        self.print_name_type(
287            ty.name.as_ref().expect("resources must be named"),
288            TypeKind::Resource,
289        );
290        if funcs.is_empty() {
291            self.output.semicolon();
292            return Ok(());
293        }
294        self.output.indent_start();
295        for func in funcs {
296            self.print_docs(&func.docs);
297            self.print_stability(&func.stability);
298
299            match &func.kind {
300                FunctionKind::Constructor(_) => {}
301                FunctionKind::Method(_) | FunctionKind::AsyncMethod(_) => {
302                    self.print_name_type(func.item_name(), TypeKind::FunctionMethod);
303                    self.output.str(": ");
304                }
305                FunctionKind::Static(_) | FunctionKind::AsyncStatic(_) => {
306                    self.print_name_type(func.item_name(), TypeKind::FunctionStatic);
307                    self.output.str(": ");
308                    self.output.keyword("static");
309                    self.output.str(" ");
310                }
311                FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => unreachable!(),
312            }
313            self.print_function(resolve, func)?;
314            self.output.semicolon();
315        }
316        self.output.indent_end();
317
318        Ok(())
319    }
320
321    fn print_function(&mut self, resolve: &Resolve, func: &Function) -> Result<()> {
322        // Handle the `async` prefix if necessary
323        match &func.kind {
324            FunctionKind::AsyncFreestanding
325            | FunctionKind::AsyncMethod(_)
326            | FunctionKind::AsyncStatic(_) => {
327                self.output.keyword("async");
328                self.output.str(" ");
329            }
330            _ => {}
331        }
332
333        // Constructors are named slightly differently.
334        match &func.kind {
335            FunctionKind::Constructor(_) => {
336                self.output.keyword("constructor");
337                self.output.str("(");
338            }
339            FunctionKind::Freestanding
340            | FunctionKind::AsyncFreestanding
341            | FunctionKind::Method(_)
342            | FunctionKind::AsyncMethod(_)
343            | FunctionKind::Static(_)
344            | FunctionKind::AsyncStatic(_) => {
345                self.output.keyword("func");
346                self.output.str("(");
347            }
348        }
349
350        // Methods don't print their `self` argument
351        let params_to_skip = match &func.kind {
352            FunctionKind::Method(_) | FunctionKind::AsyncMethod(_) => 1,
353            _ => 0,
354        };
355        for (i, param) in func.params.iter().skip(params_to_skip).enumerate() {
356            if i > 0 {
357                self.output.str(", ");
358            }
359            self.print_name_param(&param.name);
360            self.output.str(": ");
361            self.print_type_name(resolve, &param.ty)?;
362        }
363        self.output.str(")");
364
365        // shorthand constructors don't have their results printed
366        if func.is_constructor_shorthand(resolve) {
367            return Ok(());
368        }
369
370        if let Some(ty) = &func.result {
371            self.output.str(" -> ");
372            self.print_type_name(resolve, ty)?;
373        }
374        Ok(())
375    }
376
377    /// Prints the world `id` within `resolve`.
378    ///
379    /// This is a little tricky to preserve round-tripping that WIT wants. This
380    /// function inherently can't preserve ordering of imports because resource
381    /// functions aren't guaranteed to be all adjacent to the resource itself
382    /// they're attached to. That means that at the very least, when printing
383    /// resource functions, items may be printed out-of-order.
384    ///
385    /// To help solve this the printing here is kept in sync with WIT encoding
386    /// of worlds which is to print items in the order of:
387    ///
388    /// * Any imported interface. Ordering between interfaces is preserved.
389    /// * Any types, including resource functions on those types. Ordering
390    ///   between types is preserved.
391    /// * Any functions, which may refer to those types. Ordering between
392    ///   functions is preserved.
393    ///
394    /// This keeps things printed in a roughly topological fashion and makes
395    /// round-tripping a bit more reliable.
396    fn print_world(&mut self, resolve: &Resolve, id: WorldId) -> Result<()> {
397        let prev_items = mem::replace(&mut self.any_items, false);
398        let world = &resolve.worlds[id];
399        let pkgid = world.package.unwrap();
400        let mut types = Vec::new();
401        let mut resource_funcs = HashMap::new();
402        let mut function_imports_to_print = Vec::new();
403        for (name, import) in world.imports.iter() {
404            match import {
405                WorldItem::Type { id, .. } => match name {
406                    WorldKey::Name(s) => types.push((s.as_str(), *id)),
407                    WorldKey::Interface(_) => unreachable!(),
408                },
409                _ => {
410                    if let WorldItem::Function(f) = import {
411                        if let Some(id) = f.kind.resource() {
412                            resource_funcs.entry(id).or_insert(Vec::new()).push(f);
413                            continue;
414                        }
415                        function_imports_to_print.push((name, import));
416                        continue;
417                    }
418                    self.print_world_item(resolve, name, import, pkgid, "import")?;
419                    // Don't put a blank line between imports, but count
420                    // imports as having printed something so if anything comes
421                    // after them then a blank line is printed after imports.
422                    self.any_items = true;
423                }
424            }
425        }
426        self.print_types(
427            resolve,
428            TypeOwner::World(id),
429            types.into_iter(),
430            &resource_funcs,
431        )?;
432
433        for (name, import) in function_imports_to_print {
434            self.print_world_item(resolve, name, import, pkgid, "import")?;
435            self.any_items = true;
436        }
437        if !world.exports.is_empty() {
438            self.new_item();
439        }
440        for (name, export) in world.exports.iter() {
441            self.print_world_item(resolve, name, export, pkgid, "export")?;
442        }
443        self.any_items = prev_items;
444        Ok(())
445    }
446
447    fn print_world_item(
448        &mut self,
449        resolve: &Resolve,
450        name: &WorldKey,
451        item: &WorldItem,
452        cur_pkg: PackageId,
453        import_or_export_keyword: &str,
454    ) -> Result<()> {
455        // Print docs for this import/export statement. For interfaces, prefer
456        // the docs attached to the statement itself (`WorldItem::Interface`'s
457        // `docs`); for an inline `import x: interface { .. }` with no statement
458        // docs fall back to the interface definition's docs.
459        let docs = match item {
460            WorldItem::Interface { id, docs, .. } => {
461                if docs.contents.is_some() {
462                    Some(docs)
463                } else if matches!(name, WorldKey::Name(_)) {
464                    Some(&resolve.interfaces[*id].docs)
465                } else {
466                    None
467                }
468            }
469            WorldItem::Function(f) => Some(&f.docs),
470            // Types are handled separately
471            WorldItem::Type { .. } => unreachable!(),
472        };
473        if let Some(docs) = docs {
474            self.print_docs(docs);
475        }
476
477        self.print_stability(item.stability(resolve));
478        self.output.keyword(import_or_export_keyword);
479        self.output.str(" ");
480        match name {
481            WorldKey::Name(name) => {
482                match item {
483                    WorldItem::Interface { id, .. } => {
484                        self.print_name_type(name, TypeKind::Other);
485                        self.output.str(": ");
486                        if resolve.interfaces[*id].name.is_none() {
487                            // `import label: interface { .. }` syntax
488                            self.output.keyword("interface");
489                            self.output.indent_start();
490                            self.print_interface(resolve, *id)?;
491                            self.output.indent_end();
492                        } else {
493                            // `import label: use-path;` syntax
494                            self.print_path_to_interface(resolve, *id, cur_pkg)?;
495                            self.output.semicolon();
496                        }
497                    }
498                    WorldItem::Function(f) => {
499                        self.print_name_type(&f.name, TypeKind::Other);
500                        self.output.str(": ");
501                        self.print_function(resolve, f)?;
502                        self.output.semicolon();
503                    }
504                    // Types are handled separately
505                    WorldItem::Type { .. } => unreachable!(),
506                }
507            }
508            WorldKey::Interface(id) => {
509                match item {
510                    WorldItem::Interface { id: id2, .. } => assert_eq!(id, id2),
511                    _ => unreachable!(),
512                }
513                self.print_path_to_interface(resolve, *id, cur_pkg)?;
514                self.output.semicolon();
515            }
516        }
517        Ok(())
518    }
519
520    fn print_path_to_interface(
521        &mut self,
522        resolve: &Resolve,
523        interface: InterfaceId,
524        cur_pkg: PackageId,
525    ) -> Result<()> {
526        let iface = &resolve.interfaces[interface];
527        if iface.package == Some(cur_pkg) {
528            self.print_name_type(iface.name.as_ref().unwrap(), TypeKind::InterfacePath);
529        } else {
530            let pkg = &resolve.packages[iface.package.unwrap()].name;
531            self.print_name_type(&pkg.namespace, TypeKind::NamespacePath);
532            self.output.str(":");
533            self.print_name_type(&pkg.name, TypeKind::PackageNamePath);
534            self.output.str("/");
535            self.print_name_type(iface.name.as_ref().unwrap(), TypeKind::InterfacePath);
536            if let Some(version) = &pkg.version {
537                self.print_name_type(&format!("@{version}"), TypeKind::VersionPath);
538            }
539        }
540        Ok(())
541    }
542
543    /// Print the name of type `ty`.
544    pub fn print_type_name(&mut self, resolve: &Resolve, ty: &Type) -> Result<()> {
545        match ty {
546            Type::Bool => self.output.ty("bool", TypeKind::BuiltIn),
547            Type::U8 => self.output.ty("u8", TypeKind::BuiltIn),
548            Type::U16 => self.output.ty("u16", TypeKind::BuiltIn),
549            Type::U32 => self.output.ty("u32", TypeKind::BuiltIn),
550            Type::U64 => self.output.ty("u64", TypeKind::BuiltIn),
551            Type::S8 => self.output.ty("s8", TypeKind::BuiltIn),
552            Type::S16 => self.output.ty("s16", TypeKind::BuiltIn),
553            Type::S32 => self.output.ty("s32", TypeKind::BuiltIn),
554            Type::S64 => self.output.ty("s64", TypeKind::BuiltIn),
555            Type::F32 => self.output.ty("f32", TypeKind::BuiltIn),
556            Type::F64 => self.output.ty("f64", TypeKind::BuiltIn),
557            Type::Char => self.output.ty("char", TypeKind::BuiltIn),
558            Type::String => self.output.ty("string", TypeKind::BuiltIn),
559            Type::ErrorContext => self.output.ty("error-context", TypeKind::BuiltIn),
560
561            Type::Id(id) => {
562                let ty = &resolve.types[*id];
563                if let Some(name) = &ty.name {
564                    self.print_name_type(name, TypeKind::Other);
565                    return Ok(());
566                }
567
568                match &ty.kind {
569                    TypeDefKind::Handle(h) => {
570                        self.print_handle_type(resolve, h, false)?;
571                    }
572                    TypeDefKind::Resource => {
573                        bail!("resolve has an unnamed resource type");
574                    }
575                    TypeDefKind::Tuple(t) => {
576                        self.print_tuple_type(resolve, t)?;
577                    }
578                    TypeDefKind::Option(t) => {
579                        self.print_option_type(resolve, t)?;
580                    }
581                    TypeDefKind::Result(t) => {
582                        self.print_result_type(resolve, t)?;
583                    }
584                    TypeDefKind::Record(_) => {
585                        bail!("resolve has an unnamed record type");
586                    }
587                    TypeDefKind::Flags(_) => {
588                        bail!("resolve has unnamed flags type")
589                    }
590                    TypeDefKind::Enum(_) => {
591                        bail!("resolve has unnamed enum type")
592                    }
593                    TypeDefKind::Variant(_) => {
594                        bail!("resolve has unnamed variant type")
595                    }
596                    TypeDefKind::List(ty) => {
597                        self.output.ty("list", TypeKind::BuiltIn);
598                        self.output.generic_args_start();
599                        self.print_type_name(resolve, ty)?;
600                        self.output.generic_args_end();
601                    }
602                    TypeDefKind::Map(key_ty, value_ty) => {
603                        self.output.ty("map", TypeKind::BuiltIn);
604                        self.output.generic_args_start();
605                        self.print_type_name(resolve, key_ty)?;
606                        self.output.str(", ");
607                        self.print_type_name(resolve, value_ty)?;
608                        self.output.generic_args_end();
609                    }
610                    TypeDefKind::FixedLengthList(ty, size) => {
611                        self.output.ty("list", TypeKind::BuiltIn);
612                        self.output.generic_args_start();
613                        self.print_type_name(resolve, ty)?;
614                        self.output.push_str(&format!(", {}", *size));
615                        self.output.generic_args_end();
616                    }
617                    TypeDefKind::Type(ty) => self.print_type_name(resolve, ty)?,
618                    TypeDefKind::Future(ty) => {
619                        if let Some(ty) = ty {
620                            self.output.push_str("future<");
621                            self.print_type_name(resolve, ty)?;
622                            self.output.push_str(">");
623                        } else {
624                            self.output.push_str("future");
625                        }
626                    }
627                    TypeDefKind::Stream(ty) => {
628                        if let Some(ty) = ty {
629                            self.output.push_str("stream<");
630                            self.print_type_name(resolve, ty)?;
631                            self.output.push_str(">");
632                        } else {
633                            self.output.push_str("stream");
634                        }
635                    }
636                    TypeDefKind::Unknown => unreachable!(),
637                }
638            }
639        }
640
641        Ok(())
642    }
643
644    fn print_handle_type(
645        &mut self,
646        resolve: &Resolve,
647        handle: &Handle,
648        force_handle_type_printed: bool,
649    ) -> Result<()> {
650        match handle {
651            Handle::Own(ty) => {
652                let ty = &resolve.types[*ty];
653                if force_handle_type_printed {
654                    self.output.ty("own", TypeKind::BuiltIn);
655                    self.output.generic_args_start();
656                }
657                self.print_name_type(
658                    ty.name
659                        .as_ref()
660                        .ok_or_else(|| anyhow!("unnamed resource type"))?,
661                    TypeKind::Resource,
662                );
663                if force_handle_type_printed {
664                    self.output.generic_args_end();
665                }
666            }
667
668            Handle::Borrow(ty) => {
669                self.output.ty("borrow", TypeKind::BuiltIn);
670                self.output.generic_args_start();
671                let ty = &resolve.types[*ty];
672                self.print_name_type(
673                    ty.name
674                        .as_ref()
675                        .ok_or_else(|| anyhow!("unnamed resource type"))?,
676                    TypeKind::Resource,
677                );
678                self.output.generic_args_end();
679            }
680        }
681
682        Ok(())
683    }
684
685    fn print_tuple_type(&mut self, resolve: &Resolve, tuple: &Tuple) -> Result<()> {
686        self.output.ty("tuple", TypeKind::BuiltIn);
687        self.output.generic_args_start();
688        for (i, ty) in tuple.types.iter().enumerate() {
689            if i > 0 {
690                self.output.str(", ");
691            }
692            self.print_type_name(resolve, ty)?;
693        }
694        self.output.generic_args_end();
695
696        Ok(())
697    }
698
699    fn print_option_type(&mut self, resolve: &Resolve, payload: &Type) -> Result<()> {
700        self.output.ty("option", TypeKind::BuiltIn);
701        self.output.generic_args_start();
702        self.print_type_name(resolve, payload)?;
703        self.output.generic_args_end();
704        Ok(())
705    }
706
707    fn print_result_type(&mut self, resolve: &Resolve, result: &Result_) -> Result<()> {
708        match result {
709            Result_ {
710                ok: Some(ok),
711                err: Some(err),
712            } => {
713                self.output.ty("result", TypeKind::BuiltIn);
714                self.output.generic_args_start();
715                self.print_type_name(resolve, ok)?;
716                self.output.str(", ");
717                self.print_type_name(resolve, err)?;
718                self.output.generic_args_end();
719            }
720            Result_ {
721                ok: None,
722                err: Some(err),
723            } => {
724                self.output.ty("result", TypeKind::BuiltIn);
725                self.output.generic_args_start();
726                self.output.str("_, ");
727                self.print_type_name(resolve, err)?;
728                self.output.generic_args_end();
729            }
730            Result_ {
731                ok: Some(ok),
732                err: None,
733            } => {
734                self.output.ty("result", TypeKind::BuiltIn);
735                self.output.generic_args_start();
736                self.print_type_name(resolve, ok)?;
737                self.output.generic_args_end();
738            }
739            Result_ {
740                ok: None,
741                err: None,
742            } => {
743                self.output.ty("result", TypeKind::BuiltIn);
744            }
745        }
746        Ok(())
747    }
748
749    fn declare_type(&mut self, resolve: &Resolve, ty: &Type) -> Result<()> {
750        match ty {
751            Type::Bool
752            | Type::U8
753            | Type::U16
754            | Type::U32
755            | Type::U64
756            | Type::S8
757            | Type::S16
758            | Type::S32
759            | Type::S64
760            | Type::F32
761            | Type::F64
762            | Type::Char
763            | Type::String
764            | Type::ErrorContext => return Ok(()),
765
766            Type::Id(id) => {
767                let ty = &resolve.types[*id];
768                match &ty.kind {
769                    TypeDefKind::Handle(h) => {
770                        self.declare_handle(resolve, ty.name.as_deref(), h)?
771                    }
772                    TypeDefKind::Resource => panic!("resources should be processed separately"),
773                    TypeDefKind::Record(r) => {
774                        self.declare_record(resolve, ty.name.as_deref(), r)?
775                    }
776                    TypeDefKind::Tuple(t) => self.declare_tuple(resolve, ty.name.as_deref(), t)?,
777                    TypeDefKind::Flags(f) => self.declare_flags(ty.name.as_deref(), f)?,
778                    TypeDefKind::Variant(v) => {
779                        self.declare_variant(resolve, ty.name.as_deref(), v)?
780                    }
781                    TypeDefKind::Option(t) => {
782                        self.declare_option(resolve, ty.name.as_deref(), t)?
783                    }
784                    TypeDefKind::Result(r) => {
785                        self.declare_result(resolve, ty.name.as_deref(), r)?
786                    }
787                    TypeDefKind::Enum(e) => self.declare_enum(ty.name.as_deref(), e)?,
788                    TypeDefKind::List(inner) => {
789                        self.declare_list(resolve, ty.name.as_deref(), inner)?
790                    }
791                    TypeDefKind::Map(key, value) => {
792                        self.declare_map(resolve, ty.name.as_deref(), key, value)?
793                    }
794                    TypeDefKind::FixedLengthList(inner, size) => {
795                        self.declare_fixed_length_list(resolve, ty.name.as_deref(), inner, *size)?
796                    }
797                    TypeDefKind::Type(inner) => match ty.name.as_deref() {
798                        Some(name) => {
799                            self.output.keyword("type");
800                            self.output.str(" ");
801                            self.print_name_type(name, TypeKind::TypeName);
802                            self.output.str(" = ");
803                            self.print_type_name(resolve, inner)?;
804                            self.output.semicolon();
805                        }
806                        None => bail!("unnamed type in document"),
807                    },
808                    TypeDefKind::Future(inner) => {
809                        self.declare_future(resolve, ty.name.as_deref(), inner.as_ref())?
810                    }
811                    TypeDefKind::Stream(inner) => {
812                        self.declare_stream(resolve, ty.name.as_deref(), inner.as_ref())?
813                    }
814                    TypeDefKind::Unknown => unreachable!(),
815                }
816            }
817        }
818        Ok(())
819    }
820
821    fn declare_handle(
822        &mut self,
823        resolve: &Resolve,
824        name: Option<&str>,
825        handle: &Handle,
826    ) -> Result<()> {
827        match name {
828            Some(name) => {
829                self.output.keyword("type");
830                self.output.str(" ");
831                self.print_name_type(name, TypeKind::Resource);
832                self.output.str(" = ");
833                // Note that the `true` here forces owned handles to be printed
834                // as `own<T>`. The purpose of this is because `type a = b`, if
835                // `b` is a resource, is encoded differently as `type a =
836                // own<b>`. By forcing a handle to be printed here it's staying
837                // true to what's in the WIT document.
838                self.print_handle_type(resolve, handle, true)?;
839                self.output.semicolon();
840
841                Ok(())
842            }
843            None => bail!("document has unnamed handle type"),
844        }
845    }
846
847    fn declare_record(
848        &mut self,
849        resolve: &Resolve,
850        name: Option<&str>,
851        record: &Record,
852    ) -> Result<()> {
853        match name {
854            Some(name) => {
855                self.output.keyword("record");
856                self.output.str(" ");
857                self.print_name_type(name, TypeKind::Record);
858                self.output.indent_start();
859                for field in &record.fields {
860                    self.print_docs(&field.docs);
861                    self.print_name_param(&field.name);
862                    self.output.str(": ");
863                    self.print_type_name(resolve, &field.ty)?;
864                    self.output.str(",");
865                    self.output.newline();
866                }
867                self.output.indent_end();
868                Ok(())
869            }
870            None => bail!("document has unnamed record type"),
871        }
872    }
873
874    fn declare_tuple(
875        &mut self,
876        resolve: &Resolve,
877        name: Option<&str>,
878        tuple: &Tuple,
879    ) -> Result<()> {
880        if let Some(name) = name {
881            self.output.keyword("type");
882            self.output.str(" ");
883            self.print_name_type(name, TypeKind::Tuple);
884            self.output.str(" = ");
885            self.print_tuple_type(resolve, tuple)?;
886            self.output.semicolon();
887        }
888        Ok(())
889    }
890
891    fn declare_flags(&mut self, name: Option<&str>, flags: &Flags) -> Result<()> {
892        match name {
893            Some(name) => {
894                self.output.keyword("flags");
895                self.output.str(" ");
896                self.print_name_type(name, TypeKind::Flags);
897                self.output.indent_start();
898                for flag in &flags.flags {
899                    self.print_docs(&flag.docs);
900                    self.print_name_case(&flag.name);
901                    self.output.str(",");
902                    self.output.newline();
903                }
904                self.output.indent_end();
905            }
906            None => bail!("document has unnamed flags type"),
907        }
908        Ok(())
909    }
910
911    fn declare_variant(
912        &mut self,
913        resolve: &Resolve,
914        name: Option<&str>,
915        variant: &Variant,
916    ) -> Result<()> {
917        let name = match name {
918            Some(name) => name,
919            None => bail!("document has unnamed variant type"),
920        };
921        self.output.keyword("variant");
922        self.output.str(" ");
923        self.print_name_type(name, TypeKind::Variant);
924        self.output.indent_start();
925        for case in &variant.cases {
926            self.print_docs(&case.docs);
927            self.print_name_case(&case.name);
928            if let Some(ty) = case.ty {
929                self.output.str("(");
930                self.print_type_name(resolve, &ty)?;
931                self.output.str(")");
932            }
933            self.output.str(",");
934            self.output.newline();
935        }
936        self.output.indent_end();
937        Ok(())
938    }
939
940    fn declare_option(
941        &mut self,
942        resolve: &Resolve,
943        name: Option<&str>,
944        payload: &Type,
945    ) -> Result<()> {
946        if let Some(name) = name {
947            self.output.keyword("type");
948            self.output.str(" ");
949            self.print_name_type(name, TypeKind::Option);
950            self.output.str(" = ");
951            self.print_option_type(resolve, payload)?;
952            self.output.semicolon();
953        }
954        Ok(())
955    }
956
957    fn declare_result(
958        &mut self,
959        resolve: &Resolve,
960        name: Option<&str>,
961        result: &Result_,
962    ) -> Result<()> {
963        if let Some(name) = name {
964            self.output.keyword("type");
965            self.output.str(" ");
966            self.print_name_type(name, TypeKind::Result);
967            self.output.str(" = ");
968            self.print_result_type(resolve, result)?;
969            self.output.semicolon();
970        }
971        Ok(())
972    }
973
974    fn declare_enum(&mut self, name: Option<&str>, enum_: &Enum) -> Result<()> {
975        let name = match name {
976            Some(name) => name,
977            None => bail!("document has unnamed enum type"),
978        };
979        self.output.keyword("enum");
980        self.output.str(" ");
981        self.print_name_type(name, TypeKind::Enum);
982        self.output.indent_start();
983        for case in &enum_.cases {
984            self.print_docs(&case.docs);
985            self.print_name_case(&case.name);
986            self.output.str(",");
987            self.output.newline();
988        }
989        self.output.indent_end();
990        Ok(())
991    }
992
993    fn declare_list(&mut self, resolve: &Resolve, name: Option<&str>, ty: &Type) -> Result<()> {
994        if let Some(name) = name {
995            self.output.keyword("type");
996            self.output.str(" ");
997            self.print_name_type(name, TypeKind::List);
998            self.output.str(" = ");
999            self.output.ty("list", TypeKind::BuiltIn);
1000            self.output.str("<");
1001            self.print_type_name(resolve, ty)?;
1002            self.output.str(">");
1003            self.output.semicolon();
1004            return Ok(());
1005        }
1006
1007        Ok(())
1008    }
1009
1010    fn declare_map(
1011        &mut self,
1012        resolve: &Resolve,
1013        name: Option<&str>,
1014        key_ty: &Type,
1015        value_ty: &Type,
1016    ) -> Result<()> {
1017        if let Some(name) = name {
1018            self.output.keyword("type");
1019            self.output.str(" ");
1020            self.print_name_type(name, TypeKind::Map);
1021            self.output.str(" = ");
1022            self.output.ty("map", TypeKind::BuiltIn);
1023            self.output.str("<");
1024            self.print_type_name(resolve, key_ty)?;
1025            self.output.str(", ");
1026            self.print_type_name(resolve, value_ty)?;
1027            self.output.str(">");
1028            self.output.semicolon();
1029            return Ok(());
1030        }
1031
1032        Ok(())
1033    }
1034
1035    fn declare_fixed_length_list(
1036        &mut self,
1037        resolve: &Resolve,
1038        name: Option<&str>,
1039        ty: &Type,
1040        elements: u32,
1041    ) -> Result<()> {
1042        if let Some(name) = name {
1043            self.output.keyword("type");
1044            self.output.str(" ");
1045            self.print_name_type(name, TypeKind::List);
1046            self.output.str(" = ");
1047            self.output.ty("list", TypeKind::BuiltIn);
1048            self.output.str("<");
1049            self.print_type_name(resolve, ty)?;
1050            self.output.str(&format!(", {elements}"));
1051            self.output.str(">");
1052            self.output.semicolon();
1053            return Ok(());
1054        }
1055
1056        Ok(())
1057    }
1058
1059    fn declare_stream(
1060        &mut self,
1061        resolve: &Resolve,
1062        name: Option<&str>,
1063        ty: Option<&Type>,
1064    ) -> Result<()> {
1065        if let Some(name) = name {
1066            self.output.keyword("type");
1067            self.output.str(" ");
1068            self.print_name_type(name, TypeKind::Stream);
1069            self.output.str(" = ");
1070            self.output.ty("stream", TypeKind::BuiltIn);
1071            if let Some(ty) = ty {
1072                self.output.str("<");
1073                self.print_type_name(resolve, ty)?;
1074                self.output.str(">");
1075            }
1076            self.output.semicolon();
1077        }
1078
1079        Ok(())
1080    }
1081
1082    fn declare_future(
1083        &mut self,
1084        resolve: &Resolve,
1085        name: Option<&str>,
1086        ty: Option<&Type>,
1087    ) -> Result<()> {
1088        if let Some(name) = name {
1089            self.output.keyword("type");
1090            self.output.str(" ");
1091            self.print_name_type(name, TypeKind::Future);
1092            self.output.str(" = ");
1093            self.output.ty("future", TypeKind::BuiltIn);
1094            if let Some(ty) = ty {
1095                self.output.str("<");
1096                self.print_type_name(resolve, ty)?;
1097                self.output.str(">");
1098            }
1099            self.output.semicolon();
1100        }
1101
1102        Ok(())
1103    }
1104
1105    fn escape_name(name: &str) -> Cow<'_, str> {
1106        if is_keyword(name) {
1107            Cow::Owned(format!("%{name}"))
1108        } else {
1109            Cow::Borrowed(name)
1110        }
1111    }
1112
1113    fn print_name_type(&mut self, name: &str, kind: TypeKind) {
1114        self.output.ty(Self::escape_name(name).deref(), kind);
1115    }
1116
1117    fn print_name_param(&mut self, name: &str) {
1118        self.output.param(Self::escape_name(name).deref());
1119    }
1120
1121    fn print_name_case(&mut self, name: &str) {
1122        self.output.case(Self::escape_name(name).deref());
1123    }
1124
1125    fn print_docs(&mut self, docs: &Docs) {
1126        if self.emit_docs {
1127            if let Some(contents) = &docs.contents {
1128                for line in contents.lines() {
1129                    self.output.doc(line);
1130                }
1131            }
1132        }
1133    }
1134
1135    fn print_stability(&mut self, stability: &Stability) {
1136        match stability {
1137            Stability::Unknown => {}
1138            Stability::Stable { since, deprecated } => {
1139                self.output.keyword("@since");
1140                self.output.str("(");
1141                self.output.keyword("version");
1142                self.output.str(" = ");
1143                self.print_name_type(&since.to_string(), TypeKind::VersionAnnotation);
1144                self.output.str(")");
1145                self.output.newline();
1146                if let Some(version) = deprecated {
1147                    self.output.keyword("@deprecated");
1148                    self.output.str("(");
1149                    self.output.keyword("version");
1150                    self.output.str(" = ");
1151                    self.print_name_type(&version.to_string(), TypeKind::VersionAnnotation);
1152                    self.output.str(")");
1153                    self.output.newline();
1154                }
1155            }
1156            Stability::Unstable {
1157                feature,
1158                deprecated,
1159            } => {
1160                self.output.keyword("@unstable");
1161                self.output.str("(");
1162                self.output.keyword("feature");
1163                self.output.str(" = ");
1164                self.output.str(feature);
1165                self.output.str(")");
1166                self.output.newline();
1167                if let Some(version) = deprecated {
1168                    self.output.keyword("@deprecated");
1169                    self.output.str("(");
1170                    self.output.keyword("version");
1171                    self.output.str(" = ");
1172                    self.print_name_type(&version.to_string(), TypeKind::VersionAnnotation);
1173                    self.output.str(")");
1174                    self.output.newline();
1175                }
1176            }
1177        }
1178    }
1179}
1180
1181fn is_keyword(name: &str) -> bool {
1182    matches!(
1183        name,
1184        "use"
1185            | "type"
1186            | "func"
1187            | "u8"
1188            | "u16"
1189            | "u32"
1190            | "u64"
1191            | "s8"
1192            | "s16"
1193            | "s32"
1194            | "s64"
1195            | "f32"
1196            | "f64"
1197            | "float32"
1198            | "float64"
1199            | "char"
1200            | "resource"
1201            | "record"
1202            | "flags"
1203            | "variant"
1204            | "enum"
1205            | "bool"
1206            | "string"
1207            | "option"
1208            | "result"
1209            | "future"
1210            | "stream"
1211            | "list"
1212            | "own"
1213            | "borrow"
1214            | "_"
1215            | "as"
1216            | "from"
1217            | "static"
1218            | "interface"
1219            | "tuple"
1220            | "world"
1221            | "import"
1222            | "export"
1223            | "package"
1224            | "with"
1225            | "include"
1226            | "constructor"
1227            | "error-context"
1228            | "async"
1229            | "map"
1230    )
1231}
1232
1233/// Trait defining visitor methods driven by [`WitPrinter`](WitPrinter).
1234///
1235/// Some methods in this trait have default implementations. These default
1236/// implementations may rely on helper functions that are not
1237/// invoked directly by `WitPrinter`.
1238pub trait Output {
1239    /// Push a string slice into a buffer or an output.
1240    ///
1241    /// Parameter `src` can contain punctuation characters, and must be escaped
1242    /// when outputting to languages like HTML.
1243    /// Helper function used exclusively by the default implementations of trait methods.
1244    /// This function is not called directly by `WitPrinter`.
1245    /// When overriding all the trait methods, users do not need to handle this function.
1246    fn push_str(&mut self, src: &str);
1247
1248    /// Set the appropriate indentation.
1249    ///
1250    /// Helper function used exclusively by the default implementations of trait methods.
1251    /// This function is not called directly by `WitPrinter`.
1252    /// When overriding all the trait methods, users do not need to handle this function.
1253    fn indent_if_needed(&mut self) -> bool;
1254
1255    /// Start of indentation. In WIT this represents ` {\n`.
1256    fn indent_start(&mut self);
1257
1258    /// End of indentation. In WIT this represents `}\n`.
1259    fn indent_end(&mut self);
1260
1261    /// This method is designed to be used only by the default methods of this trait.
1262    /// Called only from the default implementation functions of this trait.
1263    fn indent_and_print(&mut self, src: &str) {
1264        assert!(!src.contains('\n'));
1265        let indented = self.indent_if_needed();
1266        if indented && src.starts_with(' ') {
1267            panic!("cannot add a space at the beginning of a line");
1268        }
1269        self.push_str(src);
1270    }
1271
1272    /// A newline is added.
1273    fn newline(&mut self);
1274
1275    /// A keyword is added. Keywords are hardcoded strings from `[a-z]`, but can start with `@`
1276    /// when printing a [Feature Gate](https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md#feature-gates)
1277    fn keyword(&mut self, src: &str) {
1278        self.indent_and_print(src);
1279    }
1280
1281    /// A type is added.
1282    fn ty(&mut self, src: &str, _kind: TypeKind) {
1283        self.indent_and_print(src);
1284    }
1285
1286    /// A parameter name of a function, record or a named return is added.
1287    fn param(&mut self, src: &str) {
1288        self.indent_and_print(src);
1289    }
1290
1291    /// A case belonging to a variant, enum or flags is added.
1292    fn case(&mut self, src: &str) {
1293        self.indent_and_print(src);
1294    }
1295
1296    /// Generic argument section starts. In WIT this represents the `<` character.
1297    fn generic_args_start(&mut self) {
1298        assert!(
1299            !self.indent_if_needed(),
1300            "`generic_args_start` is never called after newline"
1301        );
1302        self.push_str("<");
1303    }
1304
1305    /// Generic argument section ends. In WIT this represents the '>' character.
1306    fn generic_args_end(&mut self) {
1307        assert!(
1308            !self.indent_if_needed(),
1309            "`generic_args_end` is never called after newline"
1310        );
1311        self.push_str(">");
1312    }
1313
1314    /// Called when a single documentation line is added.
1315    /// The `doc` parameter starts with `///` omitted, and can be an empty string.
1316    fn doc(&mut self, doc: &str) {
1317        assert!(!doc.contains('\n'));
1318        self.indent_if_needed();
1319        self.push_str("///");
1320        if !doc.is_empty() {
1321            self.push_str(" ");
1322            self.push_str(doc);
1323        }
1324        self.newline();
1325    }
1326
1327    /// A semicolon is added.
1328    fn semicolon(&mut self) {
1329        assert!(
1330            !self.indent_if_needed(),
1331            "`semicolon` is never called after newline"
1332        );
1333        self.push_str(";");
1334        self.newline();
1335    }
1336
1337    /// Any string that does not have a specialized function is added.
1338    /// Parameter `src` can contain punctuation characters, and must be escaped
1339    /// when outputting to languages like HTML.
1340    fn str(&mut self, src: &str) {
1341        self.indent_and_print(src);
1342    }
1343}
1344
1345/// Represents the different kinds of types that can be encountered while
1346/// visiting a WIT file.
1347///
1348/// Each variant refers to the name of the respective element (e.g., function, type, or namespace),
1349/// not the entire declaration.
1350#[non_exhaustive]
1351#[derive(Clone, Copy, Debug)]
1352pub enum TypeKind {
1353    /// A built-in type, such as "list" or "option".
1354    BuiltIn,
1355    /// An enumeration type name.
1356    Enum,
1357    /// An error-context type name.
1358    ErrorContext,
1359    /// A flags type name.
1360    Flags,
1361    /// A freestanding function name, not associated with any specific type or namespace.
1362    /// For example, "myfunc" in `myfunc: func() -> string;`.
1363    FunctionFreestanding,
1364    /// A method, associated with a resource.
1365    FunctionMethod,
1366    /// A static function, associated with a resource.
1367    FunctionStatic,
1368    /// A future type name.
1369    Future,
1370    /// An interface declaration name.
1371    InterfaceDeclaration,
1372    /// An interface name when printing a path, for example in `use`.
1373    InterfacePath,
1374    /// A list type name.
1375    List,
1376    /// A map type name.
1377    Map,
1378    /// A namespace declaration.
1379    NamespaceDeclaration,
1380    /// A namespace when printing a path, for example in `use`.
1381    NamespacePath,
1382    /// An option type name.
1383    Option,
1384    /// A package name declaration.
1385    PackageNameDeclaration,
1386    /// A package name when printing a path, for example in `use`.
1387    PackageNamePath,
1388    /// A record type name.
1389    Record,
1390    /// A resource type name.
1391    Resource,
1392    /// A result type name.
1393    Result,
1394    /// A stream type name.
1395    Stream,
1396    /// A tuple type name.
1397    Tuple,
1398    /// A type alias.
1399    TypeAlias,
1400    /// An imported type name.
1401    TypeImport,
1402    /// A user-defined type name.
1403    TypeName,
1404    /// A variant type name.
1405    Variant,
1406    /// A version declaration.
1407    VersionDeclaration,
1408    /// A version when printing a path, for example in `use`.
1409    VersionPath,
1410    /// A version when printing stability annotations, for example in `@since`
1411    VersionAnnotation,
1412    /// A world declaration name.
1413    WorldDeclaration,
1414    /// A fallback for types that do not fit into any other category.
1415    Other,
1416}
1417
1418/// Helper structure to help maintain an indentation level when printing source,
1419/// modeled after the support in `wit-bindgen-core`. Indentation is set to two spaces.
1420#[derive(Default)]
1421pub struct OutputToString {
1422    indent: usize,
1423    output: String,
1424    // set to true after newline, then to false after first item is indented.
1425    needs_indent: bool,
1426}
1427
1428impl Output for OutputToString {
1429    fn push_str(&mut self, src: &str) {
1430        self.output.push_str(src);
1431    }
1432
1433    fn indent_if_needed(&mut self) -> bool {
1434        if self.needs_indent {
1435            for _ in 0..self.indent {
1436                // Indenting by two spaces.
1437                self.output.push_str("  ");
1438            }
1439            self.needs_indent = false;
1440            true
1441        } else {
1442            false
1443        }
1444    }
1445
1446    fn indent_start(&mut self) {
1447        assert!(
1448            !self.needs_indent,
1449            "`indent_start` is never called after newline"
1450        );
1451        self.output.push_str(" {");
1452        self.indent += 1;
1453        self.newline();
1454    }
1455
1456    fn indent_end(&mut self) {
1457        // Note that a `saturating_sub` is used here to prevent a panic
1458        // here in the case of invalid code being generated in debug
1459        // mode. It's typically easier to debug those issues through
1460        // looking at the source code rather than getting a panic.
1461        self.indent = self.indent.saturating_sub(1);
1462        self.indent_if_needed();
1463        self.output.push('}');
1464        self.newline();
1465    }
1466
1467    fn newline(&mut self) {
1468        self.output.push('\n');
1469        self.needs_indent = true;
1470    }
1471}
1472
1473impl From<OutputToString> for String {
1474    fn from(output: OutputToString) -> String {
1475        output.output
1476    }
1477}
1478
1479impl Display for OutputToString {
1480    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1481        self.output.fmt(f)
1482    }
1483}