sdml_core/model/
check.rs

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