Skip to main content

sdml_generate/convert/
source.rs

1/*!
2This module provides a generator that recreates the surface syntax for a module given its
3in-memory representation.
4
5# Example
6
7```rust
8use sdml_core::store::InMemoryModuleCache;
9use sdml_core::model::modules::Module;
10use sdml_generate::Generator;
11use sdml_generate::convert::source::{SourceGenerator, SourceGeneratorOptions};
12use std::io::stdout;
13# use sdml_core::model::identifiers::Identifier;
14# fn load_module() -> (Module, InMemoryModuleCache) { (Module::empty(Identifier::new_unchecked("example")), InMemoryModuleCache::default()) }
15# sdml_generate::color::set_colorize(sdml_errors::diagnostics::color::UseColor::Never);
16
17let (module, cache) = load_module();
18
19let mut generator: SourceGenerator = Default::default();
20let options = SourceGeneratorOptions::default();
21let source = generator
22    .generate_to_string(&module, &cache, options, None)
23    .expect("write to stdout failed");
24assert_eq!(source.as_str(), "module example is end\n");
25
26```
27*/
28
29use crate::color::sdml::{
30    braces_end, braces_start, format_url, import, keyword, member_name, module_name_def, operator,
31    paren_end, paren_start, property_name, sequence_end, sequence_start, type_name_def,
32    type_name_ref, type_variant_name_def, type_variant_ref_def, value_variant_name_def,
33};
34use crate::Generator;
35use sdml_core::error::Error;
36use sdml_core::model::annotations::{Annotation, AnnotationProperty, HasAnnotations};
37use sdml_core::model::constraints::{Constraint, ConstraintBody};
38use sdml_core::model::definitions::{
39    DatatypeDef, Definition, EntityDef, EnumDef, EventDef, HasMembers, HasVariants, PropertyDef,
40    RdfDef, StructureDef, TypeVariant, UnionDef, ValueVariant,
41};
42use sdml_core::model::identifiers::IdentifierReference;
43use sdml_core::model::members::{
44    Cardinality, Member, MemberDef, MemberKind, TypeReference, DEFAULT_CARDINALITY,
45};
46use sdml_core::model::modules::{Module, ModuleBody};
47use sdml_core::model::{HasBody, HasName, HasNameReference, HasOptionalBody};
48use sdml_core::store::ModuleStore;
49use std::path::PathBuf;
50use std::{fmt::Debug, io::Write};
51
52// ------------------------------------------------------------------------------------------------
53// Public Types
54// ------------------------------------------------------------------------------------------------
55
56/// The type that implements the generator.
57#[derive(Debug, Default)]
58pub struct SourceGenerator {
59    options: SourceGeneratorOptions,
60}
61
62/// The type that implements the generator.
63#[derive(Debug)]
64pub struct SourceGeneratorOptions {
65    indentation: usize,
66    level: SourceGenerationLevel,
67}
68
69#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
70pub enum SourceGenerationLevel {
71    #[default]
72    Full,
73    Members,
74    Definitions,
75}
76
77// ------------------------------------------------------------------------------------------------
78// Private Types
79// ------------------------------------------------------------------------------------------------
80
81const DEFAULT_INDENTATION: usize = 2;
82
83const MODULE_ANNOTATION_INDENT: usize = 1;
84const MODULE_IMPORT_INDENT: usize = 1;
85const MODULE_DEFINITION_INDENT: usize = 1;
86const DEFINITION_ANNOTATION_INDENT: usize = 2;
87const DEFINITION_MEMBER_INDENT: usize = 2;
88const MEMBER_ANNOTATION_INDENT: usize = 3;
89
90const ELIPPSIS: &str = " ;; ...\n";
91
92// ------------------------------------------------------------------------------------------------
93// Implementations
94// ------------------------------------------------------------------------------------------------
95
96impl Default for SourceGeneratorOptions {
97    fn default() -> Self {
98        Self {
99            indentation: DEFAULT_INDENTATION,
100            level: Default::default(),
101        }
102    }
103}
104
105impl SourceGeneratorOptions {
106    pub fn with_level(self, level: SourceGenerationLevel) -> Self {
107        Self { level, ..self }
108    }
109    pub fn with_indentation(self, indentation: usize) -> Self {
110        Self {
111            indentation,
112            ..self
113        }
114    }
115    fn indentation_str(&self, level: usize) -> String {
116        let n = level * self.indentation;
117        format!("{:n$}", "")
118    }
119}
120
121// ------------------------------------------------------------------------------------------------
122
123impl SourceGenerationLevel {
124    #[inline(always)]
125    const fn generate_definition_bodies(&self) -> bool {
126        matches!(self, Self::Full | Self::Members)
127    }
128
129    #[inline(always)]
130    const fn generate_member_bodies(&self) -> bool {
131        matches!(self, Self::Full)
132    }
133
134    #[inline(always)]
135    const fn generate_variant_bodies(&self) -> bool {
136        matches!(self, Self::Full)
137    }
138}
139
140// ------------------------------------------------------------------------------------------------
141
142const EOL: &[u8] = b"\n";
143
144impl Generator for SourceGenerator {
145    type Options = SourceGeneratorOptions;
146
147    fn generate_with_options<W>(
148        &mut self,
149        module: &Module,
150        _: &impl ModuleStore,
151        options: Self::Options,
152        _: Option<PathBuf>,
153        writer: &mut W,
154    ) -> Result<(), Error>
155    where
156        W: Write + Sized,
157    {
158        self.options = options;
159
160        writer.write_all(
161            format!("{} {} ", keyword("module"), module_name_def(module.name())).as_bytes(),
162        )?;
163
164        if let Some(base) = module.base_uri() {
165            writer.write_all(format!("{} ", format_url(base.as_ref())).as_bytes())?;
166        }
167
168        let body = module.body();
169        if body.has_imports() || body.has_annotations() || body.has_definitions() {
170            writer.write_all(format!("{}\n", keyword("is")).as_bytes())?;
171
172            if body.has_imports() {
173                writer.write_all(EOL)?;
174                self.write_module_imports(body, writer)?;
175            }
176
177            if body.has_annotations() {
178                writer.write_all(EOL)?;
179                self.write_annotations(body.annotations(), writer, MODULE_ANNOTATION_INDENT)?;
180            }
181            if body.has_definitions() {
182                self.write_module_definitions(body, writer)?;
183            }
184
185            writer.write_all(format!("\n{}\n", keyword("end")).as_bytes())?;
186        } else {
187            writer.write_all(format!("{} {}\n", keyword("is"), keyword("end")).as_bytes())?;
188        }
189        Ok(())
190    }
191}
192
193impl SourceGenerator {
194    fn write_module_imports(
195        &mut self,
196        module_body: &ModuleBody,
197        writer: &mut dyn Write,
198    ) -> Result<(), Error> {
199        let indentation = self.options.indentation_str(MODULE_IMPORT_INDENT);
200        if module_body.has_imports() {
201            for import_statement in module_body.imports() {
202                let imported = if import_statement.imports_len() == 1 {
203                    import_statement
204                        .imports()
205                        .map(import)
206                        .collect::<Vec<String>>()
207                        .join("")
208                } else {
209                    format!(
210                        "{} {} {}",
211                        sequence_start(),
212                        import_statement
213                            .imports()
214                            .map(import)
215                            .collect::<Vec<String>>()
216                            .join(" "),
217                        sequence_end(),
218                    )
219                };
220                writer.write_all(
221                    format!("{indentation}{} {imported}\n", keyword("import")).as_bytes(),
222                )?;
223            }
224        }
225        Ok(())
226    }
227
228    #[allow(single_use_lifetimes)]
229    fn write_annotations<'a>(
230        &mut self,
231        annotations: impl Iterator<Item = &'a Annotation>,
232        writer: &mut dyn Write,
233        indent_level: usize,
234    ) -> Result<(), Error> {
235        for annotation in annotations {
236            match annotation {
237                Annotation::Property(v) => {
238                    self.write_annotation_property(v, writer, indent_level)?
239                }
240                Annotation::Constraint(v) => self.write_constraint(v, writer, indent_level)?,
241            }
242        }
243
244        Ok(())
245    }
246
247    fn write_annotation_property(
248        &mut self,
249        annotation: &AnnotationProperty,
250        writer: &mut dyn Write,
251        indent_level: usize,
252    ) -> Result<(), Error> {
253        let indentation = self.options.indentation_str(indent_level);
254        // TODO: ensure wrapping
255        writer.write_all(
256            format!(
257                "{indentation}{} {} {}\n",
258                property_name(annotation.name_reference()),
259                operator("="),
260                annotation.value()
261            )
262            .as_bytes(),
263        )?;
264        Ok(())
265    }
266
267    fn write_constraint(
268        &mut self,
269        constraint: &Constraint,
270        writer: &mut dyn Write,
271        indent_level: usize,
272    ) -> Result<(), Error> {
273        let indentation = self.options.indentation_str(indent_level);
274        writer.write_all(format!("{indentation}{} ", keyword("assert")).as_bytes())?;
275        writer.write_all(format!("{} ", constraint.name()).as_bytes())?;
276        match constraint.body() {
277            ConstraintBody::Informal(v) => {
278                writer.write_all(format!("{} {v:?}", operator("=")).as_bytes())?;
279            }
280            ConstraintBody::Formal(_) => {
281                writer.write_all(format!("{}\n", keyword("is")).as_bytes())?;
282                // TODO: add constraint sentence
283                writer.write_all(format!("{indentation}{}\n", keyword("end")).as_bytes())?;
284            }
285        }
286        Ok(())
287    }
288
289    fn write_module_definitions(
290        &mut self,
291        module_body: &ModuleBody,
292        writer: &mut dyn Write,
293    ) -> Result<(), Error> {
294        let _indentation = self.options.indentation_str(1);
295        if module_body.has_definitions() {
296            for definition in module_body.definitions() {
297                writer.write_all(EOL)?;
298                match &definition {
299                    Definition::Datatype(v) => self.write_datatype(v, writer)?,
300                    Definition::Entity(v) => self.write_entity(v, writer)?,
301                    Definition::Enum(v) => self.write_enum(v, writer)?,
302                    Definition::Event(v) => self.write_event(v, writer)?,
303                    Definition::Property(v) => self.write_property(v, writer)?,
304                    Definition::Structure(v) => self.write_structure(v, writer)?,
305                    Definition::Rdf(v) => self.write_rdf(v, writer)?,
306                    Definition::TypeClass(_) => todo!(),
307                    Definition::Union(v) => self.write_union(v, writer)?,
308                }
309            }
310        }
311        Ok(())
312    }
313
314    fn write_datatype(&mut self, defn: &DatatypeDef, writer: &mut dyn Write) -> Result<(), Error> {
315        let indentation = self.options.indentation_str(MODULE_DEFINITION_INDENT);
316        writer.write_all(
317            format!(
318                "{indentation}{} {} {} {}",
319                keyword("datatype"),
320                type_name_def(defn.name()),
321                operator("<-"),
322                type_name_ref(defn.base_type())
323            )
324            .as_bytes(),
325        )?;
326
327        if let Some(body) = defn.body() {
328            if self.options.level.generate_definition_bodies() {
329                writer.write_all(format!(" {}\n", keyword("is")).as_bytes())?;
330                if body.has_annotations() {
331                    self.write_annotations(
332                        body.annotations(),
333                        writer,
334                        DEFINITION_ANNOTATION_INDENT,
335                    )?;
336                }
337                writer.write_all(format!("{indentation}{}\n", keyword("end")).as_bytes())?;
338            } else {
339                writer.write_all(ELIPPSIS.as_bytes())?;
340            }
341        } else {
342            writer.write_all(EOL)?;
343        }
344
345        Ok(())
346    }
347
348    fn write_entity(&mut self, defn: &EntityDef, writer: &mut dyn Write) -> Result<(), Error> {
349        let indentation = self.options.indentation_str(MODULE_DEFINITION_INDENT);
350        writer.write_all(
351            format!(
352                "{indentation}{} {}",
353                keyword("entity"),
354                type_name_def(defn.name())
355            )
356            .as_bytes(),
357        )?;
358
359        if let Some(body) = defn.body() {
360            if self.options.level.generate_definition_bodies() {
361                writer.write_all(format!(" {}\n", keyword("is")).as_bytes())?;
362                if body.has_annotations() {
363                    self.write_annotations(
364                        body.annotations(),
365                        writer,
366                        DEFINITION_ANNOTATION_INDENT,
367                    )?;
368                    if body.has_members() {
369                        writer.write_all(EOL)?;
370                    }
371                }
372                for member in body.members() {
373                    self.write_member(member, writer)?;
374                }
375                writer.write_all(format!("{indentation}{}\n", keyword("end")).as_bytes())?;
376            } else {
377                writer.write_all(ELIPPSIS.as_bytes())?;
378            }
379        } else {
380            writer.write_all(EOL)?;
381        }
382
383        Ok(())
384    }
385
386    fn write_enum(&mut self, defn: &EnumDef, writer: &mut dyn Write) -> Result<(), Error> {
387        let indentation = self.options.indentation_str(MODULE_DEFINITION_INDENT);
388        writer.write_all(
389            format!(
390                "{indentation}{} {}",
391                keyword("enum"),
392                type_name_def(defn.name())
393            )
394            .as_bytes(),
395        )?;
396
397        if let Some(body) = defn.body() {
398            if self.options.level.generate_definition_bodies() {
399                writer.write_all(format!(" {}\n", keyword("of")).as_bytes())?;
400                if body.has_annotations() {
401                    self.write_annotations(
402                        body.annotations(),
403                        writer,
404                        DEFINITION_ANNOTATION_INDENT,
405                    )?;
406                    if body.has_variants() {
407                        writer.write_all(EOL)?;
408                    }
409                }
410                if body.has_variants() {
411                    for variant in body.variants() {
412                        self.write_value_variant(variant, writer)?;
413                    }
414                }
415                writer.write_all(format!("{indentation}{}\n", keyword("end")).as_bytes())?;
416            } else {
417                writer.write_all(ELIPPSIS.as_bytes())?;
418            }
419        } else {
420            writer.write_all(EOL)?;
421        }
422
423        Ok(())
424    }
425
426    fn write_value_variant(
427        &mut self,
428        variant: &ValueVariant,
429        writer: &mut dyn Write,
430    ) -> Result<(), Error> {
431        let indentation = self.options.indentation_str(DEFINITION_MEMBER_INDENT);
432        writer.write_all(
433            format!("{indentation}{}", value_variant_name_def(variant.name())).as_bytes(),
434        )?;
435
436        if let Some(body) = variant.body() {
437            if self.options.level.generate_member_bodies() {
438                writer.write_all(format!(" {}\n", keyword("is")).as_bytes())?;
439                if body.has_annotations() {
440                    self.write_annotations(body.annotations(), writer, MEMBER_ANNOTATION_INDENT)?;
441                }
442                writer.write_all(format!("{indentation}{}\n", keyword("end")).as_bytes())?;
443            } else {
444                writer.write_all(ELIPPSIS.as_bytes())?;
445            }
446        } else {
447            writer.write_all(EOL)?;
448        }
449
450        Ok(())
451    }
452
453    fn write_event(&mut self, defn: &EventDef, writer: &mut dyn Write) -> Result<(), Error> {
454        let indentation = self.options.indentation_str(MODULE_DEFINITION_INDENT);
455        writer.write_all(
456            format!(
457                "{indentation}{} {} {} {}",
458                keyword("event"),
459                type_name_def(defn.name()),
460                keyword("source"),
461                type_name_ref(defn.event_source())
462            )
463            .as_bytes(),
464        )?;
465
466        if let Some(body) = defn.body() {
467            if self.options.level.generate_definition_bodies() {
468                writer.write_all(format!(" {}\n", keyword("is")).as_bytes())?;
469                if body.has_annotations() {
470                    self.write_annotations(
471                        body.annotations(),
472                        writer,
473                        DEFINITION_ANNOTATION_INDENT,
474                    )?;
475                    if body.has_members() {
476                        writer.write_all(EOL)?;
477                    }
478                }
479                for member in body.members() {
480                    self.write_member(member, writer)?;
481                }
482                writer.write_all(format!("{indentation}{}\n", keyword("end")).as_bytes())?;
483            } else {
484                writer.write_all(ELIPPSIS.as_bytes())?;
485            }
486        } else {
487            writer.write_all(EOL)?;
488        }
489
490        Ok(())
491    }
492
493    fn write_member(&mut self, defn: &Member, writer: &mut dyn Write) -> Result<(), Error> {
494        let indentation = self.options.indentation_str(DEFINITION_MEMBER_INDENT);
495        match defn.kind() {
496            MemberKind::Reference(v) => self.write_member_reference(v, &indentation, writer),
497            MemberKind::Definition(v) => self.write_member_definition(v, &indentation, writer),
498        }
499    }
500
501    fn write_member_definition(
502        &mut self,
503        defn: &MemberDef,
504        indentation: &str,
505        writer: &mut dyn Write,
506    ) -> Result<(), Error> {
507        self.write_member_definition_inner(
508            defn,
509            indentation,
510            MEMBER_ANNOTATION_INDENT,
511            indentation,
512            writer,
513        )
514    }
515
516    fn write_member_definition_inner(
517        &mut self,
518        defn: &MemberDef,
519        initial_indentation: &str,
520        annotation_indentation: usize,
521        end_indentation: &str,
522        writer: &mut dyn Write,
523    ) -> Result<(), Error> {
524        writer.write_all(
525            format!(
526                "{initial_indentation}{} {} ",
527                member_name(defn.name()),
528                operator("->")
529            )
530            .as_bytes(),
531        )?;
532        if *defn.target_cardinality() != DEFAULT_CARDINALITY {
533            self.write_cardinality(defn.target_cardinality(), writer)?;
534        }
535        self.write_type_reference(defn.target_type(), writer)?;
536        if let Some(body) = defn.body() {
537            if body.has_annotations() && self.options.level.generate_member_bodies() {
538                writer.write_all(format!(" {}\n", keyword("is")).as_bytes())?;
539                self.write_annotations(body.annotations(), writer, annotation_indentation)?;
540                writer.write_all(format!("{end_indentation}{}\n", keyword("end")).as_bytes())?;
541            }
542        } else {
543            writer.write_all(EOL)?;
544        }
545        Ok(())
546    }
547
548    fn write_member_reference(
549        &mut self,
550        defn: &IdentifierReference,
551        indentation: &str,
552        writer: &mut dyn Write,
553    ) -> Result<(), Error> {
554        writer.write_all(format!("{indentation}ref {}\n", defn).as_bytes())?;
555        Ok(())
556    }
557
558    fn write_cardinality(
559        &mut self,
560        defn: &Cardinality,
561        writer: &mut dyn Write,
562    ) -> Result<(), Error> {
563        writer.write_all(
564            format!(
565                "{}{}{}{}{}{} ",
566                braces_start(),
567                if let Some(uniqueness) = defn.uniqueness() {
568                    format!("{} ", keyword(uniqueness.to_string()))
569                } else {
570                    String::new()
571                },
572                if let Some(ordering) = defn.ordering() {
573                    format!("{} ", keyword(ordering.to_string()))
574                } else {
575                    String::new()
576                },
577                defn.min_occurs(),
578                if let Some(max_occurs) = defn.max_occurs() {
579                    if max_occurs == defn.min_occurs() {
580                        String::new()
581                    } else {
582                        format!("{}{}", operator(".."), max_occurs)
583                    }
584                } else {
585                    operator("..")
586                },
587                braces_end()
588            )
589            .as_bytes(),
590        )?;
591        Ok(())
592    }
593
594    #[allow(clippy::only_used_in_recursion)]
595    fn write_type_reference(
596        &mut self,
597        defn: &TypeReference,
598        writer: &mut dyn Write,
599    ) -> Result<(), Error> {
600        match defn {
601            TypeReference::Unknown => {
602                writer.write_all(keyword("unknown").as_bytes())?;
603            }
604            TypeReference::Type(name_ref) => {
605                writer.write_all(type_name_ref(name_ref).as_bytes())?;
606            }
607            TypeReference::MappingType(map_ref) => {
608                writer.write_all(paren_start().as_bytes())?;
609                self.write_type_reference(map_ref.domain(), writer)?;
610                writer.write_all(operator("->").as_bytes())?;
611                self.write_type_reference(map_ref.range(), writer)?;
612                writer.write_all(paren_end().as_bytes())?;
613            }
614        }
615        Ok(())
616    }
617
618    fn write_property(&mut self, defn: &PropertyDef, writer: &mut dyn Write) -> Result<(), Error> {
619        let indentation = self.options.indentation_str(MODULE_DEFINITION_INDENT);
620        writer.write_all(format!("{indentation}{} ", keyword("property"),).as_bytes())?;
621
622        self.write_member_definition_inner(
623            defn.member_def(),
624            "",
625            DEFINITION_ANNOTATION_INDENT,
626            &indentation,
627            writer,
628        )
629    }
630
631    fn write_rdf(&mut self, defn: &RdfDef, writer: &mut dyn Write) -> Result<(), Error> {
632        let indentation = self.options.indentation_str(MODULE_DEFINITION_INDENT);
633        writer.write_all(
634            format!(
635                "{indentation}{} {}",
636                keyword("rdf"),
637                type_name_def(defn.name())
638            )
639            .as_bytes(),
640        )?;
641
642        if self.options.level.generate_definition_bodies() {
643            let body = defn.body();
644            writer.write_all(format!(" {}\n", keyword("is")).as_bytes())?;
645            if body.has_annotations() {
646                self.write_annotations(body.annotations(), writer, DEFINITION_ANNOTATION_INDENT)?;
647            }
648            writer.write_all(format!("{indentation}{}\n", keyword("end")).as_bytes())?;
649        } else {
650            writer.write_all(
651                format!(
652                    " {}\n{indentation}{}{indentation}{}\n",
653                    keyword("is"),
654                    ELIPPSIS,
655                    keyword("end"),
656                )
657                .as_bytes(),
658            )?;
659        }
660
661        Ok(())
662    }
663
664    fn write_structure(
665        &mut self,
666        defn: &StructureDef,
667        writer: &mut dyn Write,
668    ) -> Result<(), Error> {
669        let indentation = self.options.indentation_str(MODULE_DEFINITION_INDENT);
670        writer.write_all(
671            format!(
672                "{indentation}{} {}",
673                keyword("structure"),
674                type_name_def(defn.name())
675            )
676            .as_bytes(),
677        )?;
678
679        if let Some(body) = defn.body() {
680            if self.options.level.generate_definition_bodies() {
681                writer.write_all(format!(" {}\n", keyword("is")).as_bytes())?;
682                if body.has_annotations() {
683                    self.write_annotations(
684                        body.annotations(),
685                        writer,
686                        DEFINITION_ANNOTATION_INDENT,
687                    )?;
688                    if body.has_members() {
689                        writer.write_all(EOL)?;
690                    }
691                }
692                for member in body.members() {
693                    self.write_member(member, writer)?;
694                }
695                writer.write_all(format!("{indentation}{}\n", keyword("end")).as_bytes())?;
696            } else {
697                writer.write_all(ELIPPSIS.as_bytes())?;
698            }
699        } else {
700            writer.write_all(EOL)?;
701        }
702
703        Ok(())
704    }
705
706    fn write_union(&mut self, defn: &UnionDef, writer: &mut dyn Write) -> Result<(), Error> {
707        let indentation = self.options.indentation_str(MODULE_DEFINITION_INDENT);
708        writer.write_all(
709            format!(
710                "{indentation}{} {}",
711                keyword("union"),
712                type_name_def(defn.name())
713            )
714            .as_bytes(),
715        )?;
716
717        if let Some(body) = defn.body() {
718            if self.options.level.generate_definition_bodies() {
719                writer.write_all(format!(" {}\n", keyword("of")).as_bytes())?;
720                if body.has_annotations() {
721                    self.write_annotations(
722                        body.annotations(),
723                        writer,
724                        DEFINITION_ANNOTATION_INDENT,
725                    )?;
726                    if body.has_variants() {
727                        writer.write_all(EOL)?;
728                    }
729                }
730                if body.has_variants() {
731                    for variant in body.variants() {
732                        self.write_type_variant(variant, writer)?;
733                    }
734                }
735                writer.write_all(format!("{indentation}{}\n", keyword("end")).as_bytes())?;
736            } else {
737                writer.write_all(ELIPPSIS.as_bytes())?;
738            }
739        } else {
740            writer.write_all(EOL)?;
741        }
742
743        Ok(())
744    }
745
746    fn write_type_variant(
747        &mut self,
748        variant: &TypeVariant,
749        writer: &mut dyn Write,
750    ) -> Result<(), Error> {
751        let indentation = self.options.indentation_str(DEFINITION_MEMBER_INDENT);
752
753        if let Some(rename) = variant.rename() {
754            writer.write_all(
755                format!("{indentation}{}", type_name_ref(variant.name_reference())).as_bytes(),
756            )?;
757            writer.write_all(
758                format!(" {} {}", keyword("as"), type_variant_name_def(rename)).as_bytes(),
759            )?;
760        } else {
761            writer.write_all(
762                format!(
763                    "{indentation}{}",
764                    type_variant_ref_def(variant.name_reference())
765                )
766                .as_bytes(),
767            )?;
768        }
769
770        if let Some(body) = variant.body() {
771            if self.options.level.generate_variant_bodies() {
772                writer.write_all(format!(" {}\n", keyword("is")).as_bytes())?;
773                if body.has_annotations() {
774                    self.write_annotations(body.annotations(), writer, MEMBER_ANNOTATION_INDENT)?;
775                }
776                writer.write_all(format!("{indentation}{}\n", keyword("end")).as_bytes())?;
777            } else {
778                writer.write_all(ELIPPSIS.as_bytes())?;
779            }
780        } else {
781            writer.write_all(EOL)?;
782        }
783
784        Ok(())
785    }
786}