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