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