Browse Source

Give cleaner error messages by not passing around potential null-refs

Yentl Van Tendeloo 9 years ago
parent
commit
90b327d60b
4 changed files with 135 additions and 116 deletions
  1. 23 60
      bootstrap/conformance_scd.alc
  2. 17 15
      bootstrap/modelling.alc
  3. 94 40
      integration/test_constructors_models.py
  4. 1 1
      integration/utils.py

+ 23 - 60
bootstrap/conformance_scd.alc

@@ -4,25 +4,31 @@ include "object_operations.alh"
 include "constructors.alh"
 include "modelling.alh"
 
-Boolean function is_direct_instance(model : Element, instance : Element, type : Element):
+Boolean function is_direct_instance(model : Element, instance : String, type : String):
 	// Just check whether or not the type mapping specifies the type as the type of the instance
-	return element_eq(dict_read_node(model["type_mapping"], instance), type)
+	return element_eq(dict_read_node(model["type_mapping"], model["model"][instance]), model["metamodel"]["model"][type])
 
-Boolean function is_nominal_instance(model : Element, instance : Element, type : Element):
-	if (bool_not(set_in_node(model["metamodel"]["model"], type))):
+Boolean function is_nominal_instance(model : Element, instance : String, type : String):
+	if (bool_not(dict_in(model["metamodel"]["model"], type))):
 		// type is not even in the specified metamodel, so this will never work
 		return False
 
-	if (bool_not(dict_in_node(model["type_mapping"], instance))):
+	if (bool_not(dict_in_node(model["type_mapping"], model["model"][instance]))):
 		// Doesn't even have a type
 		return False
 
-	return is_nominal_subtype(model["metamodel"], dict_read_node(model["type_mapping"], instance), type)
+	return is_nominal_subtype(model["metamodel"], getName(model["metamodel"], dict_read_node(model["type_mapping"], model["model"][instance])), type)
 
-Boolean function is_nominal_subtype(metamodel : Element, subclass : Element, superclass : Element):
-	if (element_eq(subclass, superclass)):
+Boolean function is_nominal_subtype(metamodel : Element, subclass : String, superclass : String):
+	if (element_eq(metamodel["model"][subclass], metamodel["model"][superclass])):
 		return True
 
+	if (bool_not(dict_in(metamodel["model"], subclass))):
+		return False
+
+	if (bool_not(dict_in(metamodel["model"], superclass))):
+		return False
+
 	Element superclasses
 	Element new_superclass
 	Element result
