1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
use super::{namespace::*, scope::*, type_ref::*, *};
use crate::ast;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Entity {
    /// Name of entity in snake_case
    pub name: String,
    pub attributes: Vec<EntityAttribute>,

    /// List of constraints corresponding to `SUBTYPE_CONSTRAINTS`
    /// and `SUPERTYPE OF` declaration in EXPRESS schema
    pub constraints: Vec<TypeRef>,

    /// List of types to be inherited by this entity
    ///
    /// When this entity is `sub` defined like:
    ///
    /// ```text
    /// ENTITY sub SUBTYPE OF (base);
    /// END_ENTITY;
    /// ```
    ///
    /// then this `supertypes` is `[base]`.
    ///
    pub supertypes: Vec<TypeRef>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct EntityAttribute {
    pub name: String,
    pub ty: TypeRef,
    pub optional: bool,
}

impl Legalize for EntityAttribute {
    type Input = ast::EntityAttribute;

    fn legalize(
        ns: &Namespace,
        ss: &Constraints,
        scope: &Scope,
        attr: &Self::Input,
    ) -> Result<Self, SemanticError> {
        let ty = TypeRef::legalize(ns, ss, scope, &attr.ty)?;
        let name = match &attr.name {
            ast::AttributeDecl::Reference(name) => name.clone(),
            _ => unimplemented!(),
        };
        Ok(EntityAttribute {
            name,
            ty,
            optional: attr.optional,
        })
    }
}

impl Legalize for Entity {
    type Input = ast::Entity;

    fn legalize(
        ns: &Namespace,
        ss: &Constraints,
        scope: &Scope,
        entity: &ast::Entity,
    ) -> Result<Self, SemanticError> {
        let name = entity.name.clone();
        let attributes = entity
            .attributes
            .iter()
            .map(|attr| EntityAttribute::legalize(ns, ss, scope, attr))
            .collect::<Result<Vec<_>, _>>()?;

        let supertypes = if let Some(supertypes) = &entity.subtype_of {
            supertypes
                .entity_references
                .iter()
                .map(|sup| TypeRef::from_path(ns, ss, &ns.resolve(scope, sup)?.0))
                .collect::<Result<Vec<TypeRef>, _>>()?
        } else {
            Vec::new()
        };

        let path = Path::entity(scope, &entity.name);
        let constraints = if let Some(instantiables) = ss.instantiables.get(&path) {
            instantiables
                .iter()
                .filter_map(|pce| match pce.len() {
                    // FIXME ignore complex entity case
                    1 => Some(TypeRef::from_path(ns, ss, &pce[0])),
                    _ => None,
                })
                .collect::<Result<Vec<TypeRef>, SemanticError>>()?
        } else {
            Vec::new()
        };

        Ok(Entity {
            name,
            attributes,
            constraints,
            supertypes,
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn legalize() {
        let example = SyntaxTree::example();
        let ns = Namespace::new(&example);
        let ss = Constraints::new(&ns, &example).unwrap();
        dbg!(&ns);
        let entity = &example.schemas[0].entities[0];
        let scope = Scope::root().pushed(ScopeType::Schema, &example.schemas[0].name);
        let entity = Entity::legalize(&ns, &ss, &scope, entity).unwrap();
        dbg!(&entity);
    }
}