소스 검색

Merge branch 'master' into MvK_rules

Yentl Van Tendeloo 7 년 전
부모
커밋
28dde5528f
83개의 변경된 파일3310개의 추가작업 그리고 1241개의 파일을 삭제
  1. 46 11
      bootstrap/90_core_formalism.mvc
  2. 7 16
      bootstrap/bootstrap.py
  3. 6 2
      bootstrap/bottom.mvc
  4. 26 26
      bootstrap/conformance_finding.alc
  5. 9 9
      bootstrap/conformance_scd.alc
  6. 4 4
      bootstrap/constructors.alc
  7. 194 82
      bootstrap/core_algorithm.alc
  8. 1 0
      bootstrap/initial_code_task.alc
  9. 32 0
      bootstrap/io.alc
  10. 122 0
      bootstrap/json.alc
  11. 13 0
      bootstrap/metamodels.alt
  12. 142 17
      bootstrap/mini_modify.alc
  13. 49 40
      bootstrap/model_management.alc
  14. 44 8
      bootstrap/modelling.alc
  15. 41 9
      bootstrap/object_operations.alc
  16. 29 7
      bootstrap/pm.mvc
  17. 8 17
      bootstrap/primitives.alc
  18. 22 4
      bootstrap/ramify.alc
  19. 1 1
      bootstrap/random.alc
  20. 55 9
      bootstrap/semi_primitives.alc
  21. 1 1
      bootstrap/services.alc
  22. 8 3
      bootstrap/tracability.mvc
  23. 22 12
      bootstrap/transform.alc
  24. 14 12
      bootstrap/typing.alc
  25. 8 18
      bootstrap/utils.alc
  26. 1 1
      hybrid_server/classes/mvkcontroller.xml
  27. 10 2
      integration/code/pn_design.mvc
  28. 1 1
      integration/code/pn_print.mvc
  29. 6 6
      integration/code/reachability.alc
  30. 4 4
      integration/code/reachability_subfunction.alc
  31. 4 4
      integration/code/reachabilitygraph_print.mvc
  32. 2 1
      interface/HUTN/grammars/actionlanguage.g
  33. 3 0
      interface/HUTN/hutn_compiler/hutnparser.py
  34. 24 12
      interface/HUTN/hutn_compiler/semantics_visitor.py
  35. 3 0
      interface/HUTN/includes/io.alh
  36. 2 0
      interface/HUTN/includes/json.alh
  37. 2 0
      interface/HUTN/includes/modelling.alh
  38. 2 1
      interface/HUTN/includes/object_operations.alh
  39. 12 17
      interface/HUTN/includes/primitives.alh
  40. 0 1
      interface/HUTN/includes/utils.alh
  41. 7 0
      interface/HUTN/test/constructor_compilation_action_language/code/string_concat.al
  42. 1 0
      interface/HUTN/test/constructor_compilation_action_language/expected/string_concat
  43. 7 4
      interface/HUTN/test/constructor_compilation_action_language/test_compile.py
  44. 4 12
      kernel/modelverse_jit/intrinsics.py
  45. 19 0
      kernel/modelverse_kernel/compiled.py
  46. 15 57
      kernel/modelverse_kernel/primitives.py
  47. 56 67
      kernel/test/primitives/test_cast.py
  48. 72 0
      models/MM_render.mvc
  49. 20 3
      models/MM_rendered_graphical.mvc
  50. 31 9
      models/MM_rendered_plot.mvc
  51. 48 10
      models/SCCD.mvc
  52. 7 2
      models/SCCD_Trace.mvc
  53. 2 2
      models/SCCD_execute.alc
  54. 9 2
      models/architecture.mvc
  55. 2 2
      models/combine_EPN.mvc
  56. 27 8
      models/control_PW.mvc
  57. 16 5
      models/environment_PW.mvc
  58. 3 3
      models/epn_print.alc
  59. 1 1
      models/merge_EPN.alc
  60. 25 7
      models/petrinet_ports.mvc
  61. 4 0
      models/petrinets.mvc
  62. 26 8
      models/plant_PW.mvc
  63. 3 3
      models/pn_print.alc
  64. 7 2
      models/query.mvc
  65. 6 6
      models/reachability.alc
  66. 16 4
      models/reachability_graph.mvc
  67. 2 2
      models/reachabilitygraph_print.mvc
  68. 213 0
      models/render_OD.alc
  69. 182 0
      models/render_SCD.alc
  70. 2 0
      models/requirements.mvc
  71. 25 0
      models/test_compiler.alc
  72. 11 3
      models/trace.mvc
  73. 6 1
      scripts/HUTN_service.py
  74. 89 0
      scripts/JSON_service.py
  75. 5 0
      scripts/run_local_modelverse.py
  76. 1 1
      state/modelverse_state/main.py
  77. 12 13
      unit/test_all.py
  78. 436 153
      wrappers/classes/modelverse.xml
  79. 2 0
      wrappers/compile.sh
  80. 54 9
      wrappers/modelverse.py
  81. 843 413
      wrappers/modelverse_SCCD.py
  82. 10 68
      wrappers/test.py
  83. 3 3
      wrappers/test_modelverse.py

+ 46 - 11
bootstrap/90_core_formalism.mvc

