wac_parser/ast/
printer.rs

1//! Module for printing WAC documents.
2
3use crate::ast::*;
4use std::fmt::Write;
5
6/// A printer for WAC documents.
7pub 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    /// Creates a new document printer for the given write.
17    ///
18    /// If `space` is `None`, then the printer will use four spaces for
19    /// indentation.
20    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    /// Prints the given document.
31    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    /// Prints the given package directive.
48    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    /// Prints the given statement.
66    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    /// Prints the given doc comments.
76    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    /// Prints the given import statement.
89    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    /// Prints the given import type.
111    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    /// Prints the given package path.
121    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    /// Prints the given function type.
127    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(&param.ty)?;
154        }
155
156        Ok(())
157    }
158
159    /// Prints the given type.
160    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    /// Prints the given inline interface.
225    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    /// Prints the given interface export.
245    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    /// Prints the given use type.
254    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    /// Prints the given use path.
277    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    /// Prints the given type declaration.
285    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    /// Prints the given resource declaration.
297    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    /// Prints the given resource method.
323    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    /// Prints the given constructor.
331    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    /// Prints the given method.
340    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    /// Prints the given function type reference.
354    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    /// Prints the given variant declaration.
362    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    /// Prints the given variant case.
386    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    /// Prints the given record declaration.
401    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    /// Prints the given flags declaration.
427    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    /// Prints the given enum declaration.
447    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    /// Prints the given type alias.
467    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    /// Prints the given interface export.
480    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    /// Prints the given type statement.
489    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    /// Prints the given interface declaration.
498    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    /// Prints the given world declaration.
524    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    /// Prints the given world item.
546    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    /// Prints the given world import.
557    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    /// Prints the given world export.
567    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    /// Prints the given world item path.
577    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    /// Prints the given named world item.
586    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    /// Prints the given extern type.
592    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    /// Prints the given world include.
601    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    /// Prints the given world reference.
632    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    /// Prints the given type declaration.
640    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    /// Prints the given let statement.
651    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    /// Prints the given expression.
660    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    /// Prints the given primary expression.
670    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    /// Prints the given new expression.
683    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    /// Prints the given postfix expression.
739    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    /// Prints the given access expression.
747    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    /// Prints the given named access expression.
752    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    /// Prints the given export statement.
761    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}