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