@@ -3,6 +3,7 @@ include "primitives.alh"
 
 SimpleClassDiagrams CoreFormalism {
     SimpleAttribute String {
+        name = "String"
         constraint = $
             String function constraint(model : Element, name : String):
                 if (bool_not(is_physical_string(model["model"][name]))):
@@ -13,6 +14,7 @@ SimpleClassDiagrams CoreFormalism {
     }
 
     SimpleAttribute Permissions {
+        name = "Permissions"
         constraint = $
             String function constraint(model : Element, name : String):
                 Element self
@@ -21,17 +23,18 @@ SimpleClassDiagrams CoreFormalism {
                     return "Permissions has no string value"!
                 if (bool_not(string_len(self) == 3)):
                     return "Permissions string is not of correct length"!
-                if (bool_or(cast_s2i(string_get(self, 0)) < 0, cast_s2i(string_get(self, 0)) > 2)):
+                if (bool_or(cast_integer(string_get(self, 0)) < 0, cast_integer(string_get(self, 0)) > 2)):
                     return "Owner permission is not in range [0, 2]"!
-                if (bool_or(cast_s2i(string_get(self, 1)) < 0, cast_s2i(string_get(self, 1)) > 2)):
+                if (bool_or(cast_integer(string_get(self, 1)) < 0, cast_integer(string_get(self, 1)) > 2)):
                     return "Group permission is not in range [0, 2]"!
-                if (bool_or(cast_s2i(string_get(self, 2)) < 0, cast_s2i(string_get(self, 2)) > 2)):
+                if (bool_or(cast_integer(string_get(self, 2)) < 0, cast_integer(string_get(self, 2)) > 2)):
                     return "Other permission is not in range [0, 2]"!
                 return "OK"!
             $
     }
 
     SimpleAttribute Boolean {
+        name = "Boolean"
         constraint = $
             String function constraint(model : Element, name : String):
                 if (bool_not(is_physical_boolean(model["model"][name]))):
@@ -42,6 +45,7 @@ SimpleClassDiagrams CoreFormalism {
     }
 
     SimpleAttribute Natural {
+        name = "Natural"
         constraint = $
             String function constraint(model : Element, name : String):
                 if (bool_not(is_physical_int(model["model"][name]))):
@@ -54,76 +58,107 @@ SimpleClassDiagrams CoreFormalism {
     }
 
     Class User {
+        name = "User"
         name : String
         password : String
         admin : Boolean
     }
 
     Class Group {
+        name = "Group"
         name : String
     }
 
-    Association ownedBy (Group, User) {}
-    Association belongsTo (User, Group) {}
+    Association ownedBy (Group, User) {
+        name = "ownedBy"
+    }
+    Association belongsTo (User, Group) {
+        name = "belongsTo"
+    }
 
     Class Entry {
+        name = "Entry"
         name : String
         permissions : Permissions
     }
 
     Class Folder : Entry {
+        name = "Folder"
     }
 
-    Association contains (Folder, Entry) {}
+    Association contains (Folder, Entry) {
+        name = "contains"
+    }
 
     Class Model : Entry {
+        name = "Model"
         location : String
     }
 
-    Class TypeMapping : Model {}
+    Class TypeMapping : Model {
+        name = "TypeMapping"
+    }
 
     Association instanceOf (Model, Model) {
+        name = "instanceOf"
     }
 
     Association owner (Model, User) {
+        name = "owner"
         target_lower_cardinality = 1
         target_upper_cardinality = 1
     }
 
     Association group (Model, Group) {
+        name = "group"
         target_lower_cardinality = 1
         target_upper_cardinality = 1
     }
 
-    Class Transformation : Model {}
+    Class Transformation : Model {
+        name = "Transformation"
+    }
 
-    Class ModelTransformation : Transformation {}
+    Class ModelTransformation : Transformation {
+        name = "ModelTransformation"
+    }
 
-    Class ActionLanguage : Transformation {}
+    Class ActionLanguage : Transformation {
+        name = "ActionLanguage"
+    }
 
-    Class ManualOperation : Transformation {}
+    Class ManualOperation : Transformation {
+        name = "ManualOperation"
+    }
 
     Association transformInput (Model, Transformation) {
+        name = "transformInput"
         name : String
     }
+
     Association transformOutput (Transformation, Model) {
+        name = "transformOutput"
         name : String
     }
 
     Association tracability (Model, Model) {
+        name = "tracability"
         type : String
     }
 
     Association semantics (instanceOf, ActionLanguage) {
+        name = "semantics"
         target_lower_cardinality = 1
         target_upper_cardinality = 1
     }
     Association typing (instanceOf, TypeMapping) {
+        name = "typing"
         target_lower_cardinality = 1
         target_upper_cardinality = 1
     }
 
     Class Service {
+        name = "Service"
         name : String
         port : String
     }

+ 7 - 16
bootstrap/bootstrap.py

@@ -39,22 +39,12 @@ def bootstrap():
                     "string_len": ["Integer", "String"],
                     "string_split": ["Element", "String", "String"],
                     "value_eq":  ["Boolean", "Element", "Element"],
-                    "cast_i2f": ["Float", "Integer"],
-                    "cast_i2s": ["String", "Integer"],
-                    "cast_i2b": ["Boolean", "Integer"],
-                    "cast_f2i": ["Integer", "Float"],
-                    "cast_f2b": ["Boolean", "Float"],
-                    "cast_f2s": ["String", "Float"],
-                    "cast_s2i": ["Integer", "String"],
-                    "cast_s2f": ["Float", "String"],
-                    "cast_s2b": ["Boolean", "String"],
-                    "cast_b2i": ["Integer", "Boolean"],
-                    "cast_b2f": ["Float", "Boolean"],
-                    "cast_b2s": ["String", "Boolean"],
-                    "cast_e2s": ["String", "Element"],
-                    "cast_a2s": ["String", "Action"],
-                    "cast_v2s": ["String", "Element"],
-                    "cast_id2s": ["String", "Element"],
+                    "cast_float": ["Float", "Element"],
+                    "cast_string": ["String", "Element"],
+                    "cast_boolean": ["Boolean", "Element"],
+                    "cast_integer": ["Integer", "Element"],
+                    "cast_value": ["String", "Element"],
+                    "cast_id": ["String", "Element"],
                     "list_insert": ["Element", "Element", "Integer", "Element"],
                     "list_delete": ["Element", "Element", "Integer"],
                     "dict_add_fast": ["Element", "Element", "Element", "Element"],
@@ -71,6 +61,7 @@ def bootstrap():
                     "is_physical_string": ["Boolean", "Element"],
                     "is_physical_action": ["Boolean", "Element"],
                     "is_physical_float": ["Boolean", "Element"],
+                    "is_physical_none": ["Boolean", "Element"],
                     "create_node": ["Element"],
                     "create_edge": ["Element", "Element", "Element"],
                     "create_value": ["Element", "Element"],

+ 6 - 2
bootstrap/bottom.mvc

@@ -1,8 +1,12 @@
 import models/SimpleClassDiagrams as SCD
 
 SCD Bottom{
-    Class Node {}
-    Association Edge : Node (Node, Node) {}
+    Class Node {
+        name = "Node"
+    }
+    Association Edge : Node (Node, Node) {
+        name = "Edge"
+    }
 }
 
 export Bottom to models/Bottom

+ 26 - 26
bootstrap/conformance_finding.alc

@@ -32,10 +32,10 @@ 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("Missing: " + set_to_string(set_difference(dict_keys(model["model"]), dict_keys(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...
@@ -49,30 +49,30 @@ Boolean function find_type_mapping(model : Element):
 		node_element = read_root()
 		edge_element = read_root()
 
-		elems = dict_keys(model["metamodel"]["model"])
-		log("Elements in metamodel: " + set_to_string(elems))
-		while (set_len(elems) > 0):
-			elem = set_pop(elems)
-			// log("Check " + elem)
-
-			if (bool_not(is_edge(model["metamodel"]["model"][elem]))):
-				if (element_neq(node_element, read_root())):
-					log("Multiple nodes detected!")
-					return False!
-				node_element = elem
-			else:
-				// Is an edge, but might be the inheritance link...
-				log("type: " + read_type(model["metamodel"], elem))
-				if (read_type(model["metamodel"], elem) != "Inheritance"):
-					// Is not the inheritance link
-					if (element_neq(edge_element, read_root())):
-						log("Multiple edges detected")
-						return False!
-					edge_element = elem
+		Element nodes
+		Element edges
+		nodes = allInstances(model["metamodel"], "Class")
+		edges = allInstances(model["metamodel"], "Association")
 
-		if (bool_or(element_eq(node_element, read_root()), element_eq(edge_element, read_root()))):
-			log("Not both node and edge detected")
+		if (set_len(nodes) > 1):
+			log("Got nodes: " + set_to_string(nodes))
+			log("Multiple nodes detected!")
 			return False!
+		elif (set_len(edges) > 1):
+			log("Got edges: " + set_to_string(edges))
+			log("Multiple edges detected!")
+			return False!
+		elif (set_len(nodes) != 1):
+			log("No node found!")
+			return False!
+		elif (set_len(edges) != 1):
+			log("No edge found!")
+			return False!
+		else:
+			node_element = set_pop(nodes)
+			edge_element = set_pop(edges)
+			log("Found node: " + node_element)
+			log("Found edge: " + edge_element)
 
 		// Now we have bot an edge_element and node_element of the metamodel
 		// Now just trivially bind all elements!

+ 9 - 9
bootstrap/conformance_scd.alc

@@ -159,10 +159,10 @@ String function conformance_scd(model : Element):
 				return "Type of element not in specified metamodel: " + model_info(model, model_name)!
 
 			if (is_edge(element)):
-				src_model = reverse_m[cast_id2s(read_edge_src(element))]
-				dst_model = reverse_m[cast_id2s(read_edge_dst(element))]
-				src_metamodel = reverse_mm[cast_id2s(read_edge_src(metamodel["model"][typing[model_name]]))]
-				dst_metamodel = reverse_mm[cast_id2s(read_edge_dst(metamodel["model"][typing[model_name]]))]
+				src_model = reverse_m[cast_id(read_edge_src(element))]
+				dst_model = reverse_m[cast_id(read_edge_dst(element))]
+				src_metamodel = reverse_mm[cast_id(read_edge_src(metamodel["model"][typing[model_name]]))]
+				dst_metamodel = reverse_mm[cast_id(read_edge_dst(metamodel["model"][typing[model_name]]))]
 
 				if (bool_not(is_nominal_instance(model, src_model, src_metamodel))):
 					log("got: " + src_model)
@@ -194,13 +194,13 @@ String function conformance_scd(model : Element):
 							// A lower cardinality was defined at the target
 							if (integer_gt(cardinalities[check_type]["tlc"], instances)):
 								String error
-								error = (("Lower cardinality violation for outgoing edge of type " + check_type) + " at ") + model_info(model, model_name)
+								error = "Lower cardinality violation for outgoing edge of type " + check_type + " at " + model_info(model, model_name)
 								return error!
 						if (dict_in(cardinalities[check_type], "tuc")):
 							// An upper cardinality was defined at the target
 							if (integer_lt(cardinalities[check_type]["tuc"], instances)):
 								String error
-								error = (("Upper cardinality violation for outgoing edge of type " + check_type) + " at ") + model_info(model, model_name)
+								error = "Upper cardinality violation for outgoing edge of type " + check_type + " at " + model_info(model, model_name)
 								return error!
 
 			// Identical, but for outgoing, and thus for A in the figure
@@ -218,13 +218,13 @@ String function conformance_scd(model : Element):
 							// A lower cardinality was defined at the source
 							if (integer_gt(cardinalities[check_type]["slc"], instances)):
 								String error
-								error = (("Lower cardinality violation for incoming edge of type " + check_type) + " at ") + model_info(model, model_name)
+								error = "Lower cardinality violation for incoming edge of type " + check_type + " at " + model_info(model, model_name)
 								return error!
 						if (dict_in(cardinalities[check_type], "suc")):
 							// An upper cardinality was defined at the source
 							if (integer_lt(cardinalities[check_type]["suc"], instances)):
 								String error
-								error = (("Upper cardinality violation for incoming edge of type " + check_type) + " at ") + model_info(model, model_name)
+								error = "Upper cardinality violation for incoming edge of type " + check_type + " at " + model_info(model, model_name)
 								return error!
 
 			constraint_function = read_attribute(metamodel, typing[model_name], "constraint")
@@ -281,7 +281,7 @@ String function conformance_scd(model : Element):
 			result = check_location_conformance(model["model"][complex_instance], complex_type)
 
 			if (result != "OK"):
-				return ((("Complex attribute doesn't match for: " + complex_instance) + "\n Message: ") + result)!
+				return "Complex attribute doesn't match for: " + complex_instance + "\n Message: " + result!
 
 	// Structure seems fine, now do global constraints
 	Element global_constraints

+ 4 - 4
bootstrap/constructors.alc

@@ -36,8 +36,8 @@ Element function construct_function_list(list : Element):
 		elif (command == "mutable_funcdef"):
 			result = construct_funcdef(True, list)
 		else:
-			log("ERROR (1): did not understand command " + cast_e2s(command))
-			output("ERROR: compiled code not understood: " + cast_e2s(command))
+			log("ERROR (1): did not understand command " + cast_value(command))
+			output("ERROR: compiled code not understood: " + cast_value(command))
 			return read_root()!
 
 		continue = list_pop_final(list)
@@ -218,8 +218,8 @@ Element function construct_unknown(list : Element):
 	elif (elem == "continue"):
 		return construct_continue(list)!
 	else:
-		log("ERROR (2): did not understand command " + cast_e2s(elem))
-		output("ERROR: compiled code not understood: " + cast_e2s(elem))
+		log("ERROR (2): did not understand command " + cast_value(elem))
+		output("ERROR: compiled code not understood: " + cast_value(elem))
 		return read_root()!
 
 Action function construct_if(list : Element):

+ 194 - 82
bootstrap/core_algorithm.alc

@@ -75,8 +75,8 @@ String function get_instanceOf_link(model_id : String, metamodel_id : String):
 		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_v2s(read_attribute(core, model_id, "name")))
-		log("Target meta-model: " + cast_v2s(read_attribute(core, metamodel_id, "name")))
+		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)
@@ -110,9 +110,11 @@ Element function get_full_model(model_id : String, metamodel_id : String):
 			dict_add(m, "metamodel", mm)
 
 	if (element_neq(choice, read_root())):
-		if (set_len(allAssociationDestinations(core, choice, "typing")) == 1):
+		Element types
+		types = allAssociationDestinations(core, choice, "typing")
+		if (set_len(types) == 1):
 			// Add the preferred original type mapping
-			set_type_mapping(m, import_node(read_attribute(core, set_pop(allAssociationDestinations(core, choice, "typing")), "location")))
+			set_type_mapping(m, import_node(read_attribute(core, set_pop(types), "location")))
 		else:
 			// Start from scratch
 			new_type_mapping(m)
@@ -125,8 +127,8 @@ Element function get_full_model(model_id : String, metamodel_id : String):
 		return m!
 	else:
 		log("No type mapping could be deduced!")
-		log("Error for " + cast_v2s(read_attribute(core, model_id, "name")))
-		log(" and type " + cast_v2s(read_attribute(core, metamodel_id, "name")))
+		log("Error for " + cast_value(read_attribute(core, model_id, "name")))
+		log(" and type " + cast_value(read_attribute(core, metamodel_id, "name")))
 		return read_root()!
 
 Integer function get_relation_to_model(user_id : String, model_id : String):
@@ -382,7 +384,7 @@ String function export_typing(model : Element, name : String):
 
 	// Create type mapping model
 	String location
-	location = "type mappings/" + cast_id2s(get_type_mapping(model))
+	location = "type mappings/" + cast_id(get_type_mapping(model))
 	export_node(location, get_type_mapping(model))
 
 	String instance_of
@@ -403,7 +405,7 @@ Void function model_create(model : Element, name : String, type_id : String, kin
 	String instance_of
 
 	// Create model itself
-	location = "models/" + cast_id2s(model)
+	location = "models/" + cast_id(model)
 	export_node(location, model["model"])
 
 	model_id = instantiate_node(core, kind, "")
@@ -426,7 +428,7 @@ Void function model_overwrite(model : Element, model_id : String, metamodel_id :
 	String location
 	String instanceOf_link
 
-	location = "models/" + cast_id2s(model)
+	location = "models/" + cast_id(model)
 	export_node(location, model["model"])
 
 	// Change location in meta-data
@@ -639,7 +641,7 @@ Element function execute_operation(operation_id : String, input_models : Element
 	while (set_len(iter) > 0):
 		edge = set_pop(iter)
 		dict_add(output_metamodels, read_attribute(core, edge, "name"), full_name(readAssociationDestination(core, edge)))
-
+	
 	// 1) Find merged metamodel
 
 	exact_type = read_type(core, operation_id)
@@ -679,8 +681,8 @@ Element function execute_operation(operation_id : String, input_models : Element
 			Element m
 			m = get_full_model(get_entry_id(input_models[set_pop(dict_keys(input_models))]), get_entry_id(input_metamodels[set_pop(dict_keys(input_metamodels))]))
 			if (element_eq(m, read_root())):
-				log("Signature mismatch in operation for tag " + cast_v2s(set_pop(dict_keys(input_models))))
-				output("Signature mismatch in operation for tag " + cast_v2s(set_pop(dict_keys(input_models))))
+				log("Signature mismatch in operation for tag " + cast_value(set_pop(dict_keys(input_models))))
+				output("Signature mismatch in operation for tag " + cast_value(set_pop(dict_keys(input_models))))
 				return read_root()!
 			merged_model = model_copy(m)
 		elif (bool_and(dict_len(input_models) == 0, dict_len(output_metamodels) == 0)):
@@ -708,7 +710,7 @@ Element function execute_operation(operation_id : String, input_models : Element
 			return read_root()!
 		result = transform(merged_model, operation)
 	elif (exact_type == "ManualOperation"):
-		output("Please perform manual operation " + cast_v2s(full_name(operation_id)))
+		output("Please perform manual operation " + cast_value(full_name(operation_id)))
 		modify(merged_model, True)
 		result = True
 	elif (exact_type == "ActionLanguage"):
@@ -835,7 +837,6 @@ Boolean function enact_action(pm : Element, element : String, prefix : String):
 Void function enact_PM(pm : Element, prefix : String):
 	Element worklist
 	String element
-	String start
 	String type
 	Boolean result
 	Element tuple
@@ -1035,40 +1036,96 @@ String function cmd_process_execute(process : String, prefix : String):
 	else:
 		return "Model not found: " + process!
 
-String function cmd_transformation_between(source_name : String, target_name : String):
-	String source_id
-	String target_id
-	Element onSource
-	Element onTarget
+String function cmd_transformation_between(source_dict : String, target_dict : String):
 	Element result
-	String transformation
+	Element subresult
+	String tag
+	String mm
+	String mm_id
+	Element links
+	String link
+	Element keys
 
-	source_id = get_entry_id(source_name)
-	if (source_id != ""):
-		target_id = get_entry_id(target_name)
+	result = allInstances(core, "Transformation")
 
-		if (target_id != ""):
-			onSource = allAssociationOrigins(core, source_id, "transformInput")
-			onTarget = allAssociationOrigins(core, target_id, "transformOutput")
+	// Iterate over all inputs
+	keys = dict_keys(source_dict)
+	while (set_len(keys) > 0):
+		subresult = set_create()
+		tag = set_pop(keys)
+		mm = source_dict[tag]
+		mm_id = get_entry_id(mm)
+
+		if (mm_id != ""):
+			links = allIncomingAssociationInstances(core, mm_id, "transformInput")
+
+			while (set_len(links) > 0):
+				link = set_pop(links)
+				if (value_eq(read_attribute(core, link, "name"), tag)):
+					// Correct tag, so make transformation a possibility
+					set_add(subresult, readAssociationSource(core, link))
+		else:
+			return "Model not found: " + mm!
 
-			result = set_overlap(onSource, onTarget)
+		// Got a set of subresults now, which we use to find the overlap
+		result = set_overlap(result, subresult)
 
-			String r
-			r = "Success: "
-			while (set_len(result) > 0):
-				transformation = set_pop(result)
-				if (allow_read(current_user_id, transformation)):
-					r = r + string_join(full_name(transformation), "\n")
-			return r!
+	keys = dict_keys(target_dict)
+	while (set_len(keys) > 0):
+		subresult = set_create()
+		tag = set_pop(keys)
+		mm = target_dict[tag]
+		mm_id = get_entry_id(mm)
+
+		if (mm_id != ""):
+			links = allIncomingAssociationInstances(core, mm_id, "transformOutput")
+
+			while (set_len(links) > 0):
+				link = set_pop(links)
+				if (value_eq(read_attribute(core, link, "name"), tag)):
+					// Correct tag, so make transformation a possibility
+					set_add(subresult, readAssociationSource(core, link))
 		else:
-			return "Model not found: " + target_name!
-	else:
-		return "Model not found: " + source_name!
+			return "Model not found: " + mm!
 
-String function cmd_model_render(model_name : String, mapper_name : String):
+		// Got a set of subresults now, which we use to find the overlap
+		result = set_overlap(result, subresult)
+
+	String r
+	String transformation
+	r = "Success: "
+	while (set_len(result) > 0):
+		transformation = set_pop(result)
+		if (allow_read(current_user_id, transformation)):
+			r = r + string_join(full_name(transformation), "\n")
+	return r!
+
+String function cmd_model_rendered(model_name : String, mapper_name : String):
+	Element trace_links
+	String rendered
+	String trace_link_id
+	String allowed_rendered
+	Element trace_links_2
+	String trace_link_2_id
+
+	allowed_rendered = "Success: "
+	trace_links = allOutgoingAssociationInstances(core, get_entry_id(model_name), "tracability")
+	while (set_len(trace_links) > 0):
+		trace_link_id = set_pop(trace_links)
+		if (value_eq(read_attribute(core, trace_link_id, "type"), "CS_perceptualized")):
+			rendered = readAssociationDestination(core, trace_link_id)
+			trace_links_2 = allOutgoingAssociationInstances(core, rendered, "tracability")
+			while (set_len(trace_links_2) > 0):
+				trace_link_2_id = set_pop(trace_links_2)
+				if (value_eq(read_attribute(core, readAssociationDestination(core, trace_link_2_id), "name"), mapper_name)):
+					if (value_eq(read_attribute(core, trace_link_2_id, "type"), "CS_mapper")):
+						allowed_rendered = string_join(allowed_rendered, read_attribute(core, rendered, "name")) + "\n"
+
+	return allowed_rendered!
+
+String function cmd_model_render(model_name : String, mapper_name : String, rendered_name : String):
 	String model_ID
 	String mapper_ID
-	String rendered_name
 	String tracability_name
 	Element inputs
 	Element output_map
@@ -1078,6 +1135,12 @@ String function cmd_model_render(model_name : String, mapper_name : String):
 	Element out_links
 	String link
 
+	String ID_rendered_M
+	String ID_rendered_MM
+	String ID_SCD
+	String ID_tracability_MM
+	String ID_tracability_M
+
 	model_ID = get_entry_id(model_name)
 
 	if (model_ID != ""):
@@ -1088,8 +1151,7 @@ String function cmd_model_render(model_name : String, mapper_name : String):
 				if (allow_read(current_user_id, mapper_ID)):
 					// Everything is fine; start the actual operation
 					// Find metamodel to render to
-					rendered_name = ("rendered/" + model_name) + mapper_name
-					tracability_name = ("tracability/" + model_name) + mapper_name
+					tracability_name = "tracability/" + rendered_name
 
 					// Take the abstract syntax model and the previously rendered model
 					inputs = dict_create()
@@ -1103,24 +1165,33 @@ String function cmd_model_render(model_name : String, mapper_name : String):
 						link = set_pop(out_links)
 						dict_add(output_map, read_attribute(core, link, "name"), full_name(readAssociationDestination(core, link)))
 
-					if (get_entry_id(rendered_name) == ""):
+					ID_rendered_MM = get_entry_id(output_map["rendered"])
+					ID_SCD = get_entry_id("formalisms/SimpleClassDiagrams")
+					ID_tracability_MM = get_entry_id("formalisms/Tracability")
+					ID_tracability_M = get_entry_id(tracability_name)
+					ID_rendered_M = get_entry_id(rendered_name)
+
+					if (ID_rendered_M == ""):
 						// Instantiate
 						Element rendered
-						rendered = get_full_model(get_entry_id(output_map["rendered"]), get_entry_id("formalisms/SimpleClassDiagrams"))
+						rendered = get_full_model(ID_rendered_MM, ID_SCD)
 						if (element_eq(rendered, read_root())):
-							return "Rendered metamodel cannot conform to formalisms/SimpleClassDiagrams"!
+							return "Rendered metamodel doesn't conform to formalisms/SimpleClassDiagrams"!
 
 						rendered_model = instantiate_model(rendered)
 
-						model_create(rendered_model, rendered_name, get_entry_id(output_map["rendered"]), "Model")
+						model_create(rendered_model, rendered_name, ID_rendered_MM, "Model")
 						
 						// Tracability model won't exist either
-						tracability_model = instantiate_model(get_full_model(get_entry_id("formalisms/Tracability"), get_entry_id("formalisms/SimpleClassDiagrams")))
-						model_create(tracability_model, tracability_name, get_entry_id("formalisms/Tracability"), "Model")
+						tracability_model = instantiate_model(get_full_model(ID_tracability_MM, ID_SCD))
+						model_create(tracability_model, tracability_name, ID_tracability_MM, "Model")
+
+						ID_rendered_M = get_entry_id(rendered_name)
+						ID_tracability_M = get_entry_id(tracability_name)
 
 					else:
 						// Read out tracability model
-						tracability_model = get_full_model(get_entry_id(tracability_name), get_entry_id("formalisms/Tracability"))
+						tracability_model = get_full_model(ID_tracability_M, ID_tracability_MM)
 						if (element_eq(tracability_model, read_root())):
 							return "Tracability model not typed by Tracability metamodel: " + tracability_name!
 
@@ -1128,17 +1199,24 @@ String function cmd_model_render(model_name : String, mapper_name : String):
 					result = execute_operation(mapper_ID, inputs, tracability_model)
 
 					// Overwrite the previous rendered model
-					model_overwrite(result["rendered"], get_entry_id(rendered_name), get_entry_id(output_map["rendered"]))
-					model_overwrite(result["abstract"], get_entry_id(model_name), get_entry_id(output_map["abstract"]))
+					model_overwrite(result["rendered"], ID_rendered_M, ID_rendered_MM)
 
 					// Tracability updated in-place
-					model_overwrite(tracability_model, get_entry_id(tracability_name), get_entry_id("formalisms/Tracability"))
-					tracability_model = get_full_model(get_entry_id(tracability_name), get_entry_id("formalisms/Tracability"))
+					model_overwrite(tracability_model, ID_tracability_M, ID_tracability_MM)
 					if (element_eq(tracability_model, read_root())):
 						return "Tracability model not typed by Tracability metamodel: " + tracability_name!
 
-					// Also output the resulting model
-					return "Success: " + JSON_print(get_full_model(get_entry_id(rendered_name), get_entry_id(output_map["rendered"])))!
+					// Link all information in the megamodel
+					String tr_link
+					tr_link = instantiate_link(core, "tracability", "", get_entry_id(model_name), ID_rendered_M)
+					instantiate_attribute(core, tr_link, "type", "CS_perceptualized")
+					tr_link = instantiate_link(core, "tracability", "", ID_rendered_M, get_entry_id(mapper_name))
+					instantiate_attribute(core, tr_link, "type", "CS_mapper")
+
+					// Output the resulting model
+					String value
+					value = JSON_print(result["rendered"])
+					return ("Success: " + value) !
 				else:
 					return "Permission denied to model: " + mapper_name!
 			else:
@@ -1148,7 +1226,14 @@ String function cmd_model_render(model_name : String, mapper_name : String):
 	else:
 		return "Model not found: " + model_name!
 
-String function cmd_transformation_execute(transformation_name : String, source_models : Element, target_models : Element):
+	//trace_links = allOutgoingAssociationInstances(core, operation_id, "tracability")
+	//merged_metamodel_id = ""
+	//while (set_len(trace_links) > 0):
+	//	trace_link_id = set_pop(trace_links)
+	//	if (value_eq(read_attribute(core, trace_link_id, "type"), "operatesOn")):
+	//		merged_metamodel_id = readAssociationDestination(core, trace_link_id)
+
+String function cmd_transformation_execute(transformation_name : String, source_models : Element, target_models : Element, tracability_name : String):
 	// Execute a transformation, whatever type it is
 	// First we detect the type, so we know how to prepare for invocation
 	String transformation_id
@@ -1204,26 +1289,24 @@ String function cmd_transformation_execute(transformation_name : String, source_
 					assoc_name = read_attribute(core, target, "name")
 					if (dict_in(target_models, assoc_name)):
 						target_model_name = target_models[assoc_name]
-					else:
-						return "Target model not bound: " + assoc_name!
 
-					if (get_entry_id(target_model_name) == ""):
-						// Doesn't exist yet, so we can easily create
-						if (get_entry_id(get_foldername(target_model_name)) == ""):
-							return "Folder not found: " + get_foldername(target_model_name)!
+						if (get_entry_id(target_model_name) == ""):
+							// Doesn't exist yet, so we can easily create
+							if (get_entry_id(get_foldername(target_model_name)) == ""):
+								return "Folder not found: " + get_foldername(target_model_name)!
+							else:
+								if (allow_write(current_user_id, get_entry_id(get_foldername(target_model_name)))):
+									dict_add(output_map, assoc_name, full_name(readAssociationDestination(core, target)))
+									dict_add(outputs, assoc_name, target_model_name)
+								else:
+									return "Permission denied to folder: " + get_foldername(target_model_name)!
 						else:
-							if (allow_write(current_user_id, get_entry_id(get_foldername(target_model_name)))):
-								dict_add(output_map, assoc_name, full_name(readAssociationDestination(core, target)))
+							// Already exists, so we need to check for write access
+							if (allow_write(current_user_id, get_entry_id(target_model_name))):
+								dict_add(output_map, assoc_name, read_attribute(core, readAssociationDestination(core, target), "name"))
 								dict_add(outputs, assoc_name, target_model_name)
 							else:
-								return "Permission denied to folder: " + get_foldername(target_model_name)!
-					else:
-						// Already exists, so we need to check for write access
-						if (allow_write(current_user_id, get_entry_id(target_model_name))):
-							dict_add(output_map, assoc_name, read_attribute(core, readAssociationDestination(core, target), "name"))
-							dict_add(outputs, assoc_name, target_model_name)
-						else:
-							return "Permission denied to model: " + target_model_name!
+								return "Permission denied to model: " + target_model_name!
 
 				if (read_type(core, transformation_id) == "ActionLanguage"):
 					output("Success: ready for AL execution")
@@ -1232,7 +1315,25 @@ String function cmd_transformation_execute(transformation_name : String, source_
 				else:
 					output("Success: ready for MT execution")
 
-				result = execute_operation(transformation_id, inputs, read_root())
+				// Do tracability
+				Element tracability_model
+				if (tracability_name != ""):
+					// Check if exists
+					if (get_entry_id(tracability_name) == ""):
+						// No, so create
+						tracability_model = instantiate_model(get_full_model(get_entry_id("formalisms/Tracability"), get_entry_id("formalisms/SimpleClassDiagrams")))
+						model_create(tracability_model, tracability_name, get_entry_id("formalisms/Tracability"), "Model")
+					else:
+						// Yes, so read out
+						tracability_model = get_full_model(get_entry_id(tracability_name), get_entry_id("formalisms/Tracability"))
+				else:
+					tracability_model = read_root()
+
+				result = execute_operation(transformation_id, inputs, tracability_model)
+
+				// Flush tracability again, just to be sure
+				if (tracability_name != ""):
+					model_overwrite(tracability_model, get_entry_id(tracability_name), get_entry_id("formalisms/Tracability"))
 
 				// Now write out the models again
 				if (element_eq(result, read_root())):
@@ -1416,7 +1517,7 @@ String function cmd_model_list_full(location : String):
 					name = get_filename(read_attribute(core, m, "name")) + "/"
 				else:
 					name = get_filename(read_attribute(core, m, "name"))
-				result = result + (((((((permissions + " ") + owner) + " ") + group) + " ") + name) + "\n")
+				result = result + permissions + " " + owner + " " + group + " " + name + "\n"
 			return result!
 		else:
 			return "Permission denied to folder: " + location!
@@ -1510,7 +1611,9 @@ String function transformation_add(source_models : Element, target_models : Elem
 		// New location is available, so write
 		if (bool_not(bool_and(dict_len(source_models) == 0, dict_len(target_models) == 0))):
 			merged_formalism = model_fuse(formalism_map)
+			model_create(merged_formalism, "merged/" + operation_name, get_entry_id("formalisms/SimpleClassDiagrams"), "Model")
 			modify(merged_formalism, True)
+			model_overwrite(merged_formalism, get_entry_id("merged/" + operation_name), get_entry_id("formalisms/SimpleClassDiagrams"))
 
 		if (operation_type == "manual"):
 			// Finished with all information, now create the model itself!
@@ -1535,7 +1638,6 @@ String function transformation_add(source_models : Element, target_models : Elem
 			model_id = get_entry_id(operation_name)
 
 		if (bool_not(bool_and(dict_len(source_models) == 0, dict_len(target_models) == 0))):
-			model_create(merged_formalism, "merged/" + operation_name, get_entry_id("formalisms/SimpleClassDiagrams"), "Model")
 			merged_formalism_id = get_entry_id("merged/" + operation_name)
 
 			// Add tracability links at this level
@@ -1651,7 +1753,9 @@ String function cmd_transformation_add_MT(source_models : Element, target_models
 			return "Model not found: " + name!
 
 	merged_formalism = model_fuse(to_ramify)
+	model_create(merged_formalism, "merged/" + operation_name, get_entry_id("formalisms/SimpleClassDiagrams"), "Model")
 	modify(merged_formalism, True)
+	model_overwrite(merged_formalism, get_entry_id("merged/" + operation_name), get_entry_id("formalisms/SimpleClassDiagrams"))
 
 	ramified_metamodel = ramify(merged_formalism)
 	model_create(ramified_metamodel, "RAMified/" + operation_name, get_entry_id("formalisms/SimpleClassDiagrams"), "Model")
@@ -1717,7 +1821,7 @@ String function cmd_permission_modify(model_name : String, permissions : String)
 				fail = True
 
 			while (i < 3):
-				permission = cast_s2i(string_get(permissions, i))
+				permission = cast_integer(string_get(permissions, i))
 				if (bool_or(permission < 0, permission > 2)):
 					fail = True
 					break!
@@ -1966,7 +2070,7 @@ String function cmd_service_register(service_name : String):
 		output("Success: " + get_taskname())
 
 		// Wait until we can stop the service
-		while (cast_v2s(input()) != "\"service_stop\""):
+		while (cast_value(input()) != "\"service_stop\""):
 			output("Service is running on this task: stop it by sending 'service_stop'")
 
 		model_delete_element(core, service)
@@ -2002,12 +2106,12 @@ String function cmd_transformation_signature(transformation_name : String):
 				inputs = allOutgoingAssociationInstances(core, model_id, "transformInput")
 				while (set_len(inputs) > 0):
 					elem = set_pop(inputs)
-					result = string_join(string_join(string_join(string_join("I ", read_attribute(core, elem, "name")), " "), full_name(readAssociationDestination(core, elem))), "\n")
+					result = string_join(string_join(string_join(string_join(result + "I ", read_attribute(core, elem, "name")), " "), full_name(readAssociationDestination(core, elem))), "\n")
 
 				outputs = allOutgoingAssociationInstances(core, model_id, "transformOutput")
 				while (set_len(outputs) > 0):
 					elem = set_pop(outputs)
-					result = string_join(string_join(string_join(string_join("O ", read_attribute(core, elem, "name")), " "), full_name(readAssociationDestination(core, elem))), "\n")
+					result = string_join(string_join(string_join(string_join(result + "O ", read_attribute(core, elem, "name")), " "), full_name(readAssociationDestination(core, elem))), "\n")
 
 				return result!
 			else:
@@ -2045,6 +2149,12 @@ String function cmd_folder_create(folder_name : String):
 	else:
 		return "Folder alreay exists: " + folder_name!
 
+String function cmd_conformance_add(model_name : String, metamodel_name : String):
+	// Create a new instanceOf relation now
+	String instance_of
+	instance_of = instantiate_link(core, "instanceOf", "", get_entry_id(model_name), get_entry_id(metamodel_name))
+	return "Success"!
+
 Void function user_function_skip_init(user_id : String):
 	String cmd
 	String result
@@ -2079,11 +2189,13 @@ Void function user_function_skip_init(user_id : String):
 		elif (cmd == "process_execute"):
 			output(cmd_process_execute(single_input("Process to execute?"), single_input("Model prefix to use?")))
 		elif (cmd == "transformation_between"):
-			output(cmd_transformation_between(single_input("Source type?"), single_input("Target type?")))
+			output(cmd_transformation_between(dict_input("Source signature?"), dict_input("Target signature?")))
 		elif (cmd == "model_render"):
-			output(cmd_model_render(single_input("Model name?"), single_input("Mapper name?")))
+			output(cmd_model_render(single_input("Model name?"), single_input("Mapper name?"), single_input("Rendered name?")))
+		elif (cmd == "model_rendered"):
+			output(cmd_model_rendered(single_input("Model name?"), single_input("Mapper name?")))
 		elif (cmd == "transformation_execute"):
-			output(cmd_transformation_execute(single_input("Transformation name?"), dict_input("Source models?"), dict_input("Target models?")))
+			output(cmd_transformation_execute(single_input("Transformation name?"), dict_input("Source models?"), dict_input("Target models?"), single_input("Tracability model?")))
 		elif (cmd == "verify"):
 			result = cmd_verify(single_input("Model name?"), single_input("Metamodel name?"))
 			if (result != ""):
@@ -2154,7 +2266,7 @@ Void function user_function_skip_init(user_id : String):
 			output(cmd_folder_create(single_input("Folder name?")))
 		elif (cmd == "add_conformance"):
 			// TODO
-			cmd = "FAIL"
+			output(cmd_conformance_add(single_input("Model name?"), single_input("Metamodel name?")))
 		elif (cmd == "remove_conformance"):
 			// TODO
 			cmd = "FAIL"

+ 1 - 0
bootstrap/initial_code_task.alc

@@ -24,5 +24,6 @@ Void mutable function __main():
 	exec(root["bootstrap/conformance_finding.alc"]["initializers"])
 	exec(root["bootstrap/typing.alc"]["initializers"])
 	exec(root["bootstrap/compiler.alc"]["initializers"])
+	exec(root["bootstrap/json.alc"]["initializers"])
 	new_task()
 	return!

+ 32 - 0
bootstrap/io.alc

@@ -34,3 +34,35 @@ Element function input_timeout(timeout : Float):
 			interruptable_sleep(0.1)
 
 	return read_root()!
+
+Boolean function other_has_output(comm : String):
+	// Check if there is any input on the specified pseudo-username
+	Element root
+	root = read_root()
+	return dict_in(root[comm]["output"], "value")!
+
+Void function give_input_to_other(comm : String, value : Element):
+	Element root
+	root = read_root()
+
+	Element new
+	new = create_node()
+	dict_add(root[comm]["last_input"], "value", value)
+	dict_add(root[comm]["last_input"], "next", new)
+	dict_overwrite(root[comm], "last_input", new)
+
+	return!
+
+Element function get_output_from_other(comm : String):
+	// Fetch input from the service
+	while (bool_not(other_has_output(comm))):
+		sleep(0.1)
+
+	// Return the value that we got
+	Element root
+	Element value
+	root = read_root()
+	value = root[comm]["output"]["value"]
+	dict_overwrite(root[comm], "output", root[comm]["output"]["next"])
+
+	return value!

+ 122 - 0
bootstrap/json.alc

@@ -0,0 +1,122 @@
+include "primitives.alh"
+include "services.alh"
+include "constructors.alh"
+include "modelling.alh"
+
+String function json_connect():
+	String port
+	port = ""
+	while (port == ""):
+		port = comm_connect("JSON")
+	return port!
+
+Void function json_send_data(port : String, data : Element):
+	// Send the current value to the service
+	// First determine what it is!
+
+	if (is_physical_none(data)):
+		comm_set(port, "N")
+		
+	elif (has_value(data)):
+		// Primitive value, so send as-is
+		comm_set(port, "P")
+		comm_set(port, data)
+
+	else:
+		// Is a dict or list
+		// Problem is that we don't know which it is, as everything is a dictionary in the Modelverse...
+		// We will do a simple check: if it is a dictionary with keys the contiguous range of integers from 0 to length - 1, it is a list!
+		Element keys
+		Element expected
+		Element copy
+		Element entry
+		Element key
+
+		keys = dict_keys(data)
+		expected = list_to_set(range(dict_len(data)))
+		if (set_equality(keys, expected)):
+			// Equal, so we are (most likely...) dealing with a list
+			comm_set(port, "L")
+			comm_set(port, list_len(data))
+			
+			copy = list_copy(data)
+			while (list_len(copy) > 0):
+				entry = list_pop(copy, 0)
+				json_send_data(port, entry)
+		else:
+			// Not equal, so we are surely dealing with a dict
+			comm_set(port, "D")
+			comm_set(port, dict_len(data))
+
+			while (set_len(keys) > 0):
+				key = set_pop(keys)
+				comm_set(port, key)
+				json_send_data(port, data[key])
+	return!
+
+Element function process_JSON_data(port : String):
+	String type
+	Element result
+	type = comm_get(port)
+
+	if (type == "P"):
+		// Primitive data type, so just return as-is
+		result = comm_get(port)
+	elif (type == "N"):
+		result = !none
+	elif (type == "L"):
+		// List, so fetch elements in turn
+		Integer length
+
+		length = comm_get(port)
+		result = list_create()
+		while (length > 0):
+			list_append(result, process_JSON_data(port))
+			length = length - 1
+	elif (type == "D"):
+		// Dict, so fetch elements in turn
+		Integer length
+
+		length = comm_get(port)
+		result = dict_create()
+		while (length > 0):
+			dict_add(result, comm_get(port), process_JSON_data(port))
+			length = length - 1
+	return result!
+
+String function json_serialize(data : Element):
+	String port
+	String response
+	port = json_connect()
+	comm_set(port, "encode")
+	response = comm_get(port)
+
+	if (response == "OK"):
+		// Send data to the service...
+		json_send_data(port, data)
+		response = comm_get(port)
+		comm_close(port)
+		return response!
+	else:
+		log("Error: " + response)
+		comm_close(port)
+		return ""!
+
+Element function json_deserialize(str : String):
+	String port
+	String response
+	Element rval
+	port = json_connect()
+	comm_set(port, "decode")
+
+	response = comm_get(port)
+
+	if (response == "OK"):
+		comm_set(port, str)
+		rval = process_JSON_data(port)
+		comm_close(port)
+		return rval!
+	else:
+		log("Error: " + response)
+		comm_close(port)
+		return read_root()!

+ 13 - 0
bootstrap/metamodels.alt

@@ -120,6 +120,18 @@ Element function initialize_SCD(location : String):
 	model_define_attribute(scd, "Association", "target_upper_cardinality", True, "Natural")
 	model_define_attribute(scd, "ComplexAttribute", "type", False, "Location")
 
+	model_define_attribute(scd, "Class", "name", False, "String")
+	model_define_attribute(scd, "SimpleAttribute", "name", False, "String")
+	model_define_attribute(scd, "Association", "name", False, "String")
+	instantiate_attribute(scd, "Class", "name", "Class")
+	instantiate_attribute(scd, "Association", "name", "Association")
+	instantiate_attribute(scd, "SimpleAttribute", "name", "SimpleAttribute")
+	instantiate_attribute(scd, "Location", "name", "Location")
+	instantiate_attribute(scd, "Natural", "name", "Natural")
+	instantiate_attribute(scd, "Boolean", "name", "Boolean")
+	instantiate_attribute(scd, "Inheritance", "name", "Inheritance")
+	instantiate_attribute(scd, "AttributeLink", "name", "AttributeLink")
+
 	// Export already, to allow AL to pick it up
 	export_node(location, scd)
 	// Add in the Action Language metamodel
@@ -139,6 +151,7 @@ Element function initialize_SCD(location : String):
 
 	instantiate_node(scd, "Class", "GlobalConstraint")
 	model_define_attribute(scd, "GlobalConstraint", "global_constraint", False, "ActionLanguage")
+	instantiate_attribute(scd, "GlobalConstraint", "name", "GlobalConstraint")
 
 	dict_overwrite(scd, "types", get_type_mapping(scd))
 

+ 142 - 17
bootstrap/mini_modify.alc

@@ -29,18 +29,18 @@ String function pretty_print(model : Element):
 		type = read_type(model["metamodel"], read_type(model, v_m))
 
 		if (bool_or(type == "Class", type == "Association")):
-			result = result + ((("  " + v_m) + " : ") + read_type(model, v_m))
+			result = result + "  " + v_m + " : " + read_type(model, v_m)
 			result = result + "\n"
 			if (type == "Association"):
-				result = result + ((("    " + reverseKeyLookup(model["model"], read_edge_src(model["model"][v_m]))) + " --> ") + reverseKeyLookup(model["model"], read_edge_dst(model["model"][v_m])))
+				result = result + "    " + reverseKeyLookup(model["model"], read_edge_src(model["model"][v_m])) + " --> " + reverseKeyLookup(model["model"], read_edge_dst(model["model"][v_m]))
 				result = result + "\n"
 
 			// Defines attributes
-			attr_list = getInstantiatableAttributes(model, v_m)
+			attr_list = getInstantiatableAttributes(model, v_m, "AttributeLink")
 			attr_keys = dict_keys(attr_list)
 			while (set_len(attr_keys) > 0):
 				attr_key = set_pop(attr_keys)
-				result = result + (((("      " + attr_key) + " : ") + cast_v2s(attr_list[attr_key])))
+				result = result + "      " + attr_key + " : " + cast_value(attr_list[attr_key])
 				result = result + "\n"
 
 			// Has attributes
@@ -49,9 +49,9 @@ String function pretty_print(model : Element):
 			while (set_len(attr_keys) > 0):
 				attr_key = set_pop(attr_keys)
 				if (element_eq(read_attribute(model, v_m, attr_key), read_root())):
-					result = result + (((("      " + cast_v2s(attr_key)) + " : ") + cast_v2s(attr_list[attr_key])) + " = (undefined)")
+					result = result + "      " + cast_string(attr_key) + " : " + cast_string(attr_list[attr_key]) + " = (undefined)"
 				else:
-					result = result + ((((("      " + cast_v2s(attr_key)) + " : ") + cast_v2s(attr_list[attr_key])) + " = ") + cast_v2s(read_attribute(model, v_m, attr_key)))
+					result = result + "      " + cast_string(attr_key) + " : " + cast_string(attr_list[attr_key]) + " = " + cast_value(read_attribute(model, v_m, attr_key))
 				result = result + "\n"
 		else:
 			log("Skip instance: " + type)
@@ -142,7 +142,7 @@ String function cmd_define_attribute(write : Boolean, model : Element, element_n
 		if (dict_in(model["model"], element_name)):
 			if (dict_in(model["model"], type)):
 				Element attrs
-				attrs = getAttributeList(model, element_name)
+				attrs = getInstantiatableAttributes(model, element_name, "AttributeLink")
 				if (bool_not(set_in(dict_keys(attrs), attr_name))):
 					model_define_attribute(model, element_name, attr_name, False, type)
 					return "Success"!
@@ -206,6 +206,99 @@ String function cmd_attr_del(write : Boolean, model : Element, element_name : St
 	else:
 		return "Permission denied to write"!
 
+String function cmd_attr_name(write : Boolean, model : Element, element_name : String, attr_name : String, new_attr_name : String):
+	if (write):
+		if (dict_in(model["model"], element_name)):
+			Element attrs
+			attrs = getInstantiatableAttributes(model, element_name, "AttributeLink")
+			if (set_in(dict_keys(attrs), attr_name)):
+				if (set_in(dict_keys(attrs), attr_name)):
+					if (bool_not(set_in(dict_keys(attrs), new_attr_name))):
+						Boolean optional
+						String attr_edge
+						attr_edge = reverseKeyLookup(model["model"], dict_read_edge(model["model"][element_name], attr_name))
+						optional = read_attribute(model, attr_edge, "optional")
+						model_undefine_attribute(model, element_name, attr_name)
+						model_define_attribute_ID(model, element_name, new_attr_name, optional, attrs[attr_name], attr_edge)
+						return "Success"!
+					else:
+						return "Attribute already defined: " + new_attr_name!
+				else:
+					return "Attribute not defined: " + attr_name!
+			else:
+				return "Attribute not found: " + attr_name!
+		else:
+			return "Element not found: " + element_name!
+	else:
+		return "Permission denied to write"!
+
+String function cmd_attr_type(write : Boolean, model : Element, element_name : String, attr_name : String, new_attr_type : String):
+	if (write):
+		if (dict_in(model["model"], element_name)):
+			Element attrs
+			attrs = getInstantiatableAttributes(model, element_name, "AttributeLink")
+			if (set_in(dict_keys(attrs), attr_name)):
+				if (set_in(dict_keys(attrs), attr_name)):
+					Boolean optional
+					String attr_edge
+					attr_edge = reverseKeyLookup(model["model"], dict_read_edge(model["model"][element_name], attr_name))
+					optional = read_attribute(model, attr_edge, "optional")
+					model_undefine_attribute(model, element_name, attr_name)
+					model_define_attribute_ID(model, element_name, attr_name, optional, new_attr_type, attr_edge)
+					return "Success"!
+				else:
+					return "Attribute not defined: " + attr_name!
+			else:
+				return "Attribute not found: " + attr_name!
+		else:
+			return "Element not found: " + element_name!
+	else:
+		return "Permission denied to write"!
+
+String function cmd_attr_optional(write : Boolean, model : Element, element_name : String, attr_name : String, optional : Boolean):
+	if (write):
+		if (dict_in(model["model"], element_name)):
+			Element attrs
+			attrs = getInstantiatableAttributes(model, element_name, "AttributeLink")
+			if (set_in(dict_keys(attrs), attr_name)):
+				if (set_in(dict_keys(attrs), attr_name)):
+					String attr_edge
+					attr_edge = reverseKeyLookup(model["model"], dict_read_edge(model["model"][element_name], attr_name))
+					if (optional):
+						log("Setting to optional")
+					else:
+						log("Setting to mandatory")
+					model_undefine_attribute(model, element_name, attr_name)
+					model_define_attribute_ID(model, element_name, attr_name, optional, attrs[attr_name], attr_edge)
+					return "Success"!
+				else:
+					return "Attribute not defined: " + attr_name!
+			else:
+				return "Attribute not found: " + attr_name!
+		else:
+			return "Element not found: " + element_name!
+	else:
+		return "Permission denied to write"!
+
+String function cmd_undefine_attribute(write : Boolean, model : Element, element_name : String, attr_name : String):
+	if (write):
+		if (dict_in(model["model"], element_name)):
+			Element attrs
+			attrs = getInstantiatableAttributes(model, element_name, "AttributeLink")
+			if (set_in(dict_keys(attrs), attr_name)):
+				if (set_in(dict_keys(attrs), attr_name)):
+					model_undefine_attribute(model, element_name, attr_name)
+					log("REMOVE OK")
+					return "Success"!
+				else:
+					return "Attribute not defined: " + attr_name!
+			else:
+				return "Attribute not found: " + attr_name!
+		else:
+			return "Element not found: " + element_name!
+	else:
+		return "Permission denied to write"!
+
 String function cmd_delete(write : Boolean, model : Element, element_name : String):
 	if (write):
 		if (dict_in(model["model"], element_name)):
@@ -229,7 +322,7 @@ String function cmd_list(model : Element):
 		// Filter out anonymous objects
 		if (bool_not(string_startswith(v_m, "__"))):
 			typename = read_type(model, v_m)
-			result = (result + ((("  " + v_m) + " : ") + typename)) + "\n"
+			result = result + "  " + v_m + " : " + typename + "\n"
 	
 	return result!
 
@@ -245,7 +338,7 @@ String function cmd_list_full(model : Element):
 		v_m = set_pop(keys_m)
 		// Filter out anonymous objects
 		typename = read_type(model, v_m)
-		result = (result + ((("  " + v_m) + " : ") + typename)) + "\n"
+		result = result + "  " + v_m + " : " + typename + "\n"
 	
 	return result!
 
@@ -299,12 +392,12 @@ String function cmd_read(model : Element, element_name : String):
 
 	result = "Success: "
 	if (dict_in(model["model"], element_name)):
-		result = ((result + "Type: ") + read_type(model, element_name)) + "\n"
+		result = result + "Type: " + read_type(model, element_name) + "\n"
 		if (is_edge(model["model"][element_name])):
-			result = ((result + "Source: ") + reverseKeyLookup(model["model"], read_edge_src(model["model"][element_name]))) + "\n"
-			result = ((result + "Destination: ") + reverseKeyLookup(model["model"], read_edge_dst(model["model"][element_name]))) + "\n"
+			result = result + "Source: " + reverseKeyLookup(model["model"], read_edge_src(model["model"][element_name])) + "\n"
+			result = result + "Destination: " + reverseKeyLookup(model["model"], read_edge_dst(model["model"][element_name])) + "\n"
 		if (has_value(model["model"][element_name])):
-			result = ((result + "Value: ") + cast_v2s(model["model"][element_name])) + "\n"
+			result = result + "Value: " + cast_value(model["model"][element_name]) + "\n"
 		return result!
 	else:
 		return "Element not found: " + element_name!
@@ -321,7 +414,27 @@ String function cmd_read_attrs(model : Element, element_name : String):
 		attr_keys = dict_keys(attr_list)
 		while (0 < set_len(attr_keys)):
 			attr_key = set_pop(attr_keys)
-			result = ((((((result + "  ") + cast_v2s(attr_key)) + " : ") + cast_v2s(attr_list[attr_key])) + " = ") + cast_v2s(read_attribute(model, element_name, attr_key))) + "\n"
+			result = string_join(result, attr_key) + " : " + cast_value(attr_list[attr_key]) + " = " + cast_value(read_attribute(model, element_name, attr_key)) + "\n"
+		return result!
+	else:
+		return "Element not found: " + element_name!
+
+String function cmd_read_defined_attrs(model : Element, element_name : String):
+	String result
+	Element attr_list
+	Element attr_keys
+	String attr_key
+
+	result = "Success: "
+	if (dict_in(model["model"], element_name)):
+		attr_list = getInstantiatableAttributes(model, element_name, "AttributeLink")
+		attr_keys = dict_keys(attr_list)
+		while (0 < set_len(attr_keys)):
+			attr_key = set_pop(attr_keys)
+			if (value_eq(read_attribute(model, reverseKeyLookup(model["model"], dict_read_edge(model["model"][element_name], attr_key)), "optional"), True)):
+				result = string_join(result, attr_key) + " ?: " + cast_value(attr_list[attr_key]) + "\n"
+			else:
+				result = string_join(result, attr_key) + " : " + cast_value(attr_list[attr_key]) + "\n"
 		return result!
 	else:
 		return "Element not found: " + element_name!
@@ -336,7 +449,7 @@ String function cmd_types(model : Element):
 	while (set_len(keys_t) > 0):
 		v_t = set_pop(keys_t)
 		if (bool_not(string_startswith(v_t, "__"))):
-			result = (result + string_join(("  " + v_t) + " : ", read_type(model["metamodel"], v_t))) + "\n"
+			result = result + string_join("  " + v_t + " : ", read_type(model["metamodel"], v_t)) + "\n"
 
 	return result!
 
@@ -406,7 +519,13 @@ Element function modify(model : Element, write : Boolean):
 		elif (cmd == "attr_add_code"):
 			output(cmd_attr_add_code(write, model, single_input("Name?"), single_input("Attribute name?")))
 		elif (cmd == "attr_del"):
-			output(cmd_attr_del(write, model, single_input("Name?"), single_input("Attribute_name?")))
+			output(cmd_attr_del(write, model, single_input("Name?"), single_input("Attribute name?")))
+		elif (cmd == "attr_name"):
+			output(cmd_attr_name(write, model, single_input("Name?"), single_input("Attribute name?"), single_input("New name?")))
+		elif (cmd == "attr_type"):
+			output(cmd_attr_type(write, model, single_input("Name?"), single_input("Attribute name?"), single_input("Type name?")))
+		elif (cmd == "attr_optional"):
+			output(cmd_attr_optional(write, model, single_input("Name?"), single_input("Attribute name?"), input()))
 		elif (cmd == "delete"):
 			output(cmd_delete(write, model, single_input("Name?")))
 		elif (cmd == "nice_list"):
@@ -423,6 +542,10 @@ Element function modify(model : Element, write : Boolean):
 			output(cmd_read_incoming(model, single_input("Name?"), single_input("Type?")))
 		elif (cmd == "read"):
 			output(cmd_read(model, single_input("Name?")))
+		elif (cmd == "read_attrs"):
+			output(cmd_read_attrs(model, single_input("Name?")))
+		elif (cmd == "read_defined_attrs"):
+			output(cmd_read_defined_attrs(model, single_input("Name?")))
 		elif (cmd == "types"):
 			output(cmd_types(model))
 		elif (cmd == "retype"):
@@ -437,8 +560,10 @@ Element function modify(model : Element, write : Boolean):
 			output(cmd_all_instances(model, single_input("Type?")))
 		elif (cmd == "define_attribute"):
 			output(cmd_define_attribute(write, model, single_input("On which element?"), single_input("Attribute name?"), single_input("Type?")))
+		elif (cmd == "undefine_attribute"):
+			output(cmd_undefine_attribute(write, model, single_input("On which element?"), single_input("Attribute name?")))
 		else:
-			output("Unknown command while modelling: " + cmd)
+			output("Unknown command while modelling: " + cast_value(cmd))
 			output("Use command 'help' to get a list of available commands")
 	return model!
 

+ 49 - 40
bootstrap/model_management.alc

@@ -45,8 +45,8 @@ Element function model_fuse(models : Element):
 			if (is_edge(model["model"][key])):
 				String src
 				String dst
-				src = string_join(model_name, reverse[cast_id2s(read_edge_src(model["model"][key]))])
-				dst = string_join(model_name, reverse[cast_id2s(read_edge_dst(model["model"][key]))])
+				src = string_join(model_name, reverse[cast_id(read_edge_src(model["model"][key]))])
+				dst = string_join(model_name, reverse[cast_id(read_edge_dst(model["model"][key]))])
 				if (bool_and(dict_in(new_model["model"], src), dict_in(new_model["model"], dst))):
 					instantiate_link(new_model, type, model_name + key, src, dst)
 				else:
@@ -84,8 +84,8 @@ Element function model_copy(src_model : Element):
 			String src
 			String dst
 
-			src = reverse[cast_id2s(read_edge_src(src_model["model"][name]))]
-			dst = reverse[cast_id2s(read_edge_dst(src_model["model"][name]))]
+			src = reverse[cast_id(read_edge_src(src_model["model"][name]))]
+			dst = reverse[cast_id(read_edge_dst(src_model["model"][name]))]
 
 			type = read_type(src_model, name)
 
@@ -128,11 +128,15 @@ Element function model_join(models : Element, metamodel : Element, tracability_m
 	new_model = instantiate_model(metamodel)
 	elem_map = dict_create()
 
+	Element retyping_keys
+	retyping_keys = set_create()
+
 	// Do the iteration
 	while (set_len(models) > 0):
 		tagged_model = set_pop(models)
 		retyping_key = string_join(list_read(tagged_model, 0), "/")
 		model = list_read(tagged_model, 1)
+		set_add(retyping_keys, retyping_key)
 
 		// Add all elements from 'model'
 		keys = dict_keys(model["model"])
@@ -146,8 +150,8 @@ Element function model_join(models : Element, metamodel : Element, tracability_m
 			new_name = retyping_key + key
 
 			if (is_edge(model["model"][key])):
-				src = cast_id2s(read_edge_src(model["model"][key]))
-				dst = cast_id2s(read_edge_dst(model["model"][key]))
+				src = cast_id(read_edge_src(model["model"][key]))
+				dst = cast_id(read_edge_dst(model["model"][key]))
 				if (bool_and(dict_in(elem_map, src), dict_in(elem_map, dst))):
 					new_name = instantiate_link(new_model, retyping_key + type, new_name, elem_map[src], elem_map[dst])
 				else:
@@ -160,7 +164,7 @@ Element function model_join(models : Element, metamodel : Element, tracability_m
 
 			if (new_name != ""):
 				// Add the new name to a map which registers the mapping to the new name
-				dict_add_fast(elem_map, cast_id2s(model["model"][key]), new_name)
+				dict_add_fast(elem_map, cast_id(model["model"][key]), new_name)
 
 			if (set_len(keys) == 0):
 				keys = second_keys
@@ -174,25 +178,40 @@ Element function model_join(models : Element, metamodel : Element, tracability_m
 		String tracability_link
 		String new_name_src
 		String new_name_dst
+		String src_name
+		String dst_name
+		Element src_models
+		String src_model
+		Element dst_models
+		String dst_model
 
 		tracability_links = allInstances(tracability_model, "TracabilityLink")
 
 		while (set_len(tracability_links) > 0):
 			tracability_link = set_pop(tracability_links)
 
-			// Get necessary information from the tracability link
-
-			new_name_src = elem_map[cast_id2s(read_edge_src(tracability_model["model"][tracability_link]))]
-			new_name_dst = elem_map[cast_id2s(read_edge_dst(tracability_model["model"][tracability_link]))]
-
+			src_name = read_attribute(tracability_model, readAssociationSource(tracability_model, tracability_link), "name")
+			dst_name = read_attribute(tracability_model, readAssociationDestination(tracability_model, tracability_link), "name")
 			type = read_attribute(tracability_model, tracability_link, "type")
 
-			// Connect the two with the info we have
-			new_name = instantiate_link(new_model, type, "", new_name_src, new_name_dst)
+			// Now try to find all possible combinations
+			// that is, find all models for which src_name exists, and all models for which dst_name exists, and connect them
+			src_models = set_copy(retyping_keys)
+			while (set_len(src_models) > 0):
+				src_model = set_pop(src_models)
 
-			if (new_name == ""):
-				log("ERROR: could not create a tracability link; ignoring")
+				if (dict_in(new_model["model"], src_model + src_name)):
+					// This element exists for this source model
+					dst_models = set_copy(retyping_keys)
 
+					while (set_len(dst_models) > 0):
+						dst_model = set_pop(dst_models)
+
+						if (dict_in(new_model["model"], dst_model + dst_name)):
+							// Found a match for source and target, so create a link
+							new_name = instantiate_link(new_model, type, "", src_model + src_name, dst_model + dst_name)
+							if (new_name == ""):
+								log("ERROR: could not create a tracability link; ignoring")
 	return new_model!
 	
 Element function model_split(merged_model : Element, models : Element, tracability : Boolean):
@@ -250,30 +269,20 @@ Element function model_split(merged_model : Element, models : Element, tracabili
 				// Got a tracability link!
 				// Is always an edge (for now?)
 				// Find out source and target and hope that they are already present
-				src = reverse[cast_id2s(read_edge_src(elem))]
-				dst = reverse[cast_id2s(read_edge_dst(elem))]
-
-				src_name = list_read(string_split(read_type(merged_model, src), "/"), 0)
-				dst_name = list_read(string_split(read_type(merged_model, dst), "/"), 0)
+				src = reverse[cast_id(read_edge_src(elem))]
+				dst = reverse[cast_id(read_edge_dst(elem))]
 
-				// Check if we actually keep both models around, as otherwise it is useless anyway
-				if (bool_and(dict_in(result, src_name), dict_in(result, dst_name))):
-					if (bool_and(dict_in(mapping, src), dict_in(mapping, dst))):
-						// All present, so create the link between them
-						Element src_model
-						Element dst_model
-
-						src_model = result[src_name]
-						dst_model = result[dst_name]
+				// All present, so create the link between them
+				src_name = list_pop_final(string_split(src, "/"))
+				dst_name = list_pop_final(string_split(dst, "/"))
 
-						source = reuse_element(tracability_model, "Reference", "", src_model["model"][mapping[src]])
-						target = reuse_element(tracability_model, "Reference", "", dst_model["model"][mapping[dst]])
+				source = instantiate_node(tracability_model, "Reference", "")
+				target = instantiate_node(tracability_model, "Reference", "")
+				instantiate_attribute(tracability_model, source, "name", src_name)
+				instantiate_attribute(tracability_model, target, "name", dst_name)
 
-						link = instantiate_link(tracability_model, "TracabilityLink", "", source, target)
-						instantiate_attribute(tracability_model, link, "type", type)
-					else:
-						// Not yet available!
-						set_add(second_keys, key)
+				link = instantiate_link(tracability_model, "TracabilityLink", "", source, target)
+				instantiate_attribute(tracability_model, link, "type", type)
 		else:
 			retyping_key = splitted[0]
 			if (list_len(string_split(key, "/")) > 1):
@@ -286,8 +295,8 @@ Element function model_split(merged_model : Element, models : Element, tracabili
 
 				if (is_edge(elem)):
 					// Is an edge, so potentially queue it
-					src = reverse[cast_id2s(read_edge_src(elem))]
-					dst = reverse[cast_id2s(read_edge_dst(elem))]
+					src = reverse[cast_id(read_edge_src(elem))]
+					dst = reverse[cast_id(read_edge_dst(elem))]
 
 					if (bool_and(dict_in(mapping, src), dict_in(mapping, dst))):
 						// All present, so create the link between them
@@ -316,6 +325,6 @@ Element function model_split(merged_model : Element, models : Element, tracabili
 	// Finally, we also add tracability information as a separate model
 	if (tracability):
 		dict_add_fast(result, "__tracability", tracability_model)
-		log("Tracability model created with # links = " + cast_v2s(dict_len(tracability_model["model"])))
+		log("Tracability model created with # links = " + cast_value(dict_len(tracability_model["model"])))
 
 	return result!

+ 44 - 8
bootstrap/modelling.alc

@@ -11,7 +11,7 @@ Element global_models = ?
 
 String function instantiated_name(element : Element, original : String):
 	if (original == ""):
-		return "__" + cast_id2s(element)!
+		return "__" + cast_id(element)!
 	else:
 		return original!
 
@@ -268,7 +268,7 @@ Void function instantiate_attribute_ref(model : Element, element : String, attri
 	attr_type = find_attribute_type(model, element, attribute_name)
 
 	if (attr_type == ""):
-		log("Could not find attribute " + cast_v2s(attribute_name))
+		log("Could not find attribute " + cast_value(attribute_name))
 		return!
 		
 	instantiate_link(model, attr_type, "", element, ref)
@@ -286,7 +286,7 @@ Void function add_code_model(model : Element, export_name : String, code : Eleme
 Void function instantiate_attribute_code(model : Element, element : String, attribute_name : String, code : Element):
 	// First create a new model for the AL part
 	String location
-	location = "code/" + cast_id2s(code)
+	location = "code/" + cast_id(code)
 
 	add_code_model(import_node("models/ActionLanguage"), location, code)
 
@@ -304,7 +304,7 @@ Void function instantiate_existing_attribute(model : Element, element : String,
 	attr_type = find_attribute_type(model, element, attribute_name)
 
 	if (attr_type == ""):
-		log("Could not find attribute " + cast_v2s(attribute_name))
+		log("Could not find attribute " + cast_value(attribute_name))
 		return!
 		
 	// Make a copy of the value, as it is likely that this value is reused later on
@@ -360,10 +360,30 @@ String function instantiate_link(model : Element, type : String, name : String,
 	return actual_name!
 
 Void function model_delete_element(model : Element, name : String):
+	// Delete all attributes
+	//Element attrs
+	//String attr
+	//attrs = dict_keys(getAttributeList(model, name))
+	//while (set_len(attrs) > 0):
+	//	attr = set_pop(attrs)
+	//	log("Remove attr " + attr)
+	//	attr = reverseKeyLookup(model["model"], read_attribute(model, name, attr))
+	//	remove_type(model, attr)
+	//	delete_element(model["model"][attr])
+
+	// Delete element itself
 	remove_type(model, name)
 	delete_element(model["model"][name])
 	return!
 
+String function model_undefine_attribute(model : Element, elem : String, attr_name : String):
+	String attr_edge
+	attr_edge = reverseKeyLookup(model["model"], dict_read_edge(model["model"][elem], attr_name))
+	unset_attribute(model, attr_edge, "name")
+	unset_attribute(model, attr_edge, "optional")
+	model_delete_element(model, attr_edge)
+	return attr_edge!
+
 String function model_define_attribute(model : Element, elem : String, name : String, optional : Boolean, type : String):
 	// Create the necessary links to make it an attribute
 	String edge_name
@@ -371,7 +391,23 @@ String function model_define_attribute(model : Element, elem : String, name : St
 	edge_name = (elem + "_") + name
 	while (dict_in(model["model"], edge_name)):
 		// Already exists, so make random name
-		edge_name = edge_name + cast_id2s(model["model"][elem])
+		edge_name = edge_name + cast_id(model["model"][elem])
+		log("Name clash detected for attribute: try new name: " + edge_name)
+
+	edge_name = instantiate_link(model, "AttributeLink", edge_name, elem, type)
+	instantiate_attribute(model, edge_name, "name", name)
+	instantiate_attribute(model, edge_name, "optional", optional)
+
+	return edge_name!
+
+String function model_define_attribute_ID(model : Element, elem : String, name : String, optional : Boolean, type : String, ID : String):
+	// Create the necessary links to make it an attribute
+	String edge_name
+
+	edge_name = ID
+	while (dict_in(model["model"], edge_name)):
+		// Already exists, so make random name
+		edge_name = edge_name + cast_id(model["model"][elem])
 		log("Name clash detected for attribute: try new name: " + edge_name)
 
 	edge_name = instantiate_link(model, "AttributeLink", edge_name, elem, type)
@@ -445,7 +481,7 @@ Void function add_AL_links(model : Element, list : Element, element : Element, t
 	// The name node
 	String link_name
 	link = read_edge_dst(link)
-	link_name = "__" + cast_id2s(link)
+	link_name = "__" + cast_id(link)
 
 	if (bool_not(dict_in(model["model"], link_name))):
 		reuse_element(model, "StringAttr", link_name, link)
@@ -471,12 +507,12 @@ String function add_AL(model : Element, element : Element):
 		elem = list_read(work_node, 0)
 		type = list_read(work_node, 1)
 
-		elem_name = "__" + cast_id2s(elem)
+		elem_name = "__" + cast_id(elem)
 		if (bool_not(set_in(model["model"], elem_name))):
 			// Determine the type if we don't know it
 			if (type == ""):
 				if (is_physical_action(elem)):
-					type = cast_a2s(elem)
+					type = cast_value(elem)
 				else:
 					type = "Element"
 

+ 41 - 9
bootstrap/object_operations.alc

@@ -77,7 +77,10 @@ Element function allOutgoingAssociationInstances(model : Element, source_name :
 	i = 0
 	while (i < all_out):
 		option = reverseKeyLookup(model["model"], read_out(source, i))
-		if (is_nominal_instance(model, option, assoc_name)):
+		if (assoc_name != ""):
+			if (is_nominal_instance(model, option, assoc_name)):
+				set_add(result, option)
+		else:
 			set_add(result, option)
 		i = i + 1
 
@@ -97,7 +100,10 @@ Element function allIncomingAssociationInstances(model : Element, target_name :
 	i = 0
 	while (i < all_out):
 		option = reverseKeyLookup(model["model"], read_in(source, i))
-		if (is_nominal_instance(model, option, assoc_name)):
+		if (assoc_name != ""):
+			if (is_nominal_instance(model, option, assoc_name)):
+				set_add(result, option)
+		else:
 			set_add(result, option)
 		i = i + 1
 
@@ -124,24 +130,50 @@ Element function getAttributeList(model : Element, element : String):
 		while (set_len(keys) > 0):
 			attr_name = set_pop(keys)
 			if (is_physical_string(attr_name)):
-				attr_type = reverseKeyLookup(mm, mm[type][attr_name])
+				if (read_type(model["metamodel"], reverseKeyLookup(mm, dict_read_edge(mm[type], attr_name))) == "AttributeLink"):
+					attr_type = reverseKeyLookup(mm, mm[type][attr_name])
+					// WARNING: do not change this to dict_add_fast, as this crashes random code...
+					dict_add(result, attr_name, attr_type)
+
+	return result!
+
+Element function getAttributes(model : Element, element : String):
+	Element result
+	Element keys
+	Element type
+	Element attr_name
+	Element types
+	Element mm
+
+	result = dict_create()
+	mm = model["metamodel"]["model"]
+	types = get_superclasses(model["metamodel"], read_type(model, element))
+
+	while (set_len(types) > 0):
+		type = set_pop(types)
+
+		// Add our own attributes
+		keys = dict_keys(mm[type])
+		while (set_len(keys) > 0):
+			attr_name = set_pop(keys)
+			if (is_physical_string(attr_name)):
 				// WARNING: do not change this to dict_add_fast, as this crashes random code...
-				dict_add(result, attr_name, attr_type)
+				dict_add(result, attr_name, read_attribute(model, element, attr_name))
 
 	return result!
 
-Element function getInstantiatableAttributes(model : Element, element : String):
+Element function getInstantiatableAttributes(model : Element, element : String, type : String):
 	Element all_links
 	Element result
 	String link
 
 	result = dict_create()
 
-	all_links = allOutgoingAssociationInstances(model, element, "Attribute")
+	all_links = allOutgoingAssociationInstances(model, element, type)
 	while (set_len(all_links) > 0):
 		link = set_pop(all_links)
 		// WARNING: do not change this to dict_add_fast, as this crashes random code...
-		dict_add(result, read_attribute(model, link, "name"), read_type(model, readAssociationDestination(model, link)))
+		dict_add(result, read_attribute(model, link, "name"), readAssociationDestination(model, link))
 
 	return result!
 
@@ -154,9 +186,9 @@ String function print_dict(dict : Element):
 	result = ""
 	while (0 < list_len(keys)):
 		key = set_pop(keys)
-		result = result + cast_v2s(key)
+		result = result + cast_value(key)
 		result = result + ": "
-		result = result + cast_v2s(dict[key])
+		result = result + cast_value(dict[key])
 		result = result + "\n"
 	return result!
 

+ 29 - 7
bootstrap/pm.mvc

@@ -3,8 +3,11 @@ include "primitives.alh"
 include "object_operations.alh"
 
 SimpleClassDiagrams ProcessModel {
-    SimpleAttribute String {}
+    SimpleAttribute String {
+        name = "String"
+    }
     SimpleAttribute MvCName {
+        name = "MvCName"
         constraint = $
             String function constraint(model : Element, name : String):
                 if (bool_not(is_physical_string(model["model"][name]))):
@@ -14,17 +17,26 @@ SimpleClassDiagrams ProcessModel {
             $
     }
 
-    Class Activity {}
+    Class Activity {
+        name = "Activity"
+    }
     Class Start : Activity {
+        name = "Start"
         lower_cardinality = 1
         upper_cardinality = 1
     }
     Class Finish : Activity {
+        name = "Finish"
         lower_cardinality = 1
     }
-    Class Fork : Activity {}
-    Class Join : Activity {}
+    Class Fork : Activity {
+        name = "Fork"
+    }
+    Class Join : Activity {
+        name = "Join"
+    }
     Class Decision : Activity {
+        name = "Decision"
         constraint = $
             String function constraint(model : Element, name : String):
                 if (read_nr_out(allOutgoingAssociationInstances(model, name, "Next")) == 0):
@@ -35,23 +47,33 @@ SimpleClassDiagrams ProcessModel {
     }
 
     Class Exec : Activity {
+        name = "Exec"
         name : MvCName
     }
 
     Class Data {
+        name = "Data"
         name : MvCName
         type : MvCName
     }
 
     Association Produces (Exec, Data) {
         name : String
+        name = "Produces"
     }
     Association Consumes (Exec, Data) {
         name : String
+        name = "Consumes"
+    }
+    Association Then (Decision, Activity) {
+        name = "Then"
+    }
+    Association Else (Decision, Activity) {
+        name = "Else"
+    }
+    Association Next (Activity, Activity) {
+        name = "Next"
     }
-    Association Then (Decision, Activity) {}
-    Association Else (Decision, Activity) {}
-    Association Next (Activity, Activity) {}
 }
 
 export ProcessModel to models/ProcessModel

+ 8 - 17
bootstrap/primitives.alc

@@ -14,22 +14,12 @@ Element function read_edge_src(a: Element) = ?primitives/read_edge_src
 Element function read_edge_dst(a: Element) = ?primitives/read_edge_dst
 Boolean function delete_element(a: Element) = ?primitives/delete_element
 Boolean function element_eq(a: Element, b: Element) = ?primitives/element_eq
-Float function cast_i2f(a: Integer) = ?primitives/cast_i2f
-String function cast_i2s(a: Integer) = ?primitives/cast_i2s
-Boolean function cast_i2b(a: Integer) = ?primitives/cast_i2b
-Integer function cast_f2i(a: Float) = ?primitives/cast_f2i
-Boolean function cast_f2b(a: Float) = ?primitives/cast_f2b
-String function cast_f2s(a: Float) = ?primitives/cast_f2s
-Integer function cast_s2i(a: String) = ?primitives/cast_s2i
-Float function cast_s2f(a: String) = ?primitives/cast_s2f
-Boolean function cast_s2b(a: String) = ?primitives/cast_s2b
-Integer function cast_b2i(a: Boolean) = ?primitives/cast_b2i
-Float function cast_b2f(a: Boolean) = ?primitives/cast_b2f
-String function cast_b2s(a: Boolean) = ?primitives/cast_b2s
-String function cast_e2s(a: Element) = ?primitives/cast_e2s
-String function cast_a2s(a: Action) = ?primitives/cast_a2s
-String function cast_v2s(a: Element) = ?primitives/cast_v2s
-String function cast_id2s(a: Element) = ?primitives/cast_id2s
+Float function cast_float(a: Element) = ?primitives/cast_float
+String function cast_string(a: Element) = ?primitives/cast_string
+Boolean function cast_boolean(a: Element) = ?primitives/cast_boolean
+Integer function cast_integer(a: Element) = ?primitives/cast_integer
+String function cast_value(a: Element) = ?primitives/cast_value
+String function cast_id(a: Element) = ?primitives/cast_id
 Element function dict_add_fast(a: Element, b: Element, c: Element) = ?primitives/dict_add_fast
 Element function dict_delete(a: Element, b: Element) = ?primitives/dict_delete
 Element function dict_delete_node(a: Element, b: Element) = ?primitives/dict_delete_node
@@ -64,7 +54,8 @@ Boolean function is_physical_float(a: Element) = ?primitives/is_physical_float
 Boolean function is_physical_string(a: Element) = ?primitives/is_physical_string
 Boolean function is_physical_boolean(a: Element) = ?primitives/is_physical_boolean
 Boolean function is_physical_action(a: Element) = ?primitives/is_physical_action
+Boolean function is_physical_none(a: Element) = ?primitives/is_physical_none
 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() = ?primitives/is_error
+Boolean function is_error(a : Element) = ?primitives/is_error

+ 22 - 4
bootstrap/ramify.alc

@@ -49,10 +49,12 @@ Element function ramify(model : Element):
 	//  Class LHS : LHS_Root {}
 	instantiate_node(new_model, "Class", "LHS")
 	instantiate_link(new_model, "Inheritance", "", "LHS", "LHS_Root")
+	instantiate_attribute(new_model, "LHS", "name", "LHS")
 
 	//  Class NAC : LHS_Root {}
 	instantiate_node(new_model, "Class", "NAC")
 	instantiate_link(new_model, "Inheritance", "", "NAC", "LHS_Root")
+	instantiate_attribute(new_model, "NAC", "name", "NAC")
 
 	//	Class PreElement {
 	//		label : String
@@ -73,6 +75,7 @@ Element function ramify(model : Element):
 	instantiate_node(new_model, "Class", "RHS")
 	instantiate_attribute(new_model, "RHS", "lower_cardinality", 1)
 	instantiate_attribute(new_model, "RHS", "upper_cardinality", 1)
+	instantiate_attribute(new_model, "RHS", "name", "RHS")
 	model_define_attribute(new_model, "RHS", "action", True, "ActionLanguage")
 
 	//	Class PostElement {
@@ -111,6 +114,7 @@ Element function ramify(model : Element):
 	set_add(copied_attributes, "upper_cardinality")
 	set_add(copied_attributes, "source_upper_cardinality")
 	set_add(copied_attributes, "target_upper_cardinality")
+	set_add(copied_attributes, "name")
 
 	while (list_len(keys) > 0):
 		key = list_pop(keys, 0)
@@ -130,8 +134,12 @@ Element function ramify(model : Element):
 				attr_name = set_pop(local_copied_attributes)
 				if (element_neq(read_attribute(model, key, attr_name), read_root())):
 					// Attribute was defined, so reassign in both LHS and RHS
-					instantiate_attribute(new_model, "Pre_" + key, attr_name, read_attribute(model, key, attr_name))
-					instantiate_attribute(new_model, "Post_" + key, attr_name, read_attribute(model, key, attr_name))
+					if (attr_name == "name"):
+						instantiate_attribute(new_model, "Pre_" + key, attr_name, string_join("Pre_", read_attribute(model, key, attr_name)))
+						instantiate_attribute(new_model, "Post_" + key, attr_name, string_join("Post_", read_attribute(model, key, attr_name)))
+					else:
+						instantiate_attribute(new_model, "Pre_" + key, attr_name, read_attribute(model, key, attr_name))
+						instantiate_attribute(new_model, "Post_" + key, attr_name, read_attribute(model, key, attr_name))
 
 		elif (type_name == "AttributeLink"):
 			// Got an attribute, so find out the source and name
@@ -173,8 +181,12 @@ Element function ramify(model : Element):
 				attr_name = set_pop(local_copied_attributes)
 				if (element_neq(read_attribute(model, key, attr_name), read_root())):
 					// Attribute was defined, so reassign in both LHS and RHS
-					instantiate_attribute(new_model, "Pre_" + key, attr_name, read_attribute(model, key, attr_name))
-					instantiate_attribute(new_model, "Post_" + key, attr_name, read_attribute(model, key, attr_name))
+					if (attr_name == "name"):
+						instantiate_attribute(new_model, "Pre_" + key, attr_name, string_join("Pre_", read_attribute(model, key, attr_name)))
+						instantiate_attribute(new_model, "Post_" + key, attr_name, string_join("Post_", read_attribute(model, key, attr_name)))
+					else:
+						instantiate_attribute(new_model, "Pre_" + key, attr_name, read_attribute(model, key, attr_name))
+						instantiate_attribute(new_model, "Post_" + key, attr_name, read_attribute(model, key, attr_name))
 
 		elif (type_name == "Inheritance"):
 			old_source = reverseKeyLookup(model["model"], read_edge_src(entry))
@@ -196,10 +208,12 @@ Element function ramify(model : Element):
 	//	Class Success : Entry {}
 	instantiate_node(new_model, "Class", "Success")
 	instantiate_link(new_model, "Inheritance", "", "Success", "Entry")
+	instantiate_attribute(new_model, "Success", "name", "Success")
 
 	//	Class Failure : Entry {}
 	instantiate_node(new_model, "Class", "Failure")
 	instantiate_link(new_model, "Inheritance", "", "Failure", "Entry")
+	instantiate_attribute(new_model, "Failure", "name", "Failure")
 
 	//  Class Rule : Entry {}
 	instantiate_node(new_model, "Class", "Rule")
@@ -251,20 +265,24 @@ Element function ramify(model : Element):
 	// 	Class Query : LHSRule {}
 	instantiate_node(new_model, "Class", "Query")
 	instantiate_link(new_model, "Inheritance", "", "Query", "LHSRule")
+	instantiate_attribute(new_model, "Query", "name", "Query")
 
 	//	Class Atomic : LHSRule, RHSRule {}
 	instantiate_node(new_model, "Class", "Atomic")
 	instantiate_link(new_model, "Inheritance", "", "Atomic", "LHSRule")
 	instantiate_link(new_model, "Inheritance", "", "Atomic", "RHSRule")
+	instantiate_attribute(new_model, "Atomic", "name", "Atomic")
 
 	// 	Class ForAll : LHSRule, RHSRule {}
 	instantiate_node(new_model, "Class", "ForAll")
 	instantiate_link(new_model, "Inheritance", "", "ForAll", "LHSRule")
 	instantiate_link(new_model, "Inheritance", "", "ForAll", "RHSRule")
+	instantiate_attribute(new_model, "ForAll", "name", "ForAll")
 
 	//	Class Composite : Rule {}
 	instantiate_node(new_model, "Class", "Composite")
 	instantiate_link(new_model, "Inheritance", "", "Composite", "Rule")
+	instantiate_attribute(new_model, "Composite", "name", "Composite")
 
 	//	Association Initial(Composite, Entry){
 	//		target_lower_cardinality = 1

+ 1 - 1
bootstrap/random.alc

@@ -23,7 +23,7 @@ Integer function random_interval(a : Integer, b : Integer):
 	if (a == b):
 		return a!
 	else:
-		return cast_f2i(random() * (b - a + 1) + a)!
+		return cast_integer(random() * (b - a + 1) + a)!
 
 Element function random_choice(list : Element):
 	if (list_len(list) == 0):

+ 55 - 9
bootstrap/semi_primitives.alc

@@ -22,7 +22,7 @@ Boolean function float_gt(a : Element, b : Element):
 	return bool_or(float_lt(a, b), value_eq(a, b))!
 
 Element function dict_add(a : Element, b : Element, c : Element):
-	log("Doing dict_add for " + cast_v2s(b))
+	log("Doing dict_add for " + cast_value(b))
 	create_edge(create_edge(a, c), b)
 	return a!
 
@@ -70,7 +70,7 @@ Element function set_pop(a : Element):
 		edge = read_out(a, 0)
 		result = read_edge_dst(read_out(edge, 0))
 		delete_element(edge)
-		log("Value: " + cast_v2s(result))
+		log("Value: " + cast_value(result))
 		return result!
 	else:
 		log("Set pop on empty set!")
@@ -129,7 +129,7 @@ Boolean function string_startswith(a: String, b: String):
 	return True!
 
 Boolean function has_value(a: Element):
-	return bool_or(bool_or(bool_or(is_physical_action, is_physical_int(a)), is_physical_float(a)), bool_or(is_physical_string(a), is_physical_boolean(a)))!
+	return bool_or(bool_or(bool_or(is_physical_action, is_physical_int(a)), bool_or(is_physical_none(a), is_physical_float(a))), bool_or(is_physical_string(a), is_physical_boolean(a)))!
 
 Boolean function float_gte(a: Float, b: Float):
 	return bool_or(float_gt(a, b), value_eq(a, b))!
@@ -201,7 +201,7 @@ String function set_to_string(s : Element):
 	result = "{"
 	s = set_copy(s)
 	while (set_len(s) > 0):
-		result = (result + cast_v2s(set_pop(s))) + ", "
+		result = (result + cast_value(set_pop(s))) + ", "
 	
 	result = result + "}"
 
@@ -214,7 +214,7 @@ String function list_to_string(s : Element):
 	result = "["
 	i = 0
 	while (i < list_len(s)):
-		result = result + cast_v2s(list_read(s, i))
+		result = result + cast_value(list_read(s, i))
 		result = result + ", "
 		i = i + 1
 	
@@ -242,10 +242,11 @@ String function dict_to_string(d : Element):
 	while (set_len(keys) > 0):
 		key = set_pop(keys)
 
-		result = result + cast_v2s(key)
+		result = result + cast_value(key)
 		result = result + ": "
-		result = result + cast_v2s(dict_read_node(d, key))
-		result = result + ", "
+		result = result + cast_value(dict_read_node(d, key))
+		if (set_len(keys) > 0):
+			result = result + ", "
 	
 	result = result + "}"
 
@@ -313,6 +314,19 @@ Element function dict_copy(d : Element):
 
 	return result!
 
+Element function list_copy(lst : Element):
+	Integer counter
+	Element result
+
+	result = list_create()
+	counter = 0
+
+	while (counter < list_len(lst)):
+		list_append(result, lst[counter])
+		counter = counter + 1
+
+	return result!
+
 Element function set_to_list(s : Element):
 	Element result
 	Element tmp
@@ -324,6 +338,18 @@ Element function set_to_list(s : Element):
 
 	return result!
 
+Element function list_to_set(s : Element):
+	Element result
+	Integer i
+
+	i = 0
+	result = set_create()
+	while (i < list_len(s)):
+		set_add(result, s[i])
+		i = i + 1
+
+	return result!
+
 Void function dict_overwrite(d : Element, key : Element, value : Element):
 	if (dict_in(d, key)):
 		dict_delete(d, key)
@@ -349,7 +375,7 @@ Element function make_reverse_dictionary(dict : Element):
 	keys = dict_keys(dict)
 	while (set_len(keys) > 0):
 		key = set_pop(keys)
-		value = cast_id2s(dict[key])
+		value = cast_id(dict[key])
 		if (dict_in(reverse, value)):
 			dict_delete(reverse, value)
 		dict_add(reverse, value, key)
@@ -438,5 +464,25 @@ Element function set_difference(sa : Element, sb : Element):
 		if (set_in(sa, elem)):
 			// Shared between both
 			set_remove(result, elem)
+	return result!
+
+Void function set_subtract(set1 : Element, set2 : Element):
+	Element elem
+	set2 = set_copy(set2)
+	while (set_len(set2) > 0):
+		elem = set_pop(set2)
+		if (set_in(set1, elem)):
+			set_remove(set1, elem)
+	return!
+
+Element function range(max : Integer):
+	Element result
+	Integer counter
+	result = list_create()
+	counter = 0
+
+	while (counter < max):
+		list_append(result, counter)
+		counter = counter + 1
 
 	return result!

+ 1 - 1
bootstrap/services.alc

@@ -16,7 +16,7 @@ String function comm_newPort():
 	String attempt
 	attempt = "__hierarchy"
 	while (dict_in(root, attempt)):
-		attempt = (("__" + get_taskname()) + "_") + cast_v2s(services)
+		attempt = "__" + get_taskname() + "_" + cast_value(services)
 		services = services + 1
 
 	// Create queues

+ 8 - 3
bootstrap/tracability.mvc

@@ -1,14 +1,19 @@
 import models/SimpleClassDiagrams as SimpleClassDiagrams
 
 include "primitives.alh"
-include "object_operations.alh"
 
 SimpleClassDiagrams Tracability {
-    SimpleAttribute String {}
+    SimpleAttribute String {
+        name = "String"
+    }
 
-    Class Reference {}
+    Class Reference {
+        name : String
+        name = "Reference"
+    }
     Association TracabilityLink {
         type : String
+        name = "TracabilityLink"
     }
 }
 

+ 22 - 12
bootstrap/transform.alc

@@ -59,14 +59,14 @@ Element function make_matching_schedule(schedule_model : Element, LHS : String,
 					// If it is an edge, we should also add the target and source
 					if (is_edge(schedule_model["model"][next])):
 						// Add the target/source to the schedule
-						set_add(workset, reverse[cast_id2s(read_edge_src(schedule_model["model"][next]))])
-						set_add(workset, reverse[cast_id2s(read_edge_dst(schedule_model["model"][next]))])
+						set_add(workset, reverse[cast_id(read_edge_src(schedule_model["model"][next]))])
+						set_add(workset, reverse[cast_id(read_edge_dst(schedule_model["model"][next]))])
 
 					// Also add all outgoing links
 					counter = read_nr_out(schedule_model["model"][next])
 					while (counter > 0):
 						counter = counter - 1
-						elem_id = cast_id2s(read_out(schedule_model["model"][next], counter))
+						elem_id = cast_id(read_out(schedule_model["model"][next], counter))
 						if (dict_in(reverse, elem_id)):
 							set_add(workset, reverse[elem_id])
 
@@ -74,7 +74,7 @@ Element function make_matching_schedule(schedule_model : Element, LHS : String,
 					counter = read_nr_in(schedule_model["model"][next])
 					while (counter > 0):
 						counter = counter - 1
-						elem_id = cast_id2s(read_in(schedule_model["model"][next], counter))
+						elem_id = cast_id(read_in(schedule_model["model"][next], counter))
 						if (dict_in(reverse, elem_id)):
 							set_add(workset, reverse[elem_id])
 
@@ -240,6 +240,7 @@ Element function get_possible_bindings(host_model : Element, schedule_model : El
 
 Element function full_match(host_model : Element, schedule_model : Element, current : String, single_ok : Boolean):
 	Element NACs
+	Element NACs_backup
 	String LHS
 	String NAC
 	Element mappings
@@ -255,12 +256,13 @@ Element function full_match(host_model : Element, schedule_model : Element, curr
 	mappings = match(host_model, schedule_model, LHS, dict_create())
 
 	// Got a list of all possible mappings, now filter based on NACs
-	NACs = allAssociationDestinations(schedule_model, current, "NACLink")
+	NACs_backup = allAssociationDestinations(schedule_model, current, "NACLink")
 
 	// For each possible mapping, we check all NACs!
 	while (set_len(mappings) > 0):
 		mapping = set_pop(mappings)
 		allowed = True
+		NACs = set_copy(NACs_backup)
 		while (set_len(NACs) > 0):
 			NAC = set_pop(NACs)
 			result = match(host_model, schedule_model, NAC, mapping)
@@ -297,7 +299,7 @@ Element function match(host_model : Element, schedule_model : Element, LHS : Str
 	set_add_node(mappings, initial_mapping)
 	while (list_len(schedule) > 0):
 		current_element = list_pop(schedule, list_len(schedule) - 1)
-		//log("Binding element with label " + cast_v2s(read_attribute(schedule_model, current_element, "label")))
+		//log("Binding element with label " + cast_value(read_attribute(schedule_model, current_element, "label")))
 		new_mappings = dict_create()
 
 		while (set_len(mappings) > 0):
@@ -311,7 +313,7 @@ Element function match(host_model : Element, schedule_model : Element, LHS : Str
 				set_add_node(new_mappings, new_map)
 
 		mappings = new_mappings
-		//log("Remaining options: " + cast_v2s(set_len(mappings)))
+		//log("Remaining options: " + cast_value(set_len(mappings)))
 
 		if (set_len(mappings) == 0):
 			// Stop because we have no more options remaining!
@@ -389,8 +391,8 @@ Void function rewrite(host_model : Element, schedule_model : Element, RHS : Stri
 		label = list_pop(labels_to_add, list_len(labels_to_add) - 1)
 		if (is_edge(schedule_model["model"][RHS_map[label]])):
 			// Edge
-			src = read_attribute(schedule_model, reverse[cast_id2s(read_edge_src(schedule_model["model"][RHS_map[label]]))], "label")
-			dst = read_attribute(schedule_model, reverse[cast_id2s(read_edge_dst(schedule_model["model"][RHS_map[label]]))], "label")
+			src = read_attribute(schedule_model, reverse[cast_id(read_edge_src(schedule_model["model"][RHS_map[label]]))], "label")
+			dst = read_attribute(schedule_model, reverse[cast_id(read_edge_dst(schedule_model["model"][RHS_map[label]]))], "label")
 
 			// First check whether both source and destination are already created
 			if (bool_and(dict_in(new_mapping, src), dict_in(new_mapping, dst))):
@@ -510,10 +512,18 @@ Boolean function transform_composite(host_model : Element, schedule_model : Elem
 		elif (typename == "ForAll"):
 			result = transform_forall(host_model, schedule_model, current)
 
+		Element result_set
 		if (result):
-			current = set_pop(allAssociationDestinations(schedule_model, current, "OnSuccess"))
+			result_set = allAssociationDestinations(schedule_model, current, "OnSuccess")
 		else:
-			current = set_pop(allAssociationDestinations(schedule_model, current, "OnFailure"))
+			result_set = allAssociationDestinations(schedule_model, current, "OnFailure")
+
+		if (set_len(result_set) == 0):
+			log("ERROR: no next rule found for execution result " + cast_string(result))
+		elif (set_len(result_set) > 1):
+			log("WARNING: multiple next rules found for execution result " + cast_string(result))
+			log("Picking one at random...")
+		current = set_pop(result_set)
 
 	// No longer a rule, so it is either success or failure
 	if (is_nominal_instance(schedule_model, current, "Success")):
@@ -553,7 +563,7 @@ Boolean function transform_forall(host_model : Element, schedule_model : Element
 	else:
 		result = False
 
-	//log("Matches in forall: " + cast_v2s(set_len(mappings)))
+	//log("Matches in forall: " + cast_string(set_len(mappings)))
 	while (set_len(mappings) > 0):
 		mapping = set_pop(mappings)
 		RHS = set_pop(allAssociationDestinations(schedule_model, current, "RHSLink"))

+ 14 - 12
bootstrap/typing.alc

@@ -20,10 +20,10 @@ Element function get_type_mapping(model : Element):
 		mm = model["metamodel"]["model"][model["type_mapping"][key]]
 		edge = create_edge(m, mm)
 
-		dict_add_fast(tm_model, cast_id2s(m), m)
-		if (bool_not(dict_in(tm_model, cast_id2s(mm)))):
-			dict_add_fast(tm_model, cast_id2s(mm), mm)
-		dict_add_fast(tm_model, cast_id2s(edge), edge)
+		dict_add_fast(tm_model, cast_id(m), m)
+		if (bool_not(dict_in(tm_model, cast_id(mm)))):
+			dict_add_fast(tm_model, cast_id(mm), mm)
+		dict_add_fast(tm_model, cast_id(edge), edge)
 
 	return tm_model!
 
@@ -43,11 +43,11 @@ Void function set_type_mapping(model : Element, type_mapping_model : Element):
 	while (set_len(keys) > 0):
 		key = set_pop(keys)
 		if (is_edge(type_mapping_model[key])):
-			if (bool_not(bool_or(dict_in(rev_model, cast_id2s(type_mapping_model[key])), dict_in(rev_metamodel, cast_id2s(type_mapping_model[key]))))):
+			if (bool_not(bool_or(dict_in(rev_model, cast_id(type_mapping_model[key])), dict_in(rev_metamodel, cast_id(type_mapping_model[key]))))):
 				// Element is in neither model or metamodel
 				// Must be a typing link!
 				// So add it
-				dict_add_fast(type_mapping, rev_model[cast_id2s(read_edge_src(type_mapping_model[key]))], rev_metamodel[cast_id2s(read_edge_dst(type_mapping_model[key]))])
+				dict_add_fast(type_mapping, rev_model[cast_id(read_edge_src(type_mapping_model[key]))], rev_metamodel[cast_id(read_edge_dst(type_mapping_model[key]))])
 
 	dict_overwrite(model, "type_mapping", type_mapping)
 	return!
@@ -81,17 +81,19 @@ String function read_type(model : Element, name : String):
 Void function retype(model : Element, element : String, type : String):
 	// Retype a model, deleting any previous type the element had
 	// The type string is evaluated in the metamodel previously specified
-	if (dict_in(model["type_mapping"], element)):
-		dict_delete(model["type_mapping"], element)
-	dict_add_fast(model["type_mapping"], element, type)
+	dict_overwrite(model["type_mapping"], element, type)
 	return!
 
 Void function new_type_mapping(model : Element):
-	if (dict_in(model, "type_mapping")):
-		dict_delete(model, "type_mapping")
-	dict_add_fast(model, "type_mapping", dict_create())
+	dict_overwrite(model, "type_mapping", dict_create())
 	return !
 
 Void function remove_type(model : Element, name : String):
 	dict_delete(model["type_mapping"], name)
+	
+	String elem
+	elem = cast_id(model["model"][name])
+	if (dict_in(model["type_mapping"], elem)):
+		dict_delete(model["type_mapping"], elem)
+
 	return !

+ 8 - 18
bootstrap/utils.alc

@@ -28,11 +28,11 @@ String function JSON_print(model : Element):
 				first = False
 
 			result = result + "{"
-			result = (((result + "\"id\": \"") + v_m) + "\"")
-			result = (((result + ",") + "\"type\": \"") + read_type(model, v_m)) + "\""
+			result = result + "\"id\": \"" + v_m + "\""
+			result = result + "," + "\"type\": \"" + read_type(model, v_m) + "\""
 			if (type == "Association"):
-				result = (((result + ", \"__source\": \"") + reverseKeyLookup(model["model"], read_edge_src(model["model"][v_m]))) + "\"")
-				result = (((result + ", \"__target\": \"") + reverseKeyLookup(model["model"], read_edge_dst(model["model"][v_m]))) + "\"")
+				result = result + ", \"__source\": \"" + reverseKeyLookup(model["model"], read_edge_src(model["model"][v_m])) + "\""
+				result = result + ", \"__target\": \"" + reverseKeyLookup(model["model"], read_edge_dst(model["model"][v_m])) + "\""
 
 			// Has attributes
 			attr_keys = dict_keys(getAttributeList(model, v_m))
@@ -40,15 +40,15 @@ String function JSON_print(model : Element):
 				attr_key = set_pop(attr_keys)
 				attr_value = read_attribute(model, v_m, attr_key)
 				if (element_eq(attr_value, read_root())):
-					result = (((result + ", \"") + attr_key) + "\": null")
+					result = result + ", \"" + attr_key + "\": null"
 				else:
 					if (is_physical_boolean(attr_value)):
 						if (attr_value):
-							result = ((result + ", \"") + attr_key) + "\": true"
+							result = result + ", \"" + attr_key + "\": true"
 						else:
-							result = ((result + ", \"") + attr_key) + "\": false"
+							result = result + ", \"" + attr_key + "\": false"
 					else:
-						result = ((((result + ", \"") + attr_key) + "\": ") + cast_v2s(attr_value))
+						result = result + ", \"" + attr_key + "\": " + cast_value(attr_value)
 
 			result = result + "}"
 	result = result + "]"
@@ -88,15 +88,5 @@ Void function list_extend(lst : Element, ext : Element):
 
 	return!
 
-Void function set_difference(set1 : Element, set2 : Element):
-	set2 = set_copy(set2)
-
-	Element elem
-	while (set_len(set2) > 0):
-		elem = set_pop(set2)
-		if (set_in(set1, elem)):
-			set_remove(set1, elem)
-	return!
-
 String function get_taskname():
 	return reverseKeyLookup(read_root(), read_taskroot())!

+ 1 - 1
hybrid_server/classes/mvkcontroller.xml

@@ -354,7 +354,7 @@
                     <state id="mvs_GC">
                         <onentry>
                             <script>
-                                self.mvs.garbage_collect()
+                                self.mvs.purge()
                             </script>
                             <raise scope="broad" event="resume_task"/>
                         </onentry>

+ 10 - 2
integration/code/pn_design.mvc

@@ -1,16 +1,24 @@
-SimpleAttribute Natural {}
-SimpleAttribute String {}
+SimpleAttribute Natural {
+    name = "Natural"
+}
+SimpleAttribute String {
+    name = "String"
+}
 
 Class Place {
+    name = "Place"
     tokens : Natural
     name : String
 }
 Class Transition {
+    name = "Transition"
     name : String
 }
 Association P2T (Place, Transition) {
+    name = "P2T"
     weight : Natural
 }
 Association T2P (Transition, Place) {
+    name = "T2P"
     weight : Natural
 }

+ 1 - 1
integration/code/pn_print.mvc

@@ -14,7 +14,7 @@ Composite schedule {
                 label = "0"
                 action = $
                     Void function action(model : Element, name : String, mapping : Element):
-                        output((cast_v2s(read_attribute(model, name, "name")) + " --> ") + cast_v2s(read_attribute(model, name, "tokens")))
+                        output((cast_value(read_attribute(model, name, "name")) + " --> ") + cast_value(read_attribute(model, name, "tokens")))
                         return!
                     $
             }

+ 6 - 6
integration/code/reachability.alc

@@ -77,8 +77,8 @@ Boolean function reachability_graph(model : Element):
 	set_add(workset, state_id)
 
 	// And add in the model itself
-	state = instantiate_node(model, "ReachabilityGraph/InitialState", cast_i2s(state_id))
-	instantiate_attribute(model, state, "name", cast_i2s(state_id))
+	state = instantiate_node(model, "ReachabilityGraph/InitialState", cast_string(state_id))
+	instantiate_attribute(model, state, "name", cast_string(state_id))
 	instantiate_attribute(model, state, "error", False)
 	keys = dict_keys(dict_repr)
 	while (read_nr_out(keys) > 0):
@@ -148,8 +148,8 @@ Boolean function reachability_graph(model : Element):
 					set_add(workset, target_id)
 
 					// And add in the model itself
-					state = instantiate_node(model, "ReachabilityGraph/State", cast_i2s(target_id))
-					instantiate_attribute(model, state, "name", cast_i2s(target_id))
+					state = instantiate_node(model, "ReachabilityGraph/State", cast_string(target_id))
+					instantiate_attribute(model, state, "name", cast_string(target_id))
 					instantiate_attribute(model, state, "error", False)
 
 					keys = dict_keys(new_dict_repr)
@@ -174,8 +174,8 @@ Boolean function reachability_graph(model : Element):
 				dict_add_fast(mappings[state_id], transition, target_id)
 
 				// And also store it in the model itself
-				new_transition = instantiate_link(model, "ReachabilityGraph/Transition", "", cast_i2s(state_id), cast_i2s(target_id))
+				new_transition = instantiate_link(model, "ReachabilityGraph/Transition", "", cast_string(state_id), cast_string(target_id))
 				instantiate_attribute(model, new_transition, "name", read_attribute(model, transition, "name"))
 
-	log("# reachable states: " + cast_v2s(next_id))
+	log("# reachable states: " + cast_value(next_id))
 	return True!

+ 4 - 4
integration/code/reachability_subfunction.alc

@@ -77,7 +77,7 @@ Boolean function main(model : Element):
 	set_add(workset, state_id)
 
 	// And add in the model itself
-	state = create_state(model, cast_i2s(state_id), dict_repr, cache, True)
+	state = create_state(model, cast_string(state_id), dict_repr, cache, True)
 
 	while (read_nr_out(workset) > 0):
 		state_id = set_pop(workset)
@@ -139,16 +139,16 @@ Boolean function main(model : Element):
 					set_add(workset, target_id)
 
 					// And add in the model itself
-					create_state(model, cast_i2s(target_id), new_dict_repr, cache, False)
+					create_state(model, cast_string(target_id), new_dict_repr, cache, False)
 
 				// Anyway, we have found a transition, which we should store
 				dict_add_fast(mappings[state_id], transition, target_id)
 
 				// And also store it in the model itself
-				new_transition = instantiate_link(model, "ReachabilityGraph/Transition", "", cast_i2s(state_id), cast_i2s(target_id))
+				new_transition = instantiate_link(model, "ReachabilityGraph/Transition", "", cast_string(state_id), cast_string(target_id))
 				instantiate_attribute(model, new_transition, "name", read_attribute(model, transition, "name"))
 
-	log("# reachable states: " + cast_v2s(next_id))
+	log("# reachable states: " + cast_string(next_id))
 	return True!
 
 String function create_state(model : Element, name : String, dict_repr : Element, cache : Element, initial : Boolean):

+ 4 - 4
integration/code/reachabilitygraph_print.mvc

@@ -24,8 +24,8 @@ Composite schedule {
                         while (set_len(all_values) > 0):
                             place = set_pop(all_values)
                             dict_add(dict_values, read_attribute(model, place, "name"), read_attribute(model, place, "tokens"))
-                        log((cast_v2s(read_attribute(model, name, "name")) + ": ") + dict_to_string(dict_values))
-                        output((cast_v2s(read_attribute(model, name, "name")) + ": ") + dict_to_string(dict_values))
+                        log((cast_value(read_attribute(model, name, "name")) + ": ") + dict_to_string(dict_values))
+                        output((cast_value(read_attribute(model, name, "name")) + ": ") + dict_to_string(dict_values))
                         return!
                     $
             }
@@ -55,8 +55,8 @@ Composite schedule {
                 label = "2"
                 action = $
                     Void function action(model : Element, name : String, mapping : Element):
-                        log((((cast_v2s(read_attribute(model, mapping["0"], "name")) + " --[") + cast_v2s(read_attribute(model, name, "name"))) + "]--> ") + cast_v2s(read_attribute(model, mapping["1"], "name")))
-                        output((((cast_v2s(read_attribute(model, mapping["0"], "name")) + " --[") + cast_v2s(read_attribute(model, name, "name"))) + "]--> ") + cast_v2s(read_attribute(model, mapping["1"], "name")))
+                        log((((cast_value(read_attribute(model, mapping["0"], "name")) + " --[") + cast_value(read_attribute(model, name, "name"))) + "]--> ") + cast_value(read_attribute(model, mapping["1"], "name")))
+                        output((((cast_value(read_attribute(model, mapping["0"], "name")) + " --[") + cast_value(read_attribute(model, name, "name"))) + "]--> ") + cast_value(read_attribute(model, mapping["1"], "name")))
                         return!
                     $
             }

+ 2 - 1
interface/HUTN/grammars/actionlanguage.g

@@ -86,7 +86,7 @@ grammar{
 
     type_specifier: INT | FLOAT | BOOL | STRING | TYPE | ACTION | ELEMENT;
 
-    actionname: IF_NODE | WHILE_NODE | ASSIGN_NODE | CALL_NODE | BREAK_NODE | CONTINUE_NODE | RETURN_NODE | RESOLVE_NODE | ACCESS_NODE | CONSTANT_NODE | GLOBAL_NODE | DECLARE_NODE | INPUT_NODE | OUTPUT_NODE;
+    actionname: IF_NODE | WHILE_NODE | ASSIGN_NODE | CALL_NODE | BREAK_NODE | CONTINUE_NODE | RETURN_NODE | RESOLVE_NODE | ACCESS_NODE | CONSTANT_NODE | GLOBAL_NODE | DECLARE_NODE | INPUT_NODE | OUTPUT_NODE | NONE_NODE;
 
     string: (STRVALUE|LONG_STRVALUE);
 
@@ -147,6 +147,7 @@ grammar{
         OUTPUT_NODE: '!output';
         GLOBAL_NODE: '!global';
         DECLARE_NODE: '!declare';
+        NONE_NODE: '!none';
 
         FUNCTION: 'function';
         RETURN: 'return';

+ 3 - 0
interface/HUTN/hutn_compiler/hutnparser.py

@@ -122,6 +122,9 @@ class Tree(object):
             if isinstance(f, Tree):
                 f.fix_tracability(self.inputfile)
 
+    def pretty_print(self, i=0):
+        return "\t" * i + str(self.head) + "\n" + "\n".join([("\t" * (i+1) + st) if isinstance(st, str) else st.pretty_print(i+1) for st in self.get_tail()])
+
 class Parser(object):
     class Constants(object):
         Token = 'token'

+ 24 - 12
interface/HUTN/hutn_compiler/semantics_visitor.py

@@ -127,9 +127,16 @@ class SemanticsVisitor(Visitor):
                         self.get_type(tree)))
 
     def replace_child_binary_op_with_call(self, tree, i=0):
-        child = tree.get_tail()[i]
+        if i == -1:
+            child = tree
+        else:
+            child = tree.get_tail()[i]
         if len(child.get_tail()) > 1:
-            l, op, r = child.get_tail()
+            try:
+                l, op, r = child.get_tail()
+            except:
+                # Something went wrong... this code is severely broken
+                return
             l_type, r_type = self.get_type(l), self.get_type(r)
             if type(l_type) != type(r_type):
                 print("Error: " + str(l_type) + " <-> " + str(r_type))
@@ -140,7 +147,7 @@ class SemanticsVisitor(Visitor):
                         tree.startpos['column']
                     ))
             call_name = SemanticsVisitor.call_name_binary(l_type, op)
-            call_tree = SemanticsVisitor.func_call(call_name, [l, r], tree)
+            call_tree = self.func_call(call_name, [l, r], tree)
             try:
                 self.visit(call_tree)
             except RuntimeError:
@@ -154,7 +161,12 @@ class SemanticsVisitor(Visitor):
                         tree.startpos['column'],
                         child.head,
                         call_signature))
-            tree.replace_child(child, call_tree)
+            if i == -1:
+                tree.head = call_tree.head
+                tree.tail = call_tree.tail
+                tree._tail = None
+            else:
+                tree.replace_child(child, call_tree)
         self.set_type(tree, self.get_type(tree.get_tail()[i]))
 
     def replace_child_unary_op_with_call(self, tree):
@@ -165,7 +177,7 @@ class SemanticsVisitor(Visitor):
             op, l = child.get_tail()
             l_type = self.get_type(l)
             call_name = SemanticsVisitor.call_name_unary(l_type, op)
-            call_tree = SemanticsVisitor.func_call(call_name, [l], tree)
+            call_tree = self.func_call(call_name, [l], tree)
             try:
                 self.visit(call_tree)
             except RuntimeError:
@@ -202,8 +214,7 @@ class SemanticsVisitor(Visitor):
         p_type = self.promote_unary_ops_arithmetic(tree)
         self.perform_implicit_cast(tree, l, l_type, p_type)
 
-    @staticmethod
-    def func_call(name, params, old_tree):
+    def func_call(self, name, params, old_tree):
         startpos = old_tree.startpos
         endpos = old_tree.endpos
         inputfile = old_tree.inputfile
@@ -220,6 +231,9 @@ class SemanticsVisitor(Visitor):
             ],
             startpos, endpos, inputfile)
 
+        for p in params:
+            self.replace_child_binary_op_with_call(p, -1)
+
         params = [hp.Tree("expression", [p], startpos, endpos, inputfile) for p in params]
 
         tree.tail.extend(params)
@@ -228,9 +242,8 @@ class SemanticsVisitor(Visitor):
 
     @staticmethod
     def cast_name(from_type, to_type):
-        from_t = str(from_type)[0].lower()
         to_t = str(to_type)[0].lower()
-        cast_name = "cast_{}2{}".format(from_t, to_t)
+        cast_name = "cast_" + {"f": "float", "i": "integer", "b": "boolean", "s": "string"}[to_t]
         return cast_name
 
     def raise_implicit_cast_error(self, from_type, to_type, tree):
@@ -252,8 +265,7 @@ class SemanticsVisitor(Visitor):
         if type(from_type) == type(to_type):
             return
         cast_name = SemanticsVisitor.cast_name(from_type, to_type)
-        cast_tree = \
-            SemanticsVisitor.func_call(cast_name, [child], tree)
+        cast_tree = self.func_call(cast_name, [child], tree)
         try:
             self.visit(cast_tree)
         except RuntimeError:
@@ -507,7 +519,7 @@ class SemanticsVisitor(Visitor):
             node = tree.get_child("rvalue")
             expression = tree.get_child("expression")
             operation = "dict_read"
-            call_tree = SemanticsVisitor.func_call(operation, [node, expression], tree)
+            call_tree = self.func_call(operation, [node, expression], tree)
             self.visit(call_tree)
             tree.head = call_tree.head
             tree._tail = call_tree.tail

+ 3 - 0
interface/HUTN/includes/io.alh

@@ -1,3 +1,6 @@
 Element function input()
 Void function output(value : Element)
 Element function input_timeout(timeout : Float)
+Boolean function other_has_output(comm : String)
+Void function give_input_to_other(comm : String, value : Element)
+Element function get_output_from_other(comm : String)

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

@@ -0,0 +1,2 @@
+String function json_serialize(data : Element)
+Element function json_deserialize(str : String)

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

@@ -21,7 +21,9 @@ Void function unset_attribute(model : Element, elem : String, name : String)
 Void function construct_model()
 Element function read_attribute(model : Element, elem : String, name : String)
 Void function model_delete_element(model : Element, name : String)
+String function model_undefine_attribute(model : Element, elem : String, name : String)
 String function model_define_attribute(model : Element, elem : String, name : String, optional : Boolean, type : String)
+String function model_define_attribute_ID(model : Element, elem : String, name : String, optional : Boolean, type : String, ID : String)
 Element function construct_model_raw(metamodel : Element)
 Element function get_func_AL_model(model : Element)
 Void function add_code_model(model : Element, export_name : String, code : Element)

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

@@ -4,7 +4,8 @@ Element function selectPossibleOutgoing(model : Element, source : String, limit_
 Element function allOutgoingAssociationInstances(model: Element, source_name : String, assoc_name: String)
 Element function allIncomingAssociationInstances(model: Element, target_name : String, assoc_name: String)
 Element function getAttributeList(model: Element, element: String)
-Element function getInstantiatableAttributes(model: Element, element: String)
+Element function getAttributes(model: Element, element: String)
+Element function getInstantiatableAttributes(model: Element, element: String, type: String)
 String function print_dict(dict : Element)
 String function readAssociationSource(model : Element, name : String)
 String function readAssociationDestination(model : Element, name : String)

+ 12 - 17
interface/HUTN/includes/primitives.alh

@@ -16,22 +16,12 @@ Element function read_edge_dst(a: Element)
 Boolean function delete_element(a: Element) 
 Boolean function element_eq(a: Element, b: Element) 
 Boolean function element_neq(a: Element, b: Element) 
-Float function cast_i2f(a: Integer)
-String function cast_i2s(a: Integer) 
-Boolean function cast_i2b(a: Integer) 
-Integer function cast_f2i(a: Float) 
-Boolean function cast_f2b(a: Float) 
-String function cast_f2s(a: Float) 
-Integer function cast_s2i(a: String) 
-Float function cast_s2f(a: String) 
-Boolean function cast_s2b(a: String) 
-Integer function cast_b2i(a: Boolean) 
-Float function cast_b2f(a: Boolean) 
-String function cast_b2s(a: Boolean) 
-String function cast_e2s(a: Element) 
-String function cast_a2s(a: Action) 
-String function cast_v2s(a: Element) 
-String function cast_id2s(a: Element) 
+Float function cast_float(a: Element)
+String function cast_string(a: Element) 
+Boolean function cast_boolean(a: Element) 
+Integer function cast_integer(a: Element) 
+String function cast_id(a: Element) 
+String function cast_value(a: Element) 
 Element function dict_add(a: Element, b: Element, c: Element)
 Element function dict_add_fast(a: Element, b: Element, c: Element)
 Element function dict_delete(a: Element, b: Element)
@@ -93,6 +83,7 @@ Boolean function is_physical_float(a : Element)
 Boolean function is_physical_string(a : Element)
 Boolean function is_physical_action(a : Element)
 Boolean function is_physical_boolean(a : Element)
+Boolean function is_physical_none(a : Element)
 Boolean function has_value(a : Element)
 Float function time()
 String function hash(a : String)
@@ -108,11 +99,14 @@ String function set_to_string(set : Element)
 String function list_to_string(set : Element)
 String function dict_to_string(dict : Element)
 Element function set_overlap(sa : Element, sb : Element)
-Element function set_difference(sa : Element, sb : Element)
 Element function set_equality(sa : Element, sb : Element)
+Element function set_difference(sa : Element, sb : Element)
+Void function set_subtract(sa : Element, sb : Element)
 Element function dict_eq(da : Element, db : Element)
 Element function dict_copy(dict : Element)
 Element function set_to_list(s : Element)
+Element function list_to_set(s : Element)
+Element function list_copy(list : Element)
 Element function create_tuple(a : Element, b : Element)
 Void function dict_overwrite(a : Element, b : Element, c : Element)
 Void function set_merge(sa : Element, sb : Element)
@@ -124,3 +118,4 @@ String function reverseKeyLookup(a: Element, b: Element)
 Element function reverseKeyLookupMulti(a: Element, b: Element)
 Element function dict_values(dict : Element)
 Boolean function is_error(a : Element)
+Element function range(max : Integer)

+ 0 - 1
interface/HUTN/includes/utils.alh

@@ -2,6 +2,5 @@ String function JSON_print(model : Element)
 Element function list_reverse(lst : Element)
 Element function list_splice(lst : Element, start : Integer, end : Integer)
 Void function list_extend(lst : Element, ext : Element)
-Void function set_difference(set1 : Element, set2 : Element)
 String function get_taskname()
 Void function sleep(seconds : Float)

+ 7 - 0
interface/HUTN/test/constructor_compilation_action_language/code/string_concat.al

@@ -0,0 +1,7 @@
+Element string_join = ?primitives/string_join
+Element integer_addition = ?primitives/integer_addition
+
+Void function main():
+	String a
+	a = "1" + "2" + "3"
+	return!

+ 1 - 0
interface/HUTN/test/constructor_compilation_action_language/expected/string_concat

@@ -0,0 +1 @@
+[42, "global", "string_join", "deref", "primitives/string_join", true, "global", "integer_addition", "deref", "primitives/integer_addition", true, "funcdef", "main", 0, "declare", "0", "none", true, "assign", "resolve", "0", "call", "access", "resolve", "string_join", 2, "call", "access", "resolve", "string_join", 2, "const", "1", "const", "2", false, "const", "3", false, true, "return", false, false]

+ 7 - 4
interface/HUTN/test/constructor_compilation_action_language/test_compile.py

@@ -9,10 +9,10 @@ def compile_file(obj, filename):
     try:
         expected = json.loads(open(util.get_expected_path(filename)).read())
     except:
-        #f = open(util.get_expected_path(filename), 'w')
-        #f.write(json.dumps(result))
-        #f.close()
-        pass
+        f = open(util.get_expected_path(filename), 'w')
+        f.write(json.dumps(result))
+        f.close()
+        expected = None
     assert result == expected
 
 class TestCompile(unittest.TestCase):
@@ -69,3 +69,6 @@ class TestCompile(unittest.TestCase):
 
     def test_strange_return(self):
         compile_file(self, "strange_return.al")
+
+    def test_string_concat(self):
+        compile_file(self, "string_concat.al")

+ 4 - 12
kernel/modelverse_jit/intrinsics.py

@@ -37,18 +37,10 @@ UNARY_INTRINSICS = {
 }
 
 CAST_INTRINSICS = {
-    'cast_i2f' : float,
-    'cast_i2s' : str,
-    'cast_i2b' : bool,
-    'cast_f2i' : int,
-    'cast_f2s' : str,
-    'cast_f2b' : bool,
-    'cast_s2i' : int,
-    'cast_s2f' : float,
-    'cast_s2b' : bool,
-    'cast_b2i' : int,
-    'cast_b2f' : float,
-    'cast_b2s' : str
+    'cast_float' : float,
+    'cast_string' : str,
+    'cast_boolean' : bool,
+    'cast_integer' : int,
 }
 
 def create_get_length(expression):

+ 19 - 0
kernel/modelverse_kernel/compiled.py

@@ -254,3 +254,22 @@ def list_pop_final(a, **remainder):
                                  ("RDE", [a, length -1])]
     _, = yield [("DE", [result_edge])]
     raise PrimitiveFinished(result)
+
+def instantiate_node(a, b, c, **remainder):
+    node, dict_entry, typing, name = \
+        yield [("CN", []),
+               ("RD", [a, "model"]),
+               ("RD", [a, "type_mapping"]),
+               ("RV", [c]),
+              ]
+
+    if name == "":
+        name = "__" + str(node)
+        name_node, = yield [("CNV", [name])]
+    else:
+        name_node = c
+
+    yield [("CD", [dict_entry, name, node])]
+    yield [("CD", [typing, name, b])]
+
+    raise PrimitiveFinished(name_node)

+ 15 - 57
kernel/modelverse_kernel/primitives.py

@@ -138,77 +138,30 @@ def element_eq(a, b, **remainder):
     result, = yield [("CNV", [a == b])]
     raise PrimitiveFinished(result)
 
-def cast_a2s(a, **remainder):
+def cast_string(a, **remainder):
     a_value, = yield [("RV", [a])]
-    result, = yield [("CNV", [str(a_value["value"])])]
-    raise PrimitiveFinished(result)
-
-def cast_i2f(a, **remainder):
-    a_value, = yield [("RV", [a])]
-    result, = yield [("CNV", [float(a_value)])]
-    raise PrimitiveFinished(result)
-
-def cast_i2s(a, **remainder):
-    a_value, = yield [("RV", [a])]
-    result, = yield [("CNV", [str(a_value)])]
-    raise PrimitiveFinished(result)
-
-def cast_i2b(a, **remainder):
-    a_value, = yield [("RV", [a])]
-    result, = yield [("CNV", [bool(a_value)])]
-    raise PrimitiveFinished(result)
-
-def cast_f2i(a, **remainder):
-    a_value, = yield [("RV", [a])]
-    result, = yield [("CNV", [int(a_value)])]
-    raise PrimitiveFinished(result)
-
-def cast_f2s(a, **remainder):
-    a_value, = yield [("RV", [a])]
-    result, = yield [("CNV", [str(a_value)])]
-    raise PrimitiveFinished(result)
-
-def cast_f2b(a, **remainder):
-    a_value, = yield [("RV", [a])]
-    result, = yield [("CNV", [bool(a_value)])]
-    raise PrimitiveFinished(result)
-
-def cast_s2i(a, **remainder):
-    a_value, = yield [("RV", [a])]
-    result, = yield [("CNV", [int(a_value)])]
+    if isinstance(a_value, dict):
+        result, = yield [("CNV", [str(a_value["value"])])]
+    else:
+        result, = yield [("CNV", [str(a_value)])]
     raise PrimitiveFinished(result)
 
-def cast_s2f(a, **remainder):
+def cast_float(a, **remainder):
     a_value, = yield [("RV", [a])]
     result, = yield [("CNV", [float(a_value)])]
     raise PrimitiveFinished(result)
 
-def cast_s2b(a, **remainder):
+def cast_boolean(a, **remainder):
     a_value, = yield [("RV", [a])]
     result, = yield [("CNV", [bool(a_value)])]
     raise PrimitiveFinished(result)
 
-def cast_b2i(a, **remainder):
+def cast_integer(a, **remainder):
     a_value, = yield [("RV", [a])]
     result, = yield [("CNV", [int(a_value)])]
     raise PrimitiveFinished(result)
 
-def cast_b2f(a, **remainder):
-    a_value, = yield [("RV", [a])]
-    result, = yield [("CNV", [float(a_value)])]
-    raise PrimitiveFinished(result)
-
-def cast_b2s(a, **remainder):
-    a_value, = yield [("RV", [a])]
-    result, = yield [("CNV", [str(a_value)])]
-    raise PrimitiveFinished(result)
-
-def cast_e2s(a, **remainder):
-    a_value, = yield [("RV", [a])]
-    result, = yield [("CNV", ["{ID: %s, value: %s}" % (a, a_value)])]
-    raise PrimitiveFinished(result)
-
-def cast_v2s(a, **remainder):
+def cast_value(a, **remainder):
     a_value, = yield [("RV", [a])]
     if isinstance(a_value, dict):
         # Action or type
@@ -218,7 +171,7 @@ def cast_v2s(a, **remainder):
     result, = yield [("CNV", [value])]
     raise PrimitiveFinished(result)
 
-def cast_id2s(a, **remainder):
+def cast_id(a, **remainder):
     result, = yield [("CNV", ["%s" % (a)])]
     raise PrimitiveFinished(result)
 
@@ -327,6 +280,11 @@ def is_physical_action(a, **remainder):
     result, = yield [("CNV", [isinstance(t, dict) and t["value"] in ["if", "while", "assign", "call", "break", "continue", "return", "resolve", "access", "constant", "global", "declare"]])]
     raise PrimitiveFinished(result)
 
+def is_physical_none(a, **remainder):
+    t, = yield [("RV", [a])]
+    result, = yield [("CNV", [isinstance(t, dict) and t["value"] == "none"])]
+    raise PrimitiveFinished(result)
+
 def create_node(**remainder):
     result, = yield [("CN", [])]
     raise PrimitiveFinished(result)

+ 56 - 67
kernel/test/primitives/test_cast.py

@@ -25,106 +25,95 @@ class TestCast(unittest.TestCase):
         execute_until_finished(self.mvk, self.mvs, "load_primitives", [])
         self.primitives = read_primitive_interfaces(self.root, self.mvs)
 
-    def test_cast_i2f(self):
-        self.helper_primitives_1_params("cast_i2f", 2, 2.0)
+    def test_cast_float(self):
+        self.helper_primitives_1_params("cast_float", 2, 2.0)
 
-    def test_cast_i2s(self):
-        self.helper_primitives_1_params("cast_i2s", 2, "2")
+    def test_cast_string(self):
+        self.helper_primitives_1_params("cast_string", 2, "2")
 
-    def test_cast_i2b(self):
-        self.helper_primitives_1_params("cast_i2b", 2, True)
+    def test_cast_boolean(self):
+        self.helper_primitives_1_params("cast_boolean", 2, True)
 
-    def test_cast_f2i(self):
-        self.helper_primitives_1_params("cast_f2i", 2.4, 2)
+    def test_cast_integer(self):
+        self.helper_primitives_1_params("cast_integer", 2.4, 2)
 
-    def test_cast_f2s(self):
-        self.helper_primitives_1_params("cast_f2s", 2.4, "2.4")
+    def test_cast_string(self):
+        self.helper_primitives_1_params("cast_string", 2.4, "2.4")
 
-    def test_cast_f2b(self):
-        self.helper_primitives_1_params("cast_f2b", 2.4, True)
+    def test_cast_boolean(self):
+        self.helper_primitives_1_params("cast_boolean", 2.4, True)
 
-    def test_cast_s2i(self):
-        self.helper_primitives_1_params("cast_s2i", "2", 2)
+    def test_cast_integer(self):
+        self.helper_primitives_1_params("cast_integer", "2", 2)
 
-    def test_cast_s2f(self):
-        self.helper_primitives_1_params("cast_s2f", "2.4", 2.4)
+    def test_cast_float(self):
+        self.helper_primitives_1_params("cast_float", "2.4", 2.4)
 
-    def test_cast_s2b(self):
-        self.helper_primitives_1_params("cast_s2b", "2.4", True)
+    def test_cast_boolean(self):
+        self.helper_primitives_1_params("cast_boolean", "2.4", True)
 
-    def test_cast_b2i_true(self):
-        self.helper_primitives_1_params("cast_b2i", True, 1)
+    def test_cast_integer_true(self):
+        self.helper_primitives_1_params("cast_integer", True, 1)
 
-    def test_cast_b2f_true(self):
-        self.helper_primitives_1_params("cast_b2f", True, 1.0)
+    def test_cast_float_true(self):
+        self.helper_primitives_1_params("cast_float", True, 1.0)
 
-    def test_cast_b2s_true(self):
-        self.helper_primitives_1_params("cast_b2s", True, "True")
+    def test_cast_string_true(self):
+        self.helper_primitives_1_params("cast_string", True, "True")
 
-    def test_cast_b2i_false(self):
-        self.helper_primitives_1_params("cast_b2i", False, 0)
+    def test_cast_integer_false(self):
+        self.helper_primitives_1_params("cast_integer", False, 0)
 
-    def test_cast_b2f_false(self):
-        self.helper_primitives_1_params("cast_b2f", False, 0.0)
+    def test_cast_float_false(self):
+        self.helper_primitives_1_params("cast_float", False, 0.0)
 
-    def test_cast_b2s_false(self):
-        self.helper_primitives_1_params("cast_b2s", False, "False")
+    def test_cast_string_false(self):
+        self.helper_primitives_1_params("cast_string", False, "False")
 
-    def test_cast_e2s_node(self):
+    def test_cast_string_int(self):
         n = self.mvs.execute("CN", [])
-        self.helper_primitives_1_params("cast_e2s", n, "{ID: %s, value: None}" % n, t=True)
+        self.helper_primitives_1_params("cast_string", n, "None", t=True)
 
-    def test_cast_e2s_edge(self):
-        a = self.mvs.execute("CN", [])
-        b = self.mvs.execute("CN", [])
-        n = self.mvs.execute("CE", [a, b])
-        self.helper_primitives_1_params("cast_e2s", n, "{ID: %s, value: None}" % n, t=True)
-
-    def test_cast_e2s_value(self):
-        n = self.mvs.execute("CNV", [10])
-        self.helper_primitives_1_params("cast_e2s", n, "{ID: %s, value: 10}" % n, t=True)
-
-    def test_cast_v2s_int(self):
-        n = self.mvs.execute("CN", [])
-        self.helper_primitives_1_params("cast_v2s", n, "None", t=True)
+    def test_cast_string_int(self):
+        self.helper_primitives_1_params("cast_string", 2, "2")
 
-    def test_cast_v2s_int(self):
-        self.helper_primitives_1_params("cast_v2s", 2, "2")
+    def test_cast_string_neg_int(self):
+        self.helper_primitives_1_params("cast_string", -2, "-2")
 
-    def test_cast_v2s_neg_int(self):
-        self.helper_primitives_1_params("cast_v2s", -2, "-2")
+    def test_cast_string_float(self):
+        self.helper_primitives_1_params("cast_string", 2.0, "2.0")
 
-    def test_cast_v2s_float(self):
-        self.helper_primitives_1_params("cast_v2s", 2.0, "2.0")
+    def test_cast_string_neg_float(self):
+        self.helper_primitives_1_params("cast_string", -2.0, "-2.0")
 
-    def test_cast_v2s_neg_float(self):
-        self.helper_primitives_1_params("cast_v2s", -2.0, "-2.0")
+    def test_cast_string_string(self):
+        self.helper_primitives_1_params("cast_string", "abc", "abc")
 
-    def test_cast_v2s_string(self):
-        self.helper_primitives_1_params("cast_v2s", "abc", "\"abc\"")
+    def test_cast_string_string_stringnum(self):
+        self.helper_primitives_1_params("cast_value", "3", "\"3\"")
 
-    def test_cast_v2s_string_num(self):
-        self.helper_primitives_1_params("cast_v2s", "3", "\"3\"")
+    def test_cast_string_string_num(self):
+        self.helper_primitives_1_params("cast_value", 3, "3")
 
-    def test_cast_v2s_bool(self):
-        self.helper_primitives_1_params("cast_v2s", True, "true")
+    def test_cast_string_bool(self):
+        self.helper_primitives_1_params("cast_value", True, "true")
 
-    def test_cast_v2s_action(self):
-        self.helper_primitives_1_params("cast_v2s", {"value": "call"}, "call")
+    def test_cast_string_action(self):
+        self.helper_primitives_1_params("cast_value", {"value": "call"}, "call")
 
-    def test_cast_id2s_node(self):
+    def test_cast_id_node(self):
         n = self.mvs.execute("CN", [])
-        self.helper_primitives_1_params("cast_id2s", n, str(n), t=True)
+        self.helper_primitives_1_params("cast_id", n, str(n), t=True)
 
-    def test_cast_id2s_value(self):
+    def test_cast_id_value(self):
         n = self.mvs.execute("CNV", ["abc"])
-        self.helper_primitives_1_params("cast_id2s", n, str(n), t=True)
+        self.helper_primitives_1_params("cast_id", n, str(n), t=True)
 
-    def test_cast_id2s_edge(self):
+    def test_cast_id_edge(self):
         a = self.mvs.execute("CN", [])
         b = self.mvs.execute("CN", [])
         n = self.mvs.execute("CE", [a, b])
-        self.helper_primitives_1_params("cast_id2s", n, str(n), t=True)
+        self.helper_primitives_1_params("cast_id", n, str(n), t=True)
 
     def helper_primitives_1_params(self, operation, a, result, t=False):
         self.actual_arg_a = self.mvs.execute("CN", [])

+ 72 - 0
models/MM_render.mvc

@@ -0,0 +1,72 @@
+include "primitives.alh"
+
+SimpleAttribute Natural {}
+SimpleAttribute String {}
+SimpleAttribute Boolean {}
+
+Class GraphicalElement {
+    x : Natural
+    y : Natural
+    layer : Natural
+}
+
+Class Group : GraphicalElement {
+    __asid : String
+    dirty : Boolean
+}
+
+Association ConnectingLine (Group, Group) {
+    offsetSourceX : Natural
+    offsetSourceY : Natural
+    offsetTargetX : Natural
+    offsetTargetY : Natural
+    lineWidth : Natural
+    lineColour : String
+    arrow : Boolean
+    __asid : String
+    dirty : Boolean
+    layer : Natural
+}
+
+Class LineElement : GraphicalElement {
+    lineWidth : Natural
+    lineColour : String
+}
+
+Class Text : LineElement {
+    text : String
+}
+
+Class Line : LineElement {
+    targetX : Natural
+    targetY : Natural
+    arrow : Boolean
+}
+
+Class Shape : LineElement {
+    fillColour : String
+    width : Natural
+    height : Natural
+}
+
+Class Figure : GraphicalElement {
+    width : Natural
+    height : Natural
+}
+
+Class SVG {
+    data : String
+}
+
+Class Rectangle : Shape {
+}
+
+Class Ellipse : Shape {
+}
+
+Association contains (Group, GraphicalElement) {}
+Association renders (Figure, SVG) {
+    source_lower_cardinality = 1
+    target_lower_cardinality = 1
+    target_upper_cardinality = 1
+}

+ 20 - 3
models/MM_rendered_graphical.mvc

@@ -1,54 +1,71 @@
 include "primitives.alh"
 
-SimpleAttribute Natural {}
-SimpleAttribute String {}
+SimpleAttribute Natural {
+    name = "Natural"
+}
+SimpleAttribute String {
+    name = "String"
+}
 
 Class GraphicalElement {
+    name = "GraphicalElement"
     x : Natural
     y : Natural
     __asid? : String
 }
 
 Class Group : GraphicalElement {
+    name = "Group"
 }
 
 Class LineElement : GraphicalElement {
+    name = "LineElement"
     lineWidth : Natural
     lineColour : String
 }
 
 Class Text : LineElement {
+    name = "Text"
     text : String
 }
 
 Class Line : LineElement {
+    name = "Line"
     targetX : Natural
     targetY : Natural
 }
 
 Class Shape : LineElement {
+    name = "Shape"
     fillColour : String
     width : Natural
     height : Natural
 }
 
 Class Figure : GraphicalElement {
+    name = "Figure"
     width : Natural
     height : Natural
 }
 
 Class SVG {
+    name = "SVG"
     data : String
 }
 
 Class Rectangle : Shape {
+    name = "Rectangle"
 }
 
 Class Ellipse : Shape {
+    name = "Ellipse"
 }
 
-Association contains (Group, GraphicalElement) {}
+Association contains (Group, GraphicalElement) {
+    name = "contains"
+}
 Association renders (Figure, SVG) {
+    name = "renders"
     source_lower_cardinality = 1
     target_lower_cardinality = 1
     target_upper_cardinality = 1

+ 31 - 9
models/MM_rendered_plot.mvc

@@ -1,34 +1,56 @@
-SimpleAttribute String {}
-SimpleAttribute Boolean {}
-SimpleAttribute Float {}
+SimpleAttribute String {
+    name = "String"
+}
+SimpleAttribute Boolean {
+    name = "Boolean"
+}
+SimpleAttribute Float {
+    name = "Float"
+}
 
 Class Plot {
+    name = "Plot"
     title : String
     legend : Boolean
 }
 
 Class Dataset {
+    name = "Dataset"
     legend : String
     color : String
     linestyle : String
 }
 
 Class Datapoint {
+    name = "Datapoint"
     x : Float
     y : Float
 }
 
 Class Axis {
+    name = "Axis"
     name : String
     unit : String
     lim_low? : Float
     lim_high? : Float
 }
 
-Class XAxis : Axis {}
-Class YAxis : Axis {}
+Class XAxis : Axis {
+    name = "XAxis"
+}
+Class YAxis : Axis {
+    name = "YAxis"
+}
 
-Association x (Plot, XAxis) {}
-Association y (Plot, YAxis) {}
-Association data (Plot, Dataset) {}
-Association point (Dataset, Datapoint) {}
+Association x (Plot, XAxis) {
+    name = "x"
+}
+Association y (Plot, YAxis) {
+    name = "y"
+}
+Association data (Plot, Dataset) {
+    name = "data"
+}
+Association point (Dataset, Datapoint) {
+    name = "point"
+}

+ 48 - 10
models/SCCD.mvc

@@ -2,12 +2,21 @@ include "primitives.alh"
 include "object_operations.alh"
 include "modelling.alh"
 
-SimpleAttribute Action {}
-SimpleAttribute Boolean {}
-SimpleAttribute String {}
-SimpleAttribute Natural {}
+SimpleAttribute Action {
+    name = "Action"
+}
+SimpleAttribute Boolean {
+    name = "Boolean"
+}
+SimpleAttribute String {
+    name = "String"
+}
+SimpleAttribute Natural {
+    name = "Natural"
+}
 
 Class Diagram{
+    name = "Diagram"
     name : String
     author : String
     description : String
@@ -16,6 +25,7 @@ Class Diagram{
 }
 
 Class Class{
+    name = "Class"
     name : String
     constructor_body? : Action
     destructor? : Action
@@ -24,73 +34,100 @@ Class Class{
 }
 
 Association diagram_classes(Diagram, Class){
+    name = "diagram_classes"
     target_lower_cardinality = 1
 }
 
 Class Attribute{
+    name = "Attribute"
     name : String
 }
-Association class_attributes(Class, Attribute){}
+Association class_attributes(Class, Attribute){
+    name = "class_attributes"
+}
 
 Class Method{
+    name = "Method"
     name : String
     body : Action
 }
 
 Association association(Class, Class){
+    name = "association"
     name : String
     source_upper_cardinality = 1
 }
 
 Association inheritance(Class, Class){
+    name = "inheritance"
     priority ?: Natural
     source_upper_cardinality = 1
 }
 
 Class State{
+    name = "State"
     name : String
 }
 
 Class BasicState : State{
+    name = "BasicState"
     isInitial : Boolean
     onEntryScript? : Action
     onExitScript? : Action
 }
 
 Class Raise{
+    name = "Raise"
     event : String
     scope? : String
     target? : String
     parameter? : Action
 }
-Association onEntryRaise (BasicState, Raise) {}
-Association onExitRaise (BasicState, Raise) {}
+Association onEntryRaise (BasicState, Raise) {
+    name = "onEntryRaise"
+}
+Association onExitRaise (BasicState, Raise) {
+    name = "onExitRaise"
+}
 
 Association behaviour(Class, BasicState){
+    name = "behaviour"
     target_lower_cardinality = 1
     target_upper_cardinality = 1
 }
 
 Association state_onentry_raises(BasicState, Raise){
+    name = "state_onentry_raises"
     order : Natural
 }
 Association state_onexit_raises(BasicState, Raise){
+    name = "state_onexit_raises"
     order : Natural
 }
 
-Class CompositeState : BasicState{}
+Class CompositeState : BasicState{
+    name = "CompositeState"
+}
+
 Association composite_children(CompositeState, State){
+    name = "composite_children"
     source_upper_cardinality = 1
 }
 
-Class ParallelState : BasicState{}
+Class ParallelState : BasicState{
+    name = "ParallelState"
+}
 Association parallel_children(ParallelState, CompositeState){
+    name = "parallel_children"
     source_upper_cardinality = 1
 }
 
-Class HistoryState : State{}
+Class HistoryState : State{
+    name = "HistoryState"
+}
 
 Association transition(State, State){
+    name = "transition"
     name: String
     cond? : Action
     script? : Action
@@ -99,5 +136,6 @@ Association transition(State, State){
     source_upper_cardinality = 1
 }
 Association transition_raises(transition, Raise){
+    name = "transition_raises"
     order : Natural
 }

+ 7 - 2
models/SCCD_Trace.mvc

@@ -1,7 +1,12 @@
-SimpleAttribute Float {}
-SimpleAttribute String {}
+SimpleAttribute Float {
+    name = "Float"
+}
+SimpleAttribute String {
+    name = "String"
+}
 
 Class Event{
+    name = "Event"
     timestamp : Float
     name : String
     parameter : String

+ 2 - 2
models/SCCD_execute.alc

@@ -134,7 +134,7 @@ String function start_class(model : Element, data : Element, class : String, par
 
 	// First find an empty identifier
 	String identifier
-	identifier = cast_i2s(dict_len(data["classes"]))
+	identifier = cast_string(dict_len(data["classes"]))
 
 	// Create the data structure for a running class
 	Element class_handle
@@ -442,7 +442,7 @@ Boolean function step_class(model : Element, data : Element, class : String):
 				// When leaving an orthogonal component, we must also pop all related states that might be processed in the future!
 				Element leaving
 				leaving = expand_current_state(model, current_state, data)
-				set_difference(states, leaving)
+				set_subtract(states, leaving)
 
 				transitioned = True
 				found = True

+ 9 - 2
models/architecture.mvc

@@ -1,6 +1,7 @@
 include "primitives.alh"
 
 SimpleAttribute String{
+    name = "String"
     constraint = $
         String function main(model : Element, name : String):
             if (is_physical_string(model["model"][name])):
@@ -12,11 +13,17 @@ SimpleAttribute String{
 
 Class Group {
     name : String
+    name = "Group"
 }
 
 Class Port {
     name : String
+    name = "Port"
 }
 
-Association Connects (Port, Port) {}
-Association Contains (Group, Port) {}
+Association Connects (Port, Port) {
+    name = "Connects"
+}
+Association Contains (Group, Port) {
+    name = "Contains"
+}

+ 2 - 2
models/combine_EPN.mvc

@@ -52,9 +52,9 @@ Composite schedule {
                     name_4 = read_attribute(model, mapping["4"], "name")
                     name_5 = read_attribute(model, mapping["5"], "name")
 
-                    if bool_not((name_0 + "/") + name_1 == name_2):
+                    if bool_not(name_0 + "/" + name_1 == name_2):
                         return False!
-                    if bool_not((name_3 + "/") + name_4 == name_5):
+                    if bool_not(name_3 + "/" + name_4 == name_5):
                         return False!
                     return True!
                 $

+ 27 - 8
models/control_PW.mvc

@@ -1,8 +1,13 @@
 include "primitives.alh"
 
-SimpleAttribute Boolean {}
-SimpleAttribute TriState {}
+SimpleAttribute Boolean {
+    name = "Boolean"
+}
+SimpleAttribute TriState {
+    name = "TriState"
+}
 SimpleAttribute String{
+    name = "String"
     constraint = $
         String function constraint(model : Element, name : String):
             if (is_physical_string(model["model"][name])):
@@ -13,18 +18,32 @@ SimpleAttribute String{
 }
 
 Class State {
+    name = "State"
     isInitial : Boolean
     isError : Boolean
     name : String
 }
 
-Class Up : State {}
-Class Down : State {}
-Class Neutral : State {}
+Class Up : State {
+    name = "Up"
+}
+Class Down : State {
+    name = "Down"
+}
+Class Neutral : State {
+    name = "Neutral"
+}
 
 Association Transition (State, State) {
+    name = "Transition"
     objDetected : TriState
 }
-Association UpPressed : Transition (State, State) {}
-Association NonePressed : Transition (State, State) {}
-Association DownPressed : Transition (State, State) {}
+Association UpPressed : Transition (State, State) {
+    name = "UpPressed"
+}
+Association NonePressed : Transition (State, State) {
+    name = "NonePressed"
+}
+Association DownPressed : Transition (State, State) {
+    name = "DownPressed"
+}

+ 16 - 5
models/environment_PW.mvc

@@ -1,13 +1,24 @@
 include "primitives.alh"
 
-SimpleAttribute Boolean {}
-SimpleAttribute Natural{}
-SimpleAttribute String{}
+SimpleAttribute Boolean {
+    name = "Boolean"
+}
+SimpleAttribute Natural{
+    name = "Natural"
+}
+SimpleAttribute String{
+    name = "String"
+}
 
-Class Group {}
+Class Group {
+    name = "Group"
+}
 Class Event {
+    name = "Event"
     initial : Boolean
     name : String
 }
 
-Association Contains (Group, Event) {}
+Association Contains (Group, Event) {
+    name = "Contains"
+}

+ 3 - 3
models/epn_print.alc

@@ -17,7 +17,7 @@ Boolean function pn_print(model : Element):
 		name = read_attribute(model, place, "name")
 		tokens = read_attribute(model, place, "tokens")
 
-		log((("  " + name) + ": ") + cast_v2s(tokens))
+		log("  " + name + ": " + cast_string(tokens))
 
 	log("Transitions:")
 	all_places = allInstances(model, "Encapsulated_PetriNet/Transition")
@@ -30,12 +30,12 @@ Boolean function pn_print(model : Element):
 		all_t = allIncomingAssociationInstances(model, place, "Encapsulated_PetriNet/P2T")
 		while (set_len(all_t) > 0):
 			t = set_pop(all_t)
-			log("    <-- " + cast_v2s(read_attribute(model, readAssociationSource(model, t), "name")))
+			log("    <-- " + cast_value(read_attribute(model, readAssociationSource(model, t), "name")))
 
 		all_t = allOutgoingAssociationInstances(model, place, "Encapsulated_PetriNet/T2P")
 		while (set_len(all_t) > 0):
 			t = set_pop(all_t)
-			log("    --> " + cast_v2s(read_attribute(model, readAssociationDestination(model, t), "name")))
+			log("    --> " + cast_value(read_attribute(model, readAssociationDestination(model, t), "name")))
 
 	log("Ports:")
 	all_places = allInstances(model, "Encapsulated_PetriNet/Port")

+ 1 - 1
models/merge_EPN.alc

@@ -12,5 +12,5 @@ Boolean function main(model : Element):
 		split = string_split(read_type(model, key), "/")
 		retype(model, key, string_join("Encapsulated_PetriNet/", split[1]))
 
-	//log("merge_EPN has seen # elements: " + cast_v2s(dict_len(model["model"])))
+	//log("merge_EPN has seen # elements: " + cast_value(dict_len(model["model"])))
 	return True!

+ 25 - 7
models/petrinet_ports.mvc

@@ -1,6 +1,7 @@
 include "primitives.alh"
 
 SimpleAttribute Natural{
+    name = "Natural"
     constraint = $
         String function constraint(model : Element, name : String):
             if (is_physical_int(model["model"][name])):
@@ -11,6 +12,7 @@ SimpleAttribute Natural{
 }
 
 SimpleAttribute String{
+    name = "String"
     constraint = $
         String function constraint(model : Element, name : String):
             if (is_physical_string(model["model"][name])):
@@ -20,18 +22,34 @@ SimpleAttribute String{
         $
 }
 
-SimpleAttribute Boolean {}
+SimpleAttribute Boolean {
+    name = "Boolean"
+}
 
 Class Named {
+    name = "Named"
     name : String
 }
 Class Place : Named {
+    name = "Place"
     tokens : Natural
 }
-Class Transition : Named {}
-Class Port : Named {}
+Class Transition : Named {
+    name = "Transition"
+}
+Class Port : Named {
+    name = "Port"
+}
 
-Association P2T (Place, Transition) {}
-Association T2P (Transition, Place) {}
-Association PortPlace (Port, Place) {}
-Association Related (Port, Port) {}
+Association P2T (Place, Transition) {
+    name = "P2T"
+}
+Association T2P (Transition, Place) {
+    name = "T2P"
+}
+Association PortPlace (Port, Place) {
+    name = "PortPlace"
+}
+Association Related (Port, Port) {
+    name = "Related"
+}

+ 4 - 0
models/petrinets.mvc

@@ -2,15 +2,19 @@ SimpleAttribute Natural {}
 SimpleAttribute String {}
 
 Class Place {
+    name = "Place"
     tokens : Natural
     name : String
 }
 Class Transition {
+    name = "Transition"
     name : String
 }
 Association P2T (Place, Transition) {
+    name = "P2T"
     weight : Natural
 }
 Association T2P (Transition, Place) {
+    name = "T2P"
     weight : Natural
 }

+ 26 - 8
models/plant_PW.mvc

@@ -1,17 +1,35 @@
-SimpleAttribute TriState {}
-SimpleAttribute String {}
-SimpleAttribute Boolean {}
+SimpleAttribute TriState {
+    name = "TriState"
+}
+SimpleAttribute String {
+    name = "String"
+}
+SimpleAttribute Boolean {
+    name = "Boolean"
+}
 
 Class State {
+    name = "State"
     name : String
     isInitial : Boolean
 }
-Class ErrorState : State {}
-Class NormalState : State {}
+Class ErrorState : State {
+    name = "ErrorState"
+}
+Class NormalState : State {
+    name = "NormalState"
+}
 
 Association Transition (State, State) {
+    name = "Transition"
     objPresent : TriState
 }
-Association OnUp : Transition (State, State) {}
-Association OnDown : Transition (State, State) {}
-Association OnNeutral : Transition (State, State) {}
+Association OnUp : Transition (State, State) {
+    name = "OnUp"
+}
+Association OnDown : Transition (State, State) {
+    name = "OnDown"
+}
+Association OnNeutral : Transition (State, State) {
+    name = "OnNeutral"
+}

+ 3 - 3
models/pn_print.alc

@@ -17,7 +17,7 @@ Boolean function pn_print(model : Element):
 		name = read_attribute(model, place, "name")
 		tokens = read_attribute(model, place, "tokens")
 
-		log((("  " + name) + ": ") + cast_v2s(tokens))
+		log("  " + name + ": " + cast_string(tokens))
 
 	log("Transitions:")
 	all_places = allInstances(model, "PetriNet/Transition")
@@ -30,11 +30,11 @@ Boolean function pn_print(model : Element):
 		all_t = allIncomingAssociationInstances(model, place, "PetriNet/P2T")
 		while (set_len(all_t) > 0):
 			t = set_pop(all_t)
-			log("    <-- " + cast_v2s(read_attribute(model, readAssociationSource(model, t), "name")))
+			log("    <-- " + cast_value(read_attribute(model, readAssociationSource(model, t), "name")))
 
 		all_t = allOutgoingAssociationInstances(model, place, "PetriNet/T2P")
 		while (set_len(all_t) > 0):
 			t = set_pop(all_t)
-			log("    --> " + cast_v2s(read_attribute(model, readAssociationDestination(model, t), "name")))
+			log("    --> " + cast_value(read_attribute(model, readAssociationDestination(model, t), "name")))
 
 	return True!

+ 7 - 2
models/query.mvc

@@ -2,10 +2,15 @@ include "primitives.alh"
 include "object_operations.alh"
 include "modelling.alh"
 
-SimpleAttribute String {}
-SimpleAttribute Natural {}
+SimpleAttribute String {
+    name = "String"
+}
+SimpleAttribute Natural {
+    name = "Natural"
+}
 
 Class Place {
+    name = "Place"
     name : String
     tokens : Natural
     lower_cardinality = 1

+ 6 - 6
models/reachability.alc

@@ -77,8 +77,8 @@ Boolean function reachability_graph(model : Element):
 	set_add(workset, state_id)
 
 	// And add in the model itself
-	state = instantiate_node(model, "ReachabilityGraph/InitialState", cast_i2s(state_id))
-	instantiate_attribute(model, state, "name", cast_i2s(state_id))
+	state = instantiate_node(model, "ReachabilityGraph/InitialState", cast_string(state_id))
+	instantiate_attribute(model, state, "name", cast_string(state_id))
 	instantiate_attribute(model, state, "error", False)
 	keys = dict_keys(dict_repr)
 	while (set_len(keys) > 0):
@@ -148,8 +148,8 @@ Boolean function reachability_graph(model : Element):
 					set_add(workset, target_id)
 
 					// And add in the model itself
-					state = instantiate_node(model, "ReachabilityGraph/State", cast_i2s(target_id))
-					instantiate_attribute(model, state, "name", cast_i2s(target_id))
+					state = instantiate_node(model, "ReachabilityGraph/State", cast_string(target_id))
+					instantiate_attribute(model, state, "name", cast_string(target_id))
 					instantiate_attribute(model, state, "error", False)
 
 					keys = dict_keys(new_dict_repr)
@@ -174,8 +174,8 @@ Boolean function reachability_graph(model : Element):
 				dict_add_fast(mappings[state_id], transition, target_id)
 
 				// And also store it in the model itself
-				new_transition = instantiate_link(model, "ReachabilityGraph/Transition", "", cast_i2s(state_id), cast_i2s(target_id))
+				new_transition = instantiate_link(model, "ReachabilityGraph/Transition", "", cast_string(state_id), cast_string(target_id))
 				instantiate_attribute(model, new_transition, "name", read_attribute(model, transition, "name"))
 
-	log("# reachable states: " + cast_v2s(next_id))
+	log("# reachable states: " + cast_value(next_id))
 	return True!

+ 16 - 4
models/reachability_graph.mvc

@@ -2,27 +2,39 @@ include "primitives.alh"
 include "object_operations.alh"
 include "modelling.alh"
 
-SimpleAttribute String {}
-SimpleAttribute Natural {}
-SimpleAttribute Boolean {}
+SimpleAttribute String {
+    name = "String"
+}
+SimpleAttribute Natural {
+    name = "Natural"
+}
+SimpleAttribute Boolean {
+    name = "Boolean"
+}
 
 Class State {
+    name = "State"
     name : String
     error : Boolean
 }
 Class InitialState : State {
+    name = "InitialState"
     lower_cardinality = 1
     upper_cardinality = 1
 }
 
 Class Place {
+    name = "Place"
     name : String
     tokens : Natural
 }
 Association Transition (State, State) {
+    name = "Transition"
     name : String
 }
-Association Contains (State, Place) {}
+Association Contains (State, Place) {
+    name = "Contains"
+}
 
 GlobalConstraint {
     global_constraint = $

+ 2 - 2
models/reachabilitygraph_print.mvc

@@ -24,7 +24,7 @@ Composite schedule {
                         while (set_len(all_values) > 0):
                             place = set_pop(all_values)
                             dict_add(dict_values, read_attribute(model, place, "name"), read_attribute(model, place, "tokens"))
-                        output((cast_v2s(read_attribute(model, name, "name")) + ": ") + dict_to_string(dict_values))
+                        output(cast_string(read_attribute(model, name, "name")) + ": " + dict_to_string(dict_values))
                         return!
                     $
             }
@@ -54,7 +54,7 @@ Composite schedule {
                 label = "2"
                 action = $
                     Void function action(model : Element, name : String, mapping : Element):
-                        output((((cast_v2s(read_attribute(model, mapping["0"], "name")) + " --[") + cast_v2s(read_attribute(model, name, "name"))) + "]--> ") + cast_v2s(read_attribute(model, mapping["1"], "name")))
+                        output(cast_string(read_attribute(model, mapping["0"], "name")) + " --[" + cast_string(read_attribute(model, name, "name")) + "]--> " + cast_string(read_attribute(model, mapping["1"], "name")))
                         return!
                     $
             }

+ 213 - 0
models/render_OD.alc

@@ -0,0 +1,213 @@
+include "primitives.alh"
+include "modelling.alh"
+include "object_operations.alh"
+
+Boolean function main(model : Element):
+	Element elements
+	String class
+	Element attrs
+	Element attr_keys
+	String attr_key
+	String group
+	String elem
+	Integer loc_x
+	Integer loc_y
+	Integer text_loc
+	loc_x = 10
+	loc_y = 10
+
+	Element to_remove
+	String elem_to_remove
+	Element groups
+	Element class_types
+	Element metamodel
+	metamodel = model["metamodel"]
+	String class_type
+
+	// Construct our own kind of tracability
+	Element cs_to_as
+	Element as_to_cs
+	String asid
+	cs_to_as = dict_create()
+	as_to_cs = dict_create()
+	groups = allInstances(model, "rendered/Group")
+	while (set_len(groups) > 0):
+		group = set_pop(groups)
+		asid = read_attribute(model, group, "__asid")
+		dict_add(cs_to_as, group, "abstract/" + asid)
+		dict_add(as_to_cs, "abstract/" + asid, group)
+
+	// Now render everything
+	groups = dict_create()
+	class_types = allInstances(metamodel, "Class")
+	while (set_len(class_types) > 0):
+		class_type = set_pop(class_types)
+
+		if (string_startswith(class_type, "abstract/")):
+			elements = allInstances(model, class_type)
+
+			while (set_len(elements) > 0):
+				class = set_pop(elements)
+
+				if (is_edge(model["model"][class])):
+					continue!
+				
+				Integer x
+				Integer y
+				x = loc_x
+				y = loc_y
+
+				// Check if there is already an associated element
+				if (dict_in(as_to_cs, class)):
+					// Yes, but is it still clean?
+					Element related_groups
+					group = as_to_cs[class]
+
+					if (bool_not(read_attribute(model, group, "dirty"))):
+						dict_add(groups, class, group)
+						continue!
+					else:
+						group = as_to_cs[class]
+						to_remove = allAssociationDestinations(model, group, "rendered/contains")
+						x = create_value(read_attribute(model, group, "x"))
+						y = create_value(read_attribute(model, group, "y"))
+
+						while (set_len(to_remove) > 0):
+							elem_to_remove = set_pop(to_remove)
+							if (read_type(model, elem_to_remove) == "rendered/Group"):
+								set_add(to_remove, elem_to_remove)
+							else:
+								model_delete_element(model, elem_to_remove)
+						model_delete_element(model, group)
+						dict_delete(as_to_cs, class)
+
+				if (dict_in(groups, class)):
+					// Already rendered this, so skip
+					continue!
+
+				text_loc = 5
+
+				group = instantiate_node(model, "rendered/Group", "")
+				instantiate_attribute(model, group, "x", x)
+				instantiate_attribute(model, group, "y", y)
+				instantiate_attribute(model, group, "__asid", list_read(string_split(class, "/"), 1))
+				instantiate_attribute(model, group, "layer", 0)
+				dict_add(groups, class, group)
+
+				loc_x = loc_x + 250
+				if (loc_x > 2000):
+					loc_x = 10
+					loc_y = loc_y + 300
+
+				elem = instantiate_node(model, "rendered/Rectangle", "")
+				instantiate_attribute(model, elem, "x", 0)
+				instantiate_attribute(model, elem, "y", 0)
+				instantiate_attribute(model, elem, "height", 40 + set_len(getAttributes(model, class)) * 20)
+				instantiate_attribute(model, elem, "width", 200)
+				instantiate_attribute(model, elem, "lineWidth", 2) 
+				instantiate_attribute(model, elem, "lineColour", "black")
+				instantiate_attribute(model, elem, "fillColour", "white")
+				instantiate_attribute(model, elem, "layer", 1)
+				instantiate_link(model, "rendered/contains", "", group, elem)
+
+				elem = instantiate_node(model, "rendered/Text", "")
+				instantiate_attribute(model, elem, "x", 5)
+				instantiate_attribute(model, elem, "y", 3)
+				instantiate_attribute(model, elem, "lineWidth", 1)
+				instantiate_attribute(model, elem, "lineColour", "black")
+				instantiate_attribute(model, elem, "text", string_join(cast_value(list_read(string_split(class, "/"), 1)), " : " + cast_value(list_read(string_split(read_type(model, class), "/"), 1))))
+				instantiate_attribute(model, elem, "layer", 2)
+				instantiate_link(model, "rendered/contains", "", group, elem)
+
+				elem = instantiate_node(model, "rendered/Line", "")
+				instantiate_attribute(model, elem, "x", 0)
+				instantiate_attribute(model, elem, "y", 20)
+				instantiate_attribute(model, elem, "targetX", 200)
+				instantiate_attribute(model, elem, "targetY", 20)
+				instantiate_attribute(model, elem, "lineWidth", 1)
+				instantiate_attribute(model, elem, "lineColour", "black")
+				instantiate_attribute(model, elem, "arrow", False)
+				instantiate_attribute(model, elem, "layer", 2)
+				instantiate_link(model, "rendered/contains", "", group, elem)
+
+				attrs = getAttributes(model, class)
+				attr_keys = dict_keys(attrs)
+				while (dict_len(attr_keys) > 0):
+					attr_key = set_pop(attr_keys)
+					elem = instantiate_node(model, "rendered/Text", "")
+					instantiate_attribute(model, elem, "x", 5)
+					instantiate_attribute(model, elem, "y", text_loc + 20)
+					instantiate_attribute(model, elem, "lineWidth", 1)
+					instantiate_attribute(model, elem, "lineColour", "black")
+					instantiate_attribute(model, elem, "text", (attr_key + " = ") + cast_value(attrs[attr_key]))
+					instantiate_attribute(model, elem, "layer", 2)
+					instantiate_link(model, "rendered/contains", "", group, elem)
+					text_loc = text_loc + 15
+
+	// Flush all associations
+	elements = allInstances(model, "rendered/ConnectingLine")
+	while (set_len(elements) > 0):
+		class = set_pop(elements)
+		model_delete_element(model, class)
+
+	// Rerender associations
+	Element to_render
+	to_render = set_create()
+	class_types = allInstances(metamodel, "Association")
+	while (set_len(class_types) > 0):
+		class_type = set_pop(class_types)
+		log("Checking type " + class_type)
+
+		if (string_startswith(class_type, "abstract/")):
+			elements = allInstances(model, class_type)
+			log("    Checking instance " + class)
+			while (set_len(elements) > 0):
+				class = set_pop(elements)
+				if (is_edge(model["model"][class])):
+					if (bool_not(set_in(to_render, class))):
+						set_add(to_render, class)
+						log("Added!")
+
+	to_render = set_to_list(to_render)
+	Element delayed_elements
+	Integer num_to_render
+	delayed_elements = list_create()
+	while (list_len(to_render) > 0):
+		num_to_render = list_len(to_render)
+		while (list_len(to_render) > 0):
+			class = list_pop_final(to_render)
+			attr_keys = dict_keys(getAttributes(model, class))
+
+			if (bool_not(bool_and(dict_in(groups, readAssociationSource(model, class)), dict_in(groups, readAssociationDestination(model, class))))):
+				list_append(delayed_elements, class)
+				continue!
+
+			elem = instantiate_link(model, "rendered/ConnectingLine", "", groups[readAssociationSource(model, class)], groups[readAssociationDestination(model, class)])
+			dict_add(groups, class, elem)
+			if (is_edge(model["model"][readAssociationSource(model, class)])):
+				instantiate_attribute(model, elem, "offsetSourceX", 0)
+				instantiate_attribute(model, elem, "offsetSourceY", 0)
+			else:
+				instantiate_attribute(model, elem, "offsetSourceX", 100)
+				instantiate_attribute(model, elem, "offsetSourceY", 30)
+			if (is_edge(model["model"][readAssociationDestination(model, class)])):
+				instantiate_attribute(model, elem, "offsetTargetX", 0)
+				instantiate_attribute(model, elem, "offsetTargetY", 0)
+			else:
+				instantiate_attribute(model, elem, "offsetTargetX", 100)
+				instantiate_attribute(model, elem, "offsetTargetY", 30)
+			instantiate_attribute(model, elem, "lineWidth", 3)
+			instantiate_attribute(model, elem, "lineColour", "black")
+			instantiate_attribute(model, elem, "arrow", True)
+			instantiate_attribute(model, elem, "__asid", list_read(string_split(class, "/"), 1))
+			instantiate_attribute(model, elem, "layer", 0)
+			instantiate_link(model, "rendered/contains", "", group, elem)
+
+		if (num_to_render == list_len(delayed_elements)):
+			log("Could not decrease number of rendered elements anymore... Giving up!")
+			return True!
+		else:
+			to_render = delayed_elements
+			delayed_elements = list_create()
+
+	return True!

+ 182 - 0
models/render_SCD.alc

@@ -0,0 +1,182 @@
+include "primitives.alh"
+include "modelling.alh"
+include "object_operations.alh"
+
+Boolean function main(model : Element):
+	Element elements
+	String class
+	Element attrs
+	Element attr_keys
+	String attr_key
+	String group
+	String elem
+	Integer loc
+	Integer text_loc
+	Element related_groups
+	loc = 10
+
+	Element groups
+	groups = dict_create()
+
+	elements = allInstances(model, "rendered/Group")
+	while (set_len(elements) > 0):
+		group = set_pop(elements)
+		if (set_len(allIncomingAssociationInstances(model, group, "TracabilityClass")) == 0):
+			Element to_remove
+			String elem_to_remove
+			to_remove = allAssociationDestinations(model, group, "rendered/contains")
+			while (set_len(to_remove) > 0):
+				elem_to_remove = set_pop(to_remove)
+				if (read_type(model, elem_to_remove) == "rendered/Group"):
+					set_add(to_remove, elem_to_remove)
+				else:
+					model_delete_element(model, elem_to_remove)
+			model_delete_element(model, group)
+
+	elements = allInstances(model, "abstract/Class")
+	while (set_len(elements) > 0):
+		class = set_pop(elements)
+		
+		Integer x
+		Integer y
+		x = loc
+		y = 10
+
+		// Check if there is already an associated element
+		if (set_len(allOutgoingAssociationInstances(model, class, "TracabilityClass")) > 0):
+			// Yes, but is it still clean?
+			Boolean dirty
+			dirty = False
+
+			related_groups = allAssociationDestinations(model, class, "TracabilityClass")
+			while (set_len(related_groups) > 0):
+				group = set_pop(related_groups)
+				if (value_eq(read_attribute(model, group, "dirty"), True)):
+					// No, so mark all as dirty
+					dirty = True
+					break!
+				else:
+					// Yes, so just ignore this!
+					continue!
+
+			if (bool_not(dirty)):
+				dict_add(groups, class, group)
+				continue!
+			else:
+				related_groups = allAssociationDestinations(model, class, "TracabilityClass")
+				Element to_remove
+				String elem_to_remove
+				while (set_len(related_groups) > 0):
+					group = set_pop(related_groups)
+					to_remove = allAssociationDestinations(model, group, "rendered/contains")
+					x = create_value(read_attribute(model, group, "x"))
+					y = create_value(read_attribute(model, group, "y"))
+					while (set_len(to_remove) > 0):
+						elem_to_remove = set_pop(to_remove)
+						if (read_type(model, elem_to_remove) == "rendered/Group"):
+							set_add(to_remove, elem_to_remove)
+						else:
+							model_delete_element(model, elem_to_remove)
+					model_delete_element(model, group)
+
+		attr_keys = dict_keys(getAttributeList(model, class))
+		text_loc = 5
+
+		group = instantiate_node(model, "rendered/Group", "")
+		instantiate_attribute(model, group, "x", x)
+		instantiate_attribute(model, group, "y", y)
+		instantiate_attribute(model, group, "__asid", list_read(string_split(class, "/"), 1))
+		instantiate_attribute(model, group, "layer", 0)
+		dict_add(groups, class, group)
+		loc = loc + 200
+
+		elem = instantiate_node(model, "rendered/Rectangle", "")
+		instantiate_attribute(model, elem, "x", 0)
+		instantiate_attribute(model, elem, "y", 0)
+		instantiate_attribute(model, elem, "height", 40 + set_len(getInstantiatableAttributes(model, class, "abstract/AttributeLink")) * 20)
+		instantiate_attribute(model, elem, "width", 150)
+		instantiate_attribute(model, elem, "lineWidth", 2) 
+		instantiate_attribute(model, elem, "lineColour", "black")
+		instantiate_attribute(model, elem, "fillColour", "white")
+		instantiate_attribute(model, elem, "layer", 1)
+		instantiate_link(model, "rendered/contains", "", group, elem)
+
+		String multiplicities
+		String lower_card
+		String upper_card
+		if (element_eq(read_attribute(model, class, "lower_cardinality"), read_root())):
+			lower_card = "*"
+		else:
+			lower_card = cast_value(read_attribute(model, class, "lower_cardinality"))
+		if (element_eq(read_attribute(model, class, "upper_cardinality"), read_root())):
+			upper_card = "*"
+		else:
+			upper_card = cast_value(read_attribute(model, class, "upper_cardinality"))
+		multiplicities = ((("[" + lower_card) + "..") + upper_card) + "]"
+
+		elem = instantiate_node(model, "rendered/Text", "")
+		instantiate_attribute(model, elem, "x", 5)
+		instantiate_attribute(model, elem, "y", 3)
+		instantiate_attribute(model, elem, "lineWidth", 1)
+		instantiate_attribute(model, elem, "lineColour", "black")
+		if (element_neq(read_attribute(model, class, "name"), read_root())):
+			instantiate_attribute(model, elem, "text", string_join(read_attribute(model, class, "name"), "  " + multiplicities))
+		else:
+			instantiate_attribute(model, elem, "text", "(unnamed) " + multiplicities)
+		instantiate_attribute(model, elem, "layer", 2)
+		instantiate_link(model, "rendered/contains", "", group, elem)
+
+		elem = instantiate_node(model, "rendered/Line", "")
+		instantiate_attribute(model, elem, "x", 0)
+		instantiate_attribute(model, elem, "y", 20)
+		instantiate_attribute(model, elem, "targetX", 150)
+		instantiate_attribute(model, elem, "targetY", 20)
+		instantiate_attribute(model, elem, "lineWidth", 1)
+		instantiate_attribute(model, elem, "lineColour", "black")
+		instantiate_attribute(model, elem, "arrow", False)
+		instantiate_attribute(model, elem, "layer", 2)
+		instantiate_link(model, "rendered/contains", "", group, elem)
+
+		attrs = getInstantiatableAttributes(model, class, "abstract/AttributeLink")
+		attr_keys = dict_keys(attrs)
+		while (dict_len(attr_keys) > 0):
+			attr_key = set_pop(attr_keys)
+			elem = instantiate_node(model, "rendered/Text", "")
+			instantiate_attribute(model, elem, "x", 5)
+			instantiate_attribute(model, elem, "y", text_loc + 20)
+			instantiate_attribute(model, elem, "lineWidth", 1)
+			instantiate_attribute(model, elem, "lineColour", "black")
+			instantiate_attribute(model, elem, "text", (attr_key + " : ") + cast_string(list_read(string_split(attrs[attr_key], "/"), 1)))
+			instantiate_attribute(model, elem, "layer", 2)
+			instantiate_link(model, "rendered/contains", "", group, elem)
+			text_loc = text_loc + 15
+
+		instantiate_link(model, "TracabilityClass", "", class, group)
+
+	// Flush all associations
+	elements = allInstances(model, "rendered/ConnectingLine")
+	while (set_len(elements) > 0):
+		class = set_pop(elements)
+		model_delete_element(model, class)
+
+	// Rerender associations
+	elements = allInstances(model, "abstract/Association")
+	while (set_len(elements) > 0):
+		class = set_pop(elements)
+
+		attr_keys = dict_keys(getAttributeList(model, class))
+
+		elem = instantiate_link(model, "rendered/ConnectingLine", "", groups[readAssociationSource(model, class)], groups[readAssociationDestination(model, class)])
+		instantiate_attribute(model, elem, "offsetSourceX", 75)
+		instantiate_attribute(model, elem, "offsetSourceY", 30)
+		instantiate_attribute(model, elem, "offsetTargetX", 75)
+		instantiate_attribute(model, elem, "offsetTargetY", 30)
+		instantiate_attribute(model, elem, "lineWidth", 1)
+		instantiate_attribute(model, elem, "lineColour", "black")
+		instantiate_attribute(model, elem, "arrow", True)
+		instantiate_attribute(model, elem, "__asid", list_read(string_split(class, "/"), 1))
+		instantiate_attribute(model, elem, "layer", 0)
+		log("Found ASID " + cast_value(list_read(string_split(class, "/"), 1)))
+		instantiate_link(model, "rendered/contains", "", group, elem)
+
+	return True!

+ 2 - 0
models/requirements.mvc

@@ -1,6 +1,7 @@
 include "primitives.alh"
 
 SimpleAttribute String{
+    name = "String"
     constraint = $
         String function constraint_String(model : Element, name : String):
             if (is_physical_string(model["model"][name])):
@@ -11,6 +12,7 @@ SimpleAttribute String{
 }
 
 Class UseCase {
+    name = "UseCase"
     name : String
     scope : String
     level : String

+ 25 - 0
models/test_compiler.alc

@@ -0,0 +1,25 @@
+include "compiler.alh"
+include "primitives.alh"
+
+Void function main(model : Element):
+	String code
+	code = ""
+	code = code + "include \"primitives.alh\"\n"
+	code = code + "Void function test_function():\n"
+	code = code + "    log(\"Function!\")\n"
+	code = code + "    abcd\n"
+	code = code + "    return!"
+
+	log("Got code: ")
+	log(code)
+	
+	Element result
+	result = compile_code(code)
+
+	log("Executing result: " + cast_value(result))
+	if (element_eq(result, read_root())):
+		log("ERROR: compilation error")
+	else:
+		result()
+
+	return!

+ 11 - 3
models/trace.mvc

@@ -1,13 +1,21 @@
-SimpleAttribute String {}
-SimpleAttribute Float {}
+SimpleAttribute String {
+    name = "String"
+}
+SimpleAttribute Float {
+    name = "Float"
+}
 
 Class Signal {
+    name = "Signal"
     name : String
 }
 
 Class Point {
+    name = "Point"
     x : Float
     y : Float
 }
 
-Association contains (Signal, Point) {}
+Association contains (Signal, Point) {
+    name = "contains"
+}

+ 6 - 1
scripts/HUTN_service.py

@@ -4,7 +4,7 @@ import sys
 sys.path.append(COMPILER_PATH)
 sys.path.append("wrappers")
 from hutn_compiler.compiler import main as do_compile
-from modelverse_coded import *
+from modelverse import *
 import os
 
 import time
@@ -26,6 +26,7 @@ def clean_code(code):
     return code
 
 def compile_service(port):
+    print("Start with port " + str(port))
     start = time.time()
     temp_file = ".tmp_%s" % port
 
@@ -59,6 +60,7 @@ def compile_service(port):
 
     mode = service_get(port)
     code = service_get(port)
+    print("Service set: " + str(port))
 
     try:
         if mode == "code":
@@ -76,7 +78,10 @@ def compile_service(port):
         raise
     print("Compile took %ss" % (time.time() - start))
 
+print("Start service")
 service_register("compiler", compile_service)
+print("Service OK")
+
 try:
     while raw_input() != "STOP":
         pass

+ 89 - 0
scripts/JSON_service.py

@@ -0,0 +1,89 @@
+import sys
+sys.path.append("wrappers")
+from modelverse import *
+import os
+import json
+
+import time
+time.sleep(1)
+init(sys.argv[1])
+login("JSON", "JSON")
+
+def json_service(port):
+    def print_out_json(data):
+        if isinstance(data, dict):
+            # Serialize dictionary
+            service_set(port, "D")
+            service_set(port, len(data))
+            for key, value in data.items():
+                service_set(port, key)
+                print_out_json(value)
+        elif isinstance(data, list):
+            # Serialize list
+            service_set(port, "L")
+            service_set(port, len(data))
+            for value in data:
+                print_out_json(value)
+        elif data is None:
+            service_set(port, "N")
+        else:
+            # Is a primitive value (normally), so send as-is
+            service_set(port, "P")
+            service_set(port, data)
+
+    def fetch_data():
+        data = service_get(port)
+        if data == "D":
+            rval = {}
+            length = service_get(port)
+            for _ in range(length):
+                key = service_get(port)
+                rval[key] = fetch_data()
+        elif data == "L":
+            rval = []
+            length = service_get(port)
+            for _ in range(length):
+                rval.append(fetch_data())
+        elif data == "P":
+            rval = service_get(port)
+        elif data == "N":
+            rval = None
+        else:
+            raise Exception("Unknown data type: " + data)
+        return rval
+
+    start = time.time()
+
+    mode = service_get(port)
+    try:
+        if mode == "decode":
+            service_set(port, "OK")
+            json_str = service_get(port)
+            json_data = json.loads(json_str)
+            print_out_json(json_data)
+
+        elif mode == "encode":
+            service_set(port, "OK")
+            json_data = fetch_data()
+            json_str = json.dumps(json_data)
+            service_set(port, json_str)
+            
+        else:
+            raise Exception("No such mode: " + mode)
+
+    except Exception as e:
+        service_set(port, str(e))
+        raise
+    print("JSON took %ss" % (time.time() - start))
+
+service_register("JSON", json_service)
+
+try:
+    while raw_input() != "STOP":
+        pass
+except EOFError:
+    import time
+    while 1:
+        time.sleep(1.0)
+finally:
+    service_stop()

+ 5 - 0
scripts/run_local_modelverse.py

@@ -11,6 +11,7 @@ else:
 # Start up the HUTN compilation service already
 try:
     hutn = subprocess.Popen([sys.executable, "scripts/HUTN_service.py", "127.0.0.1:%s" % port])
+    json = subprocess.Popen([sys.executable, "scripts/JSON_service.py", "127.0.0.1:%s" % port])
 
     os.chdir("hybrid_server")
     subprocess.check_call([sys.executable, "-m", "sccd.compiler.sccdc", "-p", "threads", "server.xml"])
@@ -33,3 +34,7 @@ finally:
         hutn.terminate()
     except:
         pass
+    try:
+        json.terminate()
+    except:
+        pass

+ 1 - 1
state/modelverse_state/main.py

@@ -13,7 +13,7 @@ if sys.version > '3': # pragma: no cover
 else: # pragma: no cover
     integer_types = (int, long)
     primitive_types = (int, long, float, str, bool, unicode)
-complex_primitives = frozenset(["if", "while", "assign", "call", "break", "continue", "return","resolve","access", "constant", "input", "output", "declare", "global"])
+complex_primitives = frozenset(["if", "while", "assign", "call", "break", "continue", "return","resolve","access", "constant", "input", "output", "declare", "global", "none"])
 
 def instance_to_string(value):
     return value["value"]

+ 12 - 13
unit/test_all.py

@@ -145,6 +145,7 @@ class TestModelverse(unittest.TestCase):
 
         # Create something in the formalism
         instantiate("test/Empty", "Class", ID="A")
+        attr_assign("test/Empty", "A", "name", "A")
         assert verify("test/Empty", "formalisms/SimpleClassDiagrams") == "OK"
 
         # Now instantiate that in the model as well, which now works
@@ -274,8 +275,8 @@ class TestModelverse(unittest.TestCase):
         process_execute("test/pn_reachability", "", {"test/refine_PN": callback_refine_PN, "test/reachability_print": (ctrl, "inp", "outp")})
         thrd.join()
 
-        assert set(log) == set(['"0": {"p1": 1, }',
-                                '"1": {"p1": 0, }',
+        assert set(log) == set(['"0": {"p1": 1}',
+                                '"1": {"p1": 0}',
                                 '"0" --["t1"]--> "1"'])
 
         model_delete("RAMified")
@@ -292,7 +293,7 @@ class TestModelverse(unittest.TestCase):
             instantiate(None, "Association", ("abstract/Block", "rendered/Group"), ID="TracabilityLink", context=context)
 
         transformation_add_MT({"abstract": "test/CausalBlockDiagrams", "rendered": "test/MM_rendered_graphical"}, {"abstract": "test/CausalBlockDiagrams", "rendered": "test/MM_rendered_graphical"}, "test/render_graphical_CBD", open("models/CBD_mapper.mvc", 'r').read(), add_tracability)
-        result = model_render("test/my_CBD", "test/render_graphical_CBD")
+        result = model_render("test/my_CBD", "test/render_graphical_CBD", "test/my_perceptualized_CBD")
 
         assert len(result) == 23
 
@@ -300,9 +301,7 @@ class TestModelverse(unittest.TestCase):
         model_delete("merged")
         model_delete("type mappings/RAMified")
         model_delete("type mappings/merged")
-        model_delete("rendered")
         model_delete("tracability")
-        model_delete("type mappings/rendered")
         model_delete("type mappings/tracability")
 
     def test_SCCD_basic(self):
@@ -379,16 +378,16 @@ class TestModelverse(unittest.TestCase):
         
         got = element_list_nice("test/PetriNet")
         expected = \
-            [{'id': 'Natural', 'type': 'SimpleAttribute', 'constraint': None},
-             {'id': 'String', 'type': 'SimpleAttribute', 'constraint': None},
-             {'id': 'Place', 'type': 'Class', 'lower_cardinality': None, 'upper_cardinality': None, 'constraint': None},
+            [{'id': 'Natural', 'type': 'SimpleAttribute', 'constraint': None, 'name': 'Natural'},
+             {'id': 'String', 'type': 'SimpleAttribute', 'constraint': None, 'name': 'String'},
+             {'id': 'Place', 'type': 'Class', 'lower_cardinality': None, 'upper_cardinality': None, 'constraint': None, 'name': 'Place'},
              {'id': 'Place_tokens', 'type': 'AttributeLink', '__source': 'Place', '__target': 'Natural', 'name': 'tokens', 'optional': False, 'constraint': None},
              {'id': 'Place_name', 'type': 'AttributeLink', '__source': 'Place', '__target': 'String', 'name': 'name', 'optional': False, 'constraint': None},
-             {'id': 'Transition', 'type': 'Class', 'lower_cardinality': None, 'upper_cardinality': None, 'constraint': None},
+             {'id': 'Transition', 'type': 'Class', 'lower_cardinality': None, 'upper_cardinality': None, 'constraint': None, 'name': 'Transition'},
              {'id': 'Transition_name', 'type': 'AttributeLink', '__source': 'Transition', '__target': 'String', 'name': 'name', 'optional': False, 'constraint': None},
-             {'id': 'P2T', 'type': 'Association', '__source': 'Place', '__target': 'Transition', 'source_lower_cardinality': None, 'target_lower_cardinality': None, 'source_upper_cardinality': None, 'target_upper_cardinality': None, 'constraint': None},
+             {'id': 'P2T', 'type': 'Association', '__source': 'Place', '__target': 'Transition', 'source_lower_cardinality': None, 'target_lower_cardinality': None, 'source_upper_cardinality': None, 'target_upper_cardinality': None, 'constraint': None, 'name': 'P2T'},
              {'id': 'P2T_weight', 'type': 'AttributeLink', '__source': 'P2T', '__target': 'Natural', 'name': 'weight', 'optional': False, 'constraint': None},
-             {'id': 'T2P', 'type': 'Association', '__source': 'Transition', '__target': 'Place', 'source_lower_cardinality': None, 'target_lower_cardinality': None, 'source_upper_cardinality': None, 'target_upper_cardinality': None, 'constraint': None},
+             {'id': 'T2P', 'type': 'Association', '__source': 'Transition', '__target': 'Place', 'source_lower_cardinality': None, 'target_lower_cardinality': None, 'source_upper_cardinality': None, 'target_upper_cardinality': None, 'constraint': None, 'name': 'T2P'},
              {'id': 'T2P_weight', 'type': 'AttributeLink', '__source': 'T2P', '__target': 'Natural', 'name': 'weight', 'optional': False, 'constraint': None}
             ]
         compare_unordered_lists(got, expected)
@@ -418,8 +417,8 @@ class TestModelverse(unittest.TestCase):
             else:
                 assert len(entry) == 4
                 count_edges += 1
-        assert count_nodes == 14
-        assert count_edges == 17
+        assert count_nodes == 20
+        assert count_edges == 23
 
         count_nodes = 0
         count_edges = 0

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 436 - 153
wrappers/classes/modelverse.xml


+ 2 - 0
wrappers/compile.sh

@@ -0,0 +1,2 @@
+#!/bin/bash
+python -m sccd.compiler.sccdc -p threads modelverse_SCCD.xml

+ 54 - 9
wrappers/modelverse.py

@@ -65,6 +65,8 @@ def OUTPUT():
                 raise UnknownIdentifier()
             elif response.parameters[1] == "UnknownMetamodellingHierarchy":
                 raise UnknownMetamodellingHierarchy()
+            else:
+                raise UnknownError()
 
 def init(address_param="127.0.0.1:8001", timeout=20.0):
     global controller
@@ -84,6 +86,7 @@ def init(address_param="127.0.0.1:8001", timeout=20.0):
     controller.addOutputListener("ready").fetch(-1)
 
     INPUT("init", None, [address_param, timeout])
+    controller.address = address_param
     return OUTPUT()
 
 def login(username, password):
@@ -126,8 +129,8 @@ def user_delete():
     INPUT("user_delete", None, [])
     return OUTPUT()
 
-def model_render(model_name, mapper_name):
-    INPUT("model_render", None, [model_name, mapper_name])
+def model_render(model_name, mapper_name, rendered_name):
+    INPUT("model_render", None, [model_name, mapper_name, rendered_name])
     return OUTPUT()
 
 def transformation_between(source, target):
@@ -145,6 +148,11 @@ def transformation_add_MT(source_metamodels, target_metamodels, operation_name,
 def transformation_add_AL(source_metamodels, target_metamodels, operation_name, code, callback=None):
     INPUT("transformation_add_AL", None, [source_metamodels, target_metamodels, operation_name, code])
     context = OUTPUT()
+
+    if context is None:
+        # In case the source and target metamodels are empty, the context will be None, indicating that we are finished already (no callbacks allowed)
+        return
+
     if callback is not None:
         callback(context)
     INPUT("exit", context, [])
@@ -158,11 +166,11 @@ def transformation_add_MANUAL(source_metamodels, target_metamodels, operation_na
     INPUT("exit", context, [])
     return OUTPUT()
 
-def transformation_execute_MT(operation_name, input_models_dict, output_models_dict, statechart=None):
+def transformation_execute_MT(operation_name, input_models_dict, output_models_dict, statechart=None, tracability_model="", fetch_output=True):
     if statechart is not None:
         port_sc = statechart[0].addOutputListener(statechart[2])
 
-    INPUT("transformation_execute_MT", None, [operation_name, input_models_dict, output_models_dict])
+    INPUT("transformation_execute_MT", None, [operation_name, input_models_dict, output_models_dict, tracability_model, fetch_output])
     context = OUTPUT()
     if statechart is not None:
         while 1:
@@ -192,11 +200,10 @@ def transformation_execute_MT(operation_name, input_models_dict, output_models_d
     else:
         return OUTPUT()
 
-def transformation_execute_AL(operation_name, input_models_dict, output_models_dict, statechart=None):
+def transformation_execute_AL(operation_name, input_models_dict, output_models_dict, statechart=None, tracability_model="", fetch_output=True):
     if statechart is not None:
         port_sc = statechart[0].addOutputListener(statechart[2])
-
-    INPUT("transformation_execute_AL", None, [operation_name, input_models_dict, output_models_dict])
+    INPUT("transformation_execute_AL", None, [operation_name, input_models_dict, output_models_dict, tracability_model, fetch_output])
 
     context = OUTPUT()
     if statechart is not None:
@@ -227,8 +234,8 @@ def transformation_execute_AL(operation_name, input_models_dict, output_models_d
     else:
         return OUTPUT()
 
-def transformation_execute_MANUAL(operation_name, input_models_dict, output_models_dict, callback=None):
-    INPUT("transformation_execute_MANUAL", None, [operation_name, input_models_dict, output_models_dict])
+def transformation_execute_MANUAL(operation_name, input_models_dict, output_models_dict, callback=None, tracability_model=""):
+    INPUT("transformation_execute_MANUAL", None, [operation_name, input_models_dict, output_models_dict, tracability_model])
     context = OUTPUT()
     if callback is not None:
         callback(context)
@@ -434,3 +441,41 @@ def process_execute(process_name, prefix, callbacks=None):
             if operation == "Finished":
                 # Finished execution of the process, so exit
                 return None
+
+def get_taskname():
+    """Fetch the taskname of the current connection."""
+    return controller.taskname
+
+""" Some hardcoded functions... Way easier to express them with code than with statecharts!"""
+import json
+import urllib
+import urllib2
+
+def service_register(name, function):
+    """Register a function as a service with a specific name."""
+    INPUT("service_register", None, [name, function])
+    port = OUTPUT()
+    return port
+
+def service_stop():
+    """Stop the currently executing process."""
+    INPUT("service_stop", None, [])
+    return OUTPUT()
+
+def service_get(port):
+    """Get the values on the specified port."""
+    val = json.loads(urllib2.urlopen(urllib2.Request("http://%s" % controller.address, urllib.urlencode({"op": "get_output", "taskname": port}))).read())
+    return val
+
+def service_set(port, value):
+    """Set a value on a specified port."""
+    if isinstance(value, type([])):
+        value = json.dumps(value)
+        urllib2.urlopen(urllib2.Request("http://%s" % controller.address, urllib.urlencode({"op": "set_input", "data": value, "taskname": port}))).read()
+    else:
+        value = json.dumps(value)
+        urllib2.urlopen(urllib2.Request("http://%s" % controller.address, urllib.urlencode({"op": "set_input", "value": value, "taskname": port}))).read()
+
+def service_poll(port):
+    """Checks whether or not the Modelverse side has any input ready to be processed."""
+    raise NotImplementedError()

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 843 - 413
wrappers/modelverse_SCCD.py


+ 10 - 68
wrappers/test.py

@@ -1,73 +1,15 @@
 from modelverse import *
 import random
 
-def print_mv_with_input(value):
-    if value.startswith("#"):
-        print_mv(value[1:])
-        return
-    if value.startswith("%"):
-        if (value[1:] == "construct_function"):
-            print("Enter your code...")
-            code = \
-                """
-                include "primitives.alh"
-
-                Boolean function bp_1():
-                    log("Breakpoint check!")
-                    return True!
-                """
-            upload_code(code)
-        return
-    print(value)
-    return raw_input()
-
-def print_mv(value):
-    print(value)
-    return None
-
-print("Init")
 init()
-print("Login")
-#login(str(random.random()), str(random.random()))
 login("admin", "admin")
-
-# Add the metamodels for PetriNet and ReachabilityGraph
-print("Add metamodels")
-try:
-    model_add("formalisms/PetriNet", "formalisms/SimpleClassDiagrams", open("models/petrinets.mvc").read())
-except ModelExists:
-    pass
-
-try:
-    model_add("formalisms/ReachabilityGraph", "formalisms/SimpleClassDiagrams", open("models/reachability_graph.mvc").read())
-except ModelExists:
-    pass
-
-print("Add model")
-try:
-    model_add("models/my_pn", "formalisms/PetriNet", open("models/my_pn.mvc").read())
-except ModelExists:
-    pass
-
-# Add the action language code to transform between them
-print("Add AL model")
-try:
-    transformation_add_AL({"PetriNet": "formalisms/PetriNet"}, {"ReachabilityGraph": "formalisms/ReachabilityGraph"}, "models/analyseReachability", open("models/reachability.alc", "r").read())
-except ModelExists:
-    pass
-
-# Add an example model transformation to print the reachability graph
-print("Add MT model")
-try:
-    transformation_add_MT({"ReachabilityGraph": "formalisms/ReachabilityGraph"}, {}, "models/printReachability", open("models/reachabilitygraph_print.mvc").read())
-except ModelExists:
-    pass
-
-# Do the reachability graph generation
-print("Execute AL")
-status = transformation_execute_AL("models/analyseReachability", {"PetriNet": "models/my_pn"}, {"ReachabilityGraph": "models/my_reachability"}, callback=print_mv)
-print("Reachability generation success: " + str(status))
-
-print("Execute MT")
-status = transformation_execute_MT("models/printReachability", {"ReachabilityGraph": "models/my_reachability"}, {}, callback=print_mv)
-print("Reachability printing success: " + str(status))
+model_add("formalisms/PetriNet", "formalisms/SimpleClassDiagrams", open("models/petrinets.mvc").read())
+model_add("formalisms/ReachabilityGraph", "formalisms/SimpleClassDiagrams", open("models/reachability_graph.mvc").read())
+model_add("models/my_pn", "formalisms/PetriNet", open("models/my_pn.mvc").read())
+transformation_add_AL({"PetriNet": "formalisms/PetriNet"}, {"ReachabilityGraph": "formalisms/ReachabilityGraph"}, "models/analyseReachability", open("models/reachability.alc", "r").read())
+transformation_add_MT({"ReachabilityGraph": "formalisms/ReachabilityGraph"}, {}, "models/printReachability", open("models/reachabilitygraph_print.mvc").read())
+transformation_execute_AL("models/analyseReachability", {"PetriNet": "models/my_pn"}, {"ReachabilityGraph": "models/my_reachability"}, tracability_model="trac")
+transformation_execute_MT("models/printReachability", {"ReachabilityGraph": "models/my_reachability"}, {})
+
+time.sleep(5)
+print(model_list(""))

+ 3 - 3
wrappers/test_modelverse.py

@@ -43,9 +43,9 @@ transformation_add_AL({"B": "MetamodelB", "C": "MetamodelC"}, {"B": "MetamodelB"
     include "modelling.alh"
 
     Boolean function size_of_model(model : Element):
-        log("Number of instances of A: " + cast_v2s(set_len(allInstances(model, "A/A"))))
-        log("Number of instances of B: " + cast_v2s(set_len(allInstances(model, "B/B"))))
-        log("Number of instances of C: " + cast_v2s(set_len(allInstances(model, "C/C"))))
+        log("Number of instances of A: " + cast_value(set_len(allInstances(model, "A/A"))))
+        log("Number of instances of B: " + cast_value(set_len(allInstances(model, "B/B"))))
+        log("Number of instances of C: " + cast_value(set_len(allInstances(model, "C/C"))))
         return True!
     """
     )