Skip to main content

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