Browse Source

Working conformance check for AToMPM (multi-inheritance part)

Yentl Van Tendeloo 5 years ago
parent
commit
57b95d3ebb

+ 1 - 0
bootstrap/bootstrap.py

@@ -76,6 +76,7 @@ def bootstrap():
                     "element_eq": ["Boolean", "Element", "Element"],
                     "read_root": ["Element"],
                     "read_taskroot": ["Element"],
+                    "list_sort": ["Element", "Element"],
                     "log": ["String", "String"],
                     "time": ["Float"],
                     "hash": ["String", "String"],

+ 1 - 17
bootstrap/conformance_finding.alc

@@ -32,11 +32,6 @@ Boolean function find_type_mapping(model : Element):
 	// 2) find a mapping based on the current partial mapping, but only if it is not yet complete
 	// TODO this must be expanded for other things than trivial metamodels!
 	if (dict_len(model["model"]) > dict_len(tm)):
-		log("Model is incompletely typed!")
-		log("Model has: " + set_to_string(dict_keys(model["model"])))
-		log("Type mapping has: " + set_to_string(dict_keys(tm)))
-		log("Difference: " + set_to_string(set_difference(dict_keys(model["model"]), dict_keys(tm))))
-
 		// TODO for now, this only returns something for a simple case, where the MM has one edge, and one node
 		//      and it makes the assumption that SCD is the M3 level...
 
@@ -53,14 +48,11 @@ Boolean function find_type_mapping(model : Element):
 		nodes = allInstances(model["metamodel"], "Class")
 		edges = allInstances(model["metamodel"], "Association")
 
-		log("Searching for type...")
 		if (bool_and(set_len(edges) == 1, set_len(nodes) == 1)):
 			// Simple allocation: this seems like conformance bottom
 			node_source_element = set_pop(nodes)
 			node_target_element = node_source_element
 			edge_element = set_pop(edges)
-			log("Found node: " + node_source_element)
-			log("Found edge: " + edge_element)
 
 		elif (bool_and(set_len(edges) == 1, set_len(nodes) == 2)):
 			// Simple allocation: this seems like a type mapping
@@ -70,13 +62,9 @@ Boolean function find_type_mapping(model : Element):
 			node_target_element = readAssociationDestination(model["metamodel"], edge_element)
 
 			if (value_eq(node_source_element, node_target_element)):
-				log("Source and target are the same, meaning that the second node is unknown")
+				log("Could not automatically deduce mapping in a trivial way!")
 				return False!
 
-			log("Found edge: " + edge_element)
-			log("Found source node: " + node_source_element)
-			log("Found target node: " + node_target_element)
-
 		else:
 			log("Could not automatically deduce mapping in a trivial way!")
 			return False!
@@ -84,7 +72,6 @@ Boolean function find_type_mapping(model : Element):
 
 		// Now we have both an edge_element and node_element of the metamodel
 		// Now just trivially bind all elements!
-		log("Searching for type...")
 		elems = dict_keys(model["model"])
 		while (set_len(elems) > 0):
 			elem = set_pop(elems)
@@ -92,13 +79,10 @@ Boolean function find_type_mapping(model : Element):
 			if (bool_and(is_edge(model["model"][elem]), read_nr_out(model["model"][elem]) == 0)):
 				// An edge, and there is always exactly one, so type
 				retype(model, elem, edge_element)
-				log("Type " + elem + " as " + edge_element)
 
 				// The source and target are ALWAYS typed as well!
 				retype(model, readAssociationSource(model, elem), node_source_element)
-				log("Type " + readAssociationSource(model, elem) + " as " + node_source_element)
 				retype(model, readAssociationDestination(model, elem), node_target_element)
-				log("Type " + readAssociationDestination(model, elem) + " as " + node_target_element)
 			elif (node_source_element == node_target_element):
 				// A node, and we are sure that there is only one
 				retype(model, elem, node_source_element)

+ 3 - 3
bootstrap/core_algorithm.alc

@@ -80,9 +80,9 @@ String function get_instanceOf_link(model_id : String, metamodel_id : String):
 	if (set_len(all_links) > 1):
 		log("WARNING: multiple instanceOf relations were detected for this model; picking one at random!")
 	elif (set_len(all_links) == 0):
