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