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 }
139 }
140
141 fn named_types(&mut self, types: &[NamedType]) -> std::fmt::Result {
142 for (i, param) in types.iter().enumerate() {
143 if i > 0 {
144 write!(self.writer, ", ")?;
145 }
146
147 write!(self.writer, "{id}: ", id = self.source(param.id.span))?;
148 self.ty(¶m.ty)?;
149 }
150
151 Ok(())
152 }
153
154 pub fn ty(&mut self, ty: &Type) -> std::fmt::Result {
156 match ty {
157 Type::U8(_) => write!(self.writer, "u8"),
158 Type::S8(_) => write!(self.writer, "s8"),
159 Type::U16(_) => write!(self.writer, "u16"),
160 Type::S16(_) => write!(self.writer, "s16"),
161 Type::U32(_) => write!(self.writer, "u32"),
162 Type::S32(_) => write!(self.writer, "s32"),
163 Type::U64(_) => write!(self.writer, "u64"),
164 Type::S64(_) => write!(self.writer, "s64"),
165 Type::F32(_) => write!(self.writer, "f32"),
166 Type::F64(_) => write!(self.writer, "f64"),
167 Type::Char(_) => write!(self.writer, "char"),
168 Type::Bool(_) => write!(self.writer, "bool"),
169 Type::String(_) => write!(self.writer, "string"),
170 Type::Tuple(types, _) => {
171 write!(self.writer, "tuple<")?;
172 for (i, ty) in types.iter().enumerate() {
173 if i > 0 {
174 write!(self.writer, ", ")?;
175 }
176
177 self.ty(ty)?;
178 }
179
180 write!(self.writer, ">")
181 }
182 Type::List(ty, _) => {
183 write!(self.writer, "list<")?;
184 self.ty(ty)?;
185 write!(self.writer, ">")
186 }
187 Type::Option(ty, _) => {
188 write!(self.writer, "option<")?;
189 self.ty(ty)?;
190 write!(self.writer, ">")
191 }
192 Type::Result { ok, err, .. } => match (ok, err) {
193 (None, None) => write!(self.writer, "result"),
194 (None, Some(err)) => {
195 write!(self.writer, "result<_, ")?;
196 self.ty(err)?;
197 write!(self.writer, ">")
198 }
199 (Some(ok), None) => {
200 write!(self.writer, "result<")?;
201 self.ty(ok)?;
202 write!(self.writer, ">")
203 }
204 (Some(ok), Some(err)) => {
205 write!(self.writer, "result<")?;
206 self.ty(ok)?;
207 write!(self.writer, ", ")?;
208 self.ty(err)?;
209 write!(self.writer, ">")
210 }
211 },
212 Type::Borrow(id, _) => {
213 write!(self.writer, "borrow<{id}>", id = self.source(id.span))
214 }
215 Type::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)),
216 }
217 }
218
219 pub fn inline_interface(&mut self, iface: &InlineInterface) -> std::fmt::Result {
221 write!(self.writer, "interface {{")?;
222 self.newline()?;
223
224 self.inc();
225 for (i, item) in iface.items.iter().enumerate() {
226 if i > 0 {
227 self.newline()?;
228 }
229
230 self.interface_item(item)?;
231 self.newline()?;
232 }
233
234 self.dec();
235 self.indent()?;
236 write!(self.writer, "}}")
237 }
238
239 pub fn interface_item(&mut self, item: &InterfaceItem) -> std::fmt::Result {
241 match item {
242 InterfaceItem::Use(u) => self.use_type(u),
243 InterfaceItem::Type(t) => self.item_type_decl(t),
244 InterfaceItem::Export(e) => self.interface_export(e),
245 }
246 }
247
248 pub fn use_type(&mut self, use_ty: &Use) -> std::fmt::Result {
250 self.docs(&use_ty.docs)?;
251 self.indent()?;
252 write!(self.writer, "use ")?;
253 self.use_path(&use_ty.path)?;
254
255 write!(self.writer, ".{{ ")?;
256
257 for (i, item) in use_ty.items.iter().enumerate() {
258 if i > 0 {
259 write!(self.writer, ", ")?;
260 }
261
262 write!(self.writer, "{id}", id = self.source(item.id.span))?;
263 if let Some(as_id) = &item.as_id {
264 write!(self.writer, " as {as_id}", as_id = self.source(as_id.span))?;
265 }
266 }
267
268 write!(self.writer, " }};")
269 }
270
271 pub fn use_path(&mut self, path: &UsePath) -> std::fmt::Result {
273 match path {
274 UsePath::Package(p) => self.package_path(p),
275 UsePath::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)),
276 }
277 }
278
279 pub fn item_type_decl(&mut self, decl: &ItemTypeDecl) -> std::fmt::Result {
281 match decl {
282 ItemTypeDecl::Resource(r) => self.resource_decl(r),
283 ItemTypeDecl::Variant(v) => self.variant_decl(v),
284 ItemTypeDecl::Record(r) => self.record_decl(r),
285 ItemTypeDecl::Flags(f) => self.flags_decl(f),
286 ItemTypeDecl::Enum(e) => self.enum_decl(e),
287 ItemTypeDecl::Alias(a) => self.type_alias(a),
288 }
289 }
290
291 pub fn resource_decl(&mut self, decl: &ResourceDecl) -> std::fmt::Result {
293 self.docs(&decl.docs)?;
294 self.indent()?;
295 write!(
296 self.writer,
297 "resource {id} {{",
298 id = self.source(decl.id.span)
299 )?;
300 self.newline()?;
301
302 self.inc();
303 for (i, method) in decl.methods.iter().enumerate() {
304 if i > 0 {
305 self.newline()?;
306 }
307
308 self.resource_method(method)?;
309 self.newline()?;
310 }
311
312 self.dec();
313 self.indent()?;
314 write!(self.writer, "}}")
315 }
316
317 pub fn resource_method(&mut self, method: &ResourceMethod) -> std::fmt::Result {
319 match method {
320 ResourceMethod::Constructor(c) => self.constructor(c),
321 ResourceMethod::Method(m) => self.method(m),
322 }
323 }
324
325 pub fn constructor(&mut self, constructor: &Constructor) -> std::fmt::Result {
327 self.docs(&constructor.docs)?;
328 self.indent()?;
329 write!(self.writer, "constructor(")?;
330 self.named_types(&constructor.params)?;
331 write!(self.writer, ");")
332 }
333
334 pub fn method(&mut self, method: &Method) -> std::fmt::Result {
336 self.docs(&method.docs)?;
337 self.indent()?;
338 write!(self.writer, "{id}: ", id = self.source(method.id.span))?;
339
340 if method.is_static {
341 write!(self.writer, "static ")?;
342 }
343
344 self.func_type(&method.ty)?;
345 write!(self.writer, ";")
346 }
347
348 pub fn func_type_ref(&mut self, ty: &FuncTypeRef) -> std::fmt::Result {
350 match ty {
351 FuncTypeRef::Func(ty) => self.func_type(ty),
352 FuncTypeRef::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)),
353 }
354 }
355
356 pub fn variant_decl(&mut self, decl: &VariantDecl) -> std::fmt::Result {
358 self.docs(&decl.docs)?;
359 self.indent()?;
360 write!(
361 self.writer,
362 "variant {id} {{",
363 id = self.source(decl.id.span)
364 )?;
365 self.newline()?;
366
367 self.inc();
368 for case in &decl.cases {
369 self.indent()?;
370 self.variant_case(case)?;
371 write!(self.writer, ",")?;
372 self.newline()?;
373 }
374
375 self.dec();
376 self.indent()?;
377 write!(self.writer, "}}")
378 }
379
380 pub fn variant_case(&mut self, case: &VariantCase) -> std::fmt::Result {
382 self.docs(&case.docs)?;
383 self.indent()?;
384 write!(self.writer, "{id}", id = self.source(case.id.span))?;
385
386 if let Some(ty) = &case.ty {
387 write!(self.writer, "(")?;
388 self.ty(ty)?;
389 write!(self.writer, ")")?;
390 }
391
392 Ok(())
393 }
394
395 pub fn record_decl(&mut self, decl: &RecordDecl) -> std::fmt::Result {
397 self.docs(&decl.docs)?;
398 self.indent()?;
399 write!(
400 self.writer,
401 "record {id} {{",
402 id = self.source(decl.id.span)
403 )?;
404 self.newline()?;
405
406 self.inc();
407 for field in &decl.fields {
408 self.docs(&field.docs)?;
409 self.indent()?;
410 write!(self.writer, "{id}: ", id = self.source(field.id.span))?;
411 self.ty(&field.ty)?;
412 write!(self.writer, ",")?;
413 self.newline()?;
414 }
415
416 self.dec();
417 self.indent()?;
418 write!(self.writer, "}}")
419 }
420
421 pub fn flags_decl(&mut self, decl: &FlagsDecl) -> std::fmt::Result {
423 self.docs(&decl.docs)?;
424 self.indent()?;
425 write!(self.writer, "flags {id} {{", id = self.source(decl.id.span))?;
426 self.newline()?;
427
428 self.inc();
429 for flag in &decl.flags {
430 self.docs(&flag.docs)?;
431 self.indent()?;
432 write!(self.writer, "{id},", id = self.source(flag.id.span))?;
433 self.newline()?;
434 }
435
436 self.dec();
437 self.indent()?;
438 write!(self.writer, "}}")
439 }
440
441 pub fn enum_decl(&mut self, decl: &EnumDecl) -> std::fmt::Result {
443 self.docs(&decl.docs)?;
444 self.indent()?;
445 write!(self.writer, "enum {id} {{", id = self.source(decl.id.span))?;
446 self.newline()?;
447
448 self.inc();
449 for case in &decl.cases {
450 self.docs(&case.docs)?;
451 self.indent()?;
452 write!(self.writer, "{id},", id = self.source(case.id.span))?;
453 self.newline()?;
454 }
455
456 self.dec();
457 self.indent()?;
458 write!(self.writer, "}}")
459 }
460
461 pub fn type_alias(&mut self, alias: &TypeAlias) -> std::fmt::Result {
463 self.docs(&alias.docs)?;
464 self.indent()?;
465 write!(self.writer, "type {id} = ", id = self.source(alias.id.span))?;
466 match &alias.kind {
467 TypeAliasKind::Func(ty) => self.func_type(ty)?,
468 TypeAliasKind::Type(ty) => self.ty(ty)?,
469 }
470
471 write!(self.writer, ";")
472 }
473
474 pub fn interface_export(&mut self, export: &InterfaceExport) -> std::fmt::Result {
476 self.docs(&export.docs)?;
477 self.indent()?;
478 write!(self.writer, "{id}: ", id = self.source(export.id.span))?;
479 self.func_type_ref(&export.ty)?;
480 write!(self.writer, ";")
481 }
482
483 pub fn type_statement(&mut self, stmt: &TypeStatement) -> std::fmt::Result {
485 match stmt {
486 TypeStatement::Interface(i) => self.interface_decl(i),
487 TypeStatement::World(w) => self.world_decl(w),
488 TypeStatement::Type(t) => self.type_decl(t),
489 }
490 }
491
492 pub fn interface_decl(&mut self, decl: &InterfaceDecl) -> std::fmt::Result {
494 self.docs(&decl.docs)?;
495 self.indent()?;
496 write!(
497 self.writer,
498 "interface {id} {{",
499 id = self.source(decl.id.span)
500 )?;
501 self.newline()?;
502
503 self.inc();
504 for (i, item) in decl.items.iter().enumerate() {
505 if i > 0 {
506 self.newline()?;
507 }
508
509 self.interface_item(item)?;
510 self.newline()?;
511 }
512
513 self.dec();
514 self.indent()?;
515 write!(self.writer, "}}")
516 }
517
518 pub fn world_decl(&mut self, decl: &WorldDecl) -> std::fmt::Result {
520 self.docs(&decl.docs)?;
521 self.indent()?;
522 write!(self.writer, "world {id} {{", id = self.source(decl.id.span))?;
523 self.newline()?;
524
525 self.inc();
526 for (i, item) in decl.items.iter().enumerate() {
527 if i > 0 {
528 self.newline()?;
529 }
530
531 self.world_item(item)?;
532 self.newline()?;
533 }
534
535 self.dec();
536 self.indent()?;
537 write!(self.writer, "}}")
538 }
539
540 pub fn world_item(&mut self, item: &WorldItem) -> std::fmt::Result {
542 match item {
543 WorldItem::Use(u) => self.use_type(u),
544 WorldItem::Type(t) => self.item_type_decl(t),
545 WorldItem::Import(i) => self.world_import(i),
546 WorldItem::Export(e) => self.world_export(e),
547 WorldItem::Include(i) => self.world_include(i),
548 }
549 }
550
551 pub fn world_import(&mut self, import: &WorldImport) -> std::fmt::Result {
553 self.docs(&import.docs)?;
554 self.indent()?;
555 write!(self.writer, "import ")?;
556
557 self.world_item_path(&import.path)?;
558 write!(self.writer, ";")
559 }
560
561 pub fn world_export(&mut self, export: &WorldExport) -> std::fmt::Result {
563 self.docs(&export.docs)?;
564 self.indent()?;
565 write!(self.writer, "export ")?;
566
567 self.world_item_path(&export.path)?;
568 write!(self.writer, ";")
569 }
570
571 pub fn world_item_path(&mut self, path: &WorldItemPath) -> std::fmt::Result {
573 match path {
574 WorldItemPath::Named(n) => self.named_world_item(n),
575 WorldItemPath::Package(p) => self.package_path(p),
576 WorldItemPath::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)),
577 }
578 }
579
580 pub fn named_world_item(&mut self, item: &NamedWorldItem) -> std::fmt::Result {
582 write!(self.writer, "{id}: ", id = self.source(item.id.span))?;
583 self.extern_type(&item.ty)
584 }
585
586 pub fn extern_type(&mut self, ty: &ExternType) -> std::fmt::Result {
588 match ty {
589 ExternType::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)),
590 ExternType::Func(ty) => self.func_type(ty),
591 ExternType::Interface(i) => self.inline_interface(i),
592 }
593 }
594
595 pub fn world_include(&mut self, include: &WorldInclude) -> std::fmt::Result {
597 self.docs(&include.docs)?;
598 self.indent()?;
599 write!(self.writer, "include ")?;
600 self.world_ref(&include.world)?;
601
602 if !include.with.is_empty() {
603 write!(self.writer, " with {{")?;
604 self.newline()?;
605 self.inc();
606
607 for item in &include.with {
608 self.indent()?;
609 write!(
610 self.writer,
611 "{source} as {target},",
612 source = self.source(item.from.span),
613 target = self.source(item.to.span)
614 )?;
615 self.newline()?;
616 }
617
618 self.dec();
619 self.indent()?;
620 write!(self.writer, "}}")?;
621 }
622
623 write!(self.writer, ";")
624 }
625
626 pub fn world_ref(&mut self, reference: &WorldRef) -> std::fmt::Result {
628 match reference {
629 WorldRef::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)),
630 WorldRef::Package(p) => self.package_path(p),
631 }
632 }
633
634 pub fn type_decl(&mut self, decl: &TypeDecl) -> std::fmt::Result {
636 match decl {
637 TypeDecl::Variant(v) => self.variant_decl(v),
638 TypeDecl::Record(r) => self.record_decl(r),
639 TypeDecl::Flags(f) => self.flags_decl(f),
640 TypeDecl::Enum(e) => self.enum_decl(e),
641 TypeDecl::Alias(a) => self.type_alias(a),
642 }
643 }
644
645 pub fn let_statement(&mut self, stmt: &LetStatement) -> std::fmt::Result {
647 self.docs(&stmt.docs)?;
648 self.indent()?;
649 write!(self.writer, "let {id} = ", id = self.source(stmt.id.span))?;
650 self.expr(&stmt.expr)?;
651 write!(self.writer, ";")
652 }
653
654 pub fn expr(&mut self, expr: &Expr) -> std::fmt::Result {
656 self.primary_expr(&expr.primary)?;
657 for postfix in &expr.postfix {
658 self.postfix_expr(postfix)?;
659 }
660
661 Ok(())
662 }
663
664 pub fn primary_expr(&mut self, expr: &PrimaryExpr) -> std::fmt::Result {
666 match expr {
667 PrimaryExpr::New(e) => self.new_expr(e),
668 PrimaryExpr::Nested(e) => {
669 write!(self.writer, "(")?;
670 self.expr(&e.inner)?;
671 write!(self.writer, ")")
672 }
673 PrimaryExpr::Ident(id) => write!(self.writer, "{id}", id = self.source(id.span)),
674 }
675 }
676
677 pub fn new_expr(&mut self, expr: &NewExpr) -> std::fmt::Result {
679 write!(
680 self.writer,
681 "new {name} {{",
682 name = self.source(expr.package.span)
683 )?;
684
685 if expr.arguments.is_empty() {
686 write!(self.writer, "}}")?;
687 return Ok(());
688 }
689
690 if expr.arguments.len() == 1 {
691 if let InstantiationArgument::Fill(_) = expr.arguments[0] {
692 write!(self.writer, " ... }}")?;
693 return Ok(());
694 }
695 }
696
697 self.newline()?;
698 self.inc();
699
700 for arg in &expr.arguments {
701 self.indent()?;
702
703 match arg {
704 InstantiationArgument::Inferred(id) => {
705 write!(self.writer, "{id},", id = self.source(id.span))?
706 }
707 InstantiationArgument::Spread(id) => {
708 write!(self.writer, "...{id},", id = self.source(id.span))?
709 }
710 InstantiationArgument::Named(arg) => {
711 match &arg.name {
712 InstantiationArgumentName::Ident(id) => {
713 write!(self.writer, "{id}: ", id = self.source(id.span))?;
714 }
715 InstantiationArgumentName::String(s) => {
716 write!(self.writer, "{s}: ", s = self.source(s.span))?;
717 }
718 }
719 self.expr(&arg.expr)?;
720 write!(self.writer, ",")?;
721 }
722 InstantiationArgument::Fill(_) => write!(self.writer, "...")?,
723 }
724
725 self.newline()?;
726 }
727
728 self.dec();
729 self.indent()?;
730 write!(self.writer, "}}")
731 }
732
733 pub fn postfix_expr(&mut self, expr: &PostfixExpr) -> std::fmt::Result {
735 match expr {
736 PostfixExpr::Access(a) => self.access_expr(a),
737 PostfixExpr::NamedAccess(a) => self.named_access_expr(a),
738 }
739 }
740
741 pub fn access_expr(&mut self, expr: &AccessExpr) -> std::fmt::Result {
743 write!(self.writer, ".{id}", id = self.source(expr.id.span))
744 }
745
746 pub fn named_access_expr(&mut self, expr: &NamedAccessExpr) -> std::fmt::Result {
748 write!(
749 self.writer,
750 "[{name}]",
751 name = self.source(expr.string.span)
752 )
753 }
754
755 pub fn export_statement(&mut self, stmt: &ExportStatement) -> std::fmt::Result {
757 self.docs(&stmt.docs)?;
758 self.indent()?;
759
760 write!(self.writer, "export ")?;
761
762 self.expr(&stmt.expr)?;
763
764 match &stmt.options {
765 ExportOptions::None => {}
766 ExportOptions::Spread(_) => {
767 write!(self.writer, "...")?;
768 }
769 ExportOptions::Rename(name) => {
770 write!(self.writer, " as {name}", name = self.source(name.span()))?;
771 }
772 }
773
774 write!(self.writer, ";")
775 }
776
777 fn newline(&mut self) -> std::fmt::Result {
778 writeln!(self.writer)?;
779 self.indented = false;
780 Ok(())
781 }
782
783 fn indent(&mut self) -> std::fmt::Result {
784 if !self.indented {
785 for _ in 0..self.indent {
786 write!(self.writer, "{space}", space = self.space)?;
787 }
788
789 self.indented = true;
790 }
791
792 Ok(())
793 }
794
795 fn inc(&mut self) {
796 self.indent = self.indent.saturating_add(1);
797 }
798
799 fn dec(&mut self) {
800 self.indent = self.indent.saturating_sub(1);
801 }
802
803 fn source(&self, span: SourceSpan) -> &'a str {
804 &self.source[span.offset()..span.offset() + span.len()]
805 }
806}