From 361591f971563072c9e3bfd1645849b4d62ce09d Mon Sep 17 00:00:00 2001 From: Joeri Exelmans Date: Tue, 5 Nov 2024 13:59:44 +0100 Subject: [PATCH] Conformance checker: begin porting to CDAPI for subtype checking --- api/cd.py | 30 ++++++++++-------------------- framework/conformance.py | 11 +++++------ 2 files changed, 15 insertions(+), 26 deletions(-) diff --git a/api/cd.py b/api/cd.py index 5304694..1a79675 100644 --- a/api/cd.py +++ b/api/cd.py @@ -48,36 +48,26 @@ class CDAPI: self.transitive_sub_types = { type_name: set(get_transitive_sub_types(type_name)) for type_name in self.direct_sub_types } self.transitive_super_types = { type_name: set(get_transitive_super_types(type_name)) for type_name in self.direct_super_types } - def get_type(type_name: str): + def get_type(self, type_name: str): return self.bottom.read_outgoing_elements(self.m, type_name)[0] - def is_direct_subtype(super_type_name: str, sub_type_name: str): + def is_direct_subtype(self, super_type_name: str, sub_type_name: str): return sub_type_name in self.direct_sub_types[super_type] - def is_direct_supertype(sub_type_name: str, super_type_name: str): + def is_direct_supertype(self, sub_type_name: str, super_type_name: str): return super_type_name in self.direct_super_types[sub_type_name] - def is_subtype(super_type_name: str, sub_type_name: str): - return sub_type_name in self.transitive_sub_types[super_type] + # Note: according to this function, every class is a subtype of itself + def is_subtype(self, super_type_name: str, sub_type_name: str): + return sub_type_name in self.transitive_sub_types[super_type_name] - def is_supertype(sub_type_name: str, super_type_name: str): + # Note: according to this function, every class is a supertype of itself + def is_supertype(self, sub_type_name: str, super_type_name: str): return super_type_name in self.transitive_super_types[sub_type_name] # # The edge connecting an object to the value of a slot must be named `{object_name}_{attr_name}` - # def get_attr_link_name(self, class_name, attr_name): - # assoc_name = f"{class_name}_{attr_name}" - # type_edges = self.bottom.read_outgoing_elements(self.m, assoc_name) - # if len(type_edges) == 1: - # return assoc_name - # else: - # # look for attribute in the super-types - # conf = Conformance(self.bottom.state, self.model, self.type_model) - # conf.precompute_sub_types() # only need to know about subtypes - # super_types = [s for s in conf.sub_types if class_name in conf.sub_types[s]] - # for s in super_types: - # assoc_name = f"{s}_{attr_name}" - # if len(self.bottom.read_outgoing_elements(self.type_model, assoc_name)) == 1: - # return assoc_name + def get_attr_link_name(self, class_name, attr_name): + return self.type_model_names[self.find_attribute_type(class_name, attr_name)] # Attributes are inherited, so when we instantiate an attribute of a class, the AttributeLink may contain the name of the superclass def find_attribute_type(self, class_name: str, attr_name: str): diff --git a/framework/conformance.py b/framework/conformance.py index 1940481..2e71cf5 100644 --- a/framework/conformance.py +++ b/framework/conformance.py @@ -63,6 +63,7 @@ class Conformance: self.matches = {} self.candidates = {} + self.cdapi = CDAPI(state, type_model) self.odapi = ODAPI(state, model, type_model) def check_nominal(self, *, log=False): @@ -300,16 +301,14 @@ class Conformance: source_name = self.model_names[m_source] source_type_actual = self.type_mapping[source_name] source_type_expected = self.type_model_names[tm_source] - if source_type_actual != source_type_expected: - if source_type_actual not in self.sub_types[source_type_expected]: - errors.append(f"Invalid source type '{source_type_actual}' for element '{m_name}'") + if not self.cdapi.is_subtype(super_type_name=source_type_expected, sub_type_name=source_type_actual): + errors.append(f"Invalid source type '{source_type_actual}' for element '{m_name}'") # check if target is typed correctly target_name = self.model_names[m_target] target_type_actual = self.type_mapping[target_name] target_type_expected = self.type_model_names[tm_target] - if target_type_actual != target_type_expected: - if target_type_actual not in self.sub_types[target_type_expected]: - errors.append(f"Invalid target type '{target_type_actual}' for element '{m_name}'") + if not self.cdapi.is_subtype(super_type_name=source_type_expected, sub_type_name=source_type_actual): + errors.append(f"Invalid target type '{target_type_actual}' for element '{m_name}'") return errors def check_multiplicities(self):