Przeglądaj źródła

Conformance checker: begin porting to CDAPI for subtype checking

Joeri Exelmans 1 rok temu
rodzic
commit
361591f971
2 zmienionych plików z 15 dodań i 26 usunięć
  1. 10 20
      api/cd.py
  2. 5 6
      framework/conformance.py

+ 10 - 20
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):

+ 5 - 6
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):