Browse Source

Added code for cardinality checking

Yentl Van Tendeloo 9 years ago
parent
commit
3889bd6848

+ 45 - 0
bootstrap/conformance_scd.alc

@@ -80,6 +80,8 @@ String function conformance_scd(model : Element):
 	Element src_metamodel
 	Element dst_metamodel
 	Element element
+	Element check_list
+	Element check_type
 
 	// Load in variables
 	keys = dict_keys(model["model"])
@@ -112,6 +114,49 @@ String function conformance_scd(model : Element):
 			if (bool_not(is_nominal_instance(model, dst_model, dst_metamodel))):
 				return "Destination of model edge not typed by source of type: " + model_name
 
+		// Check cardinality for all of our edges
+		//
+		//      SLC..SUC     TLC..TUC
+		//   A  ---------------------> B
+		//
+		// First the incoming, so we are at B in the above figure
+		check_list = allPossibleIncoming(model, model_name)
+		while (0 < list_len(check_list)):
+			Integer instances
+			Integer lower_val
+			Integer upper_val
+			check_type = set_pop(check_list)
+			lower_val = read_attribute(metamodel, reverseNameLookup(metamodel, check_type), "target_lower_cardinality")
+			upper_val = read_attribute(metamodel, reverseNameLookup(metamodel, check_type), "target_upper_cardinality")
+			instances = list_len(allIncomingAssociationInstances(model, element, check_type))
+			if (element_neq(lower_val, read_root())):
+				// A lower multiplicity was defined at the target
+				if (lower_val > instances):
+					return "Lower cardinality violation for incoming edge at " + model_name
+			if (element_neq(upper_val, read_root())):
+				// A lower multiplicity was defined at the target
+				if (upper_val < instances):
+					return "Upper cardinality violation for incoming edge at " + model_name
+
+		// Identical, but for outgoing, and thus for A in the figure
+		check_list = allPossibleOutgoing(model, model_name)
+		while (0 < list_len(check_list)):
+			Integer instances
+			Integer lower_val
+			Integer upper_val
+			check_type = set_pop(check_list)
+			lower_val = read_attribute(metamodel, reverseNameLookup(metamodel, check_type), "source_lower_cardinality")
+			upper_val = read_attribute(metamodel, reverseNameLookup(metamodel, check_type), "source_upper_cardinality")
+			instances = list_len(allOutgoingAssociationInstances(model, element, check_type))
+			if (element_neq(lower_val, read_root())):
+				// A lower multiplicity was defined at the source
+				if (lower_val > instances):
+					return "Lower cardinality violation for incoming edge at " + model_name
+			if (element_neq(upper_val, read_root())):
+				// A lower multiplicity was defined at the source
+				if (upper_val < instances):
+					return "Upper cardinality violation for incoming edge at " + model_name
+
 	// Check multiplicities, if they are defined (optional)
 	Element metamodel_keys
 	String metamodel_element

+ 44 - 0
bootstrap/object_operations.alc

@@ -25,6 +25,50 @@ Element function allInstances(model : Element, type : Element):
 	
 	return result
 
+Element function allPossibleIncoming(model : Element, target : String):
+	// Find all possible incoming link types for the target model
+	// Should also include those specified on the superclass(es)
+	Element all_elems
+	String type
+	Element metamodel
+	Element elem
+	Element result
+
+	result = create_node()
+	metamodel = model["metamodel"]
+	all_elems = dict_keys(model["metamodel"]["model"])
+	
+	while (0 < list_len(all_elems)):
+		type = set_pop(all_elems)
+		elem = metamodel["model"][type]
+		if (is_edge(elem)):
+			if (is_nominal_instance(metamodel, model["model"][target], read_edge_src(elem))):
+				set_add(result, elem)
+	
+	return result
+
+Element function allPossibleOutgoing(model : Element, source : String):
+	// Find all possible outgoing link types for the source model
+	// Should also include those specified on the superclass(es)
+	Element all_elems
+	String type
+	Element metamodel
+	Element elem
+	Element result
+
+	result = create_node()
+	metamodel = model["metamodel"]
+	all_elems = dict_keys(model["metamodel"]["model"])
+	
+	while (0 < list_len(all_elems)):
+		type = set_pop(all_elems)
+		elem = metamodel["model"][type]
+		if (is_edge(elem)):
+			if (is_nominal_instance(metamodel, model["model"][source], read_edge_dst(elem))):
+				set_add(result, elem)
+	
+	return result
+
 Element function allOutgoingAssociationInstances(model : Element, source : Element, assoc : Element):
 	// Read out all outgoing edges of the model and select those that are typed by the specified association
 	// TODO for some reason this crashes if allInstances is used!

+ 2 - 0
interface/HUTN/includes/object_operations.alh

@@ -7,3 +7,5 @@ Element function getInstantiatableAttributes(a: Element, b: Element)
 String function getName(a: Element, b: Element)
 String function reverseNameLookup(a: Element, b: Element)
 String function print_dict(dict : Element)
+Element function allPossibleIncoming(model : Element, target : String)
+Element function allPossibleOutgoing(model : Element, source : String)