-		log("No types found!")
-		log("Source model: " + cast_value(read_attribute(core, model_id, "name")))
-		log("Target meta-model: " + cast_value(read_attribute(core, metamodel_id, "name")))
+		//log("No types found!")
+		//log("Source model: " + cast_value(read_attribute(core, model_id, "name")))
+		//log("Target meta-model: " + cast_value(read_attribute(core, metamodel_id, "name")))
 		return read_root()!
 	
 	choice = set_pop(all_links)

+ 1 - 0
bootstrap/primitives.alc

@@ -56,3 +56,4 @@ Float function time() = ?primitives/time
 String function hash(a : String) = ?primitives/hash
 Float function __sleep(a : Float, b : Boolean) = ?primitives/__sleep
 Boolean function is_error(a : Element) = ?primitives/is_error
+Element function list_sort(a : Element) = ?primitives/list_sort

+ 11 - 0
bootstrap/semi_primitives.alc

@@ -602,3 +602,14 @@ Element function list_delete(a : Element, b : Integer):
 
 	dict_delete(a, current)
 	return a!
+
+Void function dict_update(a : Element, b : Element):
+	Element keys
+	String key
+
+	keys = dict_keys(b)
+	while (set_len(keys) > 0):
+		key = set_pop(keys)
+		dict_overwrite(a, key, b[key])
+
+	return!

+ 11 - 4
examples/multi_conformance.py

@@ -11,14 +11,20 @@ include "primitives.alh"
 
 SimpleAttribute integer {
     constraint = $
-        Boolean function constraint(value : Element):
-            return is_physical_int(value)!
+        String function constraint(value : Element):
+            if is_physical_int(value):
+                return "OK"!
+            else:
+                return "Expected integer value instead of '" + cast_string(value) + "'"!
         $
 }
 SimpleAttribute string {
     constraint = $
-        Boolean function constraint(value : Element):
-            return is_physical_string(value)!
+        String function constraint(value : Element):
+            if is_physical_string(value):
+                return "OK"!
+            else:
+                return "Expected string value instead of '" + cast_string(value) + "'"!
         $
 }
 
@@ -59,6 +65,7 @@ print(model_types("models/model_string"))
 
 #print(verify("models/model_string", "formalisms/simple_mm", "models/conformance_AToMPM"))
 transformation_execute_AL("models/conformance_AToMPM", {"model": "models/model_integer", "metamodel": "formalisms/simple_mm", "type_mapping": model_types("models/model_integer").pop()[1]}, {})
+transformation_execute_AL("models/conformance_AToMPM", {"model": "models/model_string", "metamodel": "formalisms/simple_mm", "type_mapping": model_types("models/model_string").pop()[1]}, {})
 #print(verify("models/model_integer", "formalisms/simple_mm", "models/conformance_AToMPM"))
 #print(verify("models/model_string", "formalisms/simple_mm", "models/conformance_MetaDepth"))
 #print(verify("models/model_integer", "formalisms/simple_mm", "models/conformance_MetaDepth"))

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

@@ -95,6 +95,7 @@ Element function resolve(var_name : String)
 Boolean function has_input()
 Element function list_pop(lst : Element, index : Integer)
 Element function list_pop_final(lst : Element)
+Element function list_sort(a : Element)
 Element function set_copy(set : Element)
 String function set_to_string(set : Element)
 String function list_to_string(set : Element)
@@ -122,3 +123,4 @@ Element function dict_values(dict : Element)
 Boolean function is_error(a : Element)
 Element function range(max : Integer)
 String function spawn(function : Element, arguments : Element)
+Void function dict_update(a : Element, b : Element)

+ 10 - 0
kernel/modelverse_kernel/primitives.py

@@ -430,3 +430,13 @@ def is_error(a, **remainder):
         yield [("RETURN", [{'value': True}])]
     else:
         yield [("RETURN", [{'value': False}])]
+
+def list_sort(a, **remainder):
+    elements, = yield [("RO", [a['id']])]
+    values = yield [("RD", [a['id'], i]) for i in range(elements)]
+    values = yield [("RV", [i]) for i in values]
+    new_list, = yield [("CN", [])]
+    values = yield [("CNV", [v]) for v in sorted(values))
+    yield [("CD", [new_list, i, v]) for i, v in enumerate(values)]
+
+    yield [("RETURN", [{'id': new_list}])]

