Browse Source

Merge remote-tracking branch 'upstream/master' into jit

jonathanvdc 8 years ago
parent
commit
f3e2ea263b
51 changed files with 2483 additions and 330 deletions
  1. 1 0
      .gitignore
  2. BIN
      bootstrap/bootstrap.m.gz
  3. 0 16
      bootstrap/conformance_scd.alc
  4. 0 1
      bootstrap/constructors.alc
  5. 54 0
      bootstrap/ftg.alc
  6. 7 4
      bootstrap/library.alc
  7. 165 134
      bootstrap/metamodels.alc
  8. 135 0
      bootstrap/model_management.alc
  9. 111 23
      bootstrap/modelling.alc
  10. 65 11
      bootstrap/object_operations.alc
  11. 126 0
      bootstrap/primitives.alc
  12. 281 0
      bootstrap/ramify.alc
  13. 0 1
      bootstrap/random.alc
  14. 446 0
      bootstrap/transform.alc
  15. 0 1
      bootstrap/user_manager.alc
  16. 0 1
      hybrid_server/classes/mvkcontroller.xml
  17. 12 0
      integration/code/ftg.mvc
  18. 8 0
      integration/code/graph.mvc
  19. 18 0
      integration/code/pn_design.mvc
  20. 25 0
      integration/code/pn_design_model.mvc
  21. 186 0
      integration/code/pn_design_to_runtime.mvc
  22. 146 19
      integration/code/pn_interface.alc
  23. 31 0
      integration/code/pn_print.mvc
  24. 23 0
      integration/code/pn_runtime.mvc
  25. 27 0
      integration/code/pn_runtime_model.mvc
  26. 174 0
      integration/code/pn_simulate.mvc
  27. 103 0
      integration/code/ramified_petrinets.mvc
  28. 0 3
      integration/test_constructors_models.py
  29. 2 2
      integration/test_factorial.py
  30. 184 59
      integration/test_pn_interface.py
  31. 24 2
      integration/utils.py
  32. 7 3
      interface/HUTN/grammars/modelling.g
  33. 2 2
      interface/HUTN/hutn_compiler/grammar_compiler_visitor.py
  34. 61 25
      interface/HUTN/hutn_compiler/model_visitor.py
  35. 2 0
      interface/HUTN/hutn_compiler/primitives_visitor.py
  36. 1 0
      interface/HUTN/includes/ftg.alh
  37. 2 0
      interface/HUTN/includes/metamodels.alh
  38. 3 0
      interface/HUTN/includes/model_management.alh
  39. 4 1
      interface/HUTN/includes/modelling.alh
  40. 2 0
      interface/HUTN/includes/object_operations.alh
  41. 9 0
      interface/HUTN/includes/primitives.alh
  42. 1 0
      interface/HUTN/includes/ramify.alh
  43. 1 0
      interface/HUTN/includes/transform.alh
  44. 1 1
      interface/HUTN/test/modelling_language/expected/my_petrinet
  45. 1 1
      interface/HUTN/test/modelling_language/expected/my_petrinet_with_MM
  46. 1 1
      interface/HUTN/test/modelling_language/expected/petrinets
  47. 1 1
      interface/HUTN/test/modelling_language/expected/petrinets_constraints
  48. 1 1
      interface/HUTN/test/modelling_language/expected/simpleclassdiagrams
  49. 27 15
      kernel/modelverse_kernel/compiled.py
  50. 1 1
      scripts/compile.py
  51. 1 1
      state/modelverse_state/main.py

+ 1 - 0
.gitignore

@@ -3,6 +3,7 @@
 *.dot
 .cache
 *.swp
+*.swo
 __pycache__
 hybrid_server/server.py
 perf_data.txt

BIN
bootstrap/bootstrap.m.gz


+ 0 - 16
bootstrap/conformance_scd.alc

@@ -4,21 +4,6 @@ include "object_operations.alh"
 include "constructors.alh"
 include "modelling.alh"
 
-Element function set_copy(a : Element):
-	Element b
-	Integer i
-	Integer count
-
-	b = create_node()
-	i = 0
-	count = read_nr_out(a)
-
-	while (i < count):
-		set_add(b, read_edge_dst(read_out(a, i)))
-		i = i + 1
-
-	return b!
-
 Boolean function is_direct_instance(model : Element, instance : String, type : String):
 	// Just check whether or not the type mapping specifies the type as the type of the instance
 	return element_eq(dict_read_node(model["type_mapping"], model["model"][instance]), model["metamodel"]["model"][type])!
@@ -127,7 +112,6 @@ String function conformance_scd(model : Element):
 			model_name = set_pop(keys)
 			element = model["model"][model_name]
 			type_name = reverseKeyLookup(metamodel["model"], dict_read_node(typing, element))
-			log((("Check " + model_name) + " : ") + type_name)
 
 			if (bool_not(dict_in_node(typing, element))):
 				return "Model has no type specified: " + model_info(model, model_name)!

+ 0 - 1
bootstrap/constructors.alc

@@ -148,7 +148,6 @@ Action function construct_unknown():
 		return construct_continue()!
 	elif (elem == "model"):
 		construct_model()
-		log("Constructed model")
 		return construct_unknown()!
 	else:
 		log("ERROR: did not understand command " + cast_e2s(elem))

+ 54 - 0
bootstrap/ftg.alc

@@ -0,0 +1,54 @@
+include "primitives.alh"
+include "modelling.alh"
+include "library.alh"
+
+Void function visit_ftg(ftg : Element, root : Element, path : String, current : Element):
+	log("Visit FTG: " + path)
+	if (dict_in(current, "source")):
+		// Is a transformation, and therefore an edge for the FTG
+		if (bool_not(dict_in(ftg["model"], path))):
+			if (bool_not(dict_in(ftg["model"], current["source"]))):
+				visit_ftg(ftg, root, current["source"], root[current["source"]])
+
+			if (bool_not(dict_in(ftg["model"], current["target"]))):
+				visit_ftg(ftg, root, current["target"], root[current["source"]])
+
+			instantiate_link(ftg, "Transformation", path, current["source"], current["target"])
+			instantiate_attribute(ftg, path, "location", path)
+	else:
+		// Is a model, and therefore a node for the FTG
+		if (bool_not(dict_in(ftg["model"], path))):
+			instantiate_node(ftg, "Formalism", path)
+			instantiate_attribute(ftg, path, "location", path)
+
+	return !
+
+Element function create_ftg(root : Element):
+	Element queue
+	Element current
+	Element submodels
+	Element ftg
+	String path
+	String submodel
+
+	queue = create_node()
+	set_add(queue, create_tuple("models", root))
+	ftg = instantiate_model(import_node("models/FTG"))
+
+	while (read_nr_out(queue) > 0):
+		current = set_pop(queue)
+		path = current[0]
+		current = current[1]
+		log("Check node: " + cast_e2s(current))
+		if (dict_in(current, "__hierarchy_node" )):
+			log("IS HIERARCHY: " + path)
+			submodels = dict_keys(current)
+			// Is a browser structure, and therefore not part of the FTG
+			while (read_nr_out(submodels) > 0):
+				submodel = set_pop(submodels)
+				set_add(queue, create_tuple((path + "/") + submodel, current[submodel]))
+		else:
+			log("IS MODEL: " + path)
+			visit_ftg(ftg, root, path, current)
+
+	return ftg!

+ 7 - 4
bootstrap/library.alc

@@ -10,14 +10,17 @@ Element function export_node(model_name : String, model_reference : Element):
 	Element current
 	current = dict_read(read_root(), "__hierarchy")
 	while(counter_i < length):
-		if (bool_not(dict_in(current, list_read(splitted, counter_i)))):
-			// Create it first
+		if (bool_not(dict_in(current, splitted[counter_i]))):
+			// Create the new node
 			dict_add(current, splitted[counter_i], create_node())
-		current = current[list_read(splitted, counter_i)]
+			dict_add(current[splitted[counter_i]], "__hierarchy_node", create_node())
+
+		// Read out newly created element
+		current = current[splitted[counter_i]]
 		counter_i = counter_i + 1
 	
 	// current now contains the place where we should add the element
-	dict_add(current, list_read(splitted, length), model_reference)
+	dict_add(current, splitted[length], model_reference)
 
 	return model_reference!
 

+ 165 - 134
bootstrap/metamodels.alc

@@ -164,7 +164,6 @@ Element function initialize_SCD(location : String):
 
 	// Retype to a "real" LTM, which happens to be itself
 	retype_model(scd, scd)
-	define_inheritance(scd, "Inheritance")
 	retype(scd, "Class", "Class")
 	retype(scd, "Any", "Class")
 	retype(scd, "String", "Class")
@@ -193,135 +192,7 @@ Element function initialize_SCD(location : String):
 	instantiate_attribute(scd, "tuc", "name", "target_upper_cardinality")
 
 	// Add in the Action Language metamodel
-	instantiate_node(scd, "Class", "Action")
-	instantiate_node(scd, "Class", "Statement")
-	instantiate_node(scd, "Class", "Expression")
-	instantiate_node(scd, "Class", "funcdef")
-	instantiate_node(scd, "Class", "param")
-	instantiate_node(scd, "Class", "if")
-	instantiate_node(scd, "Class", "break")
-	instantiate_node(scd, "Class", "while")
-	instantiate_node(scd, "Class", "continue")
-	instantiate_node(scd, "Class", "assign")
-	instantiate_node(scd, "Class", "return")
-	instantiate_node(scd, "Class", "output")
-	instantiate_node(scd, "Class", "declare")
-	instantiate_node(scd, "Class", "global")
-	instantiate_node(scd, "Class", "access")
-	instantiate_node(scd, "Class", "constant")
-	instantiate_node(scd, "Class", "input")
-	instantiate_node(scd, "Class", "resolve")
-	instantiate_node(scd, "Class", "call")
-	instantiate_link(scd, "Association", "dict_link", "Action", "Any")
-	instantiate_link(scd, "Association", "to_str", "dict_link", "String")
-	instantiate_attribute(scd, "to_str", "name", "name")
-	instantiate_link(scd, "Inheritance", "", "Action", "Any")
-	instantiate_link(scd, "Inheritance", "", "funcdef", "Action")
-	instantiate_link(scd, "Inheritance", "", "param", "Action")
-	instantiate_link(scd, "Inheritance", "", "Statement", "Action")
-	instantiate_link(scd, "Inheritance", "", "Expression", "Action")
-	instantiate_link(scd, "Inheritance", "", "resolve", "Statement")
-	instantiate_link(scd, "Inheritance", "", "if", "Statement")
-	instantiate_link(scd, "Inheritance", "", "break", "Statement")
-	instantiate_link(scd, "Inheritance", "", "continue", "Statement")
-	instantiate_link(scd, "Inheritance", "", "global", "Statement")
-	instantiate_link(scd, "Inheritance", "", "while", "Statement")
-	instantiate_link(scd, "Inheritance", "", "assign", "Statement")
-	instantiate_link(scd, "Inheritance", "", "return", "Statement")
-	instantiate_link(scd, "Inheritance", "", "call", "Statement")
-	instantiate_link(scd, "Inheritance", "", "declare", "Statement")
-	instantiate_link(scd, "Inheritance", "", "call", "Expression")
-	instantiate_link(scd, "Inheritance", "", "access", "Expression")
-	instantiate_link(scd, "Inheritance", "", "constant", "Expression")
-	instantiate_link(scd, "Inheritance", "", "input", "Expression")
-	instantiate_link(scd, "Association", "statement_next", "Statement", "Statement")
-	instantiate_link(scd, "Association", "if_cond", "if", "Expression")
-	instantiate_link(scd, "Association", "if_then", "if", "Statement")
-	instantiate_link(scd, "Association", "if_else", "if", "Statement")
-	instantiate_link(scd, "Association", "while_cond", "while", "Expression")
-	instantiate_link(scd, "Association", "while_body", "while", "Statement")
-	instantiate_link(scd, "Association", "assign_var", "assign", "Any")
-	instantiate_link(scd, "Association", "assign_value", "assign", "Expression")
-	instantiate_link(scd, "Association", "break_while", "break", "while")
-	instantiate_link(scd, "Association", "continue_while", "continue", "while")
-	instantiate_link(scd, "Association", "return_value", "return", "Expression")
-	instantiate_link(scd, "Association", "resolve_var", "resolve", "Any")
-	instantiate_link(scd, "Association", "access_var", "access", "Any")
-	instantiate_link(scd, "Association", "constant_node", "constant", "Any")
-	instantiate_link(scd, "Association", "output_node", "output", "Expression")
-	instantiate_link(scd, "Association", "global_var", "global", "String")
-	instantiate_link(scd, "Association", "param_name", "param", "String")
-	instantiate_link(scd, "Association", "param_value", "param", "Expression")
-	instantiate_link(scd, "Association", "param_next_param", "param", "param")
-	instantiate_link(scd, "Association", "funcdef_body", "funcdef", "Statement")
-	instantiate_link(scd, "Association", "call_func", "call", "Expression")
-	instantiate_link(scd, "Association", "call_params", "call", "param")
-	instantiate_link(scd, "Association", "call_last_param", "call", "param")
-	instantiate_link(scd, "Inheritance", "", "statement_next", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "if_cond", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "if_then", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "if_else", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "while_cond", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "while_body", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "assign_var", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "assign_value", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "break_while", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "continue_while", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "return_value", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "resolve_var", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "access_var", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "constant_node", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "output_node", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "global_var", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "param_name", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "param_value", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "param_next_param", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "funcdef_body", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "call_func", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "call_params", "dict_link")
-	instantiate_link(scd, "Inheritance", "", "call_last_param", "dict_link")
-
-	// Add cardinalities on how many connections are allowed: one of each
-	instantiate_attribute(scd, "statement_next", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "if_cond", "target_lower_cardinality", 1)
-	instantiate_attribute(scd, "if_cond", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "if_then", "target_lower_cardinality", 1)
-	instantiate_attribute(scd, "if_then", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "if_else", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "while_cond", "target_lower_cardinality", 1)
-	instantiate_attribute(scd, "while_cond", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "while_body", "target_lower_cardinality", 1)
-	instantiate_attribute(scd, "while_body", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "assign_var", "target_lower_cardinality", 1)
-	instantiate_attribute(scd, "assign_var", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "assign_value", "target_lower_cardinality", 1)
-	instantiate_attribute(scd, "assign_value", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "break_while", "target_lower_cardinality", 1)
-	instantiate_attribute(scd, "break_while", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "continue_while", "target_lower_cardinality", 1)
-	instantiate_attribute(scd, "continue_while", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "return_value", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "resolve_var", "target_lower_cardinality", 1)
-	instantiate_attribute(scd, "resolve_var", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "access_var", "target_lower_cardinality", 1)
-	instantiate_attribute(scd, "access_var", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "constant_node", "target_lower_cardinality", 1)
-	instantiate_attribute(scd, "constant_node", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "output_node", "target_lower_cardinality", 1)
-	instantiate_attribute(scd, "output_node", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "global_var", "target_lower_cardinality", 1)
-	instantiate_attribute(scd, "global_var", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "param_name", "target_lower_cardinality", 1)
-	instantiate_attribute(scd, "param_name", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "param_value", "target_lower_cardinality", 1)
-	instantiate_attribute(scd, "param_value", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "param_next_param", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "funcdef_body", "target_lower_cardinality", 1)
-	instantiate_attribute(scd, "funcdef_body", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "call_func", "target_lower_cardinality", 1)
-	instantiate_attribute(scd, "call_func", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "call_params", "target_upper_cardinality", 1)
-	instantiate_attribute(scd, "call_last_param", "target_upper_cardinality", 1)
+	add_AL_to_MM(scd)
 
 	// Now still allow for constraints on classes
 	instantiate_link(scd, "Association", "constraint", "Class", "funcdef")
@@ -358,7 +229,6 @@ Element function initialize_PN(location_SCD : String, location_PN : String):
 	scd = import_node(location_SCD)
 
 	pn = instantiate_model(scd)
-	define_inheritance(pn, "Inheritance")
 	instantiate_node(pn, "Class", "Place")
 	instantiate_node(pn, "Class", "Transition")
 	instantiate_node(pn, "Class", "Natural")
@@ -380,12 +250,37 @@ Element function initialize_PN(location_SCD : String, location_PN : String):
 	// Add constraint on the Natural
 	add_constraint(pn, "Natural", constraint_natural)
 
-	// Add global constraints
-	//set_model_constraints(pn, petrinet_constraints)
 	export_node(location_PN, pn)
 
 	return pn!
 
+Element function initialize_FTG(location_SCD : String, location_FTG : String):
+	Element ftg
+	Element scd
+	String attr
+
+	scd = import_node(location_SCD)
+
+	ftg = instantiate_model(scd)
+	instantiate_node(ftg, "Class", "String")
+
+	instantiate_node(ftg, "Class", "Formalism")
+	attr = model_define_attribute(ftg, "Formalism", "location", "String")
+	instantiate_attribute(ftg, attr, "target_lower_cardinality", 1)
+	instantiate_attribute(ftg, attr, "target_upper_cardinality", 1)
+
+	instantiate_link(ftg, "Association", "Transformation", "Formalism", "Formalism")
+	attr = model_define_attribute(ftg, "Transformation", "location", "String")
+	instantiate_attribute(ftg, attr, "target_lower_cardinality", 1)
+	instantiate_attribute(ftg, attr, "target_upper_cardinality", 1)
+
+	// Add constraint on the String
+	add_constraint(ftg, "String", constraint_string)
+
+	export_node(location_FTG, ftg)
+
+	return ftg!
+
 Element function initialize_bottom(location_bottom : String):
 	Element ltm_bottom
 	ltm_bottom = instantiate_bottom()
