1use crate::ast::*;
4use std::fmt::Write;
5
6pub struct DocumentPrinter<'a, W: Write> {
8 writer: W,
9 source: &'a str,
10 space: &'static str,
11 indent: usize,
12 indented: bool,
13}
14
15impl<'a, W: Write> DocumentPrinter<'a, W> {
16 pub fn new(writer: W, source: &'a str, space: Option<&'static str>) -> Self {
21 Self {
22 writer,
23 source,
24 space: space.unwrap_or(" "),
25 indent: 0,
26 indented: false,
27 }
28 }
29
30 pub fn document(&mut self, doc: &Document) -> std::fmt::Result {
32 self.docs(&doc.docs)?;
33 self.package_directive(&doc.directive)?;
34
35 for (i, statement) in doc.statements.iter().enumerate() {
36 if i > 0 {
37 self.newline()?;
38 }
39
40 self.statement(statement)?;
41 self.newline()?;
42 }
43
44 Ok(())
45 }
46
47 pub fn package_directive(&mut self, directive: &PackageDirective) -> std::fmt::Result {
49 self.indent()?;
50 write!(
51 self.writer,
52 "package {package}",
53 package = self.source(directive.package.span),
54 )?;
55
56 if let Some(targets) = &directive.targets {
57 write!(self.writer, " ")?;
58 self.package_path(targets)?;
59 }
60
61 writeln!(self.writer, ";")?;
62 self.newline()
63 }
64
65 pub fn statement(&mut self, statement: &Statement) -> std::fmt::Result {
67 match statement {
68 Statement::Import(i) => self.import_statement(i),
69 Statement::Type(t) => self.type_statement(t),
70 Statement::Let(l) => self.let_statement(l),
71 Statement::Export(e) => self.export_statement(e),
72 }
73 }
74
75 pub fn docs(&mut self, docs: &[DocComment]) -> std::fmt::Result {
77 for doc in docs {
78 for line in doc.comment.lines() {
79 self.indent()?;
80 write!(self.writer, "/// {line}", line = line.trim())?;
81 self.newline()?;
82 }
83 }
84
85 Ok(())
86 }
87
88 pub fn import_statement(&mut self, statement: &ImportStatement) -> std::fmt::Result {
90 self.docs(&statement.docs)?;
91
92 self.indent()?;
93 write!(
94 self.writer,
95 "import {id}",
96 id = self.source(statement.id.span)
97 )?;
98
99 if let Some(name) = &statement.name {
100 write!(self.writer, " as {name}", name = self.source(name.span()))?;
101 }
102
103 write!(self.writer, ": ")?;
104 self.import_type(&statement.ty)?;
105 write!(self.writer, ";")?;
106
107 Ok(())
108 }
109
110 pub fn import_type(&mut self, ty: &ImportType) -> std::fmt::Result {
112 match ty {
113 ImportType::Package(p) => self.package_path(p),
114 ImportType::Func(f) => self.func_type(f),
115 ImportType::Interface(i) => self.inline_interface(i),
116 ImportType::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)),
117 }
118 }
119
120 pub fn package_path(&mut self, path: &PackagePath) -> std::fmt::Result {
122 write!(self.writer, "{path}", path = self.source(path.span))?;
123 Ok(())
124 }
125
126 pub fn func_type(&mut self, ty: &FuncType) -> std::fmt::Result {
128 write!(self.writer, "func(")?;
129 self.named_types(&ty.params)?;
130 write!(self.writer, ")")?;
131
132 match &ty.results {
133 ResultList::Empty => Ok(()),
134 ResultList::Scalar(ty) => {
135 write!(self.writer, " -> ")?;
136 self.ty(ty)
137 }
138 ResultList::Named(results) => {
139 write!(self.writer, " -> (")?;
140 self.named_types(results)?;
141 write!(self.writer, ")")
142 }
143 }
144 }
145
146 fn named_types(&mut self, types: &[NamedType]) -> std::fmt::Result {
147 for (i, param) in types.iter().enumerate() {
148 if i > 0 {
149 write!(self.writer, ", ")?;
150 }
151
152 write!(self.writer, "{id}: ", id = self.source(param.id.span))?;
153 self.ty(¶m.ty)?;
154 }
155
156 Ok(())
157 }
158
159 pub fn ty(&mut self, ty: &Type) -> std::fmt::Result {
161 match ty {
162 Type::U8(_) => write!(self.writer, "u8"),
163 Type::S8(_) => write!(self.writer, "s8"),
164 Type::U16(_) => write!(self.writer, "u16"),
165 Type::S16(_) => write!(self.writer, "s16"),
166 Type::U32(_) => write!(self.writer, "u32"),
167 Type::S32(_) => write!(self.writer, "s32"),
168 Type::U64(_) => write!(self.writer, "u64"),
169 Type::S64(_) => write!(self.writer, "s64"),
170 Type::F32(_) => write!(self.writer, "f32"),
171 Type::F64(_) => write!(self.writer, "f64"),
172 Type::Char(_) => write!(self.writer, "char"),
173 Type::Bool(_) => write!(self.writer, "bool"),
174 Type::String(_) => write!(self.writer, "string"),
175 Type::Tuple(types, _) => {
176 write!(self.writer, "tuple<")?;
177 for (i, ty) in types.iter().enumerate() {
178 if i > 0 {
179 write!(self.writer, ", ")?;
180 }
181
182 self.ty(ty)?;
183 }
184
185 write!(self.writer, ">")
186 }
187 Type::List(ty, _) => {
188 write!(self.writer, "list<")?;
189 self.ty(ty)?;
190 write!(self.writer, ">")
191 }
192 Type::Option(ty, _) => {
193 write!(self.writer, "option<")?;
194 self.ty(ty)?;
195 write!(self.writer, ">")
196 }
197 Type::Result { ok, err, .. } => match (ok, err) {
198 (None, None) => write!(self.writer, "result"),
199 (None, Some(err)) => {
200 write!(self.writer, "result<_, ")?;
201 self.ty(err)?;
202 write!(self.writer, ">")
203 }
204 (Some(ok), None) => {
205 write!(self.writer, "result<")?;
206 self.ty(ok)?;
207 write!(self.writer, ">")
208 }
209 (Some(ok), Some(err)) => {
210 write!(self.writer, "result<")?;
211 self.ty(ok)?;
212 write!(self.writer, ", ")?;
213 self.ty(err)?;
214 write!(self.writer, ">")
215 }
216 },
217 Type::Borrow(id, _) => {
218 write!(self.writer, "borrow<{id}>", id = self.source(id.span))
219 }
220 Type::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)),
221 }
222 }
223
224 pub fn inline_interface(&mut self, iface: &InlineInterface) -> std::fmt::Result {
226 write!(self.writer, "interface {{")?;
227 self.newline()?;
228
229 self.inc();
230 for (i, item) in iface.items.iter().enumerate() {
231 if i > 0 {
232 self.newline()?;
233 }
234
235 self.interface_item(item)?;
236 self.newline()?;
237 }
238
239 self.dec();
240 self.indent()?;
241 write!(self.writer, "}}")
242 }
243
244 pub fn interface_item(&mut self, item: &InterfaceItem) -> std::fmt::Result {
246 match item {
247 InterfaceItem::Use(u) => self.use_type(u),
248 InterfaceItem::Type(t) => self.item_type_decl(t),
249 InterfaceItem::Export(e) => self.interface_export(e),
250 }
251 }
252
253 pub fn use_type(&mut self, use_ty: &Use) -> std::fmt::Result {
255 self.docs(&use_ty.docs)?;
256 self.indent()?;
257 write!(self.writer, "use ")?;
258 self.use_path(&use_ty.path)?;
259
260 write!(self.writer, ".{{ ")?;
261
262 for (i, item) in use_ty.items.iter().enumerate() {
263 if i > 0 {
264 write!(self.writer, ", ")?;
265 }
266
267 write!(self.writer, "{id}", id = self.source(item.id.span))?;
268 if let Some(as_id) = &item.as_id {
269 write!(self.writer, " as {as_id}", as_id = self.source(as_id.span))?;
270 }
271 }
272
273 write!(self.writer, " }};")
274 }
275
276 pub fn use_path(&mut self, path: &UsePath) -> std::fmt::Result {
278 match path {
279 UsePath::Package(p) => self.package_path(p),
280 UsePath::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)),
281 }
282 }
283
284 pub fn item_type_decl(&mut self, decl: &ItemTypeDecl) -> std::fmt::Result {
286 match decl {
287 ItemTypeDecl::Resource(r) => self.resource_decl(r),
288 ItemTypeDecl::Variant(v) => self.variant_decl(v),
289 ItemTypeDecl::Record(r) => self.record_decl(r),
290 ItemTypeDecl::Flags(f) => self.flags_decl(f),
291 ItemTypeDecl::Enum(e) => self.enum_decl(e),
292 ItemTypeDecl::Alias(a) => self.type_alias(a),
293 }
294 }
295
296 pub fn resource_decl(&mut self, decl: &ResourceDecl) -> std::fmt::Result {
298 self.docs(&decl.docs)?;
299 self.indent()?;
300 write!(
301 self.writer,
302 "resource {id} {{",
303 id = self.source(decl.id.span)
304 )?;
305 self.newline()?;
306
307 self.inc();
308 for (i, method) in decl.methods.iter().enumerate() {
309 if i > 0 {
310 self.newline()?;
311 }
312
313 self.resource_method(method)?;
314 self.newline()?;
315 }
316
317 self.dec();
318 self.indent()?;
319 write!(self.writer, "}}")
320 }
321
322 pub fn resource_method(&mut self, method: &ResourceMethod) -> std::fmt::Result {
324 match method {
325 ResourceMethod::Constructor(c) => self.constructor(c),
326 ResourceMethod::Method(m) => self.method(m),
327 }
328 }
329
330 pub fn constructor(&mut self, constructor: &Constructor) -> std::fmt::Result {
332 self.docs(&constructor.docs)?;
333 self.indent()?;
334 write!(self.writer, "constructor(")?;
335 self.named_types(&constructor.params)?;
336 write!(self.writer, ");")
337 }
338
339 pub fn method(&mut self, method: &Method) -> std::fmt::Result {
341 self.docs(&method.docs)?;
342 self.indent()?;
343 write!(self.writer, "{id}: ", id = self.source(method.id.span))?;
344
345 if method.is_static {
346 write!(self.writer, "static ")?;
347 }
348
349 self.func_type(&method.ty)?;
350 write!(self.writer, ";")
351 }
352
353 pub fn func_type_ref(&mut self, ty: &FuncTypeRef) -> std::fmt::Result {
355 match ty {
356 FuncTypeRef::Func(ty) => self.func_type(ty),
357 FuncTypeRef::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)),
358 }
359 }
360
361 pub fn variant_decl(&mut self, decl: &VariantDecl) -> std::fmt::Result {
363 self.docs(&decl.docs)?;
364 self.indent()?;
365 write!(
366 self.writer,
367 "variant {id} {{",
368 id = self.source(decl.id.span)
369 )?;
370 self.newline()?;
371
372 self.inc();
373 for case in &decl.cases {
374 self.indent()?;
375 self.variant_case(case)?;
376 write!(self.writer, ",")?;
377 self.newline()?;
378 }
379
380 self.dec();
381 self.indent()?;
382 write!(self.writer, "}}")
383 }
384
385 pub fn variant_case(&mut self, case: &VariantCase) -> std::fmt::Result {
387 self.docs(&case.docs)?;
388 self.indent()?;
389 write!(self.writer, "{id}", id = self.source(case.id.span))?;
390
391 if let Some(ty) = &case.ty {
392 write!(self.writer, "(")?;
393 self.ty(ty)?;
394 write!(self.writer, ")")?;
395 }
396
397 Ok(())
398 }
399
400 pub fn record_decl(&mut self, decl: &RecordDecl) -> std::fmt::Result {
402 self.docs(&decl.docs)?;
403 self.indent()?;
404 write!(
405 self.writer,
406 "record {id} {{",
407 id = self.source(decl.id.span)
408 )?;
409 self.newline()?;
410
411 self.inc();
412 for field in &decl.fields {
413 self.docs(&field.docs)?;
414 self.indent()?;
415 write!(self.writer, "{id}: ", id = self.source(field.id.span))?;
416 self.ty(&field.ty)?;
417 write!(self.writer, ",")?;
418 self.newline()?;
419 }
420
421 self.dec();
422 self.indent()?;
423 write!(self.writer, "}}")
424 }
425
426 pub fn flags_decl(&mut self, decl: &FlagsDecl) -> std::fmt::Result {
428 self.docs(&decl.docs)?;
429 self.indent()?;
430 write!(self.writer, "flags {id} {{", id = self.source(decl.id.span))?;
431 self.newline()?;
432
433 self.inc();
434 for flag in &decl.flags {
435 self.docs(&flag.docs)?;
436 self.indent()?;
437 write!(self.writer, "{id},", id = self.source(flag.id.span))?;
438 self.newline()?;
439 }
440
441 self.dec();
442 self.indent()?;
443 write!(self.writer, "}}")
444 }
445
446 pub fn enum_decl(&mut self, decl: &EnumDecl) -> std::fmt::Result {
448 self.docs(&decl.docs)?;
449 self.indent()?;
450 write!(self.writer, "enum {id} {{", id = self.source(decl.id.span))?;
451 self.newline()?;
452
453 self.inc();
454 for case in &decl.cases {
455 self.docs(&case.docs)?;
456 self.indent()?;
457 write!(self.writer, "{id},", id = self.source(case.id.span))?;
458 self.newline()?;
459 }
460
461 self.dec();
462 self.indent()?;
463 write!(self.writer, "}}")
464 }
465
466 pub fn type_alias(&mut self, alias: &TypeAlias) -> std::fmt::Result {
468 self.docs(&alias.docs)?;
469 self.indent()?;
470 write!(self.writer, "type {id} = ", id = self.source(alias.id.span))?;
471 match &alias.kind {
472 TypeAliasKind::Func(ty) => self.func_type(ty)?,
473 TypeAliasKind::Type(ty) => self.ty(ty)?,
474 }
475
476 write!(self.writer, ";")
477 }
478
479 pub fn interface_export(&mut self, export: &InterfaceExport) -> std::fmt::Result {
481 self.docs(&export.docs)?;
482 self.indent()?;
483 write!(self.writer, "{id}: ", id = self.source(export.id.span))?;
484 self.func_type_ref(&export.ty)?;
485 write!(self.writer, ";")
486 }
487
488 pub fn type_statement(&mut self, stmt: &TypeStatement) -> std::fmt::Result {
490 match stmt {
491 TypeStatement::Interface(i) => self.interface_decl(i),
492 TypeStatement::World(w) => self.world_decl(w),
493 TypeStatement::Type(t) => self.type_decl(t),
494 }
495 }
496
497 pub fn interface_decl(&mut self, decl: &InterfaceDecl) -> std::fmt::Result {
499 self.docs(&decl.docs)?;
500 self.indent()?;
501 write!(
502 self.writer,
503 "interface {id} {{",
504 id = self.source(decl.id.span)
505 )?;
506 self.newline()?;
507
508 self.inc();
509 for (i, item) in decl.items.iter().enumerate() {
510 if i > 0 {
511 self.newline()?;
512 }
513
514 self.interface_item(item)?;
515 self.newline()?;
516 }
517
518 self.dec();
519 self.indent()?;
520 write!(self.writer, "}}")
521 }
522
523 pub fn world_decl(&mut self, decl: &WorldDecl) -> std::fmt::Result {
525 self.docs(&decl.docs)?;
526 self.indent()?;
527 write!(self.writer, "world {id} {{", id = self.source(decl.id.span))?;
528 self.newline()?;
529
530 self.inc();
531 for (i, item) in decl.items.iter().enumerate() {
532 if i > 0 {
533 self.newline()?;
534 }
535
536 self.world_item(item)?;
537 self.newline()?;
538 }
539
540 self.dec();
541 self.indent()?;
542 write!(self.writer, "}}")
543 }
544
545 pub fn world_item(&mut self, item: &WorldItem) -> std::fmt::Result {
547 match item {
548 WorldItem::Use(u) => self.use_type(u),
549 WorldItem::Type(t) => self.item_type_decl(t),
550 WorldItem::Import(i) => self.world_import(i),
551 WorldItem::Export(e) => self.world_export(e),
552 WorldItem::Include(i) => self.world_include(i),
553 }
554 }
555
556 pub fn world_import(&mut self, import: &WorldImport) -> std::fmt::Result {
558 self.docs(&import.docs)?;
559 self.indent()?;
560 write!(self.writer, "import ")?;
561
562 self.world_item_path(&import.path)?;
563 write!(self.writer, ";")
564 }
565
566 pub fn world_export(&mut self, export: &WorldExport) -> std::fmt::Result {
568 self.docs(&export.docs)?;
569 self.indent()?;
570 write!(self.writer, "export ")?;
571
572 self.world_item_path(&export.path)?;
573 write!(self.writer, ";")
574 }
575
576 pub fn world_item_path(&mut self, path: &WorldItemPath) -> std::fmt::Result {
578 match path {
579 WorldItemPath::Named(n) => self.named_world_item(n),
580 WorldItemPath::Package(p) => self.package_path(p),
581 WorldItemPath::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)),
582 }
583 }
584
585 pub fn named_world_item(&mut self, item: &NamedWorldItem) -> std::fmt::Result {
587 write!(self.writer, "{id}: ", id = self.source(item.id.span))?;
588 self.extern_type(&item.ty)
589 }
590
591 pub fn extern_type(&mut self, ty: &ExternType) -> std::fmt::Result {
593 match ty {
594 ExternType::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)),
595 ExternType::Func(ty) => self.func_type(ty),
596 ExternType::Interface(i) => self.inline_interface(i),
597 }
598 }
599
600 pub fn world_include(&mut self, include: &WorldInclude) -> std::fmt::Result {
602 self.docs(&include.docs)?;
603 self.indent()?;
604 write!(self.writer, "include ")?;
605 self.world_ref(&include.world)?;
606
607 if !include.with.is_empty() {
608 write!(self.writer, " with {{")?;
609 self.newline()?;
610 self.inc();
611
612 for item in &include.with {
613 self.indent()?;
614 write!(
615 self.writer,
616 "{source} as {target},",
617 source = self.source(item.from.span),
618 target = self.source(item.to.span)
619 )?;
620 self.newline()?;
621 }
622
623 self.dec();
624 self.indent()?;
625 write!(self.writer, "}}")?;
626 }
627
628 write!(self.writer, ";")
629 }
630
631 pub fn world_ref(&mut self, reference: &WorldRef) -> std::fmt::Result {
633 match reference {
634 WorldRef::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)),
635 WorldRef::Package(p) => self.package_path(p),
636 }
637 }
638
639 pub fn type_decl(&mut self, decl: &TypeDecl) -> std::fmt::Result {
641 match decl {
642 TypeDecl::Variant(v) => self.variant_decl(v),
643 TypeDecl::Record(r) => self.record_decl(r),
644 TypeDecl::Flags(f) => self.flags_decl(f),
645 TypeDecl::Enum(e) => self.enum_decl(e),
646 TypeDecl::Alias(a) => self.type_alias(a),
647 }
648 }
649
650 pub fn let_statement(&mut self, stmt: &LetStatement) -> std::fmt::Result {
652 self.docs(&stmt.docs)?;
653 self.indent()?;
654 write!(self.writer, "let {id} = ", id = self.source(stmt.id.span))?;
655 self.expr(&stmt.expr)?;
656 write!(self.writer, ";")
657 }
658
659 pub fn expr(&mut self, expr: &Expr) -> std::fmt::Result {
661 self.primary_expr(&expr.primary)?;
662 for postfix in &expr.postfix {
663 self.postfix_expr(postfix)?;
664 }
665
666 Ok(())
667 }
668
669 pub fn primary_expr(&mut self, expr: &PrimaryExpr) -> std::fmt::Result {
671 match expr {
672 PrimaryExpr::New(e) => self.new_expr(e),
673 PrimaryExpr::Nested(e) => {
674 write!(self.writer, "(")?;
675 self.expr(&e.inner)?;
676 write!(self.writer, ")")
677 }
678 PrimaryExpr::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)),
679 }
680 }
681
682 pub fn new_expr(&mut self, expr: &NewExpr) -> std::fmt::Result {
684 write!(
685 self.writer,
686 "new {name} {{",
687 name = self.source(expr.package.span)
688 )?;
689
690 if expr.arguments.is_empty() {
691 write!(self.writer, "}}")?;
692 return Ok(());
693 }
694
695 if expr.arguments.len() == 1 {
696 if let InstantiationArgument::Fill(_) = expr.arguments[0] {
697 write!(self.writer, " ... }}")?;
698 return Ok(());
699 }
700 }
701
702 self.newline()?;
703 self.inc();
704
705 for arg in &expr.arguments {
706 self.indent()?;
707
708 match arg {
709 InstantiationArgument::Inferred(id) => {
710 write!(self.writer, "{id},", id = self.source(id.span))?
711 }
712 InstantiationArgument::Spread(id) => {
713 write!(self.writer, "...{id},", id = self.source(id.span))?
714 }
715 InstantiationArgument::Named(arg) => {
716 match &arg.name {
717 InstantiationArgumentName::Ident(id) => {
718 write!(self.writer, "{id}: ", id = self.source(id.span))?;
719 }
720 InstantiationArgumentName::String(s) => {
721 write!(self.writer, "{s}: ", s = self.source(s.span))?;
722 }
723 }
724 self.expr(&arg.expr)?;
725 write!(self.writer, ",")?;
726 }
727 InstantiationArgument::Fill(_) => write!(self.writer, "...")?,
728 }
729
730 self.newline()?;
731 }
732
733 self.dec();
734 self.indent()?;
735 write!(self.writer, "}}")
736 }
737
738 pub fn postfix_expr(&mut self, expr: &PostfixExpr) -> std::fmt::Result {
740 match expr {
741 PostfixExpr::Access(a) => self.access_expr(a),
742 PostfixExpr::NamedAccess(a) => self.named_access_expr(a),
743 }
744 }
745
746 pub fn access_expr(&mut self, expr: &AccessExpr) -> std::fmt::Result {
748 write!(self.writer, ".{id}", id = self.source(expr.id.span))
749 }
750
751 pub fn named_access_expr(&mut self, expr: &NamedAccessExpr) -> std::fmt::Result {
753 write!(
754 self.writer,
755 "[{name}]",
756 name = self.source(expr.string.span)
757 )
758 }
759
760 pub fn export_statement(&mut self, stmt: &ExportStatement) -> std::fmt::Result {
762 self.docs(&stmt.docs)?;
763 self.indent()?;
764
765 write!(self.writer, "export ")?;
766
767 self.expr(&stmt.expr)?;
768
769 match &stmt.options {
770 ExportOptions::None => {}
771 ExportOptions::Spread(_) => {
772 write!(self.writer, "...")?;
773 }
774 ExportOptions::Rename(name) => {
775 write!(self.writer, " as {name}", name = self.source(name.span()))?;
776 }
777 }
778
779 write!(self.writer, ";")
780 }
781
782 fn newline(&mut self) -> std::fmt::Result {
783 writeln!(self.writer)?;
784 self.indented = false;
785 Ok(())
786 }
787
788 fn indent(&mut self) -> std::fmt::Result {
789 if !self.indented {
790 for _ in 0..self.indent {
791 write!(self.writer, "{space}", space = self.space)?;
792 }
793
794 self.indented = true;
795 }
796
797 Ok(())
798 }
799
800 fn inc(&mut self) {
801 self.indent = self.indent.saturating_add(1);
802 }
803
804 fn dec(&mut self) {
805 self.indent = self.indent.saturating_sub(1);
806 }
807
808 fn source(&self, span: SourceSpan) -> &'a str {
809 &self.source[span.offset()..span.offset() + span.len()]
810 }
811}