+ 44 - 11
models/Conformance/AToMPM.alc

@@ -1,6 +1,7 @@
 include "primitives.alh"
 include "object_operations.alh"
 include "modelling.alh"
+include "library.alh"
 
 Boolean function main(model : Element):
 	// Contains three types of models: model, metamodel, and type_mapping.
@@ -10,13 +11,10 @@ Boolean function main(model : Element):
 	// Thus only the check for multiple inheritance is being done, which checks for attributes.
 	// A full example is given in the Modelverse's internal conformance relation.
 
-	log("Performing conformance check!")
-
 	// Find all instances of classes
 	// First, find the class types
 	Element classes
 	classes = allInstances(model, "metamodel/Class")
-	log("Got classes: " + set_to_string(classes))
 
 	Element links
 	String link
@@ -28,23 +26,58 @@ Boolean function main(model : Element):
 	instances = allInstances(model, "type_mapping/Instance")
 	while (set_len(instances) > 0):
 		instance = set_pop(instances)
-		log("Found instance: " + instance)
-		log("   Connects to: " + cast_string(set_pop(allAssociationDestinations(model, instance, "type_mapping/TypeLink"))))
-		log("Association connects: " + instance + " --> " + cast_string(set_pop(allAssociationDestinations(model, instance, "type_mapping/TypeLink"))))
-		//dict_add(type_mapping, "model/" + string_replace(readAssociationSource(model, link), "type_mapping/instance_", ""), "metamodel/" + string_replace(readAssociationDestination(model, link), "type_mapping/type_", ""))
+		dict_add(type_mapping, "model/" + string_replace(instance, "type_mapping/instance_", ""), "metamodel/" + string_replace(set_pop(allAssociationDestinations(model, instance, "type_mapping/TypeLink")), "type_mapping/type_", ""))
 	
-	log("Found type mapping: " + dict_to_string(type_mapping))
-
 	// Check if each attribute is there, and satisfies the constraints
 	instances = dict_keys(type_mapping)
 	while (set_len(instances) > 0):
 		instance = set_pop(instances)
-		log("Found type: " + read_type(model, type_mapping[instance]))
 		if (read_type(model, type_mapping[instance]) == "metamodel/Class"):
 			// Got an instance of a Class
-			log("Got a class instance: " + instance)
+			String type
+			Element inherits_from
+			type = type_mapping[instance]
+
+			Element outgoing_links
+			String outgoing_link
+			Element attrs
+
+			outgoing_links = allOutgoingAssociationInstances(model, instance, "")
+			attrs = dict_create()
+			while (set_len(outgoing_links) > 0):
+				outgoing_link = set_pop(outgoing_links)
+				String name
+				if (dict_in(type_mapping, outgoing_link)):
+					name = read_attribute(model, type_mapping[outgoing_link], "name")
+					dict_add(attrs, name, model["model"][readAssociationDestination(model, outgoing_link)])
 
 			// Fetch a list of attributes that should be defined
 			// TODO
+			inherits_from = allAssociationDestinations(model, type, "metamodel/Inheritance")
+
+			String superclass
+			Element defining_attributes
+			Element last_found
+
+			last_found = dict_create()
+			while (set_len(inherits_from) > 0):
+				superclass = set_pop(inherits_from)
+				defining_attributes = getInstantiatableAttributes(model, superclass, "metamodel/AttributeLink")
+				dict_update(last_found, defining_attributes)
+
+			Element keys
+			String attr
+			Element constraint
+			String result
+			keys = dict_keys(attrs)
+			while (set_len(keys) > 0):
+				attr = set_pop(keys)
+				constraint = get_func_AL_model(import_node(read_attribute(model, last_found[attr], "constraint")))
+				result = constraint(attrs[attr])
+
+				if (result != "OK"):
+					log("Conformance not OK: " + result)
+					return False!
 
+	log("Conformance OK")
 	return True!

+ 1 - 1
wrappers/modelverse_SCCD.py

@@ -1,7 +1,7 @@
 """
 Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
 
-Date:   Fri May 25 13:34:41 2018
+Date:   Fri May 25 15:31:24 2018
 
 Model author: Yentl Van Tendeloo
 Model name:   MvK Server