@@ -395,7 +290,6 @@ Element function initialize_bottom(location_bottom : String):
 	model_add_edge(ltm_bottom, "__inh", "Edge", "Node")
 
 	retype_model(ltm_bottom, ltm_bottom)
-	define_inheritance(ltm_bottom, "inheritance")
 	retype(ltm_bottom, "Node", "Node")
 	retype(ltm_bottom, "Edge", "Edge")
 	retype(ltm_bottom, "inheritance", "Edge")
@@ -409,16 +303,153 @@ Element function create_metamodels():
 	String location_SCD
 	String location_PN
 	String location_bottom
+	String location_FTG
 
 	location_SCD = "models/SimpleClassDiagrams"
 	location_PN = "models/PetriNets"
 	location_bottom = "models/LTM_bottom"
+	location_FTG = "models/FTG"
 
 	if (bool_not(dict_in(dict_read(dict_read(read_root(), "__hierarchy"), "models"), "SimpleClassDiagrams"))):
 		initialize_SCD(location_SCD)
 	if (bool_not(dict_in(dict_read(dict_read(read_root(), "__hierarchy"), "models"), "PetriNets"))):
 		initialize_PN(location_SCD, location_PN)
+	if (bool_not(dict_in(dict_read(dict_read(read_root(), "__hierarchy"), "models"), "FTG"))):
+		initialize_FTG(location_SCD, location_FTG)
 	if (bool_not(dict_in(dict_read(dict_read(read_root(), "__hierarchy"), "models"), "LTM_bottom"))):
 		initialize_bottom(location_bottom)
 
 	return dict_read(dict_read(read_root(), "__hierarchy"), "models")!
+
+Void function add_AL_to_MM(model : Element):
+	instantiate_node(model, "Class", "Action")
+	instantiate_node(model, "Class", "Statement")
+	instantiate_node(model, "Class", "Expression")
+	instantiate_node(model, "Class", "funcdef")
+	instantiate_node(model, "Class", "param")
+	instantiate_node(model, "Class", "if")
+	instantiate_node(model, "Class", "break")
+	instantiate_node(model, "Class", "while")
+	instantiate_node(model, "Class", "continue")
+	instantiate_node(model, "Class", "assign")
+	instantiate_node(model, "Class", "return")
+	instantiate_node(model, "Class", "output")
+	instantiate_node(model, "Class", "declare")
+	instantiate_node(model, "Class", "global")
+	instantiate_node(model, "Class", "access")
+	instantiate_node(model, "Class", "constant")
+	instantiate_node(model, "Class", "input")
+	instantiate_node(model, "Class", "resolve")
+	instantiate_node(model, "Class", "call")
+	instantiate_link(model, "Association", "dict_link", "Action", "Any")
+	instantiate_link(model, "Association", "to_str", "dict_link", "String")
+	instantiate_attribute(model, "to_str", "name", "name")
+	instantiate_link(model, "Inheritance", "", "Action", "Any")
+	instantiate_link(model, "Inheritance", "", "funcdef", "Action")
+	instantiate_link(model, "Inheritance", "", "param", "Action")
+	instantiate_link(model, "Inheritance", "", "Statement", "Action")
+	instantiate_link(model, "Inheritance", "", "Expression", "Action")
+	instantiate_link(model, "Inheritance", "", "resolve", "Statement")
+	instantiate_link(model, "Inheritance", "", "if", "Statement")
+	instantiate_link(model, "Inheritance", "", "break", "Statement")
+	instantiate_link(model, "Inheritance", "", "continue", "Statement")
+	instantiate_link(model, "Inheritance", "", "global", "Statement")
+	instantiate_link(model, "Inheritance", "", "while", "Statement")
+	instantiate_link(model, "Inheritance", "", "assign", "Statement")
+	instantiate_link(model, "Inheritance", "", "return", "Statement")
+	instantiate_link(model, "Inheritance", "", "call", "Statement")
+	instantiate_link(model, "Inheritance", "", "declare", "Statement")
+	instantiate_link(model, "Inheritance", "", "call", "Expression")
+	instantiate_link(model, "Inheritance", "", "access", "Expression")
+	instantiate_link(model, "Inheritance", "", "constant", "Expression")
+	instantiate_link(model, "Inheritance", "", "input", "Expression")
+	instantiate_link(model, "Association", "statement_next", "Statement", "Statement")
+	instantiate_link(model, "Association", "if_cond", "if", "Expression")
+	instantiate_link(model, "Association", "if_then", "if", "Statement")
+	instantiate_link(model, "Association", "if_else", "if", "Statement")
+	instantiate_link(model, "Association", "while_cond", "while", "Expression")
+	instantiate_link(model, "Association", "while_body", "while", "Statement")
+	instantiate_link(model, "Association", "assign_var", "assign", "Any")
+	instantiate_link(model, "Association", "assign_value", "assign", "Expression")
+	instantiate_link(model, "Association", "break_while", "break", "while")
+	instantiate_link(model, "Association", "continue_while", "continue", "while")
+	instantiate_link(model, "Association", "return_value", "return", "Expression")
+	instantiate_link(model, "Association", "resolve_var", "resolve", "Any")
+	instantiate_link(model, "Association", "access_var", "access", "Any")
+	instantiate_link(model, "Association", "constant_node", "constant", "Any")
+	instantiate_link(model, "Association", "output_node", "output", "Expression")
+	instantiate_link(model, "Association", "global_var", "global", "String")
+	instantiate_link(model, "Association", "param_name", "param", "String")
+	instantiate_link(model, "Association", "param_value", "param", "Expression")
+	instantiate_link(model, "Association", "param_next_param", "param", "param")
+	instantiate_link(model, "Association", "funcdef_body", "funcdef", "Statement")
+	instantiate_link(model, "Association", "call_func", "call", "Expression")
+	instantiate_link(model, "Association", "call_params", "call", "param")
+	instantiate_link(model, "Association", "call_last_param", "call", "param")
+	instantiate_link(model, "Inheritance", "", "statement_next", "dict_link")
+	instantiate_link(model, "Inheritance", "", "if_cond", "dict_link")
+	instantiate_link(model, "Inheritance", "", "if_then", "dict_link")
+	instantiate_link(model, "Inheritance", "", "if_else", "dict_link")
+	instantiate_link(model, "Inheritance", "", "while_cond", "dict_link")
+	instantiate_link(model, "Inheritance", "", "while_body", "dict_link")
+	instantiate_link(model, "Inheritance", "", "assign_var", "dict_link")
+	instantiate_link(model, "Inheritance", "", "assign_value", "dict_link")
+	instantiate_link(model, "Inheritance", "", "break_while", "dict_link")
+	instantiate_link(model, "Inheritance", "", "continue_while", "dict_link")
+	instantiate_link(model, "Inheritance", "", "return_value", "dict_link")
+	instantiate_link(model, "Inheritance", "", "resolve_var", "dict_link")
+	instantiate_link(model, "Inheritance", "", "access_var", "dict_link")
+	instantiate_link(model, "Inheritance", "", "constant_node", "dict_link")
+	instantiate_link(model, "Inheritance", "", "output_node", "dict_link")
+	instantiate_link(model, "Inheritance", "", "global_var", "dict_link")
+	instantiate_link(model, "Inheritance", "", "param_name", "dict_link")
+	instantiate_link(model, "Inheritance", "", "param_value", "dict_link")
+	instantiate_link(model, "Inheritance", "", "param_next_param", "dict_link")
+	instantiate_link(model, "Inheritance", "", "funcdef_body", "dict_link")
+	instantiate_link(model, "Inheritance", "", "call_func", "dict_link")
+	instantiate_link(model, "Inheritance", "", "call_params", "dict_link")
+	instantiate_link(model, "Inheritance", "", "call_last_param", "dict_link")
+
+	// Add cardinalities on how many connections are allowed: one of each
+	instantiate_attribute(model, "statement_next", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "if_cond", "target_lower_cardinality", 1)
+	instantiate_attribute(model, "if_cond", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "if_then", "target_lower_cardinality", 1)
+	instantiate_attribute(model, "if_then", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "if_else", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "while_cond", "target_lower_cardinality", 1)
+	instantiate_attribute(model, "while_cond", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "while_body", "target_lower_cardinality", 1)
+	instantiate_attribute(model, "while_body", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "assign_var", "target_lower_cardinality", 1)
+	instantiate_attribute(model, "assign_var", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "assign_value", "target_lower_cardinality", 1)
+	instantiate_attribute(model, "assign_value", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "break_while", "target_lower_cardinality", 1)
+	instantiate_attribute(model, "break_while", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "continue_while", "target_lower_cardinality", 1)
+	instantiate_attribute(model, "continue_while", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "return_value", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "resolve_var", "target_lower_cardinality", 1)
+	instantiate_attribute(model, "resolve_var", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "access_var", "target_lower_cardinality", 1)
+	instantiate_attribute(model, "access_var", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "constant_node", "target_lower_cardinality", 1)
+	instantiate_attribute(model, "constant_node", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "output_node", "target_lower_cardinality", 1)
+	instantiate_attribute(model, "output_node", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "global_var", "target_lower_cardinality", 1)
+	instantiate_attribute(model, "global_var", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "param_name", "target_lower_cardinality", 1)
+	instantiate_attribute(model, "param_name", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "param_value", "target_lower_cardinality", 1)
+	instantiate_attribute(model, "param_value", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "param_next_param", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "funcdef_body", "target_lower_cardinality", 1)
+	instantiate_attribute(model, "funcdef_body", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "call_func", "target_lower_cardinality", 1)
+	instantiate_attribute(model, "call_func", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "call_params", "target_upper_cardinality", 1)
+	instantiate_attribute(model, "call_last_param", "target_upper_cardinality", 1)
+
+	return !

+ 135 - 0
bootstrap/model_management.alc

@@ -0,0 +1,135 @@
+include "primitives.alh"
+include "io.alh"
+include "object_operations.alh"
+include "constructors.alh"
+include "metamodels.alh"
+include "library.alh"
+include "modelling.alh"
+
+Element function model_fuse(name1 : String, model1 : Element, name2 : String, model2 : Element):
+	Element new_model
+	Element tagged_model
+	String model_name
+	Element model
+	Element keys
+	String key
+	Element selected_MM
+	String type
+	Element models
+
+	// Read out some data first
+	selected_MM = model1["metamodel"]
+	new_model = instantiate_model(selected_MM)
+
+	// Create a list to nicely iterate over it
+	models = create_node()
+	tagged_model = create_node()
+	list_append(tagged_model, name1)
+	list_append(tagged_model, model1)
+	list_append(models, tagged_model)
+	tagged_model = create_node()
+	list_append(tagged_model, name2)
+	list_append(tagged_model, model2)
+	list_append(models, tagged_model)
+
+	// Do the iteration
+	while (read_nr_out(models)):
+		tagged_model = set_pop(models)
+		model_name = list_read(tagged_model, 0)
+		model = list_read(tagged_model, 1)
+
+		// Add all elements from 'model', but prepend it with the 'model_name'
+		keys = set_to_list(dict_keys(model["model"]))
+		while (read_nr_out(keys) > 0):
+			key = list_pop(keys, 0)
+			type = reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][key]))
+
+			if (is_edge(model["model"][key])):
+				String src
+				String dst
+				src = model_name + reverseKeyLookup(model["model"], read_edge_src(model["model"][key]))
+				dst = model_name + reverseKeyLookup(model["model"], 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:
+					list_append(keys, key)
+			elif (has_value(model["model"][key])):
+				instantiate_value(new_model, type, model_name + key, model["model"][key])
+			else:
+				instantiate_node(new_model, type, model_name + key)
+
+	return new_model!
+
+Element function model_copy(src_model : Element):
+	Element dst_model
+	Element queue
+	Element name
+	String type
+
+	dst_model = instantiate_model(src_model["metamodel"])
+	dict_add(dst_model, "model", create_node())
+	dict_add(dst_model, "type_mapping", create_node())
+
+	queue = set_to_list(dict_keys(src_model["model"]))
+
+	while (read_nr_out(queue) > 0):
+		name = list_pop(queue, 0)
+
+		if (is_edge(src_model["model"][name])):
+			// Is an edge, so potentially queue it
+			String src
+			String dst
+
+			src = reverseKeyLookup(src_model["model"], read_edge_src(src_model["model"][name]))
+			dst = reverseKeyLookup(src_model["model"], read_edge_dst(src_model["model"][name]))
+			type = reverseKeyLookup(src_model["metamodel"]["model"], dict_read_node(src_model["type_mapping"], src_model["model"][name]))
+
+			if (bool_and(dict_in(dst_model["model"], src), dict_in(dst_model["model"], dst))):
+				// All present, so create the link between them
+				instantiate_link(dst_model, type, name, src, dst)
+			else:
+				list_append(queue, name)
+
+		elif (has_value(src_model["model"][name])):
+			// Has a value, so copy that as well
+			type = reverseKeyLookup(src_model["metamodel"]["model"], dict_read_node(src_model["type_mapping"], src_model["model"][name]))
+			instantiate_value(dst_model, type, name, src_model["model"][name])
+
+		else:
+			// Is a node
+			type = reverseKeyLookup(src_model["metamodel"]["model"], dict_read_node(src_model["type_mapping"], src_model["model"][name]))
+			instantiate_node(dst_model, type, name)
+
+	return dst_model!
+
+Element function model_retype_on_name(model : Element, new_MM : Element, operation : String, name : String):
+	String key
+	String type
+	Element keys
+	Integer length
+
+	keys = dict_keys(model["model"])
+	length = string_len(name)
+
+	while (read_nr_out(keys) > 0):
+		key = set_pop(keys)
+		if (dict_in(model["model"], key)):
+			// Check if the element is still there, as a delete of a node might remove all attached links automatically
+			type = reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][key]))
+
+			if (operation == "+"):
+				// Keep all, but augment typename
+				dict_delete_node(model["type_mapping"], model["model"][key])
+				dict_add(model["type_mapping"], model["model"][key], new_MM["model"][name + type])
+			elif (operation == "-"):
+				// Keep only if typename beginning matches and remove from typename
+				if (string_startswith(type, name)):
+					dict_delete_node(model["type_mapping"], model["model"][key])
+					dict_add(model["type_mapping"], model["model"][key], new_MM["model"][string_substr(type, length, string_len(type))])
+				else:
+					model_delete_element(model, key)
+
+	dict_delete(model, "metamodel")
+	dict_add(model, "metamodel", new_MM)
+
+	return model!

+ 111 - 23
bootstrap/modelling.alc

@@ -24,6 +24,7 @@ Element function instantiate_bottom():
 	// Add an empty model and empty type mapping
 	dict_add(new_model, "model", create_node())
 	dict_add(new_model, "type_mapping", create_node())
+	dict_add(new_model, "__kind", "formalism")
 
 	// Return the created model
 	return new_model!
