1use anyhow::{Result, anyhow, bail};
2use std::borrow::Cow;
3use std::collections::HashMap;
4use std::fmt::Display;
5use std::mem;
6use std::ops::Deref;
7use wit_parser::*;
8
9pub struct WitPrinter<O: Output = OutputToString> {
11 pub output: O,
13
14 any_items: bool,
17
18 emit_docs: bool,
20}
21
22impl Default for WitPrinter {
23 fn default() -> Self {
24 Self::new(OutputToString::default())
25 }
26}
27
28impl<O: Output> WitPrinter<O> {
29 pub fn new(output: O) -> Self {
31 Self {
32 output,
33 any_items: false,
34 emit_docs: true,
35 }
36 }
37
38 pub fn print(&mut self, resolve: &Resolve, pkg: PackageId, nested: &[PackageId]) -> Result<()> {
43 self.print_package(resolve, pkg, true)?;
44 for (i, pkg_id) in nested.iter().enumerate() {
45 if i > 0 {
46 self.output.newline();
47 self.output.newline();
48 }
49 self.print_package(resolve, *pkg_id, false)?;
50 }
51 Ok(())
52 }
53
54 pub fn emit_docs(&mut self, enabled: bool) -> &mut Self {
58 self.emit_docs = enabled;
59 self
60 }
61
62 pub fn print_package(
66 &mut self,
67 resolve: &Resolve,
68 pkg: PackageId,
69 is_main: bool,
70 ) -> Result<()> {
71 let pkg = &resolve.packages[pkg];
72 self.print_package_outer(pkg)?;
73
74 if is_main {
75 self.output.semicolon();
76 self.output.newline();
77 } else {
78 self.output.indent_start();
79 }
80
81 for (name, id) in pkg.interfaces.iter() {
82 self.print_interface_outer(resolve, *id, name)?;
83 self.output.indent_start();
84 self.print_interface(resolve, *id)?;
85 self.output.indent_end();
86 if is_main {
87 self.output.newline();
88 }
89 }
90
91 for (name, id) in pkg.worlds.iter() {
92 self.print_docs(&resolve.worlds[*id].docs);
93 self.print_stability(&resolve.worlds[*id].stability);
94 self.output.keyword("world");
95 self.output.str(" ");
96 self.print_name_type(name, TypeKind::WorldDeclaration);
97 self.output.indent_start();
98 self.print_world(resolve, *id)?;
99 self.output.indent_end();
100 }
101 if !is_main {
102 self.output.indent_end();
103 }
104 Ok(())
105 }
106
107 pub fn print_package_outer(&mut self, pkg: &Package) -> Result<()> {
110 self.print_docs(&pkg.docs);
111 self.output.keyword("package");
112 self.output.str(" ");
113 self.print_name_type(&pkg.name.namespace, TypeKind::NamespaceDeclaration);
114 self.output.str(":");
115 self.print_name_type(&pkg.name.name, TypeKind::PackageNameDeclaration);
116 if let Some(version) = &pkg.name.version {
117 self.print_name_type(&format!("@{version}"), TypeKind::VersionDeclaration);
118 }
119 Ok(())
120 }
121
122 fn new_item(&mut self) {
123 if self.any_items {
124 self.output.newline();
125 }
126 self.any_items = true;
127 }
128
129 pub fn print_interface_outer(
132 &mut self,
133 resolve: &Resolve,
134 id: InterfaceId,
135 name: &str,
136 ) -> Result<()> {
137 self.print_docs(&resolve.interfaces[id].docs);
138 self.print_stability(&resolve.interfaces[id].stability);
139 self.output.keyword("interface");
140 self.output.str(" ");
141 self.print_name_type(name, TypeKind::InterfaceDeclaration);
142 Ok(())
143 }
144
145 pub fn print_interface(&mut self, resolve: &Resolve, id: InterfaceId) -> Result<()> {
147 let prev_items = mem::replace(&mut self.any_items, false);
148 let interface = &resolve.interfaces[id];
149
150 let mut resource_funcs = HashMap::new();
151 let mut freestanding = Vec::new();
152 for (_, func) in interface.functions.iter() {
153 if let Some(id) = func.kind.resource() {
154 resource_funcs.entry(id).or_insert(Vec::new()).push(func);
155 } else {
156 freestanding.push(func);
157 }
158 }
159
160 self.print_types(
161 resolve,
162 TypeOwner::Interface(id),
163 interface
164 .types
165 .iter()
166 .map(|(name, id)| (name.as_str(), *id)),
167 &resource_funcs,
168 )?;
169
170 for func in freestanding {
171 self.new_item();
172 self.print_docs(&func.docs);
173 self.print_stability(&func.stability);
174 self.print_external_id(func.external_id.as_deref());
175 self.print_name_type(func.item_name(), TypeKind::FunctionFreestanding);
176 self.output.str(": ");
177 self.print_function(resolve, func)?;
178 self.output.semicolon();
179 }
180
181 self.any_items = prev_items;
182
183 Ok(())
184 }
185
186 pub fn print_types<'a>(
188 &mut self,
189 resolve: &Resolve,
190 owner: TypeOwner,
191 types: impl Iterator<Item = (&'a str, TypeId)>,
192 resource_funcs: &HashMap<TypeId, Vec<&Function>>,
193 ) -> Result<()> {
194 let mut types_to_declare = Vec::new();
197 let mut types_to_import: Vec<(_, &TypeDef, Vec<_>)> = Vec::new();
198 for (name, ty_id) in types {
199 let ty = &resolve.types[ty_id];
200
201 if let TypeDefKind::Type(Type::Id(other)) = ty.kind {
204 let other = &resolve.types[other];
205 match other.owner {
206 TypeOwner::None => {}
207
208 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
218 if let Some((prev_owner, prev_ty, list)) = types_to_import.last_mut() {
222 if *prev_owner == other_owner
223 && ty.stability == prev_ty.stability
224 && ty.external_id == prev_ty.external_id
225 {
226 list.push((name, other_name));
227 continue;
228 }
229 }
230 types_to_import.push((other_owner, ty, vec![(name, other_name)]));
231 continue;
232 }
233 _ => {}
234 }
235 }
236
237 types_to_declare.push(ty_id);
238 }
239
240 let my_pkg = match owner {
242 TypeOwner::Interface(id) => resolve.interfaces[id].package.unwrap(),
243 TypeOwner::World(id) => resolve.worlds[id].package.unwrap(),
244 TypeOwner::None => unreachable!(),
245 };
246 for (owner, ty, tys) in types_to_import {
247 self.any_items = true;
248 self.print_stability(&ty.stability);
249 self.print_external_id(ty.external_id.as_deref());
250 self.output.keyword("use");
251 self.output.str(" ");
252 let id = match owner {
253 TypeOwner::Interface(id) => id,
254 _ => unreachable!(),
257 };
258 self.print_path_to_interface(resolve, id, my_pkg)?;
259 self.output.str(".{"); for (i, (my_name, other_name)) in tys.into_iter().enumerate() {
261 if i > 0 {
262 self.output.str(", ");
263 }
264 if my_name == other_name {
265 self.print_name_type(my_name, TypeKind::TypeImport);
266 } else {
267 self.print_name_type(other_name, TypeKind::TypeImport);
268 self.output.str(" ");
269 self.output.keyword("as");
270 self.output.str(" ");
271 self.print_name_type(my_name, TypeKind::TypeAlias);
272 }
273 }
274 self.output.str("}"); self.output.semicolon();
276 }
277
278 for id in types_to_declare {
279 self.new_item();
280 self.print_docs(&resolve.types[id].docs);
281 self.print_stability(&resolve.types[id].stability);
282 self.print_external_id(resolve.types[id].external_id.as_deref());
283 match resolve.types[id].kind {
284 TypeDefKind::Resource => self.print_resource(
285 resolve,
286 id,
287 resource_funcs.get(&id).unwrap_or(&Vec::new()),
288 )?,
289 _ => self.declare_type(resolve, &Type::Id(id))?,
290 }
291 }
292
293 Ok(())
294 }
295
296 fn print_resource(&mut self, resolve: &Resolve, id: TypeId, funcs: &[&Function]) -> Result<()> {
297 let ty = &resolve.types[id];
298 self.output.ty("resource", TypeKind::BuiltIn);
299 self.output.str(" ");
300 self.print_name_type(
301 ty.name.as_ref().expect("resources must be named"),
302 TypeKind::Resource,
303 );
304 if funcs.is_empty() {
305 self.output.semicolon();
306 return Ok(());
307 }
308 self.output.indent_start();
309 for func in funcs {
310 self.print_docs(&func.docs);
311 self.print_stability(&func.stability);
312 self.print_external_id(func.external_id.as_deref());
313
314 match &func.kind {
315 FunctionKind::Constructor(_) => {}
316 FunctionKind::Method(_) | FunctionKind::AsyncMethod(_) => {
317 self.print_name_type(func.item_name(), TypeKind::FunctionMethod);
318 self.output.str(": ");
319 }
320 FunctionKind::Static(_) | FunctionKind::AsyncStatic(_) => {
321 self.print_name_type(func.item_name(), TypeKind::FunctionStatic);
322 self.output.str(": ");
323 self.output.keyword("static");
324 self.output.str(" ");
325 }
326 FunctionKind::Freestanding | FunctionKind::AsyncFreestanding => unreachable!(),
327 }
328 self.print_function(resolve, func)?;
329 self.output.semicolon();
330 }
331 self.output.indent_end();
332
333 Ok(())
334 }
335
336 fn print_function(&mut self, resolve: &Resolve, func: &Function) -> Result<()> {
337 match &func.kind {
339 FunctionKind::AsyncFreestanding
340 | FunctionKind::AsyncMethod(_)
341 | FunctionKind::AsyncStatic(_) => {
342 self.output.keyword("async");
343 self.output.str(" ");
344 }
345 _ => {}
346 }
347
348 match &func.kind {
350 FunctionKind::Constructor(_) => {
351 self.output.keyword("constructor");
352 self.output.str("(");
353 }
354 FunctionKind::Freestanding
355 | FunctionKind::AsyncFreestanding
356 | FunctionKind::Method(_)
357 | FunctionKind::AsyncMethod(_)
358 | FunctionKind::Static(_)
359 | FunctionKind::AsyncStatic(_) => {
360 self.output.keyword("func");
361 self.output.str("(");
362 }
363 }
364
365 let params_to_skip = match &func.kind {
367 FunctionKind::Method(_) | FunctionKind::AsyncMethod(_) => 1,
368 _ => 0,
369 };
370 for (i, param) in func.params.iter().skip(params_to_skip).enumerate() {
371 if i > 0 {
372 self.output.str(", ");
373 }
374 self.print_name_param(¶m.name);
375 self.output.str(": ");
376 self.print_type_name(resolve, ¶m.ty)?;
377 }
378 self.output.str(")");
379
380 if func.is_constructor_shorthand(resolve) {
382 return Ok(());
383 }
384
385 if let Some(ty) = &func.result {
386 self.output.str(" -> ");
387 self.print_type_name(resolve, ty)?;
388 }
389 Ok(())
390 }
391
392 fn print_world(&mut self, resolve: &Resolve, id: WorldId) -> Result<()> {
412 let prev_items = mem::replace(&mut self.any_items, false);
413 let world = &resolve.worlds[id];
414 let pkgid = world.package.unwrap();
415 let mut types = Vec::new();
416 let mut resource_funcs = HashMap::new();
417 let mut function_imports_to_print = Vec::new();
418 for (name, import) in world.imports.iter() {
419 match import {
420 WorldItem::Type { id, .. } => match name {
421 WorldKey::Name(s) => types.push((s.as_str(), *id)),
422 WorldKey::Interface(_) => unreachable!(),
423 },
424 _ => {
425 if let WorldItem::Function(f) = import {
426 if let Some(id) = f.kind.resource() {
427 resource_funcs.entry(id).or_insert(Vec::new()).push(f);
428 continue;
429 }
430 function_imports_to_print.push((name, import));
431 continue;
432 }
433 self.print_world_item(resolve, name, import, pkgid, "import")?;
434 self.any_items = true;
438 }
439 }
440 }
441 self.print_types(
442 resolve,
443 TypeOwner::World(id),
444 types.into_iter(),
445 &resource_funcs,
446 )?;
447
448 for (name, import) in function_imports_to_print {
449 self.print_world_item(resolve, name, import, pkgid, "import")?;
450 self.any_items = true;
451 }
452 if !world.exports.is_empty() {
453 self.new_item();
454 }
455 for (name, export) in world.exports.iter() {
456 self.print_world_item(resolve, name, export, pkgid, "export")?;
457 }
458 self.any_items = prev_items;
459 Ok(())
460 }
461
462 fn print_world_item(
463 &mut self,
464 resolve: &Resolve,
465 name: &WorldKey,
466 item: &WorldItem,
467 cur_pkg: PackageId,
468 import_or_export_keyword: &str,
469 ) -> Result<()> {
470 let docs = match item {
475 WorldItem::Interface { id, docs, .. } => {
476 if docs.contents.is_some() {
477 Some(docs)
478 } else if matches!(name, WorldKey::Name(_)) {
479 Some(&resolve.interfaces[*id].docs)
480 } else {
481 None
482 }
483 }
484 WorldItem::Function(f) => Some(&f.docs),
485 WorldItem::Type { .. } => unreachable!(),
487 };
488 if let Some(docs) = docs {
489 self.print_docs(docs);
490 }
491
492 self.print_stability(item.stability(resolve));
493 self.print_external_id(resolve.external_id_value(name, item).as_deref());
494 self.output.keyword(import_or_export_keyword);
495 self.output.str(" ");
496 match name {
497 WorldKey::Name(name) => {
498 match item {
499 WorldItem::Interface { id, .. } => {
500 self.print_name_type(name, TypeKind::Other);
501 self.output.str(": ");
502 if resolve.interfaces[*id].name.is_none() {
503 self.output.keyword("interface");
505 self.output.indent_start();
506 self.print_interface(resolve, *id)?;
507 self.output.indent_end();
508 } else {
509 self.print_path_to_interface(resolve, *id, cur_pkg)?;
511 self.output.semicolon();
512 }
513 }
514 WorldItem::Function(f) => {
515 self.print_name_type(&f.name, TypeKind::Other);
516 self.output.str(": ");
517 self.print_function(resolve, f)?;
518 self.output.semicolon();
519 }
520 WorldItem::Type { .. } => unreachable!(),
522 }
523 }
524 WorldKey::Interface(id) => {
525 match item {
526 WorldItem::Interface { id: id2, .. } => assert_eq!(id, id2),
527 _ => unreachable!(),
528 }
529 self.print_path_to_interface(resolve, *id, cur_pkg)?;
530 self.output.semicolon();
531 }
532 }
533 Ok(())
534 }
535
536 fn print_path_to_interface(
537 &mut self,
538 resolve: &Resolve,
539 interface: InterfaceId,
540 cur_pkg: PackageId,
541 ) -> Result<()> {
542 let iface = &resolve.interfaces[interface];
543 if iface.package == Some(cur_pkg) {
544 self.print_name_type(iface.name.as_ref().unwrap(), TypeKind::InterfacePath);
545 } else {
546 let pkg = &resolve.packages[iface.package.unwrap()].name;
547 self.print_name_type(&pkg.namespace, TypeKind::NamespacePath);
548 self.output.str(":");
549 self.print_name_type(&pkg.name, TypeKind::PackageNamePath);
550 self.output.str("/");
551 self.print_name_type(iface.name.as_ref().unwrap(), TypeKind::InterfacePath);
552 if let Some(version) = &pkg.version {
553 self.print_name_type(&format!("@{version}"), TypeKind::VersionPath);
554 }
555 }
556 Ok(())
557 }
558
559 pub fn print_type_name(&mut self, resolve: &Resolve, ty: &Type) -> Result<()> {
561 match ty {
562 Type::Bool => self.output.ty("bool", TypeKind::BuiltIn),
563 Type::U8 => self.output.ty("u8", TypeKind::BuiltIn),
564 Type::U16 => self.output.ty("u16", TypeKind::BuiltIn),
565 Type::U32 => self.output.ty("u32", TypeKind::BuiltIn),
566 Type::U64 => self.output.ty("u64", TypeKind::BuiltIn),
567 Type::S8 => self.output.ty("s8", TypeKind::BuiltIn),
568 Type::S16 => self.output.ty("s16", TypeKind::BuiltIn),
569 Type::S32 => self.output.ty("s32", TypeKind::BuiltIn),
570 Type::S64 => self.output.ty("s64", TypeKind::BuiltIn),
571 Type::F32 => self.output.ty("f32", TypeKind::BuiltIn),
572 Type::F64 => self.output.ty("f64", TypeKind::BuiltIn),
573 Type::Char => self.output.ty("char", TypeKind::BuiltIn),
574 Type::String => self.output.ty("string", TypeKind::BuiltIn),
575 Type::ErrorContext => self.output.ty("error-context", TypeKind::BuiltIn),
576
577 Type::Id(id) => {
578 let ty = &resolve.types[*id];
579 if let Some(name) = &ty.name {
580 self.print_name_type(name, TypeKind::Other);
581 return Ok(());
582 }
583
584 match &ty.kind {
585 TypeDefKind::Handle(h) => {
586 self.print_handle_type(resolve, h, false)?;
587 }
588 TypeDefKind::Resource => {
589 bail!("resolve has an unnamed resource type");
590 }
591 TypeDefKind::Tuple(t) => {
592 self.print_tuple_type(resolve, t)?;
593 }
594 TypeDefKind::Option(t) => {
595 self.print_option_type(resolve, t)?;
596 }
597 TypeDefKind::Result(t) => {
598 self.print_result_type(resolve, t)?;
599 }
600 TypeDefKind::Record(_) => {
601 bail!("resolve has an unnamed record type");
602 }
603 TypeDefKind::Flags(_) => {
604 bail!("resolve has unnamed flags type")
605 }
606 TypeDefKind::Enum(_) => {
607 bail!("resolve has unnamed enum type")
608 }
609 TypeDefKind::Variant(_) => {
610 bail!("resolve has unnamed variant type")
611 }
612 TypeDefKind::List(ty) => {
613 self.output.ty("list", TypeKind::BuiltIn);
614 self.output.generic_args_start();
615 self.print_type_name(resolve, ty)?;
616 self.output.generic_args_end();
617 }
618 TypeDefKind::Map(key_ty, value_ty) => {
619 self.output.ty("map", TypeKind::BuiltIn);
620 self.output.generic_args_start();
621 self.print_type_name(resolve, key_ty)?;
622 self.output.str(", ");
623 self.print_type_name(resolve, value_ty)?;
624 self.output.generic_args_end();
625 }
626 TypeDefKind::FixedLengthList(ty, size) => {
627 self.output.ty("list", TypeKind::BuiltIn);
628 self.output.generic_args_start();
629 self.print_type_name(resolve, ty)?;
630 self.output.push_str(&format!(", {}", *size));
631 self.output.generic_args_end();
632 }
633 TypeDefKind::Type(ty) => self.print_type_name(resolve, ty)?,
634 TypeDefKind::Future(ty) => {
635 if let Some(ty) = ty {
636 self.output.push_str("future<");
637 self.print_type_name(resolve, ty)?;
638 self.output.push_str(">");
639 } else {
640 self.output.push_str("future");
641 }
642 }
643 TypeDefKind::Stream(ty) => {
644 if let Some(ty) = ty {
645 self.output.push_str("stream<");
646 self.print_type_name(resolve, ty)?;
647 self.output.push_str(">");
648 } else {
649 self.output.push_str("stream");
650 }
651 }
652 TypeDefKind::Unknown => unreachable!(),
653 }
654 }
655 }
656
657 Ok(())
658 }
659
660 fn print_handle_type(
661 &mut self,
662 resolve: &Resolve,
663 handle: &Handle,
664 force_handle_type_printed: bool,
665 ) -> Result<()> {
666 match handle {
667 Handle::Own(ty) => {
668 let ty = &resolve.types[*ty];
669 if force_handle_type_printed {
670 self.output.ty("own", TypeKind::BuiltIn);
671 self.output.generic_args_start();
672 }
673 self.print_name_type(
674 ty.name
675 .as_ref()
676 .ok_or_else(|| anyhow!("unnamed resource type"))?,
677 TypeKind::Resource,
678 );
679 if force_handle_type_printed {
680 self.output.generic_args_end();
681 }
682 }
683
684 Handle::Borrow(ty) => {
685 self.output.ty("borrow", TypeKind::BuiltIn);
686 self.output.generic_args_start();
687 let ty = &resolve.types[*ty];
688 self.print_name_type(
689 ty.name
690 .as_ref()
691 .ok_or_else(|| anyhow!("unnamed resource type"))?,
692 TypeKind::Resource,
693 );
694 self.output.generic_args_end();
695 }
696 }
697
698 Ok(())
699 }
700
701 fn print_tuple_type(&mut self, resolve: &Resolve, tuple: &Tuple) -> Result<()> {
702 self.output.ty("tuple", TypeKind::BuiltIn);
703 self.output.generic_args_start();
704 for (i, ty) in tuple.types.iter().enumerate() {
705 if i > 0 {
706 self.output.str(", ");
707 }
708 self.print_type_name(resolve, ty)?;
709 }
710 self.output.generic_args_end();
711
712 Ok(())
713 }
714
715 fn print_option_type(&mut self, resolve: &Resolve, payload: &Type) -> Result<()> {
716 self.output.ty("option", TypeKind::BuiltIn);
717 self.output.generic_args_start();
718 self.print_type_name(resolve, payload)?;
719 self.output.generic_args_end();
720 Ok(())
721 }
722
723 fn print_result_type(&mut self, resolve: &Resolve, result: &Result_) -> Result<()> {
724 match result {
725 Result_ {
726 ok: Some(ok),
727 err: Some(err),
728 } => {
729 self.output.ty("result", TypeKind::BuiltIn);
730 self.output.generic_args_start();
731 self.print_type_name(resolve, ok)?;
732 self.output.str(", ");
733 self.print_type_name(resolve, err)?;
734 self.output.generic_args_end();
735 }
736 Result_ {
737 ok: None,
738 err: Some(err),
739 } => {
740 self.output.ty("result", TypeKind::BuiltIn);
741 self.output.generic_args_start();
742 self.output.str("_, ");
743 self.print_type_name(resolve, err)?;
744 self.output.generic_args_end();
745 }
746 Result_ {
747 ok: Some(ok),
748 err: None,
749 } => {
750 self.output.ty("result", TypeKind::BuiltIn);
751 self.output.generic_args_start();
752 self.print_type_name(resolve, ok)?;
753 self.output.generic_args_end();
754 }
755 Result_ {
756 ok: None,
757 err: None,
758 } => {
759 self.output.ty("result", TypeKind::BuiltIn);
760 }
761 }
762 Ok(())
763 }
764
765 fn declare_type(&mut self, resolve: &Resolve, ty: &Type) -> Result<()> {
766 match ty {
767 Type::Bool
768 | Type::U8
769 | Type::U16
770 | Type::U32
771 | Type::U64
772 | Type::S8
773 | Type::S16
774 | Type::S32
775 | Type::S64
776 | Type::F32
777 | Type::F64
778 | Type::Char
779 | Type::String
780 | Type::ErrorContext => return Ok(()),
781
782 Type::Id(id) => {
783 let ty = &resolve.types[*id];
784 match &ty.kind {
785 TypeDefKind::Handle(h) => {
786 self.declare_handle(resolve, ty.name.as_deref(), h)?
787 }
788 TypeDefKind::Resource => panic!("resources should be processed separately"),
789 TypeDefKind::Record(r) => {
790 self.declare_record(resolve, ty.name.as_deref(), r)?
791 }
792 TypeDefKind::Tuple(t) => self.declare_tuple(resolve, ty.name.as_deref(), t)?,
793 TypeDefKind::Flags(f) => self.declare_flags(ty.name.as_deref(), f)?,
794 TypeDefKind::Variant(v) => {
795 self.declare_variant(resolve, ty.name.as_deref(), v)?
796 }
797 TypeDefKind::Option(t) => {
798 self.declare_option(resolve, ty.name.as_deref(), t)?
799 }
800 TypeDefKind::Result(r) => {
801 self.declare_result(resolve, ty.name.as_deref(), r)?
802 }
803 TypeDefKind::Enum(e) => self.declare_enum(ty.name.as_deref(), e)?,
804 TypeDefKind::List(inner) => {
805 self.declare_list(resolve, ty.name.as_deref(), inner)?
806 }
807 TypeDefKind::Map(key, value) => {
808 self.declare_map(resolve, ty.name.as_deref(), key, value)?
809 }
810 TypeDefKind::FixedLengthList(inner, size) => {
811 self.declare_fixed_length_list(resolve, ty.name.as_deref(), inner, *size)?
812 }
813 TypeDefKind::Type(inner) => match ty.name.as_deref() {
814 Some(name) => {
815 self.output.keyword("type");
816 self.output.str(" ");
817 self.print_name_type(name, TypeKind::TypeName);
818 self.output.str(" = ");
819 self.print_type_name(resolve, inner)?;
820 self.output.semicolon();
821 }
822 None => bail!("unnamed type in document"),
823 },
824 TypeDefKind::Future(inner) => {
825 self.declare_future(resolve, ty.name.as_deref(), inner.as_ref())?
826 }
827 TypeDefKind::Stream(inner) => {
828 self.declare_stream(resolve, ty.name.as_deref(), inner.as_ref())?
829 }
830 TypeDefKind::Unknown => unreachable!(),
831 }
832 }
833 }
834 Ok(())
835 }
836
837 fn declare_handle(
838 &mut self,
839 resolve: &Resolve,
840 name: Option<&str>,
841 handle: &Handle,
842 ) -> Result<()> {
843 match name {
844 Some(name) => {
845 self.output.keyword("type");
846 self.output.str(" ");
847 self.print_name_type(name, TypeKind::Resource);
848 self.output.str(" = ");
849 self.print_handle_type(resolve, handle, true)?;
855 self.output.semicolon();
856
857 Ok(())
858 }
859 None => bail!("document has unnamed handle type"),
860 }
861 }
862
863 fn declare_record(
864 &mut self,
865 resolve: &Resolve,
866 name: Option<&str>,
867 record: &Record,
868 ) -> Result<()> {
869 match name {
870 Some(name) => {
871 self.output.keyword("record");
872 self.output.str(" ");
873 self.print_name_type(name, TypeKind::Record);
874 self.output.indent_start();
875 for field in &record.fields {
876 self.print_docs(&field.docs);
877 self.print_name_param(&field.name);
878 self.output.str(": ");
879 self.print_type_name(resolve, &field.ty)?;
880 self.output.str(",");
881 self.output.newline();
882 }
883 self.output.indent_end();
884 Ok(())
885 }
886 None => bail!("document has unnamed record type"),
887 }
888 }
889
890 fn declare_tuple(
891 &mut self,
892 resolve: &Resolve,
893 name: Option<&str>,
894 tuple: &Tuple,
895 ) -> Result<()> {
896 if let Some(name) = name {
897 self.output.keyword("type");
898 self.output.str(" ");
899 self.print_name_type(name, TypeKind::Tuple);
900 self.output.str(" = ");
901 self.print_tuple_type(resolve, tuple)?;
902 self.output.semicolon();
903 }
904 Ok(())
905 }
906
907 fn declare_flags(&mut self, name: Option<&str>, flags: &Flags) -> Result<()> {
908 match name {
909 Some(name) => {
910 self.output.keyword("flags");
911 self.output.str(" ");
912 self.print_name_type(name, TypeKind::Flags);
913 self.output.indent_start();
914 for flag in &flags.flags {
915 self.print_docs(&flag.docs);
916 self.print_name_case(&flag.name);
917 self.output.str(",");
918 self.output.newline();
919 }
920 self.output.indent_end();
921 }
922 None => bail!("document has unnamed flags type"),
923 }
924 Ok(())
925 }
926
927 fn declare_variant(
928 &mut self,
929 resolve: &Resolve,
930 name: Option<&str>,
931 variant: &Variant,
932 ) -> Result<()> {
933 let name = match name {
934 Some(name) => name,
935 None => bail!("document has unnamed variant type"),
936 };
937 self.output.keyword("variant");
938 self.output.str(" ");
939 self.print_name_type(name, TypeKind::Variant);
940 self.output.indent_start();
941 for case in &variant.cases {
942 self.print_docs(&case.docs);
943 self.print_name_case(&case.name);
944 if let Some(ty) = case.ty {
945 self.output.str("(");
946 self.print_type_name(resolve, &ty)?;
947 self.output.str(")");
948 }
949 self.output.str(",");
950 self.output.newline();
951 }
952 self.output.indent_end();
953 Ok(())
954 }
955
956 fn declare_option(
957 &mut self,
958 resolve: &Resolve,
959 name: Option<&str>,
960 payload: &Type,
961 ) -> Result<()> {
962 if let Some(name) = name {
963 self.output.keyword("type");
964 self.output.str(" ");
965 self.print_name_type(name, TypeKind::Option);
966 self.output.str(" = ");
967 self.print_option_type(resolve, payload)?;
968 self.output.semicolon();
969 }
970 Ok(())
971 }
972
973 fn declare_result(
974 &mut self,
975 resolve: &Resolve,
976 name: Option<&str>,
977 result: &Result_,
978 ) -> Result<()> {
979 if let Some(name) = name {
980 self.output.keyword("type");
981 self.output.str(" ");
982 self.print_name_type(name, TypeKind::Result);
983 self.output.str(" = ");
984 self.print_result_type(resolve, result)?;
985 self.output.semicolon();
986 }
987 Ok(())
988 }
989
990 fn declare_enum(&mut self, name: Option<&str>, enum_: &Enum) -> Result<()> {
991 let name = match name {
992 Some(name) => name,
993 None => bail!("document has unnamed enum type"),
994 };
995 self.output.keyword("enum");
996 self.output.str(" ");
997 self.print_name_type(name, TypeKind::Enum);
998 self.output.indent_start();
999 for case in &enum_.cases {
1000 self.print_docs(&case.docs);
1001 self.print_name_case(&case.name);
1002 self.output.str(",");
1003 self.output.newline();
1004 }
1005 self.output.indent_end();
1006 Ok(())
1007 }
1008
1009 fn declare_list(&mut self, resolve: &Resolve, name: Option<&str>, ty: &Type) -> Result<()> {
1010 if let Some(name) = name {
1011 self.output.keyword("type");
1012 self.output.str(" ");
1013 self.print_name_type(name, TypeKind::List);
1014 self.output.str(" = ");
1015 self.output.ty("list", TypeKind::BuiltIn);
1016 self.output.str("<");
1017 self.print_type_name(resolve, ty)?;
1018 self.output.str(">");
1019 self.output.semicolon();
1020 return Ok(());
1021 }
1022
1023 Ok(())
1024 }
1025
1026 fn declare_map(
1027 &mut self,
1028 resolve: &Resolve,
1029 name: Option<&str>,
1030 key_ty: &Type,
1031 value_ty: &Type,
1032 ) -> Result<()> {
1033 if let Some(name) = name {
1034 self.output.keyword("type");
1035 self.output.str(" ");
1036 self.print_name_type(name, TypeKind::Map);
1037 self.output.str(" = ");
1038 self.output.ty("map", TypeKind::BuiltIn);
1039 self.output.str("<");
1040 self.print_type_name(resolve, key_ty)?;
1041 self.output.str(", ");
1042 self.print_type_name(resolve, value_ty)?;
1043 self.output.str(">");
1044 self.output.semicolon();
1045 return Ok(());
1046 }
1047
1048 Ok(())
1049 }
1050
1051 fn declare_fixed_length_list(
1052 &mut self,
1053 resolve: &Resolve,
1054 name: Option<&str>,
1055 ty: &Type,
1056 elements: u32,
1057 ) -> Result<()> {
1058 if let Some(name) = name {
1059 self.output.keyword("type");
1060 self.output.str(" ");
1061 self.print_name_type(name, TypeKind::List);
1062 self.output.str(" = ");
1063 self.output.ty("list", TypeKind::BuiltIn);
1064 self.output.str("<");
1065 self.print_type_name(resolve, ty)?;
1066 self.output.str(&format!(", {elements}"));
1067 self.output.str(">");
1068 self.output.semicolon();
1069 return Ok(());
1070 }
1071
1072 Ok(())
1073 }
1074
1075 fn declare_stream(
1076 &mut self,
1077 resolve: &Resolve,
1078 name: Option<&str>,
1079 ty: Option<&Type>,
1080 ) -> Result<()> {
1081 if let Some(name) = name {
1082 self.output.keyword("type");
1083 self.output.str(" ");
1084 self.print_name_type(name, TypeKind::Stream);
1085 self.output.str(" = ");
1086 self.output.ty("stream", TypeKind::BuiltIn);
1087 if let Some(ty) = ty {
1088 self.output.str("<");
1089 self.print_type_name(resolve, ty)?;
1090 self.output.str(">");
1091 }
1092 self.output.semicolon();
1093 }
1094
1095 Ok(())
1096 }
1097
1098 fn declare_future(
1099 &mut self,
1100 resolve: &Resolve,
1101 name: Option<&str>,
1102 ty: Option<&Type>,
1103 ) -> Result<()> {
1104 if let Some(name) = name {
1105 self.output.keyword("type");
1106 self.output.str(" ");
1107 self.print_name_type(name, TypeKind::Future);
1108 self.output.str(" = ");
1109 self.output.ty("future", TypeKind::BuiltIn);
1110 if let Some(ty) = ty {
1111 self.output.str("<");
1112 self.print_type_name(resolve, ty)?;
1113 self.output.str(">");
1114 }
1115 self.output.semicolon();
1116 }
1117
1118 Ok(())
1119 }
1120
1121 fn escape_name(name: &str) -> Cow<'_, str> {
1122 if is_keyword(name) {
1123 Cow::Owned(format!("%{name}"))
1124 } else {
1125 Cow::Borrowed(name)
1126 }
1127 }
1128
1129 fn print_name_type(&mut self, name: &str, kind: TypeKind) {
1130 self.output.ty(Self::escape_name(name).deref(), kind);
1131 }
1132
1133 fn print_name_param(&mut self, name: &str) {
1134 self.output.param(Self::escape_name(name).deref());
1135 }
1136
1137 fn print_name_case(&mut self, name: &str) {
1138 self.output.case(Self::escape_name(name).deref());
1139 }
1140
1141 fn print_docs(&mut self, docs: &Docs) {
1142 if self.emit_docs {
1143 if let Some(contents) = &docs.contents {
1144 for line in contents.lines() {
1145 self.output.doc(line);
1146 }
1147 }
1148 }
1149 }
1150
1151 fn print_stability(&mut self, stability: &Stability) {
1152 match stability {
1153 Stability::Unknown => {}
1154 Stability::Stable { since, deprecated } => {
1155 self.output.keyword("@since");
1156 self.output.str("(");
1157 self.output.keyword("version");
1158 self.output.str(" = ");
1159 self.print_name_type(&since.to_string(), TypeKind::VersionAnnotation);
1160 self.output.str(")");
1161 self.output.newline();
1162 if let Some(version) = deprecated {
1163 self.output.keyword("@deprecated");
1164 self.output.str("(");
1165 self.output.keyword("version");
1166 self.output.str(" = ");
1167 self.print_name_type(&version.to_string(), TypeKind::VersionAnnotation);
1168 self.output.str(")");
1169 self.output.newline();
1170 }
1171 }
1172 Stability::Unstable {
1173 feature,
1174 deprecated,
1175 } => {
1176 self.output.keyword("@unstable");
1177 self.output.str("(");
1178 self.output.keyword("feature");
1179 self.output.str(" = ");
1180 self.output.str(feature);
1181 self.output.str(")");
1182 self.output.newline();
1183 if let Some(version) = deprecated {
1184 self.output.keyword("@deprecated");
1185 self.output.str("(");
1186 self.output.keyword("version");
1187 self.output.str(" = ");
1188 self.print_name_type(&version.to_string(), TypeKind::VersionAnnotation);
1189 self.output.str(")");
1190 self.output.newline();
1191 }
1192 }
1193 }
1194 }
1195
1196 fn print_external_id(&mut self, id: Option<&str>) {
1197 let Some(id) = id else {
1198 return;
1199 };
1200 self.output.keyword("@external-id");
1201 self.output.str("(\"");
1202 let mut buf = [0; 4];
1203 for c in id.chars() {
1204 if c.is_ascii_alphanumeric()
1205 || c == '-'
1206 || c == '_'
1207 || c == '.'
1208 || c == '/'
1209 || c == ':'
1210 || c == ' '
1211 {
1212 self.output.push_str(c.encode_utf8(&mut buf));
1213 continue;
1214 }
1215 match c {
1216 '\\' => self.output.push_str("\\\\"),
1217 '"' => self.output.push_str("\\\""),
1218 '\n' => self.output.push_str("\\n"),
1219 '\r' => self.output.push_str("\\r"),
1220 '\t' => self.output.push_str("\\t"),
1221 _ => {
1222 self.output.push_str(&format!("\\u{{{:x}}}", c as u32));
1223 }
1224 }
1225 }
1226 self.output.str("\")");
1227 self.output.newline();
1228 }
1229}
1230
1231fn is_keyword(name: &str) -> bool {
1232 matches!(
1233 name,
1234 "use"
1235 | "type"
1236 | "func"
1237 | "u8"
1238 | "u16"
1239 | "u32"
1240 | "u64"
1241 | "s8"
1242 | "s16"
1243 | "s32"
1244 | "s64"
1245 | "f32"
1246 | "f64"
1247 | "float32"
1248 | "float64"
1249 | "char"
1250 | "resource"
1251 | "record"
1252 | "flags"
1253 | "variant"
1254 | "enum"
1255 | "bool"
1256 | "string"
1257 | "option"
1258 | "result"
1259 | "future"
1260 | "stream"
1261 | "list"
1262 | "own"
1263 | "borrow"
1264 | "_"
1265 | "as"
1266 | "from"
1267 | "static"
1268 | "interface"
1269 | "tuple"
1270 | "world"
1271 | "import"
1272 | "export"
1273 | "package"
1274 | "with"
1275 | "include"
1276 | "constructor"
1277 | "error-context"
1278 | "async"
1279 | "map"
1280 )
1281}
1282
1283pub trait Output {
1289 fn push_str(&mut self, src: &str);
1297
1298 fn indent_if_needed(&mut self) -> bool;
1304
1305 fn indent_start(&mut self);
1307
1308 fn indent_end(&mut self);
1310
1311 fn indent_and_print(&mut self, src: &str) {
1314 assert!(!src.contains('\n'));
1315 let indented = self.indent_if_needed();
1316 if indented && src.starts_with(' ') {
1317 panic!("cannot add a space at the beginning of a line");
1318 }
1319 self.push_str(src);
1320 }
1321
1322 fn newline(&mut self);
1324
1325 fn keyword(&mut self, src: &str) {
1328 self.indent_and_print(src);
1329 }
1330
1331 fn ty(&mut self, src: &str, _kind: TypeKind) {
1333 self.indent_and_print(src);
1334 }
1335
1336 fn param(&mut self, src: &str) {
1338 self.indent_and_print(src);
1339 }
1340
1341 fn case(&mut self, src: &str) {
1343 self.indent_and_print(src);
1344 }
1345
1346 fn generic_args_start(&mut self) {
1348 assert!(
1349 !self.indent_if_needed(),
1350 "`generic_args_start` is never called after newline"
1351 );
1352 self.push_str("<");
1353 }
1354
1355 fn generic_args_end(&mut self) {
1357 assert!(
1358 !self.indent_if_needed(),
1359 "`generic_args_end` is never called after newline"
1360 );
1361 self.push_str(">");
1362 }
1363
1364 fn doc(&mut self, doc: &str) {
1367 assert!(!doc.contains('\n'));
1368 self.indent_if_needed();
1369 self.push_str("///");
1370 if !doc.is_empty() {
1371 self.push_str(" ");
1372 self.push_str(doc);
1373 }
1374 self.newline();
1375 }
1376
1377 fn semicolon(&mut self) {
1379 assert!(
1380 !self.indent_if_needed(),
1381 "`semicolon` is never called after newline"
1382 );
1383 self.push_str(";");
1384 self.newline();
1385 }
1386
1387 fn str(&mut self, src: &str) {
1391 self.indent_and_print(src);
1392 }
1393}
1394
1395#[non_exhaustive]
1401#[derive(Clone, Copy, Debug)]
1402pub enum TypeKind {
1403 BuiltIn,
1405 Enum,
1407 ErrorContext,
1409 Flags,
1411 FunctionFreestanding,
1414 FunctionMethod,
1416 FunctionStatic,
1418 Future,
1420 InterfaceDeclaration,
1422 InterfacePath,
1424 List,
1426 Map,
1428 NamespaceDeclaration,
1430 NamespacePath,
1432 Option,
1434 PackageNameDeclaration,
1436 PackageNamePath,
1438 Record,
1440 Resource,
1442 Result,
1444 Stream,
1446 Tuple,
1448 TypeAlias,
1450 TypeImport,
1452 TypeName,
1454 Variant,
1456 VersionDeclaration,
1458 VersionPath,
1460 VersionAnnotation,
1462 WorldDeclaration,
1464 Other,
1466}
1467
1468#[derive(Default)]
1471pub struct OutputToString {
1472 indent: usize,
1473 output: String,
1474 needs_indent: bool,
1476}
1477
1478impl Output for OutputToString {
1479 fn push_str(&mut self, src: &str) {
1480 self.output.push_str(src);
1481 }
1482
1483 fn indent_if_needed(&mut self) -> bool {
1484 if self.needs_indent {
1485 for _ in 0..self.indent {
1486 self.output.push_str(" ");
1488 }
1489 self.needs_indent = false;
1490 true
1491 } else {
1492 false
1493 }
1494 }
1495
1496 fn indent_start(&mut self) {
1497 assert!(
1498 !self.needs_indent,
1499 "`indent_start` is never called after newline"
1500 );
1501 self.output.push_str(" {");
1502 self.indent += 1;
1503 self.newline();
1504 }
1505
1506 fn indent_end(&mut self) {
1507 self.indent = self.indent.saturating_sub(1);
1512 self.indent_if_needed();
1513 self.output.push('}');
1514 self.newline();
1515 }
1516
1517 fn newline(&mut self) {
1518 self.output.push('\n');
1519 self.needs_indent = true;
1520 }
1521}
1522
1523impl From<OutputToString> for String {
1524 fn from(output: OutputToString) -> String {
1525 output.output
1526 }
1527}
1528
1529impl Display for OutputToString {
1530 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1531 self.output.fmt(f)
1532 }
1533}