1use crate::load::ModuleLoader;
5use crate::model::definitions::{
6 DatatypeDef, EntityDef, EnumDef, EventDef, PropertyDef, StructureDef, UnionDef,
7};
8use crate::model::References;
9use crate::model::{
10 annotations::{Annotation, HasAnnotations},
11 check::{MaybeIncomplete, Validate},
12 definitions::{Definition, RdfDef, TypeClassDef},
13 identifiers::{Identifier, IdentifierReference, QualifiedIdentifier},
14 HasBody, HasName, HasSourceSpan, Span,
15};
16use crate::store::{InMemoryModuleCache, ModuleStore};
17use sdml_errors::diagnostics::functions::{
18 definition_not_found, imported_module_not_found, library_definition_not_allowed,
19 module_is_incomplete, module_version_info_empty, module_version_mismatch,
20 module_version_not_found, IdentifierCaseConvention,
21};
22use sdml_errors::{Error, FileId};
23use std::collections::HashMap;
24use std::fmt::Display;
25use std::hash::Hash;
26use std::path::PathBuf;
27use std::{collections::HashSet, fmt::Debug};
28use url::Url;
29
30#[cfg(feature = "serde")]
31use serde::{Deserialize, Serialize};
32
33#[derive(Clone, Debug)]
41#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
42pub struct Module {
43 #[cfg_attr(feature = "serde", serde(skip))]
44 source_file: Option<PathBuf>,
45 #[cfg_attr(feature = "serde", serde(skip))]
46 file_id: Option<FileId>,
47 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
48 span: Option<Box<Span>>,
49 name: Identifier,
50 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
51 base_uri: Option<HeaderValue<Url>>,
52 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
53 version_info: Option<HeaderValue<String>>,
54 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
55 version_uri: Option<HeaderValue<Url>>,
56 body: ModuleBody,
57}
58
59#[derive(Clone, Debug)]
60#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
61pub struct HeaderValue<T> {
62 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
63 span: Option<Box<Span>>,
64 value: T,
65}
66
67#[derive(Clone, Debug, Default)]
71#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
72pub struct ModuleBody {
73 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
74 span: Option<Box<Span>>,
75 file_id: Option<FileId>, is_library: bool, imports: Vec<ImportStatement>,
78 annotations: Vec<Annotation>,
79 definitions: Vec<Definition>,
80}
81
82#[derive(Clone, Debug, Default)]
90#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
91pub struct ImportStatement {
92 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
93 span: Option<Box<Span>>,
94 imports: Vec<Import>,
95}
96
97#[derive(Clone, Debug, PartialEq, Eq, Hash)]
101#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
102pub enum Import {
103 Module(ModuleImport),
105 Member(QualifiedIdentifier),
107}
108
109#[derive(Clone, Debug)]
113#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
114pub struct ModuleImport {
115 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
116 span: Option<Box<Span>>,
117 name: Identifier,
118 #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
119 version_uri: Option<HeaderValue<Url>>,
120}
121
122impl_has_source_span_for!(Module);
127
128impl_has_name_for!(Module);
129
130impl HasBody for Module {
131 type Body = ModuleBody;
132
133 fn body(&self) -> &Self::Body {
134 &self.body
135 }
136
137 fn body_mut(&mut self) -> &mut Self::Body {
138 &mut self.body
139 }
140
141 fn set_body(&mut self, body: Self::Body) {
142 let mut body_mut = body;
143 body_mut.file_id = self.file_id;
144 body_mut.set_library_status(self.name());
145 self.body = body_mut;
146 }
147}
148
149impl References for Module {
150 fn referenced_types<'a>(&'a self, names: &mut HashSet<&'a IdentifierReference>) {
151 self.body.referenced_types(names);
152 }
153
154 fn referenced_annotations<'a>(&'a self, names: &mut HashSet<&'a IdentifierReference>) {
155 self.body.referenced_annotations(names);
156 }
157}
158
159impl Module {
160 pub fn empty(name: Identifier) -> Self {
165 Self::new(name, ModuleBody::default())
166 }
167
168 pub fn new(name: Identifier, body: ModuleBody) -> Self {
169 let mut body = body;
170 body.set_library_status(&name);
171 Self {
172 source_file: None,
173 file_id: None,
174 span: None,
175 name,
176 base_uri: None,
177 version_info: None,
178 version_uri: None,
179 body,
180 }
181 }
182
183 pub fn with_source_file(self, source_file: PathBuf) -> Self {
188 Self {
189 source_file: Some(source_file),
190 ..self
191 }
192 }
193
194 pub fn with_base_uri(self, base_uri: Url) -> Self {
195 Self {
196 base_uri: Some(base_uri.into()),
197 ..self
198 }
199 }
200
201 pub fn with_version_info<S>(self, version_info: S) -> Self
202 where
203 S: Into<String>,
204 {
205 Self {
206 version_info: Some(HeaderValue::from(version_info.into())),
207 ..self
208 }
209 }
210
211 pub fn with_version_uri(self, version_uri: Url) -> Self {
212 Self {
213 version_uri: Some(version_uri.into()),
214 ..self
215 }
216 }
217
218 get_and_set!(pub source_file, set_source_file, unset_source_file => optional has_source_file, PathBuf);
219
220 get_and_set!(pub base_uri, set_base_uri, unset_base_uri => optional has_base_uri, HeaderValue<Url>);
221
222 get_and_set!(pub version_info, set_version_info, unset_version_info => optional has_version_info, HeaderValue<String>);
223
224 get_and_set!(pub version_uri, set_version_uri, unset_version_uri => optional has_version_uri, HeaderValue<Url>);
225
226 get_and_set!(pub file_id, set_file_id, unset_file_id => optional has_file_id, FileId);
227
228 delegate!(pub imported_modules, HashSet<&Identifier>, body);
231
232 delegate!(pub imported_module_versions, HashMap<&Identifier, Option<&HeaderValue<Url>>>, body);
233
234 delegate!(pub imported_types, HashSet<&QualifiedIdentifier>, body);
235
236 delegate!(pub defined_names, HashSet<&Identifier>, body);
237
238 pub fn is_incomplete(&self, cache: &InMemoryModuleCache) -> bool {
243 if !self.is_library_module() {
244 self.body.is_incomplete(self, cache)
245 } else {
246 false
247 }
248 }
249
250 pub fn validate(
260 &self,
261 cache: &InMemoryModuleCache,
262 loader: &impl ModuleLoader,
263 check_constraints: bool,
264 ) {
265 if !self.is_library_module() {
266 self.name
267 .validate(self, loader, Some(IdentifierCaseConvention::Module));
268 if let Some(version_info) = self.version_info() {
269 if version_info.as_ref().is_empty() {
270 loader
271 .report(&module_version_info_empty(
272 self.file_id().copied().unwrap_or_default(),
273 version_info.source_span().map(|span| span.byte_range()),
274 ))
275 .unwrap();
276 }
277 }
278 self.body.validate(self, cache, loader, check_constraints);
279 if self.is_incomplete(cache) {
280 loader
281 .report(&module_is_incomplete(
282 self.file_id().copied().unwrap_or_default(),
283 self.source_span().map(|span| span.byte_range()),
284 self.name(),
285 ))
286 .unwrap()
287 }
288 }
289 }
290
291 pub fn is_library_module(&self) -> bool {
296 Identifier::is_library_module_name(self.name().as_ref())
297 }
298
299 pub fn resolve_local(&self, name: &Identifier) -> Option<&Definition> {
300 self.body().definitions().find(|def| def.name() == name)
301 }
302}
303
304impl<T> AsRef<T> for HeaderValue<T> {
307 fn as_ref(&self) -> &T {
308 &self.value
309 }
310}
311
312impl<T> From<T> for HeaderValue<T> {
313 fn from(value: T) -> Self {
314 Self { span: None, value }
315 }
316}
317
318impl<T: Display> Display for HeaderValue<T> {
319 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
320 write!(f, "{}", self.value)
321 }
322}
323
324impl<T: PartialEq> PartialEq for HeaderValue<T> {
325 fn eq(&self, other: &Self) -> bool {
326 self.value == other.value
327 }
328}
329
330impl<T: PartialEq> PartialEq<T> for HeaderValue<T> {
331 fn eq(&self, other: &T) -> bool {
332 self.value == *other
333 }
334}
335
336impl<T: Eq> Eq for HeaderValue<T> {}
337
338impl<T: Hash> Hash for HeaderValue<T> {
339 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
340 self.value.hash(state);
342 }
343}
344
345impl<T> HasSourceSpan for HeaderValue<T> {
346 fn with_source_span(self, span: Span) -> Self {
347 Self {
348 span: Some(Box::new(span)),
349 ..self
350 }
351 }
352
353 fn source_span(&self) -> Option<&Span> {
354 match &self.span {
355 Some(v) => Some(v.as_ref()),
356 None => None,
357 }
358 }
359
360 fn set_source_span(&mut self, span: Span) {
361 self.span = Some(Box::new(span));
362 }
363
364 fn unset_source_span(&mut self) {
365 self.span = None;
366 }
367}
368
369impl<T: PartialEq> HeaderValue<T> {
370 pub fn eq_with_span(&self, other: &Self) -> bool {
371 self.span == other.span && self.value == other.value
372 }
373}
374
375impl<T> HeaderValue<T> {
376 get_and_set!(pub value, set_value => T);
377}
378
379impl_has_source_span_for!(ModuleBody);
382
383impl_has_annotations_for!(ModuleBody);
384
385impl References for ModuleBody {
386 fn referenced_types<'a>(&'a self, names: &mut HashSet<&'a IdentifierReference>) {
387 self.definitions
388 .iter()
389 .for_each(|def| def.referenced_types(names))
390 }
391
392 fn referenced_annotations<'a>(&'a self, names: &mut HashSet<&'a IdentifierReference>) {
393 self.definitions
394 .iter()
395 .for_each(|def| def.referenced_annotations(names));
396 }
397}
398
399impl_maybe_incomplete_for!(ModuleBody; over definitions);
400
401impl Validate for ModuleBody {
402 fn validate(
410 &self,
411 top: &Module,
412 cache: &impl ModuleStore,
413 loader: &impl ModuleLoader,
414 check_constraints: bool,
415 ) {
416 self.imports()
417 .for_each(|imp| imp.validate(top, cache, loader, check_constraints));
418 self.annotations()
419 .for_each(|ann| ann.validate(top, cache, loader, check_constraints));
420 self.definitions()
421 .for_each(|def| def.validate(top, cache, loader, check_constraints));
422 }
423}
424
425impl ModuleBody {
426 pub fn set_library_status(&mut self, module_name: &Identifier) {
427 self.is_library = Identifier::is_library_module_name(module_name);
428 }
429
430 get_and_set_vec!(
435 pub
436 has has_imports,
437 imports_len,
438 imports,
439 imports_mut,
440 add_to_imports,
441 extend_imports
442 => imports, ImportStatement
443 );
444
445 pub fn has_definitions(&self) -> bool {
446 !self.definitions.is_empty()
447 }
448
449 pub fn definitions_len(&self) -> usize {
450 self.definitions.len()
451 }
452
453 pub fn definitions(&self) -> impl Iterator<Item = &Definition> {
454 self.definitions.iter()
455 }
456
457 pub fn definitions_mut(&mut self) -> impl Iterator<Item = &mut Definition> {
458 self.definitions.iter_mut()
459 }
460
461 pub fn add_to_definitions<I>(&mut self, value: I) -> Result<(), Error>
462 where
463 I: Into<Definition>,
464 {
465 let definition = value.into();
466 if !self.is_library && matches!(definition, Definition::Rdf(_) | Definition::TypeClass(_)) {
467 Err(library_definition_not_allowed(
468 self.file_id.unwrap_or_default(),
469 definition.source_span().map(|s| s.into()),
470 definition.name(),
471 )
472 .into())
473 } else {
474 self.definitions.push(definition);
475 Ok(())
476 }
477 }
478
479 pub fn extend_definitions<I>(&mut self, extension: I) -> Result<(), Error>
480 where
481 I: IntoIterator<Item = Definition>,
482 {
483 for definition in extension.into_iter() {
485 self.add_to_definitions(definition)?;
486 }
487 Ok(())
488 }
489
490 pub fn imported_modules(&self) -> HashSet<&Identifier> {
495 self.imports()
496 .flat_map(|stmt| stmt.imported_modules())
497 .collect()
498 }
499
500 pub fn imported_module_versions(&self) -> HashMap<&Identifier, Option<&HeaderValue<Url>>> {
501 self.imports()
502 .flat_map(|stmt| stmt.imported_module_versions())
503 .collect()
504 }
505
506 pub fn imported_types(&self) -> HashSet<&QualifiedIdentifier> {
507 self.imports()
508 .flat_map(|stmt| stmt.imported_types())
509 .collect()
510 }
511
512 #[inline]
515 pub fn get_definition(&self, name: &Identifier) -> Option<&Definition> {
516 self.definitions().find(|d| d.name() == name)
517 }
518
519 #[inline]
520 pub fn datatype_definitions(&self) -> impl Iterator<Item = &DatatypeDef> {
521 self.definitions.iter().filter_map(|d| match d {
522 Definition::Datatype(v) => Some(v),
523 _ => None,
524 })
525 }
526
527 #[inline]
528 pub fn entity_definitions(&self) -> impl Iterator<Item = &EntityDef> {
529 self.definitions.iter().filter_map(|d| match d {
530 Definition::Entity(v) => Some(v),
531 _ => None,
532 })
533 }
534
535 #[inline]
536 pub fn enum_definitions(&self) -> impl Iterator<Item = &EnumDef> {
537 self.definitions.iter().filter_map(|d| match d {
538 Definition::Enum(v) => Some(v),
539 _ => None,
540 })
541 }
542
543 #[inline]
544 pub fn event_definitions(&self) -> impl Iterator<Item = &EventDef> {
545 self.definitions.iter().filter_map(|d| match d {
546 Definition::Event(v) => Some(v),
547 _ => None,
548 })
549 }
550
551 #[inline]
552 pub fn property_definitions(&self) -> impl Iterator<Item = &PropertyDef> {
553 self.definitions.iter().filter_map(|d| match d {
554 Definition::Property(v) => Some(v),
555 _ => None,
556 })
557 }
558
559 #[inline]
560 pub fn rdf_definitions(&self) -> impl Iterator<Item = &RdfDef> {
561 self.definitions.iter().filter_map(|d| match d {
562 Definition::Rdf(v) => Some(v),
563 _ => None,
564 })
565 }
566
567 #[inline]
568 pub fn structure_definitions(&self) -> impl Iterator<Item = &StructureDef> {
569 self.definitions.iter().filter_map(|d| match d {
570 Definition::Structure(v) => Some(v),
571 _ => None,
572 })
573 }
574
575 #[inline]
576 pub fn type_class_definitions(&self) -> impl Iterator<Item = &TypeClassDef> {
577 self.definitions.iter().filter_map(|d| match d {
578 Definition::TypeClass(v) => Some(v),
579 _ => None,
580 })
581 }
582
583 #[inline]
584 pub fn union_definitions(&self) -> impl Iterator<Item = &UnionDef> {
585 self.definitions.iter().filter_map(|d| match d {
586 Definition::Union(v) => Some(v),
587 _ => None,
588 })
589 }
590
591 pub fn defined_names(&self) -> HashSet<&Identifier> {
592 self.definitions().map(|def| def.name()).collect()
593 }
594}
595
596impl From<Import> for ImportStatement {
601 fn from(value: Import) -> Self {
602 Self::new(vec![value])
603 }
604}
605
606impl From<Vec<Import>> for ImportStatement {
607 fn from(value: Vec<Import>) -> Self {
608 Self::new(value)
609 }
610}
611
612impl FromIterator<Import> for ImportStatement {
613 fn from_iter<T: IntoIterator<Item = Import>>(iter: T) -> Self {
614 Self::new(Vec::from_iter(iter))
615 }
616}
617
618impl From<ImportStatement> for Vec<Import> {
619 fn from(value: ImportStatement) -> Self {
620 value.imports
621 }
622}
623
624impl_has_source_span_for! {ImportStatement}
625
626impl Validate for ImportStatement {
627 fn validate(
641 &self,
642 top: &Module,
643 cache: &impl ModuleStore,
644 loader: &impl ModuleLoader,
645 _: bool,
646 ) {
647 for import in self.imports() {
648 match import {
649 Import::Module(module_ref) => {
650 module_ref
651 .name()
652 .validate(top, loader, Some(IdentifierCaseConvention::Module));
653 if let Some(actual_module) = cache.get(module_ref.name()) {
654 match (module_ref.version_uri(), actual_module.version_uri()) {
655 (None, _) => {}
656 (Some(expected), Some(actual)) => {
657 if actual != expected {
658 loader
659 .report(&module_version_mismatch(
660 top.file_id().copied().unwrap_or_default(),
661 expected.source_span().map(|s| s.byte_range()),
662 expected.as_ref().to_string(),
663 actual_module.file_id().copied().unwrap_or_default(),
664 actual.source_span().map(|s| s.byte_range()),
665 actual.as_ref().to_string(),
666 ))
667 .unwrap();
668 }
669 }
670 (Some(expected), None) => {
671 loader
672 .report(&module_version_not_found(
673 top.file_id().copied().unwrap_or_default(),
674 module_ref.source_span().map(|s| s.byte_range()),
675 expected.as_ref().to_string(),
676 actual_module.file_id().copied().unwrap_or_default(),
677 actual_module.source_span().map(|s| s.byte_range()),
678 actual_module.name(),
679 ))
680 .unwrap();
681 }
682 }
683 } else {
684 loader
685 .report(&imported_module_not_found(
686 top.file_id().copied().unwrap_or_default(),
687 module_ref.source_span().map(|s| s.byte_range()),
688 module_ref.name(),
689 ))
690 .unwrap();
691 }
692 }
693 Import::Member(id_ref) => {
694 id_ref.validate(top, loader);
695 if let Some(actual_module) = cache.get(id_ref.module()) {
696 if actual_module.resolve_local(id_ref.member()).is_none() {
697 loader
698 .report(&definition_not_found(
699 top.file_id().copied().unwrap_or_default(),
700 id_ref.source_span().map(|s| s.byte_range()),
701 id_ref,
702 ))
703 .unwrap();
704 }
705 } else {
706 loader
707 .report(&imported_module_not_found(
708 top.file_id().copied().unwrap_or_default(),
709 id_ref.source_span().map(|s| s.byte_range()),
710 id_ref,
711 ))
712 .unwrap();
713 }
714 }
715 }
716 }
717 }
718}
719
720impl ImportStatement {
721 pub const fn new(imports: Vec<Import>) -> Self {
726 Self {
727 span: None,
728 imports,
729 }
730 }
731
732 pub fn new_module(import: Identifier) -> Self {
733 Self {
734 span: None,
735 imports: vec![Import::from(ModuleImport::from(import))],
736 }
737 }
738
739 pub fn new_module_with_version_uri(import: Identifier, version_uri: Url) -> Self {
740 Self {
741 span: None,
742 imports: vec![Import::from(
743 ModuleImport::from(import).with_version_uri(version_uri.into()),
744 )],
745 }
746 }
747
748 pub fn new_member(import: QualifiedIdentifier) -> Self {
749 Self {
750 span: None,
751 imports: vec![Import::from(import)],
752 }
753 }
754
755 get_and_set_vec!(
760 pub
761 has has_imports,
762 imports_len,
763 imports,
764 imports_mut,
765 add_to_imports,
766 extend_imports
767 => imports, Import
768 );
769
770 pub fn as_slice(&self) -> &[Import] {
773 self.imports.as_slice()
774 }
775
776 pub fn imported_modules(&self) -> HashSet<&Identifier> {
779 self.imports()
780 .map(|imp| match imp {
781 Import::Module(v) => v.name(),
782 Import::Member(v) => v.module(),
783 })
784 .collect()
785 }
786
787 pub fn imported_module_versions(&self) -> HashMap<&Identifier, Option<&HeaderValue<Url>>> {
788 HashMap::from_iter(self.imports().map(|imp| match imp {
789 Import::Module(v) => (v.name(), v.version_uri()),
790 Import::Member(v) => (v.module(), None),
791 }))
792 }
793
794 pub fn imported_types(&self) -> HashSet<&QualifiedIdentifier> {
795 self.imports()
796 .filter_map(|imp| {
797 if let Import::Member(imp) = imp {
798 Some(imp)
799 } else {
800 None
801 }
802 })
803 .collect()
804 }
805}
806
807impl From<Identifier> for Import {
810 fn from(v: Identifier) -> Self {
811 Self::Module(ModuleImport::from(v))
812 }
813}
814
815impl From<ModuleImport> for Import {
816 fn from(v: ModuleImport) -> Self {
817 Self::Module(v)
818 }
819}
820
821impl From<QualifiedIdentifier> for Import {
822 fn from(v: QualifiedIdentifier) -> Self {
823 Self::Member(v)
824 }
825}
826
827enum_display_impl!(Import => Module, Member);
828
829impl_has_source_span_for!(Import => variants Module, Member);
830
831impl Import {
832 pub fn module(&self) -> &Identifier {
833 match self {
834 Import::Module(v) => v.name(),
835 Import::Member(v) => v.module(),
836 }
837 }
838 pub fn member(&self) -> Option<&Identifier> {
839 match self {
840 Import::Module(_) => None,
841 Import::Member(v) => Some(v.member()),
842 }
843 }
844}
845
846impl Display for ModuleImport {
849 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
850 write!(
851 f,
852 "{}",
853 if let Some(version_uri) = self.version_uri() {
854 format!("{} version {}", self.name(), version_uri)
855 } else {
856 self.name().to_string()
857 }
858 )
859 }
860}
861
862impl From<Identifier> for ModuleImport {
863 fn from(value: Identifier) -> Self {
864 Self::new(value)
865 }
866}
867
868impl PartialEq for ModuleImport {
869 fn eq(&self, other: &Self) -> bool {
870 self.name == other.name && self.version_uri == other.version_uri
871 }
872}
873
874impl Eq for ModuleImport {}
875
876impl Hash for ModuleImport {
877 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
878 self.name.hash(state);
880 self.version_uri.hash(state);
881 }
882}
883
884impl_has_source_span_for!(ModuleImport);
885
886impl ModuleImport {
887 pub const fn new(name: Identifier) -> Self {
891 Self {
892 span: None,
893 name,
894 version_uri: None,
895 }
896 }
897
898 pub fn with_version_uri(self, version_uri: HeaderValue<Url>) -> Self {
899 Self {
900 version_uri: Some(version_uri),
901 ..self
902 }
903 }
904
905 get_and_set!(pub name, set_name => Identifier);
910
911 get_and_set!(pub version_uri, set_version_uri, unset_version_uri => optional has_version_uri, HeaderValue<Url>);
912
913 pub fn eq_with_span(&self, other: &Self) -> bool {
918 self.span == other.span && self.name == other.name && self.version_uri == other.version_uri
919 }
920}