@@ -106,6 +107,16 @@ String function instantiate_node(model : Element, type_name : String, instance_n
 
 	return actual_name!
 
+String function instantiate_value(model : Element, type_name : String, instance_name : String, value : Element):
+	// Create a node typed by a node from the metamodel
+	// Basically create a node and type it immediately
+	String actual_name
+
+	actual_name = model_add_value(model, instance_name, value)
+	retype(model, actual_name, type_name)
+
+	return actual_name!
+
 String function find_attribute_type(model : Element, elem : String, name : String):
 	String mm_elem
 	String direct_type
@@ -127,37 +138,50 @@ Element function get_superclasses(model : Element, name : String):
 	Element edge
 	Element elem
 	Element nodes
+	Element inheritance
 
 	nodes = create_node()
 	set_add(nodes, model["model"][name])
+	inheritance = model["metamodel"]["model"]["Inheritance"]
 
 	// Initialize empty set
 	result = create_node()
 	i = 0
 
-	while (0 < list_len(nodes)):
+	while (list_len(nodes) > 0):
 		elem = set_pop(nodes)
-		create_edge(result, reverseKeyLookup(model["model"], elem))
-		// Read out all outgoing edges
-		num_edges = read_nr_out(elem)
-		j = 0
-		while (j < num_edges):
-			edge = read_out(elem, j)
-			if (element_eq(dict_read_node(model["type_mapping"], edge), model["inheritance"])):
-				set_add(nodes, read_edge_dst(edge))
-			j = j + 1
+		if (bool_not(set_in(result, reverseKeyLookup(model["model"], elem)))):
+			create_edge(result, reverseKeyLookup(model["model"], elem))
+			// Read out all outgoing edges
+			num_edges = read_nr_out(elem)
+			j = 0
+			while (j < num_edges):
+				edge = read_out(elem, j)
+				if (element_eq(dict_read_node(model["type_mapping"], edge), inheritance)):
+					set_add(nodes, read_edge_dst(edge))
+				j = j + 1
 
 	return result!
 
 String function find_attribute_definer(model : Element, elem_name : String, name : String):
 	Element superclasses
-	Element current
+	String current
+	Integer nr_out
+	Element out
+	String name_attr
 
 	superclasses = get_superclasses(model, elem_name)
 	while (list_len(superclasses) > 0):
 		current = set_pop(superclasses)
-		if (dict_in(model["model"][current], name)):
-			return current!
+		
+		nr_out = read_nr_out(model["model"][current])
+		while (nr_out > 0):
+			nr_out = nr_out - 1
+			out = read_out(model["model"][current], nr_out)
+			name_attr = read_attribute(model, reverseKeyLookup(model["model"], out), "name")
+			if (name_attr == name):
+				return current!
+
 	return ""!
 
 Void function instantiate_attribute(model : Element, element : String, attribute_name : String, value : Element):
@@ -181,20 +205,72 @@ Void function instantiate_attribute(model : Element, element : String, attribute
 
 	return!
 
+Void function instantiate_attribute_ref(model : Element, element : String, attribute_name : String, ref : String):
+	// Instantiate an attribute of something that needs to be instantiated
+	// Actually a bit more difficult than all the rest, as we need to find the attribute to instantiate
+	String attr_type
+	String attr_name
+
+	attr_type = find_attribute_type(model, element, attribute_name)
+
+	if (attr_type == ""):
+		log("Could not find attribute " + cast_v2s(attribute_name))
+		return!
+		
+	instantiate_link(model, attr_type, "", element, ref)
+
+	return!
+
+Void function instantiate_attribute_code(model : Element, element : String, attribute_name : String, code : Element):
+	String ref
+	ref = add_AL(model, code)
+	instantiate_existing_attribute(model, element, attribute_name, ref)
+
+	return!
+
+Void function instantiate_existing_attribute(model : Element, element : String, attribute_name : String, attr_ref : String):
+	// Instantiate an attribute of something that needs to be instantiated
+	// Actually a bit more difficult than all the rest, as we need to find the attribute to instantiate
+	String attr_type
+	String attr_name
+
+	attr_type = find_attribute_type(model, element, attribute_name)
+
+	if (attr_type == ""):
+		log("Could not find attribute " + cast_v2s(attribute_name))
+		return!
+		
+	// Make a copy of the value, as it is likely that this value is reused later on
+	retype(model, attr_ref, reverseKeyLookup(model["metamodel"]["model"], read_edge_dst(model["metamodel"]["model"][attr_type])))
+	instantiate_link(model, attr_type, "", element, attr_ref)
+
+	return!
+
 String function instantiate_link(model : Element, type : String, name : String, source : String, destination : String):
 	// Create a typed link between two nodes
 	String actual_name
 
 	actual_name = model_add_edge(model, name, source, destination)
-	retype(model, actual_name, type)
 
-	return actual_name!
+	if (type == ""):
+		// Have to find the type ourselves, as it isn't defined
+		Element out
+		Element in
+		Element options
 
-Void function define_inheritance(model : Element, inheritance_name : String):
-	// Set the inheritance link to the one defined in our own metamodel, given by the specified name
-	dict_add(model, "inheritance", model["metamodel"]["model"][inheritance_name])
+		options = allowedAssociationsBetween(model, source, destination)
 
-	return!
+		if (read_nr_out(options) == 1):
+			type = set_pop(options)
+		elif (read_nr_out(options) == 0):
+			log("ERROR: cannot find possible link between entries")
+			return ""!
+		else:
+			log("ERROR: too many possible links between entries")
+			return ""!
+	
+	retype(model, actual_name, type)
+	return actual_name!
 
 Void function model_delete_element(model : Element, name : String):
 	// Remove the link
@@ -206,6 +282,15 @@ Void function model_delete_element(model : Element, name : String):
 
 	return!
 
+String function model_define_attribute(model : Element, elem : String, name : String, type : String):
+	// Create the necessary links to make it an attribute
+	String edge_name
+
+	edge_name = instantiate_link(model, "Association", "", elem, type)
+	instantiate_attribute(model, edge_name, "name", name)
+
+	return edge_name!
+
 Element function read_attribute(model : Element, element : String, attribute : String):
 	Integer i
 	Integer count
@@ -395,10 +480,12 @@ Void function construct_model():
 			instantiate_node(global_models[input()], input(), input())
 		elif (command == "instantiate_attribute"):
 			instantiate_attribute(global_models[input()], input(), input(), input())
+		elif (command == "instantiate_attribute_ref"):
+			instantiate_attribute_ref(global_models[input()], input(), input(), input())
+		elif (command == "instantiate_attribute_code"):
+			instantiate_attribute_code(global_models[input()], input(), input(), construct_function())
 		elif (command == "instantiate_link"):
 			instantiate_link(global_models[input()], input(), input(), input(), input())
-		elif (command == "define_inheritance"):
-			define_inheritance(global_models[input()], input())
 		elif (command == "add_constraint"):
 			add_constraint(global_models[input()], input(), construct_function())
 		elif (command == "initialize_SCD"):
@@ -413,9 +500,10 @@ Void function construct_model():
 			export_node(location, global_models[local_name])
 		elif (command == "import_node"):
 			Element m
-			m = import_node(input())
+			command = input()
+			m = import_node(command)
 			if (element_eq(m, read_root())):
-				log("Error: import not found")
+				log("Error: import not found for " + command)
 			else:
 				dict_add(global_models, input(), m)
 		else:

+ 65 - 11
bootstrap/object_operations.alc

@@ -124,18 +124,25 @@ Element function getAttributeList(model : Element, element : String):
 Element function getInstantiatableAttributes(model : Element, element : String):
 	Element result
 	result = create_node()
-	// Get all outgoing "dictionary" links
-	Element set_own
-	Element elem
-	elem = model["model"][element]
-	set_own = dict_keys(element)
 
-	// Filter them
-	Element e
-	while (0 < read_nr_out(set_own)):
-		e = set_pop(set_own)
-		if (is_physical_string(e)):
-			dict_add(result, e, reverseKeyLookup(model["model"], element[e]))
+	Element types
+	types = get_superclasses(model, element)
+
+	while (read_nr_out(types) > 0):
+		element = set_pop(types)
+
+		// Get all outgoing "dictionary" links
+		Element set_own
+		Element elem
+		elem = model["model"][element]
+		set_own = dict_keys(elem)
+
+		// Filter them
+		Element e
+		while (0 < read_nr_out(set_own)):
+			e = set_pop(set_own)
+			if (is_physical_string(e)):
+				dict_add(result, e, reverseKeyLookup(model["model"], elem[e]))
 
 	return result!
 
@@ -183,3 +190,50 @@ String function followAssociation(model : Element, element_name : String, associ
 		set_add(result, readAssociationDestination(model, set_pop(assocs)))
 
 	return result!
+
+Element function allAssociationDestinations(model : Element, name : String, association_type : String):
+	Element tmp
+	Element result
+
+	result = create_node()
+	tmp = allOutgoingAssociationInstances(model, name, association_type)
+
+	while (read_nr_out(tmp) > 0):
+		set_add(result, readAssociationDestination(model, set_pop(tmp)))
+
+	return result!
+
+Element function allowedAssociationsBetween(model : Element, src : String, dst : String):
+	// Go to the type and find all possibilities
+	String type
+	Element all_types
+	Integer nr_edges
+	Integer i
+	Element result
+	Element edge
+	String edge_name
+	String dst_name
+
+	result = create_node()
+	type = reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], model["model"][src]))
+	all_types = get_superclasses(model["metamodel"], type)
+
+	while (read_nr_out(all_types) > 0):
+		type = set_pop(all_types)
+		nr_edges = read_nr_out(model["metamodel"]["model"][type])
+		i = 0
+		while (i < nr_edges):
+			edge = read_out(model["metamodel"]["model"][type], i)
+
+			if (set_in(model["metamodel"]["model"], edge)):
+				// Find destination
+				dst_name = reverseKeyLookup(model["metamodel"]["model"], read_edge_dst(edge))
+				edge_name = reverseKeyLookup(model["metamodel"]["model"], edge)
+
+				if (is_nominal_instance(model, dst, dst_name)):
+					// Find out whether our dst is an instance of the found destination type
+					set_add(result, edge_name)
+
+			i = i + 1
+
+	return result!

+ 126 - 0
bootstrap/primitives.alc

@@ -173,3 +173,129 @@ Integer function integer_modulo(a : Integer, b : Integer):
 
 Boolean function has_input():
 	return (element_neq(dict_read(read_userroot(), "input"), dict_read(read_userroot(),"last_input")))!
+
+Element function list_pop(lst : Element, index : Integer):
+	Element v
+	v = list_read(lst, index)
+	list_delete(lst, index)
+	return v!
+
+Element function set_copy(a : Element):
+	Element b
+	Integer i
+	Integer count
+
+	b = create_node()
+	i = 0
+	count = read_nr_out(a)
+
+	while (i < count):
+		set_add(b, read_edge_dst(read_out(a, i)))
+		i = i + 1
+
+	return b!
+
+String function set_to_string(s : Element):
+	String result
+	Integer i
+
+	result = "{"
+	i = 0
+	while (i < read_nr_out(s)):
+		result = result + cast_v2s(read_edge_dst(read_out(s, i)))
+		result = result + ", "
+		i = i + 1
+	
+	result = result + "}"
+
+	return result!
+
+String function list_to_string(s : Element):
+	String result
+	Integer i
+
+	result = "["
+	i = 0
+	while (i < read_nr_out(s)):
+		result = result + cast_v2s(dict_read(s, i))
+		result = result + ", "
+		i = i + 1
+	
+	result = result + "]"
+
+	return result!
+
+Element function create_tuple(a : Element, b : Element):
+	Element tuple
+
+	tuple = create_node()
+	list_append(tuple, a)
+	list_append(tuple, b)
+
+	return tuple!
+
+String function dict_to_string(d : Element):
+	String result
+	Element keys
+	Element key
+
+	result = "{"
+	keys = dict_keys(d)
+
+	while (read_nr_out(keys)):
+		key = set_pop(keys)
+		result = result + cast_v2s(key)
+		result = result + ": "
+		result = result + cast_v2s(dict_read_node(d, key))
+		result = result + ", "
+	
+	result = result + "}"
+
+	return result!
+
+Element function set_overlap(sa : Element, sb : Element):
+	Element result
+	Integer i
+
+	if (read_nr_out(sa) > read_nr_out(sb)):
+		// Pick the smallest set to iterate over, so switch if sa is not the smallest
+		result = sa
+		sa = sb
+		sb = result
+
+	result = create_node()
+	i = 0
+
+	// Iterate over each element of sa and only add it to the result if it is also in sb
+	while (i < read_nr_out(sa)):
+		if (set_in(sb, read_edge_dst(read_out(sa, i)))):
+			// Shared between both
+			set_add(result, read_edge_dst(read_out(sa, i)))
+		i = i + 1
+
+	return result!
+
+Element function dict_copy(d : Element):
+	String result
+	Element keys
+	Element key
+
+	result = create_node()
+	keys = dict_keys(d)
+
+	while (read_nr_out(keys)):
+		key = set_pop(keys)
+		dict_add(result, key, dict_read_node(d, key))
+
+	return result!
+
+Element function set_to_list(s : Element):
+	Element result
+	Element tmp
+
+	result = create_node()
+	tmp = set_copy(s)
+	while (read_nr_out(tmp) > 0):
+		list_append(result, set_pop(tmp))
+
+	return result!

+ 281 - 0
bootstrap/ramify.alc

