sdml_core/model/
check.rs

1/*!
2Provides the traits and functions for model checking.
3*/
4
5use crate::{
6    load::ModuleLoader,
7    model::{
8        definitions::{Definition, HasMultiMembers},
9        identifiers::{Identifier, IdentifierReference},
10        modules::Module,
11        HasName, HasSourceSpan,
12    },
13    store::ModuleStore,
14};
15use sdml_errors::diagnostics::functions::{duplicate_member, member_is_incomplete};
16
17// ------------------------------------------------------------------------------------------------
18// Public Types
19// ------------------------------------------------------------------------------------------------
20
21pub trait MaybeIncomplete {
22    fn is_incomplete(&self, top: &Module, cache: &impl ModuleStore) -> bool;
23}
24
25pub trait Validate {
26    fn validate(
27        &self,
28        top: &Module,
29        cache: &impl ModuleStore,
30        loader: &impl ModuleLoader,
31        check_constraints: bool,
32    );
33}
34
35// ------------------------------------------------------------------------------------------------
36// Public Functions
37// ------------------------------------------------------------------------------------------------
38
39pub fn find_definition<'a>(
40    name: &IdentifierReference,
41    current: &'a Module,
42    cache: &'a impl ModuleStore,
43) -> Option<&'a Definition> {
44    cache.resolve_or_in(name, current.name())
45}
46
47pub fn validate_is_incomplete<E>(
48    model_element: &E,
49    top: &Module,
50    cache: &impl ModuleStore,
51    loader: &impl ModuleLoader,
52) where
53    E: HasName + HasSourceSpan + MaybeIncomplete,
54{
55    validate_is_incomplete_named(model_element, model_element.name(), top, cache, loader)
56}
57
58pub fn validate_is_incomplete_named<E, S>(
59    model_element: &E,
60    name: S,
61    top: &Module,
62    cache: &impl ModuleStore,
63    loader: &impl ModuleLoader,
64) where
65    E: HasSourceSpan + MaybeIncomplete,
66    S: Into<String>,
67{
68    if model_element.is_incomplete(top, cache) {
69        loader
70            .report(&member_is_incomplete(
71                top.file_id().copied().unwrap_or_default(),
72                model_element.source_span().map(|span| span.byte_range()),
73                name.into(),
74            ))
75            .unwrap()
76    }
77}
78
79pub fn validate_multiple_method_duplicates<E>(
80    model_element: &E,
81    top: &Module,
82    _cache: &impl ModuleStore,
83    loader: &impl ModuleLoader,
84) where
85    E: HasSourceSpan + HasMultiMembers,
86{
87    let mut all_names: Vec<&Identifier> = model_element.all_member_names().collect();
88    all_names.sort();
89    for pair in all_names.windows(2) {
90        if pair[0] == pair[1] {
91            loader
92                .report(&duplicate_member(
93                    top.file_id().copied().unwrap_or_default(),
94                    pair[0]
95                        .source_span()
96                        .map(|span| span.byte_range())
97                        .unwrap_or_default(),
98                    pair[1]
99                        .source_span()
100                        .map(|span| span.byte_range())
101                        .unwrap_or_default(),
102                ))
103                .unwrap()
104        }
105    }
106}
107
108// TODO: need a new version of this --v
109
110// pub fn validate_value(
111//     _a_value: &Value,
112//     a_type: &TypeReference,
113//     current: &Module,
114//     cache: &ModuleCache,
115//     _check_constraints: bool,
116//     _errors: &mut Vec<Error>,
117// ) {
118//     match a_type {
119//         TypeReference::Unknown => {
120//             panic!("no value allowed for unknown");
121//         }
122//         TypeReference::Type(id_ref) => {
123//             if let Some(_defn) = find_definition(id_ref, current, cache) {
124//                 // todo: check it's an actual type
125//                 todo!()
126//             } else {
127//                 panic!("not a valid type reference");
128//             }
129//         }
130//         TypeReference::FeatureSet(_id_ref) => todo!(),
131//         TypeReference::MappingType(_map_type) => todo!(),
132//     }
133// }
134
135#[cfg(feature = "terms")]
136pub mod terms {
137    use crate::{
138        load::ModuleLoader,
139        model::{
140            annotations::*, constraints::*, definitions::*, identifiers::*, members::*, modules::*,
141            values::*, *,
142        },
143    };
144    use sdml_errors::{diagnostics::functions::deprecated_term_used, Error};
145    use serde::{Deserialize, Serialize};
146    use std::collections::{HashMap, HashSet};
147
148    // --------------------------------------------------------------------------------------------
149    // Public Types
150    // --------------------------------------------------------------------------------------------
151
152    #[derive(Clone, Debug, Deserialize, Serialize)]
153    pub struct TermSet {
154        name: String,
155        #[serde(skip_serializing_if = "Option::is_none")]
156        version: Option<String>,
157        #[serde(skip_serializing_if = "Option::is_none")]
158        description: Option<String>,
159        terms: HashMap<String, Term>,
160    }
161
162    #[derive(Clone, Debug, Deserialize, Serialize)]
163    pub struct Term {
164        #[serde(skip_serializing_if = "Option::is_none", with = "serde_regex")]
165        regex: Option<regex::Regex>,
166        alternative_terms: Vec<String>,
167        #[serde(skip_serializing_if = "Option::is_none")]
168        reason: Option<String>,
169    }
170
171    // --------------------------------------------------------------------------------------------
172    // Public Functions
173    // --------------------------------------------------------------------------------------------
174
175    const DEFAULT_RULES: &str = include_str!("default_terms.json");
176
177    pub fn default_term_set() -> Result<TermSet, Error> {
178        Ok(serde_json::from_str(DEFAULT_RULES).unwrap())
179    }
180
181    pub fn validate_module_terms(module: &Module, term_set: &TermSet, loader: &impl ModuleLoader) {
182        let mut validator = Validator::from(term_set);
183        module.name().validate_terms(&mut validator, module, loader);
184        for annotation in module.annotations() {
185            annotation.validate_terms(&mut validator, module, loader);
186        }
187        for definition in module.definitions() {
188            definition.validate_terms(&mut validator, module, loader);
189        }
190    }
191
192    // --------------------------------------------------------------------------------------------
193    // Private Types
194    // --------------------------------------------------------------------------------------------
195
196    #[derive(Clone, Debug)]
197    struct TermInfo<'a> {
198        regex: regex::Regex,
199        alternative_terms: &'a Vec<String>,
200        reason: &'a Option<String>,
201    }
202
203    #[derive(Clone, Debug)]
204    struct Validator<'a> {
205        term_map: HashMap<String, TermInfo<'a>>,
206        seen: HashSet<String>,
207    }
208
209    // --------------------------------------------------------------------------------------------
210    // Implementations ❱ Validator
211    // --------------------------------------------------------------------------------------------
212
213    impl<'a> From<&'a TermSet> for Validator<'a> {
214        fn from(term_set: &'a TermSet) -> Self {
215            let mut term_map: HashMap<String, TermInfo<'a>> = Default::default();
216            for (term, info) in &term_set.terms {
217                let regex = if let Some(regex) = &info.regex {
218                    regex.clone()
219                } else {
220                    regex::Regex::new(&format!("(?i)\\b{}\\b", term)).unwrap()
221                };
222                let new_info = TermInfo {
223                    regex,
224                    alternative_terms: &info.alternative_terms,
225                    reason: &info.reason,
226                };
227                term_map.insert(term.clone(), new_info);
228            }
229            Self {
230                term_map,
231                seen: Default::default(),
232            }
233        }
234    }
235
236    impl Validator<'_> {
237        fn check_for_matches<S>(
238            &mut self,
239            value: S,
240            span: Option<&Span>,
241            top: &Module,
242            loader: &impl ModuleLoader,
243        ) where
244            S: Into<String>,
245        {
246            let value = value.into();
247            if self.seen.insert(value.clone()) {
248                for (term, info) in &self.term_map {
249                    if info.regex.is_match(value.as_ref()) {
250                        loader
251                            .report(&deprecated_term_used(
252                                top.file_id().copied().unwrap_or_default(),
253                                span.map(|span| span.byte_range()),
254                                &value,
255                                term,
256                                info.alternative_terms,
257                                info.reason.as_ref(),
258                            ))
259                            .unwrap()
260                    }
261                }
262            }
263        }
264    }
265
266    // --------------------------------------------------------------------------------------------
267
268    trait ValidateTerms {
269        fn validate_terms(
270            &self,
271            validator: &mut Validator<'_>,
272            top: &Module,
273            loader: &impl ModuleLoader,
274        );
275    }
276
277    impl ValidateTerms for Identifier {
278        fn validate_terms(
279            &self,
280            validator: &mut Validator<'_>,
281            top: &Module,
282            loader: &impl ModuleLoader,
283        ) {
284            validator.check_for_matches(self, self.source_span(), top, loader);
285        }
286    }
287
288    impl ValidateTerms for QualifiedIdentifier {
289        fn validate_terms(
290            &self,
291            validator: &mut Validator<'_>,
292            top: &Module,
293            loader: &impl ModuleLoader,
294        ) {
295            self.module().validate_terms(validator, top, loader);
296            self.member().validate_terms(validator, top, loader);
297        }
298    }
299
300    impl ValidateTerms for IdentifierReference {
301        fn validate_terms(
302            &self,
303            validator: &mut Validator<'_>,
304            top: &Module,
305            loader: &impl ModuleLoader,
306        ) {
307            match self {
308                Self::Identifier(v) => v.validate_terms(validator, top, loader),
309                Self::QualifiedIdentifier(v) => v.validate_terms(validator, top, loader),
310            }
311        }
312    }
313
314    impl ValidateTerms for Annotation {
315        fn validate_terms(
316            &self,
317            validator: &mut Validator<'_>,
318            top: &Module,
319            loader: &impl ModuleLoader,
320        ) {
321            match self {
322                Self::Property(v) => v.validate_terms(validator, top, loader),
323                Self::Constraint(v) => v.validate_terms(validator, top, loader),
324            }
325        }
326    }
327
328    impl ValidateTerms for AnnotationProperty {
329        fn validate_terms(
330            &self,
331            validator: &mut Validator<'_>,
332            top: &Module,
333            loader: &impl ModuleLoader,
334        ) {
335            self.name_reference().validate_terms(validator, top, loader);
336            self.value().validate_terms(validator, top, loader);
337        }
338    }
339
340    impl ValidateTerms for Value {
341        fn validate_terms(
342            &self,
343            validator: &mut Validator<'_>,
344            top: &Module,
345            loader: &impl ModuleLoader,
346        ) {
347            match self {
348                Self::Simple(v) => v.validate_terms(validator, top, loader),
349                Self::ValueConstructor(v) => v.validate_terms(validator, top, loader),
350                Self::Mapping(v) => v.validate_terms(validator, top, loader),
351                Self::Reference(v) => v.validate_terms(validator, top, loader),
352                Self::Sequence(v) => v.validate_terms(validator, top, loader),
353            }
354        }
355    }
356
357    impl ValidateTerms for SimpleValue {
358        fn validate_terms(
359            &self,
360            validator: &mut Validator<'_>,
361            top: &Module,
362            loader: &impl ModuleLoader,
363        ) {
364            if let SimpleValue::String(value) = self {
365                validator.check_for_matches(value.value(), value.source_span(), top, loader);
366            }
367        }
368    }
369
370    impl ValidateTerms for ValueConstructor {
371        fn validate_terms(
372            &self,
373            validator: &mut Validator<'_>,
374            top: &Module,
375            loader: &impl ModuleLoader,
376        ) {
377            self.type_name().validate_terms(validator, top, loader);
378            self.value().validate_terms(validator, top, loader);
379        }
380    }
381
382    impl ValidateTerms for SequenceOfValues {
383        fn validate_terms(
384            &self,
385            validator: &mut Validator<'_>,
386            top: &Module,
387            loader: &impl ModuleLoader,
388        ) {
389            for value in self.iter() {
390                value.validate_terms(validator, top, loader);
391            }
392        }
393    }
394
395    impl ValidateTerms for SequenceMember {
396        fn validate_terms(
397            &self,
398            validator: &mut Validator<'_>,
399            top: &Module,
400            loader: &impl ModuleLoader,
401        ) {
402            match self {
403                Self::Simple(v) => v.validate_terms(validator, top, loader),
404                Self::ValueConstructor(v) => v.validate_terms(validator, top, loader),
405                Self::Reference(v) => v.validate_terms(validator, top, loader),
406                Self::Mapping(v) => v.validate_terms(validator, top, loader),
407            }
408        }
409    }
410
411    impl ValidateTerms for MappingValue {
412        fn validate_terms(
413            &self,
414            validator: &mut Validator<'_>,
415            top: &Module,
416            loader: &impl ModuleLoader,
417        ) {
418            self.domain().validate_terms(validator, top, loader);
419            self.range().validate_terms(validator, top, loader);
420        }
421    }
422
423    impl ValidateTerms for AnnotationOnlyBody {
424        fn validate_terms(
425            &self,
426            validator: &mut Validator<'_>,
427            top: &Module,
428            loader: &impl ModuleLoader,
429        ) {
430            for annotation in self.annotations() {
431                annotation.validate_terms(validator, top, loader);
432            }
433        }
434    }
435
436    impl ValidateTerms for Constraint {
437        fn validate_terms(
438            &self,
439            validator: &mut Validator<'_>,
440            top: &Module,
441            loader: &impl ModuleLoader,
442        ) {
443            self.name().validate_terms(validator, top, loader);
444            match self.body() {
445                ConstraintBody::Informal(v) => v.validate_terms(validator, top, loader),
446                ConstraintBody::Formal(v) => v.validate_terms(validator, top, loader),
447            }
448        }
449    }
450
451    impl ValidateTerms for ControlledLanguageString {
452        fn validate_terms(
453            &self,
454            validator: &mut Validator<'_>,
455            top: &Module,
456            loader: &impl ModuleLoader,
457        ) {
458            validator.check_for_matches(self.value(), self.source_span(), top, loader);
459        }
460    }
461
462    impl ValidateTerms for FormalConstraint {
463        fn validate_terms(
464            &self,
465            _validator: &mut Validator<'_>,
466            _top: &Module,
467            _loader: &impl ModuleLoader,
468        ) {
469            todo!()
470        }
471    }
472
473    impl ValidateTerms for Definition {
474        fn validate_terms(
475            &self,
476            validator: &mut Validator<'_>,
477            top: &Module,
478            loader: &impl ModuleLoader,
479        ) {
480            match self {
481                Self::Datatype(v) => v.validate_terms(validator, top, loader),
482                Self::Dimension(v) => v.validate_terms(validator, top, loader),
483                Self::Entity(v) => v.validate_terms(validator, top, loader),
484                Self::Enum(v) => v.validate_terms(validator, top, loader),
485                Self::Event(v) => v.validate_terms(validator, top, loader),
486                Self::Property(v) => v.validate_terms(validator, top, loader),
487                Self::Rdf(v) => v.validate_terms(validator, top, loader),
488                Self::Structure(v) => v.validate_terms(validator, top, loader),
489                Self::TypeClass(v) => v.validate_terms(validator, top, loader),
490                Self::Union(v) => v.validate_terms(validator, top, loader),
491            }
492        }
493    }
494
495    impl ValidateTerms for DatatypeDef {
496        fn validate_terms(
497            &self,
498            validator: &mut Validator<'_>,
499            top: &Module,
500            loader: &impl ModuleLoader,
501        ) {
502            self.name().validate_terms(validator, top, loader);
503            self.base_type().validate_terms(validator, top, loader);
504            if let Some(body) = self.body() {
505                body.validate_terms(validator, top, loader);
506            }
507        }
508    }
509
510    impl ValidateTerms for DimensionDef {
511        fn validate_terms(
512            &self,
513            validator: &mut Validator<'_>,
514            top: &Module,
515            loader: &impl ModuleLoader,
516        ) {
517            self.name().validate_terms(validator, top, loader);
518            if let Some(body) = self.body() {
519                for annotation in body.annotations() {
520                    annotation.validate_terms(validator, top, loader);
521                }
522                match body.identity() {
523                    DimensionIdentity::Source(source) => {
524                        source.validate_terms(validator, top, loader)
525                    }
526                    DimensionIdentity::Identity(member) => {
527                        member.validate_terms(validator, top, loader)
528                    }
529                }
530                for parent in body.parents() {
531                    parent.validate_terms(validator, top, loader);
532                }
533                for member in body.members() {
534                    member.validate_terms(validator, top, loader);
535                }
536            }
537        }
538    }
539
540    impl ValidateTerms for SourceEntity {
541        fn validate_terms(
542            &self,
543            validator: &mut Validator<'_>,
544            top: &Module,
545            loader: &impl ModuleLoader,
546        ) {
547            self.target_entity().validate_terms(validator, top, loader);
548            for member in self.members() {
549                member.validate_terms(validator, top, loader);
550            }
551        }
552    }
553
554    impl ValidateTerms for DimensionParent {
555        fn validate_terms(
556            &self,
557            validator: &mut Validator<'_>,
558            top: &Module,
559            loader: &impl ModuleLoader,
560        ) {
561            self.name().validate_terms(validator, top, loader);
562            self.target_entity().validate_terms(validator, top, loader);
563        }
564    }
565
566    impl ValidateTerms for EntityDef {
567        fn validate_terms(
568            &self,
569            validator: &mut Validator<'_>,
570            top: &Module,
571            loader: &impl ModuleLoader,
572        ) {
573            self.name().validate_terms(validator, top, loader);
574            if let Some(body) = self.body() {
575                for annotation in body.annotations() {
576                    annotation.validate_terms(validator, top, loader);
577                }
578                for member in body.members() {
579                    member.validate_terms(validator, top, loader);
580                }
581            }
582        }
583    }
584
585    impl ValidateTerms for EnumDef {
586        fn validate_terms(
587            &self,
588            validator: &mut Validator<'_>,
589            top: &Module,
590            loader: &impl ModuleLoader,
591        ) {
592            self.name().validate_terms(validator, top, loader);
593            if let Some(body) = self.body() {
594                for annotation in body.annotations() {
595                    annotation.validate_terms(validator, top, loader);
596                }
597                for variant in body.variants() {
598                    variant.validate_terms(validator, top, loader);
599                }
600            }
601        }
602    }
603
604    impl ValidateTerms for ValueVariant {
605        fn validate_terms(
606            &self,
607            validator: &mut Validator<'_>,
608            top: &Module,
609            loader: &impl ModuleLoader,
610        ) {
611            self.name().validate_terms(validator, top, loader);
612            if let Some(body) = self.body() {
613                for annotation in body.annotations() {
614                    annotation.validate_terms(validator, top, loader);
615                }
616            }
617        }
618    }
619
620    impl ValidateTerms for EventDef {
621        fn validate_terms(
622            &self,
623            validator: &mut Validator<'_>,
624            top: &Module,
625            loader: &impl ModuleLoader,
626        ) {
627            self.name().validate_terms(validator, top, loader);
628            if let Some(body) = self.body() {
629                // TODO: put back -- body.event_source().validate_terms(validator, top, loader);
630                for annotation in body.annotations() {
631                    annotation.validate_terms(validator, top, loader);
632                    for member in body.members() {
633                        member.validate_terms(validator, top, loader);
634                    }
635                }
636            }
637        }
638    }
639
640    impl ValidateTerms for PropertyDef {
641        fn validate_terms(
642            &self,
643            validator: &mut Validator<'_>,
644            top: &Module,
645            loader: &impl ModuleLoader,
646        ) {
647            self.member_def().validate_terms(validator, top, loader);
648        }
649    }
650
651    impl ValidateTerms for RdfDef {
652        fn validate_terms(
653            &self,
654            validator: &mut Validator<'_>,
655            top: &Module,
656            loader: &impl ModuleLoader,
657        ) {
658            self.name().validate_terms(validator, top, loader);
659            for annotation in self.body().annotations() {
660                annotation.validate_terms(validator, top, loader);
661            }
662        }
663    }
664
665    impl ValidateTerms for StructureDef {
666        fn validate_terms(
667            &self,
668            validator: &mut Validator<'_>,
669            top: &Module,
670            loader: &impl ModuleLoader,
671        ) {
672            self.name().validate_terms(validator, top, loader);
673            if let Some(body) = self.body() {
674                for annotation in body.annotations() {
675                    annotation.validate_terms(validator, top, loader);
676                }
677                for member in body.members() {
678                    member.validate_terms(validator, top, loader);
679                }
680            }
681        }
682    }
683
684    impl ValidateTerms for TypeClassDef {
685        fn validate_terms(
686            &self,
687            validator: &mut Validator<'_>,
688            top: &Module,
689            loader: &impl ModuleLoader,
690        ) {
691            self.name().validate_terms(validator, top, loader);
692            if let Some(body) = self.body() {
693                for annotation in body.annotations() {
694                    annotation.validate_terms(validator, top, loader);
695                }
696            }
697            todo!("validate all")
698        }
699    }
700
701    impl ValidateTerms for UnionDef {
702        fn validate_terms(
703            &self,
704            validator: &mut Validator<'_>,
705            top: &Module,
706            loader: &impl ModuleLoader,
707        ) {
708            self.name().validate_terms(validator, top, loader);
709            if let Some(body) = self.body() {
710                for annotation in body.annotations() {
711                    annotation.validate_terms(validator, top, loader);
712                }
713                for variant in body.variants() {
714                    variant.validate_terms(validator, top, loader);
715                }
716            }
717        }
718    }
719
720    impl ValidateTerms for TypeVariant {
721        fn validate_terms(
722            &self,
723            validator: &mut Validator<'_>,
724            top: &Module,
725            loader: &impl ModuleLoader,
726        ) {
727            self.name_reference().validate_terms(validator, top, loader);
728            if let Some(rename) = self.rename() {
729                rename.validate_terms(validator, top, loader);
730            }
731            if let Some(body) = self.body() {
732                for annotation in body.annotations() {
733                    annotation.validate_terms(validator, top, loader);
734                }
735            }
736        }
737    }
738
739    impl ValidateTerms for Member {
740        fn validate_terms(
741            &self,
742            validator: &mut Validator<'_>,
743            top: &Module,
744            loader: &impl ModuleLoader,
745        ) {
746            match self.kind() {
747                MemberKind::Reference(v) => v.validate_terms(validator, top, loader),
748                MemberKind::Definition(v) => v.validate_terms(validator, top, loader),
749            }
750        }
751    }
752
753    impl ValidateTerms for MemberDef {
754        fn validate_terms(
755            &self,
756            validator: &mut Validator<'_>,
757            top: &Module,
758            loader: &impl ModuleLoader,
759        ) {
760            self.name().validate_terms(validator, top, loader);
761            self.target_type().validate_terms(validator, top, loader);
762            if let Some(body) = self.body() {
763                body.validate_terms(validator, top, loader);
764            }
765        }
766    }
767
768    impl ValidateTerms for TypeReference {
769        fn validate_terms(
770            &self,
771            validator: &mut Validator<'_>,
772            top: &Module,
773            loader: &impl ModuleLoader,
774        ) {
775            match self {
776                Self::Unknown => {}
777                Self::Type(v) => v.validate_terms(validator, top, loader),
778                Self::MappingType(v) => {
779                    v.domain().validate_terms(validator, top, loader);
780                    v.range().validate_terms(validator, top, loader);
781                }
782            }
783        }
784    }
785}