use super::HasName;
use crate::load::ModuleLoader;
use crate::model::definitions::Definition;
use crate::model::identifiers::IdentifierReference;
use crate::model::modules::Module;
use crate::store::ModuleStore;
pub trait MaybeIncomplete {
fn is_incomplete(&self, top: &Module, cache: &impl ModuleStore) -> bool;
}
pub trait Validate {
fn validate(
&self,
top: &Module,
cache: &impl ModuleStore,
loader: &impl ModuleLoader,
check_constraints: bool,
);
}
pub fn find_definition<'a>(
name: &IdentifierReference,
current: &'a Module,
cache: &'a impl ModuleStore,
) -> Option<&'a Definition> {
cache.resolve_or_in(name, current.name())
}
#[cfg(feature = "terms")]
pub mod terms {
use std::collections::HashMap;
use crate::load::ModuleLoader;
use crate::model::annotations::*;
use crate::model::constraints::*;
use crate::model::definitions::*;
use crate::model::identifiers::*;
use crate::model::members::*;
use crate::model::modules::*;
use crate::model::values::*;
use crate::model::*;
use sdml_errors::diagnostics::functions::deprecated_term_used;
use sdml_errors::Error;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct TermSet {
name: String,
#[serde(skip_serializing_if = "Option::is_none")]
version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
description: Option<String>,
terms: HashMap<String, Term>,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Term {
#[serde(skip_serializing_if = "Option::is_none", with = "serde_regex")]
regex: Option<regex::Regex>,
alternative_terms: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
reason: Option<String>,
}
const DEFAULT_RULES: &str = include_str!("default_terms.json");
pub fn default_term_set() -> Result<TermSet, Error> {
Ok(serde_json::from_str(DEFAULT_RULES).unwrap())
}
pub fn validate_module_terms(module: &Module, term_set: &TermSet, loader: &impl ModuleLoader) {
let mut validator = Validator::from(term_set);
module.name().validate_terms(&mut validator, module, loader);
for annotation in module.body().annotations() {
annotation.validate_terms(&mut validator, module, loader);
}
for definition in module.body().definitions() {
definition.validate_terms(&mut validator, module, loader);
}
}
#[derive(Clone, Debug)]
struct TermInfo<'a> {
regex: regex::Regex,
alternative_terms: &'a Vec<String>,
reason: &'a Option<String>,
}
#[derive(Clone, Debug)]
struct Validator<'a> {
term_map: HashMap<String, TermInfo<'a>>,
seen: HashSet<String>,
}
impl<'a> From<&'a TermSet> for Validator<'a> {
fn from(term_set: &'a TermSet) -> Self {
let mut term_map: HashMap<String, TermInfo<'a>> = Default::default();
for (term, info) in &term_set.terms {
let regex = if let Some(regex) = &info.regex {
regex.clone()
} else {
regex::Regex::new(&format!("(?i)\\b{}\\b", term)).unwrap()
};
let new_info = TermInfo {
regex,
alternative_terms: &info.alternative_terms,
reason: &info.reason,
};
term_map.insert(term.clone(), new_info);
}
Self {
term_map,
seen: Default::default(),
}
}
}
impl Validator<'_> {
fn check_for_matches<S>(
&mut self,
value: S,
span: Option<&Span>,
top: &Module,
loader: &impl ModuleLoader,
) where
S: Into<String>,
{
let value = value.into();
if self.seen.insert(value.clone()) {
for (term, info) in &self.term_map {
if info.regex.is_match(value.as_ref()) {
loader
.report(&deprecated_term_used(
top.file_id().copied().unwrap_or_default(),
span.map(|span| span.byte_range()),
&value,
term,
info.alternative_terms,
info.reason.as_ref(),
))
.unwrap()
}
}
}
}
}
trait ValidateTerms {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
);
}
impl ValidateTerms for Identifier {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
validator.check_for_matches(self, self.source_span(), top, loader);
}
}
impl ValidateTerms for QualifiedIdentifier {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
self.module().validate_terms(validator, top, loader);
self.member().validate_terms(validator, top, loader);
}
}
impl ValidateTerms for IdentifierReference {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
match self {
Self::Identifier(v) => v.validate_terms(validator, top, loader),
Self::QualifiedIdentifier(v) => v.validate_terms(validator, top, loader),
}
}
}
impl ValidateTerms for Annotation {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
match self {
Self::Property(v) => v.validate_terms(validator, top, loader),
Self::Constraint(v) => v.validate_terms(validator, top, loader),
}
}
}
impl ValidateTerms for AnnotationProperty {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
self.name_reference().validate_terms(validator, top, loader);
self.value().validate_terms(validator, top, loader);
}
}
impl ValidateTerms for Value {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
match self {
Self::Simple(v) => v.validate_terms(validator, top, loader),
Self::ValueConstructor(v) => v.validate_terms(validator, top, loader),
Self::Mapping(v) => v.validate_terms(validator, top, loader),
Self::Reference(v) => v.validate_terms(validator, top, loader),
Self::List(v) => v.validate_terms(validator, top, loader),
}
}
}
impl ValidateTerms for SimpleValue {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
if let SimpleValue::String(value) = self {
validator.check_for_matches(value.value(), value.source_span(), top, loader);
}
}
}
impl ValidateTerms for ValueConstructor {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
self.type_name().validate_terms(validator, top, loader);
self.value().validate_terms(validator, top, loader);
}
}
impl ValidateTerms for SequenceOfValues {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
for value in self.iter() {
value.validate_terms(validator, top, loader);
}
}
}
impl ValidateTerms for SequenceMember {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
match self {
Self::Simple(v) => v.validate_terms(validator, top, loader),
Self::ValueConstructor(v) => v.validate_terms(validator, top, loader),
Self::Reference(v) => v.validate_terms(validator, top, loader),
Self::Mapping(v) => v.validate_terms(validator, top, loader),
}
}
}
impl ValidateTerms for MappingValue {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
self.domain().validate_terms(validator, top, loader);
self.range().validate_terms(validator, top, loader);
}
}
impl ValidateTerms for AnnotationOnlyBody {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
for annotation in self.annotations() {
annotation.validate_terms(validator, top, loader);
}
}
}
impl ValidateTerms for Constraint {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
self.name().validate_terms(validator, top, loader);
match self.body() {
ConstraintBody::Informal(v) => v.validate_terms(validator, top, loader),
ConstraintBody::Formal(v) => v.validate_terms(validator, top, loader),
}
}
}
impl ValidateTerms for ControlledLanguageString {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
validator.check_for_matches(self.value(), self.source_span(), top, loader);
}
}
impl ValidateTerms for FormalConstraint {
fn validate_terms(
&self,
_validator: &mut Validator<'_>,
_top: &Module,
_loader: &impl ModuleLoader,
) {
todo!()
}
}
impl ValidateTerms for Definition {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
match self {
Self::Datatype(v) => v.validate_terms(validator, top, loader),
Self::Entity(v) => v.validate_terms(validator, top, loader),
Self::Enum(v) => v.validate_terms(validator, top, loader),
Self::Event(v) => v.validate_terms(validator, top, loader),
Self::Property(v) => v.validate_terms(validator, top, loader),
Self::Rdf(v) => v.validate_terms(validator, top, loader),
Self::Structure(v) => v.validate_terms(validator, top, loader),
Self::TypeClass(v) => v.validate_terms(validator, top, loader),
Self::Union(v) => v.validate_terms(validator, top, loader),
}
}
}
impl ValidateTerms for DatatypeDef {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
self.name().validate_terms(validator, top, loader);
self.base_type().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
body.validate_terms(validator, top, loader);
}
}
}
impl ValidateTerms for EntityDef {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
self.name().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
for annotation in body.annotations() {
annotation.validate_terms(validator, top, loader);
}
for member in body.members() {
member.validate_terms(validator, top, loader);
}
}
}
}
impl ValidateTerms for EnumDef {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
self.name().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
for annotation in body.annotations() {
annotation.validate_terms(validator, top, loader);
}
for variant in body.variants() {
variant.validate_terms(validator, top, loader);
}
}
}
}
impl ValidateTerms for ValueVariant {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
self.name().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
for annotation in body.annotations() {
annotation.validate_terms(validator, top, loader);
}
}
}
}
impl ValidateTerms for EventDef {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
self.name().validate_terms(validator, top, loader);
self.event_source().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
for annotation in body.annotations() {
annotation.validate_terms(validator, top, loader);
for member in body.members() {
member.validate_terms(validator, top, loader);
}
}
}
}
}
impl ValidateTerms for PropertyDef {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
self.member_def().validate_terms(validator, top, loader);
}
}
impl ValidateTerms for RdfDef {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
self.name().validate_terms(validator, top, loader);
for annotation in self.body().annotations() {
annotation.validate_terms(validator, top, loader);
}
}
}
impl ValidateTerms for StructureDef {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
self.name().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
for annotation in body.annotations() {
annotation.validate_terms(validator, top, loader);
}
for member in body.members() {
member.validate_terms(validator, top, loader);
}
}
}
}
impl ValidateTerms for TypeClassDef {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
self.name().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
for annotation in body.annotations() {
annotation.validate_terms(validator, top, loader);
}
}
todo!("validate all")
}
}
impl ValidateTerms for UnionDef {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
self.name().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
for annotation in body.annotations() {
annotation.validate_terms(validator, top, loader);
}
for variant in body.variants() {
variant.validate_terms(validator, top, loader);
}
}
}
}
impl ValidateTerms for TypeVariant {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
self.name_reference().validate_terms(validator, top, loader);
if let Some(rename) = self.rename() {
rename.validate_terms(validator, top, loader);
}
if let Some(body) = self.body() {
for annotation in body.annotations() {
annotation.validate_terms(validator, top, loader);
}
}
}
}
impl ValidateTerms for Member {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
match self.kind() {
MemberKind::Reference(v) => v.validate_terms(validator, top, loader),
MemberKind::Definition(v) => v.validate_terms(validator, top, loader),
}
}
}
impl ValidateTerms for MemberDef {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
self.name().validate_terms(validator, top, loader);
self.target_type().validate_terms(validator, top, loader);
if let Some(body) = self.body() {
body.validate_terms(validator, top, loader);
}
}
}
impl ValidateTerms for TypeReference {
fn validate_terms(
&self,
validator: &mut Validator<'_>,
top: &Module,
loader: &impl ModuleLoader,
) {
match self {
Self::Unknown => {}
Self::Type(v) => v.validate_terms(validator, top, loader),
Self::MappingType(v) => {
v.domain().validate_terms(validator, top, loader);
v.range().validate_terms(validator, top, loader);
}
}
}
}
}