@@ -0,0 +1,281 @@
+include "primitives.alh"
+include "object_operations.alh"
+include "modelling.alh"
+include "metamodels.alh"
+include "model_management.alh"
+
+Element function ramify(model : Element):
+	// Create new model structure
+	Element new_model
+	new_model = create_node()
+	dict_add(new_model, "model", create_node())
+	dict_add(new_model, "type_mapping", create_node())
+	dict_add(new_model, "metamodel", model["metamodel"])
+
+	dict_add(new_model, "source", model)
+	dict_add(new_model, "target", model)
+
+	// Get local variables for parts
+	Element old_m
+	Element new_m
+	Element mm
+	new_m = new_model["model"]
+	old_m = model["model"]
+	mm = new_model["metamodel"]["model"]
+
+	// Add in some primitives
+	instantiate_node(new_model, "Class", "Natural")
+	instantiate_node(new_model, "Class", "String")
+	instantiate_node(new_model, "Class", "Any")
+
+	// Add in the complete AL metamodel
+	add_AL_to_MM(new_model)
+
+	// Add some default elements
+	//	Class LHS_Root {
+	//		constraint : funcdef {
+	//			target_upper_cardinality = 1
+	//		}
+	//		upper_cardinality = 1
+	//		lower_cardinality = 1
+	//	}
+	instantiate_node(new_model, "Class", "LHS_Root")
+	instantiate_attribute(new_model, "LHS_Root", "lower_cardinality", 1)
+	instantiate_attribute(new_model, "LHS_Root", "upper_cardinality", 1)
+	instantiate_link(new_model, "Association", "LHS_constraint", "LHS_Root", "funcdef")
+	instantiate_attribute(new_model, "LHS_constraint", "name", "constraint")
+	instantiate_attribute(new_model, "LHS_constraint", "target_upper_cardinality", 1)
+
+	//  Class LHS : LHS_Root {}
+	instantiate_node(new_model, "Class", "LHS")
+	instantiate_link(new_model, "Inheritance", "", "LHS", "LHS_Root")
+
+	//  Class NAC : LHS_Root {}
+	instantiate_node(new_model, "Class", "NAC")
+	instantiate_link(new_model, "Inheritance", "", "NAC", "LHS_Root")
+
+	//	Class Pre_Element {
+	//		label : String {
+	//			target_lower_cardinality = 1
+	//			target_upper_cardinality = 1
+	//		}
+	//		constraint : funcdef {
+	//			target_upper_cardinality = 1
+	//		}
+	//	}
+	instantiate_node(new_model, "Class", "Pre_Element")
+	instantiate_link(new_model, "Association", "Pre_Element_label", "Pre_Element", "String")
+	instantiate_attribute(new_model, "Pre_Element_label", "name", "label")
+	instantiate_attribute(new_model, "Pre_Element_label", "target_lower_cardinality", 1)
+	instantiate_attribute(new_model, "Pre_Element_label", "target_upper_cardinality", 1)
+	instantiate_link(new_model, "Association", "Pre_Element_constraint", "Pre_Element", "funcdef")
+	instantiate_attribute(new_model, "Pre_Element_constraint", "name", "constraint")
+	instantiate_attribute(new_model, "Pre_Element_constraint", "target_upper_cardinality", 1)
+
+	// Association LHS_contains (LHS_Root, Pre_Element) {}
+	instantiate_link(new_model, "Association", "LHS_contains", "LHS_Root", "Pre_Element")
+	instantiate_attribute(new_model, "LHS_contains", "name", "contains")
+
+	//	Class RHS {
+	//		action : FuncDef {
+	//			target_upper_cardinality = 1
+	//		}
+	//		upper_cardinality = 1
+	//		lower_cardinality = 1
+	//	}
+	instantiate_node(new_model, "Class", "RHS")
+	instantiate_attribute(new_model, "RHS", "lower_cardinality", 1)
+	instantiate_attribute(new_model, "RHS", "upper_cardinality", 1)
+	instantiate_link(new_model, "Association", "RHS_action", "RHS", "funcdef")
+	instantiate_attribute(new_model, "RHS_action", "name", "action")
+	instantiate_attribute(new_model, "RHS_action", "target_upper_cardinality", 1)
+
+	//	Class Post_Element {
+	//		label : String {
+	//			target_lower_cardinality = 1
+	//			target_upper_cardinality = 1
+	//		}
+	//		value : funcdef {
+	//			target_upper_cardinality = 1
+	//		}
+	//		action : funcdef {
+	//			target_upper_cardinality = 1
+	//		}
+	//	}
+	instantiate_node(new_model, "Class", "Post_Element")
+	instantiate_link(new_model, "Association", "Post_Element_label", "Post_Element", "String")
+	instantiate_attribute(new_model, "Post_Element_label", "name", "label")
+	instantiate_attribute(new_model, "Post_Element_label", "target_lower_cardinality", 1)
+	instantiate_attribute(new_model, "Post_Element_label", "target_upper_cardinality", 1)
+	instantiate_link(new_model, "Association", "Post_Element_value", "Post_Element", "funcdef")
+	instantiate_attribute(new_model, "Post_Element_value", "name", "value")
+	instantiate_attribute(new_model, "Post_Element_value", "target_upper_cardinality", 1)
+	instantiate_link(new_model, "Association", "Post_Element_action", "Post_Element", "funcdef")
+	instantiate_attribute(new_model, "Post_Element_action", "name", "action")
+	instantiate_attribute(new_model, "Post_Element_action", "target_upper_cardinality", 1)
+
+	// Association RHS_contains (RHS, Post_Element) {}
+	instantiate_link(new_model, "Association", "RHS_contains", "RHS", "Post_Element")
+	instantiate_attribute(new_model, "RHS_contains", "name", "contains")
+
+	// Basics are added, now we need to add each node and transition, but slightly modified
+	Element keys
+	String key
+	Element new_entry
+	Element entry
+
+	keys = dict_keys(old_m)
+	String type_name
+	String old_source
+	String old_target
+	Element to_link
+	to_link = create_node()
+
+	while (read_nr_out(keys) > 0):
+		key = set_pop(keys)
+		entry = old_m[key]
+
+		type_name = reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], entry))
+		if (type_name == "Class"):
+			instantiate_node(new_model, type_name, "Pre_" + key)
+			instantiate_node(new_model, type_name, "Post_" + key)
+
+			// Also make it inherit from the "root element"
+			instantiate_link(new_model, "Inheritance", "", "Pre_" + key, "Pre_Element")
+			instantiate_link(new_model, "Inheritance", "", "Post_" + key, "Post_Element")
+
+		elif (type_name == "Association"):
+			old_source = reverseKeyLookup(model["model"], read_edge_src(entry))
+			old_target = reverseKeyLookup(model["model"], read_edge_dst(entry))
+			instantiate_link(new_model, type_name, "Pre_" + key, "Pre_" + old_source, "Pre_" + old_target)
+			instantiate_link(new_model, type_name, "Post_" + key, "Post_" + old_source, "Post_" + old_target)
+
+			// 1) Make it inherit from the Root Element (Pre_Element or Post_Element)
+			instantiate_link(new_model, "Inheritance", "", "Pre_" + key, "Pre_Element")
+			instantiate_link(new_model, "Inheritance", "", "Post_" + key, "Post_Element")
+			
+		elif (type_name == "Inheritance"):
+			old_source = reverseKeyLookup(model["model"], read_edge_src(entry))
+			old_target = reverseKeyLookup(model["model"], read_edge_dst(entry))
+			instantiate_link(new_model, type_name, "Pre_" + key, "Pre_" + old_source, "Pre_" + old_target)
+			instantiate_link(new_model, type_name, "Post_" + key, "Post_" + old_source, "Post_" + old_target)
+
+		elif (bool_not(has_value(entry))):
+			create_edge(to_link, entry)
+
+	while (read_nr_out(to_link) > 0):
+		entry = set_pop(to_link)
+		type_name = reverseKeyLookup(model["metamodel"]["model"], dict_read_node(model["type_mapping"], entry))
+		// Primitive values themselves are not copied, so skip that here
+
+		// An instance link, so just copy over (don't make element of Root Element), and don't even copy if it is lower cardinality
+		// It is probably an attribute at the meta-language level, so check which one it is
+		String name
+		name = read_attribute(model["metamodel"], type_name, "name")
+		if (bool_not(bool_or(bool_or(name == "lower_cardinality", name == "source_lower_cardinality"), bool_or(name == "constraint", name == "target_lower_cardinality")))):
+			// Not a lower cardinality or constraint, so copy
+			old_source = reverseKeyLookup(model["model"], read_edge_src(entry))
+			if (bool_or(bool_or(name == "name", name == "upper_cardinality"), bool_or(name == "source_upper_cardinality", name == "target_upper_cardinality"))):
+				// Keep the old name for the physical attributes!
+				instantiate_attribute(new_model, "Pre_" + old_source, name, read_edge_dst(entry))
+				instantiate_attribute(new_model, "Post_" + old_source, name, read_edge_dst(entry))
+			else:
+				// Rename the attributes as well
+				instantiate_attribute(new_model, "Pre_" + old_source, "Pre_" + name, read_edge_dst(entry))
+				instantiate_attribute(new_model, "Post_" + old_source, "Post_" + name, read_edge_dst(entry))
+
+	// Define schedule over these elements
+
+	//  Class Entry {}
+	instantiate_node(new_model, "Class", "Entry")
+
+	//	Class Success : Entry {}
+	instantiate_node(new_model, "Class", "Success")
+	instantiate_link(new_model, "Inheritance", "", "Success", "Entry")
+
+	//	Class Failure : Entry {}
+	instantiate_node(new_model, "Class", "Failure")
+	instantiate_link(new_model, "Inheritance", "", "Failure", "Entry")
+
+	//  Class Rule : Entry {}
+	instantiate_node(new_model, "Class", "Rule")
+	instantiate_link(new_model, "Inheritance", "", "Rule", "Entry")
+
+	//  Association OnSuccess(Rule, Entry){
+	//		target_lower_cardinality = 1
+	//		target_upper_cardinality = 1
+	//	}
+	instantiate_link(new_model, "Association", "OnSuccess", "Rule", "Entry")
+	instantiate_attribute(new_model, "OnSuccess", "target_lower_cardinality", 1)
+	instantiate_attribute(new_model, "OnSuccess", "target_upper_cardinality", 1)
+
+	//  Association OnFailure(Rule, Entry){
+	//		target_lower_cardinality = 1
+	//		target_upper_cardinality = 1
+	//	}
+	instantiate_link(new_model, "Association", "OnFailure", "Rule", "Entry")
+	instantiate_attribute(new_model, "OnFailure", "target_lower_cardinality", 1)
+	instantiate_attribute(new_model, "OnFailure", "target_upper_cardinality", 1)
+
+	// Class LHSRule : Rule {}
+	instantiate_node(new_model, "Class", "LHSRule")
+	instantiate_link(new_model, "Inheritance", "", "LHSRule", "Rule")
+
+	// 	Association LHSLink (LHSRule, LHS) {
+	//		target_lower_cardinality = 1
+	//		target_upper_cardinality = 1
+	//	}
+	instantiate_link(new_model, "Association", "LHSLink", "LHSRule", "LHS")
+	instantiate_attribute(new_model, "LHSLink", "target_lower_cardinality", 1)
+	instantiate_attribute(new_model, "LHSLink", "target_upper_cardinality", 1)
+
+	// 	Association NACLink (LHSRule, NAC) {}
+	instantiate_link(new_model, "Association", "NACLink", "LHSRule", "NAC")
+
+	//  Class RHSRule : Rule {}
+	instantiate_node(new_model, "Class", "RHSRule")
+	instantiate_link(new_model, "Inheritance", "", "RHSRule", "Rule")
+
+	// 	Association RHSLink (RHSRule, RHS) {
+	//		target_lower_cardinality = 1
+	//		target_upper_cardinality = 1
+	//	}
+	instantiate_link(new_model, "Association", "RHSLink", "RHSRule", "RHS")
+	instantiate_attribute(new_model, "RHSLink", "target_lower_cardinality", 1)
+	instantiate_attribute(new_model, "RHSLink", "target_upper_cardinality", 1)
+
+	// 	Class Query : LHSRule {}
+	instantiate_node(new_model, "Class", "Query")
+	instantiate_link(new_model, "Inheritance", "", "Query", "LHSRule")
+
+	//	Class Atomic : LHSRule, RHSRule {}
+	instantiate_node(new_model, "Class", "Atomic")
+	instantiate_link(new_model, "Inheritance", "", "Atomic", "LHSRule")
+	instantiate_link(new_model, "Inheritance", "", "Atomic", "RHSRule")
+
+	// 	Class ForAll : LHSRule, RHSRule {}
+	instantiate_node(new_model, "Class", "ForAll")
+	instantiate_link(new_model, "Inheritance", "", "ForAll", "LHSRule")
+	instantiate_link(new_model, "Inheritance", "", "ForAll", "RHSRule")
+
+	//	Class Composite : Rule {}
+	instantiate_node(new_model, "Class", "Composite")
+	instantiate_link(new_model, "Inheritance", "", "Composite", "Rule")
+
+	//	Association Initial(Composite, Entry){
+	//		target_lower_cardinality = 1
+	//		target_upper_cardinality = 1
+	//	}
+	instantiate_link(new_model, "Association", "Initial", "Composite", "Entry")
+	instantiate_attribute(new_model, "Initial", "target_lower_cardinality", 1)
+	instantiate_attribute(new_model, "Initial", "target_upper_cardinality", 1)
+
+	//	Association Contains(Composite, Entry){
+	//		source_upper_cardinality = 1
+	//		target_lower_cardinality = 1
+	//	}
+	instantiate_link(new_model, "Association", "Contains", "Composite", "Entry")
+	instantiate_attribute(new_model, "Contains", "source_upper_cardinality", 1)
+	instantiate_attribute(new_model, "Contains", "target_lower_cardinality", 1)
+
+	return new_model!

+ 0 - 1
bootstrap/random.alc

@@ -17,7 +17,6 @@ Float function random():
 	seed = integer_modulo(a * seed + c, m)
 
 	// The seed is the new value
-	log("Return random " + cast_f2s(float_division(seed, m)))
 	return float_division(seed, m)!
 
 Integer function random_interval(a : Integer, b : Integer):

+ 446 - 0
bootstrap/transform.alc

