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 inline item docs
456        if matches!(name, WorldKey::Name(_)) {
457            self.print_docs(match item {
458                WorldItem::Interface { id, .. } => &resolve.interfaces[*id].docs,
459                WorldItem::Function(f) => &f.docs,
460                // Types are handled separately
461                WorldItem::Type { .. } => unreachable!(),
462            });
463        }
464
465        self.print_stability(item.stability(resolve));
466        self.output.keyword(import_or_export_keyword);
467        self.output.str(" ");
468        match name {
469            WorldKey::Name(name) => {
470                match item {
471                    WorldItem::Interface { id, .. } => {
472                        self.print_name_type(name, TypeKind::Other);
473                        self.output.str(": ");
474                        if resolve.interfaces[*id].name.is_none() {
475                            // `import label: interface { .. }` syntax
476                            self.output.keyword("interface");
477                            self.output.indent_start();
478                            self.print_interface(resolve, *id)?;
479                            self.output.indent_end();
480                        } else {
481                            // `import label: use-path;` syntax
482                            self.print_path_to_interface(resolve, *id, cur_pkg)?;
483                            self.output.semicolon();
484                        }
485                    }
486                    WorldItem::Function(f) => {
487                        self.print_name_type(&f.name, TypeKind::Other);
488                        self.output.str(": ");
489                        self.print_function(resolve, f)?;
490                        self.output.semicolon();
491                    }
492                    // Types are handled separately
493                    WorldItem::Type { .. } => unreachable!(),
494                }
495            }
496            WorldKey::Interface(id) => {
497                match item {
498                    WorldItem::Interface { id: id2, .. } => assert_eq!(id, id2),
499                    _ => unreachable!(),
500                }
501                self.print_path_to_interface(resolve, *id, cur_pkg)?;
502                self.output.semicolon();
503            }
504        }
505        Ok(())
506    }
507
508    fn print_path_to_interface(
509        &mut self,
510        resolve: &Resolve,
511        interface: InterfaceId,
512        cur_pkg: PackageId,
513    ) -> Result<()> {
514        let iface = &resolve.interfaces[interface];
515        if iface.package == Some(cur_pkg) {
516            self.print_name_type(iface.name.as_ref().unwrap(), TypeKind::InterfacePath);
517        } else {
518            let pkg = &resolve.packages[iface.package.unwrap()].name;
519            self.print_name_type(&pkg.namespace, TypeKind::NamespacePath);
520            self.output.str(":");
521            self.print_name_type(&pkg.name, TypeKind::PackageNamePath);
522            self.output.str("/");
523            self.print_name_type(iface.name.as_ref().unwrap(), TypeKind::InterfacePath);
524            if let Some(version) = &pkg.version {
525                self.print_name_type(&format!("@{version}"), TypeKind::VersionPath);
526            }
527        }
528        Ok(())
529    }
530
531    /// Print the name of type `ty`.
532    pub fn print_type_name(&mut self, resolve: &Resolve, ty: &Type) -> Result<()> {
533        match ty {
534            Type::Bool => self.output.ty("bool", TypeKind::BuiltIn),
535            Type::U8 => self.output.ty("u8", TypeKind::BuiltIn),
536            Type::U16 => self.output.ty("u16", TypeKind::BuiltIn),
537            Type::U32 => self.output.ty("u32", TypeKind::BuiltIn),
538            Type::U64 => self.output.ty("u64", TypeKind::BuiltIn),
539            Type::S8 => self.output.ty("s8", TypeKind::BuiltIn),
540            Type::S16 => self.output.ty("s16", TypeKind::BuiltIn),
541            Type::S32 => self.output.ty("s32", TypeKind::BuiltIn),
542            Type::S64 => self.output.ty("s64", TypeKind::BuiltIn),
543            Type::F32 => self.output.ty("f32", TypeKind::BuiltIn),
544            Type::F64 => self.output.ty("f64", TypeKind::BuiltIn),
545            Type::Char => self.output.ty("char", TypeKind::BuiltIn),
546            Type::String => self.output.ty("string", TypeKind::BuiltIn),
547            Type::ErrorContext => self.output.ty("error-context", TypeKind::BuiltIn),
548
549            Type::Id(id) => {
550                let ty = &resolve.types[*id];
551                if let Some(name) = &ty.name {
552                    self.print_name_type(name, TypeKind::Other);
553                    return Ok(());
554                }
555
556                match &ty.kind {
557                    TypeDefKind::Handle(h) => {
558                        self.print_handle_type(resolve, h, false)?;
559                    }
560                    TypeDefKind::Resource => {
561                        bail!("resolve has an unnamed resource type");
562                    }
563                    TypeDefKind::Tuple(t) => {
564                        self.print_tuple_type(resolve, t)?;
565                    }
566                    TypeDefKind::Option(t) => {
567                        self.print_option_type(resolve, t)?;
568                    }
569                    TypeDefKind::Result(t) => {
570                        self.print_result_type(resolve, t)?;
571                    }
572                    TypeDefKind::Record(_) => {
573                        bail!("resolve has an unnamed record type");
574                    }
575                    TypeDefKind::Flags(_) => {
576                        bail!("resolve has unnamed flags type")
577                    }
578                    TypeDefKind::Enum(_) => {
579                        bail!("resolve has unnamed enum type")
580                    }
581                    TypeDefKind::Variant(_) => {
582                        bail!("resolve has unnamed variant type")
583                    }
584                    TypeDefKind::List(ty) => {
585                        self.output.ty("list", TypeKind::BuiltIn);
586                        self.output.generic_args_start();
587                        self.print_type_name(resolve, ty)?;
588                        self.output.generic_args_end();
589                    }
590                    TypeDefKind::Map(key_ty, value_ty) => {
591                        self.output.ty("map", TypeKind::BuiltIn);
592                        self.output.generic_args_start();
593                        self.print_type_name(resolve, key_ty)?;
594                        self.output.str(", ");
595                        self.print_type_name(resolve, value_ty)?;
596                        self.output.generic_args_end();
597                    }
598                    TypeDefKind::FixedLengthList(ty, size) => {
599                        self.output.ty("list", TypeKind::BuiltIn);
600                        self.output.generic_args_start();
601                        self.print_type_name(resolve, ty)?;
602                        self.output.push_str(&format!(", {}", *size));
603                        self.output.generic_args_end();
604                    }
605                    TypeDefKind::Type(ty) => self.print_type_name(resolve, ty)?,
606                    TypeDefKind::Future(ty) => {
607                        if let Some(ty) = ty {
608                            self.output.push_str("future<");
609                            self.print_type_name(resolve, ty)?;
610                            self.output.push_str(">");
611                        } else {
612                            self.output.push_str("future");
613                        }
614                    }
615                    TypeDefKind::Stream(ty) => {
616                        if let Some(ty) = ty {
617                            self.output.push_str("stream<");
618                            self.print_type_name(resolve, ty)?;
619                            self.output.push_str(">");
620                        } else {
621                            self.output.push_str("stream");
622                        }
623                    }
624                    TypeDefKind::Unknown => unreachable!(),
625                }
626            }
627        }
628
629        Ok(())
630    }
631
632    fn print_handle_type(
633        &mut self,
634        resolve: &Resolve,
635        handle: &Handle,
636        force_handle_type_printed: bool,
637    ) -> Result<()> {
638        match handle {
639            Handle::Own(ty) => {
640                let ty = &resolve.types[*ty];
641                if force_handle_type_printed {
642                    self.output.ty("own", TypeKind::BuiltIn);
643                    self.output.generic_args_start();
644                }
645                self.print_name_type(
646                    ty.name
647                        .as_ref()
648                        .ok_or_else(|| anyhow!("unnamed resource type"))?,
649                    TypeKind::Resource,
650                );
651                if force_handle_type_printed {
652                    self.output.generic_args_end();
653                }
654            }
655
656            Handle::Borrow(ty) => {
657                self.output.ty("borrow", TypeKind::BuiltIn);
658                self.output.generic_args_start();
659                let ty = &resolve.types[*ty];
660                self.print_name_type(
661                    ty.name
662                        .as_ref()
663                        .ok_or_else(|| anyhow!("unnamed resource type"))?,
664                    TypeKind::Resource,
665                );
666                self.output.generic_args_end();
667            }
668        }
669
670        Ok(())
671    }
672
673    fn print_tuple_type(&mut self, resolve: &Resolve, tuple: &Tuple) -> Result<()> {
674        self.output.ty("tuple", TypeKind::BuiltIn);
675        self.output.generic_args_start();
676        for (i, ty) in tuple.types.iter().enumerate() {
677            if i > 0 {
678                self.output.str(", ");
679            }
680            self.print_type_name(resolve, ty)?;
681        }
682        self.output.generic_args_end();
683
684        Ok(())
685    }
686
687    fn print_option_type(&mut self, resolve: &Resolve, payload: &Type) -> Result<()> {
688        self.output.ty("option", TypeKind::BuiltIn);
689        self.output.generic_args_start();
690        self.print_type_name(resolve, payload)?;
691        self.output.generic_args_end();
692        Ok(())
693    }
694
695    fn print_result_type(&mut self, resolve: &Resolve, result: &Result_) -> Result<()> {
696        match result {
697            Result_ {
698                ok: Some(ok),
699                err: Some(err),
700            } => {
701                self.output.ty("result", TypeKind::BuiltIn);
702                self.output.generic_args_start();
703                self.print_type_name(resolve, ok)?;
704                self.output.str(", ");
705                self.print_type_name(resolve, err)?;
706                self.output.generic_args_end();
707            }
708            Result_ {
709                ok: None,
710                err: Some(err),
711            } => {
712                self.output.ty("result", TypeKind::BuiltIn);
713                self.output.generic_args_start();
714                self.output.str("_, ");
715                self.print_type_name(resolve, err)?;
716                self.output.generic_args_end();
717            }
718            Result_ {
719                ok: Some(ok),
720                err: None,
721            } => {
722                self.output.ty("result", TypeKind::BuiltIn);
723                self.output.generic_args_start();
724                self.print_type_name(resolve, ok)?;
725                self.output.generic_args_end();
726            }
727            Result_ {
728                ok: None,
729                err: None,
730            } => {
731                self.output.ty("result", TypeKind::BuiltIn);
732            }
733        }
734        Ok(())
735    }
736
737    fn declare_type(&mut self, resolve: &Resolve, ty: &Type) -> Result<()> {
738        match ty {
739            Type::Bool
740            | Type::U8
741            | Type::U16
742            | Type::U32
743            | Type::U64
744            | Type::S8
745            | Type::S16
746            | Type::S32
747            | Type::S64
748            | Type::F32
749            | Type::F64
750            | Type::Char
751            | Type::String
752            | Type::ErrorContext => return Ok(()),
753
754            Type::Id(id) => {
755                let ty = &resolve.types[*id];
756                match &ty.kind {
757                    TypeDefKind::Handle(h) => {
758                        self.declare_handle(resolve, ty.name.as_deref(), h)?
759                    }
760                    TypeDefKind::Resource => panic!("resources should be processed separately"),
761                    TypeDefKind::Record(r) => {
762                        self.declare_record(resolve, ty.name.as_deref(), r)?
763                    }
764                    TypeDefKind::Tuple(t) => self.declare_tuple(resolve, ty.name.as_deref(), t)?,
765                    TypeDefKind::Flags(f) => self.declare_flags(ty.name.as_deref(), f)?,
766                    TypeDefKind::Variant(v) => {
767                        self.declare_variant(resolve, ty.name.as_deref(), v)?
768                    }
769                    TypeDefKind::Option(t) => {
770                        self.declare_option(resolve, ty.name.as_deref(), t)?
771                    }
772                    TypeDefKind::Result(r) => {
773                        self.declare_result(resolve, ty.name.as_deref(), r)?
774                    }
775                    TypeDefKind::Enum(e) => self.declare_enum(ty.name.as_deref(), e)?,
776                    TypeDefKind::List(inner) => {
777                        self.declare_list(resolve, ty.name.as_deref(), inner)?
778                    }
779                    TypeDefKind::Map(key, value) => {
780                        self.declare_map(resolve, ty.name.as_deref(), key, value)?
781                    }
782                    TypeDefKind::FixedLengthList(inner, size) => {
783                        self.declare_fixed_length_list(resolve, ty.name.as_deref(), inner, *size)?
784                    }
785                    TypeDefKind::Type(inner) => match ty.name.as_deref() {
786                        Some(name) => {
787                            self.output.keyword("type");
788                            self.output.str(" ");
789                            self.print_name_type(name, TypeKind::TypeName);
790                            self.output.str(" = ");
791                            self.print_type_name(resolve, inner)?;
792                            self.output.semicolon();
793                        }
794                        None => bail!("unnamed type in document"),
795                    },
796                    TypeDefKind::Future(inner) => {
797                        self.declare_future(resolve, ty.name.as_deref(), inner.as_ref())?
798                    }
799                    TypeDefKind::Stream(inner) => {
800                        self.declare_stream(resolve, ty.name.as_deref(), inner.as_ref())?
801                    }
802                    TypeDefKind::Unknown => unreachable!(),
803                }
804            }
805        }
806        Ok(())
807    }
808
809    fn declare_handle(
810        &mut self,
811        resolve: &Resolve,
812        name: Option<&str>,
813        handle: &Handle,
814    ) -> Result<()> {
815        match name {
816            Some(name) => {
817                self.output.keyword("type");
818                self.output.str(" ");
819                self.print_name_type(name, TypeKind::Resource);
820                self.output.str(" = ");
821                // Note that the `true` here forces owned handles to be printed
822                // as `own<T>`. The purpose of this is because `type a = b`, if
823                // `b` is a resource, is encoded differently as `type a =
824                // own<b>`. By forcing a handle to be printed here it's staying
825                // true to what's in the WIT document.
826                self.print_handle_type(resolve, handle, true)?;
827                self.output.semicolon();
828
829                Ok(())
830            }
831            None => bail!("document has unnamed handle type"),
832        }
833    }
834
835    fn declare_record(
836        &mut self,
837        resolve: &Resolve,
838        name: Option<&str>,
839        record: &Record,
840    ) -> Result<()> {
841        match name {
842            Some(name) => {
843                self.output.keyword("record");
844                self.output.str(" ");
845                self.print_name_type(name, TypeKind::Record);
846                self.output.indent_start();
847                for field in &record.fields {
848                    self.print_docs(&field.docs);
849                    self.print_name_param(&field.name);
850                    self.output.str(": ");
851                    self.print_type_name(resolve, &field.ty)?;
852                    self.output.str(",");
853                    self.output.newline();
854                }
855                self.output.indent_end();
856                Ok(())
857            }
858            None => bail!("document has unnamed record type"),
859        }
860    }
861
862    fn declare_tuple(
863        &mut self,
864        resolve: &Resolve,
865        name: Option<&str>,
866        tuple: &Tuple,
867    ) -> Result<()> {
868        if let Some(name) = name {
869            self.output.keyword("type");
870            self.output.str(" ");
871            self.print_name_type(name, TypeKind::Tuple);
872            self.output.str(" = ");
873            self.print_tuple_type(resolve, tuple)?;
874            self.output.semicolon();
875        }
876        Ok(())
877    }
878
879    fn declare_flags(&mut self, name: Option<&str>, flags: &Flags) -> Result<()> {
880        match name {
881            Some(name) => {
882                self.output.keyword("flags");
883                self.output.str(" ");
884                self.print_name_type(name, TypeKind::Flags);
885                self.output.indent_start();
886                for flag in &flags.flags {
887                    self.print_docs(&flag.docs);
888                    self.print_name_case(&flag.name);
889                    self.output.str(",");
890                    self.output.newline();
891                }
892                self.output.indent_end();
893            }
894            None => bail!("document has unnamed flags type"),
895        }
896        Ok(())
897    }
898
899    fn declare_variant(
900        &mut self,
901        resolve: &Resolve,
902        name: Option<&str>,
903        variant: &Variant,
904    ) -> Result<()> {
905        let name = match name {
906            Some(name) => name,
907            None => bail!("document has unnamed variant type"),
908        };
909        self.output.keyword("variant");
910        self.output.str(" ");
911        self.print_name_type(name, TypeKind::Variant);
912        self.output.indent_start();
913        for case in &variant.cases {
914            self.print_docs(&case.docs);
915            self.print_name_case(&case.name);
916            if let Some(ty) = case.ty {
917                self.output.str("(");
918                self.print_type_name(resolve, &ty)?;
919                self.output.str(")");
920            }
921            self.output.str(",");
922            self.output.newline();
923        }
924        self.output.indent_end();
925        Ok(())
926    }
927
928    fn declare_option(
929        &mut self,
930        resolve: &Resolve,
931        name: Option<&str>,
932        payload: &Type,
933    ) -> Result<()> {
934        if let Some(name) = name {
935            self.output.keyword("type");
936            self.output.str(" ");
937            self.print_name_type(name, TypeKind::Option);
938            self.output.str(" = ");
939            self.print_option_type(resolve, payload)?;
940            self.output.semicolon();
941        }
942        Ok(())
943    }
944
945    fn declare_result(
946        &mut self,
947        resolve: &Resolve,
948        name: Option<&str>,
949        result: &Result_,
950    ) -> Result<()> {
951        if let Some(name) = name {
952            self.output.keyword("type");
953            self.output.str(" ");
954            self.print_name_type(name, TypeKind::Result);
955            self.output.str(" = ");
956            self.print_result_type(resolve, result)?;
957            self.output.semicolon();
958        }
959        Ok(())
960    }
961
962    fn declare_enum(&mut self, name: Option<&str>, enum_: &Enum) -> Result<()> {
963        let name = match name {
964            Some(name) => name,
965            None => bail!("document has unnamed enum type"),
966        };
967        self.output.keyword("enum");
968        self.output.str(" ");
969        self.print_name_type(name, TypeKind::Enum);
970        self.output.indent_start();
971        for case in &enum_.cases {
972            self.print_docs(&case.docs);
973            self.print_name_case(&case.name);
974            self.output.str(",");
975            self.output.newline();
976        }
977        self.output.indent_end();
978        Ok(())
979    }
980
981    fn declare_list(&mut self, resolve: &Resolve, name: Option<&str>, ty: &Type) -> Result<()> {
982        if let Some(name) = name {
983            self.output.keyword("type");
984            self.output.str(" ");
985            self.print_name_type(name, TypeKind::List);
986            self.output.str(" = ");
987            self.output.ty("list", TypeKind::BuiltIn);
988            self.output.str("<");
989            self.print_type_name(resolve, ty)?;
990            self.output.str(">");
991            self.output.semicolon();
992            return Ok(());
993        }
994
995        Ok(())
996    }
997
998    fn declare_map(
999        &mut self,
1000        resolve: &Resolve,
1001        name: Option<&str>,
1002        key_ty: &Type,
1003        value_ty: &Type,
1004    ) -> Result<()> {
1005        if let Some(name) = name {
1006            self.output.keyword("type");
1007            self.output.str(" ");
1008            self.print_name_type(name, TypeKind::Map);
1009            self.output.str(" = ");
1010            self.output.ty("map", TypeKind::BuiltIn);
1011            self.output.str("<");
1012            self.print_type_name(resolve, key_ty)?;
1013            self.output.str(", ");
1014            self.print_type_name(resolve, value_ty)?;
1015            self.output.str(">");
1016            self.output.semicolon();
1017            return Ok(());
1018        }
1019
1020        Ok(())
1021    }
1022
1023    fn declare_fixed_length_list(
1024        &mut self,
1025        resolve: &Resolve,
1026        name: Option<&str>,
1027        ty: &Type,
1028        elements: u32,
1029    ) -> Result<()> {
1030        if let Some(name) = name {
1031            self.output.keyword("type");
1032            self.output.str(" ");
1033            self.print_name_type(name, TypeKind::List);
1034            self.output.str(" = ");
1035            self.output.ty("list", TypeKind::BuiltIn);
1036            self.output.str("<");
1037            self.print_type_name(resolve, ty)?;
1038            self.output.str(&format!(", {elements}"));
1039            self.output.str(">");
1040            self.output.semicolon();
1041            return Ok(());
1042        }
1043
1044        Ok(())
1045    }
1046
1047    fn declare_stream(
1048        &mut self,
1049        resolve: &Resolve,
1050        name: Option<&str>,
1051        ty: Option<&Type>,
1052    ) -> Result<()> {
1053        if let Some(name) = name {
1054            self.output.keyword("type");
1055            self.output.str(" ");
1056            self.print_name_type(name, TypeKind::Stream);
1057            self.output.str(" = ");
1058            self.output.ty("stream", TypeKind::BuiltIn);
1059            if let Some(ty) = ty {
1060                self.output.str("<");
1061                self.print_type_name(resolve, ty)?;
1062                self.output.str(">");
1063            }
1064            self.output.semicolon();
1065        }
1066
1067        Ok(())
1068    }
1069
1070    fn declare_future(
1071        &mut self,
1072        resolve: &Resolve,
1073        name: Option<&str>,
1074        ty: Option<&Type>,
1075    ) -> Result<()> {
1076        if let Some(name) = name {
1077            self.output.keyword("type");
1078            self.output.str(" ");
1079            self.print_name_type(name, TypeKind::Future);
1080            self.output.str(" = ");
1081            self.output.ty("future", TypeKind::BuiltIn);
1082            if let Some(ty) = ty {
1083                self.output.str("<");
1084                self.print_type_name(resolve, ty)?;
1085                self.output.str(">");
1086            }
1087            self.output.semicolon();
1088        }
1089
1090        Ok(())
1091    }
1092
1093    fn escape_name(name: &str) -> Cow<'_, str> {
1094        if is_keyword(name) {
1095            Cow::Owned(format!("%{name}"))
1096        } else {
1097            Cow::Borrowed(name)
1098        }
1099    }
1100
1101    fn print_name_type(&mut self, name: &str, kind: TypeKind) {
1102        self.output.ty(Self::escape_name(name).deref(), kind);
1103    }
1104
1105    fn print_name_param(&mut self, name: &str) {
1106        self.output.param(Self::escape_name(name).deref());
1107    }
1108
1109    fn print_name_case(&mut self, name: &str) {
1110        self.output.case(Self::escape_name(name).deref());
1111    }
1112
1113    fn print_docs(&mut self, docs: &Docs) {
1114        if self.emit_docs {
1115            if let Some(contents) = &docs.contents {
1116                for line in contents.lines() {
1117                    self.output.doc(line);
1118                }
1119            }
1120        }
1121    }
1122
1123    fn print_stability(&mut self, stability: &Stability) {
1124        match stability {
1125            Stability::Unknown => {}
1126            Stability::Stable { since, deprecated } => {
1127                self.output.keyword("@since");
1128                self.output.str("(");
1129                self.output.keyword("version");
1130                self.output.str(" = ");
1131                self.print_name_type(&since.to_string(), TypeKind::VersionAnnotation);
1132                self.output.str(")");
1133                self.output.newline();
1134                if let Some(version) = deprecated {
1135                    self.output.keyword("@deprecated");
1136                    self.output.str("(");
1137                    self.output.keyword("version");
1138                    self.output.str(" = ");
1139                    self.print_name_type(&version.to_string(), TypeKind::VersionAnnotation);
1140                    self.output.str(")");
1141                    self.output.newline();
1142                }
1143            }
1144            Stability::Unstable {
1145                feature,
1146                deprecated,
1147            } => {
1148                self.output.keyword("@unstable");
1149                self.output.str("(");
1150                self.output.keyword("feature");
1151                self.output.str(" = ");
1152                self.output.str(feature);
1153                self.output.str(")");
1154                self.output.newline();
1155                if let Some(version) = deprecated {
1156                    self.output.keyword("@deprecated");
1157                    self.output.str("(");
1158                    self.output.keyword("version");
1159                    self.output.str(" = ");
1160                    self.print_name_type(&version.to_string(), TypeKind::VersionAnnotation);
1161                    self.output.str(")");
1162                    self.output.newline();
1163                }
1164            }
1165        }
1166    }
1167}
1168
1169fn is_keyword(name: &str) -> bool {
1170    matches!(
1171        name,
1172        "use"
1173            | "type"
1174            | "func"
1175            | "u8"
1176            | "u16"
1177            | "u32"
1178            | "u64"
1179            | "s8"
1180            | "s16"
1181            | "s32"
1182            | "s64"
1183            | "f32"
1184            | "f64"
1185            | "float32"
1186            | "float64"
1187            | "char"
1188            | "resource"
1189            | "record"
1190            | "flags"
1191            | "variant"
1192            | "enum"
1193            | "bool"
1194            | "string"
1195            | "option"
1196            | "result"
1197            | "future"
1198            | "stream"
1199            | "list"
1200            | "own"
1201            | "borrow"
1202            | "_"
1203            | "as"
1204            | "from"
1205            | "static"
1206            | "interface"
1207            | "tuple"
1208            | "world"
1209            | "import"
1210            | "export"
1211            | "package"
1212            | "with"
1213            | "include"
1214            | "constructor"
1215            | "error-context"
1216            | "async"
1217            | "map"
1218    )
1219}
1220
1221/// Trait defining visitor methods driven by [`WitPrinter`](WitPrinter).
1222///
1223/// Some methods in this trait have default implementations. These default
1224/// implementations may rely on helper functions that are not
1225/// invoked directly by `WitPrinter`.
1226pub trait Output {
1227    /// Push a string slice into a buffer or an output.
1228    ///
1229    /// Parameter `src` can contain punctuation characters, and must be escaped
1230    /// when outputting to languages like HTML.
1231    /// Helper function used exclusively by the default implementations of trait methods.
1232    /// This function is not called directly by `WitPrinter`.
1233    /// When overriding all the trait methods, users do not need to handle this function.
1234    fn push_str(&mut self, src: &str);
1235
1236    /// Set the appropriate indentation.
1237    ///
1238    /// Helper function used exclusively by the default implementations of trait methods.
1239    /// This function is not called directly by `WitPrinter`.
1240    /// When overriding all the trait methods, users do not need to handle this function.
1241    fn indent_if_needed(&mut self) -> bool;
1242
1243    /// Start of indentation. In WIT this represents ` {\n`.
1244    fn indent_start(&mut self);
1245
1246    /// End of indentation. In WIT this represents `}\n`.
1247    fn indent_end(&mut self);
1248
1249    /// This method is designed to be used only by the default methods of this trait.
1250    /// Called only from the default implementation functions of this trait.
1251    fn indent_and_print(&mut self, src: &str) {
1252        assert!(!src.contains('\n'));
1253        let indented = self.indent_if_needed();
1254        if indented && src.starts_with(' ') {
1255            panic!("cannot add a space at the beginning of a line");
1256        }
1257        self.push_str(src);
1258    }
1259
1260    /// A newline is added.
1261    fn newline(&mut self);
1262
1263    /// A keyword is added. Keywords are hardcoded strings from `[a-z]`, but can start with `@`
1264    /// when printing a [Feature Gate](https://github.com/WebAssembly/component-model/blob/main/design/mvp/WIT.md#feature-gates)
1265    fn keyword(&mut self, src: &str) {
1266        self.indent_and_print(src);
1267    }
1268
1269    /// A type is added.
1270    fn ty(&mut self, src: &str, _kind: TypeKind) {
1271        self.indent_and_print(src);
1272    }
1273
1274    /// A parameter name of a function, record or a named return is added.
1275    fn param(&mut self, src: &str) {
1276        self.indent_and_print(src);
1277    }
1278
1279    /// A case belonging to a variant, enum or flags is added.
1280    fn case(&mut self, src: &str) {
1281        self.indent_and_print(src);
1282    }
1283
1284    /// Generic argument section starts. In WIT this represents the `<` character.
1285    fn generic_args_start(&mut self) {
1286        assert!(
1287            !self.indent_if_needed(),
1288            "`generic_args_start` is never called after newline"
1289        );
1290        self.push_str("<");
1291    }
1292
1293    /// Generic argument section ends. In WIT this represents the '>' character.
1294    fn generic_args_end(&mut self) {
1295        assert!(
1296            !self.indent_if_needed(),
1297            "`generic_args_end` is never called after newline"
1298        );
1299        self.push_str(">");
1300    }
1301
1302    /// Called when a single documentation line is added.
1303    /// The `doc` parameter starts with `///` omitted, and can be an empty string.
1304    fn doc(&mut self, doc: &str) {
1305        assert!(!doc.contains('\n'));
1306        self.indent_if_needed();
1307        self.push_str("///");
1308        if !doc.is_empty() {
1309            self.push_str(" ");
1310            self.push_str(doc);
1311        }
1312        self.newline();
1313    }
1314
1315    /// A semicolon is added.
1316    fn semicolon(&mut self) {
1317        assert!(
1318            !self.indent_if_needed(),
1319            "`semicolon` is never called after newline"
1320        );
1321        self.push_str(";");
1322        self.newline();
1323    }
1324
1325    /// Any string that does not have a specialized function is added.
1326    /// Parameter `src` can contain punctuation characters, and must be escaped
1327    /// when outputting to languages like HTML.
1328    fn str(&mut self, src: &str) {
1329        self.indent_and_print(src);
1330    }
1331}
1332
1333/// Represents the different kinds of types that can be encountered while
1334/// visiting a WIT file.
1335///
1336/// Each variant refers to the name of the respective element (e.g., function, type, or namespace),
1337/// not the entire declaration.
1338#[non_exhaustive]
1339#[derive(Clone, Copy, Debug)]
1340pub enum TypeKind {
1341    /// A built-in type, such as "list" or "option".
1342    BuiltIn,
1343    /// An enumeration type name.
1344    Enum,
1345    /// An error-context type name.
1346    ErrorContext,
1347    /// A flags type name.
1348    Flags,
1349    /// A freestanding function name, not associated with any specific type or namespace.
1350    /// For example, "myfunc" in `myfunc: func() -> string;`.
1351    FunctionFreestanding,
1352    /// A method, associated with a resource.
1353    FunctionMethod,
1354    /// A static function, associated with a resource.
1355    FunctionStatic,
1356    /// A future type name.
1357    Future,
1358    /// An interface declaration name.
1359    InterfaceDeclaration,
1360    /// An interface name when printing a path, for example in `use`.
1361    InterfacePath,
1362    /// A list type name.
1363    List,
1364    /// A map type name.
1365    Map,
1366    /// A namespace declaration.
1367    NamespaceDeclaration,
1368    /// A namespace when printing a path, for example in `use`.
1369    NamespacePath,
1370    /// An option type name.
1371    Option,
1372    /// A package name declaration.
1373    PackageNameDeclaration,
1374    /// A package name when printing a path, for example in `use`.
1375    PackageNamePath,
1376    /// A record type name.
1377    Record,
1378    /// A resource type name.
1379    Resource,
1380    /// A result type name.
1381    Result,
1382    /// A stream type name.
1383    Stream,
1384    /// A tuple type name.
1385    Tuple,
1386    /// A type alias.
1387    TypeAlias,
1388    /// An imported type name.
1389    TypeImport,
1390    /// A user-defined type name.
1391    TypeName,
1392    /// A variant type name.
1393    Variant,
1394    /// A version declaration.
1395    VersionDeclaration,
1396    /// A version when printing a path, for example in `use`.
1397    VersionPath,
1398    /// A version when printing stability annotations, for example in `@since`
1399    VersionAnnotation,
1400    /// A world declaration name.
1401    WorldDeclaration,
1402    /// A fallback for types that do not fit into any other category.
1403    Other,
1404}
1405
1406/// Helper structure to help maintain an indentation level when printing source,
1407/// modeled after the support in `wit-bindgen-core`. Indentation is set to two spaces.
1408#[derive(Default)]
1409pub struct OutputToString {
1410    indent: usize,
1411    output: String,
1412    // set to true after newline, then to false after first item is indented.
1413    needs_indent: bool,
1414}
1415
1416impl Output for OutputToString {
1417    fn push_str(&mut self, src: &str) {
1418        self.output.push_str(src);
1419    }
1420
1421    fn indent_if_needed(&mut self) -> bool {
1422        if self.needs_indent {
1423            for _ in 0..self.indent {
1424                // Indenting by two spaces.
1425                self.output.push_str("  ");
1426            }
1427            self.needs_indent = false;
1428            true
1429        } else {
1430            false
1431        }
1432    }
1433
1434    fn indent_start(&mut self) {
1435        assert!(
1436            !self.needs_indent,
1437            "`indent_start` is never called after newline"
1438        );
1439        self.output.push_str(" {");
1440        self.indent += 1;
1441        self.newline();
1442    }
1443
1444    fn indent_end(&mut self) {
1445        // Note that a `saturating_sub` is used here to prevent a panic
1446        // here in the case of invalid code being generated in debug
1447        // mode. It's typically easier to debug those issues through
1448        // looking at the source code rather than getting a panic.
1449        self.indent = self.indent.saturating_sub(1);
1450        self.indent_if_needed();
1451        self.output.push('}');
1452        self.newline();
1453    }
1454
1455    fn newline(&mut self) {
1456        self.output.push('\n');
1457        self.needs_indent = true;
1458    }
1459}
1460
1461impl From<OutputToString> for String {
1462    fn from(output: OutputToString) -> String {
1463        output.output
1464    }
1465}
1466
1467impl Display for OutputToString {
1468    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1469        self.output.fmt(f)
1470    }
1471}