wit_component/
printing.rs

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