use openbim_step::express::{self as step, ParsedSchema};
use crate::attribute::{AggregateKind, Aggregation, Attribute, Bound};
use crate::entity::{EntityDef, InverseAttribute, UniqueRule, WhereRule};
use crate::registry::Schema;
use crate::types::{TypeDef, TypeKind};
pub(crate) fn parse(source: &str) -> Schema {
convert(step::parse(source))
}
fn convert(parsed: ParsedSchema) -> Schema {
let entities = parsed.entities.into_iter().map(entity).collect();
let types = parsed.types.into_iter().map(type_def).collect();
Schema::new(parsed.name, entities, types)
}
fn entity(parsed: step::EntityDef) -> EntityDef {
let mut def = EntityDef::new(parsed.name);
def.supertypes = parsed.supertypes;
def.abstract_ = parsed.abstract_;
def.attributes = parsed.attributes.into_iter().map(attribute).collect();
def.derived = parsed.derived;
def.where_rules = parsed
.where_rules
.into_iter()
.map(|rule| WhereRule::new(rule.label, rule.expression))
.collect();
def.inverses = parsed.inverses.into_iter().map(inverse).collect();
def.unique_rules = parsed
.unique_rules
.into_iter()
.map(|rule| {
let mut owned = UniqueRule::unlabelled(rule.attributes);
owned.label = rule.label;
owned
})
.collect();
def
}
fn attribute(parsed: step::Attribute) -> Attribute {
let mut built = Attribute::new(parsed.name, parsed.type_name);
built.optional = parsed.optional;
built.aggregate = parsed.aggregate;
built.aggregation = parsed.aggregation.into_iter().map(aggregation).collect();
built
}
fn inverse(parsed: step::InverseAttribute) -> InverseAttribute {
let mut built = InverseAttribute::new(parsed.name, parsed.entity, parsed.for_attribute);
built.redeclares = parsed.redeclares;
built.aggregation = parsed.aggregation.map(aggregation);
built
}
fn aggregation(parsed: step::Aggregation) -> Aggregation {
let kind = match parsed.kind {
step::AggregateKind::List => AggregateKind::List,
step::AggregateKind::Set => AggregateKind::Set,
step::AggregateKind::Bag => AggregateKind::Bag,
step::AggregateKind::Array => AggregateKind::Array,
other => unreachable!("openbim-step =0.11.0 declares no aggregate kind {other:?}"),
};
let mut built = Aggregation::new(kind, bound(parsed.lower), bound(parsed.upper));
built.unique = parsed.unique;
built.optional_elements = parsed.optional_elements;
built
}
fn bound(parsed: step::Bound) -> Bound {
match parsed {
step::Bound::Integer(value) => Bound::Integer(value),
step::Bound::Unbounded => Bound::Unbounded,
step::Bound::Expression(text) => Bound::Expression(text),
other => unreachable!("openbim-step =0.11.0 declares no bound form {other:?}"),
}
}
fn type_def(parsed: step::TypeDef) -> TypeDef {
let kind = match parsed.kind {
step::TypeKind::Defined(alias) => TypeKind::Defined(alias),
step::TypeKind::Enumeration(members) => TypeKind::Enumeration(members),
step::TypeKind::Select(members) => TypeKind::Select(members),
other => unreachable!("openbim-step =0.11.0 declares no type kind {other:?}"),
};
TypeDef::new(parsed.name, kind)
}