sdml_core/model/
check.rs

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