@@ -36,46 +42,6 @@ Boolean function is_nominal_subtype(metamodel : Element, subclass : Element, sup
 	
 	return False
 
-Boolean function is_structural_instance(model : Element, instance : Element, type : Element):
-	return is_structural_subtype(dict_read_node(model["type_mapping"], instance), type)
-	
-Boolean function is_structural_subtype(subtype : Element, supertype : Element):
-	// Determine whether it is just the exact type or not
-	if (element_eq(subtype, supertype)):
-		return True
-
-	// Find all links that are required (name and type) from the specified type
-	Element required_keys
-	required_keys = dict_keys(supertype)
-	Integer required_keys_len
-	required_keys_len = dict_len(required_keys)
-
-	String key
-	Element equivalent
-	Integer i
-	i = 0
-
-	// Go over all keys that we require
-	while (i < required_keys_len):
-		key = set_pop(required_keys)
-		// Check whether they exist in the instance
-		if (dict_in(subtype, key)):
-			// Normally, we should still check whether they don't violate the constraints imposed on the class (i.e., are actually present)
-			// For now, we ignore this and simply require that it is always there in the metamodel (not necessarily in the instance)
-			// TODO
-
-			// Still check whether the types match
-			if (bool_not(is_structural_subtype(subtype[key], supertype[key]))):
-				return False
-
-			// All clear, so pass on to the next attribute
-			i = i + 1
-		else:
-			return False
-
-	// No violations found, so OK
-	return True
-
 String function conformance_scd(model : Element):
 	// Initialization
 	Element keys
@@ -107,14 +73,17 @@ String function conformance_scd(model : Element):
 		Integer tuc
 		String key
 		Element tmp_dict
+
 		while (0 < list_len(keys)):
 			key = set_pop(keys)
-			if (is_nominal_instance(metamodel, metamodel["model"][key], scd["model"]["Association"])):
+			log("Read cardinalities for " + key)
+			if (is_nominal_instance(metamodel, key, "Association")):
 				tmp_dict = create_node()
 				slc = read_attribute(metamodel, key, "source_lower_cardinality")
 				suc = read_attribute(metamodel, key, "source_upper_cardinality")
 				tlc = read_attribute(metamodel, key, "target_lower_cardinality")
 				tuc = read_attribute(metamodel, key, "target_upper_cardinality")
+
 				if (element_neq(slc, read_root())):
 					dict_add(tmp_dict, "slc", slc)
 				if (element_neq(suc, read_root())):
@@ -140,14 +109,14 @@ String function conformance_scd(model : Element):
 			if (bool_not(set_in_node(metamodel["model"], dict_read_node(typing, element)))):
 				return "Type of element not in specified metamodel: " + model_name
 
-			if (bool_not(is_nominal_instance(model, element, dict_read_node(typing, element)))):
+			if (bool_not(is_nominal_instance(model, model_name, getName(metamodel, dict_read_node(typing, element))))):
 				return "Element is not an instance of its specified type: " + model_name
 
 			if (is_edge(element)):
-				src_model = read_edge_src(element)
-				dst_model = read_edge_dst(element)
-				src_metamodel = read_edge_src(dict_read_node(typing, element))
-				dst_metamodel = read_edge_dst(dict_read_node(typing, element))
+				src_model = getName(model, read_edge_src(element))
+				dst_model = getName(model, read_edge_dst(element))
+				src_metamodel = getName(metamodel, read_edge_src(dict_read_node(typing, element)))
+				dst_metamodel = getName(metamodel, read_edge_dst(dict_read_node(typing, element)))
 
 				if (bool_not(is_nominal_instance(model, src_model, src_metamodel))):
 					return "Source of model edge not typed by source of type: " + model_name
@@ -165,11 +134,8 @@ String function conformance_scd(model : Element):
 			Integer upper_val
 			Integer instances
 
-			log("Check cardinalities")
 			check_list = selectPossibleOutgoing(model, model_name, dict_keys(cardinalities))
-			log("Got outgoing")
 			while (0 < list_len(check_list)):
-				log("Loop")
 				check_type = set_pop(check_list)
 				if (dict_in(cardinalities, check_type)):
 					// Cardinalities defined for this association, so check them
@@ -187,9 +153,7 @@ String function conformance_scd(model : Element):
 
 			// Identical, but for outgoing, and thus for A in the figure
 			check_list = selectPossibleIncoming(model, model_name, dict_keys(cardinalities))
-			log("Got incoming")
 			while (0 < list_len(check_list)):
-				log("Loop")
 				check_type = set_pop(check_list)
 				if (dict_in(cardinalities, check_type)):
 					// Cardinalities defined for this association, so check them
@@ -205,7 +169,6 @@ String function conformance_scd(model : Element):
 						if (integer_lt(cardinalities[check_type]["suc"], instances)):
 							return "Upper cardinality violation for incoming edge at " + model_name
 
-	log("Finished, check multiplicities")
 	// Check multiplicities, if they are defined (optional)
 	Element metamodel_keys
 	String metamodel_element

+ 17 - 15
bootstrap/modelling.alc

@@ -92,22 +92,25 @@ String function instantiate_node(model : Element, type_name : String, instance_n
 
 String function find_attribute_type(model : Element, elem : String, name : String):
 	Element mm_elem
-	Element direct_type
+	String direct_type
 
-	direct_type = dict_read_node(model["type_mapping"], model["model"][elem])
+	direct_type = getName(model["metamodel"], dict_read_node(model["type_mapping"], model["model"][elem]))
 	mm_elem = find_attribute_definer(model["metamodel"], direct_type, name)
 
-	if (element_eq(mm_elem, read_root())):
+	if (value_eq(mm_elem, "")):
 		// Couldn't find element, so is not allowed!
-		return read_root()
+		return ""
 	else:
-		return getName(model["metamodel"], dict_read_edge(mm_elem, name))
+		return getName(model["metamodel"], dict_read_edge(model["metamodel"][mm_elem], name))
 
-Element function get_superclasses(model : Element, elem : Element):
+Element function get_superclasses(model : Element, name : String):
 	Element result
 	Integer i
 	Integer num_edges
 	Element edge
+	Element elem
+
+	elem = model["model"][name]
 
 	// Initialize empty set
 	result = create_node()
@@ -118,31 +121,31 @@ Element function get_superclasses(model : Element, elem : Element):
 	while (i < num_edges):
 		edge = read_out(elem, i)
 		if (element_eq(dict_read_node(model["type_mapping"], edge), model["inheritance"])):
-			create_edge(result, read_edge_dst(edge))
+			create_edge(result, getName(model, read_edge_dst(edge)))
 		i = i + 1
 
 	return result
 
-Element function find_attribute_definer(model : Element, elem : Element, name : String):
-	if (dict_in(elem, name)):
+String function find_attribute_definer(model : Element, elem_name : String, name : String):
+	if (dict_in(model["model"][elem_name], name)):
 		// Try in the current class definition
-		return elem
+		return elem_name
 	else:
 		// Not found, so go to all superclasses and try there
 		Element superclasses
 		Element current
 		Element found
 
-		superclasses = get_superclasses(model, elem)
+		superclasses = get_superclasses(model, elem_name)
 		while (list_len(superclasses) > 0):
 			current = set_pop(superclasses)
 			found = find_attribute_definer(model, current, name)
-			if (bool_not(element_eq(found, read_root()))):
+			if (bool_not(value_eq(found, ""))):
 				// Found something!
 				return current
 
-		// Return the de facto error-value
-		return read_root()
+		// Error
+		return ""
 
 Void function instantiate_attribute(model : Element, element : String, attribute_name : String, value : Element):
 	// Instantiate an attribute of something that needs to be instantiated
@@ -216,7 +219,6 @@ Void function construct_model():
 	String command
 	while (True):
 		command = input()
-
 		if (command == "instantiate_bottom"):
 			output(instantiate_bottom())
 		elif (command == "add_node"):

+ 94 - 40
integration/test_constructors_models.py

@@ -60,6 +60,94 @@ retype = [
         '"exit"',
     ]
 
+action_language = [
+        '"model"',
+        '"instantiate_node"', 1, '"Class"', '"Action"',
+        '"instantiate_node"', 1, '"Class"', '"Statement"',
+        '"instantiate_node"', 1, '"Class"', '"Expression"',
+        '"instantiate_node"', 1, '"Class"', '"Funcdef"',
+        '"instantiate_node"', 1, '"Class"', '"Param"',
+        '"instantiate_node"', 1, '"Class"', '"If"',
+        '"instantiate_node"', 1, '"Class"', '"Break"',
+        '"instantiate_node"', 1, '"Class"', '"While"',
+        '"instantiate_node"', 1, '"Class"', '"Continue"',
+        '"instantiate_node"', 1, '"Class"', '"Assign"',
+        '"instantiate_node"', 1, '"Class"', '"Return"',
+        '"instantiate_node"', 1, '"Class"', '"Output"',
+        '"instantiate_node"', 1, '"Class"', '"Declare"',
+        '"instantiate_node"', 1, '"Class"', '"Global"',
+        '"instantiate_node"', 1, '"Class"', '"Access"',
+        '"instantiate_node"', 1, '"Class"', '"Constant"',
+        '"instantiate_node"', 1, '"Class"', '"Input"',
+        '"instantiate_node"', 1, '"Class"', '"Resolve"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"Funcdef"', '"Any"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"Action"', '"Any"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"Param"', '"Any"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"Statement"', '"Action"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"Expression"', '"Action"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"Resolve"', '"Statement"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"If"', '"Statement"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"Break"', '"Statement"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"Continue"', '"Statement"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"Global"', '"Statement"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"While"', '"Statement"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"Assign"', '"Statement"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"Return"', '"Statement"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"Call"', '"Statement"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"Declare"', '"Statement"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"Call"', '"Expression"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"Access"', '"Expression"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"Constant"', '"Expression"',
+        '"instantiate_link"', 1, '"Inheritance"', '""', '"Input"', '"Expression"',
+        '"instantiate_link"', 1, '"Association"', '"statement_next"', '"Statement"', '"Statement"',
+        '"instantiate_attribute"', 1, '"statement_next"', '"name"', '"next"',
+        '"instantiate_link"', 1, '"Association"', '"if_cond"', '"If"', '"Expression"',
+        '"instantiate_attribute"', 1, '"if_cond"', '"name"', '"cond"',
+        '"instantiate_link"', 1, '"Association"', '"if_true"', '"If"', '"Statement"',
+        '"instantiate_attribute"', 1, '"if_true"', '"name"', '"true"',
+        '"instantiate_link"', 1, '"Association"', '"if_false"', '"If"', '"Statement"',
+        '"instantiate_attribute"', 1, '"if_false"', '"name"', '"false"',
+        '"instantiate_link"', 1, '"Association"', '"while_cond"', '"While"', '"Expression"',
+        '"instantiate_attribute"', 1, '"while_cond"', '"name"', '"cond"',
+        '"instantiate_link"', 1, '"Association"', '"while_body"', '"While"', '"Statement"',
+        '"instantiate_attribute"', 1, '"while_body"', '"name"', '"body"',
+        '"instantiate_link"', 1, '"Association"', '"assign_var"', '"Assign"', '"Any"',
+        '"instantiate_attribute"', 1, '"assign_var"', '"name"', '"var"',
+        '"instantiate_link"', 1, '"Association"', '"assign_value"', '"Assign"', '"Expression"',
+        '"instantiate_attribute"', 1, '"assign_value"', '"name"', '"value"',
+        '"instantiate_link"', 1, '"Association"', '"call_func"', '"Call"', '"Expression"',
+        '"instantiate_attribute"', 1, '"call_func"', '"name"', '"func"',
+        '"instantiate_link"', 1, '"Association"', '"call_params"', '"Call"', '"Param"',
+        '"instantiate_attribute"', 1, '"call_params"', '"name"', '"params"',
+        '"instantiate_link"', 1, '"Association"', '"call_last_param"', '"Call"', '"Param"',
+        '"instantiate_attribute"', 1, '"call_last_param"', '"name"', '"last_param"',
+        '"instantiate_link"', 1, '"Association"', '"break_while"', '"Break"', '"While"',
+        '"instantiate_attribute"', 1, '"break_while"', '"name"', '"while"',
+        '"instantiate_link"', 1, '"Association"', '"continue_while"', '"Continue"', '"While"',
+        '"instantiate_attribute"', 1, '"continue_while"', '"name"', '"while"',
+        '"instantiate_link"', 1, '"Association"', '"return_value"', '"Return"', '"Expression"',
+        '"instantiate_attribute"', 1, '"return_value"', '"name"', '"value"',
+        '"instantiate_link"', 1, '"Association"', '"resolve_var"', '"Resolve"', '"Any"',
+        '"instantiate_attribute"', 1, '"resolve_var"', '"name"', '"var"',
+        '"instantiate_link"', 1, '"Association"', '"access_var"', '"Access"', '"Any"',
+        '"instantiate_attribute"', 1, '"access_var"', '"name"', '"var"',
+        '"instantiate_link"', 1, '"Association"', '"constant_node"', '"Constant"', '"Any"',
+        '"instantiate_attribute"', 1, '"constant_node"', '"name"', '"node"',
+        '"instantiate_link"', 1, '"Association"', '"output_node"', '"Output"', '"Expression"',
+        '"instantiate_attribute"', 1, '"output_node"', '"name"', '"node"',
+        '"instantiate_link"', 1, '"Association"', '"global_var"', '"Global"', '"String"',
+        '"instantiate_attribute"', 1, '"global_var"', '"name"', '"var"',
+        '"instantiate_link"', 1, '"Association"', '"param_name"', '"Param"', '"String"',
+        '"instantiate_attribute"', 1, '"param_name"', '"name"', '"name"',
+        '"instantiate_link"', 1, '"Association"', '"param_value"', '"Param"', '"Expression"',
+        '"instantiate_attribute"', 1, '"param_value"', '"name"', '"value"',
+        '"instantiate_link"', 1, '"Association"', '"param_next_param"', '"Param"', '"Param"',
+        '"instantiate_attribute"', 1, '"param_next_param"', '"name"', '"next_param"',
+        '"instantiate_link"', 1, '"Association"', '"funcdef_body"', '"Funcdef"', '"Statement"',
+        '"instantiate_attribute"', 1, '"funcdef_body"', '"name"', '"body"',
+        '"exit"',
+    ]
+
 bottom_attributes = [
         '"model"',
         '"instantiate_link"', 1, '"Association"', '"lc"', '"Class"', '"Integer"',
@@ -145,28 +233,8 @@ def conformance_call(operation, model, metamodel):
                     '"access"', '"resolve"', '"%s"' % operation,
                     '3',
                     '"const"', 3,
-                    '"call"',
-                        '"access"', '"resolve"', '"dict_read"',
-                            '2',
-                            '"call"',
-                                '"access"', '"resolve"', '"dict_read"',
-                                    '2',
-                                    '"const"', 3,
-                                    '"const"', '"model"',
-                                    'false',
-                            '"const"', '"%s"' % model,
-                        'false',
-                    '"call"',
-                        '"access"', '"resolve"', '"dict_read"',
-                            '2',
-                            '"call"',
-                                '"access"', '"resolve"', '"dict_read"',
-                                    '2',
-                                    '"const"', 2,
-                                    '"const"', '"model"',
-                                    'false',
-                            '"const"', '"%s"' % metamodel,
-                        'false',
+                    '"const"', '"%s"' % model,
+                    '"const"', '"%s"' % metamodel,
                 'false',
             'true',
             ]
@@ -193,17 +261,6 @@ is_nominal_instance = \
     conformance_call("is_nominal_instance", "b", "C") + \
     conformance_call("is_nominal_instance", "c", "C")
 
-is_structural_instance = \
-    conformance_call("is_structural_instance", "a", "A") + \
-    conformance_call("is_structural_instance", "b", "A") + \
-    conformance_call("is_structural_instance", "c", "A") + \
-    conformance_call("is_structural_instance", "a", "B") + \
-    conformance_call("is_structural_instance", "b", "B") + \
-    conformance_call("is_structural_instance", "c", "B") + \
-    conformance_call("is_structural_instance", "a", "C") + \
-    conformance_call("is_structural_instance", "b", "C") + \
-    conformance_call("is_structural_instance", "c", "C")
-
 def conformance_check(node):
     return [
             '"output"',
@@ -220,6 +277,10 @@ class TestConstructorsModels(unittest.TestCase):
         commands = bottom + retype + bottom_attributes + conformance_check(1) + ['"return"', 'false']
         self.assertTrue(run_barebone(commands, ["OK"], 1))
 
+    def test_constructors_action_language(self):
+        commands = bottom + retype + bottom_attributes + action_language + conformance_check(1) + ['"return"', 'false']
+        self.assertTrue(run_barebone(commands, ["OK"], 1))
+
     def test_constructors_instantiate_scd(self):
         commands = bottom + retype + bottom_attributes + instantiate_scd + conformance_check(2) + ['"return"', 'false']
         self.assertTrue(run_barebone(commands, ["OK"], 1))
@@ -245,10 +306,3 @@ class TestConstructorsModels(unittest.TestCase):
                     'False', 'True', 'False',
                     'False', 'False', 'True']
         self.assertTrue(run_barebone(commands, expected, 1))
-
-    def test_constructors_is_structural_instance(self):
-        commands = bottom + retype + bottom_attributes + instantiate_example + is_structural_instance + ['"return"', 'false']
-        expected = ['True', 'False', 'True',
-                    'True', 'True', 'True',
-                    'True', 'False', 'True']
-        self.assertTrue(run_barebone(commands, expected, 1))

+ 1 - 1
integration/utils.py

@@ -274,7 +274,7 @@ def run_barebone(parameters, expected, interface="0", timeout=False, wait=False,
                         # Modelverse has already terminated, which isn't a good sign!
                         return False
 
-                    val = urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "username": username})), timeout=15).read()
+                    val = urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "username": username})), timeout=30).read()
                 except:
                     if timeout:
                         return True