1use 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#[derive(Debug, Default)]
58pub struct SourceGenerator {
59 options: SourceGeneratorOptions,
60}
61
62#[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
77const 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
92impl 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
121impl 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
140const 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 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 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}