use crate::error::Error;
use crate::model::definitions::{
DatatypeDef, EntityDef, EnumDef, EventDef, PropertyDef, StructureDef, UnionDef,
};
use crate::model::References;
use crate::model::{
annotations::{Annotation, HasAnnotations},
check::Validate,
definitions::Definition,
identifiers::{Identifier, IdentifierReference, QualifiedIdentifier},
HasBody, HasName, Span,
};
use std::fmt::Display;
use std::{collections::HashSet, fmt::Debug};
use url::Url;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct Module {
span: Option<Span>,
name: Identifier,
base_uri: Option<Url>,
version_info: Option<String>,
version_uri: Option<Url>,
body: ModuleBody,
}
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct ModuleBody {
span: Option<Span>,
imports: Vec<ImportStatement>,
annotations: Vec<Annotation>,
definitions: Vec<Definition>,
}
#[derive(Clone, Debug, Default)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct ImportStatement {
span: Option<Span>,
imports: Vec<Import>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub enum Import {
Module(ModuleImport),
Member(QualifiedIdentifier),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
pub struct ModuleImport {
span: Option<Span>,
name: Identifier,
version_uri: Option<Url>,
}
impl_has_source_span_for!(Module);
impl_has_name_for!(Module);
impl_has_body_for!(Module, ModuleBody);
impl References for Module {
fn referenced_types<'a>(&'a self, names: &mut HashSet<&'a IdentifierReference>) {
self.body.referenced_types(names);
}
fn referenced_annotations<'a>(&'a self, names: &mut HashSet<&'a IdentifierReference>) {
self.body.referenced_annotations(names);
}
}
impl Module {
pub fn empty(name: Identifier) -> Self {
Self {
span: None,
name,
base_uri: Default::default(),
version_info: Default::default(),
version_uri: Default::default(),
body: Default::default(),
}
}
pub fn new(name: Identifier, body: ModuleBody) -> Self {
Self {
span: None,
name,
base_uri: Default::default(),
version_info: Default::default(),
version_uri: Default::default(),
body,
}
}
pub fn with_base_uri(self, base_uri: Url) -> Self {
Self {
base_uri: Some(base_uri),
..self
}
}
pub fn with_version_info<S>(self, version_info: S) -> Self
where
S: Into<String>,
{
Self {
version_info: Some(version_info.into()),
..self
}
}
pub fn with_version_uri(self, version_uri: Url) -> Self {
Self {
version_uri: Some(version_uri),
..self
}
}
get_and_set!(pub base_uri, set_base_uri, unset_base_uri => optional has_base_uri, Url);
get_and_set!(pub version_info, set_version_info, unset_version_info => optional has_version_info, String);
get_and_set!(pub version_uri, set_version_uri, unset_version_uri => optional has_version_uri, Url);
delegate!(pub imported_modules, HashSet<&Identifier>, body);
delegate!(pub imported_types, HashSet<&QualifiedIdentifier>, body);
delegate!(pub defined_names, HashSet<&Identifier>, body);
pub fn is_complete(&self) -> Result<bool, Error> {
self.body.is_complete(self)
}
pub fn is_valid(&self, check_constraints: bool) -> Result<bool, Error> {
self.body.is_valid(check_constraints, self)
}
pub fn is_library_module(&self) -> bool {
Identifier::is_library_module_name(self.name().as_ref())
}
pub fn validate(&self, check_constraints: bool, errors: &mut Vec<Error>) -> Result<(), Error> {
self.body.validate(check_constraints, self, errors)
}
pub fn resolve_local(&self, name: &Identifier) -> Option<&Definition> {
self.body().definitions().find(|def| def.name() == name)
}
}
impl_has_source_span_for!(ModuleBody);
impl_has_annotations_for!(ModuleBody);
impl References for ModuleBody {
fn referenced_types<'a>(&'a self, names: &mut HashSet<&'a IdentifierReference>) {
self.definitions
.iter()
.for_each(|def| def.referenced_types(names))
}
fn referenced_annotations<'a>(&'a self, names: &mut HashSet<&'a IdentifierReference>) {
self.definitions
.iter()
.for_each(|def| def.referenced_annotations(names));
}
}
impl Validate for ModuleBody {
fn is_complete(&self, top: &Module) -> Result<bool, Error> {
let failed: Result<Vec<bool>, Error> =
self.annotations().map(|ann| ann.is_complete(top)).collect();
Ok(failed?.iter().all(|b| *b))
}
fn is_valid(&self, check_constraints: bool, top: &Module) -> Result<bool, Error> {
for inner in self.annotations() {
inner.is_valid(check_constraints, top)?;
}
for inner in self.definitions() {
inner.is_valid(check_constraints, top)?;
}
Ok(true)
}
fn validate(
&self,
check_constraints: bool,
top: &Module,
errors: &mut Vec<Error>,
) -> Result<(), Error> {
for annotation in self.annotations() {
annotation.validate(check_constraints, top, errors)?;
}
for definition in self.definitions() {
definition.validate(check_constraints, top, errors)?;
}
Ok(())
}
}
impl ModuleBody {
get_and_set_vec!(
pub
has has_imports,
imports_len,
imports,
imports_mut,
add_to_imports,
extend_imports
=> imports, ImportStatement
);
pub fn imported_modules(&self) -> HashSet<&Identifier> {
self.imports()
.flat_map(|stmt| stmt.imported_modules())
.collect()
}
pub fn imported_types(&self) -> HashSet<&QualifiedIdentifier> {
self.imports()
.flat_map(|stmt| stmt.imported_types())
.collect()
}
get_and_set_vec!(
pub
has has_definitions,
definitions_len,
definitions,
definitions_mut,
add_to_definitions,
extend_definitions
=> definitions, Definition
);
#[inline]
pub fn datatype_definitions(&self) -> impl Iterator<Item = &DatatypeDef> {
self.definitions.iter().filter_map(|d| match d {
Definition::Datatype(v) => Some(v),
_ => None,
})
}
#[inline]
pub fn entity_definitions(&self) -> impl Iterator<Item = &EntityDef> {
self.definitions.iter().filter_map(|d| match d {
Definition::Entity(v) => Some(v),
_ => None,
})
}
#[inline]
pub fn enum_definitions(&self) -> impl Iterator<Item = &EnumDef> {
self.definitions.iter().filter_map(|d| match d {
Definition::Enum(v) => Some(v),
_ => None,
})
}
#[inline]
pub fn event_definitions(&self) -> impl Iterator<Item = &EventDef> {
self.definitions.iter().filter_map(|d| match d {
Definition::Event(v) => Some(v),
_ => None,
})
}
#[inline]
pub fn property_definitions(&self) -> impl Iterator<Item = &PropertyDef> {
self.definitions.iter().filter_map(|d| match d {
Definition::Property(v) => Some(v),
_ => None,
})
}
#[inline]
pub fn structure_definitions(&self) -> impl Iterator<Item = &StructureDef> {
self.definitions.iter().filter_map(|d| match d {
Definition::Structure(v) => Some(v),
_ => None,
})
}
#[inline]
pub fn union_definitions(&self) -> impl Iterator<Item = &UnionDef> {
self.definitions.iter().filter_map(|d| match d {
Definition::Union(v) => Some(v),
_ => None,
})
}
pub fn defined_names(&self) -> HashSet<&Identifier> {
self.definitions().map(|def| def.name()).collect()
}
}
impl FromIterator<Import> for ImportStatement {
fn from_iter<T: IntoIterator<Item = Import>>(iter: T) -> Self {
Self::new(Vec::from_iter(iter))
}
}
impl_has_source_span_for! {ImportStatement}
impl ImportStatement {
pub fn new(imports: Vec<Import>) -> Self {
Self {
span: None,
imports,
}
}
get_and_set_vec!(
pub
has has_imports,
imports_len,
imports,
imports_mut,
add_to_imports,
extend_imports
=> imports, Import
);
pub(crate) fn as_slice(&self) -> &[Import] {
self.imports.as_slice()
}
pub fn imported_modules(&self) -> HashSet<&Identifier> {
self.imports()
.map(|imp| match imp {
Import::Module(v) => v.name(),
Import::Member(v) => v.module(),
})
.collect()
}
pub fn imported_types(&self) -> HashSet<&QualifiedIdentifier> {
self.imports()
.filter_map(|imp| {
if let Import::Member(imp) = imp {
Some(imp)
} else {
None
}
})
.collect()
}
}
impl From<Identifier> for Import {
fn from(v: Identifier) -> Self {
Self::Module(ModuleImport::from(v))
}
}
impl From<ModuleImport> for Import {
fn from(v: ModuleImport) -> Self {
Self::Module(v)
}
}
impl From<QualifiedIdentifier> for Import {
fn from(v: QualifiedIdentifier) -> Self {
Self::Member(v)
}
}
enum_display_impl!(Import => Module, Member);
impl_has_source_span_for!(Import => variants Module, Member);
impl Display for ModuleImport {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
if let Some(version_uri) = self.version_uri() {
format!("{} version {}", self.name(), version_uri)
} else {
self.name().to_string()
}
)
}
}
impl From<Identifier> for ModuleImport {
fn from(value: Identifier) -> Self {
Self::new(value)
}
}
impl_has_source_span_for!(ModuleImport);
impl ModuleImport {
pub fn new(name: Identifier) -> Self {
Self {
span: Default::default(),
name,
version_uri: Default::default(),
}
}
pub fn with_version_uri(self, version_uri: Url) -> Self {
Self {
version_uri: Some(version_uri),
..self
}
}
get_and_set!(pub name, set_name => Identifier);
get_and_set!(pub version_uri, set_version_uri, unset_version_uri => optional has_version_uri, Url);
}