@@ -0,0 +1,446 @@
+include "primitives.alh"
+include "object_operations.alh"
+include "modelling.alh"
+include "random.alh"
+include "conformance_scd.alh"
+include "model_management.alh"
+
+Element function make_matching_schedule(schedule_model : Element, LHS : String, ignore : Element):
+	Element schedule
+	Element workset
+	Element all_elements
+	Element full_all_elements
+	Integer required_size
+	String new_element
+	Integer counter
+	String next
+	Element tmp
+
+	// Initialize
+	schedule = create_node()
+	workset = create_node()
+	all_elements = allAssociationDestinations(schedule_model, LHS, "LHS_contains")
+	full_all_elements = set_copy(all_elements)
+	required_size = read_nr_out(all_elements)
+
+	// Need to keep adding to the schedule
+	while (read_nr_out(schedule) < required_size):
+
+		// workset is empty, but we still need to add to the list
+		// Therefore, we pick a random, unbound node, and add it to the workset
+		new_element = set_pop(all_elements)
+		while (bool_or(set_in(schedule, new_element), is_edge(schedule_model["model"][new_element]))):
+			// Element is not usable, so pick another one
+			new_element = set_pop(all_elements)
+		set_add(workset, new_element)
+
+		// Handle the workset
+		while (read_nr_out(workset) > 0):
+			// Still elements in the workset, so pop from these first
+			next = set_pop(workset)
+
+			// Check if element might not be already used somewhere
+			if (bool_not(set_in(schedule, next))):
+				if (set_in(full_all_elements, next)):
+					if (bool_not(set_in(ignore, read_attribute(schedule_model, next, "label")))):
+						list_append(schedule, next)
+						required_size = required_size - 1
+
+					// 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, reverseKeyLookup(schedule_model["model"], read_edge_src(schedule_model["model"][next])))
+						set_add(workset, reverseKeyLookup(schedule_model["model"], 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
+						if (set_in_node(schedule_model["model"], read_out(schedule_model["model"][next], counter))):
+							set_add(workset, reverseKeyLookup(schedule_model["model"], read_out(schedule_model["model"][next], counter)))
+
+	return schedule!
+
+Element function get_possible_bindings(host_model : Element, schedule_model : Element, current_element : String, map : Element):
+	Element options
+	String src_label
+	String dst_label
+	String typename
+	String original_typename
+
+	options = create_node()
+
+	typename = reverseKeyLookup(schedule_model["metamodel"]["model"], dict_read_node(schedule_model["type_mapping"], schedule_model["model"][current_element]))
+	original_typename = string_substr(typename, 4, string_len(typename))
+
+	if (is_edge(schedule_model["model"][current_element])):
+		// Is an edge, so check for already bound source/target
+		src_label = read_attribute(schedule_model, reverseKeyLookup(schedule_model["model"], read_edge_src(schedule_model["model"][current_element])), "label")
+		dst_label = read_attribute(schedule_model, reverseKeyLookup(schedule_model["model"], read_edge_dst(schedule_model["model"][current_element])), "label")
+
+		if (bool_and(set_in(dict_keys(map), src_label), set_in(dict_keys(map), dst_label))):
+			// Source and destination are bound
+			options = allOutgoingAssociationInstances(host_model, map[src_label], original_typename)
+			options = set_overlap(options, allIncomingAssociationInstances(host_model, map[dst_label], original_typename))
+
+		elif (set_in(dict_keys(map), src_label)):
+			// Source is bound
+			options = allOutgoingAssociationInstances(host_model, map[src_label], original_typename)
+
+		elif (set_in(dict_keys(map), dst_label)):
+			// Destination is bound
+			options = allIncomingAssociationInstances(host_model, map[dst_label], original_typename)
+
+		else:
+			// Neither is bound, so just get all of them
+			log("ERROR: unbound source/target for association!")
+			//TODO should actually return all
+			return create_node()!
+	else:
+		// Is a node, so find whether or not there are some connections that are already resolved
+		Element ic
+		Element oc
+		String poll
+
+		ic = allIncomingAssociationInstances(schedule_model, current_element, "Pre_Element")
+		oc = allOutgoingAssociationInstances(schedule_model, current_element, "Pre_Element")
+
+		while (bool_and(read_nr_out(ic) > 0, read_nr_out(options) == 0)):
+			poll = set_pop(ic)
+			if (dict_in(map, read_attribute(schedule_model, poll, "label"))):
+				// This incoming link is already defined, so we just have one option: the destination of the link we matched
+				set_add(options, readAssociationDestination(host_model, map[read_attribute(schedule_model, poll, "label")]))
+			
+		while (bool_and(read_nr_out(oc) > 0, read_nr_out(options) == 0)):
+			poll = set_pop(oc)
+			if (dict_in(map, read_attribute(schedule_model, poll, "label"))):
+				// This incoming link is already defined, so we just have one option: the destination of the link we matched
+				set_add(options, readAssociationSource(host_model, map[read_attribute(schedule_model, poll, "label")]))
+
+		if (read_nr_out(options) == 0):
+			// Is a node and no connections, so we just pick all options
+			options = allInstances(host_model, original_typename)
+		elif (read_nr_out(options) > 1):
+			// Multiple "only" options, which will not work out: no options!
+			return create_node()!
+
+	// Filter options further
+	Element filtered_options
+	String option
+
+	filtered_options = create_node()
+	while (read_nr_out(options) > 0):
+		option = set_pop(options)
+
+		// Check for detecting same element twice
+		if (bool_not(set_in(map, option))):
+			// Option is already present with another label, so skip this!
+
+			// Check for local constraints of element
+			if (element_eq(read_attribute(schedule_model, current_element, "constraint"), read_root())):
+				// No local constraints, so all is well
+				set_add(filtered_options, option)
+			else:
+				// Check local constraints and add only if positive
+				Element constraint_function
+				constraint_function = read_attribute(schedule_model, current_element, "constraint")
+				Boolean result
+				result = constraint_function(host_model, option)
+				if (result):
+					set_add(filtered_options, option)
+
+	return filtered_options!
+
+Element function full_match(host_model : Element, schedule_model : Element, current : String):
+	Element NACs
+	String LHS
+	String NAC
+	Element mappings
+	Element mapping
+	Integer i
+	Element result
+	Element final_mappings
+	Boolean allowed
+
+	final_mappings = create_node()
+
+	// First match the LHS part itself to get initial mappings
+	LHS = set_pop(allAssociationDestinations(schedule_model, current, "LHSLink"))
+	mappings = match(host_model, schedule_model, LHS, create_node())
+
+	// Got a list of all possible mappings, now filter based on NACs
+	NACs = allAssociationDestinations(schedule_model, current, "NACLink")
+
+	// For each possible mapping, we check all NACs!
+	while (read_nr_out(mappings) > 0):
+		mapping = set_pop(mappings)
+		i = 0
+		allowed = True
+		while (bool_and(i < read_nr_out(NACs), allowed)):
+			NAC = read_edge_dst(read_out(NACs, i))
+			result = match(host_model, schedule_model, NAC, mapping)
+			if (read_nr_out(result) > 0):
+				// NAC could be matched, and therefore is not allowed
+				allowed = False
+			i = i + 1
+		
+		if (allowed):
+			set_add(final_mappings, mapping)
+
+	return final_mappings!
+
+Element function match(host_model : Element, schedule_model : Element, LHS : String, initial_mapping : Element):
+	// Match the schedule_model to the host_model, returning all possible mappings from schedule_model elements to host_model elements
+
+	// Make the schedule first
+	Element schedule
+	schedule = make_matching_schedule(schedule_model, LHS, dict_keys(initial_mapping))
+
+	// Now follow the schedule, incrementally building all mappings
+	Element mappings
+	Element new_mappings
+	Element new_map
+	String current_element
+	Element map
+	String option
+	Element options
+
+	mappings = create_node()
+	set_add(mappings, initial_mapping)
+	while (bool_and(read_nr_out(schedule) > 0, read_nr_out(mappings) > 0)):
+		current_element = list_pop(schedule, 0)
+		new_mappings = create_node()
+
+		while (read_nr_out(mappings) > 0):
+			map = set_pop(mappings)
+			options = get_possible_bindings(host_model, schedule_model, current_element, map)
+
+			while (read_nr_out(options) > 0):
+				option = set_pop(options)
+				new_map = dict_copy(map)
+				dict_add(new_map, read_attribute(schedule_model, current_element, "label"), option)
+				set_add(new_mappings, new_map)
+
+		mappings = new_mappings
+
+	// Finished, so try the global constraint
+	Element constraint
+
+	new_mappings = create_node()
+	constraint = read_attribute(schedule_model, LHS, "constraint")
+	if (element_neq(constraint, read_root())):
+		while (read_nr_out(mappings) > 0):
+			map = set_pop(mappings)
+			if (constraint(host_model, map)):
+				set_add(new_mappings, map)
+		mappings = new_mappings
+
+	return mappings!
+
+Void function rewrite(host_model : Element, schedule_model : Element, RHS : String, mapping : Element):
+	// Rewrite the host model based on the mapping combined with the RHS
+	Element LHS_labels
+	Element RHS_labels
+	Element RHS_elements
+	Element remaining
+	String elem
+	String label
+	Element labels_to_remove
+	Element labels_to_add
+	String typename
+	String original_typename
+	String src
+	String dst
+	Element new_mapping
+	String new_name
+	Element RHS_map
+	String tmp
+	Element value
+	Element value_function
+	Element action
+	Element original_RHS_labels
+
+	LHS_labels = dict_keys(mapping)
+	RHS_labels = create_node()
+	RHS_map = create_node()
+
+	RHS_elements = allAssociationDestinations(schedule_model, RHS, "RHS_contains")
+	while (read_nr_out(RHS_elements) > 0):
+		tmp = set_pop(RHS_elements)
+		label = read_attribute(schedule_model, tmp, "label")
+		set_add(RHS_labels, label)
+		dict_add(RHS_map, label, tmp)
+
+	remaining = set_overlap(LHS_labels, RHS_labels)
+	original_RHS_labels = set_copy(RHS_labels)
+	while (read_nr_out(remaining) > 0):
+		elem = set_pop(remaining)
+		set_remove(LHS_labels, elem)
+		set_remove(RHS_labels, elem)
+
+	labels_to_remove = LHS_labels
+	labels_to_add = set_to_list(RHS_labels)
+
+	new_mapping = dict_copy(mapping)
+
+	while (read_nr_out(labels_to_add) > 0):
+		// Add the elements linked to these labels
+		label = list_pop(labels_to_add, 0)
+		if (element_neq(read_attribute(schedule_model, RHS_map[label], "value"), read_root())):
+			// There is a value associated with this node
+			value_function = read_attribute(schedule_model, RHS_map[label], "value")
+			value = value_function(host_model, mapping)
+
+			typename = reverseKeyLookup(schedule_model["metamodel"]["model"], dict_read_node(schedule_model["type_mapping"], schedule_model["model"][RHS_map[label]]))
+			original_typename = string_substr(typename, 5, string_len(typename))
+			new_name = instantiate_value(host_model, original_typename, "", value)
+			dict_add(new_mapping, label, new_name)
+
+		elif (is_edge(schedule_model["model"][RHS_map[label]])):
+			// Edge
+			src = read_attribute(schedule_model, reverseKeyLookup(schedule_model["model"], read_edge_src(schedule_model["model"][RHS_map[label]])), "label")
+			dst = read_attribute(schedule_model, reverseKeyLookup(schedule_model["model"], 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))):
+				// Both are present, so we can make the link
+				typename = reverseKeyLookup(schedule_model["metamodel"]["model"], dict_read_node(schedule_model["type_mapping"], schedule_model["model"][RHS_map[label]]))
+				original_typename = string_substr(typename, 5, string_len(typename))
+				new_name = instantiate_link(host_model, original_typename, "", new_mapping[src], new_mapping[dst])
+				dict_add(new_mapping, label, new_name)
+			else:
+				// Delay this a bit, until all are bound
+				list_append(labels_to_add, label)
+		else:
+			// Node
+			// Create the node and add it
+			typename = reverseKeyLookup(schedule_model["metamodel"]["model"], dict_read_node(schedule_model["type_mapping"], schedule_model["model"][RHS_map[label]]))
+			original_typename = string_substr(typename, 5, string_len(typename))
+			new_name = instantiate_node(host_model, original_typename, "")
+			dict_add(new_mapping, label, new_name)
+
+	while (read_nr_out(original_RHS_labels) > 0):
+		label = set_pop(original_RHS_labels)
+		action = read_attribute(schedule_model, RHS_map[label], "action")
+		if (element_neq(action, read_root())):
+			action(host_model, new_mapping[label], mapping)
+
+	while (read_nr_out(labels_to_remove) > 0):
+		// Remove the elements linked to these labels
+		label = set_pop(labels_to_remove)
+		model_delete_element(host_model, mapping[label])
+		dict_delete(new_mapping, label)
+
+	// Execute global action (whatever it may be)
+	action = read_attribute(schedule_model, RHS, "action")
+	if (element_neq(action, read_root())):
+		action(host_model, new_mapping)
+
+	return!
+
+Element function transform(host_model : Element, schedule_model : Element):
+	// Find initial model
+	Element all_composites
+	String composite
+	String current
+	Element merged
+	Element original_mm
+
+	// Now start transforming for real
+	all_composites = allInstances(schedule_model, "Composite")
+	if (read_nr_out(all_composites) == 1):
+		// Only one, so it is easy
+		current = set_pop(all_composites)
+	else:
+		// Filter out those that are themselves contained
+		while (read_nr_out(all_composites) > 0):
+			composite = set_pop(all_composites)
+			if (read_nr_out(allIncomingAssociationInstances(schedule_model, composite, "Contains")) == 0):
+				// Isn't contained in any, so this is the root model!
+				current = composite
+
+	if (transform_composite(host_model, schedule_model, current)):
+		// Success, so return True if it is in-place, or the new model if it is out-place
+		log("Transform success!")
+		return True!
+	else:
+		log("Transform failed!")
+		return False!
+
+Boolean function transform_composite(host_model : Element, schedule_model : Element, composite : String):
+	String current
+	String typename
+	Boolean result
+
+	current = set_pop(allAssociationDestinations(schedule_model, composite, "Initial"))
+	while (is_nominal_instance(schedule_model, current, "Rule")):
+		// Still a rule that we must execute
+		typename = reverseKeyLookup(schedule_model["metamodel"]["model"], dict_read_node(schedule_model["type_mapping"], schedule_model["model"][current]))
+		if (typename == "Atomic"):
+			result = transform_atomic(host_model, schedule_model, current)
+		elif (typename == "Query"):
+			result = transform_query(host_model, schedule_model, current)
+		elif (typename == "Composite"):
+			result = transform_composite(host_model, schedule_model, current)
+		elif (typename == "ForAll"):
+			result = transform_forall(host_model, schedule_model, current)
+
+		if (result):
+			current = set_pop(allAssociationDestinations(schedule_model, current, "OnSuccess"))
+		else:
+			current = set_pop(allAssociationDestinations(schedule_model, current, "OnFailure"))
+
+	// No longer a rule, so it is either success or failure
+	if (is_nominal_instance(schedule_model, current, "Success")):
+		return True!
+	else:
+		return False!
+
+Boolean function transform_atomic(host_model : Element, schedule_model : Element, current : String):
+	// Execute the atomic transformation
+	Element mappings
+	Element mapping
+	mappings = full_match(host_model, schedule_model, current)
+
+	if (read_nr_out(mappings) > 0):
+		// Pick one!
+		mapping = random_choice(set_to_list(mappings))
+		String RHS
+		RHS = set_pop(allAssociationDestinations(schedule_model, current, "RHSLink"))
+		rewrite(host_model, schedule_model, RHS, mapping)
+		return True!
+	else:
+		return False!
+
+Boolean function transform_forall(host_model : Element, schedule_model : Element, current : String):
+	// Execute the atomic transformation
+	Element mappings
+	String RHS
+	Element mapping
+	Boolean result
+
+	mappings = full_match(host_model, schedule_model, current)
+
+	if (read_nr_out(mappings) > 0):
+		result = True
+	else:
+		result = False
+
+	while (read_nr_out(mappings) > 0):
+		mapping = set_pop(mappings)
+		// TODO check if there are actually no deletions happening in the meantime of other matched elements...
+		RHS = set_pop(allAssociationDestinations(schedule_model, current, "RHSLink"))
+		rewrite(host_model, schedule_model, RHS, mapping)
+
+	return result!
+
+Boolean function transform_query(host_model : Element, schedule_model : Element, current : String):
+	// Execute the transformation
+	Element mappings
+	Element mapping
+	mappings = full_match(host_model, schedule_model, current)
+
+	if (read_nr_out(mappings) > 0):
+		return True!
+	else:
+		return False!
+

+ 0 - 1
bootstrap/user_manager.alc

@@ -29,5 +29,4 @@ Void function user_management():
 
 			//Add this only at the end, as otherwise the user will already be detected
 			dict_add(read_root(), username, user_root)
-
 	return!

+ 0 - 1
hybrid_server/classes/mvkcontroller.xml

@@ -99,7 +99,6 @@
                         <script>
                             # No JSON encoding necessary, as it is not complex
                             try:
-                                print 'from_mvi %s' % data
                                 self.done_something = False
                                 if data["op"] == "set_input":
                                     if "value" in data:

+ 12 - 0
integration/code/ftg.mvc

@@ -0,0 +1,12 @@
+import models/SimpleClassDiagrams as SimpleClassDiagrams
+
+SimpleClassDiagrams FormalismTransformationGraph{
+    Class Formalism {
+        location : String
+    }
+    Association Transformation (Formalism, Formalism) {
+        location : String
+    }
+}
+
+export FormalismTransformationGraph to models/FTG

+ 8 - 0
integration/code/graph.mvc

@@ -0,0 +1,8 @@
+import models/SimpleClassDiagrams as SimpleClassDiagrams
+
+SimpleClassDiagrams Graph{
+    Class Node {}
+    Association Edge (Node, Node) {}
+}
+
+export Graph to models/Graph

+ 18 - 0
integration/code/pn_design.mvc

@@ -0,0 +1,18 @@
+import models/SimpleClassDiagrams as SimpleClassDiagrams
+
+SimpleClassDiagrams PetriNets_Design{
+    Class Natural {}
+
+    Class Place {
+        tokens : Natural
+    }
+    Class Transition {}
+    Association P2T (Place, Transition) {
+        weight : Natural
+    }
+    Association T2P (Transition, Place) {
+        weight : Natural
+    }
+}
+
+export PetriNets_Design to models/PetriNets_Design

+ 25 - 0
integration/code/pn_design_model.mvc

@@ -0,0 +1,25 @@
+import models/PetriNets_Design as PetriNets
+
+PetriNets pn {
+    Place p1 {
+        tokens = 1
+    }
+    Place p2 {
+        tokens = 2
+    }
+    Place p3 {
+        tokens = 3
+    }
+    Transition t1 {}
+    P2T (p1, t1) {
+        weight = 1
+    }
+    P2T (p2, t1) {
+        weight = 1
+    }
+    T2P (t1, p3) {
+        weight = 2
+    }
+}
+
+export pn to models/pn

+ 186 - 0
integration/code/pn_design_to_runtime.mvc

@@ -0,0 +1,186 @@
+import models/RAM_PetriNets_Design_Runtime as RAM_PN_DR
+
+RAM_PN_DR annotate {
+    Composite schedule {
+        {Contains} Failure failure {}
+        {Contains} Success success {}
+        {Contains} ForAll copy_transitions {
+            LHS {
+                Pre_SOURCE_Transition {
+                    label = "0"
+                }
+            }
+            RHS {
+                Post_SOURCE_Transition ct1 {
+                    label = "0"
+                }
+                Post_TARGET_Transition ct2 {
+                    label = "1"
+                    action = $
+                        include "primitives.alh"
+                        include "modelling.alh"
+                        Void function action(host_model : Element, name : String, mapping : Element):
+                            instantiate_attribute(host_model, name, "executing", False)
+                            return!
+                        $
+                }
+                Post_TransitionLink (ct1, ct2){
+                    label = "2"
+                }
+            }
+        }
+        {Contains} ForAll copy_places {
+            LHS {
+                Pre_SOURCE_Place {
+                    label = "0"
+                }
+            }
+            RHS {
+                Post_SOURCE_Place cp1 {
+                    label = "0"
+                }
+                Post_TARGET_Place cp2 {
+                    label = "1"
+                    action = $
+                        include "primitives.alh"
+                        include "modelling.alh"
+                        Void function action(host_model : Element, name : String, mapping : Element):
+                            instantiate_attribute(host_model, name, "tokens", read_attribute(host_model, mapping["0"], "tokens"))
+                            instantiate_attribute(host_model, name, "name", mapping["0"])
+                            return!
+                        $
+                }
+                Post_PlaceLink (cp1, cp2){
+                    label = "2"
+                }
+            }
+        }
+        {Contains} ForAll copy_P2T {
+            LHS {
+                Pre_SOURCE_Place cp2t_p{
+                    label = "0"
+                }
+                Pre_SOURCE_Transition cp2t_t{
+                    label = "1"
+                }
+                Pre_SOURCE_P2T (cp2t_p, cp2t_t){
+                    label = "2"
+                }
+                Pre_TARGET_Place cp2t_p2{
+                    label = "3"
+                }
+                Pre_TARGET_Transition cp2t_t2{
+                    label = "4"
+                }
+                Pre_PlaceLink (cp2t_p, cp2t_p2){
+                    label = "5"
+                }
+                Pre_TransitionLink (cp2t_t, cp2t_t2){
+                    label = "6"
+                }
+            }
+            RHS {
+                Post_SOURCE_Place rhs_cp2t_p{
+                    label = "0"
+                }
+                Post_SOURCE_Transition rhs_cp2t_t{
+                    label = "1"
+                }
+                Post_SOURCE_P2T rhs_cp2t_p2t (rhs_cp2t_p, rhs_cp2t_t){
+                    label = "2"
+                }
+                Post_TARGET_Place rhs_cp2t_p2 {
+                    label = "3"
+                }
+                Post_TARGET_Transition rhs_cp2t_t2 {
+                    label = "4"
+                }
+                Post_PlaceLink (rhs_cp2t_p, rhs_cp2t_p2){
+                    label = "5"
+                }
+                Post_TransitionLink (rhs_cp2t_t, rhs_cp2t_t2){
+                    label = "6"
+                }
+                Post_TARGET_P2T rhs_cp2t_p2t2(rhs_cp2t_p2, rhs_cp2t_t2) {
+                    label = "7"
+                    action = $
+                        include "primitives.alh"
+                        include "modelling.alh"
+                        Void function action(host_model : Element, name : String, mapping : Element):
+                            instantiate_attribute(host_model, name, "weight", read_attribute(host_model, mapping["2"], "weight"))
+                            return!
+                        $
+                }
+            }
+        }
+        {Contains} ForAll copy_T2P {
+            LHS {
+                Pre_SOURCE_Place ct2p_p{
+                    label = "0"
+                }
+                Pre_SOURCE_Transition ct2p_t{
+                    label = "1"
+                }
+                Pre_SOURCE_T2P (ct2p_t, ct2p_p){
+                    label = "2"
+                }
+                Pre_TARGET_Place ct2p_p2{
+                    label = "3"
+                }
+                Pre_TARGET_Transition ct2p_t2{
+                    label = "4"
+                }
+                Pre_PlaceLink (ct2p_p, ct2p_p2){
+                    label = "5"
+                }
+                Pre_TransitionLink (ct2p_t, ct2p_t2){
+                    label = "6"
+                }
+            }
+            RHS {
+                Post_SOURCE_Place rhs_ct2p_p{
+                    label = "0"
+                }
+                Post_SOURCE_Transition rhs_ct2p_t{
+                    label = "1"
+                }
+                Post_SOURCE_T2P (rhs_ct2p_t, rhs_ct2p_p){
+                    label = "2"
+                }
+                Post_TARGET_Place rhs_ct2p_p2 {
+                    label = "3"
+                }
+                Post_TARGET_Transition rhs_ct2p_t2 {
+                    label = "4"
+                }
+                Post_PlaceLink (rhs_ct2p_p, rhs_ct2p_p2){
+                    label = "5"
+                }
+                Post_TransitionLink (rhs_ct2p_t, rhs_ct2p_t2){
+                    label = "6"
+                }
+                Post_TARGET_T2P (rhs_ct2p_t2, rhs_ct2p_p2) {
+                    label = "7"
+                    action = $
+                        include "primitives.alh"
+                        include "modelling.alh"
+                        Void function action(host_model : Element, name : String, mapping : Element):
+                            instantiate_attribute(host_model, name, "weight", read_attribute(host_model, mapping["2"], "weight"))
+                            return!
+                        $
+                }
+            }
+        }
+    }
+    OnSuccess (copy_places, copy_transitions) {}
+    OnSuccess (copy_transitions, copy_P2T) {}
+    OnSuccess (copy_P2T, copy_T2P) {}
+    OnSuccess (copy_T2P, success) {}
+    OnFailure (copy_places, copy_transitions) {}
+    OnFailure (copy_transitions, copy_P2T) {}
+    OnFailure (copy_P2T, copy_T2P) {}
+    OnFailure (copy_T2P, success) {}
+    Initial (schedule, copy_places) {}
+}
+
+export annotate to models/pn_annotate

+ 146 - 19
integration/code/pn_interface.alc

@@ -7,6 +7,10 @@ include "io.alh"
 include "metamodels.alh"
 include "modelling.alh"
 include "compilation_manager.alh"
+include "ramify.alh"
+include "transform.alh"
+include "model_management.alh"
+include "ftg.alh"
 
 Element function model_loaded(model : Element):
 	String cmd
@@ -37,7 +41,9 @@ Element function model_loaded(model : Element):
 			output("  instantiate -- Create a new model element")
 			output("  delete      -- Delete an existing element")
 			output("  attr_add    -- Add an attribute to an element")
+			output("  attr_add_code -- Add a code attribute to an element")
 			output("  attr_del    -- Delete an attribute of an element")
+			output("  attr_def    -- Define a new attribute")
 			output("  constrain   -- Add a constraint function to the model")
 			output("  rename      -- Rename an existing element")
 			output("  modify      -- Modify the attributes of an element")
@@ -50,6 +56,17 @@ Element function model_loaded(model : Element):
 			output("  exit        -- Unload the model and go back to the loading prompt")
 		elif (cmd == "exit"):
 			return model!
+		elif (cmd == "attr_def"):
+			String name
+			String attr
+			String type
+			output("Which element do you want to define an attribute for?")
+			name = input()
+			output("What is the name of the attribute?")
+			attr = input()
+			output("Type of attribute?")
+			type = input()
+			model_define_attribute(model, name, attr, type)
 		elif (cmd == "instantiate"):
 			String mm_type_name
 			output("Type to instantiate?")
@@ -94,22 +111,8 @@ Element function model_loaded(model : Element):
 				output("Element not found in metamodel; aborting")
 
 		elif (cmd == "constrain"):
-			output("Element to constrain (empty for global)?")
-			String model_name
-			model_name = input()
-
-			if (model_name == ""):
-				// Global constraint
-				output("Give input to function constructors for GLOBAL constraint!")
-				set_model_constraints(model, construct_function())
-			elif (dict_in(model["model"], model_name)):
-				// Local constraint for this model
-				output("Give input to function constructors for LOCAL constraint!")
-				add_constraint(model, model_name, construct_function())
-				output("Added constraint to model!")
-			else:
-				// Local constraint, but model not found
-				output("Unknown model; aborting")
+			output("Give input to function constructors for GLOBAL constraint!")
+			set_model_constraints(model, construct_function())
 		elif (cmd == "modify"):
 			String model_name
 			output("Element to modify?")
@@ -147,6 +150,24 @@ Element function model_loaded(model : Element):
 					output("No such attribute!")
 			else:
 				output("No such model!")
+		elif (cmd == "attr_add_code"):
+			String model_name
+			output("Which model do you want to assign a coded attribute to?")
+			model_name = input()
+			if (dict_in(model["model"], model_name)):
+				Element attrs
+				attrs = getAttributeList(model, model_name)
+				String attr_name
+				output("Which attribute do you wish to assign?")
+				attr_name = input()
+				if (set_in(dict_keys(attrs), attr_name)):
+					output("Constructors for code?")
+					instantiate_attribute_code(model, model_name, attr_name, construct_function())
+					output("Added code!")
+				else:
+					output("No such attribute!")
+			else:
+				output("No such model!")
 		elif (cmd == "attr_del"):
 			String model_name
 			output("Which model do you want to remove an attribute of?")
@@ -215,7 +236,7 @@ Element function model_loaded(model : Element):
 				if (cast_v2s(read_elem) != "None"):
 					output("Value: " + cast_v2s(read_elem))
 				output("Defines attributes:")
-				attr_list_pn = getInstantiatableAttributes(model, read_elem)
+				attr_list_pn = getInstantiatableAttributes(model, cmd)
 				attr_keys_pn = dict_keys(attr_list_pn)
 				while (0 < read_nr_out(attr_keys_pn)):
 					attr_key_pn = set_pop(attr_keys_pn)
@@ -294,7 +315,6 @@ Void function main():
 	while (True):
 		output("Please give your command.")
 		command = input()
-
 		if (command == "help"):
 			output("Currently no model is loaded, so your operations are limited to:")
 			output("  new    -- Create a new model and save it for future use")
@@ -302,6 +322,9 @@ Void function main():
 			output("  rename -- Rename a previously made model")
 			output("  delete -- Delete a previously made model")
 			output("  list   -- Show a list of all stored models")
+			output("  upload -- Upload a model using the model constructor commands")
+			output("  ramify -- RAMify existing metamodels to generate a language for transformations")
+			output("  transform -- Execute a previously defined model transformation")
 			output("  help   -- Show a list of possible commands")
 		elif (command == "new"):
 			output("Metamodel to instantiate?")
@@ -317,6 +340,8 @@ Void function main():
 					model_loaded(my_model)
 			else:
 				output("Unknown metamodel; aborting")
+		elif (command == "upload"):
+			construct_model()
 		elif (command == "load"):
 			output("Model to load?")
 			name = input()
@@ -332,7 +357,8 @@ Void function main():
 			output("Found models:")
 			while (read_nr_out(keys) > 0):
 				m_menu_list = set_pop(keys)
-				output((("  " + m_menu_list) + " : ") + reverseKeyLookup(root, root[m_menu_list]["metamodel"]))
+				if (bool_not(string_startswith(m_menu_list, "__"))):
+					output((("  " + m_menu_list) + " : ") + reverseKeyLookup(root, root[m_menu_list]["metamodel"]))
 		elif (command == "delete"):
 			output("Model to delete?")
 			name = input()
@@ -361,6 +387,107 @@ Void function main():
 			output("Switching to compilation manager!")
 			compilation_manager()
 			output("Back in model manager!")
+		elif (command == "unify"):
+			String mm1
+			String mm2
+			String name1
+			String name2
+			Element result
+			name = input()
+			if (dict_in(root, name)):
+				output("Already exists; aborting")
+			else:
+				output("Which language do you want to unify?")
+				mm1 = input()
+				if (dict_in(root, mm1)):
+					output("Name of this language in the unification")
+					name1 = input()
+					output("Second language to unify?")
+					mm2 = input()
+					if (dict_in(root, mm2)):
+						output("Name of this language in the unification")
+						name2 = input()
+						log("Calling model_fuse")
+						result = model_fuse(name1, root[mm1], name2, root[mm2])
+						dict_add(root, name, result)
+					else:
+						output("Second model not found; aborting")
+				else:
+					output("Model not found; aborting")
+		elif (command == "split"):
+			String mm_name
+			String value
+
+			output("Name of the model to split up?")
+			name = input()
+			if (dict_in(root, name)):
+				output("Name of new metamodel?")
+				mm_name = input()
+				if (dict_in(root, mm_name)):
+					output("Typename to split?")
+					value = input()
+					model_retype_on_name(root[name], root[mm_name], "-", value)
+				else:
+					output("No such metamodel; aborting")
+			else:
+				output("No such model; aborting")
+		elif (command == "join"):
+			String mm_name
+			String value
+
+			output("Model name?")
+			name = input()
+			if (dict_in(root, name)):
+				output("New metamodel?")
+				mm_name = input()
+				if (dict_in(root, mm_name)):
+					value = input()
+					model_retype_on_name(root[name], root[mm_name], "+", value)
+				else:
+					output("No such metamodel; aborting")
+			else:
+				output("No such model; aborting")
+		elif (command == "ramify"):
+			Element result
+			String old_name
+			output("Name of the RAMified metamodel to create")
+			name = input()
+			if (dict_in(root, name)):
+				output("Already exists; aborting")
+			else:
+				output("Source language?")
+				String source
+				source = input()
+				if (dict_in(root, source)):
+					result = ramify(root[source])
+					dict_add(root, name, result)
+				else:
+					output("Unknown source language; aborting")
+		elif (command == "transform"):
+			Element result
+			String schedule
+			output("Which model do you want to transform?")
+			name = input()
+			if (dict_in(root, name)):
+				output("Which schedule do you want to execute?")
+				schedule = input()
+				if (dict_in(root, schedule)):
+					result = transform(root[name], root[schedule])
+					output("Transformation result: " + cast_v2s(result))
+				else:
+					output("Unknown transformation selected!")
+			else:
+				output("Unknown host model selected!")
+		elif (command == "generate_ftg"):
+			Element ftg
+			output("Name to store the FTG?")
+			name = input()
+
+			if (dict_in(root, name)):
+				output("Model already exists; aborting")
+			else:
+				ftg = create_ftg(root)
+				dict_add(root, name, ftg)
 		else:
 			output("Command not recognized, use 'help' for a list of possible commands")
 

+ 31 - 0
integration/code/pn_print.mvc

@@ -0,0 +1,31 @@
+import models/RAM_PetriNets_Runtime as RAM_PN_R
+
+RAM_PN_R print {
+    Composite schedule {
+        {Contains} Success success {}
+        {Contains} ForAll print_tokens {
+            LHS {
+                Pre_Place {
+                    label = "0"
+                }
+            }
+            RHS {
+                Post_Place {
+                    label = "0"
+                    action = $
+                        include "primitives.alh"
+                        include "modelling.alh"
+                        Void function action(host_model : Element, name : String, mapping : Element):
+                            output((cast_v2s(read_attribute(host_model, name, "name")) + " --> ") + cast_v2s(read_attribute(host_model, name, "tokens")))
+                            return!
+                        $
+                }
+            }
+        }
+    }
+    OnSuccess (print_tokens, success) {}
+    OnFailure (print_tokens, success) {}
+    Initial (schedule, print_tokens) {}
+}
+
+export print to models/pn_print

+ 23 - 0
integration/code/pn_runtime.mvc

@@ -0,0 +1,23 @@
+import models/SimpleClassDiagrams as SimpleClassDiagrams
+
+SimpleClassDiagrams PetriNets_Runtime{
+    Class Natural {}
+    Class Boolean {}
+    Class String {}
+
+    Class Place {
+        tokens : Natural
+        name : String
+    }
+    Class Transition {
+        executing : Boolean
+    }
+    Association P2T (Place, Transition) {
+        weight : Natural
+    }
+    Association T2P (Transition, Place) {
+        weight : Natural
+    }
+}
+
+export PetriNets_Runtime to models/PetriNets_Runtime

+ 27 - 0
integration/code/pn_runtime_model.mvc

@@ -0,0 +1,27 @@
+import models/PetriNets_Runtime as PetriNets_Runtime
+
+PetriNets_Runtime pn {
+	Place p1 {
+		tokens = 1
+	}
+	Place p2 {
+		tokens = 2
+	}
+	Place p3 {
+		tokens = 3
+	}
+	Transition t1 {
+		executing = False
+	}
+	P2T (p1, t1) {
+		weight = 1
+	}
+	P2T (p2, t1) {
+		weight = 1
+	}
+	T2P (t1, p3) {
+		weight = 2
+	}
+}
+
+export pn to models/pn

+ 174 - 0
integration/code/pn_simulate.mvc

@@ -0,0 +1,174 @@
+import models/RAM_PetriNets_Runtime as RAM_PN_R
+
+RAM_PN_R s {
+    Composite schedule {
+        {Contains} Failure failure {}
+        {Contains} Success success {}
+        {Contains} Atomic mark {
+            LHS {
+                Pre_Transition {
+                    label = "1"
+                    constraint = $
+                        include "primitives.alh"
+                        include "modelling.alh"
+                        include "object_operations.alh"
+                        Boolean function constraint(host_model : Element, name : String):
+                            Element links
+                            String link
+                            String place
+                            links = allIncomingAssociationInstances(host_model, name, "P2T")
+                            while (read_nr_out(links) > 0):
+                                link = set_pop(links)
+                                place = readAssociationSource(host_model, link)
+                                if (integer_lt(read_attribute(host_model, place, "tokens"), read_attribute(host_model, link, "weight"))):
+                                    return False!
+                            return True!
+                        $
+                }
+            }
+            RHS {
+                Post_Transition {
+                    label = "1"
+                    action = $
+                        include "primitives.alh"
+                        include "modelling.alh"
+                        Void function action(host_model : Element, name : String, mapping : Element):
+                            unset_attribute(host_model, name, "executing")
+                            instantiate_attribute(host_model, name, "executing", True)
+                            return!
+                        $
+                }
+            }
+        }
+        {Contains} ForAll consume {
+            LHS {
+                Pre_Transition lhs_consume_t{
+                    label = "0"
+                    constraint = $
+                        include "primitives.alh"
+                        include "modelling.alh"
+                        Boolean function constraint(host_model : Element, name : String):
+                            // Check if this node is executing currently
+                            return value_eq(read_attribute(host_model, name, "executing"), True)!
+                        $
+                }
+                Pre_Place lhs_consume_p{
+                    label = "1"
+                }
+                Pre_P2T lhs_consume_p2t(lhs_consume_p, lhs_consume_t){
+                    label = "2"
+                }
+            }
+            RHS {
+                Post_Transition rhs_consume_t {
+                    label = "0"
+                }
+                Post_Place rhs_consume_p {
+                    label = "1"
+                    action = $
+                        include "primitives.alh"
+                        include "modelling.alh"
+                        Void function action(host_model : Element, name : String, mapping : Element):
+                            Integer tokens
+                            Integer weight
+                            tokens = read_attribute(host_model, name, "tokens")
+                            weight = read_attribute(host_model, mapping["2"], "weight")
+                            unset_attribute(host_model, name, "tokens")
+                            instantiate_attribute(host_model, name, "tokens", tokens - weight)
+                            log("Consume for " + cast_v2s(read_attribute(host_model, name, "name")))
+                            log("Previous: " + cast_v2s(tokens))
+                            log("Now: " + cast_v2s(tokens - weight))
+                            return!
+                        $
+                }
+                Post_P2T (rhs_consume_p, rhs_consume_t){
+                    label = "2"
+                }
+            }
+        }
+        {Contains} ForAll produce {
+            LHS {
+                Pre_Transition lhs_produce_t{
+                    label = "0"
+                    constraint = $
+                        include "primitives.alh"
+                        include "modelling.alh"
+                        Boolean function constraint(host_model : Element, name : String):
+                            // Check if this node is executing currently
+                            return value_eq(read_attribute(host_model, name, "executing"), True)!
+                        $
+                }
+                Pre_Place lhs_produce_p{
+                    label = "1"
+                }
+                Pre_T2P (lhs_produce_t, lhs_produce_p){
+                    label = "2"
+                }
+            }
+            RHS {
+                Post_Transition rhs_produce_t{
+                    label = "0"
+                }
+                Post_Place rhs_produce_p{
+                    label = "1"
+                    action = $
+                        include "primitives.alh"
+                        include "modelling.alh"
+                        Void function action(host_model : Element, name : String, mapping : Element):
+                            Integer tokens
+                            Integer weight
+                            tokens = read_attribute(host_model, name, "tokens")
+                            weight = read_attribute(host_model, mapping["2"], "weight")
+                            unset_attribute(host_model, name, "tokens")
+                            instantiate_attribute(host_model, name, "tokens", tokens + weight)
+                            log("Produce for " + cast_v2s(read_attribute(host_model, name, "name")))
+                            log("Previous: " + cast_v2s(tokens))
+                            log("Now: " + cast_v2s(tokens + weight))
+                            return!
+                        $
+                }
+                Post_T2P (rhs_produce_t, rhs_produce_p){
+                    label = "2"
+                }
+            }
+        }
+        {Contains} Atomic unmark_transition {
+            LHS {
+                Pre_Transition {
+                    label = "0"
+                    constraint = $
+                        include "primitives.alh"
+                        include "modelling.alh"
+                        Boolean function constraint(host_model : Element, name : String):
+                            // Check if this node is executing currently
+                            return value_eq(read_attribute(host_model, name, "executing"), True)!
+                        $
+                }
+            }
+            RHS {
+                Post_Transition {
+                    label = "0"
+                    action = $
+                        include "primitives.alh"
+                        include "modelling.alh"
+                        Void function action(host_model : Element, name : String, mapping : Element):
+                            unset_attribute(host_model, name, "executing")
+                            instantiate_attribute(host_model, name, "executing", False)
+                            return!
+                        $
+                }
+            }
+        }
+    }
+    OnSuccess (mark, consume) {}
+    OnFailure (mark, failure) {}
+    OnSuccess (consume, produce) {}
+    OnFailure (consume, produce) {}
+    OnSuccess (produce, unmark_transition) {}
+    OnFailure (produce, unmark_transition) {}
+    OnSuccess (unmark_transition, success) {}
+    OnFailure (unmark_transition, failure) {}
+    Initial (schedule, mark) {}
+}
+
+export s to models/pn_simulate

+ 103 - 0
integration/code/ramified_petrinets.mvc

@@ -0,0 +1,103 @@
+SCD Pre_PetriNets {
+    // Add AL MM
+
+    Class LHS{
+        constraint : Expression {
+            target_upper_cardinality = 1
+        }
+        upper_cardinality = 1
+        lower_cardinality = 1
+    }
+    Class NAC{}
+    Class Pre_Element{
+        label : String {
+            target_lower_cardinality = 1
+            target_upper_cardinality = 1
+        }
+        constraint : Expression {
+            target_upper_cardinality = 1
+        }
+    }
+    Association (LHS, Pre_Element)
+    Association (NAC, Pre_Element){
+        target_lower_cardinality = 1
+    }
+
+    Class Pre_Place{}
+    Class Pre_Transition{}
+    Class Pre_Natural{}
+
+    Association Pre_P2T(Pre_Place, Pre_Transition) {}
+    Association Pre_T2P(Pre_Transition, Pre_Place) {}
+
+    Association Pre_Place_tokens(Pre_Place, Pre_Natural) {
+        name = "Pre_tokens"
+        target_upper_cardinality = 1
+    }
+    Association Pre_P2T_weight(Pre_P2T, Pre_Natural) {
+        name = "Pre_weight"
+        target_upper_cardinality = 1
+    }
+    Association Pre_T2P_weight(Pre_T2P, Pre_Natural) {
+        name = "Pre_weight"
+        target_upper_cardinality = 1
+    }
+
+    Inheritance (Pre_Place, Pre_Element) {}
+    Inheritance (Pre_Natural, Pre_Element) {}
+    Inheritance (Pre_Transition, Pre_Element) {}
+    Inheritance (Pre_P2T, Pre_Element) {}
+    Inheritance (Pre_Place_tokens, Pre_Element) {}
+    Inheritance (Pre_P2T_weight, Pre_Element) {}
+    Inheritance (Pre_T2P_weight, Pre_Element) {}
+}
+
+SCD Post_PetriNets{
+    // Add AL MM
+
+    Class RHS{
+        action : FunctionDefinition
+        upper_cardinality = 1
+        lower_cardinality = 1
+    }
+
+    Class Post_Element {
+        label : String {
+            target_lower_cardinality = 1
+            target_upper_cardinality = 1
+        }
+        value : Expression {
+            target_upper_cardinality = 1
+        }
+    }
+
+    Class Post_Place{}
+    Class Post_Transitions{}
+    Class Post_Natural{}
+
+    Association Post_P2T(Post_Place, Post_Transition) {}
+    Association Post_T2P(Post_Transition, Post_Place) {}
+
+    Association (Post_Place, Post_Natural) {
+        name = "Post_tokens"
+        target_upper_cardinality = 1
+    }
+
+    Association (Post_P2T, Post_Natural) {
+        name = "Post_weight"
+        target_upper_cardinality = 1
+    }
+
+    Association (Post_T2P, Post_Natural) {
+        name = "Post_weight"
+        target_upper_cardinality = 1
+    }
+
+    Inheritance (Post_Place, Post_Element) {}
+    Inheritance (Post_Natural, Post_Element) {}
+    Inheritance (Post_Transition, Post_Element) {}
+    Inheritance (Post_P2T, Post_Element) {}
+    Inheritance (Post_Place_tokens, Post_Element) {}
+    Inheritance (Post_P2T_weight, Post_Element) {}
+    Inheritance (Post_T2P_weight, Post_Element) {}
+}

+ 0 - 3
integration/test_constructors_models.py

@@ -19,7 +19,6 @@ bottom = [
         "add_edge", "1", "class_inh_any", "Class", "Any",
         "add_edge", "1", "string_inh_any", "String", "Any",
         "retype_model", "1", "1",
-        "define_inheritance", "1", "Inheritance",
         "retype", "1", "Class", "Class",
         "retype", "1", "Any", "Class",
         "retype", "1", "String", "Class",
@@ -211,7 +210,6 @@ def add_constraints(model):
 instantiate_scd = [
         "model",
         "instantiate_model", "1", "2",
-        "define_inheritance", "2", "Inheritance",
         "instantiate_node", "2", "Class", "Place",
         "instantiate_node", "2", "Class", "Transition",
         "instantiate_node", "2", "Class", "Integer",
@@ -251,7 +249,6 @@ instantiate_pn = [
 instantiate_example = [
         "model",
         "instantiate_model", "1", "2",
-        "define_inheritance", "2", "Inheritance",
         "instantiate_node", "2", "Class", "A",
         "instantiate_node", "2", "Class", "B",
         "instantiate_node", "2", "Class", "C",

+ 2 - 2
integration/test_factorial.py

@@ -12,6 +12,6 @@ class TestFactorial(unittest.TestCase):
 
     def factorial(self, mode):
         self.assertTrue(run_file(["factorial.alc", "primitives.alc"],
-            [1, 2, 3, 4],
-            [1, 2, 6, 24],
+            [1, 2, 3, 4, 20],
+            [1, 2, 6, 24, 2432902008176640000],
             mode))

+ 184 - 59
integration/test_pn_interface.py

@@ -1,12 +1,37 @@
 import unittest
 
-from utils import run_file, get_constructor
+from utils import run_file, get_constructor, get_model_constructor
 
 set_inheritance = [
         "Which link in the metamodel is the inheritance link?",
         "Set inheritance link!",
     ]
 
+join = ["Model name?",
+        "New metamodel?",
+       ]
+
+unify = ["Which language do you want to unify?",
+         "Name of this language in the unification",
+         "Second language to unify?",
+         "Name of this language in the unification",
+         ]
+
+ramify = ["Name of the RAMified metamodel to create",
+          "Source language?"]
+
+transform = ["Which model do you want to transform?",
+             "Which schedule do you want to execute?",
+            ]
+
+transform_result_true = ["Transformation result: True"]
+transform_result_false = ["Transformation result: False"]
+
+split = ["Name of the model to split up?",
+         "Name of new metamodel?",
+         "Typename to split?",
+        ]
+
 do_instantiate_simple = [
             "new", "PetriNets", "abc",
             "instantiate", "Transition", "t1",
@@ -30,7 +55,12 @@ all_files = [   "pn_interface.alc",
                 "object_operations.alc",
                 "conformance_scd.alc",
                 "library.alc",
+                "ftg.alc",
+                "transform.alc",
+                "model_management.alc",
+                "ramify.alc",
                 "metamodels.alc",
+                "random.alc",
                 "constructors.alc",
                 "modelling.alc",
                 "compilation_manager.alc",
@@ -54,6 +84,7 @@ def list_menu(defined):
     defined.append(("PetriNets", "SimpleClassDiagrams"))
     defined.append(("SimpleClassDiagrams", "SimpleClassDiagrams"))
     defined.append(("LTM_bottom", "LTM_bottom"))
+    defined.append(("FTG", "SimpleClassDiagrams"))
     return ["Found models:",
             set(["  %s : %s" % (m, mm) for m, mm in defined])]
 
@@ -398,63 +429,62 @@ include "primitives.alh"
 include "object_operations.alh"
 
 Element function constraint(model : Element, name : String):
-\tElement associations
-\tElement back_associations
-\tElement association
-\tString destination
-\tassociations = allOutgoingAssociationInstances(model, name, "tile_left")
-\twhile (0 < list_len(associations)):
-\t\tassociation = set_pop(associations)
-\t\tdestination = readAssociationDestination(model, association)
-\t\tback_associations = allOutgoingAssociationInstances(model, destination, "tile_right")
-\t\tif (list_len(back_associations) < 1):
-\t\t\treturn "Left link does not have a right link back"!
-\t\telse:
-\t\t\tassociation = set_pop(back_associations)
-\t\t\tdestination = readAssociationDestination(model, association)
-\t\t\tif (destination != name):
-\t\t\t\treturn "Right link does not have a left link back to the same tile"!
-\tassociations = allOutgoingAssociationInstances(model, name, "tile_right")
-\twhile (0 < list_len(associations)):
-\t\tassociation = set_pop(associations)
-\t\tdestination = readAssociationDestination(model, association)
-\t\tback_associations = allOutgoingAssociationInstances(model, destination, "tile_left")
-\t\tif (list_len(back_associations) < 1):
-\t\t\treturn "Right link does not have a left link back"!
-\t\telse:
-\t\t\tassociation = set_pop(back_associations)
-\t\t\tdestination = readAssociationDestination(model, association)
-\t\t\tif (destination != name):
-\t\t\t\treturn "Right link does not have a left link back to the same tile"!
-\tassociations = allOutgoingAssociationInstances(model, name, "tile_top")
-\twhile (0 < list_len(associations)):
-\t\tassociation = set_pop(associations)
-\t\tdestination = readAssociationDestination(model, association)
-\t\tback_associations = allOutgoingAssociationInstances(model, destination, "tile_bottom")
-\t\tif (list_len(back_associations) < 1):
-\t\t\treturn "Top link does not have a bottom link back"!
-\t\telse:
-\t\t\tassociation = set_pop(back_associations)
-\t\t\tdestination = readAssociationDestination(model, association)
-\t\t\tif (destination != name):
-\t\t\t\treturn "Top link does not have a bottom link back to the same tile"!
-\tassociations = allOutgoingAssociationInstances(model, name, "tile_bottom")
-\twhile (0 < list_len(associations)):
-\t\tassociation = set_pop(associations)
-\t\tdestination = readAssociationDestination(model, association)
-\t\tback_associations = allOutgoingAssociationInstances(model, destination, "tile_top")
-\t\tif (list_len(back_associations) < 1):
-\t\t\treturn "Bottom link does not have a top link back"!
-\t\telse:
-\t\t\tassociation = set_pop(back_associations)
-\t\t\tdestination = readAssociationDestination(model, association)
-\t\t\tif (destination != name):
-\t\t\t\treturn "Bottom link does not have a top link back to the same tile"!
-\treturn "OK"!
+	Element associations
+	Element back_associations
+	Element association
+	String destination
+	associations = allOutgoingAssociationInstances(model, name, "tile_left")
+	while (0 < list_len(associations)):
+		association = set_pop(associations)
+		destination = readAssociationDestination(model, association)
+		back_associations = allOutgoingAssociationInstances(model, destination, "tile_right")
+		if (list_len(back_associations) < 1):
+			return "Left link does not have a right link back"!
+		else:
+			association = set_pop(back_associations)
+			destination = readAssociationDestination(model, association)
+			if (destination != name):
+				return "Right link does not have a left link back to the same tile"!
+	associations = allOutgoingAssociationInstances(model, name, "tile_right")
+	while (0 < list_len(associations)):
+		association = set_pop(associations)
+		destination = readAssociationDestination(model, association)
+		back_associations = allOutgoingAssociationInstances(model, destination, "tile_left")
+		if (list_len(back_associations) < 1):
+			return "Right link does not have a left link back"!
+		else:
+			association = set_pop(back_associations)
+			destination = readAssociationDestination(model, association)
+			if (destination != name):
+				return "Right link does not have a left link back to the same tile"!
+	associations = allOutgoingAssociationInstances(model, name, "tile_top")
+	while (0 < list_len(associations)):
+		association = set_pop(associations)
+		destination = readAssociationDestination(model, association)
+		back_associations = allOutgoingAssociationInstances(model, destination, "tile_bottom")
+		if (list_len(back_associations) < 1):
+			return "Top link does not have a bottom link back"!
+		else:
+			association = set_pop(back_associations)
+			destination = readAssociationDestination(model, association)
+			if (destination != name):
+				return "Top link does not have a bottom link back to the same tile"!
+	associations = allOutgoingAssociationInstances(model, name, "tile_bottom")
+	while (0 < list_len(associations)):
+		association = set_pop(associations)
+		destination = readAssociationDestination(model, association)
+		back_associations = allOutgoingAssociationInstances(model, destination, "tile_top")
+		if (list_len(back_associations) < 1):
+			return "Bottom link does not have a top link back"!
+		else:
+			association = set_pop(back_associations)
+			destination = readAssociationDestination(model, association)
+			if (destination != name):
+				return "Bottom link does not have a top link back to the same tile"!
+	return "OK"!
             """
 
         constructors = get_constructor(constraint_code)
-        print(constructors)
 
         self.assertTrue(run_file(all_files,
             ["new", "SimpleClassDiagrams", "RPGame",
@@ -494,7 +524,7 @@ Element function constraint(model : Element, name : String):
                 "attr_add", "tile_top", "target_upper_cardinality", 1,
                 "attr_add", "tile_bottom", "source_upper_cardinality", 1,
                 "attr_add", "tile_bottom", "target_upper_cardinality", 1,
-                "constrain", "Tile",
+                "attr_add_code", "Tile", "constraint",
             ] + constructors + ["verify"] + ["exit"] + [
                 "new", "RPGame", "my_game",
                 "instantiate", "Scene", "scene",
@@ -525,9 +555,10 @@ Element function constraint(model : Element, name : String):
                 (instantiate_node + prompt) * 6 + \
                 (instantiate_edge + prompt) * 9 + \
                 (attr_add + prompt) * 20 + \
-                ["Element to constrain (empty for global)?",
-                 "Give input to function constructors for LOCAL constraint!",
-                 "Added constraint to model!"] + \
+                ["Which model do you want to assign a coded attribute to?",
+                 "Which attribute do you wish to assign?",
+                 "Constructors for code?",
+                 "Added code!"] + \
                 prompt + \
                 ["OK"] + \
                 prompt + prompt + new + loaded + \
@@ -535,3 +566,97 @@ Element function constraint(model : Element, name : String):
                 (instantiate_edge + prompt) * 14 + \
                 ["OK"],
             mode))
+
+    def test_po_pn_interface_model_transform_pn(self):
+        PN_runtime = open("integration/code/pn_runtime.mvc", "r").read()
+        PN_model = open("integration/code/pn_runtime_model.mvc", "r").read()
+        schedule_model = open("integration/code/pn_simulate.mvc", "r").read()
+
+        self.assertTrue(run_file(all_files,
+            get_model_constructor(PN_runtime) + [
+                ] + get_model_constructor(PN_model) + [
+                "load", "pn", 
+                    "read", "t1",
+                    "read", "p1",
+                    "read", "p2",
+                    "read", "p3",
+                    "exit",
+                "ramify", "RAM_PetriNets_Runtime", "PetriNets_Runtime",
+                ] + get_model_constructor(schedule_model) + [
+                "transform", "pn", "pn_simulate",
+                "transform", "pn", "pn_simulate",
+                "load", "pn",
+                    "verify",
+                    "read", "t1",
+                    "read", "p1",
+                    "read", "p2",
+                    "read", "p3",
+                    "exit",
+            ],
+          greeting + prompt * 3 +
+            load + loaded +
+            read_node("t1", "Transition", [], [("executing", "Boolean", False)]) + prompt +
+            read_node("p1", "Place", [], [("tokens", "Natural", 1)]) + prompt +
+            read_node("p2", "Place", [], [("tokens", "Natural", 2)]) + prompt +
+            read_node("p3", "Place", [], [("tokens", "Natural", 3)]) + prompt +
+            prompt +
+            ramify + prompt + 
+            prompt +
+            transform + transform_result_true + prompt +
+            transform + transform_result_false + prompt +
+            load + loaded +
+            ["OK"] + prompt +
+            read_node("t1", "Transition", [], [("executing", "Boolean", False)]) + prompt +
+            read_node("p1", "Place", [], [("tokens", "Natural", 0)]) + prompt +
+            read_node("p2", "Place", [], [("tokens", "Natural", 1)]) + prompt +
+            read_node("p3", "Place", [], [("tokens", "Natural", 5)]) + prompt, 
+          "PO"))
+
+    def test_po_pn_interface_transform_pn_to_runtime(self):
+        PN_runtime = open("integration/code/pn_runtime.mvc", "r").read()
+        PN_design = open("integration/code/pn_design.mvc", "r").read()
+        PN_model = open("integration/code/pn_design_model.mvc", "r").read()
+        schedule_model_design_to_runtime = open("integration/code/pn_design_to_runtime.mvc", "r").read()
+        schedule_model_print = open("integration/code/pn_print.mvc", "r").read()
+        schedule_model_simulate = open("integration/code/pn_simulate.mvc", "r").read()
+
+        self.assertTrue(run_file(all_files,
+            get_model_constructor(PN_runtime) + \
+                get_model_constructor(PN_design) + \
+                get_model_constructor(PN_model) + [
+                "unify", "PetriNets_Design_to_Runtime", "PetriNets_Design", "SOURCE_", "PetriNets_Runtime", "TARGET_",
+                "join", "pn", "PetriNets_Design_to_Runtime", "SOURCE_",
+                "load", "PetriNets_Design_to_Runtime",
+                    "instantiate", "Association", "PlaceLink", "SOURCE_Place", "TARGET_Place",
+                    "instantiate", "Association", "TransitionLink", "SOURCE_Transition", "TARGET_Transition",
+                    "exit",
+                "ramify", "RAM_PetriNets_Design_Runtime", "PetriNets_Design_to_Runtime",
+                "ramify", "RAM_PetriNets_Runtime", "PetriNets_Runtime",
+                ] + get_model_constructor(schedule_model_design_to_runtime) + [
+                ] + get_model_constructor(schedule_model_print) + [
+                ] + get_model_constructor(schedule_model_simulate) + [
+                "transform", "pn", "pn_annotate",
+                "split", "pn", "PetriNets_Runtime", "TARGET_",
+                "transform", "pn", "pn_print",
+                "transform", "pn", "pn_simulate",
+                "transform", "pn", "pn_print",
+            ],
+          greeting + prompt * 4 +
+            unify + prompt +
+            join + prompt +
+            load + loaded +
+            instantiate_edge + prompt +
+            instantiate_edge + prompt +
+            prompt +
+            ramify + prompt +
+            ramify + prompt + 
+            prompt +
+            prompt +
+            prompt +
+            transform + transform_result_true + prompt +
+            split + prompt +
+            transform + [set(['"p1" --> 1', '"p2" --> 2', '"p3" --> 3'])] + transform_result_true + prompt +
+            transform + transform_result_true + prompt +
+            transform + [set(['"p1" --> 0', '"p2" --> 1', '"p3" --> 5'])] + transform_result_true + prompt
+            , 
+          "PO"))

+ 24 - 2
integration/utils.py

@@ -137,6 +137,11 @@ def run_file(files, parameters, expected, mode):
         flush_data(address, parameters)
         
         # ... and wait for replies
+        if expected is None:
+            while 1:
+                val = urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": "get_output", "username": username})), timeout=240).read()
+                val = json.loads(val)
+                print(val)
         for e in expected:
             c = len(e) if isinstance(e, set) else 1
             for _ in range(c):
@@ -257,10 +262,27 @@ def run_barebone(parameters, expected, interface="0", timeout=False, wait=False,
         kill(proc)
 
 def get_constructor(code):
-    with open("__constraint.al", "w") as f:
+    with open("__constraint.alc", "w") as f:
+        f.write(code)
+        f.flush()
+
+    constructors = do_compile("__constraint.alc", "interface/HUTN/grammars/actionlanguage.g", "CS")
+
+    return constructors
+
+def get_model_constructor(code):
+    # First change multiple spaces to a tab
+    code_fragments = code.split("\n")
+    code_fragments = [i for i in code_fragments if i.strip() != ""]
+    code_fragments = [i.replace("    ", "\t") for i in code_fragments]
+    initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments])
+    code_fragments = [i[initial_tabs:] for i in code_fragments]
+    code = "\n".join(code_fragments)
+
+    with open("__model.mvc", "w") as f:
         f.write(code)
         f.flush()
 
-    constructors = do_compile("__constraint.al", "interface/HUTN/grammars/actionlanguage.g", "CS")
+    constructors = ["upload"] + do_compile("__model.mvc", "interface/HUTN/grammars/modelling.g", "M") + ["exit"]
 
     return constructors

+ 7 - 3
interface/HUTN/grammars/modelling.g

@@ -11,11 +11,13 @@ grammar{
 
     inheritance: COLON MODEL_ID (COMMA MODEL_ID)*;
 
-    model_attribute : (MODEL_ID COLON MODEL_ID (LCURLY NEWLINE? model_attr_instance* RCURLY)? NEWLINE?)
+    model_attribute : ((LCURLY MODEL_ID RCURLY)? model_element)
+                    | (MODEL_ID COLON MODEL_ID (LCURLY NEWLINE? model_attr_instance* RCURLY)? NEWLINE?)
                     | (model_attr_instance)
-                    | (DOLLAR ANYTHING_EXCEPT_DOLLAR DOLLAR NEWLINE?);
+                    | (NEWLINE? DOLLAR ANYTHING_EXCEPT_DOLLAR DOLLAR NEWLINE?);
 
-    model_attr_instance: MODEL_ID ASSIGN value NEWLINE?;
+    model_attr_instance: (MODEL_ID ASSIGN value NEWLINE?)
+                       | (MODEL_ID ASSIGN NEWLINE? DOLLAR ANYTHING_EXCEPT_DOLLAR DOLLAR NEWLINE?);
 
     value
         : DEC_NUMBER
@@ -40,6 +42,7 @@ grammar{
         ASSIGN: '=';
         DOLLAR: '\$';
         WS: '[ ]+' @Impl;
+        TAB: '[\t]+' @Impl;
         COLON : ':';
         LPAR: '\(';
         RPAR: '\)';
@@ -48,5 +51,6 @@ grammar{
         TO: 'to';
         ANYTHING_EXCEPT_DOLLAR: '[^$]*';
         INCLUDE: 'include';
+        EXCLAMATION: '!';
     }
 }

+ 2 - 2
interface/HUTN/hutn_compiler/grammar_compiler_visitor.py

@@ -267,7 +267,7 @@ class GrammarCompilerVisitor(Visitor):
 
             impl=  ['|'] + self.implicit
             body = [ '*', impl ]
-            msg = "Automatically generated 'Implict' rule"
+            msg = "Automatically generated 'Implicit' rule"
 
             #we add it to the rules
             self.addRule(name, body, msg)
@@ -337,4 +337,4 @@ class GrammarCompilerVisitor(Visitor):
         val = {'type': PROD_TYPE, 'body': rhs, 'errortext': msg }
         if (hidden == True):
             val['hidden'] = True
-        self.rules[name] = val
+        self.rules[name] = val

+ 61 - 25
interface/HUTN/hutn_compiler/model_visitor.py

@@ -12,7 +12,7 @@ class ModelVisitor(Visitor):
         self.free_id = 0
         self.name_maps = {}
         self.current_model = None
-        self.current_element = None
+        self.current_element = []
         self.includes = []
 
     def dump(self):
@@ -44,9 +44,8 @@ class ModelVisitor(Visitor):
     def visit_model(self, tree):
         children = tree.get_children("MODEL_ID")
         model_type = children[0].get_text()
-        model_name = children[1].get_text()
+        model_name = children[-1].get_text()
         self.constructors.extend(["instantiate_model", model_type, model_name])
-        self.constructors.extend(["define_inheritance", model_name, "Inheritance"])
         self.current_model = model_name
         for element in tree.get_children("model_element"):
             self.visit(element)
@@ -67,7 +66,8 @@ class ModelVisitor(Visitor):
             self.constructors.extend(["instantiate_link", self.current_model, element_type, element_name, source_name, target_name])
         else:
             self.constructors.extend(["instantiate_node", self.current_model, element_type, element_name])
-        self.current_element = element_name
+
+        self.current_element.append(element_name)
 
         if tree.get_children("inheritance"):
             self.visit(tree.get_children("inheritance")[0])
@@ -75,30 +75,36 @@ class ModelVisitor(Visitor):
         for attr in tree.get_children("model_attribute"):
             self.visit(attr)
 
+        self.current_element.pop()
+
+        return element_name
+
     def visit_inheritance(self, tree):
         for token in tree.get_children("MODEL_ID"):
             superclass = token.get_text()
-            self.constructors.extend(["instantiate_link", self.current_model, "Inheritance", "%s_inherits_from_%s" % (self.current_element, superclass), self.current_element, superclass])
+            self.constructors.extend(["instantiate_link", self.current_model, "Inheritance", "%s_inherits_from_%s" % (self.current_element[-1], superclass), self.current_element[-1], superclass])
 
     def visit_model_attribute(self, tree):
         children = tree.get_children("MODEL_ID")
         is_definition = bool(tree.get_children("COLON"))
         is_constraint = bool(tree.get_children("DOLLAR"))
         is_assign = bool(tree.get_children("model_attr_instance"))
+        is_nested = bool(tree.get_children("model_element"))
 
         if is_definition:
             attr_name = children[0].get_text()
             attr_type = children[1].get_text()
-            self.constructors.extend(["instantiate_link", self.current_model, "Association", self.current_element + "_" + attr_name, self.current_element, attr_type])
-            full_attribute_name = self.current_element + "_" + attr_name
+            self.constructors.extend(["instantiate_link", self.current_model, "Association", self.current_element[-1] + "_" + attr_name, self.current_element[-1], attr_type])
+            full_attribute_name = self.current_element[-1] + "_" + attr_name
             self.constructors.extend(["instantiate_attribute", self.current_model, full_attribute_name, "name", attr_name])
             if is_assign:
                 # There are also some attributes to set!
-                old_element = self.current_element
-                self.current_element = full_attribute_name
+                self.current_element.append(full_attribute_name)
+
                 for f in tree.get_children("model_attr_instance"):
                     self.visit(f)
-                self.current_element = old_element
+
+                self.current_element.pop()
         elif is_assign:
             self.visit(tree.get_children("model_attr_instance")[0])
         elif is_constraint:
@@ -115,22 +121,52 @@ class ModelVisitor(Visitor):
                 f.flush()
             directory = os.path.realpath(__file__).rsplit(os.sep, 1)[0]
             compiled = do_compile(".constraint.alc", directory + "/../grammars/actionlanguage.g", "CS")
-            self.constructors.extend(["add_constraint", self.current_model, self.current_element] + compiled)
+            self.constructors.extend(["add_constraint", self.current_model, self.current_element[-1]] + compiled)
+        elif is_nested:
+            if tree.get_children("MODEL_ID"):
+                contains_link = tree.get_children("MODEL_ID")[0].get_text()
+            else:
+                contains_link = ""
+            entry = self.visit(tree.get_children("model_element")[0])
+            self.constructors.extend(["instantiate_link", self.current_model, contains_link, "__%s" % self.free_id, self.current_element[-1], entry])
+            self.free_id += 1
 
     def visit_model_attr_instance(self, tree):
+        def constructors_compile(code):
+            code_fragments = code.split("\n")
+	    code_fragments = [i for i in code_fragments if i.strip() != ""]
+	    code_fragments = [i.replace("    ", "\t") for i in code_fragments]
+	    initial_tabs = min([len(i) - len(i.lstrip("\t")) for i in code_fragments])
+	    code_fragments = [i[initial_tabs:] for i in code_fragments]
+	    code = "\n".join(code_fragments)
+            code += "\n"
+
+            with open(".code.alc", 'w') as f:
+                f.write(code)
+                f.flush()
+            directory = os.path.realpath(__file__).rsplit(os.sep, 1)[0]
+            compiled = do_compile(".code.alc", directory + "/../grammars/actionlanguage.g", "CS")
+            return compiled
+
         children = tree.get_children("MODEL_ID")
         attr_name = children[0].get_text()
-        attr_value = tree.get_children("value")[0].get_tail()[0]
-        if attr_value.head == "STRVALUE":
-            attr_value = attr_value.get_text()[1:-1]
-        elif attr_value.head == "TRUE":
-            attr_value = True
-        elif attr_value.head == "FALSE":
-            attr_value = False
-        elif attr_value.head == "DEC_NUMBER":
-            attr_value = int(attr_value.get_text())
-        elif attr_value.head == "FLOAT_NUMBER":
-            attr_value = float(attr_value.get_text())
-        else:
-            raise Exception(attr_value.head)
-        self.constructors.extend(["instantiate_attribute", self.current_model, self.current_element, attr_name, attr_value])
+        if tree.get_children("value"):
+            # Value attribute
+            attr_value = tree.get_children("value")[0].get_tail()[0]
+            if attr_value.head == "STRVALUE":
+                attr_value = attr_value.get_text()[1:-1]
+            elif attr_value.head == "TRUE":
+                attr_value = True
+            elif attr_value.head == "FALSE":
+                attr_value = False
+            elif attr_value.head == "DEC_NUMBER":
+                attr_value = int(attr_value.get_text())
+            elif attr_value.head == "FLOAT_NUMBER":
+                attr_value = float(attr_value.get_text())
+            else:
+                raise Exception(attr_value.head)
+            self.constructors.extend(["instantiate_attribute", self.current_model, self.current_element[-1], attr_name, attr_value])
+        elif tree.get_children("DOLLAR"):
+            # Coded attribute
+            self.constructors.extend(["instantiate_attribute_code", self.current_model, self.current_element[-1], attr_name])
+            self.constructors.extend(constructors_compile(tree.get_children("ANYTHING_EXCEPT_DOLLAR")[0].get_text()))

+ 2 - 0
interface/HUTN/hutn_compiler/primitives_visitor.py

@@ -320,6 +320,8 @@ class PrimitivesVisitor(Visitor):
                     break
         for i in range(len(primitives)-1):
             self.dict(primitives[i], "next", primitives[i+1])
+        if len(primitives) == 0:
+            raise Exception("Block with no body found at %s" % tree.get_reference_line())
         self.set_primitive(tree, primitives[0])
 
     def visit_func_body(self, tree):

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

@@ -0,0 +1 @@
+Element function create_ftg(root : Element)

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

@@ -1,4 +1,6 @@
 Element function create_metamodels()
 Element function initialize_SCD(location : String)
 Element function initialize_PN(location_SCD : String, location_PN : String)
+Element function initialize_FTG(location_SCD : String, location_FTG : String)
 Element function initialize_bottom(location : String)
+Void function add_AL_to_MM(model : Element)

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

@@ -0,0 +1,3 @@
+Element function model_fuse(name1 : String, model1 : Element, name2 : String, model2 : Element)
+Element function model_copy(model : Element)
+Element function model_retype_on_name(model : Element, new_MM : Element, operation : String, name : String)

+ 4 - 1
interface/HUTN/includes/modelling.alh

@@ -7,14 +7,17 @@ Void function retype_model(model : Element, metamodel : Element)
 Void function retype(model : Element, element : String, type : String)
 Element function instantiate_model(metamodel : Element)
 String function instantiate_node(model : Element, type_name : String, instance_name : String)
+String function instantiate_value(model : Element, type_name : String, instance_name : String, value : Element)
 Element function find_attribute_type(model : Element, elem : String, name : String)
 Element function get_superclasses(model : Element, elem : Element)
 Element function find_attribute_definer(model : Element, elem : Element, name : String)
 Void function instantiate_attribute(model : Element, element : String, attribute_name : String, value : Element)
+Void function instantiate_attribute_code(model : Element, element : String, attribute_name : String, code : Element)
+Void function instantiate_existing_attribute(model : Element, element : String, attribute_name : String, attribute_ref : String)
 String function instantiate_link(model : Element, type : String, name : String, source : String, destination : String)
-Void function define_inheritance(model : Element, inheritance_name : String)
 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)
 Void function add_constraint(model : Element, name : String, constraint : Action)
+String function model_define_attribute(model : Element, elem : String, name : String, type : String)

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

@@ -10,3 +10,5 @@ String function print_dict(dict : Element)
 String function readAssociationSource(model : Element, name : String)
 String function readAssociationDestination(model : Element, name : String)
 String function followAssociation(model : Element, element_name : String, association_name : String)
+Element function allAssociationDestinations(model : Element, name : String, association_type : String)
+Element function allowedAssociationsBetween(model : Element, src : String, dst : String)

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

@@ -95,3 +95,12 @@ Float function time()
 Element function exec(a : Element)
 Element function resolve(var_name : String)
 Boolean function has_input()
+Element function list_pop(lst : Element, index : Integer)
+Element function set_copy(set : Element)
+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 dict_copy(dict : Element)
+Element function set_to_list(s : Element)
+Element function create_tuple(a : Element, b : Element)

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

@@ -0,0 +1 @@
+Element function ramify(model : Element)

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

@@ -0,0 +1 @@
+Boolean function transform(host_model : Element, schedule_model : Element)

File diff suppressed because it is too large
+ 1 - 1
interface/HUTN/test/modelling_language/expected/my_petrinet


File diff suppressed because it is too large
+ 1 - 1
interface/HUTN/test/modelling_language/expected/my_petrinet_with_MM


File diff suppressed because it is too large
+ 1 - 1
interface/HUTN/test/modelling_language/expected/petrinets


File diff suppressed because it is too large
+ 1 - 1
interface/HUTN/test/modelling_language/expected/petrinets_constraints


File diff suppressed because it is too large
+ 1 - 1
interface/HUTN/test/modelling_language/expected/simpleclassdiagrams


+ 27 - 15
kernel/modelverse_kernel/compiled.py

@@ -121,6 +121,8 @@ def allInstances(a, b, **remainder):
     b_val, =     yield [("RV", [b])]
     model_dict,= yield [("RD", [a, "model"])]
     metamodel, = yield [("RD", [a, "metamodel"])]
+    m3, =        yield [("RD", [metamodel, "metamodel"])]
+    m3_model, =  yield [("RD", [m3, "model"])]
     mm_dict, =   yield [("RD", [metamodel, "model"])]
     typing, =    yield [("RD", [a, "type_mapping"])]
     elem_keys, = yield [("RDK", [model_dict])]
@@ -134,11 +136,12 @@ def allInstances(a, b, **remainder):
     # And now we have the inverse mapping: for each type, we have the node containing the name
 
     # Get the inheritance link type
-    inheritance_type, =  yield [("RD", [metamodel, "inheritance"])]
+    inheritance_type, =  yield [("RD", [m3_model, "Inheritance"])]
 
     # Now we figure out which types are valid for the specified model
     desired_types = set()
     mm_element, =    yield [("RD", [mm_dict, b_val])]
+
     work_list = []
     work_list.append(mm_element)
     mm_typing, =     yield [("RD", [metamodel, "type_mapping"])]
@@ -288,7 +291,10 @@ def add_AL(a, b, **remainder):
     raise PrimitiveFinished(result)
 
 def get_superclasses(a, b, **remainder):
-    inheritance, =   yield [("RD", [a, "inheritance"])]
+    mm, =            yield [("RD", [a, "metamodel"])]
+    mm, =            yield [("RD", [mm, "metamodel"])]
+    m, =             yield [("RD", [mm, "model"])]
+    inheritance, =   yield [("RD", [m, "Inheritance"])]
     model_dict, =    yield [("RD", [a, "model"])]
     b_v, =           yield [("RV", [b])]
     subclass, =      yield [("RD", [model_dict, b_v])]
@@ -299,22 +305,28 @@ def get_superclasses(a, b, **remainder):
 
     result, =        yield [("CN", [])]
     worklist = [subclass]
+
+    touched = set()
+
     while worklist:
         subclass = worklist.pop()
         res = elem_to_name[subclass]
-        yield [("CE", [result, res])]
-
-        outgoing, =      yield [("RO", [subclass])]
-        types =         yield [("RDN", [type_mapping, i]) for i in outgoing]
-
-        for i, t in enumerate(types):
-            if t == inheritance:
-                # Found an inheritance link!
-                elem = outgoing[i]
-                srcdst, = yield [("RE", [elem])]
-                src, dst = srcdst
-                # Find elem in elems
-                worklist.append(dst)
+
+        if subclass not in touched:
+            touched.add(subclass)
+            yield [("CE", [result, res])]
+
+            outgoing, =      yield [("RO", [subclass])]
+            types =         yield [("RDN", [type_mapping, i]) for i in outgoing]
+
+            for i, t in enumerate(types):
+                if t == inheritance:
+                    # Found an inheritance link!
+                    elem = outgoing[i]
+                    srcdst, = yield [("RE", [elem])]
+                    src, dst = srcdst
+                    # Find elem in elems
+                    worklist.append(dst)
 
     raise PrimitiveFinished(result)
 

+ 1 - 1
scripts/compile.py

@@ -4,7 +4,7 @@ import urllib2
 import urllib
 import subprocess
 
-def do_compile(address, filename, username, modulename, mode, optionals=[], grammar="grammars/actionlanguage.g"):
+def do_compile(address, filename, username, modulename, mode, optionals=['--debug'], grammar="grammars/actionlanguage.g"):
     filename = os.path.realpath(filename)
     try:
         urllib2.urlopen(urllib2.Request(address, 'op=set_input&username=user_manager&value="%s"' % username)).read()

+ 1 - 1
state/modelverse_state/main.py

@@ -407,4 +407,4 @@ class ModelverseState(object):
                 if v in self.nodes:
                     self.delete_node(v)
 
-        print("Remaining nodes: " + str(len(self.nodes)))
+        #print("Remaining nodes: " + str(len(self.nodes)))